From 551295f1596b8ebe8c6a94d36aa5826517646141 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Jun 12 2009 09:18:59 +0000 Subject: - add support for LDAP_URI="ldap:///" SRV RR lookup. - fix incorrect dclist free. - srv lookup handle endianness. - fix bug introduced by library reload changes which causes autofs to not release mount thread resources when using submounts. - fix notify mount message path. - try harder to work out if we created mount point at remount. - fix double free in do_sasl_bind(). - manual umount recovery fixes. - fix map type info parse error. --- diff --git a/autofs-5.0.4-fix-double-free-in-do_sasl_bind.patch b/autofs-5.0.4-fix-double-free-in-do_sasl_bind.patch new file mode 100644 index 0000000..a9e28a6 --- /dev/null +++ b/autofs-5.0.4-fix-double-free-in-do_sasl_bind.patch @@ -0,0 +1,42 @@ +autofs-5.0.4 - fix double free in do_sasl_bind() + +From: Ian Kent + +In do_sasl_bind() the connection negotiation loop can exit with the +local variable server_cred non-null after it has been freed, leading +to a double free. +--- + + CHANGELOG | 1 + + modules/cyrus-sasl.c | 4 +++- + 2 files changed, 4 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index e138ca3..f0d0e58 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -53,6 +53,7 @@ + - fix not releasing resources when using submounts. + - fix notify mount message path. + - remount we created mount point fix. ++- fix double free in sasl_bind(). + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c +index ec2ab0c..04001d0 100644 +--- a/modules/cyrus-sasl.c ++++ b/modules/cyrus-sasl.c +@@ -348,8 +348,10 @@ do_sasl_bind(unsigned logopt, LDAP *ld, sasl_conn_t *conn, const char **clientou + } + } + +- if (server_cred && server_cred->bv_len > 0) ++ if (server_cred && server_cred->bv_len > 0) { + ber_bvfree(server_cred); ++ server_cred = NULL; ++ } + + } while ((bind_result == LDAP_SASL_BIND_IN_PROGRESS) || + (sasl_result == SASL_CONTINUE)); diff --git a/autofs-5.0.4-fix-incorrect-dclist-free.patch b/autofs-5.0.4-fix-incorrect-dclist-free.patch new file mode 100644 index 0000000..0a0ee68 --- /dev/null +++ b/autofs-5.0.4-fix-incorrect-dclist-free.patch @@ -0,0 +1,39 @@ +autofs-5.0.4 - fix incorrect dclist free + +From: Ian Kent + +We incorrectly try to free dclist in modules/lookup_ldap.c:find_server(). +--- + + modules/lookup_ldap.c | 10 ++++++++-- + 1 files changed, 8 insertions(+), 2 deletions(-) + + +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index f6b3f42..8f352d6 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -688,6 +688,10 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + } + } + if (!uri) { ++ if (dclist) { ++ free_dclist(dclist); ++ dclist = NULL; ++ } + p = p->next; + continue; + } +@@ -700,8 +704,10 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + } + free(uri); + uri = NULL; +- free_dclist(dclist); +- dclist = NULL; ++ if (dclist) { ++ free_dclist(dclist); ++ dclist = NULL; ++ } + p = p->next; + } + diff --git a/autofs-5.0.4-fix-map-type-info-parse-error.patch b/autofs-5.0.4-fix-map-type-info-parse-error.patch new file mode 100644 index 0000000..537eab7 --- /dev/null +++ b/autofs-5.0.4-fix-map-type-info-parse-error.patch @@ -0,0 +1,51 @@ +autofs-5.0.4 - fix map type info parse error + +From: Ian Kent + +Fix a mistake in map type info parsing introduced by the IPv6 parse +changes. +--- + + CHANGELOG | 1 + + lib/parse_subs.c | 4 +++- + 2 files changed, 4 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 05e0206..3fd97d3 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -55,6 +55,7 @@ + - remount we created mount point fix. + - fix double free in sasl_bind(). + - mannual umount recovery fixes. ++- fix map type info parse error. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/lib/parse_subs.c b/lib/parse_subs.c +index 0cba95a..0608cb7 100644 +--- a/lib/parse_subs.c ++++ b/lib/parse_subs.c +@@ -315,6 +315,7 @@ struct map_type_info *parse_map_type_info(const char *str) + { + struct map_type_info *info; + char *buf, *type, *fmt, *map, *tmp; ++ int seen_colon = 0; + + buf = strdup(str); + if (!buf) +@@ -335,11 +336,12 @@ struct map_type_info *parse_map_type_info(const char *str) + if (*tmp == ' ') { + *tmp = '\0'; + break; +- } else if (*tmp == ',') { ++ } else if (!seen_colon && *tmp == ',') { + type = buf; + *tmp++ = '\0'; + fmt = tmp; + } else if (*tmp == ':') { ++ seen_colon = 1; + if (!fmt) + type = buf; + *tmp++ = '\0'; diff --git a/autofs-5.0.4-fix-notify-mount-message-path.patch b/autofs-5.0.4-fix-notify-mount-message-path.patch new file mode 100644 index 0000000..38b9777 --- /dev/null +++ b/autofs-5.0.4-fix-notify-mount-message-path.patch @@ -0,0 +1,61 @@ +autofs-5.0.4 - fix notify mount message path + +From: Ian Kent + +If logging is set to verbose we want to log the actual path rather +than the false root. Hoevever, when logging is set to debug we do +need to show the false root to give us the true picture in relation +to accompanying log messages. +--- + + CHANGELOG | 1 + + daemon/direct.c | 5 ++++- + daemon/indirect.c | 5 ++++- + 3 files changed, 9 insertions(+), 2 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index d1cc113..0a0519f 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -51,6 +51,7 @@ + - always read file maps key lookup fixes. + - use srv query for domain dn. + - fix not releasing resources when using submounts. ++- fix notify mount message path. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/daemon/direct.c b/daemon/direct.c +index 1ed2b15..74a9acc 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -767,8 +767,11 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char * + } + + ops->timeout(ap->logopt, ioctlfd, &timeout); +- notify_mount_result(ap, mountpoint, str_offset); + cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino); ++ if (ap->logopt & LOGOPT_DEBUG) ++ notify_mount_result(ap, mountpoint, str_offset); ++ else ++ notify_mount_result(ap, me->key, str_offset); + ops->close(ap->logopt, ioctlfd); + + debug(ap->logopt, "mounted trigger %s at %s", me->key, mountpoint); +diff --git a/daemon/indirect.c b/daemon/indirect.c +index bc39e63..463b39c 100644 +--- a/daemon/indirect.c ++++ b/daemon/indirect.c +@@ -174,7 +174,10 @@ static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root) + ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO; + + ops->timeout(ap->logopt, ap->ioctlfd, &timeout); +- notify_mount_result(ap, root, str_indirect); ++ if (ap->logopt & LOGOPT_DEBUG) ++ notify_mount_result(ap, root, str_indirect); ++ else ++ notify_mount_result(ap, ap->path, str_indirect); + + return 0; + diff --git a/autofs-5.0.4-library-reload-fix-update-fix-2.patch b/autofs-5.0.4-library-reload-fix-update-fix-2.patch new file mode 100644 index 0000000..3075ccf --- /dev/null +++ b/autofs-5.0.4-library-reload-fix-update-fix-2.patch @@ -0,0 +1,53 @@ +autofs-5.0.4 - library reload fix update fix 2 + +From: Ian Kent + +The library reload fixes introduced a bug which causes autofs to +not release mount thread resources when using submounts. +--- + + CHANGELOG | 1 + + daemon/automount.c | 11 +++++++++-- + 2 files changed, 10 insertions(+), 2 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index f49784a..d1cc113 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -50,6 +50,7 @@ + - always read file maps multi map fix. + - always read file maps key lookup fixes. + - use srv query for domain dn. ++- fix not releasing resources when using submounts. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/daemon/automount.c b/daemon/automount.c +index 3a0fe0b..44dcdd6 100644 +--- a/daemon/automount.c ++++ b/daemon/automount.c +@@ -1460,14 +1460,21 @@ static void handle_mounts_cleanup(void *arg) + master_remove_mapent(ap->entry); + master_source_unlock(ap->entry); + ++ destroy_logpri_fifo(ap); ++ ++ /* ++ * Submounts are detached threads and don't belong to the ++ * master map entry list so we need to free their resources ++ * here. ++ */ + if (submount) { + mounts_mutex_unlock(ap->parent); + master_source_unlock(ap->parent->entry); ++ master_free_mapent_sources(ap->entry, 1); ++ master_free_mapent(ap->entry); + } + master_mutex_unlock(); + +- destroy_logpri_fifo(ap); +- + if (clean) { + if (rmdir(path) == -1) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); diff --git a/autofs-5.0.4-manual-umount-recovery-fixes.patch b/autofs-5.0.4-manual-umount-recovery-fixes.patch new file mode 100644 index 0000000..509ed80 --- /dev/null +++ b/autofs-5.0.4-manual-umount-recovery-fixes.patch @@ -0,0 +1,100 @@ +autofs-5.0.4 - mannual umount recovery fixes + +From: Ian Kent + +Check for the absence of a mount before doing the manual umount +checks and check ioctlfd is valid seperately. Take a write lock +on the map entry mutex to ensure any mount request is complete +before checking. +--- + + CHANGELOG | 1 + + daemon/direct.c | 4 ++-- + daemon/indirect.c | 37 +++++++++++++++++++++++-------------- + 3 files changed, 26 insertions(+), 16 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index f0d0e58..05e0206 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -54,6 +54,7 @@ + - fix notify mount message path. + - remount we created mount point fix. + - fix double free in sasl_bind(). ++- mannual umount recovery fixes. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/daemon/direct.c b/daemon/direct.c +index 74a9acc..7b02c7a 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -889,9 +889,9 @@ void *expire_proc_direct(void *arg) + /* Check for manual umount */ + cache_writelock(me->mc); + if (me->ioctlfd != -1 && +- fstat(ioctlfd, &st) != -1 && ++ fstat(me->ioctlfd, &st) != -1 && + !count_mounts(ap->logopt, next->path, st.st_dev)) { +- ops->close(ap->logopt, ioctlfd); ++ ops->close(ap->logopt, me->ioctlfd); + me->ioctlfd = -1; + cache_unlock(me->mc); + pthread_setcancelstate(cur_state, NULL); +diff --git a/daemon/indirect.c b/daemon/indirect.c +index 463b39c..8025ee4 100644 +--- a/daemon/indirect.c ++++ b/daemon/indirect.c +@@ -437,7 +437,19 @@ void *expire_proc_indirect(void *arg) + struct mapent *me = NULL; + struct stat st; + +- master_source_readlock(ap->entry); ++ /* It's got a mount, deal with in the outer loop */ ++ if (is_mounted(_PATH_MOUNTED, next->path, MNTS_REAL)) { ++ pthread_setcancelstate(cur_state, NULL); ++ continue; ++ } ++ ++ /* Don't touch submounts */ ++ if (master_find_submount(ap, next->path)) { ++ pthread_setcancelstate(cur_state, NULL); ++ continue; ++ } ++ ++ master_source_writelock(ap->entry); + + map = ap->entry->maps; + while (map) { +@@ -456,20 +468,17 @@ void *expire_proc_indirect(void *arg) + continue; + } + ++ if (me->ioctlfd == -1) { ++ cache_unlock(mc); ++ master_source_unlock(ap->entry); ++ pthread_setcancelstate(cur_state, NULL); ++ continue; ++ } ++ + /* Check for manual umount */ +- if (me->ioctlfd != -1 && +- (fstat(me->ioctlfd, &st) == -1 || +- !count_mounts(ap->logopt, me->key, st.st_dev))) { +- if (is_mounted(_PROC_MOUNTS, me->key, MNTS_REAL)) { +- error(ap->logopt, +- "error: possible mtab mismatch %s", +- me->key); +- cache_unlock(mc); +- master_source_unlock(ap->entry); +- pthread_setcancelstate(cur_state, NULL); +- continue; +- } +- close(me->ioctlfd); ++ if (fstat(me->ioctlfd, &st) == -1 || ++ !count_mounts(ap->logopt, me->key, st.st_dev)) { ++ ops->close(ap->logopt, me->ioctlfd); + me->ioctlfd = -1; + } + diff --git a/autofs-5.0.4-remount-we-created-mount-point-fix.patch b/autofs-5.0.4-remount-we-created-mount-point-fix.patch new file mode 100644 index 0000000..6ac9aa7 --- /dev/null +++ b/autofs-5.0.4-remount-we-created-mount-point-fix.patch @@ -0,0 +1,55 @@ +autofs-5.0.4 - remount we created mount point fix + +From: Ian Kent + +During remount determine if autofs created the mount point directory, +as best we can. +--- + + CHANGELOG | 1 + + lib/mounts.c | 15 +++++++-------- + 2 files changed, 8 insertions(+), 8 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 0a0519f..e138ca3 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -52,6 +52,7 @@ + - use srv query for domain dn. + - fix not releasing resources when using submounts. + - fix notify mount message path. ++- remount we created mount point fix. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/lib/mounts.c b/lib/mounts.c +index 4787bb6..4c44982 100644 +--- a/lib/mounts.c ++++ b/lib/mounts.c +@@ -1359,18 +1359,17 @@ int try_remount(struct autofs_point *ap, struct mapent *me, unsigned int type) + /* + * The directory must exist since we found a device + * number for the mount but we can't know if we created +- * it or not. However, if we're mounted on an autofs fs +- * then we need to cleanup the path anyway. ++ * it or not. However, if this is an indirect mount with ++ * the nobrowse option we need to remove the mount point ++ * directory at umount anyway. + */ + if (type == t_indirect) { +- ap->flags &= ~MOUNT_FLAG_DIR_CREATED; +- if (ret == DEV_IOCTL_IS_AUTOFS) ++ if (ap->flags & MOUNT_FLAG_GHOST) ++ ap->flags &= ~MOUNT_FLAG_DIR_CREATED; ++ else + ap->flags |= MOUNT_FLAG_DIR_CREATED; +- } else { ++ } else + me->flags &= ~MOUNT_FLAG_DIR_CREATED; +- if (ret == DEV_IOCTL_IS_AUTOFS) +- me->flags |= MOUNT_FLAG_DIR_CREATED; +- } + + /* + * Either we opened the mount or we're re-reading the map. diff --git a/autofs-5.0.4-srv-lookup-handle-endian.patch b/autofs-5.0.4-srv-lookup-handle-endian.patch new file mode 100644 index 0000000..093ecc8 --- /dev/null +++ b/autofs-5.0.4-srv-lookup-handle-endian.patch @@ -0,0 +1,37 @@ +autofs-5.0.4 - srv lookup handle endianness + +From: Ian Kent + + +--- + + modules/dclist.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + + +diff --git a/modules/dclist.c b/modules/dclist.c +index 5b0e577..967581c 100644 +--- a/modules/dclist.c ++++ b/modules/dclist.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "automount.h" + #include "dclist.h" +@@ -72,8 +73,13 @@ + #define SVAL(buf, pos) (*(const uint16_t *)((const char *)(buf) + (pos))) + #define IVAL(buf, pos) (*(const uint32_t *)((const char *)(buf) + (pos))) + ++#if __BYTE_ORDER == __LITTLE_ENDIAN + #define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) + #define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16))) ++#else ++#define SREV(x) (x) ++#define IREV(x) (x) ++#endif + + #define RSVAL(buf, pos) SREV(SVAL(buf, pos)) + #define RIVAL(buf, pos) IREV(IVAL(buf, pos)) diff --git a/autofs-5.0.4-use-srv-query-for-domain-dn.patch b/autofs-5.0.4-use-srv-query-for-domain-dn.patch new file mode 100644 index 0000000..6ab088e --- /dev/null +++ b/autofs-5.0.4-use-srv-query-for-domain-dn.patch @@ -0,0 +1,1097 @@ +autofs-5.0.4 - use srv query for domain dn + +From: Ian Kent + +Add the ability to use a domain dn in the LDAP_URI configuration +entry. If a domain dn is encountered in the LDAP_URI the list of +servers will be queried and used for the LDAP connection. The list +won't be queried again until the minimum ttl found in the SRV RR +records is reached or, if ttl isn't given in any SRV RR records, +after 1 hour. +--- + + CHANGELOG | 1 + include/dclist.h | 14 + + include/lookup_ldap.h | 3 + man/auto.master.5.in | 8 + modules/Makefile | 5 + modules/dclist.c | 785 ++++++++++++++++++++++++++++++++++++++++ + modules/lookup_ldap.c | 86 ++++ + redhat/autofs.sysconfig.in | 11 + + samples/autofs.conf.default.in | 11 + + 9 files changed, 911 insertions(+), 13 deletions(-) + create mode 100644 include/dclist.h + create mode 100644 modules/dclist.c + + +diff --git a/CHANGELOG b/CHANGELOG +index 5000f0c..f49784a 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -49,6 +49,7 @@ + - dont fail on ipv6 address when adding host. + - always read file maps multi map fix. + - always read file maps key lookup fixes. ++- use srv query for domain dn. + + 4/11/2008 autofs-5.0.4 + ----------------------- +diff --git a/include/dclist.h b/include/dclist.h +new file mode 100644 +index 0000000..ed89f97 +--- /dev/null ++++ b/include/dclist.h +@@ -0,0 +1,14 @@ ++#ifndef __DCLIST_H ++#define __DCLIST_H ++ ++#include ++ ++struct dclist { ++ time_t expire; ++ const char *uri; ++}; ++ ++struct dclist *get_dc_list(unsigned int logopt, const char *uri); ++void free_dclist(struct dclist *dclist); ++ ++#endif +diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h +index b47bf5d..dcae220 100644 +--- a/include/lookup_ldap.h ++++ b/include/lookup_ldap.h +@@ -10,6 +10,8 @@ + #include + #endif + ++#include "dclist.h" ++ + struct ldap_schema { + char *map_class; + char *map_attr; +@@ -57,6 +59,7 @@ struct lookup_context { + pthread_mutex_t uris_mutex; + struct list_head *uris; + struct ldap_uri *uri; ++ struct dclist *dclist; + char *cur_host; + struct ldap_searchdn *sdns; + +diff --git a/man/auto.master.5.in b/man/auto.master.5.in +index 7b7004f..71c4402 100644 +--- a/man/auto.master.5.in ++++ b/man/auto.master.5.in +@@ -271,6 +271,14 @@ Map entries that include a server name override this option and it is then + not used. Default is an empty list in which case either the server given + in a map entry or the LDAP configured default is used. This uri list is read at + startup and whenever the daemon receives a HUP signal. ++.P ++This configuration option can also be used to request autofs lookup SRV RRs ++for a domain of the form :///[]. Note that a trailing ++"/" is not allowed when using this form. If the domain dn is not specified ++the dns domain name (if any) is used to construct the domain dn for the ++SRV RR lookup. The server list returned from an SRV RR lookup is refreshed ++according to the minimum ttl found in the SRV RR records or after one hour, ++whichever is less. + .TP + .B SEARCH_BASE + The base dn to use when searching for amap base dn. This entry may be +diff --git a/modules/Makefile b/modules/Makefile +index 0d12f01..13b3bd8 100644 +--- a/modules/Makefile ++++ b/modules/Makefile +@@ -86,9 +86,10 @@ lookup_hesiod.so: lookup_hesiod.c + cyrus-sasl.o: cyrus-sasl.c + $(CC) $(CFLAGS) $(LDAP_FLAGS) -c $< + +-lookup_ldap.so: lookup_ldap.c $(SASL_OBJ) ++lookup_ldap.so: lookup_ldap.c dclist.o $(SASL_OBJ) + $(CC) $(SOLDFLAGS) $(CFLAGS) $(LDAP_FLAGS) -o lookup_ldap.so \ +- lookup_ldap.c $(SASL_OBJ) $(AUTOFS_LIB) $(LIBLDAP) ++ lookup_ldap.c dclist.o $(SASL_OBJ) \ ++ $(AUTOFS_LIB) $(LIBLDAP) $(LIBRESOLV) + $(STRIP) lookup_ldap.so + + mount_nfs.so: mount_nfs.c replicated.o +diff --git a/modules/dclist.c b/modules/dclist.c +new file mode 100644 +index 0000000..5b0e577 +--- /dev/null ++++ b/modules/dclist.c +@@ -0,0 +1,785 @@ ++/* ++ * Copyright 2009 Ian Kent ++ * Copyright 2009 Red Hat, Inc. ++ * ++ * This module was apapted from code contained in the Samba distribution ++ * file source/libads/dns.c which contained the following copyright ++ * information: ++ * ++ * Unix SMB/CIFS implementation. ++ * DNS utility library ++ * Copyright (C) Gerald (Jerry) Carter 2006. ++ * Copyright (C) Jeremy Allison 2007. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "automount.h" ++#include "dclist.h" ++ ++#define MAX_DNS_PACKET_SIZE 0xffff ++#define MAX_DNS_NAME_LENGTH MAXHOSTNAMELEN ++/* The longest time we will cache dns srv records */ ++#define MAX_TTL (60*60*1) /* 1 hours */ ++ ++#ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ ++#if !defined(C_IN) /* AIX 5.3 already defines C_IN */ ++# define C_IN ns_c_in ++#endif ++#if !defined(T_A) /* AIX 5.3 already defines T_A */ ++# define T_A ns_t_a ++#endif ++ ++# define T_SRV ns_t_srv ++#if !defined(T_NS) /* AIX 5.3 already defines T_NS */ ++# define T_NS ns_t_ns ++#endif ++#else ++# ifdef HFIXEDSZ ++# define NS_HFIXEDSZ HFIXEDSZ ++# else ++# define NS_HFIXEDSZ sizeof(HEADER) ++# endif /* HFIXEDSZ */ ++# ifdef PACKETSZ ++# define NS_PACKETSZ PACKETSZ ++# else /* 512 is usually the default */ ++# define NS_PACKETSZ 512 ++# endif /* PACKETSZ */ ++# define T_SRV 33 ++#endif ++ ++#define SVAL(buf, pos) (*(const uint16_t *)((const char *)(buf) + (pos))) ++#define IVAL(buf, pos) (*(const uint32_t *)((const char *)(buf) + (pos))) ++ ++#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) ++#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16))) ++ ++#define RSVAL(buf, pos) SREV(SVAL(buf, pos)) ++#define RIVAL(buf, pos) IREV(IVAL(buf, pos)) ++ ++#define QSORT_CAST (int (*)(const void *, const void *)) ++ ++/* DNS query section in replies */ ++ ++struct dns_query { ++ const char *hostname; ++ uint16_t type; ++ uint16_t in_class; ++}; ++ ++/* DNS RR record in reply */ ++ ++struct dns_rr { ++ const char *hostname; ++ uint16_t type; ++ uint16_t in_class; ++ uint32_t ttl; ++ uint16_t rdatalen; ++ uint8_t *rdata; ++}; ++ ++/* SRV records */ ++ ++struct dns_rr_srv { ++ const char *hostname; ++ uint16_t priority; ++ uint16_t weight; ++ uint16_t port; ++ uint32_t ttl; ++}; ++ ++static pthread_mutex_t dclist_mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++static void dclist_mutex_lock(void) ++{ ++ int status = pthread_mutex_lock(&dclist_mutex); ++ if (status) ++ fatal(status); ++ return; ++} ++ ++static void dclist_mutex_unlock(void) ++{ ++ int status = pthread_mutex_unlock(&dclist_mutex); ++ if (status) ++ fatal(status); ++ return; ++} ++ ++static int dns_parse_query(unsigned int logopt, ++ uint8_t *start, uint8_t *end, ++ uint8_t **ptr, struct dns_query *q) ++{ ++ uint8_t *p = *ptr; ++ char hostname[MAX_DNS_NAME_LENGTH]; ++ char buf[MAX_ERR_BUF]; ++ int namelen; ++ ++ if (!start || !end || !q || !*ptr) ++ return 0; ++ ++ memset(q, 0, sizeof(*q)); ++ ++ /* See RFC 1035 for details. If this fails, then return. */ ++ ++ namelen = dn_expand(start, end, p, hostname, sizeof(hostname)); ++ if (namelen < 0) { ++ error(logopt, "failed to expand query hostname"); ++ return 0; ++ } ++ ++ p += namelen; ++ q->hostname = strdup(hostname); ++ if (!q) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "strdup: %s", estr); ++ return 0; ++ } ++ ++ /* check that we have space remaining */ ++ ++ if (p + 4 > end) { ++ error(logopt, "insufficient buffer space for result"); ++ free((void *) q->hostname); ++ return 0; ++ } ++ ++ q->type = RSVAL(p, 0); ++ q->in_class = RSVAL(p, 2); ++ p += 4; ++ ++ *ptr = p; ++ ++ return 1; ++} ++ ++static int dns_parse_rr(unsigned int logopt, ++ uint8_t *start, uint8_t *end, ++ uint8_t **ptr, struct dns_rr *rr) ++{ ++ uint8_t *p = *ptr; ++ char hostname[MAX_DNS_NAME_LENGTH]; ++ char buf[MAX_ERR_BUF]; ++ int namelen; ++ ++ if (!start || !end || !rr || !*ptr) ++ return 0; ++ ++ memset(rr, 0, sizeof(*rr)); ++ ++ /* pull the name from the answer */ ++ ++ namelen = dn_expand(start, end, p, hostname, sizeof(hostname)); ++ if (namelen < 0) { ++ error(logopt, "failed to expand query hostname"); ++ return 0; ++ } ++ p += namelen; ++ rr->hostname = strdup(hostname); ++ if (!rr->hostname) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "strdup: %s", estr); ++ return 0; ++ } ++ ++ /* check that we have space remaining */ ++ ++ if (p + 10 > end) { ++ error(logopt, "insufficient buffer space for result"); ++ free((void *) rr->hostname); ++ return 0; ++ } ++ ++ /* pull some values and then skip onto the string */ ++ ++ rr->type = RSVAL(p, 0); ++ rr->in_class = RSVAL(p, 2); ++ rr->ttl = RIVAL(p, 4); ++ rr->rdatalen = RSVAL(p, 8); ++ ++ p += 10; ++ ++ /* sanity check the available space */ ++ ++ if (p + rr->rdatalen > end) { ++ error(logopt, "insufficient buffer space for data"); ++ free((void *) rr->hostname); ++ return 0; ++ } ++ ++ /* save a point to the rdata for this section */ ++ ++ rr->rdata = p; ++ p += rr->rdatalen; ++ ++ *ptr = p; ++ ++ return 1; ++} ++ ++static int dns_parse_rr_srv(unsigned int logopt, ++ uint8_t *start, uint8_t *end, ++ uint8_t **ptr, struct dns_rr_srv *srv) ++{ ++ struct dns_rr rr; ++ uint8_t *p; ++ char dcname[MAX_DNS_NAME_LENGTH]; ++ char buf[MAX_ERR_BUF]; ++ int namelen; ++ ++ if (!start || !end || !srv || !*ptr) ++ return 0; ++ ++ /* Parse the RR entry. Coming out of the this, ptr is at the beginning ++ of the next record */ ++ ++ if (!dns_parse_rr(logopt, start, end, ptr, &rr)) { ++ error(logopt, "Failed to parse RR record"); ++ return 0; ++ } ++ ++ if (rr.type != T_SRV) { ++ error(logopt, "Bad answer type (%d)", rr.type); ++ return 0; ++ } ++ ++ p = rr.rdata; ++ ++ srv->priority = RSVAL(p, 0); ++ srv->weight = RSVAL(p, 2); ++ srv->port = RSVAL(p, 4); ++ srv->ttl = rr.ttl; ++ ++ p += 6; ++ ++ namelen = dn_expand(start, end, p, dcname, sizeof(dcname)); ++ if (namelen < 0) { ++ error(logopt, "Failed to expand dcname"); ++ return 0; ++ } ++ ++ srv->hostname = strdup(dcname); ++ if (!srv->hostname) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "strdup: %s", estr); ++ return 0; ++ } ++ ++ debug(logopt, "Parsed %s [%u, %u, %u]", ++ srv->hostname, srv->priority, srv->weight, srv->port); ++ ++ return 1; ++} ++ ++/********************************************************************* ++ Sort SRV record list based on weight and priority. See RFC 2782. ++*********************************************************************/ ++ ++static int dnssrvcmp(struct dns_rr_srv *a, struct dns_rr_srv *b) ++{ ++ if (a->priority == b->priority) { ++ /* randomize entries with an equal weight and priority */ ++ if (a->weight == b->weight) ++ return 0; ++ ++ /* higher weights should be sorted lower */ ++ if (a->weight > b->weight) ++ return -1; ++ else ++ return 1; ++ } ++ ++ if (a->priority < b->priority) ++ return -1; ++ ++ return 1; ++} ++ ++#define DNS_FAILED_WAITTIME 30 ++ ++static int dns_send_req(unsigned int logopt, ++ const char *name, int q_type, uint8_t **rbuf, ++ int *resp_length) ++{ ++ uint8_t *buffer = NULL; ++ size_t buf_len = 0; ++ int resp_len = NS_PACKETSZ; ++ static time_t last_dns_check = 0; ++ static unsigned int last_dns_status = 0; ++ time_t now = time(NULL); ++ char buf[MAX_ERR_BUF]; ++ ++ /* Try to prevent bursts of DNS lookups if the server is down */ ++ ++ /* Protect against large clock changes */ ++ ++ if (last_dns_check > now) ++ last_dns_check = 0; ++ ++ /* IF we had a DNS timeout or a bad server and we are still ++ in the 30 second cache window, just return the previous ++ status and save the network timeout. */ ++ ++ if ((last_dns_status == ETIMEDOUT || ++ last_dns_status == ECONNREFUSED) && ++ ((last_dns_check + DNS_FAILED_WAITTIME) > now)) { ++ char *estr = strerror_r(last_dns_status, buf, MAX_ERR_BUF); ++ debug(logopt, "Returning cached status (%s)", estr); ++ return last_dns_status; ++ } ++ ++ /* Send the Query */ ++ do { ++ if (buffer) ++ free(buffer); ++ ++ buf_len = resp_len * sizeof(uint8_t); ++ ++ if (buf_len) { ++ buffer = malloc(buf_len); ++ if (!buffer) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ last_dns_status = ENOMEM; ++ last_dns_check = time(NULL); ++ return last_dns_status; ++ } ++ } ++ ++ resp_len = res_query(name, C_IN, q_type, buffer, buf_len); ++ if (resp_len < 0) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "Failed to resolve %s (%s)", name, estr); ++ free(buffer); ++ last_dns_status = ENOENT; ++ last_dns_check = time(NULL); ++ return last_dns_status; ++ } ++ ++ /* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8) ++ truncated replies never give back a resp_len > buflen ++ which ends up causing DNS resolve failures on large tcp DNS replies */ ++ ++ if (buf_len == resp_len) { ++ if (resp_len == MAX_DNS_PACKET_SIZE) { ++ error(logopt, ++ "DNS reply too large when resolving %s", ++ name); ++ free(buffer); ++ last_dns_status = EMSGSIZE; ++ last_dns_check = time(NULL); ++ return last_dns_status; ++ } ++ ++ resp_len = MIN(resp_len * 2, MAX_DNS_PACKET_SIZE); ++ } ++ } while (buf_len < resp_len && resp_len <= MAX_DNS_PACKET_SIZE); ++ ++ *rbuf = buffer; ++ *resp_length = resp_len; ++ ++ last_dns_check = time(NULL); ++ last_dns_status = 0; ++ ++ return 0; ++} ++ ++static int dns_lookup_srv(unsigned int logopt, const char *name, ++ struct dns_rr_srv **dclist, int *numdcs) ++{ ++ uint8_t *buffer = NULL; ++ int resp_len = 0; ++ struct dns_rr_srv *dcs = NULL; ++ int query_count, answer_count; ++ uint8_t *p = buffer; ++ int rrnum; ++ int idx = 0; ++ char buf[MAX_ERR_BUF]; ++ int ret; ++ ++ if (!name || !dclist) ++ return -EINVAL; ++ ++ /* Send the request. May have to loop several times in case ++ of large replies */ ++ ++ ret = dns_send_req(logopt, name, T_SRV, &buffer, &resp_len); ++ if (ret) { ++ error(logopt, "Failed to send DNS query"); ++ return ret; ++ } ++ p = buffer; ++ ++ /* For some insane reason, the ns_initparse() et. al. routines are only ++ available in libresolv.a, and not the shared lib. Who knows why.... ++ So we have to parse the DNS reply ourselves */ ++ ++ /* Pull the answer RR's count from the header. ++ * Use the NMB ordering macros */ ++ ++ query_count = RSVAL(p, 4); ++ answer_count = RSVAL(p, 6); ++ ++ debug(logopt, ++ "%d records returned in the answer section.", ++ answer_count); ++ ++ if (answer_count) { ++ dcs = malloc(sizeof(struct dns_rr_srv) * answer_count); ++ if (!dcs) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ free(buffer); ++ return ENOMEM; ++ } ++ } ++ ++ /* now skip the header */ ++ ++ p += NS_HFIXEDSZ; ++ ++ /* parse the query section */ ++ ++ for (rrnum = 0; rrnum < query_count; rrnum++) { ++ struct dns_query q; ++ ++ ret = dns_parse_query(logopt, buffer, buffer+resp_len, &p, &q); ++ if (!ret) { ++ error(logopt, ++ "Failed to parse query record [%d]", rrnum); ++ free(buffer); ++ free(dcs); ++ return EBADMSG; ++ } ++ } ++ ++ /* now we are at the answer section */ ++ ++ for (rrnum = 0; rrnum < answer_count; rrnum++) { ++ ret = dns_parse_rr_srv(logopt, ++ buffer, buffer+resp_len, ++ &p, &dcs[rrnum]); ++ if (!ret) { ++ error(logopt, ++ "Failed to parse answer record [%d]", rrnum); ++ free(buffer); ++ free(dcs); ++ return EBADMSG; ++ } ++ } ++ idx = rrnum; ++ ++ qsort(dcs, idx, sizeof(struct dns_rr_srv), QSORT_CAST dnssrvcmp); ++ ++ *dclist = dcs; ++ *numdcs = idx; ++ ++ return 0; ++} ++ ++static char *escape_dn_commas(const char *uri) ++{ ++ size_t len = strlen(uri); ++ char *new, *tmp, *ptr; ++ ++ ptr = (char *) uri; ++ while (*ptr) { ++ if (*ptr == '\\') ++ ptr += 2; ++ if (*ptr == ',') ++ len += 2; ++ ptr++; ++ } ++ ++ new = malloc(len + 1); ++ if (!new) ++ return NULL; ++ memset(new, 0, len + 1); ++ ++ ptr = (char *) uri; ++ tmp = new; ++ while (*ptr) { ++ if (*ptr == '\\') { ++ ptr++; ++ *tmp++ = *ptr++; ++ continue; ++ } ++ if (*ptr == ',') { ++ strcpy(tmp, "%2c"); ++ ptr++; ++ tmp += 3; ++ continue; ++ } ++ *tmp++ = *ptr++; ++ } ++ ++ return new; ++} ++ ++void free_dclist(struct dclist *dclist) ++{ ++ if (dclist->uri) ++ free((void *) dclist->uri); ++ free(dclist); ++} ++ ++static char *getdnsdomainname(unsigned int logopt) ++{ ++ struct addrinfo hints, *ni; ++ char name[MAX_DNS_NAME_LENGTH + 1]; ++ char buf[MAX_ERR_BUF]; ++ char *dnsdomain = NULL; ++ char *ptr; ++ int ret; ++ ++ memset(name, 0, sizeof(name)); ++ if (gethostname(name, MAX_DNS_NAME_LENGTH) == -1) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "gethostname: %s", estr); ++ return NULL; ++ } ++ ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_flags = AI_CANONNAME; ++ hints.ai_family = AF_UNSPEC; ++ hints.ai_socktype = SOCK_DGRAM; ++ ++ ret = getaddrinfo(name, NULL, &hints, &ni); ++ if (ret) { ++ error(logopt, "hostname lookup failed: %s", gai_strerror(ret)); ++ return NULL; ++ } ++ ++ ptr = ni->ai_canonname; ++ while (*ptr && *ptr != '.') ++ ptr++; ++ ++ if (*++ptr) ++ dnsdomain = strdup(ptr); ++ ++ freeaddrinfo(ni); ++ ++ return dnsdomain; ++} ++ ++struct dclist *get_dc_list(unsigned int logopt, const char *uri) ++{ ++ LDAPURLDesc *ludlist = NULL; ++ LDAPURLDesc **ludp; ++ struct dns_rr_srv *dcs; ++ unsigned int min_ttl = MAX_TTL; ++ struct dclist *dclist = NULL;; ++ char buf[MAX_ERR_BUF]; ++ char *dn_uri, *esc_uri; ++ char *domain; ++ char *list; ++ int numdcs; ++ int ret; ++ ++ if (strcmp(uri, "ldap:///") && strcmp(uri, "ldaps:///")) { ++ dn_uri = strdup(uri); ++ if (!dn_uri) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "strdup: %s", estr); ++ return NULL; ++ } ++ } else { ++ char *dnsdomain; ++ char *hdn; ++ ++ dnsdomain = getdnsdomainname(logopt); ++ if (!dnsdomain) { ++ error(logopt, "failed to get dns domainname"); ++ return NULL; ++ } ++ ++ if (ldap_domain2dn(dnsdomain, &hdn) || hdn == NULL) { ++ error(logopt, ++ "Could not turn domain \"%s\" into a dn\n", ++ dnsdomain); ++ free(dnsdomain); ++ return NULL; ++ } ++ free(dnsdomain); ++ ++ dn_uri = malloc(strlen(uri) + strlen(hdn) + 1); ++ if (!dn_uri) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ ber_memfree(hdn); ++ return NULL; ++ } ++ ++ strcpy(dn_uri, uri); ++ strcat(dn_uri, hdn); ++ ber_memfree(hdn); ++ } ++ ++ esc_uri = escape_dn_commas(dn_uri); ++ if (!esc_uri) { ++ error(logopt, "Could not escape commas in uri %s", dn_uri); ++ free(dn_uri); ++ return NULL; ++ } ++ ++ ret = ldap_url_parse(esc_uri, &ludlist); ++ if (ret != LDAP_URL_SUCCESS) { ++ error(logopt, "Could not parse uri %s (%d)", dn_uri, ret); ++ free(esc_uri); ++ free(dn_uri); ++ return NULL; ++ } ++ ++ free(esc_uri); ++ ++ if (!ludlist) { ++ error(logopt, "No dn found in uri %s", dn_uri); ++ free(dn_uri); ++ return NULL; ++ } ++ ++ free(dn_uri); ++ ++ dclist = malloc(sizeof(struct dclist)); ++ if (!dclist) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ ldap_free_urldesc(ludlist); ++ return NULL; ++ } ++ memset(dclist, 0, sizeof(struct dclist)); ++ ++ list = NULL; ++ for (ludp = &ludlist; *ludp != NULL;) { ++ LDAPURLDesc *lud = *ludp; ++ size_t req_len, len; ++ char *request = NULL; ++ char *tmp; ++ int i; ++ ++ if (!lud->lud_dn && !lud->lud_dn[0] && ++ (!lud->lud_host || !lud->lud_host[0])) { ++ *ludp = lud->lud_next; ++ continue; ++ } ++ ++ domain = NULL; ++ if (ldap_dn2domain(lud->lud_dn, &domain) || domain == NULL) { ++ error(logopt, ++ "Could not turn dn \"%s\" into a domain", ++ lud->lud_dn); ++ *ludp = lud->lud_next; ++ continue; ++ } ++ ++ debug(logopt, "doing lookup of SRV RRs for domain %s", domain); ++ ++ req_len = sizeof("_ldap._tcp.") + strlen(domain); ++ request = malloc(req_len); ++ if (!request) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ goto out_error; ++ } ++ ++ ret = snprintf(request, req_len, "_ldap._tcp.%s", domain); ++ if (ret >= req_len) { ++ free(request); ++ goto out_error; ++ } ++ ++ dclist_mutex_lock(); ++ if (dns_lookup_srv(logopt, request, &dcs, &numdcs)) { ++ error(logopt, ++ "DNS SRV query failed for domain %s", domain); ++ dclist_mutex_unlock(); ++ free(request); ++ goto out_error; ++ } ++ dclist_mutex_unlock(); ++ free(request); ++ ++ len = strlen(lud->lud_scheme); ++ len += sizeof("://"); ++ len *= numdcs; ++ ++ for (i = 0; i < numdcs; i++) { ++ if (dcs[i].ttl > 0 && dcs[i].ttl < min_ttl) ++ min_ttl = dcs[i].ttl; ++ len += strlen(dcs[i].hostname); ++ if (dcs[i].port > 0) ++ len += sizeof(":65535"); ++ } ++ ++ tmp = realloc(list, len); ++ if (!tmp) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(logopt, "realloc: %s", estr); ++ goto out_error; ++ } ++ ++ if (!list) ++ memset(tmp, 0, len); ++ else ++ strcat(tmp, " "); ++ ++ for (i = 0; i < numdcs; i++) { ++ if (i > 0) ++ strcat(tmp, " "); ++ strcat(tmp, lud->lud_scheme); ++ strcat(tmp, "://"); ++ strcat(tmp, dcs[i].hostname); ++ if (dcs[i].port > 0) { ++ char port[7]; ++ ret = snprintf(port, 7, ":%d", dcs[i].port); ++ if (ret > 6) { ++ error(logopt, ++ "invalid port: %u", dcs[i].port); ++ goto out_error; ++ } ++ strcat(tmp, port); ++ } ++ } ++ list = tmp; ++ ++ *ludp = lud->lud_next; ++ ber_memfree(domain); ++ } ++ ++ ldap_free_urldesc(ludlist); ++ ++ dclist->expire = time(NULL) + min_ttl; ++ dclist->uri = list; ++ ++ return dclist; ++ ++out_error: ++ if (list) ++ free(list); ++ if (domain) ++ ber_memfree(domain); ++ ldap_free_urldesc(ludlist); ++ free_dclist(dclist); ++ return NULL; ++} +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index a847622..f6b3f42 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -643,14 +643,26 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + LDAP *ldap = NULL; + struct ldap_uri *this; + struct list_head *p, *first; ++ struct dclist *dclist = NULL; ++ char *uri = NULL; + +- /* Try each uri in list, add connect fails to tmp list */ + uris_mutex_lock(ctxt); ++ if (ctxt->dclist) { ++ dclist = ctxt->dclist; ++ if (ctxt->dclist->expire < time(NULL)) { ++ free_dclist(ctxt->dclist); ++ ctxt->dclist = NULL; ++ dclist = NULL; ++ } ++ } + if (!ctxt->uri) + first = ctxt->uris; + else + first = &ctxt->uri->list; + uris_mutex_unlock(ctxt); ++ ++ ++ /* Try each uri, save point in server list upon success */ + p = first->next; + while(p != first) { + /* Skip list head */ +@@ -659,25 +671,62 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + continue; + } + this = list_entry(p, struct ldap_uri, list); +- debug(logopt, "trying server %s", this->uri); +- ldap = connect_to_server(logopt, this->uri, ctxt); ++ if (!strstr(this->uri, ":///")) ++ uri = strdup(this->uri); ++ else { ++ if (dclist) ++ uri = strdup(dclist->uri); ++ else { ++ struct dclist *tmp; ++ tmp = get_dc_list(logopt, this->uri); ++ if (!tmp) { ++ p = p->next; ++ continue; ++ } ++ dclist = tmp; ++ uri = strdup(dclist->uri); ++ } ++ } ++ if (!uri) { ++ p = p->next; ++ continue; ++ } ++ debug(logopt, "trying server uri %s", uri); ++ ldap = connect_to_server(logopt, uri, ctxt); + if (ldap) { +- info(logopt, "connected to uri %s", this->uri); +- uris_mutex_lock(ctxt); +- ctxt->uri = this; +- uris_mutex_unlock(ctxt); ++ info(logopt, "connected to uri %s", uri); ++ free(uri); + break; + } ++ free(uri); ++ uri = NULL; ++ free_dclist(dclist); ++ dclist = NULL; + p = p->next; + } + ++ uris_mutex_lock(ctxt); ++ if (ldap) ++ ctxt->uri = this; ++ if (dclist) { ++ if (!ctxt->dclist) ++ ctxt->dclist = dclist; ++ else { ++ if (ctxt->dclist != dclist) { ++ free_dclist(ctxt->dclist); ++ ctxt->dclist = dclist; ++ } ++ } ++ } ++ uris_mutex_unlock(ctxt); ++ + return ldap; + } + + static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + { +- struct ldap_uri *this; + LDAP *ldap; ++ char *uri; + + if (ctxt->server || !ctxt->uris) { + ldap = do_connect(logopt, ctxt->server, ctxt); +@@ -692,9 +741,20 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + } + + uris_mutex_lock(ctxt); +- this = ctxt->uri; ++ if (ctxt->dclist) ++ uri = strdup(ctxt->dclist->uri); ++ else ++ uri = strdup(ctxt->uri->uri); + uris_mutex_unlock(ctxt); +- ldap = do_connect(logopt, this->uri, ctxt); ++ ++ if (!uri) { ++ char buf[MAX_ERR_BUF]; ++ char *estr = strerror_r(errno, buf, sizeof(buf)); ++ crit(logopt, MODPREFIX "strdup: %s", estr); ++ return NULL; ++ } ++ ++ ldap = do_connect(logopt, uri, ctxt); + #ifdef WITH_SASL + /* + * Dispose of the sasl authentication connection and try the +@@ -702,9 +762,11 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + */ + if (!ldap) { + autofs_sasl_dispose(ctxt); +- ldap = connect_to_server(logopt, this->uri, ctxt); ++ ldap = connect_to_server(logopt, uri, ctxt); + } + #endif ++ free(uri); ++ + if (ldap) + return ldap; + +@@ -1296,6 +1358,8 @@ static void free_context(struct lookup_context *ctxt) + fatal(ret); + if (ctxt->sdns) + defaults_free_searchdns(ctxt->sdns); ++ if (ctxt->dclist) ++ free_dclist(ctxt->dclist); + free(ctxt); + + return; +diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in +index 97e20fe..37448ea 100644 +--- a/redhat/autofs.sysconfig.in ++++ b/redhat/autofs.sysconfig.in +@@ -50,6 +50,17 @@ BROWSE_MODE="no" + # Map entries that include a server name override + # this option. + # ++# This configuration option can also be used to ++# request autofs lookup SRV RRs for a domain of ++# the form :///[]. Note that a ++# trailing "/" is not allowed when using this form. ++# If the domain dn is not specified the dns domain ++# name (if any) is used to construct the domain dn ++# for the SRV RR lookup. The server list returned ++# from an SRV RR lookup is refreshed according to ++# the minimum ttl found in the SRV RR records or ++# after one hour, whichever is less. ++# + #LDAP_URI="" + # + # LDAP__TIMEOUT - timeout value for the synchronous API calls +diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in +index 62084c2..7dee5fd 100644 +--- a/samples/autofs.conf.default.in ++++ b/samples/autofs.conf.default.in +@@ -48,6 +48,17 @@ BROWSE_MODE="no" + # Map entries that include a server name override + # this option. + # ++# This configuration option can also be used to ++# request autofs lookup SRV RRs for a domain of ++# the form :///[]. Note that a ++# trailing "/" is not allowed when using this form. ++# If the domain dn is not specified the dns domain ++# name (if any) is used to construct the domain dn ++# for the SRV RR lookup. The server list returned ++# from an SRV RR lookup is refreshed according to ++# the minimum ttl found in the SRV RR records or ++# after one hour, whichever is less. ++# + #LDAP_URI="" + # + # LDAP__TIMEOUT - timeout value for the synchronous API calls diff --git a/autofs.spec b/autofs.spec index 78657c7..fd247f8 100644 --- a/autofs.spec +++ b/autofs.spec @@ -4,7 +4,7 @@ Summary: A tool for automatically mounting and unmounting filesystems Name: autofs Version: 5.0.4 -Release: 29 +Release: 31 Epoch: 1 License: GPLv2+ Group: System Environment/Daemons @@ -59,6 +59,15 @@ Patch46: autofs-5.0.4-improve-manual-umount-recovery.patch Patch47: autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch Patch48: autofs-5.0.4-always-read-file-maps-multi-map-fix.patch Patch49: autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch +Patch50: autofs-5.0.4-use-srv-query-for-domain-dn.patch +Patch51: autofs-5.0.4-fix-incorrect-dclist-free.patch +Patch52: autofs-5.0.4-srv-lookup-handle-endian.patch +Patch53: autofs-5.0.4-library-reload-fix-update-fix-2.patch +Patch54: autofs-5.0.4-fix-notify-mount-message-path.patch +Patch55: autofs-5.0.4-remount-we-created-mount-point-fix.patch +Patch56: autofs-5.0.4-fix-double-free-in-do_sasl_bind.patch +Patch57: autofs-5.0.4-manual-umount-recovery-fixes.patch +Patch58: autofs-5.0.4-fix-map-type-info-parse-error.patch Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: autoconf, hesiod-devel, openldap-devel, bison, flex, libxml2-devel, cyrus-sasl-devel, openssl-devel module-init-tools util-linux nfs-utils e2fsprogs libtirpc-devel Requires: kernel >= 2.6.17 @@ -149,6 +158,15 @@ echo %{version}-%{release} > .version %patch47 -p1 %patch48 -p1 %patch49 -p1 +%patch50 -p1 +%patch51 -p1 +%patch52 -p1 +%patch53 -p1 +%patch54 -p1 +%patch55 -p1 +%patch56 -p1 +%patch57 -p1 +%patch58 -p1 %build #CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir} @@ -201,6 +219,18 @@ fi %{_libdir}/autofs/ %changelog +* Fri Jun 12 2009 Ian Kent - 1:5.0.4-31 +- add support for LDAP_URI="ldap:///" SRV RR lookup. +- fix incorrect dclist free. +- srv lookup handle endianness. +- fix bug introduced by library reload changes which causes autofs to + not release mount thread resources when using submounts. +- fix notify mount message path. +- try harder to work out if we created mount point at remount. +- fix double free in do_sasl_bind(). +- manual umount recovery fixes. +- fix map type info parse error. + * Mon May 18 2009 Ian Kent - 1:5.0.4-29 - use intr option as hosts mount default. - sync kernel includes with upstream kernel.