При запуску сценарію через sudo або su я хочу отримати оригінального користувача. Це повинно відбуватися незалежно від множинних sudo
або su
пробігів всередині один одного і конкретно sudo su -
.
Відповіді:
Результати:
Використовуйте who am i | awk '{print $1}'
АБО, logname
оскільки жодні інші методи не гарантуються.
Ви увійшли як самостійно:
evan> echo $USER
evan
evan> echo $SUDO_USER
evan> echo $LOGNAME
evan
evan> whoami
evan
evan> who am i | awk '{print $1}'
evan
evan> logname
evan
evan>
Звичайне судо:
evan> sudo -s
root> echo $USER
root
root> echo $SUDO_USER
evan
root> echo $LOGNAME
root
root> whoami
root
root> who am i | awk '{print $1}'
evan
root> logname
evan
root>
sudo su -:
evan> sudo su -
[root ]# echo $USER
root
[root ]# echo $SUDO_USER
[root ]# echo $LOGNAME
root
[root ]# whoami
root
[root ]# who am i | awk '{print $1}'
evan
[root ]# logname
evan
[root ]#
sudo su -; су том:
evan> sudo su -
[root ]# su tom
tom$ echo $USER
tom
tom$ echo $SUDO_USER
tom$ echo $LOGNAME
tom
tom$ whoami
tom
tom$ who am i | awk '{print $1}'
evan
tom$ logname
evan
tom$
who am i
це те саме, що who smells bad
. Крім того, він працює лише в тому випадку, якщо STDIN
пов'язаний з TTY. Отже, якщо ви запустите echo "hello" | who am i
це просто не буде працювати.
echo "hello" | who am i
працюєте нормально, якщо ваш сценарій не працює в середовищі, де немає терміналу. Тоді ви можете побачити помилку, яка who am i
не працює, тому що існує якась проблема з нечитабельним stdin, і в цьому випадку ви можете спробувати ввести дані до who am i
розчарування, щоб задовольнити його вимоги stdin. tylerl просто зауважує, що він вже пішов цим шляхом, і конвеєр не працюватиме, оскільки stdin повинен бути як читабельним, так і пов'язаним з TTY.
logname
зараз, що, як виявляється, працює, де who am i
ні.
Не існує ідеальної відповіді. Коли ви змінюєте ідентифікатори користувачів, оригінальний ідентифікатор користувача зазвичай не зберігається, тому інформація втрачається. Деякі програми, такі як logname
і who -m
реалізують хак, де вони перевіряють, до якого терміналу підключено stdin
, а потім перевіряють, який користувач входить на цей термінал.
Це рішення часто працює, але не є надійним і, безумовно, не слід вважати безпечним. Наприклад, уявіть, якщо who
виводиться таке:
tom pts/0 2011-07-03 19:18 (1.2.3.4)
joe pts/1 2011-07-03 19:10 (5.6.7.8)
tom
використовується su
для отримання root, і запускає вашу програму. Якщо STDIN
не переспрямовано, програма logname
виведе на зразок програми tom
. Якщо він перенаправляється (наприклад, з файлу) так:
logname < /some/file
Тоді результат " no login name
", оскільки вхід не є терміналом. Однак, що ще цікавіше, той факт, що користувач міг представляти себе іншим зареєстрованим користувачем. Оскільки Джо ввійшов у систему на сторінці pts / 1, Том міг прикинутися ним, запустивши
logname < /dev/pts1
Зараз сказано, що joe
хоча Том керував командою. Іншими словами, якщо ви використовуєте цей механізм у будь-якій ролі безпеки, ви божевільні.
Цю ksh
функцію я писав на HP-UX. Я не знаю, як це буде працювати Bash
в Linux. Ідея полягає в тому, що sudo
процес працює як початковий користувач, а дочірні процеси - цільовий користувач. Повертаючись до батьківських процесів, ми можемо знайти користувача початкового процесу.
#
# The options of ps require UNIX_STD=2003. I am setting it
# in a subshell to avoid having it pollute the parent's namespace.
#
function findUser
{
thisPID=$$
origUser=$(whoami)
thisUser=$origUser
while [ "$thisUser" = "$origUser" ]
do
( export UNIX_STD=2003; ps -p$thisPID -ouser,ppid,pid,comm ) | grep $thisPID | read thisUser myPPid myPid myComm
thisPID=$myPPid
done
if [ "$thisUser" = "root" ]
then
thisUser=$origUser
fi
if [ "$#" -gt "0" ]
then
echo $origUser--$thisUser--$myComm
else
echo $thisUser
fi
return 0
}
Я знаю, що оригінальне запитання було давним-давно, але люди (такі як я) все ще задають, і це виглядало як гарне місце для вирішення проблеми.
Як щодо використання імені журналу (1) для отримання імені користувача для входу?
logname(1)
не працює, але logname
працює - додавання результатів вище
$LOGNAME
але це не спрацювало. Також додано до результатів вище.
logname
ще потрібен tty? З моїми тестами це завжди проходить. (Можливо, я щось не так.) Я запускаю Linux з coreutils 8.26.
THIS_USER=`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`
Це єдине, що мені вдалося.
Функція findUser () користувача user1683793 перенесена bash
та розширена, щоб вона також повертала імена користувачів, що зберігаються в бібліотеках NSS.
#!/bin/bash
function findUser() {
thisPID=$$
origUser=$(whoami)
thisUser=$origUser
while [ "$thisUser" = "$origUser" ]
do
ARR=($(ps h -p$thisPID -ouser,ppid;))
thisUser="${ARR[0]}"
myPPid="${ARR[1]}"
thisPID=$myPPid
done
getent passwd "$thisUser" | cut -d: -f1
}
user=$(findUser)
echo "logged in: $user"
повернення назад і надання списку користувачів
на основі відповіді користувача1683793
Виділяючи процеси, що не належать до TTY, я пропускаю root як ініціатор входу. Я не впевнений, чи може це в якомусь випадку вивести занадто багато
#!/bin/ksh
function findUserList
{
typeset userList prevUser thisPID thisUser myPPid myPid myTTY myComm
thisPID=$$ # starting with this process-ID
while [ "$thisPID" != 1 ] # and cycling back to the origin
do
( ps -p$thisPID -ouser,ppid,pid,tty,comm ) | grep $thisPID | read thisUser myPPid myPid myTTY myComm
thisPID=$myPPid
[[ $myComm =~ ^su ]] && continue # su is always run by root -> skip it
[[ $myTTY == '?' ]] && continue # skip what is running somewhere in the background (without a terminal)
if [[ $prevUser != $thisUser ]]; then # we only want the change of user
prevUser="$thisUser" # keep the user for comparing
userList="${userList:+$userList }$thisUser" # and add the new user to the list
fi
#print "$thisPID=$thisUser: $userList -> $thisUser -> $myComm " >&2
done
print "$userList"
return 0
}
logname
або who am i
не дав мені потрібний відповідь, особливо не в довгих списках su user1
, su user2
, su user3
,...
Я знаю, що оригінальне запитання було давним-давно, але люди (такі як я) все ще задають, і це виглядало як гарне місце для вирішення проблеми.
Альтернатива дзвінкам ps кілька разів: зробіть один дзвінок pstree
pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1
вихід (при вході в систему як парний): (evan)
аргументи pstree:
Отримайте першу зміну користувача (а це вхід) за допомогою grep -o
та head
.
обмеження: команда не може містити жодних фігурних дужок ()
(зазвичай це не відбувається)
У системах, що працюють systemd-logind
, API systemd надає цю інформацію . Якщо ви хочете отримати доступ до цієї інформації зі сценарію оболонки, потрібно використати щось подібне:
$ loginctl session-status \
| (read session_id ignored; loginctl show-session -p User $session_id)
User=1000
Команди session-status
and і show-ssession
system loginctl
мають різну поведінку без аргументів: session-status
використовує поточний сеанс, але show-ssession
використовує менеджер. Однак використання show-session
є кращим для використання сценаріїв завдяки машиночитаному результату. Ось чому loginctl
потрібні два виклики .
who | awk '{print $1}'