svn rev #23843: branches/iakerb/src/ appl/gss-sample/ include/ include/krb5/ ...
ghudson@MIT.EDU
ghudson at MIT.EDU
Mon Mar 29 12:18:20 EDT 2010
http://src.mit.edu/fisheye/changelog/krb5/?cs=23843
Commit By: ghudson
Log Message:
Merge changes from /users/lhoward/iakerb-refonly.
Changed Files:
U branches/iakerb/src/appl/gss-sample/gss-client.c
U branches/iakerb/src/appl/gss-sample/gss-server.c
U branches/iakerb/src/include/k5-int.h
U branches/iakerb/src/include/krb5/krb5.hin
U branches/iakerb/src/lib/gssapi/generic/gssapi_ext.h
U branches/iakerb/src/lib/gssapi/krb5/Makefile.in
U branches/iakerb/src/lib/gssapi/krb5/accept_sec_context.c
U branches/iakerb/src/lib/gssapi/krb5/acquire_cred.c
U branches/iakerb/src/lib/gssapi/krb5/add_cred.c
U branches/iakerb/src/lib/gssapi/krb5/gssapiP_krb5.h
U branches/iakerb/src/lib/gssapi/krb5/gssapi_err_krb5.et
U branches/iakerb/src/lib/gssapi/krb5/gssapi_krb5.c
U branches/iakerb/src/lib/gssapi/krb5/gssapi_krb5.hin
A branches/iakerb/src/lib/gssapi/krb5/iakerb.c
U branches/iakerb/src/lib/gssapi/krb5/init_sec_context.c
U branches/iakerb/src/lib/gssapi/krb5/inq_cred.c
U branches/iakerb/src/lib/gssapi/krb5/inq_names.c
U branches/iakerb/src/lib/gssapi/krb5/rel_cred.c
U branches/iakerb/src/lib/gssapi/krb5/ser_sctx.c
U branches/iakerb/src/lib/gssapi/libgssapi_krb5.exports
U branches/iakerb/src/lib/gssapi/mechglue/Makefile.in
A branches/iakerb/src/lib/gssapi/mechglue/g_acquire_cred_with_pw.c
U branches/iakerb/src/lib/gssapi/mechglue/g_initialize.c
U branches/iakerb/src/lib/gssapi/mechglue/mglueP.h
U branches/iakerb/src/lib/gssapi/spnego/gssapiP_spnego.h
U branches/iakerb/src/lib/gssapi/spnego/spnego_mech.c
U branches/iakerb/src/lib/krb5/asn.1/asn1_k_decode.c
U branches/iakerb/src/lib/krb5/asn.1/asn1_k_decode.h
U branches/iakerb/src/lib/krb5/asn.1/asn1_k_encode.c
U branches/iakerb/src/lib/krb5/asn.1/krb5_decode.c
U branches/iakerb/src/lib/krb5/error_tables/krb5_err.et
U branches/iakerb/src/lib/krb5/krb/Makefile.in
U branches/iakerb/src/lib/krb5/krb/gc_frm_kdc.c
A branches/iakerb/src/lib/krb5/krb/gc_frm_kdc_step.c
U branches/iakerb/src/lib/krb5/krb/int-proto.h
U branches/iakerb/src/lib/krb5/krb/kfree.c
U branches/iakerb/src/lib/krb5/libkrb5.exports
U branches/iakerb/src/tests/asn.1/krb5_decode_leak.c
U branches/iakerb/src/tests/asn.1/krb5_decode_test.c
U branches/iakerb/src/tests/asn.1/krb5_encode_test.c
U branches/iakerb/src/tests/asn.1/ktest.c
U branches/iakerb/src/tests/asn.1/ktest.h
U branches/iakerb/src/tests/asn.1/ktest_equal.c
U branches/iakerb/src/tests/asn.1/ktest_equal.h
U branches/iakerb/src/tests/asn.1/reference_encode.out
U branches/iakerb/src/tests/asn.1/trval_reference.out
Modified: branches/iakerb/src/appl/gss-sample/gss-client.c
===================================================================
--- branches/iakerb/src/appl/gss-sample/gss-client.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/appl/gss-sample/gss-client.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -64,6 +64,8 @@
#endif
#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_ext.h>
#include "gss-misc.h"
static int verbose = 1;
@@ -72,7 +74,7 @@
usage()
{
fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] [-d]\n");
- fprintf(stderr, " [-seq] [-noreplay] [-nomutual]");
+ fprintf(stderr, " [-seq] [-noreplay] [-nomutual] [-user user] [-pass pw]");
#ifdef _WIN32
fprintf(stderr, " [-threads num]");
#endif
@@ -162,6 +164,7 @@
static int
client_establish_context(int s, char *service_name, OM_uint32 gss_flags,
int auth_flag, int v1_format, gss_OID oid,
+ char *username, char *password,
gss_ctx_id_t *gss_context, OM_uint32 *ret_flags)
{
if (auth_flag) {
@@ -169,7 +172,54 @@
gss_name_t target_name;
OM_uint32 maj_stat, min_stat, init_sec_min_stat;
int token_flags;
+ gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
+ gss_name_t gss_username = GSS_C_NO_NAME;
+ gss_OID_set_desc mechs, *mechsp = GSS_C_NO_OID_SET;
+ if (oid != GSS_C_NO_OID) {
+ mechs.elements = oid;
+ mechs.count = 1;
+ mechsp = &mechs;
+ }
+
+ if (username != NULL) {
+ send_tok.value = username;
+ send_tok.length = strlen(username);
+
+ maj_stat = gss_import_name(&min_stat, &send_tok,
+ (gss_OID) gss_nt_user_name,
+ &gss_username);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("parsing client name", maj_stat, min_stat);
+ return -1;
+ }
+ }
+
+ if (password != NULL) {
+ gss_buffer_desc pwbuf;
+
+ pwbuf.value = password;
+ pwbuf.length = strlen(password);
+
+ maj_stat = gss_acquire_cred_with_password(&min_stat,
+ gss_username,
+ &pwbuf, 0,
+ mechsp, GSS_C_INITIATE,
+ &cred, NULL, NULL);
+ } else if (gss_username != GSS_C_NO_NAME) {
+ maj_stat = gss_acquire_cred(&min_stat,
+ gss_username, 0,
+ mechsp, GSS_C_INITIATE,
+ &cred, NULL, NULL);
+ } else
+ maj_stat = GSS_S_COMPLETE;
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("acquiring creds", maj_stat, min_stat);
+ gss_release_name(&min_stat, &gss_username);
+ return -1;
+ }
+ gss_release_name(&min_stat, &gss_username);
+
/*
* Import the name into target_name. Use send_tok to save
* local variable space.
@@ -213,7 +263,7 @@
do {
maj_stat = gss_init_sec_context(&init_sec_min_stat,
- GSS_C_NO_CREDENTIAL, gss_context,
+ cred, gss_context,
target_name, oid, gss_flags, 0,
NULL, /* channel bindings */
token_ptr, NULL, /* mech type */
@@ -260,6 +310,7 @@
printf("\n");
} while (maj_stat == GSS_S_CONTINUE_NEEDED);
+ (void) gss_release_cred(&min_stat, &cred);
(void) gss_release_name(&min_stat, &target_name);
} else {
if (send_token(s, TOKEN_NOOP, empty_token) < 0)
@@ -344,7 +395,7 @@
static int
call_server(host, port, oid, service_name, gss_flags, auth_flag,
wrap_flag, encrypt_flag, mic_flag, v1_format, msg, use_file,
- mcount)
+ mcount, username, password)
char *host;
u_short port;
gss_OID oid;
@@ -355,6 +406,8 @@
char *msg;
int use_file;
int mcount;
+ char *username;
+ char *password;
{
gss_ctx_id_t context;
gss_buffer_desc in_buf, out_buf;
@@ -380,7 +433,8 @@
/* Establish context */
if (client_establish_context(s, service_name, gss_flags, auth_flag,
- v1_format, oid, &context, &ret_flags) < 0) {
+ v1_format, oid, username, password,
+ &context, &ret_flags) < 0) {
(void) close(s);
return -1;
}
@@ -663,13 +717,15 @@
static gss_OID oid = GSS_C_NULL_OID;
static int mcount = 1, ccount = 1;
static int auth_flag, wrap_flag, encrypt_flag, mic_flag, v1_format;
+static char *username = NULL;
+static char *password = NULL;
static void
worker_bee(void *unused)
{
if (call_server(server_host, port, oid, service_name,
gss_flags, auth_flag, wrap_flag, encrypt_flag, mic_flag,
- v1_format, msg, use_file, mcount) < 0)
+ v1_format, msg, use_file, mcount, username, password) < 0)
exit(1);
#ifdef _WIN32
@@ -705,17 +761,33 @@
if (!argc)
usage();
mechanism = *argv;
- }
+ } else if (strcmp(*argv, "-user") == 0) {
+ argc--;
+ argv++;
+ if (!argc)
+ usage();
+ username = *argv;
+ } else if (strcmp(*argv, "-pass") == 0) {
+ argc--;
+ argv++;
+ if (!argc)
+ usage();
+ password = *argv;
+ } else if (strcmp(*argv, "-iakerb") == 0) {
+ mechanism = "{ 1 3 6 1 5 2 5 }";
+ } else if (strcmp(*argv, "-spnego") == 0) {
+ mechanism = "{ 1 3 6 1 5 5 2 }";
+ } else if (strcmp(*argv, "-krb5") == 0) {
+ mechanism = "{ 1 3 5 1 5 2 }";
#ifdef _WIN32
- else if (strcmp(*argv, "-threads") == 0) {
+ } else if (strcmp(*argv, "-threads") == 0) {
argc--;
argv++;
if (!argc)
usage();
max_threads = atoi(*argv);
- }
#endif
- else if (strcmp(*argv, "-d") == 0) {
+ } else if (strcmp(*argv, "-d") == 0) {
gss_flags |= GSS_C_DELEG_FLAG;
} else if (strcmp(*argv, "-seq") == 0) {
gss_flags |= GSS_C_SEQUENCE_FLAG;
Modified: branches/iakerb/src/appl/gss-sample/gss-server.c
===================================================================
--- branches/iakerb/src/appl/gss-sample/gss-server.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/appl/gss-sample/gss-server.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -58,6 +58,7 @@
#include <ctype.h>
#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
#include "gss-misc.h"
#ifdef HAVE_STRING_H
@@ -75,7 +76,8 @@
#endif
fprintf(stderr, "\n");
fprintf(stderr,
- " [-inetd] [-export] [-logfile file] service_name\n");
+ " [-inetd] [-export] [-logfile file] [-keytab keytab]\n"
+ " service_name\n");
exit(1);
}
@@ -690,6 +692,15 @@
exit(1);
}
}
+ } else if (strcmp(*argv, "-keytab") == 0) {
+ argc--;
+ argv++;
+ if (!argc)
+ usage();
+ if (krb5_gss_register_acceptor_identity(*argv)) {
+ fprintf(stderr, "failed to register keytab\n");
+ exit(1);
+ }
} else
break;
argc--;
Modified: branches/iakerb/src/include/k5-int.h
===================================================================
--- branches/iakerb/src/include/k5-int.h 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/include/k5-int.h 2010-03-29 16:18:20 UTC (rev 23843)
@@ -358,6 +358,10 @@
#define KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED 79 /* missing paChecksum in PA-PK-AS-REQ */
#define KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED 80 /* bad digest algorithm in SignedData */
#define KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED 81
+#define KRB_AP_ERR_IAKERB_KDC_NOT_FOUND 85 /* The IAKERB proxy could
+not find a KDC */
+#define KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE 86 /* The KDC did not respond
+to the IAKERB proxy */
/*
* This structure is returned in the e-data field of the KRB-ERROR
@@ -1032,6 +1036,15 @@
krb5_pa_data **method_data;
} krb5_ad_signedpath;
+typedef struct _krb5_iakerb_header {
+ krb5_data target_realm;
+ krb5_data *cookie;
+} krb5_iakerb_header;
+
+typedef struct _krb5_iakerb_finished {
+ krb5_checksum checksum;
+} krb5_iakerb_finished;
+
typedef krb5_error_code
(*krb5_preauth_obtain_proc)(krb5_context, krb5_pa_data *,
krb5_etype_info, krb5_keyblock *,
@@ -1329,6 +1342,10 @@
void KRB5_CALLCONV krb5_free_fast_response(krb5_context, krb5_fast_response *);
void KRB5_CALLCONV krb5_free_ad_kdcissued(krb5_context, krb5_ad_kdcissued *);
void KRB5_CALLCONV krb5_free_ad_signedpath(krb5_context, krb5_ad_signedpath *);
+void KRB5_CALLCONV krb5_free_iakerb_header
+(krb5_context, krb5_iakerb_header *);
+void KRB5_CALLCONV krb5_free_iakerb_finished
+(krb5_context, krb5_iakerb_finished *);
/* #include "krb5/wordsize.h" -- comes in through base-defs.h. */
#include "com_err.h"
@@ -1740,6 +1757,10 @@
krb5_error_code
encode_krb5_pa_fx_fast_reply(const krb5_enc_data *, krb5_data **);
+krb5_error_code encode_krb5_iakerb_header
+(const krb5_iakerb_header *, krb5_data **);
+krb5_error_code encode_krb5_iakerb_finished
+(const krb5_iakerb_finished *, krb5_data **);
krb5_error_code
encode_krb5_fast_response(const krb5_fast_response *, krb5_data **);
@@ -1939,6 +1960,12 @@
krb5_error_code
decode_krb5_ad_signedpath(const krb5_data *, krb5_ad_signedpath **);
+krb5_error_code decode_krb5_iakerb_header
+(const krb5_data *, krb5_iakerb_header **);
+
+krb5_error_code decode_krb5_iakerb_finished
+(const krb5_data *, krb5_iakerb_finished **);
+
struct _krb5_key_data; /* kdb.h */
struct ldap_seqof_key_data {
Modified: branches/iakerb/src/include/krb5/krb5.hin
===================================================================
--- branches/iakerb/src/include/krb5/krb5.hin 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/include/krb5/krb5.hin 2010-03-29 16:18:20 UTC (rev 23843)
@@ -637,6 +637,7 @@
#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY 27 /* XXX note conflict with above */
#define KRB5_KEYUSAGE_AD_SIGNEDPATH -21
+#define KRB5_KEYUSAGE_IAKERB_FINISHED 42
#define KRB5_KEYUSAGE_PA_PKINIT_KX 44
/* define in draft-ietf-krb-wg-preauth-framework*/
#define KRB5_KEYUSAGE_FAST_REQ_CHKSUM 50
@@ -2408,7 +2409,34 @@
krb5_init_creds_get_times(krb5_context context, krb5_init_creds_context ctx,
krb5_ticket_times *times);
+struct _krb5_tkt_creds_context;
+typedef struct _krb5_tkt_creds_context *krb5_tkt_creds_context;
+
krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_init(krb5_context context, krb5_ccache ccache,
+ krb5_creds *creds, int kdcopt, krb5_tkt_creds_context *ctx);
+
+krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_get_creds(krb5_context context, krb5_tkt_creds_context ctx,
+ krb5_creds *creds);
+
+void KRB5_CALLCONV
+krb5_tkt_creds_free(krb5_context context, krb5_tkt_creds_context ctx);
+
+krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_step(krb5_context context, krb5_tkt_creds_context ctx,
+ krb5_data *in, krb5_data *out, krb5_data *realm,
+ unsigned int *flags);
+
+krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_store_creds(krb5_context context, krb5_tkt_creds_context ctx,
+ krb5_ccache ccache);
+
+krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_get_times(krb5_context context, krb5_tkt_creds_context ctx,
+ krb5_ticket_times *times);
+
+krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds,
krb5_principal client, krb5_keytab arg_keytab,
krb5_deltat start_time, char *in_tkt_service,
Modified: branches/iakerb/src/lib/gssapi/generic/gssapi_ext.h
===================================================================
--- branches/iakerb/src/lib/gssapi/generic/gssapi_ext.h 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/generic/gssapi_ext.h 2010-03-29 16:18:20 UTC (rev 23843)
@@ -47,6 +47,33 @@
const char * /*username*/);
#endif
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_with_password(
+ OM_uint32 *, /* minor_status */
+ const gss_name_t, /* desired_name */
+ const gss_buffer_t, /* password */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_with_password(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t,/* input_cred_handle */
+ const gss_name_t, /* desired_name */
+ const gss_OID, /* desired_mech */
+ const gss_buffer_t, /* password */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 *); /* acceptor_time_rec */
+
/*
* GGF extensions
*/
Modified: branches/iakerb/src/lib/gssapi/krb5/Makefile.in
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/Makefile.in 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/Makefile.in 2010-03-29 16:18:20 UTC (rev 23843)
@@ -52,6 +52,7 @@
$(srcdir)/export_sec_context.c \
$(srcdir)/get_tkt_flags.c \
$(srcdir)/gssapi_krb5.c \
+ $(srcdir)/iakerb.c \
$(srcdir)/import_name.c \
$(srcdir)/import_sec_context.c \
$(srcdir)/indicate_mechs.c \
@@ -106,6 +107,7 @@
$(OUTPRE)export_sec_context.$(OBJEXT) \
$(OUTPRE)get_tkt_flags.$(OBJEXT) \
$(OUTPRE)gssapi_krb5.$(OBJEXT) \
+ $(OUTPRE)iakerb.$(OBJEXT) \
$(OUTPRE)import_name.$(OBJEXT) \
$(OUTPRE)import_sec_context.$(OBJEXT) \
$(OUTPRE)indicate_mechs.$(OBJEXT) \
@@ -163,6 +165,7 @@
export_sec_context.o \
get_tkt_flags.o \
gssapi_krb5.o \
+ iakerb.o \
import_name.o \
import_sec_context.o \
indicate_mechs.o \
Modified: branches/iakerb/src/lib/gssapi/krb5/accept_sec_context.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/accept_sec_context.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/accept_sec_context.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -105,7 +105,6 @@
#endif
#include <assert.h>
-
#ifdef CFX_EXERCISE
#define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
#else
@@ -384,12 +383,49 @@
return major_status;
}
+static krb5_error_code
+kg_process_extension(krb5_context context,
+ krb5_auth_context auth_context,
+ int ext_type,
+ krb5_data *ext_data,
+ krb5_gss_ctx_ext_t exts)
+{
+ krb5_error_code code = 0;
+
+ assert(exts != NULL);
+
+ switch (ext_type) {
+ case KRB5_GSS_EXTS_IAKERB_FINISHED:
+ if (exts->iakerb.conv == NULL) {
+ code = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
+ } else {
+ krb5_key key;
+
+ code = krb5_auth_con_getrecvsubkey_k(context, auth_context, &key);
+ if (code != 0)
+ break;
+
+ code = iakerb_verify_finished(context, key, exts->iakerb.conv,
+ ext_data);
+ if (code == 0)
+ exts->iakerb.verified = 1;
+
+ krb5_k_free_key(context, key);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return code;
+}
+
static OM_uint32
kg_accept_krb5(minor_status, context_handle,
verifier_cred_handle, input_token,
input_chan_bindings, src_name, mech_type,
output_token, ret_flags, time_rec,
- delegated_cred_handle)
+ delegated_cred_handle, exts)
OM_uint32 *minor_status;
gss_ctx_id_t *context_handle;
gss_cred_id_t verifier_cred_handle;
@@ -401,6 +437,7 @@
OM_uint32 *ret_flags;
OM_uint32 *time_rec;
gss_cred_id_t *delegated_cred_handle;
+ krb5_gss_ctx_ext_t exts;
{
krb5_context context;
unsigned char *ptr, *ptr2;
@@ -741,16 +778,11 @@
/* if the checksum length > 24, there are options to process */
- if(authdat->checksum->length > 24 && (gss_flags & GSS_C_DELEG_FLAG)) {
-
- i = authdat->checksum->length - 24;
-
+ i = authdat->checksum->length - 24;
+ if (i && (gss_flags & GSS_C_DELEG_FLAG)) {
if (i >= 4) {
-
TREAD_INT16(ptr, option_id, bigend);
-
TREAD_INT16(ptr, option.length, bigend);
-
i -= 4;
if (i < option.length || option.length < 0) {
@@ -784,37 +816,41 @@
} /* if i >= 4 */
/* ignore any additional trailing data, for now */
-#ifdef CFX_EXERCISE
- {
- FILE *f = fopen("/tmp/gsslog", "a");
- if (f) {
- fprintf(f,
- "initial context token with delegation, %d extra bytes\n",
- i);
- fclose(f);
- }
+ }
+ while (i > 0) {
+ /* Process Type-Length-Data options */
+ if (i < 8) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
}
-#endif
- } else {
-#ifdef CFX_EXERCISE
- {
- FILE *f = fopen("/tmp/gsslog", "a");
- if (f) {
- if (gss_flags & GSS_C_DELEG_FLAG)
- fprintf(f,
- "initial context token, delegation flag but too small\n");
- else
- /* no deleg flag, length might still be too big */
- fprintf(f,
- "initial context token, %d extra bytes\n",
- authdat->checksum->length - 24);
- fclose(f);
- }
+ TREAD_INT(ptr, option_id, 1);
+ TREAD_INT(ptr, option.length, 1);
+ i -= 8;
+ if (i < option.length) {
+ code = KG_BAD_LENGTH;
+ major_status = GSS_S_FAILURE;
+ goto fail;
}
-#endif
+ TREAD_STR(ptr, ptr2, option.length);
+ option.data = (char *)ptr2;
+
+ i -= option.length;
+
+ code = kg_process_extension(context, auth_context,
+ option_id, &option, exts);
+ if (code != 0) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
}
}
+ if (exts->iakerb.conv && !exts->iakerb.verified) {
+ major_status = GSS_S_BAD_SIG;
+ goto fail;
+ }
+
/* only DCE_STYLE clients are allowed to send raw AP-REQs */
if (no_encap != ((gss_flags & GSS_C_DCE_STYLE) != 0)) {
major_status = GSS_S_DEFECTIVE_TOKEN;
@@ -831,6 +867,7 @@
}
memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+ ctx->magic = KG_CONTEXT;
ctx->mech_used = (gss_OID) mech_used;
ctx->auth_context = auth_context;
ctx->initiate = 0;
@@ -1248,22 +1285,19 @@
#endif /* LEAN_CLIENT */
OM_uint32
-krb5_gss_accept_sec_context(minor_status, context_handle,
- verifier_cred_handle, input_token,
- input_chan_bindings, src_name, mech_type,
- output_token, ret_flags, time_rec,
- delegated_cred_handle)
- OM_uint32 *minor_status;
- gss_ctx_id_t *context_handle;
- gss_cred_id_t verifier_cred_handle;
- gss_buffer_t input_token;
- gss_channel_bindings_t input_chan_bindings;
- gss_name_t *src_name;
- gss_OID *mech_type;
- gss_buffer_t output_token;
- OM_uint32 *ret_flags;
- OM_uint32 *time_rec;
- gss_cred_id_t *delegated_cred_handle;
+krb5_gss_accept_sec_context_ext(
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle,
+ krb5_gss_ctx_ext_t exts)
{
krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)*context_handle;
@@ -1291,5 +1325,42 @@
verifier_cred_handle, input_token,
input_chan_bindings, src_name, mech_type,
output_token, ret_flags, time_rec,
- delegated_cred_handle);
+ delegated_cred_handle, exts);
}
+
+OM_uint32
+krb5_gss_accept_sec_context(minor_status, context_handle,
+ verifier_cred_handle, input_token,
+ input_chan_bindings, src_name, mech_type,
+ output_token, ret_flags, time_rec,
+ delegated_cred_handle)
+ OM_uint32 *minor_status;
+ gss_ctx_id_t *context_handle;
+ gss_cred_id_t verifier_cred_handle;
+ gss_buffer_t input_token;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_name_t *src_name;
+ gss_OID *mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+ gss_cred_id_t *delegated_cred_handle;
+{
+ krb5_gss_ctx_ext_rec exts;
+
+ memset(&exts, 0, sizeof(exts));
+
+ return krb5_gss_accept_sec_context_ext(minor_status,
+ context_handle,
+ verifier_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle,
+ &exts);
+}
+
Modified: branches/iakerb/src/lib/gssapi/krb5/acquire_cred.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/acquire_cred.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/acquire_cred.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -222,16 +222,17 @@
OM_uint32 *minor_status,
krb5_gss_name_t desired_name,
krb5_gss_name_t *output_name,
+ gss_buffer_t password,
krb5_gss_cred_id_rec *cred)
{
krb5_error_code code;
krb5_ccache ccache;
- krb5_principal princ, tmp_princ;
- krb5_flags flags;
+ krb5_principal princ = NULL, tmp_princ;
krb5_cc_cursor cur;
krb5_creds creds;
int got_endtime;
int caller_provided_ccache_name = 0;
+ krb5_data password_data;
cred->ccache = NULL;
@@ -335,24 +336,30 @@
}
/* turn off OPENCLOSE mode while extensive frobbing is going on */
-
- flags = 0; /* turns off OPENCLOSE mode */
- if ((code = krb5_cc_set_flags(context, ccache, flags))) {
+ code = krb5_cc_set_flags(context, ccache, 0);
+ if (code == KRB5_FCC_NOFILE &&
+ password != GSS_C_NO_BUFFER && desired_name != NULL) {
+ /* Well, we can create a memory ccache. */
+ code = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache);
+ if (code == 0)
+ code = krb5_cc_initialize(context, ccache, desired_name->princ);
+ }
+ if (code != 0) {
(void)krb5_cc_close(context, ccache);
*minor_status = code;
return(GSS_S_CRED_UNAVAIL);
}
/* get out the principal name and see if it matches */
-
- if ((code = krb5_cc_get_principal(context, ccache, &princ))) {
+ code = krb5_cc_get_principal(context, ccache, &princ);
+ if (code != 0) {
(void)krb5_cc_close(context, ccache);
*minor_status = code;
return(GSS_S_FAILURE);
}
- if (desired_name != (krb5_gss_name_t)NULL) {
- if (! krb5_principal_compare(context, princ, desired_name->princ)) {
+ if (desired_name != NULL) {
+ if (!krb5_principal_compare(context, princ, desired_name->princ)) {
(void)krb5_free_principal(context, princ);
(void)krb5_cc_close(context, ccache);
*minor_status = KG_CCACHE_NOMATCH;
@@ -369,8 +376,34 @@
*minor_status = code;
return(GSS_S_FAILURE);
}
+ /* princ is now owned by output_name, it need not be freed here */
}
+ if (password != GSS_C_NO_BUFFER) {
+ /* stash the password for later */
+ password_data.length = password->length;
+ password_data.data = (char *)password->value;
+
+ code = krb5int_copy_data_contents_add0(context, &password_data,
+ &cred->password);
+ if (code != 0) {
+ (void)krb5_cc_close(context, ccache);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ /* restore the OPENCLOSE flag */
+ code = krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
+ if (code != 0) {
+ (void)krb5_cc_close(context, ccache);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ cred->ccache = ccache;
+ return GSS_S_COMPLETE;
+ }
+
/* iterate over the ccache, find the tgt */
if ((code = krb5_cc_start_seq_get(context, ccache, &cur))) {
@@ -388,7 +421,7 @@
code = krb5_build_principal_ext(context, &tmp_princ,
krb5_princ_realm(context, princ)->length,
krb5_princ_realm(context, princ)->data,
- 6, "krbtgt",
+ KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
krb5_princ_realm(context, princ)->length,
krb5_princ_realm(context, princ)->data,
0);
@@ -433,8 +466,7 @@
*minor_status = code;
return(GSS_S_FAILURE);
}
- flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
- if ((code = krb5_cc_set_flags(context, ccache, flags))) {
+ if ((code = krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE))) {
(void)krb5_cc_close(context, ccache);
*minor_status = code;
return(GSS_S_FAILURE);
@@ -449,38 +481,36 @@
}
/*ARGSUSED*/
-OM_uint32
-krb5_gss_acquire_cred(minor_status, desired_name, time_req,
- desired_mechs, cred_usage, output_cred_handle,
- actual_mechs, time_rec)
+static OM_uint32
+acquire_cred(minor_status, desired_name, password, time_req,
+ desired_mechs, cred_usage, output_cred_handle,
+ actual_mechs, time_rec, req_iakerb)
OM_uint32 *minor_status;
- gss_name_t desired_name;
+ const gss_name_t desired_name;
+ const gss_buffer_t password;
OM_uint32 time_req;
- gss_OID_set desired_mechs;
+ const gss_OID_set desired_mechs;
gss_cred_usage_t cred_usage;
gss_cred_id_t *output_cred_handle;
gss_OID_set *actual_mechs;
OM_uint32 *time_rec;
+ int req_iakerb;
{
- krb5_context context;
+ krb5_context context = NULL;
size_t i;
- krb5_gss_cred_id_t cred;
- gss_OID_set ret_mechs = NULL;
+ krb5_gss_cred_id_t cred = NULL;
+ gss_OID_set ret_mechs = GSS_C_NO_OID_SET;
int req_old, req_new;
OM_uint32 ret;
- krb5_error_code code;
+ krb5_error_code code = 0;
code = gss_krb5int_initialize_library();
- if (code) {
- *minor_status = code;
- return GSS_S_FAILURE;
- }
+ if (code)
+ goto krb_error_out;
code = krb5_gss_init_context(&context);
- if (code) {
- *minor_status = code;
- return GSS_S_FAILURE;
- }
+ if (code)
+ goto krb_error_out;
/* make sure all outputs are valid */
@@ -495,11 +525,16 @@
/*SUPPRESS 29*/
if ((desired_name != GSS_C_NO_NAME) &&
(! kg_validate_name(desired_name))) {
- *minor_status = (OM_uint32) G_VALIDATE_FAILED;
- krb5_free_context(context);
- return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+ code = G_VALIDATE_FAILED;
+ goto krb_error_out;
}
+ if (req_iakerb &&
+ (password == GSS_C_NO_BUFFER || cred_usage == GSS_C_BOTH)) {
+ code = G_BAD_USAGE;
+ goto krb_error_out;
+ }
+
/* verify that the requested mechanism set is the default, or
contains krb5 */
@@ -518,26 +553,21 @@
}
if (!req_old && !req_new) {
- *minor_status = 0;
- krb5_free_context(context);
- return(GSS_S_BAD_MECH);
+ ret = GSS_S_BAD_MECH;
+ goto error_out;
}
}
/* create the gss cred structure */
+ cred = k5alloc(sizeof(krb5_gss_cred_id_rec), &code);
+ if (code != 0)
+ goto krb_error_out;
- if ((cred =
- (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) == NULL) {
- *minor_status = ENOMEM;
- krb5_free_context(context);
- return(GSS_S_FAILURE);
- }
- memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
-
cred->usage = cred_usage;
cred->name = NULL;
- cred->prerfc_mech = (req_old != 0);
- cred->rfc_mech = (req_new != 0);
+ cred->prerfc_mech = (req_old != 0) && (req_iakerb == 0);
+ cred->rfc_mech = (req_new != 0) && (req_iakerb == 0);
+ cred->iakerb_mech = req_iakerb;
cred->default_identity = (desired_name == GSS_C_NO_NAME);
#ifndef LEAN_CLIENT
@@ -546,11 +576,9 @@
cred->ccache = NULL;
code = k5_mutex_init(&cred->lock);
- if (code) {
- *minor_status = code;
- krb5_free_context(context);
- return GSS_S_FAILURE;
- }
+ if (code)
+ goto krb_error_out;
+
/* Note that we don't need to lock this GSSAPI credential record
here, because no other thread can gain access to it until we
return it. */
@@ -558,11 +586,8 @@
if ((cred_usage != GSS_C_INITIATE) &&
(cred_usage != GSS_C_ACCEPT) &&
(cred_usage != GSS_C_BOTH)) {
- k5_mutex_destroy(&cred->lock);
- xfree(cred);
*minor_status = (OM_uint32) G_BAD_USAGE;
- krb5_free_context(context);
- return(GSS_S_FAILURE);
+ goto error_out;
}
/* if requested, acquire credentials for accepting */
@@ -574,14 +599,7 @@
(krb5_gss_name_t)desired_name,
&cred->name, cred))
!= GSS_S_COMPLETE) {
- if (cred->name)
- kg_release_name(context, 0, &cred->name);
- k5_mutex_destroy(&cred->lock);
- xfree(cred);
- /* minor_status set by acquire_accept_cred() */
- save_error_info(*minor_status, context);
- krb5_free_context(context);
- return(ret);
+ goto error_out;
}
#endif /* LEAN_CLIENT */
@@ -589,46 +607,24 @@
/* this will fill in cred->name if it wasn't set above, and
the desired_name is not specified */
- if ((cred_usage == GSS_C_INITIATE) ||
- (cred_usage == GSS_C_BOTH))
- if ((ret =
- acquire_init_cred(context, minor_status,
- cred->name?cred->name:(krb5_gss_name_t)desired_name,
- &cred->name, cred))
- != GSS_S_COMPLETE) {
-#ifndef LEAN_CLIENT
- if (cred->keytab)
- krb5_kt_close(context, cred->keytab);
-#endif /* LEAN_CLIENT */
- if (cred->name)
- kg_release_name(context, 0, &cred->name);
- k5_mutex_destroy(&cred->lock);
- xfree(cred);
- /* minor_status set by acquire_init_cred() */
- save_error_info(*minor_status, context);
- krb5_free_context(context);
- return(ret);
- }
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
+ ret = acquire_init_cred(context, minor_status,
+ cred->name ?
+ cred->name : (krb5_gss_name_t)desired_name,
+ &cred->name, password, cred);
+ if (ret != GSS_S_COMPLETE)
+ goto error_out;
+ }
/* if the princ wasn't filled in already, fill it in now */
- if (!cred->name && (desired_name != GSS_C_NO_NAME))
- if ((code = kg_duplicate_name(context,
- (krb5_gss_name_t)desired_name,
- 0, &cred->name))) {
- if (cred->ccache)
- (void)krb5_cc_close(context, cred->ccache);
-#ifndef LEAN_CLIENT
- if (cred->keytab)
- (void)krb5_kt_close(context, cred->keytab);
-#endif /* LEAN_CLIENT */
- k5_mutex_destroy(&cred->lock);
- xfree(cred);
- *minor_status = code;
- save_error_info(*minor_status, context);
- krb5_free_context(context);
- return(GSS_S_FAILURE);
- }
+ if (!cred->name && (desired_name != GSS_C_NO_NAME)) {
+ code = kg_duplicate_name(context,
+ (krb5_gss_name_t)desired_name,
+ 0, &cred->name);
+ if (code != 0)
+ goto krb_error_out;
+ }
/*** at this point, the cred structure has been completely created */
@@ -640,22 +636,9 @@
} else {
krb5_timestamp now;
- if ((code = krb5_timeofday(context, &now))) {
- if (cred->ccache)
- (void)krb5_cc_close(context, cred->ccache);
-#ifndef LEAN_CLIENT
- if (cred->keytab)
- (void)krb5_kt_close(context, cred->keytab);
-#endif /* LEAN_CLIENT */
- if (cred->name)
- kg_release_name(context, 0, &cred->name);
- k5_mutex_destroy(&cred->lock);
- xfree(cred);
- *minor_status = code;
- save_error_info(*minor_status, context);
- krb5_free_context(context);
- return(GSS_S_FAILURE);
- }
+ code = krb5_timeofday(context, &now);
+ if (code != 0)
+ goto krb_error_out;
if (time_rec)
*time_rec = (cred->tgt_expire > now) ? (cred->tgt_expire - now) : 0;
@@ -673,44 +656,20 @@
(cred->rfc_mech &&
GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
gss_mech_krb5,
+ &ret_mechs))) ||
+ (cred->iakerb_mech &&
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_iakerb,
&ret_mechs)))) {
- if (cred->ccache)
- (void)krb5_cc_close(context, cred->ccache);
-#ifndef LEAN_CLIENT
- if (cred->keytab)
- (void)krb5_kt_close(context, cred->keytab);
-#endif /* LEAN_CLIENT */
- if (cred->name)
- kg_release_name(context, 0, &cred->name);
- k5_mutex_destroy(&cred->lock);
- xfree(cred);
- /* *minor_status set above */
- krb5_free_context(context);
- return(ret);
+ goto error_out;
}
}
/* intern the credential handle */
if (! kg_save_cred_id((gss_cred_id_t) cred)) {
- if (ret_mechs) {
- free(ret_mechs->elements);
- free(ret_mechs);
- }
- if (cred->ccache)
- (void)krb5_cc_close(context, cred->ccache);
-#ifndef LEAN_CLIENT
- if (cred->keytab)
- (void)krb5_kt_close(context, cred->keytab);
-#endif /* LEAN_CLIENT */
- if (cred->name)
- kg_release_name(context, 0, &cred->name);
- k5_mutex_destroy(&cred->lock);
- xfree(cred);
- *minor_status = (OM_uint32) G_VALIDATE_FAILED;
- save_error_string(*minor_status, "error saving credentials");
- krb5_free_context(context);
- return(GSS_S_FAILURE);
+ ret = GSS_S_FAILURE;
+ goto error_out;
}
/* return success */
@@ -722,6 +681,29 @@
krb5_free_context(context);
return(GSS_S_COMPLETE);
+
+krb_error_out:
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+
+error_out:
+ if (ret_mechs != GSS_C_NO_OID_SET) {
+ free(ret_mechs->elements);
+ free(ret_mechs);
+ }
+ if (cred->ccache)
+ (void)krb5_cc_close(context, cred->ccache);
+#ifndef LEAN_CLIENT
+ if (cred->keytab)
+ (void)krb5_kt_close(context, cred->keytab);
+#endif /* LEAN_CLIENT */
+ if (cred->name)
+ kg_release_name(context, 0, &cred->name);
+ k5_mutex_destroy(&cred->lock);
+ xfree(cred);
+ save_error_info(*minor_status, context);
+ krb5_free_context(context);
+ return ret;
}
OM_uint32
@@ -768,3 +750,57 @@
*minor_status = 0;
return GSS_S_COMPLETE;
}
+
+OM_uint32
+krb5_gss_acquire_cred(minor_status, desired_name, time_req,
+ desired_mechs, cred_usage, output_cred_handle,
+ actual_mechs, time_rec)
+ OM_uint32 *minor_status;
+ gss_name_t desired_name;
+ OM_uint32 time_req;
+ gss_OID_set desired_mechs;
+ gss_cred_usage_t cred_usage;
+ gss_cred_id_t *output_cred_handle;
+ gss_OID_set *actual_mechs;
+ OM_uint32 *time_rec;
+{
+ return acquire_cred(minor_status, desired_name, GSS_C_NO_BUFFER,
+ time_req, desired_mechs,
+ cred_usage, output_cred_handle, actual_mechs,
+ time_rec, 0);
+}
+
+OM_uint32
+krb5_gss_acquire_cred_with_password(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, password,
+ time_req, desired_mechs,
+ cred_usage, output_cred_handle, actual_mechs,
+ time_rec, 0);
+}
+
+OM_uint32
+iakerb_gss_acquire_cred_with_password(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ return acquire_cred(minor_status, desired_name, password,
+ time_req, desired_mechs,
+ cred_usage, output_cred_handle, actual_mechs,
+ time_rec, 1);
+}
+
Modified: branches/iakerb/src/lib/gssapi/krb5/add_cred.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/add_cred.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/add_cred.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -145,7 +145,8 @@
/* check that desired_mech isn't already in the credential */
if ((g_OID_equal(desired_mech, gss_mech_krb5_old) && cred->prerfc_mech) ||
- (g_OID_equal(desired_mech, gss_mech_krb5) && cred->rfc_mech)) {
+ (g_OID_equal(desired_mech, gss_mech_krb5) && cred->rfc_mech) ||
+ (g_OID_equal(desired_mech, gss_mech_iakerb) && cred->iakerb_mech)) {
*minor_status = 0;
krb5_free_context(context);
return(GSS_S_DUPLICATE_ELEMENT);
@@ -197,6 +198,7 @@
new_cred->usage = cred_usage;
new_cred->prerfc_mech = cred->prerfc_mech;
new_cred->rfc_mech = cred->rfc_mech;
+ new_cred->iakerb_mech = cred->iakerb_mech;
new_cred->tgt_expire = cred->tgt_expire;
if (cred->name)
@@ -359,6 +361,8 @@
cred->prerfc_mech = 1;
else if (g_OID_equal(desired_mech, gss_mech_krb5))
cred->rfc_mech = 1;
+ else if (g_OID_equal(desired_mech, gss_mech_iakerb))
+ cred->iakerb_mech = 1;
/* set the outputs */
Modified: branches/iakerb/src/lib/gssapi/krb5/gssapiP_krb5.h
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/gssapiP_krb5.h 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/gssapiP_krb5.h 2010-03-29 16:18:20 UTC (rev 23843)
@@ -86,6 +86,9 @@
#define GSS_MECH_KRB5_WRONG_OID_LENGTH 9
#define GSS_MECH_KRB5_WRONG_OID "\052\206\110\202\367\022\001\002\002"
+/* IAKERB variant */
+#define GSS_MECH_IAKERB_OID_LENGTH 6
+#define GSS_MECH_IAKERB_OID "\053\006\001\005\002\005"
#define CKSUMTYPE_KG_CB 0x8003
@@ -100,6 +103,7 @@
#define KG2_TOK_MIC_MSG 0x0404
#define KG2_TOK_WRAP_MSG 0x0504
#define KG2_TOK_DEL_CTX 0x0405
+#define IAKERB_TOK_PROXY 0x0501
#define KRB5_GSS_FOR_CREDS_OPTION 1
@@ -170,6 +174,7 @@
unsigned int rfc_mech : 1;
unsigned int proxy_cred : 1;
unsigned int default_identity : 1;
+ unsigned int iakerb_mech : 1;
/* keytab (accept) data */
krb5_keytab keytab;
@@ -179,9 +184,18 @@
krb5_ccache ccache;
krb5_timestamp tgt_expire;
krb5_enctype *req_enctypes; /* limit negotiated enctypes to this list */
+ krb5_data password;
} krb5_gss_cred_id_rec, *krb5_gss_cred_id_t;
+typedef struct _krb5_gss_ctx_ext_rec {
+ struct {
+ krb5_data *conv;
+ int verified;
+ } iakerb;
+} krb5_gss_ctx_ext_rec, *krb5_gss_ctx_ext_t;
+
typedef struct _krb5_gss_ctx_id_rec {
+ krb5_magic magic;
unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */
unsigned int established : 1;
unsigned int big_endian : 1;
@@ -239,7 +253,8 @@
#define kg_validate_name(name) g_validate_name(&kg_vdb,name)
#define kg_validate_cred_id(cred) g_validate_cred_id(&kg_vdb,cred)
-#define kg_validate_ctx_id(ctx) g_validate_ctx_id(&kg_vdb,ctx)
+#define kg_validate_ctx_id(ctx) (g_validate_ctx_id(&kg_vdb,ctx) && \
+ ((krb5_gss_ctx_id_t)ctx)->magic == KG_CONTEXT)
#define kg_validate_lucidctx_id(lctx) g_validate_lucidctx_id(&kg_vdb,lctx)
#define kg_delete_name(name) g_delete_name(&kg_vdb,name)
@@ -492,7 +507,8 @@
OM_uint32 *ret_flags,
OM_uint32 *time_rec,
krb5_context context,
- int default_mech);
+ int default_mech,
+ krb5_gss_ctx_ext_t exts);
/** declarations of internal name mechanism functions **/
@@ -507,6 +523,30 @@
OM_uint32* /* time_rec */
);
+OM_uint32
+krb5_gss_acquire_cred_with_password(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec);
+
+OM_uint32
+iakerb_gss_acquire_cred_with_password(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec);
+
OM_uint32 krb5_gss_release_cred
(OM_uint32*, /* minor_status */
gss_cred_id_t* /* cred_handle */
@@ -529,6 +569,24 @@
OM_uint32* /* time_rec */
);
+OM_uint32 krb5_gss_init_sec_context_ext
+(OM_uint32*, /* minor_status */
+ gss_cred_id_t, /* claimant_cred_handle */
+ gss_ctx_id_t*, /* context_handle */
+ gss_name_t, /* target_name */
+ gss_OID, /* mech_type */
+ OM_uint32, /* req_flags */
+ OM_uint32, /* time_req */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_buffer_t, /* input_token */
+ gss_OID*, /* actual_mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ krb5_gss_ctx_ext_t /* exts */
+);
+
#ifndef LEAN_CLIENT
OM_uint32 krb5_gss_accept_sec_context
(OM_uint32*, /* minor_status */
@@ -544,6 +602,22 @@
OM_uint32*, /* time_rec */
gss_cred_id_t* /* delegated_cred_handle */
);
+
+OM_uint32 krb5_gss_accept_sec_context_ext
+(OM_uint32*, /* minor_status */
+ gss_ctx_id_t*, /* context_handle */
+ gss_cred_id_t, /* verifier_cred_handle */
+ gss_buffer_t, /* input_token_buffer */
+ gss_channel_bindings_t,
+ /* input_chan_bindings */
+ gss_name_t*, /* src_name */
+ gss_OID*, /* mech_type */
+ gss_buffer_t, /* output_token */
+ OM_uint32*, /* ret_flags */
+ OM_uint32*, /* time_rec */
+ gss_cred_id_t*, /* delegated_cred_handle */
+ krb5_gss_ctx_ext_t/*exts */
+);
#endif /* LEAN_CLIENT */
OM_uint32 krb5_gss_process_context_token
@@ -1084,4 +1158,53 @@
#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
+/* IAKERB */
+
+OM_uint32
+iakerb_gss_init_sec_context(OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec);
+
+OM_uint32
+iakerb_gss_accept_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handler,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle);
+
+OM_uint32
+iakerb_gss_delete_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token);
+
+krb5_error_code
+iakerb_make_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ krb5_data **finished);
+
+krb5_error_code
+iakerb_verify_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ const krb5_data *finished);
+
+#define KRB5_GSS_EXTS_IAKERB_FINISHED 1
+
#endif /* _GSSAPIP_KRB5_H_ */
Modified: branches/iakerb/src/lib/gssapi/krb5/gssapi_err_krb5.et
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/gssapi_err_krb5.et 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/gssapi_err_krb5.et 2010-03-29 16:18:20 UTC (rev 23843)
@@ -38,4 +38,5 @@
error_code KG_NO_CTYPES, "Acceptor and Initiator share no checksum types"
error_code KG_LUCID_VERSION, "Requested lucid context version not supported"
error_code KG_INPUT_TOO_LONG, "PRF input too long"
+error_code KG_IAKERB_CONTEXT, "Bad magic number for iakerb_ctx_id_t"
end
Modified: branches/iakerb/src/lib/gssapi/krb5/gssapi_krb5.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/gssapi_krb5.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/gssapi_krb5.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -127,34 +127,36 @@
{GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID},
/* this is the unofficial, incorrect mech OID emitted by MS */
{GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID},
+ /* IAKERB OID */
+ {GSS_MECH_IAKERB_OID_LENGTH, GSS_MECH_IAKERB_OID},
/* this is the v2 assigned OID */
{9, "\052\206\110\206\367\022\001\002\003"},
/* these two are name type OID's */
-
/* 2.1.1. Kerberos Principal Name Form: (rfc 1964)
* This name form shall be represented by the Object Identifier {iso(1)
* member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
* krb5(2) krb5_name(1)}. The recommended symbolic name for this type
* is "GSS_KRB5_NT_PRINCIPAL_NAME". */
{10, "\052\206\110\206\367\022\001\002\002\001"},
-
/* gss_nt_krb5_principal. Object identifier for a krb5_principal. Do not use. */
{10, "\052\206\110\206\367\022\001\002\002\002"},
-
{ 0, 0 }
};
const gss_OID_desc * const gss_mech_krb5 = krb5_gss_oid_array+0;
const gss_OID_desc * const gss_mech_krb5_old = krb5_gss_oid_array+1;
const gss_OID_desc * const gss_mech_krb5_wrong = krb5_gss_oid_array+2;
-const gss_OID_desc * const gss_nt_krb5_name = krb5_gss_oid_array+4;
-const gss_OID_desc * const gss_nt_krb5_principal = krb5_gss_oid_array+5;
-const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+4;
+const gss_OID_desc * const gss_mech_iakerb = krb5_gss_oid_array+3;
+
+const gss_OID_desc * const gss_nt_krb5_name = krb5_gss_oid_array+5;
+const gss_OID_desc * const gss_nt_krb5_principal = krb5_gss_oid_array+6;
+const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+5;
+
static const gss_OID_set_desc oidsets[] = {
- {1, (gss_OID) krb5_gss_oid_array+0},
- {1, (gss_OID) krb5_gss_oid_array+1},
- {3, (gss_OID) krb5_gss_oid_array+0},
+ {1, (gss_OID) krb5_gss_oid_array+0}, /* RFC OID */
+ {1, (gss_OID) krb5_gss_oid_array+1}, /* pre-RFC OID */
+ {4, (gss_OID) krb5_gss_oid_array+0}, /* includes wrong OID & IAKERB */
{1, (gss_OID) krb5_gss_oid_array+2},
{3, (gss_OID) krb5_gss_oid_array+0},
};
@@ -697,18 +699,47 @@
NULL, /* set_neg_mechs */
};
+static struct gss_config_ext krb5_mechanism_ext = {
+ krb5_gss_acquire_cred_with_password,
+};
+static struct gss_config_ext iakerb_mechanism_ext = {
+ iakerb_gss_acquire_cred_with_password,
+};
+
#ifdef _GSS_STATIC_LINK
#include "mglueP.h"
+static int gss_iakerbmechglue_init(void)
+{
+ struct gss_mech_config mech_iakerb;
+ struct gss_config iakerb_mechanism = krb5_mechanism;
+
+ /* IAKERB mechanism mirrors krb5, but with different context SPIs */
+ iakerb_mechanism.gss_accept_sec_context = iakerb_gss_accept_sec_context;
+ iakerb_mechanism.gss_init_sec_context = iakerb_gss_init_sec_context;
+ iakerb_mechanism.gss_delete_sec_context = iakerb_gss_delete_sec_context;
+
+ memset(&mech_iakerb, 0, sizeof(mech_iakerb));
+ mech_iakerb.mech = &iakerb_mechanism;
+ mech_iakerb.mech_ext = &iakerb_mechanism_ext;
+
+ mech_iakerb.mechNameStr = "iakerb";
+ mech_iakerb.mech_type = (gss_OID)gss_mech_iakerb;
+ gssint_register_mechinfo(&mech_iakerb);
+
+ return 0;
+}
+
static int gss_krb5mechglue_init(void)
{
struct gss_mech_config mech_krb5;
memset(&mech_krb5, 0, sizeof(mech_krb5));
mech_krb5.mech = &krb5_mechanism;
+ mech_krb5.mech_ext = &krb5_mechanism_ext;
+
mech_krb5.mechNameStr = "kerberos_v5";
mech_krb5.mech_type = (gss_OID)gss_mech_krb5;
-
gssint_register_mechinfo(&mech_krb5);
mech_krb5.mechNameStr = "kerberos_v5_old";
@@ -766,6 +797,9 @@
return err;
#endif
#ifdef _GSS_STATIC_LINK
+ err = gss_iakerbmechglue_init();
+ if (err)
+ return err;
err = gss_krb5mechglue_init();
if (err)
return err;
Modified: branches/iakerb/src/lib/gssapi/krb5/gssapi_krb5.hin
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/gssapi_krb5.hin 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/gssapi_krb5.hin 2010-03-29 16:18:20 UTC (rev 23843)
@@ -75,6 +75,7 @@
GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5;
GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5_old;
GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5_wrong;
+GSS_DLLIMP extern const gss_OID_desc * const gss_mech_iakerb;
GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5;
GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_old;
GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_both;
Added: branches/iakerb/src/lib/gssapi/krb5/iakerb.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/iakerb.c (rev 0)
+++ branches/iakerb/src/lib/gssapi/krb5/iakerb.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -0,0 +1,1081 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+/*
+ * IAKERB implementation
+ */
+
+extern int gssint_get_der_length(unsigned char **, OM_uint32, unsigned int*);
+
+enum iakerb_state {
+ IAKERB_AS_REQ, /* acquiring ticket with initial creds */
+ IAKERB_TGS_REQ, /* acquiring ticket with TGT */
+ IAKERB_AP_REQ /* hand-off to normal GSS AP-REQ exchange */
+};
+
+struct _iakerb_ctx_id_rec {
+ krb5_magic magic; /* KG_IAKERB_CONTEXT */
+ krb5_context k5c;
+ enum iakerb_state state; /* discriminant for union below */
+ union {
+ krb5_init_creds_context icc; /* IAKERB_AS_REQ */
+ krb5_tkt_creds_context tcc; /* IAKERB_TGS_REQ */
+ gss_ctx_id_t gssc; /* IAKERB_AP_REQ */
+ } u;
+ krb5_data conv; /* conversation for checksumming */
+ unsigned int count; /* number of round trips */
+ krb5_get_init_creds_opt *gic_opts;
+};
+
+#define IAKERB_MAX_HOPS ( 16 /* MAX_IN_TKT_LOOPS */ + KRB5_REFERRAL_MAXHOPS )
+
+typedef struct _iakerb_ctx_id_rec iakerb_ctx_id_rec;
+typedef iakerb_ctx_id_rec *iakerb_ctx_id_t;
+
+/*
+ * Release an IAKERB context
+ */
+static void
+iakerb_release_context(iakerb_ctx_id_t ctx)
+{
+ OM_uint32 tmp;
+
+ if (ctx == NULL)
+ return;
+
+ switch (ctx->state) {
+ case IAKERB_AS_REQ:
+ krb5_init_creds_free(ctx->k5c, ctx->u.icc);
+ break;
+ case IAKERB_TGS_REQ:
+ krb5_tkt_creds_free(ctx->k5c, ctx->u.tcc);
+ break;
+ case IAKERB_AP_REQ:
+ krb5_gss_delete_sec_context(&tmp, &ctx->u.gssc, NULL);
+ break;
+ }
+ krb5_free_data_contents(ctx->k5c, &ctx->conv);
+ krb5_get_init_creds_opt_free(ctx->k5c, ctx->gic_opts);
+ krb5_free_context(ctx->k5c);
+ free(ctx);
+}
+
+/*
+ * Create a IAKERB-FINISHED structure containing a checksum of
+ * the entire IAKERB exchange.
+ */
+krb5_error_code
+iakerb_make_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ krb5_data **finished)
+{
+ krb5_error_code code;
+ krb5_cksumtype cksumtype;
+ krb5_iakerb_finished iaf;
+
+ *finished = NULL;
+
+ memset(&iaf, 0, sizeof(iaf));
+
+ if (key == NULL)
+ return KRB5KDC_ERR_NULL_KEY;
+
+ code = krb5int_c_mandatory_cksumtype(context,
+ krb5_k_key_enctype(context, key),
+ &cksumtype);
+ if (code != 0)
+ return code;
+
+ code = krb5_k_make_checksum(context, cksumtype,
+ key, KRB5_KEYUSAGE_IAKERB_FINISHED,
+ conv, &iaf.checksum);
+ if (code != 0)
+ return code;
+
+ code = encode_krb5_iakerb_finished(&iaf, finished);
+
+ krb5_free_checksum_contents(context, &iaf.checksum);
+
+ return code;
+}
+
+/*
+ * Verify a IAKERB-FINISHED structure submitted by the initiator
+ */
+krb5_error_code
+iakerb_verify_finished(krb5_context context,
+ krb5_key key,
+ const krb5_data *conv,
+ const krb5_data *finished)
+{
+ krb5_error_code code;
+ krb5_iakerb_finished *iaf;
+ krb5_boolean valid = FALSE;
+
+ if (key == NULL)
+ return KRB5KDC_ERR_NULL_KEY;
+
+ code = decode_krb5_iakerb_finished(finished, &iaf);
+ if (code != 0)
+ return code;
+
+ code = krb5_k_verify_checksum(context, key, KRB5_KEYUSAGE_IAKERB_FINISHED,
+ conv, &iaf->checksum, &valid);
+ if (code == 0 && valid == FALSE)
+ code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+
+ krb5_free_iakerb_finished(context, iaf);
+
+ return code;
+}
+
+/*
+ * Save a token for future checksumming.
+ */
+static krb5_error_code
+iakerb_save_token(iakerb_ctx_id_t ctx, const gss_buffer_t token)
+{
+ char *p;
+
+ p = realloc(ctx->conv.data, ctx->conv.length + token->length);
+ if (p == NULL)
+ return ENOMEM;
+
+ memcpy(p + ctx->conv.length, token->value, token->length);
+ ctx->conv.data = p;
+ ctx->conv.length += token->length;
+
+ return 0;
+}
+
+/*
+ * Parse a token into IAKERB-HEADER and KRB-KDC-REQ/REP
+ */
+static krb5_error_code
+iakerb_parse_token(iakerb_ctx_id_t ctx,
+ int initialContextToken,
+ const gss_buffer_t token,
+ krb5_data *realm,
+ krb5_data **cookie,
+ krb5_data *request)
+{
+ krb5_error_code code;
+ krb5_iakerb_header *iah = NULL;
+ unsigned int bodysize, lenlen;
+ int length;
+ unsigned char *ptr;
+ int flags = 0;
+ krb5_data data;
+
+ if (token == GSS_C_NO_BUFFER || token->length == 0) {
+ code = KRB5_BAD_MSIZE;
+ goto cleanup;
+ }
+
+ if (initialContextToken)
+ flags |= G_VFY_TOKEN_HDR_WRAPPER_REQUIRED;
+
+ ptr = token->value;
+
+ code = g_verify_token_header(gss_mech_iakerb,
+ &bodysize, &ptr,
+ IAKERB_TOK_PROXY,
+ token->length, flags);
+ if (code != 0)
+ goto cleanup;
+
+ data.data = (char *)ptr;
+
+ if (bodysize-- == 0 || *ptr++ != 0x30 /* SEQUENCE */) {
+ code = ASN1_BAD_ID;
+ goto cleanup;
+ }
+
+ length = gssint_get_der_length(&ptr, bodysize, &lenlen);
+ if (length < 0 || bodysize - lenlen < (unsigned int)length) {
+ code = KRB5_BAD_MSIZE;
+ goto cleanup;
+ }
+ data.length = 1 /* SEQUENCE */ + lenlen + length;
+
+ ptr += length;
+ bodysize -= (lenlen + length);
+
+ code = decode_krb5_iakerb_header(&data, &iah);
+ if (code != 0)
+ goto cleanup;
+
+ if (realm != NULL) {
+ *realm = iah->target_realm;
+ iah->target_realm.data = NULL;
+ }
+
+ if (cookie != NULL) {
+ *cookie = iah->cookie;
+ iah->cookie = NULL;
+ }
+
+ request->data = (char *)ptr;
+ request->length = bodysize;
+
+ assert(request->data + request->length ==
+ (char *)token->value + token->length);
+
+cleanup:
+ krb5_free_iakerb_header(ctx->k5c, iah);
+
+ return code;
+}
+
+/*
+ * Create a token from IAKERB-HEADER and KRB-KDC-REQ/REP
+ */
+static krb5_error_code
+iakerb_make_token(iakerb_ctx_id_t ctx,
+ krb5_data *realm,
+ krb5_data *cookie,
+ krb5_data *request,
+ int initialContextToken,
+ gss_buffer_t token)
+{
+ krb5_error_code code;
+ krb5_iakerb_header iah;
+ krb5_data *data = NULL;
+ char *p;
+ unsigned int tokenSize;
+ unsigned char *q;
+
+ token->value = NULL;
+ token->length = 0;
+
+ /*
+ * Assemble the IAKERB-HEADER from the realm and cookie
+ */
+ memset(&iah, 0, sizeof(iah));
+ iah.target_realm = *realm;
+ iah.cookie = cookie;
+
+ code = encode_krb5_iakerb_header(&iah, &data);
+ if (code != 0)
+ goto cleanup;
+
+ /*
+ * Concatenate Kerberos request.
+ */
+ p = realloc(data->data, data->length + request->length);
+ if (p == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ data->data = p;
+
+ memcpy(data->data + data->length, request->data, request->length);
+ data->length += request->length;
+
+ if (initialContextToken)
+ tokenSize = g_token_size(gss_mech_iakerb, data->length);
+ else
+ tokenSize = 2 + data->length;
+
+ token->value = q = k5alloc(tokenSize, &code);
+ if (code != 0)
+ goto cleanup;
+ token->length = tokenSize;
+
+ if (initialContextToken) {
+ g_make_token_header(gss_mech_iakerb, data->length, &q,
+ IAKERB_TOK_PROXY);
+ } else {
+ store_16_be(IAKERB_TOK_PROXY, q);
+ q += 2;
+ }
+ memcpy(q, data->data, data->length);
+ q += data->length;
+
+ assert(q == (unsigned char *)token->value + token->length);
+
+cleanup:
+ krb5_free_data(ctx->k5c, data);
+
+ return code;
+}
+
+/*
+ * Parse the IAKERB token in input_token and send the contained KDC
+ * request to the KDC for the realm.
+ *
+ * Wrap the KDC reply in output_token.
+ */
+static krb5_error_code
+iakerb_acceptor_step(iakerb_ctx_id_t ctx,
+ int initialContextToken,
+ const gss_buffer_t input_token,
+ gss_buffer_t output_token)
+{
+ krb5_error_code code;
+ krb5_data request, reply, realm;
+ OM_uint32 tmp;
+ int tcpOnly = 0, useMaster;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ request.data = NULL;
+ request.length = 0;
+ reply.data = NULL;
+ reply.length = 0;
+ realm.data = NULL;
+ realm.length = 0;
+
+ if (ctx->count >= IAKERB_MAX_HOPS) {
+ code = KRB5_KDC_UNREACH;
+ goto cleanup;
+ }
+
+ code = iakerb_parse_token(ctx,
+ initialContextToken,
+ input_token,
+ &realm,
+ NULL,
+ &request);
+ if (code != 0)
+ goto cleanup;
+
+ if (realm.length == 0 || request.length == 0) {
+ code = KRB5_BAD_MSIZE;
+ goto cleanup;
+ }
+
+ code = iakerb_save_token(ctx, input_token);
+ if (code != 0)
+ goto cleanup;
+
+send_again:
+ useMaster = 0;
+ code = krb5_sendto_kdc(ctx->k5c, &request, &realm,
+ &reply, &useMaster, tcpOnly);
+ if (code == KRB5_KDC_UNREACH || code == KRB5_REALM_UNKNOWN) {
+ krb5_error error;
+
+ memset(&error, 0, sizeof(error));
+ if (code == KRB5_KDC_UNREACH)
+ error.error = KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE;
+ else if (code == KRB5_REALM_UNKNOWN)
+ error.error = KRB_AP_ERR_IAKERB_KDC_NOT_FOUND;
+
+ code = krb5_mk_error(ctx->k5c, &error, &reply);
+ if (code != 0)
+ goto cleanup;
+ } else if (code == 0 && krb5_is_krb_error(&reply)) {
+ krb5_error *error;
+
+ code = decode_krb5_error(&reply, &error);
+ if (code != 0)
+ goto cleanup;
+
+ if (error && error->error == KRB_ERR_RESPONSE_TOO_BIG &&
+ tcpOnly == 0) {
+ tcpOnly = 1;
+ krb5_free_error(ctx->k5c, error);
+ krb5_free_data_contents(ctx->k5c, &reply);
+ goto send_again;
+ }
+ } else if (code != 0)
+ goto cleanup;
+
+ code = iakerb_make_token(ctx, &realm, NULL, &reply,
+ 0, output_token);
+ if (code != 0)
+ goto cleanup;
+
+ code = iakerb_save_token(ctx, output_token);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->count++;
+
+cleanup:
+ if (code != 0)
+ gss_release_buffer(&tmp, output_token);
+ /* request is a pointer into input_token, no need to free */
+ krb5_free_data_contents(ctx->k5c, &realm);
+ krb5_free_data_contents(ctx->k5c, &reply);
+
+ return code;
+}
+
+/*
+ * Initialise the krb5_init_creds context for the IAKERB context
+ */
+static krb5_error_code
+iakerb_init_creds_ctx(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ OM_uint32 time_req)
+{
+ krb5_error_code code;
+
+ if (cred->iakerb_mech == 0 || cred->password.data == NULL) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ assert(cred->name != NULL);
+ assert(cred->name->princ != NULL);
+
+ code = krb5_get_init_creds_opt_alloc(ctx->k5c, &ctx->gic_opts);
+ if (code != 0)
+ goto cleanup;
+
+ if (time_req != 0 && time_req != GSS_C_INDEFINITE)
+ krb5_get_init_creds_opt_set_tkt_life(ctx->gic_opts, time_req);
+
+ code = krb5_get_init_creds_opt_set_out_ccache(ctx->k5c, ctx->gic_opts,
+ cred->ccache);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_init_creds_init(ctx->k5c,
+ cred->name->princ,
+ NULL, /* prompter */
+ NULL, /* data */
+ 0, /* start_time */
+ ctx->gic_opts,
+ &ctx->u.icc);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_init_creds_set_password(ctx->k5c,
+ ctx->u.icc,
+ cred->password.data);
+ if (code != 0)
+ goto cleanup;
+
+cleanup:
+ return code;
+}
+
+/*
+ * Initialise the krb5_tkt_creds context for the IAKERB context
+ */
+static krb5_error_code
+iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ krb5_gss_name_t name,
+ OM_uint32 time_req)
+
+{
+ krb5_error_code code;
+ krb5_creds creds;
+ krb5_timestamp now;
+
+ assert(cred->name != NULL);
+ assert(cred->name->princ != NULL);
+
+ memset(&creds, 0, sizeof(creds));
+
+ creds.client = cred->name->princ;
+ creds.server = name->princ;
+
+ if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
+ code = krb5_timeofday(ctx->k5c, &now);
+ if (code != 0)
+ goto cleanup;
+
+ creds.times.endtime = now + time_req;
+ }
+
+ if (cred->name->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(ctx->k5c,
+ cred->name->ad_context,
+ AD_USAGE_TGS_REQ,
+ &creds.authdata);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_tkt_creds_init(ctx->k5c, cred->ccache,
+ &creds, 0, &ctx->u.tcc);
+ if (code != 0)
+ goto cleanup;
+
+cleanup:
+ krb5_free_authdata(ctx->k5c, creds.authdata);
+
+ return code;
+}
+
+/*
+ * Parse the IAKERB token in input_token and process the KDC
+ * response.
+ *
+ * Emit the next KDC request, if any, in output_token.
+ */
+static krb5_error_code
+iakerb_initiator_step(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ krb5_gss_name_t name,
+ OM_uint32 time_req,
+ const gss_buffer_t input_token,
+ gss_buffer_t output_token)
+{
+ krb5_error_code code;
+ krb5_data in, out, realm, *cookie = NULL;
+ OM_uint32 tmp;
+ int initialContextToken = (input_token == GSS_C_NO_BUFFER);
+ unsigned int flags = 0;
+ krb5_ticket_times times;
+
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ in.data = NULL;
+ in.length = 0;
+ out.data = NULL;
+ out.length = 0;
+ realm.data = NULL;
+ realm.length = 0;
+
+ if (initialContextToken) {
+ in.data = NULL;
+ in.length = 0;
+ } else {
+ code = iakerb_parse_token(ctx,
+ 0,
+ input_token,
+ NULL,
+ &cookie,
+ &in);
+ if (code != 0)
+ goto cleanup;
+
+ code = iakerb_save_token(ctx, input_token);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ switch (ctx->state) {
+ case IAKERB_AS_REQ:
+ if (ctx->u.icc == NULL) {
+ code = iakerb_init_creds_ctx(ctx, cred, time_req);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_init_creds_step(ctx->k5c,
+ ctx->u.icc,
+ &in,
+ &out,
+ &realm,
+ &flags);
+ if (code != 0)
+ goto cleanup;
+ if (flags != 0) {
+ krb5_init_creds_get_times(ctx->k5c, ctx->u.icc, ×);
+ cred->tgt_expire = times.endtime;
+
+ krb5_init_creds_free(ctx->k5c, ctx->u.icc);
+ ctx->u.icc = NULL;
+
+ ctx->state = IAKERB_TGS_REQ;
+ } else
+ break;
+ case IAKERB_TGS_REQ:
+ if (ctx->u.tcc == NULL) {
+ code = iakerb_tkt_creds_ctx(ctx, cred, name, time_req);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_tkt_creds_step(ctx->k5c,
+ ctx->u.tcc,
+ flags ? NULL : &in,
+ &out,
+ &realm,
+ &flags);
+ if (code != 0) {
+ /* we failed, but store any referrals in our ccache */
+ krb5_tkt_creds_store_creds(ctx->k5c, ctx->u.tcc, NULL);
+ goto cleanup;
+ }
+ if (flags != 0) {
+ code = krb5_tkt_creds_store_creds(ctx->k5c, ctx->u.tcc, NULL);
+ if (code != 0)
+ goto cleanup;
+
+ krb5_tkt_creds_get_times(ctx->k5c, ctx->u.tcc, ×);
+ cred->tgt_expire = times.endtime;
+
+ krb5_tkt_creds_free(ctx->k5c, ctx->u.tcc);
+ ctx->u.tcc = NULL;
+
+ ctx->state = IAKERB_AP_REQ;
+ } else
+ break;
+ case IAKERB_AP_REQ:
+ break;
+ }
+
+ if (out.length != 0) {
+ assert(ctx->state != IAKERB_AP_REQ);
+
+ code = iakerb_make_token(ctx, &realm, cookie, &out,
+ (input_token == GSS_C_NO_BUFFER),
+ output_token);
+ if (code != 0)
+ goto cleanup;
+
+ /* Save the token for generating a future checksum */
+ code = iakerb_save_token(ctx, output_token);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->count++;
+ }
+
+cleanup:
+ if (code != 0)
+ gss_release_buffer(&tmp, output_token);
+ krb5_free_data(ctx->k5c, cookie);
+ krb5_free_data_contents(ctx->k5c, &out);
+ krb5_free_data_contents(ctx->k5c, &realm);
+
+ return code;
+}
+
+/*
+ * Determine the starting IAKERB state for a context. If we already
+ * have a ticket, we may not need to do IAKERB at all.
+ */
+static krb5_error_code
+iakerb_get_initial_state(iakerb_ctx_id_t ctx,
+ krb5_gss_cred_id_t cred,
+ krb5_gss_name_t target,
+ OM_uint32 time_req,
+ enum iakerb_state *state)
+{
+ krb5_creds in_creds, *out_creds = NULL;
+ krb5_error_code code;
+
+ if (cred == NULL || cred->iakerb_mech == 0) {
+ *state = IAKERB_AP_REQ;
+ return 0;
+ }
+
+ memset(&in_creds, 0, sizeof(in_creds));
+
+ in_creds.client = cred->name->princ;
+ in_creds.server = target->princ;
+
+ if (cred->name->ad_context != NULL) {
+ code = krb5_authdata_export_authdata(ctx->k5c,
+ cred->name->ad_context,
+ AD_USAGE_TGS_REQ,
+ &in_creds.authdata);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(ctx->k5c, &now);
+ if (code != 0)
+ goto cleanup;
+
+ in_creds.times.endtime = now + time_req;
+ }
+
+ code = krb5_get_credentials(ctx->k5c, KRB5_GC_CACHED,
+ cred->ccache,
+ &in_creds, &out_creds);
+ if (code == KRB5_CC_NOTFOUND) {
+ krb5_principal tgs;
+ krb5_data *realm = krb5_princ_realm(ctx->k5c, in_creds.client);
+
+ /* If we have a TGT for the client realm, can proceed to TGS-REQ. */
+ code = krb5_build_principal_ext(ctx->k5c,
+ &tgs,
+ realm->length,
+ realm->data,
+ KRB5_TGS_NAME_SIZE,
+ KRB5_TGS_NAME,
+ realm->length,
+ realm->data,
+ NULL);
+ if (code != 0)
+ goto cleanup;
+
+ in_creds.server = tgs;
+
+ code = krb5_get_credentials(ctx->k5c, KRB5_GC_CACHED,
+ cred->ccache,
+ &in_creds, &out_creds);
+ if (code == KRB5_CC_NOTFOUND) {
+ *state = IAKERB_AS_REQ;
+ code = 0;
+ } else if (code == 0) {
+ *state = IAKERB_TGS_REQ;
+ krb5_free_creds(ctx->k5c, out_creds);
+ }
+ krb5_free_principal(ctx->k5c, tgs);
+ } else if (code == 0) {
+ *state = IAKERB_AP_REQ;
+ krb5_free_creds(ctx->k5c, out_creds);
+ }
+
+cleanup:
+ krb5_free_authdata(ctx->k5c, in_creds.authdata);
+
+ return code;
+}
+
+/*
+ * Allocate and initialise an IAKERB context
+ */
+static krb5_error_code
+iakerb_alloc_context(iakerb_ctx_id_t *pctx)
+{
+ iakerb_ctx_id_t ctx;
+ krb5_error_code code;
+
+ *pctx = NULL;
+
+ ctx = k5alloc(sizeof(*ctx), &code);
+ if (ctx == NULL)
+ goto cleanup;
+ ctx->magic = KG_IAKERB_CONTEXT;
+ ctx->state = IAKERB_AS_REQ;
+ ctx->count = 0;
+
+ code = krb5_gss_init_context(&ctx->k5c);
+ if (code != 0)
+ goto cleanup;
+
+ *pctx = ctx;
+
+cleanup:
+ if (code != 0)
+ iakerb_release_context(ctx);
+
+ return code;
+}
+
+/*
+ * Delete an IAKERB context. This can also accept Kerberos context
+ * handles. The heuristic is similar to SPNEGO's delete_sec_context.
+ */
+OM_uint32
+iakerb_gss_delete_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_buffer_t output_token)
+{
+ OM_uint32 major_status = GSS_S_COMPLETE;
+
+ if (output_token != GSS_C_NO_BUFFER) {
+ output_token->length = 0;
+ output_token->value = NULL;
+ }
+
+ *minor_status = 0;
+
+ if (*context_handle != GSS_C_NO_CONTEXT) {
+ iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle;
+
+ if (iakerb_ctx->magic == KG_IAKERB_CONTEXT) {
+ iakerb_release_context(iakerb_ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ } else {
+ assert(iakerb_ctx->magic == KG_CONTEXT);
+
+ major_status = krb5_gss_delete_sec_context(minor_status,
+ context_handle,
+ output_token);
+ }
+ }
+
+ return major_status;
+}
+
+static krb5_boolean
+iakerb_is_iakerb_token(const gss_buffer_t token)
+{
+ krb5_error_code code;
+ unsigned int bodysize = token->length;
+ unsigned char *ptr = token->value;
+
+ code = g_verify_token_header(gss_mech_iakerb,
+ &bodysize, &ptr,
+ IAKERB_TOK_PROXY,
+ token->length, 0);
+
+ return (code == 0);
+}
+
+static void
+iakerb_make_exts(iakerb_ctx_id_t ctx, krb5_gss_ctx_ext_rec *exts)
+{
+ memset(exts, 0, sizeof(*exts));
+
+ if (ctx->conv.length != 0)
+ exts->iakerb.conv = &ctx->conv;
+}
+
+/*
+ *
+ */
+OM_uint32
+iakerb_gss_accept_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t *context_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_buffer_t input_token,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_name_t *src_name,
+ gss_OID *mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ gss_cred_id_t *delegated_cred_handle)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ OM_uint32 code;
+ iakerb_ctx_id_t ctx;
+ int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
+
+ if (initialContextToken) {
+ code = iakerb_alloc_context(&ctx);
+ if (code != 0)
+ goto cleanup;
+
+ } else
+ ctx = (iakerb_ctx_id_t)*context_handle;
+
+ if (iakerb_is_iakerb_token(input_token)) {
+ if (ctx->u.gssc != GSS_C_NO_CONTEXT) {
+ /* We shouldn't get an IAKERB token now. */
+ code = G_WRONG_TOKID;
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
+ code = iakerb_acceptor_step(ctx, initialContextToken,
+ input_token, output_token);
+ if (code == (OM_uint32)KRB5_BAD_MSIZE)
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ if (code != 0)
+ goto cleanup;
+ if (initialContextToken) {
+ *context_handle = (gss_ctx_id_t)ctx;
+ ctx = NULL;
+ }
+ if (src_name != NULL)
+ *src_name = GSS_C_NO_NAME;
+ if (mech_type != NULL)
+ *mech_type = (gss_OID)gss_mech_iakerb;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ if (delegated_cred_handle != NULL)
+ *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+ major_status = GSS_S_CONTINUE_NEEDED;
+ } else {
+ krb5_gss_ctx_ext_rec exts;
+
+ iakerb_make_exts(ctx, &exts);
+
+ major_status = krb5_gss_accept_sec_context_ext(&code,
+ &ctx->u.gssc,
+ verifier_cred_handle,
+ input_token,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle,
+ &exts);
+ if (major_status == GSS_S_COMPLETE) {
+ *context_handle = ctx->u.gssc;
+ ctx->u.gssc = NULL;
+ iakerb_release_context(ctx);
+ }
+ }
+
+cleanup:
+ if (initialContextToken && GSS_ERROR(major_status)) {
+ iakerb_release_context(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+
+ *minor_status = code;
+ return major_status;
+}
+
+OM_uint32
+iakerb_gss_init_sec_context(OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major_status = GSS_S_FAILURE;
+ krb5_error_code code;
+ iakerb_ctx_id_t ctx;
+ krb5_gss_cred_id_t kcred;
+ krb5_gss_name_t kname;
+ int credLocked = 0;
+ int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
+
+ if (initialContextToken) {
+ code = iakerb_alloc_context(&ctx);
+ if (code != 0) {
+ *minor_status = code;
+ goto cleanup;
+ }
+ } else
+ ctx = (iakerb_ctx_id_t)*context_handle;
+
+ if (!kg_validate_name(target_name)) {
+ *minor_status = G_VALIDATE_FAILED;
+ major_status = GSS_S_CALL_BAD_STRUCTURE | GSS_S_BAD_NAME;
+ goto cleanup;
+ }
+
+ kname = (krb5_gss_name_t)target_name;
+
+ if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
+ major_status = krb5_gss_validate_cred_1(minor_status,
+ claimant_cred_handle,
+ ctx->k5c);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ credLocked = 1;
+ kcred = (krb5_gss_cred_id_t)claimant_cred_handle;
+ } else
+ kcred = NULL;
+
+ major_status = GSS_S_FAILURE;
+
+ if (initialContextToken) {
+ code = iakerb_get_initial_state(ctx, kcred, kname, time_req,
+ &ctx->state);
+ if (code != 0) {
+ *minor_status = code;
+ goto cleanup;
+ }
+ *context_handle = (gss_ctx_id_t)ctx;
+ }
+
+ if (ctx->state != IAKERB_AP_REQ) {
+ /* We need to do IAKERB. */
+ code = iakerb_initiator_step(ctx,
+ kcred,
+ kname,
+ time_req,
+ input_token,
+ output_token);
+ if (code == KRB5_BAD_MSIZE)
+ major_status = GSS_S_DEFECTIVE_TOKEN;
+ if (code != 0) {
+ *minor_status = code;
+ goto cleanup;
+ }
+ }
+
+ if (ctx->state == IAKERB_AP_REQ) {
+ krb5_gss_ctx_ext_rec exts;
+
+ /* Ensure cred is marked as usable for Kerberos mechanism */
+ if (kcred != NULL) {
+ if (kcred->iakerb_mech)
+ kcred->rfc_mech = 1;
+
+ k5_mutex_unlock(&kcred->lock);
+ credLocked = 0;
+ }
+
+ iakerb_make_exts(ctx, &exts);
+
+ if (ctx->u.gssc == GSS_C_NO_CONTEXT)
+ input_token = GSS_C_NO_BUFFER;
+
+ /* IAKERB is finished, or we skipped to Kerberos directly. */
+ major_status = krb5_gss_init_sec_context_ext(minor_status,
+ claimant_cred_handle,
+ &ctx->u.gssc,
+ target_name,
+ GSS_C_NULL_OID,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ &exts);
+ if (major_status == GSS_S_COMPLETE) {
+ *context_handle = ctx->u.gssc;
+ ctx->u.gssc = GSS_C_NO_CONTEXT;
+ iakerb_release_context(ctx);
+ }
+ } else {
+ if (actual_mech_type != NULL)
+ *actual_mech_type = (gss_OID)gss_mech_iakerb;
+ if (ret_flags != NULL)
+ *ret_flags = 0;
+ if (time_rec != NULL)
+ *time_rec = 0;
+ major_status = GSS_S_CONTINUE_NEEDED;
+ }
+
+cleanup:
+ if (credLocked)
+ k5_mutex_unlock(&kcred->lock);
+ if (initialContextToken && GSS_ERROR(major_status)) {
+ iakerb_release_context(ctx);
+ *context_handle = GSS_C_NO_CONTEXT;
+ }
+
+ return major_status;
+}
+
Modified: branches/iakerb/src/lib/gssapi/krb5/init_sec_context.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/init_sec_context.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/init_sec_context.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -195,8 +195,36 @@
goto cleanup;
}
+ /* Don't go out over the network if we used IAKERB */
+ if (cred->iakerb_mech)
+ flags |= KRB5_GC_CACHED;
+
code = krb5_get_credentials(context, flags, cred->ccache,
&in_creds, out_creds);
+ if (code == KRB5_NO_TKT_IN_RLM && cred->password.data != NULL) {
+ krb5_creds tgt_creds;
+
+ memset(&tgt_creds, 0, sizeof(tgt_creds));
+
+ code = krb5_get_init_creds_password(context, &tgt_creds,
+ in_creds.client,
+ cred->password.data,
+ NULL, NULL,
+ 0, NULL, NULL);
+ if (code)
+ goto cleanup;
+
+ code = krb5_cc_store_cred(context, cred->ccache, &tgt_creds);
+ if (code) {
+ krb5_free_cred_contents(context, &tgt_creds);
+ goto cleanup;
+ }
+ cred->tgt_expire = tgt_creds.times.endtime;
+ krb5_free_cred_contents(context, &tgt_creds);
+
+ code = krb5_get_credentials(context, flags, cred->ccache,
+ &in_creds, out_creds);
+ }
if (code)
goto cleanup;
@@ -232,11 +260,9 @@
krb5_gss_cred_id_t cred;
krb5_checksum md5;
krb5_data checksum_data;
+ krb5_gss_ctx_ext_t exts;
};
-#ifdef CFX_EXERCISE
-#include "../../krb5/krb/auth_con.h"
-#endif
static krb5_error_code KRB5_CALLCONV
make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
void *cksum_data, krb5_data **out)
@@ -247,6 +273,7 @@
struct gss_checksum_data *data = cksum_data;
krb5_data credmsg;
unsigned int junk;
+ krb5_data *finished = NULL;
data->checksum_data.data = 0;
credmsg.data = 0;
@@ -279,8 +306,8 @@
data->checksum_data.length = 24;
} else {
if (credmsg.length+28 > KRB5_INT16_MAX) {
- krb5_free_data_contents(context, &credmsg);
- return(KRB5KRB_ERR_FIELD_TOOLONG);
+ code = KRB5KRB_ERR_FIELD_TOOLONG;
+ goto cleanup;
}
data->checksum_data.length = 28+credmsg.length;
@@ -302,6 +329,26 @@
junk = 0;
#endif
+ assert(data->exts != NULL);
+
+ if (data->exts->iakerb.conv) {
+ krb5_key key;
+
+ code = krb5_auth_con_getsendsubkey_k(context, auth_context, &key);
+ if (code != 0)
+ goto cleanup;
+
+ code = iakerb_make_finished(context, key, data->exts->iakerb.conv,
+ &finished);
+ if (code != 0) {
+ krb5_k_free_key(context, key);
+ goto cleanup;
+ }
+
+ krb5_k_free_key(context, key);
+ data->checksum_data.length += 8 + finished->length;
+ }
+
data->checksum_data.length += junk;
/* now allocate a buffer to hold the checksum data and
@@ -309,9 +356,8 @@
if ((data->checksum_data.data =
(char *) xmalloc(data->checksum_data.length)) == NULL) {
- if (credmsg.data)
- krb5_free_data_contents(context, &credmsg);
- return(ENOMEM);
+ code = ENOMEM;
+ goto cleanup;
}
ptr = (unsigned char *)data->checksum_data.data;
@@ -327,19 +373,25 @@
TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0);
TWRITE_INT16(ptr, credmsg.length, 0);
TWRITE_STR(ptr, credmsg.data, credmsg.length);
-
- /* free credmsg data */
- krb5_free_data_contents(context, &credmsg);
}
+ if (data->exts->iakerb.conv) {
+ TWRITE_INT(ptr, KRB5_GSS_EXTS_IAKERB_FINISHED, 1);
+ TWRITE_INT(ptr, finished->length, 1);
+ TWRITE_STR(ptr, finished->data, finished->length);
+ }
if (junk)
memset(ptr, 'i', junk);
*out = &data->checksum_data;
- return 0;
+ code = 0;
+cleanup:
+ krb5_free_data_contents(context, &credmsg);
+ krb5_free_data(context, finished);
+ return code;
}
static krb5_error_code
make_ap_req_v1(context, ctx, cred, k_cred, ad_context,
- chan_bindings, mech_type, token)
+ chan_bindings, mech_type, token, exts)
krb5_context context;
krb5_gss_ctx_id_rec *ctx;
krb5_gss_cred_id_t cred;
@@ -348,6 +400,7 @@
gss_channel_bindings_t chan_bindings;
gss_OID mech_type;
gss_buffer_t token;
+ krb5_gss_ctx_ext_t exts;
{
krb5_flags mk_req_flags = 0;
krb5_error_code code;
@@ -373,6 +426,7 @@
cksum_struct.ctx = ctx;
cksum_struct.cred = cred;
cksum_struct.checksum_data.data = NULL;
+ cksum_struct.exts = exts;
switch (k_cred->keyblock.enctype) {
case ENCTYPE_DES_CBC_CRC:
case ENCTYPE_DES_CBC_MD4:
@@ -474,7 +528,8 @@
OM_uint32 *ret_flags,
OM_uint32 *time_rec,
krb5_context context,
- int default_mech)
+ int default_mech,
+ krb5_gss_ctx_ext_t exts)
{
OM_uint32 major_status;
krb5_error_code code;
@@ -514,6 +569,7 @@
/* fill in the ctx */
memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+ ctx->magic = KG_CONTEXT;
ctx_free = ctx;
if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
goto fail;
@@ -592,7 +648,7 @@
if ((code = make_ap_req_v1(context, ctx,
cred, k_cred, ctx->here->ad_context,
input_chan_bindings,
- mech_type, &token))) {
+ mech_type, &token, exts))) {
if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
(code == KG_EMPTY_CCACHE))
major_status = GSS_S_NO_CRED;
@@ -703,7 +759,8 @@
gss_buffer_t output_token,
OM_uint32 *ret_flags,
OM_uint32 *time_rec,
- krb5_context context)
+ krb5_context context,
+ krb5_gss_ctx_ext_t exts)
{
OM_uint32 major_status;
unsigned char *ptr;
@@ -878,24 +935,21 @@
}
OM_uint32
-krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
- context_handle, target_name, mech_type,
- req_flags, time_req, input_chan_bindings,
- input_token, actual_mech_type, output_token,
- ret_flags, time_rec)
- OM_uint32 *minor_status;
- gss_cred_id_t claimant_cred_handle;
- gss_ctx_id_t *context_handle;
- gss_name_t target_name;
- gss_OID mech_type;
- OM_uint32 req_flags;
- OM_uint32 time_req;
- gss_channel_bindings_t input_chan_bindings;
- gss_buffer_t input_token;
- gss_OID *actual_mech_type;
- gss_buffer_t output_token;
- OM_uint32 *ret_flags;
- OM_uint32 *time_rec;
+krb5_gss_init_sec_context_ext(
+ OM_uint32 *minor_status,
+ gss_cred_id_t claimant_cred_handle,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ krb5_gss_ctx_ext_t exts)
{
krb5_context context;
krb5_gss_cred_id_t cred;
@@ -1013,7 +1067,7 @@
time_req, input_chan_bindings,
input_token, actual_mech_type,
output_token, ret_flags, time_rec,
- context, default_mech);
+ context, default_mech, exts);
k5_mutex_unlock(&cred->lock);
if (*context_handle == GSS_C_NO_CONTEXT) {
save_error_info (*minor_status, context);
@@ -1028,7 +1082,7 @@
time_req, input_chan_bindings,
input_token, actual_mech_type,
output_token, ret_flags, time_rec,
- context);
+ context, exts);
/* If context_handle is now NO_CONTEXT, mutual_auth called
delete_sec_context, which would've zapped the krb5 context
too. */
@@ -1093,3 +1147,44 @@
return GSS_S_COMPLETE;
}
#endif
+
+OM_uint32
+krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
+ context_handle, target_name, mech_type,
+ req_flags, time_req, input_chan_bindings,
+ input_token, actual_mech_type, output_token,
+ ret_flags, time_rec)
+ OM_uint32 *minor_status;
+ gss_cred_id_t claimant_cred_handle;
+ gss_ctx_id_t *context_handle;
+ gss_name_t target_name;
+ gss_OID mech_type;
+ OM_uint32 req_flags;
+ OM_uint32 time_req;
+ gss_channel_bindings_t input_chan_bindings;
+ gss_buffer_t input_token;
+ gss_OID *actual_mech_type;
+ gss_buffer_t output_token;
+ OM_uint32 *ret_flags;
+ OM_uint32 *time_rec;
+{
+ krb5_gss_ctx_ext_rec exts;
+
+ memset(&exts, 0, sizeof(exts));
+
+ return krb5_gss_init_sec_context_ext(minor_status,
+ claimant_cred_handle,
+ context_handle,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ actual_mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ &exts);
+}
+
Modified: branches/iakerb/src/lib/gssapi/krb5/inq_cred.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/inq_cred.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/inq_cred.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -166,6 +166,10 @@
(cred->rfc_mech &&
GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
gss_mech_krb5,
+ &mechs))) ||
+ (cred->iakerb_mech &&
+ GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_iakerb,
&mechs)))) {
k5_mutex_unlock(&cred->lock);
if (ret_name)
Modified: branches/iakerb/src/lib/gssapi/krb5/inq_names.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/inq_names.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/inq_names.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -44,7 +44,8 @@
*/
if ((mechanism != GSS_C_NULL_OID) &&
!g_OID_equal(gss_mech_krb5, mechanism) &&
- !g_OID_equal(gss_mech_krb5_old, mechanism)) {
+ !g_OID_equal(gss_mech_krb5_old, mechanism) &&
+ !g_OID_equal(gss_mech_iakerb, mechanism)) {
*minor_status = 0;
return(GSS_S_BAD_MECH);
}
Modified: branches/iakerb/src/lib/gssapi/krb5/rel_cred.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/rel_cred.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/rel_cred.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -77,6 +77,11 @@
if (cred->req_enctypes)
free(cred->req_enctypes);
+ if (cred->password.data) {
+ zap(cred->password.data, cred->password.length);
+ krb5_free_data_contents(context, &cred->password);
+ }
+
xfree(cred);
*cred_handle = NULL;
Modified: branches/iakerb/src/lib/gssapi/krb5/ser_sctx.c
===================================================================
--- branches/iakerb/src/lib/gssapi/krb5/ser_sctx.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/krb5/ser_sctx.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -610,6 +610,7 @@
xmalloc(sizeof(krb5_gss_ctx_id_rec)))) {
memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+ ctx->magic = ibuf;
ctx->k5_context = kcontext;
/* Get static data */
Modified: branches/iakerb/src/lib/gssapi/libgssapi_krb5.exports
===================================================================
--- branches/iakerb/src/lib/gssapi/libgssapi_krb5.exports 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/libgssapi_krb5.exports 2010-03-29 16:18:20 UTC (rev 23843)
@@ -9,6 +9,7 @@
GSS_KRB5_NT_PRINCIPAL_NAME
gss_accept_sec_context
gss_acquire_cred
+gss_acquire_cred_with_password
gss_acquire_cred_impersonate_name
gss_add_buffer_set_member
gss_add_cred
@@ -54,6 +55,7 @@
gsskrb5_extract_authtime_from_sec_context
gsskrb5_extract_authz_data_from_sec_context
gss_map_name_to_any
+gss_mech_iakerb
gss_mech_krb5
gss_mech_krb5_old
gss_mech_set_krb5
Modified: branches/iakerb/src/lib/gssapi/mechglue/Makefile.in
===================================================================
--- branches/iakerb/src/lib/gssapi/mechglue/Makefile.in 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/mechglue/Makefile.in 2010-03-29 16:18:20 UTC (rev 23843)
@@ -12,6 +12,7 @@
SRCS = \
$(srcdir)/g_accept_sec_context.c \
$(srcdir)/g_acquire_cred.c \
+ $(srcdir)/g_acquire_cred_with_pw.c \
$(srcdir)/g_acquire_cred_imp_name.c \
$(srcdir)/g_buffer_set.c \
$(srcdir)/g_canon_name.c \
@@ -67,6 +68,7 @@
OBJS = \
$(OUTPRE)g_accept_sec_context.$(OBJEXT) \
$(OUTPRE)g_acquire_cred.$(OBJEXT) \
+ $(OUTPRE)g_acquire_cred_with_pw.$(OBJEXT) \
$(OUTPRE)g_acquire_cred_imp_name.$(OBJEXT) \
$(OUTPRE)g_buffer_set.$(OBJEXT) \
$(OUTPRE)g_canon_name.$(OBJEXT) \
@@ -122,6 +124,7 @@
STLIBOBJS = \
g_accept_sec_context.o \
g_acquire_cred.o \
+ g_acquire_cred_with_pw.o \
g_acquire_cred_imp_name.o \
g_buffer_set.o \
g_canon_name.o \
Added: branches/iakerb/src/lib/gssapi/mechglue/g_acquire_cred_with_pw.c
===================================================================
--- branches/iakerb/src/lib/gssapi/mechglue/g_acquire_cred_with_pw.c (rev 0)
+++ branches/iakerb/src/lib/gssapi/mechglue/g_acquire_cred_with_pw.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -0,0 +1,544 @@
+/* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * glue routine for gss_acquire_cred_with_password
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static OM_uint32
+val_acq_cred_pw_args(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ int cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NULL_OID_SET;
+
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ if (password == GSS_C_NO_BUFFER ||
+ password->length == 0 ||
+ password->value == NULL) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_with_password(
+ minor_status,
+ desired_name,
+ password,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec)
+
+OM_uint32 * minor_status;
+const gss_name_t desired_name;
+const gss_buffer_t password;
+OM_uint32 time_req;
+const gss_OID_set desired_mechs;
+int cred_usage;
+gss_cred_id_t * output_cred_handle;
+gss_OID_set * actual_mechs;
+OM_uint32 * time_rec;
+{
+ OM_uint32 major = GSS_S_FAILURE;
+ OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+ gss_OID_set_desc default_OID_set;
+ gss_OID_set mechs;
+ gss_OID_desc default_OID;
+ gss_mechanism mech;
+ unsigned int i;
+ gss_union_cred_t creds;
+
+ major = val_acq_cred_pw_args(minor_status,
+ desired_name,
+ password,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec);
+ if (major != GSS_S_COMPLETE)
+ return (major);
+
+ /* Initial value needed below. */
+ major = GSS_S_FAILURE;
+
+ /*
+ * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
+ * appropriate default. We use the first mechanism in the
+ * mechansim list as the default. This set is created with
+ * statics thus needs not be freed
+ */
+ if(desired_mechs == GSS_C_NULL_OID_SET) {
+ mech = gssint_get_mechanism(NULL);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ mechs = &default_OID_set;
+ default_OID_set.count = 1;
+ default_OID_set.elements = &default_OID;
+ default_OID.length = mech->mech_type.length;
+ default_OID.elements = mech->mech_type.elements;
+ } else
+ mechs = desired_mechs;
+
+ if (mechs->count == 0)
+ return (GSS_S_BAD_MECH);
+
+ /* allocate the output credential structure */
+ creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+ if (creds == NULL)
+ return (GSS_S_FAILURE);
+
+ /* initialize to 0s */
+ (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+ creds->loopback = creds;
+
+ /* for each requested mech attempt to obtain a credential */
+ for (i = 0; i < mechs->count; i++) {
+ major = gss_add_cred_with_password(minor_status, (gss_cred_id_t)creds,
+ desired_name,
+ &mechs->elements[i],
+ password,
+ cred_usage, time_req, time_req, NULL,
+ NULL, &initTimeOut, &acceptTimeOut);
+ if (major == GSS_S_COMPLETE) {
+ /* update the credential's time */
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (outTime > acceptTimeOut)
+ outTime = acceptTimeOut;
+ } else if (cred_usage == GSS_C_INITIATE) {
+ if (outTime > initTimeOut)
+ outTime = initTimeOut;
+ } else {
+ /*
+ * time_rec is the lesser of the
+ * init/accept times
+ */
+ if (initTimeOut > acceptTimeOut)
+ outTime = (outTime > acceptTimeOut) ?
+ acceptTimeOut : outTime;
+ else
+ outTime = (outTime > initTimeOut) ?
+ initTimeOut : outTime;
+ }
+ }
+ } /* for */
+
+ /* ensure that we have at least one credential element */
+ if (creds->count < 1) {
+ free(creds);
+ return (major);
+ }
+
+ /*
+ * fill in output parameters
+ * setup the actual mechs output parameter
+ */
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = creds->count;
+ oids.elements = creds->mechs_array;
+
+ major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(major)) {
+ (void) gss_release_cred(minor_status,
+ (gss_cred_id_t *)&creds);
+ return (major);
+ }
+ }
+
+ if (time_rec)
+ *time_rec = outTime;
+
+
+ creds->loopback = creds;
+ *output_cred_handle = (gss_cred_id_t)creds;
+ return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+val_add_cred_pw_args(
+ OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_name_t desired_name,
+ const gss_OID desired_mech,
+ const gss_buffer_t password,
+ gss_cred_usage_t cred_usage,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+
+ if (acceptor_time_rec != NULL)
+ *acceptor_time_rec = 0;
+
+ if (initiator_time_rec != NULL)
+ *initiator_time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+ output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ if (password == GSS_C_NO_BUFFER ||
+ password->length == 0 ||
+ password->value == NULL) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+
+ return (GSS_S_COMPLETE);
+}
+
+
+/* V2 KRB5_CALLCONV */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_with_password(minor_status, input_cred_handle,
+ desired_name, desired_mech, password, cred_usage,
+ initiator_time_req, acceptor_time_req,
+ output_cred_handle, actual_mechs,
+ initiator_time_rec, acceptor_time_rec)
+ OM_uint32 *minor_status;
+ const gss_cred_id_t input_cred_handle;
+ const gss_name_t desired_name;
+ const gss_OID desired_mech;
+ const gss_buffer_t password;
+ gss_cred_usage_t cred_usage;
+ OM_uint32 initiator_time_req;
+ OM_uint32 acceptor_time_req;
+ gss_cred_id_t *output_cred_handle;
+ gss_OID_set *actual_mechs;
+ OM_uint32 *initiator_time_rec;
+ OM_uint32 *acceptor_time_rec;
+{
+ OM_uint32 status, temp_minor_status;
+ OM_uint32 time_req, time_rec;
+ gss_union_name_t union_name;
+ gss_union_cred_t new_union_cred, union_cred;
+ gss_name_t internal_name = GSS_C_NO_NAME;
+ gss_name_t allocated_name = GSS_C_NO_NAME;
+ gss_mechanism mech;
+ gss_mechanism_ext mech_ext;
+ gss_cred_id_t cred = NULL;
+ gss_OID new_mechs_array = NULL;
+ gss_cred_id_t * new_cred_array = NULL;
+
+ status = val_add_cred_pw_args(minor_status,
+ input_cred_handle,
+ desired_name,
+ desired_mech,
+ password,
+ cred_usage,
+ initiator_time_req,
+ acceptor_time_req,
+ output_cred_handle,
+ actual_mechs,
+ initiator_time_rec,
+ acceptor_time_rec);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ mech = gssint_get_mechanism(desired_mech);
+ if (!mech)
+ return GSS_S_BAD_MECH;
+
+ mech_ext = gssint_get_mechanism_ext(desired_mech);
+ if (!mech_ext || !mech_ext->gssspi_acquire_cred_with_password)
+ return GSS_S_UNAVAILABLE;
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (union_cred == NULL)
+ return (GSS_S_FAILURE);
+
+ (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+ /* for default credentials we will use GSS_C_NO_NAME */
+ internal_name = GSS_C_NO_NAME;
+ } else {
+ union_cred = (gss_union_cred_t)input_cred_handle;
+ if (gssint_get_mechanism_cred(union_cred, desired_mech) !=
+ GSS_C_NO_CREDENTIAL)
+ return (GSS_S_DUPLICATE_ELEMENT);
+
+ /* may need to create a mechanism specific name */
+ if (desired_name) {
+ union_name = (gss_union_name_t)desired_name;
+ if (union_name->mech_type &&
+ g_OID_equal(union_name->mech_type,
+ &mech->mech_type))
+ internal_name = union_name->mech_name;
+ else {
+ if (gssint_import_internal_name(minor_status,
+ &mech->mech_type, union_name,
+ &allocated_name) != GSS_S_COMPLETE)
+ return (GSS_S_BAD_NAME);
+ internal_name = allocated_name;
+ }
+ }
+ }
+
+
+ if (cred_usage == GSS_C_ACCEPT)
+ time_req = acceptor_time_req;
+ else if (cred_usage == GSS_C_INITIATE)
+ time_req = initiator_time_req;
+ else if (cred_usage == GSS_C_BOTH)
+ time_req = (acceptor_time_req > initiator_time_req) ?
+ acceptor_time_req : initiator_time_req;
+ else
+ time_req = 0;
+
+ status = mech_ext->gssspi_acquire_cred_with_password(minor_status,
+ internal_name,
+ password,
+ time_req,
+ GSS_C_NULL_OID_SET,
+ cred_usage,
+ &cred,
+ NULL,
+ &time_rec);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto errout;
+ }
+
+ /* may need to set credential auxinfo strucutre */
+ if (union_cred->auxinfo.creation_time == 0) {
+ union_cred->auxinfo.creation_time = time(NULL);
+ union_cred->auxinfo.time_rec = time_rec;
+ union_cred->auxinfo.cred_usage = cred_usage;
+
+ /*
+ * we must set the name; if name is not supplied
+ * we must do inquire cred to get it
+ */
+ if (internal_name == NULL) {
+ if (mech->gss_inquire_cred == NULL ||
+ ((status = mech->gss_inquire_cred(
+ &temp_minor_status, cred,
+ &allocated_name, NULL, NULL,
+ NULL)) != GSS_S_COMPLETE))
+ goto errout;
+ internal_name = allocated_name;
+ }
+
+ if (internal_name != GSS_C_NO_NAME) {
+ status = mech->gss_display_name(&temp_minor_status, internal_name,
+ &union_cred->auxinfo.name,
+ &union_cred->auxinfo.name_type);
+
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+ }
+ }
+
+ /* now add the new credential elements */
+ new_mechs_array = (gss_OID)
+ malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
+ new_cred_array = (gss_cred_id_t *)
+ malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
+
+ if (!new_mechs_array || !new_cred_array) {
+ status = GSS_S_FAILURE;
+ goto errout;
+ }
+
+ if (acceptor_time_rec)
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
+ *acceptor_time_rec = time_rec;
+ if (initiator_time_rec)
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
+ *initiator_time_rec = time_rec;
+
+ /*
+ * OK, expand the mechanism array and the credential array
+ */
+ (void) memcpy(new_mechs_array, union_cred->mechs_array,
+ sizeof (gss_OID_desc) * union_cred->count);
+ (void) memcpy(new_cred_array, union_cred->cred_array,
+ sizeof (gss_cred_id_t) * union_cred->count);
+
+ new_cred_array[union_cred->count] = cred;
+ if ((new_mechs_array[union_cred->count].elements =
+ malloc(mech->mech_type.length)) == NULL)
+ goto errout;
+
+ g_OID_copy(&new_mechs_array[union_cred->count],
+ &mech->mech_type);
+
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = union_cred->count + 1;
+ oids.elements = new_mechs_array;
+
+ status = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(status)) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ }
+
+ if (output_cred_handle == NULL) {
+ free(union_cred->mechs_array);
+ free(union_cred->cred_array);
+ new_union_cred = union_cred;
+ } else {
+ new_union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (new_union_cred == NULL) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ *new_union_cred = *union_cred;
+ *output_cred_handle = (gss_cred_id_t)new_union_cred;
+ }
+
+ new_union_cred->mechs_array = new_mechs_array;
+ new_union_cred->cred_array = new_cred_array;
+ new_union_cred->count++;
+ new_union_cred->loopback = new_union_cred;
+
+ /* We're done with the internal name. Free it if we allocated it. */
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &allocated_name);
+
+ return (GSS_S_COMPLETE);
+
+errout:
+ if (new_mechs_array)
+ free(new_mechs_array);
+ if (new_cred_array)
+ free(new_cred_array);
+
+ if (cred != NULL && mech->gss_release_cred)
+ mech->gss_release_cred(&temp_minor_status, &cred);
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &allocated_name);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
+ if (union_cred->auxinfo.name.value)
+ free(union_cred->auxinfo.name.value);
+ free(union_cred);
+ }
+
+ return (status);
+}
Modified: branches/iakerb/src/lib/gssapi/mechglue/g_initialize.c
===================================================================
--- branches/iakerb/src/lib/gssapi/mechglue/g_initialize.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/mechglue/g_initialize.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -609,6 +609,10 @@
memset(cf->mech, 0, sizeof(*cf->mech));
free(cf->mech);
}
+ if (cf->mech_ext != NULL) {
+ memset(cf->mech_ext, 0, sizeof(*cf->mech_ext));
+ free(cf->mech_ext);
+ }
if (cf->dl_handle != NULL)
krb5int_close_plugin(cf->dl_handle);
@@ -646,6 +650,16 @@
new_cf->freeMech = 1;
new_cf->next = NULL;
+ if (template->mech_ext != NULL) {
+ new_cf->mech_ext = (gss_mechanism_ext)calloc(1,
+ sizeof(struct gss_config_ext));
+ if (new_cf->mech_ext == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ *new_cf->mech_ext = *template->mech_ext;
+ }
+
if (template->kmodName != NULL) {
new_cf->kmodName = strdup(template->kmodName);
if (new_cf->kmodName == NULL) {
@@ -785,6 +799,21 @@
return mech;
}
+static gss_mechanism_ext
+build_dynamicMechExt(void *dl, const gss_OID mech_type)
+{
+ gss_mechanism_ext mech_ext;
+
+ mech_ext = (gss_mechanism_ext)calloc(1, sizeof(*mech_ext));
+ if (mech_ext == NULL) {
+ return NULL;
+ }
+
+ GSS_ADD_DYNAMIC_METHOD(dl, mech_ext, gssspi_acquire_cred_with_password);
+
+ return mech_ext;
+}
+
static void
freeMechList(void)
{
@@ -828,8 +857,8 @@
gssint_get_mechanism(oid)
const gss_OID oid;
{
- gss_mech_info aMech;
- gss_mechanism (*sym)(const gss_OID);
+ gss_mech_info aMech;
+ gss_mechanism (*sym)(const gss_OID);
struct plugin_file_handle *dl;
struct errinfo errinfo;
@@ -905,60 +934,51 @@
gssint_get_mechanism_ext(oid)
const gss_OID oid;
{
- gss_mech_info aMech;
- gss_mechanism_ext mech_ext;
+ gss_mech_info aMech;
if (gssint_mechglue_initialize_library() != 0)
return (NULL);
+ if (k5_mutex_lock(&g_mechListLock) != 0)
+ return NULL;
/* check if the mechanism is already loaded */
- if ((aMech = searchMechList(oid)) != NULL && aMech->mech_ext != NULL)
+ if ((aMech = searchMechList(oid)) != NULL && aMech->mech_ext) {
+ (void) k5_mutex_unlock(&g_mechListLock);
return (aMech->mech_ext);
+ }
- if (gssint_get_mechanism(oid) == NULL)
- return (NULL);
+ /*
+ * might need to re-read the configuration file before loading
+ * the mechanism to ensure we have the latest info.
+ */
+ updateMechList();
- if (aMech->dl_handle == NULL)
- return (NULL);
+ aMech = searchMechList(oid);
- /* Load the gss_config_ext struct for this mech */
+ /* is the mechanism present in the list ? */
+ if (aMech == NULL || aMech->dl_handle == NULL) {
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism_ext)NULL);
+ }
- mech_ext = (gss_mechanism_ext)malloc(sizeof (struct gss_config_ext));
+ /* has another thread loaded the mech */
+ if (aMech->mech_ext) {
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return (aMech->mech_ext);
+ }
- if (mech_ext == NULL)
- return (NULL);
+ /* Try dynamic dispatch table */
+ aMech->mech_ext = build_dynamicMechExt(aMech->dl_handle,
+ aMech->mech_type);
+ if (aMech->mech_ext == NULL) {
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism_ext)NULL);
+ }
-#if 0
- /*
- * dlsym() the mech's 'method' functions for the extended APIs
- *
- * NOTE: Until the void *context argument is removed from the
- * SPI method functions' signatures it will be necessary to have
- * different function pointer typedefs and function names for
- * the SPI methods than for the API. When this argument is
- * removed it will be possible to rename gss_*_sfct to gss_*_fct
- * and and gssspi_* to gss_*.
- */
- mech_ext->gss_acquire_cred_with_password =
- (gss_acquire_cred_with_password_sfct)dlsym(aMech->dl_handle,
- "gssspi_acquire_cred_with_password");
-#endif
-
- /* Set aMech->mech_ext */
- (void) k5_mutex_lock(&g_mechListLock);
-
- if (aMech->mech_ext == NULL)
- aMech->mech_ext = mech_ext;
- else
- free(mech_ext); /* we raced and lost; don't leak */
-
(void) k5_mutex_unlock(&g_mechListLock);
-
return (aMech->mech_ext);
-
} /* gssint_get_mechanism_ext */
-
/*
* this routine is used for searching the list of mechanism data.
*
Modified: branches/iakerb/src/lib/gssapi/mechglue/mglueP.h
===================================================================
--- branches/iakerb/src/lib/gssapi/mechglue/mglueP.h 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/mechglue/mglueP.h 2010-03-29 16:18:20 UTC (rev 23843)
@@ -77,7 +77,6 @@
} gss_union_cred_desc, *gss_union_cred_t;
typedef OM_uint32 (*gss_acquire_cred_with_password_sfct)(
- void *, /* context */
OM_uint32 *, /* minor_status */
const gss_name_t, /* desired_name */
const gss_buffer_t, /* password */
@@ -593,7 +592,7 @@
/* This structure MUST NOT be used by any code outside libgss */
typedef struct gss_config_ext {
- gss_acquire_cred_with_password_sfct gss_acquire_cred_with_password;
+ gss_acquire_cred_with_password_sfct gssspi_acquire_cred_with_password;
} *gss_mechanism_ext;
/*
Modified: branches/iakerb/src/lib/gssapi/spnego/gssapiP_spnego.h
===================================================================
--- branches/iakerb/src/lib/gssapi/spnego/gssapiP_spnego.h 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/spnego/gssapiP_spnego.h 2010-03-29 16:18:20 UTC (rev 23843)
@@ -458,6 +458,18 @@
OM_uint32 *); /* time_rec */
OM_uint32
+spnego_gss_acquire_cred_with_password(
+ OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec);
+
+OM_uint32
spnego_gss_display_name_ext
(
OM_uint32 *minor_status,
Modified: branches/iakerb/src/lib/gssapi/spnego/spnego_mech.c
===================================================================
--- branches/iakerb/src/lib/gssapi/spnego/spnego_mech.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/gssapi/spnego/spnego_mech.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -274,6 +274,11 @@
spnego_gss_set_neg_mechs,
};
+static struct gss_config_ext spnego_mechanism_ext =
+{
+ spnego_gss_acquire_cred_with_password
+};
+
#ifdef _GSS_STATIC_LINK
#include "mglueP.h"
@@ -283,6 +288,7 @@
memset(&mech_spnego, 0, sizeof(mech_spnego));
mech_spnego.mech = &spnego_mechanism;
+ mech_spnego.mech_ext = &spnego_mechanism_ext;
mech_spnego.mechNameStr = "spnego";
mech_spnego.mech_type = GSS_C_NO_OID;
@@ -852,7 +858,7 @@
* token back if this is the first token or if a MIC exchange
* is required.
*/
- if (*send_token == CONT_TOKEN_SEND &&
+ if (mechtok_in->length != 0 &&
mechtok_out->length == 0 &&
(!sc->mic_reqd ||
!(sc->ctx_flags & GSS_C_INTEG_FLAG))) {
@@ -873,7 +879,8 @@
*send_token = ERROR_TOKEN_SEND;
}
*negState = REJECT;
- }
+ } else if (*send_token == NO_TOKEN_SEND)
+ *send_token = CONT_TOKEN_SEND;
return ret;
}
@@ -2447,6 +2454,47 @@
}
OM_uint32
+spnego_gss_acquire_cred_with_password(OM_uint32 *minor_status,
+ const gss_name_t desired_name,
+ const gss_buffer_t password,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 status;
+ gss_OID_set amechs = GSS_C_NULL_OID_SET;
+
+ dsyslog("Entering spnego_gss_acquire_cred_with_password\n");
+
+ if (actual_mechs)
+ *actual_mechs = NULL;
+
+ if (time_rec)
+ *time_rec = 0;
+
+ if (desired_mechs == GSS_C_NULL_OID_SET) {
+ status = get_available_mechs(minor_status,
+ desired_name, cred_usage,
+ output_cred_handle, &amechs);
+ }
+
+ status = gss_acquire_cred_with_password(minor_status,
+ desired_name, password, time_req,
+ desired_mechs ? desired_mechs : amechs, cred_usage,
+ output_cred_handle, actual_mechs,
+ time_rec);
+
+ if (amechs != GSS_C_NULL_OID_SET)
+ (void) gss_release_oid_set(minor_status, &amechs);
+
+ dsyslog("Leaving spnego_gss_acquire_cred_with_password\n");
+ return (status);
+}
+
+OM_uint32
spnego_gss_display_name_ext(OM_uint32 *minor_status,
gss_name_t name,
gss_OID display_as_name_type,
Modified: branches/iakerb/src/lib/krb5/asn.1/asn1_k_decode.c
===================================================================
--- branches/iakerb/src/lib/krb5/asn.1/asn1_k_decode.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/asn.1/asn1_k_decode.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -1899,6 +1899,47 @@
return retval;
}
+asn1_error_code asn1_decode_iakerb_header
+(asn1buf *buf, krb5_iakerb_header *val)
+{
+ setup();
+ val->target_realm.data = NULL;
+ val->target_realm.length = 0;
+ val->cookie = NULL;
+ {
+ begin_structure();
+ get_lenfield(val->target_realm.length, val->target_realm.data,
+ 1, asn1_decode_charstring);
+ if (tagnum == 2) {
+ alloc_data(val->cookie);
+ get_lenfield(val->cookie->length, val->cookie->data,
+ 2, asn1_decode_charstring);
+ }
+ end_structure();
+ }
+ return 0;
+error_out:
+ krb5_free_data_contents(NULL, &val->target_realm);
+ krb5_free_data(NULL, val->cookie);
+ return retval;
+}
+
+asn1_error_code asn1_decode_iakerb_finished
+(asn1buf *buf, krb5_iakerb_finished *val)
+{
+ setup();
+ val->checksum.contents = NULL;
+ {
+ begin_structure();
+ get_field(val->checksum, 1, asn1_decode_checksum);
+ end_structure();
+ }
+ return 0;
+error_out:
+ krb5_free_checksum_contents(NULL, &val->checksum);
+ return retval;
+}
+
#ifndef DISABLE_PKINIT
/* PKINIT */
Modified: branches/iakerb/src/lib/krb5/asn.1/asn1_k_decode.h
===================================================================
--- branches/iakerb/src/lib/krb5/asn.1/asn1_k_decode.h 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/asn.1/asn1_k_decode.h 2010-03-29 16:18:20 UTC (rev 23843)
@@ -271,4 +271,10 @@
asn1_error_code asn1_decode_ad_signedpath(asn1buf *buf,
krb5_ad_signedpath *val);
+asn1_error_code asn1_decode_iakerb_header(asn1buf *buf,
+ krb5_iakerb_header *val);
+
+asn1_error_code asn1_decode_iakerb_finished(asn1buf *buf,
+ krb5_iakerb_finished *val);
+
#endif
Modified: branches/iakerb/src/lib/krb5/asn.1/asn1_k_encode.c
===================================================================
--- branches/iakerb/src/lib/krb5/asn.1/asn1_k_encode.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/asn.1/asn1_k_encode.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -1394,6 +1394,35 @@
DEFSEQTYPE(ad_signedpath, krb5_ad_signedpath, ad_signedpath_fields, ad_signedpath_optional);
+static const struct field_info iakerb_header_fields[] = {
+ FIELDOF_NORM(krb5_iakerb_header, ostring_data, target_realm, 1),
+ FIELDOF_OPT(krb5_iakerb_header, ostring_data_ptr, cookie, 2, 2),
+};
+
+static unsigned int iakerb_header_optional(const void *p)
+{
+ unsigned int optional = 0;
+ const krb5_iakerb_header *val = p;
+ if (val->cookie && val->cookie->data)
+ optional |= (1u << 2);
+ return optional;
+}
+
+DEFSEQTYPE(iakerb_header, krb5_iakerb_header, iakerb_header_fields, iakerb_header_optional);
+
+static const struct field_info iakerb_finished_fields[] = {
+ FIELDOF_NORM(krb5_iakerb_finished, checksum, checksum, 1),
+};
+
+static unsigned int iakerb_finished_optional(const void *p)
+{
+ unsigned int optional = 0;
+ return optional;
+}
+
+DEFSEQTYPE(iakerb_finished, krb5_iakerb_finished, iakerb_finished_fields,
+iakerb_finished_optional);
+
/* Exported complete encoders -- these produce a krb5_data with
the encoding in the correct byte order. */
@@ -1472,6 +1501,8 @@
MAKE_FULL_ENCODER(encode_krb5_ad_kdcissued, ad_kdc_issued);
MAKE_FULL_ENCODER(encode_krb5_ad_signedpath_data, ad_signedpath_data);
MAKE_FULL_ENCODER(encode_krb5_ad_signedpath, ad_signedpath);
+MAKE_FULL_ENCODER(encode_krb5_iakerb_header, iakerb_header);
+MAKE_FULL_ENCODER(encode_krb5_iakerb_finished, iakerb_finished);
Modified: branches/iakerb/src/lib/krb5/asn.1/krb5_decode.c
===================================================================
--- branches/iakerb/src/lib/krb5/asn.1/krb5_decode.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/asn.1/krb5_decode.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -1218,6 +1218,30 @@
cleanup(free);
}
+krb5_error_code decode_krb5_iakerb_header
+(const krb5_data *code, krb5_iakerb_header **repptr)
+{
+ setup_buf_only(krb5_iakerb_header *);
+ alloc_field(rep);
+
+ retval = asn1_decode_iakerb_header(&buf, rep);
+ if (retval) clean_return(retval);
+
+ cleanup(free);
+}
+
+krb5_error_code decode_krb5_iakerb_finished
+(const krb5_data *code, krb5_iakerb_finished **repptr)
+{
+ setup_buf_only(krb5_iakerb_finished *);
+ alloc_field(rep);
+
+ retval = asn1_decode_iakerb_finished(&buf, rep);
+ if (retval) clean_return(retval);
+
+ cleanup(free);
+}
+
krb5_error_code
krb5int_get_authdata_containee_types(krb5_context context,
const krb5_authdata *authdata,
Modified: branches/iakerb/src/lib/krb5/error_tables/krb5_err.et
===================================================================
--- branches/iakerb/src/lib/krb5/error_tables/krb5_err.et 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/error_tables/krb5_err.et 2010-03-29 16:18:20 UTC (rev 23843)
@@ -126,8 +126,8 @@
error_code KRB5PLACEHOLD_82, "KRB5 error code 82"
error_code KRB5PLACEHOLD_83, "KRB5 error code 83"
error_code KRB5PLACEHOLD_84, "KRB5 error code 84"
-error_code KRB5PLACEHOLD_85, "KRB5 error code 85"
-error_code KRB5PLACEHOLD_86, "KRB5 error code 86"
+error_code KRB5KRB_AP_ERR_IAKERB_KDC_NOT_FOUND, "The IAKERB proxy could not find a KDC"
+error_code KRB5KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE, "The KDC did not respond to the IAKERB proxy"
error_code KRB5PLACEHOLD_87, "KRB5 error code 87"
error_code KRB5PLACEHOLD_88, "KRB5 error code 88"
error_code KRB5PLACEHOLD_89, "KRB5 error code 89"
Modified: branches/iakerb/src/lib/krb5/krb/Makefile.in
===================================================================
--- branches/iakerb/src/lib/krb5/krb/Makefile.in 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/krb/Makefile.in 2010-03-29 16:18:20 UTC (rev 23843)
@@ -48,6 +48,7 @@
fast.o \
fwd_tgt.o \
gc_frm_kdc.o \
+ gc_frm_kdc_step.o \
gc_via_tkt.o \
gen_seqnum.o \
gen_subkey.o \
@@ -147,6 +148,7 @@
$(OUTPRE)fast.$(OBJEXT) \
$(OUTPRE)fwd_tgt.$(OBJEXT) \
$(OUTPRE)gc_frm_kdc.$(OBJEXT) \
+ $(OUTPRE)gc_frm_kdc_step.$(OBJEXT) \
$(OUTPRE)gc_via_tkt.$(OBJEXT) \
$(OUTPRE)gen_seqnum.$(OBJEXT) \
$(OUTPRE)gen_subkey.$(OBJEXT) \
@@ -247,6 +249,7 @@
$(srcdir)/fast.c \
$(srcdir)/fwd_tgt.c \
$(srcdir)/gc_frm_kdc.c \
+ $(srcdir)/gc_frm_kdc_step.c \
$(srcdir)/gc_via_tkt.c \
$(srcdir)/gen_seqnum.c \
$(srcdir)/gen_subkey.c \
Modified: branches/iakerb/src/lib/krb5/krb/gc_frm_kdc.c
===================================================================
--- branches/iakerb/src/lib/krb5/krb/gc_frm_kdc.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/krb/gc_frm_kdc.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -152,8 +152,6 @@
/*
* Prototypes of helper functions
*/
-static krb5_error_code tgt_mcred(krb5_context, krb5_principal,
- krb5_principal, krb5_principal, krb5_creds *);
static krb5_error_code retr_local_tgt(struct tr_state *, krb5_principal);
static krb5_error_code try_ccache(struct tr_state *, krb5_creds *);
static krb5_error_code find_nxt_realm(struct tr_state *);
@@ -295,10 +293,10 @@
* failure. The peculiar ordering of DST and SRC args is for
* consistency with krb5int_tgtname().
*/
-static krb5_error_code
-tgt_mcred(krb5_context ctx, krb5_principal client,
- krb5_principal dst, krb5_principal src,
- krb5_creds *mcreds)
+krb5_error_code
+krb5int_tgt_mcred(krb5_context ctx, krb5_principal client,
+ krb5_principal dst, krb5_principal src,
+ krb5_creds *mcreds)
{
krb5_error_code retval;
@@ -365,7 +363,7 @@
krb5_creds tgtq;
memset(&tgtq, 0, sizeof(tgtq));
- retval = tgt_mcred(ts->ctx, client, client, client, &tgtq);
+ retval = krb5int_tgt_mcred(ts->ctx, client, client, client, &tgtq);
if (retval)
return retval;
@@ -997,7 +995,7 @@
* local realm in the default (referral) case or for the remote
* realm if we're starting someplace non-local.
*/
- retval = tgt_mcred(context, client, server, client, &tgtq);
+ retval = krb5int_tgt_mcred(context, client, server, client, &tgtq);
if (retval)
goto cleanup;
@@ -1235,7 +1233,7 @@
*/
krb5_free_cred_contents(context, &tgtq);
- retval = tgt_mcred(context, client, server, client, &tgtq);
+ retval = krb5int_tgt_mcred(context, client, server, client, &tgtq);
if (retval)
goto cleanup;
Added: branches/iakerb/src/lib/krb5/krb/gc_frm_kdc_step.c
===================================================================
--- branches/iakerb/src/lib/krb5/krb/gc_frm_kdc_step.c (rev 0)
+++ branches/iakerb/src/lib/krb5/krb/gc_frm_kdc_step.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -0,0 +1,450 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 1990-2009 by the Massachusetts Institute of Technology.
+ * Copyright (c) 1994 CyberSAFE Corporation
+ * Copyright (c) 1993 Open Computing Security Group
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * Neither M.I.T., the Open Computing Security Group, nor
+ * CyberSAFE Corporation make any representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * krb5_tkt_creds_step() and related functions:
+ *
+ * Get credentials from some KDC somewhere, possibly accumulating TGTs
+ * along the way. This is asychronous version of the API in gc_frm_kdc.c.
+ * It requires that the KDC support cross-realm referrals.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include "int-proto.h"
+
+#define KRB5_TKT_CREDS_STEP_FLAG_COMPLETE 0x1
+#define KRB5_TKT_CREDS_STEP_FLAG_CTX_KTYPES 0x2
+
+struct _krb5_tkt_creds_context {
+ krb5_ccache ccache;
+ krb5_creds in_cred;
+ krb5_principal client;
+ krb5_principal server;
+ krb5_principal req_server;
+ int req_kdcopt;
+
+ unsigned int flags;
+ krb5_creds cc_tgt;
+ krb5_creds *tgtptr;
+ unsigned int referral_count;
+ krb5_creds *referral_tgts[KRB5_REFERRAL_MAXHOPS];
+ krb5_boolean default_use_conf_ktypes;
+ krb5_timestamp timestamp;
+ krb5_int32 nonce;
+ int kdcopt;
+ krb5_keyblock *subkey;
+ krb5_data encoded_previous_request;
+
+ krb5_creds *out_cred;
+};
+
+/* Convert ticket flags to necessary KDC options */
+#define FLAGS2OPTS(flags) (flags & KDC_TKT_COMMON_MASK)
+
+static krb5_error_code
+tkt_make_tgs_request(krb5_context context,
+ krb5_tkt_creds_context ctx,
+ krb5_creds *tgt,
+ krb5_creds *in_cred,
+ krb5_data *req)
+{
+ krb5_error_code code;
+
+ /* These flags are always included */
+ ctx->kdcopt |= FLAGS2OPTS(tgt->ticket_flags);
+
+ if ((ctx->kdcopt & KDC_OPT_ENC_TKT_IN_SKEY) == 0)
+ in_cred->is_skey = FALSE;
+
+ if (!krb5_c_valid_enctype(tgt->keyblock.enctype))
+ return KRB5_PROG_ETYPE_NOSUPP;
+
+ code = krb5int_make_tgs_request(context, tgt, ctx->kdcopt,
+ tgt->addresses, NULL,
+ in_cred, NULL, NULL, req,
+ &ctx->timestamp, &ctx->nonce, &ctx->subkey);
+ return code;
+}
+
+static krb5_error_code
+tkt_process_tgs_reply(krb5_context context,
+ krb5_tkt_creds_context ctx,
+ krb5_data *rep,
+ krb5_creds *tgt,
+ krb5_creds *in_cred,
+ krb5_creds **out_cred)
+{
+ krb5_error_code code;
+
+ code = krb5int_process_tgs_reply(context,
+ rep,
+ tgt,
+ ctx->kdcopt,
+ tgt->addresses,
+ NULL,
+ in_cred,
+ ctx->timestamp,
+ ctx->nonce,
+ ctx->subkey,
+ NULL,
+ NULL,
+ out_cred);
+
+ return code;
+}
+
+/*
+ * Asynchronous API
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_init(krb5_context context,
+ krb5_ccache ccache,
+ krb5_creds *creds,
+ int kdcopt,
+ krb5_tkt_creds_context *pctx)
+{
+ krb5_error_code code;
+ krb5_tkt_creds_context ctx = NULL;
+ krb5_creds tgtq;
+ krb5_flags flags = KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES;
+
+ memset(&tgtq, 0, sizeof(tgtq));
+
+ ctx = k5alloc(sizeof(*ctx), &code);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5int_copy_creds_contents(context, creds, &ctx->in_cred);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->ccache = ccache; /* XXX */
+
+ ctx->req_kdcopt = kdcopt;
+ ctx->default_use_conf_ktypes = context->use_conf_ktypes;
+ ctx->client = ctx->in_cred.client;
+ ctx->server = ctx->in_cred.server;
+
+ code = krb5_copy_principal(context, ctx->server, &ctx->req_server);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5int_tgt_mcred(context, ctx->client, ctx->client,
+ ctx->client, &tgtq);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_cc_retrieve_cred(context, ctx->ccache, flags,
+ &tgtq, &ctx->cc_tgt);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->tgtptr = &ctx->cc_tgt;
+
+ *pctx = ctx;
+
+cleanup:
+ if (code != 0)
+ krb5_tkt_creds_free(context, ctx);
+ krb5_free_cred_contents(context, &tgtq);
+
+ return code;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_get_creds(krb5_context context,
+ krb5_tkt_creds_context ctx,
+ krb5_creds *creds)
+{
+ krb5_error_code code;
+
+ if (ctx->flags & KRB5_TKT_CREDS_STEP_FLAG_COMPLETE)
+ code = krb5int_copy_creds_contents(context, ctx->out_cred, creds);
+ else
+ code = KRB5_NO_TKT_SUPPLIED;
+
+ return code;
+}
+
+/*
+ * Store credentials in credentials cache. If ccache is NULL, the
+ * credentials cache associated with the context is used. This can
+ * be called on an incomplete context, in which case the referral
+ * TGT only will be stored.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_store_creds(krb5_context context,
+ krb5_tkt_creds_context ctx,
+ krb5_ccache ccache)
+{
+ krb5_error_code code;
+
+ if (ccache == NULL)
+ ccache = ctx->ccache;
+
+ /* Only store the referral from our local KDC */
+ if (ctx->referral_tgts[0] != NULL)
+ krb5_cc_store_cred(context, ccache, ctx->referral_tgts[0]);
+
+ if (ctx->flags & KRB5_TKT_CREDS_STEP_FLAG_COMPLETE)
+ code = krb5_cc_store_cred(context, ccache, ctx->out_cred);
+ else
+ code = KRB5_NO_TKT_SUPPLIED;
+
+ return code;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_get_times(krb5_context context,
+ krb5_tkt_creds_context ctx,
+ krb5_ticket_times *times)
+{
+ if ((ctx->flags & KRB5_TKT_CREDS_STEP_FLAG_COMPLETE) == 0)
+ return KRB5_NO_TKT_SUPPLIED;
+
+ *times = ctx->out_cred->times;
+
+ return 0;
+}
+
+void KRB5_CALLCONV
+krb5_tkt_creds_free(krb5_context context,
+ krb5_tkt_creds_context ctx)
+{
+ int i;
+
+ if (ctx == NULL)
+ return;
+
+ krb5_free_principal(context, ctx->req_server);
+ krb5_free_cred_contents(context, &ctx->in_cred);
+ krb5_free_creds(context, ctx->out_cred);
+ krb5_free_data_contents(context, &ctx->encoded_previous_request);
+ krb5_free_keyblock(context, ctx->subkey);
+
+ /* Free referral TGTs list. */
+ for (i = 0; i < KRB5_REFERRAL_MAXHOPS; i++) {
+ if (ctx->referral_tgts[i] != NULL) {
+ krb5_free_creds(context, ctx->referral_tgts[i]);
+ ctx->referral_tgts[i] = NULL;
+ }
+ }
+
+ free(ctx);
+}
+
+static krb5_error_code
+tkt_creds_step_request(krb5_context context,
+ krb5_tkt_creds_context ctx,
+ krb5_data *req)
+{
+ krb5_error_code code;
+
+ if (ctx->referral_count >= KRB5_REFERRAL_MAXHOPS)
+ return KRB5_KDC_UNREACH;
+
+ assert(ctx->tgtptr != NULL);
+
+ /* Copy krbtgt realm to server principal */
+ krb5_free_data_contents(context, &ctx->server->realm);
+ code = krb5int_copy_data_contents(context,
+ &ctx->tgtptr->server->data[1],
+ &ctx->server->realm);
+ if (code != 0)
+ return code;
+
+ ctx->kdcopt = ctx->req_kdcopt | KDC_OPT_CANONICALIZE;
+
+ if (ctx->in_cred.second_ticket.length != 0 &&
+ (ctx->kdcopt & KDC_OPT_CNAME_IN_ADDL_TKT) == 0) {
+ ctx->kdcopt |= KDC_OPT_ENC_TKT_IN_SKEY;
+ }
+
+ if ((ctx->flags & KRB5_TKT_CREDS_STEP_FLAG_CTX_KTYPES) == 0)
+ context->use_conf_ktypes = 1;
+
+ code = tkt_make_tgs_request(context, ctx, ctx->tgtptr,
+ &ctx->in_cred, req);
+
+ context->use_conf_ktypes = ctx->default_use_conf_ktypes;
+
+ return code;
+}
+
+static krb5_error_code
+tkt_creds_step_reply(krb5_context context,
+ krb5_tkt_creds_context ctx,
+ krb5_data *rep)
+{
+ krb5_error_code code;
+ unsigned int i;
+ krb5_boolean got_tkt = FALSE;
+
+ krb5_free_creds(context, ctx->out_cred);
+ ctx->out_cred = NULL;
+
+ code = tkt_process_tgs_reply(context, ctx, rep, ctx->tgtptr,
+ &ctx->in_cred, &ctx->out_cred);
+ if (code != 0)
+ goto cleanup;
+
+ /*
+ * Referral request succeeded; let's see what it is
+ */
+ if (krb5_principal_compare(context, ctx->server, ctx->out_cred->server)) {
+ /*
+ * Check if the return enctype is one that we requested if
+ * needed.
+ */
+ if (ctx->default_use_conf_ktypes || context->tgs_etypes == NULL)
+ got_tkt = TRUE;
+ else
+ for (i = 0; context->tgs_etypes[i] != ENCTYPE_NULL; i++) {
+ if (ctx->out_cred->keyblock.enctype == context->tgs_etypes[i]) {
+ /* Found an allowable etype, so we're done */
+ got_tkt = TRUE;
+ break;
+ }
+ }
+
+ if (got_tkt == FALSE)
+ ctx->flags |= KRB5_TKT_CREDS_STEP_FLAG_CTX_KTYPES; /* try again */
+ } else if (IS_TGS_PRINC(context, ctx->out_cred->server)) {
+ krb5_data *r1, *r2;
+
+ if (ctx->referral_count == 0)
+ r1 = &ctx->tgtptr->server->data[1];
+ else
+ r1 = &ctx->referral_tgts[ctx->referral_count - 1]->server->data[1];
+
+ r2 = &ctx->out_cred->server->data[1];
+ if (data_eq(*r1, *r2)) {
+ code = KRB5_KDC_UNREACH;
+ goto cleanup;
+ }
+
+ /* Check for referral routing loop. */
+ for (i = 0; i < ctx->referral_count; i++) {
+ if (krb5_principal_compare(context,
+ ctx->out_cred->server,
+ ctx->referral_tgts[i]->server)) {
+ code = KRB5_KDC_UNREACH;
+ goto cleanup;
+ }
+ }
+ /* Point current tgt pointer at newly-received TGT. */
+ ctx->tgtptr = ctx->out_cred;
+
+ /* avoid multiple copies of authdata */
+ ctx->out_cred->authdata = ctx->in_cred.authdata;
+ ctx->in_cred.authdata = NULL;
+
+ ctx->referral_tgts[ctx->referral_count++] = ctx->out_cred;
+ ctx->out_cred = NULL;
+ } else {
+ code = KRB5KRB_AP_ERR_NO_TGT;
+ }
+
+ assert(ctx->tgtptr == NULL || code == 0);
+
+ if (code == 0 && got_tkt == TRUE) {
+ krb5_free_principal(context, ctx->out_cred->server);
+ ctx->out_cred->server = ctx->req_server;
+ ctx->req_server = NULL;
+
+ if (ctx->in_cred.authdata != NULL) {
+ code = krb5_copy_authdata(context, ctx->in_cred.authdata,
+ &ctx->out_cred->authdata);
+ }
+
+ ctx->flags |= KRB5_TKT_CREDS_STEP_FLAG_COMPLETE;
+ }
+
+cleanup:
+ return code;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_tkt_creds_step(krb5_context context,
+ krb5_tkt_creds_context ctx,
+ krb5_data *in,
+ krb5_data *out,
+ krb5_data *realm,
+ unsigned int *flags)
+{
+ krb5_error_code code, code2;
+
+ *flags = 0;
+
+ out->data = NULL;
+ out->length = 0;
+
+ realm->data = NULL;
+ realm->length = 0;
+
+ if (ctx->flags & KRB5_TKT_CREDS_STEP_FLAG_COMPLETE)
+ goto cleanup;
+
+ if (in != NULL && in->length != 0) {
+ code = tkt_creds_step_reply(context, ctx, in);
+ if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG) {
+ code2 = krb5int_copy_data_contents(context,
+ &ctx->encoded_previous_request,
+ out);
+ if (code2 != 0)
+ code = code2;
+ goto copy_realm;
+ }
+ if (code != 0 || (ctx->flags & KRB5_TKT_CREDS_STEP_FLAG_COMPLETE))
+ goto cleanup;
+ }
+
+ code = tkt_creds_step_request(context, ctx, out);
+ if (code != 0)
+ goto cleanup;
+
+ assert(out->length != 0);
+
+ code = krb5int_copy_data_contents(context,
+ out,
+ &ctx->encoded_previous_request);
+ if (code != 0)
+ goto cleanup;
+
+copy_realm:
+ code2 = krb5int_copy_data_contents(context, &ctx->server->realm, realm);
+ if (code2 != 0) {
+ code = code2;
+ goto cleanup;
+ }
+
+cleanup:
+ *flags = (ctx->flags & KRB5_TKT_CREDS_STEP_FLAG_COMPLETE);
+
+ return code;
+}
+
Modified: branches/iakerb/src/lib/krb5/krb/int-proto.h
===================================================================
--- branches/iakerb/src/lib/krb5/krb/int-proto.h 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/krb/int-proto.h 2010-03-29 16:18:20 UTC (rev 23843)
@@ -142,6 +142,11 @@
krb5_pa_data ***out_enc_padata,
krb5_creds **out_cred);
+krb5_error_code
+krb5int_tgt_mcred(krb5_context ctx, krb5_principal client,
+ krb5_principal dst, krb5_principal src,
+ krb5_creds *mcreds);
+
krb5_error_code krb5int_send_tgs(krb5_context, krb5_flags,
const krb5_ticket_times *,
const krb5_enctype *,
Modified: branches/iakerb/src/lib/krb5/krb/kfree.c
===================================================================
--- branches/iakerb/src/lib/krb5/krb/kfree.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/krb/kfree.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -913,3 +913,22 @@
krb5_free_pa_data(context, val->method_data);
free(val);
}
+
+void KRB5_CALLCONV
+krb5_free_iakerb_header(krb5_context context, krb5_iakerb_header *val)
+{
+ if (val == NULL)
+ return ;
+
+ krb5_free_data_contents(context, &val->target_realm);
+ krb5_free_data(context, val->cookie);
+}
+
+void KRB5_CALLCONV
+krb5_free_iakerb_finished(krb5_context context, krb5_iakerb_finished *val)
+{
+ if (val == NULL)
+ return ;
+
+ krb5_free_checksum_contents(context, &val->checksum);
+}
Modified: branches/iakerb/src/lib/krb5/libkrb5.exports
===================================================================
--- branches/iakerb/src/lib/krb5/libkrb5.exports 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/lib/krb5/libkrb5.exports 2010-03-29 16:18:20 UTC (rev 23843)
@@ -22,6 +22,8 @@
decode_krb5_etype_info
decode_krb5_etype_info2
decode_krb5_fast_req
+decode_krb5_iakerb_finished
+decode_krb5_iakerb_header
decode_krb5_kdc_req_body
decode_krb5_pa_enc_ts
decode_krb5_pa_for_user
@@ -67,6 +69,8 @@
encode_krb5_etype_info
encode_krb5_etype_info2
encode_krb5_fast_response
+encode_krb5_iakerb_finished
+encode_krb5_iakerb_header
encode_krb5_kdc_req_body
encode_krb5_pa_enc_ts
encode_krb5_pa_for_user
@@ -266,6 +270,8 @@
krb5_free_fast_armored_req
krb5_free_fast_req
krb5_free_host_realm
+krb5_free_iakerb_finished
+krb5_free_iakerb_header
krb5_free_kdc_rep
krb5_free_kdc_req
krb5_free_keyblock
@@ -550,6 +556,12 @@
krb5_string_to_timestamp
krb5_sync_disk_file
krb5int_tgtname
+krb5_tkt_creds_free
+krb5_tkt_creds_get_creds
+krb5_tkt_creds_get_times
+krb5_tkt_creds_init
+krb5_tkt_creds_step
+krb5_tkt_creds_store_creds
krb5_timeofday
krb5_timestamp_to_sfstring
krb5_timestamp_to_string
Modified: branches/iakerb/src/tests/asn.1/krb5_decode_leak.c
===================================================================
--- branches/iakerb/src/tests/asn.1/krb5_decode_leak.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/tests/asn.1/krb5_decode_leak.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -704,6 +704,28 @@
krb5_free_ad_signedpath);
ktest_empty_ad_signedpath(&sp);
}
+ /****************************************************************/
+ /* encode_krb5_iakerb_header */
+ {
+ krb5_iakerb_header ih, *tmp;
+ setup(ih, "iakerb_header",
+ ktest_make_sample_iakerb_header);
+ leak_test(ih, encode_krb5_iakerb_header,
+ decode_krb5_iakerb_header,
+ krb5_free_iakerb_header);
+ ktest_empty_iakerb_header(&ih);
+ }
+ /****************************************************************/
+ /* encode_krb5_iakerb_finished */
+ {
+ krb5_iakerb_finished ih, *tmp;
+ setup(ih, "iakerb_finished",
+ ktest_make_sample_iakerb_finished);
+ leak_test(ih, encode_krb5_iakerb_finished,
+ decode_krb5_iakerb_finished,
+ krb5_free_iakerb_finished);
+ ktest_empty_iakerb_finished(&ih);
+ }
krb5_free_context(test_context);
return 0;
}
Modified: branches/iakerb/src/tests/asn.1/krb5_decode_test.c
===================================================================
--- branches/iakerb/src/tests/asn.1/krb5_decode_test.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/tests/asn.1/krb5_decode_test.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -916,6 +916,22 @@
ktest_empty_ad_signedpath(&ref);
}
+ /****************************************************************/
+ /* decode_iakerb_header */
+ {
+ setup(krb5_iakerb_header,"krb5_iakerb_header",ktest_make_sample_iakerb_header);
+ decode_run("iakerb_header","","30 18 A1 0A 04 08 6B 72 62 35 64 61 74 61 A2 0A 04 08 6B 72 62 35 64 61 74 61",decode_krb5_iakerb_header,ktest_equal_iakerb_header,krb5_free_iakerb_header);
+ ktest_empty_iakerb_header(&ref);
+ }
+
+ /****************************************************************/
+ /* decode_iakerb_finished */
+ {
+ setup(krb5_iakerb_finished,"krb5_iakerb_finished",ktest_make_sample_iakerb_finished);
+ decode_run("iakerb_finished","","30 11 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34",decode_krb5_iakerb_finished,ktest_equal_iakerb_finished,krb5_free_iakerb_finished);
+ ktest_empty_iakerb_finished(&ref);
+ }
+
#ifdef ENABLE_LDAP
/* ldap sequence_of_keys */
{
Modified: branches/iakerb/src/tests/asn.1/krb5_encode_test.c
===================================================================
--- branches/iakerb/src/tests/asn.1/krb5_encode_test.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/tests/asn.1/krb5_encode_test.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -740,6 +740,28 @@
encode_krb5_ad_signedpath);
ktest_empty_ad_signedpath(&sp);
}
+ /****************************************************************/
+ /* encode_krb5_iakerb_header */
+ {
+ krb5_iakerb_header ih;
+ setup(ih,krb5_ad_signedpath,"iakerb_header",
+ ktest_make_sample_iakerb_header);
+ encode_run(ih,krb5_iakerb_header,
+ "iakerb_header","",
+ encode_krb5_iakerb_header);
+ ktest_empty_iakerb_header(&ih);
+ }
+ /****************************************************************/
+ /* encode_krb5_iakerb_finished */
+ {
+ krb5_iakerb_finished ih;
+ setup(ih,krb5_ad_signedpath,"iakerb_finished",
+ ktest_make_sample_iakerb_finished);
+ encode_run(ih,krb5_iakerb_finished,
+ "iakerb_finished","",
+ encode_krb5_iakerb_finished);
+ ktest_empty_iakerb_finished(&ih);
+ }
#ifdef ENABLE_LDAP
{
ldap_seqof_key_data skd;
Modified: branches/iakerb/src/tests/asn.1/ktest.c
===================================================================
--- branches/iakerb/src/tests/asn.1/ktest.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/tests/asn.1/ktest.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -890,6 +890,28 @@
return retval;
}
+krb5_error_code ktest_make_sample_iakerb_header(ih)
+ krb5_iakerb_header *ih;
+{
+ krb5_error_code retval;
+ retval = ktest_make_sample_data(&(ih->target_realm));
+ if (retval) return retval;
+ ih->cookie = k5alloc(sizeof(krb5_data), &retval);
+ if (retval) return retval;
+ retval = ktest_make_sample_data(ih->cookie);
+ if (retval) return retval;
+ return retval;
+}
+
+krb5_error_code ktest_make_sample_iakerb_finished(ih)
+ krb5_iakerb_finished *ih;
+{
+ krb5_error_code retval;
+ retval = ktest_make_sample_checksum(&ih->checksum);
+ if (retval) return retval;
+ return retval;
+}
+
#ifdef ENABLE_LDAP
static krb5_error_code ktest_make_sample_key_data(krb5_key_data *p, int i)
{
@@ -1532,6 +1554,19 @@
ktest_destroy_pa_data_array(&p->method_data);
}
+void ktest_empty_iakerb_header(p)
+ krb5_iakerb_header *p;
+{
+ krb5_free_data_contents(NULL, &p->target_realm);
+ krb5_free_data(NULL, p->cookie);
+}
+
+void ktest_empty_iakerb_finished(p)
+ krb5_iakerb_finished *p;
+{
+ krb5_free_checksum_contents(NULL, &p->checksum);
+}
+
#ifdef ENABLE_LDAP
void ktest_empty_ldap_seqof_key_data(ctx, p)
krb5_context ctx;
Modified: branches/iakerb/src/tests/asn.1/ktest.h
===================================================================
--- branches/iakerb/src/tests/asn.1/ktest.h 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/tests/asn.1/ktest.h 2010-03-29 16:18:20 UTC (rev 23843)
@@ -109,6 +109,8 @@
krb5_error_code ktest_make_sample_ad_kdcissued(krb5_ad_kdcissued *p);
krb5_error_code ktest_make_sample_ad_signedpath_data(krb5_ad_signedpath_data *p);
krb5_error_code ktest_make_sample_ad_signedpath(krb5_ad_signedpath *p);
+krb5_error_code ktest_make_sample_iakerb_header(krb5_iakerb_header *p);
+krb5_error_code ktest_make_sample_iakerb_finished(krb5_iakerb_finished *p);
#ifdef ENABLE_LDAP
krb5_error_code ktest_make_sample_ldap_seqof_key_data(ldap_seqof_key_data * p);
@@ -221,6 +223,8 @@
void ktest_empty_ad_kdcissued(krb5_ad_kdcissued *p);
void ktest_empty_ad_signedpath_data(krb5_ad_signedpath_data *p);
void ktest_empty_ad_signedpath(krb5_ad_signedpath *p);
+void ktest_empty_iakerb_header(krb5_iakerb_header *p);
+void ktest_empty_iakerb_finished(krb5_iakerb_finished *p);
#ifdef ENABLE_LDAP
void ktest_empty_ldap_seqof_key_data(krb5_context, ldap_seqof_key_data *p);
Modified: branches/iakerb/src/tests/asn.1/ktest_equal.c
===================================================================
--- branches/iakerb/src/tests/asn.1/ktest_equal.c 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/tests/asn.1/ktest_equal.c 2010-03-29 16:18:20 UTC (rev 23843)
@@ -600,6 +600,29 @@
return p;
}
+int ktest_equal_iakerb_header(ref, var)
+ krb5_iakerb_header *ref;
+ krb5_iakerb_header *var;
+{
+ int p = TRUE;
+ if (ref == var) return TRUE;
+ else if (ref == NULL || var == NULL) return FALSE;
+ p=p&&struct_equal(target_realm,ktest_equal_data);
+ p=p&&ptr_equal(cookie,ktest_equal_data);
+ return p;
+}
+
+int ktest_equal_iakerb_finished(ref, var)
+ krb5_iakerb_finished *ref;
+ krb5_iakerb_finished *var;
+{
+ int p = TRUE;
+ if (ref == var) return TRUE;
+ else if (ref == NULL || var == NULL) return FALSE;
+ p=p&&struct_equal(checksum,ktest_equal_checksum);
+ return p;
+}
+
#ifdef ENABLE_LDAP
static int equal_key_data(ref, var)
krb5_key_data *ref;
Modified: branches/iakerb/src/tests/asn.1/ktest_equal.h
===================================================================
--- branches/iakerb/src/tests/asn.1/ktest_equal.h 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/tests/asn.1/ktest_equal.h 2010-03-29 16:18:20 UTC (rev 23843)
@@ -106,6 +106,12 @@
int ktest_equal_ad_signedpath
(krb5_ad_signedpath *ref,
krb5_ad_signedpath *var);
+int ktest_equal_iakerb_header
+ (krb5_iakerb_header *ref,
+ krb5_iakerb_header *var);
+int ktest_equal_iakerb_finished
+ (krb5_iakerb_finished *ref,
+ krb5_iakerb_finished *var);
int ktest_equal_ldap_sequence_of_keys(ldap_seqof_key_data *ref,
ldap_seqof_key_data *var);
Modified: branches/iakerb/src/tests/asn.1/reference_encode.out
===================================================================
--- branches/iakerb/src/tests/asn.1/reference_encode.out 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/tests/asn.1/reference_encode.out 2010-03-29 16:18:20 UTC (rev 23843)
@@ -60,3 +60,5 @@
encode_krb5_ad_kdcissued: 30 65 A0 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
encode_krb5_ad_signedpath_data: 30 81 C7 A0 30 30 2E A0 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 32 30 30 30 2E A0 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A4 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
encode_krb5_ad_signedpath: 30 3E A0 03 02 01 01 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61
+encode_krb5_iakerb_header: 30 18 A1 0A 04 08 6B 72 62 35 64 61 74 61 A2 0A 04 08 6B 72 62 35 64 61 74 61
+encode_krb5_iakerb_finished: 30 11 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
Modified: branches/iakerb/src/tests/asn.1/trval_reference.out
===================================================================
--- branches/iakerb/src/tests/asn.1/trval_reference.out 2010-03-29 15:34:58 UTC (rev 23842)
+++ branches/iakerb/src/tests/asn.1/trval_reference.out 2010-03-29 16:18:20 UTC (rev 23843)
@@ -1332,3 +1332,16 @@
. . . [1] [Integer] 13
. . . [2] [Octet String] "pa-data"
+encode_krb5_iakerb_header:
+
+[Sequence/Sequence Of]
+. [1] [Octet String] "krb5data"
+. [2] [Octet String] "krb5data"
+
+encode_krb5_iakerb_finished:
+
+[Sequence/Sequence Of]
+. [1] [Sequence/Sequence Of]
+. . [0] [Integer] 1
+. . [1] [Octet String] "1234"
+
More information about the cvs-krb5
mailing list