1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <smbsrv/smb_vops.h> 27 #include <smbsrv/smb_incl.h> 28 #include <smbsrv/smb_fsops.h> 29 30 /* 31 * Trans2 Query File/Path Information Levels: 32 * 33 * SMB_INFO_STANDARD 34 * SMB_INFO_QUERY_EA_SIZE 35 * SMB_INFO_QUERY_EAS_FROM_LIST 36 * SMB_INFO_QUERY_ALL_EAS - not valid for pipes 37 * SMB_INFO_IS_NAME_VALID - only valid when query is by path 38 * 39 * SMB_QUERY_FILE_BASIC_INFO 40 * SMB_QUERY_FILE_STANDARD_INFO 41 * SMB_QUERY_FILE_EA_INFO 42 * SMB_QUERY_FILE_NAME_INFO 43 * SMB_QUERY_FILE_ALL_INFO 44 * SMB_QUERY_FILE_ALT_NAME_INFO - not valid for pipes 45 * SMB_QUERY_FILE_STREAM_INFO - not valid for pipes 46 * SMB_QUERY_FILE_COMPRESSION_INFO - not valid for pipes 47 * 48 * Supported Passthrough levels: 49 * SMB_FILE_BASIC_INFORMATION 50 * SMB_FILE_STANDARD_INFORMATION 51 * SMB_FILE_INTERNAL_INFORMATION 52 * SMB_FILE_EA_INFORMATION 53 * SMB_FILE_ACCESS_INFORMATION - not yet supported quen query by path 54 * SMB_FILE_NAME_INFORMATION 55 * SMB_FILE_ALL_INFORMATION 56 * SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes 57 * SMB_FILE_STREAM_INFORMATION - not valid for pipes 58 * SMB_FILE_COMPRESSION_INFORMATION - not valid for pipes 59 * SMB_FILE_ATTR_TAG_INFORMATION - not valid for pipes 60 * 61 * Internal levels representing non trans2 requests 62 * SMB_QUERY_INFORMATION 63 * SMB_QUERY_INFORMATION2 64 */ 65 66 typedef struct smb_queryinfo { 67 smb_node_t *qi_node; /* NULL for pipes */ 68 smb_attr_t qi_attr; 69 boolean_t qi_delete_on_close; 70 uint32_t qi_namelen; 71 char qi_name83[SMB_SHORTNAMELEN]; 72 char qi_shortname[SMB_SHORTNAMELEN]; 73 char qi_name[MAXPATHLEN]; 74 } smb_queryinfo_t; 75 #define qi_mtime qi_attr.sa_vattr.va_mtime 76 #define qi_ctime qi_attr.sa_vattr.va_ctime 77 #define qi_atime qi_attr.sa_vattr.va_atime 78 #define qi_crtime qi_attr.sa_crtime 79 80 static int smb_query_by_fid(smb_request_t *, smb_xa_t *, uint16_t); 81 static int smb_query_by_path(smb_request_t *, smb_xa_t *, 82 uint16_t, char *); 83 84 static int smb_query_fileinfo(smb_request_t *, smb_node_t *, 85 uint16_t, smb_queryinfo_t *); 86 static int smb_query_pipeinfo(smb_request_t *, smb_opipe_t *, 87 uint16_t, smb_queryinfo_t *); 88 static boolean_t smb_query_pipe_valid_infolev(smb_request_t *, uint16_t); 89 90 static int smb_query_encode_response(smb_request_t *, smb_xa_t *, 91 uint16_t, smb_queryinfo_t *); 92 static void smb_encode_stream_info(smb_request_t *, smb_xa_t *, 93 smb_queryinfo_t *); 94 static int smb_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t); 95 uint32_t smb_pad_align(uint32_t offset, uint32_t align); 96 97 98 /* 99 * smb_com_trans2_query_file_information 100 */ 101 smb_sdrc_t 102 smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa) 103 { 104 uint16_t infolev; 105 106 if (smb_mbc_decodef(&xa->req_param_mb, "ww", 107 &sr->smb_fid, &infolev) != 0) 108 return (SDRC_ERROR); 109 110 if (smb_query_by_fid(sr, xa, infolev) != 0) 111 return (SDRC_ERROR); 112 113 return (SDRC_SUCCESS); 114 } 115 116 /* 117 * smb_com_trans2_query_path_information 118 */ 119 smb_sdrc_t 120 smb_com_trans2_query_path_information(smb_request_t *sr, smb_xa_t *xa) 121 { 122 uint16_t infolev; 123 char *path; 124 125 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 126 smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, 127 ERRDOS, ERROR_INVALID_FUNCTION); 128 return (SDRC_ERROR); 129 } 130 131 if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u", 132 sr, &infolev, &path) != 0) 133 return (SDRC_ERROR); 134 135 if (smb_query_by_path(sr, xa, infolev, path) != 0) 136 return (SDRC_ERROR); 137 138 return (SDRC_SUCCESS); 139 } 140 141 /* 142 * smb_com_query_information (aka getattr) 143 */ 144 smb_sdrc_t 145 smb_pre_query_information(smb_request_t *sr) 146 { 147 int rc; 148 smb_fqi_t *fqi = &sr->arg.dirop.fqi; 149 150 rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path); 151 152 DTRACE_SMB_2(op__QueryInformation__start, smb_request_t *, sr, 153 smb_fqi_t *, fqi); 154 155 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 156 } 157 158 void 159 smb_post_query_information(smb_request_t *sr) 160 { 161 DTRACE_SMB_1(op__QueryInformation__done, smb_request_t *, sr); 162 } 163 164 smb_sdrc_t 165 smb_com_query_information(smb_request_t *sr) 166 { 167 char *path = sr->arg.dirop.fqi.fq_path.pn_path; 168 uint16_t infolev = SMB_QUERY_INFORMATION; 169 170 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 171 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 172 ERRDOS, ERROR_ACCESS_DENIED); 173 return (SDRC_ERROR); 174 } 175 176 if (smb_query_by_path(sr, NULL, infolev, path) != 0) 177 return (SDRC_ERROR); 178 179 return (SDRC_SUCCESS); 180 } 181 182 /* 183 * smb_com_query_information2 (aka getattre) 184 */ 185 smb_sdrc_t 186 smb_pre_query_information2(smb_request_t *sr) 187 { 188 int rc; 189 rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid); 190 191 DTRACE_SMB_1(op__QueryInformation2__start, smb_request_t *, sr); 192 193 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 194 } 195 196 void 197 smb_post_query_information2(smb_request_t *sr) 198 { 199 DTRACE_SMB_1(op__QueryInformation2__done, smb_request_t *, sr); 200 } 201 202 smb_sdrc_t 203 smb_com_query_information2(smb_request_t *sr) 204 { 205 uint16_t infolev = SMB_QUERY_INFORMATION2; 206 207 if (smb_query_by_fid(sr, NULL, infolev) != 0) 208 return (SDRC_ERROR); 209 210 return (SDRC_SUCCESS); 211 } 212 213 /* 214 * smb_query_by_fid 215 * 216 * Common code for querying file information by open file (or pipe) id. 217 * Use the id to identify the node / pipe object and request the 218 * smb_queryinfo_t data for that object. 219 */ 220 static int 221 smb_query_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev) 222 { 223 int rc; 224 smb_queryinfo_t *qinfo; 225 smb_node_t *node; 226 smb_opipe_t *opipe; 227 228 smbsr_lookup_file(sr); 229 230 if (sr->fid_ofile == NULL) { 231 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 232 return (-1); 233 } 234 235 if (infolev == SMB_INFO_IS_NAME_VALID) { 236 smbsr_error(sr, 0, ERRDOS, ERRunknownlevel); 237 smbsr_release_file(sr); 238 return (-1); 239 } 240 241 if ((sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE) && 242 (!smb_query_pipe_valid_infolev(sr, infolev))) { 243 smbsr_release_file(sr); 244 return (-1); 245 } 246 247 qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP); 248 249 switch (sr->fid_ofile->f_ftype) { 250 case SMB_FTYPE_DISK: 251 node = sr->fid_ofile->f_node; 252 rc = smb_query_fileinfo(sr, node, infolev, qinfo); 253 break; 254 case SMB_FTYPE_MESG_PIPE: 255 opipe = sr->fid_ofile->f_pipe; 256 rc = smb_query_pipeinfo(sr, opipe, infolev, qinfo); 257 break; 258 default: 259 smbsr_error(sr, 0, ERRDOS, ERRbadfile); 260 rc = -1; 261 break; 262 } 263 264 if (rc == 0) 265 rc = smb_query_encode_response(sr, xa, infolev, qinfo); 266 267 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 268 smbsr_release_file(sr); 269 return (rc); 270 } 271 272 /* 273 * smb_query_by_path 274 * 275 * Common code for querying file information by file name. 276 * Use the file name to identify the node object and request the 277 * smb_queryinfo_t data for that node. 278 * 279 * Querying attributes on a named pipe by name is an error and 280 * is handled in the calling functions so that they can return 281 * the appropriate error status code (which differs by caller). 282 */ 283 static int 284 smb_query_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev, char *path) 285 { 286 smb_queryinfo_t *qinfo; 287 smb_node_t *node, *dnode; 288 int rc; 289 int len; 290 291 /* VALID, but not yet supported */ 292 if (infolev == SMB_FILE_ACCESS_INFORMATION) { 293 smbsr_error(sr, 0, ERRDOS, ERRunknownlevel); 294 return (-1); 295 } 296 297 /* 298 * Some MS clients pass NULL file names. NT interprets this as "\". 299 * Otherwise, if path is not "\\", remove the terminating slash. 300 */ 301 if ((len = strlen(path)) == 0) 302 path = "\\"; 303 else { 304 if ((len > 1) && (path[len - 1] == '\\')) { 305 path[len - 1] = 0; 306 } 307 } 308 309 qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP); 310 311 rc = smb_pathname_reduce(sr, sr->user_cr, path, sr->tid_tree->t_snode, 312 sr->tid_tree->t_snode, &dnode, qinfo->qi_name); 313 if (rc == 0) { 314 rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS, 315 sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node); 316 smb_node_release(dnode); 317 } 318 319 if (rc != 0) { 320 if (rc == ENOENT) 321 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 322 ERRDOS, ERROR_FILE_NOT_FOUND); 323 else 324 smbsr_errno(sr, rc); 325 326 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 327 return (-1); 328 } 329 330 rc = smb_query_fileinfo(sr, node, infolev, qinfo); 331 if (rc != 0) { 332 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 333 smb_node_release(node); 334 return (rc); 335 } 336 337 /* If delete_on_close - NT_STATUS_DELETE_PENDING */ 338 if (qinfo->qi_delete_on_close) { 339 smbsr_error(sr, NT_STATUS_DELETE_PENDING, 340 ERRDOS, ERROR_ACCESS_DENIED); 341 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 342 smb_node_release(node); 343 return (-1); 344 } 345 346 rc = smb_query_encode_response(sr, xa, infolev, qinfo); 347 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 348 smb_node_release(node); 349 return (rc); 350 } 351 352 /* 353 * smb_size32 354 * Some responses only support 32 bit file sizes. If the file size 355 * exceeds UINT_MAX (32 bit) we return UINT_MAX in the response. 356 */ 357 static uint32_t 358 smb_size32(u_offset_t size) 359 { 360 return ((size > UINT_MAX) ? UINT_MAX : (uint32_t)size); 361 } 362 363 /* 364 * smb_query_encode_response 365 * 366 * Encode the data from smb_queryinfo_t into client response 367 */ 368 int 369 smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa, 370 uint16_t infolev, smb_queryinfo_t *qinfo) 371 { 372 uint16_t dattr; 373 u_offset_t datasz, allocsz; 374 375 dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK; 376 datasz = qinfo->qi_attr.sa_vattr.va_size; 377 allocsz = qinfo->qi_attr.sa_allocsz; 378 379 switch (infolev) { 380 case SMB_QUERY_INFORMATION: 381 (void) smbsr_encode_result(sr, 10, 0, "bwll10.w", 382 10, 383 dattr, 384 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), 385 smb_size32(datasz), 386 0); 387 break; 388 389 case SMB_QUERY_INFORMATION2: 390 (void) smbsr_encode_result(sr, 11, 0, "byyyllww", 391 11, 392 smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec), 393 smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec), 394 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), 395 smb_size32(datasz), smb_size32(allocsz), dattr, 0); 396 break; 397 398 case SMB_FILE_ACCESS_INFORMATION: 399 ASSERT(sr->fid_ofile); 400 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 401 sr->fid_ofile->f_granted_access); 402 break; 403 404 case SMB_INFO_STANDARD: 405 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 406 (void) smb_mbc_encodef(&xa->rep_data_mb, 407 ((sr->session->native_os == NATIVE_OS_WIN95) ? 408 "YYYllw" : "yyyllw"), 409 smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec), 410 smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec), 411 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), 412 smb_size32(datasz), smb_size32(allocsz), dattr); 413 break; 414 415 case SMB_INFO_QUERY_EA_SIZE: 416 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 417 (void) smb_mbc_encodef(&xa->rep_data_mb, 418 ((sr->session->native_os == NATIVE_OS_WIN95) ? 419 "YYYllwl" : "yyyllwl"), 420 smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec), 421 smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec), 422 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), 423 smb_size32(datasz), smb_size32(allocsz), dattr, 0); 424 break; 425 426 case SMB_INFO_QUERY_ALL_EAS: 427 case SMB_INFO_QUERY_EAS_FROM_LIST: 428 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 429 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0); 430 break; 431 432 case SMB_INFO_IS_NAME_VALID: 433 break; 434 435 case SMB_QUERY_FILE_BASIC_INFO: 436 case SMB_FILE_BASIC_INFORMATION: 437 /* 438 * NT includes 6 bytes (spec says 4) at the end of this 439 * response, which are required by NetBench 5.01. 440 */ 441 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 442 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.", 443 &qinfo->qi_crtime, 444 &qinfo->qi_atime, 445 &qinfo->qi_mtime, 446 &qinfo->qi_ctime, 447 dattr); 448 break; 449 450 case SMB_QUERY_FILE_STANDARD_INFO: 451 case SMB_FILE_STANDARD_INFORMATION: 452 /* 2-byte pad at end */ 453 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 454 (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.", 455 (uint64_t)allocsz, 456 (uint64_t)datasz, 457 qinfo->qi_attr.sa_vattr.va_nlink, 458 qinfo->qi_delete_on_close, 459 (qinfo->qi_attr.sa_vattr.va_type == VDIR)); 460 break; 461 462 case SMB_QUERY_FILE_EA_INFO: 463 case SMB_FILE_EA_INFORMATION: 464 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 465 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0); 466 break; 467 468 case SMB_QUERY_FILE_NAME_INFO: 469 case SMB_FILE_NAME_INFORMATION: 470 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 471 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr, 472 qinfo->qi_namelen, qinfo->qi_name); 473 break; 474 475 case SMB_QUERY_FILE_ALL_INFO: 476 case SMB_FILE_ALL_INFORMATION: 477 /* 478 * There is a 6-byte pad between Attributes and AllocationSize, 479 * and a 2-byte pad after the Directory field. 480 */ 481 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 482 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l", 483 &qinfo->qi_crtime, 484 &qinfo->qi_atime, 485 &qinfo->qi_mtime, 486 &qinfo->qi_ctime, 487 dattr, 488 (uint64_t)allocsz, 489 (uint64_t)datasz, 490 qinfo->qi_attr.sa_vattr.va_nlink, 491 qinfo->qi_delete_on_close, 492 (qinfo->qi_attr.sa_vattr.va_type == VDIR), 493 0); 494 495 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", 496 sr, qinfo->qi_namelen, qinfo->qi_name); 497 break; 498 499 case SMB_QUERY_FILE_ALT_NAME_INFO: 500 case SMB_FILE_ALT_NAME_INFORMATION: 501 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 502 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr, 503 mts_wcequiv_strlen(qinfo->qi_shortname), 504 qinfo->qi_shortname); 505 break; 506 507 case SMB_QUERY_FILE_STREAM_INFO: 508 case SMB_FILE_STREAM_INFORMATION: 509 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 510 smb_encode_stream_info(sr, xa, qinfo); 511 break; 512 513 case SMB_QUERY_FILE_COMPRESSION_INFO: 514 case SMB_FILE_COMPRESSION_INFORMATION: 515 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 516 (void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.", 517 datasz, 0, 0, 0, 0); 518 break; 519 520 case SMB_FILE_INTERNAL_INFORMATION: 521 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 522 (void) smb_mbc_encodef(&xa->rep_data_mb, "q", 523 qinfo->qi_attr.sa_vattr.va_nodeid); 524 break; 525 526 case SMB_FILE_ATTR_TAG_INFORMATION: 527 /* 528 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the 529 * second dword should be the reparse tag. Otherwise 530 * the tag value should be set to zero. 531 * We don't support reparse points, so we set the tag 532 * to zero. 533 */ 534 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 535 (void) smb_mbc_encodef(&xa->rep_data_mb, "ll", 536 (uint32_t)dattr, 0); 537 break; 538 539 default: 540 smbsr_error(sr, 0, ERRDOS, ERRunknownlevel); 541 return (-1); 542 } 543 544 return (0); 545 } 546 547 /* 548 * smb_encode_stream_info 549 * 550 * This function encodes the streams information. 551 * The following rules about how have been derived from observed NT 552 * behaviour. 553 * 554 * If the target is a file: 555 * 1. If there are no named streams, the response should still contain 556 * an entry for the unnamed stream. 557 * 2. If there are named streams, the response should contain an entry 558 * for the unnamed stream followed by the entries for the named 559 * streams. 560 * 561 * If the target is a directory: 562 * 1. If there are no streams, the response is complete. Directories 563 * do not report the unnamed stream. 564 * 2. If there are streams, the response should contain entries for 565 * those streams but there should not be an entry for the unnamed 566 * stream. 567 * 568 * Note that the stream name lengths exclude the null terminator but 569 * the field lengths (i.e. next offset calculations) need to include 570 * the null terminator and be padded to a multiple of 8 bytes. The 571 * last entry does not seem to need any padding. 572 * 573 * If an error is encountered when trying to read the stream entries 574 * (smb_odir_read_streaminfo) it is treated as if there are no [more] 575 * entries. The entries that have been read so far are returned and 576 * no error is reported. 577 * 578 * Offset calculation: 579 * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24 580 */ 581 static void 582 smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo) 583 { 584 char *stream_name; 585 uint32_t next_offset; 586 uint32_t stream_nlen; 587 uint32_t pad; 588 u_offset_t datasz, allocsz; 589 boolean_t is_dir; 590 smb_streaminfo_t *sinfo, *sinfo_next; 591 int rc = 0; 592 boolean_t done = B_FALSE; 593 boolean_t eos = B_FALSE; 594 uint16_t odid; 595 smb_odir_t *od = NULL; 596 597 smb_node_t *fnode = qinfo->qi_node; 598 smb_attr_t *attr = &qinfo->qi_attr; 599 600 ASSERT(fnode); 601 if (SMB_IS_STREAM(fnode)) { 602 fnode = fnode->n_unode; 603 ASSERT(fnode); 604 } 605 ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 606 ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 607 608 sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); 609 sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); 610 is_dir = (attr->sa_vattr.va_type == VDIR); 611 datasz = attr->sa_vattr.va_size; 612 allocsz = attr->sa_allocsz; 613 614 odid = smb_odir_openat(sr, fnode); 615 if (odid != 0) 616 od = smb_tree_lookup_odir(sr->tid_tree, odid); 617 if (od != NULL) 618 rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos); 619 620 if ((od == NULL) || (rc != 0) || (eos)) 621 done = B_TRUE; 622 623 /* If not a directory, encode an entry for the unnamed stream. */ 624 if (!is_dir) { 625 stream_name = "::$DATA"; 626 stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name); 627 628 if (done) 629 next_offset = 0; 630 else 631 next_offset = 24 + stream_nlen + 632 smb_ascii_or_unicode_null_len(sr); 633 634 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr, 635 next_offset, stream_nlen, datasz, allocsz, stream_name); 636 } 637 638 /* 639 * Since last packet does not have a pad we need to check 640 * for the next stream before we encode the current one 641 */ 642 while (!done) { 643 stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name); 644 sinfo_next->si_name[0] = 0; 645 646 rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos); 647 if ((rc != 0) || (eos)) { 648 done = B_TRUE; 649 next_offset = 0; 650 pad = 0; 651 } else { 652 next_offset = 24 + stream_nlen + 653 smb_ascii_or_unicode_null_len(sr); 654 pad = smb_pad_align(next_offset, 8); 655 next_offset += pad; 656 } 657 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.", 658 sr, next_offset, stream_nlen, 659 sinfo->si_size, sinfo->si_alloc_size, 660 sinfo->si_name, pad); 661 662 (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t)); 663 } 664 665 kmem_free(sinfo, sizeof (smb_streaminfo_t)); 666 kmem_free(sinfo_next, sizeof (smb_streaminfo_t)); 667 if (od) { 668 smb_odir_close(od); 669 smb_odir_release(od); 670 } 671 } 672 673 /* 674 * smb_pad_align 675 * 676 * Returns the number of bytes required to pad an offset to the 677 * specified alignment. 678 */ 679 uint32_t 680 smb_pad_align(uint32_t offset, uint32_t align) 681 { 682 uint32_t pad = offset % align; 683 684 if (pad != 0) 685 pad = align - pad; 686 687 return (pad); 688 } 689 690 /* 691 * smb_all_info_filename 692 * 693 * This format of filename is only used by the ALL_INFO levels. 694 * 695 * Determine the absolute pathname of 'node' within the share. 696 * For example if the node represents file "test1.txt" in directory 697 * "dir1" on share "share1", the path would be: \share1\dir1\test1.txt 698 * 699 * If node represents a named stream, construct the pathname for the 700 * associated unnamed stream then append the stream name. 701 */ 702 static int 703 smb_all_info_filename(smb_tree_t *tree, smb_node_t *node, 704 char *buf, size_t buflen) 705 { 706 char *sharename = tree->t_sharename; 707 int rc; 708 size_t len; 709 vnode_t *vp; 710 711 len = snprintf(buf, buflen, "\\%s", sharename); 712 if (len == (buflen - 1)) 713 return (ENAMETOOLONG); 714 715 buf += len; 716 buflen -= len; 717 718 if (SMB_IS_STREAM(node)) 719 vp = node->n_unode->vp; 720 else 721 vp = node->vp; 722 723 rc = vnodetopath(tree->t_snode->vp, vp, buf, buflen, kcred); 724 if (rc == 0) { 725 (void) strsubst(buf, '/', '\\'); 726 727 if (SMB_IS_STREAM(node)) 728 (void) strlcat(buf, node->od_name, buflen); 729 } 730 731 return (rc); 732 } 733 734 /* 735 * smb_query_fileinfo 736 * 737 * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK 738 * (This should become an smb_ofile / smb_node function.) 739 */ 740 int 741 smb_query_fileinfo(smb_request_t *sr, smb_node_t *node, uint16_t infolev, 742 smb_queryinfo_t *qinfo) 743 { 744 char *namep = node->od_name; 745 int rc; 746 747 (void) bzero(qinfo, sizeof (smb_queryinfo_t)); 748 749 if (smb_node_getattr(sr, node, &qinfo->qi_attr) != 0) { 750 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 751 ERRDOS, ERROR_INTERNAL_ERROR); 752 return (-1); 753 } 754 755 qinfo->qi_node = node; 756 qinfo->qi_delete_on_close = 757 (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0; 758 759 /* 760 * The number of links reported should be the number of 761 * non-deleted links. Thus if delete_on_close is set, 762 * decrement the link count. 763 */ 764 if (qinfo->qi_delete_on_close && 765 qinfo->qi_attr.sa_vattr.va_nlink > 0) { 766 --(qinfo->qi_attr.sa_vattr.va_nlink); 767 } 768 769 /* populate name, namelen and shortname */ 770 771 /* ALL_INFO levels are a special case for name field */ 772 if ((infolev == SMB_QUERY_FILE_ALL_INFO) || 773 (infolev == SMB_FILE_ALL_INFORMATION)) { 774 rc = smb_all_info_filename(sr->tid_tree, node, 775 qinfo->qi_name, MAXPATHLEN); 776 if (rc != 0) { 777 smbsr_errno(sr, rc); 778 return (-1); 779 } 780 qinfo->qi_namelen = 781 smb_ascii_or_unicode_strlen(sr, qinfo->qi_name); 782 return (0); 783 } 784 785 /* 786 * It looks like NT doesn't know what to do with the name "." 787 * so we convert it to "\\" to indicate the root directory. 788 * If the leading \ is missing, add it. 789 */ 790 if (strcmp(namep, ".") == 0) 791 (void) strlcpy(qinfo->qi_name, "\\", MAXNAMELEN); 792 else if (*namep != '\\') 793 (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep); 794 else 795 (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN); 796 797 qinfo->qi_namelen = smb_ascii_or_unicode_strlen(sr, qinfo->qi_name); 798 799 /* 800 * For some reason NT will not show the security tab in the root 801 * directory of a mapped drive unless the filename length is 802 * greater than one. So we hack the length here to persuade NT 803 * to show the tab. It should be safe because of the null 804 * terminator character. 805 */ 806 if (qinfo->qi_namelen == 1) 807 qinfo->qi_namelen = 2; 808 809 /* 810 * If the shortname is generated by smb_mangle_name() 811 * it will be returned as the alternative name. 812 * Otherwise, convert the original name to upper-case 813 * and return it as the alternative name. 814 */ 815 (void) smb_mangle_name(qinfo->qi_attr.sa_vattr.va_nodeid, 816 namep, qinfo->qi_shortname, qinfo->qi_name83, 0); 817 if (*qinfo->qi_shortname == 0) { 818 (void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN); 819 (void) utf8_strupr(qinfo->qi_shortname); 820 } 821 822 return (0); 823 } 824 825 /* 826 * smb_query_pipeinfo 827 * 828 * Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE 829 * (This should become an smb_opipe function.) 830 */ 831 static int 832 smb_query_pipeinfo(smb_request_t *sr, smb_opipe_t *opipe, uint16_t infolev, 833 smb_queryinfo_t *qinfo) 834 { 835 char *namep = opipe->p_name; 836 837 (void) bzero(qinfo, sizeof (smb_queryinfo_t)); 838 qinfo->qi_node = NULL; 839 qinfo->qi_attr.sa_vattr.va_nlink = 1; 840 qinfo->qi_delete_on_close = 1; 841 842 if ((infolev == SMB_INFO_STANDARD) || 843 (infolev == SMB_INFO_QUERY_EA_SIZE) || 844 (infolev == SMB_QUERY_INFORMATION2)) { 845 qinfo->qi_attr.sa_dosattr = 0; 846 } else { 847 qinfo->qi_attr.sa_dosattr = FILE_ATTRIBUTE_NORMAL; 848 } 849 850 /* If the leading \ is missing from the pipe name, add it. */ 851 if (*namep != '\\') 852 (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep); 853 else 854 (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN); 855 856 qinfo->qi_namelen= 857 smb_ascii_or_unicode_strlen(sr, qinfo->qi_name); 858 859 return (0); 860 } 861 862 /* 863 * smb_query_pipe_valid_infolev 864 * 865 * If the infolev is not valid for a message pipe, the error 866 * information is set in sr and B_FALSE is returned. 867 * Otherwise, returns B_TRUE. 868 */ 869 static boolean_t 870 smb_query_pipe_valid_infolev(smb_request_t *sr, uint16_t infolev) 871 { 872 switch (infolev) { 873 case SMB_INFO_QUERY_ALL_EAS: 874 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 875 ERRDOS, ERROR_ACCESS_DENIED); 876 return (B_FALSE); 877 878 case SMB_QUERY_FILE_ALT_NAME_INFO: 879 case SMB_FILE_ALT_NAME_INFORMATION: 880 case SMB_QUERY_FILE_STREAM_INFO: 881 case SMB_FILE_STREAM_INFORMATION: 882 case SMB_QUERY_FILE_COMPRESSION_INFO: 883 case SMB_FILE_COMPRESSION_INFORMATION: 884 case SMB_FILE_ATTR_TAG_INFORMATION: 885 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 886 ERRDOS, ERROR_INVALID_PARAMETER); 887 return (B_FALSE); 888 } 889 890 return (B_TRUE); 891 } 892