Project

General

Profile

spawn.c

Marius Gligor, 11/21/2013 01:22 PM

Download (3.42 KB)

 
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
}