home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / kerberosIV / krb / rd_req.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-11  |  11.4 KB  |  336 lines

  1. /*
  2.  * $Source: /usr/src/kerberosIV/src/lib/krb/RCS/rd_req.c,v $
  3.  * $Author: kfall $
  4.  *
  5.  * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
  6.  * of Technology.
  7.  *
  8.  * For copying and distribution information, please see the file
  9.  * <mit-copyright.h>.
  10.  */
  11.  
  12. #ifndef lint
  13. static char *rcsid_rd_req_c =
  14. "$Header: /usr/src/kerberosIV/src/lib/krb/RCS/rd_req.c,v 4.17 90/05/12 00:58:48 kfall Exp $";
  15. #endif /* lint */
  16.  
  17. #include <mit-copyright.h>
  18. #include <des.h>
  19. #include <krb.h>
  20. #include <prot.h>
  21. #include <sys/time.h>
  22. #include <strings.h>
  23.  
  24. extern int krb_ap_req_debug;
  25.  
  26. static struct timeval t_local = { 0, 0 };
  27.  
  28. /*
  29.  * Keep the following information around for subsequent calls
  30.  * to this routine by the same server using the same key.
  31.  */
  32.  
  33. static Key_schedule serv_key;    /* Key sched to decrypt ticket */
  34. static C_Block ky;              /* Initialization vector */
  35. static int st_kvno;        /* version number for this key */
  36. static char st_rlm[REALM_SZ];    /* server's realm */
  37. static char st_nam[ANAME_SZ];    /* service name */
  38. static char st_inst[INST_SZ];    /* server's instance */
  39.  
  40. /*
  41.  * This file contains two functions.  krb_set_key() takes a DES
  42.  * key or password string and returns a DES key (either the original
  43.  * key, or the password converted into a DES key) and a key schedule
  44.  * for it.
  45.  *
  46.  * krb_rd_req() reads an authentication request and returns information
  47.  * about the identity of the requestor, or an indication that the
  48.  * identity information was not authentic.
  49.  */
  50.  
  51. /*
  52.  * krb_set_key() takes as its first argument either a DES key or a
  53.  * password string.  The "cvt" argument indicates how the first
  54.  * argument "key" is to be interpreted: if "cvt" is null, "key" is
  55.  * taken to be a DES key; if "cvt" is non-null, "key" is taken to
  56.  * be a password string, and is converted into a DES key using
  57.  * string_to_key().  In either case, the resulting key is returned
  58.  * in the external static variable "ky".  A key schedule is
  59.  * generated for "ky" and returned in the external static variable
  60.  * "serv_key".
  61.  *
  62.  * This routine returns the return value of des_key_sched.
  63.  *
  64.  * krb_set_key() needs to be in the same .o file as krb_rd_req() so that
  65.  * the key set by krb_set_key() is available in private storage for
  66.  * krb_rd_req().
  67.  */
  68.  
  69. int
  70. krb_set_key(key,cvt)
  71.     char *key;
  72.     int cvt;
  73. {
  74. #ifdef NOENCRYPTION
  75.     bzero(ky, sizeof(ky));
  76.     return KSUCCESS;
  77. #else /* Encrypt */
  78.     if (cvt)
  79.         string_to_key(key,ky);
  80.     else
  81.         bcopy(key,(char *)ky,8);
  82.     return(des_key_sched(ky,serv_key));
  83. #endif /* NOENCRYPTION */
  84. }
  85.  
  86.  
  87. /*
  88.  * krb_rd_req() takes an AUTH_MSG_APPL_REQUEST or
  89.  * AUTH_MSG_APPL_REQUEST_MUTUAL message created by krb_mk_req(),
  90.  * checks its integrity and returns a judgement as to the requestor's
  91.  * identity.
  92.  *
  93.  * The "authent" argument is a pointer to the received message.
  94.  * The "service" and "instance" arguments name the receiving server,
  95.  * and are used to get the service's ticket to decrypt the ticket
  96.  * in the message, and to compare against the server name inside the
  97.  * ticket.  "from_addr" is the network address of the host from which
  98.  * the message was received; this is checked against the network
  99.  * address in the ticket.  If "from_addr" is zero, the check is not
  100.  * performed.  "ad" is an AUTH_DAT structure which is
  101.  * filled in with information about the sender's identity according
  102.  * to the authenticator and ticket sent in the message.  Finally,
  103.  * "fn" contains the name of the file containing the server's key.
  104.  * (If "fn" is NULL, the server's key is assumed to have been set
  105.  * by krb_set_key().  If "fn" is the null string ("") the default
  106.  * file KEYFILE, defined in "krb.h", is used.)
  107.  *
  108.  * krb_rd_req() returns RD_AP_OK if the authentication information
  109.  * was genuine, or one of the following error codes (defined in
  110.  * "krb.h"):
  111.  *
  112.  *    RD_AP_VERSION        - wrong protocol version number
  113.  *    RD_AP_MSG_TYPE        - wrong message type
  114.  *    RD_AP_UNDEC        - couldn't decipher the message
  115.  *    RD_AP_INCON        - inconsistencies found
  116.  *    RD_AP_BADD        - wrong network address
  117.  *    RD_AP_TIME        - client time (in authenticator)
  118.  *                  too far off server time
  119.  *    RD_AP_NYV        - Kerberos time (in ticket) too
  120.  *                  far off server time
  121.  *    RD_AP_EXP        - ticket expired
  122.  *
  123.  * For the message format, see krb_mk_req().
  124.  *
  125.  * Mutual authentication is not implemented.
  126.  */
  127.  
  128. krb_rd_req(authent,service,instance,from_addr,ad,fn)
  129.     register KTEXT authent;    /* The received message */
  130.     char *service;        /* Service name */
  131.     char *instance;        /* Service instance */
  132.     long from_addr;        /* Net address of originating host */
  133.     AUTH_DAT *ad;        /* Structure to be filled in */
  134.     char *fn;            /* Filename to get keys from */
  135. {
  136.     static KTEXT_ST ticket;     /* Temp storage for ticket */
  137.     static KTEXT tkt = &ticket;
  138.     static KTEXT_ST req_id_st;  /* Temp storage for authenticator */
  139.     register KTEXT req_id = &req_id_st;
  140.  
  141.     char realm[REALM_SZ];    /* Realm of issuing kerberos */
  142.     static Key_schedule seskey_sched; /* Key sched for session key */
  143.     unsigned char skey[KKEY_SZ]; /* Session key from ticket */
  144.     char sname[SNAME_SZ];    /* Service name from ticket */
  145.     char iname[INST_SZ];    /* Instance name from ticket */
  146.     char r_aname[ANAME_SZ];    /* Client name from authenticator */
  147.     char r_inst[INST_SZ];    /* Client instance from authenticator */
  148.     char r_realm[REALM_SZ];    /* Client realm from authenticator */
  149.     unsigned int r_time_ms;     /* Fine time from authenticator */
  150.     unsigned long r_time_sec;   /* Coarse time from authenticator */
  151.     register char *ptr;        /* For stepping through */
  152.     unsigned long delta_t;      /* Time in authenticator - local time */
  153.     long tkt_age;        /* Age of ticket */
  154.     static int swap_bytes;    /* Need to swap bytes? */
  155.     static int mutual;        /* Mutual authentication requested? */
  156.     static unsigned char s_kvno;/* Version number of the server's key
  157.                  * Kerberos used to encrypt ticket */
  158.     int status;
  159.  
  160.     if (authent->length <= 0)
  161.     return(RD_AP_MODIFIED);
  162.  
  163.     ptr = (char *) authent->dat;
  164.  
  165.     /* get msg version, type and byte order, and server key version */
  166.  
  167.     /* check version */
  168.     if (KRB_PROT_VERSION != (unsigned int) *ptr++)
  169.         return(RD_AP_VERSION);
  170.  
  171.     /* byte order */
  172.     swap_bytes = 0;
  173.     if ((*ptr & 1) != HOST_BYTE_ORDER)
  174.         swap_bytes++;
  175.  
  176.     /* check msg type */
  177.     mutual = 0;
  178.     switch (*ptr++ & ~1) {
  179.     case AUTH_MSG_APPL_REQUEST:
  180.         break;
  181.     case AUTH_MSG_APPL_REQUEST_MUTUAL:
  182.         mutual++;
  183.         break;
  184.     default:
  185.         return(RD_AP_MSG_TYPE);
  186.     }
  187.  
  188. #ifdef lint
  189.     /* XXX mutual is set but not used; why??? */
  190.     /* this is a crock to get lint to shut up */
  191.     if (mutual)
  192.         mutual = 0;
  193. #endif /* lint */
  194.     s_kvno = *ptr++;        /* get server key version */
  195.     (void) strcpy(realm,ptr);   /* And the realm of the issuing KDC */
  196.     ptr += strlen(ptr) + 1;     /* skip the realm "hint" */
  197.  
  198.     /*
  199.      * If "fn" is NULL, key info should already be set; don't
  200.      * bother with ticket file.  Otherwise, check to see if we
  201.      * already have key info for the given server and key version
  202.      * (saved in the static st_* variables).  If not, go get it
  203.      * from the ticket file.  If "fn" is the null string, use the
  204.      * default ticket file.
  205.      */
  206.     if (fn && (strcmp(st_nam,service) || strcmp(st_inst,instance) ||
  207.                strcmp(st_rlm,realm) || (st_kvno != s_kvno))) {
  208.         if (*fn == 0) fn = KEYFILE;
  209.         st_kvno = s_kvno;
  210. #ifndef NOENCRYPTION
  211.         if (read_service_key(service,instance,realm,(int) s_kvno,
  212.                             fn,(char *)skey))
  213.             return(RD_AP_UNDEC);
  214.         if (status = krb_set_key((char *)skey,0))
  215.         return(status);
  216. #endif /* !NOENCRYPTION */
  217.         (void) strcpy(st_rlm,realm);
  218.         (void) strcpy(st_nam,service);
  219.         (void) strcpy(st_inst,instance);
  220.     }
  221.  
  222.     /* Get ticket from authenticator */
  223.     tkt->length = (int) *ptr++;
  224.     if ((tkt->length + (ptr+1 - (char *) authent->dat)) > authent->length)
  225.     return(RD_AP_MODIFIED);
  226.     bcopy(ptr+1,(char *)(tkt->dat),tkt->length);
  227.  
  228.     if (krb_ap_req_debug)
  229.         log("ticket->length: %d",tkt->length);
  230.  
  231. #ifndef NOENCRYPTION
  232.     /* Decrypt and take apart ticket */
  233. #endif
  234.  
  235.     if (decomp_ticket(tkt,&ad->k_flags,ad->pname,ad->pinst,ad->prealm,
  236.                       &(ad->address),ad->session, &(ad->life),
  237.                       &(ad->time_sec),sname,iname,ky,serv_key))
  238.         return(RD_AP_UNDEC);
  239.  
  240.     if (krb_ap_req_debug) {
  241.         log("Ticket Contents.");
  242.         log(" Aname:   %s.%s",ad->pname,
  243.             ((int)*(ad->prealm) ? ad->prealm : "Athena"));
  244.         log(" Service: %s%s%s",sname,((int)*iname ? "." : ""),iname);
  245.     }
  246.  
  247.     /* Extract the authenticator */
  248.     req_id->length = (int) *(ptr++);
  249.     if ((req_id->length + (ptr + tkt->length - (char *) authent->dat)) >
  250.     authent->length)
  251.     return(RD_AP_MODIFIED);
  252.     bcopy(ptr + tkt->length, (char *)(req_id->dat),req_id->length);
  253.  
  254. #ifndef NOENCRYPTION
  255.     /* And decrypt it with the session key from the ticket */
  256.     if (krb_ap_req_debug) log("About to decrypt authenticator");
  257.     key_sched(ad->session,seskey_sched);
  258.     pcbc_encrypt((C_Block *)req_id->dat,(C_Block *)req_id->dat,
  259.                  (long) req_id->length, seskey_sched,ad->session,DES_DECRYPT);
  260.     if (krb_ap_req_debug) log("Done.");
  261. #endif /* NOENCRYPTION */
  262.  
  263. #define check_ptr() if ((ptr - (char *) req_id->dat) > req_id->length) return(RD_AP_MODIFIED);
  264.  
  265.     ptr = (char *) req_id->dat;
  266.     (void) strcpy(r_aname,ptr);    /* Authentication name */
  267.     ptr += strlen(r_aname)+1;
  268.     check_ptr();
  269.     (void) strcpy(r_inst,ptr);    /* Authentication instance */
  270.     ptr += strlen(r_inst)+1;
  271.     check_ptr();
  272.     (void) strcpy(r_realm,ptr);    /* Authentication name */
  273.     ptr += strlen(r_realm)+1;
  274.     check_ptr();
  275.     bcopy(ptr,(char *)&ad->checksum,4);    /* Checksum */
  276.     ptr += 4;
  277.     check_ptr();
  278.     if (swap_bytes) swap_u_long(ad->checksum);
  279.     r_time_ms = *(ptr++);    /* Time (fine) */
  280. #ifdef lint
  281.     /* XXX r_time_ms is set but not used.  why??? */
  282.     /* this is a crock to get lint to shut up */
  283.     if (r_time_ms)
  284.         r_time_ms = 0;
  285. #endif /* lint */
  286.     check_ptr();
  287.     /* assume sizeof(r_time_sec) == 4 ?? */
  288.     bcopy(ptr,(char *)&r_time_sec,4); /* Time (coarse) */
  289.     if (swap_bytes) swap_u_long(r_time_sec);
  290.  
  291.     /* Check for authenticity of the request */
  292.     if (krb_ap_req_debug)
  293.         log("Pname:   %s %s",ad->pname,r_aname);
  294.     if (strcmp(ad->pname,r_aname) != 0)
  295.         return(RD_AP_INCON);
  296.     if (strcmp(ad->pinst,r_inst) != 0)
  297.         return(RD_AP_INCON);
  298.     if (krb_ap_req_debug)
  299.         log("Realm:   %s %s",ad->prealm,r_realm);
  300.     if ((strcmp(ad->prealm,r_realm) != 0))
  301.         return(RD_AP_INCON);
  302.  
  303.     if (krb_ap_req_debug)
  304.         log("Address: %d %d",ad->address,from_addr);
  305.     if (from_addr && (ad->address != from_addr))
  306.         return(RD_AP_BADD);
  307.  
  308.     (void) gettimeofday(&t_local,(struct timezone *) 0);
  309.     delta_t = abs((int)(t_local.tv_sec - r_time_sec));
  310.     if (delta_t > CLOCK_SKEW) {
  311.         if (krb_ap_req_debug)
  312.             log("Time out of range: %d - %d = %d",
  313.                 t_local.tv_sec,r_time_sec,delta_t);
  314.         return(RD_AP_TIME);
  315.     }
  316.  
  317.     /* Now check for expiration of ticket */
  318.  
  319.     tkt_age = t_local.tv_sec - ad->time_sec;
  320.     if (krb_ap_req_debug)
  321.         log("Time: %d Issue Date: %d Diff: %d Life %x",
  322.             t_local.tv_sec,ad->time_sec,tkt_age,ad->life);
  323.  
  324.     if (t_local.tv_sec < ad->time_sec) {
  325.         if ((ad->time_sec - t_local.tv_sec) > CLOCK_SKEW)
  326.             return(RD_AP_NYV);
  327.     }
  328.     else if ((t_local.tv_sec - ad->time_sec) > 5 * 60 * ad->life)
  329.         return(RD_AP_EXP);
  330.  
  331.     /* All seems OK */
  332.     ad->reply.length = 0;
  333.  
  334.     return(RD_AP_OK);
  335. }
  336.