diff options
-rw-r--r-- | source3/auth/auth_domain.c | 6 | ||||
-rw-r--r-- | source3/include/ads.h | 41 | ||||
-rw-r--r-- | source3/libads/ads_struct.c | 119 | ||||
-rw-r--r-- | source3/libads/kerberos.c | 12 | ||||
-rw-r--r-- | source3/libads/kerberos_verify.c | 2 | ||||
-rw-r--r-- | source3/libads/ldap.c | 355 | ||||
-rw-r--r-- | source3/libads/ldap_user.c | 6 | ||||
-rw-r--r-- | source3/libads/sasl.c | 9 | ||||
-rw-r--r-- | source3/libads/util.c | 2 | ||||
-rw-r--r-- | source3/libsmb/namequery.c | 2 | ||||
-rw-r--r-- | source3/nsswitch/winbindd.h | 8 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_ads.c | 119 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cache.c | 15 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cm.c | 22 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_rpc.c | 15 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_util.c | 118 | ||||
-rw-r--r-- | source3/rpc_client/cli_lsarpc.c | 5 | ||||
-rw-r--r-- | source3/rpcclient/cmd_lsarpc.c | 18 | ||||
-rw-r--r-- | source3/smbd/negprot.c | 5 | ||||
-rw-r--r-- | source3/smbd/server.c | 4 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 14 | ||||
-rw-r--r-- | source3/utils/net_ads.c | 88 | ||||
-rw-r--r-- | source3/utils/net_lookup.c | 2 | ||||
-rw-r--r-- | source3/utils/net_rpc.c | 4 |
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)) { |