spawn.c
1 |
#include <sys/types.h> |
---|---|
2 |
#include <unistd.h> |
3 |
#include <sys/wait.h> |
4 |
#include <string.h> |
5 |
#include <pwd.h> |
6 |
#include <shadow.h> |
7 |
#include <signal.h> |
8 |
#include <grp.h> |
9 |
#include <errno.h> |
10 |
#include <stdio.h> |
11 |
#include <stdlib.h> |
12 |
|
13 |
#define _GNU_SOURCE
|
14 |
#include <crypt.h> |
15 |
|
16 |
//link option: -lm -lcrypt
|
17 |
|
18 |
/** Global data */
|
19 |
struct passwd *pw;
|
20 |
|
21 |
struct spwd *sp;
|
22 |
|
23 |
/**
|
24 |
* Execute a command on a specified user environment.
|
25 |
* A child process is created via fork().
|
26 |
* The child process uid is set to the new user uid.
|
27 |
* The environment is also set for the new user.
|
28 |
*
|
29 |
* @param command
|
30 |
* Command to execute
|
31 |
* @param args
|
32 |
* Command arguments.
|
33 |
|
34 |
* @return child_status
|
35 |
* Child status on exit.
|
36 |
*/
|
37 |
int spawn(char* command, char* args) |
38 |
{ |
39 |
int child_pid, child_status;
|
40 |
|
41 |
child_pid = fork(); |
42 |
if (child_pid == 0) |
43 |
{ |
44 |
if (setgid(pw->pw_gid) < 0 || getgid() != pw->pw_gid || getegid() != pw->pw_gid) |
45 |
perror("Could not setgid");
|
46 |
|
47 |
if (setuid(pw->pw_uid) < 0 || getuid() != pw->pw_uid || geteuid() != pw->pw_uid) |
48 |
perror("Could not setuid");
|
49 |
|
50 |
char* path = strdup(getenv("PATH")); |
51 |
setenv("HOME",pw->pw_dir,1); |
52 |
setenv("USER",pw->pw_name,1); |
53 |
setenv("LOGNAME",pw->pw_name,1); |
54 |
setenv("LOGIN",pw->pw_name,1); /*< Historical; only strictly needed on AIX */ |
55 |
setenv("SHELL", pw->pw_shell[0] ? pw->pw_shell : "/bin/sh",1); |
56 |
setenv("PATH",path,1); |
57 |
free(path); |
58 |
if (chdir(getenv("HOME")) < 0) |
59 |
perror("chdir($HOME)");
|
60 |
|
61 |
execlp(command, args, (char*)0); |
62 |
//perror("execlp()");
|
63 |
_exit(10);
|
64 |
} |
65 |
else if(child_pid < 0) |
66 |
{ |
67 |
_exit(-1);
|
68 |
} |
69 |
else
|
70 |
{ |
71 |
// wait for child to exit
|
72 |
wait(&child_status); |
73 |
} |
74 |
|
75 |
return child_status;
|
76 |
} |
77 |
|
78 |
/**
|
79 |
* Get user informations including uid and password.
|
80 |
* Check if the password match if the user exists
|
81 |
*
|
82 |
* @param username
|
83 |
* User name.
|
84 |
* @param password
|
85 |
* Use password.
|
86 |
|
87 |
* @return 0 - success.
|
88 |
* 1 - user does not exists
|
89 |
* 2 - password doe not match.
|
90 |
*/
|
91 |
int check_user (const char *username, const char *password) |
92 |
{ |
93 |
char *encrypted, *correct;
|
94 |
|
95 |
pw = getpwnam(username); |
96 |
endpwent(); |
97 |
|
98 |
if (!pw) return 1; //user doesn't really exist |
99 |
|
100 |
sp = getspnam(pw->pw_name); |
101 |
endspent(); |
102 |
|
103 |
correct = sp ? sp->sp_pwdp : pw->pw_passwd; |
104 |
encrypted = crypt(password, correct); |
105 |
|
106 |
return strcmp(encrypted, correct) ? 2 : 0; // bad pw=2, success=0 |
107 |
} |
108 |
|
109 |
/**
|
110 |
* Main function.
|
111 |
*
|
112 |
* @param argc
|
113 |
* Number of command line arguments.
|
114 |
* @param argv
|
115 |
* Command line arguments.
|
116 |
*
|
117 |
* @return Exit status
|
118 |
*/
|
119 |
int main(int argc, char *argv[]){ |
120 |
int r, i;
|
121 |
char args[1024] = ""; |
122 |
|
123 |
if(argc < 4) |
124 |
{ |
125 |
printf("Usage: spawn <usr> <psw> <command> [args]\n");
|
126 |
exit(1);
|
127 |
} |
128 |
|
129 |
// build arguments
|
130 |
for(i=3;i< argc;i++) |
131 |
{ |
132 |
strcat(args, argv[i]); |
133 |
if(i < argc-1) |
134 |
strcat(args, " ");
|
135 |
} |
136 |
|
137 |
if(getuid() != 0 || geteuid() != 0) |
138 |
{ |
139 |
printf("Must run as root.\n");
|
140 |
exit(0);
|
141 |
} |
142 |
|
143 |
r = check_user(argv[1],argv[2]); |
144 |
switch(r)
|
145 |
{ |
146 |
case 0: |
147 |
printf("OK UID=%d.\n", pw->pw_uid);
|
148 |
r = spawn(argv[3], args);
|
149 |
break;
|
150 |
case 1: |
151 |
printf("Inavlid username.\n");
|
152 |
break;
|
153 |
case 2: |
154 |
printf("Inavlid password.\n");
|
155 |
break;
|
156 |
} |
157 |
|
158 |
printf("Exit status %d.\n", r);
|
159 |
_exit(r); |
160 |
} |