Home | History | Annotate | Line # | Download | only in liblutil
      1 /*	$NetBSD: sasl.c,v 1.4 2025/09/05 21:16:23 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1998-2024 The OpenLDAP Foundation.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted only as authorized by the OpenLDAP
     11  * Public License.
     12  *
     13  * A copy of this license is available in the file LICENSE in the
     14  * top-level directory of the distribution or, alternatively, at
     15  * <http://www.OpenLDAP.org/license.html>.
     16  */
     17 
     18 #include <sys/cdefs.h>
     19 __RCSID("$NetBSD: sasl.c,v 1.4 2025/09/05 21:16:23 christos Exp $");
     20 
     21 #include "portable.h"
     22 
     23 #ifdef HAVE_CYRUS_SASL
     24 
     25 #include <stdio.h>
     26 #include <ac/stdlib.h>
     27 #include <ac/string.h>
     28 #include <ac/unistd.h>
     29 
     30 #ifdef HAVE_SASL_SASL_H
     31 #include <sasl/sasl.h>
     32 #else
     33 #include <sasl.h>
     34 #endif
     35 
     36 #include <ldap.h>
     37 #include "ldap_pvt.h"
     38 #include "lutil_ldap.h"
     39 
     40 
     41 typedef struct lutil_sasl_defaults_s {
     42 	char *mech;
     43 	char *realm;
     44 	char *authcid;
     45 	char *passwd;
     46 	char *authzid;
     47 	char **resps;
     48 	int nresps;
     49 } lutilSASLdefaults;
     50 
     51 
     52 void
     53 lutil_sasl_freedefs(
     54 	void *defaults )
     55 {
     56 	lutilSASLdefaults *defs = defaults;
     57 
     58 	assert( defs != NULL );
     59 
     60 	if (defs->mech) ber_memfree(defs->mech);
     61 	if (defs->realm) ber_memfree(defs->realm);
     62 	if (defs->authcid) ber_memfree(defs->authcid);
     63 	if (defs->passwd) ber_memfree(defs->passwd);
     64 	if (defs->authzid) ber_memfree(defs->authzid);
     65 	if (defs->resps) ldap_charray_free(defs->resps);
     66 
     67 	ber_memfree(defs);
     68 }
     69 
     70 void *
     71 lutil_sasl_defaults(
     72 	LDAP *ld,
     73 	char *mech,
     74 	char *realm,
     75 	char *authcid,
     76 	char *passwd,
     77 	char *authzid )
     78 {
     79 	lutilSASLdefaults *defaults;
     80 
     81 	defaults = ber_memalloc( sizeof( lutilSASLdefaults ) );
     82 
     83 	if( defaults == NULL ) return NULL;
     84 
     85 	defaults->mech = mech ? ber_strdup(mech) : NULL;
     86 	defaults->realm = realm ? ber_strdup(realm) : NULL;
     87 	defaults->authcid = authcid ? ber_strdup(authcid) : NULL;
     88 	defaults->passwd = passwd ? ber_strdup(passwd) : NULL;
     89 	defaults->authzid = authzid ? ber_strdup(authzid) : NULL;
     90 
     91 	if( defaults->mech == NULL ) {
     92 		ldap_get_option( ld, LDAP_OPT_X_SASL_MECH, &defaults->mech );
     93 	}
     94 	if( defaults->realm == NULL ) {
     95 		ldap_get_option( ld, LDAP_OPT_X_SASL_REALM, &defaults->realm );
     96 	}
     97 	if( defaults->authcid == NULL ) {
     98 		ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHCID, &defaults->authcid );
     99 	}
    100 	if( defaults->authzid == NULL ) {
    101 		ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHZID, &defaults->authzid );
    102 	}
    103 	defaults->resps = NULL;
    104 	defaults->nresps = 0;
    105 
    106 	return defaults;
    107 }
    108 
    109 static int interaction(
    110 	unsigned flags,
    111 	sasl_interact_t *interact,
    112 	lutilSASLdefaults *defaults )
    113 {
    114 	const char *dflt = interact->defresult;
    115 	char input[1024];
    116 
    117 	int noecho=0;
    118 	int challenge=0;
    119 
    120 	switch( interact->id ) {
    121 	case SASL_CB_GETREALM:
    122 		if( defaults ) dflt = defaults->realm;
    123 		break;
    124 	case SASL_CB_AUTHNAME:
    125 		if( defaults ) dflt = defaults->authcid;
    126 		break;
    127 	case SASL_CB_PASS:
    128 		if( defaults ) dflt = defaults->passwd;
    129 		noecho = 1;
    130 		break;
    131 	case SASL_CB_USER:
    132 		if( defaults ) dflt = defaults->authzid;
    133 		break;
    134 	case SASL_CB_NOECHOPROMPT:
    135 		noecho = 1;
    136 		challenge = 1;
    137 		break;
    138 	case SASL_CB_ECHOPROMPT:
    139 		challenge = 1;
    140 		break;
    141 	}
    142 
    143 	if( dflt && !*dflt ) dflt = NULL;
    144 
    145 	if( flags != LDAP_SASL_INTERACTIVE &&
    146 		( dflt || interact->id == SASL_CB_USER ) )
    147 	{
    148 		goto use_default;
    149 	}
    150 
    151 	if( flags == LDAP_SASL_QUIET ) {
    152 		/* don't prompt */
    153 		return LDAP_OTHER;
    154 	}
    155 
    156 	if( challenge ) {
    157 		if( interact->challenge ) {
    158 			fprintf( stderr, _("Challenge: %s\n"), interact->challenge );
    159 		}
    160 	}
    161 
    162 	if( dflt ) {
    163 		fprintf( stderr, _("Default: %s\n"), dflt );
    164 	}
    165 
    166 	snprintf( input, sizeof input, "%s: ",
    167 		interact->prompt ? interact->prompt : _("Interact") );
    168 
    169 	if( noecho ) {
    170 		interact->result = (char *) getpassphrase( input );
    171 		interact->len = interact->result
    172 			? strlen( interact->result ) : 0;
    173 
    174 	} else {
    175 		/* prompt user */
    176 		fputs( input, stderr );
    177 
    178 		/* get input */
    179 		interact->result = fgets( input, sizeof(input), stdin );
    180 
    181 		if( interact->result == NULL ) {
    182 			interact->len = 0;
    183 			return LDAP_UNAVAILABLE;
    184 		}
    185 
    186 		/* len of input */
    187 		interact->len = strlen(input);
    188 
    189 		if( interact->len > 0 && input[interact->len - 1] == '\n' ) {
    190 			/* input includes '\n', trim it */
    191 			interact->len--;
    192 			input[interact->len] = '\0';
    193 		}
    194 	}
    195 
    196 
    197 	if( interact->len > 0 ) {
    198 		/* duplicate */
    199 		char *p = (char *)interact->result;
    200 		ldap_charray_add(&defaults->resps, interact->result);
    201 		interact->result = defaults->resps[defaults->nresps++];
    202 
    203 		/* zap */
    204 		memset( p, '\0', interact->len );
    205 
    206 	} else {
    207 use_default:
    208 		/* input must be empty */
    209 		interact->result = (dflt && *dflt) ? dflt : "";
    210 		interact->len = strlen( interact->result );
    211 	}
    212 
    213 	return LDAP_SUCCESS;
    214 }
    215 
    216 int lutil_sasl_interact(
    217 	LDAP *ld,
    218 	unsigned flags,
    219 	void *defaults,
    220 	void *in )
    221 {
    222 	sasl_interact_t *interact = in;
    223 
    224 	if( flags == LDAP_SASL_INTERACTIVE ) {
    225 		fputs( _("SASL Interaction\n"), stderr );
    226 	}
    227 
    228 	while( interact->id != SASL_CB_LIST_END ) {
    229 		int rc = interaction( flags, interact, defaults );
    230 
    231 		if( rc )  return rc;
    232 		interact++;
    233 	}
    234 
    235 	return LDAP_SUCCESS;
    236 }
    237 #endif
    238