W Cygwin nie ma polecenia „sudo”


41

Ponieważ w Cygwin nie ma polecenia sudo , skrypty, które chcę uruchomić, zawodzą

./install.sh: line N: sudo: command not found

Jaki jest standardowy sposób na obejście tego? Edytujesz skrypty do usunięcia sudo? Dostajesz jakieś sudopodobne narzędzie do systemu Windows?


@dotancohen, mam nadzieję, że wybrałem właściwy.
Jason Sundram

Wygląda mi na dobre rozwiązanie! Wsparcie Cygwina poprawiło się w ciągu ostatnich pięciu lat!
dotancohen


@Benj, zastanawiam się, dlaczego to pytanie również nie zostało tutaj przeniesione.
Jason Sundram

@JasonSundram rzeczywiście. Daj mi znać, jeśli odpowiedź zostanie przeniesiona, a następnie zaktualizuję link.
Benj

Odpowiedzi:


8

Napisałem (raczej prosty) TOUACExt dla SUDO dla CygWin , automatyzację skryptów powłoki przed wersją beta, która podchodzi do zachowania klasycznego sudo dla Linuksa:

  • Otwiera i zamyka automatycznie sudoserver.py w razie potrzeby.
  • Żąda monitu o podniesienie UAC .

Instalacja wymaga skopiowania czterech .shskryptów do jakiegoś katalogu ścieżki, utworzenia aliasu i tylko kilku dodatkowych kroków opisanych w wątku.

Rezultaty : wpiszesz pojedynczy sudo YourCommandi otrzymasz wynik, bez martwienia się o resztę procesu.


35

Jednym ze sposobów jest utworzenie fałszywego polecenia „sudo” o następującej treści:

#!/usr/bin/bash

"$@"

Pozwoli install.shto kontynuować, ponieważ znaleziono sudo.

Nie podnosi to uprawnień, tak jak robi to prawdziwe sudo. Jeśli naprawdę potrzebujesz podwyższonych uprawnień, uruchom powłokę cygwin z konta z uprawnieniami administracyjnymi (XP) lub kliknij przycisk cygwin.bat i kliknij „uruchom jako administrator” (Vista, Win7)


5
Z ciekawości kogoś, kto nie mówi płynnie bash: dlaczego to działa? Strona nie mówi nic o $@robieniu czegoś sudopodobnego. Zamiast tego są to tylko argumenty skryptu. I czy w takim przypadku cytaty wokół niego nie byłyby zbyteczne? W przeciwnym razie, jeśli to zrobisz sudo foo bar, spróbuje wykonać "foo bar"jako pojedyncze polecenie, które prawdopodobnie nie istnieje, biorąc pod uwagę ten irracjonalny strach przed spacjami w systemach typu UNIX.
Joey

7
@Johannes: "$@"(gdy jest cytowany) działa inaczej niż "$*": rozwija się do osobnego słowa dla każdej zmiennej pozycyjnej. Przykład: Jeśli $1 == "foo bar"i $2 == "baz", to "$@"jest "foo bar" baz- jedno słowo dla każdego parametru (w przeciwieństwie do tego "$*", co daje "foo bar baz"jedno słowo). Patrz instrukcja bash, sekcja Parametry , podsekcja Parametry specjalne . Efektem końcowym skryptu Peona jest to, że wykonuje on swoje argumenty dokładnie tak, jak zostały przekazane.
grawity

1
Ach, okej A skąd ta sudoczęść? Powyższy fragment nie robi nic zdalnie w tym kierunku, prawda?
Joey

2
@Johannes: W Uniksie prawdziwy sudopodnosiłby przywileje od śmiertelnych do rootprzed uruchomieniem polecenia. W Cygwin nie ma czegoś takiego, więc fałszywy skrypt Peona (który należy nazwać sudo) po prostu uruchamia polecenie bezpośrednio, nie zmieniając jego uprawnień. (Oznacza to, że może być konieczne uruchomienie ./install.shjako Administrator.)
grawity

2
@grawity: runaspowinien działać, nie opiera się na UAC i sam monituje o hasło. Byłem po prostu zdezorientowany, dlaczego scenariusz w odpowiedzi najwyraźniej nie zrobił tego, co sugerowała nazwa, co, jak zakładam, było celem. Przepraszam za moją głupotę ;-)
Joey

21

Odpowiedź znalazłem na liście dyskusyjnej cygwina . Aby uruchomić commandz podwyższonymi uprawnieniami w Cygwin, poprzedź polecenie cygstart --action=runasnastępująco:

$ cygstart --action=runas command

Otworzy się okno dialogowe Windows z prośbą o hasło administratora i uruchom polecenie, jeśli zostanie wprowadzone prawidłowe hasło.

Można to łatwo wykonać za pomocą skryptu, o ile ~/binznajduje się na twojej ścieżce:

$ cat ~/bin/sudo
#!/usr/bin/bash
cygstart --action=runas "$@"

$ PATH=$HOME/bin:$PATH
$ chmod +x ~/bin/sudo
$ sudo elevatedCommand

Testowany na 64-bitowym systemie Windows 8.


5
Problem z tą cygstartmetodą polega na tym, że działa ona tylko dla poleceń / programów Windows. Nie możesz tego zrobić sudo ls. SUDO dla CygWin jest schludne, ale wciąż brakuje sudow nim dobrej znajomości.
Sopalajo de Arrierez

Dziękuję Sopalajode. W jakiej sytuacji sudo lsmusiałeś skorzystać z Cygwin?
dotancohen

3
O nie, @Dotancohen, to był tylko przykład. Możesz użyć sudoCygWin do uruchomienia dowolnego polecenia Windows lub CygWin. Jest to dla mnie bardzo przydatne. Ale bardziej praktyczną metodą, którą znalazłem, jest to opakowanie skryptu dla SUDO dla CygWin, które opracowałem: superuser.com/questions/741345/… (wciąż w wersji Beta, ale wydaje się, że działa). Dzięki niemu możesz wygodnie zamawiać takie rzeczy sudo net start vncserver.
Sopalajo de Arrierez

@SopalajodeArrierez: To absolutnie wspaniałe! Dziękuję za post i link.
dotancohen

co ciekawe, to rozbiera się /bini /usr/binod PATH. Z powodzeniem wywołuje emacs: ShellExecute(NULL, "runas", "C:\cygwin64\bin\emacs-w32.exe", "(null)", "(null)", 1)ale wtedy emacs nie może znaleźć lsnp. M-x diredNawet po interaktywnym przywracaniu PATH za pomocą (setenv ...). Czy występuje tu problem z zaufanymi ścieżkami?
BaseZen

5

Opierając się na odpowiedzi dotancohen, używam aliasu:

alias sudo="cygstart --action=runas"

Działa jako urok programów zewnętrznych (ale nie wbudowanych w powłokę):

sudo chown User:Group <file>

3

Sudo (Elevate) na Windows ™

Dużo pracuję nad wierszem poleceń w systemie Windows ™.

W samym Cygwin wierzę, że możesz uruchomić polecenie root su -c /the/cmdjak dla samego sudo w systemie plików Windows ™, podnosząc uprawnienia użytkownika z linii poleceń. Jeśli jesteś administratorem, będzie to dla ciebie świetne. W przeciwnym razie użyj run i zdobądź przepustkę administratora;).

Teraz nie pamiętam, skąd mamy ten kod, ale oto on. Mam nadzieję, że to pomoże.

BTW, pakiet, którego używamy do kompilacji tego był gcc-mingw32.

$ i586-mingw32msvc-gcc sudo.c -o sudo.exe
# Put sudo.exe in /usr/bin or in your windows path (%homedrive%\windows)
#example:
$ sudo vi /cygdrive/c/windows/system32/drivers/etc/hosts

/**
* (sudo for Windows™)
* @filename sudo.c
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <shellapi.h>
#include <wchar.h>


LPWSTR *mergestrings(LPWSTR *left, LPCWSTR right)
{
    size_t size = ( 1 + lstrlen(*left) + lstrlen(right) ) * sizeof(LPWSTR*);
    if ( *left ) {
        LPWSTR leftcopy = _wcsdup(*left);
        *left = (LPWSTR)realloc(*left, size);
        *left = lstrcpy(*left, leftcopy);
        *left = lstrcat(*left, right);
        free( leftcopy );
    }
    else
        *left = _wcsdup(right);
    return left;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpcommand, int nShowCmd)
{
    DWORD result = 0x2a;
    LPWSTR *argv = NULL;
    int argc = 0;
    if ( argv = CommandLineToArgvW(GetCommandLineW(), &argc) ) {
        if ( argc < 2 ) {
            LPWSTR usagemsg = NULL;
            usagemsg = *mergestrings(&usagemsg, argv[0]);
            usagemsg = *mergestrings(&usagemsg, TEXT(" <command_to_run> [arguments]"));
            MessageBox(NULL, usagemsg, TEXT("Usage:"), MB_OK | MB_ICONEXCLAMATION );
            LocalFree( argv );
            free( usagemsg );
            return ERROR_BAD_ARGUMENTS;
        }
        else {
            LPWSTR command = argv[1];
            LPWSTR arguments = NULL;
            int c;
            for ( c = 2; c < argc; c++ ) {
                arguments = *mergestrings(&arguments, argv[c]);
                arguments = *mergestrings(&arguments, TEXT(" "));
            }
            result = (DWORD)ShellExecute(NULL, TEXT("runas"), command, arguments, NULL, SW_SHOWNORMAL);
            LocalFree( argv );
            if ( arguments )
                free( arguments );
            switch ( result )
            {
                case 0:
                    result = ERROR_OUTOFMEMORY;
                    break;

                case 27:
                case 31:
                    result = ERROR_NO_ASSOCIATION;
                    break;

                case 28:
                case 29:
                case 30:
                    result = ERROR_DDE_FAIL;
                    break;
                case 32:
                    result = ERROR_DLL_NOT_FOUND;
                    break;
                default:
                    if ( result > 32 )
                        result = 0x2a;
            }
        }
    }
    else
        result = GetLastError();

    if (result != 0x2a) {
        LPWSTR errormsg = NULL;
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                      NULL, result, 0, (LPWSTR)&errormsg, 0, NULL);
        MessageBox(NULL, errormsg, TEXT("Error:"), MB_OK | MB_ICONERROR);
        LocalFree( errormsg );
        return result;
    }
    else
        return NO_ERROR;
}

5
Ten kod jest okropny. Jest pełen błędów, takich jak nie sprawdzanie wartości zwracanej przez realloc () przed dereferencją lub zapisywanie sizeof (LPWSTR *) zamiast sizeof (* LPWSTR), gdzie LPWSTR wydaje się być typem wskaźnika i chce się pobrać rozmiar jednego znaku, a nie rozmiar wskaźnika. Co więcej, nie jest całkowicie jasne, dlaczego np. Przypadek 29 prowadzi do ERROR_DDE_FAIL. Czy możesz wyciągnąć wnioski z kodu, dlaczego? Nie mogę i chyba nikt inny też nie może. Nie publikuj takiego kodu w przyszłości.

4
@Mattew: w przyszłości pomóż społeczności, publikując oczyszczoną wersję fragmentu kodu, którego nie lubisz.
Erik Allik,

Kod nie powinien znajdować się na superużytkowniku. Umieść go na codereview.se i po prostu połącz go stąd.
Ben Voigt

@ user185282: Dobre punkty. Głosowałem za odpowiedzią.
niezapomniany

Drogi Tao: Napisałeś: „Nie pamiętam, skąd mamy ten kod”. Czy napisałeś ten kod, czy ktoś go napisał?
niezapomniany

2

Nieznaczna poprawa fałszywego skryptu sudo Peona:

#!/bin/sh
# Drop any option arguments.
while [[ $# -ge 0 && $1 = -* ]]; do
  shift
done

"$@"

Ten skrypt po cichu usuwa wszystkie opcje przekazane do sudo i wykonuje polecenie (bez faktycznego podnoszenia uprawnień). Usunięcie opcji nieco poprawia kompatybilność. Bardziej kompletny skrypt opakowujący powinien analizować opcje w taki sam sposób, jak robi to sudo.

Zamiast próbować zastąpić sudo opakowaniem, które to robi cygstart --action=runas "$@", wystarczy użyć tego prostego fałszywego opakowania sudo i uruchomić sam skrypt instalacyjny (lub cokolwiek, co próbujesz uruchomić, który używa sudo) z podwyższonymi uprawnieniami.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.