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