Print this page
NEX-18761 panic in smb_ofile_free with vdbench
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5273 SMB 3 Encryption
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-6858 Non-admin users unable to mount CIFS shares
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6276 SMB sparse file support
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5737 mutex_enter: bad mutex in smb2 causes panic in mutex_vector_enter
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-3553 SMB2/3 durable handles
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-5537 Want reference counts for users, trees...
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-4313 want iops, bandwidth, and latency kstats for smb
Portions contributed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-3863 Would like an SMB share property to enable/disable quotas
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-3441 CLONE - PORT NEX-3398 Restore SMB map/unmap upcall feature
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-74 Process oplock breaks as session requests (part two)
SMB-50 User-mode SMB server
Includes work by these authors:
Thomas Keiser <thomas.keiser@nexenta.com>
Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (use zone_kcred())
SUP-694 panic on bad mutex in smb_event_wait()
SMB-65 SMB server in non-global zones (data structure changes)
Many things move to the smb_server_t object, and
many functions gain an sv arg (which server).
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
re #13470 rb4432 Sync some SMB differences from illumos
re #6813 rb1757 port 2976 Child folder visibility through shares
re #6812 rb1753 backport illumos 1604 smbd print_enable doesn't really work
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_tree.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_tree.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
25 25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 26 */
27 27
28 28 /*
29 29 * General Structures Layout
30 30 * -------------------------
31 31 *
32 32 * This is a simplified diagram showing the relationship between most of the
33 33 * main structures.
34 34 *
35 35 * +-------------------+
36 36 * | SMB_INFO |
37 37 * +-------------------+
38 38 * |
39 39 * |
40 40 * v
41 41 * +-------------------+ +-------------------+ +-------------------+
42 42 * | SESSION |<----->| SESSION |......| SESSION |
43 43 * +-------------------+ +-------------------+ +-------------------+
44 44 * | |
45 45 * | |
46 46 * | v
47 47 * | +-------------------+ +-------------------+ +-------------------+
48 48 * | | USER |<--->| USER |...| USER |
49 49 * | +-------------------+ +-------------------+ +-------------------+
50 50 * |
51 51 * |
52 52 * v
53 53 * +-------------------+ +-------------------+ +-------------------+
54 54 * | TREE |<----->| TREE |......| TREE |
55 55 * +-------------------+ +-------------------+ +-------------------+
56 56 * | |
57 57 * | |
58 58 * | v
59 59 * | +-------+ +-------+ +-------+
60 60 * | | OFILE |<----->| OFILE |......| OFILE |
61 61 * | +-------+ +-------+ +-------+
62 62 * |
63 63 * |
64 64 * v
65 65 * +-------+ +------+ +------+
66 66 * | ODIR |<----->| ODIR |......| ODIR |
67 67 * +-------+ +------+ +------+
68 68 *
69 69 *
70 70 * Tree State Machine
71 71 * ------------------
72 72 *
73 73 * +-----------------------------+ T0
74 74 * | SMB_TREE_STATE_CONNECTED |<----------- Creation/Allocation
75 75 * +-----------------------------+
76 76 * |
77 77 * | T1
78 78 * |
79 79 * v
80 80 * +------------------------------+
81 81 * | SMB_TREE_STATE_DISCONNECTING |
82 82 * +------------------------------+
83 83 * |
84 84 * | T2
85 85 * |
86 86 * v
87 87 * +-----------------------------+ T3
88 88 * | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free
89 89 * +-----------------------------+
90 90 *
91 91 * SMB_TREE_STATE_CONNECTED
92 92 *
93 93 * While in this state:
94 94 * - The tree is queued in the list of trees of its user.
95 95 * - References will be given out if the tree is looked up.
96 96 * - Files under that tree can be accessed.
97 97 *
98 98 * SMB_TREE_STATE_DISCONNECTING
99 99 *
100 100 * While in this state:
101 101 * - The tree is queued in the list of trees of its user.
102 102 * - References will not be given out if the tree is looked up.
103 103 * - The files and directories open under the tree are being closed.
104 104 * - The resources associated with the tree remain.
105 105 *
106 106 * SMB_TREE_STATE_DISCONNECTED
107 107 *
108 108 * While in this state:
109 109 * - The tree is queued in the list of trees of its user.
110 110 * - References will not be given out if the tree is looked up.
111 111 * - The tree has no more files and directories opened.
112 112 * - The resources associated with the tree remain.
113 113 *
114 114 * Transition T0
|
↓ open down ↓ |
80 lines elided |
↑ open up ↑ |
115 115 *
116 116 * This transition occurs in smb_tree_connect(). A new tree is created and
117 117 * added to the list of trees of a user.
118 118 *
119 119 * Transition T1
120 120 *
121 121 * This transition occurs in smb_tree_disconnect().
122 122 *
123 123 * Transition T2
124 124 *
125 + * This transition occurs in smb_tree_disconnect()
126 + *
127 + * Transition T3
128 + *
125 129 * This transition occurs in smb_tree_release(). The resources associated
126 130 * with the tree are freed as well as the tree structure. For the transition
127 - * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and
128 - * the reference count be zero.
131 + * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED and the
132 + * reference count must be zero.
129 133 *
130 134 * Comments
131 135 * --------
132 136 *
133 137 * The state machine of the tree structures is controlled by 3 elements:
134 138 * - The list of trees of the user it belongs to.
135 139 * - The mutex embedded in the structure itself.
136 140 * - The reference count.
137 141 *
138 142 * There's a mutex embedded in the tree structure used to protect its fields
139 143 * and there's a lock embedded in the list of trees of a user. To
140 144 * increment or to decrement the reference count the mutex must be entered.
141 145 * To insert the tree into the list of trees of the user and to remove
142 146 * the tree from it, the lock must be entered in RW_WRITER mode.
143 147 *
144 148 * Rules of access to a tree structure:
145 149 *
146 150 * 1) In order to avoid deadlocks, when both (mutex and lock of the user
147 - * list) have to be entered, the lock must be entered first.
151 + * list) have to be entered, the lock must be entered first. Additionally,
152 + * when both the (mutex and lock of the ofile list) have to be entered,
153 + * the mutex must be entered first. However, the ofile list lock must NOT
154 + * be dropped while the mutex is held in such a way that the ofile deleteq
155 + * is flushed.
148 156 *
149 157 * 2) All actions applied to a tree require a reference count.
150 158 *
151 159 * 3) There are 2 ways of getting a reference count: when a tree is
152 160 * connected and when a tree is looked up.
153 161 *
154 162 * It should be noted that the reference count of a tree registers the
155 163 * number of references to the tree in other structures (such as an smb
156 164 * request). The reference count is not incremented in these 2 instances:
157 165 *
158 166 * 1) The tree is connected. An tree is anchored by its state. If there's
159 167 * no activity involving a tree currently connected, the reference
160 168 * count of that tree is zero.
161 169 *
162 170 * 2) The tree is queued in the list of trees of the user. The fact of
163 171 * being queued in that list is NOT registered by incrementing the
164 172 * reference count.
165 173 */
166 174
167 175 #include <sys/refstr_impl.h>
168 176 #include <smbsrv/smb_kproto.h>
|
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
169 177 #include <smbsrv/smb_ktypes.h>
170 178 #include <smbsrv/smb_fsops.h>
171 179 #include <smbsrv/smb_share.h>
172 180
173 181 int smb_tcon_mute = 0;
174 182
175 183 uint32_t smb_tree_connect_core(smb_request_t *);
176 184 uint32_t smb_tree_connect_disk(smb_request_t *, smb_arg_tcon_t *);
177 185 uint32_t smb_tree_connect_printq(smb_request_t *, smb_arg_tcon_t *);
178 186 uint32_t smb_tree_connect_ipc(smb_request_t *, smb_arg_tcon_t *);
179 -static smb_tree_t *smb_tree_alloc(smb_request_t *, const smb_kshare_t *,
180 - smb_node_t *, uint32_t, uint32_t);
187 +static void smb_tree_dealloc(void *);
181 188 static boolean_t smb_tree_is_connected_locked(smb_tree_t *);
182 -static boolean_t smb_tree_is_disconnected(smb_tree_t *);
183 189 static char *smb_tree_get_sharename(char *);
184 190 static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *);
185 191 static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
186 192 static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *);
187 193 static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
188 -static void smb_tree_close_odirs(smb_tree_t *, uint16_t);
189 -static smb_ofile_t *smb_tree_get_ofile(smb_tree_t *, smb_ofile_t *);
190 -static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *);
194 +static void smb_tree_close_odirs(smb_tree_t *, uint32_t);
191 195 static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int);
192 196 static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *);
193 197 static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *);
194 198 static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *);
195 199 static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
196 200
197 201 uint32_t
198 202 smb_tree_connect(smb_request_t *sr)
199 203 {
200 204 smb_server_t *sv = sr->sr_server;
201 205 uint32_t status;
202 206
203 207 if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) {
204 208 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
205 209 }
206 210
207 211 status = smb_tree_connect_core(sr);
208 212 smb_threshold_exit(&sv->sv_tcon_ct);
209 213 return (status);
210 214 }
211 215
212 216 /*
213 217 * Lookup the share name dispatch the appropriate stype handler.
214 218 * Share names are case insensitive so we map the share name to
215 219 * lower-case as a convenience for internal processing.
216 220 *
217 221 * Valid service values are:
218 222 * A: Disk share
219 223 * LPT1: Printer
220 224 * IPC Named pipe (IPC$ is reserved as the named pipe share).
221 225 * COMM Communications device
222 226 * ????? Any type of device (wildcard)
223 227 */
224 228 uint32_t
225 229 smb_tree_connect_core(smb_request_t *sr)
226 230 {
227 231 smb_arg_tcon_t *tcon = &sr->sr_tcon;
228 232 smb_kshare_t *si;
229 233 char *name;
230 234 uint32_t status;
231 235
232 236 (void) smb_strlwr(tcon->path);
233 237
234 238 if ((name = smb_tree_get_sharename(tcon->path)) == NULL) {
235 239 smb_tree_log(sr, tcon->path, "invalid UNC path");
236 240 return (NT_STATUS_BAD_NETWORK_NAME);
237 241 }
238 242
239 243 si = smb_kshare_lookup(sr->sr_server, name);
240 244 if (si == NULL) {
241 245 smb_tree_log(sr, name, "share not found");
242 246 return (NT_STATUS_BAD_NETWORK_NAME);
243 247 }
244 248
|
↓ open down ↓ |
44 lines elided |
↑ open up ↑ |
245 249 if (!strcasecmp(SMB_SHARE_PRINT, name)) {
246 250 smb_kshare_release(sr->sr_server, si);
247 251 smb_tree_log(sr, name, "access not permitted");
248 252 return (NT_STATUS_ACCESS_DENIED);
249 253 }
250 254
251 255 /* NB: name points into tcon->path - don't free it. */
252 256 tcon->name = name;
253 257 sr->sr_tcon.si = si;
254 258
259 + /*
260 + * [MS-SMB2] 3.3.5.7 Receiving an SMB2 TREE_CONNECT Request
261 + *
262 + * If we support 3.x, RejectUnencryptedAccess is TRUE,
263 + * if Tcon.EncryptData is TRUE or global EncryptData is TRUE,
264 + * and the connection doesn't support encryption,
265 + * return ACCESS_DENIED.
266 + *
267 + * If RejectUnencryptedAccess is TRUE, we force max_protocol
268 + * to at least 3.0. Additionally, if the tree requires encryption,
269 + * we don't care what we support, we still enforce encryption.
270 + */
271 + if ((sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED ||
272 + si->shr_encrypt == SMB_CONFIG_REQUIRED) &&
273 + (sr->session->srv_cap & SMB2_CAP_ENCRYPTION) == 0) {
274 + status = NT_STATUS_ACCESS_DENIED;
275 + goto out;
276 + }
277 +
255 278 switch (si->shr_type & STYPE_MASK) {
256 279 case STYPE_DISKTREE:
257 280 status = smb_tree_connect_disk(sr, &sr->sr_tcon);
258 281 break;
259 282 case STYPE_IPC:
260 283 status = smb_tree_connect_ipc(sr, &sr->sr_tcon);
261 284 break;
262 285 case STYPE_PRINTQ:
263 286 status = smb_tree_connect_printq(sr, &sr->sr_tcon);
264 287 break;
265 288 default:
266 289 status = NT_STATUS_BAD_DEVICE_TYPE;
267 290 break;
268 291 }
269 292
270 - smb_kshare_release(sr->sr_server, si);
293 +out:
294 + /*
295 + * On return from smb_tree_connect_* sr->tid_tree is filled in
296 + * and valid for all share types. We can't call smb_kshare_release
297 + * until we disconnect the tree or we will invalidate the reference
298 + * we have here.
299 + */
300 + if (sr->tid_tree != NULL) {
301 + sr->tid_tree->t_kshare = si;
302 + } else {
303 + smb_kshare_release(sr->sr_server, si);
304 + }
305 +
271 306 sr->sr_tcon.si = NULL;
272 307
273 308 return (status);
274 309 }
275 310
276 311 /*
277 312 * Disconnect a tree.
313 + *
314 + * The "do_exec" arg is obsolete and ignored.
278 315 */
279 316 void
280 317 smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec)
281 318 {
319 + _NOTE(ARGUNUSED(do_exec))
282 320 smb_shr_execinfo_t execinfo;
283 321
284 322 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
285 323
286 324 mutex_enter(&tree->t_mutex);
287 325 ASSERT(tree->t_refcnt);
288 326
289 - if (smb_tree_is_connected_locked(tree)) {
290 - /*
291 - * Indicate that the disconnect process has started.
292 - */
293 - tree->t_state = SMB_TREE_STATE_DISCONNECTING;
327 + if (!smb_tree_is_connected_locked(tree)) {
294 328 mutex_exit(&tree->t_mutex);
295 -
296 - if (do_exec) {
297 - /*
298 - * The files opened under this tree are closed.
299 - */
300 - smb_ofile_close_all(tree);
301 - /*
302 - * The directories opened under this tree are closed.
303 - */
304 - smb_tree_close_odirs(tree, 0);
305 - }
306 -
307 - mutex_enter(&tree->t_mutex);
308 - tree->t_state = SMB_TREE_STATE_DISCONNECTED;
309 - smb_server_dec_trees(tree->t_server);
329 + return;
310 330 }
311 331
332 + /*
333 + * Indicate that the disconnect process has started.
334 + */
335 + tree->t_state = SMB_TREE_STATE_DISCONNECTING;
312 336 mutex_exit(&tree->t_mutex);
313 337
314 - if (do_exec && (tree->t_state == SMB_TREE_STATE_DISCONNECTED) &&
315 - (tree->t_execflags & SMB_EXEC_UNMAP)) {
338 + /*
339 + * The files opened under this tree are closed.
340 + */
341 + smb_ofile_close_all(tree, 0);
342 + /*
343 + * The directories opened under this tree are closed.
344 + */
345 + smb_tree_close_odirs(tree, 0);
316 346
347 + if ((tree->t_execflags & SMB_EXEC_UNMAP) != 0) {
317 348 smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP);
318 349 (void) smb_kshare_exec(tree->t_server, &execinfo);
319 350 }
320 351 }
321 352
322 353 /*
323 354 * Take a reference on a tree.
324 355 */
325 356 boolean_t
326 357 smb_tree_hold(
327 358 smb_tree_t *tree)
328 359 {
329 360 SMB_TREE_VALID(tree);
330 361
331 362 mutex_enter(&tree->t_mutex);
332 363
333 364 if (smb_tree_is_connected_locked(tree)) {
334 365 tree->t_refcnt++;
335 366 mutex_exit(&tree->t_mutex);
336 367 return (B_TRUE);
337 368 }
338 369
339 370 mutex_exit(&tree->t_mutex);
340 371 return (B_FALSE);
341 372 }
342 373
343 374 /*
344 375 * Bump the hold count regardless of the tree state. This is used in
345 376 * some internal code paths where we've already checked that we had a
346 377 * valid tree connection, and don't want to deal with the possiblity
347 378 * that the tree state might have changed to disconnecting after our
348 379 * original hold was taken. It's correct to continue processing a
349 380 * request even when new requests cannot lookup that tree anymore.
350 381 */
351 382 void
352 383 smb_tree_hold_internal(
353 384 smb_tree_t *tree)
354 385 {
355 386 SMB_TREE_VALID(tree);
356 387
357 388 mutex_enter(&tree->t_mutex);
358 389 tree->t_refcnt++;
359 390 mutex_exit(&tree->t_mutex);
360 391 }
361 392
362 393 /*
363 394 * Release a reference on a tree. If the tree is disconnected and the
|
↓ open down ↓ |
37 lines elided |
↑ open up ↑ |
364 395 * reference count falls to zero, post the object for deletion.
365 396 * Object deletion is deferred to avoid modifying a list while an
366 397 * iteration may be in progress.
367 398 */
368 399 void
369 400 smb_tree_release(
370 401 smb_tree_t *tree)
371 402 {
372 403 SMB_TREE_VALID(tree);
373 404
374 - mutex_enter(&tree->t_mutex);
375 - ASSERT(tree->t_refcnt);
376 - tree->t_refcnt--;
377 -
378 405 /* flush the ofile and odir lists' delete queues */
379 406 smb_llist_flush(&tree->t_ofile_list);
380 407 smb_llist_flush(&tree->t_odir_list);
381 408
382 - if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0))
383 - smb_session_post_tree(tree->t_session, tree);
409 + mutex_enter(&tree->t_mutex);
410 + ASSERT(tree->t_refcnt);
411 + tree->t_refcnt--;
384 412
413 + switch (tree->t_state) {
414 + case SMB_TREE_STATE_DISCONNECTING:
415 + if (tree->t_refcnt == 0) {
416 + smb_session_t *ssn = tree->t_session;
417 + tree->t_state = SMB_TREE_STATE_DISCONNECTED;
418 + smb_llist_post(&ssn->s_tree_list, tree,
419 + smb_tree_dealloc);
420 + }
421 + break;
422 + case SMB_TREE_STATE_CONNECTED:
423 + break;
424 + default:
425 + ASSERT(0);
426 + break;
427 + }
428 +
385 429 mutex_exit(&tree->t_mutex);
386 430 }
387 431
388 -void
389 -smb_tree_post_ofile(smb_tree_t *tree, smb_ofile_t *of)
390 -{
391 - SMB_TREE_VALID(tree);
392 - SMB_OFILE_VALID(of);
393 - ASSERT(of->f_refcnt == 0);
394 - ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED);
395 - ASSERT(of->f_tree == tree);
396 -
397 - smb_llist_post(&tree->t_ofile_list, of, smb_ofile_delete);
398 -}
399 -
400 -void
401 -smb_tree_post_odir(smb_tree_t *tree, smb_odir_t *od)
402 -{
403 - SMB_TREE_VALID(tree);
404 - SMB_ODIR_VALID(od);
405 - ASSERT(od->d_refcnt == 0);
406 - ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
407 - ASSERT(od->d_tree == tree);
408 -
409 - smb_llist_post(&tree->t_odir_list, od, smb_odir_delete);
410 -}
411 -
412 432 /*
413 433 * Close ofiles and odirs that match pid.
414 434 */
415 435 void
416 436 smb_tree_close_pid(
417 437 smb_tree_t *tree,
418 438 uint32_t pid)
419 439 {
420 440 ASSERT(tree);
421 441 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
422 442
423 - smb_ofile_close_all_by_pid(tree, pid);
443 + smb_ofile_close_all(tree, pid);
424 444 smb_tree_close_odirs(tree, pid);
425 445 }
426 446
427 447 /*
428 448 * Check whether or not a tree supports the features identified by flags.
429 449 */
430 450 boolean_t
431 451 smb_tree_has_feature(smb_tree_t *tree, uint32_t flags)
432 452 {
433 453 ASSERT(tree);
434 454 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
435 455
436 456 return ((tree->t_flags & flags) == flags);
437 457 }
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
438 458
439 459 /*
440 460 * If the enumeration request is for tree data, handle the request
441 461 * here. Otherwise, pass it on to the ofiles.
442 462 *
443 463 * This function should be called with a hold on the tree.
444 464 */
445 465 int
446 466 smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
447 467 {
468 + smb_llist_t *of_list;
448 469 smb_ofile_t *of;
449 - smb_ofile_t *next;
450 470 int rc = 0;
451 471
452 - ASSERT(tree);
453 - ASSERT(tree->t_magic == SMB_TREE_MAGIC);
454 -
455 472 if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE)
456 473 return (smb_tree_enum_private(tree, svcenum));
457 474
458 - of = smb_tree_get_ofile(tree, NULL);
459 - while (of) {
460 - ASSERT(of->f_tree == tree);
475 + of_list = &tree->t_ofile_list;
476 + smb_llist_enter(of_list, RW_READER);
461 477
462 - rc = smb_ofile_enum(of, svcenum);
463 - if (rc != 0) {
478 + of = smb_llist_head(of_list);
479 + while (of) {
480 + if (smb_ofile_hold(of)) {
481 + rc = smb_ofile_enum(of, svcenum);
464 482 smb_ofile_release(of);
465 - break;
466 483 }
467 -
468 - next = smb_tree_get_ofile(tree, of);
469 - smb_ofile_release(of);
470 - of = next;
484 + if (rc != 0)
485 + break;
486 + of = smb_llist_next(of_list, of);
471 487 }
472 488
489 + smb_llist_exit(of_list);
490 +
473 491 return (rc);
474 492 }
475 493
476 494 /*
477 495 * Close a file by its unique id.
478 496 */
479 497 int
480 498 smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid)
481 499 {
482 500 smb_ofile_t *of;
483 501
484 502 ASSERT(tree);
485 503 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
486 504
505 + /*
506 + * Note that ORPHANED ofiles aren't fclosable, as they have
507 + * no session, user, or tree by which they might be found.
508 + * They will eventually expire.
509 + */
487 510 if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL)
488 511 return (ENOENT);
489 512
490 513 if (smb_ofile_disallow_fclose(of)) {
491 514 smb_ofile_release(of);
492 515 return (EACCES);
493 516 }
494 517
495 518 smb_ofile_close(of, 0);
496 519 smb_ofile_release(of);
497 520 return (0);
498 521 }
499 522
500 523 /* *************************** Static Functions ***************************** */
501 524
502 525 #define SHARES_DIR ".zfs/shares/"
503 526
504 527 /*
505 528 * Calculates permissions given by the share's ACL to the
506 529 * user in the passed request. The default is full access.
507 530 * If any error occurs, full access is granted.
508 531 *
509 532 * Using the vnode of the share path find the root directory
510 533 * of the mounted file system. Then look to see if there is a
511 534 * .zfs/shares directory and if there is, lookup the file with
512 535 * the same name as the share name in it. The ACL set for this
513 536 * file is the share's ACL which is used for access check here.
514 537 */
515 538 static uint32_t
516 539 smb_tree_acl_access(smb_request_t *sr, const smb_kshare_t *si, vnode_t *pathvp)
517 540 {
518 541 smb_user_t *user;
519 542 cred_t *cred;
520 543 int rc;
521 544 vfs_t *vfsp;
522 545 vnode_t *root = NULL;
523 546 vnode_t *sharevp = NULL;
524 547 char *sharepath;
525 548 struct pathname pnp;
526 549 size_t size;
527 550 uint32_t access;
528 551
529 552 user = sr->uid_user;
530 553 cred = user->u_cred;
531 554 access = ACE_ALL_PERMS;
532 555
533 556 if (si->shr_flags & SMB_SHRF_AUTOHOME) {
534 557 /*
535 558 * An autohome share owner gets full access to the share.
536 559 * Everyone else is denied access.
537 560 */
538 561 if (si->shr_uid != crgetuid(cred))
539 562 access = 0;
540 563
541 564 return (access);
542 565 }
543 566
544 567 /*
545 568 * The hold on 'root' is released by the lookuppnvp() that follows
546 569 */
547 570 vfsp = pathvp->v_vfsp;
548 571 if (vfsp != NULL)
549 572 rc = VFS_ROOT(vfsp, &root);
550 573 else
551 574 rc = ENOENT;
552 575
553 576 if (rc != 0)
554 577 return (access);
555 578
556 579
557 580 size = sizeof (SHARES_DIR) + strlen(si->shr_name) + 1;
558 581 sharepath = smb_srm_alloc(sr, size);
559 582 (void) snprintf(sharepath, size, "%s%s", SHARES_DIR, si->shr_name);
560 583
561 584 pn_alloc(&pnp);
562 585 (void) pn_set(&pnp, sharepath);
563 586 rc = lookuppnvp(&pnp, NULL, NO_FOLLOW, NULL, &sharevp, rootdir, root,
564 587 zone_kcred());
565 588 pn_free(&pnp);
566 589
567 590 /*
568 591 * Now get the effective access value based on cred and ACL values.
569 592 */
570 593 if (rc == 0) {
571 594 smb_vop_eaccess(sharevp, (int *)&access, V_ACE_MASK, NULL,
572 595 cred);
573 596 VN_RELE(sharevp);
574 597 }
575 598
576 599 return (access);
577 600 }
578 601
579 602 /*
580 603 * Performs the following access checks for a disk share:
581 604 *
582 605 * - No IPC/anonymous user is allowed
583 606 *
584 607 * - If user is Guest, guestok property of the share should be
585 608 * enabled
586 609 *
587 610 * - If this is an Admin share, the user should have administrative
588 611 * privileges
589 612 *
590 613 * - Host based access control lists
591 614 *
592 615 * - Share ACL
593 616 *
594 617 * Returns the access allowed or 0 if access is denied.
595 618 */
596 619 static uint32_t
597 620 smb_tree_chkaccess(smb_request_t *sr, smb_kshare_t *shr, vnode_t *vp)
598 621 {
599 622 smb_user_t *user = sr->uid_user;
600 623 char *sharename = shr->shr_name;
601 624 uint32_t host_access;
602 625 uint32_t acl_access;
603 626 uint32_t access;
604 627
605 628 if (user->u_flags & SMB_USER_FLAG_ANON) {
606 629 smb_tree_log(sr, sharename, "access denied: IPC only");
607 630 return (0);
608 631 }
609 632
610 633 if ((user->u_flags & SMB_USER_FLAG_GUEST) &&
611 634 ((shr->shr_flags & SMB_SHRF_GUEST_OK) == 0)) {
612 635 smb_tree_log(sr, sharename, "access denied: guest disabled");
613 636 return (0);
614 637 }
615 638
616 639 if ((shr->shr_flags & SMB_SHRF_ADMIN) && !smb_user_is_admin(user)) {
617 640 smb_tree_log(sr, sharename, "access denied: not admin");
618 641 return (0);
619 642 }
620 643
621 644 host_access = smb_kshare_hostaccess(shr, sr->session);
622 645 if ((host_access & ACE_ALL_PERMS) == 0) {
623 646 smb_tree_log(sr, sharename, "access denied: host access");
624 647 return (0);
625 648 }
626 649
627 650 acl_access = smb_tree_acl_access(sr, shr, vp);
628 651 if ((acl_access & ACE_ALL_PERMS) == 0) {
629 652 smb_tree_log(sr, sharename, "access denied: share ACL");
630 653 return (0);
631 654 }
|
↓ open down ↓ |
135 lines elided |
↑ open up ↑ |
632 655
633 656 access = host_access & acl_access;
634 657 if ((access & ACE_ALL_PERMS) == 0) {
635 658 smb_tree_log(sr, sharename, "access denied");
636 659 return (0);
637 660 }
638 661
639 662 return (access);
640 663 }
641 664
665 +/* How long should tree connect wait for DH import to complete? */
666 +int smb_tcon_import_wait = 20; /* sec. */
667 +
642 668 /*
643 669 * Connect a share for use with files and directories.
644 670 */
645 671 uint32_t
646 672 smb_tree_connect_disk(smb_request_t *sr, smb_arg_tcon_t *tcon)
647 673 {
648 674 char *sharename = tcon->path;
649 675 const char *any = "?????";
650 676 smb_user_t *user = sr->uid_user;
651 - smb_node_t *dnode = NULL;
652 677 smb_node_t *snode = NULL;
653 - smb_kshare_t *si = tcon->si;
678 + smb_kshare_t *si = tcon->si;
654 679 char *service = tcon->service;
655 - char last_component[MAXNAMELEN];
656 680 smb_tree_t *tree;
657 681 int rc;
658 682 uint32_t access;
659 683 smb_shr_execinfo_t execinfo;
684 + clock_t time;
660 685
661 686 ASSERT(user);
662 687 ASSERT(user->u_cred);
663 688
664 689 if (service != NULL &&
665 690 strcmp(service, any) != 0 &&
666 691 strcasecmp(service, "A:") != 0) {
667 692 smb_tree_log(sr, sharename, "invalid service (%s)", service);
668 693 return (NT_STATUS_BAD_DEVICE_TYPE);
669 694 }
670 695
671 696 /*
672 697 * Check that the shared directory exists.
673 698 */
674 - rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
675 - last_component);
676 - if (rc == 0) {
677 - rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
678 - sr->sr_server->si_root_smb_node, dnode, last_component,
679 - &snode);
680 -
681 - smb_node_release(dnode);
682 - }
683 -
684 - if (rc) {
685 - if (snode)
686 - smb_node_release(snode);
687 -
699 + snode = si->shr_root_node;
700 + if (snode == NULL) {
688 701 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
689 702 return (NT_STATUS_BAD_NETWORK_NAME);
690 703 }
691 704
692 705 if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
693 - smb_node_release(snode);
694 706 return (NT_STATUS_ACCESS_DENIED);
695 707 }
696 708
697 709 /*
710 + * Wait for DH import of persistent handles to finish.
711 + * If we timeout, it's not clear what status to return,
712 + * but as the share is not really availale yet, let's
713 + * return the status for "no such share".
714 + */
715 + time = SEC_TO_TICK(smb_tcon_import_wait) + ddi_get_lbolt();
716 + mutex_enter(&si->shr_mutex);
717 + while (si->shr_import_busy != NULL) {
718 + if (cv_timedwait(&si->shr_cv, &si->shr_mutex, time) < 0) {
719 + mutex_exit(&si->shr_mutex);
720 + return (NT_STATUS_BAD_NETWORK_NAME);
721 + }
722 + }
723 + mutex_exit(&si->shr_mutex);
724 +
725 + /*
698 726 * Set up the OptionalSupport for this share.
699 727 */
700 728 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
701 729
702 730 switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
703 731 case SMB_SHRF_CSC_DISABLED:
704 732 tcon->optional_support |= SMB_CSC_CACHE_NONE;
705 733 break;
706 734 case SMB_SHRF_CSC_AUTO:
707 735 tcon->optional_support |= SMB_CSC_CACHE_AUTO_REINT;
708 736 break;
709 737 case SMB_SHRF_CSC_VDO:
710 738 tcon->optional_support |= SMB_CSC_CACHE_VDO;
711 739 break;
712 740 case SMB_SHRF_CSC_MANUAL:
713 741 default:
714 742 /*
715 743 * Default to SMB_CSC_CACHE_MANUAL_REINT.
716 744 */
717 745 break;
718 746 }
719 747
720 748 /* ABE support */
721 749 if (si->shr_flags & SMB_SHRF_ABE)
722 750 tcon->optional_support |=
723 751 SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
724 752
725 753 if (si->shr_flags & SMB_SHRF_DFSROOT)
726 754 tcon->optional_support |= SMB_SHARE_IS_IN_DFS;
727 755
728 756 /* if 'smb' zfs property: shortnames=disabled */
729 757 if (!smb_shortnames)
730 758 sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME;
731 759
732 760 tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
733 761
734 - smb_node_release(snode);
735 -
736 762 if (tree == NULL)
737 763 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
738 764
739 765 if (tree->t_execflags & SMB_EXEC_MAP) {
740 766 smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP);
741 767
742 768 rc = smb_kshare_exec(tree->t_server, &execinfo);
743 769
744 770 if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) {
745 - smb_tree_disconnect(tree, B_FALSE);
771 + /*
772 + * Inline parts of: smb_tree_disconnect()
773 + * Not using smb_tree_disconnect() for cleanup
774 + * here because: we don't want an exec up-call,
775 + * and there can't be any opens as we never
776 + * returned this TID to the client.
777 + */
778 + mutex_enter(&tree->t_mutex);
779 + tree->t_state = SMB_TREE_STATE_DISCONNECTING;
780 + mutex_enter(&tree->t_mutex);
781 +
746 782 smb_tree_release(tree);
747 783 return (NT_STATUS_ACCESS_DENIED);
748 784 }
749 785 }
750 786
751 787 sr->tid_tree = tree;
752 788 sr->smb_tid = tree->t_tid;
753 789
754 790 return (0);
755 791 }
756 792
757 793 /*
758 794 * Shares have both a share and host based access control. The access
759 795 * granted will be minimum permissions based on both hostaccess
760 796 * (permissions allowed by host based access) and aclaccess (from the
|
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
761 797 * share ACL).
762 798 */
763 799 uint32_t
764 800 smb_tree_connect_printq(smb_request_t *sr, smb_arg_tcon_t *tcon)
765 801 {
766 802 char *sharename = tcon->path;
767 803 const char *any = "?????";
768 804 smb_user_t *user = sr->uid_user;
769 805 smb_node_t *dnode = NULL;
770 806 smb_node_t *snode = NULL;
771 - smb_kshare_t *si = tcon->si;
807 + smb_kshare_t *si = tcon->si;
772 808 char *service = tcon->service;
773 809 char last_component[MAXNAMELEN];
774 810 smb_tree_t *tree;
775 811 int rc;
776 812 uint32_t access;
777 813
778 814 ASSERT(user);
779 815 ASSERT(user->u_cred);
780 816
781 817 if (sr->sr_server->sv_cfg.skc_print_enable == 0) {
782 818 smb_tree_log(sr, sharename, "printing disabled");
783 819 return (NT_STATUS_BAD_NETWORK_NAME);
784 820 }
785 821
786 822 if (service != NULL &&
787 823 strcmp(service, any) != 0 &&
788 824 strcasecmp(service, "LPT1:") != 0) {
789 825 smb_tree_log(sr, sharename, "invalid service (%s)", service);
790 826 return (NT_STATUS_BAD_DEVICE_TYPE);
791 827 }
792 828
793 829 /*
794 830 * Check that the shared directory exists.
795 831 */
796 832 rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode,
797 833 last_component);
798 834 if (rc == 0) {
799 835 rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS,
800 836 sr->sr_server->si_root_smb_node, dnode, last_component,
801 837 &snode);
802 838
803 839 smb_node_release(dnode);
804 840 }
805 841
806 842 if (rc) {
807 843 if (snode)
808 844 smb_node_release(snode);
809 845
810 846 smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
811 847 return (NT_STATUS_BAD_NETWORK_NAME);
812 848 }
813 849
814 850 if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) {
815 851 smb_node_release(snode);
816 852 return (NT_STATUS_ACCESS_DENIED);
817 853 }
818 854
819 855 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
820 856
821 857 tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags);
822 858
823 859 smb_node_release(snode);
824 860
825 861 if (tree == NULL)
826 862 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
827 863
828 864 sr->tid_tree = tree;
829 865 sr->smb_tid = tree->t_tid;
830 866
831 867 return (0);
832 868 }
833 869
834 870 /*
835 871 * Connect an IPC share for use with named pipes.
836 872 */
837 873 uint32_t
838 874 smb_tree_connect_ipc(smb_request_t *sr, smb_arg_tcon_t *tcon)
839 875 {
840 876 char *name = tcon->path;
841 877 const char *any = "?????";
842 878 smb_user_t *user = sr->uid_user;
843 879 smb_tree_t *tree;
844 880 smb_kshare_t *si = tcon->si;
845 881 char *service = tcon->service;
846 882
847 883 ASSERT(user);
848 884
849 885 if (service != NULL &&
850 886 strcmp(service, any) != 0 &&
851 887 strcasecmp(service, "IPC") != 0) {
852 888 smb_tree_log(sr, name, "invalid service (%s)", service);
853 889 return (NT_STATUS_BAD_DEVICE_TYPE);
854 890 }
855 891
856 892 if ((user->u_flags & SMB_USER_FLAG_ANON) &&
857 893 sr->sr_cfg->skc_restrict_anon) {
858 894 smb_tree_log(sr, name, "access denied: restrict anonymous");
859 895 return (NT_STATUS_ACCESS_DENIED);
860 896 }
861 897
862 898 tcon->optional_support = SMB_SUPPORT_SEARCH_BITS;
863 899
864 900 tree = smb_tree_alloc(sr, si, NULL, ACE_ALL_PERMS, 0);
865 901 if (tree == NULL)
866 902 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
|
↓ open down ↓ |
85 lines elided |
↑ open up ↑ |
867 903
868 904 sr->tid_tree = tree;
869 905 sr->smb_tid = tree->t_tid;
870 906
871 907 return (0);
872 908 }
873 909
874 910 /*
875 911 * Allocate a tree.
876 912 */
877 -static smb_tree_t *
913 +smb_tree_t *
878 914 smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si,
879 915 smb_node_t *snode, uint32_t access, uint32_t execflags)
880 916 {
881 917 smb_session_t *session = sr->session;
882 918 smb_tree_t *tree;
883 919 uint32_t stype = si->shr_type;
884 920 uint16_t tid;
885 921
886 922 if (smb_idpool_alloc(&session->s_tid_pool, &tid))
887 923 return (NULL);
888 924
889 925 tree = kmem_cache_alloc(smb_cache_tree, KM_SLEEP);
890 926 bzero(tree, sizeof (smb_tree_t));
891 927
892 928 tree->t_session = session;
893 929 tree->t_server = session->s_server;
894 930
895 931 /* grab a ref for tree->t_owner */
896 932 smb_user_hold_internal(sr->uid_user);
897 933 tree->t_owner = sr->uid_user;
898 934
899 935 if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
900 936 if (smb_tree_getattr(si, snode, tree) != 0) {
901 937 smb_idpool_free(&session->s_tid_pool, tid);
902 938 kmem_cache_free(smb_cache_tree, tree);
903 939 return (NULL);
904 940 }
905 941 }
906 942
907 943 if (smb_idpool_constructor(&tree->t_fid_pool)) {
908 944 smb_idpool_free(&session->s_tid_pool, tid);
909 945 kmem_cache_free(smb_cache_tree, tree);
910 946 return (NULL);
|
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
911 947 }
912 948
913 949 if (smb_idpool_constructor(&tree->t_odid_pool)) {
914 950 smb_idpool_destructor(&tree->t_fid_pool);
915 951 smb_idpool_free(&session->s_tid_pool, tid);
916 952 kmem_cache_free(smb_cache_tree, tree);
917 953 return (NULL);
918 954 }
919 955
920 956 smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
921 - offsetof(smb_ofile_t, f_lnd));
957 + offsetof(smb_ofile_t, f_tree_lnd));
922 958
923 959 smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
924 960 offsetof(smb_odir_t, d_lnd));
925 961
926 962 (void) strlcpy(tree->t_sharename, si->shr_name,
927 963 sizeof (tree->t_sharename));
928 964 (void) strlcpy(tree->t_resource, si->shr_path,
929 965 sizeof (tree->t_resource));
930 966
931 967 mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
932 968
933 969 tree->t_refcnt = 1;
934 970 tree->t_tid = tid;
935 971 tree->t_res_type = stype;
936 972 tree->t_state = SMB_TREE_STATE_CONNECTED;
937 973 tree->t_magic = SMB_TREE_MAGIC;
938 974 tree->t_access = access;
939 975 tree->t_connect_time = gethrestime_sec();
940 976 tree->t_execflags = execflags;
941 977
942 978 /* if FS is readonly, enforce that here */
943 979 if (tree->t_flags & SMB_TREE_READONLY)
944 980 tree->t_access &= ~ACE_ALL_WRITE_PERMS;
945 981
946 982 if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
947 983 smb_node_ref(snode);
948 984 tree->t_snode = snode;
949 985 tree->t_acltype = smb_fsop_acltype(snode);
950 986 }
951 987
952 988 smb_llist_enter(&session->s_tree_list, RW_WRITER);
953 989 smb_llist_insert_head(&session->s_tree_list, tree);
954 990 smb_llist_exit(&session->s_tree_list);
955 991 atomic_inc_32(&session->s_tree_cnt);
956 992 smb_server_inc_trees(session->s_server);
|
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
957 993 return (tree);
958 994 }
959 995
960 996 /*
961 997 * Deallocate a tree. The open file and open directory lists should be
962 998 * empty.
963 999 *
964 1000 * Remove the tree from the user's tree list before freeing resources
965 1001 * associated with the tree.
966 1002 */
967 -void
1003 +static void
968 1004 smb_tree_dealloc(void *arg)
969 1005 {
970 1006 smb_session_t *session;
971 1007 smb_tree_t *tree = (smb_tree_t *)arg;
972 1008
973 1009 SMB_TREE_VALID(tree);
974 1010 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
975 1011 ASSERT(tree->t_refcnt == 0);
976 1012
1013 + smb_server_dec_trees(tree->t_server);
1014 +
977 1015 session = tree->t_session;
978 1016 smb_llist_enter(&session->s_tree_list, RW_WRITER);
979 1017 smb_llist_remove(&session->s_tree_list, tree);
980 1018 smb_idpool_free(&session->s_tid_pool, tree->t_tid);
981 1019 atomic_dec_32(&session->s_tree_cnt);
982 1020 smb_llist_exit(&session->s_tree_list);
983 1021
1022 + /*
1023 + * This tree is no longer on s_tree_list, however...
1024 + *
1025 + * This is called via smb_llist_post, which means it may run
1026 + * BEFORE smb_tree_release drops t_mutex (if another thread
1027 + * flushes the delete queue before we do). Synchronize.
1028 + */
984 1029 mutex_enter(&tree->t_mutex);
985 1030 mutex_exit(&tree->t_mutex);
986 1031
987 1032 tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
988 1033
1034 + if (tree->t_kshare != NULL) {
1035 + smb_kshare_release(tree->t_server, tree->t_kshare);
1036 + tree->t_kshare = NULL;
1037 + }
1038 +
989 1039 if (tree->t_snode)
990 1040 smb_node_release(tree->t_snode);
991 1041
992 1042 mutex_destroy(&tree->t_mutex);
993 1043 smb_llist_destructor(&tree->t_ofile_list);
994 1044 smb_llist_destructor(&tree->t_odir_list);
995 1045 smb_idpool_destructor(&tree->t_fid_pool);
996 1046 smb_idpool_destructor(&tree->t_odid_pool);
997 1047
998 1048 SMB_USER_VALID(tree->t_owner);
999 1049 smb_user_release(tree->t_owner);
1000 1050
1001 1051 kmem_cache_free(smb_cache_tree, tree);
1002 1052 }
1003 1053
1004 1054 /*
1005 1055 * Determine whether or not a tree is connected.
1006 1056 * This function must be called with the tree mutex held.
1007 1057 */
|
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
1008 1058 static boolean_t
1009 1059 smb_tree_is_connected_locked(smb_tree_t *tree)
1010 1060 {
1011 1061 switch (tree->t_state) {
1012 1062 case SMB_TREE_STATE_CONNECTED:
1013 1063 return (B_TRUE);
1014 1064
1015 1065 case SMB_TREE_STATE_DISCONNECTING:
1016 1066 case SMB_TREE_STATE_DISCONNECTED:
1017 1067 /*
1018 - * The tree exists but being diconnected or destroyed.
1068 + * The tree exists but is being disconnected or destroyed.
1019 1069 */
1020 1070 return (B_FALSE);
1021 1071
1022 1072 default:
1023 1073 ASSERT(0);
1024 1074 return (B_FALSE);
1025 1075 }
1026 1076 }
1027 1077
1028 1078 /*
1029 - * Determine whether or not a tree is disconnected.
1030 - * This function must be called with the tree mutex held.
1031 - */
1032 -static boolean_t
1033 -smb_tree_is_disconnected(smb_tree_t *tree)
1034 -{
1035 - switch (tree->t_state) {
1036 - case SMB_TREE_STATE_DISCONNECTED:
1037 - return (B_TRUE);
1038 -
1039 - case SMB_TREE_STATE_CONNECTED:
1040 - case SMB_TREE_STATE_DISCONNECTING:
1041 - return (B_FALSE);
1042 -
1043 - default:
1044 - ASSERT(0);
1045 - return (B_FALSE);
1046 - }
1047 -}
1048 -
1049 -/*
1050 1079 * Return a pointer to the share name within a share resource path.
1051 1080 *
1052 1081 * The share path may be a Uniform Naming Convention (UNC) string
1053 1082 * (\\server\share) or simply the share name. We validate the UNC
1054 1083 * format but we don't look at the server name.
1055 1084 */
1056 1085 static char *
1057 1086 smb_tree_get_sharename(char *unc_path)
1058 1087 {
1059 1088 char *sharename = unc_path;
1060 1089
1061 1090 if (sharename[0] == '\\') {
1062 1091 /*
1063 1092 * Looks like a UNC path, validate the format.
1064 1093 */
1065 1094 if (sharename[1] != '\\')
1066 1095 return (NULL);
1067 1096
1068 1097 if ((sharename = strchr(sharename+2, '\\')) == NULL)
1069 1098 return (NULL);
1070 1099
1071 1100 ++sharename;
1072 1101 } else if (strchr(sharename, '\\') != NULL) {
1073 1102 /*
1074 1103 * This should be a share name (no embedded \'s).
1075 1104 */
1076 1105 return (NULL);
1077 1106 }
1078 1107
|
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
1079 1108 return (sharename);
1080 1109 }
1081 1110
1082 1111 /*
1083 1112 * Obtain the tree attributes: volume name, typename and flags.
1084 1113 */
1085 1114 static int
1086 1115 smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree)
1087 1116 {
1088 1117 vfs_t *vfsp = SMB_NODE_VFS(node);
1118 + smb_cfg_val_t srv_encrypt;
1089 1119
1090 1120 ASSERT(vfsp);
1091 1121
1092 1122 if (getvfs(&vfsp->vfs_fsid) != vfsp)
1093 1123 return (ESTALE);
1094 1124
1095 1125 smb_tree_get_volname(vfsp, tree);
1096 1126 smb_tree_get_flags(si, vfsp, tree);
1097 1127
1128 + srv_encrypt = tree->t_session->s_server->sv_cfg.skc_encrypt;
1129 + if (tree->t_session->dialect >= SMB_VERS_3_0) {
1130 + if (si->shr_encrypt == SMB_CONFIG_REQUIRED ||
1131 + srv_encrypt == SMB_CONFIG_REQUIRED)
1132 + tree->t_encrypt = SMB_CONFIG_REQUIRED;
1133 + else if (si->shr_encrypt == SMB_CONFIG_ENABLED ||
1134 + srv_encrypt == SMB_CONFIG_ENABLED)
1135 + tree->t_encrypt = SMB_CONFIG_ENABLED;
1136 + else
1137 + tree->t_encrypt = SMB_CONFIG_DISABLED;
1138 + } else
1139 + tree->t_encrypt = SMB_CONFIG_DISABLED;
1140 +
1098 1141 VFS_RELE(vfsp);
1099 1142 return (0);
1100 1143 }
1101 1144
1102 1145 /*
1103 1146 * Extract the volume name.
1104 1147 */
1105 1148 static void
1106 1149 smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
1107 1150 {
1108 1151 #ifdef _FAKE_KERNEL
1109 1152 _NOTE(ARGUNUSED(vfsp))
1110 1153 (void) strlcpy(tree->t_volume, "fake", SMB_VOLNAMELEN);
1111 1154 #else /* _FAKE_KERNEL */
1112 1155 refstr_t *vfs_mntpoint;
1113 1156 const char *s;
1114 1157 char *name;
1115 1158
1116 1159 vfs_mntpoint = vfs_getmntpoint(vfsp);
1117 1160
1118 1161 s = refstr_value(vfs_mntpoint);
1119 1162 s += strspn(s, "/");
1120 1163 (void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);
1121 1164
1122 1165 refstr_rele(vfs_mntpoint);
1123 1166
1124 1167 name = tree->t_volume;
1125 1168 (void) strsep((char **)&name, "/");
1126 1169 #endif /* _FAKE_KERNEL */
1127 1170 }
1128 1171
1129 1172 /*
1130 1173 * Always set "unicode on disk" because we always use utf8 names locally.
1131 1174 * Always set ACL support because the VFS will fake ACLs for file systems
1132 1175 * that don't support them.
1133 1176 *
1134 1177 * Some flags are dependent on the typename, which is also set up here.
1135 1178 * File system types are hardcoded in uts/common/os/vfs_conf.c.
1136 1179 */
1137 1180 static void
1138 1181 smb_tree_get_flags(const smb_kshare_t *si, vfs_t *vfsp, smb_tree_t *tree)
1139 1182 {
|
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
1140 1183 smb_session_t *ssn = tree->t_session;
1141 1184 struct vfssw *vswp;
1142 1185
1143 1186 typedef struct smb_mtype {
1144 1187 char *mt_name;
1145 1188 size_t mt_namelen;
1146 1189 uint32_t mt_flags;
1147 1190 } smb_mtype_t;
1148 1191
1149 1192 static smb_mtype_t smb_mtype[] = {
1193 +#ifdef _FAKE_KERNEL
1194 + /* See libfksmbsrv:fake_vfs.c */
1195 + { "fake", 3, SMB_TREE_SPARSE},
1196 +#endif /* _FAKE_KERNEL */
1150 1197 { "zfs", 3, SMB_TREE_QUOTA | SMB_TREE_SPARSE},
1151 1198 { "ufs", 3, 0 },
1152 1199 { "nfs", 3, SMB_TREE_NFS_MOUNTED },
1153 1200 { "tmpfs", 5, SMB_TREE_NO_EXPORT }
1154 1201 };
1155 1202 smb_mtype_t *mtype;
1156 1203 char *name;
1157 1204 uint32_t flags =
1158 1205 SMB_TREE_SUPPORTS_ACLS |
1159 1206 SMB_TREE_UNICODE_ON_DISK;
1160 1207 int i;
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
1161 1208
1162 1209 if (si->shr_flags & SMB_SHRF_DFSROOT)
1163 1210 flags |= SMB_TREE_DFSROOT;
1164 1211
1165 1212 if (si->shr_flags & SMB_SHRF_CATIA)
1166 1213 flags |= SMB_TREE_CATIA;
1167 1214
1168 1215 if (si->shr_flags & SMB_SHRF_ABE)
1169 1216 flags |= SMB_TREE_ABE;
1170 1217
1218 + if (si->shr_flags & SMB_SHRF_CA)
1219 + flags |= SMB_TREE_CA;
1220 +
1221 + if (si->shr_flags & SMB_SHRF_FSO)
1222 + flags |= SMB_TREE_FORCE_L2_OPLOCK;
1223 +
1171 1224 if (ssn->s_cfg.skc_oplock_enable) {
1172 1225 /* if 'smb' zfs property: oplocks=enabled */
1173 1226 flags |= SMB_TREE_OPLOCKS;
1174 1227 }
1175 1228
1176 1229 /* Global config option for now. Later make per-share. */
1177 1230 if (ssn->s_cfg.skc_traverse_mounts)
1178 1231 flags |= SMB_TREE_TRAVERSE_MOUNTS;
1179 1232
1180 1233 /* if 'smb' zfs property: shortnames=enabled */
1181 1234 if (smb_shortnames)
1182 1235 flags |= SMB_TREE_SHORTNAMES;
1183 1236
1184 1237 if (vfsp->vfs_flag & VFS_RDONLY)
1185 1238 flags |= SMB_TREE_READONLY;
1186 1239
1187 1240 if (vfsp->vfs_flag & VFS_XATTR)
1188 1241 flags |= SMB_TREE_STREAMS;
1189 1242
1190 1243 vswp = vfs_getvfsswbyvfsops(vfs_getops(vfsp));
1191 1244 if (vswp != NULL) {
1192 1245 name = vswp->vsw_name;
1193 1246 vfs_unrefvfssw(vswp);
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
1194 1247 } else {
1195 1248 name = "?";
1196 1249 }
1197 1250
1198 1251 for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
1199 1252 mtype = &smb_mtype[i];
1200 1253 if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
1201 1254 flags |= mtype->mt_flags;
1202 1255 }
1203 1256
1257 + /*
1258 + * SMB_TREE_QUOTA will be on here if the FS is ZFS. We want to
1259 + * turn it OFF when the share property says false.
1260 + */
1261 + if ((si->shr_flags & SMB_SHRF_QUOTAS) == 0)
1262 + flags &= ~SMB_TREE_QUOTA;
1263 +
1204 1264 (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
1205 1265 (void) smb_strupr((char *)tree->t_typename);
1206 1266
1207 1267 if (vfs_has_feature(vfsp, VFSFT_XVATTR))
1208 1268 flags |= SMB_TREE_XVATTR;
1209 1269
1210 1270 if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
1211 1271 flags |= SMB_TREE_CASEINSENSITIVE;
1212 1272
1213 1273 if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
1214 1274 flags |= SMB_TREE_NO_CASESENSITIVE;
1215 1275
1216 1276 if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
1217 1277 flags |= SMB_TREE_DIRENTFLAGS;
1218 1278
1219 1279 if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
1220 1280 flags |= SMB_TREE_ACLONCREATE;
1221 1281
1222 1282 if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
1223 1283 flags |= SMB_TREE_ACEMASKONACCESS;
1224 1284
1225 1285 DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);
1226 1286
1227 1287
1228 1288 tree->t_flags = flags;
1229 1289 }
1230 1290
1231 1291 /*
1232 1292 * Report share access result to syslog.
1233 1293 */
1234 1294 static void
1235 1295 smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...)
1236 1296 {
1237 1297 va_list ap;
1238 1298 char buf[128];
1239 1299 smb_user_t *user = sr->uid_user;
1240 1300
1241 1301 ASSERT(user);
1242 1302
1243 1303 if (smb_tcon_mute)
1244 1304 return;
1245 1305
1246 1306 if ((user->u_name) && (strcasecmp(sharename, "IPC$") == 0)) {
1247 1307 /*
1248 1308 * Only report normal users, i.e. ignore W2K misuse
1249 1309 * of the IPC connection by filtering out internal
1250 1310 * names such as nobody and root.
1251 1311 */
1252 1312 if ((strcmp(user->u_name, "root") == 0) ||
1253 1313 (strcmp(user->u_name, "nobody") == 0)) {
1254 1314 return;
1255 1315 }
1256 1316 }
1257 1317
1258 1318 va_start(ap, fmt);
1259 1319 (void) vsnprintf(buf, 128, fmt, ap);
1260 1320 va_end(ap);
1261 1321
1262 1322 cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
1263 1323 user->u_domain, user->u_name, sharename, buf);
1264 1324 }
1265 1325
1266 1326 /*
1267 1327 * smb_tree_lookup_odir
1268 1328 *
1269 1329 * Find the specified odir in the tree's list of odirs, and
1270 1330 * attempt to obtain a hold on the odir.
1271 1331 *
1272 1332 * Returns NULL if odir not found or a hold cannot be obtained.
1273 1333 */
1274 1334 smb_odir_t *
1275 1335 smb_tree_lookup_odir(smb_request_t *sr, uint16_t odid)
1276 1336 {
1277 1337 smb_odir_t *od;
1278 1338 smb_llist_t *od_list;
1279 1339 smb_tree_t *tree = sr->tid_tree;
1280 1340
1281 1341 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1282 1342
1283 1343 od_list = &tree->t_odir_list;
1284 1344
1285 1345 smb_llist_enter(od_list, RW_READER);
1286 1346 od = smb_llist_head(od_list);
1287 1347 while (od) {
1288 1348 if (od->d_odid == odid)
1289 1349 break;
1290 1350 od = smb_llist_next(od_list, od);
1291 1351 }
1292 1352 if (od == NULL)
1293 1353 goto out;
1294 1354
1295 1355 /*
1296 1356 * Only allow use of a given Search ID with the same UID that
1297 1357 * was used to create it. MS-CIFS 3.3.5.14
1298 1358 */
1299 1359 if (od->d_user != sr->uid_user) {
1300 1360 od = NULL;
1301 1361 goto out;
1302 1362 }
1303 1363 if (!smb_odir_hold(od))
1304 1364 od = NULL;
1305 1365
1306 1366 out:
1307 1367 smb_llist_exit(od_list);
1308 1368 return (od);
1309 1369 }
1310 1370
1311 1371 boolean_t
1312 1372 smb_tree_is_connected(smb_tree_t *tree)
|
↓ open down ↓ |
99 lines elided |
↑ open up ↑ |
1313 1373 {
1314 1374 boolean_t rb;
1315 1375
1316 1376 mutex_enter(&tree->t_mutex);
1317 1377 rb = smb_tree_is_connected_locked(tree);
1318 1378 mutex_exit(&tree->t_mutex);
1319 1379 return (rb);
1320 1380 }
1321 1381
1322 1382 /*
1323 - * Get the next open ofile in the list. A reference is taken on
1324 - * the ofile, which can be released later with smb_ofile_release().
1325 - *
1326 - * If the specified ofile is NULL, search from the beginning of the
1327 - * list. Otherwise, the search starts just after that ofile.
1328 - *
1329 - * Returns NULL if there are no open files in the list.
1330 - */
1331 -static smb_ofile_t *
1332 -smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of)
1333 -{
1334 - smb_llist_t *ofile_list;
1335 -
1336 - ASSERT(tree);
1337 - ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1338 -
1339 - ofile_list = &tree->t_ofile_list;
1340 - smb_llist_enter(ofile_list, RW_READER);
1341 -
1342 - if (of) {
1343 - ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1344 - of = smb_llist_next(ofile_list, of);
1345 - } else {
1346 - of = smb_llist_head(ofile_list);
1347 - }
1348 -
1349 - while (of) {
1350 - if (smb_ofile_hold(of))
1351 - break;
1352 -
1353 - of = smb_llist_next(ofile_list, of);
1354 - }
1355 -
1356 - smb_llist_exit(ofile_list);
1357 - return (of);
1358 -}
1359 -
1360 -/*
1361 - * smb_tree_get_odir
1362 - *
1363 - * Find the next odir in the tree's list of odirs, and obtain a
1364 - * hold on it.
1365 - * If the specified odir is NULL the search starts at the beginning
1366 - * of the tree's odir list, otherwise the search starts after the
1367 - * specified odir.
1368 - */
1369 -static smb_odir_t *
1370 -smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od)
1371 -{
1372 - smb_llist_t *od_list;
1373 -
1374 - ASSERT(tree);
1375 - ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1376 -
1377 - od_list = &tree->t_odir_list;
1378 - smb_llist_enter(od_list, RW_READER);
1379 -
1380 - if (od) {
1381 - ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1382 - od = smb_llist_next(od_list, od);
1383 - } else {
1384 - od = smb_llist_head(od_list);
1385 - }
1386 -
1387 - while (od) {
1388 - ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1389 -
1390 - if (smb_odir_hold(od))
1391 - break;
1392 - od = smb_llist_next(od_list, od);
1393 - }
1394 -
1395 - smb_llist_exit(od_list);
1396 - return (od);
1397 -}
1398 -
1399 -/*
1400 1383 * smb_tree_close_odirs
1401 1384 *
1402 1385 * Close all open odirs in the tree's list which were opened by
1403 1386 * the process identified by pid.
1404 1387 * If pid is zero, close all open odirs in the tree's list.
1405 1388 */
1406 1389 static void
1407 -smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
1390 +smb_tree_close_odirs(smb_tree_t *tree, uint32_t pid)
1408 1391 {
1409 - smb_odir_t *od, *next_od;
1392 + smb_llist_t *od_list;
1393 + smb_odir_t *od;
1410 1394
1411 1395 ASSERT(tree);
1412 1396 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
1413 1397
1414 - od = smb_tree_get_odir(tree, NULL);
1415 - while (od) {
1398 + od_list = &tree->t_odir_list;
1399 + smb_llist_enter(od_list, RW_READER);
1400 +
1401 + for (od = smb_llist_head(od_list);
1402 + od != NULL;
1403 + od = smb_llist_next(od_list, od)) {
1404 +
1416 1405 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1417 1406 ASSERT(od->d_tree == tree);
1418 1407
1419 - next_od = smb_tree_get_odir(tree, od);
1420 - if ((pid == 0) || (od->d_opened_by_pid == pid))
1421 - smb_odir_close(od);
1422 - smb_odir_release(od);
1408 + if (pid != 0 && od->d_opened_by_pid != pid)
1409 + continue;
1423 1410
1424 - od = next_od;
1411 + if (smb_odir_hold(od)) {
1412 + smb_odir_close(od);
1413 + smb_odir_release(od);
1414 + }
1425 1415 }
1416 +
1417 + smb_llist_exit(od_list);
1426 1418 }
1427 1419
1428 1420 static void
1429 1421 smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec,
1430 1422 int exec_type)
1431 1423 {
1432 1424 exec->e_sharename = tree->t_sharename;
1433 1425 exec->e_winname = tree->t_owner->u_name;
1434 1426 exec->e_userdom = tree->t_owner->u_domain;
1435 1427 exec->e_srv_ipaddr = tree->t_session->local_ipaddr;
1436 1428 exec->e_cli_ipaddr = tree->t_session->ipaddr;
1437 1429 exec->e_cli_netbiosname = tree->t_session->workstation;
1438 1430 exec->e_uid = crgetuid(tree->t_owner->u_cred);
1439 1431 exec->e_type = exec_type;
1440 1432 }
1441 1433
1442 1434 /*
1443 1435 * Private function to support smb_tree_enum.
1444 1436 */
1445 1437 static int
1446 1438 smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
1447 1439 {
1448 1440 uint8_t *pb;
1449 1441 uint_t nbytes;
1450 1442 int rc;
1451 1443
1452 1444 if (svcenum->se_nskip > 0) {
1453 1445 svcenum->se_nskip--;
1454 1446 return (0);
1455 1447 }
1456 1448
1457 1449 if (svcenum->se_nitems >= svcenum->se_nlimit) {
1458 1450 svcenum->se_nitems = svcenum->se_nlimit;
1459 1451 return (0);
1460 1452 }
1461 1453
1462 1454 pb = &svcenum->se_buf[svcenum->se_bused];
1463 1455 rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
1464 1456 if (rc == 0) {
1465 1457 svcenum->se_bavail -= nbytes;
1466 1458 svcenum->se_bused += nbytes;
1467 1459 svcenum->se_nitems++;
1468 1460 }
1469 1461
1470 1462 return (rc);
1471 1463 }
1472 1464
1473 1465 /*
1474 1466 * Encode connection information into a buffer: connection information
1475 1467 * needed in user space to support RPC requests.
1476 1468 */
1477 1469 static int
1478 1470 smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
1479 1471 uint32_t *nbytes)
1480 1472 {
1481 1473 smb_netconnectinfo_t info;
1482 1474 int rc;
1483 1475
1484 1476 smb_tree_netinfo_init(tree, &info);
1485 1477 rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
1486 1478 smb_tree_netinfo_fini(&info);
1487 1479
1488 1480 return (rc);
1489 1481 }
1490 1482
1491 1483 static void
1492 1484 smb_tree_netinfo_username(smb_tree_t *tree, char **namestr, uint32_t *namelen)
1493 1485 {
1494 1486 smb_user_t *user = tree->t_owner;
1495 1487
1496 1488 /*
1497 1489 * u_domain_len and u_name_len include the '\0' in their
1498 1490 * lengths, hence the sum of the two lengths gives us room
1499 1491 * for both the '\\' and '\0' chars.
1500 1492 */
1501 1493 ASSERT(namestr);
1502 1494 ASSERT(namelen);
1503 1495 ASSERT(user->u_domain_len > 0);
1504 1496 ASSERT(user->u_name_len > 0);
1505 1497 *namelen = user->u_domain_len + user->u_name_len;
1506 1498 *namestr = kmem_alloc(*namelen, KM_SLEEP);
1507 1499 (void) snprintf(*namestr, *namelen, "%s\\%s", user->u_domain,
1508 1500 user->u_name);
1509 1501 }
1510 1502
1511 1503 /*
1512 1504 * Note: ci_numusers should be the number of users connected to
1513 1505 * the share rather than the number of references on the tree but
1514 1506 * we don't have a mechanism to track users/share in smbsrv yet.
1515 1507 */
1516 1508 static void
1517 1509 smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
1518 1510 {
1519 1511 ASSERT(tree);
1520 1512
1521 1513 info->ci_id = tree->t_tid;
1522 1514 info->ci_type = tree->t_res_type;
1523 1515 info->ci_numopens = tree->t_open_files;
1524 1516 info->ci_numusers = tree->t_refcnt;
1525 1517 info->ci_time = gethrestime_sec() - tree->t_connect_time;
1526 1518
1527 1519 info->ci_sharelen = strlen(tree->t_sharename) + 1;
1528 1520 info->ci_share = smb_mem_strdup(tree->t_sharename);
1529 1521
1530 1522 smb_tree_netinfo_username(tree, &info->ci_username, &info->ci_namelen);
1531 1523 }
1532 1524
1533 1525 static void
1534 1526 smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
1535 1527 {
1536 1528 if (info == NULL)
1537 1529 return;
1538 1530
1539 1531 if (info->ci_username)
1540 1532 kmem_free(info->ci_username, info->ci_namelen);
1541 1533 if (info->ci_share)
1542 1534 smb_mem_free(info->ci_share);
1543 1535
1544 1536 bzero(info, sizeof (smb_netconnectinfo_t));
1545 1537 }
|
↓ open down ↓ |
110 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX