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 / authen.c < prev    next >
C/C++ Source or Header  |  2012-03-28  |  13KB  |  462 lines

  1. /*
  2.  * $Id: authen.c,v 1.13 2009-04-10 18:46:43 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.  
  24. static int choose();
  25. static void authenticate();
  26. static void do_start();
  27.  
  28. /*
  29.  *  Come here when we receive an authentication START packet
  30.  */
  31. void
  32. authen(u_char *pak)
  33. {
  34.     char msg[55];
  35.     struct authen_start *start;
  36.     HDR *hdr;
  37.  
  38.     hdr = (HDR *)pak;
  39.     start = (struct authen_start *)(pak + TAC_PLUS_HDR_SIZE);
  40.  
  41.     /* Must be at least sizeof(struct authen_start) in size */
  42.     if (ntohl(hdr->datalength) < TAC_AUTHEN_START_FIXED_FIELDS_SIZE) {
  43.     report(LOG_ERR, "%s: authen minimum payload length: %zu, got: %u",
  44.            session.peer, TAC_AUTHEN_START_FIXED_FIELDS_SIZE,
  45.            ntohl(hdr->datalength));
  46.     send_authen_error("Invalid AUTHEN/START packet (too short)");
  47.     return;
  48.     }
  49.  
  50.     if ((hdr->seq_no != 1) ||
  51.     (ntohl(hdr->datalength) != TAC_AUTHEN_START_FIXED_FIELDS_SIZE +
  52.      start->user_len + start->port_len + start->rem_addr_len +
  53.      start->data_len)) {
  54.     send_authen_error("Invalid AUTHEN/START packet (check keys)");
  55.     return;
  56.     }
  57.  
  58.     switch (start->action) {
  59.     case TAC_PLUS_AUTHEN_LOGIN:
  60.     case TAC_PLUS_AUTHEN_SENDAUTH:
  61.     case TAC_PLUS_AUTHEN_SENDPASS:
  62.     do_start(pak);
  63.     return;
  64.     default:
  65.     snprintf(msg, sizeof(msg), "Invalid AUTHEN/START action=%d",
  66.              start->action);
  67.     send_authen_error(msg);
  68.     return;
  69.     }
  70. }
  71.  
  72. /*
  73.  * We have a valid AUTHEN/START packet. Fill out data structures and
  74.  * attempt to authenticate.
  75.  */
  76. static void
  77. do_start(u_char *pak)
  78. {
  79.     struct identity identity;
  80.     struct authen_data authen_data;
  81.     struct authen_type authen_type;
  82.     struct authen_start *start;
  83.     u_char *p;
  84.     int ret;
  85.  
  86.     if (debug & DEBUG_PACKET_FLAG)
  87.     report(LOG_DEBUG, "Authen Start request");
  88.  
  89.     /* fixed fields of this packet */
  90.     start = (struct authen_start *)(pak + TAC_PLUS_HDR_SIZE);
  91.  
  92.     /* variable length data starts here */
  93.     p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_START_FIXED_FIELDS_SIZE;
  94.  
  95.     /* The identity structure */
  96.  
  97.     /* zero out identity struct so that all strings can be NULL terminated */
  98.     memset(&identity, 0, sizeof(struct identity));
  99.  
  100.     identity.username = tac_make_string(p, (int)start->user_len);
  101.     p += start->user_len;
  102.  
  103.     identity.NAS_name = tac_strdup(session.peer);
  104. #ifdef ACLS
  105.     identity.NAS_ip = tac_strdup(session.peerip);
  106. #endif
  107.  
  108.     identity.NAS_port = tac_make_string(p, (int)start->port_len);
  109.     p += start->port_len;
  110.  
  111.     if (start->port_len <= 0) {
  112.     strcpy(session.port, "unknown-port");
  113.     } else {
  114.     strcpy(session.port, identity.NAS_port);
  115.     }
  116.  
  117.     identity.NAC_address = tac_make_string(p, (int)start->rem_addr_len);
  118.     p += start->rem_addr_len;
  119.  
  120.     identity.priv_lvl = start->priv_lvl;
  121.  
  122.     /* The authen_data structure */
  123.     memset(&authen_data, 0, sizeof(struct authen_data));
  124.  
  125.     authen_data.NAS_id = &identity;
  126.     authen_data.action = start->action;
  127.     authen_data.service = start->service;
  128.     authen_data.type = start->authen_type;
  129.     authen_data.client_dlen = start->data_len;
  130.  
  131.     authen_data.client_data = tac_malloc(start->data_len);
  132.     memcpy(authen_data.client_data, p, start->data_len);
  133.  
  134.     /* The authen_type structure */
  135.     memset(&authen_type, 0, sizeof(struct authen_type));
  136.  
  137.     authen_type.authen_type = start->authen_type;
  138.  
  139.     /*
  140.      * All data structures are now initialised. Now see if we can authenticate
  141.      * this puppy. Begin by choosing a suitable authentication function to
  142.      * call to actually do the work.
  143.      */
  144.     ret = choose(&authen_data, &authen_type);
  145.  
  146.     switch (ret) {
  147.     case 1:
  148.     /* A successful choice. Authenticate */
  149.     authenticate(&authen_data, &authen_type);
  150.     break;
  151.     case 0:
  152.     /* We lost our connection, aborted, or something dreadful happened */
  153.     break;
  154.     }
  155.  
  156.     /* free data structures */
  157.     if (authen_data.server_msg) {
  158.     free(authen_data.server_msg);
  159.     authen_data.server_msg = NULL;
  160.     }
  161.     if (authen_data.server_data) {
  162.     free(authen_data.server_data);
  163.     authen_data.server_data = NULL;
  164.     }
  165.     if (authen_data.client_msg) {
  166.     free(authen_data.client_msg);
  167.     authen_data.client_msg = NULL;
  168.     }
  169.     if (authen_data.client_data) {
  170.     free(authen_data.client_data);
  171.     authen_data.client_data = NULL;
  172.     }
  173.     if (authen_data.method_data) {
  174.     report(LOG_ERR, "%s: Method data not set to NULL after authentication",
  175.            session.peer);
  176.     }
  177.     free(identity.username);
  178.     free(identity.NAS_name);
  179.     free(identity.NAS_port);
  180.     free(identity.NAC_address);
  181.     return;
  182. }
  183.  
  184. /*
  185.  * Choose an authentication function. Return 1 if we successfully
  186.  * chose a function.  0 if we couldn't make a choice for some reason
  187.  */
  188. static int
  189. choose(struct authen_data *datap, struct authen_type *typep)
  190. {
  191.     int iterations = 0;
  192.     int status;
  193.     char *prompt;
  194.     struct authen_cont *cont;
  195.     u_char *reply;
  196.     u_char *p;
  197.     struct identity *identp;
  198.  
  199.     while (1) {
  200.     /* check interation counter here */
  201.     if (++iterations >= TAC_PLUS_MAX_ITERATIONS) {
  202.         report(LOG_ERR, "%s: %s Too many iterations for choose_authen",
  203.            session.peer,
  204.            session.port);
  205.         return(0);
  206.     }
  207.     status = choose_authen(datap, typep);
  208.  
  209.     if (status && (debug & DEBUG_PACKET_FLAG))
  210.         report(LOG_DEBUG, "choose_authen returns %d", status);
  211.  
  212.     switch (status) {
  213.     case CHOOSE_BADTYPE: /* FIXME */
  214.     default:
  215.         send_authen_error("choose_authen: unexpected failure return");
  216.         return(0);
  217.     case CHOOSE_OK:
  218.         if (debug & DEBUG_PACKET_FLAG)
  219.         report(LOG_DEBUG, "choose_authen chose %s", typep->authen_name);
  220.         return(1);
  221.     case CHOOSE_FAILED:
  222.         send_authen_error("choose_authen: unacceptable authen method");
  223.         return(0);
  224.     case CHOOSE_GETUSER:
  225.         /*
  226.          * respond with GETUSER containing an optional message from
  227.          * authen_data.server_msg.
  228.          */
  229.         datap->status = TAC_PLUS_AUTHEN_STATUS_GETUSER;
  230.         if (datap->service == TAC_PLUS_AUTHEN_SVC_LOGIN) {
  231.         prompt = cfg_get_host_prompt(datap->NAS_id->NAS_ip);
  232.         if (prompt == NULL && !STREQ(datap->NAS_id->NAS_name,
  233.                          datap->NAS_id->NAS_ip)) {
  234.             prompt = cfg_get_host_prompt(datap->NAS_id->NAS_name);
  235.         }
  236.  
  237.         if (prompt == NULL) {
  238.             prompt = "\nUser Access Verification\n\nUsername: ";
  239.         }
  240.         } else {
  241.         prompt = "Username: ";
  242.         }
  243.         send_authen_reply(TAC_PLUS_AUTHEN_STATUS_GETUSER, /* status */
  244.                   prompt, /* msg */
  245.                   strlen(prompt), /* msg_len */
  246.                   datap->server_data,
  247.                   datap->server_dlen,
  248.                   0 /* flags */);
  249.  
  250.         if (datap->server_data) {
  251.         free(datap->server_data);
  252.         datap->server_dlen = 0;
  253.         }
  254.         /* expect a CONT from the NAS */
  255.         reply = get_authen_continue();
  256.         if (reply == NULL) {
  257.         /* Typically premature close of connection */
  258.         report(LOG_ERR, "%s %s: Null reply packet, expecting CONTINUE",
  259.                session.peer, session.port);
  260.         return(0);
  261.         }
  262.  
  263.         cont = (struct authen_cont *)(reply + TAC_PLUS_HDR_SIZE);
  264.  
  265.         if (cont->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
  266.         char buf[65537];
  267.         buf[0] = '\0';
  268.         session.aborted = 1;
  269.  
  270.         if (cont->user_data_len) {
  271.             /* An abort message exists. Log it */
  272.             p = reply + TAC_PLUS_HDR_SIZE +
  273.             TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE + cont->user_msg_len;
  274.  
  275.             memcpy(buf, p, cont->user_data_len);
  276.             buf[cont->user_data_len] = '\0';
  277.         }
  278.         report(LOG_INFO, "%s %s: Login aborted by request -- msg: %s",
  279.                session.peer, session.port, buf);
  280.         free(reply);
  281.         return(0);
  282.         }
  283.  
  284.         p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;
  285.  
  286.         identp = datap->NAS_id;
  287.  
  288.         if (identp->username) {
  289.         free(identp->username);
  290.         }
  291.         identp->username = tac_make_string(p, cont->user_msg_len);
  292.         free(reply);
  293.     }
  294.     }
  295.     /* NOTREACHED */
  296. }
  297.  
  298. /*
  299.  * Perform authentication assuming we have successfully chosen an
  300.  * authentication method
  301.  */
  302. static void
  303. authenticate(struct authen_data *datap, struct authen_type *typep)
  304. {
  305.     int iterations = 0;
  306.     u_char *reply, *p;
  307.     struct authen_cont *cont;
  308.     int (*func) ();
  309.  
  310.     if (debug & DEBUG_PACKET_FLAG)
  311.     report(LOG_DEBUG, "Calling authentication function");
  312.  
  313.     func = typep->authen_func;
  314.  
  315.     if (!func) {
  316.     send_authen_error("authenticate: cannot find function pointer");
  317.     return;
  318.     }
  319.  
  320.     while (1) {
  321.     if (session.aborted)
  322.         return;
  323.  
  324.     if (++iterations >= TAC_PLUS_MAX_ITERATIONS) {
  325.         send_authen_error("Too many iterations while authenticating");
  326.         return;
  327.     }
  328.  
  329.     if ((*func)(datap)) {
  330.         send_authen_error("Unexpected authentication function failure");
  331.         return;
  332.     }
  333.  
  334.     switch (datap->status) {
  335.     default:
  336.         send_authen_error("Illegal status value from authentication "
  337.                   "function");
  338.         return;
  339.     case TAC_PLUS_AUTHEN_STATUS_PASS:
  340.         /* A successful authentication */
  341.         send_authen_reply(TAC_PLUS_AUTHEN_STATUS_PASS,
  342.                   datap->server_msg,
  343.                   datap->server_msg ? strlen(datap->server_msg) : 0,
  344.                   datap->server_data,
  345.                   datap->server_dlen,
  346.                   0);
  347.         return;
  348.     case TAC_PLUS_AUTHEN_STATUS_ERROR:
  349.         /*
  350.          * never supposed to happen. reply with a server_msg if any, and
  351.          * bail out
  352.          */
  353.         send_authen_error(datap->server_msg ? datap->server_msg :
  354.                 "authentication function: unspecified failure");
  355.         return;
  356.     case TAC_PLUS_AUTHEN_STATUS_FAIL:
  357.         /* An invalid user/password combination */
  358.         send_authen_reply(TAC_PLUS_AUTHEN_STATUS_FAIL,
  359.                   datap->server_msg,
  360.                   datap->server_msg ? strlen(datap->server_msg) : 0,
  361.                   NULL, 0, 0);
  362.         return;
  363.     case TAC_PLUS_AUTHEN_STATUS_GETUSER:
  364.     case TAC_PLUS_AUTHEN_STATUS_GETPASS:
  365.     case TAC_PLUS_AUTHEN_STATUS_GETDATA:
  366.         /* ship GETPASS/GETDATA containing datap->server_msg to NAS. */
  367.         send_authen_reply(datap->status,
  368.                   datap->server_msg,
  369.                   datap->server_msg ? strlen(datap->server_msg) : 0,
  370.                   datap->server_data,
  371.                   datap->server_dlen,
  372.                   datap->flags);
  373.  
  374.         datap->flags = 0;
  375.  
  376.         if (datap->server_msg) {
  377.         free(datap->server_msg);
  378.         datap->server_msg = NULL;
  379.         }
  380.         if (datap->server_data) {
  381.         free(datap->server_data);
  382.         datap->server_data = NULL;
  383.         }
  384.         if (datap->client_msg) {
  385.         free(datap->client_msg);
  386.         datap->client_msg = NULL;
  387.         }
  388.         reply = get_authen_continue();
  389.         if (!reply) {
  390.         /* Typically due to a premature connection close */
  391.         report(LOG_ERR, "%s %s: Null reply packet, expecting CONTINUE",
  392.                session.peer, session.port);
  393.  
  394.         /* Tell the authentication function it should clean up
  395.            any private data */
  396.  
  397.         datap->flags |= TAC_PLUS_CONTINUE_FLAG_ABORT;
  398.  
  399.         if (datap->method_data)
  400.             ((*func)(datap));
  401.  
  402.         datap->flags = 0;
  403.         return;
  404.         }
  405.  
  406.         cont = (struct authen_cont *)(reply + TAC_PLUS_HDR_SIZE);
  407.  
  408.         if (cont->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
  409.         session.aborted = 1;
  410.  
  411.         /* Tell the authentication function to clean up
  412.            its private data, if there is any */
  413.  
  414.         datap->flags |= TAC_PLUS_CONTINUE_FLAG_ABORT;
  415.         if (datap->method_data)
  416.             ((*func)(datap));
  417.         datap->flags = 0;
  418.  
  419.         if (cont->user_data_len) {
  420.             /*
  421.              * An abort message exists. Create a null-terminated
  422.              * string for authen_data
  423.              */
  424.             datap->client_data = (char *)
  425.             tac_malloc(cont->user_data_len + 1);
  426.  
  427.             p = reply + TAC_PLUS_HDR_SIZE +
  428.             TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE + cont->user_msg_len;
  429.  
  430.             memcpy(datap->client_data, p, cont->user_data_len);
  431.             datap->client_data[cont->user_data_len] = '\0';
  432.         }
  433.  
  434.         free(reply);
  435.         return;
  436.         }
  437.  
  438.         p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;
  439.  
  440.         switch (datap->status) {
  441.         case TAC_PLUS_AUTHEN_STATUS_GETDATA:
  442.         case TAC_PLUS_AUTHEN_STATUS_GETPASS:
  443.         /* A response to our GETDATA/GETPASS request. Create a
  444.          * null-terminated string for authen_data */
  445.         datap->client_msg = (char *)tac_malloc(cont->user_msg_len + 1);
  446.         memcpy(datap->client_msg, p, cont->user_msg_len);
  447.         datap->client_msg[cont->user_msg_len] = '\0';
  448.         free(reply);
  449.         continue;
  450.         case TAC_PLUS_AUTHEN_STATUS_GETUSER:
  451.         default:
  452.         report(LOG_ERR, "%s: authenticate: cannot happen",
  453.                session.peer);
  454.         send_authen_error("authenticate: cannot happen");
  455.         free(reply);
  456.         return;
  457.         }
  458.     }
  459.     /* NOTREACHED */
  460.     }
  461. }
  462.