1*cf1d77f7Schristos /*	$NetBSD: sasl.c,v 1.3 2021/08/14 16:14:58 christos Exp $	*/
24e6df137Slukem 
333197c6aStron /* $OpenLDAP$ */
42de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
52de962bdSlukem  *
6*cf1d77f7Schristos  * Copyright 1998-2021 The OpenLDAP Foundation.
72de962bdSlukem  * All rights reserved.
82de962bdSlukem  *
92de962bdSlukem  * Redistribution and use in source and binary forms, with or without
102de962bdSlukem  * modification, are permitted only as authorized by the OpenLDAP
112de962bdSlukem  * Public License.
122de962bdSlukem  *
132de962bdSlukem  * A copy of this license is available in the file LICENSE in the
142de962bdSlukem  * top-level directory of the distribution or, alternatively, at
152de962bdSlukem  * <http://www.OpenLDAP.org/license.html>.
162de962bdSlukem  */
172de962bdSlukem 
188bd9f7cdSchristos #include <sys/cdefs.h>
19*cf1d77f7Schristos __RCSID("$NetBSD: sasl.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
208bd9f7cdSchristos 
212de962bdSlukem #include "portable.h"
222de962bdSlukem 
232de962bdSlukem #ifdef HAVE_CYRUS_SASL
242de962bdSlukem 
252de962bdSlukem #include <stdio.h>
262de962bdSlukem #include <ac/stdlib.h>
272de962bdSlukem #include <ac/string.h>
282de962bdSlukem #include <ac/unistd.h>
292de962bdSlukem 
302de962bdSlukem #ifdef HAVE_SASL_SASL_H
312de962bdSlukem #include <sasl/sasl.h>
322de962bdSlukem #else
332de962bdSlukem #include <sasl.h>
342de962bdSlukem #endif
352de962bdSlukem 
362de962bdSlukem #include <ldap.h>
372de962bdSlukem #include "ldap_pvt.h"
382de962bdSlukem #include "lutil_ldap.h"
392de962bdSlukem 
402de962bdSlukem 
412de962bdSlukem typedef struct lutil_sasl_defaults_s {
422de962bdSlukem 	char *mech;
432de962bdSlukem 	char *realm;
442de962bdSlukem 	char *authcid;
452de962bdSlukem 	char *passwd;
462de962bdSlukem 	char *authzid;
472de962bdSlukem 	char **resps;
482de962bdSlukem 	int nresps;
492de962bdSlukem } lutilSASLdefaults;
502de962bdSlukem 
512de962bdSlukem 
522de962bdSlukem void
lutil_sasl_freedefs(void * defaults)532de962bdSlukem lutil_sasl_freedefs(
542de962bdSlukem 	void *defaults )
552de962bdSlukem {
562de962bdSlukem 	lutilSASLdefaults *defs = defaults;
572de962bdSlukem 
582de962bdSlukem 	assert( defs != NULL );
592de962bdSlukem 
602de962bdSlukem 	if (defs->mech) ber_memfree(defs->mech);
612de962bdSlukem 	if (defs->realm) ber_memfree(defs->realm);
622de962bdSlukem 	if (defs->authcid) ber_memfree(defs->authcid);
632de962bdSlukem 	if (defs->passwd) ber_memfree(defs->passwd);
642de962bdSlukem 	if (defs->authzid) ber_memfree(defs->authzid);
652de962bdSlukem 	if (defs->resps) ldap_charray_free(defs->resps);
662de962bdSlukem 
672de962bdSlukem 	ber_memfree(defs);
682de962bdSlukem }
692de962bdSlukem 
702de962bdSlukem void *
lutil_sasl_defaults(LDAP * ld,char * mech,char * realm,char * authcid,char * passwd,char * authzid)712de962bdSlukem lutil_sasl_defaults(
722de962bdSlukem 	LDAP *ld,
732de962bdSlukem 	char *mech,
742de962bdSlukem 	char *realm,
752de962bdSlukem 	char *authcid,
762de962bdSlukem 	char *passwd,
772de962bdSlukem 	char *authzid )
782de962bdSlukem {
792de962bdSlukem 	lutilSASLdefaults *defaults;
802de962bdSlukem 
812de962bdSlukem 	defaults = ber_memalloc( sizeof( lutilSASLdefaults ) );
822de962bdSlukem 
832de962bdSlukem 	if( defaults == NULL ) return NULL;
842de962bdSlukem 
852de962bdSlukem 	defaults->mech = mech ? ber_strdup(mech) : NULL;
862de962bdSlukem 	defaults->realm = realm ? ber_strdup(realm) : NULL;
872de962bdSlukem 	defaults->authcid = authcid ? ber_strdup(authcid) : NULL;
882de962bdSlukem 	defaults->passwd = passwd ? ber_strdup(passwd) : NULL;
892de962bdSlukem 	defaults->authzid = authzid ? ber_strdup(authzid) : NULL;
902de962bdSlukem 
912de962bdSlukem 	if( defaults->mech == NULL ) {
922de962bdSlukem 		ldap_get_option( ld, LDAP_OPT_X_SASL_MECH, &defaults->mech );
932de962bdSlukem 	}
942de962bdSlukem 	if( defaults->realm == NULL ) {
952de962bdSlukem 		ldap_get_option( ld, LDAP_OPT_X_SASL_REALM, &defaults->realm );
962de962bdSlukem 	}
972de962bdSlukem 	if( defaults->authcid == NULL ) {
982de962bdSlukem 		ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHCID, &defaults->authcid );
992de962bdSlukem 	}
1002de962bdSlukem 	if( defaults->authzid == NULL ) {
1012de962bdSlukem 		ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHZID, &defaults->authzid );
1022de962bdSlukem 	}
1032de962bdSlukem 	defaults->resps = NULL;
1042de962bdSlukem 	defaults->nresps = 0;
1052de962bdSlukem 
1062de962bdSlukem 	return defaults;
1072de962bdSlukem }
1082de962bdSlukem 
interaction(unsigned flags,sasl_interact_t * interact,lutilSASLdefaults * defaults)1092de962bdSlukem static int interaction(
1102de962bdSlukem 	unsigned flags,
1112de962bdSlukem 	sasl_interact_t *interact,
1122de962bdSlukem 	lutilSASLdefaults *defaults )
1132de962bdSlukem {
1142de962bdSlukem 	const char *dflt = interact->defresult;
1152de962bdSlukem 	char input[1024];
1162de962bdSlukem 
1172de962bdSlukem 	int noecho=0;
1182de962bdSlukem 	int challenge=0;
1192de962bdSlukem 
1202de962bdSlukem 	switch( interact->id ) {
1212de962bdSlukem 	case SASL_CB_GETREALM:
1222de962bdSlukem 		if( defaults ) dflt = defaults->realm;
1232de962bdSlukem 		break;
1242de962bdSlukem 	case SASL_CB_AUTHNAME:
1252de962bdSlukem 		if( defaults ) dflt = defaults->authcid;
1262de962bdSlukem 		break;
1272de962bdSlukem 	case SASL_CB_PASS:
1282de962bdSlukem 		if( defaults ) dflt = defaults->passwd;
1292de962bdSlukem 		noecho = 1;
1302de962bdSlukem 		break;
1312de962bdSlukem 	case SASL_CB_USER:
1322de962bdSlukem 		if( defaults ) dflt = defaults->authzid;
1332de962bdSlukem 		break;
1342de962bdSlukem 	case SASL_CB_NOECHOPROMPT:
1352de962bdSlukem 		noecho = 1;
1362de962bdSlukem 		challenge = 1;
1372de962bdSlukem 		break;
1382de962bdSlukem 	case SASL_CB_ECHOPROMPT:
1392de962bdSlukem 		challenge = 1;
1402de962bdSlukem 		break;
1412de962bdSlukem 	}
1422de962bdSlukem 
1432de962bdSlukem 	if( dflt && !*dflt ) dflt = NULL;
1442de962bdSlukem 
1452de962bdSlukem 	if( flags != LDAP_SASL_INTERACTIVE &&
1462de962bdSlukem 		( dflt || interact->id == SASL_CB_USER ) )
1472de962bdSlukem 	{
1482de962bdSlukem 		goto use_default;
1492de962bdSlukem 	}
1502de962bdSlukem 
1512de962bdSlukem 	if( flags == LDAP_SASL_QUIET ) {
1522de962bdSlukem 		/* don't prompt */
1532de962bdSlukem 		return LDAP_OTHER;
1542de962bdSlukem 	}
1552de962bdSlukem 
1562de962bdSlukem 	if( challenge ) {
1572de962bdSlukem 		if( interact->challenge ) {
1582de962bdSlukem 			fprintf( stderr, _("Challenge: %s\n"), interact->challenge );
1592de962bdSlukem 		}
1602de962bdSlukem 	}
1612de962bdSlukem 
1622de962bdSlukem 	if( dflt ) {
1632de962bdSlukem 		fprintf( stderr, _("Default: %s\n"), dflt );
1642de962bdSlukem 	}
1652de962bdSlukem 
1662de962bdSlukem 	snprintf( input, sizeof input, "%s: ",
1672de962bdSlukem 		interact->prompt ? interact->prompt : _("Interact") );
1682de962bdSlukem 
1692de962bdSlukem 	if( noecho ) {
1702de962bdSlukem 		interact->result = (char *) getpassphrase( input );
1712de962bdSlukem 		interact->len = interact->result
1722de962bdSlukem 			? strlen( interact->result ) : 0;
1732de962bdSlukem 
1742de962bdSlukem 	} else {
1752de962bdSlukem 		/* prompt user */
1762de962bdSlukem 		fputs( input, stderr );
1772de962bdSlukem 
1782de962bdSlukem 		/* get input */
1792de962bdSlukem 		interact->result = fgets( input, sizeof(input), stdin );
1802de962bdSlukem 
1812de962bdSlukem 		if( interact->result == NULL ) {
1822de962bdSlukem 			interact->len = 0;
1832de962bdSlukem 			return LDAP_UNAVAILABLE;
1842de962bdSlukem 		}
1852de962bdSlukem 
1862de962bdSlukem 		/* len of input */
1872de962bdSlukem 		interact->len = strlen(input);
1882de962bdSlukem 
1892de962bdSlukem 		if( interact->len > 0 && input[interact->len - 1] == '\n' ) {
1902de962bdSlukem 			/* input includes '\n', trim it */
1912de962bdSlukem 			interact->len--;
1922de962bdSlukem 			input[interact->len] = '\0';
1932de962bdSlukem 		}
1942de962bdSlukem 	}
1952de962bdSlukem 
1962de962bdSlukem 
1972de962bdSlukem 	if( interact->len > 0 ) {
1982de962bdSlukem 		/* duplicate */
1992de962bdSlukem 		char *p = (char *)interact->result;
2002de962bdSlukem 		ldap_charray_add(&defaults->resps, interact->result);
2012de962bdSlukem 		interact->result = defaults->resps[defaults->nresps++];
2022de962bdSlukem 
2032de962bdSlukem 		/* zap */
2042de962bdSlukem 		memset( p, '\0', interact->len );
2052de962bdSlukem 
2062de962bdSlukem 	} else {
2072de962bdSlukem use_default:
2082de962bdSlukem 		/* input must be empty */
2092de962bdSlukem 		interact->result = (dflt && *dflt) ? dflt : "";
2102de962bdSlukem 		interact->len = strlen( interact->result );
2112de962bdSlukem 	}
2122de962bdSlukem 
2132de962bdSlukem 	return LDAP_SUCCESS;
2142de962bdSlukem }
2152de962bdSlukem 
lutil_sasl_interact(LDAP * ld,unsigned flags,void * defaults,void * in)2162de962bdSlukem int lutil_sasl_interact(
2172de962bdSlukem 	LDAP *ld,
2182de962bdSlukem 	unsigned flags,
2192de962bdSlukem 	void *defaults,
2202de962bdSlukem 	void *in )
2212de962bdSlukem {
2222de962bdSlukem 	sasl_interact_t *interact = in;
2232de962bdSlukem 
2242de962bdSlukem 	if( flags == LDAP_SASL_INTERACTIVE ) {
2252de962bdSlukem 		fputs( _("SASL Interaction\n"), stderr );
2262de962bdSlukem 	}
2272de962bdSlukem 
2282de962bdSlukem 	while( interact->id != SASL_CB_LIST_END ) {
2292de962bdSlukem 		int rc = interaction( flags, interact, defaults );
2302de962bdSlukem 
2312de962bdSlukem 		if( rc )  return rc;
2322de962bdSlukem 		interact++;
2332de962bdSlukem 	}
2342de962bdSlukem 
2352de962bdSlukem 	return LDAP_SUCCESS;
2362de962bdSlukem }
2372de962bdSlukem #endif
238