|
Packit Service |
6d40f9 |
/*
|
|
Packit Service |
6d40f9 |
* adcli
|
|
Packit Service |
6d40f9 |
*
|
|
Packit Service |
6d40f9 |
* Copyright (C) 2012 Red Hat Inc.
|
|
Packit Service |
6d40f9 |
*
|
|
Packit Service |
6d40f9 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
6d40f9 |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit Service |
6d40f9 |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
6d40f9 |
* the License, or (at your option) any later version.
|
|
Packit Service |
6d40f9 |
*
|
|
Packit Service |
6d40f9 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit Service |
6d40f9 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
6d40f9 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
6d40f9 |
* Lesser General Public License for more details.
|
|
Packit Service |
6d40f9 |
*
|
|
Packit Service |
6d40f9 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
6d40f9 |
* License along with this program; if not, write to the Free Software
|
|
Packit Service |
6d40f9 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
Packit Service |
6d40f9 |
* MA 02110-1301 USA
|
|
Packit Service |
6d40f9 |
*
|
|
Packit Service |
6d40f9 |
* Author: Stef Walter <stefw@gnome.org>
|
|
Packit Service |
6d40f9 |
*/
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
#include "config.h"
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
#include "adcli.h"
|
|
Packit Service |
6d40f9 |
#include "adprivate.h"
|
|
Packit Service |
6d40f9 |
#include "addisco.h"
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
#include <sys/types.h>
|
|
Packit Service |
6d40f9 |
#include <sys/socket.h>
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
#include <arpa/inet.h>
|
|
Packit Service |
6d40f9 |
#include <arpa/nameser.h>
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
#include <assert.h>
|
|
Packit Service |
6d40f9 |
#include <netdb.h>
|
|
Packit Service |
6d40f9 |
#include <resolv.h>
|
|
Packit Service |
6d40f9 |
#include <stdio.h>
|
|
Packit Service |
6d40f9 |
#include <stdlib.h>
|
|
Packit Service |
6d40f9 |
#include <string.h>
|
|
Packit Service |
6d40f9 |
#include <time.h>
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Number of servers to do discovery against */
|
|
Packit Service |
6d40f9 |
#define DISCO_COUNT 5
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* The time period in which to do rapid requests */
|
|
Packit Service |
6d40f9 |
#define DISCO_FEVER 1
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Discovery timeout in seconds */
|
|
Packit Service |
6d40f9 |
#define DISCO_TIME 15
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Type of LDAP to use for discovery */
|
|
Packit Service |
6d40f9 |
#define DISCO_SCHEME "cldap"
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
typedef struct _srvinfo {
|
|
Packit Service |
6d40f9 |
unsigned short priority;
|
|
Packit Service |
6d40f9 |
unsigned short weight;
|
|
Packit Service |
6d40f9 |
unsigned short port;
|
|
Packit Service |
6d40f9 |
char *hostname;
|
|
Packit Service |
6d40f9 |
struct _srvinfo *next;
|
|
Packit Service |
6d40f9 |
} srvinfo;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static void
|
|
Packit Service |
6d40f9 |
freesrvinfo (srvinfo *res)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
srvinfo *next;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
while (res != NULL) {
|
|
Packit Service |
6d40f9 |
next = res->next;
|
|
Packit Service |
6d40f9 |
free (res->hostname);
|
|
Packit Service |
6d40f9 |
free (res);
|
|
Packit Service |
6d40f9 |
res = next;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
perform_query (const char *rrname,
|
|
Packit Service |
6d40f9 |
unsigned char **answer,
|
|
Packit Service |
6d40f9 |
int *length)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
unsigned char *ans = NULL;
|
|
Packit Service |
6d40f9 |
unsigned char *mem;
|
|
Packit Service |
6d40f9 |
int len = 512;
|
|
Packit Service |
6d40f9 |
int herr;
|
|
Packit Service |
6d40f9 |
int ret;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
for (;;) {
|
|
Packit Service |
6d40f9 |
len *= 2;
|
|
Packit Service |
6d40f9 |
mem = realloc (ans, len);
|
|
Packit Service |
6d40f9 |
if (mem == NULL) {
|
|
Packit Service |
6d40f9 |
free (ans);
|
|
Packit Service |
6d40f9 |
return EAI_MEMORY;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
ans = mem;
|
|
Packit Service |
6d40f9 |
ret = res_query (rrname, C_IN, T_SRV, ans, len);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* If answer fit in the buffer then we're done */
|
|
Packit Service |
6d40f9 |
if (ret < 0 || ret < len) {
|
|
Packit Service |
6d40f9 |
len = ret;
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/*
|
|
Packit Service |
6d40f9 |
* On overflow some res_query's return the length needed, others
|
|
Packit Service |
6d40f9 |
* return the full length entered. This code works in either case.
|
|
Packit Service |
6d40f9 |
*/
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
herr = h_errno;
|
|
Packit Service |
6d40f9 |
if (len <= 0) {
|
|
Packit Service |
6d40f9 |
free (ans);
|
|
Packit Service |
6d40f9 |
if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA)
|
|
Packit Service |
6d40f9 |
return EAI_NONAME;
|
|
Packit Service |
6d40f9 |
else if (herr == TRY_AGAIN)
|
|
Packit Service |
6d40f9 |
return EAI_AGAIN;
|
|
Packit Service |
6d40f9 |
else
|
|
Packit Service |
6d40f9 |
return EAI_FAIL;
|
|
Packit Service |
6d40f9 |
} else {
|
|
Packit Service |
6d40f9 |
*answer = ans;
|
|
Packit Service |
6d40f9 |
*length = len;
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static unsigned short
|
|
Packit Service |
6d40f9 |
get_16 (unsigned char **p,
|
|
Packit Service |
6d40f9 |
unsigned char *end)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
unsigned short val;
|
|
Packit Service |
6d40f9 |
if (end - (*p) < 2)
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
val = ns_get16 (*p);
|
|
Packit Service |
6d40f9 |
(*p) += 2;
|
|
Packit Service |
6d40f9 |
return val;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static unsigned long
|
|
Packit Service |
6d40f9 |
get_32 (unsigned char **p,
|
|
Packit Service |
6d40f9 |
unsigned char *end)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
unsigned long val;
|
|
Packit Service |
6d40f9 |
if (end - (*p) < 4)
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
val = ns_get32 (*p);
|
|
Packit Service |
6d40f9 |
(*p) += 4;
|
|
Packit Service |
6d40f9 |
return val;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static char *
|
|
Packit Service |
6d40f9 |
get_string (unsigned char *beg,
|
|
Packit Service |
6d40f9 |
unsigned char *end,
|
|
Packit Service |
6d40f9 |
unsigned char **at)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
char buffer[HOST_NAME_MAX];
|
|
Packit Service |
6d40f9 |
int n;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
n = dn_expand (beg, end, *at, buffer, sizeof (buffer));
|
|
Packit Service |
6d40f9 |
if (n < 0)
|
|
Packit Service |
6d40f9 |
return NULL;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
(*at) += n;
|
|
Packit Service |
6d40f9 |
return strdup (buffer);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
parse_record (unsigned char *answer,
|
|
Packit Service |
6d40f9 |
unsigned char *p,
|
|
Packit Service |
6d40f9 |
unsigned char *end,
|
|
Packit Service |
6d40f9 |
srvinfo **res)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
srvinfo *srv;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Check that the below calls are sane */
|
|
Packit Service |
6d40f9 |
if (end - p < 8)
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
srv = calloc (1, sizeof (srvinfo));
|
|
Packit Service |
6d40f9 |
if (srv == NULL)
|
|
Packit Service |
6d40f9 |
return EAI_MEMORY;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
srv->priority = get_16 (&p, end);
|
|
Packit Service |
6d40f9 |
srv->weight = get_16 (&p, end);
|
|
Packit Service |
6d40f9 |
srv->port = get_16 (&p, end);
|
|
Packit Service |
6d40f9 |
srv->hostname = get_string (answer, end, &p);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (!srv->hostname) {
|
|
Packit Service |
6d40f9 |
free (srv);
|
|
Packit Service |
6d40f9 |
return EAI_FAIL;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* This is not perfect RFC 2782 sorting */
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
while (*res != NULL) {
|
|
Packit Service |
6d40f9 |
if (srv->priority == (*res)->priority) {
|
|
Packit Service |
6d40f9 |
/* Just sort zero weights first */
|
|
Packit Service |
6d40f9 |
if (!!srv->weight > !!((*res)->weight))
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
} else if (srv->priority > (*res)->priority) {
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
res = &((*res)->next);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
srv->next = *res;
|
|
Packit Service |
6d40f9 |
*res = srv;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
parse_answer (unsigned char *answer,
|
|
Packit Service |
6d40f9 |
int length,
|
|
Packit Service |
6d40f9 |
srvinfo **res)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
srvinfo *results = NULL;
|
|
Packit Service |
6d40f9 |
unsigned char *p, *end;
|
|
Packit Service |
6d40f9 |
unsigned short type, qclass, rdlength;
|
|
Packit Service |
6d40f9 |
HEADER *header;
|
|
Packit Service |
6d40f9 |
int count;
|
|
Packit Service |
6d40f9 |
int ret;
|
|
Packit Service |
6d40f9 |
int n;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
header = (HEADER *)answer;
|
|
Packit Service |
6d40f9 |
p = answer + sizeof (HEADER);
|
|
Packit Service |
6d40f9 |
end = answer + length;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (p > end)
|
|
Packit Service |
6d40f9 |
return EAI_FAIL;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Skip query */
|
|
Packit Service |
6d40f9 |
count = ntohs (header->qdcount);
|
|
Packit Service |
6d40f9 |
while (count-- && p < end) {
|
|
Packit Service |
6d40f9 |
n = dn_skipname (p, end);
|
|
Packit Service |
6d40f9 |
if (n < 0)
|
|
Packit Service |
6d40f9 |
return EAI_FAIL;
|
|
Packit Service |
6d40f9 |
p += (n + 4);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (count >= 0)
|
|
Packit Service |
6d40f9 |
return EAI_FAIL;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Read answers */
|
|
Packit Service |
6d40f9 |
count = ntohs (header->ancount);
|
|
Packit Service |
6d40f9 |
while (count-- && p < end) {
|
|
Packit Service |
6d40f9 |
n = dn_skipname (p, end);
|
|
Packit Service |
6d40f9 |
if (n < 0 || (end - p) < (n + 10)) {
|
|
Packit Service |
6d40f9 |
freesrvinfo (results);
|
|
Packit Service |
6d40f9 |
return EAI_FAIL;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
p += n;
|
|
Packit Service |
6d40f9 |
type = get_16 (&p, end);
|
|
Packit Service |
6d40f9 |
qclass = get_16 (&p, end);
|
|
Packit Service |
6d40f9 |
get_32 (&p, end); /* skip the ttl */
|
|
Packit Service |
6d40f9 |
rdlength = get_16 (&p, end);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (type == T_SRV && qclass == C_IN && (end - p) >= rdlength) {
|
|
Packit Service |
6d40f9 |
ret = parse_record (answer, p, end, &results);
|
|
Packit Service |
6d40f9 |
if (ret != 0) {
|
|
Packit Service |
6d40f9 |
freesrvinfo (results);
|
|
Packit Service |
6d40f9 |
return ret;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
p += rdlength;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Note that we allow truncated results by not checking count */
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* 'A Target of "." means that the service is decidedly not
|
|
Packit Service |
6d40f9 |
* available at this domain.'
|
|
Packit Service |
6d40f9 |
*/
|
|
Packit Service |
6d40f9 |
if (results == NULL ||
|
|
Packit Service |
6d40f9 |
(results->next == NULL &&
|
|
Packit Service |
6d40f9 |
strcmp (results->hostname, ".") == 0)) {
|
|
Packit Service |
6d40f9 |
freesrvinfo (results);
|
|
Packit Service |
6d40f9 |
return EAI_NONAME;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
*res = results;
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
getsrvinfo (const char *rrname,
|
|
Packit Service |
6d40f9 |
srvinfo **res)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
unsigned char *answer;
|
|
Packit Service |
6d40f9 |
int length;
|
|
Packit Service |
6d40f9 |
int ret;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
ret = perform_query (rrname, &answer, &length);
|
|
Packit Service |
6d40f9 |
if (ret != 0)
|
|
Packit Service |
6d40f9 |
return ret;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
ret = parse_answer (answer, length, res);
|
|
Packit Service |
6d40f9 |
free (answer);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
return ret;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
parse_disco_string (unsigned char *beg,
|
|
Packit Service |
6d40f9 |
unsigned char *end,
|
|
Packit Service |
6d40f9 |
unsigned char **at,
|
|
Packit Service |
6d40f9 |
char **result)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
char *string;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
assert (result);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
string = get_string (beg, end, at);
|
|
Packit Service |
6d40f9 |
if (string == NULL)
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
free (*result);
|
|
Packit Service |
6d40f9 |
*result = string;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
return 1;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
get_32_le (unsigned char **at,
|
|
Packit Service |
6d40f9 |
unsigned char *end,
|
|
Packit Service |
6d40f9 |
unsigned int *val)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
unsigned char *p = *at;
|
|
Packit Service |
6d40f9 |
if (end - p < 4)
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
*val = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
|
|
Packit Service |
6d40f9 |
(*at) += 4;
|
|
Packit Service |
6d40f9 |
return 1;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
skip_n (unsigned char **at,
|
|
Packit Service |
6d40f9 |
unsigned char *end,
|
|
Packit Service |
6d40f9 |
int n)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
if (end - (*at) < n)
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
(*at) += n;
|
|
Packit Service |
6d40f9 |
return 1;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static adcli_disco *
|
|
Packit Service |
6d40f9 |
parse_disco_data (struct berval *bv)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
unsigned char *at, *end, *beg;
|
|
Packit Service |
6d40f9 |
unsigned int type;
|
|
Packit Service |
6d40f9 |
adcli_disco *disco;
|
|
Packit Service |
6d40f9 |
char *user = NULL;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
beg = (unsigned char *)bv->bv_val;
|
|
Packit Service |
6d40f9 |
end = beg + bv->bv_len;
|
|
Packit Service |
6d40f9 |
at = beg;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
disco = calloc (1, sizeof (adcli_disco));
|
|
Packit Service |
6d40f9 |
return_val_if_fail (disco != NULL, NULL);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* domain forest */
|
|
Packit Service |
6d40f9 |
if (!get_32_le (&at, end, &type) || type != 23 ||
|
|
Packit Service |
6d40f9 |
!get_32_le (&at, end, &disco->flags) ||
|
|
Packit Service |
6d40f9 |
!skip_n (&at, end, 16) || /* guid */
|
|
Packit Service |
6d40f9 |
!parse_disco_string (beg, end, &at, &disco->forest) ||
|
|
Packit Service |
6d40f9 |
!parse_disco_string (beg, end, &at, &disco->domain) ||
|
|
Packit Service |
6d40f9 |
!parse_disco_string (beg, end, &at, &disco->host_name) ||
|
|
Packit Service |
6d40f9 |
!parse_disco_string (beg, end, &at, &disco->domain_short) ||
|
|
Packit Service |
6d40f9 |
!parse_disco_string (beg, end, &at, &disco->host_short) ||
|
|
Packit Service |
6d40f9 |
!parse_disco_string (beg, end, &at, &user) ||
|
|
Packit Service |
6d40f9 |
!parse_disco_string (beg, end, &at, &disco->server_site) ||
|
|
Packit Service |
6d40f9 |
!parse_disco_string (beg, end, &at, &disco->client_site)) {
|
|
Packit Service |
6d40f9 |
_adcli_warn ("Could not parse NetLogon discovery data");
|
|
Packit Service |
6d40f9 |
adcli_disco_free (disco);
|
|
Packit Service |
6d40f9 |
disco = NULL;
|
|
Packit Service |
6d40f9 |
} else {
|
|
Packit Service |
6d40f9 |
_adcli_info ("Received NetLogon info from: %s", disco->host_name);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* We don't care about these */
|
|
Packit Service |
6d40f9 |
free (user);
|
|
Packit Service |
6d40f9 |
return disco;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
insert_disco_sorted (adcli_disco **res,
|
|
Packit Service |
6d40f9 |
adcli_disco *disco,
|
|
Packit Service |
6d40f9 |
int usability,
|
|
Packit Service |
6d40f9 |
int unique)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
adcli_disco **at = NULL;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Sort in order of usability of this disco record */
|
|
Packit Service |
6d40f9 |
while (*res != NULL) {
|
|
Packit Service |
6d40f9 |
if (unique && strcasecmp (disco->host_name, (*res)->host_name) == 0)
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
if (!at && usability > adcli_disco_usable (*res))
|
|
Packit Service |
6d40f9 |
at = res;
|
|
Packit Service |
6d40f9 |
if (at && !unique)
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
res = &((*res)->next);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (at == NULL)
|
|
Packit Service |
6d40f9 |
at = res;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
disco->next = *at;
|
|
Packit Service |
6d40f9 |
*at = disco;
|
|
Packit Service |
6d40f9 |
return 1;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
parse_disco (LDAP *ldap,
|
|
Packit Service |
6d40f9 |
const char *host_addr,
|
|
Packit Service |
6d40f9 |
LDAPMessage *message,
|
|
Packit Service |
6d40f9 |
adcli_disco **res)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
adcli_disco *disco = NULL;
|
|
Packit Service |
6d40f9 |
LDAPMessage *entry;
|
|
Packit Service |
6d40f9 |
struct berval **bvs;
|
|
Packit Service |
6d40f9 |
int usability;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
entry = ldap_first_entry (ldap, message);
|
|
Packit Service |
6d40f9 |
if (entry != NULL) {
|
|
Packit Service |
6d40f9 |
bvs = ldap_get_values_len (ldap, entry, "NetLogon");
|
|
Packit Service |
6d40f9 |
if (bvs != NULL) {
|
|
Packit Service |
6d40f9 |
if (!bvs[0])
|
|
Packit Service |
6d40f9 |
disco = NULL;
|
|
Packit Service |
6d40f9 |
else
|
|
Packit Service |
6d40f9 |
disco = parse_disco_data (bvs[0]);
|
|
Packit Service |
6d40f9 |
ldap_value_free_len (bvs);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (!disco)
|
|
Packit Service |
6d40f9 |
return ADCLI_DISCO_UNUSABLE;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
disco->host_addr = strdup (host_addr);
|
|
Packit Service |
6d40f9 |
return_val_if_fail (disco, ADCLI_DISCO_UNUSABLE);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
usability = adcli_disco_usable (disco);
|
|
Packit Service |
6d40f9 |
if (!insert_disco_sorted (res, disco, usability, 0))
|
|
Packit Service |
6d40f9 |
assert (0 && "not reached");
|
|
Packit Service |
6d40f9 |
return usability;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
ldap_disco (const char *domain,
|
|
Packit Service |
6d40f9 |
srvinfo *srv,
|
|
Packit Service |
6d40f9 |
adcli_disco **results)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
char *attrs[] = { "NetLogon", NULL };
|
|
Packit Service |
6d40f9 |
LDAP *ldap[DISCO_COUNT];
|
|
Packit Service |
6d40f9 |
const char *addrs[DISCO_COUNT];
|
|
Packit Service |
6d40f9 |
int found = ADCLI_DISCO_UNUSABLE;
|
|
Packit Service |
6d40f9 |
LDAPMessage *message;
|
|
Packit Service |
6d40f9 |
char buffer[1024];
|
|
Packit Service |
6d40f9 |
struct addrinfo hints;
|
|
Packit Service |
6d40f9 |
struct addrinfo *res, *ai;
|
|
Packit Service |
6d40f9 |
const char *scheme;
|
|
Packit Service |
6d40f9 |
int msgidp;
|
|
Packit Service |
6d40f9 |
int version;
|
|
Packit Service |
6d40f9 |
time_t started;
|
|
Packit Service |
6d40f9 |
time_t now;
|
|
Packit Service |
6d40f9 |
char *url;
|
|
Packit Service |
6d40f9 |
char *filter;
|
|
Packit Service |
6d40f9 |
char *value;
|
|
Packit Service |
6d40f9 |
int num, i;
|
|
Packit Service |
6d40f9 |
int ret;
|
|
Packit Service |
6d40f9 |
int have_any = 0;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (domain) {
|
|
Packit Service |
6d40f9 |
value = _adcli_ldap_escape_filter (domain);
|
|
Packit Service |
6d40f9 |
return_val_if_fail (value != NULL, 0);
|
|
Packit Service |
6d40f9 |
if (asprintf (&filter, "(&(DnsDomain=%s)(NtVer=\\06\\00\\00\\00))", value) < 0)
|
|
Packit Service |
6d40f9 |
return_val_if_reached (0);
|
|
Packit Service |
6d40f9 |
free (value);
|
|
Packit Service |
6d40f9 |
} else {
|
|
Packit Service |
6d40f9 |
if (asprintf (&filter, "(&(NtVer=\\06\\00\\00\\00)(AAC=\\00\\00\\00\\00))") < 0)
|
|
Packit Service |
6d40f9 |
return_val_if_reached (0);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
memset (addrs, 0, sizeof (addrs));
|
|
Packit Service |
6d40f9 |
memset (ldap, 0, sizeof (ldap));
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Make sure cldap is supported, it's not always built into openldap */
|
|
Packit Service |
6d40f9 |
if (ldap_is_ldap_url (DISCO_SCHEME "://hostname"))
|
|
Packit Service |
6d40f9 |
scheme = DISCO_SCHEME;
|
|
Packit Service |
6d40f9 |
else
|
|
Packit Service |
6d40f9 |
scheme = "ldap";
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/*
|
|
Packit Service |
6d40f9 |
* The ai_socktype and ai_protocol hint fields are unused below,
|
|
Packit Service |
6d40f9 |
* but are set in order to prevent duplicate returns from
|
|
Packit Service |
6d40f9 |
* getaddrinfo().
|
|
Packit Service |
6d40f9 |
*/
|
|
Packit Service |
6d40f9 |
memset (&hints, 0, sizeof (hints));
|
|
Packit Service |
6d40f9 |
hints.ai_socktype = SOCK_STREAM;
|
|
Packit Service |
6d40f9 |
hints.ai_protocol = IPPROTO_TCP;
|
|
Packit Service |
6d40f9 |
hints.ai_flags |= AI_NUMERICSERV;
|
|
Packit Service |
6d40f9 |
#ifdef AI_ADDRCONFIG
|
|
Packit Service |
6d40f9 |
hints.ai_flags |= AI_ADDRCONFIG;
|
|
Packit Service |
6d40f9 |
#endif
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
for (num = 0; srv != NULL; srv = srv->next) {
|
|
Packit Service |
6d40f9 |
ret = getaddrinfo (srv->hostname, "389", &hints, &res;;
|
|
Packit Service |
6d40f9 |
if (ret != 0) {
|
|
Packit Service |
6d40f9 |
_adcli_warn ("Couldn't resolve server host: %s: %s",
|
|
Packit Service |
6d40f9 |
srv->hostname, gai_strerror (ret));
|
|
Packit Service |
6d40f9 |
continue;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
for (ai = res; num < DISCO_COUNT && ai != NULL; ai = ai->ai_next) {
|
|
Packit Service |
6d40f9 |
if (getnameinfo (ai->ai_addr, ai->ai_addrlen, buffer, sizeof (buffer),
|
|
Packit Service |
6d40f9 |
NULL, 0, NI_NUMERICHOST) != 0)
|
|
Packit Service |
6d40f9 |
return_val_if_reached (0);
|
|
Packit Service |
6d40f9 |
if (ai->ai_family == AF_INET6) {
|
|
Packit Service |
6d40f9 |
/*
|
|
Packit Service |
6d40f9 |
* Currently openldap has cldap bugs when used with IPv6:
|
|
Packit Service |
6d40f9 |
* http://www.openldap.org/its/index.cgi/Incoming?id=7694
|
|
Packit Service |
6d40f9 |
*/
|
|
Packit Service |
6d40f9 |
if (asprintf (&url, "%s://[%s]", "ldap", buffer) < 0)
|
|
Packit Service |
6d40f9 |
return_val_if_reached (0);
|
|
Packit Service |
6d40f9 |
} else {
|
|
Packit Service |
6d40f9 |
if (asprintf (&url, "%s://%s", scheme, buffer) < 0)
|
|
Packit Service |
6d40f9 |
return_val_if_reached (0);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
ret = ldap_initialize (&ldap[num], url);
|
|
Packit Service |
6d40f9 |
if (ret == LDAP_SUCCESS) {
|
|
Packit Service |
6d40f9 |
version = LDAP_VERSION3;
|
|
Packit Service |
6d40f9 |
ldap_set_option (ldap[num], LDAP_OPT_PROTOCOL_VERSION, &version);
|
|
Packit Service |
6d40f9 |
ldap_set_option (ldap[num], LDAP_OPT_REFERRALS , 0);
|
|
Packit Service |
6d40f9 |
_adcli_info ("Sending netlogon pings to domain controller: %s", url);
|
|
Packit Service |
6d40f9 |
addrs[num] = srv->hostname;
|
|
Packit Service |
6d40f9 |
have_any = 1;
|
|
Packit Service |
6d40f9 |
num++;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
} else {
|
|
Packit Service |
6d40f9 |
_adcli_err ("Couldn't perform discovery on server: %s: %s", url, ldap_err2string (ret));
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
free (url);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
freeaddrinfo (res);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Wait for the first response. Poor mans fd watch */
|
|
Packit Service |
6d40f9 |
for (started = now = time (NULL);
|
|
Packit Service |
6d40f9 |
have_any && found != ADCLI_DISCO_USABLE && now < started + DISCO_TIME;
|
|
Packit Service |
6d40f9 |
now = time (NULL)) {
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
struct timeval tvpoll = { 0, 0 };
|
|
Packit Service |
6d40f9 |
struct timeval interval;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* If in the initial period, send feverishly */
|
|
Packit Service |
6d40f9 |
if (now < started + DISCO_FEVER) {
|
|
Packit Service |
6d40f9 |
interval.tv_sec = 0;
|
|
Packit Service |
6d40f9 |
interval.tv_usec = 100 * 1000;
|
|
Packit Service |
6d40f9 |
} else {
|
|
Packit Service |
6d40f9 |
interval.tv_sec = 1;
|
|
Packit Service |
6d40f9 |
interval.tv_usec = 0;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
select (0, NULL, NULL, NULL, &interval);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
have_any = 0;
|
|
Packit Service |
6d40f9 |
for (i = 0; found != ADCLI_DISCO_USABLE && i < num; i++) {
|
|
Packit Service |
6d40f9 |
int close_ldap;
|
|
Packit Service |
6d40f9 |
int parsed;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (ldap[i] == NULL)
|
|
Packit Service |
6d40f9 |
continue;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
ret = 0;
|
|
Packit Service |
6d40f9 |
have_any = 1;
|
|
Packit Service |
6d40f9 |
switch (ldap_result (ldap[i], LDAP_RES_ANY, 1, &tvpoll, &message)) {
|
|
Packit Service |
6d40f9 |
case LDAP_RES_SEARCH_ENTRY:
|
|
Packit Service |
6d40f9 |
case LDAP_RES_SEARCH_RESULT:
|
|
Packit Service |
6d40f9 |
parsed = parse_disco (ldap[i], addrs[i], message, results);
|
|
Packit Service |
6d40f9 |
if (parsed > found)
|
|
Packit Service |
6d40f9 |
found = parsed;
|
|
Packit Service |
6d40f9 |
ldap_msgfree (message);
|
|
Packit Service |
6d40f9 |
close_ldap = 1;
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
case 0:
|
|
Packit Service |
6d40f9 |
ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE,
|
|
Packit Service |
6d40f9 |
filter, attrs, 0, NULL, NULL, NULL,
|
|
Packit Service |
6d40f9 |
-1, &msgidp);
|
|
Packit Service |
6d40f9 |
close_ldap = (ret != 0);
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
case -1:
|
|
Packit Service |
6d40f9 |
ldap_get_option (ldap[i], LDAP_OPT_RESULT_CODE, &ret;;
|
|
Packit Service |
6d40f9 |
close_ldap = 1;
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
default:
|
|
Packit Service |
6d40f9 |
ldap_msgfree (message);
|
|
Packit Service |
6d40f9 |
close_ldap = 0;
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (ret != LDAP_SUCCESS) {
|
|
Packit Service |
6d40f9 |
_adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG,
|
|
Packit Service |
6d40f9 |
"Couldn't perform discovery search");
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/* Done with this connection */
|
|
Packit Service |
6d40f9 |
if (close_ldap) {
|
|
Packit Service |
6d40f9 |
ldap_unbind_ext_s (ldap[i], NULL, NULL);
|
|
Packit Service |
6d40f9 |
ldap[i] = NULL;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
for (i = 0; i < num; i++) {
|
|
Packit Service |
6d40f9 |
if (ldap[i] != NULL)
|
|
Packit Service |
6d40f9 |
ldap_unbind_ext_s (ldap[i], NULL, NULL);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
free (filter);
|
|
Packit Service |
6d40f9 |
return found;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static void
|
|
Packit Service |
6d40f9 |
fill_disco (adcli_disco **results,
|
|
Packit Service |
6d40f9 |
int usability,
|
|
Packit Service |
6d40f9 |
const char *domain,
|
|
Packit Service |
6d40f9 |
const char *site,
|
|
Packit Service |
6d40f9 |
srvinfo *srv)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
adcli_disco *disco;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
while (srv != NULL) {
|
|
Packit Service |
6d40f9 |
disco = calloc (1, sizeof (adcli_disco));
|
|
Packit Service |
6d40f9 |
return_if_fail (disco != NULL);
|
|
Packit Service |
6d40f9 |
disco->client_site = site ? strdup (site) : NULL;
|
|
Packit Service |
6d40f9 |
disco->server_site = site ? strdup (site) : NULL;
|
|
Packit Service |
6d40f9 |
disco->domain = strdup (domain);
|
|
Packit Service |
6d40f9 |
disco->host_name = strdup (srv->hostname);
|
|
Packit Service |
6d40f9 |
disco->host_addr = strdup (srv->hostname);
|
|
Packit Service |
6d40f9 |
if (!insert_disco_sorted (results, disco, usability, 1))
|
|
Packit Service |
6d40f9 |
adcli_disco_free (disco);
|
|
Packit Service |
6d40f9 |
srv = srv->next;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
static int
|
|
Packit Service |
6d40f9 |
site_disco (adcli_disco *disco,
|
|
Packit Service |
6d40f9 |
adcli_disco **results)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
srvinfo *srv;
|
|
Packit Service |
6d40f9 |
char *rrname;
|
|
Packit Service |
6d40f9 |
int found;
|
|
Packit Service |
6d40f9 |
int ret;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (!disco->client_site || !disco->domain)
|
|
Packit Service |
6d40f9 |
return ADCLI_DISCO_MAYBE;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (asprintf (&rrname, "_ldap._tcp.%s._sites.dc._msdcs.%s",
|
|
Packit Service |
6d40f9 |
disco->client_site, disco->domain) < 0)
|
|
Packit Service |
6d40f9 |
return_val_if_reached (ADCLI_DISCO_UNUSABLE);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
_adcli_info ("Discovering site domain controllers: %s", rrname);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
ret = getsrvinfo (rrname, &srv;;
|
|
Packit Service |
6d40f9 |
switch (ret) {
|
|
Packit Service |
6d40f9 |
case 0:
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
case EAI_NONAME:
|
|
Packit Service |
6d40f9 |
case EAI_AGAIN:
|
|
Packit Service |
6d40f9 |
_adcli_err ("No LDAP SRV site records: %s: %s",
|
|
Packit Service |
6d40f9 |
rrname, gai_strerror (ret));
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
default:
|
|
Packit Service |
6d40f9 |
_adcli_err ("Couldn't resolve SRV site records: %s: %s",
|
|
Packit Service |
6d40f9 |
rrname, gai_strerror (ret));
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
free (rrname);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (ret != 0)
|
|
Packit Service |
6d40f9 |
return ADCLI_DISCO_MAYBE;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
/*
|
|
Packit Service |
6d40f9 |
* Now that we have discovered the site domain controllers do a
|
|
Packit Service |
6d40f9 |
* second round of cldap discovery.
|
|
Packit Service |
6d40f9 |
*/
|
|
Packit Service |
6d40f9 |
found = ldap_disco (disco->domain, srv, results);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
fill_disco (results, ADCLI_DISCO_MAYBE,
|
|
Packit Service |
6d40f9 |
disco->domain, disco->client_site, srv);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
freesrvinfo (srv);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
return found;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
int
|
|
Packit Service |
6d40f9 |
adcli_disco_domain (const char *domain,
|
|
Packit Service |
6d40f9 |
adcli_disco **results)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
char *rrname;
|
|
Packit Service |
6d40f9 |
srvinfo *srv;
|
|
Packit Service |
6d40f9 |
int found;
|
|
Packit Service |
6d40f9 |
int ret;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
return_unexpected_if_fail (domain != NULL);
|
|
Packit Service |
6d40f9 |
return_unexpected_if_fail (results != NULL);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
*results = NULL;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (asprintf (&rrname, "_ldap._tcp.%s", domain) < 0)
|
|
Packit Service |
6d40f9 |
return_unexpected_if_reached ();
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
_adcli_info ("Discovering domain controllers: %s", rrname);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
ret = getsrvinfo (rrname, &srv;;
|
|
Packit Service |
6d40f9 |
switch (ret) {
|
|
Packit Service |
6d40f9 |
case 0:
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
case EAI_NONAME:
|
|
Packit Service |
6d40f9 |
case EAI_AGAIN:
|
|
Packit Service |
6d40f9 |
_adcli_err ("No LDAP SRV records for domain: %s: %s",
|
|
Packit Service |
6d40f9 |
rrname, gai_strerror (ret));
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
default:
|
|
Packit Service |
6d40f9 |
_adcli_err ("Couldn't resolve SRV record: %s: %s",
|
|
Packit Service |
6d40f9 |
rrname, gai_strerror (ret));
|
|
Packit Service |
6d40f9 |
break;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
free (rrname);
|
|
Packit Service |
6d40f9 |
if (ret != 0)
|
|
Packit Service |
6d40f9 |
return 0;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
found = ldap_disco (domain, srv, results);
|
|
Packit Service |
6d40f9 |
if (found == ADCLI_DISCO_MAYBE) {
|
|
Packit Service |
6d40f9 |
assert (*results);
|
|
Packit Service |
6d40f9 |
found = site_disco (*results, results);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
fill_disco (results, ADCLI_DISCO_MAYBE, domain, NULL, srv);
|
|
Packit Service |
6d40f9 |
freesrvinfo (srv);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
return found;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
int
|
|
Packit Service |
6d40f9 |
adcli_disco_host (const char *host,
|
|
Packit Service |
6d40f9 |
adcli_disco **results)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
srvinfo srv;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
return_val_if_fail (host != NULL, 0);
|
|
Packit Service |
6d40f9 |
return_val_if_fail (results != NULL, 0);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
*results = NULL;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
memset (&srv, 0, sizeof (srv));
|
|
Packit Service |
6d40f9 |
srv.hostname = (char *)host;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
return ldap_disco (NULL, &srv, results);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
void
|
|
Packit Service |
6d40f9 |
adcli_disco_free (adcli_disco *disco)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
adcli_disco *next;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
for (; disco != NULL; disco = next) {
|
|
Packit Service |
6d40f9 |
next = disco->next;
|
|
Packit Service |
6d40f9 |
free (disco->host_addr);
|
|
Packit Service |
6d40f9 |
free (disco->host_name);
|
|
Packit Service |
6d40f9 |
free (disco->host_short);
|
|
Packit Service |
6d40f9 |
free (disco->forest);
|
|
Packit Service |
6d40f9 |
free (disco->domain);
|
|
Packit Service |
6d40f9 |
free (disco->domain_short);
|
|
Packit Service |
6d40f9 |
free (disco->client_site);
|
|
Packit Service |
6d40f9 |
free (disco->server_site);
|
|
Packit Service |
6d40f9 |
free (disco);
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
int
|
|
Packit Service |
6d40f9 |
adcli_disco_usable (adcli_disco *disco)
|
|
Packit Service |
6d40f9 |
{
|
|
Packit Service |
6d40f9 |
return_val_if_fail (disco != NULL, ADCLI_DISCO_UNUSABLE);
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (disco->flags != 0) {
|
|
Packit Service |
6d40f9 |
if ((disco->flags & (ADCLI_DISCO_KDC | ADCLI_DISCO_LDAP | ADCLI_DISCO_WRITABLE)) == 0)
|
|
Packit Service |
6d40f9 |
return ADCLI_DISCO_UNUSABLE;
|
|
Packit Service |
6d40f9 |
}
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
if (disco->client_site && disco->server_site &&
|
|
Packit Service |
6d40f9 |
strcasecmp (disco->client_site, disco->server_site) == 0)
|
|
Packit Service |
6d40f9 |
return ADCLI_DISCO_USABLE;
|
|
Packit Service |
6d40f9 |
|
|
Packit Service |
6d40f9 |
return ADCLI_DISCO_MAYBE;
|
|
Packit Service |
6d40f9 |
}
|