Print this page
NEX-2807 Restoring previous versions from snapshots doesn't work with nested folders.
Reviewed by: Gordon Ross <gordon.ross@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-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-4538 SMB1 create file should support extended_response format (2)
NEX-6116 Failures in smbtorture raw.open
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Include this commit if upstreaming/backporting any of:
NEX-4540 SMB server declines EA support incorrectly
NEX-4239 smbtorture create failures re. allocation size
(illumos) 6398 SMB should support path names longer than 1024
NEX-5082 panic getting Mac attributes for a 255 character file name
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Conflicts:
usr/src/uts/common/fs/smbsrv/smb_pathname.c
NEX-3611 CLONE NEX-3550 Replace smb2_enable with max_protocol
Reviewed by: Yuri Pankov <Yuri.Pankov@nexenta.com>
SMB-115 Support SMB path names with length > 1024
SMB-100 Internal error if filename is too long
Approved by: Gordon Ross <gwr@nexenta.com>
SMB-136 Snapshots not visible in Windows previous versions
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-65 SMB server in non-global zones (use zone_kcred())
re #13470 rb4432 Sync some SMB differences from illumos
re #6854 FindFirstFile,FindFirstFileEx,... are not working correctly on Nexenta CIFS-shares
re #6813 rb1757 port 2976 Child folder visibility through shares
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_pathname.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_pathname.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
23 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 #include <smbsrv/smb_kproto.h>
27 27 #include <smbsrv/smb_fsops.h>
28 28 #include <sys/pathname.h>
29 29 #include <sys/sdt.h>
30 30
31 31 static char *smb_pathname_catia_v5tov4(smb_request_t *, char *, char *, int);
32 32 static char *smb_pathname_catia_v4tov5(smb_request_t *, char *, char *, int);
33 33 static int smb_pathname_lookup(pathname_t *, pathname_t *, int,
34 34 vnode_t **, vnode_t *, vnode_t *, smb_attr_t *attr, cred_t *);
35 35 static char *smb_pathname_strdup(smb_request_t *, const char *);
36 36 static char *smb_pathname_strcat(smb_request_t *, char *, const char *);
37 37 static void smb_pathname_preprocess(smb_request_t *, smb_pathname_t *);
38 38 static void smb_pathname_preprocess_quota(smb_request_t *, smb_pathname_t *);
39 39 static int smb_pathname_dfs_preprocess(smb_request_t *, char *, size_t);
40 40 static void smb_pathname_preprocess_adminshare(smb_request_t *,
41 41 smb_pathname_t *);
42 42
43 43
44 44 uint32_t
45 45 smb_is_executable(char *path)
46 46 {
47 47 char extension[5];
48 48 int len = strlen(path);
49 49
50 50 if ((len >= 4) && (path[len - 4] == '.')) {
51 51 (void) strcpy(extension, &path[len - 3]);
52 52 (void) smb_strupr(extension);
53 53
54 54 if (strcmp(extension, "EXE") == 0)
55 55 return (NODE_FLAGS_EXECUTABLE);
56 56
57 57 if (strcmp(extension, "COM") == 0)
58 58 return (NODE_FLAGS_EXECUTABLE);
59 59
60 60 if (strcmp(extension, "DLL") == 0)
61 61 return (NODE_FLAGS_EXECUTABLE);
62 62
63 63 if (strcmp(extension, "SYM") == 0)
64 64 return (NODE_FLAGS_EXECUTABLE);
65 65 }
66 66
67 67 return (0);
68 68 }
69 69
70 70 /*
71 71 * smb_pathname_reduce
72 72 *
73 73 * smb_pathname_reduce() takes a path and returns the smb_node for the
74 74 * second-to-last component of the path. It also returns the name of the last
75 75 * component. Pointers for both of these fields must be supplied by the caller.
76 76 *
77 77 * Upon success, 0 is returned.
78 78 *
79 79 * Upon error, *dir_node will be set to 0.
80 80 *
81 81 * *sr (in)
82 82 * ---
83 83 * smb_request structure pointer
84 84 *
85 85 * *cred (in)
86 86 * -----
87 87 * credential
88 88 *
89 89 * *path (in)
90 90 * -----
91 91 * pathname to be looked up
92 92 *
93 93 * *share_root_node (in)
94 94 * ----------------
95 95 * File operations which are share-relative should pass sr->tid_tree->t_snode.
96 96 * If the call is not for a share-relative operation, this parameter must be 0
97 97 * (e.g. the call from smbsr_setup_share()). (Such callers will have path
98 98 * operations done using root_smb_node.) This parameter is used to determine
99 99 * whether mount points can be crossed.
100 100 *
101 101 * share_root_node should have at least one reference on it. This reference
102 102 * will stay intact throughout this routine.
103 103 *
104 104 * *cur_node (in)
105 105 * ---------
106 106 * The smb_node for the current directory (for relative paths).
107 107 * cur_node should have at least one reference on it.
108 108 * This reference will stay intact throughout this routine.
109 109 *
110 110 * **dir_node (out)
111 111 * ----------
112 112 * Directory for the penultimate component of the original path.
113 113 * (Note that this is not the same as the parent directory of the ultimate
114 114 * target in the case of a link.)
115 115 *
116 116 * The directory smb_node is returned held. The caller will need to release
117 117 * the hold or otherwise make sure it will get released (e.g. in a destroy
118 118 * routine if made part of a global structure).
119 119 *
120 120 * last_component (out)
121 121 * --------------
122 122 * The last component of the path. (This may be different from the name of any
123 123 * link target to which the last component may resolve.)
124 124 *
125 125 *
126 126 * ____________________________
127 127 *
128 128 * The CIFS server lookup path needs to have logic equivalent to that of
129 129 * smb_fsop_lookup(), smb_vop_lookup() and other smb_vop_*() routines in the
130 130 * following areas:
131 131 *
132 132 * - traversal of child mounts (handled by smb_pathname_reduce)
133 133 * - unmangling (handled in smb_pathname)
134 134 * - "chroot" behavior of share root (handled by lookuppnvp)
135 135 *
136 136 * In addition, it needs to replace backslashes with forward slashes. It also
137 137 * ensures that link processing is done correctly, and that directory
138 138 * information requested by the caller is correctly returned (i.e. for paths
139 139 * with a link in the last component, the directory information of the
140 140 * link and not the target needs to be returned).
141 141 */
142 142
143 143 int
|
↓ open down ↓ |
110 lines elided |
↑ open up ↑ |
144 144 smb_pathname_reduce(
145 145 smb_request_t *sr,
146 146 cred_t *cred,
147 147 const char *path,
148 148 smb_node_t *share_root_node,
149 149 smb_node_t *cur_node,
150 150 smb_node_t **dir_node,
151 151 char *last_component)
152 152 {
153 153 smb_node_t *root_node;
154 - pathname_t ppn;
154 + pathname_t ppn, mnt_pn;
155 155 char *usepath;
156 156 int lookup_flags = FOLLOW;
157 157 int trailing_slash = 0;
158 158 int err = 0;
159 159 int len;
160 - smb_node_t *vss_cur_node;
161 - smb_node_t *vss_root_node;
160 + smb_node_t *vss_node;
162 161 smb_node_t *local_cur_node;
163 162 smb_node_t *local_root_node;
163 + boolean_t chk_vss;
164 + char *gmttoken;
164 165
165 166 ASSERT(dir_node);
166 167 ASSERT(last_component);
167 168
168 169 *dir_node = NULL;
169 170 *last_component = '\0';
170 - vss_cur_node = NULL;
171 - vss_root_node = NULL;
171 + vss_node = NULL;
172 + gmttoken = NULL;
173 + chk_vss = B_FALSE;
172 174
173 175 if (sr && sr->tid_tree) {
174 176 if (STYPE_ISIPC(sr->tid_tree->t_res_type))
175 177 return (EACCES);
176 178 }
177 179
178 180 if (SMB_TREE_IS_CASEINSENSITIVE(sr))
179 181 lookup_flags |= FIGNORECASE;
180 182
181 183 if (path == NULL)
182 184 return (EINVAL);
183 185
184 186 if (*path == '\0')
185 187 return (ENOENT);
186 188
187 189 usepath = kmem_alloc(SMB_MAXPATHLEN, KM_SLEEP);
188 190
189 191 len = strlcpy(usepath, path, SMB_MAXPATHLEN);
190 192 if (len >= SMB_MAXPATHLEN) {
191 193 kmem_free(usepath, SMB_MAXPATHLEN);
192 194 return (ENAMETOOLONG);
193 195 }
194 196
195 197 (void) strsubst(usepath, '\\', '/');
196 198
197 199 if (share_root_node)
198 200 root_node = share_root_node;
199 201 else
200 202 root_node = sr->sr_server->si_root_smb_node;
201 203
202 204 if (cur_node == NULL)
203 205 cur_node = root_node;
204 206
205 207 local_cur_node = cur_node;
206 208 local_root_node = root_node;
207 209
208 210 if (SMB_TREE_IS_DFSROOT(sr)) {
209 211 int is_dfs;
210 212 if (sr->session->dialect >= SMB_VERS_2_BASE)
211 213 is_dfs = sr->smb2_hdr_flags &
212 214 SMB2_FLAGS_DFS_OPERATIONS;
213 215 else
214 216 is_dfs = sr->smb_flg2 & SMB_FLAGS2_DFS;
215 217 if (is_dfs != 0) {
216 218 err = smb_pathname_dfs_preprocess(sr, usepath,
|
↓ open down ↓ |
35 lines elided |
↑ open up ↑ |
217 219 SMB_MAXPATHLEN);
218 220 if (err != 0) {
219 221 kmem_free(usepath, SMB_MAXPATHLEN);
220 222 return (err);
221 223 }
222 224 len = strlen(usepath);
223 225 }
224 226 }
225 227
226 228 if (sr != NULL) {
227 - boolean_t chk_vss;
228 - if (sr->session->dialect >= SMB_VERS_2_BASE)
229 + if (sr->session->dialect >= SMB_VERS_2_BASE) {
229 230 chk_vss = sr->arg.open.create_timewarp;
230 - else
231 + } else {
231 232 chk_vss = (sr->smb_flg2 &
232 233 SMB_FLAGS2_REPARSE_PATH) != 0;
233 - if (chk_vss) {
234 - err = smb_vss_lookup_nodes(sr, root_node, cur_node,
235 - usepath, &vss_cur_node, &vss_root_node);
236 - if (err != 0) {
237 - kmem_free(usepath, SMB_MAXPATHLEN);
238 - return (err);
239 - }
240 234
241 - len = strlen(usepath);
242 - local_cur_node = vss_cur_node;
243 - local_root_node = vss_root_node;
235 + if (chk_vss) {
236 + gmttoken = kmem_alloc(SMB_VSS_GMT_SIZE,
237 + KM_SLEEP);
238 + err = smb_vss_extract_gmttoken(usepath,
239 + gmttoken);
240 + if (err != 0) {
241 + kmem_free(usepath, SMB_MAXPATHLEN);
242 + kmem_free(gmttoken, SMB_VSS_GMT_SIZE);
243 + return (err);
244 + }
245 + len = strlen(usepath);
246 + }
244 247 }
248 + if (chk_vss)
249 + (void) pn_alloc(&mnt_pn);
245 250 }
246 251
247 252 if (usepath[len - 1] == '/')
248 253 trailing_slash = 1;
249 254
250 255 (void) strcanon(usepath, "/");
251 256
252 257 (void) pn_alloc_sz(&ppn, SMB_MAXPATHLEN);
253 258
254 259 if ((err = pn_set(&ppn, usepath)) != 0) {
255 260 (void) pn_free(&ppn);
256 261 kmem_free(usepath, SMB_MAXPATHLEN);
257 - if (vss_cur_node != NULL)
258 - (void) smb_node_release(vss_cur_node);
259 - if (vss_root_node != NULL)
260 - (void) smb_node_release(vss_root_node);
262 + if (chk_vss)
263 + (void) pn_free(&mnt_pn);
264 + if (gmttoken != NULL)
265 + kmem_free(gmttoken, SMB_VSS_GMT_SIZE);
261 266 return (err);
262 267 }
263 268
264 269 /*
265 270 * If a path does not have a trailing slash, strip off the
266 271 * last component. (We only need to return an smb_node for
267 272 * the second to last component; a name is returned for the
268 273 * last component.)
274 + *
275 + * For VSS requests, the last component might be a filesystem of its
276 + * own, and we need to discover that before exiting this function,
277 + * so allow the lookup to happen on the last component.
278 + * We'll correct this later when we convert to the snapshot.
269 279 */
270 280
271 - if (trailing_slash) {
272 - (void) strlcpy(last_component, ".", MAXNAMELEN);
273 - } else {
274 - (void) pn_setlast(&ppn);
275 - (void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
276 - ppn.pn_path[0] = '\0';
281 + if (!chk_vss) {
282 + if (trailing_slash) {
283 + (void) strlcpy(last_component, ".", MAXNAMELEN);
284 + } else {
285 + (void) pn_setlast(&ppn);
286 + (void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
287 + ppn.pn_path[0] = '\0';
288 + }
277 289 }
278 290
279 291 if ((strcmp(ppn.pn_buf, "/") == 0) || (ppn.pn_buf[0] == '\0')) {
280 292 smb_node_ref(local_cur_node);
281 293 *dir_node = local_cur_node;
282 294 } else {
283 295 err = smb_pathname(sr, ppn.pn_buf, lookup_flags,
284 - local_root_node, local_cur_node, NULL, dir_node, cred);
296 + local_root_node, local_cur_node, NULL, dir_node, cred,
297 + chk_vss ? &mnt_pn : NULL);
285 298 }
286 299
287 300 (void) pn_free(&ppn);
288 301 kmem_free(usepath, SMB_MAXPATHLEN);
289 302
290 303 /*
304 + * We need to try and convert to snapshots, even on error.
305 + * This is to handle the following cases:
306 + * - We're on the lowest level filesystem, but a directory got renamed
307 + * on the live version. We'll get ENOENT, but can still find it in
308 + * the snapshot.
309 + * - The last component was actually a file. We need to leave the last
310 + * component in in case it is, itself, a mountpoint, but that means
311 + * we might get ENOTDIR if it's not actually a directory.
312 + *
313 + * Note that if you change the share-relative name of a mountpoint,
314 + * you won't be able to access previous versions of files under it.
315 + */
316 + if (chk_vss && *dir_node != NULL) {
317 + if ((err = smb_vss_lookup_nodes(sr, *dir_node, &vss_node,
318 + gmttoken)) == 0) {
319 + char *p = mnt_pn.pn_path;
320 + size_t pathleft;
321 +
322 + smb_node_release(*dir_node);
323 + *dir_node = NULL;
324 + pathleft = pn_pathleft(&mnt_pn);
325 +
326 + if (pathleft == 0 || trailing_slash) {
327 + (void) strlcpy(last_component, ".", MAXNAMELEN);
328 + } else {
329 + (void) pn_setlast(&mnt_pn);
330 + (void) strlcpy(last_component, mnt_pn.pn_path,
331 + MAXNAMELEN);
332 + mnt_pn.pn_path[0] = '\0';
333 + pathleft -= strlen(last_component);
334 + }
335 +
336 + if (pathleft != 0) {
337 + err = smb_pathname(sr, p, lookup_flags,
338 + vss_node, vss_node, NULL, dir_node, cred,
339 + NULL);
340 + } else {
341 + *dir_node = vss_node;
342 + vss_node = NULL;
343 + }
344 + }
345 + }
346 +
347 + if (chk_vss)
348 + (void) pn_free(&mnt_pn);
349 + if (gmttoken != NULL)
350 + kmem_free(gmttoken, SMB_VSS_GMT_SIZE);
351 +
352 + /*
291 353 * Prevent traversal to another file system if mount point
292 354 * traversal is disabled.
293 355 *
294 356 * Note that we disregard whether the traversal of the path went
295 357 * outside of the file system and then came back (say via a link).
296 358 * This means that only symlinks that are expressed relatively to
297 359 * the share root work.
298 360 *
299 361 * share_root_node is NULL when mapping a share, so we disregard
300 362 * that case.
301 363 */
302 364
303 365 if ((err == 0) && share_root_node) {
304 366 if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp) {
305 367 err = EACCES;
306 368 if ((sr) && (sr)->tid_tree &&
307 369 smb_tree_has_feature((sr)->tid_tree,
308 370 SMB_TREE_TRAVERSE_MOUNTS))
309 371 err = 0;
310 372 }
|
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
311 373 }
312 374
313 375 if (err) {
314 376 if (*dir_node) {
315 377 (void) smb_node_release(*dir_node);
316 378 *dir_node = NULL;
317 379 }
318 380 *last_component = 0;
319 381 }
320 382
321 - if (vss_cur_node != NULL)
322 - (void) smb_node_release(vss_cur_node);
323 - if (vss_root_node != NULL)
324 - (void) smb_node_release(vss_root_node);
325 -
383 + if (vss_node != NULL)
384 + (void) smb_node_release(vss_node);
326 385 return (err);
327 386 }
328 387
329 388 /*
330 389 * smb_pathname()
331 390 * wrapper to lookuppnvp(). Handles name unmangling.
332 391 *
333 392 * *dir_node is the true directory of the target *node.
334 393 *
335 394 * If any component but the last in the path is not found, ENOTDIR instead of
336 395 * ENOENT will be returned.
337 396 *
338 397 * Path components are processed one at a time so that smb_nodes can be
339 398 * created for each component. This allows the n_dnode field in the
340 399 * smb_node to be properly populated.
341 400 *
342 401 * Because of the above, links are also processed in this routine
343 402 * (i.e., we do not pass the FOLLOW flag to lookuppnvp()). This
344 403 * will allow smb_nodes to be created for each component of a link.
345 404 *
346 405 * Mangle checking is per component. If a name is mangled, when the
347 406 * unmangled name is passed to smb_pathname_lookup() do not pass
348 407 * FIGNORECASE, since the unmangled name is the real on-disk name.
349 408 * Otherwise pass FIGNORECASE if it's set in flags. This will cause the
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
350 409 * file system to return "first match" in the event of a case collision.
351 410 *
352 411 * If CATIA character translation is enabled it is applied to each
353 412 * component before passing the component to smb_pathname_lookup().
354 413 * After smb_pathname_lookup() the reverse translation is applied.
355 414 */
356 415
357 416 int
358 417 smb_pathname(smb_request_t *sr, char *path, int flags,
359 418 smb_node_t *root_node, smb_node_t *cur_node, smb_node_t **dir_node,
360 - smb_node_t **ret_node, cred_t *cred)
419 + smb_node_t **ret_node, cred_t *cred, pathname_t *mnt_pn)
361 420 {
362 421 char *component, *real_name, *namep;
363 422 pathname_t pn, rpn, upn, link_pn;
364 - smb_node_t *dnode, *fnode;
423 + smb_node_t *dnode, *fnode, *mnt_node;
365 424 smb_attr_t attr;
366 425 vnode_t *rootvp, *vp;
367 426 size_t pathleft;
368 427 int err = 0;
369 428 int nlink = 0;
370 429 int local_flags;
371 430 uint32_t abe_flag = 0;
372 431 char namebuf[MAXNAMELEN];
432 + vnode_t *fsrootvp = NULL;
373 433
374 434 if (path == NULL)
375 435 return (EINVAL);
376 436
377 437 ASSERT(root_node);
378 438 ASSERT(cur_node);
379 439 ASSERT(ret_node);
380 440
381 441 *ret_node = NULL;
382 442
383 443 if (dir_node)
384 444 *dir_node = NULL;
385 445
386 446 (void) pn_alloc_sz(&upn, SMB_MAXPATHLEN);
387 447
388 448 if ((err = pn_set(&upn, path)) != 0) {
389 449 (void) pn_free(&upn);
390 450 return (err);
391 451 }
392 452
453 + if (mnt_pn != NULL && (err = pn_set(mnt_pn, path) != 0)) {
454 + (void) pn_free(&upn);
455 + return (err);
456 + }
457 +
393 458 if (SMB_TREE_SUPPORTS_ABE(sr))
394 459 abe_flag = SMB_ABE;
395 460
396 461 (void) pn_alloc(&pn);
397 462 (void) pn_alloc(&rpn);
398 463
399 464 component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
400 465 real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
401 466
467 + if (mnt_pn != NULL) {
468 + mnt_node = cur_node;
469 + smb_node_ref(cur_node);
470 + } else
471 + mnt_node = NULL;
402 472 fnode = NULL;
403 473 dnode = cur_node;
404 474 smb_node_ref(dnode);
405 475 rootvp = root_node->vp;
406 476
407 477 while ((pathleft = pn_pathleft(&upn)) != 0) {
408 478 if (fnode) {
409 479 smb_node_release(dnode);
410 480 dnode = fnode;
411 481 fnode = NULL;
412 482 }
413 483
414 484 if ((err = pn_getcomponent(&upn, component)) != 0)
415 485 break;
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
416 486
417 487 if ((namep = smb_pathname_catia_v5tov4(sr, component,
418 488 namebuf, sizeof (namebuf))) == NULL) {
419 489 err = EILSEQ;
420 490 break;
421 491 }
422 492
423 493 if ((err = pn_set(&pn, namep)) != 0)
424 494 break;
425 495
496 + /* We want the DOS attributes. */
497 + bzero(&attr, sizeof (attr));
498 + attr.sa_mask = SMB_AT_DOSATTR;
499 +
426 500 local_flags = flags & FIGNORECASE;
427 501 err = smb_pathname_lookup(&pn, &rpn, local_flags,
428 502 &vp, rootvp, dnode->vp, &attr, cred);
429 503
430 504 if (err) {
431 505 if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
432 506 !smb_maybe_mangled(component))
433 507 break;
434 508
435 509 if ((err = smb_unmangle(dnode, component,
436 510 real_name, MAXNAMELEN, abe_flag)) != 0)
437 511 break;
438 512
439 513 if ((namep = smb_pathname_catia_v5tov4(sr, real_name,
440 514 namebuf, sizeof (namebuf))) == NULL) {
441 515 err = EILSEQ;
442 516 break;
443 517 }
444 518
445 519 if ((err = pn_set(&pn, namep)) != 0)
446 520 break;
447 521
448 522 local_flags = 0;
449 523 err = smb_pathname_lookup(&pn, &rpn, local_flags,
450 524 &vp, rootvp, dnode->vp, &attr, cred);
451 525 if (err)
452 526 break;
453 527 }
454 528
455 529 /*
456 530 * This check MUST be done before symlink check
457 531 * since a reparse point is of type VLNK but should
458 532 * not be handled like a regular symlink.
459 533 */
460 534 if (attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) {
461 535 err = EREMOTE;
462 536 VN_RELE(vp);
463 537 break;
464 538 }
465 539
466 540 if ((vp->v_type == VLNK) &&
467 541 ((flags & FOLLOW) || pn_pathleft(&upn))) {
468 542
469 543 if (++nlink > MAXSYMLINKS) {
470 544 err = ELOOP;
471 545 VN_RELE(vp);
472 546 break;
473 547 }
474 548
475 549 (void) pn_alloc(&link_pn);
476 550 err = pn_getsymlink(vp, &link_pn, cred);
477 551 VN_RELE(vp);
478 552
479 553 if (err == 0) {
480 554 if (pn_pathleft(&link_pn) == 0)
481 555 (void) pn_set(&link_pn, ".");
482 556 err = pn_insert(&upn, &link_pn,
483 557 strlen(component));
484 558 }
485 559 pn_free(&link_pn);
486 560
487 561 if (err)
488 562 break;
489 563
490 564 if (upn.pn_pathlen == 0) {
491 565 err = ENOENT;
492 566 break;
493 567 }
494 568
495 569 if (upn.pn_path[0] == '/') {
496 570 fnode = root_node;
497 571 smb_node_ref(fnode);
498 572 }
499 573
500 574 if (pn_fixslash(&upn))
501 575 flags |= FOLLOW;
502 576
503 577 } else {
504 578 if (flags & FIGNORECASE) {
505 579 if (strcmp(rpn.pn_path, "/") != 0)
506 580 pn_setlast(&rpn);
507 581 namep = rpn.pn_path;
508 582 } else {
509 583 namep = pn.pn_path;
510 584 }
511 585
512 586 namep = smb_pathname_catia_v4tov5(sr, namep,
513 587 namebuf, sizeof (namebuf));
514 588
515 589 fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
516 590 dnode, NULL);
517 591 VN_RELE(vp);
518 592
519 593 if (fnode == NULL) {
|
↓ open down ↓ |
84 lines elided |
↑ open up ↑ |
520 594 err = ENOMEM;
521 595 break;
522 596 }
523 597 }
524 598
525 599 while (upn.pn_path[0] == '/') {
526 600 upn.pn_path++;
527 601 upn.pn_pathlen--;
528 602 }
529 603
604 + /*
605 + * If the node we looked up is the root of a filesystem,
606 + * snapshot the lookup so we can replay this after discovering
607 + * the lowest mounted filesystem.
608 + */
609 + if (mnt_pn != NULL &&
610 + (err = VFS_ROOT(fnode->vp->v_vfsp, &fsrootvp)) == 0) {
611 + if (fsrootvp == fnode->vp) {
612 + mnt_pn->pn_pathlen = pn_pathleft(&upn);
613 + mnt_pn->pn_path = mnt_pn->pn_buf +
614 + ((ptrdiff_t)upn.pn_path -
615 + (ptrdiff_t)upn.pn_buf);
616 +
617 + smb_node_ref(fnode);
618 + if (mnt_node != NULL)
619 + smb_node_release(mnt_node);
620 + mnt_node = fnode;
621 +
622 + }
623 + VN_RELE(fsrootvp);
624 + }
530 625 }
531 626
532 627 if ((pathleft) && (err == ENOENT))
533 628 err = ENOTDIR;
534 629
535 - if (err) {
630 + if (mnt_node == NULL)
631 + mnt_pn = NULL;
632 +
633 + /*
634 + * We always want to return a node when we're doing VSS
635 + * (mnt_pn != NULL)
636 + */
637 + if (mnt_pn == NULL && err != 0) {
536 638 if (fnode)
537 639 smb_node_release(fnode);
538 640 if (dnode)
539 641 smb_node_release(dnode);
540 642 } else {
541 - *ret_node = fnode;
643 + if (mnt_pn != NULL) {
644 + *ret_node = mnt_node;
645 + if (fnode != NULL)
646 + smb_node_release(fnode);
647 + } else {
648 + *ret_node = fnode;
649 + }
542 650
543 651 if (dir_node)
544 652 *dir_node = dnode;
545 653 else
546 654 smb_node_release(dnode);
547 655 }
548 656
549 657 kmem_free(component, MAXNAMELEN);
550 658 kmem_free(real_name, MAXNAMELEN);
551 659 (void) pn_free(&pn);
552 660 (void) pn_free(&rpn);
553 661 (void) pn_free(&upn);
554 662
555 663 return (err);
556 664 }
557 665
558 666 /*
559 667 * Holds on dvp and rootvp (if not rootdir) are required by lookuppnvp()
560 668 * and will be released within lookuppnvp().
561 669 */
562 670 static int
563 671 smb_pathname_lookup(pathname_t *pn, pathname_t *rpn, int flags,
564 672 vnode_t **vp, vnode_t *rootvp, vnode_t *dvp, smb_attr_t *attr, cred_t *cred)
565 673 {
566 674 int err;
567 675
568 676 *vp = NULL;
569 677 VN_HOLD(dvp);
570 678 if (rootvp != rootdir)
571 679 VN_HOLD(rootvp);
572 680
573 681 err = lookuppnvp(pn, rpn, flags, NULL, vp, rootvp, dvp, cred);
574 682 if ((err == 0) && (attr != NULL))
575 683 (void) smb_vop_getattr(*vp, NULL, attr, 0, zone_kcred());
576 684
577 685 return (err);
578 686 }
579 687
580 688 /*
581 689 * CATIA Translation of a pathname component prior to passing it to lookuppnvp
582 690 *
583 691 * If the translated component name contains a '/' NULL is returned.
584 692 * The caller should treat this as error EILSEQ. It is not valid to
585 693 * have a directory name with a '/'.
586 694 */
587 695 static char *
588 696 smb_pathname_catia_v5tov4(smb_request_t *sr, char *name,
589 697 char *namebuf, int buflen)
590 698 {
591 699 char *namep;
592 700
593 701 if (SMB_TREE_SUPPORTS_CATIA(sr)) {
594 702 namep = smb_vop_catia_v5tov4(name, namebuf, buflen);
595 703 if (strchr(namep, '/') != NULL)
596 704 return (NULL);
597 705 return (namep);
598 706 }
599 707
600 708 return (name);
601 709 }
602 710
603 711 /*
604 712 * CATIA translation of a pathname component after returning from lookuppnvp
605 713 */
606 714 static char *
607 715 smb_pathname_catia_v4tov5(smb_request_t *sr, char *name,
608 716 char *namebuf, int buflen)
609 717 {
610 718 if (SMB_TREE_SUPPORTS_CATIA(sr)) {
611 719 smb_vop_catia_v4tov5(name, namebuf, buflen);
612 720 return (namebuf);
613 721 }
614 722
615 723 return (name);
616 724 }
617 725
618 726 /*
619 727 * sr - needed to check for case sense
620 728 * path - non mangled path needed to be looked up from the startvp
621 729 * startvp - the vnode to start the lookup from
622 730 * rootvp - the vnode of the root of the filesystem
623 731 * returns the vnode found when starting at startvp and using the path
624 732 *
625 733 * Finds a vnode starting at startvp and parsing the non mangled path
626 734 */
627 735
628 736 vnode_t *
629 737 smb_lookuppathvptovp(smb_request_t *sr, char *path, vnode_t *startvp,
630 738 vnode_t *rootvp)
631 739 {
632 740 pathname_t pn;
633 741 vnode_t *vp = NULL;
634 742 int lookup_flags = FOLLOW;
635 743
636 744 if (SMB_TREE_IS_CASEINSENSITIVE(sr))
637 745 lookup_flags |= FIGNORECASE;
638 746
639 747 (void) pn_alloc(&pn);
640 748
641 749 if (pn_set(&pn, path) == 0) {
642 750 VN_HOLD(startvp);
643 751 if (rootvp != rootdir)
644 752 VN_HOLD(rootvp);
645 753
646 754 /* lookuppnvp should release the holds */
647 755 if (lookuppnvp(&pn, NULL, lookup_flags, NULL, &vp,
648 756 rootvp, startvp, zone_kcred()) != 0) {
649 757 pn_free(&pn);
650 758 return (NULL);
651 759 }
652 760 }
653 761
654 762 pn_free(&pn);
655 763 return (vp);
656 764 }
657 765
658 766 /*
659 767 * smb_pathname_init
660 768 * Parse path: pname\\fname:sname:stype
661 769 *
662 770 * Elements of the smb_pathname_t structure are allocated using request
663 771 * specific storage and will be free'd when the sr is destroyed.
664 772 *
665 773 * Populate pn structure elements with the individual elements
666 774 * of pn->pn_path. pn->pn_sname will contain the whole stream name
667 775 * including the stream type and preceding colon: :sname:%DATA
668 776 * pn_stype will point to the stream type within pn_sname.
669 777 *
670 778 * If the pname element is missing pn_pname will be set to NULL.
671 779 * If any other element is missing the pointer in pn will be NULL.
672 780 */
673 781 void
674 782 smb_pathname_init(smb_request_t *sr, smb_pathname_t *pn, char *path)
675 783 {
676 784 char *pname, *fname, *sname;
677 785 int len;
678 786
679 787 bzero(pn, sizeof (smb_pathname_t));
680 788 pn->pn_path = smb_pathname_strdup(sr, path);
681 789
682 790 smb_pathname_preprocess(sr, pn);
683 791
684 792 /* parse pn->pn_path into its constituent parts */
685 793 pname = pn->pn_path;
686 794 fname = strrchr(pn->pn_path, '\\');
687 795
688 796 if (fname) {
689 797 if (fname == pname) {
690 798 pn->pn_pname = NULL;
691 799 } else {
692 800 *fname = '\0';
693 801 pn->pn_pname =
694 802 smb_pathname_strdup(sr, pname);
695 803 *fname = '\\';
696 804 }
697 805 ++fname;
698 806 } else {
699 807 fname = pname;
700 808 pn->pn_pname = NULL;
701 809 }
702 810
703 811 if (fname[0] == '\0') {
704 812 pn->pn_fname = NULL;
705 813 return;
706 814 }
707 815
708 816 if (!smb_is_stream_name(fname)) {
709 817 pn->pn_fname = smb_pathname_strdup(sr, fname);
710 818 return;
711 819 }
712 820
713 821 /*
714 822 * find sname and stype in fname.
715 823 * sname can't be NULL smb_is_stream_name checks this
716 824 */
717 825 sname = strchr(fname, ':');
718 826 if (sname == fname)
719 827 fname = NULL;
720 828 else {
721 829 *sname = '\0';
722 830 pn->pn_fname =
723 831 smb_pathname_strdup(sr, fname);
724 832 *sname = ':';
725 833 }
726 834
727 835 pn->pn_sname = smb_pathname_strdup(sr, sname);
728 836 pn->pn_stype = strchr(pn->pn_sname + 1, ':');
729 837 if (pn->pn_stype) {
730 838 (void) smb_strupr(pn->pn_stype);
731 839 } else {
732 840 len = strlen(pn->pn_sname);
733 841 pn->pn_sname = smb_pathname_strcat(sr, pn->pn_sname, ":$DATA");
734 842 pn->pn_stype = pn->pn_sname + len;
735 843 }
736 844 ++pn->pn_stype;
737 845 }
738 846
739 847 /*
740 848 * smb_pathname_preprocess
741 849 *
742 850 * Perform common pre-processing of pn->pn_path:
743 851 * - if the pn_path is blank, set it to '\\'
744 852 * - perform unicode wildcard converstion.
745 853 * - convert any '/' to '\\'
746 854 * - eliminate duplicate slashes
747 855 * - remove trailing slashes
748 856 * - quota directory specific pre-processing
749 857 */
750 858 static void
751 859 smb_pathname_preprocess(smb_request_t *sr, smb_pathname_t *pn)
752 860 {
753 861 char *p;
754 862
755 863 /* treat empty path as "\\" */
756 864 if (strlen(pn->pn_path) == 0) {
757 865 pn->pn_path = smb_pathname_strdup(sr, "\\");
758 866 return;
759 867 }
760 868
761 869 if (sr->session->dialect < NT_LM_0_12)
762 870 smb_convert_wildcards(pn->pn_path);
763 871
764 872 /* treat '/' as '\\' */
765 873 (void) strsubst(pn->pn_path, '/', '\\');
766 874
767 875 (void) strcanon(pn->pn_path, "\\");
768 876
769 877 /* remove trailing '\\' */
770 878 p = pn->pn_path + strlen(pn->pn_path) - 1;
771 879 if ((p != pn->pn_path) && (*p == '\\'))
772 880 *p = '\0';
773 881
774 882 smb_pathname_preprocess_quota(sr, pn);
775 883 smb_pathname_preprocess_adminshare(sr, pn);
776 884 }
777 885
778 886 /*
779 887 * smb_pathname_preprocess_quota
780 888 *
781 889 * There is a special file required by windows so that the quota
782 890 * tab will be displayed by windows clients. This is created in
783 891 * a special directory, $EXTEND, at the root of the shared file
784 892 * system. To hide this directory prepend a '.' (dot).
785 893 */
786 894 static void
787 895 smb_pathname_preprocess_quota(smb_request_t *sr, smb_pathname_t *pn)
788 896 {
789 897 char *name = "$EXTEND";
790 898 char *new_name = ".$EXTEND";
791 899 char *p, *slash;
792 900 int len;
793 901
794 902 if (!smb_node_is_vfsroot(sr->tid_tree->t_snode))
795 903 return;
796 904
797 905 p = pn->pn_path;
798 906
799 907 /* ignore any initial "\\" */
800 908 p += strspn(p, "\\");
801 909 if (smb_strcasecmp(p, name, strlen(name)) != 0)
802 910 return;
803 911
804 912 p += strlen(name);
805 913 if ((*p != ':') && (*p != '\\') && (*p != '\0'))
806 914 return;
807 915
808 916 slash = (pn->pn_path[0] == '\\') ? "\\" : "";
809 917 len = strlen(pn->pn_path) + 2;
810 918 pn->pn_path = smb_srm_alloc(sr, len);
811 919 (void) snprintf(pn->pn_path, len, "%s%s%s", slash, new_name, p);
812 920 (void) smb_strupr(pn->pn_path);
813 921 }
814 922
815 923 /*
816 924 * smb_pathname_preprocess_adminshare
817 925 *
818 926 * Convert any path with share name "C$" or "c$" (Admin share) in to lower case.
819 927 */
820 928 static void
821 929 smb_pathname_preprocess_adminshare(smb_request_t *sr, smb_pathname_t *pn)
822 930 {
823 931 if (strcasecmp(sr->tid_tree->t_sharename, "c$") == 0)
824 932 (void) smb_strlwr(pn->pn_path);
825 933 }
826 934
827 935 /*
828 936 * smb_pathname_strdup
829 937 *
830 938 * Duplicate NULL terminated string s.
831 939 *
832 940 * The new string is allocated using request specific storage and will
833 941 * be free'd when the sr is destroyed.
834 942 */
835 943 static char *
836 944 smb_pathname_strdup(smb_request_t *sr, const char *s)
837 945 {
838 946 char *s2;
839 947 size_t n;
840 948
841 949 n = strlen(s) + 1;
842 950 s2 = smb_srm_zalloc(sr, n);
843 951 (void) strlcpy(s2, s, n);
844 952 return (s2);
845 953 }
846 954
847 955 /*
848 956 * smb_pathname_strcat
849 957 *
850 958 * Reallocate NULL terminated string s1 to accommodate
851 959 * concatenating NULL terminated string s2.
852 960 * Append s2 and return resulting NULL terminated string.
853 961 *
854 962 * The string buffer is reallocated using request specific
855 963 * storage and will be free'd when the sr is destroyed.
856 964 */
857 965 static char *
858 966 smb_pathname_strcat(smb_request_t *sr, char *s1, const char *s2)
859 967 {
860 968 size_t n;
861 969
862 970 n = strlen(s1) + strlen(s2) + 1;
863 971 s1 = smb_srm_rezalloc(sr, s1, n);
864 972 (void) strlcat(s1, s2, n);
865 973 return (s1);
866 974 }
867 975
868 976 /*
869 977 * smb_pathname_validate
870 978 *
871 979 * Perform basic validation of pn:
872 980 * - If first component of pn->path is ".." -> PATH_SYNTAX_BAD
873 981 * - If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID
874 982 * - If fname is "." -> INVALID_OBJECT_NAME
875 983 *
876 984 * On unix .. at the root of a file system links to the root. Thus
877 985 * an attempt to lookup "/../../.." will be the same as looking up "/"
878 986 * CIFs clients expect the above to result in
879 987 * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible
880 988 * (and questionable if it's desirable) to deal with all cases
881 989 * but paths beginning with \\.. are handled.
882 990 *
883 991 * Returns: B_TRUE if pn is valid,
884 992 * otherwise returns B_FALSE and sets error status in sr.
885 993 *
886 994 * XXX: Get rid of smbsr_error calls for SMB2
887 995 */
888 996 boolean_t
889 997 smb_pathname_validate(smb_request_t *sr, smb_pathname_t *pn)
890 998 {
891 999 char *path = pn->pn_path;
892 1000
893 1001 /* ignore any initial "\\" */
894 1002 path += strspn(path, "\\");
895 1003
896 1004 /* If first component of path is ".." -> PATH_SYNTAX_BAD */
897 1005 if ((strcmp(path, "..") == 0) || (strncmp(path, "..\\", 3) == 0)) {
898 1006 smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
899 1007 ERRDOS, ERROR_BAD_PATHNAME);
|
↓ open down ↓ |
348 lines elided |
↑ open up ↑ |
900 1008 return (B_FALSE);
901 1009 }
902 1010
903 1011 /* If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID */
904 1012 if (pn->pn_pname && smb_contains_wildcards(pn->pn_pname)) {
905 1013 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
906 1014 ERRDOS, ERROR_INVALID_NAME);
907 1015 return (B_FALSE);
908 1016 }
909 1017
910 - /* If fname is "." -> INVALID_OBJECT_NAME */
1018 + /* If fname is "." -> OBJECT_NAME_INVALID */
911 1019 if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) {
912 1020 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
913 - ERRDOS, ERROR_PATH_NOT_FOUND);
1021 + ERRDOS, ERROR_INVALID_NAME);
914 1022 return (B_FALSE);
915 1023 }
916 1024
917 1025 return (B_TRUE);
918 1026 }
919 1027
920 1028 /*
921 1029 * smb_validate_dirname
922 1030 *
923 1031 * smb_pathname_validate() should have already been performed on pn.
924 1032 *
925 1033 * Very basic directory name validation: checks for colons in a path.
926 1034 * Need to skip the drive prefix since it contains a colon.
927 1035 *
928 1036 * Returns: B_TRUE if the name is valid,
929 1037 * otherwise returns B_FALSE and sets error status in sr.
930 1038 */
931 1039 boolean_t
932 1040 smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn)
933 1041 {
934 1042 char *name;
935 1043 char *path = pn->pn_path;
936 1044
937 1045 if ((name = path) != 0) {
938 1046 name += strspn(name, "\\");
939 1047
940 1048 if (strchr(name, ':') != 0) {
941 1049 smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
942 1050 ERRDOS, ERROR_INVALID_NAME);
943 1051 return (B_FALSE);
944 1052 }
945 1053 }
946 1054
947 1055 return (B_TRUE);
948 1056 }
949 1057
950 1058 /*
951 1059 * smb_validate_object_name
952 1060 *
953 1061 * smb_pathname_validate() should have already been pertformed on pn.
954 1062 *
955 1063 * Very basic file name validation.
956 1064 * For filenames, we check for names of the form "AAAn:". Names that
957 1065 * contain three characters, a single digit and a colon (:) are reserved
958 1066 * as DOS device names, i.e. "COM1:".
959 1067 * Stream name validation is handed off to smb_validate_stream_name
960 1068 *
961 1069 * Returns: B_TRUE if pn->pn_fname is valid,
962 1070 * otherwise returns B_FALSE and sets error status in sr.
963 1071 */
964 1072 boolean_t
965 1073 smb_validate_object_name(smb_request_t *sr, smb_pathname_t *pn)
966 1074 {
967 1075 if (pn->pn_fname &&
968 1076 strlen(pn->pn_fname) == 5 &&
969 1077 smb_isdigit(pn->pn_fname[3]) &&
970 1078 pn->pn_fname[4] == ':') {
971 1079 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
972 1080 ERRDOS, ERROR_INVALID_NAME);
973 1081 return (B_FALSE);
974 1082 }
975 1083
976 1084 if (pn->pn_sname)
|
↓ open down ↓ |
53 lines elided |
↑ open up ↑ |
977 1085 return (smb_validate_stream_name(sr, pn));
978 1086
979 1087 return (B_TRUE);
980 1088 }
981 1089
982 1090 /*
983 1091 * smb_stream_parse_name
984 1092 *
985 1093 * smb_stream_parse_name should only be called for a path that
986 1094 * contains a valid named stream. Path validation should have
987 - * been performed before this function is called.
1095 + * been performed before this function is called, typically by
1096 + * calling smb_is_stream_name() just before this.
988 1097 *
989 1098 * Find the last component of path and split it into filename
990 1099 * and stream name.
991 1100 *
992 1101 * On return the named stream type will be present. The stream
993 1102 * type defaults to ":$DATA", if it has not been defined
994 - * For exmaple, 'stream' contains :<sname>:$DATA
1103 + * For example, 'stream' contains :<sname>:$DATA
1104 + *
1105 + * Output args: filename, stream both MAXNAMELEN
995 1106 */
996 1107 void
997 1108 smb_stream_parse_name(char *path, char *filename, char *stream)
998 1109 {
999 1110 char *fname, *sname, *stype;
1111 + size_t flen, slen;
1000 1112
1001 1113 ASSERT(path);
1002 1114 ASSERT(filename);
1003 1115 ASSERT(stream);
1004 1116
1005 1117 fname = strrchr(path, '\\');
1006 1118 fname = (fname == NULL) ? path : fname + 1;
1007 - (void) strlcpy(filename, fname, MAXNAMELEN);
1119 + sname = strchr(fname, ':');
1120 + /* Caller makes sure there is a ':' in path. */
1121 + VERIFY(sname != NULL);
1122 + /* LINTED: possible ptrdiff_t overflow */
1123 + flen = sname - fname;
1124 + slen = strlen(sname);
1008 1125
1009 - sname = strchr(filename, ':');
1010 - (void) strlcpy(stream, sname, MAXNAMELEN);
1011 - *sname = '\0';
1126 + if (flen > (MAXNAMELEN-1))
1127 + flen = (MAXNAMELEN-1);
1128 + (void) strncpy(filename, fname, flen);
1129 + filename[flen] = '\0';
1012 1130
1131 + if (slen > (MAXNAMELEN-1))
1132 + slen = (MAXNAMELEN-1);
1133 + (void) strncpy(stream, sname, slen);
1134 + stream[slen] = '\0';
1135 +
1136 + /* Add a "stream type" if there isn't one. */
1013 1137 stype = strchr(stream + 1, ':');
1014 1138 if (stype == NULL)
1015 1139 (void) strlcat(stream, ":$DATA", MAXNAMELEN);
1016 1140 else
1017 1141 (void) smb_strupr(stype);
1018 1142 }
1019 1143
1020 1144 /*
1021 1145 * smb_is_stream_name
1022 1146 *
1023 1147 * Determines if 'path' specifies a named stream.
1024 1148 *
1025 1149 * path is a NULL terminated string which could be a stream path.
1026 1150 * [pathname/]fname[:stream_name[:stream_type]]
1027 1151 *
1028 1152 * - If there is no colon in the path or it's the last char
1029 1153 * then it's not a stream name
1030 1154 *
1031 1155 * - '::' is a non-stream and is commonly used by Windows to designate
1032 1156 * the unamed stream in the form "::$DATA"
1033 1157 */
1034 1158 boolean_t
1035 1159 smb_is_stream_name(char *path)
1036 1160 {
1037 1161 char *colonp;
1038 1162
1039 1163 if (path == NULL)
1040 1164 return (B_FALSE);
1041 1165
1042 1166 colonp = strchr(path, ':');
|
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
1043 1167 if ((colonp == NULL) || (*(colonp+1) == '\0'))
1044 1168 return (B_FALSE);
1045 1169
1046 1170 if (strstr(path, "::"))
1047 1171 return (B_FALSE);
1048 1172
1049 1173 return (B_TRUE);
1050 1174 }
1051 1175
1052 1176 /*
1177 + * Is this stream node a "restricted" type?
1178 + */
1179 +boolean_t
1180 +smb_strname_restricted(char *strname)
1181 +{
1182 + char *stype;
1183 +
1184 + stype = strrchr(strname, ':');
1185 + if (stype == NULL)
1186 + return (B_FALSE);
1187 +
1188 + /*
1189 + * Only ":$CA" is restricted (for now).
1190 + */
1191 + if (strcmp(stype, ":$CA") == 0)
1192 + return (B_TRUE);
1193 +
1194 + return (B_FALSE);
1195 +}
1196 +
1197 +/*
1053 1198 * smb_validate_stream_name
1054 1199 *
1055 1200 * B_FALSE will be returned, and the error status ser in the sr, if:
1056 1201 * - the path is not a stream name
1057 1202 * - a path is specified but the fname is ommitted.
1058 1203 * - the stream_type is specified but not valid.
1059 1204 *
1060 1205 * Note: the stream type is case-insensitive.
1061 1206 */
1062 1207 boolean_t
1063 1208 smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn)
1064 1209 {
1065 1210 static char *strmtype[] = {
1211 + "$CA",
1066 1212 "$DATA",
1067 1213 "$INDEX_ALLOCATION"
1068 1214 };
1069 1215 int i;
1070 1216
1071 1217 ASSERT(pn);
1072 1218 ASSERT(pn->pn_sname);
1073 1219
1074 1220 if ((!(pn->pn_sname)) ||
1075 1221 ((pn->pn_pname) && !(pn->pn_fname))) {
1076 1222 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
1077 1223 ERRDOS, ERROR_INVALID_NAME);
1078 1224 return (B_FALSE);
1079 1225 }
1080 1226
1081 1227
1082 1228 if (pn->pn_stype != NULL) {
1083 1229 for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) {
1084 1230 if (strcasecmp(pn->pn_stype, strmtype[i]) == 0)
1085 1231 return (B_TRUE);
1086 1232 }
1087 1233
1088 1234 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
1089 1235 ERRDOS, ERROR_INVALID_NAME);
1090 1236 return (B_FALSE);
1091 1237 }
1092 1238
1093 1239 return (B_TRUE);
1094 1240 }
1095 1241
1096 1242 /*
1097 1243 * valid DFS I/O path:
1098 1244 *
1099 1245 * \server-or-domain\share
1100 1246 * \server-or-domain\share\path
1101 1247 *
1102 1248 * All the returned errors by this function needs to be
1103 1249 * checked against Windows.
1104 1250 */
1105 1251 static int
1106 1252 smb_pathname_dfs_preprocess(smb_request_t *sr, char *path, size_t pathsz)
1107 1253 {
1108 1254 smb_unc_t unc;
1109 1255 char *linkpath;
1110 1256 int rc;
1111 1257
1112 1258 if (sr->tid_tree == NULL)
1113 1259 return (0);
1114 1260
1115 1261 if ((rc = smb_unc_init(path, &unc)) != 0)
1116 1262 return (rc);
1117 1263
1118 1264 if (smb_strcasecmp(unc.unc_share, sr->tid_tree->t_sharename, 0)) {
1119 1265 smb_unc_free(&unc);
1120 1266 return (EINVAL);
1121 1267 }
1122 1268
1123 1269 linkpath = unc.unc_path;
1124 1270 (void) snprintf(path, pathsz, "/%s", (linkpath) ? linkpath : "");
1125 1271
1126 1272 smb_unc_free(&unc);
1127 1273 return (0);
1128 1274 }
|
↓ open down ↓ |
53 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX