📄 krb5tgs.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: krb5tgs.c 22071 2007-11-14 20:04:50Z lha $");/* * return the realm of a krbtgt-ticket or NULL */static Realm get_krbtgt_realm(const PrincipalName *p){ if(p->name_string.len == 2 && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0) return p->name_string.val[1]; else return NULL;}/* * The KDC might add a signed path to the ticket authorization data * field. This is to avoid server impersonating clients and the * request constrained delegation. * * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single * entry of type KRB5SignedPath. */static krb5_error_codefind_KRB5SignedPath(krb5_context context, const AuthorizationData *ad, krb5_data *data){ AuthorizationData child; krb5_error_code ret; int pos; if (ad == NULL || ad->len == 0) return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; pos = ad->len - 1; if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT) return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; ret = decode_AuthorizationData(ad->val[pos].ad_data.data, ad->val[pos].ad_data.length, &child, NULL); if (ret) { krb5_set_error_string(context, "Failed to decode " "IF_RELEVANT with %d", ret); return ret; } if (child.len != 1) { free_AuthorizationData(&child); return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; } if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) { free_AuthorizationData(&child); return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; } if (data) ret = der_copy_octet_string(&child.val[0].ad_data, data); free_AuthorizationData(&child); return ret;}krb5_error_code_kdc_add_KRB5SignedPath(krb5_context context, krb5_kdc_configuration *config, hdb_entry_ex *krbtgt, krb5_enctype enctype, krb5_const_principal server, KRB5SignedPathPrincipals *principals, EncTicketPart *tkt){ krb5_error_code ret; KRB5SignedPath sp; krb5_data data; krb5_crypto crypto = NULL; size_t size; if (server && principals) { ret = add_KRB5SignedPathPrincipals(principals, server); if (ret) return ret; } { KRB5SignedPathData spd; spd.encticket = *tkt; spd.delegated = principals; ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, &spd, &size, ret); if (ret) return ret; if (data.length != size) krb5_abortx(context, "internal asn.1 encoder error"); } { Key *key; ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key); if (ret == 0) ret = krb5_crypto_init(context, &key->key, 0, &crypto); if (ret) { free(data.data); return ret; } } /* * Fill in KRB5SignedPath */ sp.etype = enctype; sp.delegated = principals; ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0, data.data, data.length, &sp.cksum); krb5_crypto_destroy(context, crypto); free(data.data); if (ret) return ret; ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret); free_Checksum(&sp.cksum); if (ret) return ret; if (data.length != size) krb5_abortx(context, "internal asn.1 encoder error"); /* * Add IF-RELEVANT(KRB5SignedPath) to the last slot in * authorization data field. */ ret = _kdc_tkt_add_if_relevant_ad(context, tkt, KRB5_AUTHDATA_SIGNTICKET, &data); krb5_data_free(&data); return ret;}static krb5_error_codecheck_KRB5SignedPath(krb5_context context, krb5_kdc_configuration *config, hdb_entry_ex *krbtgt, EncTicketPart *tkt, KRB5SignedPathPrincipals **delegated, int require_signedpath){ krb5_error_code ret; krb5_data data; krb5_crypto crypto = NULL; *delegated = NULL; ret = find_KRB5SignedPath(context, tkt->authorization_data, &data); if (ret == 0) { KRB5SignedPathData spd; KRB5SignedPath sp; AuthorizationData *ad; size_t size; ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL); krb5_data_free(&data); if (ret) return ret; spd.encticket = *tkt; /* the KRB5SignedPath is the last entry */ ad = spd.encticket.authorization_data; if (--ad->len == 0) spd.encticket.authorization_data = NULL; spd.delegated = sp.delegated; ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, &spd, &size, ret); ad->len++; spd.encticket.authorization_data = ad; if (ret) { free_KRB5SignedPath(&sp); return ret; } if (data.length != size) krb5_abortx(context, "internal asn.1 encoder error"); { Key *key; ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key); if (ret == 0) ret = krb5_crypto_init(context, &key->key, 0, &crypto); if (ret) { free(data.data); free_KRB5SignedPath(&sp); return ret; } } ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, data.data, data.length, &sp.cksum); krb5_crypto_destroy(context, crypto); free(data.data); if (ret) { free_KRB5SignedPath(&sp); return ret; } if (sp.delegated) { *delegated = malloc(sizeof(*sp.delegated)); if (*delegated == NULL) { free_KRB5SignedPath(&sp); return ENOMEM; } ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated); if (ret) { free_KRB5SignedPath(&sp); free(*delegated); *delegated = NULL; return ret; } } free_KRB5SignedPath(&sp); } else { if (require_signedpath) return KRB5KDC_ERR_BADOPTION; } return 0;}/* * */static krb5_error_codecheck_PAC(krb5_context context, krb5_kdc_configuration *config, const krb5_principal client_principal, hdb_entry_ex *client, hdb_entry_ex *server, const EncryptionKey *server_key, const EncryptionKey *krbtgt_key, EncTicketPart *tkt, krb5_data *rspac, int *require_signedpath){ AuthorizationData *ad = tkt->authorization_data; unsigned i, j; krb5_error_code ret; if (ad == NULL || ad->len == 0) return 0; for (i = 0; i < ad->len; i++) { AuthorizationData child; if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) continue; ret = decode_AuthorizationData(ad->val[i].ad_data.data, ad->val[i].ad_data.length, &child, NULL); if (ret) { krb5_set_error_string(context, "Failed to decode " "IF_RELEVANT with %d", ret); return ret; } for (j = 0; j < child.len; j++) { if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { krb5_pac pac; /* Found PAC */ ret = krb5_pac_parse(context, child.val[j].ad_data.data, child.val[j].ad_data.length, &pac); free_AuthorizationData(&child); if (ret) return ret; ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal, krbtgt_key, NULL); if (ret) { krb5_pac_free(context, pac); return ret; } ret = _kdc_pac_verify(context, client_principal, client, server, &pac); if (ret) { krb5_pac_free(context, pac); return ret; } *require_signedpath = 0; ret = _krb5_pac_sign(context, pac, tkt->authtime, client_principal, server_key, krbtgt_key, rspac); krb5_pac_free(context, pac); return ret; } } free_AuthorizationData(&child); } return 0;}/* * */static krb5_error_codecheck_tgs_flags(krb5_context context, krb5_kdc_configuration *config, KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et){ KDCOptions f = b->kdc_options; if(f.validate){ if(!tgt->flags.invalid || tgt->starttime == NULL){ kdc_log(context, config, 0, "Bad request to validate ticket"); return KRB5KDC_ERR_BADOPTION; } if(*tgt->starttime > kdc_time){ kdc_log(context, config, 0, "Early request to validate ticket"); return KRB5KRB_AP_ERR_TKT_NYV; } /* XXX tkt = tgt */ et->flags.invalid = 0; }else if(tgt->flags.invalid){ kdc_log(context, config, 0, "Ticket-granting ticket has INVALID flag set"); return KRB5KRB_AP_ERR_TKT_INVALID; } if(f.forwardable){ if(!tgt->flags.forwardable){ kdc_log(context, config, 0, "Bad request for forwardable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.forwardable = 1; } if(f.forwarded){ if(!tgt->flags.forwardable){ kdc_log(context, config, 0, "Request to forward non-forwardable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.forwarded = 1; et->caddr = b->addresses; } if(tgt->flags.forwarded) et->flags.forwarded = 1; if(f.proxiable){ if(!tgt->flags.proxiable){ kdc_log(context, config, 0, "Bad request for proxiable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.proxiable = 1; } if(f.proxy){ if(!tgt->flags.proxiable){ kdc_log(context, config, 0, "Request to proxy non-proxiable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.proxy = 1; et->caddr = b->addresses; } if(tgt->flags.proxy) et->flags.proxy = 1; if(f.allow_postdate){ if(!tgt->flags.may_postdate){ kdc_log(context, config, 0, "Bad request for post-datable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.may_postdate = 1; } if(f.postdated){ if(!tgt->flags.may_postdate){ kdc_log(context, config, 0, "Bad request for postdated ticket"); return KRB5KDC_ERR_BADOPTION; } if(b->from) *et->starttime = *b->from; et->flags.postdated = 1; et->flags.invalid = 1; }else if(b->from && *b->from > kdc_time + context->max_skew){ kdc_log(context, config, 0, "Ticket cannot be postdated"); return KRB5KDC_ERR_CANNOT_POSTDATE; } if(f.renewable){ if(!tgt->flags.renewable){ kdc_log(context, config, 0, "Bad request for renewable ticket"); return KRB5KDC_ERR_BADOPTION; } et->flags.renewable = 1; ALLOC(et->renew_till); _kdc_fix_time(&b->rtime); *et->renew_till = *b->rtime; } if(f.renew){ time_t old_life; if(!tgt->flags.renewable || tgt->renew_till == NULL){ kdc_log(context, config, 0, "Request to renew non-renewable ticket"); return KRB5KDC_ERR_BADOPTION; } old_life = tgt->endtime; if(tgt->starttime) old_life -= *tgt->starttime; else old_life -= tgt->authtime; et->endtime = *et->starttime + old_life; if (et->renew_till != NULL) et->endtime = min(*et->renew_till, et->endtime); } #if 0 /* checks for excess flags */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -