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/>.
22 #include "system/passwd.h" /* uid_wrapper */
23 #include "../lib/util/setid.h"
26 /* we are running this code in autoconf test mode to see which type of setuid
28 #if defined(HAVE_UNISTD_H)
33 #include <sys/types.h>
36 #ifdef HAVE_SYS_PRIV_H
43 #define DEBUG(x, y) printf y
44 #define smb_panic(x) exit(1)
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 ****************************************************************************/
60 static int initialized
;
63 initial_uid
= geteuid();
64 initial_gid
= getegid();
69 /****************************************************************************
70 some code (eg. winbindd) needs to know what uid we started as
71 ****************************************************************************/
72 uid_t
sec_initial_uid(void)
77 /****************************************************************************
78 some code (eg. winbindd, profiling shm) needs to know what gid we started as
79 ****************************************************************************/
80 gid_t
sec_initial_gid(void)
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");
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");
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);
143 samba_setreuid(0, 0);
147 samba_setuidx(ID_EFFECTIVE
, 0);
148 samba_setuidx(ID_REAL
, 0);
151 /* this is needed on some systems */
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);
177 samba_setgidx(ID_EFFECTIVE
, 0);
178 samba_setgidx(ID_REAL
, 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",
213 samba_setreuid(-1,uid
);
221 samba_setuidx(ID_EFFECTIVE
, 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);
238 samba_setregid(-1,gid
);
246 samba_setgidx(ID_EFFECTIVE
, 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
258 ****************************************************************************/
259 void save_re_uid(void)
261 saved_ruid
= getuid();
262 saved_euid
= geteuid();
266 /****************************************************************************
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);
275 samba_setreuid(saved_ruid
, -1);
276 samba_setreuid(-1,saved_euid
);
278 samba_setuidx(ID_REAL
, saved_ruid
);
279 samba_setuidx(ID_EFFECTIVE
, saved_euid
);
281 set_effective_uid(saved_euid
);
282 if (getuid() != saved_ruid
)
283 samba_setuid(saved_ruid
);
284 set_effective_uid(saved_euid
);
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
299 ****************************************************************************/
300 void save_re_gid(void)
302 saved_rgid
= getgid();
303 saved_egid
= getegid();
306 /****************************************************************************
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);
314 samba_setregid(saved_rgid
, -1);
315 samba_setregid(-1,saved_egid
);
317 samba_setgidx(ID_REAL
, saved_rgid
);
318 samba_setgidx(ID_EFFECTIVE
, saved_egid
);
320 set_effective_gid(saved_egid
);
321 if (getgid() != saved_rgid
)
322 samba_setgid(saved_rgid
);
323 set_effective_gid(saved_egid
);
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 ****************************************************************************/
337 uid_t uid
= geteuid();
339 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
340 samba_setresuid(uid
, uid
, -1);
344 samba_setreuid(0, 0);
345 samba_setreuid(uid
, -1);
346 samba_setreuid(-1, uid
);
359 assert_uid(uid
, uid
);
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
);
381 samba_setresuid(uid
,uid
,uid
);
386 samba_setregid(gid
,gid
);
388 samba_setreuid(uid
,uid
);
401 samba_setgidx(ID_REAL
, gid
);
402 samba_setgidx(ID_EFFECTIVE
, gid
);
404 samba_setuidx(ID_REAL
, uid
);
405 samba_setuidx(ID_EFFECTIVE
, uid
);
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
,
423 #if defined(USE_LINUX_THREAD_CREDENTIALS)
425 * With Linux thread-specific credentials
426 * we know we have setresuid/setresgid
432 if (samba_setresuid(0, 0, -1) != 0) {
435 /* Set our primary gid. */
436 /* Set rg=gid, eg=gid, sg=gid */
437 if (samba_setresgid(gid
, gid
, gid
) != 0) {
440 /* Set extra groups list. */
441 if (samba_setgroups(setlen
, gidset
) != 0) {
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) {
449 if (geteuid() != uid
|| getuid() != uid
||
450 getegid() != gid
|| getgid() != gid
) {
451 smb_panic("set_thread_credentials_permanently failed\n");
463 /****************************************************************************
464 this function just checks that we don't get ENOSYS back
465 ****************************************************************************/
466 static int have_syscall(void)
470 #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS)
471 samba_setresuid(-1,-1,-1);
475 samba_setreuid(-1,-1);
483 samba_setuidx(ID_EFFECTIVE
, -1);
486 if (errno
== ENOSYS
) return -1;
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");
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);
512 gain_root_privilege();
513 gain_root_group_privilege();
514 become_user_permanently(1, 1);
517 fprintf(stderr
,"uid not set permanently\n");
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);