xref: /titanic_51/usr/src/lib/libldap5/sources/ldap/common/sasl.c (revision e6a862fb20c4553833b7a4b0ccf3a456a4d8c23f)
17c478bd9Sstevel@tonic-gate /*
236ca3987Schinlong  * CDDL HEADER START
336ca3987Schinlong  *
436ca3987Schinlong  * The contents of this file are subject to the terms of the
536ca3987Schinlong  * Common Development and Distribution License (the "License").
636ca3987Schinlong  * You may not use this file except in compliance with the License.
736ca3987Schinlong  *
836ca3987Schinlong  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
936ca3987Schinlong  * or http://www.opensolaris.org/os/licensing.
1036ca3987Schinlong  * See the License for the specific language governing permissions
1136ca3987Schinlong  * and limitations under the License.
1236ca3987Schinlong  *
1336ca3987Schinlong  * When distributing Covered Code, include this CDDL HEADER in each
1436ca3987Schinlong  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1536ca3987Schinlong  * If applicable, add the following below this CDDL HEADER, with the
1636ca3987Schinlong  * fields enclosed by brackets "[]" replaced with your own identifying
1736ca3987Schinlong  * information: Portions Copyright [yyyy] [name of copyright owner]
1836ca3987Schinlong  *
1936ca3987Schinlong  * CDDL HEADER END
2036ca3987Schinlong  */
2136ca3987Schinlong /*
22*e6a862fbSDouglas Leavitt  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #ifdef LDAP_SASLIO_HOOKS
277c478bd9Sstevel@tonic-gate #include <assert.h>
287c478bd9Sstevel@tonic-gate #include "ldap-int.h"
297c478bd9Sstevel@tonic-gate #include "../ber/lber-int.h"
307c478bd9Sstevel@tonic-gate #include <sasl/sasl.h>
317c478bd9Sstevel@tonic-gate #include <thread.h>
327c478bd9Sstevel@tonic-gate #include <synch.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #define SEARCH_TIMEOUT_SECS	120
357c478bd9Sstevel@tonic-gate #define NSLDAPI_SM_BUF	128
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate extern void *sasl_create_context(void);
387c478bd9Sstevel@tonic-gate extern void sasl_free_context(void *ctx);
397c478bd9Sstevel@tonic-gate extern int _sasl_client_init(void *ctx, const sasl_callback_t *callbacks);
407c478bd9Sstevel@tonic-gate extern int _sasl_client_new(void *ctx, const char *service,
417c478bd9Sstevel@tonic-gate 	const char *serverFQDN, const char *iplocalport,
427c478bd9Sstevel@tonic-gate 	const char *ipremoteport,
437c478bd9Sstevel@tonic-gate 	const sasl_callback_t *prompt_supp,
447c478bd9Sstevel@tonic-gate 	unsigned flags, sasl_conn_t **pconn);
457c478bd9Sstevel@tonic-gate extern int _sasl_server_init(void *ctx,
467c478bd9Sstevel@tonic-gate 	const sasl_callback_t *callbacks, const char *appname);
477c478bd9Sstevel@tonic-gate extern int _sasl_server_new(void *ctx, const char *service,
487c478bd9Sstevel@tonic-gate 	const char *serverFQDN, const char *user_realm,
497c478bd9Sstevel@tonic-gate 	const char *iplocalport, const char *ipremoteport,
507c478bd9Sstevel@tonic-gate 	const sasl_callback_t *callbacks,
517c478bd9Sstevel@tonic-gate 	unsigned flags, sasl_conn_t **pconn);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static int nsldapi_sasl_close( LDAP *ld, Sockbuf *sb );
54*e6a862fbSDouglas Leavitt static void destroy_sasliobuf(Sockbuf *sb);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * SASL Dependent routines
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  * SASL security and integrity options are supported through the
607c478bd9Sstevel@tonic-gate  * use of the extended I/O functionality.  Because the extended
617c478bd9Sstevel@tonic-gate  * I/O functions may already be in use prior to enabling encryption,
627c478bd9Sstevel@tonic-gate  * when SASL encryption is enabled, these routine interpose themselves
637c478bd9Sstevel@tonic-gate  * over the existng extended I/O routines and add an additional level
647c478bd9Sstevel@tonic-gate  * of indirection.
657c478bd9Sstevel@tonic-gate  *  IE: Before SASL:  client->libldap->lber->extio
667c478bd9Sstevel@tonic-gate  *      After  SASL:  client->libldap->lber->saslio->extio
677c478bd9Sstevel@tonic-gate  * Any extio functions are still used for the raw i/O [IE prldap]
687c478bd9Sstevel@tonic-gate  * but SASL will decrypt before passing to lber.
697c478bd9Sstevel@tonic-gate  * SASL cannot decrypt a stream so full packets must be read
707c478bd9Sstevel@tonic-gate  * before proceeding.
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static int nsldapi_sasl_fail()
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate 	return( SASL_FAIL );
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * Global SASL Init data
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static sasl_callback_t client_callbacks[] = {
837c478bd9Sstevel@tonic-gate 	{ SASL_CB_GETOPT, nsldapi_sasl_fail, NULL },
847c478bd9Sstevel@tonic-gate 	{ SASL_CB_GETREALM, NULL, NULL },
857c478bd9Sstevel@tonic-gate 	{ SASL_CB_USER, NULL, NULL },
867c478bd9Sstevel@tonic-gate 	{ SASL_CB_AUTHNAME, NULL, NULL },
877c478bd9Sstevel@tonic-gate 	{ SASL_CB_PASS, NULL, NULL },
887c478bd9Sstevel@tonic-gate 	{ SASL_CB_ECHOPROMPT, NULL, NULL },
897c478bd9Sstevel@tonic-gate 	{ SASL_CB_NOECHOPROMPT, NULL, NULL },
907c478bd9Sstevel@tonic-gate 	{ SASL_CB_LIST_END, NULL, NULL }
917c478bd9Sstevel@tonic-gate };
927c478bd9Sstevel@tonic-gate static mutex_t sasl_mutex = DEFAULTMUTEX;
937c478bd9Sstevel@tonic-gate static int nsldapi_sasl_inited = 0;
947c478bd9Sstevel@tonic-gate static void *gctx;  /* intentially not freed - avoid libsasl re-inits */
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate int nsldapi_sasl_init( void )
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	int	saslrc;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	mutex_lock(&sasl_mutex);
1017c478bd9Sstevel@tonic-gate 	if ( nsldapi_sasl_inited ) {
1027c478bd9Sstevel@tonic-gate 		mutex_unlock(&sasl_mutex);
1037c478bd9Sstevel@tonic-gate 		return( 0 );
1047c478bd9Sstevel@tonic-gate 	}
1057c478bd9Sstevel@tonic-gate 	if ((gctx = (void *)sasl_create_context()) != NULL) {
1067c478bd9Sstevel@tonic-gate 		saslrc = _sasl_client_init(gctx, client_callbacks);
1077c478bd9Sstevel@tonic-gate 		if (saslrc == SASL_OK ) {
1087c478bd9Sstevel@tonic-gate 			nsldapi_sasl_inited = 1;
1097c478bd9Sstevel@tonic-gate 			mutex_unlock(&sasl_mutex);
1107c478bd9Sstevel@tonic-gate 			return( 0 );
1117c478bd9Sstevel@tonic-gate 		}
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate 	mutex_unlock(&sasl_mutex);
1147c478bd9Sstevel@tonic-gate 	return( -1 );
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate  * SASL encryption routines
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * Get the 4 octet header [size] for a sasl encrypted buffer.
1237c478bd9Sstevel@tonic-gate  * See RFC222 [section 3].
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate static int
1277c478bd9Sstevel@tonic-gate nsldapi_sasl_pktlen( char *buf, int maxbufsize )
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	int	size;
1307c478bd9Sstevel@tonic-gate 
13136ca3987Schinlong #if defined( _WINDOWS ) || defined( _WIN32 )
1327c478bd9Sstevel@tonic-gate 	size = ntohl(*(long *)buf);
13336ca3987Schinlong #else
13436ca3987Schinlong 	size = ntohl(*(uint32_t *)buf);
13536ca3987Schinlong #endif
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	if ( size < 0 || size > maxbufsize ) {
1387c478bd9Sstevel@tonic-gate 		return (-1 );
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	return( size + 4 ); /* include the first 4 bytes */
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate static int
1457c478bd9Sstevel@tonic-gate nsldapi_sasl_read( int s, void *buf, int  len,
1467c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private *arg)
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
1497c478bd9Sstevel@tonic-gate 	LDAP		*ld;
1507c478bd9Sstevel@tonic-gate 	const char	*dbuf;
1517c478bd9Sstevel@tonic-gate 	char		*cp;
1527c478bd9Sstevel@tonic-gate 	int		ret;
1537c478bd9Sstevel@tonic-gate 	unsigned	dlen, blen;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	if (sb == NULL) {
1567c478bd9Sstevel@tonic-gate 		return( -1 );
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	ld = (LDAP *)sb->sb_sasl_prld;
1607c478bd9Sstevel@tonic-gate 	if (ld == NULL) {
1617c478bd9Sstevel@tonic-gate 		return( -1 );
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	/* Is there anything left in the existing buffer? */
1657c478bd9Sstevel@tonic-gate 	if ((ret = sb->sb_sasl_ilen) > 0) {
1667c478bd9Sstevel@tonic-gate 		ret = (ret > len ? len : ret);
1677c478bd9Sstevel@tonic-gate 		SAFEMEMCPY( buf, sb->sb_sasl_iptr, ret );
1687c478bd9Sstevel@tonic-gate 		if (ret == sb->sb_sasl_ilen) {
1697c478bd9Sstevel@tonic-gate 			sb->sb_sasl_ilen = 0;
1707c478bd9Sstevel@tonic-gate 			sb->sb_sasl_iptr = NULL;
1717c478bd9Sstevel@tonic-gate 		} else {
1727c478bd9Sstevel@tonic-gate 			sb->sb_sasl_ilen -= ret;
1737c478bd9Sstevel@tonic-gate 			sb->sb_sasl_iptr += ret;
1747c478bd9Sstevel@tonic-gate 		}
1757c478bd9Sstevel@tonic-gate 		return( ret );
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/* buffer is empty - fill it */
1797c478bd9Sstevel@tonic-gate 	cp = sb->sb_sasl_ibuf;
1807c478bd9Sstevel@tonic-gate 	dlen = 0;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/* Read the length of the packet */
1837c478bd9Sstevel@tonic-gate 	while ( dlen < 4 ) {
1847c478bd9Sstevel@tonic-gate 		if (sb->sb_sasl_fns.lbextiofn_read != NULL) {
1857c478bd9Sstevel@tonic-gate 			ret = sb->sb_sasl_fns.lbextiofn_read(
1867c478bd9Sstevel@tonic-gate 				s, cp, 4 - dlen,
1877c478bd9Sstevel@tonic-gate 				sb->sb_sasl_fns.lbextiofn_socket_arg);
1887c478bd9Sstevel@tonic-gate 		} else {
1897c478bd9Sstevel@tonic-gate 			ret = read( sb->sb_sd, cp, 4 - dlen );
1907c478bd9Sstevel@tonic-gate 		}
1917c478bd9Sstevel@tonic-gate #ifdef EINTR
1927c478bd9Sstevel@tonic-gate 		if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) )
1937c478bd9Sstevel@tonic-gate 			continue;
1947c478bd9Sstevel@tonic-gate #endif
1957c478bd9Sstevel@tonic-gate 		if ( ret <= 0 )
1967c478bd9Sstevel@tonic-gate 			return( ret );
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 		cp += ret;
1997c478bd9Sstevel@tonic-gate 		dlen += ret;
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	blen = 4;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	ret = nsldapi_sasl_pktlen( sb->sb_sasl_ibuf, sb->sb_sasl_bfsz );
2057c478bd9Sstevel@tonic-gate 	if (ret < 0) {
2067c478bd9Sstevel@tonic-gate 		LDAP_SET_ERRNO(ld, EIO);
2077c478bd9Sstevel@tonic-gate 		return( -1 );
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 	dlen = ret - dlen;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	/* read the rest of the encrypted packet */
2127c478bd9Sstevel@tonic-gate 	while ( dlen > 0 ) {
2137c478bd9Sstevel@tonic-gate 		if (sb->sb_sasl_fns.lbextiofn_read != NULL) {
2147c478bd9Sstevel@tonic-gate 			ret = sb->sb_sasl_fns.lbextiofn_read(
2157c478bd9Sstevel@tonic-gate 				s, cp, dlen,
2167c478bd9Sstevel@tonic-gate 				sb->sb_sasl_fns.lbextiofn_socket_arg);
2177c478bd9Sstevel@tonic-gate 		} else {
2187c478bd9Sstevel@tonic-gate 			ret = read( sb->sb_sd, cp, dlen );
2197c478bd9Sstevel@tonic-gate 		}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate #ifdef EINTR
2227c478bd9Sstevel@tonic-gate 		if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) )
2237c478bd9Sstevel@tonic-gate 			continue;
2247c478bd9Sstevel@tonic-gate #endif
2257c478bd9Sstevel@tonic-gate 		if ( ret <= 0 )
2267c478bd9Sstevel@tonic-gate 			return( ret );
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 		cp += ret;
2297c478bd9Sstevel@tonic-gate 		blen += ret;
2307c478bd9Sstevel@tonic-gate 		dlen -= ret;
2317c478bd9Sstevel@tonic-gate    	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/* Decode the packet */
2347c478bd9Sstevel@tonic-gate 	ret = sasl_decode( sb->sb_sasl_ctx,
2357c478bd9Sstevel@tonic-gate 			   sb->sb_sasl_ibuf, blen,
2367c478bd9Sstevel@tonic-gate 			   &dbuf, &dlen);
2377c478bd9Sstevel@tonic-gate 	if ( ret != SASL_OK ) {
2387c478bd9Sstevel@tonic-gate 		/* sb_sasl_read: failed to decode packet, drop it, error */
2397c478bd9Sstevel@tonic-gate 		sb->sb_sasl_iptr = NULL;
2407c478bd9Sstevel@tonic-gate 		sb->sb_sasl_ilen = 0;
2417c478bd9Sstevel@tonic-gate 		LDAP_SET_ERRNO(ld, EIO);
2427c478bd9Sstevel@tonic-gate 		return( -1 );
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/* copy decrypted packet to the input buffer */
2467c478bd9Sstevel@tonic-gate 	SAFEMEMCPY( sb->sb_sasl_ibuf, dbuf, dlen );
2477c478bd9Sstevel@tonic-gate 	sb->sb_sasl_iptr = sb->sb_sasl_ibuf;
2487c478bd9Sstevel@tonic-gate 	sb->sb_sasl_ilen = dlen;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	ret = (dlen > (unsigned) len ? len : dlen);
2517c478bd9Sstevel@tonic-gate 	SAFEMEMCPY( buf, sb->sb_sasl_iptr, ret );
2527c478bd9Sstevel@tonic-gate 	if (ret == sb->sb_sasl_ilen) {
2537c478bd9Sstevel@tonic-gate 		sb->sb_sasl_ilen = 0;
2547c478bd9Sstevel@tonic-gate 		sb->sb_sasl_iptr = NULL;
2557c478bd9Sstevel@tonic-gate 	} else {
2567c478bd9Sstevel@tonic-gate 		sb->sb_sasl_ilen -= ret;
2577c478bd9Sstevel@tonic-gate 		sb->sb_sasl_iptr += ret;
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 	return( ret );
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate static int
2637c478bd9Sstevel@tonic-gate nsldapi_sasl_write( int s, const void *buf, int  len,
2647c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private *arg)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
267*e6a862fbSDouglas Leavitt 	int		ret = 0;
268*e6a862fbSDouglas Leavitt 	const char	*obuf, *optr, *cbuf = (const char *)buf;
269*e6a862fbSDouglas Leavitt 	unsigned	olen, clen, tlen = 0;
270*e6a862fbSDouglas Leavitt 	unsigned	*maxbuf;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if (sb == NULL) {
2737c478bd9Sstevel@tonic-gate 		return( -1 );
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 
276*e6a862fbSDouglas Leavitt 	ret = sasl_getprop(sb->sb_sasl_ctx, SASL_MAXOUTBUF,
277*e6a862fbSDouglas Leavitt 					     (const void **)&maxbuf);
278*e6a862fbSDouglas Leavitt 	if ( ret != SASL_OK ) {
279*e6a862fbSDouglas Leavitt 		/* just a sanity check, should never happen */
280*e6a862fbSDouglas Leavitt 		return( -1 );
281*e6a862fbSDouglas Leavitt 	}
282*e6a862fbSDouglas Leavitt 
283*e6a862fbSDouglas Leavitt 	while (len > 0) {
284*e6a862fbSDouglas Leavitt 		clen = (len > *maxbuf) ? *maxbuf : len;
2857c478bd9Sstevel@tonic-gate 		/* encode the next packet. */
286*e6a862fbSDouglas Leavitt 		ret = sasl_encode( sb->sb_sasl_ctx, cbuf, clen, &obuf, &olen);
2877c478bd9Sstevel@tonic-gate 		if ( ret != SASL_OK ) {
2887c478bd9Sstevel@tonic-gate 			/* XXX Log error? "sb_sasl_write: failed to encode packet..." */
2897c478bd9Sstevel@tonic-gate 			return( -1 );
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 		/* Write everything now, buffer is only good until next sasl_encode */
2927c478bd9Sstevel@tonic-gate 		optr = obuf;
2937c478bd9Sstevel@tonic-gate 		while (olen > 0) {
2947c478bd9Sstevel@tonic-gate 			if (sb->sb_sasl_fns.lbextiofn_write != NULL) {
2957c478bd9Sstevel@tonic-gate 				ret = sb->sb_sasl_fns.lbextiofn_write(
2967c478bd9Sstevel@tonic-gate 					s, optr, olen,
2977c478bd9Sstevel@tonic-gate 					sb->sb_sasl_fns.lbextiofn_socket_arg);
2987c478bd9Sstevel@tonic-gate 			} else {
2997c478bd9Sstevel@tonic-gate 				ret = write( sb->sb_sd, optr, olen);
3007c478bd9Sstevel@tonic-gate 			}
3017c478bd9Sstevel@tonic-gate 			if ( ret < 0 )
3027c478bd9Sstevel@tonic-gate 				return( ret );
3037c478bd9Sstevel@tonic-gate 			optr += ret;
3047c478bd9Sstevel@tonic-gate 			olen -= ret;
3057c478bd9Sstevel@tonic-gate 		}
306*e6a862fbSDouglas Leavitt 		len -= clen;
307*e6a862fbSDouglas Leavitt 		cbuf += clen;
308*e6a862fbSDouglas Leavitt 		tlen += clen;
309*e6a862fbSDouglas Leavitt 	}
310*e6a862fbSDouglas Leavitt 	return( tlen );
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate static int
3147c478bd9Sstevel@tonic-gate nsldapi_sasl_poll(
3157c478bd9Sstevel@tonic-gate 	LDAP_X_PollFD fds[], int nfds, int timeout,
3167c478bd9Sstevel@tonic-gate 	struct lextiof_session_private *arg )
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
3197c478bd9Sstevel@tonic-gate 	LDAP		*ld;
3207c478bd9Sstevel@tonic-gate 	int		i;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (sb == NULL) {
3237c478bd9Sstevel@tonic-gate 		return( -1 );
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 	ld = (LDAP *)sb->sb_sasl_prld;
3267c478bd9Sstevel@tonic-gate 	if (ld == NULL) {
3277c478bd9Sstevel@tonic-gate 		return( -1 );
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (fds && nfds > 0) {
3317c478bd9Sstevel@tonic-gate 		for(i = 0; i < nfds; i++) {
3327c478bd9Sstevel@tonic-gate 			if (fds[i].lpoll_socketarg ==
3337c478bd9Sstevel@tonic-gate 			     (struct lextiof_socket_private *)sb) {
3347c478bd9Sstevel@tonic-gate 				fds[i].lpoll_socketarg =
3357c478bd9Sstevel@tonic-gate 					(struct lextiof_socket_private *)
3367c478bd9Sstevel@tonic-gate 					sb->sb_sasl_fns.lbextiofn_socket_arg;
3377c478bd9Sstevel@tonic-gate 			}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 	return ( ld->ld_sasl_io_fns.lextiof_poll( fds, nfds, timeout,
3427c478bd9Sstevel@tonic-gate 		(void *)ld->ld_sasl_io_fns.lextiof_session_arg) );
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /* no encryption indirect routines */
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate static int
3487c478bd9Sstevel@tonic-gate nsldapi_sasl_ne_read( int s, void *buf, int  len,
3497c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private *arg)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if (sb == NULL) {
3547c478bd9Sstevel@tonic-gate 		return( -1 );
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	return( sb->sb_sasl_fns.lbextiofn_read( s, buf, len,
3587c478bd9Sstevel@tonic-gate 			sb->sb_sasl_fns.lbextiofn_socket_arg) );
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate static int
3627c478bd9Sstevel@tonic-gate nsldapi_sasl_ne_write( int s, const void *buf, int  len,
3637c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private *arg)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	if (sb == NULL) {
3687c478bd9Sstevel@tonic-gate 		return( -1 );
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	return( sb->sb_sasl_fns.lbextiofn_write( s, buf, len,
3727c478bd9Sstevel@tonic-gate 			sb->sb_sasl_fns.lbextiofn_socket_arg) );
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate static int
3767c478bd9Sstevel@tonic-gate nsldapi_sasl_close_socket(int s, struct lextiof_socket_private *arg )
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
3797c478bd9Sstevel@tonic-gate 	LDAP		*ld;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if (sb == NULL) {
3827c478bd9Sstevel@tonic-gate 		return( -1 );
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 	ld = (LDAP *)sb->sb_sasl_prld;
3857c478bd9Sstevel@tonic-gate 	if (ld == NULL) {
3867c478bd9Sstevel@tonic-gate 		return( -1 );
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 	/* undo function pointer interposing */
3897c478bd9Sstevel@tonic-gate 	ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &ld->ld_sasl_io_fns );
3907c478bd9Sstevel@tonic-gate 	ber_sockbuf_set_option( sb,
3917c478bd9Sstevel@tonic-gate 			LBER_SOCKBUF_OPT_EXT_IO_FNS,
3927c478bd9Sstevel@tonic-gate 			(void *)&sb->sb_sasl_fns);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	/* undo SASL */
3957c478bd9Sstevel@tonic-gate 	nsldapi_sasl_close( ld, sb );
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	return ( ld->ld_sasl_io_fns.lextiof_close( s,
3987c478bd9Sstevel@tonic-gate 		(struct lextiof_socket_private *)
3997c478bd9Sstevel@tonic-gate 		sb->sb_sasl_fns.lbextiofn_socket_arg ) );
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate  * install encryption routines if security has been negotiated
4047c478bd9Sstevel@tonic-gate  */
4057c478bd9Sstevel@tonic-gate static int
4067c478bd9Sstevel@tonic-gate nsldapi_sasl_install( LDAP *ld, Sockbuf *sb, void *ctx_arg, sasl_ssf_t *ssf)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate 	struct lber_x_ext_io_fns	fns;
4097c478bd9Sstevel@tonic-gate 	struct ldap_x_ext_io_fns	iofns;
4107c478bd9Sstevel@tonic-gate 	sasl_security_properties_t 	*secprops;
4117c478bd9Sstevel@tonic-gate 	int	rc, value;
4127c478bd9Sstevel@tonic-gate 	int	bufsiz;
4137c478bd9Sstevel@tonic-gate 	int	encrypt = 0;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	if (ssf && *ssf) {
4167c478bd9Sstevel@tonic-gate 		encrypt = 1;
4177c478bd9Sstevel@tonic-gate 	}
418*e6a862fbSDouglas Leavitt 	if ( sb == NULL ) {
419*e6a862fbSDouglas Leavitt 		return( LDAP_LOCAL_ERROR );
420*e6a862fbSDouglas Leavitt 	}
4217c478bd9Sstevel@tonic-gate 	rc = ber_sockbuf_get_option( sb,
4227c478bd9Sstevel@tonic-gate 			LBER_SOCKBUF_OPT_TO_FILE_ONLY,
4237c478bd9Sstevel@tonic-gate 			(void *) &value);
4247c478bd9Sstevel@tonic-gate 	if (rc != 0 || value != 0)
4257c478bd9Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (encrypt) {
4287c478bd9Sstevel@tonic-gate 		/* initialize input buffer - use MAX SIZE to avoid reallocs */
4297c478bd9Sstevel@tonic-gate 		sb->sb_sasl_ctx = (sasl_conn_t *)ctx_arg;
4307c478bd9Sstevel@tonic-gate 		rc = sasl_getprop( sb->sb_sasl_ctx, SASL_SEC_PROPS,
4317c478bd9Sstevel@tonic-gate 				   (const void **)&secprops );
4327c478bd9Sstevel@tonic-gate 		if (rc != SASL_OK)
4337c478bd9Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
4347c478bd9Sstevel@tonic-gate 		bufsiz = secprops->maxbufsize;
4357c478bd9Sstevel@tonic-gate 		if (bufsiz <= 0) {
4367c478bd9Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
4377c478bd9Sstevel@tonic-gate 		}
4387c478bd9Sstevel@tonic-gate 		if ((sb->sb_sasl_ibuf = NSLDAPI_MALLOC(bufsiz)) == NULL) {
4397c478bd9Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
4407c478bd9Sstevel@tonic-gate 		}
4417c478bd9Sstevel@tonic-gate 		sb->sb_sasl_iptr = NULL;
4427c478bd9Sstevel@tonic-gate 		sb->sb_sasl_bfsz = bufsiz;
4437c478bd9Sstevel@tonic-gate 		sb->sb_sasl_ilen = 0;
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	/* Reset Session then Socket Args */
4477c478bd9Sstevel@tonic-gate 	/* Get old values */
4487c478bd9Sstevel@tonic-gate 	(void) memset( &sb->sb_sasl_fns, 0, LBER_X_EXTIO_FNS_SIZE);
4497c478bd9Sstevel@tonic-gate 	sb->sb_sasl_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
4507c478bd9Sstevel@tonic-gate 	rc = ber_sockbuf_get_option( sb,
4517c478bd9Sstevel@tonic-gate 			LBER_SOCKBUF_OPT_EXT_IO_FNS,
4527c478bd9Sstevel@tonic-gate 			(void *)&sb->sb_sasl_fns);
453*e6a862fbSDouglas Leavitt 	if (rc != 0) {
454*e6a862fbSDouglas Leavitt 		destroy_sasliobuf(sb);
455*e6a862fbSDouglas Leavitt 		return( LDAP_LOCAL_ERROR );
456*e6a862fbSDouglas Leavitt 	}
4577c478bd9Sstevel@tonic-gate 	memset( &ld->ld_sasl_io_fns, 0, sizeof(iofns));
4587c478bd9Sstevel@tonic-gate 	ld->ld_sasl_io_fns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
4597c478bd9Sstevel@tonic-gate 	rc = ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
4607c478bd9Sstevel@tonic-gate 			      &ld->ld_sasl_io_fns );
461*e6a862fbSDouglas Leavitt 	if (rc != 0 ) {
462*e6a862fbSDouglas Leavitt 		destroy_sasliobuf(sb);
4637c478bd9Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
464*e6a862fbSDouglas Leavitt 	}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	/* Set new values */
4677c478bd9Sstevel@tonic-gate 	if (  ld->ld_sasl_io_fns.lextiof_read != NULL ||
4687c478bd9Sstevel@tonic-gate 	      ld->ld_sasl_io_fns.lextiof_write != NULL ||
4697c478bd9Sstevel@tonic-gate 	      ld->ld_sasl_io_fns.lextiof_poll != NULL ||
4707c478bd9Sstevel@tonic-gate 	      ld->ld_sasl_io_fns.lextiof_connect != NULL ||
4717c478bd9Sstevel@tonic-gate 	      ld->ld_sasl_io_fns.lextiof_close != NULL ) {
4727c478bd9Sstevel@tonic-gate 		memset( &iofns, 0, sizeof(iofns));
4737c478bd9Sstevel@tonic-gate 		iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
4747c478bd9Sstevel@tonic-gate 		if (encrypt) {
4757c478bd9Sstevel@tonic-gate 			iofns.lextiof_read = nsldapi_sasl_read;
4767c478bd9Sstevel@tonic-gate 			iofns.lextiof_write = nsldapi_sasl_write;
4777c478bd9Sstevel@tonic-gate 			iofns.lextiof_poll = nsldapi_sasl_poll;
4787c478bd9Sstevel@tonic-gate 		} else {
4797c478bd9Sstevel@tonic-gate 			iofns.lextiof_read = nsldapi_sasl_ne_read;
4807c478bd9Sstevel@tonic-gate 			iofns.lextiof_write = nsldapi_sasl_ne_write;
4817c478bd9Sstevel@tonic-gate 			iofns.lextiof_poll = nsldapi_sasl_poll;
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 		iofns.lextiof_connect = ld->ld_sasl_io_fns.lextiof_connect;
4847c478bd9Sstevel@tonic-gate 		iofns.lextiof_close = nsldapi_sasl_close_socket;
4857c478bd9Sstevel@tonic-gate 		iofns.lextiof_newhandle = ld->ld_sasl_io_fns.lextiof_newhandle;
4867c478bd9Sstevel@tonic-gate 		iofns.lextiof_disposehandle =
4877c478bd9Sstevel@tonic-gate 				ld->ld_sasl_io_fns.lextiof_disposehandle;
4887c478bd9Sstevel@tonic-gate 		iofns.lextiof_session_arg =
4897c478bd9Sstevel@tonic-gate 				(void *) sb;
4907c478bd9Sstevel@tonic-gate 				/* ld->ld_sasl_io_fns.lextiof_session_arg; */
4917c478bd9Sstevel@tonic-gate 		rc = ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
4927c478bd9Sstevel@tonic-gate 			      &iofns );
493*e6a862fbSDouglas Leavitt 		if (rc != 0 ) {
494*e6a862fbSDouglas Leavitt 			destroy_sasliobuf(sb);
4957c478bd9Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
496*e6a862fbSDouglas Leavitt 		}
4977c478bd9Sstevel@tonic-gate 		sb->sb_sasl_prld = (void *)ld;
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	if (encrypt) {
5017c478bd9Sstevel@tonic-gate 		(void) memset( &fns, 0, LBER_X_EXTIO_FNS_SIZE);
5027c478bd9Sstevel@tonic-gate 		fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
5037c478bd9Sstevel@tonic-gate 		fns.lbextiofn_read = nsldapi_sasl_read;
5047c478bd9Sstevel@tonic-gate 		fns.lbextiofn_write = nsldapi_sasl_write;
5057c478bd9Sstevel@tonic-gate 		fns.lbextiofn_socket_arg =
5067c478bd9Sstevel@tonic-gate 			(void *) sb;
5077c478bd9Sstevel@tonic-gate 			/* (void *)sb->sb_sasl_fns.lbextiofn_socket_arg; */
5087c478bd9Sstevel@tonic-gate 		rc = ber_sockbuf_set_option( sb,
5097c478bd9Sstevel@tonic-gate 				LBER_SOCKBUF_OPT_EXT_IO_FNS,
5107c478bd9Sstevel@tonic-gate 				(void *)&fns);
511*e6a862fbSDouglas Leavitt 		if (rc != 0) {
512*e6a862fbSDouglas Leavitt 			destroy_sasliobuf(sb);
5137c478bd9Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
5147c478bd9Sstevel@tonic-gate 		}
515*e6a862fbSDouglas Leavitt 	}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate static int
521*e6a862fbSDouglas Leavitt nsldapi_sasl_cvterrno( LDAP *ld, int err, char *msg )
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	int rc = LDAP_LOCAL_ERROR;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	switch (err) {
5267c478bd9Sstevel@tonic-gate 	case SASL_OK:
5277c478bd9Sstevel@tonic-gate 		rc = LDAP_SUCCESS;
5287c478bd9Sstevel@tonic-gate 		break;
5297c478bd9Sstevel@tonic-gate 	case SASL_NOMECH:
5307c478bd9Sstevel@tonic-gate 		rc = LDAP_AUTH_UNKNOWN;
5317c478bd9Sstevel@tonic-gate 		break;
5327c478bd9Sstevel@tonic-gate 	case SASL_BADSERV:
5337c478bd9Sstevel@tonic-gate 		rc = LDAP_CONNECT_ERROR;
5347c478bd9Sstevel@tonic-gate 		break;
5357c478bd9Sstevel@tonic-gate 	case SASL_DISABLED:
5367c478bd9Sstevel@tonic-gate 	case SASL_ENCRYPT:
5377c478bd9Sstevel@tonic-gate 	case SASL_EXPIRED:
5387c478bd9Sstevel@tonic-gate 	case SASL_NOUSERPASS:
5397c478bd9Sstevel@tonic-gate 	case SASL_NOVERIFY:
5407c478bd9Sstevel@tonic-gate 	case SASL_PWLOCK:
5417c478bd9Sstevel@tonic-gate 	case SASL_TOOWEAK:
5427c478bd9Sstevel@tonic-gate 	case SASL_UNAVAIL:
5437c478bd9Sstevel@tonic-gate 	case SASL_WEAKPASS:
5447c478bd9Sstevel@tonic-gate 		rc = LDAP_INAPPROPRIATE_AUTH;
5457c478bd9Sstevel@tonic-gate 		break;
5467c478bd9Sstevel@tonic-gate 	case SASL_BADAUTH:
5477c478bd9Sstevel@tonic-gate 	case SASL_NOAUTHZ:
5487c478bd9Sstevel@tonic-gate 		rc = LDAP_INVALID_CREDENTIALS;
5497c478bd9Sstevel@tonic-gate 		break;
5507c478bd9Sstevel@tonic-gate 	case SASL_NOMEM:
5517c478bd9Sstevel@tonic-gate 		rc = LDAP_NO_MEMORY;
5527c478bd9Sstevel@tonic-gate 		break;
5537c478bd9Sstevel@tonic-gate 	case SASL_NOUSER:
5547c478bd9Sstevel@tonic-gate 		rc = LDAP_NO_SUCH_OBJECT;
5557c478bd9Sstevel@tonic-gate 		break;
5567c478bd9Sstevel@tonic-gate 	case SASL_CONTINUE:
5577c478bd9Sstevel@tonic-gate 	case SASL_FAIL:
5587c478bd9Sstevel@tonic-gate 	case SASL_INTERACT:
5597c478bd9Sstevel@tonic-gate 	default:
5607c478bd9Sstevel@tonic-gate 		rc = LDAP_LOCAL_ERROR;
5617c478bd9Sstevel@tonic-gate 		break;
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 
564*e6a862fbSDouglas Leavitt 	LDAP_SET_LDERRNO( ld, rc, NULL, msg );
5657c478bd9Sstevel@tonic-gate 	return( rc );
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate int
5697c478bd9Sstevel@tonic-gate nsldapi_sasl_open(LDAP *ld)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 	Sockbuf *sb;
5727c478bd9Sstevel@tonic-gate 	char * host;
5737c478bd9Sstevel@tonic-gate 	int saslrc;
574*e6a862fbSDouglas Leavitt 	sasl_conn_t *ctx = NULL;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	if (ld == NULL) {
5777c478bd9Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	if (ld->ld_defconn == NULL) {
5817c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
5827c478bd9Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 	sb = ld->ld_defconn->lconn_sb;
5857c478bd9Sstevel@tonic-gate 	host = ld->ld_defhost;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	if ( sb == NULL || host == NULL ) {
5887c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
5897c478bd9Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 
592*e6a862fbSDouglas Leavitt 	if (sb->sb_sasl_ctx) {
593*e6a862fbSDouglas Leavitt 	    sasl_dispose(&sb->sb_sasl_ctx);
594*e6a862fbSDouglas Leavitt 	    sb->sb_sasl_ctx = NULL;
595*e6a862fbSDouglas Leavitt 	}
596*e6a862fbSDouglas Leavitt 
5977c478bd9Sstevel@tonic-gate 	/* SASL is not properly initialized */
5987c478bd9Sstevel@tonic-gate 	mutex_lock(&sasl_mutex);
5997c478bd9Sstevel@tonic-gate 	if (gctx == NULL) {
6007c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
6017c478bd9Sstevel@tonic-gate 		mutex_unlock(&sasl_mutex);
6027c478bd9Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	saslrc = _sasl_client_new(gctx, "ldap", host,
6067c478bd9Sstevel@tonic-gate 		NULL, NULL, /* iplocal ipremote strings currently unused */
6077c478bd9Sstevel@tonic-gate 		NULL, 0, &ctx );
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	if ( saslrc != SASL_OK ) {
6107c478bd9Sstevel@tonic-gate 		mutex_unlock(&sasl_mutex);
611*e6a862fbSDouglas Leavitt 		sasl_dispose(&ctx);
612*e6a862fbSDouglas Leavitt 		return( nsldapi_sasl_cvterrno( ld, saslrc, NULL ) );
6137c478bd9Sstevel@tonic-gate 	}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	sb->sb_sasl_ctx = (void *)ctx;
6167c478bd9Sstevel@tonic-gate 	mutex_unlock(&sasl_mutex);
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6210c71ee58SMilan Jurik static void
6220c71ee58SMilan Jurik destroy_sasliobuf(Sockbuf *sb)
6230c71ee58SMilan Jurik {
6240c71ee58SMilan Jurik 	if (sb != NULL && sb->sb_sasl_ibuf != NULL) {
6250c71ee58SMilan Jurik 		NSLDAPI_FREE(sb->sb_sasl_ibuf);
6260c71ee58SMilan Jurik 		sb->sb_sasl_ibuf = NULL;
627*e6a862fbSDouglas Leavitt 		sb->sb_sasl_iptr = NULL;
628*e6a862fbSDouglas Leavitt 		sb->sb_sasl_bfsz = 0;
629*e6a862fbSDouglas Leavitt 		sb->sb_sasl_ilen = 0;
6300c71ee58SMilan Jurik 	}
6310c71ee58SMilan Jurik }
6320c71ee58SMilan Jurik 
6337c478bd9Sstevel@tonic-gate static int
6347c478bd9Sstevel@tonic-gate nsldapi_sasl_close( LDAP *ld, Sockbuf *sb )
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 	sasl_conn_t	*ctx = (sasl_conn_t *)sb->sb_sasl_ctx;
6377c478bd9Sstevel@tonic-gate 
6380c71ee58SMilan Jurik 	destroy_sasliobuf(sb);
6390c71ee58SMilan Jurik 
6407c478bd9Sstevel@tonic-gate 	if( ctx != NULL ) {
6417c478bd9Sstevel@tonic-gate 		sasl_dispose( &ctx );
6427c478bd9Sstevel@tonic-gate 		sb->sb_sasl_ctx = NULL;
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate static int
6487c478bd9Sstevel@tonic-gate nsldapi_sasl_do_bind( LDAP *ld, const char *dn,
6497c478bd9Sstevel@tonic-gate 	const char *mechs, unsigned flags,
6507c478bd9Sstevel@tonic-gate 	LDAP_SASL_INTERACT_PROC *callback, void *defaults,
6517c478bd9Sstevel@tonic-gate 	LDAPControl **sctrl, LDAPControl **cctrl )
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate 	sasl_interact_t *prompts = NULL;
6547c478bd9Sstevel@tonic-gate 	sasl_conn_t	*ctx;
6557c478bd9Sstevel@tonic-gate 	sasl_ssf_t	*ssf = NULL;
6567c478bd9Sstevel@tonic-gate 	const char	*mech = NULL;
6577c478bd9Sstevel@tonic-gate 	int		saslrc, rc;
6587c478bd9Sstevel@tonic-gate 	struct berval	ccred;
6597c478bd9Sstevel@tonic-gate 	unsigned	credlen;
660*e6a862fbSDouglas Leavitt 	int		stepnum = 1;
661*e6a862fbSDouglas Leavitt 	char *sasl_username = NULL;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	if (NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3) {
6647c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
6657c478bd9Sstevel@tonic-gate 		return( LDAP_NOT_SUPPORTED );
6667c478bd9Sstevel@tonic-gate 	}
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	/* shouldn't happen */
6697c478bd9Sstevel@tonic-gate 	if (callback == NULL) {
6707c478bd9Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	if ( ld->ld_defconn == NULL ||
6747c478bd9Sstevel@tonic-gate 	     ld->ld_defconn->lconn_status != LDAP_CONNST_CONNECTED) {
6757c478bd9Sstevel@tonic-gate 		rc = nsldapi_open_ldap_defconn( ld );
6767c478bd9Sstevel@tonic-gate 		if( rc < 0 )  {
6777c478bd9Sstevel@tonic-gate 			return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
6787c478bd9Sstevel@tonic-gate 		}
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	/* should have a valid ld connection - now create sasl connection */
6827c478bd9Sstevel@tonic-gate 	if ((rc = nsldapi_sasl_open(ld)) != LDAP_SUCCESS) {
6837c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
6847c478bd9Sstevel@tonic-gate 		return( rc );
6857c478bd9Sstevel@tonic-gate 	}
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	/* expect context to be initialized when connection is open */
6887c478bd9Sstevel@tonic-gate 	ctx = (sasl_conn_t *)ld->ld_defconn->lconn_sb->sb_sasl_ctx;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	if( ctx == NULL ) {
6917c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
6927c478bd9Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	/* (re)set security properties */
6967c478bd9Sstevel@tonic-gate 	sasl_setprop( ctx, SASL_SEC_PROPS, &ld->ld_sasl_secprops );
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	ccred.bv_val = NULL;
6997c478bd9Sstevel@tonic-gate 	ccred.bv_len = 0;
7007c478bd9Sstevel@tonic-gate 
701*e6a862fbSDouglas Leavitt 	LDAPDebug(LDAP_DEBUG_TRACE, "Starting SASL/%s authentication\n",
702*e6a862fbSDouglas Leavitt 		  (mech ? mech : ""), 0, 0 );
703*e6a862fbSDouglas Leavitt 
7047c478bd9Sstevel@tonic-gate 	do {
7057c478bd9Sstevel@tonic-gate 		saslrc = sasl_client_start( ctx,
7067c478bd9Sstevel@tonic-gate 			mechs,
7077c478bd9Sstevel@tonic-gate 			&prompts,
7087c478bd9Sstevel@tonic-gate 			(const char **)&ccred.bv_val,
7097c478bd9Sstevel@tonic-gate 			&credlen,
7107c478bd9Sstevel@tonic-gate 			&mech );
7117c478bd9Sstevel@tonic-gate 
712*e6a862fbSDouglas Leavitt 		LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of client start for SASL/%s authentication\n",
713*e6a862fbSDouglas Leavitt 			  stepnum, (mech ? mech : ""), 0 );
714*e6a862fbSDouglas Leavitt 		stepnum++;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		if( saslrc == SASL_INTERACT &&
7177c478bd9Sstevel@tonic-gate 		    (callback)(ld, flags, defaults, prompts) != LDAP_SUCCESS ) {
7187c478bd9Sstevel@tonic-gate 			break;
7197c478bd9Sstevel@tonic-gate 		}
7207c478bd9Sstevel@tonic-gate 	} while ( saslrc == SASL_INTERACT );
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	ccred.bv_len = credlen;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
725*e6a862fbSDouglas Leavitt 		return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
7267c478bd9Sstevel@tonic-gate 	}
7277c478bd9Sstevel@tonic-gate 
728*e6a862fbSDouglas Leavitt 	stepnum = 1;
729*e6a862fbSDouglas Leavitt 
7307c478bd9Sstevel@tonic-gate 	do {
7317c478bd9Sstevel@tonic-gate 		struct berval *scred;
732*e6a862fbSDouglas Leavitt 		int clientstepnum = 1;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 		scred = NULL;
7357c478bd9Sstevel@tonic-gate 
736*e6a862fbSDouglas Leavitt 		LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of bind for SASL/%s authentication\n",
737*e6a862fbSDouglas Leavitt                           stepnum, (mech ? mech : ""), 0 );
738*e6a862fbSDouglas Leavitt                 stepnum++;
739*e6a862fbSDouglas Leavitt 
7407c478bd9Sstevel@tonic-gate 		/* notify server of a sasl bind step */
7417c478bd9Sstevel@tonic-gate 		rc = ldap_sasl_bind_s(ld, dn, mech, &ccred,
7427c478bd9Sstevel@tonic-gate 				      sctrl, cctrl, &scred);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		if ( ccred.bv_val != NULL ) {
7457c478bd9Sstevel@tonic-gate 			ccred.bv_val = NULL;
7467c478bd9Sstevel@tonic-gate 		}
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 		if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
7497c478bd9Sstevel@tonic-gate 			ber_bvfree( scred );
7507c478bd9Sstevel@tonic-gate 			return( rc );
7517c478bd9Sstevel@tonic-gate 		}
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 		if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
7547c478bd9Sstevel@tonic-gate 			/* we're done, no need to step */
755*e6a862fbSDouglas Leavitt 			if( scred ) {
756*e6a862fbSDouglas Leavitt 			    if (scred->bv_len  == 0 ) { /* MS AD sends back empty screds */
757*e6a862fbSDouglas Leavitt 				LDAPDebug(LDAP_DEBUG_ANY,
758*e6a862fbSDouglas Leavitt 					  "SASL BIND complete - ignoring empty credential response\n",
759*e6a862fbSDouglas Leavitt 					  0, 0, 0);
760*e6a862fbSDouglas Leavitt 				ber_bvfree( scred );
761*e6a862fbSDouglas Leavitt 			    } else {
7627c478bd9Sstevel@tonic-gate 				/* but server provided us with data! */
763*e6a862fbSDouglas Leavitt 				LDAPDebug(LDAP_DEBUG_TRACE,
764*e6a862fbSDouglas Leavitt 					  "SASL BIND complete but invalid because server responded with credentials - length [%u]\n",
765*e6a862fbSDouglas Leavitt 					  scred->bv_len, 0, 0);
7667c478bd9Sstevel@tonic-gate 				ber_bvfree( scred );
7677c478bd9Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR,
768*e6a862fbSDouglas Leavitt 				    NULL, nsldapi_strdup( dgettext(TEXT_DOMAIN,
769*e6a862fbSDouglas Leavitt 				    "Error during SASL handshake - "
770*e6a862fbSDouglas Leavitt 				    "invalid server credential response") ));
7717c478bd9Sstevel@tonic-gate 				return( LDAP_LOCAL_ERROR );
7727c478bd9Sstevel@tonic-gate 			    }
773*e6a862fbSDouglas Leavitt 			}
7747c478bd9Sstevel@tonic-gate 			break;
7757c478bd9Sstevel@tonic-gate 		}
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 		/* perform the next step of the sasl bind */
7787c478bd9Sstevel@tonic-gate 		do {
779*e6a862fbSDouglas Leavitt 			LDAPDebug(LDAP_DEBUG_TRACE, "Doing client step %d of bind step %d for SASL/%s authentication\n",
780*e6a862fbSDouglas Leavitt 				  clientstepnum, stepnum, (mech ? mech : "") );
781*e6a862fbSDouglas Leavitt 			clientstepnum++;
7827c478bd9Sstevel@tonic-gate 			saslrc = sasl_client_step( ctx,
7837c478bd9Sstevel@tonic-gate 				(scred == NULL) ? NULL : scred->bv_val,
7847c478bd9Sstevel@tonic-gate 				(scred == NULL) ? 0 : scred->bv_len,
7857c478bd9Sstevel@tonic-gate 				&prompts,
7867c478bd9Sstevel@tonic-gate 				(const char **)&ccred.bv_val,
7877c478bd9Sstevel@tonic-gate 				&credlen );
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 			if( saslrc == SASL_INTERACT &&
7907c478bd9Sstevel@tonic-gate 			    (callback)(ld, flags, defaults, prompts)
7917c478bd9Sstevel@tonic-gate 							!= LDAP_SUCCESS ) {
7927c478bd9Sstevel@tonic-gate 				break;
7937c478bd9Sstevel@tonic-gate 			}
7947c478bd9Sstevel@tonic-gate 		} while ( saslrc == SASL_INTERACT );
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 		ccred.bv_len = credlen;
7977c478bd9Sstevel@tonic-gate 		ber_bvfree( scred );
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 		if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
800*e6a862fbSDouglas Leavitt 			return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
8017c478bd9Sstevel@tonic-gate 		}
8027c478bd9Sstevel@tonic-gate 	} while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	if ( rc != LDAP_SUCCESS ) {
8057c478bd9Sstevel@tonic-gate 		return( rc );
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	if ( saslrc != SASL_OK ) {
809*e6a862fbSDouglas Leavitt 		return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
810*e6a862fbSDouglas Leavitt 	}
811*e6a862fbSDouglas Leavitt 
812*e6a862fbSDouglas Leavitt 	saslrc = sasl_getprop( ctx, SASL_USERNAME, (const void **) &sasl_username );
813*e6a862fbSDouglas Leavitt 	if ( (saslrc == SASL_OK) && sasl_username ) {
814*e6a862fbSDouglas Leavitt 		LDAPDebug(LDAP_DEBUG_TRACE, "SASL identity: %s\n", sasl_username, 0, 0);
8157c478bd9Sstevel@tonic-gate 	}
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	saslrc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf );
8187c478bd9Sstevel@tonic-gate 	if( saslrc == SASL_OK ) {
819*e6a862fbSDouglas Leavitt 		if( ssf && *ssf ) {
820*e6a862fbSDouglas Leavitt 			LDAPDebug(LDAP_DEBUG_TRACE,
821*e6a862fbSDouglas Leavitt 				"SASL install encryption, for SSF: %lu\n",
822*e6a862fbSDouglas Leavitt 				(unsigned long) *ssf, 0, 0 );
823*e6a862fbSDouglas Leavitt 		}
8247c478bd9Sstevel@tonic-gate 		rc = nsldapi_sasl_install(ld, ld->ld_conns->lconn_sb, ctx, ssf);
8257c478bd9Sstevel@tonic-gate 	}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	return( rc );
8287c478bd9Sstevel@tonic-gate }
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
8317c478bd9Sstevel@tonic-gate /*
8327c478bd9Sstevel@tonic-gate  * Get available SASL Mechanisms supported by the server
8337c478bd9Sstevel@tonic-gate  */
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate static int
8367c478bd9Sstevel@tonic-gate nsldapi_get_sasl_mechs ( LDAP *ld, char **pmech )
8377c478bd9Sstevel@tonic-gate {
8387c478bd9Sstevel@tonic-gate 	char *attr[] = { "supportedSASLMechanisms", NULL };
8397c478bd9Sstevel@tonic-gate 	char **values, **v, *mech, *m;
8407c478bd9Sstevel@tonic-gate 	LDAPMessage *res, *e;
8417c478bd9Sstevel@tonic-gate 	struct timeval	timeout;
8427c478bd9Sstevel@tonic-gate 	int slen, rc;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
8457c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
8467c478bd9Sstevel@tonic-gate 	}
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	timeout.tv_sec = SEARCH_TIMEOUT_SECS;
8497c478bd9Sstevel@tonic-gate 	timeout.tv_usec = 0;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	rc = ldap_search_st( ld, "", LDAP_SCOPE_BASE,
8527c478bd9Sstevel@tonic-gate 		"objectclass=*", attr, 0, &timeout, &res );
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	if ( rc != LDAP_SUCCESS ) {
8557c478bd9Sstevel@tonic-gate 		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
8567c478bd9Sstevel@tonic-gate 	}
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	e = ldap_first_entry( ld, res );
8597c478bd9Sstevel@tonic-gate 	if ( e == NULL ) {
8607c478bd9Sstevel@tonic-gate 		ldap_msgfree( res );
8617c478bd9Sstevel@tonic-gate 		if ( ld->ld_errno == LDAP_SUCCESS ) {
8627c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_OBJECT, NULL, NULL );
8637c478bd9Sstevel@tonic-gate 		}
8647c478bd9Sstevel@tonic-gate 		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
8687c478bd9Sstevel@tonic-gate 	if ( values == NULL ) {
8697c478bd9Sstevel@tonic-gate 		ldap_msgfree( res );
8707c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL );
8717c478bd9Sstevel@tonic-gate 		return( LDAP_NO_SUCH_ATTRIBUTE );
8727c478bd9Sstevel@tonic-gate 	}
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	slen = 0;
8757c478bd9Sstevel@tonic-gate 	for(v = values; *v != NULL; v++ ) {
8767c478bd9Sstevel@tonic-gate 		slen += strlen(*v) + 1;
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 	if ( (mech = NSLDAPI_CALLOC(1, slen)) == NULL) {
8797c478bd9Sstevel@tonic-gate 		ldap_value_free( values );
8807c478bd9Sstevel@tonic-gate 		ldap_msgfree( res );
8817c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
8827c478bd9Sstevel@tonic-gate 		return( LDAP_NO_MEMORY );
8837c478bd9Sstevel@tonic-gate 	}
8847c478bd9Sstevel@tonic-gate 	m = mech;
8857c478bd9Sstevel@tonic-gate 	for(v = values; *v; v++) {
8867c478bd9Sstevel@tonic-gate 		if (v != values) {
8877c478bd9Sstevel@tonic-gate 			*m++ = ' ';
8887c478bd9Sstevel@tonic-gate 		}
8897c478bd9Sstevel@tonic-gate 		slen = strlen(*v);
8907c478bd9Sstevel@tonic-gate 		strncpy(m, *v, slen);
8917c478bd9Sstevel@tonic-gate 		m += slen;
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 	*m = '\0';
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	ldap_value_free( values );
8967c478bd9Sstevel@tonic-gate 	ldap_msgfree( res );
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	*pmech = mech;
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate #endif
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate int nsldapi_sasl_secprops(
9057c478bd9Sstevel@tonic-gate 	const char *in,
9067c478bd9Sstevel@tonic-gate 	sasl_security_properties_t *secprops )
9077c478bd9Sstevel@tonic-gate {
9087c478bd9Sstevel@tonic-gate 	int i;
9097c478bd9Sstevel@tonic-gate 	char **props = NULL;
9107c478bd9Sstevel@tonic-gate 	char *inp;
9117c478bd9Sstevel@tonic-gate 	unsigned sflags = 0;
9127c478bd9Sstevel@tonic-gate 	sasl_ssf_t max_ssf = 0;
9137c478bd9Sstevel@tonic-gate 	sasl_ssf_t min_ssf = 0;
9147c478bd9Sstevel@tonic-gate 	unsigned maxbufsize = 0;
9157c478bd9Sstevel@tonic-gate 	int got_sflags = 0;
9167c478bd9Sstevel@tonic-gate 	int got_max_ssf = 0;
9177c478bd9Sstevel@tonic-gate 	int got_min_ssf = 0;
9187c478bd9Sstevel@tonic-gate 	int got_maxbufsize = 0;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	if (in == NULL) {
9217c478bd9Sstevel@tonic-gate 		return LDAP_PARAM_ERROR;
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate 	inp = nsldapi_strdup(in);
9247c478bd9Sstevel@tonic-gate 	if (inp == NULL) {
9257c478bd9Sstevel@tonic-gate 		return LDAP_PARAM_ERROR;
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 	props = ldap_str2charray( inp, "," );
9287c478bd9Sstevel@tonic-gate 	NSLDAPI_FREE( inp );
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	if( props == NULL || secprops == NULL ) {
9317c478bd9Sstevel@tonic-gate 		return LDAP_PARAM_ERROR;
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	for( i=0; props[i]; i++ ) {
9357c478bd9Sstevel@tonic-gate 		if( strcasecmp(props[i], "none") == 0 ) {
9367c478bd9Sstevel@tonic-gate 			got_sflags++;
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "noactive") == 0 ) {
9397c478bd9Sstevel@tonic-gate 			got_sflags++;
9407c478bd9Sstevel@tonic-gate 			sflags |= SASL_SEC_NOACTIVE;
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "noanonymous") == 0 ) {
9437c478bd9Sstevel@tonic-gate 			got_sflags++;
9447c478bd9Sstevel@tonic-gate 			sflags |= SASL_SEC_NOANONYMOUS;
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "nodict") == 0 ) {
9477c478bd9Sstevel@tonic-gate 			got_sflags++;
9487c478bd9Sstevel@tonic-gate 			sflags |= SASL_SEC_NODICTIONARY;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "noplain") == 0 ) {
9517c478bd9Sstevel@tonic-gate 			got_sflags++;
9527c478bd9Sstevel@tonic-gate 			sflags |= SASL_SEC_NOPLAINTEXT;
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "forwardsec") == 0 ) {
9557c478bd9Sstevel@tonic-gate 			got_sflags++;
9567c478bd9Sstevel@tonic-gate 			sflags |= SASL_SEC_FORWARD_SECRECY;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "passcred") == 0 ) {
9597c478bd9Sstevel@tonic-gate 			got_sflags++;
9607c478bd9Sstevel@tonic-gate 			sflags |= SASL_SEC_PASS_CREDENTIALS;
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 		} else if( strncasecmp(props[i],
9637c478bd9Sstevel@tonic-gate 			"minssf=", sizeof("minssf")) == 0 ) {
9647c478bd9Sstevel@tonic-gate 			if( isdigit( props[i][sizeof("minssf")] ) ) {
9657c478bd9Sstevel@tonic-gate 				got_min_ssf++;
9667c478bd9Sstevel@tonic-gate 				min_ssf = atoi( &props[i][sizeof("minssf")] );
9677c478bd9Sstevel@tonic-gate 			} else {
9687c478bd9Sstevel@tonic-gate 				return LDAP_NOT_SUPPORTED;
9697c478bd9Sstevel@tonic-gate 			}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 		} else if( strncasecmp(props[i],
9727c478bd9Sstevel@tonic-gate 			"maxssf=", sizeof("maxssf")) == 0 ) {
9737c478bd9Sstevel@tonic-gate 			if( isdigit( props[i][sizeof("maxssf")] ) ) {
9747c478bd9Sstevel@tonic-gate 				got_max_ssf++;
9757c478bd9Sstevel@tonic-gate 				max_ssf = atoi( &props[i][sizeof("maxssf")] );
9767c478bd9Sstevel@tonic-gate 			} else {
9777c478bd9Sstevel@tonic-gate 				return LDAP_NOT_SUPPORTED;
9787c478bd9Sstevel@tonic-gate 			}
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 		} else if( strncasecmp(props[i],
9817c478bd9Sstevel@tonic-gate 			"maxbufsize=", sizeof("maxbufsize")) == 0 ) {
9827c478bd9Sstevel@tonic-gate 			if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
9837c478bd9Sstevel@tonic-gate 				got_maxbufsize++;
9847c478bd9Sstevel@tonic-gate 				maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
9857c478bd9Sstevel@tonic-gate 				if( maxbufsize &&
9867c478bd9Sstevel@tonic-gate 				    (( maxbufsize < SASL_MIN_BUFF_SIZE )
9877c478bd9Sstevel@tonic-gate 				    || (maxbufsize > SASL_MAX_BUFF_SIZE ))) {
9887c478bd9Sstevel@tonic-gate 					return( LDAP_PARAM_ERROR );
9897c478bd9Sstevel@tonic-gate 				}
9907c478bd9Sstevel@tonic-gate 			} else {
9917c478bd9Sstevel@tonic-gate 				return( LDAP_NOT_SUPPORTED );
9927c478bd9Sstevel@tonic-gate 			}
9937c478bd9Sstevel@tonic-gate 		} else {
9947c478bd9Sstevel@tonic-gate 			return( LDAP_NOT_SUPPORTED );
9957c478bd9Sstevel@tonic-gate 		}
9967c478bd9Sstevel@tonic-gate 	}
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	if(got_sflags) {
9997c478bd9Sstevel@tonic-gate 		secprops->security_flags = sflags;
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 	if(got_min_ssf) {
10027c478bd9Sstevel@tonic-gate 		secprops->min_ssf = min_ssf;
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 	if(got_max_ssf) {
10057c478bd9Sstevel@tonic-gate 		secprops->max_ssf = max_ssf;
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 	if(got_maxbufsize) {
10087c478bd9Sstevel@tonic-gate 		secprops->maxbufsize = maxbufsize;
10097c478bd9Sstevel@tonic-gate 	}
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	ldap_charray_free( props );
10127c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate /*
10167c478bd9Sstevel@tonic-gate  * SASL Authentication Interface: ldap_sasl_interactive_bind_s
10177c478bd9Sstevel@tonic-gate  *
10187c478bd9Sstevel@tonic-gate  * This routine takes a DN, SASL mech list, and a SASL callback
10197c478bd9Sstevel@tonic-gate  * and performs the necessary sequencing to complete a SASL bind
10207c478bd9Sstevel@tonic-gate  * to the LDAP connection ld.  The user provided callback can
10217c478bd9Sstevel@tonic-gate  * use an optionally provided set of default values to complete
10227c478bd9Sstevel@tonic-gate  * any necessary interactions.
10237c478bd9Sstevel@tonic-gate  *
10247c478bd9Sstevel@tonic-gate  * Currently inpose the following restrictions:
10257c478bd9Sstevel@tonic-gate  *   A mech list must be provided, only LDAP_SASL_INTERACTIVE
10267c478bd9Sstevel@tonic-gate  *   mode is supported
10277c478bd9Sstevel@tonic-gate  */
10287c478bd9Sstevel@tonic-gate int
10297c478bd9Sstevel@tonic-gate LDAP_CALL
10307c478bd9Sstevel@tonic-gate ldap_sasl_interactive_bind_s( LDAP *ld, const char *dn,
10317c478bd9Sstevel@tonic-gate 	const char *saslMechanism,
10327c478bd9Sstevel@tonic-gate 	LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
10337c478bd9Sstevel@tonic-gate 	LDAP_SASL_INTERACT_PROC *callback, void *defaults )
10347c478bd9Sstevel@tonic-gate {
10357c478bd9Sstevel@tonic-gate #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
10367c478bd9Sstevel@tonic-gate 	char *smechs;
10377c478bd9Sstevel@tonic-gate #endif
10387c478bd9Sstevel@tonic-gate 	int rc;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	LDAPDebug(LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind_s\n", 0, 0, 0);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
10437c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
10447c478bd9Sstevel@tonic-gate 	}
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	if (flags != LDAP_SASL_INTERACTIVE || callback == NULL) {
10477c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK(ld, LDAP_SASL_LOCK );
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	if( saslMechanism == NULL || *saslMechanism == '\0' ) {
10537c478bd9Sstevel@tonic-gate #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
10547c478bd9Sstevel@tonic-gate 		rc = nsldapi_get_sasl_mechs( ld, &smechs );
10557c478bd9Sstevel@tonic-gate 		if( rc != LDAP_SUCCESS ) {
10567c478bd9Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
10577c478bd9Sstevel@tonic-gate 			return( rc );
10587c478bd9Sstevel@tonic-gate 		}
10597c478bd9Sstevel@tonic-gate 		saslMechanism = smechs;
10607c478bd9Sstevel@tonic-gate #else
10617c478bd9Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
10627c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
10637c478bd9Sstevel@tonic-gate #endif
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	/* initialize SASL library */
10677c478bd9Sstevel@tonic-gate 	if ( nsldapi_sasl_init() < 0 ) {
10687c478bd9Sstevel@tonic-gate 	    return( LDAP_PARAM_ERROR );
10697c478bd9Sstevel@tonic-gate 	}
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	rc = nsldapi_sasl_do_bind( ld, dn, saslMechanism,
10727c478bd9Sstevel@tonic-gate 			flags, callback, defaults, sctrl, cctrl);
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
10757c478bd9Sstevel@tonic-gate 	return( rc );
10767c478bd9Sstevel@tonic-gate }
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate #endif
1079