Line data Source code
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 3 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, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "system/passwd.h"
22 : #include "smbd/smbd.h"
23 : #include "smbd/globals.h"
24 : #include "libcli/security/security_token.h"
25 : #include "auth.h"
26 : #include "smbprofile.h"
27 : #include "../lib/util/setid.h"
28 :
29 : extern struct current_user current_user;
30 :
31 : /****************************************************************************
32 : Are two UNIX tokens equal ?
33 : ****************************************************************************/
34 :
35 170327 : bool unix_token_equal(const struct security_unix_token *t1, const struct security_unix_token *t2)
36 : {
37 170327 : if (t1->uid != t2->uid || t1->gid != t2->gid ||
38 170106 : t1->ngroups != t2->ngroups) {
39 215 : return false;
40 : }
41 170106 : if (memcmp(t1->groups, t2->groups,
42 170106 : t1->ngroups*sizeof(gid_t)) != 0) {
43 0 : return false;
44 : }
45 169776 : return true;
46 : }
47 :
48 : /****************************************************************************
49 : Become the specified uid.
50 : ****************************************************************************/
51 :
52 9913698 : static bool become_uid(uid_t uid)
53 : {
54 : /* Check for dodgy uid values */
55 :
56 9913698 : if (uid == (uid_t)-1 ||
57 : ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) {
58 0 : if (!become_uid_done) {
59 0 : DEBUG(1,("WARNING: using uid %d is a security risk\n",
60 : (int)uid));
61 0 : become_uid_done = true;
62 : }
63 : }
64 :
65 : /* Set effective user id */
66 :
67 9913698 : set_effective_uid(uid);
68 :
69 9913698 : return True;
70 : }
71 :
72 : /****************************************************************************
73 : Become the specified gid.
74 : ****************************************************************************/
75 :
76 9913698 : static bool become_gid(gid_t gid)
77 : {
78 : /* Check for dodgy gid values */
79 :
80 9913698 : if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) &&
81 : (gid == (gid_t)65535))) {
82 0 : if (!become_gid_done) {
83 0 : DEBUG(1,("WARNING: using gid %d is a security risk\n",
84 : (int)gid));
85 0 : become_gid_done = true;
86 : }
87 : }
88 :
89 : /* Set effective group id */
90 :
91 9913698 : set_effective_gid(gid);
92 9913698 : return True;
93 : }
94 :
95 : /****************************************************************************
96 : Drop back to root privileges in order to change to another user.
97 : ****************************************************************************/
98 :
99 9913698 : static void gain_root(void)
100 : {
101 9913698 : if (non_root_mode()) {
102 9886876 : return;
103 : }
104 :
105 0 : if (geteuid() != 0) {
106 0 : set_effective_uid(0);
107 :
108 0 : if (geteuid() != 0) {
109 0 : DEBUG(0,
110 : ("Warning: You appear to have a trapdoor "
111 : "uid system\n"));
112 : }
113 : }
114 :
115 0 : if (getegid() != 0) {
116 0 : set_effective_gid(0);
117 :
118 0 : if (getegid() != 0) {
119 0 : DEBUG(0,
120 : ("Warning: You appear to have a trapdoor "
121 : "gid system\n"));
122 : }
123 : }
124 : }
125 :
126 : /****************************************************************************
127 : Get the list of current groups.
128 : ****************************************************************************/
129 :
130 0 : static int get_current_groups(gid_t gid, uint32_t *p_ngroups, gid_t **p_groups)
131 : {
132 0 : int i;
133 0 : int ngroups;
134 0 : gid_t *groups = NULL;
135 :
136 0 : (*p_ngroups) = 0;
137 0 : (*p_groups) = NULL;
138 :
139 : /* this looks a little strange, but is needed to cope with
140 : systems that put the current egid in the group list
141 : returned from getgroups() (tridge) */
142 0 : save_re_gid();
143 0 : set_effective_gid(gid);
144 0 : samba_setgid(gid);
145 :
146 0 : ngroups = sys_getgroups(0, NULL);
147 0 : if (ngroups <= 0) {
148 0 : goto fail;
149 : }
150 :
151 0 : if((groups = SMB_MALLOC_ARRAY(gid_t, ngroups+1)) == NULL) {
152 0 : DEBUG(0,("setup_groups malloc fail !\n"));
153 0 : goto fail;
154 : }
155 :
156 0 : if ((ngroups = sys_getgroups(ngroups,groups)) == -1) {
157 0 : goto fail;
158 : }
159 :
160 0 : restore_re_gid();
161 :
162 0 : (*p_ngroups) = ngroups;
163 0 : (*p_groups) = groups;
164 :
165 0 : DEBUG( 4, ( "get_current_groups: user is in %u groups: ", ngroups));
166 0 : for (i = 0; i < ngroups; i++ ) {
167 0 : DEBUG( 4, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
168 : }
169 0 : DEBUG( 4, ( "\n" ) );
170 :
171 0 : return ngroups;
172 :
173 0 : fail:
174 0 : SAFE_FREE(groups);
175 0 : restore_re_gid();
176 0 : return -1;
177 : }
178 :
179 : /****************************************************************************
180 : Create a new security context on the stack. It is the same as the old
181 : one. User changes are done using the set_sec_ctx() function.
182 : ****************************************************************************/
183 :
184 4508465 : bool push_sec_ctx(void)
185 : {
186 7608 : struct sec_ctx *ctx_p;
187 :
188 4508465 : START_PROFILE(push_sec_ctx);
189 :
190 : /* Check we don't overflow our stack */
191 :
192 4508465 : if (sec_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
193 0 : DEBUG(0, ("Security context stack overflow!\n"));
194 0 : smb_panic("Security context stack overflow!");
195 : }
196 :
197 : /* Store previous user context */
198 :
199 4508465 : sec_ctx_stack_ndx++;
200 :
201 4508465 : ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
202 :
203 4508465 : ctx_p->ut.uid = geteuid();
204 4508465 : ctx_p->ut.gid = getegid();
205 :
206 4508465 : DEBUG(4, ("push_sec_ctx(%u, %u) : sec_ctx_stack_ndx = %d\n",
207 : (unsigned int)ctx_p->ut.uid, (unsigned int)ctx_p->ut.gid, sec_ctx_stack_ndx ));
208 :
209 9016930 : ctx_p->token = security_token_duplicate(NULL,
210 4508465 : sec_ctx_stack[sec_ctx_stack_ndx-1].token);
211 :
212 4508465 : ctx_p->ut.ngroups = sys_getgroups(0, NULL);
213 :
214 4508465 : if (ctx_p->ut.ngroups != 0) {
215 3107613 : if (!(ctx_p->ut.groups = SMB_MALLOC_ARRAY(gid_t, ctx_p->ut.ngroups))) {
216 0 : DEBUG(0, ("Out of memory in push_sec_ctx()\n"));
217 0 : TALLOC_FREE(ctx_p->token);
218 0 : return False;
219 : }
220 :
221 3107613 : sys_getgroups(ctx_p->ut.ngroups, ctx_p->ut.groups);
222 : } else {
223 1400852 : ctx_p->ut.groups = NULL;
224 : }
225 :
226 4508465 : END_PROFILE(push_sec_ctx);
227 :
228 4500857 : return True;
229 : }
230 :
231 : #ifndef HAVE_DARWIN_INITGROUPS
232 : /****************************************************************************
233 : Become the specified uid and gid.
234 : ****************************************************************************/
235 :
236 9913698 : static bool become_id(uid_t uid, gid_t gid)
237 : {
238 9913698 : return become_gid(gid) && become_uid(uid);
239 : }
240 :
241 : /****************************************************************************
242 : Change UNIX security context. Calls panic if not successful so no return value.
243 : ****************************************************************************/
244 : /* Normal credential switch path. */
245 :
246 9913698 : static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
247 : {
248 : /* Start context switch */
249 9913698 : gain_root();
250 : #ifdef HAVE_SETGROUPS
251 9913698 : if (sys_setgroups(gid, ngroups, groups) != 0 && !non_root_mode()) {
252 0 : smb_panic("sys_setgroups failed");
253 : }
254 : #endif
255 9913698 : become_id(uid, gid);
256 : /* end context switch */
257 9913698 : }
258 :
259 : #else /* HAVE_DARWIN_INITGROUPS */
260 :
261 : /* The Darwin groups implementation is a little unusual. The list of
262 : * groups in the kernel credential is not exhaustive, but more like
263 : * a cache. The full group list is held in userspace and checked
264 : * dynamically.
265 : *
266 : * This is an optional mechanism, and setgroups(2) opts out
267 : * of it. That is, if you call setgroups, then the list of groups you
268 : * set are the only groups that are ever checked. This is not what we
269 : * want. We want to opt in to the dynamic resolution mechanism, so we
270 : * need to specify the uid of the user whose group list (cache) we are
271 : * setting.
272 : *
273 : * The Darwin rules are:
274 : * 1. Thou shalt setegid, initgroups and seteuid IN THAT ORDER
275 : * 2. Thou shalt not pass more that NGROUPS_MAX to initgroups
276 : * 3. Thou shalt leave the first entry in the groups list well alone
277 : */
278 :
279 : #include <sys/syscall.h>
280 :
281 : static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
282 : {
283 : int max = NGROUPS_MAX;
284 :
285 : /* Start context switch */
286 : gain_root();
287 :
288 : become_gid(gid);
289 :
290 :
291 : if (syscall(SYS_initgroups, (ngroups > max) ? max : ngroups,
292 : groups, uid) == -1 && !non_root_mode()) {
293 : DEBUG(0, ("WARNING: failed to set group list "
294 : "(%d groups) for UID %d: %s\n",
295 : ngroups, uid, strerror(errno)));
296 : smb_panic("sys_setgroups failed");
297 : }
298 :
299 : become_uid(uid);
300 : /* end context switch */
301 : }
302 :
303 : #endif /* HAVE_DARWIN_INITGROUPS */
304 :
305 : /****************************************************************************
306 : Set the current security context to a given user.
307 : ****************************************************************************/
308 :
309 5405239 : static void set_sec_ctx_internal(uid_t uid, gid_t gid,
310 : int ngroups, gid_t *groups,
311 : const struct security_token *token)
312 : {
313 5405239 : struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
314 :
315 : /* Set the security context */
316 :
317 5405239 : DEBUG(4, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
318 : (unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));
319 :
320 5405239 : security_token_debug(DBGC_CLASS, 5, token);
321 5405239 : debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups);
322 :
323 : /* Change uid, gid and supplementary group list. */
324 5405239 : set_unix_security_ctx(uid, gid, ngroups, groups);
325 :
326 5405239 : ctx_p->ut.ngroups = ngroups;
327 :
328 5405239 : SAFE_FREE(ctx_p->ut.groups);
329 5405239 : if (token && (token == ctx_p->token)) {
330 0 : smb_panic("DUPLICATE_TOKEN");
331 : }
332 :
333 5405239 : TALLOC_FREE(ctx_p->token);
334 :
335 5405239 : if (ngroups) {
336 708375 : ctx_p->ut.groups = (gid_t *)smb_xmemdup(groups,
337 : sizeof(gid_t) * ngroups);
338 : } else {
339 4696864 : ctx_p->ut.groups = NULL;
340 : }
341 :
342 5405239 : if (token) {
343 708375 : ctx_p->token = security_token_duplicate(NULL, token);
344 708375 : if (!ctx_p->token) {
345 0 : smb_panic("security_token_duplicate failed");
346 : }
347 : } else {
348 4696864 : ctx_p->token = NULL;
349 : }
350 :
351 5405239 : ctx_p->ut.uid = uid;
352 5405239 : ctx_p->ut.gid = gid;
353 :
354 : /* Update current_user stuff */
355 :
356 5405239 : current_user.ut.uid = uid;
357 5405239 : current_user.ut.gid = gid;
358 5405239 : current_user.ut.ngroups = ngroups;
359 5405239 : current_user.ut.groups = groups;
360 5405239 : current_user.nt_user_token = ctx_p->token;
361 :
362 : /*
363 : * Delete any ChDir cache. We can't assume
364 : * the new uid has access to current working
365 : * directory.
366 : * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14682
367 : */
368 5405239 : SAFE_FREE(LastDir);
369 5405239 : }
370 :
371 708393 : void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, const struct security_token *token)
372 : {
373 708393 : START_PROFILE(set_sec_ctx);
374 708393 : set_sec_ctx_internal(uid, gid, ngroups, groups, token);
375 708393 : END_PROFILE(set_sec_ctx);
376 708393 : }
377 :
378 : /****************************************************************************
379 : Become root context.
380 : ****************************************************************************/
381 :
382 4696846 : void set_root_sec_ctx(void)
383 : {
384 : /* May need to worry about supplementary groups at some stage */
385 :
386 4696846 : START_PROFILE(set_root_sec_ctx);
387 4696846 : set_sec_ctx_internal(0, 0, 0, NULL, NULL);
388 4696846 : END_PROFILE(set_root_sec_ctx);
389 4696846 : }
390 :
391 : /****************************************************************************
392 : Pop a security context from the stack.
393 : ****************************************************************************/
394 :
395 4508459 : bool pop_sec_ctx(void)
396 : {
397 7608 : struct sec_ctx *ctx_p;
398 7608 : struct sec_ctx *prev_ctx_p;
399 :
400 4508459 : START_PROFILE(pop_sec_ctx);
401 :
402 : /* Check for stack underflow */
403 :
404 4508459 : if (sec_ctx_stack_ndx == 0) {
405 0 : DEBUG(0, ("Security context stack underflow!\n"));
406 0 : smb_panic("Security context stack underflow!");
407 : }
408 :
409 4508459 : ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
410 :
411 : /* Clear previous user info */
412 :
413 4508459 : ctx_p->ut.uid = (uid_t)-1;
414 4508459 : ctx_p->ut.gid = (gid_t)-1;
415 :
416 4508459 : SAFE_FREE(ctx_p->ut.groups);
417 4508459 : ctx_p->ut.ngroups = 0;
418 :
419 4508459 : TALLOC_FREE(ctx_p->token);
420 :
421 : /* Pop back previous user */
422 :
423 4508459 : sec_ctx_stack_ndx--;
424 :
425 4508459 : prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
426 :
427 : /* Change uid, gid and supplementary group list. */
428 4508459 : set_unix_security_ctx(prev_ctx_p->ut.uid,
429 : prev_ctx_p->ut.gid,
430 4508459 : prev_ctx_p->ut.ngroups,
431 : prev_ctx_p->ut.groups);
432 :
433 : /* Update current_user stuff */
434 :
435 4508459 : current_user.ut.uid = prev_ctx_p->ut.uid;
436 4508459 : current_user.ut.gid = prev_ctx_p->ut.gid;
437 4508459 : current_user.ut.ngroups = prev_ctx_p->ut.ngroups;
438 4508459 : current_user.ut.groups = prev_ctx_p->ut.groups;
439 4508459 : current_user.nt_user_token = prev_ctx_p->token;
440 :
441 4508459 : END_PROFILE(pop_sec_ctx);
442 :
443 4508459 : DEBUG(4, ("pop_sec_ctx (%u, %u) - sec_ctx_stack_ndx = %d\n",
444 : (unsigned int)geteuid(), (unsigned int)getegid(), sec_ctx_stack_ndx));
445 :
446 4508459 : return True;
447 : }
448 :
449 : /* Initialise the security context system */
450 :
451 0 : void init_sec_ctx(void)
452 : {
453 0 : int i;
454 0 : struct sec_ctx *ctx_p;
455 :
456 : /* Initialise security context stack */
457 :
458 0 : memset(sec_ctx_stack, 0, sizeof(struct sec_ctx) * MAX_SEC_CTX_DEPTH);
459 :
460 0 : for (i = 0; i < MAX_SEC_CTX_DEPTH; i++) {
461 0 : sec_ctx_stack[i].ut.uid = (uid_t)-1;
462 0 : sec_ctx_stack[i].ut.gid = (gid_t)-1;
463 : }
464 :
465 : /* Initialise first level of stack. It is the current context */
466 0 : ctx_p = &sec_ctx_stack[0];
467 :
468 0 : ctx_p->ut.uid = geteuid();
469 0 : ctx_p->ut.gid = getegid();
470 :
471 0 : get_current_groups(ctx_p->ut.gid, &ctx_p->ut.ngroups, &ctx_p->ut.groups);
472 :
473 0 : ctx_p->token = NULL; /* Maps to guest user. */
474 :
475 : /* Initialise current_user global */
476 :
477 0 : current_user.ut.uid = ctx_p->ut.uid;
478 0 : current_user.ut.gid = ctx_p->ut.gid;
479 0 : current_user.ut.ngroups = ctx_p->ut.ngroups;
480 0 : current_user.ut.groups = ctx_p->ut.groups;
481 :
482 : /* The conn and vuid are usually taken care of by other modules.
483 : We initialise them here. */
484 :
485 0 : current_user.conn = NULL;
486 0 : current_user.vuid = UID_FIELD_INVALID;
487 0 : current_user.nt_user_token = NULL;
488 0 : }
489 :
490 : /*************************************************************
491 : Called when we're inside a become_root() temporary escalation
492 : of privileges and the nt_user_token is NULL. Return the last
493 : active token on the context stack. We know there is at least
494 : one valid non-NULL token on the stack so panic if we underflow.
495 : *************************************************************/
496 :
497 0 : const struct security_token *sec_ctx_active_token(void)
498 : {
499 0 : int stack_index = sec_ctx_stack_ndx;
500 0 : struct sec_ctx *ctx_p = &sec_ctx_stack[stack_index];
501 :
502 0 : while (ctx_p->token == NULL) {
503 0 : stack_index--;
504 0 : if (stack_index < 0) {
505 0 : DEBUG(0, ("Security context active token "
506 : "stack underflow!\n"));
507 0 : smb_panic("Security context active token "
508 : "stack underflow!");
509 : }
510 0 : ctx_p = &sec_ctx_stack[stack_index];
511 : }
512 0 : return ctx_p->token;
513 : }
|