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