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