]> git.pld-linux.org Git - packages/autofs.git/blame - autofs-5.0.4-use-srv-query-for-domain-dn.patch
- updated to 5.0.5, nfy.
[packages/autofs.git] / autofs-5.0.4-use-srv-query-for-domain-dn.patch
CommitLineData
e5fd101c
PS
1autofs-5.0.4 - use srv query for domain dn
2
3From: Ian Kent <raven@themaw.net>
4
5Add the ability to use a domain dn in the LDAP_URI configuration
6entry. If a domain dn is encountered in the LDAP_URI the list of
7servers will be queried and used for the LDAP connection. The list
8won't be queried again until the minimum ttl found in the SRV RR
9records is reached or, if ttl isn't given in any SRV RR records,
10after 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
27diff --git a/CHANGELOG b/CHANGELOG
28index 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 -----------------------
39diff --git a/include/dclist.h b/include/dclist.h
40new file mode 100644
41index 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
59diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
60index 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
80diff --git a/man/auto.master.5.in b/man/auto.master.5.in
81index 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
99diff --git a/modules/Makefile b/modules/Makefile
100index 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
116diff --git a/modules/dclist.c b/modules/dclist.c
117new file mode 100644
118index 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+}
907diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
908index 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;
1054diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
1055index 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
1076diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
1077index 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 0.195429 seconds and 4 git commands to generate.