xref: /freebsd/crypto/krb5/src/kdc/kdc_authdata.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* kdc/kdc_authdata.c - Authorization data routines for the KDC */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright (C) 2007 Apple Inc.  All Rights Reserved.
5*7f2fe78bSCy Schubert  * Copyright (C) 2008, 2009 by the Massachusetts Institute of Technology.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
9*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert  *
12*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
24*7f2fe78bSCy Schubert  * or implied warranty.
25*7f2fe78bSCy Schubert  */
26*7f2fe78bSCy Schubert 
27*7f2fe78bSCy Schubert #include "k5-int.h"
28*7f2fe78bSCy Schubert #include "kdc_util.h"
29*7f2fe78bSCy Schubert #include "extern.h"
30*7f2fe78bSCy Schubert #include <stdio.h>
31*7f2fe78bSCy Schubert #include "adm_proto.h"
32*7f2fe78bSCy Schubert 
33*7f2fe78bSCy Schubert #include <syslog.h>
34*7f2fe78bSCy Schubert 
35*7f2fe78bSCy Schubert #include <assert.h>
36*7f2fe78bSCy Schubert #include <krb5/kdcauthdata_plugin.h>
37*7f2fe78bSCy Schubert 
38*7f2fe78bSCy Schubert typedef struct kdcauthdata_handle_st {
39*7f2fe78bSCy Schubert     struct krb5_kdcauthdata_vtable_st vt;
40*7f2fe78bSCy Schubert     krb5_kdcauthdata_moddata data;
41*7f2fe78bSCy Schubert } kdcauthdata_handle;
42*7f2fe78bSCy Schubert 
43*7f2fe78bSCy Schubert static kdcauthdata_handle *authdata_modules;
44*7f2fe78bSCy Schubert static size_t n_authdata_modules;
45*7f2fe78bSCy Schubert 
46*7f2fe78bSCy Schubert /* Load authdata plugin modules. */
47*7f2fe78bSCy Schubert krb5_error_code
load_authdata_plugins(krb5_context context)48*7f2fe78bSCy Schubert load_authdata_plugins(krb5_context context)
49*7f2fe78bSCy Schubert {
50*7f2fe78bSCy Schubert     krb5_error_code ret;
51*7f2fe78bSCy Schubert     krb5_plugin_initvt_fn *modules = NULL, *mod;
52*7f2fe78bSCy Schubert     kdcauthdata_handle *list, *h;
53*7f2fe78bSCy Schubert     size_t count;
54*7f2fe78bSCy Schubert 
55*7f2fe78bSCy Schubert     ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCAUTHDATA, &modules);
56*7f2fe78bSCy Schubert     if (ret)
57*7f2fe78bSCy Schubert         return ret;
58*7f2fe78bSCy Schubert 
59*7f2fe78bSCy Schubert     /* Allocate a large enough list of handles. */
60*7f2fe78bSCy Schubert     for (count = 0; modules[count] != NULL; count++);
61*7f2fe78bSCy Schubert     list = calloc(count + 1, sizeof(*list));
62*7f2fe78bSCy Schubert     if (list == NULL) {
63*7f2fe78bSCy Schubert         k5_plugin_free_modules(context, modules);
64*7f2fe78bSCy Schubert         return ENOMEM;
65*7f2fe78bSCy Schubert     }
66*7f2fe78bSCy Schubert 
67*7f2fe78bSCy Schubert     /* Initialize each module's vtable and module data. */
68*7f2fe78bSCy Schubert     count = 0;
69*7f2fe78bSCy Schubert     for (mod = modules; *mod != NULL; mod++) {
70*7f2fe78bSCy Schubert         h = &list[count];
71*7f2fe78bSCy Schubert         memset(h, 0, sizeof(*h));
72*7f2fe78bSCy Schubert         ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&h->vt);
73*7f2fe78bSCy Schubert         if (ret)                /* Version mismatch, keep going. */
74*7f2fe78bSCy Schubert             continue;
75*7f2fe78bSCy Schubert         if (h->vt.init != NULL) {
76*7f2fe78bSCy Schubert             ret = h->vt.init(context, &h->data);
77*7f2fe78bSCy Schubert             if (ret) {
78*7f2fe78bSCy Schubert                 kdc_err(context, ret, _("while loading authdata module %s"),
79*7f2fe78bSCy Schubert                         h->vt.name);
80*7f2fe78bSCy Schubert                 continue;
81*7f2fe78bSCy Schubert             }
82*7f2fe78bSCy Schubert         }
83*7f2fe78bSCy Schubert         count++;
84*7f2fe78bSCy Schubert     }
85*7f2fe78bSCy Schubert 
86*7f2fe78bSCy Schubert     authdata_modules = list;
87*7f2fe78bSCy Schubert     n_authdata_modules = count;
88*7f2fe78bSCy Schubert     k5_plugin_free_modules(context, modules);
89*7f2fe78bSCy Schubert     return 0;
90*7f2fe78bSCy Schubert }
91*7f2fe78bSCy Schubert 
92*7f2fe78bSCy Schubert krb5_error_code
unload_authdata_plugins(krb5_context context)93*7f2fe78bSCy Schubert unload_authdata_plugins(krb5_context context)
94*7f2fe78bSCy Schubert {
95*7f2fe78bSCy Schubert     kdcauthdata_handle *h;
96*7f2fe78bSCy Schubert     size_t i;
97*7f2fe78bSCy Schubert 
98*7f2fe78bSCy Schubert     for (i = 0; i < n_authdata_modules; i++) {
99*7f2fe78bSCy Schubert         h = &authdata_modules[i];
100*7f2fe78bSCy Schubert         if (h->vt.fini != NULL)
101*7f2fe78bSCy Schubert             h->vt.fini(context, h->data);
102*7f2fe78bSCy Schubert     }
103*7f2fe78bSCy Schubert     free(authdata_modules);
104*7f2fe78bSCy Schubert     authdata_modules = NULL;
105*7f2fe78bSCy Schubert     return 0;
106*7f2fe78bSCy Schubert }
107*7f2fe78bSCy Schubert 
108*7f2fe78bSCy Schubert /* Return true if authdata should be filtered when copying from untrusted
109*7f2fe78bSCy Schubert  * authdata.  If desired_type is non-zero, look only for that type. */
110*7f2fe78bSCy Schubert static krb5_boolean
is_kdc_issued_authdatum(krb5_authdata * authdata,krb5_authdatatype desired_type)111*7f2fe78bSCy Schubert is_kdc_issued_authdatum(krb5_authdata *authdata,
112*7f2fe78bSCy Schubert                         krb5_authdatatype desired_type)
113*7f2fe78bSCy Schubert {
114*7f2fe78bSCy Schubert     krb5_boolean result = FALSE;
115*7f2fe78bSCy Schubert     krb5_authdatatype ad_type;
116*7f2fe78bSCy Schubert     unsigned int i, count = 0;
117*7f2fe78bSCy Schubert     krb5_authdatatype *ad_types, *containee_types = NULL;
118*7f2fe78bSCy Schubert 
119*7f2fe78bSCy Schubert     if (authdata->ad_type == KRB5_AUTHDATA_IF_RELEVANT) {
120*7f2fe78bSCy Schubert         if (krb5int_get_authdata_containee_types(NULL, authdata, &count,
121*7f2fe78bSCy Schubert                                                  &containee_types) != 0)
122*7f2fe78bSCy Schubert             goto cleanup;
123*7f2fe78bSCy Schubert         ad_types = containee_types;
124*7f2fe78bSCy Schubert     } else {
125*7f2fe78bSCy Schubert         ad_type = authdata->ad_type;
126*7f2fe78bSCy Schubert         count = 1;
127*7f2fe78bSCy Schubert         ad_types = &ad_type;
128*7f2fe78bSCy Schubert     }
129*7f2fe78bSCy Schubert 
130*7f2fe78bSCy Schubert     for (i = 0; i < count; i++) {
131*7f2fe78bSCy Schubert         switch (ad_types[i]) {
132*7f2fe78bSCy Schubert         case KRB5_AUTHDATA_SIGNTICKET:
133*7f2fe78bSCy Schubert         case KRB5_AUTHDATA_KDC_ISSUED:
134*7f2fe78bSCy Schubert         case KRB5_AUTHDATA_WIN2K_PAC:
135*7f2fe78bSCy Schubert         case KRB5_AUTHDATA_CAMMAC:
136*7f2fe78bSCy Schubert         case KRB5_AUTHDATA_AUTH_INDICATOR:
137*7f2fe78bSCy Schubert             result = desired_type ? (desired_type == ad_types[i]) : TRUE;
138*7f2fe78bSCy Schubert             break;
139*7f2fe78bSCy Schubert         default:
140*7f2fe78bSCy Schubert             result = FALSE;
141*7f2fe78bSCy Schubert             break;
142*7f2fe78bSCy Schubert         }
143*7f2fe78bSCy Schubert         if (result)
144*7f2fe78bSCy Schubert             break;
145*7f2fe78bSCy Schubert     }
146*7f2fe78bSCy Schubert 
147*7f2fe78bSCy Schubert cleanup:
148*7f2fe78bSCy Schubert     free(containee_types);
149*7f2fe78bSCy Schubert     return result;
150*7f2fe78bSCy Schubert }
151*7f2fe78bSCy Schubert 
152*7f2fe78bSCy Schubert /* Return true if authdata contains any mandatory-for-KDC elements. */
153*7f2fe78bSCy Schubert static krb5_boolean
has_mandatory_for_kdc_authdata(krb5_context context,krb5_authdata ** authdata)154*7f2fe78bSCy Schubert has_mandatory_for_kdc_authdata(krb5_context context, krb5_authdata **authdata)
155*7f2fe78bSCy Schubert {
156*7f2fe78bSCy Schubert     int i;
157*7f2fe78bSCy Schubert 
158*7f2fe78bSCy Schubert     if (authdata == NULL)
159*7f2fe78bSCy Schubert         return FALSE;
160*7f2fe78bSCy Schubert     for (i = 0; authdata[i] != NULL; i++) {
161*7f2fe78bSCy Schubert         if (authdata[i]->ad_type == KRB5_AUTHDATA_MANDATORY_FOR_KDC)
162*7f2fe78bSCy Schubert             return TRUE;
163*7f2fe78bSCy Schubert     }
164*7f2fe78bSCy Schubert     return FALSE;
165*7f2fe78bSCy Schubert }
166*7f2fe78bSCy Schubert 
167*7f2fe78bSCy Schubert /* Add elements from *new_elements to *existing_list, reallocating as
168*7f2fe78bSCy Schubert  * necessary.  On success, release *new_elements and set it to NULL. */
169*7f2fe78bSCy Schubert static krb5_error_code
merge_authdata(krb5_authdata *** existing_list,krb5_authdata *** new_elements)170*7f2fe78bSCy Schubert merge_authdata(krb5_authdata ***existing_list, krb5_authdata ***new_elements)
171*7f2fe78bSCy Schubert {
172*7f2fe78bSCy Schubert     size_t count = 0, ncount = 0;
173*7f2fe78bSCy Schubert     krb5_authdata **list = *existing_list, **nlist = *new_elements;
174*7f2fe78bSCy Schubert 
175*7f2fe78bSCy Schubert     if (nlist == NULL)
176*7f2fe78bSCy Schubert         return 0;
177*7f2fe78bSCy Schubert 
178*7f2fe78bSCy Schubert     for (count = 0; list != NULL && list[count] != NULL; count++);
179*7f2fe78bSCy Schubert     for (ncount = 0; nlist[ncount] != NULL; ncount++);
180*7f2fe78bSCy Schubert 
181*7f2fe78bSCy Schubert     list = realloc(list, (count + ncount + 1) * sizeof(*list));
182*7f2fe78bSCy Schubert     if (list == NULL)
183*7f2fe78bSCy Schubert         return ENOMEM;
184*7f2fe78bSCy Schubert 
185*7f2fe78bSCy Schubert     memcpy(list + count, nlist, ncount * sizeof(*nlist));
186*7f2fe78bSCy Schubert     list[count + ncount] = NULL;
187*7f2fe78bSCy Schubert     free(nlist);
188*7f2fe78bSCy Schubert 
189*7f2fe78bSCy Schubert     if (list[0] == NULL) {
190*7f2fe78bSCy Schubert         free(list);
191*7f2fe78bSCy Schubert         list = NULL;
192*7f2fe78bSCy Schubert     }
193*7f2fe78bSCy Schubert 
194*7f2fe78bSCy Schubert     *new_elements = NULL;
195*7f2fe78bSCy Schubert     *existing_list = list;
196*7f2fe78bSCy Schubert     return 0;
197*7f2fe78bSCy Schubert }
198*7f2fe78bSCy Schubert 
199*7f2fe78bSCy Schubert /* Add a copy of new_elements to *existing_list, omitting KDC-issued
200*7f2fe78bSCy Schubert  * authdata. */
201*7f2fe78bSCy Schubert static krb5_error_code
add_filtered_authdata(krb5_authdata *** existing_list,krb5_authdata ** new_elements)202*7f2fe78bSCy Schubert add_filtered_authdata(krb5_authdata ***existing_list,
203*7f2fe78bSCy Schubert                       krb5_authdata **new_elements)
204*7f2fe78bSCy Schubert {
205*7f2fe78bSCy Schubert     krb5_error_code ret;
206*7f2fe78bSCy Schubert     krb5_authdata **copy;
207*7f2fe78bSCy Schubert     size_t i, j;
208*7f2fe78bSCy Schubert 
209*7f2fe78bSCy Schubert     if (new_elements == NULL)
210*7f2fe78bSCy Schubert         return 0;
211*7f2fe78bSCy Schubert 
212*7f2fe78bSCy Schubert     ret = krb5_copy_authdata(NULL, new_elements, &copy);
213*7f2fe78bSCy Schubert     if (ret)
214*7f2fe78bSCy Schubert         return ret;
215*7f2fe78bSCy Schubert 
216*7f2fe78bSCy Schubert     /* Remove KDC-issued elements from copy. */
217*7f2fe78bSCy Schubert     j = 0;
218*7f2fe78bSCy Schubert     for (i = 0; copy[i] != NULL; i++) {
219*7f2fe78bSCy Schubert         if (is_kdc_issued_authdatum(copy[i], 0)) {
220*7f2fe78bSCy Schubert             free(copy[i]->contents);
221*7f2fe78bSCy Schubert             free(copy[i]);
222*7f2fe78bSCy Schubert         } else {
223*7f2fe78bSCy Schubert             copy[j++] = copy[i];
224*7f2fe78bSCy Schubert         }
225*7f2fe78bSCy Schubert     }
226*7f2fe78bSCy Schubert     copy[j] = NULL;
227*7f2fe78bSCy Schubert 
228*7f2fe78bSCy Schubert     /* Destructively merge the filtered copy into existing_list. */
229*7f2fe78bSCy Schubert     ret = merge_authdata(existing_list, &copy);
230*7f2fe78bSCy Schubert     krb5_free_authdata(NULL, copy);
231*7f2fe78bSCy Schubert     return ret;
232*7f2fe78bSCy Schubert }
233*7f2fe78bSCy Schubert 
234*7f2fe78bSCy Schubert /* Copy TGS-REQ authorization data into the ticket authdata. */
235*7f2fe78bSCy Schubert static krb5_error_code
copy_request_authdata(krb5_context context,krb5_keyblock * client_key,krb5_kdc_req * req,krb5_enc_tkt_part * enc_tkt_req,krb5_authdata *** tkt_authdata)236*7f2fe78bSCy Schubert copy_request_authdata(krb5_context context, krb5_keyblock *client_key,
237*7f2fe78bSCy Schubert                       krb5_kdc_req *req, krb5_enc_tkt_part *enc_tkt_req,
238*7f2fe78bSCy Schubert                       krb5_authdata ***tkt_authdata)
239*7f2fe78bSCy Schubert {
240*7f2fe78bSCy Schubert     krb5_error_code ret;
241*7f2fe78bSCy Schubert     krb5_data plaintext;
242*7f2fe78bSCy Schubert 
243*7f2fe78bSCy Schubert     assert(enc_tkt_req != NULL);
244*7f2fe78bSCy Schubert 
245*7f2fe78bSCy Schubert     ret = alloc_data(&plaintext, req->authorization_data.ciphertext.length);
246*7f2fe78bSCy Schubert     if (ret)
247*7f2fe78bSCy Schubert         return ret;
248*7f2fe78bSCy Schubert 
249*7f2fe78bSCy Schubert     /*
250*7f2fe78bSCy Schubert      * RFC 4120 requires authdata in the TGS body to be encrypted in the subkey
251*7f2fe78bSCy Schubert      * with usage 5 if a subkey is present, and in the TGS session key with key
252*7f2fe78bSCy Schubert      * usage 4 if it is not.  Prior to krb5 1.7, we got this wrong, always
253*7f2fe78bSCy Schubert      * decrypting the authorization data with the TGS session key and usage 4.
254*7f2fe78bSCy Schubert      * For the sake of conservatism, try the decryption the old way (wrong if
255*7f2fe78bSCy Schubert      * client_key is a subkey) first, and then try again the right way (in the
256*7f2fe78bSCy Schubert      * case where client_key is a subkey) if the first way fails.
257*7f2fe78bSCy Schubert      */
258*7f2fe78bSCy Schubert     ret = krb5_c_decrypt(context, enc_tkt_req->session,
259*7f2fe78bSCy Schubert                          KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY, 0,
260*7f2fe78bSCy Schubert                          &req->authorization_data, &plaintext);
261*7f2fe78bSCy Schubert     if (ret) {
262*7f2fe78bSCy Schubert         ret = krb5_c_decrypt(context, client_key,
263*7f2fe78bSCy Schubert                              KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY, 0,
264*7f2fe78bSCy Schubert                              &req->authorization_data, &plaintext);
265*7f2fe78bSCy Schubert     }
266*7f2fe78bSCy Schubert     if (ret)
267*7f2fe78bSCy Schubert         goto cleanup;
268*7f2fe78bSCy Schubert 
269*7f2fe78bSCy Schubert     /* Decode the decrypted authdata and make it available to modules in the
270*7f2fe78bSCy Schubert      * request. */
271*7f2fe78bSCy Schubert     ret = decode_krb5_authdata(&plaintext, &req->unenc_authdata);
272*7f2fe78bSCy Schubert     if (ret)
273*7f2fe78bSCy Schubert         goto cleanup;
274*7f2fe78bSCy Schubert 
275*7f2fe78bSCy Schubert     if (has_mandatory_for_kdc_authdata(context, req->unenc_authdata)) {
276*7f2fe78bSCy Schubert         ret = KRB5KDC_ERR_POLICY;
277*7f2fe78bSCy Schubert         goto cleanup;
278*7f2fe78bSCy Schubert     }
279*7f2fe78bSCy Schubert 
280*7f2fe78bSCy Schubert     ret = add_filtered_authdata(tkt_authdata, req->unenc_authdata);
281*7f2fe78bSCy Schubert 
282*7f2fe78bSCy Schubert cleanup:
283*7f2fe78bSCy Schubert     free(plaintext.data);
284*7f2fe78bSCy Schubert     return ret;
285*7f2fe78bSCy Schubert }
286*7f2fe78bSCy Schubert 
287*7f2fe78bSCy Schubert /* Copy TGT authorization data into the ticket authdata. */
288*7f2fe78bSCy Schubert static krb5_error_code
copy_tgt_authdata(krb5_context context,krb5_kdc_req * request,krb5_authdata ** tgt_authdata,krb5_authdata *** tkt_authdata)289*7f2fe78bSCy Schubert copy_tgt_authdata(krb5_context context, krb5_kdc_req *request,
290*7f2fe78bSCy Schubert                   krb5_authdata **tgt_authdata, krb5_authdata ***tkt_authdata)
291*7f2fe78bSCy Schubert {
292*7f2fe78bSCy Schubert     if (has_mandatory_for_kdc_authdata(context, tgt_authdata))
293*7f2fe78bSCy Schubert         return KRB5KDC_ERR_POLICY;
294*7f2fe78bSCy Schubert 
295*7f2fe78bSCy Schubert     return add_filtered_authdata(tkt_authdata, tgt_authdata);
296*7f2fe78bSCy Schubert }
297*7f2fe78bSCy Schubert 
298*7f2fe78bSCy Schubert /* Add authentication indicator authdata to enc_tkt_reply, wrapped in a CAMMAC
299*7f2fe78bSCy Schubert  * and an IF-RELEVANT container. */
300*7f2fe78bSCy Schubert static krb5_error_code
add_auth_indicators(krb5_context context,krb5_data * const * auth_indicators,krb5_keyblock * server_key,krb5_db_entry * krbtgt,krb5_keyblock * krbtgt_key,krb5_enc_tkt_part * enc_tkt_reply)301*7f2fe78bSCy Schubert add_auth_indicators(krb5_context context, krb5_data *const *auth_indicators,
302*7f2fe78bSCy Schubert                     krb5_keyblock *server_key, krb5_db_entry *krbtgt,
303*7f2fe78bSCy Schubert                     krb5_keyblock *krbtgt_key,
304*7f2fe78bSCy Schubert                     krb5_enc_tkt_part *enc_tkt_reply)
305*7f2fe78bSCy Schubert {
306*7f2fe78bSCy Schubert     krb5_error_code ret;
307*7f2fe78bSCy Schubert     krb5_data *der_indicators = NULL;
308*7f2fe78bSCy Schubert     krb5_authdata ad, *list[2], **cammac = NULL;
309*7f2fe78bSCy Schubert 
310*7f2fe78bSCy Schubert     if (auth_indicators == NULL || *auth_indicators == NULL)
311*7f2fe78bSCy Schubert         return 0;
312*7f2fe78bSCy Schubert 
313*7f2fe78bSCy Schubert     /* Format the authentication indicators into an authdata list. */
314*7f2fe78bSCy Schubert     ret = encode_utf8_strings(auth_indicators, &der_indicators);
315*7f2fe78bSCy Schubert     if (ret)
316*7f2fe78bSCy Schubert         goto cleanup;
317*7f2fe78bSCy Schubert     ad.ad_type = KRB5_AUTHDATA_AUTH_INDICATOR;
318*7f2fe78bSCy Schubert     ad.length = der_indicators->length;
319*7f2fe78bSCy Schubert     ad.contents = (uint8_t *)der_indicators->data;
320*7f2fe78bSCy Schubert     list[0] = &ad;
321*7f2fe78bSCy Schubert     list[1] = NULL;
322*7f2fe78bSCy Schubert 
323*7f2fe78bSCy Schubert     /* Wrap the list in CAMMAC and IF-RELEVANT containers. */
324*7f2fe78bSCy Schubert     ret = cammac_create(context, enc_tkt_reply, server_key, krbtgt, krbtgt_key,
325*7f2fe78bSCy Schubert                         list, &cammac);
326*7f2fe78bSCy Schubert     if (ret)
327*7f2fe78bSCy Schubert         goto cleanup;
328*7f2fe78bSCy Schubert 
329*7f2fe78bSCy Schubert     /* Add the wrapped authdata to the ticket, without copying or filtering. */
330*7f2fe78bSCy Schubert     ret = merge_authdata(&enc_tkt_reply->authorization_data, &cammac);
331*7f2fe78bSCy Schubert 
332*7f2fe78bSCy Schubert cleanup:
333*7f2fe78bSCy Schubert     krb5_free_data(context, der_indicators);
334*7f2fe78bSCy Schubert     krb5_free_authdata(context, cammac);
335*7f2fe78bSCy Schubert     return ret;
336*7f2fe78bSCy Schubert }
337*7f2fe78bSCy Schubert 
338*7f2fe78bSCy Schubert /* Extract any properly verified authentication indicators from the authdata in
339*7f2fe78bSCy Schubert  * enc_tkt. */
340*7f2fe78bSCy Schubert krb5_error_code
get_auth_indicators(krb5_context context,krb5_enc_tkt_part * enc_tkt,krb5_db_entry * local_tgt,krb5_keyblock * local_tgt_key,krb5_data *** indicators_out)341*7f2fe78bSCy Schubert get_auth_indicators(krb5_context context, krb5_enc_tkt_part *enc_tkt,
342*7f2fe78bSCy Schubert                     krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
343*7f2fe78bSCy Schubert                     krb5_data ***indicators_out)
344*7f2fe78bSCy Schubert {
345*7f2fe78bSCy Schubert     krb5_error_code ret;
346*7f2fe78bSCy Schubert     krb5_authdata **cammacs = NULL, **adp;
347*7f2fe78bSCy Schubert     krb5_cammac *cammac = NULL;
348*7f2fe78bSCy Schubert     krb5_data **indicators = NULL, der_cammac;
349*7f2fe78bSCy Schubert 
350*7f2fe78bSCy Schubert     *indicators_out = NULL;
351*7f2fe78bSCy Schubert 
352*7f2fe78bSCy Schubert     ret = krb5_find_authdata(context, enc_tkt->authorization_data, NULL,
353*7f2fe78bSCy Schubert                              KRB5_AUTHDATA_CAMMAC, &cammacs);
354*7f2fe78bSCy Schubert     if (ret)
355*7f2fe78bSCy Schubert         goto cleanup;
356*7f2fe78bSCy Schubert 
357*7f2fe78bSCy Schubert     for (adp = cammacs; adp != NULL && *adp != NULL; adp++) {
358*7f2fe78bSCy Schubert         der_cammac = make_data((*adp)->contents, (*adp)->length);
359*7f2fe78bSCy Schubert         ret = decode_krb5_cammac(&der_cammac, &cammac);
360*7f2fe78bSCy Schubert         if (ret)
361*7f2fe78bSCy Schubert             goto cleanup;
362*7f2fe78bSCy Schubert         if (cammac_check_kdcver(context, cammac, enc_tkt, local_tgt,
363*7f2fe78bSCy Schubert                                 local_tgt_key)) {
364*7f2fe78bSCy Schubert             ret = authind_extract(context, cammac->elements, &indicators);
365*7f2fe78bSCy Schubert             if (ret)
366*7f2fe78bSCy Schubert                 goto cleanup;
367*7f2fe78bSCy Schubert         }
368*7f2fe78bSCy Schubert         k5_free_cammac(context, cammac);
369*7f2fe78bSCy Schubert         cammac = NULL;
370*7f2fe78bSCy Schubert     }
371*7f2fe78bSCy Schubert 
372*7f2fe78bSCy Schubert     *indicators_out = indicators;
373*7f2fe78bSCy Schubert     indicators = NULL;
374*7f2fe78bSCy Schubert 
375*7f2fe78bSCy Schubert cleanup:
376*7f2fe78bSCy Schubert     krb5_free_authdata(context, cammacs);
377*7f2fe78bSCy Schubert     k5_free_cammac(context, cammac);
378*7f2fe78bSCy Schubert     k5_free_data_ptr_list(indicators);
379*7f2fe78bSCy Schubert     return ret;
380*7f2fe78bSCy Schubert }
381*7f2fe78bSCy Schubert 
382*7f2fe78bSCy Schubert static krb5_error_code
update_delegation_info(krb5_context context,krb5_kdc_req * req,krb5_pac old_pac,krb5_pac new_pac)383*7f2fe78bSCy Schubert update_delegation_info(krb5_context context, krb5_kdc_req *req,
384*7f2fe78bSCy Schubert                        krb5_pac old_pac, krb5_pac new_pac)
385*7f2fe78bSCy Schubert {
386*7f2fe78bSCy Schubert     krb5_error_code ret;
387*7f2fe78bSCy Schubert     krb5_data ndr_di_in = empty_data(), ndr_di_out = empty_data();
388*7f2fe78bSCy Schubert     struct pac_s4u_delegation_info *di = NULL;
389*7f2fe78bSCy Schubert     char *namestr = NULL;
390*7f2fe78bSCy Schubert 
391*7f2fe78bSCy Schubert     ret = krb5_pac_get_buffer(context, old_pac, KRB5_PAC_DELEGATION_INFO,
392*7f2fe78bSCy Schubert                               &ndr_di_in);
393*7f2fe78bSCy Schubert     if (ret && ret != ENOENT)
394*7f2fe78bSCy Schubert         goto cleanup;
395*7f2fe78bSCy Schubert     if (ret) {
396*7f2fe78bSCy Schubert         /* Create new delegation info. */
397*7f2fe78bSCy Schubert         di = k5alloc(sizeof(*di), &ret);
398*7f2fe78bSCy Schubert         if (di == NULL)
399*7f2fe78bSCy Schubert             goto cleanup;
400*7f2fe78bSCy Schubert         di->transited_services = k5calloc(1, sizeof(char *), &ret);
401*7f2fe78bSCy Schubert         if (di->transited_services == NULL)
402*7f2fe78bSCy Schubert             goto cleanup;
403*7f2fe78bSCy Schubert     } else {
404*7f2fe78bSCy Schubert         /* Decode and modify old delegation info. */
405*7f2fe78bSCy Schubert         ret = ndr_dec_delegation_info(&ndr_di_in, &di);
406*7f2fe78bSCy Schubert         if (ret)
407*7f2fe78bSCy Schubert             goto cleanup;
408*7f2fe78bSCy Schubert     }
409*7f2fe78bSCy Schubert 
410*7f2fe78bSCy Schubert     /* Set proxy_target to the requested server, without realm. */
411*7f2fe78bSCy Schubert     ret = krb5_unparse_name_flags(context, req->server,
412*7f2fe78bSCy Schubert                                   KRB5_PRINCIPAL_UNPARSE_DISPLAY |
413*7f2fe78bSCy Schubert                                   KRB5_PRINCIPAL_UNPARSE_NO_REALM,
414*7f2fe78bSCy Schubert                                   &namestr);
415*7f2fe78bSCy Schubert     if (ret)
416*7f2fe78bSCy Schubert         goto cleanup;
417*7f2fe78bSCy Schubert     free(di->proxy_target);
418*7f2fe78bSCy Schubert     di->proxy_target = namestr;
419*7f2fe78bSCy Schubert 
420*7f2fe78bSCy Schubert     /* Add a transited entry for the requesting service, with realm. */
421*7f2fe78bSCy Schubert     assert(req->second_ticket != NULL && req->second_ticket[0] != NULL);
422*7f2fe78bSCy Schubert     ret = krb5_unparse_name(context, req->second_ticket[0]->server, &namestr);
423*7f2fe78bSCy Schubert     if (ret)
424*7f2fe78bSCy Schubert         goto cleanup;
425*7f2fe78bSCy Schubert     di->transited_services[di->transited_services_length++] = namestr;
426*7f2fe78bSCy Schubert 
427*7f2fe78bSCy Schubert     ret = ndr_enc_delegation_info(di, &ndr_di_out);
428*7f2fe78bSCy Schubert     if (ret)
429*7f2fe78bSCy Schubert         goto cleanup;
430*7f2fe78bSCy Schubert 
431*7f2fe78bSCy Schubert     ret = krb5_pac_add_buffer(context, new_pac, KRB5_PAC_DELEGATION_INFO,
432*7f2fe78bSCy Schubert                               &ndr_di_out);
433*7f2fe78bSCy Schubert 
434*7f2fe78bSCy Schubert cleanup:
435*7f2fe78bSCy Schubert     krb5_free_data_contents(context, &ndr_di_in);
436*7f2fe78bSCy Schubert     krb5_free_data_contents(context, &ndr_di_out);
437*7f2fe78bSCy Schubert     ndr_free_delegation_info(di);
438*7f2fe78bSCy Schubert     return ret;
439*7f2fe78bSCy Schubert }
440*7f2fe78bSCy Schubert 
441*7f2fe78bSCy Schubert static krb5_error_code
copy_pac_buffer(krb5_context context,uint32_t buffer_type,krb5_pac old_pac,krb5_pac new_pac)442*7f2fe78bSCy Schubert copy_pac_buffer(krb5_context context, uint32_t buffer_type, krb5_pac old_pac,
443*7f2fe78bSCy Schubert                 krb5_pac new_pac)
444*7f2fe78bSCy Schubert {
445*7f2fe78bSCy Schubert     krb5_error_code ret;
446*7f2fe78bSCy Schubert     krb5_data data;
447*7f2fe78bSCy Schubert 
448*7f2fe78bSCy Schubert     ret = krb5_pac_get_buffer(context, old_pac, buffer_type, &data);
449*7f2fe78bSCy Schubert     if (ret)
450*7f2fe78bSCy Schubert         return ret;
451*7f2fe78bSCy Schubert     ret = krb5_pac_add_buffer(context, new_pac, buffer_type, &data);
452*7f2fe78bSCy Schubert     krb5_free_data_contents(context, &data);
453*7f2fe78bSCy Schubert     return ret;
454*7f2fe78bSCy Schubert }
455*7f2fe78bSCy Schubert 
456*7f2fe78bSCy Schubert /*
457*7f2fe78bSCy Schubert  * Possibly add a signed PAC to enc_tkt_reply.  Also possibly add auth
458*7f2fe78bSCy Schubert  * indicators; these are handled here so that the KDB module's issue_pac()
459*7f2fe78bSCy Schubert  * method can alter the auth indicator list.
460*7f2fe78bSCy Schubert  */
461*7f2fe78bSCy Schubert static krb5_error_code
handle_pac(kdc_realm_t * realm,unsigned int flags,krb5_db_entry * client,krb5_db_entry * server,krb5_db_entry * subject_server,krb5_db_entry * local_tgt,krb5_keyblock * local_tgt_key,krb5_keyblock * server_key,krb5_keyblock * subject_key,krb5_keyblock * replaced_reply_key,krb5_enc_tkt_part * subject_tkt,krb5_pac subject_pac,krb5_kdc_req * req,krb5_const_principal altcprinc,krb5_timestamp authtime,krb5_enc_tkt_part * enc_tkt_reply,krb5_data *** auth_indicators)462*7f2fe78bSCy Schubert handle_pac(kdc_realm_t *realm, unsigned int flags, krb5_db_entry *client,
463*7f2fe78bSCy Schubert            krb5_db_entry *server, krb5_db_entry *subject_server,
464*7f2fe78bSCy Schubert            krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
465*7f2fe78bSCy Schubert            krb5_keyblock *server_key, krb5_keyblock *subject_key,
466*7f2fe78bSCy Schubert            krb5_keyblock *replaced_reply_key, krb5_enc_tkt_part *subject_tkt,
467*7f2fe78bSCy Schubert            krb5_pac subject_pac, krb5_kdc_req *req,
468*7f2fe78bSCy Schubert            krb5_const_principal altcprinc, krb5_timestamp authtime,
469*7f2fe78bSCy Schubert            krb5_enc_tkt_part *enc_tkt_reply, krb5_data ***auth_indicators)
470*7f2fe78bSCy Schubert {
471*7f2fe78bSCy Schubert     krb5_context context = realm->realm_context;
472*7f2fe78bSCy Schubert     krb5_error_code ret;
473*7f2fe78bSCy Schubert     krb5_pac new_pac = NULL;
474*7f2fe78bSCy Schubert     krb5_const_principal pac_client = NULL;
475*7f2fe78bSCy Schubert     krb5_boolean with_realm, is_as_req = (req->msg_type == KRB5_AS_REQ);
476*7f2fe78bSCy Schubert     krb5_db_entry *signing_tgt;
477*7f2fe78bSCy Schubert     krb5_keyblock *privsvr_key = NULL;
478*7f2fe78bSCy Schubert 
479*7f2fe78bSCy Schubert     /* Don't add a PAC or auth indicators if the server disables authdata. */
480*7f2fe78bSCy Schubert     if (server->attributes & KRB5_KDB_NO_AUTH_DATA_REQUIRED)
481*7f2fe78bSCy Schubert         return 0;
482*7f2fe78bSCy Schubert 
483*7f2fe78bSCy Schubert     /*
484*7f2fe78bSCy Schubert      * Don't add a PAC if the realm disables them, or to an anonymous ticket,
485*7f2fe78bSCy Schubert      * or for an AS-REQ if the client requested not to get one, or for a
486*7f2fe78bSCy Schubert      * TGS-REQ if the subject ticket didn't contain one.
487*7f2fe78bSCy Schubert      */
488*7f2fe78bSCy Schubert     if (realm->realm_disable_pac ||
489*7f2fe78bSCy Schubert         (enc_tkt_reply->flags & TKT_FLG_ANONYMOUS) ||
490*7f2fe78bSCy Schubert         (is_as_req && !include_pac_p(context, req)) ||
491*7f2fe78bSCy Schubert         (!is_as_req && subject_pac == NULL)) {
492*7f2fe78bSCy Schubert         return add_auth_indicators(context, *auth_indicators, server_key,
493*7f2fe78bSCy Schubert                                    local_tgt, local_tgt_key, enc_tkt_reply);
494*7f2fe78bSCy Schubert     }
495*7f2fe78bSCy Schubert 
496*7f2fe78bSCy Schubert     ret = krb5_pac_init(context, &new_pac);
497*7f2fe78bSCy Schubert     if (ret)
498*7f2fe78bSCy Schubert         goto cleanup;
499*7f2fe78bSCy Schubert 
500*7f2fe78bSCy Schubert     if (subject_pac == NULL)
501*7f2fe78bSCy Schubert         signing_tgt = NULL;
502*7f2fe78bSCy Schubert     else if (krb5_is_tgs_principal(subject_server->princ))
503*7f2fe78bSCy Schubert         signing_tgt = subject_server;
504*7f2fe78bSCy Schubert     else
505*7f2fe78bSCy Schubert         signing_tgt = local_tgt;
506*7f2fe78bSCy Schubert 
507*7f2fe78bSCy Schubert     ret = krb5_db_issue_pac(context, flags, client, replaced_reply_key, server,
508*7f2fe78bSCy Schubert                             signing_tgt, authtime, subject_pac, new_pac,
509*7f2fe78bSCy Schubert                             auth_indicators);
510*7f2fe78bSCy Schubert     if (ret) {
511*7f2fe78bSCy Schubert         if (ret == KRB5_PLUGIN_OP_NOTSUPP)
512*7f2fe78bSCy Schubert             ret = 0;
513*7f2fe78bSCy Schubert         if (ret)
514*7f2fe78bSCy Schubert             goto cleanup;
515*7f2fe78bSCy Schubert     }
516*7f2fe78bSCy Schubert 
517*7f2fe78bSCy Schubert     ret = add_auth_indicators(context, *auth_indicators, server_key,
518*7f2fe78bSCy Schubert                               local_tgt, local_tgt_key, enc_tkt_reply);
519*7f2fe78bSCy Schubert 
520*7f2fe78bSCy Schubert     if ((flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) &&
521*7f2fe78bSCy Schubert         !(flags & KRB5_KDB_FLAG_CROSS_REALM)) {
522*7f2fe78bSCy Schubert         /* Add delegation info for the first S4U2Proxy request. */
523*7f2fe78bSCy Schubert         ret = update_delegation_info(context, req, subject_pac, new_pac);
524*7f2fe78bSCy Schubert         if (ret)
525*7f2fe78bSCy Schubert             goto cleanup;
526*7f2fe78bSCy Schubert     } else if (subject_pac != NULL) {
527*7f2fe78bSCy Schubert         /* Copy delegation info if it was present in the subject PAC. */
528*7f2fe78bSCy Schubert         ret = copy_pac_buffer(context, KRB5_PAC_DELEGATION_INFO, subject_pac,
529*7f2fe78bSCy Schubert                               new_pac);
530*7f2fe78bSCy Schubert         if (ret && ret != ENOENT)
531*7f2fe78bSCy Schubert             goto cleanup;
532*7f2fe78bSCy Schubert     }
533*7f2fe78bSCy Schubert 
534*7f2fe78bSCy Schubert     if ((flags & KRB5_KDB_FLAGS_S4U) &&
535*7f2fe78bSCy Schubert         (flags & KRB5_KDB_FLAG_ISSUING_REFERRAL)) {
536*7f2fe78bSCy Schubert         /* When issuing a referral for either kind of S4U request, add client
537*7f2fe78bSCy Schubert          * info for the subject with realm. */
538*7f2fe78bSCy Schubert         pac_client = altcprinc;
539*7f2fe78bSCy Schubert         with_realm = TRUE;
540*7f2fe78bSCy Schubert     } else if (subject_pac == NULL || (flags & KRB5_KDB_FLAGS_S4U)) {
541*7f2fe78bSCy Schubert         /* For a new PAC or when issuing a final ticket for either kind of S4U
542*7f2fe78bSCy Schubert          * request, add client info for the ticket client without the realm. */
543*7f2fe78bSCy Schubert         pac_client = enc_tkt_reply->client;
544*7f2fe78bSCy Schubert         with_realm = FALSE;
545*7f2fe78bSCy Schubert     } else {
546*7f2fe78bSCy Schubert         /*
547*7f2fe78bSCy Schubert          * For regular TGS and transitive RBCD requests, copy the client info
548*7f2fe78bSCy Schubert          * from the incoming PAC, and don't add client info during signing.  We
549*7f2fe78bSCy Schubert          * validated the incoming client info in validate_tgs_request().
550*7f2fe78bSCy Schubert          */
551*7f2fe78bSCy Schubert         ret = copy_pac_buffer(context, KRB5_PAC_CLIENT_INFO, subject_pac,
552*7f2fe78bSCy Schubert                               new_pac);
553*7f2fe78bSCy Schubert         if (ret)
554*7f2fe78bSCy Schubert             goto cleanup;
555*7f2fe78bSCy Schubert         pac_client = NULL;
556*7f2fe78bSCy Schubert         with_realm = FALSE;
557*7f2fe78bSCy Schubert     }
558*7f2fe78bSCy Schubert 
559*7f2fe78bSCy Schubert     ret = pac_privsvr_key(context, server, local_tgt_key, &privsvr_key);
560*7f2fe78bSCy Schubert     if (ret)
561*7f2fe78bSCy Schubert         goto cleanup;
562*7f2fe78bSCy Schubert     ret = krb5_kdc_sign_ticket(context, enc_tkt_reply, new_pac, server->princ,
563*7f2fe78bSCy Schubert                                pac_client, server_key, privsvr_key,
564*7f2fe78bSCy Schubert                                with_realm);
565*7f2fe78bSCy Schubert     if (ret)
566*7f2fe78bSCy Schubert         goto cleanup;
567*7f2fe78bSCy Schubert 
568*7f2fe78bSCy Schubert     ret = 0;
569*7f2fe78bSCy Schubert 
570*7f2fe78bSCy Schubert cleanup:
571*7f2fe78bSCy Schubert     krb5_pac_free(context, new_pac);
572*7f2fe78bSCy Schubert     krb5_free_keyblock(context, privsvr_key);
573*7f2fe78bSCy Schubert     return ret;
574*7f2fe78bSCy Schubert }
575*7f2fe78bSCy Schubert 
576*7f2fe78bSCy Schubert krb5_error_code
handle_authdata(kdc_realm_t * realm,unsigned int flags,krb5_db_entry * client,krb5_db_entry * server,krb5_db_entry * subject_server,krb5_db_entry * local_tgt,krb5_keyblock * local_tgt_key,krb5_keyblock * client_key,krb5_keyblock * server_key,krb5_keyblock * subject_key,krb5_keyblock * replaced_reply_key,krb5_data * req_pkt,krb5_kdc_req * req,krb5_const_principal altcprinc,krb5_pac subject_pac,krb5_enc_tkt_part * enc_tkt_req,krb5_data *** auth_indicators,krb5_enc_tkt_part * enc_tkt_reply)577*7f2fe78bSCy Schubert handle_authdata(kdc_realm_t *realm, unsigned int flags, krb5_db_entry *client,
578*7f2fe78bSCy Schubert                 krb5_db_entry *server, krb5_db_entry *subject_server,
579*7f2fe78bSCy Schubert                 krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
580*7f2fe78bSCy Schubert                 krb5_keyblock *client_key, krb5_keyblock *server_key,
581*7f2fe78bSCy Schubert                 krb5_keyblock *subject_key, krb5_keyblock *replaced_reply_key,
582*7f2fe78bSCy Schubert                 krb5_data *req_pkt, krb5_kdc_req *req,
583*7f2fe78bSCy Schubert                 krb5_const_principal altcprinc, krb5_pac subject_pac,
584*7f2fe78bSCy Schubert                 krb5_enc_tkt_part *enc_tkt_req, krb5_data ***auth_indicators,
585*7f2fe78bSCy Schubert                 krb5_enc_tkt_part *enc_tkt_reply)
586*7f2fe78bSCy Schubert {
587*7f2fe78bSCy Schubert     krb5_context context = realm->realm_context;
588*7f2fe78bSCy Schubert     kdcauthdata_handle *h;
589*7f2fe78bSCy Schubert     krb5_error_code ret = 0;
590*7f2fe78bSCy Schubert     size_t i;
591*7f2fe78bSCy Schubert 
592*7f2fe78bSCy Schubert     if (req->msg_type == KRB5_TGS_REQ &&
593*7f2fe78bSCy Schubert         req->authorization_data.ciphertext.data != NULL) {
594*7f2fe78bSCy Schubert         /* Copy TGS request authdata.  This must be done first so that modules
595*7f2fe78bSCy Schubert          * have access to the unencrypted request authdata. */
596*7f2fe78bSCy Schubert         ret = copy_request_authdata(context, client_key, req, enc_tkt_req,
597*7f2fe78bSCy Schubert                                     &enc_tkt_reply->authorization_data);
598*7f2fe78bSCy Schubert         if (ret)
599*7f2fe78bSCy Schubert             return ret;
600*7f2fe78bSCy Schubert     }
601*7f2fe78bSCy Schubert 
602*7f2fe78bSCy Schubert     /* Invoke loaded module handlers. */
603*7f2fe78bSCy Schubert     if (!isflagset(enc_tkt_reply->flags, TKT_FLG_ANONYMOUS)) {
604*7f2fe78bSCy Schubert         for (i = 0; i < n_authdata_modules; i++) {
605*7f2fe78bSCy Schubert             h = &authdata_modules[i];
606*7f2fe78bSCy Schubert             ret = h->vt.handle(context, h->data, flags, client, server,
607*7f2fe78bSCy Schubert                                subject_server, client_key, server_key,
608*7f2fe78bSCy Schubert                                subject_key, req_pkt, req, altcprinc,
609*7f2fe78bSCy Schubert                                enc_tkt_req, enc_tkt_reply);
610*7f2fe78bSCy Schubert             if (ret)
611*7f2fe78bSCy Schubert                 kdc_err(context, ret, "from authdata module %s", h->vt.name);
612*7f2fe78bSCy Schubert         }
613*7f2fe78bSCy Schubert     }
614*7f2fe78bSCy Schubert 
615*7f2fe78bSCy Schubert     if (req->msg_type == KRB5_TGS_REQ) {
616*7f2fe78bSCy Schubert         /* Copy authdata from the TGT to the issued ticket. */
617*7f2fe78bSCy Schubert         ret = copy_tgt_authdata(context, req, enc_tkt_req->authorization_data,
618*7f2fe78bSCy Schubert                                 &enc_tkt_reply->authorization_data);
619*7f2fe78bSCy Schubert         if (ret)
620*7f2fe78bSCy Schubert             return ret;
621*7f2fe78bSCy Schubert     }
622*7f2fe78bSCy Schubert 
623*7f2fe78bSCy Schubert     return handle_pac(realm, flags, client, server, subject_server, local_tgt,
624*7f2fe78bSCy Schubert                       local_tgt_key, server_key, subject_key,
625*7f2fe78bSCy Schubert                       replaced_reply_key, enc_tkt_req, subject_pac, req,
626*7f2fe78bSCy Schubert                       altcprinc, enc_tkt_reply->times.authtime, enc_tkt_reply,
627*7f2fe78bSCy Schubert                       auth_indicators);
628*7f2fe78bSCy Schubert }
629