1 /*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $
33 */
34
35 /*
36 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
37 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
38 * Use is subject to license terms.
39 */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/time.h>
44 #include <sys/vnode.h>
45 #include <sys/sunddi.h>
46 #include <sys/cmn_err.h>
47
48 #include <netsmb/smb_osdep.h>
49
50 #include <netsmb/smb.h>
51 #include <netsmb/smb_conn.h>
52 #include <netsmb/smb_subr.h>
53 #include <netsmb/smb_rq.h>
54
55 #include <smbfs/smbfs.h>
56 #include <smbfs/smbfs_node.h>
57 #include <smbfs/smbfs_subr.h>
58
59 /*
60 * Jan 1 1980 as 64 bit NT time.
61 * (tenths of microseconds since 1601)
62 */
63 const uint64_t NT1980 = 11960035200ULL*10000000ULL;
64
65 /*
66 * Local functions.
67 * Not static, to aid debugging.
68 */
69
70 int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
71 struct smbfattr *fap, struct smb_cred *scrp);
72 int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
73 struct smb_cred *scrp, uint16_t infolevel);
74
75 int smbfs_smb_statfsLM1(struct smb_share *ssp,
76 statvfs64_t *sbp, struct smb_cred *scrp);
77 int smbfs_smb_statfsLM2(struct smb_share *ssp,
78 statvfs64_t *sbp, struct smb_cred *scrp);
79
80 int smbfs_smb_setfattrNT(struct smbnode *np, int fid,
81 uint32_t attr, struct timespec *mtime, struct timespec *atime,
82 struct smb_cred *scrp);
83
84 int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
85 struct timespec *mtime, struct timespec *atime,
86 struct smb_cred *scrp);
87
88 int smbfs_smb_setpattr1(struct smbnode *np,
89 const char *name, int len, uint32_t attr,
90 struct timespec *mtime, struct smb_cred *scrp);
91
92
93 /*
94 * Todo: locking over-the-wire
95 */
96 #ifdef APPLE
97
98 static int
smbfs_smb_lockandx(struct smbnode * np,int op,uint32_t pid,offset_t start,uint64_t len,int largelock,struct smb_cred * scrp,uint32_t timeout)99 smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
100 offset_t start, uint64_t len, int largelock,
101 struct smb_cred *scrp, uint32_t timeout)
102 {
103 struct smb_share *ssp = np->n_mount->smi_share;
104 struct smb_rq rq, *rqp = &rq;
105 struct mbchain *mbp;
106 uint8_t ltype = 0;
107 int error;
108
109 /* Shared lock for n_fid use below. */
110 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
111
112 /* After reconnect, n_fid is invalid */
113 if (np->n_vcgenid != ssp->ss_vcgenid)
114 return (ESTALE);
115
116 if (op == SMB_LOCK_SHARED)
117 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
118 /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
119 if (largelock)
120 ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
121 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
122 if (error)
123 return (error);
124 smb_rq_getrequest(rqp, &mbp);
125 smb_rq_wstart(rqp);
126 mb_put_uint8(mbp, 0xff); /* secondary command */
127 mb_put_uint8(mbp, 0); /* MBZ */
128 mb_put_uint16le(mbp, 0);
129 mb_put_uint16le(mbp, np->n_fid);
130 mb_put_uint8(mbp, ltype); /* locktype */
131 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
132 mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
133 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
134 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
135 smb_rq_wend(rqp);
136 smb_rq_bstart(rqp);
137 mb_put_uint16le(mbp, pid);
138 if (!largelock) {
139 mb_put_uint32le(mbp, start);
140 mb_put_uint32le(mbp, len);
141 } else {
142 mb_put_uint16le(mbp, 0); /* pad */
143 mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
144 mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
145 mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
146 mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
147 }
148 smb_rq_bend(rqp);
149 /*
150 * Don't want to risk missing a successful
151 * unlock send or lock response, or we could
152 * lose track of an outstanding lock.
153 */
154 if (op == SMB_LOCK_RELEASE)
155 rqp->sr_flags |= SMBR_NOINTR_SEND;
156 else
157 rqp->sr_flags |= SMBR_NOINTR_RECV;
158
159 error = smb_rq_simple(rqp);
160 smb_rq_done(rqp);
161 return (error);
162 }
163
164 int
smbfs_smb_lock(struct smbnode * np,int op,caddr_t id,offset_t start,uint64_t len,int largelock,struct smb_cred * scrp,uint32_t timeout)165 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
166 offset_t start, uint64_t len, int largelock,
167 struct smb_cred *scrp, uint32_t timeout)
168 {
169 struct smb_share *ssp = np->n_mount->smi_share;
170
171 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
172 /*
173 * TODO: use LOCK_BYTE_RANGE here.
174 */
175 return (EINVAL);
176
177 /*
178 * XXX: compute largelock via:
179 * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)?
180 */
181 return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
182 largelock, scrp, timeout));
183 }
184
185 #endif /* APPLE */
186
187 /*
188 * Helper for smbfs_getattr
189 * Something like nfs_getattr_otw
190 */
191 int
smbfs_smb_getfattr(struct smbnode * np,struct smbfattr * fap,struct smb_cred * scrp)192 smbfs_smb_getfattr(
193 struct smbnode *np,
194 struct smbfattr *fap,
195 struct smb_cred *scrp)
196 {
197 int error;
198
199 /*
200 * This lock is necessary for FID-based calls.
201 * Lock may be writer (via open) or reader.
202 */
203 ASSERT(np->r_lkserlock.count != 0);
204
205 /*
206 * Extended attribute directory or file.
207 */
208 if (np->n_flag & N_XATTR) {
209 error = smbfs_xa_getfattr(np, fap, scrp);
210 return (error);
211 }
212
213 error = smbfs_smb_trans2_query(np, fap, scrp, 0);
214 if (error != EINVAL)
215 return (error);
216
217 /* fallback */
218 error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
219
220 return (error);
221 }
222
223 /*
224 * Common function for QueryFileInfo, QueryPathInfo.
225 */
226 int
smbfs_smb_trans2_query(struct smbnode * np,struct smbfattr * fap,struct smb_cred * scrp,uint16_t infolevel)227 smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
228 struct smb_cred *scrp, uint16_t infolevel)
229 {
230 struct smb_share *ssp = np->n_mount->smi_share;
231 struct smb_vc *vcp = SSTOVC(ssp);
232 struct smb_t2rq *t2p;
233 int error, svtz, timesok = 1;
234 struct mbchain *mbp;
235 struct mdchain *mdp;
236 uint16_t cmd, date, time, wattr;
237 uint64_t llongint, lsize;
238 uint32_t size, dattr;
239
240 /*
241 * Shared lock for n_fid use below.
242 * See smbfs_smb_getfattr()
243 */
244 ASSERT(np->r_lkserlock.count != 0);
245
246 /*
247 * If we have a valid open FID, use it.
248 */
249 if ((np->n_fidrefs > 0) &&
250 (np->n_fid != SMB_FID_UNUSED) &&
251 (np->n_vcgenid == ssp->ss_vcgenid))
252 cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
253 else
254 cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
255
256 top:
257 error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
258 if (error)
259 return (error);
260 mbp = &t2p->t2_tparam;
261 mb_init(mbp);
262 if (!infolevel) {
263 if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
264 infolevel = SMB_QFILEINFO_STANDARD;
265 else
266 infolevel = SMB_QFILEINFO_ALL_INFO;
267 }
268
269 if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
270 mb_put_uint16le(mbp, np->n_fid);
271
272 mb_put_uint16le(mbp, infolevel);
273
274 if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
275 mb_put_uint32le(mbp, 0);
276 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
277 error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
278 if (error) {
279 smb_t2_done(t2p);
280 return (error);
281 }
282 }
283
284 t2p->t2_maxpcount = 2;
285 t2p->t2_maxdcount = vcp->vc_txmax;
286 error = smb_t2_request(t2p);
287 if (error) {
288 smb_t2_done(t2p);
289 /* Invalid info level? Try fallback. */
290 if (error == EINVAL &&
291 infolevel == SMB_QFILEINFO_ALL_INFO) {
292 infolevel = SMB_QFILEINFO_STANDARD;
293 goto top;
294 }
295 return (error);
296 }
297 mdp = &t2p->t2_rdata;
298 svtz = vcp->vc_sopt.sv_tz;
299 switch (infolevel) {
300 case SMB_QFILEINFO_STANDARD:
301 md_get_uint16le(mdp, &date);
302 md_get_uint16le(mdp, &time); /* creation time */
303 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime);
304 md_get_uint16le(mdp, &date);
305 md_get_uint16le(mdp, &time); /* access time */
306 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
307 md_get_uint16le(mdp, &date);
308 md_get_uint16le(mdp, &time); /* modify time */
309 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
310 md_get_uint32le(mdp, &size); /* EOF position */
311 fap->fa_size = size;
312 md_get_uint32le(mdp, &size); /* allocation size */
313 fap->fa_allocsz = size;
314 error = md_get_uint16le(mdp, &wattr);
315 fap->fa_attr = wattr;
316 timesok = 1;
317 break;
318 case SMB_QFILEINFO_ALL_INFO:
319 timesok = 0;
320 /* creation time */
321 md_get_uint64le(mdp, &llongint);
322 if (llongint)
323 timesok++;
324 smb_time_NT2local(llongint, &fap->fa_createtime);
325
326 /* last access time */
327 md_get_uint64le(mdp, &llongint);
328 if (llongint)
329 timesok++;
330 smb_time_NT2local(llongint, &fap->fa_atime);
331
332 /* last write time */
333 md_get_uint64le(mdp, &llongint);
334 if (llongint)
335 timesok++;
336 smb_time_NT2local(llongint, &fap->fa_mtime);
337
338 /* last change time */
339 md_get_uint64le(mdp, &llongint);
340 if (llongint)
341 timesok++;
342 smb_time_NT2local(llongint, &fap->fa_ctime);
343
344 /* attributes */
345 md_get_uint32le(mdp, &dattr);
346 fap->fa_attr = dattr;
347
348 /*
349 * 4-Byte alignment - discard
350 * Specs don't talk about this.
351 */
352 md_get_uint32le(mdp, NULL);
353 /* allocation size */
354 md_get_uint64le(mdp, &lsize);
355 fap->fa_allocsz = lsize;
356 /* File size */
357 error = md_get_uint64le(mdp, &lsize);
358 fap->fa_size = lsize;
359 break;
360 default:
361 SMBVDEBUG("unexpected info level %d\n", infolevel);
362 error = EINVAL;
363 }
364 smb_t2_done(t2p);
365 /*
366 * if all times are zero (observed with FAT on NT4SP6)
367 * then fall back to older info level
368 */
369 if (!timesok) {
370 if (infolevel == SMB_QFILEINFO_ALL_INFO) {
371 infolevel = SMB_QFILEINFO_STANDARD;
372 goto top;
373 }
374 error = EINVAL;
375 }
376 return (error);
377 }
378
379 /*
380 * Support functions for _qstreaminfo
381 * Moved to smbfs_xattr.c
382 */
383
384 int
smbfs_smb_qfsattr(struct smb_share * ssp,struct smb_fs_attr_info * fsa,struct smb_cred * scrp)385 smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
386 struct smb_cred *scrp)
387 {
388 struct smb_t2rq *t2p;
389 struct mbchain *mbp;
390 struct mdchain *mdp;
391 int error;
392 uint32_t nlen;
393
394 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
395 scrp, &t2p);
396 if (error)
397 return (error);
398 mbp = &t2p->t2_tparam;
399 mb_init(mbp);
400 mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
401 t2p->t2_maxpcount = 4;
402 t2p->t2_maxdcount = 4 * 3 + 512;
403 error = smb_t2_request(t2p);
404 if (error)
405 goto out;
406
407 mdp = &t2p->t2_rdata;
408 md_get_uint32le(mdp, &fsa->fsa_aflags);
409 md_get_uint32le(mdp, &fsa->fsa_maxname);
410 error = md_get_uint32le(mdp, &nlen); /* fs name length */
411 if (error)
412 goto out;
413
414 /*
415 * Get the FS type name.
416 */
417 bzero(fsa->fsa_tname, FSTYPSZ);
418 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
419 uint16_t tmpbuf[FSTYPSZ];
420 size_t tmplen, outlen;
421
422 if (nlen > sizeof (tmpbuf))
423 nlen = sizeof (tmpbuf);
424 error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
425 tmplen = nlen / 2; /* UCS-2 chars */
426 outlen = FSTYPSZ - 1;
427 (void) uconv_u16tou8(tmpbuf, &tmplen,
428 (uchar_t *)fsa->fsa_tname, &outlen,
429 UCONV_IN_LITTLE_ENDIAN);
430 } else {
431 if (nlen > (FSTYPSZ - 1))
432 nlen = FSTYPSZ - 1;
433 error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
434 }
435
436 /*
437 * If fs_name starts with FAT, we can't set dates before 1980
438 */
439 if (0 == strncmp(fsa->fsa_tname, "FAT", 3)) {
440 SMB_SS_LOCK(ssp);
441 ssp->ss_flags |= SMBS_FST_FAT;
442 SMB_SS_UNLOCK(ssp);
443 }
444
445 out:
446 smb_t2_done(t2p);
447 return (0);
448 }
449
450 int
smbfs_smb_statfs(struct smb_share * ssp,statvfs64_t * sbp,struct smb_cred * scp)451 smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
452 struct smb_cred *scp)
453 {
454 int error;
455
456 if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
457 error = smbfs_smb_statfsLM2(ssp, sbp, scp);
458 else
459 error = smbfs_smb_statfsLM1(ssp, sbp, scp);
460
461 return (error);
462 }
463
464 int
smbfs_smb_statfsLM2(struct smb_share * ssp,statvfs64_t * sbp,struct smb_cred * scrp)465 smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
466 struct smb_cred *scrp)
467 {
468 struct smb_t2rq *t2p;
469 struct mbchain *mbp;
470 struct mdchain *mdp;
471 uint16_t bsize;
472 uint32_t units, bpu, funits;
473 uint64_t s, t, f;
474 int error;
475
476 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
477 scrp, &t2p);
478 if (error)
479 return (error);
480 mbp = &t2p->t2_tparam;
481 mb_init(mbp);
482 mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
483 t2p->t2_maxpcount = 4;
484 t2p->t2_maxdcount = 4 * 4 + 2;
485 error = smb_t2_request(t2p);
486 if (error)
487 goto out;
488
489 mdp = &t2p->t2_rdata;
490 md_get_uint32le(mdp, NULL); /* fs id */
491 md_get_uint32le(mdp, &bpu);
492 md_get_uint32le(mdp, &units);
493 md_get_uint32le(mdp, &funits);
494 error = md_get_uint16le(mdp, &bsize);
495 if (error)
496 goto out;
497 s = bsize;
498 s *= bpu;
499 t = units;
500 f = funits;
501 /*
502 * Don't allow over-large blocksizes as they determine
503 * Finder List-view size granularities. On the other
504 * hand, we mustn't let the block count overflow the
505 * 31 bits available.
506 */
507 while (s > 16 * 1024) {
508 if (t > LONG_MAX)
509 break;
510 s /= 2;
511 t *= 2;
512 f *= 2;
513 }
514 while (t > LONG_MAX) {
515 t /= 2;
516 f /= 2;
517 s *= 2;
518 }
519 sbp->f_bsize = (ulong_t)s; /* file system block size */
520 sbp->f_blocks = t; /* total data blocks in file system */
521 sbp->f_bfree = f; /* free blocks in fs */
522 sbp->f_bavail = f; /* free blocks avail to non-superuser */
523 sbp->f_files = (-1); /* total file nodes in file system */
524 sbp->f_ffree = (-1); /* free file nodes in fs */
525
526 out:
527 smb_t2_done(t2p);
528 return (0);
529 }
530
531 int
smbfs_smb_statfsLM1(struct smb_share * ssp,statvfs64_t * sbp,struct smb_cred * scrp)532 smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
533 struct smb_cred *scrp)
534 {
535 struct smb_rq rq, *rqp = &rq;
536 struct mdchain *mdp;
537 uint16_t units, bpu, bsize, funits;
538 uint64_t s, t, f;
539 int error;
540
541 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
542 scrp);
543 if (error)
544 return (error);
545 smb_rq_wstart(rqp);
546 smb_rq_wend(rqp);
547 smb_rq_bstart(rqp);
548 smb_rq_bend(rqp);
549 error = smb_rq_simple(rqp);
550 if (error)
551 goto out;
552
553 smb_rq_getreply(rqp, &mdp);
554 md_get_uint16le(mdp, &units);
555 md_get_uint16le(mdp, &bpu);
556 md_get_uint16le(mdp, &bsize);
557 error = md_get_uint16le(mdp, &funits);
558 if (error)
559 goto out;
560 s = bsize;
561 s *= bpu;
562 t = units;
563 f = funits;
564 /*
565 * Don't allow over-large blocksizes as they determine
566 * Finder List-view size granularities. On the other
567 * hand, we mustn't let the block count overflow the
568 * 31 bits available.
569 */
570 while (s > 16 * 1024) {
571 if (t > LONG_MAX)
572 break;
573 s /= 2;
574 t *= 2;
575 f *= 2;
576 }
577 while (t > LONG_MAX) {
578 t /= 2;
579 f /= 2;
580 s *= 2;
581 }
582 sbp->f_bsize = (ulong_t)s; /* file system block size */
583 sbp->f_blocks = t; /* total data blocks in file system */
584 sbp->f_bfree = f; /* free blocks in fs */
585 sbp->f_bavail = f; /* free blocks avail to non-superuser */
586 sbp->f_files = (-1); /* total file nodes in file system */
587 sbp->f_ffree = (-1); /* free file nodes in fs */
588
589 out:
590 smb_rq_done(rqp);
591 return (0);
592 }
593
594 int
smbfs_smb_seteof(struct smb_share * ssp,uint16_t fid,uint64_t newsize,struct smb_cred * scrp)595 smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
596 struct smb_cred *scrp)
597 {
598 struct smb_t2rq *t2p;
599 struct smb_vc *vcp = SSTOVC(ssp);
600 struct mbchain *mbp;
601 int error;
602
603 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
604 scrp, &t2p);
605 if (error)
606 return (error);
607 mbp = &t2p->t2_tparam;
608 mb_init(mbp);
609 mb_put_uint16le(mbp, fid);
610 if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
611 mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
612 else
613 mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
614 mb_put_uint16le(mbp, 0); /* pad */
615 mbp = &t2p->t2_tdata;
616 mb_init(mbp);
617 mb_put_uint64le(mbp, newsize);
618 t2p->t2_maxpcount = 2;
619 t2p->t2_maxdcount = 0;
620 error = smb_t2_request(t2p);
621 smb_t2_done(t2p);
622 return (error);
623 }
624
625 /*ARGSUSED*/
626 int
smbfs_smb_t2rename(struct smbnode * np,struct smbnode * tdnp,const char * tname,int tnmlen,struct smb_cred * scrp,int overwrite)627 smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
628 const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite)
629 {
630 struct smb_t2rq *t2p;
631 struct smb_share *ssp = np->n_mount->smi_share;
632 struct smb_vc *vcp = SSTOVC(ssp);
633 struct mbchain *mbp;
634 int32_t *ucslenp;
635 int error, cerror;
636 uint16_t fid = 0;
637
638 /* Shared lock for n_fid use below. */
639 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
640
641 /* After reconnect, n_fid is invalid */
642 if (np->n_vcgenid != ssp->ss_vcgenid)
643 return (ESTALE);
644
645 if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
646 return (ENOTSUP);
647 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
648 scrp, &t2p);
649 if (error)
650 return (error);
651 if (tdnp) {
652 error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp,
653 &fid);
654 if (error)
655 goto exit;
656 }
657 mbp = &t2p->t2_tparam;
658 mb_init(mbp);
659 mb_put_uint16le(mbp, np->n_fid);
660 mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
661 mb_put_uint16le(mbp, 0); /* reserved, nowadays */
662 mbp = &t2p->t2_tdata;
663 mb_init(mbp);
664 mb_put_uint32le(mbp, overwrite);
665 mb_put_uint16le(mbp, fid); /* base for tname */
666 mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */
667 ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
668 mbp->mb_count = 0;
669 error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE);
670 if (error)
671 goto exit;
672 mbp->mb_count--; /* don't count the null */
673 *ucslenp = htolel(mbp->mb_count);
674 t2p->t2_maxpcount = 2;
675 t2p->t2_maxdcount = 0;
676 error = smb_t2_request(t2p);
677 exit:
678 if (fid) {
679 cerror = smbfs_smb_tmpclose(tdnp, fid, scrp);
680 if (cerror)
681 SMBVDEBUG("error %d closing %s\n",
682 cerror, tdnp->n_rpath);
683 }
684 smb_t2_done(t2p);
685 return (error);
686 }
687
688 int
smbfs_smb_flush(struct smbnode * np,struct smb_cred * scrp)689 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
690 {
691 struct smb_share *ssp = np->n_mount->smi_share;
692 struct smb_rq rq, *rqp = &rq;
693 struct mbchain *mbp;
694 int error;
695
696 /* Shared lock for n_fid use below. */
697 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
698
699 if (!(np->n_flag & NFLUSHWIRE))
700 return (0);
701 if (np->n_fidrefs == 0)
702 return (0); /* not open */
703
704 /* After reconnect, n_fid is invalid */
705 if (np->n_vcgenid != ssp->ss_vcgenid)
706 return (ESTALE);
707
708 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
709 if (error)
710 return (error);
711 smb_rq_getrequest(rqp, &mbp);
712 smb_rq_wstart(rqp);
713 mb_put_uint16le(mbp, np->n_fid);
714 smb_rq_wend(rqp);
715 smb_rq_bstart(rqp);
716 smb_rq_bend(rqp);
717 error = smb_rq_simple(rqp);
718 smb_rq_done(rqp);
719 if (!error) {
720 mutex_enter(&np->r_statelock);
721 np->n_flag &= ~NFLUSHWIRE;
722 mutex_exit(&np->r_statelock);
723 }
724 return (error);
725 }
726
727 int
smbfs_smb_setfsize(struct smbnode * np,uint16_t fid,uint64_t newsize,struct smb_cred * scrp)728 smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
729 struct smb_cred *scrp)
730 {
731 struct smb_share *ssp = np->n_mount->smi_share;
732 struct smb_rq rq, *rqp = &rq;
733 struct mbchain *mbp;
734 int error;
735
736 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
737 /*
738 * This call knows about 64-bit offsets.
739 */
740 error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
741 if (!error) {
742 mutex_enter(&np->r_statelock);
743 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
744 mutex_exit(&np->r_statelock);
745 return (0);
746 }
747 }
748
749 /*
750 * OK, so fallback to SMB_COM_WRITE, but note:
751 * it only supports 32-bit file offsets.
752 */
753 if (newsize > UINT32_MAX)
754 return (EFBIG);
755
756 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
757 if (error)
758 return (error);
759 smb_rq_getrequest(rqp, &mbp);
760 smb_rq_wstart(rqp);
761 mb_put_uint16le(mbp, fid);
762 mb_put_uint16le(mbp, 0);
763 mb_put_uint32le(mbp, newsize);
764 mb_put_uint16le(mbp, 0);
765 smb_rq_wend(rqp);
766 smb_rq_bstart(rqp);
767 mb_put_uint8(mbp, SMB_DT_DATA);
768 mb_put_uint16le(mbp, 0);
769 smb_rq_bend(rqp);
770 error = smb_rq_simple(rqp);
771 smb_rq_done(rqp);
772 mutex_enter(&np->r_statelock);
773 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
774 mutex_exit(&np->r_statelock);
775 return (error);
776 }
777
778 /*
779 * Old method for getting file attributes.
780 */
781 int
smbfs_smb_query_info(struct smbnode * np,const char * name,int nmlen,struct smbfattr * fap,struct smb_cred * scrp)782 smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
783 struct smbfattr *fap, struct smb_cred *scrp)
784 {
785 struct smb_rq rq, *rqp = &rq;
786 struct smb_share *ssp = np->n_mount->smi_share;
787 struct mbchain *mbp;
788 struct mdchain *mdp;
789 uint8_t wc;
790 int error;
791 uint16_t wattr;
792 uint32_t longint;
793
794 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
795 if (error)
796 return (error);
797 smb_rq_getrequest(rqp, &mbp);
798 smb_rq_wstart(rqp);
799 smb_rq_wend(rqp);
800 smb_rq_bstart(rqp);
801 mb_put_uint8(mbp, SMB_DT_ASCII);
802
803 error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
804 name, nmlen, '\\');
805 if (error)
806 goto out;
807 smb_rq_bend(rqp);
808 error = smb_rq_simple(rqp);
809 if (error)
810 goto out;
811 smb_rq_getreply(rqp, &mdp);
812 error = md_get_uint8(mdp, &wc);
813 if (error)
814 goto out;
815 if (wc != 10) {
816 error = EBADRPC;
817 goto out;
818 }
819 md_get_uint16le(mdp, &wattr);
820 fap->fa_attr = wattr;
821 /*
822 * Be careful using the time returned here, as
823 * with FAT on NT4SP6, at least, the time returned is low
824 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
825 * over about every seven minutes!
826 */
827 md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
828 smb_time_server2local(longint,
829 SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
830 error = md_get_uint32le(mdp, &longint);
831 fap->fa_size = longint;
832
833 out:
834 smb_rq_done(rqp);
835 return (error);
836 }
837
838 /*
839 * Set DOS file attributes. mtime should be NULL for dialects above lm10
840 */
841 int
smbfs_smb_setpattr1(struct smbnode * np,const char * name,int len,uint32_t attr,struct timespec * mtime,struct smb_cred * scrp)842 smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
843 uint32_t attr, struct timespec *mtime,
844 struct smb_cred *scrp)
845 {
846 struct smb_rq rq, *rqp = &rq;
847 struct smb_share *ssp = np->n_mount->smi_share;
848 struct mbchain *mbp;
849 long time;
850 int error, svtz;
851
852 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
853 if (error)
854 return (error);
855 svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
856 smb_rq_getrequest(rqp, &mbp);
857 smb_rq_wstart(rqp);
858 mb_put_uint16le(mbp, (uint16_t)attr);
859 if (mtime) {
860 smb_time_local2server(mtime, svtz, &time);
861 } else
862 time = 0;
863 mb_put_uint32le(mbp, time); /* mtime */
864 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
865 smb_rq_wend(rqp);
866 smb_rq_bstart(rqp);
867 mb_put_uint8(mbp, SMB_DT_ASCII);
868
869 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len, '\\');
870 if (error)
871 goto out;
872 mb_put_uint8(mbp, SMB_DT_ASCII);
873 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
874 mb_put_padbyte(mbp);
875 mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
876 }
877 mb_put_uint8(mbp, 0);
878 smb_rq_bend(rqp);
879 error = smb_rq_simple(rqp);
880
881 out:
882 smb_rq_done(rqp);
883 return (error);
884 }
885
886 int
smbfs_smb_hideit(struct smbnode * np,const char * name,int len,struct smb_cred * scrp)887 smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
888 struct smb_cred *scrp)
889 {
890 struct smbfattr fa;
891 int error;
892 uint32_t attr;
893
894 error = smbfs_smb_query_info(np, name, len, &fa, scrp);
895 attr = fa.fa_attr;
896 if (!error && !(attr & SMB_FA_HIDDEN)) {
897 attr |= SMB_FA_HIDDEN;
898 error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
899 }
900 return (error);
901 }
902
903
904 int
smbfs_smb_unhideit(struct smbnode * np,const char * name,int len,struct smb_cred * scrp)905 smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
906 struct smb_cred *scrp)
907 {
908 struct smbfattr fa;
909 uint32_t attr;
910 int error;
911
912 error = smbfs_smb_query_info(np, name, len, &fa, scrp);
913 attr = fa.fa_attr;
914 if (!error && (attr & SMB_FA_HIDDEN)) {
915 attr &= ~SMB_FA_HIDDEN;
916 error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
917 }
918 return (error);
919 }
920
921 /*
922 * Set file attributes (optionally: DOS attr, atime, mtime)
923 * either by open FID or by path name (FID == -1).
924 */
925 int
smbfs_smb_setfattr(struct smbnode * np,int fid,uint32_t attr,struct timespec * mtime,struct timespec * atime,struct smb_cred * scrp)926 smbfs_smb_setfattr(
927 struct smbnode *np,
928 int fid,
929 uint32_t attr,
930 struct timespec *mtime,
931 struct timespec *atime,
932 struct smb_cred *scrp)
933 {
934 struct smb_share *ssp = np->n_mount->smi_share;
935 struct smb_vc *vcp = SSTOVC(ssp);
936 int error;
937
938 /*
939 * Normally can use the trans2 call.
940 */
941 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
942 error = smbfs_smb_setfattrNT(np, fid,
943 attr, mtime, atime, scrp);
944 return (error);
945 }
946
947 /*
948 * Fall-back for older protocols.
949 */
950 if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
951 error = smbfs_smb_setftime1(np, fid,
952 mtime, atime, scrp);
953 return (error);
954 }
955 error = smbfs_smb_setpattr1(np, NULL, 0,
956 attr, mtime, scrp);
957 return (error);
958 }
959
960 /*
961 * Set file atime and mtime. Isn't supported by core dialect.
962 */
963 int
smbfs_smb_setftime1(struct smbnode * np,uint16_t fid,struct timespec * mtime,struct timespec * atime,struct smb_cred * scrp)964 smbfs_smb_setftime1(
965 struct smbnode *np,
966 uint16_t fid,
967 struct timespec *mtime,
968 struct timespec *atime,
969 struct smb_cred *scrp)
970 {
971 struct smb_rq rq, *rqp = &rq;
972 struct smb_share *ssp = np->n_mount->smi_share;
973 struct mbchain *mbp;
974 uint16_t date, time;
975 int error, tzoff;
976
977 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
978 if (error)
979 return (error);
980
981 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
982 smb_rq_getrequest(rqp, &mbp);
983 smb_rq_wstart(rqp);
984 mb_put_uint16le(mbp, fid);
985 mb_put_uint32le(mbp, 0); /* creation time */
986
987 if (atime)
988 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
989 else
990 time = date = 0;
991 mb_put_uint16le(mbp, date);
992 mb_put_uint16le(mbp, time);
993 if (mtime)
994 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
995 else
996 time = date = 0;
997 mb_put_uint16le(mbp, date);
998 mb_put_uint16le(mbp, time);
999 smb_rq_wend(rqp);
1000 smb_rq_bstart(rqp);
1001 smb_rq_bend(rqp);
1002 error = smb_rq_simple(rqp);
1003 SMBVDEBUG("%d\n", error);
1004 smb_rq_done(rqp);
1005 return (error);
1006 }
1007
1008 /*
1009 * Set DOS file attributes, either via open FID or by path name.
1010 * Looks like this call can be used only if CAP_NT_SMBS bit is on.
1011 *
1012 * When setting via path (fid == -1):
1013 * *BASIC_INFO works with Samba, but Win2K servers say it is an
1014 * invalid information level on a SET_PATH_INFO. Note Win2K does
1015 * support *BASIC_INFO on a SET_FILE_INFO, and they support the
1016 * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure.
1017 */
1018 int
smbfs_smb_setfattrNT(struct smbnode * np,int fid,uint32_t attr,struct timespec * mtime,struct timespec * atime,struct smb_cred * scrp)1019 smbfs_smb_setfattrNT(
1020 struct smbnode *np,
1021 int fid, /* if fid == -1, set by path */
1022 uint32_t attr,
1023 struct timespec *mtime,
1024 struct timespec *atime,
1025 struct smb_cred *scrp)
1026 {
1027 struct smb_t2rq *t2p;
1028 struct smb_share *ssp = np->n_mount->smi_share;
1029 struct smb_vc *vcp = SSTOVC(ssp);
1030 struct mbchain *mbp;
1031 uint64_t tm;
1032 int error;
1033 uint16_t cmd, level;
1034
1035 if (fid == -1) {
1036 cmd = SMB_TRANS2_SET_PATH_INFORMATION;
1037 } else {
1038 if (fid > UINT16_MAX)
1039 return (EINVAL);
1040 cmd = SMB_TRANS2_SET_FILE_INFORMATION;
1041 }
1042 if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
1043 level = SMB_SFILEINFO_BASIC_INFORMATION;
1044 else
1045 level = SMB_SFILEINFO_BASIC_INFO;
1046
1047 error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
1048 if (error)
1049 return (error);
1050
1051 mbp = &t2p->t2_tparam;
1052 mb_init(mbp);
1053
1054 if (cmd == SMB_TRANS2_SET_FILE_INFORMATION)
1055 mb_put_uint16le(mbp, fid);
1056
1057 mb_put_uint16le(mbp, level);
1058 mb_put_uint32le(mbp, 0); /* MBZ */
1059
1060 if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) {
1061 error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
1062 if (error != 0)
1063 goto out;
1064 }
1065
1066 /* FAT file systems don't support dates earlier than 1980. */
1067
1068 mbp = &t2p->t2_tdata;
1069 mb_init(mbp);
1070 mb_put_uint64le(mbp, 0); /* creation time */
1071 if (atime) {
1072 smb_time_local2NT(atime, &tm);
1073 if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1074 tm < NT1980)
1075 tm = NT1980;
1076 } else
1077 tm = 0;
1078 mb_put_uint64le(mbp, tm); /* access time */
1079 if (mtime) {
1080 smb_time_local2NT(mtime, &tm);
1081 if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1082 tm < NT1980)
1083 tm = NT1980;
1084 } else
1085 tm = 0;
1086 mb_put_uint64le(mbp, tm); /* last write time */
1087 mb_put_uint64le(mbp, 0); /* ctime (no change) */
1088 mb_put_uint32le(mbp, attr);
1089 mb_put_uint32le(mbp, 0); /* padding */
1090 t2p->t2_maxpcount = 2;
1091 t2p->t2_maxdcount = 0;
1092 error = smb_t2_request(t2p);
1093 out:
1094 smb_t2_done(t2p);
1095 return (error);
1096 }
1097
1098 /*
1099 * Modern create/open of file or directory.
1100 */
1101 int
smbfs_smb_ntcreatex(struct smbnode * np,const char * name,int nmlen,int xattr,uint32_t req_acc,uint32_t efa,uint32_t share_acc,uint32_t disp,uint32_t createopt,struct smb_cred * scrp,uint16_t * fidp,uint32_t * cr_act_p,struct smbfattr * fap)1102 smbfs_smb_ntcreatex(
1103 struct smbnode *np,
1104 const char *name,
1105 int nmlen,
1106 int xattr, /* is named stream? */
1107 uint32_t req_acc, /* requested access */
1108 uint32_t efa, /* ext. file attrs (DOS attr +) */
1109 uint32_t share_acc,
1110 uint32_t disp, /* open disposition */
1111 uint32_t createopt, /* NTCREATEX_OPTIONS_ */
1112 struct smb_cred *scrp,
1113 uint16_t *fidp, /* returned FID */
1114 uint32_t *cr_act_p, /* optional returned create action */
1115 struct smbfattr *fap) /* optional returned attributes */
1116 {
1117 struct mbchain name_mb;
1118 struct smb_share *ssp = np->n_mount->smi_share;
1119 int err;
1120
1121 mb_init(&name_mb);
1122
1123 if (name == NULL)
1124 nmlen = 0;
1125 err = smbfs_fullpath(&name_mb, SSTOVC(ssp),
1126 np, name, nmlen, xattr ? ':' : '\\');
1127 if (err)
1128 goto out;
1129
1130 err = smb_smb_ntcreate(ssp, &name_mb,
1131 0, /* NTCREATEX_FLAGS... */
1132 req_acc, efa, share_acc, disp, createopt,
1133 NTCREATEX_IMPERSONATION_IMPERSONATION,
1134 scrp, fidp, cr_act_p, fap);
1135
1136 out:
1137 mb_done(&name_mb);
1138
1139 return (err);
1140 }
1141
1142 static uint32_t
smb_mode2rights(int mode)1143 smb_mode2rights(int mode)
1144 {
1145 mode = mode & SMB_AM_OPENMODE;
1146 uint32_t rights =
1147 STD_RIGHT_SYNCHRONIZE_ACCESS |
1148 STD_RIGHT_READ_CONTROL_ACCESS;
1149
1150 if ((mode == SMB_AM_OPENREAD) ||
1151 (mode == SMB_AM_OPENRW)) {
1152 rights |=
1153 SA_RIGHT_FILE_READ_ATTRIBUTES |
1154 SA_RIGHT_FILE_READ_DATA;
1155 }
1156
1157 if ((mode == SMB_AM_OPENWRITE) ||
1158 (mode == SMB_AM_OPENRW)) {
1159 rights |=
1160 SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1161 SA_RIGHT_FILE_APPEND_DATA |
1162 SA_RIGHT_FILE_WRITE_DATA;
1163 }
1164
1165 if (mode == SMB_AM_OPENEXEC) {
1166 rights |=
1167 SA_RIGHT_FILE_READ_ATTRIBUTES |
1168 SA_RIGHT_FILE_EXECUTE;
1169 }
1170
1171 return (rights);
1172 }
1173
1174 static int
smb_rights2mode(uint32_t rights)1175 smb_rights2mode(uint32_t rights)
1176 {
1177 int accmode = SMB_AM_OPENEXEC; /* our fallback */
1178
1179 if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
1180 SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1181 SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
1182 STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS))
1183 accmode = SMB_AM_OPENWRITE;
1184 if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
1185 SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS))
1186 accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
1187 : SMB_AM_OPENRW;
1188 return (accmode);
1189 }
1190
1191 static int
smbfs_smb_oldopen(struct smbnode * np,const char * name,int nmlen,int xattr,int accmode,struct smb_cred * scrp,uint16_t * fidp,uint16_t * granted_mode_p,smbfattr_t * fap)1192 smbfs_smb_oldopen(
1193 struct smbnode *np,
1194 const char *name,
1195 int nmlen,
1196 int xattr,
1197 int accmode,
1198 struct smb_cred *scrp,
1199 uint16_t *fidp,
1200 uint16_t *granted_mode_p,
1201 smbfattr_t *fap)
1202 {
1203 struct smb_rq rq, *rqp = &rq;
1204 struct smb_share *ssp = np->n_mount->smi_share;
1205 struct smb_vc *vcp = SSTOVC(ssp);
1206 struct mbchain *mbp;
1207 struct mdchain *mdp;
1208 struct smbfattr fa;
1209 uint8_t wc;
1210 uint16_t wattr;
1211 uint32_t longint;
1212 int error;
1213
1214 bzero(&fa, sizeof (fa));
1215
1216 /*
1217 * XXX: move to callers...
1218 *
1219 * Use DENYNONE to give unixy semantics of permitting
1220 * everything not forbidden by permissions. Ie denial
1221 * is up to server with clients/openers needing to use
1222 * advisory locks for further control.
1223 */
1224 accmode |= SMB_SM_DENYNONE;
1225
1226 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
1227 if (error)
1228 return (error);
1229 smb_rq_getrequest(rqp, &mbp);
1230 smb_rq_wstart(rqp);
1231 mb_put_uint16le(mbp, accmode);
1232 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
1233 SMB_FA_DIR);
1234 smb_rq_wend(rqp);
1235 smb_rq_bstart(rqp);
1236 mb_put_uint8(mbp, SMB_DT_ASCII);
1237
1238 error = smbfs_fullpath(mbp, vcp, np, name, nmlen,
1239 xattr ? ':' : '\\');
1240 if (error)
1241 goto done;
1242 smb_rq_bend(rqp);
1243 /*
1244 * Don't want to risk missing a successful
1245 * open response, or we could "leak" FIDs.
1246 */
1247 rqp->sr_flags |= SMBR_NOINTR_RECV;
1248 error = smb_rq_simple_timed(rqp, smb_timo_open);
1249 if (error)
1250 goto done;
1251 smb_rq_getreply(rqp, &mdp);
1252 /*
1253 * 8/2002 a DAVE server returned wc of 15 so we ignore that.
1254 * (the actual packet length and data was correct)
1255 */
1256 error = md_get_uint8(mdp, &wc);
1257 if (error)
1258 goto done;
1259 if (wc != 7 && wc != 15) {
1260 error = EBADRPC;
1261 goto done;
1262 }
1263 md_get_uint16le(mdp, fidp);
1264 md_get_uint16le(mdp, &wattr);
1265 fa.fa_attr = wattr;
1266 /*
1267 * Be careful using the time returned here, as
1268 * with FAT on NT4SP6, at least, the time returned is low
1269 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
1270 * over about every seven minutes!
1271 */
1272 md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
1273 smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime);
1274 md_get_uint32le(mdp, &longint);
1275 fa.fa_size = longint;
1276 error = md_get_uint16le(mdp, granted_mode_p);
1277
1278 done:
1279 smb_rq_done(rqp);
1280 if (error)
1281 return (error);
1282
1283 if (fap)
1284 *fap = fa; /* struct copy */
1285
1286 return (0);
1287 }
1288
1289 int
smbfs_smb_tmpopen(struct smbnode * np,uint32_t rights,struct smb_cred * scrp,uint16_t * fidp)1290 smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
1291 uint16_t *fidp)
1292 {
1293 struct smb_share *ssp = np->n_mount->smi_share;
1294 struct smb_vc *vcp = SSTOVC(ssp);
1295 int accmode, error;
1296
1297 /* Shared lock for n_fid use below. */
1298 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1299
1300 /* Can we re-use n_fid? or must we open anew? */
1301 mutex_enter(&np->r_statelock);
1302 if (np->n_fidrefs > 0 &&
1303 np->n_vcgenid == ssp->ss_vcgenid &&
1304 (rights & np->n_rights) == rights) {
1305 np->n_fidrefs++;
1306 *fidp = np->n_fid;
1307 mutex_exit(&np->r_statelock);
1308 return (0);
1309 }
1310 mutex_exit(&np->r_statelock);
1311
1312 /* re-open an existing file. */
1313 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1314 error = smbfs_smb_ntcreatex(np,
1315 NULL, 0, 0, /* name nmlen xattr */
1316 rights, SMB_EFA_NORMAL,
1317 NTCREATEX_SHARE_ACCESS_ALL,
1318 NTCREATEX_DISP_OPEN,
1319 0, /* create options */
1320 scrp, fidp,
1321 NULL, NULL); /* cr_act_p fa_p */
1322 return (error);
1323 }
1324
1325 accmode = smb_rights2mode(rights);
1326 error = smbfs_smb_oldopen(np,
1327 NULL, 0, 0, /* name nmlen xattr */
1328 accmode, scrp,
1329 fidp,
1330 NULL, /* granted mode p */
1331 NULL); /* fa p */
1332
1333 return (error);
1334 }
1335
1336 int
smbfs_smb_tmpclose(struct smbnode * np,uint16_t fid,struct smb_cred * scrp)1337 smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
1338 {
1339 struct smb_share *ssp = np->n_mount->smi_share;
1340 int error = 0;
1341 uint16_t oldfid = SMB_FID_UNUSED;
1342
1343 /* Shared lock for n_fid use below. */
1344 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1345
1346 mutex_enter(&np->r_statelock);
1347 if (fid == np->n_fid) {
1348 ASSERT(np->n_fidrefs > 0);
1349 if (--np->n_fidrefs == 0) {
1350 /*
1351 * Don't expect to find the last reference
1352 * here in tmpclose. Hard to deal with as
1353 * we don't have r_lkserlock exclusive.
1354 * Will close oldfid below.
1355 */
1356 oldfid = np->n_fid;
1357 np->n_fid = SMB_FID_UNUSED;
1358 }
1359 } else {
1360 /* Will close the passed fid. */
1361 oldfid = fid;
1362 }
1363 mutex_exit(&np->r_statelock);
1364
1365 if (oldfid != SMB_FID_UNUSED)
1366 error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
1367
1368 return (error);
1369 }
1370
1371 int
smbfs_smb_open(struct smbnode * np,const char * name,int nmlen,int xattr,uint32_t rights,struct smb_cred * scrp,uint16_t * fidp,uint32_t * rightsp,smbfattr_t * fap)1372 smbfs_smb_open(
1373 struct smbnode *np,
1374 const char *name,
1375 int nmlen,
1376 int xattr,
1377 uint32_t rights,
1378 struct smb_cred *scrp,
1379 uint16_t *fidp,
1380 uint32_t *rightsp,
1381 smbfattr_t *fap)
1382 {
1383 struct smb_share *ssp = np->n_mount->smi_share;
1384 struct smb_vc *vcp = SSTOVC(ssp);
1385 int accmode, error;
1386 uint16_t grantedmode;
1387
1388 /* open an existing file */
1389 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1390 error = smbfs_smb_ntcreatex(np,
1391 name, nmlen, xattr,
1392 rights, SMB_EFA_NORMAL,
1393 NTCREATEX_SHARE_ACCESS_ALL,
1394 NTCREATEX_DISP_OPEN,
1395 0, /* create options */
1396 scrp, fidp,
1397 NULL, fap); /* cr_act_p fa_p */
1398 if (error != 0)
1399 return (error);
1400 *rightsp = rights;
1401 return (0);
1402 }
1403
1404 accmode = smb_rights2mode(rights);
1405 error = smbfs_smb_oldopen(np,
1406 name, nmlen, xattr, accmode, scrp,
1407 fidp, &grantedmode, fap);
1408 if (error != 0)
1409 return (error);
1410 *rightsp = smb_mode2rights(grantedmode);
1411 (void) smbfs_smb_getfattr(np, fap, scrp);
1412
1413 return (0);
1414 }
1415
1416 int
smbfs_smb_close(struct smb_share * ssp,uint16_t fid,struct timespec * mtime,struct smb_cred * scrp)1417 smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
1418 struct timespec *mtime, struct smb_cred *scrp)
1419 {
1420 int error;
1421
1422 error = smb_smb_close(ssp, fid, mtime, scrp);
1423
1424 /*
1425 * ENOTCONN isn't interesting - if the connection is closed,
1426 * so are all our FIDs - and EIO is also not interesting,
1427 * as it means a forced unmount was done. (was ENXIO)
1428 * Also ETIME, which means we sent the request but gave up
1429 * waiting before the response came back.
1430 *
1431 * Don't clog up the system log with warnings about these
1432 * uninteresting failures on closes.
1433 */
1434 switch (error) {
1435 case ENOTCONN:
1436 case ENXIO:
1437 case EIO:
1438 case ETIME:
1439 error = 0;
1440 }
1441 return (error);
1442 }
1443
1444 static int
smbfs_smb_oldcreate(struct smbnode * dnp,const char * name,int nmlen,int xattr,struct smb_cred * scrp,uint16_t * fidp)1445 smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
1446 int xattr, struct smb_cred *scrp, uint16_t *fidp)
1447 {
1448 struct smb_rq rq, *rqp = &rq;
1449 struct smb_share *ssp = dnp->n_mount->smi_share;
1450 struct mbchain *mbp;
1451 struct mdchain *mdp;
1452 struct timespec ctime;
1453 uint8_t wc;
1454 long tm;
1455 int error;
1456 uint16_t attr = SMB_FA_ARCHIVE;
1457
1458 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
1459 if (error)
1460 return (error);
1461 smb_rq_getrequest(rqp, &mbp);
1462 smb_rq_wstart(rqp);
1463 if (name && *name == '.')
1464 attr |= SMB_FA_HIDDEN;
1465 mb_put_uint16le(mbp, attr); /* attributes */
1466 gethrestime(&ctime);
1467 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
1468 mb_put_uint32le(mbp, tm);
1469 smb_rq_wend(rqp);
1470 smb_rq_bstart(rqp);
1471 mb_put_uint8(mbp, SMB_DT_ASCII);
1472 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen,
1473 xattr ? ':' : '\\');
1474 if (error)
1475 goto out;
1476 smb_rq_bend(rqp);
1477 /*
1478 * Don't want to risk missing a successful
1479 * open response, or we could "leak" FIDs.
1480 */
1481 rqp->sr_flags |= SMBR_NOINTR_RECV;
1482 error = smb_rq_simple_timed(rqp, smb_timo_open);
1483 if (error)
1484 goto out;
1485
1486 smb_rq_getreply(rqp, &mdp);
1487 md_get_uint8(mdp, &wc);
1488 if (wc != 1) {
1489 error = EBADRPC;
1490 goto out;
1491 }
1492 error = md_get_uint16le(mdp, fidp);
1493
1494 out:
1495 smb_rq_done(rqp);
1496 return (error);
1497 }
1498
1499 int
smbfs_smb_create(struct smbnode * dnp,const char * name,int nmlen,int xattr,uint32_t disp,struct smb_cred * scrp,uint16_t * fidp)1500 smbfs_smb_create(
1501 struct smbnode *dnp,
1502 const char *name,
1503 int nmlen,
1504 int xattr,
1505 uint32_t disp,
1506 struct smb_cred *scrp,
1507 uint16_t *fidp)
1508 {
1509 struct smb_share *ssp = dnp->n_mount->smi_share;
1510 struct smb_vc *vcp = SSTOVC(ssp);
1511 uint32_t efa, rights;
1512 int error;
1513
1514 /*
1515 * At present the only access we might need is to WRITE data,
1516 * and that only if we are creating a "symlink". When/if the
1517 * access needed gets more complex it should made a parameter
1518 * and be set upstream.
1519 */
1520 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1521 rights = SA_RIGHT_FILE_WRITE_DATA;
1522 efa = SMB_EFA_NORMAL;
1523 if (!xattr && name && *name == '.')
1524 efa = SMB_EFA_HIDDEN;
1525 error = smbfs_smb_ntcreatex(dnp,
1526 name, nmlen, xattr, rights, efa,
1527 NTCREATEX_SHARE_ACCESS_ALL,
1528 disp, /* != NTCREATEX_DISP_OPEN */
1529 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
1530 scrp, fidp, NULL, NULL); /* cr_act_p fa_p */
1531 return (error);
1532 }
1533
1534 error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp);
1535 return (error);
1536 }
1537
1538 int
smbfs_smb_delete(struct smbnode * np,struct smb_cred * scrp,const char * name,int nmlen,int xattr)1539 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
1540 int nmlen, int xattr)
1541 {
1542 struct smb_rq rq, *rqp = &rq;
1543 struct smb_share *ssp = np->n_mount->smi_share;
1544 struct mbchain *mbp;
1545 int error;
1546
1547 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
1548 if (error)
1549 return (error);
1550 smb_rq_getrequest(rqp, &mbp);
1551 smb_rq_wstart(rqp);
1552 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
1553 smb_rq_wend(rqp);
1554 smb_rq_bstart(rqp);
1555 mb_put_uint8(mbp, SMB_DT_ASCII);
1556 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, nmlen,
1557 xattr ? ':' : '\\');
1558 if (!error) {
1559 smb_rq_bend(rqp);
1560 error = smb_rq_simple(rqp);
1561 }
1562 smb_rq_done(rqp);
1563 return (error);
1564 }
1565
1566 int
smbfs_smb_rename(struct smbnode * src,struct smbnode * tdnp,const char * tname,int tnmlen,struct smb_cred * scrp)1567 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
1568 const char *tname, int tnmlen, struct smb_cred *scrp)
1569 {
1570 struct smb_rq rq, *rqp = &rq;
1571 struct smb_share *ssp = src->n_mount->smi_share;
1572 struct mbchain *mbp;
1573 int error;
1574 uint16_t fa;
1575 char sep;
1576
1577 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
1578 if (error)
1579 return (error);
1580 smb_rq_getrequest(rqp, &mbp);
1581 smb_rq_wstart(rqp);
1582 /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
1583 fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
1584 fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
1585 mb_put_uint16le(mbp, fa);
1586 smb_rq_wend(rqp);
1587 smb_rq_bstart(rqp);
1588
1589 /*
1590 * When we're not adding any component name, the
1591 * passed sep is ignored, so just pass sep=0.
1592 */
1593 mb_put_uint8(mbp, SMB_DT_ASCII);
1594 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
1595 if (error)
1596 goto out;
1597
1598 /*
1599 * After XATTR directories, separator is ":"
1600 */
1601 sep = (src->n_flag & N_XATTR) ? ':' : '\\';
1602 mb_put_uint8(mbp, SMB_DT_ASCII);
1603 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
1604 if (error)
1605 goto out;
1606
1607 smb_rq_bend(rqp);
1608 error = smb_rq_simple(rqp);
1609 out:
1610 smb_rq_done(rqp);
1611 return (error);
1612 }
1613
1614 int
smbfs_smb_move(struct smbnode * src,struct smbnode * tdnp,const char * tname,int tnmlen,uint16_t flags,struct smb_cred * scrp)1615 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
1616 const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
1617 {
1618 struct smb_rq rq, *rqp = &rq;
1619 struct smb_share *ssp = src->n_mount->smi_share;
1620 struct mbchain *mbp;
1621 int error;
1622
1623 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
1624 if (error)
1625 return (error);
1626 smb_rq_getrequest(rqp, &mbp);
1627 smb_rq_wstart(rqp);
1628 mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
1629 mb_put_uint16le(mbp, 0x20); /* delete target file */
1630 mb_put_uint16le(mbp, flags);
1631 smb_rq_wend(rqp);
1632 smb_rq_bstart(rqp);
1633 mb_put_uint8(mbp, SMB_DT_ASCII);
1634
1635 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, '\\');
1636 if (error)
1637 goto out;
1638 mb_put_uint8(mbp, SMB_DT_ASCII);
1639 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, '\\');
1640 if (error)
1641 goto out;
1642 smb_rq_bend(rqp);
1643 error = smb_rq_simple(rqp);
1644
1645 out:
1646 smb_rq_done(rqp);
1647 return (error);
1648 }
1649
1650 static int
smbfs_smb_oldmkdir(struct smbnode * dnp,const char * name,int len,struct smb_cred * scrp)1651 smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
1652 struct smb_cred *scrp)
1653 {
1654 struct smb_rq rq, *rqp = &rq;
1655 struct smb_share *ssp = dnp->n_mount->smi_share;
1656 struct mbchain *mbp;
1657 int error;
1658
1659 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
1660 if (error)
1661 return (error);
1662 smb_rq_getrequest(rqp, &mbp);
1663 smb_rq_wstart(rqp);
1664 smb_rq_wend(rqp);
1665 smb_rq_bstart(rqp);
1666 mb_put_uint8(mbp, SMB_DT_ASCII);
1667 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len, '\\');
1668 if (!error) {
1669 smb_rq_bend(rqp);
1670 error = smb_rq_simple(rqp);
1671 }
1672 smb_rq_done(rqp);
1673 return (error);
1674 }
1675
1676 int
smbfs_smb_mkdir(struct smbnode * dnp,const char * name,int nmlen,struct smb_cred * scrp)1677 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
1678 struct smb_cred *scrp)
1679 {
1680 struct smb_share *ssp = dnp->n_mount->smi_share;
1681 struct smb_vc *vcp = SSTOVC(ssp);
1682 uint32_t rights;
1683 uint16_t fid;
1684 int error;
1685
1686 /*
1687 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
1688 * just to be asking for something. The rights==0 case could
1689 * easily be broken on some old or unusual servers.
1690 */
1691 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1692 rights = SA_RIGHT_FILE_READ_DATA;
1693 error = smbfs_smb_ntcreatex(dnp,
1694 name, nmlen, 0, /* xattr */
1695 rights, SMB_EFA_DIRECTORY,
1696 NTCREATEX_SHARE_ACCESS_ALL,
1697 NTCREATEX_DISP_CREATE,
1698 NTCREATEX_OPTIONS_DIRECTORY,
1699 scrp, &fid, NULL, NULL); /* cr_act_p fa_p */
1700 if (error)
1701 return (error);
1702 (void) smbfs_smb_close(ssp, fid, NULL, scrp);
1703 return (0);
1704 }
1705
1706 error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp);
1707 return (error);
1708 }
1709
1710 int
smbfs_smb_rmdir(struct smbnode * np,struct smb_cred * scrp)1711 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
1712 {
1713 struct smb_rq rq, *rqp = &rq;
1714 struct smb_share *ssp = np->n_mount->smi_share;
1715 struct mbchain *mbp;
1716 int error;
1717
1718 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
1719 if (error)
1720 return (error);
1721 smb_rq_getrequest(rqp, &mbp);
1722 smb_rq_wstart(rqp);
1723 smb_rq_wend(rqp);
1724 smb_rq_bstart(rqp);
1725 mb_put_uint8(mbp, SMB_DT_ASCII);
1726 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0, '\\');
1727 if (!error) {
1728 smb_rq_bend(rqp);
1729 error = smb_rq_simple(rqp);
1730 }
1731 smb_rq_done(rqp);
1732 return (error);
1733 }
1734
1735 static int
smbfs_smb_search(struct smbfs_fctx * ctx)1736 smbfs_smb_search(struct smbfs_fctx *ctx)
1737 {
1738 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1739 struct smb_rq *rqp;
1740 struct mbchain *mbp;
1741 struct mdchain *mdp;
1742 uint8_t wc, bt;
1743 uint16_t ec, dlen, bc;
1744 int maxent, error, iseof = 0;
1745
1746 maxent = min(ctx->f_left,
1747 (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
1748 if (ctx->f_rq) {
1749 smb_rq_done(ctx->f_rq);
1750 ctx->f_rq = NULL;
1751 }
1752 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
1753 ctx->f_scred, &rqp);
1754 if (error)
1755 return (error);
1756 ctx->f_rq = rqp;
1757 smb_rq_getrequest(rqp, &mbp);
1758 smb_rq_wstart(rqp);
1759 mb_put_uint16le(mbp, maxent); /* max entries to return */
1760 mb_put_uint16le(mbp, ctx->f_attrmask);
1761 smb_rq_wend(rqp);
1762 smb_rq_bstart(rqp);
1763 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */
1764 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1765 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
1766 ctx->f_wildcard, ctx->f_wclen, '\\');
1767 if (error)
1768 return (error);
1769 mb_put_uint8(mbp, SMB_DT_VARIABLE);
1770 mb_put_uint16le(mbp, 0); /* context length */
1771 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1772 } else {
1773 if (SMB_UNICODE_STRINGS(vcp)) {
1774 mb_put_padbyte(mbp);
1775 mb_put_uint8(mbp, 0);
1776 }
1777 mb_put_uint8(mbp, 0);
1778 mb_put_uint8(mbp, SMB_DT_VARIABLE);
1779 mb_put_uint16le(mbp, SMB_SKEYLEN);
1780 mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1781 }
1782 smb_rq_bend(rqp);
1783 error = smb_rq_simple(rqp);
1784 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
1785 error = 0;
1786 iseof = 1;
1787 ctx->f_flags |= SMBFS_RDD_EOF;
1788 } else if (error)
1789 return (error);
1790 smb_rq_getreply(rqp, &mdp);
1791 error = md_get_uint8(mdp, &wc);
1792 if (error)
1793 return (error);
1794 if (wc != 1)
1795 return (iseof ? ENOENT : EBADRPC);
1796 md_get_uint16le(mdp, &ec);
1797 md_get_uint16le(mdp, &bc);
1798 md_get_uint8(mdp, &bt);
1799 error = md_get_uint16le(mdp, &dlen);
1800 if (error)
1801 return (error);
1802 if (ec == 0)
1803 return (ENOENT);
1804 ctx->f_ecnt = ec;
1805 if (bc < 3)
1806 return (EBADRPC);
1807 bc -= 3;
1808 if (bt != SMB_DT_VARIABLE)
1809 return (EBADRPC);
1810 if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
1811 return (EBADRPC);
1812 return (0);
1813 }
1814
1815
1816 /*ARGSUSED*/
1817 static int
smbfs_smb_findopenLM1(struct smbfs_fctx * ctx,struct smbnode * dnp,const char * wildcard,int wclen,uint16_t attr)1818 smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
1819 const char *wildcard, int wclen, uint16_t attr)
1820 {
1821
1822 ctx->f_type = ft_LM1;
1823 ctx->f_attrmask = attr;
1824 if (wildcard) {
1825 if (wclen == 1 && wildcard[0] == '*') {
1826 ctx->f_wildcard = "*.*";
1827 ctx->f_wclen = 3;
1828 } else {
1829 ctx->f_wildcard = wildcard;
1830 ctx->f_wclen = wclen;
1831 }
1832 } else {
1833 ctx->f_wildcard = NULL;
1834 ctx->f_wclen = 0;
1835 }
1836 ctx->f_name = (char *)ctx->f_fname;
1837 ctx->f_namesz = 0;
1838 return (0);
1839 }
1840
1841 static int
smbfs_smb_findnextLM1(struct smbfs_fctx * ctx,uint16_t limit)1842 smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
1843 {
1844 struct mdchain *mdp;
1845 struct smb_rq *rqp;
1846 char *cp;
1847 uint8_t battr;
1848 uint16_t date, time;
1849 uint32_t size;
1850 int error;
1851 struct timespec ts;
1852
1853 if (ctx->f_ecnt == 0) {
1854 if (ctx->f_flags & SMBFS_RDD_EOF)
1855 return (ENOENT);
1856 ctx->f_left = ctx->f_limit = limit;
1857 gethrestime(&ts);
1858 error = smbfs_smb_search(ctx);
1859 if (error)
1860 return (error);
1861 }
1862 rqp = ctx->f_rq;
1863 smb_rq_getreply(rqp, &mdp);
1864 md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1865 md_get_uint8(mdp, &battr);
1866 md_get_uint16le(mdp, &time);
1867 md_get_uint16le(mdp, &date);
1868 md_get_uint32le(mdp, &size);
1869 cp = ctx->f_name;
1870 error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
1871 cp[sizeof (ctx->f_fname) - 1] = 0;
1872 cp += strlen(cp) - 1;
1873 while (*cp == ' ' && cp >= ctx->f_name)
1874 *cp-- = 0;
1875 ctx->f_attr.fa_attr = battr;
1876 smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
1877 &ctx->f_attr.fa_mtime);
1878 ctx->f_attr.fa_size = size;
1879 ctx->f_nmlen = strlen(ctx->f_name);
1880 ctx->f_ecnt--;
1881 ctx->f_left--;
1882 return (0);
1883 }
1884
1885 static int
smbfs_smb_findcloseLM1(struct smbfs_fctx * ctx)1886 smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
1887 {
1888 if (ctx->f_rq)
1889 smb_rq_done(ctx->f_rq);
1890 return (0);
1891 }
1892
1893 /*
1894 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
1895 */
1896 static int
smbfs_smb_trans2find2(struct smbfs_fctx * ctx)1897 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
1898 {
1899 struct smb_t2rq *t2p;
1900 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1901 struct mbchain *mbp;
1902 struct mdchain *mdp;
1903 uint16_t ecnt, eos, lno, flags;
1904 int error;
1905
1906 if (ctx->f_t2) {
1907 smb_t2_done(ctx->f_t2);
1908 ctx->f_t2 = NULL;
1909 }
1910 flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
1911 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1912 flags |= FIND2_CLOSE_AFTER_REQUEST;
1913 ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1914 }
1915 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1916 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1917 ctx->f_scred, &t2p);
1918 if (error)
1919 return (error);
1920 ctx->f_t2 = t2p;
1921 mbp = &t2p->t2_tparam;
1922 mb_init(mbp);
1923 mb_put_uint16le(mbp, ctx->f_attrmask);
1924 mb_put_uint16le(mbp, ctx->f_limit);
1925 mb_put_uint16le(mbp, flags);
1926 mb_put_uint16le(mbp, ctx->f_infolevel);
1927 mb_put_uint32le(mbp, 0);
1928 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
1929 ctx->f_wildcard, ctx->f_wclen, '\\');
1930 if (error)
1931 return (error);
1932 } else {
1933 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1934 ctx->f_scred, &t2p);
1935 if (error)
1936 return (error);
1937 ctx->f_t2 = t2p;
1938 mbp = &t2p->t2_tparam;
1939 mb_init(mbp);
1940 mb_put_uint16le(mbp, ctx->f_Sid);
1941 mb_put_uint16le(mbp, ctx->f_limit);
1942 mb_put_uint16le(mbp, ctx->f_infolevel);
1943 /* Send whatever resume key we received... */
1944 mb_put_uint32le(mbp, ctx->f_rkey);
1945 mb_put_uint16le(mbp, flags);
1946 /* ... and the resume name if we have one. */
1947 if (ctx->f_rname) {
1948 /* resume file name */
1949 mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
1950 MB_MSYSTEM);
1951 }
1952 /* Add trailing null - 1 byte if ASCII, 2 if Unicode */
1953 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
1954 mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
1955 mb_put_uint8(mbp, 0);
1956 }
1957 t2p->t2_maxpcount = 5 * 2;
1958 t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */
1959 error = smb_t2_request(t2p);
1960 if (error)
1961 return (error);
1962
1963 /*
1964 * This is the "resume name" we just sent.
1965 * We want the new one (if any) that may be
1966 * found in the response we just received and
1967 * will now begin parsing. Free the old one
1968 * now so we'll know if we found a new one.
1969 */
1970 if (ctx->f_rname) {
1971 kmem_free(ctx->f_rname, ctx->f_rnamelen);
1972 ctx->f_rname = NULL;
1973 ctx->f_rnamelen = 0;
1974 }
1975
1976 mdp = &t2p->t2_rparam;
1977 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1978 if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
1979 goto nodata;
1980 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1981 }
1982 md_get_uint16le(mdp, &ecnt); /* entry count */
1983 md_get_uint16le(mdp, &eos); /* end of search */
1984 md_get_uint16le(mdp, NULL); /* EA err. off. */
1985 error = md_get_uint16le(mdp, &lno); /* last name off. */
1986 if (error != 0)
1987 goto nodata;
1988
1989 /*
1990 * The "end of search" flag from an XP server sometimes
1991 * comes back zero when the prior find_next returned exactly
1992 * the number of entries requested. in which case we'd try again
1993 * but the search has in fact been closed so an EBADF results.
1994 * our circumvention is to check here for a zero entry count.
1995 */
1996 ctx->f_ecnt = ecnt;
1997 if (eos || ctx->f_ecnt == 0)
1998 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1999 if (ctx->f_ecnt == 0)
2000 return (ENOENT);
2001
2002 /* Last Name Off (LNO) is the entry with the resume name. */
2003 ctx->f_rnameofs = lno;
2004 ctx->f_eofs = 0;
2005 return (0);
2006
2007 nodata:
2008 /*
2009 * Failed parsing the FindFirst or FindNext response.
2010 * Force this directory listing closed, otherwise the
2011 * calling process may hang in an infinite loop.
2012 */
2013 ctx->f_ecnt = 0; /* Force closed. */
2014 ctx->f_flags |= SMBFS_RDD_EOF;
2015 return (EIO);
2016 }
2017
2018 static int
smbfs_smb_findclose2(struct smbfs_fctx * ctx)2019 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
2020 {
2021 struct smb_rq rq, *rqp = &rq;
2022 struct mbchain *mbp;
2023 int error;
2024
2025 error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
2026 ctx->f_scred);
2027 if (error)
2028 return (error);
2029 smb_rq_getrequest(rqp, &mbp);
2030 smb_rq_wstart(rqp);
2031 mb_put_uint16le(mbp, ctx->f_Sid);
2032 smb_rq_wend(rqp);
2033 smb_rq_bstart(rqp);
2034 smb_rq_bend(rqp);
2035 /* Ditto comments at _smb_close */
2036 rqp->sr_flags |= SMBR_NOINTR_SEND;
2037 error = smb_rq_simple(rqp);
2038 smb_rq_done(rqp);
2039 return (error);
2040 }
2041
2042 /*ARGSUSED*/
2043 static int
smbfs_smb_findopenLM2(struct smbfs_fctx * ctx,struct smbnode * dnp,const char * wildcard,int wclen,uint16_t attr)2044 smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
2045 const char *wildcard, int wclen, uint16_t attr)
2046 {
2047
2048 ctx->f_type = ft_LM2;
2049 ctx->f_namesz = SMB_MAXFNAMELEN + 1;
2050 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2051 ctx->f_namesz *= 2;
2052 ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
2053 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
2054 < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
2055 SMB_FIND_BOTH_DIRECTORY_INFO;
2056 ctx->f_attrmask = attr;
2057 ctx->f_wildcard = wildcard;
2058 ctx->f_wclen = wclen;
2059 return (0);
2060 }
2061
2062 static int
smbfs_smb_findnextLM2(struct smbfs_fctx * ctx,uint16_t limit)2063 smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
2064 {
2065 struct mdchain *mdp;
2066 struct smb_t2rq *t2p;
2067 char *cp;
2068 uint8_t tb;
2069 uint16_t date, time, wattr;
2070 uint32_t size, next, dattr, resumekey = 0;
2071 uint64_t llongint;
2072 int error, svtz, cnt, fxsz, nmlen, recsz;
2073 struct timespec ts;
2074
2075 if (ctx->f_ecnt == 0) {
2076 if (ctx->f_flags & SMBFS_RDD_EOF)
2077 return (ENOENT);
2078 ctx->f_left = ctx->f_limit = limit;
2079 gethrestime(&ts);
2080 error = smbfs_smb_trans2find2(ctx);
2081 if (error)
2082 return (error);
2083 ctx->f_otws++;
2084 }
2085 t2p = ctx->f_t2;
2086 mdp = &t2p->t2_rdata;
2087 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
2088 switch (ctx->f_infolevel) {
2089 case SMB_FIND_STANDARD:
2090 next = 0;
2091 fxsz = 0;
2092 md_get_uint16le(mdp, &date);
2093 md_get_uint16le(mdp, &time); /* creation time */
2094 smb_dos2unixtime(date, time, 0, svtz,
2095 &ctx->f_attr.fa_createtime);
2096 md_get_uint16le(mdp, &date);
2097 md_get_uint16le(mdp, &time); /* access time */
2098 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
2099 md_get_uint16le(mdp, &date);
2100 md_get_uint16le(mdp, &time); /* modify time */
2101 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
2102 md_get_uint32le(mdp, &size);
2103 ctx->f_attr.fa_size = size;
2104 md_get_uint32le(mdp, &size); /* allocation size */
2105 ctx->f_attr.fa_allocsz = size;
2106 md_get_uint16le(mdp, &wattr);
2107 ctx->f_attr.fa_attr = wattr;
2108 error = md_get_uint8(mdp, &tb);
2109 if (error)
2110 goto nodata;
2111 size = nmlen = tb;
2112 fxsz = 23;
2113 recsz = next = 24 + nmlen; /* docs misses zero byte @end */
2114 break;
2115 case SMB_FIND_DIRECTORY_INFO:
2116 case SMB_FIND_BOTH_DIRECTORY_INFO:
2117 md_get_uint32le(mdp, &next);
2118 md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
2119 md_get_uint64le(mdp, &llongint); /* creation time */
2120 smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
2121 md_get_uint64le(mdp, &llongint);
2122 smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
2123 md_get_uint64le(mdp, &llongint);
2124 smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
2125 md_get_uint64le(mdp, &llongint);
2126 smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
2127 md_get_uint64le(mdp, &llongint); /* file size */
2128 ctx->f_attr.fa_size = llongint;
2129 md_get_uint64le(mdp, &llongint); /* alloc. size */
2130 ctx->f_attr.fa_allocsz = llongint;
2131 md_get_uint32le(mdp, &dattr); /* ext. file attributes */
2132 ctx->f_attr.fa_attr = dattr;
2133 error = md_get_uint32le(mdp, &size); /* name len */
2134 if (error)
2135 goto nodata;
2136 fxsz = 64; /* size ofinfo up to filename */
2137 if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
2138 /*
2139 * Skip EaSize(4 bytes), a byte of ShortNameLength,
2140 * a reserved byte, and ShortName(8.3 means 24 bytes,
2141 * as Leach defined it to always be Unicode)
2142 */
2143 error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
2144 if (error)
2145 goto nodata;
2146 fxsz += 30;
2147 }
2148 recsz = next ? next : fxsz + size;
2149 break;
2150 default:
2151 SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
2152 return (EINVAL);
2153 }
2154
2155 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2156 nmlen = min(size, SMB_MAXFNAMELEN * 2);
2157 else
2158 nmlen = min(size, SMB_MAXFNAMELEN);
2159
2160 /* Allocated f_name in findopen */
2161 ASSERT(nmlen < ctx->f_namesz);
2162 cp = ctx->f_name;
2163
2164 error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
2165 if (error)
2166 goto nodata;
2167 if (next) {
2168 /* How much data to skip? */
2169 cnt = next - nmlen - fxsz;
2170 if (cnt < 0) {
2171 SMBVDEBUG("out of sync\n");
2172 goto nodata;
2173 }
2174 if (cnt > 0)
2175 md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
2176 }
2177 /* Don't count any trailing null in the name. */
2178 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
2179 if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
2180 nmlen -= 2;
2181 } else {
2182 if (nmlen && cp[nmlen - 1] == 0)
2183 nmlen--;
2184 }
2185 if (nmlen == 0)
2186 goto nodata;
2187
2188 /*
2189 * On a find-next we expect that the server will:
2190 * 1) if the continue bit is set, use the server's offset,
2191 * 2) else if the resume key is non-zero, use that offset,
2192 * 3) else if the resume name is set, use that offset,
2193 * 4) else use the server's idea of current offset.
2194 *
2195 * We always set the resume key flag. If the server returns
2196 * a resume key then we should always send it back to them.
2197 */
2198 ctx->f_rkey = resumekey;
2199
2200 next = ctx->f_eofs + recsz;
2201 if (ctx->f_rnameofs &&
2202 ctx->f_rnameofs >= ctx->f_eofs &&
2203 ctx->f_rnameofs < (int)next) {
2204 /*
2205 * This entry is the "resume name".
2206 * Save it for the next request.
2207 */
2208 if (ctx->f_rnamelen != nmlen) {
2209 if (ctx->f_rname)
2210 kmem_free(ctx->f_rname, ctx->f_rnamelen);
2211 ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
2212 ctx->f_rnamelen = nmlen;
2213 }
2214 bcopy(ctx->f_name, ctx->f_rname, nmlen);
2215 }
2216 ctx->f_nmlen = nmlen;
2217 ctx->f_eofs = next;
2218 ctx->f_ecnt--;
2219 ctx->f_left--;
2220
2221 smbfs_fname_tolocal(ctx);
2222 return (0);
2223
2224 nodata:
2225 /*
2226 * Something bad has happened and we ran out of data
2227 * before we could parse all f_ecnt entries expected.
2228 * Force this directory listing closed, otherwise the
2229 * calling process may hang in an infinite loop.
2230 */
2231 SMBVDEBUG("ran out of data\n");
2232 ctx->f_ecnt = 0; /* Force closed. */
2233 ctx->f_flags |= SMBFS_RDD_EOF;
2234 return (EIO);
2235 }
2236
2237 static int
smbfs_smb_findcloseLM2(struct smbfs_fctx * ctx)2238 smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
2239 {
2240 int error = 0;
2241 if (ctx->f_name)
2242 kmem_free(ctx->f_name, ctx->f_namesz);
2243 if (ctx->f_t2)
2244 smb_t2_done(ctx->f_t2);
2245 /*
2246 * If SMBFS_RDD_FINDFIRST is still set, we were opened
2247 * but never saw a findfirst, so we don't have any
2248 * search handle to close.
2249 */
2250 if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
2251 error = smbfs_smb_findclose2(ctx);
2252 return (error);
2253 }
2254
2255 int
smbfs_smb_findopen(struct smbnode * dnp,const char * wild,int wlen,int attr,struct smb_cred * scrp,struct smbfs_fctx ** ctxpp)2256 smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
2257 int attr, struct smb_cred *scrp,
2258 struct smbfs_fctx **ctxpp)
2259 {
2260 struct smbfs_fctx *ctx;
2261 int error;
2262
2263 ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
2264
2265 ctx->f_flags = SMBFS_RDD_FINDFIRST;
2266 ctx->f_dnp = dnp;
2267 ctx->f_scred = scrp;
2268 ctx->f_ssp = dnp->n_mount->smi_share;
2269
2270 if (dnp->n_flag & N_XATTR) {
2271 error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
2272 goto out;
2273 }
2274
2275 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) {
2276 error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr);
2277 } else {
2278 error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
2279 }
2280
2281 out:
2282 if (error)
2283 (void) smbfs_smb_findclose(ctx, scrp);
2284 else
2285 *ctxpp = ctx;
2286 return (error);
2287 }
2288
2289 int
smbfs_smb_findnext(struct smbfs_fctx * ctx,int limit,struct smb_cred * scrp)2290 smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
2291 {
2292 int error;
2293
2294 /*
2295 * Note: "limit" (maxcount) needs to fit in a short!
2296 */
2297 if (limit > 0xffff)
2298 limit = 0xffff;
2299
2300 ctx->f_scred = scrp;
2301 for (;;) {
2302 bzero(&ctx->f_attr, sizeof (ctx->f_attr));
2303 switch (ctx->f_type) {
2304 case ft_LM1:
2305 error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
2306 break;
2307 case ft_LM2:
2308 error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
2309 break;
2310 case ft_XA:
2311 error = smbfs_xa_findnext(ctx, (uint16_t)limit);
2312 break;
2313 default:
2314 ASSERT(0);
2315 error = EINVAL;
2316 break;
2317 }
2318 if (error)
2319 return (error);
2320 /*
2321 * Skip "." or ".." - easy now that ctx->f_name
2322 * has already been converted to utf-8 format.
2323 */
2324 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
2325 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
2326 ctx->f_name[1] == '.'))
2327 continue;
2328 break;
2329 }
2330
2331 /*
2332 * Moved the smbfs_fname_tolocal(ctx) call into
2333 * the ..._findnext functions above.
2334 */
2335
2336 ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
2337 return (0);
2338 }
2339
2340
2341 int
smbfs_smb_findclose(struct smbfs_fctx * ctx,struct smb_cred * scrp)2342 smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
2343 {
2344 int error;
2345
2346 ctx->f_scred = scrp;
2347 switch (ctx->f_type) {
2348 case ft_LM1:
2349 error = smbfs_smb_findcloseLM1(ctx);
2350 break;
2351 case ft_LM2:
2352 error = smbfs_smb_findcloseLM2(ctx);
2353 break;
2354 case ft_XA:
2355 error = smbfs_xa_findclose(ctx);
2356 break;
2357 }
2358 if (ctx->f_rname)
2359 kmem_free(ctx->f_rname, ctx->f_rnamelen);
2360 if (ctx->f_firstnm)
2361 kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
2362 kmem_free(ctx, sizeof (*ctx));
2363 return (error);
2364 }
2365
2366
2367 int
smbfs_smb_lookup(struct smbnode * dnp,const char ** namep,int * nmlenp,struct smbfattr * fap,struct smb_cred * scrp)2368 smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
2369 struct smbfattr *fap, struct smb_cred *scrp)
2370 {
2371 struct smbfs_fctx *ctx;
2372 int error, intr;
2373 const char *name = (namep ? *namep : NULL);
2374 int nmlen = (nmlenp ? *nmlenp : 0);
2375
2376 /* This is no longer called with a null dnp */
2377 ASSERT(dnp);
2378
2379 /*
2380 * Should not get here with "" anymore.
2381 */
2382 if (!name || !nmlen) {
2383 DEBUG_ENTER("smbfs_smb_lookup: name is NULL");
2384 return (EINVAL);
2385 }
2386
2387 /*
2388 * Should not get here with "." or ".." anymore.
2389 */
2390 if ((nmlen == 1 && name[0] == '.') ||
2391 (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
2392 DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
2393 return (EINVAL);
2394 }
2395
2396 /*
2397 * XXX: Should use _qpathinfo here instead.
2398 * (if SMB_CAP_NT_SMBS)
2399 */
2400
2401 /*
2402 * Shared lock for n_fid use (smb_flush).
2403 */
2404 intr = dnp->n_mount->smi_flags & SMI_INT;
2405 if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
2406 return (EINTR);
2407
2408 /*
2409 * This hides a server bug observable in Win98:
2410 * size changes may not show until a CLOSE or a FLUSH op
2411 * XXX: Make this conditional on !NTSMBs
2412 */
2413 error = smbfs_smb_flush(dnp, scrp);
2414 if (error)
2415 goto out;
2416 error = smbfs_smb_findopen(dnp, name, nmlen,
2417 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
2418 if (error)
2419 goto out;
2420 ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
2421 error = smbfs_smb_findnext(ctx, 1, scrp);
2422 if (error == 0) {
2423 *fap = ctx->f_attr;
2424 /*
2425 * Solaris smbfattr doesn't have fa_ino,
2426 * and we don't allow name==NULL in this
2427 * function anymore.
2428 */
2429 if (namep)
2430 *namep = (const char *)smbfs_name_alloc(
2431 ctx->f_name, ctx->f_nmlen);
2432 if (nmlenp)
2433 *nmlenp = ctx->f_nmlen;
2434 }
2435 (void) smbfs_smb_findclose(ctx, scrp);
2436
2437 out:
2438 smbfs_rw_exit(&dnp->r_lkserlock);
2439 return (error);
2440 }
2441
2442 /*
2443 * OTW function to Get a security descriptor (SD).
2444 *
2445 * Note: On success, this fills in mdp->md_top,
2446 * which the caller should free.
2447 */
2448 int
smbfs_smb_getsec_m(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp,uint32_t selector,mblk_t ** res,uint32_t * reslen)2449 smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
2450 struct smb_cred *scrp, uint32_t selector,
2451 mblk_t **res, uint32_t *reslen)
2452 {
2453 struct smb_ntrq *ntp;
2454 struct mbchain *mbp;
2455 struct mdchain *mdp;
2456 int error, len;
2457
2458 error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
2459 scrp, &ntp);
2460 if (error)
2461 return (error);
2462
2463 /* Parameters part */
2464 mbp = &ntp->nt_tparam;
2465 mb_init(mbp);
2466 mb_put_uint16le(mbp, fid);
2467 mb_put_uint16le(mbp, 0); /* reserved */
2468 mb_put_uint32le(mbp, selector);
2469 /* Data part (none) */
2470
2471 /* Max. returned parameters and data. */
2472 ntp->nt_maxpcount = 4;
2473 ntp->nt_maxdcount = *reslen;
2474
2475 error = smb_nt_request(ntp);
2476 if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
2477 goto done;
2478 *res = NULL;
2479
2480 /*
2481 * if there's more data than we said we could receive, here
2482 * is where we pick up the length of it
2483 */
2484 mdp = &ntp->nt_rparam;
2485 md_get_uint32le(mdp, reslen);
2486 if (error)
2487 goto done;
2488
2489 /*
2490 * get the data part.
2491 */
2492 mdp = &ntp->nt_rdata;
2493 if (mdp->md_top == NULL) {
2494 SMBVDEBUG("null md_top? fid 0x%x\n", fid);
2495 error = EBADRPC;
2496 goto done;
2497 }
2498
2499 /*
2500 * The returned parameter SD_length should match
2501 * the length of the returned data. Unfortunately,
2502 * we have to work around server bugs here.
2503 */
2504 len = m_fixhdr(mdp->md_top);
2505 if (len != *reslen) {
2506 SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
2507 len, *reslen, fid);
2508 }
2509
2510 /*
2511 * Actual data provided is < returned SD_length.
2512 *
2513 * The following "if (len < *reslen)" handles a Windows bug
2514 * observed when the underlying filesystem is FAT32. In that
2515 * case a 32 byte security descriptor comes back (S-1-1-0, ie
2516 * "Everyone") but the Parameter Block claims 44 is the length
2517 * of the security descriptor. (The Data Block length
2518 * claimed is 32. This server bug was reported against NT
2519 * first and I've personally observed it with W2K.
2520 */
2521 if (len < *reslen)
2522 *reslen = len;
2523
2524 /*
2525 * Actual data provided is > returned SD_length.
2526 * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
2527 * Narrow work-around for returned SD_length==0.
2528 */
2529 if (len > *reslen) {
2530 /*
2531 * Increase *reslen, but carefully.
2532 */
2533 if (*reslen == 0 && len <= ntp->nt_maxdcount)
2534 *reslen = len;
2535 }
2536 error = md_get_mbuf(mdp, len, res);
2537
2538 done:
2539 if (error == 0 && *res == NULL) {
2540 ASSERT(*res);
2541 error = EBADRPC;
2542 }
2543
2544 smb_nt_done(ntp);
2545 return (error);
2546 }
2547
2548 #ifdef APPLE
2549 /*
2550 * Wrapper for _getsd() compatible with darwin code.
2551 */
2552 int
smbfs_smb_getsec(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp,uint32_t selector,struct ntsecdesc ** res)2553 smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
2554 uint32_t selector, struct ntsecdesc **res)
2555 {
2556 int error;
2557 uint32_t len, olen;
2558 struct mdchain *mdp, md_store;
2559 struct mbuf *m;
2560
2561 bzero(mdp, sizeof (*mdp));
2562 len = 500; /* "overlarge" values => server errors */
2563 again:
2564 olen = len;
2565 error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
2566 /*
2567 * Server may give us an error indicating that we
2568 * need a larger data buffer to receive the SD,
2569 * and the size we'll need. Use the given size,
2570 * but only after a sanity check.
2571 *
2572 * XXX: Check for specific error values here?
2573 * XXX: also ... && len <= MAX_RAW_SD_SIZE
2574 */
2575 if (error && len > olen)
2576 goto again;
2577
2578 if (error)
2579 return (error);
2580
2581 mdp = &md_store;
2582 md_initm(mdp, m);
2583 MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
2584 error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
2585 md_done(mdp);
2586
2587 return (error);
2588 }
2589 #endif /* APPLE */
2590
2591 /*
2592 * OTW function to Set a security descriptor (SD).
2593 * Caller data are carried in an mbchain_t.
2594 *
2595 * Note: This normally consumes mbp->mb_top, and clears
2596 * that pointer when it does.
2597 */
smbfs_smb_setsec_m(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp,uint32_t selector,mblk_t ** mp)2598 int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
2599 struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
2600 {
2601 struct smb_ntrq *ntp;
2602 struct mbchain *mbp;
2603 int error;
2604
2605 error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
2606 scrp, &ntp);
2607 if (error)
2608 return (error);
2609
2610 /* Parameters part */
2611 mbp = &ntp->nt_tparam;
2612 mb_init(mbp);
2613 mb_put_uint16le(mbp, fid);
2614 mb_put_uint16le(mbp, 0); /* reserved */
2615 mb_put_uint32le(mbp, selector);
2616
2617 /* Data part */
2618 mbp = &ntp->nt_tdata;
2619 mb_initm(mbp, *mp);
2620 *mp = NULL; /* consumed */
2621
2622 /* No returned parameters or data. */
2623 ntp->nt_maxpcount = 0;
2624 ntp->nt_maxdcount = 0;
2625
2626 error = smb_nt_request(ntp);
2627 smb_nt_done(ntp);
2628
2629 return (error);
2630 }
2631
2632 #ifdef APPLE
2633 /*
2634 * This function builds the SD given the various parts.
2635 */
2636 int
smbfs_smb_setsec(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp,uint32_t selector,uint16_t flags,struct ntsid * owner,struct ntsid * group,struct ntacl * sacl,struct ntacl * dacl)2637 smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
2638 uint32_t selector, uint16_t flags, struct ntsid *owner,
2639 struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
2640 {
2641 struct mbchain *mbp, mb_store;
2642 struct ntsecdesc ntsd;
2643 int error, off;
2644
2645 /*
2646 * Build the SD as its own mbuf chain and pass it to
2647 * smbfs_smb_setsec_m()
2648 */
2649 mbp = &mb_store;
2650 mb_init(mbp);
2651 bzero(&ntsd, sizeof (ntsd));
2652 wset_sdrevision(&ntsd);
2653 /*
2654 * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
2655 * We set here only those bits we can be sure must be set. The rest
2656 * are up to the caller. In particular, the caller may intentionally
2657 * set an acl PRESENT bit while giving us a null pointer for the
2658 * acl - that sets a null acl, giving access to everyone. Note also
2659 * that the AUTO_INHERITED bits should probably always be set unless
2660 * the server is NT.
2661 */
2662 flags |= SD_SELF_RELATIVE;
2663 off = sizeof (ntsd);
2664 if (owner) {
2665 wset_sdowneroff(&ntsd, off);
2666 off += sidlen(owner);
2667 }
2668 if (group) {
2669 wset_sdgroupoff(&ntsd, off);
2670 off += sidlen(group);
2671 }
2672 if (sacl) {
2673 flags |= SD_SACL_PRESENT;
2674 wset_sdsacloff(&ntsd, off);
2675 off += acllen(sacl);
2676 }
2677 if (dacl) {
2678 flags |= SD_DACL_PRESENT;
2679 wset_sddacloff(&ntsd, off);
2680 }
2681 wset_sdflags(&ntsd, flags);
2682 mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
2683 if (owner)
2684 mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
2685 if (group)
2686 mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
2687 if (sacl)
2688 mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
2689 if (dacl)
2690 mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
2691
2692 /*
2693 * Just pass the mbuf to _setsec_m
2694 * It will clear mb_top if consumed.
2695 */
2696 error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
2697 mb_done(mbp);
2698
2699 return (error);
2700 }
2701
2702 #endif /* APPLE */
2703