Update: Kerberos Ticket Forwarding Patch/Update [3.2]
Jeremy Allison
jra at samba.org
Fri Aug 1 20:29:46 GMT 2008
On Fri, Aug 01, 2008 at 03:49:57PM -0400, Derrick Schommer wrote:
> The latest one I just sent (passed in transmission) removes the struct in total. It's been awhile, I didn't know the krb5_mk_1cred was non-portable though. Hmm..
>
> I also saw your use of the SMB_MALLOC, didn't know you had that :) The code I wrote came out of a in-house CIFS client I wrote a few years ago for internal testing, it only had to run in this one environment, I tried to port it as cleanly as possible but I see I've been pretty unsuccessful :-)
Ok, here's the finished version. Can you check that
it works in your environment please ?
The only thing left to do is decide how to cope
with the krb5_mk_1cred() call...
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..8479ca1 100644
--- a/source/libsmb/clikrb5.c
+++ b/source/libsmb/clikrb5.c
@@ -37,6 +37,31 @@
#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)
+
+static 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);
+
/**************************************************************
Wrappers around kerberos string functions that convert from
utf8 -> unix charset and vica versa.
@@ -636,6 +661,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 +718,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(retval)));
+ 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(retval)));
+ 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(retval)));
+ 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 +1783,167 @@ 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.
+**************************************************************/
+
+static 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);
+ ZERO_STRUCTP(authenticator);
+
+ retval = krb5_fwd_tgt_creds(context,/* Krb5 context [in] */
+ *auth_context, /* Authentication context [in] */
+ CONST_DISCARD(char *, 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)));
+ goto out;
+ }
+
+ /* 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)));
+ goto out;
+ }
+
+ /* The mk_1cred will be a single credential ticket that will contain all the
+ information 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;
+ }
+
+ /* Paranoia check for integer wrap. */
+ if ((unsigned int)GSSAPI_CHECKSUM_SIZE + (unsigned int)pKrbCred->length <
+ (unsigned int)GSSAPI_CHECKSUM_SIZE) {
+ retval = EINVAL;
+ goto out;
+ }
+
+ /* 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) {
+ retval = ENOMEM;
+ goto out;
+ }
+
+ 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 */
+ retval = krb5_auth_con_set_req_cksumtype( context, *auth_context, GSSAPI_CHECKSUM );
+ if (retval) {
+ goto out;
+ }
+
+ /* We now have a service ticket, now turn it into an AP-REQ. */
+ authenticator->length = ntohs(pKrbCred->length + GSSAPI_CHECKSUM_SIZE);
+
+ /* Caller should call free() when they're done with this. */
+ authenticator->data = (char *)pChksum;
+
+ out:
+
+ if (pKrbCred && (pKrbCred->length > 0)) {
+ krb5_free_data( context, pKrbCred );
+ }
+
+ if (inputCreds) {
+ /* 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,
More information about the samba-technical
mailing list