2 * Copyright (c) 1997-1999 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.6 1999/09/30 21:01:31 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
)
186 * XXX: by checking that map_type must be defined, aren't we
187 * excluding the possibility of automatic searches through all
190 if (!gopt
.map_type
|| !STREQ(gopt
.map_type
, AMD_LDAP_TYPE
)) {
195 dlog("Map %s is ldap\n", map
);
199 aldh
= (ALD
*) xmalloc(sizeof(ALD
));
200 creds
= (CR
*) xmalloc(sizeof(CR
));
202 aldh
->hostent
= string2he(gopt
.ldap_hostports
);
203 if (aldh
->hostent
== NULL
) {
204 plog(XLOG_USER
, "Unable to parse hostport %s for ldap map %s",
205 gopt
.ldap_hostports
, map
);
210 creds
->method
= LDAP_AUTH_SIMPLE
;
211 aldh
->credentials
= creds
;
214 dlog("Trying for %s:%d\n", aldh
->hostent
->host
, aldh
->hostent
->port
);
216 if (amu_ldap_rebind(aldh
)) {
220 m
->map_data
= (void *) aldh
;
222 dlog("Bound to %s:%d\n", aldh
->hostent
->host
, aldh
->hostent
->port
);
224 if (get_ldap_timestamp(aldh
->ldap
, map
, ts
))
227 dlog("Got timestamp for map %s: %ld\n", map
, *ts
);
235 amu_ldap_rebind(ALD
*a
)
239 CR
*c
= a
->credentials
;
240 time_t now
= clocktime();
243 if (a
->ldap
!= NULL
) {
244 if ((a
->timestamp
- now
) > AMD_LDAP_TTL
) {
246 dlog("Reestablishing ldap connection\n");
248 ldap_unbind(a
->ldap
);
254 for (try=0; try<10; try++) { /* XXX: try up to 10 times (makes sense?) */
255 for (h
= a
->hostent
; h
!= NULL
; h
= h
->next
) {
256 if ((ld
= ldap_open(h
->host
, h
->port
)) == NULL
) {
257 plog(XLOG_WARNING
, "Unable to ldap_open to %s:%d\n", h
->host
, h
->port
);
260 if (ldap_bind_s(ld
, c
->who
, c
->pw
, c
->method
) != LDAP_SUCCESS
) {
261 plog(XLOG_WARNING
, "Unable to ldap_bind to %s:%d as %s\n",
262 h
->host
, h
->port
, c
->who
);
265 if (gopt
.ldap_cache_seconds
> 0) {
266 ldap_enable_cache(ld
, gopt
.ldap_cache_seconds
, gopt
.ldap_cache_maxmem
);
272 plog(XLOG_WARNING
, "Exhausted list of ldap servers, looping.\n");
275 plog(XLOG_USER
, "Unable to (re)bind to any ldap hosts\n");
281 get_ldap_timestamp(LDAP
* ld
, char *map
, time_t *ts
)
285 char filter
[MAXPATHLEN
];
286 int i
, err
= 0, nentries
= 0;
287 LDAPMessage
*res
, *entry
;
291 sprintf(filter
, AMD_LDAP_TSFILTER
, map
);
293 dlog("Getting timestamp for map %s\n", map
);
294 dlog("Filter is: %s\n", filter
);
295 dlog("Base is: %s\n", gopt
.ldap_base
);
297 for (i
= 0; i
< AMD_LDAP_RETRIES
; i
++) {
298 err
= ldap_search_st(ld
,
306 if (err
== LDAP_SUCCESS
)
309 dlog("Timestamp search timed out, trying again...\n");
313 if (err
!= LDAP_SUCCESS
) {
315 plog(XLOG_USER
, "LDAP timestamp search failed: %s\n",
316 ldap_err2string(ld
->ld_errno
));
320 nentries
= ldap_count_entries(ld
, res
);
322 plog(XLOG_USER
, "No timestamp entry for map %s\n", map
);
328 entry
= ldap_first_entry(ld
, res
);
329 vals
= ldap_get_values(ld
, entry
, AMD_LDAP_TSATTR
);
330 if (ldap_count_values(vals
) == 0) {
331 plog(XLOG_USER
, "Missing timestamp value for map %s\n", map
);
333 ldap_value_free(vals
);
339 dlog("TS value is:%s:\n", vals
[0]);
343 *ts
= (time_t) strtol(vals
[0], &end
, 10);
344 if (end
== vals
[0]) {
345 plog(XLOG_USER
, "Unable to decode ldap timestamp %s for map %s\n",
350 plog(XLOG_USER
, "Nonpositive timestamp %ld for map %s\n",
355 plog(XLOG_USER
, "Empty timestamp value for map %s\n", map
);
360 ldap_value_free(vals
);
364 dlog("The timestamp for %s is %ld (err=%d)\n", map
, *ts
, err
);
371 amu_ldap_search(mnt_map
*m
, char *map
, char *key
, char **pval
, time_t *ts
)
373 char **vals
, filter
[MAXPATHLEN
];
375 int i
, err
= 0, nvals
= 0, nentries
= 0;
376 LDAPMessage
*entry
, *res
;
377 ALD
*a
= (ALD
*) (m
->map_data
);
382 plog(XLOG_USER
, "LDAP panic: no map data\n");
385 if (amu_ldap_rebind(a
)) /* Check that's the handle is still valid */
388 sprintf(filter
, AMD_LDAP_FILTER
, map
, key
);
390 dlog("Search with filter: %s\n", filter
);
392 for (i
= 0; i
< AMD_LDAP_RETRIES
; i
++) {
393 err
= ldap_search_st(a
->ldap
,
401 if (err
== LDAP_SUCCESS
)
408 case LDAP_NO_SUCH_OBJECT
:
415 plog(XLOG_USER
, "LDAP search failed: %s\n",
416 ldap_err2string(a
->ldap
->ld_errno
));
421 nentries
= ldap_count_entries(a
->ldap
, res
);
423 dlog("Search found %d entries\n", nentries
);
429 entry
= ldap_first_entry(a
->ldap
, res
);
430 vals
= ldap_get_values(a
->ldap
, entry
, AMD_LDAP_ATTR
);
431 nvals
= ldap_count_values(vals
);
433 plog(XLOG_USER
, "Missing value for %s in map %s\n", key
, map
);
434 ldap_value_free(vals
);
440 dlog("Map %s, %s => %s\n", map
, key
, vals
[0]);
443 *pval
= strdup(vals
[0]);
446 plog(XLOG_USER
, "Empty value for %s in map %s\n", key
, map
);
451 ldap_value_free(vals
);
458 amu_ldap_mtime(mnt_map
*m
, char *map
, time_t *ts
)
460 ALD
*aldh
= (ALD
*) (m
->map_data
);
464 dlog("LDAP panic: unable to find map data\n");
468 if (amu_ldap_rebind(aldh
)) {
471 if (get_ldap_timestamp(aldh
->ldap
, map
, ts
)) {