man pages get built in the build- directories
[debian/sudo] / set_perms.c
1 /*
2  * Copyright (c) 1994-1996,1998-2008 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.44 2008/03/06 17:19:56 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 void
81 set_perms(perm)
82     int perm;
83 {
84     const char *errstr;
85
86     if (perm == current_perm)
87         return;
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;
173 bad:
174     errorx(1, "%s: %s", errstr,
175         errno == EAGAIN ? "too many processes" : strerror(errno));
176 }
177
178 #else
179 # ifdef HAVE_SETREUID
180
181 /*
182  * Set real and effective uids and gids based on perm.
183  * We always retain a real or effective uid of ROOT_UID unless
184  * we are headed for an exec().
185  * This version of set_perms() works fine with the "stay_setuid" option.
186  */
187 void
188 set_perms(perm)
189     int perm;
190 {
191     const char *errstr;
192
193     if (perm == current_perm)
194         return;
195
196     switch (perm) {
197         case PERM_ROOT:
198                                 if (setreuid(-1, ROOT_UID)) {
199                                     errstr = "setreuid(-1, ROOT_UID)";
200                                     goto bad;
201                                 }
202                                 if (setuid(ROOT_UID)) {
203                                     errstr = "setuid(ROOT_UID)";
204                                     goto bad;
205                                 }
206                                 (void) setregid(-1, user_gid);
207                                 if (current_perm == PERM_RUNAS)
208                                     restore_groups();
209                                 break;
210
211         case PERM_USER:
212                                 (void) setregid(-1, user_gid);
213                                 if (setreuid(ROOT_UID, user_uid)) {
214                                     errstr = "setreuid(ROOT_UID, user_uid)";
215                                     goto bad;
216                                 }
217                                 break;
218                                 
219         case PERM_FULL_USER:
220                                 /* headed for exec() */
221                                 (void) setgid(user_gid);
222                                 if (setreuid(user_uid, user_uid)) {
223                                     errstr = "setreuid(user_uid, user_uid)";
224                                     goto bad;
225                                 }
226                                 break;
227                                 
228         case PERM_RUNAS:
229                                 runas_setgroups();
230                                 (void) setregid(-1, runas_gr ?
231                                     runas_gr->gr_gid : runas_pw->pw_gid);
232                                 if (setreuid(-1,
233                                     runas_pw ? runas_pw->pw_uid : user_uid)) {
234                                     errstr = "unable to change to runas uid";
235                                     goto bad;
236                                 }
237                                 break;
238
239         case PERM_FULL_RUNAS:
240                                 /* headed for exec(), assume euid == ROOT_UID */
241                                 runas_setup();
242                                 if (setreuid(def_stay_setuid ? user_uid :
243                                     runas_pw->pw_uid, runas_pw->pw_uid)) {
244                                     errstr = "unable to change to runas uid";
245                                     goto bad;
246                                 }
247                                 break;
248
249         case PERM_SUDOERS:
250                                 /* assume euid == ROOT_UID, ruid == user */
251                                 if (setregid(-1, SUDOERS_GID))
252                                     error(1, "unable to change to sudoers gid");
253
254                                 /*
255                                  * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
256                                  * is group readable we use a non-zero
257                                  * uid in order to avoid NFS lossage.
258                                  * Using uid 1 is a bit bogus but should
259                                  * work on all OS's.
260                                  */
261                                 if (SUDOERS_UID == ROOT_UID) {
262                                     if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
263                                         errstr = "setreuid(ROOT_UID, 1)";
264                                         goto bad;
265                                     }
266                                 } else {
267                                     if (setreuid(ROOT_UID, SUDOERS_UID)) {
268                                         errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
269                                         goto bad;
270                                     }
271                                 }
272                                 break;
273         case PERM_TIMESTAMP:
274                                 if (setreuid(ROOT_UID, timestamp_uid)) {
275                                     errstr = "setreuid(ROOT_UID, timestamp_uid)";
276                                     goto bad;
277                                 }
278                                 break;
279     }
280
281     current_perm = perm;
282     return;
283 bad:
284     errorx(1, "%s: %s", errstr,
285         errno == EAGAIN ? "too many processes" : strerror(errno));
286 }
287
288 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
289 # ifdef HAVE_SETEUID
290
291 /*
292  * Set real and effective uids and gids based on perm.
293  * NOTE: does not support the "stay_setuid" option.
294  */
295 void
296 set_perms(perm)
297     int perm;
298 {
299     const char *errstr;
300
301     if (perm == current_perm)
302         return;
303
304     /*
305      * Since we only have setuid() and seteuid() and semantics
306      * for these calls differ on various systems, we set
307      * real and effective uids to ROOT_UID initially to be safe.
308      */
309     if (seteuid(ROOT_UID)) {
310         errstr = "seteuid(ROOT_UID)";
311         goto bad;
312     }
313     if (setuid(ROOT_UID)) {
314         errstr = "setuid(ROOT_UID)";
315         goto bad;
316     }
317
318     switch (perm) {
319         case PERM_ROOT:
320                                 /* uid set above */
321                                 (void) setegid(user_gid);
322                                 if (current_perm == PERM_RUNAS)
323                                     restore_groups();
324                                 break;
325
326         case PERM_USER:
327                                 (void) setegid(user_gid);
328                                 if (seteuid(user_uid)) {
329                                     errstr = "seteuid(user_uid)";
330                                     goto bad;
331                                 }
332                                 break;
333                                 
334         case PERM_FULL_USER:
335                                 /* headed for exec() */
336                                 (void) setgid(user_gid);
337                                 if (setuid(user_uid)) {
338                                     errstr = "setuid(user_uid)";
339                                     goto bad;
340                                 }
341                                 break;
342                                 
343         case PERM_RUNAS:
344                                 runas_setgroups();
345                                 (void) setegid(runas_gr ?
346                                     runas_gr->gr_gid : runas_pw->pw_gid);
347                                 if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
348                                     errstr = "unable to change to runas uid";
349                                     goto bad;
350                                 }
351                                 break;
352
353         case PERM_FULL_RUNAS:
354                                 /* headed for exec() */
355                                 runas_setup();
356                                 if (setuid(runas_pw->pw_uid)) {
357                                     errstr = "unable to change to runas uid";
358                                     goto bad;
359                                 }
360                                 break;
361
362         case PERM_SUDOERS:
363                                 if (setegid(SUDOERS_GID))
364                                     error(1, "unable to change to sudoers gid");
365
366                                 /*
367                                  * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
368                                  * is group readable we use a non-zero
369                                  * uid in order to avoid NFS lossage.
370                                  * Using uid 1 is a bit bogus but should
371                                  * work on all OS's.
372                                  */
373                                 if (SUDOERS_UID == ROOT_UID) {
374                                     if ((SUDOERS_MODE & 040) && seteuid(1)) {
375                                         errstr = "seteuid(1)";
376                                         goto bad;
377                                     }
378                                 } else {
379                                     if (seteuid(SUDOERS_UID)) {
380                                         errstr = "seteuid(SUDOERS_UID)";
381                                         goto bad;
382                                     }
383                                 }
384                                 break;
385         case PERM_TIMESTAMP:
386                                 if (seteuid(timestamp_uid)) {
387                                     errstr = "seteuid(timestamp_uid)";
388                                     goto bad;
389                                 }
390                                 break;
391     }
392
393     current_perm = perm;
394     return;
395 bad:
396     errorx(1, "%s: %s", errstr,
397         errno == EAGAIN ? "too many processes" : strerror(errno));
398 }
399
400 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
401
402 /*
403  * Set uids and gids based on perm via setuid() and setgid().
404  * NOTE: does not support the "stay_setuid" or timestampowner options.
405  *       Also, SUDOERS_UID and SUDOERS_GID are not used.
406  */
407 void
408 set_perms(perm)
409     int perm;
410 {
411     const char *errstr;
412
413     if (perm == current_perm)
414         return;
415
416     switch (perm) {
417         case PERM_ROOT:
418                                 if (setuid(ROOT_UID)) {
419                                     errstr = "setuid(ROOT_UID)";
420                                     goto bad;
421                                 }
422                                 if (current_perm == PERM_RUNAS)
423                                     restore_groups();
424                                 break;
425
426         case PERM_FULL_USER:
427                                 (void) setgid(user_gid);
428                                 if (setuid(user_uid)) {
429                                     errstr = "setuid(user_uid)";
430                                     goto bad;
431                                 }
432                                 break;
433                                 
434         case PERM_FULL_RUNAS:
435                                 runas_setup();
436                                 if (setuid(runas_pw->pw_uid)) {
437                                     errstr = "unable to change to runas uid";
438                                     goto bad;
439                                 }
440                                 break;
441
442         case PERM_USER:
443         case PERM_SUDOERS:
444         case PERM_RUNAS:
445         case PERM_TIMESTAMP:
446                                 /* Unsupported since we can't set euid. */
447                                 break;
448     }
449
450     current_perm = perm;
451     return;
452 bad:
453     errorx(1, "%s: %s", errstr,
454         errno == EAGAIN ? "too many processes" : strerror(errno));
455 }
456 #  endif /* HAVE_SETEUID */
457 # endif /* HAVE_SETREUID */
458 #endif /* HAVE_SETRESUID */
459
460 #ifdef HAVE_INITGROUPS
461 static void
462 runas_setgroups()
463 {
464     static int ngroups = -1;
465     static GETGROUPS_T *groups;
466     struct passwd *pw;
467
468     if (def_preserve_groups)
469         return;
470
471     /*
472      * Use stashed copy of runas groups if available, else initgroups and stash.
473      */
474     if (ngroups == -1) {
475         pw = runas_pw ? runas_pw : sudo_user.pw;
476         if (initgroups(pw->pw_name, pw->pw_gid) < 0)
477             log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
478         if ((ngroups = getgroups(0, NULL)) < 0)
479             log_error(USE_ERRNO|MSG_ONLY, "can't get runas ngroups");
480         groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
481         if (getgroups(ngroups, groups) < 0)
482             log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
483     } else {
484         if (setgroups(ngroups, groups) < 0)
485             log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
486     }
487 }
488
489 static void
490 restore_groups()
491 {
492     if (setgroups(user_ngroups, user_groups) < 0)
493         log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
494 }
495
496 #else
497
498 static void
499 runas_setgroups()
500 {
501     /* STUB */
502 }
503
504 static void
505 restore_groups()
506 {
507     /* STUB */
508 }
509
510 #endif /* HAVE_INITGROUPS */
511
512 static void
513 runas_setup()
514 {
515     gid_t gid;
516 #ifdef HAVE_LOGIN_CAP_H
517     int flags;
518     extern login_cap_t *lc;
519 #endif
520
521     if (runas_pw->pw_name != NULL) {
522         gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
523 #ifdef HAVE_GETUSERATTR
524         aix_setlimits(runas_pw->pw_name);
525 #endif
526 #ifdef HAVE_PAM
527         pam_prep_user(runas_pw);
528 #endif /* HAVE_PAM */
529
530 #ifdef HAVE_LOGIN_CAP_H
531         if (def_use_loginclass) {
532             /*
533              * We only use setusercontext() set the nice value and rlimits.
534              */
535             flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
536             if (!def_preserve_groups)
537                 SET(flags, LOGIN_SETGROUP);
538             else if (setgid(gid))
539                 warning("cannot set gid to runas gid");
540             if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
541                 if (runas_pw->pw_uid != ROOT_UID)
542                     error(1, "unable to set user context");
543                 else
544                     warning("unable to set user context");
545             }
546         }
547 #endif /* HAVE_LOGIN_CAP_H */
548         if (setgid(gid))
549             warning("cannot set gid to runas gid");
550         /*
551          * Initialize group vector
552          */
553         runas_setgroups();
554     }
555 }