From 6fada7a82aa67e7b80ff003bd527092da68542c8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 31 Aug 2006 01:20:21 +0000 Subject: [PATCH] r17943: The horror, the horror. Add KDC site support by writing out a custom krb5.conf file containing the KDC I need. This may suck.... Needs some testing :-). Jeremy. (This used to be commit d500e1f96d92dfcc6292c448d1b399195f762d89) --- source3/include/ads.h | 1 + source3/libads/cldap.c | 2 -- source3/libads/kerberos.c | 58 +++++++++++++++++++++++++++++++ source3/libads/ldap.c | 1 + source3/libsmb/namequery_dc.c | 27 +++++++++++---- source3/nsswitch/winbindd_cm.c | 63 ++++++++++++++++++++-------------- 6 files changed, 117 insertions(+), 35 deletions(-) diff --git a/source3/include/ads.h b/source3/include/ads.h index 0ef84b48058..365ac3e8526 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -42,6 +42,7 @@ typedef struct { /* info derived from the servers config */ struct { + uint32 flags; /* cldap flags identifying the services. */ char *realm; char *bind_path; char *ldap_server_name; diff --git a/source3/libads/cldap.c b/source3/libads/cldap.c index 3a6083558f1..da1dec6b931 100644 --- a/source3/libads/cldap.c +++ b/source3/libads/cldap.c @@ -306,5 +306,3 @@ BOOL ads_cldap_netlogon(const char *server, const char *realm, struct cldap_net return True; } - - diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 910207968c8..4e4e4cfebf8 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -464,4 +464,62 @@ int kerberos_kinit_password(const char *principal, 0); } +/************************************************************************ + Create a specific krb5.conf file in the private directory pointing + at a specific kdc for a realm. Keyed off domain name. Sets + KRB5_CONFIG environment variable to point to this file. Must be + run as root or will fail (which is a good thing :-). +************************************************************************/ + +BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain, struct in_addr ip) +{ + XFILE *xfp = NULL; + char *fname = talloc_asprintf(NULL, "%s/smb_krb5.conf.%s", lp_private_dir(), domain); + char *file_contents = NULL; + size_t flen = 0; + + if (!fname) { + return False; + } + + file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n" + "[realms]\n\t%s = {\n" + "\t\tkdc = %s\n]\n", + realm, realm, inet_ntoa(ip)); + + if (!file_contents) { + TALLOC_FREE(fname); + return False; + } + + flen = strlen(file_contents); + xfp = x_fopen(fname, O_CREAT|O_WRONLY, 0600); + if (!xfp) { + TALLOC_FREE(fname); + return False; + } + /* Lock the file. */ + if (!fcntl_lock(xfp->fd, F_SETLKW, 0, 1, F_WRLCK)) { + unlink(fname); + x_fclose(xfp); + TALLOC_FREE(fname); + return False; + } + + if (x_fwrite(file_contents, flen, 1, xfp) != flen) { + unlink(fname); + x_fclose(xfp); + TALLOC_FREE(fname); + return False; + } + if (x_fclose(xfp)==-1) { + unlink(fname); + TALLOC_FREE(fname); + return False; + } + /* Set the environment variable to this file. */ + setenv("KRB5_CONFIG", fname, 1); + TALLOC_FREE(fname); + return True; +} #endif diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 947f58a8fd5..1d192895d90 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -159,6 +159,7 @@ BOOL ads_try_connect(ADS_STRUCT *ads, const char *server ) SAFE_FREE(ads->config.ldap_server_name); SAFE_FREE(ads->server.workgroup); + ads->config.flags = cldap_reply.flags; ads->config.ldap_server_name = SMB_STRDUP(cldap_reply.hostname); strupper_m(cldap_reply.domain); ads->config.realm = SMB_STRDUP(cldap_reply.domain); diff --git a/source3/libsmb/namequery_dc.c b/source3/libsmb/namequery_dc.c index ed71a9816a9..4099cc9dd8f 100644 --- a/source3/libsmb/namequery_dc.c +++ b/source3/libsmb/namequery_dc.c @@ -38,8 +38,9 @@ static BOOL ads_dc_name(const char *domain, char *sitename = sitename_fetch(); int i; - if (!realm && strequal(domain, lp_workgroup())) + if (!realm && strequal(domain, lp_workgroup())) { realm = lp_realm(); + } /* Try this 3 times then give up. */ for( i =0 ; i < 3; i++) { @@ -64,22 +65,34 @@ static BOOL ads_dc_name(const char *domain, } /* Now we've found a server, see if our sitename - has changed. If so, we need to re-do the query + has changed. If so, we need to re-do the DNS query to ensure we only find servers in our site. */ - if (!sitename_changed(sitename)) { - break; + if (sitename_changed(sitename)) { + SAFE_FREE(sitename); + sitename = sitename_fetch(); + ads_destroy(&ads); + continue; } - ads_destroy(&ads); - } +#ifdef HAVE_KRB5 + if ((ads->config.flags & ADS_KDC) && sitename) { + /* We're going to use this KDC for this realm/domain. + If we are using sites, then force the krb5 libs + to use this KDC. */ + create_local_private_krb5_conf_for_domain(realm, + domain, + ads->ldap_ip); + } +#endif + break; + } if (i == 3) { DEBUG(1,("ads_dc_name: sitename (now \"%s\") keeps changing ???\n", sitename ? sitename : "")); SAFE_FREE(sitename); - ads_destroy(&ads); return False; } diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 2f2bfb60ee8..a09faaed949 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -590,7 +590,43 @@ static BOOL dcip_to_name( const char *domainname, const char *realm, ip_list.ip = ip; ip_list.port = 0; - /* try GETDC requests first */ +#ifdef WITH_ADS + /* For active directory servers, try to get the ldap server name. + None of these failures should be considered critical for now */ + + if ( lp_security() == SEC_ADS ) { + ADS_STRUCT *ads; + + ads = ads_init(realm, domainname, NULL); + ads->auth.flags |= ADS_AUTH_NO_BIND; + + if (ads_try_connect( ads, inet_ntoa(ip) ) ) { + const char *sitename = sitename_fetch(); + /* We got a cldap packet. */ + fstrcpy(name, ads->config.ldap_server_name); + namecache_store(name, 0x20, 1, &ip_list); + +#ifdef HAVE_KRB5 + if ((ads->config.flags & ADS_KDC) && sitename) { + /* We're going to use this KDC for this realm/domain. + If we are using sites, then force the krb5 libs + to use this KDC. */ + + create_local_private_krb5_conf_for_domain(realm, + domainname, + ip); + } +#endif + SAFE_FREE(sitename); + ads_destroy( &ads ); + return True; + } + + ads_destroy( &ads ); + } +#endif + + /* try GETDC requests next */ if (send_getdc_request(ip, domainname, sid)) { int i; @@ -610,31 +646,6 @@ static BOOL dcip_to_name( const char *domainname, const char *realm, namecache_store(name, 0x20, 1, &ip_list); return True; } - -#ifdef WITH_ADS - /* for active directory servers, try to get the ldap server name. - None of these failure should be considered critical for now */ - - if ( lp_security() == SEC_ADS ) - { - ADS_STRUCT *ads; - - ads = ads_init( realm, domainname, NULL ); - ads->auth.flags |= ADS_AUTH_NO_BIND; - - if ( !ads_try_connect( ads, inet_ntoa(ip) ) ) { - ads_destroy( &ads ); - return False; - } - - fstrcpy(name, ads->config.ldap_server_name); - namecache_store(name, 0x20, 1, &ip_list); - - ads_destroy( &ads ); - return True; - } -#endif - return False; }