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