Fix typo we've had for a long time in set_re_uid() in the USE_SETRESUID case.
[Samba/gbeck.git] / source3 / lib / util_sec.c
blob36d2a2b25384f8cd99aa6c96fb785de02741bdd6
1 /*
2 Unix SMB/CIFS implementation.
3 Copyright (C) Jeremy Allison 1998.
4 rewritten for version 2.0.6 by Tridge
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.
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.
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/>.
20 #ifndef AUTOCONF_TEST
21 #include "includes.h"
22 #include "system/passwd.h" /* uid_wrapper */
23 #include "../lib/util/setid.h"
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>
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
43 #define DEBUG(x, y) printf y
44 #define smb_panic(x) exit(1)
45 #define bool int
46 #endif
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;
53 /****************************************************************************
54 remember what uid we got started as - this allows us to run correctly
55 as non-root while catching trapdoor systems
56 ****************************************************************************/
58 void sec_init(void)
60 static int initialized;
62 if (!initialized) {
63 initial_uid = geteuid();
64 initial_gid = getegid();
65 initialized = 1;
69 /****************************************************************************
70 some code (eg. winbindd) needs to know what uid we started as
71 ****************************************************************************/
72 uid_t sec_initial_uid(void)
74 return initial_uid;
77 /****************************************************************************
78 some code (eg. winbindd, profiling shm) needs to know what gid we started as
79 ****************************************************************************/
80 gid_t sec_initial_gid(void)
82 return initial_gid;
85 /****************************************************************************
86 are we running in non-root mode?
87 ****************************************************************************/
88 bool non_root_mode(void)
90 return (initial_uid != (uid_t)0);
93 /****************************************************************************
94 abort if we haven't set the uid correctly
95 ****************************************************************************/
96 static void assert_uid(uid_t ruid, uid_t euid)
98 if ((euid != (uid_t)-1 && geteuid() != euid) ||
99 (ruid != (uid_t)-1 && getuid() != ruid)) {
100 if (!non_root_mode()) {
101 DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
102 (int)ruid, (int)euid,
103 (int)getuid(), (int)geteuid()));
104 smb_panic("failed to set uid\n");
105 exit(1);
110 /****************************************************************************
111 abort if we haven't set the gid correctly
112 ****************************************************************************/
113 static void assert_gid(gid_t rgid, gid_t egid)
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);
128 /****************************************************************************
129 Gain root privilege before doing something.
130 We want to end up with ruid==euid==0
131 ****************************************************************************/
132 void gain_root_privilege(void)
134 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
135 samba_setresuid(0,0,0);
136 #endif
138 #if USE_SETEUID
139 samba_seteuid(0);
140 #endif
142 #if USE_SETREUID
143 samba_setreuid(0, 0);
144 #endif
146 #if USE_SETUIDX
147 samba_setuidx(ID_EFFECTIVE, 0);
148 samba_setuidx(ID_REAL, 0);
149 #endif
151 /* this is needed on some systems */
152 samba_setuid(0);
154 assert_uid(0, 0);
158 /****************************************************************************
159 Ensure our real and effective groups are zero.
160 we want to end up with rgid==egid==0
161 ****************************************************************************/
162 void gain_root_group_privilege(void)
164 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
165 samba_setresgid(0,0,0);
166 #endif
168 #if USE_SETREUID
169 samba_setregid(0,0);
170 #endif
172 #if USE_SETEUID
173 samba_setegid(0);
174 #endif
176 #if USE_SETUIDX
177 samba_setgidx(ID_EFFECTIVE, 0);
178 samba_setgidx(ID_REAL, 0);
179 #endif
181 samba_setgid(0);
183 assert_gid(0, 0);
187 /****************************************************************************
188 Set effective uid, and possibly the real uid too.
189 We want to end up with either:
191 ruid==uid and euid==uid
195 ruid==0 and euid==uid
197 depending on what the local OS will allow us to regain root from.
198 ****************************************************************************/
199 void set_effective_uid(uid_t uid)
201 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
202 /* Set the effective as well as the real uid. */
203 if (samba_setresuid(uid,uid,-1) == -1) {
204 if (errno == EAGAIN) {
205 DEBUG(0, ("samba_setresuid failed with EAGAIN. uid(%d) "
206 "might be over its NPROC limit\n",
207 (int)uid));
210 #endif
212 #if USE_SETREUID
213 samba_setreuid(-1,uid);
214 #endif
216 #if USE_SETEUID
217 samba_seteuid(uid);
218 #endif
220 #if USE_SETUIDX
221 samba_setuidx(ID_EFFECTIVE, uid);
222 #endif
224 assert_uid(-1, uid);
227 /****************************************************************************
228 Set *only* the effective gid.
229 we want to end up with rgid==0 and egid==gid
230 ****************************************************************************/
231 void set_effective_gid(gid_t gid)
233 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
234 samba_setresgid(-1,gid,-1);
235 #endif
237 #if USE_SETREUID
238 samba_setregid(-1,gid);
239 #endif
241 #if USE_SETEUID
242 samba_setegid(gid);
243 #endif
245 #if USE_SETUIDX
246 samba_setgidx(ID_EFFECTIVE, gid);
247 #endif
249 assert_gid(-1, gid);
252 static uid_t saved_euid, saved_ruid;
253 static gid_t saved_egid, saved_rgid;
255 /****************************************************************************
256 save the real and effective uid for later restoration. Used by the quotas
257 code
258 ****************************************************************************/
259 void save_re_uid(void)
261 saved_ruid = getuid();
262 saved_euid = geteuid();
266 /****************************************************************************
267 and restore them!
268 ****************************************************************************/
270 void restore_re_uid_fromroot(void)
272 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
273 samba_setresuid(saved_ruid, saved_euid, -1);
274 #elif USE_SETREUID
275 samba_setreuid(saved_ruid, -1);
276 samba_setreuid(-1,saved_euid);
277 #elif USE_SETUIDX
278 samba_setuidx(ID_REAL, saved_ruid);
279 samba_setuidx(ID_EFFECTIVE, saved_euid);
280 #else
281 set_effective_uid(saved_euid);
282 if (getuid() != saved_ruid)
283 samba_setuid(saved_ruid);
284 set_effective_uid(saved_euid);
285 #endif
287 assert_uid(saved_ruid, saved_euid);
290 void restore_re_uid(void)
292 set_effective_uid(0);
293 restore_re_uid_fromroot();
296 /****************************************************************************
297 save the real and effective gid for later restoration. Used by the
298 getgroups code
299 ****************************************************************************/
300 void save_re_gid(void)
302 saved_rgid = getgid();
303 saved_egid = getegid();
306 /****************************************************************************
307 and restore them!
308 ****************************************************************************/
309 void restore_re_gid(void)
311 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
312 samba_setresgid(saved_rgid, saved_egid, -1);
313 #elif USE_SETREUID
314 samba_setregid(saved_rgid, -1);
315 samba_setregid(-1,saved_egid);
316 #elif USE_SETUIDX
317 samba_setgidx(ID_REAL, saved_rgid);
318 samba_setgidx(ID_EFFECTIVE, saved_egid);
319 #else
320 set_effective_gid(saved_egid);
321 if (getgid() != saved_rgid)
322 samba_setgid(saved_rgid);
323 set_effective_gid(saved_egid);
324 #endif
326 assert_gid(saved_rgid, saved_egid);
330 /****************************************************************************
331 set the real AND effective uid to the current effective uid in a way that
332 allows root to be regained.
333 This is only possible on some platforms.
334 ****************************************************************************/
335 int set_re_uid(void)
337 uid_t uid = geteuid();
339 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
340 samba_setresuid(uid, uid, -1);
341 #endif
343 #if USE_SETREUID
344 samba_setreuid(0, 0);
345 samba_setreuid(uid, -1);
346 samba_setreuid(-1, uid);
347 #endif
349 #if USE_SETEUID
350 /* can't be done */
351 return -1;
352 #endif
354 #if USE_SETUIDX
355 /* can't be done */
356 return -1;
357 #endif
359 assert_uid(uid, uid);
360 return 0;
364 /****************************************************************************
365 Become the specified uid and gid - permanently !
366 there should be no way back if possible
367 ****************************************************************************/
368 void become_user_permanently(uid_t uid, gid_t gid)
371 * First - gain root privilege. We do this to ensure
372 * we can lose it again.
375 gain_root_privilege();
376 gain_root_group_privilege();
378 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
379 samba_setresgid(gid,gid,gid);
380 samba_setgid(gid);
381 samba_setresuid(uid,uid,uid);
382 samba_setuid(uid);
383 #endif
385 #if USE_SETREUID
386 samba_setregid(gid,gid);
387 samba_setgid(gid);
388 samba_setreuid(uid,uid);
389 samba_setuid(uid);
390 #endif
392 #if USE_SETEUID
393 samba_setegid(gid);
394 samba_setgid(gid);
395 samba_setuid(uid);
396 samba_seteuid(uid);
397 samba_setuid(uid);
398 #endif
400 #if USE_SETUIDX
401 samba_setgidx(ID_REAL, gid);
402 samba_setgidx(ID_EFFECTIVE, gid);
403 samba_setgid(gid);
404 samba_setuidx(ID_REAL, uid);
405 samba_setuidx(ID_EFFECTIVE, uid);
406 samba_setuid(uid);
407 #endif
409 assert_uid(uid, uid);
410 assert_gid(gid, gid);
413 /**********************************************************
414 Function to set thread specific credentials in an
415 irreversible way. Must be thread-safe code.
416 **********************************************************/
418 int set_thread_credentials_permanently(uid_t uid,
419 gid_t gid,
420 size_t setlen,
421 const gid_t *gidset)
423 #if defined(USE_LINUX_THREAD_CREDENTIALS)
425 * With Linux thread-specific credentials
426 * we know we have setresuid/setresgid
427 * available.
430 /* Become root. */
431 /* Set ru=0, eu=0 */
432 if (samba_setresuid(0, 0, -1) != 0) {
433 return -1;
435 /* Set our primary gid. */
436 /* Set rg=gid, eg=gid, sg=gid */
437 if (samba_setresgid(gid, gid, gid) != 0) {
438 return -1;
440 /* Set extra groups list. */
441 if (samba_setgroups(setlen, gidset) != 0) {
442 return -1;
444 /* Become the requested user. No way back after this. */
445 /* Set ru=uid, eu=uid, su=uid */
446 if (samba_setresuid(uid, uid, uid) != 0) {
447 return -1;
449 if (geteuid() != uid || getuid() != uid ||
450 getegid() != gid || getgid() != gid) {
451 smb_panic("set_thread_credentials_permanently failed\n");
452 return -1;
454 return 0;
455 #else
456 errno = ENOSYS;
457 return -1;
458 #endif
461 #ifdef AUTOCONF_TEST
463 /****************************************************************************
464 this function just checks that we don't get ENOSYS back
465 ****************************************************************************/
466 static int have_syscall(void)
468 errno = 0;
470 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
471 samba_setresuid(-1,-1,-1);
472 #endif
474 #if USE_SETREUID
475 samba_setreuid(-1,-1);
476 #endif
478 #if USE_SETEUID
479 samba_seteuid(-1);
480 #endif
482 #if USE_SETUIDX
483 samba_setuidx(ID_EFFECTIVE, -1);
484 #endif
486 if (errno == ENOSYS) return -1;
488 return 0;
491 main()
493 if (getuid() != 0) {
494 #if (defined(AIX) && defined(USE_SETREUID))
495 /* setreuid is badly broken on AIX 4.1, we avoid it completely */
496 fprintf(stderr,"avoiding possibly broken setreuid\n");
497 exit(1);
498 #endif
500 /* if not running as root then at least check to see if we get ENOSYS - this
501 handles Linux 2.0.x with glibc 2.1 */
502 fprintf(stderr,"not running as root: checking for ENOSYS\n");
503 exit(have_syscall());
506 gain_root_privilege();
507 gain_root_group_privilege();
508 set_effective_gid(1);
509 set_effective_uid(1);
510 save_re_uid();
511 restore_re_uid();
512 gain_root_privilege();
513 gain_root_group_privilege();
514 become_user_permanently(1, 1);
515 samba_setuid(0);
516 if (getuid() == 0) {
517 fprintf(stderr,"uid not set permanently\n");
518 exit(1);
521 printf("OK\n");
523 exit(0);
525 #endif
527 /****************************************************************************
528 Check if we are setuid root. Used in libsmb and smbpasswd paranoia checks.
529 ****************************************************************************/
530 bool is_setuid_root(void)
532 return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);