krb5 commit: Move validate_tgs_request() to a separate file
Tom Yu
tlyu at MIT.EDU
Mon Oct 15 20:27:44 EDT 2012
https://github.com/krb5/krb5/commit/6f1a8f8c42cfc92fce8745e9228badb080bac892
commit 6f1a8f8c42cfc92fce8745e9228badb080bac892
Author: Tom Yu <tlyu at mit.edu>
Date: Thu Sep 20 14:13:44 2012 -0400
Move validate_tgs_request() to a separate file
src/kdc/Makefile.in | 6 +-
src/kdc/kdc_util.c | 334 +-------------------------------------------
src/kdc/kdc_util.h | 7 +
src/kdc/tgs_policy.c | 381 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 394 insertions(+), 334 deletions(-)
diff --git a/src/kdc/Makefile.in b/src/kdc/Makefile.in
index 52e65d6..acc7dbb 100644
--- a/src/kdc/Makefile.in
+++ b/src/kdc/Makefile.in
@@ -27,7 +27,8 @@ SRCS= \
$(srcdir)/extern.c \
$(srcdir)/replay.c \
$(srcdir)/kdc_authdata.c \
- $(srcdir)/kdc_transit.c
+ $(srcdir)/kdc_transit.c \
+ $(srcdir)/tgs_policy.c
OBJS= \
kdc5_err.o \
@@ -44,7 +45,8 @@ OBJS= \
extern.o \
replay.o \
kdc_authdata.o \
- kdc_transit.o
+ kdc_transit.o \
+ tgs_policy.o
RT_OBJS= rtest.o \
kdc_transit.o
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index 0162f79..10ed383 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -551,7 +551,7 @@ check_hot_list(krb5_ticket *ticket)
/* Convert an API error code to a protocol error code. */
-static int
+int
errcode_to_protocol(krb5_error_code code)
{
int protcode;
@@ -562,7 +562,7 @@ errcode_to_protocol(krb5_error_code code)
/* Return -1 if the AS or TGS request is disallowed due to KDC policy on
* anonymous tickets. */
-static int
+int
check_anon(kdc_realm_t *kdc_active_realm,
krb5_principal client, krb5_principal server)
{
@@ -874,336 +874,6 @@ fetch_asn1_field(unsigned char *astream, unsigned int level,
return(-1);
}
-/*
- * Routines that validate a TGS request; checks a lot of things. :-)
- *
- * Returns a Kerberos protocol error number, which is _not_ the same
- * as a com_err error number!
- */
-
-struct tgsflagrule {
- krb5_flags reqflags; /* Flag(s) in TGS-REQ */
- krb5_flags checkflag; /* Flags to check against */
- char *status; /* Status string */
- int err; /* Protocol error code */
-};
-
-/* Service principal TGS policy checking functions */
-typedef int (check_tgs_svc_pol_fn)(krb5_kdc_req *, krb5_db_entry,
- krb5_ticket *, const char **);
-
-static check_tgs_svc_pol_fn check_tgs_svc_deny_opts;
-static check_tgs_svc_pol_fn check_tgs_svc_deny_all;
-static check_tgs_svc_pol_fn check_tgs_svc_reqd_flags;
-
-static const struct tgsflagrule tgsflagrules[] = {
- { (KDC_OPT_FORWARDED | KDC_OPT_FORWARDABLE), TKT_FLG_FORWARDABLE,
- "TGT NOT FORWARDABLE", KDC_ERR_BADOPTION },
- { (KDC_OPT_PROXY | KDC_OPT_PROXIABLE), TKT_FLG_PROXIABLE,
- "TGT NOT PROXIABLE", KDC_ERR_BADOPTION },
- { (KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED), TKT_FLG_MAY_POSTDATE,
- "TGT NOT POSTDATABLE", KDC_ERR_BADOPTION },
- { KDC_OPT_VALIDATE, TKT_FLG_INVALID,
- "VALIDATE VALID TICKET", KDC_ERR_BADOPTION },
- { (KDC_OPT_RENEW | KDC_OPT_RENEWABLE), TKT_FLG_RENEWABLE,
- "TICKET NOT RENEWABLE", KDC_ERR_BADOPTION }
-};
-
-/*
- * Check that TGS-REQ options are consistent with the ticket flags.
- */
-static int
-check_tgs_opts(krb5_kdc_req *req, krb5_ticket *tkt, const char **status)
-{
- size_t i;
- size_t nrules = sizeof(tgsflagrules) / sizeof(tgsflagrules[0]);
- const struct tgsflagrule *r;
-
- for (i = 0; i < nrules; i++) {
- r = &tgsflagrules[i];
- if (!(r->reqflags & req->kdc_options))
- continue;
- if (!(r->checkflag & tkt->enc_part2->flags)) {
- *status = r->status;
- return r->err;
- }
- }
- return 0;
-}
-
-static const struct tgsflagrule svcdenyrules[] = {
- { KDC_OPT_FORWARDABLE, KRB5_KDB_DISALLOW_FORWARDABLE,
- "NON-FORWARDABLE TICKET", KDC_ERR_POLICY },
- { KDC_OPT_RENEWABLE, KRB5_KDB_DISALLOW_RENEWABLE,
- "NON-RENEWABLE TICKET", KDC_ERR_POLICY },
- { KDC_OPT_PROXIABLE, KRB5_KDB_DISALLOW_PROXIABLE,
- "NON-PROXIABLE TICKET", KDC_ERR_POLICY },
- { KDC_OPT_ALLOW_POSTDATE, KRB5_KDB_DISALLOW_POSTDATED,
- "NON-POSTDATABLE TICKET", KDC_ERR_CANNOT_POSTDATE },
- { KDC_OPT_ENC_TKT_IN_SKEY, KRB5_KDB_DISALLOW_DUP_SKEY,
- "DUP_SKEY DISALLOWED", KDC_ERR_POLICY }
-};
-
-/*
- * A service principal can forbid some TGS-REQ options.
- */
-static int
-check_tgs_svc_deny_opts(krb5_kdc_req *req, krb5_db_entry server,
- krb5_ticket *tkt, const char **status)
-{
- size_t i;
- size_t nrules = sizeof(svcdenyrules) / sizeof(svcdenyrules[0]);
- const struct tgsflagrule *r;
-
- for (i = 0; i < nrules; i++) {
- r = &svcdenyrules[i];
- if (!(r->reqflags & req->kdc_options))
- continue;
- if (r->checkflag & server.attributes) {
- *status = r->status;
- return r->err;
- }
- }
- return 0;
-}
-
-static int
-check_tgs_svc_deny_all(krb5_kdc_req *req, krb5_db_entry server,
- krb5_ticket *tkt, const char **status)
-{
- if (server.attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
- *status = "SERVER LOCKED OUT";
- return KDC_ERR_S_PRINCIPAL_UNKNOWN;
- }
- if (server.attributes & KRB5_KDB_DISALLOW_SVR) {
- *status = "SERVER NOT ALLOWED";
- return KDC_ERR_MUST_USE_USER2USER;
- }
- return 0;
-}
-
-/*
- * A service principal can require certain TGT flags.
- */
-static int
-check_tgs_svc_reqd_flags(krb5_kdc_req *req, krb5_db_entry server,
- krb5_ticket *tkt, const char **status)
-{
- if (server.attributes & KRB5_KDB_REQUIRES_HW_AUTH &&
- !(tkt->enc_part2->flags & TKT_FLG_HW_AUTH)) {
- *status = "NO HW PREAUTH";
- return KRB_ERR_GENERIC;
- }
- if (server.attributes & KRB5_KDB_REQUIRES_PRE_AUTH &&
- !(tkt->enc_part2->flags & TKT_FLG_PRE_AUTH)) {
- *status = "NO PREAUTH";
- return KRB_ERR_GENERIC;
- }
- return 0;
-}
-
-static check_tgs_svc_pol_fn *svc_pol_fns[] = {
- check_tgs_svc_deny_opts, check_tgs_svc_deny_all, check_tgs_svc_reqd_flags
-};
-
-static int
-check_tgs_svc_policy(krb5_kdc_req *req, krb5_db_entry server,
- krb5_ticket *tkt, const char **status)
-{
- int errcode;
- size_t i;
- size_t nfns = sizeof(svc_pol_fns) / sizeof(svc_pol_fns[0]);
-
- for (i = 0; i < nfns; i++) {
- errcode = svc_pol_fns[i](req, server, tkt, status);
- if (errcode != 0)
- return errcode;
- }
- return 0;
-}
-
-/*
- * Check some timestamps in the TGS-REQ.
- */
-static int
-check_tgs_times(krb5_kdc_req *req, krb5_db_entry server, krb5_ticket *tkt,
- krb5_timestamp kdc_time, const char **status)
-{
-
- /* Check to see if service principal has expired. */
- if (server.expiration && server.expiration < kdc_time) {
- *status = "SERVICE EXPIRED";
- return KDC_ERR_SERVICE_EXP;
- }
- /* For validating a postdated ticket, check the start time vs. the
- KDC time. */
- if (req->kdc_options & KDC_OPT_VALIDATE) {
- if (tkt->enc_part2->times.starttime > kdc_time) {
- *status = "NOT_YET_VALID";
- return KRB_AP_ERR_TKT_NYV;
- }
- }
- /*
- * Check the renew_till time. The endtime was already
- * been checked in the initial authentication check.
- */
- if ((req->kdc_options & KDC_OPT_RENEW) &&
- (tkt->enc_part2->times.renew_till < kdc_time)) {
- *status = "TKT_EXPIRED";
- return KRB_AP_ERR_TKT_EXPIRED;
- }
- return 0;
-}
-
-/*
- * Check second ticket, if required by TGS-REQ options.
- */
-static int
-check_2nd_tkt(kdc_realm_t *kdc_active_realm,
- krb5_kdc_req *req, const char **status)
-{
- /* user-to-user */
- if (req->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
- /* Check that second ticket is in request. */
- if (!req->second_ticket || !req->second_ticket[0]) {
- *status = "NO_2ND_TKT";
- return KDC_ERR_BADOPTION;
- }
- /* Check that second ticket is a TGT. */
- if (!krb5_principal_compare(kdc_context,
- req->second_ticket[0]->server,
- tgs_server)) {
- *status = "2ND_TKT_NOT_TGS";
- return KDC_ERR_POLICY;
- }
- }
- /* S4U2Proxy */
- if (req->kdc_options & KDC_OPT_CNAME_IN_ADDL_TKT) {
- /* Check that second ticket is in request. */
- if (!req->second_ticket || !req->second_ticket[0]) {
- *status = "NO_2ND_TKT";
- return KDC_ERR_BADOPTION;
- }
- }
- return 0;
-}
-
-/*
- * Some TGS-REQ options allow for a non-TGS principal in the ticket. Do some
- * checks that are peculiar to these cases. (e.g., ticket service principal
- * matches requested service principal)
- */
-static int
-check_tgs_nontgt(kdc_realm_t *kdc_active_realm,
- krb5_kdc_req *req, krb5_ticket *tkt, const char **status)
-{
-
- if (!krb5_principal_compare(kdc_context, tkt->server, req->server)) {
- *status = "SERVER DIDN'T MATCH TICKET FOR RENEW/FORWARD/ETC";
- return KDC_ERR_SERVER_NOMATCH;
- }
- /* Cannot proxy ticket granting tickets. */
- if ((req->kdc_options & KDC_OPT_PROXY) &&
- krb5_is_tgs_principal(req->server)) {
- *status = "CAN'T PROXY TGT";
- return KDC_ERR_BADOPTION;
- }
- return 0;
-}
-
-/*
- * Do some checks for a normal TGS-REQ (where the ticket service must be a TGS
- * principal).
- */
-static int
-check_tgs_tgt(kdc_realm_t *kdc_active_realm,
- krb5_kdc_req *req, krb5_db_entry server,
- krb5_ticket *tkt, const char **status)
-{
- /* Make sure it's a TGS principal. */
- if (!krb5_is_tgs_principal(tkt->server)) {
- *status = "BAD TGS SERVER NAME";
- return KRB_AP_ERR_NOT_US;
- }
- /* TGS principal second component must match service realm. */
- if (!data_eq(*krb5_princ_component(kdc_context, tkt->server, 1),
- *krb5_princ_realm(kdc_context, req->server))) {
- *status = "BAD TGS SERVER INSTANCE";
- return KRB_AP_ERR_NOT_US;
- }
- /* Server must allow TGS based issuances */
- if (server.attributes & KRB5_KDB_DISALLOW_TGT_BASED) {
- *status = "TGT BASED NOT ALLOWED";
- return KDC_ERR_POLICY;
- }
- return 0;
-}
-
-/* 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)
-
-int
-validate_tgs_request(kdc_realm_t *kdc_active_realm,
- register krb5_kdc_req *request, krb5_db_entry server,
- krb5_ticket *ticket, krb5_timestamp kdc_time,
- const char **status, krb5_pa_data ***e_data)
-{
- int errcode;
- krb5_error_code ret;
-
- errcode = check_tgs_times(request, server, ticket, kdc_time, status);
- if (errcode != 0)
- return errcode;
-
- errcode = check_tgs_opts(request, ticket, status);
- if (errcode != 0)
- return errcode;
-
- errcode = check_tgs_svc_policy(request, server, ticket, status);
- if (errcode != 0)
- return errcode;
-
- if (request->kdc_options & NON_TGT_OPTION)
- errcode = check_tgs_nontgt(kdc_active_realm, request, ticket, status);
- else
- errcode = check_tgs_tgt(kdc_active_realm, request, server, ticket,
- status);
- if (errcode != 0)
- return errcode;
-
- /* Check the hot list */
- if (check_hot_list(ticket)) {
- *status = "HOT_LIST";
- return(KRB_AP_ERR_REPEAT);
- }
-
- errcode = check_2nd_tkt(kdc_active_realm, request, status);
- if (errcode != 0)
- return errcode;
-
- if (check_anon(kdc_active_realm, ticket->enc_part2->client,
- request->server) != 0) {
- *status = "ANONYMOUS NOT ALLOWED";
- return(KDC_ERR_POLICY);
- }
-
- /* Perform KDB module policy checks. */
- ret = krb5_db_check_policy_tgs(kdc_context, request, &server,
- ticket, status, e_data);
- if (ret && ret != KRB5_PLUGIN_OP_NOTSUPP)
- return errcode_to_protocol(ret);
-
- /* Check local policy. */
- errcode = against_local_policy_tgs(request, server, ticket,
- status, e_data);
- if (errcode)
- return errcode;
-
-
- return 0;
-}
-
/* Return true if we believe server can support enctype as a session key. */
static krb5_boolean
dbentry_supports_enctype(kdc_realm_t *kdc_active_realm, krb5_db_entry *server,
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index 2f215a7..b89bd99 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -392,5 +392,12 @@ struct krb5_kdcpreauth_rock_st {
/* 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)
+int check_anon(kdc_realm_t *kdc_active_realm,
+ krb5_principal client, krb5_principal server);
+int errcode_to_protocol(krb5_error_code code);
#endif /* __KRB5_KDC_UTIL__ */
diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c
new file mode 100644
index 0000000..0650c23
--- /dev/null
+++ b/src/kdc/tgs_policy.c
@@ -0,0 +1,381 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* kdc/tgs_policy.c */
+/*
+ * Copyright (C) 2012 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 "k5-int.h"
+#include "kdc_util.h"
+
+/*
+ * Routines that validate a TGS request; checks a lot of things. :-)
+ *
+ * Returns a Kerberos protocol error number, which is _not_ the same
+ * as a com_err error number!
+ */
+
+struct tgsflagrule {
+ krb5_flags reqflags; /* Flag(s) in TGS-REQ */
+ krb5_flags checkflag; /* Flags to check against */
+ char *status; /* Status string */
+ int err; /* Protocol error code */
+};
+
+/* Service principal TGS policy checking functions */
+typedef int (check_tgs_svc_pol_fn)(krb5_kdc_req *, krb5_db_entry,
+ krb5_ticket *, krb5_timestamp,
+ const char **);
+
+static check_tgs_svc_pol_fn check_tgs_svc_deny_opts;
+static check_tgs_svc_pol_fn check_tgs_svc_deny_all;
+static check_tgs_svc_pol_fn check_tgs_svc_reqd_flags;
+static check_tgs_svc_pol_fn check_tgs_svc_time;
+
+static check_tgs_svc_pol_fn * const svc_pol_fns[] = {
+ check_tgs_svc_deny_opts, check_tgs_svc_deny_all, check_tgs_svc_reqd_flags,
+ check_tgs_svc_time
+};
+
+static const struct tgsflagrule tgsflagrules[] = {
+ { (KDC_OPT_FORWARDED | KDC_OPT_FORWARDABLE), TKT_FLG_FORWARDABLE,
+ "TGT NOT FORWARDABLE", KDC_ERR_BADOPTION },
+ { (KDC_OPT_PROXY | KDC_OPT_PROXIABLE), TKT_FLG_PROXIABLE,
+ "TGT NOT PROXIABLE", KDC_ERR_BADOPTION },
+ { (KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED), TKT_FLG_MAY_POSTDATE,
+ "TGT NOT POSTDATABLE", KDC_ERR_BADOPTION },
+ { KDC_OPT_VALIDATE, TKT_FLG_INVALID,
+ "VALIDATE VALID TICKET", KDC_ERR_BADOPTION },
+ { (KDC_OPT_RENEW | KDC_OPT_RENEWABLE), TKT_FLG_RENEWABLE,
+ "TICKET NOT RENEWABLE", KDC_ERR_BADOPTION }
+};
+
+/*
+ * Some TGS-REQ options require that the ticket have corresponding flags set.
+ */
+static int
+check_tgs_opts(krb5_kdc_req *req, krb5_ticket *tkt, const char **status)
+{
+ size_t i;
+ size_t nrules = sizeof(tgsflagrules) / sizeof(tgsflagrules[0]);
+ const struct tgsflagrule *r;
+
+ for (i = 0; i < nrules; i++) {
+ r = &tgsflagrules[i];
+ if (r->reqflags & req->kdc_options) {
+ if (!(r->checkflag & tkt->enc_part2->flags)) {
+ *status = r->status;
+ return r->err;
+ }
+ }
+ }
+ return 0;
+}
+
+static const struct tgsflagrule svcdenyrules[] = {
+ { KDC_OPT_FORWARDABLE, KRB5_KDB_DISALLOW_FORWARDABLE,
+ "NON-FORWARDABLE TICKET", KDC_ERR_POLICY },
+ { KDC_OPT_RENEWABLE, KRB5_KDB_DISALLOW_RENEWABLE,
+ "NON-RENEWABLE TICKET", KDC_ERR_POLICY },
+ { KDC_OPT_PROXIABLE, KRB5_KDB_DISALLOW_PROXIABLE,
+ "NON-PROXIABLE TICKET", KDC_ERR_POLICY },
+ { KDC_OPT_ALLOW_POSTDATE, KRB5_KDB_DISALLOW_POSTDATED,
+ "NON-POSTDATABLE TICKET", KDC_ERR_CANNOT_POSTDATE },
+ { KDC_OPT_ENC_TKT_IN_SKEY, KRB5_KDB_DISALLOW_DUP_SKEY,
+ "DUP_SKEY DISALLOWED", KDC_ERR_POLICY }
+};
+
+/*
+ * A service principal can forbid some TGS-REQ options.
+ */
+static int
+check_tgs_svc_deny_opts(krb5_kdc_req *req, krb5_db_entry server,
+ krb5_ticket *tkt, krb5_timestamp kdc_time,
+ const char **status)
+{
+ size_t i;
+ size_t nrules = sizeof(svcdenyrules) / sizeof(svcdenyrules[0]);
+ const struct tgsflagrule *r;
+
+ for (i = 0; i < nrules; i++) {
+ r = &svcdenyrules[i];
+ if (!(r->reqflags & req->kdc_options))
+ continue;
+ if (r->checkflag & server.attributes) {
+ *status = r->status;
+ return r->err;
+ }
+ }
+ return 0;
+}
+
+/*
+ * A service principal can deny all TGS-REQs for it.
+ */
+static int
+check_tgs_svc_deny_all(krb5_kdc_req *req, krb5_db_entry server,
+ krb5_ticket *tkt, krb5_timestamp kdc_time,
+ const char **status)
+{
+ if (server.attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
+ *status = "SERVER LOCKED OUT";
+ return KDC_ERR_S_PRINCIPAL_UNKNOWN;
+ }
+ if (server.attributes & KRB5_KDB_DISALLOW_SVR) {
+ *status = "SERVER NOT ALLOWED";
+ return KDC_ERR_MUST_USE_USER2USER;
+ }
+ if (server.attributes & KRB5_KDB_DISALLOW_TGT_BASED) {
+ if (krb5_is_tgs_principal(tkt->server)) {
+ *status = "TGT BASED NOT ALLOWED";
+ return KDC_ERR_POLICY;
+ }
+ }
+ return 0;
+}
+
+/*
+ * A service principal can require certain TGT flags.
+ */
+static int
+check_tgs_svc_reqd_flags(krb5_kdc_req *req, krb5_db_entry server,
+ krb5_ticket *tkt,
+ krb5_timestamp kdc_time, const char **status)
+{
+ if (server.attributes & KRB5_KDB_REQUIRES_HW_AUTH) {
+ if (!(tkt->enc_part2->flags & TKT_FLG_HW_AUTH)) {
+ *status = "NO HW PREAUTH";
+ return KRB_ERR_GENERIC;
+ }
+ }
+ if (server.attributes & KRB5_KDB_REQUIRES_PRE_AUTH) {
+ if (!(tkt->enc_part2->flags & TKT_FLG_PRE_AUTH)) {
+ *status = "NO PREAUTH";
+ return KRB_ERR_GENERIC;
+ }
+ }
+ return 0;
+}
+
+static int
+check_tgs_svc_time(krb5_kdc_req *req, krb5_db_entry server, krb5_ticket *tkt,
+ krb5_timestamp kdc_time, const char **status)
+{
+ if (server.expiration && server.expiration < kdc_time) {
+ *status = "SERVICE EXPIRED";
+ return KDC_ERR_SERVICE_EXP;
+ }
+ return 0;
+}
+
+static int
+check_tgs_svc_policy(krb5_kdc_req *req, krb5_db_entry server, krb5_ticket *tkt,
+ krb5_timestamp kdc_time, const char **status)
+{
+ int errcode;
+ size_t i;
+ size_t nfns = sizeof(svc_pol_fns) / sizeof(svc_pol_fns[0]);
+
+ for (i = 0; i < nfns; i++) {
+ errcode = svc_pol_fns[i](req, server, tkt, kdc_time, status);
+ if (errcode != 0)
+ return errcode;
+ }
+ return 0;
+}
+
+/*
+ * Check some timestamps in the TGS-REQ.
+ */
+static int
+check_tgs_times(krb5_kdc_req *req, krb5_ticket *tkt,
+ krb5_timestamp kdc_time, const char **status)
+{
+ /* For validating a postdated ticket, check the start time vs. the
+ KDC time. */
+ if (req->kdc_options & KDC_OPT_VALIDATE) {
+ if (tkt->enc_part2->times.starttime > kdc_time) {
+ *status = "NOT_YET_VALID";
+ return KRB_AP_ERR_TKT_NYV;
+ }
+ }
+ /*
+ * Check the renew_till time. The endtime was already
+ * been checked in the initial authentication check.
+ */
+ if ((req->kdc_options & KDC_OPT_RENEW) &&
+ (tkt->enc_part2->times.renew_till < kdc_time)) {
+ *status = "TKT_EXPIRED";
+ return KRB_AP_ERR_TKT_EXPIRED;
+ }
+ return 0;
+}
+
+static int
+check_tgs_s4u2proxy(kdc_realm_t *kdc_active_realm,
+ krb5_kdc_req *req, const char **status)
+{
+ if (req->kdc_options & KDC_OPT_CNAME_IN_ADDL_TKT) {
+ /* Check that second ticket is in request. */
+ if (!req->second_ticket || !req->second_ticket[0]) {
+ *status = "NO_2ND_TKT";
+ return KDC_ERR_BADOPTION;
+ }
+ }
+ return 0;
+}
+
+static int
+check_tgs_u2u(kdc_realm_t *kdc_active_realm,
+ krb5_kdc_req *req, const char **status)
+{
+ if (req->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
+ /* Check that second ticket is in request. */
+ if (!req->second_ticket || !req->second_ticket[0]) {
+ *status = "NO_2ND_TKT";
+ return KDC_ERR_BADOPTION;
+ }
+ /* Check that second ticket is a TGT. */
+ if (!krb5_principal_compare(kdc_context,
+ req->second_ticket[0]->server,
+ tgs_server)) {
+ *status = "2ND_TKT_NOT_TGS";
+ return KDC_ERR_POLICY;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Some TGS-REQ options allow for a non-TGS principal in the ticket. Do some
+ * checks that are peculiar to these cases. (e.g., ticket service principal
+ * matches requested service principal)
+ */
+static int
+check_tgs_nontgt(kdc_realm_t *kdc_active_realm,
+ krb5_kdc_req *req, krb5_ticket *tkt, const char **status)
+{
+ if (!krb5_principal_compare(kdc_context, tkt->server, req->server)) {
+ *status = "SERVER DIDN'T MATCH TICKET FOR RENEW/FORWARD/ETC";
+ return KDC_ERR_SERVER_NOMATCH;
+ }
+ /* Cannot proxy ticket granting tickets. */
+ if ((req->kdc_options & KDC_OPT_PROXY) &&
+ krb5_is_tgs_principal(req->server)) {
+ *status = "CAN'T PROXY TGT";
+ return KDC_ERR_BADOPTION;
+ }
+ return 0;
+}
+
+/*
+ * Do some checks for a normal TGS-REQ (where the ticket service must be a TGS
+ * principal).
+ */
+static int
+check_tgs_tgt(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
+ krb5_ticket *tkt, const char **status)
+{
+ /* Make sure it's a TGS principal. */
+ if (!krb5_is_tgs_principal(tkt->server)) {
+ *status = "BAD TGS SERVER NAME";
+ return KRB_AP_ERR_NOT_US;
+ }
+ /* TGS principal second component must match service realm. */
+ if (!data_eq(*krb5_princ_component(kdc_context, tkt->server, 1),
+ *krb5_princ_realm(kdc_context, req->server))) {
+ *status = "BAD TGS SERVER INSTANCE";
+ return KRB_AP_ERR_NOT_US;
+ }
+ return 0;
+}
+
+int
+validate_tgs_request(kdc_realm_t *kdc_active_realm,
+ register krb5_kdc_req *request, krb5_db_entry server,
+ krb5_ticket *ticket, krb5_timestamp kdc_time,
+ const char **status, krb5_pa_data ***e_data)
+{
+ int errcode;
+ krb5_error_code ret;
+
+ /* Depends only on request and ticket. */
+ errcode = check_tgs_opts(request, ticket, status);
+ if (errcode != 0)
+ return errcode;
+
+ /* Depends only on request, ticket, and time. */
+ errcode = check_tgs_times(request, ticket, kdc_time, status);
+ if (errcode != 0)
+ return errcode;
+
+ errcode = check_tgs_svc_policy(request, server, ticket, kdc_time, status);
+ if (errcode != 0)
+ return errcode;
+
+ if (request->kdc_options & NON_TGT_OPTION)
+ errcode = check_tgs_nontgt(kdc_active_realm, request, ticket, status);
+ else
+ errcode = check_tgs_tgt(kdc_active_realm, request, ticket, status);
+ if (errcode != 0)
+ return errcode;
+
+ /* Check the hot list */
+ if (check_hot_list(ticket)) {
+ *status = "HOT_LIST";
+ return(KRB_AP_ERR_REPEAT);
+ }
+
+ errcode = check_tgs_u2u(kdc_active_realm, request, status);
+ if (errcode != 0)
+ return errcode;
+
+ errcode = check_tgs_s4u2proxy(kdc_active_realm, request, status);
+ if (errcode != 0)
+ return errcode;
+
+ if (check_anon(kdc_active_realm, ticket->enc_part2->client,
+ request->server) != 0) {
+ *status = "ANONYMOUS NOT ALLOWED";
+ return(KDC_ERR_POLICY);
+ }
+
+ /* Perform KDB module policy checks. */
+ ret = krb5_db_check_policy_tgs(kdc_context, request, &server,
+ ticket, status, e_data);
+ if (ret && ret != KRB5_PLUGIN_OP_NOTSUPP)
+ return errcode_to_protocol(ret);
+
+ /* Check local policy. */
+ errcode = against_local_policy_tgs(request, server, ticket,
+ status, e_data);
+ if (errcode)
+ return errcode;
+
+ return 0;
+}
More information about the cvs-krb5
mailing list