]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/amd/amd/info_ldap.c
This commit was generated by cvs2svn to compensate for changes in r50764,
[FreeBSD/FreeBSD.git] / contrib / amd / amd / info_ldap.c
1 /*
2  * Copyright (c) 1997-1998 Erez Zadok
3  * Copyright (c) 1989 Jan-Simon Pendry
4  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
5  * Copyright (c) 1989 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Jan-Simon Pendry at Imperial College, London.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgment:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *      %W% (Berkeley) %G%
40  *
41  * $Id: info_ldap.c,v 1.1.1.1 1998/11/05 02:04:49 ezk Exp $
42  *
43  */
44
45
46 /*
47  * Get info from LDAP (Lightweight Directory Access Protocol)
48  * LDAP Home Page: http://www.umich.edu/~rsug/ldap/
49  */
50
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif /* HAVE_CONFIG_H */
54 #include <am_defs.h>
55 #include <amd.h>
56
57
58 /*
59  * MACROS:
60  */
61 #define AMD_LDAP_TYPE           "ldap"
62 /* Time to live for an LDAP cached in an mnt_map */
63 #define AMD_LDAP_TTL            3600
64 #define AMD_LDAP_RETRIES        5
65 #define AMD_LDAP_HOST           "ldap"
66 #ifndef LDAP_PORT
67 # define LDAP_PORT              389
68 #endif /* LDAP_PORT */
69
70 /* How timestamps are searched */
71 #define AMD_LDAP_TSFILTER "(&(objectClass=amdmapTimestamp)(amdmapName=%s))"
72 /* How maps are searched */
73 #define AMD_LDAP_FILTER "(&(objectClass=amdmap)(amdmapName=%s)(amdmapKey=%s))"
74 /* How timestamps are stored */
75 #define AMD_LDAP_TSATTR "amdmaptimestamp"
76 /* How maps are stored */
77 #define AMD_LDAP_ATTR "amdmapvalue"
78
79 /*
80  * TYPEDEFS:
81  */
82 typedef struct ald_ent ALD;
83 typedef struct cr_ent CR;
84 typedef struct he_ent HE;
85
86 /*
87  * STRUCTURES:
88  */
89 struct ald_ent {
90   LDAP *ldap;
91   HE *hostent;
92   CR *credentials;
93   time_t timestamp;
94 };
95
96 struct cr_ent {
97   char *who;
98   char *pw;
99   int method;
100 };
101
102 struct he_ent {
103   char *host;
104   int port;
105   struct he_ent *next;
106 };
107
108 /*
109  * FORWARD DECLARATIONS:
110  */
111 static int amu_ldap_rebind(ALD *a);
112 static int get_ldap_timestamp(LDAP *ld, char *map, time_t *ts);
113
114
115 /*
116  * FUNCTIONS:
117  */
118
119 static void
120 he_free(HE *h)
121 {
122   XFREE(h->host);
123   if (h->next != NULL)
124     he_free(h->next);
125   XFREE(h);
126 }
127
128
129 static HE *
130 string2he(char *s)
131 {
132   char *c, *p;
133   HE *new, *old = NULL;
134
135   if (s == NULL)
136     return (NULL);
137   for (p = s; p; p = strchr(p, ',')) {
138     if (old != NULL) {
139       new = (HE *) xmalloc(sizeof(HE));
140       old->next = new;
141       old = new;
142     } else {
143       old = (HE *) xmalloc(sizeof(HE));
144       old->next = NULL;
145     }
146     c = strchr(p, ':');
147     if (c) {                    /* Host and port */
148       *c++ = '\0';
149       old->host = strdup(p);
150       old->port = atoi(c);
151     } else
152       old->host = strdup(p);
153
154   }
155   return (old);
156 }
157
158
159 static void
160 cr_free(CR *c)
161 {
162   XFREE(c->who);
163   XFREE(c->pw);
164   XFREE(c);
165 }
166
167
168 static void
169 ald_free(ALD *a)
170 {
171   he_free(a->hostent);
172   cr_free(a->credentials);
173   if (a->ldap != NULL)
174     ldap_unbind(a->ldap);
175   XFREE(a);
176 }
177
178
179 int
180 amu_ldap_init(mnt_map *m, char *map, time_t *ts)
181 {
182   ALD *aldh;
183   CR *creds;
184
185   if (!STREQ(gopt.map_type, AMD_LDAP_TYPE)) {
186     return (ENOENT);
187   }
188 #ifdef DEBUG
189   else {
190     dlog("Map %s is ldap\n", map);
191   }
192 #endif /* DEBUG */
193
194   aldh = (ALD *) xmalloc(sizeof(ALD));
195   creds = (CR *) xmalloc(sizeof(CR));
196
197   aldh->hostent = string2he(gopt.ldap_hostports);
198   if (aldh->hostent == NULL) {
199     plog(XLOG_USER, "Unable to parse hostport %s for ldap map %s",
200          gopt.ldap_hostports, map);
201     return (ENOENT);
202   }
203   creds->who = "";
204   creds->pw = "";
205   creds->method = LDAP_AUTH_SIMPLE;
206   aldh->credentials = creds;
207   aldh->timestamp = 0;
208 #ifdef DEBUG
209   dlog("Trying for %s:%d\n", aldh->hostent->host, aldh->hostent->port);
210 #endif /* DEBUG */
211   if (amu_ldap_rebind(aldh)) {
212     ald_free(aldh);
213     return (ENOENT);
214   }
215   m->map_data = (void *) aldh;
216 #ifdef DEBUG
217   dlog("Bound to %s:%d\n", aldh->hostent->host, aldh->hostent->port);
218 #endif /* DEBUG */
219   if (get_ldap_timestamp(aldh->ldap, map, ts))
220     return (ENOENT);
221 #ifdef DEBUG
222   dlog("Got timestamp for map %s: %d\n", map, *ts);
223 #endif /* DEBUG */
224
225   return (0);
226 }
227
228
229 static int
230 amu_ldap_rebind(ALD *a)
231 {
232   LDAP *ld;
233   HE *h;
234   CR *c = a->credentials;
235   time_t now = clocktime();
236
237   if (a->ldap != NULL) {
238     if ((a->timestamp - now) > AMD_LDAP_TTL) {
239 #ifdef DEBUG
240       dlog("Reestablishing ldap connection\n");
241 #endif /* DEBUG */
242       ldap_unbind(a->ldap);
243       a->timestamp = now;
244     } else
245       return (0);
246   }
247
248   while (TRUE) {
249     for (h = a->hostent; h != NULL; h = h->next) {
250       if ((ld = ldap_open(h->host, h->port)) == NULL) {
251         plog(XLOG_WARNING, "Unable to ldap_open to %s:%d\n", h->host, h->port);
252         break;
253       }
254       if (ldap_bind_s(ld, c->who, c->pw, c->method) != LDAP_SUCCESS) {
255         plog(XLOG_WARNING, "Unable to ldap_bind to %s:%d as %s\n",
256              h->host, h->port, c->who);
257         break;
258       }
259       if (gopt.ldap_cache_seconds > 0) {
260         ldap_enable_cache(ld, gopt.ldap_cache_seconds, gopt.ldap_cache_maxmem);
261         a->ldap = ld;
262         a->timestamp = now;
263         return (0);
264       }
265     }
266     plog(XLOG_WARNING, "Exhausted list of ldap servers, looping.\n");
267   }
268
269   plog(XLOG_USER, "Unable to (re)bind to any ldap hosts\n");
270   return (ENOENT);
271 }
272
273
274 static int
275 get_ldap_timestamp(LDAP * ld, char *map, time_t *ts)
276 {
277   struct timeval tv;
278   char **vals, *end;
279   char filter[MAXPATHLEN];
280   int i, err, nentries = 0;
281   LDAPMessage *res, *entry;
282
283   tv.tv_sec = 3;
284   tv.tv_usec = 0;
285   sprintf(filter, AMD_LDAP_TSFILTER, map);
286 #ifdef DEBUG
287   dlog("Getting timestamp for map %s\n", map);
288   dlog("Filter is: %s\n", filter);
289   dlog("Base is: %s\n", gopt.ldap_base);
290 #endif /* DEBUG */
291   for (i = 0; i < AMD_LDAP_RETRIES; i++) {
292     err = ldap_search_st(ld,
293                          gopt.ldap_base,
294                          LDAP_SCOPE_SUBTREE,
295                          filter,
296                          0,
297                          0,
298                          &tv,
299                          &res);
300     if (err == LDAP_SUCCESS)
301       break;
302     dlog("Timestamp search timed out, trying again...\n");
303   }
304
305   if (err != LDAP_SUCCESS) {
306     *ts = 0;
307     plog(XLOG_USER, "LDAP timestamp search failed: %s\n",
308          ldap_err2string(ld->ld_errno));
309     return (ENOENT);
310   }
311
312   nentries = ldap_count_entries(ld, res);
313   if (nentries == 0) {
314     plog(XLOG_USER, "No timestamp entry for map %s\n", map);
315     *ts = 0;
316     ldap_msgfree(res);
317     return (ENOENT);
318   }
319
320   entry = ldap_first_entry(ld, res);
321   vals = ldap_get_values(ld, entry, AMD_LDAP_TSATTR);
322   if (ldap_count_values(vals) == 0) {
323     plog(XLOG_USER, "Missing timestamp value for map %s\n", map);
324     *ts = 0;
325     ldap_value_free(vals);
326     ldap_msgfree(res);
327     ldap_msgfree(entry);
328     return (ENOENT);
329   }
330 #ifdef DEBUG
331   dlog("TS value is:%s:\n", vals[0]);
332 #endif /* DEBUG */
333
334   if (vals[0]) {
335     *ts = (time_t) strtol(vals[0], &end, 10);
336     if (end == vals[0]) {
337       plog(XLOG_USER, "Unable to decode ldap timestamp %s for map %s\n",
338            vals[0], map);
339       err = ENOENT;
340     }
341     if (!*ts > 0) {
342       plog(XLOG_USER, "Nonpositive timestamp %d for map %s\n",
343            *ts, map);
344       err = ENOENT;
345     }
346   } else {
347     plog(XLOG_USER, "Empty timestamp value for map %s\n", map);
348     *ts = 0;
349     err = ENOENT;
350   }
351
352   ldap_value_free(vals);
353   ldap_msgfree(res);
354   ldap_msgfree(entry);
355 #ifdef DEBUG
356   dlog("The timestamp for %s is %d (err=%d)\n", map, *ts, err);
357 #endif /* DEBUG */
358   return (err);
359 }
360
361
362 int
363 amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts)
364 {
365   char **vals, filter[MAXPATHLEN];
366   struct timeval tv;
367   int i, err, nvals = 0, nentries = 0;
368   LDAPMessage *entry, *res;
369   ALD *a = (ALD *) (m->map_data);
370
371   tv.tv_sec = 2;
372   tv.tv_usec = 0;
373   if (a == NULL) {
374     plog(XLOG_USER, "LDAP panic: no map data\n");
375     return (EIO);
376   }
377   if (amu_ldap_rebind(a))       /* Check that's the handle is still valid */
378     return (ENOENT);
379
380   sprintf(filter, AMD_LDAP_FILTER, map, key);
381 #ifdef DEBUG
382   dlog("Search with filter: %s\n", filter);
383 #endif /* DEBUG */
384   for (i = 0; i < AMD_LDAP_RETRIES; i++) {
385     err = ldap_search_st(a->ldap,
386                          gopt.ldap_base,
387                          LDAP_SCOPE_SUBTREE,
388                          filter,
389                          0,
390                          0,
391                          &tv,
392                          &res);
393     if (err == LDAP_SUCCESS)
394       break;
395   }
396
397   switch (err) {
398   case LDAP_SUCCESS:
399     break;
400   case LDAP_NO_SUCH_OBJECT:
401 #ifdef DEBUG
402     dlog("No object\n");
403 #endif /* DEBUG */
404     ldap_msgfree(res);
405     return (ENOENT);
406   default:
407     plog(XLOG_USER, "LDAP search failed: %s\n",
408          ldap_err2string(a->ldap->ld_errno));
409     ldap_msgfree(res);
410     return (EIO);
411   }
412
413   nentries = ldap_count_entries(a->ldap, res);
414 #ifdef DEBUG
415   dlog("Search found %d entries\n", nentries);
416 #endif /* DEBUG */
417   if (nentries == 0) {
418     ldap_msgfree(res);
419     return (ENOENT);
420   }
421   entry = ldap_first_entry(a->ldap, res);
422   vals = ldap_get_values(a->ldap, entry, AMD_LDAP_ATTR);
423   nvals = ldap_count_values(vals);
424   if (nvals == 0) {
425     plog(XLOG_USER, "Missing value for %s in map %s\n", key, map);
426     ldap_value_free(vals);
427     ldap_msgfree(res);
428     ldap_msgfree(entry);
429     return (EIO);
430   }
431 #ifdef DEBUG
432   dlog("Map %s, %s => %s\n", map, key, vals[0]);
433 #endif /* DEBUG */
434   if (vals[0]) {
435     *pval = strdup(vals[0]);
436     err = 0;
437   } else {
438     plog(XLOG_USER, "Empty value for %s in map %s\n", key, map);
439     err = ENOENT;
440   }
441   ldap_msgfree(res);
442   ldap_msgfree(entry);
443   ldap_value_free(vals);
444
445   return (err);
446 }
447
448
449 int
450 amu_ldap_mtime(mnt_map *m, char *map, time_t *ts)
451 {
452   ALD *aldh = (ALD *) (m->map_data);
453
454   if (aldh == NULL) {
455     dlog("LDAP panic: unable to find map data\n");
456     return (ENOENT);
457   }
458   if (amu_ldap_rebind(aldh)) {
459     return (ENOENT);
460   }
461   if (get_ldap_timestamp(aldh->ldap, map, ts)) {
462     return (ENOENT);
463   }
464   return (0);
465 }