📄 kerberos5.c
字号:
/* * Copyright (c) 1997-2007 Kungliga Tekniska H鰃skolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "kdc_locl.h"RCSID("$Id: kerberos5.c 22071 2007-11-14 20:04:50Z lha $");#define MAX_TIME ((time_t)((1U << 31) - 1))void_kdc_fix_time(time_t **t){ if(*t == NULL){ ALLOC(*t); **t = MAX_TIME; } if(**t == 0) **t = MAX_TIME; /* fix for old clients */}static intrealloc_method_data(METHOD_DATA *md){ PA_DATA *pa; pa = realloc(md->val, (md->len + 1) * sizeof(*md->val)); if(pa == NULL) return ENOMEM; md->val = pa; md->len++; return 0;}static voidset_salt_padata (METHOD_DATA *md, Salt *salt){ if (salt) { realloc_method_data(md); md->val[md->len - 1].padata_type = salt->type; der_copy_octet_string(&salt->salt, &md->val[md->len - 1].padata_value); }}const PA_DATA*_kdc_find_padata(const KDC_REQ *req, int *start, int type){ if (req->padata == NULL) return NULL; while(*start < req->padata->len){ (*start)++; if(req->padata->val[*start - 1].padata_type == type) return &req->padata->val[*start - 1]; } return NULL;}/* * Detect if `key' is the using the the precomputed `default_salt'. */static krb5_booleanis_default_salt_p(const krb5_salt *default_salt, const Key *key){ if (key->salt == NULL) return TRUE; if (default_salt->salttype != key->salt->type) return FALSE; if (krb5_data_cmp(&default_salt->saltvalue, &key->salt->salt)) return FALSE; return TRUE;}/* * return the first appropriate key of `princ' in `ret_key'. Look for * all the etypes in (`etypes', `len'), stopping as soon as we find * one, but preferring one that has default salt */krb5_error_code_kdc_find_etype(krb5_context context, const hdb_entry_ex *princ, krb5_enctype *etypes, unsigned len, Key **ret_key, krb5_enctype *ret_etype){ int i; krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP; krb5_salt def_salt; krb5_get_pw_salt (context, princ->entry.principal, &def_salt); for(i = 0; ret != 0 && i < len ; i++) { Key *key = NULL; if (krb5_enctype_valid(context, etypes[i]) != 0) continue; while (hdb_next_enctype2key(context, &princ->entry, etypes[i], &key) == 0) { if (key->key.keyvalue.length == 0) { ret = KRB5KDC_ERR_NULL_KEY; continue; } *ret_key = key; *ret_etype = etypes[i]; ret = 0; if (is_default_salt_p(&def_salt, key)) { krb5_free_salt (context, def_salt); return ret; } } } krb5_free_salt (context, def_salt); return ret;}krb5_error_code_kdc_make_anonymous_principalname (PrincipalName *pn){ pn->name_type = KRB5_NT_PRINCIPAL; pn->name_string.len = 1; pn->name_string.val = malloc(sizeof(*pn->name_string.val)); if (pn->name_string.val == NULL) return ENOMEM; pn->name_string.val[0] = strdup("anonymous"); if (pn->name_string.val[0] == NULL) { free(pn->name_string.val); pn->name_string.val = NULL; return ENOMEM; } return 0;}void_kdc_log_timestamp(krb5_context context, krb5_kdc_configuration *config, const char *type, KerberosTime authtime, KerberosTime *starttime, KerberosTime endtime, KerberosTime *renew_till){ char authtime_str[100], starttime_str[100], endtime_str[100], renewtime_str[100]; krb5_format_time(context, authtime, authtime_str, sizeof(authtime_str), TRUE); if (starttime) krb5_format_time(context, *starttime, starttime_str, sizeof(starttime_str), TRUE); else strlcpy(starttime_str, "unset", sizeof(starttime_str)); krb5_format_time(context, endtime, endtime_str, sizeof(endtime_str), TRUE); if (renew_till) krb5_format_time(context, *renew_till, renewtime_str, sizeof(renewtime_str), TRUE); else strlcpy(renewtime_str, "unset", sizeof(renewtime_str)); kdc_log(context, config, 5, "%s authtime: %s starttime: %s endtime: %s renew till: %s", type, authtime_str, starttime_str, endtime_str, renewtime_str);}static voidlog_patypes(krb5_context context, krb5_kdc_configuration *config, METHOD_DATA *padata){ struct rk_strpool *p = NULL; char *str; int i; for (i = 0; i < padata->len; i++) { switch(padata->val[i].padata_type) { case KRB5_PADATA_PK_AS_REQ: p = rk_strpoolprintf(p, "PK-INIT(ietf)"); break; case KRB5_PADATA_PK_AS_REQ_WIN: p = rk_strpoolprintf(p, "PK-INIT(win2k)"); break; case KRB5_PADATA_PA_PK_OCSP_RESPONSE: p = rk_strpoolprintf(p, "OCSP"); break; case KRB5_PADATA_ENC_TIMESTAMP: p = rk_strpoolprintf(p, "encrypted-timestamp"); break; default: p = rk_strpoolprintf(p, "%d", padata->val[i].padata_type); break; } if (p && i + 1 < padata->len) p = rk_strpoolprintf(p, ", "); if (p == NULL) { kdc_log(context, config, 0, "out of memory"); return; } } if (p == NULL) p = rk_strpoolprintf(p, "none"); str = rk_strpoolcollect(p); kdc_log(context, config, 0, "Client sent patypes: %s", str); free(str);}/* * */krb5_error_code_kdc_encode_reply(krb5_context context, krb5_kdc_configuration *config, KDC_REP *rep, const EncTicketPart *et, EncKDCRepPart *ek, krb5_enctype etype, int skvno, const EncryptionKey *skey, int ckvno, const EncryptionKey *ckey, const char **e_text, krb5_data *reply){ unsigned char *buf; size_t buf_size; size_t len; krb5_error_code ret; krb5_crypto crypto; ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, et, &len, ret); if(ret) { kdc_log(context, config, 0, "Failed to encode ticket: %s", krb5_get_err_text(context, ret)); return ret; } if(buf_size != len) { free(buf); kdc_log(context, config, 0, "Internal error in ASN.1 encoder"); *e_text = "KDC internal error"; return KRB5KRB_ERR_GENERIC; } ret = krb5_crypto_init(context, skey, etype, &crypto); if (ret) { free(buf); kdc_log(context, config, 0, "krb5_crypto_init failed: %s", krb5_get_err_text(context, ret)); return ret; } ret = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_TICKET, buf, len, skvno, &rep->ticket.enc_part); free(buf); krb5_crypto_destroy(context, crypto); if(ret) { kdc_log(context, config, 0, "Failed to encrypt data: %s", krb5_get_err_text(context, ret)); return ret; } if(rep->msg_type == krb_as_rep && !config->encode_as_rep_as_tgs_rep) ASN1_MALLOC_ENCODE(EncASRepPart, buf, buf_size, ek, &len, ret); else ASN1_MALLOC_ENCODE(EncTGSRepPart, buf, buf_size, ek, &len, ret); if(ret) { kdc_log(context, config, 0, "Failed to encode KDC-REP: %s", krb5_get_err_text(context, ret)); return ret; } if(buf_size != len) { free(buf); kdc_log(context, config, 0, "Internal error in ASN.1 encoder"); *e_text = "KDC internal error"; return KRB5KRB_ERR_GENERIC; } ret = krb5_crypto_init(context, ckey, 0, &crypto); if (ret) { free(buf); kdc_log(context, config, 0, "krb5_crypto_init failed: %s", krb5_get_err_text(context, ret)); return ret; } if(rep->msg_type == krb_as_rep) { krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_AS_REP_ENC_PART, buf, len, ckvno, &rep->enc_part); free(buf); ASN1_MALLOC_ENCODE(AS_REP, buf, buf_size, rep, &len, ret); } else { krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_TGS_REP_ENC_PART_SESSION, buf, len, ckvno, &rep->enc_part); free(buf); ASN1_MALLOC_ENCODE(TGS_REP, buf, buf_size, rep, &len, ret); } krb5_crypto_destroy(context, crypto); if(ret) { kdc_log(context, config, 0, "Failed to encode KDC-REP: %s", krb5_get_err_text(context, ret)); return ret; } if(buf_size != len) { free(buf); kdc_log(context, config, 0, "Internal error in ASN.1 encoder"); *e_text = "KDC internal error"; return KRB5KRB_ERR_GENERIC; } reply->data = buf; reply->length = buf_size; return 0;}/* * Return 1 if the client have only older enctypes, this is for * determining if the server should send ETYPE_INFO2 or not. */static intolder_enctype(krb5_enctype enctype){ switch (enctype) { case ETYPE_DES_CBC_CRC: case ETYPE_DES_CBC_MD4: case ETYPE_DES_CBC_MD5: case ETYPE_DES3_CBC_SHA1: case ETYPE_ARCFOUR_HMAC_MD5: case ETYPE_ARCFOUR_HMAC_MD5_56: /* * The following three is "old" windows enctypes and is needed for * windows 2000 hosts. */ case ETYPE_ARCFOUR_MD4: case ETYPE_ARCFOUR_HMAC_OLD: case ETYPE_ARCFOUR_HMAC_OLD_EXP: return 1; default: return 0; }}static intonly_older_enctype_p(const KDC_REQ *req){ int i; for(i = 0; i < req->req_body.etype.len; i++) { if (!older_enctype(req->req_body.etype.val[i])) return 0; } return 1;}/* * */static krb5_error_codemake_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key){ ent->etype = key->key.keytype; if(key->salt){#if 0 ALLOC(ent->salttype); if(key->salt->type == hdb_pw_salt) *ent->salttype = 0; /* or 1? or NULL? */ else if(key->salt->type == hdb_afs3_salt) *ent->salttype = 2; else { kdc_log(context, config, 0, "unknown salt-type: %d", key->salt->type); return KRB5KRB_ERR_GENERIC; } /* according to `the specs', we can't send a salt if we have AFS3 salted key, but that requires that you *know* what cell you are using (e.g by assuming that the cell is the same as the realm in lower case) */#elif 0 ALLOC(ent->salttype); *ent->salttype = key->salt->type;#else /* * We shouldn't sent salttype since it is incompatible with the * specification and it breaks windows clients. The afs * salting problem is solved by using KRB5-PADATA-AFS3-SALT * implemented in Heimdal 0.7 and later. */ ent->salttype = NULL;#endif krb5_copy_data(context, &key->salt->salt, &ent->salt); } else { /* we return no salt type at all, as that should indicate * the default salt type and make everybody happy. some * systems (like w2k) dislike being told the salt type * here. */ ent->salttype = NULL; ent->salt = NULL; } return 0;}static krb5_error_codeget_pa_etype_info(krb5_context context, krb5_kdc_configuration *config, METHOD_DATA *md, hdb_entry *client, ENCTYPE *etypes, unsigned int etypes_len){ krb5_error_code ret = 0; int i, j;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -