1/*	$NetBSD: sasl.c,v 1.1.1.3 2010/12/12 15:22:11 adam Exp $	*/
2
3/* OpenLDAP: pkg/ldap/libraries/liblutil/sasl.c,v 1.22.2.5 2010/04/13 20:23:06 kurt Exp */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1998-2010 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
38typedef 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
49void
50lutil_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
67void *
68lutil_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
106static 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 {
204use_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
213int 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