Fix bug #7079 - cliconnect gets realm wrong with trusted domains.
authorJeremy Allison <jra@samba.org>
Sun, 31 Jan 2010 03:24:28 +0000 (19:24 -0800)
committerJeremy Allison <jra@samba.org>
Sun, 31 Jan 2010 03:24:28 +0000 (19:24 -0800)
Passing NULL as dest_realm for cli_session_setup_spnego() was
always using our own realm (as for a NetBIOS name). Change this
to look for the mapped realm using krb5_get_host_realm() if
the destination machine name is a DNS name (contains a '.').
Could get fancier with DNS name detection (length, etc.) but
this will do for now.

Jeremy.

source3/configure.in
source3/include/proto.h
source3/libads/kerberos.c
source3/libsmb/cliconnect.c

index 7740b3a7fcb8fccca79367a485dc3425aa7cac5a..f64110b9d4899e6d10cd34da1cc7a3bc47ae9472 100644 (file)
@@ -3660,6 +3660,9 @@ if test x"$with_ads_support" != x"no"; then
   AC_CHECK_FUNC_EXT(krb5_get_creds_opt_set_impersonate, $KRB5_LIBS)
   AC_CHECK_FUNC_EXT(krb5_get_creds, $KRB5_LIBS)
   AC_CHECK_FUNC_EXT(krb5_get_credentials_for_user, $KRB5_LIBS)
+  AC_CHECK_FUNC_EXT(krb5_get_host_realm, $KRB5_LIBS)
+  AC_CHECK_FUNC_EXT(krb5_free_host_realm, $KRB5_LIBS)
+
   # MIT krb5 1.8 does not expose this call (yet)
   AC_CHECK_DECLS(krb5_get_credentials_for_user, [], [], [#include <krb5.h>])
 
@@ -4002,6 +4005,18 @@ if test x"$with_ads_support" != x"no"; then
                [Whether the WRFILE:-keytab is supported])
   fi
 
+  AC_CACHE_CHECK([for krb5_realm type],
+                samba_cv_HAVE_KRB5_REALM_TYPE,[
+    AC_TRY_COMPILE([#include <krb5.h>],
+      [krb5_realm realm;],
+      samba_cv_HAVE_KRB5_REALM_TYPE=yes,
+      samba_cv_HAVE_KRB5_REALM_TYPE=no)])
+
+  if test x"$samba_cv_HAVE_KRB5_REALM_TYPE" = x"yes"; then
+    AC_DEFINE(HAVE_KRB5_REALM_TYPE,1,
+               [Whether the type krb5_realm exists])
+  fi
+
   AC_CACHE_CHECK([for krb5_princ_realm returns krb5_realm or krb5_data],
                samba_cv_KRB5_PRINC_REALM_RETURNS_REALM,[
     AC_TRY_COMPILE([#include <krb5.h>],
index f0ccc92c46f54067d1b75601b89ef6a4681a97d4..fa4a40c4350ef389b60bc96d49a4259abf39ca73 100644 (file)
@@ -1795,6 +1795,8 @@ char* kerberos_standard_des_salt( void );
 bool kerberos_secrets_store_des_salt( const char* salt );
 char* kerberos_secrets_fetch_des_salt( void );
 char *kerberos_get_default_realm_from_ccache( void );
+char *kerberos_get_realm_from_hostname(const char *hostname);
+
 bool kerberos_secrets_store_salting_principal(const char *service,
                                              int enctype,
                                              const char *principal);
index af8ea3937053f21d2bd04dd09e51b56c8682d3c6..7fb4ec33e4f8d311f233a9a408213a9cfb67a556 100644 (file)
@@ -525,6 +525,58 @@ char *kerberos_get_default_realm_from_ccache( void )
        return realm;
 }
 
+/************************************************************************
+ Routine to get the realm from a given DNS name. Returns malloc'ed memory.
+ Caller must free() if the return value is not NULL.
+************************************************************************/
+
+char *kerberos_get_realm_from_hostname(const char *hostname)
+{
+#if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM)
+#if defined(HAVE_KRB5_REALM_TYPE)
+       /* Heimdal. */
+       krb5_realm *realm_list = NULL;
+#else
+       /* MIT */
+       char **realm_list = NULL;
+#endif
+       char *realm = NULL;
+       krb5_error_code kerr;
+       krb5_context ctx = NULL;
+
+       initialize_krb5_error_table();
+       if (krb5_init_context(&ctx)) {
+               return NULL;
+       }
+
+       kerr = krb5_get_host_realm(ctx, hostname, &realm_list);
+       if (kerr != 0) {
+               DEBUG(3,("kerberos_get_realm_from_hostname %s: "
+                       "failed %s\n",
+                       hostname ? hostname : "(NULL)",
+                       error_message(kerr) ));
+               goto out;
+       }
+
+       if (realm_list && realm_list[0]) {
+               realm = SMB_STRDUP(realm_list[0]);
+       }
+
+  out:
+
+       if (ctx) {
+               if (realm_list) {
+                       krb5_free_host_realm(ctx, realm_list);
+                       realm_list = NULL;
+               }
+               krb5_free_context(ctx);
+               ctx = NULL;
+       }
+       return realm;
+#else
+       return NULL;
+#endif
+}
 
 /************************************************************************
  Routine to get the salting principal for this service.  This is 
index 31f848cb00b2210a607795ccbb9e2cf9ee39377d..a81cb0683979a7565b72dfacfe0c55af6c00ba5a 100644 (file)
@@ -1287,6 +1287,7 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
 
                        host = strchr_m(cli->desthost, '.');
                        if (host) {
+                               /* We had a '.' in the name. */
                                machine = SMB_STRNDUP(cli->desthost,
                                        host - cli->desthost);
                        } else {
@@ -1300,11 +1301,29 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
                                realm = SMB_STRDUP(dest_realm);
                                strupper_m(realm);
                        } else {
-                               realm = kerberos_get_default_realm_from_ccache();
+                               if (host) {
+                                       /* DNS name. */
+                                       realm = kerberos_get_realm_from_hostname(cli->desthost);
+                               } else {
+                                       /* NetBIOS name - use our realm. */
+                                       realm = kerberos_get_default_realm_from_ccache();
+                               }
                        }
+
                        if (realm && *realm) {
-                               principal = talloc_asprintf(NULL, "%s$@%s",
-                                                       machine, realm);
+                               if (host) {
+                                       /* DNS name. */
+                                       principal = talloc_asprintf(talloc_tos(),
+                                                       "cifs/%s@%s",
+                                                       cli->desthost,
+                                                       realm);
+                               } else {
+                                       /* NetBIOS name, use machine account. */
+                                       principal = talloc_asprintf(talloc_tos(),
+                                                       "%s$@%s",
+                                                       machine,
+                                                       realm);
+                               }
                                if (!principal) {
                                        SAFE_FREE(machine);
                                        SAFE_FREE(realm);