do_tgs_req.c revision 46736d35df047bb400483364f76bfcb08cdcbb25
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*
* Copyright 1990,1991,2001 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.
* 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.
*
*
* KDC Routines to deal with TGS_REQ's
*/
#define NEED_SOCKETS
#include "k5-int.h"
#include "com_err.h"
#include <syslog.h>
#ifdef HAVE_NETINET_IN_H
#ifndef hpux
#endif
#endif
#include "kdc_util.h"
#include "policy.h"
#include "extern.h"
#include "adm_proto.h"
krb5_boolean *, int *,
int, const char *, krb5_data **,
const char *);
/*ARGSUSED*/
{
krb5_kdc_req *request = 0;
int st_idx = 0;
int newtransited = 0;
krb5_error_code retval = 0;
int nprincs = 0;
const char *fromstring = 0;
/* krb5_address *noaddrarray[1]; */
register int i;
int firstpass = 1;
const char *status = 0;
char ktypestr[128];
char rep_etypestr[128];
char fromstringbuf[70];
long long tmp_server_times, tmp_realm_times;
if (retval)
return retval;
/*
* setup_server_realm() sets up the global realm-specific data pointer.
*/
return retval;
fromstringbuf, sizeof(fromstringbuf));
if (!fromstring)
fromstring = "<unknown>";
status = "UNPARSING SERVER";
goto cleanup;
}
/* errcode = kdc_process_tgs_req(request, from, pkt, &req_authdat); */
&cname))) {
status = "UNPARSING CLIENT";
goto cleanup;
}
if (errcode) {
status = "PROCESS_TGS";
goto cleanup;
}
if (!header_ticket) {
status="UNEXPECTED NULL in header_ticket";
goto cleanup;
}
/*
* We've already dealt with the AP_REQ authentication, so we can
* use header_ticket freely. The encrypted part (if any) has been
* decrypted with the session key.
*/
/* XXX make sure server here has the proper realm...taken from AP_REQ
header? */
nprincs = 1;
status = "LOOKING_UP_SERVER";
nprincs = 0;
goto cleanup;
}
if (more) {
status = "NON_UNIQUE_PRINCIPAL";
goto cleanup;
} else if (nprincs != 1) {
/*
* might be a request for a TGT for some other realm; we
* should do our best to find such a TGS in this db
*/
firstpass = 0;
goto tgt_again;
}
}
}
status = "UNKNOWN_SERVER";
goto cleanup;
}
status = "TIME_OF_DAY";
goto cleanup;
}
if (!status)
status = "UNKNOWN_REASON";
goto cleanup;
}
/*
* We pick the session keytype here....
*
* Some special care needs to be taken in the user-to-user
* case, since we don't know what keytypes the application server
* which is doing user-to-user authentication can support. We
* know that it at least must be able to support the encryption
* type of the session key in the TGT, since otherwise it won't be
* able to decrypt the U2U ticket! So we use that in preference
* to anything else.
*/
useenctype = 0;
/*
* Get the key for the second ticket, and decrypt it.
*/
&st_srv_kvno))) {
status = "2ND_TKT_SERVER";
goto cleanup;
}
if (errcode) {
status = "2ND_TKT_DECRYPT";
goto cleanup;
}
if (!krb5_c_valid_enctype(etype)) {
status = "BAD_ETYPE_IN_2ND_TKT";
goto cleanup;
}
useenctype = etype;
break;
}
}
}
/*
* Select the keytype for the ticket session key.
*/
if ((useenctype == 0) &&
/* unsupported ktype */
status = "BAD_ENCRYPTION_TYPE";
goto cleanup;
}
if (errcode) {
/* random key failed */
status = "RANDOM_KEY_FAILED";
goto cleanup;
}
enc_tkt_reply.flags = 0;
/*
* Fix header_ticket's starttime; if it's zero, fill in the
* authtime's value.
*/
/* don't use new addresses unless forwarded, see below */
/* noaddrarray[0] = 0; */
/* It should be noted that local policy may affect the */
/* processing of any of these flags. For example, some */
/* realms may refuse to issue renewable tickets */
/* include new addresses in ticket & reply */
}
/* include new addresses in ticket & reply */
}
} else
/* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
to the caller */
ticket_reply = *(header_ticket);
}
/* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
to the caller */
ticket_reply = *(header_ticket);
} else {
/* not a renew request */
/* SUNW */
KRB5_KDB_EXPIRATION)))); /* SUNW */
/*
enc_tkt_reply.times.endtime =
min(until, min(enc_tkt_reply.times.starttime + server.max_life,
min(enc_tkt_reply.times.starttime + max_life_for_realm,
min(header_ticket->enc_part2->times.endtime)));
*/
}
}
/* already checked above in policy check to reject request for a
renewable ticket using a non-renewable ticket */
} else {
}
/*
* Set authtime to be the same as header_ticket's
*/
/*
* Propagate the preauthentication flags through to the returned ticket.
*/
/* starttime is optional, and treated as authtime if not present.
so we can nuke it if it matches */
/* assemble any authorization data */
status = "AUTH_NOMEM";
goto cleanup;
}
0, &request->authorization_data,
&scratch))) {
status = "AUTH_ENCRYPT_FAIL";
goto cleanup;
}
/* scratch now has the authorization data, so we decode it */
if (errcode) {
status = "AUTH_DECODE";
goto cleanup;
}
if ((errcode =
status = "CONCAT_AUTH";
goto cleanup;
}
} else
/*
* Only add the realm of the presented tgt to the transited list if
* it is different than the local realm (cross-realm) and it is different
* than the realm of the client (since the realm of the client is already
* implicitly part of the transited list and should not be explicitly
* listed).
*/
/* realm compare is like strcmp, but knows how to deal with these args */
/* tgt issued by local realm or issued by realm of client */
} else {
/* tgt issued by some other realm and not the realm of the client */
/* assemble new transited field into allocated storage */
status = "BAD_TRTYPE";
goto cleanup;
}
if ((errcode =
status = "ADD_TR_FAIL";
goto cleanup;
}
newtransited = 1;
}
unsigned int tlen;
char *tdots;
if (errcode == 0) {
} else if (errcode == KRB5KRB_AP_ERR_ILL_CR_TKT)
"bad realm transit path from '%s' to '%s' "
"via '%.*s%s'",
tlen,
tdots);
else
"unexpected error checking transit from "
"'%s' to '%s' via '%.*s%s': %s",
tlen,
} else
status = "BAD_TRANSIT";
goto cleanup;
}
/*
* If we are doing user-to-user authentication, then make sure
* that the client for the second ticket matches the request
* server, and then encrypt the ticket using the session key of
* the second ticket.
*/
/*
* Make sure the client for the second ticket matches
* requested server.
*/
tmp = 0;
"TGS_REQ %s: 2ND_TKT_MISMATCH: "
"authtime %d, %s for %s, 2nd tkt client %s",
goto cleanup;
}
&ticket_reply))) {
status = "2ND_TKT_ENCRYPT";
goto cleanup;
}
st_idx++;
} else {
/*
* Find the server key
*/
-1, /* ignore keytype */
-1, /* Ignore salttype */
0, /* Get highest kvno */
&server_key))) {
status = "FINDING_SERVER_KEY";
goto cleanup;
}
/* convert server.key into a real key (it may be encrypted
* in the database) */
NULL))) {
status = "DECRYPT_SERVER_KEY";
goto cleanup;
}
&ticket_reply);
if (errcode) {
status = "TKT_ENCRYPT";
goto cleanup;
}
}
/* Start assembling the response */
/* copy the time fields EXCEPT for authtime; its location
is used for ktime */
/* starttime is optional, and treated as authtime if not present.
so we can nuke it if it matches */
nolrarray[1] = 0;
/* use the session key in the ticket, unless there's a subsession key
in the AP_REQ */
subkey ? 1 : 0,
if (errcode) {
status = "ENCODE_KDC_REP";
} else {
status = "ISSUE";
}
}
/* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
can use them in raw form if needed. But, we don't... */
}
if (status) {
errcode);
if (!errcode)
"TGS_REQ (%s) %s: %s: authtime %d, "
"%s%s %s for %s%s%s",
}
if (errcode) {
if (status == 0)
}
if (header_ticket)
if (request)
if (cname)
if (sname)
if (nprincs)
if (session_key.contents)
if (newtransited)
return retval;
}
static krb5_error_code
{
return(retval);
else
return ENOMEM;
return ENOMEM;
}
if (retval)
else
return retval;
}
/*
* The request seems to be for a ticket-granting service somewhere else,
* but we don't have a ticket for the final TGS. Try to give the requestor
* some intermediate realm.
*/
static void
{
*nprincs = 0;
/*
* Call to krb5_princ_component is normally not safe but is so
* here only because find_alternate_tgs() is only called from
* somewhere that has already checked the number of components in
* the principal.
*/
return;
/* move to the end */
ignore it */
*nprincs = 1;
if (retval) {
*nprincs = 0;
return;
}
if (*more) {
continue;
} else if (*nprincs == 1) {
/* Found it! */
char *sname;
continue;
}
0, cname, "<unparseable>", 0);
"TGS_REQ: issuing alternate <un-unparseable> TGT");
} else {
"TGS_REQ: issuing TGT %s", sname);
}
return;
}
continue;
}
*nprincs = 0;
return;
}