summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2009-12-28 17:15:30 +0000
committerSam Hartman <hartmans@mit.edu>2009-12-28 17:15:30 +0000
commitec49e6e673ab229462ef18aa2986167eaa643643 (patch)
tree625dba55e939a0073cf69f7b79c8c0010df991eb /src/lib
parentc5479d0c5b29430a49cf3683513c1223a173ac4e (diff)
downloadkrb5-ec49e6e673ab229462ef18aa2986167eaa643643.tar.gz
krb5-ec49e6e673ab229462ef18aa2986167eaa643643.tar.xz
krb5-ec49e6e673ab229462ef18aa2986167eaa643643.zip
Anonymous support for Kerberos
This ticket implements Project/Anonymous pkinit from k5wiki. Provides support for completely anonymous principals and untested client support for realm-exposed anonymous authentication. * Introduce kinit -n * Introduce kadmin -n * krb5_get_init_creds_opt_set_out_ccache aliases the supplied ccache * No longer generate ad-initial-verified-cas in pkinit * Fix pkinit interactions with non-TGT authentication Merge remote branch 'anonymous' into trunk Conflicts: src/lib/krb5/krb/gic_opt.c ticket: 6607 Tags: enhancement git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23527 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/gssapi/krb5/disp_name.c9
-rw-r--r--src/lib/gssapi/krb5/import_name.c11
-rw-r--r--src/lib/kadm5/admin.h7
-rw-r--r--src/lib/kadm5/clnt/client_init.c60
-rw-r--r--src/lib/kadm5/clnt/libkadm5clnt.exports1
-rw-r--r--src/lib/kadm5/srv/libkadm5srv.exports1
-rw-r--r--src/lib/kadm5/srv/server_init.c13
-rw-r--r--src/lib/krb5/krb/bld_princ.c30
-rw-r--r--src/lib/krb5/krb/chk_trans.c6
-rw-r--r--src/lib/krb5/krb/get_in_tkt.c101
-rw-r--r--src/lib/krb5/krb/gic_opt.c20
-rw-r--r--src/lib/krb5/libkrb5.exports3
12 files changed, 228 insertions, 34 deletions
diff --git a/src/lib/gssapi/krb5/disp_name.c b/src/lib/gssapi/krb5/disp_name.c
index ac576f5b4..79b14f1a9 100644
--- a/src/lib/gssapi/krb5/disp_name.c
+++ b/src/lib/gssapi/krb5/disp_name.c
@@ -34,6 +34,8 @@ krb5_gss_display_name(minor_status, input_name, output_name_buffer,
krb5_context context;
krb5_error_code code;
char *str;
+ krb5_gss_name_t k5name = (krb5_gss_name_t) input_name;
+ gss_OID nametype = (gss_OID) gss_nt_krb5_name;
code = krb5_gss_init_context(&context);
if (code) {
@@ -49,6 +51,11 @@ krb5_gss_display_name(minor_status, input_name, output_name_buffer,
krb5_free_context(context);
return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
}
+ if (krb5_princ_type(context, k5name->princ) == KRB5_NT_WELLKNOWN) {
+ if (krb5_principal_compare(context, k5name->princ,
+ krb5_anonymous_principal()))
+ nametype = GSS_C_NT_ANONYMOUS;
+ }
if ((code = krb5_unparse_name(context,
((krb5_gss_name_t) input_name)->princ,
@@ -72,6 +79,6 @@ krb5_gss_display_name(minor_status, input_name, output_name_buffer,
*minor_status = 0;
if (output_name_type)
- *output_name_type = (gss_OID) gss_nt_krb5_name;
+ *output_name_type = (gss_OID) nametype;
return(GSS_S_COMPLETE);
}
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
index cd2748b56..cfb75fb22 100644
--- a/src/lib/gssapi/krb5/import_name.c
+++ b/src/lib/gssapi/krb5/import_name.c
@@ -154,7 +154,16 @@ krb5_gss_import_name(minor_status, input_name_buffer,
krb5_free_context(context);
return(GSS_S_FAILURE);
}
- } else {
+ } else if ((input_name_type != NULL) &&
+ g_OID_equal(input_name_type, GSS_C_NT_ANONYMOUS)) {
+ code = krb5_copy_principal(context, krb5_anonymous_principal(), &princ);
+ if (code != 0) {
+ krb5_free_context(context);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ }
+ else {
#ifndef NO_PASSWORD
uid_t uid;
struct passwd pwx;
diff --git a/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h
index 4196a19e2..8fad11177 100644
--- a/src/lib/kadm5/admin.h
+++ b/src/lib/kadm5/admin.h
@@ -338,6 +338,13 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name,
krb5_ui_4 api_version,
char **db_args,
void **server_handle);
+kadm5_ret_t kadm5_init_anonymous(krb5_context context, char *client_name,
+ char *service_name,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle);
kadm5_ret_t kadm5_init_with_password(krb5_context context,
char *client_name,
char *pass,
diff --git a/src/lib/kadm5/clnt/client_init.c b/src/lib/kadm5/clnt/client_init.c
index 95c4954ef..82033e9fd 100644
--- a/src/lib/kadm5/clnt/client_init.c
+++ b/src/lib/kadm5/clnt/client_init.c
@@ -59,7 +59,7 @@
#define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX"
-enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS };
+enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS , INIT_ANONYMOUS};
static kadm5_ret_t _kadm5_init_any(krb5_context context,
char *client_name,
@@ -129,6 +129,19 @@ kadm5_ret_t kadm5_init_with_password(krb5_context context, char *client_name,
api_version, db_args, server_handle);
}
+kadm5_ret_t kadm5_init_anonymous(krb5_context context, char *client_name,
+ char *service_name,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle)
+{
+ return _kadm5_init_any(context, client_name, INIT_ANONYMOUS, NULL, NULL,
+ service_name, params, struct_version,
+ api_version, db_args, server_handle);
+}
+
kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
char *service_name,
kadm5_config_params *params,
@@ -343,7 +356,8 @@ static kadm5_ret_t _kadm5_init_any(krb5_context context, char *client_name,
* The RPC connection is open; establish the GSS-API
* authentication context.
*/
- code = kadm5_setup_gss(handle, params_in, client_name, full_svcname);
+ code = kadm5_setup_gss(handle, params_in, (init_type == INIT_CREDS)?client_name:NULL,
+ full_svcname);
if (code)
goto error;
@@ -490,7 +504,7 @@ kadm5_get_init_creds(kadm5_server_handle_t handle,
full_svcname, full_svcname_len);
if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
|| code == KRB5_CC_NOTFOUND) && svcname_in == NULL) {
- /* Retry with old host-independent service princpal. */
+ /* Retry with old host-independent service principal. */
code = kadm5_gic_iter(handle, init_type, ccache,
client, pass,
KADM5_ADMIN_SERVICE, realm,
@@ -525,7 +539,7 @@ kadm5_gic_iter(kadm5_server_handle_t handle,
kadm5_ret_t code;
krb5_context ctx;
krb5_keytab kt;
- krb5_get_init_creds_opt opt;
+ krb5_get_init_creds_opt *opt = NULL;
krb5_creds mcreds, outcreds;
int n;
@@ -540,29 +554,32 @@ kadm5_gic_iter(kadm5_server_handle_t handle,
if (realm) {
n = snprintf(full_svcname, full_svcname_len, "%s@%s",
svcname, realm);
- if (n < 0 || n >= full_svcname_len)
+ if (n < 0 || n >= (int) full_svcname_len)
goto error;
} else {
/* krb5_princ_realm(client) is not null terminated */
n = snprintf(full_svcname, full_svcname_len, "%s@%.*s",
svcname, krb5_princ_realm(ctx, client)->length,
krb5_princ_realm(ctx, client)->data);
- if (n < 0 || n >= full_svcname_len)
+ if (n < 0 || n >= (int) full_svcname_len)
goto error;
}
/* Credentials for kadmin don't need to be forwardable or proxiable. */
if (init_type != INIT_CREDS) {
- krb5_get_init_creds_opt_init(&opt);
- krb5_get_init_creds_opt_set_forwardable(&opt, 0);
- krb5_get_init_creds_opt_set_proxiable(&opt, 0);
+ code = krb5_get_init_creds_opt_alloc(ctx, &opt);
+ krb5_get_init_creds_opt_set_forwardable(opt, 0);
+ krb5_get_init_creds_opt_set_proxiable(opt, 0);
+ krb5_get_init_creds_opt_set_out_ccache(ctx, opt, ccache);
+ if (init_type == INIT_ANONYMOUS)
+ krb5_get_init_creds_opt_set_anonymous(opt, 1);
}
- if (init_type == INIT_PASS) {
+ if (init_type == INIT_PASS || init_type == INIT_ANONYMOUS) {
code = krb5_get_init_creds_password(ctx, &outcreds, client, pass,
krb5_prompter_posix,
NULL, 0,
- full_svcname, &opt);
+ full_svcname, opt);
if (code)
goto error;
} else if (init_type == INIT_SKEY) {
@@ -572,7 +589,7 @@ kadm5_gic_iter(kadm5_server_handle_t handle,
goto error;
}
code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt,
- 0, full_svcname, &opt);
+ 0, full_svcname, opt);
if (pass)
krb5_kt_close(ctx, kt);
if (code)
@@ -588,14 +605,10 @@ kadm5_gic_iter(kadm5_server_handle_t handle,
if (code)
goto error;
}
- if (init_type != INIT_CREDS) {
- /* Caller has initialized ccache. */
- code = krb5_cc_store_cred(ctx, ccache, &outcreds);
- if (code)
- goto error;
- }
error:
krb5_free_cred_contents(ctx, &outcreds);
+ if (opt)
+ krb5_get_init_creds_opt_free(ctx, opt);
return code;
}
@@ -644,10 +657,13 @@ kadm5_setup_gss(kadm5_server_handle_t handle,
goto error;
}
- buf.value = client_name;
- buf.length = strlen((char *)buf.value) + 1;
- gssstat = gss_import_name(&minor_stat, &buf,
- (gss_OID) gss_nt_krb5_name, &gss_client);
+ if (client_name) {
+ buf.value = client_name;
+ buf.length = strlen((char *)buf.value) + 1;
+ gssstat = gss_import_name(&minor_stat, &buf,
+ (gss_OID) gss_nt_krb5_name, &gss_client);
+ } else gss_client = GSS_C_NO_NAME;
+
if (gssstat != GSS_S_COMPLETE) {
code = KADM5_GSS_ERROR;
goto error;
diff --git a/src/lib/kadm5/clnt/libkadm5clnt.exports b/src/lib/kadm5/clnt/libkadm5clnt.exports
index 617484778..5e81580b1 100644
--- a/src/lib/kadm5/clnt/libkadm5clnt.exports
+++ b/src/lib/kadm5/clnt/libkadm5clnt.exports
@@ -24,6 +24,7 @@ kadm5_get_principal
kadm5_get_principals
kadm5_get_privs
kadm5_init
+kadm5_init_anonymous
kadm5_init_krb5_context
kadm5_init_with_creds
kadm5_init_with_password
diff --git a/src/lib/kadm5/srv/libkadm5srv.exports b/src/lib/kadm5/srv/libkadm5srv.exports
index 35745be88..d8d3b2283 100644
--- a/src/lib/kadm5/srv/libkadm5srv.exports
+++ b/src/lib/kadm5/srv/libkadm5srv.exports
@@ -40,6 +40,7 @@ kadm5_get_principal_keys
kadm5_get_principals
kadm5_get_privs
kadm5_init
+kadm5_init_anonymous
kadm5_init_krb5_context
kadm5_init_with_creds
kadm5_init_with_password
diff --git a/src/lib/kadm5/srv/server_init.c b/src/lib/kadm5/srv/server_init.c
index ed71cbf96..557ef0ad4 100644
--- a/src/lib/kadm5/srv/server_init.c
+++ b/src/lib/kadm5/srv/server_init.c
@@ -104,6 +104,19 @@ kadm5_ret_t kadm5_init_with_password(krb5_context context, char *client_name,
server_handle);
}
+kadm5_ret_t kadm5_init_anonymous(krb5_context context, char *client_name,
+ char *service_name,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle)
+{
+ return kadm5_init(context, client_name, NULL, service_name, params,
+ struct_version, api_version, db_args,
+ server_handle);
+}
+
kadm5_ret_t kadm5_init_with_creds(krb5_context context,
char *client_name,
krb5_ccache ccache,
diff --git a/src/lib/krb5/krb/bld_princ.c b/src/lib/krb5/krb/bld_princ.c
index ac2c92a9e..8378599d3 100644
--- a/src/lib/krb5/krb/bld_princ.c
+++ b/src/lib/krb5/krb/bld_princ.c
@@ -187,3 +187,33 @@ krb5_build_principal(krb5_context context,
return retval;
}
+
+/*Anonymous and well known principals*/
+static const char anon_realm_str[]
+= KRB5_ANONYMOUS_REALMSTR;
+static const krb5_data anon_realm_data = {
+ KV5M_DATA, sizeof(anon_realm_str)-1,
+ (char *) anon_realm_str};
+static const char wellknown_str[] = KRB5_WELLKNOWN_NAMESTR;
+static const char anon_str[] = KRB5_ANONYMOUS_PRINCSTR;
+static const krb5_data anon_princ_data[] = {
+ {KV5M_DATA, sizeof(wellknown_str)-1, (char *) wellknown_str},
+ {KV5M_DATA, sizeof(anon_str)-1, (char *)anon_str}
+};
+
+const krb5_principal_data anon_princ = {
+ KV5M_PRINCIPAL,
+ {KV5M_DATA, sizeof(anon_realm_str)-1, (char *) anon_realm_str},
+ (krb5_data *) anon_princ_data, 2, KRB5_NT_WELLKNOWN
+};
+
+const krb5_data * KRB5_CALLCONV
+krb5_anonymous_realm()
+{
+ return &anon_realm_data;
+}
+krb5_const_principal KRB5_CALLCONV
+krb5_anonymous_principal()
+{
+ return &anon_princ;
+}
diff --git a/src/lib/krb5/krb/chk_trans.c b/src/lib/krb5/krb/chk_trans.c
index 3c014817c..def50885c 100644
--- a/src/lib/krb5/krb/chk_trans.c
+++ b/src/lib/krb5/krb/chk_trans.c
@@ -315,6 +315,7 @@ krb5_check_transited_list (krb5_context ctx, const krb5_data *trans_in,
krb5_data trans;
struct check_data cdata;
krb5_error_code r;
+ const krb5_data *anonymous;
trans.length = trans_in->length;
trans.data = (char *) trans_in->data;
@@ -327,6 +328,11 @@ krb5_check_transited_list (krb5_context ctx, const krb5_data *trans_in,
(int) srealm->length, srealm->data));
if (trans.length == 0)
return 0;
+ anonymous = krb5_anonymous_realm();
+ if (crealm->length == anonymous->length
+ && (memcmp(crealm->data, anonymous->data, anonymous->length) == 0))
+ return 0; /*Nothing to check for anonymous*/
+
r = krb5_walk_realm_tree (ctx, crealm, srealm, &cdata.tgs,
KRB5_REALM_BRANCH_CHAR);
if (r) {
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index 06b3c3874..315bdc943 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -283,6 +283,71 @@ cleanup:
return (retval);
}
+/**
+ * Fully anonymous replies include a pa_pkinit_kx padata type including the KDC
+ * contribution key. This routine confirms that the session key is of the
+ * right form for fully anonymous requests. It is here rather than in the
+ * preauth code because the session key cannot be verified until the AS reply
+ * is decrypted and the preauth code all runs before the AS reply is decrypted.
+ */
+static krb5_error_code
+verify_anonymous( krb5_context context, krb5_kdc_req *request,
+ krb5_kdc_rep *reply, krb5_keyblock *as_key)
+{
+ krb5_error_code ret = 0;
+ krb5_pa_data *pa;
+ krb5_data scratch;
+ krb5_keyblock *kdc_key = NULL, *expected = NULL;
+ krb5_enc_data *enc = NULL;
+ krb5_keyblock *session = reply->enc_part2->session;
+ if (!krb5_principal_compare_any_realm(context, request->client,
+ krb5_anonymous_principal()))
+ return 0; /*Only applies to fully anonymous*/
+ pa = krb5int_find_pa_data(context, reply->padata, KRB5_PADATA_PKINIT_KX);
+ if (pa == NULL)
+ goto verification_error;
+ scratch.length = pa->length;
+ scratch.data = (char *) pa->contents;
+ ret = decode_krb5_enc_data( &scratch, &enc);
+ if (ret)
+ goto cleanup;
+ scratch.data = k5alloc(enc->ciphertext.length, &ret);
+ if (ret)
+ goto cleanup;
+ scratch.length = enc->ciphertext.length;
+ ret = krb5_c_decrypt(context, as_key, KRB5_KEYUSAGE_PA_PKINIT_KX,
+ NULL /*cipherstate*/, enc, &scratch);
+ if (ret) {
+ free( scratch.data);
+ goto cleanup;
+ }
+ ret = decode_krb5_encryption_key( &scratch, &kdc_key);
+ zap(scratch.data, scratch.length);
+ free(scratch.data);
+ if (ret)
+ goto cleanup;
+ ret = krb5_c_fx_cf2_simple( context, kdc_key, "PKINIT",
+ as_key, "KEYEXCHANGE", &expected);
+ if (ret)
+ goto cleanup;
+ if ((expected->enctype != session->enctype)
+ || (expected->length != session->length)
+ || (memcmp(expected->contents, session->contents, expected->length) != 0))
+ goto verification_error;
+cleanup:
+ if (kdc_key)
+ krb5_free_keyblock(context, kdc_key);
+ if (expected)
+ krb5_free_keyblock(context, expected);
+ if (enc)
+ krb5_free_enc_data(context, enc);
+ return ret;
+verification_error:
+ ret = KRB5_KDCREP_MODIFIED;
+ krb5_set_error_message(context, ret, "Reply has wrong form of session key for anonymous request");
+ goto cleanup;
+}
+
static krb5_error_code
verify_as_reply(krb5_context context,
krb5_timestamp time_now,
@@ -304,10 +369,14 @@ verify_as_reply(krb5_context context,
* principal) and we requested (and received) a TGT.
*/
canon_req = ((request->kdc_options & KDC_OPT_CANONICALIZE) != 0) ||
- (krb5_princ_type(context, request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL);
+ (krb5_princ_type(context, request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL)
+ || (request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS);
if (canon_req) {
canon_ok = IS_TGS_PRINC(context, request->server) &&
IS_TGS_PRINC(context, as_reply->enc_part2->server);
+ if ((!canon_ok ) && (request->kdc_options &KDC_OPT_REQUEST_ANONYMOUS))
+ canon_ok = krb5_principal_compare_any_realm(context, as_reply->client,
+ krb5_anonymous_principal());
} else
canon_ok = 0;
@@ -1394,6 +1463,32 @@ krb5_init_creds_init(krb5_context context,
ctx->salt.data = NULL;
}
+ /*Anonymous*/
+ if(opte->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) {
+ ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
+ /*Remap @REALM to WELLKNOWN/ANONYMOUS@REALM*/
+ if (client->length == 1 && client->data[0].length ==0) {
+ krb5_principal new_client;
+ code = krb5_build_principal_ext(context, &new_client, client->realm.length,
+ client->realm.data,
+ strlen(KRB5_WELLKNOWN_NAMESTR),
+ KRB5_WELLKNOWN_NAMESTR,
+ strlen(KRB5_ANONYMOUS_PRINCSTR),
+ KRB5_ANONYMOUS_PRINCSTR,
+ 0);
+ if (code)
+ goto cleanup;
+ krb5_free_principal(context, ctx->request->client);
+ ctx->request->client = new_client;
+ krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
+ }
+ }
+ /*We will also handle anonymous if the input principal is the anonymous principal*/
+ if (krb5_principal_compare_any_realm(context, ctx->request->client,
+ krb5_anonymous_principal())) {
+ ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS;
+ krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN;
+ }
code = restart_init_creds_loop(context, ctx, NULL);
*pctx = ctx;
@@ -1829,6 +1924,10 @@ init_creds_step_reply(krb5_context context,
ctx->request, ctx->reply);
if (code != 0)
goto cleanup;
+ code = verify_anonymous( context, ctx->request, ctx->reply,
+ &encrypting_key);
+ if (code)
+ goto cleanup;
code = stash_as_reply(context, ctx->request_time, ctx->request,
ctx->reply, &ctx->cred, NULL);
diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c
index d326ac570..c94ee3487 100644
--- a/src/lib/krb5/krb/gic_opt.c
+++ b/src/lib/krb5/krb/gic_opt.c
@@ -53,6 +53,15 @@ krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opt, int canon
}
void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_anonymous (krb5_get_init_creds_opt *opt,
+ int anonymous)
+{
+ if (anonymous)
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
+ else opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
+}
+
+void KRB5_CALLCONV
krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt, krb5_enctype *etype_list, int etype_list_length)
{
opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST;
@@ -149,8 +158,6 @@ krb5int_gic_opte_private_free(krb5_context context, krb5_gic_opt_ext *opte)
free_gic_opt_ext_preauth_data(context, opte);
if (opte->opt_private->fast_ccache_name)
free(opte->opt_private->fast_ccache_name);
- if (opte->opt_private->out_ccache)
- krb5_cc_close(context, opte->opt_private->out_ccache);
free(opte->opt_private);
opte->opt_private = NULL;
return 0;
@@ -504,13 +511,8 @@ krb5_get_init_creds_opt_set_out_ccache(krb5_context context,
"krb5_get_init_creds_opt_set_out_ccache");
if (retval)
return retval;
- if (opte->opt_private->out_ccache) {
- krb5_cc_close(context, opte->opt_private->out_ccache);
- opte->opt_private->out_ccache = NULL;
- }
- retval = krb5_cc_resolve(context, krb5_cc_get_name(context, ccache),
- &opte->opt_private->out_ccache);
- return retval;
+ opte->opt_private->out_ccache = ccache;
+ return 0;
}
krb5_error_code KRB5_CALLCONV
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 1c35c4592..e7c191b63 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -109,6 +109,8 @@ krb5_address_compare
krb5_address_order
krb5_address_search
krb5_aname_to_localname
+krb5_anonymous_principal
+krb5_anonymous_realm
krb5_appdefault_boolean
krb5_appdefault_string
krb5_auth_con_free
@@ -337,6 +339,7 @@ krb5_get_init_creds_opt_get_fast_flags
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_anonymous
krb5_get_init_creds_opt_set_canonicalize
krb5_get_init_creds_opt_set_change_password_prompt
krb5_get_init_creds_opt_set_etype_list