home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / libtelnet / kerberos5.c,v < prev    next >
Encoding:
Text File  |  1994-05-23  |  15.1 KB  |  606 lines

  1. head    1.1;
  2. access;
  3. symbols;
  4. locks
  5.     rzsfl:1.1; strict;
  6. comment    @ * @;
  7.  
  8.  
  9. 1.1
  10. date    94.05.23.09.04.51;    author rzsfl;    state Exp;
  11. branches;
  12. next    ;
  13.  
  14.  
  15. desc
  16. @Original
  17. @
  18.  
  19.  
  20. 1.1
  21. log
  22. @Initial revision
  23. @
  24. text
  25. @/*-
  26.  * Copyright (c) 1991 The Regents of the University of California.
  27.  * All rights reserved.
  28.  *
  29.  * Redistribution and use in source and binary forms, with or without
  30.  * modification, are permitted provided that the following conditions
  31.  * are met:
  32.  * 1. Redistributions of source code must retain the above copyright
  33.  *    notice, this list of conditions and the following disclaimer.
  34.  * 2. Redistributions in binary form must reproduce the above copyright
  35.  *    notice, this list of conditions and the following disclaimer in the
  36.  *    documentation and/or other materials provided with the distribution.
  37.  * 3. All advertising materials mentioning features or use of this software
  38.  *    must display the following acknowledgement:
  39.  *    This product includes software developed by the University of
  40.  *    California, Berkeley and its contributors.
  41.  * 4. Neither the name of the University nor the names of its contributors
  42.  *    may be used to endorse or promote products derived from this software
  43.  *    without specific prior written permission.
  44.  *
  45.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  46.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  47.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  48.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  49.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  50.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  51.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  52.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  53.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  54.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  55.  * SUCH DAMAGE.
  56.  */
  57.  
  58. #ifndef lint
  59. /*static char sccsid[] = "from: @@(#)kerberos5.c    5.2 (Berkeley) 3/22/91";*/
  60. static char rcsid[] = "$Id: kerberos5.c,v 1.2 1993/08/01 18:32:34 mycroft Exp $";
  61. #endif /* not lint */
  62.  
  63. /*
  64.  * Copyright (C) 1990 by the Massachusetts Institute of Technology
  65.  *
  66.  * Export of this software from the United States of America is assumed
  67.  * to require a specific license from the United States Government.
  68.  * It is the responsibility of any person or organization contemplating
  69.  * export to obtain such a license before exporting.
  70.  *
  71.  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  72.  * distribute this software and its documentation for any purpose and
  73.  * without fee is hereby granted, provided that the above copyright
  74.  * notice appear in all copies and that both that copyright notice and
  75.  * this permission notice appear in supporting documentation, and that
  76.  * the name of M.I.T. not be used in advertising or publicity pertaining
  77.  * to distribution of the software without specific, written prior
  78.  * permission.  M.I.T. makes no representations about the suitability of
  79.  * this software for any purpose.  It is provided "as is" without express
  80.  * or implied warranty.
  81.  */
  82.  
  83.  
  84. #ifdef    KRB5
  85. #include <arpa/telnet.h>
  86. #include <stdio.h>
  87. #include <krb5/krb5.h>
  88. #include <krb5/crc-32.h>
  89. #include <krb5/libos-proto.h>
  90. #include <netdb.h>
  91. #include <ctype.h>
  92.  
  93. #ifdef    __STDC__
  94. #include <stdlib.h>
  95. #endif
  96. #ifdef    NO_STRING_H
  97. #include <strings.h>
  98. #else
  99. #include <string.h>
  100. #endif
  101.  
  102. #include "encrypt.h"
  103. #include "auth.h"
  104. #include "misc.h"
  105.  
  106. extern auth_debug_mode;
  107.  
  108. char *malloc();
  109.  
  110. static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
  111.                       AUTHTYPE_KERBEROS_V5, };
  112. static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
  113.                     TELQUAL_NAME, };
  114.  
  115. #define    KRB_AUTH    0        /* Authentication data follows */
  116. #define    KRB_REJECT    1        /* Rejected (reason might follow) */
  117. #define    KRB_ACCEPT    2        /* Accepted */
  118. #define    KRB_CHALLANGE    3        /* Challange for mutual auth. */
  119. #define    KRB_RESPONSE    4        /* Response for mutual auth. */
  120.  
  121. static    krb5_data auth;
  122.     /* telnetd gets session key from here */
  123. static    krb5_tkt_authent *authdat = NULL;
  124.  
  125. #if    defined(ENCRYPT)
  126. Block    session_key;
  127. #endif
  128. static Schedule sched;
  129. static Block    challange;
  130.  
  131.     static int
  132. Data(ap, type, d, c)
  133.     Authenticator *ap;
  134.     int type;
  135.     void *d;
  136.     int c;
  137. {
  138.         unsigned char *p = str_data + 4;
  139.     unsigned char *cd = (unsigned char *)d;
  140.  
  141.     if (c == -1)
  142.         c = strlen((char *)cd);
  143.  
  144.         if (auth_debug_mode) {
  145.                 printf("%s:%d: [%d] (%d)",
  146.                         str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
  147.                         str_data[3],
  148.                         type, c);
  149.                 printd(d, c);
  150.                 printf("\r\n");
  151.         }
  152.     *p++ = ap->type;
  153.     *p++ = ap->way;
  154.     *p++ = type;
  155.         while (c-- > 0) {
  156.                 if ((*p++ = *cd++) == IAC)
  157.                         *p++ = IAC;
  158.         }
  159.         *p++ = IAC;
  160.         *p++ = SE;
  161.     if (str_data[3] == TELQUAL_IS)
  162.         printsub('>', &str_data[2], p - &str_data[2]);
  163.         return(net_write(str_data, p - str_data));
  164. }
  165.  
  166.     int
  167. kerberos5_init(ap, server)
  168.     Authenticator *ap;
  169.     int server;
  170. {
  171.     if (server)
  172.         str_data[3] = TELQUAL_REPLY;
  173.     else
  174.         str_data[3] = TELQUAL_IS;
  175.         krb5_init_ets();
  176.     return(1);
  177. }
  178.  
  179.     int
  180. kerberos5_send(ap)
  181.     Authenticator *ap;
  182. {
  183.     char **realms;
  184.     char *name;
  185.     char *p1, *p2;
  186.     krb5_checksum ksum;
  187.     krb5_octet sum[CRC32_CKSUM_LENGTH];
  188.     krb5_data *server[4];
  189.     krb5_data srvdata[3];
  190.     krb5_error_code r;
  191.     krb5_ccache ccache;
  192.     krb5_creds creds;        /* telnet gets session key from here */
  193.     extern krb5_flags krb5_kdc_default_options;
  194.  
  195.     ksum.checksum_type = CKSUMTYPE_CRC32;
  196.     ksum.contents = sum;
  197.     ksum.length = sizeof(sum);
  198.     bzero((void *)sum, sizeof(sum));
  199.     
  200.         if (!UserNameRequested) {
  201.                 if (auth_debug_mode) {
  202.                         printf("Kerberos V5: no user name supplied\r\n");
  203.                 }
  204.                 return(0);
  205.         }
  206.  
  207.     if (r = krb5_cc_default(&ccache)) {
  208.         if (auth_debug_mode) {
  209.             printf("Kerberos V5: could not get default ccache\r\n");
  210.         }
  211.         return(0);
  212.     }
  213.  
  214.     if ((name = malloc(strlen(RemoteHostName)+1)) == NULL) {
  215.         if (auth_debug_mode)
  216.             printf("Out of memory for hostname in Kerberos V5\r\n");
  217.         return(0);
  218.     }
  219.  
  220.     if (r = krb5_get_host_realm(RemoteHostName, &realms)) {
  221.         if (auth_debug_mode)
  222.             printf("Kerberos V5: no realm for %s\r\n", RemoteHostName);
  223.         free(name);
  224.         return(0);
  225.     }
  226.  
  227.     p1 = RemoteHostName;
  228.     p2 = name;
  229.  
  230.     while (*p2 = *p1++) {
  231.         if (isupper(*p2))
  232.             *p2 |= 040;
  233.         ++p2;
  234.     }
  235.  
  236.     srvdata[0].data = realms[0];
  237.     srvdata[0].length = strlen(realms[0]);
  238.     srvdata[1].data = "rcmd";
  239.     srvdata[1].length = 4;
  240.     srvdata[2].data = name;
  241.     srvdata[2].length = p2 - name;
  242.  
  243.     server[0] = &srvdata[0];
  244.     server[1] = &srvdata[1];
  245.     server[2] = &srvdata[2];
  246.     server[3] = 0;
  247.  
  248.     bzero((char *)&creds, sizeof(creds));
  249.     creds.server = (krb5_principal)server;
  250.  
  251.     if (r = krb5_cc_get_principal(ccache, &creds.client)) {
  252.         if (auth_debug_mode) {
  253.             printf("Keberos V5: failure on principal (%d)\r\n",
  254.                 error_message(r));
  255.         }
  256.         free(name);
  257.         krb5_free_host_realm(realms);
  258.         return(0);
  259.     }
  260.  
  261.     if (r = krb5_get_credentials(krb5_kdc_default_options, ccache, &creds)) {
  262.         if (auth_debug_mode) {
  263.             printf("Keberos V5: failure on credentials(%d)\r\n",r);
  264.         }
  265.         free(name);
  266.         krb5_free_host_realm(realms);
  267.         return(0);
  268.     }
  269.  
  270.     r = krb5_mk_req_extended(0, &ksum, &creds.times,
  271.                  krb5_kdc_default_options,
  272.                  ccache, &creds, 0, &auth);
  273.  
  274.     free(name);
  275.     krb5_free_host_realm(realms);
  276.     if (r) {
  277.         if (auth_debug_mode) {
  278.             printf("Keberos V5: mk_req failed\r\n");
  279.         }
  280.         return(0);
  281.     }
  282.  
  283.         if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
  284.                 if (auth_debug_mode)
  285.                         printf("Not enough room for user name\r\n");
  286.                 return(0);
  287.         }
  288.     if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
  289.         if (auth_debug_mode)
  290.             printf("Not enough room for authentication data\r\n");
  291.         return(0);
  292.     }
  293.     /*
  294.      * If we are doing mutual authentication, get set up to send
  295.      * the challange, and verify it when the response comes back.
  296.      */
  297.     if (((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
  298.         && (creds.keyblock.keytype == KEYTYPE_DES)) {
  299.         register int i;
  300.  
  301.         des_key_sched(creds.keyblock.contents, sched);
  302.         des_set_random_generator_seed(creds.keyblock.contents);
  303.         des_new_random_key(challange);
  304.         des_ecb_encrypt(challange, session_key, sched, 1);
  305.         /*
  306.          * Increment the challange by 1, and encrypt it for
  307.          * later comparison.
  308.          */
  309.         for (i = 7; i >= 0; --i) {
  310.             register int x;
  311.             x = (unsigned int)challange[i] + 1;
  312.             challange[i] = x;    /* ignore overflow */
  313.             if (x < 256)        /* if no overflow, all done */
  314.                 break;
  315.         }
  316.         des_ecb_encrypt(challange, challange, sched, 1);
  317.     }
  318.     
  319.     if (auth_debug_mode) {
  320.         printf("Sent Kerberos V5 credentials to server\r\n");
  321.     }
  322.     return(1);
  323. }
  324.  
  325.     void
  326. kerberos5_is(ap, data, cnt)
  327.     Authenticator *ap;
  328.     unsigned char *data;
  329.     int cnt;
  330. {
  331.     int r;
  332.     struct hostent *hp;
  333.     char *p1, *p2;
  334.     static char *realm = NULL;
  335.     krb5_data *server[4];
  336.     krb5_data srvdata[3];
  337.         Session_Key skey;
  338.     char *name;
  339.     char *getenv();
  340.  
  341.     if (cnt-- < 1)
  342.         return;
  343.     switch (*data++) {
  344.     case KRB_AUTH:
  345.         auth.data = (char *)data;
  346.         auth.length = cnt;
  347.  
  348.         if (!(hp = gethostbyname(LocalHostName))) {
  349.             if (auth_debug_mode)
  350.                 printf("Cannot resolve local host name\r\n");
  351.             Data(ap, KRB_REJECT, "Unknown local hostname.", -1);
  352.             auth_finished(ap, AUTH_REJECT);
  353.             return;
  354.         }
  355.  
  356.         if (!realm && (krb5_get_default_realm(&realm))) {
  357.             if (auth_debug_mode)
  358.                 printf("Could not get defualt realm\r\n");
  359.             Data(ap, KRB_REJECT, "Could not get default realm.", -1);
  360.             auth_finished(ap, AUTH_REJECT);
  361.             return;
  362.         }
  363.  
  364.         if ((name = malloc(strlen(hp->h_name)+1)) == NULL) {
  365.             if (auth_debug_mode)
  366.                 printf("Out of memory for hostname in Kerberos V5\r\n");
  367.             Data(ap, KRB_REJECT, "Out of memory.", -1);
  368.             auth_finished(ap, AUTH_REJECT);
  369.             return;
  370.         }
  371.  
  372.         p1 = hp->h_name;
  373.         p2 = name;
  374.  
  375.         while (*p2 = *p1++) {
  376.             if (isupper(*p2))
  377.                 *p2 |= 040;
  378.             ++p2;
  379.         }
  380.  
  381.         srvdata[0].data = realm;
  382.         srvdata[0].length = strlen(realm);
  383.         srvdata[1].data = "rcmd";
  384.         srvdata[1].length = 4;
  385.         srvdata[2].data = name;
  386.         srvdata[2].length = p2 - name;
  387.  
  388.         server[0] = &srvdata[0];
  389.         server[1] = &srvdata[1];
  390.         server[2] = &srvdata[2];
  391.         server[3] = 0;
  392.  
  393.         if (authdat)
  394.             krb5_free_tkt_authent(authdat);
  395.         if (r = krb5_rd_req_simple(&auth, server, 0, &authdat)) {
  396.             char errbuf[128];
  397.  
  398.             authdat = 0;
  399.             (void) strcpy(errbuf, "Read req failed: ");
  400.             (void) strcat(errbuf, error_message(r));
  401.             Data(ap, KRB_REJECT, errbuf, -1);
  402.             if (auth_debug_mode)
  403.                 printf("%s\r\n", errbuf);
  404.             return;
  405.         }
  406.         free(name);
  407.         if (krb5_unparse_name(authdat->ticket->enc_part2 ->client,
  408.                                           &name))
  409.             name = 0;
  410.         Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
  411.         if (auth_debug_mode) {
  412.             printf("Kerberos5 accepting him as ``%s''\r\n",
  413.                             name ? name : "");
  414.         }
  415.                 auth_finished(ap, AUTH_USER);
  416.         if (authdat->ticket->enc_part2->session->keytype != KEYTYPE_DES)
  417.             break;
  418.         bcopy((void *)authdat->ticket->enc_part2->session->contents,
  419.               (void *)session_key, sizeof(Block));
  420.         break;
  421.  
  422.     case KRB_CHALLANGE:
  423.         if (!VALIDKEY(session_key)) {
  424.             /*
  425.              * We don't have a valid session key, so just
  426.              * send back a response with an empty session
  427.              * key.
  428.              */
  429.             Data(ap, KRB_RESPONSE, (void *)0, 0);
  430.             break;
  431.         }
  432.  
  433.         des_key_sched(session_key, sched);
  434.         bcopy((void *)data, (void *)datablock, sizeof(Block));
  435.         /*
  436.          * Take the received encrypted challange, and encrypt
  437.          * it again to get a unique session_key for the
  438.          * ENCRYPT option.
  439.          */
  440.         des_ecb_encrypt(datablock, session_key, sched, 1);
  441.         skey.type = SK_DES;
  442.         skey.length = 8;
  443.         skey.data = session_key;
  444.         encrypt_session_key(&skey, 1);
  445.         /*
  446.          * Now decrypt the received encrypted challange,
  447.          * increment by one, re-encrypt it and send it back.
  448.          */
  449.         des_ecb_encrypt(datablock, challange, sched, 0);
  450.         for (r = 7; r >= 0; r++) {
  451.             register int t;
  452.             t = (unsigned int)challange[r] + 1;
  453.             challange[r] = t;    /* ignore overflow */
  454.             if (t < 256)        /* if no overflow, all done */
  455.                 break;
  456.         }
  457.         des_ecb_encrypt(challange, challange, sched, 1);
  458.         Data(ap, KRB_RESPONSE, (void *)challange, sizeof(challange));
  459.         break;
  460.  
  461.     default:
  462.         if (auth_debug_mode)
  463.             printf("Unknown Kerberos option %d\r\n", data[-1]);
  464.         Data(ap, KRB_REJECT, 0, 0);
  465.         break;
  466.     }
  467. }
  468.  
  469.     void
  470. kerberos5_reply(ap, data, cnt)
  471.     Authenticator *ap;
  472.     unsigned char *data;
  473.     int cnt;
  474. {
  475.         Session_Key skey;
  476.  
  477.     if (cnt-- < 1)
  478.         return;
  479.     switch (*data++) {
  480.     case KRB_REJECT:
  481.         if (cnt > 0) {
  482.             printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
  483.                 cnt, data);
  484.         } else
  485.             printf("[ Kerberos V5 refuses authentication ]\r\n");
  486.         auth_send_retry();
  487.         return;
  488.     case KRB_ACCEPT:
  489.         printf("[ Kerberos V5 accepts you ]\n", cnt, data);
  490.         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
  491.             /*
  492.              * Send over the encrypted challange.
  493.               */
  494.             Data(ap, KRB_CHALLANGE, (void *)session_key,
  495.                         sizeof(session_key));
  496. #if    defined(ENCRYPT)
  497.             des_ecb_encrypt(session_key, session_key, sched, 1);
  498.             skey.type = SK_DES;
  499.             skey.length = 8;
  500.             skey.data = session_key;
  501.             encrypt_session_key(&skey, 0);
  502. #endif
  503.             return;
  504.         }
  505.         auth_finished(ap, AUTH_USER);
  506.         return;
  507.     case KRB_RESPONSE:
  508.         /*
  509.          * Verify that the response to the challange is correct.
  510.          */
  511.         if ((cnt != sizeof(Block)) ||
  512.             (0 != memcmp((void *)data, (void *)challange,
  513.                         sizeof(challange))))
  514.         {
  515.             printf("[ Kerberos V5 challange failed!!! ]\r\n");
  516.             auth_send_retry();
  517.             return;
  518.         }
  519.         printf("[ Kerberos V5 challange successful ]\r\n");
  520.         auth_finished(ap, AUTH_USER);
  521.         break;
  522.     default:
  523.         if (auth_debug_mode)
  524.             printf("Unknown Kerberos option %d\r\n", data[-1]);
  525.         return;
  526.     }
  527. }
  528.  
  529.     int
  530. kerberos5_status(ap, name, level)
  531.     Authenticator *ap;
  532.     char *name;
  533.     int level;
  534. {
  535.     if (level < AUTH_USER)
  536.         return(level);
  537.  
  538.     if (UserNameRequested &&
  539.         krb5_kuserok(authdat->ticket->enc_part2->client, UserNameRequested))
  540.     {
  541.         strcpy(name, UserNameRequested);
  542.         return(AUTH_VALID);
  543.     } else
  544.         return(AUTH_USER);
  545. }
  546.  
  547. #define    BUMP(buf, len)        while (*(buf)) {++(buf), --(len);}
  548. #define    ADDC(buf, len, c)    if ((len) > 0) {*(buf)++ = (c); --(len));}
  549.  
  550.     void
  551. kerberos5_printsub(data, cnt, buf, buflen)
  552.     unsigned char *data, *buf;
  553.     int cnt, buflen;
  554. {
  555.     char lbuf[32];
  556.     register int i;
  557.  
  558.     buf[buflen-1] = '\0';        /* make sure its NULL terminated */
  559.     buflen -= 1;
  560.  
  561.     switch(data[3]) {
  562.     case KRB_REJECT:        /* Rejected (reason might follow) */
  563.         strncpy((char *)buf, " REJECT ", buflen);
  564.         goto common;
  565.  
  566.     case KRB_ACCEPT:        /* Accepted (name might follow) */
  567.         strncpy((char *)buf, " ACCEPT ", buflen);
  568.     common:
  569.         BUMP(buf, buflen);
  570.         if (cnt <= 4)
  571.             break;
  572.         ADDC(buf, buflen, '"');
  573.         for (i = 4; i < cnt; i++)
  574.             ADDC(buf, buflen, data[i]);
  575.         ADDC(buf, buflen, '"');
  576.         ADDC(buf, buflen, '\0');
  577.         break;
  578.  
  579.     case KRB_AUTH:            /* Authentication data follows */
  580.         strncpy((char *)buf, " AUTH", buflen);
  581.         goto common2;
  582.  
  583.     case KRB_CHALLANGE:
  584.         strncpy((char *)buf, " CHALLANGE", buflen);
  585.         goto common2;
  586.  
  587.     case KRB_RESPONSE:
  588.         strncpy((char *)buf, " RESPONSE", buflen);
  589.         goto common2;
  590.  
  591.     default:
  592.         sprintf(lbuf, " %d (unknown)", data[3]);
  593.         strncpy((char *)buf, lbuf, buflen);
  594.     common2:
  595.         BUMP(buf, buflen);
  596.         for (i = 4; i < cnt; i++) {
  597.             sprintf(lbuf, " %d", data[i]);
  598.             strncpy((char *)buf, lbuf, buflen);
  599.             BUMP(buf, buflen);
  600.         }
  601.         break;
  602.     }
  603. }
  604. #endif
  605. @
  606.