2 Unix SMB/CIFS implementation.
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.
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)
33 return current_user.gid;
36 gid_t get_current_user_gid_next(int *piterator)
40 if (!current_user.groups || *piterator >= current_user.ngroups) {
44 ret = current_user.groups[*piterator];
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;
58 /* Don't need to free() this as its stored in a static */
59 pass = getpwnam_alloc(lp_guestaccount());
65 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
67 initgroups(pass->pw_name, pass->pw_gid);
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;
80 /****************************************************************************
81 Readonly share for this user ?
82 ****************************************************************************/
84 static BOOL is_share_read_only_for_user(connection_struct *conn, user_struct *vuser)
87 const char *service = lp_servicename(conn->service);
88 BOOL read_only_ret = lp_readonly(conn->service);
93 str_list_copy(&list, lp_readlist(conn->service));
95 if (!str_list_sub_basic(list, vuser->user.smb_name) ) {
96 DEBUG(0, ("is_share_read_only_for_user: ERROR: read list substitution failed\n"));
98 if (!str_list_substitute(list, "%S", service)) {
99 DEBUG(0, ("is_share_read_only_for_user: ERROR: read list service substitution failed\n"));
101 if (user_in_list(vuser->user.unix_name, (const char **)list, vuser->groups, vuser->n_groups)) {
102 read_only_ret = True;
104 str_list_free(&list);
107 str_list_copy(&list, lp_writelist(conn->service));
109 if (!str_list_sub_basic(list, vuser->user.smb_name) ) {
110 DEBUG(0, ("is_share_read_only_for_user: ERROR: write "
111 "list substitution failed\n"));
113 if (!str_list_substitute(list, "%S", service)) {
114 DEBUG(0, ("is_share_read_only_for_user: ERROR: write "
115 "list service substitution failed\n"));
117 if (user_in_list(vuser->user.unix_name, (const char **)list,
118 vuser->groups, vuser->n_groups)) {
119 read_only_ret = False;
121 str_list_free(&list);
124 DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user "
126 read_only_ret ? "read-only" : "read-write",
127 vuser->user.unix_name ));
129 return read_only_ret;
132 /*******************************************************************
133 Check if a username is OK.
134 ********************************************************************/
136 static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
139 struct vuid_cache_entry *ent = NULL;
142 for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
143 if (conn->vuid_cache.array[i].vuid == vuser->vuid) {
144 ent = &conn->vuid_cache.array[i];
145 conn->read_only = ent->read_only;
146 conn->admin_user = ent->admin_user;
151 if (!user_ok(vuser->user.unix_name,snum, vuser->groups, vuser->n_groups))
154 readonly_share = is_share_read_only_for_user(conn, vuser);
156 if (!readonly_share &&
157 !share_access_check(conn, snum, vuser, FILE_WRITE_DATA)) {
158 /* smb.conf allows r/w, but the security descriptor denies
159 * write. Fall back to looking at readonly. */
160 readonly_share = True;
161 DEBUG(5,("falling back to read-only access-evaluation due to security descriptor\n"));
164 if (!share_access_check(conn, snum, vuser, readonly_share ? FILE_READ_DATA : FILE_WRITE_DATA)) {
168 i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
169 if (conn->vuid_cache.entries < VUID_CACHE_SIZE)
170 conn->vuid_cache.entries++;
172 ent = &conn->vuid_cache.array[i];
173 ent->vuid = vuser->vuid;
174 ent->read_only = readonly_share;
176 if (user_in_list(vuser->user.unix_name ,lp_admin_users(conn->service), vuser->groups, vuser->n_groups)) {
177 ent->admin_user = True;
179 ent->admin_user = False;
182 conn->read_only = ent->read_only;
183 conn->admin_user = ent->admin_user;
188 /****************************************************************************
189 Become the user of a connection number without changing the security context
190 stack, but modify the current_user entries.
191 ****************************************************************************/
193 BOOL change_to_user(connection_struct *conn, uint16 vuid)
195 user_struct *vuser = get_valid_user_struct(vuid);
200 BOOL must_free_token = False;
201 NT_USER_TOKEN *token = NULL;
204 DEBUG(2,("change_to_user: Connection not open\n"));
209 * We need a separate check in security=share mode due to vuid
210 * always being UID_FIELD_INVALID. If we don't do this then
211 * in share mode security we are *always* changing uid's between
212 * SMB's - this hurts performance - Badly.
215 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
216 (current_user.uid == conn->uid)) {
217 DEBUG(4,("change_to_user: Skipping user change - already user\n"));
219 } else if ((current_user.conn == conn) &&
220 (vuser != 0) && (current_user.vuid == vuid) &&
221 (current_user.uid == vuser->uid)) {
222 DEBUG(4,("change_to_user: Skipping user change - already user\n"));
228 if ((vuser) && !check_user_ok(conn, vuser, snum)) {
229 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) not permitted access to share %s.\n",
230 vuser->user.smb_name, vuser->user.unix_name, vuid, lp_servicename(snum)));
234 if (conn->force_user) /* security = share sets this too */ {
237 current_user.groups = conn->groups;
238 current_user.ngroups = conn->ngroups;
239 token = conn->nt_user_token;
241 uid = conn->admin_user ? 0 : vuser->uid;
243 current_user.ngroups = vuser->n_groups;
244 current_user.groups = vuser->groups;
245 token = vuser->nt_user_token;
247 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing share %s.\n",vuid, lp_servicename(snum) ));
252 * See if we should force group for this service.
253 * If so this overrides any group set in the force
257 if((group_c = *lp_force_group(snum))) {
258 BOOL is_guest = False;
263 * Only force group if the user is a member of
264 * the service group. Check the group memberships for
265 * this user (we already have this) to
266 * see if we should force the group.
270 for (i = 0; i < current_user.ngroups; i++) {
271 if (current_user.groups[i] == conn->gid) {
281 * We've changed the group list in the token - we must
285 if (vuser && vuser->guest)
288 token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest);
290 DEBUG(1, ("change_to_user: create_nt_token failed!\n"));
293 must_free_token = True;
296 set_sec_ctx(uid, gid, current_user.ngroups, current_user.groups, token);
299 * Free the new token (as set_sec_ctx copies it).
303 delete_nt_token(&token);
305 current_user.conn = conn;
306 current_user.vuid = vuid;
308 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
309 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
314 /****************************************************************************
315 Go back to being root without changing the security context stack,
316 but modify the current_user entries.
317 ****************************************************************************/
319 BOOL change_to_root_user(void)
323 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
324 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
326 current_user.conn = NULL;
327 current_user.vuid = UID_FIELD_INVALID;
332 /****************************************************************************
333 Become the user of an authenticated connected named pipe.
334 When this is called we are currently running as the connection
335 user. Doesn't modify current_user.
336 ****************************************************************************/
338 BOOL become_authenticated_pipe_user(pipes_struct *p)
343 set_sec_ctx(p->pipe_user.uid, p->pipe_user.gid,
344 p->pipe_user.ngroups, p->pipe_user.groups, p->pipe_user.nt_user_token);
349 /****************************************************************************
350 Unbecome the user of an authenticated connected named pipe.
351 When this is called we are running as the authenticated pipe
352 user and need to go back to being the connection user. Doesn't modify
354 ****************************************************************************/
356 BOOL unbecome_authenticated_pipe_user(void)
358 return pop_sec_ctx();
361 /****************************************************************************
362 Utility functions used by become_xxx/unbecome_xxx.
363 ****************************************************************************/
366 connection_struct *conn;
370 /* A stack of current_user connection contexts. */
372 static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
373 static int conn_ctx_stack_ndx;
375 static void push_conn_ctx(void)
377 struct conn_ctx *ctx_p;
379 /* Check we don't overflow our stack */
381 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
382 DEBUG(0, ("Connection context stack overflow!\n"));
383 smb_panic("Connection context stack overflow!\n");
386 /* Store previous user context */
387 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
389 ctx_p->conn = current_user.conn;
390 ctx_p->vuid = current_user.vuid;
392 DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
393 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
395 conn_ctx_stack_ndx++;
398 static void pop_conn_ctx(void)
400 struct conn_ctx *ctx_p;
402 /* Check for stack underflow. */
404 if (conn_ctx_stack_ndx == 0) {
405 DEBUG(0, ("Connection context stack underflow!\n"));
406 smb_panic("Connection context stack underflow!\n");
409 conn_ctx_stack_ndx--;
410 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
412 current_user.conn = ctx_p->conn;
413 current_user.vuid = ctx_p->vuid;
416 ctx_p->vuid = UID_FIELD_INVALID;
419 /****************************************************************************
420 Temporarily become a root user. Must match with unbecome_root(). Saves and
421 restores the connection context.
422 ****************************************************************************/
424 void become_root(void)
431 /* Unbecome the root user */
433 void unbecome_root(void)
439 /****************************************************************************
440 Push the current security context then force a change via change_to_user().
441 Saves and restores the connection context.
442 ****************************************************************************/
444 BOOL become_user(connection_struct *conn, uint16 vuid)
451 if (!change_to_user(conn, vuid)) {
460 BOOL unbecome_user(void)