/* note that reading the application request requires first determining the server for which a ticket was issued, and choosing the correct key for decryption. The name of the server appears in the plaintext part of the ticket. */ if (no KRB_AP_REQ in req.padata) then error_out(KDC_ERR_PADATA_TYPE_NOSUPP); endif verify KRB_AP_REQ in req.padata; /* Note that the realm in which the Kerberos server is operating is determined by the instance from the ticket-granting ticket. The realm in the ticket-granting ticket is the realm under which the ticket granting ticket was issued. It is possible for a single Kerberos server to support more than one realm. */ auth_hdr := KRB_AP_REQ; tgt := auth_hdr.ticket; if (tgt.sname is not a TGT for local realm and is not req.sname) then error_out(KRB_AP_ERR_NOT_US); realm := realm_tgt_is_for(tgt); decode remainder of request; if (auth_hdr.authenticator.cksum is missing) then error_out(KRB_AP_ERR_INAPP_CKSUM); endif if (auth_hdr.authenticator.cksum type is not supported) then error_out(KDC_ERR_SUMTYPE_NOSUPP); endif if (auth_hdr.authenticator.cksum is not both collision-proof and keyed) then error_out(KRB_AP_ERR_INAPP_CKSUM); endif set computed_checksum := checksum(req); if (computed_checksum != auth_hdr.authenticatory.cksum) then error_out(KRB_AP_ERR_MODIFIED); endif server := lookup(req.sname,realm); if (!server) then if (is_foreign_tgt_name(server)) then server := best_intermediate_tgs(server); else /* no server in Database */ error_out(KDC_ERR_S_PRINCIPAL_UNKNOWN); endif endif session := generate_random_session_key(); use_etype := first supported etype in req.etypes; if (no support for req.etypes) then error_out(KDC_ERR_ETYPE_NOSUPP); endif new_tkt.vno := ticket version; /* = 5 */ new_tkt.sname := req.sname; new_tkt.srealm := realm; reset all flags in new_tkt.flags; /* 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 */ new_tkt.caddr := tgt.caddr; resp.caddr := NULL; /* We only include this if they change */ if (req.kdc-options.FORWARDABLE is set) then if (tgt.flags.FORWARDABLE is reset) then error_out(KDC_ERR_BADOPTION); endif set new_tkt.flags.FORWARDABLE; endif if (req.kdc-options.FORWARDED is set) then if (tgt.flags.FORWARDABLE is reset) then error_out(KDC_ERR_BADOPTION); endif set new_tkt.flags.FORWARDED; new_tkt.caddr := req.addresses; resp.caddr := req.addresses; endif if (tgt.flags.FORWARDED is set) then set new_tkt.flags.FORWARDED; endif if (req.kdc-options.PROXIABLE is set) then if (tgt.flags.PROXIABLE is reset) error_out(KDC_ERR_BADOPTION); endif set new_tkt.flags.PROXIABLE; endif if (req.kdc-options.PROXY is set) then if (tgt.flags.PROXIABLE is reset) then error_out(KDC_ERR_BADOPTION); endif set new_tkt.flags.PROXY; new_tkt.caddr := req.addresses; resp.caddr := req.addresses; endif if (req.kdc-options.POSTDATE is set) then if (tgt.flags.POSTDATE is reset) error_out(KDC_ERR_BADOPTION); endif set new_tkt.flags.POSTDATE; endif if (req.kdc-options.POSTDATED is set) then if (tgt.flags.POSTDATE is reset) then error_out(KDC_ERR_BADOPTION); endif set new_tkt.flags.POSTDATED; set new_tkt.flags.INVALID; if (against_postdate_policy(req.from)) then error_out(KDC_ERR_POLICY); endif new_tkt.starttime := req.from; endif if (req.kdc-options.VALIDATE is set) then if (tgt.flags.INVALID is reset) then error_out(KDC_ERR_POLICY); endif if (tgt.starttime > kdc_time) then error_out(KRB_AP_ERR_NYV); endif if (check_hot_list(tgt)) then error_out(KRB_AP_ERR_REPEAT); endif tkt := tgt; reset new_tkt.flags.INVALID; endif if (req.kdc-options.(any flag except ENC-TKT-IN-SKEY, RENEW, and those already processed) is set) then error_out(KDC_ERR_BADOPTION); endif new_tkt.authtime := tgt.authtime; if (req.kdc-options.RENEW is set) then /* Note that if the endtime has already passed, the ticket */ /* would have been rejected in the initial authentication */ /* stage, so there is no need to check again here */ if (tgt.flags.RENEWABLE is reset) then error_out(KDC_ERR_BADOPTION); endif if (tgt.renew-till >= kdc_time) then error_out(KRB_AP_ERR_TKT_EXPIRED); endif tkt := tgt; new_tkt.starttime := kdc_time; old_life := tgt.endttime - tgt.starttime; new_tkt.endtime := min(tgt.renew-till, new_tkt.starttime + old_life); else new_tkt.starttime := kdc_time; if (req.till = 0) then till := infinity; else till := req.till; endif new_tkt.endtime := min(till, new_tkt.starttime+client.max_life, new_tkt.starttime+server.max_life, new_tkt.starttime+max_life_for_realm, tgt.endtime); if ((req.kdc-options.RENEWABLE-OK is set) and (new_tkt.endtime < req.till) and (tgt.flags.RENEWABLE is set) then /* we set the RENEWABLE option for later */ /* processing */ set req.kdc-options.RENEWABLE; req.rtime := min(req.till, tgt.renew-till); endif endif if (req.rtime = 0) then rtime := infinity; else rtime := req.rtime; endif if ((req.kdc-options.RENEWABLE is set) and (tgt.flags.RENEWABLE is set)) then set new_tkt.flags.RENEWABLE; new_tkt.renew-till := min(rtime, new_tkt.starttime+client.max_rlife, new_tkt.starttime+server.max_rlife, new_tkt.starttime+max_rlife_for_realm, tgt.renew-till); else new_tkt.renew-till := OMIT; /* leave the renew-till field out */ endif if (req.enc-authorization-data is present) then decrypt req.enc-authorization-data into decrypted_authorization_data using auth_hdr.authenticator.subkey; if (decrypt_error()) then error_out(KRB_AP_ERR_BAD_INTEGRITY); endif endif new_tkt.authorization_data := req.auth_hdr.ticket.authorization_data + decrypted_authorization_data; new_tkt.key := session; new_tkt.crealm := tgt.crealm; new_tkt.cname := req.auth_hdr.ticket.cname; if (realm_tgt_is_for(tgt) := tgt.realm) then /* tgt issued by local realm */ new_tkt.transited := tgt.transited; else /* was issued for this realm by some other realm */ if (tgt.transited.tr-type not supported) then error_out(KDC_ERR_TRTYPE_NOSUPP); endif new_tkt.transited := compress_transited(tgt.transited + tgt.realm) endif encode encrypted part of new_tkt into OCTET STRING; if (req.kdc-options.ENC-TKT-IN-SKEY is set) then if (server not specified) then server = req.second_ticket.client; endif if ((req.second_ticket is not a TGT) or (req.second_ticket.client != server)) then error_out(KDC_ERR_POLICY); endif new_tkt.enc-part := encrypt OCTET STRING using using etype_for_key(second-ticket.key), second-ticket.key; else new_tkt.enc-part := encrypt OCTET STRING using etype_for_key(server.key), server.key, server.p_kvno; endif resp.pvno := 5; resp.msg-type := KRB_TGS_REP; resp.crealm := tgt.crealm; resp.cname := tgt.cname; resp.ticket := new_tkt; resp.key := session; resp.nonce := req.nonce; resp.last-req := fetch_last_request_info(client); resp.flags := new_tkt.flags; resp.authtime := new_tkt.authtime; resp.starttime := new_tkt.starttime; resp.endtime := new_tkt.endtime; omit resp.key-expiration; resp.sname := new_tkt.sname; resp.realm := new_tkt.realm; if (new_tkt.flags.RENEWABLE) then resp.renew-till := new_tkt.renew-till; endif encode body of reply into OCTET STRING; if (req.padata.authenticator.subkey) resp.enc-part := encrypt OCTET STRING using use_etype, req.padata.authenticator.subkey; else resp.enc-part := encrypt OCTET STRING using use_etype, tgt.key; send(resp);