home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / libtelnet / kerberos.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-22  |  14.7 KB  |  565 lines

  1. /*-
  2.  * Copyright (c) 1991, 1993
  3.  *    The Regents of the University of California.  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[] = "@(#)kerberos.c    8.3 (Berkeley) 5/30/95";
  36. #endif /* not lint */
  37.  
  38. /*
  39.  * Copyright (C) 1990 by the Massachusetts Institute of Technology
  40.  *
  41.  * Export of this software from the United States of America is assumed
  42.  * to require a specific license from the United States Government.
  43.  * It is the responsibility of any person or organization contemplating
  44.  * export to obtain such a license before exporting.
  45.  *
  46.  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  47.  * distribute this software and its documentation for any purpose and
  48.  * without fee is hereby granted, provided that the above copyright
  49.  * notice appear in all copies and that both that copyright notice and
  50.  * this permission notice appear in supporting documentation, and that
  51.  * the name of M.I.T. not be used in advertising or publicity pertaining
  52.  * to distribution of the software without specific, written prior
  53.  * permission.  M.I.T. makes no representations about the suitability of
  54.  * this software for any purpose.  It is provided "as is" without express
  55.  * or implied warranty.
  56.  */
  57.  
  58. #ifdef HAVE_CONFIG_H
  59. #include <config.h>
  60. #endif
  61.  
  62. #ifdef    KRB4
  63. #include <sys/types.h>
  64. #include <arpa/telnet.h>
  65. #include <stdio.h>
  66. #include <des.h>        /* BSD wont include this in krb.h, so we do it here */
  67. #include <krb.h>
  68. #ifdef    __STDC__
  69. #include <stdlib.h>
  70. #endif
  71. #ifdef    NO_STRING_H
  72. #include <strings.h>
  73. #else
  74. #include <string.h>
  75. #endif
  76.  
  77. #include "encrypt.h"
  78. #include "auth.h"
  79. #include "misc.h"
  80.  
  81. int kerberos4_cksum P((unsigned char *, int));
  82. int krb_mk_req P((KTEXT, char *, char *, char *, u_long));
  83. int krb_rd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *));
  84. int krb_kntoln P((AUTH_DAT *, char *));
  85. int krb_get_cred P((char *, char *, char *, CREDENTIALS *));
  86. int krb_get_lrealm P((char *, int));
  87. int kuserok P((AUTH_DAT *, char *));
  88.  
  89. extern auth_debug_mode;
  90.  
  91. static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
  92.                       AUTHTYPE_KERBEROS_V4, };
  93. static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
  94.                     TELQUAL_NAME, };
  95.  
  96. #define    KRB_AUTH    0        /* Authentication data follows */
  97. #define    KRB_REJECT    1        /* Rejected (reason might follow) */
  98. #define    KRB_ACCEPT    2        /* Accepted */
  99. #define    KRB_CHALLENGE    3        /* Challenge for mutual auth. */
  100. #define    KRB_RESPONSE    4        /* Response for mutual auth. */
  101.  
  102. #define KRB_SERVICE_NAME   "rcmd"
  103.  
  104. static    KTEXT_ST auth;
  105. static    char name[ANAME_SZ];
  106. static    AUTH_DAT adat = { 0 };
  107. #ifdef    ENCRYPTION
  108. static Block    session_key    = { 0 };
  109. static Schedule sched;
  110. static Block    challenge    = { 0 };
  111. #endif    /* ENCRYPTION */
  112.  
  113.     static int
  114. Data(ap, type, d, c)
  115.     Authenticator *ap;
  116.     int type;
  117.     void *d;
  118.     int c;
  119. {
  120.         unsigned char *p = str_data + 4;
  121.     unsigned char *cd = (unsigned char *)d;
  122.  
  123.     if (c == -1)
  124.         c = strlen((char *)cd);
  125.  
  126.         if (auth_debug_mode) {
  127.                 printf("%s:%d: [%d] (%d)",
  128.                         str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
  129.                         str_data[3],
  130.                         type, c);
  131.                 printd(d, c);
  132.                 printf("\r\n");
  133.         }
  134.     *p++ = ap->type;
  135.     *p++ = ap->way;
  136.     *p++ = type;
  137.         while (c-- > 0) {
  138.                 if ((*p++ = *cd++) == IAC)
  139.                         *p++ = IAC;
  140.         }
  141.         *p++ = IAC;
  142.         *p++ = SE;
  143.     if (str_data[3] == TELQUAL_IS)
  144.         printsub('>', &str_data[2], p - (&str_data[2]));
  145.         return(net_write(str_data, p - str_data));
  146. }
  147.  
  148.     int
  149. kerberos4_init(ap, server)
  150.     Authenticator *ap;
  151.     int server;
  152. {
  153.     FILE *fp;
  154.  
  155.     if (server) {
  156.         str_data[3] = TELQUAL_REPLY;
  157.         if ((fp = fopen(KEYFILE, "r")) == NULL)
  158.             return(0);
  159.         fclose(fp);
  160.     } else {
  161.         str_data[3] = TELQUAL_IS;
  162.     }
  163.     return(1);
  164. }
  165.  
  166. char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
  167. int dst_realm_sz = REALM_SZ;
  168.  
  169.     int
  170. kerberos4_send(ap)
  171.     Authenticator *ap;
  172. {
  173.     KTEXT_ST auth;
  174. #ifdef    ENCRYPTION
  175.     Block enckey;
  176. #endif    /* ENCRYPTION */
  177.     char instance[INST_SZ];
  178.     char *realm;
  179.     char *krb_realmofhost();
  180.     char *krb_get_phost();
  181.     CREDENTIALS cred;
  182.     int r;
  183.  
  184.     printf("[ Trying KERBEROS4 ... ]\n");    
  185.     if (!UserNameRequested) {
  186.         if (auth_debug_mode) {
  187.             printf("Kerberos V4: no user name supplied\r\n");
  188.         }
  189.         return(0);
  190.     }
  191.  
  192.     memset(instance, 0, sizeof(instance));
  193.  
  194.     if (realm = krb_get_phost(RemoteHostName))
  195.         strncpy(instance, realm, sizeof(instance));
  196.  
  197.     instance[sizeof(instance)-1] = '\0';
  198.  
  199.     realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName);
  200.  
  201.     if (!realm) {
  202.         printf("Kerberos V4: no realm for %s\r\n", RemoteHostName);
  203.         return(0);
  204.     }
  205.     if (r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L)) {
  206.         printf("mk_req failed: %s\r\n", krb_err_txt[r]);
  207.         return(0);
  208.     }
  209.     if (r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred)) {
  210.         printf("get_cred failed: %s\r\n", krb_err_txt[r]);
  211.         return(0);
  212.     }
  213.     if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
  214.         if (auth_debug_mode)
  215.             printf("Not enough room for user name\r\n");
  216.         return(0);
  217.     }
  218.     if (auth_debug_mode)
  219.         printf("Sent %d bytes of authentication data\r\n", auth.length);
  220.     if (!Data(ap, KRB_AUTH, (void *)auth.dat, auth.length)) {
  221.         if (auth_debug_mode)
  222.             printf("Not enough room for authentication data\r\n");
  223.         return(0);
  224.     }
  225. #ifdef    ENCRYPTION
  226.     /*
  227.      * If we are doing mutual authentication, get set up to send
  228.      * the challenge, and verify it when the response comes back.
  229.      */
  230.     if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
  231.         register int i;
  232.  
  233.         des_key_sched(cred.session, sched);
  234.         des_init_random_number_generator(cred.session);
  235.         des_new_random_key(session_key);
  236.         des_ecb_encrypt(session_key, session_key, sched, 0);
  237.         des_ecb_encrypt(session_key, challenge, sched, 0);
  238.         /*
  239.          * Increment the challenge by 1, and encrypt it for
  240.          * later comparison.
  241.          */
  242.         for (i = 7; i >= 0; --i) {
  243.             register int x;
  244.             x = (unsigned int)challenge[i] + 1;
  245.             challenge[i] = x;    /* ignore overflow */
  246.             if (x < 256)        /* if no overflow, all done */
  247.                 break;
  248.         }
  249.         des_ecb_encrypt(challenge, challenge, sched, 1);
  250.     }
  251. #endif    /* ENCRYPTION */
  252.     
  253.     if (auth_debug_mode) {
  254.         printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
  255.         printd(auth.dat, auth.length);
  256.         printf("\r\n");
  257.         printf("Sent Kerberos V4 credentials to server\r\n");
  258.     }
  259.     return(1);
  260. }
  261.  
  262.     void
  263. kerberos4_is(ap, data, cnt)
  264.     Authenticator *ap;
  265.     unsigned char *data;
  266.     int cnt;
  267. {
  268. #ifdef    ENCRYPTION
  269.     Session_Key skey;
  270.     Block datablock;
  271. #endif    /* ENCRYPTION */
  272.     char realm[REALM_SZ];
  273.     char instance[INST_SZ];
  274.     int r;
  275.  
  276.     if (cnt-- < 1)
  277.         return;
  278.     switch (*data++) {
  279.     case KRB_AUTH:
  280.         if (krb_get_lrealm(realm, 1) != KSUCCESS) {
  281.             Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1);
  282.             auth_finished(ap, AUTH_REJECT);
  283.             if (auth_debug_mode)
  284.                 printf("No local realm\r\n");
  285.             return;
  286.         }
  287.         memmove((void *)auth.dat, (void *)data, auth.length = cnt);
  288.         if (auth_debug_mode) {
  289.             printf("Got %d bytes of authentication data\r\n", cnt);
  290.             printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
  291.             printd(auth.dat, auth.length);
  292.             printf("\r\n");
  293.         }
  294.         instance[0] = '*'; instance[1] = 0;
  295.         if (r = krb_rd_req(&auth, KRB_SERVICE_NAME,
  296.                    instance, 0, &adat, "")) {
  297.             if (auth_debug_mode)
  298.                 printf("Kerberos failed him as %s\r\n", name);
  299.             Data(ap, KRB_REJECT, (void *)krb_err_txt[r], -1);
  300.             auth_finished(ap, AUTH_REJECT);
  301.             return;
  302.         }
  303. #ifdef    ENCRYPTION
  304.         memmove((void *)session_key, (void *)adat.session, sizeof(Block));
  305. #endif    /* ENCRYPTION */
  306.         krb_kntoln(&adat, name);
  307.  
  308.         if (UserNameRequested && !kuserok(&adat, UserNameRequested))
  309.             Data(ap, KRB_ACCEPT, (void *)0, 0);
  310.         else
  311.             Data(ap, KRB_REJECT,
  312.                 (void *)"user is not authorized", -1);
  313.         auth_finished(ap, AUTH_USER);
  314.         break;
  315.  
  316.     case KRB_CHALLENGE:
  317. #ifndef    ENCRYPTION
  318.         Data(ap, KRB_RESPONSE, (void *)0, 0);
  319. #else    /* ENCRYPTION */
  320.         if (!VALIDKEY(session_key)) {
  321.             /*
  322.              * We don't have a valid session key, so just
  323.              * send back a response with an empty session
  324.              * key.
  325.              */
  326.             Data(ap, KRB_RESPONSE, (void *)0, 0);
  327.             break;
  328.         }
  329.  
  330.         /*
  331.          * Initialize the random number generator since it's
  332.          * used later on by the encryption routine.
  333.          */
  334.         des_init_random_number_generator(session_key);
  335.         des_key_sched(session_key, sched);
  336.         memmove((void *)datablock, (void *)data, sizeof(Block));
  337.         /*
  338.          * Take the received encrypted challenge, and encrypt
  339.          * it again to get a unique session_key for the
  340.          * ENCRYPT option.
  341.          */
  342.         des_ecb_encrypt(datablock, session_key, sched, 1);
  343.         skey.type = SK_DES;
  344.         skey.length = 8;
  345.         skey.data = session_key;
  346.         encrypt_session_key(&skey, 1);
  347.         /*
  348.          * Now decrypt the received encrypted challenge,
  349.          * increment by one, re-encrypt it and send it back.
  350.          */
  351.         des_ecb_encrypt(datablock, challenge, sched, 0);
  352.         for (r = 7; r >= 0; r--) {
  353.             register int t;
  354.             t = (unsigned int)challenge[r] + 1;
  355.             challenge[r] = t;    /* ignore overflow */
  356.             if (t < 256)        /* if no overflow, all done */
  357.                 break;
  358.         }
  359.         des_ecb_encrypt(challenge, challenge, sched, 1);
  360.         Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge));
  361. #endif    /* ENCRYPTION */
  362.         break;
  363.  
  364.     default:
  365.         if (auth_debug_mode)
  366.             printf("Unknown Kerberos option %d\r\n", data[-1]);
  367.         Data(ap, KRB_REJECT, 0, 0);
  368.         break;
  369.     }
  370. }
  371.  
  372.     void
  373. kerberos4_reply(ap, data, cnt)
  374.     Authenticator *ap;
  375.     unsigned char *data;
  376.     int cnt;
  377. {
  378. #ifdef    ENCRYPTION
  379.     Session_Key skey;
  380. #endif    /* ENCRYPTION */
  381.  
  382.     if (cnt-- < 1)
  383.         return;
  384.     switch (*data++) {
  385.     case KRB_REJECT:
  386.         if (cnt > 0) {
  387.             printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n",
  388.                 cnt, data);
  389.         } else
  390.             printf("[ Kerberos V4 refuses authentication ]\r\n");
  391.         auth_send_retry();
  392.         return;
  393.     case KRB_ACCEPT:
  394.         printf("[ Kerberos V4 accepts you ]\n");
  395.         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
  396.             /*
  397.              * Send over the encrypted challenge.
  398.               */
  399. #ifndef    ENCRYPTION
  400.             Data(ap, KRB_CHALLENGE, (void *)0, 0);
  401. #else    /* ENCRYPTION */
  402.             Data(ap, KRB_CHALLENGE, (void *)session_key,
  403.                         sizeof(session_key));
  404.             des_ecb_encrypt(session_key, session_key, sched, 1);
  405.             skey.type = SK_DES;
  406.             skey.length = 8;
  407.             skey.data = session_key;
  408.             encrypt_session_key(&skey, 0);
  409. #endif    /* ENCRYPTION */
  410.             return;
  411.         }
  412.         auth_finished(ap, AUTH_USER);
  413.         return;
  414.     case KRB_RESPONSE:
  415. #ifdef    ENCRYPTION
  416.         /*
  417.          * Verify that the response to the challenge is correct.
  418.          */
  419.         if ((cnt != sizeof(Block)) ||
  420.             (0 != memcmp((void *)data, (void *)challenge,
  421.                         sizeof(challenge))))
  422.         {
  423. #endif    /* ENCRYPTION */
  424.             printf("[ Kerberos V4 challenge failed!!! ]\r\n");
  425.             auth_send_retry();
  426.             return;
  427. #ifdef    ENCRYPTION
  428.         }
  429.         printf("[ Kerberos V4 challenge successful ]\r\n");
  430.         auth_finished(ap, AUTH_USER);
  431. #endif    /* ENCRYPTION */
  432.         break;
  433.     default:
  434.         if (auth_debug_mode)
  435.             printf("Unknown Kerberos option %d\r\n", data[-1]);
  436.         return;
  437.     }
  438. }
  439.  
  440.     int
  441. kerberos4_status(ap, name, level)
  442.     Authenticator *ap;
  443.     char *name;
  444.     int level;
  445. {
  446.     if (level < AUTH_USER)
  447.         return(level);
  448.  
  449.     if (UserNameRequested && !kuserok(&adat, UserNameRequested)) {
  450.         strcpy(name, UserNameRequested);
  451.         return(AUTH_VALID);
  452.     } else
  453.         return(AUTH_USER);
  454. }
  455.  
  456. #define    BUMP(buf, len)        while (*(buf)) {++(buf), --(len);}
  457. #define    ADDC(buf, len, c)    if ((len) > 0) {*(buf)++ = (c); --(len);}
  458.  
  459.     void
  460. kerberos4_printsub(data, cnt, buf, buflen)
  461.     unsigned char *data, *buf;
  462.     int cnt, buflen;
  463. {
  464.     char lbuf[32];
  465.     register int i;
  466.  
  467.     buf[buflen-1] = '\0';        /* make sure its NULL terminated */
  468.     buflen -= 1;
  469.  
  470.     switch(data[3]) {
  471.     case KRB_REJECT:        /* Rejected (reason might follow) */
  472.         strncpy((char *)buf, " REJECT ", buflen);
  473.         goto common;
  474.  
  475.     case KRB_ACCEPT:        /* Accepted (name might follow) */
  476.         strncpy((char *)buf, " ACCEPT ", buflen);
  477.     common:
  478.         BUMP(buf, buflen);
  479.         if (cnt <= 4)
  480.             break;
  481.         ADDC(buf, buflen, '"');
  482.         for (i = 4; i < cnt; i++)
  483.             ADDC(buf, buflen, data[i]);
  484.         ADDC(buf, buflen, '"');
  485.         ADDC(buf, buflen, '\0');
  486.         break;
  487.  
  488.     case KRB_AUTH:            /* Authentication data follows */
  489.         strncpy((char *)buf, " AUTH", buflen);
  490.         goto common2;
  491.  
  492.     case KRB_CHALLENGE:
  493.         strncpy((char *)buf, " CHALLENGE", buflen);
  494.         goto common2;
  495.  
  496.     case KRB_RESPONSE:
  497.         strncpy((char *)buf, " RESPONSE", buflen);
  498.         goto common2;
  499.  
  500.     default:
  501.         sprintf(lbuf, " %d (unknown)", data[3]);
  502.         strncpy((char *)buf, lbuf, buflen);
  503.     common2:
  504.         BUMP(buf, buflen);
  505.         for (i = 4; i < cnt; i++) {
  506.             sprintf(lbuf, " %d", data[i]);
  507.             strncpy((char *)buf, lbuf, buflen);
  508.             BUMP(buf, buflen);
  509.         }
  510.         break;
  511.     }
  512. }
  513.  
  514.     int
  515. kerberos4_cksum(d, n)
  516.     unsigned char *d;
  517.     int n;
  518. {
  519.     int ck = 0;
  520.  
  521.     /*
  522.      * A comment is probably needed here for those not
  523.      * well versed in the "C" language.  Yes, this is
  524.      * supposed to be a "switch" with the body of the
  525.      * "switch" being a "while" statement.  The whole
  526.      * purpose of the switch is to allow us to jump into
  527.      * the middle of the while() loop, and then not have
  528.      * to do any more switch()s.
  529.      *
  530.      * Some compilers will spit out a warning message
  531.      * about the loop not being entered at the top.
  532.      */
  533.     switch (n&03)
  534.     while (n > 0) {
  535.     case 0:
  536.         ck ^= (int)*d++ << 24;
  537.         --n;
  538.     case 3:
  539.         ck ^= (int)*d++ << 16;
  540.         --n;
  541.     case 2:
  542.         ck ^= (int)*d++ << 8;
  543.         --n;
  544.     case 1:
  545.         ck ^= (int)*d++;
  546.         --n;
  547.     }
  548.     return(ck);
  549. }
  550. #endif
  551.  
  552. #ifdef notdef
  553.  
  554. prkey(msg, key)
  555.     char *msg;
  556.     unsigned char *key;
  557. {
  558.     register int i;
  559.     printf("%s:", msg);
  560.     for (i = 0; i < 8; i++)
  561.         printf(" %3d", key[i]);
  562.     printf("\r\n");
  563. }
  564. #endif
  565.