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