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