Whoops, typo.
[ira/wip.git] / source3 / lib / util_sec.c
1 /*
2    Unix SMB/CIFS implementation.
3    Copyright (C) Jeremy Allison 1998.
4    rewritten for version 2.0.6 by Tridge
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #ifndef AUTOCONF_TEST
22 #include "includes.h"
23 #else
24 /* we are running this code in autoconf test mode to see which type of setuid
25    function works */
26 #if defined(HAVE_UNISTD_H)
27 #include <unistd.h>
28 #endif
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <errno.h>
33
34 #ifdef HAVE_SYS_PRIV_H
35 #include <sys/priv.h>
36 #endif
37 #ifdef HAVE_SYS_ID_H
38 #include <sys/id.h>
39 #endif
40
41 #define DEBUG(x, y) printf y
42 #define smb_panic(x) exit(1)
43 #define BOOL int
44 #endif
45
46 /* are we running as non-root? This is used by the regresison test code,
47    and potentially also for sites that want non-root smbd */
48 static uid_t initial_uid;
49 static gid_t initial_gid;
50
51 static BOOL sec_initialised;
52
53 /****************************************************************************
54 remember what uid we got started as - this allows us to run correctly
55 as non-root while catching trapdoor systems
56 ****************************************************************************/
57 void sec_init(void)
58 {
59         initial_uid = geteuid();
60         initial_gid = getegid();
61
62         sec_initialised = True;
63 }
64
65 /****************************************************************************
66 some code (eg. winbindd) needs to know what uid we started as
67 ****************************************************************************/
68 uid_t sec_initial_uid(void)
69 {
70         if (!sec_initialised)
71                 smb_panic("sec_initial_uid() called before sec_init()\n");
72
73         return initial_uid;
74 }
75
76 /****************************************************************************
77 some code (eg. winbindd, profiling shm) needs to know what gid we started as
78 ****************************************************************************/
79 gid_t sec_initial_gid(void)
80 {
81         if (!sec_initialised)
82                 smb_panic("sec_initial_gid() called before sec_init()\n");
83
84         return initial_gid;
85 }
86
87 /****************************************************************************
88 are we running in non-root mode?
89 ****************************************************************************/
90 BOOL non_root_mode(void)
91 {
92         if (!sec_initialised)
93                 smb_panic("non_root_mode() called before sec_init()\n");
94
95         return (initial_uid != (uid_t)0);
96 }
97
98 /****************************************************************************
99 abort if we haven't set the uid correctly
100 ****************************************************************************/
101 static void assert_uid(uid_t ruid, uid_t euid)
102 {
103         if ((euid != (uid_t)-1 && geteuid() != euid) ||
104             (ruid != (uid_t)-1 && getuid() != ruid)) {
105                 if (!non_root_mode()) {
106                         DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
107                                  (int)ruid, (int)euid,
108                                  (int)getuid(), (int)geteuid()));
109                         smb_panic("failed to set uid\n");
110                         exit(1);
111                 }
112         }
113 }
114
115 /****************************************************************************
116 abort if we haven't set the gid correctly
117 ****************************************************************************/
118 static void assert_gid(gid_t rgid, gid_t egid)
119 {
120         if ((egid != (gid_t)-1 && getegid() != egid) ||
121             (rgid != (gid_t)-1 && getgid() != rgid)) {
122                 if (!non_root_mode()) {
123                         DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
124                                  (int)rgid, (int)egid,
125                                  (int)getgid(), (int)getegid(),
126                                  (int)getuid(), (int)geteuid()));
127                         smb_panic("failed to set gid\n");
128                         exit(1);
129                 }
130         }
131 }
132
133 /****************************************************************************
134  Gain root privilege before doing something. 
135  We want to end up with ruid==euid==0
136 ****************************************************************************/
137 void gain_root_privilege(void)
138 {       
139 #if USE_SETRESUID
140         setresuid(0,0,0);
141 #endif
142     
143 #if USE_SETEUID
144         seteuid(0);
145 #endif
146
147 #if USE_SETREUID
148         setreuid(0, 0);
149 #endif
150
151 #if USE_SETUIDX
152         setuidx(ID_EFFECTIVE, 0);
153         setuidx(ID_REAL, 0);
154 #endif
155
156         /* this is needed on some systems */
157         setuid(0);
158
159         assert_uid(0, 0);
160 }
161
162
163 /****************************************************************************
164  Ensure our real and effective groups are zero.
165  we want to end up with rgid==egid==0
166 ****************************************************************************/
167 void gain_root_group_privilege(void)
168 {
169 #if USE_SETRESUID
170         setresgid(0,0,0);
171 #endif
172
173 #if USE_SETREUID
174         setregid(0,0);
175 #endif
176
177 #if USE_SETEUID
178         setegid(0);
179 #endif
180
181 #if USE_SETUIDX
182         setgidx(ID_EFFECTIVE, 0);
183         setgidx(ID_REAL, 0);
184 #endif
185
186         setgid(0);
187
188         assert_gid(0, 0);
189 }
190
191
192 /****************************************************************************
193  Set *only* the effective uid.
194  we want to end up with ruid==0 and euid==uid
195 ****************************************************************************/
196 void set_effective_uid(uid_t uid)
197 {
198 #if USE_SETRESUID
199         setresuid(-1,uid,-1);
200 #endif
201
202 #if USE_SETREUID
203         setreuid(-1,uid);
204 #endif
205
206 #if USE_SETEUID
207         seteuid(uid);
208 #endif
209
210 #if USE_SETUIDX
211         setuidx(ID_EFFECTIVE, uid);
212 #endif
213
214         assert_uid(-1, uid);
215 }
216
217 /****************************************************************************
218  Set *only* the effective gid.
219  we want to end up with rgid==0 and egid==gid
220 ****************************************************************************/
221 void set_effective_gid(gid_t gid)
222 {
223 #if USE_SETRESUID
224         setresgid(-1,gid,-1);
225 #endif
226
227 #if USE_SETREUID
228         setregid(-1,gid);
229 #endif
230
231 #if USE_SETEUID
232         setegid(gid);
233 #endif
234
235 #if USE_SETUIDX
236         setgidx(ID_EFFECTIVE, gid);
237 #endif
238
239         assert_gid(-1, gid);
240 }
241
242 static uid_t saved_euid, saved_ruid;
243
244 /****************************************************************************
245  save the real and effective uid for later restoration. Used by the quotas
246  code
247 ****************************************************************************/
248 void save_re_uid(void)
249 {
250         saved_ruid = getuid();
251         saved_euid = geteuid();
252 }
253
254
255 /****************************************************************************
256  and restore them!
257 ****************************************************************************/
258 void restore_re_uid(void)
259 {
260         set_effective_uid(0);
261
262 #if USE_SETRESUID
263         setresuid(saved_ruid, saved_euid, -1);
264 #elif USE_SETREUID
265         setreuid(saved_ruid, -1);
266         setreuid(-1,saved_euid);
267 #elif USE_SETUIDX
268         setuidx(ID_REAL, saved_ruid);
269         setuidx(ID_EFFECTIVE, saved_euid);
270 #else
271         set_effective_uid(saved_euid);
272         if (getuid() != saved_ruid)
273                 setuid(saved_ruid);
274         set_effective_uid(saved_euid);
275 #endif
276
277         assert_uid(saved_ruid, saved_euid);
278 }
279
280 /****************************************************************************
281  set the real AND effective uid to the current effective uid in a way that
282  allows root to be regained.
283  This is only possible on some platforms.
284 ****************************************************************************/
285 int set_re_uid(void)
286 {
287         uid_t uid = geteuid();
288
289 #if USE_SETRESUID
290         setresuid(geteuid(), -1, -1);
291 #endif
292
293 #if USE_SETREUID
294         setreuid(0, 0);
295         setreuid(uid, -1);
296         setreuid(-1, uid);
297 #endif
298
299 #if USE_SETEUID
300         /* can't be done */
301         return -1;
302 #endif
303
304 #if USE_SETUIDX
305         /* can't be done */
306         return -1;
307 #endif
308
309         assert_uid(uid, uid);
310         return 0;
311 }
312
313
314 /****************************************************************************
315  Become the specified uid and gid - permanently !
316  there should be no way back if possible
317 ****************************************************************************/
318 void become_user_permanently(uid_t uid, gid_t gid)
319 {
320         /*
321          * First - gain root privilege. We do this to ensure
322          * we can lose it again.
323          */
324
325         gain_root_privilege();
326         gain_root_group_privilege();
327
328 #if USE_SETRESUID
329         setresgid(gid,gid,gid);
330         setgid(gid);
331         setresuid(uid,uid,uid);
332         setuid(uid);
333 #endif
334
335 #if USE_SETREUID
336         setregid(gid,gid);
337         setgid(gid);
338         setreuid(uid,uid);
339         setuid(uid);
340 #endif
341
342 #if USE_SETEUID
343         setegid(gid);
344         setgid(gid);
345         setuid(uid);
346         seteuid(uid);
347         setuid(uid);
348 #endif
349
350 #if USE_SETUIDX
351         setgidx(ID_REAL, gid);
352         setgidx(ID_EFFECTIVE, gid);
353         setgid(gid);
354         setuidx(ID_REAL, uid);
355         setuidx(ID_EFFECTIVE, uid);
356         setuid(uid);
357 #endif
358         
359         assert_uid(uid, uid);
360         assert_gid(gid, gid);
361 }
362
363 #ifdef AUTOCONF_TEST
364
365 /****************************************************************************
366 this function just checks that we don't get ENOSYS back
367 ****************************************************************************/
368 static int have_syscall(void)
369 {
370         errno = 0;
371
372 #if USE_SETRESUID
373         setresuid(-1,-1,-1);
374 #endif
375
376 #if USE_SETREUID
377         setreuid(-1,-1);
378 #endif
379
380 #if USE_SETEUID
381         seteuid(-1);
382 #endif
383
384 #if USE_SETUIDX
385         setuidx(ID_EFFECTIVE, -1);
386 #endif
387
388         if (errno == ENOSYS) return -1;
389         
390         return 0;
391 }
392
393 main()
394 {
395         if (getuid() != 0) {
396 #if (defined(AIX) && defined(USE_SETREUID))
397                 /* setreuid is badly broken on AIX 4.1, we avoid it completely */
398                 fprintf(stderr,"avoiding possibly broken setreuid\n");
399                 exit(1);
400 #endif
401
402                 /* if not running as root then at least check to see if we get ENOSYS - this 
403                    handles Linux 2.0.x with glibc 2.1 */
404                 fprintf(stderr,"not running as root: checking for ENOSYS\n");
405                 exit(have_syscall());
406         }
407
408         gain_root_privilege();
409         gain_root_group_privilege();
410         set_effective_gid(1);
411         set_effective_uid(1);
412         save_re_uid();
413         restore_re_uid();
414         gain_root_privilege();
415         gain_root_group_privilege();
416         become_user_permanently(1, 1);
417         setuid(0);
418         if (getuid() == 0) {
419                 fprintf(stderr,"uid not set permanently\n");
420                 exit(1);
421         }
422
423         printf("OK\n");
424
425         exit(0);
426 }
427 #endif
428
429 /****************************************************************************
430 Check if we are setuid root.  Used in libsmb and smbpasswd parinoia checks.
431 ****************************************************************************/
432 BOOL is_setuid_root(void) 
433 {
434         return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
435 }