aboutsummaryrefslogtreecommitdiff
path: root/src/runas.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/runas.c')
-rw-r--r--src/runas.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/src/runas.c b/src/runas.c
new file mode 100644
index 0000000..9d2a6c1
--- /dev/null
+++ b/src/runas.c
@@ -0,0 +1,191 @@
1/* This file is part of genrc
2Copyryght (C) 2018 Sergey Poznyakoff
3License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
4This is free software: you are free to change and redistribute it.
5There is NO WARRANTY, to the extent permitted by law.
6*/
7#include "genrc.h"
8#include <pwd.h>
9#include <grp.h>
10
11static void
12addgid(gid_t **pgv, size_t *pgc, size_t *pgi, gid_t gid)
13{
14 gid_t *gv = *pgv;
15 size_t gc = *pgc;
16 size_t gi = *pgi;
17
18 if (gi == gc)
19 gv = x2nrealloc(gv, &gc, sizeof(gv[0]));
20
21 gv[gi++] = gid;
22 *pgv = gv;
23 *pgc = gc;
24 *pgi = gi;
25}
26
27static int
28member(gid_t *gv, size_t gc, gid_t gid)
29{
30 size_t i;
31
32 for (i = 0; i < gc; i++)
33 if (gv[i] == gid)
34 return 1;
35 return 0;
36}
37
38static size_t
39get_user_groups(const char *user, gid_t **pgv, size_t *pgc)
40{
41 struct group *gr;
42 size_t gi = 0;
43
44 setgrent();
45 while ((gr = getgrent())) {
46 char **p;
47 for (p = gr->gr_mem; *p; p++)
48 if (strcmp(*p, user) == 0)
49 addgid(pgv, pgc, &gi, gr->gr_gid);
50 }
51 endgrent();
52 return gi;
53}
54
55static gid_t
56strtogid(char const *str)
57{
58 struct group *gr;
59
60 if (str[0] == '+') {
61 char *end;
62 unsigned long n;
63
64 errno = 0;
65 n = strtoul(str, &end, 10);
66 if (errno || *end) {
67 genrc_error("invalid group name %s", str);
68 exit(1);
69 }
70
71 gr = getgrgid(n);
72 } else
73 gr = getgrnam(str);
74
75 if (!gr) {
76 genrc_error("%s: no such group", str);
77 exit(1);
78 }
79
80 return gr->gr_gid;
81}
82
83void
84runas(void)
85{
86 struct passwd *pw;
87 uid_t uid;
88 gid_t gid;
89 gid_t *gv;
90 size_t gc, gn;
91 char const *runas_user;
92 char const *runas_groups;
93
94 runas_user = getenv("GENRC_USER");
95 runas_groups = getenv("GENRC_GROUP");
96
97 if (!(runas_user || runas_groups))
98 return;
99 if (getuid() != 0) {
100 genrc_error("not root: can't switch to user privileges");
101 exit(1);
102 }
103
104 if (!runas_user) {
105 pw = getpwuid(0);
106 runas_user = "root";
107 } else if (runas_user[0] == '+') {
108 char *end;
109 unsigned long n;
110
111 errno = 0;
112 n = strtoul(runas_user + 1, &end, 10);
113 if (errno || *end) {
114 genrc_error("invalid user name %s", runas_user);
115 exit(1);
116 }
117
118 pw = getpwuid(n);
119 } else
120 pw = getpwnam(runas_user);
121
122 if (!pw) {
123 genrc_error("%s: no such user", runas_user);
124 exit(1);
125 }
126 runas_user = pw->pw_name;
127
128 uid = pw->pw_uid;
129 gid = pw->pw_gid;
130
131 gv = NULL;
132 gc = 0;
133
134 if (runas_groups && runas_groups[0]) {
135 struct wordsplit ws;
136 size_t i;
137
138 ws.ws_delim = ",";
139 ws.ws_error = genrc_error;
140 if (wordsplit(runas_groups, &ws,
141 WRDSF_NOCMD
142 | WRDSF_NOVAR
143 | WRDSF_DELIM
144 | WRDSF_ENOMEMABRT
145 | WRDSF_SHOWERR
146 | WRDSF_ERROR))
147 exit(1);
148
149 if (ws.ws_wordc == 0) {
150 genrc_error("bad group list: '%s'", runas_groups);
151 exit(1);
152 }
153
154 gid = strtogid(ws.ws_wordv[0]);
155 for (i = 1; i < ws.ws_wordc; i++)
156 addgid(&gv, &gc, &gn, strtogid(ws.ws_wordv[i]));
157
158 wordsplit_free(&ws);
159 }
160
161 if (gc == 0) {
162 gn = get_user_groups(runas_user, &gv, &gc);
163 if (!member(gv, gn, gid))
164 addgid(&gv, &gc, &gn, gid);
165 }
166
167 /* Reset group permissions */
168 if (setgroups(gn, gv)) {
169 system_error(errno, "setgroups");
170 exit(1);
171 }
172 free(gv);
173
174 if (gid) {
175 /* Switch to the user's gid. */
176 if (setgid(gid)) {
177 system_error(errno, "setgid(%lu) failed",
178 (unsigned long) gid);
179 exit(1);
180 }
181 }
182
183 /* Now reset uid */
184 if (uid) {
185 if (setuid(uid)) {
186 system_error(errno, "setuid(%lu) failed: %s",
187 (unsigned long) uid);
188 exit(1);
189 }
190 }
191}

Return to:

Send suggestions and report system problems to the System administrator.