Jak użyć su do wykonania pozostałej części skryptu bash jako ten użytkownik?

126

Napisałem skrypt, który jako argument przyjmuje ciąg będący połączeniem nazwy użytkownika i projektu. Skrypt powinien przełączyć się (su) na nazwę użytkownika, cd do określonego katalogu na podstawie ciągu znaków projektu.

Zasadniczo chcę zrobić:

su $USERNAME;  
cd /home/$USERNAME/$PROJECT;  
svn update;  

Problem w tym, że kiedy zrobię su ... to po prostu tam czeka. Ma to sens, ponieważ przepływ wykonania przeszedł do przełączenia na użytkownika. Kiedy wyjdę, reszta rzeczy jest wykonywana, ale nie działa zgodnie z oczekiwaniami.

Dodałem su do polecenia svn, ale polecenie nie powiodło się (tj. Nie zaktualizowało svn w żądanym katalogu).

Jak napisać skrypt, który pozwoli użytkownikowi na zmianę użytkownika i wywołanie svn (między innymi)?

Avery
źródło

Odpowiedzi:

86

Sztuczka polega na użyciu polecenia „sudo” zamiast „su”

Być może będziesz musiał to dodać

username1 ALL=(username2) NOPASSWD: /path/to/svn

do pliku / etc / sudoers

i zmień swój skrypt na:

sudo -u username2 -H sh -c "cd /home/$USERNAME/$PROJECT; svn update" 

Gdzie nazwa_użytkownika2 to użytkownik, jako którego ma zostać uruchomiona komenda SVN, a nazwa_użytkownika1 to użytkownik uruchamiający skrypt.

Jeśli potrzebujesz wielu użytkowników do uruchomienia tego skryptu, użyj %groupnamezamiast nazwy użytkownika1

Kimvais
źródło
Mam podobny problem, ale chciałem uruchomić chshdla innych użytkowników. Mój problem jest wymieniony na stackoverflow.com/q/15307289/80353 Jak dostosować odpowiedź do mojej sytuacji?
Kim Stacks
Zrobiłem to - ale nadal prosił mnie o hasło.
Hippyjim
@Hippyjim Czy na pewno masz nazwy użytkowników we właściwy sposób?
Kimvais,
1
Zrobiłem - okazuje się, że musiałem również zezwolić na użycie / bin / bash.
Hippyjim
3
Niezależnie od tego, czy używasz, sudoczy suma drugorzędne znaczenie, sudojest o wiele bezpieczniejsze i wygodniejsze.
tripleee
105

O wiele prostsze: użyj sudodo uruchomienia powłoki i użyj heredoc do podawania poleceń.

#!/usr/bin/env bash
whoami
sudo -i -u someuser bash << EOF
echo "In"
whoami
EOF
echo "Out"
whoami

(odpowiedź pierwotnie na SuperUser )

Dan Dascalescu
źródło
5
Ta odpowiedź zadziałała najlepiej. Polecam skorzystać z opcji, -iaby uzyskać someuseroczekiwane środowisko.
not2savvy
2
sudomoże być wygodny, ale nie jest dobry, jeśli nie jest wyjęty z pudełka (jak w systemie AIX). su -c 'commands'to poprawna odpowiedź.
Tricky
1
Epickie rozwiązanie!
3bdalla
Jak udostępnić zmienne w zakresie herdoc?
dotslashlu
w systemie AIX zgłasza ten błąd ksh: sh: 0403-006 Odmowa uprawnień do wykonywania.
AhmedRana
54

Użyj skryptu podobnego do poniższego, aby wykonać pozostałą część lub część skryptu przez innego użytkownika:

#!/bin/sh

id

exec sudo -u transmission /bin/sh - << eof

id

eof
Walder
źródło
11
Możesz użyć "sudo -i -u ...", aby upewnić się, że takie rzeczy jak $ HOME są ustawione poprawnie.
Bryan Larsen
Przepraszam za żadne pytanie, ale jaki jest identyfikator?
Nitin Jadhav
1
@NitinJadhav, użył go tutaj tylko do pokazania ID aktualnego użytkownika, ID roota to 0, więc pierwszy id pokaże ci jakąś liczbę, ale drugi na pewno pokaże 0 (ponieważ drugi został wykonany w środku blok uruchamiany przez roota). Możesz whoamizamiast tego użytkownik idzwróci nazwę zamiast identyfikatora
Mohammed Noureldin
@MohammedNoureldin Thanks!
Nitin Jadhav
sudomoże być wygodny, ale nie jest dobry, jeśli nie jest wyjęty z pudełka (jak w systemie AIX). su -c 'commands'to poprawna odpowiedź.
Tricky
52

Musisz wykonać wszystkie polecenia dla różnych użytkowników jako ich własny skrypt. Jeśli jest to tylko jedno polecenie lub kilka poleceń, funkcja inline powinna działać. Jeśli jest dużo poleceń, prawdopodobnie najlepiej przenieść je do własnego pliku.

su -c "cd /home/$USERNAME/$PROJECT ; svn update" -m "$USERNAME" 
Douglas Leeder
źródło
4
To jedyna poprawna odpowiedź. Sudo nie jest do tego konieczne.
helvete
1
Konieczne może być również zapewnienie powłoki su -s /bin/bash.
mixel
najlepsze rozwiązanie dla użytkowników root
rfinz
Najlepsza odpowiedź dla tych, którzy nie mają domyślnie zainstalowanego sudo (patrzę na ciebie AIX)
Tricky
46

Oto jeszcze jedno podejście, które było wygodniejsze w moim przypadku (chciałem po prostu zrzucić uprawnienia roota i wykonać resztę skryptu od użytkownika z ograniczonym dostępem): możesz zmusić skrypt do ponownego uruchomienia od właściwego użytkownika. Załóżmy, że początkowo jest uruchamiany jako root. Wtedy będzie wyglądać tak:

#!/bin/bash
if [ $UID -eq 0 ]; then
  user=$1
  dir=$2
  shift 2     # if you need some other parameters
  cd "$dir"
  exec su "$user" "$0" -- "$@"
  # nothing will be executed beyond that line,
  # because exec replaces running process with the new one
fi

echo "This will be run from user $UID"
...
MarSoft
źródło
6
Zastanawiam się, dlaczego to nie jest wyżej oceniane. Jest to najlepsze rozwiązanie pierwotnego pytania, jednocześnie utrzymując wszystko w bash.
SirVer
Lub runuser -u $user -- "$@", jak stwierdzono w su (1)
cghislai
1
exec su "$user" "$0" -- "$@"
macieksk
1
Dzięki @macieksk, niezły chwyt. Zaktualizuję. To --jest naprawdę przydatne.
MarSoft
1
Przedstawione podejście jest najlepsze ze wszystkich i kompletne. Wszystko jest napisane w jednym skrypcie i wszystkie używa bash. W efekcie ten skrypt jest uruchamiany dwukrotnie. Na początku testu skryptu jest to root, następnie przygotuj środowisko i zmień użytkownika przez su. Ale zrób to za pomocą polecenia exec, wtedy jest tylko jedna instancja skryptu. W drugiej pętli pomijane jest wyrażenie if / fi, a następnie skrypt bezpośrednio wykonuje przygotowaną akcję. W tym przykładzie jest to echo. Wszystkie inne podejścia rozwiązują problem tylko częściowo. Oczywiście ten skrypt można uruchomić pod sh nie bash, ale musimy przetestować specjalną zmienną $ HOME, a nie $ UID
Znik
7

Użyj sudozamiast tego

EDYCJA : Jak zauważył Douglas, nie można używać programu cdin, sudoponieważ nie jest to polecenie zewnętrzne . Aby wszystko działało, musisz uruchamiać polecenia w podpowłoce cd.

sudo -u $USERNAME -H sh -c "cd ~/$PROJECT; svn update"

sudo -u $USERNAME -H cd ~/$PROJECT
sudo -u $USERNAME svn update

Możesz zostać poproszony o wprowadzenie hasła tego użytkownika, ale tylko raz.

iamamac
źródło
To jednak nie zadziała - płyta CD zostanie utracona po zakończeniu wykonywania pierwszego sudo.
Douglas Leeder
Właściwie nie możesz nawet bezpośrednio wywołać cd, ponieważ nie jest to polecenie zewnętrzne .
iamamac
sudomoże być wygodny, ale nie jest dobry, jeśli nie jest wyjęty z pudełka (jak w systemie AIX). su -c 'commands'to poprawna odpowiedź.
Tricky
6

Nie można zmienić użytkownika w skrypcie powłoki. Obejścia z użyciem sudo opisane w innych odpowiedziach są prawdopodobnie najlepszym rozwiązaniem.

Jeśli jesteś na tyle szalony, aby uruchamiać skrypty Perla jako root, możesz to zrobić ze $< $( $> $) zmiennymi, które przechowują rzeczywisty / efektywny uid / gid, np .:

#!/usr/bin/perl -w
$user = shift;
if (!$<) {
    $> = getpwnam $user;
    $) = getgrnam $user;
} else {
    die 'must be root to change uid';
}
system('whoami');
Orzechy P
źródło
-1 jak to JEST możliwe sudo tymczasowo uzyskać praw innych użytkowników.
Kimvais
4
Nie jest to możliwe w tym sensie, że użytkownik, który sam uruchamia skrypt powłoki, nie może zostać zmieniony (o to właśnie zadawano oryginalne pytanie). Wywołanie innych procesów za pomocą sudo nie zmienia, jako kogo działa sam skrypt.
P-Nuts
2

To zadziałało dla mnie

Oddzieliłem moją „obsługę administracyjną” od mojego „uruchomienia”.

 # Configure everything else ready to run 
  config.vm.provision :shell, path: "provision.sh"
  config.vm.provision :shell, path: "start_env.sh", run: "always"

następnie w moim start_env.sh

#!/usr/bin/env bash

echo "Starting Server Env"
#java -jar /usr/lib/node_modules/selenium-server-standalone-jar/jar/selenium-server-standalone-2.40.0.jar  &
#(cd /vagrant_projects/myproj && sudo -u vagrant -H sh -c "nohup npm install 0<&- &>/dev/null &;bower install 0<&- &>/dev/null &")
cd /vagrant_projects/myproj
nohup grunt connect:server:keepalive 0<&- &>/dev/null &
nohup apimocker -c /vagrant_projects/myproj/mock_api_data/config.json 0<&- &>/dev/null &
httpete
źródło
-2

Zainspirowany pomysłem z @ MarSoft, ale zmieniłem linie w następujący sposób:

USERNAME='desireduser'
COMMAND=$0
COMMANDARGS="$(printf " %q" "${@}")"
if [ $(whoami) != "$USERNAME" ]; then
  exec sudo -E su $USERNAME -c "/usr/bin/bash -l $COMMAND $COMMANDARGS"
  exit
fi

Kiedyś sudopozwalałem na hasło mniej wykonywania skryptu. Jeśli chcesz wprowadzić hasło dla użytkownika, usuń rozszerzenie sudo. Jeśli nie potrzebujesz zmiennych środowiskowych, usuń -Ez sudo.

Te /usr/bin/bash -l, zapewnia, że profile.dskrypty są wykonywane na zainicjowany środowiska.

Trendfischer
źródło
sudomoże być wygodny, ale nie jest dobry, jeśli nie jest wyjęty z pudełka (jak w systemie AIX). su -c 'commands'to poprawna odpowiedź.
Tricky
@Tricky Być może przeczytaj pełną odpowiedź, już sugeruje usunięcie sudo. W rzeczywistości sudo nie jest takie proste, w wielu przypadkach potrzebujesz nawet sudo -Ewpisu konfiguracji w sudoers.d, aby umożliwić wykonanie bez tty z !requiretty. Ale jest wiele przypadków, w których sudo jest niezbędne do automatycznych wywoływanych skryptów, w których okno dialogowe hasła może przeszkadzać. Dlatego nie usuwałbym go ze standardowego rozwiązania.
Trendfischer
Kod, o którym mowa, jest po prostu błędny - złamie nazwy skryptów lub argumenty spacjami; pamiętaj, że umieszczenie "$@"wewnątrz łańcucha oznacza, że ​​argumenty znajdujące się poza pierwszym są dołączane do oddzielnego ciągu, a nie są w nim zawarte -c. Jeśli chcesz, aby było to bezpieczne, możesz printf -v arg_q '%q ' "$0" "$@"użyćsu "$USERNAME" -c "/usr/bin/bash -l $arg_q"
Charles Duffy
@CharlesDuffy Masz rację! Za bardzo uprościłem mój skrypt produkcyjny dla tej odpowiedzi :-( Samo dodanie a COMMANDARGS=$@rozwiązuje problem z -c. Argumenty ze spacjami nie były wcześniej problemem, ale zaimplementowałem twoje dobre dane wejściowe. Musiałem tylko zrobić kilka eksperymentów, aby to zadziałało. zredagowałem pytanie i mam nadzieję, że nie
wkleiłem