Imported Upstream version 1.6.9p17
[debian/sudo] / set_perms.c
1 /*
2  * Copyright (c) 1994-1996,1998-2006 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 #ifdef HAVE_ERR_H
46 # include <err.h>
47 #else
48 # include "emul/err.h"
49 #endif /* HAVE_ERR_H */
50 #include <pwd.h>
51 #include <errno.h>
52 #include <grp.h>
53 #ifdef HAVE_LOGIN_CAP_H
54 # include <login_cap.h>
55 #endif
56
57 #include "sudo.h"
58
59 #ifndef lint
60 __unused static const char rcsid[] = "$Sudo: set_perms.c,v 1.30.2.7 2007/11/27 23:41:23 millert Exp $";
61 #endif /* lint */
62
63 #ifdef __TANDEM
64 # define ROOT_UID       65535
65 #else
66 # define ROOT_UID       0
67 #endif
68
69 /*
70  * Prototypes
71  */
72 static void runas_setup         __P((void));
73 static void runas_setgroups     __P((void));
74 static void restore_groups      __P((void));
75
76 static int current_perm = -1;
77
78 #ifdef HAVE_SETRESUID
79 /*
80  * Set real and effective and saved uids and gids based on perm.
81  * We always retain a saved uid of 0 unless we are headed for an exec().
82  * We only flip the effective gid since it only changes for PERM_SUDOERS.
83  * This version of set_perms() works fine with the "stay_setuid" option.
84  */
85 void
86 set_perms(perm)
87     int perm;
88 {
89     if (perm == current_perm)
90         return;
91
92     switch (perm) {
93         case PERM_ROOT:
94                                 if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID))
95                                     errx(1, "setresuid(ROOT_UID, ROOT_UID, ROOT_UID) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid");
96                                 (void) setresgid(-1, user_gid, -1);
97                                 if (current_perm == PERM_RUNAS)
98                                     restore_groups();
99                                 break;
100
101         case PERM_USER:
102                                 (void) setresgid(-1, user_gid, -1);
103                                 if (setresuid(user_uid, user_uid, ROOT_UID))
104                                     err(1, "setresuid(user_uid, user_uid, ROOT_UID)");
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                                     err(1, "setresuid(user_uid, user_uid, user_uid)");
112                                 break;
113                                 
114         case PERM_RUNAS:
115                                 runas_setgroups();
116                                 (void) setresgid(-1, runas_pw->pw_gid, -1);
117                                 if (setresuid(-1, runas_pw->pw_uid, -1))
118                                     err(1, "unable to change to runas uid");
119                                 break;
120
121         case PERM_FULL_RUNAS:
122                                 /* headed for exec(), assume euid == ROOT_UID */
123                                 runas_setup();
124                                 if (setresuid(def_stay_setuid ?
125                                     user_uid : runas_pw->pw_uid,
126                                     runas_pw->pw_uid, runas_pw->pw_uid))
127                                     err(1, "unable to change to runas uid");
128                                 break;
129
130         case PERM_SUDOERS:
131                                 /* assume euid == ROOT_UID, ruid == user */
132                                 if (setresgid(-1, SUDOERS_GID, -1))
133                                     err(1, "unable to change to sudoers gid");
134
135                                 /*
136                                  * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
137                                  * is group readable we use a non-zero
138                                  * uid in order to avoid NFS lossage.
139                                  * Using uid 1 is a bit bogus but should
140                                  * work on all OS's.
141                                  */
142                                 if (SUDOERS_UID == ROOT_UID) {
143                                     if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID))
144                                         err(1, "setresuid(ROOT_UID, 1, ROOT_UID)");
145                                 } else {
146                                     if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID))
147                                         err(1, "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)");
148                                 }
149                                 break;
150         case PERM_TIMESTAMP:
151                                 if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID))
152                                     err(1, "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)");
153                                 break;
154     }
155
156     current_perm = perm;
157 }
158
159 #else
160 # ifdef HAVE_SETREUID
161
162 /*
163  * Set real and effective uids and gids based on perm.
164  * We always retain a real or effective uid of ROOT_UID unless
165  * we are headed for an exec().
166  * This version of set_perms() works fine with the "stay_setuid" option.
167  */
168 void
169 set_perms(perm)
170     int perm;
171 {
172     if (perm == current_perm)
173         return;
174
175     switch (perm) {
176         case PERM_ROOT:
177                                 if (setreuid(-1, ROOT_UID))
178                                     errx(1, "setreuid(-1, ROOT_UID) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid");
179                                 if (setuid(ROOT_UID))
180                                     err(1, "setuid(ROOT_UID)");
181                                 (void) setregid(-1, user_gid);
182                                 if (current_perm == PERM_RUNAS)
183                                     restore_groups();
184                                 break;
185
186         case PERM_USER:
187                                 (void) setregid(-1, user_gid);
188                                 if (setreuid(ROOT_UID, user_uid))
189                                     err(1, "setreuid(ROOT_UID, user_uid)");
190                                 break;
191                                 
192         case PERM_FULL_USER:
193                                 /* headed for exec() */
194                                 (void) setgid(user_gid);
195                                 if (setreuid(user_uid, user_uid))
196                                     err(1, "setreuid(user_uid, user_uid)");
197                                 break;
198                                 
199         case PERM_RUNAS:
200                                 runas_setgroups();
201                                 (void) setregid(-1, runas_pw->pw_gid);
202                                 if (setreuid(-1, runas_pw->pw_uid))
203                                     err(1, "unable to change to runas uid");
204                                 break;
205
206         case PERM_FULL_RUNAS:
207                                 /* headed for exec(), assume euid == ROOT_UID */
208                                 runas_setup();
209                                 if (setreuid(def_stay_setuid ? user_uid :
210                                     runas_pw->pw_uid, runas_pw->pw_uid))
211                                     err(1, "unable to change to runas uid");
212                                 break;
213
214         case PERM_SUDOERS:
215                                 /* assume euid == ROOT_UID, ruid == user */
216                                 if (setregid(-1, SUDOERS_GID))
217                                     err(1, "unable to change to sudoers gid");
218
219                                 /*
220                                  * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
221                                  * is group readable we use a non-zero
222                                  * uid in order to avoid NFS lossage.
223                                  * Using uid 1 is a bit bogus but should
224                                  * work on all OS's.
225                                  */
226                                 if (SUDOERS_UID == ROOT_UID) {
227                                     if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1))
228                                         err(1, "setreuid(ROOT_UID, 1)");
229                                 } else {
230                                     if (setreuid(ROOT_UID, SUDOERS_UID))
231                                         err(1, "setreuid(ROOT_UID, SUDOERS_UID)");
232                                 }
233                                 break;
234         case PERM_TIMESTAMP:
235                                 if (setreuid(ROOT_UID, timestamp_uid))
236                                     err(1, "setreuid(ROOT_UID, timestamp_uid)");
237                                 break;
238     }
239
240     current_perm = perm;
241 }
242
243 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
244 # ifdef HAVE_SETEUID
245
246 /*
247  * Set real and effective uids and gids based on perm.
248  * NOTE: does not support the "stay_setuid" option.
249  */
250 void
251 set_perms(perm)
252     int perm;
253 {
254     if (perm == current_perm)
255         return;
256
257     /*
258      * Since we only have setuid() and seteuid() and semantics
259      * for these calls differ on various systems, we set
260      * real and effective uids to ROOT_UID initially to be safe.
261      */
262     if (seteuid(ROOT_UID))
263         err(1, "seteuid(ROOT_UID)");
264     if (setuid(ROOT_UID))
265         err(1, "setuid(ROOT_UID)");
266
267     switch (perm) {
268         case PERM_ROOT:
269                                 /* uid set above */
270                                 (void) setegid(user_gid);
271                                 if (current_perm == PERM_RUNAS)
272                                     restore_groups();
273                                 break;
274
275         case PERM_USER:
276                                 (void) setegid(user_gid);
277                                 if (seteuid(user_uid))
278                                     err(1, "seteuid(user_uid)");
279                                 break;
280                                 
281         case PERM_FULL_USER:
282                                 /* headed for exec() */
283                                 (void) setgid(user_gid);
284                                 if (setuid(user_uid))
285                                     err(1, "setuid(user_uid)");
286                                 break;
287                                 
288         case PERM_RUNAS:
289                                 runas_setgroups();
290                                 (void) setegid(runas_pw->pw_gid);
291                                 if (seteuid(runas_pw->pw_uid))
292                                     err(1, "unable to change to runas uid");
293                                 break;
294
295         case PERM_FULL_RUNAS:
296                                 /* headed for exec() */
297                                 runas_setup();
298                                 if (setuid(runas_pw->pw_uid))
299                                     err(1, "unable to change to runas uid");
300                                 break;
301
302         case PERM_SUDOERS:
303                                 if (setegid(SUDOERS_GID))
304                                     err(1, "unable to change to sudoers gid");
305
306                                 /*
307                                  * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
308                                  * is group readable we use a non-zero
309                                  * uid in order to avoid NFS lossage.
310                                  * Using uid 1 is a bit bogus but should
311                                  * work on all OS's.
312                                  */
313                                 if (SUDOERS_UID == ROOT_UID) {
314                                     if ((SUDOERS_MODE & 040) && seteuid(1))
315                                         err(1, "seteuid(1)");
316                                 } else {
317                                     if (seteuid(SUDOERS_UID))
318                                         err(1, "seteuid(SUDOERS_UID)");
319                                 }
320                                 break;
321         case PERM_TIMESTAMP:
322                                 if (seteuid(timestamp_uid))
323                                     err(1, "seteuid(timestamp_uid)");
324                                 break;
325     }
326
327     current_perm = perm;
328 }
329
330 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
331
332 /*
333  * Set uids and gids based on perm via setuid() and setgid().
334  * NOTE: does not support the "stay_setuid" or timestampowner options.
335  *       Also, SUDOERS_UID and SUDOERS_GID are not used.
336  */
337 void
338 set_perms(perm)
339     int perm;
340 {
341     if (perm == current_perm)
342         return;
343
344     switch (perm) {
345         case PERM_ROOT:
346                                 if (setuid(ROOT_UID))
347                                         err(1, "setuid(ROOT_UID)");
348                                 if (current_perm == PERM_RUNAS)
349                                     restore_groups();
350                                 break;
351
352         case PERM_FULL_USER:
353                                 (void) setgid(user_gid);
354                                 if (setuid(user_uid))
355                                     err(1, "setuid(user_uid)");
356                                 break;
357                                 
358         case PERM_FULL_RUNAS:
359                                 runas_setup();
360                                 if (setuid(runas_pw->pw_uid))
361                                     err(1, "unable to change to runas uid");
362                                 break;
363
364         case PERM_USER:
365         case PERM_SUDOERS:
366         case PERM_RUNAS:
367         case PERM_TIMESTAMP:
368                                 /* Unsupported since we can't set euid. */
369                                 break;
370     }
371
372     current_perm = perm;
373 }
374 #  endif /* HAVE_SETEUID */
375 # endif /* HAVE_SETREUID */
376 #endif /* HAVE_SETRESUID */
377
378 #ifdef HAVE_INITGROUPS
379 static void
380 runas_setgroups()
381 {
382     static int ngroups = -1;
383     static GETGROUPS_T *groups;
384     struct passwd *pw;
385
386     if (def_preserve_groups)
387         return;
388
389     /*
390      * Use stashed copy of runas groups if available, else initgroups and stash.
391      */
392     if (ngroups == -1) {
393         pw = runas_pw ? runas_pw : sudo_user.pw;
394         if (initgroups(pw->pw_name, pw->pw_gid) < 0)
395             log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
396         if ((ngroups = getgroups(0, NULL)) < 0)
397             log_error(USE_ERRNO|MSG_ONLY, "can't get runas ngroups");
398         groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
399         if (getgroups(ngroups, groups) < 0)
400             log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
401     } else {
402         if (setgroups(ngroups, groups) < 0)
403             log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
404     }
405 }
406
407 static void
408 restore_groups()
409 {
410     if (setgroups(user_ngroups, user_groups) < 0)
411         log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
412 }
413
414 #else
415
416 static void
417 runas_setgroups()
418 {
419     /* STUB */
420 }
421
422 static void
423 restore_groups()
424 {
425     /* STUB */
426 }
427
428 #endif /* HAVE_INITGROUPS */
429
430 static void
431 runas_setup()
432 {
433 #ifdef HAVE_LOGIN_CAP_H
434     int flags;
435     extern login_cap_t *lc;
436 #endif
437
438     if (runas_pw->pw_name != NULL) {
439 #ifdef HAVE_PAM
440         pam_prep_user(runas_pw);
441 #endif /* HAVE_PAM */
442
443 #ifdef HAVE_LOGIN_CAP_H
444         if (def_use_loginclass) {
445             /*
446              * We only use setusercontext() set the nice value and rlimits.
447              */
448             flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
449             if (!def_preserve_groups)
450                 SET(flags, LOGIN_SETGROUP);
451             else if (setgid(runas_pw->pw_gid))
452                 warn("cannot set gid to runas gid");
453             if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
454                 if (runas_pw->pw_uid != ROOT_UID)
455                     err(1, "unable to set user context");
456                 else
457                     warn("unable to set user context");
458             }
459         }
460 #endif /* HAVE_LOGIN_CAP_H */
461         if (setgid(runas_pw->pw_gid))
462             warn("cannot set gid to runas gid");
463         /*
464          * Initialize group vector unless asked not to.
465          */
466         runas_setgroups();
467     }
468 }