summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/auth/auth_domain.c6
-rw-r--r--source3/include/ads.h41
-rw-r--r--source3/libads/ads_struct.c119
-rw-r--r--source3/libads/kerberos.c12
-rw-r--r--source3/libads/kerberos_verify.c2
-rw-r--r--source3/libads/ldap.c355
-rw-r--r--source3/libads/ldap_user.c6
-rw-r--r--source3/libads/sasl.c9
-rw-r--r--source3/libads/util.c2
-rw-r--r--source3/libsmb/namequery.c2
-rw-r--r--source3/nsswitch/winbindd.h8
-rw-r--r--source3/nsswitch/winbindd_ads.c119
-rw-r--r--source3/nsswitch/winbindd_cache.c15
-rw-r--r--source3/nsswitch/winbindd_cm.c22
-rw-r--r--source3/nsswitch/winbindd_rpc.c15
-rw-r--r--source3/nsswitch/winbindd_util.c118
-rw-r--r--source3/rpc_client/cli_lsarpc.c5
-rw-r--r--source3/rpcclient/cmd_lsarpc.c18
-rw-r--r--source3/smbd/negprot.c5
-rw-r--r--source3/smbd/server.c4
-rw-r--r--source3/smbd/sesssetup.c14
-rw-r--r--source3/utils/net_ads.c88
-rw-r--r--source3/utils/net_lookup.c2
-rw-r--r--source3/utils/net_rpc.c4
24 files changed, 629 insertions, 362 deletions
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c
index b37ce2cc91..d48cec5b29 100644
--- a/source3/auth/auth_domain.c
+++ b/source3/auth/auth_domain.c
@@ -46,7 +46,9 @@ static NTSTATUS ads_resolve_dc(fstring remote_machine,
return NT_STATUS_NO_LOGON_SERVERS;
}
- DEBUG(4,("ads_resolve_dc: realm=%s\n", ads->realm));
+ DEBUG(4,("ads_resolve_dc: realm=%s\n", ads->config.realm));
+
+ ads->auth.no_bind = 1;
#ifdef HAVE_ADS
/* a full ads_connect() is actually overkill, as we don't srictly need
@@ -55,7 +57,7 @@ static NTSTATUS ads_resolve_dc(fstring remote_machine,
ads_connect(ads);
#endif
- fstrcpy(remote_machine, ads->ldap_server_name);
+ fstrcpy(remote_machine, ads->config.ldap_server_name);
strupper(remote_machine);
*dest_ip = ads->ldap_ip;
ads_destroy(&ads);
diff --git a/source3/include/ads.h b/source3/include/ads.h
index 78d2fcf4b5..9305b71671 100644
--- a/source3/include/ads.h
+++ b/source3/include/ads.h
@@ -5,19 +5,34 @@
*/
typedef struct {
- void *ld;
- char *realm;
- char *workgroup;
- char *ldap_server;
- char *ldap_server_name;
- char *kdc_server;
+ void *ld; /* the active ldap structure */
+ struct in_addr ldap_ip; /* the ip of the active connection, if any */
+ time_t last_attempt; /* last attempt to reconnect */
int ldap_port;
- char *bind_path;
- time_t last_attempt;
- char *password;
- char *user_name;
- char *server_realm;
- struct in_addr ldap_ip;
+
+ /* info needed to find the server */
+ struct {
+ char *realm;
+ char *workgroup;
+ char *ldap_server;
+ int foreign; /* set to 1 if connecting to a foreign realm */
+ } server;
+
+ /* info needed to authenticate */
+ struct {
+ char *realm;
+ char *password;
+ char *user_name;
+ char *kdc_server;
+ int no_bind;
+ } auth;
+
+ /* info derived from the servers config */
+ struct {
+ char *realm;
+ char *bind_path;
+ char *ldap_server_name;
+ } config;
} ADS_STRUCT;
typedef struct {
@@ -95,7 +110,7 @@ typedef void **ADS_MODLIST;
/* macros to simplify error returning */
#define ADS_ERROR(rc) ads_build_error(ADS_ERROR_LDAP, rc, 0)
-#define ADS_ERROR_SYSTEM(rc) ads_build_error(ADS_ERROR_SYSTEM, rc, 0)
+#define ADS_ERROR_SYSTEM(rc) ads_build_error(ADS_ERROR_SYSTEM, rc?rc:EINVAL, 0)
#define ADS_ERROR_KRB5(rc) ads_build_error(ADS_ERROR_KRB5, rc, 0)
#define ADS_ERROR_GSS(rc, minor) ads_build_error(ADS_ERROR_GSS, rc, minor)
diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c
index af0b5d4143..b68c822ce3 100644
--- a/source3/libads/ads_struct.c
+++ b/source3/libads/ads_struct.c
@@ -72,47 +72,6 @@ char *ads_build_dn(const char *realm)
}
-#ifdef HAVE_LDAP
-/*
- find the ldap server from DNS
-*/
-static char *find_ldap_server(ADS_STRUCT *ads)
-{
- char *list = NULL;
- struct in_addr ip;
-
- if (ads->realm &&
- strcasecmp(ads->workgroup, lp_workgroup()) == 0 &&
- ldap_domain2hostlist(ads->realm, &list) == LDAP_SUCCESS) {
- char *p;
- p = strchr(list, ':');
- if (p) *p = 0;
- return list;
- }
-
- /* get desperate, find the domain controller IP */
- if (resolve_name(ads->workgroup, &ip, 0x1B)) {
- return strdup(inet_ntoa(ip));
- }
-
- /* or a BDC ... */
- if (resolve_name(ads->workgroup, &ip, 0x1C)) {
- return strdup(inet_ntoa(ip));
- }
-
- return NULL;
-}
-
-#else
-
-static char *find_ldap_server(ADS_STRUCT *ads)
-{
- /* Without LDAP this doesn't make much sense */
- return NULL;
-}
-
-#endif
-
#ifndef LDAP_PORT
#define LDAP_PORT 389
#endif
@@ -122,58 +81,24 @@ static char *find_ldap_server(ADS_STRUCT *ads)
*/
ADS_STRUCT *ads_init(const char *realm,
const char *workgroup,
- const char *ldap_server,
- const char *bind_path,
- const char *password)
+ const char *ldap_server)
{
ADS_STRUCT *ads;
ads = (ADS_STRUCT *)smb_xmalloc(sizeof(*ads));
ZERO_STRUCTP(ads);
- if (!workgroup) {
- workgroup = lp_workgroup();
+ ads->server.realm = realm? strdup(realm) : NULL;
+ ads->server.workgroup = workgroup ? strdup(workgroup) : NULL;
+ ads->server.ldap_server = ldap_server? strdup(ldap_server) : NULL;
+
+ /* we need to know if this is a foreign realm to know if we can
+ use lp_ads_server() */
+ if (realm && strcasecmp(lp_realm(), realm) != 0) {
+ ads->server.foreign = 1;
}
-
- ads->realm = realm? strdup(realm) : NULL;
- ads->workgroup = strdup(workgroup);
- ads->ldap_server = ldap_server? strdup(ldap_server) : NULL;
- ads->bind_path = bind_path? strdup(bind_path) : NULL;
- ads->ldap_port = LDAP_PORT;
- if (password) ads->password = strdup(password);
-
- if (!ads->realm) {
- ads->realm = strdup(lp_realm());
- if (!ads->realm[0]) {
- SAFE_FREE(ads->realm);
- }
- }
-
- if (!ads->realm && strchr_m(ads->workgroup, '.')) {
- /* the smb.conf has specified the realm in 'workgroup =' */
- ads->realm = strdup(ads->workgroup);
- }
-
- if (!ads->bind_path && ads->realm) {
- ads->bind_path = ads_build_dn(ads->realm);
- }
- if (!ads->ldap_server) {
- if (strcasecmp(ads->workgroup, lp_workgroup()) == 0) {
- ads->ldap_server = strdup(lp_ads_server());
- }
- if (!ads->ldap_server || !ads->ldap_server[0]) {
- SAFE_FREE(ads->ldap_server);
- ads->ldap_server = find_ldap_server(ads);
- }
- }
- if (!ads->kdc_server) {
- /* assume its the same as LDAP */
- ads->kdc_server = ads->ldap_server? strdup(ads->ldap_server) : NULL;
- }
-
- if (ads->ldap_server) {
- /* its very useful knowing the IP of the ldap server */
- ads->ldap_ip = *interpret_addr2(ads->ldap_server);
+ if (workgroup && strcasecmp(lp_workgroup(), workgroup) != 0) {
+ ads->server.foreign = 1;
}
return ads;
@@ -182,7 +107,7 @@ ADS_STRUCT *ads_init(const char *realm,
/* a simpler ads_init() interface using all defaults */
ADS_STRUCT *ads_init_simple(void)
{
- return ads_init(NULL, NULL, NULL, NULL, NULL);
+ return ads_init(NULL, NULL, NULL);
}
/*
@@ -194,13 +119,19 @@ void ads_destroy(ADS_STRUCT **ads)
#if HAVE_LDAP
if ((*ads)->ld) ldap_unbind((*ads)->ld);
#endif
- SAFE_FREE((*ads)->realm);
- SAFE_FREE((*ads)->ldap_server);
- SAFE_FREE((*ads)->ldap_server_name);
- SAFE_FREE((*ads)->kdc_server);
- SAFE_FREE((*ads)->bind_path);
- SAFE_FREE((*ads)->password);
- SAFE_FREE((*ads)->user_name);
+ SAFE_FREE((*ads)->server.realm);
+ SAFE_FREE((*ads)->server.workgroup);
+ SAFE_FREE((*ads)->server.ldap_server);
+
+ SAFE_FREE((*ads)->auth.realm);
+ SAFE_FREE((*ads)->auth.password);
+ SAFE_FREE((*ads)->auth.user_name);
+ SAFE_FREE((*ads)->auth.kdc_server);
+
+ SAFE_FREE((*ads)->config.realm);
+ SAFE_FREE((*ads)->config.bind_path);
+ SAFE_FREE((*ads)->config.ldap_server_name);
+
ZERO_STRUCTP(*ads);
SAFE_FREE(*ads);
}
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 1ba5d978e8..9a486237c9 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -110,16 +110,8 @@ int ads_kinit_password(ADS_STRUCT *ads)
char *s;
int ret;
- if (!ads->user_name) {
- /* by default use the machine account */
- extern pstring global_myname;
- fstring myname;
- fstrcpy(myname, global_myname);
- strlower(myname);
- asprintf(&ads->user_name, "HOST/%s", global_myname);
- }
- asprintf(&s, "%s@%s", ads->user_name, ads->realm);
- ret = kerberos_kinit_password(s, ads->password);
+ asprintf(&s, "%s@%s", ads->auth.user_name, ads->auth.realm);
+ ret = kerberos_kinit_password(s, ads->auth.password);
if (ret) {
DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c
index dac90908c4..22b58f47dd 100644
--- a/source3/libads/kerberos_verify.c
+++ b/source3/libads/kerberos_verify.c
@@ -67,7 +67,7 @@ NTSTATUS ads_verify_ticket(ADS_STRUCT *ads, const DATA_BLOB *ticket,
return NT_STATUS_LOGON_FAILURE;
}
- ret = krb5_set_default_realm(context, ads->realm);
+ ret = krb5_set_default_realm(context, ads->auth.realm);
if (ret) {
DEBUG(1,("krb5_set_default_realm failed (%s)\n", error_message(ret)));
ads_destroy(&ads);
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 1753d7d3ad..a8126faffe 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -37,6 +37,153 @@
* codepoints in UTF-8). This may have to change at some point
**/
+
+/*
+ try a connection to a given ldap server, returning True and setting the servers IP
+ in the ads struct if successful
+ */
+static BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
+{
+ char *srv;
+
+ if (!server || !*server) {
+ return False;
+ }
+
+ DEBUG(5,("ads_try_connect: trying ldap server '%s' port %u\n", server, port));
+
+ /* this copes with inet_ntoa brokenness */
+ srv = strdup(server);
+
+ ads->ld = ldap_open(srv, port);
+ if (!ads->ld) {
+ free(srv);
+ return False;
+ }
+ ads->ldap_port = port;
+ ads->ldap_ip = *interpret_addr2(srv);
+ free(srv);
+ return True;
+}
+
+/* used by the IP comparison function */
+struct ldap_ip {
+ struct in_addr ip;
+ unsigned port;
+};
+
+/* compare 2 ldap IPs by nearness to our interfaces - used in qsort */
+static int ldap_ip_compare(struct ldap_ip *ip1, struct ldap_ip *ip2)
+{
+ return ip_compare(&ip1->ip, &ip2->ip);
+}
+
+/* try connecting to a ldap server via DNS */
+static BOOL ads_try_dns(ADS_STRUCT *ads)
+{
+ char *realm, *ptr;
+ char *list = NULL;
+ pstring tok;
+ struct ldap_ip *ip_list;
+ int count, i=0;
+
+ realm = ads->server.realm;
+ if (!realm || !*realm) {
+ SAFE_FREE(realm);
+ realm = lp_realm();
+ }
+ if (!realm || !*realm) {
+ SAFE_FREE(realm);
+ realm = ads->server.workgroup;
+ }
+ if (!realm || !*realm) {
+ SAFE_FREE(realm);
+ realm = lp_workgroup();
+ }
+ if (!realm) {
+ return False;
+ }
+
+ DEBUG(6,("ads_try_dns: looking for realm '%s'\n", realm));
+ if (ldap_domain2hostlist(realm, &list) != LDAP_SUCCESS) {
+ return False;
+ }
+
+ DEBUG(6,("ads_try_dns: ldap realm '%s' host list '%s'\n", realm, list));
+
+ count = count_chars(list, ' ') + 1;
+ ip_list = malloc(count * sizeof(struct ldap_ip));
+ if (!ip_list) {
+ return False;
+ }
+
+ ptr = list;
+ while (next_token(&ptr, tok, " ", sizeof(tok))) {
+ unsigned port = LDAP_PORT;
+ char *p = strchr(tok, ':');
+ if (p) {
+ *p = 0;
+ port = atoi(p+1);
+ }
+ ip_list[i].ip = *interpret_addr2(tok);
+ ip_list[i].port = port;
+ if (!is_zero_ip(ip_list[i].ip)) {
+ i++;
+ }
+ }
+ free(list);
+
+ count = i;
+
+ /* we sort the list of addresses by closeness to our interfaces. This
+ tries to prevent us using a DC on the other side of the country */
+ if (count > 1) {
+ qsort(ip_list, count, sizeof(struct ldap_ip),
+ QSORT_CAST ldap_ip_compare);
+ }
+
+ for (i=0;i<count;i++) {
+ if (ads_try_connect(ads, inet_ntoa(ip_list[i].ip), ip_list[i].port)) {
+ free(ip_list);
+ return True;
+ }
+ }
+
+ SAFE_FREE(ip_list);
+ return False;
+}
+
+/* try connecting to a ldap server via netbios */
+static BOOL ads_try_netbios(ADS_STRUCT *ads)
+{
+ struct in_addr *ip_list;
+ int count;
+ int i;
+ char *workgroup = ads->server.workgroup;
+
+ if (!workgroup) {
+ workgroup = lp_workgroup();
+ }
+
+ DEBUG(6,("ads_try_netbios: looking for workgroup '%s'\n", workgroup));
+
+ if (!get_dc_list(True, workgroup, &ip_list, &count) &&
+ !get_dc_list(False, workgroup, &ip_list, &count)) {
+ return False;
+ }
+
+ 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);
+ return False;
+}
+
/**
* Connect to the LDAP server
* @param ads Pointer to an existing ADS_STRUCT
@@ -49,38 +196,35 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
ADS_STATUS status;
ads->last_attempt = time(NULL);
-
ads->ld = NULL;
- if (ads->ldap_server) {
- ads->ld = ldap_open(ads->ldap_server, ads->ldap_port);
+ /* try with a user specified server */
+ if (ads->server.ldap_server &&
+ ads_try_connect(ads, ads->server.ldap_server, LDAP_PORT)) {
+ goto got_connection;
}
- /* if that failed then try each of the BDC's in turn */
- if (!ads->ld) {
- struct in_addr *ip_list;
- int count;
-
- if (get_dc_list(False, ads->workgroup, &ip_list, &count)) {
- int i;
- for (i=0;i<count;i++) {
- ads->ld = ldap_open(inet_ntoa(ip_list[i]),
- ads->ldap_port);
- if (ads->ld) break;
- }
- if (ads->ld) {
- SAFE_FREE(ads->ldap_server);
- ads->ldap_server = strdup(inet_ntoa(ip_list[i]));
- }
- free(ip_list);
- }
+ /* try with a smb.conf ads server setting if we are connecting
+ to the primary workgroup or realm */
+ if (!ads->server.foreign &&
+ ads_try_connect(ads, lp_ads_server(), LDAP_PORT)) {
+ goto got_connection;
}
- if (!ads->ld) {
- return ADS_ERROR_SYSTEM(errno);
+ /* try via DNS */
+ if (ads_try_dns(ads)) {
+ goto got_connection;
+ }
+
+ /* try via netbios lookups */
+ if (!lp_disable_netbios() && ads_try_netbios(ads)) {
+ goto got_connection;
}
- DEBUG(3,("Connected to LDAP server %s\n", ads->ldap_server));
+ return ADS_ERROR_SYSTEM(errno?errno:ENOENT);
+
+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)) {
@@ -90,22 +234,43 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+ if (!ads->auth.user_name) {
+ /* by default use the machine account */
+ extern pstring global_myname;
+ fstring myname;
+ fstrcpy(myname, global_myname);
+ strlower(myname);
+ asprintf(&ads->auth.user_name, "HOST/%s", myname);
+ }
+
+ if (!ads->auth.realm) {
+ ads->auth.realm = strdup(ads->config.realm);
+ }
+
+ if (!ads->auth.kdc_server) {
+ ads->auth.kdc_server = strdup(inet_ntoa(ads->ldap_ip));
+ }
+
#if KRB5_DNS_HACK
/* this is a really nasty hack to avoid ADS DNS problems. It needs a patch
to MIT kerberos to work (tridge) */
{
char *env;
- asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->server_realm);
- setenv(env, inet_ntoa(*interpret_addr2(ads->ldap_server)), 1);
+ asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->config.realm);
+ setenv(env, ads->auth.kdc_server, 1);
free(env);
}
#endif
- if (ads->password) {
+ if (ads->auth.password) {
if ((code = ads_kinit_password(ads)))
return ADS_ERROR_KRB5(code);
}
+ if (ads->auth.no_bind) {
+ return ADS_SUCCESS;
+ }
+
return ads_sasl_bind(ads);
}
@@ -494,7 +659,7 @@ ADS_STATUS ads_search(ADS_STRUCT *ads, void **res,
const char *exp,
const char **attrs)
{
- return ads_do_search(ads, ads->bind_path, LDAP_SCOPE_SUBTREE,
+ return ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
exp, attrs, res);
}
@@ -805,11 +970,11 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", hostname)))
goto done;
- if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->realm)))
+ if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->config.realm)))
goto done;
ou_str = ads_ou_string(org_unit);
new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", hostname, ou_str,
- ads->bind_path);
+ ads->config.bind_path);
free(ou_str);
if (!new_dn)
goto done;
@@ -925,6 +1090,7 @@ static BOOL ads_dump_field(char *field, void **values, void *data_area)
} handlers[] = {
{"objectGUID", False, dump_binary},
{"nTSecurityDescriptor", False, dump_sd},
+ {"dnsRecord", False, dump_binary},
{"objectSid", False, dump_sid},
{NULL, True, NULL}
};
@@ -1061,7 +1227,7 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org
status = ads_leave_realm(ads, host);
if (!ADS_ERR_OK(status)) {
DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n",
- host, ads->realm));
+ host, ads->config.realm));
return status;
}
}
@@ -1224,20 +1390,15 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
char *host = strdup(hostname);
char *principal;
- if (!ads->kdc_server) {
- DEBUG(0, ("Unable to find KDC server\n"));
- return ADS_ERROR(LDAP_SERVER_DOWN);
- }
-
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->realm);
+ asprintf(&principal, "%s$@%s", host, ads->auth.realm);
- status = krb5_set_password(ads->kdc_server, principal, password);
+ status = krb5_set_password(ads->auth.kdc_server, principal, password);
free(host);
free(principal);
@@ -1472,33 +1633,27 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
return ADS_ERROR(LDAP_DECODING_ERROR);
}
- SAFE_FREE(ads->ldap_server_name);
+ SAFE_FREE(ads->config.ldap_server_name);
- ads->ldap_server_name = strdup(p+1);
- p = strchr(ads->ldap_server_name, '$');
+ ads->config.ldap_server_name = strdup(p+1);
+ p = strchr(ads->config.ldap_server_name, '$');
if (!p || p[1] != '@') {
ldap_value_free(values);
ldap_msgfree(res);
- SAFE_FREE(ads->ldap_server_name);
+ SAFE_FREE(ads->config.ldap_server_name);
return ADS_ERROR(LDAP_DECODING_ERROR);
}
*p = 0;
- SAFE_FREE(ads->server_realm);
- SAFE_FREE(ads->bind_path);
+ SAFE_FREE(ads->config.realm);
+ SAFE_FREE(ads->config.bind_path);
- ads->server_realm = strdup(p+2);
- ads->bind_path = ads_build_dn(ads->server_realm);
-
- /* in case the realm isn't configured in smb.conf */
- if (!ads->realm || !ads->realm[0]) {
- SAFE_FREE(ads->realm);
- ads->realm = strdup(ads->server_realm);
- }
+ 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->ldap_server_name, ads->realm));
+ ads->config.ldap_server_name, ads->config.realm));
return ADS_SUCCESS;
}
@@ -1514,9 +1669,13 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
* @return the count of SIDs pulled
**/
ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
- int *num_trusts, char ***names, DOM_SID **sids)
+ int *num_trusts,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **sids)
{
- const char *attrs[] = {"flatName", "securityIdentifier", NULL};
+ const char *attrs[] = {"name", "flatname", "securityIdentifier",
+ "trustDirection", NULL};
ADS_STATUS status;
void *res, *msg;
int count, i;
@@ -1533,11 +1692,31 @@ ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
}
(*names) = talloc(mem_ctx, sizeof(char *) * count);
+ (*alt_names) = talloc(mem_ctx, sizeof(char *) * count);
(*sids) = talloc(mem_ctx, sizeof(DOM_SID) * count);
if (! *names || ! *sids) return ADS_ERROR(LDAP_NO_MEMORY);
for (i=0, msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
- (*names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatName");
+ uint32 direction;
+
+ /* direction is a 2 bit bitfield, 1 means they trust us
+ but we don't trust them, so we should not list them
+ as users from that domain can't login */
+ if (ads_pull_uint32(ads, msg, "trustDirection", &direction) &&
+ direction == 1) {
+ continue;
+ }
+
+ (*names)[i] = ads_pull_string(ads, mem_ctx, msg, "name");
+ (*alt_names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatname");
+
+ if ((*alt_names)[i] && (*alt_names)[i][0]) {
+ /* we prefer the flatname as the primary name
+ for consistency with RPC */
+ char *name = (*alt_names)[i];
+ (*alt_names)[i] = (*names)[i];
+ (*names)[i] = name;
+ }
if (ads_pull_sid(ads, msg, "securityIdentifier", &(*sids)[i])) {
i++;
}
@@ -1562,7 +1741,7 @@ ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
void *res;
ADS_STATUS rc;
- rc = ads_do_search(ads, ads->bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",
+ rc = ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",
attrs, &res);
if (!ADS_ERR_OK(rc)) return rc;
if (!ads_pull_sid(ads, res, "objectSid", sid)) {
@@ -1573,4 +1752,66 @@ 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
+*/
+ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **workgroup)
+{
+ char *exp;
+ ADS_STATUS rc;
+ char **principles;
+ char *prefix;
+ int prefix_length;
+ int i;
+ void *res;
+ const char *attrs[] = {"servicePrincipalName", NULL};
+
+ (*workgroup) = NULL;
+
+ asprintf(&exp, "(&(objectclass=computer)(dnshostname=%s.%s))",
+ ads->config.ldap_server_name, ads->config.realm);
+ rc = ads_search(ads, &res, exp, attrs);
+ free(exp);
+
+ if (!ADS_ERR_OK(rc)) {
+ return rc;
+ }
+
+ principles = ads_pull_strings(ads, mem_ctx, res, "servicePrincipalName");
+
+ 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 (strncasecmp(principles[i], prefix, prefix_length) == 0 &&
+ strcasecmp(ads->config.realm, principles[i]+prefix_length) != 0 &&
+ !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;
+}
+
#endif
diff --git a/source3/libads/ldap_user.c b/source3/libads/ldap_user.c
index b6e3d189c5..b6fef24b5c 100644
--- a/source3/libads/ldap_user.c
+++ b/source3/libads/ldap_user.c
@@ -55,10 +55,10 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user,
status = ADS_ERROR(LDAP_NO_MEMORY);
- if (!(upn = talloc_asprintf(ctx, "%s@%s", user, ads->realm)))
+ if (!(upn = talloc_asprintf(ctx, "%s@%s", user, ads->config.realm)))
goto done;
if (!(new_dn = talloc_asprintf(ctx, "cn=%s,cn=Users,%s", name,
- ads->bind_path)))
+ ads->config.bind_path)))
goto done;
if (!(controlstr = talloc_asprintf(ctx, "%u", UF_NORMAL_ACCOUNT)))
goto done;
@@ -94,7 +94,7 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group,
status = ADS_ERROR(LDAP_NO_MEMORY);
if (!(new_dn = talloc_asprintf(ctx, "cn=%s,cn=Users,%s", group,
- ads->bind_path)))
+ ads->config.bind_path)))
goto done;
if (!(mods = ads_init_mods(ctx)))
goto done;
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index 1b55453cac..81dedb0a81 100644
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -77,7 +77,7 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
/* we need to fetch a service ticket as the ldap user in the
servers realm, regardless of our realm */
- asprintf(&sname, "ldap/%s@%s", ads->ldap_server_name, ads->server_realm);
+ asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);
krb5_init_context(&ctx);
krb5_set_default_tgs_ktypes(ctx, enc_types);
krb5_parse_name(ctx, sname, &principal);
@@ -163,7 +163,7 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
gss_release_buffer(&minor_status, &output_token);
- output_token.value = malloc(strlen(ads->bind_path) + 8);
+ output_token.value = malloc(strlen(ads->config.bind_path) + 8);
p = output_token.value;
*p++ = 1; /* no sign or seal */
@@ -171,9 +171,10 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
*p++ = max_msg_size>>16;
*p++ = max_msg_size>>8;
*p++ = max_msg_size;
- snprintf(p, strlen(ads->bind_path)+4, "dn:%s", ads->bind_path);
+ snprintf(p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path);
+ p += strlen(ads->config.bind_path);
- output_token.length = strlen(ads->bind_path) + 8;
+ output_token.length = strlen(ads->config.bind_path) + 8;
gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
&output_token, &conf_state,
diff --git a/source3/libads/util.c b/source3/libads/util.c
index d48eb10b71..b10b130a31 100644
--- a/source3/libads/util.c
+++ b/source3/libads/util.c
@@ -39,7 +39,7 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip
new_password = strdup(tmp_password);
asprintf(&service_principal, "HOST/%s", host_principal);
- ret = kerberos_set_password(ads->kdc_server, host_principal, password,
+ ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password,
service_principal, new_password);
if (!secrets_store_machine_password(new_password)) {
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 141581e261..3382ce4f4a 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -216,7 +216,7 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t
/*
comparison function used by sort_ip_list
*/
-static int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
+int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
{
int max_bits1=0, max_bits2=0;
int num_interfaces = iface_count();
diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h
index 11d399be49..dd92ecefe6 100644
--- a/source3/nsswitch/winbindd.h
+++ b/source3/nsswitch/winbindd.h
@@ -88,7 +88,7 @@ typedef struct {
struct winbindd_domain {
fstring name; /* Domain name */
- fstring full_name; /* full Domain name (realm) */
+ fstring alt_name; /* alt Domain name (if any) */
DOM_SID sid; /* SID for this domain */
/* Lookup methods for this domain (LDAP or RPC) */
@@ -170,11 +170,15 @@ struct winbindd_methods {
TALLOC_CTX *mem_ctx,
uint32 *num_domains,
char ***names,
+ char ***alt_names,
DOM_SID **dom_sids);
/* find the domain sid */
NTSTATUS (*domain_sid)(struct winbindd_domain *domain,
DOM_SID *sid);
+
+ /* setup the list of alternate names for the domain, if any */
+ NTSTATUS (*alternate_name)(struct winbindd_domain *domain);
};
/* Used to glue a policy handle and cli_state together */
@@ -190,6 +194,8 @@ typedef struct {
#include "rpc_client.h"
#define WINBINDD_ESTABLISH_LOOP 30
+#define WINBINDD_RESCAN_FREQ 300
+
#define DOM_SEQUENCE_NONE ((uint32)-1)
/* SETENV */
diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c
index b61348adfe..b0b70178a4 100644
--- a/source3/nsswitch/winbindd_ads.c
+++ b/source3/nsswitch/winbindd_ads.c
@@ -61,8 +61,8 @@ ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope
if (*res) ads_msgfree(ads, *res);
*res = NULL;
- DEBUG(3,("Reopening ads connection to %s after error %s\n",
- ads->ldap_server, ads_errstr(status)));
+ DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n",
+ ads->config.realm, ads_errstr(status)));
if (ads->ld) {
ldap_unbind(ads->ld);
}
@@ -87,7 +87,7 @@ ADS_STATUS ads_search_retry(ADS_STRUCT *ads, void **res,
const char *exp,
const char **attrs)
{
- return ads_do_search_retry(ads, ads->bind_path, LDAP_SCOPE_SUBTREE,
+ return ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
exp, attrs, res);
}
@@ -108,8 +108,6 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
ADS_STRUCT *ads;
ADS_STATUS status;
char *ccache;
- struct in_addr server_ip;
- char *sname;
if (domain->private) {
return (ADS_STRUCT *)domain->private;
@@ -120,30 +118,23 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
SETENV("KRB5CCNAME", ccache, 1);
unlink(ccache);
- if (resolve_name(domain->name, &server_ip, 0x1b)) {
- sname = inet_ntoa(server_ip);
- } else if (resolve_name(domain->name, &server_ip, 0x1c)) {
- sname = inet_ntoa(server_ip);
- } else {
- if (strcasecmp(domain->name, lp_workgroup()) != 0) {
- DEBUG(1,("can't find domain controller for %s\n", domain->name));
- return NULL;
- }
- sname = NULL;
- }
-
- ads = ads_init(primary_realm, domain->name, NULL, NULL, NULL);
+ ads = ads_init(domain->alt_name, domain->name, NULL);
if (!ads) {
DEBUG(1,("ads_init for domain %s failed\n", domain->name));
return NULL;
}
/* the machine acct password might have change - fetch it every time */
- SAFE_FREE(ads->password);
- ads->password = secrets_fetch_machine_password();
+ SAFE_FREE(ads->auth.password);
+ ads->auth.password = secrets_fetch_machine_password();
+
+ if (primary_realm) {
+ SAFE_FREE(ads->auth.realm);
+ ads->auth.realm = strdup(primary_realm);
+ }
status = ads_connect(ads);
- if (!ADS_ERR_OK(status) || !ads->realm) {
+ if (!ADS_ERR_OK(status) || !ads->config.realm) {
extern struct winbindd_methods msrpc_methods;
DEBUG(1,("ads_connect for domain %s failed: %s\n",
domain->name, ads_errstr(status)));
@@ -161,11 +152,9 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
/* remember our primary realm for trusted domain support */
if (!primary_realm) {
- primary_realm = strdup(ads->realm);
+ primary_realm = strdup(ads->config.realm);
}
- fstrcpy(domain->full_name, ads->server_realm);
-
domain->private = (void *)ads;
return ads;
}
@@ -405,7 +394,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
/* accept either the win2000 or the pre-win2000 username */
asprintf(&exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))",
- name, name, ads->realm);
+ name, name, ads->config.realm);
rc = ads_search_retry(ads, &res, exp, attrs);
free(exp);
if (!ADS_ERR_OK(rc)) {
@@ -535,49 +524,6 @@ failed:
return False;
}
-
-/* convert a sid to a distnguished name */
-static NTSTATUS sid_to_distinguished_name(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
- DOM_SID *sid,
- char **dn)
-{
- ADS_STRUCT *ads = NULL;
- const char *attrs[] = {"distinguishedName", NULL};
- ADS_STATUS rc;
- void *msg = NULL;
- char *exp;
- char *sidstr;
- NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-
- DEBUG(3,("ads: sid_to_distinguished_name\n"));
-
- ads = ads_cached_connection(domain);
- if (!ads) goto done;
-
- sidstr = sid_binstring(sid);
- asprintf(&exp, "(objectSid=%s)", sidstr);
- rc = ads_search_retry(ads, &msg, exp, attrs);
- free(exp);
- free(sidstr);
- if (!ADS_ERR_OK(rc)) {
- DEBUG(1,("sid_to_distinguished_name ads_search: %s\n", ads_errstr(rc)));
- goto done;
- }
-
- *dn = ads_pull_string(ads, mem_ctx, msg, "distinguishedName");
-
- status = NT_STATUS_OK;
-
- DEBUG(3,("ads sid_to_distinguished_name mapped %s\n", *dn));
-
-done:
- if (msg) ads_msgfree(ads, msg);
-
- return status;
-}
-
-
/* Lookup user information from a rid */
static NTSTATUS query_user(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
@@ -831,6 +777,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_domains,
char ***names,
+ char ***alt_names,
DOM_SID **dom_sids)
{
ADS_STRUCT *ads;
@@ -842,7 +789,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
ads = ads_cached_connection(domain);
if (!ads) return NT_STATUS_UNSUCCESSFUL;
- rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, dom_sids);
+ rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, alt_names, dom_sids);
return ads_ntstatus(rc);
}
@@ -867,6 +814,37 @@ static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
return ads_ntstatus(rc);
}
+
+/* find alternate names list for the domain - for ADS this is the
+ netbios name */
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS rc;
+ TALLOC_CTX *ctx;
+ char *workgroup;
+
+ ads = ads_cached_connection(domain);
+ if (!ads) return NT_STATUS_UNSUCCESSFUL;
+
+ if (!(ctx = talloc_init_named("alternate_name"))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = ads_workgroup_name(ads, ctx, &workgroup);
+
+ if (ADS_ERR_OK(rc)) {
+ fstrcpy(domain->name, workgroup);
+ fstrcpy(domain->alt_name, ads->config.realm);
+ strupper(domain->alt_name);
+ strupper(domain->name);
+ }
+
+ talloc_destroy(ctx);
+
+ return ads_ntstatus(rc);
+}
+
/* the ADS backend methods are exposed via this structure */
struct winbindd_methods ads_methods = {
True,
@@ -879,7 +857,8 @@ struct winbindd_methods ads_methods = {
lookup_groupmem,
sequence_number,
trusted_domains,
- domain_sid
+ domain_sid,
+ alternate_name
};
#endif
diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c
index a607727867..060139af3e 100644
--- a/source3/nsswitch/winbindd_cache.c
+++ b/source3/nsswitch/winbindd_cache.c
@@ -873,13 +873,14 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_domains,
char ***names,
+ char ***alt_names,
DOM_SID **dom_sids)
{
struct winbind_cache *cache = get_cache(domain);
/* we don't cache this call */
return cache->backend->trusted_domains(domain, mem_ctx, num_domains,
- names, dom_sids);
+ names, alt_names, dom_sids);
}
/* find the domain sid */
@@ -891,6 +892,15 @@ static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
return cache->backend->domain_sid(domain, sid);
}
+/* find the alternate names for the domain, if any */
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+ struct winbind_cache *cache = get_cache(domain);
+
+ /* we don't cache this call */
+ return cache->backend->alternate_name(domain);
+}
+
/* the ADS backend methods are exposed via this structure */
struct winbindd_methods cache_methods = {
True,
@@ -903,5 +913,6 @@ struct winbindd_methods cache_methods = {
lookup_groupmem,
sequence_number,
trusted_domains,
- domain_sid
+ domain_sid,
+ alternate_name
};
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c
index 3175860a79..be28984791 100644
--- a/source3/nsswitch/winbindd_cm.c
+++ b/source3/nsswitch/winbindd_cm.c
@@ -97,12 +97,15 @@ struct get_dc_name_cache {
static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name)
{
ADS_STRUCT *ads;
- ads = ads_init_simple();
+ ads = ads_init(domain, domain, NULL);
if (!ads) {
return False;
}
- DEBUG(4,("cm_ads_find_dc: realm=%s\n", ads->realm));
+ /* we don't need to bind, just connect */
+ ads->auth.no_bind = 1;
+
+ DEBUG(4,("cm_ads_find_dc: domain=%s\n", domain));
#ifdef HAVE_ADS
/* a full ads_connect() is actually overkill, as we don't srictly need
@@ -111,15 +114,15 @@ static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring sr
ads_connect(ads);
#endif
- fstrcpy(srv_name, ads->ldap_server_name);
+ if (!ads->config.realm) {
+ return False;
+ }
+
+ fstrcpy(srv_name, ads->config.ldap_server_name);
strupper(srv_name);
*dc_ip = ads->ldap_ip;
ads_destroy(&ads);
- if (!*srv_name || is_zero_ip(*dc_ip)) {
- return False;
- }
-
DEBUG(4,("cm_ads_find_dc: using server='%s' IP=%s\n",
srv_name, inet_ntoa(*dc_ip)));
@@ -247,9 +250,12 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr
zero_ip(&dc_ip);
+ ret = False;
if (lp_security() == SEC_ADS) {
ret = cm_ads_find_dc(domain, &dc_ip, srv_name);
- } else {
+ }
+ if (!ret) {
+ /* fall back on rpc methods if the ADS methods fail */
ret = cm_rpc_find_dc(domain, &dc_ip, srv_name);
}
diff --git a/source3/nsswitch/winbindd_rpc.c b/source3/nsswitch/winbindd_rpc.c
index 2bb0e8c49f..5ec34f663d 100644
--- a/source3/nsswitch/winbindd_rpc.c
+++ b/source3/nsswitch/winbindd_rpc.c
@@ -575,22 +575,23 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_domains,
char ***names,
+ char ***alt_names,
DOM_SID **dom_sids)
{
CLI_POLICY_HND *hnd;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
uint32 enum_ctx = 0;
- uint32 pref_num_domains = 5;
DEBUG(3,("rpc: trusted_domains\n"));
*num_domains = 0;
+ *alt_names = NULL;
if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
goto done;
result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
- &hnd->pol, &enum_ctx, &pref_num_domains,
+ &hnd->pol, &enum_ctx,
num_domains, names, dom_sids);
done:
return result;
@@ -621,6 +622,13 @@ done:
return status;
}
+/* find alternate names list for the domain - none for rpc */
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+ return NT_STATUS_OK;
+}
+
+
/* the rpc backend methods are exposed via this structure */
struct winbindd_methods msrpc_methods = {
False,
@@ -633,5 +641,6 @@ struct winbindd_methods msrpc_methods = {
lookup_groupmem,
sequence_number,
trusted_domains,
- domain_sid
+ domain_sid,
+ alternate_name
};
diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c
index b927380af8..daa3abb340 100644
--- a/source3/nsswitch/winbindd_util.c
+++ b/source3/nsswitch/winbindd_util.c
@@ -74,19 +74,17 @@ void free_domain_list(void)
}
/* Add a trusted domain to our list of domains */
-
-static struct winbindd_domain *add_trusted_domain(char *domain_name,
- struct winbindd_methods *methods)
+static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
+ struct winbindd_methods *methods,
+ DOM_SID *sid)
{
struct winbindd_domain *domain;
/* We can't call domain_list() as this function is called from
init_domain_list() and we'll get stuck in a loop. */
-
for (domain = _domain_list; domain; domain = domain->next) {
- if (strcmp(domain_name, domain->name) == 0) {
- DEBUG(3, ("domain %s already in domain list\n",
- domain_name));
+ if (strcmp(domain_name, domain->name) == 0 ||
+ strcmp(domain_name, domain->alt_name) == 0) {
return domain;
}
}
@@ -101,40 +99,95 @@ static struct winbindd_domain *add_trusted_domain(char *domain_name,
ZERO_STRUCTP(domain);
+ /* prioritise the short name */
+ if (strchr_m(domain_name, '.') && alt_name && *alt_name) {
+ fstrcpy(domain->name, alt_name);
+ fstrcpy(domain->alt_name, domain_name);
+ } else {
fstrcpy(domain->name, domain_name);
+ if (alt_name) {
+ fstrcpy(domain->alt_name, alt_name);
+ }
+ }
+
domain->methods = methods;
domain->sequence_number = DOM_SEQUENCE_NONE;
domain->last_seq_check = 0;
+ if (sid) {
+ sid_copy(&domain->sid, sid);
+ }
/* Link to domain list */
-
DLIST_ADD(_domain_list, domain);
+ DEBUG(1,("Added domain %s %s %s\n",
+ domain->name, domain->alt_name,
+ sid?sid_string_static(&domain->sid):""));
+
return domain;
}
-/* Look up global info for the winbind daemon */
+/*
+ rescan our domains looking for new trusted domains
+ */
+void rescan_trusted_domains(void)
+{
+ struct winbindd_domain *domain;
+ TALLOC_CTX *mem_ctx;
+ static time_t last_scan;
+ time_t t = time(NULL);
+
+ /* ony rescan every few minutes */
+ if ((unsigned)(t - last_scan) < WINBINDD_RESCAN_FREQ) {
+ return;
+ }
+ last_scan = time(NULL);
+
+ DEBUG(1, ("scanning trusted domain list\n"));
+
+ if (!(mem_ctx = talloc_init_named("init_domain_list")))
+ return;
+
+ for (domain = _domain_list; domain; domain = domain->next) {
+ NTSTATUS result;
+ char **names;
+ char **alt_names;
+ int num_domains = 0;
+ DOM_SID *dom_sids;
+ int i;
+
+ result = domain->methods->trusted_domains(domain, mem_ctx, &num_domains,
+ &names, &alt_names, &dom_sids);
+ if (!NT_STATUS_IS_OK(result)) {
+ continue;
+ }
+
+ /* Add each domain to the trusted domain list. Each domain inherits
+ the access methods of its parent */
+ for(i = 0; i < num_domains; i++) {
+ DEBUG(10,("Found domain %s\n", names[i]));
+ add_trusted_domain(names[i],
+ alt_names?alt_names[i]:NULL,
+ domain->methods, &dom_sids[i]);
+ }
+ }
+
+ talloc_destroy(mem_ctx);
+}
+
+/* Look up global info for the winbind daemon */
BOOL init_domain_list(void)
{
NTSTATUS result;
- TALLOC_CTX *mem_ctx;
extern struct winbindd_methods cache_methods;
struct winbindd_domain *domain;
- DOM_SID *dom_sids;
- char **names;
- uint32 num_domains = 0;
-
- if (!(mem_ctx = talloc_init_named("init_domain_list")))
- return False;
/* Free existing list */
-
free_domain_list();
/* Add ourselves as the first entry */
-
- domain = add_trusted_domain(lp_workgroup(), &cache_methods);
+ domain = add_trusted_domain(lp_workgroup(), NULL, &cache_methods, NULL);
/* Now we *must* get the domain sid for our primary domain. Go into
a holding pattern until that is available */
@@ -147,29 +200,12 @@ BOOL init_domain_list(void)
result = cache_methods.domain_sid(domain, &domain->sid);
}
- DEBUG(1,("Added domain %s (%s)\n",
- domain->name,
- sid_string_static(&domain->sid)));
-
- DEBUG(1, ("getting trusted domain list\n"));
+ /* get any alternate name for the primary domain */
+ cache_methods.alternate_name(domain);
- result = cache_methods.trusted_domains(domain, mem_ctx, &num_domains,
- &names, &dom_sids);
+ /* do an initial scan for trusted domains */
+ rescan_trusted_domains();
- /* Add each domain to the trusted domain list */
- if (NT_STATUS_IS_OK(result)) {
- int i;
- for(i = 0; i < num_domains; i++) {
- domain = add_trusted_domain(names[i], &cache_methods);
- if (!domain) continue;
- sid_copy(&domain->sid, &dom_sids[i]);
- DEBUG(1,("Added domain %s (%s)\n",
- domain->name,
- sid_string_static(&domain->sid)));
- }
- }
-
- talloc_destroy(mem_ctx);
return True;
}
@@ -184,7 +220,7 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
for (domain = domain_list(); domain != NULL; domain = domain->next) {
if (strequal(domain_name, domain->name) ||
- strequal(domain_name, domain->full_name))
+ (domain->alt_name[0] && strequal(domain_name, domain->alt_name)))
return domain;
}
diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c
index 542fad311c..14227a349a 100644
--- a/source3/rpc_client/cli_lsarpc.c
+++ b/source3/rpc_client/cli_lsarpc.c
@@ -542,7 +542,7 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *pol, uint32 *enum_ctx,
- uint32 *pref_num_domains, uint32 *num_domains,
+ uint32 *num_domains,
char ***domain_names, DOM_SID **domain_sids)
{
prs_struct qbuf, rbuf;
@@ -561,7 +561,8 @@ NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* Marshall data and send request */
- init_q_enum_trust_dom(&q, pol, *enum_ctx, *pref_num_domains);
+ /* 64k is enough for about 2000 trusted domains */
+ init_q_enum_trust_dom(&q, pol, *enum_ctx, 0x10000);
if (!lsa_io_q_enum_trust_dom("", &q, &qbuf, 0) ||
!rpc_api_pipe_req(cli, LSA_ENUMTRUSTDOM, &qbuf, &rbuf)) {
diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c
index 067325c06e..51b260cceb 100644
--- a/source3/rpcclient/cmd_lsarpc.c
+++ b/source3/rpcclient/cmd_lsarpc.c
@@ -191,23 +191,15 @@ static NTSTATUS cmd_lsa_enum_trust_dom(struct cli_state *cli,
/* defaults, but may be changed using params */
uint32 enum_ctx = 0;
- uint32 preferred_maxnum = 5;
uint32 num_domains = 0;
int i;
- if (argc > 3) {
- printf("Usage: %s [preferred max number (%d)] [enum context (0)]\n",
- argv[0], preferred_maxnum);
+ if (argc > 2) {
+ printf("Usage: %s [enum context (0)]\n", argv[0]);
return NT_STATUS_OK;
}
- /* enumeration context */
- if (argc >= 2 && argv[1]) {
- preferred_maxnum = atoi(argv[1]);
- }
-
- /* preferred maximum number */
- if (argc == 3 && argv[2]) {
+ if (argc == 2 && argv[1]) {
enum_ctx = atoi(argv[2]);
}
@@ -221,8 +213,8 @@ static NTSTATUS cmd_lsa_enum_trust_dom(struct cli_state *cli,
/* Lookup list of trusted domains */
result = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx,
- &preferred_maxnum, &num_domains,
- &domain_names, &domain_sids);
+ &num_domains,
+ &domain_names, &domain_sids);
if (!NT_STATUS_IS_OK(result) &&
!NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) &&
!NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index d8aea624be..1d79cbd5d0 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -200,14 +200,11 @@ static int negprot_spnego(char *p)
if (lp_security() != SEC_ADS) {
blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
} else {
- ADS_STRUCT *ads;
- ads = ads_init_simple();
/* win2000 uses host$@REALM, which we will probably use eventually,
but for now this works */
- asprintf(&principal, "HOST/%s@%s", guid, ads->realm);
+ asprintf(&principal, "HOST/%s@%s", guid, lp_realm());
blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
free(principal);
- ads_destroy(&ads);
}
memcpy(p, blob.data, blob.length);
len = blob.length;
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 1eef3d98e8..d173fec00e 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -364,6 +364,10 @@ static BOOL open_sockets_smbd(BOOL is_daemon,const char *smb_ports)
set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
set_socket_options(smbd_server_fd(),user_socket_options);
+ /* this is needed so that we get decent entries
+ in smbstatus for port 445 connects */
+ fstrcpy(remote_machine, get_socket_addr(smbd_server_fd()));
+
/* Reset global variables in util.c so
that client substitutions will be
done correctly in the process. */
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index a00554e638..2e9e54b8d9 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -122,6 +122,12 @@ static int reply_spnego_kerberos(connection_struct *conn,
ads = ads_init_simple();
+ if (!ads) {
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+
+ ads->auth.realm = strdup(lp_realm());
+
ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1,("Failed to verify incoming ticket!\n"));
@@ -139,7 +145,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
}
*p = 0;
- if (strcasecmp(p+1, ads->realm) != 0) {
+ if (strcasecmp(p+1, ads->auth.realm) != 0) {
DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
if (!lp_allow_trusted_domains()) {
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
@@ -379,6 +385,7 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
uint32 auth_flags = AUTH_FLAG_NONE;
auth_usersupplied_info *user_info = NULL;
auth_serversupplied_info *server_info = NULL;
+ extern fstring remote_machine;
/* we must have setup the auth context by now */
if (!ntlmssp_auth_context) {
@@ -413,6 +420,11 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
user, workgroup, machine, lmhash.length, nthash.length));
+ /* the client has given us its machine name (which we otherwise would not get on port 445).
+ we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
+ fstrcpy(remote_machine, machine);
+ reload_services(True);
+
#if 0
file_save("nthash1.dat", nthash.data, nthash.length);
file_save("lmhash1.dat", lmhash.data, lmhash.length);
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index ef4de3d76f..f74f633cf9 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -58,23 +58,23 @@ static int net_ads_info(int argc, const char **argv)
{
ADS_STRUCT *ads;
- ads = ads_init(NULL, NULL, opt_host, NULL, NULL);
+ ads = ads_init(NULL, NULL, opt_host);
- /* we want this servers realm, not our realm */
- SAFE_FREE(ads->realm);
+ if (ads) {
+ ads->auth.no_bind = 1;
+ }
ads_connect(ads);
- if (!ads) {
+ if (!ads || !ads->config.realm) {
d_printf("Didn't find the ldap server!\n");
return -1;
}
- d_printf("LDAP server: %s\n", ads->ldap_server);
- d_printf("LDAP server IP: %s\n", inet_ntoa(ads->ldap_ip));
- d_printf("LDAP server name: %s\n", ads->ldap_server_name);
- d_printf("Realm: %s\n", ads->realm);
- d_printf("Bind Path: %s\n", ads->bind_path);
+ d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
+ d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
+ d_printf("Realm: %s\n", ads->config.realm);
+ d_printf("Bind Path: %s\n", ads->config.bind_path);
d_printf("LDAP port: %d\n", ads->ldap_port);
return 0;
@@ -88,7 +88,7 @@ static ADS_STRUCT *ads_startup(void)
BOOL need_password = False;
BOOL second_time = False;
- ads = ads_init(NULL, NULL, opt_host, NULL, NULL);
+ ads = ads_init(NULL, NULL, opt_host);
if (!opt_user_name) {
opt_user_name = "administrator";
@@ -106,9 +106,9 @@ retry:
}
if (opt_password)
- ads->password = strdup(opt_password);
+ ads->auth.password = strdup(opt_password);
- ads->user_name = strdup(opt_user_name);
+ ads->auth.user_name = strdup(opt_user_name);
status = ads_connect(ads);
if (!ADS_ERR_OK(status)) {
@@ -141,8 +141,38 @@ int net_ads_check(void)
return 0;
}
+/*
+ determine the netbios workgroup name for a domain
+ */
+static int net_ads_workgroup(int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ TALLOC_CTX *ctx;
+ char *workgroup;
+
+ if (!(ads = ads_startup())) return -1;
+
+ if (!(ctx = talloc_init_named("net_ads_workgroup"))) {
+ return -1;
+ }
+
+ if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) {
+ d_printf("Failed to find workgroup for realm '%s'\n",
+ ads->config.realm);
+ talloc_destroy(ctx);
+ return -1;
+ }
+
+ d_printf("Workgroup: %s\n", workgroup);
+
+ talloc_destroy(ctx);
+
+ return 0;
+}
+
+
-static BOOL usergrp_display(char *field, void **values, void *data_area)
+static void usergrp_display(char *field, void **values, void *data_area)
{
char **disp_fields = (char **) data_area;
@@ -156,16 +186,15 @@ static BOOL usergrp_display(char *field, void **values, void *data_area)
}
SAFE_FREE(disp_fields[0]);
SAFE_FREE(disp_fields[1]);
- return True;
+ return;
}
if (!values) /* must be new field, indicate string field */
- return True;
+ return;
if (StrCaseCmp(field, "sAMAccountName") == 0) {
disp_fields[0] = strdup((char *) values[0]);
}
if (StrCaseCmp(field, "description") == 0)
disp_fields[1] = strdup((char *) values[0]);
- return True; /* always strings here */
}
static int net_ads_user_usage(int argc, const char **argv)
@@ -213,8 +242,8 @@ static int ads_user_add(int argc, const char **argv)
}
/* try setting the password */
- asprintf(&upn, "%s@%s", argv[0], ads->realm);
- status = krb5_set_password(ads->kdc_server, upn, argv[1]);
+ asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
+ status = krb5_set_password(ads->auth.kdc_server, upn, argv[1]);
safe_free(upn);
if (ADS_ERR_OK(status)) {
d_printf("User %s added\n", argv[0]);
@@ -331,7 +360,7 @@ int net_ads_user(int argc, const char **argv)
d_printf("\nUser name Comment"\
"\n-----------------------------\n");
- rc = ads_do_search_all_fn(ads, ads->bind_path,
+ rc = ads_do_search_all_fn(ads, ads->config.bind_path,
LDAP_SCOPE_SUBTREE,
"(objectclass=user)",
opt_long_list_entries ? longattrs :
@@ -438,7 +467,7 @@ int net_ads_group(int argc, const char **argv)
if (opt_long_list_entries)
d_printf("\nGroup name Comment"\
"\n-----------------------------\n");
- rc = ads_do_search_all_fn(ads, ads->bind_path,
+ rc = ads_do_search_all_fn(ads, ads->config.bind_path,
LDAP_SCOPE_SUBTREE,
"(objectclass=group)",
opt_long_list_entries ? longattrs :
@@ -499,11 +528,11 @@ static int net_ads_leave(int argc, const char **argv)
rc = ads_leave_realm(ads, global_myname);
if (!ADS_ERR_OK(rc)) {
d_printf("Failed to delete host '%s' from the '%s' realm.\n",
- global_myname, ads->realm);
+ global_myname, ads->config.realm);
return -1;
}
- d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->realm);
+ d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->config.realm);
return 0;
}
@@ -534,7 +563,7 @@ int net_ads_join(int argc, const char **argv)
if (!(ads = ads_startup())) return -1;
ou_str = ads_ou_string(org_unit);
- asprintf(&dn, "%s,%s", ou_str, ads->bind_path);
+ asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);
free(ou_str);
rc = ads_search_dn(ads, &res, dn, NULL);
@@ -580,7 +609,7 @@ int net_ads_join(int argc, const char **argv)
return -1;
}
- d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->realm);
+ d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->config.realm);
free(password);
@@ -675,7 +704,7 @@ static int net_ads_printer_publish(int argc, const char **argv)
get_a_printer, because the server name might be
localhost or an ip address */
prt.printerName = argv[0];
- asprintf(&servername, "%s.%s", global_myname, ads->realm);
+ asprintf(&servername, "%s.%s", global_myname, ads->config.realm);
prt.serverName = servername;
prt.shortServerName = global_myname;
prt.versionNumber = "4";
@@ -779,13 +808,13 @@ static int net_ads_password(int argc, const char **argv)
/* use the realm so we can eventually change passwords for users
in realms other than default */
- if (!(ads = ads_init(realm, NULL, NULL, NULL, NULL))) return -1;
+ if (!(ads = ads_init(realm, NULL, NULL))) return -1;
asprintf(&prompt, "Enter new password for %s:", argv[0]);
new_password = getpass(prompt);
- ret = kerberos_set_password(ads->kdc_server, auth_principal,
+ ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
auth_password, argv[0], new_password);
if (!ADS_ERR_OK(ret)) {
d_printf("Password change failed :-( ...\n");
@@ -814,7 +843,7 @@ static int net_ads_change_localhost_pass(int argc, const char **argv)
hostname = strdup(global_myname);
strlower(hostname);
- asprintf(&host_principal, "%s@%s", hostname, ads->realm);
+ asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
SAFE_FREE(hostname);
d_printf("Changing password for principal: HOST/%s\n", host_principal);
@@ -873,7 +902,7 @@ static int net_ads_search(int argc, const char **argv)
exp = argv[0];
attrs = (argv + 1);
- rc = ads_do_search_all(ads, ads->bind_path,
+ rc = ads_do_search_all(ads, ads->config.bind_path,
LDAP_SCOPE_SUBTREE,
exp, attrs, &res);
if (!ADS_ERR_OK(rc)) {
@@ -927,6 +956,7 @@ int net_ads(int argc, const char **argv)
{"CHOSTPASS", net_ads_change_localhost_pass},
{"PRINTER", net_ads_printer},
{"SEARCH", net_ads_search},
+ {"WORKGROUP", net_ads_workgroup},
{"HELP", net_ads_help},
{NULL, NULL}
};
diff --git a/source3/utils/net_lookup.c b/source3/utils/net_lookup.c
index a9aa080054..f76b186251 100644
--- a/source3/utils/net_lookup.c
+++ b/source3/utils/net_lookup.c
@@ -215,6 +215,8 @@ static int net_lookup_kdc(int argc, const char **argv)
DEBUG(1, ("No kerberos support\n"));
return -1;
}
+
+
/* lookup hosts or IP addresses using internal samba lookup fns */
int net_lookup(int argc, const char **argv)
{
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index 9b3248cf63..ae956076d5 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -1824,7 +1824,7 @@ static int rpc_trustdom_list(int argc, const char **argv)
POLICY_HND connect_hnd;
/* trusted domains listing variables */
- int enum_ctx = 0, pref_num_domains = 5;
+ int enum_ctx = 0;
int num_domains, i, pad_len, col_len = 20;
DOM_SID *domain_sids;
char **trusted_dom_names;
@@ -1894,7 +1894,7 @@ static int rpc_trustdom_list(int argc, const char **argv)
do {
nt_status = cli_lsa_enum_trust_dom(cli, mem_ctx, &connect_hnd, &enum_ctx,
- &pref_num_domains, &num_domains,
+ &num_domains,
&trusted_dom_names, &domain_sids);
if (NT_STATUS_IS_ERR(nt_status)) {