source: branches/samba-3.5.x/source3/lib/util_sec.c

Last change on this file was 737, checked in by Silvan Scherrer, 13 years ago

Samba Server 3.5: update branche to 3.5.17

File size: 11.7 KB
Line 
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 3 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, see <http://www.gnu.org/licenses/>.
18*/
19
20#ifndef AUTOCONF_TEST
21#include "includes.h"
22#else
23/* we are running this code in autoconf test mode to see which type of setuid
24 function works */
25#if defined(HAVE_UNISTD_H)
26#include <unistd.h>
27#endif
28#include <stdlib.h>
29#include <stdio.h>
30#include <sys/types.h>
31#include <errno.h>
32
33#ifdef HAVE_SYS_PRIV_H
34#include <sys/priv.h>
35#endif
36#ifdef HAVE_SYS_ID_H
37#include <sys/id.h>
38#endif
39
40#define DEBUG(x, y) printf y
41#define smb_panic(x) exit(1)
42#define bool int
43#endif
44
45/* are we running as non-root? This is used by the regresison test code,
46 and potentially also for sites that want non-root smbd */
47static uid_t initial_uid;
48static gid_t initial_gid;
49
50/****************************************************************************
51remember what uid we got started as - this allows us to run correctly
52as non-root while catching trapdoor systems
53****************************************************************************/
54
55void sec_init(void)
56{
57 static int initialized;
58
59 if (!initialized) {
60 initial_uid = geteuid();
61 initial_gid = getegid();
62 initialized = 1;
63 }
64}
65
66/****************************************************************************
67some code (eg. winbindd) needs to know what uid we started as
68****************************************************************************/
69uid_t sec_initial_uid(void)
70{
71 return initial_uid;
72}
73
74/****************************************************************************
75some code (eg. winbindd, profiling shm) needs to know what gid we started as
76****************************************************************************/
77gid_t sec_initial_gid(void)
78{
79 return initial_gid;
80}
81
82/****************************************************************************
83are we running in non-root mode?
84****************************************************************************/
85bool non_root_mode(void)
86{
87 return (initial_uid != (uid_t)0);
88}
89
90/****************************************************************************
91abort if we haven't set the uid correctly
92****************************************************************************/
93static void assert_uid(uid_t ruid, uid_t euid)
94{
95#ifndef __OS2__
96 if ((euid != (uid_t)-1 && geteuid() != euid) ||
97 (ruid != (uid_t)-1 && getuid() != ruid)) {
98 if (!non_root_mode()) {
99 DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
100 (int)ruid, (int)euid,
101 (int)getuid(), (int)geteuid()));
102 smb_panic("failed to set uid\n");
103 exit(1);
104 }
105 }
106#endif
107}
108
109/****************************************************************************
110abort if we haven't set the gid correctly
111****************************************************************************/
112static void assert_gid(gid_t rgid, gid_t egid)
113{
114#ifndef __OS2__
115 if ((egid != (gid_t)-1 && getegid() != egid) ||
116 (rgid != (gid_t)-1 && getgid() != rgid)) {
117 if (!non_root_mode()) {
118 DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
119 (int)rgid, (int)egid,
120 (int)getgid(), (int)getegid(),
121 (int)getuid(), (int)geteuid()));
122 smb_panic("failed to set gid\n");
123 exit(1);
124 }
125 }
126#endif
127}
128
129/****************************************************************************
130 Gain root privilege before doing something.
131 We want to end up with ruid==euid==0
132****************************************************************************/
133void gain_root_privilege(void)
134{
135#if USE_SETRESUID
136 setresuid(0,0,0);
137#endif
138
139#if USE_SETEUID
140 seteuid(0);
141#endif
142
143#if USE_SETREUID
144 setreuid(0, 0);
145#endif
146
147#if USE_SETUIDX
148 setuidx(ID_EFFECTIVE, 0);
149 setuidx(ID_REAL, 0);
150#endif
151
152 /* this is needed on some systems */
153 setuid(0);
154
155 assert_uid(0, 0);
156}
157
158
159/****************************************************************************
160 Ensure our real and effective groups are zero.
161 we want to end up with rgid==egid==0
162****************************************************************************/
163void gain_root_group_privilege(void)
164{
165#if USE_SETRESUID
166 setresgid(0,0,0);
167#endif
168
169#if USE_SETREUID
170 setregid(0,0);
171#endif
172
173#if USE_SETEUID
174 setegid(0);
175#endif
176
177#if USE_SETUIDX
178 setgidx(ID_EFFECTIVE, 0);
179 setgidx(ID_REAL, 0);
180#endif
181
182 setgid(0);
183
184 assert_gid(0, 0);
185}
186
187
188/****************************************************************************
189 Set effective uid, and possibly the real uid too.
190 We want to end up with either:
191
192 ruid==uid and euid==uid
193
194 or
195
196 ruid==0 and euid==uid
197
198 depending on what the local OS will allow us to regain root from.
199****************************************************************************/
200void set_effective_uid(uid_t uid)
201{
202#if USE_SETRESUID
203 /* Set the effective as well as the real uid. */
204 if (setresuid(uid,uid,-1) == -1) {
205 if (errno == EAGAIN) {
206 DEBUG(0, ("setresuid failed with EAGAIN. uid(%d) "
207 "might be over its NPROC limit\n",
208 (int)uid));
209 }
210 }
211#endif
212
213#if USE_SETREUID
214 setreuid(-1,uid);
215#endif
216
217#if USE_SETEUID
218 seteuid(uid);
219#endif
220
221#if USE_SETUIDX
222 setuidx(ID_EFFECTIVE, uid);
223#endif
224
225 assert_uid(-1, uid);
226}
227
228/****************************************************************************
229 Set *only* the effective gid.
230 we want to end up with rgid==0 and egid==gid
231****************************************************************************/
232void set_effective_gid(gid_t gid)
233{
234#if USE_SETRESUID
235 setresgid(-1,gid,-1);
236#endif
237
238#if USE_SETREUID
239 setregid(-1,gid);
240#endif
241
242#if USE_SETEUID
243 setegid(gid);
244#endif
245
246#if USE_SETUIDX
247 setgidx(ID_EFFECTIVE, gid);
248#endif
249
250 assert_gid(-1, gid);
251}
252
253static uid_t saved_euid, saved_ruid;
254static gid_t saved_egid, saved_rgid;
255
256/****************************************************************************
257 save the real and effective uid for later restoration. Used by the quotas
258 code
259****************************************************************************/
260void save_re_uid(void)
261{
262 saved_ruid = getuid();
263 saved_euid = geteuid();
264}
265
266
267/****************************************************************************
268 and restore them!
269****************************************************************************/
270
271void restore_re_uid_fromroot(void)
272{
273#if USE_SETRESUID
274 setresuid(saved_ruid, saved_euid, -1);
275#elif USE_SETREUID
276 setreuid(saved_ruid, -1);
277 setreuid(-1,saved_euid);
278#elif USE_SETUIDX
279 setuidx(ID_REAL, saved_ruid);
280 setuidx(ID_EFFECTIVE, saved_euid);
281#else
282 set_effective_uid(saved_euid);
283 if (getuid() != saved_ruid)
284 setuid(saved_ruid);
285 set_effective_uid(saved_euid);
286#endif
287
288 assert_uid(saved_ruid, saved_euid);
289}
290
291void restore_re_uid(void)
292{
293 set_effective_uid(0);
294 restore_re_uid_fromroot();
295}
296
297/****************************************************************************
298 save the real and effective gid for later restoration. Used by the
299 getgroups code
300****************************************************************************/
301void save_re_gid(void)
302{
303 saved_rgid = getgid();
304 saved_egid = getegid();
305}
306
307/****************************************************************************
308 and restore them!
309****************************************************************************/
310void restore_re_gid(void)
311{
312#if USE_SETRESUID
313 setresgid(saved_rgid, saved_egid, -1);
314#elif USE_SETREUID
315 setregid(saved_rgid, -1);
316 setregid(-1,saved_egid);
317#elif USE_SETUIDX
318 setgidx(ID_REAL, saved_rgid);
319 setgidx(ID_EFFECTIVE, saved_egid);
320#else
321 set_effective_gid(saved_egid);
322 if (getgid() != saved_rgid)
323 setgid(saved_rgid);
324 set_effective_gid(saved_egid);
325#endif
326
327 assert_gid(saved_rgid, saved_egid);
328}
329
330
331/****************************************************************************
332 set the real AND effective uid to the current effective uid in a way that
333 allows root to be regained.
334 This is only possible on some platforms.
335****************************************************************************/
336int set_re_uid(void)
337{
338 uid_t uid = geteuid();
339
340#if USE_SETRESUID
341 setresuid(uid, uid, -1);
342#endif
343
344#if USE_SETREUID
345 setreuid(0, 0);
346 setreuid(uid, -1);
347 setreuid(-1, uid);
348#endif
349
350#if USE_SETEUID
351 /* can't be done */
352 return -1;
353#endif
354
355#if USE_SETUIDX
356 /* can't be done */
357 return -1;
358#endif
359
360 assert_uid(uid, uid);
361 return 0;
362}
363
364
365/****************************************************************************
366 Become the specified uid and gid - permanently !
367 there should be no way back if possible
368****************************************************************************/
369void become_user_permanently(uid_t uid, gid_t gid)
370{
371 /*
372 * First - gain root privilege. We do this to ensure
373 * we can lose it again.
374 */
375
376 gain_root_privilege();
377 gain_root_group_privilege();
378
379#if USE_SETRESUID
380 setresgid(gid,gid,gid);
381 setgid(gid);
382 setresuid(uid,uid,uid);
383 setuid(uid);
384#endif
385
386#if USE_SETREUID
387 setregid(gid,gid);
388 setgid(gid);
389 setreuid(uid,uid);
390 setuid(uid);
391#endif
392
393#if USE_SETEUID
394 setegid(gid);
395 setgid(gid);
396 setuid(uid);
397 seteuid(uid);
398 setuid(uid);
399#endif
400
401#if USE_SETUIDX
402 setgidx(ID_REAL, gid);
403 setgidx(ID_EFFECTIVE, gid);
404 setgid(gid);
405 setuidx(ID_REAL, uid);
406 setuidx(ID_EFFECTIVE, uid);
407 setuid(uid);
408#endif
409
410 assert_uid(uid, uid);
411 assert_gid(gid, gid);
412}
413
414#ifdef AUTOCONF_TEST
415
416/****************************************************************************
417this function just checks that we don't get ENOSYS back
418****************************************************************************/
419static int have_syscall(void)
420{
421 errno = 0;
422
423#if USE_SETRESUID
424 setresuid(-1,-1,-1);
425#endif
426
427#if USE_SETREUID
428 setreuid(-1,-1);
429#endif
430
431#if USE_SETEUID
432 seteuid(-1);
433#endif
434
435#if USE_SETUIDX
436 setuidx(ID_EFFECTIVE, -1);
437#endif
438
439 if (errno == ENOSYS) return -1;
440
441 return 0;
442}
443
444main()
445{
446 if (getuid() != 0) {
447#if (defined(AIX) && defined(USE_SETREUID))
448 /* setreuid is badly broken on AIX 4.1, we avoid it completely */
449 fprintf(stderr,"avoiding possibly broken setreuid\n");
450 exit(1);
451#endif
452
453 /* if not running as root then at least check to see if we get ENOSYS - this
454 handles Linux 2.0.x with glibc 2.1 */
455 fprintf(stderr,"not running as root: checking for ENOSYS\n");
456 exit(have_syscall());
457 }
458
459 gain_root_privilege();
460 gain_root_group_privilege();
461 set_effective_gid(1);
462 set_effective_uid(1);
463 save_re_uid();
464 restore_re_uid();
465 gain_root_privilege();
466 gain_root_group_privilege();
467 become_user_permanently(1, 1);
468 setuid(0);
469 if (getuid() == 0) {
470 fprintf(stderr,"uid not set permanently\n");
471 exit(1);
472 }
473
474 printf("OK\n");
475
476 exit(0);
477}
478#endif
479
480/****************************************************************************
481Check if we are setuid root. Used in libsmb and smbpasswd paranoia checks.
482****************************************************************************/
483bool is_setuid_root(void)
484{
485 return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
486}
Note: See TracBrowser for help on using the repository browser.