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