Update: Kerberos Ticket Forwarding Patch/Update [3.2]

Jeremy Allison jra at samba.org
Fri Aug 1 19:44:47 GMT 2008


On Fri, Aug 01, 2008 at 03:27:03PM -0400, Derrick Schommer wrote:
> Okay, I was going to ask about the structure, and if it was "cool" to use "magic numbers" in order to get the size right. 

Actually I'm in the process of rewriting this patch, as 
it's nearly "close enough" :-).

Here's what I have so far. Not quite finished, but if
you're going to rewrite it I thought you might was well
start with what I'd do to it anyway. I added several
checks for return calls that were missing and re-arranged
the termination logic to come first, which is what
we prefer.

NB. You're using a non-portable krb5 interface
krb5_mk_1cred(). As far as I can tell this is not
defined as an external entry point. We do that in
other places, but we have to create wrappers for
other kinds of krb5 (Heimdal etc.).

If you can finish this up I'd appreciate it.
Anyone got any good ideas on what to do about
krb5_mk_1cred() ?

Jeremy
-------------- next part --------------
diff --git a/source/configure.in b/source/configure.in
index 9a230de..e1c0776 100644
--- a/source/configure.in
+++ b/source/configure.in
@@ -3367,6 +3367,7 @@ if test x"$with_ads_support" != x"no"; then
   AC_CHECK_FUNC_EXT(krb5_get_init_creds_opt_free, $KRB5_LIBS)
   AC_CHECK_FUNC_EXT(krb5_get_init_creds_opt_get_error, $KRB5_LIBS)
   AC_CHECK_FUNC_EXT(krb5_enctype_to_string, $KRB5_LIBS)
+  AC_CHECK_FUNC_EXT(krb5_auth_con_set_req_cksumtype, $KRB5_LIBS)
 
   LIBS="$KRB5_LIBS $LIBS"
 
diff --git a/source/libsmb/clifsinfo.c b/source/libsmb/clifsinfo.c
index 0005c39..5e73b61 100644
--- a/source/libsmb/clifsinfo.c
+++ b/source/libsmb/clifsinfo.c
@@ -528,7 +528,7 @@ static NTSTATUS make_cli_gss_blob(struct smb_trans_enc_state *es,
 				&es->s.gss_state->gss_ctx,
 				srv_name,
 				GSS_C_NO_OID, /* default OID. */
-				GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+				GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG,
 				GSS_C_INDEFINITE,	/* requested ticket lifetime. */
 				NULL,   /* no channel bindings */
 				p_tok_in,
diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c
index c289740..288c0c8 100644
--- a/source/libsmb/clikrb5.c
+++ b/source/libsmb/clikrb5.c
@@ -37,6 +37,25 @@
 #define KRB5_KEY_DATA(k)	((k)->contents)
 #endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
 
+
+#define GSSAPI_CHECKSUM      0x8003             /* Checksum type value for Kerberos */
+#define GSSAPI_BNDLENGTH     16                 /* Bind Length (rfc-1964 pg.3) */
+
+/*
+ We marshal into a structure that should look like the
+ following (linearized) in LE format.
+
+struct gssChecksum {
+	uint32_t   lgth;                       Number of bytes in the 'Bnd' field (always 16)
+	uint8_t    bnd[GSSAPI_BNDLENGTH];      16-byte Bnd field.
+	uint32_t   flags;                      Context-establishment flags.
+	uint16_t   dlgOpt;                     Delegation options
+	uint16_t   dlgth;                      Length of Deleg field buffer.
+	uint8_t    deleg[];                    Deleg field buffer ( one or more bytes of GSS-API data)
+};
+*/
+#define GSSAPI_CHECKSUM_SIZE (12+GSSAPI_BNDLENGTH)
+
 /**************************************************************
  Wrappers around kerberos string functions that convert from
  utf8 -> unix charset and vica versa.
@@ -636,6 +655,8 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
 	bool creds_ready = False;
 	int i = 0, maxtries = 3;
 	
+	ZERO_STRUCT(in_data);
+
 	retval = smb_krb5_parse_name(context, principal, &server);
 	if (retval) {
 		DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
@@ -691,14 +712,66 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
 		*expire_time = (time_t)credsp->times.endtime;
 	}
 
-	in_data.length = 0;
+	/* Fetch a forwarded TGT from the KDC so that we can hand off a 2nd ticket
+	 as part of the kerberos exchange. */
+	if( credsp->ticket_flags & TKT_FLG_OK_AS_DELEGATE ) {
+		DEBUG( 3, ("ads_krb5_mk_req: server marked as OK to delegate to, building forwardable TGT\n")  );
+
+		if( *auth_context == NULL ) {
+			/* Allocate if it has not yet been allocated. */
+			retval = krb5_auth_con_init( context, auth_context );
+			if (retval) {
+				DEBUG(1,("ads_krb5_mk_req: krb5_auth_con_init failed (%s)\n",
+					error_message(ret)));
+				goto cleanup_creds;
+			}
+		}
+
+		retval = krb5_auth_con_setuseruserkey( context, *auth_context, &credsp->keyblock );
+		if (retval) {
+			DEBUG(1,("ads_krb5_mk_req: krb5_auth_con_setuseruserkey failed (%s)\n",
+				error_message(ret)));
+			goto cleanup_creds;
+		}
+
+		/* Must use a subkey for forwarded tickets. */
+		retval = krb5_auth_con_setflags( context, *auth_context, KRB5_AUTH_CONTEXT_USE_SUBKEY);
+		if (retval) {
+			DEBUG(1,("ads_krb5_mk_req: krb5_auth_con_setflags failed (%s)\n",
+				error_message(ret)));
+			goto cleanup_creds;
+		}
+
+		retval = ads_krb5_get_fwd_ticket( context,
+						auth_context,
+						credsp,
+						ccache,
+						&in_data );
+		if (retval) {
+			DEBUG( 1, ("ads_krb5_get_fwd_ticket failed (%s)\n", error_message( retval ) ) );
+			goto cleanup_creds;
+		}
+		/* We need to do this in order to allow our GSS-API: */
+		retval = krb5_auth_con_set_req_cksumtype( context, *auth_context, GSSAPI_CHECKSUM );
+		if (retval) {
+			DEBUG( 1, ("krb5_auth_con_set_req_cksumtype failed (%s)\n",
+				error_message( retval ) ) );
+			goto cleanup_creds;
+		}
+	}
+
 	retval = krb5_mk_req_extended(context, auth_context, ap_req_options, 
 				      &in_data, credsp, outbuf);
 	if (retval) {
 		DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n", 
 			 error_message(retval)));
 	}
-	
+
+	if (in_data.data) {
+		free( in_data.data );
+		in_data.length = 0;
+	}
+
 	krb5_free_creds(context, credsp);
 
 cleanup_creds:
@@ -1704,6 +1777,147 @@ done:
  	return ret;
 }
 
+
+
+/**************************************************************
+Routine: ads_krb5_get_fwd_ticket
+ Description:
+    When a service ticket is flagged as trusted
+    for delegation we should provide a forwardable
+    ticket so that the remote host can act on our
+    behalf.  This is done by taking the 2nd forwardable
+    TGT and storing it in the GSS-API authenticator
+    "checksum".  This routine will populate
+    the krb5_data authenticator with this TGT.
+ Parameters:
+    krb5_context context: The kerberos context for this authentication.
+    krb5_auth_context:    The authentication context.
+    krb5_creds *credsp:   The ticket credentials (AS-REP).
+    krb5_ccache ccache:   The credentials cache.
+    krb5_data &authenticator: The checksum field that will store the TGT, and
+     authenticator.data must be freed by the caller.
+
+ Returns:
+    krb5_error_code: 0 if no errors, otherwise set.
+**************************************************************/
+ krb5_error_code ads_krb5_get_fwd_ticket( krb5_context context,
+					 krb5_auth_context *auth_context,
+					 krb5_creds *credsp,
+					 krb5_ccache ccache,
+					 krb5_data *authenticator)
+{
+	krb5_data fwdData;
+    	krb5_creds **inputCreds = NULL;
+	krb5_error_code retval = 0;
+    	krb5_data *pKrbCred  = NULL;
+	char *pChksum = NULL;
+	char *p = NULL;
+
+	ZERO_STRUCT(fwdData);
+	retval = krb5_fwd_tgt_creds(context,/* Krb5 context [in] */
+				*auth_context,  /* Authentication context [in] */
+				KRB5_TGS_NAME,  /* Ticket service name ("krbtgt") [in] */
+				credsp->client, /* Client principal for the tgt [in] */
+				credsp->server, /* Server principal for the tgt [in] */
+				ccache,         /* Credential cache to use for storage [in] */
+				1,              /* Turn on for "Forwardable ticket" [in] */
+				&fwdData );     /* Resulting response [out] */
+
+	if (retval) {
+		DEBUG(1,("ads_krb5_get_fwd_ticket: krb5_fwd_tgt_creds failed (%s)\n", 
+			error_message(retval)));
+		return retval;
+	}
+
+    	/* Read the forward data response and extract a credentials block. */
+    	retval = krb5_rd_cred( context, *auth_context, &fwdData, &inputCreds, NULL );
+
+    	/* Remove that input data, we never needed it anyway. */
+    	if( fwdData.length > 0 ) {
+      		krb5_free_data_contents( context, &fwdData );
+    	}
+
+	if (retval) {
+		DEBUG(1,("ads_krb5_get_fwd_ticket: krb5_rd_cred failed (%s)\n",
+       					error_message(retval)));
+		return retval;
+	}
+
+	/* The mk_1cred will be a single credential ticket that will contain all the
+	   informatin needed to hand to a remote host so they can work on behalf of
+	   us (power of attorney I believe its called).  The mk_1cred will build
+	   what is known as a KRB_CRED structure, or an ASN.1 APPLICATION 22 message:
+
+		RFC-1510 page 63:
+			KRB-CRED         ::= [APPLICATION 22]   SEQUENCE {
+				pvno[0]                INTEGER,
+				msg-type[1]            INTEGER, -- KRB_CRED
+				tickets[2]             SEQUENCE OF Ticket,
+				enc-part[3]            EncryptedData
+			}
+
+	  That will be represented here:
+	*/
+
+	retval = krb5_mk_1cred(context,
+				*auth_context,
+				*inputCreds,    /* INPUT (this is what we're using as a source) */
+				&pKrbCred,      /* OUTPUT (our resulting KRB_CRED structure) */
+				NULL);
+
+	if (retval) {
+		DEBUG(1,("ads_krb5_get_fwd_ticket: krb5_mk_1cred failed (%s)\n", 
+		 					error_message(retval)));
+		return retval;
+	}
+
+	/* We're going to allocate a gssChecksum structure with a little
+	   extra data the length of the kerberos credentials length 
+	   (APPLICATION 22) so that we can pack it on the end of the structure. */
+
+	pChksum	= SMB_MALLOC(GSSAPI_CHECKSUM_SIZE + pKrbCred->length );
+	if (!pChksum) {
+	}
+
+	p = pChksum;
+
+	SIVAL( p, 0, GSSAPI_BNDLENGTH );
+	p += 4;
+
+	/* Zero out the bindings fields */
+	memset( p, 0x0, GSSAPI_BNDLENGTH );
+	p += GSSAPI_BNDLENGTH;
+
+	SIVAL( p, 0, GSS_C_DELEG_FLAG );
+	p += 4;
+	SSVAL( p, 0, 1 );
+	p += 2;
+	SSVAL( p, 0, pKrbCred->length );
+	p += 2;
+
+	/* Migrate the kerberos KRB_CRED data to the checksum delegation */
+	memcpy( p, pKrbCred->data, pKrbCred->length );
+	p += pKrbCred->length;
+
+	/* We need to do this in order to allow our GSS-API  */
+	krb5_auth_con_set_req_cksumtype( context, *auth_context, GSSAPI_CHECKSUM );
+
+	/* We now have a service ticket, now turn it into an AP-REQ. */
+	authenticator->length = ntohs( pKrbCred->length + sizeof( struct gssChecksum ) );
+
+	/* Caller should call free() when they're done with this. */
+	authenticator->data = (char *)pChksum;
+
+	if( pKrbCred->length > 0 ) {
+		krb5_free_data( context, pKrbCred );
+	}
+
+	/* This free's the triple pointer mess. */
+	krb5_free_tgt_creds( context, inputCreds );
+
+	return retval;
+}
+
 #else /* HAVE_KRB5 */
  /* this saves a few linking headaches */
  int cli_krb5_get_ticket(const char *principal, time_t time_offset, 
diff --git a/source/utils/smbcontrol.c b/source/utils/smbcontrol.c
index db2eefe..3075d6d 100644
--- a/source/utils/smbcontrol.c
+++ b/source/utils/smbcontrol.c
@@ -1244,7 +1244,7 @@ static struct server_id parse_dest(const char *dest)
 
 	/* Zero is a special return value for broadcast smbd */
 
-	if (strequal(dest, "smbd")) {
+	if (strequal(dest, "all")) {
 		return interpret_pid(MSG_BROADCAST_PID_STR);
 	}
 


More information about the samba-technical mailing list