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