Blame modules/dclist.c

Packit Service a4b2a9
/*
Packit Service a4b2a9
 * Copyright 2011 Ian Kent <raven@themaw.net>
Packit Service a4b2a9
 * Copyright 2011 Red Hat, Inc.
Packit Service a4b2a9
 *
Packit Service a4b2a9
 * This program is free software; you can redistribute it and/or modify
Packit Service a4b2a9
 * it under the terms of the GNU General Public License as published by
Packit Service a4b2a9
 * the Free Software Foundation, either version 2 of the License, or
Packit Service a4b2a9
 * (at your option) any later version.
Packit Service a4b2a9
 *
Packit Service a4b2a9
 * This program is distributed in the hope that it will be useful,
Packit Service a4b2a9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a4b2a9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a4b2a9
 * GNU General Public License for more details.
Packit Service a4b2a9
 *
Packit Service a4b2a9
 * You should have received a copy of the GNU General Public License
Packit Service a4b2a9
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service a4b2a9
*/
Packit Service a4b2a9
Packit Service a4b2a9
#include <sys/types.h>
Packit Service a4b2a9
#include <netinet/in.h>
Packit Service a4b2a9
#include <arpa/inet.h>
Packit Service a4b2a9
#include <arpa/nameser.h>
Packit Service a4b2a9
#include <stdlib.h>
Packit Service a4b2a9
#include <string.h>
Packit Service a4b2a9
#include <resolv.h>
Packit Service a4b2a9
#include <netdb.h>
Packit Service a4b2a9
#include <ldap.h>
Packit Service a4b2a9
#include <sys/param.h>
Packit Service a4b2a9
#include <errno.h>
Packit Service a4b2a9
#include <endian.h>
Packit Service a4b2a9
Packit Service a4b2a9
#include "automount.h"
Packit Service a4b2a9
#include "dclist.h"
Packit Service a4b2a9
Packit Service a4b2a9
#define MAX_TTL		(60*60) /* 1 hour */
Packit Service a4b2a9
Packit Service a4b2a9
struct rr {
Packit Service a4b2a9
	unsigned int type;
Packit Service a4b2a9
	unsigned int class;
Packit Service a4b2a9
	unsigned long ttl;
Packit Service a4b2a9
	unsigned int len;
Packit Service a4b2a9
};
Packit Service a4b2a9
Packit Service a4b2a9
struct srv_rr {
Packit Service a4b2a9
	const char *name;
Packit Service a4b2a9
	unsigned int priority;
Packit Service a4b2a9
	unsigned int weight;
Packit Service a4b2a9
	unsigned int port;
Packit Service a4b2a9
	unsigned long ttl;
Packit Service a4b2a9
};
Packit Service a4b2a9
Packit Service a4b2a9
static pthread_mutex_t dclist_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit Service a4b2a9
Packit Service a4b2a9
static void dclist_mutex_lock(void)
Packit Service a4b2a9
{
Packit Service a4b2a9
	int status = pthread_mutex_lock(&dclist_mutex);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
	return;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static void dclist_mutex_unlock(void)
Packit Service a4b2a9
{
Packit Service a4b2a9
	int status = pthread_mutex_unlock(&dclist_mutex);
Packit Service a4b2a9
	if (status)
Packit Service a4b2a9
		fatal(status);
Packit Service a4b2a9
	return;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static int do_srv_query(unsigned int logopt, char *name, u_char **packet)
Packit Service a4b2a9
{
Packit Service a4b2a9
	int len = PACKETSZ;
Packit Service a4b2a9
	unsigned int last_len = len;
Packit Service a4b2a9
	char ebuf[MAX_ERR_BUF];
Packit Service a4b2a9
	u_char *buf;
Packit Service a4b2a9
Packit Service a4b2a9
	while (1) {
Packit Service a4b2a9
		buf = malloc(last_len);
Packit Service a4b2a9
		if (!buf) {
Packit Service a4b2a9
			char *estr = strerror_r(errno, ebuf, MAX_ERR_BUF);
Packit Service a4b2a9
			error(logopt, "malloc: %s", estr);
Packit Service a4b2a9
			return -1;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		len = res_query(name, C_IN, T_SRV, buf, last_len);
Packit Service a4b2a9
		if (len < 0) {
Packit Service a4b2a9
			char *estr = strerror_r(errno, ebuf, MAX_ERR_BUF);
Packit Service a4b2a9
			error(logopt, "Failed to resolve %s (%s)", name, estr);
Packit Service a4b2a9
			free(buf);
Packit Service a4b2a9
			return -1;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		if (len == last_len) {
Packit Service a4b2a9
			/* These shouldn't too large, bump by PACKETSZ only */
Packit Service a4b2a9
			last_len += PACKETSZ;
Packit Service a4b2a9
			free(buf);
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		break;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	*packet = buf;
Packit Service a4b2a9
Packit Service a4b2a9
	return len;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static int get_name_len(u_char *buffer, u_char *start, u_char *end)
Packit Service a4b2a9
{
Packit Service a4b2a9
	char tmp[MAXDNAME];
Packit Service a4b2a9
	return dn_expand(buffer, end, start, tmp, MAXDNAME);
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static int get_data_offset(u_char *buffer,
Packit Service a4b2a9
			   u_char *start, u_char *end,
Packit Service a4b2a9
			   struct rr *rr)
Packit Service a4b2a9
{
Packit Service a4b2a9
	u_char *cp = start;
Packit Service a4b2a9
	int name_len;
Packit Service a4b2a9
Packit Service a4b2a9
	name_len = get_name_len(buffer, start, end);
Packit Service a4b2a9
	if (name_len < 0)
Packit Service a4b2a9
		return -1;
Packit Service a4b2a9
	cp += name_len;
Packit Service a4b2a9
Packit Service a4b2a9
	GETSHORT(rr->type, cp);
Packit Service a4b2a9
	GETSHORT(rr->class, cp);
Packit Service a4b2a9
	GETLONG(rr->ttl, cp);
Packit Service a4b2a9
	GETSHORT(rr->len, cp);
Packit Service a4b2a9
Packit Service a4b2a9
	return (cp - start);
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static struct srv_rr *parse_srv_rr(unsigned int logopt,
Packit Service a4b2a9
				   u_char *buffer, u_char *start, u_char *end,
Packit Service a4b2a9
				   struct rr *rr, struct srv_rr *srv)
Packit Service a4b2a9
{
Packit Service a4b2a9
	u_char *cp = start;
Packit Service a4b2a9
	char ebuf[MAX_ERR_BUF];
Packit Service a4b2a9
	char tmp[MAXDNAME];
Packit Service a4b2a9
	int len;
Packit Service a4b2a9
Packit Service a4b2a9
	GETSHORT(srv->priority, cp);
Packit Service a4b2a9
	GETSHORT(srv->weight, cp);
Packit Service a4b2a9
	GETSHORT(srv->port, cp);
Packit Service a4b2a9
	srv->ttl = rr->ttl;
Packit Service a4b2a9
Packit Service a4b2a9
	len = dn_expand(buffer, end, cp, tmp, MAXDNAME);
Packit Service a4b2a9
	if (len < 0) {
Packit Service a4b2a9
		error(logopt, "failed to expand name");
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	}
Packit Service a4b2a9
	srv->name = strdup(tmp);
Packit Service a4b2a9
	if (!srv->name) {
Packit Service a4b2a9
		char *estr = strerror_r(errno, ebuf, MAX_ERR_BUF);
Packit Service a4b2a9
		error(logopt, "strdup: %s", estr);
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	return srv;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static int cmp(struct srv_rr *a, struct srv_rr *b)
Packit Service a4b2a9
{
Packit Service a4b2a9
	if (a->priority < b->priority)
Packit Service a4b2a9
		return -1;
Packit Service a4b2a9
Packit Service a4b2a9
	if (a->priority > b->priority)
Packit Service a4b2a9
		return 1;
Packit Service a4b2a9
Packit Service a4b2a9
	if (!a->weight || a->weight == b->weight)
Packit Service a4b2a9
		return 0;
Packit Service a4b2a9
Packit Service a4b2a9
	if (a->weight > b->weight)
Packit Service a4b2a9
		return -1;
Packit Service a4b2a9
Packit Service a4b2a9
	return 1;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static void free_srv_rrs(struct srv_rr *dcs, unsigned int count)
Packit Service a4b2a9
{
Packit Service a4b2a9
	int i;
Packit Service a4b2a9
Packit Service a4b2a9
	for (i = 0; i < count; i++) {
Packit Service a4b2a9
		if (dcs[i].name)
Packit Service a4b2a9
			free((void *) dcs[i].name);
Packit Service a4b2a9
	}
Packit Service a4b2a9
	free(dcs);
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
int get_srv_rrs(unsigned int logopt,
Packit Service a4b2a9
		char *name, struct srv_rr **dcs, unsigned int *dcs_count)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct srv_rr *srvs;
Packit Service a4b2a9
	unsigned int srv_num;
Packit Service a4b2a9
	HEADER *header;
Packit Service a4b2a9
	u_char *packet;
Packit Service a4b2a9
	u_char *start;
Packit Service a4b2a9
	u_char *end;
Packit Service a4b2a9
	unsigned int count;
Packit Service a4b2a9
	int i, len;
Packit Service a4b2a9
	char ebuf[MAX_ERR_BUF];
Packit Service a4b2a9
Packit Service a4b2a9
	len = do_srv_query(logopt, name, &packet);
Packit Service a4b2a9
	if (len < 0)
Packit Service a4b2a9
		return 0;
Packit Service a4b2a9
Packit Service a4b2a9
	header = (HEADER *) packet;
Packit Service a4b2a9
	start = packet + sizeof(HEADER);
Packit Service a4b2a9
	end = packet + len;
Packit Service a4b2a9
Packit Service a4b2a9
	srvs = NULL;
Packit Service a4b2a9
	srv_num = 0;
Packit Service a4b2a9
Packit Service a4b2a9
	/* Skip over question */
Packit Service a4b2a9
	len = get_name_len(packet, start, end);
Packit Service a4b2a9
	if (len < 0) {
Packit Service a4b2a9
		error(logopt, "failed to get name length");
Packit Service a4b2a9
		goto error_out;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	start += len + QFIXEDSZ;
Packit Service a4b2a9
Packit Service a4b2a9
	count = ntohs(header->ancount);
Packit Service a4b2a9
Packit Service a4b2a9
	debug(logopt, "%d records returned in the answer section", count);
Packit Service a4b2a9
Packit Service a4b2a9
	if (count <= 0) {
Packit Service a4b2a9
		error(logopt, "no records found in answers section");
Packit Service a4b2a9
		goto error_out;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	srvs = malloc(sizeof(struct srv_rr) * count);
Packit Service a4b2a9
	if (!srvs) {
Packit Service a4b2a9
		char *estr = strerror_r(errno, ebuf, MAX_ERR_BUF);
Packit Service a4b2a9
		error(logopt, "malloc: %s", estr);
Packit Service a4b2a9
		goto error_out;
Packit Service a4b2a9
	}
Packit Service a4b2a9
	memset(srvs, 0, sizeof(struct srv_rr) * count);
Packit Service a4b2a9
Packit Service a4b2a9
	srv_num = 0;
Packit Service a4b2a9
	for (i = 0; i < count && (start < end); i++) {
Packit Service a4b2a9
		unsigned int data_offset;
Packit Service a4b2a9
		struct srv_rr srv;
Packit Service a4b2a9
		struct srv_rr *psrv;
Packit Service a4b2a9
		struct rr rr;
Packit Service a4b2a9
Packit Service a4b2a9
		memset(&rr, 0, sizeof(struct rr));
Packit Service a4b2a9
Packit Service a4b2a9
		data_offset = get_data_offset(packet, start, end, &rr);
Packit Service a4b2a9
		if (data_offset <= 0) {
Packit Service a4b2a9
			error(logopt, "failed to get start of data");
Packit Service a4b2a9
			goto error_out;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		start += data_offset;
Packit Service a4b2a9
Packit Service a4b2a9
		if (rr.type != T_SRV)
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
Packit Service a4b2a9
		psrv = parse_srv_rr(logopt, packet, start, end, &rr, &srv;;
Packit Service a4b2a9
		if (psrv) {
Packit Service a4b2a9
			memcpy(&srvs[srv_num], psrv, sizeof(struct srv_rr));
Packit Service a4b2a9
			srv_num++;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		start += rr.len;
Packit Service a4b2a9
	}
Packit Service a4b2a9
	free(packet);
Packit Service a4b2a9
Packit Service a4b2a9
	if (!srv_num) {
Packit Service a4b2a9
		error(logopt, "no srv resource records found");
Packit Service a4b2a9
		goto error_srvs;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	qsort(srvs, srv_num, sizeof(struct srv_rr),
Packit Service a4b2a9
		(int (*)(const void *, const void *)) cmp);
Packit Service a4b2a9
Packit Service a4b2a9
	*dcs = srvs;
Packit Service a4b2a9
	*dcs_count = srv_num;
Packit Service a4b2a9
Packit Service a4b2a9
	return 1;
Packit Service a4b2a9
Packit Service a4b2a9
error_out:
Packit Service a4b2a9
	free(packet);
Packit Service a4b2a9
error_srvs:
Packit Service a4b2a9
	if (srvs)
Packit Service a4b2a9
		free_srv_rrs(srvs, srv_num);
Packit Service a4b2a9
	return 0;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static char *escape_dn_commas(const char *uri)
Packit Service a4b2a9
{
Packit Service a4b2a9
	size_t len = strlen(uri);
Packit Service a4b2a9
	char *new, *tmp, *ptr;
Packit Service a4b2a9
Packit Service a4b2a9
	ptr = (char *) uri;
Packit Service a4b2a9
	while (*ptr) {
Packit Service a4b2a9
		if (*ptr == '\\')
Packit Service a4b2a9
			ptr += 2;
Packit Service a4b2a9
		if (*ptr == ',')
Packit Service a4b2a9
			len += 2;
Packit Service a4b2a9
		ptr++;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	new = malloc(len + 1);
Packit Service a4b2a9
	if (!new)
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	memset(new, 0, len + 1);
Packit Service a4b2a9
Packit Service a4b2a9
	ptr = (char *) uri;
Packit Service a4b2a9
	tmp = new;
Packit Service a4b2a9
	while (*ptr) {
Packit Service a4b2a9
		if (*ptr == '\\') {
Packit Service a4b2a9
			ptr++;
Packit Service a4b2a9
			*tmp++ = *ptr++;
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		if (*ptr == ',') {
Packit Service a4b2a9
			strcpy(tmp, "%2c");
Packit Service a4b2a9
			ptr++;
Packit Service a4b2a9
			tmp += 3;
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		*tmp++ = *ptr++;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	return new;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
void free_dclist(struct dclist *dclist)
Packit Service a4b2a9
{
Packit Service a4b2a9
	if (dclist->uri)
Packit Service a4b2a9
		free((void *) dclist->uri);
Packit Service a4b2a9
	free(dclist);
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
static char *getdnsdomainname(unsigned int logopt)
Packit Service a4b2a9
{
Packit Service a4b2a9
	struct addrinfo hints, *ni;
Packit Service a4b2a9
	char name[MAXDNAME + 1];
Packit Service a4b2a9
	char buf[MAX_ERR_BUF];
Packit Service a4b2a9
	char *dnsdomain = NULL;
Packit Service a4b2a9
	char *ptr;
Packit Service a4b2a9
	int ret;
Packit Service a4b2a9
Packit Service a4b2a9
	memset(name, 0, sizeof(name));
Packit Service a4b2a9
	if (gethostname(name, MAXDNAME) == -1) {
Packit Service a4b2a9
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
		error(logopt, "gethostname: %s", estr);
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	memset(&hints, 0, sizeof(hints));
Packit Service a4b2a9
	hints.ai_flags = AI_CANONNAME;
Packit Service a4b2a9
	hints.ai_family = AF_UNSPEC;
Packit Service a4b2a9
	hints.ai_socktype = SOCK_DGRAM;
Packit Service a4b2a9
Packit Service a1e0af
	ni = NULL;
Packit Service a4b2a9
	ret = getaddrinfo(name, NULL, &hints, &ni);
Packit Service a4b2a9
	if (ret) {
Packit Service 6ff4f4
		error(logopt,
Packit Service 6ff4f4
		      "hostname lookup for %s failed: %s",
Packit Service 6ff4f4
		      name, gai_strerror(ret));
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	ptr = ni->ai_canonname;
Packit Service a4b2a9
	while (*ptr && *ptr != '.')
Packit Service a4b2a9
		ptr++;
Packit Service a4b2a9
Packit Service a4b2a9
	if (*++ptr)
Packit Service a4b2a9
		dnsdomain = strdup(ptr);
Packit Service a4b2a9
Packit Service a4b2a9
	freeaddrinfo(ni);
Packit Service a4b2a9
Packit Service a4b2a9
	return dnsdomain;
Packit Service a4b2a9
}
Packit Service a4b2a9
Packit Service a4b2a9
struct dclist *get_dc_list(unsigned int logopt, const char *uri)
Packit Service a4b2a9
{
Packit Service a4b2a9
	LDAPURLDesc *ludlist = NULL;
Packit Service a4b2a9
	LDAPURLDesc **ludp;
Packit Service a4b2a9
	unsigned int min_ttl = MAX_TTL;
Packit Service a4b2a9
	struct dclist *dclist = NULL;;
Packit Service a4b2a9
	char buf[MAX_ERR_BUF];
Packit Service a4b2a9
	char *dn_uri, *esc_uri;
Packit Service a4b2a9
	char *domain;
Packit Service a4b2a9
	char *list;
Packit Service a4b2a9
	int ret;
Packit Service a4b2a9
Packit Service a4b2a9
	if (strcmp(uri, "ldap:///") && strcmp(uri, "ldaps:///")) {
Packit Service a4b2a9
		dn_uri = strdup(uri);
Packit Service a4b2a9
		if (!dn_uri) {
Packit Service a4b2a9
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
			error(logopt, "strdup: %s", estr);
Packit Service a4b2a9
			return NULL;
Packit Service a4b2a9
		}
Packit Service a4b2a9
	} else {
Packit Service a4b2a9
		char *dnsdomain;
Packit Service a4b2a9
		char *hdn;
Packit Service a4b2a9
Packit Service a4b2a9
		dnsdomain = getdnsdomainname(logopt);
Packit Service a4b2a9
		if (!dnsdomain) {
Packit Service a4b2a9
			error(logopt, "failed to get dns domainname");
Packit Service a4b2a9
			return NULL;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		if (ldap_domain2dn(dnsdomain, &hdn) || hdn == NULL) {
Packit Service a4b2a9
			error(logopt,
Packit Service a4b2a9
			      "Could not turn domain \"%s\" into a dn\n",
Packit Service a4b2a9
			      dnsdomain);
Packit Service a4b2a9
			free(dnsdomain);
Packit Service a4b2a9
			return NULL;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		free(dnsdomain);
Packit Service a4b2a9
Packit Service a4b2a9
		dn_uri = malloc(strlen(uri) + strlen(hdn) + 1);
Packit Service a4b2a9
		if (!dn_uri) {
Packit Service a4b2a9
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
			error(logopt, "malloc: %s", estr);
Packit Service a4b2a9
			ber_memfree(hdn);
Packit Service a4b2a9
			return NULL;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		strcpy(dn_uri, uri);
Packit Service a4b2a9
		strcat(dn_uri, hdn);
Packit Service a4b2a9
		ber_memfree(hdn);
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	esc_uri = escape_dn_commas(dn_uri);
Packit Service a4b2a9
	if (!esc_uri) {
Packit Service a4b2a9
		error(logopt, "Could not escape commas in uri %s", dn_uri);
Packit Service a4b2a9
		free(dn_uri);
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	ret = ldap_url_parse(esc_uri, &ludlist);
Packit Service a4b2a9
	if (ret != LDAP_URL_SUCCESS) {
Packit Service a4b2a9
		error(logopt, "Could not parse uri %s (%d)", dn_uri, ret);
Packit Service a4b2a9
		free(esc_uri);
Packit Service a4b2a9
		free(dn_uri);
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	free(esc_uri);
Packit Service a4b2a9
Packit Service a4b2a9
	if (!ludlist) {
Packit Service a4b2a9
		error(logopt, "No dn found in uri %s", dn_uri);
Packit Service a4b2a9
		free(dn_uri);
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	free(dn_uri);
Packit Service a4b2a9
Packit Service a4b2a9
	dclist = malloc(sizeof(struct dclist));
Packit Service a4b2a9
	if (!dclist) {
Packit Service a4b2a9
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
		error(logopt, "malloc: %s", estr);
Packit Service a4b2a9
		ldap_free_urldesc(ludlist);
Packit Service a4b2a9
		return NULL;
Packit Service a4b2a9
	}
Packit Service a4b2a9
	memset(dclist, 0, sizeof(struct dclist));
Packit Service a4b2a9
Packit Service a4b2a9
	list = NULL;
Packit Service a4b2a9
	for (ludp = &ludlist; *ludp != NULL;) {
Packit Service a4b2a9
		LDAPURLDesc *lud = *ludp;
Packit Service a4b2a9
		struct srv_rr *dcs = NULL;
Packit Service a4b2a9
		unsigned int numdcs = 0;
Packit Service a4b2a9
		size_t req_len, len;
Packit Service a4b2a9
		char *request = NULL;
Packit Service a4b2a9
		char *tmp;
Packit Service a4b2a9
		int i;
Packit Service a4b2a9
Packit Service a4b2a9
		if (!lud->lud_dn && !lud->lud_dn[0] &&
Packit Service a4b2a9
		   (!lud->lud_host || !lud->lud_host[0])) {
Packit Service a4b2a9
			*ludp = lud->lud_next;
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		domain = NULL;
Packit Service a4b2a9
		if (ldap_dn2domain(lud->lud_dn, &domain) || domain == NULL) {
Packit Service a4b2a9
			error(logopt,
Packit Service a4b2a9
			      "Could not turn dn \"%s\" into a domain",
Packit Service a4b2a9
			      lud->lud_dn);
Packit Service a4b2a9
			*ludp = lud->lud_next;
Packit Service a4b2a9
			continue;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		debug(logopt, "doing lookup of SRV RRs for domain %s", domain);
Packit Service a4b2a9
Packit Service a4b2a9
		req_len = sizeof("_ldap._tcp.") + strlen(domain);
Packit Service a4b2a9
		request = malloc(req_len);
Packit Service a4b2a9
		if (!request) {
Packit Service a4b2a9
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
			error(logopt, "malloc: %s", estr);
Packit Service a4b2a9
			goto out_error;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		ret = snprintf(request, req_len, "_ldap._tcp.%s", domain);
Packit Service a4b2a9
		if (ret >= req_len) {
Packit Service a4b2a9
			free(request);
Packit Service a4b2a9
			goto out_error;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		dclist_mutex_lock();
Packit Service a4b2a9
		ret = get_srv_rrs(logopt, request, &dcs, &numdcs);
Packit Service a4b2a9
		if (!ret | !dcs) {
Packit Service a4b2a9
			error(logopt,
Packit Service a4b2a9
			      "DNS SRV query failed for domain %s", domain);
Packit Service a4b2a9
			dclist_mutex_unlock();
Packit Service a4b2a9
			free(request);
Packit Service a4b2a9
			goto out_error;
Packit Service a4b2a9
		}
Packit Service a4b2a9
		dclist_mutex_unlock();
Packit Service a4b2a9
		free(request);
Packit Service a4b2a9
Packit Service a4b2a9
		len = strlen(lud->lud_scheme);
Packit Service a4b2a9
		len += sizeof("://");
Packit Service a4b2a9
		len *= numdcs;
Packit Service a4b2a9
Packit Service a4b2a9
		for (i = 0; i < numdcs; i++) {
Packit Service a4b2a9
			if (dcs[i].ttl > 0 && dcs[i].ttl < min_ttl)
Packit Service a4b2a9
				min_ttl = dcs[i].ttl;
Packit Service a4b2a9
			len += strlen(dcs[i].name);
Packit Service a4b2a9
			if (dcs[i].port > 0)
Packit Service a4b2a9
				len += sizeof(":65535");
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		tmp = realloc(list, len);
Packit Service a4b2a9
		if (!tmp) {
Packit Service a4b2a9
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit Service a4b2a9
			error(logopt, "realloc: %s", estr);
Packit Service a4b2a9
			free_srv_rrs(dcs, numdcs);
Packit Service a4b2a9
			goto out_error;
Packit Service a4b2a9
		}
Packit Service a4b2a9
Packit Service a4b2a9
		if (!list)
Packit Service a4b2a9
			memset(tmp, 0, len);
Packit Service a4b2a9
		else
Packit Service a4b2a9
			strcat(tmp, " ");
Packit Service a4b2a9
Packit Service a4b2a9
		list = NULL;
Packit Service a4b2a9
		for (i = 0; i < numdcs; i++) {
Packit Service a4b2a9
			if (i > 0)
Packit Service a4b2a9
				strcat(tmp, " ");
Packit Service a4b2a9
			strcat(tmp, lud->lud_scheme);
Packit Service a4b2a9
			strcat(tmp, "://");
Packit Service a4b2a9
			strcat(tmp, dcs[i].name);
Packit Service a4b2a9
			if (dcs[i].port > 0) {
Packit Service a4b2a9
				char port[7];
Packit Service a4b2a9
				ret = snprintf(port, 7, ":%d", dcs[i].port);
Packit Service a4b2a9
				if (ret > 6) {
Packit Service a4b2a9
					error(logopt,
Packit Service a4b2a9
					      "invalid port: %u", dcs[i].port);
Packit Service a4b2a9
					free_srv_rrs(dcs, numdcs);
Packit Service a4b2a9
					free(tmp);
Packit Service a4b2a9
					goto out_error;
Packit Service a4b2a9
				}
Packit Service a4b2a9
				strcat(tmp, port);
Packit Service a4b2a9
			}
Packit Service a4b2a9
		}
Packit Service a4b2a9
		list = tmp;
Packit Service a4b2a9
Packit Service a4b2a9
		*ludp = lud->lud_next;
Packit Service a4b2a9
		ber_memfree(domain);
Packit Service a4b2a9
		free_srv_rrs(dcs, numdcs);
Packit Service a4b2a9
	}
Packit Service a4b2a9
Packit Service a4b2a9
	ldap_free_urldesc(ludlist);
Packit Service a4b2a9
Packit Service a4b2a9
	if (!list)
Packit Service a4b2a9
		goto out_error;
Packit Service a4b2a9
Packit Service a4b2a9
	dclist->expire = monotonic_time(NULL) + min_ttl;
Packit Service a4b2a9
	dclist->uri = list;
Packit Service a4b2a9
Packit Service a4b2a9
	return dclist;
Packit Service a4b2a9
Packit Service a4b2a9
out_error:
Packit Service a4b2a9
	if (list)
Packit Service a4b2a9
		free(list);
Packit Service a4b2a9
	if (domain)
Packit Service a4b2a9
		ber_memfree(domain);
Packit Service a4b2a9
	ldap_free_urldesc(ludlist);
Packit Service a4b2a9
	free_dclist(dclist);
Packit Service a4b2a9
	return NULL;
Packit Service a4b2a9
}