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