mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-21 03:10:25 +08:00
305 lines
5.7 KiB
C
305 lines
5.7 KiB
C
/* $OpenLDAP$ */
|
|
/*
|
|
* Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
|
|
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
|
|
*/
|
|
|
|
/*
|
|
* locate LDAP servers using DNS SRV records.
|
|
* Location code based on MIT Kerberos KDC location code.
|
|
*/
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ac/stdlib.h>
|
|
|
|
#include <ac/param.h>
|
|
#include <ac/socket.h>
|
|
#include <ac/string.h>
|
|
#include <ac/time.h>
|
|
|
|
#include "ldap-int.h"
|
|
|
|
#ifdef HAVE_ARPA_NAMESER_H
|
|
#include <arpa/nameser.h>
|
|
#endif
|
|
#ifdef HAVE_RESOLV_H
|
|
#include <resolv.h>
|
|
#endif
|
|
|
|
/* Sometimes this is not defined. */
|
|
#ifndef T_SRV
|
|
#define T_SRV 33
|
|
#endif /* T_SRV */
|
|
|
|
int ldap_dn2domain(
|
|
LDAP_CONST char *dn_in,
|
|
char **domainp)
|
|
{
|
|
int i;
|
|
char *domain = NULL;
|
|
char **dn;
|
|
|
|
if( dn_in == NULL || domainp == NULL ) {
|
|
return -1;
|
|
}
|
|
|
|
dn = ldap_explode_dn( dn_in, 0 );
|
|
|
|
if( dn == NULL ) {
|
|
return -2;
|
|
}
|
|
|
|
for( i=0; dn[i] != NULL; i++ ) {
|
|
char ** rdn = ldap_explode_rdn( dn[i], 0 );
|
|
|
|
if( rdn == NULL || *rdn == NULL ) {
|
|
LDAP_FREE( rdn );
|
|
LDAP_FREE( domain );
|
|
LDAP_VFREE( dn );
|
|
return -3;
|
|
}
|
|
|
|
|
|
if( rdn[1] == NULL ) {
|
|
/*
|
|
* single-valued RDN
|
|
*/
|
|
char *dc;
|
|
|
|
#define LDAP_DC "dc="
|
|
#define LDAP_DCOID "0.9.2342.19200300.100.1.25="
|
|
|
|
if( strncasecmp( rdn[0],
|
|
LDAP_DC, sizeof(LDAP_DC)-1 ) == 0 )
|
|
{
|
|
dc = &rdn[0][sizeof(LDAP_DC)-1];
|
|
|
|
} else if( strncmp( rdn[0],
|
|
LDAP_DCOID, sizeof(LDAP_DCOID)-1 ) == 0 )
|
|
{
|
|
dc = &rdn[0][sizeof(LDAP_DCOID)-1];
|
|
|
|
} else {
|
|
dc = NULL;
|
|
}
|
|
|
|
if( dc != NULL ) {
|
|
char *ndomain;
|
|
|
|
if( *dc == '\0' ) {
|
|
/* dc value is empty! */
|
|
LDAP_FREE( rdn );
|
|
LDAP_FREE( domain );
|
|
LDAP_VFREE( dn );
|
|
LDAP_VFREE( rdn );
|
|
return -4;
|
|
}
|
|
|
|
ndomain = LDAP_REALLOC( domain,
|
|
( domain == NULL ? 0 : strlen(domain) )
|
|
+ strlen(dc) + sizeof(".") );
|
|
|
|
if( ndomain == NULL ) {
|
|
LDAP_FREE( rdn );
|
|
LDAP_FREE( domain );
|
|
LDAP_VFREE( dn );
|
|
LDAP_VFREE( rdn );
|
|
return -5;
|
|
}
|
|
|
|
if( domain == NULL ) ndomain[0] = '\0';
|
|
|
|
strcat( ndomain, dc );
|
|
strcat( ndomain, "." );
|
|
|
|
domain = ndomain;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* multi-valued RDN or fall thru
|
|
*/
|
|
|
|
LDAP_VFREE( rdn );
|
|
LDAP_FREE( domain );
|
|
domain = NULL;
|
|
}
|
|
|
|
if( domain != NULL && *domain == '\0' ) {
|
|
LDAP_FREE( domain );
|
|
domain = NULL;
|
|
}
|
|
|
|
*domainp = domain;
|
|
return 0;
|
|
}
|
|
|
|
int ldap_domain2dn(
|
|
LDAP_CONST char *domain_in,
|
|
char **dnp)
|
|
{
|
|
char *domain, *s, *tok_r, *dn;
|
|
size_t loc;
|
|
|
|
if (domain_in == NULL || dnp == NULL) {
|
|
return LDAP_NO_MEMORY;
|
|
}
|
|
domain = LDAP_STRDUP(domain_in);
|
|
if (domain == NULL) {
|
|
return LDAP_NO_MEMORY;
|
|
}
|
|
dn = NULL;
|
|
loc = 0;
|
|
|
|
for (s = ldap_pvt_strtok(domain, ".", &tok_r);
|
|
s != NULL;
|
|
s = ldap_pvt_strtok(NULL, ".", &tok_r)) {
|
|
size_t len = strlen(s);
|
|
|
|
dn = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len );
|
|
if (dn == NULL) {
|
|
LDAP_FREE(domain);
|
|
return LDAP_NO_MEMORY;
|
|
}
|
|
if (loc > 0) {
|
|
/* not first time. */
|
|
strcpy(dn + loc, ",");
|
|
loc++;
|
|
}
|
|
strcpy(dn + loc, "dc=");
|
|
loc += sizeof("dc=")-1;
|
|
|
|
strcpy(dn + loc, s);
|
|
loc += len;
|
|
}
|
|
|
|
LDAP_FREE(domain);
|
|
|
|
*dnp = dn;
|
|
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Lookup and return LDAP servers for domain (using the DNS
|
|
* SRV record _ldap._tcp.domain).
|
|
*/
|
|
int ldap_domain2hostlist(
|
|
LDAP_CONST char *domain,
|
|
char **list )
|
|
{
|
|
#ifdef HAVE_RES_SEARCH
|
|
char *request;
|
|
char *dn;
|
|
char *hostlist = NULL;
|
|
int rc, len, cur = 0;
|
|
unsigned char reply[1024];
|
|
|
|
if( domain == NULL || *domain == '\0' ) {
|
|
return LDAP_PARAM_ERROR;
|
|
}
|
|
|
|
if( list == NULL ) {
|
|
return LDAP_PARAM_ERROR;
|
|
}
|
|
|
|
request = LDAP_MALLOC(strlen(domain) + sizeof("_ldap._tcp."));
|
|
if (request == NULL) {
|
|
rc = LDAP_NO_MEMORY;
|
|
goto out;
|
|
}
|
|
sprintf(request, "_ldap._tcp.%s", domain);
|
|
|
|
#ifdef LDAP_R_COMPILE
|
|
ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex);
|
|
#endif
|
|
|
|
rc = LDAP_UNAVAILABLE;
|
|
len = res_search(request, C_IN, T_SRV, reply, sizeof(reply));
|
|
if (len >= 0) {
|
|
unsigned char *p;
|
|
char host[1024];
|
|
int status;
|
|
u_short port;
|
|
/* int priority, weight; */
|
|
|
|
/* Parse out query */
|
|
p = reply;
|
|
p += sizeof(HEADER);
|
|
status = dn_expand(reply, reply + len, p, host, sizeof(host));
|
|
if (status < 0) {
|
|
goto out;
|
|
}
|
|
p += status;
|
|
p += 4;
|
|
|
|
while (p < reply + len) {
|
|
int type, class, ttl, size;
|
|
status = dn_expand(reply, reply + len, p, host, sizeof(host));
|
|
if (status < 0) {
|
|
goto out;
|
|
}
|
|
p += status;
|
|
type = (p[0] << 8) | p[1];
|
|
p += 2;
|
|
class = (p[0] << 8) | p[1];
|
|
p += 2;
|
|
ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
|
p += 4;
|
|
size = (p[0] << 8) | p[1];
|
|
p += 2;
|
|
if (type == T_SRV) {
|
|
int buflen;
|
|
status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
|
|
if (status < 0) {
|
|
goto out;
|
|
}
|
|
/* ignore priority and weight for now */
|
|
/* priority = (p[0] << 8) | p[1]; */
|
|
/* weight = (p[2] << 8) | p[3]; */
|
|
port = (p[4] << 8) | p[5];
|
|
|
|
buflen = strlen(host) + sizeof(":65355");
|
|
hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen);
|
|
if (hostlist == NULL) {
|
|
rc = LDAP_NO_MEMORY;
|
|
goto out;
|
|
}
|
|
if (cur > 0) {
|
|
/* not first time around */
|
|
hostlist[cur++] = ' ';
|
|
}
|
|
cur += sprintf(&hostlist[cur], "%s:%hd", host, port);
|
|
}
|
|
p += size;
|
|
}
|
|
}
|
|
if (hostlist == NULL) {
|
|
/* No LDAP servers found in DNS. */
|
|
rc = LDAP_UNAVAILABLE;
|
|
goto out;
|
|
}
|
|
|
|
rc = LDAP_SUCCESS;
|
|
*list = hostlist;
|
|
|
|
out:
|
|
#ifdef LDAP_R_COMPILE
|
|
ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex);
|
|
#endif
|
|
|
|
if (request != NULL) {
|
|
LDAP_FREE(request);
|
|
}
|
|
if (rc != LDAP_SUCCESS && hostlist != NULL) {
|
|
LDAP_FREE(hostlist);
|
|
}
|
|
return rc;
|
|
#else
|
|
return LDAP_NOT_SUPPORTED;
|
|
#endif /* HAVE_RES_SEARCH */
|
|
}
|