4 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
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.
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.
27 * Utility functions for the KDC implementation.
39 #include "adm_proto.h"
43 static char *kdc_current_rcname
= (char *) NULL
;
44 krb5_deltat rc_lifetime
; /* See kdc_initialize_rcache() */
49 * initialize the replay cache.
52 kdc_initialize_rcache(krb5_context kcontext
, char *rcache_name
)
54 krb5_error_code retval
;
58 rcname
= (rcache_name
) ? rcache_name
: kdc_current_rcname
;
60 /* rc_lifetime used elsewhere to verify we're not */
61 /* replaying really old data */
62 rc_lifetime
= kcontext
->clockskew
;
66 if (!(retval
= krb5_rc_resolve_full(kcontext
, &kdc_rcache
, rcname
))) {
67 /* Recover or initialize the replay cache */
68 if (!(retval
= krb5_rc_recover(kcontext
, kdc_rcache
)) ||
69 !(retval
= krb5_rc_initialize(kcontext
,
73 /* Expunge the replay cache */
74 if (!(retval
= krb5_rc_expunge(kcontext
, kdc_rcache
))) {
75 sname
= kdc_current_rcname
;
76 kdc_current_rcname
= strdup(rcname
);
81 krb5_rc_close(kcontext
, kdc_rcache
);
88 * concatenate first two authdata arrays, returning an allocated replacement.
89 * The replacement should be freed with krb5_free_authdata().
92 concat_authorization_data(krb5_authdata
**first
, krb5_authdata
**second
,
93 krb5_authdata
***output
)
96 register krb5_authdata
**ptr
, **retdata
;
98 /* count up the entries */
101 for (ptr
= first
; *ptr
; ptr
++)
104 for (ptr
= second
; *ptr
; ptr
++)
107 retdata
= (krb5_authdata
**)malloc((i
+1)*sizeof(*retdata
));
110 retdata
[i
] = 0; /* null-terminated array */
111 for (i
= 0, j
= 0, ptr
= first
; j
< 2 ; ptr
= second
, j
++)
112 while (ptr
&& *ptr
) {
113 /* now walk & copy */
114 retdata
[i
] = (krb5_authdata
*)malloc(sizeof(*retdata
[i
]));
116 krb5_free_authdata(kdc_context
, retdata
);
120 if (!(retdata
[i
]->contents
=
121 (krb5_octet
*)malloc(retdata
[i
]->length
))) {
122 free((char *)retdata
[i
]);
124 krb5_free_authdata(kdc_context
, retdata
);
127 memcpy((char *) retdata
[i
]->contents
,
128 (char *)(*ptr
)->contents
,
139 realm_compare(krb5_principal princ1
, krb5_principal princ2
)
141 krb5_data
*realm1
= krb5_princ_realm(kdc_context
, princ1
);
142 krb5_data
*realm2
= krb5_princ_realm(kdc_context
, princ2
);
144 return((realm1
->length
== realm2
->length
) &&
145 !memcmp(realm1
->data
, realm2
->data
, realm1
->length
));
149 * Returns TRUE if the kerberos principal is the name of a Kerberos ticket
152 krb5_boolean
krb5_is_tgs_principal(krb5_principal principal
)
154 if ((krb5_princ_size(kdc_context
, principal
) > 0) &&
155 (krb5_princ_component(kdc_context
, principal
, 0)->length
==
156 KRB5_TGS_NAME_SIZE
) &&
157 (!memcmp(krb5_princ_component(kdc_context
, principal
, 0)->data
,
158 KRB5_TGS_NAME
, KRB5_TGS_NAME_SIZE
)))
164 * given authentication data (provides seed for checksum), verify checksum
167 static krb5_error_code
168 comp_cksum(krb5_context kcontext
, krb5_data
*source
, krb5_ticket
*ticket
,
169 krb5_checksum
*his_cksum
)
171 krb5_error_code retval
;
174 if (!krb5_c_valid_cksumtype(his_cksum
->checksum_type
))
175 return KRB5KDC_ERR_SUMTYPE_NOSUPP
;
177 /* must be collision proof */
178 if (!krb5_c_is_coll_proof_cksum(his_cksum
->checksum_type
))
179 return KRB5KRB_AP_ERR_INAPP_CKSUM
;
181 /* verify checksum */
182 if ((retval
= krb5_c_verify_checksum(kcontext
, ticket
->enc_part2
->session
,
183 KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM
,
184 source
, his_cksum
, &valid
)))
188 return(KRB5KRB_AP_ERR_BAD_INTEGRITY
);
194 kdc_process_tgs_req(krb5_kdc_req
*request
, const krb5_fulladdr
*from
,
195 krb5_data
*pkt
, krb5_ticket
**ticket
,
196 krb5_keyblock
**subkey
)
198 krb5_pa_data
** tmppa
;
200 krb5_error_code retval
;
202 krb5_data
* scratch
= NULL
;
203 krb5_boolean foreign_server
= FALSE
;
204 krb5_auth_context auth_context
= NULL
;
205 krb5_authenticator
* authenticator
= NULL
;
206 krb5_checksum
* his_cksum
= NULL
;
207 /* krb5_keyblock * key = NULL;*/
208 /* krb5_kvno kvno = 0;*/
210 if (!request
->padata
)
211 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
212 for (tmppa
= request
->padata
; *tmppa
; tmppa
++) {
213 if ((*tmppa
)->pa_type
== KRB5_PADATA_AP_REQ
)
216 if (!*tmppa
) /* cannot find any AP_REQ */
217 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
219 scratch1
.length
= (*tmppa
)->length
;
220 scratch1
.data
= (char *)(*tmppa
)->contents
;
221 if ((retval
= decode_krb5_ap_req(&scratch1
, &apreq
)))
224 if (isflagset(apreq
->ap_options
, AP_OPTS_USE_SESSION_KEY
) ||
225 isflagset(apreq
->ap_options
, AP_OPTS_MUTUAL_REQUIRED
)) {
226 krb5_klog_syslog(LOG_INFO
, "TGS_REQ: SESSION KEY or MUTUAL");
227 retval
= KRB5KDC_ERR_POLICY
;
231 /* If the "server" principal in the ticket is not something
232 in the local realm, then we must refuse to service the request
233 if the client claims to be from the local realm.
235 If we don't do this, then some other realm's nasty KDC can
236 claim to be authenticating a client from our realm, and we'll
237 give out tickets concurring with it!
239 we set a flag here for checking below.
241 if ((krb5_princ_realm(kdc_context
, apreq
->ticket
->server
)->length
!=
242 krb5_princ_realm(kdc_context
, tgs_server
)->length
) ||
243 memcmp(krb5_princ_realm(kdc_context
, apreq
->ticket
->server
)->data
,
244 krb5_princ_realm(kdc_context
, tgs_server
)->data
,
245 krb5_princ_realm(kdc_context
, tgs_server
)->length
))
246 foreign_server
= TRUE
;
248 if ((retval
= krb5_auth_con_init(kdc_context
, &auth_context
)))
251 if ((retval
= krb5_auth_con_setaddrs(kdc_context
, auth_context
, NULL
,
253 goto cleanup_auth_context
;
255 if ((retval
= krb5_auth_con_setrcache(kdc_context
, auth_context
,
257 goto cleanup_auth_context
;
261 if ((retval = kdc_get_server_key(apreq->ticket, &key, &kvno)))
262 goto cleanup_auth_context;
266 * XXX This is currently wrong but to fix it will require making a
267 * new keytab for groveling over the kdb.
270 retval = krb5_auth_con_setuseruserkey(kdc_context, auth_context, key);
271 krb5_free_keyblock(kdc_context, key);
273 goto cleanup_auth_context;
276 if ((retval
= krb5_rd_req_decoded_anyflag(kdc_context
, &auth_context
, apreq
,
277 apreq
->ticket
->server
,
278 kdc_active_realm
->realm_keytab
,
282 * I'm not so sure that this is right, but it's better than nothing
285 * If we choke in the rd_req because of the replay cache, then attempt
286 * to reinitialize the replay cache because somebody could have deleted
287 * it from underneath us (e.g. a cron job)
289 if ((retval
== KRB5_RC_IO_IO
) ||
290 (retval
== KRB5_RC_IO_UNKNOWN
)) {
291 (void) krb5_rc_close(kdc_context
, kdc_rcache
);
292 kdc_rcache
= (krb5_rcache
) NULL
;
293 if (!(retval
= kdc_initialize_rcache(kdc_context
, (char *) NULL
))) {
294 if ((retval
= krb5_auth_con_setrcache(kdc_context
, auth_context
,
296 (retval
= krb5_rd_req_decoded_anyflag(kdc_context
, &auth_context
,
297 apreq
, apreq
->ticket
->server
,
298 kdc_active_realm
->realm_keytab
,
301 goto cleanup_auth_context
;
304 goto cleanup_auth_context
;
306 goto cleanup_auth_context
;
310 /* "invalid flag" tickets can must be used to validate */
311 if (isflagset((*ticket
)->enc_part2
->flags
, TKT_FLG_INVALID
)
312 && !isflagset(request
->kdc_options
, KDC_OPT_VALIDATE
)) {
313 retval
= KRB5KRB_AP_ERR_TKT_INVALID
;
314 goto cleanup_auth_context
;
317 if ((retval
= krb5_auth_con_getrecvsubkey(kdc_context
,
318 auth_context
, subkey
)))
319 goto cleanup_auth_context
;
321 if ((retval
= krb5_auth_con_getauthenticator(kdc_context
, auth_context
,
323 goto cleanup_auth_context
;
325 /* Check for a checksum */
326 if (!(his_cksum
= authenticator
->checksum
)) {
327 retval
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
328 goto cleanup_authenticator
;
331 /* make sure the client is of proper lineage (see above) */
332 if (foreign_server
) {
333 krb5_data
*tkt_realm
= krb5_princ_realm(kdc_context
,
334 (*ticket
)->enc_part2
->client
);
335 krb5_data
*tgs_realm
= krb5_princ_realm(kdc_context
, tgs_server
);
336 if (tkt_realm
->length
== tgs_realm
->length
&&
337 !memcmp(tkt_realm
->data
, tgs_realm
->data
, tgs_realm
->length
)) {
338 /* someone in a foreign realm claiming to be local */
339 krb5_klog_syslog(LOG_INFO
, "PROCESS_TGS: failed lineage check");
340 retval
= KRB5KDC_ERR_POLICY
;
341 goto cleanup_authenticator
;
346 * Check application checksum vs. tgs request
348 * We try checksumming the req-body two different ways: first we
349 * try reaching into the raw asn.1 stream (if available), and
350 * checksum that directly; if that fails, then we try encoding
351 * using our local asn.1 library.
353 if (pkt
&& (fetch_asn1_field((unsigned char *) pkt
->data
,
354 1, 4, &scratch1
) >= 0)) {
355 if (comp_cksum(kdc_context
, &scratch1
, *ticket
, his_cksum
)) {
356 if (!(retval
= encode_krb5_kdc_req_body(request
, &scratch
)))
357 retval
= comp_cksum(kdc_context
, scratch
, *ticket
, his_cksum
);
358 krb5_free_data(kdc_context
, scratch
);
362 cleanup_authenticator
:
363 krb5_free_authenticator(kdc_context
, authenticator
);
365 cleanup_auth_context
:
366 /* We do not want the free of the auth_context to close the rcache */
368 (void) krb5_auth_con_setrcache(kdc_context
, auth_context
, 0);
370 krb5_auth_con_free(kdc_context
, auth_context
);
373 krb5_free_ap_req(kdc_context
, apreq
);
377 /* XXX This function should no longer be necessary.
378 * The KDC should take the keytab associated with the realm and pass that to
379 * the krb5_rd_req_decode(). --proven
381 * It's actually still used by do_tgs_req() for u2u auth, and not too
385 kdc_get_server_key(krb5_ticket
*ticket
, krb5_keyblock
**key
, krb5_kvno
*kvno
)
387 krb5_error_code retval
;
388 krb5_db_entry server
;
391 krb5_key_data
* server_key
;
395 if ((retval
= krb5_db_get_principal(kdc_context
, ticket
->server
,
401 krb5_db_free_principal(kdc_context
, &server
, nprincs
);
402 return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE
);
403 } else if (nprincs
!= 1) {
406 krb5_db_free_principal(kdc_context
, &server
, nprincs
);
407 if (!krb5_unparse_name(kdc_context
, ticket
->server
, &sname
)) {
409 krb5_klog_syslog(LOG_ERR
,"TGS_REQ: UNKNOWN SERVER: server='%s'",
413 return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
);
415 retval
= krb5_dbe_find_enctype(kdc_context
, &server
,
416 ticket
->enc_part
.enctype
, -1,
417 ticket
->enc_part
.kvno
, &server_key
);
421 retval
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
424 *kvno
= server_key
->key_data_kvno
;
425 if ((*key
= (krb5_keyblock
*)malloc(sizeof **key
))) {
426 retval
= krb5_dbekd_decrypt_key_data(kdc_context
, &master_keyblock
,
432 krb5_db_free_principal(kdc_context
, &server
, nprincs
);
436 /* This probably wants to be updated if you support last_req stuff */
438 static krb5_last_req_entry nolrentry
= { KV5M_LAST_REQ_ENTRY
, KRB5_LRQ_NONE
, 0 };
439 static krb5_last_req_entry
*nolrarray
[] = { &nolrentry
, 0 };
442 fetch_last_req_info(krb5_db_entry
*dbentry
, krb5_last_req_entry
***lrentry
)
444 *lrentry
= nolrarray
;
449 /* XXX! This is a temporary place-holder */
452 check_hot_list(krb5_ticket
*ticket
)
458 #define MAX_REALM_LN 500
462 * subrealm - determine if r2 is a subrealm of r1
464 * SUBREALM takes two realms, r1 and r2, and
465 * determines if r2 is a subrealm of r1.
466 * r2 is a subrealm of r1 if (r1 is a prefix
467 * of r2 AND r1 and r2 begin with a /) or if
468 * (r1 is a suffix of r2 and neither r1 nor r2
471 * RETURNS: If r2 is a subrealm, and r1 is a prefix, the number
472 * of characters in the suffix of r2 is returned as a
475 * If r2 is a subrealm, and r1 is a suffix, the number
476 * of characters in the prefix of r2 is returned as a
479 * If r2 is not a subrealm, SUBREALM returns 0.
482 subrealm(char *r1
, char *r2
)
487 if(l2
<= l1
) return(0);
488 if((*r1
== '/') && (*r2
== '/') && (strncmp(r1
,r2
,l1
) == 0)) return(l1
-l2
);
489 if((*r1
!= '/') && (*r2
!= '/') && (strncmp(r1
,r2
+l2
-l1
,l1
) == 0))
495 * add_to_transited Adds the name of the realm which issued the
496 * ticket granting ticket on which the new ticket to
497 * be issued is based (note that this is the same as
498 * the realm of the server listed in the ticket
501 * ASSUMPTIONS: This procedure assumes that the transited field from
502 * the existing ticket granting ticket already appears
503 * in compressed form. It will add the new realm while
504 * maintaining that form. As long as each successive
505 * realm is added using this (or a similar) routine, the
506 * transited field will be in compressed form. The
507 * basis step is an empty transited field which is, by
508 * its nature, in its most compressed form.
510 * ARGUMENTS: krb5_data *tgt_trans Transited field from TGT
511 * krb5_data *new_trans The transited field for the new ticket
512 * krb5_principal tgs Name of ticket granting server
513 * This includes the realm of the KDC
514 * that issued the ticket granting
515 * ticket. This is the realm that is
516 * to be added to the transited field.
517 * krb5_principal client Name of the client
518 * krb5_principal server The name of the requested server.
519 * This may be the an intermediate
520 * ticket granting server.
522 * The last two argument are needed since they are
523 * implicitly part of the transited field of the new ticket
524 * even though they are not explicitly listed.
526 * RETURNS: krb5_error_code - Success, or out of memory
528 * MODIFIES: new_trans: ->length will contain the length of the new
531 * If ->data was not null when this procedure
532 * is called, the memory referenced by ->data
533 * will be deallocated.
535 * Memory will be allocated for the new transited field
536 * ->data will be updated to point to the newly
539 * BUGS: The space allocated for the new transited field is the
540 * maximum that might be needed given the old transited field,
541 * and the realm to be added. This length is calculated
542 * assuming that no compression of the new realm is possible.
543 * This has no adverse consequences other than the allocation
544 * of more space than required.
546 * This procedure will not yet use the null subfield notation,
547 * and it will get confused if it sees it.
549 * This procedure does not check for quoted commas in realm
554 data2string (krb5_data
*d
)
557 s
= malloc(d
->length
+ 1);
559 memcpy(s
, d
->data
, d
->length
);
566 add_to_transited(krb5_data
*tgt_trans
, krb5_data
*new_trans
,
567 krb5_principal tgs
, krb5_principal client
,
568 krb5_principal server
)
570 krb5_error_code retval
;
573 char *otrans
, *otrans_ptr
;
575 /* The following are for stepping through the transited field */
577 char prev
[MAX_REALM_LN
];
578 char next
[MAX_REALM_LN
];
579 char current
[MAX_REALM_LN
];
580 char exp
[MAX_REALM_LN
]; /* Expanded current realm name */
583 int clst
, nlst
; /* count of last character in current and next */
584 int pl
, pl1
; /* prefix length */
585 int added
; /* TRUE = new realm has been added */
587 realm
= data2string(krb5_princ_realm(kdc_context
, tgs
));
591 otrans
= data2string(tgt_trans
);
592 if (otrans
== NULL
) {
596 /* Keep track of start so we can free */
600 +1 for extra comma which may be added between
601 +1 for potential space when leading slash in realm */
602 if (!(trans
= (char *) malloc(strlen(realm
) + strlen(otrans
) + 3))) {
607 free(new_trans
->data
);
608 new_trans
->data
= trans
;
609 new_trans
->length
= 0;
613 /* For the purpose of appending, the realm preceding the first */
614 /* realm in the transited field is considered the null realm */
618 /* read field into current */
619 for (i
= 0; *otrans
!= '\0';) {
620 if (*otrans
== '\\') {
621 if (*(++otrans
) == '\0')
626 if (*otrans
== ',') {
630 current
[i
++] = *otrans
++;
631 if (i
>= MAX_REALM_LN
) {
632 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
638 added
= (krb5_princ_realm(kdc_context
, client
)->length
== strlen(realm
) &&
639 !strncmp(krb5_princ_realm(kdc_context
, client
)->data
, realm
, strlen(realm
))) ||
640 (krb5_princ_realm(kdc_context
, server
)->length
== strlen(realm
) &&
641 !strncmp(krb5_princ_realm(kdc_context
, server
)->data
, realm
, strlen(realm
)));
645 /* figure out expanded form of current name */
647 clst
= strlen(current
) - 1;
648 if (current
[0] == ' ') {
649 strncpy(exp
, current
+1, sizeof(exp
) - 1);
650 exp
[sizeof(exp
) - 1] = '\0';
652 else if ((current
[0] == '/') && (prev
[0] == '/')) {
653 strncpy(exp
, prev
, sizeof(exp
) - 1);
654 exp
[sizeof(exp
) - 1] = '\0';
655 if (strlen(exp
) + strlen(current
) + 1 >= MAX_REALM_LN
) {
656 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
659 strncat(exp
, current
, sizeof(exp
) - 1 - strlen(exp
));
661 else if (current
[clst
] == '.') {
662 strncpy(exp
, current
, sizeof(exp
) - 1);
663 exp
[sizeof(exp
) - 1] = '\0';
664 if (strlen(exp
) + strlen(prev
) + 1 >= MAX_REALM_LN
) {
665 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
668 strncat(exp
, prev
, sizeof(exp
) - 1 - strlen(exp
));
671 strncpy(exp
, current
, sizeof(exp
) - 1);
672 exp
[sizeof(exp
) - 1] = '\0';
675 /* read field into next */
676 for (i
= 0; *otrans
!= '\0';) {
677 if (*otrans
== '\\') {
678 if (*(++otrans
) == '\0')
683 if (*otrans
== ',') {
687 next
[i
++] = *otrans
++;
688 if (i
>= MAX_REALM_LN
) {
689 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
696 if (!strcmp(exp
, realm
)) added
= TRUE
;
698 /* If we still have to insert the new realm */
702 /* Is the next field compressed? If not, and if the new */
703 /* realm is a subrealm of the current realm, compress */
704 /* the new realm, and insert immediately following the */
705 /* current one. Note that we can not do this if the next*/
706 /* field is already compressed since it would mess up */
707 /* what has already been done. In most cases, this is */
708 /* not a problem because the realm to be added will be a */
709 /* subrealm of the next field too, and we will catch */
710 /* it in a future iteration. */
712 /* Note that the second test here is an unsigned comparison,
713 so the first half (or a cast) is also required. */
714 assert(nlst
< 0 || nlst
< sizeof(next
));
715 if ((nlst
< 0 || next
[nlst
] != '.') &&
717 (pl
= subrealm(exp
, realm
))) {
719 current
[sizeof(current
) - 1] = '\0';
720 if (strlen(current
) + (pl
>0?pl
:-pl
) + 2 >= MAX_REALM_LN
) {
721 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
724 strncat(current
, ",", sizeof(current
) - 1 - strlen(current
));
726 strncat(current
, realm
, (unsigned) pl
);
729 strncat(current
, realm
+strlen(realm
)+pl
, (unsigned) (-pl
));
733 /* Whether or not the next field is compressed, if the */
734 /* realm to be added is a superrealm of the current realm,*/
735 /* then the current realm can be compressed. First the */
736 /* realm to be added must be compressed relative to the */
737 /* previous realm (if possible), and then the current */
738 /* realm compressed relative to the new realm. Note that */
739 /* if the realm to be added is also a superrealm of the */
740 /* previous realm, it would have been added earlier, and */
741 /* we would not reach this step this time around. */
743 else if ((pl
= subrealm(realm
, exp
))) {
746 if ((pl1
= subrealm(prev
,realm
))) {
747 if (strlen(current
) + (pl1
>0?pl1
:-pl1
) + 1 >= MAX_REALM_LN
) {
748 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
752 strncat(current
, realm
, (unsigned) pl1
);
755 strncat(current
, realm
+strlen(realm
)+pl1
, (unsigned) (-pl1
));
758 else { /* If not a subrealm */
759 if ((realm
[0] == '/') && prev
[0]) {
760 if (strlen(current
) + 2 >= MAX_REALM_LN
) {
761 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
764 strncat(current
, " ", sizeof(current
) - 1 - strlen(current
));
765 current
[sizeof(current
) - 1] = '\0';
767 if (strlen(current
) + strlen(realm
) + 1 >= MAX_REALM_LN
) {
768 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
771 strncat(current
, realm
, sizeof(current
) - 1 - strlen(current
));
772 current
[sizeof(current
) - 1] = '\0';
774 if (strlen(current
) + (pl
>0?pl
:-pl
) + 2 >= MAX_REALM_LN
) {
775 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
778 strncat(current
,",", sizeof(current
) - 1 - strlen(current
));
779 current
[sizeof(current
) - 1] = '\0';
781 strncat(current
, exp
, (unsigned) pl
);
784 strncat(current
, exp
+strlen(exp
)+pl
, (unsigned)(-pl
));
789 if (new_trans
->length
!= 0) {
790 if (strlen(trans
) + 2 >= MAX_REALM_LN
) {
791 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
796 if (strlen(trans
) + strlen(current
) + 1 >= MAX_REALM_LN
) {
797 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
800 strcat(trans
, current
);
801 new_trans
->length
= strlen(trans
);
803 strncpy(prev
, exp
, sizeof(prev
) - 1);
804 prev
[sizeof(prev
) - 1] = '\0';
805 strncpy(current
, next
, sizeof(current
) - 1);
806 current
[sizeof(current
) - 1] = '\0';
810 if (new_trans
->length
!= 0) {
811 if (strlen(trans
) + 2 >= MAX_REALM_LN
) {
812 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
817 if((realm
[0] == '/') && trans
[0]) {
818 if (strlen(trans
) + 2 >= MAX_REALM_LN
) {
819 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
824 if (strlen(trans
) + strlen(realm
) + 1 >= MAX_REALM_LN
) {
825 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
828 strcat(trans
, realm
);
829 new_trans
->length
= strlen(trans
);
840 * Routines that validate a AS request; checks a lot of things. :-)
842 * Returns a Kerberos protocol error number, which is _not_ the same
843 * as a com_err error number!
845 #define AS_INVALID_OPTIONS (KDC_OPT_FORWARDED | KDC_OPT_PROXY |\
846 KDC_OPT_VALIDATE | KDC_OPT_RENEW | KDC_OPT_ENC_TKT_IN_SKEY)
848 validate_as_request(register krb5_kdc_req
*request
, krb5_db_entry client
,
849 krb5_db_entry server
, krb5_timestamp kdc_time
,
855 * If an option is set that is only allowed in TGS requests, complain.
857 if (request
->kdc_options
& AS_INVALID_OPTIONS
) {
858 *status
= "INVALID AS OPTIONS";
859 return KDC_ERR_BADOPTION
;
862 /* The client's password must not be expired, unless the server is
863 a KRB5_KDC_PWCHANGE_SERVICE. */
864 if (client
.pw_expiration
&& client
.pw_expiration
< kdc_time
&&
865 !isflagset(server
.attributes
, KRB5_KDB_PWCHANGE_SERVICE
)) {
866 *status
= "CLIENT KEY EXPIRED";
867 #ifdef KRBCONF_VAGUE_ERRORS
868 return(KRB_ERR_GENERIC
);
870 return(KDC_ERR_KEY_EXP
);
874 /* The client must not be expired */
875 if (client
.expiration
&& client
.expiration
< kdc_time
) {
876 *status
= "CLIENT EXPIRED";
877 #ifdef KRBCONF_VAGUE_ERRORS
878 return(KRB_ERR_GENERIC
);
880 return(KDC_ERR_NAME_EXP
);
884 /* The server must not be expired */
885 if (server
.expiration
&& server
.expiration
< kdc_time
) {
886 *status
= "SERVICE EXPIRED";
887 return(KDC_ERR_SERVICE_EXP
);
891 * If the client requires password changing, then only allow the
894 if (isflagset(client
.attributes
, KRB5_KDB_REQUIRES_PWCHANGE
) &&
895 !isflagset(server
.attributes
, KRB5_KDB_PWCHANGE_SERVICE
)) {
896 *status
= "REQUIRED PWCHANGE";
897 return(KDC_ERR_KEY_EXP
);
900 /* Client and server must allow postdating tickets */
901 if ((isflagset(request
->kdc_options
, KDC_OPT_ALLOW_POSTDATE
) ||
902 isflagset(request
->kdc_options
, KDC_OPT_POSTDATED
)) &&
903 (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_POSTDATED
) ||
904 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_POSTDATED
))) {
905 *status
= "POSTDATE NOT ALLOWED";
906 return(KDC_ERR_CANNOT_POSTDATE
);
909 /* Client and server must allow forwardable tickets */
910 if (isflagset(request
->kdc_options
, KDC_OPT_FORWARDABLE
) &&
911 (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_FORWARDABLE
) ||
912 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_FORWARDABLE
))) {
913 *status
= "FORWARDABLE NOT ALLOWED";
914 return(KDC_ERR_POLICY
);
917 /* Client and server must allow renewable tickets */
918 if (isflagset(request
->kdc_options
, KDC_OPT_RENEWABLE
) &&
919 (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_RENEWABLE
) ||
920 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_RENEWABLE
))) {
921 *status
= "RENEWABLE NOT ALLOWED";
922 return(KDC_ERR_POLICY
);
925 /* Client and server must allow proxiable tickets */
926 if (isflagset(request
->kdc_options
, KDC_OPT_PROXIABLE
) &&
927 (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_PROXIABLE
) ||
928 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_PROXIABLE
))) {
929 *status
= "PROXIABLE NOT ALLOWED";
930 return(KDC_ERR_POLICY
);
933 /* Check to see if client is locked out */
934 if (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_ALL_TIX
)) {
935 *status
= "CLIENT LOCKED OUT";
936 return(KDC_ERR_C_PRINCIPAL_UNKNOWN
);
939 /* Check to see if server is locked out */
940 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_ALL_TIX
)) {
941 *status
= "SERVICE LOCKED OUT";
942 return(KDC_ERR_S_PRINCIPAL_UNKNOWN
);
945 /* Check to see if server is allowed to be a service */
946 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_SVR
)) {
947 *status
= "SERVICE NOT ALLOWED";
948 return(KDC_ERR_S_PRINCIPAL_UNKNOWN
);
952 * Check against local policy
954 errcode
= against_local_policy_as(request
, server
, client
,
962 #define ASN1_ID_CLASS (0xc0)
963 #define ASN1_ID_TYPE (0x20)
964 #define ASN1_ID_TAG (0x1f)
965 #define ASN1_CLASS_UNIV (0)
966 #define ASN1_CLASS_APP (1)
967 #define ASN1_CLASS_CTX (2)
968 #define ASN1_CLASS_PRIV (3)
969 #define asn1_id_constructed(x) (x & ASN1_ID_TYPE)
970 #define asn1_id_primitive(x) (!asn1_id_constructed(x))
971 #define asn1_id_class(x) ((x & ASN1_ID_CLASS) >> 6)
972 #define asn1_id_tag(x) (x & ASN1_ID_TAG)
975 * asn1length - return encoded length of value.
977 * passed a pointer into the asn.1 stream, which is updated
978 * to point right after the length bits.
980 * returns -1 on failure.
983 asn1length(unsigned char **astream
)
985 int length
; /* resulting length */
986 int sublen
; /* sublengths */
987 int blen
; /* bytes of length */
988 unsigned char *p
; /* substring searching */
990 if (**astream
& 0x80) {
991 blen
= **astream
& 0x7f;
995 for (++*astream
, length
= 0; blen
; ++*astream
, blen
--) {
996 length
= (length
<< 8) | **astream
;
999 /* indefinite length, figure out by hand */
1003 /* compute value length. */
1004 if ((sublen
= asn1length(&p
)) < 0) {
1008 /* check for termination */
1009 if ((!*p
++) && (!*p
)) {
1014 length
= p
- *astream
;
1024 * fetch_asn1_field - return raw asn.1 stream of subfield.
1026 * this routine is passed a context-dependent tag number and "level" and returns
1027 * the size and length of the corresponding level subfield.
1029 * levels and are numbered starting from 1.
1031 * returns 0 on success, -1 otherwise.
1034 fetch_asn1_field(unsigned char *astream
, unsigned int level
,
1035 unsigned int field
, krb5_data
*data
)
1037 unsigned char *estream
; /* end of stream */
1038 int classes
; /* # classes seen so far this level */
1039 unsigned int levels
= 0; /* levels seen so far */
1040 int lastlevel
= 1000; /* last level seen */
1041 int length
; /* various lengths */
1042 int tag
; /* tag number */
1043 unsigned char savelen
; /* saved length of our field */
1046 /* we assume that the first identifier/length will tell us
1047 how long the entire stream is. */
1050 if ((length
= asn1length(&astream
)) < 0) {
1054 /* search down the stream, checking identifiers. we process identifiers
1055 until we hit the "level" we want, and then process that level for our
1056 subfield, always making sure we don't go off the end of the stream. */
1057 while (astream
< estream
) {
1058 if (!asn1_id_constructed(*astream
)) {
1061 if (asn1_id_class(*astream
) == ASN1_CLASS_CTX
) {
1062 if ((tag
= (int)asn1_id_tag(*astream
)) <= lastlevel
) {
1067 if (levels
== level
) {
1068 /* in our context-dependent class, is this the one we're looking for ? */
1070 /* return length and data */
1073 if ((data
->length
= asn1length(&astream
)) < 0) {
1076 /* if the field length is indefinite, we will have to subtract two
1077 (terminating octets) from the length returned since we don't want
1078 to pass any info from the "wrapper" back. asn1length will always return
1079 the *total* length of the field, not just what's contained in it */
1080 if ((savelen
& 0xff) == 0x80) {
1083 data
->data
= (char *)astream
;
1085 } else if (tag
<= classes
) {
1086 /* we've seen this class before, something must be wrong */
1093 /* if we're not on our level yet, process this value. otherwise skip over it */
1095 if ((length
= asn1length(&astream
)) < 0) {
1098 if (levels
== level
) {
1106 * Routines that validate a TGS request; checks a lot of things. :-)
1108 * Returns a Kerberos protocol error number, which is _not_ the same
1109 * as a com_err error number!
1111 #define TGS_OPTIONS_HANDLED (KDC_OPT_FORWARDABLE | KDC_OPT_FORWARDED | \
1112 KDC_OPT_PROXIABLE | KDC_OPT_PROXY | \
1113 KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED | \
1114 KDC_OPT_RENEWABLE | KDC_OPT_RENEWABLE_OK | \
1115 KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_RENEW | \
1118 #define NO_TGT_OPTION (KDC_OPT_FORWARDED | KDC_OPT_PROXY | KDC_OPT_RENEW | \
1122 validate_tgs_request(register krb5_kdc_req
*request
, krb5_db_entry server
,
1123 krb5_ticket
*ticket
, krb5_timestamp kdc_time
,
1124 const char **status
)
1130 * If an illegal option is set, ignore it.
1132 request
->kdc_options
&= TGS_OPTIONS_HANDLED
;
1134 /* Check to see if server has expired */
1135 if (server
.expiration
&& server
.expiration
< kdc_time
) {
1136 *status
= "SERVICE EXPIRED";
1137 return(KDC_ERR_SERVICE_EXP
);
1141 * Verify that the server principal in authdat->ticket is correct
1142 * (either the ticket granting service or the service that was
1143 * originally requested)
1145 if (request
->kdc_options
& NO_TGT_OPTION
) {
1146 if (!krb5_principal_compare(kdc_context
, ticket
->server
, request
->server
)) {
1147 *status
= "SERVER DIDN'T MATCH TICKET FOR RENEW/FORWARD/ETC";
1148 return(KDC_ERR_SERVER_NOMATCH
);
1152 * OK, we need to validate the krbtgt service in the ticket.
1154 * The krbtgt service is of the form:
1155 * krbtgt/realm-A@realm-B
1157 * Realm A is the "server realm"; the realm of the
1158 * server of the requested ticket must match this realm.
1159 * Of course, it should be a realm serviced by this KDC.
1161 * Realm B is the "client realm"; this is what should be
1162 * added to the transited field. (which is done elsewhere)
1165 /* Make sure there are two components... */
1166 if (krb5_princ_size(kdc_context
, ticket
->server
) != 2) {
1167 *status
= "BAD TGS SERVER LENGTH";
1168 return KRB_AP_ERR_NOT_US
;
1170 /* ...that the first component is krbtgt... */
1171 if (!krb5_is_tgs_principal(ticket
->server
)) {
1172 *status
= "BAD TGS SERVER NAME";
1173 return KRB_AP_ERR_NOT_US
;
1175 /* ...and that the second component matches the server realm... */
1176 if ((krb5_princ_size(kdc_context
, ticket
->server
) <= 1) ||
1177 (krb5_princ_component(kdc_context
, ticket
->server
, 1)->length
!=
1178 krb5_princ_realm(kdc_context
, request
->server
)->length
) ||
1179 memcmp(krb5_princ_component(kdc_context
, ticket
->server
, 1)->data
,
1180 krb5_princ_realm(kdc_context
, request
->server
)->data
,
1181 krb5_princ_realm(kdc_context
, request
->server
)->length
)) {
1182 *status
= "BAD TGS SERVER INSTANCE";
1183 return KRB_AP_ERR_NOT_US
;
1185 /* XXX add check that second component must match locally
1189 /* Server must allow TGS based issuances */
1190 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_TGT_BASED
)) {
1191 *status
= "TGT BASED NOT ALLOWED";
1192 return(KDC_ERR_POLICY
);
1196 /* TGS must be forwardable to get forwarded or forwardable ticket */
1197 if ((isflagset(request
->kdc_options
, KDC_OPT_FORWARDED
) ||
1198 isflagset(request
->kdc_options
, KDC_OPT_FORWARDABLE
)) &&
1199 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_FORWARDABLE
)) {
1200 *status
= "TGT NOT FORWARDABLE";
1202 return KDC_ERR_BADOPTION
;
1205 /* TGS must be proxiable to get proxiable ticket */
1206 if ((isflagset(request
->kdc_options
, KDC_OPT_PROXY
) ||
1207 isflagset(request
->kdc_options
, KDC_OPT_PROXIABLE
)) &&
1208 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_PROXIABLE
)) {
1209 *status
= "TGT NOT PROXIABLE";
1210 return KDC_ERR_BADOPTION
;
1213 /* TGS must allow postdating to get postdated ticket */
1214 if ((isflagset(request
->kdc_options
, KDC_OPT_ALLOW_POSTDATE
) ||
1215 isflagset(request
->kdc_options
, KDC_OPT_POSTDATED
)) &&
1216 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_MAY_POSTDATE
)) {
1217 *status
= "TGT NOT POSTDATABLE";
1218 return KDC_ERR_BADOPTION
;
1221 /* can only validate invalid tix */
1222 if (isflagset(request
->kdc_options
, KDC_OPT_VALIDATE
) &&
1223 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_INVALID
)) {
1224 *status
= "VALIDATE VALID TICKET";
1225 return KDC_ERR_BADOPTION
;
1228 /* can only renew renewable tix */
1229 if ((isflagset(request
->kdc_options
, KDC_OPT_RENEW
) ||
1230 isflagset(request
->kdc_options
, KDC_OPT_RENEWABLE
)) &&
1231 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_RENEWABLE
)) {
1232 *status
= "TICKET NOT RENEWABLE";
1233 return KDC_ERR_BADOPTION
;
1236 /* can not proxy ticket granting tickets */
1237 if (isflagset(request
->kdc_options
, KDC_OPT_PROXY
) &&
1238 (!request
->server
->data
||
1239 request
->server
->data
[0].length
!= KRB5_TGS_NAME_SIZE
||
1240 memcmp(request
->server
->data
[0].data
, KRB5_TGS_NAME
,
1241 KRB5_TGS_NAME_SIZE
))) {
1242 *status
= "CAN'T PROXY TGT";
1243 return KDC_ERR_BADOPTION
;
1246 /* Server must allow forwardable tickets */
1247 if (isflagset(request
->kdc_options
, KDC_OPT_FORWARDABLE
) &&
1248 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_FORWARDABLE
)) {
1249 *status
= "NON-FORWARDABLE TICKET";
1250 return(KDC_ERR_POLICY
);
1253 /* Server must allow renewable tickets */
1254 if (isflagset(request
->kdc_options
, KDC_OPT_RENEWABLE
) &&
1255 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_RENEWABLE
)) {
1256 *status
= "NON-RENEWABLE TICKET";
1257 return(KDC_ERR_POLICY
);
1260 /* Server must allow proxiable tickets */
1261 if (isflagset(request
->kdc_options
, KDC_OPT_PROXIABLE
) &&
1262 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_PROXIABLE
)) {
1263 *status
= "NON-PROXIABLE TICKET";
1264 return(KDC_ERR_POLICY
);
1267 /* Server must allow postdated tickets */
1268 if (isflagset(request
->kdc_options
, KDC_OPT_ALLOW_POSTDATE
) &&
1269 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_POSTDATED
)) {
1270 *status
= "NON-POSTDATABLE TICKET";
1271 return(KDC_ERR_CANNOT_POSTDATE
);
1274 /* Server must allow DUP SKEY requests */
1275 if (isflagset(request
->kdc_options
, KDC_OPT_ENC_TKT_IN_SKEY
) &&
1276 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_DUP_SKEY
)) {
1277 *status
= "DUP_SKEY DISALLOWED";
1278 return(KDC_ERR_POLICY
);
1281 /* Server must not be locked out */
1282 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_ALL_TIX
)) {
1283 *status
= "SERVER LOCKED OUT";
1284 return(KDC_ERR_S_PRINCIPAL_UNKNOWN
);
1287 /* Server must be allowed to be a service */
1288 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_SVR
)) {
1289 *status
= "SERVER NOT ALLOWED";
1290 return(KDC_ERR_S_PRINCIPAL_UNKNOWN
);
1293 /* Check the hot list */
1294 if (check_hot_list(ticket
)) {
1295 *status
= "HOT_LIST";
1296 return(KRB_AP_ERR_REPEAT
);
1299 /* Check the start time vs. the KDC time */
1300 if (isflagset(request
->kdc_options
, KDC_OPT_VALIDATE
)) {
1301 if (ticket
->enc_part2
->times
.starttime
> kdc_time
) {
1302 *status
= "NOT_YET_VALID";
1303 return(KRB_AP_ERR_TKT_NYV
);
1308 * Check the renew_till time. The endtime was already
1309 * been checked in the initial authentication check.
1311 if (isflagset(request
->kdc_options
, KDC_OPT_RENEW
) &&
1312 (ticket
->enc_part2
->times
.renew_till
< kdc_time
)) {
1313 *status
= "TKT_EXPIRED";
1314 return(KRB_AP_ERR_TKT_EXPIRED
);
1318 * Checks for ENC_TKT_IN_SKEY:
1320 * (1) Make sure the second ticket exists
1321 * (2) Make sure it is a ticket granting ticket
1323 if (isflagset(request
->kdc_options
, KDC_OPT_ENC_TKT_IN_SKEY
)) {
1324 if (!request
->second_ticket
||
1325 !request
->second_ticket
[st_idx
]) {
1326 *status
= "NO_2ND_TKT";
1327 return(KDC_ERR_BADOPTION
);
1329 if (!krb5_principal_compare(kdc_context
, request
->second_ticket
[st_idx
]->server
,
1331 *status
= "2ND_TKT_NOT_TGS";
1332 return(KDC_ERR_POLICY
);
1337 /* Check for hardware preauthentication */
1338 if (isflagset(server
.attributes
, KRB5_KDB_REQUIRES_HW_AUTH
) &&
1339 !isflagset(ticket
->enc_part2
->flags
,TKT_FLG_HW_AUTH
)) {
1340 *status
= "NO HW PREAUTH";
1341 return KRB_ERR_GENERIC
;
1344 /* Check for any kind of preauthentication */
1345 if (isflagset(server
.attributes
, KRB5_KDB_REQUIRES_PRE_AUTH
) &&
1346 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_PRE_AUTH
)) {
1347 *status
= "NO PREAUTH";
1348 return KRB_ERR_GENERIC
;
1352 * Check local policy
1354 errcode
= against_local_policy_tgs(request
, server
, ticket
, status
);
1363 * This function returns 1 if the dbentry has a key for a specified
1364 * keytype, and 0 if not.
1367 dbentry_has_key_for_enctype(krb5_context context
, krb5_db_entry
*client
,
1368 krb5_enctype enctype
)
1370 krb5_error_code retval
;
1371 krb5_key_data
*datap
;
1373 retval
= krb5_dbe_find_enctype(context
, client
, enctype
,
1382 * This function returns 1 if the entity referenced by this
1383 * structure can support the a particular encryption system, and 0 if
1386 * XXX eventually this information should be looked up in the
1387 * database. Since it isn't, we use some hueristics and attribute
1388 * options bits for now.
1391 dbentry_supports_enctype(krb5_context context
, krb5_db_entry
*client
,
1392 krb5_enctype enctype
)
1395 * If it's DES_CBC_MD5, there's a bit in the attribute mask which
1396 * checks to see if we support it.
1398 * In theory everything's supposed to support DES_CBC_MD5, but
1399 * that's not the reality....
1403 * We are assuming that all entries can support MD5; this information
1404 * need not be kept in the database.
1408 if (enctype
== ENCTYPE_DES_CBC_MD5
)
1412 * XXX we assume everything can understand DES_CBC_CRC
1414 if (enctype
== ENCTYPE_DES_CBC_CRC
)
1418 * If we have a key for the encryption system, we assume it's
1421 return dbentry_has_key_for_enctype(context
, client
, enctype
);
1425 * This function returns the keytype which should be selected for the
1426 * session key. It is based on the ordered list which the user
1427 * requested, and what the KDC and the application server can support.
1430 select_session_keytype(krb5_context context
, krb5_db_entry
*server
,
1431 int nktypes
, krb5_enctype
*ktype
)
1435 for (i
= 0; i
< nktypes
; i
++) {
1436 if (!krb5_c_valid_enctype(ktype
[i
]))
1439 if (!krb5_is_permitted_enctype(context
, ktype
[i
]))
1442 if (dbentry_supports_enctype(context
, server
, ktype
[i
]))
1449 * This function returns salt information for a particular client_key
1452 get_salt_from_key(krb5_context context
, krb5_principal client
,
1453 krb5_key_data
*client_key
, krb5_data
*salt
)
1455 krb5_error_code retval
;
1459 salt
->length
= SALT_TYPE_NO_LENGTH
;
1461 if (client_key
->key_data_ver
== 1)
1464 switch (client_key
->key_data_type
[1]) {
1465 case KRB5_KDB_SALTTYPE_NORMAL
:
1467 case KRB5_KDB_SALTTYPE_V4
:
1468 /* send an empty (V4) salt */
1472 case KRB5_KDB_SALTTYPE_NOREALM
:
1473 if ((retval
= krb5_principal2salt_norealm(context
, client
, salt
)))
1476 case KRB5_KDB_SALTTYPE_AFS3
:
1477 /* send the same salt as with onlyrealm - but with no type info,
1478 we just hope they figure it out on the other end. */
1479 /* fall through to onlyrealm: */
1480 case KRB5_KDB_SALTTYPE_ONLYREALM
:
1481 realm
= krb5_princ_realm(context
, client
);
1482 salt
->length
= realm
->length
;
1483 if ((salt
->data
= malloc(realm
->length
)) == NULL
)
1485 memcpy(salt
->data
, realm
->data
, realm
->length
);
1487 case KRB5_KDB_SALTTYPE_SPECIAL
:
1488 salt
->length
= client_key
->key_data_length
[1];
1489 if ((salt
->data
= malloc(salt
->length
)) == NULL
)
1491 memcpy(salt
->data
, client_key
->key_data_contents
[1], salt
->length
);
1498 * Limit strings to a "reasonable" length to prevent crowding out of
1499 * other useful information in the log entry
1501 #define NAME_LENGTH_LIMIT 128
1503 void limit_string(char *name
)
1510 if (strlen(name
) < NAME_LENGTH_LIMIT
)
1513 i
= NAME_LENGTH_LIMIT
-4;
1522 * L10_2 = log10(2**x), rounded up; log10(2) ~= 0.301.
1524 #define L10_2(x) ((int)(((x * 301) + 999) / 1000))
1527 * Max length of sprintf("%ld") for an int of type T; includes leading
1528 * minus sign and terminating NUL.
1530 #define D_LEN(t) (L10_2(sizeof(t) * CHAR_BIT) + 2)
1533 ktypes2str(char *s
, size_t len
, int nktypes
, krb5_enctype
*ktype
)
1536 char stmp
[D_LEN(krb5_enctype
) + 1];
1540 || len
< (sizeof(" etypes {...}") + D_LEN(int))) {
1545 sprintf(s
, "%d etypes {", nktypes
);
1546 for (i
= 0; i
< nktypes
; i
++) {
1547 sprintf(stmp
, "%s%ld", i
? " " : "", (long)ktype
[i
]);
1548 if (strlen(s
) + strlen(stmp
) + sizeof("}") > len
)
1554 * We broke out of the loop. Try to truncate the list.
1557 while (p
- s
+ sizeof("...}") > len
) {
1558 while (p
> s
&& *p
!= ' ' && *p
!= '{')
1560 if (p
> s
&& *p
== ' ') {
1572 rep_etypes2str(char *s
, size_t len
, krb5_kdc_rep
*rep
)
1574 char stmp
[sizeof("ses=") + D_LEN(krb5_enctype
)];
1576 if (len
< (3 * D_LEN(krb5_enctype
)
1577 + sizeof("etypes {rep= tkt= ses=}"))) {
1582 sprintf(s
, "etypes {rep=%ld", (long)rep
->enc_part
.enctype
);
1584 if (rep
->ticket
!= NULL
) {
1585 sprintf(stmp
, " tkt=%ld", (long)rep
->ticket
->enc_part
.enctype
);
1589 if (rep
->ticket
!= NULL
1590 && rep
->ticket
->enc_part2
!= NULL
1591 && rep
->ticket
->enc_part2
->session
!= NULL
) {
1592 sprintf(stmp
, " ses=%ld",
1593 (long)rep
->ticket
->enc_part2
->session
->enctype
);