]> git.pld-linux.org Git - packages/autofs.git/blob - autofs-5.0.4-use-srv-query-for-domain-dn.patch
- import latest patchset.
[packages/autofs.git] / autofs-5.0.4-use-srv-query-for-domain-dn.patch
1 autofs-5.0.4 - use srv query for domain dn
2
3 From: Ian Kent <raven@themaw.net>
4
5 Add the ability to use a domain dn in the LDAP_URI configuration
6 entry. If a domain dn is encountered in the LDAP_URI the list of
7 servers will be queried and used for the LDAP connection. The list
8 won't be queried again until the minimum ttl found in the SRV RR
9 records is reached or, if ttl isn't given in any SRV RR records,
10 after 1 hour.
11 ---
12
13  CHANGELOG                      |    1 
14  include/dclist.h               |   14 +
15  include/lookup_ldap.h          |    3 
16  man/auto.master.5.in           |    8 
17  modules/Makefile               |    5 
18  modules/dclist.c               |  785 ++++++++++++++++++++++++++++++++++++++++
19  modules/lookup_ldap.c          |   86 ++++
20  redhat/autofs.sysconfig.in     |   11 +
21  samples/autofs.conf.default.in |   11 +
22  9 files changed, 911 insertions(+), 13 deletions(-)
23  create mode 100644 include/dclist.h
24  create mode 100644 modules/dclist.c
25
26
27 diff --git a/CHANGELOG b/CHANGELOG
28 index 5000f0c..f49784a 100644
29 --- a/CHANGELOG
30 +++ b/CHANGELOG
31 @@ -49,6 +49,7 @@
32  - dont fail on ipv6 address when adding host.
33  - always read file maps multi map fix.
34  - always read file maps key lookup fixes.
35 +- use srv query for domain dn.
36  
37  4/11/2008 autofs-5.0.4
38  -----------------------
39 diff --git a/include/dclist.h b/include/dclist.h
40 new file mode 100644
41 index 0000000..ed89f97
42 --- /dev/null
43 +++ b/include/dclist.h
44 @@ -0,0 +1,14 @@
45 +#ifndef __DCLIST_H
46 +#define __DCLIST_H
47 +
48 +#include <sys/types.h>
49 +
50 +struct dclist {
51 +       time_t expire;
52 +       const char *uri;
53 +};
54 +
55 +struct dclist *get_dc_list(unsigned int logopt, const char *uri);
56 +void free_dclist(struct dclist *dclist);
57 +
58 +#endif
59 diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
60 index b47bf5d..dcae220 100644
61 --- a/include/lookup_ldap.h
62 +++ b/include/lookup_ldap.h
63 @@ -10,6 +10,8 @@
64  #include <krb5.h>
65  #endif
66  
67 +#include "dclist.h"
68 +
69  struct ldap_schema {
70         char *map_class;
71         char *map_attr;
72 @@ -57,6 +59,7 @@ struct lookup_context {
73         pthread_mutex_t uris_mutex;
74         struct list_head *uris;
75         struct ldap_uri *uri;
76 +       struct dclist *dclist;
77         char *cur_host;
78         struct ldap_searchdn *sdns;
79  
80 diff --git a/man/auto.master.5.in b/man/auto.master.5.in
81 index 7b7004f..71c4402 100644
82 --- a/man/auto.master.5.in
83 +++ b/man/auto.master.5.in
84 @@ -271,6 +271,14 @@ Map entries that include a server name override this option and it is then
85  not used. Default is an empty list in which case either the server given
86  in a map entry or the LDAP configured default is used. This uri list is read at
87  startup and whenever the daemon receives a HUP signal.
88 +.P
89 +This configuration option can also be used to request autofs lookup SRV RRs
90 +for a domain of the form <proto>:///[<domain dn>]. Note that a trailing
91 +"/" is not allowed when using this form. If the domain dn is not specified
92 +the dns domain name (if any) is used to construct the domain dn for the
93 +SRV RR lookup. The server list returned from an SRV RR lookup is refreshed
94 +according to the minimum ttl found in the SRV RR records or after one hour,
95 +whichever is less.
96  .TP
97  .B SEARCH_BASE
98  The base dn to use when searching for amap base dn. This entry may be
99 diff --git a/modules/Makefile b/modules/Makefile
100 index 0d12f01..13b3bd8 100644
101 --- a/modules/Makefile
102 +++ b/modules/Makefile
103 @@ -86,9 +86,10 @@ lookup_hesiod.so: lookup_hesiod.c
104  cyrus-sasl.o: cyrus-sasl.c
105         $(CC) $(CFLAGS) $(LDAP_FLAGS) -c $<
106  
107 -lookup_ldap.so: lookup_ldap.c $(SASL_OBJ)
108 +lookup_ldap.so: lookup_ldap.c dclist.o $(SASL_OBJ)
109         $(CC) $(SOLDFLAGS) $(CFLAGS) $(LDAP_FLAGS) -o lookup_ldap.so \
110 -               lookup_ldap.c $(SASL_OBJ) $(AUTOFS_LIB) $(LIBLDAP)
111 +               lookup_ldap.c dclist.o $(SASL_OBJ) \
112 +               $(AUTOFS_LIB) $(LIBLDAP) $(LIBRESOLV)
113         $(STRIP) lookup_ldap.so
114  
115  mount_nfs.so: mount_nfs.c replicated.o
116 diff --git a/modules/dclist.c b/modules/dclist.c
117 new file mode 100644
118 index 0000000..5b0e577
119 --- /dev/null
120 +++ b/modules/dclist.c
121 @@ -0,0 +1,785 @@
122 +/*
123 + * Copyright 2009 Ian Kent <raven@themaw.net>
124 + * Copyright 2009 Red Hat, Inc.
125 + *
126 + * This module was apapted from code contained in the Samba distribution
127 + * file source/libads/dns.c which contained the following copyright
128 + * information:
129 + *
130 + * Unix SMB/CIFS implementation.
131 + * DNS utility library
132 + * Copyright (C) Gerald (Jerry) Carter           2006.
133 + * Copyright (C) Jeremy Allison                  2007.
134 + *
135 + * This program is free software; you can redistribute it and/or modify
136 + * it under the terms of the GNU General Public License as published by
137 + * the Free Software Foundation; either version 3 of the License, or
138 + * (at your option) any later version.
139 + *
140 + * This program is distributed in the hope that it will be useful,
141 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
142 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
143 + * GNU General Public License for more details.
144 + *
145 + * You should have received a copy of the GNU General Public License
146 + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
147 +*/
148 +
149 +#include <netinet/in.h>
150 +#include <arpa/nameser.h>
151 +#include <stdlib.h>
152 +#include <string.h>
153 +#include <resolv.h>
154 +#include <netdb.h>
155 +#include <ldap.h>
156 +#include <sys/param.h>
157 +#include <errno.h>
158 +
159 +#include "automount.h"
160 +#include "dclist.h"
161 +
162 +#define        MAX_DNS_PACKET_SIZE     0xffff
163 +#define        MAX_DNS_NAME_LENGTH     MAXHOSTNAMELEN
164 +/* The longest time we will cache dns srv records */
165 +#define MAX_TTL                        (60*60*1) /* 1 hours */
166 +
167 +#ifdef NS_HFIXEDSZ     /* Bind 8/9 interface */
168 +#if !defined(C_IN)     /* AIX 5.3 already defines C_IN */
169 +#  define C_IN         ns_c_in
170 +#endif
171 +#if !defined(T_A)      /* AIX 5.3 already defines T_A */
172 +#  define T_A          ns_t_a
173 +#endif
174 +
175 +#  define T_SRV        ns_t_srv
176 +#if !defined(T_NS)     /* AIX 5.3 already defines T_NS */
177 +#  define T_NS                 ns_t_ns
178 +#endif
179 +#else
180 +#  ifdef HFIXEDSZ
181 +#    define NS_HFIXEDSZ HFIXEDSZ
182 +#  else
183 +#    define NS_HFIXEDSZ sizeof(HEADER)
184 +#  endif       /* HFIXEDSZ */
185 +#  ifdef PACKETSZ
186 +#    define NS_PACKETSZ        PACKETSZ
187 +#  else        /* 512 is usually the default */
188 +#    define NS_PACKETSZ        512
189 +#  endif       /* PACKETSZ */
190 +#  define T_SRV        33
191 +#endif
192 +
193 +#define SVAL(buf, pos) (*(const uint16_t *)((const char *)(buf) + (pos)))
194 +#define IVAL(buf, pos) (*(const uint32_t *)((const char *)(buf) + (pos)))
195 +
196 +#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
197 +#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
198 +
199 +#define RSVAL(buf, pos) SREV(SVAL(buf, pos))
200 +#define RIVAL(buf, pos) IREV(IVAL(buf, pos))
201 +
202 +#define QSORT_CAST     (int (*)(const void *, const void *))
203 +
204 +/* DNS query section in replies */
205 +
206 +struct dns_query {
207 +       const char *hostname;
208 +       uint16_t type;
209 +       uint16_t in_class;
210 +};
211 +
212 +/* DNS RR record in reply */
213 +
214 +struct dns_rr {
215 +       const char *hostname;
216 +       uint16_t type;
217 +       uint16_t in_class;
218 +       uint32_t ttl;
219 +       uint16_t rdatalen;
220 +       uint8_t *rdata;
221 +};
222 +
223 +/* SRV records */
224 +
225 +struct dns_rr_srv {
226 +       const char *hostname;
227 +       uint16_t priority;
228 +       uint16_t weight;
229 +       uint16_t port;
230 +       uint32_t ttl;
231 +};
232 +
233 +static pthread_mutex_t dclist_mutex = PTHREAD_MUTEX_INITIALIZER;
234 +
235 +static void dclist_mutex_lock(void)
236 +{
237 +       int status = pthread_mutex_lock(&dclist_mutex);
238 +       if (status)
239 +               fatal(status);
240 +       return;
241 +}
242 +
243 +static void dclist_mutex_unlock(void)
244 +{
245 +       int status = pthread_mutex_unlock(&dclist_mutex);
246 +       if (status)
247 +               fatal(status);
248 +       return;
249 +}
250 +
251 +static int dns_parse_query(unsigned int logopt,
252 +                          uint8_t *start, uint8_t *end,
253 +                          uint8_t **ptr, struct dns_query *q)
254 +{
255 +       uint8_t *p = *ptr;
256 +       char hostname[MAX_DNS_NAME_LENGTH];
257 +       char buf[MAX_ERR_BUF];
258 +       int namelen;
259 +
260 +       if (!start || !end || !q || !*ptr)
261 +               return 0;
262 +
263 +       memset(q, 0, sizeof(*q));
264 +
265 +       /* See RFC 1035 for details. If this fails, then return. */
266 +
267 +       namelen = dn_expand(start, end, p, hostname, sizeof(hostname));
268 +       if (namelen < 0) {
269 +               error(logopt, "failed to expand query hostname");
270 +               return 0;
271 +       }
272 +
273 +       p += namelen;
274 +       q->hostname = strdup(hostname);
275 +       if (!q) {
276 +               char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
277 +               error(logopt, "strdup: %s", estr);
278 +               return 0;
279 +       }
280 +
281 +       /* check that we have space remaining */
282 +
283 +       if (p + 4 > end) {
284 +               error(logopt, "insufficient buffer space for result");
285 +               free((void *) q->hostname);
286 +               return 0;
287 +       }
288 +
289 +       q->type     = RSVAL(p, 0);
290 +       q->in_class = RSVAL(p, 2);
291 +       p += 4;
292 +
293 +       *ptr = p;
294 +
295 +       return 1;
296 +}
297 +
298 +static int dns_parse_rr(unsigned int logopt,
299 +                       uint8_t *start, uint8_t *end,
300 +                       uint8_t **ptr, struct dns_rr *rr)
301 +{
302 +       uint8_t *p = *ptr;
303 +       char hostname[MAX_DNS_NAME_LENGTH];
304 +       char buf[MAX_ERR_BUF];
305 +       int namelen;
306 +
307 +       if (!start || !end || !rr || !*ptr)
308 +               return 0;
309 +
310 +       memset(rr, 0, sizeof(*rr));
311 +
312 +       /* pull the name from the answer */
313 +
314 +       namelen = dn_expand(start, end, p, hostname, sizeof(hostname));
315 +       if (namelen < 0) {
316 +               error(logopt, "failed to expand query hostname");
317 +               return 0;
318 +       }
319 +       p += namelen;
320 +       rr->hostname = strdup(hostname);
321 +       if (!rr->hostname) {
322 +               char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
323 +               error(logopt, "strdup: %s", estr);
324 +               return 0;
325 +       }
326 +
327 +       /* check that we have space remaining */
328 +
329 +       if (p + 10 > end) {
330 +               error(logopt, "insufficient buffer space for result");
331 +               free((void *) rr->hostname);
332 +               return 0;
333 +       }
334 +
335 +       /* pull some values and then skip onto the string */
336 +
337 +       rr->type     = RSVAL(p, 0);
338 +       rr->in_class = RSVAL(p, 2);
339 +       rr->ttl      = RIVAL(p, 4);
340 +       rr->rdatalen = RSVAL(p, 8);
341 +
342 +       p += 10;
343 +
344 +       /* sanity check the available space */
345 +
346 +       if (p + rr->rdatalen > end) {
347 +               error(logopt, "insufficient buffer space for data");
348 +               free((void *) rr->hostname);
349 +               return 0;
350 +       }
351 +
352 +       /* save a point to the rdata for this section */
353 +
354 +       rr->rdata = p;
355 +       p += rr->rdatalen;
356 +
357 +       *ptr = p;
358 +
359 +       return 1;
360 +}
361 +
362 +static int dns_parse_rr_srv(unsigned int logopt,
363 +                           uint8_t *start, uint8_t *end,
364 +                           uint8_t **ptr, struct dns_rr_srv *srv)
365 +{
366 +       struct dns_rr rr;
367 +       uint8_t *p;
368 +       char dcname[MAX_DNS_NAME_LENGTH];
369 +       char buf[MAX_ERR_BUF];
370 +       int namelen;
371 +
372 +       if (!start || !end || !srv || !*ptr)
373 +               return 0;
374 +
375 +       /* Parse the RR entry.  Coming out of the this, ptr is at the beginning
376 +          of the next record */
377 +
378 +       if (!dns_parse_rr(logopt, start, end, ptr, &rr)) {
379 +               error(logopt, "Failed to parse RR record");
380 +               return 0;
381 +       }
382 +
383 +       if (rr.type != T_SRV) {
384 +               error(logopt, "Bad answer type (%d)", rr.type);
385 +               return 0;
386 +       }
387 +
388 +       p = rr.rdata;
389 +
390 +       srv->priority = RSVAL(p, 0);
391 +       srv->weight   = RSVAL(p, 2);
392 +       srv->port     = RSVAL(p, 4);
393 +       srv->ttl      = rr.ttl;
394 +
395 +       p += 6;
396 +
397 +       namelen = dn_expand(start, end, p, dcname, sizeof(dcname));
398 +       if (namelen < 0) {
399 +               error(logopt, "Failed to expand dcname");
400 +               return 0;
401 +       }
402 +
403 +       srv->hostname = strdup(dcname);
404 +       if (!srv->hostname) {
405 +               char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
406 +               error(logopt, "strdup: %s", estr);
407 +               return 0;
408 +       }
409 +
410 +       debug(logopt, "Parsed %s [%u, %u, %u]",
411 +             srv->hostname, srv->priority, srv->weight, srv->port);
412 +
413 +       return 1;
414 +}
415 +
416 +/*********************************************************************
417 + Sort SRV record list based on weight and priority.  See RFC 2782.
418 +*********************************************************************/
419 +
420 +static int dnssrvcmp(struct dns_rr_srv *a, struct dns_rr_srv *b)
421 +{
422 +       if (a->priority == b->priority) {
423 +               /* randomize entries with an equal weight and priority */
424 +               if (a->weight == b->weight)
425 +                       return 0;
426 +
427 +               /* higher weights should be sorted lower */
428 +               if (a->weight > b->weight)
429 +                       return -1;
430 +               else
431 +                       return 1;
432 +       }
433 +
434 +       if (a->priority < b->priority)
435 +               return -1;
436 +
437 +       return 1;
438 +}
439 +
440 +#define DNS_FAILED_WAITTIME          30
441 +
442 +static int dns_send_req(unsigned int logopt,
443 +                       const char *name, int q_type, uint8_t **rbuf,
444 +                       int *resp_length)
445 +{
446 +       uint8_t *buffer = NULL;
447 +       size_t buf_len = 0;
448 +       int resp_len = NS_PACKETSZ;
449 +       static time_t last_dns_check = 0;
450 +       static unsigned int last_dns_status = 0;
451 +       time_t now = time(NULL);
452 +       char buf[MAX_ERR_BUF];
453 +
454 +       /* Try to prevent bursts of DNS lookups if the server is down */
455 +
456 +       /* Protect against large clock changes */
457 +
458 +       if (last_dns_check > now)
459 +               last_dns_check = 0;
460 +
461 +       /* IF we had a DNS timeout or a bad server and we are still
462 +          in the 30 second cache window, just return the previous
463 +          status and save the network timeout. */
464 +
465 +       if ((last_dns_status == ETIMEDOUT ||
466 +            last_dns_status == ECONNREFUSED) &&
467 +            ((last_dns_check + DNS_FAILED_WAITTIME) > now)) {
468 +               char *estr = strerror_r(last_dns_status, buf, MAX_ERR_BUF);
469 +               debug(logopt, "Returning cached status (%s)", estr);
470 +               return last_dns_status;
471 +       }
472 +
473 +       /* Send the Query */
474 +       do {
475 +               if (buffer)
476 +                       free(buffer);
477 +
478 +               buf_len = resp_len * sizeof(uint8_t);
479 +
480 +               if (buf_len) {
481 +                       buffer = malloc(buf_len);
482 +                       if (!buffer) {
483 +                               char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
484 +                               error(logopt, "malloc: %s", estr);
485 +                               last_dns_status = ENOMEM;
486 +                               last_dns_check = time(NULL);
487 +                               return last_dns_status;
488 +                       }
489 +               }
490 +
491 +               resp_len = res_query(name, C_IN, q_type, buffer, buf_len);
492 +               if (resp_len < 0) {
493 +                       char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
494 +                       error(logopt, "Failed to resolve %s (%s)", name, estr);
495 +                       free(buffer);
496 +                       last_dns_status = ENOENT;
497 +                       last_dns_check = time(NULL);
498 +                       return last_dns_status;
499 +               }
500 +
501 +               /* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8)
502 +                  truncated replies never give back a resp_len > buflen
503 +                  which ends up causing DNS resolve failures on large tcp DNS replies */
504 +
505 +               if (buf_len == resp_len) {
506 +                       if (resp_len == MAX_DNS_PACKET_SIZE) {
507 +                               error(logopt,
508 +                                     "DNS reply too large when resolving %s",
509 +                                     name);
510 +                               free(buffer);
511 +                               last_dns_status = EMSGSIZE;
512 +                               last_dns_check = time(NULL);
513 +                               return last_dns_status;
514 +                       }
515 +
516 +                       resp_len = MIN(resp_len * 2, MAX_DNS_PACKET_SIZE);
517 +               }
518 +       } while (buf_len < resp_len && resp_len <= MAX_DNS_PACKET_SIZE);
519 +
520 +       *rbuf = buffer;
521 +       *resp_length = resp_len;
522 +
523 +       last_dns_check = time(NULL);
524 +       last_dns_status = 0;
525 +
526 +       return 0;
527 +}
528 +
529 +static int dns_lookup_srv(unsigned int logopt, const char *name,
530 +                         struct dns_rr_srv **dclist, int *numdcs)
531 +{
532 +       uint8_t *buffer = NULL;
533 +       int resp_len = 0;
534 +       struct dns_rr_srv *dcs = NULL;
535 +       int query_count, answer_count;
536 +       uint8_t *p = buffer;
537 +       int rrnum;
538 +       int idx = 0;
539 +       char buf[MAX_ERR_BUF];
540 +       int ret;
541 +
542 +       if (!name || !dclist)
543 +               return -EINVAL;
544 +
545 +       /* Send the request.  May have to loop several times in case
546 +          of large replies */
547 +
548 +       ret = dns_send_req(logopt, name, T_SRV, &buffer, &resp_len);
549 +       if (ret) {
550 +               error(logopt, "Failed to send DNS query");
551 +               return ret;
552 +       }
553 +       p = buffer;
554 +
555 +       /* For some insane reason, the ns_initparse() et. al. routines are only
556 +          available in libresolv.a, and not the shared lib.  Who knows why....
557 +          So we have to parse the DNS reply ourselves */
558 +
559 +       /* Pull the answer RR's count from the header.
560 +        * Use the NMB ordering macros */
561 +
562 +       query_count      = RSVAL(p, 4);
563 +       answer_count     = RSVAL(p, 6);
564 +
565 +       debug(logopt,
566 +             "%d records returned in the answer section.",
567 +              answer_count);
568 +
569 +       if (answer_count) {
570 +               dcs = malloc(sizeof(struct dns_rr_srv) * answer_count);
571 +               if (!dcs) {
572 +                       char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
573 +                       error(logopt, "malloc: %s", estr);
574 +                       free(buffer);
575 +                       return ENOMEM;
576 +               }
577 +       }
578 +
579 +       /* now skip the header */
580 +
581 +       p += NS_HFIXEDSZ;
582 +
583 +       /* parse the query section */
584 +
585 +       for (rrnum = 0; rrnum < query_count; rrnum++) {
586 +               struct dns_query q;
587 +
588 +               ret = dns_parse_query(logopt, buffer, buffer+resp_len, &p, &q);
589 +               if (!ret) {
590 +                       error(logopt,
591 +                             "Failed to parse query record [%d]", rrnum);
592 +                       free(buffer);
593 +                       free(dcs);
594 +                       return EBADMSG;
595 +               }
596 +       }
597 +
598 +       /* now we are at the answer section */
599 +
600 +       for (rrnum = 0; rrnum < answer_count; rrnum++) {
601 +               ret = dns_parse_rr_srv(logopt,
602 +                                      buffer, buffer+resp_len,
603 +                                      &p, &dcs[rrnum]);
604 +               if (!ret) {
605 +                       error(logopt,
606 +                             "Failed to parse answer record [%d]", rrnum);
607 +                       free(buffer);
608 +                       free(dcs);
609 +                       return EBADMSG;
610 +               }
611 +       }
612 +       idx = rrnum;
613 +
614 +       qsort(dcs, idx, sizeof(struct dns_rr_srv), QSORT_CAST dnssrvcmp);
615 +
616 +       *dclist = dcs;
617 +       *numdcs = idx;
618 +
619 +       return 0;
620 +}
621 +
622 +static char *escape_dn_commas(const char *uri)
623 +{
624 +       size_t len = strlen(uri);
625 +       char *new, *tmp, *ptr;
626 +
627 +       ptr = (char *) uri;
628 +       while (*ptr) {
629 +               if (*ptr == '\\')
630 +                       ptr += 2;
631 +               if (*ptr == ',')
632 +                       len += 2;
633 +               ptr++;
634 +       }
635 +
636 +       new = malloc(len + 1);
637 +       if (!new)
638 +               return NULL;
639 +       memset(new, 0, len + 1);
640 +
641 +       ptr = (char *) uri;
642 +       tmp = new;
643 +       while (*ptr) {
644 +               if (*ptr == '\\') {
645 +                       ptr++;
646 +                       *tmp++ = *ptr++;
647 +                       continue;
648 +               }
649 +               if (*ptr == ',') {
650 +                       strcpy(tmp, "%2c");
651 +                       ptr++;
652 +                       tmp += 3;
653 +                       continue;
654 +               }
655 +               *tmp++ = *ptr++;
656 +       }
657 +
658 +       return new;
659 +}
660 +
661 +void free_dclist(struct dclist *dclist)
662 +{
663 +       if (dclist->uri)
664 +               free((void *) dclist->uri);
665 +       free(dclist);
666 +}
667 +
668 +static char *getdnsdomainname(unsigned int logopt)
669 +{
670 +       struct addrinfo hints, *ni;
671 +       char name[MAX_DNS_NAME_LENGTH + 1];
672 +       char buf[MAX_ERR_BUF];
673 +       char *dnsdomain = NULL;
674 +       char *ptr;
675 +       int ret;
676 +
677 +       memset(name, 0, sizeof(name));
678 +       if (gethostname(name, MAX_DNS_NAME_LENGTH) == -1) {
679 +               char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
680 +               error(logopt, "gethostname: %s", estr);
681 +               return NULL;
682 +       }
683 +
684 +       memset(&hints, 0, sizeof(hints));
685 +       hints.ai_flags = AI_CANONNAME;
686 +       hints.ai_family = AF_UNSPEC;
687 +       hints.ai_socktype = SOCK_DGRAM;
688 +
689 +       ret = getaddrinfo(name, NULL, &hints, &ni);
690 +       if (ret) {
691 +               error(logopt, "hostname lookup failed: %s", gai_strerror(ret));
692 +               return NULL;
693 +       }
694 +
695 +       ptr = ni->ai_canonname;
696 +       while (*ptr && *ptr != '.')
697 +               ptr++;
698 +
699 +       if (*++ptr)
700 +               dnsdomain = strdup(ptr);
701 +
702 +       freeaddrinfo(ni);
703 +
704 +       return dnsdomain;
705 +}
706 +
707 +struct dclist *get_dc_list(unsigned int logopt, const char *uri)
708 +{
709 +       LDAPURLDesc *ludlist = NULL;
710 +       LDAPURLDesc **ludp;
711 +       struct dns_rr_srv *dcs;
712 +       unsigned int min_ttl = MAX_TTL;
713 +       struct dclist *dclist = NULL;;
714 +       char buf[MAX_ERR_BUF];
715 +       char *dn_uri, *esc_uri;
716 +       char *domain;
717 +       char *list;
718 +       int numdcs;
719 +       int ret;
720 +
721 +       if (strcmp(uri, "ldap:///") && strcmp(uri, "ldaps:///")) {
722 +               dn_uri = strdup(uri);
723 +               if (!dn_uri) {
724 +                       char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
725 +                       error(logopt, "strdup: %s", estr);
726 +                       return NULL;
727 +               }
728 +       } else {
729 +               char *dnsdomain;
730 +               char *hdn;
731 +
732 +               dnsdomain = getdnsdomainname(logopt);
733 +               if (!dnsdomain) {
734 +                       error(logopt, "failed to get dns domainname");
735 +                       return NULL;
736 +               }
737 +
738 +               if (ldap_domain2dn(dnsdomain, &hdn) || hdn == NULL) {
739 +                       error(logopt,
740 +                             "Could not turn domain \"%s\" into a dn\n",
741 +                             dnsdomain);
742 +                       free(dnsdomain);
743 +                       return NULL;
744 +               }
745 +               free(dnsdomain);
746 +
747 +               dn_uri = malloc(strlen(uri) + strlen(hdn) + 1);
748 +               if (!dn_uri) {
749 +                       char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
750 +                       error(logopt, "malloc: %s", estr);
751 +                       ber_memfree(hdn);
752 +                       return NULL;
753 +               }
754 +
755 +               strcpy(dn_uri, uri);
756 +               strcat(dn_uri, hdn);
757 +               ber_memfree(hdn);
758 +       }
759 +
760 +       esc_uri = escape_dn_commas(dn_uri);
761 +       if (!esc_uri) {
762 +               error(logopt, "Could not escape commas in uri %s", dn_uri);
763 +               free(dn_uri);
764 +               return NULL;
765 +       }
766 +
767 +       ret = ldap_url_parse(esc_uri, &ludlist);
768 +       if (ret != LDAP_URL_SUCCESS) {
769 +               error(logopt, "Could not parse uri %s (%d)", dn_uri, ret);
770 +               free(esc_uri);
771 +               free(dn_uri);
772 +               return NULL;
773 +       }
774 +
775 +       free(esc_uri);
776 +
777 +       if (!ludlist) {
778 +               error(logopt, "No dn found in uri %s", dn_uri);
779 +               free(dn_uri);
780 +               return NULL;
781 +       }
782 +
783 +       free(dn_uri);
784 +
785 +       dclist = malloc(sizeof(struct dclist));
786 +       if (!dclist) {
787 +               char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
788 +               error(logopt, "malloc: %s", estr);
789 +               ldap_free_urldesc(ludlist);
790 +               return NULL;
791 +       }
792 +       memset(dclist, 0, sizeof(struct dclist));
793 +
794 +       list = NULL;
795 +       for (ludp = &ludlist; *ludp != NULL;) {
796 +               LDAPURLDesc *lud = *ludp;
797 +               size_t req_len, len;
798 +               char *request = NULL;
799 +               char *tmp;
800 +               int i;
801 +
802 +               if (!lud->lud_dn && !lud->lud_dn[0] &&
803 +                  (!lud->lud_host || !lud->lud_host[0])) {
804 +                       *ludp = lud->lud_next;
805 +                       continue;
806 +               }
807 +
808 +               domain = NULL;
809 +               if (ldap_dn2domain(lud->lud_dn, &domain) || domain == NULL) {
810 +                       error(logopt,
811 +                             "Could not turn dn \"%s\" into a domain",
812 +                             lud->lud_dn);
813 +                       *ludp = lud->lud_next;
814 +                       continue;
815 +               }
816 +
817 +               debug(logopt, "doing lookup of SRV RRs for domain %s", domain);
818 +
819 +               req_len = sizeof("_ldap._tcp.") + strlen(domain);
820 +               request = malloc(req_len);
821 +               if (!request) {
822 +                       char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
823 +                       error(logopt, "malloc: %s", estr);
824 +                       goto out_error;
825 +               }
826 +
827 +               ret = snprintf(request, req_len, "_ldap._tcp.%s", domain);
828 +               if (ret >= req_len) {
829 +                       free(request);
830 +                       goto out_error;
831 +               }
832 +
833 +               dclist_mutex_lock();
834 +               if (dns_lookup_srv(logopt, request, &dcs, &numdcs)) {
835 +                       error(logopt,
836 +                             "DNS SRV query failed for domain %s", domain);
837 +                       dclist_mutex_unlock();
838 +                       free(request);
839 +                       goto out_error;
840 +               }
841 +               dclist_mutex_unlock();
842 +               free(request);
843 +
844 +               len = strlen(lud->lud_scheme);
845 +               len += sizeof("://");
846 +               len *= numdcs;
847 +
848 +               for (i = 0; i < numdcs; i++) {
849 +                       if (dcs[i].ttl > 0 && dcs[i].ttl < min_ttl)
850 +                               min_ttl = dcs[i].ttl;
851 +                       len += strlen(dcs[i].hostname);
852 +                       if (dcs[i].port > 0)
853 +                               len += sizeof(":65535");
854 +               }
855 +
856 +               tmp = realloc(list, len);
857 +               if (!tmp) {
858 +                       char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
859 +                       error(logopt, "realloc: %s", estr);
860 +                       goto out_error;
861 +               }
862 +
863 +               if (!list)
864 +                       memset(tmp, 0, len);
865 +               else
866 +                       strcat(tmp, " ");
867 +
868 +               for (i = 0; i < numdcs; i++) {
869 +                       if (i > 0)
870 +                               strcat(tmp, " ");
871 +                       strcat(tmp, lud->lud_scheme);
872 +                       strcat(tmp, "://");
873 +                       strcat(tmp, dcs[i].hostname);
874 +                       if (dcs[i].port > 0) {
875 +                               char port[7];
876 +                               ret = snprintf(port, 7, ":%d", dcs[i].port);
877 +                               if (ret > 6) {
878 +                                       error(logopt,
879 +                                             "invalid port: %u", dcs[i].port);
880 +                                       goto out_error;
881 +                               }
882 +                               strcat(tmp, port);
883 +                       }
884 +               }
885 +               list = tmp;
886 +
887 +               *ludp = lud->lud_next;
888 +               ber_memfree(domain);
889 +       }
890 +
891 +       ldap_free_urldesc(ludlist);
892 +
893 +       dclist->expire = time(NULL) + min_ttl;
894 +       dclist->uri = list;
895 +
896 +       return dclist;
897 +
898 +out_error:
899 +       if (list)
900 +               free(list);
901 +       if (domain)
902 +               ber_memfree(domain);
903 +       ldap_free_urldesc(ludlist);
904 +       free_dclist(dclist);
905 +       return NULL;
906 +}
907 diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
908 index a847622..f6b3f42 100644
909 --- a/modules/lookup_ldap.c
910 +++ b/modules/lookup_ldap.c
911 @@ -643,14 +643,26 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt)
912         LDAP *ldap = NULL;
913         struct ldap_uri *this;
914         struct list_head *p, *first;
915 +       struct dclist *dclist = NULL;
916 +       char *uri = NULL;
917  
918 -       /* Try each uri in list, add connect fails to tmp list */
919         uris_mutex_lock(ctxt);
920 +       if (ctxt->dclist) {
921 +               dclist = ctxt->dclist;
922 +               if (ctxt->dclist->expire < time(NULL)) {
923 +                       free_dclist(ctxt->dclist);
924 +                       ctxt->dclist = NULL;
925 +                       dclist = NULL;
926 +               }
927 +       }
928         if (!ctxt->uri)
929                 first = ctxt->uris;
930         else
931                 first = &ctxt->uri->list;
932         uris_mutex_unlock(ctxt);
933 +
934 +
935 +       /* Try each uri, save point in server list upon success */
936         p = first->next;
937         while(p != first) {
938                 /* Skip list head */
939 @@ -659,25 +671,62 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt)
940                         continue;
941                 }
942                 this = list_entry(p, struct ldap_uri, list);
943 -               debug(logopt, "trying server %s", this->uri);
944 -               ldap = connect_to_server(logopt, this->uri, ctxt);
945 +               if (!strstr(this->uri, ":///"))
946 +                       uri = strdup(this->uri);
947 +               else {
948 +                       if (dclist)
949 +                               uri = strdup(dclist->uri);
950 +                       else {
951 +                               struct dclist *tmp;
952 +                               tmp = get_dc_list(logopt, this->uri);
953 +                               if (!tmp) {
954 +                                       p = p->next;
955 +                                       continue;
956 +                               }
957 +                               dclist = tmp;
958 +                               uri = strdup(dclist->uri);
959 +                       }
960 +               }
961 +               if (!uri) {
962 +                       p = p->next;
963 +                       continue;
964 +               }
965 +               debug(logopt, "trying server uri %s", uri);
966 +               ldap = connect_to_server(logopt, uri, ctxt);
967                 if (ldap) {
968 -                       info(logopt, "connected to uri %s", this->uri);
969 -                       uris_mutex_lock(ctxt);
970 -                       ctxt->uri = this;
971 -                       uris_mutex_unlock(ctxt);
972 +                       info(logopt, "connected to uri %s", uri);
973 +                       free(uri);
974                         break;
975                 }
976 +               free(uri);
977 +               uri = NULL;
978 +               free_dclist(dclist);
979 +               dclist = NULL;
980                 p = p->next;
981         }
982  
983 +       uris_mutex_lock(ctxt);
984 +       if (ldap)
985 +               ctxt->uri = this;
986 +       if (dclist) {
987 +               if (!ctxt->dclist)
988 +                       ctxt->dclist = dclist;
989 +               else {
990 +                       if (ctxt->dclist != dclist) {
991 +                               free_dclist(ctxt->dclist);
992 +                               ctxt->dclist = dclist;
993 +                       }
994 +               }
995 +       }
996 +       uris_mutex_unlock(ctxt);
997 +
998         return ldap;
999  }
1000  
1001  static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
1002  {
1003 -       struct ldap_uri *this;
1004         LDAP *ldap;
1005 +       char *uri;
1006  
1007         if (ctxt->server || !ctxt->uris) {
1008                 ldap = do_connect(logopt, ctxt->server, ctxt);
1009 @@ -692,9 +741,20 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
1010         }
1011  
1012         uris_mutex_lock(ctxt);
1013 -       this = ctxt->uri;
1014 +       if (ctxt->dclist)
1015 +               uri = strdup(ctxt->dclist->uri);
1016 +       else
1017 +               uri = strdup(ctxt->uri->uri);
1018         uris_mutex_unlock(ctxt);
1019 -       ldap = do_connect(logopt, this->uri, ctxt);
1020 +
1021 +       if (!uri) {
1022 +               char buf[MAX_ERR_BUF];
1023 +               char *estr = strerror_r(errno, buf, sizeof(buf));
1024 +               crit(logopt, MODPREFIX "strdup: %s", estr);
1025 +               return NULL;
1026 +       }
1027 +
1028 +       ldap = do_connect(logopt, uri, ctxt);
1029  #ifdef WITH_SASL
1030         /*
1031          * Dispose of the sasl authentication connection and try the
1032 @@ -702,9 +762,11 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
1033          */
1034         if (!ldap) {
1035                 autofs_sasl_dispose(ctxt);
1036 -               ldap = connect_to_server(logopt, this->uri, ctxt);
1037 +               ldap = connect_to_server(logopt, uri, ctxt);
1038         }
1039  #endif
1040 +       free(uri);
1041 +
1042         if (ldap)
1043                 return ldap;
1044  
1045 @@ -1296,6 +1358,8 @@ static void free_context(struct lookup_context *ctxt)
1046                 fatal(ret);
1047         if (ctxt->sdns)
1048                 defaults_free_searchdns(ctxt->sdns);
1049 +       if (ctxt->dclist)
1050 +               free_dclist(ctxt->dclist);
1051         free(ctxt);
1052  
1053         return;
1054 diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
1055 index 97e20fe..37448ea 100644
1056 --- a/redhat/autofs.sysconfig.in
1057 +++ b/redhat/autofs.sysconfig.in
1058 @@ -50,6 +50,17 @@ BROWSE_MODE="no"
1059  #           Map entries that include a server name override
1060  #           this option.
1061  #
1062 +#           This configuration option can also be used to
1063 +#           request autofs lookup SRV RRs for a domain of
1064 +#           the form <proto>:///[<domain dn>]. Note that a
1065 +#           trailing "/" is not allowed when using this form.
1066 +#           If the domain dn is not specified the dns domain
1067 +#           name (if any) is used to construct the domain dn
1068 +#           for the SRV RR lookup. The server list returned
1069 +#           from an SRV RR lookup is refreshed according to
1070 +#           the minimum ttl found in the SRV RR records or
1071 +#           after one hour, whichever is less.
1072 +#
1073  #LDAP_URI=""
1074  #
1075  # LDAP__TIMEOUT - timeout value for the synchronous API  calls
1076 diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
1077 index 62084c2..7dee5fd 100644
1078 --- a/samples/autofs.conf.default.in
1079 +++ b/samples/autofs.conf.default.in
1080 @@ -48,6 +48,17 @@ BROWSE_MODE="no"
1081  #           Map entries that include a server name override
1082  #           this option.
1083  #
1084 +#           This configuration option can also be used to
1085 +#           request autofs lookup SRV RRs for a domain of
1086 +#           the form <proto>:///[<domain dn>]. Note that a
1087 +#           trailing "/" is not allowed when using this form.
1088 +#           If the domain dn is not specified the dns domain
1089 +#           name (if any) is used to construct the domain dn
1090 +#           for the SRV RR lookup. The server list returned
1091 +#           from an SRV RR lookup is refreshed according to
1092 +#           the minimum ttl found in the SRV RR records or
1093 +#           after one hour, whichever is less.
1094 +#
1095  #LDAP_URI=""
1096  #
1097  # LDAP__TIMEOUT - timeout value for the synchronous API  calls
This page took 1.664223 seconds and 3 git commands to generate.