From c2aae726ea3f697c50f8d2304e2a9e69c56ab90f Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 17 Nov 2006 21:46:26 +0000 Subject: r19762: libaddns/*[ch] code fixes donated by Centeris Corporation (http://www.centeris.com/) under my copyright. * Rework error reporting to use DNS_ERROR instead of int32 * Convert memory allocation to use talloc() * Generalize the DNS request/response packet marshalling * Fix the secure update requests (This used to be commit c78798333616c3f823514df0f58da2eb3a30a988) --- source3/utils/net_ads.c | 206 +++++++++++++++++++++++++++++++++--------------- source3/utils/net_dns.c | 141 +++++++++++++++++++++++++++------ 2 files changed, 261 insertions(+), 86 deletions(-) (limited to 'source3/utils') diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 0f189f9c6f..76b6b043ba 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -1220,79 +1220,79 @@ static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads ) *******************************************************************/ #if defined(WITH_DNS_UPDATES) -static BOOL net_update_dns( TALLOC_CTX *ctx, ADS_STRUCT *ads ) +#include "dns.h" +DNS_ERROR DoDNSUpdate(ADS_STRUCT *ads, char *pszServerName, + const char *pszDomainName, + const char *pszHostName, + const struct in_addr *iplist, int num_addrs ); + + +static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads, + const char *machine_name, + const struct in_addr *addrs, + int num_addrs) { - int num_addrs; - struct in_addr *iplist = NULL; struct dns_rr_ns *nameservers = NULL; int ns_count = 0; - int ret = 0; - NTSTATUS dns_status; - fstring machine_name; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + DNS_ERROR dns_err; fstring dns_server; const char *dnsdomain; - ADS_STRUCT *ads_s = NULL; - name_to_fqdn( machine_name, global_myname() ); - strlower_m( machine_name ); if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) { - d_printf("No DNS domain configured for %s. Unable to perform DNS Update.\n", - machine_name); + d_printf("No DNS domain configured for %s. " + "Unable to perform DNS Update.\n", machine_name); + status = NT_STATUS_INVALID_PARAMETER; goto done; } dnsdomain++; - dns_status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count ); - if ( !NT_STATUS_IS_OK(dns_status) || (ns_count == 0)) { - DEBUG(3,("net_ads_join: Failed to find name server for the %s realm\n", - ads->config.realm)); - goto done; - } - - /* Get our ip address (not the 127.0.0.x address but a real ip address) */ - - num_addrs = get_my_ip_address( &iplist ); - if ( num_addrs <= 0 ) { - DEBUG(4,("net_ads_join: Failed to find my non-loopback IP addresses!\n")); - ret = -1; + status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count ); + if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) { + DEBUG(3,("net_ads_join: Failed to find name server for the %s " + "realm\n", ads->config.realm)); goto done; } - /* Drop the user creds */ + /* Now perform the dns update - we'll try non-secure and if we fail, + we'll follow it up with a secure update */ - ads_kdestroy( NULL ); + fstrcpy( dns_server, nameservers[0].hostname ); - ads_s = ads_init( ads->server.realm, ads->server.workgroup, ads->server.ldap_server ); - if ( !ads_s ) { - DEBUG(1,("net_ads_join: ads_init() failed!\n")); - ret = -1; - goto done; + dns_err = DoDNSUpdate(ads, dns_server, dnsdomain, machine_name, addrs, num_addrs); + if (!ERR_DNS_IS_OK(dns_err)) { + status = NT_STATUS_UNSUCCESSFUL; } - /* kinit with the machine password */ +done: + return status; + } - asprintf( &ads_s->auth.user_name, "%s$", global_myname() ); - ads_s->auth.password = secrets_fetch_machine_password( lp_workgroup(), NULL, NULL ); - ads_s->auth.realm = SMB_STRDUP( lp_realm() ); - ads_kinit_password( ads_s ); +static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads) +{ + int num_addrs; + struct in_addr *iplist = NULL; + fstring machine_name; + NTSTATUS status; - /* Now perform the dns update - we'll try non-secure and if we fail, we'll - follow it up with a secure update */ + name_to_fqdn( machine_name, global_myname() ); + strlower_m( machine_name ); - fstrcpy( dns_server, nameservers[0].hostname ); + /* Get our ip address (not the 127.0.0.x address but a real ip + * address) */ - ret = DoDNSUpdate(dns_server, dnsdomain, machine_name, iplist, num_addrs ); - if ( ret ) { - DEBUG(1, ("Error creating dns update!\n")); + num_addrs = get_my_ip_address( &iplist ); + if ( num_addrs <= 0 ) { + DEBUG(4,("net_ads_join: Failed to find my non-loopback IP " + "addresses!\n")); + return NT_STATUS_INVALID_PARAMETER; } -done: + status = net_update_dns_internal(mem_ctx, ads, machine_name, + iplist, num_addrs); SAFE_FREE( iplist ); - if ( ads_s ) - ads_destroy( &ads_s ); - - return (ret == 0); + return status; } #endif @@ -1506,8 +1506,22 @@ int net_ads_join(int argc, const char **argv) #if defined(WITH_DNS_UPDATES) /* We enter this block with user creds */ + ads_kdestroy( NULL ); + ads_destroy(&ads); + ads = NULL; + + if ( (ads = ads_init( lp_realm(), NULL, NULL )) != NULL ) { + /* kinit with the machine password */ + + use_in_memory_ccache(); + asprintf( &ads->auth.user_name, "%s$", global_myname() ); + ads->auth.password = secrets_fetch_machine_password( + lp_workgroup(), NULL, NULL ); + ads->auth.realm = SMB_STRDUP( lp_realm() ); + ads_kinit_password( ads ); + } - if ( !net_update_dns( ctx, ads ) ) { + if ( !ads || !NT_STATUS_IS_OK(net_update_dns( ctx, ads )) ) { d_fprintf( stderr, "DNS update failed!\n" ); } @@ -1554,42 +1568,72 @@ static int net_ads_dns_usage(int argc, const char **argv) /******************************************************************* ********************************************************************/ -static int net_ads_dns(int argc, const char **argv) +static int net_ads_dns_register(int argc, const char **argv) { #if defined(WITH_DNS_UPDATES) ADS_STRUCT *ads; ADS_STATUS status; TALLOC_CTX *ctx; - BOOL register_dns = False; - int i; + fstring name; + int num_addrs; + struct in_addr *iplist = NULL; - status = ads_startup(True, &ads); - if ( !ADS_ERR_OK(status) ) { - DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status))); +#ifdef DEVELOPER + talloc_enable_leak_report(); +#endif + + if (argc > 2) { + d_fprintf(stderr, "net ads dns register \n"); return -1; } if (!(ctx = talloc_init("net_ads_dns"))) { - DEBUG(0, ("Could not initialise talloc context\n")); + d_fprintf(stderr, "Could not initialise talloc context\n"); return -1; } - /* process additional command line args */ + if (argc > 0) { + fstrcpy(name, argv[0]); + } else { + name_to_fqdn(name, global_myname()); + } + strlower_m(name); - for ( i=0; i 1) { + if (!(iplist = SMB_MALLOC_ARRAY(struct in_addr, 1))) { + d_fprintf(stderr, "net_ads_dns_register: malloc " + "failed\n"); + return -1; } - else { - d_fprintf(stderr, "Bad option: %s\n", argv[i]); + if (inet_aton(argv[1], iplist) == 0) { + d_fprintf(stderr, "net_ads_dns_register: %s is not " + "a valid IP address\n", argv[1]); + SAFE_FREE(iplist); + return -1; + } + num_addrs = 1; + } else { + num_addrs = get_my_ip_address( &iplist ); + if ( num_addrs <= 0 ) { + d_fprintf(stderr, "net_ads_dns_regiser: Failed to " + "find my non-loopback IP addresses!\n"); return -1; } } - if ( !net_update_dns( ctx, ads ) ) { + status = ads_startup_nobind(True, &ads); + if ( !ADS_ERR_OK(status) ) { + DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status))); + TALLOC_FREE(ctx); + return -1; + } + + if ( !NT_STATUS_IS_OK(net_update_dns_internal(ctx, ads, name, + iplist, num_addrs)) ) { d_fprintf( stderr, "DNS update failed!\n" ); ads_destroy( &ads ); TALLOC_FREE( ctx ); + SAFE_FREE(iplist); return -1; } @@ -1597,6 +1641,7 @@ static int net_ads_dns(int argc, const char **argv) ads_destroy(&ads); TALLOC_FREE( ctx ); + SAFE_FREE(iplist); return 0; #else @@ -1605,6 +1650,43 @@ static int net_ads_dns(int argc, const char **argv) #endif } +#if defined(WITH_DNS_UPDATES) +DNS_ERROR do_gethostbyname(const char *server, const char *host); +#endif + +static int net_ads_dns_gethostbyname(int argc, const char **argv) +{ +#if defined(WITH_DNS_UPDATES) + DNS_ERROR err; + +#ifdef DEVELOPER + talloc_enable_leak_report(); +#endif + + if (argc != 2) { + d_fprintf(stderr, "net ads dns gethostbyname " + "\n"); + return -1; + } + + err = do_gethostbyname(argv[0], argv[1]); + + d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err)); +#endif + return 0; +} + +static int net_ads_dns(int argc, const char *argv[]) +{ + struct functable func[] = { + {"REGISTER", net_ads_dns_register}, + {"GETHOSTBYNAME", net_ads_dns_gethostbyname}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, net_ads_dns_usage); +} + /******************************************************************* ********************************************************************/ diff --git a/source3/utils/net_dns.c b/source3/utils/net_dns.c index cb83b000ca..d372211a5f 100644 --- a/source3/utils/net_dns.c +++ b/source3/utils/net_dns.c @@ -30,41 +30,115 @@ /********************************************************************* *********************************************************************/ -int DoDNSUpdate( char *pszServerName, const char *pszDomainName, - char *pszHostName, struct in_addr *iplist, int num_addrs ) +DNS_ERROR DoDNSUpdate(ADS_STRUCT *ads, char *pszServerName, + const char *pszDomainName, const char *pszHostName, + const struct in_addr *iplist, int num_addrs ) { - int32 dwError = 0; - DNS_ERROR dns_status; - HANDLE hDNSServer = ( HANDLE ) NULL; - int32 dwResponseCode = 0; - DNS_UPDATE_RESPONSE *pDNSUpdateResponse = NULL; -#if 0 - DNS_UPDATE_RESPONSE *pDNSSecureUpdateResponse = NULL; -#endif + DNS_ERROR err; + struct dns_connection *conn; + TALLOC_CTX *mem_ctx; + OM_uint32 minor; + struct dns_update_request *req, *resp; if ( (num_addrs <= 0) || !iplist ) { - return -1; + return ERROR_DNS_INVALID_PARAMETER; + } + + if (!(mem_ctx = talloc_init("DoDNSUpdate"))) { + return ERROR_DNS_NO_MEMORY; } - dns_status = DNSOpen( pszServerName, DNS_TCP, &hDNSServer ); - BAIL_ON_DNS_ERROR( dns_status ); + err = dns_open( pszServerName, DNS_TCP, mem_ctx, &conn ); + if (!ERR_DNS_IS_OK(err)) { + goto error; + } + + /* + * Probe if everything's fine + */ + + err = dns_create_probe(mem_ctx, pszDomainName, pszHostName, + num_addrs, iplist, &req); + if (!ERR_DNS_IS_OK(err)) goto error; + + err = dns_update_transaction(mem_ctx, conn, req, &resp); + if (!ERR_DNS_IS_OK(err)) goto error; + + if (dns_response_code(resp->flags) == DNS_NO_ERROR) { + TALLOC_FREE(mem_ctx); + return ERROR_DNS_SUCCESS; + } + + /* + * First try without signing + */ - dwError = DNSSendUpdate( hDNSServer, pszDomainName, pszHostName, - iplist, num_addrs, &pDNSUpdateResponse ); - BAIL_ON_ERROR( dwError ); + err = dns_create_update_request(mem_ctx, pszDomainName, pszHostName, + iplist[0].s_addr, &req); + if (!ERR_DNS_IS_OK(err)) goto error; - dwError = DNSUpdateGetResponseCode( pDNSUpdateResponse, - &dwResponseCode ); - if ( dwResponseCode == DNS_REFUSED ) { - dwError = -1; + err = dns_update_transaction(mem_ctx, conn, req, &resp); + if (!ERR_DNS_IS_OK(err)) goto error; + + if (dns_response_code(resp->flags) == DNS_NO_ERROR) { + TALLOC_FREE(mem_ctx); + return ERROR_DNS_SUCCESS; + } + + /* + * Okay, we have to try with signing + */ + { + ADS_STRUCT *ads_s; + gss_ctx_id_t gss_context; + int res; + char *keyname; + + if (!(keyname = dns_generate_keyname( mem_ctx ))) { + err = ERROR_DNS_NO_MEMORY; + goto error; + } + + if (!(ads_s = ads_init(ads->server.realm, ads->server.workgroup, + ads->server.ldap_server))) { + return ERROR_DNS_NO_MEMORY; + } + + /* kinit with the machine password */ + setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1); + asprintf( &ads_s->auth.user_name, "%s$", global_myname() ); + ads_s->auth.password = secrets_fetch_machine_password( + lp_workgroup(), NULL, NULL ); + ads_s->auth.realm = SMB_STRDUP( lp_realm() ); + res = ads_kinit_password( ads_s ); + ads_destroy(&ads_s); + if (res) { + err = ERROR_DNS_GSS_ERROR; + goto error; + } + + err = dns_negotiate_sec_ctx( pszDomainName, pszServerName, + keyname, &gss_context ); + if (!ERR_DNS_IS_OK(err)) goto error; + + err = dns_sign_update(req, gss_context, keyname, + "gss.microsoft.com", time(NULL), 3600); + + gss_delete_sec_context(&minor, &gss_context, GSS_C_NO_BUFFER); + + if (!ERR_DNS_IS_OK(err)) goto error; + + err = dns_update_transaction(mem_ctx, conn, req, &resp); + if (!ERR_DNS_IS_OK(err)) goto error; + + err = (dns_response_code(resp->flags) == DNS_NO_ERROR) ? + ERROR_DNS_SUCCESS : ERROR_DNS_UPDATE_FAILED; } - BAIL_ON_ERROR( dwError ); -cleanup: - return dwError; error: - goto cleanup; + TALLOC_FREE(mem_ctx); + return err; } /********************************************************************* @@ -96,4 +170,23 @@ int get_my_ip_address( struct in_addr **ips ) return count; } +DNS_ERROR do_gethostbyname(const char *server, const char *host) +{ + struct dns_connection *conn; + struct dns_request *req, *resp; + DNS_ERROR err; + + err = dns_open(server, DNS_UDP, NULL, &conn); + if (!ERR_DNS_IS_OK(err)) goto error; + + err = dns_create_query(conn, host, QTYPE_A, DNS_CLASS_IN, &req); + if (!ERR_DNS_IS_OK(err)) goto error; + + err = dns_transaction(conn, conn, req, &resp); + + error: + TALLOC_FREE(conn); + return err; +} + #endif /* defined(WITH_DNS_UPDATES) */ -- cgit