source: branches/samba-3.0/source/smbd/uid.c@ 347

Last change on this file since 347 was 165, checked in by Paul Smedley, 16 years ago

Add 'missing' 3.0.34 diffs

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