Imported Upstream version 1.6.6
[debian/sudo] / set_perms.c
1 /*
2  * Copyright (c) 1994-1996,1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * 4. Products derived from this software may not be called "Sudo" nor
20  *    may "Sudo" appear in their names without specific prior written
21  *    permission from the author.
22  *
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
26  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include "config.h"
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <stdio.h>
41 #ifdef STDC_HEADERS
42 # include <stdlib.h>
43 # include <stddef.h>
44 #else
45 # ifdef HAVE_STDLIB_H
46 #  include <stdlib.h>
47 # endif
48 #endif /* STDC_HEADERS */
49 #ifdef HAVE_STRING_H
50 # include <string.h>
51 #else
52 # ifdef HAVE_STRINGS_H
53 #  include <strings.h>
54 # endif
55 #endif /* HAVE_STRING_H */
56 #ifdef HAVE_UNISTD_H
57 # include <unistd.h>
58 #endif /* HAVE_UNISTD_H */
59 #include <pwd.h>
60 #include <errno.h>
61 #include <grp.h>
62 #ifdef HAVE_LOGIN_CAP_H
63 # include <login_cap.h>
64 #endif
65
66 #include "sudo.h"
67
68 #ifndef lint
69 static const char rcsid[] = "$Sudo: set_perms.c,v 1.12 2002/01/22 02:00:25 millert Exp $";
70 #endif /* lint */
71
72 /*
73  * Prototypes
74  */
75 static void runas_setup         __P((void));
76 static void fatal               __P((char *, int));
77
78 #if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
79 /*
80  * Set real and effective uids and gids based on perm.
81  * Since we have POSIX saved IDs we can get away with just
82  * toggling the effective uid/gid unless we are headed for an exec().
83  */
84 void
85 set_perms_posix(perm, sudo_mode)
86     int perm;
87     int sudo_mode;
88 {
89     int error;
90
91     switch (perm) {
92         case PERM_ROOT:
93                                 if (seteuid(0))
94                                     fatal("seteuid(0) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-saved-ids", 0);
95                                 break;
96
97         case PERM_FULL_ROOT:
98                                 /* headed for exec() */
99                                 (void) seteuid(0);
100                                 if (setuid(0))
101                                     fatal("setuid(0)", 1);
102                                 break;
103
104         case PERM_USER:
105                                 (void) setegid(user_gid);
106                                 if (seteuid(user_uid))
107                                     fatal("seteuid(user_uid)", 1);
108                                 break;
109
110         case PERM_FULL_USER:
111                                 /* headed for exec() */
112                                 (void) setgid(user_gid);
113                                 if (setuid(user_uid))
114                                     fatal("setuid(user_uid)", 1);
115                                 break;
116                                 
117         case PERM_RUNAS:
118                                 /* headed for exec(), assume euid == 0 */
119                                 runas_setup();
120                                 if (def_flag(I_STAY_SETUID))
121                                     error = seteuid(runas_pw->pw_uid);
122                                 else
123                                     error = setuid(runas_pw->pw_uid);
124                                 if (error)
125                                     fatal("unable to change to runas uid", 1);
126                                 break;
127
128         case PERM_SUDOERS:
129                                 /* assume euid == 0, ruid == user */
130                                 if (setegid(SUDOERS_GID))
131                                     fatal("unable to change to sudoers gid", 1);
132
133                                 /*
134                                  * If SUDOERS_UID == 0 and SUDOERS_MODE
135                                  * is group readable we use a non-zero
136                                  * uid in order to avoid NFS lossage.
137                                  * Using uid 1 is a bit bogus but should
138                                  * work on all OS's.
139                                  */
140                                 if (SUDOERS_UID == 0) {
141                                     if ((SUDOERS_MODE & 040) && seteuid(1))
142                                         fatal("seteuid(1)", 1);
143                                 } else {
144                                     if (seteuid(SUDOERS_UID))
145                                         fatal("seteuid(SUDOERS_UID)", 1);
146                                 }
147                                 break;
148     }
149 }
150 #endif /* !NO_SAVED_IDS && _SC_SAVED_IDS && _SC_VERSION */
151
152 #ifdef HAVE_SETREUID
153 /*
154  * Set real and effective uids and gids based on perm.
155  * We always retain a real or effective uid of 0 unless
156  * we are headed for an exec().
157  */
158 void
159 set_perms_fallback(perm, sudo_mode)
160     int perm;
161     int sudo_mode;
162 {
163     int error;
164
165     switch (perm) {
166         case PERM_FULL_ROOT:
167         case PERM_ROOT:
168                                 if (setuid(0))
169                                     fatal("setuid(0) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-setreuid", 0);
170                                 break;
171
172         case PERM_USER:
173                                 (void) setegid(user_gid);
174                                 if (setreuid(0, user_uid))
175                                     fatal("setreuid(0, user_uid)", 1);
176                                 break;
177                                 
178         case PERM_FULL_USER:
179                                 /* headed for exec() */
180                                 (void) setgid(user_gid);
181                                 if (setuid(user_uid))
182                                     fatal("setuid(user_uid)", 1);
183                                 break;
184                                 
185         case PERM_RUNAS:
186                                 /* headed for exec(), assume euid == 0 */
187                                 runas_setup();
188                                 if (def_flag(I_STAY_SETUID))
189                                     error = setreuid(user_uid, runas_pw->pw_uid);
190                                 else
191                                     error = setuid(runas_pw->pw_uid);
192                                 if (error)
193                                     fatal("unable to change to runas uid", 1);
194                                 break;
195
196         case PERM_SUDOERS:
197                                 /* assume euid == 0, ruid == user */
198                                 if (setegid(SUDOERS_GID))
199                                     fatal("unable to change to sudoers gid", 1);
200
201                                 /*
202                                  * If SUDOERS_UID == 0 and SUDOERS_MODE
203                                  * is group readable we use a non-zero
204                                  * uid in order to avoid NFS lossage.
205                                  * Using uid 1 is a bit bogus but should
206                                  * work on all OS's.
207                                  */
208                                 if (SUDOERS_UID == 0) {
209                                     if ((SUDOERS_MODE & 040) && setreuid(0, 1))
210                                         fatal("setreuid(0, 1)", 1);
211                                 } else {
212                                     if (setreuid(0, SUDOERS_UID))
213                                         fatal("setreuid(0, SUDOERS_UID)", 1);
214                                 }
215                                 break;
216     }
217 }
218
219 #else
220
221 /*
222  * Set real and effective uids and gids based on perm.
223  * NOTE: does not support the "stay_setuid" option.
224  */
225 void
226 set_perms_fallback(perm, sudo_mode)
227     int perm;
228     int sudo_mode;
229 {
230
231     /*
232      * Since we only have setuid() and seteuid() we have to set
233      * real and effective uidss to 0 initially.
234      */
235     if (setuid(0))
236         fatal("setuid(0)", 1);
237
238     switch (perm) {
239         case PERM_USER:
240                                 (void) setegid(user_gid);
241                                 if (seteuid(user_uid))
242                                     fatal("seteuid(user_uid)", 1);
243                                 break;
244                                 
245         case PERM_FULL_USER:
246                                 /* headed for exec() */
247                                 (void) setgid(user_gid);
248                                 if (setuid(user_uid))
249                                     fatal("setuid(user_uid)", 1);
250                                 break;
251                                 
252         case PERM_RUNAS:
253                                 /* headed for exec(), assume euid == 0 */
254                                 runas_setup();
255                                 if (setuid(runas_pw->pw_uid))
256                                     fatal("unable to change to runas uid", 1);
257                                 break;
258
259         case PERM_SUDOERS:
260                                 /* assume euid == 0, ruid == user */
261                                 if (setegid(SUDOERS_GID))
262                                     fatal("unable to change to sudoers gid", 1);
263
264                                 /*
265                                  * If SUDOERS_UID == 0 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 == 0) {
272                                     if ((SUDOERS_MODE & 040) && seteuid(1))
273                                         fatal("seteuid(1)", 1);
274                                 } else {
275                                     if (seteuid(SUDOERS_UID))
276                                         fatal("seteuid(SUDOERS_UID)", 1);
277                                 }
278                                 break;
279     }
280 }
281 #endif /* HAVE_SETREUID */
282
283 static void
284 runas_setup()
285 {
286 #ifdef HAVE_LOGIN_CAP_H
287     int error, flags;
288     extern login_cap_t *lc;
289 #endif
290
291     if (runas_pw->pw_name != NULL) {
292 #ifdef HAVE_PAM
293         pam_prep_user(runas_pw);
294 #endif /* HAVE_PAM */
295
296 #ifdef HAVE_LOGIN_CAP_H
297         if (def_flag(I_USE_LOGINCLASS)) {
298             /*
299              * We don't have setusercontext() set the user since we
300              * may only want to set the effective uid.  Depending on
301              * sudoers and/or command line arguments we may not want
302              * setusercontext() to call initgroups().
303              */
304             flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
305             if (!def_flag(I_PRESERVE_GROUPS))
306                 flags |= LOGIN_SETGROUP;
307             else if (setgid(runas_pw->pw_gid))
308                 perror("cannot set gid to runas gid");
309             error = setusercontext(lc, runas_pw,
310                 runas_pw->pw_uid, flags);
311             if (error)
312                 perror("unable to set user context");
313         } else
314 #endif /* HAVE_LOGIN_CAP_H */
315         {
316             if (setgid(runas_pw->pw_gid))
317                 perror("cannot set gid to runas gid");
318 #ifdef HAVE_INITGROUPS
319             /*
320              * Initialize group vector unless asked not to.
321              */
322             if (!def_flag(I_PRESERVE_GROUPS) &&
323                 initgroups(*user_runas, runas_pw->pw_gid) < 0)
324                 perror("cannot set group vector");
325 #endif /* HAVE_INITGROUPS */
326         }
327     }
328 }
329
330 static void
331 fatal(str, printerr)
332     char *str;
333 {
334
335     if (str) {
336         if (printerr)
337             perror(str);
338         else {
339             fputs(str, stderr);
340             fputc('\n', stderr);
341         }
342     }
343     exit(1);
344 }