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