[linux] uid euid??

리눅스 C 라이브러리의 unistd.h에는 getuid , geteuid 가 있다.

이 두 함수의 차이점이 좀 어려운데, 정확하게 알아야 한다.

getuidget user identification의 약어 함수로 사용자의 uid를 정수로 바꾼 값을 반환한다.

리눅스 시스템에서는 권한을 숫자로 표기하는데 숫자가 낮을 수록 권한이 높으며 root는 0 의 값을 가진다.

일반적으로 사용자는 500번대 또는 1000번대의 uid를 가진다.

이는 터미널에서 id 명령어를 통해 확인 할 수 있다.

kimbom@mint ~ $ id
uid=1000(kimbom) gid=1000(kimbom) 그룹들=1000(kimbom),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),110(sambashare)

위에서 sudo 그룹이 27로 되어있는데, 어떻게 sudo가 root권한을 갖는지 아래에서 의문이 풀리게 된다.

간단하게 C언어 코드를 이용해 uid와 euid를 확인해 보자.

#include<stdio.h>       //printf
#include<unistd.h>      //getuid, geteuid
#include<stdlib.h>      //EXIT_SUCCESS
int main(){
        printf("getuid()\t%d\n",getuid());
        printf("geteuid()\t%d\n",geteuid());
        return EXIT_SUCCESS;
}
getuid()    1000
geteuid()    1000

위에서 확인한 바와 같이 kimbom계정에서의 uid와 euid는 모두 1000이 나온다.
그럼 euid는 뭐냐? effective user id이다. effective의 뜻은 여러가지가 있지만, 여기서는 실질적인 이란 뜻으로 사용된다.

effective 뜻 링크

이는 실질적인 사용자 권한을 나타내는 숫자이다. 일반적인 경우에는 uid와 같지만 조금 색다르게 사용이 가능하다.
예를들어 위의 파일들을 ls -l 명령어로 확인 해보자


ls -l

합계 16
-rwxr-xr-x 1 kimbom kimbom 8657  5월 16 22:42 a.out
-rw-r--r-- 1 kimbom kimbom  210  5월 16 22:44 main.c

ls -l에 대해서 혹시 모를수도 있으니 설명하자면 아래와 같은 형식을 띈다.
ls 는 list의 약어로 file listing의 뜻이다.

권한은 첫번째문자는 파일 형식을 나타낸다(-일반 , d디렉토리, b블록구조파일 등….)

뒤로 3글자씩 소유자(user),그룹(group),다른 사용자(others)의 읽기(r),쓰기(w),실행(x)를 나타낸다.

우리가 알아야 할껀 권한 , 소유자 , 그룹 정도이다.

이제 sudo 그룹은 uid가 27인데, sudo로 위의 a.out파일을 실행하면 어떻게 되는지 보자.

getuid()    0
geteuid()    0
어라?

분명히 sudo는 uid가 27인데 어떻게 0이 될 수 있을까? uid에 대해 좀 아는 사람은 uid가 올라갈수는 있지 내려가는건 안된다고 알고 있을것이다.

사실 그게 아니다. uid는 현재 권한이고, euid는 권한을 휘두를수있는 최대 단계? 라고 이해하면 되겠다. 즉 uid는 euid만큼 내려갈 수 있다.

이것이 어떻게 가능한지 살펴보자.

우선 소스를 아래와 같이 수정한다.

#include<stdio.h>       //printf
#include<unistd.h>      //getuid, geteuid, setuid
#include<stdlib.h>      //EXIT_SUCCESS
#include<errno.h>       //perror
int main(){
        printf("getuid()\t%d\n",getuid());
        printf("geteuid()\t%d\n",geteuid());
        if(setuid(25)==0){
                puts("uid change complete!!");
                printf("getuid()\t%d\n",getuid());
                printf("geteuid()\t%d\n",geteuid());
        }else{
                perror("setuid : ");
        }
        return EXIT_SUCCESS;
}

이를 일반 계정인 kimbom으로 실행하면 결과는 아래와 같다.

getuid()    1000
geteuid()    1000
setuid : : Operation not permitted
setuid가 실패했다. 그 이유를 uid때문이라고 생각하면 절대 안된다.

리눅스의 파일권한 시스템에는 755와 같이 3글자로 보통 표기하지만 사실 4글자로 표기된다.(3글자는 축소 표기법이다)

0777 같은 방식으로 표기하는데 뒤의 3개의 숫자는 이미 알고있는 권한들이다.

1777 은 sTicky bits가 붙어있는것이다.

2777 은 sgid가 붙어있는것이고

4777 은 suid가 붙어있는 것이다.


sticky bits는 소유자가 아니면 해당 파일을 삭제하거나 이름변경을 못하게 하는 것이다.

보통 공유 디렉토리를 만들때 사용한다.

home디렉토리에 share라는 디렉토리를 만들고 권한을 1777(sticky bits)로 주었다.

kimbom@mint /home $ ls -l
합계 12
drwxr-xr-x 18 haneul haneul 4096  5월 17 00:55 haneul
drwxr-xr-x 25 kimbom kimbom 4096  5월 17 00:50 kimbom
drwxrwxrwt  2 root   root   4096  5월 17 01:11 share

아래의 명령을 보자.

kimbom@mint /home/share $ ls -l
합계 16
-rwxrwxrwx 1 kimbom kimbom 7  5월 17 01:16 test1
-rwxrwxrwx 1 kimbom kimbom 7  5월 17 01:17 test2
-rw-r--r-- 1 kimbom kimbom 7  5월 17 01:17 test3
-rw-r--r-- 1 kimbom kimbom 7  5월 17 01:17 test4
kimbom@mint /home/share $ rm test4
kimbom@mint /home/share $ ls
test1  test2  test3

share폴더에는 sticky bits가 걸려있다. 소유자만이 해당 폴더 내에서 파일을 지울 수 있다.
이제 다른 계정에서 test1과 test2를 지워보자.(이 파일들은 777이다)

haneul@mint /home/share $ ls -l
합계 12
-rwxrwxrwx 1 kimbom kimbom 7  5월 17 01:16 test1
-rwxrwxrwx 1 kimbom kimbom 7  5월 17 01:17 test2
-rw-r--r-- 1 kimbom kimbom 7  5월 17 01:17 test3
haneul@mint /home/share $ rm test2
rm: `test2'를 지울 수 없음: 명령을 허용하지 않음

그렇다!! 공유 폴더에 걸어놓기 딱 좋은 옵션이다.

파일의 내용을 수정을 할 순 있어도 파일을 삭제가 불가능하다.

그런데 저 파일은 왜 삭제가 안될까? 파일은 sticky bits가 걸리지 않았는데?

답은 파일의 권한보다 디렉토리의 권한이 우선순위가 높기 때문이다.


잠시 이야기가 딴데로 샛는데….. 이제 4777과 같은 suid 설정에 대해 알아보자.

이는 euid를 변경한다.

아래의 명령을 보자.

kimbom@mint ~/hotspring_test $ ls -l
합계 16
-rwxr-xr-x 1 kimbom kimbom 8811  5월 17 01:47 a.out
-rw-r--r-- 1 kimbom kimbom  409  5월 17 00:33 main.c
kimbom@mint ~/hotspring_test $ sudo chown root a.out
kimbom@mint ~/hotspring_test $ sudo chmod u+s a.out
kimbom@mint ~/hotspring_test $ ls -l
합계 16
-rwsr-xr-x 1 root   kimbom 8811  5월 17 01:47 a.out
-rw-r--r-- 1 kimbom kimbom  409  5월 17 00:33 main.c
kimbom@mint ~/hotspring_test $ ./a.out
getuid()    1000
geteuid()    0
uid change complete!!
getuid()    25
geteuid()    25

uid 는 1000인데 euid는 0이 나왔다. 그리고 uid를 변경하는데 성공하였다.

이제 실질적인 권한에 대해 감이 좀 오는가?

그렇다면 sudo 라는 프로세스도 uid는 27 euid는 0이므로 실행은 누구나 할 수 있고

setuid(0); 을통해 root권한으로 승격한뒤 해당 작업을 실행하는것이라고 볼 수 있다.

패스워드를 변경하는 passwd 도 마찬가지이다. euid는 0일 것이다.

아래는 함수에 대한 간략한 설명이다.

gid는 그룹의 권한이라고 생각하면된다 uid와 별반 다르지 않다.