source: branches/samba-3.2.x/source/smbd/uid.c@ 252

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

Update 3.2 branch to 3.2.6

File size: 13.2 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 Iterator functions for getting all gid's from current_user.
27****************************************************************************/
28
29gid_t get_current_user_gid_first(int *piterator)
30{
31 *piterator = 0;
32 return current_user.ut.gid;
33}
34
35gid_t get_current_user_gid_next(int *piterator)
36{
37 gid_t ret;
38
39 if (!current_user.ut.groups || *piterator >= current_user.ut.ngroups) {
40 return (gid_t)-1;
41 }
42
43 ret = current_user.ut.groups[*piterator];
44 (*piterator) += 1;
45 return ret;
46}
47
48/****************************************************************************
49 Become the guest user without changing the security context stack.
50****************************************************************************/
51
52bool change_to_guest(void)
53{
54 static struct passwd *pass=NULL;
55
56 if (!pass) {
57 /* Don't need to free() this as its stored in a static */
58 pass = getpwnam_alloc(NULL, lp_guestaccount());
59 if (!pass)
60 return(False);
61 }
62
63#ifdef AIX
64 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
65 setting IDs */
66 initgroups(pass->pw_name, pass->pw_gid);
67#endif
68
69 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
70
71 current_user.conn = NULL;
72 current_user.vuid = UID_FIELD_INVALID;
73
74 TALLOC_FREE(pass);
75 pass = NULL;
76
77 return True;
78}
79
80/*******************************************************************
81 Check if a username is OK.
82********************************************************************/
83
84static bool check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
85{
86 unsigned int i;
87 struct vuid_cache_entry *ent = NULL;
88 bool readonly_share;
89 NT_USER_TOKEN *token;
90
91 for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
92 if (conn->vuid_cache.array[i].vuid == vuser->vuid) {
93 ent = &conn->vuid_cache.array[i];
94 conn->read_only = ent->read_only;
95 conn->admin_user = ent->admin_user;
96 return(True);
97 }
98 }
99
100 if (!user_ok_token(vuser->user.unix_name, vuser->nt_user_token, snum))
101 return(False);
102
103 readonly_share = is_share_read_only_for_token(vuser->user.unix_name,
104 vuser->nt_user_token,
105 conn);
106
107 token = conn->nt_user_token ?
108 conn->nt_user_token : vuser->nt_user_token;
109
110 if (!readonly_share &&
111 !share_access_check(token, lp_servicename(snum),
112 FILE_WRITE_DATA)) {
113 /* smb.conf allows r/w, but the security descriptor denies
114 * write. Fall back to looking at readonly. */
115 readonly_share = True;
116 DEBUG(5,("falling back to read-only access-evaluation due to "
117 "security descriptor\n"));
118 }
119
120 if (!share_access_check(token, lp_servicename(snum),
121 readonly_share ?
122 FILE_READ_DATA : FILE_WRITE_DATA)) {
123 return False;
124 }
125
126 i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
127 if (conn->vuid_cache.entries < VUID_CACHE_SIZE)
128 conn->vuid_cache.entries++;
129
130 ent = &conn->vuid_cache.array[i];
131 ent->vuid = vuser->vuid;
132 ent->read_only = readonly_share;
133
134 ent->admin_user = token_contains_name_in_list(
135 vuser->user.unix_name, NULL, vuser->nt_user_token,
136 lp_admin_users(SNUM(conn)));
137
138 conn->read_only = ent->read_only;
139 conn->admin_user = ent->admin_user;
140
141 return(True);
142}
143
144/*******************************************************************
145 Check if a username is OK in share level security.
146********************************************************************/
147
148static bool check_user_ok_sharelevel_security(connection_struct *conn,
149 const char *unix_name,
150 int snum)
151{
152 NT_USER_TOKEN *token = conn->nt_user_token;
153
154 if (!user_ok_token(unix_name, token, snum)) {
155 return false;
156 }
157
158 conn->read_only = is_share_read_only_for_token(unix_name,
159 token,
160 conn);
161
162 if (!conn->read_only &&
163 !share_access_check(token, lp_servicename(snum),
164 FILE_WRITE_DATA)) {
165 /* smb.conf allows r/w, but the security descriptor denies
166 * write. Fall back to looking at readonly. */
167 conn->read_only = true;
168 DEBUG(5,("falling back to read-only access-evaluation due to "
169 "security descriptor\n"));
170 }
171
172 if (!share_access_check(token, lp_servicename(snum),
173 conn->read_only ?
174 FILE_READ_DATA : FILE_WRITE_DATA)) {
175 return false;
176 }
177
178 conn->admin_user = token_contains_name_in_list(
179 unix_name, NULL, token,
180 lp_admin_users(SNUM(conn)));
181
182 return true;
183}
184
185
186/****************************************************************************
187 Become the user of a connection number without changing the security context
188 stack, but modify the current_user entries.
189****************************************************************************/
190
191bool change_to_user(connection_struct *conn, uint16 vuid)
192{
193#ifndef __OS2__
194
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#endif
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 /*
442 * no good way to handle push_sec_ctx() failing without changing
443 * the prototype of become_root()
444 */
445 if (!push_sec_ctx()) {
446 smb_panic("become_root: push_sec_ctx failed");
447 }
448 push_conn_ctx();
449 set_root_sec_ctx();
450}
451
452/* Unbecome the root user */
453
454void unbecome_root(void)
455{
456 pop_sec_ctx();
457 pop_conn_ctx();
458}
459
460/****************************************************************************
461 Push the current security context then force a change via change_to_user().
462 Saves and restores the connection context.
463****************************************************************************/
464
465bool become_user(connection_struct *conn, uint16 vuid)
466{
467 if (!push_sec_ctx())
468 return False;
469
470 push_conn_ctx();
471
472 if (!change_to_user(conn, vuid)) {
473 pop_sec_ctx();
474 pop_conn_ctx();
475 return False;
476 }
477
478 return True;
479}
480
481bool unbecome_user(void)
482{
483 pop_sec_ctx();
484 pop_conn_ctx();
485 return True;
486}
Note: See TracBrowser for help on using the repository browser.