summaryrefslogtreecommitdiff
path: root/source3/libads
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2006-05-12 15:17:35 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:16:57 -0500
commit2c029a8b96ae476f1d5c2abe14ee25f98a1513d8 (patch)
treed256cef6a5f4802549a599477c6bc8b4897d4ff0 /source3/libads
parentfc5f948260477e4c43e844be1abb09056174d69e (diff)
downloadsamba-2c029a8b96ae476f1d5c2abe14ee25f98a1513d8.tar.gz
samba-2c029a8b96ae476f1d5c2abe14ee25f98a1513d8.tar.bz2
samba-2c029a8b96ae476f1d5c2abe14ee25f98a1513d8.zip
r15543: New implementation of 'net ads join' to be more like Windows XP.
The motivating factor is to not require more privileges for the user account than Windows does when joining a domain. The points of interest are * net_ads_join() uses same rpc mechanisms as net_rpc_join() * Enable CLDAP queries for filling in the majority of the ADS_STRUCT->config information * Remove ldap_initialized() from sam/idmap_ad.c and libads/ldap.c * Remove some unnecessary fields from ADS_STRUCT * Manually set the dNSHostName and servicePrincipalName attribute using the machine account after the join Thanks to Guenther and Simo for the review. Still to do: * Fix the userAccountControl for DES only systems * Set the userPrincipalName in order to support things like 'kinit -k' (although we might be able to just use the sAMAccountName instead) * Re-add support for pre-creating the machine account in a specific OU (This used to be commit 4c4ea7b20f44cd200cef8c7b389d51b72eccc39b)
Diffstat (limited to 'source3/libads')
-rw-r--r--source3/libads/ads_struct.c6
-rw-r--r--source3/libads/cldap.c278
-rw-r--r--source3/libads/ldap.c363
3 files changed, 441 insertions, 206 deletions
diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c
index 9b2179ad31..48533c7ffb 100644
--- a/source3/libads/ads_struct.c
+++ b/source3/libads/ads_struct.c
@@ -118,12 +118,13 @@ void ads_destroy(ADS_STRUCT **ads)
is_mine = (*ads)->is_mine;
#if HAVE_LDAP
- if ((*ads)->ld) ldap_unbind((*ads)->ld);
+ if ((*ads)->ld) {
+ ldap_unbind((*ads)->ld);
+ }
#endif
SAFE_FREE((*ads)->server.realm);
SAFE_FREE((*ads)->server.workgroup);
SAFE_FREE((*ads)->server.ldap_server);
- SAFE_FREE((*ads)->server.ldap_uri);
SAFE_FREE((*ads)->auth.realm);
SAFE_FREE((*ads)->auth.password);
@@ -132,7 +133,6 @@ void ads_destroy(ADS_STRUCT **ads)
SAFE_FREE((*ads)->config.realm);
SAFE_FREE((*ads)->config.bind_path);
- SAFE_FREE((*ads)->config.schema_path);
SAFE_FREE((*ads)->config.ldap_server_name);
SAFE_FREE((*ads)->schema.sfu_uidnumber_attr);
diff --git a/source3/libads/cldap.c b/source3/libads/cldap.c
new file mode 100644
index 0000000000..6a62f573c9
--- /dev/null
+++ b/source3/libads/cldap.c
@@ -0,0 +1,278 @@
+/*
+ Samba Unix/Linux SMB client library
+ net ads cldap functions
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ These seem to be strings as described in RFC1035 4.1.4 and can be:
+
+ - a sequence of labels ending in a zero octet
+ - a pointer
+ - a sequence of labels ending with a pointer
+
+ A label is a byte where the first two bits must be zero and the remaining
+ bits represent the length of the label followed by the label itself.
+ Therefore, the length of a label is at max 64 bytes. Under RFC1035, a
+ sequence of labels cannot exceed 255 bytes.
+
+ A pointer consists of a 14 bit offset from the beginning of the data.
+
+ struct ptr {
+ unsigned ident:2; // must be 11
+ unsigned offset:14; // from the beginning of data
+ };
+
+ This is used as a method to compress the packet by eliminated duplicate
+ domain components. Since a UDP packet should probably be < 512 bytes and a
+ DNS name can be up to 255 bytes, this actually makes a lot of sense.
+*/
+static unsigned pull_netlogon_string(char *ret, const char *ptr,
+ const char *data)
+{
+ char *pret = ret;
+ int followed_ptr = 0;
+ unsigned ret_len = 0;
+
+ memset(pret, 0, MAX_DNS_LABEL);
+ do {
+ if ((*ptr & 0xc0) == 0xc0) {
+ uint16 len;
+
+ if (!followed_ptr) {
+ ret_len += 2;
+ followed_ptr = 1;
+ }
+ len = ((ptr[0] & 0x3f) << 8) | ptr[1];
+ ptr = data + len;
+ } else if (*ptr) {
+ uint8 len = (uint8)*(ptr++);
+
+ if ((pret - ret + len + 1) >= MAX_DNS_LABEL) {
+ d_fprintf(stderr, "DC returning too long DNS name\n");
+ return 0;
+ }
+
+ if (pret != ret) {
+ *pret = '.';
+ pret++;
+ }
+ memcpy(pret, ptr, len);
+ pret += len;
+ ptr += len;
+
+ if (!followed_ptr) {
+ ret_len += (len + 1);
+ }
+ }
+ } while (*ptr);
+
+ return followed_ptr ? ret_len : ret_len + 1;
+}
+
+/*
+ do a cldap netlogon query
+*/
+static int send_cldap_netlogon(int sock, const char *domain,
+ const char *hostname, unsigned ntversion)
+{
+ ASN1_DATA data;
+ char ntver[4];
+#ifdef CLDAP_USER_QUERY
+ char aac[4];
+
+ SIVAL(aac, 0, 0x00000180);
+#endif
+ SIVAL(ntver, 0, ntversion);
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+ asn1_write_Integer(&data, 4);
+ asn1_push_tag(&data, ASN1_APPLICATION(3));
+ asn1_write_OctetString(&data, NULL, 0);
+ asn1_write_enumerated(&data, 0);
+ asn1_write_enumerated(&data, 0);
+ asn1_write_Integer(&data, 0);
+ asn1_write_Integer(&data, 0);
+ asn1_write_BOOLEAN2(&data, False);
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "DnsDomain", 9);
+ asn1_write_OctetString(&data, domain, strlen(domain));
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "Host", 4);
+ asn1_write_OctetString(&data, hostname, strlen(hostname));
+ asn1_pop_tag(&data);
+
+#ifdef CLDAP_USER_QUERY
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "User", 4);
+ asn1_write_OctetString(&data, "SAMBA$", 6);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "AAC", 4);
+ asn1_write_OctetString(&data, aac, 4);
+ asn1_pop_tag(&data);
+#endif
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "NtVer", 5);
+ asn1_write_OctetString(&data, ntver, 4);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+ asn1_write_OctetString(&data, "NetLogon", 8);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ d_fprintf(stderr, "Failed to build cldap netlogon at offset %d\n", (int)data.ofs);
+ asn1_free(&data);
+ return -1;
+ }
+
+ if (write(sock, data.data, data.length) != (ssize_t)data.length) {
+ d_fprintf(stderr, "failed to send cldap query (%s)\n", strerror(errno));
+ }
+
+ asn1_free(&data);
+
+ return 0;
+}
+
+
+/*
+ receive a cldap netlogon reply
+*/
+static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
+{
+ int ret;
+ ASN1_DATA data;
+ DATA_BLOB blob;
+ DATA_BLOB os1, os2, os3;
+ int i1;
+ char *p;
+
+ blob = data_blob(NULL, 8192);
+
+ ret = read(sock, blob.data, blob.length);
+
+ if (ret <= 0) {
+ d_fprintf(stderr, "no reply received to cldap netlogon\n");
+ return -1;
+ }
+ blob.length = ret;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_read_Integer(&data, &i1);
+ asn1_start_tag(&data, ASN1_APPLICATION(4));
+ asn1_read_OctetString(&data, &os1);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_read_OctetString(&data, &os2);
+ asn1_start_tag(&data, ASN1_SET);
+ asn1_read_OctetString(&data, &os3);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ d_fprintf(stderr, "Failed to parse cldap reply\n");
+ return -1;
+ }
+
+ p = (char *)os3.data;
+
+ reply->type = IVAL(p, 0); p += 4;
+ reply->flags = IVAL(p, 0); p += 4;
+
+ memcpy(&reply->guid.info, p, UUID_FLAT_SIZE);
+ p += UUID_FLAT_SIZE;
+
+ p += pull_netlogon_string(reply->forest, p, (const char *)os3.data);
+ p += pull_netlogon_string(reply->domain, p, (const char *)os3.data);
+ p += pull_netlogon_string(reply->hostname, p, (const char *)os3.data);
+ p += pull_netlogon_string(reply->netbios_domain, p, (const char *)os3.data);
+ p += pull_netlogon_string(reply->netbios_hostname, p, (const char *)os3.data);
+ p += pull_netlogon_string(reply->unk, p, (const char *)os3.data);
+
+ if (reply->type == SAMLOGON_AD_R) {
+ p += pull_netlogon_string(reply->user_name, p, (const char *)os3.data);
+ } else {
+ *reply->user_name = 0;
+ }
+
+ p += pull_netlogon_string(reply->site_name, p, (const char *)os3.data);
+ p += pull_netlogon_string(reply->site_name_2, p, (const char *)os3.data);
+
+ reply->version = IVAL(p, 0);
+ reply->lmnt_token = SVAL(p, 4);
+ reply->lm20_token = SVAL(p, 6);
+
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
+ data_blob_free(&blob);
+
+ return 0;
+}
+
+/*******************************************************************
+ do a cldap netlogon query. Always 389/udp
+*******************************************************************/
+
+BOOL ads_cldap_netlogon(const char *server, const char *realm, struct cldap_netlogon_reply *reply)
+{
+ int sock;
+ int ret;
+
+ sock = open_udp_socket(server, LDAP_PORT );
+ if (sock == -1) {
+ DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n",
+ server));
+ return False;
+ }
+
+ ret = send_cldap_netlogon(sock, realm, global_myname(), 6);
+ if (ret != 0) {
+ return False;
+ }
+ ret = recv_cldap_netlogon(sock, reply);
+ close(sock);
+
+ if (ret == -1) {
+ return False;
+ }
+
+ return True;
+}
+
+
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index a8877b5697..6f698dc3a9 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -112,31 +112,52 @@ static int ldap_search_with_timeout(LDAP *ld,
/*
try a connection to a given ldap server, returning True and setting the servers IP
in the ads struct if successful
-
- TODO : add a negative connection cache in here leveraged off of the one
- found in the rpc code. --jerry
*/
-BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
+BOOL ads_try_connect(ADS_STRUCT *ads, const char *server )
{
char *srv;
+ struct cldap_netlogon_reply cldap_reply;
if (!server || !*server) {
return False;
}
-
- DEBUG(5,("ads_try_connect: trying ldap server '%s' port %u\n", server, port));
+
+ DEBUG(5,("ads_try_connect: sending CLDAP request to %s\n", server));
/* this copes with inet_ntoa brokenness */
+
srv = SMB_STRDUP(server);
- ads->ld = ldap_open_with_timeout(srv, port, lp_ldap_timeout());
- if (!ads->ld) {
- free(srv);
+ ZERO_STRUCT( cldap_reply );
+
+ if ( !ads_cldap_netlogon( srv, ads->server.realm, &cldap_reply ) ) {
+ DEBUG(3,("ads_try_connect: CLDAP request %s failed.\n", srv));
return False;
}
- ads->ldap_port = port;
+
+ /* Check the CLDAP reply flags */
+
+ if ( !(cldap_reply.flags & ADS_LDAP) ) {
+ DEBUG(1,("ads_try_connect: %s's CLDAP reply says it is not an LDAP server!\n",
+ srv));
+ SAFE_FREE( srv );
+ return False;
+ }
+
+ /* Fill in the ads->config values */
+
+ SAFE_FREE(ads->config.realm);
+ SAFE_FREE(ads->config.bind_path);
+ SAFE_FREE(ads->config.ldap_server_name);
+
+ ads->config.ldap_server_name = SMB_STRDUP(cldap_reply.hostname);
+ strupper_m(cldap_reply.domain);
+ ads->config.realm = SMB_STRDUP(cldap_reply.domain);
+ ads->config.bind_path = ads_build_dn(ads->config.realm);
+
+ ads->ldap_port = LDAP_PORT;
ads->ldap_ip = *interpret_addr2(srv);
- free(srv);
+ SAFE_FREE(srv);
/* cache the successful connection */
@@ -145,29 +166,6 @@ BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
return True;
}
-/*
- try a connection to a given ldap server, based on URL, returning True if successful
- */
-static BOOL ads_try_connect_uri(ADS_STRUCT *ads)
-{
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
- DEBUG(5,("ads_try_connect: trying ldap server at URI '%s'\n",
- ads->server.ldap_uri));
-
-
- if (ldap_initialize((LDAP**)&(ads->ld), ads->server.ldap_uri) == LDAP_SUCCESS) {
- return True;
- }
- DEBUG(0, ("ldap_initialize: %s\n", strerror(errno)));
-
-#else
-
- DEBUG(1, ("no URL support in LDAP libs!\n"));
-#endif
-
- return False;
-}
-
/**********************************************************************
Try to find an AD dc using our internal name resolution routines
Try the realm first and then then workgroup name if netbios is not
@@ -233,8 +231,6 @@ again:
/* if we fail this loop, then giveup since all the IP addresses returned were dead */
for ( i=0; i<count; i++ ) {
- /* since this is an ads conection request, default to LDAP_PORT is not set */
- int port = (ip_list[i].port!=PORT_NONE) ? ip_list[i].port : LDAP_PORT;
fstring server;
fstrcpy( server, inet_ntoa(ip_list[i].ip) );
@@ -242,7 +238,7 @@ again:
if ( !NT_STATUS_IS_OK(check_negative_conn_cache(realm, server)) )
continue;
- if ( ads_try_connect(ads, server, port) ) {
+ if ( ads_try_connect(ads, server) ) {
SAFE_FREE(ip_list);
return True;
}
@@ -270,16 +266,10 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
ads->last_attempt = time(NULL);
ads->ld = NULL;
- /* try with a URL based server */
-
- if (ads->server.ldap_uri &&
- ads_try_connect_uri(ads)) {
- goto got_connection;
- }
-
/* try with a user specified server */
+
if (ads->server.ldap_server &&
- ads_try_connect(ads, ads->server.ldap_server, LDAP_PORT)) {
+ ads_try_connect(ads, ads->server.ldap_server)) {
goto got_connection;
}
@@ -292,22 +282,12 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
got_connection:
DEBUG(3,("Connected to LDAP server %s\n", inet_ntoa(ads->ldap_ip)));
- status = ads_server_info(ads);
- if (!ADS_ERR_OK(status)) {
- DEBUG(1,("Failed to get ldap server info\n"));
- return status;
- }
-
- ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
-
- status = ADS_ERROR(smb_ldap_start_tls(ads->ld, version));
- if (!ADS_ERR_OK(status)) {
- return status;
- }
-
if (!ads->auth.user_name) {
/* have to use the userPrincipalName value here and
- not servicePrincipalName; found by Guenther Deschner @ Sernet */
+ not servicePrincipalName; found by Guenther Deschner @ Sernet.
+
+ Is this still correct? The comment does not match
+ the code. --jerry */
asprintf(&ads->auth.user_name, "host/%s", global_myname() );
}
@@ -331,10 +311,35 @@ got_connection:
}
#endif
+ /* If the caller() requested no LDAP bind, then we are done */
+
if (ads->auth.flags & ADS_AUTH_NO_BIND) {
return ADS_SUCCESS;
}
+
+ /* Otherwise setup the TCP LDAP session */
+
+ if ( (ads->ld = ldap_open_with_timeout(ads->config.ldap_server_name,
+ LDAP_PORT, lp_ldap_timeout())) == NULL )
+ {
+ return ADS_ERROR(LDAP_OPERATIONS_ERROR);
+ }
+ ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+ status = ADS_ERROR(smb_ldap_start_tls(ads->ld, version));
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ /* fill in the current time and offsets */
+
+ status = ads_current_time( ads );
+ if ( !ADS_ERR_OK(status) ) {
+ return status;
+ }
+ /* Now do the bind */
+
if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
return ADS_ERROR(ldap_simple_bind_s( ads->ld, NULL, NULL));
}
@@ -2464,7 +2469,7 @@ static time_t ads_parse_time(const char *str)
}
-const char *ads_get_attrname_by_oid(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char * OID)
+const char *ads_get_attrname_by_oid(ADS_STRUCT *ads, const char *schema_path, TALLOC_CTX *mem_ctx, const char * OID)
{
ADS_STATUS rc;
int count = 0;
@@ -2482,8 +2487,8 @@ const char *ads_get_attrname_by_oid(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const
goto failed;
}
- rc = ads_do_search_retry(ads, ads->config.schema_path,
- LDAP_SCOPE_SUBTREE, expr, attrs, &res);
+ rc = ads_do_search_retry(ads, schema_path, LDAP_SCOPE_SUBTREE,
+ expr, attrs, &res);
if (!ADS_ERR_OK(rc)) {
goto failed;
}
@@ -2513,97 +2518,94 @@ failed:
* @param ads connection to ads server
* @return status of search
**/
-ADS_STATUS ads_server_info(ADS_STRUCT *ads)
+ADS_STATUS ads_current_time(ADS_STRUCT *ads)
{
- const char *attrs[] = {"ldapServiceName",
- "currentTime",
- "schemaNamingContext", NULL};
+ const char *attrs[] = {"currentTime", NULL};
ADS_STATUS status;
void *res;
- char *value;
- char *p;
char *timestr;
- char *schema_path;
TALLOC_CTX *ctx;
+ ADS_STRUCT *ads_s = ads;
if (!(ctx = talloc_init("ads_server_info"))) {
return ADS_ERROR(LDAP_NO_MEMORY);
}
- status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
- if (!ADS_ERR_OK(status)) {
- talloc_destroy(ctx);
- return status;
- }
+ /* establish a new ldap tcp session if necessary */
- value = ads_pull_string(ads, ctx, res, "ldapServiceName");
- if (!value) {
- ads_msgfree(ads, res);
- talloc_destroy(ctx);
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ if ( !ads->ld ) {
+ if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup,
+ ads->server.ldap_server )) == NULL )
+ {
+ goto done;
+ }
+ ads_s->auth.flags = ADS_AUTH_ANON_BIND;
+ status = ads_connect( ads_s );
+ if ( !ADS_ERR_OK(status))
+ goto done;
}
- timestr = ads_pull_string(ads, ctx, res, "currentTime");
- if (!timestr) {
- ads_msgfree(ads, res);
+ status = ads_do_search(ads_s, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) {
talloc_destroy(ctx);
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ goto done;
}
- schema_path = ads_pull_string(ads, ctx, res, "schemaNamingContext");
- if (!schema_path) {
+ timestr = ads_pull_string(ads_s, ctx, res, "currentTime");
+ if (!timestr) {
ads_msgfree(ads, res);
talloc_destroy(ctx);
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ status = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ goto done;
}
- SAFE_FREE(ads->config.schema_path);
- ads->config.schema_path = SMB_STRDUP(schema_path);
-
- ads_msgfree(ads, res);
+ /* but save the time and offset in the original ADS_STRUCT */
+
+ ads->config.current_time = ads_parse_time(timestr);
- p = strchr(value, ':');
- if (!p) {
- talloc_destroy(ctx);
- DEBUG(1, ("ads_server_info: returned ldap server name did not contain a ':' "
- "so was deemed invalid\n"));
- return ADS_ERROR(LDAP_DECODING_ERROR);
+ if (ads->config.current_time != 0) {
+ ads->auth.time_offset = ads->config.current_time - time(NULL);
+ DEBUG(4,("time offset is %d seconds\n", ads->auth.time_offset));
}
- SAFE_FREE(ads->config.ldap_server_name);
+ status = ADS_SUCCESS;
- ads->config.ldap_server_name = SMB_STRDUP(p+1);
- p = strchr(ads->config.ldap_server_name, '$');
- if (!p || p[1] != '@') {
- talloc_destroy(ctx);
- DEBUG(1, ("ads_server_info: returned ldap server name (%s) does not contain '$@'"
- " so was deemed invalid\n", ads->config.ldap_server_name));
- SAFE_FREE(ads->config.ldap_server_name);
- return ADS_ERROR(LDAP_DECODING_ERROR);
+done:
+ /* free any temporary ads connections */
+ if ( ads_s != ads ) {
+ ads_destroy( &ads_s );
}
+ talloc_destroy(ctx);
- *p = 0;
+ return status;
+}
- SAFE_FREE(ads->config.realm);
- SAFE_FREE(ads->config.bind_path);
+/*********************************************************************
+*********************************************************************/
- ads->config.realm = SMB_STRDUP(p+2);
- ads->config.bind_path = ads_build_dn(ads->config.realm);
+static ADS_STATUS ads_schema_path(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **schema_path)
+{
+ ADS_STATUS status;
+ void *res;
+ const char *schema;
+ const char *attrs[] = { "schemaNamingContext", NULL };
- DEBUG(3,("got ldap server name %s@%s, using bind path: %s\n",
- ads->config.ldap_server_name, ads->config.realm,
- ads->config.bind_path));
+ status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
- ads->config.current_time = ads_parse_time(timestr);
+ if ( (schema = ads_pull_string(ads, mem_ctx, res, "schemaNamingContext")) == NULL ) {
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
- if (ads->config.current_time != 0) {
- ads->auth.time_offset = ads->config.current_time - time(NULL);
- DEBUG(4,("time offset is %d seconds\n", ads->auth.time_offset));
+ if ( (*schema_path = talloc_strdup(mem_ctx, schema)) == NULL ) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
}
- talloc_destroy(ctx);
+ ads_msgfree(ads, res);
- return ADS_SUCCESS;
+ return status;
}
/**
@@ -2617,41 +2619,71 @@ BOOL ads_check_sfu_mapping(ADS_STRUCT *ads)
BOOL ret = False;
TALLOC_CTX *ctx = NULL;
const char *gidnumber, *uidnumber, *homedir, *shell, *gecos;
+ char *schema_path;
+ ADS_STRUCT *ads_s = ads;
+ ADS_STATUS status;
+
+ if ( (ctx = talloc_init("ads_check_sfu_mapping")) == NULL ) {
+ goto done;
+ }
+
+ /* establish a new ldap tcp session if necessary */
- ctx = talloc_init("ads_check_sfu_mapping");
- if (ctx == NULL)
+ if ( !ads->ld ) {
+ if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup,
+ ads->server.ldap_server )) == NULL )
+ {
+ goto done;
+ }
+
+ ads_s->auth.flags = ADS_AUTH_ANON_BIND;
+ status = ads_connect( ads_s );
+ if ( !ADS_ERR_OK(status))
+ goto done;
+ }
+
+ status = ads_schema_path( ads, ctx, &schema_path );
+ if ( !ADS_ERR_OK(status) ) {
+ DEBUG(3,("ads_check_sfu_mapping: Unable to retrieve schema DN!\n"));
goto done;
+ }
- gidnumber = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_GIDNUMBER_OID);
+ gidnumber = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_GIDNUMBER_OID);
if (gidnumber == NULL)
goto done;
ads->schema.sfu_gidnumber_attr = SMB_STRDUP(gidnumber);
- uidnumber = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_UIDNUMBER_OID);
+ uidnumber = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_UIDNUMBER_OID);
if (uidnumber == NULL)
goto done;
ads->schema.sfu_uidnumber_attr = SMB_STRDUP(uidnumber);
- homedir = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_HOMEDIR_OID);
+ homedir = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_HOMEDIR_OID);
if (homedir == NULL)
goto done;
ads->schema.sfu_homedir_attr = SMB_STRDUP(homedir);
- shell = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_SHELL_OID);
+ shell = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_SHELL_OID);
if (shell == NULL)
goto done;
ads->schema.sfu_shell_attr = SMB_STRDUP(shell);
- gecos = ads_get_attrname_by_oid(ads, ctx, ADS_ATTR_SFU_GECOS_OID);
+ gecos = ads_get_attrname_by_oid(ads_s, schema_path, ctx, ADS_ATTR_SFU_GECOS_OID);
if (gecos == NULL)
goto done;
ads->schema.sfu_gecos_attr = SMB_STRDUP(gecos);
ret = True;
done:
- if (ctx)
+ /* free any temporary ads connections */
+ if ( ads_s != ads ) {
+ ads_destroy( &ads_s );
+ }
+
+ if (ctx) {
talloc_destroy(ctx);
-
+ }
+
return ret;
}
@@ -2679,81 +2711,6 @@ ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
return ADS_SUCCESS;
}
-/* this is rather complex - we need to find the allternate (netbios) name
- for the domain, but there isn't a simple query to do this. Instead
- we look for the principle names on the DCs account and find one that has
- the right form, then extract the netbios name of the domain from that
-
- NOTE! better method is this:
-
-bin/net -Uadministrator%XXXXX ads search '(&(objectclass=crossref)(dnsroot=VNET3.HOME.SAMBA.ORG))' nETBIOSName
-
-but you need to force the bind path to match the configurationNamingContext from the rootDSE
-
-*/
-ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **workgroup)
-{
- char *expr;
- ADS_STATUS rc;
- char **principles;
- char *prefix;
- int prefix_length;
- int i;
- void *res;
- const char *attrs[] = {"servicePrincipalName", NULL};
- size_t num_principals;
-
- (*workgroup) = NULL;
-
- asprintf(&expr, "(&(objectclass=computer)(dnshostname=%s.%s))",
- ads->config.ldap_server_name, ads->config.realm);
- if (expr == NULL) {
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
- rc = ads_search(ads, &res, expr, attrs);
- free(expr);
-
- if (!ADS_ERR_OK(rc)) {
- return rc;
- }
-
- principles = ads_pull_strings(ads, mem_ctx, res,
- "servicePrincipalName", &num_principals);
-
- ads_msgfree(ads, res);
-
- if (!principles) {
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
- }
-
- asprintf(&prefix, "HOST/%s.%s/",
- ads->config.ldap_server_name,
- ads->config.realm);
-
- prefix_length = strlen(prefix);
-
- for (i=0;principles[i]; i++) {
- if (strnequal(principles[i], prefix, prefix_length) &&
- !strequal(ads->config.realm, principles[i]+prefix_length) &&
- !strchr(principles[i]+prefix_length, '.')) {
- /* found an alternate (short) name for the domain. */
- DEBUG(3,("Found alternate name '%s' for realm '%s'\n",
- principles[i]+prefix_length,
- ads->config.realm));
- (*workgroup) = talloc_strdup(mem_ctx, principles[i]+prefix_length);
- break;
- }
- }
- free(prefix);
-
- if (!*workgroup) {
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
- }
-
- return ADS_SUCCESS;
-}
-
/**
* find our site name
* @param ads connection to ads server