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