Как найти исходного пользователя с помощью нескольких команд sudo и su?

При запуске скрипта через sudo или su я хочу получить исходного пользователя. Это должно происходить независимо от нескольких sudo или su прогонов друг в друге и, в частности, sudo su -.


person evan    schedule 04.01.2011    source источник


Ответы (10)


Полученные результаты:

Используйте 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>

судо су - :

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 ]#

судо су -; су том:

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$
person evan    schedule 04.01.2011
comment
В этом случае вы можете просто использовать who | awk '{print $1}' - person SiegeX; 04.01.2011
comment
... если вы единственный, кто вошел в систему (и это только один раз). - person Dennis Williamson; 05.01.2011
comment
все, что вам нужно, это 2 аргумента: who am i совпадает с who smells bad. Кроме того, это работает, только если STDIN связан с TTY. Поэтому, если вы запустите echo "hello" | who am i, это просто не сработает. - person tylerl; 04.07.2011
comment
Это для использования внутри скрипта. Зачем мне запускать echo "hello" | who am i из скрипта?? - person evan; 04.07.2011
comment
Вы бы не запускали echo "hello" | who am i нормально, если бы ваш скрипт не работал в среде, где нет терминала. Затем вы можете увидеть ошибку, что who am i не работает, потому что есть какая-то проблема с нечитаемым стандартным вводом, и в этом случае вы можете попробовать передать данные в who am i из отчаяния, чтобы удовлетворить его требования к стандартному вводу. tylerl просто отмечает, что он уже прошел этот путь, и канал не будет работать, потому что стандартный ввод должен быть доступен для чтения и связан с TTY. - person Edwin Buck; 22.11.2011
comment
Есть ли способ заставить его работать при выполнении скрипта по ssh без шелла, т.е. ssh [email protected] ./myscript.sh? - person Bart van Heukelom; 07.12.2011
comment
@BartvanHeukelom - это если вы не знаете, кто будет использовать скрипт. В вашем случае вы знаете, поэтому просто передайте пользователя в качестве параметра вашего скрипта. ssh [email protected] ./myscript.sh bart - person evan; 07.12.2011
comment
@even Правда, хотя я бы хотел, чтобы для этого требовалось как можно меньше настроек, поэтому сейчас я использую logname, который, как оказалось, работает, а who am i - нет. - person Bart van Heukelom; 07.12.2011
comment
logname имеет ту же проблему, что и @tylerl в отношении who am i: он работает, только если STDIN является TTY. К счастью, это не должно быть проблемой в практических случаях. Другой вариант — stat -c %U "$(readlink /proc/self/fd/0)" с той же оговоркой, но я не вижу преимуществ перед тем, чтобы просто придерживаться logname. - person Wildcard; 13.11.2018

Не существует идеального ответа. При изменении идентификаторов пользователей исходный идентификатор пользователя обычно не сохраняется, поэтому информация теряется. Некоторые программы, такие как 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, несмотря на то, что именно Том запустил команду. Другими словами, если вы используете этот механизм в какой-либо роли безопасности, вы сошли с ума.

person tylerl    schedule 04.07.2011
comment
Если вы запускаете сценарий самостоятельно (о чем свидетельствуют используемые команды), безопасность не является проблемой. Если это так, у вас гораздо больше проблем, поскольку у них также есть доступ к sudo. Человек может просто скопировать сценарий и изменить его по своему усмотрению. Это просто способ получить зарегистрированное имя для использования в скрипте. Или я что-то упускаю из того, что вы говорите? - person evan; 04.07.2011
comment
@evan: наличие доступа к sudo не означает возможность перезаписывать файлы. - person Flimzy; 16.05.2013
comment
@Flimzy В каком случае root не может перезаписывать файлы? - person evan; 18.05.2013
comment
@evan: Каждый раз, когда ваш доступ к sudo не дает вам доступа к оболочке или любой другой команде, которая может перезаписывать файлы, очевидно. - person Flimzy; 19.05.2013
comment
Доступ @evan sudo не всегда (не должен быть в большинстве случаев администратора) полным корневым доступом. Это набор настраиваемых ограниченных контекстов выполнения. - person DylanYoung; 13.08.2019

Это функция 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
}

Я знаю, что первоначальный вопрос был задан давным-давно, но люди (такие как я) все еще спрашивают, и это выглядело как хорошее место для решения.

person user1683793    schedule 19.10.2012

Как насчет использования logname(1) для получения логина пользователя?

person sam    schedule 05.01.2011
comment
logname(1) не работает, а logname работает — добавление результатов выше - person evan; 05.01.2011
comment
изначально я пробовал $LOGNAME, но это не сработало. Также добавлено к результатам выше. - person evan; 05.01.2011
comment
Требуется ли logname телетайп? С моими тестами всегда проходит. (Может быть, я что-то не так.) Я использую Linux с coreutils 8.26. - person simohe; 23.01.2018
comment
Мое имя журнала (GNU coreutils) 8.28 всегда возвращает имя журнала: нет имени для входа (Ubuntu 18.04.2) - person sondra.kinsey; 08.03.2019

Функция 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"
person asdfghjkl    schedule 11.12.2013
comment
К вашему сведению: эта функция (и та, на которой она была основана) не будет циклически проходить через несколько оболочек, порожденных sudo, вложенных друг в друга. - person asdfghjkl; 11.12.2013

вернуться назад и дать список пользователей

на основе ответа пользователя 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, ...

Я знаю, что первоначальный вопрос был задан давным-давно, но люди (такие как я) все еще спрашивают, и это выглядело как хорошее место для решения.

person ULick    schedule 14.04.2017

Альтернатива многократному вызову ps: сделайте один вызов pstree

pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1

вывод (при входе в систему как четный): (evan)

Аргументы pstree:

  • -l: длинные строки (без сокращения)
  • -u: показывать, когда пользователь меняется как (userName)
  • -s $$: показать родителей этого процесса

Получите первое изменение пользователя (которое является логином) с помощью grep -o и head.

ограничение: команда не может содержать фигурные скобки () (обычно их нет)

person simohe    schedule 23.01.2018
comment
pstree -lu -s $$ |head -n1|sed -e 's/[^(]*(([^)]*)).*/\1/' - person Alexx Roche; 19.02.2018

В системах с systemd-logind systemd API предоставляет эту информацию. Если вы хотите получить доступ к этой информации из сценария оболочки, вам нужно использовать что-то вроде этого:

$ loginctl session-status \
  | (read session_id ignored; loginctl show-session -p User $session_id)
User=1000

Системные команды session-status и show-ssession в loginctl ведут себя по-разному без аргументов: session-status использует текущий сеанс, а show-ssession использует менеджер. Однако использование show-session предпочтительнее для использования скрипта из-за его машиночитаемого вывода. Вот почему необходимы два вызова loginctl.

person Florian Weimer    schedule 19.09.2020

Получить его можно у владельца управляющего терминала. Вот старый код C для утилиты whowasi: http://sivann.gr/software/whowasi.c< /а>

person sivann    schedule 21.01.2021

person    schedule
comment
Никаких объяснений и лишь минимальное улучшение по сравнению с существующим ответом - person sondra.kinsey; 08.03.2019