diff --git a/usr/src/cmd/mdb/common/modules/libmlsvc/smb_ht.c b/usr/src/cmd/mdb/common/modules/libmlsvc/smb_ht.c
index 52421264e71e..d6625ed58a1d 100644
--- a/usr/src/cmd/mdb/common/modules/libmlsvc/smb_ht.c
+++ b/usr/src/cmd/mdb/common/modules/libmlsvc/smb_ht.c
@@ -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);
}
@@ -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);
@@ -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 +
diff --git a/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
index d7ea83166390..5368aa7fcc03 100644
--- a/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
+++ b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
@@ -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);
diff --git a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
index e04a6e30e693..b54549eebbeb 100644
--- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
+++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
@@ -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 },
@@ -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 }
};
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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'");
@@ -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);
}
@@ -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) {
@@ -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);
}
diff --git a/usr/src/cmd/smbsrv/smbd/server.xml b/usr/src/cmd/smbsrv/smbd/server.xml
index ac93f2f70e88..fa2ee7fdd44e 100644
--- a/usr/src/cmd/smbsrv/smbd/server.xml
+++ b/usr/src/cmd/smbsrv/smbd/server.xml
@@ -157,6 +157,8 @@ file.
value='true' override='true'/>
+
tkn_flags & SMB_ATF_ANON) == 0 &&
+ smb_config_getbool(SMB_CI_BYPASS_TRAVERSE_CHECKING))
+ smb_privset_enable(privs, SE_CHANGE_NOTIFY_LUID);
+
return (privs);
}
diff --git a/usr/src/lib/smbsrv/libsmb/common/libsmb.h b/usr/src/lib/smbsrv/libsmb/common/libsmb.h
index 56cab5ca8a10..8d6eb04683c2 100644
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h
@@ -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;
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
index cfecd0e944a5..45b0e79c44e8 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
@@ -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 */
};
diff --git a/usr/src/man/man4/smb.4 b/usr/src/man/man4/smb.4
index 99404484e661..c593a5217830 100644
--- a/usr/src/man/man4/smb.4
+++ b/usr/src/man/man4/smb.4
@@ -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
diff --git a/usr/src/uts/common/fs/smbsrv/smb_authenticate.c b/usr/src/uts/common/fs/smbsrv/smb_authenticate.c
index a5d0bad335ae..af9f5d271f7d 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_authenticate.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_authenticate.c
@@ -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);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_cred.c b/usr/src/uts/common/fs/smbsrv/smb_cred.c
index c6956518fc05..f47f5e72a5b2 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_cred.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_cred.c
@@ -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)
@@ -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);
}
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index 7011ac6dbebb..09e52b70f75c 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -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