summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c30
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_delete.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dispatch.c22
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsops.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c3
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c3
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_odir.c31
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_ofile.c108
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_opipe.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_process_exit.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_server.c103
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session.c310
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_find.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree.c157
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree_connect.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_user.c370
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h24
-rw-r--r--usr/src/uts/common/smbsrv/smb_ktypes.h12
21 files changed, 648 insertions, 561 deletions
diff --git a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
index 83ffae0634..eaa381cc47 100644
--- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
+++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
@@ -688,9 +688,12 @@ static const smb_exp_t smb_session_exp[] =
{ SMB_OPT_REQUEST,
offsetof(smb_session_t, s_req_list.sl_list),
"smbreq", "smb_request"},
- { SMB_OPT_USER | SMB_OPT_TREE | SMB_OPT_OFILE | SMB_OPT_ODIR,
+ { SMB_OPT_USER,
offsetof(smb_session_t, s_user_list.ll_list),
"smbuser", "smb_user"},
+ { SMB_OPT_TREE | SMB_OPT_OFILE | SMB_OPT_ODIR,
+ offsetof(smb_session_t, s_tree_list.ll_list),
+ "smbtree", "smb_tree"},
{ 0, 0, NULL, NULL}
};
@@ -963,17 +966,6 @@ static const char *smb_user_state[SMB_USER_STATE_SENTINEL] =
"LOGGED_OFF"
};
-/*
- * List of objects that can be expanded under a user structure.
- */
-static const smb_exp_t smb_user_exp[] =
-{
- { SMB_OPT_TREE | SMB_OPT_OFILE | SMB_OPT_ODIR,
- offsetof(smb_user_t, u_tree_list.ll_list),
- "smbtree", "smb_tree"},
- { 0, 0, NULL, NULL}
-};
-
static void
smb_dcmd_user_help(void)
{
@@ -983,17 +975,13 @@ smb_dcmd_user_help(void)
mdb_printf("%<b>OPTIONS%</b>\n");
(void) mdb_inc_indent(2);
mdb_printf(
- "-v\tDisplay verbose smb_user information\n"
- "-d\tDisplay the list of smb_odirs attached\n"
- "-f\tDisplay the list of smb_ofiles attached\n"
- "-t\tDisplay the list of smb_trees attached\n");
+ "-v\tDisplay verbose smb_user information\n");
}
static int
smb_dcmd_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
uint_t opts;
- ulong_t indent = 0;
if (smb_dcmd_getopt(&opts, argc, argv))
return (DCMD_USAGE);
@@ -1009,8 +997,6 @@ smb_dcmd_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
smb_user_t *user;
char *account;
- indent = SMB_DCMD_INDENT;
-
user = mdb_alloc(sizeof (*user), UM_SLEEP | UM_GC);
if (mdb_vread(user, sizeof (*user), addr) == -1) {
mdb_warn("failed to read smb_user at %p", addr);
@@ -1058,8 +1044,6 @@ smb_dcmd_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
account);
}
}
- if (smb_obj_expand(addr, opts, smb_user_exp, indent))
- return (DCMD_ERR);
return (DCMD_OK);
}
@@ -1217,6 +1201,8 @@ smb_dcmd_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
addr);
mdb_printf("State: %d (%s)\n", od->d_state, state);
mdb_printf("SID: %u\n", od->d_odid);
+ mdb_printf("User: %p\n", od->d_user);
+ mdb_printf("Tree: %p\n", od->d_tree);
mdb_printf("Reference Count: %d\n", od->d_refcnt);
mdb_printf("Pattern: %s\n", od->d_pattern);
mdb_printf("SMB Node: %p\n\n", od->d_dnode);
@@ -1292,6 +1278,8 @@ smb_dcmd_ofile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
((of->f_flags & SMB_OFLAGS_LLF_POS_VALID) ?
"Valid" : "Invalid"));
mdb_printf("Flags: 0x%08x\n", of->f_flags);
+ mdb_printf("User: %p\n", of->f_user);
+ mdb_printf("Tree: %p\n", of->f_tree);
mdb_printf("Credential: %p\n\n", of->f_cr);
} else {
if (DCMD_HDRSPEC(flags))
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
index 3fa43d43cb..5eaa5865c6 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -820,8 +820,8 @@ smb_open_subr(smb_request_t *sr)
status = NT_STATUS_SUCCESS;
- of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op, SMB_FTYPE_DISK,
- uniq_fid, &err);
+ of = smb_ofile_open(sr, node, sr->smb_pid, op, SMB_FTYPE_DISK, uniq_fid,
+ &err);
if (of == NULL) {
smbsr_error(sr, err.status, err.errcls, err.errcode);
status = err.status;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete.c b/usr/src/uts/common/fs/smbsrv/smb_delete.c
index 4930f741ef..14eff73896 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c
@@ -297,7 +297,7 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
if (odid == 0)
return (-1);
- if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL)
+ if ((od = smb_tree_lookup_odir(sr, odid)) == NULL)
return (-1);
for (;;) {
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
index 1afcf18b28..9b1fed6f9a 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
@@ -20,8 +20,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -694,16 +694,13 @@ andx_more:
}
sr->user_cr = smb_user_getcred(sr->uid_user);
-
- if (!(sdd->sdt_flags & SDDF_SUPPRESS_TID) &&
- (sr->tid_tree == NULL)) {
- sr->tid_tree = smb_user_lookup_tree(
- sr->uid_user, sr->smb_tid);
- if (sr->tid_tree == NULL) {
- smbsr_error(sr, 0, ERRSRV, ERRinvnid);
- smbsr_cleanup(sr);
- goto report_error;
- }
+ }
+ if (!(sdd->sdt_flags & SDDF_SUPPRESS_TID) && (sr->tid_tree == NULL)) {
+ sr->tid_tree = smb_session_lookup_tree(session, sr->smb_tid);
+ if (sr->tid_tree == NULL) {
+ smbsr_error(sr, 0, ERRSRV, ERRinvnid);
+ smbsr_cleanup(sr);
+ goto report_error;
}
}
@@ -1116,8 +1113,7 @@ void
smbsr_lookup_file(smb_request_t *sr)
{
if (sr->fid_ofile == NULL)
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
- sr->smb_fid);
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr, sr->smb_fid);
}
static int
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find.c b/usr/src/uts/common/fs/smbsrv/smb_find.c
index 1dae4e8cb5..eecbeff4df 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_find.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_find.c
@@ -306,7 +306,7 @@ smb_com_search(smb_request_t *sr)
}
}
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ od = smb_tree_lookup_odir(sr, odid);
if (od == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERROR_INVALID_HANDLE);
@@ -452,7 +452,7 @@ smb_com_find(smb_request_t *sr)
}
}
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ od = smb_tree_lookup_odir(sr, odid);
if (od == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERROR_INVALID_HANDLE);
@@ -575,7 +575,7 @@ smb_com_find_close(smb_request_t *sr)
return (SDRC_ERROR);
}
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ od = smb_tree_lookup_odir(sr, odid);
if (od == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERROR_INVALID_HANDLE);
@@ -649,7 +649,7 @@ smb_com_find_unique(struct smb_request *sr)
odid = smb_odir_open(sr, pn->pn_path, sattr, 0);
if (odid == 0)
return (SDRC_ERROR);
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ od = smb_tree_lookup_odir(sr, odid);
if (od == NULL)
return (SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
index 2f4545e966..c64313fdbf 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
@@ -805,7 +805,7 @@ smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode)
return (-1);
}
- if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) {
+ if ((od = smb_tree_lookup_odir(sr, odid)) == NULL) {
smbsr_errno(sr, ENOENT);
return (-1);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
index c77c175fc1..037c1373b5 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
@@ -264,8 +264,7 @@ smb_com_nt_create_andx(struct smb_request *sr)
if (op->rootdirfid == 0) {
op->fqi.fq_dnode = sr->tid_tree->t_snode;
} else {
- op->dir = smb_ofile_lookup_by_fid(sr->tid_tree,
- (uint16_t)op->rootdirfid);
+ op->dir = smb_ofile_lookup_by_fid(sr, (uint16_t)op->rootdirfid);
if (op->dir == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERRbadfid);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
index fcc12f2fc8..dcfa469617 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
@@ -173,8 +173,7 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
if (op->rootdirfid == 0) {
op->fqi.fq_dnode = sr->tid_tree->t_snode;
} else {
- op->dir = smb_ofile_lookup_by_fid(sr->tid_tree,
- (uint16_t)op->rootdirfid);
+ op->dir = smb_ofile_lookup_by_fid(sr, (uint16_t)op->rootdirfid);
if (op->dir == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERRbadfid);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_odir.c b/usr/src/uts/common/fs/smbsrv/smb_odir.c
index b8435d191a..16fffa6692 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_odir.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c
@@ -39,15 +39,15 @@
* +-------------------+ +-------------------+ +-------------------+
* | SESSION |<----->| SESSION |......| SESSION |
* +-------------------+ +-------------------+ +-------------------+
- * |
- * |
- * v
- * +-------------------+ +-------------------+ +-------------------+
- * | USER |<----->| USER |......| USER |
- * +-------------------+ +-------------------+ +-------------------+
- * |
- * |
- * v
+ * | |
+ * | |
+ * | v
+ * | +-------------------+ +-------------------+ +-------------------+
+ * | | USER |<--->| USER |...| USER |
+ * | +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
* +-------------------+ +-------------------+ +-------------------+
* | TREE |<----->| TREE |......| TREE |
* +-------------------+ +-------------------+ +-------------------+
@@ -153,7 +153,7 @@
* and add it into the tree's list of odirs.
* Return an identifier (odid) uniquely identifying the created odir.
*
- * smb_odir_t *odir = smb_tree_lookup_odir(odid)
+ * smb_odir_t *odir = smb_tree_lookup_odir(..., odid)
* Find the odir corresponding to the specified odid in the tree's
* list of odirs. Place a hold on the odir.
*
@@ -312,9 +312,9 @@ smb_odir_open(smb_request_t *sr, char *path, uint16_t sattr, uint32_t flags)
}
if (flags & SMB_ODIR_OPENF_BACKUP_INTENT)
- cr = smb_user_getprivcred(tree->t_user);
+ cr = smb_user_getprivcred(sr->uid_user);
else
- cr = tree->t_user->u_cred;
+ cr = sr->uid_user->u_cred;
odid = smb_odir_create(sr, dnode, pattern, sattr, cr);
smb_node_release(dnode);
@@ -888,6 +888,12 @@ smb_odir_create(smb_request_t *sr, smb_node_t *dnode,
od->d_opened_by_pid = sr->smb_pid;
od->d_session = tree->t_session;
od->d_cred = cr;
+ /*
+ * grab a ref for od->d_user
+ * released in smb_odir_delete()
+ */
+ smb_user_hold_internal(sr->uid_user);
+ od->d_user = sr->uid_user;
od->d_tree = tree;
od->d_dnode = dnode;
smb_node_ref(dnode);
@@ -947,6 +953,7 @@ smb_odir_delete(void *arg)
od->d_magic = 0;
smb_node_release(od->d_dnode);
+ smb_user_release(od->d_user);
mutex_destroy(&od->d_mutex);
kmem_cache_free(od->d_tree->t_server->si_cache_odir, od);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
index 8987da2950..ee45f13c8b 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
@@ -39,15 +39,15 @@
* +-------------------+ +-------------------+ +-------------------+
* | SESSION |<----->| SESSION |......| SESSION |
* +-------------------+ +-------------------+ +-------------------+
- * |
- * |
- * v
- * +-------------------+ +-------------------+ +-------------------+
- * | USER |<----->| USER |......| USER |
- * +-------------------+ +-------------------+ +-------------------+
- * |
- * |
- * v
+ * | |
+ * | |
+ * | v
+ * | +-------------------+ +-------------------+ +-------------------+
+ * | | USER |<--->| USER |...| USER |
+ * | +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
* +-------------------+ +-------------------+ +-------------------+
* | TREE |<----->| TREE |......| TREE |
* +-------------------+ +-------------------+ +-------------------+
@@ -175,7 +175,7 @@ static void smb_ofile_netinfo_fini(smb_netfileinfo_t *);
*/
smb_ofile_t *
smb_ofile_open(
- smb_tree_t *tree,
+ smb_request_t *sr,
smb_node_t *node,
uint16_t pid,
struct open_param *op,
@@ -183,10 +183,13 @@ smb_ofile_open(
uint32_t uniqid,
smb_error_t *err)
{
+ smb_tree_t *tree = sr->tid_tree;
smb_ofile_t *of;
uint16_t fid;
smb_attr_t attr;
int rc;
+ enum errstates { EMPTY, FIDALLOC, CRHELD, MUTEXINIT };
+ enum errstates state = EMPTY;
if (smb_idpool_alloc(&tree->t_fid_pool, &fid)) {
err->status = NT_STATUS_TOO_MANY_OPENED_FILES;
@@ -194,6 +197,7 @@ smb_ofile_open(
err->errcode = ERROR_TOO_MANY_OPEN_FILES;
return (NULL);
}
+ state = FIDALLOC;
of = kmem_cache_alloc(tree->t_server->si_cache_ofile, KM_SLEEP);
bzero(of, sizeof (smb_ofile_t));
@@ -206,16 +210,23 @@ smb_ofile_open(
of->f_share_access = op->share_access;
of->f_create_options = op->create_options;
of->f_cr = (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) ?
- smb_user_getprivcred(tree->t_user) : tree->t_user->u_cred;
+ smb_user_getprivcred(sr->uid_user) : sr->uid_user->u_cred;
crhold(of->f_cr);
+ state = CRHELD;
of->f_ftype = ftype;
of->f_server = tree->t_server;
- of->f_session = tree->t_user->u_session;
- of->f_user = tree->t_user;
+ of->f_session = tree->t_session;
+ /*
+ * grab a ref for of->f_user
+ * released in smb_ofile_delete()
+ */
+ smb_user_hold_internal(sr->uid_user);
+ of->f_user = sr->uid_user;
of->f_tree = tree;
of->f_node = node;
mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL);
+ state = MUTEXINIT;
of->f_state = SMB_OFILE_STATE_OPEN;
if (ftype == SMB_FTYPE_MESG_PIPE) {
@@ -232,15 +243,10 @@ smb_ofile_open(
attr.sa_mask = SMB_AT_UID | SMB_AT_DOSATTR;
rc = smb_node_getattr(NULL, node, of->f_cr, NULL, &attr);
if (rc != 0) {
- of->f_magic = 0;
- mutex_destroy(&of->f_mutex);
- crfree(of->f_cr);
- smb_idpool_free(&tree->t_fid_pool, of->f_fid);
- kmem_cache_free(tree->t_server->si_cache_ofile, of);
err->status = NT_STATUS_INTERNAL_ERROR;
err->errcls = ERRDOS;
err->errcode = ERROR_INTERNAL_ERROR;
- return (NULL);
+ goto errout;
}
if (crgetuid(of->f_cr) == attr.sa_vattr.va_uid) {
/*
@@ -254,16 +260,10 @@ smb_ofile_open(
of->f_mode =
smb_fsop_amask_to_omode(of->f_granted_access);
if (smb_fsop_open(node, of->f_mode, of->f_cr) != 0) {
- of->f_magic = 0;
- mutex_destroy(&of->f_mutex);
- crfree(of->f_cr);
- smb_idpool_free(&tree->t_fid_pool, of->f_fid);
- kmem_cache_free(tree->t_server->si_cache_ofile,
- of);
err->status = NT_STATUS_ACCESS_DENIED;
err->errcls = ERRDOS;
err->errcode = ERROR_ACCESS_DENIED;
- return (NULL);
+ goto errout;
}
}
@@ -290,6 +290,25 @@ smb_ofile_open(
atomic_inc_32(&tree->t_open_files);
atomic_inc_32(&of->f_session->s_file_cnt);
return (of);
+
+errout:
+ switch (state) {
+ case MUTEXINIT:
+ mutex_destroy(&of->f_mutex);
+ smb_user_release(of->f_user);
+ /*FALLTHROUGH*/
+ case CRHELD:
+ crfree(of->f_cr);
+ of->f_magic = 0;
+ kmem_cache_free(tree->t_server->si_cache_ofile, of);
+ /*FALLTHROUGH*/
+ case FIDALLOC:
+ smb_idpool_free(&tree->t_fid_pool, fid);
+ /*FALLTHROUGH*/
+ case EMPTY:
+ break;
+ }
+ return (NULL);
}
/*
@@ -601,9 +620,10 @@ smb_ofile_request_complete(smb_ofile_t *of)
*/
smb_ofile_t *
smb_ofile_lookup_by_fid(
- smb_tree_t *tree,
+ smb_request_t *sr,
uint16_t fid)
{
+ smb_tree_t *tree = sr->tid_tree;
smb_llist_t *of_list;
smb_ofile_t *of;
@@ -616,19 +636,32 @@ smb_ofile_lookup_by_fid(
while (of) {
ASSERT(of->f_magic == SMB_OFILE_MAGIC);
ASSERT(of->f_tree == tree);
- if (of->f_fid == fid) {
- mutex_enter(&of->f_mutex);
- if (of->f_state != SMB_OFILE_STATE_OPEN) {
- mutex_exit(&of->f_mutex);
- smb_llist_exit(of_list);
- return (NULL);
- }
- of->f_refcnt++;
- mutex_exit(&of->f_mutex);
+ if (of->f_fid == fid)
break;
- }
of = smb_llist_next(of_list, of);
}
+ if (of == NULL)
+ goto out;
+
+ /*
+ * Only allow use of a given FID with the same UID that
+ * was used to open it. MS-CIFS 3.3.5.14
+ */
+ if (of->f_user != sr->uid_user) {
+ of = NULL;
+ goto out;
+ }
+
+ mutex_enter(&of->f_mutex);
+ if (of->f_state != SMB_OFILE_STATE_OPEN) {
+ mutex_exit(&of->f_mutex);
+ of = NULL;
+ goto out;
+ }
+ of->f_refcnt++;
+ mutex_exit(&of->f_mutex);
+
+out:
smb_llist_exit(of_list);
return (of);
}
@@ -921,6 +954,7 @@ smb_ofile_delete(void *arg)
of->f_magic = (uint32_t)~SMB_OFILE_MAGIC;
mutex_destroy(&of->f_mutex);
crfree(of->f_cr);
+ smb_user_release(of->f_user);
kmem_cache_free(of->f_tree->t_server->si_cache_ofile, of);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_opipe.c b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
index bb178f3952..90cb25aaa0 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
@@ -130,8 +130,8 @@ smb_opipe_open(smb_request_t *sr)
op->create_options = 0;
- of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op,
- SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err);
+ of = smb_ofile_open(sr, NULL, sr->smb_pid, op, SMB_FTYPE_MESG_PIPE,
+ SMB_UNIQ_FID(), &err);
if (of == NULL)
return (err.status);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_process_exit.c b/usr/src/uts/common/fs/smbsrv/smb_process_exit.c
index b8c835cd57..2839ca2807 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_process_exit.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_process_exit.c
@@ -85,11 +85,11 @@ smb_com_process_exit(smb_request_t *sr)
* to be the only thing that sends this request these days and
* it doesn't provide a TID.
*/
- sr->tid_tree = smb_user_lookup_tree(sr->uid_user, sr->smb_tid);
+ sr->tid_tree = smb_session_lookup_tree(sr->session, sr->smb_tid);
if (sr->tid_tree != NULL)
smb_tree_close_pid(sr->tid_tree, sr->smb_pid);
else
- smb_user_close_pid(sr->uid_user, sr->smb_pid);
+ smb_session_close_pid(sr->session, sr->smb_pid);
rc = smbsr_encode_empty_result(sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c b/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c
index bef69e7f61..70ac2e7b24 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c
@@ -662,7 +662,7 @@ smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo)
odid = smb_odir_openat(sr, fnode);
if (odid != 0)
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ od = smb_tree_lookup_odir(sr, odid);
if (od != NULL)
rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c
index 3654744569..8687d42b18 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c
@@ -240,7 +240,8 @@ static void smb_event_cancel(smb_server_t *, uint32_t);
static uint32_t smb_event_alloc_txid(void);
static void smb_server_disconnect_share(smb_llist_t *, const char *);
-static void smb_server_enum_private(smb_llist_t *, smb_svcenum_t *);
+static void smb_server_enum_users(smb_llist_t *, smb_svcenum_t *);
+static void smb_server_enum_trees(smb_llist_t *, smb_svcenum_t *);
static int smb_server_session_disconnect(smb_llist_t *, const char *,
const char *);
static int smb_server_fclose(smb_llist_t *, uint32_t);
@@ -833,15 +834,6 @@ smb_server_enum(smb_ioc_svcenum_t *ioc)
smb_server_t *sv;
int rc;
- switch (svcenum->se_type) {
- case SMB_SVCENUM_TYPE_USER:
- case SMB_SVCENUM_TYPE_TREE:
- case SMB_SVCENUM_TYPE_FILE:
- break;
- default:
- return (EINVAL);
- }
-
if ((rc = smb_server_lookup(&sv)) != 0)
return (rc);
@@ -849,11 +841,26 @@ smb_server_enum(smb_ioc_svcenum_t *ioc)
svcenum->se_bused = 0;
svcenum->se_nitems = 0;
- smb_server_enum_private(&sv->sv_nbt_daemon.ld_session_list, svcenum);
- smb_server_enum_private(&sv->sv_tcp_daemon.ld_session_list, svcenum);
+ switch (svcenum->se_type) {
+ case SMB_SVCENUM_TYPE_USER:
+ smb_server_enum_users(&sv->sv_nbt_daemon.ld_session_list,
+ svcenum);
+ smb_server_enum_users(&sv->sv_tcp_daemon.ld_session_list,
+ svcenum);
+ break;
+ case SMB_SVCENUM_TYPE_TREE:
+ case SMB_SVCENUM_TYPE_FILE:
+ smb_server_enum_trees(&sv->sv_nbt_daemon.ld_session_list,
+ svcenum);
+ smb_server_enum_trees(&sv->sv_tcp_daemon.ld_session_list,
+ svcenum);
+ break;
+ default:
+ rc = EINVAL;
+ }
smb_server_release(sv);
- return (0);
+ return (rc);
}
/*
@@ -1694,7 +1701,7 @@ smb_server_release(smb_server_t *sv)
* Enumerate the users associated with a session list.
*/
static void
-smb_server_enum_private(smb_llist_t *ll, smb_svcenum_t *svcenum)
+smb_server_enum_users(smb_llist_t *ll, smb_svcenum_t *svcenum)
{
smb_session_t *sn;
smb_llist_t *ulist;
@@ -1714,6 +1721,8 @@ smb_server_enum_private(smb_llist_t *ll, smb_svcenum_t *svcenum)
if (smb_user_hold(user)) {
rc = smb_user_enum(user, svcenum);
smb_user_release(user);
+ if (rc != 0)
+ break;
}
user = smb_llist_next(ulist, user);
@@ -1731,6 +1740,48 @@ smb_server_enum_private(smb_llist_t *ll, smb_svcenum_t *svcenum)
}
/*
+ * Enumerate the trees/files associated with a session list.
+ */
+static void
+smb_server_enum_trees(smb_llist_t *ll, smb_svcenum_t *svcenum)
+{
+ smb_session_t *sn;
+ smb_llist_t *tlist;
+ smb_tree_t *tree;
+ int rc = 0;
+
+ smb_llist_enter(ll, RW_READER);
+ sn = smb_llist_head(ll);
+
+ while (sn != NULL) {
+ SMB_SESSION_VALID(sn);
+ tlist = &sn->s_tree_list;
+ smb_llist_enter(tlist, RW_READER);
+ tree = smb_llist_head(tlist);
+
+ while (tree != NULL) {
+ if (smb_tree_hold(tree)) {
+ rc = smb_tree_enum(tree, svcenum);
+ smb_tree_release(tree);
+ if (rc != 0)
+ break;
+ }
+
+ tree = smb_llist_next(tlist, tree);
+ }
+
+ smb_llist_exit(tlist);
+
+ if (rc != 0)
+ break;
+
+ sn = smb_llist_next(ll, sn);
+ }
+
+ smb_llist_exit(ll);
+}
+
+/*
* Disconnect sessions associated with the specified client and username.
* Empty strings are treated as wildcards.
*/
@@ -1796,8 +1847,8 @@ static int
smb_server_fclose(smb_llist_t *ll, uint32_t uniqid)
{
smb_session_t *sn;
- smb_llist_t *ulist;
- smb_user_t *user;
+ smb_llist_t *tlist;
+ smb_tree_t *tree;
int rc = ENOENT;
smb_llist_enter(ll, RW_READER);
@@ -1805,20 +1856,20 @@ smb_server_fclose(smb_llist_t *ll, uint32_t uniqid)
while ((sn != NULL) && (rc == ENOENT)) {
SMB_SESSION_VALID(sn);
- ulist = &sn->s_user_list;
- smb_llist_enter(ulist, RW_READER);
- user = smb_llist_head(ulist);
-
- while ((user != NULL) && (rc == ENOENT)) {
- if (smb_user_hold(user)) {
- rc = smb_user_fclose(user, uniqid);
- smb_user_release(user);
+ tlist = &sn->s_tree_list;
+ smb_llist_enter(tlist, RW_READER);
+ tree = smb_llist_head(tlist);
+
+ while ((tree != NULL) && (rc == ENOENT)) {
+ if (smb_tree_hold(tree)) {
+ rc = smb_tree_fclose(tree, uniqid);
+ smb_tree_release(tree);
}
- user = smb_llist_next(ulist, user);
+ tree = smb_llist_next(tlist, tree);
}
- smb_llist_exit(ulist);
+ smb_llist_exit(tlist);
sn = smb_llist_next(ll, sn);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c
index 0fdac10ca6..b8284b372f 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c
@@ -43,6 +43,7 @@ static int smb_session_message(smb_session_t *);
static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
uint8_t *, size_t);
static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *);
+static smb_tree_t *smb_session_get_tree(smb_session_t *, smb_tree_t *);
static void smb_session_logoff(smb_session_t *);
static void smb_request_init_command_mbuf(smb_request_t *sr);
void dump_smb_inaddr(smb_inaddr_t *ipaddr);
@@ -624,6 +625,11 @@ smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv,
kmem_cache_free(sv->si_cache_session, session);
return (NULL);
}
+ if (smb_idpool_constructor(&session->s_tid_pool)) {
+ smb_idpool_destructor(&session->s_uid_pool);
+ kmem_cache_free(sv->si_cache_session, session);
+ return (NULL);
+ }
now = ddi_get_lbolt64();
@@ -642,6 +648,9 @@ smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv,
smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
offsetof(smb_user_t, u_lnd));
+ smb_llist_constructor(&session->s_tree_list, sizeof (smb_tree_t),
+ offsetof(smb_tree_t, t_lnd));
+
smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
offsetof(smb_xa_t, xa_lnd));
@@ -719,6 +728,7 @@ smb_session_delete(smb_session_t *session)
list_destroy(&session->s_oplock_brkreqs);
smb_slist_destructor(&session->s_req_list);
+ smb_llist_destructor(&session->s_tree_list);
smb_llist_destructor(&session->s_user_list);
smb_llist_destructor(&session->s_xa_list);
@@ -726,6 +736,7 @@ smb_session_delete(smb_session_t *session)
ASSERT(session->s_file_cnt == 0);
ASSERT(session->s_dir_cnt == 0);
+ smb_idpool_destructor(&session->s_tid_pool);
smb_idpool_destructor(&session->s_uid_pool);
if (session->sock != NULL) {
if (session->s_local_port == IPPORT_NETBIOS_SSN)
@@ -928,45 +939,306 @@ smb_session_post_user(smb_session_t *session, smb_user_t *user)
}
/*
- * Logoff all users associated with the specified session.
+ * Find a tree by tree-id.
*/
-static void
-smb_session_logoff(smb_session_t *session)
+smb_tree_t *
+smb_session_lookup_tree(
+ smb_session_t *session,
+ uint16_t tid)
+
{
- smb_user_t *user;
+ smb_tree_t *tree;
SMB_SESSION_VALID(session);
- smb_llist_enter(&session->s_user_list, RW_READER);
+ smb_llist_enter(&session->s_tree_list, RW_READER);
+ tree = smb_llist_head(&session->s_tree_list);
- user = smb_llist_head(&session->s_user_list);
- while (user) {
- SMB_USER_VALID(user);
- ASSERT(user->u_session == session);
+ while (tree) {
+ ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
+ ASSERT(tree->t_session == session);
- if (smb_user_hold(user)) {
- smb_user_logoff(user);
- smb_user_release(user);
+ if (tree->t_tid == tid) {
+ if (smb_tree_hold(tree)) {
+ smb_llist_exit(&session->s_tree_list);
+ return (tree);
+ } else {
+ smb_llist_exit(&session->s_tree_list);
+ return (NULL);
+ }
}
- user = smb_llist_next(&session->s_user_list, user);
+ tree = smb_llist_next(&session->s_tree_list, tree);
}
- smb_llist_exit(&session->s_user_list);
+ smb_llist_exit(&session->s_tree_list);
+ return (NULL);
+}
+
+/*
+ * Find the first connected tree that matches the specified sharename.
+ * If the specified tree is NULL the search starts from the beginning of
+ * the user's tree list. If a tree is provided the search starts just
+ * after that tree.
+ */
+smb_tree_t *
+smb_session_lookup_share(
+ smb_session_t *session,
+ const char *sharename,
+ smb_tree_t *tree)
+{
+ SMB_SESSION_VALID(session);
+ ASSERT(sharename);
+
+ smb_llist_enter(&session->s_tree_list, RW_READER);
+
+ if (tree) {
+ ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
+ ASSERT(tree->t_session == session);
+ tree = smb_llist_next(&session->s_tree_list, tree);
+ } else {
+ tree = smb_llist_head(&session->s_tree_list);
+ }
+
+ while (tree) {
+ ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
+ ASSERT(tree->t_session == session);
+ if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) {
+ if (smb_tree_hold(tree)) {
+ smb_llist_exit(&session->s_tree_list);
+ return (tree);
+ }
+ }
+ tree = smb_llist_next(&session->s_tree_list, tree);
+ }
+
+ smb_llist_exit(&session->s_tree_list);
+ return (NULL);
+}
+
+/*
+ * Find the first connected tree that matches the specified volume name.
+ * If the specified tree is NULL the search starts from the beginning of
+ * the user's tree list. If a tree is provided the search starts just
+ * after that tree.
+ */
+smb_tree_t *
+smb_session_lookup_volume(
+ smb_session_t *session,
+ const char *name,
+ smb_tree_t *tree)
+{
+ SMB_SESSION_VALID(session);
+ ASSERT(name);
+
+ smb_llist_enter(&session->s_tree_list, RW_READER);
+
+ if (tree) {
+ ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
+ ASSERT(tree->t_session == session);
+ tree = smb_llist_next(&session->s_tree_list, tree);
+ } else {
+ tree = smb_llist_head(&session->s_tree_list);
+ }
+
+ while (tree) {
+ ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
+ ASSERT(tree->t_session == session);
+
+ if (smb_strcasecmp(tree->t_volume, name, 0) == 0) {
+ if (smb_tree_hold(tree)) {
+ smb_llist_exit(&session->s_tree_list);
+ return (tree);
+ }
+ }
+
+ tree = smb_llist_next(&session->s_tree_list, tree);
+ }
+
+ smb_llist_exit(&session->s_tree_list);
+ return (NULL);
+}
+
+/*
+ * Disconnect all trees that match the specified client process-id.
+ */
+void
+smb_session_close_pid(
+ smb_session_t *session,
+ uint16_t pid)
+{
+ smb_tree_t *tree;
+
+ SMB_SESSION_VALID(session);
+
+ tree = smb_session_get_tree(session, NULL);
+ while (tree) {
+ smb_tree_t *next;
+ ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
+ ASSERT(tree->t_session == session);
+ smb_tree_close_pid(tree, pid);
+ next = smb_session_get_tree(session, tree);
+ smb_tree_release(tree);
+ tree = next;
+ }
+}
+
+static void
+smb_session_tree_dtor(void *t)
+{
+ smb_tree_t *tree = (smb_tree_t *)t;
+
+ smb_tree_disconnect(tree, B_TRUE);
+ /* release the ref acquired during the traversal loop */
+ smb_tree_release(tree);
}
+
/*
- * Disconnect any trees associated with the specified share.
- * Iterate through the users on this session and tell each user
- * to disconnect from the share.
+ * Disconnect all trees that this user has connected.
*/
void
-smb_session_disconnect_share(smb_session_t *session, const char *sharename)
+smb_session_disconnect_owned_trees(
+ smb_session_t *session,
+ smb_user_t *owner)
+{
+ smb_tree_t *tree;
+ smb_llist_t *tree_list = &session->s_tree_list;
+
+ SMB_SESSION_VALID(session);
+ SMB_USER_VALID(owner);
+
+ smb_llist_enter(tree_list, RW_READER);
+
+ tree = smb_llist_head(tree_list);
+ while (tree) {
+ if ((tree->t_owner == owner) &&
+ smb_tree_hold(tree)) {
+ /*
+ * smb_tree_hold() succeeded, hence we are in state
+ * SMB_TREE_STATE_CONNECTED; schedule this tree
+ * for asynchronous disconnect, which will fire
+ * after we drop the llist traversal lock.
+ */
+ smb_llist_post(tree_list, tree, smb_session_tree_dtor);
+ }
+ tree = smb_llist_next(tree_list, tree);
+ }
+
+ /* drop the lock and flush the dtor queue */
+ smb_llist_exit(tree_list);
+}
+
+/*
+ * Disconnect all trees that this user has connected.
+ */
+void
+smb_session_disconnect_trees(
+ smb_session_t *session)
+{
+ smb_tree_t *tree;
+
+ SMB_SESSION_VALID(session);
+
+ tree = smb_session_get_tree(session, NULL);
+ while (tree) {
+ ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
+ ASSERT(tree->t_session == session);
+ smb_tree_disconnect(tree, B_TRUE);
+ smb_tree_release(tree);
+ tree = smb_session_get_tree(session, NULL);
+ }
+}
+
+/*
+ * Disconnect all trees that match the specified share name.
+ */
+void
+smb_session_disconnect_share(
+ smb_session_t *session,
+ const char *sharename)
+{
+ smb_tree_t *tree;
+ smb_tree_t *next;
+
+ SMB_SESSION_VALID(session);
+
+ tree = smb_session_lookup_share(session, sharename, NULL);
+ while (tree) {
+ ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
+ ASSERT(tree->t_session == session);
+ smb_session_cancel_requests(session, tree, NULL);
+ smb_tree_disconnect(tree, B_TRUE);
+ next = smb_session_lookup_share(session, sharename, tree);
+ smb_tree_release(tree);
+ tree = next;
+ }
+}
+
+void
+smb_session_post_tree(smb_session_t *session, smb_tree_t *tree)
+{
+ SMB_SESSION_VALID(session);
+ SMB_TREE_VALID(tree);
+ ASSERT0(tree->t_refcnt);
+ ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
+ ASSERT(tree->t_session == session);
+
+ smb_llist_post(&session->s_tree_list, tree, smb_tree_dealloc);
+}
+
+/*
+ * Get the next connected tree in the list. A reference is taken on
+ * the tree, which can be released later with smb_tree_release().
+ *
+ * If the specified tree is NULL the search starts from the beginning of
+ * the tree list. If a tree is provided the search starts just after
+ * that tree.
+ *
+ * Returns NULL if there are no connected trees in the list.
+ */
+static smb_tree_t *
+smb_session_get_tree(
+ smb_session_t *session,
+ smb_tree_t *tree)
+{
+ smb_llist_t *tree_list;
+
+ SMB_SESSION_VALID(session);
+ tree_list = &session->s_tree_list;
+
+ smb_llist_enter(tree_list, RW_READER);
+
+ if (tree) {
+ ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
+ tree = smb_llist_next(tree_list, tree);
+ } else {
+ tree = smb_llist_head(tree_list);
+ }
+
+ while (tree) {
+ if (smb_tree_hold(tree))
+ break;
+
+ tree = smb_llist_next(tree_list, tree);
+ }
+
+ smb_llist_exit(tree_list);
+ return (tree);
+}
+
+/*
+ * Logoff all users associated with the specified session.
+ */
+static void
+smb_session_logoff(smb_session_t *session)
{
smb_user_t *user;
SMB_SESSION_VALID(session);
+ smb_session_disconnect_trees(session);
+
smb_llist_enter(&session->s_user_list, RW_READER);
user = smb_llist_head(&session->s_user_list);
@@ -975,7 +1247,7 @@ smb_session_disconnect_share(smb_session_t *session, const char *sharename)
ASSERT(user->u_session == session);
if (smb_user_hold(user)) {
- smb_user_disconnect_share(user, sharename);
+ smb_user_logoff(user);
smb_user_release(user);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
index 037b2a3b36..d0d60cea5d 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
@@ -332,7 +332,7 @@ smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa)
return (SDRC_ERROR);
}
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ od = smb_tree_lookup_odir(sr, odid);
if (od == NULL)
return (SDRC_ERROR);
@@ -463,7 +463,7 @@ smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
if (args.fa_maxdata == 0)
return (SDRC_ERROR);
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ od = smb_tree_lookup_odir(sr, odid);
if (od == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERROR_INVALID_HANDLE);
@@ -943,7 +943,7 @@ smb_com_find_close2(smb_request_t *sr)
if (smbsr_decode_vwv(sr, "w", &odid) != 0)
return (SDRC_ERROR);
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ od = smb_tree_lookup_odir(sr, odid);
if (od == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERROR_INVALID_HANDLE);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c
index 13adc2d803..b225c67623 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -40,15 +40,15 @@
* +-------------------+ +-------------------+ +-------------------+
* | SESSION |<----->| SESSION |......| SESSION |
* +-------------------+ +-------------------+ +-------------------+
- * |
- * |
- * v
- * +-------------------+ +-------------------+ +-------------------+
- * | USER |<----->| USER |......| USER |
- * +-------------------+ +-------------------+ +-------------------+
- * |
- * |
- * v
+ * | |
+ * | |
+ * | v
+ * | +-------------------+ +-------------------+ +-------------------+
+ * | | USER |<--->| USER |...| USER |
+ * | +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
* +-------------------+ +-------------------+ +-------------------+
* | TREE |<----->| TREE |......| TREE |
* +-------------------+ +-------------------+ +-------------------+
@@ -175,7 +175,7 @@ static smb_tree_t *smb_tree_connect_core(smb_request_t *);
static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *);
static smb_tree_t *smb_tree_connect_printq(smb_request_t *, const char *);
static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *);
-static smb_tree_t *smb_tree_alloc(smb_user_t *, const smb_kshare_t *,
+static smb_tree_t *smb_tree_alloc(smb_request_t *, const smb_kshare_t *,
smb_node_t *, uint32_t, uint32_t);
static boolean_t smb_tree_is_connected_locked(smb_tree_t *);
static boolean_t smb_tree_is_disconnected(smb_tree_t *);
@@ -269,6 +269,7 @@ smb_tree_connect_core(smb_request_t *sr)
}
smb_kshare_release(si);
+
return (tree);
}
@@ -361,7 +362,7 @@ smb_tree_release(
smb_llist_flush(&tree->t_odir_list);
if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0))
- smb_user_post_tree(tree->t_user, tree);
+ smb_session_post_tree(tree->t_session, tree);
mutex_exit(&tree->t_mutex);
}
@@ -428,7 +429,7 @@ smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
{
smb_ofile_t *of;
smb_ofile_t *next;
- int rc;
+ int rc = 0;
ASSERT(tree);
ASSERT(tree->t_magic == SMB_TREE_MAGIC);
@@ -712,8 +713,7 @@ smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
if (!smb_shortnames)
sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME;
- tree = smb_tree_alloc(user, si, snode, access,
- sr->sr_cfg->skc_execflags);
+ tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
smb_node_release(snode);
@@ -805,8 +805,7 @@ smb_tree_connect_printq(smb_request_t *sr, const char *sharename)
sr->sr_tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
- tree = smb_tree_alloc(user, si, snode, access,
- sr->sr_cfg->skc_execflags);
+ tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
smb_node_release(snode);
@@ -846,7 +845,7 @@ smb_tree_connect_ipc(smb_request_t *sr, const char *name)
sr->sr_tcon.optional_support = SMB_SUPPORT_SEARCH_BITS;
- tree = smb_tree_alloc(user, si, NULL, ACE_ALL_PERMS, 0);
+ tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0);
if (tree == NULL) {
smb_tree_log(sr, name, "access denied");
smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
@@ -859,41 +858,45 @@ smb_tree_connect_ipc(smb_request_t *sr, const char *name)
* Allocate a tree.
*/
static smb_tree_t *
-smb_tree_alloc(smb_user_t *user, const smb_kshare_t *si, smb_node_t *snode,
- uint32_t access, uint32_t execflags)
+smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si,
+ smb_node_t *snode, uint32_t access, uint32_t execflags)
{
+ smb_session_t *session = sr->session;
smb_tree_t *tree;
uint32_t stype = si->shr_type;
uint16_t tid;
- if (smb_idpool_alloc(&user->u_tid_pool, &tid))
+ if (smb_idpool_alloc(&session->s_tid_pool, &tid))
return (NULL);
- tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP);
+ tree = kmem_cache_alloc(session->s_server->si_cache_tree, KM_SLEEP);
bzero(tree, sizeof (smb_tree_t));
- tree->t_user = user;
- tree->t_session = user->u_session;
- tree->t_server = user->u_server;
+ tree->t_session = session;
+ tree->t_server = session->s_server;
+
+ /* grab a ref for tree->t_owner */
+ smb_user_hold_internal(sr->uid_user);
+ tree->t_owner = sr->uid_user;
if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
if (smb_tree_getattr(si, snode, tree) != 0) {
- smb_idpool_free(&user->u_tid_pool, tid);
- kmem_cache_free(user->u_server->si_cache_tree, tree);
+ smb_idpool_free(&session->s_tid_pool, tid);
+ kmem_cache_free(session->s_server->si_cache_tree, tree);
return (NULL);
}
}
if (smb_idpool_constructor(&tree->t_fid_pool)) {
- smb_idpool_free(&user->u_tid_pool, tid);
- kmem_cache_free(user->u_server->si_cache_tree, tree);
+ smb_idpool_free(&session->s_tid_pool, tid);
+ kmem_cache_free(session->s_server->si_cache_tree, tree);
return (NULL);
}
if (smb_idpool_constructor(&tree->t_odid_pool)) {
smb_idpool_destructor(&tree->t_fid_pool);
- smb_idpool_free(&user->u_tid_pool, tid);
- kmem_cache_free(user->u_server->si_cache_tree, tree);
+ smb_idpool_free(&session->s_tid_pool, tid);
+ kmem_cache_free(session->s_server->si_cache_tree, tree);
return (NULL);
}
@@ -929,11 +932,11 @@ smb_tree_alloc(smb_user_t *user, const smb_kshare_t *si, smb_node_t *snode,
tree->t_acltype = smb_fsop_acltype(snode);
}
- smb_llist_enter(&user->u_tree_list, RW_WRITER);
- smb_llist_insert_head(&user->u_tree_list, tree);
- smb_llist_exit(&user->u_tree_list);
- atomic_inc_32(&user->u_session->s_tree_cnt);
- smb_server_inc_trees(user->u_server);
+ smb_llist_enter(&session->s_tree_list, RW_WRITER);
+ smb_llist_insert_head(&session->s_tree_list, tree);
+ smb_llist_exit(&session->s_tree_list);
+ atomic_inc_32(&session->s_tree_cnt);
+ smb_server_inc_trees(session->s_server);
return (tree);
}
@@ -947,19 +950,19 @@ smb_tree_alloc(smb_user_t *user, const smb_kshare_t *si, smb_node_t *snode,
void
smb_tree_dealloc(void *arg)
{
- smb_user_t *user;
+ smb_session_t *session;
smb_tree_t *tree = (smb_tree_t *)arg;
SMB_TREE_VALID(tree);
ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
ASSERT(tree->t_refcnt == 0);
- user = tree->t_user;
- smb_llist_enter(&user->u_tree_list, RW_WRITER);
- smb_llist_remove(&user->u_tree_list, tree);
- smb_idpool_free(&user->u_tid_pool, tree->t_tid);
- atomic_dec_32(&tree->t_session->s_tree_cnt);
- smb_llist_exit(&user->u_tree_list);
+ session = tree->t_session;
+ smb_llist_enter(&session->s_tree_list, RW_WRITER);
+ smb_llist_remove(&session->s_tree_list, tree);
+ smb_idpool_free(&session->s_tid_pool, tree->t_tid);
+ atomic_dec_32(&session->s_tree_cnt);
+ smb_llist_exit(&session->s_tree_list);
mutex_enter(&tree->t_mutex);
mutex_exit(&tree->t_mutex);
@@ -974,6 +977,10 @@ smb_tree_dealloc(void *arg)
smb_llist_destructor(&tree->t_odir_list);
smb_idpool_destructor(&tree->t_fid_pool);
smb_idpool_destructor(&tree->t_odid_pool);
+
+ SMB_USER_VALID(tree->t_owner);
+ smb_user_release(tree->t_owner);
+
kmem_cache_free(tree->t_server->si_cache_tree, tree);
}
@@ -1234,27 +1241,38 @@ smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
* Returns NULL if odir not found or a hold cannot be obtained.
*/
smb_odir_t *
-smb_tree_lookup_odir(smb_tree_t *tree, uint16_t odid)
+smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid)
{
smb_odir_t *od;
smb_llist_t *od_list;
+ smb_tree_t *tree = sr->tid_tree;
- ASSERT(tree);
ASSERT(tree->t_magic == SMB_TREE_MAGIC);
od_list = &tree->t_odir_list;
- smb_llist_enter(od_list, RW_READER);
+ smb_llist_enter(od_list, RW_READER);
od = smb_llist_head(od_list);
while (od) {
- if (od->d_odid == odid) {
- if (!smb_odir_hold(od))
- od = NULL;
+ if (od->d_odid == odid)
break;
- }
od = smb_llist_next(od_list, od);
}
+ if (od == NULL)
+ goto out;
+
+ /*
+ * Only allow use of a given Search ID with the same UID that
+ * was used to create it. MS-CIFS 3.3.5.14
+ */
+ if (od->d_user != sr->uid_user) {
+ od = NULL;
+ goto out;
+ }
+ if (!smb_odir_hold(od))
+ od = NULL;
+out:
smb_llist_exit(od_list);
return (od);
}
@@ -1377,15 +1395,16 @@ smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
}
static void
-smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec, int exec_type)
+smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec,
+ int exec_type)
{
exec->e_sharename = tree->t_sharename;
- exec->e_winname = tree->t_user->u_name;
- exec->e_userdom = tree->t_user->u_domain;
+ exec->e_winname = tree->t_owner->u_name;
+ exec->e_userdom = tree->t_owner->u_domain;
exec->e_srv_ipaddr = tree->t_session->local_ipaddr;
exec->e_cli_ipaddr = tree->t_session->ipaddr;
exec->e_cli_netbiosname = tree->t_session->workstation;
- exec->e_uid = crgetuid(tree->t_user->u_cred);
+ exec->e_uid = crgetuid(tree->t_owner->u_cred);
exec->e_type = exec_type;
}
@@ -1438,6 +1457,26 @@ smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
return (rc);
}
+static void
+smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen)
+{
+ smb_user_t *user = tree->t_owner;
+
+ /*
+ * u_domain_len and u_name_len include the '\0' in their
+ * lengths, hence the sum of the two lengths gives us room
+ * for both the '\\' and '\0' chars.
+ */
+ ASSERT(namestr);
+ ASSERT(namelen);
+ ASSERT(user->u_domain_len > 0);
+ ASSERT(user->u_name_len > 0);
+ *namelen = user->u_domain_len + user->u_name_len;
+ *namestr = kmem_alloc(*namelen, KM_SLEEP);
+ (void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain,
+ user->u_name);
+}
+
/*
* Note: ci_numusers should be the number of users connected to
* the share rather than the number of references on the tree but
@@ -1446,8 +1485,6 @@ smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
static void
smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
{
- smb_user_t *user;
-
ASSERT(tree);
info->ci_id = tree->t_tid;
@@ -1459,13 +1496,7 @@ smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
info->ci_sharelen = strlen(tree->t_sharename) + 1;
info->ci_share = smb_mem_strdup(tree->t_sharename);
- user = tree->t_user;
- ASSERT(user);
-
- info->ci_namelen = user->u_domain_len + user->u_name_len + 2;
- info->ci_username = kmem_alloc(info->ci_namelen, KM_SLEEP);
- (void) snprintf(info->ci_username, info->ci_namelen, "%s\\%s",
- user->u_domain, user->u_name);
+ smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen);
}
static void
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
index 1ce9720f5d..19b857e834 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
@@ -362,8 +363,7 @@ smb_sdrc_t
smb_pre_tree_disconnect(smb_request_t *sr)
{
sr->uid_user = smb_session_lookup_uid(sr->session, sr->smb_uid);
- if (sr->uid_user != NULL)
- sr->tid_tree = smb_user_lookup_tree(sr->uid_user, sr->smb_tid);
+ sr->tid_tree = smb_session_lookup_tree(sr->session, sr->smb_tid);
DTRACE_SMB_1(op__TreeDisconnect__start, smb_request_t *, sr);
return (SDRC_SUCCESS);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_user.c b/usr/src/uts/common/fs/smbsrv/smb_user.c
index cc3fde7f38..09eaba699c 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_user.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -38,15 +39,15 @@
* +-------------------+ +-------------------+ +-------------------+
* | SESSION |<----->| SESSION |......| SESSION |
* +-------------------+ +-------------------+ +-------------------+
- * |
- * |
- * v
- * +-------------------+ +-------------------+ +-------------------+
- * | USER |<----->| USER |......| USER |
- * +-------------------+ +-------------------+ +-------------------+
- * |
- * |
- * v
+ * | |
+ * | |
+ * | v
+ * | +-------------------+ +-------------------+ +-------------------+
+ * | | USER |<--->| USER |...| USER |
+ * | +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
* +-------------------+ +-------------------+ +-------------------+
* | TREE |<----->| TREE |......| TREE |
* +-------------------+ +-------------------+ +-------------------+
@@ -170,7 +171,6 @@
static boolean_t smb_user_is_logged_in(smb_user_t *);
static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
-static smb_tree_t *smb_user_get_tree(smb_llist_t *, smb_tree_t *);
static void smb_user_setcred(smb_user_t *, cred_t *, uint32_t);
static void smb_user_nonauth_logon(uint32_t);
static void smb_user_auth_logoff(uint32_t);
@@ -210,20 +210,15 @@ smb_user_login(
user->u_audit_sid = audit_sid;
if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) {
- if (!smb_idpool_constructor(&user->u_tid_pool)) {
- smb_llist_constructor(&user->u_tree_list,
- sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd));
- mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
- smb_user_setcred(user, cr, privileges);
- user->u_state = SMB_USER_STATE_LOGGED_IN;
- user->u_magic = SMB_USER_MAGIC;
- smb_llist_enter(&session->s_user_list, RW_WRITER);
- smb_llist_insert_tail(&session->s_user_list, user);
- smb_llist_exit(&session->s_user_list);
- smb_server_inc_users(session->s_server);
- return (user);
- }
- smb_idpool_free(&session->s_uid_pool, user->u_uid);
+ mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
+ smb_user_setcred(user, cr, privileges);
+ user->u_state = SMB_USER_STATE_LOGGED_IN;
+ user->u_magic = SMB_USER_MAGIC;
+ smb_llist_enter(&session->s_user_list, RW_WRITER);
+ smb_llist_insert_tail(&session->s_user_list, user);
+ smb_llist_exit(&session->s_user_list);
+ smb_server_inc_users(session->s_server);
+ return (user);
}
smb_mem_free(user->u_name);
smb_mem_free(user->u_domain);
@@ -279,10 +274,7 @@ smb_user_logoff(
*/
user->u_state = SMB_USER_STATE_LOGGING_OFF;
mutex_exit(&user->u_mutex);
- /*
- * All the trees hanging off of this user are disconnected.
- */
- smb_user_disconnect_trees(user);
+ smb_session_disconnect_owned_trees(user->u_session, user);
smb_user_auth_logoff(user->u_audit_sid);
mutex_enter(&user->u_mutex);
user->u_state = SMB_USER_STATE_LOGGED_OFF;
@@ -301,13 +293,13 @@ smb_user_logoff(
}
/*
- * Take a reference on a user.
+ * Take a reference on a user. Do not return a reference unless the user is in
+ * the logged-in state.
*/
boolean_t
smb_user_hold(smb_user_t *user)
{
- ASSERT(user);
- ASSERT(user->u_magic == SMB_USER_MAGIC);
+ SMB_USER_VALID(user);
mutex_enter(&user->u_mutex);
@@ -322,6 +314,19 @@ smb_user_hold(smb_user_t *user)
}
/*
+ * Unconditionally take a reference on a user.
+ */
+void
+smb_user_hold_internal(smb_user_t *user)
+{
+ SMB_USER_VALID(user);
+
+ mutex_enter(&user->u_mutex);
+ user->u_refcnt++;
+ mutex_exit(&user->u_mutex);
+}
+
+/*
* Release a reference on a user. If the reference count falls to
* zero and the user has logged off, post the object for deletion.
* Object deletion is deferred to avoid modifying a list while an
@@ -337,9 +342,6 @@ smb_user_release(
ASSERT(user->u_refcnt);
user->u_refcnt--;
- /* flush the tree list's delete queue */
- smb_llist_flush(&user->u_tree_list);
-
switch (user->u_state) {
case SMB_USER_STATE_LOGGED_OFF:
if (user->u_refcnt == 0)
@@ -357,248 +359,6 @@ smb_user_release(
mutex_exit(&user->u_mutex);
}
-void
-smb_user_post_tree(smb_user_t *user, smb_tree_t *tree)
-{
- SMB_USER_VALID(user);
- SMB_TREE_VALID(tree);
- ASSERT(tree->t_refcnt == 0);
- ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
- ASSERT(tree->t_user == user);
-
- smb_llist_post(&user->u_tree_list, tree, smb_tree_dealloc);
-}
-
-
-/*
- * Find a tree by tree-id.
- */
-smb_tree_t *
-smb_user_lookup_tree(
- smb_user_t *user,
- uint16_t tid)
-
-{
- smb_tree_t *tree;
-
- ASSERT(user);
- ASSERT(user->u_magic == SMB_USER_MAGIC);
-
- smb_llist_enter(&user->u_tree_list, RW_READER);
- tree = smb_llist_head(&user->u_tree_list);
-
- while (tree) {
- ASSERT(tree->t_magic == SMB_TREE_MAGIC);
- ASSERT(tree->t_user == user);
-
- if (tree->t_tid == tid) {
- if (smb_tree_hold(tree)) {
- smb_llist_exit(&user->u_tree_list);
- return (tree);
- } else {
- smb_llist_exit(&user->u_tree_list);
- return (NULL);
- }
- }
-
- tree = smb_llist_next(&user->u_tree_list, tree);
- }
-
- smb_llist_exit(&user->u_tree_list);
- return (NULL);
-}
-
-/*
- * Find the first connected tree that matches the specified sharename.
- * If the specified tree is NULL the search starts from the beginning of
- * the user's tree list. If a tree is provided the search starts just
- * after that tree.
- */
-smb_tree_t *
-smb_user_lookup_share(
- smb_user_t *user,
- const char *sharename,
- smb_tree_t *tree)
-{
- ASSERT(user);
- ASSERT(user->u_magic == SMB_USER_MAGIC);
- ASSERT(sharename);
-
- smb_llist_enter(&user->u_tree_list, RW_READER);
-
- if (tree) {
- ASSERT(tree->t_magic == SMB_TREE_MAGIC);
- ASSERT(tree->t_user == user);
- tree = smb_llist_next(&user->u_tree_list, tree);
- } else {
- tree = smb_llist_head(&user->u_tree_list);
- }
-
- while (tree) {
- ASSERT(tree->t_magic == SMB_TREE_MAGIC);
- ASSERT(tree->t_user == user);
- if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) {
- if (smb_tree_hold(tree)) {
- smb_llist_exit(&user->u_tree_list);
- return (tree);
- }
- }
- tree = smb_llist_next(&user->u_tree_list, tree);
- }
-
- smb_llist_exit(&user->u_tree_list);
- return (NULL);
-}
-
-/*
- * Find the first connected tree that matches the specified volume name.
- * If the specified tree is NULL the search starts from the beginning of
- * the user's tree list. If a tree is provided the search starts just
- * after that tree.
- */
-smb_tree_t *
-smb_user_lookup_volume(
- smb_user_t *user,
- const char *name,
- smb_tree_t *tree)
-{
- ASSERT(user);
- ASSERT(user->u_magic == SMB_USER_MAGIC);
- ASSERT(name);
-
- smb_llist_enter(&user->u_tree_list, RW_READER);
-
- if (tree) {
- ASSERT(tree->t_magic == SMB_TREE_MAGIC);
- ASSERT(tree->t_user == user);
- tree = smb_llist_next(&user->u_tree_list, tree);
- } else {
- tree = smb_llist_head(&user->u_tree_list);
- }
-
- while (tree) {
- ASSERT(tree->t_magic == SMB_TREE_MAGIC);
- ASSERT(tree->t_user == user);
-
- if (smb_strcasecmp(tree->t_volume, name, 0) == 0) {
- if (smb_tree_hold(tree)) {
- smb_llist_exit(&user->u_tree_list);
- return (tree);
- }
- }
-
- tree = smb_llist_next(&user->u_tree_list, tree);
- }
-
- smb_llist_exit(&user->u_tree_list);
- return (NULL);
-}
-
-/*
- * Disconnect all trees that match the specified client process-id.
- */
-void
-smb_user_close_pid(
- smb_user_t *user,
- uint16_t pid)
-{
- smb_tree_t *tree;
-
- ASSERT(user);
- ASSERT(user->u_magic == SMB_USER_MAGIC);
-
- tree = smb_user_get_tree(&user->u_tree_list, NULL);
- while (tree) {
- smb_tree_t *next;
- ASSERT(tree->t_user == user);
- smb_tree_close_pid(tree, pid);
- next = smb_user_get_tree(&user->u_tree_list, tree);
- smb_tree_release(tree);
- tree = next;
- }
-}
-
-/*
- * Disconnect all trees that this user has connected.
- */
-void
-smb_user_disconnect_trees(
- smb_user_t *user)
-{
- smb_tree_t *tree;
-
- ASSERT(user);
- ASSERT(user->u_magic == SMB_USER_MAGIC);
-
- tree = smb_user_get_tree(&user->u_tree_list, NULL);
- while (tree) {
- ASSERT(tree->t_user == user);
- smb_tree_disconnect(tree, B_TRUE);
- smb_tree_release(tree);
- tree = smb_user_get_tree(&user->u_tree_list, NULL);
- }
-}
-
-/*
- * Disconnect all trees that match the specified share name.
- */
-void
-smb_user_disconnect_share(
- smb_user_t *user,
- const char *sharename)
-{
- smb_tree_t *tree;
- smb_tree_t *next;
-
- ASSERT(user);
- ASSERT(user->u_magic == SMB_USER_MAGIC);
- ASSERT(user->u_refcnt);
-
- tree = smb_user_lookup_share(user, sharename, NULL);
- while (tree) {
- ASSERT(tree->t_magic == SMB_TREE_MAGIC);
- smb_session_cancel_requests(user->u_session, tree, NULL);
- smb_tree_disconnect(tree, B_TRUE);
- next = smb_user_lookup_share(user, sharename, tree);
- smb_tree_release(tree);
- tree = next;
- }
-}
-
-/*
- * Close a file by its unique id.
- */
-int
-smb_user_fclose(smb_user_t *user, uint32_t uniqid)
-{
- smb_llist_t *tree_list;
- smb_tree_t *tree;
- int rc = ENOENT;
-
- ASSERT(user);
- ASSERT(user->u_magic == SMB_USER_MAGIC);
-
- tree_list = &user->u_tree_list;
- ASSERT(tree_list);
-
- smb_llist_enter(tree_list, RW_READER);
- tree = smb_llist_head(tree_list);
-
- while ((tree != NULL) && (rc == ENOENT)) {
- ASSERT(tree->t_user == user);
-
- if (smb_tree_hold(tree)) {
- rc = smb_tree_fclose(tree, uniqid);
- smb_tree_release(tree);
- }
-
- tree = smb_llist_next(tree_list, tree);
- }
-
- smb_llist_exit(tree_list);
- return (rc);
-}
-
/*
* Determine whether or not the user is an administrator.
* Members of the administrators group have administrative rights.
@@ -688,9 +448,7 @@ smb_user_namecmp(smb_user_t *user, const char *name)
int
smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
{
- smb_tree_t *tree;
- smb_tree_t *next;
- int rc;
+ int rc = 0;
ASSERT(user);
ASSERT(user->u_magic == SMB_USER_MAGIC);
@@ -698,21 +456,6 @@ smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
return (smb_user_enum_private(user, svcenum));
- tree = smb_user_get_tree(&user->u_tree_list, NULL);
- while (tree) {
- ASSERT(tree->t_user == user);
-
- rc = smb_tree_enum(tree, svcenum);
- if (rc != 0) {
- smb_tree_release(tree);
- break;
- }
-
- next = smb_user_get_tree(&user->u_tree_list, tree);
- smb_tree_release(tree);
- tree = next;
- }
-
return (rc);
}
@@ -769,8 +512,6 @@ smb_user_delete(void *arg)
user->u_magic = (uint32_t)~SMB_USER_MAGIC;
mutex_destroy(&user->u_mutex);
- smb_llist_destructor(&user->u_tree_list);
- smb_idpool_destructor(&user->u_tid_pool);
if (user->u_cred)
crfree(user->u_cred);
if (user->u_privcred)
@@ -780,43 +521,6 @@ smb_user_delete(void *arg)
kmem_cache_free(user->u_server->si_cache_user, user);
}
-/*
- * Get the next connected tree in the list. A reference is taken on
- * the tree, which can be released later with smb_tree_release().
- *
- * If the specified tree is NULL the search starts from the beginning of
- * the tree list. If a tree is provided the search starts just after
- * that tree.
- *
- * Returns NULL if there are no connected trees in the list.
- */
-static smb_tree_t *
-smb_user_get_tree(
- smb_llist_t *tree_list,
- smb_tree_t *tree)
-{
- ASSERT(tree_list);
-
- smb_llist_enter(tree_list, RW_READER);
-
- if (tree) {
- ASSERT(tree->t_magic == SMB_TREE_MAGIC);
- tree = smb_llist_next(tree_list, tree);
- } else {
- tree = smb_llist_head(tree_list);
- }
-
- while (tree) {
- if (smb_tree_hold(tree))
- break;
-
- tree = smb_llist_next(tree_list, tree);
- }
-
- smb_llist_exit(tree_list);
- return (tree);
-}
-
cred_t *
smb_user_getcred(smb_user_t *user)
{
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
index f2de265176..ad7402fd80 100644
--- a/usr/src/uts/common/smbsrv/smb_kproto.h
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -521,6 +521,15 @@ void smb_session_disconnect_from_share(smb_llist_t *, char *);
smb_user_t *smb_session_dup_user(smb_session_t *, char *, char *);
smb_user_t *smb_session_lookup_uid(smb_session_t *, uint16_t);
void smb_session_post_user(smb_session_t *, smb_user_t *);
+void smb_session_post_tree(smb_session_t *, smb_tree_t *);
+smb_tree_t *smb_session_lookup_tree(smb_session_t *, uint16_t);
+smb_tree_t *smb_session_lookup_share(smb_session_t *, const char *,
+ smb_tree_t *);
+smb_tree_t *smb_session_lookup_volume(smb_session_t *, const char *,
+ smb_tree_t *);
+void smb_session_close_pid(smb_session_t *, uint16_t);
+void smb_session_disconnect_owned_trees(smb_session_t *, smb_user_t *);
+void smb_session_disconnect_trees(smb_session_t *);
void smb_session_disconnect_share(smb_session_t *, const char *);
void smb_session_getclient(smb_session_t *, char *, size_t);
boolean_t smb_session_isclient(smb_session_t *, const char *);
@@ -539,10 +548,10 @@ void smb_request_free(smb_request_t *);
/*
* ofile functions (file smb_ofile.c)
*/
-smb_ofile_t *smb_ofile_lookup_by_fid(smb_tree_t *, uint16_t);
+smb_ofile_t *smb_ofile_lookup_by_fid(smb_request_t *, uint16_t);
smb_ofile_t *smb_ofile_lookup_by_uniqid(smb_tree_t *, uint32_t);
boolean_t smb_ofile_disallow_fclose(smb_ofile_t *);
-smb_ofile_t *smb_ofile_open(smb_tree_t *, smb_node_t *, uint16_t,
+smb_ofile_t *smb_ofile_open(smb_request_t *, smb_node_t *, uint16_t,
smb_arg_open_t *, uint16_t, uint32_t, smb_error_t *);
void smb_ofile_close(smb_ofile_t *, int32_t);
void smb_ofile_delete(void *);
@@ -603,18 +612,11 @@ smb_user_t *smb_user_login(smb_session_t *, cred_t *,
smb_user_t *smb_user_dup(smb_user_t *);
void smb_user_logoff(smb_user_t *);
void smb_user_delete(void *);
-void smb_user_post_tree(smb_user_t *, smb_tree_t *);
-smb_tree_t *smb_user_lookup_tree(smb_user_t *, uint16_t);
-smb_tree_t *smb_user_lookup_share(smb_user_t *, const char *, smb_tree_t *);
-smb_tree_t *smb_user_lookup_volume(smb_user_t *, const char *, smb_tree_t *);
boolean_t smb_user_is_admin(smb_user_t *);
boolean_t smb_user_namecmp(smb_user_t *, const char *);
int smb_user_enum(smb_user_t *, smb_svcenum_t *);
-void smb_user_close_pid(smb_user_t *, uint16_t);
-void smb_user_disconnect_trees(smb_user_t *user);
-void smb_user_disconnect_share(smb_user_t *, const char *);
-int smb_user_fclose(smb_user_t *, uint32_t);
boolean_t smb_user_hold(smb_user_t *);
+void smb_user_hold_internal(smb_user_t *);
void smb_user_release(smb_user_t *);
cred_t *smb_user_getcred(smb_user_t *);
cred_t *smb_user_getprivcred(smb_user_t *);
@@ -637,7 +639,7 @@ int smb_tree_enum(smb_tree_t *, smb_svcenum_t *);
int smb_tree_fclose(smb_tree_t *, uint32_t);
boolean_t smb_tree_hold(smb_tree_t *);
void smb_tree_release(smb_tree_t *);
-smb_odir_t *smb_tree_lookup_odir(smb_tree_t *, uint16_t);
+smb_odir_t *smb_tree_lookup_odir(smb_request_t *, uint16_t);
boolean_t smb_tree_is_connected(smb_tree_t *);
#define SMB_TREE_GET_TID(tree) ((tree)->t_tid)
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index 493e7130a7..2c5d102f62 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -908,7 +908,9 @@ typedef struct smb_session {
smb_slist_t s_req_list;
smb_llist_t s_xa_list;
smb_llist_t s_user_list;
+ smb_llist_t s_tree_list;
smb_idpool_t s_uid_pool;
+ smb_idpool_t s_tid_pool;
smb_txlst_t s_txlst;
volatile uint32_t s_tree_cnt;
@@ -975,9 +977,6 @@ typedef struct smb_user {
cred_t *u_cred;
cred_t *u_privcred;
- smb_llist_t u_tree_list;
- smb_idpool_t u_tid_pool;
-
uint32_t u_refcnt;
uint32_t u_flags;
uint32_t u_privileges;
@@ -1028,7 +1027,11 @@ typedef struct smb_tree {
struct smb_server *t_server;
smb_session_t *t_session;
- smb_user_t *t_user;
+ /*
+ * user whose uid was in the tree connect message
+ * ("owner" in MS-CIFS parlance, see section 2.2.1.6 definition of FID)
+ */
+ smb_user_t *t_owner;
smb_node_t *t_snode;
smb_llist_t t_ofile_list;
@@ -1259,6 +1262,7 @@ typedef struct smb_odir {
list_node_t d_lnd;
smb_odir_state_t d_state;
smb_session_t *d_session;
+ smb_user_t *d_user;
smb_tree_t *d_tree;
smb_node_t *d_dnode;
cred_t *d_cred;