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