summaryrefslogtreecommitdiff
path: root/source3/libsmb/clikrb5.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2010-07-23 10:54:46 -0700
committerJeremy Allison <jra@samba.org>2010-07-23 10:54:46 -0700
commit5912206606babc178aa1e3c1a3be853eba808323 (patch)
tree74c96a3e4157000c70cfa3dbd56f54ac0a0638de /source3/libsmb/clikrb5.c
parentc75106fd3ab3715af190dbbdeda9809a019edaac (diff)
downloadsamba-5912206606babc178aa1e3c1a3be853eba808323.tar.gz
samba-5912206606babc178aa1e3c1a3be853eba808323.tar.bz2
samba-5912206606babc178aa1e3c1a3be853eba808323.zip
Fix bug 7583 - Smbclient fails to kerberos connect to a Alfresco JLAN CIFS Server
Correctly calculate the gssapi channel binding checkum. Jeremy Signed off by: simo <idra@samba.org>
Diffstat (limited to 'source3/libsmb/clikrb5.c')
-rw-r--r--source3/libsmb/clikrb5.c303
1 files changed, 151 insertions, 152 deletions
diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c
index 68b45d8908..fb2fdba86d 100644
--- a/source3/libsmb/clikrb5.c
+++ b/source3/libsmb/clikrb5.c
@@ -35,14 +35,16 @@
#define GSSAPI_CHECKSUM 0x8003 /* Checksum type value for Kerberos */
#define GSSAPI_BNDLENGTH 16 /* Bind Length (rfc-1964 pg.3) */
-#define GSSAPI_CHECKSUM_SIZE (12+GSSAPI_BNDLENGTH)
-
-#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_FWD_TGT_CREDS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY)
-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);
+#define GSSAPI_CHECKSUM_SIZE (4+GSSAPI_BNDLENGTH+4) /* Length of bind length,
+ bind field, flags field. */
+
+/* MIT krb5 1.7beta3 (in Ubuntu Karmic) is missing the prototype,
+ but still has the symbol */
+#if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE
+krb5_error_code krb5_auth_con_set_req_cksumtype(
+ krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_cksumtype cksumtype);
#endif
/**************************************************************
@@ -652,6 +654,92 @@ static bool ads_cleanup_expired_creds(krb5_context context,
return True;
}
+/* Allocate and setup the auth context into the state we need. */
+
+static krb5_error_code setup_auth_context(krb5_context context,
+ krb5_auth_context *auth_context)
+{
+ krb5_error_code retval;
+
+ retval = krb5_auth_con_init(context, auth_context );
+ if (retval) {
+ DEBUG(1,("krb5_auth_con_init failed (%s)\n",
+ error_message(retval)));
+ return retval;
+ }
+
+ /* Ensure this is an addressless ticket. */
+ retval = krb5_auth_con_setaddrs(context, *auth_context, NULL, NULL);
+ if (retval) {
+ DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n",
+ error_message(retval)));
+ }
+
+ return retval;
+}
+
+static krb5_error_code create_gss_checksum(krb5_data *in_data, /* [inout] */
+ uint32_t gss_flags)
+{
+ unsigned int orig_length = in_data->length;
+ unsigned int base_cksum_size = GSSAPI_CHECKSUM_SIZE;
+ char *gss_cksum = NULL;
+
+ if (orig_length) {
+ /* Extra length field for delgated ticket. */
+ base_cksum_size += 4;
+ }
+
+ if ((unsigned int)base_cksum_size + orig_length <
+ (unsigned int)base_cksum_size) {
+ return EINVAL;
+ }
+
+ gss_cksum = (char *)SMB_MALLOC(base_cksum_size + orig_length);
+ if (gss_cksum == NULL) {
+ return ENOMEM;
+ }
+
+ memset(gss_cksum, '\0', base_cksum_size + orig_length);
+ SIVAL(gss_cksum, 0, GSSAPI_BNDLENGTH);
+
+ /* Precalculated MD5sum of NULL channel bindings (20 bytes) */
+ /* Channel bindings are: (all ints encoded as little endian)
+
+ [4 bytes] initiator_addrtype (255 for null bindings)
+ [4 bytes] initiator_address length
+ [n bytes] .. initiator_address data - not present
+ in null bindings.
+ [4 bytes] acceptor_addrtype (255 for null bindings)
+ [4 bytes] acceptor_address length
+ [n bytes] .. acceptor_address data - not present
+ in null bindings.
+ [4 bytes] application_data length
+ [n bytes] .. application_ data - not present
+ in null bindings.
+ MD5 of this is ""\x14\x8f\x0c\xf7\xb1u\xdey*J\x9a%\xdfV\xc5\x18"
+ */
+
+ memcpy(&gss_cksum[4],
+ "\x14\x8f\x0c\xf7\xb1u\xdey*J\x9a%\xdfV\xc5\x18",
+ GSSAPI_BNDLENGTH);
+
+ SIVAL(gss_cksum, 20, gss_flags);
+
+ if (orig_length) {
+ SSVAL(gss_cksum, 24, 1); /* The Delegation Option identifier */
+ SSVAL(gss_cksum, 26, orig_length);
+ /* Copy the kerberos KRB_CRED data */
+ memcpy(gss_cksum + 28, in_data->data, orig_length);
+ free(in_data->data);
+ in_data->data = NULL;
+ in_data->length = 0;
+ }
+ in_data->data = gss_cksum;
+ in_data->length = base_cksum_size + orig_length;
+ return 0;
+}
+
/*
we can't use krb5_mk_req because w2k wants the service to be in a particular format
*/
@@ -672,7 +760,8 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
krb5_data in_data;
bool creds_ready = False;
int i = 0, maxtries = 3;
-
+ uint32_t gss_flags = 0;
+
ZERO_STRUCT(in_data);
retval = smb_krb5_parse_name(context, principal, &server);
@@ -742,45 +831,51 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
*expire_time = (time_t)credsp->times.endtime;
}
-#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_FWD_TGT_CREDS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY)
+ /* Allocate the auth_context. */
+ retval = setup_auth_context(context, auth_context);
+ if (retval) {
+ DEBUG(1,("setup_auth_context failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_creds;
+ }
+
+#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_FWD_TGT_CREDS) && defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY)
if( credsp->ticket_flags & TKT_FLG_OK_AS_DELEGATE ) {
/* Fetch a forwarded TGT from the KDC so that we can hand off a 2nd ticket
as part of the kerberos exchange. */
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 );
+ 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",
+ DEBUG(1,("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);
+ 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",
+ DEBUG(1,("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 );
+ 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] */
+ &in_data ); /* Resulting response [out] */
+
if (retval) {
- DEBUG( 3, ("ads_krb5_get_fwd_ticket failed (%s)\n",
+ DEBUG( 3, ("krb5_fwd_tgt_creds failed (%s)\n",
error_message( retval ) ) );
/*
@@ -795,10 +890,35 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
}
krb5_auth_con_free(context, *auth_context);
*auth_context = NULL;
+ retval = setup_auth_context(context, auth_context);
+ if (retval) {
+ DEBUG(1,("setup_auth_context failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_creds;
+ }
+ } else {
+ /* We got a delegated ticket. */
+ gss_flags |= GSS_C_DELEG_FLAG;
}
}
#endif
+ /* Frees and reallocates in_data into a GSS checksum blob. */
+ retval = create_gss_checksum(&in_data, gss_flags);
+ if (retval) {
+ goto cleanup_data;
+ }
+
+#if defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
+ /* We always want GSS-checksum types. */
+ 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_data;
+ }
+#endif
+
retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
&in_data, credsp, outbuf);
if (retval) {
@@ -806,6 +926,7 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
error_message(retval)));
}
+cleanup_data:
if (in_data.data) {
free( in_data.data );
in_data.length = 0;
@@ -1864,128 +1985,6 @@ krb5_error_code smb_krb5_keytab_name(TALLOC_CTX *mem_ctx,
return ret;
}
-#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_FWD_TGT_CREDS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY)
-/**************************************************************
-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_error_code retval = 0;
- char *pChksum = NULL;
- char *p = NULL;
-
-/* MIT krb5 1.7beta3 (in Ubuntu Karmic) is missing the prototype,
- but still has the symbol */
-#if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE
-krb5_error_code krb5_auth_con_set_req_cksumtype(
- krb5_context context,
- krb5_auth_context auth_context,
- krb5_cksumtype cksumtype);
-#endif
-
- 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;
- }
-
- if ((unsigned int)GSSAPI_CHECKSUM_SIZE + (unsigned int)fwdData.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 = (char *)SMB_MALLOC(GSSAPI_CHECKSUM_SIZE + fwdData.length );
- if (!pChksum) {
- retval = ENOMEM;
- goto out;
- }
-
- p = pChksum;
-
- SIVAL(p, 0, GSSAPI_BNDLENGTH);
- p += 4;
-
- /* Zero out the bindings fields */
- memset(p, '\0', GSSAPI_BNDLENGTH );
- p += GSSAPI_BNDLENGTH;
-
- SIVAL(p, 0, GSS_C_DELEG_FLAG );
- p += 4;
- SSVAL(p, 0, 1 );
- p += 2;
- SSVAL(p, 0, fwdData.length );
- p += 2;
-
- /* Migrate the kerberos KRB_CRED data to the checksum delegation */
- memcpy(p, fwdData.data, fwdData.length );
- p += fwdData.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 = fwdData.length + GSSAPI_CHECKSUM_SIZE;
-
- /* Caller should call free() when they're done with this. */
- authenticator->data = (char *)pChksum;
-
- out:
-
- /* Remove that input data, we never needed it anyway. */
- if (fwdData.length > 0) {
- krb5_free_data_contents( context, &fwdData );
- }
-
- return retval;
-}
-#endif
-
#if defined(HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE) && \
defined(HAVE_KRB5_GET_CREDS_OPT_ALLOC) && \
defined(HAVE_KRB5_GET_CREDS)