Navigation Menu

Skip to content

Commit

Permalink
11024 SMB should bypass ACL traverse checking
Browse files Browse the repository at this point in the history
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Approved by: Garrett D'Amore <garrett@damore.org>
  • Loading branch information
gwr committed Aug 10, 2019
1 parent 3e2c0c0 commit cc3780e
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 24 deletions.
6 changes: 3 additions & 3 deletions usr/src/cmd/mdb/common/modules/libmlsvc/smb_ht.c
Expand Up @@ -42,7 +42,7 @@ smb_ht_walk_init(mdb_walk_state_t *wsp)
uintptr_t addr = wsp->walk_addr;
HT_HANDLE *ht;

if (addr == (uintptr_t)NULL) {
if (addr == 0) {
mdb_printf("require address of an HT_HANDLE\n");
return (WALK_ERR);
}
Expand All @@ -63,7 +63,7 @@ smb_ht_walk_init(mdb_walk_state_t *wsp)
}

hw->hw_idx = -1;
wsp->walk_addr = (uintptr_t)NULL;
wsp->walk_addr = 0;
wsp->walk_data = hw;

return (WALK_NEXT);
Expand All @@ -78,7 +78,7 @@ smb_ht_walk_step(mdb_walk_state_t *wsp)
uintptr_t he_addr;
int rv;

while (wsp->walk_addr == (uintptr_t)NULL) {
while (wsp->walk_addr == 0) {
if (++hw->hw_idx >= hw->hw_handle.ht_table_size)
return (WALK_DONE);
he_addr = (uintptr_t)hw->hw_handle.ht_table +
Expand Down
2 changes: 1 addition & 1 deletion usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
Expand Up @@ -281,7 +281,7 @@ static const mdb_dcmd_t dcmds[] = {
int
vfs_walk_init(mdb_walk_state_t *wsp)
{
if (wsp->walk_addr == (uintptr_t)NULL &&
if (wsp->walk_addr == 0 &&
mdb_readvar(&wsp->walk_addr, "rootvfs") == -1) {
mdb_warn("failed to read 'rootvfs'");
return (WALK_ERR);
Expand Down
37 changes: 26 additions & 11 deletions usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
Expand Up @@ -1382,6 +1382,21 @@ user_flag_bits[] = {

static const mdb_bitmask_t
user_priv_bits[] = {
/*
* Old definitions of these bits, for when we're
* looking at an older core file. These happen to
* have no overlap with the current definitions.
*/
{ "TAKE_OWNER", 1, 1 },
{ "BACKUP", 2, 2 },
{ "RESTORE", 4, 4 },
{ "SECURITY", 8, 8 },
/*
* Current definitions
*/
{ "SECURITY",
SMB_USER_PRIV_SECURITY,
SMB_USER_PRIV_SECURITY },
{ "TAKE_OWNER",
SMB_USER_PRIV_TAKE_OWNERSHIP,
SMB_USER_PRIV_TAKE_OWNERSHIP },
Expand All @@ -1391,9 +1406,9 @@ user_priv_bits[] = {
{ "RESTORE",
SMB_USER_PRIV_RESTORE,
SMB_USER_PRIV_RESTORE },
{ "SECURITY",
SMB_USER_PRIV_SECURITY,
SMB_USER_PRIV_SECURITY },
{ "CHANGE_NOTIFY",
SMB_USER_PRIV_CHANGE_NOTIFY,
SMB_USER_PRIV_CHANGE_NOTIFY },
{ NULL, 0, 0 }
};

Expand Down Expand Up @@ -1940,7 +1955,7 @@ smb_hash_walk_init(mdb_walk_state_t *wsp)
int ll_off, sll_off, i;
uintptr_t addr = wsp->walk_addr;

if (addr == (uintptr_t)NULL) {
if (addr == 0) {
mdb_printf("require address of an smb_hash_t\n");
return (WALK_ERR);
}
Expand Down Expand Up @@ -2029,7 +2044,7 @@ smb_hashstat_walk_init(mdb_walk_state_t *wsp)
uint32_t arr_sz;
smb_hash_wd_t *wd;

if (addr == (uintptr_t)NULL) {
if (addr == 0) {
mdb_printf("require address of an smb_hash_t\n");
return (WALK_ERR);
}
Expand Down Expand Up @@ -2284,7 +2299,7 @@ smb_kshare_walk_init(mdb_walk_state_t *wsp)
{
int sv_exp_off, ex_sha_off, avl_tr_off;

if (wsp->walk_addr == (uintptr_t)NULL) {
if (wsp->walk_addr == 0) {
mdb_printf("require address of an smb_server_t\n");
return (WALK_ERR);
}
Expand Down Expand Up @@ -2417,7 +2432,7 @@ smb_vfs_walk_init(mdb_walk_state_t *wsp)
{
int sv_exp_off, ex_vfs_off, ll_off;

if (wsp->walk_addr == (uintptr_t)NULL) {
if (wsp->walk_addr == 0) {
mdb_printf("require address of an smb_server_t\n");
return (WALK_ERR);
}
Expand Down Expand Up @@ -2751,7 +2766,7 @@ smb_node_walk_init(mdb_walk_state_t *wsp)
int ll_off;
int i;

if (wsp->walk_addr == (uintptr_t)NULL) {
if (wsp->walk_addr == 0) {
if (mdb_lookup_by_obj(SMBSRV_OBJNAME, "smb_node_hash_table",
&sym) == -1) {
mdb_warn("failed to find 'smb_node_hash_table'");
Expand Down Expand Up @@ -3227,7 +3242,7 @@ smb_mbuf_walk_init(mdb_walk_state_t *wsp)
{
mbuf_t *m;

if (wsp->walk_addr == (uintptr_t)NULL) {
if (wsp->walk_addr == 0) {
mdb_printf("require address of an mbuf_t\n");
return (WALK_ERR);
}
Expand All @@ -3243,7 +3258,7 @@ smb_mbuf_walk_step(mdb_walk_state_t *wsp)
mbuf_t *m = wsp->walk_data;
int rc;

if (wsp->walk_addr == (uintptr_t)NULL)
if (wsp->walk_addr == 0)
return (WALK_DONE);

if (mdb_vread(m, sizeof (*m), addr) == -1) {
Expand Down Expand Up @@ -3369,7 +3384,7 @@ smb_ace_walk_init(mdb_walk_state_t *wsp)
{
int sal_off;

if (wsp->walk_addr == (uintptr_t)NULL) {
if (wsp->walk_addr == 0) {
mdb_printf("smb_ace walk only supports local walks\n");
return (WALK_ERR);
}
Expand Down
2 changes: 2 additions & 0 deletions usr/src/cmd/smbsrv/smbd/server.xml
Expand Up @@ -157,6 +157,8 @@ file.
value='true' override='true'/>
<propval name='autohome_map' type='astring'
value='/etc' override='true'/>
<propval name='bypass_traverse_checking' type='boolean'
value='true' override='true'/>
<propval name='debug' type='integer'
value='0' override='true'/>
<propval name='domain_sid' type='astring'
Expand Down
2 changes: 2 additions & 0 deletions usr/src/lib/libshare/smb/libshare_smb.c
Expand Up @@ -924,6 +924,8 @@ struct smb_proto_option_defs {
SMB_REFRESH_REFRESH },
{ SMB_CI_MIN_PROTOCOL, 0, MAX_VALUE_BUFLEN, protocol_validator,
SMB_REFRESH_REFRESH },
{ SMB_CI_BYPASS_TRAVERSE_CHECKING, 0, 0, true_false_validator,
SMB_REFRESH_REFRESH },
{ SMB_CI_OPLOCK_ENABLE, 0, 0, true_false_validator,
SMB_REFRESH_REFRESH },
};
Expand Down
10 changes: 10 additions & 0 deletions usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c
Expand Up @@ -328,6 +328,16 @@ smb_token_create_privs(smb_token_t *token)
smb_privset_enable(privs, SE_SECURITY_LUID);
}

/*
* Members of "Authenticated Users" (!anon) should normally get
* "Bypass traverse checking" privilege, though we allow this
* to be disabled (see smb.4). For historical reasons, the
* internal privilege name is "SeChangeNotifyPrivilege".
*/
if ((token->tkn_flags & SMB_ATF_ANON) == 0 &&
smb_config_getbool(SMB_CI_BYPASS_TRAVERSE_CHECKING))
smb_privset_enable(privs, SE_CHANGE_NOTIFY_LUID);

return (privs);
}

Expand Down
1 change: 1 addition & 0 deletions usr/src/lib/smbsrv/libsmb/common/libsmb.h
Expand Up @@ -159,6 +159,7 @@ typedef enum {
SMB_CI_MAX_PROTOCOL,
SMB_CI_ENCRYPT,
SMB_CI_MIN_PROTOCOL,
SMB_CI_BYPASS_TRAVERSE_CHECKING,

SMB_CI_MAX
} smb_cfg_id_t;
Expand Down
2 changes: 2 additions & 0 deletions usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
Expand Up @@ -148,6 +148,8 @@ static smb_cfg_param_t smb_cfg_table[] =
{SMB_CI_MAX_PROTOCOL, "max_protocol", SCF_TYPE_ASTRING, 0},
{SMB_CI_ENCRYPT, "encrypt", SCF_TYPE_ASTRING, 0},
{SMB_CI_MIN_PROTOCOL, "min_protocol", SCF_TYPE_ASTRING, 0},
{SMB_CI_BYPASS_TRAVERSE_CHECKING,
"bypass_traverse_checking", SCF_TYPE_BOOLEAN, 0},

/* SMB_CI_MAX */
};
Expand Down
16 changes: 16 additions & 0 deletions usr/src/man/man4/smb.4
Expand Up @@ -56,6 +56,22 @@ Specifies the full path for the SMD autohome map file, \fBsmbautohome\fR. The
default path is \fB/etc\fR.
.RE

.sp
.ne 2
.na
\fB\fBbypass_traverse_checking\fR\fR
.ad
.sp .6
.RS 4n
When set, allows the SMB server to bypass ACL "traverse" checks.
The default value is \fBtrue\fR, for Windows compatibility.
If this parameter is \fBfalse\fR, ACL checks require that
"traverse" (directory execute) is granted on every directory
above the directory the SMB client tries to access.
Windows shares are normally setup with the higher level
directories not specifically granting such access.
.RE

.sp
.ne 2
.na
Expand Down
13 changes: 8 additions & 5 deletions usr/src/uts/common/fs/smbsrv/smb_authenticate.c
Expand Up @@ -529,17 +529,20 @@ smb_priv_xlate(smb_token_t *token)
{
uint32_t privileges = 0;

if (smb_token_query_privilege(token, SE_SECURITY_LUID))
privileges |= SMB_USER_PRIV_SECURITY;

if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;

if (smb_token_query_privilege(token, SE_BACKUP_LUID))
privileges |= SMB_USER_PRIV_BACKUP;

if (smb_token_query_privilege(token, SE_RESTORE_LUID))
privileges |= SMB_USER_PRIV_RESTORE;

if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;

if (smb_token_query_privilege(token, SE_SECURITY_LUID))
privileges |= SMB_USER_PRIV_SECURITY;
if (smb_token_query_privilege(token, SE_CHANGE_NOTIFY_LUID))
privileges |= SMB_USER_PRIV_CHANGE_NOTIFY;

return (privileges);
}
Expand Down
17 changes: 17 additions & 0 deletions usr/src/uts/common/fs/smbsrv/smb_cred.c
Expand Up @@ -49,6 +49,11 @@ static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps);
* If the mapped UID is ephemeral, or the primary group could not be
* obtained, the cred gid is set to whatever Solaris group is mapped
* to the token's primary group.
*
* Also add any privileges that should always be in effect for this user.
* Note that an SMB user object also gets a u_privcred which is used
* when the client opens an object with "backup/restore intent".
* That cred is setup later, in smb_user_setcred().
*/
cred_t *
smb_cred_create(smb_token_t *token)
Expand Down Expand Up @@ -109,6 +114,18 @@ smb_cred_create(smb_token_t *token)
NULL);
}

/*
* See smb.4 bypass_traverse_checking
*
* For historical reasons, the Windows privilege is named
* SeChangeNotifyPrivilege, though the description is
* "Bypass traverse checking".
*/
if (smb_token_query_privilege(token, SE_CHANGE_NOTIFY_LUID)) {
(void) crsetpriv(cr, PRIV_FILE_DAC_SEARCH, NULL);
}


return (cr);
}

Expand Down
13 changes: 9 additions & 4 deletions usr/src/uts/common/smbsrv/smb_ktypes.h
Expand Up @@ -1008,10 +1008,15 @@ typedef struct smb_session {
#define SMB_USER_IS_ADMIN(U) (((U)->u_flags & SMB_USER_FLAG_ADMIN) != 0)
#define SMB_USER_IS_GUEST(U) (((U)->u_flags & SMB_USER_FLAG_GUEST) != 0)

#define SMB_USER_PRIV_TAKE_OWNERSHIP 0x00000001
#define SMB_USER_PRIV_BACKUP 0x00000002
#define SMB_USER_PRIV_RESTORE 0x00000004
#define SMB_USER_PRIV_SECURITY 0x00000008
/*
* Internal privilege flags derived from smb_privilege.h numbers
* Would rather not include that in this file.
*/
#define SMB_USER_PRIV_SECURITY (1<<8) /* SE_SECURITY_LUID */
#define SMB_USER_PRIV_TAKE_OWNERSHIP (1<<9) /* SE_TAKE_OWNERSHIP_LUID */
#define SMB_USER_PRIV_BACKUP (1<<17) /* SE_BACKUP_LUID */
#define SMB_USER_PRIV_RESTORE (1<<18) /* SE_RESTORE_LUID */
#define SMB_USER_PRIV_CHANGE_NOTIFY (1<<23) /* SE_CHANGE_NOTIFY_LUID */

/*
* See the long "User State Machine" comment in smb_user.c
Expand Down

0 comments on commit cc3780e

Please sign in to comment.