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