This commit was manufactured by cvs2svn to create tag 'V1_0_6_BETA2'
[krb5.git] / src / krb524 / cnv_tkt_skey.c
index 4e5ce9b149da3e2b1afd5175c8d3d7bf1ace4886..19bb386f33b5a1f3291ede7a3db18b5aec8e8542 100644 (file)
@@ -20,7 +20,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "krb5.h"
+#include "k5-int.h"            /* we need krb5_context::clockskew */
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include <krb4-proto.h>
 #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, skey)
+int krb524_convert_tkt_skey(context, v5tkt, v4tkt, v5_skey, v4_skey)
      krb5_context context;
      krb5_ticket *v5tkt;
      KTEXT_ST *v4tkt;
-     krb5_keyblock *skey;
+     krb5_keyblock *v5_skey, *v4_skey;
 {
      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;
+     int ret, lifetime, deltatime;
+     krb5_timestamp server_time;
 
      v5tkt->enc_part2 = NULL;
-     if ((ret = krb5_decrypt_tkt_part(context, skey, v5tkt))) {
+     if ((ret = krb5_decrypt_tkt_part(context, v5_skey, v5tkt))) {
          krb5_free_ticket(context, v5tkt);
          return ret;
      }
@@ -60,11 +83,11 @@ int krb524_convert_tkt_skey(context, v5tkt, v4tkt, skey)
          return ret;
      }
      
-     if (v5etkt->session->keytype != KEYTYPE_DES ||
+     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->keytype,
+                      v5etkt->session->enctype,
                       v5etkt->session->length,
                       sizeof(C_Block));
          krb5_free_enc_tkt_part(context, v5etkt);
@@ -76,8 +99,39 @@ int krb524_convert_tkt_skey(context, v5tkt, v4tkt, skey)
      /* V4 lifetime is 1 byte, in 5 minute increments */
      if (v5etkt->times.starttime == 0)
          v5etkt->times.starttime = v5etkt->times.authtime;
-     lifetime = 0xff &
-         ((v5etkt->times.endtime - v5etkt->times.authtime) / 300);
+     /* 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;
+     }
 
      /* XXX perhaps we should use the addr of the client host if */
      /* v5creds contains more than one addr.  Q: Does V4 support */
@@ -104,13 +158,13 @@ int krb524_convert_tkt_skey(context, v5tkt, v4tkt, skey)
                             pinst,
                             prealm,
                             *((unsigned long *)v5etkt->caddrs[0]->contents),
-                            v5etkt->session->contents,
+                            (char *) v5etkt->session->contents,
                             lifetime,
                             /* issue_data */
-                            v5etkt->times.starttime,
+                            server_time,
                             sname,
                             sinst,
-                            skey->contents);
+                            v4_skey->contents);
 
      krb5_free_enc_tkt_part(context, v5etkt);
      v5tkt->enc_part2 = NULL;