Як знайти початкового користувача за допомогою декількох команд 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>

Звичайне судо:

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$

1
У цьому випадку ви можете просто скористатисяwho | awk '{print $1}'
SiegeX

2
... якщо ви єдиний, хто ввійшов (і це лише один раз).
Призупинено до подальшого повідомлення.

9
потрібні лише 2 аргументи: who am iце те саме, що who smells bad. Крім того, він працює лише в тому випадку, якщо STDINпов'язаний з TTY. Отже, якщо ви запустите echo "hello" | who am iце просто не буде працювати.
tylerl

1
Ви не echo "hello" | who am iпрацюєте нормально, якщо ваш сценарій не працює в середовищі, де немає терміналу. Тоді ви можете побачити помилку, яка who am iне працює, тому що існує якась проблема з нечитабельним stdin, і в цьому випадку ви можете спробувати ввести дані до who am iрозчарування, щоб задовольнити його вимоги stdin. tylerl просто зауважує, що він вже пішов цим шляхом, і конвеєр не працюватиме, оскільки stdin повинен бути як читабельним, так і пов'язаним з TTY.
Едвін Бак,

4
@even Правда, хоча я хотів би, щоб це вимагало якомога менше конфігурації, тому я використовую lognameзараз, що, як виявляється, працює, де who am iні.
Барт ван Хойкелом,

18

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


2
Якщо ви запускаєте сценарій самостійно (про що свідчать використовувані команди), проблема не в проблемі. Якщо це так, у вас набагато більше проблем, оскільки вони також мають доступ до sudo. Людина могла просто скопіювати сценарій та модифікувати його будь-яким способом, яким завгодно. Це просто спосіб отримати зареєстроване ім’я для використання в сценарії. Або мені щось не вистачає у тому, що ви говорите?
evan

1
@evan: Наявність доступу sudo не означає можливості перезаписувати файли.
Неміцний

@Flimzy У якому випадку root не має можливості перезаписати файли?
Еван,

1
@evan: Очевидно, що коли ваш доступ до sudo не дає вам доступу до оболонки або будь-якої іншої команди, яка може перезаписати файли.
Неміцний

Доступ до @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
}

Я знаю, що оригінальне запитання було давним-давно, але люди (такі як я) все ще задають, і це виглядало як гарне місце для вирішення проблеми.


5

Як щодо використання імені журналу (1) для отримання імені користувача для входу?


logname(1)не працює, але lognameпрацює - додавання результатів вище
Еван

спочатку я намагався, $LOGNAMEале це не спрацювало. Також додано до результатів вище.
Еван

Все lognameще потрібен tty? З моїми тестами це завжди проходить. (Можливо, я щось не так.) Я запускаю Linux з coreutils 8.26.
simohe

Моє ім'я журналу (GNU coreutils) 8.28 завжди повертає "ім'я журналу: немає імені для входу" (Ubuntu 18.04.2)
sondra.kinsey


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"

FYI: ця функція (і та, на якій вона базувалася) не буде циклічно повертатися через кілька оболонок, породжених sudo, вкладеними одна в одну.
asdfghjkl

2

повернення назад і надання списку користувачів

на основі відповіді користувача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,...

Я знаю, що оригінальне запитання було давним-давно, але люди (такі як я) все ще задають, і це виглядало як гарне місце для вирішення проблеми.


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, API systemd надає цю інформацію . Якщо ви хочете отримати доступ до цієї інформації зі сценарію оболонки, потрібно використати щось подібне:

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

Команди session-statusand і show-ssessionsystem loginctlмають різну поведінку без аргументів: session-statusвикористовує поточний сеанс, але show-ssessionвикористовує менеджер. Однак використання show-sessionє кращим для використання сценаріїв завдяки машиночитаному результату. Ось чому loginctlпотрібні два виклики .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.