diff --git a/SOURCES/Add-recursion-limit-for-ASN.1-indefinite-lengths.patch b/SOURCES/Add-recursion-limit-for-ASN.1-indefinite-lengths.patch
index 0c4a4d0..41cf09c 100644
--- a/SOURCES/Add-recursion-limit-for-ASN.1-indefinite-lengths.patch
+++ b/SOURCES/Add-recursion-limit-for-ASN.1-indefinite-lengths.patch
@@ -1,4 +1,4 @@
-From 3a5576fab22ecd21bbf72cccec5be2096e0e05c4 Mon Sep 17 00:00:00 2001
+From 3c47e4adbed5e0a2e7f3993a24097889216a9d50 Mon Sep 17 00:00:00 2001
 From: Greg Hudson <ghudson@mit.edu>
 Date: Sat, 31 Oct 2020 17:07:05 -0400
 Subject: [PATCH] Add recursion limit for ASN.1 indefinite lengths
diff --git a/SOURCES/Add-support-for-start_realm-cache-config.patch b/SOURCES/Add-support-for-start_realm-cache-config.patch
new file mode 100644
index 0000000..b83092c
--- /dev/null
+++ b/SOURCES/Add-support-for-start_realm-cache-config.patch
@@ -0,0 +1,303 @@
+From bb5552ece2a351dc3ccab52cceea1eaffeacd768 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 14 Dec 2020 13:16:17 -0500
+Subject: [PATCH] Add support for start_realm cache config
+
+When making TGS requests, if start_realm is set in the cache, use the
+named realm to look up the initial TGT for referral or cross-realm
+requests.  (Also correct a comment in struct _tkt_creds_context: the
+ccache field is an owner pointer, not an alias.)
+
+Add an internal API k5_cc_store_primary_cred(), which sets start_realm
+if the cred being stored is a TGT for a realm other than the client
+realm.  Use this API when acquiring initial tickets with a
+caller-specified output ccache, when renewing or validating tickets
+with kinit, when accepting a delegated credential in a GSS context,
+and when storing a single cred with kvno --out-cache.
+
+ticket: 8332
+tags: pullup
+target_version: 1.19
+
+(cherry picked from commit 0d56740ab9fcc40dc7f46c6fbebdf8f1214f9d96)
+[rharwood@redhat.com: backport around spelling and canonicalization fallback]
+---
+ doc/formats/ccache_file_format.rst       |  6 +++++
+ src/clients/kinit/kinit.c                |  2 +-
+ src/clients/kvno/kvno.c                  |  5 ++++-
+ src/include/k5-int.h                     |  4 ++++
+ src/lib/gssapi/krb5/accept_sec_context.c |  2 +-
+ src/lib/krb5/ccache/ccfns.c              | 20 +++++++++++++++++
+ src/lib/krb5/krb/get_creds.c             | 28 ++++++++++++++++++------
+ src/lib/krb5/krb/get_in_tkt.c            |  2 +-
+ src/lib/krb5/libkrb5.exports             |  1 +
+ src/lib/krb5_32.def                      |  3 +++
+ src/tests/t_crossrealm.py                |  8 +++++++
+ src/tests/t_pkinit.py                    |  3 +++
+ 12 files changed, 73 insertions(+), 11 deletions(-)
+
+diff --git a/doc/formats/ccache_file_format.rst b/doc/formats/ccache_file_format.rst
+index 6349e0d29..6138c1b58 100644
+--- a/doc/formats/ccache_file_format.rst
++++ b/doc/formats/ccache_file_format.rst
+@@ -174,3 +174,9 @@ refresh_time
+     decimal representation of a timestamp at which the GSS mechanism
+     should attempt to refresh the credential cache from the client
+     keytab.
++
++start_realm
++    This key indicates the realm of the ticket-granting ticket to be
++    used for TGS requests, when making a referrals request or
++    beginning a cross-realm request.  If it is not present, the client
++    realm is used.
+diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
+index 3fdae2878..e5ebeb895 100644
+--- a/src/clients/kinit/kinit.c
++++ b/src/clients/kinit/kinit.c
+@@ -828,7 +828,7 @@ k5_kinit(struct k_opts *opts, struct k5_data *k5)
+         if (opts->verbose)
+             fprintf(stderr, _("Initialized cache\n"));
+ 
+-        ret = krb5_cc_store_cred(k5->ctx, k5->out_cc, &my_creds);
++        ret = k5_cc_store_primary_cred(k5->ctx, k5->out_cc, &my_creds);
+         if (ret) {
+             com_err(progname, ret, _("while storing credentials"));
+             goto cleanup;
+diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
+index c5f6bf700..f83c68a99 100644
+--- a/src/clients/kvno/kvno.c
++++ b/src/clients/kvno/kvno.c
+@@ -561,7 +561,10 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
+                 }
+                 initialized = 1;
+             }
+-            ret = krb5_cc_store_cred(context, out_ccache, creds);
++            if (count == 1)
++                ret = k5_cc_store_primary_cred(context, out_ccache, creds);
++            else
++                ret = krb5_cc_store_cred(context, out_ccache, creds);
+             if (ret) {
+                 com_err(prog, ret, _("while storing creds in output ccache"));
+                 exit(1);
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index eb18a4cd6..912aaedac 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -307,6 +307,7 @@ typedef unsigned char   u_char;
+ #define KRB5_CC_CONF_PA_TYPE                   "pa_type"
+ #define KRB5_CC_CONF_PROXY_IMPERSONATOR        "proxy_impersonator"
+ #define KRB5_CC_CONF_REFRESH_TIME              "refresh_time"
++#define KRB5_CC_CONF_START_REALM               "start_realm"
+ 
+ /* Error codes used in KRB_ERROR protocol messages.
+    Return values of library routines are based on a different error table
+@@ -1910,6 +1911,9 @@ krb5_ser_unpack_bytes(krb5_octet *, size_t, krb5_octet **, size_t *);
+ krb5_error_code KRB5_CALLCONV
+ krb5int_cc_default(krb5_context, krb5_ccache *);
+ 
++krb5_error_code
++k5_cc_store_primary_cred(krb5_context, krb5_ccache, krb5_creds *);
++
+ /* Fill in the buffer with random alpha-numeric data. */
+ krb5_error_code
+ krb5int_random_string(krb5_context, char *string, unsigned int length);
+diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
+index 3d5b84b15..abccb5d11 100644
+--- a/src/lib/gssapi/krb5/accept_sec_context.c
++++ b/src/lib/gssapi/krb5/accept_sec_context.c
+@@ -216,7 +216,7 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
+     if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
+         goto cleanup;
+ 
+-    if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
++    if ((retval = k5_cc_store_primary_cred(context, ccache, creds[0])))
+         goto cleanup;
+ 
+     /* generate a delegated credential handle */
+diff --git a/src/lib/krb5/ccache/ccfns.c b/src/lib/krb5/ccache/ccfns.c
+index 62a6983d8..23edc2578 100644
+--- a/src/lib/krb5/ccache/ccfns.c
++++ b/src/lib/krb5/ccache/ccfns.c
+@@ -297,3 +297,23 @@ krb5_cc_switch(krb5_context context, krb5_ccache cache)
+         return 0;
+     return cache->ops->switch_to(context, cache);
+ }
++
++krb5_error_code
++k5_cc_store_primary_cred(krb5_context context, krb5_ccache cache,
++                         krb5_creds *creds)
++{
++    krb5_error_code ret;
++
++    /* Write a start realm if we're writing a TGT and the client realm isn't
++     * the same as the TGS realm. */
++    if (IS_TGS_PRINC(creds->server) &&
++        !data_eq(creds->client->realm, creds->server->data[1])) {
++        ret = krb5_cc_set_config(context, cache, NULL,
++                                 KRB5_CC_CONF_START_REALM,
++                                 &creds->server->data[1]);
++        if (ret)
++            return ret;
++    }
++
++    return krb5_cc_store_cred(context, cache, creds);
++}
+diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c
+index e0a3b5cd8..b40f705fc 100644
+--- a/src/lib/krb5/krb/get_creds.c
++++ b/src/lib/krb5/krb/get_creds.c
+@@ -149,7 +149,8 @@ struct _krb5_tkt_creds_context {
+     krb5_principal client;      /* Caller-requested client principal (alias) */
+     krb5_principal server;      /* Server principal (alias) */
+     krb5_principal req_server;  /* Caller-requested server principal */
+-    krb5_ccache ccache;         /* Caller-provided ccache (alias) */
++    krb5_ccache ccache;         /* Caller-provided ccache */
++    krb5_data start_realm;      /* Realm of starting TGT in ccache */
+     krb5_flags req_options;     /* Caller-requested KRB5_GC_* options */
+     krb5_flags req_kdcopt;      /* Caller-requested options as KDC options */
+     krb5_authdata **authdata;   /* Caller-requested authdata */
+@@ -783,7 +784,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx,
+         return code;
+ 
+     /* Construct the principal name. */
+-    code = krb5int_tgtname(context, &ctx->client->realm, &ctx->client->realm,
++    code = krb5int_tgtname(context, &ctx->start_realm, &ctx->start_realm,
+                            &tgtname);
+     if (code != 0)
+         return code;
+@@ -821,7 +822,7 @@ init_realm_path(krb5_context context, krb5_tkt_creds_context ctx)
+     size_t nrealms;
+ 
+     /* Get the client realm path and count its length. */
+-    code = k5_client_realm_path(context, &ctx->client->realm,
++    code = k5_client_realm_path(context, &ctx->start_realm,
+                                 &ctx->server->realm, &realm_path);
+     if (code != 0)
+         return code;
+@@ -933,7 +934,7 @@ step_get_tgt(krb5_context context, krb5_tkt_creds_context ctx)
+                 ctx->cur_realm = path_realm;
+                 ctx->next_realm = ctx->last_realm;
+             }
+-        } else if (data_eq(*tgt_realm, ctx->client->realm)) {
++        } else if (data_eq(*tgt_realm, ctx->start_realm)) {
+             /* We were referred back to the local realm, which is bad. */
+             return KRB5_KDCREP_MODIFIED;
+         } else {
+@@ -963,7 +964,7 @@ begin_get_tgt(krb5_context context, krb5_tkt_creds_context ctx)
+ 
+     ctx->state = STATE_GET_TGT;
+ 
+-    is_local_service = data_eq(ctx->client->realm, ctx->server->realm);
++    is_local_service = data_eq(ctx->start_realm, ctx->server->realm);
+     if (!is_local_service) {
+         /* See if we have a cached TGT for the server realm. */
+         code = get_cached_tgt(context, ctx, &ctx->server->realm, &cached_tgt);
+@@ -1048,10 +1049,10 @@ begin(krb5_context context, krb5_tkt_creds_context ctx)
+     if (code != 0 || ctx->state == STATE_COMPLETE)
+         return code;
+ 
+-    /* If the server realm is unspecified, start with the client realm. */
++    /* If the server realm is unspecified, start with the TGT realm. */
+     if (krb5_is_referral_realm(&ctx->server->realm)) {
+         krb5_free_data_contents(context, &ctx->server->realm);
+-        code = krb5int_copy_data_contents(context, &ctx->client->realm,
++        code = krb5int_copy_data_contents(context, &ctx->start_realm,
+                                           &ctx->server->realm);
+         TRACE_TKT_CREDS_REFERRAL_REALM(context, ctx->server);
+         if (code != 0)
+@@ -1100,6 +1101,18 @@ krb5_tkt_creds_init(krb5_context context, krb5_ccache ccache,
+     code = krb5_cc_dup(context, ccache, &ctx->ccache);
+     if (code != 0)
+         goto cleanup;
++
++    /* Get the start realm from the cache config, defaulting to the client
++     * realm. */
++    code = krb5_cc_get_config(context, ccache, NULL, "start_realm",
++                              &ctx->start_realm);
++    if (code != 0) {
++        code = krb5int_copy_data_contents(context, &ctx->client->realm,
++                                          &ctx->start_realm);
++        if (code != 0)
++            goto cleanup;
++    }
++
+     code = krb5_copy_authdata(context, in_creds->authdata, &ctx->authdata);
+     if (code != 0)
+         goto cleanup;
+@@ -1139,6 +1152,7 @@ krb5_tkt_creds_free(krb5_context context, krb5_tkt_creds_context ctx)
+     krb5int_fast_free_state(context, ctx->fast_state);
+     krb5_free_creds(context, ctx->in_creds);
+     krb5_cc_close(context, ctx->ccache);
++    krb5_free_data_contents(context, &ctx->start_realm);
+     krb5_free_principal(context, ctx->req_server);
+     krb5_free_authdata(context, ctx->authdata);
+     krb5_free_creds(context, ctx->cur_tgt);
+diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
+index cc0f70e83..f5dd7518b 100644
+--- a/src/lib/krb5/krb/get_in_tkt.c
++++ b/src/lib/krb5/krb/get_in_tkt.c
+@@ -1779,7 +1779,7 @@ init_creds_step_reply(krb5_context context,
+         code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
+         if (code != 0)
+             goto cc_cleanup;
+-        code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
++        code = k5_cc_store_primary_cred(context, out_ccache, &ctx->cred);
+         if (code != 0)
+             goto cc_cleanup;
+         if (fast_avail) {
+diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
+index 5aba29ee4..cab5b3b17 100644
+--- a/src/lib/krb5/libkrb5.exports
++++ b/src/lib/krb5/libkrb5.exports
+@@ -125,6 +125,7 @@ k5_add_pa_data_from_data
+ k5_alloc_pa_data
+ k5_authind_decode
+ k5_build_conf_principals
++k5_cc_store_primary_cred
+ k5_ccselect_free_context
+ k5_change_error_message_code
+ k5_etypes_contains
+diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
+index a0734c729..de5823c17 100644
+--- a/src/lib/krb5_32.def
++++ b/src/lib/krb5_32.def
+@@ -499,3 +499,6 @@ EXPORTS
+ 	k5_size_context					@467 ; PRIVATE GSSAPI
+ 	k5_size_keyblock				@468 ; PRIVATE GSSAPI
+ 	k5_size_principal				@469 ; PRIVATE GSSAPI
++
++; new in 1.19
++	k5_cc_store_primary_cred			@470 ; PRIVATE
+diff --git a/src/tests/t_crossrealm.py b/src/tests/t_crossrealm.py
+index fa7fd2604..28b397cfb 100755
+--- a/src/tests/t_crossrealm.py
++++ b/src/tests/t_crossrealm.py
+@@ -77,6 +77,14 @@ r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),
+                                 {'realm': 'B.X'}))
+ test_kvno(r1, r3.host_princ, 'KDC domain walk')
+ check_klist(r1, (tgt(r1, r1), r3.host_princ))
++
++# Test start_realm in this setup.
++r1.run([kvno, '--out-cache', r1.ccache, r2.krbtgt_princ])
++r1.run([klist, '-C'], expected_msg='config: start_realm = X')
++msgs = ('Requesting TGT krbtgt/B.X@X using TGT krbtgt/X@X',
++        'Received TGT for service realm: krbtgt/B.X@X')
++r1.run([kvno, r3.host_princ], expected_trace=msgs)
++
+ stop(r1, r2, r3)
+ 
+ # Test client capaths.  The client in A will ask for a cross TGT to D,
+diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
+index ecd450e8a..f224383c8 100755
+--- a/src/tests/t_pkinit.py
++++ b/src/tests/t_pkinit.py
+@@ -130,6 +130,9 @@ realm.run([kvno, realm.host_princ])
+ out = realm.run(['./adata', realm.host_princ])
+ if '97:' in out:
+     fail('auth indicators seen in anonymous PKINIT ticket')
++# Verify start_realm setting and test referrals TGS request.
++realm.run([klist, '-C'], expected_msg='start_realm = KRBTEST.COM')
++realm.run([kvno, '-S', 'host', hostname])
+ 
+ # Test anonymous kadmin.
+ mark('anonymous kadmin')
diff --git a/SOURCES/Add-three-kvno-options-from-Heimdal-kgetcred.patch b/SOURCES/Add-three-kvno-options-from-Heimdal-kgetcred.patch
new file mode 100644
index 0000000..ee42732
--- /dev/null
+++ b/SOURCES/Add-three-kvno-options-from-Heimdal-kgetcred.patch
@@ -0,0 +1,403 @@
+From a1f38973435b60c7f147abfca12b95c6a0a64406 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Wed, 17 Jun 2020 20:48:38 -0400
+Subject: [PATCH] Add three kvno options from Heimdal kgetcred
+
+Add the flags --cached-only and --no-store, which pass the
+corresponding options to krb5_get_credentials().  Add the option
+--out-cache to write the retrieved credentials to a specified output
+cache.
+
+Add a Python test script for kvno command-line options, including
+tests for the new options.
+
+ticket: 8917 (new)
+---
+ doc/user/user_commands/kvno.rst |  13 ++++
+ src/clients/kvno/Makefile.in    |   3 +
+ src/clients/kvno/kvno.c         | 115 +++++++++++++++++++++++---------
+ src/clients/kvno/t_kvno.py      |  75 +++++++++++++++++++++
+ src/man/kvno.man                |  13 ++++
+ 5 files changed, 187 insertions(+), 32 deletions(-)
+ create mode 100644 src/clients/kvno/t_kvno.py
+
+diff --git a/doc/user/user_commands/kvno.rst b/doc/user/user_commands/kvno.rst
+index 3892f0ca5..718313576 100644
+--- a/doc/user/user_commands/kvno.rst
++++ b/doc/user/user_commands/kvno.rst
+@@ -74,6 +74,19 @@ OPTIONS
+     client principal with the X.509 certificate in *cert_file*.  The
+     certificate file must be in PEM format.
+ 
++**--cached-only**
++    Only retrieve credentials already present in the cache, not from
++    the KDC.
++
++**--no-store**
++    Do not store retrieved credentials in the cache.  If
++    **--out-cache** is also specified, credentials will still be
++    stored into the output credential cache.
++
++**--out-cache** *ccache*
++    Initialize *ccache* and store all retrieved credentials into it.
++    Do not store acquired credentials in the input cache.
++
+ **--u2u** *ccache*
+     Requests a user-to-user ticket.  *ccache* must contain a local
+     krbtgt ticket for the server principal.  The reported version
+diff --git a/src/clients/kvno/Makefile.in b/src/clients/kvno/Makefile.in
+index 1c3f79392..5ba877271 100644
+--- a/src/clients/kvno/Makefile.in
++++ b/src/clients/kvno/Makefile.in
+@@ -26,6 +26,9 @@ kvno: kvno.o $(KRB5_BASE_DEPLIBS)
+ ##WIN32##	link $(EXE_LINKOPTS) /out:$@ $**
+ ##WIN32##	$(_VC_MANIFEST_EMBED_EXE)
+ 
++check-pytests: kvno
++	$(RUNPYTEST) $(srcdir)/t_kvno.py $(PYTESTFLAGS)
++
+ clean-unix::
+ 	$(RM) kvno.o kvno
+ 
+diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
+index 2472c0cfe..9d85864f6 100644
+--- a/src/clients/kvno/kvno.c
++++ b/src/clients/kvno/kvno.c
+@@ -44,14 +44,17 @@ xusage()
+     fprintf(stderr, _("usage: %s [-C] [-u] [-c ccache] [-e etype]\n"), prog);
+     fprintf(stderr, _("\t[-k keytab] [-S sname] [{-I | -U} for_user | "
+                       "[-F cert_file] [-P]]\n"));
+-    fprintf(stderr, _("\t[--u2u ccache] service1 service2 ...\n"));
++    fprintf(stderr, _("\t[--cached-only] [--no-store] [--out-cache ccache] "
++                      "[--u2u ccache]\n"));
++    fprintf(stderr, _("\tservice1 service2 ...\n"));
+     exit(1);
+ }
+ 
+ static void do_v5_kvno(int argc, char *argv[], char *ccachestr, char *etypestr,
+-                       char *keytab_name, char *sname, int canon, int unknown,
+-                       char *for_user, int for_user_enterprise,
+-                       char *for_user_cert_file, int proxy,
++                       char *keytab_name, char *sname, int cached_only,
++                       int canon, int no_store, int unknown, char *for_user,
++                       int for_user_enterprise, char *for_user_cert_file,
++                       int proxy, const char *out_ccname,
+                        const char *u2u_ccname);
+ 
+ #include <com_err.h>
+@@ -61,18 +64,21 @@ static void extended_com_err_fn(const char *myprog, errcode_t code,
+ int
+ main(int argc, char *argv[])
+ {
+-    enum { OPTION_U2U = 256 };
+-    struct option lopts[] = {
+-        { "u2u", 1, NULL, OPTION_U2U },
+-        { NULL, 0, NULL, 0 }
+-    };
++    enum { OPTION_U2U = 256, OPTION_OUT_CACHE = 257 };
+     const char *shopts = "uCc:e:hk:qPS:I:U:F:";
+     int option;
+     char *etypestr = NULL, *ccachestr = NULL, *keytab_name = NULL;
+     char *sname = NULL, *for_user = NULL, *u2u_ccname = NULL;
+-    char *for_user_cert_file = NULL;
++    char *for_user_cert_file = NULL, *out_ccname = NULL;
+     int canon = 0, unknown = 0, proxy = 0, for_user_enterprise = 0;
+-    int impersonate = 0;
++    int impersonate = 0, cached_only = 0, no_store = 0;
++    struct option lopts[] = {
++        { "cached-only", 0, &cached_only, 1 },
++        { "no-store", 0, &no_store, 1 },
++        { "out-cache", 1, NULL, OPTION_OUT_CACHE },
++        { "u2u", 1, NULL, OPTION_U2U },
++        { NULL, 0, NULL, 0 }
++    };
+ 
+     setlocale(LC_ALL, "");
+     set_com_err_hook(extended_com_err_fn);
+@@ -135,6 +141,12 @@ main(int argc, char *argv[])
+         case OPTION_U2U:
+             u2u_ccname = optarg;
+             break;
++        case OPTION_OUT_CACHE:
++            out_ccname = optarg;
++            break;
++        case 0:
++            /* If this option set a flag, do nothing else now. */
++            break;
+         default:
+             xusage();
+             break;
+@@ -159,8 +171,9 @@ main(int argc, char *argv[])
+         xusage();
+ 
+     do_v5_kvno(argc - optind, argv + optind, ccachestr, etypestr, keytab_name,
+-               sname, canon, unknown, for_user, for_user_enterprise,
+-               for_user_cert_file, proxy, u2u_ccname);
++               sname, cached_only, canon, no_store, unknown, for_user,
++               for_user_enterprise, for_user_cert_file, proxy, out_ccname,
++               u2u_ccname);
+     return 0;
+ }
+ 
+@@ -274,14 +287,16 @@ static krb5_error_code
+ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
+      krb5_enctype etype, krb5_keytab keytab, const char *sname,
+      krb5_flags options, int unknown, krb5_principal for_user_princ,
+-     krb5_data *for_user_cert, int proxy, krb5_data *u2u_ticket)
++     krb5_data *for_user_cert, int proxy, krb5_data *u2u_ticket,
++     krb5_creds **creds_out)
+ {
+     krb5_error_code ret;
+     krb5_principal server = NULL;
+     krb5_ticket *ticket = NULL;
+-    krb5_creds in_creds, *out_creds = NULL;
++    krb5_creds in_creds, *creds = NULL;
+     char *princ = NULL;
+ 
++    *creds_out = NULL;
+     memset(&in_creds, 0, sizeof(in_creds));
+ 
+     if (sname != NULL) {
+@@ -321,13 +336,12 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
+         in_creds.client = for_user_princ;
+         in_creds.server = me;
+         ret = krb5_get_credentials_for_user(context, options, ccache,
+-                                            &in_creds, for_user_cert,
+-                                            &out_creds);
++                                            &in_creds, for_user_cert, &creds);
+     } else {
+         in_creds.client = me;
+         in_creds.server = server;
+         ret = krb5_get_credentials(context, options, ccache, &in_creds,
+-                                   &out_creds);
++                                   &creds);
+     }
+ 
+     if (ret) {
+@@ -336,7 +350,7 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
+     }
+ 
+     /* We need a native ticket. */
+-    ret = krb5_decode_ticket(&out_creds->ticket, &ticket);
++    ret = krb5_decode_ticket(&creds->ticket, &ticket);
+     if (ret) {
+         com_err(prog, ret, _("while decoding ticket for %s"), princ);
+         goto cleanup;
+@@ -362,15 +376,15 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
+     }
+ 
+     if (proxy) {
+-        in_creds.client = out_creds->client;
+-        out_creds->client = NULL;
+-        krb5_free_creds(context, out_creds);
+-        out_creds = NULL;
++        in_creds.client = creds->client;
++        creds->client = NULL;
++        krb5_free_creds(context, creds);
++        creds = NULL;
+         in_creds.server = server;
+ 
+         ret = krb5_get_credentials_for_proxy(context, KRB5_GC_CANONICALIZE,
+                                              ccache, &in_creds, ticket,
+-                                             &out_creds);
++                                             &creds);
+         krb5_free_principal(context, in_creds.client);
+         if (ret) {
+             com_err(prog, ret, _("%s: constrained delegation failed"),
+@@ -379,10 +393,13 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
+         }
+     }
+ 
++    *creds_out = creds;
++    creds = NULL;
++
+ cleanup:
+     krb5_free_principal(context, server);
+     krb5_free_ticket(context, ticket);
+-    krb5_free_creds(context, out_creds);
++    krb5_free_creds(context, creds);
+     krb5_free_unparsed_name(context, princ);
+     return ret;
+ }
+@@ -428,19 +445,28 @@ cleanup:
+ 
+ static void
+ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
+-           char *keytab_name, char *sname, int canon, int unknown,
+-           char *for_user, int for_user_enterprise,
+-           char *for_user_cert_file, int proxy, const char *u2u_ccname)
++           char *keytab_name, char *sname, int cached_only, int canon,
++           int no_store, int unknown, char *for_user, int for_user_enterprise,
++           char *for_user_cert_file, int proxy, const char *out_ccname,
++           const char *u2u_ccname)
+ {
+     krb5_error_code ret;
+-    int i, errors, flags;
++    int i, errors, flags, initialized = 0;
+     krb5_enctype etype;
+-    krb5_ccache ccache;
++    krb5_ccache ccache, out_ccache = NULL;
+     krb5_principal me;
+     krb5_keytab keytab = NULL;
+     krb5_principal for_user_princ = NULL;
+-    krb5_flags options = canon ? KRB5_GC_CANONICALIZE : 0;
++    krb5_flags options = 0;
+     krb5_data cert_data = empty_data(), *user_cert = NULL, *u2u_ticket = NULL;
++    krb5_creds *creds;
++
++    if (canon)
++        options |= KRB5_GC_CANONICALIZE;
++    if (cached_only)
++        options |= KRB5_GC_CACHED;
++    if (no_store || out_ccname != NULL)
++        options |= KRB5_GC_NO_STORE;
+ 
+     ret = krb5_init_context(&context);
+     if (ret) {
+@@ -467,6 +493,14 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
+         exit(1);
+     }
+ 
++    if (out_ccname != NULL) {
++        ret = krb5_cc_resolve(context, out_ccname, &out_ccache);
++        if (ret) {
++            com_err(prog, ret, _("while resolving output ccache"));
++            exit(1);
++        }
++    }
++
+     if (keytab_name != NULL) {
+         ret = krb5_kt_resolve(context, keytab_name, &keytab);
+         if (ret) {
+@@ -513,8 +547,25 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
+     errors = 0;
+     for (i = 0; i < count; i++) {
+         if (kvno(names[i], ccache, me, etype, keytab, sname, options, unknown,
+-                 for_user_princ, user_cert, proxy, u2u_ticket) != 0)
++                 for_user_princ, user_cert, proxy, u2u_ticket, &creds) != 0) {
+             errors++;
++        } else if (out_ccache != NULL) {
++            if (!initialized) {
++                ret = krb5_cc_initialize(context, out_ccache, creds->client);
++                if (ret) {
++                    com_err(prog, ret, _("while initializing output ccache"));
++                    exit(1);
++                }
++                initialized = 1;
++            }
++            ret = krb5_cc_store_cred(context, out_ccache, creds);
++            if (ret) {
++                com_err(prog, ret, _("while storing creds in output ccache"));
++                exit(1);
++            }
++        }
++
++        krb5_free_creds(context, creds);
+     }
+ 
+     if (keytab != NULL)
+diff --git a/src/clients/kvno/t_kvno.py b/src/clients/kvno/t_kvno.py
+new file mode 100644
+index 000000000..e98b90e8a
+--- /dev/null
++++ b/src/clients/kvno/t_kvno.py
+@@ -0,0 +1,75 @@
++from k5test import *
++
++realm = K5Realm()
++
++def check_cache(ccache, expected_services):
++    # Fetch the klist output and skip past the header.
++    lines = realm.run([klist, '-c', ccache]).splitlines()
++    lines = lines[4:]
++
++    # For each line not beginning with an indent, match against the
++    # expected service principals.
++    svcs = {x: True for x in expected_services}
++    for l in lines:
++        if not l.startswith('\t'):
++            svcprinc = l.split()[4]
++            if svcprinc in svcs:
++                del svcs[svcprinc]
++            else:
++                fail('unexpected service princ ' + svcprinc)
++
++    if svcs:
++        fail('services not found in klist output: ' + ' '.join(svcs.keys()))
++
++
++mark('no options')
++realm.run([kvno, realm.user_princ], expected_msg='user@KRBTEST.COM: kvno = 1')
++check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
++
++mark('-e')
++msgs = ('etypes requested in TGS request: camellia128-cts',
++        '/KDC has no support for encryption type')
++realm.run([kvno, '-e', 'camellia128-cts', realm.host_princ],
++          expected_code=1, expected_trace=msgs)
++
++mark('--cached-only')
++realm.run([kvno, '--cached-only', realm.user_princ], expected_msg='kvno = 1')
++realm.run([kvno, '--cached-only', realm.host_princ],
++          expected_code=1, expected_msg='Matching credential not found')
++check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
++
++mark('--no-store')
++realm.run([kvno, '--no-store', realm.host_princ], expected_msg='kvno = 1')
++check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
++
++mark('--out-cache') # and multiple services
++out_ccache = os.path.join(realm.testdir, 'ccache.out')
++realm.run([kvno, '--out-cache', out_ccache,
++           realm.host_princ, realm.admin_princ])
++check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
++check_cache(out_ccache, [realm.host_princ, realm.admin_princ])
++
++mark('--out-cache --cached-only') # tests out-cache overwriting, and -q
++realm.run([kvno, '--out-cache', out_ccache, '--cached-only', realm.host_princ],
++          expected_code=1, expected_msg='Matching credential not found')
++out = realm.run([kvno, '-q', '--out-cache', out_ccache, '--cached-only',
++                 realm.user_princ])
++if out:
++    fail('unexpected kvno output with -q')
++check_cache(out_ccache, [realm.user_princ])
++
++mark('-U') # and -c
++svc_ccache = os.path.join(realm.testdir, 'ccache.svc')
++realm.run([kinit, '-k', '-c', svc_ccache, realm.host_princ])
++realm.run([kvno, '-c', svc_ccache, '-U', 'user', realm.host_princ])
++realm.run([klist, '-c', svc_ccache], expected_msg='for client user@')
++realm.run([kvno, '-c', svc_ccache, '-U', 'user', '--out-cache', out_ccache,
++           realm.host_princ])
++out = realm.run([klist, '-c', out_ccache])
++if ('Default principal: user@KRBTEST.COM' not in out):
++    fail('wrong default principal in klist output')
++
++# More S4U options are tested in tests/gssapi/t_s4u.py.
++# --u2u is tested in tests/t_u2u.py.
++
++success('kvno tests')
+diff --git a/src/man/kvno.man b/src/man/kvno.man
+index 005a2ec97..b9f6739eb 100644
+--- a/src/man/kvno.man
++++ b/src/man/kvno.man
+@@ -95,6 +95,19 @@ Specifies that protocol transition is to be used, identifying the
+ client principal with the X.509 certificate in \fIcert_file\fP\&.  The
+ certificate file must be in PEM format.
+ .TP
++\fB\-\-cached\-only\fP
++Only retrieve credentials already present in the cache, not from
++the KDC.
++.TP
++\fB\-\-no\-store\fP
++Do not store retrieved credentials in the cache.  If
++\fB\-\-out\-cache\fP is also specified, credentials will still be
++stored into the output credential cache.
++.TP
++\fB\-\-out\-cache\fP \fIccache\fP
++Initialize \fIccache\fP and store all retrieved credentials into it.
++Do not store acquired credentials in the input cache.
++.TP
+ \fB\-\-u2u\fP \fIccache\fP
+ Requests a user\-to\-user ticket.  \fIccache\fP must contain a local
+ krbtgt ticket for the server principal.  The reported version
diff --git a/SOURCES/Document-k-option-in-kvno-1-synopsis.patch b/SOURCES/Document-k-option-in-kvno-1-synopsis.patch
index 85fb523..d2c2b0c 100644
--- a/SOURCES/Document-k-option-in-kvno-1-synopsis.patch
+++ b/SOURCES/Document-k-option-in-kvno-1-synopsis.patch
@@ -1,4 +1,4 @@
-From e9200e874f33defec7193c11a093675b70e588b6 Mon Sep 17 00:00:00 2001
+From 5c1c391a80edd8ceb9e8bba9f7bdfb6639883ae6 Mon Sep 17 00:00:00 2001
 From: Robbie Harwood <rharwood@redhat.com>
 Date: Tue, 24 Nov 2020 12:52:02 -0500
 Subject: [PATCH] Document -k option in kvno(1) synopsis
@@ -14,7 +14,7 @@ synopsis, option descriptions, and xusage(), but missed one option.
  2 files changed, 2 insertions(+)
 
 diff --git a/doc/user/user_commands/kvno.rst b/doc/user/user_commands/kvno.rst
-index 53e569651..00689ab4c 100644
+index 65c44e1c0..93a5132b2 100644
 --- a/doc/user/user_commands/kvno.rst
 +++ b/doc/user/user_commands/kvno.rst
 @@ -9,6 +9,7 @@ SYNOPSIS
@@ -26,7 +26,7 @@ index 53e569651..00689ab4c 100644
  [**-u** | **-S** *sname*]
  [**-P**]
 diff --git a/src/man/kvno.man b/src/man/kvno.man
-index e156df723..3eeab41b2 100644
+index 22318324d..4e5b43b3b 100644
 --- a/src/man/kvno.man
 +++ b/src/man/kvno.man
 @@ -35,6 +35,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
diff --git a/SOURCES/Fix-leak-in-KERB_AP_OPTIONS_CBT-server-support.patch b/SOURCES/Fix-leak-in-KERB_AP_OPTIONS_CBT-server-support.patch
index a0785b9..ab45a2e 100644
--- a/SOURCES/Fix-leak-in-KERB_AP_OPTIONS_CBT-server-support.patch
+++ b/SOURCES/Fix-leak-in-KERB_AP_OPTIONS_CBT-server-support.patch
@@ -1,4 +1,4 @@
-From ce6defae3595fc3d9980bcf5ddc4f1a6ee90d391 Mon Sep 17 00:00:00 2001
+From 7a87189f7bdabc144e22d4caa6a0785a06416d8f Mon Sep 17 00:00:00 2001
 From: Greg Hudson <ghudson@mit.edu>
 Date: Fri, 24 Jul 2020 16:05:24 -0400
 Subject: [PATCH] Fix leak in KERB_AP_OPTIONS_CBT server support
diff --git a/SOURCES/Ignore-bad-enctypes-in-krb5_string_to_keysalts.patch b/SOURCES/Ignore-bad-enctypes-in-krb5_string_to_keysalts.patch
index da1503e..86f8e85 100644
--- a/SOURCES/Ignore-bad-enctypes-in-krb5_string_to_keysalts.patch
+++ b/SOURCES/Ignore-bad-enctypes-in-krb5_string_to_keysalts.patch
@@ -1,4 +1,4 @@
-From 087794ce6a9a529f4e6b0474fbfe3b6be3bc01b2 Mon Sep 17 00:00:00 2001
+From 42e29f27ce64fece2839bcce910813e97ca31210 Mon Sep 17 00:00:00 2001
 From: Robbie Harwood <rharwood@redhat.com>
 Date: Wed, 15 Jul 2020 15:42:20 -0400
 Subject: [PATCH] Ignore bad enctypes in krb5_string_to_keysalts()
diff --git a/SOURCES/Unify-kvno-option-documentation.patch b/SOURCES/Unify-kvno-option-documentation.patch
index 0a1c522..8106564 100644
--- a/SOURCES/Unify-kvno-option-documentation.patch
+++ b/SOURCES/Unify-kvno-option-documentation.patch
@@ -1,4 +1,4 @@
-From 54dade355262fafab54572384c4215cc6c63ecfb Mon Sep 17 00:00:00 2001
+From 6858ecbb9c407ff6d2b22cac283ea2461af1757b Mon Sep 17 00:00:00 2001
 From: Robbie Harwood <rharwood@redhat.com>
 Date: Thu, 20 Aug 2020 17:49:29 -0400
 Subject: [PATCH] Unify kvno option documentation
@@ -25,15 +25,14 @@ target_version: 1.18-next
 
 (cherry picked from commit becd1ad6830b526d08ddaf5b2b6f213154c6446c)
 (cherry picked from commit 52e3695cc5ef00766e12adfe8ed276c2885e71bb)
-[rharwood@redhat.com: backport around added kvno options]
 ---
- doc/user/user_commands/kvno.rst | 17 +++++++++--------
- src/clients/kvno/kvno.c         | 12 ++++++++----
- src/man/kvno.man                | 17 +++++++++--------
- 3 files changed, 26 insertions(+), 20 deletions(-)
+ doc/user/user_commands/kvno.rst | 24 +++++++++++++-----------
+ src/clients/kvno/kvno.c         | 15 +++++++++------
+ src/man/kvno.man                | 24 +++++++++++++-----------
+ 3 files changed, 35 insertions(+), 28 deletions(-)
 
 diff --git a/doc/user/user_commands/kvno.rst b/doc/user/user_commands/kvno.rst
-index 3892f0ca5..53e569651 100644
+index 718313576..65c44e1c0 100644
 --- a/doc/user/user_commands/kvno.rst
 +++ b/doc/user/user_commands/kvno.rst
 @@ -10,13 +10,9 @@ SYNOPSIS
@@ -73,11 +72,32 @@ index 3892f0ca5..53e569651 100644
  
  **-P**
      Specifies that the *service1 service2* ...  arguments are to be
+@@ -76,16 +77,17 @@ OPTIONS
+ 
+ **--cached-only**
+     Only retrieve credentials already present in the cache, not from
+-    the KDC.
++    the KDC.  (Added in release 1.19.)
+ 
+ **--no-store**
+     Do not store retrieved credentials in the cache.  If
+     **--out-cache** is also specified, credentials will still be
+-    stored into the output credential cache.
++    stored into the output credential cache.  (Added in release 1.19.)
+ 
+ **--out-cache** *ccache*
+     Initialize *ccache* and store all retrieved credentials into it.
+-    Do not store acquired credentials in the input cache.
++    Do not store acquired credentials in the input cache.  (Added in
++    release 1.19.)
+ 
+ **--u2u** *ccache*
+     Requests a user-to-user ticket.  *ccache* must contain a local
 diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
-index 2472c0cfe..8edd97361 100644
+index 9d85864f6..c5f6bf700 100644
 --- a/src/clients/kvno/kvno.c
 +++ b/src/clients/kvno/kvno.c
-@@ -38,13 +38,17 @@
+@@ -38,15 +38,18 @@
  static char *prog;
  static int quiet = 0;
  
@@ -89,18 +109,21 @@ index 2472c0cfe..8edd97361 100644
 -    fprintf(stderr, _("usage: %s [-C] [-u] [-c ccache] [-e etype]\n"), prog);
 -    fprintf(stderr, _("\t[-k keytab] [-S sname] [{-I | -U} for_user | "
 -                      "[-F cert_file] [-P]]\n"));
--    fprintf(stderr, _("\t[--u2u ccache] service1 service2 ...\n"));
+-    fprintf(stderr, _("\t[--cached-only] [--no-store] [--out-cache ccache] "
+-                      "[--u2u ccache]\n"));
+-    fprintf(stderr, _("\tservice1 service2 ...\n"));
 +    fprintf(stderr, _("usage: %s [-c ccache] [-e etype] [-k keytab] [-q] "
 +                      "[-u | -S sname]" XUSAGE_BREAK
 +                      "[[{-F cert_file | {-I | -U} for_user} [-P]] | "
 +                      "--u2u ccache]" XUSAGE_BREAK
++                      "[--cached-only] [--no-store] [--out-cache] "
 +                      "service1 service2 ...\n"),
 +            prog);
      exit(1);
  }
  
 diff --git a/src/man/kvno.man b/src/man/kvno.man
-index 005a2ec97..e156df723 100644
+index b9f6739eb..22318324d 100644
 --- a/src/man/kvno.man
 +++ b/src/man/kvno.man
 @@ -36,13 +36,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
@@ -140,3 +163,24 @@ index 005a2ec97..e156df723 100644
  .TP
  \fB\-P\fP
  Specifies that the \fIservice1 service2\fP ...  arguments are to be
+@@ -97,16 +98,17 @@ certificate file must be in PEM format.
+ .TP
+ \fB\-\-cached\-only\fP
+ Only retrieve credentials already present in the cache, not from
+-the KDC.
++the KDC.  (Added in release 1.19.)
+ .TP
+ \fB\-\-no\-store\fP
+ Do not store retrieved credentials in the cache.  If
+ \fB\-\-out\-cache\fP is also specified, credentials will still be
+-stored into the output credential cache.
++stored into the output credential cache.  (Added in release 1.19.)
+ .TP
+ \fB\-\-out\-cache\fP \fIccache\fP
+ Initialize \fIccache\fP and store all retrieved credentials into it.
+-Do not store acquired credentials in the input cache.
++Do not store acquired credentials in the input cache.  (Added in
++release 1.19.)
+ .TP
+ \fB\-\-u2u\fP \fIccache\fP
+ Requests a user\-to\-user ticket.  \fIccache\fP must contain a local
diff --git a/SPECS/krb5.spec b/SPECS/krb5.spec
index 15caa13..f1566ef 100644
--- a/SPECS/krb5.spec
+++ b/SPECS/krb5.spec
@@ -18,7 +18,7 @@ Summary: The Kerberos network authentication system
 Name: krb5
 Version: 1.18.2
 # for prerelease, should be e.g., 0.% {prerelease}.1% { ?dist } (without spaces)
-Release: 8%{?dist}
+Release: 9%{?dist}
 
 # lookaside-cached sources; two downloads and a build artifact
 Source0: https://web.mit.edu/kerberos/dist/krb5/1.18/krb5-%{version}%{prerelease}.tar.gz
@@ -71,11 +71,13 @@ Patch125: Implement-KERB_AP_OPTIONS_CBT-server-side.patch
 Patch126: Add-client_aware_channel_bindings-option.patch
 Patch127: Pass-channel-bindings-through-SPNEGO.patch
 Patch128: Add-channel-bindings-tests.patch
-Patch129: Ignore-bad-enctypes-in-krb5_string_to_keysalts.patch
-Patch130: Fix-leak-in-KERB_AP_OPTIONS_CBT-server-support.patch
-Patch131: Unify-kvno-option-documentation.patch
-Patch132: Document-k-option-in-kvno-1-synopsis.patch
-Patch133: Add-recursion-limit-for-ASN.1-indefinite-lengths.patch
+Patch129: Add-three-kvno-options-from-Heimdal-kgetcred.patch
+Patch130: Ignore-bad-enctypes-in-krb5_string_to_keysalts.patch
+Patch131: Fix-leak-in-KERB_AP_OPTIONS_CBT-server-support.patch
+Patch132: Unify-kvno-option-documentation.patch
+Patch133: Document-k-option-in-kvno-1-synopsis.patch
+Patch134: Add-recursion-limit-for-ASN.1-indefinite-lengths.patch
+Patch135: Add-support-for-start_realm-cache-config.patch
 
 License: MIT
 URL: http://web.mit.edu/kerberos/www/
@@ -686,6 +688,10 @@ exit 0
 %{_libdir}/libkadm5srv_mit.so.*
 
 %changelog
+* Tue Apr 20 2021 Robbie Harwood <rharwood@redhat.com> - 1.18.2-9
+- Add support for start_realm cache config
+- Resolves: #1901195
+
 * Wed Dec 16 2020 Robbie Harwood <rharwood@redhat.com> - 1.18.2-8
 - Add recursion limit for ASN.1 indefinite lengths (CVE-2020-28196)
 - Resolves: #1906492