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/smbd.h"
23 #include "smbd/globals.h"
24 #include "../librpc/gen_ndr/netlogon.h"
25 #include "libcli/security/security.h"
26 #include "passdb/lookup_sid.h"
28 #include "../auth/auth_util.h"
29 #include "source3/lib/substitute.h"
31 /* what user is current? */
32 extern struct current_user current_user
;
34 /****************************************************************************
35 Become the guest user without changing the security context stack.
36 ****************************************************************************/
38 bool change_to_guest(void)
42 pass
= Get_Pwnam_alloc(talloc_tos(), lp_guest_account());
48 /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before
50 initgroups(pass
->pw_name
, pass
->pw_gid
);
53 set_sec_ctx(pass
->pw_uid
, pass
->pw_gid
, 0, NULL
, NULL
);
55 current_user
.conn
= NULL
;
56 current_user
.vuid
= UID_FIELD_INVALID
;
63 /****************************************************************************
64 talloc free the conn->session_info if not used in the vuid cache.
65 ****************************************************************************/
67 static void free_conn_session_info_if_unused(connection_struct
*conn
)
71 for (i
= 0; i
< VUID_CACHE_SIZE
; i
++) {
72 struct vuid_cache_entry
*ent
;
73 ent
= &conn
->vuid_cache
->array
[i
];
74 if (ent
->vuid
!= UID_FIELD_INVALID
&&
75 conn
->session_info
== ent
->session_info
) {
79 /* Not used, safe to free. */
80 TALLOC_FREE(conn
->session_info
);
83 /****************************************************************************
84 Setup the share access mask for a connection.
85 ****************************************************************************/
87 static uint32_t create_share_access_mask(int snum
,
89 const struct security_token
*token
)
91 uint32_t share_access
= 0;
93 share_access_check(token
,
94 lp_const_servicename(snum
),
95 MAXIMUM_ALLOWED_ACCESS
,
100 ~(SEC_FILE_WRITE_DATA
| SEC_FILE_APPEND_DATA
|
101 SEC_FILE_WRITE_EA
| SEC_FILE_WRITE_ATTRIBUTE
|
102 SEC_DIR_DELETE_CHILD
);
105 if (security_token_has_privilege(token
, SEC_PRIV_SECURITY
)) {
106 share_access
|= SEC_FLAG_SYSTEM_SECURITY
;
108 if (security_token_has_privilege(token
, SEC_PRIV_RESTORE
)) {
109 share_access
|= SEC_RIGHTS_PRIV_RESTORE
;
111 if (security_token_has_privilege(token
, SEC_PRIV_BACKUP
)) {
112 share_access
|= SEC_RIGHTS_PRIV_BACKUP
;
114 if (security_token_has_privilege(token
, SEC_PRIV_TAKE_OWNERSHIP
)) {
115 share_access
|= SEC_STD_WRITE_OWNER
;
121 /*******************************************************************
122 Calculate access mask and if this user can access this share.
123 ********************************************************************/
125 NTSTATUS
check_user_share_access(connection_struct
*conn
,
126 const struct auth_session_info
*session_info
,
127 uint32_t *p_share_access
,
128 bool *p_readonly_share
)
130 int snum
= SNUM(conn
);
131 uint32_t share_access
= 0;
132 bool readonly_share
= false;
134 if (!user_ok_token(session_info
->unix_info
->unix_name
,
135 session_info
->info
->domain_name
,
136 session_info
->security_token
, snum
)) {
137 return NT_STATUS_ACCESS_DENIED
;
140 readonly_share
= is_share_read_only_for_token(
141 session_info
->unix_info
->unix_name
,
142 session_info
->info
->domain_name
,
143 session_info
->security_token
,
146 share_access
= create_share_access_mask(snum
,
148 session_info
->security_token
);
150 if ((share_access
& (FILE_READ_DATA
|FILE_WRITE_DATA
)) == 0) {
151 /* No access, read or write. */
152 DBG_NOTICE("user %s connection to %s denied due to share "
153 "security descriptor.\n",
154 session_info
->unix_info
->unix_name
,
155 lp_const_servicename(snum
));
156 return NT_STATUS_ACCESS_DENIED
;
159 if (!readonly_share
&&
160 !(share_access
& FILE_WRITE_DATA
)) {
161 /* smb.conf allows r/w, but the security descriptor denies
162 * write. Fall back to looking at readonly. */
163 readonly_share
= true;
164 DBG_INFO("falling back to read-only access-evaluation due to "
165 "security descriptor\n");
168 *p_share_access
= share_access
;
169 *p_readonly_share
= readonly_share
;
174 /*******************************************************************
175 Check if a username is OK.
177 This sets up conn->session_info with a copy related to this vuser that
178 later code can then mess with.
179 ********************************************************************/
181 static bool check_user_ok(connection_struct
*conn
,
183 const struct auth_session_info
*session_info
,
187 bool readonly_share
= false;
188 bool admin_user
= false;
189 struct vuid_cache_entry
*ent
= NULL
;
190 uint32_t share_access
= 0;
193 for (i
=0; i
<VUID_CACHE_SIZE
; i
++) {
194 ent
= &conn
->vuid_cache
->array
[i
];
195 if (ent
->vuid
== vuid
) {
196 if (vuid
== UID_FIELD_INVALID
) {
198 * Slow path, we don't care
199 * about the array traversal.
203 free_conn_session_info_if_unused(conn
);
204 conn
->session_info
= ent
->session_info
;
205 conn
->read_only
= ent
->read_only
;
206 conn
->share_access
= ent
->share_access
;
207 conn
->vuid
= ent
->vuid
;
212 status
= check_user_share_access(conn
,
216 if (!NT_STATUS_IS_OK(status
)) {
220 admin_user
= token_contains_name_in_list(
221 session_info
->unix_info
->unix_name
,
222 session_info
->info
->domain_name
,
223 NULL
, session_info
->security_token
, lp_admin_users(snum
));
225 ent
= &conn
->vuid_cache
->array
[conn
->vuid_cache
->next_entry
];
227 conn
->vuid_cache
->next_entry
=
228 (conn
->vuid_cache
->next_entry
+ 1) % VUID_CACHE_SIZE
;
230 TALLOC_FREE(ent
->session_info
);
233 * If force_user was set, all session_info's are based on the same
234 * username-based faked one.
237 ent
->session_info
= copy_session_info(
238 conn
, conn
->force_user
? conn
->session_info
: session_info
);
240 if (ent
->session_info
== NULL
) {
241 ent
->vuid
= UID_FIELD_INVALID
;
246 DEBUG(2,("check_user_ok: user %s is an admin user. "
247 "Setting uid as %d\n",
248 ent
->session_info
->unix_info
->unix_name
,
249 sec_initial_uid() ));
250 ent
->session_info
->unix_token
->uid
= sec_initial_uid();
254 * It's actually OK to call check_user_ok() with
255 * vuid == UID_FIELD_INVALID as called from become_user_by_session().
256 * All this will do is throw away one entry in the cache.
260 ent
->read_only
= readonly_share
;
261 ent
->share_access
= share_access
;
262 free_conn_session_info_if_unused(conn
);
263 conn
->session_info
= ent
->session_info
;
264 conn
->vuid
= ent
->vuid
;
265 if (vuid
== UID_FIELD_INVALID
) {
267 * Not strictly needed, just make it really
268 * clear this entry is actually an unused one.
270 ent
->read_only
= false;
271 ent
->share_access
= 0;
272 ent
->session_info
= NULL
;
275 conn
->read_only
= readonly_share
;
276 conn
->share_access
= share_access
;
281 static void print_impersonation_info(connection_struct
*conn
)
283 struct smb_filename
*cwdfname
= NULL
;
285 if (!CHECK_DEBUGLVL(DBGLVL_INFO
)) {
289 cwdfname
= vfs_GetWd(talloc_tos(), conn
);
290 if (cwdfname
== NULL
) {
294 DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n",
299 cwdfname
->base_name
);
300 TALLOC_FREE(cwdfname
);
303 /****************************************************************************
304 Become the user of a connection number without changing the security context
305 stack, but modify the current_user entries.
306 ****************************************************************************/
308 static bool change_to_user_impersonate(connection_struct
*conn
,
309 const struct auth_session_info
*session_info
,
312 const struct loadparm_substitution
*lp_sub
=
313 loadparm_s3_global_substitution();
317 const char *force_group_name
;
320 gid_t
*group_list
= NULL
;
323 if ((current_user
.conn
== conn
) &&
324 (current_user
.vuid
== vuid
) &&
325 (current_user
.ut
.uid
== session_info
->unix_token
->uid
))
327 DBG_INFO("Skipping user change - already user\n");
331 set_current_user_info(session_info
->unix_info
->sanitized_username
,
332 session_info
->unix_info
->unix_name
,
333 session_info
->info
->domain_name
);
337 ok
= check_user_ok(conn
, vuid
, session_info
, snum
);
339 DBG_WARNING("SMB user %s (unix user %s) "
340 "not permitted access to share %s.\n",
341 session_info
->unix_info
->sanitized_username
,
342 session_info
->unix_info
->unix_name
,
343 lp_const_servicename(snum
));
347 uid
= conn
->session_info
->unix_token
->uid
;
348 gid
= conn
->session_info
->unix_token
->gid
;
349 num_groups
= conn
->session_info
->unix_token
->ngroups
;
350 group_list
= conn
->session_info
->unix_token
->groups
;
353 * See if we should force group for this service. If so this overrides
354 * any group set in the force user code.
356 force_group_name
= lp_force_group(talloc_tos(), lp_sub
, snum
);
357 group_c
= *force_group_name
;
359 if ((group_c
!= '\0') && (conn
->force_group_gid
== (gid_t
)-1)) {
361 * This can happen if "force group" is added to a
362 * share definition whilst an existing connection
363 * to that share exists. In that case, don't change
364 * the existing credentials for force group, only
365 * do so for new connections.
367 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
369 DBG_INFO("Not forcing group %s on existing connection to "
370 "share %s for SMB user %s (unix user %s)\n",
372 lp_const_servicename(snum
),
373 session_info
->unix_info
->sanitized_username
,
374 session_info
->unix_info
->unix_name
);
377 if((group_c
!= '\0') && (conn
->force_group_gid
!= (gid_t
)-1)) {
379 * Only force group for connections where
380 * conn->force_group_gid has already been set
381 * to the correct value (i.e. the connection
382 * happened after the 'force group' definition
383 * was added to the share definition. Connections
384 * that were made before force group was added
385 * should stay with their existing credentials.
387 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13690
390 if (group_c
== '+') {
394 * Only force group if the user is a member of the
395 * service group. Check the group memberships for this
396 * user (we already have this) to see if we should force
399 for (i
= 0; i
< num_groups
; i
++) {
400 if (group_list
[i
] == conn
->force_group_gid
) {
401 conn
->session_info
->unix_token
->gid
=
402 conn
->force_group_gid
;
403 gid
= conn
->force_group_gid
;
404 gid_to_sid(&conn
->session_info
->security_token
410 conn
->session_info
->unix_token
->gid
= conn
->force_group_gid
;
411 gid
= conn
->force_group_gid
;
412 gid_to_sid(&conn
->session_info
->security_token
->sids
[1],
421 conn
->session_info
->security_token
);
423 current_user
.conn
= conn
;
424 current_user
.vuid
= vuid
;
429 * Impersonate user and change directory to service
431 * change_to_user_and_service() is used to impersonate the user associated with
432 * the given vuid and to change the working directory of the process to the
433 * service base directory.
435 bool change_to_user_and_service(connection_struct
*conn
, uint64_t vuid
)
437 int snum
= SNUM(conn
);
438 struct auth_session_info
*si
= NULL
;
443 DBG_WARNING("Connection not open\n");
447 status
= smbXsrv_session_info_lookup(conn
->sconn
->client
,
450 if (!NT_STATUS_IS_OK(status
)) {
451 DBG_WARNING("Invalid vuid %llu used on share %s.\n",
452 (unsigned long long)vuid
,
453 lp_const_servicename(snum
));
457 ok
= change_to_user_impersonate(conn
, si
, vuid
);
462 if (conn
->tcon_done
) {
463 ok
= chdir_current_service(conn
);
469 print_impersonation_info(conn
);
474 * Impersonate user and change directory to service
476 * change_to_user_and_service_by_fsp() is used to impersonate the user
477 * associated with the given vuid and to change the working directory of the
478 * process to the service base directory.
480 bool change_to_user_and_service_by_fsp(struct files_struct
*fsp
)
482 return change_to_user_and_service(fsp
->conn
, fsp
->vuid
);
485 /****************************************************************************
486 Go back to being root without changing the security context stack,
487 but modify the current_user entries.
488 ****************************************************************************/
490 bool smbd_change_to_root_user(void)
494 DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
495 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
497 current_user
.conn
= NULL
;
498 current_user
.vuid
= UID_FIELD_INVALID
;
503 /****************************************************************************
504 Become the user of an authenticated connected named pipe.
505 When this is called we are currently running as the connection
506 user. Doesn't modify current_user.
507 ****************************************************************************/
509 bool smbd_become_authenticated_pipe_user(struct auth_session_info
*session_info
)
514 set_current_user_info(session_info
->unix_info
->sanitized_username
,
515 session_info
->unix_info
->unix_name
,
516 session_info
->info
->domain_name
);
518 set_sec_ctx(session_info
->unix_token
->uid
, session_info
->unix_token
->gid
,
519 session_info
->unix_token
->ngroups
, session_info
->unix_token
->groups
,
520 session_info
->security_token
);
522 DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
531 /****************************************************************************
532 Unbecome the user of an authenticated connected named pipe.
533 When this is called we are running as the authenticated pipe
534 user and need to go back to being the connection user. Doesn't modify
536 ****************************************************************************/
538 bool smbd_unbecome_authenticated_pipe_user(void)
540 return pop_sec_ctx();
543 /****************************************************************************
544 Utility functions used by become_xxx/unbecome_xxx.
545 ****************************************************************************/
547 static void push_conn_ctx(void)
549 struct conn_ctx
*ctx_p
;
550 extern userdom_struct current_user_info
;
552 /* Check we don't overflow our stack */
554 if (conn_ctx_stack_ndx
== MAX_SEC_CTX_DEPTH
) {
555 DEBUG(0, ("Connection context stack overflow!\n"));
556 smb_panic("Connection context stack overflow!\n");
559 /* Store previous user context */
560 ctx_p
= &conn_ctx_stack
[conn_ctx_stack_ndx
];
562 ctx_p
->conn
= current_user
.conn
;
563 ctx_p
->vuid
= current_user
.vuid
;
564 ctx_p
->user_info
= current_user_info
;
566 DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
567 (unsigned long long)ctx_p
->vuid
, conn_ctx_stack_ndx
));
569 conn_ctx_stack_ndx
++;
572 static void pop_conn_ctx(void)
574 struct conn_ctx
*ctx_p
;
576 /* Check for stack underflow. */
578 if (conn_ctx_stack_ndx
== 0) {
579 DEBUG(0, ("Connection context stack underflow!\n"));
580 smb_panic("Connection context stack underflow!\n");
583 conn_ctx_stack_ndx
--;
584 ctx_p
= &conn_ctx_stack
[conn_ctx_stack_ndx
];
586 set_current_user_info(ctx_p
->user_info
.smb_name
,
587 ctx_p
->user_info
.unix_name
,
588 ctx_p
->user_info
.domain
);
590 current_user
.conn
= ctx_p
->conn
;
591 current_user
.vuid
= ctx_p
->vuid
;
593 *ctx_p
= (struct conn_ctx
) {
594 .vuid
= UID_FIELD_INVALID
,
598 /****************************************************************************
599 Temporarily become a root user. Must match with unbecome_root(). Saves and
600 restores the connection context.
601 ****************************************************************************/
603 void smbd_become_root(void)
606 * no good way to handle push_sec_ctx() failing without changing
607 * the prototype of become_root()
609 if (!push_sec_ctx()) {
610 smb_panic("become_root: push_sec_ctx failed");
616 /* Unbecome the root user */
618 void smbd_unbecome_root(void)
624 /****************************************************************************
625 Push the current security context then force a change via change_to_user().
626 Saves and restores the connection context.
627 ****************************************************************************/
629 bool become_user_without_service(connection_struct
*conn
, uint64_t vuid
)
631 struct auth_session_info
*session_info
= NULL
;
632 int snum
= SNUM(conn
);
637 DBG_WARNING("Connection not open\n");
641 status
= smbXsrv_session_info_lookup(conn
->sconn
->client
,
644 if (!NT_STATUS_IS_OK(status
)) {
645 /* Invalid vuid sent */
646 DBG_WARNING("Invalid vuid %llu used on share %s.\n",
647 (unsigned long long)vuid
,
648 lp_const_servicename(snum
));
659 ok
= change_to_user_impersonate(conn
, session_info
, vuid
);
669 bool become_user_without_service_by_fsp(struct files_struct
*fsp
)
671 return become_user_without_service(fsp
->conn
, fsp
->vuid
);
674 bool become_user_without_service_by_session(connection_struct
*conn
,
675 const struct auth_session_info
*session_info
)
679 SMB_ASSERT(conn
!= NULL
);
680 SMB_ASSERT(session_info
!= NULL
);
689 ok
= change_to_user_impersonate(conn
, session_info
, UID_FIELD_INVALID
);
699 bool unbecome_user_without_service(void)
706 /****************************************************************************
707 Return the current user we are running effectively as on this connection.
708 I'd like to make this return conn->session_info->unix_token->uid, but become_root()
709 doesn't alter this value.
710 ****************************************************************************/
712 uid_t
get_current_uid(connection_struct
*conn
)
714 return current_user
.ut
.uid
;
717 /****************************************************************************
718 Return the current group we are running effectively as on this connection.
719 I'd like to make this return conn->session_info->unix_token->gid, but become_root()
720 doesn't alter this value.
721 ****************************************************************************/
723 gid_t
get_current_gid(connection_struct
*conn
)
725 return current_user
.ut
.gid
;
728 /****************************************************************************
729 Return the UNIX token we are running effectively as on this connection.
730 I'd like to make this return &conn->session_info->unix_token-> but become_root()
731 doesn't alter this value.
732 ****************************************************************************/
734 const struct security_unix_token
*get_current_utok(connection_struct
*conn
)
736 return ¤t_user
.ut
;
739 /****************************************************************************
740 Return the Windows token we are running effectively as on this connection.
741 If this is currently a NULL token as we're inside become_root() - a temporary
742 UNIX security override, then we search up the stack for the previous active
744 ****************************************************************************/
746 const struct security_token
*get_current_nttok(connection_struct
*conn
)
748 if (current_user
.nt_user_token
) {
749 return current_user
.nt_user_token
;
751 return sec_ctx_active_token();