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