/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* kdc/kdc_util.h */ /* * Portions Copyright (C) 2007 Apple Inc. * Copyright 1990, 2007, 2014 by the Massachusetts Institute of Technology. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * * Declarations for policy.c */ #ifndef __KRB5_KDC_UTIL__ #define __KRB5_KDC_UTIL__ #include #include "kdb.h" #include "net-server.h" #include "realm_data.h" #include "reqstate.h" krb5_error_code check_hot_list (krb5_ticket *); krb5_boolean krb5_is_tgs_principal (krb5_const_principal); krb5_boolean is_cross_tgs_principal(krb5_const_principal); krb5_boolean is_local_tgs_principal(krb5_const_principal); krb5_error_code add_to_transited (krb5_data *, krb5_data *, krb5_principal, krb5_principal, krb5_principal); krb5_error_code compress_transited (krb5_data *, krb5_principal, krb5_data *); krb5_error_code fetch_last_req_info (krb5_db_entry *, krb5_last_req_entry ***); krb5_error_code kdc_convert_key (krb5_keyblock *, krb5_keyblock *, int); krb5_error_code kdc_process_tgs_req (kdc_realm_t *, krb5_kdc_req *, const krb5_fulladdr *, krb5_data *, krb5_ticket **, krb5_db_entry **krbtgt_ptr, krb5_keyblock **, krb5_keyblock **, krb5_pa_data **pa_tgs_req); krb5_error_code kdc_get_server_key (krb5_context, krb5_ticket *, unsigned int, krb5_boolean match_enctype, krb5_db_entry **, krb5_keyblock **, krb5_kvno *); krb5_error_code get_first_current_key(krb5_context context, krb5_db_entry *entry, krb5_keyblock *key_out); krb5_error_code get_local_tgt(krb5_context context, const krb5_data *realm, krb5_db_entry *candidate, krb5_db_entry **alias_out, krb5_db_entry **storage_out, krb5_keyblock *kb_out); int validate_as_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry *, krb5_db_entry *, krb5_timestamp, const char **, krb5_pa_data ***); int validate_tgs_request(kdc_realm_t *kdc_active_realm, krb5_kdc_req *request, krb5_db_entry *server, krb5_ticket *ticket, const krb5_ticket *stkt, krb5_db_entry *stkt_server, krb5_timestamp kdc_time, krb5_pa_s4u_x509_user *s4u_x509_user, krb5_db_entry *s4u2self_client, krb5_boolean is_crossrealm, krb5_boolean is_referral, const char **status, krb5_pa_data ***e_data); krb5_flags get_ticket_flags(krb5_flags reqflags, krb5_db_entry *client, krb5_db_entry *server, krb5_enc_tkt_part *header_enc); krb5_error_code check_indicators(krb5_context context, krb5_db_entry *server, krb5_data *const *indicators); int fetch_asn1_field (unsigned char *, unsigned int, unsigned int, krb5_data *); krb5_enctype select_session_keytype (kdc_realm_t *kdc_active_realm, krb5_db_entry *server, int nktypes, krb5_enctype *ktypes); void limit_string (char *name); char *ktypes2str(krb5_enctype *ktype, int nktypes); char *rep_etypes2str(krb5_kdc_rep *rep); /* authind.c */ krb5_boolean authind_contains(krb5_data *const *indicators, const char *ind); krb5_error_code authind_add(krb5_context context, const char *ind, krb5_data ***indicators); krb5_error_code authind_extract(krb5_context context, krb5_authdata **authdata, krb5_data ***indicators); /* cammac.c */ krb5_error_code cammac_create(krb5_context context, krb5_enc_tkt_part *enc_tkt_reply, krb5_keyblock *server_key, krb5_db_entry *tgt, krb5_keyblock *tgt_key, krb5_authdata **contents, krb5_authdata ***cammac_out); krb5_boolean cammac_check_kdcver(krb5_context context, krb5_cammac *cammac, krb5_enc_tkt_part *enc_tkt, krb5_db_entry *tgt, krb5_keyblock *tgt_key); /* do_as_req.c */ void process_as_req (krb5_kdc_req *, krb5_data *, const krb5_fulladdr *, const krb5_fulladdr *, kdc_realm_t *, verto_ctx *, loop_respond_fn, void *); /* do_tgs_req.c */ krb5_error_code process_tgs_req (krb5_kdc_req *, krb5_data *, const krb5_fulladdr *, kdc_realm_t *, krb5_data ** ); /* dispatch.c */ void dispatch (void *, const krb5_fulladdr *, const krb5_fulladdr *, krb5_data *, int, verto_ctx *, loop_respond_fn, void *); void kdc_err(krb5_context call_context, errcode_t code, const char *fmt, ...) #if !defined(__cplusplus) && (__GNUC__ > 2) __attribute__((__format__(__printf__, 3, 4))) #endif ; /* kdc_preauth.c */ krb5_boolean enctype_requires_etype_info_2(krb5_enctype enctype); const char * missing_required_preauth (krb5_db_entry *client, krb5_db_entry *server, krb5_enc_tkt_part *enc_tkt_reply); typedef void (*kdc_hint_respond_fn)(void *arg); void get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock, krb5_pa_data ***e_data_out, kdc_hint_respond_fn respond, void *arg); void load_preauth_plugins(struct server_handle * handle, krb5_context context, verto_ctx *ctx); void unload_preauth_plugins(krb5_context context); typedef void (*kdc_preauth_respond_fn)(void *arg, krb5_error_code code); void check_padata(krb5_context context, krb5_kdcpreauth_rock rock, krb5_data *req_pkt, krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply, void **padata_context, krb5_pa_data ***e_data, krb5_boolean *typed_e_data, kdc_preauth_respond_fn respond, void *state); krb5_error_code return_padata(krb5_context context, krb5_kdcpreauth_rock rock, krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply, krb5_keyblock *encrypting_key, void **padata_context); void free_padata_context(krb5_context context, void *padata_context); /* kdc_preauth_ec.c */ krb5_error_code kdcpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver, int min_ver, krb5_plugin_vtable vtable); /* kdc_preauth_enctsc.c */ krb5_error_code kdcpreauth_encrypted_timestamp_initvt(krb5_context context, int maj_ver, int min_ver, krb5_plugin_vtable vtable); /* kdc_authdata.c */ krb5_error_code load_authdata_plugins(krb5_context context); krb5_error_code unload_authdata_plugins(krb5_context context); krb5_error_code get_auth_indicators(krb5_context context, krb5_enc_tkt_part *enc_tkt, krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key, krb5_data ***indicators_out); krb5_error_code handle_authdata (krb5_context context, unsigned int flags, krb5_db_entry *client, krb5_db_entry *server, krb5_db_entry *subject_server, krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key, krb5_keyblock *client_key, krb5_keyblock *server_key, krb5_keyblock *header_key, krb5_data *req_pkt, krb5_kdc_req *request, krb5_const_principal altcprinc, void *ad_info, krb5_enc_tkt_part *enc_tkt_request, krb5_data ***auth_indicators, krb5_enc_tkt_part *enc_tkt_reply); /* replay.c */ krb5_error_code kdc_init_lookaside(krb5_context context); krb5_boolean kdc_check_lookaside (krb5_context, krb5_data *, krb5_data **); void kdc_insert_lookaside (krb5_context, krb5_data *, krb5_data *); void kdc_remove_lookaside (krb5_context kcontext, krb5_data *); void kdc_free_lookaside(krb5_context); /* kdc_util.c */ void reset_for_hangup(void *); krb5_boolean include_pac_p(krb5_context context, krb5_kdc_req *request); krb5_error_code return_enc_padata(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, krb5_keyblock *reply_key, krb5_db_entry *server, krb5_enc_kdc_rep_part *reply_encpart, krb5_boolean is_referral); krb5_error_code kdc_process_s4u2self_req (kdc_realm_t *kdc_active_realm, krb5_kdc_req *request, const krb5_db_entry *server, krb5_keyblock *tgs_subkey, krb5_keyblock *tgs_session, krb5_pa_s4u_x509_user **s4u2self_req, krb5_db_entry **princ_ptr, const char **status); krb5_error_code kdc_make_s4u2self_rep (krb5_context context, krb5_keyblock *tgs_subkey, krb5_keyblock *tgs_session, krb5_pa_s4u_x509_user *req_s4u_user, krb5_kdc_rep *reply, krb5_enc_kdc_rep_part *reply_encpart); krb5_error_code kdc_process_s4u2proxy_req (kdc_realm_t *kdc_active_realm, unsigned int flags, krb5_kdc_req *request, const krb5_enc_tkt_part *t2enc, krb5_db_entry *krbtgt, krb5_keyblock *krbtgt_key, const krb5_db_entry *server, krb5_keyblock *server_key, krb5_const_principal server_princ, const krb5_db_entry *proxy, krb5_const_principal proxy_princ, void *ad_info, void **stkt_ad_info, krb5_principal *stkt_ad_client, const char **status); krb5_error_code kdc_check_transited_list (kdc_realm_t *kdc_active_realm, const krb5_data *trans, const krb5_data *realm1, const krb5_data *realm2); void kdc_get_ticket_endtime(kdc_realm_t *kdc_active_realm, krb5_timestamp now, krb5_timestamp endtime, krb5_timestamp till, krb5_db_entry *client, krb5_db_entry *server, krb5_timestamp *out_endtime); void kdc_get_ticket_renewtime(kdc_realm_t *realm, krb5_kdc_req *request, krb5_enc_tkt_part *tgt, krb5_db_entry *client, krb5_db_entry *server, krb5_enc_tkt_part *tkt); void log_as_req(krb5_context context, const krb5_fulladdr *local_addr, const krb5_fulladdr *remote_addr, krb5_kdc_req *request, krb5_kdc_rep *reply, krb5_db_entry *client, const char *cname, krb5_db_entry *server, const char *sname, krb5_timestamp authtime, const char *status, krb5_error_code errcode, const char *emsg); void log_tgs_req(krb5_context ctx, const krb5_fulladdr *from, krb5_kdc_req *request, krb5_kdc_rep *reply, krb5_principal cprinc, krb5_principal sprinc, krb5_principal altcprinc, krb5_timestamp authtime, unsigned int c_flags, const char *status, krb5_error_code errcode, const char *emsg); void log_tgs_badtrans(krb5_context ctx, krb5_principal cprinc, krb5_principal sprinc, krb5_data *trcont, krb5_error_code errcode); void log_tgs_alt_tgt(krb5_context context, krb5_principal p); krb5_boolean is_client_db_alias(krb5_context context, const krb5_db_entry *entry, krb5_const_principal princ); /* FAST*/ enum krb5_fast_kdc_flags { KRB5_FAST_REPLY_KEY_USED = 0x1, KRB5_FAST_REPLY_KEY_REPLACED = 0x02 }; /* * If *requestptr contains FX_FAST padata, compute the armor key, verify the * checksum over checksummed_data, decode the FAST request, and substitute * *requestptr with the inner request. Set the armor_key, cookie, and * fast_options fields in state. state->cookie will be set for a non-FAST * request if it contains FX_COOKIE padata. If inner_body_out is non-NULL, set * *inner_body_out to a copy of the encoded inner body, or to NULL if the * request is not a FAST request. */ krb5_error_code kdc_find_fast (krb5_kdc_req **requestptr, krb5_data *checksummed_data, krb5_keyblock *tgs_subkey, krb5_keyblock *tgs_session, struct kdc_request_state *state, krb5_data **inner_body_out); krb5_error_code kdc_fast_response_handle_padata (struct kdc_request_state *state, krb5_kdc_req *request, krb5_kdc_rep *rep, krb5_enctype enctype); krb5_error_code kdc_fast_handle_error (krb5_context context, struct kdc_request_state *state, krb5_kdc_req *request, krb5_pa_data **in_padata, krb5_error *err, krb5_data **fast_edata_out); krb5_error_code kdc_fast_handle_reply_key(struct kdc_request_state *state, krb5_keyblock *existing_key, krb5_keyblock **out_key); krb5_boolean kdc_fast_hide_client(struct kdc_request_state *state); krb5_error_code kdc_handle_protected_negotiation( krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, const krb5_keyblock *reply_key, krb5_pa_data ***out_enc_padata); krb5_error_code kdc_fast_read_cookie(krb5_context context, struct kdc_request_state *state, krb5_kdc_req *req, krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key); krb5_boolean kdc_fast_search_cookie(struct kdc_request_state *state, krb5_preauthtype pa_type, krb5_data *out); krb5_error_code kdc_fast_set_cookie(struct kdc_request_state *state, krb5_preauthtype pa_type, const krb5_data *data); krb5_error_code kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state, krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key, krb5_const_principal client_princ, krb5_pa_data **cookie_out); krb5_error_code kdc_add_pa_pac_options(krb5_context context, krb5_kdc_req *request, krb5_pa_data ***out_enc_padata); krb5_error_code kdc_get_pa_pac_options(krb5_context context, krb5_pa_data **in_padata, krb5_pa_pac_options **pac_options_out); krb5_error_code kdc_get_pa_pac_rbcd(krb5_context context, krb5_pa_data **in_padata, krb5_boolean *supported); /* Information handle for kdcpreauth callbacks. All pointers are aliases. */ struct krb5_kdcpreauth_rock_st { krb5_kdc_req *request; krb5_data *inner_body; krb5_db_entry *client; krb5_db_entry *local_tgt; krb5_keyblock *local_tgt_key; krb5_key_data *client_key; krb5_keyblock *client_keyblock; struct kdc_request_state *rstate; verto_ctx *vctx; krb5_data ***auth_indicators; krb5_boolean send_freshness_token; }; #define isflagset(flagfield, flag) (flagfield & (flag)) #define setflag(flagfield, flag) (flagfield |= (flag)) #define clear(flagfield, flag) (flagfield &= ~(flag)) #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #endif #define ts_min(a, b) (ts_after(a, b) ? (b) : (a)) #define ADDRTYPE2FAMILY(X) \ ((X) == ADDRTYPE_INET6 ? AF_INET6 : (X) == ADDRTYPE_INET ? AF_INET : -1) /* RFC 4120: KRB5KDC_ERR_KEY_TOO_WEAK * RFC 4556: KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED */ #define KRB5KDC_ERR_KEY_TOO_WEAK KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED /* TGS-REQ options where the service can be a non-TGS principal */ #define NON_TGT_OPTION (KDC_OPT_FORWARDED | KDC_OPT_PROXY | KDC_OPT_RENEW | \ KDC_OPT_VALIDATE) /* TGS-REQ options which are not compatible with referrals */ #define NO_REFERRAL_OPTION (NON_TGT_OPTION | KDC_OPT_ENC_TKT_IN_SKEY) /* Options incompatible with AS and S4U2Self requests */ #define AS_INVALID_OPTIONS (NO_REFERRAL_OPTION | KDC_OPT_CNAME_IN_ADDL_TKT) /* * Mask of KDC options that request the corresponding ticket flag with * the same number. Some of these are invalid for AS-REQs, but * validate_as_request() takes care of that. KDC_OPT_RENEWABLE isn't * here because it needs special handling in * kdc_get_ticket_renewtime(). * * According to RFC 4120 section 3.1.3 the following AS-REQ options * request their corresponding ticket flags if local policy allows: * * KDC_OPT_FORWARDABLE KDC_OPT_ALLOW_POSTDATE * KDC_OPT_POSTDATED KDC_OPT_PROXIABLE * KDC_OPT_RENEWABLE * * RFC 1510 section A.6 shows pseudocode indicating that the following * TGS-REQ options request their corresponding ticket flags if local * policy allows: * * KDC_OPT_FORWARDABLE KDC_OPT_FORWARDED * KDC_OPT_PROXIABLE KDC_OPT_PROXY * KDC_OPT_POSTDATED KDC_OPT_RENEWABLE * * The above list omits KDC_OPT_ALLOW_POSTDATE, but RFC 4120 section * 5.4.1 says the TGS also handles it. * * RFC 6112 makes KDC_OPT_REQUEST_ANONYMOUS the same bit number as * TKT_FLG_ANONYMOUS. */ #define OPTS_COMMON_FLAGS_MASK \ (KDC_OPT_FORWARDABLE | KDC_OPT_FORWARDED | \ KDC_OPT_PROXIABLE | KDC_OPT_PROXY | \ KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED | \ KDC_OPT_REQUEST_ANONYMOUS) /* Copy KDC options that request the corresponding ticket flags. */ #define OPTS2FLAGS(x) (x & OPTS_COMMON_FLAGS_MASK) /* * Mask of ticket flags for the TGS to propagate from a ticket to a * derivative ticket. * * RFC 4120 section 2.1 says the following flags are carried forward * from an initial ticket to derivative tickets: * * TKT_FLG_PRE_AUTH * TKT_FLG_HW_AUTH * * RFC 4120 section 2.6 says TKT_FLG_FORWARDED is carried forward to * derivative tickets. Proxy tickets are basically identical to * forwarded tickets except that a TGT may never be proxied, therefore * tickets derived from proxy tickets should have TKT_FLAG_PROXY set. * RFC 4120 and RFC 1510 apparently have an accidental omission in not * requiring that tickets derived from a proxy ticket have * TKT_FLG_PROXY set. Previous code also omitted this behavior. * * RFC 6112 section 4.2 implies that TKT_FLG_ANONYMOUS must be * propagated from an anonymous ticket to derivative tickets. */ #define TGS_COPIED_FLAGS_MASK \ (TKT_FLG_FORWARDED | TKT_FLG_PROXY | \ TKT_FLG_PRE_AUTH | TKT_FLG_HW_AUTH | \ TKT_FLG_ANONYMOUS) /* Copy appropriate header ticket flags to new ticket. */ #define COPY_TKT_FLAGS(x) (x & TGS_COPIED_FLAGS_MASK) int check_anon(kdc_realm_t *kdc_active_realm, krb5_principal client, krb5_principal server); int errcode_to_protocol(krb5_error_code code); char *data2string(krb5_data *d); /* Return the current key version of entry, or 0 if it has no keys. */ static inline krb5_kvno current_kvno(krb5_db_entry *entry) { return (entry->n_key_data == 0) ? 0 : entry->key_data[0].key_data_kvno; } #endif /* __KRB5_KDC_UTIL__ */