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/>.
21 #include "system/passwd.h"
22 #include "smbd/globals.h"
23 #include "../librpc/gen_ndr/netlogon.h"
24 #include "libcli/security/security.h"
25 #include "passdb/lookup_sid.h"
27 /* what user is current? */
28 extern struct current_user current_user;
30 /****************************************************************************
31 Become the guest user without changing the security context stack.
32 ****************************************************************************/
34 bool change_to_guest(void)
38 pass = Get_Pwnam_alloc(talloc_tos(), lp_guestaccount());
44 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
46 initgroups(pass->pw_name, pass->pw_gid);
49 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
51 current_user.conn = NULL;
52 current_user.vuid = UID_FIELD_INVALID;
59 /****************************************************************************
60 talloc free the conn->session_info if not used in the vuid cache.
61 ****************************************************************************/
63 static void free_conn_session_info_if_unused(connection_struct *conn)
67 for (i = 0; i < VUID_CACHE_SIZE; i++) {
68 struct vuid_cache_entry *ent;
69 ent = &conn->vuid_cache.array[i];
70 if (ent->vuid != UID_FIELD_INVALID &&
71 conn->session_info == ent->session_info) {
75 /* Not used, safe to free. */
76 TALLOC_FREE(conn->session_info);
79 /*******************************************************************
80 Check if a username is OK.
82 This sets up conn->session_info with a copy related to this vuser that
83 later code can then mess with.
84 ********************************************************************/
86 static bool check_user_ok(connection_struct *conn,
88 const struct auth_serversupplied_info *session_info,
91 bool valid_vuid = (vuid != UID_FIELD_INVALID);
97 struct vuid_cache_entry *ent;
99 for (i=0; i<VUID_CACHE_SIZE; i++) {
100 ent = &conn->vuid_cache.array[i];
101 if (ent->vuid == vuid) {
102 free_conn_session_info_if_unused(conn);
103 conn->session_info = ent->session_info;
104 conn->read_only = ent->read_only;
110 if (!user_ok_token(session_info->unix_name,
111 session_info->info3->base.domain.string,
112 session_info->security_token, snum))
115 readonly_share = is_share_read_only_for_token(
116 session_info->unix_name,
117 session_info->info3->base.domain.string,
118 session_info->security_token,
121 if (!readonly_share &&
122 !share_access_check(session_info->security_token, lp_servicename(snum),
124 /* smb.conf allows r/w, but the security descriptor denies
125 * write. Fall back to looking at readonly. */
126 readonly_share = True;
127 DEBUG(5,("falling back to read-only access-evaluation due to "
128 "security descriptor\n"));
131 if (!share_access_check(session_info->security_token, lp_servicename(snum),
133 FILE_READ_DATA : FILE_WRITE_DATA)) {
137 admin_user = token_contains_name_in_list(
138 session_info->unix_name,
139 session_info->info3->base.domain.string,
140 NULL, session_info->security_token, lp_admin_users(snum));
143 struct vuid_cache_entry *ent =
144 &conn->vuid_cache.array[conn->vuid_cache.next_entry];
146 conn->vuid_cache.next_entry =
147 (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
149 TALLOC_FREE(ent->session_info);
152 * If force_user was set, all session_info's are based on the same
153 * username-based faked one.
156 ent->session_info = copy_serverinfo(
157 conn, conn->force_user ? conn->session_info : session_info);
159 if (ent->session_info == NULL) {
160 ent->vuid = UID_FIELD_INVALID;
165 ent->read_only = readonly_share;
166 free_conn_session_info_if_unused(conn);
167 conn->session_info = ent->session_info;
170 conn->read_only = readonly_share;
172 DEBUG(2,("check_user_ok: user %s is an admin user. "
173 "Setting uid as %d\n",
174 conn->session_info->unix_name,
175 sec_initial_uid() ));
176 conn->session_info->utok.uid = sec_initial_uid();
182 /****************************************************************************
183 Clear a vuid out of the connection's vuid cache
184 This is only called on SMBulogoff.
185 ****************************************************************************/
187 void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid)
191 for (i=0; i<VUID_CACHE_SIZE; i++) {
192 struct vuid_cache_entry *ent;
194 ent = &conn->vuid_cache.array[i];
196 if (ent->vuid == vuid) {
197 ent->vuid = UID_FIELD_INVALID;
199 * We need to keep conn->session_info around
200 * if it's equal to ent->session_info as a SMBulogoff
201 * is often followed by a SMBtdis (with an invalid
202 * vuid). The debug code (or regular code in
203 * vfs_full_audit) wants to refer to the
204 * conn->session_info pointer to print debug
205 * statements. Theoretically this is a bug,
206 * as once the vuid is gone the session_info
207 * on the conn struct isn't valid any more,
208 * but there's enough code that assumes
209 * conn->session_info is never null that
210 * it's easier to hold onto the old pointer
211 * until we get a new sessionsetupX.
212 * As everything is hung off the
213 * conn pointer as a talloc context we're not
214 * leaking memory here. See bug #6315. JRA.
216 if (conn->session_info == ent->session_info) {
217 ent->session_info = NULL;
219 TALLOC_FREE(ent->session_info);
221 ent->read_only = False;
226 /****************************************************************************
227 Become the user of a connection number without changing the security context
228 stack, but modify the current_user entries.
229 ****************************************************************************/
231 bool change_to_user(connection_struct *conn, uint16 vuid)
233 const struct auth_serversupplied_info *session_info = NULL;
240 gid_t *group_list = NULL;
243 DEBUG(2,("change_to_user: Connection not open\n"));
247 vuser = get_valid_user_struct(conn->sconn, vuid);
250 * We need a separate check in security=share mode due to vuid
251 * always being UID_FIELD_INVALID. If we don't do this then
252 * in share mode security we are *always* changing uid's between
253 * SMB's - this hurts performance - Badly.
256 if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
257 (current_user.ut.uid == conn->session_info->utok.uid)) {
258 DEBUG(4,("change_to_user: Skipping user change - already "
261 } else if ((current_user.conn == conn) &&
262 (vuser != NULL) && (current_user.vuid == vuid) &&
263 (current_user.ut.uid == vuser->session_info->utok.uid)) {
264 DEBUG(4,("change_to_user: Skipping user change - already "
271 session_info = vuser ? vuser->session_info : conn->session_info;
274 /* Invalid vuid sent - even with security = share. */
275 DEBUG(2,("change_to_user: Invalid vuid %d used on "
276 "share %s.\n",vuid, lp_servicename(snum) ));
280 if (!check_user_ok(conn, vuid, session_info, snum)) {
281 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
282 "not permitted access to share %s.\n",
283 session_info->sanitized_username,
284 session_info->unix_name, vuid,
285 lp_servicename(snum)));
289 /* security = share sets force_user. */
290 if (!conn->force_user && !vuser) {
291 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
292 "share %s.\n",vuid, lp_servicename(snum) ));
297 * conn->session_info is now correctly set up with a copy we can mess
298 * with for force_group etc.
301 uid = conn->session_info->utok.uid;
302 gid = conn->session_info->utok.gid;
303 num_groups = conn->session_info->utok.ngroups;
304 group_list = conn->session_info->utok.groups;
307 * See if we should force group for this service.
308 * If so this overrides any group set in the force
312 if((group_c = *lp_force_group(snum))) {
314 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
319 * Only force group if the user is a member of
320 * the service group. Check the group memberships for
321 * this user (we already have this) to
322 * see if we should force the group.
326 for (i = 0; i < num_groups; i++) {
328 == conn->force_group_gid) {
329 conn->session_info->utok.gid =
330 conn->force_group_gid;
331 gid = conn->force_group_gid;
332 gid_to_sid(&conn->session_info->security_token
338 conn->session_info->utok.gid = conn->force_group_gid;
339 gid = conn->force_group_gid;
340 gid_to_sid(&conn->session_info->security_token->sids[1],
345 /* Now set current_user since we will immediately also call
348 current_user.ut.ngroups = num_groups;
349 current_user.ut.groups = group_list;
351 set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
352 conn->session_info->security_token);
354 current_user.conn = conn;
355 current_user.vuid = vuid;
357 DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
358 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
363 /****************************************************************************
364 Go back to being root without changing the security context stack,
365 but modify the current_user entries.
366 ****************************************************************************/
368 bool change_to_root_user(void)
372 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
373 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
375 current_user.conn = NULL;
376 current_user.vuid = UID_FIELD_INVALID;
381 /****************************************************************************
382 Become the user of an authenticated connected named pipe.
383 When this is called we are currently running as the connection
384 user. Doesn't modify current_user.
385 ****************************************************************************/
387 bool become_authenticated_pipe_user(struct pipes_struct *p)
392 set_sec_ctx(p->session_info->utok.uid, p->session_info->utok.gid,
393 p->session_info->utok.ngroups, p->session_info->utok.groups,
394 p->session_info->security_token);
399 /****************************************************************************
400 Unbecome the user of an authenticated connected named pipe.
401 When this is called we are running as the authenticated pipe
402 user and need to go back to being the connection user. Doesn't modify
404 ****************************************************************************/
406 bool unbecome_authenticated_pipe_user(void)
408 return pop_sec_ctx();
411 /****************************************************************************
412 Utility functions used by become_xxx/unbecome_xxx.
413 ****************************************************************************/
415 static void push_conn_ctx(void)
417 struct conn_ctx *ctx_p;
419 /* Check we don't overflow our stack */
421 if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
422 DEBUG(0, ("Connection context stack overflow!\n"));
423 smb_panic("Connection context stack overflow!\n");
426 /* Store previous user context */
427 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
429 ctx_p->conn = current_user.conn;
430 ctx_p->vuid = current_user.vuid;
432 DEBUG(4, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
433 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
435 conn_ctx_stack_ndx++;
438 static void pop_conn_ctx(void)
440 struct conn_ctx *ctx_p;
442 /* Check for stack underflow. */
444 if (conn_ctx_stack_ndx == 0) {
445 DEBUG(0, ("Connection context stack underflow!\n"));
446 smb_panic("Connection context stack underflow!\n");
449 conn_ctx_stack_ndx--;
450 ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
452 current_user.conn = ctx_p->conn;
453 current_user.vuid = ctx_p->vuid;
456 ctx_p->vuid = UID_FIELD_INVALID;
459 /****************************************************************************
460 Temporarily become a root user. Must match with unbecome_root(). Saves and
461 restores the connection context.
462 ****************************************************************************/
464 void become_root(void)
467 * no good way to handle push_sec_ctx() failing without changing
468 * the prototype of become_root()
470 if (!push_sec_ctx()) {
471 smb_panic("become_root: push_sec_ctx failed");
477 /* Unbecome the root user */
479 void unbecome_root(void)
485 /****************************************************************************
486 Push the current security context then force a change via change_to_user().
487 Saves and restores the connection context.
488 ****************************************************************************/
490 bool become_user(connection_struct *conn, uint16 vuid)
497 if (!change_to_user(conn, vuid)) {
506 bool unbecome_user(void)
513 /****************************************************************************
514 Return the current user we are running effectively as on this connection.
515 I'd like to make this return conn->session_info->utok.uid, but become_root()
516 doesn't alter this value.
517 ****************************************************************************/
519 uid_t get_current_uid(connection_struct *conn)
521 return current_user.ut.uid;
524 /****************************************************************************
525 Return the current group we are running effectively as on this connection.
526 I'd like to make this return conn->session_info->utok.gid, but become_root()
527 doesn't alter this value.
528 ****************************************************************************/
530 gid_t get_current_gid(connection_struct *conn)
532 return current_user.ut.gid;
535 /****************************************************************************
536 Return the UNIX token we are running effectively as on this connection.
537 I'd like to make this return &conn->session_info->utok, but become_root()
538 doesn't alter this value.
539 ****************************************************************************/
541 const struct security_unix_token *get_current_utok(connection_struct *conn)
543 return ¤t_user.ut;
546 const struct security_token *get_current_nttok(connection_struct *conn)
548 return current_user.nt_user_token;
551 uint16_t get_current_vuid(connection_struct *conn)
553 return current_user.vuid;