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