로컬로 로그인일 경우 명령을 실행하는 코드 소스

[code:1zfl38og]
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <utmp.h>

int *get_ppids(int pid) {
char buf[128];
int *a_ppid;
int *p_ppid;
int n=0;
FILE *fp;
a_ppid=malloc(sizeof(int)*128);
p_ppid=a_ppid;

while(pid&gt;1) {
	sprintf(buf, &quot;/proc/%d/stat&quot;, (int)pid);
	fp=fopen(buf, &quot;r&quot;);
	if(fp == NULL) break;

	fscanf(fp, &quot;%*d %*s %*s %d&quot;, &amp;pid);
	fclose(fp);
	if (pid&lt;1) break;

	*p_ppid++=(int)pid;
}
*p_ppid=0;
return a_ppid;

}

int is_local_tty() {
char *s=ttyname(0);
struct utmp *ut;
int len=0;
int *xpid,*xpid0;
pid_t ppid=getppid();

if (s==NULL) return 0;

while ( (ut=getutent()) &amp;&amp; ut-&gt;ut_name&#91;0&#93;!='\0') {		
	xpid=xpid0=get_ppids((int)ppid);
	while(*xpid!=0) {
		if (ut-&gt;ut_pid==*xpid++
			&amp;&amp; (ut-&gt;ut_host&#91;0&#93;=='\0'|| ut-&gt;ut_host&#91;0&#93;=='&#58;') 
		)
		{
			free(xpid0);
			endutent();
			return 1;
		}
	}
	free(xpid0);
}
endutent();
return 0;

}
int main(int argc, char *argv[], char *env[]) {
char *p[argc];
int i;
if (argc<2) {
fputs("Commands not specified.\n",stderr);
return 1;
}

if (!is_local_tty()) {
	fputs(&quot;Must run at local computer&#46;\n&quot;,stderr);
	return 1;
}
for(i=0;i&lt;argc-1;i++) {
	p&#91;i&#93;=argv&#91;i+1&#93;;
}
p&#91;argc-1&#93;=NULL;
execvpe(argv&#91;1&#93;, p, env);

}
[/code:1zfl38og]

[code:1zfl38og]코드의 원리는 다음과 같고... 이것은 로컬에서 실행할 경우, 루트권한으로 실행하기 위해 코딩하였습니다.
즉, 이 코드의 컴파일 결과 실행파일의 소유권을 root로 하고,
chmod +s로 setuid비트를 켜서, 누가 실행하던 루트로 실행하게 하기 위함이며,
단 보안상 문제로, 프로그램 자체에서 로컬 로그인 여부를 판단합니다.

1. 현재 코드의 ppid(parent process id)를 얻음
2. ppid를 기준으로 모든 부모 pid들을 얻음
3. utmp의 pid를 검색하여 모든 부모 pid 중 일치값을 찾음
4. 일치한 결과에 대해 host값이 없거나 콜론으로 시작하는 값이면 로컬에서 실행한 것으로 판단
5. 매개변수로 받은 명령 및 매개변수를 실행.

정의한 is_local_tty 함수는
현재 프로그램이 로컬에서 실행되고 있는지 확인합니다.

ttyname 함수는
파일디스크립터를 매개변수로 하여, tty값을 리턴합니다.
여기서는 0 즉, 표준입력의 tty값을 넘겼습니다.
파이프라인으로 프로그램을 실행하면 리턴값이 없습니다.
그래서, 파이프라인으로 실행되는 것을 막기위해 사용하였습니다.

getppid 함수는 현재프로그램의 ppid를 리턴합니다.(getpid함수는 현재 pid리턴)

정의한 get_ppids 함수는
주어진 pid(Process ID)를 기준으로 역으로 부모 pid를 찾아서 정수형포인터배열을 리턴합니다

구조체 utmp는 로그인 정보를 담습니다 (/var/run/utmp는 현재상황, /var/log/wtmp는 과거이력포함)
멤버 ut_pid 는 로그인한 프로그램의 process id
멤버 ut_host는 접속한 위치를 나타냅니다.
(이때, 로컬 콘솔 로그인이면 값이 없고,
그래픽 환경으로 로그인하면 DISPLAY 환경변수 값이 저장됩니다.
그리고 DISPLAY 환경변수는 로컬의 경우, :번호 로 나타납니다.
그래서 이런 점을 이용해서 로컬인지 확인합니다.)

getutent 함수는 utmp 구조체의 포인터를 리턴합니다.
endutent 함수는 열어 놓은 utmp 파일을 닫습니다.[/code:1zfl38og]