xref: /titanic_50/usr/src/lib/rpcsec_gss/rpcsec_gss_utils.c (revision 61961e0f20c7637a3846bb39786bb9dffa91dfb9)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22*61961e0fSrobinson 
237c478bd9Sstevel@tonic-gate /*
24*61961e0fSrobinson  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*61961e0fSrobinson  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <ctype.h>
337c478bd9Sstevel@tonic-gate #include <strings.h>
347c478bd9Sstevel@tonic-gate #include <errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/stat.h>
377c478bd9Sstevel@tonic-gate #include <syslog.h>
387c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h>
397c478bd9Sstevel@tonic-gate #include <gssapi/gssapi_ext.h>
407c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
417c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_defs.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #define	SVC_INTEGRITY	"integrity"
447c478bd9Sstevel@tonic-gate #define	SVC_PRIVACY	"privacy"
457c478bd9Sstevel@tonic-gate #define	SVC_NONE	"none"
467c478bd9Sstevel@tonic-gate #define	SVC_DEFAULT	"default"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define	MCALL_MSG_SIZE 24
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * Private data kept per client handle
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate struct cu_data {
537c478bd9Sstevel@tonic-gate 	int			cu_fd;		/* connections fd */
547c478bd9Sstevel@tonic-gate 	bool_t			cu_closeit;	/* opened by library */
557c478bd9Sstevel@tonic-gate 	struct netbuf		cu_raddr;	/* remote address */
567c478bd9Sstevel@tonic-gate 	struct timeval		cu_wait;	/* retransmit interval */
577c478bd9Sstevel@tonic-gate 	struct timeval		cu_total;	/* total time for the call */
587c478bd9Sstevel@tonic-gate 	struct rpc_err		cu_error;
597c478bd9Sstevel@tonic-gate 	struct t_unitdata	*cu_tr_data;
607c478bd9Sstevel@tonic-gate 	XDR			cu_outxdrs;
617c478bd9Sstevel@tonic-gate 	char			*cu_outbuf_start;
627c478bd9Sstevel@tonic-gate 	char			cu_outbuf[MCALL_MSG_SIZE];
63*61961e0fSrobinson 	uint_t			cu_xdrpos;
64*61961e0fSrobinson 	uint_t			cu_sendsz;	/* send size */
65*61961e0fSrobinson 	uint_t			cu_recvsz;	/* recv size */
667c478bd9Sstevel@tonic-gate 	struct pollfd		pfdp;
677c478bd9Sstevel@tonic-gate 	char			cu_inbuf[1];
687c478bd9Sstevel@tonic-gate };
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * Internal utility routines.
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_mech_to_oid(char * mech,rpc_gss_OID * oid)74*61961e0fSrobinson __rpc_gss_mech_to_oid(char *mech, rpc_gss_OID *oid)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE)
777c478bd9Sstevel@tonic-gate 		return (FALSE);
787c478bd9Sstevel@tonic-gate 	return (TRUE);
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate char *
__rpc_gss_oid_to_mech(rpc_gss_OID oid)82*61961e0fSrobinson __rpc_gss_oid_to_mech(rpc_gss_OID oid)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate 	return ((char *)__gss_oid_to_mech((const gss_OID)oid));
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_qop_to_num(char * qop,char * mech,OM_uint32 * num)89*61961e0fSrobinson __rpc_gss_qop_to_num(char *qop, char *mech, OM_uint32 *num)
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate 	if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE)
927c478bd9Sstevel@tonic-gate 		return (FALSE);
937c478bd9Sstevel@tonic-gate 	return (TRUE);
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate char *
__rpc_gss_num_to_qop(char * mech,OM_uint32 num)97*61961e0fSrobinson __rpc_gss_num_to_qop(char *mech, OM_uint32 num)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	char *qop;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE)
1027c478bd9Sstevel@tonic-gate 		return (NULL);
1037c478bd9Sstevel@tonic-gate 	return (qop);
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_svc_to_num(char * svc,rpc_gss_service_t * num)107*61961e0fSrobinson __rpc_gss_svc_to_num(char *svc, rpc_gss_service_t *num)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	if (strcasecmp(svc, SVC_INTEGRITY) == 0)
1107c478bd9Sstevel@tonic-gate 		*num = rpc_gss_svc_integrity;
1117c478bd9Sstevel@tonic-gate 	else if (strcasecmp(svc, SVC_PRIVACY) == 0)
1127c478bd9Sstevel@tonic-gate 		*num = rpc_gss_svc_privacy;
1137c478bd9Sstevel@tonic-gate 	else if (strcasecmp(svc, SVC_NONE) == 0)
1147c478bd9Sstevel@tonic-gate 		*num = rpc_gss_svc_none;
1157c478bd9Sstevel@tonic-gate 	else if (strcasecmp(svc, SVC_DEFAULT) == 0)
1167c478bd9Sstevel@tonic-gate 		*num = rpc_gss_svc_default;
1177c478bd9Sstevel@tonic-gate 	else
1187c478bd9Sstevel@tonic-gate 		return (FALSE);
1197c478bd9Sstevel@tonic-gate 	return (TRUE);
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate char *
__rpc_gss_num_to_svc(rpc_gss_service_t num)123*61961e0fSrobinson __rpc_gss_num_to_svc(rpc_gss_service_t num)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate 	switch (num) {
1267c478bd9Sstevel@tonic-gate 	case rpc_gss_svc_integrity:
1277c478bd9Sstevel@tonic-gate 		return (strdup(SVC_INTEGRITY));
1287c478bd9Sstevel@tonic-gate 	case rpc_gss_svc_privacy:
1297c478bd9Sstevel@tonic-gate 		return (strdup(SVC_PRIVACY));
1307c478bd9Sstevel@tonic-gate 	case rpc_gss_svc_none:
1317c478bd9Sstevel@tonic-gate 		return (strdup(SVC_NONE));
1327c478bd9Sstevel@tonic-gate 	case rpc_gss_svc_default:
1337c478bd9Sstevel@tonic-gate 		return (strdup(SVC_DEFAULT));
1347c478bd9Sstevel@tonic-gate 	default:
1357c478bd9Sstevel@tonic-gate 		return (NULL);
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate  * Given the user name, node, and security domain, get the mechanism
1417c478bd9Sstevel@tonic-gate  * specific principal name (for the user name) in exported form.
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_get_principal_name(rpc_gss_principal_t * principal,char * mech,char * user,char * node,char * secdomain)144*61961e0fSrobinson __rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mech,
145*61961e0fSrobinson 				char *user, char *node, char *secdomain)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	gss_name_t		gss_name, gss_canon_name;
1487c478bd9Sstevel@tonic-gate 	gss_buffer_desc		name_buf = GSS_C_EMPTY_BUFFER;
1497c478bd9Sstevel@tonic-gate 	char			user_name[256], *s;
1507c478bd9Sstevel@tonic-gate 	gss_OID			mech_oid;
1517c478bd9Sstevel@tonic-gate 	int			nlen = 0, slen = 0, plen;
1527c478bd9Sstevel@tonic-gate 	OM_uint32		major, minor;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	*principal = NULL;
1557c478bd9Sstevel@tonic-gate 	if (user == NULL || strlen(user) == 0)
1567c478bd9Sstevel@tonic-gate 		return (FALSE);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) {
1597c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get"
1607c478bd9Sstevel@tonic-gate 			"mech oid");
1617c478bd9Sstevel@tonic-gate 		return (FALSE);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if (secdomain != NULL)
1657c478bd9Sstevel@tonic-gate 		slen = strlen(secdomain);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	if (node != NULL)
1687c478bd9Sstevel@tonic-gate 		nlen = strlen(node);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	strcpy(user_name, user);
1717c478bd9Sstevel@tonic-gate 	if (nlen > 0) {
1727c478bd9Sstevel@tonic-gate 		strcat(user_name, "/");
1737c478bd9Sstevel@tonic-gate 		strcat(user_name, node);
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	if (slen > 0) {
1777c478bd9Sstevel@tonic-gate 		strcat(user_name, "@");
1787c478bd9Sstevel@tonic-gate 		strcat(user_name, secdomain);
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	name_buf.value = user_name;
1827c478bd9Sstevel@tonic-gate 	name_buf.length = strlen(user_name);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	/*
1857c478bd9Sstevel@tonic-gate 	 *  Convert a text string to a GSSAPI Internal name.
1867c478bd9Sstevel@tonic-gate 	 */
1877c478bd9Sstevel@tonic-gate 	if ((major = gss_import_name(&minor, &name_buf,
1887c478bd9Sstevel@tonic-gate 		(gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) {
1897c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: import name"
1907c478bd9Sstevel@tonic-gate 			"failed 0x%x", major);
1917c478bd9Sstevel@tonic-gate 		return (FALSE);
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	/*
1957c478bd9Sstevel@tonic-gate 	 *  Convert the GSSAPI Internal name to a MN - Mechanism Name
1967c478bd9Sstevel@tonic-gate 	 */
1977c478bd9Sstevel@tonic-gate 	if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid,
1987c478bd9Sstevel@tonic-gate 		&gss_canon_name)) != GSS_S_COMPLETE) {
1997c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name"
2007c478bd9Sstevel@tonic-gate 			"failed 0x%x", major);
2017c478bd9Sstevel@tonic-gate 		gss_release_name(&minor, &gss_name);
2027c478bd9Sstevel@tonic-gate 		return (FALSE);
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 	gss_release_name(&minor, &gss_name);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	/*
2077c478bd9Sstevel@tonic-gate 	 *  Convert the MN Internal name to an exported flat name, so
2087c478bd9Sstevel@tonic-gate 	 *  it is suitable for binary comparison.
2097c478bd9Sstevel@tonic-gate 	 */
2107c478bd9Sstevel@tonic-gate 	if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) !=
2117c478bd9Sstevel@tonic-gate 		GSS_S_COMPLETE) {
2127c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpc_gss_get_principal_name: export name"
2137c478bd9Sstevel@tonic-gate 			"failed %x", major);
2147c478bd9Sstevel@tonic-gate 		gss_release_name(&minor, &gss_canon_name);
2157c478bd9Sstevel@tonic-gate 		return (FALSE);
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 	gss_release_name(&minor, &gss_canon_name);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	 *  Put the exported name into rpc_gss_principal_t structure.
2217c478bd9Sstevel@tonic-gate 	 */
2227c478bd9Sstevel@tonic-gate 	plen = RNDUP(name_buf.length) + sizeof (int);
223*61961e0fSrobinson 	(*principal) = malloc(plen);
2247c478bd9Sstevel@tonic-gate 	if ((*principal) == NULL) {
2257c478bd9Sstevel@tonic-gate 		gss_release_buffer(&minor, &name_buf);
2267c478bd9Sstevel@tonic-gate 		return (FALSE);
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 	bzero((caddr_t)(*principal), plen);
2297c478bd9Sstevel@tonic-gate 	(*principal)->len = RNDUP(name_buf.length);
2307c478bd9Sstevel@tonic-gate 	s = (*principal)->name;
2317c478bd9Sstevel@tonic-gate 	memcpy(s, name_buf.value, name_buf.length);
2327c478bd9Sstevel@tonic-gate 	gss_release_buffer(&minor, &name_buf);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	return (TRUE);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * Return supported mechanisms.
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate char **
__rpc_gss_get_mechanisms(void)241*61961e0fSrobinson __rpc_gss_get_mechanisms(void)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	static char	*mech_list[MAX_MECH_OID_PAIRS+1];
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	*mech_list = NULL;
2467c478bd9Sstevel@tonic-gate 	__gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
2477c478bd9Sstevel@tonic-gate 	return (mech_list);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate /*
2517c478bd9Sstevel@tonic-gate  * For a given mechanism, return information about it.
2527c478bd9Sstevel@tonic-gate  */
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * static char			*krb5_qop_list[] = {Q_DEFAULT, NULL};
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
2587c478bd9Sstevel@tonic-gate /* Don't know how to get the service type for a given mech.	*/
2597c478bd9Sstevel@tonic-gate /* "service" should NOT be there!				*/
2607c478bd9Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate char **
__rpc_gss_get_mech_info(char * mech,rpc_gss_service_t * service)263*61961e0fSrobinson __rpc_gss_get_mech_info(char *mech, rpc_gss_service_t *service)
2647c478bd9Sstevel@tonic-gate {
2657c478bd9Sstevel@tonic-gate 	char **l;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *));
2687c478bd9Sstevel@tonic-gate 	if (l == NULL)
2697c478bd9Sstevel@tonic-gate 		return (NULL);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) {
2727c478bd9Sstevel@tonic-gate 		free(l);
2737c478bd9Sstevel@tonic-gate 		return (NULL);
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 					/* !!!!!!!!!!!!!!!! */
2767c478bd9Sstevel@tonic-gate 	*service = rpc_gss_svc_privacy; /* What service type? */
2777c478bd9Sstevel@tonic-gate 					/* !!!!!!!!!!!!!!!! */
2787c478bd9Sstevel@tonic-gate 	return (l);
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate /*
2827c478bd9Sstevel@tonic-gate  * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
2837c478bd9Sstevel@tonic-gate  */
2847c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_get_versions(uint_t * vers_hi,uint_t * vers_lo)285*61961e0fSrobinson __rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	*vers_hi = RPCSEC_GSS_VERSION;
2887c478bd9Sstevel@tonic-gate 	*vers_lo = RPCSEC_GSS_VERSION;
2897c478bd9Sstevel@tonic-gate 	return (TRUE);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate  * Check if a mechanism is installed.
2947c478bd9Sstevel@tonic-gate  */
2957c478bd9Sstevel@tonic-gate bool_t
__rpc_gss_is_installed(char * mech)296*61961e0fSrobinson __rpc_gss_is_installed(char *mech)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	char **l;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	if (mech == NULL)
3017c478bd9Sstevel@tonic-gate 		return (FALSE);
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if ((l = __rpc_gss_get_mechanisms()) == NULL)
3047c478bd9Sstevel@tonic-gate 		return (FALSE);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	while (*l != NULL) {
3077c478bd9Sstevel@tonic-gate 		if (strcmp(*l, mech) == 0)
3087c478bd9Sstevel@tonic-gate 			return (TRUE);
3097c478bd9Sstevel@tonic-gate 		l++;
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 	return (FALSE);
3127c478bd9Sstevel@tonic-gate }
313