xref: /freebsd/crypto/krb5/src/kdc/kdc_util.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* kdc/kdc_util.c - Utility functions for the KDC implementation */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright 1990,1991,2007,2008,2009 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert  * All Rights Reserved.
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  * Copyright (c) 2006-2008, Novell, Inc.
28*7f2fe78bSCy Schubert  * All rights reserved.
29*7f2fe78bSCy Schubert  *
30*7f2fe78bSCy Schubert  * Redistribution and use in source and binary forms, with or without
31*7f2fe78bSCy Schubert  * modification, are permitted provided that the following conditions are met:
32*7f2fe78bSCy Schubert  *
33*7f2fe78bSCy Schubert  *   * Redistributions of source code must retain the above copyright notice,
34*7f2fe78bSCy Schubert  *       this list of conditions and the following disclaimer.
35*7f2fe78bSCy Schubert  *   * Redistributions in binary form must reproduce the above copyright
36*7f2fe78bSCy Schubert  *       notice, this list of conditions and the following disclaimer in the
37*7f2fe78bSCy Schubert  *       documentation and/or other materials provided with the distribution.
38*7f2fe78bSCy Schubert  *   * The copyright holder's name is not used to endorse or promote products
39*7f2fe78bSCy Schubert  *       derived from this software without specific prior written permission.
40*7f2fe78bSCy Schubert  *
41*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
42*7f2fe78bSCy Schubert  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43*7f2fe78bSCy Schubert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44*7f2fe78bSCy Schubert  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
45*7f2fe78bSCy Schubert  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
46*7f2fe78bSCy Schubert  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
47*7f2fe78bSCy Schubert  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
48*7f2fe78bSCy Schubert  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
49*7f2fe78bSCy Schubert  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50*7f2fe78bSCy Schubert  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
51*7f2fe78bSCy Schubert  * POSSIBILITY OF SUCH DAMAGE.
52*7f2fe78bSCy Schubert  */
53*7f2fe78bSCy Schubert 
54*7f2fe78bSCy Schubert #include "k5-int.h"
55*7f2fe78bSCy Schubert #include "kdc_util.h"
56*7f2fe78bSCy Schubert #include "extern.h"
57*7f2fe78bSCy Schubert #include <stdio.h>
58*7f2fe78bSCy Schubert #include <ctype.h>
59*7f2fe78bSCy Schubert #include <syslog.h>
60*7f2fe78bSCy Schubert #include <kadm5/admin.h>
61*7f2fe78bSCy Schubert #include "adm_proto.h"
62*7f2fe78bSCy Schubert #include "net-server.h"
63*7f2fe78bSCy Schubert #include <limits.h>
64*7f2fe78bSCy Schubert 
65*7f2fe78bSCy Schubert #ifdef KRBCONF_VAGUE_ERRORS
66*7f2fe78bSCy Schubert const int vague_errors = 1;
67*7f2fe78bSCy Schubert #else
68*7f2fe78bSCy Schubert const int vague_errors = 0;
69*7f2fe78bSCy Schubert #endif
70*7f2fe78bSCy Schubert 
71*7f2fe78bSCy Schubert static krb5_error_code kdc_rd_ap_req(kdc_realm_t *realm, krb5_ap_req *apreq,
72*7f2fe78bSCy Schubert                                      krb5_auth_context auth_context,
73*7f2fe78bSCy Schubert                                      krb5_db_entry **server,
74*7f2fe78bSCy Schubert                                      krb5_keyblock **tgskey);
75*7f2fe78bSCy Schubert static krb5_error_code find_server_key(krb5_context,
76*7f2fe78bSCy Schubert                                        krb5_db_entry *, krb5_enctype,
77*7f2fe78bSCy Schubert                                        krb5_kvno, krb5_keyblock **,
78*7f2fe78bSCy Schubert                                        krb5_kvno *);
79*7f2fe78bSCy Schubert 
80*7f2fe78bSCy Schubert /*
81*7f2fe78bSCy Schubert  * Returns TRUE if the kerberos principal is the name of a Kerberos ticket
82*7f2fe78bSCy Schubert  * service.
83*7f2fe78bSCy Schubert  */
84*7f2fe78bSCy Schubert krb5_boolean
krb5_is_tgs_principal(krb5_const_principal principal)85*7f2fe78bSCy Schubert krb5_is_tgs_principal(krb5_const_principal principal)
86*7f2fe78bSCy Schubert {
87*7f2fe78bSCy Schubert     if (krb5_princ_size(kdc_context, principal) != 2)
88*7f2fe78bSCy Schubert         return FALSE;
89*7f2fe78bSCy Schubert     if (data_eq_string(*krb5_princ_component(kdc_context, principal, 0),
90*7f2fe78bSCy Schubert                        KRB5_TGS_NAME))
91*7f2fe78bSCy Schubert         return TRUE;
92*7f2fe78bSCy Schubert     else
93*7f2fe78bSCy Schubert         return FALSE;
94*7f2fe78bSCy Schubert }
95*7f2fe78bSCy Schubert 
96*7f2fe78bSCy Schubert /* Returns TRUE if principal is the name of a cross-realm TGS. */
97*7f2fe78bSCy Schubert krb5_boolean
is_cross_tgs_principal(krb5_const_principal principal)98*7f2fe78bSCy Schubert is_cross_tgs_principal(krb5_const_principal principal)
99*7f2fe78bSCy Schubert {
100*7f2fe78bSCy Schubert     return krb5_is_tgs_principal(principal) &&
101*7f2fe78bSCy Schubert         !data_eq(principal->data[1], principal->realm);
102*7f2fe78bSCy Schubert }
103*7f2fe78bSCy Schubert 
104*7f2fe78bSCy Schubert /* Return true if princ is the name of a local TGS for any realm. */
105*7f2fe78bSCy Schubert krb5_boolean
is_local_tgs_principal(krb5_const_principal principal)106*7f2fe78bSCy Schubert is_local_tgs_principal(krb5_const_principal principal)
107*7f2fe78bSCy Schubert {
108*7f2fe78bSCy Schubert     return krb5_is_tgs_principal(principal) &&
109*7f2fe78bSCy Schubert         data_eq(principal->data[1], principal->realm);
110*7f2fe78bSCy Schubert }
111*7f2fe78bSCy Schubert 
112*7f2fe78bSCy Schubert /*
113*7f2fe78bSCy Schubert  * given authentication data (provides seed for checksum), verify checksum
114*7f2fe78bSCy Schubert  * for source data.
115*7f2fe78bSCy Schubert  */
116*7f2fe78bSCy Schubert static krb5_error_code
comp_cksum(krb5_context kcontext,krb5_data * source,krb5_ticket * ticket,krb5_checksum * his_cksum)117*7f2fe78bSCy Schubert comp_cksum(krb5_context kcontext, krb5_data *source, krb5_ticket *ticket,
118*7f2fe78bSCy Schubert            krb5_checksum *his_cksum)
119*7f2fe78bSCy Schubert {
120*7f2fe78bSCy Schubert     krb5_error_code       retval;
121*7f2fe78bSCy Schubert     krb5_boolean          valid;
122*7f2fe78bSCy Schubert 
123*7f2fe78bSCy Schubert     if (!krb5_c_valid_cksumtype(his_cksum->checksum_type))
124*7f2fe78bSCy Schubert         return KRB5KDC_ERR_SUMTYPE_NOSUPP;
125*7f2fe78bSCy Schubert 
126*7f2fe78bSCy Schubert     /* must be collision proof */
127*7f2fe78bSCy Schubert     if (!krb5_c_is_coll_proof_cksum(his_cksum->checksum_type))
128*7f2fe78bSCy Schubert         return KRB5KRB_AP_ERR_INAPP_CKSUM;
129*7f2fe78bSCy Schubert 
130*7f2fe78bSCy Schubert     /* verify checksum */
131*7f2fe78bSCy Schubert     if ((retval = krb5_c_verify_checksum(kcontext, ticket->enc_part2->session,
132*7f2fe78bSCy Schubert                                          KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
133*7f2fe78bSCy Schubert                                          source, his_cksum, &valid)))
134*7f2fe78bSCy Schubert         return(retval);
135*7f2fe78bSCy Schubert 
136*7f2fe78bSCy Schubert     if (!valid)
137*7f2fe78bSCy Schubert         return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
138*7f2fe78bSCy Schubert 
139*7f2fe78bSCy Schubert     return(0);
140*7f2fe78bSCy Schubert }
141*7f2fe78bSCy Schubert 
142*7f2fe78bSCy Schubert /* If a header ticket is decrypted, *ticket_out is filled in even on error. */
143*7f2fe78bSCy Schubert krb5_error_code
kdc_process_tgs_req(kdc_realm_t * realm,krb5_kdc_req * request,const krb5_fulladdr * from,krb5_data * pkt,krb5_ticket ** ticket_out,krb5_db_entry ** krbtgt_ptr,krb5_keyblock ** tgskey,krb5_keyblock ** subkey,krb5_pa_data ** pa_tgs_req)144*7f2fe78bSCy Schubert kdc_process_tgs_req(kdc_realm_t *realm, krb5_kdc_req *request,
145*7f2fe78bSCy Schubert                     const krb5_fulladdr *from, krb5_data *pkt,
146*7f2fe78bSCy Schubert                     krb5_ticket **ticket_out, krb5_db_entry **krbtgt_ptr,
147*7f2fe78bSCy Schubert                     krb5_keyblock **tgskey, krb5_keyblock **subkey,
148*7f2fe78bSCy Schubert                     krb5_pa_data **pa_tgs_req)
149*7f2fe78bSCy Schubert {
150*7f2fe78bSCy Schubert     krb5_context context = realm->realm_context;
151*7f2fe78bSCy Schubert     krb5_pa_data        * tmppa;
152*7f2fe78bSCy Schubert     krb5_ap_req         * apreq;
153*7f2fe78bSCy Schubert     krb5_error_code       retval;
154*7f2fe78bSCy Schubert     krb5_authdata **authdata = NULL;
155*7f2fe78bSCy Schubert     krb5_data             scratch1;
156*7f2fe78bSCy Schubert     krb5_data           * scratch = NULL;
157*7f2fe78bSCy Schubert     krb5_auth_context     auth_context = NULL;
158*7f2fe78bSCy Schubert     krb5_authenticator  * authenticator = NULL;
159*7f2fe78bSCy Schubert     krb5_checksum       * his_cksum = NULL;
160*7f2fe78bSCy Schubert     krb5_db_entry       * krbtgt = NULL;
161*7f2fe78bSCy Schubert     krb5_ticket         * ticket;
162*7f2fe78bSCy Schubert 
163*7f2fe78bSCy Schubert     *ticket_out = NULL;
164*7f2fe78bSCy Schubert     *krbtgt_ptr = NULL;
165*7f2fe78bSCy Schubert     *tgskey = NULL;
166*7f2fe78bSCy Schubert 
167*7f2fe78bSCy Schubert     tmppa = krb5int_find_pa_data(context, request->padata, KRB5_PADATA_AP_REQ);
168*7f2fe78bSCy Schubert     if (!tmppa)
169*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
170*7f2fe78bSCy Schubert 
171*7f2fe78bSCy Schubert     scratch1.length = tmppa->length;
172*7f2fe78bSCy Schubert     scratch1.data = (char *)tmppa->contents;
173*7f2fe78bSCy Schubert     if ((retval = decode_krb5_ap_req(&scratch1, &apreq)))
174*7f2fe78bSCy Schubert         return retval;
175*7f2fe78bSCy Schubert     ticket = apreq->ticket;
176*7f2fe78bSCy Schubert 
177*7f2fe78bSCy Schubert     if (isflagset(apreq->ap_options, AP_OPTS_USE_SESSION_KEY) ||
178*7f2fe78bSCy Schubert         isflagset(apreq->ap_options, AP_OPTS_MUTUAL_REQUIRED)) {
179*7f2fe78bSCy Schubert         krb5_klog_syslog(LOG_INFO, _("TGS_REQ: SESSION KEY or MUTUAL"));
180*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_POLICY;
181*7f2fe78bSCy Schubert         goto cleanup;
182*7f2fe78bSCy Schubert     }
183*7f2fe78bSCy Schubert 
184*7f2fe78bSCy Schubert     retval = krb5_auth_con_init(context, &auth_context);
185*7f2fe78bSCy Schubert     if (retval)
186*7f2fe78bSCy Schubert         goto cleanup;
187*7f2fe78bSCy Schubert 
188*7f2fe78bSCy Schubert     /* Don't use a replay cache. */
189*7f2fe78bSCy Schubert     retval = krb5_auth_con_setflags(context, auth_context, 0);
190*7f2fe78bSCy Schubert     if (retval)
191*7f2fe78bSCy Schubert         goto cleanup;
192*7f2fe78bSCy Schubert 
193*7f2fe78bSCy Schubert     retval = krb5_auth_con_setaddrs(context, auth_context, NULL,
194*7f2fe78bSCy Schubert                                     from->address);
195*7f2fe78bSCy Schubert     if (retval)
196*7f2fe78bSCy Schubert         goto cleanup_auth_context;
197*7f2fe78bSCy Schubert 
198*7f2fe78bSCy Schubert     retval = kdc_rd_ap_req(realm, apreq, auth_context, &krbtgt, tgskey);
199*7f2fe78bSCy Schubert     if (retval)
200*7f2fe78bSCy Schubert         goto cleanup_auth_context;
201*7f2fe78bSCy Schubert 
202*7f2fe78bSCy Schubert     retval = krb5_auth_con_getrecvsubkey(context, auth_context, subkey);
203*7f2fe78bSCy Schubert     if (retval)
204*7f2fe78bSCy Schubert         goto cleanup_auth_context;
205*7f2fe78bSCy Schubert 
206*7f2fe78bSCy Schubert     retval = krb5_auth_con_getauthenticator(context, auth_context,
207*7f2fe78bSCy Schubert                                             &authenticator);
208*7f2fe78bSCy Schubert     if (retval)
209*7f2fe78bSCy Schubert         goto cleanup_auth_context;
210*7f2fe78bSCy Schubert 
211*7f2fe78bSCy Schubert     retval = krb5_find_authdata(context, ticket->enc_part2->authorization_data,
212*7f2fe78bSCy Schubert                                 authenticator->authorization_data,
213*7f2fe78bSCy Schubert                                 KRB5_AUTHDATA_FX_ARMOR, &authdata);
214*7f2fe78bSCy Schubert     if (retval != 0)
215*7f2fe78bSCy Schubert         goto cleanup_authenticator;
216*7f2fe78bSCy Schubert     if (authdata&& authdata[0]) {
217*7f2fe78bSCy Schubert         k5_setmsg(context, KRB5KDC_ERR_POLICY,
218*7f2fe78bSCy Schubert                   "ticket valid only as FAST armor");
219*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_POLICY;
220*7f2fe78bSCy Schubert         krb5_free_authdata(context, authdata);
221*7f2fe78bSCy Schubert         goto cleanup_authenticator;
222*7f2fe78bSCy Schubert     }
223*7f2fe78bSCy Schubert     krb5_free_authdata(context, authdata);
224*7f2fe78bSCy Schubert 
225*7f2fe78bSCy Schubert 
226*7f2fe78bSCy Schubert     /* Check for a checksum */
227*7f2fe78bSCy Schubert     if (!(his_cksum = authenticator->checksum)) {
228*7f2fe78bSCy Schubert         retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
229*7f2fe78bSCy Schubert         goto cleanup_authenticator;
230*7f2fe78bSCy Schubert     }
231*7f2fe78bSCy Schubert 
232*7f2fe78bSCy Schubert     /*
233*7f2fe78bSCy Schubert      * Check application checksum vs. tgs request
234*7f2fe78bSCy Schubert      *
235*7f2fe78bSCy Schubert      * We try checksumming the req-body two different ways: first we
236*7f2fe78bSCy Schubert      * try reaching into the raw asn.1 stream (if available), and
237*7f2fe78bSCy Schubert      * checksum that directly; if that fails, then we try encoding
238*7f2fe78bSCy Schubert      * using our local asn.1 library.
239*7f2fe78bSCy Schubert      */
240*7f2fe78bSCy Schubert     if (pkt && (fetch_asn1_field((unsigned char *) pkt->data,
241*7f2fe78bSCy Schubert                                  1, 4, &scratch1) >= 0)) {
242*7f2fe78bSCy Schubert         if (comp_cksum(context, &scratch1, ticket, his_cksum)) {
243*7f2fe78bSCy Schubert             if (!(retval = encode_krb5_kdc_req_body(request, &scratch)))
244*7f2fe78bSCy Schubert                 retval = comp_cksum(context, scratch, ticket, his_cksum);
245*7f2fe78bSCy Schubert             krb5_free_data(context, scratch);
246*7f2fe78bSCy Schubert             if (retval)
247*7f2fe78bSCy Schubert                 goto cleanup_authenticator;
248*7f2fe78bSCy Schubert         }
249*7f2fe78bSCy Schubert     }
250*7f2fe78bSCy Schubert 
251*7f2fe78bSCy Schubert     *pa_tgs_req = tmppa;
252*7f2fe78bSCy Schubert     *krbtgt_ptr = krbtgt;
253*7f2fe78bSCy Schubert     krbtgt = NULL;
254*7f2fe78bSCy Schubert 
255*7f2fe78bSCy Schubert cleanup_authenticator:
256*7f2fe78bSCy Schubert     krb5_free_authenticator(context, authenticator);
257*7f2fe78bSCy Schubert 
258*7f2fe78bSCy Schubert cleanup_auth_context:
259*7f2fe78bSCy Schubert     krb5_auth_con_free(context, auth_context);
260*7f2fe78bSCy Schubert 
261*7f2fe78bSCy Schubert cleanup:
262*7f2fe78bSCy Schubert     if (retval != 0) {
263*7f2fe78bSCy Schubert         krb5_free_keyblock(context, *tgskey);
264*7f2fe78bSCy Schubert         *tgskey = NULL;
265*7f2fe78bSCy Schubert     }
266*7f2fe78bSCy Schubert     if (apreq->ticket->enc_part2 != NULL) {
267*7f2fe78bSCy Schubert         /* Steal the decrypted ticket pointer, even on error. */
268*7f2fe78bSCy Schubert         *ticket_out = apreq->ticket;
269*7f2fe78bSCy Schubert         apreq->ticket = NULL;
270*7f2fe78bSCy Schubert     }
271*7f2fe78bSCy Schubert     krb5_free_ap_req(context, apreq);
272*7f2fe78bSCy Schubert     krb5_db_free_principal(context, krbtgt);
273*7f2fe78bSCy Schubert     return retval;
274*7f2fe78bSCy Schubert }
275*7f2fe78bSCy Schubert 
276*7f2fe78bSCy Schubert /*
277*7f2fe78bSCy Schubert  * This is a KDC wrapper around krb5_rd_req_decoded_anyflag().
278*7f2fe78bSCy Schubert  *
279*7f2fe78bSCy Schubert  * We can't depend on KDB-as-keytab for handling the AP-REQ here for
280*7f2fe78bSCy Schubert  * optimization reasons: we want to minimize the number of KDB lookups.  We'll
281*7f2fe78bSCy Schubert  * need the KDB entry for the TGS principal, and the TGS key used to decrypt
282*7f2fe78bSCy Schubert  * the TGT, elsewhere in the TGS code.
283*7f2fe78bSCy Schubert  *
284*7f2fe78bSCy Schubert  * This function also implements key rollover support for kvno 0 cross-realm
285*7f2fe78bSCy Schubert  * TGTs issued by AD.
286*7f2fe78bSCy Schubert  */
287*7f2fe78bSCy Schubert static
288*7f2fe78bSCy Schubert krb5_error_code
kdc_rd_ap_req(kdc_realm_t * realm,krb5_ap_req * apreq,krb5_auth_context auth_context,krb5_db_entry ** server,krb5_keyblock ** tgskey)289*7f2fe78bSCy Schubert kdc_rd_ap_req(kdc_realm_t *realm, krb5_ap_req *apreq,
290*7f2fe78bSCy Schubert               krb5_auth_context auth_context, krb5_db_entry **server,
291*7f2fe78bSCy Schubert               krb5_keyblock **tgskey)
292*7f2fe78bSCy Schubert {
293*7f2fe78bSCy Schubert     krb5_context context = realm->realm_context;
294*7f2fe78bSCy Schubert     krb5_error_code     retval;
295*7f2fe78bSCy Schubert     krb5_enctype        search_enctype = apreq->ticket->enc_part.enctype;
296*7f2fe78bSCy Schubert     krb5_boolean        match_enctype = 1;
297*7f2fe78bSCy Schubert     krb5_kvno           kvno;
298*7f2fe78bSCy Schubert     size_t              tries = 3;
299*7f2fe78bSCy Schubert 
300*7f2fe78bSCy Schubert     /*
301*7f2fe78bSCy Schubert      * When we issue tickets we use the first key in the principals' highest
302*7f2fe78bSCy Schubert      * kvno keyset.  For non-cross-realm krbtgt principals we want to only
303*7f2fe78bSCy Schubert      * allow the use of the first key of the principal's keyset that matches
304*7f2fe78bSCy Schubert      * the given kvno.
305*7f2fe78bSCy Schubert      */
306*7f2fe78bSCy Schubert     if (krb5_is_tgs_principal(apreq->ticket->server) &&
307*7f2fe78bSCy Schubert         !is_cross_tgs_principal(apreq->ticket->server)) {
308*7f2fe78bSCy Schubert         search_enctype = -1;
309*7f2fe78bSCy Schubert         match_enctype = 0;
310*7f2fe78bSCy Schubert     }
311*7f2fe78bSCy Schubert 
312*7f2fe78bSCy Schubert     retval = kdc_get_server_key(context, apreq->ticket, 0, match_enctype,
313*7f2fe78bSCy Schubert                                 server, NULL, NULL);
314*7f2fe78bSCy Schubert     if (retval)
315*7f2fe78bSCy Schubert         return retval;
316*7f2fe78bSCy Schubert 
317*7f2fe78bSCy Schubert     *tgskey = NULL;
318*7f2fe78bSCy Schubert     kvno = apreq->ticket->enc_part.kvno;
319*7f2fe78bSCy Schubert     do {
320*7f2fe78bSCy Schubert         krb5_free_keyblock(context, *tgskey);
321*7f2fe78bSCy Schubert         retval = find_server_key(context, *server, search_enctype, kvno,
322*7f2fe78bSCy Schubert                                  tgskey, &kvno);
323*7f2fe78bSCy Schubert         if (retval)
324*7f2fe78bSCy Schubert             continue;
325*7f2fe78bSCy Schubert 
326*7f2fe78bSCy Schubert         /* Make the TGS key available to krb5_rd_req_decoded_anyflag() */
327*7f2fe78bSCy Schubert         retval = krb5_auth_con_setuseruserkey(context, auth_context, *tgskey);
328*7f2fe78bSCy Schubert         if (retval)
329*7f2fe78bSCy Schubert             return retval;
330*7f2fe78bSCy Schubert 
331*7f2fe78bSCy Schubert         retval = krb5_rd_req_decoded_anyflag(context, &auth_context, apreq,
332*7f2fe78bSCy Schubert                                              apreq->ticket->server,
333*7f2fe78bSCy Schubert                                              realm->realm_keytab, NULL, NULL);
334*7f2fe78bSCy Schubert 
335*7f2fe78bSCy Schubert         /* If the ticket was decrypted, don't try any more keys. */
336*7f2fe78bSCy Schubert         if (apreq->ticket->enc_part2 != NULL)
337*7f2fe78bSCy Schubert             break;
338*7f2fe78bSCy Schubert 
339*7f2fe78bSCy Schubert     } while (retval && apreq->ticket->enc_part.kvno == 0 && kvno-- > 1 &&
340*7f2fe78bSCy Schubert              --tries > 0);
341*7f2fe78bSCy Schubert 
342*7f2fe78bSCy Schubert     return retval;
343*7f2fe78bSCy Schubert }
344*7f2fe78bSCy Schubert 
345*7f2fe78bSCy Schubert /*
346*7f2fe78bSCy Schubert  * The KDC should take the keytab associated with the realm and pass
347*7f2fe78bSCy Schubert  * that to the krb5_rd_req_decoded_anyflag(), but we still need to use
348*7f2fe78bSCy Schubert  * the service (TGS, here) key elsewhere.  This approach is faster than
349*7f2fe78bSCy Schubert  * the KDB keytab approach too.
350*7f2fe78bSCy Schubert  *
351*7f2fe78bSCy Schubert  * This is also used by do_tgs_req() for u2u auth.
352*7f2fe78bSCy Schubert  */
353*7f2fe78bSCy Schubert krb5_error_code
kdc_get_server_key(krb5_context context,krb5_ticket * ticket,unsigned int flags,krb5_boolean match_enctype,krb5_db_entry ** server_ptr,krb5_keyblock ** key,krb5_kvno * kvno)354*7f2fe78bSCy Schubert kdc_get_server_key(krb5_context context,
355*7f2fe78bSCy Schubert                    krb5_ticket *ticket, unsigned int flags,
356*7f2fe78bSCy Schubert                    krb5_boolean match_enctype, krb5_db_entry **server_ptr,
357*7f2fe78bSCy Schubert                    krb5_keyblock **key, krb5_kvno *kvno)
358*7f2fe78bSCy Schubert {
359*7f2fe78bSCy Schubert     krb5_error_code       retval;
360*7f2fe78bSCy Schubert     krb5_db_entry       * server = NULL;
361*7f2fe78bSCy Schubert     krb5_enctype          search_enctype = -1;
362*7f2fe78bSCy Schubert     krb5_kvno             search_kvno = -1;
363*7f2fe78bSCy Schubert 
364*7f2fe78bSCy Schubert     if (match_enctype)
365*7f2fe78bSCy Schubert         search_enctype = ticket->enc_part.enctype;
366*7f2fe78bSCy Schubert     if (ticket->enc_part.kvno)
367*7f2fe78bSCy Schubert         search_kvno = ticket->enc_part.kvno;
368*7f2fe78bSCy Schubert 
369*7f2fe78bSCy Schubert     *server_ptr = NULL;
370*7f2fe78bSCy Schubert 
371*7f2fe78bSCy Schubert     retval = krb5_db_get_principal(context, ticket->server, flags,
372*7f2fe78bSCy Schubert                                    &server);
373*7f2fe78bSCy Schubert     if (retval == KRB5_KDB_NOENTRY) {
374*7f2fe78bSCy Schubert         char *sname;
375*7f2fe78bSCy Schubert         if (!krb5_unparse_name(context, ticket->server, &sname)) {
376*7f2fe78bSCy Schubert             limit_string(sname);
377*7f2fe78bSCy Schubert             krb5_klog_syslog(LOG_ERR,
378*7f2fe78bSCy Schubert                              _("TGS_REQ: UNKNOWN SERVER: server='%s'"), sname);
379*7f2fe78bSCy Schubert             free(sname);
380*7f2fe78bSCy Schubert         }
381*7f2fe78bSCy Schubert         return KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
382*7f2fe78bSCy Schubert     } else if (retval)
383*7f2fe78bSCy Schubert         return retval;
384*7f2fe78bSCy Schubert     if (server->attributes & KRB5_KDB_DISALLOW_SVR ||
385*7f2fe78bSCy Schubert         server->attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
386*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
387*7f2fe78bSCy Schubert         goto errout;
388*7f2fe78bSCy Schubert     }
389*7f2fe78bSCy Schubert 
390*7f2fe78bSCy Schubert     if (key) {
391*7f2fe78bSCy Schubert         retval = find_server_key(context, server, search_enctype, search_kvno,
392*7f2fe78bSCy Schubert                                  key, kvno);
393*7f2fe78bSCy Schubert         if (retval)
394*7f2fe78bSCy Schubert             goto errout;
395*7f2fe78bSCy Schubert     }
396*7f2fe78bSCy Schubert     *server_ptr = server;
397*7f2fe78bSCy Schubert     server = NULL;
398*7f2fe78bSCy Schubert     return 0;
399*7f2fe78bSCy Schubert 
400*7f2fe78bSCy Schubert errout:
401*7f2fe78bSCy Schubert     krb5_db_free_principal(context, server);
402*7f2fe78bSCy Schubert     return retval;
403*7f2fe78bSCy Schubert }
404*7f2fe78bSCy Schubert 
405*7f2fe78bSCy Schubert /*
406*7f2fe78bSCy Schubert  * A utility function to get the right key from a KDB entry.  Used in handling
407*7f2fe78bSCy Schubert  * of kvno 0 TGTs, for example.
408*7f2fe78bSCy Schubert  */
409*7f2fe78bSCy Schubert static
410*7f2fe78bSCy Schubert krb5_error_code
find_server_key(krb5_context context,krb5_db_entry * server,krb5_enctype enctype,krb5_kvno kvno,krb5_keyblock ** key_out,krb5_kvno * kvno_out)411*7f2fe78bSCy Schubert find_server_key(krb5_context context,
412*7f2fe78bSCy Schubert                 krb5_db_entry *server, krb5_enctype enctype, krb5_kvno kvno,
413*7f2fe78bSCy Schubert                 krb5_keyblock **key_out, krb5_kvno *kvno_out)
414*7f2fe78bSCy Schubert {
415*7f2fe78bSCy Schubert     krb5_error_code       retval;
416*7f2fe78bSCy Schubert     krb5_key_data       * server_key;
417*7f2fe78bSCy Schubert     krb5_keyblock       * key;
418*7f2fe78bSCy Schubert 
419*7f2fe78bSCy Schubert     *key_out = NULL;
420*7f2fe78bSCy Schubert     retval = krb5_dbe_find_enctype(context, server, enctype, -1,
421*7f2fe78bSCy Schubert                                    kvno ? (krb5_int32)kvno : -1, &server_key);
422*7f2fe78bSCy Schubert     if (retval)
423*7f2fe78bSCy Schubert         return retval;
424*7f2fe78bSCy Schubert     if (!server_key)
425*7f2fe78bSCy Schubert         return KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
426*7f2fe78bSCy Schubert     if ((key = (krb5_keyblock *)malloc(sizeof *key)) == NULL)
427*7f2fe78bSCy Schubert         return ENOMEM;
428*7f2fe78bSCy Schubert     retval = krb5_dbe_decrypt_key_data(context, NULL, server_key,
429*7f2fe78bSCy Schubert                                        key, NULL);
430*7f2fe78bSCy Schubert     if (retval)
431*7f2fe78bSCy Schubert         goto errout;
432*7f2fe78bSCy Schubert     if (enctype != -1) {
433*7f2fe78bSCy Schubert         krb5_boolean similar;
434*7f2fe78bSCy Schubert         retval = krb5_c_enctype_compare(context, enctype, key->enctype,
435*7f2fe78bSCy Schubert                                         &similar);
436*7f2fe78bSCy Schubert         if (retval)
437*7f2fe78bSCy Schubert             goto errout;
438*7f2fe78bSCy Schubert         if (!similar) {
439*7f2fe78bSCy Schubert             retval = KRB5_KDB_NO_PERMITTED_KEY;
440*7f2fe78bSCy Schubert             goto errout;
441*7f2fe78bSCy Schubert         }
442*7f2fe78bSCy Schubert         key->enctype = enctype;
443*7f2fe78bSCy Schubert     }
444*7f2fe78bSCy Schubert     *key_out = key;
445*7f2fe78bSCy Schubert     key = NULL;
446*7f2fe78bSCy Schubert     if (kvno_out)
447*7f2fe78bSCy Schubert         *kvno_out = server_key->key_data_kvno;
448*7f2fe78bSCy Schubert errout:
449*7f2fe78bSCy Schubert     krb5_free_keyblock(context, key);
450*7f2fe78bSCy Schubert     return retval;
451*7f2fe78bSCy Schubert }
452*7f2fe78bSCy Schubert 
453*7f2fe78bSCy Schubert /* Find the first key data entry (of a valid enctype) of the highest kvno in
454*7f2fe78bSCy Schubert  * entry, and decrypt it into *key_out. */
455*7f2fe78bSCy Schubert krb5_error_code
get_first_current_key(krb5_context context,krb5_db_entry * entry,krb5_keyblock * key_out)456*7f2fe78bSCy Schubert get_first_current_key(krb5_context context, krb5_db_entry *entry,
457*7f2fe78bSCy Schubert                       krb5_keyblock *key_out)
458*7f2fe78bSCy Schubert {
459*7f2fe78bSCy Schubert     krb5_error_code ret;
460*7f2fe78bSCy Schubert     krb5_key_data *kd;
461*7f2fe78bSCy Schubert 
462*7f2fe78bSCy Schubert     memset(key_out, 0, sizeof(*key_out));
463*7f2fe78bSCy Schubert     ret = krb5_dbe_find_enctype(context, entry, -1, -1, 0, &kd);
464*7f2fe78bSCy Schubert     if (ret)
465*7f2fe78bSCy Schubert         return ret;
466*7f2fe78bSCy Schubert     return krb5_dbe_decrypt_key_data(context, NULL, kd, key_out, NULL);
467*7f2fe78bSCy Schubert }
468*7f2fe78bSCy Schubert 
469*7f2fe78bSCy Schubert /*
470*7f2fe78bSCy Schubert  * If candidate is the local TGT for realm, set *alias_out to candidate and
471*7f2fe78bSCy Schubert  * *storage_out to NULL.  Otherwise, load the local TGT into *storage_out and
472*7f2fe78bSCy Schubert  * set *alias_out to *storage_out.  In either case, set *key_out to the
473*7f2fe78bSCy Schubert  * decrypted first key of the local TGT.
474*7f2fe78bSCy Schubert  *
475*7f2fe78bSCy Schubert  * In the future we might generalize this to a small per-request principal
476*7f2fe78bSCy Schubert  * cache.  For now, it saves a load operation in the common case where the AS
477*7f2fe78bSCy Schubert  * server or TGS header ticket server is the local TGT.
478*7f2fe78bSCy Schubert  */
479*7f2fe78bSCy Schubert krb5_error_code
get_local_tgt(krb5_context context,const krb5_data * realm,krb5_db_entry * candidate,krb5_db_entry ** alias_out,krb5_db_entry ** storage_out,krb5_keyblock * key_out)480*7f2fe78bSCy Schubert get_local_tgt(krb5_context context, const krb5_data *realm,
481*7f2fe78bSCy Schubert               krb5_db_entry *candidate, krb5_db_entry **alias_out,
482*7f2fe78bSCy Schubert               krb5_db_entry **storage_out, krb5_keyblock *key_out)
483*7f2fe78bSCy Schubert {
484*7f2fe78bSCy Schubert     krb5_error_code ret;
485*7f2fe78bSCy Schubert     krb5_principal princ;
486*7f2fe78bSCy Schubert     krb5_db_entry *storage = NULL, *tgt;
487*7f2fe78bSCy Schubert 
488*7f2fe78bSCy Schubert     *alias_out = NULL;
489*7f2fe78bSCy Schubert     *storage_out = NULL;
490*7f2fe78bSCy Schubert     memset(key_out, 0, sizeof(*key_out));
491*7f2fe78bSCy Schubert 
492*7f2fe78bSCy Schubert     ret = krb5_build_principal_ext(context, &princ, realm->length, realm->data,
493*7f2fe78bSCy Schubert                                    KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
494*7f2fe78bSCy Schubert                                    realm->length, realm->data, 0);
495*7f2fe78bSCy Schubert     if (ret)
496*7f2fe78bSCy Schubert         goto cleanup;
497*7f2fe78bSCy Schubert 
498*7f2fe78bSCy Schubert     if (!krb5_principal_compare(context, candidate->princ, princ)) {
499*7f2fe78bSCy Schubert         ret = krb5_db_get_principal(context, princ, 0, &storage);
500*7f2fe78bSCy Schubert         if (ret)
501*7f2fe78bSCy Schubert             goto cleanup;
502*7f2fe78bSCy Schubert         tgt = storage;
503*7f2fe78bSCy Schubert     } else {
504*7f2fe78bSCy Schubert         tgt = candidate;
505*7f2fe78bSCy Schubert     }
506*7f2fe78bSCy Schubert 
507*7f2fe78bSCy Schubert     ret = get_first_current_key(context, tgt, key_out);
508*7f2fe78bSCy Schubert     if (ret)
509*7f2fe78bSCy Schubert         goto cleanup;
510*7f2fe78bSCy Schubert 
511*7f2fe78bSCy Schubert     *alias_out = tgt;
512*7f2fe78bSCy Schubert     *storage_out = storage;
513*7f2fe78bSCy Schubert     storage = NULL;
514*7f2fe78bSCy Schubert 
515*7f2fe78bSCy Schubert cleanup:
516*7f2fe78bSCy Schubert     krb5_db_free_principal(context, storage);
517*7f2fe78bSCy Schubert     krb5_free_principal(context, princ);
518*7f2fe78bSCy Schubert     return ret;
519*7f2fe78bSCy Schubert }
520*7f2fe78bSCy Schubert 
521*7f2fe78bSCy Schubert /* If server has a pac_privsvr_enctype attribute and it differs from tgt_key's
522*7f2fe78bSCy Schubert  * enctype, derive a key of the specified enctype.  Otherwise copy tgt_key. */
523*7f2fe78bSCy Schubert krb5_error_code
pac_privsvr_key(krb5_context context,krb5_db_entry * server,const krb5_keyblock * tgt_key,krb5_keyblock ** key_out)524*7f2fe78bSCy Schubert pac_privsvr_key(krb5_context context, krb5_db_entry *server,
525*7f2fe78bSCy Schubert                 const krb5_keyblock *tgt_key, krb5_keyblock **key_out)
526*7f2fe78bSCy Schubert {
527*7f2fe78bSCy Schubert     krb5_error_code ret;
528*7f2fe78bSCy Schubert     char *attrval = NULL;
529*7f2fe78bSCy Schubert     krb5_enctype privsvr_enctype;
530*7f2fe78bSCy Schubert     krb5_data prf_input = string2data("pac_privsvr");
531*7f2fe78bSCy Schubert 
532*7f2fe78bSCy Schubert     ret = krb5_dbe_get_string(context, server, KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE,
533*7f2fe78bSCy Schubert                               &attrval);
534*7f2fe78bSCy Schubert     if (ret)
535*7f2fe78bSCy Schubert         return ret;
536*7f2fe78bSCy Schubert     if (attrval == NULL)
537*7f2fe78bSCy Schubert         return krb5_copy_keyblock(context, tgt_key, key_out);
538*7f2fe78bSCy Schubert 
539*7f2fe78bSCy Schubert     ret = krb5_string_to_enctype(attrval, &privsvr_enctype);
540*7f2fe78bSCy Schubert     if (ret) {
541*7f2fe78bSCy Schubert         k5_setmsg(context, ret, _("Invalid pac_privsvr_enctype value %s"),
542*7f2fe78bSCy Schubert                   attrval);
543*7f2fe78bSCy Schubert         goto cleanup;
544*7f2fe78bSCy Schubert     }
545*7f2fe78bSCy Schubert 
546*7f2fe78bSCy Schubert     if (tgt_key->enctype == privsvr_enctype) {
547*7f2fe78bSCy Schubert         ret = krb5_copy_keyblock(context, tgt_key, key_out);
548*7f2fe78bSCy Schubert     } else {
549*7f2fe78bSCy Schubert         ret = krb5_c_derive_prfplus(context, tgt_key, &prf_input,
550*7f2fe78bSCy Schubert                                     privsvr_enctype, key_out);
551*7f2fe78bSCy Schubert     }
552*7f2fe78bSCy Schubert 
553*7f2fe78bSCy Schubert cleanup:
554*7f2fe78bSCy Schubert     krb5_dbe_free_string(context, attrval);
555*7f2fe78bSCy Schubert     return ret;
556*7f2fe78bSCy Schubert }
557*7f2fe78bSCy Schubert 
558*7f2fe78bSCy Schubert /* Try verifying a ticket's PAC using a privsvr key either equal to or derived
559*7f2fe78bSCy Schubert  * from tgt_key, respecting the server's pac_privsvr_enctype value if set. */
560*7f2fe78bSCy Schubert static krb5_error_code
try_verify_pac(krb5_context context,const krb5_enc_tkt_part * enc_tkt,krb5_db_entry * server,krb5_keyblock * server_key,const krb5_keyblock * tgt_key,krb5_pac * pac_out)561*7f2fe78bSCy Schubert try_verify_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
562*7f2fe78bSCy Schubert                krb5_db_entry *server, krb5_keyblock *server_key,
563*7f2fe78bSCy Schubert                const krb5_keyblock *tgt_key, krb5_pac *pac_out)
564*7f2fe78bSCy Schubert {
565*7f2fe78bSCy Schubert     krb5_error_code ret;
566*7f2fe78bSCy Schubert     krb5_keyblock *privsvr_key;
567*7f2fe78bSCy Schubert 
568*7f2fe78bSCy Schubert     ret = pac_privsvr_key(context, server, tgt_key, &privsvr_key);
569*7f2fe78bSCy Schubert     if (ret)
570*7f2fe78bSCy Schubert         return ret;
571*7f2fe78bSCy Schubert     ret = krb5_kdc_verify_ticket(context, enc_tkt, server->princ, server_key,
572*7f2fe78bSCy Schubert                                  privsvr_key, pac_out);
573*7f2fe78bSCy Schubert     krb5_free_keyblock(context, privsvr_key);
574*7f2fe78bSCy Schubert     return ret;
575*7f2fe78bSCy Schubert }
576*7f2fe78bSCy Schubert 
577*7f2fe78bSCy Schubert /*
578*7f2fe78bSCy Schubert  * If a PAC is present in enc_tkt, verify it and place it in *pac_out.  sprinc
579*7f2fe78bSCy Schubert  * is the canonical name of the server principal entry used to decrypt enc_tkt.
580*7f2fe78bSCy Schubert  * server_key is the ticket decryption key.  tgt is the local krbtgt entry for
581*7f2fe78bSCy Schubert  * the ticket server realm, and tgt_key is its first key.
582*7f2fe78bSCy Schubert  */
583*7f2fe78bSCy Schubert krb5_error_code
get_verified_pac(krb5_context context,const krb5_enc_tkt_part * enc_tkt,krb5_db_entry * server,krb5_keyblock * server_key,krb5_db_entry * tgt,krb5_keyblock * tgt_key,krb5_pac * pac_out)584*7f2fe78bSCy Schubert get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
585*7f2fe78bSCy Schubert                  krb5_db_entry *server, krb5_keyblock *server_key,
586*7f2fe78bSCy Schubert                  krb5_db_entry *tgt, krb5_keyblock *tgt_key, krb5_pac *pac_out)
587*7f2fe78bSCy Schubert {
588*7f2fe78bSCy Schubert     krb5_error_code ret;
589*7f2fe78bSCy Schubert     krb5_key_data *kd;
590*7f2fe78bSCy Schubert     krb5_keyblock old_key;
591*7f2fe78bSCy Schubert     krb5_kvno kvno;
592*7f2fe78bSCy Schubert     int tries;
593*7f2fe78bSCy Schubert 
594*7f2fe78bSCy Schubert     *pac_out = NULL;
595*7f2fe78bSCy Schubert 
596*7f2fe78bSCy Schubert     /* For local or cross-realm TGTs we only check the server signature. */
597*7f2fe78bSCy Schubert     if (krb5_is_tgs_principal(server->princ)) {
598*7f2fe78bSCy Schubert         return krb5_kdc_verify_ticket(context, enc_tkt, server->princ,
599*7f2fe78bSCy Schubert                                       server_key, NULL, pac_out);
600*7f2fe78bSCy Schubert     }
601*7f2fe78bSCy Schubert 
602*7f2fe78bSCy Schubert     ret = try_verify_pac(context, enc_tkt, server, server_key, tgt_key,
603*7f2fe78bSCy Schubert                          pac_out);
604*7f2fe78bSCy Schubert     if (ret != KRB5KRB_AP_ERR_MODIFIED && ret != KRB5_BAD_ENCTYPE)
605*7f2fe78bSCy Schubert         return ret;
606*7f2fe78bSCy Schubert 
607*7f2fe78bSCy Schubert     /* There is no kvno in PAC signatures, so try two previous versions. */
608*7f2fe78bSCy Schubert     kvno = tgt->key_data[0].key_data_kvno - 1;
609*7f2fe78bSCy Schubert     for (tries = 2; tries > 0 && kvno > 0; tries--, kvno--) {
610*7f2fe78bSCy Schubert         ret = krb5_dbe_find_enctype(context, tgt, -1, -1, kvno, &kd);
611*7f2fe78bSCy Schubert         if (ret)
612*7f2fe78bSCy Schubert             return KRB5KRB_AP_ERR_MODIFIED;
613*7f2fe78bSCy Schubert         ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &old_key, NULL);
614*7f2fe78bSCy Schubert         if (ret)
615*7f2fe78bSCy Schubert             return ret;
616*7f2fe78bSCy Schubert         ret = try_verify_pac(context, enc_tkt, server, server_key, &old_key,
617*7f2fe78bSCy Schubert                              pac_out);
618*7f2fe78bSCy Schubert         krb5_free_keyblock_contents(context, &old_key);
619*7f2fe78bSCy Schubert         if (!ret)
620*7f2fe78bSCy Schubert             return 0;
621*7f2fe78bSCy Schubert     }
622*7f2fe78bSCy Schubert 
623*7f2fe78bSCy Schubert     return KRB5KRB_AP_ERR_MODIFIED;
624*7f2fe78bSCy Schubert }
625*7f2fe78bSCy Schubert 
626*7f2fe78bSCy Schubert /*
627*7f2fe78bSCy Schubert  * Fetch the client info from pac and parse it into a principal name, expecting
628*7f2fe78bSCy Schubert  * a realm in the string.  Set *authtime_out to the client info authtime if it
629*7f2fe78bSCy Schubert  * is not null.
630*7f2fe78bSCy Schubert  */
631*7f2fe78bSCy Schubert krb5_error_code
get_pac_princ_with_realm(krb5_context context,krb5_pac pac,krb5_principal * princ_out,krb5_timestamp * authtime_out)632*7f2fe78bSCy Schubert get_pac_princ_with_realm(krb5_context context, krb5_pac pac,
633*7f2fe78bSCy Schubert                          krb5_principal *princ_out,
634*7f2fe78bSCy Schubert                          krb5_timestamp *authtime_out)
635*7f2fe78bSCy Schubert {
636*7f2fe78bSCy Schubert     krb5_error_code ret;
637*7f2fe78bSCy Schubert     int n_atsigns, flags = KRB5_PRINCIPAL_PARSE_REQUIRE_REALM;
638*7f2fe78bSCy Schubert     char *client_str = NULL;
639*7f2fe78bSCy Schubert     const char *p;
640*7f2fe78bSCy Schubert 
641*7f2fe78bSCy Schubert     *princ_out = NULL;
642*7f2fe78bSCy Schubert 
643*7f2fe78bSCy Schubert     ret = krb5_pac_get_client_info(context, pac, authtime_out, &client_str);
644*7f2fe78bSCy Schubert     if (ret)
645*7f2fe78bSCy Schubert         return ret;
646*7f2fe78bSCy Schubert 
647*7f2fe78bSCy Schubert     n_atsigns = 0;
648*7f2fe78bSCy Schubert     for (p = client_str; *p != '\0'; p++) {
649*7f2fe78bSCy Schubert         if (*p == '@')
650*7f2fe78bSCy Schubert             n_atsigns++;
651*7f2fe78bSCy Schubert     }
652*7f2fe78bSCy Schubert 
653*7f2fe78bSCy Schubert     if (n_atsigns == 2) {
654*7f2fe78bSCy Schubert         flags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
655*7f2fe78bSCy Schubert     } else if (n_atsigns != 1) {
656*7f2fe78bSCy Schubert         ret = KRB5_PARSE_MALFORMED;
657*7f2fe78bSCy Schubert         goto cleanup;
658*7f2fe78bSCy Schubert     }
659*7f2fe78bSCy Schubert 
660*7f2fe78bSCy Schubert     ret = krb5_parse_name_flags(context, client_str, flags, princ_out);
661*7f2fe78bSCy Schubert     if (ret)
662*7f2fe78bSCy Schubert         return ret;
663*7f2fe78bSCy Schubert 
664*7f2fe78bSCy Schubert     (*princ_out)->type = KRB5_NT_MS_PRINCIPAL;
665*7f2fe78bSCy Schubert 
666*7f2fe78bSCy Schubert cleanup:
667*7f2fe78bSCy Schubert     free(client_str);
668*7f2fe78bSCy Schubert     return 0;
669*7f2fe78bSCy Schubert }
670*7f2fe78bSCy Schubert 
671*7f2fe78bSCy Schubert /* This probably wants to be updated if you support last_req stuff */
672*7f2fe78bSCy Schubert 
673*7f2fe78bSCy Schubert static krb5_last_req_entry nolrentry = { KV5M_LAST_REQ_ENTRY, KRB5_LRQ_NONE, 0 };
674*7f2fe78bSCy Schubert static krb5_last_req_entry *nolrarray[] = { &nolrentry, 0 };
675*7f2fe78bSCy Schubert 
676*7f2fe78bSCy Schubert krb5_error_code
fetch_last_req_info(krb5_db_entry * dbentry,krb5_last_req_entry *** lrentry)677*7f2fe78bSCy Schubert fetch_last_req_info(krb5_db_entry *dbentry, krb5_last_req_entry ***lrentry)
678*7f2fe78bSCy Schubert {
679*7f2fe78bSCy Schubert     *lrentry = nolrarray;
680*7f2fe78bSCy Schubert     return 0;
681*7f2fe78bSCy Schubert }
682*7f2fe78bSCy Schubert 
683*7f2fe78bSCy Schubert 
684*7f2fe78bSCy Schubert /* Convert an API error code to a protocol error code. */
685*7f2fe78bSCy Schubert int
errcode_to_protocol(krb5_error_code code)686*7f2fe78bSCy Schubert errcode_to_protocol(krb5_error_code code)
687*7f2fe78bSCy Schubert {
688*7f2fe78bSCy Schubert     int protcode;
689*7f2fe78bSCy Schubert 
690*7f2fe78bSCy Schubert     protcode = code - ERROR_TABLE_BASE_krb5;
691*7f2fe78bSCy Schubert     return (protcode >= 0 && protcode <= 128) ? protcode : KRB_ERR_GENERIC;
692*7f2fe78bSCy Schubert }
693*7f2fe78bSCy Schubert 
694*7f2fe78bSCy Schubert /* Return -1 if the AS or TGS request is disallowed due to KDC policy on
695*7f2fe78bSCy Schubert  * anonymous tickets. */
696*7f2fe78bSCy Schubert int
check_anon(kdc_realm_t * realm,krb5_principal client,krb5_principal server)697*7f2fe78bSCy Schubert check_anon(kdc_realm_t *realm, krb5_principal client, krb5_principal server)
698*7f2fe78bSCy Schubert {
699*7f2fe78bSCy Schubert     /* If restrict_anon is set, reject requests from anonymous clients to
700*7f2fe78bSCy Schubert      * server principals other than local TGTs. */
701*7f2fe78bSCy Schubert     if (realm->realm_restrict_anon &&
702*7f2fe78bSCy Schubert         krb5_principal_compare_any_realm(realm->realm_context, client,
703*7f2fe78bSCy Schubert                                          krb5_anonymous_principal()) &&
704*7f2fe78bSCy Schubert         !is_local_tgs_principal(server))
705*7f2fe78bSCy Schubert         return -1;
706*7f2fe78bSCy Schubert     return 0;
707*7f2fe78bSCy Schubert }
708*7f2fe78bSCy Schubert 
709*7f2fe78bSCy Schubert krb5_error_code
validate_as_request(kdc_realm_t * realm,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,krb5_timestamp kdc_time,const char ** status,krb5_pa_data *** e_data)710*7f2fe78bSCy Schubert validate_as_request(kdc_realm_t *realm, krb5_kdc_req *request,
711*7f2fe78bSCy Schubert                     krb5_db_entry *client, krb5_db_entry *server,
712*7f2fe78bSCy Schubert                     krb5_timestamp kdc_time, const char **status,
713*7f2fe78bSCy Schubert                     krb5_pa_data ***e_data)
714*7f2fe78bSCy Schubert {
715*7f2fe78bSCy Schubert     krb5_context context = realm->realm_context;
716*7f2fe78bSCy Schubert     krb5_error_code ret;
717*7f2fe78bSCy Schubert 
718*7f2fe78bSCy Schubert     /*
719*7f2fe78bSCy Schubert      * If an option is set that is only allowed in TGS requests, complain.
720*7f2fe78bSCy Schubert      */
721*7f2fe78bSCy Schubert     if (request->kdc_options & AS_INVALID_OPTIONS) {
722*7f2fe78bSCy Schubert         *status = "INVALID AS OPTIONS";
723*7f2fe78bSCy Schubert         return KRB5KDC_ERR_BADOPTION;
724*7f2fe78bSCy Schubert     }
725*7f2fe78bSCy Schubert 
726*7f2fe78bSCy Schubert     /* The client must not be expired */
727*7f2fe78bSCy Schubert     if (client->expiration && ts_after(kdc_time, client->expiration)) {
728*7f2fe78bSCy Schubert         *status = "CLIENT EXPIRED";
729*7f2fe78bSCy Schubert         if (vague_errors)
730*7f2fe78bSCy Schubert             return KRB5KRB_ERR_GENERIC;
731*7f2fe78bSCy Schubert         else
732*7f2fe78bSCy Schubert             return KRB5KDC_ERR_NAME_EXP;
733*7f2fe78bSCy Schubert     }
734*7f2fe78bSCy Schubert 
735*7f2fe78bSCy Schubert     /* The client's password must not be expired, unless the server is
736*7f2fe78bSCy Schubert        a KRB5_KDC_PWCHANGE_SERVICE. */
737*7f2fe78bSCy Schubert     if (client->pw_expiration && ts_after(kdc_time, client->pw_expiration) &&
738*7f2fe78bSCy Schubert         !isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
739*7f2fe78bSCy Schubert         *status = "CLIENT KEY EXPIRED";
740*7f2fe78bSCy Schubert         if (vague_errors)
741*7f2fe78bSCy Schubert             return KRB5KRB_ERR_GENERIC;
742*7f2fe78bSCy Schubert         else
743*7f2fe78bSCy Schubert             return KRB5KDC_ERR_KEY_EXP;
744*7f2fe78bSCy Schubert     }
745*7f2fe78bSCy Schubert 
746*7f2fe78bSCy Schubert     /* The server must not be expired */
747*7f2fe78bSCy Schubert     if (server->expiration && ts_after(kdc_time, server->expiration)) {
748*7f2fe78bSCy Schubert         *status = "SERVICE EXPIRED";
749*7f2fe78bSCy Schubert         return KRB5KDC_ERR_SERVICE_EXP;
750*7f2fe78bSCy Schubert     }
751*7f2fe78bSCy Schubert 
752*7f2fe78bSCy Schubert     /*
753*7f2fe78bSCy Schubert      * If the client requires password changing, then only allow the
754*7f2fe78bSCy Schubert      * pwchange service.
755*7f2fe78bSCy Schubert      */
756*7f2fe78bSCy Schubert     if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PWCHANGE) &&
757*7f2fe78bSCy Schubert         !isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
758*7f2fe78bSCy Schubert         *status = "REQUIRED PWCHANGE";
759*7f2fe78bSCy Schubert         return KRB5KDC_ERR_KEY_EXP;
760*7f2fe78bSCy Schubert     }
761*7f2fe78bSCy Schubert 
762*7f2fe78bSCy Schubert     /* Client and server must allow postdating tickets */
763*7f2fe78bSCy Schubert     if ((isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE) ||
764*7f2fe78bSCy Schubert          isflagset(request->kdc_options, KDC_OPT_POSTDATED)) &&
765*7f2fe78bSCy Schubert         (isflagset(client->attributes, KRB5_KDB_DISALLOW_POSTDATED) ||
766*7f2fe78bSCy Schubert          isflagset(server->attributes, KRB5_KDB_DISALLOW_POSTDATED))) {
767*7f2fe78bSCy Schubert         *status = "POSTDATE NOT ALLOWED";
768*7f2fe78bSCy Schubert         return KRB5KDC_ERR_CANNOT_POSTDATE;
769*7f2fe78bSCy Schubert     }
770*7f2fe78bSCy Schubert 
771*7f2fe78bSCy Schubert     /* Check to see if client is locked out */
772*7f2fe78bSCy Schubert     if (isflagset(client->attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
773*7f2fe78bSCy Schubert         *status = "CLIENT LOCKED OUT";
774*7f2fe78bSCy Schubert         return KRB5KDC_ERR_CLIENT_REVOKED;
775*7f2fe78bSCy Schubert     }
776*7f2fe78bSCy Schubert 
777*7f2fe78bSCy Schubert     /* Check to see if server is locked out */
778*7f2fe78bSCy Schubert     if (isflagset(server->attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
779*7f2fe78bSCy Schubert         *status = "SERVICE LOCKED OUT";
780*7f2fe78bSCy Schubert         return KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
781*7f2fe78bSCy Schubert     }
782*7f2fe78bSCy Schubert 
783*7f2fe78bSCy Schubert     /* Check to see if server is allowed to be a service */
784*7f2fe78bSCy Schubert     if (isflagset(server->attributes, KRB5_KDB_DISALLOW_SVR)) {
785*7f2fe78bSCy Schubert         *status = "SERVICE NOT ALLOWED";
786*7f2fe78bSCy Schubert         return KRB5KDC_ERR_MUST_USE_USER2USER;
787*7f2fe78bSCy Schubert     }
788*7f2fe78bSCy Schubert 
789*7f2fe78bSCy Schubert     if (check_anon(realm, client->princ, request->server) != 0) {
790*7f2fe78bSCy Schubert         *status = "ANONYMOUS NOT ALLOWED";
791*7f2fe78bSCy Schubert         return KRB5KDC_ERR_POLICY;
792*7f2fe78bSCy Schubert     }
793*7f2fe78bSCy Schubert 
794*7f2fe78bSCy Schubert     /* Perform KDB module policy checks. */
795*7f2fe78bSCy Schubert     ret = krb5_db_check_policy_as(context, request, client, server, kdc_time,
796*7f2fe78bSCy Schubert                                   status, e_data);
797*7f2fe78bSCy Schubert     return (ret == KRB5_PLUGIN_OP_NOTSUPP) ? 0 : ret;
798*7f2fe78bSCy Schubert }
799*7f2fe78bSCy Schubert 
800*7f2fe78bSCy Schubert /*
801*7f2fe78bSCy Schubert  * Compute ticket flags based on the request, the client and server DB entry
802*7f2fe78bSCy Schubert  * (which may prohibit forwardable or proxiable tickets), and the header
803*7f2fe78bSCy Schubert  * ticket.  client may be NULL for a TGS request (although it may be set, such
804*7f2fe78bSCy Schubert  * as for an S4U2Self request).  header_enc may be NULL for an AS request.
805*7f2fe78bSCy Schubert  */
806*7f2fe78bSCy Schubert krb5_flags
get_ticket_flags(krb5_flags reqflags,krb5_db_entry * client,krb5_db_entry * server,krb5_enc_tkt_part * header_enc)807*7f2fe78bSCy Schubert get_ticket_flags(krb5_flags reqflags, krb5_db_entry *client,
808*7f2fe78bSCy Schubert                  krb5_db_entry *server, krb5_enc_tkt_part *header_enc)
809*7f2fe78bSCy Schubert {
810*7f2fe78bSCy Schubert     krb5_flags flags;
811*7f2fe78bSCy Schubert 
812*7f2fe78bSCy Schubert     /* Validation and renewal TGS requests preserve the header ticket flags. */
813*7f2fe78bSCy Schubert     if ((reqflags & (KDC_OPT_VALIDATE | KDC_OPT_RENEW)) && header_enc != NULL)
814*7f2fe78bSCy Schubert         return header_enc->flags & ~TKT_FLG_INVALID;
815*7f2fe78bSCy Schubert 
816*7f2fe78bSCy Schubert     /* Indicate support for encrypted padata (RFC 6806), and set flags based on
817*7f2fe78bSCy Schubert      * request options and the header ticket. */
818*7f2fe78bSCy Schubert     flags = OPTS2FLAGS(reqflags) | TKT_FLG_ENC_PA_REP;
819*7f2fe78bSCy Schubert     if (reqflags & KDC_OPT_POSTDATED)
820*7f2fe78bSCy Schubert         flags |= TKT_FLG_INVALID;
821*7f2fe78bSCy Schubert     if (header_enc != NULL)
822*7f2fe78bSCy Schubert         flags |= COPY_TKT_FLAGS(header_enc->flags);
823*7f2fe78bSCy Schubert     if (header_enc == NULL)
824*7f2fe78bSCy Schubert         flags |= TKT_FLG_INITIAL;
825*7f2fe78bSCy Schubert 
826*7f2fe78bSCy Schubert     /* For TGS requests, indicate if the service is marked ok-as-delegate. */
827*7f2fe78bSCy Schubert     if (header_enc != NULL && (server->attributes & KRB5_KDB_OK_AS_DELEGATE))
828*7f2fe78bSCy Schubert         flags |= TKT_FLG_OK_AS_DELEGATE;
829*7f2fe78bSCy Schubert 
830*7f2fe78bSCy Schubert     /* Unset PROXIABLE if it is disallowed. */
831*7f2fe78bSCy Schubert     if (client != NULL && (client->attributes & KRB5_KDB_DISALLOW_PROXIABLE))
832*7f2fe78bSCy Schubert         flags &= ~TKT_FLG_PROXIABLE;
833*7f2fe78bSCy Schubert     if (server->attributes & KRB5_KDB_DISALLOW_PROXIABLE)
834*7f2fe78bSCy Schubert         flags &= ~TKT_FLG_PROXIABLE;
835*7f2fe78bSCy Schubert     if (header_enc != NULL && !(header_enc->flags & TKT_FLG_PROXIABLE))
836*7f2fe78bSCy Schubert         flags &= ~TKT_FLG_PROXIABLE;
837*7f2fe78bSCy Schubert 
838*7f2fe78bSCy Schubert     /* Unset FORWARDABLE if it is disallowed. */
839*7f2fe78bSCy Schubert     if (client != NULL && (client->attributes & KRB5_KDB_DISALLOW_FORWARDABLE))
840*7f2fe78bSCy Schubert         flags &= ~TKT_FLG_FORWARDABLE;
841*7f2fe78bSCy Schubert     if (server->attributes & KRB5_KDB_DISALLOW_FORWARDABLE)
842*7f2fe78bSCy Schubert         flags &= ~TKT_FLG_FORWARDABLE;
843*7f2fe78bSCy Schubert     if (header_enc != NULL && !(header_enc->flags & TKT_FLG_FORWARDABLE))
844*7f2fe78bSCy Schubert         flags &= ~TKT_FLG_FORWARDABLE;
845*7f2fe78bSCy Schubert 
846*7f2fe78bSCy Schubert     /* We don't currently handle issuing anonymous tickets based on
847*7f2fe78bSCy Schubert      * non-anonymous ones. */
848*7f2fe78bSCy Schubert     if (header_enc != NULL && !(header_enc->flags & TKT_FLG_ANONYMOUS))
849*7f2fe78bSCy Schubert         flags &= ~TKT_FLG_ANONYMOUS;
850*7f2fe78bSCy Schubert 
851*7f2fe78bSCy Schubert     return flags;
852*7f2fe78bSCy Schubert }
853*7f2fe78bSCy Schubert 
854*7f2fe78bSCy Schubert /* Return KRB5KDC_ERR_POLICY if indicators does not contain the required auth
855*7f2fe78bSCy Schubert  * indicators for server, ENOMEM on allocation error, 0 otherwise. */
856*7f2fe78bSCy Schubert krb5_error_code
check_indicators(krb5_context context,krb5_db_entry * server,krb5_data * const * indicators)857*7f2fe78bSCy Schubert check_indicators(krb5_context context, krb5_db_entry *server,
858*7f2fe78bSCy Schubert                  krb5_data *const *indicators)
859*7f2fe78bSCy Schubert {
860*7f2fe78bSCy Schubert     krb5_error_code ret;
861*7f2fe78bSCy Schubert     char *str = NULL, *copy = NULL, *save, *ind;
862*7f2fe78bSCy Schubert 
863*7f2fe78bSCy Schubert     ret = krb5_dbe_get_string(context, server, KRB5_KDB_SK_REQUIRE_AUTH, &str);
864*7f2fe78bSCy Schubert     if (ret || str == NULL)
865*7f2fe78bSCy Schubert         goto cleanup;
866*7f2fe78bSCy Schubert     copy = strdup(str);
867*7f2fe78bSCy Schubert     if (copy == NULL) {
868*7f2fe78bSCy Schubert         ret = ENOMEM;
869*7f2fe78bSCy Schubert         goto cleanup;
870*7f2fe78bSCy Schubert     }
871*7f2fe78bSCy Schubert 
872*7f2fe78bSCy Schubert     /* Look for any of the space-separated strings in indicators. */
873*7f2fe78bSCy Schubert     ind = strtok_r(copy, " ", &save);
874*7f2fe78bSCy Schubert     while (ind != NULL) {
875*7f2fe78bSCy Schubert         if (authind_contains(indicators, ind))
876*7f2fe78bSCy Schubert             goto cleanup;
877*7f2fe78bSCy Schubert         ind = strtok_r(NULL, " ", &save);
878*7f2fe78bSCy Schubert     }
879*7f2fe78bSCy Schubert 
880*7f2fe78bSCy Schubert     ret = KRB5KDC_ERR_POLICY;
881*7f2fe78bSCy Schubert     k5_setmsg(context, ret,
882*7f2fe78bSCy Schubert               _("Required auth indicators not present in ticket: %s"), str);
883*7f2fe78bSCy Schubert 
884*7f2fe78bSCy Schubert cleanup:
885*7f2fe78bSCy Schubert     krb5_dbe_free_string(context, str);
886*7f2fe78bSCy Schubert     free(copy);
887*7f2fe78bSCy Schubert     return ret;
888*7f2fe78bSCy Schubert }
889*7f2fe78bSCy Schubert 
890*7f2fe78bSCy Schubert #define ASN1_ID_CLASS   (0xc0)
891*7f2fe78bSCy Schubert #define ASN1_ID_TYPE    (0x20)
892*7f2fe78bSCy Schubert #define ASN1_ID_TAG     (0x1f)
893*7f2fe78bSCy Schubert #define ASN1_CLASS_UNIV (0)
894*7f2fe78bSCy Schubert #define ASN1_CLASS_APP  (1)
895*7f2fe78bSCy Schubert #define ASN1_CLASS_CTX  (2)
896*7f2fe78bSCy Schubert #define ASN1_CLASS_PRIV (3)
897*7f2fe78bSCy Schubert #define asn1_id_constructed(x)  (x & ASN1_ID_TYPE)
898*7f2fe78bSCy Schubert #define asn1_id_primitive(x)    (!asn1_id_constructed(x))
899*7f2fe78bSCy Schubert #define asn1_id_class(x)        ((x & ASN1_ID_CLASS) >> 6)
900*7f2fe78bSCy Schubert #define asn1_id_tag(x)          (x & ASN1_ID_TAG)
901*7f2fe78bSCy Schubert 
902*7f2fe78bSCy Schubert /*
903*7f2fe78bSCy Schubert  * asn1length - return encoded length of value.
904*7f2fe78bSCy Schubert  *
905*7f2fe78bSCy Schubert  * passed a pointer into the asn.1 stream, which is updated
906*7f2fe78bSCy Schubert  * to point right after the length bits.
907*7f2fe78bSCy Schubert  *
908*7f2fe78bSCy Schubert  * returns -1 on failure.
909*7f2fe78bSCy Schubert  */
910*7f2fe78bSCy Schubert static int
asn1length(unsigned char ** astream)911*7f2fe78bSCy Schubert asn1length(unsigned char **astream)
912*7f2fe78bSCy Schubert {
913*7f2fe78bSCy Schubert     int length;         /* resulting length */
914*7f2fe78bSCy Schubert     int sublen;         /* sublengths */
915*7f2fe78bSCy Schubert     int blen;           /* bytes of length */
916*7f2fe78bSCy Schubert     unsigned char *p;   /* substring searching */
917*7f2fe78bSCy Schubert 
918*7f2fe78bSCy Schubert     if (**astream & 0x80) {
919*7f2fe78bSCy Schubert         blen = **astream & 0x7f;
920*7f2fe78bSCy Schubert         if (blen > 3) {
921*7f2fe78bSCy Schubert             return(-1);
922*7f2fe78bSCy Schubert         }
923*7f2fe78bSCy Schubert         for (++*astream, length = 0; blen; ++*astream, blen--) {
924*7f2fe78bSCy Schubert             length = (length << 8) | **astream;
925*7f2fe78bSCy Schubert         }
926*7f2fe78bSCy Schubert         if (length == 0) {
927*7f2fe78bSCy Schubert             /* indefinite length, figure out by hand */
928*7f2fe78bSCy Schubert             p = *astream;
929*7f2fe78bSCy Schubert             p++;
930*7f2fe78bSCy Schubert             while (1) {
931*7f2fe78bSCy Schubert                 /* compute value length. */
932*7f2fe78bSCy Schubert                 if ((sublen = asn1length(&p)) < 0) {
933*7f2fe78bSCy Schubert                     return(-1);
934*7f2fe78bSCy Schubert                 }
935*7f2fe78bSCy Schubert                 p += sublen;
936*7f2fe78bSCy Schubert                 /* check for termination */
937*7f2fe78bSCy Schubert                 if ((!*p++) && (!*p)) {
938*7f2fe78bSCy Schubert                     p++;
939*7f2fe78bSCy Schubert                     break;
940*7f2fe78bSCy Schubert                 }
941*7f2fe78bSCy Schubert             }
942*7f2fe78bSCy Schubert             length = p - *astream;
943*7f2fe78bSCy Schubert         }
944*7f2fe78bSCy Schubert     } else {
945*7f2fe78bSCy Schubert         length = **astream;
946*7f2fe78bSCy Schubert         ++*astream;
947*7f2fe78bSCy Schubert     }
948*7f2fe78bSCy Schubert     return(length);
949*7f2fe78bSCy Schubert }
950*7f2fe78bSCy Schubert 
951*7f2fe78bSCy Schubert /*
952*7f2fe78bSCy Schubert  * fetch_asn1_field - return raw asn.1 stream of subfield.
953*7f2fe78bSCy Schubert  *
954*7f2fe78bSCy Schubert  * this routine is passed a context-dependent tag number and "level" and returns
955*7f2fe78bSCy Schubert  * the size and length of the corresponding level subfield.
956*7f2fe78bSCy Schubert  *
957*7f2fe78bSCy Schubert  * levels and are numbered starting from 1.
958*7f2fe78bSCy Schubert  *
959*7f2fe78bSCy Schubert  * returns 0 on success, -1 otherwise.
960*7f2fe78bSCy Schubert  */
961*7f2fe78bSCy Schubert int
fetch_asn1_field(unsigned char * astream,unsigned int level,unsigned int field,krb5_data * data)962*7f2fe78bSCy Schubert fetch_asn1_field(unsigned char *astream, unsigned int level,
963*7f2fe78bSCy Schubert                  unsigned int field, krb5_data *data)
964*7f2fe78bSCy Schubert {
965*7f2fe78bSCy Schubert     unsigned char *estream;     /* end of stream */
966*7f2fe78bSCy Schubert     int classes;                /* # classes seen so far this level */
967*7f2fe78bSCy Schubert     unsigned int levels = 0;            /* levels seen so far */
968*7f2fe78bSCy Schubert     int lastlevel = 1000;       /* last level seen */
969*7f2fe78bSCy Schubert     int length;                 /* various lengths */
970*7f2fe78bSCy Schubert     int tag;                    /* tag number */
971*7f2fe78bSCy Schubert     unsigned char savelen;      /* saved length of our field */
972*7f2fe78bSCy Schubert 
973*7f2fe78bSCy Schubert     classes = -1;
974*7f2fe78bSCy Schubert     /* we assume that the first identifier/length will tell us
975*7f2fe78bSCy Schubert        how long the entire stream is. */
976*7f2fe78bSCy Schubert     astream++;
977*7f2fe78bSCy Schubert     estream = astream;
978*7f2fe78bSCy Schubert     if ((length = asn1length(&astream)) < 0) {
979*7f2fe78bSCy Schubert         return(-1);
980*7f2fe78bSCy Schubert     }
981*7f2fe78bSCy Schubert     estream += length;
982*7f2fe78bSCy Schubert     /* search down the stream, checking identifiers.  we process identifiers
983*7f2fe78bSCy Schubert        until we hit the "level" we want, and then process that level for our
984*7f2fe78bSCy Schubert        subfield, always making sure we don't go off the end of the stream.  */
985*7f2fe78bSCy Schubert     while (astream < estream) {
986*7f2fe78bSCy Schubert         if (!asn1_id_constructed(*astream)) {
987*7f2fe78bSCy Schubert             return(-1);
988*7f2fe78bSCy Schubert         }
989*7f2fe78bSCy Schubert         if (asn1_id_class(*astream) == ASN1_CLASS_CTX) {
990*7f2fe78bSCy Schubert             if ((tag = (int)asn1_id_tag(*astream)) <= lastlevel) {
991*7f2fe78bSCy Schubert                 levels++;
992*7f2fe78bSCy Schubert                 classes = -1;
993*7f2fe78bSCy Schubert             }
994*7f2fe78bSCy Schubert             lastlevel = tag;
995*7f2fe78bSCy Schubert             if (levels == level) {
996*7f2fe78bSCy Schubert                 /* in our context-dependent class, is this the one we're looking for ? */
997*7f2fe78bSCy Schubert                 if (tag == (int)field) {
998*7f2fe78bSCy Schubert                     /* return length and data */
999*7f2fe78bSCy Schubert                     astream++;
1000*7f2fe78bSCy Schubert                     savelen = *astream;
1001*7f2fe78bSCy Schubert                     if ((length = asn1length(&astream)) < 0) {
1002*7f2fe78bSCy Schubert                         return(-1);
1003*7f2fe78bSCy Schubert                     }
1004*7f2fe78bSCy Schubert                     data->length = length;
1005*7f2fe78bSCy Schubert                     /* if the field length is indefinite, we will have to subtract two
1006*7f2fe78bSCy Schubert                        (terminating octets) from the length returned since we don't want
1007*7f2fe78bSCy Schubert                        to pass any info from the "wrapper" back.  asn1length will always return
1008*7f2fe78bSCy Schubert                        the *total* length of the field, not just what's contained in it */
1009*7f2fe78bSCy Schubert                     if ((savelen & 0xff) == 0x80) {
1010*7f2fe78bSCy Schubert                         data->length -=2 ;
1011*7f2fe78bSCy Schubert                     }
1012*7f2fe78bSCy Schubert                     data->data = (char *)astream;
1013*7f2fe78bSCy Schubert                     return(0);
1014*7f2fe78bSCy Schubert                 } else if (tag <= classes) {
1015*7f2fe78bSCy Schubert                     /* we've seen this class before, something must be wrong */
1016*7f2fe78bSCy Schubert                     return(-1);
1017*7f2fe78bSCy Schubert                 } else {
1018*7f2fe78bSCy Schubert                     classes = tag;
1019*7f2fe78bSCy Schubert                 }
1020*7f2fe78bSCy Schubert             }
1021*7f2fe78bSCy Schubert         }
1022*7f2fe78bSCy Schubert         /* if we're not on our level yet, process this value.  otherwise skip over it */
1023*7f2fe78bSCy Schubert         astream++;
1024*7f2fe78bSCy Schubert         if ((length = asn1length(&astream)) < 0) {
1025*7f2fe78bSCy Schubert             return(-1);
1026*7f2fe78bSCy Schubert         }
1027*7f2fe78bSCy Schubert         if (levels == level) {
1028*7f2fe78bSCy Schubert             astream += length;
1029*7f2fe78bSCy Schubert         }
1030*7f2fe78bSCy Schubert     }
1031*7f2fe78bSCy Schubert     return(-1);
1032*7f2fe78bSCy Schubert }
1033*7f2fe78bSCy Schubert 
1034*7f2fe78bSCy Schubert /* Return true if we believe server can support enctype as a session key. */
1035*7f2fe78bSCy Schubert static krb5_boolean
dbentry_supports_enctype(krb5_context context,krb5_db_entry * server,krb5_enctype enctype)1036*7f2fe78bSCy Schubert dbentry_supports_enctype(krb5_context context, krb5_db_entry *server,
1037*7f2fe78bSCy Schubert                          krb5_enctype enctype)
1038*7f2fe78bSCy Schubert {
1039*7f2fe78bSCy Schubert     krb5_error_code     retval;
1040*7f2fe78bSCy Schubert     krb5_key_data       *datap;
1041*7f2fe78bSCy Schubert     char                *etypes_str = NULL;
1042*7f2fe78bSCy Schubert     krb5_enctype        default_enctypes[1] = { 0 };
1043*7f2fe78bSCy Schubert     krb5_enctype        *etypes = NULL;
1044*7f2fe78bSCy Schubert     krb5_boolean        in_list;
1045*7f2fe78bSCy Schubert 
1046*7f2fe78bSCy Schubert     /* Look up the supported session key enctypes list in the KDB. */
1047*7f2fe78bSCy Schubert     retval = krb5_dbe_get_string(context, server, KRB5_KDB_SK_SESSION_ENCTYPES,
1048*7f2fe78bSCy Schubert                                  &etypes_str);
1049*7f2fe78bSCy Schubert     if (retval == 0 && etypes_str != NULL && *etypes_str != '\0') {
1050*7f2fe78bSCy Schubert         /* Pass a fake profile key for tracing of unrecognized tokens. */
1051*7f2fe78bSCy Schubert         retval = krb5int_parse_enctype_list(context, "KDB-session_etypes",
1052*7f2fe78bSCy Schubert                                             etypes_str, default_enctypes,
1053*7f2fe78bSCy Schubert                                             &etypes);
1054*7f2fe78bSCy Schubert         if (retval == 0 && etypes != NULL && etypes[0]) {
1055*7f2fe78bSCy Schubert             in_list = k5_etypes_contains(etypes, enctype);
1056*7f2fe78bSCy Schubert             free(etypes_str);
1057*7f2fe78bSCy Schubert             free(etypes);
1058*7f2fe78bSCy Schubert             return in_list;
1059*7f2fe78bSCy Schubert         }
1060*7f2fe78bSCy Schubert         /* Fall through on error or empty list */
1061*7f2fe78bSCy Schubert     }
1062*7f2fe78bSCy Schubert     free(etypes_str);
1063*7f2fe78bSCy Schubert     free(etypes);
1064*7f2fe78bSCy Schubert 
1065*7f2fe78bSCy Schubert     /* Assume every server without a session_enctypes attribute supports
1066*7f2fe78bSCy Schubert      * aes256-cts-hmac-sha1-96. */
1067*7f2fe78bSCy Schubert     if (enctype == ENCTYPE_AES256_CTS_HMAC_SHA1_96)
1068*7f2fe78bSCy Schubert         return TRUE;
1069*7f2fe78bSCy Schubert     /* Assume the server supports any enctype it has a long-term key for. */
1070*7f2fe78bSCy Schubert     return !krb5_dbe_find_enctype(context, server, enctype, -1, 0, &datap);
1071*7f2fe78bSCy Schubert }
1072*7f2fe78bSCy Schubert 
1073*7f2fe78bSCy Schubert /*
1074*7f2fe78bSCy Schubert  * This function returns the keytype which should be selected for the
1075*7f2fe78bSCy Schubert  * session key.  It is based on the ordered list which the user
1076*7f2fe78bSCy Schubert  * requested, and what the KDC and the application server can support.
1077*7f2fe78bSCy Schubert  */
1078*7f2fe78bSCy Schubert krb5_enctype
select_session_keytype(krb5_context context,krb5_db_entry * server,int nktypes,krb5_enctype * ktype)1079*7f2fe78bSCy Schubert select_session_keytype(krb5_context context, krb5_db_entry *server,
1080*7f2fe78bSCy Schubert                        int nktypes, krb5_enctype *ktype)
1081*7f2fe78bSCy Schubert {
1082*7f2fe78bSCy Schubert     int         i;
1083*7f2fe78bSCy Schubert 
1084*7f2fe78bSCy Schubert     for (i = 0; i < nktypes; i++) {
1085*7f2fe78bSCy Schubert         if (!krb5_c_valid_enctype(ktype[i]))
1086*7f2fe78bSCy Schubert             continue;
1087*7f2fe78bSCy Schubert 
1088*7f2fe78bSCy Schubert         if (!krb5_is_permitted_enctype(context, ktype[i]))
1089*7f2fe78bSCy Schubert             continue;
1090*7f2fe78bSCy Schubert 
1091*7f2fe78bSCy Schubert         /*
1092*7f2fe78bSCy Schubert          * Prevent these deprecated enctypes from being used as session keys
1093*7f2fe78bSCy Schubert          * unless they are explicitly allowed.  In the future they will be more
1094*7f2fe78bSCy Schubert          * comprehensively disabled and eventually removed.
1095*7f2fe78bSCy Schubert          */
1096*7f2fe78bSCy Schubert         if (ktype[i] == ENCTYPE_DES3_CBC_SHA1 && !context->allow_des3)
1097*7f2fe78bSCy Schubert             continue;
1098*7f2fe78bSCy Schubert         if (ktype[i] == ENCTYPE_ARCFOUR_HMAC && !context->allow_rc4)
1099*7f2fe78bSCy Schubert             continue;
1100*7f2fe78bSCy Schubert 
1101*7f2fe78bSCy Schubert         if (dbentry_supports_enctype(context, server, ktype[i]))
1102*7f2fe78bSCy Schubert             return ktype[i];
1103*7f2fe78bSCy Schubert     }
1104*7f2fe78bSCy Schubert 
1105*7f2fe78bSCy Schubert     return 0;
1106*7f2fe78bSCy Schubert }
1107*7f2fe78bSCy Schubert 
1108*7f2fe78bSCy Schubert /*
1109*7f2fe78bSCy Schubert  * Limit strings to a "reasonable" length to prevent crowding out of
1110*7f2fe78bSCy Schubert  * other useful information in the log entry
1111*7f2fe78bSCy Schubert  */
1112*7f2fe78bSCy Schubert #define NAME_LENGTH_LIMIT 128
1113*7f2fe78bSCy Schubert 
limit_string(char * name)1114*7f2fe78bSCy Schubert void limit_string(char *name)
1115*7f2fe78bSCy Schubert {
1116*7f2fe78bSCy Schubert     int     i;
1117*7f2fe78bSCy Schubert 
1118*7f2fe78bSCy Schubert     if (!name)
1119*7f2fe78bSCy Schubert         return;
1120*7f2fe78bSCy Schubert 
1121*7f2fe78bSCy Schubert     if (strlen(name) < NAME_LENGTH_LIMIT)
1122*7f2fe78bSCy Schubert         return;
1123*7f2fe78bSCy Schubert 
1124*7f2fe78bSCy Schubert     i = NAME_LENGTH_LIMIT-4;
1125*7f2fe78bSCy Schubert     name[i++] = '.';
1126*7f2fe78bSCy Schubert     name[i++] = '.';
1127*7f2fe78bSCy Schubert     name[i++] = '.';
1128*7f2fe78bSCy Schubert     name[i] = '\0';
1129*7f2fe78bSCy Schubert     return;
1130*7f2fe78bSCy Schubert }
1131*7f2fe78bSCy Schubert 
1132*7f2fe78bSCy Schubert /* Wrapper of krb5_enctype_to_name() to include the PKINIT types. */
1133*7f2fe78bSCy Schubert static krb5_error_code
enctype_name(krb5_enctype ktype,char * buf,size_t buflen)1134*7f2fe78bSCy Schubert enctype_name(krb5_enctype ktype, char *buf, size_t buflen)
1135*7f2fe78bSCy Schubert {
1136*7f2fe78bSCy Schubert     const char *name, *prefix = "";
1137*7f2fe78bSCy Schubert     size_t len;
1138*7f2fe78bSCy Schubert 
1139*7f2fe78bSCy Schubert     if (buflen == 0)
1140*7f2fe78bSCy Schubert         return EINVAL;
1141*7f2fe78bSCy Schubert     *buf = '\0'; /* ensure these are always valid C-strings */
1142*7f2fe78bSCy Schubert 
1143*7f2fe78bSCy Schubert     if (!krb5_c_valid_enctype(ktype))
1144*7f2fe78bSCy Schubert         prefix = "UNSUPPORTED:";
1145*7f2fe78bSCy Schubert     else if (krb5int_c_deprecated_enctype(ktype))
1146*7f2fe78bSCy Schubert         prefix = "DEPRECATED:";
1147*7f2fe78bSCy Schubert     len = strlcpy(buf, prefix, buflen);
1148*7f2fe78bSCy Schubert     if (len >= buflen)
1149*7f2fe78bSCy Schubert         return ENOMEM;
1150*7f2fe78bSCy Schubert     buflen -= len;
1151*7f2fe78bSCy Schubert     buf += len;
1152*7f2fe78bSCy Schubert 
1153*7f2fe78bSCy Schubert     /* rfc4556 recommends that clients wishing to indicate support for these
1154*7f2fe78bSCy Schubert      * pkinit algorithms include them in the etype field of the AS-REQ. */
1155*7f2fe78bSCy Schubert     if (ktype == ENCTYPE_DSA_SHA1_CMS)
1156*7f2fe78bSCy Schubert         name = "id-dsa-with-sha1-CmsOID";
1157*7f2fe78bSCy Schubert     else if (ktype == ENCTYPE_MD5_RSA_CMS)
1158*7f2fe78bSCy Schubert         name = "md5WithRSAEncryption-CmsOID";
1159*7f2fe78bSCy Schubert     else if (ktype == ENCTYPE_SHA1_RSA_CMS)
1160*7f2fe78bSCy Schubert         name = "sha-1WithRSAEncryption-CmsOID";
1161*7f2fe78bSCy Schubert     else if (ktype == ENCTYPE_RC2_CBC_ENV)
1162*7f2fe78bSCy Schubert         name = "rc2-cbc-EnvOID";
1163*7f2fe78bSCy Schubert     else if (ktype == ENCTYPE_RSA_ENV)
1164*7f2fe78bSCy Schubert         name = "rsaEncryption-EnvOID";
1165*7f2fe78bSCy Schubert     else if (ktype == ENCTYPE_RSA_ES_OAEP_ENV)
1166*7f2fe78bSCy Schubert         name = "id-RSAES-OAEP-EnvOID";
1167*7f2fe78bSCy Schubert     else if (ktype == ENCTYPE_DES3_CBC_ENV)
1168*7f2fe78bSCy Schubert         name = "des-ede3-cbc-EnvOID";
1169*7f2fe78bSCy Schubert     else
1170*7f2fe78bSCy Schubert         return krb5_enctype_to_name(ktype, FALSE, buf, buflen);
1171*7f2fe78bSCy Schubert 
1172*7f2fe78bSCy Schubert     if (strlcpy(buf, name, buflen) >= buflen)
1173*7f2fe78bSCy Schubert         return ENOMEM;
1174*7f2fe78bSCy Schubert     return 0;
1175*7f2fe78bSCy Schubert }
1176*7f2fe78bSCy Schubert 
1177*7f2fe78bSCy Schubert char *
ktypes2str(krb5_enctype * ktype,int nktypes)1178*7f2fe78bSCy Schubert ktypes2str(krb5_enctype *ktype, int nktypes)
1179*7f2fe78bSCy Schubert {
1180*7f2fe78bSCy Schubert     struct k5buf buf;
1181*7f2fe78bSCy Schubert     int i;
1182*7f2fe78bSCy Schubert     char name[64];
1183*7f2fe78bSCy Schubert 
1184*7f2fe78bSCy Schubert     if (nktypes < 0)
1185*7f2fe78bSCy Schubert         return NULL;
1186*7f2fe78bSCy Schubert 
1187*7f2fe78bSCy Schubert     k5_buf_init_dynamic(&buf);
1188*7f2fe78bSCy Schubert     k5_buf_add_fmt(&buf, "%d etypes {", nktypes);
1189*7f2fe78bSCy Schubert     for (i = 0; i < nktypes; i++) {
1190*7f2fe78bSCy Schubert         enctype_name(ktype[i], name, sizeof(name));
1191*7f2fe78bSCy Schubert         k5_buf_add_fmt(&buf, "%s%s(%ld)", i ? ", " : "", name, (long)ktype[i]);
1192*7f2fe78bSCy Schubert     }
1193*7f2fe78bSCy Schubert     k5_buf_add(&buf, "}");
1194*7f2fe78bSCy Schubert     return k5_buf_cstring(&buf);
1195*7f2fe78bSCy Schubert }
1196*7f2fe78bSCy Schubert 
1197*7f2fe78bSCy Schubert char *
rep_etypes2str(krb5_kdc_rep * rep)1198*7f2fe78bSCy Schubert rep_etypes2str(krb5_kdc_rep *rep)
1199*7f2fe78bSCy Schubert {
1200*7f2fe78bSCy Schubert     struct k5buf buf;
1201*7f2fe78bSCy Schubert     char name[64];
1202*7f2fe78bSCy Schubert     krb5_enctype etype;
1203*7f2fe78bSCy Schubert 
1204*7f2fe78bSCy Schubert     k5_buf_init_dynamic(&buf);
1205*7f2fe78bSCy Schubert     k5_buf_add(&buf, "etypes {rep=");
1206*7f2fe78bSCy Schubert     enctype_name(rep->enc_part.enctype, name, sizeof(name));
1207*7f2fe78bSCy Schubert     k5_buf_add_fmt(&buf, "%s(%ld)", name, (long)rep->enc_part.enctype);
1208*7f2fe78bSCy Schubert 
1209*7f2fe78bSCy Schubert     if (rep->ticket != NULL) {
1210*7f2fe78bSCy Schubert         etype = rep->ticket->enc_part.enctype;
1211*7f2fe78bSCy Schubert         enctype_name(etype, name, sizeof(name));
1212*7f2fe78bSCy Schubert         k5_buf_add_fmt(&buf, ", tkt=%s(%ld)", name, (long)etype);
1213*7f2fe78bSCy Schubert     }
1214*7f2fe78bSCy Schubert 
1215*7f2fe78bSCy Schubert     if (rep->ticket != NULL && rep->ticket->enc_part2 != NULL &&
1216*7f2fe78bSCy Schubert         rep->ticket->enc_part2->session != NULL) {
1217*7f2fe78bSCy Schubert         etype = rep->ticket->enc_part2->session->enctype;
1218*7f2fe78bSCy Schubert         enctype_name(etype, name, sizeof(name));
1219*7f2fe78bSCy Schubert         k5_buf_add_fmt(&buf, ", ses=%s(%ld)", name, (long)etype);
1220*7f2fe78bSCy Schubert     }
1221*7f2fe78bSCy Schubert 
1222*7f2fe78bSCy Schubert     k5_buf_add(&buf, "}");
1223*7f2fe78bSCy Schubert     return k5_buf_cstring(&buf);
1224*7f2fe78bSCy Schubert }
1225*7f2fe78bSCy Schubert 
1226*7f2fe78bSCy Schubert static krb5_error_code
verify_for_user_checksum(krb5_context context,krb5_keyblock * key,krb5_pa_for_user * req)1227*7f2fe78bSCy Schubert verify_for_user_checksum(krb5_context context,
1228*7f2fe78bSCy Schubert                          krb5_keyblock *key,
1229*7f2fe78bSCy Schubert                          krb5_pa_for_user *req)
1230*7f2fe78bSCy Schubert {
1231*7f2fe78bSCy Schubert     krb5_error_code             code;
1232*7f2fe78bSCy Schubert     int                         i;
1233*7f2fe78bSCy Schubert     krb5_int32                  name_type;
1234*7f2fe78bSCy Schubert     char                        *p;
1235*7f2fe78bSCy Schubert     krb5_data                   data;
1236*7f2fe78bSCy Schubert     krb5_boolean                valid = FALSE;
1237*7f2fe78bSCy Schubert 
1238*7f2fe78bSCy Schubert     if (!krb5_c_is_keyed_cksum(req->cksum.checksum_type)) {
1239*7f2fe78bSCy Schubert         return KRB5KRB_AP_ERR_INAPP_CKSUM;
1240*7f2fe78bSCy Schubert     }
1241*7f2fe78bSCy Schubert 
1242*7f2fe78bSCy Schubert     /*
1243*7f2fe78bSCy Schubert      * Checksum is over name type and string components of
1244*7f2fe78bSCy Schubert      * client principal name and auth_package.
1245*7f2fe78bSCy Schubert      */
1246*7f2fe78bSCy Schubert     data.length = 4;
1247*7f2fe78bSCy Schubert     for (i = 0; i < krb5_princ_size(context, req->user); i++) {
1248*7f2fe78bSCy Schubert         data.length += krb5_princ_component(context, req->user, i)->length;
1249*7f2fe78bSCy Schubert     }
1250*7f2fe78bSCy Schubert     data.length += krb5_princ_realm(context, req->user)->length;
1251*7f2fe78bSCy Schubert     data.length += req->auth_package.length;
1252*7f2fe78bSCy Schubert 
1253*7f2fe78bSCy Schubert     p = data.data = malloc(data.length);
1254*7f2fe78bSCy Schubert     if (data.data == NULL) {
1255*7f2fe78bSCy Schubert         return ENOMEM;
1256*7f2fe78bSCy Schubert     }
1257*7f2fe78bSCy Schubert 
1258*7f2fe78bSCy Schubert     name_type = krb5_princ_type(context, req->user);
1259*7f2fe78bSCy Schubert     p[0] = (name_type >> 0 ) & 0xFF;
1260*7f2fe78bSCy Schubert     p[1] = (name_type >> 8 ) & 0xFF;
1261*7f2fe78bSCy Schubert     p[2] = (name_type >> 16) & 0xFF;
1262*7f2fe78bSCy Schubert     p[3] = (name_type >> 24) & 0xFF;
1263*7f2fe78bSCy Schubert     p += 4;
1264*7f2fe78bSCy Schubert 
1265*7f2fe78bSCy Schubert     for (i = 0; i < krb5_princ_size(context, req->user); i++) {
1266*7f2fe78bSCy Schubert         if (krb5_princ_component(context, req->user, i)->length > 0) {
1267*7f2fe78bSCy Schubert             memcpy(p, krb5_princ_component(context, req->user, i)->data,
1268*7f2fe78bSCy Schubert                    krb5_princ_component(context, req->user, i)->length);
1269*7f2fe78bSCy Schubert         }
1270*7f2fe78bSCy Schubert         p += krb5_princ_component(context, req->user, i)->length;
1271*7f2fe78bSCy Schubert     }
1272*7f2fe78bSCy Schubert 
1273*7f2fe78bSCy Schubert     if (krb5_princ_realm(context, req->user)->length > 0) {
1274*7f2fe78bSCy Schubert         memcpy(p, krb5_princ_realm(context, req->user)->data,
1275*7f2fe78bSCy Schubert                krb5_princ_realm(context, req->user)->length);
1276*7f2fe78bSCy Schubert     }
1277*7f2fe78bSCy Schubert     p += krb5_princ_realm(context, req->user)->length;
1278*7f2fe78bSCy Schubert 
1279*7f2fe78bSCy Schubert     if (req->auth_package.length > 0)
1280*7f2fe78bSCy Schubert         memcpy(p, req->auth_package.data, req->auth_package.length);
1281*7f2fe78bSCy Schubert     p += req->auth_package.length;
1282*7f2fe78bSCy Schubert 
1283*7f2fe78bSCy Schubert     code = krb5_c_verify_checksum(context,
1284*7f2fe78bSCy Schubert                                   key,
1285*7f2fe78bSCy Schubert                                   KRB5_KEYUSAGE_APP_DATA_CKSUM,
1286*7f2fe78bSCy Schubert                                   &data,
1287*7f2fe78bSCy Schubert                                   &req->cksum,
1288*7f2fe78bSCy Schubert                                   &valid);
1289*7f2fe78bSCy Schubert 
1290*7f2fe78bSCy Schubert     if (code == 0 && valid == FALSE)
1291*7f2fe78bSCy Schubert         code = KRB5KRB_AP_ERR_MODIFIED;
1292*7f2fe78bSCy Schubert 
1293*7f2fe78bSCy Schubert     free(data.data);
1294*7f2fe78bSCy Schubert 
1295*7f2fe78bSCy Schubert     return code;
1296*7f2fe78bSCy Schubert }
1297*7f2fe78bSCy Schubert 
1298*7f2fe78bSCy Schubert /*
1299*7f2fe78bSCy Schubert  * Legacy protocol transition (Windows 2003 and above)
1300*7f2fe78bSCy Schubert  */
1301*7f2fe78bSCy Schubert static krb5_error_code
kdc_process_for_user(krb5_context context,krb5_pa_data * pa_data,krb5_keyblock * tgs_session,krb5_pa_s4u_x509_user ** s4u_x509_user,const char ** status)1302*7f2fe78bSCy Schubert kdc_process_for_user(krb5_context context, krb5_pa_data *pa_data,
1303*7f2fe78bSCy Schubert                      krb5_keyblock *tgs_session,
1304*7f2fe78bSCy Schubert                      krb5_pa_s4u_x509_user **s4u_x509_user,
1305*7f2fe78bSCy Schubert                      const char **status)
1306*7f2fe78bSCy Schubert {
1307*7f2fe78bSCy Schubert     krb5_error_code             code;
1308*7f2fe78bSCy Schubert     krb5_pa_for_user            *for_user;
1309*7f2fe78bSCy Schubert     krb5_data                   req_data;
1310*7f2fe78bSCy Schubert 
1311*7f2fe78bSCy Schubert     req_data.length = pa_data->length;
1312*7f2fe78bSCy Schubert     req_data.data = (char *)pa_data->contents;
1313*7f2fe78bSCy Schubert 
1314*7f2fe78bSCy Schubert     code = decode_krb5_pa_for_user(&req_data, &for_user);
1315*7f2fe78bSCy Schubert     if (code) {
1316*7f2fe78bSCy Schubert         *status = "DECODE_PA_FOR_USER";
1317*7f2fe78bSCy Schubert         return code;
1318*7f2fe78bSCy Schubert     }
1319*7f2fe78bSCy Schubert 
1320*7f2fe78bSCy Schubert     code = verify_for_user_checksum(context, tgs_session, for_user);
1321*7f2fe78bSCy Schubert     if (code) {
1322*7f2fe78bSCy Schubert         *status = "INVALID_S4U2SELF_CHECKSUM";
1323*7f2fe78bSCy Schubert         krb5_free_pa_for_user(context, for_user);
1324*7f2fe78bSCy Schubert         return code;
1325*7f2fe78bSCy Schubert     }
1326*7f2fe78bSCy Schubert 
1327*7f2fe78bSCy Schubert     *s4u_x509_user = calloc(1, sizeof(krb5_pa_s4u_x509_user));
1328*7f2fe78bSCy Schubert     if (*s4u_x509_user == NULL) {
1329*7f2fe78bSCy Schubert         krb5_free_pa_for_user(context, for_user);
1330*7f2fe78bSCy Schubert         return ENOMEM;
1331*7f2fe78bSCy Schubert     }
1332*7f2fe78bSCy Schubert 
1333*7f2fe78bSCy Schubert     (*s4u_x509_user)->user_id.user = for_user->user;
1334*7f2fe78bSCy Schubert     for_user->user = NULL;
1335*7f2fe78bSCy Schubert     krb5_free_pa_for_user(context, for_user);
1336*7f2fe78bSCy Schubert 
1337*7f2fe78bSCy Schubert     return 0;
1338*7f2fe78bSCy Schubert }
1339*7f2fe78bSCy Schubert 
1340*7f2fe78bSCy Schubert static krb5_error_code
verify_s4u_x509_user_checksum(krb5_context context,krb5_keyblock * key,krb5_data * req_data,krb5_int32 kdc_req_nonce,krb5_pa_s4u_x509_user * req)1341*7f2fe78bSCy Schubert verify_s4u_x509_user_checksum(krb5_context context,
1342*7f2fe78bSCy Schubert                               krb5_keyblock *key,
1343*7f2fe78bSCy Schubert                               krb5_data *req_data,
1344*7f2fe78bSCy Schubert                               krb5_int32 kdc_req_nonce,
1345*7f2fe78bSCy Schubert                               krb5_pa_s4u_x509_user *req)
1346*7f2fe78bSCy Schubert {
1347*7f2fe78bSCy Schubert     krb5_error_code             code;
1348*7f2fe78bSCy Schubert     krb5_data                   scratch;
1349*7f2fe78bSCy Schubert     krb5_boolean                valid = FALSE;
1350*7f2fe78bSCy Schubert 
1351*7f2fe78bSCy Schubert     if (enctype_requires_etype_info_2(key->enctype) &&
1352*7f2fe78bSCy Schubert         !krb5_c_is_keyed_cksum(req->cksum.checksum_type))
1353*7f2fe78bSCy Schubert         return KRB5KRB_AP_ERR_INAPP_CKSUM;
1354*7f2fe78bSCy Schubert 
1355*7f2fe78bSCy Schubert     if (req->user_id.nonce != kdc_req_nonce)
1356*7f2fe78bSCy Schubert         return KRB5KRB_AP_ERR_MODIFIED;
1357*7f2fe78bSCy Schubert 
1358*7f2fe78bSCy Schubert     /*
1359*7f2fe78bSCy Schubert      * Verify checksum over the encoded userid. If that fails,
1360*7f2fe78bSCy Schubert      * re-encode, and verify that. This is similar to the
1361*7f2fe78bSCy Schubert      * behaviour in kdc_process_tgs_req().
1362*7f2fe78bSCy Schubert      */
1363*7f2fe78bSCy Schubert     if (fetch_asn1_field((unsigned char *)req_data->data, 1, 0, &scratch) < 0)
1364*7f2fe78bSCy Schubert         return ASN1_PARSE_ERROR;
1365*7f2fe78bSCy Schubert 
1366*7f2fe78bSCy Schubert     code = krb5_c_verify_checksum(context,
1367*7f2fe78bSCy Schubert                                   key,
1368*7f2fe78bSCy Schubert                                   KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST,
1369*7f2fe78bSCy Schubert                                   &scratch,
1370*7f2fe78bSCy Schubert                                   &req->cksum,
1371*7f2fe78bSCy Schubert                                   &valid);
1372*7f2fe78bSCy Schubert     if (code != 0)
1373*7f2fe78bSCy Schubert         return code;
1374*7f2fe78bSCy Schubert 
1375*7f2fe78bSCy Schubert     if (valid == FALSE) {
1376*7f2fe78bSCy Schubert         krb5_data *data;
1377*7f2fe78bSCy Schubert 
1378*7f2fe78bSCy Schubert         code = encode_krb5_s4u_userid(&req->user_id, &data);
1379*7f2fe78bSCy Schubert         if (code != 0)
1380*7f2fe78bSCy Schubert             return code;
1381*7f2fe78bSCy Schubert 
1382*7f2fe78bSCy Schubert         code = krb5_c_verify_checksum(context,
1383*7f2fe78bSCy Schubert                                       key,
1384*7f2fe78bSCy Schubert                                       KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST,
1385*7f2fe78bSCy Schubert                                       data,
1386*7f2fe78bSCy Schubert                                       &req->cksum,
1387*7f2fe78bSCy Schubert                                       &valid);
1388*7f2fe78bSCy Schubert 
1389*7f2fe78bSCy Schubert         krb5_free_data(context, data);
1390*7f2fe78bSCy Schubert 
1391*7f2fe78bSCy Schubert         if (code != 0)
1392*7f2fe78bSCy Schubert             return code;
1393*7f2fe78bSCy Schubert     }
1394*7f2fe78bSCy Schubert 
1395*7f2fe78bSCy Schubert     return valid ? 0 : KRB5KRB_AP_ERR_MODIFIED;
1396*7f2fe78bSCy Schubert }
1397*7f2fe78bSCy Schubert 
1398*7f2fe78bSCy Schubert /*
1399*7f2fe78bSCy Schubert  * New protocol transition request (Windows 2008 and above)
1400*7f2fe78bSCy Schubert  */
1401*7f2fe78bSCy Schubert static krb5_error_code
kdc_process_s4u_x509_user(krb5_context context,krb5_kdc_req * request,krb5_pa_data * pa_data,krb5_keyblock * tgs_subkey,krb5_keyblock * tgs_session,krb5_pa_s4u_x509_user ** s4u_x509_user,const char ** status)1402*7f2fe78bSCy Schubert kdc_process_s4u_x509_user(krb5_context context,
1403*7f2fe78bSCy Schubert                           krb5_kdc_req *request,
1404*7f2fe78bSCy Schubert                           krb5_pa_data *pa_data,
1405*7f2fe78bSCy Schubert                           krb5_keyblock *tgs_subkey,
1406*7f2fe78bSCy Schubert                           krb5_keyblock *tgs_session,
1407*7f2fe78bSCy Schubert                           krb5_pa_s4u_x509_user **s4u_x509_user,
1408*7f2fe78bSCy Schubert                           const char **status)
1409*7f2fe78bSCy Schubert {
1410*7f2fe78bSCy Schubert     krb5_error_code             code;
1411*7f2fe78bSCy Schubert     krb5_data                   req_data;
1412*7f2fe78bSCy Schubert 
1413*7f2fe78bSCy Schubert     req_data.length = pa_data->length;
1414*7f2fe78bSCy Schubert     req_data.data = (char *)pa_data->contents;
1415*7f2fe78bSCy Schubert 
1416*7f2fe78bSCy Schubert     code = decode_krb5_pa_s4u_x509_user(&req_data, s4u_x509_user);
1417*7f2fe78bSCy Schubert     if (code) {
1418*7f2fe78bSCy Schubert         *status = "DECODE_PA_S4U_X509_USER";
1419*7f2fe78bSCy Schubert         return code;
1420*7f2fe78bSCy Schubert     }
1421*7f2fe78bSCy Schubert 
1422*7f2fe78bSCy Schubert     code = verify_s4u_x509_user_checksum(context,
1423*7f2fe78bSCy Schubert                                          tgs_subkey ? tgs_subkey :
1424*7f2fe78bSCy Schubert                                          tgs_session,
1425*7f2fe78bSCy Schubert                                          &req_data,
1426*7f2fe78bSCy Schubert                                          request->nonce, *s4u_x509_user);
1427*7f2fe78bSCy Schubert 
1428*7f2fe78bSCy Schubert     if (code) {
1429*7f2fe78bSCy Schubert         *status = "INVALID_S4U2SELF_CHECKSUM";
1430*7f2fe78bSCy Schubert         krb5_free_pa_s4u_x509_user(context, *s4u_x509_user);
1431*7f2fe78bSCy Schubert         *s4u_x509_user = NULL;
1432*7f2fe78bSCy Schubert         return code;
1433*7f2fe78bSCy Schubert     }
1434*7f2fe78bSCy Schubert 
1435*7f2fe78bSCy Schubert     if (krb5_princ_size(context, (*s4u_x509_user)->user_id.user) == 0 &&
1436*7f2fe78bSCy Schubert         (*s4u_x509_user)->user_id.subject_cert.length == 0) {
1437*7f2fe78bSCy Schubert         *status = "INVALID_S4U2SELF_REQUEST";
1438*7f2fe78bSCy Schubert         krb5_free_pa_s4u_x509_user(context, *s4u_x509_user);
1439*7f2fe78bSCy Schubert         *s4u_x509_user = NULL;
1440*7f2fe78bSCy Schubert         return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1441*7f2fe78bSCy Schubert     }
1442*7f2fe78bSCy Schubert 
1443*7f2fe78bSCy Schubert     return 0;
1444*7f2fe78bSCy Schubert }
1445*7f2fe78bSCy Schubert 
1446*7f2fe78bSCy Schubert krb5_error_code
kdc_make_s4u2self_rep(krb5_context context,krb5_keyblock * tgs_subkey,krb5_keyblock * tgs_session,krb5_pa_s4u_x509_user * req_s4u_user,krb5_kdc_rep * reply,krb5_enc_kdc_rep_part * reply_encpart)1447*7f2fe78bSCy Schubert kdc_make_s4u2self_rep(krb5_context context,
1448*7f2fe78bSCy Schubert                       krb5_keyblock *tgs_subkey,
1449*7f2fe78bSCy Schubert                       krb5_keyblock *tgs_session,
1450*7f2fe78bSCy Schubert                       krb5_pa_s4u_x509_user *req_s4u_user,
1451*7f2fe78bSCy Schubert                       krb5_kdc_rep *reply,
1452*7f2fe78bSCy Schubert                       krb5_enc_kdc_rep_part *reply_encpart)
1453*7f2fe78bSCy Schubert {
1454*7f2fe78bSCy Schubert     krb5_error_code             code;
1455*7f2fe78bSCy Schubert     krb5_data                   *der_user_id = NULL, *der_s4u_x509_user = NULL;
1456*7f2fe78bSCy Schubert     krb5_pa_s4u_x509_user       rep_s4u_user;
1457*7f2fe78bSCy Schubert     krb5_pa_data                *pa = NULL;
1458*7f2fe78bSCy Schubert     krb5_enctype                enctype;
1459*7f2fe78bSCy Schubert     krb5_keyusage               usage;
1460*7f2fe78bSCy Schubert 
1461*7f2fe78bSCy Schubert     memset(&rep_s4u_user, 0, sizeof(rep_s4u_user));
1462*7f2fe78bSCy Schubert 
1463*7f2fe78bSCy Schubert     rep_s4u_user.user_id.nonce   = req_s4u_user->user_id.nonce;
1464*7f2fe78bSCy Schubert     rep_s4u_user.user_id.user    = req_s4u_user->user_id.user;
1465*7f2fe78bSCy Schubert     rep_s4u_user.user_id.options =
1466*7f2fe78bSCy Schubert         req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE;
1467*7f2fe78bSCy Schubert 
1468*7f2fe78bSCy Schubert     code = encode_krb5_s4u_userid(&rep_s4u_user.user_id, &der_user_id);
1469*7f2fe78bSCy Schubert     if (code != 0)
1470*7f2fe78bSCy Schubert         goto cleanup;
1471*7f2fe78bSCy Schubert 
1472*7f2fe78bSCy Schubert     if (req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE)
1473*7f2fe78bSCy Schubert         usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY;
1474*7f2fe78bSCy Schubert     else
1475*7f2fe78bSCy Schubert         usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST;
1476*7f2fe78bSCy Schubert 
1477*7f2fe78bSCy Schubert     code = krb5_c_make_checksum(context, req_s4u_user->cksum.checksum_type,
1478*7f2fe78bSCy Schubert                                 tgs_subkey != NULL ? tgs_subkey : tgs_session,
1479*7f2fe78bSCy Schubert                                 usage, der_user_id, &rep_s4u_user.cksum);
1480*7f2fe78bSCy Schubert     if (code != 0)
1481*7f2fe78bSCy Schubert         goto cleanup;
1482*7f2fe78bSCy Schubert 
1483*7f2fe78bSCy Schubert     code = encode_krb5_pa_s4u_x509_user(&rep_s4u_user, &der_s4u_x509_user);
1484*7f2fe78bSCy Schubert     if (code != 0)
1485*7f2fe78bSCy Schubert         goto cleanup;
1486*7f2fe78bSCy Schubert 
1487*7f2fe78bSCy Schubert     code = k5_add_pa_data_from_data(&reply->padata, KRB5_PADATA_S4U_X509_USER,
1488*7f2fe78bSCy Schubert                                     der_s4u_x509_user);
1489*7f2fe78bSCy Schubert     if (code != 0)
1490*7f2fe78bSCy Schubert         goto cleanup;
1491*7f2fe78bSCy Schubert 
1492*7f2fe78bSCy Schubert     if (tgs_subkey != NULL)
1493*7f2fe78bSCy Schubert         enctype = tgs_subkey->enctype;
1494*7f2fe78bSCy Schubert     else
1495*7f2fe78bSCy Schubert         enctype = tgs_session->enctype;
1496*7f2fe78bSCy Schubert 
1497*7f2fe78bSCy Schubert     /*
1498*7f2fe78bSCy Schubert      * Owing to a bug in Windows, unkeyed checksums were used for older
1499*7f2fe78bSCy Schubert      * enctypes, including rc4-hmac. A forthcoming workaround for this
1500*7f2fe78bSCy Schubert      * includes the checksum bytes in the encrypted padata.
1501*7f2fe78bSCy Schubert      */
1502*7f2fe78bSCy Schubert     if (enctype_requires_etype_info_2(enctype) == FALSE) {
1503*7f2fe78bSCy Schubert         code = k5_alloc_pa_data(KRB5_PADATA_S4U_X509_USER,
1504*7f2fe78bSCy Schubert                                 req_s4u_user->cksum.length +
1505*7f2fe78bSCy Schubert                                 rep_s4u_user.cksum.length, &pa);
1506*7f2fe78bSCy Schubert         if (code != 0)
1507*7f2fe78bSCy Schubert             goto cleanup;
1508*7f2fe78bSCy Schubert         memcpy(pa->contents,
1509*7f2fe78bSCy Schubert                req_s4u_user->cksum.contents, req_s4u_user->cksum.length);
1510*7f2fe78bSCy Schubert         memcpy(&pa->contents[req_s4u_user->cksum.length],
1511*7f2fe78bSCy Schubert                rep_s4u_user.cksum.contents, rep_s4u_user.cksum.length);
1512*7f2fe78bSCy Schubert 
1513*7f2fe78bSCy Schubert         code = k5_add_pa_data_element(&reply_encpart->enc_padata, &pa);
1514*7f2fe78bSCy Schubert         if (code != 0)
1515*7f2fe78bSCy Schubert             goto cleanup;
1516*7f2fe78bSCy Schubert     }
1517*7f2fe78bSCy Schubert 
1518*7f2fe78bSCy Schubert cleanup:
1519*7f2fe78bSCy Schubert     if (rep_s4u_user.cksum.contents != NULL)
1520*7f2fe78bSCy Schubert         krb5_free_checksum_contents(context, &rep_s4u_user.cksum);
1521*7f2fe78bSCy Schubert     krb5_free_data(context, der_user_id);
1522*7f2fe78bSCy Schubert     krb5_free_data(context, der_s4u_x509_user);
1523*7f2fe78bSCy Schubert     k5_free_pa_data_element(pa);
1524*7f2fe78bSCy Schubert     return code;
1525*7f2fe78bSCy Schubert }
1526*7f2fe78bSCy Schubert 
1527*7f2fe78bSCy Schubert /* Return true if princ canonicalizes to the same principal as entry's. */
1528*7f2fe78bSCy Schubert krb5_boolean
is_client_db_alias(krb5_context context,const krb5_db_entry * entry,krb5_const_principal princ)1529*7f2fe78bSCy Schubert is_client_db_alias(krb5_context context, const krb5_db_entry *entry,
1530*7f2fe78bSCy Schubert                    krb5_const_principal princ)
1531*7f2fe78bSCy Schubert {
1532*7f2fe78bSCy Schubert     krb5_error_code ret;
1533*7f2fe78bSCy Schubert     krb5_db_entry *self;
1534*7f2fe78bSCy Schubert     krb5_boolean is_self = FALSE;
1535*7f2fe78bSCy Schubert 
1536*7f2fe78bSCy Schubert     ret = krb5_db_get_principal(context, princ, KRB5_KDB_FLAG_CLIENT, &self);
1537*7f2fe78bSCy Schubert     if (!ret) {
1538*7f2fe78bSCy Schubert         is_self = krb5_principal_compare(context, entry->princ, self->princ);
1539*7f2fe78bSCy Schubert         krb5_db_free_principal(context, self);
1540*7f2fe78bSCy Schubert     }
1541*7f2fe78bSCy Schubert 
1542*7f2fe78bSCy Schubert     return is_self;
1543*7f2fe78bSCy Schubert }
1544*7f2fe78bSCy Schubert 
1545*7f2fe78bSCy Schubert /*
1546*7f2fe78bSCy Schubert  * If S4U2Self padata is present in request, verify the checksum and set
1547*7f2fe78bSCy Schubert  * *s4u_x509_user to the S4U2Self request.  If the requested client realm is
1548*7f2fe78bSCy Schubert  * local, look up the client and set *princ_ptr to its DB entry.
1549*7f2fe78bSCy Schubert  */
1550*7f2fe78bSCy Schubert krb5_error_code
kdc_process_s4u2self_req(krb5_context context,krb5_kdc_req * request,const krb5_db_entry * server,krb5_keyblock * tgs_subkey,krb5_keyblock * tgs_session,krb5_pa_s4u_x509_user ** s4u_x509_user,krb5_db_entry ** princ_ptr,const char ** status)1551*7f2fe78bSCy Schubert kdc_process_s4u2self_req(krb5_context context, krb5_kdc_req *request,
1552*7f2fe78bSCy Schubert                          const krb5_db_entry *server,
1553*7f2fe78bSCy Schubert                          krb5_keyblock *tgs_subkey, krb5_keyblock *tgs_session,
1554*7f2fe78bSCy Schubert                          krb5_pa_s4u_x509_user **s4u_x509_user,
1555*7f2fe78bSCy Schubert                          krb5_db_entry **princ_ptr, const char **status)
1556*7f2fe78bSCy Schubert {
1557*7f2fe78bSCy Schubert     krb5_error_code             code;
1558*7f2fe78bSCy Schubert     krb5_pa_data                *pa_data;
1559*7f2fe78bSCy Schubert     krb5_db_entry               *princ;
1560*7f2fe78bSCy Schubert     krb5_s4u_userid             *id;
1561*7f2fe78bSCy Schubert 
1562*7f2fe78bSCy Schubert     *princ_ptr = NULL;
1563*7f2fe78bSCy Schubert 
1564*7f2fe78bSCy Schubert     pa_data = krb5int_find_pa_data(context, request->padata,
1565*7f2fe78bSCy Schubert                                    KRB5_PADATA_S4U_X509_USER);
1566*7f2fe78bSCy Schubert     if (pa_data != NULL) {
1567*7f2fe78bSCy Schubert         code = kdc_process_s4u_x509_user(context, request, pa_data, tgs_subkey,
1568*7f2fe78bSCy Schubert                                          tgs_session, s4u_x509_user, status);
1569*7f2fe78bSCy Schubert         if (code != 0)
1570*7f2fe78bSCy Schubert             return code;
1571*7f2fe78bSCy Schubert     } else {
1572*7f2fe78bSCy Schubert         pa_data = krb5int_find_pa_data(context, request->padata,
1573*7f2fe78bSCy Schubert                                        KRB5_PADATA_FOR_USER);
1574*7f2fe78bSCy Schubert         if (pa_data != NULL) {
1575*7f2fe78bSCy Schubert             code = kdc_process_for_user(context, pa_data, tgs_session,
1576*7f2fe78bSCy Schubert                                         s4u_x509_user, status);
1577*7f2fe78bSCy Schubert             if (code != 0)
1578*7f2fe78bSCy Schubert                 return code;
1579*7f2fe78bSCy Schubert         } else
1580*7f2fe78bSCy Schubert             return 0;
1581*7f2fe78bSCy Schubert     }
1582*7f2fe78bSCy Schubert     id = &(*s4u_x509_user)->user_id;
1583*7f2fe78bSCy Schubert 
1584*7f2fe78bSCy Schubert     if (data_eq(server->princ->realm, id->user->realm)) {
1585*7f2fe78bSCy Schubert         if (id->subject_cert.length != 0) {
1586*7f2fe78bSCy Schubert             code = krb5_db_get_s4u_x509_principal(context,
1587*7f2fe78bSCy Schubert                                                   &id->subject_cert, id->user,
1588*7f2fe78bSCy Schubert                                                   KRB5_KDB_FLAG_CLIENT,
1589*7f2fe78bSCy Schubert                                                   &princ);
1590*7f2fe78bSCy Schubert             if (code == 0 && id->user->length == 0) {
1591*7f2fe78bSCy Schubert                 krb5_free_principal(context, id->user);
1592*7f2fe78bSCy Schubert                 code = krb5_copy_principal(context, princ->princ, &id->user);
1593*7f2fe78bSCy Schubert             }
1594*7f2fe78bSCy Schubert         } else {
1595*7f2fe78bSCy Schubert             code = krb5_db_get_principal(context, id->user,
1596*7f2fe78bSCy Schubert                                          KRB5_KDB_FLAG_CLIENT, &princ);
1597*7f2fe78bSCy Schubert         }
1598*7f2fe78bSCy Schubert         if (code == KRB5_KDB_NOENTRY) {
1599*7f2fe78bSCy Schubert             *status = "UNKNOWN_S4U2SELF_PRINCIPAL";
1600*7f2fe78bSCy Schubert             return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1601*7f2fe78bSCy Schubert         } else if (code) {
1602*7f2fe78bSCy Schubert             *status = "LOOKING_UP_S4U2SELF_PRINCIPAL";
1603*7f2fe78bSCy Schubert             return code; /* caller can free for_user */
1604*7f2fe78bSCy Schubert         }
1605*7f2fe78bSCy Schubert 
1606*7f2fe78bSCy Schubert         /* Ignore password expiration and needchange attributes (as Windows
1607*7f2fe78bSCy Schubert          * does), since S4U2Self is not password authentication. */
1608*7f2fe78bSCy Schubert         princ->pw_expiration = 0;
1609*7f2fe78bSCy Schubert         clear(princ->attributes, KRB5_KDB_REQUIRES_PWCHANGE);
1610*7f2fe78bSCy Schubert 
1611*7f2fe78bSCy Schubert         *princ_ptr = princ;
1612*7f2fe78bSCy Schubert     }
1613*7f2fe78bSCy Schubert 
1614*7f2fe78bSCy Schubert     return 0;
1615*7f2fe78bSCy Schubert }
1616*7f2fe78bSCy Schubert 
1617*7f2fe78bSCy Schubert /* Clear the forwardable flag in tkt if server cannot obtain forwardable
1618*7f2fe78bSCy Schubert  * S4U2Self tickets according to [MS-SFU] 3.2.5.1.2. */
1619*7f2fe78bSCy Schubert krb5_error_code
s4u2self_forwardable(krb5_context context,krb5_db_entry * server,krb5_flags * tktflags)1620*7f2fe78bSCy Schubert s4u2self_forwardable(krb5_context context, krb5_db_entry *server,
1621*7f2fe78bSCy Schubert                      krb5_flags *tktflags)
1622*7f2fe78bSCy Schubert {
1623*7f2fe78bSCy Schubert     krb5_error_code ret;
1624*7f2fe78bSCy Schubert 
1625*7f2fe78bSCy Schubert     /* Allow the forwardable flag if server has ok-to-auth-as-delegate set. */
1626*7f2fe78bSCy Schubert     if (server->attributes & KRB5_KDB_OK_TO_AUTH_AS_DELEGATE)
1627*7f2fe78bSCy Schubert         return 0;
1628*7f2fe78bSCy Schubert 
1629*7f2fe78bSCy Schubert     /* Deny the forwardable flag if server has any authorized delegation
1630*7f2fe78bSCy Schubert      * targets for traditional S4U2Proxy. */
1631*7f2fe78bSCy Schubert     ret = krb5_db_check_allowed_to_delegate(context, NULL, server, NULL);
1632*7f2fe78bSCy Schubert     if (!ret)
1633*7f2fe78bSCy Schubert         *tktflags &= ~TKT_FLG_FORWARDABLE;
1634*7f2fe78bSCy Schubert 
1635*7f2fe78bSCy Schubert     if (ret == KRB5KDC_ERR_BADOPTION || ret == KRB5_PLUGIN_OP_NOTSUPP)
1636*7f2fe78bSCy Schubert         return 0;
1637*7f2fe78bSCy Schubert     return ret;
1638*7f2fe78bSCy Schubert }
1639*7f2fe78bSCy Schubert 
1640*7f2fe78bSCy Schubert krb5_error_code
kdc_check_transited_list(krb5_context context,const krb5_data * trans,const krb5_data * realm1,const krb5_data * realm2)1641*7f2fe78bSCy Schubert kdc_check_transited_list(krb5_context context, const krb5_data *trans,
1642*7f2fe78bSCy Schubert                          const krb5_data *realm1, const krb5_data *realm2)
1643*7f2fe78bSCy Schubert {
1644*7f2fe78bSCy Schubert     krb5_error_code             code;
1645*7f2fe78bSCy Schubert 
1646*7f2fe78bSCy Schubert     /* Check against the KDB module.  Treat this answer as authoritative if the
1647*7f2fe78bSCy Schubert      * method is supported and doesn't explicitly pass control. */
1648*7f2fe78bSCy Schubert     code = krb5_db_check_transited_realms(context, trans, realm1, realm2);
1649*7f2fe78bSCy Schubert     if (code != KRB5_PLUGIN_OP_NOTSUPP && code != KRB5_PLUGIN_NO_HANDLE)
1650*7f2fe78bSCy Schubert         return code;
1651*7f2fe78bSCy Schubert 
1652*7f2fe78bSCy Schubert     /* Check using krb5.conf [capaths] or hierarchical relationships. */
1653*7f2fe78bSCy Schubert     return krb5_check_transited_list(context, trans, realm1, realm2);
1654*7f2fe78bSCy Schubert }
1655*7f2fe78bSCy Schubert 
1656*7f2fe78bSCy Schubert krb5_boolean
enctype_requires_etype_info_2(krb5_enctype enctype)1657*7f2fe78bSCy Schubert enctype_requires_etype_info_2(krb5_enctype enctype)
1658*7f2fe78bSCy Schubert {
1659*7f2fe78bSCy Schubert     switch(enctype) {
1660*7f2fe78bSCy Schubert     case ENCTYPE_DES3_CBC_SHA1:
1661*7f2fe78bSCy Schubert     case ENCTYPE_DES3_CBC_RAW:
1662*7f2fe78bSCy Schubert     case ENCTYPE_ARCFOUR_HMAC:
1663*7f2fe78bSCy Schubert     case ENCTYPE_ARCFOUR_HMAC_EXP :
1664*7f2fe78bSCy Schubert         return 0;
1665*7f2fe78bSCy Schubert     default:
1666*7f2fe78bSCy Schubert         return krb5_c_valid_enctype(enctype);
1667*7f2fe78bSCy Schubert     }
1668*7f2fe78bSCy Schubert }
1669*7f2fe78bSCy Schubert 
1670*7f2fe78bSCy Schubert void
kdc_get_ticket_endtime(kdc_realm_t * realm,krb5_timestamp starttime,krb5_timestamp endtime,krb5_timestamp till,krb5_db_entry * client,krb5_db_entry * server,krb5_timestamp * out_endtime)1671*7f2fe78bSCy Schubert kdc_get_ticket_endtime(kdc_realm_t *realm, krb5_timestamp starttime,
1672*7f2fe78bSCy Schubert                        krb5_timestamp endtime, krb5_timestamp till,
1673*7f2fe78bSCy Schubert                        krb5_db_entry *client, krb5_db_entry *server,
1674*7f2fe78bSCy Schubert                        krb5_timestamp *out_endtime)
1675*7f2fe78bSCy Schubert {
1676*7f2fe78bSCy Schubert     krb5_timestamp until;
1677*7f2fe78bSCy Schubert     krb5_deltat life;
1678*7f2fe78bSCy Schubert 
1679*7f2fe78bSCy Schubert     if (till == 0)
1680*7f2fe78bSCy Schubert         till = kdc_infinity;
1681*7f2fe78bSCy Schubert 
1682*7f2fe78bSCy Schubert     until = ts_min(till, endtime);
1683*7f2fe78bSCy Schubert 
1684*7f2fe78bSCy Schubert     /* Determine the requested lifetime, capped at the maximum valid time
1685*7f2fe78bSCy Schubert      * interval. */
1686*7f2fe78bSCy Schubert     life = ts_delta(until, starttime);
1687*7f2fe78bSCy Schubert     if (ts_after(until, starttime) && life < 0)
1688*7f2fe78bSCy Schubert         life = INT32_MAX;
1689*7f2fe78bSCy Schubert 
1690*7f2fe78bSCy Schubert     if (client != NULL && client->max_life != 0)
1691*7f2fe78bSCy Schubert         life = min(life, client->max_life);
1692*7f2fe78bSCy Schubert     if (server->max_life != 0)
1693*7f2fe78bSCy Schubert         life = min(life, server->max_life);
1694*7f2fe78bSCy Schubert     if (realm->realm_maxlife != 0)
1695*7f2fe78bSCy Schubert         life = min(life, realm->realm_maxlife);
1696*7f2fe78bSCy Schubert 
1697*7f2fe78bSCy Schubert     *out_endtime = ts_incr(starttime, life);
1698*7f2fe78bSCy Schubert }
1699*7f2fe78bSCy Schubert 
1700*7f2fe78bSCy Schubert /*
1701*7f2fe78bSCy Schubert  * Set times->renew_till to the requested renewable lifetime as modified by
1702*7f2fe78bSCy Schubert  * policy.  Set the TKT_FLG_RENEWABLE bit in *tktflags if we set a nonzero
1703*7f2fe78bSCy Schubert  * renew_till.  *times must be filled in except for renew_till.  client and tgt
1704*7f2fe78bSCy Schubert  * may be NULL.
1705*7f2fe78bSCy Schubert  */
1706*7f2fe78bSCy Schubert void
kdc_get_ticket_renewtime(kdc_realm_t * realm,krb5_kdc_req * request,krb5_enc_tkt_part * tgt,krb5_db_entry * client,krb5_db_entry * server,krb5_flags * tktflags,krb5_ticket_times * times)1707*7f2fe78bSCy Schubert kdc_get_ticket_renewtime(kdc_realm_t *realm, krb5_kdc_req *request,
1708*7f2fe78bSCy Schubert                          krb5_enc_tkt_part *tgt, krb5_db_entry *client,
1709*7f2fe78bSCy Schubert                          krb5_db_entry *server, krb5_flags *tktflags,
1710*7f2fe78bSCy Schubert                          krb5_ticket_times *times)
1711*7f2fe78bSCy Schubert {
1712*7f2fe78bSCy Schubert     krb5_timestamp rtime, max_rlife;
1713*7f2fe78bSCy Schubert 
1714*7f2fe78bSCy Schubert     *tktflags &= ~TKT_FLG_RENEWABLE;
1715*7f2fe78bSCy Schubert     times->renew_till = 0;
1716*7f2fe78bSCy Schubert 
1717*7f2fe78bSCy Schubert     /* Don't issue renewable tickets if the client or server don't allow it,
1718*7f2fe78bSCy Schubert      * or if this is a TGS request and the TGT isn't renewable. */
1719*7f2fe78bSCy Schubert     if (server->attributes & KRB5_KDB_DISALLOW_RENEWABLE)
1720*7f2fe78bSCy Schubert         return;
1721*7f2fe78bSCy Schubert     if (client != NULL && (client->attributes & KRB5_KDB_DISALLOW_RENEWABLE))
1722*7f2fe78bSCy Schubert         return;
1723*7f2fe78bSCy Schubert     if (tgt != NULL && !(tgt->flags & TKT_FLG_RENEWABLE))
1724*7f2fe78bSCy Schubert         return;
1725*7f2fe78bSCy Schubert 
1726*7f2fe78bSCy Schubert     /* Determine the requested renewable time. */
1727*7f2fe78bSCy Schubert     if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE))
1728*7f2fe78bSCy Schubert         rtime = request->rtime ? request->rtime : kdc_infinity;
1729*7f2fe78bSCy Schubert     else if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
1730*7f2fe78bSCy Schubert              ts_after(request->till, times->endtime))
1731*7f2fe78bSCy Schubert         rtime = request->till;
1732*7f2fe78bSCy Schubert     else
1733*7f2fe78bSCy Schubert         return;
1734*7f2fe78bSCy Schubert 
1735*7f2fe78bSCy Schubert     /* Truncate it to the allowable renewable time. */
1736*7f2fe78bSCy Schubert     if (tgt != NULL)
1737*7f2fe78bSCy Schubert         rtime = ts_min(rtime, tgt->times.renew_till);
1738*7f2fe78bSCy Schubert     max_rlife = min(server->max_renewable_life, realm->realm_maxrlife);
1739*7f2fe78bSCy Schubert     if (client != NULL)
1740*7f2fe78bSCy Schubert         max_rlife = min(max_rlife, client->max_renewable_life);
1741*7f2fe78bSCy Schubert     rtime = ts_min(rtime, ts_incr(times->starttime, max_rlife));
1742*7f2fe78bSCy Schubert 
1743*7f2fe78bSCy Schubert     /* If the client only specified renewable-ok, don't issue a renewable
1744*7f2fe78bSCy Schubert      * ticket unless the truncated renew time exceeds the ticket end time. */
1745*7f2fe78bSCy Schubert     if (!isflagset(request->kdc_options, KDC_OPT_RENEWABLE) &&
1746*7f2fe78bSCy Schubert         !ts_after(rtime, times->endtime))
1747*7f2fe78bSCy Schubert         return;
1748*7f2fe78bSCy Schubert 
1749*7f2fe78bSCy Schubert     *tktflags |= TKT_FLG_RENEWABLE;
1750*7f2fe78bSCy Schubert     times->renew_till = rtime;
1751*7f2fe78bSCy Schubert }
1752*7f2fe78bSCy Schubert 
1753*7f2fe78bSCy Schubert /**
1754*7f2fe78bSCy Schubert  * Handle protected negotiation of FAST using enc_padata
1755*7f2fe78bSCy Schubert  * - If ENCPADATA_REQ_ENC_PA_REP is present, then:
1756*7f2fe78bSCy Schubert  * - Return ENCPADATA_REQ_ENC_PA_REP with checksum of AS-REQ from client
1757*7f2fe78bSCy Schubert  * - Include PADATA_FX_FAST in the enc_padata to indicate FAST
1758*7f2fe78bSCy Schubert  * @pre @c out_enc_padata has space for at least two more padata
1759*7f2fe78bSCy Schubert  * @param index in/out index into @c out_enc_padata for next item
1760*7f2fe78bSCy Schubert  */
1761*7f2fe78bSCy Schubert krb5_error_code
kdc_handle_protected_negotiation(krb5_context context,krb5_data * req_pkt,krb5_kdc_req * request,const krb5_keyblock * reply_key,krb5_pa_data *** out_enc_padata)1762*7f2fe78bSCy Schubert kdc_handle_protected_negotiation(krb5_context context,
1763*7f2fe78bSCy Schubert                                  krb5_data *req_pkt, krb5_kdc_req *request,
1764*7f2fe78bSCy Schubert                                  const krb5_keyblock *reply_key,
1765*7f2fe78bSCy Schubert                                  krb5_pa_data ***out_enc_padata)
1766*7f2fe78bSCy Schubert {
1767*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
1768*7f2fe78bSCy Schubert     krb5_checksum checksum;
1769*7f2fe78bSCy Schubert     krb5_data *der_cksum = NULL;
1770*7f2fe78bSCy Schubert     krb5_pa_data *pa_in;
1771*7f2fe78bSCy Schubert 
1772*7f2fe78bSCy Schubert     memset(&checksum, 0, sizeof(checksum));
1773*7f2fe78bSCy Schubert 
1774*7f2fe78bSCy Schubert     pa_in = krb5int_find_pa_data(context, request->padata,
1775*7f2fe78bSCy Schubert                                  KRB5_ENCPADATA_REQ_ENC_PA_REP);
1776*7f2fe78bSCy Schubert     if (pa_in == NULL)
1777*7f2fe78bSCy Schubert         return 0;
1778*7f2fe78bSCy Schubert 
1779*7f2fe78bSCy Schubert     /* Compute and encode a checksum over the AS-REQ. */
1780*7f2fe78bSCy Schubert     retval = krb5_c_make_checksum(context, 0, reply_key, KRB5_KEYUSAGE_AS_REQ,
1781*7f2fe78bSCy Schubert                                   req_pkt, &checksum);
1782*7f2fe78bSCy Schubert     if (retval != 0)
1783*7f2fe78bSCy Schubert         goto cleanup;
1784*7f2fe78bSCy Schubert     retval = encode_krb5_checksum(&checksum, &der_cksum);
1785*7f2fe78bSCy Schubert     if (retval != 0)
1786*7f2fe78bSCy Schubert         goto cleanup;
1787*7f2fe78bSCy Schubert 
1788*7f2fe78bSCy Schubert     retval = k5_add_pa_data_from_data(out_enc_padata,
1789*7f2fe78bSCy Schubert                                       KRB5_ENCPADATA_REQ_ENC_PA_REP,
1790*7f2fe78bSCy Schubert                                       der_cksum);
1791*7f2fe78bSCy Schubert     if (retval)
1792*7f2fe78bSCy Schubert         goto cleanup;
1793*7f2fe78bSCy Schubert 
1794*7f2fe78bSCy Schubert     /* Add a zero-length PA-FX-FAST element to the list. */
1795*7f2fe78bSCy Schubert     retval = k5_add_empty_pa_data(out_enc_padata, KRB5_PADATA_FX_FAST);
1796*7f2fe78bSCy Schubert 
1797*7f2fe78bSCy Schubert cleanup:
1798*7f2fe78bSCy Schubert     krb5_free_checksum_contents(context, &checksum);
1799*7f2fe78bSCy Schubert     krb5_free_data(context, der_cksum);
1800*7f2fe78bSCy Schubert     return retval;
1801*7f2fe78bSCy Schubert }
1802*7f2fe78bSCy Schubert 
1803*7f2fe78bSCy Schubert krb5_error_code
kdc_get_pa_pac_options(krb5_context context,krb5_pa_data ** in_padata,krb5_pa_pac_options ** pac_options_out)1804*7f2fe78bSCy Schubert kdc_get_pa_pac_options(krb5_context context, krb5_pa_data **in_padata,
1805*7f2fe78bSCy Schubert                        krb5_pa_pac_options **pac_options_out)
1806*7f2fe78bSCy Schubert {
1807*7f2fe78bSCy Schubert     krb5_pa_data *pa;
1808*7f2fe78bSCy Schubert     krb5_data der_pac_options;
1809*7f2fe78bSCy Schubert 
1810*7f2fe78bSCy Schubert     *pac_options_out = NULL;
1811*7f2fe78bSCy Schubert 
1812*7f2fe78bSCy Schubert     pa = krb5int_find_pa_data(context, in_padata, KRB5_PADATA_PAC_OPTIONS);
1813*7f2fe78bSCy Schubert     if (pa == NULL)
1814*7f2fe78bSCy Schubert         return 0;
1815*7f2fe78bSCy Schubert 
1816*7f2fe78bSCy Schubert     der_pac_options = make_data(pa->contents, pa->length);
1817*7f2fe78bSCy Schubert     return decode_krb5_pa_pac_options(&der_pac_options, pac_options_out);
1818*7f2fe78bSCy Schubert }
1819*7f2fe78bSCy Schubert 
1820*7f2fe78bSCy Schubert krb5_error_code
kdc_add_pa_pac_options(krb5_context context,krb5_kdc_req * request,krb5_pa_data *** out_enc_padata)1821*7f2fe78bSCy Schubert kdc_add_pa_pac_options(krb5_context context, krb5_kdc_req *request,
1822*7f2fe78bSCy Schubert                        krb5_pa_data ***out_enc_padata)
1823*7f2fe78bSCy Schubert {
1824*7f2fe78bSCy Schubert     krb5_error_code ret;
1825*7f2fe78bSCy Schubert     krb5_pa_pac_options *pac_options = NULL;
1826*7f2fe78bSCy Schubert     krb5_data *der_pac_options;
1827*7f2fe78bSCy Schubert 
1828*7f2fe78bSCy Schubert     ret = kdc_get_pa_pac_options(context, request->padata, &pac_options);
1829*7f2fe78bSCy Schubert     if (ret || pac_options == NULL)
1830*7f2fe78bSCy Schubert         return ret;
1831*7f2fe78bSCy Schubert 
1832*7f2fe78bSCy Schubert     /* Only return supported PAC options (currently only resource-based
1833*7f2fe78bSCy Schubert      * constrained delegation support). */
1834*7f2fe78bSCy Schubert     pac_options->options &= KRB5_PA_PAC_OPTIONS_RBCD;
1835*7f2fe78bSCy Schubert     if (pac_options->options == 0) {
1836*7f2fe78bSCy Schubert         free(pac_options);
1837*7f2fe78bSCy Schubert         return 0;
1838*7f2fe78bSCy Schubert     }
1839*7f2fe78bSCy Schubert 
1840*7f2fe78bSCy Schubert     ret = encode_krb5_pa_pac_options(pac_options, &der_pac_options);
1841*7f2fe78bSCy Schubert     free(pac_options);
1842*7f2fe78bSCy Schubert     if (ret)
1843*7f2fe78bSCy Schubert         return ret;
1844*7f2fe78bSCy Schubert 
1845*7f2fe78bSCy Schubert     ret = k5_add_pa_data_from_data(out_enc_padata, KRB5_PADATA_PAC_OPTIONS,
1846*7f2fe78bSCy Schubert                                    der_pac_options);
1847*7f2fe78bSCy Schubert     krb5_free_data(context, der_pac_options);
1848*7f2fe78bSCy Schubert     return ret;
1849*7f2fe78bSCy Schubert }
1850*7f2fe78bSCy Schubert 
1851*7f2fe78bSCy Schubert krb5_error_code
kdc_get_pa_pac_rbcd(krb5_context context,krb5_pa_data ** in_padata,krb5_boolean * supported)1852*7f2fe78bSCy Schubert kdc_get_pa_pac_rbcd(krb5_context context, krb5_pa_data **in_padata,
1853*7f2fe78bSCy Schubert                     krb5_boolean *supported)
1854*7f2fe78bSCy Schubert {
1855*7f2fe78bSCy Schubert     krb5_error_code retval;
1856*7f2fe78bSCy Schubert     krb5_pa_pac_options *pac_options = NULL;
1857*7f2fe78bSCy Schubert 
1858*7f2fe78bSCy Schubert     *supported = FALSE;
1859*7f2fe78bSCy Schubert 
1860*7f2fe78bSCy Schubert     retval = kdc_get_pa_pac_options(context, in_padata, &pac_options);
1861*7f2fe78bSCy Schubert     if (retval || !pac_options)
1862*7f2fe78bSCy Schubert         return retval;
1863*7f2fe78bSCy Schubert 
1864*7f2fe78bSCy Schubert     if (pac_options->options & KRB5_PA_PAC_OPTIONS_RBCD)
1865*7f2fe78bSCy Schubert         *supported = TRUE;
1866*7f2fe78bSCy Schubert 
1867*7f2fe78bSCy Schubert     free(pac_options);
1868*7f2fe78bSCy Schubert     return 0;
1869*7f2fe78bSCy Schubert }
1870*7f2fe78bSCy Schubert 
1871*7f2fe78bSCy Schubert /*
1872*7f2fe78bSCy Schubert  * Although the KDC doesn't call this function directly,
1873*7f2fe78bSCy Schubert  * process_tcp_connection_read() in net-server.c does call it.
1874*7f2fe78bSCy Schubert  */
1875*7f2fe78bSCy Schubert krb5_error_code
make_toolong_error(void * handle,krb5_data ** out)1876*7f2fe78bSCy Schubert make_toolong_error (void *handle, krb5_data **out)
1877*7f2fe78bSCy Schubert {
1878*7f2fe78bSCy Schubert     krb5_error errpkt;
1879*7f2fe78bSCy Schubert     krb5_error_code retval;
1880*7f2fe78bSCy Schubert     krb5_data *scratch;
1881*7f2fe78bSCy Schubert     struct server_handle *h = handle;
1882*7f2fe78bSCy Schubert 
1883*7f2fe78bSCy Schubert     retval = krb5_us_timeofday(h->kdc_err_context,
1884*7f2fe78bSCy Schubert                                &errpkt.stime, &errpkt.susec);
1885*7f2fe78bSCy Schubert     if (retval)
1886*7f2fe78bSCy Schubert         return retval;
1887*7f2fe78bSCy Schubert     errpkt.error = KRB_ERR_FIELD_TOOLONG;
1888*7f2fe78bSCy Schubert     errpkt.server = h->kdc_realmlist[0]->realm_tgsprinc;
1889*7f2fe78bSCy Schubert     errpkt.client = NULL;
1890*7f2fe78bSCy Schubert     errpkt.cusec = 0;
1891*7f2fe78bSCy Schubert     errpkt.ctime = 0;
1892*7f2fe78bSCy Schubert     errpkt.text.length = 0;
1893*7f2fe78bSCy Schubert     errpkt.text.data = 0;
1894*7f2fe78bSCy Schubert     errpkt.e_data.length = 0;
1895*7f2fe78bSCy Schubert     errpkt.e_data.data = 0;
1896*7f2fe78bSCy Schubert     scratch = malloc(sizeof(*scratch));
1897*7f2fe78bSCy Schubert     if (scratch == NULL)
1898*7f2fe78bSCy Schubert         return ENOMEM;
1899*7f2fe78bSCy Schubert     retval = krb5_mk_error(h->kdc_err_context, &errpkt, scratch);
1900*7f2fe78bSCy Schubert     if (retval) {
1901*7f2fe78bSCy Schubert         free(scratch);
1902*7f2fe78bSCy Schubert         return retval;
1903*7f2fe78bSCy Schubert     }
1904*7f2fe78bSCy Schubert 
1905*7f2fe78bSCy Schubert     *out = scratch;
1906*7f2fe78bSCy Schubert     return 0;
1907*7f2fe78bSCy Schubert }
1908*7f2fe78bSCy Schubert 
reset_for_hangup(void * ctx)1909*7f2fe78bSCy Schubert void reset_for_hangup(void *ctx)
1910*7f2fe78bSCy Schubert {
1911*7f2fe78bSCy Schubert     int k;
1912*7f2fe78bSCy Schubert     struct server_handle *h = ctx;
1913*7f2fe78bSCy Schubert 
1914*7f2fe78bSCy Schubert     for (k = 0; k < h->kdc_numrealms; k++)
1915*7f2fe78bSCy Schubert         krb5_db_refresh_config(h->kdc_realmlist[k]->realm_context);
1916*7f2fe78bSCy Schubert }
1917