1*a83f6c13Smrg /* $NetBSD: info_ldap.c,v 1.3 2019/10/04 09:01:59 mrg Exp $ */
2a53f50b9Schristos
3a53f50b9Schristos /*
48bae5d40Schristos * Copyright (c) 1997-2014 Erez Zadok
5a53f50b9Schristos * Copyright (c) 1989 Jan-Simon Pendry
6a53f50b9Schristos * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7a53f50b9Schristos * Copyright (c) 1989 The Regents of the University of California.
8a53f50b9Schristos * All rights reserved.
9a53f50b9Schristos *
10a53f50b9Schristos * This code is derived from software contributed to Berkeley by
11a53f50b9Schristos * Jan-Simon Pendry at Imperial College, London.
12a53f50b9Schristos *
13a53f50b9Schristos * Redistribution and use in source and binary forms, with or without
14a53f50b9Schristos * modification, are permitted provided that the following conditions
15a53f50b9Schristos * are met:
16a53f50b9Schristos * 1. Redistributions of source code must retain the above copyright
17a53f50b9Schristos * notice, this list of conditions and the following disclaimer.
18a53f50b9Schristos * 2. Redistributions in binary form must reproduce the above copyright
19a53f50b9Schristos * notice, this list of conditions and the following disclaimer in the
20a53f50b9Schristos * documentation and/or other materials provided with the distribution.
218bae5d40Schristos * 3. Neither the name of the University nor the names of its contributors
22a53f50b9Schristos * may be used to endorse or promote products derived from this software
23a53f50b9Schristos * without specific prior written permission.
24a53f50b9Schristos *
25a53f50b9Schristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26a53f50b9Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27a53f50b9Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28a53f50b9Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29a53f50b9Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30a53f50b9Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31a53f50b9Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32a53f50b9Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33a53f50b9Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34a53f50b9Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35a53f50b9Schristos * SUCH DAMAGE.
36a53f50b9Schristos *
37a53f50b9Schristos *
38a53f50b9Schristos * File: am-utils/amd/info_ldap.c
39a53f50b9Schristos *
40a53f50b9Schristos */
41a53f50b9Schristos
42a53f50b9Schristos
43a53f50b9Schristos /*
44a53f50b9Schristos * Get info from LDAP (Lightweight Directory Access Protocol)
45a53f50b9Schristos * LDAP Home Page: http://www.umich.edu/~rsug/ldap/
46a53f50b9Schristos */
47a53f50b9Schristos
48a53f50b9Schristos /*
49a53f50b9Schristos * WARNING: as of Linux Fedora Core 5 (which comes with openldap-2.3.9), the
50a53f50b9Schristos * ldap.h headers deprecate several functions used in this file, such as
51a53f50b9Schristos * ldap_unbind. You get compile errors about missing extern definitions.
52a53f50b9Schristos * Those externs are still in <ldap.h>, but surrounded by an ifdef
53a53f50b9Schristos * LDAP_DEPRECATED. I am turning on that ifdef here, under the assumption
54a53f50b9Schristos * that the functions may be deprecated, but they still work for this
55a53f50b9Schristos * (older?) version of the LDAP API. It gets am-utils to compile, but it is
56a53f50b9Schristos * not clear if it will work perfectly.
57a53f50b9Schristos */
58a53f50b9Schristos #ifndef LDAP_DEPRECATED
59a53f50b9Schristos # define LDAP_DEPRECATED 1
60a53f50b9Schristos #endif /* not LDAP_DEPRECATED */
61a53f50b9Schristos
62a53f50b9Schristos #ifdef HAVE_CONFIG_H
63a53f50b9Schristos # include <config.h>
64a53f50b9Schristos #endif /* HAVE_CONFIG_H */
65a53f50b9Schristos #include <am_defs.h>
66a53f50b9Schristos #include <amd.h>
67a53f50b9Schristos #include <sun_map.h>
68a53f50b9Schristos
69a53f50b9Schristos
70a53f50b9Schristos /*
71a53f50b9Schristos * MACROS:
72a53f50b9Schristos */
73a53f50b9Schristos #define AMD_LDAP_TYPE "ldap"
74a53f50b9Schristos /* Time to live for an LDAP cached in an mnt_map */
75a53f50b9Schristos #define AMD_LDAP_TTL 3600
76a53f50b9Schristos #define AMD_LDAP_RETRIES 5
77a53f50b9Schristos #define AMD_LDAP_HOST "ldap"
78a53f50b9Schristos #ifndef LDAP_PORT
79a53f50b9Schristos # define LDAP_PORT 389
80a53f50b9Schristos #endif /* LDAP_PORT */
81a53f50b9Schristos
82a53f50b9Schristos /* How timestamps are searched */
83a53f50b9Schristos #define AMD_LDAP_TSFILTER "(&(objectClass=amdmapTimestamp)(amdmapName=%s))"
84a53f50b9Schristos /* How maps are searched */
85a53f50b9Schristos #define AMD_LDAP_FILTER "(&(objectClass=amdmap)(amdmapName=%s)(amdmapKey=%s))"
86a53f50b9Schristos /* How timestamps are stored */
87a53f50b9Schristos #define AMD_LDAP_TSATTR "amdmaptimestamp"
88a53f50b9Schristos /* How maps are stored */
89a53f50b9Schristos #define AMD_LDAP_ATTR "amdmapvalue"
90a53f50b9Schristos
91a53f50b9Schristos /*
92a53f50b9Schristos * TYPEDEFS:
93a53f50b9Schristos */
94a53f50b9Schristos typedef struct ald_ent ALD;
95a53f50b9Schristos typedef struct cr_ent CR;
96a53f50b9Schristos typedef struct he_ent HE_ENT;
97a53f50b9Schristos
98a53f50b9Schristos /*
99a53f50b9Schristos * STRUCTURES:
100a53f50b9Schristos */
101a53f50b9Schristos struct ald_ent {
102a53f50b9Schristos LDAP *ldap;
103a53f50b9Schristos HE_ENT *hostent;
104a53f50b9Schristos CR *credentials;
105a53f50b9Schristos time_t timestamp;
106a53f50b9Schristos };
107a53f50b9Schristos
108a53f50b9Schristos struct cr_ent {
109a53f50b9Schristos char *who;
110a53f50b9Schristos char *pw;
111a53f50b9Schristos int method;
112a53f50b9Schristos };
113a53f50b9Schristos
114a53f50b9Schristos struct he_ent {
115a53f50b9Schristos char *host;
116a53f50b9Schristos int port;
117a53f50b9Schristos struct he_ent *next;
118a53f50b9Schristos };
119a53f50b9Schristos
1208bae5d40Schristos static ALD *ldap_connection;
1218bae5d40Schristos
122a53f50b9Schristos /*
123a53f50b9Schristos * FORWARD DECLARATIONS:
124a53f50b9Schristos */
125a53f50b9Schristos static int amu_ldap_rebind(ALD *a);
126a53f50b9Schristos static int get_ldap_timestamp(ALD *a, char *map, time_t *ts);
127a53f50b9Schristos
128a53f50b9Schristos int amu_ldap_init(mnt_map *m, char *map, time_t *tsu);
129a53f50b9Schristos int amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts);
130a53f50b9Schristos int amu_ldap_mtime(mnt_map *m, char *map, time_t *ts);
131a53f50b9Schristos
132a53f50b9Schristos /*
133a53f50b9Schristos * FUNCTIONS:
134a53f50b9Schristos */
135a53f50b9Schristos
136a53f50b9Schristos static void
he_free(HE_ENT * h)137a53f50b9Schristos he_free(HE_ENT *h)
138a53f50b9Schristos {
139a53f50b9Schristos XFREE(h->host);
140a53f50b9Schristos if (h->next != NULL)
141a53f50b9Schristos he_free(h->next);
142a53f50b9Schristos XFREE(h);
143a53f50b9Schristos }
144a53f50b9Schristos
145a53f50b9Schristos
146a53f50b9Schristos static HE_ENT *
string2he(char * s_orig)147a53f50b9Schristos string2he(char *s_orig)
148a53f50b9Schristos {
149a53f50b9Schristos char *c, *p;
150a53f50b9Schristos char *s;
1514bcd344eSchristos HE_ENT *first = NULL, *cur = NULL;
152a53f50b9Schristos
1538bae5d40Schristos if (NULL == s_orig)
154a53f50b9Schristos return NULL;
1558bae5d40Schristos s = xstrdup(s_orig);
1564bcd344eSchristos for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
1574bcd344eSchristos if (cur != NULL) {
1584bcd344eSchristos cur->next = ALLOC(HE_ENT);
1594bcd344eSchristos cur = cur->next;
1604bcd344eSchristos } else
1614bcd344eSchristos first = cur = ALLOC(HE_ENT);
1624bcd344eSchristos
1634bcd344eSchristos cur->next = NULL;
164a53f50b9Schristos c = strchr(p, ':');
165a53f50b9Schristos if (c) { /* Host and port */
166a53f50b9Schristos *c++ = '\0';
1678bae5d40Schristos cur->host = xstrdup(p);
1684bcd344eSchristos cur->port = atoi(c);
1694bcd344eSchristos } else {
1708bae5d40Schristos cur->host = xstrdup(p);
1714bcd344eSchristos cur->port = LDAP_PORT;
1724bcd344eSchristos }
1734bcd344eSchristos plog(XLOG_USER, "Adding ldap server %s:%d",
1744bcd344eSchristos cur->host, cur->port);
175a53f50b9Schristos }
176a53f50b9Schristos XFREE(s);
1774bcd344eSchristos return first;
178a53f50b9Schristos }
179a53f50b9Schristos
180a53f50b9Schristos
181a53f50b9Schristos static void
cr_free(CR * c)182a53f50b9Schristos cr_free(CR *c)
183a53f50b9Schristos {
184a53f50b9Schristos XFREE(c->who);
185a53f50b9Schristos XFREE(c->pw);
186a53f50b9Schristos XFREE(c);
187a53f50b9Schristos }
188a53f50b9Schristos
189a53f50b9Schristos
190a53f50b9Schristos /*
191a53f50b9Schristos * Special ldap_unbind function to handle SIGPIPE.
192a53f50b9Schristos * We first ignore SIGPIPE, in case a remote LDAP server was
193a53f50b9Schristos * restarted, then we reinstall the handler.
194a53f50b9Schristos */
195a53f50b9Schristos static int
amu_ldap_unbind(LDAP * ld)196a53f50b9Schristos amu_ldap_unbind(LDAP *ld)
197a53f50b9Schristos {
198a53f50b9Schristos int e;
199a53f50b9Schristos #ifdef HAVE_SIGACTION
200*a83f6c13Smrg struct sigaction sa, osa;
201a53f50b9Schristos #else /* not HAVE_SIGACTION */
202a53f50b9Schristos void (*handler)(int);
203a53f50b9Schristos #endif /* not HAVE_SIGACTION */
204a53f50b9Schristos
205a53f50b9Schristos dlog("amu_ldap_unbind()\n");
206a53f50b9Schristos
207a53f50b9Schristos #ifdef HAVE_SIGACTION
208a53f50b9Schristos sa.sa_handler = SIG_IGN;
209a53f50b9Schristos sa.sa_flags = 0;
210a53f50b9Schristos sigemptyset(&(sa.sa_mask));
211a53f50b9Schristos sigaddset(&(sa.sa_mask), SIGPIPE);
212*a83f6c13Smrg sigaction(SIGPIPE, &sa, &osa); /* set IGNORE, and get old action */
213a53f50b9Schristos #else /* not HAVE_SIGACTION */
214a53f50b9Schristos handler = signal(SIGPIPE, SIG_IGN);
215a53f50b9Schristos #endif /* not HAVE_SIGACTION */
216a53f50b9Schristos
217a53f50b9Schristos e = ldap_unbind(ld);
218a53f50b9Schristos
219a53f50b9Schristos #ifdef HAVE_SIGACTION
220*a83f6c13Smrg sigemptyset(&(osa.sa_mask));
221*a83f6c13Smrg sigaddset(&(osa.sa_mask), SIGPIPE);
222*a83f6c13Smrg sigaction(SIGPIPE, &osa, NULL);
223a53f50b9Schristos #else /* not HAVE_SIGACTION */
224a53f50b9Schristos (void) signal(SIGPIPE, handler);
225a53f50b9Schristos #endif /* not HAVE_SIGACTION */
226a53f50b9Schristos
227a53f50b9Schristos return e;
228a53f50b9Schristos }
229a53f50b9Schristos
230a53f50b9Schristos
231a53f50b9Schristos static void
ald_free(ALD * a)232a53f50b9Schristos ald_free(ALD *a)
233a53f50b9Schristos {
234a53f50b9Schristos he_free(a->hostent);
235a53f50b9Schristos cr_free(a->credentials);
236a53f50b9Schristos if (a->ldap != NULL)
237a53f50b9Schristos amu_ldap_unbind(a->ldap);
238a53f50b9Schristos XFREE(a);
239a53f50b9Schristos }
240a53f50b9Schristos
241a53f50b9Schristos
242a53f50b9Schristos int
amu_ldap_init(mnt_map * m,char * map,time_t * ts)243a53f50b9Schristos amu_ldap_init(mnt_map *m, char *map, time_t *ts)
244a53f50b9Schristos {
245a53f50b9Schristos ALD *aldh;
246a53f50b9Schristos CR *creds;
247a53f50b9Schristos
248a53f50b9Schristos dlog("-> amu_ldap_init: map <%s>\n", map);
249a53f50b9Schristos
250a53f50b9Schristos /*
251a53f50b9Schristos * XXX: by checking that map_type must be defined, aren't we
252a53f50b9Schristos * excluding the possibility of automatic searches through all
253a53f50b9Schristos * map types?
254a53f50b9Schristos */
255a53f50b9Schristos if (!gopt.map_type || !STREQ(gopt.map_type, AMD_LDAP_TYPE)) {
256a53f50b9Schristos dlog("amu_ldap_init called with map_type <%s>\n",
257a53f50b9Schristos (gopt.map_type ? gopt.map_type : "null"));
2588bae5d40Schristos return ENOENT;
259a53f50b9Schristos } else {
260a53f50b9Schristos dlog("Map %s is ldap\n", map);
261a53f50b9Schristos }
262a53f50b9Schristos
2638bae5d40Schristos #ifndef LDAP_CONNECTION_PER_MAP
2648bae5d40Schristos if (ldap_connection != NULL) {
2658bae5d40Schristos m->map_data = (void *) ldap_connection;
2668bae5d40Schristos return 0;
2678bae5d40Schristos }
2688bae5d40Schristos #endif
2698bae5d40Schristos
270a53f50b9Schristos aldh = ALLOC(ALD);
271a53f50b9Schristos creds = ALLOC(CR);
272a53f50b9Schristos aldh->ldap = NULL;
273a53f50b9Schristos aldh->hostent = string2he(gopt.ldap_hostports);
274a53f50b9Schristos if (aldh->hostent == NULL) {
275a53f50b9Schristos plog(XLOG_USER, "Unable to parse hostport %s for ldap map %s",
276a53f50b9Schristos gopt.ldap_hostports ? gopt.ldap_hostports : "(null)", map);
277a53f50b9Schristos XFREE(creds);
278a53f50b9Schristos XFREE(aldh);
279a53f50b9Schristos return (ENOENT);
280a53f50b9Schristos }
281a53f50b9Schristos creds->who = "";
282a53f50b9Schristos creds->pw = "";
283a53f50b9Schristos creds->method = LDAP_AUTH_SIMPLE;
284a53f50b9Schristos aldh->credentials = creds;
285a53f50b9Schristos aldh->timestamp = 0;
286a53f50b9Schristos aldh->ldap = NULL;
287a53f50b9Schristos dlog("Trying for %s:%d\n", aldh->hostent->host, aldh->hostent->port);
288a53f50b9Schristos if (amu_ldap_rebind(aldh)) {
289a53f50b9Schristos ald_free(aldh);
290a53f50b9Schristos return (ENOENT);
291a53f50b9Schristos }
292a53f50b9Schristos dlog("Bound to %s:%d\n", aldh->hostent->host, aldh->hostent->port);
2938bae5d40Schristos if (get_ldap_timestamp(aldh, map, ts)) {
2948bae5d40Schristos ald_free(aldh);
295a53f50b9Schristos return (ENOENT);
2968bae5d40Schristos }
297a53f50b9Schristos dlog("Got timestamp for map %s: %ld\n", map, (u_long) *ts);
2988bae5d40Schristos ldap_connection = aldh;
2998bae5d40Schristos m->map_data = (void *) ldap_connection;
300a53f50b9Schristos
301a53f50b9Schristos return (0);
302a53f50b9Schristos }
303a53f50b9Schristos
304a53f50b9Schristos
305a53f50b9Schristos static int
amu_ldap_rebind(ALD * a)306a53f50b9Schristos amu_ldap_rebind(ALD *a)
307a53f50b9Schristos {
308a53f50b9Schristos LDAP *ld;
309a53f50b9Schristos HE_ENT *h;
310a53f50b9Schristos CR *c = a->credentials;
311a53f50b9Schristos time_t now = clocktime(NULL);
312a53f50b9Schristos int try;
313a53f50b9Schristos
314a53f50b9Schristos dlog("-> amu_ldap_rebind\n");
315a53f50b9Schristos
316a53f50b9Schristos if (a->ldap != NULL) {
317a53f50b9Schristos if ((a->timestamp - now) > AMD_LDAP_TTL) {
318a53f50b9Schristos dlog("Re-establishing ldap connection\n");
319a53f50b9Schristos amu_ldap_unbind(a->ldap);
320a53f50b9Schristos a->timestamp = now;
321a53f50b9Schristos a->ldap = NULL;
322a53f50b9Schristos } else {
323a53f50b9Schristos /* Assume all is OK. If it wasn't we'll be back! */
324a53f50b9Schristos dlog("amu_ldap_rebind: timestamp OK\n");
325a53f50b9Schristos return (0);
326a53f50b9Schristos }
327a53f50b9Schristos }
328a53f50b9Schristos
329a53f50b9Schristos for (try=0; try<10; try++) { /* XXX: try up to 10 times (makes sense?) */
330a53f50b9Schristos for (h = a->hostent; h != NULL; h = h->next) {
331a53f50b9Schristos if ((ld = ldap_open(h->host, h->port)) == NULL) {
332a53f50b9Schristos plog(XLOG_WARNING, "Unable to ldap_open to %s:%d\n", h->host, h->port);
3334bcd344eSchristos continue;
334a53f50b9Schristos }
335a53f50b9Schristos #if LDAP_VERSION_MAX > LDAP_VERSION2
336a53f50b9Schristos /* handle LDAPv3 and heigher, if available and amd.conf-igured */
337a53f50b9Schristos if (gopt.ldap_proto_version > LDAP_VERSION2) {
338a53f50b9Schristos if (!ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &gopt.ldap_proto_version)) {
339a53f50b9Schristos dlog("amu_ldap_rebind: LDAP protocol version set to %ld\n",
340a53f50b9Schristos gopt.ldap_proto_version);
341a53f50b9Schristos } else {
3424bcd344eSchristos plog(XLOG_WARNING, "Unable to set ldap protocol version to %ld for "
3434bcd344eSchristos "%s:%d\n", gopt.ldap_proto_version, h->host, h->port);
3444bcd344eSchristos continue;
345a53f50b9Schristos }
346a53f50b9Schristos }
347a53f50b9Schristos #endif /* LDAP_VERSION_MAX > LDAP_VERSION2 */
348a53f50b9Schristos if (ldap_bind_s(ld, c->who, c->pw, c->method) != LDAP_SUCCESS) {
349a53f50b9Schristos plog(XLOG_WARNING, "Unable to ldap_bind to %s:%d as %s\n",
350a53f50b9Schristos h->host, h->port, c->who);
3514bcd344eSchristos continue;
352a53f50b9Schristos }
353a53f50b9Schristos if (gopt.ldap_cache_seconds > 0) {
354a53f50b9Schristos #if defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE)
355a53f50b9Schristos ldap_enable_cache(ld, gopt.ldap_cache_seconds, gopt.ldap_cache_maxmem);
356a53f50b9Schristos #else /* not defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE) */
357a53f50b9Schristos plog(XLOG_WARNING, "ldap_enable_cache(%ld) is not available on this system!\n", gopt.ldap_cache_seconds);
358a53f50b9Schristos #endif /* not defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE) */
359a53f50b9Schristos }
360a53f50b9Schristos a->ldap = ld;
361a53f50b9Schristos a->timestamp = now;
362a53f50b9Schristos return (0);
363a53f50b9Schristos }
364a53f50b9Schristos plog(XLOG_WARNING, "Exhausted list of ldap servers, looping.\n");
365a53f50b9Schristos }
366a53f50b9Schristos
367a53f50b9Schristos plog(XLOG_USER, "Unable to (re)bind to any ldap hosts\n");
368a53f50b9Schristos return (ENOENT);
369a53f50b9Schristos }
370a53f50b9Schristos
371a53f50b9Schristos
372a53f50b9Schristos static int
get_ldap_timestamp(ALD * a,char * map,time_t * ts)373a53f50b9Schristos get_ldap_timestamp(ALD *a, char *map, time_t *ts)
374a53f50b9Schristos {
375a53f50b9Schristos struct timeval tv;
376a53f50b9Schristos char **vals, *end;
377a53f50b9Schristos char filter[MAXPATHLEN];
378a53f50b9Schristos int i, err = 0, nentries = 0;
379a53f50b9Schristos LDAPMessage *res = NULL, *entry;
380a53f50b9Schristos
381a53f50b9Schristos dlog("-> get_ldap_timestamp: map <%s>\n", map);
382a53f50b9Schristos
383a53f50b9Schristos tv.tv_sec = 3;
384a53f50b9Schristos tv.tv_usec = 0;
385a53f50b9Schristos xsnprintf(filter, sizeof(filter), AMD_LDAP_TSFILTER, map);
386a53f50b9Schristos dlog("Getting timestamp for map %s\n", map);
387a53f50b9Schristos dlog("Filter is: %s\n", filter);
388a53f50b9Schristos dlog("Base is: %s\n", gopt.ldap_base);
389a53f50b9Schristos for (i = 0; i < AMD_LDAP_RETRIES; i++) {
390a53f50b9Schristos err = ldap_search_st(a->ldap,
391a53f50b9Schristos gopt.ldap_base,
392a53f50b9Schristos LDAP_SCOPE_SUBTREE,
393a53f50b9Schristos filter,
394a53f50b9Schristos 0,
395a53f50b9Schristos 0,
396a53f50b9Schristos &tv,
397a53f50b9Schristos &res);
398a53f50b9Schristos if (err == LDAP_SUCCESS)
399a53f50b9Schristos break;
400a53f50b9Schristos if (res) {
401a53f50b9Schristos ldap_msgfree(res);
402a53f50b9Schristos res = NULL;
403a53f50b9Schristos }
404a53f50b9Schristos plog(XLOG_USER, "Timestamp LDAP search attempt %d failed: %s\n",
405a53f50b9Schristos i + 1, ldap_err2string(err));
406a53f50b9Schristos if (err != LDAP_TIMEOUT) {
407a53f50b9Schristos dlog("get_ldap_timestamp: unbinding...\n");
408a53f50b9Schristos amu_ldap_unbind(a->ldap);
409a53f50b9Schristos a->ldap = NULL;
410a53f50b9Schristos if (amu_ldap_rebind(a))
411a53f50b9Schristos return (ENOENT);
412a53f50b9Schristos }
413a53f50b9Schristos dlog("Timestamp search failed, trying again...\n");
414a53f50b9Schristos }
415a53f50b9Schristos
416a53f50b9Schristos if (err != LDAP_SUCCESS) {
417a53f50b9Schristos *ts = 0;
418a53f50b9Schristos plog(XLOG_USER, "LDAP timestamp search failed: %s\n",
419a53f50b9Schristos ldap_err2string(err));
420a53f50b9Schristos if (res)
421a53f50b9Schristos ldap_msgfree(res);
422a53f50b9Schristos return (ENOENT);
423a53f50b9Schristos }
424a53f50b9Schristos
425a53f50b9Schristos nentries = ldap_count_entries(a->ldap, res);
426a53f50b9Schristos if (nentries == 0) {
427a53f50b9Schristos plog(XLOG_USER, "No timestamp entry for map %s\n", map);
428a53f50b9Schristos *ts = 0;
429a53f50b9Schristos ldap_msgfree(res);
430a53f50b9Schristos return (ENOENT);
431a53f50b9Schristos }
432a53f50b9Schristos
433a53f50b9Schristos entry = ldap_first_entry(a->ldap, res);
434a53f50b9Schristos vals = ldap_get_values(a->ldap, entry, AMD_LDAP_TSATTR);
435a53f50b9Schristos if (ldap_count_values(vals) == 0) {
436a53f50b9Schristos plog(XLOG_USER, "Missing timestamp value for map %s\n", map);
437a53f50b9Schristos *ts = 0;
438a53f50b9Schristos ldap_value_free(vals);
439a53f50b9Schristos ldap_msgfree(res);
440a53f50b9Schristos return (ENOENT);
441a53f50b9Schristos }
442a53f50b9Schristos dlog("TS value is:%s:\n", vals[0]);
443a53f50b9Schristos
444a53f50b9Schristos if (vals[0]) {
445a53f50b9Schristos *ts = (time_t) strtol(vals[0], &end, 10);
446a53f50b9Schristos if (end == vals[0]) {
447a53f50b9Schristos plog(XLOG_USER, "Unable to decode ldap timestamp %s for map %s\n",
448a53f50b9Schristos vals[0], map);
449a53f50b9Schristos err = ENOENT;
450a53f50b9Schristos }
45155053983Sjoerg if (*ts <= 0) {
452a53f50b9Schristos plog(XLOG_USER, "Nonpositive timestamp %ld for map %s\n",
453a53f50b9Schristos (u_long) *ts, map);
454a53f50b9Schristos err = ENOENT;
455a53f50b9Schristos }
456a53f50b9Schristos } else {
457a53f50b9Schristos plog(XLOG_USER, "Empty timestamp value for map %s\n", map);
458a53f50b9Schristos *ts = 0;
459a53f50b9Schristos err = ENOENT;
460a53f50b9Schristos }
461a53f50b9Schristos
462a53f50b9Schristos ldap_value_free(vals);
463a53f50b9Schristos ldap_msgfree(res);
464a53f50b9Schristos dlog("The timestamp for %s is %ld (err=%d)\n", map, (u_long) *ts, err);
465a53f50b9Schristos return (err);
466a53f50b9Schristos }
467a53f50b9Schristos
468a53f50b9Schristos
469a53f50b9Schristos int
amu_ldap_search(mnt_map * m,char * map,char * key,char ** pval,time_t * ts)470a53f50b9Schristos amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts)
471a53f50b9Schristos {
472a53f50b9Schristos char **vals, filter[MAXPATHLEN], filter2[2 * MAXPATHLEN];
473a53f50b9Schristos char *f1, *f2;
474a53f50b9Schristos struct timeval tv;
475a53f50b9Schristos int i, err = 0, nvals = 0, nentries = 0;
476a53f50b9Schristos LDAPMessage *entry, *res = NULL;
477a53f50b9Schristos ALD *a = (ALD *) (m->map_data);
478a53f50b9Schristos
479a53f50b9Schristos dlog("-> amu_ldap_search: map <%s>, key <%s>\n", map, key);
480a53f50b9Schristos
481a53f50b9Schristos tv.tv_sec = 2;
482a53f50b9Schristos tv.tv_usec = 0;
483a53f50b9Schristos if (a == NULL) {
484a53f50b9Schristos plog(XLOG_USER, "LDAP panic: no map data\n");
485a53f50b9Schristos return (EIO);
486a53f50b9Schristos }
487a53f50b9Schristos if (amu_ldap_rebind(a)) /* Check that's the handle is still valid */
488a53f50b9Schristos return (ENOENT);
489a53f50b9Schristos
490a53f50b9Schristos xsnprintf(filter, sizeof(filter), AMD_LDAP_FILTER, map, key);
491a53f50b9Schristos /* "*" is special to ldap_search(); run through the filter escaping it. */
492a53f50b9Schristos f1 = filter; f2 = filter2;
493a53f50b9Schristos while (*f1) {
494a53f50b9Schristos if (*f1 == '*') {
495a53f50b9Schristos *f2++ = '\\'; *f2++ = '2'; *f2++ = 'a';
496a53f50b9Schristos f1++;
497a53f50b9Schristos } else {
498a53f50b9Schristos *f2++ = *f1++;
499a53f50b9Schristos }
500a53f50b9Schristos }
501a53f50b9Schristos *f2 = '\0';
502a53f50b9Schristos dlog("Search with filter: <%s>\n", filter2);
503a53f50b9Schristos for (i = 0; i < AMD_LDAP_RETRIES; i++) {
504a53f50b9Schristos err = ldap_search_st(a->ldap,
505a53f50b9Schristos gopt.ldap_base,
506a53f50b9Schristos LDAP_SCOPE_SUBTREE,
507a53f50b9Schristos filter2,
508a53f50b9Schristos 0,
509a53f50b9Schristos 0,
510a53f50b9Schristos &tv,
511a53f50b9Schristos &res);
512a53f50b9Schristos if (err == LDAP_SUCCESS)
513a53f50b9Schristos break;
514a53f50b9Schristos if (res) {
515a53f50b9Schristos ldap_msgfree(res);
516a53f50b9Schristos res = NULL;
517a53f50b9Schristos }
518a53f50b9Schristos plog(XLOG_USER, "LDAP search attempt %d failed: %s\n",
519a53f50b9Schristos i + 1, ldap_err2string(err));
520a53f50b9Schristos if (err != LDAP_TIMEOUT) {
521a53f50b9Schristos dlog("amu_ldap_search: unbinding...\n");
522a53f50b9Schristos amu_ldap_unbind(a->ldap);
523a53f50b9Schristos a->ldap = NULL;
524a53f50b9Schristos if (amu_ldap_rebind(a))
525a53f50b9Schristos return (ENOENT);
526a53f50b9Schristos }
527a53f50b9Schristos }
528a53f50b9Schristos
529a53f50b9Schristos switch (err) {
530a53f50b9Schristos case LDAP_SUCCESS:
531a53f50b9Schristos break;
532a53f50b9Schristos case LDAP_NO_SUCH_OBJECT:
533a53f50b9Schristos dlog("No object\n");
534a53f50b9Schristos if (res)
535a53f50b9Schristos ldap_msgfree(res);
536a53f50b9Schristos return (ENOENT);
537a53f50b9Schristos default:
538a53f50b9Schristos plog(XLOG_USER, "LDAP search failed: %s\n",
539a53f50b9Schristos ldap_err2string(err));
540a53f50b9Schristos if (res)
541a53f50b9Schristos ldap_msgfree(res);
542a53f50b9Schristos return (EIO);
543a53f50b9Schristos }
544a53f50b9Schristos
545a53f50b9Schristos nentries = ldap_count_entries(a->ldap, res);
546a53f50b9Schristos dlog("Search found %d entries\n", nentries);
547a53f50b9Schristos if (nentries == 0) {
548a53f50b9Schristos ldap_msgfree(res);
549a53f50b9Schristos return (ENOENT);
550a53f50b9Schristos }
551a53f50b9Schristos entry = ldap_first_entry(a->ldap, res);
552a53f50b9Schristos vals = ldap_get_values(a->ldap, entry, AMD_LDAP_ATTR);
553a53f50b9Schristos nvals = ldap_count_values(vals);
554a53f50b9Schristos if (nvals == 0) {
555a53f50b9Schristos plog(XLOG_USER, "Missing value for %s in map %s\n", key, map);
556a53f50b9Schristos ldap_value_free(vals);
557a53f50b9Schristos ldap_msgfree(res);
558a53f50b9Schristos return (EIO);
559a53f50b9Schristos }
560a53f50b9Schristos dlog("Map %s, %s => %s\n", map, key, vals[0]);
561a53f50b9Schristos if (vals[0]) {
562a53f50b9Schristos if (m->cfm && (m->cfm->cfm_flags & CFM_SUN_MAP_SYNTAX))
563a53f50b9Schristos *pval = sun_entry2amd(key, vals[0]);
564a53f50b9Schristos else
5658bae5d40Schristos *pval = xstrdup(vals[0]);
566a53f50b9Schristos err = 0;
567a53f50b9Schristos } else {
568a53f50b9Schristos plog(XLOG_USER, "Empty value for %s in map %s\n", key, map);
569a53f50b9Schristos err = ENOENT;
570a53f50b9Schristos }
571a53f50b9Schristos ldap_msgfree(res);
572a53f50b9Schristos ldap_value_free(vals);
573a53f50b9Schristos
574a53f50b9Schristos return (err);
575a53f50b9Schristos }
576a53f50b9Schristos
577a53f50b9Schristos
578a53f50b9Schristos int
amu_ldap_mtime(mnt_map * m,char * map,time_t * ts)579a53f50b9Schristos amu_ldap_mtime(mnt_map *m, char *map, time_t *ts)
580a53f50b9Schristos {
581a53f50b9Schristos ALD *aldh = (ALD *) (m->map_data);
582a53f50b9Schristos
583a53f50b9Schristos if (aldh == NULL) {
584a53f50b9Schristos dlog("LDAP panic: unable to find map data\n");
585a53f50b9Schristos return (ENOENT);
586a53f50b9Schristos }
587a53f50b9Schristos if (amu_ldap_rebind(aldh)) {
588a53f50b9Schristos return (ENOENT);
589a53f50b9Schristos }
590a53f50b9Schristos if (get_ldap_timestamp(aldh, map, ts)) {
591a53f50b9Schristos return (ENOENT);
592a53f50b9Schristos }
593a53f50b9Schristos return (0);
594a53f50b9Schristos }
595