1 /*
2 * Copyright (c) 1994-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 *
16 * Sponsored in part by the Defense Advanced Research Projects
17 * Agency (DARPA) and Air Force Research Laboratory, Air Force
18 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
19 */
20
21 #include "config.h"
22
23 #include <sys/types.h>
24 #include <sys/param.h>
25 #include <sys/stat.h>
26 #include <stdio.h>
27 #ifdef STDC_HEADERS
28 # include <stdlib.h>
29 # include <stddef.h>
30 #else
31 # ifdef HAVE_STDLIB_H
32 # include <stdlib.h>
33 # endif
34 #endif /* STDC_HEADERS */
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #else
38 # ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 # endif
41 #endif /* HAVE_STRING_H */
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif /* HAVE_UNISTD_H */
45 #include <pwd.h>
46 #include <errno.h>
47 #include <grp.h>
48 #ifdef HAVE_LOGIN_CAP_H
49 # include <login_cap.h>
50 #endif
51
52 #include "sudo.h"
53
54 #ifndef lint
55 static const char rcsid[] = "$Sudo: set_perms.c,v 1.30 2004/05/27 23:12:02 millert Exp $";
56 #endif /* lint */
57
58 #ifdef __TANDEM
59 # define ROOT_UID 65535
60 #else
61 # define ROOT_UID 0
62 #endif
63
64 /*
65 * Prototypes
66 */
67 static void runas_setup __P((void));
68 static void fatal __P((char *, int));
69
70 #if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \
71 !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
72 /*
73 * Set real and effective uids and gids based on perm.
74 * Since we have POSIX saved IDs we can get away with just
75 * toggling the effective uid/gid unless we are headed for an exec().
76 */
77 void
set_perms_posix(perm)78 set_perms_posix(perm)
79 int perm;
80 {
81 int error;
82
83 switch (perm) {
84 case PERM_ROOT:
85 if (seteuid(ROOT_UID))
86 fatal("seteuid(ROOT_UID) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-saved-ids", 0);
87 break;
88
89 case PERM_FULL_ROOT:
90 /* headed for exec() */
91 (void) seteuid(ROOT_UID);
92 if (setuid(ROOT_UID))
93 fatal("setuid(ROOT_UID)", 1);
94 break;
95
96 case PERM_USER:
97 (void) setegid(user_gid);
98 if (seteuid(user_uid))
99 fatal("seteuid(user_uid)", 1);
100 break;
101
102 case PERM_FULL_USER:
103 /* headed for exec() */
104 (void) setgid(user_gid);
105 if (setuid(user_uid))
106 fatal("setuid(user_uid)", 1);
107 break;
108
109 case PERM_RUNAS:
110 if (seteuid(runas_pw->pw_uid))
111 fatal("unable to change to runas uid", 1);
112 break;
113
114 case PERM_FULL_RUNAS:
115 /* headed for exec(), assume euid == ROOT_UID */
116 runas_setup();
117 if (def_stay_setuid)
118 error = seteuid(runas_pw->pw_uid);
119 else
120 error = setuid(runas_pw->pw_uid);
121 if (error)
122 fatal("unable to change to runas uid", 1);
123 break;
124
125 case PERM_SUDOERS:
126 /* assume euid == ROOT_UID, ruid == user */
127 if (setegid(SUDOERS_GID))
128 fatal("unable to change to sudoers gid", 1);
129
130 /*
131 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
132 * is group readable we use a non-zero
133 * uid in order to avoid NFS lossage.
134 * Using uid 1 is a bit bogus but should
135 * work on all OS's.
136 */
137 if (SUDOERS_UID == ROOT_UID) {
138 if ((SUDOERS_MODE & 040) && seteuid(1))
139 fatal("seteuid(1)", 1);
140 } else {
141 if (seteuid(SUDOERS_UID))
142 fatal("seteuid(SUDOERS_UID)", 1);
143 }
144 break;
145 case PERM_TIMESTAMP:
146 if (seteuid(timestamp_uid))
147 fatal("seteuid(timestamp_uid)", 1);
148 break;
149
150 }
151 }
152 #endif /* !NO_SAVED_IDS && _SC_SAVED_IDS && _SC_VERSION */
153
154 #ifdef HAVE_SETRESUID
155 /*
156 * Set real and effective and saved uids and gids based on perm.
157 * We always retain a saved uid of 0 unless we are headed for an exec().
158 * We only flip the effective gid since it only changes for PERM_SUDOERS.
159 * This version of set_perms() works fine with the "stay_setuid" option.
160 */
161 void
set_perms_suid(perm)162 set_perms_suid(perm)
163 int perm;
164 {
165 int error;
166
167 switch (perm) {
168 case PERM_FULL_ROOT:
169 case PERM_ROOT:
170 if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID))
171 fatal("setresuid(ROOT_UID, ROOT_UID, ROOT_UID) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid", 0);
172 break;
173
174 case PERM_USER:
175 (void) setresgid(-1, user_gid, -1);
176 if (setresuid(user_uid, user_uid, ROOT_UID))
177 fatal("setresuid(user_uid, user_uid, ROOT_UID)", 1);
178 break;
179
180 case PERM_FULL_USER:
181 /* headed for exec() */
182 (void) setgid(user_gid);
183 if (setresuid(user_uid, user_uid, user_uid))
184 fatal("setresuid(user_uid, user_uid, user_uid)", 1);
185 break;
186
187 case PERM_RUNAS:
188 if (setresuid(-1, runas_pw->pw_uid, -1))
189 fatal("unable to change to runas uid", 1);
190 break;
191
192 case PERM_FULL_RUNAS:
193 /* headed for exec(), assume euid == ROOT_UID */
194 runas_setup();
195 error = setresuid(def_stay_setuid ?
196 user_uid : runas_pw->pw_uid,
197 runas_pw->pw_uid, runas_pw->pw_uid);
198 if (error)
199 fatal("unable to change to runas uid", 1);
200 break;
201
202 case PERM_SUDOERS:
203 /* assume euid == ROOT_UID, ruid == user */
204 if (setresgid(-1, SUDOERS_GID, -1))
205 fatal("unable to change to sudoers gid", 1);
206
207 /*
208 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
209 * is group readable we use a non-zero
210 * uid in order to avoid NFS lossage.
211 * Using uid 1 is a bit bogus but should
212 * work on all OS's.
213 */
214 if (SUDOERS_UID == ROOT_UID) {
215 if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID))
216 fatal("setresuid(ROOT_UID, 1, ROOT_UID)", 1);
217 } else {
218 if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID))
219 fatal("setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)", 1);
220 }
221 break;
222 case PERM_TIMESTAMP:
223 if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID))
224 fatal("setresuid(ROOT_UID, timestamp_uid, ROOT_UID)", 1);
225 break;
226 }
227 }
228
229 #else
230 # ifdef HAVE_SETREUID
231
232 /*
233 * Set real and effective uids and gids based on perm.
234 * We always retain a real or effective uid of ROOT_UID unless
235 * we are headed for an exec().
236 * This version of set_perms() works fine with the "stay_setuid" option.
237 */
238 void
set_perms_suid(perm)239 set_perms_suid(perm)
240 int perm;
241 {
242 int error;
243
244 switch (perm) {
245 case PERM_FULL_ROOT:
246 case PERM_ROOT:
247 if (setreuid(-1, ROOT_UID))
248 fatal("setreuid(-1, ROOT_UID) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid", 0);
249 if (setuid(ROOT_UID))
250 fatal("setuid(ROOT_UID)", 1);
251 break;
252
253 case PERM_USER:
254 (void) setregid(-1, user_gid);
255 if (setreuid(ROOT_UID, user_uid))
256 fatal("setreuid(ROOT_UID, user_uid)", 1);
257 break;
258
259 case PERM_FULL_USER:
260 /* headed for exec() */
261 (void) setgid(user_gid);
262 if (setreuid(user_uid, user_uid))
263 fatal("setreuid(user_uid, user_uid)", 1);
264 break;
265
266 case PERM_RUNAS:
267 if (setreuid(-1, runas_pw->pw_uid))
268 fatal("unable to change to runas uid", 1);
269 break;
270
271 case PERM_FULL_RUNAS:
272 /* headed for exec(), assume euid == ROOT_UID */
273 runas_setup();
274 error = setreuid(def_stay_setuid ?
275 user_uid : runas_pw->pw_uid,
276 runas_pw->pw_uid);
277 if (error)
278 fatal("unable to change to runas uid", 1);
279 break;
280
281 case PERM_SUDOERS:
282 /* assume euid == ROOT_UID, ruid == user */
283 if (setregid(-1, SUDOERS_GID))
284 fatal("unable to change to sudoers gid", 1);
285
286 /*
287 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
288 * is group readable we use a non-zero
289 * uid in order to avoid NFS lossage.
290 * Using uid 1 is a bit bogus but should
291 * work on all OS's.
292 */
293 if (SUDOERS_UID == ROOT_UID) {
294 if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1))
295 fatal("setreuid(ROOT_UID, 1)", 1);
296 } else {
297 if (setreuid(ROOT_UID, SUDOERS_UID))
298 fatal("setreuid(ROOT_UID, SUDOERS_UID)", 1);
299 }
300 break;
301 case PERM_TIMESTAMP:
302 if (setreuid(ROOT_UID, timestamp_uid))
303 fatal("setreuid(ROOT_UID, timestamp_uid)", 1);
304 break;
305 }
306 }
307
308 # else
309 # ifdef HAVE_SETREUID
310
311 /*
312 * Set real and effective uids and gids based on perm.
313 * NOTE: does not support the "stay_setuid" option.
314 */
315 void
set_perms_nosuid(perm)316 set_perms_nosuid(perm)
317 int perm;
318 {
319
320 /*
321 * Since we only have setuid() and seteuid() we have to set
322 * real and effective uids to ROOT_UID initially.
323 */
324 if (setuid(ROOT_UID))
325 fatal("setuid(ROOT_UID)", 1);
326
327 switch (perm) {
328 case PERM_USER:
329 (void) setegid(user_gid);
330 if (seteuid(user_uid))
331 fatal("seteuid(user_uid)", 1);
332 break;
333
334 case PERM_FULL_USER:
335 /* headed for exec() */
336 (void) setgid(user_gid);
337 if (setuid(user_uid))
338 fatal("setuid(user_uid)", 1);
339 break;
340
341 case PERM_RUNAS:
342 if (seteuid(runas_pw->pw_uid))
343 fatal("unable to change to runas uid", 1);
344 break;
345
346 case PERM_FULL_RUNAS:
347 /* headed for exec(), assume euid == ROOT_UID */
348 runas_setup();
349 if (setuid(runas_pw->pw_uid))
350 fatal("unable to change to runas uid", 1);
351 break;
352
353 case PERM_SUDOERS:
354 /* assume euid == ROOT_UID, ruid == user */
355 if (setegid(SUDOERS_GID))
356 fatal("unable to change to sudoers gid", 1);
357
358 /*
359 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
360 * is group readable we use a non-zero
361 * uid in order to avoid NFS lossage.
362 * Using uid 1 is a bit bogus but should
363 * work on all OS's.
364 */
365 if (SUDOERS_UID == ROOT_UID) {
366 if ((SUDOERS_MODE & 040) && seteuid(1))
367 fatal("seteuid(1)", 1);
368 } else {
369 if (seteuid(SUDOERS_UID))
370 fatal("seteuid(SUDOERS_UID)", 1);
371 }
372 break;
373 case PERM_TIMESTAMP:
374 if (seteuid(timestamp_uid))
375 fatal("seteuid(timestamp_uid)", 1);
376 break;
377 }
378 }
379
380 # else
381
382 /*
383 * Set uids and gids based on perm via setuid() and setgid().
384 * NOTE: does not support the "stay_setuid" or timestampowner options.
385 * Also, SUDOERS_UID and SUDOERS_GID are not used.
386 */
387 void
set_perms_nosuid(perm)388 set_perms_nosuid(perm)
389 int perm;
390 {
391
392 switch (perm) {
393 case PERM_FULL_ROOT:
394 case PERM_ROOT:
395 if (setuid(ROOT_UID))
396 fatal("setuid(ROOT_UID)", 1);
397 break;
398
399 case PERM_FULL_USER:
400 (void) setgid(user_gid);
401 if (setuid(user_uid))
402 fatal("setuid(user_uid)", 1);
403 break;
404
405 case PERM_FULL_RUNAS:
406 runas_setup();
407 if (setuid(runas_pw->pw_uid))
408 fatal("unable to change to runas uid", 1);
409 break;
410
411 case PERM_USER:
412 case PERM_SUDOERS:
413 case PERM_RUNAS:
414 case PERM_TIMESTAMP:
415 /* Unsupported since we can't set euid. */
416 break;
417 }
418 }
419 # endif /* HAVE_SETEUID */
420 # endif /* HAVE_SETREUID */
421 #endif /* HAVE_SETRESUID */
422
423 static void
runas_setup()424 runas_setup()
425 {
426 #ifdef HAVE_LOGIN_CAP_H
427 int error, flags;
428 extern login_cap_t *lc;
429 #endif
430
431 if (runas_pw->pw_name != NULL) {
432 #ifdef HAVE_PAM
433 pam_prep_user(runas_pw);
434 #endif /* HAVE_PAM */
435
436 #ifdef HAVE_LOGIN_CAP_H
437 if (def_use_loginclass) {
438 /*
439 * We don't have setusercontext() set the user since we
440 * may only want to set the effective uid. Depending on
441 * sudoers and/or command line arguments we may not want
442 * setusercontext() to call initgroups().
443 */
444 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
445 if (!def_preserve_groups)
446 SET(flags, LOGIN_SETGROUP);
447 else if (setgid(runas_pw->pw_gid))
448 perror("cannot set gid to runas gid");
449 error = setusercontext(lc, runas_pw,
450 runas_pw->pw_uid, flags);
451 if (error) {
452 if (runas_pw->pw_uid != ROOT_UID)
453 fatal("unable to set user context", 1);
454 else
455 perror("unable to set user context");
456 }
457 } else
458 #endif /* HAVE_LOGIN_CAP_H */
459 {
460 if (setgid(runas_pw->pw_gid))
461 perror("cannot set gid to runas gid");
462 #ifdef HAVE_INITGROUPS
463 /*
464 * Initialize group vector unless asked not to.
465 */
466 if (!def_preserve_groups &&
467 initgroups(*user_runas, runas_pw->pw_gid) < 0)
468 perror("cannot set group vector");
469 #endif /* HAVE_INITGROUPS */
470 }
471 }
472 }
473
474 static void
fatal(str,printerr)475 fatal(str, printerr)
476 char *str;
477 int printerr;
478 {
479
480 if (str) {
481 if (printerr)
482 perror(str);
483 else {
484 fputs(str, stderr);
485 fputc('\n', stderr);
486 }
487 }
488 exit(1);
489 }
490