[PATCH] Fix kerberos authentication with Vista

Jeremy Allison jra at samba.org
Sat Dec 15 07:52:11 GMT 2007


On Thu, Dec 13, 2007 at 03:27:30PM +0100, Andreas Schneider wrote:
> Andreas Schneider wrote:
> > 
> > Gerald (Jerry) Carter wrote:
> >> Andreas Schneider wrote:
> >>> Hi List,
> >>> attached is a patch against v3-0-test to fix smbclient's 
> >>> kerberos authentication against a Vista client. It depends
> >>> on 'realm =' to be set in smb.conf. I didn't find a way to
> >>> get the realm another way and I think we shouldn't do a clap
> >>> or dns request here.
> >> Sorry.  That's a broken implementation then.  You can't
> >> assume that every client you connect to will be in the same
> >> domain.
> >>
> > 
> > Two trusted domains MARVIN and ARTHUR, a user MARVIN\anschneider and a share
> > on the machine barteldan:
> > 
> >         Vista Client                               Vista Client
> >   +-----------------------+                      +---------------+
> >   | m: antares            | u tries to access s  | m: barteldan  |
> >   | d: MARVIN             |--------------------->| d: ARTHUR     |
> >   | u: MARVIN\anschneider |                      | s: Share      |
> >   +-----------------------+                      +---------------+
> > 
> > m = machine
> > d = domain
> > u = user
> > s = share
> > 
> > If you try to access the share on barteldan with Vista, it tries to get a
> > ticket for BARTELDAN$@MARVIN.REALM.COM. Then it falls back to user/password
> > authentication.
> > 
> > I think Vista uses the REALM from the TGT, cause it works if you login to
> > barteldan and access a share on antares.
> 
> Next try. This patch behaves the same like Vista now. Bug by bug, feature by
> feature.

Here's a fixed version that fixes the memory leak and
tidies up a few more things. It correctly uses configure
to test for the new krb5 calls you are using. Should apply
to the 3.0.28 code.

Please test and let me know if it works for you.

Jeremy.
-------------- next part --------------
diff --git a/source/configure.in b/source/configure.in
index 91f1582..d9fc21b 100644
--- a/source/configure.in
+++ b/source/configure.in
@@ -3944,6 +3944,30 @@ if test x"$with_ads_support" != x"no"; then
   fi
 
 
+  AC_CACHE_CHECK([for krb5_principal_get_realm],
+                samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM,[
+    AC_TRY_LINK([#include <krb5.h>],
+      [krb5_context ctx = NULL; krb5_principal princ = NULL; const char *str = krb5_principal_get_realm(ctx, princ);],
+      samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM=yes,
+      samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM=no)])
+
+  if test x"$samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM" = x"yes"; then
+    AC_DEFINE(HAVE_KRB5_PRINCIPAL_GET_REALM,1,
+               [Whether the function krb5_principal_get_realm is defined])
+  fi
+
+  AC_CACHE_CHECK([for krb5_princ_realm],
+                samba_cv_HAVE_KRB5_PRINC_REALM,[
+    AC_TRY_LINK([#include <krb5.h>],
+      [krb5_context ctx = NULL; krb5_principal princ = NULL; const char *str = krb5_princ_realm(ctx, princ)->data;],
+      samba_cv_HAVE_KRB5_PRINC_REALM=yes,
+      samba_cv_HAVE_KRB5_PRINC_REALM=no)])
+
+  if test x"$samba_cv_HAVE_KRB5_PRINC_REALM" = x"yes"; then
+    AC_DEFINE(HAVE_KRB5_PRINC_REALM,1,
+               [Whether the macro krb5_princ_realm is defined])
+  fi
+
   #
   #
   # Now the decisions whether we can support krb5
diff --git a/source/libads/kerberos.c b/source/libads/kerberos.c
index c74c98d..6e3063d 100644
--- a/source/libads/kerberos.c
+++ b/source/libads/kerberos.c
@@ -362,6 +362,58 @@ char* kerberos_secrets_fetch_des_salt( void )
 	return salt;
 }
 
+/************************************************************************
+ Routine to get the default realm from the kerberos credentials cache.
+ Caller must free if the return value is not NULL.
+************************************************************************/
+
+char *kerberos_get_default_realm_from_ccache( void )
+{
+	char *realm = NULL;
+	krb5_context ctx = NULL;
+	krb5_ccache cc = NULL;
+	krb5_principal princ = NULL;
+
+	initialize_krb5_error_table();
+	if (krb5_init_context(&ctx)) {
+		return NULL;
+	}
+
+	DEBUG(5,("kerberos_get_default_realm_from_ccache: "
+		"Trying to read krb5 cache: %s\n",
+		krb5_cc_default_name(ctx)));
+	if (krb5_cc_default(ctx, &cc)) {
+		DEBUG(0,("kerberos_get_default_realm_from_ccache: "
+			"failed to read default cache\n"));
+		goto out;
+	}
+	if (krb5_cc_get_principal(ctx, cc, &princ)) {
+		DEBUG(0,("kerberos_get_default_realm_from_ccache: "
+			"failed to get default principal\n"));
+		goto done;
+	}
+
+#if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
+	realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
+#elif defined(HAVE_KRB5_PRINC_REALM)
+	realm = SMB_STRDUP(krb5_princ_realm(ctx, princ)->data);
+#endif
+
+  out:
+
+	if (princ) {
+		krb5_free_principal(ctx, princ);
+	}
+	if (cc) {
+		krb5_cc_close(ctx, cc);
+	}
+	if (ctx) {
+		krb5_free_context(ctx);
+	}
+done:
+	return realm;
+}
+
 
 /************************************************************************
  Routine to get the salting principal for this service.  This is 
diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c
index d458ce2..0f646aa 100644
--- a/source/libsmb/cliconnect.c
+++ b/source/libsmb/cliconnect.c
@@ -40,6 +40,8 @@ static const struct {
 	{-1,NULL}
 };
 
+static const char *star_smbserver_name = "*SMBSERVER";
+
 /**
  * Set the user session key for a connection
  * @param cli The cli structure to add it too
@@ -861,6 +863,32 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
 			}
 		}
 		
+		/* If we get a bad principal, try to guess it if
+		   we have a valid host NetBIOS name.
+		 */
+		if (!is_ipaddress(cli->desthost) &&
+				!strequal(star_smbserver_name, cli->desthost) &&
+				strequal(principal,
+					"not_defined_in_RFC4178 at please_ignore")) {
+			char *realm = NULL;
+			DEBUG(3,("cli_session_setup_spnego: got a "
+				"bad principal, trying to guess ...\n"));
+
+			realm = kerberos_get_default_realm_from_ccache();
+			if (realm && *realm) {
+				SAFE_FREE(principal);
+				if (asprintf(&principal, "%s$@%s",
+						cli->desthost, realm) < 0) {
+					SAFE_FREE(realm);
+					return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+				}
+				DEBUG(3,("cli_session_setup_spnego: guessed "
+					"principal=%s\n",
+					principal ? principal : "<null>"));
+			}
+			SAFE_FREE(realm);
+		}
+
 		rc = cli_session_setup_kerberos(cli, principal, domain);
 		if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
 			SAFE_FREE(principal);
@@ -1412,7 +1440,7 @@ NTSTATUS cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip
 	char *p;
 
 	/* reasonable default hostname */
-	if (!host) host = "*SMBSERVER";
+	if (!host) host = star_smbserver_name;
 
 	fstrcpy(cli->desthost, host);
 
@@ -1527,8 +1555,8 @@ again:
 			*p = 0;
 			goto again;
 		}
-		if (strcmp(called.name, "*SMBSERVER")) {
-			make_nmb_name(&called , "*SMBSERVER", 0x20);
+		if (strcmp(called.name, star_smbserver_name)) {
+			make_nmb_name(&called , star_smbserver_name, 0x20);
 			goto again;
 		}
 		return NT_STATUS_BAD_NETWORK_NAME;
@@ -1652,7 +1680,7 @@ BOOL attempt_netbios_session_request(struct cli_state **ppcli, const char *srcho
 	 */
 
 	if(is_ipaddress(desthost)) {
-		make_nmb_name(&called, "*SMBSERVER", 0x20);
+		make_nmb_name(&called, star_smbserver_name, 0x20);
 	} else {
 		make_nmb_name(&called, desthost, 0x20);
 	}
@@ -1661,7 +1689,7 @@ BOOL attempt_netbios_session_request(struct cli_state **ppcli, const char *srcho
 		NTSTATUS status;
 		struct nmb_name smbservername;
 
-		make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
+		make_nmb_name(&smbservername, star_smbserver_name, 0x20);
 
 		/*
 		 * If the name wasn't *SMBSERVER then


More information about the samba-technical mailing list