Am-Utils Cross Reference
am-utils/amd/info_ldap.c

source navigation ]
diff markup ]
identifier search ]
freetext search ]
file search ]
 
Version: 6.0.1 ] [ 6.0.2 ] [ 6.0.3 ] [ 6.0.4 ] [ 6.0.5 ] [ 6.0.6 ] [ 6.0.7 ] [ 6.0.8 ] [ 6.0.9 ] [ 6.0.10 ] [ 6.1 ] [ 6.1.1 ]

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
This page is hosted at the Filesystems and Storage Lab at Stony Brook.