home *** CD-ROM | disk | FTP | other *** search
/ ftp.shrubbery.net / 2015-02-07.ftp.shrubbery.net.tar / ftp.shrubbery.net / pub / tac_plus / tacacs+-F4.0.4.27a.tar.gz / tacacs+-F4.0.4.27a.tar / tacacs+-F4.0.4.27a / sendauth.c < prev    next >
C/C++ Source or Header  |  2012-01-23  |  9KB  |  348 lines

  1. /*
  2.  * $Id: sendauth.c,v 1.7 2009-03-17 18:40:20 heas Exp $
  3.  *
  4.  * Copyright (c) 1995-1998 by Cisco systems, Inc.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software for
  7.  * any purpose and without fee is hereby granted, provided that this
  8.  * copyright and permission notice appear on all copies of the
  9.  * software and supporting documentation, the name of Cisco Systems,
  10.  * Inc. not be used in advertising or publicity pertaining to
  11.  * distribution of the program without specific prior permission, and
  12.  * notice be given in supporting documentation that modification,
  13.  * copying and distribution is by permission of Cisco Systems, Inc.
  14.  *
  15.  * Cisco Systems, Inc. makes no representations about the suitability
  16.  * of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
  17.  * IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
  18.  * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  19.  * FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21.  
  22. #include "tac_plus.h"
  23. #include "expire.h"
  24. #include "md5.h"
  25.  
  26. static int do_sendauth_fn();
  27. static void outbound_chap();
  28. #ifdef MSCHAP
  29. static void outbound_mschap();
  30. #endif /* MSCHAP */
  31. void outbound_pap();
  32.  
  33. int
  34. sendauth_fn(struct authen_data *data)
  35. {
  36.     int status;
  37.     char *name, *p;
  38.  
  39.     status = 0;
  40.     name = data->NAS_id->username;
  41.  
  42.     if (STREQ(name, DEFAULT_USERNAME)) {
  43.     /* This username is only valid for authorization */
  44.     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
  45.     } else {
  46.     status = do_sendauth_fn(data);
  47.     }
  48.  
  49.     if (debug) {
  50.     switch (data->type) {
  51.     case TAC_PLUS_AUTHEN_TYPE_CHAP:
  52.         p = "chap";
  53.         break;
  54.  
  55. #ifdef MSCHAP
  56.     case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
  57.         p = "ms-chap";
  58.         break;
  59. #endif /* MSCHAP */
  60.  
  61.     case TAC_PLUS_AUTHEN_TYPE_PAP:
  62.         p = "pap";
  63.         break;
  64.  
  65.     default:
  66.         p = "unknown";
  67.         break;
  68.     }
  69.  
  70.     report(LOG_INFO, "%s-sendauth query for '%s' %s from %s %s",
  71.            p,
  72.            name && name[0] ? name : "unknown",
  73.            session.peer, session.port,
  74.            (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
  75.            "accepted" : "rejected");
  76.     }
  77.     return(status);
  78. }
  79.  
  80. /*
  81.  * For PAP we need to supply the outgoing PAP cleartext password.
  82.  * from the config file.
  83.  *
  84.  * For CHAP, we expect an id and a challenge. We will return an MD5 hash
  85.  * if we're successful,
  86.  *
  87.  * Return 0 if data->status is valid, otherwise 1
  88.  */
  89. static int
  90. do_sendauth_fn(struct authen_data *data)
  91. {
  92.     char *name, *exp_date;
  93.  
  94.     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
  95.  
  96.     /* We must have a username */
  97.     if (!data->NAS_id->username[0]) {
  98.     /* Missing username is a gross error */
  99.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  100.     data->server_msg = tac_strdup("No username supplied");
  101.     report(LOG_ERR, "%s: No username for sendauth_fn", session.peer);
  102.     return(0);
  103.     }
  104.     name = data->NAS_id->username;
  105.  
  106.     switch (data->type) {
  107.     case TAC_PLUS_AUTHEN_TYPE_CHAP:
  108.     outbound_chap(data);
  109.     break;
  110.  
  111. #ifdef MSCHAP
  112.     case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
  113.     outbound_mschap(data);
  114.     break;
  115. #endif /* MSCHAP */
  116.  
  117.     case TAC_PLUS_AUTHEN_TYPE_PAP:
  118.     outbound_pap(data);
  119.     break;
  120.  
  121.     default:
  122.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  123.     report(LOG_ERR, "%s %s: %s Illegal data type for sendauth_fn",
  124.            session.peer, session.port, name);
  125.     return(0);
  126.     }
  127.  
  128.     exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE);
  129.     set_expiration_status(exp_date, data);
  130.     return(0);
  131. }
  132.  
  133. void
  134. outbound_pap(struct authen_data *data)
  135. {
  136.     char *secret, *p, *name;
  137.  
  138.     name = data->NAS_id->username;
  139.  
  140.     /* We must have a username */
  141.     if (!name) {
  142.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  143.     return;
  144.     }
  145.  
  146.     /* Return her secret outbound PAP info */
  147.     secret = cfg_get_opap_secret(name, TAC_PLUS_RECURSE);
  148.     if (!secret) {
  149.     if (debug & DEBUG_AUTHEN_FLAG) {
  150.         report(LOG_ERR, "%s %s: No opap secret for %s",
  151.            session.peer, session.port, name);
  152.     }
  153.     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
  154.     return;
  155.     }
  156.  
  157.     p = tac_find_substring("cleartext ", secret);
  158.     if (!p) {
  159.     /* Should never happen */
  160.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  161.     report(LOG_ERR, "%s %s: Illegal opap secret format %s",
  162.            session.peer, session.port, secret);
  163.     return;
  164.     }
  165.  
  166.     data->server_data = tac_strdup(p);
  167.     data->server_dlen = strlen(data->server_data);
  168.     data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
  169. }
  170.  
  171. static void
  172. outbound_chap(struct authen_data *data)
  173. {
  174.     char *name, *secret, *chal, digest[TAC_MD5_DIGEST_LEN];
  175.     char *p;
  176.     u_char *mdp;
  177.     char id;
  178.     int chal_len, inlen;
  179.     MD5_CTX mdcontext;
  180.  
  181.     name = data->NAS_id->username;
  182.  
  183.     if (!name) {
  184.     report(LOG_ERR, "%s %s: no username for outbound_chap",
  185.            session.peer, session.port);
  186.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  187.     return;
  188.     }
  189.  
  190.     id = data->client_data[0];
  191.  
  192.     chal_len = data->client_dlen - 1;
  193.     if (chal_len < 0) {
  194.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  195.     return;
  196.     }
  197.  
  198.     if (debug & DEBUG_AUTHEN_FLAG) {
  199.     report(LOG_DEBUG, "%s %s: user %s, id=%d chal_len=%d",
  200.            session.peer, session.port, name, (int)id, chal_len);
  201.     }
  202.  
  203.     /* Assume failure */
  204.     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
  205.  
  206.     /* Get the secret */
  207.     secret = cfg_get_chap_secret(name, TAC_PLUS_RECURSE);
  208.  
  209.     /* If there is no chap password for this user, see if there is
  210.        a global password for her that we can use */
  211.     if (!secret) {
  212.     secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE);
  213.     }
  214.  
  215.     if (!secret) {
  216.     /* No secret. Fail */
  217.     if (debug & DEBUG_AUTHEN_FLAG) {
  218.         report(LOG_DEBUG, "%s %s: No chap or global secret for %s",
  219.            session.peer, session.port, name);
  220.     }
  221.     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
  222.     return;
  223.     }
  224.  
  225.  
  226.     p = tac_find_substring("cleartext ", secret);
  227.     if (!p) {
  228.     /* Should never happen */
  229.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  230.     report(LOG_ERR, "%s %s: Illegal opap secret format %s",
  231.            session.peer, session.port, secret);
  232.     return;
  233.     }
  234.     secret = p;
  235.  
  236.     /*
  237.      * We now have the secret, the id, and the challenge value.
  238.      * Put them all together, and run them through the MD5 digest
  239.      * algorithm. */
  240.  
  241.     inlen = sizeof(u_char) + strlen(secret) + chal_len;
  242.     mdp = (u_char *)tac_malloc(inlen);
  243.     mdp[0] = id;
  244.     memcpy(&mdp[1], secret, strlen(secret));
  245.     chal = data->client_data + 1;
  246.     memcpy(mdp + strlen(secret) + 1, chal, chal_len);
  247.     MD5Init(&mdcontext);
  248.     MD5Update(&mdcontext, mdp, inlen);
  249.     MD5Final((u_char *)digest, &mdcontext);
  250.     free(mdp);
  251.  
  252.     /*
  253.      * Now return the calculated response value */
  254.  
  255.     data->server_data = tac_malloc(TAC_MD5_DIGEST_LEN);
  256.     memcpy(data->server_data, digest, TAC_MD5_DIGEST_LEN);
  257.     data->server_dlen = TAC_MD5_DIGEST_LEN;
  258.  
  259.     data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
  260. }
  261.  
  262. #ifdef MSCHAP
  263.  
  264. static void
  265. outbound_mschap(struct authen_data *data)
  266. {
  267.     char *name, *secret, *chal;
  268.     char *p;
  269.     char id;
  270.     int chal_len;
  271.  
  272.     name = data->NAS_id->username;
  273.  
  274.     if (!name) {
  275.     report(LOG_ERR, "%s %s: no username for outbound_mschap",
  276.            session.peer, session.port);
  277.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  278.     return;
  279.     }
  280.  
  281.     id = data->client_data[0];
  282.  
  283.     chal_len = data->client_dlen - 1;
  284.     if (data->client_dlen <= 2) {
  285.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  286.     return;
  287.     }
  288.  
  289.     if (debug & DEBUG_AUTHEN_FLAG) {
  290.     report(LOG_DEBUG, "%s %s: user %s, id=%d chal_len=%d",
  291.            session.peer, session.port, name, (int)id, chal_len);
  292.     }
  293.  
  294.     /* Assume failure */
  295.     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
  296.  
  297.     /* Get the secret */
  298.     secret = cfg_get_mschap_secret(name, TAC_PLUS_RECURSE);
  299.  
  300.     /* If there is no chap password for this user, see if there is
  301.        a global password for her that we can use */
  302.     if (!secret) {
  303.     secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE);
  304.     }
  305.  
  306.     if (!secret) {
  307.     /* No secret. Fail */
  308.     if (debug & DEBUG_AUTHEN_FLAG) {
  309.         report(LOG_DEBUG, "%s %s: No ms-chap or global secret for %s",
  310.            session.peer, session.port, name);
  311.     }
  312.     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
  313.     return;
  314.     }
  315.  
  316.     p = tac_find_substring("cleartext ", secret);
  317.     if (!p) {
  318.     /* Should never happen */
  319.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  320.     report(LOG_ERR, "%s %s: Illegal ms-chap secret format %s",
  321.            session.peer, session.port, secret);
  322.     return;
  323.     }
  324.     secret = p;
  325.  
  326.     /*
  327.      * We now have the secret, the id, and the challenge value.
  328.      * Put them all together, and run them through the MD4 digest
  329.      * algorithm. */
  330.  
  331.     chal = data->client_data + 1;
  332.  
  333.     /*
  334.      * Now return the calculated response value */
  335.  
  336.     data->server_data = tac_malloc(MSCHAP_DIGEST_LEN);
  337.  
  338.     mschap_lmchallengeresponse(chal,secret,&data->server_data[0]);
  339.     mschap_ntchallengeresponse(chal,secret,&data->server_data[24]);
  340.  
  341.     data->server_data[48] = 1; /* Mark it to use the NT response*/
  342.     data->server_dlen = MSCHAP_DIGEST_LEN;
  343.  
  344.     data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
  345. }
  346.  
  347. #endif /* MSCHAP */
  348.