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