1/* 2 * Copyright (c) 2011 - 2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <sys/smb_apple.h> 25#include <sys/syslog.h> 26 27#include <sys/msfscc.h> 28#include <netsmb/smb.h> 29#include <netsmb/smb_2.h> 30#include <netsmb/smb_rq.h> 31#include <netsmb/smb_rq_2.h> 32#include <netsmb/smb_conn.h> 33#include <netsmb/smb_conn_2.h> 34 35#include <smbfs/smbfs.h> 36#include <smbfs/smbfs_node.h> 37#include <smbfs/smbfs_subr.h> 38#include <smbfs/smbfs_subr_2.h> 39#include <smbfs/smbfs_notify_change.h> 40#include <smbclient/ntstatus.h> 41#include <netsmb/smb_converter.h> 42 43 44static int 45smb2fs_smb_copyfile_mac(struct smb_share *share, struct smbnode *src_np, 46 struct smbnode *tdnp, const char *tnamep, size_t tname_len, 47 vfs_context_t context); 48static int 49smb2fs_smb_delete(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 50 const char *namep, size_t name_len, 51 int xattr, vfs_context_t context); 52 53static uint32_t 54smb2fs_smb_fillchunk_arr(struct smb2_copychunk_chunk *chunk_arr, 55 uint32_t chunk_arr_size, 56 uint64_t total_len, uint32_t max_chunk_len, 57 uint64_t src_offset, uint64_t trg_offset, 58 uint32_t *chunk_count_out, uint64_t *total_len_out); 59 60static uint32_t 61smb2fs_smb_get_create_options(struct smb_share *share, struct smbnode *np, 62 const char *namep, const char *strm_namep, 63 enum vtype vnode_type, uint32_t check_reparse); 64 65static int 66smb2fs_smb_listxattrs(struct smb_share *share, struct smbnode *np, char **xattrlist, 67 size_t *xattrlist_len, vfs_context_t context); 68int 69smb2fs_smb_ntcreatex(struct smb_share *share, struct smbnode *np, 70 const char *namep, size_t in_nmlen, 71 const char *strm_namep, size_t in_strm_nmlen, 72 uint32_t desired_access, enum vtype vnode_type, 73 uint32_t share_access, uint32_t disposition, 74 uint64_t create_flags, uint32_t create_options, 75 SMBFID *fidp, struct smbfattr *fap, 76 struct smb_rq **compound_rqp, struct smb2_create_rq **in_createp, 77 void *create_contextp, vfs_context_t context); 78static int 79smb2fs_smb_parse_ntcreatex(struct smb_share *share, struct smbnode *np, 80 struct smb2_create_rq *createp, 81 SMBFID *fidp, struct smbfattr *fap, 82 vfs_context_t context); 83static int 84smb2fs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 85 const char *namep, size_t name_len, 86 const char *stream_namep, 87 uio_t uio, size_t *sizep, 88 uint64_t *stream_sizep, uint64_t *stream_alloc_sizep, 89 uint32_t *stream_flagsp, uint32_t *max_accessp, 90 vfs_context_t context); 91static int 92smb2fs_smb_request_resume_key(struct smb_share *share, SMBFID fid, u_char *resume_key, 93 vfs_context_t context); 94 95static int 96smb2fs_smb_set_eof(struct smb_share *share, SMBFID fid, uint64_t newsize, 97 vfs_context_t context); 98 99 100/* 101 * Note: The _smbfs_smb_ in the function name indicates that these functions 102 * are called from the smbfs kext and set up the structs necessary to call the 103 * _smb_ functions. Then copy the results back out to smbfs. 104 * 105 * 106 * SMB 1 implementation remains in original files 107 * 108 * Implementations listed in alphabetical order 109 * 1) SMB 2/3 implementation listed first, 110 * 2) SMB 1, SMB 2/3 generic implementation next 111 * 112 */ 113 114/* 115 * Compound Request Chain notes: 116 * 1) A compound req is identified by rqp->sr_next_rqp != NULL 117 * 2) The first rqp in the chain has the response data for ALL the 118 * responses. Its header data has already been parsed out and saved in 119 * the first rqp. Subsequent headers will have to be manually parsed out. 120 * 3) When parsing the response chain, even if an earlier response gets an 121 * error, continuing trying to parse the rest of the replies to get the 122 * credits granted in the response header. 123 * 4) If the first response got an error, only print that error message and 124 * skip printing any more errors for the rest of the responses in the chain. 125 */ 126 127int 128smb2fs_smb_cmpd_check_copyfile(struct smb_share *share, 129 struct smbnode *create_np, 130 vfs_context_t context) 131{ 132 int error, tmp_error; 133 SMBFID fid = 0; 134 struct smb2_create_rq *createp = NULL; 135 struct smb2_ioctl_rq *ioctlp = NULL; 136 struct smb2_close_rq *closep = NULL; 137 struct smb_rq *create_rqp = NULL; 138 struct smb_rq *ioctl_rqp = NULL; 139 struct smb_rq *close_rqp = NULL; 140 struct mdchain *mdp; 141 size_t next_cmd_offset = 0; 142 uint32_t need_delete_fid = 0; 143 uint32_t create_desired_access = SMB2_FILE_READ_DATA | 144 SMB2_FILE_READ_ATTRIBUTES | 145 SMB2_FILE_READ_EA; 146 enum vtype vnode_type = VREG; 147 uint32_t share_access = NTCREATEX_SHARE_ACCESS_READ; 148 uint64_t create_flags = 0; 149 uint32_t create_options = 0; 150 uint32_t disposition = FILE_OPEN; 151 152 /* 153 * For this function, vnode_type is the item's type. The item will be 154 * Opened and the Ioctl done on the item. 155 */ 156 157 SMB_MALLOC(ioctlp, 158 struct smb2_ioctl_rq *, 159 sizeof(struct smb2_ioctl_rq), 160 M_SMBTEMP, 161 M_WAITOK | M_ZERO); 162 if (ioctlp == NULL) { 163 SMBERROR("SMB_MALLOC failed\n"); 164 error = ENOMEM; 165 goto bad; 166 } 167 168 if (create_np) { 169 vnode_type = vnode_isdir(create_np->n_vnode) ? VDIR : VREG; 170 } 171 172resend: 173 /* 174 * Build the Create call 175 */ 176 create_options = smb2fs_smb_get_create_options(share, create_np, 177 NULL, NULL, 178 vnode_type, 0); 179 error = smb2fs_smb_ntcreatex(share, create_np, 180 NULL, 0, 181 NULL, 0, 182 create_desired_access, vnode_type, 183 share_access, disposition, 184 create_flags, create_options, 185 &fid, NULL, 186 &create_rqp, &createp, 187 NULL, context); 188 189 if (error) { 190 SMBDEBUG("smb2fs_smb_ntcreatex failed %d\n", error); 191 goto bad; 192 } 193 194 /* Update Create hdr */ 195 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 196 if (error) { 197 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 198 goto bad; 199 } 200 201 /* 202 * Build the IOCTL request 203 */ 204 ioctlp->share = share; 205 ioctlp->ctl_code = FSCTL_SRV_REQUEST_RESUME_KEY; 206 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 207 ioctlp->fid = fid; 208 209 ioctlp->snd_input_len = 0; 210 ioctlp->snd_output_len = 0; 211 ioctlp->rcv_input_len = 0; 212 ioctlp->rcv_output_len = 0x20; 213 214 error = smb2_smb_ioctl(share, ioctlp, &ioctl_rqp, context); 215 if (error) { 216 SMBERROR("smb2_smb_ioctl failed %d\n", error); 217 goto bad; 218 } 219 220 /* Update IOCTL hdr */ 221 error = smb2_rq_update_cmpd_hdr(ioctl_rqp, SMB2_CMPD_MIDDLE); 222 if (error) { 223 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 224 goto bad; 225 } 226 227 /* Chain IOCTL to the Create */ 228 create_rqp->sr_next_rqp = ioctl_rqp; 229 230 /* 231 * Build the Close request 232 */ 233 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 234 if (error) { 235 SMBERROR("smb2_smb_close_fid failed %d\n", error); 236 goto bad; 237 } 238 239 /* Update Close hdr */ 240 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 241 if (error) { 242 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 243 goto bad; 244 } 245 246 /* Chain Close to the IOCTL */ 247 ioctl_rqp->sr_next_rqp = close_rqp; 248 249 /* 250 * Send the compound request of Create/IOCTL/Close 251 */ 252 error = smb_rq_simple(create_rqp); 253 254 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 255 /* Rebuild and try sending again */ 256 smb_rq_done(create_rqp); 257 create_rqp = NULL; 258 259 smb_rq_done(ioctl_rqp); 260 ioctl_rqp = NULL; 261 262 smb_rq_done(close_rqp); 263 close_rqp = NULL; 264 265 SMB_FREE(createp, M_SMBTEMP); 266 createp = NULL; 267 268 SMB_FREE(closep, M_SMBTEMP); 269 closep = NULL; 270 271 goto resend; 272 } 273 274 createp->ret_ntstatus = create_rqp->sr_ntstatus; 275 276 /* Get pointer to response data */ 277 smb_rq_getreply(create_rqp, &mdp); 278 279 if (error) { 280 /* Create failed, try parsing the IOCTL */ 281 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 282 error, create_rqp->sr_messageid); 283 goto parse_ioctl; 284 } 285 286 /* 287 * Parse the Create response. 288 */ 289 error = smb2_smb_parse_create(share, mdp, createp); 290 if (error) { 291 /* Create parsing failed, try parsing the IOCTL */ 292 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 293 error, create_rqp->sr_messageid); 294 goto parse_ioctl; 295 } 296 297 /* At this point, fid has been entered into fid table */ 298 need_delete_fid = 1; 299 300 /* 301 * No need to call smb2fs_smb_parse_ntcreatex since just need a FID. 302 */ 303 304parse_ioctl: 305 /* Consume any pad bytes */ 306 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 307 if (tmp_error) { 308 /* Failed to find next command, so can't parse rest of the responses */ 309 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 310 tmp_error, create_rqp->sr_messageid); 311 goto bad; 312 } 313 314 /* 315 * Parse IOCTL SMB 2/3 header 316 */ 317 tmp_error = smb2_rq_parse_header(ioctl_rqp, &mdp); 318 ioctlp->ret_ntstatus = ioctl_rqp->sr_ntstatus; 319 if (tmp_error) { 320 /* IOCTL got an error, try parsing the Close */ 321 if (!error) { 322 SMBDEBUG("ioctl smb2_rq_parse_header failed %d, id %lld\n", 323 tmp_error, ioctl_rqp->sr_messageid); 324 error = tmp_error; 325 } 326 goto parse_close; 327 } 328 329 /* Parse the IOCTL response */ 330 tmp_error = smb2_smb_parse_ioctl(mdp, ioctlp); 331 if (tmp_error) { 332 /* IOCTL parsing got an error, try parsing the Close */ 333 if (!error) { 334 SMBERROR("smb2_smb_parse_ioctl failed %d id %lld\n", 335 tmp_error, ioctl_rqp->sr_messageid); 336 error = tmp_error; 337 } 338 goto parse_close; 339 } 340 341 /* 342 * At this point, we know the IOCTL worked. Thats all we need to 343 * know is whether this compound request worked or not. 344 */ 345 346parse_close: 347 /* Update closep fid so it gets freed from FID table */ 348 closep->fid = createp->ret_fid; 349 350 /* Consume any pad bytes */ 351 tmp_error = smb2_rq_next_command(ioctl_rqp, &next_cmd_offset, mdp); 352 if (tmp_error) { 353 /* Failed to find next command, so can't parse rest of the responses */ 354 SMBERROR("ioctl smb2_rq_next_command failed %d\n", tmp_error); 355 error = error ? error : tmp_error; 356 goto bad; 357 } 358 359 /* 360 * Parse Close SMB 2/3 header 361 */ 362 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 363 closep->ret_ntstatus = close_rqp->sr_ntstatus; 364 if (tmp_error) { 365 if (!error) { 366 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 367 tmp_error, close_rqp->sr_messageid); 368 error = tmp_error; 369 } 370 goto bad; 371 } 372 373 /* Parse the Close response */ 374 tmp_error = smb2_smb_parse_close(mdp, closep); 375 if (tmp_error) { 376 if (!error) { 377 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 378 tmp_error, close_rqp->sr_messageid); 379 error = tmp_error; 380 } 381 goto bad; 382 } 383 384 /* At this point, fid has been removed from fid table */ 385 need_delete_fid = 0; 386 387bad: 388 if (need_delete_fid == 1) { 389 /* 390 * Close failed but the Create worked and was successfully parsed. 391 * Try issuing the Close request again. 392 */ 393 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 394 NULL, NULL, context); 395 if (tmp_error) { 396 SMBERROR("Second close failed %d\n", tmp_error); 397 } 398 } 399 400 if (create_rqp != NULL) { 401 smb_rq_done(create_rqp); 402 } 403 if (ioctl_rqp != NULL) { 404 smb_rq_done(ioctl_rqp); 405 } 406 if (close_rqp != NULL) { 407 smb_rq_done(close_rqp); 408 } 409 410 if (createp != NULL) { 411 SMB_FREE(createp, M_SMBTEMP); 412 } 413 if (ioctlp != NULL) { 414 SMB_FREE(ioctlp, M_SMBTEMP); 415 } 416 if (closep != NULL) { 417 SMB_FREE(closep, M_SMBTEMP); 418 } 419 420 return (error); 421} 422 423int 424smb2fs_smb_cmpd_create(struct smb_share *share, struct smbnode *np, 425 const char *namep, size_t name_len, 426 const char *strm_namep, size_t strm_name_len, 427 uint32_t desired_access, enum vtype vnode_type, 428 uint32_t share_access, uint32_t disposition, 429 uint64_t create_flags, uint32_t *ntstatus, 430 SMBFID *fidp, struct smbfattr *fap, 431 void *create_contextp, vfs_context_t context) 432{ 433 int error, tmp_error; 434 struct smb2_create_rq *createp = NULL; 435 struct smb2_query_info_rq *queryp = NULL; 436 struct smb2_close_rq *closep = NULL; 437 struct smb_rq *create_rqp = NULL; 438 struct smb_rq *query_rqp = NULL; 439 struct smb_rq *close_rqp = NULL; 440 struct mdchain *mdp; 441 size_t next_cmd_offset = 0; 442 uint32_t need_delete_fid = 0; 443 SMBFID fid = 0; 444 int add_query = 0; 445 int add_close = 0; 446 uint64_t inode_number = 0; 447 uint32_t inode_number_len; 448 uint32_t create_options = 0; 449 450 /* 451 * For this function, vnode_type is the item's type. The item will be 452 * Opened and the Query Info will be done on the item. 453 */ 454 455 /* 456 * This function can do Create/Close, Create/Query, or Create/Query/Close 457 * If SMB2_CREATE_DO_CREATE is set in create_flags, then the Query is 458 * added to get the file ID. If fidp is NULL, then the Close is added. 459 * 460 * ntstatus is needed for DFS code. smb_usr_check_dir needs to return the 461 * ntstatus up to isReferralPathNotCovered() in user space. 462 */ 463 464 if ((create_flags & SMB2_CREATE_DO_CREATE) && 465 (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) { 466 /* Need the file id, so add a query into the compound request */ 467 add_query = 1; 468 } 469 470 if (fidp == NULL) { 471 /* If fidp is null, add the close into the compound request */ 472 add_close = 1; 473 } 474 475 if ((add_query == 0) && (add_close == 0)) { 476 /* Just doing a simple create */ 477 create_options = smb2fs_smb_get_create_options(share, np, 478 namep, strm_namep, 479 vnode_type, 1); 480 error = smb2fs_smb_ntcreatex(share, np, 481 namep, name_len, 482 strm_namep, strm_name_len, 483 desired_access, vnode_type, 484 share_access, disposition, 485 create_flags, create_options, 486 fidp, fap, 487 NULL, NULL, 488 create_contextp, context); 489 return error; 490 } 491 492 if (add_query) { 493 SMB_MALLOC(queryp, 494 struct smb2_query_info_rq *, 495 sizeof(struct smb2_query_info_rq), 496 M_SMBTEMP, 497 M_WAITOK | M_ZERO); 498 if (queryp == NULL) { 499 SMBERROR("SMB_MALLOC failed\n"); 500 error = ENOMEM; 501 goto bad; 502 } 503 } 504 505resend: 506 /* 507 * Build the Create call 508 */ 509 create_options = smb2fs_smb_get_create_options(share, np, 510 namep, strm_namep, 511 vnode_type, 1); 512 error = smb2fs_smb_ntcreatex(share, np, 513 namep, name_len, 514 strm_namep, strm_name_len, 515 desired_access, vnode_type, 516 share_access, disposition, 517 create_flags, create_options, 518 &fid, fap, 519 &create_rqp, &createp, 520 create_contextp, context); 521 if (error) { 522 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 523 goto bad; 524 } 525 526 /* Update Create hdr */ 527 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 528 if (error) { 529 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 530 goto bad; 531 } 532 533 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 534 535 if (add_query) { 536 /* 537 * Build the Query Info request (to get File ID) 538 */ 539 inode_number_len = (uint32_t) sizeof(inode_number); 540 541 queryp->info_type = SMB2_0_INFO_FILE; 542 queryp->file_info_class = FileInternalInformation; 543 queryp->add_info = 0; 544 queryp->flags = 0; 545 queryp->output_buffer_len = inode_number_len; 546 queryp->output_buffer = (uint8_t *) &inode_number; 547 queryp->input_buffer_len = 0; 548 queryp->input_buffer = NULL; 549 queryp->ret_buffer_len = 0; 550 queryp->fid = fid; 551 552 error = smb2_smb_query_info(share, queryp, &query_rqp, context); 553 if (error) { 554 SMBERROR("smb2_smb_query_info failed %d\n", error); 555 goto bad; 556 } 557 558 /* Update Query hdr */ 559 if (add_close) { 560 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE); 561 } 562 else { 563 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_LAST); 564 } 565 if (error) { 566 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 567 goto bad; 568 } 569 570 /* Chain Query Info to the Create */ 571 create_rqp->sr_next_rqp = query_rqp; 572 } 573 574 if (add_close) { 575 /* 576 * Build the Close request 577 */ 578 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 579 if (error) { 580 SMBERROR("smb2_smb_close_fid failed %d\n", error); 581 goto bad; 582 } 583 584 /* Update Close hdr */ 585 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 586 if (error) { 587 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 588 goto bad; 589 } 590 591 if (add_query) { 592 /* Chain Close to the Query */ 593 query_rqp->sr_next_rqp = close_rqp; 594 } 595 else { 596 /* Chain Close to the Create */ 597 create_rqp->sr_next_rqp = close_rqp; 598 } 599 } 600 601 /* 602 * Send the compound request of Create/Query/Close 603 */ 604 error = smb_rq_simple(create_rqp); 605 606 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 607 /* Rebuild and try sending again */ 608 smb_rq_done(create_rqp); 609 create_rqp = NULL; 610 611 if (query_rqp != NULL) { 612 smb_rq_done(query_rqp); 613 query_rqp = NULL; 614 } 615 616 if (close_rqp != NULL) { 617 smb_rq_done(close_rqp); 618 close_rqp = NULL; 619 } 620 621 SMB_FREE(createp, M_SMBTEMP); 622 createp = NULL; 623 624 if (closep != NULL) { 625 SMB_FREE(closep, M_SMBTEMP); 626 closep = NULL; 627 } 628 629 goto resend; 630 } 631 632 createp->ret_ntstatus = create_rqp->sr_ntstatus; 633 if (ntstatus) { 634 /* Return NT Status error if they want it */ 635 *ntstatus = createp->ret_ntstatus; 636 } 637 638 /* Get pointer to response data */ 639 smb_rq_getreply(create_rqp, &mdp); 640 641 if (error) { 642 /* Create failed, try parsing the Query */ 643 if (error != ENOENT) { 644 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 645 error, create_rqp->sr_messageid); 646 } 647 goto parse_query; 648 } 649 650 /* 651 * Parse the Create response. 652 */ 653 error = smb2_smb_parse_create(share, mdp, createp); 654 if (error) { 655 /* Create parsing failed, try parsing the Query */ 656 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 657 error, create_rqp->sr_messageid); 658 goto parse_query; 659 } 660 661 /* At this point, fid has been entered into fid table */ 662 need_delete_fid = 1; 663 664 /* 665 * Fill in fap and possibly update vnode's meta data caches 666 */ 667 error = smb2fs_smb_parse_ntcreatex(share, np, createp, 668 fidp, fap, context); 669 if (error) { 670 /* Updating meta data cache failed, try parsing the Close */ 671 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 672 error, create_rqp->sr_messageid); 673 } 674 675parse_query: 676 if (query_rqp != NULL) { 677 /* Consume any pad bytes */ 678 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 679 if (tmp_error) { 680 /* Failed to find next command, so can't parse rest of the responses */ 681 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 682 tmp_error, create_rqp->sr_messageid); 683 error = error ? error : tmp_error; 684 goto bad; 685 } 686 687 /* 688 * Parse Query Info SMB 2/3 header 689 */ 690 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 691 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 692 if (tmp_error) { 693 /* Query Info got an error, try parsing the Close */ 694 if (!error) { 695 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 696 tmp_error, query_rqp->sr_messageid); 697 error = tmp_error; 698 } 699 goto parse_close; 700 } 701 702 /* Parse the Query Info response */ 703 tmp_error = smb2_smb_parse_query_info(mdp, queryp); 704 if (tmp_error) { 705 /* Query Info parsing got an error, try parsing the Close */ 706 if (!error) { 707 if (tmp_error != ENOATTR) { 708 SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n", 709 tmp_error, query_rqp->sr_messageid); 710 } 711 error = tmp_error; 712 } 713 goto parse_close; 714 } 715 else { 716 /* Query worked, so get the inode number */ 717 if (fap) { 718 fap->fa_ino = inode_number; 719 smb2fs_smb_file_id_check(share, fap->fa_ino, NULL, 0); 720 } 721 } 722 } 723 724parse_close: 725 if (close_rqp != NULL) { 726 /* Update closep fid so it gets freed from FID table */ 727 closep->fid = createp->ret_fid; 728 729 /* Consume any pad bytes */ 730 tmp_error = smb2_rq_next_command(query_rqp != NULL ? query_rqp : create_rqp, 731 &next_cmd_offset, mdp); 732 if (tmp_error) { 733 /* Failed to find next command, so can't parse rest of the responses */ 734 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 735 tmp_error, create_rqp->sr_messageid); 736 error = error ? error : tmp_error; 737 goto bad; 738 } 739 740 /* 741 * Parse Close SMB 2/3 header 742 */ 743 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 744 closep->ret_ntstatus = close_rqp->sr_ntstatus; 745 if (tmp_error) { 746 if (!error) { 747 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 748 tmp_error, close_rqp->sr_messageid); 749 error = tmp_error; 750 751 if (ntstatus) { 752 /* Return NT Status error if they want it */ 753 *ntstatus = closep->ret_ntstatus; 754 } 755 } 756 goto bad; 757 } 758 759 /* Parse the Close response */ 760 tmp_error = smb2_smb_parse_close(mdp, closep); 761 if (tmp_error) { 762 if (!error) { 763 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 764 tmp_error, close_rqp->sr_messageid); 765 error = tmp_error; 766 } 767 goto bad; 768 } 769 770 /* At this point, fid has been removed from fid table */ 771 need_delete_fid = 0; 772 } 773 else { 774 /* Not doing a close, so leave it open */ 775 need_delete_fid = 0; 776 } 777 778bad: 779 if (need_delete_fid == 1) { 780 /* 781 * Close failed but the Create worked and was successfully parsed. 782 * Try issuing the Close request again. 783 */ 784 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 785 NULL, NULL, context); 786 if (tmp_error) { 787 SMBERROR("Second close failed %d\n", tmp_error); 788 } 789 } 790 791 if (create_rqp != NULL) { 792 smb_rq_done(create_rqp); 793 } 794 if (query_rqp != NULL) { 795 smb_rq_done(query_rqp); 796 } 797 if (close_rqp != NULL) { 798 smb_rq_done(close_rqp); 799 } 800 801 if (createp != NULL) { 802 SMB_FREE(createp, M_SMBTEMP); 803 } 804 if (queryp != NULL) { 805 SMB_FREE(queryp, M_SMBTEMP); 806 } 807 if (closep != NULL) { 808 SMB_FREE(closep, M_SMBTEMP); 809 } 810 811 return error; 812} 813 814static int 815smb2fs_smb_cmpd_create_read(struct smb_share *share, struct smbnode *dnp, 816 const char *namep, size_t name_len, 817 const char *snamep, size_t sname_len, 818 uint32_t desired_access, uio_t uio, 819 size_t *sizep, uint32_t *max_accessp, 820 SMBFID *fidp, struct timespec *mtime, 821 vfs_context_t context) 822{ 823 int error, tmp_error; 824 uint32_t disposition; 825 uint32_t share_access; 826 SMBFID fid = 0; 827 struct smbfattr *fap = NULL; 828 struct smb2_create_rq *createp = NULL; 829 struct smb2_rw_rq *readp = NULL; 830 struct smb2_close_rq *closep = NULL; 831 struct smb_rq *create_rqp = NULL; 832 struct smb_rq *read_rqp = NULL; 833 struct smb_rq *close_rqp = NULL; 834 struct mdchain *mdp; 835 size_t next_cmd_offset = 0; 836 user_ssize_t len, resid = 0; 837 user_ssize_t rresid = 0; 838 uint64_t create_flags = SMB2_CREATE_GET_MAX_ACCESS; 839 uint32_t need_delete_fid = 0; 840 int add_close = 0; 841 uint32_t create_options = 0; 842 enum vtype vnode_type = VREG; 843 844 /* 845 * We can only read files, so vnode_type is always VREG 846 * Named streams are always files. 847 */ 848 849 /* 850 * This function can do Create/Read or Create/Read/Close 851 * If fidp is NULL, then the Close is added. 852 */ 853 854 /* 855 * (1) This is used when dealing with readdirattr for Finder Info 856 * It has a parent dnp, child of namep and stream name of snamep. 857 * (2) This is used for dealing with Finder Info which is an xattr 858 * (ie stream) and assumes the read data will all fit in one read request 859 */ 860 861 if (fidp == NULL) { 862 /* If fidp is null, add the close into the compound request */ 863 add_close = 1; 864 } 865 else { 866 *fidp = 0; /* indicates create failed */ 867 } 868 869 SMB_MALLOC(fap, 870 struct smbfattr *, 871 sizeof(struct smbfattr), 872 M_SMBTEMP, 873 M_WAITOK | M_ZERO); 874 if (fap == NULL) { 875 SMBERROR("SMB_MALLOC failed\n"); 876 error = ENOMEM; 877 goto bad; 878 } 879 880 SMB_MALLOC(readp, 881 struct smb2_rw_rq *, 882 sizeof(struct smb2_rw_rq), 883 M_SMBTEMP, 884 M_WAITOK | M_ZERO); 885 if (readp == NULL) { 886 SMBERROR("SMB_MALLOC failed\n"); 887 error = ENOMEM; 888 goto bad; 889 } 890 891 /* 892 * Be careful here. The vnode_type is for the actual item that the 893 * Read is being done on. The path to the item is built from 894 * create_np and namep, but only the calling function knows what the 895 * item type is. 896 */ 897 898 /* 899 * Set up for the Create call 900 */ 901 if (snamep) { 902 create_flags |= SMB2_CREATE_IS_NAMED_STREAM; 903 /* Named streams are always files */ 904 vnode_type = VREG; 905 } 906 907 if (desired_access & SMB2_FILE_WRITE_DATA) { 908 share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE; 909 disposition = FILE_OPEN_IF; 910 } 911 else { 912 share_access = NTCREATEX_SHARE_ACCESS_ALL; 913 disposition = FILE_OPEN; 914 } 915 916resend: 917 /* 918 * Build the Create call 919 */ 920 create_options = smb2fs_smb_get_create_options(share, dnp, 921 namep, snamep, 922 vnode_type, 0); 923 error = smb2fs_smb_ntcreatex(share, dnp, 924 namep, name_len, 925 snamep, sname_len, 926 desired_access, vnode_type, 927 share_access, disposition, 928 create_flags, create_options, 929 &fid, fap, 930 &create_rqp, &createp, 931 NULL, context); 932 if (error) { 933 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 934 goto bad; 935 } 936 937 /* Update Create hdr */ 938 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 939 if (error) { 940 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 941 goto bad; 942 } 943 944 /* 945 * Build the Read request 946 */ 947 readp->flags = 0; 948 readp->remaining = 0; 949 readp->write_flags = 0; 950 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 951 readp->fid = fid; 952 readp->auio = uio; 953 954 /* assume we can read it all in one request */ 955 len = uio_resid(readp->auio); 956 957 error = smb2_smb_read_one(share, readp, &len, &resid, &read_rqp, context); 958 if (error) { 959 SMBERROR("smb2_smb_read_one failed %d\n", error); 960 goto bad; 961 } 962 963 /* Update Read hdr */ 964 if (add_close) { 965 error = smb2_rq_update_cmpd_hdr(read_rqp, SMB2_CMPD_MIDDLE); 966 } 967 else { 968 error = smb2_rq_update_cmpd_hdr(read_rqp, SMB2_CMPD_LAST); 969 } 970 if (error) { 971 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 972 goto bad; 973 } 974 975 /* Chain Read to the Create */ 976 create_rqp->sr_next_rqp = read_rqp; 977 978 if (add_close) { 979 /* 980 * Build the Close request 981 */ 982 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 983 if (error) { 984 SMBERROR("smb2_smb_close_fid failed %d\n", error); 985 goto bad; 986 } 987 988 /* Update Close hdr */ 989 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 990 if (error) { 991 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 992 goto bad; 993 } 994 995 /* Chain Close to the Read */ 996 read_rqp->sr_next_rqp = close_rqp; 997 } 998 999 /* 1000 * Send the compound request of Create/Read/Close 1001 */ 1002 error = smb_rq_simple(create_rqp); 1003 1004 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 1005 /* Rebuild and try sending again */ 1006 smb_rq_done(create_rqp); 1007 create_rqp = NULL; 1008 1009 smb_rq_done(read_rqp); 1010 read_rqp = NULL; 1011 1012 if (close_rqp != NULL) { 1013 smb_rq_done(close_rqp); 1014 close_rqp = NULL; 1015 } 1016 1017 SMB_FREE(createp, M_SMBTEMP); 1018 createp = NULL; 1019 1020 if (closep != NULL) { 1021 SMB_FREE(closep, M_SMBTEMP); 1022 closep = NULL; 1023 } 1024 1025 goto resend; 1026 } 1027 1028 createp->ret_ntstatus = create_rqp->sr_ntstatus; 1029 1030 /* Get pointer to response data */ 1031 smb_rq_getreply(create_rqp, &mdp); 1032 1033 if (error) { 1034 /* Create failed, try parsing the Read */ 1035 if (error != ENOENT) { 1036 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 1037 error, create_rqp->sr_messageid); 1038 } 1039 1040 if (fidp) { 1041 *fidp = 0; /* indicate Create failed */ 1042 } 1043 goto parse_read; 1044 } 1045 1046 /* 1047 * Parse the Create response. 1048 */ 1049 error = smb2_smb_parse_create(share, mdp, createp); 1050 if (error) { 1051 /* Create parsing failed, try parsing the Read */ 1052 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 1053 error, create_rqp->sr_messageid); 1054 1055 if (fidp) { 1056 *fidp = 0; /* indicate Create failed */ 1057 } 1058 goto parse_read; 1059 } 1060 1061 /* At this point, fid has been entered into fid table */ 1062 need_delete_fid = 1; 1063 1064 /* 1065 * Fill in fap and possibly update vnode's meta data caches 1066 */ 1067 error = smb2fs_smb_parse_ntcreatex(share, dnp, createp, 1068 fidp, fap, context); 1069 if (error) { 1070 /* Updating meta data cache failed, try parsing the Read */ 1071 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 1072 error, create_rqp->sr_messageid); 1073 } 1074 else { 1075 /* Return max access if they want it */ 1076 if (max_accessp) { 1077 DBG_ASSERT(fap->fa_valid_mask & FA_MAX_ACCESS_VALID) 1078 *max_accessp = fap->fa_max_access; 1079 } 1080 if (mtime) { 1081 *mtime = fap->fa_mtime; 1082 } 1083 } 1084 1085parse_read: 1086 /* Consume any pad bytes */ 1087 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 1088 if (tmp_error) { 1089 /* Failed to find next command, so can't parse rest of the responses */ 1090 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 1091 tmp_error, create_rqp->sr_messageid); 1092 error = error ? error : tmp_error; 1093 goto bad; 1094 } 1095 1096 /* 1097 * Parse Read SMB 2/3 header 1098 */ 1099 tmp_error = smb2_rq_parse_header(read_rqp, &mdp); 1100 readp->ret_ntstatus = read_rqp->sr_ntstatus; 1101 1102 if (tmp_error == ENODATA) { 1103 /* 1104 * Ignore EOF and leave error alone as it could contain an error from 1105 * the create, but skip trying to parse the read data 1106 */ 1107 goto parse_close; 1108 } 1109 1110 if (tmp_error) { 1111 /* Read got an error, try parsing the Close */ 1112 if (!error) { 1113 SMBDEBUG("read smb2_rq_parse_header failed %d, id %lld\n", 1114 tmp_error, read_rqp->sr_messageid); 1115 error = tmp_error; 1116 } 1117 goto parse_close; 1118 } 1119 1120 /* Parse the Read response */ 1121 tmp_error = smb2_smb_parse_read_one(mdp, &rresid, readp); 1122 if (tmp_error) { 1123 /* Read parsing got an error, try parsing the Close */ 1124 if (!error) { 1125 SMBERROR("smb2_smb_parse_read_one failed %d id %lld\n", 1126 tmp_error, read_rqp->sr_messageid); 1127 error = tmp_error; 1128 } 1129 goto parse_close; 1130 } 1131 1132 if (sizep) { 1133 /* 1134 * *sizep contains the logical size of the stream 1135 * The calling routines can only handle size_t 1136 */ 1137 *sizep = fap->fa_size; 1138 } 1139 1140parse_close: 1141 if (close_rqp != NULL) { 1142 /* Update closep fid so it gets freed from FID table */ 1143 closep->fid = createp->ret_fid; 1144 1145 /* Consume any pad bytes */ 1146 tmp_error = smb2_rq_next_command(read_rqp, &next_cmd_offset, mdp); 1147 if (tmp_error) { 1148 /* Failed to find next command, so can't parse rest of the responses */ 1149 SMBERROR("read smb2_rq_next_command failed %d id %lld\n", 1150 tmp_error, read_rqp->sr_messageid); 1151 error = error ? error : tmp_error; 1152 goto bad; 1153 } 1154 1155 /* 1156 * Parse Close SMB 2/3 header 1157 */ 1158 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 1159 closep->ret_ntstatus = close_rqp->sr_ntstatus; 1160 if (tmp_error) { 1161 if (!error) { 1162 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 1163 tmp_error, close_rqp->sr_messageid); 1164 error = tmp_error; 1165 } 1166 goto bad; 1167 } 1168 1169 /* Parse the Close response */ 1170 tmp_error = smb2_smb_parse_close(mdp, closep); 1171 if (tmp_error) { 1172 if (!error) { 1173 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 1174 tmp_error, close_rqp->sr_messageid); 1175 error = tmp_error; 1176 } 1177 goto bad; 1178 } 1179 1180 /* At this point, fid has been removed from fid table */ 1181 need_delete_fid = 0; 1182 } 1183 else { 1184 /* Not doing a close, so leave it open */ 1185 need_delete_fid = 0; 1186 } 1187 1188bad: 1189 if (need_delete_fid == 1) { 1190 /* 1191 * Close failed but the Create worked and was successfully parsed. 1192 * Try issuing the Close request again. 1193 */ 1194 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 1195 NULL, NULL, context); 1196 if (tmp_error) { 1197 SMBERROR("Second close failed %d\n", tmp_error); 1198 } 1199 } 1200 1201 if (create_rqp != NULL) { 1202 smb_rq_done(create_rqp); 1203 } 1204 if (read_rqp != NULL) { 1205 smb_rq_done(read_rqp); 1206 } 1207 if (close_rqp != NULL) { 1208 smb_rq_done(close_rqp); 1209 } 1210 1211 if (createp != NULL) { 1212 SMB_FREE(createp, M_SMBTEMP); 1213 } 1214 if (readp != NULL) { 1215 SMB_FREE(readp, M_SMBTEMP); 1216 } 1217 if (closep != NULL) { 1218 SMB_FREE(closep, M_SMBTEMP); 1219 } 1220 1221 if (fap != NULL) { 1222 SMB_FREE(fap, M_SMBTEMP); 1223 } 1224 1225 return error; 1226} 1227 1228int smbfs_smb_cmpd_create_read_close(struct smb_share *share, struct smbnode *dnp, 1229 const char *namep, size_t name_len, 1230 const char *snamep, size_t sname_len, 1231 uio_t uio, size_t *sizep, 1232 uint32_t *max_accessp, 1233 vfs_context_t context) 1234{ 1235 int error; 1236 SMBFID fid = 0; 1237 1238 /* 1239 * This is only used when dealing with readdirattr for Finder Info 1240 */ 1241 1242 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 1243 /* Do a Create/Read/Close */ 1244 error = smb2fs_smb_cmpd_create_read(share, dnp, 1245 namep, name_len, 1246 snamep, sname_len, 1247 SMB2_FILE_READ_DATA, uio, 1248 sizep, max_accessp, 1249 NULL, NULL, 1250 context); 1251 } 1252 else { 1253 error = smb1fs_smb_open_read(share, dnp, 1254 namep, name_len, 1255 snamep, sname_len, 1256 &fid, uio, sizep, 1257 max_accessp, 1258 context); 1259 if (fid) { 1260 (void)smbfs_smb_close(share, fid, context); 1261 } 1262 } 1263 1264 return error; 1265} 1266 1267int 1268smb2fs_smb_cmpd_create_write(struct smb_share *share, struct smbnode *dnp, 1269 const char *namep, size_t name_len, 1270 const char *snamep, size_t sname_len, 1271 uint32_t desired_access, struct smbfattr *fap, 1272 uint64_t create_flags, uio_t uio, 1273 SMBFID *fidp, int ioflag, 1274 vfs_context_t context) 1275{ 1276#pragma unused(ioflag) 1277 int error, tmp_error; 1278 uint32_t disposition; 1279 uint32_t share_access; 1280 SMBFID fid = 0; 1281 struct smb2_create_rq *createp = NULL; 1282 struct smb2_query_info_rq *queryp = NULL; 1283 struct smb2_rw_rq *writep = NULL; 1284 struct smb2_close_rq *closep = NULL; 1285 struct smb_rq *create_rqp = NULL; 1286 struct smb_rq *query_rqp = NULL; 1287 struct smb_rq *write_rqp = NULL; 1288 struct smb_rq *close_rqp = NULL; 1289 struct mdchain *mdp; 1290 size_t next_cmd_offset = 0; 1291 user_ssize_t len, resid = 0; 1292 user_ssize_t rresid = 0; 1293 uint32_t need_delete_fid = 0; 1294 int add_query = 0; 1295 int add_close = 0; 1296 uint32_t create_options = 0; 1297 uint32_t write_mode = 0; /* Never supports write through */ 1298 uint64_t inode_number = 0; 1299 uint32_t inode_number_len; 1300 1301 /* 1302 * This function can do Create/Write, Create/Query/Write, 1303 * Create/Write/Close or Create/Query/Write/Close. 1304 * 1305 * If SMB2_CREATE_DO_CREATE is set in create_flags, then the Query is 1306 * added to get the file ID 1307 * 1308 * If fidp is NULL, then the Close is added. 1309 */ 1310 1311 if ((create_flags & SMB2_CREATE_DO_CREATE) && 1312 (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) { 1313 /* Need the file id, so add a query into the compound request */ 1314 add_query = 1; 1315 } 1316 1317 if (fidp == NULL) { 1318 /* If fidp is null, add the close into the compound request */ 1319 add_close = 1; 1320 } 1321 else { 1322 *fidp = 0; /* indicates create failed */ 1323 } 1324 1325 if (add_query) { 1326 SMB_MALLOC(queryp, 1327 struct smb2_query_info_rq *, 1328 sizeof(struct smb2_query_info_rq), 1329 M_SMBTEMP, 1330 M_WAITOK | M_ZERO); 1331 if (queryp == NULL) { 1332 SMBERROR("SMB_MALLOC failed\n"); 1333 error = ENOMEM; 1334 goto bad; 1335 } 1336 } 1337 1338 SMB_MALLOC(writep, 1339 struct smb2_rw_rq *, 1340 sizeof(struct smb2_rw_rq), 1341 M_SMBTEMP, 1342 M_WAITOK | M_ZERO); 1343 if (writep == NULL) { 1344 SMBERROR("SMB_MALLOC failed\n"); 1345 error = ENOMEM; 1346 goto bad; 1347 } 1348 1349 /* 1350 * Set up for the Create call 1351 */ 1352 if (snamep) { 1353 create_flags |= SMB2_CREATE_IS_NAMED_STREAM; 1354 } 1355 1356 if (desired_access & SMB2_FILE_WRITE_DATA) { 1357 share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE; 1358 disposition = FILE_OPEN_IF; 1359 } 1360 else { 1361 share_access = NTCREATEX_SHARE_ACCESS_ALL; 1362 disposition = FILE_OPEN; 1363 } 1364 1365resend: 1366 /* 1367 * Build the Create call 1368 */ 1369 1370 create_options = smb2fs_smb_get_create_options(share, dnp, 1371 namep, snamep, 1372 VREG, 0); 1373 error = smb2fs_smb_ntcreatex(share, dnp, 1374 namep, name_len, 1375 snamep, sname_len, 1376 desired_access, VREG, 1377 share_access, disposition, 1378 create_flags, create_options, 1379 &fid, fap, 1380 &create_rqp, &createp, 1381 NULL, context); 1382 if (error) { 1383 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 1384 goto bad; 1385 } 1386 1387 /* Update Create hdr */ 1388 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 1389 if (error) { 1390 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1391 goto bad; 1392 } 1393 1394 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 1395 1396 if (add_query) { 1397 /* 1398 * Build the Query Info request (to get File ID) 1399 */ 1400 inode_number_len = (uint32_t) sizeof(inode_number); 1401 1402 queryp->info_type = SMB2_0_INFO_FILE; 1403 queryp->file_info_class = FileInternalInformation; 1404 queryp->add_info = 0; 1405 queryp->flags = 0; 1406 queryp->output_buffer_len = inode_number_len; 1407 queryp->output_buffer = (uint8_t *) &inode_number; 1408 queryp->input_buffer_len = 0; 1409 queryp->input_buffer = NULL; 1410 queryp->ret_buffer_len = 0; 1411 queryp->fid = fid; 1412 1413 error = smb2_smb_query_info(share, queryp, &query_rqp, context); 1414 if (error) { 1415 SMBERROR("smb2_smb_query_info failed %d\n", error); 1416 goto bad; 1417 } 1418 1419 /* Update Query hdr */ 1420 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE); 1421 if (error) { 1422 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1423 goto bad; 1424 } 1425 1426 /* Chain Query Info to the Create */ 1427 create_rqp->sr_next_rqp = query_rqp; 1428 } 1429 1430 /* 1431 * Build the Write request 1432 */ 1433 writep->flags = 0; 1434 writep->remaining = 0; 1435 writep->write_flags = write_mode; 1436 writep->fid = fid; 1437 writep->auio = uio; 1438 1439 /* assume we can write it all in one request */ 1440 len = uio_resid(writep->auio); 1441 1442 error = smb2_smb_write_one(share, writep, &len, &resid, &write_rqp, context); 1443 if (error) { 1444 SMBERROR("smb2_smb_write_one failed %d\n", error); 1445 goto bad; 1446 } 1447 1448 /* Manually compound align the write here */ 1449 smb2_rq_align8(write_rqp); 1450 1451 /* Update Write hdr */ 1452 if (add_close) { 1453 error = smb2_rq_update_cmpd_hdr(write_rqp, SMB2_CMPD_MIDDLE); 1454 } 1455 else { 1456 error = smb2_rq_update_cmpd_hdr(write_rqp, SMB2_CMPD_LAST); 1457 } 1458 if (error) { 1459 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1460 goto bad; 1461 } 1462 1463 if (add_query) { 1464 /* Chain Write to the Query */ 1465 query_rqp->sr_next_rqp = write_rqp; 1466 } 1467 else { 1468 /* Chain Write to the Create */ 1469 create_rqp->sr_next_rqp = write_rqp; 1470 } 1471 1472 if (add_close) { 1473 /* 1474 * Build the Close request 1475 */ 1476 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 1477 if (error) { 1478 SMBERROR("smb2_smb_close_fid failed %d\n", error); 1479 goto bad; 1480 } 1481 1482 /* Update Close hdr */ 1483 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 1484 if (error) { 1485 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1486 goto bad; 1487 } 1488 1489 /* Chain Close to the Write */ 1490 write_rqp->sr_next_rqp = close_rqp; 1491 } 1492 1493 /* 1494 * Send the compound request of Create/Query/Write/Close 1495 */ 1496 error = smb_rq_simple(create_rqp); 1497 1498 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 1499 /* Rebuild and try sending again */ 1500 smb_rq_done(create_rqp); 1501 create_rqp = NULL; 1502 1503 if (query_rqp != NULL) { 1504 smb_rq_done(query_rqp); 1505 query_rqp = NULL; 1506 } 1507 1508 smb_rq_done(write_rqp); 1509 write_rqp = NULL; 1510 1511 if (close_rqp != NULL) { 1512 smb_rq_done(close_rqp); 1513 close_rqp = NULL; 1514 } 1515 1516 SMB_FREE(createp, M_SMBTEMP); 1517 createp = NULL; 1518 1519 if (closep != NULL) { 1520 SMB_FREE(closep, M_SMBTEMP); 1521 closep = NULL; 1522 } 1523 1524 goto resend; 1525 } 1526 1527 createp->ret_ntstatus = create_rqp->sr_ntstatus; 1528 1529 /* Get pointer to response data */ 1530 smb_rq_getreply(create_rqp, &mdp); 1531 1532 if (error) { 1533 /* Create failed, try parsing the Query */ 1534 if (error != ENOENT) { 1535 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 1536 error, create_rqp->sr_messageid); 1537 } 1538 1539 if (fidp) { 1540 *fidp = 0; /* indicate Create failed */ 1541 } 1542 goto parse_query; 1543 } 1544 1545 /* 1546 * Parse the Create response. 1547 */ 1548 error = smb2_smb_parse_create(share, mdp, createp); 1549 if (error) { 1550 /* Create parsing failed, try parsing the Query */ 1551 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 1552 error, create_rqp->sr_messageid); 1553 1554 if (fidp) { 1555 *fidp = 0; /* indicate Create failed */ 1556 } 1557 goto parse_query; 1558 } 1559 1560 /* At this point, fid has been entered into fid table */ 1561 need_delete_fid = 1; 1562 1563 /* 1564 * Fill in fap and possibly update vnode's meta data caches 1565 */ 1566 error = smb2fs_smb_parse_ntcreatex(share, dnp, createp, 1567 fidp, fap, context); 1568 if (error) { 1569 /* Updating meta data cache failed, try parsing the Query */ 1570 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 1571 error, create_rqp->sr_messageid); 1572 } 1573 1574parse_query: 1575 if (query_rqp != NULL) { 1576 /* Consume any pad bytes */ 1577 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 1578 if (tmp_error) { 1579 /* Failed to find next command, so can't parse rest of the responses */ 1580 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 1581 tmp_error, create_rqp->sr_messageid); 1582 error = error ? error : tmp_error; 1583 goto bad; 1584 } 1585 1586 /* 1587 * Parse Query Info SMB 2/3 header 1588 */ 1589 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 1590 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 1591 if (tmp_error) { 1592 /* Query Info got an error, try parsing the Close */ 1593 if (!error) { 1594 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 1595 tmp_error, query_rqp->sr_messageid); 1596 error = tmp_error; 1597 } 1598 goto parse_write; 1599 } 1600 1601 /* Parse the Query Info response */ 1602 tmp_error = smb2_smb_parse_query_info(mdp, queryp); 1603 if (tmp_error) { 1604 /* Query Info parsing got an error, try parsing the Close */ 1605 if (!error) { 1606 if (tmp_error != ENOATTR) { 1607 SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n", 1608 tmp_error, query_rqp->sr_messageid); 1609 } 1610 error = tmp_error; 1611 } 1612 goto parse_write; 1613 } 1614 else { 1615 /* Query worked, so get the inode number */ 1616 if (fap) { 1617 fap->fa_ino = inode_number; 1618 smb2fs_smb_file_id_check(share, fap->fa_ino, NULL, 0); 1619 } 1620 } 1621 } 1622 1623parse_write: 1624 /* Consume any pad bytes */ 1625 tmp_error = smb2_rq_next_command(query_rqp != NULL ? query_rqp : create_rqp, 1626 &next_cmd_offset, mdp); 1627 if (tmp_error) { 1628 /* Failed to find next command, so can't parse rest of the responses */ 1629 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 1630 tmp_error, create_rqp->sr_messageid); 1631 error = error ? error : tmp_error; 1632 goto bad; 1633 } 1634 1635 /* 1636 * Parse Write SMB 2/3 header 1637 */ 1638 tmp_error = smb2_rq_parse_header(write_rqp, &mdp); 1639 writep->ret_ntstatus = write_rqp->sr_ntstatus; 1640 1641 if (tmp_error) { 1642 /* Write got an error, try parsing the Close */ 1643 if (!error) { 1644 SMBDEBUG("write smb2_rq_parse_header failed %d, id %lld\n", 1645 tmp_error, write_rqp->sr_messageid); 1646 error = tmp_error; 1647 } 1648 goto parse_close; 1649 } 1650 1651 /* Parse the Write response */ 1652 tmp_error = smb2_smb_parse_write_one(mdp, &rresid, writep); 1653 if (tmp_error) { 1654 /* Write parsing got an error, try parsing the Close */ 1655 if (!error) { 1656 SMBERROR("smb2_smb_parse_write_one failed %d id %lld\n", 1657 tmp_error, write_rqp->sr_messageid); 1658 error = tmp_error; 1659 } 1660 goto parse_close; 1661 } 1662 1663parse_close: 1664 if (close_rqp != NULL) { 1665 /* Update closep fid so it gets freed from FID table */ 1666 closep->fid = createp->ret_fid; 1667 1668 /* Consume any pad bytes */ 1669 tmp_error = smb2_rq_next_command(write_rqp, &next_cmd_offset, mdp); 1670 if (tmp_error) { 1671 /* Failed to find next command, so can't parse rest of the responses */ 1672 SMBERROR("write smb2_rq_next_command failed %d id %lld\n", 1673 tmp_error, write_rqp->sr_messageid); 1674 error = error ? error : tmp_error; 1675 goto bad; 1676 } 1677 1678 /* 1679 * Parse Close SMB 2/3 header 1680 */ 1681 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 1682 closep->ret_ntstatus = close_rqp->sr_ntstatus; 1683 if (tmp_error) { 1684 if (!error) { 1685 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 1686 tmp_error, close_rqp->sr_messageid); 1687 error = tmp_error; 1688 } 1689 goto bad; 1690 } 1691 1692 /* Parse the Close response */ 1693 tmp_error = smb2_smb_parse_close(mdp, closep); 1694 if (tmp_error) { 1695 if (!error) { 1696 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 1697 tmp_error, close_rqp->sr_messageid); 1698 error = tmp_error; 1699 } 1700 goto bad; 1701 } 1702 1703 /* At this point, fid has been removed from fid table */ 1704 need_delete_fid = 0; 1705 } 1706 else { 1707 /* Not doing a close, so leave it open */ 1708 need_delete_fid = 0; 1709 } 1710 1711bad: 1712 if (need_delete_fid == 1) { 1713 /* 1714 * Close failed but the Create worked and was successfully parsed. 1715 * Try issuing the Close request again. 1716 */ 1717 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 1718 NULL, NULL, context); 1719 if (tmp_error) { 1720 SMBERROR("Second close failed %d\n", tmp_error); 1721 } 1722 } 1723 1724 if (create_rqp != NULL) { 1725 smb_rq_done(create_rqp); 1726 } 1727 if (query_rqp != NULL) { 1728 smb_rq_done(query_rqp); 1729 } 1730 if (write_rqp != NULL) { 1731 smb_rq_done(write_rqp); 1732 } 1733 if (close_rqp != NULL) { 1734 smb_rq_done(close_rqp); 1735 } 1736 1737 if (createp != NULL) { 1738 SMB_FREE(createp, M_SMBTEMP); 1739 } 1740 if (queryp != NULL) { 1741 SMB_FREE(queryp, M_SMBTEMP); 1742 } 1743 if (writep != NULL) { 1744 SMB_FREE(writep, M_SMBTEMP); 1745 } 1746 if (closep != NULL) { 1747 SMB_FREE(closep, M_SMBTEMP); 1748 } 1749 1750 return error; 1751} 1752 1753static int 1754smb2fs_smb_cmpd_query(struct smb_share *share, struct smbnode *create_np, enum vtype vnode_type, 1755 const char *create_namep, size_t create_name_len, 1756 uint32_t create_xattr, uint32_t create_desired_access, 1757 uint8_t query_info_type, uint8_t query_file_info_class, 1758 uint32_t query_add_info, uint32_t *max_accessp, 1759 uint32_t *query_output_buffer_len, uint8_t *query_output_buffer, 1760 vfs_context_t context) 1761{ 1762 int error, tmp_error; 1763 SMBFID fid = 0; 1764 struct smbfattr *fap = NULL; 1765 struct smb2_create_rq *createp = NULL; 1766 struct smb2_query_info_rq *queryp = NULL; 1767 struct smb2_close_rq *closep = NULL; 1768 struct smb_rq *create_rqp = NULL; 1769 struct smb_rq *query_rqp = NULL; 1770 struct smb_rq *close_rqp = NULL; 1771 struct mdchain *mdp; 1772 size_t next_cmd_offset = 0; 1773 uint32_t need_delete_fid = 0; 1774 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 1775 uint64_t create_flags = create_xattr ? SMB2_CREATE_IS_NAMED_STREAM : 0; 1776 char *file_namep = NULL, *stream_namep = NULL; 1777 size_t file_name_len = 0, stream_name_len = 0; 1778 int add_submount_path = 0; 1779 uint32_t create_options = 0; 1780 uint32_t disposition = FILE_OPEN; 1781 1782 /* 1783 * For this function, vnode_type is the item's type. The item will be 1784 * Opened and the Query Info will be done on the item. 1785 */ 1786 1787 /* 1788 * Note: Be careful as 1789 * (1) share->ss_mount can be null 1790 * (2) create_np can be null 1791 */ 1792 1793 SMB_MALLOC(fap, 1794 struct smbfattr *, 1795 sizeof(struct smbfattr), 1796 M_SMBTEMP, 1797 M_WAITOK | M_ZERO); 1798 if (fap == NULL) { 1799 SMBERROR("SMB_MALLOC failed\n"); 1800 error = ENOMEM; 1801 goto bad; 1802 } 1803 1804 SMB_MALLOC(queryp, 1805 struct smb2_query_info_rq *, 1806 sizeof(struct smb2_query_info_rq), 1807 M_SMBTEMP, 1808 M_WAITOK | M_ZERO); 1809 if (queryp == NULL) { 1810 SMBERROR("SMB_MALLOC failed\n"); 1811 error = ENOMEM; 1812 goto bad; 1813 } 1814 1815 if ((create_np == NULL) && (create_namep != NULL) && 1816 ((query_file_info_class == FileFsAttributeInformation) || 1817 (query_file_info_class == FileFsSizeInformation))) { 1818 /* 1819 * Must be during mount time which means we do not have the root 1820 * vnode yet, but we do have a submount path. Submount path is 1821 * inside the create_namep and already in network form. 1822 */ 1823 add_submount_path = 1; 1824 } 1825 1826resend: 1827 /* 1828 * Build the Create call 1829 */ 1830 create_flags |= SMB2_CREATE_GET_MAX_ACCESS; 1831 1832 if (add_submount_path == 1) { 1833 create_flags |= SMB2_CREATE_NAME_IS_PATH; 1834 } 1835 1836 /* Should we check to see if the server is OS X based? */ 1837 if (!(SSTOVC(share)->vc_misc_flags & (SMBV_OSX_SERVER | SMBV_OTHER_SERVER))) { 1838 if ((create_np != NULL) && 1839 (create_namep == NULL) && 1840 (create_xattr == 0) && 1841 (create_np->n_ino == create_np->n_mount->sm_root_ino)) { 1842 SMBDEBUG("Checking for OS X server \n"); 1843 create_flags |= SMB2_CREATE_AAPL_QUERY; 1844 } 1845 } 1846 1847 if (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM)) { 1848 file_namep = (char *) create_namep; 1849 file_name_len = create_name_len; 1850 } 1851 else { 1852 /* create_namep is actually the stream name */ 1853 stream_namep = (char *) create_namep; 1854 stream_name_len = create_name_len; 1855 } 1856 1857 /* 1858 * Be careful here. The vnode_type is for the actual item that the 1859 * Query Info is being done on. The path to the item is built from 1860 * create_np and file_namep, but only the calling function knows what the 1861 * item type is. 1862 */ 1863 create_options = smb2fs_smb_get_create_options(share, create_np, 1864 file_namep, stream_namep, 1865 vnode_type, 1); 1866 error = smb2fs_smb_ntcreatex(share, create_np, 1867 file_namep, file_name_len, 1868 stream_namep, stream_name_len, 1869 create_desired_access, vnode_type, 1870 share_access, disposition, 1871 create_flags, create_options, 1872 &fid, fap, 1873 &create_rqp, &createp, 1874 NULL, context); 1875 if (error) { 1876 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 1877 goto bad; 1878 } 1879 1880 if (add_submount_path == 1) { 1881 /* Clear DFS Operation flag that got set */ 1882 *create_rqp->sr_flagsp &= ~(htolel(SMB2_FLAGS_DFS_OPERATIONS)); 1883 } 1884 1885 /* Update Create hdr */ 1886 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 1887 if (error) { 1888 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1889 goto bad; 1890 } 1891 1892 /* 1893 * Build the Query Info request 1894 */ 1895 queryp->info_type = query_info_type; 1896 queryp->file_info_class = query_file_info_class; 1897 queryp->add_info = query_add_info; 1898 queryp->flags = 0; 1899 queryp->output_buffer_len = *query_output_buffer_len; 1900 queryp->output_buffer = query_output_buffer; 1901 queryp->input_buffer_len = 0; 1902 queryp->input_buffer = NULL; 1903 queryp->ret_buffer_len = 0; 1904 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 1905 queryp->fid = fid; 1906 1907 error = smb2_smb_query_info(share, queryp, &query_rqp, context); 1908 if (error) { 1909 SMBERROR("smb2_smb_query_info failed %d\n", error); 1910 goto bad; 1911 } 1912 1913 /* Update Query hdr */ 1914 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE); 1915 if (error) { 1916 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1917 goto bad; 1918 } 1919 1920 /* Chain Query Info to the Create */ 1921 create_rqp->sr_next_rqp = query_rqp; 1922 1923 /* 1924 * Build the Close request 1925 */ 1926 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 1927 if (error) { 1928 SMBERROR("smb2_smb_close_fid failed %d\n", error); 1929 goto bad; 1930 } 1931 1932 /* Update Close hdr */ 1933 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 1934 if (error) { 1935 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 1936 goto bad; 1937 } 1938 1939 /* Chain Close to the Query Info */ 1940 query_rqp->sr_next_rqp = close_rqp; 1941 1942 /* 1943 * Send the compound request of Create/Query/Close 1944 */ 1945 error = smb_rq_simple(create_rqp); 1946 1947 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 1948 /* Rebuild and try sending again */ 1949 smb_rq_done(create_rqp); 1950 create_rqp = NULL; 1951 1952 smb_rq_done(query_rqp); 1953 query_rqp = NULL; 1954 1955 smb_rq_done(close_rqp); 1956 close_rqp = NULL; 1957 1958 SMB_FREE(createp, M_SMBTEMP); 1959 createp = NULL; 1960 1961 SMB_FREE(closep, M_SMBTEMP); 1962 closep = NULL; 1963 1964 goto resend; 1965 } 1966 1967 createp->ret_ntstatus = create_rqp->sr_ntstatus; 1968 1969 /* Get pointer to response data */ 1970 smb_rq_getreply(create_rqp, &mdp); 1971 1972 if (error) { 1973 /* Create failed, try parsing the Query Info */ 1974 if ((error != ENOENT) && (error != EACCES)) { 1975 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 1976 error, create_rqp->sr_messageid); 1977 } 1978 1979 /* 1980 * Some servers return an error with the AAPL Create context instead 1981 * of just ignoring the context like it says in the MS-SMB doc. 1982 * Obviously must be a non OS X Server. 1983 */ 1984 if (createp->flags & SMB2_CREATE_AAPL_QUERY) { 1985 SMBDEBUG("Found a NON OS X server\n"); 1986 SSTOVC(share)->vc_misc_flags |= SMBV_OTHER_SERVER; 1987 } 1988 1989 goto parse_query; 1990 } 1991 1992 /* 1993 * Parse the Create response. 1994 */ 1995 error = smb2_smb_parse_create(share, mdp, createp); 1996 if (error) { 1997 /* Create parsing failed, try parsing the Query Info */ 1998 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 1999 error, create_rqp->sr_messageid); 2000 goto parse_query; 2001 } 2002 2003 /* At this point, fid has been entered into fid table */ 2004 need_delete_fid = 1; 2005 2006 /* 2007 * Fill in fap and possibly update vnode's meta data caches 2008 */ 2009 error = smb2fs_smb_parse_ntcreatex(share, create_np, createp, 2010 &fid, fap, context); 2011 if (error) { 2012 /* Updating meta data cache failed, try parsing the Query Info */ 2013 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 2014 error, create_rqp->sr_messageid); 2015 } 2016 else { 2017 /* Return max access if they want it */ 2018 if (max_accessp) { 2019 DBG_ASSERT(fap->fa_valid_mask & FA_MAX_ACCESS_VALID) 2020 *max_accessp = fap->fa_max_access; 2021 } 2022 } 2023 2024parse_query: 2025 /* Consume any pad bytes */ 2026 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 2027 if (tmp_error) { 2028 /* Failed to find next command, so can't parse rest of the responses */ 2029 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 2030 tmp_error, create_rqp->sr_messageid); 2031 error = error ? error : tmp_error; 2032 goto bad; 2033 } 2034 2035 /* 2036 * Parse Query Info SMB 2/3 header 2037 */ 2038 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 2039 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 2040 if (tmp_error) { 2041 /* Query Info got an error, try parsing the Close */ 2042 if (!error) { 2043 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 2044 tmp_error, query_rqp->sr_messageid); 2045 error = tmp_error; 2046 } 2047 goto parse_close; 2048 } 2049 2050 /* Parse the Query Info response */ 2051 tmp_error = smb2_smb_parse_query_info(mdp, queryp); 2052 if (tmp_error) { 2053 /* Query Info parsing got an error, try parsing the Close */ 2054 if (!error) { 2055 if (tmp_error != ENOATTR) { 2056 SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n", 2057 tmp_error, query_rqp->sr_messageid); 2058 } 2059 error = tmp_error; 2060 } 2061 goto parse_close; 2062 } 2063 else { 2064 *query_output_buffer_len = queryp->ret_buffer_len; 2065 } 2066 2067parse_close: 2068 /* Update closep fid so it gets freed from FID table */ 2069 closep->fid = createp->ret_fid; 2070 2071 /* Consume any pad bytes */ 2072 tmp_error = smb2_rq_next_command(query_rqp, &next_cmd_offset, mdp); 2073 if (tmp_error) { 2074 /* Failed to find next command, so can't parse rest of the responses */ 2075 SMBERROR("query smb2_rq_next_command failed %d\n", tmp_error); 2076 error = error ? error : tmp_error; 2077 goto bad; 2078 } 2079 2080 /* 2081 * Parse Close SMB 2/3 header 2082 */ 2083 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 2084 closep->ret_ntstatus = close_rqp->sr_ntstatus; 2085 if (tmp_error) { 2086 /* Close got an error */ 2087 if (!error) { 2088 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 2089 tmp_error, close_rqp->sr_messageid); 2090 error = tmp_error; 2091 } 2092 goto bad; 2093 } 2094 2095 /* Parse the Close response */ 2096 tmp_error = smb2_smb_parse_close(mdp, closep); 2097 if (tmp_error) { 2098 /* Close parsing got an error */ 2099 if (!error) { 2100 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 2101 tmp_error, close_rqp->sr_messageid); 2102 error = tmp_error; 2103 } 2104 goto bad; 2105 } 2106 2107 /* At this point, fid has been removed from fid table */ 2108 need_delete_fid = 0; 2109 2110bad: 2111 if (need_delete_fid == 1) { 2112 /* 2113 * Close failed but the Create worked and was successfully parsed. 2114 * Try issuing the Close request again. 2115 */ 2116 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 2117 NULL, NULL, context); 2118 if (tmp_error) { 2119 SMBERROR("Second close failed %d\n", tmp_error); 2120 } 2121 } 2122 2123 if (create_rqp != NULL) { 2124 smb_rq_done(create_rqp); 2125 } 2126 if (query_rqp != NULL) { 2127 smb_rq_done(query_rqp); 2128 } 2129 if (close_rqp != NULL) { 2130 smb_rq_done(close_rqp); 2131 } 2132 2133 if (createp != NULL) { 2134 SMB_FREE(createp, M_SMBTEMP); 2135 } 2136 if (queryp != NULL) { 2137 SMB_FREE(queryp, M_SMBTEMP); 2138 } 2139 if (closep != NULL) { 2140 SMB_FREE(closep, M_SMBTEMP); 2141 } 2142 2143 if (fap != NULL) { 2144 SMB_FREE(fap, M_SMBTEMP); 2145 } 2146 2147 return error; 2148} 2149 2150static int 2151smb2fs_smb_cmpd_query_dir(struct smbfs_fctx *ctx, 2152 struct smb2_query_dir_rq *queryp, 2153 vfs_context_t context) 2154{ 2155 int error, tmp_error; 2156 struct mdchain *mdp; 2157 size_t next_cmd_offset = 0; 2158 struct smb_rq *create_rqp = NULL; 2159 struct smb_rq *query_rqp = NULL; 2160 struct smb2_create_rq *createp = NULL; 2161 struct smbnode *create_np; 2162 uint32_t desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_LIST_DIRECTORY | SMB2_SYNCHRONIZE; 2163 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 2164 uint64_t create_flags = 0; 2165 uint32_t create_options = 0; 2166 uint32_t disposition = FILE_OPEN; 2167 enum vtype vnode_type = VDIR; 2168 int n_parent_locked = 0; 2169 2170 /* 2171 * For this function, vnode_type is VDIR as the Open will be done on the 2172 * parent dir and then the Query Dir will be done on that directory. 2173 */ 2174 2175 /* 2176 * SMB 2/3 searches do not want any paths (ie no '\') in the search 2177 * pattern so we have to open the actual dir that we are going to 2178 * search. 2179 * 2180 * Get the FID for the dir we are going to search 2181 */ 2182 if (ctx->f_lookupName == NULL) { 2183 /* 2184 * No name, open the parent of dnp, search pattern will 2185 * be dnp->n_name 2186 */ 2187 lck_rw_lock_shared(&ctx->f_dnp->n_parent_rwlock); 2188 n_parent_locked = 1; 2189 2190 if (ctx->f_dnp->n_parent == NULL) { 2191 SMBERROR("Looking for dnp->n_name, but f_dnp->n_parent is NULL\n"); 2192 error = ENOENT; 2193 goto bad; 2194 } 2195 create_np = ctx->f_dnp->n_parent; 2196 } 2197 else { 2198 /* 2199 * Have a name, so just open dnp and search pattern will 2200 * be ctx->f_lookupName 2201 */ 2202 create_np = ctx->f_dnp; 2203 } 2204 2205resend: 2206 /* 2207 * Build the Create call 2208 */ 2209 2210 /* fid is -1 for compound requests */ 2211 ctx->f_create_fid = 0xffffffffffffffff; 2212 2213 create_options = smb2fs_smb_get_create_options(ctx->f_share, create_np, 2214 NULL, NULL, 2215 vnode_type, 0); 2216 error = smb2fs_smb_ntcreatex(ctx->f_share, create_np, 2217 NULL, 0, 2218 NULL, 0, 2219 desired_access, vnode_type, 2220 share_access, disposition, 2221 create_flags, create_options, 2222 &ctx->f_create_fid, NULL, 2223 &create_rqp, &createp, 2224 NULL, context); 2225 if (error) { 2226 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 2227 goto bad; 2228 } 2229 2230 /* Update Create hdr */ 2231 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 2232 if (error) { 2233 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2234 goto bad; 2235 } 2236 2237 /* Create the Query Dir */ 2238 error = smb2_smb_query_dir(ctx->f_share, queryp, &query_rqp, context); 2239 if (error) { 2240 SMBERROR("smb2_smb_query_dir failed %d\n", error); 2241 goto bad; 2242 } 2243 2244 /* Update Query Hdr */ 2245 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_LAST); 2246 if (error) { 2247 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2248 goto bad; 2249 } 2250 2251 /* Chain Query Dir to the Create */ 2252 create_rqp->sr_next_rqp = query_rqp; 2253 2254 /* 2255 * Send the compound request of Create/Query Dir 2256 */ 2257 error = smb_rq_simple(create_rqp); 2258 2259 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 2260 /* Rebuild and try sending again */ 2261 smb_rq_done(create_rqp); 2262 create_rqp = NULL; 2263 2264 smb_rq_done(query_rqp); 2265 query_rqp = NULL; 2266 2267 SMB_FREE(createp, M_SMBTEMP); 2268 createp = NULL; 2269 2270 goto resend; 2271 } 2272 2273 createp->ret_ntstatus = create_rqp->sr_ntstatus; 2274 2275 /* Get pointer to response data */ 2276 smb_rq_getreply(create_rqp, &mdp); 2277 2278 if (error) { 2279 /* Create failed, try parsing the Query Dir */ 2280 if (error != ENOENT) { 2281 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 2282 error, create_rqp->sr_messageid); 2283 } 2284 goto parse_query; 2285 } 2286 2287 /* 2288 * Parse the Create response. 2289 */ 2290 error = smb2_smb_parse_create(ctx->f_share, mdp, createp); 2291 if (error) { 2292 /* Create parsing failed, try parsing the Query Dir */ 2293 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 2294 error, create_rqp->sr_messageid); 2295 goto parse_query; 2296 } 2297 2298 /* 2299 * No need to call smb2fs_smb_parse_ntcreatex since this is Query Dir and 2300 * the only vnode we have is the parent dir being searched. 2301 */ 2302 2303 /* At this point, the dir was successfully opened */ 2304 ctx->f_need_close = TRUE; 2305 ctx->f_create_fid = createp->ret_fid; 2306 2307parse_query: 2308 /* Consume any pad bytes */ 2309 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 2310 if (tmp_error) { 2311 /* Failed to find next command, so can't parse rest of the responses */ 2312 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 2313 tmp_error, create_rqp->sr_messageid); 2314 error = error ? error : tmp_error; 2315 goto bad; 2316 } 2317 2318 /* 2319 * Parse Query Dir SMB 2/3 header 2320 */ 2321 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 2322 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 2323 if (tmp_error) { 2324 /* Query Dir got an error */ 2325 if (!error) { 2326 if (tmp_error != ENOENT) { 2327 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 2328 tmp_error, query_rqp->sr_messageid); 2329 } 2330 error = tmp_error; 2331 } 2332 goto bad; 2333 } 2334 2335 /* Parse the Query Dir response */ 2336 tmp_error = smb2_smb_parse_query_dir(mdp, queryp); 2337 if (tmp_error) { 2338 /* Query Dir parsing got an error */ 2339 if (!error) { 2340 SMBERROR("smb2_smb_parse_query_dir failed %d id %lld\n", 2341 tmp_error, query_rqp->sr_messageid); 2342 error = tmp_error; 2343 } 2344 goto bad; 2345 } 2346 2347bad: 2348 ctx->f_create_rqp = create_rqp; /* save rqp so it can be freed later */ 2349 ctx->f_query_rqp = query_rqp; /* save rqp so it can be freed later */ 2350 2351 if (n_parent_locked) { 2352 lck_rw_unlock_shared(&ctx->f_dnp->n_parent_rwlock); 2353 } 2354 2355 if (createp != NULL) { 2356 SMB_FREE(createp, M_SMBTEMP); 2357 } 2358 2359 return error; 2360} 2361 2362int 2363smb2fs_smb_cmpd_query_dir_one(struct smb_share *share, struct smbnode *np, 2364 const char *query_namep, size_t query_name_len, 2365 struct smbfattr *fap, char **namep, size_t *name_lenp, 2366 vfs_context_t context) 2367{ 2368 int error, tmp_error; 2369 uint16_t info_level; 2370 uint8_t info_class, flags; 2371 SMBFID fid = 0; 2372 struct smb2_create_rq *createp = NULL; 2373 struct smb2_query_dir_rq *queryp = NULL; 2374 struct smb2_close_rq *closep = NULL; 2375 struct smb_rq *create_rqp = NULL; 2376 struct smb_rq *query_rqp = NULL; 2377 struct smb_rq *close_rqp = NULL; 2378 struct mdchain *mdp; 2379 size_t next_cmd_offset = 0; 2380 uint32_t need_delete_fid = 0; 2381 uint32_t desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_LIST_DIRECTORY | SMB2_SYNCHRONIZE; 2382 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 2383 uint64_t create_flags = 0; 2384 char *network_name = NULL; 2385 uint32_t network_name_len = 0; 2386 char *local_name = NULL; 2387 size_t local_name_len = 0; 2388 size_t max_network_name_buffer_size = 0; 2389 struct smbmount *smp; 2390 uint32_t create_options = 0; 2391 uint32_t disposition = FILE_OPEN; 2392 enum vtype vnode_type = VDIR; 2393 char *tmp_namep = NULL; 2394 int n_parent_locked = 0; 2395 2396 /* 2397 * For this function, vnode_type is VDIR as the Open will be done on the 2398 * parent dir and then the Query Dir will be done on that directory. 2399 */ 2400 2401 smp = np->n_mount; 2402 if ((np->n_ino == smp->sm_root_ino) && (query_namep == NULL)) { 2403 /* 2404 * For the root vnode, we just need limited info, so a Create/Close 2405 * will work. Cant do a Create/Query Dir/Close on the root vnode since 2406 * we have no parent to do the Create on. 2407 */ 2408 fap->fa_ino = smp->sm_root_ino; /* default value */ 2409 2410 /* Add SMB2_CREATE_DO_CREATE to get the root vnode'd File ID */ 2411 create_flags = SMB2_CREATE_GET_MAX_ACCESS | SMB2_CREATE_DO_CREATE; 2412 2413 error = smb2fs_smb_cmpd_create(share, np, 2414 NULL, 0, 2415 NULL, 0, 2416 SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, VDIR, 2417 NTCREATEX_SHARE_ACCESS_ALL, FILE_OPEN, 2418 create_flags, NULL, 2419 NULL, fap, 2420 NULL, context); 2421 if (!error) { 2422 fap->fa_attr = SMB_EFA_DIRECTORY; 2423 fap->fa_vtype = VDIR; 2424 fap->fa_valid_mask |= FA_VTYPE_VALID; 2425 } 2426 2427 return (error); 2428 } 2429 2430 /* 2431 * Unicode requires 4 * max file name len, codepage requires 3 * max file 2432 * name, so lets just always use the unicode size. 2433 */ 2434 max_network_name_buffer_size = share->ss_maxfilenamelen * 4; 2435 SMB_MALLOC(network_name, char *, max_network_name_buffer_size, M_TEMP, 2436 M_WAITOK | M_ZERO); 2437 if (network_name == NULL) { 2438 SMBERROR("network_name malloc failed\n"); 2439 error = ENOMEM; 2440 goto bad; 2441 } 2442 2443 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 2444 2445 info_level = SMB_FIND_BOTH_DIRECTORY_INFO; 2446 2447 /* 2448 * Set up for the Query Dir call 2449 */ 2450 SMB_MALLOC(queryp, 2451 struct smb2_query_dir_rq *, 2452 sizeof(struct smb2_query_dir_rq), 2453 M_SMBTEMP, 2454 M_WAITOK | M_ZERO); 2455 if (queryp == NULL) { 2456 SMBERROR("SMB_MALLOC failed\n"); 2457 error = ENOMEM; 2458 goto bad; 2459 } 2460 2461 /* Just want first search entry returned and start from beginning */ 2462 flags = SMB2_RETURN_SINGLE_ENTRY | SMB2_RESTART_SCANS; 2463 2464 switch (info_level) { 2465 case SMB_FIND_FULL_DIRECTORY_INFO: 2466 /* For SMB 2/3, get the file/dir IDs too but no short names */ 2467 info_class = FileIdFullDirectoryInformation; 2468 break; 2469 2470 case SMB_FIND_BOTH_DIRECTORY_INFO: 2471 /* For SMB 2/3, get the file/dir IDs too */ 2472 info_class = FileIdBothDirectoryInformation; 2473 break; 2474 2475 default: 2476 SMBERROR("invalid infolevel %d", info_level); 2477 error = EINVAL; 2478 goto bad; 2479 } 2480 2481 queryp->file_info_class = info_class; 2482 queryp->flags = flags; 2483 queryp->file_index = 0; /* no FileIndex from prev search */ 2484 queryp->fid = fid; 2485 queryp->output_buffer_len = 64 * 1024; /* 64K should be large enough */ 2486 2487 /* 2488 * Not a wildcard, so use UTF_SFM_CONVERSIONS 2489 */ 2490 queryp->name_flags = UTF_SFM_CONVERSIONS; 2491 2492 if (query_namep != NULL) { 2493 /* We have a dnp and a name to search for in that dir */ 2494 queryp->dnp = np; 2495 queryp->namep = (char*) query_namep; 2496 queryp->name_len = (uint32_t) query_name_len; 2497 } 2498 else { 2499 /* 2500 * We are looking for np, so use np->n_parent and np->n_name 2501 */ 2502 lck_rw_lock_shared(&np->n_parent_rwlock); 2503 n_parent_locked = 1; 2504 2505 queryp->dnp = np->n_parent; 2506 2507 if (queryp->dnp == NULL) { 2508 /* This could happen during a forced unmount */ 2509 SMBERROR("Looking for np, but np->n_parent is NULL\n"); 2510 error = ENOENT; 2511 goto bad; 2512 2513 } 2514 2515 lck_rw_lock_shared(&np->n_name_rwlock); 2516 tmp_namep = smb_strndup(np->n_name, np->n_nmlen); 2517 queryp->namep = tmp_namep; 2518 lck_rw_unlock_shared(&np->n_name_rwlock); 2519 2520 queryp->name_len = (uint32_t) np->n_nmlen; 2521 } 2522 2523resend: 2524 /* 2525 * Build the Create call 2526 */ 2527 DBG_ASSERT (vnode_vtype(queryp->dnp->n_vnode) == VDIR); 2528 2529 create_options = smb2fs_smb_get_create_options(share, queryp->dnp, 2530 NULL, NULL, 2531 vnode_type, 0); 2532 error = smb2fs_smb_ntcreatex(share, queryp->dnp, 2533 NULL, 0, 2534 NULL, 0, 2535 desired_access, vnode_type, 2536 share_access, disposition, 2537 create_flags, create_options, 2538 &fid, NULL, 2539 &create_rqp, &createp, 2540 NULL, context); 2541 if (error) { 2542 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 2543 goto bad; 2544 } 2545 2546 /* Update Create hdr */ 2547 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 2548 if (error) { 2549 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2550 goto bad; 2551 } 2552 2553 /* 2554 * Build the Query Dir request 2555 */ 2556 error = smb2_smb_query_dir(share, queryp, &query_rqp, context); 2557 if (error) { 2558 SMBERROR("smb2_smb_query_dir failed %d\n", error); 2559 goto bad; 2560 } 2561 2562 /* Update Query Hdr */ 2563 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE); 2564 if (error) { 2565 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2566 goto bad; 2567 } 2568 2569 /* Chain Query Dir to the Create */ 2570 create_rqp->sr_next_rqp = query_rqp; 2571 2572 /* 2573 * Build the Close request 2574 */ 2575 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 2576 if (error) { 2577 SMBERROR("smb2_smb_close_fid failed %d\n", error); 2578 goto bad; 2579 } 2580 2581 /* Update Close hdr */ 2582 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 2583 if (error) { 2584 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2585 goto bad; 2586 } 2587 2588 /* Chain Close to the Query Info */ 2589 query_rqp->sr_next_rqp = close_rqp; 2590 2591 /* 2592 * Send the compound request of Create/QueryDir/Close 2593 */ 2594 error = smb_rq_simple(create_rqp); 2595 2596 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 2597 /* Rebuild and try sending again */ 2598 smb_rq_done(create_rqp); 2599 create_rqp = NULL; 2600 2601 smb_rq_done(query_rqp); 2602 query_rqp = NULL; 2603 2604 smb_rq_done(close_rqp); 2605 close_rqp = NULL; 2606 2607 SMB_FREE(createp, M_SMBTEMP); 2608 createp = NULL; 2609 2610 SMB_FREE(closep, M_SMBTEMP); 2611 closep = NULL; 2612 2613 goto resend; 2614 } 2615 2616 createp->ret_ntstatus = create_rqp->sr_ntstatus; 2617 2618 /* Get pointer to response data */ 2619 smb_rq_getreply(create_rqp, &mdp); 2620 2621 if (error) { 2622 /* Create failed, try parsing the Query Dir */ 2623 if ((error != ENOENT) && (error != EACCES)) { 2624 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 2625 error, create_rqp->sr_messageid); 2626 } 2627 goto parse_query; 2628 } 2629 2630 /* 2631 * Parse the Create response. 2632 */ 2633 error = smb2_smb_parse_create(share, mdp, createp); 2634 if (error) { 2635 /* Create parsing failed, try parsing the Query Dir */ 2636 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 2637 error, create_rqp->sr_messageid); 2638 goto parse_query; 2639 } 2640 2641 /* At this point, fid has been entered into fid table */ 2642 need_delete_fid = 1; 2643 2644 /* 2645 * No need to call smb2fs_smb_parse_ntcreatex since this is Query Dir and 2646 * the only vnode we have is the parent dir being searched. 2647 */ 2648 2649parse_query: 2650 /* Consume any pad bytes */ 2651 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 2652 if (tmp_error) { 2653 /* Failed to find next command, so can't parse rest of the responses */ 2654 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 2655 tmp_error, create_rqp->sr_messageid); 2656 error = error ? error : tmp_error; 2657 goto bad; 2658 } 2659 2660 /* 2661 * Parse Query Dir SMB 2/3 header 2662 */ 2663 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 2664 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 2665 if (tmp_error) { 2666 /* Query Dir got an error */ 2667 if (!error) { 2668 if (tmp_error != ENOENT) { 2669 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 2670 tmp_error, query_rqp->sr_messageid); 2671 } 2672 error = tmp_error; 2673 } 2674 goto parse_close; 2675 } 2676 2677 /* Parse the Query Dir response */ 2678 tmp_error = smb2_smb_parse_query_dir(mdp, queryp); 2679 if (tmp_error) { 2680 /* Query Dir parsing got an error */ 2681 if (!error) { 2682 SMBERROR("smb2_smb_parse_query_dir failed %d id %lld\n", 2683 tmp_error, query_rqp->sr_messageid); 2684 error = tmp_error; 2685 } 2686 goto parse_close; 2687 } 2688 2689 /* 2690 * Parse the only entry out of the output buffer 2691 */ 2692 switch (queryp->file_info_class) { 2693 case FileIdFullDirectoryInformation: 2694 case FileIdBothDirectoryInformation: 2695 /* Call the parsing function */ 2696 tmp_error = smb2_smb_parse_query_dir_both_dir_info(share, mdp, 2697 info_level, 2698 NULL, fap, 2699 network_name, &network_name_len, 2700 max_network_name_buffer_size); 2701 if (tmp_error) { 2702 /* Query Dir parsing got an error */ 2703 if (!error) { 2704 SMBERROR("smb2_smb_parse_query_dir_both_dir_info failed %d id %lld\n", 2705 tmp_error, query_rqp->sr_messageid); 2706 error = tmp_error; 2707 } 2708 goto parse_close; 2709 } 2710 2711 /* 2712 * Convert network name to a malloc'd local name and return 2713 * that name 2714 */ 2715 local_name_len = network_name_len; 2716 local_name = smbfs_ntwrkname_tolocal(network_name, &local_name_len, 2717 SMB_UNICODE_STRINGS(SSTOVC(share))); 2718 2719 if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) { 2720 /* Server does not support File IDs */ 2721 fap->fa_ino = smbfs_getino(np, local_name, local_name_len); 2722 } 2723 2724 /* Return the malloc'd name from the server */ 2725 if (namep) { 2726 *namep = local_name; 2727 local_name = NULL; 2728 } 2729 2730 if (name_lenp) { 2731 *name_lenp = local_name_len; 2732 } 2733 2734 break; 2735 2736 default: 2737 if (!error) { 2738 SMBERROR("unexpected info level %d\n", queryp->file_info_class); 2739 error = EINVAL; 2740 } 2741 goto parse_close; 2742 } 2743 2744parse_close: 2745 /* Update closep fid so it gets freed from FID table */ 2746 closep->fid = createp->ret_fid; 2747 2748 /* Consume any pad bytes */ 2749 tmp_error = smb2_rq_next_command(query_rqp, &next_cmd_offset, mdp); 2750 if (tmp_error) { 2751 /* Failed to find next command, so can't parse rest of the responses */ 2752 SMBERROR("query smb2_rq_next_command failed %d\n", tmp_error); 2753 error = error ? error : tmp_error; 2754 goto bad; 2755 } 2756 2757 /* 2758 * Parse Close SMB 2/3 header 2759 */ 2760 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 2761 closep->ret_ntstatus = close_rqp->sr_ntstatus; 2762 if (tmp_error) { 2763 /* Close got an error */ 2764 if (!error) { 2765 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 2766 tmp_error, close_rqp->sr_messageid); 2767 error = tmp_error; 2768 } 2769 goto bad; 2770 } 2771 2772 /* Parse the Close response */ 2773 tmp_error = smb2_smb_parse_close(mdp, closep); 2774 if (tmp_error) { 2775 /* Close parsing got an error */ 2776 if (!error) { 2777 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 2778 tmp_error, close_rqp->sr_messageid); 2779 error = tmp_error; 2780 } 2781 goto bad; 2782 } 2783 2784 /* At this point, fid has been removed from fid table */ 2785 need_delete_fid = 0; 2786 2787bad: 2788 if (need_delete_fid == 1) { 2789 /* 2790 * Close failed but the Create worked and was successfully parsed. 2791 * Try issuing the Close request again. 2792 */ 2793 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 2794 NULL, NULL, context); 2795 if (tmp_error) { 2796 SMBERROR("Second close failed %d\n", tmp_error); 2797 } 2798 } 2799 2800 if (tmp_namep) { 2801 SMB_FREE(tmp_namep, M_SMBSTR); 2802 } 2803 2804 if (n_parent_locked) { 2805 lck_rw_unlock_shared(&np->n_parent_rwlock); 2806 } 2807 2808 if (create_rqp != NULL) { 2809 smb_rq_done(create_rqp); 2810 } 2811 if (query_rqp != NULL) { 2812 smb_rq_done(query_rqp); 2813 } 2814 if (close_rqp != NULL) { 2815 smb_rq_done(close_rqp); 2816 } 2817 2818 if (createp != NULL) { 2819 SMB_FREE(createp, M_SMBTEMP); 2820 } 2821 if (queryp != NULL) { 2822 SMB_FREE(queryp, M_SMBTEMP); 2823 } 2824 if (closep != NULL) { 2825 SMB_FREE(closep, M_SMBTEMP); 2826 } 2827 2828 if (network_name != NULL) { 2829 SMB_FREE(network_name, M_SMBTEMP); 2830 } 2831 if (local_name != NULL) { 2832 SMB_FREE(local_name, M_SMBTEMP); 2833 } 2834 2835 return error; 2836} 2837 2838static int 2839smb2fs_smb_cmpd_reparse_point_get(struct smb_share *share, 2840 struct smbnode *create_np, 2841 struct uio *ioctl_uiop, 2842 vfs_context_t context) 2843{ 2844 int error, tmp_error; 2845 SMBFID fid = 0; 2846 struct smbfattr *fap = NULL; 2847 struct smb2_create_rq *createp = NULL; 2848 struct smb2_ioctl_rq *ioctlp = NULL; 2849 struct smb2_close_rq *closep = NULL; 2850 struct smb_rq *create_rqp = NULL; 2851 struct smb_rq *ioctl_rqp = NULL; 2852 struct smb_rq *close_rqp = NULL; 2853 struct mdchain *mdp; 2854 size_t next_cmd_offset = 0; 2855 uint32_t need_delete_fid = 0; 2856 uint32_t create_desired_access = SMB2_FILE_READ_DATA | 2857 SMB2_FILE_READ_ATTRIBUTES; 2858 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 2859 uint64_t create_flags = SMB2_CREATE_GET_MAX_ACCESS; 2860 uint32_t create_options = 0; 2861 uint32_t disposition = FILE_OPEN; 2862 enum vtype vnode_type = VREG; 2863 2864 /* 2865 * For this function, vnode_type is VREG as the Open will be done on the 2866 * reparse point and then the Ioctl will be done on the reparse point. 2867 */ 2868 2869 SMB_MALLOC(fap, 2870 struct smbfattr *, 2871 sizeof(struct smbfattr), 2872 M_SMBTEMP, 2873 M_WAITOK | M_ZERO); 2874 if (fap == NULL) { 2875 SMBERROR("SMB_MALLOC failed\n"); 2876 error = ENOMEM; 2877 goto bad; 2878 } 2879 2880 SMB_MALLOC(ioctlp, 2881 struct smb2_ioctl_rq *, 2882 sizeof(struct smb2_ioctl_rq), 2883 M_SMBTEMP, 2884 M_WAITOK | M_ZERO); 2885 if (ioctlp == NULL) { 2886 SMBERROR("SMB_MALLOC failed\n"); 2887 error = ENOMEM; 2888 goto bad; 2889 } 2890 2891resend: 2892 /* 2893 * Build the Create call 2894 */ 2895 create_options = smb2fs_smb_get_create_options(share, create_np, 2896 NULL, NULL, 2897 vnode_type, 1); 2898 error = smb2fs_smb_ntcreatex(share, create_np, 2899 NULL, 0, 2900 NULL, 0, 2901 create_desired_access, vnode_type, 2902 share_access, disposition, 2903 create_flags, create_options, 2904 &fid, NULL, 2905 &create_rqp, &createp, 2906 NULL, context); 2907 if (error) { 2908 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 2909 goto bad; 2910 } 2911 2912 /* Update Create hdr */ 2913 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 2914 if (error) { 2915 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2916 goto bad; 2917 } 2918 2919 /* 2920 * Build the IOCTL request 2921 */ 2922 ioctlp->share = share; 2923 ioctlp->ctl_code = FSCTL_GET_REPARSE_POINT; 2924 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 2925 ioctlp->fid = fid; 2926 2927 ioctlp->snd_input_len = 0; 2928 ioctlp->snd_output_len = 0; 2929 ioctlp->rcv_input_len = 0; 2930 /* reparse points should not need more than 16K of data */ 2931 ioctlp->rcv_output_len = 16 * 1024; 2932 2933 error = smb2_smb_ioctl(share, ioctlp, &ioctl_rqp, context); 2934 if (error) { 2935 SMBERROR("smb2_smb_ioctl failed %d\n", error); 2936 goto bad; 2937 } 2938 2939 /* Update IOCTL hdr */ 2940 error = smb2_rq_update_cmpd_hdr(ioctl_rqp, SMB2_CMPD_MIDDLE); 2941 if (error) { 2942 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2943 goto bad; 2944 } 2945 2946 /* Chain IOCTL to the Create */ 2947 create_rqp->sr_next_rqp = ioctl_rqp; 2948 2949 /* 2950 * Build the Close request 2951 */ 2952 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 2953 if (error) { 2954 SMBERROR("smb2_smb_close_fid failed %d\n", error); 2955 goto bad; 2956 } 2957 2958 /* Update Close hdr */ 2959 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 2960 if (error) { 2961 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 2962 goto bad; 2963 } 2964 2965 /* Chain Close to the IOCTL */ 2966 ioctl_rqp->sr_next_rqp = close_rqp; 2967 2968 /* 2969 * Send the compound request of Create/IOCTL/Close 2970 */ 2971 error = smb_rq_simple(create_rqp); 2972 2973 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 2974 /* Rebuild and try sending again */ 2975 smb_rq_done(create_rqp); 2976 create_rqp = NULL; 2977 2978 smb_rq_done(ioctl_rqp); 2979 ioctl_rqp = NULL; 2980 2981 smb_rq_done(close_rqp); 2982 close_rqp = NULL; 2983 2984 SMB_FREE(createp, M_SMBTEMP); 2985 createp = NULL; 2986 2987 SMB_FREE(closep, M_SMBTEMP); 2988 closep = NULL; 2989 2990 goto resend; 2991 } 2992 2993 createp->ret_ntstatus = create_rqp->sr_ntstatus; 2994 2995 /* Get pointer to response data */ 2996 smb_rq_getreply(create_rqp, &mdp); 2997 2998 if (error) { 2999 /* Create failed, try parsing the IOCTL */ 3000 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 3001 error, create_rqp->sr_messageid); 3002 goto parse_ioctl; 3003 } 3004 3005 /* 3006 * Parse the Create response. 3007 */ 3008 error = smb2_smb_parse_create(share, mdp, createp); 3009 if (error) { 3010 /* Create parsing failed, try parsing the IOCTL */ 3011 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 3012 error, create_rqp->sr_messageid); 3013 goto parse_ioctl; 3014 } 3015 3016 /* At this point, fid has been entered into fid table */ 3017 need_delete_fid = 1; 3018 3019 /* 3020 * Fill in fap and possibly update vnode's meta data caches 3021 */ 3022 error = smb2fs_smb_parse_ntcreatex(share, create_np, createp, 3023 &fid, fap, context); 3024 if (error) { 3025 /* Updating meta data cache failed, try parsing the Ioctl */ 3026 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 3027 error, create_rqp->sr_messageid); 3028 } 3029 3030parse_ioctl: 3031 /* Consume any pad bytes */ 3032 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 3033 if (tmp_error) { 3034 /* Failed to find next command, so can't parse rest of the responses */ 3035 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 3036 tmp_error, create_rqp->sr_messageid); 3037 goto bad; 3038 } 3039 3040 /* 3041 * Parse IOCTL SMB 2/3 header 3042 */ 3043 tmp_error = smb2_rq_parse_header(ioctl_rqp, &mdp); 3044 ioctlp->ret_ntstatus = ioctl_rqp->sr_ntstatus; 3045 if (tmp_error) { 3046 /* IOCTL got an error, try parsing the Close */ 3047 if (!error) { 3048 SMBDEBUG("ioctl smb2_rq_parse_header failed %d, id %lld\n", 3049 tmp_error, ioctl_rqp->sr_messageid); 3050 error = tmp_error; 3051 } 3052 goto parse_close; 3053 } 3054 3055 /* Parse the IOCTL response */ 3056 tmp_error = smb2_smb_parse_ioctl(mdp, ioctlp); 3057 if (tmp_error) { 3058 /* IOCTL parsing got an error, try parsing the Close */ 3059 if (!error) { 3060 SMBERROR("smb2_smb_parse_ioctl failed %d id %lld\n", 3061 tmp_error, ioctl_rqp->sr_messageid); 3062 error = tmp_error; 3063 } 3064 goto parse_close; 3065 } 3066 3067 /* 3068 * At this point, we know the IOCTL worked. 3069 * The IOCTL will return the path in rcv_output_buffer and rcv_output_len 3070 * Update the create_np with the symlink info. 3071 * smbfs_update_symlink_cache will deal with any null pointers 3072 */ 3073 smbfs_update_symlink_cache(create_np, (char *) ioctlp->rcv_output_buffer, 3074 ioctlp->rcv_output_len); 3075 tmp_error = uiomove((char *) ioctlp->rcv_output_buffer, 3076 (int) ioctlp->rcv_output_len, 3077 ioctl_uiop); 3078 if (tmp_error) { 3079 /* uiomove failed */ 3080 if (!error) { 3081 SMBERROR("uiomove failed %d id %lld\n", 3082 tmp_error, ioctl_rqp->sr_messageid); 3083 error = tmp_error; 3084 } 3085 goto parse_close; 3086 } 3087 3088parse_close: 3089 /* Update closep fid so it gets freed from FID table */ 3090 closep->fid = createp->ret_fid; 3091 3092 /* Consume any pad bytes */ 3093 tmp_error = smb2_rq_next_command(ioctl_rqp, &next_cmd_offset, mdp); 3094 if (tmp_error) { 3095 /* Failed to find next command, so can't parse rest of the responses */ 3096 SMBERROR("ioctl smb2_rq_next_command failed %d\n", tmp_error); 3097 error = error ? error : tmp_error; 3098 goto bad; 3099 } 3100 3101 /* 3102 * Parse Close SMB 2/3 header 3103 */ 3104 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 3105 closep->ret_ntstatus = close_rqp->sr_ntstatus; 3106 if (tmp_error) { 3107 if (!error) { 3108 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 3109 tmp_error, close_rqp->sr_messageid); 3110 error = tmp_error; 3111 } 3112 goto bad; 3113 } 3114 3115 /* Parse the Close response */ 3116 tmp_error = smb2_smb_parse_close(mdp, closep); 3117 if (tmp_error) { 3118 if (!error) { 3119 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 3120 tmp_error, close_rqp->sr_messageid); 3121 error = tmp_error; 3122 } 3123 goto bad; 3124 } 3125 3126 /* At this point, fid has been removed from fid table */ 3127 need_delete_fid = 0; 3128 3129bad: 3130 if (need_delete_fid == 1) { 3131 /* 3132 * Close failed but the Create worked and was successfully parsed. 3133 * Try issuing the Close request again. 3134 */ 3135 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 3136 NULL, NULL, context); 3137 if (tmp_error) { 3138 SMBERROR("Second close failed %d\n", tmp_error); 3139 } 3140 } 3141 3142 if (create_rqp != NULL) { 3143 smb_rq_done(create_rqp); 3144 } 3145 if (ioctl_rqp != NULL) { 3146 smb_rq_done(ioctl_rqp); 3147 } 3148 if (close_rqp != NULL) { 3149 smb_rq_done(close_rqp); 3150 } 3151 3152 if (createp != NULL) { 3153 SMB_FREE(createp, M_SMBTEMP); 3154 } 3155 if (ioctlp != NULL) { 3156 SMB_FREE(ioctlp, M_SMBTEMP); 3157 } 3158 if (closep != NULL) { 3159 SMB_FREE(closep, M_SMBTEMP); 3160 } 3161 3162 if (fap != NULL) { 3163 SMB_FREE(fap, M_SMBTEMP); 3164 } 3165 3166 return error; 3167} 3168 3169static int 3170smb2fs_smb_cmpd_reparse_point_set(struct smb_share *share, struct smbnode *create_np, 3171 const char *namep, size_t name_len, 3172 char *targetp, size_t target_len, 3173 struct smbfattr *fap, vfs_context_t context) 3174{ 3175 int error, tmp_error; 3176 int ioctl_error= EINVAL; /* assume IOCTL failed */ 3177 SMBFID fid = 0; 3178 struct smb2_create_rq *createp = NULL; 3179 struct smb2_query_info_rq *queryp = NULL; 3180 struct smb2_ioctl_rq *ioctlp = NULL; 3181 struct smb2_close_rq *closep = NULL; 3182 struct smb_rq *create_rqp = NULL; 3183 struct smb_rq *query_rqp = NULL; 3184 struct smb_rq *ioctl_rqp = NULL; 3185 struct smb_rq *close_rqp = NULL; 3186 struct mdchain *mdp; 3187 size_t next_cmd_offset = 0; 3188 uint32_t need_delete_fid = 0, create_worked = 0; 3189 uint32_t create_desired_access = SMB2_FILE_WRITE_DATA | 3190 SMB2_FILE_WRITE_ATTRIBUTES | 3191 SMB2_DELETE; 3192 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 3193 uint64_t create_flags = SMB2_CREATE_DO_CREATE | SMB2_CREATE_GET_MAX_ACCESS; 3194 size_t path_len; 3195 char *pathp = NULL; 3196 struct smbmount *smp = create_np->n_mount; 3197 int add_query = 0; 3198 uint64_t inode_number = 0; 3199 uint32_t inode_number_len; 3200 uint32_t create_options = 0; 3201 uint32_t disposition = FILE_CREATE; 3202 enum vtype vnode_type = VREG; 3203 3204 /* 3205 * For this function, vnode_type is VREG as the Open will be done on the 3206 * reparse point and then the Ioctl will be done on the reparse point. 3207 */ 3208 3209 if (fap == NULL) { 3210 /* This should never happen */ 3211 SMBERROR("fap is NULL \n"); 3212 error = EINVAL; 3213 goto bad; 3214 } 3215 3216 /* 3217 * This function can do Create/Query/Ioctl/Close, or Create/Ioctl/Close 3218 * If File IDs are supported, then the Query is added to get the file ID. 3219 */ 3220 3221 if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) { 3222 /* Need the file id, so add a query into the compound request */ 3223 add_query = 1; 3224 } 3225 3226 /* Convert target to a network style path */ 3227 path_len = (target_len * 2) + 2; /* Start with the max possible size */ 3228 SMB_MALLOC(pathp, char *, path_len, M_TEMP, M_WAITOK | M_ZERO); 3229 if (pathp == NULL) { 3230 error = ENOMEM; 3231 goto bad; 3232 } 3233 3234 error = smb_convert_path_to_network(targetp, target_len, pathp, &path_len, 3235 '\\', SMB_UTF_SFM_CONVERSIONS, 3236 SMB_UNICODE_STRINGS(SSTOVC(share))); 3237 if (error) { 3238 goto bad; 3239 } 3240 3241 if (add_query) { 3242 SMB_MALLOC(queryp, 3243 struct smb2_query_info_rq *, 3244 sizeof(struct smb2_query_info_rq), 3245 M_SMBTEMP, 3246 M_WAITOK | M_ZERO); 3247 if (queryp == NULL) { 3248 SMBERROR("SMB_MALLOC failed\n"); 3249 error = ENOMEM; 3250 goto bad; 3251 } 3252 } 3253 3254 SMB_MALLOC(ioctlp, 3255 struct smb2_ioctl_rq *, 3256 sizeof(struct smb2_ioctl_rq), 3257 M_SMBTEMP, 3258 M_WAITOK | M_ZERO); 3259 if (ioctlp == NULL) { 3260 SMBERROR("SMB_MALLOC failed\n"); 3261 error = ENOMEM; 3262 goto bad; 3263 } 3264 3265resend: 3266 /* 3267 * Build the Create call 3268 */ 3269 create_options = smb2fs_smb_get_create_options(share, create_np, 3270 namep, NULL, 3271 vnode_type, 1); 3272 error = smb2fs_smb_ntcreatex(share, create_np, 3273 namep, name_len, 3274 NULL, 0, 3275 create_desired_access, vnode_type, 3276 share_access, disposition, 3277 create_flags, create_options, 3278 &fid, fap, 3279 &create_rqp, &createp, 3280 NULL, context); 3281 if (error) { 3282 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 3283 goto bad; 3284 } 3285 3286 /* Update Create hdr */ 3287 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 3288 if (error) { 3289 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 3290 goto bad; 3291 } 3292 3293 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 3294 3295 if (add_query) { 3296 /* 3297 * Build the Query Info request (to get File ID) 3298 */ 3299 inode_number_len = (uint32_t) sizeof(inode_number); 3300 3301 queryp->info_type = SMB2_0_INFO_FILE; 3302 queryp->file_info_class = FileInternalInformation; 3303 queryp->add_info = 0; 3304 queryp->flags = 0; 3305 queryp->output_buffer_len = inode_number_len; 3306 queryp->output_buffer = (uint8_t *) &inode_number; 3307 queryp->input_buffer_len = 0; 3308 queryp->input_buffer = NULL; 3309 queryp->ret_buffer_len = 0; 3310 queryp->fid = fid; 3311 3312 error = smb2_smb_query_info(share, queryp, &query_rqp, context); 3313 if (error) { 3314 SMBERROR("smb2_smb_query_info failed %d\n", error); 3315 goto bad; 3316 } 3317 3318 /* Update Query hdr */ 3319 error = smb2_rq_update_cmpd_hdr(query_rqp, SMB2_CMPD_MIDDLE); 3320 if (error) { 3321 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 3322 goto bad; 3323 } 3324 3325 /* Chain Query Info to the Create */ 3326 create_rqp->sr_next_rqp = query_rqp; 3327 } 3328 3329 /* 3330 * Build the IOCTL request 3331 * path and path len is passed in via snd_input_buffer and snd_input_len 3332 */ 3333 ioctlp->share = share; 3334 ioctlp->ctl_code = FSCTL_SET_REPARSE_POINT; 3335 ioctlp->fid = fid; 3336 3337 ioctlp->snd_input_len = (uint32_t) path_len; 3338 ioctlp->snd_output_len = 0; 3339 ioctlp->rcv_input_len = 0; 3340 ioctlp->rcv_output_len = 0; 3341 ioctlp->snd_input_buffer = (uint8_t *) pathp; 3342 3343 error = smb2_smb_ioctl(share, ioctlp, &ioctl_rqp, context); 3344 if (error) { 3345 SMBERROR("smb2_smb_ioctl failed %d\n", error); 3346 goto bad; 3347 } 3348 3349 /* Update IOCTL hdr */ 3350 error = smb2_rq_update_cmpd_hdr(ioctl_rqp, SMB2_CMPD_MIDDLE); 3351 if (error) { 3352 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 3353 goto bad; 3354 } 3355 3356 if (add_query) { 3357 /* Chain IOCTL to the Query */ 3358 query_rqp->sr_next_rqp = ioctl_rqp; 3359 } 3360 else { 3361 /* Chain IOCTL to the Create */ 3362 create_rqp->sr_next_rqp = ioctl_rqp; 3363 } 3364 3365 /* 3366 * Build the Close request 3367 */ 3368 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 3369 if (error) { 3370 SMBERROR("smb2_smb_close_fid failed %d\n", error); 3371 goto bad; 3372 } 3373 3374 /* Update Close hdr */ 3375 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 3376 if (error) { 3377 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 3378 goto bad; 3379 } 3380 3381 /* Chain Close to the IOCTL */ 3382 ioctl_rqp->sr_next_rqp = close_rqp; 3383 3384 /* 3385 * Send the compound request of Create/IOCTL/Close 3386 */ 3387 error = smb_rq_simple(create_rqp); 3388 3389 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 3390 /* Rebuild and try sending again */ 3391 smb_rq_done(create_rqp); 3392 create_rqp = NULL; 3393 3394 if (query_rqp) { 3395 smb_rq_done(query_rqp); 3396 query_rqp = NULL; 3397 } 3398 3399 smb_rq_done(ioctl_rqp); 3400 ioctl_rqp = NULL; 3401 3402 smb_rq_done(close_rqp); 3403 close_rqp = NULL; 3404 3405 SMB_FREE(createp, M_SMBTEMP); 3406 createp = NULL; 3407 3408 SMB_FREE(closep, M_SMBTEMP); 3409 closep = NULL; 3410 3411 goto resend; 3412 } 3413 3414 createp->ret_ntstatus = create_rqp->sr_ntstatus; 3415 3416 /* Get pointer to response data */ 3417 smb_rq_getreply(create_rqp, &mdp); 3418 3419 if (error) { 3420 /* Create failed, try parsing the IOCTL */ 3421 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 3422 error, create_rqp->sr_messageid); 3423 goto parse_query; 3424 } 3425 3426 /* 3427 * Parse the Create response. 3428 */ 3429 error = smb2_smb_parse_create(share, mdp, createp); 3430 if (error) { 3431 /* Create parsing failed, try parsing the IOCTL */ 3432 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 3433 error, create_rqp->sr_messageid); 3434 goto parse_query; 3435 } 3436 3437 /* At this point, fid has been entered into fid table */ 3438 need_delete_fid = 1; 3439 create_worked = 1; 3440 3441 /* 3442 * Fill in fap and possibly update vnode's meta data caches 3443 */ 3444 error = smb2fs_smb_parse_ntcreatex(share, create_np, createp, 3445 &fid, fap, context); 3446 if (error) { 3447 /* Updating meta data cache failed, try parsing the IOCTL */ 3448 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 3449 error, create_rqp->sr_messageid); 3450 } 3451 3452parse_query: 3453 if (query_rqp != NULL) { 3454 /* Consume any pad bytes */ 3455 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 3456 if (tmp_error) { 3457 /* Failed to find next command, so can't parse rest of the responses */ 3458 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 3459 tmp_error, create_rqp->sr_messageid); 3460 error = error ? error : tmp_error; 3461 goto bad; 3462 } 3463 3464 /* 3465 * Parse Query Info SMB 2/3 header 3466 */ 3467 tmp_error = smb2_rq_parse_header(query_rqp, &mdp); 3468 queryp->ret_ntstatus = query_rqp->sr_ntstatus; 3469 if (tmp_error) { 3470 /* Query Info got an error, try parsing the Close */ 3471 if (!error) { 3472 SMBDEBUG("query smb2_rq_parse_header failed %d, id %lld\n", 3473 tmp_error, query_rqp->sr_messageid); 3474 error = tmp_error; 3475 } 3476 goto parse_ioctl; 3477 } 3478 3479 /* Parse the Query Info response */ 3480 tmp_error = smb2_smb_parse_query_info(mdp, queryp); 3481 if (tmp_error) { 3482 /* Query Info parsing got an error, try parsing the Close */ 3483 if (!error) { 3484 if (tmp_error != ENOATTR) { 3485 SMBERROR("smb2_smb_parse_query_info failed %d id %lld\n", 3486 tmp_error, query_rqp->sr_messageid); 3487 } 3488 error = tmp_error; 3489 } 3490 goto parse_ioctl; 3491 } 3492 else { 3493 /* Query worked, so get the inode number */ 3494 if (fap) { 3495 fap->fa_ino = inode_number; 3496 smb2fs_smb_file_id_check(share, fap->fa_ino, NULL, 0); 3497 } 3498 } 3499 } 3500 3501parse_ioctl: 3502 /* Consume any pad bytes */ 3503 tmp_error = smb2_rq_next_command(query_rqp != NULL ? query_rqp : create_rqp, 3504 &next_cmd_offset, mdp); 3505 if (tmp_error) { 3506 /* Failed to find next command, so can't parse rest of the responses */ 3507 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 3508 tmp_error, create_rqp->sr_messageid); 3509 goto bad; 3510 } 3511 3512 /* 3513 * Parse IOCTL SMB 2/3 header 3514 */ 3515 tmp_error = smb2_rq_parse_header(ioctl_rqp, &mdp); 3516 ioctlp->ret_ntstatus = ioctl_rqp->sr_ntstatus; 3517 ioctl_error = tmp_error; 3518 if (tmp_error) { 3519 /* IOCTL got an error, try parsing the Close */ 3520 if (!error) { 3521 SMBDEBUG("ioctl smb2_rq_parse_header failed %d, id %lld\n", 3522 tmp_error, ioctl_rqp->sr_messageid); 3523 error = tmp_error; 3524 } 3525 goto parse_close; 3526 } 3527 3528 /* Parse the IOCTL response */ 3529 tmp_error = smb2_smb_parse_ioctl(mdp, ioctlp); 3530 if (tmp_error) { 3531 /* IOCTL parsing got an error, try parsing the Close */ 3532 if (!error) { 3533 SMBERROR("smb2_smb_parse_ioctl failed %d id %lld\n", 3534 tmp_error, ioctl_rqp->sr_messageid); 3535 error = tmp_error; 3536 } 3537 goto parse_close; 3538 } 3539 3540parse_close: 3541 /* Update closep fid so it gets freed from FID table */ 3542 closep->fid = createp->ret_fid; 3543 3544 /* Consume any pad bytes */ 3545 tmp_error = smb2_rq_next_command(ioctl_rqp, &next_cmd_offset, mdp); 3546 if (tmp_error) { 3547 /* Failed to find next command, so can't parse rest of the responses */ 3548 SMBERROR("ioctl smb2_rq_next_command failed %d\n", tmp_error); 3549 error = error ? error : tmp_error; 3550 goto bad; 3551 } 3552 3553 /* 3554 * Parse Close SMB 2/3 header 3555 */ 3556 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 3557 closep->ret_ntstatus = close_rqp->sr_ntstatus; 3558 if (tmp_error) { 3559 if (!error) { 3560 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 3561 tmp_error, close_rqp->sr_messageid); 3562 error = tmp_error; 3563 } 3564 goto bad; 3565 } 3566 3567 /* Parse the Close response */ 3568 tmp_error = smb2_smb_parse_close(mdp, closep); 3569 if (tmp_error) { 3570 if (!error) { 3571 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 3572 tmp_error, close_rqp->sr_messageid); 3573 error = tmp_error; 3574 } 3575 goto bad; 3576 } 3577 3578 /* At this point, fid has been removed from fid table */ 3579 need_delete_fid = 0; 3580 3581bad: 3582 if (need_delete_fid == 1) { 3583 /* 3584 * Close failed but the Create worked and was successfully parsed. 3585 * Try issuing the Close request again. 3586 */ 3587 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 3588 NULL, NULL, context); 3589 if (tmp_error) { 3590 SMBERROR("Second close failed %d\n", tmp_error); 3591 } 3592 } 3593 3594 /* Only check for IOCTL errors if the create worked */ 3595 if (create_worked == 1) { 3596 if (ioctl_error) { 3597 SMBDEBUG("smb2_smb_ioctl failed %d ntstatus %d\n", 3598 ioctl_error, ioctlp->ret_ntstatus); 3599 3600 /* Failed to create the symlink, remove the file */ 3601 (void) smb2fs_smb_delete(share, create_np, VREG, 3602 namep, name_len, 3603 0, context); 3604 } 3605 else { 3606 /* IOCTL worked, reset any other fap information */ 3607 fap->fa_size = target_len; 3608 /* FSCTL_SET_REPARSE_POINT succeeded, so mark it as a reparse point */ 3609 fap->fa_attr |= SMB_EFA_REPARSE_POINT; 3610 fap->fa_valid_mask |= FA_REPARSE_TAG_VALID; 3611 fap->fa_reparse_tag = IO_REPARSE_TAG_SYMLINK; 3612 fap->fa_valid_mask |= FA_VTYPE_VALID; 3613 fap->fa_vtype = VLNK; 3614 } 3615 3616 /* 3617 * Windows systems requires special user access to create a reparse symlinks. 3618 * They default to only allow administrator symlink create access. This can 3619 * be changed on the server, but we are going to run into this issue. So if 3620 * we get an access error on the fsctl then we assume this user doesn't have 3621 * create symlink rights and we need to fallback to the old Conrad/Steve 3622 * symlinks. Since the create worked, we know the user has access to the file 3623 * system, they just don't have create symlink rights. We never fallback if 3624 * the server is running darwin. 3625 */ 3626 if ((ioctl_error) && !(UNIX_SERVER(SSTOVC(share)))) { 3627 /* 3628 * <14281932> Could be NetApp server not supporting reparse 3629 * points and returning STATUS_INVALID_DEVICE_REQUEST. 3630 */ 3631 if ((ioctl_error == EACCES) || 3632 (ioctlp->ret_ntstatus == STATUS_INVALID_DEVICE_REQUEST)) { 3633 smp->sm_flags &= ~MNT_SUPPORTS_REPARSE_SYMLINKS; 3634 3635 error = smbfs_smb_create_windows_symlink(share, create_np, 3636 namep, name_len, 3637 targetp, target_len, 3638 fap, context); 3639 if (!error) { 3640 SMBDEBUG("smbfs_smb_create_windows_symlink failed %d\n", error); 3641 } 3642 } 3643 } 3644 } 3645 3646 if (create_rqp != NULL) { 3647 smb_rq_done(create_rqp); 3648 } 3649 if (query_rqp != NULL) { 3650 smb_rq_done(query_rqp); 3651 } 3652 if (ioctl_rqp != NULL) { 3653 smb_rq_done(ioctl_rqp); 3654 } 3655 if (close_rqp != NULL) { 3656 smb_rq_done(close_rqp); 3657 } 3658 3659 if (createp != NULL) { 3660 SMB_FREE(createp, M_SMBTEMP); 3661 } 3662 if (queryp != NULL) { 3663 SMB_FREE(queryp, M_SMBTEMP); 3664 } 3665 if (ioctlp != NULL) { 3666 SMB_FREE(ioctlp, M_SMBTEMP); 3667 } 3668 if (closep != NULL) { 3669 SMB_FREE(closep, M_SMBTEMP); 3670 } 3671 3672 if (pathp != NULL) { 3673 SMB_FREE(pathp, M_TEMP); 3674 } 3675 3676 return error; 3677} 3678 3679int 3680smb2fs_smb_cmpd_resolve_id(struct smb_share *share, struct smbnode *np, 3681 uint64_t ino, uint32_t *resolve_errorp, char **pathp, 3682 vfs_context_t context) 3683{ 3684 int error, tmp_error; 3685 struct smbfattr *fap = NULL; 3686 struct smb2_create_rq *createp = NULL; 3687 struct smb2_close_rq *closep = NULL; 3688 struct smb_rq *create_rqp = NULL; 3689 struct smb_rq *close_rqp = NULL; 3690 struct mdchain *mdp; 3691 size_t next_cmd_offset = 0; 3692 uint32_t need_delete_fid = 0; 3693 SMBFID fid = 0; 3694 struct smb2_create_ctx_resolve_id resolve_id; 3695 uint32_t create_options = 0; 3696 uint32_t disposition = FILE_OPEN; 3697 enum vtype vnode_type = VDIR; 3698 3699 /* 3700 * For this function, vnode_type is VDIR we always do the Resolve ID on the 3701 * root node. The item will be Opened and the Resolve ID will be done on 3702 * it. 3703 */ 3704 3705 SMB_MALLOC(fap, 3706 struct smbfattr *, 3707 sizeof(struct smbfattr), 3708 M_SMBTEMP, 3709 M_WAITOK | M_ZERO); 3710 if (fap == NULL) { 3711 SMBERROR("SMB_MALLOC failed\n"); 3712 error = ENOMEM; 3713 goto bad; 3714 } 3715 3716 /* Fill in Resolve ID context */ 3717 resolve_id.file_id = ino; 3718 resolve_id.ret_errorp = resolve_errorp; 3719 resolve_id.ret_pathp = pathp; 3720 3721resend: 3722 /* 3723 * Build the Create call 3724 */ 3725 create_options = smb2fs_smb_get_create_options(share, np, 3726 NULL, NULL, 3727 vnode_type, 0); 3728 error = smb2fs_smb_ntcreatex(share, np, 3729 NULL, 0, 3730 NULL, 0, 3731 SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, vnode_type, 3732 NTCREATEX_SHARE_ACCESS_ALL, disposition, 3733 SMB2_CREATE_AAPL_RESOLVE_ID, create_options, 3734 &fid, fap, 3735 &create_rqp, &createp, 3736 &resolve_id, context); 3737 if (error) { 3738 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 3739 goto bad; 3740 } 3741 3742 /* Update Create hdr */ 3743 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 3744 if (error) { 3745 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 3746 goto bad; 3747 } 3748 3749 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 3750 3751 /* 3752 * Build the Close request 3753 */ 3754 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 3755 if (error) { 3756 SMBERROR("smb2_smb_close_fid failed %d\n", error); 3757 goto bad; 3758 } 3759 3760 /* Update Close hdr */ 3761 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 3762 if (error) { 3763 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 3764 goto bad; 3765 } 3766 3767 /* Chain Close to the Create */ 3768 create_rqp->sr_next_rqp = close_rqp; 3769 3770 /* 3771 * Send the compound request of Create/Close 3772 */ 3773 error = smb_rq_simple(create_rqp); 3774 3775 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 3776 /* Rebuild and try sending again */ 3777 smb_rq_done(create_rqp); 3778 create_rqp = NULL; 3779 3780 smb_rq_done(close_rqp); 3781 close_rqp = NULL; 3782 3783 SMB_FREE(createp, M_SMBTEMP); 3784 createp = NULL; 3785 3786 SMB_FREE(closep, M_SMBTEMP); 3787 closep = NULL; 3788 3789 goto resend; 3790 } 3791 3792 createp->ret_ntstatus = create_rqp->sr_ntstatus; 3793 3794 /* Get pointer to response data */ 3795 smb_rq_getreply(create_rqp, &mdp); 3796 3797 if (error) { 3798 /* Create failed, try parsing the Close */ 3799 if (error != ENOENT) { 3800 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 3801 error, create_rqp->sr_messageid); 3802 } 3803 goto parse_close; 3804 } 3805 3806 /* 3807 * Parse the Create response. 3808 */ 3809 error = smb2_smb_parse_create(share, mdp, createp); 3810 if (error) { 3811 /* Create parsing failed, try parsing the Close */ 3812 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 3813 error, create_rqp->sr_messageid); 3814 goto parse_close; 3815 } 3816 3817 /* At this point, fid has been entered into fid table */ 3818 need_delete_fid = 1; 3819 3820parse_close: 3821 /* Update closep fid so it gets freed from FID table */ 3822 closep->fid = createp->ret_fid; 3823 3824 /* Consume any pad bytes */ 3825 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 3826 if (tmp_error) { 3827 /* Failed to find next command, so can't parse rest of the responses */ 3828 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 3829 tmp_error, create_rqp->sr_messageid); 3830 error = error ? error : tmp_error; 3831 goto bad; 3832 } 3833 3834 /* 3835 * Parse Close SMB 2/3 header 3836 */ 3837 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 3838 closep->ret_ntstatus = close_rqp->sr_ntstatus; 3839 if (tmp_error) { 3840 if (!error) { 3841 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 3842 tmp_error, close_rqp->sr_messageid); 3843 error = tmp_error; 3844 } 3845 goto bad; 3846 } 3847 3848 /* Parse the Close response */ 3849 tmp_error = smb2_smb_parse_close(mdp, closep); 3850 if (tmp_error) { 3851 if (!error) { 3852 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 3853 tmp_error, close_rqp->sr_messageid); 3854 error = tmp_error; 3855 } 3856 goto bad; 3857 } 3858 3859 /* At this point, fid has been removed from fid table */ 3860 need_delete_fid = 0; 3861 3862bad: 3863 if (need_delete_fid == 1) { 3864 /* 3865 * Close failed but the Create worked and was successfully parsed. 3866 * Try issuing the Close request again. 3867 */ 3868 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 3869 NULL, NULL, context); 3870 if (tmp_error) { 3871 SMBERROR("Second close failed %d\n", tmp_error); 3872 } 3873 } 3874 3875 if (create_rqp != NULL) { 3876 smb_rq_done(create_rqp); 3877 } 3878 if (close_rqp != NULL) { 3879 smb_rq_done(close_rqp); 3880 } 3881 3882 if (createp != NULL) { 3883 SMB_FREE(createp, M_SMBTEMP); 3884 } 3885 if (closep != NULL) { 3886 SMB_FREE(closep, M_SMBTEMP); 3887 } 3888 3889 if (fap != NULL) { 3890 SMB_FREE(fap, M_SMBTEMP); 3891 } 3892 3893 return error; 3894} 3895 3896static int 3897smb2fs_smb_cmpd_set_info(struct smb_share *share, struct smbnode *create_np, enum vtype vnode_type, 3898 const char *create_namep, size_t create_name_len, 3899 uint32_t create_xattr, uint32_t create_desired_access, 3900 uint8_t setinfo_info_type, uint8_t setinfo_file_info_class, 3901 uint32_t setinfo_add_info, 3902 uint32_t setinfo_input_buffer_len, uint8_t *setinfo_input_buffer, 3903 uint32_t *setinfo_ntstatus, 3904 vfs_context_t context) 3905{ 3906#pragma unused(setinfo_input_buffer_len) 3907 int error, tmp_error; 3908 SMBFID fid = 0; 3909 struct smbfattr *fap = NULL; 3910 struct smb2_create_rq *createp = NULL; 3911 struct smb2_set_info_rq *infop = NULL; 3912 struct smb2_close_rq *closep = NULL; 3913 struct smb_rq *create_rqp = NULL; 3914 struct smb_rq *setinfo_rqp = NULL; 3915 struct smb_rq *close_rqp = NULL; 3916 struct mdchain *mdp; 3917 size_t next_cmd_offset = 0; 3918 uint32_t need_delete_fid = 0; 3919 uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL; 3920 uint64_t create_flags = create_xattr ? SMB2_CREATE_IS_NAMED_STREAM : 0; 3921 char *file_namep = NULL, *stream_namep = NULL; 3922 size_t file_name_len = 0, stream_name_len = 0; 3923 uint32_t create_options = 0; 3924 uint32_t disposition = FILE_OPEN; 3925 3926 /* 3927 * For this function, vnode_type is the item's type. The item will be 3928 * Opened and the Set Info will be done on the item. 3929 */ 3930 3931 if ((setinfo_info_type == SMB2_0_INFO_FILE) && 3932 (setinfo_file_info_class == FileDispositionInformation)) { 3933 /* 3934 * <17346821> Must be a Delete. Set share_access to 3935 * NTCREATEX_SHARE_ACCESS_NONE so that we can attempt to delete the 3936 * item right now. 3937 */ 3938 share_access = NTCREATEX_SHARE_ACCESS_NONE; 3939 } 3940 3941 *setinfo_ntstatus = 0; 3942 3943 SMB_MALLOC(fap, 3944 struct smbfattr *, 3945 sizeof(struct smbfattr), 3946 M_SMBTEMP, 3947 M_WAITOK | M_ZERO); 3948 if (fap == NULL) { 3949 SMBERROR("SMB_MALLOC failed\n"); 3950 error = ENOMEM; 3951 goto bad; 3952 } 3953 3954 SMB_MALLOC(infop, 3955 struct smb2_set_info_rq *, 3956 sizeof(struct smb2_set_info_rq), 3957 M_SMBTEMP, 3958 M_WAITOK | M_ZERO); 3959 if (infop == NULL) { 3960 SMBERROR("SMB_MALLOC failed\n"); 3961 error = ENOMEM; 3962 goto bad; 3963 } 3964 3965resend: 3966 /* 3967 * Build the Create call 3968 */ 3969 create_flags |= SMB2_CREATE_GET_MAX_ACCESS; 3970 3971 if (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM)) { 3972 file_namep = (char *) create_namep; 3973 file_name_len = create_name_len; 3974 } 3975 else { 3976 /* create_namep is actually the stream name */ 3977 stream_namep = (char *) create_namep; 3978 stream_name_len = create_name_len; 3979 } 3980 3981 create_options = smb2fs_smb_get_create_options(share, create_np, 3982 file_namep, stream_namep, 3983 vnode_type, 1); 3984 error = smb2fs_smb_ntcreatex(share, create_np, 3985 file_namep, file_name_len, 3986 stream_namep, stream_name_len, 3987 create_desired_access, vnode_type, 3988 share_access, disposition, 3989 create_flags, create_options, 3990 &fid, fap, 3991 &create_rqp, &createp, 3992 NULL, context); 3993 3994 if (error) { 3995 SMBERROR("smb2fs_smb_ntcreatex failed %d\n", error); 3996 goto bad; 3997 } 3998 3999 /* Update Create hdr */ 4000 error = smb2_rq_update_cmpd_hdr(create_rqp, SMB2_CMPD_FIRST); 4001 if (error) { 4002 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 4003 goto bad; 4004 } 4005 4006 /* 4007 * Build the Set Info request 4008 */ 4009 infop->info_type = setinfo_info_type; 4010 infop->file_info_class = setinfo_file_info_class; 4011 infop->add_info = setinfo_add_info; 4012 fid = 0xffffffffffffffff; /* fid is -1 for compound requests */ 4013 infop->fid = fid; 4014 infop->input_buffer = setinfo_input_buffer; 4015 4016 error = smb2_smb_set_info(share, infop, &setinfo_rqp, context); 4017 if (error) { 4018 SMBERROR("smb2_smb_set_info failed %d\n", error); 4019 goto bad; 4020 } 4021 4022 /* Update Set Info hdr */ 4023 error = smb2_rq_update_cmpd_hdr(setinfo_rqp, SMB2_CMPD_MIDDLE); 4024 if (error) { 4025 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 4026 goto bad; 4027 } 4028 4029 /* Chain Set Info to the Create */ 4030 create_rqp->sr_next_rqp = setinfo_rqp; 4031 4032 /* 4033 * Build the Close request 4034 */ 4035 error = smb2_smb_close_fid(share, fid, &close_rqp, &closep, context); 4036 if (error) { 4037 SMBERROR("smb2_smb_close_fid failed %d\n", error); 4038 goto bad; 4039 } 4040 4041 /* Update Close hdr */ 4042 error = smb2_rq_update_cmpd_hdr(close_rqp, SMB2_CMPD_LAST); 4043 if (error) { 4044 SMBERROR("smb2_rq_update_cmpd_hdr failed %d\n", error); 4045 goto bad; 4046 } 4047 4048 /* Chain Close to the Query Info */ 4049 setinfo_rqp->sr_next_rqp = close_rqp; 4050 4051 /* 4052 * Send the compound request of Create/SetInfo/Close 4053 */ 4054 error = smb_rq_simple(create_rqp); 4055 4056 if ((error) && (create_rqp->sr_flags & SMBR_RECONNECTED)) { 4057 /* Rebuild and try sending again */ 4058 smb_rq_done(create_rqp); 4059 create_rqp = NULL; 4060 4061 smb_rq_done(setinfo_rqp); 4062 setinfo_rqp = NULL; 4063 4064 smb_rq_done(close_rqp); 4065 close_rqp = NULL; 4066 4067 SMB_FREE(createp, M_SMBTEMP); 4068 createp = NULL; 4069 4070 SMB_FREE(closep, M_SMBTEMP); 4071 closep = NULL; 4072 4073 goto resend; 4074 } 4075 4076 createp->ret_ntstatus = create_rqp->sr_ntstatus; 4077 4078 /* Get pointer to response data */ 4079 smb_rq_getreply(create_rqp, &mdp); 4080 4081 if (error) { 4082 /* Create failed, try parsing the Set Info */ 4083 if (error != ENOENT) { 4084 SMBDEBUG("smb_rq_simple failed %d id %lld\n", 4085 error, create_rqp->sr_messageid); 4086 } 4087 goto parse_setinfo; 4088 } 4089 4090 /* 4091 * Parse the Create response. 4092 */ 4093 error = smb2_smb_parse_create(share, mdp, createp); 4094 if (error) { 4095 /* Create parsing failed, try parsing the Set Info */ 4096 SMBERROR("smb2_smb_parse_create failed %d id %lld\n", 4097 error, create_rqp->sr_messageid); 4098 goto parse_setinfo; 4099 } 4100 4101 /* At this point, fid has been entered into fid table */ 4102 need_delete_fid = 1; 4103 4104 /* 4105 * Fill in fap and possibly update vnode's meta data caches 4106 */ 4107 error = smb2fs_smb_parse_ntcreatex(share, create_np, createp, 4108 &fid, fap, context); 4109 if (error) { 4110 /* Updating meta data cache failed, try parsing the IOCTL */ 4111 SMBERROR("smb2fs_smb_parse_ntcreatex failed %d id %lld\n", 4112 error, create_rqp->sr_messageid); 4113 } 4114 4115parse_setinfo: 4116 /* Consume any pad bytes */ 4117 tmp_error = smb2_rq_next_command(create_rqp, &next_cmd_offset, mdp); 4118 if (tmp_error) { 4119 /* Failed to find next command, so can't parse rest of the responses */ 4120 SMBERROR("create smb2_rq_next_command failed %d id %lld\n", 4121 tmp_error, create_rqp->sr_messageid); 4122 goto bad; 4123 } 4124 4125 /* 4126 * Parse Set Info SMB 2/3 header 4127 */ 4128 tmp_error = smb2_rq_parse_header(setinfo_rqp, &mdp); 4129 infop->ret_ntstatus = setinfo_rqp->sr_ntstatus; 4130 *setinfo_ntstatus = setinfo_rqp->sr_ntstatus; 4131 if (tmp_error) { 4132 /* Set Info got an error, try parsing the Close */ 4133 if (!error) { 4134 if ((tmp_error != EACCES) && (tmp_error != ENOTEMPTY)) { 4135 SMBDEBUG("setinfo smb2_rq_parse_header failed %d, id %lld\n", 4136 tmp_error, setinfo_rqp->sr_messageid); 4137 } 4138 error = tmp_error; 4139 } 4140 goto parse_close; 4141 } 4142 4143 /* Parse the Set Info response */ 4144 tmp_error = smb2_smb_parse_set_info(mdp, infop); 4145 if (tmp_error) { 4146 /* Query Info parsing got an error, try parsing the Close */ 4147 if (!error) { 4148 if (tmp_error != EACCES) { 4149 SMBERROR("smb2_smb_parse_set_info failed %d id %lld\n", 4150 tmp_error, setinfo_rqp->sr_messageid); 4151 } 4152 error = tmp_error; 4153 } 4154 goto parse_close; 4155 } 4156 4157parse_close: 4158 /* Update closep fid so it gets freed from FID table */ 4159 closep->fid = createp->ret_fid; 4160 4161 /* Consume any pad bytes */ 4162 tmp_error = smb2_rq_next_command(setinfo_rqp, &next_cmd_offset, mdp); 4163 if (tmp_error) { 4164 /* Failed to find next command, so can't parse rest of the responses */ 4165 SMBERROR("setinfo smb2_rq_next_command failed %d\n", tmp_error); 4166 error = error ? error : tmp_error; 4167 goto bad; 4168 } 4169 4170 /* 4171 * Parse Close SMB 2/3 header 4172 */ 4173 tmp_error = smb2_rq_parse_header(close_rqp, &mdp); 4174 closep->ret_ntstatus = close_rqp->sr_ntstatus; 4175 if (tmp_error) { 4176 if (!error) { 4177 SMBDEBUG("close smb2_rq_parse_header failed %d id %lld\n", 4178 tmp_error, close_rqp->sr_messageid); 4179 error = tmp_error; 4180 } 4181 goto bad; 4182 } 4183 4184 /* Parse the Close response */ 4185 tmp_error = smb2_smb_parse_close(mdp, closep); 4186 if (tmp_error) { 4187 if (!error) { 4188 SMBERROR("smb2_smb_parse_close failed %d id %lld\n", 4189 tmp_error, close_rqp->sr_messageid); 4190 error = tmp_error; 4191 } 4192 goto bad; 4193 } 4194 4195 /* At this point, fid has been removed from fid table */ 4196 need_delete_fid = 0; 4197 4198bad: 4199 if (need_delete_fid == 1) { 4200 /* 4201 * Close failed but the Create worked and was successfully parsed. 4202 * Try issuing the Close request again. 4203 */ 4204 tmp_error = smb2_smb_close_fid(share, createp->ret_fid, 4205 NULL, NULL, context); 4206 if (tmp_error) { 4207 SMBERROR("Second close failed %d\n", tmp_error); 4208 } 4209 } 4210 4211 if (create_rqp != NULL) { 4212 smb_rq_done(create_rqp); 4213 } 4214 if (setinfo_rqp != NULL) { 4215 smb_rq_done(setinfo_rqp); 4216 } 4217 if (close_rqp != NULL) { 4218 smb_rq_done(close_rqp); 4219 } 4220 4221 if (createp != NULL) { 4222 SMB_FREE(createp, M_SMBTEMP); 4223 } 4224 if (infop != NULL) { 4225 SMB_FREE(infop, M_SMBTEMP); 4226 } 4227 if (closep != NULL) { 4228 SMB_FREE(closep, M_SMBTEMP); 4229 } 4230 4231 if (fap != NULL) { 4232 SMB_FREE(fap, M_SMBTEMP); 4233 } 4234 4235 return error; 4236} 4237 4238int 4239smb2fs_smb_change_notify(struct smb_share *share, uint32_t output_buffer_len, 4240 uint32_t completion_filter, 4241 void *fn_callback, void *fn_callback_args, 4242 vfs_context_t context) 4243{ 4244 int error; 4245 struct watch_item *watch_item = fn_callback_args; 4246 struct smb2_change_notify_rq *changep = NULL; 4247 uint32_t flags = 0; 4248 4249 SMB_MALLOC(changep, 4250 struct smb2_change_notify_rq *, 4251 sizeof(struct smb2_change_notify_rq), 4252 M_SMBTEMP, 4253 M_WAITOK | M_ZERO); 4254 if (changep == NULL) { 4255 SMBERROR("SMB_MALLOC failed\n"); 4256 error = ENOMEM; 4257 goto bad; 4258 } 4259 4260 /* 4261 * Set up for the Change Notify call 4262 */ 4263 if (watch_item->watchTree) { 4264 flags |= SMB2_WATCH_TREE; 4265 } 4266 changep->flags = flags; 4267 if (watch_item->isServerMsg) { 4268 /* special FID to let server know this is a 4269 * Mac-to-Mac srvmsg notify 4270 */ 4271 changep->fid = 0xffffffffffffffff; 4272 } else { 4273 changep->fid = watch_item->np->d_fid; 4274 } 4275 changep->output_buffer_len = output_buffer_len; 4276 changep->filter = completion_filter; 4277 changep->fn_callback = fn_callback; 4278 changep->fn_callback_args = fn_callback_args; 4279 4280 /* 4281 * Do the Change Notify call 4282 * Save the rqp into watch_item->rqp 4283 */ 4284 error = smb2_smb_change_notify(share, changep, &watch_item->rqp, context); 4285 if (error) { 4286 SMBERROR("smb2_smb_change_notify failed %d\n", error); 4287 goto bad; 4288 } 4289 4290bad: 4291 if (changep != NULL) { 4292 SMB_FREE(changep, M_SMBTEMP); 4293 } 4294 4295 return error; 4296} 4297 4298int 4299smbfs_smb_close(struct smb_share *share, SMBFID fid, vfs_context_t context) 4300{ 4301 int error; 4302 4303 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 4304 error = smb2_smb_close_fid(share, fid, NULL, NULL, context); 4305 } 4306 else { 4307 error = smb1fs_smb_close(share, fid, context); 4308 } 4309 4310 /* 4311 * ENOTCONN isn't interesting - if the connection is closed, 4312 * so are all our FIDs - and ENXIO is also not interesting, 4313 * as it means a forced unmount was done. 4314 * 4315 * EBADF means the fid is no longer good. Reconnect will make this happen. 4316 * Should we check to see if the open was broken on the reconnect or does it 4317 * really matter? 4318 * 4319 * Don't clog up the system log with warnings about those failures 4320 * on closes. 4321 */ 4322 if ((error == ENOTCONN) || (error == ENXIO) || (error == EBADF)) { 4323 error = 0; 4324 } 4325 4326 return error; 4327} 4328 4329/* 4330 * This routine is used for both Mac-to-Mac and Mac-to-Windows copyfile 4331 * operations. For Mac-to-Mac, the FSCTL_SRV_COPYCHUNK ioctl is sent with 4332 * a chunk count of zero, because the server uses copyfile(3) and doesn't need 4333 * a list of chunks from the client. To specify Mac-to-Mac semantics, the 4334 * mac_to_mac parameter should be set to TRUE. 4335 */ 4336static int 4337smb2fs_smb_copychunks(struct smb_share *share, SMBFID src_fid, 4338 SMBFID targ_fid, uint64_t src_file_len, 4339 int mac_to_mac, vfs_context_t context) 4340{ 4341 struct smb2_ioctl_rq *ioctlp = NULL; 4342 struct smb2_copychunk *copychunk_hdr; 4343 struct smb2_copychunk_chunk *copychunk_element; 4344 struct smb2_copychunk_result *copychunk_result; 4345 char *sendbuf = NULL; 4346 uint32_t sendbuf_len, src_offset, chunk_count; 4347 uint32_t max_chunk_len, retry; 4348 uint64_t remaining_len, this_len; 4349 u_char resume_key[SMB2_RESUME_KEY_LEN]; 4350 int error = 0; 4351 4352 /* Allocate a copychunk header with an array of chunk elements */ 4353 sendbuf_len = sizeof(struct smb2_copychunk) + 4354 (sizeof(struct smb2_copychunk_chunk) * SMB2_COPYCHUNK_ARR_SIZE); 4355 4356 /* setup a send buffer for the copychunk headers */ 4357 SMB_MALLOC(sendbuf, 4358 char *, 4359 sendbuf_len, 4360 M_SMBTEMP, 4361 M_WAITOK | M_ZERO); 4362 if (sendbuf == NULL) { 4363 SMBERROR("SMB_MALLOC failed\n"); 4364 error = ENOMEM; 4365 goto out; 4366 } 4367 4368 /* Begin by getting a resume key from the source */ 4369 error = smb2fs_smb_request_resume_key(share, src_fid, resume_key, context); 4370 4371 if (error) { 4372 SMBERROR("Failed to get resume key, error: %d\n", error); 4373 goto out; 4374 } 4375 4376 /* 4377 * Build the IOCTL request 4378 */ 4379 SMB_MALLOC(ioctlp, 4380 struct smb2_ioctl_rq *, 4381 sizeof(struct smb2_ioctl_rq), 4382 M_SMBTEMP, 4383 M_WAITOK | M_ZERO); 4384 if (ioctlp == NULL) { 4385 SMBERROR("SMB_MALLOC failed\n"); 4386 error = ENOMEM; 4387 goto out; 4388 } 4389 4390 /* We will initialize ioctlp->snd_input_len later */ 4391 ioctlp->share = share; 4392 ioctlp->ctl_code = FSCTL_SRV_COPYCHUNK; 4393 ioctlp->fid = targ_fid; 4394 ioctlp->snd_input_buffer = (uint8_t *)sendbuf; 4395 ioctlp->rcv_output_len = sizeof(struct smb2_copychunk_result); 4396 4397 copychunk_hdr = (struct smb2_copychunk *)sendbuf; 4398 4399 /* setup copy chunk hdr */ 4400 memcpy(copychunk_hdr->source_key, resume_key, SMB2_RESUME_KEY_LEN); 4401 copychunk_hdr->reserved = 0; 4402 4403 if (mac_to_mac == TRUE) { 4404 /* Mac-to-Mac case */ 4405 4406 /* Just a header, no chunks */ 4407 ioctlp->snd_input_len = sizeof(struct smb2_copychunk); 4408 4409 copychunk_hdr->chunk_count = 0; 4410 4411 error = smb2_smb_ioctl(share, ioctlp, NULL, context); 4412 4413 if (error) { 4414 SMBDEBUG("smb2_smb_ioctl error: %d\n", error); 4415 goto out; 4416 } 4417 4418 /* sanity check */ 4419 if (ioctlp->rcv_output_len < sizeof(struct smb2_copychunk_result)) { 4420 /* big problem, response too small, nothing we can do */ 4421 SMBERROR("rcv_output_buffer too small, expected: %lu, got: %u\n", 4422 sizeof(struct smb2_copychunk_result), ioctlp->rcv_output_len); 4423 error = EINVAL; 4424 goto out; 4425 } 4426 4427 // Check results 4428 if (ioctlp->ret_ntstatus != STATUS_SUCCESS) { 4429 SMBDEBUG("copychunk result: nt_stat: 0x%0x\n", ioctlp->ret_ntstatus); 4430 4431 /* map the nt_status to an errno */ 4432 error = smb_ntstatus_to_errno(ioctlp->ret_ntstatus); 4433 goto out; 4434 } 4435 } else { 4436 /* Non Mac-to-Mac case */ 4437 4438 retry = 0; 4439 copychunk_element = (struct smb2_copychunk_chunk *)(sendbuf + sizeof(struct smb2_copychunk)); 4440 max_chunk_len = SMB2_COPYCHUNK_MAX_CHUNK_LEN; 4441 4442again: 4443 remaining_len = src_file_len; 4444 src_offset = 0; 4445 while (remaining_len) { 4446 4447 /* Fillup the chunk array */ 4448 error = smb2fs_smb_fillchunk_arr(copychunk_element, 4449 SMB2_COPYCHUNK_ARR_SIZE, 4450 remaining_len, max_chunk_len, 4451 src_offset, src_offset, 4452 &chunk_count, &this_len); 4453 if (error) { 4454 goto out; 4455 } 4456 4457 remaining_len -= this_len; 4458 src_offset += this_len; 4459 copychunk_hdr->chunk_count = chunk_count; 4460 4461 /* snd_input_len depends on how many chunks we're sending */ 4462 ioctlp->snd_input_len = sizeof(struct smb2_copychunk) + 4463 (sizeof(struct smb2_copychunk_chunk) * chunk_count); 4464 4465 error = smb2_smb_ioctl(share, ioctlp, NULL, context); 4466 4467 if (error) { 4468 SMBDEBUG("smb2_smb_ioctl error: %d, remain: %llu, max_chunk: %u, count: %u, this_len: %llu\n", 4469 error, remaining_len, max_chunk_len, chunk_count, this_len); 4470 4471 if (ioctlp->ret_ntstatus != STATUS_INVALID_PARAMETER) { 4472 goto out; 4473 } 4474 } 4475 4476 /* sanity check */ 4477 if ( (ioctlp->rcv_output_len < sizeof(struct smb2_copychunk_result)) || 4478 (ioctlp->rcv_output_buffer == NULL) ) { 4479 /* big problem, response too small, nothing we can do */ 4480 SMBERROR("rcv_output_buffer too small, expected: %lu, got: %u\n", 4481 sizeof(struct smb2_copychunk_result), ioctlp->rcv_output_len); 4482 error = EINVAL; 4483 goto out; 4484 } 4485 4486 // Check results 4487 copychunk_result = (struct smb2_copychunk_result *)ioctlp->rcv_output_buffer; 4488 4489 if (ioctlp->ret_ntstatus == STATUS_INVALID_PARAMETER && !retry) { 4490 /* 4491 * Exceeded server's maximum chunk length. We will try 4492 * once more using the server's value, which is 4493 * returned by the server in chunk_bytes_written. 4494 * See <rdar://problem/14750992>. 4495 */ 4496 4497 if (copychunk_result->chunk_bytes_written < max_chunk_len) { 4498 max_chunk_len = copychunk_result->chunk_bytes_written; 4499 retry = 1; 4500 4501 SMB_FREE(ioctlp->rcv_output_buffer, M_SMBTEMP); 4502 goto again; 4503 } 4504 } 4505 4506 if (ioctlp->ret_ntstatus != STATUS_SUCCESS) { 4507 SMBDEBUG("smb2_smb_ioctl result: nt_stat: 0x%0x\n", ioctlp->ret_ntstatus); 4508 4509 /* map the nt_status to an errno */ 4510 error = smb_ntstatus_to_errno(ioctlp->ret_ntstatus); 4511 goto out; 4512 } 4513 4514 if (copychunk_result->chunks_written != copychunk_hdr->chunk_count) { 4515 SMBERROR("copychunk error: chunks_written: %u, expected: %u\n", 4516 copychunk_result->chunks_written, copychunk_hdr->chunk_count); 4517 error = EIO; 4518 goto out; 4519 } 4520 4521 if (copychunk_result->total_bytes_written != this_len) { 4522 SMBERROR("copychunk error: total_bytes_written: %u, expected: %llu\n", 4523 copychunk_result->total_bytes_written, this_len); 4524 error = EIO; 4525 goto out; 4526 } 4527 4528 SMB_FREE(ioctlp->rcv_output_buffer, M_SMBTEMP); 4529 } 4530 } 4531out: 4532 // clean house 4533 if (sendbuf != NULL) { 4534 SMB_FREE(sendbuf, M_SMBTEMP); 4535 } 4536 4537 if (ioctlp != NULL) { 4538 if (ioctlp->rcv_output_buffer != NULL) { 4539 SMB_FREE(ioctlp->rcv_output_buffer, M_SMBTEMP); 4540 } 4541 4542 SMB_FREE(ioctlp, M_SMBTEMP); 4543 } 4544 4545 return (error); 4546} 4547 4548int 4549smb2fs_smb_copyfile(struct smb_share *share, struct smbnode *src_np, 4550 struct smbnode *tdnp, const char *tnamep, 4551 size_t tname_len, vfs_context_t context) 4552{ 4553 struct smbfattr *sfap = NULL, *tfap = NULL; 4554 char *xattr_list = NULL, *xattrp = NULL; 4555 SMBFID src_fid = 0, targ_fid = 0, src_xattr_fid = 0, targ_xattr_fid = 0; 4556 size_t xattrlist_len = 0, remaining_len = 0, this_len; 4557 uint32_t desired_access, share_access, disp; 4558 boolean_t src_is_open = FALSE, targ_is_open = FALSE; 4559 boolean_t srcxattr_is_open = FALSE, targxattr_is_open = FALSE; 4560 uint64_t create_flags, src_file_len; 4561 struct timespec mtime; 4562 int error = 0; 4563 uint32_t ntstatus = 0; 4564 uint32_t target_created = 0; 4565 uint32_t create_options = 0; 4566 enum vtype vnode_type = VREG; 4567 4568 if ((SSTOVC(share)->vc_misc_flags & SMBV_OSX_SERVER) && 4569 (SSTOVC(share)->vc_server_caps & kAAPL_SUPPORTS_OSX_COPYFILE)) { 4570 /* Mac-to-Mac copyfile */ 4571 return smb2fs_smb_copyfile_mac(share, src_np, 4572 tdnp, tnamep, 4573 tname_len, context); 4574 } 4575 4576 /* We'll need a couple of fattrs */ 4577 SMB_MALLOC(sfap, 4578 struct smbfattr *, 4579 sizeof(struct smbfattr), 4580 M_SMBTEMP, 4581 M_WAITOK | M_ZERO); 4582 if (sfap == NULL) { 4583 SMBERROR("SMB_MALLOC failed, sfap\n"); 4584 error = ENOMEM; 4585 goto out; 4586 } 4587 4588 SMB_MALLOC(tfap, 4589 struct smbfattr *, 4590 sizeof(struct smbfattr), 4591 M_SMBTEMP, 4592 M_WAITOK | M_ZERO); 4593 if (tfap == NULL) { 4594 SMBERROR("SMB_MALLOC failed, tfap\n"); 4595 error = ENOMEM; 4596 goto out; 4597 } 4598 4599 /*******************************/ 4600 /* Get list of src file xattrs */ 4601 /*******************************/ 4602 if (share->ss_attributes & FILE_NAMED_STREAMS) { 4603 error = smb2fs_smb_listxattrs(share, src_np, &xattr_list, 4604 &xattrlist_len, context); 4605 if (error) { 4606 SMBDEBUG("listxattrs failed, error: %d\n", error); 4607 goto out; 4608 } 4609 } 4610 4611 /********************/ 4612 /* Open source file */ 4613 /********************/ 4614 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA; 4615 share_access = NTCREATEX_SHARE_ACCESS_READ; 4616 disp = FILE_OPEN; 4617 create_flags = 0; 4618 4619 create_options = smb2fs_smb_get_create_options(share, src_np, 4620 NULL, NULL, 4621 vnode_type, 0); 4622 error = smb2fs_smb_ntcreatex(share, src_np, 4623 NULL, 0, 4624 NULL, 0, 4625 desired_access, vnode_type, 4626 share_access, disp, 4627 create_flags, create_options, 4628 &src_fid, sfap, 4629 NULL, NULL, 4630 NULL, context); 4631 4632 if (error) { 4633 SMBDEBUG("smb2fs_smb_ntcreatex failed (src file) %d\n", error); 4634 goto out; 4635 } 4636 4637 src_is_open = TRUE; 4638 src_file_len = sfap->fa_size; 4639 4640 /***************************/ 4641 /* Open/Create target file */ 4642 /***************************/ 4643 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA | 4644 SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_FILE_WRITE_EA; 4645 disp = FILE_OVERWRITE_IF; 4646 create_flags = SMB2_CREATE_DO_CREATE; 4647 share_access = 0; /* No Access */ 4648 4649 /* Do a Create */ 4650 error = smb2fs_smb_cmpd_create(share, tdnp, 4651 tnamep, tname_len, 4652 NULL, 0, 4653 desired_access, VREG, 4654 share_access, disp, 4655 create_flags, &ntstatus, 4656 &targ_fid, tfap, 4657 NULL, context); 4658 4659 if (error) { 4660 SMBDEBUG("smb2fs_smb_ntcreatex failed (targ file) %d\n", error); 4661 goto out; 4662 } 4663 4664 targ_is_open = TRUE; 4665 target_created = 1; 4666 4667 /*************************************/ 4668 /* Now initiate the server-side copy */ 4669 /*************************************/ 4670 error = smb2fs_smb_copychunks(share, src_fid, 4671 targ_fid, src_file_len, 4672 FALSE, context); 4673 4674 if (error) { 4675 SMBDEBUG("smb2fs_smb_copychunks failed (file data) %d\n", error); 4676 goto out; 4677 } 4678 4679 /********************************/ 4680 /* Set metadata of target file. */ 4681 /********************************/ 4682 4683 /* Set EOF of target file */ 4684 error = smb2fs_smb_set_eof(share, targ_fid, src_file_len, context); 4685 if (error) { 4686 SMBDEBUG("failed setting target eof, error: %d\n", error); 4687 goto out; 4688 } 4689 4690 /* 4691 * Set LastWriteTime timestamp of target file. 4692 * 4693 * Note: Windows clients will also set LastChangeTime here, 4694 * but we don't allow anyone to set the change time. 4695 */ 4696 nanotime(&mtime); 4697 error = smbfs_smb_setfattrNT(share, 0, targ_fid, NULL, &mtime, NULL, context); 4698 if (error) { 4699 SMBDEBUG("failed setting mtime: %d\n", error); 4700 goto out; 4701 } 4702 4703 /*********************************/ 4704 /* Close source and target files */ 4705 /*********************************/ 4706 smb2_smb_close_fid(share, src_fid, NULL, NULL, context); 4707 smb2_smb_close_fid(share, targ_fid, NULL, NULL, context); 4708 src_is_open = FALSE; 4709 targ_is_open = FALSE; 4710 4711 /*******************************/ 4712 /* Copy named streams (if any) */ 4713 /*******************************/ 4714 xattrp = xattr_list; 4715 remaining_len = xattrlist_len; 4716 while (remaining_len) { 4717 this_len = strnlen(xattrp, xattrlist_len); 4718 4719 /********************************************/ 4720 /* Open src_xattr, Open/Create target xattr */ 4721 /********************************************/ 4722 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA; 4723 share_access = NTCREATEX_SHARE_ACCESS_READ; 4724 disp = FILE_OPEN; 4725 create_flags = SMB2_CREATE_IS_NAMED_STREAM; 4726 4727 create_options = smb2fs_smb_get_create_options(share, src_np, 4728 NULL, xattrp, 4729 vnode_type, 0); 4730 error = smb2fs_smb_ntcreatex(share, src_np, 4731 NULL, 0, 4732 xattrp, this_len, 4733 desired_access, vnode_type, 4734 share_access, disp, 4735 create_flags, create_options, 4736 &src_xattr_fid, sfap, 4737 NULL, NULL, 4738 NULL, context); 4739 if (error) { 4740 SMBDEBUG("smb2fs_smb_ntcreatex failed (src xattr), error: %d\n", error); 4741 goto out; 4742 } 4743 4744 srcxattr_is_open = TRUE; 4745 src_file_len = sfap->fa_size; 4746 4747 /* Open/Create target file xattr */ 4748 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA | 4749 SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_FILE_WRITE_EA; 4750 disp = FILE_OVERWRITE_IF; 4751 create_flags = SMB2_CREATE_IS_NAMED_STREAM | SMB2_CREATE_DO_CREATE; 4752 share_access = 0; /* No Access */ 4753 4754 /* Do a Create */ 4755 error = smb2fs_smb_cmpd_create(share, tdnp, 4756 tnamep, tname_len, 4757 xattrp, this_len, 4758 desired_access, VREG, 4759 share_access, disp, 4760 create_flags, &ntstatus, 4761 &targ_xattr_fid, tfap, 4762 NULL, context); 4763 4764 if (error) { 4765 SMBDEBUG("smb2fs_smb_ntcreatex failed (targ xattr), error: %d\n", error); 4766 goto out; 4767 } 4768 4769 targxattr_is_open = TRUE; 4770 4771 /*************************************/ 4772 /* Now initiate the server-side copy */ 4773 /*************************************/ 4774 error = smb2fs_smb_copychunks(share, src_xattr_fid, 4775 targ_xattr_fid, src_file_len, 4776 FALSE, context); 4777 4778 if (error) { 4779 SMBDEBUG("smb2fs_smb_copychunks failed (xattr), error: %d\n", error); 4780 goto out; 4781 } 4782 4783 /*********************************/ 4784 /* Set metadata of target xattr. */ 4785 /*********************************/ 4786 4787 /* Set EOF */ 4788 error = smb2fs_smb_set_eof(share, targ_xattr_fid, src_file_len, context); 4789 if (error) { 4790 SMBDEBUG("failed setting target xattr eof, error: %d\n", error); 4791 goto out; 4792 } 4793 4794 /* 4795 * Set LastWriteTime timestamp of target file. 4796 * 4797 * Note: Windows clients will also set LastChangeTime here, 4798 * but we don't allow anyone to set the change time. 4799 */ 4800 nanotime(&mtime); 4801 error = smbfs_smb_setfattrNT(share, 0, targ_xattr_fid, NULL, &mtime, NULL, context); 4802 if (error) { 4803 SMBDEBUG("failed setting xattr mtime: %d\n", error); 4804 goto out; 4805 } 4806 4807 /**********************************/ 4808 /* Close source and target xattrs */ 4809 /**********************************/ 4810 smb2_smb_close_fid(share, src_xattr_fid, NULL, NULL, context); 4811 smb2_smb_close_fid(share, targ_xattr_fid, NULL, NULL, context); 4812 srcxattr_is_open = FALSE; 4813 targxattr_is_open = FALSE; 4814 4815 /* Skip over terminating NULL, advance to next xattr name */ 4816 this_len += 1; 4817 remaining_len -= this_len; 4818 if (xattrlist_len) { 4819 xattrp += this_len; 4820 } 4821 } 4822 4823out: 4824 /* Clean house */ 4825 if (src_is_open == TRUE) { 4826 smb2_smb_close_fid(share, src_fid, NULL, NULL, context); 4827 } 4828 4829 if (srcxattr_is_open == TRUE) { 4830 smb2_smb_close_fid(share, src_xattr_fid, NULL, NULL, context); 4831 } 4832 4833 if (targ_is_open == TRUE) { 4834 smb2_smb_close_fid(share, targ_fid, NULL, NULL, context); 4835 } 4836 4837 if (targxattr_is_open == TRUE) { 4838 smb2_smb_close_fid(share, targ_xattr_fid, NULL, NULL, context); 4839 } 4840 4841 if (xattr_list != NULL) { 4842 SMB_FREE(xattr_list, M_SMBTEMP); 4843 } 4844 4845 if (sfap != NULL) { 4846 SMB_FREE(sfap, M_SMBTEMP); 4847 } 4848 4849 if (tfap != NULL) { 4850 SMB_FREE(tfap, M_SMBTEMP); 4851 } 4852 4853 if ((error) && (target_created == 1)) { 4854 /* Try to delete the target file we created */ 4855 smbfs_smb_delete(share, tdnp, VREG, 4856 tnamep, tname_len, 4857 0, context); 4858 } 4859 4860 return error; 4861} 4862 4863static int 4864smb2fs_smb_copyfile_mac(struct smb_share *share, struct smbnode *src_np, 4865 struct smbnode *tdnp, const char *tnamep, size_t tname_len, 4866 vfs_context_t context) 4867{ 4868 struct smbfattr *sfap = NULL, *tfap = NULL; 4869 SMBFID src_fid = 0, targ_fid = 0; 4870 uint32_t desired_access, share_access, disp; 4871 boolean_t src_is_open = FALSE, targ_is_open = FALSE; 4872 uint64_t create_flags; 4873 int error = 0; 4874 uint32_t ntstatus = 0; 4875 uint32_t target_created = 0; 4876 uint32_t create_options = 0; 4877 enum vtype vnode_type = VREG; 4878 4879 /* We'll need a couple of fattrs */ 4880 SMB_MALLOC(sfap, 4881 struct smbfattr *, 4882 sizeof(struct smbfattr), 4883 M_SMBTEMP, 4884 M_WAITOK | M_ZERO); 4885 if (sfap == NULL) { 4886 SMBERROR("SMB_MALLOC failed, sfap\n"); 4887 error = ENOMEM; 4888 goto out; 4889 } 4890 4891 SMB_MALLOC(tfap, 4892 struct smbfattr *, 4893 sizeof(struct smbfattr), 4894 M_SMBTEMP, 4895 M_WAITOK | M_ZERO); 4896 if (tfap == NULL) { 4897 SMBERROR("SMB_MALLOC failed, tfap\n"); 4898 error = ENOMEM; 4899 goto out; 4900 } 4901 4902 /*********************************************/ 4903 /* Open source file, Open/Create target file */ 4904 /*********************************************/ 4905 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA; 4906 share_access = NTCREATEX_SHARE_ACCESS_READ; 4907 disp = FILE_OPEN; 4908 create_flags = 0; 4909 4910 create_options = smb2fs_smb_get_create_options(share, src_np, 4911 NULL, NULL, 4912 vnode_type, 0); 4913 error = smb2fs_smb_ntcreatex(share, src_np, 4914 NULL, 0, 4915 NULL, 0, 4916 desired_access, vnode_type, 4917 share_access, disp, 4918 create_flags, create_options, 4919 &src_fid, sfap, 4920 NULL, NULL, 4921 NULL, context); 4922 4923 if (error) { 4924 SMBDEBUG("smb2fs_smb_ntcreatex failed (src file) %d\n", error); 4925 goto out; 4926 } 4927 4928 src_is_open = TRUE; 4929 4930 /***************************/ 4931 /* Open/Create target file */ 4932 /***************************/ 4933 desired_access = SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA | 4934 SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_ATTRIBUTES | SMB2_FILE_WRITE_EA; 4935 disp = FILE_OVERWRITE_IF; 4936 create_flags = SMB2_CREATE_DO_CREATE; 4937 share_access = 0; /* No Access */ 4938 4939 /* Do a Create */ 4940 error = smb2fs_smb_cmpd_create(share, tdnp, 4941 tnamep, tname_len, 4942 NULL, 0, 4943 desired_access, VREG, 4944 share_access, disp, 4945 create_flags, &ntstatus, 4946 &targ_fid, tfap, 4947 NULL, context); 4948 4949 if (error) { 4950 SMBDEBUG("smb2fs_smb_ntcreatex failed (targ file) %d\n", error); 4951 goto out; 4952 } 4953 4954 targ_is_open = TRUE; 4955 target_created = 1; 4956 4957 /*************************************/ 4958 /* Now initiate the server-side copy */ 4959 /*************************************/ 4960 error = smb2fs_smb_copychunks(share, src_fid, 4961 targ_fid, 0, 4962 TRUE, context); 4963 4964 if (error) { 4965 SMBDEBUG("smb2fs_smb_copychunks_mac failed (file data) %d\n", error); 4966 goto out; 4967 } 4968 4969 /*********************************/ 4970 /* Close source and target files */ 4971 /*********************************/ 4972 smb2_smb_close_fid(share, src_fid, NULL, NULL, context); 4973 smb2_smb_close_fid(share, targ_fid, NULL, NULL, context); 4974 src_is_open = FALSE; 4975 targ_is_open = FALSE; 4976 4977out: 4978 /* Clean house */ 4979 if (src_is_open == TRUE) { 4980 smb2_smb_close_fid(share, src_fid, NULL, NULL, context); 4981 } 4982 4983 if (targ_is_open == TRUE) { 4984 smb2_smb_close_fid(share, targ_fid, NULL, NULL, context); 4985 } 4986 4987 if (sfap != NULL) { 4988 SMB_FREE(sfap, M_SMBTEMP); 4989 } 4990 4991 if (tfap != NULL) { 4992 SMB_FREE(tfap, M_SMBTEMP); 4993 } 4994 4995 if ((error) && (target_created == 1)) { 4996 /* Try to delete the target file we created */ 4997 smbfs_smb_delete(share, tdnp, VREG, 4998 tnamep, tname_len, 4999 0, context); 5000 } 5001 5002 return error; 5003} 5004 5005int 5006smbfs_smb_create_reparse_symlink(struct smb_share *share, struct smbnode *dnp, 5007 const char *namep, size_t name_len, 5008 char *targetp, size_t target_len, 5009 struct smbfattr *fap, vfs_context_t context) 5010{ 5011 int error; 5012 5013 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5014 error = smb2fs_smb_cmpd_reparse_point_set(share, dnp, 5015 namep, name_len, 5016 targetp, target_len, 5017 fap, context); 5018 } 5019 else { 5020 error = smb1fs_smb_create_reparse_symlink(share, dnp, 5021 namep, name_len, 5022 targetp, target_len, 5023 fap, context); 5024 } 5025 5026 return error; 5027 5028} 5029 5030static int 5031smb2fs_smb_delete(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 5032 const char *namep, size_t name_len, 5033 int xattr, vfs_context_t context) 5034{ 5035 int error; 5036 uint32_t setinfo_ntstatus; 5037 uint8_t delete_byte = 1; 5038 5039 /* 5040 * Looking at Win <-> Win with SMB 2/3, delete is handled by opening the file 5041 * with Delete and "Read Attributes", then a Set Info is done to set 5042 * "Delete on close", then a Close is sent. 5043 */ 5044 5045 /* 5046 * Do the Compound Create/SetInfo/Close call 5047 */ 5048 error = smb2fs_smb_cmpd_set_info(share, np, vnode_type, 5049 namep, name_len, 5050 xattr, SMB2_FILE_READ_ATTRIBUTES | SMB2_STD_ACCESS_DELETE | SMB2_SYNCHRONIZE, 5051 SMB2_0_INFO_FILE, FileDispositionInformation, 5052 0, 5053 sizeof (delete_byte), (uint8_t *) &delete_byte, 5054 &setinfo_ntstatus, 5055 context); 5056 if (error) { 5057 if (error != ENOTEMPTY) { 5058 SMBDEBUG_LOCK(np, "smb2fs_smb_cmpd_set_info failed %d %s:%s\n", error, np->n_name, namep); 5059 } 5060 goto bad; 5061 } 5062 5063bad: 5064 return error; 5065} 5066 5067/* 5068 * The calling routine must hold a reference on the share 5069 */ 5070int 5071smbfs_smb_delete(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 5072 const char *name, size_t nmlen, 5073 int xattr, vfs_context_t context) 5074{ 5075 int error; 5076 5077 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5078 error = smb2fs_smb_delete (share, np, vnode_type, 5079 name, nmlen, 5080 xattr, context); 5081 } 5082 else { 5083 error = smb1fs_smb_delete (share, np, name, nmlen, xattr, context); 5084 } 5085 5086 return error; 5087} 5088 5089static uint32_t 5090smb2fs_smb_fillchunk_arr(struct smb2_copychunk_chunk *chunk_arr, 5091 uint32_t chunk_arr_size, 5092 uint64_t total_len, uint32_t max_chunk_len, 5093 uint64_t src_offset, uint64_t trg_offset, 5094 uint32_t *chunk_count_out, uint64_t *total_len_out) 5095{ 5096 uint64_t len_remaining = total_len; 5097 uint64_t total_chunk_len, src_off, trg_off; 5098 uint32_t i, chunk_count, this_chunk_len; 5099 5100 src_off = src_offset; 5101 trg_off = trg_offset; 5102 5103 chunk_count = 0; 5104 total_chunk_len = 0; 5105 for (i = 0; i < chunk_arr_size; i++) { 5106 if (!len_remaining) { 5107 // all done 5108 break; 5109 } 5110 5111 if (len_remaining > max_chunk_len) { 5112 this_chunk_len = max_chunk_len; 5113 } 5114 else { 5115 /* Cast is fine, here */ 5116 this_chunk_len = (uint32_t)len_remaining; 5117 } 5118 5119 chunk_arr[i].length = this_chunk_len; 5120 chunk_arr[i].reserved = 0; 5121 chunk_arr[i].source_offset = src_off; 5122 chunk_arr[i].target_offset = trg_off; 5123 5124 total_chunk_len += this_chunk_len; 5125 len_remaining -= this_chunk_len; 5126 chunk_count++; 5127 src_off += this_chunk_len; 5128 trg_off += this_chunk_len; 5129 } 5130 5131 *chunk_count_out = chunk_count; 5132 *total_len_out = total_chunk_len; 5133 return (0); 5134} 5135 5136int 5137smbfs_smb_findclose(struct smbfs_fctx *ctx, vfs_context_t context) 5138{ 5139 int error; 5140 5141 if (SSTOVC(ctx->f_share)->vc_flags & SMBV_SMB2) { 5142 if (ctx->f_create_rqp) { 5143 smb_rq_done(ctx->f_create_rqp); 5144 ctx->f_create_rqp = NULL; 5145 } 5146 if (ctx->f_query_rqp) { 5147 smb_rq_done(ctx->f_query_rqp); 5148 ctx->f_query_rqp = NULL; 5149 } 5150 5151 /* Close Create FID if we need to */ 5152 if (ctx->f_need_close == TRUE) { 5153 error = smb2_smb_close_fid(ctx->f_share, ctx->f_create_fid, 5154 NULL, NULL, context); 5155 if (error) { 5156 SMBDEBUG("smb2_smb_close_fid failed %d\n", error); 5157 } 5158 ctx->f_need_close = FALSE; 5159 } 5160 5161 /* We are done with the share release our reference */ 5162 smb_share_rele(ctx->f_share, context); 5163 5164 if (ctx->f_LocalName) { 5165 SMB_FREE(ctx->f_LocalName, M_SMBFSDATA); 5166 } 5167 5168 if (ctx->f_NetworkNameBuffer) { 5169 SMB_FREE(ctx->f_NetworkNameBuffer, M_SMBFSDATA); 5170 } 5171 5172 if (ctx->f_rname) { 5173 SMB_FREE(ctx->f_rname, M_SMBFSDATA); 5174 } 5175 5176 SMB_FREE(ctx, M_SMBFSDATA); 5177 return 0; 5178 } 5179 else { 5180 error = smb1fs_smb_findclose(ctx, context); 5181 return (error); 5182 } 5183 5184} 5185 5186static int 5187smb2fs_smb_findnext(struct smbfs_fctx *ctx, vfs_context_t context) 5188{ 5189 struct timespec ts; 5190 int error = EINVAL; 5191 struct mdchain *mdp; 5192 struct smb2_query_dir_rq *queryp = NULL; 5193 uint8_t info_class, flags; 5194 uint32_t file_index; 5195 int attempts = 0; 5196 5197 SMB_MALLOC(queryp, 5198 struct smb2_query_dir_rq *, 5199 sizeof(struct smb2_query_dir_rq), 5200 M_SMBTEMP, 5201 M_WAITOK | M_ZERO); 5202 if (queryp == NULL) { 5203 SMBERROR("SMB_MALLOC failed\n"); 5204 error = ENOMEM; 5205 goto bad; 5206 } 5207 5208 if (ctx->f_output_buf_len == 0) { 5209 /* 5210 * if no more output buffer bytes to parse, then we have finished 5211 * parsing out all the entries from this search. 5212 */ 5213 if (ctx->f_flags & SMBFS_RDD_EOF) { 5214 error = ENOENT; 5215 goto bad; 5216 } 5217 5218 nanouptime(&ts); 5219 5220 /* free any previous search requests */ 5221 if (ctx->f_create_rqp) { 5222 smb_rq_done(ctx->f_create_rqp); 5223 ctx->f_create_rqp = NULL; 5224 } 5225 if (ctx->f_query_rqp) { 5226 smb_rq_done(ctx->f_query_rqp); 5227 ctx->f_query_rqp = NULL; 5228 } 5229 5230 /* Clear resume file name */ 5231 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 5232 5233 /* Is the dir already open? */ 5234 if (ctx->f_need_close == FALSE) { 5235 /* 5236 * Dir needs to be opened first so do a Create/Query Dir 5237 * fid is -1 for compound requests 5238 */ 5239 ctx->f_create_fid = 0xffffffffffffffff; 5240 } 5241 5242 /* 5243 * Set up for the Query Dir call 5244 */ 5245 5246 /* If not a wildcard search, then want first search entry returned */ 5247 flags = 0; 5248 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 5249 flags |= SMB2_RETURN_SINGLE_ENTRY; 5250 } 5251 5252 /* Resuming a search happens by default, no need to use File Index */ 5253 file_index = 0; 5254 5255 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 5256 /* Because this is first search, set some flags */ 5257 flags |= SMB2_RESTART_SCANS; /* start search from beginning */ 5258 file_index = 0; /* no FileIndex from prev search */ 5259 } 5260 5261 switch (ctx->f_infolevel) { 5262 case SMB_FIND_FULL_DIRECTORY_INFO: 5263 /* For SMB 2/3, get the file/dir IDs too but no short names */ 5264 info_class = FileIdFullDirectoryInformation; 5265 break; 5266 5267 case SMB_FIND_BOTH_DIRECTORY_INFO: 5268 /* For SMB 2/3, get the file/dir IDs too */ 5269 info_class = FileIdBothDirectoryInformation; 5270 break; 5271 5272 default: 5273 SMBERROR("invalid infolevel %d", ctx->f_infolevel); 5274 error = EINVAL; 5275 goto bad; 5276 } 5277 5278again: 5279 queryp->file_info_class = info_class; 5280 queryp->flags = flags; 5281 queryp->file_index = file_index; 5282 queryp->fid = ctx->f_create_fid; 5283 5284 /* handle servers that dislike large output buffer lens */ 5285 if (SSTOVC(ctx->f_share)->vc_misc_flags & SMBV_64K_QUERY_DIR) { 5286 queryp->output_buffer_len = kSMB_64K; 5287 } 5288 else { 5289 queryp->output_buffer_len = MIN(SSTOVC(ctx->f_share)->vc_txmax, 5290 kSMB_MAX_TX); 5291 } 5292 5293 /* 5294 * Copy in whether to use UTF_SFM_CONVERSIONS or not 5295 * Seems like if NOT a wildcard, then use UTF_SFM_CONVERSIONS 5296 */ 5297 queryp->name_flags = ctx->f_sfm_conversion; 5298 5299 queryp->dnp = ctx->f_dnp; 5300 queryp->namep = (char*) ctx->f_lookupName; 5301 queryp->name_len = (uint32_t) ctx->f_lookupNameLen; 5302 5303 if (ctx->f_need_close == FALSE) { 5304 /* Build and send a Create/Query dir */ 5305 error = smb2fs_smb_cmpd_query_dir(ctx, queryp, context); 5306 } 5307 else { 5308 /* Just send a single Query Dir */ 5309 error = smb2_smb_query_dir(ctx->f_share, queryp, NULL, context); 5310 5311 /* save f_query_rqp so it can be freed later */ 5312 ctx->f_query_rqp = queryp->ret_rqp; 5313 } 5314 5315 if (error) { 5316 if (error == ENOENT) { 5317 ctx->f_flags |= SMBFS_RDD_EOF; 5318 } 5319 5320 /* handle servers that dislike large output buffer lens */ 5321 if ((error == EINVAL) && 5322 (queryp->ret_ntstatus == STATUS_INVALID_PARAMETER) && 5323 !((SSTOVC(ctx->f_share)->vc_misc_flags) & SMBV_64K_QUERY_DIR) && 5324 (attempts == 0)) { 5325 SMBWARNING("SMB 2/3 server cant handle large OutputBufferLength in Query_Dir. Reducing to 64Kb.\n"); 5326 SSTOVC(ctx->f_share)->vc_misc_flags |= SMBV_64K_QUERY_DIR; 5327 attempts += 1; 5328 5329 if (ctx->f_create_rqp) { 5330 smb_rq_done(ctx->f_create_rqp); 5331 ctx->f_create_rqp = NULL; 5332 } 5333 if (ctx->f_query_rqp) { 5334 smb_rq_done(ctx->f_query_rqp); 5335 ctx->f_query_rqp = NULL; 5336 } 5337 goto again; 5338 } 5339 5340 goto bad; 5341 } 5342 5343 ctx->f_output_buf_len = queryp->ret_buffer_len; 5344 5345 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 5346 /* next find will be a Find Next */ 5347 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 5348 } 5349 5350 ctx->f_eofs = 0; 5351 ctx->f_attr.fa_reqtime = ts; 5352 } 5353 5354 /* 5355 * Either we did a new search and we are parsing the first entry out or 5356 * we are just parsing more names out of a previous search. 5357 */ 5358 ctx->f_NetworkNameLen = 0; 5359 5360 /* at this point, mdp is pointing to output buffer */ 5361 if (ctx->f_create_rqp != NULL) { 5362 /* 5363 * <14227703> Check to see if server is using non compound replies. 5364 * If SMB2_RESPONSE is set in queyr_rqp, then server is not using 5365 * compound replies and thusreply is in the query_rqp 5366 */ 5367 if (!(ctx->f_query_rqp->sr_extflags & SMB2_RESPONSE)) { 5368 /* Did a compound request so data is in create_rqp */ 5369 smb_rq_getreply(ctx->f_create_rqp, &mdp); 5370 } 5371 else { 5372 /* Server does not support compound replies */ 5373 smb_rq_getreply(ctx->f_query_rqp, &mdp); 5374 } 5375 } 5376 else { 5377 /* Only a Query Dir, so data is in query_rqp */ 5378 smb_rq_getreply(ctx->f_query_rqp, &mdp); 5379 } 5380 5381 /* 5382 * Parse one entry out of the output buffer and store results into ctx 5383 */ 5384 switch (ctx->f_infolevel) { 5385 case SMB_FIND_FULL_DIRECTORY_INFO: 5386 case SMB_FIND_BOTH_DIRECTORY_INFO: 5387 /* Call the parsing function */ 5388 error = smb2_smb_parse_query_dir_both_dir_info(ctx->f_share, mdp, 5389 ctx->f_infolevel, 5390 ctx, &ctx->f_attr, 5391 ctx->f_NetworkNameBuffer, &ctx->f_NetworkNameLen, 5392 ctx->f_MaxNetworkNameBufferSize); 5393 if (error) { 5394 goto bad; 5395 } 5396 break; 5397 default: 5398 SMBERROR("unexpected info level %d\n", ctx->f_infolevel); 5399 return EINVAL; 5400 } 5401 5402bad: 5403 if (queryp != NULL) { 5404 SMB_FREE(queryp, M_SMBTEMP); 5405 } 5406 5407 return error; 5408} 5409 5410int 5411smbfs_smb_findnext(struct smbfs_fctx *ctx, vfs_context_t context) 5412{ 5413 struct smb_vc *vcp = SSTOVC(ctx->f_share); 5414 int error; 5415 5416 if (vcp->vc_flags & SMBV_SMB2) { 5417 error = smb2fs_smb_findnext(ctx, context); 5418 } 5419 else { 5420 error = smb1fs_smb_findnext(ctx, context); 5421 } 5422 5423 return error; 5424} 5425 5426/* 5427 * This routine will send a flush across the wire to the server. This is an expensive 5428 * operation that should only be done when the user request it. 5429 * 5430 * The calling routine must hold a reference on the share 5431 * 5432 */ 5433int 5434smbfs_smb_flush(struct smb_share *share, SMBFID fid, vfs_context_t context) 5435{ 5436 int error; 5437 5438 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5439 error = smb2_smb_flush(share, fid, context); 5440 } 5441 else { 5442 error = smb1fs_smb_flush(share, fid, context); 5443 } 5444 return error; 5445} 5446 5447uint32_t 5448smb2fs_smb_get_create_options(struct smb_share *share, struct smbnode *np, 5449 const char *namep, const char *strm_namep, 5450 enum vtype vnode_type, uint32_t check_reparse) 5451{ 5452 uint32_t create_options = 0; 5453 5454 /* 5455 * smb2fs_smb_get_create_options() has various ways it can be called 5456 * 1) np - open item (np) 5457 * 2) np, namep - open the child (namep) in parent dir (np) 5458 * 3) np, strm_namep - open named stream (strm_namep) of item (np) 5459 * 4) np, namep, strm_namep - open named stream of (strm_namep) of 5460 * child (namep) in parent dir (np) 5461 */ 5462 5463 /* If its a dir, then set the dir option */ 5464 if (vnode_type == VDIR) { 5465 create_options |= NTCREATEX_OPTIONS_DIRECTORY; 5466 } 5467 5468 /* 5469 * If it a reparse point, then we have to be careful on whether to set 5470 * NTCREATEX_OPTIONS_OPEN_REPARSE_POINT or not. 5471 * 5472 * Most of the time we do not to set the reparse bit. This allows the 5473 * reparse point to go ahead and trigger a mount if needed. For example, 5474 * if the reparse point is a folder that is really an NTFS mount. 5475 * 5476 * If we are doing Create/QueryInfo or Create/SetInfo on the reparse point, 5477 * then set the reparse bit so we change the reparse point itself and not 5478 * its target. 5479 */ 5480 if (check_reparse == 0) { 5481 /* Go ahead and trigger the reparse point */ 5482 goto done; 5483 } 5484 5485 if ((share) && !(share->ss_attributes & FILE_SUPPORTS_REPARSE_POINTS)) { 5486 /* No reparse points, so no need to set reparse point bit */ 5487 goto done; 5488 } 5489 5490 /* Case (1) */ 5491 if ((np) && 5492 (namep == NULL) && 5493 (strm_namep == NULL)) { 5494 /* 5495 * If its some type of reparse point and it has not been moved to 5496 * offline storage, open the reparse point itself. 5497 */ 5498 if ((np->n_dosattr & SMB_EFA_REPARSE_POINT) && 5499 !(np->n_dosattr & SMB_EFA_OFFLINE)){ 5500 create_options |= NTCREATEX_OPTIONS_OPEN_REPARSE_POINT; 5501 } 5502 } 5503 5504 /* 5505 * For cases (2) - (4), the Create will be on a parent dir or opening a 5506 * named stream. In either case we should not need to set the 5507 * NTCREATEX_OPTIONS_OPEN_REPARSE_POINT bit. 5508 */ 5509 5510done: 5511 return(create_options); 5512} 5513 5514static int 5515smb2fs_smb_listxattrs(struct smb_share *share, struct smbnode *np, char **xattrlist, 5516 size_t *xattrlist_len, vfs_context_t context) 5517{ 5518 uio_t xuio = NULL; 5519 size_t xattr_len = 0; 5520 char *xattrb = NULL; 5521 uint32_t flags = 0, max_access = 0; 5522 int error = 0; 5523 enum vtype vnode_type = VREG; 5524 5525 if (np == NULL) { 5526 SMBERROR("Missing vnode\n"); 5527 error = EINVAL; 5528 goto out; 5529 } 5530 5531 if ((np) && (np->n_vnode)) { 5532 /* Use vnode to determine type */ 5533 vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG; 5534 } 5535 5536 /* Only pass stream_buf_sizep, so we can determine the size of the list */ 5537 error = smb2fs_smb_qstreaminfo(share, np, vnode_type, 5538 NULL, 0, 5539 NULL, 5540 NULL, &xattr_len, 5541 NULL, NULL, 5542 &flags, &max_access, 5543 context); 5544 if (error) { 5545 if (error !=ENOATTR) { 5546 SMBERROR("qstreaminfo error: %d\n", error); 5547 goto out; 5548 } 5549 error = 0; 5550 } 5551 5552 if (!xattr_len) { 5553 /* np does not have any xattrs */ 5554 goto out; 5555 } 5556 5557 /* Setup a uio and buffer for the xattr list */ 5558 SMB_MALLOC(xattrb, 5559 char *, 5560 xattr_len, 5561 M_SMBTEMP, 5562 M_WAITOK | M_ZERO); 5563 if (xattrb == NULL) { 5564 SMBERROR("SMB_MALLOC failed\n"); 5565 error = ENOMEM; 5566 goto out; 5567 } 5568 5569 xuio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ); 5570 if (xuio == NULL) { 5571 SMBERROR("uio_create failed\n"); 5572 error = ENOMEM; 5573 goto out; 5574 } 5575 5576 error = uio_addiov(xuio, xattrb, xattr_len); 5577 5578 if (error) { 5579 SMBERROR("uio_addiov failed, error: %d", error); 5580 goto out; 5581 } 5582 5583 uio_setoffset(xuio, 0); 5584 5585 /* Only pass a uio and stream_buf_sizep, to get the entire list of xattrs */ 5586 flags = SMB_NO_TRANSLATE_NAMES; /* Do not translate AFP_Resource & AFP_AfpInfo */ 5587 error = smb2fs_smb_qstreaminfo(share, np, vnode_type, 5588 NULL, 0, 5589 NULL, 5590 xuio, &xattr_len, 5591 NULL, NULL, 5592 &flags, &max_access, 5593 context); 5594 5595 if (error) { 5596 SMBDEBUG("qstream failed, error: %d", error); 5597 goto out; 5598 } 5599 5600 /* Return the results */ 5601 *xattrlist = xattrb; 5602 *xattrlist_len = xattr_len; 5603 5604 /* Clean up */ 5605 uio_free(xuio); 5606 5607 return (0); 5608 5609out: 5610 if (xuio != NULL) { 5611 uio_free(xuio); 5612 } 5613 if (xattrb != NULL) { 5614 SMB_FREE(xattrb, M_SMBTEMP); 5615 } 5616 5617 *xattrlist = NULL; 5618 *xattrlist_len = 0; 5619 5620 return (error); 5621} 5622 5623int 5624smbfs_smb_lock(struct smb_share *share, int op, SMBFID fid, uint32_t pid, 5625 off_t start, uint64_t len, uint32_t timo, vfs_context_t context) 5626{ 5627 int error; 5628 5629 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5630 error = smb2_smb_lock(share, op, fid, start, len, context); 5631 } 5632 else { 5633 error = smb1fs_smb_lock(share, op, fid, pid, start, len, timo, context); 5634 } 5635 return error; 5636} 5637 5638static int 5639smb2fs_smb_markfordelete(struct smb_share *share, SMBFID fid, vfs_context_t context) 5640{ 5641 int error; 5642 struct smb2_set_info_rq *infop = NULL; 5643 uint8_t delete_byte = 1; 5644 5645 SMB_MALLOC(infop, 5646 struct smb2_set_info_rq *, 5647 sizeof(struct smb2_set_info_rq), 5648 M_SMBTEMP, 5649 M_WAITOK | M_ZERO); 5650 if (infop == NULL) { 5651 SMBERROR("SMB_MALLOC failed\n"); 5652 error = ENOMEM; 5653 goto bad; 5654 } 5655 5656 /* 5657 * Set up for the Set Info call 5658 */ 5659 infop->info_type = SMB2_0_INFO_FILE; 5660 infop->file_info_class = FileDispositionInformation; 5661 infop->add_info = 0; 5662 infop->fid = fid; 5663 infop->input_buffer = (uint8_t *) &delete_byte; 5664 5665 error = smb2_smb_set_info(share, infop, NULL, context); 5666 if (error) { 5667 SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n", 5668 error, 5669 infop->ret_ntstatus); 5670 goto bad; 5671 } 5672 5673bad: 5674 if (infop != NULL) { 5675 SMB_FREE(infop, M_SMBTEMP); 5676 } 5677 5678 return error; 5679} 5680 5681/* 5682 * smbfs_smb_markfordelete 5683 * 5684 * We have an open file that they want to delete. This call will tell the 5685 * server to delete the file when the last close happens. Currenly we know that 5686 * XP, Windows 2000 and Windows 2003 support this call. SAMBA does support the 5687 * call, but currently has a bug that prevents it from working. 5688 * 5689 * The calling routine must hold a reference on the share 5690 * 5691 */ 5692int 5693smbfs_smb_markfordelete(struct smb_share *share, SMBFID fid, vfs_context_t context) 5694{ 5695 int error; 5696 5697 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5698 error = smb2fs_smb_markfordelete(share, fid, context); 5699 } 5700 else { 5701 error = smb1fs_smb_markfordelete(share, fid, context); 5702 } 5703 return error; 5704} 5705 5706int 5707smb2fs_smb_ntcreatex(struct smb_share *share, struct smbnode *np, 5708 const char *namep, size_t in_nmlen, 5709 const char *strm_namep, size_t in_strm_nmlen, 5710 uint32_t desired_access, enum vtype vnode_type, 5711 uint32_t share_access, uint32_t disposition, 5712 uint64_t create_flags, uint32_t create_options, 5713 SMBFID *fidp, struct smbfattr *fap, 5714 struct smb_rq **compound_rqp, struct smb2_create_rq **in_createp, 5715 void *create_contextp, vfs_context_t context) 5716{ 5717 uint32_t file_attributes; 5718 int error; 5719 size_t name_len = in_nmlen; 5720 size_t strm_name_len = in_strm_nmlen; 5721 /* Don't change the input name length, we need it for making the ino number */ 5722 struct smb2_create_rq *createp = NULL; 5723 uint32_t impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; 5724 uint8_t oplock_level = SMB2_OPLOCK_LEVEL_NONE; 5725 char *snamep = NULL; 5726 5727 /* 5728 * smb2fs_smb_ntcreatex() has various ways it can be called 5729 * 1) np - open item (np) 5730 * 2) np, namep - open the child (namep) in parent dir (np) 5731 * 3) np, strm_namep - open named stream (strm_namep) of item (np) 5732 * 4) np, namep, strm_namep - open named stream of (strm_namep) of 5733 * child (namep) in parent dir (np) 5734 */ 5735 5736 if (fap) { 5737 bzero(fap, sizeof(*fap)); 5738 nanouptime(&fap->fa_reqtime); 5739 } 5740 5741 SMB_MALLOC(createp, 5742 struct smb2_create_rq *, 5743 sizeof(struct smb2_create_rq), 5744 M_SMBTEMP, 5745 M_WAITOK | M_ZERO); 5746 if (createp == NULL) { 5747 SMBERROR("SMB_MALLOC failed\n"); 5748 error = ENOMEM; 5749 goto bad; 5750 } 5751 5752 /* determine file attributes */ 5753 if (vnode_type == VDIR) { 5754 file_attributes = SMB_EFA_DIRECTORY; 5755 } 5756 else { 5757 file_attributes = SMB_EFA_NORMAL; 5758 } 5759 if ((disposition != FILE_OPEN) && 5760 (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM))) { 5761 if (file_attributes == SMB_EFA_NORMAL) { 5762 file_attributes |= SMB_EFA_ARCHIVE; 5763 } 5764 if ((namep) && (*namep == '.')) { 5765 file_attributes |= SMB_EFA_HIDDEN; 5766 } 5767 } 5768 5769 /* start wth the passed in flag settings */ 5770 createp->flags |= create_flags; 5771 5772 /* Do they want to open the resource fork? */ 5773 if ((np) && (np->n_vnode) && 5774 (vnode_isnamedstream(np->n_vnode)) && 5775 (!strm_namep) && (!(create_flags & SMB2_CREATE_IS_NAMED_STREAM))) { 5776 lck_rw_lock_shared(&np->n_name_rwlock); 5777 snamep = smb_strndup(np->n_sname, np->n_snmlen); 5778 strm_namep = snamep; 5779 lck_rw_unlock_shared(&np->n_name_rwlock); 5780 5781 strm_name_len = np->n_snmlen; 5782 createp->flags |= SMB2_CREATE_IS_NAMED_STREAM; 5783 } 5784 5785 if (create_flags & SMB2_CREATE_DUR_HANDLE_RECONNECT) { 5786 impersonation_level = 0; 5787 file_attributes = 0; 5788 create_options = 0; 5789 createp->create_contextp = create_contextp; 5790 oplock_level = SMB2_OPLOCK_LEVEL_LEASE; 5791 } 5792 else { 5793 if (create_flags & SMB2_CREATE_DUR_HANDLE) { 5794 createp->create_contextp = create_contextp; 5795 oplock_level = SMB2_OPLOCK_LEVEL_LEASE; 5796 } 5797 } 5798 5799 if (create_flags & SMB2_CREATE_AAPL_RESOLVE_ID) { 5800 createp->create_contextp = create_contextp; 5801 } 5802 5803 /* 5804 * Set up for the Create call 5805 */ 5806 createp->oplock_level = oplock_level; 5807 createp->impersonate_level = impersonation_level; 5808 5809 createp->desired_access = desired_access; 5810 if (create_flags & SMB2_CREATE_GET_MAX_ACCESS) { 5811 /* since getting max access, make sure SMB2_FILE_READ_ATTRIBUTES set */ 5812 createp->desired_access |= SMB2_FILE_READ_ATTRIBUTES; 5813 } 5814 createp->file_attributes = file_attributes; 5815 createp->share_access = share_access; 5816 createp->disposition = disposition; 5817 createp->create_options = create_options; 5818 createp->name_len = (uint32_t) name_len; 5819 createp->namep = (char *) namep; 5820 createp->strm_name_len = (uint32_t) strm_name_len; 5821 createp->strm_namep = (char *) strm_namep; 5822 createp->dnp = np; 5823 5824 /* 5825 * Do the Create call 5826 */ 5827 error = smb2_smb_create(share, createp, compound_rqp, context); 5828 if (error) { 5829 if ((error != ENOENT) && (error != EEXIST) && (error != EBUSY)) { 5830 SMBDEBUG("smb2_smb_create failed %d ntstatus 0x%x\n", 5831 error, 5832 createp->ret_ntstatus); 5833 } 5834 goto bad; 5835 } 5836 5837 /* Building a compound requests */ 5838 if (in_createp != NULL) { 5839 *in_createp = createp; 5840 return (0); 5841 } 5842 5843 if (fidp) { 5844 *fidp = createp->ret_fid; 5845 } 5846 5847 /* 5848 * Fill in fap and possibly update vnode's meta data caches 5849 */ 5850 error = smb2fs_smb_parse_ntcreatex(share, np, createp, 5851 fidp, fap, context); 5852bad: 5853 if (createp != NULL) { 5854 SMB_FREE(createp, M_SMBTEMP); 5855 } 5856 5857 if (snamep) { 5858 SMB_FREE(snamep, M_SMBSTR); 5859 } 5860 5861 return error; 5862} 5863 5864/* 5865 * Modern create/open of file or directory. 5866 * 5867 * If disp is FILE_OPEN then this is an open attempt, and: 5868 * If xattr then name is the stream to be opened at np, 5869 * Else np should be opened. 5870 * ...we won't touch *fidp, 5871 * Else this is a creation attempt, and: 5872 * If xattr then name is the stream to create at np, 5873 * Else name is the thing to create under directory np. 5874 * ...we will return *fidp, 5875 * 5876 * The calling routine must hold a reference on the share 5877 * 5878 * Either pass in np which is the file/dir to open OR 5879 * pass in dnp and a name 5880 * 5881 */ 5882int 5883smbfs_smb_ntcreatex(struct smb_share *share, struct smbnode *np, 5884 uint32_t rights, uint32_t shareMode, enum vtype vt, 5885 SMBFID *fidp, const char *name, size_t in_nmlen, 5886 uint32_t disp, int xattr, struct smbfattr *fap, 5887 int do_create, struct smb2_durable_handle *dur_handlep, vfs_context_t context) 5888{ 5889 int error; 5890 uint64_t create_flags = 0; 5891 char *file_namep = NULL, *stream_namep = NULL; 5892 size_t file_name_len = 0, stream_name_len = 0; 5893 5894 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5895 create_flags = SMB2_CREATE_GET_MAX_ACCESS; /* Always set want_max_access */ 5896 5897 if (do_create) 5898 create_flags |= SMB2_CREATE_DO_CREATE; 5899 5900 if (dur_handlep) { 5901 if (dur_handlep->flags & SMB2_DURABLE_HANDLE_RECONNECT) { 5902 create_flags = SMB2_CREATE_DUR_HANDLE_RECONNECT; 5903 } 5904 else { 5905 if (dur_handlep->flags & SMB2_DURABLE_HANDLE_REQUEST) { 5906 create_flags = SMB2_CREATE_DUR_HANDLE; 5907 } 5908 } 5909 } 5910 5911 if (!xattr) { 5912 file_namep = (char *) name; 5913 file_name_len = in_nmlen; 5914 } 5915 else { 5916 /* name is actually the stream name */ 5917 create_flags |= SMB2_CREATE_IS_NAMED_STREAM; 5918 5919 stream_namep = (char *) name; 5920 stream_name_len = in_nmlen; 5921 } 5922 5923 error = smb2fs_smb_cmpd_create(share, np, 5924 file_namep, file_name_len, 5925 stream_namep, stream_name_len, 5926 rights, vt, 5927 shareMode, disp, 5928 create_flags, NULL, 5929 fidp, fap, 5930 dur_handlep, context); 5931 } 5932 else { 5933 error = smb1fs_smb_ntcreatex(share, np, rights, shareMode, vt, fidp, 5934 name, in_nmlen, disp, xattr, fap, 5935 do_create, context); 5936 } 5937 5938 return error; 5939} 5940 5941/* 5942 * This routine chains the open and read into one message. This routine is used 5943 * only for reading data out of a stream. If we decided to use it for something 5944 * else then we will need to make some changes. 5945 * 5946 * The calling routine must hold a reference on the share 5947 * 5948 */ 5949int 5950smbfs_smb_openread(struct smb_share *share, struct smbnode *np, 5951 SMBFID *fidp, uint32_t desired_access, 5952 uio_t uio, size_t *sizep, const char *stream_namep, 5953 struct timespec *mtimep, vfs_context_t context) 5954{ 5955 int error; 5956 size_t stream_name_len = strnlen(stream_namep, 5957 share->ss_maxfilenamelen + 1); 5958 uint32_t max_access; 5959 5960 /* This is only used when dealing with xattr calls */ 5961 5962 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 5963 /* 5964 * Do a Create/Read or Create/Read/Close. The Close is added if 5965 * fidp is NULL 5966 */ 5967 error = smb2fs_smb_cmpd_create_read(share, np, 5968 NULL, 0, 5969 stream_namep, stream_name_len, 5970 desired_access, uio, 5971 sizep, &max_access, 5972 fidp, mtimep, 5973 context); 5974 } 5975 else { 5976 error = smb1fs_smb_openread(share, np, fidp, desired_access, uio, sizep, 5977 stream_namep, mtimep, context); 5978 } 5979 5980 return error; 5981} 5982 5983static int 5984smb2fs_smb_parse_ntcreatex(struct smb_share *share, struct smbnode *np, 5985 struct smb2_create_rq *createp, 5986 SMBFID *fidp, struct smbfattr *fap, 5987 vfs_context_t context) 5988{ 5989 /* 5990 * smb2fs_smb_ntcreatex() has various ways it can be called 5991 * (1) np - open item (np) 5992 * (2) np, namep - open the child (namep) in parent dir (np) 5993 * (3) np, strm_namep - open named stream (strm_namep) of item (np) 5994 * (4) np, namep, strm_namep - open named stream of (strm_namep) of 5995 * child (namep) in parent dir (np) 5996 * 5997 * If there is a namep, then do not update the vnode np as that will 5998 * be the parent vnode. 5999 */ 6000 6001 DBG_ASSERT(fap != NULL); 6002 6003 /* 6004 * Copy results out into fap 6005 */ 6006 fap->fa_created_disp = createp->ret_create_action; 6007 smb_time_NT2local(createp->ret_create_time, &fap->fa_crtime); 6008 smb_time_NT2local(createp->ret_access_time, &fap->fa_atime); 6009 smb_time_NT2local(createp->ret_write_time, &fap->fa_mtime); 6010 smb_time_NT2local(createp->ret_change_time, &fap->fa_chtime); 6011 6012 /* 6013 * Because of the Steve/Conrad Symlinks we can never be completely 6014 * sure that we have the correct vnode type if its a file. For 6015 * directories we always know the correct information. 6016 */ 6017 fap->fa_attr = createp->ret_attributes; 6018 if (fap->fa_attr & SMB_EFA_DIRECTORY) { 6019 fap->fa_valid_mask |= FA_VTYPE_VALID; 6020 } 6021 fap->fa_vtype = (fap->fa_attr & SMB_EFA_DIRECTORY) ? VDIR : VREG; 6022 6023 fap->fa_data_alloc = createp->ret_alloc_size; 6024 fap->fa_size = createp->ret_eof; 6025 6026 if (createp->flags & SMB2_CREATE_GET_MAX_ACCESS) { 6027 fap->fa_max_access = createp->ret_max_access; 6028 fap->fa_valid_mask |= FA_MAX_ACCESS_VALID; 6029 6030 /* Special case the root vnode */ 6031 if (createp->namep == NULL) { 6032 /* Must be (1) or (3) and could be the root vnode */ 6033 if ((np) && (np->n_vnode) && (vnode_isvroot(np->n_vnode))) { 6034 /* 6035 * its the root folder, if no Execute, but share grants 6036 * Execute then grant Execute to root folder 6037 */ 6038 if ((!(np->maxAccessRights & SMB2_FILE_EXECUTE)) && 6039 (share->maxAccessRights & SMB2_FILE_EXECUTE)) { 6040 fap->fa_max_access |= SMB2_FILE_EXECUTE; 6041 } 6042 6043 /* 6044 * its the root, if no ReadAttr, but share grants 6045 * ReadAttr then grant ReadAttr to root 6046 */ 6047 if ((!(np->maxAccessRights & SMB2_FILE_READ_ATTRIBUTES)) && 6048 (share->maxAccessRights & SMB2_FILE_READ_ATTRIBUTES)) { 6049 fap->fa_max_access |= SMB2_FILE_READ_ATTRIBUTES; 6050 } 6051 } 6052 } 6053 } 6054 6055 if (fidp) { 6056 *fidp = createp->ret_fid; 6057 } 6058 6059 /* 6060 * If not a directory, check if node needs to be reopened, 6061 * if so, then don't update anything at this point. 6062 * See <rdar://problem/11366143>. 6063 */ 6064 if ((np) && (np->n_vnode) && !(vnode_isdir(np->n_vnode))) { 6065 lck_mtx_lock(&np->f_openStateLock); 6066 if (np->f_openState & kInReopen) { 6067 lck_mtx_unlock(&np->f_openStateLock); 6068 goto done; 6069 } 6070 lck_mtx_unlock(&np->f_openStateLock); 6071 } 6072 6073 if (createp->flags & SMB2_CREATE_IS_NAMED_STREAM) { 6074 /* 6075 * Must be (3) or (4). 6076 * If an EA or Stream then we are done. We dont update that main 6077 * data vnode with information from a stream. Possibly we could since 6078 * the data should be valid... 6079 */ 6080 goto done; 6081 } 6082 6083 if ((np) && (createp->flags & SMB2_CREATE_DO_CREATE)) { 6084 if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) { 6085 /* 6086 * File server does not support File IDs 6087 */ 6088 6089 /* 6090 * Must be (2). We are creating the item so create the ino number. 6091 * Since its a create, it must be the data fork and thus 6092 * createp->name_len is the same as the orig in_nmlen. 6093 */ 6094 6095 /* This is a create so better have a name, but root does not have a name */ 6096 fap->fa_ino = smbfs_getino(np, createp->namep, createp->name_len); 6097 goto done; 6098 } 6099 } 6100 6101 if (createp->namep) { 6102 /* 6103 * SMB2_CREATE_DO_CREATE is not set, but still have a name, so 6104 * must be (2) 6105 */ 6106 goto done; 6107 } 6108 6109 /* If this is a SYMLINK, then n_vnode could be set to NULL */ 6110 if ((np) && (np->n_vnode == NULL)) { 6111 goto done; 6112 } 6113 6114 /* 6115 * At this point, it must be (1). 6116 * We have all the meta data attributes so update the cache. If the 6117 * calling routine is setting an attribute it should not change the 6118 * smb node value until after the open has completed. NOTE: The old 6119 * code would only update the cache if the mtime, attributes and size 6120 * haven't changed. 6121 */ 6122 if (np) { 6123 smbfs_attr_cacheenter(share, np->n_vnode, fap, TRUE, context); 6124 } 6125 6126done: 6127 return 0; 6128} 6129 6130static int 6131smb2fs_smb_qfsattr(struct smbmount *smp, 6132 struct FILE_FS_ATTRIBUTE_INFORMATION *fs_attrs, 6133 vfs_context_t context) 6134{ 6135 struct smb_share *share = smp->sm_share; 6136 int error; 6137 uint32_t output_buffer_len; 6138 6139 output_buffer_len = sizeof(struct FILE_FS_ATTRIBUTE_INFORMATION); 6140 output_buffer_len += PATH_MAX; 6141 6142 /* 6143 * Do the Compound Create/Query Info/Close call 6144 * Query results are passed back in *fs_attrs 6145 * 6146 * Have to pass in submount path if it exists because we have no root vnode, 6147 * and smbmount and smb_share may not be fully set up yet. 6148 * 6149 * This is always done on the root of the share 6150 */ 6151 error = smb2fs_smb_cmpd_query(share, NULL, VDIR, 6152 (smp->sm_args.path_len == 0 ? NULL : smp->sm_args.path), 6153 smp->sm_args.path_len, 6154 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, 6155 SMB2_0_INFO_FILESYSTEM, FileFsAttributeInformation, 6156 0, NULL, 6157 &output_buffer_len, (uint8_t *) fs_attrs, 6158 context); 6159 6160 return error; 6161} 6162 6163/* 6164 * Since the first thing we do is set the default values there is no longer 6165 * any reason to return an error for this routine. Some servers may not support 6166 * this call. We should not fail the mount just because they do not support this 6167 * call. 6168 * 6169 * The calling routine must hold a reference on the share 6170 * 6171 */ 6172void 6173smbfs_smb_qfsattr(struct smbmount *smp, vfs_context_t context) 6174{ 6175 struct smb_share *share = smp->sm_share; 6176 struct smb_vc *vcp = SSTOVC(share); 6177 struct FILE_FS_ATTRIBUTE_INFORMATION fs_attrs; 6178 int error; 6179 size_t fs_nmlen; /* The sized malloced for fs_name */ 6180 char *fsname = NULL; 6181 6182 /* Start with the default values */ 6183 share->ss_fstype = SMB_FS_FAT; /* default to FAT File System */ 6184 share->ss_attributes = 0; 6185 share->ss_maxfilenamelen = 255; 6186 6187 bzero(&fs_attrs, sizeof(fs_attrs)); 6188 6189 if (vcp->vc_flags & SMBV_SMB2) { 6190 error = smb2fs_smb_qfsattr(smp, &fs_attrs, context); 6191 } 6192 else { 6193 /* 6194 * Goal is to leave the SMB 1 code unchanged as much as possible 6195 * to minimize the risk. That is why there is duplicate code here 6196 * for the SMB 2/3 path and also in SMB 1 code path. 6197 */ 6198 smb1fs_qfsattr(share, context); 6199 return; 6200 } 6201 6202 if (error) { 6203 /* This is a very bad server */ 6204 SMBWARNING("Server returned a bad SMB_QFS_ATTRIBUTE_INFO message\n"); 6205 /* Don't believe them when they say they are unix */ 6206 SSTOVC(share)->vc_sopt.sv_caps &= ~SMB_CAP_UNIX; 6207 return; 6208 } 6209 6210 share->ss_attributes = fs_attrs.file_system_attrs; 6211 share->ss_maxfilenamelen = fs_attrs.max_component_name_len; 6212 6213 if (!SMB_UNICODE_STRINGS(SSTOVC(share))) { 6214 SMBERROR("Unicode must be supported\n"); 6215 goto done; 6216 } 6217 6218 /* If have a file system name, determine what it is */ 6219 if (fs_attrs.file_system_namep != NULL) { 6220 /* Convert Unicode string */ 6221 fs_nmlen = fs_attrs.file_system_name_len; 6222 fsname = smbfs_ntwrkname_tolocal(fs_attrs.file_system_namep, 6223 &fs_nmlen, 6224 SMB_UNICODE_STRINGS(SSTOVC(share))); 6225 if (fsname == NULL) { 6226 SMBERROR("fs_attr name failed to convert\n"); 6227 goto done; /* Should never happen, but just to be safe */ 6228 } 6229 6230 fs_nmlen += 1; /* Include the null byte for the compare */ 6231 6232 /* 6233 * Let's start keeping track of the file system type. Most 6234 * things we need to do differently really depend on the 6235 * file system type. As an example we know that FAT file systems 6236 * do not update the modify time on directories. 6237 */ 6238 if (strncmp(fsname, "FAT", fs_nmlen) == 0) 6239 share->ss_fstype = SMB_FS_FAT; 6240 else if (strncmp(fsname, "FAT12", fs_nmlen) == 0) 6241 share->ss_fstype = SMB_FS_FAT; 6242 else if (strncmp(fsname, "FAT16", fs_nmlen) == 0) 6243 share->ss_fstype = SMB_FS_FAT; 6244 else if (strncmp(fsname, "FAT32", fs_nmlen) == 0) 6245 share->ss_fstype = SMB_FS_FAT; 6246 else if (strncmp(fsname, "CDFS", fs_nmlen) == 0) 6247 share->ss_fstype = SMB_FS_CDFS; 6248 else if (strncmp(fsname, "UDF", fs_nmlen) == 0) 6249 share->ss_fstype = SMB_FS_UDF; 6250 else if (strncmp(fsname, "NTFS", fs_nmlen) == 0) 6251 share->ss_fstype = SMB_FS_NTFS_UNKNOWN; /* Could be lying */ 6252 6253 SMBWARNING("%s/%s type '%s', attr 0x%x, maxfilename %d\n", 6254 SSTOVC(share)->vc_srvname, share->ss_name, fsname, 6255 share->ss_attributes, share->ss_maxfilenamelen); 6256 6257 /* 6258 * NT4 will not return the FILE_NAMED_STREAMS bit in the ss_attributes 6259 * even though they support streams. So if its a NT4 server and a 6260 * NTFS file format then turn on the streams flag. 6261 */ 6262 if ((SSTOVC(share)->vc_flags & SMBV_NT4) && 6263 (share->ss_fstype & SMB_FS_NTFS_UNKNOWN)) { 6264 share->ss_attributes |= FILE_NAMED_STREAMS; 6265 } 6266 /* 6267 * The server says they support streams and they say they are NTFS. So mark 6268 * the subtype as NTFS. Remember a lot of non Windows servers pretend 6269 * their NTFS so they can support ACLs, but they aren't really because they have 6270 * no stream support. This allows us to tell the difference. 6271 */ 6272 if ((share->ss_fstype == SMB_FS_NTFS_UNKNOWN) && 6273 (share->ss_attributes & FILE_NAMED_STREAMS)) { 6274 share->ss_fstype = SMB_FS_NTFS; /* Real NTFS Volume */ 6275 } 6276 else if ((share->ss_fstype == SMB_FS_NTFS_UNKNOWN) && 6277 (UNIX_SERVER(SSTOVC(share)))) { 6278 share->ss_fstype = SMB_FS_NTFS_UNIX; 6279 /* UNIX system lying about being NTFS */ 6280 } 6281 6282 /* 6283 * Note: If this is an OS X SMB 2/3 server, smbfs_mount() will 6284 * set share->ss_fstype() to SMB_FS_MAC_OS_X. We cannot do 6285 * that here because at this point we haven't yet queried the 6286 * server for AAPL create context support. 6287 */ 6288 } 6289 6290done: 6291 if (fs_attrs.file_system_namep != NULL) { 6292 SMB_FREE(fs_attrs.file_system_namep, M_SMBFSDATA); 6293 } 6294 if (fsname != NULL) { 6295 SMB_FREE(fsname, M_SMBSTR); 6296 } 6297} 6298 6299static int 6300smb2fs_smb_qpathinfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 6301 struct smbfattr *fap, short infolevel, 6302 const char **namep, size_t *name_lenp, 6303 vfs_context_t context) 6304{ 6305 struct FILE_ALL_INFORMATION *all_infop = NULL; 6306 int error = EINVAL; 6307 const char *name = (namep ? *namep : NULL); 6308 size_t name_len = (name_lenp ? *name_lenp : 0); 6309 uint32_t output_buffer_len; 6310 6311 SMB_MALLOC(all_infop, 6312 struct FILE_ALL_INFORMATION *, 6313 sizeof(struct FILE_ALL_INFORMATION), 6314 M_SMBTEMP, 6315 M_WAITOK | M_ZERO); 6316 if (all_infop == NULL) { 6317 SMBERROR("SMB_MALLOC failed\n"); 6318 error = ENOMEM; 6319 goto bad; 6320 } 6321 6322 /* 6323 * Set up for the Query Info call 6324 */ 6325 switch (infolevel) { 6326 case SMB_QFILEINFO_ALL_INFO: 6327 all_infop->share = share; 6328 all_infop->np = np; 6329 all_infop->fap = fap; 6330 all_infop->namep = namep; 6331 all_infop->name_lenp = name_lenp; 6332 break; 6333 6334 default: 6335 SMBERROR("Unimplemented infolevel %d\n", infolevel); 6336 goto bad; 6337 break; 6338 } 6339 6340 output_buffer_len = SMB2_FILE_ALL_INFO_LEN; 6341 6342 /* 6343 * Do the Compound Create/SetInfo/Close call 6344 * Query results are passed back in *fap 6345 */ 6346 error = smb2fs_smb_cmpd_query(share, np, vnode_type, 6347 name, name_len, 6348 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, 6349 SMB2_0_INFO_FILE, FileAllInformation, 6350 0, NULL, 6351 &output_buffer_len, (uint8_t *) all_infop, 6352 context); 6353 6354bad: 6355 if (all_infop != NULL) { 6356 SMB_FREE(all_infop, M_SMBTEMP); 6357 } 6358 6359 return error; 6360} 6361 6362/* 6363 * The calling routine must hold a reference on the share 6364 */ 6365int 6366smbfs_smb_qpathinfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 6367 struct smbfattr *fap, short infolevel, 6368 const char **namep, size_t *nmlenp, 6369 vfs_context_t context) 6370{ 6371 struct smb_vc *vcp = SSTOVC(share); 6372 int error; 6373 6374 if (vcp->vc_flags & SMBV_SMB2) { 6375 error = smb2fs_smb_qpathinfo(share, np, vnode_type, 6376 fap, infolevel, 6377 namep, nmlenp, 6378 context); 6379 } 6380 else { 6381 error = smb1fs_smb_qpathinfo(share, 6382 np, 6383 fap, 6384 infolevel, 6385 namep, 6386 nmlenp, 6387 context); 6388 } 6389 6390 return error; 6391} 6392 6393/* 6394 * When calling this routine be very careful when passing the arguments. 6395 * Depending on the arguments different actions will be taken with this routine. 6396 * 6397 * The calling routine must hold a reference on the share 6398 * 6399 */ 6400static int 6401smb2fs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 6402 const char *namep, size_t name_len, 6403 const char *stream_namep, 6404 uio_t uio, size_t *sizep, 6405 uint64_t *stream_sizep, uint64_t *stream_alloc_sizep, 6406 uint32_t *stream_flagsp, uint32_t *max_accessp, 6407 vfs_context_t context) 6408{ 6409 /* 6410 * For this function, vnode_type is the item's type. The item will be 6411 * opened and checked for named streams. 6412 */ 6413 6414 /* 6415 * Two usage cases: 6416 * 1) Given np and namep == NULL. Query the path of np 6417 * 2) Given np and namep (must be readdirattr). Query PARENT np and 6418 * child namep. In this case, do not update vnode np as that is the parent. 6419 * 6420 * In both cases, Query for a list of streams and if streams are found, 6421 * see if they match stream_namep that was passed in. 6422 */ 6423 struct FILE_STREAM_INFORMATION *stream_infop = NULL; 6424 int error; 6425 uint32_t output_buffer_len; 6426 6427 if (namep == NULL) { 6428 /* Not readdirattr case */ 6429 if ((np->n_fstatus & kNO_SUBSTREAMS) || 6430 (np->n_dosattr & SMB_EFA_REPARSE_POINT)) { 6431 error = ENOATTR; 6432 goto bad; 6433 } 6434 } 6435 6436 if (sizep) { 6437 *sizep = 0; 6438 } 6439 6440 SMB_MALLOC(stream_infop, 6441 struct FILE_STREAM_INFORMATION *, 6442 sizeof(struct FILE_STREAM_INFORMATION), 6443 M_SMBTEMP, 6444 M_WAITOK | M_ZERO); 6445 if (stream_infop == NULL) { 6446 SMBERROR("SMB_MALLOC failed\n"); 6447 error = ENOMEM; 6448 goto bad; 6449 } 6450 6451 /* 6452 * Set up for the Query Info call 6453 * 6454 * We have two typical usages for this call 6455 * 1) listxattr - uio and/or stream_buf_sizep 6456 * a) if uio and stream_buf_sizep, then return all xattrs If stream_flagsp has 6457 * SMB_NO_TRANSLATE_NAMES set, then AFP_Resource & AFP_AfpInfo are not translated 6458 * to extended attribute names. 6459 * b) if only stream_buf_sizep, then they are just trying to determine size 6460 * of a buffer sufficiently large enough to hold all the xattr names 6461 * 2) Checking for existence of a specific stream 6462 * a) If stream_namep and stream_sizep/stream_alloc_sizep, then look for 6463 * that specific stream and if found, return its logical and alloc sizes 6464 * b) If only stream_namep, just check for existence of that specific stream 6465 */ 6466 stream_infop->share = share; 6467 stream_infop->np = np; 6468 stream_infop->namep = namep; 6469 stream_infop->name_len = name_len; 6470 stream_infop->uio = uio; 6471 stream_infop->stream_buf_sizep = sizep; 6472 stream_infop->stream_namep = stream_namep; 6473 stream_infop->stream_sizep = stream_sizep; 6474 stream_infop->stream_alloc_sizep = stream_alloc_sizep; 6475 stream_infop->stream_flagsp = stream_flagsp; 6476 6477 /* 6478 * Some servers do not grant us that many credits, so limit credit 6479 * usage to just 1. That should be plenty for getting 6480 * FileStreamInformation which is just a list of very short names like 6481 * ::$DATA 6482 */ 6483 output_buffer_len = 64 * 1024; 6484 6485 /* 6486 * Do the Compound Create/QueryInfo/Close call 6487 * Query results are passed back in uio 6488 */ 6489 error = smb2fs_smb_cmpd_query(share, np, vnode_type, 6490 namep, name_len, 6491 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, 6492 SMB2_0_INFO_FILE, FileStreamInformation, 6493 0, max_accessp, 6494 &output_buffer_len, (uint8_t *) stream_infop, 6495 context); 6496 6497 if (error) { 6498 if ((error != ENOATTR) && (error != EINVAL) && 6499 (error != EACCES) && (error != ENOENT)) { 6500 SMBDEBUG("smb2fs_smb_cmpd_query failed %d\n", error); 6501 } 6502 goto bad; 6503 } 6504 6505 /* Is there only the data stream and no other named streams? */ 6506 if ((namep == NULL) && (stream_flagsp != NULL)) { 6507 /* Not readdirattr case */ 6508 if (*stream_flagsp & SMB_NO_SUBSTREAMS) { 6509 np->n_fstatus |= kNO_SUBSTREAMS; 6510 } 6511 } 6512 6513bad: 6514 if (stream_infop != NULL) { 6515 SMB_FREE(stream_infop, M_SMBTEMP); 6516 } 6517 6518 return error; 6519} 6520 6521/* 6522 * When calling this routine be very careful when passing the arguments. 6523 * Depending on the arguments different actions will be taken with this routine. 6524 * 6525 * The calling routine must hold a reference on the share 6526 * 6527 */ 6528int 6529smbfs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 6530 const char *namep, size_t name_len, 6531 const char *stream_namep, 6532 uio_t uio, size_t *sizep, 6533 uint64_t *strm_sizep, uint64_t *strm_alloc_sizep, 6534 uint32_t *stream_flags, uint32_t *max_accessp, 6535 vfs_context_t context) 6536{ 6537 struct smb_vc *vcp = SSTOVC(share); 6538 int error; 6539 6540 if (vcp->vc_flags & SMBV_SMB2) { 6541 error = smb2fs_smb_qstreaminfo(share, np, vnode_type, 6542 namep, name_len, 6543 stream_namep, 6544 uio, sizep, 6545 strm_sizep, strm_alloc_sizep, 6546 stream_flags, max_accessp, 6547 context); 6548 } 6549 else { 6550 error = smb1fs_smb_qstreaminfo(share, np, 6551 namep, name_len, 6552 stream_namep, 6553 uio, sizep, 6554 strm_sizep, strm_alloc_sizep, 6555 stream_flags, 6556 context); 6557 } 6558 6559 return error; 6560 6561} 6562 6563/* 6564 * We should replace it with something more modern. See <rdar://problem/7595213>. 6565 * This routine is only used to test the existence of an item or to get its 6566 * DOS attributes when changing the status of the HIDDEN bit. 6567 * 6568 * The calling routine must hold a reference on the share 6569 * 6570 */ 6571int 6572smbfs_smb_query_info(struct smb_share *share, struct smbnode *dnp, enum vtype vnode_type, 6573 const char *in_name, size_t len, uint32_t *attr, 6574 vfs_context_t context) 6575{ 6576 struct smb_vc *vcp = SSTOVC(share); 6577 const char *name = in_name; 6578 size_t name_len = len; 6579 struct smbfattr *fap = NULL; 6580 int error; 6581 6582 if (vcp->vc_flags & SMBV_SMB2) { 6583 SMB_MALLOC(fap, 6584 struct smbfattr *, 6585 sizeof(struct smbfattr), 6586 M_SMBTEMP, 6587 M_WAITOK | M_ZERO); 6588 if (fap == NULL) { 6589 SMBERROR("SMB_MALLOC failed\n"); 6590 error = ENOMEM; 6591 goto out; 6592 } 6593 6594 if (vcp->vc_misc_flags & SMBV_NO_QUERYINFO) { 6595 /* Use Query Dir instead of Query Info, but only if SMB 2/3 */ 6596 error = smb2fs_smb_cmpd_query_dir_one(share, dnp, 6597 name, name_len, 6598 fap, (char **) &name, &name_len, 6599 context); 6600 } 6601 else { 6602 /* This is always a parent dir dnp and a name in that dir */ 6603 error = smb2fs_smb_qpathinfo(share, dnp, vnode_type, 6604 fap, SMB_QFILEINFO_ALL_INFO, 6605 &name, &name_len, 6606 context); 6607 } 6608 6609 if (error) { 6610 goto out; 6611 } 6612 6613 /* return attributes if they want them */ 6614 if (attr != NULL) { 6615 *attr = fap->fa_attr; 6616 } 6617 6618 /* if got returned a new name, free it since we do not need it */ 6619 if (name != in_name) { 6620 SMB_FREE(name, M_SMBNODENAME); 6621 } 6622 } 6623 else { 6624 error = smb1fs_smb_query_info(share, 6625 dnp, 6626 name, 6627 len, 6628 attr, 6629 context); 6630 } 6631 6632out: 6633 if (fap != NULL) { 6634 SMB_FREE(fap, M_SMBTEMP); 6635 } 6636 6637 return error; 6638} 6639 6640static int 6641smb2fs_smb_rename(struct smb_share *share, struct smbnode *src, 6642 struct smbnode *tdnp, const char *tnamep, size_t tname_len, 6643 vfs_context_t context) 6644{ 6645 int error; 6646 uint32_t setinfo_ntstatus; 6647 struct smb2_set_info_file_rename_info *renamep = NULL; 6648 enum vtype vnode_type = VREG; 6649 6650 /* 6651 * Looking at Win <-> Win with SMB 2/3, rename/move is handled by opening the 6652 * file with Delete and "Read Attributes", then a Set Info is done to move 6653 * or rename the file. Finally a Close is sent. 6654 */ 6655 6656 SMB_MALLOC(renamep, 6657 struct smb2_set_info_file_rename_info *, 6658 sizeof(struct smb2_set_info_file_rename_info), 6659 M_SMBTEMP, 6660 M_WAITOK | M_ZERO); 6661 if (renamep == NULL) { 6662 SMBERROR("SMB_MALLOC failed\n"); 6663 error = ENOMEM; 6664 goto bad; 6665 } 6666 6667 /* 6668 * Set up for the Set Info call 6669 */ 6670 renamep->replace_if_exists = 0; 6671 renamep->tname_len = (uint32_t) tname_len; 6672 renamep->tdnp = tdnp; 6673 renamep->tnamep = (char*) tnamep; 6674 6675 if ((src) && (src->n_vnode)) { 6676 /* Use vnode to determine type */ 6677 vnode_type = vnode_isdir(src->n_vnode) ? VDIR : VREG; 6678 } 6679 6680 /* 6681 * Do the Compound Create/SetInfo/Close call 6682 * Delete access will allow us to rename an open file 6683 */ 6684 error = smb2fs_smb_cmpd_set_info(share, src, vnode_type, 6685 NULL, 0, 6686 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_STD_ACCESS_DELETE | SMB2_SYNCHRONIZE, 6687 SMB2_0_INFO_FILE, FileRenameInformation, 6688 0, 6689 sizeof (*renamep), (uint8_t *) renamep, 6690 &setinfo_ntstatus, 6691 context); 6692 if (error) { 6693 if (error != EACCES) { 6694 SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d\n", error); 6695 } 6696 goto bad; 6697 } 6698 6699bad: 6700 if (renamep != NULL) { 6701 SMB_FREE(renamep, M_SMBTEMP); 6702 } 6703 6704 return error; 6705} 6706 6707/* 6708 * The calling routine must hold a reference on the share 6709 */ 6710int 6711smbfs_smb_rename(struct smb_share *share, struct smbnode *src, 6712 struct smbnode *tdnp, const char *tname, size_t tnmlen, 6713 vfs_context_t context) 6714{ 6715 int error; 6716 6717 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 6718 error = smb2fs_smb_rename(share, src, tdnp, tname, tnmlen, context); 6719 } 6720 else { 6721 error = smb1fs_smb_rename(share, src, tdnp, tname, tnmlen, context); 6722 } 6723 6724 return error; 6725} 6726 6727int 6728smbfs_smb_reparse_read_symlink(struct smb_share *share, struct smbnode *np, 6729 struct uio *uiop, vfs_context_t context) 6730{ 6731 int error; 6732 6733 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 6734 error = smb2fs_smb_cmpd_reparse_point_get(share, np, uiop, context); 6735 } 6736 else { 6737 error = smb1fs_smb_reparse_read_symlink(share, np, uiop, context); 6738 } 6739 6740 return error; 6741 6742} 6743 6744static int 6745smb2fs_smb_request_resume_key(struct smb_share *share, SMBFID fid, u_char *resume_key, 6746 vfs_context_t context) 6747{ 6748 struct smb2_ioctl_rq *ioctlp = NULL; 6749 int error = 0; 6750 6751 /* 6752 * Build the IOCTL request 6753 */ 6754 SMB_MALLOC(ioctlp, 6755 struct smb2_ioctl_rq *, 6756 sizeof(struct smb2_ioctl_rq), 6757 M_SMBTEMP, 6758 M_WAITOK | M_ZERO); 6759 if (ioctlp == NULL) { 6760 SMBERROR("SMB_MALLOC failed\n"); 6761 error = ENOMEM; 6762 goto bad; 6763 } 6764 6765 ioctlp->share = share; 6766 ioctlp->ctl_code = FSCTL_SRV_REQUEST_RESUME_KEY; 6767 ioctlp->fid = fid; 6768 6769 ioctlp->snd_input_len = 0; 6770 ioctlp->snd_output_len = 0; 6771 ioctlp->rcv_input_len = 0; 6772 ioctlp->rcv_output_len = 0x20; 6773 6774 error = smb2_smb_ioctl(share, ioctlp, NULL, context); 6775 6776 if (!error) { 6777 memcpy(resume_key, ioctlp->rcv_output_buffer, SMB2_RESUME_KEY_LEN); 6778 SMB_FREE(ioctlp->rcv_output_buffer, M_TEMP); 6779 } 6780 6781bad: 6782 if (ioctlp != NULL) { 6783 SMB_FREE(ioctlp, M_SMBTEMP); 6784 } 6785 6786 return (error); 6787} 6788 6789/* 6790 * The calling routine must hold a reference on the share 6791 */ 6792int 6793smbfs_smb_rmdir(struct smb_share *share, struct smbnode *np, 6794 vfs_context_t context) 6795{ 6796 int error; 6797 6798 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 6799 error = smb2fs_smb_delete (share, np, VDIR, 6800 NULL, 0, 6801 0, context); 6802 } 6803 else { 6804 error = smb1fs_smb_rmdir (share, np, context); 6805 } 6806 6807 return error; 6808} 6809 6810int 6811smb2fs_smb_security_get(struct smb_share *share, struct smbnode *np, 6812 uint32_t desired_access, uint32_t security_attrs, 6813 struct ntsecdesc **resp, uint32_t *resp_len, 6814 vfs_context_t context) 6815{ 6816 int error; 6817 enum vtype vnode_type = VREG; 6818 6819 /* Try to determine the vnode type for the Create Request */ 6820 6821 if ((np) && (np->n_vnode)) { 6822 /* Use vnode to determine type */ 6823 vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG; 6824 } 6825 6826 /* 6827 * Do the Compound Create/QueryInfo/Close call 6828 */ 6829 error = smb2fs_smb_cmpd_query(share, np, vnode_type, 6830 NULL, 0, 6831 0, desired_access, 6832 SMB2_0_INFO_SECURITY, 0, 6833 security_attrs, NULL, 6834 resp_len, (uint8_t *) resp, 6835 context); 6836 if (error) { 6837 SMBDEBUG("smb2fs_smb_cmpd_query failed %d\n", error); 6838 } 6839 6840 return error; 6841} 6842 6843int 6844smb2fs_smb_security_set(struct smb_share *share, struct smbnode *np, 6845 uint32_t desired_access, 6846 uint32_t security_attrs, uint16_t control_flags, 6847 struct ntsid *owner, struct ntsid *group, 6848 struct ntacl *sacl, struct ntacl *dacl, 6849 vfs_context_t context) 6850{ 6851 int error; 6852 uint32_t setinfo_ntstatus; 6853 struct smb2_set_info_security sec_info; 6854 enum vtype vnode_type = VREG; 6855 6856 /* 6857 * Set up for the Set Info call 6858 */ 6859 sec_info.security_attrs = security_attrs; 6860 sec_info.control_flags = control_flags; 6861 sec_info.owner = owner; 6862 sec_info.group = group; 6863 sec_info.sacl = sacl; 6864 sec_info.dacl = dacl; 6865 6866 if ((np) && (np->n_vnode)) { 6867 /* Use vnode to determine type */ 6868 vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG; 6869 } 6870 6871 /* 6872 * Do the Compound Create/SetInfo/Close call 6873 */ 6874 error = smb2fs_smb_cmpd_set_info(share, np, vnode_type, 6875 NULL, 0, 6876 0, desired_access, 6877 SMB2_0_INFO_SECURITY, 0, 6878 security_attrs, 6879 sizeof (sec_info), (uint8_t *) &sec_info, 6880 &setinfo_ntstatus, 6881 context); 6882 if (error) { 6883 SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d, ntstatus 0x%x\n", 6884 error, setinfo_ntstatus); 6885 6886 if (setinfo_ntstatus == STATUS_INVALID_SID) { 6887 /* 6888 * If the server returns STATUS_INVALID_SID, then just pretend 6889 * that we set the security info even though it "failed". 6890 * See <rdar://problem/10852453>. 6891 */ 6892 error = 0; 6893 } 6894 } 6895 6896 return error; 6897} 6898 6899int 6900smbfs_smb_setsec(struct smb_share *share, struct smbnode *np, 6901 uint32_t desired_access, SMBFID fid, 6902 uint32_t selector, uint16_t control_flags, 6903 struct ntsid *owner, struct ntsid *group, 6904 struct ntacl *sacl, struct ntacl *dacl, 6905 vfs_context_t context) 6906{ 6907 int error; 6908 6909 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 6910 error = smb2fs_smb_security_set(share, np, desired_access, 6911 selector, control_flags, 6912 owner, group, 6913 sacl, dacl, 6914 context); 6915 } 6916 else { 6917 error = smb1fs_setsec(share, fid, selector, control_flags, 6918 owner, group, sacl, dacl, context); 6919 } 6920 6921 return (error); 6922} 6923 6924static int 6925smb2fs_smb_set_allocation(struct smb_share *share, SMBFID fid, 6926 uint64_t new_size, vfs_context_t context) 6927{ 6928 int error; 6929 struct smb2_set_info_rq *infop = NULL; 6930 6931 SMB_MALLOC(infop, 6932 struct smb2_set_info_rq *, 6933 sizeof(struct smb2_set_info_rq), 6934 M_SMBTEMP, 6935 M_WAITOK | M_ZERO); 6936 if (infop == NULL) { 6937 SMBERROR("SMB_MALLOC failed\n"); 6938 error = ENOMEM; 6939 goto bad; 6940 } 6941 6942 /* 6943 * Set up for the Set Info call 6944 */ 6945 infop->info_type = SMB2_0_INFO_FILE; 6946 infop->file_info_class = FileAllocationInformation; 6947 infop->add_info = 0; 6948 infop->fid = fid; 6949 infop->input_buffer = (uint8_t *) &new_size; 6950 6951 error = smb2_smb_set_info(share, infop, NULL, context); 6952 if (error) { 6953 SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n", 6954 error, 6955 infop->ret_ntstatus); 6956 goto bad; 6957 } 6958 6959bad: 6960 if (infop != NULL) { 6961 SMB_FREE(infop, M_SMBTEMP); 6962 } 6963 6964 return error; 6965} 6966 6967/* 6968 * This routine will send an allocation across the wire to the server. 6969 * 6970 * The calling routine must hold a reference on the share 6971 * 6972 */ 6973int 6974smbfs_smb_set_allocation(struct smb_share *share, SMBFID fid, uint64_t new_size, 6975 vfs_context_t context) 6976{ 6977 int error; 6978 6979 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 6980 error = smb2fs_smb_set_allocation(share, fid, new_size, context); 6981 } 6982 else { 6983 error = smb1fs_set_allocation(share, fid, new_size, context); 6984 } 6985 return error; 6986} 6987 6988 6989static int 6990smb2fs_smb_set_eof(struct smb_share *share, SMBFID fid, uint64_t newsize, 6991 vfs_context_t context) 6992{ 6993 int error; 6994 struct smb2_set_info_rq *infop = NULL; 6995 6996 SMB_MALLOC(infop, 6997 struct smb2_set_info_rq *, 6998 sizeof(struct smb2_set_info_rq), 6999 M_SMBTEMP, 7000 M_WAITOK | M_ZERO); 7001 if (infop == NULL) { 7002 SMBERROR("SMB_MALLOC failed\n"); 7003 error = ENOMEM; 7004 goto bad; 7005 } 7006 7007 /* 7008 * Set up for the Set Info call 7009 */ 7010 infop->info_type = SMB2_0_INFO_FILE; 7011 infop->file_info_class = FileEndOfFileInformation; 7012 infop->add_info = 0; 7013 infop->fid = fid; 7014 infop->input_buffer = (uint8_t *) &newsize; 7015 7016 /* 7017 * Do the Set Info call 7018 */ 7019 error = smb2_smb_set_info(share, infop, NULL, context); 7020 if (error) { 7021 SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n", 7022 error, 7023 infop->ret_ntstatus); 7024 goto bad; 7025 } 7026 7027bad: 7028 if (infop != NULL) { 7029 SMB_FREE(infop, M_SMBTEMP); 7030 } 7031 7032 return error; 7033} 7034 7035/* 7036 * This routine will send a seteof across the wire to the server. 7037 * 7038 * The calling routine must hold a reference on the share 7039 * 7040 */ 7041int 7042smbfs_smb_seteof(struct smb_share *share, SMBFID fid, uint64_t newsize, 7043 vfs_context_t context) 7044{ 7045 int error; 7046 7047 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 7048 error = smb2fs_smb_set_eof(share, fid, newsize, context); 7049 } 7050 else { 7051 error = smb1fs_seteof(share, fid, newsize, context); 7052 } 7053 return error; 7054} 7055 7056static int 7057smb2fs_smb_set_file_basic_info(struct smb_share *share, 7058 struct smb2_set_info_file_basic_info **infopp, 7059 struct timespec *crtime, struct timespec *atime, 7060 struct timespec *mtime, uint32_t file_attrs) 7061{ 7062 uint64_t tm; 7063 7064 SMB_MALLOC(*infopp, 7065 struct smb2_set_info_file_basic_info *, 7066 sizeof(struct smb2_set_info_file_basic_info), 7067 M_SMBTEMP, 7068 M_WAITOK | M_ZERO); 7069 if (*infopp == NULL) { 7070 SMBERROR("SMB_MALLOC failed\n"); 7071 return (ENOMEM); 7072 } 7073 7074 /* 7075 * Set Creation time 7076 */ 7077 tm = 0; 7078 if (crtime) { 7079 smb_time_local2NT(crtime, &tm, (share->ss_fstype == SMB_FS_FAT)); 7080 (*infopp)->create_time = tm; 7081 } 7082 7083 /* Set last access time */ 7084 tm = 0; 7085 if (atime) { 7086 smb_time_local2NT(atime, &tm, (share->ss_fstype == SMB_FS_FAT)); 7087 (*infopp)->access_time = tm; 7088 } 7089 7090 /* Set last write time */ 7091 tm = 0; 7092 if (mtime) { 7093 smb_time_local2NT(mtime, &tm, (share->ss_fstype == SMB_FS_FAT)); 7094 (*infopp)->write_time = tm; 7095 } 7096 7097 /* We never allow anyone to set the change time */ 7098 7099 /* set file attributes */ 7100 (*infopp)->attributes = file_attrs; 7101 7102 return (0); 7103} 7104 7105static int 7106smb2fs_smb_setfattrNT(struct smb_share *share, uint32_t attr, SMBFID fid, 7107 struct timespec *crtime, struct timespec *mtime, 7108 struct timespec *atime, vfs_context_t context) 7109{ 7110 int error; 7111 struct smb2_set_info_rq *infop = NULL; 7112 struct smb2_set_info_file_basic_info *basic_infop = NULL; 7113 7114 /* Allocate and fill out the file basic info */ 7115 error = smb2fs_smb_set_file_basic_info(share, &basic_infop, 7116 crtime, atime, mtime, attr); 7117 if (error) { 7118 SMBDEBUG("smb2fs_smb_set_file_basic_info failed %d\n", error); 7119 goto bad; 7120 } 7121 7122 SMB_MALLOC(infop, 7123 struct smb2_set_info_rq *, 7124 sizeof(struct smb2_set_info_rq), 7125 M_SMBTEMP, 7126 M_WAITOK | M_ZERO); 7127 if (infop == NULL) { 7128 SMBERROR("SMB_MALLOC failed\n"); 7129 error = ENOMEM; 7130 goto bad; 7131 } 7132 7133 /* 7134 * Set up for the Set Info call 7135 */ 7136 infop->info_type = SMB2_0_INFO_FILE; 7137 infop->file_info_class = FileBasicInformation; 7138 infop->add_info = 0; 7139 infop->fid = fid; 7140 infop->input_buffer = (uint8_t *) basic_infop; 7141 7142 /* 7143 * Do the Set Info call 7144 */ 7145 error = smb2_smb_set_info(share, infop, NULL, context); 7146 if (error) { 7147 SMBDEBUG("smb2_smb_set_info failed %d ntstatus %d\n", 7148 error, 7149 infop->ret_ntstatus); 7150 goto bad; 7151 } 7152 7153bad: 7154 if (infop != NULL) { 7155 SMB_FREE(infop, M_SMBTEMP); 7156 } 7157 7158 if (basic_infop != NULL) { 7159 SMB_FREE(basic_infop, M_SMBTEMP); 7160 } 7161 7162 return error; 7163} 7164 7165/* 7166 * Same as smbfs_smb_setpattrNT except with a file handle. Note once we remove 7167 * Windows 98 support we can remove passing the node into this routine. 7168 * 7169 * The calling routine must hold a reference on the share 7170 * 7171 */ 7172int 7173smbfs_smb_setfattrNT(struct smb_share *share, uint32_t attr, SMBFID fid, 7174 struct timespec *crtime, struct timespec *mtime, 7175 struct timespec *atime, vfs_context_t context) 7176{ 7177 int error; 7178 7179 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 7180 error = smb2fs_smb_setfattrNT(share, attr, fid, crtime, mtime, atime, 7181 context); 7182 } 7183 else { 7184 error = smb1fs_smb_setfattrNT(share, attr, fid, crtime, mtime, atime, 7185 context); 7186 } 7187 return error; 7188} 7189 7190/* 7191 * Set DOS file attributes, may want to replace with a more modern call 7192 * 7193 * The calling routine must hold a reference on the share 7194 * 7195 */ 7196int 7197smbfs_smb_setpattr(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 7198 const char *namep, size_t name_len, 7199 uint16_t attr, vfs_context_t context) 7200{ 7201 int error; 7202 7203 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 7204 error = smb2fs_smb_setpattrNT(share, np, vnode_type, 7205 namep, name_len, 7206 attr, NULL, 7207 NULL, NULL, 7208 context); 7209 } 7210 else { 7211 error = smb1fs_smb_setpattr(share, np, 7212 namep, name_len, 7213 attr, context); 7214 } 7215 return error; 7216} 7217 7218int 7219smb2fs_smb_setpattrNT(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 7220 const char *namep, size_t name_len, 7221 uint32_t attr, struct timespec *crtime, 7222 struct timespec *mtime, struct timespec *atime, 7223 vfs_context_t context) 7224{ 7225 int error; 7226 uint32_t setinfo_ntstatus; 7227 struct smb2_set_info_file_basic_info *basic_infop = NULL; 7228 7229 /* Allocate and fill out the file basic info */ 7230 error = smb2fs_smb_set_file_basic_info(share, &basic_infop, 7231 crtime, atime, mtime, attr); 7232 if (error) { 7233 SMBDEBUG("smb2fs_smb_set_file_basic_info failed %d\n", error); 7234 goto bad; 7235 } 7236 7237 /* 7238 * Do the Compound Create/SetInfo/Close call 7239 */ 7240 error = smb2fs_smb_cmpd_set_info(share, np, vnode_type, 7241 namep, name_len, 7242 0, SMB2_FILE_WRITE_ATTRIBUTES | SMB2_SYNCHRONIZE, 7243 SMB2_0_INFO_FILE, FileBasicInformation, 7244 0, 7245 sizeof (*basic_infop), (uint8_t *) basic_infop, 7246 &setinfo_ntstatus, 7247 context); 7248 if (error) { 7249 SMBDEBUG("smb2fs_smb_cmpd_set_info failed %d\n", error); 7250 goto bad; 7251 } 7252 7253bad: 7254 if (basic_infop != NULL) { 7255 SMB_FREE(basic_infop, M_SMBTEMP); 7256 } 7257 7258 return error; 7259} 7260 7261/* 7262 * BASIC_INFO works with Samba, but Win2K servers say it is an invalid information 7263 * level on a SET_PATH_INFO. Note Win2K does support *BASIC_INFO on a SET_FILE_INFO, 7264 * and they support the equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure. 7265 * 7266 * The calling routine must hold a reference on the share 7267 * 7268 */ 7269int 7270smbfs_smb_setpattrNT(struct smb_share *share, struct smbnode *np, enum vtype vnode_type, 7271 const char *namep, size_t name_len, 7272 uint32_t attr, struct timespec *crtime, 7273 struct timespec *mtime, struct timespec *atime, 7274 vfs_context_t context) 7275{ 7276 int error; 7277 7278 if (SSTOVC(share)->vc_flags & SMBV_SMB2) { 7279 error = smb2fs_smb_setpattrNT(share, np, vnode_type, 7280 namep, name_len, 7281 attr, crtime, 7282 mtime, atime, 7283 context); 7284 } 7285 else { 7286 error = smb1fs_smb_setpattrNT(share, np, attr, crtime, mtime, atime, 7287 context); 7288 } 7289 return error; 7290} 7291 7292static int 7293smb2fs_smb_statfs(struct smbmount *smp, 7294 struct FILE_FS_SIZE_INFORMATION *fs_size, 7295 vfs_context_t context) 7296{ 7297 struct smb_share *share = smp->sm_share; 7298 int error; 7299 uint32_t output_buffer_len; 7300 7301 output_buffer_len = sizeof(struct FILE_FS_SIZE_INFORMATION); 7302 7303 /* 7304 * Do the Compound Create/GetInfo/Close call 7305 * Query results are passed back in *fs_size 7306 * 7307 * Have to pass in submount path if it exists because we have no root vnode, 7308 * and smbmount and smb_share may not be fully set up yet. 7309 * 7310 * This is always done on the root of the share. 7311 */ 7312 error = smb2fs_smb_cmpd_query(share, NULL, VDIR, 7313 (smp->sm_args.path_len == 0 ? NULL : smp->sm_args.path), 7314 smp->sm_args.path_len, 7315 0, SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE, 7316 SMB2_0_INFO_FILESYSTEM, FileFsSizeInformation, 7317 0, NULL, 7318 &output_buffer_len, (uint8_t *) fs_size, 7319 context); 7320 7321 return error; 7322} 7323 7324/* 7325 * The calling routine must hold a reference on the share 7326 */ 7327int 7328smbfs_smb_statfs(struct smbmount *smp, struct vfsstatfs *sbp, 7329 vfs_context_t context) 7330{ 7331 struct smb_share *share = smp->sm_share; 7332 struct smb_vc *vcp = SSTOVC(share); 7333 struct FILE_FS_SIZE_INFORMATION fs_size; 7334 int error; 7335 uint64_t s, t, f; 7336 size_t xmax; 7337 7338 bzero(&fs_size, sizeof(fs_size)); 7339 7340 if (vcp->vc_flags & SMBV_SMB2) { 7341 error = smb2fs_smb_statfs(smp, &fs_size, context); 7342 } 7343 else { 7344 /* 7345 * Goal is to leave the SMB 1 code unchanged as much as possible 7346 * to minimize the risk. That is why there is duplicate code here 7347 * for the SMB 2/3 path and also in SMB 1 code path. 7348 */ 7349 error = smb1fs_statfs(share, sbp, context); 7350 return (error); 7351 } 7352 7353 if (error) { 7354 return error; 7355 } 7356 7357 t = fs_size.total_alloc_units; 7358 f = fs_size.avail_alloc_units; 7359 s = fs_size.bytes_per_sector; 7360 s *= fs_size.sectors_per_alloc_unit; 7361 /* 7362 * Don't allow over-large blocksizes as they determine 7363 * Finder List-view size granularities. On the other 7364 * hand, we mustn't let the block count overflow the 7365 * 31 bits available. 7366 */ 7367 while (s > 16 * 1024) { 7368 if (t > LONG_MAX) 7369 break; 7370 s /= 2; 7371 t *= 2; 7372 f *= 2; 7373 } 7374 while (t > LONG_MAX) { 7375 t /= 2; 7376 f /= 2; 7377 s *= 2; 7378 } 7379 sbp->f_bsize = (uint32_t)s; /* fundamental file system block size */ 7380 sbp->f_blocks= t; /* total data blocks in file system */ 7381 sbp->f_bfree = f; /* free blocks in fs */ 7382 sbp->f_bavail= f; /* free blocks avail to non-superuser */ 7383 sbp->f_files = (-1); /* total file nodes in file system */ 7384 sbp->f_ffree = (-1); /* free file nodes in fs */ 7385 7386 /* 7387 * Done with the network stuff, now get the iosize. This code was moved from 7388 * smbfs_vfs_getattr to here 7389 * 7390 * The min size of f_iosize is 1 MB and the max is SMB_IOMAX. 7391 * 7392 * We used to report back a multiple of the max io size supported by the 7393 * server and then read/write that amount in synchronous calls (SMB 1 still 7394 * does this). Now, we just let the applications decide how large and how 7395 * many IO blocks they want to give us. Finder will scale up to 8 MB IO 7396 * blocks depending on the transfer times for each block. UBC will give us 7397 * multiple blocks of f_iosize depending on their internal logic. UBC gets 7398 * the f_iosize from us because we call vfs_setioattr(). 7399 */ 7400 xmax = max(SSTOVC(share)->vc_rxmax, SSTOVC(share)->vc_wxmax); 7401 7402 /* 7403 * <Is this still needed???> 7404 * Now we want to make sure it will land on both a PAGE_SIZE boundary and a 7405 * smb xfer size boundary. So first mod the xfer size by the page size, then 7406 * subtract that from page size. This will give us the extra amount that 7407 * will be needed to get it on a page boundary. Now divide the page size by 7408 * this amount. This will give us the number of xmax it will take to make 7409 * f_iosize land on a page size and xfer boundary. 7410 */ 7411 xmax = (PAGE_SIZE / (PAGE_SIZE - (xmax % PAGE_SIZE))) * xmax; 7412 7413 if (xmax < SMB_IOMIN) { 7414 xmax = SMB_IOMIN; 7415 } 7416 7417 if (xmax > SMB_IOMAX) 7418 sbp->f_iosize = SMB_IOMAX; 7419 else 7420 sbp->f_iosize = xmax; 7421 7422 return error; 7423} 7424 7425int 7426smb2fs_smb_validate_neg_info(struct smb_share *share, vfs_context_t context) 7427{ 7428 struct smb_vc *vcp = SSTOVC(share); 7429 int error = 0; 7430 struct smb2_ioctl_rq *ioctlp = NULL; 7431 struct smb2_secure_neg_info req; 7432 struct smb2_secure_neg_info reply; 7433 struct smb_sopt *sp = NULL; 7434 7435 if (vcp == NULL) { 7436 SMBERROR("vcp is null \n"); 7437 return EINVAL; 7438 } 7439 7440 /* 7441 * Only SMB 3.x and non Anonymous/Guest supports validate negotiate 7442 */ 7443 if (!(vcp->vc_flags & SMBV_SMB2) || 7444 (vcp->vc_flags & (SMBV_SMB2002 | SMBV_SMB21)) || 7445 (vcp->vc_flags & SMBV_ANONYMOUS_ACCESS) || 7446 (vcp->vc_flags & SMBV_GUEST_ACCESS)) { 7447 return 0; 7448 } 7449 7450 sp = &vcp->vc_sopt; 7451 if (sp == NULL) { 7452 SMBERROR("sp is null \n"); 7453 return EINVAL; 7454 } 7455 7456 bzero(&req, sizeof(req)); 7457 bzero(&reply, sizeof(reply)); 7458 7459 SMB_MALLOC(ioctlp, 7460 struct smb2_ioctl_rq *, 7461 sizeof(struct smb2_ioctl_rq), 7462 M_SMBTEMP, 7463 M_WAITOK | M_ZERO); 7464 if (ioctlp == NULL) { 7465 SMBERROR("SMB_MALLOC failed\n"); 7466 error = ENOMEM; 7467 goto bad; 7468 } 7469 7470 /* 7471 * Fill in the Secure Negotiate Request Info 7472 */ 7473 req.capabilities = smb2_smb_get_client_capabilities(vcp); 7474 memcpy(&req.guid, vcp->vc_client_guid, 16); 7475 req.security_mode = smb2_smb_get_client_security_mode(vcp); 7476 7477 error = smb2_smb_get_client_dialects(vcp, 0, &req.dialect_count, 7478 req.dialects, sizeof(req.dialects)); 7479 if (error) { 7480 return error; 7481 } 7482 7483 /* 7484 * Build and send the IOCTL request 7485 */ 7486 ioctlp->share = share; 7487 ioctlp->ctl_code = FSCTL_VALIDATE_NEGOTIATE_INFO; 7488 ioctlp->fid = 0; 7489 7490 ioctlp->snd_output_len = 0; 7491 ioctlp->rcv_input_len = 0; 7492 7493 /* 7494 * Calculate len of Validate Negotiate Request 7495 * 24 = Capabilities (4) + GUID (16) + SecurityMode (2) + DialectCount (2) 7496 * +2 bytes per Dialect added 7497 */ 7498 ioctlp->snd_input_len = 24; 7499 ioctlp->snd_input_len += 2 * req.dialect_count; 7500 ioctlp->snd_input_buffer = (uint8_t *) &req; 7501 7502 ioctlp->rcv_output_len = sizeof(reply); 7503 ioctlp->rcv_output_buffer = (uint8_t *) &reply; 7504 7505 error = smb2_smb_ioctl(share, ioctlp, NULL, context); 7506 if (error) { 7507 if ((error == EINVAL) || (error == ENOTSUP)) { 7508 /* 7509 * A signed reply with STATUS_NOT_SUPPORTED is acceptable, but 7510 * we can not validate the server capabilites. Just leave with 7511 * no error and without checking capabilities. 7512 * 7513 * NetApp is returning STATUS_INVALID_DEVICE_REQUEST instead which 7514 * is not correct. 7515 */ 7516 SMBWARNING("Server does not fully support Validate Negotiate %d\n", error); 7517 error = 0; 7518 } 7519 else { 7520 SMBERROR("smb2_smb_ioctl failed %d\n", error); 7521 } 7522 7523 goto bad; 7524 } 7525 7526 /* Verify that the server info matches our current session */ 7527 7528 /* Check Capabilities */ 7529 if (reply.capabilities != sp->sv_capabilities) { 7530 SMBERROR("Server capabilities do not match \n"); 7531 error = EAUTH; 7532 goto bad; 7533 } 7534 7535 /* Check GUID */ 7536 if (memcmp(&reply.guid, &sp->sv_guid, sizeof(reply.guid)) != 0) { 7537 SMBERROR("Server GUID does not match \n"); 7538 error = EAUTH; 7539 goto bad; 7540 } 7541 7542 /* Check Security Mode */ 7543 if (reply.security_mode != sp->sv_security_mode) { 7544 SMBERROR("Server security mode does not match \n"); 7545 error = EAUTH; 7546 goto bad; 7547 } 7548 7549 /* Check Dialect */ 7550 switch (reply.dialects[0]) { 7551 case SMB2_DIALECT_0302: 7552 if (!(vcp->vc_flags & (SMBV_SMB2 | SMBV_SMB302))) { 7553 SMBERROR("Server dialect does not match \n"); 7554 error = EAUTH; 7555 } 7556 break; 7557 case SMB2_DIALECT_0300: 7558 if (!(vcp->vc_flags & (SMBV_SMB2 | SMBV_SMB30))) { 7559 SMBERROR("Server dialect does not match \n"); 7560 error = EAUTH; 7561 } 7562 break; 7563 case SMB2_DIALECT_0210: 7564 if (!(vcp->vc_flags & (SMBV_SMB2 | SMBV_SMB21))) { 7565 SMBERROR("Server dialect does not match \n"); 7566 error = EAUTH; 7567 } 7568 break; 7569 case SMB2_DIALECT_0202: 7570 if (!(vcp->vc_flags & (SMBV_SMB2 | SMBV_SMB2002))) { 7571 SMBERROR("Server dialect does not match \n"); 7572 error = EAUTH; 7573 } 7574 break; 7575 7576 default: 7577 SMBERROR("Unknown server dialect does not match \n"); 7578 error = EAUTH; 7579 break; 7580 } 7581 7582bad: 7583 if (ioctlp != NULL) { 7584 SMB_FREE(ioctlp, M_SMBTEMP); 7585 } 7586 7587 return error; 7588} 7589 7590