xref: /onnv-gate/usr/src/lib/libldap5/sources/ldap/common/sasl.c (revision 12023:a90e8ee77a4b)
10Sstevel@tonic-gate /*
27068Schinlong  * CDDL HEADER START
37068Schinlong  *
47068Schinlong  * The contents of this file are subject to the terms of the
57068Schinlong  * Common Development and Distribution License (the "License").
67068Schinlong  * You may not use this file except in compliance with the License.
77068Schinlong  *
87068Schinlong  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97068Schinlong  * or http://www.opensolaris.org/os/licensing.
107068Schinlong  * See the License for the specific language governing permissions
117068Schinlong  * and limitations under the License.
127068Schinlong  *
137068Schinlong  * When distributing Covered Code, include this CDDL HEADER in each
147068Schinlong  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157068Schinlong  * If applicable, add the following below this CDDL HEADER, with the
167068Schinlong  * fields enclosed by brackets "[]" replaced with your own identifying
177068Schinlong  * information: Portions Copyright [yyyy] [name of copyright owner]
187068Schinlong  *
197068Schinlong  * CDDL HEADER END
207068Schinlong  */
217068Schinlong /*
22*12023SDoug.Leavitt@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #ifdef LDAP_SASLIO_HOOKS
270Sstevel@tonic-gate #include <assert.h>
280Sstevel@tonic-gate #include "ldap-int.h"
290Sstevel@tonic-gate #include "../ber/lber-int.h"
300Sstevel@tonic-gate #include <sasl/sasl.h>
310Sstevel@tonic-gate #include <thread.h>
320Sstevel@tonic-gate #include <synch.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #define SEARCH_TIMEOUT_SECS	120
350Sstevel@tonic-gate #define NSLDAPI_SM_BUF	128
360Sstevel@tonic-gate 
370Sstevel@tonic-gate extern void *sasl_create_context(void);
380Sstevel@tonic-gate extern void sasl_free_context(void *ctx);
390Sstevel@tonic-gate extern int _sasl_client_init(void *ctx, const sasl_callback_t *callbacks);
400Sstevel@tonic-gate extern int _sasl_client_new(void *ctx, const char *service,
410Sstevel@tonic-gate 	const char *serverFQDN, const char *iplocalport,
420Sstevel@tonic-gate 	const char *ipremoteport,
430Sstevel@tonic-gate 	const sasl_callback_t *prompt_supp,
440Sstevel@tonic-gate 	unsigned flags, sasl_conn_t **pconn);
450Sstevel@tonic-gate extern int _sasl_server_init(void *ctx,
460Sstevel@tonic-gate 	const sasl_callback_t *callbacks, const char *appname);
470Sstevel@tonic-gate extern int _sasl_server_new(void *ctx, const char *service,
480Sstevel@tonic-gate 	const char *serverFQDN, const char *user_realm,
490Sstevel@tonic-gate 	const char *iplocalport, const char *ipremoteport,
500Sstevel@tonic-gate 	const sasl_callback_t *callbacks,
510Sstevel@tonic-gate 	unsigned flags, sasl_conn_t **pconn);
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static int nsldapi_sasl_close( LDAP *ld, Sockbuf *sb );
54*12023SDoug.Leavitt@Sun.COM static void destroy_sasliobuf(Sockbuf *sb);
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /*
570Sstevel@tonic-gate  * SASL Dependent routines
580Sstevel@tonic-gate  *
590Sstevel@tonic-gate  * SASL security and integrity options are supported through the
600Sstevel@tonic-gate  * use of the extended I/O functionality.  Because the extended
610Sstevel@tonic-gate  * I/O functions may already be in use prior to enabling encryption,
620Sstevel@tonic-gate  * when SASL encryption is enabled, these routine interpose themselves
630Sstevel@tonic-gate  * over the existng extended I/O routines and add an additional level
640Sstevel@tonic-gate  * of indirection.
650Sstevel@tonic-gate  *  IE: Before SASL:  client->libldap->lber->extio
660Sstevel@tonic-gate  *      After  SASL:  client->libldap->lber->saslio->extio
670Sstevel@tonic-gate  * Any extio functions are still used for the raw i/O [IE prldap]
680Sstevel@tonic-gate  * but SASL will decrypt before passing to lber.
690Sstevel@tonic-gate  * SASL cannot decrypt a stream so full packets must be read
700Sstevel@tonic-gate  * before proceeding.
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate 
nsldapi_sasl_fail()730Sstevel@tonic-gate static int nsldapi_sasl_fail()
740Sstevel@tonic-gate {
750Sstevel@tonic-gate 	return( SASL_FAIL );
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * Global SASL Init data
800Sstevel@tonic-gate  */
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static sasl_callback_t client_callbacks[] = {
830Sstevel@tonic-gate 	{ SASL_CB_GETOPT, nsldapi_sasl_fail, NULL },
840Sstevel@tonic-gate 	{ SASL_CB_GETREALM, NULL, NULL },
850Sstevel@tonic-gate 	{ SASL_CB_USER, NULL, NULL },
860Sstevel@tonic-gate 	{ SASL_CB_AUTHNAME, NULL, NULL },
870Sstevel@tonic-gate 	{ SASL_CB_PASS, NULL, NULL },
880Sstevel@tonic-gate 	{ SASL_CB_ECHOPROMPT, NULL, NULL },
890Sstevel@tonic-gate 	{ SASL_CB_NOECHOPROMPT, NULL, NULL },
900Sstevel@tonic-gate 	{ SASL_CB_LIST_END, NULL, NULL }
910Sstevel@tonic-gate };
920Sstevel@tonic-gate static mutex_t sasl_mutex = DEFAULTMUTEX;
930Sstevel@tonic-gate static int nsldapi_sasl_inited = 0;
940Sstevel@tonic-gate static void *gctx;  /* intentially not freed - avoid libsasl re-inits */
950Sstevel@tonic-gate 
nsldapi_sasl_init(void)960Sstevel@tonic-gate int nsldapi_sasl_init( void )
970Sstevel@tonic-gate {
980Sstevel@tonic-gate 	int	saslrc;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	mutex_lock(&sasl_mutex);
1010Sstevel@tonic-gate 	if ( nsldapi_sasl_inited ) {
1020Sstevel@tonic-gate 		mutex_unlock(&sasl_mutex);
1030Sstevel@tonic-gate 		return( 0 );
1040Sstevel@tonic-gate 	}
1050Sstevel@tonic-gate 	if ((gctx = (void *)sasl_create_context()) != NULL) {
1060Sstevel@tonic-gate 		saslrc = _sasl_client_init(gctx, client_callbacks);
1070Sstevel@tonic-gate 		if (saslrc == SASL_OK ) {
1080Sstevel@tonic-gate 			nsldapi_sasl_inited = 1;
1090Sstevel@tonic-gate 			mutex_unlock(&sasl_mutex);
1100Sstevel@tonic-gate 			return( 0 );
1110Sstevel@tonic-gate 		}
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate 	mutex_unlock(&sasl_mutex);
1140Sstevel@tonic-gate 	return( -1 );
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate /*
1180Sstevel@tonic-gate  * SASL encryption routines
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * Get the 4 octet header [size] for a sasl encrypted buffer.
1230Sstevel@tonic-gate  * See RFC222 [section 3].
1240Sstevel@tonic-gate  */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate static int
nsldapi_sasl_pktlen(char * buf,int maxbufsize)1270Sstevel@tonic-gate nsldapi_sasl_pktlen( char *buf, int maxbufsize )
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate 	int	size;
1300Sstevel@tonic-gate 
1317068Schinlong #if defined( _WINDOWS ) || defined( _WIN32 )
1320Sstevel@tonic-gate 	size = ntohl(*(long *)buf);
1337068Schinlong #else
1347068Schinlong 	size = ntohl(*(uint32_t *)buf);
1357068Schinlong #endif
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	if ( size < 0 || size > maxbufsize ) {
1380Sstevel@tonic-gate 		return (-1 );
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	return( size + 4 ); /* include the first 4 bytes */
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate static int
nsldapi_sasl_read(int s,void * buf,int len,struct lextiof_socket_private * arg)1450Sstevel@tonic-gate nsldapi_sasl_read( int s, void *buf, int  len,
1460Sstevel@tonic-gate 	struct lextiof_socket_private *arg)
1470Sstevel@tonic-gate {
1480Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
1490Sstevel@tonic-gate 	LDAP		*ld;
1500Sstevel@tonic-gate 	const char	*dbuf;
1510Sstevel@tonic-gate 	char		*cp;
1520Sstevel@tonic-gate 	int		ret;
1530Sstevel@tonic-gate 	unsigned	dlen, blen;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	if (sb == NULL) {
1560Sstevel@tonic-gate 		return( -1 );
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	ld = (LDAP *)sb->sb_sasl_prld;
1600Sstevel@tonic-gate 	if (ld == NULL) {
1610Sstevel@tonic-gate 		return( -1 );
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	/* Is there anything left in the existing buffer? */
1650Sstevel@tonic-gate 	if ((ret = sb->sb_sasl_ilen) > 0) {
1660Sstevel@tonic-gate 		ret = (ret > len ? len : ret);
1670Sstevel@tonic-gate 		SAFEMEMCPY( buf, sb->sb_sasl_iptr, ret );
1680Sstevel@tonic-gate 		if (ret == sb->sb_sasl_ilen) {
1690Sstevel@tonic-gate 			sb->sb_sasl_ilen = 0;
1700Sstevel@tonic-gate 			sb->sb_sasl_iptr = NULL;
1710Sstevel@tonic-gate 		} else {
1720Sstevel@tonic-gate 			sb->sb_sasl_ilen -= ret;
1730Sstevel@tonic-gate 			sb->sb_sasl_iptr += ret;
1740Sstevel@tonic-gate 		}
1750Sstevel@tonic-gate 		return( ret );
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/* buffer is empty - fill it */
1790Sstevel@tonic-gate 	cp = sb->sb_sasl_ibuf;
1800Sstevel@tonic-gate 	dlen = 0;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/* Read the length of the packet */
1830Sstevel@tonic-gate 	while ( dlen < 4 ) {
1840Sstevel@tonic-gate 		if (sb->sb_sasl_fns.lbextiofn_read != NULL) {
1850Sstevel@tonic-gate 			ret = sb->sb_sasl_fns.lbextiofn_read(
1860Sstevel@tonic-gate 				s, cp, 4 - dlen,
1870Sstevel@tonic-gate 				sb->sb_sasl_fns.lbextiofn_socket_arg);
1880Sstevel@tonic-gate 		} else {
1890Sstevel@tonic-gate 			ret = read( sb->sb_sd, cp, 4 - dlen );
1900Sstevel@tonic-gate 		}
1910Sstevel@tonic-gate #ifdef EINTR
1920Sstevel@tonic-gate 		if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) )
1930Sstevel@tonic-gate 			continue;
1940Sstevel@tonic-gate #endif
1950Sstevel@tonic-gate 		if ( ret <= 0 )
1960Sstevel@tonic-gate 			return( ret );
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 		cp += ret;
1990Sstevel@tonic-gate 		dlen += ret;
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	blen = 4;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	ret = nsldapi_sasl_pktlen( sb->sb_sasl_ibuf, sb->sb_sasl_bfsz );
2050Sstevel@tonic-gate 	if (ret < 0) {
2060Sstevel@tonic-gate 		LDAP_SET_ERRNO(ld, EIO);
2070Sstevel@tonic-gate 		return( -1 );
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 	dlen = ret - dlen;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	/* read the rest of the encrypted packet */
2120Sstevel@tonic-gate 	while ( dlen > 0 ) {
2130Sstevel@tonic-gate 		if (sb->sb_sasl_fns.lbextiofn_read != NULL) {
2140Sstevel@tonic-gate 			ret = sb->sb_sasl_fns.lbextiofn_read(
2150Sstevel@tonic-gate 				s, cp, dlen,
2160Sstevel@tonic-gate 				sb->sb_sasl_fns.lbextiofn_socket_arg);
2170Sstevel@tonic-gate 		} else {
2180Sstevel@tonic-gate 			ret = read( sb->sb_sd, cp, dlen );
2190Sstevel@tonic-gate 		}
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate #ifdef EINTR
2220Sstevel@tonic-gate 		if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) )
2230Sstevel@tonic-gate 			continue;
2240Sstevel@tonic-gate #endif
2250Sstevel@tonic-gate 		if ( ret <= 0 )
2260Sstevel@tonic-gate 			return( ret );
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 		cp += ret;
2290Sstevel@tonic-gate 		blen += ret;
2300Sstevel@tonic-gate 		dlen -= ret;
2310Sstevel@tonic-gate    	}
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	/* Decode the packet */
2340Sstevel@tonic-gate 	ret = sasl_decode( sb->sb_sasl_ctx,
2350Sstevel@tonic-gate 			   sb->sb_sasl_ibuf, blen,
2360Sstevel@tonic-gate 			   &dbuf, &dlen);
2370Sstevel@tonic-gate 	if ( ret != SASL_OK ) {
2380Sstevel@tonic-gate 		/* sb_sasl_read: failed to decode packet, drop it, error */
2390Sstevel@tonic-gate 		sb->sb_sasl_iptr = NULL;
2400Sstevel@tonic-gate 		sb->sb_sasl_ilen = 0;
2410Sstevel@tonic-gate 		LDAP_SET_ERRNO(ld, EIO);
2420Sstevel@tonic-gate 		return( -1 );
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	/* copy decrypted packet to the input buffer */
2460Sstevel@tonic-gate 	SAFEMEMCPY( sb->sb_sasl_ibuf, dbuf, dlen );
2470Sstevel@tonic-gate 	sb->sb_sasl_iptr = sb->sb_sasl_ibuf;
2480Sstevel@tonic-gate 	sb->sb_sasl_ilen = dlen;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	ret = (dlen > (unsigned) len ? len : dlen);
2510Sstevel@tonic-gate 	SAFEMEMCPY( buf, sb->sb_sasl_iptr, ret );
2520Sstevel@tonic-gate 	if (ret == sb->sb_sasl_ilen) {
2530Sstevel@tonic-gate 		sb->sb_sasl_ilen = 0;
2540Sstevel@tonic-gate 		sb->sb_sasl_iptr = NULL;
2550Sstevel@tonic-gate 	} else {
2560Sstevel@tonic-gate 		sb->sb_sasl_ilen -= ret;
2570Sstevel@tonic-gate 		sb->sb_sasl_iptr += ret;
2580Sstevel@tonic-gate 	}
2590Sstevel@tonic-gate 	return( ret );
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate static int
nsldapi_sasl_write(int s,const void * buf,int len,struct lextiof_socket_private * arg)2630Sstevel@tonic-gate nsldapi_sasl_write( int s, const void *buf, int  len,
2640Sstevel@tonic-gate 	struct lextiof_socket_private *arg)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
267*12023SDoug.Leavitt@Sun.COM 	int		ret = 0;
268*12023SDoug.Leavitt@Sun.COM 	const char	*obuf, *optr, *cbuf = (const char *)buf;
269*12023SDoug.Leavitt@Sun.COM 	unsigned	olen, clen, tlen = 0;
270*12023SDoug.Leavitt@Sun.COM 	unsigned	*maxbuf;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	if (sb == NULL) {
2730Sstevel@tonic-gate 		return( -1 );
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 
276*12023SDoug.Leavitt@Sun.COM 	ret = sasl_getprop(sb->sb_sasl_ctx, SASL_MAXOUTBUF,
277*12023SDoug.Leavitt@Sun.COM 					     (const void **)&maxbuf);
2780Sstevel@tonic-gate 	if ( ret != SASL_OK ) {
279*12023SDoug.Leavitt@Sun.COM 		/* just a sanity check, should never happen */
2800Sstevel@tonic-gate 		return( -1 );
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
283*12023SDoug.Leavitt@Sun.COM 	while (len > 0) {
284*12023SDoug.Leavitt@Sun.COM 		clen = (len > *maxbuf) ? *maxbuf : len;
285*12023SDoug.Leavitt@Sun.COM 		/* encode the next packet. */
286*12023SDoug.Leavitt@Sun.COM 		ret = sasl_encode( sb->sb_sasl_ctx, cbuf, clen, &obuf, &olen);
287*12023SDoug.Leavitt@Sun.COM 		if ( ret != SASL_OK ) {
288*12023SDoug.Leavitt@Sun.COM 			/* XXX Log error? "sb_sasl_write: failed to encode packet..." */
289*12023SDoug.Leavitt@Sun.COM 			return( -1 );
2900Sstevel@tonic-gate 		}
291*12023SDoug.Leavitt@Sun.COM 		/* Write everything now, buffer is only good until next sasl_encode */
292*12023SDoug.Leavitt@Sun.COM 		optr = obuf;
293*12023SDoug.Leavitt@Sun.COM 		while (olen > 0) {
294*12023SDoug.Leavitt@Sun.COM 			if (sb->sb_sasl_fns.lbextiofn_write != NULL) {
295*12023SDoug.Leavitt@Sun.COM 				ret = sb->sb_sasl_fns.lbextiofn_write(
296*12023SDoug.Leavitt@Sun.COM 					s, optr, olen,
297*12023SDoug.Leavitt@Sun.COM 					sb->sb_sasl_fns.lbextiofn_socket_arg);
298*12023SDoug.Leavitt@Sun.COM 			} else {
299*12023SDoug.Leavitt@Sun.COM 				ret = write( sb->sb_sd, optr, olen);
300*12023SDoug.Leavitt@Sun.COM 			}
301*12023SDoug.Leavitt@Sun.COM 			if ( ret < 0 )
302*12023SDoug.Leavitt@Sun.COM 				return( ret );
303*12023SDoug.Leavitt@Sun.COM 			optr += ret;
304*12023SDoug.Leavitt@Sun.COM 			olen -= ret;
305*12023SDoug.Leavitt@Sun.COM 		}
306*12023SDoug.Leavitt@Sun.COM 		len -= clen;
307*12023SDoug.Leavitt@Sun.COM 		cbuf += clen;
308*12023SDoug.Leavitt@Sun.COM 		tlen += clen;
3090Sstevel@tonic-gate 	}
310*12023SDoug.Leavitt@Sun.COM 	return( tlen );
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate static int
nsldapi_sasl_poll(LDAP_X_PollFD fds[],int nfds,int timeout,struct lextiof_session_private * arg)3140Sstevel@tonic-gate nsldapi_sasl_poll(
3150Sstevel@tonic-gate 	LDAP_X_PollFD fds[], int nfds, int timeout,
3160Sstevel@tonic-gate 	struct lextiof_session_private *arg )
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
3190Sstevel@tonic-gate 	LDAP		*ld;
3200Sstevel@tonic-gate 	int		i;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if (sb == NULL) {
3230Sstevel@tonic-gate 		return( -1 );
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 	ld = (LDAP *)sb->sb_sasl_prld;
3260Sstevel@tonic-gate 	if (ld == NULL) {
3270Sstevel@tonic-gate 		return( -1 );
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if (fds && nfds > 0) {
3310Sstevel@tonic-gate 		for(i = 0; i < nfds; i++) {
3320Sstevel@tonic-gate 			if (fds[i].lpoll_socketarg ==
3330Sstevel@tonic-gate 			     (struct lextiof_socket_private *)sb) {
3340Sstevel@tonic-gate 				fds[i].lpoll_socketarg =
3350Sstevel@tonic-gate 					(struct lextiof_socket_private *)
3360Sstevel@tonic-gate 					sb->sb_sasl_fns.lbextiofn_socket_arg;
3370Sstevel@tonic-gate 			}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 	return ( ld->ld_sasl_io_fns.lextiof_poll( fds, nfds, timeout,
3420Sstevel@tonic-gate 		(void *)ld->ld_sasl_io_fns.lextiof_session_arg) );
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate /* no encryption indirect routines */
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate static int
nsldapi_sasl_ne_read(int s,void * buf,int len,struct lextiof_socket_private * arg)3480Sstevel@tonic-gate nsldapi_sasl_ne_read( int s, void *buf, int  len,
3490Sstevel@tonic-gate 	struct lextiof_socket_private *arg)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	if (sb == NULL) {
3540Sstevel@tonic-gate 		return( -1 );
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	return( sb->sb_sasl_fns.lbextiofn_read( s, buf, len,
3580Sstevel@tonic-gate 			sb->sb_sasl_fns.lbextiofn_socket_arg) );
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate static int
nsldapi_sasl_ne_write(int s,const void * buf,int len,struct lextiof_socket_private * arg)3620Sstevel@tonic-gate nsldapi_sasl_ne_write( int s, const void *buf, int  len,
3630Sstevel@tonic-gate 	struct lextiof_socket_private *arg)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	if (sb == NULL) {
3680Sstevel@tonic-gate 		return( -1 );
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	return( sb->sb_sasl_fns.lbextiofn_write( s, buf, len,
3720Sstevel@tonic-gate 			sb->sb_sasl_fns.lbextiofn_socket_arg) );
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate static int
nsldapi_sasl_close_socket(int s,struct lextiof_socket_private * arg)3760Sstevel@tonic-gate nsldapi_sasl_close_socket(int s, struct lextiof_socket_private *arg )
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 	Sockbuf		*sb = (Sockbuf *)arg;
3790Sstevel@tonic-gate 	LDAP		*ld;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	if (sb == NULL) {
3820Sstevel@tonic-gate 		return( -1 );
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 	ld = (LDAP *)sb->sb_sasl_prld;
3850Sstevel@tonic-gate 	if (ld == NULL) {
3860Sstevel@tonic-gate 		return( -1 );
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate 	/* undo function pointer interposing */
3890Sstevel@tonic-gate 	ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &ld->ld_sasl_io_fns );
3900Sstevel@tonic-gate 	ber_sockbuf_set_option( sb,
3910Sstevel@tonic-gate 			LBER_SOCKBUF_OPT_EXT_IO_FNS,
3920Sstevel@tonic-gate 			(void *)&sb->sb_sasl_fns);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	/* undo SASL */
3950Sstevel@tonic-gate 	nsldapi_sasl_close( ld, sb );
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	return ( ld->ld_sasl_io_fns.lextiof_close( s,
3980Sstevel@tonic-gate 		(struct lextiof_socket_private *)
3990Sstevel@tonic-gate 		sb->sb_sasl_fns.lbextiofn_socket_arg ) );
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate  * install encryption routines if security has been negotiated
4040Sstevel@tonic-gate  */
4050Sstevel@tonic-gate static int
nsldapi_sasl_install(LDAP * ld,Sockbuf * sb,void * ctx_arg,sasl_ssf_t * ssf)4060Sstevel@tonic-gate nsldapi_sasl_install( LDAP *ld, Sockbuf *sb, void *ctx_arg, sasl_ssf_t *ssf)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate 	struct lber_x_ext_io_fns	fns;
4090Sstevel@tonic-gate 	struct ldap_x_ext_io_fns	iofns;
4100Sstevel@tonic-gate 	sasl_security_properties_t 	*secprops;
4110Sstevel@tonic-gate 	int	rc, value;
4120Sstevel@tonic-gate 	int	bufsiz;
4130Sstevel@tonic-gate 	int	encrypt = 0;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	if (ssf && *ssf) {
4160Sstevel@tonic-gate 		encrypt = 1;
4170Sstevel@tonic-gate 	}
418*12023SDoug.Leavitt@Sun.COM 	if ( sb == NULL ) {
419*12023SDoug.Leavitt@Sun.COM 		return( LDAP_LOCAL_ERROR );
420*12023SDoug.Leavitt@Sun.COM 	}
4210Sstevel@tonic-gate 	rc = ber_sockbuf_get_option( sb,
4220Sstevel@tonic-gate 			LBER_SOCKBUF_OPT_TO_FILE_ONLY,
4230Sstevel@tonic-gate 			(void *) &value);
4240Sstevel@tonic-gate 	if (rc != 0 || value != 0)
4250Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	if (encrypt) {
4280Sstevel@tonic-gate 		/* initialize input buffer - use MAX SIZE to avoid reallocs */
4290Sstevel@tonic-gate 		sb->sb_sasl_ctx = (sasl_conn_t *)ctx_arg;
4300Sstevel@tonic-gate 		rc = sasl_getprop( sb->sb_sasl_ctx, SASL_SEC_PROPS,
4310Sstevel@tonic-gate 				   (const void **)&secprops );
4320Sstevel@tonic-gate 		if (rc != SASL_OK)
4330Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
4340Sstevel@tonic-gate 		bufsiz = secprops->maxbufsize;
4350Sstevel@tonic-gate 		if (bufsiz <= 0) {
4360Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
4370Sstevel@tonic-gate 		}
4380Sstevel@tonic-gate 		if ((sb->sb_sasl_ibuf = NSLDAPI_MALLOC(bufsiz)) == NULL) {
4390Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
4400Sstevel@tonic-gate 		}
4410Sstevel@tonic-gate 		sb->sb_sasl_iptr = NULL;
4420Sstevel@tonic-gate 		sb->sb_sasl_bfsz = bufsiz;
4430Sstevel@tonic-gate 		sb->sb_sasl_ilen = 0;
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	/* Reset Session then Socket Args */
4470Sstevel@tonic-gate 	/* Get old values */
4480Sstevel@tonic-gate 	(void) memset( &sb->sb_sasl_fns, 0, LBER_X_EXTIO_FNS_SIZE);
4490Sstevel@tonic-gate 	sb->sb_sasl_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
4500Sstevel@tonic-gate 	rc = ber_sockbuf_get_option( sb,
4510Sstevel@tonic-gate 			LBER_SOCKBUF_OPT_EXT_IO_FNS,
4520Sstevel@tonic-gate 			(void *)&sb->sb_sasl_fns);
453*12023SDoug.Leavitt@Sun.COM 	if (rc != 0) {
454*12023SDoug.Leavitt@Sun.COM 		destroy_sasliobuf(sb);
455*12023SDoug.Leavitt@Sun.COM 		return( LDAP_LOCAL_ERROR );
456*12023SDoug.Leavitt@Sun.COM 	}
4570Sstevel@tonic-gate 	memset( &ld->ld_sasl_io_fns, 0, sizeof(iofns));
4580Sstevel@tonic-gate 	ld->ld_sasl_io_fns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
4590Sstevel@tonic-gate 	rc = ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
4600Sstevel@tonic-gate 			      &ld->ld_sasl_io_fns );
461*12023SDoug.Leavitt@Sun.COM 	if (rc != 0 ) {
462*12023SDoug.Leavitt@Sun.COM 		destroy_sasliobuf(sb);
4630Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
464*12023SDoug.Leavitt@Sun.COM 	}
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	/* Set new values */
4670Sstevel@tonic-gate 	if (  ld->ld_sasl_io_fns.lextiof_read != NULL ||
4680Sstevel@tonic-gate 	      ld->ld_sasl_io_fns.lextiof_write != NULL ||
4690Sstevel@tonic-gate 	      ld->ld_sasl_io_fns.lextiof_poll != NULL ||
4700Sstevel@tonic-gate 	      ld->ld_sasl_io_fns.lextiof_connect != NULL ||
4710Sstevel@tonic-gate 	      ld->ld_sasl_io_fns.lextiof_close != NULL ) {
4720Sstevel@tonic-gate 		memset( &iofns, 0, sizeof(iofns));
4730Sstevel@tonic-gate 		iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
4740Sstevel@tonic-gate 		if (encrypt) {
4750Sstevel@tonic-gate 			iofns.lextiof_read = nsldapi_sasl_read;
4760Sstevel@tonic-gate 			iofns.lextiof_write = nsldapi_sasl_write;
4770Sstevel@tonic-gate 			iofns.lextiof_poll = nsldapi_sasl_poll;
4780Sstevel@tonic-gate 		} else {
4790Sstevel@tonic-gate 			iofns.lextiof_read = nsldapi_sasl_ne_read;
4800Sstevel@tonic-gate 			iofns.lextiof_write = nsldapi_sasl_ne_write;
4810Sstevel@tonic-gate 			iofns.lextiof_poll = nsldapi_sasl_poll;
4820Sstevel@tonic-gate 		}
4830Sstevel@tonic-gate 		iofns.lextiof_connect = ld->ld_sasl_io_fns.lextiof_connect;
4840Sstevel@tonic-gate 		iofns.lextiof_close = nsldapi_sasl_close_socket;
4850Sstevel@tonic-gate 		iofns.lextiof_newhandle = ld->ld_sasl_io_fns.lextiof_newhandle;
4860Sstevel@tonic-gate 		iofns.lextiof_disposehandle =
4870Sstevel@tonic-gate 				ld->ld_sasl_io_fns.lextiof_disposehandle;
4880Sstevel@tonic-gate 		iofns.lextiof_session_arg =
4890Sstevel@tonic-gate 				(void *) sb;
4900Sstevel@tonic-gate 				/* ld->ld_sasl_io_fns.lextiof_session_arg; */
4910Sstevel@tonic-gate 		rc = ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
4920Sstevel@tonic-gate 			      &iofns );
493*12023SDoug.Leavitt@Sun.COM 		if (rc != 0 ) {
494*12023SDoug.Leavitt@Sun.COM 			destroy_sasliobuf(sb);
4950Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
496*12023SDoug.Leavitt@Sun.COM 		}
4970Sstevel@tonic-gate 		sb->sb_sasl_prld = (void *)ld;
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	if (encrypt) {
5010Sstevel@tonic-gate 		(void) memset( &fns, 0, LBER_X_EXTIO_FNS_SIZE);
5020Sstevel@tonic-gate 		fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
5030Sstevel@tonic-gate 		fns.lbextiofn_read = nsldapi_sasl_read;
5040Sstevel@tonic-gate 		fns.lbextiofn_write = nsldapi_sasl_write;
5050Sstevel@tonic-gate 		fns.lbextiofn_socket_arg =
5060Sstevel@tonic-gate 			(void *) sb;
5070Sstevel@tonic-gate 			/* (void *)sb->sb_sasl_fns.lbextiofn_socket_arg; */
5080Sstevel@tonic-gate 		rc = ber_sockbuf_set_option( sb,
5090Sstevel@tonic-gate 				LBER_SOCKBUF_OPT_EXT_IO_FNS,
5100Sstevel@tonic-gate 				(void *)&fns);
511*12023SDoug.Leavitt@Sun.COM 		if (rc != 0) {
512*12023SDoug.Leavitt@Sun.COM 			destroy_sasliobuf(sb);
5130Sstevel@tonic-gate 			return( LDAP_LOCAL_ERROR );
514*12023SDoug.Leavitt@Sun.COM 		}
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	return( LDAP_SUCCESS );
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate static int
nsldapi_sasl_cvterrno(LDAP * ld,int err,char * msg)521*12023SDoug.Leavitt@Sun.COM nsldapi_sasl_cvterrno( LDAP *ld, int err, char *msg )
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate 	int rc = LDAP_LOCAL_ERROR;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	switch (err) {
5260Sstevel@tonic-gate 	case SASL_OK:
5270Sstevel@tonic-gate 		rc = LDAP_SUCCESS;
5280Sstevel@tonic-gate 		break;
5290Sstevel@tonic-gate 	case SASL_NOMECH:
5300Sstevel@tonic-gate 		rc = LDAP_AUTH_UNKNOWN;
5310Sstevel@tonic-gate 		break;
5320Sstevel@tonic-gate 	case SASL_BADSERV:
5330Sstevel@tonic-gate 		rc = LDAP_CONNECT_ERROR;
5340Sstevel@tonic-gate 		break;
5350Sstevel@tonic-gate 	case SASL_DISABLED:
5360Sstevel@tonic-gate 	case SASL_ENCRYPT:
5370Sstevel@tonic-gate 	case SASL_EXPIRED:
5380Sstevel@tonic-gate 	case SASL_NOUSERPASS:
5390Sstevel@tonic-gate 	case SASL_NOVERIFY:
5400Sstevel@tonic-gate 	case SASL_PWLOCK:
5410Sstevel@tonic-gate 	case SASL_TOOWEAK:
5420Sstevel@tonic-gate 	case SASL_UNAVAIL:
5430Sstevel@tonic-gate 	case SASL_WEAKPASS:
5440Sstevel@tonic-gate 		rc = LDAP_INAPPROPRIATE_AUTH;
5450Sstevel@tonic-gate 		break;
5460Sstevel@tonic-gate 	case SASL_BADAUTH:
5470Sstevel@tonic-gate 	case SASL_NOAUTHZ:
5480Sstevel@tonic-gate 		rc = LDAP_INVALID_CREDENTIALS;
5490Sstevel@tonic-gate 		break;
5500Sstevel@tonic-gate 	case SASL_NOMEM:
5510Sstevel@tonic-gate 		rc = LDAP_NO_MEMORY;
5520Sstevel@tonic-gate 		break;
5530Sstevel@tonic-gate 	case SASL_NOUSER:
5540Sstevel@tonic-gate 		rc = LDAP_NO_SUCH_OBJECT;
5550Sstevel@tonic-gate 		break;
5560Sstevel@tonic-gate 	case SASL_CONTINUE:
5570Sstevel@tonic-gate 	case SASL_FAIL:
5580Sstevel@tonic-gate 	case SASL_INTERACT:
5590Sstevel@tonic-gate 	default:
5600Sstevel@tonic-gate 		rc = LDAP_LOCAL_ERROR;
5610Sstevel@tonic-gate 		break;
5620Sstevel@tonic-gate 	}
5630Sstevel@tonic-gate 
564*12023SDoug.Leavitt@Sun.COM 	LDAP_SET_LDERRNO( ld, rc, NULL, msg );
5650Sstevel@tonic-gate 	return( rc );
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate int
nsldapi_sasl_open(LDAP * ld)5690Sstevel@tonic-gate nsldapi_sasl_open(LDAP *ld)
5700Sstevel@tonic-gate {
5710Sstevel@tonic-gate 	Sockbuf *sb;
5720Sstevel@tonic-gate 	char * host;
5730Sstevel@tonic-gate 	int saslrc;
574*12023SDoug.Leavitt@Sun.COM 	sasl_conn_t *ctx = NULL;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	if (ld == NULL) {
5770Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	if (ld->ld_defconn == NULL) {
5810Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
5820Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate 	sb = ld->ld_defconn->lconn_sb;
5850Sstevel@tonic-gate 	host = ld->ld_defhost;
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	if ( sb == NULL || host == NULL ) {
5880Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
5890Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
5900Sstevel@tonic-gate 	}
5910Sstevel@tonic-gate 
592*12023SDoug.Leavitt@Sun.COM 	if (sb->sb_sasl_ctx) {
593*12023SDoug.Leavitt@Sun.COM 	    sasl_dispose(&sb->sb_sasl_ctx);
594*12023SDoug.Leavitt@Sun.COM 	    sb->sb_sasl_ctx = NULL;
595*12023SDoug.Leavitt@Sun.COM 	}
596*12023SDoug.Leavitt@Sun.COM 
5970Sstevel@tonic-gate 	/* SASL is not properly initialized */
5980Sstevel@tonic-gate 	mutex_lock(&sasl_mutex);
5990Sstevel@tonic-gate 	if (gctx == NULL) {
6000Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
6010Sstevel@tonic-gate 		mutex_unlock(&sasl_mutex);
6020Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	saslrc = _sasl_client_new(gctx, "ldap", host,
6060Sstevel@tonic-gate 		NULL, NULL, /* iplocal ipremote strings currently unused */
6070Sstevel@tonic-gate 		NULL, 0, &ctx );
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	if ( saslrc != SASL_OK ) {
6100Sstevel@tonic-gate 		mutex_unlock(&sasl_mutex);
611*12023SDoug.Leavitt@Sun.COM 		sasl_dispose(&ctx);
612*12023SDoug.Leavitt@Sun.COM 		return( nsldapi_sasl_cvterrno( ld, saslrc, NULL ) );
6130Sstevel@tonic-gate 	}
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	sb->sb_sasl_ctx = (void *)ctx;
6160Sstevel@tonic-gate 	mutex_unlock(&sasl_mutex);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	return( LDAP_SUCCESS );
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate 
62110285SMilan.Jurik@Sun.COM static void
destroy_sasliobuf(Sockbuf * sb)62210285SMilan.Jurik@Sun.COM destroy_sasliobuf(Sockbuf *sb)
62310285SMilan.Jurik@Sun.COM {
62410285SMilan.Jurik@Sun.COM 	if (sb != NULL && sb->sb_sasl_ibuf != NULL) {
62510285SMilan.Jurik@Sun.COM 		NSLDAPI_FREE(sb->sb_sasl_ibuf);
62610285SMilan.Jurik@Sun.COM 		sb->sb_sasl_ibuf = NULL;
627*12023SDoug.Leavitt@Sun.COM 		sb->sb_sasl_iptr = NULL;
628*12023SDoug.Leavitt@Sun.COM 		sb->sb_sasl_bfsz = 0;
629*12023SDoug.Leavitt@Sun.COM 		sb->sb_sasl_ilen = 0;
63010285SMilan.Jurik@Sun.COM 	}
63110285SMilan.Jurik@Sun.COM }
63210285SMilan.Jurik@Sun.COM 
6330Sstevel@tonic-gate static int
nsldapi_sasl_close(LDAP * ld,Sockbuf * sb)6340Sstevel@tonic-gate nsldapi_sasl_close( LDAP *ld, Sockbuf *sb )
6350Sstevel@tonic-gate {
6360Sstevel@tonic-gate 	sasl_conn_t	*ctx = (sasl_conn_t *)sb->sb_sasl_ctx;
6370Sstevel@tonic-gate 
63810285SMilan.Jurik@Sun.COM 	destroy_sasliobuf(sb);
63910285SMilan.Jurik@Sun.COM 
6400Sstevel@tonic-gate 	if( ctx != NULL ) {
6410Sstevel@tonic-gate 		sasl_dispose( &ctx );
6420Sstevel@tonic-gate 		sb->sb_sasl_ctx = NULL;
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 	return( LDAP_SUCCESS );
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate static int
nsldapi_sasl_do_bind(LDAP * ld,const char * dn,const char * mechs,unsigned flags,LDAP_SASL_INTERACT_PROC * callback,void * defaults,LDAPControl ** sctrl,LDAPControl ** cctrl)6480Sstevel@tonic-gate nsldapi_sasl_do_bind( LDAP *ld, const char *dn,
6490Sstevel@tonic-gate 	const char *mechs, unsigned flags,
6500Sstevel@tonic-gate 	LDAP_SASL_INTERACT_PROC *callback, void *defaults,
6510Sstevel@tonic-gate 	LDAPControl **sctrl, LDAPControl **cctrl )
6520Sstevel@tonic-gate {
6530Sstevel@tonic-gate 	sasl_interact_t *prompts = NULL;
6540Sstevel@tonic-gate 	sasl_conn_t	*ctx;
6550Sstevel@tonic-gate 	sasl_ssf_t	*ssf = NULL;
6560Sstevel@tonic-gate 	const char	*mech = NULL;
6570Sstevel@tonic-gate 	int		saslrc, rc;
6580Sstevel@tonic-gate 	struct berval	ccred;
6590Sstevel@tonic-gate 	unsigned	credlen;
660*12023SDoug.Leavitt@Sun.COM 	int		stepnum = 1;
661*12023SDoug.Leavitt@Sun.COM 	char *sasl_username = NULL;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	if (NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3) {
6640Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
6650Sstevel@tonic-gate 		return( LDAP_NOT_SUPPORTED );
6660Sstevel@tonic-gate 	}
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	/* shouldn't happen */
6690Sstevel@tonic-gate 	if (callback == NULL) {
6700Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	if ( ld->ld_defconn == NULL ||
6740Sstevel@tonic-gate 	     ld->ld_defconn->lconn_status != LDAP_CONNST_CONNECTED) {
6750Sstevel@tonic-gate 		rc = nsldapi_open_ldap_defconn( ld );
6760Sstevel@tonic-gate 		if( rc < 0 )  {
6770Sstevel@tonic-gate 			return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
6780Sstevel@tonic-gate 		}
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	/* should have a valid ld connection - now create sasl connection */
6820Sstevel@tonic-gate 	if ((rc = nsldapi_sasl_open(ld)) != LDAP_SUCCESS) {
6830Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
6840Sstevel@tonic-gate 		return( rc );
6850Sstevel@tonic-gate 	}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	/* expect context to be initialized when connection is open */
6880Sstevel@tonic-gate 	ctx = (sasl_conn_t *)ld->ld_defconn->lconn_sb->sb_sasl_ctx;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	if( ctx == NULL ) {
6910Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
6920Sstevel@tonic-gate 		return( LDAP_LOCAL_ERROR );
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	/* (re)set security properties */
6960Sstevel@tonic-gate 	sasl_setprop( ctx, SASL_SEC_PROPS, &ld->ld_sasl_secprops );
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	ccred.bv_val = NULL;
6990Sstevel@tonic-gate 	ccred.bv_len = 0;
7000Sstevel@tonic-gate 
701*12023SDoug.Leavitt@Sun.COM 	LDAPDebug(LDAP_DEBUG_TRACE, "Starting SASL/%s authentication\n",
702*12023SDoug.Leavitt@Sun.COM 		  (mech ? mech : ""), 0, 0 );
703*12023SDoug.Leavitt@Sun.COM 
7040Sstevel@tonic-gate 	do {
7050Sstevel@tonic-gate 		saslrc = sasl_client_start( ctx,
7060Sstevel@tonic-gate 			mechs,
7070Sstevel@tonic-gate 			&prompts,
7080Sstevel@tonic-gate 			(const char **)&ccred.bv_val,
7090Sstevel@tonic-gate 			&credlen,
7100Sstevel@tonic-gate 			&mech );
7110Sstevel@tonic-gate 
712*12023SDoug.Leavitt@Sun.COM 		LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of client start for SASL/%s authentication\n",
713*12023SDoug.Leavitt@Sun.COM 			  stepnum, (mech ? mech : ""), 0 );
714*12023SDoug.Leavitt@Sun.COM 		stepnum++;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		if( saslrc == SASL_INTERACT &&
7170Sstevel@tonic-gate 		    (callback)(ld, flags, defaults, prompts) != LDAP_SUCCESS ) {
7180Sstevel@tonic-gate 			break;
7190Sstevel@tonic-gate 		}
7200Sstevel@tonic-gate 	} while ( saslrc == SASL_INTERACT );
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	ccred.bv_len = credlen;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
725*12023SDoug.Leavitt@Sun.COM 		return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
728*12023SDoug.Leavitt@Sun.COM 	stepnum = 1;
729*12023SDoug.Leavitt@Sun.COM 
7300Sstevel@tonic-gate 	do {
7310Sstevel@tonic-gate 		struct berval *scred;
732*12023SDoug.Leavitt@Sun.COM 		int clientstepnum = 1;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 		scred = NULL;
7350Sstevel@tonic-gate 
736*12023SDoug.Leavitt@Sun.COM 		LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of bind for SASL/%s authentication\n",
737*12023SDoug.Leavitt@Sun.COM                           stepnum, (mech ? mech : ""), 0 );
738*12023SDoug.Leavitt@Sun.COM                 stepnum++;
739*12023SDoug.Leavitt@Sun.COM 
7400Sstevel@tonic-gate 		/* notify server of a sasl bind step */
7410Sstevel@tonic-gate 		rc = ldap_sasl_bind_s(ld, dn, mech, &ccred,
7420Sstevel@tonic-gate 				      sctrl, cctrl, &scred);
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 		if ( ccred.bv_val != NULL ) {
7450Sstevel@tonic-gate 			ccred.bv_val = NULL;
7460Sstevel@tonic-gate 		}
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 		if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
749*12023SDoug.Leavitt@Sun.COM 			ber_bvfree( scred );
7500Sstevel@tonic-gate 			return( rc );
7510Sstevel@tonic-gate 		}
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 		if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
7540Sstevel@tonic-gate 			/* we're done, no need to step */
755*12023SDoug.Leavitt@Sun.COM 			if( scred ) {
756*12023SDoug.Leavitt@Sun.COM 			    if (scred->bv_len  == 0 ) { /* MS AD sends back empty screds */
757*12023SDoug.Leavitt@Sun.COM 				LDAPDebug(LDAP_DEBUG_ANY,
758*12023SDoug.Leavitt@Sun.COM 					  "SASL BIND complete - ignoring empty credential response\n",
759*12023SDoug.Leavitt@Sun.COM 					  0, 0, 0);
760*12023SDoug.Leavitt@Sun.COM 				ber_bvfree( scred );
761*12023SDoug.Leavitt@Sun.COM 			    } else {
7620Sstevel@tonic-gate 				/* but server provided us with data! */
763*12023SDoug.Leavitt@Sun.COM 				LDAPDebug(LDAP_DEBUG_TRACE,
764*12023SDoug.Leavitt@Sun.COM 					  "SASL BIND complete but invalid because server responded with credentials - length [%u]\n",
765*12023SDoug.Leavitt@Sun.COM 					  scred->bv_len, 0, 0);
7660Sstevel@tonic-gate 				ber_bvfree( scred );
7670Sstevel@tonic-gate 				LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR,
768*12023SDoug.Leavitt@Sun.COM 				    NULL, nsldapi_strdup( dgettext(TEXT_DOMAIN,
769*12023SDoug.Leavitt@Sun.COM 				    "Error during SASL handshake - "
770*12023SDoug.Leavitt@Sun.COM 				    "invalid server credential response") ));
7710Sstevel@tonic-gate 				return( LDAP_LOCAL_ERROR );
772*12023SDoug.Leavitt@Sun.COM 			    }
7730Sstevel@tonic-gate 			}
7740Sstevel@tonic-gate 			break;
7750Sstevel@tonic-gate 		}
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 		/* perform the next step of the sasl bind */
7780Sstevel@tonic-gate 		do {
779*12023SDoug.Leavitt@Sun.COM 			LDAPDebug(LDAP_DEBUG_TRACE, "Doing client step %d of bind step %d for SASL/%s authentication\n",
780*12023SDoug.Leavitt@Sun.COM 				  clientstepnum, stepnum, (mech ? mech : "") );
781*12023SDoug.Leavitt@Sun.COM 			clientstepnum++;
7820Sstevel@tonic-gate 			saslrc = sasl_client_step( ctx,
7830Sstevel@tonic-gate 				(scred == NULL) ? NULL : scred->bv_val,
7840Sstevel@tonic-gate 				(scred == NULL) ? 0 : scred->bv_len,
7850Sstevel@tonic-gate 				&prompts,
7860Sstevel@tonic-gate 				(const char **)&ccred.bv_val,
7870Sstevel@tonic-gate 				&credlen );
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 			if( saslrc == SASL_INTERACT &&
7900Sstevel@tonic-gate 			    (callback)(ld, flags, defaults, prompts)
7910Sstevel@tonic-gate 							!= LDAP_SUCCESS ) {
7920Sstevel@tonic-gate 				break;
7930Sstevel@tonic-gate 			}
7940Sstevel@tonic-gate 		} while ( saslrc == SASL_INTERACT );
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		ccred.bv_len = credlen;
7970Sstevel@tonic-gate 		ber_bvfree( scred );
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 		if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
800*12023SDoug.Leavitt@Sun.COM 			return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
8010Sstevel@tonic-gate 		}
8020Sstevel@tonic-gate 	} while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	if ( rc != LDAP_SUCCESS ) {
8050Sstevel@tonic-gate 		return( rc );
8060Sstevel@tonic-gate 	}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	if ( saslrc != SASL_OK ) {
809*12023SDoug.Leavitt@Sun.COM 		return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
810*12023SDoug.Leavitt@Sun.COM 	}
811*12023SDoug.Leavitt@Sun.COM 
812*12023SDoug.Leavitt@Sun.COM 	saslrc = sasl_getprop( ctx, SASL_USERNAME, (const void **) &sasl_username );
813*12023SDoug.Leavitt@Sun.COM 	if ( (saslrc == SASL_OK) && sasl_username ) {
814*12023SDoug.Leavitt@Sun.COM 		LDAPDebug(LDAP_DEBUG_TRACE, "SASL identity: %s\n", sasl_username, 0, 0);
8150Sstevel@tonic-gate 	}
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	saslrc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf );
8180Sstevel@tonic-gate 	if( saslrc == SASL_OK ) {
819*12023SDoug.Leavitt@Sun.COM 		if( ssf && *ssf ) {
820*12023SDoug.Leavitt@Sun.COM 			LDAPDebug(LDAP_DEBUG_TRACE,
821*12023SDoug.Leavitt@Sun.COM 				"SASL install encryption, for SSF: %lu\n",
822*12023SDoug.Leavitt@Sun.COM 				(unsigned long) *ssf, 0, 0 );
823*12023SDoug.Leavitt@Sun.COM 		}
8240Sstevel@tonic-gate 		rc = nsldapi_sasl_install(ld, ld->ld_conns->lconn_sb, ctx, ssf);
8250Sstevel@tonic-gate 	}
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	return( rc );
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
8310Sstevel@tonic-gate /*
8320Sstevel@tonic-gate  * Get available SASL Mechanisms supported by the server
8330Sstevel@tonic-gate  */
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate static int
nsldapi_get_sasl_mechs(LDAP * ld,char ** pmech)8360Sstevel@tonic-gate nsldapi_get_sasl_mechs ( LDAP *ld, char **pmech )
8370Sstevel@tonic-gate {
8380Sstevel@tonic-gate 	char *attr[] = { "supportedSASLMechanisms", NULL };
8390Sstevel@tonic-gate 	char **values, **v, *mech, *m;
8400Sstevel@tonic-gate 	LDAPMessage *res, *e;
8410Sstevel@tonic-gate 	struct timeval	timeout;
8420Sstevel@tonic-gate 	int slen, rc;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
8450Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
8460Sstevel@tonic-gate 	}
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	timeout.tv_sec = SEARCH_TIMEOUT_SECS;
8490Sstevel@tonic-gate 	timeout.tv_usec = 0;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	rc = ldap_search_st( ld, "", LDAP_SCOPE_BASE,
8520Sstevel@tonic-gate 		"objectclass=*", attr, 0, &timeout, &res );
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	if ( rc != LDAP_SUCCESS ) {
8550Sstevel@tonic-gate 		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	e = ldap_first_entry( ld, res );
8590Sstevel@tonic-gate 	if ( e == NULL ) {
8600Sstevel@tonic-gate 		ldap_msgfree( res );
8610Sstevel@tonic-gate 		if ( ld->ld_errno == LDAP_SUCCESS ) {
8620Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_OBJECT, NULL, NULL );
8630Sstevel@tonic-gate 		}
8640Sstevel@tonic-gate 		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
8650Sstevel@tonic-gate 	}
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
8680Sstevel@tonic-gate 	if ( values == NULL ) {
8690Sstevel@tonic-gate 		ldap_msgfree( res );
8700Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL );
8710Sstevel@tonic-gate 		return( LDAP_NO_SUCH_ATTRIBUTE );
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	slen = 0;
8750Sstevel@tonic-gate 	for(v = values; *v != NULL; v++ ) {
8760Sstevel@tonic-gate 		slen += strlen(*v) + 1;
8770Sstevel@tonic-gate 	}
8780Sstevel@tonic-gate 	if ( (mech = NSLDAPI_CALLOC(1, slen)) == NULL) {
8790Sstevel@tonic-gate 		ldap_value_free( values );
8800Sstevel@tonic-gate 		ldap_msgfree( res );
8810Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
8820Sstevel@tonic-gate 		return( LDAP_NO_MEMORY );
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 	m = mech;
8850Sstevel@tonic-gate 	for(v = values; *v; v++) {
8860Sstevel@tonic-gate 		if (v != values) {
8870Sstevel@tonic-gate 			*m++ = ' ';
8880Sstevel@tonic-gate 		}
8890Sstevel@tonic-gate 		slen = strlen(*v);
8900Sstevel@tonic-gate 		strncpy(m, *v, slen);
8910Sstevel@tonic-gate 		m += slen;
8920Sstevel@tonic-gate 	}
8930Sstevel@tonic-gate 	*m = '\0';
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	ldap_value_free( values );
8960Sstevel@tonic-gate 	ldap_msgfree( res );
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	*pmech = mech;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	return( LDAP_SUCCESS );
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate #endif
9030Sstevel@tonic-gate 
nsldapi_sasl_secprops(const char * in,sasl_security_properties_t * secprops)9040Sstevel@tonic-gate int nsldapi_sasl_secprops(
9050Sstevel@tonic-gate 	const char *in,
9060Sstevel@tonic-gate 	sasl_security_properties_t *secprops )
9070Sstevel@tonic-gate {
9080Sstevel@tonic-gate 	int i;
9090Sstevel@tonic-gate 	char **props = NULL;
9100Sstevel@tonic-gate 	char *inp;
9110Sstevel@tonic-gate 	unsigned sflags = 0;
9120Sstevel@tonic-gate 	sasl_ssf_t max_ssf = 0;
9130Sstevel@tonic-gate 	sasl_ssf_t min_ssf = 0;
9140Sstevel@tonic-gate 	unsigned maxbufsize = 0;
9150Sstevel@tonic-gate 	int got_sflags = 0;
9160Sstevel@tonic-gate 	int got_max_ssf = 0;
9170Sstevel@tonic-gate 	int got_min_ssf = 0;
9180Sstevel@tonic-gate 	int got_maxbufsize = 0;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	if (in == NULL) {
9210Sstevel@tonic-gate 		return LDAP_PARAM_ERROR;
9220Sstevel@tonic-gate 	}
9230Sstevel@tonic-gate 	inp = nsldapi_strdup(in);
9240Sstevel@tonic-gate 	if (inp == NULL) {
9250Sstevel@tonic-gate 		return LDAP_PARAM_ERROR;
9260Sstevel@tonic-gate 	}
9270Sstevel@tonic-gate 	props = ldap_str2charray( inp, "," );
9280Sstevel@tonic-gate 	NSLDAPI_FREE( inp );
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	if( props == NULL || secprops == NULL ) {
9310Sstevel@tonic-gate 		return LDAP_PARAM_ERROR;
9320Sstevel@tonic-gate 	}
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	for( i=0; props[i]; i++ ) {
9350Sstevel@tonic-gate 		if( strcasecmp(props[i], "none") == 0 ) {
9360Sstevel@tonic-gate 			got_sflags++;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "noactive") == 0 ) {
9390Sstevel@tonic-gate 			got_sflags++;
9400Sstevel@tonic-gate 			sflags |= SASL_SEC_NOACTIVE;
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "noanonymous") == 0 ) {
9430Sstevel@tonic-gate 			got_sflags++;
9440Sstevel@tonic-gate 			sflags |= SASL_SEC_NOANONYMOUS;
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "nodict") == 0 ) {
9470Sstevel@tonic-gate 			got_sflags++;
9480Sstevel@tonic-gate 			sflags |= SASL_SEC_NODICTIONARY;
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "noplain") == 0 ) {
9510Sstevel@tonic-gate 			got_sflags++;
9520Sstevel@tonic-gate 			sflags |= SASL_SEC_NOPLAINTEXT;
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "forwardsec") == 0 ) {
9550Sstevel@tonic-gate 			got_sflags++;
9560Sstevel@tonic-gate 			sflags |= SASL_SEC_FORWARD_SECRECY;
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 		} else if( strcasecmp(props[i], "passcred") == 0 ) {
9590Sstevel@tonic-gate 			got_sflags++;
9600Sstevel@tonic-gate 			sflags |= SASL_SEC_PASS_CREDENTIALS;
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 		} else if( strncasecmp(props[i],
9630Sstevel@tonic-gate 			"minssf=", sizeof("minssf")) == 0 ) {
9640Sstevel@tonic-gate 			if( isdigit( props[i][sizeof("minssf")] ) ) {
9650Sstevel@tonic-gate 				got_min_ssf++;
9660Sstevel@tonic-gate 				min_ssf = atoi( &props[i][sizeof("minssf")] );
9670Sstevel@tonic-gate 			} else {
9680Sstevel@tonic-gate 				return LDAP_NOT_SUPPORTED;
9690Sstevel@tonic-gate 			}
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 		} else if( strncasecmp(props[i],
9720Sstevel@tonic-gate 			"maxssf=", sizeof("maxssf")) == 0 ) {
9730Sstevel@tonic-gate 			if( isdigit( props[i][sizeof("maxssf")] ) ) {
9740Sstevel@tonic-gate 				got_max_ssf++;
9750Sstevel@tonic-gate 				max_ssf = atoi( &props[i][sizeof("maxssf")] );
9760Sstevel@tonic-gate 			} else {
9770Sstevel@tonic-gate 				return LDAP_NOT_SUPPORTED;
9780Sstevel@tonic-gate 			}
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 		} else if( strncasecmp(props[i],
9810Sstevel@tonic-gate 			"maxbufsize=", sizeof("maxbufsize")) == 0 ) {
9820Sstevel@tonic-gate 			if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
9830Sstevel@tonic-gate 				got_maxbufsize++;
9840Sstevel@tonic-gate 				maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
9850Sstevel@tonic-gate 				if( maxbufsize &&
9860Sstevel@tonic-gate 				    (( maxbufsize < SASL_MIN_BUFF_SIZE )
9870Sstevel@tonic-gate 				    || (maxbufsize > SASL_MAX_BUFF_SIZE ))) {
9880Sstevel@tonic-gate 					return( LDAP_PARAM_ERROR );
9890Sstevel@tonic-gate 				}
9900Sstevel@tonic-gate 			} else {
9910Sstevel@tonic-gate 				return( LDAP_NOT_SUPPORTED );
9920Sstevel@tonic-gate 			}
9930Sstevel@tonic-gate 		} else {
9940Sstevel@tonic-gate 			return( LDAP_NOT_SUPPORTED );
9950Sstevel@tonic-gate 		}
9960Sstevel@tonic-gate 	}
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	if(got_sflags) {
9990Sstevel@tonic-gate 		secprops->security_flags = sflags;
10000Sstevel@tonic-gate 	}
10010Sstevel@tonic-gate 	if(got_min_ssf) {
10020Sstevel@tonic-gate 		secprops->min_ssf = min_ssf;
10030Sstevel@tonic-gate 	}
10040Sstevel@tonic-gate 	if(got_max_ssf) {
10050Sstevel@tonic-gate 		secprops->max_ssf = max_ssf;
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 	if(got_maxbufsize) {
10080Sstevel@tonic-gate 		secprops->maxbufsize = maxbufsize;
10090Sstevel@tonic-gate 	}
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	ldap_charray_free( props );
10120Sstevel@tonic-gate 	return( LDAP_SUCCESS );
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate /*
10160Sstevel@tonic-gate  * SASL Authentication Interface: ldap_sasl_interactive_bind_s
10170Sstevel@tonic-gate  *
10180Sstevel@tonic-gate  * This routine takes a DN, SASL mech list, and a SASL callback
10190Sstevel@tonic-gate  * and performs the necessary sequencing to complete a SASL bind
10200Sstevel@tonic-gate  * to the LDAP connection ld.  The user provided callback can
10210Sstevel@tonic-gate  * use an optionally provided set of default values to complete
10220Sstevel@tonic-gate  * any necessary interactions.
10230Sstevel@tonic-gate  *
10240Sstevel@tonic-gate  * Currently inpose the following restrictions:
10250Sstevel@tonic-gate  *   A mech list must be provided, only LDAP_SASL_INTERACTIVE
10260Sstevel@tonic-gate  *   mode is supported
10270Sstevel@tonic-gate  */
10280Sstevel@tonic-gate int
10290Sstevel@tonic-gate LDAP_CALL
ldap_sasl_interactive_bind_s(LDAP * ld,const char * dn,const char * saslMechanism,LDAPControl ** sctrl,LDAPControl ** cctrl,unsigned flags,LDAP_SASL_INTERACT_PROC * callback,void * defaults)10300Sstevel@tonic-gate ldap_sasl_interactive_bind_s( LDAP *ld, const char *dn,
10310Sstevel@tonic-gate 	const char *saslMechanism,
10320Sstevel@tonic-gate 	LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
10330Sstevel@tonic-gate 	LDAP_SASL_INTERACT_PROC *callback, void *defaults )
10340Sstevel@tonic-gate {
10350Sstevel@tonic-gate #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
10360Sstevel@tonic-gate 	char *smechs;
10370Sstevel@tonic-gate #endif
10380Sstevel@tonic-gate 	int rc;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	LDAPDebug(LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind_s\n", 0, 0, 0);
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
10430Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
10440Sstevel@tonic-gate 	}
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	if (flags != LDAP_SASL_INTERACTIVE || callback == NULL) {
10470Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
10480Sstevel@tonic-gate 	}
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	LDAP_MUTEX_LOCK(ld, LDAP_SASL_LOCK );
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	if( saslMechanism == NULL || *saslMechanism == '\0' ) {
10530Sstevel@tonic-gate #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
10540Sstevel@tonic-gate 		rc = nsldapi_get_sasl_mechs( ld, &smechs );
10550Sstevel@tonic-gate 		if( rc != LDAP_SUCCESS ) {
10560Sstevel@tonic-gate 			LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
10570Sstevel@tonic-gate 			return( rc );
10580Sstevel@tonic-gate 		}
10590Sstevel@tonic-gate 		saslMechanism = smechs;
10600Sstevel@tonic-gate #else
10610Sstevel@tonic-gate 		LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
10620Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
10630Sstevel@tonic-gate #endif
10640Sstevel@tonic-gate 	}
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	/* initialize SASL library */
10670Sstevel@tonic-gate 	if ( nsldapi_sasl_init() < 0 ) {
10680Sstevel@tonic-gate 	    return( LDAP_PARAM_ERROR );
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	rc = nsldapi_sasl_do_bind( ld, dn, saslMechanism,
10720Sstevel@tonic-gate 			flags, callback, defaults, sctrl, cctrl);
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
10750Sstevel@tonic-gate 	return( rc );
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate #endif
1079