]> git.sur5r.net Git - openldap/blob - contrib/ldapsasl/ldapdb.c
Sync ACL plugin security fix with HEAD
[openldap] / contrib / ldapsasl / ldapdb.c
1 /* $OpenLDAP$ */
2 /* SASL LDAP auxprop implementation
3  * Copyright (C) 2002,2003 Howard Chu, All rights reserved. <hyc@symas.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted only as authorized by the OpenLDAP
7  * Public License.
8  *
9  * A copy of this license is available in the file LICENSE in the
10  * top-level directory of the distribution or, alternatively, at
11  * <http://www.OpenLDAP.org/license.html>.
12  */
13
14 #include <config.h>
15
16 #include <stdio.h>
17
18 #include "sasl.h"
19 #include "saslutil.h"
20 #include "saslplug.h"
21
22 #define SASL_VERSION_FULL ((SASL_VERSION_MAJOR << 16) |\
23         (SASL_VERSION_MINOR << 8) |SASL_VERSION_STEP)
24
25 #include "plugin_common.h"
26
27 #include <ldap.h>
28
29 static char ldapdb[] = "ldapdb";
30
31 typedef struct ldapctx {
32         const char *uri;        /* URI of LDAP server */
33         struct berval id;       /* SASL authcid to bind as */
34         struct berval pw;       /* password for bind */
35         struct berval mech;     /* SASL mech */
36         int use_tls;            /* Issue StartTLS request? */
37 } ldapctx;
38
39 static int ldapdb_interact(LDAP *ld, unsigned flags __attribute__((unused)),
40         void *def, void *inter)
41 {
42         sasl_interact_t *in = inter;
43         ldapctx *ctx = def;
44         struct berval p;
45
46         for (;in->id != SASL_CB_LIST_END;in++)
47         {
48                 p.bv_val = NULL;
49                 switch(in->id)
50                 {
51                         case SASL_CB_GETREALM:
52                                 ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &p.bv_val);
53                                 if (p.bv_val) p.bv_len = strlen(p.bv_val);
54                                 break;          
55                         case SASL_CB_AUTHNAME:
56                                 p = ctx->id;
57                                 break;
58                         case SASL_CB_PASS:
59                                 p = ctx->pw;
60                                 break;
61                 }
62                 if (p.bv_val)
63                 {
64                         in->result = p.bv_val;
65                         in->len = p.bv_len;
66                 }
67         }
68         return LDAP_SUCCESS;
69 }
70
71 typedef struct connparm {
72         LDAP *ld;
73         LDAPControl c;
74         LDAPControl *ctrl[2];
75         struct berval *dn;
76 } connparm;
77
78 static int ldapdb_connect(ldapctx *ctx, sasl_server_params_t *sparams,
79         const char *user, unsigned ulen, connparm *cp)
80 {
81     int i;
82     char *authzid;
83
84     if((i=ldap_initialize(&cp->ld, ctx->uri))) {
85         return i;
86     }
87
88     authzid = sparams->utils->malloc(ulen + sizeof("u:"));
89     if (!authzid) {
90         return LDAP_NO_MEMORY;
91     } 
92     strcpy(authzid, "u:");
93     strcpy(authzid+2, user);
94     cp->c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
95     cp->c.ldctl_value.bv_val = authzid;
96     cp->c.ldctl_value.bv_len = ulen + 2;
97     cp->c.ldctl_iscritical = 1;
98
99     i = LDAP_VERSION3;
100     ldap_set_option(cp->ld, LDAP_OPT_PROTOCOL_VERSION, &i);
101
102     /* If TLS is set and it fails, continue or bail out as requested */
103     if (ctx->use_tls && (i=ldap_start_tls_s(cp->ld, NULL, NULL)) != LDAP_SUCCESS
104         && ctx->use_tls > 1) {
105         sparams->utils->free(authzid);
106         return i;
107     }
108
109     i = ldap_sasl_interactive_bind_s(cp->ld, NULL, ctx->mech.bv_val, NULL,
110         NULL, LDAP_SASL_QUIET, ldapdb_interact, ctx);
111     if (i != LDAP_SUCCESS) {
112         sparams->utils->free(authzid);
113         return i;
114     }
115     
116     cp->ctrl[0] = &cp->c;
117     cp->ctrl[1] = NULL;
118     i = ldap_whoami_s(cp->ld, &cp->dn, cp->ctrl, NULL);
119     if (i == LDAP_SUCCESS && cp->dn) {
120         if (!cp->dn->bv_val || strncmp(cp->dn->bv_val, "dn:", 3)) {
121             ber_bvfree(cp->dn);
122             cp->dn = NULL;
123             i = LDAP_INVALID_SYNTAX;
124         } else {
125             cp->c.ldctl_value = *(cp->dn);
126         }
127     }
128     sparams->utils->free(authzid);
129     return i;
130 }
131
132 static void ldapdb_auxprop_lookup(void *glob_context,
133                                   sasl_server_params_t *sparams,
134                                   unsigned flags,
135                                   const char *user,
136                                   unsigned ulen)
137 {
138     ldapctx *ctx = glob_context;
139     connparm cp;
140     int ret, i, n, *aindx;
141     const struct propval *pr;
142     struct berval **bvals;
143     LDAPMessage *msg, *res;
144     char **attrs = NULL;
145     
146     if(!ctx || !sparams || !user) return;
147
148     pr = sparams->utils->prop_get(sparams->propctx);
149     if(!pr) return;
150
151     /* count how many attrs to fetch */
152     for(i = 0, n = 0; pr[i].name; i++) {
153         if(pr[i].name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID))
154             continue;
155         if(pr[i].values && !(flags & SASL_AUXPROP_OVERRIDE))
156             continue;
157         n++;
158     }
159     /* nothing to do, bail out */
160     if (!n) return;
161
162     /* alloc an array of attr names for search, and index to the props */
163     attrs = sparams->utils->malloc((n+1)*sizeof(char *)*2);
164     if (!attrs) return;
165
166     aindx = (int *)(attrs + n + 1);
167
168     /* copy attr list */
169     for (i=0, n=0; pr[i].name; i++) {
170         if(pr[i].name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID))
171             continue;
172         if(pr[i].values && !(flags & SASL_AUXPROP_OVERRIDE))
173             continue;
174         attrs[n] = (char *)pr[i].name;
175         if (pr[i].name[0] == '*') attrs[n]++;
176         aindx[n] = i;
177         n++;
178     }
179     attrs[n] = NULL;
180
181     if(ldapdb_connect(ctx, sparams, user, ulen, &cp)) {
182         goto done;
183     }
184
185     ret = ldap_search_ext_s(cp.ld, cp.dn->bv_val+3, LDAP_SCOPE_BASE,
186         "(objectclass=*)", attrs, 0, cp.ctrl, NULL, NULL, 1, &res);
187     ber_bvfree(cp.dn);
188
189     if (ret != LDAP_SUCCESS) goto done;
190
191     for(msg=ldap_first_message(cp.ld, res); msg; msg=ldap_next_message(cp.ld, msg))
192     {
193         if (ldap_msgtype(msg) != LDAP_RES_SEARCH_ENTRY) continue;
194         for (i=0; i<n; i++)
195         {
196             bvals = ldap_get_values_len(cp.ld, msg, attrs[i]);
197             if (!bvals) continue;
198             if (pr[aindx[i]].values)
199                 sparams->utils->prop_erase(sparams->propctx, pr[aindx[i]].name);
200             sparams->utils->prop_set(sparams->propctx, pr[aindx[i]].name,
201                                  bvals[0]->bv_val, bvals[0]->bv_len);
202             ber_bvecfree(bvals);
203         }
204     }
205     ldap_msgfree(res);
206
207  done:
208     if(attrs) sparams->utils->free(attrs);
209     if(cp.ld) ldap_unbind(cp.ld);
210 }
211
212 #if SASL_VERSION_FULL >= 0x020110
213 static int ldapdb_auxprop_store(void *glob_context,
214                                   sasl_server_params_t *sparams,
215                                   struct propctx *prctx,
216                                   const char *user,
217                                   unsigned ulen)
218 {
219     ldapctx *ctx = glob_context;
220     connparm cp;
221     const struct propval *pr;
222     int i, n;
223     LDAPMod **mods;
224
225     /* just checking if we are enabled */
226     if (!prctx) return SASL_OK;
227
228     if (!sparams || !user) return SASL_BADPARAM;
229
230     pr = sparams->utils->prop_get(prctx);
231     if (!pr) return SASL_BADPARAM;
232
233     for (n=0; pr[n].name; n++);
234     if (!n) return SASL_BADPARAM;
235
236     mods = sparams->utils->malloc((n+1) * sizeof(LDAPMod*) + n * sizeof(LDAPMod));
237     if (!mods) return SASL_NOMEM;
238
239     if((i=ldapdb_connect(ctx, sparams, user, ulen, &cp)) == 0) {
240
241         for (i=0; i<n; i++) {
242             mods[i] = (LDAPMod *)((char *)(mods+n+1) + i * sizeof(LDAPMod));
243             mods[i]->mod_op = LDAP_MOD_REPLACE;
244             mods[i]->mod_type = (char *)pr[i].name;
245             mods[i]->mod_values = (char **)pr[i].values;
246         }
247         mods[i] = NULL;
248
249         i = ldap_modify_ext_s(cp.ld, cp.dn->bv_val+3, mods, cp.ctrl, NULL);
250         ber_bvfree(cp.dn);
251     }
252
253     sparams->utils->free(mods);
254
255     if (i) {
256         sparams->utils->seterror(sparams->utils->conn, 0,
257             ldap_err2string(i));
258         if (i == LDAP_NO_MEMORY) i = SASL_NOMEM;
259         else i = SASL_FAIL;
260     }
261     if (cp.ld) ldap_unbind(cp.ld);
262     return i;
263 }
264 #endif /* SASL_VERSION_FULL >= 2.1.16 */
265
266 static void ldapdb_auxprop_free(void *glob_ctx, const sasl_utils_t *utils)
267 {
268         utils->free(glob_ctx);
269 }
270
271 static sasl_auxprop_plug_t ldapdb_auxprop_plugin = {
272     0,           /* Features */
273     0,           /* spare */
274     NULL,        /* glob_context */
275     ldapdb_auxprop_free,        /* auxprop_free */
276     ldapdb_auxprop_lookup,      /* auxprop_lookup */
277     ldapdb,    /* name */
278 #if SASL_VERSION_FULL >=0x020110
279     ldapdb_auxprop_store        /* spare if <2.1.16*/
280 #else
281     NULL
282 #endif
283 };
284
285 static int ldapdb_auxprop_plug_init(const sasl_utils_t *utils,
286                              int max_version,
287                              int *out_version,
288                              sasl_auxprop_plug_t **plug,
289                              const char *plugname __attribute__((unused))) 
290 {
291     ldapctx tmp, *p;
292     const char *s;
293     unsigned len;
294
295     if(!out_version || !plug) return SASL_BADPARAM;
296
297     if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
298     
299     memset(&tmp, 0, sizeof(tmp));
300
301     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_uri", &tmp.uri, NULL);
302     if(!tmp.uri) return SASL_BADPARAM;
303
304     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_id",
305         (const char **)&tmp.id.bv_val, &len);
306     tmp.id.bv_len = len;
307     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_pw",
308         (const char **)&tmp.pw.bv_val, &len);
309     tmp.pw.bv_len = len;
310     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_mech",
311         (const char **)&tmp.mech.bv_val, &len);
312     tmp.mech.bv_len = len;
313     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_starttls", &s, NULL);
314     if (s)
315     {
316         if (!strcasecmp(s, "demand")) tmp.use_tls = 2;
317         else if (!strcasecmp(s, "try")) tmp.use_tls = 1;
318     }
319     utils->getopt(utils->getopt_context, ldapdb, "ldapdb_rc", &s, &len);
320     if (s)
321     {
322         char *str = utils->malloc(sizeof("LDAPRC=")+len);
323         if (!str) return SASL_NOMEM;
324         strcpy( str, "LDAPRC=" );
325         strcpy( str + sizeof("LDAPRC=")-1, s );
326         if (putenv(str))
327         {
328             utils->free(str);
329             return SASL_NOMEM;
330         }
331     }
332
333     p = utils->malloc(sizeof(ldapctx));
334     if (!p) return SASL_NOMEM;
335     *p = tmp;
336     ldapdb_auxprop_plugin.glob_context = p;
337
338     *out_version = SASL_AUXPROP_PLUG_VERSION;
339
340     *plug = &ldapdb_auxprop_plugin;
341
342     return SASL_OK;
343 }
344
345 SASL_AUXPROP_PLUG_INIT( ldapdb )
346