xref: /netbsd-src/external/bsd/am-utils/dist/amd/info_ldap.c (revision a83f6c13171e562ca1a870d6e82ace3a77e252a1)
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