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
);
82 krb5_rc_close(kcontext
, kdc_rcache
);
89 * concatenate first two authdata arrays, returning an allocated replacement.
90 * The replacement should be freed with krb5_free_authdata().
93 concat_authorization_data(krb5_authdata
**first
, krb5_authdata
**second
,
94 krb5_authdata
***output
)
97 register krb5_authdata
**ptr
, **retdata
;
99 /* count up the entries */
102 for (ptr
= first
; *ptr
; ptr
++)
105 for (ptr
= second
; *ptr
; ptr
++)
108 retdata
= (krb5_authdata
**)malloc((i
+1)*sizeof(*retdata
));
111 retdata
[i
] = 0; /* null-terminated array */
112 for (i
= 0, j
= 0, ptr
= first
; j
< 2 ; ptr
= second
, j
++)
113 while (ptr
&& *ptr
) {
114 /* now walk & copy */
115 retdata
[i
] = (krb5_authdata
*)malloc(sizeof(*retdata
[i
]));
117 krb5_free_authdata(kdc_context
, retdata
);
121 if (!(retdata
[i
]->contents
=
122 (krb5_octet
*)malloc(retdata
[i
]->length
))) {
123 free((char *)retdata
[i
]);
125 krb5_free_authdata(kdc_context
, retdata
);
128 memcpy((char *) retdata
[i
]->contents
,
129 (char *)(*ptr
)->contents
,
140 realm_compare(krb5_principal princ1
, krb5_principal princ2
)
142 krb5_data
*realm1
= krb5_princ_realm(kdc_context
, princ1
);
143 krb5_data
*realm2
= krb5_princ_realm(kdc_context
, princ2
);
145 return((realm1
->length
== realm2
->length
) &&
146 !memcmp(realm1
->data
, realm2
->data
, realm1
->length
));
150 * Returns TRUE if the kerberos principal is the name of a Kerberos ticket
153 krb5_boolean
krb5_is_tgs_principal(krb5_principal principal
)
155 if ((krb5_princ_size(kdc_context
, principal
) > 0) &&
156 (krb5_princ_component(kdc_context
, principal
, 0)->length
==
157 KRB5_TGS_NAME_SIZE
) &&
158 (!memcmp(krb5_princ_component(kdc_context
, principal
, 0)->data
,
159 KRB5_TGS_NAME
, KRB5_TGS_NAME_SIZE
)))
165 * given authentication data (provides seed for checksum), verify checksum
168 static krb5_error_code
169 comp_cksum(krb5_context kcontext
, krb5_data
*source
, krb5_ticket
*ticket
,
170 krb5_checksum
*his_cksum
)
172 krb5_error_code retval
;
175 if (!krb5_c_valid_cksumtype(his_cksum
->checksum_type
))
176 return KRB5KDC_ERR_SUMTYPE_NOSUPP
;
178 /* must be collision proof */
179 if (!krb5_c_is_coll_proof_cksum(his_cksum
->checksum_type
))
180 return KRB5KRB_AP_ERR_INAPP_CKSUM
;
182 /* verify checksum */
183 if ((retval
= krb5_c_verify_checksum(kcontext
, ticket
->enc_part2
->session
,
184 KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM
,
185 source
, his_cksum
, &valid
)))
189 return(KRB5KRB_AP_ERR_BAD_INTEGRITY
);
195 kdc_process_tgs_req(krb5_kdc_req
*request
, const krb5_fulladdr
*from
,
196 krb5_data
*pkt
, krb5_ticket
**ticket
,
197 krb5_keyblock
**subkey
)
199 krb5_pa_data
** tmppa
;
201 krb5_error_code retval
;
203 krb5_data
* scratch
= NULL
;
204 krb5_boolean foreign_server
= FALSE
;
205 krb5_auth_context auth_context
= NULL
;
206 krb5_authenticator
* authenticator
= NULL
;
207 krb5_checksum
* his_cksum
= NULL
;
208 /* krb5_keyblock * key = NULL;*/
209 /* krb5_kvno kvno = 0;*/
211 if (!request
->padata
)
212 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
213 for (tmppa
= request
->padata
; *tmppa
; tmppa
++) {
214 if ((*tmppa
)->pa_type
== KRB5_PADATA_AP_REQ
)
217 if (!*tmppa
) /* cannot find any AP_REQ */
218 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
220 scratch1
.length
= (*tmppa
)->length
;
221 scratch1
.data
= (char *)(*tmppa
)->contents
;
222 if ((retval
= decode_krb5_ap_req(&scratch1
, &apreq
)))
225 if (isflagset(apreq
->ap_options
, AP_OPTS_USE_SESSION_KEY
) ||
226 isflagset(apreq
->ap_options
, AP_OPTS_MUTUAL_REQUIRED
)) {
227 krb5_klog_syslog(LOG_INFO
, "TGS_REQ: SESSION KEY or MUTUAL");
228 retval
= KRB5KDC_ERR_POLICY
;
232 /* If the "server" principal in the ticket is not something
233 in the local realm, then we must refuse to service the request
234 if the client claims to be from the local realm.
236 If we don't do this, then some other realm's nasty KDC can
237 claim to be authenticating a client from our realm, and we'll
238 give out tickets concurring with it!
240 we set a flag here for checking below.
242 if ((krb5_princ_realm(kdc_context
, apreq
->ticket
->server
)->length
!=
243 krb5_princ_realm(kdc_context
, tgs_server
)->length
) ||
244 memcmp(krb5_princ_realm(kdc_context
, apreq
->ticket
->server
)->data
,
245 krb5_princ_realm(kdc_context
, tgs_server
)->data
,
246 krb5_princ_realm(kdc_context
, tgs_server
)->length
))
247 foreign_server
= TRUE
;
249 if ((retval
= krb5_auth_con_init(kdc_context
, &auth_context
)))
252 if ((retval
= krb5_auth_con_setaddrs(kdc_context
, auth_context
, NULL
,
254 goto cleanup_auth_context
;
256 if ((retval
= krb5_auth_con_setrcache(kdc_context
, auth_context
,
258 goto cleanup_auth_context
;
262 if ((retval = kdc_get_server_key(apreq->ticket, &key, &kvno)))
263 goto cleanup_auth_context;
267 * XXX This is currently wrong but to fix it will require making a
268 * new keytab for groveling over the kdb.
271 retval = krb5_auth_con_setuseruserkey(kdc_context, auth_context, key);
272 krb5_free_keyblock(kdc_context, key);
274 goto cleanup_auth_context;
277 if ((retval
= krb5_rd_req_decoded_anyflag(kdc_context
, &auth_context
, apreq
,
278 apreq
->ticket
->server
,
279 kdc_active_realm
->realm_keytab
,
283 * I'm not so sure that this is right, but it's better than nothing
286 * If we choke in the rd_req because of the replay cache, then attempt
287 * to reinitialize the replay cache because somebody could have deleted
288 * it from underneath us (e.g. a cron job)
290 if ((retval
== KRB5_RC_IO_IO
) ||
291 (retval
== KRB5_RC_IO_UNKNOWN
)) {
292 (void) krb5_rc_close(kdc_context
, kdc_rcache
);
293 kdc_rcache
= (krb5_rcache
) NULL
;
294 if (!(retval
= kdc_initialize_rcache(kdc_context
, (char *) NULL
))) {
295 if ((retval
= krb5_auth_con_setrcache(kdc_context
, auth_context
,
297 (retval
= krb5_rd_req_decoded_anyflag(kdc_context
, &auth_context
,
298 apreq
, apreq
->ticket
->server
,
299 kdc_active_realm
->realm_keytab
,
302 goto cleanup_auth_context
;
305 goto cleanup_auth_context
;
307 goto cleanup_auth_context
;
311 /* "invalid flag" tickets can must be used to validate */
312 if (isflagset((*ticket
)->enc_part2
->flags
, TKT_FLG_INVALID
)
313 && !isflagset(request
->kdc_options
, KDC_OPT_VALIDATE
)) {
314 retval
= KRB5KRB_AP_ERR_TKT_INVALID
;
315 goto cleanup_auth_context
;
318 if ((retval
= krb5_auth_con_getrecvsubkey(kdc_context
,
319 auth_context
, subkey
)))
320 goto cleanup_auth_context
;
322 if ((retval
= krb5_auth_con_getauthenticator(kdc_context
, auth_context
,
324 goto cleanup_auth_context
;
326 /* Check for a checksum */
327 if (!(his_cksum
= authenticator
->checksum
)) {
328 retval
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
329 goto cleanup_authenticator
;
332 /* make sure the client is of proper lineage (see above) */
333 if (foreign_server
) {
334 krb5_data
*tkt_realm
= krb5_princ_realm(kdc_context
,
335 (*ticket
)->enc_part2
->client
);
336 krb5_data
*tgs_realm
= krb5_princ_realm(kdc_context
, tgs_server
);
337 if (tkt_realm
->length
== tgs_realm
->length
&&
338 !memcmp(tkt_realm
->data
, tgs_realm
->data
, tgs_realm
->length
)) {
339 /* someone in a foreign realm claiming to be local */
340 krb5_klog_syslog(LOG_INFO
, "PROCESS_TGS: failed lineage check");
341 retval
= KRB5KDC_ERR_POLICY
;
342 goto cleanup_authenticator
;
347 * Check application checksum vs. tgs request
349 * We try checksumming the req-body two different ways: first we
350 * try reaching into the raw asn.1 stream (if available), and
351 * checksum that directly; if that fails, then we try encoding
352 * using our local asn.1 library.
354 if (pkt
&& (fetch_asn1_field((unsigned char *) pkt
->data
,
355 1, 4, &scratch1
) >= 0)) {
356 if (comp_cksum(kdc_context
, &scratch1
, *ticket
, his_cksum
)) {
357 if (!(retval
= encode_krb5_kdc_req_body(request
, &scratch
)))
358 retval
= comp_cksum(kdc_context
, scratch
, *ticket
, his_cksum
);
359 krb5_free_data(kdc_context
, scratch
);
363 cleanup_authenticator
:
364 krb5_free_authenticator(kdc_context
, authenticator
);
366 cleanup_auth_context
:
367 /* We do not want the free of the auth_context to close the rcache */
369 (void) krb5_auth_con_setrcache(kdc_context
, auth_context
, 0);
371 krb5_auth_con_free(kdc_context
, auth_context
);
374 krb5_free_ap_req(kdc_context
, apreq
);
378 /* XXX This function should no longer be necessary.
379 * The KDC should take the keytab associated with the realm and pass that to
380 * the krb5_rd_req_decode(). --proven
382 * It's actually still used by do_tgs_req() for u2u auth, and not too
386 kdc_get_server_key(krb5_ticket
*ticket
, krb5_keyblock
**key
, krb5_kvno
*kvno
)
388 krb5_error_code retval
;
389 krb5_db_entry server
;
392 krb5_key_data
* server_key
;
396 if ((retval
= krb5_db_get_principal(kdc_context
, ticket
->server
,
402 krb5_db_free_principal(kdc_context
, &server
, nprincs
);
403 return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE
);
404 } else if (nprincs
!= 1) {
407 krb5_db_free_principal(kdc_context
, &server
, nprincs
);
408 if (!krb5_unparse_name(kdc_context
, ticket
->server
, &sname
)) {
410 krb5_klog_syslog(LOG_ERR
,"TGS_REQ: UNKNOWN SERVER: server='%s'",
414 return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
);
416 retval
= krb5_dbe_find_enctype(kdc_context
, &server
,
417 ticket
->enc_part
.enctype
, -1,
418 ticket
->enc_part
.kvno
, &server_key
);
422 retval
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
425 *kvno
= server_key
->key_data_kvno
;
426 if ((*key
= (krb5_keyblock
*)malloc(sizeof **key
))) {
427 retval
= krb5_dbekd_decrypt_key_data(kdc_context
, &master_keyblock
,
433 krb5_db_free_principal(kdc_context
, &server
, nprincs
);
437 /* This probably wants to be updated if you support last_req stuff */
439 static krb5_last_req_entry nolrentry
= { KV5M_LAST_REQ_ENTRY
, KRB5_LRQ_NONE
, 0 };
440 static krb5_last_req_entry
*nolrarray
[] = { &nolrentry
, 0 };
443 fetch_last_req_info(krb5_db_entry
*dbentry
, krb5_last_req_entry
***lrentry
)
445 *lrentry
= nolrarray
;
450 /* XXX! This is a temporary place-holder */
453 check_hot_list(krb5_ticket
*ticket
)
459 #define MAX_REALM_LN 500
463 * subrealm - determine if r2 is a subrealm of r1
465 * SUBREALM takes two realms, r1 and r2, and
466 * determines if r2 is a subrealm of r1.
467 * r2 is a subrealm of r1 if (r1 is a prefix
468 * of r2 AND r1 and r2 begin with a /) or if
469 * (r1 is a suffix of r2 and neither r1 nor r2
472 * RETURNS: If r2 is a subrealm, and r1 is a prefix, the number
473 * of characters in the suffix of r2 is returned as a
476 * If r2 is a subrealm, and r1 is a suffix, the number
477 * of characters in the prefix of r2 is returned as a
480 * If r2 is not a subrealm, SUBREALM returns 0.
483 subrealm(char *r1
, char *r2
)
488 if(l2
<= l1
) return(0);
489 if((*r1
== '/') && (*r2
== '/') && (strncmp(r1
,r2
,l1
) == 0)) return(l1
-l2
);
490 if((*r1
!= '/') && (*r2
!= '/') && (strncmp(r1
,r2
+l2
-l1
,l1
) == 0))
496 * add_to_transited Adds the name of the realm which issued the
497 * ticket granting ticket on which the new ticket to
498 * be issued is based (note that this is the same as
499 * the realm of the server listed in the ticket
502 * ASSUMPTIONS: This procedure assumes that the transited field from
503 * the existing ticket granting ticket already appears
504 * in compressed form. It will add the new realm while
505 * maintaining that form. As long as each successive
506 * realm is added using this (or a similar) routine, the
507 * transited field will be in compressed form. The
508 * basis step is an empty transited field which is, by
509 * its nature, in its most compressed form.
511 * ARGUMENTS: krb5_data *tgt_trans Transited field from TGT
512 * krb5_data *new_trans The transited field for the new ticket
513 * krb5_principal tgs Name of ticket granting server
514 * This includes the realm of the KDC
515 * that issued the ticket granting
516 * ticket. This is the realm that is
517 * to be added to the transited field.
518 * krb5_principal client Name of the client
519 * krb5_principal server The name of the requested server.
520 * This may be the an intermediate
521 * ticket granting server.
523 * The last two argument are needed since they are
524 * implicitly part of the transited field of the new ticket
525 * even though they are not explicitly listed.
527 * RETURNS: krb5_error_code - Success, or out of memory
529 * MODIFIES: new_trans: ->length will contain the length of the new
532 * If ->data was not null when this procedure
533 * is called, the memory referenced by ->data
534 * will be deallocated.
536 * Memory will be allocated for the new transited field
537 * ->data will be updated to point to the newly
540 * BUGS: The space allocated for the new transited field is the
541 * maximum that might be needed given the old transited field,
542 * and the realm to be added. This length is calculated
543 * assuming that no compression of the new realm is possible.
544 * This has no adverse consequences other than the allocation
545 * of more space than required.
547 * This procedure will not yet use the null subfield notation,
548 * and it will get confused if it sees it.
550 * This procedure does not check for quoted commas in realm
555 data2string (krb5_data
*d
)
558 s
= malloc(d
->length
+ 1);
560 memcpy(s
, d
->data
, d
->length
);
567 add_to_transited(krb5_data
*tgt_trans
, krb5_data
*new_trans
,
568 krb5_principal tgs
, krb5_principal client
,
569 krb5_principal server
)
571 krb5_error_code retval
;
574 char *otrans
, *otrans_ptr
;
576 /* The following are for stepping through the transited field */
578 char prev
[MAX_REALM_LN
];
579 char next
[MAX_REALM_LN
];
580 char current
[MAX_REALM_LN
];
581 char exp
[MAX_REALM_LN
]; /* Expanded current realm name */
584 int clst
, nlst
; /* count of last character in current and next */
585 int pl
, pl1
; /* prefix length */
586 int added
; /* TRUE = new realm has been added */
588 realm
= data2string(krb5_princ_realm(kdc_context
, tgs
));
592 otrans
= data2string(tgt_trans
);
593 if (otrans
== NULL
) {
597 /* Keep track of start so we can free */
601 +1 for extra comma which may be added between
602 +1 for potential space when leading slash in realm */
603 if (!(trans
= (char *) malloc(strlen(realm
) + strlen(otrans
) + 3))) {
608 if (new_trans
->data
) free(new_trans
->data
);
609 new_trans
->data
= trans
;
610 new_trans
->length
= 0;
614 /* For the purpose of appending, the realm preceding the first */
615 /* realm in the transited field is considered the null realm */
619 /* read field into current */
620 for (i
= 0; *otrans
!= '\0';) {
621 if (*otrans
== '\\') {
622 if (*(++otrans
) == '\0')
627 if (*otrans
== ',') {
631 current
[i
++] = *otrans
++;
632 if (i
>= MAX_REALM_LN
) {
633 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
639 added
= (krb5_princ_realm(kdc_context
, client
)->length
== strlen(realm
) &&
640 !strncmp(krb5_princ_realm(kdc_context
, client
)->data
, realm
, strlen(realm
))) ||
641 (krb5_princ_realm(kdc_context
, server
)->length
== strlen(realm
) &&
642 !strncmp(krb5_princ_realm(kdc_context
, server
)->data
, realm
, strlen(realm
)));
646 /* figure out expanded form of current name */
648 clst
= strlen(current
) - 1;
649 if (current
[0] == ' ') {
650 strncpy(exp
, current
+1, sizeof(exp
) - 1);
651 exp
[sizeof(exp
) - 1] = '\0';
653 else if ((current
[0] == '/') && (prev
[0] == '/')) {
654 strncpy(exp
, prev
, sizeof(exp
) - 1);
655 exp
[sizeof(exp
) - 1] = '\0';
656 if (strlen(exp
) + strlen(current
) + 1 >= MAX_REALM_LN
) {
657 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
660 strncat(exp
, current
, sizeof(exp
) - 1 - strlen(exp
));
662 else if (current
[clst
] == '.') {
663 strncpy(exp
, current
, sizeof(exp
) - 1);
664 exp
[sizeof(exp
) - 1] = '\0';
665 if (strlen(exp
) + strlen(prev
) + 1 >= MAX_REALM_LN
) {
666 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
669 strncat(exp
, prev
, sizeof(exp
) - 1 - strlen(exp
));
672 strncpy(exp
, current
, sizeof(exp
) - 1);
673 exp
[sizeof(exp
) - 1] = '\0';
676 /* read field into next */
677 for (i
= 0; *otrans
!= '\0';) {
678 if (*otrans
== '\\') {
679 if (*(++otrans
) == '\0')
684 if (*otrans
== ',') {
688 next
[i
++] = *otrans
++;
689 if (i
>= MAX_REALM_LN
) {
690 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
697 if (!strcmp(exp
, realm
)) added
= TRUE
;
699 /* If we still have to insert the new realm */
703 /* Is the next field compressed? If not, and if the new */
704 /* realm is a subrealm of the current realm, compress */
705 /* the new realm, and insert immediately following the */
706 /* current one. Note that we can not do this if the next*/
707 /* field is already compressed since it would mess up */
708 /* what has already been done. In most cases, this is */
709 /* not a problem because the realm to be added will be a */
710 /* subrealm of the next field too, and we will catch */
711 /* it in a future iteration. */
713 /* Note that the second test here is an unsigned comparison,
714 so the first half (or a cast) is also required. */
715 assert(nlst
< 0 || nlst
< sizeof(next
));
716 if ((nlst
< 0 || next
[nlst
] != '.') &&
718 (pl
= subrealm(exp
, realm
))) {
720 current
[sizeof(current
) - 1] = '\0';
721 if (strlen(current
) + (pl
>0?pl
:-pl
) + 2 >= MAX_REALM_LN
) {
722 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
725 strncat(current
, ",", sizeof(current
) - 1 - strlen(current
));
727 strncat(current
, realm
, (unsigned) pl
);
730 strncat(current
, realm
+strlen(realm
)+pl
, (unsigned) (-pl
));
734 /* Whether or not the next field is compressed, if the */
735 /* realm to be added is a superrealm of the current realm,*/
736 /* then the current realm can be compressed. First the */
737 /* realm to be added must be compressed relative to the */
738 /* previous realm (if possible), and then the current */
739 /* realm compressed relative to the new realm. Note that */
740 /* if the realm to be added is also a superrealm of the */
741 /* previous realm, it would have been added earlier, and */
742 /* we would not reach this step this time around. */
744 else if ((pl
= subrealm(realm
, exp
))) {
747 if ((pl1
= subrealm(prev
,realm
))) {
748 if (strlen(current
) + (pl1
>0?pl1
:-pl1
) + 1 >= MAX_REALM_LN
) {
749 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
753 strncat(current
, realm
, (unsigned) pl1
);
756 strncat(current
, realm
+strlen(realm
)+pl1
, (unsigned) (-pl1
));
759 else { /* If not a subrealm */
760 if ((realm
[0] == '/') && prev
[0]) {
761 if (strlen(current
) + 2 >= MAX_REALM_LN
) {
762 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
765 strncat(current
, " ", sizeof(current
) - 1 - strlen(current
));
766 current
[sizeof(current
) - 1] = '\0';
768 if (strlen(current
) + strlen(realm
) + 1 >= MAX_REALM_LN
) {
769 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
772 strncat(current
, realm
, sizeof(current
) - 1 - strlen(current
));
773 current
[sizeof(current
) - 1] = '\0';
775 if (strlen(current
) + (pl
>0?pl
:-pl
) + 2 >= MAX_REALM_LN
) {
776 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
779 strncat(current
,",", sizeof(current
) - 1 - strlen(current
));
780 current
[sizeof(current
) - 1] = '\0';
782 strncat(current
, exp
, (unsigned) pl
);
785 strncat(current
, exp
+strlen(exp
)+pl
, (unsigned)(-pl
));
790 if (new_trans
->length
!= 0) {
791 if (strlen(trans
) + 2 >= MAX_REALM_LN
) {
792 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
797 if (strlen(trans
) + strlen(current
) + 1 >= MAX_REALM_LN
) {
798 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
801 strcat(trans
, current
);
802 new_trans
->length
= strlen(trans
);
804 strncpy(prev
, exp
, sizeof(prev
) - 1);
805 prev
[sizeof(prev
) - 1] = '\0';
806 strncpy(current
, next
, sizeof(current
) - 1);
807 current
[sizeof(current
) - 1] = '\0';
811 if (new_trans
->length
!= 0) {
812 if (strlen(trans
) + 2 >= MAX_REALM_LN
) {
813 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
818 if((realm
[0] == '/') && trans
[0]) {
819 if (strlen(trans
) + 2 >= MAX_REALM_LN
) {
820 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
825 if (strlen(trans
) + strlen(realm
) + 1 >= MAX_REALM_LN
) {
826 retval
= KRB5KRB_AP_ERR_ILL_CR_TKT
;
829 strcat(trans
, realm
);
830 new_trans
->length
= strlen(trans
);
841 * Routines that validate a AS request; checks a lot of things. :-)
843 * Returns a Kerberos protocol error number, which is _not_ the same
844 * as a com_err error number!
846 #define AS_INVALID_OPTIONS (KDC_OPT_FORWARDED | KDC_OPT_PROXY |\
847 KDC_OPT_VALIDATE | KDC_OPT_RENEW | KDC_OPT_ENC_TKT_IN_SKEY)
849 validate_as_request(register krb5_kdc_req
*request
, krb5_db_entry client
,
850 krb5_db_entry server
, krb5_timestamp kdc_time
,
856 * If an option is set that is only allowed in TGS requests, complain.
858 if (request
->kdc_options
& AS_INVALID_OPTIONS
) {
859 *status
= "INVALID AS OPTIONS";
860 return KDC_ERR_BADOPTION
;
863 /* The client's password must not be expired, unless the server is
864 a KRB5_KDC_PWCHANGE_SERVICE. */
865 if (client
.pw_expiration
&& client
.pw_expiration
< kdc_time
&&
866 !isflagset(server
.attributes
, KRB5_KDB_PWCHANGE_SERVICE
)) {
867 *status
= "CLIENT KEY EXPIRED";
868 #ifdef KRBCONF_VAGUE_ERRORS
869 return(KRB_ERR_GENERIC
);
871 return(KDC_ERR_KEY_EXP
);
875 /* The client must not be expired */
876 if (client
.expiration
&& client
.expiration
< kdc_time
) {
877 *status
= "CLIENT EXPIRED";
878 #ifdef KRBCONF_VAGUE_ERRORS
879 return(KRB_ERR_GENERIC
);
881 return(KDC_ERR_NAME_EXP
);
885 /* The server must not be expired */
886 if (server
.expiration
&& server
.expiration
< kdc_time
) {
887 *status
= "SERVICE EXPIRED";
888 return(KDC_ERR_SERVICE_EXP
);
892 * If the client requires password changing, then only allow the
895 if (isflagset(client
.attributes
, KRB5_KDB_REQUIRES_PWCHANGE
) &&
896 !isflagset(server
.attributes
, KRB5_KDB_PWCHANGE_SERVICE
)) {
897 *status
= "REQUIRED PWCHANGE";
898 return(KDC_ERR_KEY_EXP
);
901 /* Client and server must allow postdating tickets */
902 if ((isflagset(request
->kdc_options
, KDC_OPT_ALLOW_POSTDATE
) ||
903 isflagset(request
->kdc_options
, KDC_OPT_POSTDATED
)) &&
904 (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_POSTDATED
) ||
905 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_POSTDATED
))) {
906 *status
= "POSTDATE NOT ALLOWED";
907 return(KDC_ERR_CANNOT_POSTDATE
);
910 /* Client and server must allow forwardable tickets */
911 if (isflagset(request
->kdc_options
, KDC_OPT_FORWARDABLE
) &&
912 (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_FORWARDABLE
) ||
913 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_FORWARDABLE
))) {
914 *status
= "FORWARDABLE NOT ALLOWED";
915 return(KDC_ERR_POLICY
);
918 /* Client and server must allow renewable tickets */
919 if (isflagset(request
->kdc_options
, KDC_OPT_RENEWABLE
) &&
920 (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_RENEWABLE
) ||
921 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_RENEWABLE
))) {
922 *status
= "RENEWABLE NOT ALLOWED";
923 return(KDC_ERR_POLICY
);
926 /* Client and server must allow proxiable tickets */
927 if (isflagset(request
->kdc_options
, KDC_OPT_PROXIABLE
) &&
928 (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_PROXIABLE
) ||
929 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_PROXIABLE
))) {
930 *status
= "PROXIABLE NOT ALLOWED";
931 return(KDC_ERR_POLICY
);
934 /* Check to see if client is locked out */
935 if (isflagset(client
.attributes
, KRB5_KDB_DISALLOW_ALL_TIX
)) {
936 *status
= "CLIENT LOCKED OUT";
937 return(KDC_ERR_C_PRINCIPAL_UNKNOWN
);
940 /* Check to see if server is locked out */
941 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_ALL_TIX
)) {
942 *status
= "SERVICE LOCKED OUT";
943 return(KDC_ERR_S_PRINCIPAL_UNKNOWN
);
946 /* Check to see if server is allowed to be a service */
947 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_SVR
)) {
948 *status
= "SERVICE NOT ALLOWED";
949 return(KDC_ERR_S_PRINCIPAL_UNKNOWN
);
953 * Check against local policy
955 errcode
= against_local_policy_as(request
, server
, client
,
963 #define ASN1_ID_CLASS (0xc0)
964 #define ASN1_ID_TYPE (0x20)
965 #define ASN1_ID_TAG (0x1f)
966 #define ASN1_CLASS_UNIV (0)
967 #define ASN1_CLASS_APP (1)
968 #define ASN1_CLASS_CTX (2)
969 #define ASN1_CLASS_PRIV (3)
970 #define asn1_id_constructed(x) (x & ASN1_ID_TYPE)
971 #define asn1_id_primitive(x) (!asn1_id_constructed(x))
972 #define asn1_id_class(x) ((x & ASN1_ID_CLASS) >> 6)
973 #define asn1_id_tag(x) (x & ASN1_ID_TAG)
976 * asn1length - return encoded length of value.
978 * passed a pointer into the asn.1 stream, which is updated
979 * to point right after the length bits.
981 * returns -1 on failure.
984 asn1length(unsigned char **astream
)
986 int length
; /* resulting length */
987 int sublen
; /* sublengths */
988 int blen
; /* bytes of length */
989 unsigned char *p
; /* substring searching */
991 if (**astream
& 0x80) {
992 blen
= **astream
& 0x7f;
996 for (++*astream
, length
= 0; blen
; ++*astream
, blen
--) {
997 length
= (length
<< 8) | **astream
;
1000 /* indefinite length, figure out by hand */
1004 /* compute value length. */
1005 if ((sublen
= asn1length(&p
)) < 0) {
1009 /* check for termination */
1010 if ((!*p
++) && (!*p
)) {
1015 length
= p
- *astream
;
1025 * fetch_asn1_field - return raw asn.1 stream of subfield.
1027 * this routine is passed a context-dependent tag number and "level" and returns
1028 * the size and length of the corresponding level subfield.
1030 * levels and are numbered starting from 1.
1032 * returns 0 on success, -1 otherwise.
1035 fetch_asn1_field(unsigned char *astream
, unsigned int level
,
1036 unsigned int field
, krb5_data
*data
)
1038 unsigned char *estream
; /* end of stream */
1039 int classes
; /* # classes seen so far this level */
1040 unsigned int levels
= 0; /* levels seen so far */
1041 int lastlevel
= 1000; /* last level seen */
1042 int length
; /* various lengths */
1043 int tag
; /* tag number */
1044 unsigned char savelen
; /* saved length of our field */
1047 /* we assume that the first identifier/length will tell us
1048 how long the entire stream is. */
1051 if ((length
= asn1length(&astream
)) < 0) {
1055 /* search down the stream, checking identifiers. we process identifiers
1056 until we hit the "level" we want, and then process that level for our
1057 subfield, always making sure we don't go off the end of the stream. */
1058 while (astream
< estream
) {
1059 if (!asn1_id_constructed(*astream
)) {
1062 if (asn1_id_class(*astream
) == ASN1_CLASS_CTX
) {
1063 if ((tag
= (int)asn1_id_tag(*astream
)) <= lastlevel
) {
1068 if (levels
== level
) {
1069 /* in our context-dependent class, is this the one we're looking for ? */
1071 /* return length and data */
1074 if ((data
->length
= asn1length(&astream
)) < 0) {
1077 /* if the field length is indefinite, we will have to subtract two
1078 (terminating octets) from the length returned since we don't want
1079 to pass any info from the "wrapper" back. asn1length will always return
1080 the *total* length of the field, not just what's contained in it */
1081 if ((savelen
& 0xff) == 0x80) {
1084 data
->data
= (char *)astream
;
1086 } else if (tag
<= classes
) {
1087 /* we've seen this class before, something must be wrong */
1094 /* if we're not on our level yet, process this value. otherwise skip over it */
1096 if ((length
= asn1length(&astream
)) < 0) {
1099 if (levels
== level
) {
1107 * Routines that validate a TGS request; checks a lot of things. :-)
1109 * Returns a Kerberos protocol error number, which is _not_ the same
1110 * as a com_err error number!
1112 #define TGS_OPTIONS_HANDLED (KDC_OPT_FORWARDABLE | KDC_OPT_FORWARDED | \
1113 KDC_OPT_PROXIABLE | KDC_OPT_PROXY | \
1114 KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED | \
1115 KDC_OPT_RENEWABLE | KDC_OPT_RENEWABLE_OK | \
1116 KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_RENEW | \
1119 #define NO_TGT_OPTION (KDC_OPT_FORWARDED | KDC_OPT_PROXY | KDC_OPT_RENEW | \
1123 validate_tgs_request(register krb5_kdc_req
*request
, krb5_db_entry server
,
1124 krb5_ticket
*ticket
, krb5_timestamp kdc_time
,
1125 const char **status
)
1131 * If an illegal option is set, ignore it.
1133 request
->kdc_options
&= TGS_OPTIONS_HANDLED
;
1135 /* Check to see if server has expired */
1136 if (server
.expiration
&& server
.expiration
< kdc_time
) {
1137 *status
= "SERVICE EXPIRED";
1138 return(KDC_ERR_SERVICE_EXP
);
1142 * Verify that the server principal in authdat->ticket is correct
1143 * (either the ticket granting service or the service that was
1144 * originally requested)
1146 if (request
->kdc_options
& NO_TGT_OPTION
) {
1147 if (!krb5_principal_compare(kdc_context
, ticket
->server
, request
->server
)) {
1148 *status
= "SERVER DIDN'T MATCH TICKET FOR RENEW/FORWARD/ETC";
1149 return(KDC_ERR_SERVER_NOMATCH
);
1153 * OK, we need to validate the krbtgt service in the ticket.
1155 * The krbtgt service is of the form:
1156 * krbtgt/realm-A@realm-B
1158 * Realm A is the "server realm"; the realm of the
1159 * server of the requested ticket must match this realm.
1160 * Of course, it should be a realm serviced by this KDC.
1162 * Realm B is the "client realm"; this is what should be
1163 * added to the transited field. (which is done elsewhere)
1166 /* Make sure there are two components... */
1167 if (krb5_princ_size(kdc_context
, ticket
->server
) != 2) {
1168 *status
= "BAD TGS SERVER LENGTH";
1169 return KRB_AP_ERR_NOT_US
;
1171 /* ...that the first component is krbtgt... */
1172 if (!krb5_is_tgs_principal(ticket
->server
)) {
1173 *status
= "BAD TGS SERVER NAME";
1174 return KRB_AP_ERR_NOT_US
;
1176 /* ...and that the second component matches the server realm... */
1177 if ((krb5_princ_size(kdc_context
, ticket
->server
) <= 1) ||
1178 (krb5_princ_component(kdc_context
, ticket
->server
, 1)->length
!=
1179 krb5_princ_realm(kdc_context
, request
->server
)->length
) ||
1180 memcmp(krb5_princ_component(kdc_context
, ticket
->server
, 1)->data
,
1181 krb5_princ_realm(kdc_context
, request
->server
)->data
,
1182 krb5_princ_realm(kdc_context
, request
->server
)->length
)) {
1183 *status
= "BAD TGS SERVER INSTANCE";
1184 return KRB_AP_ERR_NOT_US
;
1186 /* XXX add check that second component must match locally
1190 /* Server must allow TGS based issuances */
1191 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_TGT_BASED
)) {
1192 *status
= "TGT BASED NOT ALLOWED";
1193 return(KDC_ERR_POLICY
);
1197 /* TGS must be forwardable to get forwarded or forwardable ticket */
1198 if ((isflagset(request
->kdc_options
, KDC_OPT_FORWARDED
) ||
1199 isflagset(request
->kdc_options
, KDC_OPT_FORWARDABLE
)) &&
1200 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_FORWARDABLE
)) {
1201 *status
= "TGT NOT FORWARDABLE";
1203 return KDC_ERR_BADOPTION
;
1206 /* TGS must be proxiable to get proxiable ticket */
1207 if ((isflagset(request
->kdc_options
, KDC_OPT_PROXY
) ||
1208 isflagset(request
->kdc_options
, KDC_OPT_PROXIABLE
)) &&
1209 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_PROXIABLE
)) {
1210 *status
= "TGT NOT PROXIABLE";
1211 return KDC_ERR_BADOPTION
;
1214 /* TGS must allow postdating to get postdated ticket */
1215 if ((isflagset(request
->kdc_options
, KDC_OPT_ALLOW_POSTDATE
) ||
1216 isflagset(request
->kdc_options
, KDC_OPT_POSTDATED
)) &&
1217 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_MAY_POSTDATE
)) {
1218 *status
= "TGT NOT POSTDATABLE";
1219 return KDC_ERR_BADOPTION
;
1222 /* can only validate invalid tix */
1223 if (isflagset(request
->kdc_options
, KDC_OPT_VALIDATE
) &&
1224 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_INVALID
)) {
1225 *status
= "VALIDATE VALID TICKET";
1226 return KDC_ERR_BADOPTION
;
1229 /* can only renew renewable tix */
1230 if ((isflagset(request
->kdc_options
, KDC_OPT_RENEW
) ||
1231 isflagset(request
->kdc_options
, KDC_OPT_RENEWABLE
)) &&
1232 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_RENEWABLE
)) {
1233 *status
= "TICKET NOT RENEWABLE";
1234 return KDC_ERR_BADOPTION
;
1237 /* can not proxy ticket granting tickets */
1238 if (isflagset(request
->kdc_options
, KDC_OPT_PROXY
) &&
1239 (!request
->server
->data
||
1240 request
->server
->data
[0].length
!= KRB5_TGS_NAME_SIZE
||
1241 memcmp(request
->server
->data
[0].data
, KRB5_TGS_NAME
,
1242 KRB5_TGS_NAME_SIZE
))) {
1243 *status
= "CAN'T PROXY TGT";
1244 return KDC_ERR_BADOPTION
;
1247 /* Server must allow forwardable tickets */
1248 if (isflagset(request
->kdc_options
, KDC_OPT_FORWARDABLE
) &&
1249 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_FORWARDABLE
)) {
1250 *status
= "NON-FORWARDABLE TICKET";
1251 return(KDC_ERR_POLICY
);
1254 /* Server must allow renewable tickets */
1255 if (isflagset(request
->kdc_options
, KDC_OPT_RENEWABLE
) &&
1256 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_RENEWABLE
)) {
1257 *status
= "NON-RENEWABLE TICKET";
1258 return(KDC_ERR_POLICY
);
1261 /* Server must allow proxiable tickets */
1262 if (isflagset(request
->kdc_options
, KDC_OPT_PROXIABLE
) &&
1263 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_PROXIABLE
)) {
1264 *status
= "NON-PROXIABLE TICKET";
1265 return(KDC_ERR_POLICY
);
1268 /* Server must allow postdated tickets */
1269 if (isflagset(request
->kdc_options
, KDC_OPT_ALLOW_POSTDATE
) &&
1270 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_POSTDATED
)) {
1271 *status
= "NON-POSTDATABLE TICKET";
1272 return(KDC_ERR_CANNOT_POSTDATE
);
1275 /* Server must allow DUP SKEY requests */
1276 if (isflagset(request
->kdc_options
, KDC_OPT_ENC_TKT_IN_SKEY
) &&
1277 isflagset(server
.attributes
, KRB5_KDB_DISALLOW_DUP_SKEY
)) {
1278 *status
= "DUP_SKEY DISALLOWED";
1279 return(KDC_ERR_POLICY
);
1282 /* Server must not be locked out */
1283 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_ALL_TIX
)) {
1284 *status
= "SERVER LOCKED OUT";
1285 return(KDC_ERR_S_PRINCIPAL_UNKNOWN
);
1288 /* Server must be allowed to be a service */
1289 if (isflagset(server
.attributes
, KRB5_KDB_DISALLOW_SVR
)) {
1290 *status
= "SERVER NOT ALLOWED";
1291 return(KDC_ERR_S_PRINCIPAL_UNKNOWN
);
1294 /* Check the hot list */
1295 if (check_hot_list(ticket
)) {
1296 *status
= "HOT_LIST";
1297 return(KRB_AP_ERR_REPEAT
);
1300 /* Check the start time vs. the KDC time */
1301 if (isflagset(request
->kdc_options
, KDC_OPT_VALIDATE
)) {
1302 if (ticket
->enc_part2
->times
.starttime
> kdc_time
) {
1303 *status
= "NOT_YET_VALID";
1304 return(KRB_AP_ERR_TKT_NYV
);
1309 * Check the renew_till time. The endtime was already
1310 * been checked in the initial authentication check.
1312 if (isflagset(request
->kdc_options
, KDC_OPT_RENEW
) &&
1313 (ticket
->enc_part2
->times
.renew_till
< kdc_time
)) {
1314 *status
= "TKT_EXPIRED";
1315 return(KRB_AP_ERR_TKT_EXPIRED
);
1319 * Checks for ENC_TKT_IN_SKEY:
1321 * (1) Make sure the second ticket exists
1322 * (2) Make sure it is a ticket granting ticket
1324 if (isflagset(request
->kdc_options
, KDC_OPT_ENC_TKT_IN_SKEY
)) {
1325 if (!request
->second_ticket
||
1326 !request
->second_ticket
[st_idx
]) {
1327 *status
= "NO_2ND_TKT";
1328 return(KDC_ERR_BADOPTION
);
1330 if (!krb5_principal_compare(kdc_context
, request
->second_ticket
[st_idx
]->server
,
1332 *status
= "2ND_TKT_NOT_TGS";
1333 return(KDC_ERR_POLICY
);
1338 /* Check for hardware preauthentication */
1339 if (isflagset(server
.attributes
, KRB5_KDB_REQUIRES_HW_AUTH
) &&
1340 !isflagset(ticket
->enc_part2
->flags
,TKT_FLG_HW_AUTH
)) {
1341 *status
= "NO HW PREAUTH";
1342 return KRB_ERR_GENERIC
;
1345 /* Check for any kind of preauthentication */
1346 if (isflagset(server
.attributes
, KRB5_KDB_REQUIRES_PRE_AUTH
) &&
1347 !isflagset(ticket
->enc_part2
->flags
, TKT_FLG_PRE_AUTH
)) {
1348 *status
= "NO PREAUTH";
1349 return KRB_ERR_GENERIC
;
1353 * Check local policy
1355 errcode
= against_local_policy_tgs(request
, server
, ticket
, status
);
1364 * This function returns 1 if the dbentry has a key for a specified
1365 * keytype, and 0 if not.
1368 dbentry_has_key_for_enctype(krb5_context context
, krb5_db_entry
*client
,
1369 krb5_enctype enctype
)
1371 krb5_error_code retval
;
1372 krb5_key_data
*datap
;
1374 retval
= krb5_dbe_find_enctype(context
, client
, enctype
,
1383 * This function returns 1 if the entity referenced by this
1384 * structure can support the a particular encryption system, and 0 if
1387 * XXX eventually this information should be looked up in the
1388 * database. Since it isn't, we use some hueristics and attribute
1389 * options bits for now.
1392 dbentry_supports_enctype(krb5_context context
, krb5_db_entry
*client
,
1393 krb5_enctype enctype
)
1396 * If it's DES_CBC_MD5, there's a bit in the attribute mask which
1397 * checks to see if we support it.
1399 * In theory everything's supposed to support DES_CBC_MD5, but
1400 * that's not the reality....
1404 * We are assuming that all entries can support MD5; this information
1405 * need not be kept in the database.
1409 if (enctype
== ENCTYPE_DES_CBC_MD5
)
1413 * XXX we assume everything can understand DES_CBC_CRC
1415 if (enctype
== ENCTYPE_DES_CBC_CRC
)
1419 * If we have a key for the encryption system, we assume it's
1422 return dbentry_has_key_for_enctype(context
, client
, enctype
);
1426 * This function returns the keytype which should be selected for the
1427 * session key. It is based on the ordered list which the user
1428 * requested, and what the KDC and the application server can support.
1431 select_session_keytype(krb5_context context
, krb5_db_entry
*server
,
1432 int nktypes
, krb5_enctype
*ktype
)
1436 for (i
= 0; i
< nktypes
; i
++) {
1437 if (!krb5_c_valid_enctype(ktype
[i
]))
1440 if (!krb5_is_permitted_enctype(context
, ktype
[i
]))
1443 if (dbentry_supports_enctype(context
, server
, ktype
[i
]))
1450 * This function returns salt information for a particular client_key
1453 get_salt_from_key(krb5_context context
, krb5_principal client
,
1454 krb5_key_data
*client_key
, krb5_data
*salt
)
1456 krb5_error_code retval
;
1460 salt
->length
= SALT_TYPE_NO_LENGTH
;
1462 if (client_key
->key_data_ver
== 1)
1465 switch (client_key
->key_data_type
[1]) {
1466 case KRB5_KDB_SALTTYPE_NORMAL
:
1468 case KRB5_KDB_SALTTYPE_V4
:
1469 /* send an empty (V4) salt */
1473 case KRB5_KDB_SALTTYPE_NOREALM
:
1474 if ((retval
= krb5_principal2salt_norealm(context
, client
, salt
)))
1477 case KRB5_KDB_SALTTYPE_AFS3
:
1478 /* send the same salt as with onlyrealm - but with no type info,
1479 we just hope they figure it out on the other end. */
1480 /* fall through to onlyrealm: */
1481 case KRB5_KDB_SALTTYPE_ONLYREALM
:
1482 realm
= krb5_princ_realm(context
, client
);
1483 salt
->length
= realm
->length
;
1484 if ((salt
->data
= malloc(realm
->length
)) == NULL
)
1486 memcpy(salt
->data
, realm
->data
, realm
->length
);
1488 case KRB5_KDB_SALTTYPE_SPECIAL
:
1489 salt
->length
= client_key
->key_data_length
[1];
1490 if ((salt
->data
= malloc(salt
->length
)) == NULL
)
1492 memcpy(salt
->data
, client_key
->key_data_contents
[1], salt
->length
);
1499 * Limit strings to a "reasonable" length to prevent crowding out of
1500 * other useful information in the log entry
1502 #define NAME_LENGTH_LIMIT 128
1504 void limit_string(char *name
)
1511 if (strlen(name
) < NAME_LENGTH_LIMIT
)
1514 i
= NAME_LENGTH_LIMIT
-4;
1523 * L10_2 = log10(2**x), rounded up; log10(2) ~= 0.301.
1525 #define L10_2(x) ((int)(((x * 301) + 999) / 1000))
1528 * Max length of sprintf("%ld") for an int of type T; includes leading
1529 * minus sign and terminating NUL.
1531 #define D_LEN(t) (L10_2(sizeof(t) * CHAR_BIT) + 2)
1534 ktypes2str(char *s
, size_t len
, int nktypes
, krb5_enctype
*ktype
)
1537 char stmp
[D_LEN(krb5_enctype
) + 1];
1541 || len
< (sizeof(" etypes {...}") + D_LEN(int))) {
1546 sprintf(s
, "%d etypes {", nktypes
);
1547 for (i
= 0; i
< nktypes
; i
++) {
1548 sprintf(stmp
, "%s%ld", i
? " " : "", (long)ktype
[i
]);
1549 if (strlen(s
) + strlen(stmp
) + sizeof("}") > len
)
1555 * We broke out of the loop. Try to truncate the list.
1558 while (p
- s
+ sizeof("...}") > len
) {
1559 while (p
> s
&& *p
!= ' ' && *p
!= '{')
1561 if (p
> s
&& *p
== ' ') {
1573 rep_etypes2str(char *s
, size_t len
, krb5_kdc_rep
*rep
)
1575 char stmp
[sizeof("ses=") + D_LEN(krb5_enctype
)];
1577 if (len
< (3 * D_LEN(krb5_enctype
)
1578 + sizeof("etypes {rep= tkt= ses=}"))) {
1583 sprintf(s
, "etypes {rep=%ld", (long)rep
->enc_part
.enctype
);
1585 if (rep
->ticket
!= NULL
) {
1586 sprintf(stmp
, " tkt=%ld", (long)rep
->ticket
->enc_part
.enctype
);
1590 if (rep
->ticket
!= NULL
1591 && rep
->ticket
->enc_part2
!= NULL
1592 && rep
->ticket
->enc_part2
->session
!= NULL
) {
1593 sprintf(stmp
, " ses=%ld",
1594 (long)rep
->ticket
->enc_part2
->session
->enctype
);