xref: /netbsd-src/external/bsd/openldap/dist/libraries/liblutil/sasl.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: sasl.c,v 1.3 2021/08/14 16:14:58 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2021 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.3 2021/08/14 16:14:58 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
lutil_sasl_freedefs(void * defaults)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 *
lutil_sasl_defaults(LDAP * ld,char * mech,char * realm,char * authcid,char * passwd,char * authzid)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 
interaction(unsigned flags,sasl_interact_t * interact,lutilSASLdefaults * defaults)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 
lutil_sasl_interact(LDAP * ld,unsigned flags,void * defaults,void * in)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