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 / skey_fn.c < prev    next >
C/C++ Source or Header  |  2012-06-28  |  7KB  |  224 lines

  1. /*
  2.  * $Id: skey_fn.c,v 1.10 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.  
  25. /* internal state variables */
  26. #define STATE_AUTHEN_START   0    /* no requests issued */
  27. #define STATE_AUTHEN_GETUSER 1    /* username has been requested */
  28. #define STATE_AUTHEN_GETPASS 2    /* password has been requested */
  29.  
  30. #include <skey.h>
  31.  
  32. struct private_data {
  33.     struct skey skey;
  34.     char password[MAX_PASSWD_LEN + 1];
  35.     int state;
  36. };
  37.  
  38. /*
  39.  * Use s/key to verify a supplied password using state set up earlier
  40.  * when the username was supplied.
  41.  */
  42. static int
  43. skey_verify(char *passwd, struct authen_data *data)
  44. {
  45.     struct private_data *p = data->method_data;
  46.     struct skey *skeyp = &p->skey;
  47.  
  48.     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
  49.  
  50.     if (skeyverify(skeyp, passwd) == 0) {
  51.     /* S/Key authentication succeeded */
  52.     data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
  53.     if (skeyp->n < 5) {
  54.         data->server_msg = tac_strdup("Password will expire soon");
  55.         return(1);
  56.     }
  57.     }
  58.     return(0);
  59. }
  60.  
  61. /*
  62.  * Skey tacacs login authentication function. Wants a username
  63.  * and a password, and tries to verify them via skey.
  64.  *
  65.  * Choose_authen will ensure that we already have a username before this
  66.  * gets called.
  67.  *
  68.  * We will query for a password and keep it in the method_data.
  69.  *
  70.  * Any strings returned via pointers in authen_data must come from the
  71.  * heap. They will get freed by the caller.
  72.  *
  73.  * Return 0 if data->status is valid, otherwise 1
  74.  */
  75. int
  76. skey_fn(struct authen_data *data)
  77. {
  78.     char *name, *passwd;
  79.     struct private_data *p;
  80.     char *prompt;
  81.     int pwlen;
  82.  
  83.     p = (struct private_data *) data->method_data;
  84.  
  85.     /* An abort has been received. Clean up and return */
  86.     if (data->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
  87.     if (data->method_data)
  88.         free(data->method_data);
  89.     data->method_data = NULL;
  90.     return(1);
  91.     }
  92.     /* Initialise method_data if first time through */
  93.     if (!p) {
  94.     p = (struct private_data *) tac_malloc(sizeof(struct private_data));
  95.     memset(p, 0, sizeof(struct private_data));
  96.     data->method_data = p;
  97.     p->state = STATE_AUTHEN_START;
  98.     }
  99.  
  100.     /* Unless we're enabling, we need a username */
  101.     if (data->service != TAC_PLUS_AUTHEN_SVC_ENABLE &&
  102.     (char)data->NAS_id->username[0] == '\0') {
  103.     switch (p->state) {
  104.  
  105.     case STATE_AUTHEN_GETUSER:
  106.         /* we have previously asked for a username but none came back.
  107.          * This is a gross error */
  108.         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  109.         report(LOG_ERR, "%s: No username supplied after GETUSER",
  110.            session.peer);
  111.         return(0);
  112.  
  113.     case STATE_AUTHEN_START:
  114.         /* No username. Try requesting one */
  115.         data->status = TAC_PLUS_AUTHEN_STATUS_GETUSER;
  116.         if (data->service == TAC_PLUS_AUTHEN_SVC_LOGIN) {
  117.         prompt = "\nUser Access Verification\n\nUsername: ";
  118.         } else {
  119.         prompt = "Username: ";
  120.         }
  121.         data->server_msg = tac_strdup(prompt);
  122.         p->state = STATE_AUTHEN_GETUSER;
  123.         return(0);
  124.  
  125.     default:
  126.         /* something awful has happened. Give up and die */
  127.         report(LOG_ERR, "%s: skey_fn bad state %d",
  128.            session.peer, p->state);
  129.         return(1);
  130.     }
  131.     }
  132.  
  133.     /* we now have a username if we needed one */
  134.     name = data->NAS_id->username;
  135.  
  136.     /* Do we have a password? */
  137.     passwd = p->password;
  138.  
  139.     if (!passwd[0]) {
  140.     char skeyprompt[80];
  141.  
  142.     /* no password yet. Either we need to ask for one and expect to get
  143.      * called again, or we asked but nothing came back, which is fatal */
  144.  
  145.     switch (p->state) {
  146.     case STATE_AUTHEN_GETPASS:
  147.         /* We already asked for a password. This should be the reply */
  148.         if (data->client_msg) {
  149.         pwlen = MIN(strlen(data->client_msg), MAX_PASSWD_LEN);
  150.         } else {
  151.         pwlen = 0;
  152.         }
  153.         strncpy(passwd, data->client_msg, pwlen);
  154.         passwd[pwlen] = '\0';
  155.         break;
  156.  
  157.     default:
  158.         /* Request a password */
  159.         passwd = cfg_get_login_secret(name, TAC_PLUS_RECURSE);
  160.         if (!passwd && !STREQ(passwd, "skey")) {
  161.         report(LOG_ERR, "Cannot find skey password declaration for %s",
  162.                name);
  163.         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  164.         return(1);
  165.         }
  166.  
  167.         if (skeychallenge(&p->skey, name, skeyprompt, 80) == 0) {
  168.         char buf[256];
  169.         snprintf(buf, sizeof(buf), "%s\nS/Key challenge: ", skeyprompt);
  170.         data->server_msg = tac_strdup(buf);
  171.         data->status = TAC_PLUS_AUTHEN_STATUS_GETPASS;
  172.         p->state = STATE_AUTHEN_GETPASS;
  173.         return(0);
  174.         }
  175.  
  176.         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  177.         report(LOG_ERR, "Cannot generate skey prompt for %s", name);
  178.         return(1);
  179.     }
  180.     }
  181.  
  182.     /* We have a username and password. Try validating */
  183.  
  184.     /* Assume the worst */
  185.     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
  186.  
  187.     switch (data->service) {
  188.     case TAC_PLUS_AUTHEN_SVC_LOGIN:
  189.     case TAC_PLUS_AUTHEN_SVC_ENABLE:
  190.     skey_verify(passwd, data);
  191.     if (debug)
  192.         report(LOG_INFO, "login/enable query for '%s' %s from %s %s",
  193.            name && name[0] ? name : "unknown",
  194.            data->NAS_id->NAS_port && data->NAS_id->NAS_port[0] ?
  195.                data->NAS_id->NAS_port : "unknown",
  196.            session.peer,
  197.            (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
  198.            "accepted" : "rejected");
  199.     break;
  200.  
  201.     default:
  202.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  203.     report(LOG_ERR, "%s: Bogus service value %d from packet",
  204.                            session.peer, data->service);
  205.     break;
  206.     }
  207.  
  208.     if (data->method_data)
  209.     free(data->method_data);
  210.     data->method_data = NULL;
  211.  
  212.     switch (data->status) {
  213.     case TAC_PLUS_AUTHEN_STATUS_ERROR:
  214.     case TAC_PLUS_AUTHEN_STATUS_FAIL:
  215.     case TAC_PLUS_AUTHEN_STATUS_PASS:
  216.     return(0);
  217.     default:
  218.     report(LOG_ERR, "%s: skey_fn couldn't set recognizable status %d",
  219.            session.peer, data->status);
  220.     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
  221.     return(1);
  222.     }
  223. }
  224.