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/>.
23
/* we are running this code in autoconf test mode to see which type of setuid
25
#if defined(HAVE_UNISTD_H)
30
#include <sys/types.h>
33
#ifdef HAVE_SYS_PRIV_H
40
#define DEBUG(x, y) printf y
41
#define smb_panic(x) exit(1)
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 */
47
static uid_t initial_uid;
48
static gid_t initial_gid;
50
/****************************************************************************
51
remember what uid we got started as - this allows us to run correctly
52
as non-root while catching trapdoor systems
53
****************************************************************************/
57
static int initialized;
60
initial_uid = geteuid();
61
initial_gid = getegid();
66
/****************************************************************************
67
some code (eg. winbindd) needs to know what uid we started as
68
****************************************************************************/
69
uid_t sec_initial_uid(void)
74
/****************************************************************************
75
some code (eg. winbindd, profiling shm) needs to know what gid we started as
76
****************************************************************************/
77
gid_t sec_initial_gid(void)
82
/****************************************************************************
83
are we running in non-root mode?
84
****************************************************************************/
85
bool non_root_mode(void)
87
return (initial_uid != (uid_t)0);
90
/****************************************************************************
91
abort if we haven't set the uid correctly
92
****************************************************************************/
93
static void assert_uid(uid_t ruid, uid_t euid)
95
if ((euid != (uid_t)-1 && geteuid() != euid) ||
96
(ruid != (uid_t)-1 && getuid() != ruid)) {
97
if (!non_root_mode()) {
98
DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
100
(int)getuid(), (int)geteuid()));
101
smb_panic("failed to set uid\n");
107
/****************************************************************************
108
abort if we haven't set the gid correctly
109
****************************************************************************/
110
static void assert_gid(gid_t rgid, gid_t egid)
112
if ((egid != (gid_t)-1 && getegid() != egid) ||
113
(rgid != (gid_t)-1 && getgid() != rgid)) {
114
if (!non_root_mode()) {
115
DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
116
(int)rgid, (int)egid,
117
(int)getgid(), (int)getegid(),
118
(int)getuid(), (int)geteuid()));
119
smb_panic("failed to set gid\n");
125
/****************************************************************************
126
Gain root privilege before doing something.
127
We want to end up with ruid==euid==0
128
****************************************************************************/
129
void gain_root_privilege(void)
144
setuidx(ID_EFFECTIVE, 0);
148
/* this is needed on some systems */
155
/****************************************************************************
156
Ensure our real and effective groups are zero.
157
we want to end up with rgid==egid==0
158
****************************************************************************/
159
void gain_root_group_privilege(void)
174
setgidx(ID_EFFECTIVE, 0);
184
/****************************************************************************
185
Set effective uid, and possibly the real uid too.
186
We want to end up with either:
188
ruid==uid and euid==uid
192
ruid==0 and euid==uid
194
depending on what the local OS will allow us to regain root from.
195
****************************************************************************/
196
void set_effective_uid(uid_t uid)
199
/* Set the effective as well as the real uid. */
200
if (setresuid(uid,uid,-1) == -1) {
201
if (errno == EAGAIN) {
202
DEBUG(0, ("setresuid failed with EAGAIN. uid(%d) "
203
"might be over its NPROC limit\n",
218
setuidx(ID_EFFECTIVE, uid);
224
/****************************************************************************
225
Set *only* the effective gid.
226
we want to end up with rgid==0 and egid==gid
227
****************************************************************************/
228
void set_effective_gid(gid_t gid)
231
setresgid(-1,gid,-1);
243
setgidx(ID_EFFECTIVE, gid);
249
static uid_t saved_euid, saved_ruid;
250
static gid_t saved_egid, saved_rgid;
252
/****************************************************************************
253
save the real and effective uid for later restoration. Used by the quotas
255
****************************************************************************/
256
void save_re_uid(void)
258
saved_ruid = getuid();
259
saved_euid = geteuid();
263
/****************************************************************************
265
****************************************************************************/
267
void restore_re_uid_fromroot(void)
270
setresuid(saved_ruid, saved_euid, -1);
272
setreuid(saved_ruid, -1);
273
setreuid(-1,saved_euid);
275
setuidx(ID_REAL, saved_ruid);
276
setuidx(ID_EFFECTIVE, saved_euid);
278
set_effective_uid(saved_euid);
279
if (getuid() != saved_ruid)
281
set_effective_uid(saved_euid);
284
assert_uid(saved_ruid, saved_euid);
287
void restore_re_uid(void)
289
set_effective_uid(0);
290
restore_re_uid_fromroot();
293
/****************************************************************************
294
save the real and effective gid for later restoration. Used by the
296
****************************************************************************/
297
void save_re_gid(void)
299
saved_rgid = getgid();
300
saved_egid = getegid();
303
/****************************************************************************
305
****************************************************************************/
306
void restore_re_gid(void)
309
setresgid(saved_rgid, saved_egid, -1);
311
setregid(saved_rgid, -1);
312
setregid(-1,saved_egid);
314
setgidx(ID_REAL, saved_rgid);
315
setgidx(ID_EFFECTIVE, saved_egid);
317
set_effective_gid(saved_egid);
318
if (getgid() != saved_rgid)
320
set_effective_gid(saved_egid);
323
assert_gid(saved_rgid, saved_egid);
327
/****************************************************************************
328
set the real AND effective uid to the current effective uid in a way that
329
allows root to be regained.
330
This is only possible on some platforms.
331
****************************************************************************/
334
uid_t uid = geteuid();
337
setresuid(geteuid(), -1, -1);
356
assert_uid(uid, uid);
361
/****************************************************************************
362
Become the specified uid and gid - permanently !
363
there should be no way back if possible
364
****************************************************************************/
365
void become_user_permanently(uid_t uid, gid_t gid)
368
* First - gain root privilege. We do this to ensure
369
* we can lose it again.
372
gain_root_privilege();
373
gain_root_group_privilege();
376
setresgid(gid,gid,gid);
378
setresuid(uid,uid,uid);
398
setgidx(ID_REAL, gid);
399
setgidx(ID_EFFECTIVE, gid);
401
setuidx(ID_REAL, uid);
402
setuidx(ID_EFFECTIVE, uid);
406
assert_uid(uid, uid);
407
assert_gid(gid, gid);
412
/****************************************************************************
413
this function just checks that we don't get ENOSYS back
414
****************************************************************************/
415
static int have_syscall(void)
432
setuidx(ID_EFFECTIVE, -1);
435
if (errno == ENOSYS) return -1;
443
#if (defined(AIX) && defined(USE_SETREUID))
444
/* setreuid is badly broken on AIX 4.1, we avoid it completely */
445
fprintf(stderr,"avoiding possibly broken setreuid\n");
449
/* if not running as root then at least check to see if we get ENOSYS - this
450
handles Linux 2.0.x with glibc 2.1 */
451
fprintf(stderr,"not running as root: checking for ENOSYS\n");
452
exit(have_syscall());
455
gain_root_privilege();
456
gain_root_group_privilege();
457
set_effective_gid(1);
458
set_effective_uid(1);
461
gain_root_privilege();
462
gain_root_group_privilege();
463
become_user_permanently(1, 1);
466
fprintf(stderr,"uid not set permanently\n");
476
/****************************************************************************
477
Check if we are setuid root. Used in libsmb and smbpasswd paranoia checks.
478
****************************************************************************/
479
bool is_setuid_root(void)
481
return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);