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