source: trunk-3.0/source/smbd/sec_ctx.c@ 101

Last change on this file since 101 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

File size: 10.3 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 uid/user handling
4 Copyright (C) Tim Potter 2000
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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23extern struct current_user current_user;
24
25struct sec_ctx {
26 UNIX_USER_TOKEN ut;
27 NT_USER_TOKEN *token;
28};
29
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. */
32
33static struct sec_ctx sec_ctx_stack[MAX_SEC_CTX_DEPTH + 1];
34static int sec_ctx_stack_ndx;
35
36/****************************************************************************
37 Become the specified uid.
38****************************************************************************/
39
40static BOOL become_uid(uid_t uid)
41{
42 /* Check for dodgy uid values */
43
44 if (uid == (uid_t)-1 ||
45 ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) {
46 static int done;
47
48 if (!done) {
49 DEBUG(1,("WARNING: using uid %d is a security risk\n",
50 (int)uid));
51 done = 1;
52 }
53 }
54
55 /* Set effective user id */
56
57 set_effective_uid(uid);
58
59 DO_PROFILE_INC(uid_changes);
60 return True;
61}
62
63/****************************************************************************
64 Become the specified gid.
65****************************************************************************/
66
67static BOOL become_gid(gid_t gid)
68{
69 /* Check for dodgy gid values */
70
71 if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) &&
72 (gid == (gid_t)65535))) {
73 static int done;
74
75 if (!done) {
76 DEBUG(1,("WARNING: using gid %d is a security risk\n",
77 (int)gid));
78 done = 1;
79 }
80 }
81
82 /* Set effective group id */
83
84 set_effective_gid(gid);
85 return True;
86}
87
88/****************************************************************************
89 Become the specified uid and gid.
90****************************************************************************/
91
92static BOOL become_id(uid_t uid, gid_t gid)
93{
94 return become_gid(gid) && become_uid(uid);
95}
96
97/****************************************************************************
98 Drop back to root privileges in order to change to another user.
99****************************************************************************/
100
101static void gain_root(void)
102{
103 if (non_root_mode()) {
104 return;
105 }
106
107 if (geteuid() != 0) {
108 set_effective_uid(0);
109
110 if (geteuid() != 0) {
111 DEBUG(0,
112 ("Warning: You appear to have a trapdoor "
113 "uid system\n"));
114 }
115 }
116
117 if (getegid() != 0) {
118 set_effective_gid(0);
119
120 if (getegid() != 0) {
121 DEBUG(0,
122 ("Warning: You appear to have a trapdoor "
123 "gid system\n"));
124 }
125 }
126}
127
128/****************************************************************************
129 Get the list of current groups.
130****************************************************************************/
131
132static int get_current_groups(gid_t gid, int *p_ngroups, gid_t **p_groups)
133{
134 int i;
135 gid_t grp;
136 int ngroups;
137 gid_t *groups = NULL;
138
139 (*p_ngroups) = 0;
140 (*p_groups) = NULL;
141
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) */
145 save_re_gid();
146 set_effective_gid(gid);
147 setgid(gid);
148
149 ngroups = sys_getgroups(0,&grp);
150 if (ngroups <= 0) {
151 goto fail;
152 }
153
154 if((groups = SMB_MALLOC_ARRAY(gid_t, ngroups+1)) == NULL) {
155 DEBUG(0,("setup_groups malloc fail !\n"));
156 goto fail;
157 }
158
159 if ((ngroups = sys_getgroups(ngroups,groups)) == -1) {
160 goto fail;
161 }
162
163 restore_re_gid();
164
165 (*p_ngroups) = ngroups;
166 (*p_groups) = groups;
167
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] ) );
171 }
172 DEBUG( 3, ( "\n" ) );
173
174 return ngroups;
175
176fail:
177 SAFE_FREE(groups);
178 restore_re_gid();
179 return -1;
180}
181
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****************************************************************************/
186
187BOOL push_sec_ctx(void)
188{
189 struct sec_ctx *ctx_p;
190
191 /* Check we don't overflow our stack */
192
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");
196 }
197
198 /* Store previous user context */
199
200 sec_ctx_stack_ndx++;
201
202 ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
203
204 ctx_p->ut.uid = geteuid();
205 ctx_p->ut.gid = getegid();
206
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 ));
209
210 ctx_p->token = dup_nt_token(NULL,
211 sec_ctx_stack[sec_ctx_stack_ndx-1].token);
212
213 ctx_p->ut.ngroups = sys_getgroups(0, NULL);
214
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);
219 return False;
220 }
221
222 sys_getgroups(ctx_p->ut.ngroups, ctx_p->ut.groups);
223 } else {
224 ctx_p->ut.groups = NULL;
225 }
226
227 return True;
228}
229
230/****************************************************************************
231 Set the current security context to a given user.
232****************************************************************************/
233
234void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token)
235{
236#ifndef __OS2__
237 struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
238 ctx_p->uid = getuid();
239 current_user.uid = getuid();
240#else
241 struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
242
243 /* Set the security context */
244
245 DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
246 (unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));
247
248 debug_nt_user_token(DBGC_CLASS, 5, token);
249 debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups);
250
251 gain_root();
252
253#ifdef HAVE_SETGROUPS
254 sys_setgroups(ngroups, groups);
255#endif
256
257 ctx_p->ut.ngroups = ngroups;
258
259 SAFE_FREE(ctx_p->ut.groups);
260 if (token && (token == ctx_p->token)) {
261 smb_panic("DUPLICATE_TOKEN");
262 }
263
264 TALLOC_FREE(ctx_p->token);
265
266 if (ngroups) {
267 ctx_p->ut.groups = (gid_t *)memdup(groups,
268 sizeof(gid_t) * ngroups);
269 if (!ctx_p->ut.groups) {
270 smb_panic("memdup failed");
271 }
272 } else {
273 ctx_p->ut.groups = NULL;
274 }
275
276 if (token) {
277 ctx_p->token = dup_nt_token(NULL, token);
278 if (!ctx_p->token) {
279 smb_panic("dup_nt_token failed");
280 }
281 } else {
282 ctx_p->token = NULL;
283 }
284
285 become_id(uid, gid);
286
287 ctx_p->ut.uid = uid;
288 ctx_p->ut.gid = gid;
289
290 /* Update current_user stuff */
291
292 current_user.ut.uid = uid;
293 current_user.ut.gid = gid;
294 current_user.ut.ngroups = ngroups;
295 current_user.ut.groups = groups;
296 current_user.nt_user_token = ctx_p->token;
297#endif /* __OS2__ */
298}
299
300/****************************************************************************
301 Become root context.
302****************************************************************************/
303
304void set_root_sec_ctx(void)
305{
306 /* May need to worry about supplementary groups at some stage */
307
308 set_sec_ctx(0, 0, 0, NULL, NULL);
309}
310
311/****************************************************************************
312 Pop a security context from the stack.
313****************************************************************************/
314
315BOOL pop_sec_ctx(void)
316{
317 struct sec_ctx *ctx_p;
318 struct sec_ctx *prev_ctx_p;
319
320 /* Check for stack underflow */
321
322 if (sec_ctx_stack_ndx == 0) {
323 DEBUG(0, ("Security context stack underflow!\n"));
324 smb_panic("Security context stack underflow!\n");
325 }
326
327 ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
328
329 /* Clear previous user info */
330
331 ctx_p->ut.uid = (uid_t)-1;
332 ctx_p->ut.gid = (gid_t)-1;
333
334 SAFE_FREE(ctx_p->ut.groups);
335 ctx_p->ut.ngroups = 0;
336
337 TALLOC_FREE(ctx_p->token);
338
339 /* Pop back previous user */
340
341 sec_ctx_stack_ndx--;
342
343#ifndef __OS2__
344 current_user.uid = getuid();
345#else
346 gain_root();
347
348 prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
349
350#ifdef HAVE_SETGROUPS
351 sys_setgroups(prev_ctx_p->ut.ngroups, prev_ctx_p->ut.groups);
352#endif
353
354 become_id(prev_ctx_p->ut.uid, prev_ctx_p->ut.gid);
355
356 /* Update current_user stuff */
357
358 current_user.ut.uid = prev_ctx_p->ut.uid;
359 current_user.ut.gid = prev_ctx_p->ut.gid;
360 current_user.ut.ngroups = prev_ctx_p->ut.ngroups;
361 current_user.ut.groups = prev_ctx_p->ut.groups;
362 current_user.nt_user_token = prev_ctx_p->token;
363#endif /* __OS2__ */
364 DEBUG(3, ("pop_sec_ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
365 (unsigned int)geteuid(), (unsigned int)getegid(), sec_ctx_stack_ndx));
366
367 return True;
368}
369
370/* Initialise the security context system */
371
372void init_sec_ctx(void)
373{
374 int i;
375 struct sec_ctx *ctx_p;
376
377 /* Initialise security context stack */
378
379 memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH);
380
381 for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
382 sec_ctx_stack[i].ut.uid = (uid_t)-1;
383 sec_ctx_stack[i].ut.gid = (gid_t)-1;
384 }
385
386 /* Initialise first level of stack. It is the current context */
387 ctx_p = &sec_ctx_stack[0];
388
389 ctx_p->ut.uid = geteuid();
390 ctx_p->ut.gid = getegid();
391
392 get_current_groups(ctx_p->ut.gid, &ctx_p->ut.ngroups, &ctx_p->ut.groups);
393
394 ctx_p->token = NULL; /* Maps to guest user. */
395
396 /* Initialise current_user global */
397
398 current_user.ut.uid = ctx_p->ut.uid;
399 current_user.ut.gid = ctx_p->ut.gid;
400 current_user.ut.ngroups = ctx_p->ut.ngroups;
401 current_user.ut.groups = ctx_p->ut.groups;
402
403 /* The conn and vuid are usually taken care of by other modules.
404 We initialise them here. */
405
406 current_user.conn = NULL;
407 current_user.vuid = UID_FIELD_INVALID;
408 current_user.nt_user_token = NULL;
409}
Note: See TracBrowser for help on using the repository browser.