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/smbinfo.h>
     28 #include <smbsrv/smb_fsops.h>
     29 
     30 typedef struct smb_dirpath {
     31 	char	*sp_path;	/* Original path */
     32 	char	*sp_curp;	/* Current pointer into the original path */
     33 	smb_request_t *sp_sr;	/* Current request pointer */
     34 } smb_dirpath_t;
     35 
     36 static smb_dirpath_t *smb_dirpath_new(smb_request_t *);
     37 static int smb_dirpath_next(smb_dirpath_t *);
     38 static boolean_t smb_dirpath_isvalid(const char *);
     39 
     40 /*
     41  * The create directory message is sent to create a new directory.  The
     42  * appropriate Tid and additional pathname are passed.  The directory must
     43  * not exist for it to be created.
     44  *
     45  * Client Request                     Description
     46  * ================================== =================================
     47  * UCHAR WordCount;                   Count of parameter words = 0
     48  * USHORT ByteCount;                  Count of data bytes; min = 2
     49  * UCHAR BufferFormat;                0x04
     50  * STRING DirectoryName[];            Directory name
     51  *
     52  * Servers require clients to have at least create permission for the
     53  * subtree containing the directory in order to create a new directory.
     54  * The creator's access rights to the new directory are be determined by
     55  * local policy on the server.
     56  *
     57  * Server Response                    Description
     58  * ================================== =================================
     59  * UCHAR WordCount;                   Count of parameter words = 0
     60  * USHORT ByteCount;                  Count of data bytes = 0
     61  */
     62 smb_sdrc_t
     63 smb_pre_create_directory(smb_request_t *sr)
     64 {
     65 	int rc;
     66 
     67 	rc = smbsr_decode_data(sr, "%S", sr,
     68 	    &sr->arg.dirop.fqi.fq_path.pn_path);
     69 
     70 	DTRACE_SMB_2(op__CreateDirectory__start, smb_request_t *, sr,
     71 	    struct dirop *, &sr->arg.dirop);
     72 
     73 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
     74 }
     75 
     76 void
     77 smb_post_create_directory(smb_request_t *sr)
     78 {
     79 	DTRACE_SMB_1(op__CreateDirectory__done, smb_request_t *, sr);
     80 }
     81 
     82 /*
     83  * smb_com_create_directory
     84  *
     85  * It is possible to get a full pathname here and the client expects any
     86  * or all of the components to be created if they don't already exist.
     87  */
     88 smb_sdrc_t
     89 smb_com_create_directory(smb_request_t *sr)
     90 {
     91 	smb_dirpath_t *spp;
     92 	DWORD status;
     93 	int rc = 0;
     94 	char *path = sr->arg.dirop.fqi.fq_path.pn_path;
     95 
     96 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
     97 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
     98 		    ERRDOS, ERROR_ACCESS_DENIED);
     99 		return (SDRC_ERROR);
    100 	}
    101 
    102 	if (!smb_dirpath_isvalid(path)) {
    103 		smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
    104 		    ERRDOS, ERROR_BAD_PATHNAME);
    105 		return (SDRC_ERROR);
    106 	}
    107 
    108 	status = smb_validate_dirname(path);
    109 	if (status != 0) {
    110 		smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
    111 		return (SDRC_ERROR);
    112 	}
    113 
    114 	/*
    115 	 * Try each component of the path.  EEXIST on path
    116 	 * components is okay except on the last one.
    117 	 */
    118 	spp = smb_dirpath_new(sr);
    119 
    120 	while (smb_dirpath_next(spp)) {
    121 		rc = smb_common_create_directory(sr);
    122 
    123 		switch (rc) {
    124 		case 0:
    125 			break;
    126 		case EEXIST:
    127 			break;
    128 		case ENOENT:
    129 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
    130 			    ERRDOS, ERROR_FILE_NOT_FOUND);
    131 			return (SDRC_ERROR);
    132 		case ENOTDIR:
    133 			/*
    134 			 * Spec says status should be OBJECT_PATH_INVALID
    135 			 * but testing shows OBJECT_PATH_NOT_FOUND
    136 			 */
    137 			smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND,
    138 			    ERRDOS, ERROR_PATH_NOT_FOUND);
    139 			return (SDRC_ERROR);
    140 		default:
    141 			smbsr_errno(sr, rc);
    142 			return (SDRC_ERROR);
    143 		}
    144 	}
    145 
    146 	if (rc != 0) {
    147 		if (rc == EEXIST)
    148 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
    149 			    ERRDOS, ERROR_FILE_EXISTS);
    150 		else
    151 			smbsr_errno(sr, rc);
    152 		return (SDRC_ERROR);
    153 	}
    154 
    155 	rc = smbsr_encode_empty_result(sr);
    156 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    157 }
    158 
    159 /*
    160  * smb_validate_dirname
    161  *
    162  * Very basic directory name validation: checks for colons in a path.
    163  * Need to skip the drive prefix since it contains a colon.
    164  *
    165  * Returns NT_STATUS_SUCCESS if the name is valid,
    166  *         otherwise NT_STATUS_NOT_A_DIRECTORY.
    167  */
    168 uint32_t
    169 smb_validate_dirname(char *path)
    170 {
    171 	char *name;
    172 
    173 	if ((name = path) != 0) {
    174 		name += strspn(name, "\\");
    175 
    176 		if (strchr(name, ':') != 0)
    177 			return (NT_STATUS_NOT_A_DIRECTORY);
    178 	}
    179 
    180 	return (NT_STATUS_SUCCESS);
    181 }
    182 
    183 /*
    184  * smb_common_create_directory
    185  *
    186  * Currently called from:
    187  *		smb_com_create_directory
    188  *		smb_com_trans2_create_directory
    189  *
    190  * Returns errno values.
    191  */
    192 int
    193 smb_common_create_directory(smb_request_t *sr)
    194 {
    195 	int rc;
    196 	smb_attr_t new_attr;
    197 	smb_fqi_t *fqi;
    198 	smb_node_t *tnode;
    199 
    200 	fqi = &sr->arg.dirop.fqi;
    201 	tnode = sr->tid_tree->t_snode;
    202 
    203 	rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
    204 	    tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
    205 	if (rc != 0)
    206 		return (rc);
    207 
    208 	/* lookup node - to ensure that it does NOT exist */
    209 	rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
    210 	    tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
    211 	if (rc == 0) {
    212 		smb_node_release(fqi->fq_dnode);
    213 		smb_node_release(fqi->fq_fnode);
    214 		return (EEXIST);
    215 	}
    216 	if (rc != ENOENT) {
    217 		smb_node_release(fqi->fq_dnode);
    218 		return (rc);
    219 	}
    220 
    221 	rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode,
    222 	    FILE_ADD_SUBDIRECTORY);
    223 	if (rc != NT_STATUS_SUCCESS) {
    224 		smb_node_release(fqi->fq_dnode);
    225 		return (EACCES);
    226 	}
    227 
    228 	/*
    229 	 * Explicitly set sa_dosattr, otherwise the file system may
    230 	 * automatically apply FILE_ATTRIBUTE_ARCHIVE which, for
    231 	 * compatibility with windows servers, should not be set.
    232 	 */
    233 	bzero(&new_attr, sizeof (new_attr));
    234 	new_attr.sa_dosattr = FILE_ATTRIBUTE_DIRECTORY;
    235 	new_attr.sa_vattr.va_type = VDIR;
    236 	new_attr.sa_vattr.va_mode = 0777;
    237 	new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR;
    238 
    239 	rc = smb_fsop_mkdir(sr, sr->user_cr, fqi->fq_dnode, fqi->fq_last_comp,
    240 	    &new_attr, &fqi->fq_fnode);
    241 	if (rc != 0) {
    242 		smb_node_release(fqi->fq_dnode);
    243 		return (rc);
    244 	}
    245 
    246 	sr->arg.open.create_options = FILE_DIRECTORY_FILE;
    247 
    248 	smb_node_release(fqi->fq_dnode);
    249 	smb_node_release(fqi->fq_fnode);
    250 	return (0);
    251 }
    252 
    253 static smb_dirpath_t *
    254 smb_dirpath_new(smb_request_t *sr)
    255 {
    256 	int pathLen;
    257 	char *xpath;
    258 	smb_dirpath_t *spp;
    259 
    260 	/* Allocate using request specific memory. */
    261 	spp = smb_srm_alloc(sr, sizeof (smb_dirpath_t));
    262 	spp->sp_path = sr->arg.dirop.fqi.fq_path.pn_path;
    263 	pathLen = strlen(spp->sp_path);
    264 	spp->sp_curp = spp->sp_path;
    265 	xpath = smb_srm_alloc(sr, pathLen + 1);
    266 	sr->arg.dirop.fqi.fq_path.pn_path = xpath;
    267 	spp->sp_sr = sr;
    268 
    269 	return (spp);
    270 }
    271 
    272 /*
    273  * Perhaps somewhat dangerous since everything happens as a side effect. The
    274  * returns 1 if there is a valid component updated to the fqi, 0 otherwise.
    275  */
    276 static int
    277 smb_dirpath_next(smb_dirpath_t *spp)
    278 {
    279 	char *xp;
    280 	int xlen;
    281 
    282 	if (spp == 0)
    283 		return (0);
    284 
    285 	/* Move the index to the "next" "\" and copy the path to the fqi */
    286 	/* path for the next component. */
    287 
    288 	/* First look for the next component */
    289 	while (*spp->sp_curp == '\\')
    290 		spp->sp_curp++;
    291 
    292 	/* Now get to the end of the component */
    293 	xp = spp->sp_curp; /* Remember from where we started */
    294 	while (*spp->sp_curp != '\0' && *spp->sp_curp != '\\') {
    295 		spp->sp_curp++;
    296 	}
    297 
    298 	/* If we made no progress, we are done */
    299 	if (xp == spp->sp_curp)
    300 		return (0);
    301 
    302 	/*
    303 	 * Now copy the original path up to but not including our current
    304 	 * pointer
    305 	 */
    306 
    307 	/*LINTED E_PTRDIFF_OVERFLOW*/
    308 	xlen = spp->sp_curp - spp->sp_path;
    309 	(void) strncpy(spp->sp_sr->arg.dirop.fqi.fq_path.pn_path,
    310 	    spp->sp_path, xlen);
    311 
    312 	/* Now NULL terminate it */
    313 	spp->sp_sr->arg.dirop.fqi.fq_path.pn_path[xlen] = '\0';
    314 	return (1);
    315 }
    316 
    317 /*
    318  * The delete directory message is sent to delete an empty directory. The
    319  * appropriate Tid and additional pathname are passed. The directory must
    320  * be empty for it to be deleted.
    321  *
    322  * NT supports a hidden permission known as File Delete Child (FDC). If
    323  * the user has FullControl access to a directory, the user is permitted
    324  * to delete any object in the directory regardless of the permissions
    325  * on the object.
    326  *
    327  * Client Request                     Description
    328  * ================================== =================================
    329  * UCHAR WordCount;                   Count of parameter words = 0
    330  * USHORT ByteCount;                  Count of data bytes; min = 2
    331  * UCHAR BufferFormat;                0x04
    332  * STRING DirectoryName[];            Directory name
    333  *
    334  * The directory to be deleted cannot be the root of the share specified
    335  * by Tid.
    336  *
    337  * Server Response                    Description
    338  * ================================== =================================
    339  * UCHAR WordCount;                   Count of parameter words = 0
    340  * USHORT ByteCount;                  Count of data bytes = 0
    341  */
    342 smb_sdrc_t
    343 smb_pre_delete_directory(smb_request_t *sr)
    344 {
    345 	int rc;
    346 
    347 	rc = smbsr_decode_data(sr, "%S", sr,
    348 	    &sr->arg.dirop.fqi.fq_path.pn_path);
    349 
    350 	DTRACE_SMB_2(op__DeleteDirectory__start, smb_request_t *, sr,
    351 	    struct dirop *, &sr->arg.dirop);
    352 
    353 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    354 }
    355 
    356 void
    357 smb_post_delete_directory(smb_request_t *sr)
    358 {
    359 	DTRACE_SMB_1(op__DeleteDirectory__done, smb_request_t *, sr);
    360 }
    361 
    362 smb_sdrc_t
    363 smb_com_delete_directory(smb_request_t *sr)
    364 {
    365 	int rc;
    366 	uint32_t flags = 0;
    367 	smb_fqi_t *fqi;
    368 	smb_node_t *tnode;
    369 
    370 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
    371 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
    372 		    ERRDOS, ERROR_ACCESS_DENIED);
    373 		return (SDRC_ERROR);
    374 	}
    375 
    376 	fqi = &sr->arg.dirop.fqi;
    377 	tnode = sr->tid_tree->t_snode;
    378 
    379 	rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
    380 	    tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
    381 	if (rc != 0) {
    382 		smbsr_errno(sr, rc);
    383 		return (SDRC_ERROR);
    384 	}
    385 
    386 	rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
    387 	    tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
    388 	if (rc != 0) {
    389 		if (rc == ENOENT)
    390 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
    391 			    ERRDOS, ERROR_FILE_NOT_FOUND);
    392 		else
    393 			smbsr_errno(sr, rc);
    394 		smb_node_release(fqi->fq_dnode);
    395 		return (SDRC_ERROR);
    396 	}
    397 
    398 	rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
    399 	if (rc != 0) {
    400 		smbsr_errno(sr, rc);
    401 		smb_node_release(fqi->fq_dnode);
    402 		smb_node_release(fqi->fq_fnode);
    403 		return (SDRC_ERROR);
    404 	}
    405 
    406 	if (fqi->fq_fattr.sa_vattr.va_type != VDIR) {
    407 		smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
    408 		    ERRDOS, ERROR_PATH_NOT_FOUND);
    409 		smb_node_release(fqi->fq_dnode);
    410 		smb_node_release(fqi->fq_fnode);
    411 		return (SDRC_ERROR);
    412 	}
    413 
    414 	if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) ||
    415 	    (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE)
    416 	    != NT_STATUS_SUCCESS)) {
    417 		smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
    418 		    ERRDOS, ERROR_ACCESS_DENIED);
    419 		smb_node_release(fqi->fq_dnode);
    420 		smb_node_release(fqi->fq_fnode);
    421 		return (SDRC_ERROR);
    422 	}
    423 
    424 	if (SMB_TREE_SUPPORTS_CATIA(sr))
    425 		flags |= SMB_CATIA;
    426 
    427 	rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
    428 	    fqi->fq_fnode->od_name, flags);
    429 
    430 	smb_node_release(fqi->fq_fnode);
    431 	smb_node_release(fqi->fq_dnode);
    432 
    433 	if (rc != 0) {
    434 		if (rc == EEXIST)
    435 			smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
    436 			    ERRDOS, ERROR_DIR_NOT_EMPTY);
    437 		else
    438 			smbsr_errno(sr, rc);
    439 		return (SDRC_ERROR);
    440 	}
    441 
    442 	rc = smbsr_encode_empty_result(sr);
    443 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    444 }
    445 
    446 /*
    447  * This SMB is used to verify that a path exists and is a directory.  No
    448  * error is returned if the given path exists and the client has read
    449  * access to it.  Client machines which maintain a concept of a "working
    450  * directory" will find this useful to verify the validity of a "change
    451  * working directory" command.  Note that the servers do NOT have a concept
    452  * of working directory for a particular client.  The client must always
    453  * supply full pathnames relative to the Tid in the SMB header.
    454  *
    455  * Client Request                     Description
    456  * ================================== =================================
    457  *
    458  * UCHAR WordCount;                   Count of parameter words = 0
    459  * USHORT ByteCount;                  Count of data bytes;    min = 2
    460  * UCHAR BufferFormat;                0x04
    461  * STRING DirectoryPath[];            Directory path
    462  *
    463  * Server Response                    Description
    464  * ================================== =================================
    465  *
    466  * UCHAR WordCount;                   Count of parameter words = 0
    467  * USHORT ByteCount;                  Count of data bytes = 0
    468  *
    469  * DOS clients, in particular, depend on ERRbadpath if the directory is
    470  * not found.
    471  */
    472 smb_sdrc_t
    473 smb_pre_check_directory(smb_request_t *sr)
    474 {
    475 	int rc;
    476 
    477 	rc = smbsr_decode_data(sr, "%S", sr,
    478 	    &sr->arg.dirop.fqi.fq_path.pn_path);
    479 
    480 	DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr,
    481 	    struct dirop *, &sr->arg.dirop);
    482 
    483 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    484 }
    485 
    486 void
    487 smb_post_check_directory(smb_request_t *sr)
    488 {
    489 	DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr);
    490 }
    491 
    492 smb_sdrc_t
    493 smb_com_check_directory(smb_request_t *sr)
    494 {
    495 	int rc;
    496 	smb_fqi_t *fqi;
    497 	smb_node_t *tnode;
    498 	char *path;
    499 
    500 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
    501 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
    502 		    ERROR_ACCESS_DENIED);
    503 		return (SDRC_ERROR);
    504 	}
    505 
    506 	fqi = &sr->arg.dirop.fqi;
    507 	path = fqi->fq_path.pn_path;
    508 
    509 	if (path[0] == '\0') {
    510 		rc = smbsr_encode_empty_result(sr);
    511 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    512 	}
    513 
    514 	if (!smb_dirpath_isvalid(path)) {
    515 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
    516 		    ERRDOS, ERROR_PATH_NOT_FOUND);
    517 		return (SDRC_ERROR);
    518 	}
    519 
    520 	tnode = sr->tid_tree->t_snode;
    521 
    522 	rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
    523 	    &fqi->fq_dnode, fqi->fq_last_comp);
    524 	if (rc != 0) {
    525 		smbsr_errno(sr, rc);
    526 		return (SDRC_ERROR);
    527 	}
    528 
    529 	rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
    530 	    tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
    531 	smb_node_release(fqi->fq_dnode);
    532 	if (rc != 0) {
    533 		if (rc == ENOENT)
    534 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
    535 			    ERRDOS, ERROR_PATH_NOT_FOUND);
    536 		else
    537 			smbsr_errno(sr, rc);
    538 		return (SDRC_ERROR);
    539 	}
    540 
    541 	rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
    542 	if (rc != 0) {
    543 		smbsr_errno(sr, rc);
    544 		smb_node_release(fqi->fq_fnode);
    545 		return (SDRC_ERROR);
    546 	}
    547 
    548 	if (fqi->fq_fattr.sa_vattr.va_type != VDIR) {
    549 		smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
    550 		    ERRDOS, ERROR_PATH_NOT_FOUND);
    551 		smb_node_release(fqi->fq_fnode);
    552 		return (SDRC_ERROR);
    553 	}
    554 
    555 	rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, FILE_TRAVERSE);
    556 
    557 	smb_node_release(fqi->fq_fnode);
    558 
    559 	if (rc != 0) {
    560 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
    561 		    ERRDOS, ERROR_ACCESS_DENIED);
    562 		return (SDRC_ERROR);
    563 	}
    564 
    565 	rc = smbsr_encode_empty_result(sr);
    566 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    567 }
    568 
    569 static boolean_t
    570 smb_dirpath_isvalid(const char *path)
    571 {
    572 	struct {
    573 		char *name;
    574 		int len;
    575 	} *bad, bad_paths[] = {
    576 		{ ".\0",   2 },
    577 		{ ".\\\0", 3 },
    578 		{ "..\0",  3 },
    579 		{ "..\\",  3 }
    580 	};
    581 
    582 	char *cp;
    583 	char *p;
    584 	int i;
    585 
    586 	if (*path == '\0')
    587 		return (B_TRUE);
    588 
    589 	cp = smb_strdup(path);
    590 	p = strcanon(cp, "\\");
    591 	p += strspn(p, "\\");
    592 
    593 	for (i = 0; i < sizeof (bad_paths) / sizeof (bad_paths[0]); ++i) {
    594 		bad = &bad_paths[i];
    595 
    596 		if (strncmp(p, bad->name, bad->len) == 0) {
    597 			smb_mfree(cp);
    598 			return (B_FALSE);
    599 		}
    600 	}
    601 
    602 	smb_mfree(cp);
    603 	return (B_TRUE);
    604 }
    605