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