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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
41 * $Id: info_ldap.c,v 1.1.1.1 1998/11/05 02:04:49 ezk Exp $
47 * Get info from LDAP (Lightweight Directory Access Protocol)
48 * LDAP Home Page: http://www.umich.edu/~rsug/ldap/
53 #endif /* HAVE_CONFIG_H */
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"
67 # define LDAP_PORT 389
68 #endif /* LDAP_PORT */
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"
82 typedef struct ald_ent ALD;
83 typedef struct cr_ent CR;
84 typedef struct he_ent HE;
109 * FORWARD DECLARATIONS:
111 static int amu_ldap_rebind(ALD *a);
112 static int get_ldap_timestamp(LDAP *ld, char *map, time_t *ts);
133 HE *new, *old = NULL;
137 for (p = s; p; p = strchr(p, ',')) {
139 new = (HE *) xmalloc(sizeof(HE));
143 old = (HE *) xmalloc(sizeof(HE));
147 if (c) { /* Host and port */
149 old->host = strdup(p);
152 old->host = strdup(p);
172 cr_free(a->credentials);
174 ldap_unbind(a->ldap);
180 amu_ldap_init(mnt_map *m, char *map, time_t *ts)
185 if (!STREQ(gopt.map_type, AMD_LDAP_TYPE)) {
190 dlog("Map %s is ldap\n", map);
194 aldh = (ALD *) xmalloc(sizeof(ALD));
195 creds = (CR *) xmalloc(sizeof(CR));
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);
205 creds->method = LDAP_AUTH_SIMPLE;
206 aldh->credentials = creds;
209 dlog("Trying for %s:%d\n", aldh->hostent->host, aldh->hostent->port);
211 if (amu_ldap_rebind(aldh)) {
215 m->map_data = (void *) aldh;
217 dlog("Bound to %s:%d\n", aldh->hostent->host, aldh->hostent->port);
219 if (get_ldap_timestamp(aldh->ldap, map, ts))
222 dlog("Got timestamp for map %s: %d\n", map, *ts);
230 amu_ldap_rebind(ALD *a)
234 CR *c = a->credentials;
235 time_t now = clocktime();
237 if (a->ldap != NULL) {
238 if ((a->timestamp - now) > AMD_LDAP_TTL) {
240 dlog("Reestablishing ldap connection\n");
242 ldap_unbind(a->ldap);
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);
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);
259 if (gopt.ldap_cache_seconds > 0) {
260 ldap_enable_cache(ld, gopt.ldap_cache_seconds, gopt.ldap_cache_maxmem);
266 plog(XLOG_WARNING, "Exhausted list of ldap servers, looping.\n");
269 plog(XLOG_USER, "Unable to (re)bind to any ldap hosts\n");
275 get_ldap_timestamp(LDAP * ld, char *map, time_t *ts)
279 char filter[MAXPATHLEN];
280 int i, err, nentries = 0;
281 LDAPMessage *res, *entry;
285 sprintf(filter, AMD_LDAP_TSFILTER, map);
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);
291 for (i = 0; i < AMD_LDAP_RETRIES; i++) {
292 err = ldap_search_st(ld,
300 if (err == LDAP_SUCCESS)
302 dlog("Timestamp search timed out, trying again...\n");
305 if (err != LDAP_SUCCESS) {
307 plog(XLOG_USER, "LDAP timestamp search failed: %s\n",
308 ldap_err2string(ld->ld_errno));
312 nentries = ldap_count_entries(ld, res);
314 plog(XLOG_USER, "No timestamp entry for map %s\n", map);
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);
325 ldap_value_free(vals);
331 dlog("TS value is:%s:\n", 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",
342 plog(XLOG_USER, "Nonpositive timestamp %d for map %s\n",
347 plog(XLOG_USER, "Empty timestamp value for map %s\n", map);
352 ldap_value_free(vals);
356 dlog("The timestamp for %s is %d (err=%d)\n", map, *ts, err);
363 amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts)
365 char **vals, filter[MAXPATHLEN];
367 int i, err, nvals = 0, nentries = 0;
368 LDAPMessage *entry, *res;
369 ALD *a = (ALD *) (m->map_data);
374 plog(XLOG_USER, "LDAP panic: no map data\n");
377 if (amu_ldap_rebind(a)) /* Check that's the handle is still valid */
380 sprintf(filter, AMD_LDAP_FILTER, map, key);
382 dlog("Search with filter: %s\n", filter);
384 for (i = 0; i < AMD_LDAP_RETRIES; i++) {
385 err = ldap_search_st(a->ldap,
393 if (err == LDAP_SUCCESS)
400 case LDAP_NO_SUCH_OBJECT:
407 plog(XLOG_USER, "LDAP search failed: %s\n",
408 ldap_err2string(a->ldap->ld_errno));
413 nentries = ldap_count_entries(a->ldap, res);
415 dlog("Search found %d entries\n", nentries);
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);
425 plog(XLOG_USER, "Missing value for %s in map %s\n", key, map);
426 ldap_value_free(vals);
432 dlog("Map %s, %s => %s\n", map, key, vals[0]);
435 *pval = strdup(vals[0]);
438 plog(XLOG_USER, "Empty value for %s in map %s\n", key, map);
443 ldap_value_free(vals);
450 amu_ldap_mtime(mnt_map *m, char *map, time_t *ts)
452 ALD *aldh = (ALD *) (m->map_data);
455 dlog("LDAP panic: unable to find map data\n");
458 if (amu_ldap_rebind(aldh)) {
461 if (get_ldap_timestamp(aldh->ldap, map, ts)) {