Project

General

Profile

spawn.c

Marius Gligor, 11/22/2013 11:38 AM

Download (4.15 KB)

 
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
}