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

93

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

Эван
источник

Ответы:

136

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

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

Нормальный sudo:

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

судо су -; su tom:

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$
Эван
источник
1
В этом случае вы можете просто использоватьwho | awk '{print $1}'
SiegeX
2
... если вы единственный, кто вошел в систему (и только один раз).
Приостановлено до дальнейшего уведомления.
9
все, что вам нужно, это 2 аргумента: who am iто же, что и who smells bad. Кроме того, он работает, только если STDINон связан с телетайпом. Так что если вы запустите, echo "hello" | who am iэто просто не сработает.
Tylerl 04
1
Вы не сможете работать echo "hello" | who am iнормально, если ваш скрипт не работает в среде, где нет терминала. Затем вы можете увидеть ошибку, которая who am iне работает, потому что существует какая-то проблема с нечитаемым стандартным вводом, и в этом случае вы можете попытаться передать данные по конвейеру who am iот отчаяния, чтобы удовлетворить его требования к стандартному вводу. Тайлерл просто отмечает, что он уже прошел этот путь, и канал не будет работать, потому что stdin должен быть как читаемым, так и связанным с TTY.
Эдвин Бак
4
@even Верно, хотя я бы хотел, чтобы он требовал как можно меньше настроек, поэтому я использую lognameсейчас, что, как оказалось, работает, а где who am i- нет.
Барт ван Хёкелом
18

Нет идеального ответа. При изменении идентификаторов пользователей исходный идентификатор пользователя обычно не сохраняется, поэтому информация теряется. Некоторые программы, такие как lognameи, who -mреализуют взлом, когда они проверяют, какой терминал подключен stdin, а затем проверяют, какой пользователь вошел в систему на этом терминале.

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

Тайлерл
источник
2
Если вы запускаете сценарий самостоятельно (о чем свидетельствуют используемые команды), проблема не в безопасности. Если это так, у вас гораздо больше проблем, поскольку у них также есть доступ к sudo. Человек мог просто скопировать сценарий и изменить его как угодно. Это просто способ получить зарегистрированное имя для использования в скрипте. Или мне что-то не хватает в том, что вы говорите?
Evan
1
@evan: доступ к sudo не означает возможности перезаписывать файлы.
Flimzy
@Flimzy В каком случае root не имеет возможности перезаписывать файлы?
Эван
1
@evan: Каждый раз, когда ваш доступ к sudo не дает вам доступа к оболочке или любой другой команде, которая может перезаписывать файлы, очевидно.
Flimzy
@evan sudo - это не всегда (а не в большинстве случаев администратора) полный root-доступ. Это набор настраиваемых ограниченных контекстов выполнения.
DylanYoung
8

Это 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
}

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

user1683793
источник
5

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

Сэм
источник
logname(1)не работает, но lognameработает - добавляем результаты выше
evan
изначально я пытался, $LOGNAMEно это не сработало. Также добавлено к результатам выше.
Evan
По- lognameпрежнему требуется tty? С моими тестами всегда проходит. (Возможно, я что-то не так.) Я запускаю linux с coreutils 8.26.
simohe
My logname (GNU coreutils) 8.28 on всегда возвращает «logname: no login name» (Ubuntu 18.04.2)
sondra.kinsey 08
5
THIS_USER=`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`

Это единственное, что у меня сработало.

Серый Христофоро
источник
1
Никаких объяснений, и только минимальные улучшения по
сравнению
2

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

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

на основе ответа user1683793

Исключая процессы, не относящиеся к 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,...

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

ULick
источник
2

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

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

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

pstree аргументы:

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

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

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

симохе
источник
pstree -lu -s $$ | head -n1 | sed -e 's / [^ (] * (([^)] *)). * / \ 1 /'
Alexx Roche
0

На системах 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.

Флориан Веймер
источник