Samba 3: added Samba 3.0.24 sources
[tomato.git] / release / src / router / samba3 / source / smbd / uid.c
blobc62c9d928abac5b2e882269c277e8fc9b941ddc2
1 /*
2 Unix SMB/CIFS implementation.
3 uid/user handling
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
21 #include "includes.h"
23 /* what user is current? */
24 extern struct current_user current_user;
26 /****************************************************************************
27 Iterator functions for getting all gid's from current_user.
28 ****************************************************************************/
30 gid_t get_current_user_gid_first(int *piterator)
32 *piterator = 0;
33 return current_user.ut.gid;
36 gid_t get_current_user_gid_next(int *piterator)
38 gid_t ret;
40 if (!current_user.ut.groups || *piterator >= current_user.ut.ngroups) {
41 return (gid_t)-1;
44 ret = current_user.ut.groups[*piterator];
45 (*piterator) += 1;
46 return ret;
49 /****************************************************************************
50 Become the guest user without changing the security context stack.
51 ****************************************************************************/
53 BOOL change_to_guest(void)
55 static struct passwd *pass=NULL;
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);
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
70 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
72 current_user.conn = NULL;
73 current_user.vuid = UID_FIELD_INVALID;
75 TALLOC_FREE(pass);
76 pass = NULL;
78 return True;
81 /*******************************************************************
82 Check if a username is OK.
83 ********************************************************************/
85 static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
87 unsigned int i;
88 struct vuid_cache_entry *ent = NULL;
89 BOOL readonly_share;
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);
100 if (!user_ok_token(vuser->user.unix_name, vuser->nt_user_token, snum))
101 return(False);
103 readonly_share = is_share_read_only_for_token(vuser->user.unix_name,
104 vuser->nt_user_token,
105 conn->service);
107 if (!readonly_share &&
108 !share_access_check(conn, snum, vuser, FILE_WRITE_DATA)) {
109 /* smb.conf allows r/w, but the security descriptor denies
110 * write. Fall back to looking at readonly. */
111 readonly_share = True;
112 DEBUG(5,("falling back to read-only access-evaluation due to "
113 "security descriptor\n"));
116 if (!share_access_check(conn, snum, vuser,
117 readonly_share ?
118 FILE_READ_DATA : FILE_WRITE_DATA)) {
119 return False;
122 i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
123 if (conn->vuid_cache.entries < VUID_CACHE_SIZE)
124 conn->vuid_cache.entries++;
126 ent = &conn->vuid_cache.array[i];
127 ent->vuid = vuser->vuid;
128 ent->read_only = readonly_share;
130 ent->admin_user = token_contains_name_in_list(
131 vuser->user.unix_name, NULL, vuser->nt_user_token,
132 lp_admin_users(conn->service));
134 conn->read_only = ent->read_only;
135 conn->admin_user = ent->admin_user;
137 return(True);
140 /****************************************************************************
141 Become the user of a connection number without changing the security context
142 stack, but modify the current_user entries.
143 ****************************************************************************/
145 BOOL change_to_user(connection_struct *conn, uint16 vuid)
147 user_struct *vuser = get_valid_user_struct(vuid);
148 int snum;
149 gid_t gid;
150 uid_t uid;
151 char group_c;
152 BOOL must_free_token = False;
153 NT_USER_TOKEN *token = NULL;
155 if (!conn) {
156 DEBUG(2,("change_to_user: Connection not open\n"));
157 return(False);
161 * We need a separate check in security=share mode due to vuid
162 * always being UID_FIELD_INVALID. If we don't do this then
163 * in share mode security we are *always* changing uid's between
164 * SMB's - this hurts performance - Badly.
167 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
168 (current_user.ut.uid == conn->uid)) {
169 DEBUG(4,("change_to_user: Skipping user change - already "
170 "user\n"));
171 return(True);
172 } else if ((current_user.conn == conn) &&
173 (vuser != 0) && (current_user.vuid == vuid) &&
174 (current_user.ut.uid == vuser->uid)) {
175 DEBUG(4,("change_to_user: Skipping user change - already "
176 "user\n"));
177 return(True);
180 snum = SNUM(conn);
182 if ((vuser) && !check_user_ok(conn, vuser, snum)) {
183 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
184 "not permitted access to share %s.\n",
185 vuser->user.smb_name, vuser->user.unix_name, vuid,
186 lp_servicename(snum)));
187 return False;
190 if (conn->force_user) /* security = share sets this too */ {
191 uid = conn->uid;
192 gid = conn->gid;
193 current_user.ut.groups = conn->groups;
194 current_user.ut.ngroups = conn->ngroups;
195 token = conn->nt_user_token;
196 } else if (vuser) {
197 uid = conn->admin_user ? 0 : vuser->uid;
198 gid = vuser->gid;
199 current_user.ut.ngroups = vuser->n_groups;
200 current_user.ut.groups = vuser->groups;
201 token = vuser->nt_user_token;
202 } else {
203 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
204 "share %s.\n",vuid, lp_servicename(snum) ));
205 return False;
209 * See if we should force group for this service.
210 * If so this overrides any group set in the force
211 * user code.
214 if((group_c = *lp_force_group(snum))) {
216 token = dup_nt_token(NULL, token);
217 if (token == NULL) {
218 DEBUG(0, ("dup_nt_token failed\n"));
219 return False;
221 must_free_token = True;
223 if(group_c == '+') {
226 * Only force group if the user is a member of
227 * the service group. Check the group memberships for
228 * this user (we already have this) to
229 * see if we should force the group.
232 int i;
233 for (i = 0; i < current_user.ut.ngroups; i++) {
234 if (current_user.ut.groups[i] == conn->gid) {
235 gid = conn->gid;
236 gid_to_sid(&token->user_sids[1], gid);
237 break;
240 } else {
241 gid = conn->gid;
242 gid_to_sid(&token->user_sids[1], gid);
246 set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
247 token);
250 * Free the new token (as set_sec_ctx copies it).
253 if (must_free_token)
254 TALLOC_FREE(token);
256 current_user.conn = conn;
257 current_user.vuid = vuid;
259 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
260 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
262 return(True);
265 /****************************************************************************
266 Go back to being root without changing the security context stack,
267 but modify the current_user entries.
268 ****************************************************************************/
270 BOOL change_to_root_user(void)
272 set_root_sec_ctx();
274 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
275 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
277 current_user.conn = NULL;
278 current_user.vuid = UID_FIELD_INVALID;
280 return(True);
283 /****************************************************************************
284 Become the user of an authenticated connected named pipe.
285 When this is called we are currently running as the connection
286 user. Doesn't modify current_user.
287 ****************************************************************************/
289 BOOL become_authenticated_pipe_user(pipes_struct *p)
291 if (!push_sec_ctx())
292 return False;
294 set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid,
295 p->pipe_user.ut.ngroups, p->pipe_user.ut.groups,
296 p->pipe_user.nt_user_token);
298 return True;
301 /****************************************************************************
302 Unbecome the user of an authenticated connected named pipe.
303 When this is called we are running as the authenticated pipe
304 user and need to go back to being the connection user. Doesn't modify
305 current_user.
306 ****************************************************************************/
308 BOOL unbecome_authenticated_pipe_user(void)
310 return pop_sec_ctx();
313 /****************************************************************************
314 Utility functions used by become_xxx/unbecome_xxx.
315 ****************************************************************************/
317 struct conn_ctx {
318 connection_struct *conn;
319 uint16 vuid;
322 /* A stack of current_user connection contexts. */
324 static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
325 static int conn_ctx_stack_ndx;
327 static void push_conn_ctx(void)
329 struct conn_ctx *ctx_p;
331 /* Check we don't overflow our stack */
333 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
334 DEBUG(0, ("Connection context stack overflow!\n"));
335 smb_panic("Connection context stack overflow!\n");
338 /* Store previous user context */
339 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
341 ctx_p->conn = current_user.conn;
342 ctx_p->vuid = current_user.vuid;
344 DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
345 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
347 conn_ctx_stack_ndx++;
350 static void pop_conn_ctx(void)
352 struct conn_ctx *ctx_p;
354 /* Check for stack underflow. */
356 if (conn_ctx_stack_ndx == 0) {
357 DEBUG(0, ("Connection context stack underflow!\n"));
358 smb_panic("Connection context stack underflow!\n");
361 conn_ctx_stack_ndx--;
362 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
364 current_user.conn = ctx_p->conn;
365 current_user.vuid = ctx_p->vuid;
367 ctx_p->conn = NULL;
368 ctx_p->vuid = UID_FIELD_INVALID;
371 /****************************************************************************
372 Temporarily become a root user. Must match with unbecome_root(). Saves and
373 restores the connection context.
374 ****************************************************************************/
376 void become_root(void)
378 push_sec_ctx();
379 push_conn_ctx();
380 set_root_sec_ctx();
383 /* Unbecome the root user */
385 void unbecome_root(void)
387 pop_sec_ctx();
388 pop_conn_ctx();
391 /****************************************************************************
392 Push the current security context then force a change via change_to_user().
393 Saves and restores the connection context.
394 ****************************************************************************/
396 BOOL become_user(connection_struct *conn, uint16 vuid)
398 if (!push_sec_ctx())
399 return False;
401 push_conn_ctx();
403 if (!change_to_user(conn, vuid)) {
404 pop_sec_ctx();
405 pop_conn_ctx();
406 return False;
409 return True;
412 BOOL unbecome_user(void)
414 pop_sec_ctx();
415 pop_conn_ctx();
416 return True;