-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsu.c
121 lines (92 loc) · 2.63 KB
/
su.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
* Copyright Tian Hao <[email protected]>
* License: GPLv3
* It is a opensource (free) software
*/
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 700
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
extern char **environ;
#define setenv_er(name, value) do { \
if (setenv((name), (value), 1) < 0) \
goto cleanup_save_env_err; \
} while (0);
static char* save_evs[] = { "DISPLAY", "PATH", "TERM", "LANG", "LANGUAGE", "LC_CTYPE",
"LC_NUMERIC", "LC_TIME", "LC_COLLATE", "LC_MONETARY",
"LC_MESSAGES", "LC_PAPER", "LC_NAME", "LC_ADDRESS",
"LC_TELEPHONE", "LC_MEASUREMENT", "LC_IDENTIFICATION",
"LC_ALL", "XAUTHORITY" };
static char* save_evs_values[sizeof(save_evs) / sizeof(char*)];
static int save_env(char* value, int n)
{
char* buffer;
size_t length;
length = strlen(value);
if ((buffer = malloc(length + 1)) == NULL) {
errno = ENOMEM;
return -1;
}
strcpy(buffer, value);
save_evs_values[n] = buffer;
return 0;
}
int switch_user(const char* username)
{
struct passwd* pwd;
memset(save_evs_values, 0, sizeof(save_evs_values));
if ((pwd = getpwnam(username)) == NULL)
return -1;
if (initgroups(pwd->pw_name, pwd->pw_gid) < 0)
return -1;
if ((setgid(pwd->pw_gid) < 0) || (setuid(pwd->pw_uid) < 0))
return -1;
if (chdir(pwd->pw_dir) < 0)
return -1;
int i = 0;
while (environ[i]) {
for (int j = 0; j < (sizeof(save_evs) / sizeof(char*)); j++) {
size_t length = strlen(save_evs[j]);
if ((memcmp(environ[i], save_evs[j], length) == 0)
&& (environ[i][length] == '=')) {
if (save_env(environ[i], j) < 0)
goto cleanup_save_env_err;
}
}
i++;
}
environ = NULL;
setenv_er("HOME", pwd->pw_dir);
setenv_er("USER", pwd->pw_name);
setenv_er("LOGNAME", pwd->pw_name);
setenv_er("SHELL", pwd->pw_shell);
for (int n = 0; n < (sizeof(save_evs) / sizeof(char*)); n++) {
if (save_evs_values[n]) {
char* value = strchr(save_evs_values[n], '=');
if (!value || *value == 0) {
free(save_evs_values[n]);
continue;
}
value++;
setenv_er(save_evs[n], value);
free(save_evs_values[n]);
save_evs_values[n] = NULL;
}
}
return 0;
cleanup_save_env_err:
for (int n = 0; n < (sizeof(save_evs) / sizeof(char*)); n++) {
if (save_evs_values[n])
free(save_evs_values[n]);
}
return -1;
}