1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2011 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
36typedef 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
47void
48lutil_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
65void *
66lutil_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
104static 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 {
202use_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
211int 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