#include "includes.h"
-#ifdef HAVE_ADS
+#ifdef HAVE_LDAP
/**
* @file ldap.c
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;
+}
+
/* used by the IP comparison function */
struct ldap_ip {
struct in_addr ip;
/* try connecting to a ldap server via DNS */
static BOOL ads_try_dns(ADS_STRUCT *ads)
{
- char *realm, *ptr;
+ const char *c_realm;
+ const char *ptr;
+ char *realm;
char *list = NULL;
pstring tok;
struct ldap_ip *ip_list;
int count, i=0;
- realm = ads->server.realm;
- if (!realm || !*realm) {
- realm = lp_realm();
+ c_realm = ads->server.realm;
+ if (!c_realm || !*c_realm) {
+ c_realm = lp_realm();
}
- if (!realm || !*realm) {
- realm = ads->server.workgroup;
+ if (!c_realm || !*c_realm) {
+ c_realm = ads->server.workgroup;
}
- if (!realm || !*realm) {
- realm = lp_workgroup();
+ if (!c_realm || !*c_realm) {
+ c_realm = lp_workgroup();
}
- if (!realm) {
+ if (!c_realm) {
return False;
}
- realm = smb_xstrdup(realm);
+ realm = smb_xstrdup(c_realm);
DEBUG(6,("ads_try_dns: looking for realm '%s'\n", realm));
if (ldap_domain2hostlist(realm, &list) != LDAP_SUCCESS) {
/* try connecting to a ldap server via netbios */
static BOOL ads_try_netbios(ADS_STRUCT *ads)
{
- struct in_addr *ip_list;
+ struct in_addr *ip_list, pdc_ip;
int count;
int i;
- char *workgroup = ads->server.workgroup;
+ const char *workgroup = ads->server.workgroup;
+ BOOL list_ordered;
if (!workgroup) {
workgroup = lp_workgroup();
DEBUG(6,("ads_try_netbios: looking for workgroup '%s'\n", workgroup));
/* try the PDC first */
- if (get_dc_list(True, workgroup, &ip_list, &count)) {
- for (i=0;i<count;i++) {
- DEBUG(6,("ads_try_netbios: trying server '%s'\n",
- inet_ntoa(ip_list[i])));
- if (ads_try_connect(ads, inet_ntoa(ip_list[i]), LDAP_PORT)) {
- free(ip_list);
- return True;
- }
- }
- free(ip_list);
+ if (get_pdc_ip(workgroup, &pdc_ip)) {
+ DEBUG(6,("ads_try_netbios: trying server '%s'\n",
+ inet_ntoa(pdc_ip)));
+ if (ads_try_connect(ads, inet_ntoa(pdc_ip), LDAP_PORT))
+ return True;
}
/* now any DC, including backups */
- if (get_dc_list(False, workgroup, &ip_list, &count)) {
+ if (get_dc_list(workgroup, &ip_list, &count, &list_ordered)) {
for (i=0;i<count;i++) {
DEBUG(6,("ads_try_netbios: trying server '%s'\n",
inet_ntoa(ip_list[i])));
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)) {
if (!ads->auth.user_name) {
/* by default use the machine account */
- extern pstring global_myname;
fstring myname;
- fstrcpy(myname, global_myname);
+ fstrcpy(myname, global_myname());
strlower(myname);
asprintf(&ads->auth.user_name, "HOST/%s", myname);
}
return ADS_SUCCESS;
}
+ if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
+ return ADS_ERROR(ldap_simple_bind_s( ads->ld, NULL, NULL));
+ }
+
+ if (ads->auth.flags & ADS_AUTH_SIMPLE_BIND) {
+ return ADS_ERROR(ldap_simple_bind_s( ads->ld, ads->auth.user_name, ads->auth.password));
+ }
+
return ads_sasl_bind(ads);
}
if (!in_val) return NULL;
value = talloc_zero(ctx, sizeof(struct berval));
+ if (value == NULL)
+ return NULL;
if (in_val->bv_len == 0) return value;
value->bv_len = in_val->bv_len;
*res = NULL;
- if (!(ctx = talloc_init()))
+ if (!(ctx = talloc_init("ads_do_paged_search")))
return ADS_ERROR(LDAP_NO_MEMORY);
/* 0 means the conversion worked but the result was empty
else {
/* This would be the utf8-encoded version...*/
/* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
- if (!(str_list_copy(&search_attrs, attrs)))
- {
+ if (!(str_list_copy(&search_attrs, attrs))) {
rc = LDAP_NO_MEMORY;
goto done;
}
char *utf8_exp, *utf8_path, **search_attrs = NULL;
TALLOC_CTX *ctx;
- if (!(ctx = talloc_init())) {
+ if (!(ctx = talloc_init("ads_do_search"))) {
DEBUG(1,("ads_do_search: talloc_init() failed!"));
return ADS_ERROR(LDAP_NO_MEMORY);
}
/* the easiest way to find a machine account anywhere in the tree
is to look for hostname$ */
- asprintf(&exp, "(samAccountName=%s$)", host);
+ if (asprintf(&exp, "(samAccountName=%s$)", host) == -1) {
+ DEBUG(1, ("asprintf failed!\n"));
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
status = ads_search(ads, res, exp, attrs);
free(exp);
return status;
non-existent attribute (but allowable for the object) to run
*/
LDAPControl PermitModify = {
- "1.2.840.113556.1.4.1413",
+ ADS_PERMIT_MODIFY_OID,
{0, NULL},
(char) 1};
LDAPControl *controls[2];
controls[0] = &PermitModify;
controls[1] = NULL;
- push_utf8_allocate((void **) &utf8_dn, mod_dn);
+ if (push_utf8_allocate(&utf8_dn, mod_dn) == -1) {
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
/* find the end of the list, marked by NULL or -1 */
for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
/* make sure the end of the list is NULL */
mods[i] = NULL;
- ret = ldap_modify_ext_s(ads->ld, utf8_dn ? utf8_dn : mod_dn,
+ ret = ldap_modify_ext_s(ads->ld, utf8_dn,
(LDAPMod **) mods, controls, NULL);
SAFE_FREE(utf8_dn);
return ADS_ERROR(ret);
int ret, i;
char *utf8_dn = NULL;
- push_utf8_allocate((void **) &utf8_dn, new_dn);
+ if (push_utf8_allocate(&utf8_dn, new_dn) == -1) {
+ DEBUG(1, ("ads_gen_add: push_utf8_allocate failed!"));
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
/* find the end of the list, marked by NULL or -1 */
for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
/* make sure the end of the list is NULL */
mods[i] = NULL;
- ret = ldap_add_s(ads->ld, utf8_dn ? utf8_dn : new_dn, mods);
+ ret = ldap_add_s(ads->ld, utf8_dn, mods);
SAFE_FREE(utf8_dn);
return ADS_ERROR(ret);
}
{
int ret;
char *utf8_dn = NULL;
- push_utf8_allocate((void **) &utf8_dn, del_dn);
- ret = ldap_delete(ads->ld, utf8_dn ? utf8_dn : del_dn);
+ if (push_utf8_allocate(&utf8_dn, del_dn) == -1) {
+ DEBUG(1, ("ads_del_dn: push_utf8_allocate failed!"));
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ ret = ldap_delete(ads->ld, utf8_dn);
return ADS_ERROR(ret);
}
ADS_MODLIST mods;
const char *objectClass[] = {"top", "person", "organizationalPerson",
"user", "computer", NULL};
+ const char *servicePrincipalName[5] = {NULL, NULL, NULL, NULL, NULL};
+ char *psp, *psp2;
+ unsigned acct_control;
- if (!(ctx = talloc_init_named("machine_account")))
+ if (!(ctx = talloc_init("machine_account")))
return ADS_ERROR(LDAP_NO_MEMORY);
ret = ADS_ERROR(LDAP_NO_MEMORY);
if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->config.realm)))
goto done;
ou_str = ads_ou_string(org_unit);
+ if (!ou_str) {
+ DEBUG(1, ("ads_ou_string returned NULL (malloc failure?)\n"));
+ goto done;
+ }
new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", hostname, ou_str,
ads->config.bind_path);
+ servicePrincipalName[0] = talloc_asprintf(ctx, "HOST/%s", hostname);
+ psp = talloc_asprintf(ctx, "HOST/%s.%s",
+ hostname,
+ ads->config.realm);
+ strlower(&psp[5]);
+ servicePrincipalName[1] = psp;
+ servicePrincipalName[2] = talloc_asprintf(ctx, "CIFS/%s", hostname);
+ psp2 = talloc_asprintf(ctx, "CIFS/%s.%s",
+ hostname,
+ ads->config.realm);
+ strlower(&psp2[5]);
+ servicePrincipalName[3] = psp2;
+
free(ou_str);
if (!new_dn)
goto done;
if (!(samAccountName = talloc_asprintf(ctx, "%s$", hostname)))
goto done;
- if (!(controlstr = talloc_asprintf(ctx, "%u",
- UF_DONT_EXPIRE_PASSWD | UF_WORKSTATION_TRUST_ACCOUNT |
- UF_TRUSTED_FOR_DELEGATION | UF_USE_DES_KEY_ONLY)))
+
+ acct_control = UF_WORKSTATION_TRUST_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
+#ifndef ENCTYPE_ARCFOUR_HMAC
+ acct_control |= UF_USE_DES_KEY_ONLY;
+#endif
+ if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control)))
goto done;
if (!(mods = ads_init_mods(ctx)))
ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
ads_mod_str(ctx, &mods, "userPrincipalName", host_upn);
- ads_mod_str(ctx, &mods, "servicePrincipalName", host_spn);
+ ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
ads_mod_str(ctx, &mods, "dNSHostName", hostname);
ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
ads_mod_str(ctx, &mods, "operatingSystem", "Samba");
}
}
+struct uuid {
+ uint32 i1;
+ uint16 i2;
+ uint16 i3;
+ uint8 s[8];
+};
+
+static void dump_guid(const char *field, struct berval **values)
+{
+ int i;
+ GUID guid;
+ for (i=0; values[i]; i++) {
+ memcpy(guid.info, values[i]->bv_val, sizeof(guid.info));
+ printf("%s: %s\n", field, uuid_string_static(guid));
+ }
+}
+
/*
dump a sid result from ldap
*/
SEC_DESC *psd = 0;
TALLOC_CTX *ctx = 0;
- if (!(ctx = talloc_init_named("sec_io_desc")))
+ if (!(ctx = talloc_init("sec_io_desc")))
return;
/* prepare data */
prs_init(&ps, values[0]->bv_len, ctx, UNMARSHALL);
- prs_append_data(&ps, values[0]->bv_val, values[0]->bv_len);
- ps.data_offset = 0;
+ prs_copy_data_in(&ps, values[0]->bv_val, values[0]->bv_len);
+ prs_set_offset(&ps,0);
/* parse secdesc */
if (!sec_io_desc("sd", &psd, &ps, 1)) {
static BOOL ads_dump_field(char *field, void **values, void *data_area)
{
- struct {
- char *name;
+ const struct {
+ const char *name;
BOOL string;
void (*handler)(const char *, struct berval **);
} handlers[] = {
- {"objectGUID", False, dump_binary},
+ {"objectGUID", False, dump_guid},
{"nTSecurityDescriptor", False, dump_sd},
{"dnsRecord", False, dump_binary},
{"objectSid", False, dump_sid},
void *msg;
TALLOC_CTX *ctx;
- if (!(ctx = talloc_init()))
+ if (!(ctx = talloc_init("ads_process_results")))
return;
for (msg = ads_first_entry(ads, res); msg;
const char *attrs[] = {"ntSecurityDescriptor", "objectSid", 0};
char *exp = 0;
size_t sd_size = 0;
- struct berval **bvals = 0;
struct berval bval = {0, NULL};
- prs_struct ps;
prs_struct ps_wire;
+ char *escaped_hostname = escape_ldap_string_alloc(hostname);
LDAPMessage *res = 0;
LDAPMessage *msg = 0;
ret = ADS_ERROR(LDAP_SUCCESS);
- asprintf(&exp, "(samAccountName=%s$)", hostname);
+ if (!escaped_hostname) {
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ if (asprintf(&exp, "(samAccountName=%s$)", escaped_hostname) == -1) {
+ DEBUG(1, ("ads_set_machine_sd: asprintf failed!\n"));
+ SAFE_FREE(escaped_hostname);
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ SAFE_FREE(escaped_hostname);
+
ret = ads_search(ads, (void *) &res, exp, attrs);
if (!ADS_ERR_OK(ret)) return ret;
- msg = ads_first_entry(ads, res);
- bvals = ldap_get_values_len(ads->ld, msg, attrs[0]);
- ads_pull_sid(ads, msg, attrs[1], &sid);
- ads_msgfree(ads, res);
-#if 0
- file_save("/tmp/sec_desc.old", bvals[0]->bv_val, bvals[0]->bv_len);
-#endif
- if (!(ctx = talloc_init_named("sec_io_desc")))
- return ADS_ERROR(LDAP_NO_MEMORY);
+ if ( !(msg = ads_first_entry(ads, res) )) {
+ ret = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ goto ads_set_sd_error;
+ }
- prs_init(&ps, bvals[0]->bv_len, ctx, UNMARSHALL);
- prs_append_data(&ps, bvals[0]->bv_val, bvals[0]->bv_len);
- ps.data_offset = 0;
- ldap_value_free_len(bvals);
+ ads_pull_sid(ads, msg, attrs[1], &sid);
+ if (!(ctx = talloc_init("sec_io_desc"))) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto ads_set_sd_error;
+ }
- if (!sec_io_desc("sd", &psd, &ps, 1))
+ if (!ads_pull_sd(ads, ctx, msg, attrs[0], &psd)) {
+ ret = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
goto ads_set_sd_error;
+ }
status = sec_desc_add_sid(ctx, &psd, &sid, SEC_RIGHTS_FULL_CTRL, &sd_size);
- if (!NT_STATUS_IS_OK(status))
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = ADS_ERROR_NT(status);
goto ads_set_sd_error;
+ }
prs_init(&ps_wire, sd_size, ctx, MARSHALL);
- if (!sec_io_desc("sd_wire", &psd, &ps_wire, 1))
+ if (!sec_io_desc("sd_wire", &psd, &ps_wire, 1)) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
goto ads_set_sd_error;
+ }
#if 0
file_save("/tmp/sec_desc.new", ps_wire.data_p, sd_size);
if (!(mods = ads_init_mods(ctx))) return ADS_ERROR(LDAP_NO_MEMORY);
bval.bv_len = sd_size;
- bval.bv_val = prs_data_p(&ps_wire);
+ bval.bv_val = talloc(ctx, sd_size);
+ if (!bval.bv_val) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto ads_set_sd_error;
+ }
+ prs_copy_all_data_out((char *)&bval.bv_val, &ps_wire);
+
ads_mod_ber(ctx, &mods, attrs[0], &bval);
ret = ads_gen_mod(ads, dn, mods);
- prs_mem_free(&ps);
- prs_mem_free(&ps_wire);
- talloc_destroy(ctx);
- return ret;
-
ads_set_sd_error:
- prs_mem_free(&ps);
+ ads_msgfree(ads, res);
prs_mem_free(&ps_wire);
talloc_destroy(ctx);
- return ADS_ERROR(LDAP_NO_MEMORY);
-}
-
-/**
- * Set the machine account password
- * @param ads connection to ads server
- * @param hostname machine whose password is being set
- * @param password new password
- * @return status of password change
- **/
-ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
- const char *hostname,
- const char *password)
-{
- ADS_STATUS status;
- char *host = strdup(hostname);
- char *principal;
-
- strlower(host);
-
- /*
- we need to use the '$' form of the name here, as otherwise the
- server might end up setting the password for a user instead
- */
- asprintf(&principal, "%s$@%s", host, ads->auth.realm);
-
- status = krb5_set_password(ads->auth.kdc_server, principal, password, ads->auth.time_offset);
-
- free(host);
- free(principal);
-
- return status;
+ return ret;
}
/**
int rc;
values = ldap_get_values(ads->ld, msg, field);
- if (!values) return NULL;
+ if (!values)
+ return NULL;
if (values[0]) {
rc = pull_utf8_talloc(mem_ctx, &ux_string,
int i, n;
values = ldap_get_values(ads->ld, msg, field);
- if (!values) return NULL;
+ if (!values)
+ return NULL;
- for (i=0;values[i];i++) /* noop */ ;
+ for (i=0;values[i];i++)
+ /* noop */ ;
n = i;
ret = talloc(mem_ctx, sizeof(char *) * (n+1));
+ if (!ret) {
+ ldap_value_free(values);
+ return NULL;
+ }
for (i=0;i<n;i++) {
if (pull_utf8_talloc(mem_ctx, &ret[i], values[i]) == -1) {
+ ldap_value_free(values);
return NULL;
}
}
char **values;
values = ldap_get_values(ads->ld, msg, field);
- if (!values) return False;
+ if (!values)
+ return False;
if (!values[0]) {
ldap_value_free(values);
return False;
return True;
}
+/**
+ * pull a single objectGUID from an ADS result
+ * @param ads connection to ADS server
+ * @param msg results of search
+ * @param guid 37-byte area to receive text guid
+ * @return boolean indicating success
+ **/
+BOOL ads_pull_guid(ADS_STRUCT *ads,
+ void *msg, GUID *guid)
+{
+ char **values;
+
+ values = ldap_get_values(ads->ld, msg, "objectGUID");
+ if (!values)
+ return False;
+
+ if (values[0]) {
+ memcpy(guid, values[0], sizeof(GUID));
+ ldap_value_free(values);
+ return True;
+ }
+ ldap_value_free(values);
+ return False;
+
+}
+
+
/**
* pull a single DOM_SID from a ADS result
* @param ads connection to ads server
values = ldap_get_values_len(ads->ld, msg, field);
- if (!values) return False;
+ if (!values)
+ return False;
- if (values[0]) {
+ if (values[0])
ret = sid_parse(values[0]->bv_val, values[0]->bv_len, sid);
- }
ldap_value_free_len(values);
return ret;
values = ldap_get_values_len(ads->ld, msg, field);
- if (!values) return 0;
+ if (!values)
+ return 0;
- for (i=0; values[i]; i++) /* nop */ ;
+ for (i=0; values[i]; i++)
+ /* nop */ ;
(*sids) = talloc(mem_ctx, sizeof(DOM_SID) * i);
+ if (!(*sids)) {
+ ldap_value_free_len(values);
+ return 0;
+ }
count = 0;
for (i=0; values[i]; i++) {
ret = sid_parse(values[i]->bv_val, values[i]->bv_len, &(*sids)[count]);
- if (ret) count++;
+ if (ret)
+ count++;
}
ldap_value_free_len(values);
return count;
}
+/**
+ * pull a SEC_DESC from a ADS result
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX for allocating sid array
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @param sd Pointer to *SEC_DESC to store result (talloc()ed)
+ * @return boolean inidicating success
+*/
+BOOL ads_pull_sd(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ void *msg, const char *field, SEC_DESC **sd)
+{
+ struct berval **values;
+ prs_struct ps;
+ BOOL ret = False;
+
+ values = ldap_get_values_len(ads->ld, msg, field);
+
+ if (!values) return False;
+
+ if (values[0]) {
+ prs_init(&ps, values[0]->bv_len, mem_ctx, UNMARSHALL);
+ prs_copy_data_in(&ps, values[0]->bv_val, values[0]->bv_len);
+ prs_set_offset(&ps,0);
+
+ ret = sec_io_desc("sd", sd, &ps, 1);
+ }
+
+ ldap_value_free_len(values);
+ return ret;
+}
+
+/*
+ * in order to support usernames longer than 21 characters we need to
+ * use both the sAMAccountName and the userPrincipalName attributes
+ * It seems that not all users have the userPrincipalName attribute set
+ *
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX for allocating sid array
+ * @param msg Results of search
+ * @return the username
+ */
+char *ads_pull_username(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, void *msg)
+{
+ char *ret, *p;
+
+ ret = ads_pull_string(ads, mem_ctx, msg, "userPrincipalName");
+ if (ret && (p = strchr(ret, '@'))) {
+ *p = 0;
+ return ret;
+ }
+ return ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
+}
+
/**
* find the update serial number - this is the core of the ldap cache
char *timestr;
TALLOC_CTX *ctx;
- if (!(ctx = talloc_init())) {
+ if (!(ctx = talloc_init("ads_server_info"))) {
return ADS_ERROR(LDAP_NO_MEMORY);
}
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);
- DEBUG(1, ("ads_server_info: returned ldap server name did not contain '$@' so was deemed invalid\n"));
return ADS_ERROR(LDAP_DECODING_ERROR);
}
ads->config.realm = strdup(p+2);
ads->config.bind_path = ads_build_dn(ads->config.realm);
- DEBUG(3,("got ldap server name %s@%s\n",
- ads->config.ldap_server_name, ads->config.realm));
+ 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));
ads->config.current_time = ads_parse_time(timestr);
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, char **workgroup)
{