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 3 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, see <http://www.gnu.org/licenses/>.
22 /* what user is current? */
23 extern struct current_user current_user;
25 /****************************************************************************
26 Become the guest user without changing the security context stack.
27 ****************************************************************************/
29 bool change_to_guest(void)
31 static struct passwd *pass=NULL;
34 /* Don't need to free() this as its stored in a static */
35 pass = getpwnam_alloc(NULL, lp_guestaccount());
41 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
43 initgroups(pass->pw_name, pass->pw_gid);
46 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
48 current_user.conn = NULL;
49 current_user.vuid = UID_FIELD_INVALID;
57 /*******************************************************************
58 Check if a username is OK.
59 ********************************************************************/
61 static bool check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
64 struct vuid_cache_entry *ent = NULL;
68 for (i=0; i<VUID_CACHE_SIZE; i++) {
69 ent = &conn->vuid_cache.array[i];
70 if (ent->vuid == vuser->vuid) {
71 conn->read_only = ent->read_only;
72 conn->admin_user = ent->admin_user;
77 if (!user_ok_token(vuser->server_info->unix_name,
78 vuser->server_info->ptok,
82 readonly_share = is_share_read_only_for_token(
83 vuser->server_info->unix_name, vuser->server_info->ptok,
86 token = conn->nt_user_token ?
87 conn->nt_user_token : vuser->server_info->ptok;
89 if (!readonly_share &&
90 !share_access_check(token, lp_servicename(snum),
92 /* smb.conf allows r/w, but the security descriptor denies
93 * write. Fall back to looking at readonly. */
94 readonly_share = True;
95 DEBUG(5,("falling back to read-only access-evaluation due to "
96 "security descriptor\n"));
99 if (!share_access_check(token, lp_servicename(snum),
101 FILE_READ_DATA : FILE_WRITE_DATA)) {
105 ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry];
107 conn->vuid_cache.next_entry =
108 (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
110 ent->vuid = vuser->vuid;
111 ent->read_only = readonly_share;
113 ent->admin_user = token_contains_name_in_list(
114 vuser->server_info->unix_name, NULL, vuser->server_info->ptok,
115 lp_admin_users(SNUM(conn)));
117 conn->read_only = ent->read_only;
118 conn->admin_user = ent->admin_user;
123 /****************************************************************************
124 Become the user of a connection number without changing the security context
125 stack, but modify the current_user entries.
126 ****************************************************************************/
128 bool change_to_user(connection_struct *conn, uint16 vuid)
130 user_struct *vuser = get_valid_user_struct(vuid);
135 bool must_free_token = False;
136 NT_USER_TOKEN *token = NULL;
138 gid_t *group_list = NULL;
141 DEBUG(2,("change_to_user: Connection not open\n"));
146 * We need a separate check in security=share mode due to vuid
147 * always being UID_FIELD_INVALID. If we don't do this then
148 * in share mode security we are *always* changing uid's between
149 * SMB's - this hurts performance - Badly.
152 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
153 (current_user.ut.uid == conn->uid)) {
154 DEBUG(4,("change_to_user: Skipping user change - already "
157 } else if ((current_user.conn == conn) &&
158 (vuser != 0) && (current_user.vuid == vuid) &&
159 (current_user.ut.uid == vuser->server_info->uid)) {
160 DEBUG(4,("change_to_user: Skipping user change - already "
167 if ((vuser) && !check_user_ok(conn, vuser, snum)) {
168 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
169 "not permitted access to share %s.\n",
170 vuser->server_info->sanitized_username,
171 vuser->server_info->unix_name, vuid,
172 lp_servicename(snum)));
176 if (conn->force_user) /* security = share sets this too */ {
179 group_list = conn->groups;
180 num_groups = conn->ngroups;
181 token = conn->nt_user_token;
183 uid = conn->admin_user ? 0 : vuser->server_info->uid;
184 gid = vuser->server_info->gid;
185 num_groups = vuser->server_info->n_groups;
186 group_list = vuser->server_info->groups;
187 token = vuser->server_info->ptok;
189 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
190 "share %s.\n",vuid, lp_servicename(snum) ));
195 * See if we should force group for this service.
196 * If so this overrides any group set in the force
200 if((group_c = *lp_force_group(snum))) {
202 token = dup_nt_token(talloc_tos(), token);
204 DEBUG(0, ("dup_nt_token failed\n"));
207 must_free_token = True;
212 * Only force group if the user is a member of
213 * the service group. Check the group memberships for
214 * this user (we already have this) to
215 * see if we should force the group.
219 for (i = 0; i < num_groups; i++) {
220 if (group_list[i] == conn->gid) {
222 gid_to_sid(&token->user_sids[1], gid);
228 gid_to_sid(&token->user_sids[1], gid);
232 /* Now set current_user since we will immediately also call
235 current_user.ut.ngroups = num_groups;
236 current_user.ut.groups = group_list;
238 set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
242 * Free the new token (as set_sec_ctx copies it).
248 current_user.conn = conn;
249 current_user.vuid = vuid;
251 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
252 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
257 /****************************************************************************
258 Go back to being root without changing the security context stack,
259 but modify the current_user entries.
260 ****************************************************************************/
262 bool change_to_root_user(void)
266 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
267 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
269 current_user.conn = NULL;
270 current_user.vuid = UID_FIELD_INVALID;
275 /****************************************************************************
276 Become the user of an authenticated connected named pipe.
277 When this is called we are currently running as the connection
278 user. Doesn't modify current_user.
279 ****************************************************************************/
281 bool become_authenticated_pipe_user(pipes_struct *p)
286 set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid,
287 p->pipe_user.ut.ngroups, p->pipe_user.ut.groups,
288 p->pipe_user.nt_user_token);
293 /****************************************************************************
294 Unbecome the user of an authenticated connected named pipe.
295 When this is called we are running as the authenticated pipe
296 user and need to go back to being the connection user. Doesn't modify
298 ****************************************************************************/
300 bool unbecome_authenticated_pipe_user(void)
302 return pop_sec_ctx();
305 /****************************************************************************
306 Utility functions used by become_xxx/unbecome_xxx.
307 ****************************************************************************/
310 connection_struct *conn;
314 /* A stack of current_user connection contexts. */
316 static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
317 static int conn_ctx_stack_ndx;
319 static void push_conn_ctx(void)
321 struct conn_ctx *ctx_p;
323 /* Check we don't overflow our stack */
325 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
326 DEBUG(0, ("Connection context stack overflow!\n"));
327 smb_panic("Connection context stack overflow!\n");
330 /* Store previous user context */
331 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
333 ctx_p->conn = current_user.conn;
334 ctx_p->vuid = current_user.vuid;
336 DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
337 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
339 conn_ctx_stack_ndx++;
342 static void pop_conn_ctx(void)
344 struct conn_ctx *ctx_p;
346 /* Check for stack underflow. */
348 if (conn_ctx_stack_ndx == 0) {
349 DEBUG(0, ("Connection context stack underflow!\n"));
350 smb_panic("Connection context stack underflow!\n");
353 conn_ctx_stack_ndx--;
354 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
356 current_user.conn = ctx_p->conn;
357 current_user.vuid = ctx_p->vuid;
360 ctx_p->vuid = UID_FIELD_INVALID;
363 /****************************************************************************
364 Temporarily become a root user. Must match with unbecome_root(). Saves and
365 restores the connection context.
366 ****************************************************************************/
368 void become_root(void)
371 * no good way to handle push_sec_ctx() failing without changing
372 * the prototype of become_root()
374 if (!push_sec_ctx()) {
375 smb_panic("become_root: push_sec_ctx failed");
381 /* Unbecome the root user */
383 void unbecome_root(void)
389 /****************************************************************************
390 Push the current security context then force a change via change_to_user().
391 Saves and restores the connection context.
392 ****************************************************************************/
394 bool become_user(connection_struct *conn, uint16 vuid)
401 if (!change_to_user(conn, vuid)) {
410 bool unbecome_user(void)