X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Flibads%2Fldap.c;h=8e0ecb87569ef6780ca8ea0a6f2d26a3472a4b19;hb=e18610a197aab80a32cae8c1e09b96496679bbad;hp=2c52e326d3e9d71699a2fc56d97dbaf999217f50;hpb=81cf1fa9e1f49a8c8e0041ddf11f79c3c7ca3fac;p=samba.git diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 2c52e326d3e..8e0ecb87569 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -29,7 +29,9 @@ #include "../libds/common/flags.h" #include "smbldap.h" #include "../libcli/security/security.h" +#include "../librpc/gen_ndr/netlogon.h" #include "lib/param/loadparm.h" +#include "libsmb/namequery.h" #ifdef HAVE_LDAP @@ -278,7 +280,12 @@ static bool ads_try_connect(ADS_STRUCT *ads, bool gc, SAFE_FREE(ads->config.client_site_name); SAFE_FREE(ads->server.workgroup); - ads->config.flags = cldap_reply.server_type; + if (!check_cldap_reply_required_flags(cldap_reply.server_type, + ads->config.flags)) { + ret = false; + goto out; + } + ads->config.ldap_server_name = SMB_STRDUP(cldap_reply.pdc_dns_name); ads->config.realm = SMB_STRDUP(cldap_reply.dns_domain); if (!strupper_m(ads->config.realm)) { @@ -304,6 +311,9 @@ static bool ads_try_connect(ADS_STRUCT *ads, bool gc, sitename_store( cldap_reply.domain_name, cldap_reply.client_site); sitename_store( cldap_reply.dns_domain, cldap_reply.client_site); + /* Leave this until last so that the flags are not clobbered */ + ads->config.flags = cldap_reply.server_type; + ret = true; out: @@ -333,7 +343,9 @@ static NTSTATUS cldap_ping_list(ADS_STRUCT *ads,const char *domain, check_negative_conn_cache(domain, server))) continue; + /* Returns ok only if it matches the correct server type */ ok = ads_try_connect(ads, false, &ip_list[i].ss); + if (ok) { return NT_STATUS_OK; } @@ -401,7 +413,7 @@ static NTSTATUS resolve_and_ping_dns(ADS_STRUCT *ads, const char *sitename, const char *realm) { int count; - struct ip_service *ip_list; + struct ip_service *ip_list = NULL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; DEBUG(6, ("resolve_and_ping_dns: (cldap) looking for realm '%s'\n", @@ -410,6 +422,7 @@ static NTSTATUS resolve_and_ping_dns(ADS_STRUCT *ads, const char *sitename, status = get_sorted_dc_list(realm, sitename, &ip_list, &count, true); if (!NT_STATUS_IS_OK(status)) { + SAFE_FREE(ip_list); return status; } @@ -552,140 +565,6 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads) c_realm, c_domain, nt_errstr(status))); return status; } - -/********************************************************************* - *********************************************************************/ - -static NTSTATUS ads_lookup_site(void) -{ - ADS_STRUCT *ads = NULL; - ADS_STATUS ads_status; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - - ads = ads_init(lp_realm(), NULL, NULL); - if (!ads) { - return NT_STATUS_NO_MEMORY; - } - - /* The NO_BIND here will find a DC and set the client site - but not establish the TCP connection */ - - ads->auth.flags = ADS_AUTH_NO_BIND; - ads_status = ads_connect(ads); - if (!ADS_ERR_OK(ads_status)) { - DEBUG(4, ("ads_lookup_site: ads_connect to our realm failed! (%s)\n", - ads_errstr(ads_status))); - } - nt_status = ads_ntstatus(ads_status); - - if (ads) { - ads_destroy(&ads); - } - - return nt_status; -} - -/********************************************************************* - *********************************************************************/ - -static const char* host_dns_domain(const char *fqdn) -{ - const char *p = fqdn; - - /* go to next char following '.' */ - - if ((p = strchr_m(fqdn, '.')) != NULL) { - p++; - } - - return p; -} - - -/** - * Connect to the Global Catalog server - * @param ads Pointer to an existing ADS_STRUCT - * @return status of connection - * - * Simple wrapper around ads_connect() that fills in the - * GC ldap server information - **/ - -ADS_STATUS ads_connect_gc(ADS_STRUCT *ads) -{ - TALLOC_CTX *frame = talloc_stackframe(); - struct dns_rr_srv *gcs_list; - int num_gcs; - const char *realm = ads->server.realm; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); - int i; - bool done = false; - char *sitename = NULL; - - if (!realm) - realm = lp_realm(); - - if ((sitename = sitename_fetch(frame, realm)) == NULL) { - ads_lookup_site(); - sitename = sitename_fetch(frame, realm); - } - - do { - /* We try once with a sitename and once without - (unless we don't have a sitename and then we're - done */ - - if (sitename == NULL) - done = true; - - nt_status = ads_dns_query_gcs(frame, - realm, - sitename, - &gcs_list, - &num_gcs); - - if (!NT_STATUS_IS_OK(nt_status)) { - ads_status = ADS_ERROR_NT(nt_status); - goto done; - } - - /* Loop until we get a successful connection or have gone - through them all. When connecting a GC server, make sure that - the realm is the server's DNS name and not the forest root */ - - for (i=0; iserver.gc = true; - ads->server.ldap_server = SMB_STRDUP(gcs_list[i].hostname); - ads->server.realm = SMB_STRDUP(host_dns_domain(ads->server.ldap_server)); - ads_status = ads_connect(ads); - if (ADS_ERR_OK(ads_status)) { - /* Reset the bind_dn to "". A Global Catalog server - may host multiple domain trees in a forest. - Windows 2003 GC server will accept "" as the search - path to imply search all domain trees in the forest */ - - SAFE_FREE(ads->config.bind_path); - ads->config.bind_path = SMB_STRDUP(""); - - - goto done; - } - SAFE_FREE(ads->server.ldap_server); - SAFE_FREE(ads->server.realm); - } - - TALLOC_FREE(gcs_list); - num_gcs = 0; - } while (!done); - -done: - talloc_destroy(frame); - - return ads_status; -} - - /** * Connect to the LDAP server * @param ads Pointer to an existing ADS_STRUCT @@ -699,8 +578,9 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads) char addr[INET6_ADDRSTRLEN]; ZERO_STRUCT(ads->ldap); + ZERO_STRUCT(ads->ldap_wrap_data); ads->ldap.last_attempt = time_mono(NULL); - ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN; + ads->ldap_wrap_data.wrap_type = ADS_SASLWRAP_TYPE_PLAIN; /* try with a user specified server */ @@ -735,6 +615,11 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads) if (ads->server.gc == true) { return ADS_ERROR(LDAP_OPERATIONS_ERROR); } + + if (ads->server.no_fallback) { + status = ADS_ERROR_NT(NT_STATUS_NOT_FOUND); + goto out; + } } ntstatus = ads_find_dc(ads); @@ -776,8 +661,8 @@ got_connection: goto out; } - ads->ldap.mem_ctx = talloc_init("ads LDAP connection memory"); - if (!ads->ldap.mem_ctx) { + ads->ldap_wrap_data.mem_ctx = talloc_init("ads LDAP connection memory"); + if (!ads->ldap_wrap_data.mem_ctx) { status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); goto out; } @@ -863,13 +748,15 @@ void ads_disconnect(ADS_STRUCT *ads) ldap_unbind(ads->ldap.ld); ads->ldap.ld = NULL; } - if (ads->ldap.wrap_ops && ads->ldap.wrap_ops->disconnect) { - ads->ldap.wrap_ops->disconnect(ads); + if (ads->ldap_wrap_data.wrap_ops && + ads->ldap_wrap_data.wrap_ops->disconnect) { + ads->ldap_wrap_data.wrap_ops->disconnect(&ads->ldap_wrap_data); } - if (ads->ldap.mem_ctx) { - talloc_free(ads->ldap.mem_ctx); + if (ads->ldap_wrap_data.mem_ctx) { + talloc_free(ads->ldap_wrap_data.mem_ctx); } ZERO_STRUCT(ads->ldap); + ZERO_STRUCT(ads->ldap_wrap_data); } /* @@ -1169,6 +1056,11 @@ done: ber_bvfree(ext_bv); } + if (rc != LDAP_SUCCESS && *res != NULL) { + ads_msgfree(ads, *res); + *res = NULL; + } + /* if/when we decide to utf8-encode attrs, take out this next line */ TALLOC_FREE(search_attrs); @@ -1219,9 +1111,6 @@ static ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path, status = ads_do_paged_search_args(ads, bind_path, scope, expr, attrs, args, &res2, &count, &cookie); if (!ADS_ERR_OK(status)) { - /* Ensure we free all collected results */ - ads_msgfree(ads, *res); - *res = NULL; break; } @@ -1477,7 +1366,7 @@ char *ads_parent_dn(const char *dn) { ADS_STATUS status; char *expr; - const char *attrs[] = {"*", "nTSecurityDescriptor", NULL}; + const char *attrs[] = {"*", "msDS-SupportedEncryptionTypes", "nTSecurityDescriptor", NULL}; *res = NULL; @@ -1627,6 +1516,17 @@ static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods, } #endif +static void ads_print_error(int ret, LDAP *ld) +{ + if (ret != 0) { + char *ld_error = NULL; + ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(10,("AD LDAP failure %d (%s):\n%s\n", ret, + ldap_err2string(ret), ld_error)); + SAFE_FREE(ld_error); + } +} + /** * Perform an ldap modify * @param ads connection to ads server @@ -1662,6 +1562,7 @@ ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods) mods[i] = NULL; ret = ldap_modify_ext_s(ads->ldap.ld, utf8_dn, (LDAPMod **) mods, controls, NULL); + ads_print_error(ret, ads->ldap.ld); TALLOC_FREE(utf8_dn); return ADS_ERROR(ret); } @@ -1690,6 +1591,7 @@ ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods) mods[i] = NULL; ret = ldap_add_s(ads->ldap.ld, utf8_dn, (LDAPMod**)mods); + ads_print_error(ret, ads->ldap.ld); TALLOC_FREE(utf8_dn); return ADS_ERROR(ret); } @@ -1711,6 +1613,7 @@ ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn) } ret = ldap_delete_s(ads->ldap.ld, utf8_dn); + ads_print_error(ret, ads->ldap.ld); TALLOC_FREE(utf8_dn); return ADS_ERROR(ret); } @@ -2044,7 +1947,7 @@ bool ads_element_in_array(const char **el_array, size_t num_el, const char *el) * * @param[in] num_spns The number of principals stored in the array. * - * @return 0 on success, or a ADS error if a failure occured. + * @return 0 on success, or a ADS error if a failure occurred. */ ADS_STATUS ads_get_service_principal_names(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, @@ -2095,28 +1998,27 @@ done: * (found by hostname) in AD. * @param ads An initialized ADS_STRUCT * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account. - * @param my_fqdn The fully qualified DNS name of the machine - * @param spn A string of the service principal to add, i.e. 'host' + * @param spns An array or strings for the service principals to add, + * i.e. 'cifs/machine_name', 'http/machine.full.domain.com' etc. * @return 0 upon sucess, or non-zero if a failure occurs **/ -ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_name, - const char *my_fqdn, const char *spn) +ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads, + const char *machine_name, + const char **spns) { ADS_STATUS ret; TALLOC_CTX *ctx; LDAPMessage *res = NULL; - char *psp1, *psp2; ADS_MODLIST mods; char *dn_string = NULL; - const char *servicePrincipalName[3] = {NULL, NULL, NULL}; + const char **servicePrincipalName = spns; ret = ads_find_machine_acct(ads, &res, machine_name); if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) { DEBUG(1,("ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation.\n", machine_name)); - DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principal '%s/%s@%s' has NOT been added.\n", - spn, machine_name, ads->config.realm)); + DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principals have NOT been added.\n")); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_SUCH_OBJECT); } @@ -2127,44 +2029,24 @@ ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_n return ADS_ERROR(LDAP_NO_MEMORY); } - /* add short name spn */ + DEBUG(5,("ads_add_service_principal_name: INFO: " + "Adding %s to host %s\n", + spns[0] ? "N/A" : spns[0], machine_name)); - if ( (psp1 = talloc_asprintf(ctx, "%s/%s", spn, machine_name)) == NULL ) { - talloc_destroy(ctx); - ads_msgfree(ads, res); - return ADS_ERROR(LDAP_NO_MEMORY); - } - if (!strlower_m(&psp1[strlen(spn) + 1])) { - ret = ADS_ERROR(LDAP_NO_MEMORY); - goto out; - } - servicePrincipalName[0] = psp1; - DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", - psp1, machine_name)); - - - /* add fully qualified spn */ - - if ( (psp2 = talloc_asprintf(ctx, "%s/%s", spn, my_fqdn)) == NULL ) { - ret = ADS_ERROR(LDAP_NO_MEMORY); - goto out; - } - if (!strlower_m(&psp2[strlen(spn) + 1])) { - ret = ADS_ERROR(LDAP_NO_MEMORY); - goto out; - } - servicePrincipalName[1] = psp2; - - DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", - psp2, machine_name)); + DEBUG(5,("ads_add_service_principal_name: INFO: " + "Adding %s to host %s\n", + spns[1] ? "N/A" : spns[1], machine_name)); if ( (mods = ads_init_mods(ctx)) == NULL ) { ret = ADS_ERROR(LDAP_NO_MEMORY); goto out; } - ret = ads_add_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName); + ret = ads_add_strlist(ctx, + &mods, + "servicePrincipalName", + servicePrincipalName); if (!ADS_ERR_OK(ret)) { DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n")); goto out; @@ -2196,8 +2078,10 @@ ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_n * @return 0 upon success, or non-zero otherwise **/ -ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, - const char *org_unit) +ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, + const char *machine_name, + const char *org_unit, + uint32_t etype_list) { ADS_STATUS ret; char *samAccountName, *controlstr; @@ -2211,6 +2095,12 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, uint32_t acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\ UF_DONT_EXPIRE_PASSWD |\ UF_ACCOUNTDISABLE ); + uint32_t func_level = 0; + + ret = ads_domain_func_level(ads, &func_level); + if (!ADS_ERR_OK(ret)) { + return ret; + } if (!(ctx = talloc_init("ads_add_machine_acct"))) return ADS_ERROR(LDAP_NO_MEMORY); @@ -2242,6 +2132,17 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, ads_mod_strlist(ctx, &mods, "objectClass", objectClass); ads_mod_str(ctx, &mods, "userAccountControl", controlstr); + if (func_level >= DS_DOMAIN_FUNCTION_2008) { + const char *etype_list_str; + + etype_list_str = talloc_asprintf(ctx, "%d", (int)etype_list); + if (etype_list_str == NULL) { + goto done; + } + ads_mod_str(ctx, &mods, "msDS-SupportedEncryptionTypes", + etype_list_str); + } + ret = ads_gen_add(ads, new_dn, mods); done: @@ -2328,8 +2229,9 @@ done: */ static void dump_binary(ADS_STRUCT *ads, const char *field, struct berval **values) { - int i, j; + size_t i; for (i=0; values[i]; i++) { + ber_len_t j; printf("%s: ", field); for (j=0; jbv_len; j++) { printf("%02X", (unsigned char)values[i]->bv_val[j]); @@ -2362,13 +2264,15 @@ static void dump_sid(ADS_STRUCT *ads, const char *field, struct berval **values) { int i; for (i=0; values[i]; i++) { + struct sid_parse_ret ret; struct dom_sid sid; - fstring tmp; - if (!sid_parse((const uint8_t *)values[i]->bv_val, - values[i]->bv_len, &sid)) { + struct dom_sid_buf tmp; + ret = sid_parse((const uint8_t *)values[i]->bv_val, + values[i]->bv_len, &sid); + if (ret.len == -1) { return; } - printf("%s: %s\n", field, sid_to_fstring(tmp, &sid)); + printf("%s: %s\n", field, dom_sid_str_buf(&sid, &tmp)); } } @@ -2639,8 +2543,7 @@ int ads_count_replies(ADS_STRUCT *ads, void *res) { char **values; char **ret = NULL; - int i; - size_t converted_size; + size_t i, converted_size; values = ldap_get_values(ads->ldap.ld, msg, field); if (!values) @@ -2872,7 +2775,6 @@ int ads_count_replies(ADS_STRUCT *ads, void *res) LDAPMessage *msg, const char *field, struct dom_sid **sids) { struct berval **values; - bool ret; int count, i; values = ldap_get_values_len(ads->ldap.ld, msg, field); @@ -2895,11 +2797,13 @@ int ads_count_replies(ADS_STRUCT *ads, void *res) count = 0; for (i=0; values[i]; i++) { + struct sid_parse_ret ret; ret = sid_parse((const uint8_t *)values[i]->bv_val, values[i]->bv_len, &(*sids)[count]); - if (ret) { - DEBUG(10, ("pulling SID: %s\n", - sid_string_dbg(&(*sids)[count]))); + if (ret.len != -1) { + struct dom_sid_buf buf; + DBG_DEBUG("pulling SID: %s\n", + dom_sid_str_buf(&(*sids)[count], &buf)); count++; } } @@ -3047,6 +2951,7 @@ ADS_STATUS ads_current_time(ADS_STRUCT *ads) if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup, ads->server.ldap_server )) == NULL ) { + status = ADS_ERROR(LDAP_NO_MEMORY); goto done; } ads_s->auth.flags = ADS_AUTH_ANON_BIND; @@ -3453,6 +3358,7 @@ ADS_STATUS ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx, } break; case ADS_EXTENDED_DN_HEX_STRING: { + struct sid_parse_ret ret; fstring buf; size_t buf_len; @@ -3461,7 +3367,8 @@ ADS_STATUS ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx, return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); } - if (!sid_parse((const uint8_t *)buf, buf_len, sid)) { + ret = sid_parse((const uint8_t *)buf, buf_len, sid); + if (ret.len == -1) { DEBUG(10,("failed to parse sid\n")); return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); } @@ -3485,7 +3392,7 @@ char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine int count = 0; char *name = NULL; - status = ads_find_machine_acct(ads, &res, lp_netbios_name()); + status = ads_find_machine_acct(ads, &res, machine_name); if (!ADS_ERR_OK(status)) { DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n", lp_netbios_name())); @@ -3542,33 +3449,37 @@ out: /******************************************************************** ********************************************************************/ -char* ads_get_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name ) +bool ads_has_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name ) { LDAPMessage *res = NULL; ADS_STATUS status; int count = 0; char *name = NULL; + bool ok = false; - status = ads_find_machine_acct(ads, &res, lp_netbios_name()); + status = ads_find_machine_acct(ads, &res, machine_name); if (!ADS_ERR_OK(status)) { - DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n", + DEBUG(0,("ads_has_samaccountname: Failed to find account for %s\n", lp_netbios_name())); goto out; } if ( (count = ads_count_replies(ads, res)) != 1 ) { - DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count)); + DEBUG(1,("ads_has_samaccountname: %d entries returned!\n", count)); goto out; } if ( (name = ads_pull_string(ads, ctx, res, "sAMAccountName")) == NULL ) { - DEBUG(0,("ads_get_dnshostname: No sAMAccountName attribute!\n")); + DEBUG(0,("ads_has_samaccountname: No sAMAccountName attribute!\n")); } out: ads_msgfree(ads, res); - - return name; + if (name != NULL) { + ok = (strlen(name) > 0); + } + TALLOC_FREE(name); + return ok; } #if 0 @@ -4035,10 +3946,16 @@ ADS_STATUS ads_check_ou_dn(TALLOC_CTX *mem_ctx, const char *name; char *ou_string; - exploded_dn = ldap_explode_dn(*account_ou, 0); - if (exploded_dn) { - ldap_value_free(exploded_dn); - return ADS_SUCCESS; + if (account_ou == NULL) { + return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } + + if (*account_ou != NULL) { + exploded_dn = ldap_explode_dn(*account_ou, 0); + if (exploded_dn) { + ldap_value_free(exploded_dn); + return ADS_SUCCESS; + } } ou_string = ads_ou_string(ads, *account_ou);