krb5_last_req_entry *nolrarray[2], nolrentry;
/* krb5_address *noaddrarray[1]; */
krb5_enctype useetype;
- int errcode;
+ int errcode, errcode2;
register int i;
int firstpass = 1;
char *status = 0;
if (!fromstring)
fromstring = "<unknown>";
+ if (errcode = krb5_unparse_name(request->server, &sname)) {
+ status = "UNPARSING SERVER";
+ goto cleanup;
+ }
+
errcode = kdc_process_tgs_req(request, from, pkt, &req_authdat);
if (req_authdat)
header_ticket = req_authdat->ticket;
- if (errcode)
+
+ if (header_ticket && header_ticket->enc_part2 &&
+ (errcode2 = krb5_unparse_name(header_ticket->enc_part2->client,
+ &cname))) {
+ status = "UNPARSING CLIENT";
+ errcode = errcode2;
+ 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
* decrypted with the session key.
*/
- if (errcode = krb5_unparse_name(header_ticket->enc_part2->client, &cname))
- goto cleanup;
-
- if (errcode = krb5_unparse_name(request->server, &sname))
- goto cleanup;
-
authtime = header_ticket->enc_part2->times.authtime;
/* XXX make sure server here has the proper realm...taken from AP_REQ
cleanup:
if (status)
- syslog(LOG_INFO, "TGS_REQ%c %s: authtime %d, host %s, %s for %s",
- secondary_ch, status, authtime, fromstring, cname, sname);
+ syslog(LOG_INFO, "TGS_REQ%c %s: authtime %d, host %s, %s for %s%s%s",
+ secondary_ch, status, authtime, fromstring,
+ cname ? cname : "<unknown client>",
+ sname ? sname : "<unknown server>",
+ errcode ? ", " : "",
+ errcode ? error_message(errcode) : "");
if (errcode) {
errcode -= ERROR_TABLE_BASE_krb5;
if (errcode < 0 || errcode > 128)
retval = prepare_error_tgs(request, header_ticket, errcode,
fromstring, response);
}
+
if (request)
krb5_free_kdc_req(request);
if (req_authdat)
krb5_free_keyblock(session_key);
if (newtransited)
free(enc_tkt_reply.transited.tr_contents.data);
-
+
return retval;
}
}
errpkt.error = error;
errpkt.server = request->server;
- errpkt.client = ticket ? ticket->enc_part2->client : 0; /* may not know
- the name */
+ if (ticket && ticket->enc_part2)
+ errpkt.client = ticket->enc_part2->client;
+ else
+ errpkt.client = 0;
errpkt.text.length = strlen(error_message(error+KRB5KDC_ERR_NONE))+1;
if (!(errpkt.text.data = malloc(errpkt.text.length))) {
if (ticket)
OLDDECLARG(krb5_keyblock **, key)
{
register struct kparg *whoisit = (struct kparg *)keyprocarg;
-
- if (vno != whoisit->kvno)
+ char *sname;
+
+ if (vno != whoisit->kvno) {
+ if (!krb5_unparse_name(principal, &sname)) {
+ syslog(LOG_ERR,
+ "TGS_REQ: BAD KEY VNO: server='%s', expecting %d, got %d",
+ sname, vno, whoisit->kvno);
+ free(sname);
+ }
return KRB5KRB_AP_ERR_BADKEYVER;
+ }
return(krb5_copy_keyblock(whoisit->key, key));
}
+/*
+ * Returns TRUE if the kerberos principal is the name of a Kerberos ticket
+ * service.
+ */
+krb5_boolean krb5_is_tgs_principal(principal)
+ krb5_principal principal;
+{
+ if ((krb5_princ_component(principal, 0)->length ==
+ KRB5_TGS_NAME_SIZE) &&
+ (!memcmp(krb5_princ_component(principal, 0)->data,
+ KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE)))
+ return TRUE;
+ return FALSE;
+}
/*
* given authentication data (provides seed for checksum), calculate checksum
krb5_checksum our_cksum;
krb5_data *scratch = 0, scratch1, scratch2;
krb5_pa_data **tmppa;
- krb5_boolean local_client = TRUE;
+ krb5_boolean foreign_server = FALSE;
krb5_enc_tkt_part *ticket_enc;
our_cksum.contents = 0;
if (retval = decode_krb5_ap_req(&scratch2, &apreq))
return retval;
-
+
if (!(authdat = (krb5_tkt_authent *)malloc(sizeof(*authdat)))) {
retval = ENOMEM;
goto cleanup;
if (isflagset(apreq->ap_options, AP_OPTS_USE_SESSION_KEY) ||
isflagset(apreq->ap_options, AP_OPTS_MUTUAL_REQUIRED)) {
+ syslog(LOG_INFO, "TGS_REQ: SESSION KEY or MUTUAL");
retval = KRB5KDC_ERR_POLICY;
apreq->ticket = 0; /* Caller will free the ticket */
goto cleanup;
memcmp(krb5_princ_realm(apreq->ticket->server)->data,
krb5_princ_realm(tgs_server)->data,
krb5_princ_realm(tgs_server)->length))
- local_client = FALSE;
+ foreign_server = TRUE;
+ {
+ char *tmp, *tmp1;
+
+ krb5_unparse_name(apreq->ticket->server, &tmp);
+ krb5_unparse_name(tgs_server, &tmp1);
+ syslog(LOG_INFO, "server: %s, tgs_server: %s", tmp, tmp1);
+ }
retval = krb5_rd_req_decoded(apreq, apreq->ticket->server,
from->address,
/* now rearrange output from rd_req_decoded */
/* make sure the client is of proper lineage (see above) */
- if (!local_client) {
+ if (foreign_server) {
krb5_data *tkt_realm = krb5_princ_realm(ticket_enc->client);
krb5_data *tgs_realm = krb5_princ_realm(tgs_server);
- if (tkt_realm->length != tgs_realm->length ||
- memcmp(tkt_realm->data, tgs_realm->data, tgs_realm->length)) {
+ if (tkt_realm->length == tgs_realm->length ||
+ !memcmp(tkt_realm->data, tgs_realm->data, tgs_realm->length)) {
/* someone in a foreign realm claiming to be local */
+ syslog(LOG_INFO, "PROCESS_TGS: failed lineage check");
retval = KRB5KDC_ERR_POLICY;
goto cleanup;
}
}
+ if (!authdat->authenticator->checksum) {
+ retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
+ goto cleanup;
+ }
our_cksum.checksum_type = authdat->authenticator->checksum->checksum_type;
if (!valid_cksumtype(our_cksum.checksum_type)) {
retval = KRB5KDC_ERR_SUMTYPE_NOSUPP;
krb5_db_free_principal(&server, nprincs);
if (!krb5_unparse_name(ticket->server, &sname)) {
- syslog(LOG_ERR, "TGS_REQ: can't find key for '%s'",
+ syslog(LOG_ERR, "TGS_REQ: UNKNOWN SERVER: server='%s'",
sname);
free(sname);
}
int lastlevel = 1000; /* last level seen */
int length; /* various lengths */
int tag; /* tag number */
+ unsigned char savelen; /* saved length of our field */
/* we assume that the first identifier/length will tell us
how long the entire stream is. */
if (tag == field) {
/* return length and data */
astream++;
+ savelen = *astream;
if ((data->length = asn1length(&astream)) < 0) {
return(-1);
}
+ /* if the field length is indefinite, we will have to subtract two
+ (terminating octets) from the length returned since we don't want
+ to pass any info from the "wrapper" back. asn1length will always return
+ the *total* length of the field, not just what's contained in it */
+ if ((savelen & 0xff) == 0x80) {
+ data->length -=2 ;
+ }
data->data = (char *)astream;
return(0);
} else if (tag <= classes) {
}
}
return(-1);
-}
+}
/*
* Routines that validate a TGS request; checks a lot of things. :-)
/*
* Verify that the server principal in authdat->ticket is correct
- * (either the ticket granting service or the service we're
- * looking for)
+ * (either the ticket granting service or the service that was
+ * originally requested)
*/
- if (krb5_principal_compare(ticket->server, tgs_server)) {
- /* Server must allow TGS based issuances */
- if (isflagset(server.attributes, KRB5_KDB_DISALLOW_TGT_BASED)) {
- *status = "TGT BASED NOT ALLOWED";
- return(KDC_ERR_POLICY);
- }
- } else {
- if (!krb5_principal_compare(ticket->server,
- request->server)) {
- *status = "BAD SERVER IN TKT";
- return KRB5KRB_AP_ERR_NOT_US;
- }
+ if (!krb5_principal_compare(ticket->server, request->server)) {
+ /*
+ * OK, we need to validate the krbtgt service in the ticket.
+ *
+ * The krbtgt service is of the form:
+ * krbtgt/realm-A@realm-B
+ *
+ * Realm A is the "server realm"; the realm of the
+ * server of the requested ticket must match this realm.
+ * Of course, it should be a realm serviced by this KDC.
+ *
+ * Realm B is the "client realm"; this is what should be
+ * added to the transited field. (which is done elsewhere)
+ */
+ char *destination_realm;
+
+ /* Make sure there are two components... */
+ if (krb5_princ_size(ticket->server) != 2) {
+ *status = "BAD TGS SERVER LENGTH";
+ return KRB_AP_ERR_NOT_US;
+ }
+ /* ...that the first component is krbtgt... */
+ if (!krb5_is_tgs_principal(ticket->server)) {
+ *status = "BAD TGS SERVER NAME";
+ return KRB_AP_ERR_NOT_US;
+ }
+ /* ...and that the second component matches the server realm... */
+ if ((krb5_princ_component(ticket->server, 1)->length !=
+ krb5_princ_realm(request->server)->length) ||
+ memcmp(krb5_princ_component(ticket->server, 1)->data,
+ krb5_princ_realm(request->server)->data,
+ krb5_princ_realm(request->server)->length)) {
+ *status = "BAD TGS SERVER INSTANCE";
+ return KRB_AP_ERR_NOT_US;
+ }
+ /* XXX add check that second component must match locally
+ * supported realm?
+ */
+
+ /* Server must allow TGS based issuances */
+ if (isflagset(server.attributes, KRB5_KDB_DISALLOW_TGT_BASED)) {
+ *status = "TGT BASED NOT ALLOWED";
+ return(KDC_ERR_POLICY);
+ }
}
-
+
/* TGS must be forwardable to get forwarded or forwardable ticket */
if ((isflagset(request->kdc_options, KDC_OPT_FORWARDED) ||
isflagset(request->kdc_options, KDC_OPT_FORWARDABLE)) &&