xref: /onnv-gate/usr/src/lib/libldap4/common/saslbind.c (revision 3857:21b9b714e4ab)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  *
3*3857Sstevel  * Copyright 2000 Sun Microsystems, Inc.  All rights reserved.
4*3857Sstevel  * Use is subject to license terms.
50Sstevel@tonic-gate  *
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * Comments:
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  */
100Sstevel@tonic-gate 
110Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
120Sstevel@tonic-gate 
130Sstevel@tonic-gate #include <stdio.h>
140Sstevel@tonic-gate #include <string.h>
150Sstevel@tonic-gate 
160Sstevel@tonic-gate #include "lber.h"
170Sstevel@tonic-gate #include "ldap.h"
180Sstevel@tonic-gate #include "ldap-private.h"
190Sstevel@tonic-gate #include "ldap-int.h"
200Sstevel@tonic-gate #include "sec.h"
210Sstevel@tonic-gate #include <strings.h>
220Sstevel@tonic-gate 
ldap_build_sasl_bind_req(LDAP * ld,char * dn,char * mechanism,struct berval * creds,LDAPControl ** serverctrls)230Sstevel@tonic-gate BerElement * ldap_build_sasl_bind_req( LDAP *ld, char *dn, char *mechanism, struct berval *creds, LDAPControl ** serverctrls)
240Sstevel@tonic-gate {
250Sstevel@tonic-gate 	BerElement *ber = NULL;
260Sstevel@tonic-gate 	int err;
270Sstevel@tonic-gate 
280Sstevel@tonic-gate 	/* Create a Bind Request for SASL authentication.
290Sstevel@tonic-gate 	 * It look like this :
300Sstevel@tonic-gate 	 * BindRequest := [APPLICATION 0] SEQUENCE {
310Sstevel@tonic-gate 	 *		version		INTEGER,
320Sstevel@tonic-gate 	 *		name		LDAPDN,
330Sstevel@tonic-gate 	 *		authentication	CHOICE {
340Sstevel@tonic-gate 	 *			sasl		[3] SEQUENCE {
350Sstevel@tonic-gate 	 *				mechanism	LDAPString,
360Sstevel@tonic-gate 	 *				credential	OCTET STRING OPTIONAL
370Sstevel@tonic-gate 	 * 			}
380Sstevel@tonic-gate 	 *		}
390Sstevel@tonic-gate 	 *	}
400Sstevel@tonic-gate 	 * all wrapped up in an LDAPMessage sequence.
410Sstevel@tonic-gate 	 */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate 	if (dn == NULL || *dn == '\0'){
440Sstevel@tonic-gate 		ld->ld_errno = LDAP_PARAM_ERROR;
450Sstevel@tonic-gate 		return (NULLBER);
460Sstevel@tonic-gate 	}
470Sstevel@tonic-gate 
480Sstevel@tonic-gate 
490Sstevel@tonic-gate 	if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
500Sstevel@tonic-gate 		return (NULLBER);
510Sstevel@tonic-gate 	}
520Sstevel@tonic-gate 	if ( ber_printf( ber, "{it{ist{s", ++ld->ld_msgid, LDAP_REQ_BIND, ld->ld_version, dn, LDAP_AUTH_SASL, mechanism) == -1){
530Sstevel@tonic-gate 		ld->ld_errno = LDAP_ENCODING_ERROR;
540Sstevel@tonic-gate 		ber_free(ber, 1);
550Sstevel@tonic-gate 		return (NULLBER);
560Sstevel@tonic-gate 	}
570Sstevel@tonic-gate 	if (creds != NULL && creds->bv_val != NULL) {
580Sstevel@tonic-gate 		if (ber_printf(ber, "o", creds->bv_val, creds->bv_len) == -1){
590Sstevel@tonic-gate 			ld->ld_errno = LDAP_ENCODING_ERROR;
600Sstevel@tonic-gate 			ber_free(ber, 1);
610Sstevel@tonic-gate 			return (NULLBER);
620Sstevel@tonic-gate 		}
630Sstevel@tonic-gate 	}
640Sstevel@tonic-gate 	if (ber_printf(ber, "}}") == -1){
650Sstevel@tonic-gate 		ld->ld_errno = LDAP_ENCODING_ERROR;
660Sstevel@tonic-gate 		ber_free( ber, 1 );
670Sstevel@tonic-gate 		return( NULLBER );
680Sstevel@tonic-gate 	}
690Sstevel@tonic-gate 	/* LDAPv3 */
700Sstevel@tonic-gate 	/* Code controls if any */
710Sstevel@tonic-gate 	if (serverctrls && serverctrls[0]) {
720Sstevel@tonic-gate 		if (ldap_controls_code(ber, serverctrls) != LDAP_SUCCESS){
730Sstevel@tonic-gate 			ld->ld_errno = LDAP_ENCODING_ERROR;
740Sstevel@tonic-gate 			ber_free( ber, 1 );
750Sstevel@tonic-gate 			return( NULLBER );
760Sstevel@tonic-gate 		}
770Sstevel@tonic-gate 	} else if (ld->ld_srvctrls && ld->ld_srvctrls[0]) {
780Sstevel@tonic-gate 		/* Otherwise, is there any global server ctrls ? */
790Sstevel@tonic-gate 		if (ldap_controls_code(ber, ld->ld_srvctrls) != LDAP_SUCCESS){
800Sstevel@tonic-gate 			ld->ld_errno = LDAP_ENCODING_ERROR;
810Sstevel@tonic-gate 			ber_free( ber, 1 );
820Sstevel@tonic-gate 			return( NULLBER );
830Sstevel@tonic-gate 		}
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	if ( ber_printf( ber, "}" ) == -1 ) {
870Sstevel@tonic-gate 		ld->ld_errno = LDAP_ENCODING_ERROR;
880Sstevel@tonic-gate 		ber_free( ber, 1 );
890Sstevel@tonic-gate 		return( NULLBER );
900Sstevel@tonic-gate 	}
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	return (ber);
930Sstevel@tonic-gate }
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate  * ldap_sasl_bind - bind to the ldap server (and X.500).
970Sstevel@tonic-gate  * dn, mechanism, cred, serverctrls, and clientctrls are supplied.
980Sstevel@tonic-gate  * the message id of the request is returned in msgid
990Sstevel@tonic-gate  * Returns LDAP_SUCCESS or an error code.
1000Sstevel@tonic-gate  */
1010Sstevel@tonic-gate 
ldap_sasl_bind(LDAP * ld,char * dn,char * mechanism,struct berval * cred,LDAPControl ** serverctrls,LDAPControl ** clientctrls,int * msgidp)1020Sstevel@tonic-gate int ldap_sasl_bind(
1030Sstevel@tonic-gate 	LDAP *ld,
1040Sstevel@tonic-gate 	char *dn,
1050Sstevel@tonic-gate 	char *mechanism,
1060Sstevel@tonic-gate 	struct berval *cred,
1070Sstevel@tonic-gate 	LDAPControl **serverctrls,
1080Sstevel@tonic-gate 	LDAPControl **clientctrls,
1090Sstevel@tonic-gate 	int *msgidp)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate 	int theErr = LDAP_SUCCESS;
1120Sstevel@tonic-gate 	int rv;
1130Sstevel@tonic-gate 	BerElement *ber = NULL;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	Debug ( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1288, "ldap_sasl_bind\n"), 0,0,0);
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate #ifdef _REENTRANT
1180Sstevel@tonic-gate 	LOCK_LDAP(ld);
1190Sstevel@tonic-gate #endif
1200Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_SIMPLE) == 0){
1210Sstevel@tonic-gate 		/* Simple bind */
1220Sstevel@tonic-gate 		if ( (ber = ldap_build_simple_bind_req(ld, dn, cred->bv_val, serverctrls)) == NULLBER){
1230Sstevel@tonic-gate 			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
1240Sstevel@tonic-gate #ifdef _REENTRANT
1250Sstevel@tonic-gate 			UNLOCK_LDAP(ld);
1260Sstevel@tonic-gate #endif
1270Sstevel@tonic-gate 			return (theErr);
1280Sstevel@tonic-gate 		}
1290Sstevel@tonic-gate 	}
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_CRAM_MD5) == 0){
1320Sstevel@tonic-gate 		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_CRAM_MD5, cred, serverctrls)) == NULLBER) {
1330Sstevel@tonic-gate 			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
1340Sstevel@tonic-gate #ifdef _REENTRANT
1350Sstevel@tonic-gate 			UNLOCK_LDAP(ld);
1360Sstevel@tonic-gate #endif
1370Sstevel@tonic-gate 			return (theErr);
1380Sstevel@tonic-gate 		}
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_EXTERNAL) == 0){
1420Sstevel@tonic-gate 		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_EXTERNAL, cred, serverctrls)) == NULLBER) {
1430Sstevel@tonic-gate 			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
1440Sstevel@tonic-gate #ifdef _REENTRANT
1450Sstevel@tonic-gate 			UNLOCK_LDAP(ld);
1460Sstevel@tonic-gate #endif
1470Sstevel@tonic-gate 			return (theErr);
1480Sstevel@tonic-gate 		}
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_X511_PROTECTED) == 0){
1520Sstevel@tonic-gate #ifdef _REENTRANT
1530Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
1540Sstevel@tonic-gate #endif
1550Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
1580Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
1590Sstevel@tonic-gate  *#ifdef _REENTRANT
1600Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
1610Sstevel@tonic-gate  *#endif
1620Sstevel@tonic-gate  *			return (theErr);
1630Sstevel@tonic-gate  *		}
1640Sstevel@tonic-gate  */
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_X511_STRONG) == 0){
1670Sstevel@tonic-gate #ifdef _REENTRANT
1680Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
1690Sstevel@tonic-gate #endif
1700Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
1730Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
1740Sstevel@tonic-gate  *#ifdef _REENTRANT
1750Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
1760Sstevel@tonic-gate  *#endif
1770Sstevel@tonic-gate  *			return (theErr);
1780Sstevel@tonic-gate  *		}
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_KERBEROS_V4) == 0){
1820Sstevel@tonic-gate #ifdef _REENTRANT
1830Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
1840Sstevel@tonic-gate #endif
1850Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
1880Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
1890Sstevel@tonic-gate  *#ifdef _REENTRANT
1900Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
1910Sstevel@tonic-gate  *#endif
1920Sstevel@tonic-gate  *			return (theErr);
1930Sstevel@tonic-gate  *		}
1940Sstevel@tonic-gate  */
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_GSSAPI) == 0){
1970Sstevel@tonic-gate #ifdef _REENTRANT
1980Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
1990Sstevel@tonic-gate #endif
2000Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
2010Sstevel@tonic-gate /*
2020Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
2030Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
2040Sstevel@tonic-gate  *#ifdef _REENTRANT
2050Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
2060Sstevel@tonic-gate  *#endif
2070Sstevel@tonic-gate  *			return (theErr);
2080Sstevel@tonic-gate  *		}
2090Sstevel@tonic-gate  */
2100Sstevel@tonic-gate 	}
2110Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_SKEY) == 0){
2120Sstevel@tonic-gate #ifdef _REENTRANT
2130Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
2140Sstevel@tonic-gate #endif
2150Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
2180Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
2190Sstevel@tonic-gate  *#ifdef _REENTRANT
2200Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
2210Sstevel@tonic-gate  *#endif
2220Sstevel@tonic-gate  *			return (theErr);
2230Sstevel@tonic-gate  *		}
2240Sstevel@tonic-gate  */
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 	if (ber == NULL){
2270Sstevel@tonic-gate #ifdef _REENTRANT
2280Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
2290Sstevel@tonic-gate #endif
2300Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate #ifndef NO_CACHE
2340Sstevel@tonic-gate 	if ( ld->ld_cache != NULL ) {
2350Sstevel@tonic-gate 		ldap_flush_cache( ld );
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate #endif /* !NO_CACHE */
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	/* send the message */
2400Sstevel@tonic-gate 	rv = send_initial_request( ld, LDAP_REQ_BIND, dn, ber );
2410Sstevel@tonic-gate 	if (rv == -1){
2420Sstevel@tonic-gate 		rv = ld->ld_errno;
2430Sstevel@tonic-gate 		if (rv == LDAP_SUCCESS){
2440Sstevel@tonic-gate 			rv = LDAP_OTHER;
2450Sstevel@tonic-gate 		}
2460Sstevel@tonic-gate #ifdef _REENTRANT
2470Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
2480Sstevel@tonic-gate #endif
2490Sstevel@tonic-gate 		return (rv);
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 	*msgidp = rv;
2520Sstevel@tonic-gate #ifdef _REENTRANT
2530Sstevel@tonic-gate 	UNLOCK_LDAP(ld);
2540Sstevel@tonic-gate #endif
2550Sstevel@tonic-gate 	return ( LDAP_SUCCESS );
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate /*
2590Sstevel@tonic-gate  * ldap_sasl_bind_s - bind to the ldap server (and X.500).
2600Sstevel@tonic-gate  * dn, mechanism, cred, serverctrls, and clientctrls are supplied.
2610Sstevel@tonic-gate  * the message id of the request is returned in msgid
2620Sstevel@tonic-gate  * Returns LDAP_SUCCESS or an error code.
2630Sstevel@tonic-gate  */
2640Sstevel@tonic-gate 
ldap_sasl_bind_s(LDAP * ld,char * dn,char * mechanism,struct berval * cred,LDAPControl ** serverctrls,LDAPControl ** clientctrls,struct berval ** servercredp)2650Sstevel@tonic-gate int ldap_sasl_bind_s(
2660Sstevel@tonic-gate 	LDAP *ld,
2670Sstevel@tonic-gate 	char *dn,
2680Sstevel@tonic-gate 	char *mechanism,
2690Sstevel@tonic-gate 	struct berval *cred,
2700Sstevel@tonic-gate 	LDAPControl **serverctrls,
2710Sstevel@tonic-gate 	LDAPControl **clientctrls,
2720Sstevel@tonic-gate 	struct berval **servercredp)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	int msgid;
2750Sstevel@tonic-gate 	int retcode;
2760Sstevel@tonic-gate 	LDAPMessage *res;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	Debug ( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1288, "ldap_sasl_bind\n"), 0,0,0);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	if ((retcode = ldap_sasl_bind(ld, dn, mechanism, cred, serverctrls, clientctrls, &msgid)) != LDAP_SUCCESS)
2810Sstevel@tonic-gate 		return (retcode);
2820Sstevel@tonic-gate 	if (ldap_result(ld, msgid, 1, (struct timeval *)NULL, &res ) == -1)
2830Sstevel@tonic-gate 		return (ld->ld_errno );
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	return (ldap_parse_sasl_bind_result(ld, res, servercredp, 1));
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
ldap_sasl_cram_md5_bind_s(LDAP * ld,char * dn,struct berval * cred,LDAPControl ** serverctrls,LDAPControl ** clientctrls)2880Sstevel@tonic-gate int ldap_sasl_cram_md5_bind_s(
2890Sstevel@tonic-gate 	LDAP *ld,
2900Sstevel@tonic-gate 	char *dn,
2910Sstevel@tonic-gate 	struct berval *cred,
2920Sstevel@tonic-gate 	LDAPControl **serverctrls,
2930Sstevel@tonic-gate 	LDAPControl **clientctrls )
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate 	int res;
2960Sstevel@tonic-gate 	struct berval *challenge = NULL;
2970Sstevel@tonic-gate 	struct berval resp;
2980Sstevel@tonic-gate 	unsigned char digest[16];
2990Sstevel@tonic-gate 	char *theHDigest;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	if (dn == NULL){
3020Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	bzero(digest, sizeof (digest));
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	if ((res = ldap_sasl_bind_s(ld, dn, LDAP_SASL_CRAM_MD5, NULL, serverctrls, clientctrls, &challenge))
3080Sstevel@tonic-gate 		!= LDAP_SASL_BIND_INPROGRESS){
3090Sstevel@tonic-gate 		return (res);
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 	if (challenge == NULL){
3120Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
3130Sstevel@tonic-gate 	}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	Debug (LDAP_DEBUG_TRACE, "SASL challenge: %s\n", challenge->bv_val, 0, 0);
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	hmac_md5((unsigned char *)challenge->bv_val, challenge->bv_len,
3180Sstevel@tonic-gate 					 (unsigned char *)cred->bv_val, cred->bv_len,  digest);
3190Sstevel@tonic-gate 	ber_bvfree(challenge);
3200Sstevel@tonic-gate 	challenge = NULL;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	theHDigest = hexa_print(digest, 16);
3230Sstevel@tonic-gate 	if (theHDigest == NULL){
3240Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	resp.bv_len = (strlen(dn) + 32 + 1);
3280Sstevel@tonic-gate 	if ((resp.bv_val = (char *)malloc(resp.bv_len+1)) == NULL) {
3290Sstevel@tonic-gate 		return(LDAP_NO_MEMORY);
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	sprintf(resp.bv_val, "%s %s", dn, theHDigest);
3330Sstevel@tonic-gate 	free(theHDigest);
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	Debug (LDAP_DEBUG_TRACE, "SASL response: %s\n", resp.bv_val, 0, 0);
3360Sstevel@tonic-gate 	res = ldap_sasl_bind_s(ld, dn, LDAP_SASL_CRAM_MD5, &resp, serverctrls, clientctrls, &challenge);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	free(resp.bv_val);
3390Sstevel@tonic-gate 	return (res);
3400Sstevel@tonic-gate }
341