1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-23 09:57:40 +03:00

libads: Add API call to connect to a global catalog server.

Extends ads_connect() to a new call ads_connect_gc() which connects on port
3268 rather than port 389.  Also makes ads_try_connect() static and
only used internally to ldap.c
(This used to be commit f4c37dbe2c986fb7bfe510cdff3b4a9fbc06d079)
This commit is contained in:
Gerald W. Carter 2008-06-27 10:22:39 -04:00
parent e08943f8d8
commit 9ff1ffcbee
5 changed files with 148 additions and 9 deletions

View File

@ -53,7 +53,9 @@ typedef struct ads_struct {
char *realm;
char *workgroup;
char *ldap_server;
int foreign; /* set to 1 if connecting to a foreign realm */
int foreign; /* set to 1 if connecting to a foreign
* realm */
bool gc; /* Is this a global catalog server? */
} server;
/* info needed to authenticate */

View File

@ -2063,7 +2063,6 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
bool ads_sitename_match(ADS_STRUCT *ads);
bool ads_closest_dc(ADS_STRUCT *ads);
bool ads_try_connect(ADS_STRUCT *ads, const char *server );
ADS_STATUS ads_connect(ADS_STRUCT *ads);
ADS_STATUS ads_connect_user_creds(ADS_STRUCT *ads);
void ads_disconnect(ADS_STRUCT *ads);

View File

@ -1847,6 +1847,7 @@ typedef struct _smb_iconv_t {
#ifndef LDAP_PORT
#define LDAP_PORT 389
#endif
#define LDAP_GC_PORT 3268
/* used by the IP comparison function */
struct ip_service {

View File

@ -173,7 +173,7 @@ bool ads_closest_dc(ADS_STRUCT *ads)
try a connection to a given ldap server, returning True and setting the servers IP
in the ads struct if successful
*/
bool ads_try_connect(ADS_STRUCT *ads, const char *server )
static bool ads_try_connect(ADS_STRUCT *ads, const char *server, bool gc)
{
char *srv;
struct nbt_cldap_netlogon_5 cldap_reply;
@ -238,7 +238,7 @@ bool ads_try_connect(ADS_STRUCT *ads, const char *server )
}
ads->server.workgroup = SMB_STRDUP(cldap_reply.domain);
ads->ldap.port = LDAP_PORT;
ads->ldap.port = gc ? LDAP_GC_PORT : LDAP_PORT;
if (!interpret_string_addr(&ads->ldap.ss, srv, 0)) {
DEBUG(1,("ads_try_connect: unable to convert %s "
"to an address\n",
@ -358,7 +358,7 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
}
}
if ( ads_try_connect(ads, server) ) {
if ( ads_try_connect(ads, server, false) ) {
SAFE_FREE(ip_list);
SAFE_FREE(sitename);
return NT_STATUS_OK;
@ -385,6 +385,141 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
return NT_STATUS_NO_LOGON_SERVERS;
}
/*********************************************************************
*********************************************************************/
static NTSTATUS ads_lookup_site(void)
{
ADS_STRUCT *ads = NULL;
ADS_STATUS ads_status;
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
struct nbt_cldap_netlogon_5 cldap_reply;
ZERO_STRUCT(cldap_reply);
ads = ads_init(lp_realm(), NULL, NULL);
if (!ads) {
return NT_STATUS_NO_MEMORY;
}
/* The NO_BIND here will find a DC and set the client site
but not establish the TCP connection */
ads->auth.flags = ADS_AUTH_NO_BIND;
ads_status = ads_connect(ads);
if (!ADS_ERR_OK(ads_status)) {
DEBUG(4, ("ads_lookup_site: ads_connect to our realm failed! (%s)\n",
ads_errstr(ads_status)));
}
nt_status = ads_ntstatus(ads_status);
if (ads) {
ads_destroy(&ads);
}
return nt_status;
}
/*********************************************************************
*********************************************************************/
static const char* host_dns_domain(const char *fqdn)
{
const char *p = fqdn;
/* go to next char following '.' */
if ((p = strchr_m(fqdn, '.')) != NULL) {
p++;
}
return p;
}
/**
* Connect to the Global Catalog server
* @param ads Pointer to an existing ADS_STRUCT
* @return status of connection
*
* Simple wrapper around ads_connect() that fills in the
* GC ldap server information
**/
ADS_STATUS ads_connect_gc(ADS_STRUCT *ads)
{
TALLOC_CTX *frame = talloc_stackframe();
struct dns_rr_srv *gcs_list;
int num_gcs;
char *realm = ads->server.realm;
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
int i;
bool done = false;
char *sitename = NULL;
if (!realm)
realm = lp_realm();
if ((sitename = sitename_fetch(realm)) == NULL) {
ads_lookup_site();
sitename = sitename_fetch(realm);
}
do {
/* We try once with a sitename and once without
(unless we don't have a sitename and then we're
done */
if (sitename == NULL)
done = true;
nt_status = ads_dns_query_gcs(frame, realm, sitename,
&gcs_list, &num_gcs);
SAFE_FREE(sitename);
if (!NT_STATUS_IS_OK(nt_status)) {
ads_status = ADS_ERROR_NT(nt_status);
goto done;
}
/* Loop until we get a successful connection or have gone
through them all. When connecting a GC server, make sure that
the realm is the server's DNS name and not the forest root */
for (i=0; i<num_gcs; i++) {
ads->server.gc = true;
ads->server.ldap_server = SMB_STRDUP(gcs_list[i].hostname);
ads->server.realm = SMB_STRDUP(host_dns_domain(ads->server.ldap_server));
ads_status = ads_connect(ads);
if (ADS_ERR_OK(ads_status)) {
/* Reset the bind_dn to "". A Global Catalog server
may host multiple domain trees in a forest.
Windows 2003 GC server will accept "" as the search
path to imply search all domain trees in the forest */
SAFE_FREE(ads->config.bind_path);
ads->config.bind_path = SMB_STRDUP("");
goto done;
}
SAFE_FREE(ads->server.ldap_server);
SAFE_FREE(ads->server.realm);
}
TALLOC_FREE(gcs_list);
num_gcs = 0;
} while (!done);
done:
SAFE_FREE(sitename);
talloc_destroy(frame);
return ads_status;
}
/**
* Connect to the LDAP server
@ -412,7 +547,7 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
}
if (ads->server.ldap_server &&
ads_try_connect(ads, ads->server.ldap_server)) {
ads_try_connect(ads, ads->server.ldap_server, ads->server.gc)) {
goto got_connection;
}
@ -472,7 +607,7 @@ got_connection:
/* Otherwise setup the TCP LDAP session */
ads->ldap.ld = ldap_open_with_timeout(ads->config.ldap_server_name,
LDAP_PORT, lp_ldap_timeout());
ads->ldap.port, lp_ldap_timeout());
if (ads->ldap.ld == NULL) {
status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
goto out;

View File

@ -1043,14 +1043,16 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx,
if (lp_security() == SEC_ADS) {
ADS_STRUCT *ads;
ADS_STATUS ads_status;
char addr[INET6_ADDRSTRLEN];
print_sockaddr(addr, sizeof(addr), pss);
ads = ads_init(domain->alt_name, domain->name, NULL);
ads = ads_init(domain->alt_name, domain->name, addr);
ads->auth.flags |= ADS_AUTH_NO_BIND;
if (ads_try_connect(ads, addr)) {
ads_status = ads_connect(ads);
if (ADS_ERR_OK(ads_status)) {
/* We got a cldap packet. */
fstrcpy(name, ads->config.ldap_server_name);
namecache_store(name, 0x20, 1, &ip_list);