diff options
author | Gerald Carter <jerry@samba.org> | 2006-05-12 15:17:35 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:16:57 -0500 |
commit | 2c029a8b96ae476f1d5c2abe14ee25f98a1513d8 (patch) | |
tree | d256cef6a5f4802549a599477c6bc8b4897d4ff0 /source3/libads | |
parent | fc5f948260477e4c43e844be1abb09056174d69e (diff) | |
download | samba-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.c | 6 | ||||
-rw-r--r-- | source3/libads/cldap.c | 278 | ||||
-rw-r--r-- | source3/libads/ldap.c | 363 |
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 |