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 * $FreeBSD$ 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/proc.h> 39 #include <sys/lock.h> 40 #include <sys/vnode.h> 41 #include <sys/mbuf.h> 42 #include <sys/mount.h> 43 44 #ifdef USE_MD5_HASH 45 #include <sys/md5.h> 46 #endif 47 48 #include <netsmb/smb.h> 49 #include <netsmb/smb_subr.h> 50 #include <netsmb/smb_rq.h> 51 #include <netsmb/smb_conn.h> 52 53 #include <fs/smbfs/smbfs.h> 54 #include <fs/smbfs/smbfs_node.h> 55 #include <fs/smbfs/smbfs_subr.h> 56 57 /* 58 * Lack of inode numbers leads us to the problem of generating them. 59 * Partially this problem can be solved by having a dir/file cache 60 * with inode numbers generated from the incremented by one counter. 61 * However this way will require too much kernel memory, gives all 62 * sorts of locking and consistency problems, not to mentinon counter overflows. 63 * So, I'm decided to use a hash function to generate pseudo random (and unique) 64 * inode numbers. 65 */ 66 static long 67 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen) 68 { 69 #ifdef USE_MD5_HASH 70 MD5_CTX md5; 71 u_int32_t state[4]; 72 long ino; 73 int i; 74 75 MD5Init(&md5); 76 MD5Update(&md5, name, nmlen); 77 MD5Final((u_char *)state, &md5); 78 for (i = 0, ino = 0; i < 4; i++) 79 ino += state[i]; 80 return dnp->n_ino + ino; 81 #endif 82 u_int32_t ino; 83 84 ino = dnp->n_ino + smbfs_hash(name, nmlen); 85 if (ino <= 2) 86 ino += 3; 87 return ino; 88 } 89 90 static int 91 smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end, 92 struct smb_cred *scred) 93 { 94 struct smb_share *ssp = np->n_mount->sm_share; 95 struct smb_rq rq, *rqp = &rq; 96 struct mbchain *mbp; 97 u_char ltype = 0; 98 int error; 99 100 if (op == SMB_LOCK_SHARED) 101 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; 102 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred); 103 if (error) 104 return error; 105 smb_rq_getrequest(rqp, &mbp); 106 smb_rq_wstart(rqp); 107 mb_put_uint8(mbp, 0xff); /* secondary command */ 108 mb_put_uint8(mbp, 0); /* MBZ */ 109 mb_put_uint16le(mbp, 0); 110 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 111 mb_put_uint8(mbp, ltype); /* locktype */ 112 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ 113 mb_put_uint32le(mbp, 0); /* timeout - break immediately */ 114 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); 115 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); 116 smb_rq_wend(rqp); 117 smb_rq_bstart(rqp); 118 mb_put_uint16le(mbp, pid); 119 mb_put_uint32le(mbp, start); 120 mb_put_uint32le(mbp, end - start); 121 smb_rq_bend(rqp); 122 error = smb_rq_simple(rqp); 123 smb_rq_done(rqp); 124 return error; 125 } 126 127 int 128 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, 129 off_t start, off_t end, struct smb_cred *scred) 130 { 131 struct smb_share *ssp = np->n_mount->sm_share; 132 133 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) 134 /* 135 * TODO: use LOCK_BYTE_RANGE here. 136 */ 137 return EINVAL; 138 else 139 return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred); 140 } 141 142 static int 143 smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, 144 struct smb_cred *scred, short infolevel) 145 { 146 struct smb_share *ssp = np->n_mount->sm_share; 147 struct smb_vc *vcp = SSTOVC(ssp); 148 struct smb_t2rq *t2p; 149 int error, svtz, timesok = 1; 150 struct mbchain *mbp; 151 struct mdchain *mdp; 152 u_int16_t date, time, wattr; 153 int64_t lint; 154 u_int32_t size, dattr; 155 156 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION, 157 scred, &t2p); 158 if (error) 159 return error; 160 mbp = &t2p->t2_tparam; 161 mb_init(mbp); 162 if (!infolevel) { 163 if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) 164 infolevel = SMB_QUERY_FILE_STANDARD; 165 else 166 infolevel = SMB_QUERY_FILE_BASIC_INFO; 167 } 168 mb_put_uint16le(mbp, infolevel); 169 mb_put_uint32le(mbp, 0); 170 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ 171 error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 172 if (error) { 173 smb_t2_done(t2p); 174 return error; 175 } 176 t2p->t2_maxpcount = 2; 177 t2p->t2_maxdcount = vcp->vc_txmax; 178 error = smb_t2_request(t2p); 179 if (error) { 180 smb_t2_done(t2p); 181 if (infolevel == SMB_QUERY_FILE_STANDARD || error != EINVAL) 182 return error; 183 return smbfs_smb_qpathinfo(np, fap, scred, 184 SMB_QUERY_FILE_STANDARD); 185 } 186 mdp = &t2p->t2_rdata; 187 svtz = vcp->vc_sopt.sv_tz; 188 switch (infolevel) { 189 case SMB_QUERY_FILE_STANDARD: 190 timesok = 0; 191 md_get_uint16le(mdp, NULL); 192 md_get_uint16le(mdp, NULL); /* creation time */ 193 md_get_uint16le(mdp, &date); 194 md_get_uint16le(mdp, &time); /* access time */ 195 if (date || time) { 196 timesok++; 197 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); 198 } 199 md_get_uint16le(mdp, &date); 200 md_get_uint16le(mdp, &time); /* modify time */ 201 if (date || time) { 202 timesok++; 203 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); 204 } 205 md_get_uint32le(mdp, &size); 206 fap->fa_size = size; 207 md_get_uint32(mdp, NULL); /* allocation size */ 208 md_get_uint16le(mdp, &wattr); 209 fap->fa_attr = wattr; 210 break; 211 case SMB_QUERY_FILE_BASIC_INFO: 212 timesok = 0; 213 md_get_int64(mdp, NULL); /* creation time */ 214 md_get_int64le(mdp, &lint); 215 if (lint) { 216 timesok++; 217 smb_time_NT2local(lint, svtz, &fap->fa_atime); 218 } 219 md_get_int64le(mdp, &lint); 220 if (lint) { 221 timesok++; 222 smb_time_NT2local(lint, svtz, &fap->fa_mtime); 223 } 224 md_get_int64le(mdp, &lint); 225 if (lint) { 226 timesok++; 227 smb_time_NT2local(lint, svtz, &fap->fa_ctime); 228 } 229 md_get_uint32le(mdp, &dattr); 230 fap->fa_attr = dattr; 231 md_get_uint32(mdp, NULL); 232 /* XXX could use ALL_INFO to get size */ 233 break; 234 default: 235 SMBERROR("unexpected info level %d\n", infolevel); 236 error = EINVAL; 237 } 238 smb_t2_done(t2p); 239 /* 240 * if all times are zero (observed with FAT on NT4SP6) 241 * then fall back to older info level 242 */ 243 if (!timesok) { 244 if (infolevel != SMB_QUERY_FILE_STANDARD) 245 return smbfs_smb_qpathinfo(np, fap, scred, 246 SMB_QUERY_FILE_STANDARD); 247 error = EINVAL; 248 } 249 return error; 250 } 251 252 int 253 smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp, 254 struct smb_cred *scred) 255 { 256 struct smb_t2rq *t2p; 257 struct mbchain *mbp; 258 struct mdchain *mdp; 259 u_int16_t bsize; 260 u_int32_t units, bpu, funits; 261 int error; 262 263 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 264 scred, &t2p); 265 if (error) 266 return error; 267 mbp = &t2p->t2_tparam; 268 mb_init(mbp); 269 mb_put_uint16le(mbp, SMB_INFO_ALLOCATION); 270 t2p->t2_maxpcount = 4; 271 t2p->t2_maxdcount = 4 * 4 + 2; 272 error = smb_t2_request(t2p); 273 if (error) { 274 smb_t2_done(t2p); 275 return error; 276 } 277 mdp = &t2p->t2_rdata; 278 md_get_uint32(mdp, NULL); /* fs id */ 279 md_get_uint32le(mdp, &bpu); 280 md_get_uint32le(mdp, &units); 281 md_get_uint32le(mdp, &funits); 282 md_get_uint16le(mdp, &bsize); 283 sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 284 sbp->f_blocks= units; /* total data blocks in filesystem */ 285 sbp->f_bfree = funits; /* free blocks in fs */ 286 sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 287 sbp->f_files = 0xffff; /* total file nodes in filesystem */ 288 sbp->f_ffree = 0xffff; /* free file nodes in fs */ 289 smb_t2_done(t2p); 290 return 0; 291 } 292 293 int 294 smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, 295 struct smb_cred *scred) 296 { 297 struct smb_rq rq, *rqp = &rq; 298 struct mdchain *mdp; 299 u_int16_t units, bpu, bsize, funits; 300 int error; 301 302 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred); 303 if (error) 304 return error; 305 smb_rq_wstart(rqp); 306 smb_rq_wend(rqp); 307 smb_rq_bstart(rqp); 308 smb_rq_bend(rqp); 309 error = smb_rq_simple(rqp); 310 if (error) { 311 smb_rq_done(rqp); 312 return error; 313 } 314 smb_rq_getreply(rqp, &mdp); 315 md_get_uint16le(mdp, &units); 316 md_get_uint16le(mdp, &bpu); 317 md_get_uint16le(mdp, &bsize); 318 md_get_uint16le(mdp, &funits); 319 sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 320 sbp->f_blocks= units; /* total data blocks in filesystem */ 321 sbp->f_bfree = funits; /* free blocks in fs */ 322 sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 323 sbp->f_files = 0xffff; /* total file nodes in filesystem */ 324 sbp->f_ffree = 0xffff; /* free file nodes in fs */ 325 smb_rq_done(rqp); 326 return 0; 327 } 328 329 static int 330 smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred) 331 { 332 struct smb_t2rq *t2p; 333 struct smb_share *ssp = np->n_mount->sm_share; 334 struct mbchain *mbp; 335 int error; 336 337 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 338 scred, &t2p); 339 if (error) 340 return error; 341 mbp = &t2p->t2_tparam; 342 mb_init(mbp); 343 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 344 mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO); 345 mb_put_uint32le(mbp, 0); 346 mbp = &t2p->t2_tdata; 347 mb_init(mbp); 348 mb_put_int64le(mbp, newsize); 349 mb_put_uint32le(mbp, 0); /* padding */ 350 mb_put_uint16le(mbp, 0); 351 t2p->t2_maxpcount = 2; 352 t2p->t2_maxdcount = 0; 353 error = smb_t2_request(t2p); 354 smb_t2_done(t2p); 355 return error; 356 } 357 358 static int 359 smb_smb_flush(struct smbnode *np, struct smb_cred *scred) 360 { 361 struct smb_share *ssp = np->n_mount->sm_share; 362 struct smb_rq rq, *rqp = &rq; 363 struct mbchain *mbp; 364 int error; 365 366 if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) || 367 SMBTOV(np)->v_type != VREG) 368 return 0; /* not a regular open file */ 369 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred); 370 if (error) 371 return (error); 372 smb_rq_getrequest(rqp, &mbp); 373 smb_rq_wstart(rqp); 374 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 375 smb_rq_wend(rqp); 376 smb_rq_bstart(rqp); 377 smb_rq_bend(rqp); 378 error = smb_rq_simple(rqp); 379 smb_rq_done(rqp); 380 if (!error) 381 np->n_flag &= ~NFLUSHWIRE; 382 return (error); 383 } 384 385 int 386 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred) 387 { 388 if (np->n_flag & NFLUSHWIRE) 389 return (smb_smb_flush(np, scred)); 390 return (0); 391 } 392 393 int 394 smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) 395 { 396 struct smb_share *ssp = np->n_mount->sm_share; 397 struct smb_rq rq, *rqp = &rq; 398 struct mbchain *mbp; 399 int error; 400 401 if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) { 402 np->n_flag |= NFLUSHWIRE; 403 return (0); 404 } 405 406 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred); 407 if (error) 408 return error; 409 smb_rq_getrequest(rqp, &mbp); 410 smb_rq_wstart(rqp); 411 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 412 mb_put_uint16le(mbp, 0); 413 mb_put_uint32le(mbp, newsize); 414 mb_put_uint16le(mbp, 0); 415 smb_rq_wend(rqp); 416 smb_rq_bstart(rqp); 417 mb_put_uint8(mbp, SMB_DT_DATA); 418 mb_put_uint16le(mbp, 0); 419 smb_rq_bend(rqp); 420 error = smb_rq_simple(rqp); 421 smb_rq_done(rqp); 422 return error; 423 } 424 425 int 426 smbfs_smb_query_info(struct smbnode *np, const char *name, int len, 427 struct smbfattr *fap, struct smb_cred *scred) 428 { 429 struct smb_rq rq, *rqp = &rq; 430 struct smb_share *ssp = np->n_mount->sm_share; 431 struct mbchain *mbp; 432 struct mdchain *mdp; 433 u_int8_t wc; 434 int error; 435 u_int16_t wattr; 436 u_int32_t lint; 437 438 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred); 439 if (error) 440 return error; 441 smb_rq_getrequest(rqp, &mbp); 442 smb_rq_wstart(rqp); 443 smb_rq_wend(rqp); 444 smb_rq_bstart(rqp); 445 mb_put_uint8(mbp, SMB_DT_ASCII); 446 do { 447 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len); 448 if (error) 449 break; 450 smb_rq_bend(rqp); 451 error = smb_rq_simple(rqp); 452 if (error) 453 break; 454 smb_rq_getreply(rqp, &mdp); 455 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) { 456 error = EBADRPC; 457 break; 458 } 459 md_get_uint16le(mdp, &wattr); 460 fap->fa_attr = wattr; 461 /* 462 * Be careful using the time returned here, as 463 * with FAT on NT4SP6, at least, the time returned is low 464 * 32 bits of 100s of nanoseconds (since 1601) so it rolls 465 * over about every seven minutes! 466 */ 467 md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */ 468 if (lint) /* avoid bogus zero returns */ 469 smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz, 470 &fap->fa_mtime); 471 md_get_uint32le(mdp, &lint); 472 fap->fa_size = lint; 473 } while(0); 474 smb_rq_done(rqp); 475 return error; 476 } 477 478 /* 479 * Set DOS file attributes. mtime should be NULL for dialects above lm10 480 */ 481 int 482 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 483 struct smb_cred *scred) 484 { 485 struct smb_rq rq, *rqp = &rq; 486 struct smb_share *ssp = np->n_mount->sm_share; 487 struct mbchain *mbp; 488 u_long time; 489 int error, svtz; 490 491 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred); 492 if (error) 493 return error; 494 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 495 smb_rq_getrequest(rqp, &mbp); 496 smb_rq_wstart(rqp); 497 mb_put_uint16le(mbp, attr); 498 if (mtime) { 499 smb_time_local2server(mtime, svtz, &time); 500 } else 501 time = 0; 502 mb_put_uint32le(mbp, time); /* mtime */ 503 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); 504 smb_rq_wend(rqp); 505 smb_rq_bstart(rqp); 506 mb_put_uint8(mbp, SMB_DT_ASCII); 507 do { 508 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 509 if (error) 510 break; 511 mb_put_uint8(mbp, SMB_DT_ASCII); 512 mb_put_uint8(mbp, 0); 513 smb_rq_bend(rqp); 514 error = smb_rq_simple(rqp); 515 if (error) { 516 SMBERROR("smb_rq_simple(rqp) => error %d\n", error); 517 break; 518 } 519 } while(0); 520 smb_rq_done(rqp); 521 return error; 522 } 523 524 /* 525 * Note, win95 doesn't support this call. 526 */ 527 int 528 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, 529 struct timespec *atime, int attr, struct smb_cred *scred) 530 { 531 struct smb_t2rq *t2p; 532 struct smb_share *ssp = np->n_mount->sm_share; 533 struct smb_vc *vcp = SSTOVC(ssp); 534 struct mbchain *mbp; 535 u_int16_t date, time; 536 int error, tzoff; 537 538 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 539 scred, &t2p); 540 if (error) 541 return error; 542 mbp = &t2p->t2_tparam; 543 mb_init(mbp); 544 mb_put_uint16le(mbp, SMB_INFO_STANDARD); 545 mb_put_uint32le(mbp, 0); /* MBZ */ 546 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 547 error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 548 if (error) { 549 smb_t2_done(t2p); 550 return error; 551 } 552 tzoff = vcp->vc_sopt.sv_tz; 553 mbp = &t2p->t2_tdata; 554 mb_init(mbp); 555 mb_put_uint32le(mbp, 0); /* creation time */ 556 if (atime) 557 smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 558 else 559 time = date = 0; 560 mb_put_uint16le(mbp, date); 561 mb_put_uint16le(mbp, time); 562 if (mtime) 563 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 564 else 565 time = date = 0; 566 mb_put_uint16le(mbp, date); 567 mb_put_uint16le(mbp, time); 568 mb_put_uint32le(mbp, 0); /* file size */ 569 mb_put_uint32le(mbp, 0); /* allocation unit size */ 570 mb_put_uint16le(mbp, attr); /* DOS attr */ 571 mb_put_uint32le(mbp, 0); /* EA size */ 572 t2p->t2_maxpcount = 5 * 2; 573 t2p->t2_maxdcount = vcp->vc_txmax; 574 error = smb_t2_request(t2p); 575 smb_t2_done(t2p); 576 return error; 577 } 578 579 /* 580 * NT level. Specially for win9x 581 */ 582 int 583 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, 584 struct timespec *atime, struct smb_cred *scred) 585 { 586 struct smb_t2rq *t2p; 587 struct smb_share *ssp = np->n_mount->sm_share; 588 struct smb_vc *vcp = SSTOVC(ssp); 589 struct mbchain *mbp; 590 int64_t tm; 591 int error, tzoff; 592 593 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 594 scred, &t2p); 595 if (error) 596 return error; 597 mbp = &t2p->t2_tparam; 598 mb_init(mbp); 599 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 600 mb_put_uint32le(mbp, 0); /* MBZ */ 601 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 602 error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 603 if (error) { 604 smb_t2_done(t2p); 605 return error; 606 } 607 tzoff = vcp->vc_sopt.sv_tz; 608 mbp = &t2p->t2_tdata; 609 mb_init(mbp); 610 mb_put_int64le(mbp, 0); /* creation time */ 611 if (atime) { 612 smb_time_local2NT(atime, tzoff, &tm); 613 } else 614 tm = 0; 615 mb_put_int64le(mbp, tm); 616 if (mtime) { 617 smb_time_local2NT(mtime, tzoff, &tm); 618 } else 619 tm = 0; 620 mb_put_int64le(mbp, tm); 621 mb_put_int64le(mbp, tm); /* change time */ 622 mb_put_uint32le(mbp, attr); /* attr */ 623 t2p->t2_maxpcount = 24; 624 t2p->t2_maxdcount = 56; 625 error = smb_t2_request(t2p); 626 smb_t2_done(t2p); 627 return error; 628 } 629 630 /* 631 * Set file atime and mtime. Doesn't supported by core dialect. 632 */ 633 int 634 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime, 635 struct timespec *atime, struct smb_cred *scred) 636 { 637 struct smb_rq rq, *rqp = &rq; 638 struct smb_share *ssp = np->n_mount->sm_share; 639 struct mbchain *mbp; 640 u_int16_t date, time; 641 int error, tzoff; 642 643 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred); 644 if (error) 645 return error; 646 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 647 smb_rq_getrequest(rqp, &mbp); 648 smb_rq_wstart(rqp); 649 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 650 mb_put_uint32le(mbp, 0); /* creation time */ 651 652 if (atime) 653 smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 654 else 655 time = date = 0; 656 mb_put_uint16le(mbp, date); 657 mb_put_uint16le(mbp, time); 658 if (mtime) 659 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 660 else 661 time = date = 0; 662 mb_put_uint16le(mbp, date); 663 mb_put_uint16le(mbp, time); 664 smb_rq_wend(rqp); 665 smb_rq_bstart(rqp); 666 smb_rq_bend(rqp); 667 error = smb_rq_simple(rqp); 668 SMBSDEBUG("%d\n", error); 669 smb_rq_done(rqp); 670 return error; 671 } 672 673 /* 674 * Set DOS file attributes. 675 * Looks like this call can be used only if CAP_NT_SMBS bit is on. 676 */ 677 int 678 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 679 struct timespec *atime, struct smb_cred *scred) 680 { 681 struct smb_t2rq *t2p; 682 struct smb_share *ssp = np->n_mount->sm_share; 683 struct mbchain *mbp; 684 int64_t tm; 685 int error, svtz; 686 687 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 688 scred, &t2p); 689 if (error) 690 return error; 691 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 692 mbp = &t2p->t2_tparam; 693 mb_init(mbp); 694 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 695 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 696 mb_put_uint32le(mbp, 0); 697 mbp = &t2p->t2_tdata; 698 mb_init(mbp); 699 mb_put_int64le(mbp, 0); /* creation time */ 700 if (atime) { 701 smb_time_local2NT(atime, svtz, &tm); 702 } else 703 tm = 0; 704 mb_put_int64le(mbp, tm); 705 if (mtime) { 706 smb_time_local2NT(mtime, svtz, &tm); 707 } else 708 tm = 0; 709 mb_put_int64le(mbp, tm); 710 mb_put_int64le(mbp, tm); /* change time */ 711 mb_put_uint16le(mbp, attr); 712 mb_put_uint32le(mbp, 0); /* padding */ 713 mb_put_uint16le(mbp, 0); 714 t2p->t2_maxpcount = 2; 715 t2p->t2_maxdcount = 0; 716 error = smb_t2_request(t2p); 717 smb_t2_done(t2p); 718 return error; 719 } 720 721 722 int 723 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) 724 { 725 struct smb_rq rq, *rqp = &rq; 726 struct smb_share *ssp = np->n_mount->sm_share; 727 struct mbchain *mbp; 728 struct mdchain *mdp; 729 u_int8_t wc; 730 u_int16_t fid, wattr, grantedmode; 731 int error; 732 733 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred); 734 if (error) 735 return error; 736 smb_rq_getrequest(rqp, &mbp); 737 smb_rq_wstart(rqp); 738 mb_put_uint16le(mbp, accmode); 739 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 740 smb_rq_wend(rqp); 741 smb_rq_bstart(rqp); 742 mb_put_uint8(mbp, SMB_DT_ASCII); 743 do { 744 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 745 if (error) 746 break; 747 smb_rq_bend(rqp); 748 error = smb_rq_simple(rqp); 749 if (error) 750 break; 751 smb_rq_getreply(rqp, &mdp); 752 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { 753 error = EBADRPC; 754 break; 755 } 756 md_get_uint16(mdp, &fid); 757 md_get_uint16le(mdp, &wattr); 758 md_get_uint32(mdp, NULL); /* mtime */ 759 md_get_uint32(mdp, NULL); /* fsize */ 760 md_get_uint16le(mdp, &grantedmode); 761 /* 762 * TODO: refresh attributes from this reply 763 */ 764 } while(0); 765 smb_rq_done(rqp); 766 if (error) 767 return error; 768 np->n_fid = fid; 769 np->n_rwstate = grantedmode; 770 return 0; 771 } 772 773 774 int 775 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, 776 struct smb_cred *scred) 777 { 778 struct smb_rq rq, *rqp = &rq; 779 struct mbchain *mbp; 780 u_long time; 781 int error; 782 783 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred); 784 if (error) 785 return error; 786 smb_rq_getrequest(rqp, &mbp); 787 smb_rq_wstart(rqp); 788 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 789 if (mtime) { 790 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); 791 } else 792 time = 0; 793 mb_put_uint32le(mbp, time); 794 smb_rq_wend(rqp); 795 smb_rq_bstart(rqp); 796 smb_rq_bend(rqp); 797 error = smb_rq_simple(rqp); 798 smb_rq_done(rqp); 799 return error; 800 } 801 802 int 803 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, 804 struct smb_cred *scred) 805 { 806 struct smb_rq rq, *rqp = &rq; 807 struct smb_share *ssp = dnp->n_mount->sm_share; 808 struct mbchain *mbp; 809 struct mdchain *mdp; 810 struct timespec ctime; 811 u_int8_t wc; 812 u_int16_t fid; 813 u_long tm; 814 int error; 815 816 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred); 817 if (error) 818 return error; 819 smb_rq_getrequest(rqp, &mbp); 820 smb_rq_wstart(rqp); 821 mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ 822 nanotime(&ctime); 823 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 824 mb_put_uint32le(mbp, tm); 825 smb_rq_wend(rqp); 826 smb_rq_bstart(rqp); 827 mb_put_uint8(mbp, SMB_DT_ASCII); 828 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); 829 if (!error) { 830 smb_rq_bend(rqp); 831 error = smb_rq_simple(rqp); 832 if (!error) { 833 smb_rq_getreply(rqp, &mdp); 834 md_get_uint8(mdp, &wc); 835 if (wc == 1) 836 md_get_uint16(mdp, &fid); 837 else 838 error = EBADRPC; 839 } 840 } 841 smb_rq_done(rqp); 842 if (error) 843 return error; 844 smbfs_smb_close(ssp, fid, &ctime, scred); 845 return error; 846 } 847 848 int 849 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred) 850 { 851 struct smb_rq rq, *rqp = &rq; 852 struct smb_share *ssp = np->n_mount->sm_share; 853 struct mbchain *mbp; 854 int error; 855 856 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred); 857 if (error) 858 return error; 859 smb_rq_getrequest(rqp, &mbp); 860 smb_rq_wstart(rqp); 861 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 862 smb_rq_wend(rqp); 863 smb_rq_bstart(rqp); 864 mb_put_uint8(mbp, SMB_DT_ASCII); 865 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 866 if (!error) { 867 smb_rq_bend(rqp); 868 error = smb_rq_simple(rqp); 869 } 870 smb_rq_done(rqp); 871 return error; 872 } 873 874 int 875 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 876 const char *tname, int tnmlen, struct smb_cred *scred) 877 { 878 struct smb_rq rq, *rqp = &rq; 879 struct smb_share *ssp = src->n_mount->sm_share; 880 struct mbchain *mbp; 881 int error; 882 883 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred); 884 if (error) 885 return error; 886 smb_rq_getrequest(rqp, &mbp); 887 smb_rq_wstart(rqp); 888 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 889 smb_rq_wend(rqp); 890 smb_rq_bstart(rqp); 891 mb_put_uint8(mbp, SMB_DT_ASCII); 892 do { 893 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 894 if (error) 895 break; 896 mb_put_uint8(mbp, SMB_DT_ASCII); 897 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 898 if (error) 899 break; 900 smb_rq_bend(rqp); 901 error = smb_rq_simple(rqp); 902 } while(0); 903 smb_rq_done(rqp); 904 return error; 905 } 906 907 int 908 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 909 const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred) 910 { 911 struct smb_rq rq, *rqp = &rq; 912 struct smb_share *ssp = src->n_mount->sm_share; 913 struct mbchain *mbp; 914 int error; 915 916 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred); 917 if (error) 918 return error; 919 smb_rq_getrequest(rqp, &mbp); 920 smb_rq_wstart(rqp); 921 mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 922 mb_put_uint16le(mbp, 0x20); /* delete target file */ 923 mb_put_uint16le(mbp, flags); 924 smb_rq_wend(rqp); 925 smb_rq_bstart(rqp); 926 mb_put_uint8(mbp, SMB_DT_ASCII); 927 do { 928 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 929 if (error) 930 break; 931 mb_put_uint8(mbp, SMB_DT_ASCII); 932 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 933 if (error) 934 break; 935 smb_rq_bend(rqp); 936 error = smb_rq_simple(rqp); 937 } while(0); 938 smb_rq_done(rqp); 939 return error; 940 } 941 942 int 943 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, 944 struct smb_cred *scred) 945 { 946 struct smb_rq rq, *rqp = &rq; 947 struct smb_share *ssp = dnp->n_mount->sm_share; 948 struct mbchain *mbp; 949 int error; 950 951 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred); 952 if (error) 953 return error; 954 smb_rq_getrequest(rqp, &mbp); 955 smb_rq_wstart(rqp); 956 smb_rq_wend(rqp); 957 smb_rq_bstart(rqp); 958 mb_put_uint8(mbp, SMB_DT_ASCII); 959 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len); 960 if (!error) { 961 smb_rq_bend(rqp); 962 error = smb_rq_simple(rqp); 963 } 964 smb_rq_done(rqp); 965 return error; 966 } 967 968 int 969 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred) 970 { 971 struct smb_rq rq, *rqp = &rq; 972 struct smb_share *ssp = np->n_mount->sm_share; 973 struct mbchain *mbp; 974 int error; 975 976 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred); 977 if (error) 978 return error; 979 smb_rq_getrequest(rqp, &mbp); 980 smb_rq_wstart(rqp); 981 smb_rq_wend(rqp); 982 smb_rq_bstart(rqp); 983 mb_put_uint8(mbp, SMB_DT_ASCII); 984 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 985 if (!error) { 986 smb_rq_bend(rqp); 987 error = smb_rq_simple(rqp); 988 } 989 smb_rq_done(rqp); 990 return error; 991 } 992 993 static int 994 smbfs_smb_search(struct smbfs_fctx *ctx) 995 { 996 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 997 struct smb_rq *rqp; 998 struct mbchain *mbp; 999 struct mdchain *mdp; 1000 u_int8_t wc, bt; 1001 u_int16_t ec, dlen, bc; 1002 int maxent, error, iseof = 0; 1003 1004 maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); 1005 if (ctx->f_rq) { 1006 smb_rq_done(ctx->f_rq); 1007 ctx->f_rq = NULL; 1008 } 1009 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); 1010 if (error) 1011 return error; 1012 ctx->f_rq = rqp; 1013 smb_rq_getrequest(rqp, &mbp); 1014 smb_rq_wstart(rqp); 1015 mb_put_uint16le(mbp, maxent); /* max entries to return */ 1016 mb_put_uint16le(mbp, ctx->f_attrmask); 1017 smb_rq_wend(rqp); 1018 smb_rq_bstart(rqp); 1019 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 1020 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1021 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 1022 if (error) 1023 return error; 1024 mb_put_uint8(mbp, SMB_DT_VARIABLE); 1025 mb_put_uint16le(mbp, 0); /* context length */ 1026 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 1027 } else { 1028 mb_put_uint8(mbp, 0); /* file name length */ 1029 mb_put_uint8(mbp, SMB_DT_VARIABLE); 1030 mb_put_uint16le(mbp, SMB_SKEYLEN); 1031 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 1032 } 1033 smb_rq_bend(rqp); 1034 error = smb_rq_simple(rqp); 1035 if (error) { 1036 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { 1037 error = 0; 1038 iseof = 1; 1039 ctx->f_flags |= SMBFS_RDD_EOF; 1040 } else 1041 return error; 1042 } 1043 smb_rq_getreply(rqp, &mdp); 1044 md_get_uint8(mdp, &wc); 1045 if (wc != 1) 1046 return iseof ? ENOENT : EBADRPC; 1047 md_get_uint16le(mdp, &ec); 1048 if (ec == 0) 1049 return ENOENT; 1050 ctx->f_ecnt = ec; 1051 md_get_uint16le(mdp, &bc); 1052 if (bc < 3) 1053 return EBADRPC; 1054 bc -= 3; 1055 md_get_uint8(mdp, &bt); 1056 if (bt != SMB_DT_VARIABLE) 1057 return EBADRPC; 1058 md_get_uint16le(mdp, &dlen); 1059 if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 1060 return EBADRPC; 1061 return 0; 1062 } 1063 1064 static int 1065 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 1066 const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1067 { 1068 ctx->f_attrmask = attr; 1069 if (wildcard) { 1070 if (wclen == 1 && wildcard[0] == '*') { 1071 ctx->f_wildcard = "*.*"; 1072 ctx->f_wclen = 3; 1073 } else { 1074 ctx->f_wildcard = wildcard; 1075 ctx->f_wclen = wclen; 1076 } 1077 } else { 1078 ctx->f_wildcard = NULL; 1079 ctx->f_wclen = 0; 1080 } 1081 ctx->f_name = ctx->f_fname; 1082 return 0; 1083 } 1084 1085 static int 1086 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) 1087 { 1088 struct mdchain *mbp; 1089 struct smb_rq *rqp; 1090 char *cp; 1091 u_int8_t battr; 1092 u_int16_t date, time; 1093 u_int32_t size; 1094 int error; 1095 1096 if (ctx->f_ecnt == 0) { 1097 if (ctx->f_flags & SMBFS_RDD_EOF) 1098 return ENOENT; 1099 ctx->f_left = ctx->f_limit = limit; 1100 error = smbfs_smb_search(ctx); 1101 if (error) 1102 return error; 1103 } 1104 rqp = ctx->f_rq; 1105 smb_rq_getreply(rqp, &mbp); 1106 md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 1107 md_get_uint8(mbp, &battr); 1108 md_get_uint16le(mbp, &time); 1109 md_get_uint16le(mbp, &date); 1110 md_get_uint32le(mbp, &size); 1111 cp = ctx->f_name; 1112 md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); 1113 cp[sizeof(ctx->f_fname) - 1] = 0; 1114 cp += strlen(cp) - 1; 1115 while (*cp == ' ' && cp >= ctx->f_name) 1116 *cp-- = 0; 1117 ctx->f_attr.fa_attr = battr; 1118 smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, 1119 &ctx->f_attr.fa_mtime); 1120 ctx->f_attr.fa_size = size; 1121 ctx->f_nmlen = strlen(ctx->f_name); 1122 ctx->f_ecnt--; 1123 ctx->f_left--; 1124 return 0; 1125 } 1126 1127 static int 1128 smbfs_findcloseLM1(struct smbfs_fctx *ctx) 1129 { 1130 if (ctx->f_rq) 1131 smb_rq_done(ctx->f_rq); 1132 return 0; 1133 } 1134 1135 /* 1136 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect 1137 */ 1138 static int 1139 smbfs_smb_trans2find2(struct smbfs_fctx *ctx) 1140 { 1141 struct smb_t2rq *t2p; 1142 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 1143 struct mbchain *mbp; 1144 struct mdchain *mdp; 1145 u_int16_t tw, flags; 1146 int error; 1147 1148 if (ctx->f_t2) { 1149 smb_t2_done(ctx->f_t2); 1150 ctx->f_t2 = NULL; 1151 } 1152 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 1153 flags = 8 | 2; /* <resume> | <close if EOS> */ 1154 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 1155 flags |= 1; /* close search after this request */ 1156 ctx->f_flags |= SMBFS_RDD_NOCLOSE; 1157 } 1158 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1159 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, 1160 ctx->f_scred, &t2p); 1161 if (error) 1162 return error; 1163 ctx->f_t2 = t2p; 1164 mbp = &t2p->t2_tparam; 1165 mb_init(mbp); 1166 mb_put_uint16le(mbp, ctx->f_attrmask); 1167 mb_put_uint16le(mbp, ctx->f_limit); 1168 mb_put_uint16le(mbp, flags); 1169 mb_put_uint16le(mbp, ctx->f_infolevel); 1170 mb_put_uint32le(mbp, 0); 1171 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 1172 if (error) 1173 return error; 1174 } else { 1175 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, 1176 ctx->f_scred, &t2p); 1177 if (error) 1178 return error; 1179 ctx->f_t2 = t2p; 1180 mbp = &t2p->t2_tparam; 1181 mb_init(mbp); 1182 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 1183 mb_put_uint16le(mbp, ctx->f_limit); 1184 mb_put_uint16le(mbp, ctx->f_infolevel); 1185 mb_put_uint32le(mbp, 0); /* resume key */ 1186 mb_put_uint16le(mbp, flags); 1187 if (ctx->f_rname) 1188 mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM); 1189 else 1190 mb_put_uint8(mbp, 0); /* resume file name */ 1191 #if 0 1192 struct timeval tv; 1193 tv.tv_sec = 0; 1194 tv.tv_usec = 200 * 1000; /* 200ms */ 1195 if (vcp->vc_flags & SMBC_WIN95) { 1196 /* 1197 * some implementations suggests to sleep here 1198 * for 200ms, due to the bug in the Win95. 1199 * I've didn't notice any problem, but put code 1200 * for it. 1201 */ 1202 pause("fix95", tvtohz(&tv)); 1203 } 1204 #endif 1205 } 1206 t2p->t2_maxpcount = 5 * 2; 1207 t2p->t2_maxdcount = vcp->vc_txmax; 1208 error = smb_t2_request(t2p); 1209 if (error) 1210 return error; 1211 mdp = &t2p->t2_rparam; 1212 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1213 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) 1214 return error; 1215 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 1216 } 1217 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1218 return error; 1219 ctx->f_ecnt = tw; 1220 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1221 return error; 1222 if (tw) 1223 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1224 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1225 return error; 1226 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1227 return error; 1228 if (ctx->f_ecnt == 0) { 1229 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1230 return ENOENT; 1231 } 1232 ctx->f_rnameofs = tw; 1233 mdp = &t2p->t2_rdata; 1234 if (mdp->md_top == NULL) { 1235 printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt); 1236 return ENOENT; 1237 } 1238 if (mdp->md_top->m_len == 0) { 1239 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next); 1240 return ENOENT; 1241 } 1242 ctx->f_eofs = 0; 1243 return 0; 1244 } 1245 1246 static int 1247 smbfs_smb_findclose2(struct smbfs_fctx *ctx) 1248 { 1249 struct smb_rq rq, *rqp = &rq; 1250 struct mbchain *mbp; 1251 int error; 1252 1253 error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred); 1254 if (error) 1255 return error; 1256 smb_rq_getrequest(rqp, &mbp); 1257 smb_rq_wstart(rqp); 1258 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 1259 smb_rq_wend(rqp); 1260 smb_rq_bstart(rqp); 1261 smb_rq_bend(rqp); 1262 error = smb_rq_simple(rqp); 1263 smb_rq_done(rqp); 1264 return error; 1265 } 1266 1267 static int 1268 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, 1269 const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1270 { 1271 ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); 1272 if (ctx->f_name == NULL) 1273 return ENOMEM; 1274 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? 1275 SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO; 1276 ctx->f_attrmask = attr; 1277 ctx->f_wildcard = wildcard; 1278 ctx->f_wclen = wclen; 1279 return 0; 1280 } 1281 1282 static int 1283 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) 1284 { 1285 struct mdchain *mbp; 1286 struct smb_t2rq *t2p; 1287 char *cp; 1288 u_int8_t tb; 1289 u_int16_t date, time, wattr; 1290 u_int32_t size, next, dattr; 1291 int64_t lint; 1292 int error, svtz, cnt, fxsz, nmlen, recsz; 1293 1294 if (ctx->f_ecnt == 0) { 1295 if (ctx->f_flags & SMBFS_RDD_EOF) 1296 return ENOENT; 1297 ctx->f_left = ctx->f_limit = limit; 1298 error = smbfs_smb_trans2find2(ctx); 1299 if (error) 1300 return error; 1301 } 1302 t2p = ctx->f_t2; 1303 mbp = &t2p->t2_rdata; 1304 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; 1305 switch (ctx->f_infolevel) { 1306 case SMB_INFO_STANDARD: 1307 next = 0; 1308 fxsz = 0; 1309 md_get_uint16le(mbp, &date); 1310 md_get_uint16le(mbp, &time); /* creation time */ 1311 md_get_uint16le(mbp, &date); 1312 md_get_uint16le(mbp, &time); /* access time */ 1313 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); 1314 md_get_uint16le(mbp, &date); 1315 md_get_uint16le(mbp, &time); /* access time */ 1316 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); 1317 md_get_uint32le(mbp, &size); 1318 ctx->f_attr.fa_size = size; 1319 md_get_uint32(mbp, NULL); /* allocation size */ 1320 md_get_uint16le(mbp, &wattr); 1321 ctx->f_attr.fa_attr = wattr; 1322 md_get_uint8(mbp, &tb); 1323 size = nmlen = tb; 1324 fxsz = 23; 1325 recsz = next = 24 + nmlen; /* docs misses zero byte at end */ 1326 break; 1327 case SMB_FIND_FILE_DIRECTORY_INFO: 1328 md_get_uint32le(mbp, &next); 1329 md_get_uint32(mbp, NULL); /* file index */ 1330 md_get_int64(mbp, NULL); /* creation time */ 1331 md_get_int64le(mbp, &lint); 1332 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); 1333 md_get_int64le(mbp, &lint); 1334 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); 1335 md_get_int64le(mbp, &lint); 1336 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); 1337 md_get_int64le(mbp, &lint); /* file size */ 1338 ctx->f_attr.fa_size = lint; 1339 md_get_int64(mbp, NULL); /* real size (should use) */ 1340 md_get_uint32le(mbp, &dattr); /* EA */ 1341 ctx->f_attr.fa_attr = dattr; 1342 md_get_uint32le(mbp, &size); /* name len */ 1343 fxsz = 64; 1344 recsz = next ? next : fxsz + size; 1345 break; 1346 default: 1347 SMBERROR("unexpected info level %d\n", ctx->f_infolevel); 1348 return EINVAL; 1349 } 1350 nmlen = min(size, SMB_MAXFNAMELEN); 1351 cp = ctx->f_name; 1352 error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); 1353 if (error) 1354 return error; 1355 if (next) { 1356 cnt = next - nmlen - fxsz; 1357 if (cnt > 0) 1358 md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); 1359 else if (cnt < 0) { 1360 SMBERROR("out of sync\n"); 1361 return EBADRPC; 1362 } 1363 } 1364 if (nmlen && cp[nmlen - 1] == 0) 1365 nmlen--; 1366 if (nmlen == 0) 1367 return EBADRPC; 1368 1369 next = ctx->f_eofs + recsz; 1370 if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && 1371 (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { 1372 /* 1373 * Server needs a resume filename. 1374 */ 1375 if (ctx->f_rnamelen <= nmlen) { 1376 if (ctx->f_rname) 1377 free(ctx->f_rname, M_SMBFSDATA); 1378 ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); 1379 ctx->f_rnamelen = nmlen; 1380 } 1381 bcopy(ctx->f_name, ctx->f_rname, nmlen); 1382 ctx->f_rname[nmlen] = 0; 1383 ctx->f_flags |= SMBFS_RDD_GOTRNAME; 1384 } 1385 ctx->f_nmlen = nmlen; 1386 ctx->f_eofs = next; 1387 ctx->f_ecnt--; 1388 ctx->f_left--; 1389 return 0; 1390 } 1391 1392 static int 1393 smbfs_findcloseLM2(struct smbfs_fctx *ctx) 1394 { 1395 if (ctx->f_name) 1396 free(ctx->f_name, M_SMBFSDATA); 1397 if (ctx->f_t2) 1398 smb_t2_done(ctx->f_t2); 1399 if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) 1400 smbfs_smb_findclose2(ctx); 1401 return 0; 1402 } 1403 1404 int 1405 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr, 1406 struct smb_cred *scred, struct smbfs_fctx **ctxpp) 1407 { 1408 struct smbfs_fctx *ctx; 1409 int error; 1410 1411 ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK); 1412 if (ctx == NULL) 1413 return ENOMEM; 1414 bzero(ctx, sizeof(*ctx)); 1415 ctx->f_ssp = dnp->n_mount->sm_share; 1416 ctx->f_dnp = dnp; 1417 ctx->f_flags = SMBFS_RDD_FINDFIRST; 1418 ctx->f_scred = scred; 1419 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || 1420 (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) { 1421 ctx->f_flags |= SMBFS_RDD_USESEARCH; 1422 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred); 1423 } else 1424 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred); 1425 if (error) 1426 smbfs_findclose(ctx, scred); 1427 else 1428 *ctxpp = ctx; 1429 return error; 1430 } 1431 1432 int 1433 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) 1434 { 1435 int error; 1436 1437 if (limit == 0) 1438 limit = 1000000; 1439 else if (limit > 1) 1440 limit *= 4; /* imperical */ 1441 ctx->f_scred = scred; 1442 for (;;) { 1443 if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1444 error = smbfs_findnextLM1(ctx, limit); 1445 } else 1446 error = smbfs_findnextLM2(ctx, limit); 1447 if (error) 1448 return error; 1449 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || 1450 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && 1451 ctx->f_name[1] == '.')) 1452 continue; 1453 break; 1454 } 1455 smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen, 1456 ctx->f_dnp->n_mount->sm_caseopt); 1457 ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); 1458 return 0; 1459 } 1460 1461 int 1462 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred) 1463 { 1464 ctx->f_scred = scred; 1465 if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1466 smbfs_findcloseLM1(ctx); 1467 } else 1468 smbfs_findcloseLM2(ctx); 1469 if (ctx->f_rname) 1470 free(ctx->f_rname, M_SMBFSDATA); 1471 free(ctx, M_SMBFSDATA); 1472 return 0; 1473 } 1474 1475 int 1476 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, 1477 struct smbfattr *fap, struct smb_cred *scred) 1478 { 1479 struct smbfs_fctx *ctx; 1480 int error; 1481 1482 if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { 1483 bzero(fap, sizeof(*fap)); 1484 fap->fa_attr = SMB_FA_DIR; 1485 fap->fa_ino = 2; 1486 return 0; 1487 } 1488 if (nmlen == 1 && name[0] == '.') { 1489 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 1490 return error; 1491 } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 1492 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 1493 scred); 1494 printf("%s: knows NOTHING about '..'\n", __func__); 1495 return error; 1496 } 1497 error = smbfs_findopen(dnp, name, nmlen, 1498 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); 1499 if (error) 1500 return error; 1501 ctx->f_flags |= SMBFS_RDD_FINDSINGLE; 1502 error = smbfs_findnext(ctx, 1, scred); 1503 if (error == 0) { 1504 *fap = ctx->f_attr; 1505 if (name == NULL) 1506 fap->fa_ino = dnp->n_ino; 1507 } 1508 smbfs_findclose(ctx, scred); 1509 return error; 1510 } 1511