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