Skip to content

Commit

Permalink
Refactor KDC option/flag processing
Browse files Browse the repository at this point in the history
A lot of KDC code was spent copying options to flags, and copying
header_ticket flags to the output ticket.

Behavior change: previous code didn't copy PROXY from the
header_ticket, but this seems to have been a minor bug rather than
intentional.  This also seems to have been an omission from RFC 4120.
  • Loading branch information
tlyu committed Apr 28, 2014
1 parent f5645d3 commit 4d08c9a
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 50 deletions.
18 changes: 4 additions & 14 deletions src/kdc/do_as_req.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
/* kdc/do_as_req.c */
/*
* Portions Copyright (C) 2007 Apple Inc.
* Copyright 1990, 1991, 2007, 2008, 2009, 2013 by the Massachusetts Institute
* of Technology. All Rights Reserved.
* Copyright 1990, 1991, 2007, 2008, 2009, 2013, 2014 by the
* Massachusetts Institute of Technology. All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
Expand Down Expand Up @@ -686,7 +686,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
state->ticket_reply.server = state->request->server;
}

state->enc_tkt_reply.flags = 0;
/* Copy options that request the corresponding ticket flags. */
state->enc_tkt_reply.flags = OPTS2FLAGS(state->request->kdc_options);
state->enc_tkt_reply.times.authtime = state->authtime;

setflag(state->enc_tkt_reply.flags, TKT_FLG_INITIAL);
Expand All @@ -698,15 +699,6 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
* realms may refuse to issue renewable tickets
*/

if (isflagset(state->request->kdc_options, KDC_OPT_FORWARDABLE))
setflag(state->enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);

if (isflagset(state->request->kdc_options, KDC_OPT_PROXIABLE))
setflag(state->enc_tkt_reply.flags, TKT_FLG_PROXIABLE);

if (isflagset(state->request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
setflag(state->enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);

state->enc_tkt_reply.session = &state->session_key;
if (isflagset(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
state->client_princ = *(state->client->princ);
Expand All @@ -720,7 +712,6 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
state->enc_tkt_reply.transited.tr_contents = empty_string;

if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED)) {
setflag(state->enc_tkt_reply.flags, TKT_FLG_POSTDATED);
setflag(state->enc_tkt_reply.flags, TKT_FLG_INVALID);
state->enc_tkt_reply.times.starttime = state->request->from;
} else
Expand Down Expand Up @@ -757,7 +748,6 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
state->status = "VALIDATE_ANONYMOUS_PRINCIPAL";
goto errout;
}
setflag(state->enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
krb5_free_principal(kdc_context, state->request->client);
state->request->client = NULL;
errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
Expand Down
46 changes: 11 additions & 35 deletions src/kdc/do_tgs_req.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* kdc/do_tgs_req.c - KDC Routines to deal with TGS_REQ's */
/*
* Copyright 1990, 1991, 2001, 2007, 2008, 2009, 2013 by the Massachusetts
* Institute of Technology. All Rights Reserved.
* Copyright 1990, 1991, 2001, 2007, 2008, 2009, 2013, 2014 by the
* Massachusetts Institute of Technology. All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
Expand Down Expand Up @@ -376,7 +376,8 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt,
else
ticket_reply.server = request->server; /* XXX careful for realm... */

enc_tkt_reply.flags = 0;
enc_tkt_reply.flags = OPTS2FLAGS(request->kdc_options);
enc_tkt_reply.flags |= COPY_TKT_FLAGS(header_enc_tkt->flags);
enc_tkt_reply.times.starttime = 0;

if (isflagset(server->attributes, KRB5_KDB_OK_AS_DELEGATE))
Expand Down Expand Up @@ -404,7 +405,6 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt,
*/

if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE)) {
setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);

if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
/*
Expand Down Expand Up @@ -435,34 +435,21 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt,
}
}

if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) {
setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);
if (isflagset(request->kdc_options, KDC_OPT_FORWARDED) ||
isflagset(request->kdc_options, KDC_OPT_PROXY)) {

/* include new addresses in ticket & reply */

enc_tkt_reply.caddrs = request->addresses;
reply_encpart.caddrs = request->addresses;
}
if (isflagset(header_enc_tkt->flags, TKT_FLG_FORWARDED))
setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);

if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE))
setflag(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);

if (isflagset(request->kdc_options, KDC_OPT_PROXY)) {
setflag(enc_tkt_reply.flags, TKT_FLG_PROXY);

/* include new addresses in ticket & reply */

enc_tkt_reply.caddrs = request->addresses;
reply_encpart.caddrs = request->addresses;
}

if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
/* We don't currently handle issuing anonymous tickets based on
* non-anonymous ones, so just ignore the option. */
if (isflagset(request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS) &&
!isflagset(header_enc_tkt->flags, TKT_FLG_ANONYMOUS))
clear(enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);

if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
enc_tkt_reply.times.starttime = request->from;
} else
Expand Down Expand Up @@ -506,22 +493,11 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt,
kdc_get_ticket_renewtime(kdc_active_realm, request, header_enc_tkt, client,
server, &enc_tkt_reply);

if (isflagset(header_enc_tkt->flags, TKT_FLG_ANONYMOUS))
setflag(enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
/*
* Set authtime to be the same as header or evidence ticket's
*/
enc_tkt_reply.times.authtime = authtime;

/*
* Propagate the preauthentication flags through to the returned ticket.
*/
if (isflagset(header_enc_tkt->flags, TKT_FLG_PRE_AUTH))
setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH);

if (isflagset(header_enc_tkt->flags, TKT_FLG_HW_AUTH))
setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH);

/* starttime is optional, and treated as authtime if not present.
so we can nuke it if it matches */
if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
Expand Down
68 changes: 67 additions & 1 deletion src/kdc/kdc_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* kdc/kdc_util.h */
/*
* Portions Copyright (C) 2007 Apple Inc.
* Copyright 1990, 2007 by the Massachusetts Institute of Technology.
* 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.
Expand Down Expand Up @@ -414,6 +414,72 @@ struct krb5_kdcpreauth_rock_st {
/* TGS-REQ options which are not compatible with referrals */
#define NO_REFERRAL_OPTION (NON_TGT_OPTION | KDC_OPT_ENC_TKT_IN_SKEY)

/*
* 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);
Expand Down

0 comments on commit 4d08c9a

Please sign in to comment.