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