여러 sudo 및 su 명령을 통해 원래 사용자를 어떻게 찾습니까?


93

sudo 또는 su를 통해 스크립트를 실행할 때 원래 사용자를 얻고 싶습니다. 이것은 여러 개 sudo또는 su서로 내부에서 특히 실행에 관계없이 발생해야합니다 sudo su -.

답변:


136

결과 :

다른 방법은 보장되지 않으므로 who am i | awk '{print $1}'OR 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 ]#

sudo su-; 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 2011 년

2
... 로그인 한 사람이 한 번 뿐인 경우.
추후 공지가있을 때까지 일시 중지되었습니다.

9
당신이 필요로하는 모든 2 인자입니다 : who am i와 동일합니다 who smells bad. 또한 STDINTTY와 연결된 경우에만 작동합니다 . 따라서 실행 echo "hello" | who am i하면 작동하지 않습니다.
tylerl 2011

1
echo "hello" | who am i스크립트가 터미널이없는 환경에서 실행되지 않는 한 정상적으로 실행되지 않습니다 . 그런 다음 who am i읽을 수없는 stdin에 어떤 종류의 문제가 있기 때문에 작동하지 않는 오류가 표시 될 수 있습니다. 이 경우 who am istdin 요구 사항을 충족하기 위해 데이터를 파이핑하려고 할 수 있습니다 . tylerl은 그가 이미 그 경로를 따라 왔고 stdin이 읽을 수 있고 TTY와 연결되어야하므로 파이프가 작동하지 않는다는 점을 지적합니다.
Edwin Buck

4
@even True, 가능한 한 적은 구성이 필요하기를 원하므로 지금 사용하고 logname있습니다 who am i.
Bart van Heukelom 2011

18

완벽한 답 은 없습니다 . 사용자 ID를 변경할 때 원래 사용자 ID는 일반적으로 보존되지 않으므로 정보가 손실됩니다. 같은 일부 프로그램, 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)

tomsu루트에 도달하고 프로그램을 실행하는 데 사용 됩니다. 경우 STDIN처럼, 다음 프로그램 리디렉션되지 logname가 출력 tom. 다음과 같이 리디렉션되는 경우 (예 : 파일에서) :

logname < /some/file

no login name입력이 터미널이 아니기 때문에 결과는 " "입니다. 하지만 더 흥미로운 것은 사용자가 다른 로그인 사용자로 위장 할 수 있다는 사실입니다. Joe가 pts / 1에 로그인했기 때문에 Tom은 다음을 실행하여 자신을 가장 할 수 있습니다.

logname < /dev/pts1

이제 joe명령을 실행 한 사람은 톰이라고합니다. 즉, 어떤 종류의 보안 역할에서든이 메커니즘을 사용하면 미친 짓입니다.


2
스크립트를 직접 실행하는 경우 (사용 된 명령에서 알 수 있듯이) 보안이 문제가되지 않습니다. 그렇다면 sudo 액세스 권한도 있기 때문에 더 많은 문제가 있습니다. 그 사람은 스크립트를 복사하여 원하는대로 수정할 수 있습니다. 이것은 단순히 스크립트에서 사용하기 위해 로그인 한 이름을 얻는 방법입니다. 아니면 내가 당신이 말하는 것에 대해 뭔가를 놓치고 있습니까?
evan

1
@evan : sudo 액세스 권한이 있다고해서 파일을 덮어 쓸 수있는 것은 아닙니다.
Flimzy

@Flimzy 어떤 경우에 루트가 파일을 덮어 쓸 수 없는가?
에반

1
@evan : sudo 액세스가 셸 또는 파일을 덮어 쓸 수있는 다른 명령에 대한 액세스 권한을 부여하지 않을 때마다 분명히.
Flimzy

@evan sudo 액세스는 항상 전체 루트 액세스가 아닙니다 (대부분의 관리자의 경우는 안 됨). 구성 가능한 제한된 실행 컨텍스트 집합입니다.
DylanYoung

8

이것은 ksh내가 HP-UX에서 작성한 함수입니다. BashLinux에서 어떻게 작동할지 모르겠습니다 . 아이디어는 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

사용자의 로그인 이름을 얻기 위해 logname (1)을 사용하는 것은 어떻습니까?


logname(1)작동하지 않습니다하지만 logname않습니다 - 위의 결과를 추가
에반

원래 시도 $LOGNAME했지만 작동하지 않았습니다. 또한 위의 결과에 추가되었습니다.
에반

logname여전히 tty가 필요 합니까 ? 내 테스트에서는 항상 통과합니다. (아마 내가 뭔가 잘못했을 수도 있습니다.) coreutils 8.26으로 Linux를 실행하고 있습니다.
simohe

: "아니오 로그인 이름 LOGNAME"(우분투 18.04.2) 항상 내 LOGNAME (GNU의로 coreutils) 8.28 반환
sondra.kinsey


2

user1683793의 findUser () 함수가 포팅 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"

참고 :이 함수 (및 기반이 된 함수)는 서로 중첩 된 sudo에 의해 생성 된 여러 셸을 순환하지 않습니다.
asdfghjkl

2

다시 순환하고 사용자 목록 제공

user1683793의 답변에 따라

비 TTY 프로세스를 제외하여 로그인 시작 자로서 루트를 건너 뜁니다. 어떤 경우에는 너무 많이 빠져 나갈 수 있는지 잘 모르겠습니다

#!/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 -ohead.

제한 : 명령에 중괄호가 포함될 수 없습니다 ()(일반적으로는 아님).


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-statusshow-ssession시스템 명령은 loginctl인수없이 동작이 다릅니다 session-status. 현재 세션을 show-ssession사용 하지만 관리자를 사용합니다. 그러나 show-session컴퓨터에서 읽을 수있는 출력으로 인해 스크립트 사용 에는 using을 사용하는 것이 좋습니다. 이것이 두 번의 호출 loginctl이 필요한 이유 입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.