aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/clients/kinit/kinit.c108
-rw-r--r--src/clients/kpasswd/kpasswd.c22
-rw-r--r--src/clients/kpasswd/ksetpwd.c23
-rw-r--r--src/include/k5-int.h85
-rw-r--r--src/include/krb5/krb5.hin31
-rw-r--r--src/include/krb5/preauth_plugin.h48
-rw-r--r--src/lib/krb5/krb/get_in_tkt.c39
-rw-r--r--src/lib/krb5/krb/gic_keytab.c34
-rw-r--r--src/lib/krb5/krb/gic_opt.c418
-rw-r--r--src/lib/krb5/krb/gic_pwd.c77
-rw-r--r--src/lib/krb5/krb/preauth2.c68
-rw-r--r--src/lib/krb5/libkrb5.exports12
-rw-r--r--src/lib/krb5_32.def5
-rw-r--r--src/plugins/preauth/cksum_body/cksum_body_main.c39
-rw-r--r--src/plugins/preauth/wpse/wpse_main.c17
15 files changed, 925 insertions, 101 deletions
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
index 452d98c..f8e5b77 100644
--- a/src/clients/kinit/kinit.c
+++ b/src/clients/kinit/kinit.c
@@ -38,6 +38,7 @@
#include <string.h>
#include <stdio.h>
#include <time.h>
+#include <errno.h>
#include <com_err.h>
#ifdef GETOPT_LONG
@@ -143,6 +144,9 @@ struct k_opts
char* k4_cache_name;
action_type action;
+
+ int num_pa_opts;
+ krb5_gic_opt_pa_data *pa_opts;
};
struct k5_data
@@ -283,6 +287,37 @@ static void extended_com_err_fn (const char *myprog, errcode_t code,
fprintf (stderr, "\n");
}
+static int
+add_preauth_opt(struct k_opts *opts, char *av)
+{
+ char *sep, *v;
+ krb5_gic_opt_pa_data *p, *x;
+
+ if (opts->num_pa_opts == 0) {
+ opts->pa_opts = malloc(sizeof(krb5_gic_opt_pa_data));
+ if (opts->pa_opts == NULL)
+ return ENOMEM;
+ } else {
+ size_t newsize = (opts->num_pa_opts + 1) * sizeof(krb5_gic_opt_pa_data);
+ x = realloc(opts->pa_opts, newsize);
+ if (x == NULL)
+ return ENOMEM;
+ opts->pa_opts = x;
+ }
+ p = &opts->pa_opts[opts->num_pa_opts];
+ sep = strchr(av, '=');
+ if (sep) {
+ *sep = '\0';
+ v = ++sep;
+ p->value = v;
+ } else {
+ p->value = "yes";
+ }
+ p->attr = av;
+ opts->num_pa_opts++;
+ return 0;
+}
+
static char *
parse_options(argc, argv, opts, progname)
int argc;
@@ -296,7 +331,7 @@ parse_options(argc, argv, opts, progname)
int use_k5 = 0;
int i;
- while ((i = GETOPT(argc, argv, "r:fpFP54aAVl:s:c:kt:RS:v"))
+ while ((i = GETOPT(argc, argv, "r:fpFP54aAVl:s:c:kt:RS:vX:"))
!= -1) {
switch (i) {
case 'V':
@@ -380,6 +415,14 @@ parse_options(argc, argv, opts, progname)
opts->k5_cache_name = optarg;
}
break;
+ case 'X':
+ code = add_preauth_opt(opts, optarg);
+ if (code)
+ {
+ com_err(progname, code, "while adding preauth option");
+ errflg++;
+ }
+ break;
#if 0
/*
A little more work is needed before we can enable this
@@ -752,12 +795,15 @@ k5_kinit(opts, k5)
krb5_keytab keytab = 0;
krb5_creds my_creds;
krb5_error_code code = 0;
- krb5_get_init_creds_opt options;
+ krb5_get_init_creds_opt *options = NULL;
+ int i;
if (!got_k5)
return 0;
- krb5_get_init_creds_opt_init(&options);
+ code = krb5_get_init_creds_opt_alloc(k5->ctx, &options);
+ if (code)
+ goto cleanup;
memset(&my_creds, 0, sizeof(my_creds));
/*
@@ -766,17 +812,17 @@ k5_kinit(opts, k5)
*/
if (opts->lifetime)
- krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime);
+ krb5_get_init_creds_opt_set_tkt_life(options, opts->lifetime);
if (opts->rlife)
- krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife);
+ krb5_get_init_creds_opt_set_renew_life(options, opts->rlife);
if (opts->forwardable)
- krb5_get_init_creds_opt_set_forwardable(&options, 1);
+ krb5_get_init_creds_opt_set_forwardable(options, 1);
if (opts->not_forwardable)
- krb5_get_init_creds_opt_set_forwardable(&options, 0);
+ krb5_get_init_creds_opt_set_forwardable(options, 0);
if (opts->proxiable)
- krb5_get_init_creds_opt_set_proxiable(&options, 1);
+ krb5_get_init_creds_opt_set_proxiable(options, 1);
if (opts->not_proxiable)
- krb5_get_init_creds_opt_set_proxiable(&options, 0);
+ krb5_get_init_creds_opt_set_proxiable(options, 0);
if (opts->addresses)
{
krb5_address **addresses = NULL;
@@ -785,10 +831,10 @@ k5_kinit(opts, k5)
com_err(progname, code, "getting local addresses");
goto cleanup;
}
- krb5_get_init_creds_opt_set_address_list(&options, addresses);
+ krb5_get_init_creds_opt_set_address_list(options, addresses);
}
if (opts->no_addresses)
- krb5_get_init_creds_opt_set_address_list(&options, NULL);
+ krb5_get_init_creds_opt_set_address_list(options, NULL);
if ((opts->action == INIT_KT) && opts->keytab_name)
{
@@ -800,20 +846,49 @@ k5_kinit(opts, k5)
}
}
+ for (i = 0; i < opts->num_pa_opts; i++) {
+ code = krb5_get_init_creds_opt_set_pa(k5->ctx, options,
+ opts->pa_opts[i].attr,
+ opts->pa_opts[i].value);
+ if (code != 0) {
+ com_err(progname, code, "while setting '%s'='%s'",
+ opts->pa_opts[i].attr, opts->pa_opts[i].value);
+ goto cleanup;
+ }
+ }
+
+#if 0 /* XXX Testing... */
+ code = krb5_get_init_creds_opt_set_pkinit(
+ k5->ctx, /* context */
+ options, /* get_init_creds_opt */
+ NULL, /* principal */
+ "/tmp/x509up_u20010", /* X509_user_identity */
+ "/etc/grid-security/certificates", /* X509_anchors */
+ NULL, /* X509_chain_list */
+ NULL, /* X509_revoke_list */
+ 0, /* flags */
+ NULL, /* prompter_fct */
+ NULL, /* prompter_data */
+ NULL); /* password */
+ if (code) {
+ com_err(progname, code, "while setting pkinit options");
+ goto cleanup;
+ }
+#endif
switch (opts->action) {
case INIT_PW:
code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me,
0, kinit_prompter, 0,
opts->starttime,
opts->service_name,
- &options);
+ options);
break;
case INIT_KT:
code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me,
keytab,
opts->starttime,
opts->service_name,
- &options);
+ options);
break;
case VALIDATE:
code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc,
@@ -876,9 +951,16 @@ k5_kinit(opts, k5)
notix = 0;
cleanup:
+ if (options)
+ krb5_get_init_creds_opt_free(k5->ctx, options);
if (my_creds.client == k5->me) {
my_creds.client = 0;
}
+ if (opts->pa_opts) {
+ free(opts->pa_opts);
+ opts->pa_opts = NULL;
+ opts->num_pa_opts = 0;
+ }
krb5_free_cred_contents(k5->ctx, &my_creds);
if (keytab)
krb5_kt_close(k5->ctx, keytab);
diff --git a/src/clients/kpasswd/kpasswd.c b/src/clients/kpasswd/kpasswd.c
index 95e33ff..204a8bf 100644
--- a/src/clients/kpasswd/kpasswd.c
+++ b/src/clients/kpasswd/kpasswd.c
@@ -49,7 +49,7 @@ int main(int argc, char *argv[])
krb5_principal princ;
char *pname;
krb5_ccache ccache;
- krb5_get_init_creds_opt opts;
+ krb5_get_init_creds_opt *opts = NULL;
krb5_creds creds;
char pw[1024];
@@ -102,26 +102,31 @@ int main(int argc, char *argv[])
get_name_from_passwd_file(argv[0], context, &princ);
}
- krb5_get_init_creds_opt_init(&opts);
- krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
- krb5_get_init_creds_opt_set_renew_life(&opts, 0);
- krb5_get_init_creds_opt_set_forwardable(&opts, 0);
- krb5_get_init_creds_opt_set_proxiable(&opts, 0);
+ if ((ret = krb5_get_init_creds_opt_alloc(context, &opts))) {
+ com_err(argv[0], ret, "allocating krb5_get_init_creds_opt");
+ exit(1);
+ }
+ krb5_get_init_creds_opt_set_tkt_life(opts, 5*60);
+ krb5_get_init_creds_opt_set_renew_life(opts, 0);
+ krb5_get_init_creds_opt_set_forwardable(opts, 0);
+ krb5_get_init_creds_opt_set_proxiable(opts, 0);
if ((ret = krb5_get_init_creds_password(context, &creds, princ, NULL,
krb5_prompter_posix, NULL,
- 0, "kadmin/changepw", &opts))) {
+ 0, "kadmin/changepw", opts))) {
if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
com_err(argv[0], 0,
"Password incorrect while getting initial ticket");
else
com_err(argv[0], ret, "getting initial ticket");
+ krb5_get_init_creds_opt_free(context, opts);
exit(1);
}
pwlen = sizeof(pw);
if ((ret = krb5_read_password(context, P1, P2, pw, &pwlen))) {
com_err(argv[0], ret, "while reading password");
+ krb5_get_init_creds_opt_free(context, opts);
exit(1);
}
@@ -129,6 +134,7 @@ int main(int argc, char *argv[])
&result_code, &result_code_string,
&result_string))) {
com_err(argv[0], ret, "changing password");
+ krb5_get_init_creds_opt_free(context, opts);
exit(1);
}
@@ -138,6 +144,7 @@ int main(int argc, char *argv[])
result_string.length?": ":"",
(int) result_string.length,
result_string.data ? result_string.data : "");
+ krb5_get_init_creds_opt_free(context, opts);
exit(2);
}
@@ -145,6 +152,7 @@ int main(int argc, char *argv[])
free(result_string.data);
if (result_code_string.data != NULL)
free(result_code_string.data);
+ krb5_get_init_creds_opt_free(context, opts);
printf("Password changed.\n");
exit(0);
diff --git a/src/clients/kpasswd/ksetpwd.c b/src/clients/kpasswd/ksetpwd.c
index 148e686..2eec397 100644
--- a/src/clients/kpasswd/ksetpwd.c
+++ b/src/clients/kpasswd/ksetpwd.c
@@ -34,8 +34,6 @@ static void get_init_creds_opt_init( krb5_get_init_creds_opt *outOptions )
{
krb5_preauthtype preauth[] = { KRB5_PADATA_ENC_TIMESTAMP };
krb5_enctype etypes[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_CRC};
- memset( outOptions, 0, sizeof(*outOptions) );
- krb5_get_init_creds_opt_init(outOptions);
krb5_get_init_creds_opt_set_address_list(outOptions, NULL);
krb5_get_init_creds_opt_set_etype_list( outOptions, etypes, sizeof(etypes)/sizeof(krb5_enctype) );
krb5_get_init_creds_opt_set_preauth_list(outOptions, preauth, sizeof(preauth)/sizeof(krb5_preauthtype) );
@@ -128,17 +126,21 @@ static kbrccache_t userinitcontext(
}
if( kres != 0 || have_credentials == 0 )
{
- krb5_get_init_creds_opt options;
- get_init_creds_opt_init(&options);
+ krb5_get_init_creds_opt *options = NULL;
+ kres = krb5_get_init_creds_opt_alloc(kcontext, &options);
+ if ( kres == 0 )
+ {
+ get_init_creds_opt_init(options);
/*
** no valid credentials - get new ones
*/
- kres = krb5_get_init_creds_password( kcontext, &kcreds, kme, pPass,
- NULL /*prompter*/,
- NULL /*data*/,
- 0 /*starttime*/,
- 0 /*in_tkt_service*/,
- &options /*options*/ );
+ kres = krb5_get_init_creds_password( kcontext, &kcreds, kme, pPass,
+ NULL /*prompter*/,
+ NULL /*data*/,
+ 0 /*starttime*/,
+ 0 /*in_tkt_service*/,
+ options /*options*/ );
+ }
if( kres == 0 )
{
if( numCreds <= 0 )
@@ -148,6 +150,7 @@ static kbrccache_t userinitcontext(
if( kres == 0 )
have_credentials = 1;
}
+ krb5_get_init_creds_opt_free(kcontext, options);
}
#ifdef NOTUSED
if( have_credentials )
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index ac4bb62..21b0f4d 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -876,6 +876,7 @@ typedef struct _krb5_preauth_context {
krb5_error_code (*client_process)(krb5_context context,
void *plugin_context,
void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc get_data_proc,
krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
@@ -893,6 +894,7 @@ typedef struct _krb5_preauth_context {
krb5_error_code (*client_tryagain)(krb5_context context,
void *plugin_context,
void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc get_data_proc,
krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
@@ -908,6 +910,7 @@ typedef struct _krb5_preauth_context {
krb5_data *s2kparams,
krb5_keyblock *as_key,
krb5_pa_data **new_pa_data);
+ supply_gic_opts_proc client_supply_gic_opts;
void (*client_req_init)(krb5_context context, void *plugin_context,
void **request_context);
void (*client_req_fini)(krb5_context context, void *plugin_context,
@@ -1014,6 +1017,74 @@ void krb5_free_etype_info
/*
* End "preauth.h"
*/
+
+/*
+ * Extending the krb5_get_init_creds_opt structure. The original
+ * krb5_get_init_creds_opt structure is defined publicly. The
+ * new extended version is private. The original interface
+ * assumed a pre-allocated structure which was passed to
+ * krb5_get_init_creds_init(). The new interface assumes that
+ * the caller will call krb5_get_init_creds_alloc() and
+ * krb5_get_init_creds_free().
+ *
+ * Callers MUST NOT call krb5_get_init_creds_init() after allocating an
+ * opts structure using krb5_get_init_creds_alloc(). To do so will
+ * introduce memory leaks. Unfortunately, there is no way to enforce
+ * this behavior.
+ *
+ * Two private flags are added for backward compatibility.
+ * KRB5_GET_INIT_CREDS_OPT_EXTENDED says that the structure was allocated
+ * with the new krb5_get_init_creds_opt_alloc() function.
+ * KRB5_GET_INIT_CREDS_OPT_SHADOWED is set to indicate that the extended
+ * structure is a shadow copy of an original krb5_get_init_creds_opt
+ * structure.
+ * If KRB5_GET_INIT_CREDS_OPT_SHADOWED is set after a call to
+ * krb5int_gic_opt_to_opte(), the resulting extended structure should be
+ * freed (using krb5_get_init_creds_free). Otherwise, the original
+ * structure was already extended and there is no need to free it.
+ */
+
+#define KRB5_GET_INIT_CREDS_OPT_EXTENDED 0x80000000
+#define KRB5_GET_INIT_CREDS_OPT_SHADOWED 0x40000000
+
+#define krb5_gic_opt_is_extended(s) \
+ (((s)->flags & KRB5_GET_INIT_CREDS_OPT_EXTENDED) ? 1 : 0)
+#define krb5_gic_opt_is_shadowed(s) \
+ (((s)->flags & KRB5_GET_INIT_CREDS_OPT_SHADOWED) ? 1 : 0)
+
+
+typedef struct _krb5_gic_opt_private {
+ int num_preauth_data;
+ krb5_gic_opt_pa_data *preauth_data;
+} krb5_gic_opt_private;
+
+typedef struct _krb5_gic_opt_ext {
+ krb5_flags flags;
+ krb5_deltat tkt_life;
+ krb5_deltat renew_life;
+ int forwardable;
+ int proxiable;
+ krb5_enctype *etype_list;
+ int etype_list_length;
+ krb5_address **address_list;
+ krb5_preauthtype *preauth_list;
+ int preauth_list_length;
+ krb5_data *salt;
+ /*
+ * Do not change anything above this point in this structure.
+ * It is identical to the public krb5_get_init_creds_opt structure.
+ * New members must be added below.
+ */
+ krb5_gic_opt_private *opt_private;
+} krb5_gic_opt_ext;
+
+krb5_error_code
+krb5int_gic_opt_to_opte(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_gic_opt_ext **opte,
+ unsigned int force,
+ const char *where);
+
krb5_error_code
krb5int_copy_data_contents (krb5_context, const krb5_data *, krb5_data *);
@@ -1040,14 +1111,14 @@ krb5_get_init_creds
void *prompter_data,
krb5_deltat start_time,
char *in_tkt_service,
- krb5_get_init_creds_opt *gic_options,
+ krb5_gic_opt_ext *gic_options,
krb5_gic_get_as_key_fct gak,
void *gak_data,
int *master,
krb5_kdc_rep **as_reply);
-void krb5int_populate_gic_opt (
- krb5_context, krb5_get_init_creds_opt *,
+krb5_error_code krb5int_populate_gic_opt (
+ krb5_context, krb5_gic_opt_ext **,
krb5_flags options, krb5_address * const *addrs, krb5_enctype *ktypes,
krb5_preauthtype *pre_auth_types, krb5_creds *creds);
@@ -1062,7 +1133,8 @@ krb5_error_code KRB5_CALLCONV krb5_do_preauth
krb5_enctype *etype, krb5_keyblock *as_key,
krb5_prompter_fct prompter, void *prompter_data,
krb5_gic_get_as_key_fct gak_fct, void *gak_data,
- krb5_preauth_client_rock *get_data_rock);
+ krb5_preauth_client_rock *get_data_rock,
+ krb5_gic_opt_ext *opte);
krb5_error_code KRB5_CALLCONV krb5_do_preauth_tryagain
(krb5_context context,
krb5_kdc_req *request,
@@ -1074,7 +1146,8 @@ krb5_error_code KRB5_CALLCONV krb5_do_preauth_tryagain
krb5_enctype *etype, krb5_keyblock *as_key,
krb5_prompter_fct prompter, void *prompter_data,
krb5_gic_get_as_key_fct gak_fct, void *gak_data,
- krb5_preauth_client_rock *get_data_rock);
+ krb5_preauth_client_rock *get_data_rock,
+ krb5_gic_opt_ext *opte);
void KRB5_CALLCONV krb5_init_preauth_context
(krb5_context);
void KRB5_CALLCONV krb5_free_preauth_context
@@ -1082,7 +1155,7 @@ void KRB5_CALLCONV krb5_free_preauth_context
void KRB5_CALLCONV krb5_clear_preauth_context_use_counts
(krb5_context);
void KRB5_CALLCONV krb5_preauth_prepare_request
- (krb5_context, krb5_get_init_creds_opt *, krb5_kdc_req *);
+ (krb5_context, krb5_gic_opt_ext *, krb5_kdc_req *);
void KRB5_CALLCONV krb5_preauth_request_context_init
(krb5_context);
void KRB5_CALLCONV krb5_preauth_request_context_fini
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 1c5f157..ff0a31b 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -2081,6 +2081,16 @@ typedef struct _krb5_get_init_creds_opt {
#define KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT 0x0100
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_alloc
+(krb5_context context,
+ krb5_get_init_creds_opt **opt);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_free
+(krb5_context context,
+ krb5_get_init_creds_opt *opt);
+
void KRB5_CALLCONV
krb5_get_init_creds_opt_init
(krb5_get_init_creds_opt *opt);
@@ -2132,6 +2142,27 @@ krb5_get_init_creds_opt_set_change_password_prompt
(krb5_get_init_creds_opt *opt,
int prompt);
+/* Generic preauth option attribute/value pairs */
+typedef struct _krb5_gic_opt_pa_data {
+ char *attr;
+ char *value;
+} krb5_gic_opt_pa_data;
+
+/*
+ * This function allows the caller to supply options to preauth
+ * plugins. Preauth plugin modules are given a chance to look
+ * at each option at the time this function is called in ordre
+ * to check the validity of the option.
+ * The 'opt' pointer supplied to this function must have been
+ * obtained using krb5_get_init_creds_opt_alloc()
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_set_pa
+ (krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value);
+
krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_password
(krb5_context context,
diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h
index f8a9db1..7243a00 100644
--- a/src/include/krb5/preauth_plugin.h
+++ b/src/include/krb5/preauth_plugin.h
@@ -158,6 +158,17 @@ typedef krb5_error_code
void *gak_data);
/*
+ * Client function which receives krb5_get_init_creds_opt information.
+ * The attr and value information supplied should be copied locally by
+ * the module if it wishes to reference it after returning from this call.
+ */
+typedef krb5_error_code
+(*supply_gic_opts_proc)(krb5_context context,
+ void *plugin_context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value);
+/*
* The function table / structure which a preauth client module must export as
* "preauthentication_client_0". If the interfaces work correctly, future
* versions of the table will add either more callbacks or more arguments to
@@ -207,6 +218,7 @@ typedef struct krb5plugin_preauth_client_ftable_v0 {
krb5_error_code (*process)(krb5_context context,
void *plugin_context,
void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc get_data_proc,
struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
@@ -227,8 +239,9 @@ typedef struct krb5plugin_preauth_client_ftable_v0 {
krb5_error_code (*tryagain)(krb5_context context,
void *plugin_context,
void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc get_data_proc,
- struct _krb5_preauth_client_rock *rock,
+ struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
krb5_data *encoded_request_body,
krb5_data *encoded_previous_request,
@@ -241,6 +254,12 @@ typedef struct krb5plugin_preauth_client_ftable_v0 {
krb5_data *salt, krb5_data *s2kparams,
krb5_keyblock *as_key,
krb5_pa_data **out_pa_data);
+ /*
+ * Client function which receives krb5_get_init_creds_opt information.
+ * The attr and value information supplied should be copied locally by
+ * the module if it wishes to reference it after returning from this call.
+ */
+ supply_gic_opts_proc gic_opts;
} krb5plugin_preauth_client_ftable_v0;
/*
@@ -323,4 +342,31 @@ typedef struct krb5plugin_preauth_server_ftable_v0 {
void *pa_module_context,
void **request_pa_context);
} krb5plugin_preauth_server_ftable_v0;
+
+
+/*
+ * This function allows a preauth plugin to obtain preauth
+ * options. The preauth_data returned from this function
+ * should be freed by calling krb5_get_init_creds_opt_free_pa().
+ *
+ * The 'opt' pointer supplied to this function must have been
+ * obtained using krb5_get_init_creds_opt_alloc()
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_get_pa
+ (krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ int *num_preauth_data,
+ krb5_gic_opt_pa_data **preauth_data);
+
+/*
+ * This function frees the preauth_data that was returned by
+ * krb5_get_init_creds_opt_get_pa().
+ */
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_free_pa
+ (krb5_context context,
+ int num_preauth_data,
+ krb5_gic_opt_pa_data *preauth_data);
+
#endif /* KRB5_PREAUTH_PLUGIN_H_INCLUDED */
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index 12476d3..efde914 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -843,7 +843,7 @@ krb5_get_init_creds(krb5_context context,
void *prompter_data,
krb5_deltat start_time,
char *in_tkt_service,
- krb5_get_init_creds_opt *options,
+ krb5_gic_opt_ext *options,
krb5_gic_get_as_key_fct gak_fct,
void *gak_data,
int *use_master,
@@ -1111,30 +1111,21 @@ krb5_get_init_creds(krb5_context context,
&salt, &s2kparams, &etype, &as_key,
prompter, prompter_data,
gak_fct, gak_data,
- &get_data_rock)))
+ &get_data_rock, options)))
goto cleanup;
} else {
- if (preauth_to_use != NULL) {
- /*
- * Retry after an error other than PREAUTH_NEEDED,
- * using e-data to figure out what to change.
- */
- ret = krb5_do_preauth_tryagain(context,
- &request,
- encoded_request_body,
- encoded_previous_request,
- preauth_to_use, &request.padata,
- err_reply,
- &salt, &s2kparams, &etype,
- &as_key,
- prompter, prompter_data,
- gak_fct, gak_data,
- &get_data_rock);
- } else {
- /* No preauth supplied, so can't query the plug-ins. */
- ret = KRB5KRB_ERR_GENERIC;
- }
- if (ret) {
+ /* retrying after an error other than PREAUTH_NEEDED, using e-data
+ * to figure out what to change */
+ if (krb5_do_preauth_tryagain(context,
+ &request,
+ encoded_request_body,
+ encoded_previous_request,
+ preauth_to_use, &request.padata,
+ err_reply,
+ &salt, &s2kparams, &etype, &as_key,
+ prompter, prompter_data,
+ gak_fct, gak_data,
+ &get_data_rock, options)) {
/* couldn't come up with anything better */
ret = err_reply->error + ERROR_TABLE_BASE_krb5;
}
@@ -1214,7 +1205,7 @@ krb5_get_init_creds(krb5_context context,
local_as_reply->padata, &kdc_padata,
&salt, &s2kparams, &etype, &as_key, prompter,
prompter_data, gak_fct, gak_data,
- &get_data_rock)))
+ &get_data_rock, options)))
goto cleanup;
/* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
diff --git a/src/lib/krb5/krb/gic_keytab.c b/src/lib/krb5/krb/gic_keytab.c
index ba704e6..cae0495 100644
--- a/src/lib/krb5/krb/gic_keytab.c
+++ b/src/lib/krb5/krb/gic_keytab.c
@@ -76,11 +76,18 @@ krb5_get_as_key_keytab(
}
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, krb5_get_init_creds_opt *options)
+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,
+ krb5_get_init_creds_opt *options)
{
krb5_error_code ret, ret2;
int use_master;
krb5_keytab keytab;
+ krb5_gic_opt_ext *opte = NULL;
if (arg_keytab == NULL) {
if ((ret = krb5_kt_default(context, &keytab)))
@@ -89,12 +96,17 @@ krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_princip
keytab = arg_keytab;
}
+ ret = krb5int_gic_opt_to_opte(context, options, &opte, 1,
+ "krb5_get_init_creds_keytab");
+ if (ret)
+ return ret;
+
use_master = 0;
/* first try: get the requested tkt from any kdc */
ret = krb5_get_init_creds(context, creds, client, NULL, NULL,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_keytab, (void *) keytab,
&use_master,NULL);
@@ -115,7 +127,7 @@ krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_princip
use_master = 1;
ret2 = krb5_get_init_creds(context, creds, client, NULL, NULL,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_keytab, (void *) keytab,
&use_master, NULL);
@@ -139,6 +151,8 @@ krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_princip
do any prompting or changing for keytabs, that's it. */
cleanup:
+ if (opte && krb5_gic_opt_is_shadowed(opte))
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
if (arg_keytab == NULL)
krb5_kt_close(context, keytab);
@@ -152,15 +166,18 @@ krb5_get_in_tkt_with_keytab(krb5_context context, krb5_flags options,
krb5_creds *creds, krb5_kdc_rep **ret_as_reply)
{
krb5_error_code retval;
- krb5_get_init_creds_opt opt;
+ krb5_gic_opt_ext *opte;
char * server = NULL;
krb5_keytab keytab;
krb5_principal client_princ, server_princ;
int use_master = 0;
- krb5int_populate_gic_opt(context, &opt,
- options, addrs, ktypes,
- pre_auth_types, creds);
+ retval = krb5int_populate_gic_opt(context, &opte,
+ options, addrs, ktypes,
+ pre_auth_types, creds);
+ if (retval)
+ return retval;
+
if (arg_keytab == NULL) {
retval = krb5_kt_default(context, &keytab);
if (retval)
@@ -176,10 +193,11 @@ krb5_get_in_tkt_with_keytab(krb5_context context, krb5_flags options,
retval = krb5_get_init_creds (context,
creds, creds->client,
krb5_prompter_posix, NULL,
- 0, server, &opt,
+ 0, server, opte,
krb5_get_as_key_keytab, (void *)keytab,
&use_master, ret_as_reply);
krb5_free_unparsed_name( context, server);
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
if (retval) {
goto cleanup;
}
diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c
index 3ec59e8..10fe759 100644
--- a/src/lib/krb5/krb/gic_opt.c
+++ b/src/lib/krb5/krb/gic_opt.c
@@ -64,11 +64,419 @@ krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt, krb5_data *salt)
opt->salt = salt;
}
+/*
+ * Extending the krb5_get_init_creds_opt structure. The original
+ * krb5_get_init_creds_opt structure is defined publicly. The
+ * new extended version is private. The original interface
+ * assumed a pre-allocated structure which was passed to
+ * krb5_get_init_creds_init(). The new interface assumes that
+ * the caller will call krb5_get_init_creds_alloc() and
+ * krb5_get_init_creds_free().
+ *
+ * Callers MUST NOT call krb5_get_init_creds_init() after allocating an
+ * opts structure using krb5_get_init_creds_alloc(). To do so will
+ * introduce memory leaks. Unfortunately, there is no way to enforce
+ * this behavior.
+ *
+ * Two private flags are added for backward compatibility.
+ * KRB5_GET_INIT_CREDS_OPT_EXTENDED says that the structure was allocated
+ * with the new krb5_get_init_creds_opt_alloc() function.
+ * KRB5_GET_INIT_CREDS_OPT_SHADOWED is set to indicate that the extended
+ * structure is a shadow copy of an original krb5_get_init_creds_opt
+ * structure.
+ * If KRB5_GET_INIT_CREDS_OPT_SHADOWED is set after a call to
+ * krb5int_gic_opt_to_opte(), the resulting extended structure should be
+ * freed (using krb5_get_init_creds_free). Otherwise, the original
+ * structure was already extended and there is no need to free it.
+ */
+
+/* Forward prototype */
+static void
+free_gic_opt_ext_preauth_data(krb5_context context,
+ krb5_gic_opt_ext *opte);
+
+static krb5_error_code
+krb5int_gic_opte_private_alloc(krb5_context context, krb5_gic_opt_ext *opte)
+{
+ if (NULL == opte || !krb5_gic_opt_is_extended(opte))
+ return EINVAL;
+
+ opte->opt_private = calloc(1, sizeof(*opte->opt_private));
+ if (NULL == opte->opt_private) {
+ return ENOMEM;
+ }
+ /* Allocate any private stuff */
+ opte->opt_private->num_preauth_data = 0;
+ opte->opt_private->preauth_data = NULL;
+ return 0;
+}
+
+static krb5_error_code
+krb5int_gic_opte_private_free(krb5_context context, krb5_gic_opt_ext *opte)
+{
+ if (NULL == opte || !krb5_gic_opt_is_extended(opte))
+ return EINVAL;
+
+ /* Free up any private stuff */
+ if (opte->opt_private->preauth_data != NULL)
+ free_gic_opt_ext_preauth_data(context, opte);
+ free(opte->opt_private);
+ opte->opt_private = NULL;
+ return 0;
+}
+
+static krb5_gic_opt_ext *
+krb5int_gic_opte_alloc(krb5_context context)
+{
+ krb5_gic_opt_ext *opte;
+ krb5_error_code code;
+
+ opte = calloc(1, sizeof(*opte));
+ if (NULL == opte)
+ return NULL;
+ opte->flags = KRB5_GET_INIT_CREDS_OPT_EXTENDED;
+
+ code = krb5int_gic_opte_private_alloc(context, opte);
+ if (code) {
+ krb5int_set_error(&context->err, code,
+ "krb5int_gic_opte_alloc: krb5int_gic_opte_private_alloc failed");
+ free(opte);
+ return NULL;
+ }
+ return(opte);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_alloc(krb5_context context,
+ krb5_get_init_creds_opt **opt)
+{
+ krb5_gic_opt_ext *opte;
+
+ if (NULL == opt)
+ return EINVAL;
+ *opt = NULL;
+
+ /*
+ * We return a new extended structure cast as a krb5_get_init_creds_opt
+ */
+ opte = krb5int_gic_opte_alloc(context);
+ if (NULL == opte)
+ return ENOMEM;
+
+ *opt = (krb5_get_init_creds_opt *) opte;
+ return 0;
+}
+
void KRB5_CALLCONV
-krb5_get_init_creds_opt_set_change_password_prompt(krb5_get_init_creds_opt *opt, int prompt)
+krb5_get_init_creds_opt_free(krb5_context context,
+ krb5_get_init_creds_opt *opt)
{
- if (prompt)
- opt->flags |= KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT;
- else
- opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT;
+ krb5_gic_opt_ext *opte;
+
+ if (NULL == opt)
+ return;
+
+ /* Don't touch it if we didn't allocate it */
+ if (!krb5_gic_opt_is_extended(opt))
+ return;
+
+ opte = (krb5_gic_opt_ext *)opt;
+ if (opte->opt_private)
+ krb5int_gic_opte_private_free(context, opte);
+
+ free(opte);
+}
+
+static krb5_error_code
+krb5int_gic_opte_copy(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_gic_opt_ext **opte)
+{
+ krb5_gic_opt_ext *oe;
+
+ oe = krb5int_gic_opte_alloc(context);
+ if (NULL == oe)
+ return ENOMEM;
+ memcpy(oe, opt, sizeof(*opt));
+ /* Fix these -- overwritten by the copy */
+ oe->flags |= ( KRB5_GET_INIT_CREDS_OPT_EXTENDED |
+ KRB5_GET_INIT_CREDS_OPT_SHADOWED);
+
+ *opte = oe;
+ return 0;
+}
+
+/*
+ * Convert a krb5_get_init_creds_opt pointer to a pointer to
+ * an extended, krb5_gic_opt_ext pointer. If the original
+ * pointer already points to an extended structure, then simply
+ * return the original pointer. Otherwise, if 'force' is non-zero,
+ * allocate an extended structure and copy the original over it.
+ * If the original pointer did not point to an extended structure
+ * and 'force' is zero, then return an error. This is used in
+ * cases where the original *should* be an extended structure.
+ */
+krb5_error_code
+krb5int_gic_opt_to_opte(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_gic_opt_ext **opte,
+ unsigned int force,
+ const char *where)
+{
+ if (!krb5_gic_opt_is_extended(opt)) {
+ if (force) {
+ return krb5int_gic_opte_copy(context, opt, opte);
+ } else {
+ krb5int_set_error(&context->err, EINVAL,
+ "%s: attempt to convert non-extended krb5_get_init_creds_opt",
+ where);
+ return EINVAL;
+ }
+ }
+ /* If it is already extended, just return it */
+ *opte = (krb5_gic_opt_ext *)opt;
+ return 0;
+}
+
+static void
+free_gic_opt_ext_preauth_data(krb5_context context,
+ krb5_gic_opt_ext *opte)
+{
+ int i;
+
+ if (NULL == opte || !krb5_gic_opt_is_extended(opte))
+ return;
+ if (NULL == opte->opt_private || NULL == opte->opt_private->preauth_data)
+ return;
+
+ for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
+ if (opte->opt_private->preauth_data[i].attr != NULL)
+ free(opte->opt_private->preauth_data[i].attr);
+ if (opte->opt_private->preauth_data[i].value != NULL)
+ free(opte->opt_private->preauth_data[i].value);
+ }
+ free(opte->opt_private->preauth_data);
+ opte->opt_private->preauth_data = NULL;
+ opte->opt_private->num_preauth_data = 0;
+}
+
+static krb5_error_code
+add_gic_opt_ext_preauth_data(krb5_context context,
+ krb5_gic_opt_ext *opte,
+ const char *attr,
+ const char *value)
+{
+ size_t newsize;
+ int i;
+ krb5_gic_opt_pa_data *newpad;
+
+ newsize = opte->opt_private->num_preauth_data + 1;
+ newsize = newsize * sizeof(*opte->opt_private->preauth_data);
+ if (opte->opt_private->preauth_data == NULL)
+ newpad = malloc(newsize);
+ else
+ newpad = realloc(opte->opt_private->preauth_data, newsize);
+ if (newpad == NULL)
+ return ENOMEM;
+
+ i = opte->opt_private->num_preauth_data;
+ newpad[i].attr = strdup(attr);
+ if (newpad[i].attr == NULL)
+ return ENOMEM;
+ newpad[i].value = strdup(value);
+ if (newpad[i].value == NULL) {
+ free(newpad[i].attr);
+ return ENOMEM;
+ }
+ opte->opt_private->num_preauth_data += 1;
+ opte->opt_private->preauth_data = newpad;
+ return 0;
+}
+
+/*
+ * This function allows the caller to supply options to preauth
+ * plugins. Preauth plugin modules are given a chance to look
+ * at each option at the time this function is called in ordre
+ * to check the validity of the option.
+ * The 'opt' pointer supplied to this function must have been
+ * obtained using krb5_get_init_creds_opt_alloc()
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_set_pa(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value)
+{
+ krb5_error_code retval;
+ krb5_gic_opt_ext *opte;
+
+ retval = krb5int_gic_opt_to_opte(context, opt, &opte, 0,
+ "krb5_get_init_creds_opt_set_pa");
+ if (retval)
+ return retval;
+
+ /*
+ * Copy the option into the extended get_init_creds_opt structure
+ */
+ retval = add_gic_opt_ext_preauth_data(context, opte, attr, value);
+ if (retval)
+ return retval;
+
+ /*
+ * Give the plugins a chance to look at the option now.
+ */
+ retval = krb5_preauth_supply_preauth_data(context, opte, attr, value);
+ return retval;
+}
+
+/*
+ * This function allows a preauth plugin to obtain preauth
+ * options. The preauth_data returned from this function
+ * should be freed by calling krb5_get_init_creds_opt_free_pa().
+ *
+ * The 'opt' pointer supplied to this function must have been
+ * obtained using krb5_get_init_creds_opt_alloc()
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_get_pa(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ int *num_preauth_data,
+ krb5_gic_opt_pa_data **preauth_data)
+{
+ krb5_error_code retval;
+ krb5_gic_opt_ext *opte;
+ krb5_gic_opt_pa_data *p = NULL;
+ int i;
+ size_t allocsize;
+
+ retval = krb5int_gic_opt_to_opte(context, opt, &opte, 0,
+ "krb5_get_init_creds_opt_get_pa");
+ if (retval)
+ return retval;
+
+ if (num_preauth_data == NULL || preauth_data == NULL)
+ return EINVAL;
+
+ *num_preauth_data = 0;
+ *preauth_data = NULL;
+
+ if (opte->opt_private->num_preauth_data == 0)
+ return 0;
+
+ allocsize =
+ opte->opt_private->num_preauth_data * sizeof(krb5_gic_opt_pa_data);
+ p = malloc(allocsize);
+ if (p == NULL)
+ return ENOMEM;
+
+ /* Init these to make cleanup easier */
+ for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
+ p[i].attr = NULL;
+ p[i].value = NULL;
+ }
+
+ for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
+ p[i].attr = strdup(opte->opt_private->preauth_data[i].attr);
+ p[i].value = strdup(opte->opt_private->preauth_data[i].value);
+ if (p[i].attr == NULL || p[i].value == NULL)
+ goto cleanup;
+ }
+ *num_preauth_data = i;
+ *preauth_data = p;
+ return 0;
+cleanup:
+ for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
+ if (p[i].attr != NULL)
+ free(p[i].attr);
+ if (p[i].value != NULL)
+ free(p[i].value);
+ }
+ free(p);
+ return ENOMEM;
+}
+
+/*
+ * This function frees the preauth_data that was returned by
+ * krb5_get_init_creds_opt_get_pa().
+ */
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_free_pa(krb5_context context,
+ int num_preauth_data,
+ krb5_gic_opt_pa_data *preauth_data)
+{
+ int i;
+
+ if (num_preauth_data <= 0 || preauth_data == NULL)
+ return;
+
+ for (i = 0; i < num_preauth_data; i++) {
+ if (preauth_data[i].attr != NULL)
+ free(preauth_data[i].attr);
+ if (preauth_data[i].value != NULL)
+ free(preauth_data[i].value);
+ }
+ free(preauth_data);
+}
+
+
+/*
+ * This function is provided for compatibility with Heimdal's
+ * function of the same name. We ignore the principal,
+ * password, and prompter parameters.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_opt_set_pkinit(krb5_context context,
+ krb5_get_init_creds_opt *opt,
+ krb5_principal principal,
+ const char *x509_user_identity,
+ const char *x509_anchors,
+ char * const * x509_chain_list,
+ char * const * x509_revoke_list,
+ int flags,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ char *password)
+{
+ int i;
+ krb5_error_code retval;
+
+#define PKINIT_RSA_PROTOCOL 0x00000002 /* XXX */
+
+ if (x509_user_identity != NULL) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "X509_user_identity", x509_user_identity);
+ if (retval)
+ return retval;
+ }
+ if (x509_anchors != NULL) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "X509_anchors", x509_anchors);
+ if (retval)
+ return retval;
+ }
+ if (x509_chain_list != NULL) {
+ for (i = 0; x509_chain_list[i] != NULL; i++) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "X509_chain_list", x509_chain_list[i]);
+ if (retval)
+ return retval;
+ }
+ }
+ if (x509_revoke_list != NULL) {
+ for (i = 0; x509_revoke_list[i] != NULL; i++) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "X509_revoke_list", x509_revoke_list[i]);
+ if (retval)
+ return retval;
+ }
+ }
+ if (flags != 0) {
+ if (flags & PKINIT_RSA_PROTOCOL) {
+ retval = krb5_get_init_creds_opt_set_pa(context, opt,
+ "flag_RSA_PROTOCOL", "yes");
+ if (retval)
+ return retval;
+ }
+ }
+ return retval;
}
diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c
index f7f62f4..02d344c 100644
--- a/src/lib/krb5/krb/gic_pwd.c
+++ b/src/lib/krb5/krb/gic_pwd.c
@@ -85,18 +85,28 @@ krb5_get_as_key_password(
}
krb5_error_code KRB5_CALLCONV
-krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_principal client, char *password, krb5_prompter_fct prompter, void *data, krb5_deltat start_time, char *in_tkt_service, krb5_get_init_creds_opt *options)
+krb5_get_init_creds_password(krb5_context context,
+ krb5_creds *creds,
+ krb5_principal client,
+ char *password,
+ krb5_prompter_fct prompter,
+ void *data,
+ krb5_deltat start_time,
+ char *in_tkt_service,
+ krb5_get_init_creds_opt *options)
{
krb5_error_code ret, ret2;
int use_master;
krb5_kdc_rep *as_reply;
int tries;
krb5_creds chpw_creds;
- krb5_get_init_creds_opt chpw_opts;
+ krb5_get_init_creds_opt *chpw_opts = NULL;
krb5_data pw0, pw1;
char banner[1024], pw0array[1024], pw1array[1024];
krb5_prompt prompt[2];
krb5_prompt_type prompt_types[sizeof(prompt)/sizeof(prompt[0])];
+ krb5_gic_opt_ext *opte = NULL;
+ krb5_gic_opt_ext *chpw_opte = NULL;
use_master = 0;
as_reply = NULL;
@@ -119,10 +129,15 @@ krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_princ
pw1.data[0] = '\0';
pw1.length = sizeof(pw1array);
+ ret = krb5int_gic_opt_to_opte(context, options, &opte, 1,
+ "krb5_get_init_creds_password");
+ if (ret)
+ goto cleanup;
+
/* first try: get the requested tkt from any kdc */
ret = krb5_get_init_creds(context, creds, client, prompter, data,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_password, (void *) &pw0,
&use_master, &as_reply);
@@ -151,7 +166,7 @@ krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_princ
as_reply = NULL;
}
ret2 = krb5_get_init_creds(context, creds, client, prompter, data,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_password, (void *) &pw0,
&use_master, &as_reply);
@@ -197,15 +212,21 @@ krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_princ
/* use a minimal set of options */
- krb5_get_init_creds_opt_init(&chpw_opts);
- krb5_get_init_creds_opt_set_tkt_life(&chpw_opts, 5*60);
- krb5_get_init_creds_opt_set_renew_life(&chpw_opts, 0);
- krb5_get_init_creds_opt_set_forwardable(&chpw_opts, 0);
- krb5_get_init_creds_opt_set_proxiable(&chpw_opts, 0);
+ ret = krb5_get_init_creds_opt_alloc(context, &chpw_opts);
+ if (ret)
+ goto cleanup;
+ krb5_get_init_creds_opt_set_tkt_life(chpw_opts, 5*60);
+ krb5_get_init_creds_opt_set_renew_life(chpw_opts, 0);
+ krb5_get_init_creds_opt_set_forwardable(chpw_opts, 0);
+ krb5_get_init_creds_opt_set_proxiable(chpw_opts, 0);
+ ret = krb5int_gic_opt_to_opte(context, chpw_opts, &chpw_opte, 0,
+ "krb5_get_init_creds_password (changing password)");
+ if (ret)
+ goto cleanup;
if ((ret = krb5_get_init_creds(context, &chpw_creds, client,
prompter, data,
- start_time, "kadmin/changepw", &chpw_opts,
+ start_time, "kadmin/changepw", chpw_opte,
krb5_get_as_key_password, (void *) &pw0,
&use_master, NULL)))
goto cleanup;
@@ -293,7 +314,7 @@ krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_princ
is final. */
ret = krb5_get_init_creds(context, creds, client, prompter, data,
- start_time, in_tkt_service, options,
+ start_time, in_tkt_service, opte,
krb5_get_as_key_password, (void *) &pw0,
&use_master, &as_reply);
@@ -373,6 +394,10 @@ cleanup:
}
}
+ if (chpw_opts)
+ krb5_get_init_creds_opt_free(context, chpw_opts);
+ if (opte && krb5_gic_opt_is_shadowed(opte))
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
memset(pw0array, 0, sizeof(pw0array));
memset(pw1array, 0, sizeof(pw1array));
krb5_free_cred_contents(context, &chpw_creds);
@@ -381,15 +406,20 @@ cleanup:
return(ret);
}
-void krb5int_populate_gic_opt (
- krb5_context context, krb5_get_init_creds_opt *opt,
+krb5_error_code krb5int_populate_gic_opt (
+ krb5_context context, krb5_gic_opt_ext **opte,
krb5_flags options, krb5_address * const *addrs, krb5_enctype *ktypes,
krb5_preauthtype *pre_auth_types, krb5_creds *creds)
{
int i;
krb5_int32 starttime;
+ krb5_get_init_creds_opt *opt;
+ krb5_error_code retval;
+
+ retval = krb5_get_init_creds_opt_alloc(context, &opt);
+ if (retval)
+ return(retval);
- krb5_get_init_creds_opt_init(opt);
if (addrs)
krb5_get_init_creds_opt_set_address_list(opt, (krb5_address **) addrs);
if (ktypes) {
@@ -413,6 +443,8 @@ void krb5int_populate_gic_opt (
if (creds->times.starttime) starttime = creds->times.starttime;
krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
}
+ return krb5int_gic_opt_to_opte(context, opt, opte, 0,
+ "krb5int_populate_gic_opt");
}
/*
@@ -445,10 +477,10 @@ krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options,
krb5_error_code retval;
krb5_data pw0;
char pw0array[1024];
- krb5_get_init_creds_opt opt;
char * server;
krb5_principal server_princ, client_princ;
int use_master = 0;
+ krb5_gic_opt_ext *opte = NULL;
pw0array[0] = '\0';
pw0.data = pw0array;
@@ -462,21 +494,26 @@ krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options,
} else {
pw0.length = sizeof(pw0array);
}
- krb5int_populate_gic_opt(context, &opt,
- options, addrs, ktypes,
- pre_auth_types, creds);
- retval = krb5_unparse_name( context, creds->server, &server);
+ retval = krb5int_populate_gic_opt(context, &opte,
+ options, addrs, ktypes,
+ pre_auth_types, creds);
if (retval)
return (retval);
+ retval = krb5_unparse_name( context, creds->server, &server);
+ if (retval) {
+ return (retval);
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
+ }
server_princ = creds->server;
client_princ = creds->client;
retval = krb5_get_init_creds (context,
creds, creds->client,
krb5_prompter_posix, NULL,
- 0, server, &opt,
+ 0, server, opte,
krb5_get_as_key_password, &pw0,
&use_master, ret_as_reply);
krb5_free_unparsed_name( context, server);
+ krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
if (retval) {
return (retval);
}
diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c
index 598709a..2a2756f 100644
--- a/src/lib/krb5/krb/preauth2.c
+++ b/src/lib/krb5/krb/preauth2.c
@@ -163,6 +163,10 @@ krb5_init_preauth_context(krb5_context kcontext)
context->modules[k].use_count = 0;
context->modules[k].client_process = table->process;
context->modules[k].client_tryagain = table->tryagain;
+ if (j == 0)
+ context->modules[k].client_supply_gic_opts = table->gic_opts;
+ else
+ context->modules[k].client_supply_gic_opts = NULL;
context->modules[k].request_context = NULL;
/*
* Only call request_init and request_fini once per plugin.
@@ -211,6 +215,52 @@ krb5_clear_preauth_context_use_counts(krb5_context context)
}
}
+/*
+ * Give all the preauth plugins a look at the preauth option which
+ * has just been set
+ */
+krb5_error_code
+krb5_preauth_supply_preauth_data(krb5_context context,
+ krb5_gic_opt_ext *opte,
+ const char *attr,
+ const char *value)
+{
+ krb5_error_code retval;
+ int i;
+ void *pctx;
+ const char *emsg = NULL;
+
+ if (context->preauth_context == NULL)
+ krb5_init_preauth_context(context);
+ if (context->preauth_context == NULL) {
+ retval = EINVAL;
+ krb5int_set_error(&context->err, retval,
+ "krb5_preauth_supply_preauth_data: "
+ "Unable to initialize preauth context");
+ return retval;
+ }
+
+ /*
+ * Go down the list of preauth modules, and supply them with the
+ * attribute/value pair.
+ */
+ for (i = 0; i < context->preauth_context->n_modules; i++) {
+ if (context->preauth_context->modules[i].client_supply_gic_opts == NULL)
+ continue;
+ pctx = context->preauth_context->modules[i].plugin_context;
+ retval = (*context->preauth_context->modules[i].client_supply_gic_opts)
+ (context, pctx,
+ (krb5_get_init_creds_opt *)opte, attr, value);
+ if (retval) {
+ emsg = krb5_get_error_message(context, retval);
+ krb5int_set_error(&context->err, retval, "Preauth plugin %s: %s",
+ context->preauth_context->modules[i].name, emsg);
+ break;
+ }
+ }
+ return retval;
+}
+
/* Free the per-krb5_context preauth_context. This means clearing any
* plugin-specific context which may have been created, and then
* freeing the context itself. */
@@ -405,7 +455,7 @@ client_data_proc(krb5_context kcontext,
* involved things. */
void KRB5_CALLCONV
krb5_preauth_prepare_request(krb5_context kcontext,
- krb5_get_init_creds_opt *options,
+ krb5_gic_opt_ext *opte,
krb5_kdc_req *request)
{
int i, j;
@@ -415,7 +465,7 @@ krb5_preauth_prepare_request(krb5_context kcontext,
}
/* Add the module-specific enctype list to the request, but only if
* it's something we can safely modify. */
- if (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
+ if (!(opte && (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
if (kcontext->preauth_context->modules[i].enctypes == NULL)
continue;
@@ -448,7 +498,8 @@ krb5_run_preauth_plugins(krb5_context kcontext,
krb5_pa_data ***out_pa_list,
int *out_pa_list_size,
int *module_ret,
- int *module_flags)
+ int *module_flags,
+ krb5_gic_opt_ext *opte)
{
int i;
krb5_pa_data *out_pa_data;
@@ -487,6 +538,7 @@ krb5_run_preauth_plugins(krb5_context kcontext,
ret = module->client_process(kcontext,
module->plugin_context,
*module->request_context_pp,
+ (krb5_get_init_creds_opt *)opte,
client_data_proc,
get_data_rock,
request,
@@ -1299,7 +1351,8 @@ krb5_do_preauth_tryagain(krb5_context kcontext,
krb5_keyblock *as_key,
krb5_prompter_fct prompter, void *prompter_data,
krb5_gic_get_as_key_fct gak_fct, void *gak_data,
- krb5_preauth_client_rock *get_data_rock)
+ krb5_preauth_client_rock *get_data_rock,
+ krb5_gic_opt_ext *opte)
{
krb5_error_code ret;
krb5_pa_data *out_padata;
@@ -1330,6 +1383,7 @@ krb5_do_preauth_tryagain(krb5_context kcontext,
if ((*module->client_tryagain)(kcontext,
module->plugin_context,
*module->request_context_pp,
+ (krb5_get_init_creds_opt *)opte,
client_data_proc,
get_data_rock,
request,
@@ -1362,7 +1416,8 @@ krb5_do_preauth(krb5_context context,
krb5_keyblock *as_key,
krb5_prompter_fct prompter, void *prompter_data,
krb5_gic_get_as_key_fct gak_fct, void *gak_data,
- krb5_preauth_client_rock *get_data_rock)
+ krb5_preauth_client_rock *get_data_rock,
+ krb5_gic_opt_ext *opte)
{
int h, i, j, out_pa_list_size;
int seen_etype_info2 = 0;
@@ -1555,7 +1610,8 @@ krb5_do_preauth(krb5_context context,
&out_pa_list,
&out_pa_list_size,
&module_ret,
- &module_flags);
+ &module_flags,
+ opte);
if (ret == 0) {
if (module_ret == 0) {
if (paorder[h] == PA_REAL) {
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index bca1e1e..a46ad70 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -439,11 +439,16 @@ krb5_get_in_tkt_with_password
krb5_get_in_tkt_with_skey
krb5_get_init_creds
krb5_get_init_creds_keytab
+krb5_get_init_creds_opt_alloc
+krb5_get_init_creds_opt_free
+krb5_get_init_creds_opt_free_pa
+krb5_get_init_creds_opt_get_pa
krb5_get_init_creds_opt_init
krb5_get_init_creds_opt_set_address_list
krb5_get_init_creds_opt_set_change_password_prompt
krb5_get_init_creds_opt_set_etype_list
krb5_get_init_creds_opt_set_forwardable
+krb5_get_init_creds_opt_set_pa
krb5_get_init_creds_opt_set_preauth_list
krb5_get_init_creds_opt_set_proxiable
krb5_get_init_creds_opt_set_renew_life
@@ -739,3 +744,10 @@ profile_update_file_data
profile_update_relation
profile_verify_node
profile_write_tree_file
+krb5_set_error_message
+krb5_vset_error_message
+krb5_get_error_message
+krb5_free_error_message
+krb5_clear_error_message
+krb5int_init_context_kdc
+krb5_get_init_creds_opt_set_pkinit
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
index 078b8ca..5b833f4 100644
--- a/src/lib/krb5_32.def
+++ b/src/lib/krb5_32.def
@@ -155,7 +155,12 @@ krb5_c_string_to_key_with_params
krb5_get_in_tkt_with_password ; DEPRECATED
krb5_get_in_tkt_with_skey ; DEPRECATED
krb5_get_init_creds_keytab
+ krb5_get_init_creds_opt_alloc
+ krb5_get_init_creds_opt_free
+ krb5_get_init_creds_opt_free_pa
+ krb5_get_init_creds_opt_get_pa
krb5_get_init_creds_opt_init
+ krb5_get_init_creds_opt_set_pa
krb5_get_init_creds_opt_set_address_list
krb5_get_init_creds_opt_set_etype_list
krb5_get_init_creds_opt_set_forwardable
diff --git a/src/plugins/preauth/cksum_body/cksum_body_main.c b/src/plugins/preauth/cksum_body/cksum_body_main.c
index 6b46b00..cd19daf 100644
--- a/src/plugins/preauth/cksum_body/cksum_body_main.c
+++ b/src/plugins/preauth/cksum_body/cksum_body_main.c
@@ -78,6 +78,7 @@ static krb5_error_code
client_process(krb5_context kcontext,
void *client_plugin_context,
void *client_request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc client_get_data_proc,
struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
@@ -99,6 +100,27 @@ client_process(krb5_context kcontext,
krb5_error_code status = 0;
krb5_int32 cksumtype, *enctypes;
unsigned int i, n_enctypes, cksumtype_count;
+ int num_gic_info = 0;
+ krb5_gic_opt_pa_data *gic_info;
+
+ status = krb5_get_init_creds_opt_get_pa(kcontext, opt,
+ &num_gic_info, &gic_info);
+ if (status && status != ENOENT) {
+#ifdef DEBUG
+ fprintf(stderr, "Error from krb5_get_init_creds_opt_get_pa: %s\n",
+ error_message(status));
+#endif
+ return status;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "(cksum_body) Got the following gic options:\n");
+#endif
+ for (i = 0; i < num_gic_info; i++) {
+#ifdef DEBUG
+ fprintf(stderr, " '%s' = '%s'\n", gic_info[i].attr, gic_info[i].value);
+#endif
+ }
+ krb5_get_init_creds_opt_free_pa(kcontext, num_gic_info, gic_info);
memset(&checksum, 0, sizeof(checksum));
@@ -193,6 +215,20 @@ client_process(krb5_context kcontext,
return 0;
}
+static krb5_error_code
+client_gic_opt(krb5_context kcontext,
+ void *plugin_context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value)
+{
+#ifdef DEBUG
+ fprintf(stderr, "(cksum_body) client_gic_opt: received '%s' = '%s'\n",
+ attr, value);
+#endif
+ return 0;
+}
+
/* Initialize and tear down the server-side module, and do stat tracking. */
static krb5_error_code
server_init(krb5_context kcontext, void **module_context)
@@ -200,7 +236,7 @@ server_init(krb5_context kcontext, void **module_context)
struct server_stats *stats;
stats = malloc(sizeof(struct server_stats));
if (stats == NULL)
- return ENOMEM;
+ return ENOMEM;
stats->successes = 0;
stats->failures = 0;
*module_context = stats;
@@ -506,6 +542,7 @@ struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = {
NULL, /* request fini function */
client_process, /* process function */
NULL, /* try_again function */
+ client_gic_opt /* get init creds opt function */
};
struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = {
diff --git a/src/plugins/preauth/wpse/wpse_main.c b/src/plugins/preauth/wpse/wpse_main.c
index 46ea662..f858063 100644
--- a/src/plugins/preauth/wpse/wpse_main.c
+++ b/src/plugins/preauth/wpse/wpse_main.c
@@ -90,6 +90,7 @@ static krb5_error_code
client_process(krb5_context kcontext,
void *plugin_context,
void *request_context,
+ krb5_get_init_creds_opt *opt,
preauth_get_client_data_proc client_get_data_proc,
struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
@@ -208,6 +209,21 @@ client_req_cleanup(krb5_context kcontext, void *plugin_context, void *req_contex
return;
}
+static krb5_error_code
+client_gic_opt(krb5_context kcontext,
+ void *plugin_context,
+ krb5_get_init_creds_opt *opt,
+ const char *attr,
+ const char *value)
+{
+#ifdef DEBUG
+ fprintf(stderr, "(wpse) client_gic_opt: received '%s' = '%s'\n",
+ attr, value);
+#endif
+ return 0;
+}
+
+
/* Free state. */
static krb5_error_code
server_free_pa_request_context(krb5_context kcontext, void *plugin_context,
@@ -378,6 +394,7 @@ struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = {
client_req_cleanup, /* request fini function */
client_process, /* process function */
NULL, /* try_again function */
+ client_gic_opt /* get init creds opts function */
};
struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = {