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