info_ldap.c revision 174295
1228753Smm/*
2228753Smm * Copyright (c) 1997-2006 Erez Zadok
3238856Smm * Copyright (c) 1989 Jan-Simon Pendry
4228753Smm * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
5228753Smm * Copyright (c) 1989 The Regents of the University of California.
6228753Smm * All rights reserved.
7228753Smm *
8228753Smm * This code is derived from software contributed to Berkeley by
9228753Smm * Jan-Simon Pendry at Imperial College, London.
10228753Smm *
11228753Smm * Redistribution and use in source and binary forms, with or without
12228753Smm * modification, are permitted provided that the following conditions
13228753Smm * are met:
14228753Smm * 1. Redistributions of source code must retain the above copyright
15228753Smm *    notice, this list of conditions and the following disclaimer.
16228753Smm * 2. Redistributions in binary form must reproduce the above copyright
17228753Smm *    notice, this list of conditions and the following disclaimer in the
18228753Smm *    documentation and/or other materials provided with the distribution.
19228753Smm * 3. All advertising materials mentioning features or use of this software
20228753Smm *    must display the following acknowledgment:
21228753Smm *      This product includes software developed by the University of
22228753Smm *      California, Berkeley and its contributors.
23228753Smm * 4. Neither the name of the University nor the names of its contributors
24228753Smm *    may be used to endorse or promote products derived from this software
25228753Smm *    without specific prior written permission.
26228753Smm *
27228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28231200Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29231200Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30231200Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32231200Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34231200Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35231200Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36231200Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37231200Smm * SUCH DAMAGE.
38231200Smm *
39231200Smm *
40231200Smm * File: am-utils/amd/info_ldap.c
41231200Smm *
42231200Smm */
43231200Smm
44231200Smm
45231200Smm/*
46231200Smm * Get info from LDAP (Lightweight Directory Access Protocol)
47231200Smm * LDAP Home Page: http://www.umich.edu/~rsug/ldap/
48231200Smm */
49231200Smm
50231200Smm/*
51231200Smm * WARNING: as of Linux Fedora Core 5 (which comes with openldap-2.3.9), the
52231200Smm * ldap.h headers deprecate several functions used in this file, such as
53231200Smm * ldap_unbind.  You get compile errors about missing extern definitions.
54231200Smm * Those externs are still in <ldap.h>, but surrounded by an ifdef
55238856Smm * LDAP_DEPRECATED.  I am turning on that ifdef here, under the assumption
56238856Smm * that the functions may be deprecated, but they still work for this
57238856Smm * (older?) version of the LDAP API.  It gets am-utils to compile, but it is
58238856Smm * not clear if it will work perfectly.
59238856Smm */
60238856Smm#ifndef LDAP_DEPRECATED
61238856Smm# define LDAP_DEPRECATED 1
62238856Smm#endif /* not LDAP_DEPRECATED */
63238856Smm
64238856Smm#ifdef HAVE_CONFIG_H
65238856Smm# include <config.h>
66238856Smm#endif /* HAVE_CONFIG_H */
67238856Smm#include <am_defs.h>
68231200Smm#include <amd.h>
69231200Smm
70231200Smm
71231200Smm/*
72231200Smm * MACROS:
73231200Smm */
74231200Smm#define AMD_LDAP_TYPE		"ldap"
75231200Smm/* Time to live for an LDAP cached in an mnt_map */
76231200Smm#define AMD_LDAP_TTL		3600
77231200Smm#define AMD_LDAP_RETRIES	5
78231200Smm#define AMD_LDAP_HOST		"ldap"
79231200Smm#ifndef LDAP_PORT
80231200Smm# define LDAP_PORT		389
81231200Smm#endif /* LDAP_PORT */
82231200Smm
83231200Smm/* How timestamps are searched */
84231200Smm#define AMD_LDAP_TSFILTER "(&(objectClass=amdmapTimestamp)(amdmapName=%s))"
85231200Smm/* How maps are searched */
86231200Smm#define AMD_LDAP_FILTER "(&(objectClass=amdmap)(amdmapName=%s)(amdmapKey=%s))"
87231200Smm/* How timestamps are stored */
88231200Smm#define AMD_LDAP_TSATTR "amdmaptimestamp"
89231200Smm/* How maps are stored */
90231200Smm#define AMD_LDAP_ATTR "amdmapvalue"
91231200Smm
92238856Smm/*
93238856Smm * TYPEDEFS:
94238856Smm */
95231200Smmtypedef struct ald_ent ALD;
96228753Smmtypedef struct cr_ent CR;
97228753Smmtypedef struct he_ent HE_ENT;
98228753Smm
99228753Smm/*
100228753Smm * STRUCTURES:
101228753Smm */
102231200Smmstruct ald_ent {
103231200Smm  LDAP *ldap;
104231200Smm  HE_ENT *hostent;
105231200Smm  CR *credentials;
106231200Smm  time_t timestamp;
107231200Smm};
108248616Smm
109248616Smmstruct cr_ent {
110248616Smm  char *who;
111231200Smm  char *pw;
112231200Smm  int method;
113231200Smm};
114231200Smm
115231200Smmstruct he_ent {
116231200Smm  char *host;
117231200Smm  int port;
118231200Smm  struct he_ent *next;
119231200Smm};
120231200Smm
121231200Smm/*
122231200Smm * FORWARD DECLARATIONS:
123231200Smm */
124231200Smmstatic int amu_ldap_rebind(ALD *a);
125231200Smmstatic int get_ldap_timestamp(ALD *a, char *map, time_t *ts);
126231200Smm
127231200Smm
128231200Smm/*
129231200Smm * FUNCTIONS:
130231200Smm */
131231200Smm
132231200Smmstatic void
133231200Smmhe_free(HE_ENT *h)
134231200Smm{
135231200Smm  XFREE(h->host);
136231200Smm  if (h->next != NULL)
137231200Smm    he_free(h->next);
138231200Smm  XFREE(h);
139231200Smm}
140231200Smm
141231200Smm
142231200Smmstatic HE_ENT *
143231200Smmstring2he(char *s_orig)
144231200Smm{
145231200Smm  char *c, *p;
146231200Smm  char *s;
147231200Smm  HE_ENT *new, *old = NULL;
148231200Smm
149231200Smm  if (NULL == s_orig || NULL == (s = strdup(s_orig)))
150231200Smm    return NULL;
151231200Smm  for (p = s; p; p = strchr(p, ',')) {
152231200Smm    if (old != NULL) {
153231200Smm      new = ALLOC(HE_ENT);
154231200Smm      old->next = new;
155231200Smm      old = new;
156231200Smm    } else {
157231200Smm      old = ALLOC(HE_ENT);
158231200Smm      old->next = NULL;
159231200Smm    }
160231200Smm    c = strchr(p, ':');
161231200Smm    if (c) {            /* Host and port */
162231200Smm      *c++ = '\0';
163231200Smm      old->host = strdup(p);
164231200Smm      old->port = atoi(c);
165231200Smm    } else
166231200Smm      old->host = strdup(p);
167231200Smm
168231200Smm  }
169231200Smm  XFREE(s);
170231200Smm  return (old);
171231200Smm}
172231200Smm
173231200Smm
174231200Smmstatic void
175231200Smmcr_free(CR *c)
176231200Smm{
177231200Smm  XFREE(c->who);
178231200Smm  XFREE(c->pw);
179231200Smm  XFREE(c);
180231200Smm}
181231200Smm
182231200Smm
183231200Smm/*
184231200Smm * Special ldap_unbind function to handle SIGPIPE.
185231200Smm * We first ignore SIGPIPE, in case a remote LDAP server was
186231200Smm * restarted, then we reinstall the handler.
187231200Smm */
188231200Smmstatic int
189231200Smmamu_ldap_unbind(LDAP *ld)
190231200Smm{
191231200Smm  int e;
192231200Smm#ifdef HAVE_SIGACTION
193231200Smm  struct sigaction sa;
194231200Smm#else /* not HAVE_SIGACTION */
195231200Smm  void (*handler)(int);
196231200Smm#endif /* not HAVE_SIGACTION */
197231200Smm
198231200Smm  dlog("amu_ldap_unbind()\n");
199231200Smm
200231200Smm#ifdef HAVE_SIGACTION
201231200Smm  sa.sa_handler = SIG_IGN;
202231200Smm  sa.sa_flags = 0;
203231200Smm  sigemptyset(&(sa.sa_mask));
204231200Smm  sigaddset(&(sa.sa_mask), SIGPIPE);
205231200Smm  sigaction(SIGPIPE, &sa, &sa);	/* set IGNORE, and get old action */
206231200Smm#else /* not HAVE_SIGACTION */
207231200Smm  handler = signal(SIGPIPE, SIG_IGN);
208231200Smm#endif /* not HAVE_SIGACTION */
209231200Smm
210231200Smm  e = ldap_unbind(ld);
211231200Smm
212231200Smm#ifdef HAVE_SIGACTION
213231200Smm  sigemptyset(&(sa.sa_mask));
214231200Smm  sigaddset(&(sa.sa_mask), SIGPIPE);
215231200Smm  sigaction(SIGPIPE, &sa, NULL);
216231200Smm#else /* not HAVE_SIGACTION */
217231200Smm  (void) signal(SIGPIPE, handler);
218231200Smm#endif /* not HAVE_SIGACTION */
219231200Smm
220231200Smm  return e;
221231200Smm}
222231200Smm
223231200Smm
224231200Smmstatic void
225231200Smmald_free(ALD *a)
226231200Smm{
227231200Smm  he_free(a->hostent);
228231200Smm  cr_free(a->credentials);
229231200Smm  if (a->ldap != NULL)
230231200Smm    amu_ldap_unbind(a->ldap);
231231200Smm  XFREE(a);
232231200Smm}
233231200Smm
234231200Smm
235231200Smmint
236231200Smmamu_ldap_init(mnt_map *m, char *map, time_t *ts)
237231200Smm{
238231200Smm  ALD *aldh;
239231200Smm  CR *creds;
240231200Smm
241231200Smm  dlog("-> amu_ldap_init: map <%s>\n", map);
242231200Smm
243231200Smm  /*
244238856Smm   * XXX: by checking that map_type must be defined, aren't we
245231200Smm   * excluding the possibility of automatic searches through all
246231200Smm   * map types?
247231200Smm   */
248231200Smm  if (!gopt.map_type || !STREQ(gopt.map_type, AMD_LDAP_TYPE)) {
249231200Smm    dlog("amu_ldap_init called with map_type <%s>\n",
250231200Smm	 (gopt.map_type ? gopt.map_type : "null"));
251231200Smm  } else {
252231200Smm    dlog("Map %s is ldap\n", map);
253231200Smm  }
254231200Smm
255231200Smm  aldh = ALLOC(ALD);
256231200Smm  creds = ALLOC(CR);
257231200Smm  aldh->ldap = NULL;
258231200Smm  aldh->hostent = string2he(gopt.ldap_hostports);
259231200Smm  if (aldh->hostent == NULL) {
260231200Smm    plog(XLOG_USER, "Unable to parse hostport %s for ldap map %s",
261231200Smm	 gopt.ldap_hostports ? gopt.ldap_hostports : "(null)", map);
262231200Smm    XFREE(creds);
263238856Smm    XFREE(aldh);
264231200Smm    return (ENOENT);
265231200Smm  }
266231200Smm  creds->who = "";
267231200Smm  creds->pw = "";
268231200Smm  creds->method = LDAP_AUTH_SIMPLE;
269231200Smm  aldh->credentials = creds;
270231200Smm  aldh->timestamp = 0;
271231200Smm  aldh->ldap = NULL;
272231200Smm  dlog("Trying for %s:%d\n", aldh->hostent->host, aldh->hostent->port);
273231200Smm  if (amu_ldap_rebind(aldh)) {
274231200Smm    ald_free(aldh);
275231200Smm    return (ENOENT);
276231200Smm  }
277231200Smm  m->map_data = (void *) aldh;
278231200Smm  dlog("Bound to %s:%d\n", aldh->hostent->host, aldh->hostent->port);
279231200Smm  if (get_ldap_timestamp(aldh, map, ts))
280231200Smm    return (ENOENT);
281231200Smm  dlog("Got timestamp for map %s: %ld\n", map, (u_long) *ts);
282231200Smm
283231200Smm  return (0);
284231200Smm}
285231200Smm
286231200Smm
287231200Smmstatic int
288231200Smmamu_ldap_rebind(ALD *a)
289231200Smm{
290231200Smm  LDAP *ld;
291231200Smm  HE_ENT *h;
292231200Smm  CR *c = a->credentials;
293231200Smm  time_t now = clocktime(NULL);
294231200Smm  int try;
295231200Smm
296231200Smm  dlog("-> amu_ldap_rebind\n");
297231200Smm
298231200Smm  if (a->ldap != NULL) {
299231200Smm    if ((a->timestamp - now) > AMD_LDAP_TTL) {
300231200Smm      dlog("Re-establishing ldap connection\n");
301231200Smm      amu_ldap_unbind(a->ldap);
302231200Smm      a->timestamp = now;
303231200Smm      a->ldap = NULL;
304231200Smm    } else {
305231200Smm      /* Assume all is OK.  If it wasn't we'll be back! */
306231200Smm      dlog("amu_ldap_rebind: timestamp OK\n");
307231200Smm      return (0);
308231200Smm    }
309231200Smm  }
310231200Smm
311231200Smm  for (try=0; try<10; try++) {	/* XXX: try up to 10 times (makes sense?) */
312231200Smm    for (h = a->hostent; h != NULL; h = h->next) {
313231200Smm      if ((ld = ldap_open(h->host, h->port)) == NULL) {
314231200Smm	plog(XLOG_WARNING, "Unable to ldap_open to %s:%d\n", h->host, h->port);
315231200Smm	break;
316231200Smm      }
317231200Smm#if LDAP_VERSION_MAX > LDAP_VERSION2
318231200Smm      /* handle LDAPv3 and heigher, if available and amd.conf-igured */
319231200Smm      if (gopt.ldap_proto_version > LDAP_VERSION2) {
320231200Smm        if (!ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &gopt.ldap_proto_version)) {
321231200Smm          dlog("amu_ldap_rebind: LDAP protocol version set to %ld\n",
322231200Smm	       gopt.ldap_proto_version);
323231200Smm        } else {
324231200Smm          plog(XLOG_WARNING, "Unable to set ldap protocol version to %ld\n",
325231200Smm	       gopt.ldap_proto_version);
326231200Smm	  break;
327231200Smm        }
328231200Smm      }
329231200Smm#endif /* LDAP_VERSION_MAX > LDAP_VERSION2 */
330231200Smm      if (ldap_bind_s(ld, c->who, c->pw, c->method) != LDAP_SUCCESS) {
331231200Smm	plog(XLOG_WARNING, "Unable to ldap_bind to %s:%d as %s\n",
332231200Smm	     h->host, h->port, c->who);
333231200Smm	break;
334231200Smm      }
335231200Smm      if (gopt.ldap_cache_seconds > 0) {
336231200Smm#if defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE)
337231200Smm	ldap_enable_cache(ld, gopt.ldap_cache_seconds, gopt.ldap_cache_maxmem);
338231200Smm#else /* not defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE) */
339231200Smm	plog(XLOG_WARNING, "ldap_enable_cache(%ld) is not available on this system!\n", gopt.ldap_cache_seconds);
340231200Smm#endif /* not defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE) */
341231200Smm      }
342231200Smm      a->ldap = ld;
343231200Smm      a->timestamp = now;
344231200Smm      return (0);
345231200Smm    }
346231200Smm    plog(XLOG_WARNING, "Exhausted list of ldap servers, looping.\n");
347231200Smm  }
348231200Smm
349231200Smm  plog(XLOG_USER, "Unable to (re)bind to any ldap hosts\n");
350231200Smm  return (ENOENT);
351231200Smm}
352231200Smm
353231200Smm
354231200Smmstatic int
355228905Smmget_ldap_timestamp(ALD *a, char *map, time_t *ts)
356228753Smm{
357231200Smm  struct timeval tv;
358231200Smm  char **vals, *end;
359231200Smm  char filter[MAXPATHLEN];
360231200Smm  int i, err = 0, nentries = 0;
361231200Smm  LDAPMessage *res = NULL, *entry;
362231200Smm
363231200Smm  dlog("-> get_ldap_timestamp: map <%s>\n", map);
364231200Smm
365231200Smm  tv.tv_sec = 3;
366238856Smm  tv.tv_usec = 0;
367248616Smm  xsnprintf(filter, sizeof(filter), AMD_LDAP_TSFILTER, map);
368228753Smm  dlog("Getting timestamp for map %s\n", map);
369231200Smm  dlog("Filter is: %s\n", filter);
370228753Smm  dlog("Base is: %s\n", gopt.ldap_base);
371228753Smm  for (i = 0; i < AMD_LDAP_RETRIES; i++) {
372228753Smm    err = ldap_search_st(a->ldap,
373228753Smm			 gopt.ldap_base,
374228753Smm			 LDAP_SCOPE_SUBTREE,
375228753Smm			 filter,
376228753Smm			 0,
377228905Smm			 0,
378228753Smm			 &tv,
379231200Smm			 &res);
380231200Smm    if (err == LDAP_SUCCESS)
381231200Smm      break;
382228753Smm    if (res) {
383228753Smm      ldap_msgfree(res);
384228753Smm      res = NULL;
385228753Smm    }
386228753Smm    plog(XLOG_USER, "Timestamp LDAP search attempt %d failed: %s\n",
387231200Smm	 i + 1, ldap_err2string(err));
388228753Smm    if (err != LDAP_TIMEOUT) {
389228753Smm      dlog("get_ldap_timestamp: unbinding...\n");
390231200Smm      amu_ldap_unbind(a->ldap);
391231200Smm      a->ldap = NULL;
392231200Smm      if (amu_ldap_rebind(a))
393231200Smm        return (ENOENT);
394231200Smm    }
395231200Smm    dlog("Timestamp search failed, trying again...\n");
396228753Smm  }
397228753Smm
398228753Smm  if (err != LDAP_SUCCESS) {
399231200Smm    *ts = 0;
400228753Smm    plog(XLOG_USER, "LDAP timestamp search failed: %s\n",
401228753Smm	 ldap_err2string(err));
402231200Smm    if (res)
403231200Smm      ldap_msgfree(res);
404231200Smm    return (ENOENT);
405231200Smm  }
406231200Smm
407231200Smm  nentries = ldap_count_entries(a->ldap, res);
408228753Smm  if (nentries == 0) {
409228753Smm    plog(XLOG_USER, "No timestamp entry for map %s\n", map);
410228753Smm    *ts = 0;
411228753Smm    ldap_msgfree(res);
412228753Smm    return (ENOENT);
413231200Smm  }
414228753Smm
415228753Smm  entry = ldap_first_entry(a->ldap, res);
416228753Smm  vals = ldap_get_values(a->ldap, entry, AMD_LDAP_TSATTR);
417231200Smm  if (ldap_count_values(vals) == 0) {
418228753Smm    plog(XLOG_USER, "Missing timestamp value for map %s\n", map);
419228753Smm    *ts = 0;
420228753Smm    ldap_value_free(vals);
421228753Smm    ldap_msgfree(res);
422228753Smm    return (ENOENT);
423228753Smm  }
424228753Smm  dlog("TS value is:%s:\n", vals[0]);
425228753Smm
426228753Smm  if (vals[0]) {
427228753Smm    *ts = (time_t) strtol(vals[0], &end, 10);
428228753Smm    if (end == vals[0]) {
429228753Smm      plog(XLOG_USER, "Unable to decode ldap timestamp %s for map %s\n",
430228753Smm	   vals[0], map);
431228753Smm      err = ENOENT;
432231200Smm    }
433228753Smm    if (!*ts > 0) {
434228753Smm      plog(XLOG_USER, "Nonpositive timestamp %ld for map %s\n",
435228753Smm	   (u_long) *ts, map);
436231200Smm      err = ENOENT;
437228753Smm    }
438228753Smm  } else {
439228753Smm    plog(XLOG_USER, "Empty timestamp value for map %s\n", map);
440228753Smm    *ts = 0;
441228753Smm    err = ENOENT;
442228753Smm  }
443228753Smm
444228753Smm  ldap_value_free(vals);
445228753Smm  ldap_msgfree(res);
446228753Smm  dlog("The timestamp for %s is %ld (err=%d)\n", map, (u_long) *ts, err);
447228753Smm  return (err);
448228753Smm}
449228753Smm
450228753Smm
451228753Smmint
452228753Smmamu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts)
453228753Smm{
454228753Smm  char **vals, filter[MAXPATHLEN], filter2[2 * MAXPATHLEN];
455228753Smm  char *f1, *f2;
456238856Smm  struct timeval tv;
457228753Smm  int i, err = 0, nvals = 0, nentries = 0;
458228753Smm  LDAPMessage *entry, *res = NULL;
459228753Smm  ALD *a = (ALD *) (m->map_data);
460231200Smm
461228753Smm  dlog("-> amu_ldap_search: map <%s>, key <%s>\n", map, key);
462228753Smm
463228753Smm  tv.tv_sec = 2;
464238856Smm  tv.tv_usec = 0;
465238856Smm  if (a == NULL) {
466238856Smm    plog(XLOG_USER, "LDAP panic: no map data\n");
467238856Smm    return (EIO);
468238856Smm  }
469228753Smm  if (amu_ldap_rebind(a))	/* Check that's the handle is still valid */
470228753Smm    return (ENOENT);
471228753Smm
472228753Smm  xsnprintf(filter, sizeof(filter), AMD_LDAP_FILTER, map, key);
473228905Smm  /* "*" is special to ldap_search(); run through the filter escaping it. */
474228753Smm  f1 = filter; f2 = filter2;
475228753Smm  while (*f1) {
476231200Smm    if (*f1 == '*') {
477228753Smm      *f2++ = '\\'; *f2++ = '2'; *f2++ = 'a';
478231200Smm      f1++;
479231200Smm    } else {
480231200Smm      *f2++ = *f1++;
481231200Smm    }
482231200Smm  }
483231200Smm  *f2 = '\0';
484231200Smm  dlog("Search with filter: <%s>\n", filter2);
485231200Smm  for (i = 0; i < AMD_LDAP_RETRIES; i++) {
486231200Smm    err = ldap_search_st(a->ldap,
487231200Smm			 gopt.ldap_base,
488231200Smm			 LDAP_SCOPE_SUBTREE,
489228753Smm			 filter2,
490228753Smm			 0,
491228753Smm			 0,
492228753Smm			 &tv,
493228753Smm			 &res);
494231200Smm    if (err == LDAP_SUCCESS)
495231200Smm      break;
496228753Smm    if (res) {
497231200Smm      ldap_msgfree(res);
498228753Smm      res = NULL;
499228753Smm    }
500228753Smm    plog(XLOG_USER, "LDAP search attempt %d failed: %s\n",
501228753Smm        i + 1, ldap_err2string(err));
502228753Smm    if (err != LDAP_TIMEOUT) {
503231200Smm      dlog("amu_ldap_search: unbinding...\n");
504231200Smm      amu_ldap_unbind(a->ldap);
505231200Smm      a->ldap = NULL;
506231200Smm      if (amu_ldap_rebind(a))
507231200Smm        return (ENOENT);
508231200Smm    }
509231200Smm  }
510231200Smm
511231200Smm  switch (err) {
512231200Smm  case LDAP_SUCCESS:
513228753Smm    break;
514228753Smm  case LDAP_NO_SUCH_OBJECT:
515228753Smm    dlog("No object\n");
516231200Smm    if (res)
517231200Smm      ldap_msgfree(res);
518231200Smm    return (ENOENT);
519231200Smm  default:
520231200Smm    plog(XLOG_USER, "LDAP search failed: %s\n",
521231200Smm	 ldap_err2string(err));
522231200Smm    if (res)
523231200Smm      ldap_msgfree(res);
524231200Smm    return (EIO);
525231200Smm  }
526231200Smm
527231200Smm  nentries = ldap_count_entries(a->ldap, res);
528228753Smm  dlog("Search found %d entries\n", nentries);
529228753Smm  if (nentries == 0) {
530228753Smm    ldap_msgfree(res);
531228753Smm    return (ENOENT);
532231200Smm  }
533231200Smm  entry = ldap_first_entry(a->ldap, res);
534231200Smm  vals = ldap_get_values(a->ldap, entry, AMD_LDAP_ATTR);
535228753Smm  nvals = ldap_count_values(vals);
536228753Smm  if (nvals == 0) {
537228753Smm    plog(XLOG_USER, "Missing value for %s in map %s\n", key, map);
538228753Smm    ldap_value_free(vals);
539228753Smm    ldap_msgfree(res);
540228753Smm    return (EIO);
541228753Smm  }
542231200Smm  dlog("Map %s, %s => %s\n", map, key, vals[0]);
543231200Smm  if (vals[0]) {
544231200Smm    *pval = strdup(vals[0]);
545228753Smm    err = 0;
546228753Smm  } else {
547228753Smm    plog(XLOG_USER, "Empty value for %s in map %s\n", key, map);
548228753Smm    err = ENOENT;
549228753Smm  }
550228753Smm  ldap_msgfree(res);
551228753Smm  ldap_value_free(vals);
552231200Smm
553231200Smm  return (err);
554231200Smm}
555228753Smm
556228753Smm
557228753Smmint
558231200Smmamu_ldap_mtime(mnt_map *m, char *map, time_t *ts)
559231200Smm{
560231200Smm  ALD *aldh = (ALD *) (m->map_data);
561231200Smm
562231200Smm  if (aldh == NULL) {
563231200Smm    dlog("LDAP panic: unable to find map data\n");
564231200Smm    return (ENOENT);
565231200Smm  }
566231200Smm  if (amu_ldap_rebind(aldh)) {
567231200Smm    return (ENOENT);
568231200Smm  }
569231200Smm  if (get_ldap_timestamp(aldh, map, ts)) {
570231200Smm    return (ENOENT);
571231200Smm  }
572231200Smm  return (0);
573231200Smm}
574231200Smm