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 < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-23  |  14.9 KB  |  582 lines

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