add doc about interaction with RAMRUN to README.Debian in response to #581393
[debian/sudo] / set_perms.c
1 /*
2  * Copyright (c) 1994-1996,1998-2009 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 #ifdef __TANDEM
55 # define ROOT_UID       65535
56 #else
57 # define ROOT_UID       0
58 #endif
59
60 /*
61  * Prototypes
62  */
63 static void runas_setup         __P((void));
64 static void runas_setgroups     __P((void));
65 static void restore_groups      __P((void));
66
67 static int current_perm = -1;
68
69 #ifdef HAVE_SETRESUID
70 /*
71  * Set real and effective and saved uids and gids based on perm.
72  * We always retain a saved uid of 0 unless we are headed for an exec().
73  * We only flip the effective gid since it only changes for PERM_SUDOERS.
74  * This version of set_perms() works fine with the "stay_setuid" option.
75  */
76 int
77 set_perms(perm)
78     int perm;
79 {
80     const char *errstr;
81     int noexit;
82
83     noexit = ISSET(perm, PERM_NOEXIT);
84     CLR(perm, PERM_MASK);
85
86     if (perm == current_perm)
87         return(1);
88
89     switch (perm) {
90         case PERM_ROOT:
91                                 if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) {
92                                     errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
93                                     goto bad;
94                                 }
95                                 (void) setresgid(-1, user_gid, -1);
96                                 if (current_perm == PERM_RUNAS)
97                                     restore_groups();
98                                 break;
99
100         case PERM_USER:
101                                 (void) setresgid(-1, user_gid, -1);
102                                 if (setresuid(user_uid, user_uid, ROOT_UID)) {
103                                     errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
104                                     goto bad;
105                                 }
106                                 break;
107                                 
108         case PERM_FULL_USER:
109                                 /* headed for exec() */
110                                 (void) setgid(user_gid);
111                                 if (setresuid(user_uid, user_uid, user_uid)) {
112                                     errstr = "setresuid(user_uid, user_uid, user_uid)";
113                                     goto bad;
114                                 }
115                                 break;
116                                 
117         case PERM_RUNAS:
118                                 runas_setgroups();
119                                 (void) setresgid(-1, runas_gr ?
120                                     runas_gr->gr_gid : runas_pw->pw_gid, -1);
121                                 if (setresuid(-1, runas_pw ? runas_pw->pw_uid :
122                                     user_uid, -1)) {
123                                     errstr = "unable to change to runas uid";
124                                     goto bad;
125                                 }
126                                 break;
127
128         case PERM_FULL_RUNAS:
129                                 /* headed for exec(), assume euid == ROOT_UID */
130                                 runas_setup();
131                                 if (setresuid(def_stay_setuid ?
132                                     user_uid : runas_pw->pw_uid,
133                                     runas_pw->pw_uid, runas_pw->pw_uid)) {
134                                     errstr = "unable to change to runas uid";
135                                     goto bad;
136                                 }
137                                 break;
138
139         case PERM_SUDOERS:
140                                 /* assume euid == ROOT_UID, ruid == user */
141                                 if (setresgid(-1, SUDOERS_GID, -1))
142                                     error(1, "unable to change to sudoers gid");
143
144                                 /*
145                                  * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
146                                  * is group readable we use a non-zero
147                                  * uid in order to avoid NFS lossage.
148                                  * Using uid 1 is a bit bogus but should
149                                  * work on all OS's.
150                                  */
151                                 if (SUDOERS_UID == ROOT_UID) {
152                                     if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID)) {
153                                         errstr = "setresuid(ROOT_UID, 1, ROOT_UID)";
154                                         goto bad;
155                                     }
156                                 } else {
157                                     if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) {
158                                         errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
159                                         goto bad;
160                                     }
161                                 }
162                                 break;
163         case PERM_TIMESTAMP:
164                                 if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
165                                     errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
166                                     goto bad;
167                                 }
168                                 break;
169     }
170
171     current_perm = perm;
172     return(1);
173 bad:
174     warningx("%s: %s", errstr,
175         errno == EAGAIN ? "too many processes" : strerror(errno));
176     if (noexit)
177         return(0);
178     exit(1);
179 }
180
181 #else
182 # ifdef HAVE_SETREUID
183
184 /*
185  * Set real and effective uids and gids based on perm.
186  * We always retain a real or effective uid of ROOT_UID unless
187  * we are headed for an exec().
188  * This version of set_perms() works fine with the "stay_setuid" option.
189  */
190 int
191 set_perms(perm)
192     int perm;
193 {
194     const char *errstr;
195     int noexit;
196
197     noexit = ISSET(perm, PERM_NOEXIT);
198     CLR(perm, PERM_MASK);
199
200     if (perm == current_perm)
201         return(1);
202
203     switch (perm) {
204         case PERM_ROOT:
205                                 if (setreuid(-1, ROOT_UID)) {
206                                     errstr = "setreuid(-1, ROOT_UID)";
207                                     goto bad;
208                                 }
209                                 if (setuid(ROOT_UID)) {
210                                     errstr = "setuid(ROOT_UID)";
211                                     goto bad;
212                                 }
213                                 (void) setregid(-1, user_gid);
214                                 if (current_perm == PERM_RUNAS)
215                                     restore_groups();
216                                 break;
217
218         case PERM_USER:
219                                 (void) setregid(-1, user_gid);
220                                 if (setreuid(ROOT_UID, user_uid)) {
221                                     errstr = "setreuid(ROOT_UID, user_uid)";
222                                     goto bad;
223                                 }
224                                 break;
225                                 
226         case PERM_FULL_USER:
227                                 /* headed for exec() */
228                                 (void) setgid(user_gid);
229                                 if (setreuid(user_uid, user_uid)) {
230                                     errstr = "setreuid(user_uid, user_uid)";
231                                     goto bad;
232                                 }
233                                 break;
234                                 
235         case PERM_RUNAS:
236                                 runas_setgroups();
237                                 (void) setregid(-1, runas_gr ?
238                                     runas_gr->gr_gid : runas_pw->pw_gid);
239                                 if (setreuid(-1,
240                                     runas_pw ? runas_pw->pw_uid : user_uid)) {
241                                     errstr = "unable to change to runas uid";
242                                     goto bad;
243                                 }
244                                 break;
245
246         case PERM_FULL_RUNAS:
247                                 /* headed for exec(), assume euid == ROOT_UID */
248                                 runas_setup();
249                                 if (setreuid(def_stay_setuid ? user_uid :
250                                     runas_pw->pw_uid, runas_pw->pw_uid)) {
251                                     errstr = "unable to change to runas uid";
252                                     goto bad;
253                                 }
254                                 break;
255
256         case PERM_SUDOERS:
257                                 /* assume euid == ROOT_UID, ruid == user */
258                                 if (setregid(-1, SUDOERS_GID))
259                                     error(1, "unable to change to sudoers gid");
260
261                                 /*
262                                  * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
263                                  * is group readable we use a non-zero
264                                  * uid in order to avoid NFS lossage.
265                                  * Using uid 1 is a bit bogus but should
266                                  * work on all OS's.
267                                  */
268                                 if (SUDOERS_UID == ROOT_UID) {
269                                     if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
270                                         errstr = "setreuid(ROOT_UID, 1)";
271                                         goto bad;
272                                     }
273                                 } else {
274                                     if (setreuid(ROOT_UID, SUDOERS_UID)) {
275                                         errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
276                                         goto bad;
277                                     }
278                                 }
279                                 break;
280         case PERM_TIMESTAMP:
281                                 if (setreuid(ROOT_UID, timestamp_uid)) {
282                                     errstr = "setreuid(ROOT_UID, timestamp_uid)";
283                                     goto bad;
284                                 }
285                                 break;
286     }
287
288     current_perm = perm;
289     return(1);
290 bad:
291     warningx("%s: %s", errstr,
292         errno == EAGAIN ? "too many processes" : strerror(errno));
293     if (noexit)
294         return(0);
295     exit(1);
296 }
297
298 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
299 # ifdef HAVE_SETEUID
300
301 /*
302  * Set real and effective uids and gids based on perm.
303  * NOTE: does not support the "stay_setuid" option.
304  */
305 int
306 set_perms(perm)
307     int perm;
308 {
309     const char *errstr;
310     int noexit;
311
312     noexit = ISSET(perm, PERM_NOEXIT);
313     CLR(perm, PERM_MASK);
314
315     if (perm == current_perm)
316         return(1);
317
318     /*
319      * Since we only have setuid() and seteuid() and semantics
320      * for these calls differ on various systems, we set
321      * real and effective uids to ROOT_UID initially to be safe.
322      */
323     if (seteuid(ROOT_UID)) {
324         errstr = "seteuid(ROOT_UID)";
325         goto bad;
326     }
327     if (setuid(ROOT_UID)) {
328         errstr = "setuid(ROOT_UID)";
329         goto bad;
330     }
331
332     switch (perm) {
333         case PERM_ROOT:
334                                 /* uid set above */
335                                 (void) setegid(user_gid);
336                                 if (current_perm == PERM_RUNAS)
337                                     restore_groups();
338                                 break;
339
340         case PERM_USER:
341                                 (void) setegid(user_gid);
342                                 if (seteuid(user_uid)) {
343                                     errstr = "seteuid(user_uid)";
344                                     goto bad;
345                                 }
346                                 break;
347                                 
348         case PERM_FULL_USER:
349                                 /* headed for exec() */
350                                 (void) setgid(user_gid);
351                                 if (setuid(user_uid)) {
352                                     errstr = "setuid(user_uid)";
353                                     goto bad;
354                                 }
355                                 break;
356                                 
357         case PERM_RUNAS:
358                                 runas_setgroups();
359                                 (void) setegid(runas_gr ?
360                                     runas_gr->gr_gid : runas_pw->pw_gid);
361                                 if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
362                                     errstr = "unable to change to runas uid";
363                                     goto bad;
364                                 }
365                                 break;
366
367         case PERM_FULL_RUNAS:
368                                 /* headed for exec() */
369                                 runas_setup();
370                                 if (setuid(runas_pw->pw_uid)) {
371                                     errstr = "unable to change to runas uid";
372                                     goto bad;
373                                 }
374                                 break;
375
376         case PERM_SUDOERS:
377                                 if (setegid(SUDOERS_GID))
378                                     error(1, "unable to change to sudoers gid");
379
380                                 /*
381                                  * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
382                                  * is group readable we use a non-zero
383                                  * uid in order to avoid NFS lossage.
384                                  * Using uid 1 is a bit bogus but should
385                                  * work on all OS's.
386                                  */
387                                 if (SUDOERS_UID == ROOT_UID) {
388                                     if ((SUDOERS_MODE & 040) && seteuid(1)) {
389                                         errstr = "seteuid(1)";
390                                         goto bad;
391                                     }
392                                 } else {
393                                     if (seteuid(SUDOERS_UID)) {
394                                         errstr = "seteuid(SUDOERS_UID)";
395                                         goto bad;
396                                     }
397                                 }
398                                 break;
399         case PERM_TIMESTAMP:
400                                 if (seteuid(timestamp_uid)) {
401                                     errstr = "seteuid(timestamp_uid)";
402                                     goto bad;
403                                 }
404                                 break;
405     }
406
407     current_perm = perm;
408     return(1);
409 bad:
410     warningx("%s: %s", errstr,
411         errno == EAGAIN ? "too many processes" : strerror(errno));
412     if (noexit)
413         return(0);
414     exit(1);
415 }
416
417 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
418
419 /*
420  * Set uids and gids based on perm via setuid() and setgid().
421  * NOTE: does not support the "stay_setuid" or timestampowner options.
422  *       Also, SUDOERS_UID and SUDOERS_GID are not used.
423  */
424 int
425 set_perms(perm)
426     int perm;
427 {
428     const char *errstr;
429     int noexit;
430
431     noexit = ISSET(perm, PERM_NOEXIT);
432     CLR(perm, PERM_MASK);
433
434     if (perm == current_perm)
435         return(1);
436
437     switch (perm) {
438         case PERM_ROOT:
439                                 if (setuid(ROOT_UID)) {
440                                     errstr = "setuid(ROOT_UID)";
441                                     goto bad;
442                                 }
443                                 if (current_perm == PERM_RUNAS)
444                                     restore_groups();
445                                 break;
446
447         case PERM_FULL_USER:
448                                 (void) setgid(user_gid);
449                                 if (setuid(user_uid)) {
450                                     errstr = "setuid(user_uid)";
451                                     goto bad;
452                                 }
453                                 break;
454                                 
455         case PERM_FULL_RUNAS:
456                                 runas_setup();
457                                 if (setuid(runas_pw->pw_uid)) {
458                                     errstr = "unable to change to runas uid";
459                                     goto bad;
460                                 }
461                                 break;
462
463         case PERM_USER:
464         case PERM_SUDOERS:
465         case PERM_RUNAS:
466         case PERM_TIMESTAMP:
467                                 /* Unsupported since we can't set euid. */
468                                 break;
469     }
470
471     current_perm = perm;
472     return(1);
473 bad:
474     warningx("%s: %s", errstr,
475         errno == EAGAIN ? "too many processes" : strerror(errno));
476     if (noexit)
477         return(0);
478     exit(1);
479 }
480 #  endif /* HAVE_SETEUID */
481 # endif /* HAVE_SETREUID */
482 #endif /* HAVE_SETRESUID */
483
484 #ifdef HAVE_INITGROUPS
485 static void
486 runas_setgroups()
487 {
488     static int ngroups = -1;
489 #ifdef HAVE_GETGROUPS
490     static GETGROUPS_T *groups;
491 #endif
492     struct passwd *pw;
493
494     if (def_preserve_groups)
495         return;
496
497     /*
498      * Use stashed copy of runas groups if available, else initgroups and stash.
499      */
500     if (ngroups == -1) {
501         pw = runas_pw ? runas_pw : sudo_user.pw;
502         if (initgroups(pw->pw_name, pw->pw_gid) < 0)
503             log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
504 #ifdef HAVE_GETGROUPS
505         if ((ngroups = getgroups(0, NULL)) > 0) {
506             groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
507             if (getgroups(ngroups, groups) < 0)
508                 log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
509         }
510     } else {
511         if (setgroups(ngroups, groups) < 0)
512             log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
513 #endif /* HAVE_GETGROUPS */
514     }
515 }
516
517 static void
518 restore_groups()
519 {
520     if (setgroups(user_ngroups, user_groups) < 0)
521         log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
522 }
523
524 #else
525
526 static void
527 runas_setgroups()
528 {
529     /* STUB */
530 }
531
532 static void
533 restore_groups()
534 {
535     /* STUB */
536 }
537
538 #endif /* HAVE_INITGROUPS */
539
540 static void
541 runas_setup()
542 {
543     gid_t gid;
544 #ifdef HAVE_LOGIN_CAP_H
545     int flags;
546     extern login_cap_t *lc;
547 #endif
548
549     if (runas_pw->pw_name != NULL) {
550         gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
551 #ifdef HAVE_GETUSERATTR
552         aix_setlimits(runas_pw->pw_name);
553 #endif
554 #ifdef HAVE_PAM
555         pam_prep_user(runas_pw);
556 #endif /* HAVE_PAM */
557
558 #ifdef HAVE_LOGIN_CAP_H
559         if (def_use_loginclass) {
560             /*
561              * We only use setusercontext() to set the nice value and rlimits.
562              */
563             flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
564             if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
565                 if (runas_pw->pw_uid != ROOT_UID)
566                     error(1, "unable to set user context");
567                 else
568                     warning("unable to set user context");
569             }
570         }
571 #endif /* HAVE_LOGIN_CAP_H */
572         /*
573          * Initialize group vector
574          */
575         runas_setgroups();
576 #ifdef HAVE_SETEUID
577         if (setegid(gid))
578             warning("cannot set egid to runas gid");
579 #endif
580         if (setgid(gid))
581             warning("cannot set gid to runas gid");
582     }
583 }