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