*out_creds = ncreds;
return 0;
}
-
-#define INT_GC_VALIDATE 1
-#define INT_GC_RENEW 2
-
-static krb5_error_code
-get_credentials_val_renew_core(krb5_context context, krb5_flags options,
- krb5_ccache ccache, krb5_creds *in_creds,
- krb5_creds **out_creds, int which)
-{
- krb5_error_code retval;
- krb5_principal tmp;
- krb5_creds **tgts = 0;
-
- switch(which) {
- case INT_GC_VALIDATE:
- retval = krb5_get_cred_from_kdc_validate(context, ccache,
- in_creds, out_creds, &tgts);
- break;
- case INT_GC_RENEW:
- retval = krb5_get_cred_from_kdc_renew(context, ccache,
- in_creds, out_creds, &tgts);
- break;
- default:
- /* Should never happen */
- retval = 255;
- break;
- }
- /*
- * Callers to krb5_get_cred_blah... must free up tgts even in
- * error cases.
- */
- if (tgts) krb5_free_tgt_creds(context, tgts);
- if (retval) return retval;
-
- retval = krb5_cc_get_principal(context, ccache, &tmp);
- if (retval) return retval;
-
- retval = krb5_cc_initialize(context, ccache, tmp);
- if (retval) return retval;
-
- retval = krb5_cc_store_cred(context, ccache, *out_creds);
- return retval;
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_get_credentials_validate(krb5_context context, krb5_flags options,
- krb5_ccache ccache, krb5_creds *in_creds,
- krb5_creds **out_creds)
-{
- return(get_credentials_val_renew_core(context, options, ccache,
- in_creds, out_creds,
- INT_GC_VALIDATE));
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_get_credentials_renew(krb5_context context, krb5_flags options,
- krb5_ccache ccache, krb5_creds *in_creds,
- krb5_creds **out_creds)
-{
-
- return(get_credentials_val_renew_core(context, options, ccache,
- in_creds, out_creds,
- INT_GC_RENEW));
-}
-
-static krb5_error_code
-validate_or_renew_creds(krb5_context context, krb5_creds *creds,
- krb5_principal client, krb5_ccache ccache,
- char *in_tkt_service, int validate)
-{
- krb5_error_code ret;
- krb5_creds in_creds; /* only client and server need to be filled in */
- krb5_creds *out_creds = 0; /* for check before dereferencing below */
- krb5_creds **tgts;
-
- memset(&in_creds, 0, sizeof(krb5_creds));
-
- in_creds.server = NULL;
- tgts = NULL;
-
- in_creds.client = client;
-
- if (in_tkt_service) {
- /* this is ugly, because so are the data structures involved. I'm
- in the library, so I'm going to manipulate the data structures
- directly, otherwise, it will be worse. */
-
- if ((ret = krb5_parse_name(context, in_tkt_service, &in_creds.server)))
- goto cleanup;
-
- /* stuff the client realm into the server principal.
- realloc if necessary */
- if (in_creds.server->realm.length < in_creds.client->realm.length)
- if ((in_creds.server->realm.data =
- (char *) realloc(in_creds.server->realm.data,
- in_creds.client->realm.length)) == NULL) {
- ret = ENOMEM;
- goto cleanup;
- }
-
- in_creds.server->realm.length = in_creds.client->realm.length;
- memcpy(in_creds.server->realm.data, in_creds.client->realm.data,
- in_creds.client->realm.length);
- } else {
- if ((ret = krb5_build_principal_ext(context, &in_creds.server,
- in_creds.client->realm.length,
- in_creds.client->realm.data,
- KRB5_TGS_NAME_SIZE,
- KRB5_TGS_NAME,
- in_creds.client->realm.length,
- in_creds.client->realm.data,
- 0)))
- goto cleanup;
- }
-
- if (validate)
- ret = krb5_get_cred_from_kdc_validate(context, ccache,
- &in_creds, &out_creds, &tgts);
- else
- ret = krb5_get_cred_from_kdc_renew(context, ccache,
- &in_creds, &out_creds, &tgts);
-
- /* ick. copy the struct contents, free the container */
- if (out_creds) {
- *creds = *out_creds;
- free(out_creds);
- }
-
-cleanup:
-
- if (in_creds.server)
- krb5_free_principal(context, in_creds.server);
- if (tgts)
- krb5_free_tgt_creds(context, tgts);
-
- return(ret);
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_get_validated_creds(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_ccache ccache, char *in_tkt_service)
-{
- return(validate_or_renew_creds(context, creds, client, ccache,
- in_tkt_service, 1));
-}
-
-krb5_error_code KRB5_CALLCONV
-krb5_get_renewed_creds(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_ccache ccache, char *in_tkt_service)
-{
- return(validate_or_renew_creds(context, creds, client, ccache,
- in_tkt_service, 0));
-}
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * lib/krb5/krb/val_renew.c
+ *
+ * Copyright (C) 2010 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.
+ *
+ *
+ * Implements the following APIs:
+ *
+ * krb5_get_credentials_validate
+ * krb5_get_credentials_renew
+ * krb5_get_validated_creds
+ * krb5_get_renewed_creds
+ *
+ * The first two are old but not formally deprecated; the latter two are newer.
+ */
+
+#include "k5-int.h"
+#include "int-proto.h"
+
+/*
+ * Get a validated or renewed credential matching in_creds, by retrieving a
+ * matching credential from ccache and renewing or validating it with the
+ * credential's realm's KDC. kdcopt specifies whether to validate or renew.
+ * The result is placed in *out_creds.
+ */
+static krb5_error_code
+get_new_creds(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds,
+ krb5_flags kdcopt, krb5_creds **out_creds)
+{
+ krb5_error_code code;
+ krb5_creds old_creds, *new_creds = NULL;
+
+ *out_creds = NULL;
+
+ /* Retrieve an existing cached credential matching in_creds. */
+ code = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_SUPPORTED_KTYPES,
+ in_creds, &old_creds);
+ if (code != 0)
+ return code;
+
+ /* Use it to get a new credential from the KDC. */
+ code = krb5_get_cred_via_tkt(context, &old_creds, kdcopt,
+ old_creds.addresses, in_creds, &new_creds);
+ krb5_free_cred_contents(context, &old_creds);
+ if (code != 0)
+ return code;
+
+ *out_creds = new_creds;
+ return code;
+}
+
+/*
+ * Core of the older pair of APIs: get a validated or renewed credential
+ * matching in_creds and reinitialize ccache so that it contains only the new
+ * credential.
+ */
+static krb5_error_code
+gc_valrenew(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds,
+ krb5_flags kdcopt, krb5_creds **out_creds)
+{
+ krb5_error_code code;
+ krb5_creds *new_creds = NULL;
+ krb5_principal default_princ = NULL;
+
+ /* Get the validated or renewed credential. */
+ code = get_new_creds(context, ccache, in_creds, kdcopt, &new_creds);
+ if (code != 0)
+ goto cleanup;
+
+ /* Reinitialize the cache without changing its default principal. */
+ code = krb5_cc_get_principal(context, ccache, &default_princ);
+ if (code != 0)
+ goto cleanup;
+ code = krb5_cc_initialize(context, ccache, default_princ);
+ if (code != 0)
+ goto cleanup;
+
+ /* Store the validated or renewed cred in the now-empty cache. */
+ code = krb5_cc_store_cred(context, ccache, new_creds);
+ if (code != 0)
+ goto cleanup;
+
+ *out_creds = new_creds;
+ new_creds = NULL;
+
+cleanup:
+ krb5_free_principal(context, default_princ);
+ krb5_free_creds(context, new_creds);
+ return code;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_validate(krb5_context context, krb5_flags options,
+ krb5_ccache ccache, krb5_creds *in_creds,
+ krb5_creds **out_creds)
+{
+ return gc_valrenew(context, ccache, in_creds, KDC_OPT_VALIDATE, out_creds);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_renew(krb5_context context, krb5_flags options,
+ krb5_ccache ccache, krb5_creds *in_creds,
+ krb5_creds **out_creds)
+{
+ return gc_valrenew(context, ccache, in_creds, KDC_OPT_RENEW, out_creds);
+}
+
+/*
+ * Core of the newer pair of APIs: get new credentials for in_tkt_service
+ * (defaults to the TGT of the client's realm) and store them into *out_creds.
+ */
+static krb5_error_code
+get_valrenewed_creds(krb5_context context, krb5_creds *out_creds,
+ krb5_principal client, krb5_ccache ccache,
+ char *in_tkt_service, int kdcopt)
+{
+ krb5_error_code code;
+ krb5_creds in_creds, *new_creds;
+ krb5_principal server = NULL;
+
+ if (in_tkt_service != NULL) {
+ /* Parse in_tkt_service, but use the client's realm. */
+ code = krb5_parse_name(context, in_tkt_service, &server);
+ if (code != 0)
+ goto cleanup;
+ krb5_free_data_contents(context, &server->realm);
+ code = krb5int_copy_data_contents(context, &client->realm,
+ &server->realm);
+ if (code != 0)
+ goto cleanup;
+ } else {
+ /* Use the TGT name for the client's realm. */
+ code = krb5int_tgtname(context, &client->realm, &client->realm,
+ &server);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ memset(&in_creds, 0, sizeof(krb5_creds));
+ in_creds.client = client;
+ in_creds.server = server;
+
+ /* Get the validated or renewed credential from the KDC. */
+ code = get_new_creds(context, ccache, &in_creds, kdcopt, &new_creds);
+ if (code != 0)
+ goto cleanup;
+
+ /* Fill in *out_creds and free the unwanted new_creds container. */
+ *out_creds = *new_creds;
+ free(new_creds);
+
+cleanup:
+ krb5_free_principal(context, server);
+ return code;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_validated_creds(krb5_context context, krb5_creds *creds,
+ krb5_principal client, krb5_ccache ccache,
+ char *in_tkt_service)
+{
+ return get_valrenewed_creds(context, creds, client, ccache,
+ in_tkt_service, KDC_OPT_VALIDATE);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_renewed_creds(krb5_context context, krb5_creds *creds,
+ krb5_principal client, krb5_ccache ccache,
+ char *in_tkt_service)
+{
+ return get_valrenewed_creds(context, creds, client, ccache,
+ in_tkt_service, KDC_OPT_RENEW);
+}