s3:libads: Fix code spelling
[samba.git] / source3 / libads / kerberos.c
index a307286ef2798e137203812dd09709584c09628c..50f4a6de3c625223b8926e970b49f7a8bc237f91 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    kerberos utility library
    Copyright (C) Andrew Tridgell 2001
@@ -22,6 +22,7 @@
 */
 
 #include "includes.h"
+#include "libsmb/namequery.h"
 #include "system/filesys.h"
 #include "smb_krb5.h"
 #include "../librpc/gen_ndr/ndr_misc.h"
 #define LIBADS_CCACHE_NAME "MEMORY:libads"
 
 /*
-  we use a prompter to avoid a crash bug in the kerberos libs when 
+  we use a prompter to avoid a crash bug in the kerberos libs when
   dealing with empty passwords
   this prompter is just a string copy ...
 */
-static krb5_error_code 
+static krb5_error_code
 kerb_prompter(krb5_context ctx, void *data,
               const char *name,
               const char *banner,
@@ -58,7 +59,7 @@ kerb_prompter(krb5_context ctx, void *data,
                 * version have looping detection and return with a proper error code.
                 */
 
-#if HAVE_KRB5_PROMPT_TYPE /* Heimdal */
+#if defined(HAVE_KRB5_PROMPT_TYPE) /* Heimdal */
                 if (prompts[0].type == KRB5_PROMPT_TYPE_NEW_PASSWORD &&
                     prompts[1].type == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) {
                        /*
@@ -104,7 +105,7 @@ kerb_prompter(krb5_context ctx, void *data,
   place in default cache location.
   remus@snapserver.com
 */
-int kerberos_kinit_password_ext(const char *principal,
+int kerberos_kinit_password_ext(const char *given_principal,
                                const char *password,
                                int time_offset,
                                time_t *expire_time,
@@ -113,8 +114,12 @@ int kerberos_kinit_password_ext(const char *principal,
                                bool request_pac,
                                bool add_netbios_addr,
                                time_t renewable_time,
+                               TALLOC_CTX *mem_ctx,
+                               char **_canon_principal,
+                               char **_canon_realm,
                                NTSTATUS *ntstatus)
 {
+       TALLOC_CTX *frame = talloc_stackframe();
        krb5_context ctx = NULL;
        krb5_error_code code = 0;
        krb5_ccache cc = NULL;
@@ -123,27 +128,33 @@ int kerberos_kinit_password_ext(const char *principal,
        krb5_creds my_creds;
        krb5_get_init_creds_opt *opt = NULL;
        smb_krb5_addresses *addr = NULL;
+       char *canon_principal = NULL;
+       char *canon_realm = NULL;
 
        ZERO_STRUCT(my_creds);
 
-       initialize_krb5_error_table();
-       if ((code = krb5_init_context(&ctx)))
-               goto out;
+       code = smb_krb5_init_context_common(&ctx);
+       if (code != 0) {
+               DBG_ERR("kerberos init context failed (%s)\n",
+                       error_message(code));
+               TALLOC_FREE(frame);
+               return code;
+       }
 
        if (time_offset != 0) {
                krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
        }
 
-       DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
-                       principal,
-                       cache_name ? cache_name: krb5_cc_default_name(ctx),
-                       getenv("KRB5_CONFIG")));
+       DBG_DEBUG("as %s using [%s] as ccache and config [%s]\n",
+                 given_principal,
+                 cache_name ? cache_name: krb5_cc_default_name(ctx),
+                 getenv("KRB5_CONFIG"));
 
        if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
                goto out;
        }
 
-       if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
+       if ((code = smb_krb5_parse_name(ctx, given_principal, &me))) {
                goto out;
        }
 
@@ -155,7 +166,10 @@ int kerberos_kinit_password_ext(const char *principal,
        krb5_get_init_creds_opt_set_forwardable(opt, True);
 
        /* Turn on canonicalization for lower case realm support */
-#ifndef SAMBA4_USES_HEIMDAL /* MIT */
+#ifdef SAMBA4_USES_HEIMDAL
+       krb5_get_init_creds_opt_set_win2k(ctx, opt, true);
+       krb5_get_init_creds_opt_set_canonicalize(ctx, opt, true);
+#else /* MIT */
        krb5_get_init_creds_opt_set_canonicalize(opt, true);
 #endif /* MIT */
 #if 0
@@ -178,16 +192,29 @@ int kerberos_kinit_password_ext(const char *principal,
                krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
        }
 
-       if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password), 
+       if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password),
                                                 kerb_prompter, discard_const_p(char, password),
                                                 0, NULL, opt))) {
                goto out;
        }
 
-       canon_princ = me;
-#ifndef SAMBA4_USES_HEIMDAL /* MIT */
        canon_princ = my_creds.client;
-#endif /* MIT */
+
+       code = smb_krb5_unparse_name(frame,
+                                    ctx,
+                                    canon_princ,
+                                    &canon_principal);
+       if (code != 0) {
+               goto out;
+       }
+
+       DBG_DEBUG("%s mapped to %s\n", given_principal, canon_principal);
+
+       canon_realm = smb_krb5_principal_get_realm(frame, ctx, canon_princ);
+       if (canon_realm == NULL) {
+               code = ENOMEM;
+               goto out;
+       }
 
        if ((code = krb5_cc_initialize(ctx, cc, canon_princ))) {
                goto out;
@@ -204,6 +231,13 @@ int kerberos_kinit_password_ext(const char *principal,
        if (renew_till_time) {
                *renew_till_time = (time_t) my_creds.times.renew_till;
        }
+
+       if (_canon_principal != NULL) {
+               *_canon_principal = talloc_move(mem_ctx, &canon_principal);
+       }
+       if (_canon_realm != NULL) {
+               *_canon_realm = talloc_move(mem_ctx, &canon_realm);
+       }
  out:
        if (ntstatus) {
                /* fast path */
@@ -233,6 +267,7 @@ int kerberos_kinit_password_ext(const char *principal,
        if (ctx) {
                krb5_free_context(ctx);
        }
+       TALLOC_FREE(frame);
        return code;
 }
 
@@ -242,10 +277,10 @@ int ads_kdestroy(const char *cc_name)
        krb5_context ctx = NULL;
        krb5_ccache cc = NULL;
 
-       initialize_krb5_error_table();
-       if ((code = krb5_init_context (&ctx))) {
-               DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
-                       error_message(code)));
+       code = smb_krb5_init_context_common(&ctx);
+       if (code != 0) {
+               DBG_ERR("kerberos init context failed (%s)\n",
+                       error_message(code));
                return code;
        }
 
@@ -264,7 +299,7 @@ int ads_kdestroy(const char *cc_name)
        }
 
        if ((code = krb5_cc_destroy (ctx, cc))) {
-               DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
+               DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
                        error_message(code)));
        }
 
@@ -272,110 +307,6 @@ int ads_kdestroy(const char *cc_name)
        return code;
 }
 
-/************************************************************************
- Return the standard DES salt key
-************************************************************************/
-
-char* kerberos_standard_des_salt( void )
-{
-       fstring salt;
-
-       fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
-       (void)strlower_m( salt );
-       fstrcat( salt, lp_realm() );
-
-       return SMB_STRDUP( salt );
-}
-
-/************************************************************************
-************************************************************************/
-
-static char* des_salt_key( void )
-{
-       char *key;
-
-       if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
-                    lp_realm()) == -1) {
-               return NULL;
-       }
-
-       return key;
-}
-
-/************************************************************************
-************************************************************************/
-
-bool kerberos_secrets_store_des_salt( const char* salt )
-{
-       char* key;
-       bool ret;
-
-       if ( (key = des_salt_key()) == NULL ) {
-               DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
-               return False;
-       }
-
-       if ( !salt ) {
-               DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
-               secrets_delete( key );
-               return True;
-       }
-
-       DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
-
-       ret = secrets_store( key, salt, strlen(salt)+1 );
-
-       SAFE_FREE( key );
-
-       return ret;
-}
-
-/************************************************************************
-************************************************************************/
-
-static
-char* kerberos_secrets_fetch_des_salt( void )
-{
-       char *salt, *key;
-
-       if ( (key = des_salt_key()) == NULL ) {
-               DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
-               return NULL;
-       }
-
-       salt = (char*)secrets_fetch( key, NULL );
-
-       SAFE_FREE( key );
-
-       return salt;
-}
-
-/************************************************************************
- Routine to get the salting principal for this service.
- Caller must free if return is not null.
- ************************************************************************/
-
-char *kerberos_secrets_fetch_salt_princ(void)
-{
-       char *salt_princ_s;
-       /* lookup new key first */
-
-       salt_princ_s = kerberos_secrets_fetch_des_salt();
-       if (salt_princ_s == NULL) {
-               /* fall back to host/machine.realm@REALM */
-               salt_princ_s = kerberos_standard_des_salt();
-       }
-
-       return salt_princ_s;
-}
-
-char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
-                                              const char *host_princ_s,
-                                              int enctype)
-{
-       return kerberos_secrets_fetch_salt_princ();
-}
-
 int create_kerberos_key_from_string(krb5_context context,
                                        krb5_principal host_princ,
                                        krb5_principal salt_princ,
@@ -417,15 +348,18 @@ int kerberos_kinit_password(const char *principal,
                            int time_offset,
                            const char *cache_name)
 {
-       return kerberos_kinit_password_ext(principal, 
-                                          password, 
-                                          time_offset, 
-                                          0, 
+       return kerberos_kinit_password_ext(principal,
+                                          password,
+                                          time_offset,
+                                          0,
                                           0,
                                           cache_name,
                                           False,
                                           False,
                                           0,
+                                          NULL,
+                                          NULL,
+                                          NULL,
                                           NULL);
 }
 
@@ -440,10 +374,10 @@ int kerberos_kinit_password(const char *principal,
 
 ************************************************************************/
 
-static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
+static void add_sockaddr_unique(struct sockaddr_storage *addrs, size_t *num_addrs,
                                const struct sockaddr_storage *addr)
 {
-       int i;
+       size_t i;
 
        for (i=0; i<*num_addrs; i++) {
                if (sockaddr_equal((const struct sockaddr *)&addrs[i],
@@ -486,24 +420,40 @@ static char *get_kdc_ip_string(char *mem_ctx,
                const struct sockaddr_storage *pss)
 {
        TALLOC_CTX *frame = talloc_stackframe();
-       int i;
-       struct ip_service *ip_srv_site = NULL;
-       struct ip_service *ip_srv_nonsite = NULL;
-       int count_site = 0;
-       int count_nonsite;
-       int num_dcs;
-       struct sockaddr_storage *dc_addrs;
+       size_t i;
+       struct samba_sockaddr *ip_sa_site = NULL;
+       struct samba_sockaddr *ip_sa_nonsite = NULL;
+       struct samba_sockaddr sa = {0};
+       size_t count_site = 0;
+       size_t count_nonsite;
+       size_t num_dcs;
+       struct sockaddr_storage *dc_addrs = NULL;
        struct tsocket_address **dc_addrs2 = NULL;
        const struct tsocket_address * const *dc_addrs3 = NULL;
        char *result = NULL;
        struct netlogon_samlogon_response **responses = NULL;
        NTSTATUS status;
-       char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "",
-                                       print_canonical_sockaddr_with_port(mem_ctx, pss));
+       bool ok;
+       char *kdc_str = NULL;
+       char *canon_sockaddr = NULL;
+
+       SMB_ASSERT(pss != NULL);
+
+       canon_sockaddr = print_canonical_sockaddr_with_port(frame, pss);
+       if (canon_sockaddr == NULL) {
+               goto out;
+       }
 
+       kdc_str = talloc_asprintf(frame,
+                                 "\t\tkdc = %s\n",
+                                 canon_sockaddr);
        if (kdc_str == NULL) {
-               TALLOC_FREE(frame);
-               return NULL;
+               goto out;
+       }
+
+       ok = sockaddr_storage_to_samba_sockaddr(&sa, pss);
+       if (!ok) {
+               goto out;
        }
 
        /*
@@ -512,15 +462,41 @@ static char *get_kdc_ip_string(char *mem_ctx,
         */
 
        if (sitename) {
-               get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
-               DEBUG(10, ("got %d addresses from site %s search\n", count_site,
-                          sitename));
+               status = get_kdc_list(frame,
+                                       realm,
+                                       sitename,
+                                       &ip_sa_site,
+                                       &count_site);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DBG_ERR("get_kdc_list fail %s\n",
+                               nt_errstr(status));
+                       goto out;
+               }
+               DBG_DEBUG("got %zu addresses from site %s search\n",
+                       count_site,
+                       sitename);
        }
 
        /* Get all KDC's. */
 
-       get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
-       DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite));
+       status = get_kdc_list(frame,
+                                       realm,
+                                       NULL,
+                                       &ip_sa_nonsite,
+                                       &count_nonsite);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("get_kdc_list (site-less) fail %s\n",
+                       nt_errstr(status));
+               goto out;
+       }
+       DBG_DEBUG("got %zu addresses from site-less search\n", count_nonsite);
+
+       if (count_site + count_nonsite < count_site) {
+               /* Wrap check. */
+               DBG_ERR("get_kdc_list_talloc (site-less) fail wrap error\n");
+               goto out;
+       }
+
 
        dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
                                count_site + count_nonsite);
@@ -531,31 +507,32 @@ static char *get_kdc_ip_string(char *mem_ctx,
        num_dcs = 0;
 
        for (i = 0; i < count_site; i++) {
-               if (!sockaddr_equal(
-                       (const struct sockaddr *)pss,
-                       (const struct sockaddr *)&ip_srv_site[i].ss)) {
+               if (!sockaddr_equal(&sa.u.sa, &ip_sa_site[i].u.sa)) {
                        add_sockaddr_unique(dc_addrs, &num_dcs,
-                                           &ip_srv_site[i].ss);
+                                           &ip_sa_site[i].u.ss);
                }
        }
 
        for (i = 0; i < count_nonsite; i++) {
-               if (!sockaddr_equal(
-                       (const struct sockaddr *)pss,
-                       (const struct sockaddr *)&ip_srv_nonsite[i].ss)) {
+               if (!sockaddr_equal(&sa.u.sa, &ip_sa_nonsite[i].u.sa)) {
                        add_sockaddr_unique(dc_addrs, &num_dcs,
-                                           &ip_srv_nonsite[i].ss);
+                                           &ip_sa_nonsite[i].u.ss);
                }
        }
 
-       dc_addrs2 = talloc_zero_array(talloc_tos(),
-                                     struct tsocket_address *,
-                                     num_dcs);
-
-       DEBUG(10, ("%d additional KDCs to test\n", num_dcs));
+       DBG_DEBUG("%zu additional KDCs to test\n", num_dcs);
        if (num_dcs == 0) {
+               /*
+                * We do not have additional KDCs, but we have the one passed
+                * in via `pss`. So just use that one and leave.
+                */
+               result = talloc_move(mem_ctx, &kdc_str);
                goto out;
        }
+
+       dc_addrs2 = talloc_zero_array(talloc_tos(),
+                                     struct tsocket_address *,
+                                     num_dcs);
        if (dc_addrs2 == NULL) {
                goto out;
        }
@@ -601,22 +578,25 @@ static char *get_kdc_ip_string(char *mem_ctx,
                }
 
                /* Append to the string - inefficient but not done often. */
-               new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n",
-                                             kdc_str,
-                                             print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
+               new_kdc_str = talloc_asprintf_append(
+                               kdc_str,
+                               "\t\tkdc = %s\n",
+                               print_canonical_sockaddr_with_port(
+                                       mem_ctx, &dc_addrs[i]));
                if (new_kdc_str == NULL) {
                        goto out;
                }
-               TALLOC_FREE(kdc_str);
                kdc_str = new_kdc_str;
        }
 
+       result = talloc_move(mem_ctx, &kdc_str);
 out:
-       DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str));
+       if (result != NULL) {
+               DBG_DEBUG("Returning\n%s\n", result);
+       } else {
+               DBG_NOTICE("Failed to get KDC ip address\n");
+       }
 
-       result = kdc_str;
-       SAFE_FREE(ip_srv_site);
-       SAFE_FREE(ip_srv_nonsite);
        TALLOC_FREE(frame);
        return result;
 }
@@ -642,25 +622,22 @@ static char *get_enctypes(TALLOC_CTX *mem_ctx)
 
        if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
            lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
-#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
                aes_enctypes = talloc_asprintf_append(
                    aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
                if (aes_enctypes == NULL) {
                        goto done;
                }
-#endif
-#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
                aes_enctypes = talloc_asprintf_append(
                    aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
                if (aes_enctypes == NULL) {
                        goto done;
                }
-#endif
        }
 
-       if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
-           lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
-               legacy_enctypes = "RC4-HMAC DES-CBC-CRC DES-CBC-MD5";
+       if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_ALLOWED &&
+           (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
+            lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY)) {
+               legacy_enctypes = "RC4-HMAC";
        }
 
        enctypes =
@@ -688,7 +665,7 @@ static char *get_enctypes(TALLOC_CTX *mem_ctx)
 
        if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
            lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
-               legacy_enctypes = "arcfour-hmac-md5 des-cbc-crc des-cbc-md5";
+               legacy_enctypes = "arcfour-hmac-md5";
        }
 
        enctypes = talloc_asprintf(mem_ctx, "\tdefault_etypes = %s %s\n",
@@ -731,7 +708,7 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
                return false;
        }
 
-       dname = lock_path("smb_krb5");
+       dname = lock_path(talloc_tos(), "smb_krb5");
        if (!dname) {
                return false;
        }
@@ -742,7 +719,7 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
                goto done;
        }
 
-       tmpname = lock_path("smb_tmp_krb5.XXXXXX");
+       tmpname = lock_path(talloc_tos(), "smb_tmp_krb5.XXXXXX");
        if (!tmpname) {
                goto done;
        }
@@ -776,18 +753,30 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
        }
 #endif
 
+       /*
+        * We are setting 'dns_lookup_kdc' to true, because we want to lookup
+        * KDCs which are not configured via DNS SRV records, eg. if we do:
+        *
+        *     net ads join -Uadmin@otherdomain
+        */
        file_contents =
            talloc_asprintf(fname,
-                           "[libdefaults]\n\tdefault_realm = %s\n"
+                           "[libdefaults]\n"
+                           "\tdefault_realm = %s\n"
                            "%s"
-                           "\tdns_lookup_realm = false\n\n"
+                           "\tdns_lookup_realm = false\n"
+                           "\tdns_lookup_kdc = true\n\n"
                            "[realms]\n\t%s = {\n"
                            "%s\t}\n"
+                           "\t%s = {\n"
+                           "%s\t}\n"
                            "%s\n",
                            realm_upper,
                            enctypes,
                            realm_upper,
                            kdc_ip_string,
+                           domain,
+                           kdc_ip_string,
                            include_system_krb5);
 
        if (!file_contents) {
@@ -800,9 +789,9 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
        fd = mkstemp(tmpname);
        umask(mask);
        if (fd == -1) {
-               DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
-                       " for file %s. Errno %s\n",
-                       tmpname, strerror(errno) ));
+               DBG_ERR("mkstemp failed, for file %s. Errno %s\n",
+                       tmpname,
+                       strerror(errno));
                goto done;
        }
 
@@ -839,9 +828,8 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
                goto done;
        }
 
-       DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
-               "file %s with realm %s KDC list = %s\n",
-               fname, realm_upper, kdc_ip_string));
+       DBG_INFO("wrote file %s with realm %s KDC list:\n%s\n",
+                fname, realm_upper, kdc_ip_string);
 
        /* Set the environment variable to this file. */
        setenv("KRB5_CONFIG", fname, 1);
@@ -892,7 +880,7 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
                                goto done; /* Not a fatal error. */
                        }
 
-                       /* Yes, this is a race conditon... too bad. */
+                       /* Yes, this is a race condition... too bad. */
                        if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
                                DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
                                        "of %s to %s failed. Errno %s\n",