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