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_NETWORK_OPEN_INFORMATION - not valid for pipes 60 * SMB_FILE_ATTR_TAG_INFORMATION - not valid for pipes 61 * 62 * Internal levels representing non trans2 requests 63 * SMB_QUERY_INFORMATION 64 * SMB_QUERY_INFORMATION2 65 */ 66 67 typedef struct smb_queryinfo { 68 smb_node_t *qi_node; /* NULL for pipes */ 69 smb_attr_t qi_attr; 70 boolean_t qi_delete_on_close; 71 uint32_t qi_namelen; 72 char qi_name83[SMB_SHORTNAMELEN]; 73 char qi_shortname[SMB_SHORTNAMELEN]; 74 char qi_name[MAXPATHLEN]; 75 } smb_queryinfo_t; 76 #define qi_mtime qi_attr.sa_vattr.va_mtime 77 #define qi_ctime qi_attr.sa_vattr.va_ctime 78 #define qi_atime qi_attr.sa_vattr.va_atime 79 #define qi_crtime qi_attr.sa_crtime 80 81 static int smb_query_by_fid(smb_request_t *, smb_xa_t *, uint16_t); 82 static int smb_query_by_path(smb_request_t *, smb_xa_t *, uint16_t); 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 97 int smb_query_passthru; 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 smb_fqi_t *fqi = &sr->arg.dirop.fqi; 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, &fqi->fq_path.pn_path) != 0) 134 return (SDRC_ERROR); 135 136 if (smb_query_by_path(sr, xa, infolev) != 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 uint16_t infolev = SMB_QUERY_INFORMATION; 169 170 if (STYPE_ISIPC(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) != 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 * Path should be set in sr->arg.dirop.fqi.fq_path prior to 280 * calling smb_query_by_path. 281 * 282 * Querying attributes on a named pipe by name is an error and 283 * is handled in the calling functions so that they can return 284 * the appropriate error status code (which differs by caller). 285 */ 286 static int 287 smb_query_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev) 288 { 289 smb_queryinfo_t *qinfo; 290 smb_node_t *node, *dnode; 291 smb_pathname_t *pn; 292 int rc; 293 294 /* VALID, but not yet supported */ 295 if (infolev == SMB_FILE_ACCESS_INFORMATION) { 296 smbsr_error(sr, 0, ERRDOS, ERRunknownlevel); 297 return (-1); 298 } 299 300 pn = &sr->arg.dirop.fqi.fq_path; 301 smb_pathname_init(sr, pn, pn->pn_path); 302 if (!smb_pathname_validate(sr, pn)) 303 return (-1); 304 305 qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP); 306 307 rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path, 308 sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, 309 qinfo->qi_name); 310 311 if (rc == 0) { 312 rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS, 313 sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node); 314 smb_node_release(dnode); 315 } 316 317 if (rc != 0) { 318 if (rc == ENOENT) 319 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 320 ERRDOS, ERROR_FILE_NOT_FOUND); 321 else 322 smbsr_errno(sr, rc); 323 324 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 325 return (-1); 326 } 327 328 if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) { 329 smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); 330 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 331 smb_node_release(node); 332 return (-1); 333 } 334 335 rc = smb_query_fileinfo(sr, node, infolev, qinfo); 336 if (rc != 0) { 337 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 338 smb_node_release(node); 339 return (rc); 340 } 341 342 /* If delete_on_close - NT_STATUS_DELETE_PENDING */ 343 if (qinfo->qi_delete_on_close) { 344 smbsr_error(sr, NT_STATUS_DELETE_PENDING, 345 ERRDOS, ERROR_ACCESS_DENIED); 346 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 347 smb_node_release(node); 348 return (-1); 349 } 350 351 rc = smb_query_encode_response(sr, xa, infolev, qinfo); 352 kmem_free(qinfo, sizeof (smb_queryinfo_t)); 353 smb_node_release(node); 354 return (rc); 355 } 356 357 /* 358 * smb_size32 359 * Some responses only support 32 bit file sizes. If the file size 360 * exceeds UINT_MAX (32 bit) we return UINT_MAX in the response. 361 */ 362 static uint32_t 363 smb_size32(u_offset_t size) 364 { 365 return ((size > UINT_MAX) ? UINT_MAX : (uint32_t)size); 366 } 367 368 /* 369 * smb_query_encode_response 370 * 371 * Encode the data from smb_queryinfo_t into client response 372 */ 373 int 374 smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa, 375 uint16_t infolev, smb_queryinfo_t *qinfo) 376 { 377 uint16_t dattr; 378 u_offset_t datasz, allocsz; 379 uint32_t isdir; 380 381 dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK; 382 datasz = qinfo->qi_attr.sa_vattr.va_size; 383 allocsz = qinfo->qi_attr.sa_allocsz; 384 isdir = ((dattr & FILE_ATTRIBUTE_DIRECTORY) != 0); 385 386 switch (infolev) { 387 case SMB_QUERY_INFORMATION: 388 (void) smbsr_encode_result(sr, 10, 0, "bwll10.w", 389 10, 390 dattr, 391 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), 392 smb_size32(datasz), 393 0); 394 break; 395 396 case SMB_QUERY_INFORMATION2: 397 (void) smbsr_encode_result(sr, 11, 0, "byyyllww", 398 11, 399 smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec), 400 smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec), 401 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), 402 smb_size32(datasz), smb_size32(allocsz), dattr, 0); 403 break; 404 405 case SMB_FILE_ACCESS_INFORMATION: 406 ASSERT(sr->fid_ofile); 407 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 408 sr->fid_ofile->f_granted_access); 409 break; 410 411 case SMB_INFO_STANDARD: 412 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 413 (void) smb_mbc_encodef(&xa->rep_data_mb, 414 ((sr->session->native_os == NATIVE_OS_WIN95) ? 415 "YYYllw" : "yyyllw"), 416 smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec), 417 smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec), 418 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), 419 smb_size32(datasz), smb_size32(allocsz), dattr); 420 break; 421 422 case SMB_INFO_QUERY_EA_SIZE: 423 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 424 (void) smb_mbc_encodef(&xa->rep_data_mb, 425 ((sr->session->native_os == NATIVE_OS_WIN95) ? 426 "YYYllwl" : "yyyllwl"), 427 smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec), 428 smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec), 429 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), 430 smb_size32(datasz), smb_size32(allocsz), dattr, 0); 431 break; 432 433 case SMB_INFO_QUERY_ALL_EAS: 434 case SMB_INFO_QUERY_EAS_FROM_LIST: 435 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 436 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0); 437 break; 438 439 case SMB_INFO_IS_NAME_VALID: 440 break; 441 442 case SMB_QUERY_FILE_BASIC_INFO: 443 case SMB_FILE_BASIC_INFORMATION: 444 /* 445 * NT includes 6 bytes (spec says 4) at the end of this 446 * response, which are required by NetBench 5.01. 447 */ 448 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 449 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.", 450 &qinfo->qi_crtime, 451 &qinfo->qi_atime, 452 &qinfo->qi_mtime, 453 &qinfo->qi_ctime, 454 dattr); 455 break; 456 457 case SMB_QUERY_FILE_STANDARD_INFO: 458 case SMB_FILE_STANDARD_INFORMATION: 459 /* 2-byte pad at end */ 460 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 461 (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.", 462 (uint64_t)allocsz, 463 (uint64_t)datasz, 464 qinfo->qi_attr.sa_vattr.va_nlink, 465 qinfo->qi_delete_on_close, 466 (uint8_t)isdir); 467 break; 468 469 case SMB_QUERY_FILE_EA_INFO: 470 case SMB_FILE_EA_INFORMATION: 471 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 472 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0); 473 break; 474 475 case SMB_QUERY_FILE_NAME_INFO: 476 case SMB_FILE_NAME_INFORMATION: 477 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 478 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr, 479 qinfo->qi_namelen, qinfo->qi_name); 480 break; 481 482 case SMB_QUERY_FILE_ALL_INFO: 483 case SMB_FILE_ALL_INFORMATION: 484 /* 485 * There is a 6-byte pad between Attributes and AllocationSize, 486 * and a 2-byte pad after the Directory field. 487 */ 488 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 489 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l", 490 &qinfo->qi_crtime, 491 &qinfo->qi_atime, 492 &qinfo->qi_mtime, 493 &qinfo->qi_ctime, 494 dattr, 495 (uint64_t)allocsz, 496 (uint64_t)datasz, 497 qinfo->qi_attr.sa_vattr.va_nlink, 498 qinfo->qi_delete_on_close, 499 isdir, 500 0); 501 502 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", 503 sr, qinfo->qi_namelen, qinfo->qi_name); 504 break; 505 506 case SMB_QUERY_FILE_ALT_NAME_INFO: 507 case SMB_FILE_ALT_NAME_INFORMATION: 508 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 509 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr, 510 smb_wcequiv_strlen(qinfo->qi_shortname), 511 qinfo->qi_shortname); 512 break; 513 514 case SMB_QUERY_FILE_STREAM_INFO: 515 case SMB_FILE_STREAM_INFORMATION: 516 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 517 smb_encode_stream_info(sr, xa, qinfo); 518 break; 519 520 case SMB_QUERY_FILE_COMPRESSION_INFO: 521 case SMB_FILE_COMPRESSION_INFORMATION: 522 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 523 (void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.", 524 datasz, 0, 0, 0, 0); 525 break; 526 527 case SMB_FILE_INTERNAL_INFORMATION: 528 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 529 (void) smb_mbc_encodef(&xa->rep_data_mb, "q", 530 qinfo->qi_attr.sa_vattr.va_nodeid); 531 break; 532 533 case SMB_FILE_NETWORK_OPEN_INFORMATION: 534 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 535 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTqql4.", 536 &qinfo->qi_crtime, 537 &qinfo->qi_atime, 538 &qinfo->qi_mtime, 539 &qinfo->qi_ctime, 540 (uint64_t)allocsz, 541 (uint64_t)datasz, 542 (uint32_t)dattr); 543 break; 544 545 case SMB_FILE_ATTR_TAG_INFORMATION: 546 /* 547 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the 548 * second dword should be the reparse tag. Otherwise 549 * the tag value should be set to zero. 550 * We don't support reparse points, so we set the tag 551 * to zero. 552 */ 553 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); 554 (void) smb_mbc_encodef(&xa->rep_data_mb, "ll", 555 (uint32_t)dattr, 0); 556 break; 557 558 default: 559 if ((infolev > 1000) && smb_query_passthru) 560 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, 561 ERRDOS, ERROR_NOT_SUPPORTED); 562 else 563 smbsr_error(sr, 0, ERRDOS, ERRunknownlevel); 564 return (-1); 565 } 566 567 return (0); 568 } 569 570 /* 571 * smb_encode_stream_info 572 * 573 * This function encodes the streams information. 574 * The following rules about how have been derived from observed NT 575 * behaviour. 576 * 577 * If the target is a file: 578 * 1. If there are no named streams, the response should still contain 579 * an entry for the unnamed stream. 580 * 2. If there are named streams, the response should contain an entry 581 * for the unnamed stream followed by the entries for the named 582 * streams. 583 * 584 * If the target is a directory: 585 * 1. If there are no streams, the response is complete. Directories 586 * do not report the unnamed stream. 587 * 2. If there are streams, the response should contain entries for 588 * those streams but there should not be an entry for the unnamed 589 * stream. 590 * 591 * Note that the stream name lengths exclude the null terminator but 592 * the field lengths (i.e. next offset calculations) need to include 593 * the null terminator and be padded to a multiple of 8 bytes. The 594 * last entry does not seem to need any padding. 595 * 596 * If an error is encountered when trying to read the stream entries 597 * (smb_odir_read_streaminfo) it is treated as if there are no [more] 598 * entries. The entries that have been read so far are returned and 599 * no error is reported. 600 * 601 * Offset calculation: 602 * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24 603 */ 604 static void 605 smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo) 606 { 607 char *stream_name; 608 uint32_t next_offset; 609 uint32_t stream_nlen; 610 uint32_t pad; 611 u_offset_t datasz, allocsz; 612 boolean_t is_dir; 613 smb_streaminfo_t *sinfo, *sinfo_next; 614 int rc = 0; 615 boolean_t done = B_FALSE; 616 boolean_t eos = B_FALSE; 617 uint16_t odid; 618 smb_odir_t *od = NULL; 619 620 smb_node_t *fnode = qinfo->qi_node; 621 smb_attr_t *attr = &qinfo->qi_attr; 622 623 ASSERT(fnode); 624 if (SMB_IS_STREAM(fnode)) { 625 fnode = fnode->n_unode; 626 ASSERT(fnode); 627 } 628 ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 629 ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 630 631 sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); 632 sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); 633 is_dir = ((attr->sa_dosattr & FILE_ATTRIBUTE_DIRECTORY) != 0); 634 datasz = attr->sa_vattr.va_size; 635 allocsz = attr->sa_allocsz; 636 637 odid = smb_odir_openat(sr, fnode); 638 if (odid != 0) 639 od = smb_tree_lookup_odir(sr->tid_tree, odid); 640 if (od != NULL) 641 rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos); 642 643 if ((od == NULL) || (rc != 0) || (eos)) 644 done = B_TRUE; 645 646 /* If not a directory, encode an entry for the unnamed stream. */ 647 if (!is_dir) { 648 stream_name = "::$DATA"; 649 stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name); 650 651 if (done) 652 next_offset = 0; 653 else 654 next_offset = 24 + stream_nlen + 655 smb_ascii_or_unicode_null_len(sr); 656 657 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr, 658 next_offset, stream_nlen, datasz, allocsz, stream_name); 659 } 660 661 /* 662 * Since last packet does not have a pad we need to check 663 * for the next stream before we encode the current one 664 */ 665 while (!done) { 666 stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name); 667 sinfo_next->si_name[0] = 0; 668 669 rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos); 670 if ((rc != 0) || (eos)) { 671 done = B_TRUE; 672 next_offset = 0; 673 pad = 0; 674 } else { 675 next_offset = 24 + stream_nlen + 676 smb_ascii_or_unicode_null_len(sr); 677 pad = smb_pad_align(next_offset, 8); 678 next_offset += pad; 679 } 680 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.", 681 sr, next_offset, stream_nlen, 682 sinfo->si_size, sinfo->si_alloc_size, 683 sinfo->si_name, pad); 684 685 (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t)); 686 } 687 688 kmem_free(sinfo, sizeof (smb_streaminfo_t)); 689 kmem_free(sinfo_next, sizeof (smb_streaminfo_t)); 690 if (od) { 691 smb_odir_close(od); 692 smb_odir_release(od); 693 } 694 } 695 696 /* 697 * smb_query_pathname 698 * 699 * Determine the absolute pathname of 'node' within the share. 700 * For some levels (e.g. ALL_INFO) the pathname should include the 701 * sharename for others (e.g. NAME_INFO) the pathname should be 702 * relative to the share. 703 * For example if the node represents file "test1.txt" in directory 704 * "dir1" on share "share1" 705 * - if include_share is TRUE the pathname would be: \share1\dir1\test1.txt 706 * - if include_share is FALSE the pathname would be: \dir1\test1.txt 707 */ 708 static int 709 smb_query_pathname(smb_tree_t *tree, smb_node_t *node, boolean_t include_share, 710 char *buf, size_t buflen) 711 { 712 char *sharename = tree->t_sharename; 713 int rc; 714 size_t len; 715 716 if (include_share) { 717 len = snprintf(buf, buflen, "\\%s", sharename); 718 if (len == (buflen - 1)) 719 return (ENAMETOOLONG); 720 721 buf += len; 722 buflen -= len; 723 } 724 725 rc = smb_node_getshrpath(node, tree, buf, buflen); 726 return (rc); 727 } 728 729 /* 730 * smb_query_fileinfo 731 * 732 * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK 733 * (This should become an smb_ofile / smb_node function.) 734 */ 735 int 736 smb_query_fileinfo(smb_request_t *sr, smb_node_t *node, uint16_t infolev, 737 smb_queryinfo_t *qinfo) 738 { 739 int rc; 740 boolean_t include_sharename = B_FALSE; 741 char *namep; 742 743 (void) bzero(qinfo, sizeof (smb_queryinfo_t)); 744 745 if (smb_node_getattr(sr, node, &qinfo->qi_attr) != 0) { 746 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 747 ERRDOS, ERROR_INTERNAL_ERROR); 748 return (-1); 749 } 750 751 qinfo->qi_node = node; 752 qinfo->qi_delete_on_close = 753 (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0; 754 755 /* 756 * The number of links reported should be the number of 757 * non-deleted links. Thus if delete_on_close is set, 758 * decrement the link count. 759 */ 760 if (qinfo->qi_delete_on_close && 761 qinfo->qi_attr.sa_vattr.va_nlink > 0) { 762 --(qinfo->qi_attr.sa_vattr.va_nlink); 763 } 764 765 /* populate name, namelen and shortname */ 766 767 /* ALL_INFO levels include the sharename in the name field */ 768 if ((infolev == SMB_QUERY_FILE_ALL_INFO) || 769 (infolev == SMB_FILE_ALL_INFORMATION)) { 770 include_sharename = B_TRUE; 771 } 772 773 rc = smb_query_pathname(sr->tid_tree, node, include_sharename, 774 qinfo->qi_name, MAXPATHLEN); 775 if (rc != 0) { 776 smbsr_errno(sr, rc); 777 return (-1); 778 } 779 780 qinfo->qi_namelen = smb_ascii_or_unicode_strlen(sr, qinfo->qi_name); 781 782 /* 783 * For some reason NT will not show the security tab in the root 784 * directory of a mapped drive unless the filename length is 785 * greater than one. So we hack the length here to persuade NT 786 * to show the tab. It should be safe because of the null 787 * terminator character. 788 */ 789 if (qinfo->qi_namelen == 1) 790 qinfo->qi_namelen = 2; 791 792 /* 793 * If the node is an named stream, use its associated 794 * unnamed stream name to determine the shortname. 795 * If the shortname is generated by smb_mangle_name() 796 * it will be returned as the alternative name. 797 * Otherwise, convert the original name to upper-case 798 * and return it as the alternative name. 799 */ 800 if (SMB_IS_STREAM(node)) 801 namep = node->n_unode->od_name; 802 else 803 namep = node->od_name; 804 805 (void) smb_mangle_name(qinfo->qi_attr.sa_vattr.va_nodeid, 806 namep, qinfo->qi_shortname, qinfo->qi_name83, 0); 807 if (*qinfo->qi_shortname == 0) { 808 (void) strlcpy(qinfo->qi_shortname, namep, 809 SMB_SHORTNAMELEN); 810 (void) smb_strupr(qinfo->qi_shortname); 811 } 812 813 return (0); 814 } 815 816 /* 817 * smb_query_pipeinfo 818 * 819 * Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE 820 * (This should become an smb_opipe function.) 821 */ 822 static int 823 smb_query_pipeinfo(smb_request_t *sr, smb_opipe_t *opipe, uint16_t infolev, 824 smb_queryinfo_t *qinfo) 825 { 826 char *namep = opipe->p_name; 827 828 (void) bzero(qinfo, sizeof (smb_queryinfo_t)); 829 qinfo->qi_node = NULL; 830 qinfo->qi_attr.sa_vattr.va_nlink = 1; 831 qinfo->qi_delete_on_close = 1; 832 833 if ((infolev == SMB_INFO_STANDARD) || 834 (infolev == SMB_INFO_QUERY_EA_SIZE) || 835 (infolev == SMB_QUERY_INFORMATION2)) { 836 qinfo->qi_attr.sa_dosattr = 0; 837 } else { 838 qinfo->qi_attr.sa_dosattr = FILE_ATTRIBUTE_NORMAL; 839 } 840 841 /* If the leading \ is missing from the pipe name, add it. */ 842 if (*namep != '\\') 843 (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep); 844 else 845 (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN); 846 847 qinfo->qi_namelen= 848 smb_ascii_or_unicode_strlen(sr, qinfo->qi_name); 849 850 return (0); 851 } 852 853 /* 854 * smb_query_pipe_valid_infolev 855 * 856 * If the infolev is not valid for a message pipe, the error 857 * information is set in sr and B_FALSE is returned. 858 * Otherwise, returns B_TRUE. 859 */ 860 static boolean_t 861 smb_query_pipe_valid_infolev(smb_request_t *sr, uint16_t infolev) 862 { 863 switch (infolev) { 864 case SMB_INFO_QUERY_ALL_EAS: 865 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 866 ERRDOS, ERROR_ACCESS_DENIED); 867 return (B_FALSE); 868 869 case SMB_QUERY_FILE_ALT_NAME_INFO: 870 case SMB_FILE_ALT_NAME_INFORMATION: 871 case SMB_QUERY_FILE_STREAM_INFO: 872 case SMB_FILE_STREAM_INFORMATION: 873 case SMB_QUERY_FILE_COMPRESSION_INFO: 874 case SMB_FILE_COMPRESSION_INFORMATION: 875 case SMB_FILE_NETWORK_OPEN_INFORMATION: 876 case SMB_FILE_ATTR_TAG_INFORMATION: 877 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 878 ERRDOS, ERROR_INVALID_PARAMETER); 879 return (B_FALSE); 880 } 881 882 return (B_TRUE); 883 } 884