Wykonywanie funkcji skryptu Bash w Sudo


22

Mam skrypt, który wykonuje wiele różnych czynności, z których większość nie wymaga żadnych specjalnych uprawnień. Jednak jedna konkretna sekcja, którą zawarłem w ramach funkcji, wymaga uprawnień roota.

Nie chcę wymagać, aby cały skrypt działał jako root i chcę móc wywoływać tę funkcję z uprawnieniami roota z poziomu skryptu. Żądanie hasła w razie potrzeby nie stanowi problemu, ponieważ i tak jest w większości interaktywne. Jednak gdy próbuję użyć sudo functionx, otrzymuję:

sudo: functionx: command not found

Tak jak się spodziewałem, exportnie miało to znaczenia. Chciałbym być w stanie wykonać funkcję bezpośrednio w skrypcie, zamiast rozbijać ją i wykonywać jako osobny skrypt z wielu powodów.

Czy jest jakiś sposób, aby uczynić moją funkcję „widoczną” dla sudo bez wypakowywania jej, znajdowania odpowiedniego katalogu, a następnie wykonywania go jako samodzielnego skryptu?

Ta funkcja dotyczy samej długości strony i zawiera wiele ciągów znaków, niektóre cudzysłowy i niektóre cudzysłowy. Zależy również od funkcji menu zdefiniowanej w innym miejscu w głównym skrypcie.

Spodziewałbym się tylko, że ktoś z sudo KAŻDY będzie mógł uruchomić tę funkcję, ponieważ jedną z rzeczy, które robi, jest zmiana hasła.


Fakt, że w grę wchodzi kilka funkcji, czyni go jeszcze bardziej skomplikowanym i podatnym na awarie. Teraz musisz znaleźć wszystkie takie zależności (a także wszystkie ich zależności, jeśli w ogóle ... aż do wielu poziomów głębokości), w tym wszelkie inne funkcje, które może wywołać funkcja menu, a także declareje.
cas

Zgodziłem się i być może będę musiał po prostu ugryźć pocisk i rozbić go (i dołożę wszelkich starań, aby dokładnie określić ścieżkę, z której został uruchomiony, a także mieć nadzieję, że użytkownik końcowy zachowa pliki razem), jeśli nie ma lepszych alternatyw.
BryKKan,

Odpowiedzi:


19

Przyznaję, że nie ma prostego, intuicyjnego sposobu, aby to zrobić, a to jest trochę hackey. Ale możesz to zrobić w następujący sposób:

function hello()
{
    echo "Hello!"
}

# Test that it works.
hello

FUNC=$(declare -f hello)
sudo bash -c "$FUNC; hello"

Lub prościej:

sudo bash -c "$(declare -f hello); hello"

Mi to pasuje:

$ bash --version
GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin14.5.0)
$ hello
Hello!
$
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Hello!

Zasadniczo declare -fzwróci zawartość funkcji, którą następnie przekażesz bash -cinline.

Jeśli chcesz wyeksportować wszystkie funkcje z zewnętrznego wystąpienia bash, zmień FUNC=$(declare -f hello)na FUNC=$(declare -f).

Edytować

Aby odnieść się do komentarzy na temat cytowania, zobacz ten przykład:

$ hello()
> {
> echo "This 'is a' test."
> }
$ declare -f hello
hello ()
{
    echo "This 'is a' test."
}
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Password:
This 'is a' test.

1
Działa to tylko przypadkowo, ponieważ echo "Hello!"jest faktycznie takie samo jak echo Hello!(tzn. Podwójne cudzysłowy nie mają znaczenia dla tego konkretnego polecenia echa). W wielu / większości innych przypadków podwójne cudzysłowy w funkcji prawdopodobnie powodują przerwanie bash -cpolecenia.
cas

1
To odpowiada na pierwotne pytanie, więc jeśli nie znajdę lepszego rozwiązania, zaakceptuję je. Jednak psuje moją konkretną funkcję (patrz moja edycja), ponieważ jest zależna od funkcji zdefiniowanych gdzie indziej w skrypcie.
BryKKan,

1
Zrobiłem kilka testów wcześniej tego popołudnia (używając bash -xcraczej niż tylko bash -c) i wygląda na to, że bashjest wystarczająco inteligentny, aby cytować rzeczy w tej sytuacji, nawet w zakresie zastępowania podwójnych cudzysłowów pojedynczymi cudzysłowami i zmieniania 'na, '\''jeśli to konieczne. Jestem pewien, że będą pewne przypadki, których nie będzie w stanie obsłużyć, ale na pewno działa to w co najmniej prostych i średnio skomplikowanych przypadkach - np. Tryfunction hello() { filename="this is a 'filename' with single quotes and spaces" ; echo "$filename" ; } ; FUNC=$(declare -f hello) ; bash -xc "$FUNC ; hello"
cas

4
@cas declare -fdrukuje definicji funkcji w sposób, który może być ponownie przetwarzane przez bash tak bash -c "$(declare -f)" robi działają prawidłowo (przy założeniu, że zewnętrzna powłoka jest atakujących). W opublikowanym przykładzie pokazano, że działa poprawnie - tam, gdzie zmieniono cudzysłowy, znajduje się w śladzie , ponieważ bash drukuje ślady w składni powłoki, np. Spróbujbash -xc 'echo "hello world"'
Gilles „SO- przestań być zły”

3
Doskonała odpowiedź. Wdrożyłem twoje rozwiązanie - chciałbym zauważyć, że możesz zaimportować sam skrypt ze skryptu, pod warunkiem, że zagnieżdżasz go w warunku, który sprawdza, czy sudo yourFunctionnie można go znaleźć (w przeciwnym razie podczas rekursji
wystąpi

5

„Problem” polega na tym, że sudooczyszcza środowisko (z wyjątkiem kilku dozwolonych zmiennych) i ustawia niektóre zmienne na wstępnie zdefiniowane bezpieczne wartości w celu ochrony przed zagrożeniami bezpieczeństwa. innymi słowy, nie jest to tak naprawdę problemem. To funkcja.

Na przykład, jeśli ustawiłeś PATH="/path/to/myevildirectory:$PATH"i sudonie ustawiłeś PATH na wstępnie zdefiniowaną wartość, wówczas każdy skrypt, który nie określiłby pełnej ścieżki do WSZYSTKICH poleceń, które uruchamia (tj. Większość skryptów) szukałby /path/to/myevildirectoryprzed jakimkolwiek innym katalogiem. Umieszczaj w nim polecenia takie jak lslub grepinne popularne narzędzia, dzięki czemu możesz łatwo robić, co chcesz w systemie.

Najłatwiejszym / najlepszym sposobem jest ponowne zapisanie funkcji jako skryptu i zapisanie jej gdzieś na ścieżce (lub określenie pełnej ścieżki do skryptu w sudowierszu poleceń - co i tak musisz zrobić, chyba że sudoskonfigurowano to tak, aby ci pozwalało aby uruchomić DOWOLNĄ komendę jako root) i uczynić ją wykonywalną za pomocąchmod +x /path/to/scriptname.sh

Przebudowywanie powłoki funkcję jako skrypt jest tak proste, jak to tylko oszczędność poleceń wewnątrz definicji funkcji w pliku (bez function ..., {a }wiersze).


To w żaden sposób nie odpowiada na pytanie. W szczególności chce uniknąć umieszczania go w skrypcie.
Czy

1
sudo -EUnika także czyszczenia środowiska.
Czy

W pewnym stopniu rozumiem, dlaczego tak się dzieje. Miałem nadzieję, że istnieją jakieś środki, aby tymczasowo zastąpić to zachowanie. Gdzie indziej wspomniano o opcji -E, ale to nie zadziałało w tym przypadku. Niestety, choć doceniam wyjaśnienie, w jaki sposób uczynić z niego samodzielny skrypt, to w szczególności nie odpowiada na pytanie, ponieważ chciałem tego uniknąć. Nie mam kontroli nad tym, gdzie użytkownik końcowy umieszcza skrypt i chciałbym uniknąć zarówno mocno zakodowanych katalogów, jak i piosenki i tańca, próbując dokładnie ustalić, skąd został uruchomiony główny skrypt.
BryKKan,

nie ma znaczenia, czy o to poprosił PO, czy nie. Jeśli to, czego chce, albo nie zadziała, albo można je zmusić do działania, robiąc coś wyjątkowo niepewnego, trzeba im o tym powiedzieć i zapewnić alternatywę - nawet jeśli alternatywa jest czymś, czego wyraźnie oświadczyła, że ​​nie chce (ponieważ czasami jest to jedyny lub najlepszy sposób, aby zrobić to bezpiecznie). Byłoby nieodpowiedzialne powiedzenie komuś, jak strzelić sobie w stopę, bez ostrzeżenia go o prawdopodobnych konsekwencjach celowania pistoletem w stopy i pociągnięcia za spust.
cas

1
@cas To prawda. Nie można tego zrobić bezpiecznie, jest to akceptowalna odpowiedź w niektórych okolicznościach. Zobacz jednak moją ostatnią edycję. Byłbym ciekawy, czy twoja opinia na temat wpływu na bezpieczeństwo jest taka sama, biorąc pod uwagę to.
BryKKan,

3

W tym celu napisałem własną Sudofunkcję bash, która działa do wywoływania funkcji i aliasów:

function Sudo {
        local firstArg=$1
        if [ $(type -t $firstArg) = function ]
        then
                shift && command sudo bash -c "$(declare -f $firstArg);$firstArg $*"
        elif [ $(type -t $firstArg) = alias ]
        then
                alias sudo='\sudo '
                eval "sudo $@"
        else
                command sudo "$@"
        fi
}

2

Możesz łączyć funkcje i aliasy

Przykład:

function hello_fn() {
    echo "Hello!" 
}

alias hello='bash -c "$(declare -f hello_fn); hello_fn"' 
alias sudo='sudo '

wtedy sudo hellodziała


1

Oto wariant odpowiedzi Willa . Wymaga dodatkowego catprocesu, ale oferuje komfort heredoc. W skrócie wygląda to tak:

f () 
{
    echo ok;
}

cat <<EOS | sudo bash
$(declare -f f)
f
EOS

Jeśli chcesz więcej do myślenia, spróbuj tego:

#!/bin/bash

f () 
{ 
    x="a b"; 
    menu "$x"; 
    y="difficult thing"; 
    echo "a $y to parse"; 
}

menu () 
{
    [ "$1" == "a b" ] && 
    echo "here's the menu"; 
}

cat <<EOS | sudo bash
$(declare -f f)
$(declare -f menu)
f
EOS

Dane wyjściowe to:

here's the menu
a difficult thing to pass

Tutaj mamy menufunkcję odpowiadającą tej w pytaniu, która jest „zdefiniowana gdzie indziej w głównym skrypcie”. Jeśli „gdzie indziej” oznacza, że ​​jego definicja została już odczytana na tym etapie, gdy wykonywana jest funkcja wymagająca sudo, sytuacja jest analogiczna. Ale może jeszcze nie został przeczytany. Może istnieć inna funkcja, która jeszcze uruchomi jej definicję. W takim przypadku declare -f menunależy zastąpić coś bardziej zaawansowanego lub cały skrypt skorygowany w taki sposób, że menufunkcja jest już zadeklarowana.


Bardzo interesujące. W pewnym momencie będę musiał to wypróbować. I tak, menufunkcja zostałaby zadeklarowana przed tym punktem, ponieważ fjest wywoływana z menu.
BryKKan

0

Zakładając, że twój skrypt jest (a) samowystarczalny lub (b) może pozyskiwać swoje komponenty na podstawie jego lokalizacji (zamiast zapamiętywania twojego katalogu domowego), możesz zrobić coś takiego:

  • użyj nazwy $0ścieżki do skryptu, używając tej w sudopoleceniu, i przekaż opcję, którą skrypt sprawdzi, aby wywołać aktualizację hasła. Tak długo, jak polegasz na znalezieniu skryptu na ścieżce (zamiast po prostu uruchomić ./myscript), powinieneś otrzymać bezwzględną nazwę ścieżki $0.
  • ponieważ sudouruchamia skrypt, ma dostęp do funkcji potrzebnych w skrypcie.
  • w górnej części skryptu (zamiast deklaracji funkcji), skrypt sprawdzi jego uidi zda sobie sprawę, że został uruchomiony jako użytkownik root , i zobaczy, że ma ustawioną opcję nakazującą mu aktualizację hasła, idź i zrób że.

Skrypty mogą się powtarzać z różnych przyczyn: jednym z nich jest zmiana uprawnień.

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.