]> git.sur5r.net Git - openldap/blob - libraries/liblutil/sasl.c
01ac055ce98f5182fc7d97bfaf4b0af8340596cc
[openldap] / libraries / liblutil / sasl.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2017 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