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