source: branches/samba-3.3.x/source/smbd/uid.c@ 310

Last change on this file since 310 was 274, checked in by Herwig Bauernfeind, 16 years ago

Update 3.3 branch to 3.3.5

File size: 14.6 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 uid/user handling
4 Copyright (C) Andrew Tridgell 1992-1998
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
22/* what user is current? */
23extern struct current_user current_user;
24
25/****************************************************************************
26 Become the guest user without changing the security context stack.
27****************************************************************************/
28
29bool change_to_guest(void)
30{
31 static struct passwd *pass=NULL;
32
33 if (!pass) {
34 /* Don't need to free() this as its stored in a static */
35 pass = getpwnam_alloc(talloc_autofree_context(), lp_guestaccount());
36 if (!pass)
37 return(False);
38 }
39
40#ifdef AIX
41 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
42 setting IDs */
43 initgroups(pass->pw_name, pass->pw_gid);
44#endif
45
46 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
47
48 current_user.conn = NULL;
49 current_user.vuid = UID_FIELD_INVALID;
50
51 TALLOC_FREE(pass);
52 pass = NULL;
53
54 return True;
55}
56
57/****************************************************************************
58 talloc free the conn->server_info if not used in the vuid cache.
59****************************************************************************/
60
61static void free_conn_server_info_if_unused(connection_struct *conn)
62{
63 unsigned int i;
64
65 for (i = 0; i < VUID_CACHE_SIZE; i++) {
66 struct vuid_cache_entry *ent;
67 ent = &conn->vuid_cache.array[i];
68 if (ent->vuid != UID_FIELD_INVALID &&
69 conn->server_info == ent->server_info) {
70 return;
71 }
72 }
73 /* Not used, safe to free. */
74 TALLOC_FREE(conn->server_info);
75}
76
77/*******************************************************************
78 Check if a username is OK.
79
80 This sets up conn->server_info with a copy related to this vuser that
81 later code can then mess with.
82********************************************************************/
83
84static bool check_user_ok(connection_struct *conn,
85 uint16_t vuid,
86 const struct auth_serversupplied_info *server_info,
87 int snum)
88{
89 bool valid_vuid = (vuid != UID_FIELD_INVALID);
90 unsigned int i;
91 bool readonly_share;
92 bool admin_user;
93
94 if (valid_vuid) {
95 struct vuid_cache_entry *ent;
96
97 for (i=0; i<VUID_CACHE_SIZE; i++) {
98 ent = &conn->vuid_cache.array[i];
99 if (ent->vuid == vuid) {
100 free_conn_server_info_if_unused(conn);
101 conn->server_info = ent->server_info;
102 conn->read_only = ent->read_only;
103 conn->admin_user = ent->admin_user;
104 return(True);
105 }
106 }
107 }
108
109 if (!user_ok_token(server_info->unix_name,
110 pdb_get_domain(server_info->sam_account),
111 server_info->ptok, snum))
112 return(False);
113
114 readonly_share = is_share_read_only_for_token(
115 server_info->unix_name,
116 pdb_get_domain(server_info->sam_account),
117 server_info->ptok,
118 conn);
119
120 if (!readonly_share &&
121 !share_access_check(server_info->ptok, lp_servicename(snum),
122 FILE_WRITE_DATA)) {
123 /* smb.conf allows r/w, but the security descriptor denies
124 * write. Fall back to looking at readonly. */
125 readonly_share = True;
126 DEBUG(5,("falling back to read-only access-evaluation due to "
127 "security descriptor\n"));
128 }
129
130 if (!share_access_check(server_info->ptok, lp_servicename(snum),
131 readonly_share ?
132 FILE_READ_DATA : FILE_WRITE_DATA)) {
133 return False;
134 }
135
136 admin_user = token_contains_name_in_list(
137 server_info->unix_name,
138 pdb_get_domain(server_info->sam_account),
139 NULL, server_info->ptok, lp_admin_users(snum));
140
141 if (valid_vuid) {
142 struct vuid_cache_entry *ent =
143 &conn->vuid_cache.array[conn->vuid_cache.next_entry];
144
145 conn->vuid_cache.next_entry =
146 (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
147
148 TALLOC_FREE(ent->server_info);
149
150 /*
151 * If force_user was set, all server_info's are based on the same
152 * username-based faked one.
153 */
154
155 ent->server_info = copy_serverinfo(
156 conn, conn->force_user ? conn->server_info : server_info);
157
158 if (ent->server_info == NULL) {
159 ent->vuid = UID_FIELD_INVALID;
160 return false;
161 }
162
163 ent->vuid = vuid;
164 ent->read_only = readonly_share;
165 ent->admin_user = admin_user;
166 free_conn_server_info_if_unused(conn);
167 conn->server_info = ent->server_info;
168 }
169
170 conn->read_only = readonly_share;
171 conn->admin_user = admin_user;
172
173 return(True);
174}
175
176/****************************************************************************
177 Clear a vuid out of the connection's vuid cache
178 This is only called on SMBulogoff.
179****************************************************************************/
180
181void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid)
182{
183 int i;
184
185 for (i=0; i<VUID_CACHE_SIZE; i++) {
186 struct vuid_cache_entry *ent;
187
188 ent = &conn->vuid_cache.array[i];
189
190 if (ent->vuid == vuid) {
191 ent->vuid = UID_FIELD_INVALID;
192 /*
193 * We need to keep conn->server_info around
194 * if it's equal to ent->server_info as a SMBulogoff
195 * is often followed by a SMBtdis (with an invalid
196 * vuid). The debug code (or regular code in
197 * vfs_full_audit) wants to refer to the
198 * conn->server_info pointer to print debug
199 * statements. Theoretically this is a bug,
200 * as once the vuid is gone the server_info
201 * on the conn struct isn't valid any more,
202 * but there's enough code that assumes
203 * conn->server_info is never null that
204 * it's easier to hold onto the old pointer
205 * until we get a new sessionsetupX.
206 * As everything is hung off the
207 * conn pointer as a talloc context we're not
208 * leaking memory here. See bug #6315. JRA.
209 */
210 if (conn->server_info == ent->server_info) {
211 ent->server_info = NULL;
212 } else {
213 TALLOC_FREE(ent->server_info);
214 }
215 ent->read_only = False;
216 ent->admin_user = False;
217 }
218 }
219}
220
221/****************************************************************************
222 Become the user of a connection number without changing the security context
223 stack, but modify the current_user entries.
224****************************************************************************/
225
226bool change_to_user(connection_struct *conn, uint16 vuid)
227{
228 const struct auth_serversupplied_info *server_info = NULL;
229 user_struct *vuser = get_valid_user_struct(vuid);
230 int snum;
231 gid_t gid;
232 uid_t uid;
233 char group_c;
234 int num_groups = 0;
235 gid_t *group_list = NULL;
236
237 if (!conn) {
238 DEBUG(2,("change_to_user: Connection not open\n"));
239 return(False);
240 }
241
242 /*
243 * We need a separate check in security=share mode due to vuid
244 * always being UID_FIELD_INVALID. If we don't do this then
245 * in share mode security we are *always* changing uid's between
246 * SMB's - this hurts performance - Badly.
247 */
248
249 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
250 (current_user.ut.uid == conn->server_info->utok.uid)) {
251 DEBUG(4,("change_to_user: Skipping user change - already "
252 "user\n"));
253 return(True);
254 } else if ((current_user.conn == conn) &&
255 (vuser != NULL) && (current_user.vuid == vuid) &&
256 (current_user.ut.uid == vuser->server_info->utok.uid)) {
257 DEBUG(4,("change_to_user: Skipping user change - already "
258 "user\n"));
259 return(True);
260 }
261
262 snum = SNUM(conn);
263
264 server_info = vuser ? vuser->server_info : conn->server_info;
265
266 if (!server_info) {
267 /* Invalid vuid sent - even with security = share. */
268 DEBUG(2,("change_to_user: Invalid vuid %d used on "
269 "share %s.\n",vuid, lp_servicename(snum) ));
270 return false;
271 }
272
273 if (!check_user_ok(conn, vuid, server_info, snum)) {
274 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
275 "not permitted access to share %s.\n",
276 server_info->sanitized_username,
277 server_info->unix_name, vuid,
278 lp_servicename(snum)));
279 return false;
280 }
281
282 /*
283 * conn->server_info is now correctly set up with a copy we can mess
284 * with for force_group etc.
285 */
286
287 if (conn->force_user) /* security = share sets this too */ {
288 uid = conn->server_info->utok.uid;
289 gid = conn->server_info->utok.gid;
290 group_list = conn->server_info->utok.groups;
291 num_groups = conn->server_info->utok.ngroups;
292 } else if (vuser) {
293 uid = conn->admin_user ? 0 : vuser->server_info->utok.uid;
294 gid = conn->server_info->utok.gid;
295 num_groups = conn->server_info->utok.ngroups;
296 group_list = conn->server_info->utok.groups;
297 } else {
298 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
299 "share %s.\n",vuid, lp_servicename(snum) ));
300 return False;
301 }
302
303 /*
304 * See if we should force group for this service.
305 * If so this overrides any group set in the force
306 * user code.
307 */
308
309 if((group_c = *lp_force_group(snum))) {
310
311 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
312
313 if(group_c == '+') {
314
315 /*
316 * Only force group if the user is a member of
317 * the service group. Check the group memberships for
318 * this user (we already have this) to
319 * see if we should force the group.
320 */
321
322 int i;
323 for (i = 0; i < num_groups; i++) {
324 if (group_list[i]
325 == conn->force_group_gid) {
326 conn->server_info->utok.gid =
327 conn->force_group_gid;
328 gid = conn->force_group_gid;
329 gid_to_sid(&conn->server_info->ptok
330 ->user_sids[1], gid);
331 break;
332 }
333 }
334 } else {
335 conn->server_info->utok.gid = conn->force_group_gid;
336 gid = conn->force_group_gid;
337 gid_to_sid(&conn->server_info->ptok->user_sids[1],
338 gid);
339 }
340 }
341
342 /* Now set current_user since we will immediately also call
343 set_sec_ctx() */
344
345 current_user.ut.ngroups = num_groups;
346 current_user.ut.groups = group_list;
347
348 set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
349 conn->server_info->ptok);
350
351 current_user.conn = conn;
352 current_user.vuid = vuid;
353
354 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
355 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
356
357 return(True);
358}
359
360/****************************************************************************
361 Go back to being root without changing the security context stack,
362 but modify the current_user entries.
363****************************************************************************/
364
365bool change_to_root_user(void)
366{
367 set_root_sec_ctx();
368
369 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
370 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
371
372 current_user.conn = NULL;
373 current_user.vuid = UID_FIELD_INVALID;
374
375 return(True);
376}
377
378/****************************************************************************
379 Become the user of an authenticated connected named pipe.
380 When this is called we are currently running as the connection
381 user. Doesn't modify current_user.
382****************************************************************************/
383
384bool become_authenticated_pipe_user(pipes_struct *p)
385{
386 if (!push_sec_ctx())
387 return False;
388
389 set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid,
390 p->pipe_user.ut.ngroups, p->pipe_user.ut.groups,
391 p->pipe_user.nt_user_token);
392
393 return True;
394}
395
396/****************************************************************************
397 Unbecome the user of an authenticated connected named pipe.
398 When this is called we are running as the authenticated pipe
399 user and need to go back to being the connection user. Doesn't modify
400 current_user.
401****************************************************************************/
402
403bool unbecome_authenticated_pipe_user(void)
404{
405 return pop_sec_ctx();
406}
407
408/****************************************************************************
409 Utility functions used by become_xxx/unbecome_xxx.
410****************************************************************************/
411
412struct conn_ctx {
413 connection_struct *conn;
414 uint16 vuid;
415};
416
417/* A stack of current_user connection contexts. */
418
419static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
420static int conn_ctx_stack_ndx;
421
422static void push_conn_ctx(void)
423{
424 struct conn_ctx *ctx_p;
425
426 /* Check we don't overflow our stack */
427
428 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
429 DEBUG(0, ("Connection context stack overflow!\n"));
430 smb_panic("Connection context stack overflow!\n");
431 }
432
433 /* Store previous user context */
434 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
435
436 ctx_p->conn = current_user.conn;
437 ctx_p->vuid = current_user.vuid;
438
439 DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
440 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
441
442 conn_ctx_stack_ndx++;
443}
444
445static void pop_conn_ctx(void)
446{
447 struct conn_ctx *ctx_p;
448
449 /* Check for stack underflow. */
450
451 if (conn_ctx_stack_ndx == 0) {
452 DEBUG(0, ("Connection context stack underflow!\n"));
453 smb_panic("Connection context stack underflow!\n");
454 }
455
456 conn_ctx_stack_ndx--;
457 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
458
459 current_user.conn = ctx_p->conn;
460 current_user.vuid = ctx_p->vuid;
461
462 ctx_p->conn = NULL;
463 ctx_p->vuid = UID_FIELD_INVALID;
464}
465
466/****************************************************************************
467 Temporarily become a root user. Must match with unbecome_root(). Saves and
468 restores the connection context.
469****************************************************************************/
470
471void become_root(void)
472{
473 /*
474 * no good way to handle push_sec_ctx() failing without changing
475 * the prototype of become_root()
476 */
477 if (!push_sec_ctx()) {
478 smb_panic("become_root: push_sec_ctx failed");
479 }
480 push_conn_ctx();
481 set_root_sec_ctx();
482}
483
484/* Unbecome the root user */
485
486void unbecome_root(void)
487{
488 pop_sec_ctx();
489 pop_conn_ctx();
490}
491
492/****************************************************************************
493 Push the current security context then force a change via change_to_user().
494 Saves and restores the connection context.
495****************************************************************************/
496
497bool become_user(connection_struct *conn, uint16 vuid)
498{
499 if (!push_sec_ctx())
500 return False;
501
502 push_conn_ctx();
503
504 if (!change_to_user(conn, vuid)) {
505 pop_sec_ctx();
506 pop_conn_ctx();
507 return False;
508 }
509
510 return True;
511}
512
513bool unbecome_user(void)
514{
515 pop_sec_ctx();
516 pop_conn_ctx();
517 return True;
518}
Note: See TracBrowser for help on using the repository browser.