2
Unix SMB/CIFS implementation.
4
Copyright (C) Tim Potter 2000
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 2 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, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
extern struct current_user current_user;
30
/* A stack of security contexts. We include the current context as being
31
the first one, so there is room for another MAX_SEC_CTX_DEPTH more. */
33
static struct sec_ctx sec_ctx_stack[MAX_SEC_CTX_DEPTH + 1];
34
static int sec_ctx_stack_ndx;
36
/****************************************************************************
37
Become the specified uid.
38
****************************************************************************/
40
static BOOL become_uid(uid_t uid)
42
/* Check for dodgy uid values */
44
if (uid == (uid_t)-1 ||
45
((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) {
49
DEBUG(1,("WARNING: using uid %d is a security risk\n",
55
/* Set effective user id */
57
set_effective_uid(uid);
59
DO_PROFILE_INC(uid_changes);
63
/****************************************************************************
64
Become the specified gid.
65
****************************************************************************/
67
static BOOL become_gid(gid_t gid)
69
/* Check for dodgy gid values */
71
if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) &&
72
(gid == (gid_t)65535))) {
76
DEBUG(1,("WARNING: using gid %d is a security risk\n",
82
/* Set effective group id */
84
set_effective_gid(gid);
88
/****************************************************************************
89
Become the specified uid and gid.
90
****************************************************************************/
92
static BOOL become_id(uid_t uid, gid_t gid)
94
return become_gid(gid) && become_uid(uid);
97
/****************************************************************************
98
Drop back to root privileges in order to change to another user.
99
****************************************************************************/
101
static void gain_root(void)
103
if (non_root_mode()) {
107
if (geteuid() != 0) {
108
set_effective_uid(0);
110
if (geteuid() != 0) {
112
("Warning: You appear to have a trapdoor "
117
if (getegid() != 0) {
118
set_effective_gid(0);
120
if (getegid() != 0) {
122
("Warning: You appear to have a trapdoor "
128
/****************************************************************************
129
Get the list of current groups.
130
****************************************************************************/
132
static int get_current_groups(gid_t gid, int *p_ngroups, gid_t **p_groups)
137
gid_t *groups = NULL;
142
/* this looks a little strange, but is needed to cope with
143
systems that put the current egid in the group list
144
returned from getgroups() (tridge) */
146
set_effective_gid(gid);
149
ngroups = sys_getgroups(0,&grp);
154
if((groups = SMB_MALLOC_ARRAY(gid_t, ngroups+1)) == NULL) {
155
DEBUG(0,("setup_groups malloc fail !\n"));
159
if ((ngroups = sys_getgroups(ngroups,groups)) == -1) {
165
(*p_ngroups) = ngroups;
166
(*p_groups) = groups;
168
DEBUG( 3, ( "get_current_groups: user is in %u groups: ", ngroups));
169
for (i = 0; i < ngroups; i++ ) {
170
DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
172
DEBUG( 3, ( "\n" ) );
182
/****************************************************************************
183
Create a new security context on the stack. It is the same as the old
184
one. User changes are done using the set_sec_ctx() function.
185
****************************************************************************/
187
BOOL push_sec_ctx(void)
189
struct sec_ctx *ctx_p;
191
/* Check we don't overflow our stack */
193
if (sec_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
194
DEBUG(0, ("Security context stack overflow!\n"));
195
smb_panic("Security context stack overflow!\n");
198
/* Store previous user context */
202
ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
204
ctx_p->ut.uid = geteuid();
205
ctx_p->ut.gid = getegid();
207
DEBUG(3, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n",
208
(unsigned int)ctx_p->ut.uid, (unsigned int)ctx_p->ut.gid, sec_ctx_stack_ndx ));
210
ctx_p->token = dup_nt_token(NULL,
211
sec_ctx_stack[sec_ctx_stack_ndx-1].token);
213
ctx_p->ut.ngroups = sys_getgroups(0, NULL);
215
if (ctx_p->ut.ngroups != 0) {
216
if (!(ctx_p->ut.groups = SMB_MALLOC_ARRAY(gid_t, ctx_p->ut.ngroups))) {
217
DEBUG(0, ("Out of memory in push_sec_ctx()\n"));
218
TALLOC_FREE(ctx_p->token);
222
sys_getgroups(ctx_p->ut.ngroups, ctx_p->ut.groups);
224
ctx_p->ut.groups = NULL;
230
/****************************************************************************
231
Set the current security context to a given user.
232
****************************************************************************/
234
void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token)
236
struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
238
/* Set the security context */
240
DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
241
(unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));
243
debug_nt_user_token(DBGC_CLASS, 5, token);
244
debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups);
248
#ifdef HAVE_SETGROUPS
249
sys_setgroups(ngroups, groups);
252
ctx_p->ut.ngroups = ngroups;
254
SAFE_FREE(ctx_p->ut.groups);
255
if (token && (token == ctx_p->token)) {
256
smb_panic("DUPLICATE_TOKEN");
259
TALLOC_FREE(ctx_p->token);
262
ctx_p->ut.groups = memdup(groups, sizeof(gid_t) * ngroups);
263
if (!ctx_p->ut.groups) {
264
smb_panic("memdup failed");
267
ctx_p->ut.groups = NULL;
271
ctx_p->token = dup_nt_token(NULL, token);
273
smb_panic("dup_nt_token failed");
284
/* Update current_user stuff */
286
current_user.ut.uid = uid;
287
current_user.ut.gid = gid;
288
current_user.ut.ngroups = ngroups;
289
current_user.ut.groups = groups;
290
current_user.nt_user_token = ctx_p->token;
293
/****************************************************************************
295
****************************************************************************/
297
void set_root_sec_ctx(void)
299
/* May need to worry about supplementary groups at some stage */
301
set_sec_ctx(0, 0, 0, NULL, NULL);
304
/****************************************************************************
305
Pop a security context from the stack.
306
****************************************************************************/
308
BOOL pop_sec_ctx(void)
310
struct sec_ctx *ctx_p;
311
struct sec_ctx *prev_ctx_p;
313
/* Check for stack underflow */
315
if (sec_ctx_stack_ndx == 0) {
316
DEBUG(0, ("Security context stack underflow!\n"));
317
smb_panic("Security context stack underflow!\n");
320
ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
322
/* Clear previous user info */
324
ctx_p->ut.uid = (uid_t)-1;
325
ctx_p->ut.gid = (gid_t)-1;
327
SAFE_FREE(ctx_p->ut.groups);
328
ctx_p->ut.ngroups = 0;
330
TALLOC_FREE(ctx_p->token);
332
/* Pop back previous user */
338
prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
340
#ifdef HAVE_SETGROUPS
341
sys_setgroups(prev_ctx_p->ut.ngroups, prev_ctx_p->ut.groups);
344
become_id(prev_ctx_p->ut.uid, prev_ctx_p->ut.gid);
346
/* Update current_user stuff */
348
current_user.ut.uid = prev_ctx_p->ut.uid;
349
current_user.ut.gid = prev_ctx_p->ut.gid;
350
current_user.ut.ngroups = prev_ctx_p->ut.ngroups;
351
current_user.ut.groups = prev_ctx_p->ut.groups;
352
current_user.nt_user_token = prev_ctx_p->token;
354
DEBUG(3, ("pop_sec_ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
355
(unsigned int)geteuid(), (unsigned int)getegid(), sec_ctx_stack_ndx));
360
/* Initialise the security context system */
362
void init_sec_ctx(void)
365
struct sec_ctx *ctx_p;
367
/* Initialise security context stack */
369
memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH);
371
for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
372
sec_ctx_stack[i].ut.uid = (uid_t)-1;
373
sec_ctx_stack[i].ut.gid = (gid_t)-1;
376
/* Initialise first level of stack. It is the current context */
377
ctx_p = &sec_ctx_stack[0];
379
ctx_p->ut.uid = geteuid();
380
ctx_p->ut.gid = getegid();
382
get_current_groups(ctx_p->ut.gid, &ctx_p->ut.ngroups, &ctx_p->ut.groups);
384
ctx_p->token = NULL; /* Maps to guest user. */
386
/* Initialise current_user global */
388
current_user.ut.uid = ctx_p->ut.uid;
389
current_user.ut.gid = ctx_p->ut.gid;
390
current_user.ut.ngroups = ctx_p->ut.ngroups;
391
current_user.ut.groups = ctx_p->ut.groups;
393
/* The conn and vuid are usually taken care of by other modules.
394
We initialise them here. */
396
current_user.conn = NULL;
397
current_user.vuid = UID_FIELD_INVALID;
398
current_user.nt_user_token = NULL;