/* * Copyright 1994 by OpenVision Technologies, Inc. * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appears in all copies and * that both that copyright notice and this permission notice appear in * supporting documentation, and that the name of OpenVision not be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. OpenVision makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "k5-int.h" /* we need krb5_context::clockskew */ #include #include #include #include #include #include "krb524.h" /* rather than copying the cmu code, these values are derived from a calculation based on the table and comments found there. the expression (in elisp) is: (defun cmu-to-secs2 (j) (if (< j 128) (* j 5 60) (round (* 38400 (expt 1.06914489 (- j 128)))))) and is low by one for 16 values but is exact for the others. */ static long cmu_seconds[] = { 38400, 41055, 43894, 46929, 50174, 53643, 57352, 61318, 65558, 70091, 74937, 80119, 85658, 91581, 97914, 104684, 111922, 119661, 127935, 136781, 146239, 156350, 167161, 178720, 191077, 204289, 218415, 233517, 249663, 266926, 285383, 305116, 326213, 348769, 372885, 398668, 426233, 455705, 487215, 520903, 556921, 595430, 636600, 680618, 727679, 777995, 831789, 889303, 950794, 1016536, 1086825, 1161973, 1242317, 1328217, 1420057, 1518246, 1623225, 1735463, 1855462, 1983757, 2120924, 2267575, 2424366, 2591999, 0 }; /* * Convert a v5 ticket for server to a v4 ticket, using service key * skey for both. */ int krb524_convert_tkt_skey(context, v5tkt, v4tkt, v5_skey, v4_skey, saddr) krb5_context context; krb5_ticket *v5tkt; KTEXT_ST *v4tkt; krb5_keyblock *v5_skey, *v4_skey; struct sockaddr_in *saddr; { char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; char sname[ANAME_SZ], sinst[INST_SZ]; krb5_enc_tkt_part *v5etkt; int ret, lifetime, deltatime; krb5_timestamp server_time; struct sockaddr_in *sinp = (struct sockaddr_in *)saddr; krb5_address kaddr; v5tkt->enc_part2 = NULL; if ((ret = krb5_decrypt_tkt_part(context, v5_skey, v5tkt))) { krb5_free_ticket(context, v5tkt); return ret; } v5etkt = v5tkt->enc_part2; if ((ret = krb524_convert_princs(context, v5etkt->client, v5tkt->server, pname, pinst, prealm, sname, sinst))) { krb5_free_enc_tkt_part(context, v5etkt); v5tkt->enc_part2 = NULL; return ret; } if (v5etkt->session->enctype != ENCTYPE_DES_CBC_CRC || v5etkt->session->length != sizeof(C_Block)) { if (krb524_debug) fprintf(stderr, "v5 session keyblock type %d length %d != C_Block size %d\n", v5etkt->session->enctype, v5etkt->session->length, sizeof(C_Block)); krb5_free_enc_tkt_part(context, v5etkt); v5tkt->enc_part2 = NULL; return KRB524_BADKEY; } /* V4 has no concept of authtime or renew_till, so ignore them */ /* V4 lifetime is 1 byte, in 5 minute increments */ if (v5etkt->times.starttime == 0) v5etkt->times.starttime = v5etkt->times.authtime; /* rather than apply fit an extended v5 lifetime into a v4 range, give out a v4 ticket with as much of the v5 lifetime is available "now" instead. */ if ((ret = krb5_timeofday(context, &server_time))) { if (krb524_debug) fprintf(stderr, "krb5_timeofday failed!\n"); krb5_free_enc_tkt_part(context, v5etkt); v5tkt->enc_part2 = NULL; return ret; } if ( (server_time+context->clockskew >= v5etkt->times.starttime) && (server_time-context->clockskew <= v5etkt->times.endtime)) { deltatime = v5etkt->times.endtime - (server_time-context->clockskew); lifetime = deltatime / 300; /* if (lifetime > 255) lifetime = 255; */ if (lifetime > 127) { /* use the CMU algorithm instead: */ long *clist = cmu_seconds; while(*clist && *clist < deltatime) clist++; lifetime = 128 + (clist - cmu_seconds); } } else { if (krb524_debug) fprintf(stderr, "v5 ticket time out of bounds\n"); krb5_free_enc_tkt_part(context, v5etkt); v5tkt->enc_part2 = NULL; if (server_time+context->clockskew < v5etkt->times.starttime) return KRB5KRB_AP_ERR_TKT_NYV; else if (server_time-context->clockskew > v5etkt->times.endtime) return KRB5KRB_AP_ERR_TKT_EXPIRED; else /* shouldn't happen, but just in case... */ return KRB5KRB_AP_ERR_TKT_NYV; } kaddr.addrtype = ADDRTYPE_INET; kaddr.length = sizeof(sinp->sin_addr); kaddr.contents = (krb5_octet *)&sinp->sin_addr; if (!krb5_address_search(context, &kaddr, v5etkt->caddrs)) { if (krb524_debug) fprintf(stderr, "Invalid v5creds address information.\n"); krb5_free_enc_tkt_part(context, v5etkt); v5tkt->enc_part2 = NULL; return KRB524_BADADDR; } if (krb524_debug) printf("startime = %ld, authtime = %ld, lifetime = %ld\n", (long) v5etkt->times.starttime, (long) v5etkt->times.authtime, (long) lifetime); /* XXX are there V5 flags we should map to V4 equivalents? */ if (v4_skey->enctype == ENCTYPE_DES_CBC_CRC) { ret = krb_create_ticket(v4tkt, 0, /* flags */ pname, pinst, prealm, *((unsigned long *)kaddr.contents), (char *) v5etkt->session->contents, lifetime, /* issue_data */ server_time, sname, sinst, v4_skey->contents); } else { /* Force enctype to be raw if using DES3. */ if (v4_skey->enctype == ENCTYPE_DES3_CBC_SHA1 || v4_skey->enctype == ENCTYPE_LOCAL_DES3_HMAC_SHA1) v4_skey->enctype = ENCTYPE_DES3_CBC_RAW; ret = krb_cr_tkt_krb5(v4tkt, 0, /* flags */ pname, pinst, prealm, *((unsigned long *)kaddr.contents), (char *) v5etkt->session->contents, lifetime, /* issue_data */ server_time, sname, sinst, v4_skey); } krb5_free_enc_tkt_part(context, v5etkt); v5tkt->enc_part2 = NULL; if (ret == KSUCCESS) return 0; else return KRB524_V4ERR; }