home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / radius-2.zip / src / radiusd.c < prev    next >
C/C++ Source or Header  |  1996-05-14  |  43KB  |  1,732 lines

  1. /*
  2.  *
  3.  *    RADIUS
  4.  *    Remote Authentication Dial In User Service
  5.  *
  6.  *
  7.  *    Livingston Enterprises, Inc.
  8.  *    6920 Koll Center Parkway
  9.  *    Pleasanton, CA   94566
  10.  *
  11.  *    Copyright 1992 Livingston Enterprises, Inc.
  12.  *
  13.  *    Permission to use, copy, modify, and distribute this software for any
  14.  *    purpose and without fee is hereby granted, provided that this
  15.  *    copyright and permission notice appear on all copies and supporting
  16.  *    documentation, the name of Livingston Enterprises, Inc. not be used
  17.  *    in advertising or publicity pertaining to distribution of the
  18.  *    program without specific prior permission, and notice be given
  19.  *    in supporting documentation that copying and distribution is by
  20.  *    permission of Livingston Enterprises, Inc.   
  21.  *
  22.  *    Livingston Enterprises, Inc. makes no representations about
  23.  *    the suitability of this software for any purpose.  It is
  24.  *    provided "as is" without express or implied warranty.
  25.  *
  26.  */
  27.  
  28. /* don't look here for the version, run radiusd -v or look in version.c */
  29. static char sccsid[] =
  30. "@(#)radiusd.c    1.17 Copyright 1992 Livingston Enterprises Inc";
  31.  
  32. #include    <sys/types.h>
  33. #include    <sys/socket.h>
  34. #include    <sys/time.h>
  35. #include    <sys/file.h>
  36. #include    <netinet/in.h>
  37.  
  38. #include    <stdio.h>
  39. #include    <netdb.h>
  40. #include    <fcntl.h>
  41. #include    <pwd.h>
  42. #include    <time.h>
  43. #include    <ctype.h>
  44. #include    <unistd.h>
  45. #include    <signal.h>
  46. #include    <errno.h>
  47. #include    <sys/wait.h>
  48.  
  49. #if !defined(NOSHADOW)
  50. #include    <shadow.h>
  51. #endif /* !NOSHADOW */
  52.  
  53. #include    "radius.h"
  54.  
  55. char        recv_buffer[4096];
  56. char        send_buffer[4096];
  57. char        *progname;
  58. int        sockfd;
  59. int        acctfd;
  60. int        debug_flag;
  61. int        spawn_flag;
  62. int        acct_pid;
  63. char        *radius_dir;
  64. char        *radacct_dir;
  65. UINT4        expiration_seconds;
  66. UINT4        warning_seconds;
  67. extern int    errno;
  68. static AUTH_REQ    *first_request;
  69.  
  70. void        sig_fatal();
  71. void        sig_hup();
  72. void        sig_cleanup();
  73. void        rad_passchange();
  74.  
  75. main(argc, argv)
  76. int    argc;
  77. char    **argv;
  78. {
  79.     int            salen;
  80.     int            result;
  81.     struct    sockaddr    salocal;
  82.     struct    sockaddr    saremote;
  83.     struct    sockaddr_in    *sin;
  84.     struct    servent        *svp;
  85.         u_short                 lport;
  86.     AUTH_REQ        *authreq;
  87.     AUTH_REQ        *radrecv();
  88.     char            argval;
  89.     int            t;
  90.     int            pid;
  91.     int            cons;
  92.     fd_set            readfds;
  93.     int            status;
  94.  
  95.     progname = *argv++;
  96.     argc--;
  97.  
  98.     debug_flag = 0;
  99.     spawn_flag = 1;
  100.     radacct_dir = RADACCT_DIR;
  101.     radius_dir = RADIUS_DIR;
  102.  
  103.     signal(SIGHUP, sig_hup);
  104.     signal(SIGINT, sig_fatal);
  105.     signal(SIGQUIT, sig_fatal);
  106.     signal(SIGILL, sig_fatal);
  107.     signal(SIGTRAP, sig_fatal);
  108.     signal(SIGFPE, sig_fatal);
  109.     signal(SIGTERM, sig_fatal);
  110.     signal(SIGCHLD, sig_cleanup);
  111.  
  112.  
  113.  
  114.     while(argc) {
  115.  
  116.         if(**argv != '-') {
  117.             usage();
  118.         }
  119.  
  120.         argval = *(*argv + 1);
  121.         argc--;
  122.         argv++;
  123.  
  124.         switch(argval) {
  125.  
  126.         case 'a':
  127.             if(argc == 0) {
  128.                 usage();
  129.             }
  130.             radacct_dir = *argv;
  131.             argc--;
  132.             argv++;
  133.             break;
  134.         
  135.         case 'd':
  136.             if(argc == 0) {
  137.                 usage();
  138.             }
  139.             radius_dir = *argv;
  140.             argc--;
  141.             argv++;
  142.             break;
  143.         
  144.         case 's':    /* Single process mode */
  145.             spawn_flag = 0;
  146.             break;
  147.  
  148.         case 'v':
  149.             version();
  150.             break;
  151.  
  152.         case 'x':
  153.             debug_flag = 1;
  154.             break;
  155.         
  156.         default:
  157.             usage();
  158.             break;
  159.         }
  160.     }
  161.  
  162.     /* Initialize the dictionary */
  163.     if(dict_init() != 0) {
  164.         exit(-1);
  165.     }
  166.  
  167.     /* Initialize Configuration Values */
  168.     if(config_init() != 0) {
  169.         exit(-1);
  170.     }
  171.  
  172.     lport = (u_short) htons(1645);
  173.  
  174.     sockfd = socket (AF_INET, SOCK_DGRAM, 0);
  175.     if (sockfd < 0) {
  176.         (void) perror ("auth socket");
  177.         exit(-1);
  178.     }
  179.  
  180.     sin = (struct sockaddr_in *) & salocal;
  181.         memset ((char *) sin, '\0', sizeof (salocal));
  182.     sin->sin_family = AF_INET;
  183.     sin->sin_addr.s_addr = INADDR_ANY;
  184.     sin->sin_port = lport;
  185.  
  186.     result = bind (sockfd, & salocal, sizeof (*sin));
  187.     if (result < 0) {
  188.         (void) perror ("auth bind");
  189.         exit(-1);
  190.     }
  191.  
  192.  
  193.     /*
  194.      * Open Accounting Socket.
  195.      */
  196.     /* svp = getservbyname ("radacct", "udp");
  197.     if (svp == (struct servent *) 0) {
  198.         fprintf (stderr, "%s: No such service: %s/%s\n",
  199.             progname, "radacct", "udp");
  200.         exit(-1);
  201.     } */
  202.     lport = htons(ntohs(lport) +1);
  203.     acctfd = socket (AF_INET, SOCK_DGRAM, 0);
  204.     if (acctfd < 0) {
  205.         (void) perror ("acct socket");
  206.         exit(-1);
  207.     }
  208.  
  209.     sin = (struct sockaddr_in *) & salocal;
  210.         memset ((char *) sin, '\0', sizeof (salocal));
  211.     sin->sin_family = AF_INET;
  212.     sin->sin_addr.s_addr = INADDR_ANY;
  213.     sin->sin_port = lport;
  214.  
  215.     result = bind (acctfd, & salocal, sizeof (*sin));
  216.     if (result < 0) {
  217.         (void) perror ("acct bind");
  218.         exit(-1);
  219.     }
  220.  
  221.     /*
  222.      *    Disconnect from session
  223.      */
  224.     if(debug_flag == 0) {
  225.         pid = fork();
  226.         if(pid < 0) {
  227.             fprintf(stderr, "%s: Couldn't fork\n",
  228.                         progname);
  229.             exit(-1);
  230.         }
  231.         if(pid > 0) {
  232.             exit(0);
  233.         }
  234.     }
  235.  
  236.     /*
  237.      *    Disconnect from tty
  238.      */
  239.     for (t = 32; t >= 3; t--) {
  240.         if(t != sockfd && t != acctfd) {
  241.             close(t);
  242.         }
  243.     }
  244.  
  245. #if !defined(M_UNIX)
  246.     /*
  247.      * Open system console as stderr
  248.      */
  249.     cons = open("/dev/console", O_WRONLY | O_NOCTTY);
  250.     if(cons != 2) {
  251.         dup2(cons, 2);
  252.         close(cons);
  253.     }
  254. #endif
  255.     /*
  256.      * If we are able to spawn processes, we will start a child
  257.      * to listen for Accounting requests.  If not, we will 
  258.      * listen for them ourself.
  259.      */
  260.     if(spawn_flag) {
  261.         acct_pid = fork();
  262.         if(acct_pid < 0) {
  263.             fprintf(stderr, "%s: Couldn't fork\n",
  264.                         progname);
  265.             exit(-1);
  266.         }
  267.         if(acct_pid > 0) {
  268.             close(acctfd);
  269.             acctfd = -1;
  270.         }
  271.         else {
  272.             close(sockfd);
  273.             sockfd = -1;
  274.         }
  275.     }
  276.         
  277.  
  278.     /*
  279.      *    Receive user requests
  280.      */
  281.     sin = (struct sockaddr_in *) & saremote;
  282.  
  283.     for(;;) {
  284.  
  285.         FD_ZERO(&readfds);
  286.         if(sockfd >= 0) {
  287.             FD_SET(sockfd, &readfds);
  288.         }
  289.         if(acctfd >= 0) {
  290.             FD_SET(acctfd, &readfds);
  291.         }
  292.  
  293.         status = select(32, &readfds, NULL, NULL, NULL);
  294.         if(status == -1) {
  295.             if (errno == EINTR)
  296.                 continue;
  297.             sig_fatal(101);
  298.         }
  299.         if(sockfd >= 0 && FD_ISSET(sockfd, &readfds)) {
  300.             salen = sizeof (saremote);
  301.             result = recvfrom (sockfd, (char *) recv_buffer,
  302.                 (int) sizeof(recv_buffer),
  303.                 (int) 0, & saremote, & salen);
  304.  
  305.             if(result > 0) {
  306.                 authreq = radrecv(
  307.                     ntohl(sin->sin_addr.s_addr),
  308.                     ntohs(sin->sin_port),
  309.                     recv_buffer, result);
  310.                 radrespond(authreq, sockfd);
  311.             }
  312.             else if(result < 0 && errno == EINTR) {
  313.                 result = 0;
  314.             }
  315.         }
  316.         if(acctfd >=0 && FD_ISSET(acctfd, &readfds)) {
  317.             salen = sizeof (saremote);
  318.             result = recvfrom (acctfd, (char *) recv_buffer,
  319.                 (int) sizeof(recv_buffer),
  320.                 (int) 0, & saremote, & salen);
  321.  
  322.             if(result > 0) {
  323.                 authreq = radrecv(
  324.                     ntohl(sin->sin_addr.s_addr),
  325.                     ntohs(sin->sin_port),
  326.                     recv_buffer, result);
  327.                 radrespond(authreq, acctfd);
  328.             }
  329.             else if(result < 0 && errno == EINTR) {
  330.                 result = 0;
  331.             }
  332.         }
  333.     }
  334. }
  335.  
  336. /*************************************************************************
  337.  *
  338.  *    Function: radrecv
  339.  *
  340.  *    Purpose: Receive UDP client requests, build an authorization request
  341.  *         structure, and attach attribute-value pairs contained in
  342.  *         the request to the new structure.
  343.  *
  344.  *************************************************************************/
  345.  
  346. AUTH_REQ    *
  347. radrecv(host, udp_port, buffer, length)
  348. UINT4    host;
  349. u_short    udp_port;
  350. u_char    *buffer;
  351. int    length;
  352. {
  353.     u_char        *ptr;
  354.     AUTH_HDR    *auth;
  355.     int        totallen;
  356.     int        attribute;
  357.     int        attrlen;
  358.     DICT_ATTR    *attr;
  359.     DICT_ATTR    *dict_attrget();
  360.     char        string[64];
  361.     UINT4        lvalue;
  362.     char        *ip_hostname();
  363.     VALUE_PAIR    *first_pair;
  364.     VALUE_PAIR    *prev;
  365.     VALUE_PAIR    *pair;
  366.     AUTH_REQ    *authreq;
  367.  
  368.     /*
  369.      * Pre-allocate the new request data structure
  370.      */
  371.  
  372.     if((authreq = (AUTH_REQ *)malloc(sizeof(AUTH_REQ))) ==
  373.                         (AUTH_REQ *)NULL) {
  374.         fprintf(stderr, "%s: no memory\n", progname);
  375.         exit(-1);
  376.     }
  377.  
  378.     auth = (AUTH_HDR *)buffer;
  379.     totallen = ntohs(auth->length);
  380.  
  381.     DEBUG("radrecv: Request from host %lx code=%d, id=%d, length=%d\n",
  382.                 (u_long)host, auth->code, auth->id, totallen);
  383.  
  384.     /*
  385.      * Fill header fields
  386.      */
  387.     authreq->ipaddr = host;
  388.     authreq->udp_port = udp_port;
  389.     authreq->id = auth->id;
  390.     authreq->code = auth->code;
  391.     memcpy(authreq->vector, auth->vector, AUTH_VECTOR_LEN);
  392.  
  393.     /*
  394.      * Extract attribute-value pairs
  395.      */
  396.     ptr = auth->data;
  397.     length -= AUTH_HDR_LEN;
  398.     first_pair = (VALUE_PAIR *)NULL;
  399.     prev = (VALUE_PAIR *)NULL;
  400.  
  401.     while(length > 0) {
  402.  
  403.         attribute = *ptr++;
  404.         attrlen = *ptr++;
  405.         if(attrlen < 2) {
  406.             length = 0;
  407.             continue;
  408.         }
  409.         attrlen -= 2;
  410.         if((attr = dict_attrget(attribute)) == (DICT_ATTR *)NULL) {
  411.             DEBUG("Received unknown attribute %d\n", attribute);
  412.         }
  413.         else if ( attrlen >= AUTH_STRING_LEN ) {
  414.             DEBUG("attribute %d too long, %d >= %d\n", attribute,
  415.                 attrlen, AUTH_STRING_LEN);
  416.         }
  417.         else {
  418.             if((pair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
  419.                         (VALUE_PAIR *)NULL) {
  420.                 fprintf(stderr, "%s: no memory\n",
  421.                         progname);
  422.                 exit(-1);
  423.             }
  424.             strcpy(pair->name, attr->name);
  425.             pair->attribute = attr->value;
  426.             pair->type = attr->type;
  427.             pair->next = (VALUE_PAIR *)NULL;
  428.  
  429.             switch(attr->type) {
  430.  
  431.             case PW_TYPE_STRING:
  432.                 memcpy(pair->strvalue, ptr, attrlen);
  433.                 pair->strvalue[attrlen] = '\0';
  434.                 debug_pair(stdout, pair);
  435.                 if(first_pair == (VALUE_PAIR *)NULL) {
  436.                     first_pair = pair;
  437.                 }
  438.                 else {
  439.                     prev->next = pair;
  440.                 }
  441.                 prev = pair;
  442.                 break;
  443.             
  444.             case PW_TYPE_INTEGER:
  445.             case PW_TYPE_IPADDR:
  446.                 memcpy(&lvalue, ptr, sizeof(UINT4));
  447.                 pair->lvalue = ntohl(lvalue);
  448.                 debug_pair(stdout, pair);
  449.                 if(first_pair == (VALUE_PAIR *)NULL) {
  450.                     first_pair = pair;
  451.                 }
  452.                 else {
  453.                     prev->next = pair;
  454.                 }
  455.                 prev = pair;
  456.                 break;
  457.             
  458.             default:
  459.                 DEBUG("    %s (Unknown Type %d)\n", attr->name,attr->type);
  460.                 free(pair);
  461.                 break;
  462.             }
  463.  
  464.         }
  465.         ptr += attrlen;
  466.         length -= attrlen + 2;
  467.     }
  468.     authreq->request = first_pair;
  469.     return(authreq);
  470. }
  471.  
  472. /*************************************************************************
  473.  *
  474.  *    Function: radrespond
  475.  *
  476.  *    Purpose: Respond to supported requests:
  477.  *
  478.  *         PW_AUTHENTICATION_REQUEST - Authentication request from
  479.  *                a client network access server.
  480.  *
  481.  *         PW_ACCOUNTING_REQUEST - Accounting request from
  482.  *                a client network access server.
  483.  *
  484.  *         PW_PASSWORD_REQUEST - User request to change a password.
  485.  *
  486.  *************************************************************************/
  487.  
  488. radrespond(authreq, activefd)
  489. AUTH_REQ    *authreq;
  490. int        activefd;
  491. {
  492.     switch(authreq->code) {
  493.  
  494.     case PW_AUTHENTICATION_REQUEST:
  495.         if(spawn_flag) {
  496.             rad_spawn_child(authreq, activefd);
  497.         }
  498.         else {
  499.             rad_authenticate(authreq, activefd);
  500.         }
  501.         break;
  502.     
  503.     case PW_ACCOUNTING_REQUEST:
  504.         rad_accounting(authreq, activefd);
  505.         break;
  506.     
  507.     case PW_PASSWORD_REQUEST:
  508.         rad_passchange(authreq, activefd);
  509.         break;
  510.     
  511.     default:
  512.         break;
  513.     }
  514.     return(0);
  515. }
  516.  
  517.  
  518.  
  519. /*************************************************************************
  520.  *
  521.  *    Function: rad_spawn_child
  522.  *
  523.  *    Purpose: Spawns child processes to perform password authentication
  524.  *         and respond to RADIUS clients.  This functions also
  525.  *         cleans up complete child requests, and verifies that there
  526.  *         is only one process responding to each request (duplicate
  527.  *         requests are filtered out.
  528.  *
  529.  *************************************************************************/
  530.  
  531. rad_spawn_child(authreq, activefd)
  532. AUTH_REQ    *authreq;
  533. int        activefd;
  534. {
  535.     AUTH_REQ    *curreq;
  536.     AUTH_REQ    *prevreq;
  537.     UINT4        curtime;
  538.     int        request_count;
  539.     char        msg[128];
  540.     char        *ip_hostname();
  541.     int        child_pid;
  542.  
  543.     curtime = (UINT4)time(0);
  544.     request_count = 0;
  545.     curreq = first_request;
  546.     prevreq = (AUTH_REQ *)NULL;
  547.     while(curreq != (AUTH_REQ *)NULL) {
  548.         if(curreq->child_pid == -1 &&
  549.                 curreq->timestamp + CLEANUP_DELAY <= curtime) {
  550.             /* Request completed, delete it */
  551.             if(prevreq == (AUTH_REQ *)NULL) {
  552.                 first_request = curreq->next;
  553.                 pairfree(curreq->request);
  554.                 free(curreq);
  555.                 curreq = first_request;
  556.             }
  557.             else {
  558.                 prevreq->next = curreq->next;
  559.                 pairfree(curreq->request);
  560.                 free(curreq);
  561.                 curreq = prevreq->next;
  562.             }
  563.         }
  564.         else if(curreq->ipaddr == authreq->ipaddr &&
  565.                     curreq->id == authreq->id) {
  566.             /* This is a duplicate request - just drop it */
  567.             sprintf(msg, "Dropping duplicate: from %s - ID: %d\n",
  568.                 ip_hostname(authreq->ipaddr), authreq->id);
  569.             log_err(msg);
  570.             pairfree(authreq->request);
  571.             free(authreq);
  572.             return(0);
  573.         }
  574.         else {
  575.             if(curreq->timestamp + MAX_REQUEST_TIME <= curtime &&
  576.                         curreq->child_pid != -1) {
  577.                 /* This request seems to have hung - kill it */
  578.                 child_pid = curreq->child_pid;
  579.                 sprintf(msg,
  580.                     "Killing unresponsive child pid %d\n",
  581.                                 child_pid);
  582.                 log_err(msg);
  583.                 curreq->child_pid = -1;
  584.                 kill(child_pid, SIGHUP);
  585.             }
  586.             prevreq = curreq;
  587.             curreq = curreq->next;
  588.             request_count++;
  589.         }
  590.     }
  591.  
  592.     /* This is a new request */
  593.     if(request_count > MAX_REQUESTS) {
  594.         sprintf(msg, "Dropping request (too many): from %s - ID: %d\n",
  595.                 ip_hostname(authreq->ipaddr), authreq->id);
  596.         log_err(msg);
  597.         pairfree(authreq->request);
  598.         free(authreq);
  599.         return(0);
  600.     }
  601.  
  602.     /* Add this request to the list */
  603.     authreq->next = (AUTH_REQ *)NULL;
  604.     authreq->child_pid = -1;
  605.     authreq->timestamp = curtime;
  606.  
  607.     if(prevreq == (AUTH_REQ *)NULL) {
  608.         first_request = authreq;
  609.     }
  610.     else {
  611.         prevreq->next = authreq;
  612.     }
  613.  
  614.     /* fork our child */
  615.     child_pid = fork();
  616.     if(child_pid < 0) {
  617.         sprintf(msg, "Fork failed for request from %s - ID: %d\n",
  618.                 ip_hostname(authreq->ipaddr), authreq->id);
  619.         log_err(msg);
  620.     }
  621.     if(child_pid == 0) {
  622.         /* This is the child, it should go ahead and respond */
  623.         rad_authenticate(authreq, activefd);
  624.         exit(0);
  625.     }
  626.  
  627.     /* Register the Child */
  628.     authreq->child_pid = child_pid;
  629.     return(0);
  630. }
  631.  
  632. void
  633. sig_cleanup()
  634. {
  635.     int        status;
  636.         pid_t        pid;
  637.     AUTH_REQ    *curreq;
  638.  
  639.         for (;;) {
  640.         pid = waitpid((pid_t)-1,&status,WNOHANG);
  641.         signal(SIGCHLD, sig_cleanup);
  642.                 if (pid <= 0)
  643.                         return;
  644.  
  645. #if defined (aix)
  646.         kill(pid, SIGKILL);
  647. #endif
  648.  
  649.         if(pid == acct_pid) {
  650.             sig_fatal(100);
  651.         }
  652.         curreq = first_request;
  653.         while(curreq != (AUTH_REQ *)NULL) {
  654.             if(curreq->child_pid == pid) {
  655.                 curreq->child_pid = -1;
  656.                 curreq->timestamp = (UINT4)time(0);
  657.                 break;
  658.             }
  659.             curreq = curreq->next;
  660.         }
  661.         }
  662. }
  663.  
  664. /*************************************************************************
  665.  *
  666.  *    Function: rad_passchange
  667.  *
  668.  *    Purpose: Change a users password
  669.  *
  670.  *************************************************************************/
  671.  
  672. void
  673. rad_passchange(authreq, activefd)
  674. AUTH_REQ    *authreq;
  675. int        activefd;
  676. {
  677.     VALUE_PAIR    *namepair;
  678.     VALUE_PAIR    *check_item;
  679.     VALUE_PAIR    *newpasspair;
  680.     VALUE_PAIR    *oldpasspair;
  681.     VALUE_PAIR    *curpass;
  682.     VALUE_PAIR    *user_check;
  683.     VALUE_PAIR    *user_reply;
  684.     char        pw_digest[16];
  685.     char        string[64];
  686.     char        passbuf[AUTH_PASS_LEN];
  687.     int        i;
  688.     int        secretlen;
  689.     char        msg[128];
  690.     char        *ip_hostname();
  691.  
  692.     /* Get the username */
  693.     namepair = authreq->request;
  694.     while(namepair != (VALUE_PAIR *)NULL) {
  695.         if(namepair->attribute == PW_USER_NAME) {
  696.             break;
  697.         }
  698.         namepair = namepair->next;
  699.     }
  700.     if(namepair == (VALUE_PAIR *)NULL) {
  701.         sprintf(msg,
  702.             "Passchange: from %s - No User name supplied\n",
  703.             ip_hostname(authreq->ipaddr));
  704.         log_err(msg);
  705.         pairfree(authreq->request);
  706.         memset(authreq, 0, sizeof(AUTH_REQ));
  707.         free(authreq);
  708.         return;
  709.     }
  710.  
  711.     /*
  712.      * Look the user up in the database
  713.      */
  714.     if(user_find(namepair->strvalue, &user_check, &user_reply) != 0) {
  715.         sprintf(msg,
  716.             "Passchange: from %s - Invalid User: %s\n",
  717.             ip_hostname(authreq->ipaddr), namepair->strvalue);
  718.         log_err(msg);
  719.         send_reject(authreq, (char *)NULL, activefd);
  720.         pairfree(authreq->request);
  721.         memset(authreq, 0, sizeof(AUTH_REQ));
  722.         free(authreq);
  723.         return;
  724.     }
  725.  
  726.     /*
  727.      * Validate the user -
  728.      *
  729.      * We have to unwrap this in a special way to decrypt the
  730.      * old and new passwords.  The MD5 calculation is based
  731.      * on the old password.  The vector is different.  The old
  732.      * password is encrypted using the encrypted new password
  733.      * as its vector.  The new password is encrypted using the
  734.      * random encryption vector in the request header.
  735.      */
  736.  
  737.     /* Extract the attr-value pairs for the old and new passwords */
  738.     check_item = authreq->request;
  739.     while(check_item != (VALUE_PAIR *)NULL) {
  740.         if(check_item->attribute == PW_PASSWORD) {
  741.             newpasspair = check_item;
  742.         }
  743.         else if(check_item->attribute == PW_OLD_PASSWORD) {
  744.             oldpasspair = check_item;
  745.         }
  746.         check_item = check_item->next;
  747.     }
  748.  
  749.     /* Verify that both encrypted passwords were supplied */
  750.     if(newpasspair == (VALUE_PAIR *)NULL ||
  751.                     oldpasspair == (VALUE_PAIR *)NULL) {
  752.         /* Missing one of the passwords */
  753.         sprintf(msg,
  754.             "Passchange: from %s - Missing Password: %s\n",
  755.             ip_hostname(authreq->ipaddr), namepair->strvalue);
  756.         log_err(msg);
  757.         send_reject(authreq, (char *)NULL, activefd);
  758.         pairfree(authreq->request);
  759.         pairfree(user_check);
  760.         pairfree(user_reply);
  761.         memset(authreq, 0, sizeof(AUTH_REQ));
  762.         free(authreq);
  763.         return;
  764.     }
  765.  
  766.     /* Get the current password from the database */
  767.     curpass = user_check;
  768.     while(curpass != (VALUE_PAIR *)NULL) {
  769.         if(curpass->attribute == PW_PASSWORD) {
  770.             break;
  771.         }
  772.         curpass = curpass->next;
  773.     }
  774.     if((curpass == (VALUE_PAIR *)NULL) || curpass->strvalue == (char *)NULL) {
  775.         /* Missing our local copy of the password */
  776.         sprintf(msg,
  777.             "Passchange: from %s - Missing Local Password: %s\n",
  778.             ip_hostname(authreq->ipaddr), namepair->strvalue);
  779.         log_err(msg);
  780.         send_reject(authreq, (char *)NULL, activefd);
  781.         pairfree(authreq->request);
  782.         pairfree(user_check);
  783.         pairfree(user_reply);
  784.         memset(authreq, 0, sizeof(AUTH_REQ));
  785.         free(authreq);
  786.         return;
  787.     }
  788.     if(strcmp(curpass->strvalue,"UNIX") == 0) {
  789.         /* Can't change passwords that aren't in users file */
  790.         sprintf(msg,
  791.             "Passchange: from %s - system password change not allowed: %s\n",
  792.             ip_hostname(authreq->ipaddr), namepair->strvalue);
  793.         log_err(msg);
  794.         send_reject(authreq, (char *)NULL, activefd);
  795.         pairfree(authreq->request);
  796.         pairfree(user_check);
  797.         pairfree(user_reply);
  798.         memset(authreq, 0, sizeof(AUTH_REQ));
  799.         free(authreq);
  800.         return;
  801.     }
  802.  
  803.     /* Decrypt the old password */
  804.     secretlen = strlen(curpass->strvalue);
  805.     memcpy(string, curpass->strvalue, secretlen);
  806.     memcpy(string + secretlen, newpasspair->strvalue, AUTH_VECTOR_LEN);
  807.     md5_calc(pw_digest, string, AUTH_VECTOR_LEN + secretlen);
  808.     memcpy(passbuf, oldpasspair->strvalue, AUTH_PASS_LEN);
  809.     for(i = 0;i < AUTH_PASS_LEN;i++) {
  810.         passbuf[i] ^= pw_digest[i];
  811.     }
  812.  
  813.     /* Did they supply the correct password ??? */
  814.     if(strncmp(passbuf, curpass->strvalue, AUTH_PASS_LEN) != 0) {
  815.         sprintf(msg,
  816.             "Passchange: from %s - Incorrect Password: %s\n",
  817.             ip_hostname(authreq->ipaddr), namepair->strvalue);
  818.         log_err(msg);
  819.         send_reject(authreq, (char *)NULL, activefd);
  820.         pairfree(authreq->request);
  821.         pairfree(user_check);
  822.         pairfree(user_reply);
  823.         memset(authreq, 0, sizeof(AUTH_REQ));
  824.         free(authreq);
  825.         return;
  826.     }
  827.  
  828.     /* Decrypt the new password */
  829.     memcpy(string, curpass->strvalue, secretlen);
  830.     memcpy(string + secretlen, authreq->vector, AUTH_VECTOR_LEN);
  831.     md5_calc(pw_digest, string, AUTH_VECTOR_LEN + secretlen);
  832.     memcpy(passbuf, newpasspair->strvalue, AUTH_PASS_LEN);
  833.     for(i = 0;i < AUTH_PASS_LEN;i++) {
  834.         passbuf[i] ^= pw_digest[i];
  835.     }
  836.  
  837.     /* Update the users password */
  838.     strncpy(curpass->strvalue, passbuf, AUTH_PASS_LEN);
  839.  
  840.     /* Add a new expiration date if we are aging passwords */
  841.     if(expiration_seconds != (UINT4)0) {
  842.         set_expiration(user_check, expiration_seconds);
  843.     }
  844.  
  845.     /* Update the database */
  846.     if(user_update(namepair->strvalue, user_check, user_reply) != 0) {
  847.         send_reject(authreq, (char *)NULL, activefd);
  848.         sprintf(msg,
  849.             "Passchange: unable to update password for %s\n",
  850.             namepair->strvalue);
  851.         log_err(msg);
  852.  
  853.     }
  854.     else {
  855.         send_pwack(authreq, activefd);
  856.     }
  857.     pairfree(authreq->request);
  858.     pairfree(user_check);
  859.     pairfree(user_reply);
  860.     memset(authreq, 0, sizeof(AUTH_REQ));
  861.     free(authreq);
  862.     return;
  863. }
  864.  
  865. /*************************************************************************
  866.  *
  867.  *    Function: rad_authenticate
  868.  *
  869.  *    Purpose: Process and reply to an authentication request
  870.  *
  871.  *************************************************************************/
  872.  
  873. rad_authenticate(authreq, activefd)
  874. AUTH_REQ    *authreq;
  875. int        activefd;
  876. {
  877.     VALUE_PAIR    *namepair;
  878.     VALUE_PAIR    *check_item;
  879.     VALUE_PAIR    *auth_item;
  880.     VALUE_PAIR    *user_check;
  881.     VALUE_PAIR    *user_reply;
  882.     int        result;
  883.     char        pw_digest[16];
  884.     char        string[128];
  885.     int        i;
  886.     char        msg[128];
  887.     char        umsg[128];
  888.     char        *user_msg;
  889.     char        *ip_hostname();
  890.     int        retval;
  891.     char        *ptr;
  892.  
  893.     /* Get the username from the request */
  894.     namepair = authreq->request;
  895.     while(namepair != (VALUE_PAIR *)NULL) {
  896.         if(namepair->attribute == PW_USER_NAME) {
  897.             break;
  898.         }
  899.         namepair = namepair->next;
  900.     }
  901.     if((namepair == (VALUE_PAIR *)NULL) || 
  902.        (strlen(namepair->strvalue) <= 0)) {
  903.         sprintf(msg, "Authenticate: from %s - No User Name\n",
  904.             ip_hostname(authreq->ipaddr));
  905.         log_err(msg);
  906.         pairfree(authreq->request);
  907.         memset(authreq, 0, sizeof(AUTH_REQ));
  908.         free(authreq);
  909.         return;
  910.     }
  911.  
  912.     /* Verify the client and Calculate the MD5 Password Digest */
  913.     if(calc_digest(pw_digest, authreq) != 0) {
  914.         /* We dont respond when this fails */
  915.         sprintf(msg, "Authenticate: from %s - Security Breach: %s\n",
  916.             ip_hostname(authreq->ipaddr), namepair->strvalue);
  917.         log_err(msg);
  918.         pairfree(authreq->request);
  919.         memset(authreq, 0, sizeof(AUTH_REQ));
  920.         free(authreq);
  921.         return;
  922.     }
  923.  
  924.     /* Get the user from the database */
  925.     if(user_find(namepair->strvalue, &user_check, &user_reply) != 0) {
  926.         sprintf(msg, "Authenticate: from %s - Invalid User: %s\n",
  927.             ip_hostname(authreq->ipaddr), namepair->strvalue);
  928.         log_err(msg);
  929.         send_reject(authreq, (char *)NULL, activefd);
  930.         pairfree(authreq->request);
  931.         memset(authreq, 0, sizeof(AUTH_REQ));
  932.         free(authreq);
  933.         return;
  934.     }
  935.  
  936.     /* Validate the user */
  937.  
  938.     /* Look for matching check items */
  939.     result = 0;
  940.     user_msg = (char *)NULL;
  941.     check_item = user_check;
  942.     while(result == 0 && check_item != (VALUE_PAIR *)NULL) {
  943.  
  944.         /*
  945.          * Check expiration date if we are doing password aging.
  946.          */
  947.         if(check_item->attribute == PW_EXPIRATION) {
  948.             /* Has this user's password expired */
  949.             retval = pw_expired(check_item->lvalue);
  950.             if(retval < 0) {
  951.                 result = -1;
  952.                 user_msg = "Password Has Expired\r\n";
  953.             }
  954.             else {
  955.                 if(retval > 0) {
  956.                     sprintf(umsg,
  957.                       "Password Will Expire in %d Days\r\n",
  958.                       retval);
  959.                     user_msg = umsg;
  960.                 }
  961.                 check_item = check_item->next;
  962.             }
  963.             continue;
  964.         }
  965.  
  966.         /*
  967.          * Look for the matching attribute in the request.
  968.          */
  969.         auth_item = authreq->request;
  970.         while(auth_item != (VALUE_PAIR *)NULL) {
  971.             if(check_item->attribute == auth_item->attribute) {
  972.                 break;
  973.             }
  974.             if(check_item->attribute == PW_PASSWORD &&
  975.                      auth_item->attribute == PW_CHAP_PASSWORD) {
  976.                 break;
  977.             }
  978.  
  979.             auth_item = auth_item->next;
  980.         }
  981.         if(auth_item == (VALUE_PAIR *)NULL) {
  982.             result = -1;
  983.             continue;
  984.         }
  985.  
  986.         /*
  987.          * Special handling for passwords which are encrypted,
  988.          * and sometimes authenticated against the UNIX passwd database.
  989.          * Also they can come using the Three-Way CHAP.
  990.          *
  991.          */
  992.         if(check_item->attribute == PW_PASSWORD) {
  993.             if(auth_item->attribute == PW_CHAP_PASSWORD) {
  994.                 /* Use MD5 to verify */
  995.                 ptr = string;
  996.                 *ptr++ = *auth_item->strvalue;
  997.                 strcpy(ptr, check_item->strvalue);
  998.                 ptr += strlen(check_item->strvalue);
  999.                 memcpy(ptr, authreq->vector, AUTH_VECTOR_LEN);
  1000.                 md5_calc(pw_digest, string,
  1001.                     1 + CHAP_VALUE_LENGTH +
  1002.                     strlen(check_item->strvalue));
  1003.                 /* Compare them */
  1004.                 if(memcmp(pw_digest, auth_item->strvalue + 1,
  1005.                         CHAP_VALUE_LENGTH) != 0) {
  1006.                     result = -1;
  1007.                 }
  1008.             }
  1009.             else {
  1010.                 /* Decrypt the password */
  1011.                 memcpy(string,
  1012.                     auth_item->strvalue, AUTH_PASS_LEN);
  1013.                 for(i = 0;i < AUTH_PASS_LEN;i++) {
  1014.                     string[i] ^= pw_digest[i];
  1015.                 }
  1016.                 string[AUTH_PASS_LEN] = '\0';
  1017.                 /* Test Code for Challenge */
  1018.                 if(strcmp(string, "challenge") == 0) {
  1019.                     send_challenge(authreq, 
  1020.                 "You want me to challenge you??\r\nOkay I will",
  1021.                         "1",activefd);
  1022.                     pairfree(authreq->request);
  1023.                     memset(authreq, 0, sizeof(AUTH_REQ));
  1024.                     free(authreq);
  1025.                     return;
  1026.                 }
  1027.                 if(strcmp(check_item->strvalue, "UNIX") == 0) {
  1028.                     if(unix_pass(namepair->strvalue,
  1029.                                 string) != 0) {
  1030.                         result = -1;
  1031.                         user_msg = (char *)NULL;
  1032.                     }
  1033.                 }
  1034.                 else if(strcmp(check_item->strvalue,
  1035.                                 string) != 0) {
  1036.                     result = -1;
  1037.                     user_msg = (char *)NULL;
  1038.                 }
  1039.             }
  1040.         }
  1041.         else {
  1042.             switch(check_item->type) {
  1043.  
  1044.             case PW_TYPE_STRING:
  1045.                 if(strcmp(check_item->strvalue,
  1046.                         auth_item->strvalue) != 0) {
  1047.                     result = -1;
  1048.                 }
  1049.                 break;
  1050.  
  1051.             case PW_TYPE_INTEGER:
  1052.             case PW_TYPE_IPADDR:
  1053.                 if(check_item->lvalue != auth_item->lvalue) {
  1054.                     result = -1;
  1055.                 }
  1056.                 break;
  1057.  
  1058.             default:
  1059.                 result = -1;
  1060.                 break;
  1061.             }
  1062.         }
  1063.         check_item = check_item->next;
  1064.     }
  1065.     if(result != 0) {
  1066.         send_reject(authreq, user_msg, activefd);
  1067.     }
  1068.     else {
  1069.         send_accept(authreq, user_reply, user_msg, activefd);
  1070.     }
  1071.     pairfree(authreq->request);
  1072.     memset(authreq, 0, sizeof(AUTH_REQ));
  1073.     free(authreq);
  1074.     pairfree(user_check);
  1075.     pairfree(user_reply);
  1076.     return;
  1077. }
  1078.  
  1079. /*************************************************************************
  1080.  *
  1081.  *    Function: send_reject
  1082.  *
  1083.  *    Purpose: Reply to the request with a REJECT.  Also attach
  1084.  *         any user message provided.
  1085.  *
  1086.  *************************************************************************/
  1087.  
  1088. send_reject(authreq, msg, activefd)
  1089. AUTH_REQ    *authreq;
  1090. char        *msg;
  1091. int        activefd;
  1092. {
  1093.     AUTH_HDR        *auth;
  1094.     struct    sockaddr    saremote;
  1095.     struct    sockaddr_in    *sin;
  1096.     char            *ip_hostname();
  1097.     char            digest[AUTH_VECTOR_LEN];
  1098.     int            secretlen;
  1099.     int            total_length;
  1100.     u_char            *ptr;
  1101.     int            len;
  1102.  
  1103.     auth = (AUTH_HDR *)send_buffer;
  1104.  
  1105.     /* Build standard response header */
  1106.     if(authreq->code == PW_PASSWORD_REQUEST) {
  1107.         auth->code = PW_PASSWORD_REJECT;
  1108.     }
  1109.     else {
  1110.         auth->code = PW_AUTHENTICATION_REJECT;
  1111.     }
  1112.     auth->id = authreq->id;
  1113.     memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
  1114.     total_length = AUTH_HDR_LEN;
  1115.  
  1116.     /* Append the user message */
  1117.     if(msg != (char *)NULL) {
  1118.         len = strlen(msg);
  1119.         if(len > 0 && len < AUTH_STRING_LEN) {
  1120.             ptr = auth->data;
  1121.             *ptr++ = PW_PORT_MESSAGE;
  1122.             *ptr++ = len + 2;
  1123.             memcpy(ptr, msg, len);
  1124.             ptr += len;
  1125.             total_length += len + 2;
  1126.         }
  1127.     }
  1128.  
  1129.     /* Set total length in the header */
  1130.     auth->length = htons(total_length);
  1131.  
  1132.     /* Calculate the response digest */
  1133.     secretlen = strlen(authreq->secret);
  1134.     memcpy(send_buffer + total_length, authreq->secret, secretlen);
  1135.     md5_calc(digest, (char *)auth, total_length + secretlen);
  1136.     memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  1137.     memset(send_buffer + total_length, 0, secretlen);
  1138.  
  1139.     sin = (struct sockaddr_in *) &saremote;
  1140.         memset ((char *) sin, '\0', sizeof (saremote));
  1141.     sin->sin_family = AF_INET;
  1142.     sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  1143.     sin->sin_port = htons(authreq->udp_port);
  1144.  
  1145.     DEBUG("Sending Reject of id %d to %lx (%s)\n",
  1146.         authreq->id, (u_long)authreq->ipaddr,
  1147.         ip_hostname(authreq->ipaddr));
  1148.     
  1149.     /* Send it to the user */
  1150.     sendto(activefd, (char *)auth, (int)total_length, (int)0,
  1151.             (struct sockaddr *) &saremote, sizeof(struct sockaddr_in));
  1152. }
  1153.  
  1154. /*************************************************************************
  1155.  *
  1156.  *    Function: send_challenge
  1157.  *
  1158.  *    Purpose: Reply to the request with a CHALLENGE.  Also attach
  1159.  *         any user message provided and a state value.
  1160.  *
  1161.  *************************************************************************/
  1162.  
  1163. send_challenge(authreq, msg, state, activefd)
  1164. AUTH_REQ    *authreq;
  1165. char        *msg;
  1166. char        *state;
  1167. int        activefd;
  1168. {
  1169.     AUTH_HDR        *auth;
  1170.     struct    sockaddr_in    saremote;
  1171.     struct    sockaddr_in    *sin;
  1172.     char            *ip_hostname();
  1173.     char            digest[AUTH_VECTOR_LEN];
  1174.     int            secretlen;
  1175.     int            total_length;
  1176.     u_char            *ptr;
  1177.     int            len;
  1178.  
  1179.     auth = (AUTH_HDR *)send_buffer;
  1180.  
  1181.     /* Build standard response header */
  1182.     auth->code = PW_ACCESS_CHALLENGE;
  1183.     auth->id = authreq->id;
  1184.     memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
  1185.     total_length = AUTH_HDR_LEN;
  1186.  
  1187.     /* Append the user message */
  1188.     if(msg != (char *)NULL) {
  1189.         len = strlen(msg);
  1190.         if(len > 0 && len < AUTH_STRING_LEN) {
  1191.             ptr = auth->data;
  1192.             *ptr++ = PW_PORT_MESSAGE;
  1193.             *ptr++ = len + 2;
  1194.             memcpy(ptr, msg, len);
  1195.             ptr += len;
  1196.             total_length += len + 2;
  1197.         }
  1198.     }
  1199.  
  1200.     /* Append the state info */
  1201.     if((state != (char *)NULL) && (strlen(state) > 0)) {
  1202.         len = strlen(state);
  1203.         *ptr++ = PW_STATE;
  1204.         *ptr++ = len + 2;
  1205.         memcpy(ptr, state, len);
  1206.         ptr += len;
  1207.         total_length += len + 2;
  1208.     }
  1209.  
  1210.     /* Set total length in the header */
  1211.     auth->length = htons(total_length);
  1212.  
  1213.     /* Calculate the response digest */
  1214.     secretlen = strlen(authreq->secret);
  1215.     memcpy(send_buffer + total_length, authreq->secret, secretlen);
  1216.     md5_calc(digest, (char *)auth, total_length + secretlen);
  1217.     memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  1218.     memset(send_buffer + total_length, 0, secretlen);
  1219.  
  1220.     sin = (struct sockaddr_in *) &saremote;
  1221.         memset ((char *) sin, '\0', sizeof (saremote));
  1222.     sin->sin_family = AF_INET;
  1223.     sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  1224.     sin->sin_port = htons(authreq->udp_port);
  1225.  
  1226.     DEBUG("Sending Challenge of id %d to %lx (%s)\n",
  1227.         authreq->id, (u_long)authreq->ipaddr,
  1228.         ip_hostname(authreq->ipaddr));
  1229.     
  1230.     /* Send it to the user */
  1231.     sendto(activefd, (char *)auth, (int)total_length, (int)0,
  1232.             (struct sockaddr *) &saremote, sizeof(struct sockaddr_in));
  1233. }
  1234.  
  1235. /*************************************************************************
  1236.  *
  1237.  *    Function: send_pwack
  1238.  *
  1239.  *    Purpose: Reply to the request with an ACKNOWLEDGE.
  1240.  *         User password has been successfully changed.
  1241.  *
  1242.  *************************************************************************/
  1243.  
  1244. send_pwack(authreq, activefd)
  1245. AUTH_REQ    *authreq;
  1246. int        activefd;
  1247. {
  1248.     AUTH_HDR        *auth;
  1249.     struct    sockaddr    saremote;
  1250.     struct    sockaddr_in    *sin;
  1251.     char            *ip_hostname();
  1252.     char            digest[AUTH_VECTOR_LEN];
  1253.     int            secretlen;
  1254.  
  1255.     auth = (AUTH_HDR *)send_buffer;
  1256.  
  1257.     /* Build standard response header */
  1258.     auth->code = PW_PASSWORD_ACK;
  1259.     auth->id = authreq->id;
  1260.     memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
  1261.     auth->length = htons(AUTH_HDR_LEN);
  1262.  
  1263.     /* Calculate the response digest */
  1264.     secretlen = strlen(authreq->secret);
  1265.     memcpy(send_buffer + AUTH_HDR_LEN, authreq->secret, secretlen);
  1266.     md5_calc(digest, (char *)auth, AUTH_HDR_LEN + secretlen);
  1267.     memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  1268.     memset(send_buffer + AUTH_HDR_LEN, 0, secretlen);
  1269.  
  1270.     sin = (struct sockaddr_in *) &saremote;
  1271.         memset ((char *) sin, '\0', sizeof (saremote));
  1272.     sin->sin_family = AF_INET;
  1273.     sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  1274.     sin->sin_port = htons(authreq->udp_port);
  1275.  
  1276.     DEBUG("Sending PW Ack of id %d to %lx (%s)\n",
  1277.         authreq->id, (u_long)authreq->ipaddr,
  1278.         ip_hostname(authreq->ipaddr));
  1279.     
  1280.     /* Send it to the user */
  1281.     sendto(activefd, (char *)auth, (int)AUTH_HDR_LEN, (int)0,
  1282.             &saremote, sizeof(struct sockaddr_in));
  1283. }
  1284.  
  1285. /*************************************************************************
  1286.  *
  1287.  *    Function: send_accept
  1288.  *
  1289.  *    Purpose: Reply to the request with an ACKNOWLEDGE.  Also attach
  1290.  *         reply attribute value pairs and any user message provided.
  1291.  *
  1292.  *************************************************************************/
  1293.  
  1294. send_accept(authreq, reply, msg, activefd)
  1295. AUTH_REQ    *authreq;
  1296. VALUE_PAIR    *reply;
  1297. char        *msg;
  1298. int        activefd;
  1299. {
  1300.     AUTH_HDR        *auth;
  1301.     u_short            total_length;
  1302.     struct    sockaddr    saremote;
  1303.     struct    sockaddr_in    *sin;
  1304.     u_char            *ptr;
  1305.     int            len;
  1306.     UINT4            lvalue;
  1307.     u_char            digest[16];
  1308.     int            secretlen;
  1309.     char            *ip_hostname();
  1310.  
  1311.     auth = (AUTH_HDR *)send_buffer;
  1312.  
  1313.     /* Build standard header */
  1314.     auth->code = PW_AUTHENTICATION_ACK;
  1315.     auth->id = authreq->id;
  1316.     memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);
  1317.  
  1318.     DEBUG("Sending Ack of id %d to %lx (%s)\n",
  1319.         authreq->id, (u_long)authreq->ipaddr,
  1320.         ip_hostname(authreq->ipaddr));
  1321.  
  1322.     total_length = AUTH_HDR_LEN;
  1323.  
  1324.     /* Load up the configuration values for the user */
  1325.     ptr = auth->data;
  1326.     while(reply != (VALUE_PAIR *)NULL) {
  1327.         debug_pair(stdout, reply);
  1328.         *ptr++ = reply->attribute;
  1329.  
  1330.         switch(reply->type) {
  1331.  
  1332.         case PW_TYPE_STRING:
  1333.             len = strlen(reply->strvalue);
  1334.             if (len >= AUTH_STRING_LEN) {
  1335.                 len = AUTH_STRING_LEN - 1;
  1336.             }
  1337.             *ptr++ = len + 2;
  1338.             memcpy(ptr, reply->strvalue,len);
  1339.             ptr += len;
  1340.             total_length += len + 2;
  1341.             break;
  1342.             
  1343.         case PW_TYPE_INTEGER:
  1344.         case PW_TYPE_IPADDR:
  1345.             *ptr++ = sizeof(UINT4) + 2;
  1346.             lvalue = htonl(reply->lvalue);
  1347.             memcpy(ptr, &lvalue, sizeof(UINT4));
  1348.             ptr += sizeof(UINT4);
  1349.             total_length += sizeof(UINT4) + 2;
  1350.             break;
  1351.  
  1352.         default:
  1353.             break;
  1354.         }
  1355.  
  1356.         reply = reply->next;
  1357.     }
  1358.  
  1359.     /* Append the user message */
  1360.     if(msg != (char *)NULL) {
  1361.         len = strlen(msg);
  1362.         if(len > 0 && len < AUTH_STRING_LEN) {
  1363.             *ptr++ = PW_PORT_MESSAGE;
  1364.             *ptr++ = len + 2;
  1365.             memcpy(ptr, msg, len);
  1366.             ptr += len;
  1367.             total_length += len + 2;
  1368.         }
  1369.     }
  1370.  
  1371.     auth->length = htons(total_length);
  1372.  
  1373.     /* Append secret and calculate the response digest */
  1374.     secretlen = strlen(authreq->secret);
  1375.     memcpy(send_buffer + total_length, authreq->secret, secretlen);
  1376.     md5_calc(digest, (char *)auth, total_length + secretlen);
  1377.     memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
  1378.     memset(send_buffer + total_length, 0, secretlen);
  1379.  
  1380.     sin = (struct sockaddr_in *) &saremote;
  1381.         memset ((char *) sin, '\0', sizeof (saremote));
  1382.     sin->sin_family = AF_INET;
  1383.     sin->sin_addr.s_addr = htonl(authreq->ipaddr);
  1384.     sin->sin_port = htons(authreq->udp_port);
  1385.  
  1386.     /* Send it to the user */
  1387.     sendto(activefd, (char *)auth, (int)total_length, (int)0,
  1388.             &saremote, sizeof(struct sockaddr_in));
  1389. }
  1390.  
  1391. /*************************************************************************
  1392.  *
  1393.  *    Function: unix_pass
  1394.  *
  1395.  *    Purpose: Check the users password against the standard UNIX
  1396.  *         password table.
  1397.  *
  1398.  *************************************************************************/
  1399.  
  1400. unix_pass(name, passwd)
  1401. char    *name;
  1402. char    *passwd;
  1403. {
  1404.     struct passwd    *pwd;
  1405.     struct passwd    *getpwnam();
  1406.     char        *encpw;
  1407.     char        *crypt();
  1408.     char        *encrypted_pass;
  1409. #if !defined(NOSHADOW)
  1410. #if defined(M_UNIX)
  1411.     struct passwd    *spwd;
  1412. #else
  1413.     struct spwd    *spwd;
  1414. #endif
  1415. #endif /* !NOSHADOW */
  1416.     
  1417.     /* Get encrypted password from password file */
  1418.     if((pwd = getpwnam(name)) == NULL) {
  1419.         return(-1);
  1420.     }
  1421.  
  1422.     encrypted_pass = pwd->pw_passwd;
  1423.  
  1424. #if !defined(NOSHADOW)
  1425.     if(strcmp(pwd->pw_passwd, "x") == 0) {
  1426.         if((spwd = getspnam(name)) == NULL) {
  1427.             return(-1);
  1428.         }
  1429. #if defined(M_UNIX)
  1430.         encrypted_pass = spwd->pw_passwd;
  1431. #else
  1432.         encrypted_pass = spwd->sp_pwdp;
  1433. #endif    /* M_UNIX */
  1434.     }
  1435. #endif    /* !NOSHADOW */
  1436.  
  1437.     /* Run encryption algorythm */
  1438.     encpw = crypt(passwd, encrypted_pass);
  1439.  
  1440.     /* Check it */
  1441.     if(strcmp(encpw, encrypted_pass)) {
  1442.         return(-1);
  1443.     }
  1444.     return(0);
  1445. }
  1446.  
  1447. /*************************************************************************
  1448.  *
  1449.  *    Function: calc_digest
  1450.  *
  1451.  *    Purpose: Validates the requesting client NAS.  Calculates the
  1452.  *         digest to be used for decrypting the users password
  1453.  *         based on the clients private key.
  1454.  *
  1455.  *************************************************************************/
  1456.  
  1457. calc_digest(digest, authreq)
  1458. u_char        *digest;
  1459. AUTH_REQ    *authreq;
  1460. {
  1461.     FILE    *clientfd;
  1462.     u_char    buffer[128];
  1463.     u_char    secret[64];
  1464.     char    hostnm[256];
  1465.     char    msg[128];
  1466.     char    *ip_hostname();
  1467.     int    secretlen;
  1468.     UINT4    ipaddr;
  1469.     UINT4    get_ipaddr();
  1470.  
  1471.     /* Find the client in the database */
  1472.     sprintf(buffer, "%s/%s", radius_dir, RADIUS_CLIENTS);
  1473.     if((clientfd = fopen(buffer, "r")) == (FILE *)NULL) {
  1474.         fprintf(stderr, "%s: couldn't open %s to find clients\n",
  1475.                 progname, buffer);
  1476.         return(-1);
  1477.     }
  1478.     ipaddr = (UINT4)0;
  1479.     while(fgets(buffer, sizeof(buffer), clientfd) != (char *)NULL) {
  1480.         if(*buffer == '#') {
  1481.             continue;
  1482.         }
  1483.         if(sscanf(buffer, "%s%s", hostnm, secret) != 2) {
  1484.             continue;
  1485.         }
  1486.         ipaddr = get_ipaddr(hostnm);
  1487.         if(ipaddr == authreq->ipaddr) {
  1488.             break;
  1489.         }
  1490.     }
  1491.     fclose(clientfd);
  1492.     memset(buffer, 0, sizeof(buffer));
  1493.  
  1494.     /*
  1495.      * Validate the requesting IP address -
  1496.      * Not secure, but worth the check for accidental requests
  1497.      */
  1498.     if(ipaddr != authreq->ipaddr) {
  1499.         strcpy(hostnm,ip_hostname(ipaddr));
  1500.         sprintf(msg, "requester address mismatch: %s != %s\n",
  1501.             hostnm,
  1502.             ip_hostname(authreq->ipaddr));
  1503.         log_err(msg);
  1504.         memset(secret, 0, sizeof(secret));
  1505.         return(-1);
  1506.     }
  1507.  
  1508.     /* Use the secret to setup the decryption digest */
  1509.     secretlen = strlen(secret);
  1510.     strcpy(buffer, secret);
  1511.     memcpy(buffer + secretlen, authreq->vector, AUTH_VECTOR_LEN);
  1512.     md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN);
  1513.     strcpy(authreq->secret, secret);
  1514.     memset(buffer, 0, sizeof(buffer));
  1515.     memset(secret, 0, sizeof(secret));
  1516.     return(0);
  1517. }
  1518.  
  1519. /*************************************************************************
  1520.  *
  1521.  *    Function: debug_pair
  1522.  *
  1523.  *    Purpose: Print the Attribute-value pair to the desired File.
  1524.  *
  1525.  *************************************************************************/
  1526.  
  1527. debug_pair(fd, pair)
  1528. FILE        *fd;
  1529. VALUE_PAIR    *pair;
  1530. {
  1531.     if(debug_flag) {
  1532.         fputs("    ", fd);
  1533.         fprint_attr_val(fd, pair);
  1534.         fputs("\n", fd);
  1535.     }
  1536. }
  1537.  
  1538. /*************************************************************************
  1539.  *
  1540.  *    Function: usage
  1541.  *
  1542.  *    Purpose: Display the syntax for starting this program.
  1543.  *
  1544.  *************************************************************************/
  1545.  
  1546. usage()
  1547. {
  1548.     fprintf(stderr, "Usage: %s [ -a acct_dir ] [ -s ] [ -x ] [ -d db_dir ]\n",progname);
  1549.     exit(-1);
  1550. }
  1551.  
  1552. /*************************************************************************
  1553.  *
  1554.  *    Function: log_err
  1555.  *
  1556.  *    Purpose: Log the error message provided to the error log with
  1557.          a time stamp.
  1558.  *
  1559.  *************************************************************************/
  1560.  
  1561. log_err(msg)
  1562. char    *msg;
  1563. {
  1564.     FILE    *msgfd;
  1565.     char    buffer[128];
  1566.     time_t    timeval;
  1567.  
  1568.     sprintf(buffer, "%s/%s", radius_dir, RADIUS_LOG);
  1569.     if((msgfd = fopen(buffer, "a")) == (FILE *)NULL) {
  1570.         fprintf(stderr, "%s:Couldn't open %s for logging\n",
  1571.                 progname, buffer);
  1572.         return(-1);
  1573.     }
  1574.     timeval = time(0);
  1575.     fprintf(msgfd, "%-24.24s: %s", ctime(&timeval), msg);
  1576.     fclose(msgfd);
  1577.     return(0);
  1578. }
  1579.  
  1580. /*************************************************************************
  1581.  *
  1582.  *    Function: config_init
  1583.  *
  1584.  *    Purpose: intializes configuration values:
  1585.  *
  1586.  *         expiration_seconds - When updating a user password,
  1587.  *            the amount of time to add to the current time
  1588.  *            to set the time when the password will expire.
  1589.  *            This is stored as the VALUE Password-Expiration
  1590.  *            in the dictionary as number of days.
  1591.  *
  1592.  *        warning_seconds - When acknowledging a user authentication
  1593.  *            time remaining for valid password to notify user
  1594.  *            of password expiration.
  1595.  *
  1596.  *************************************************************************/
  1597.  
  1598. config_init()
  1599. {
  1600.     DICT_VALUE    *dval;
  1601.     DICT_VALUE    *dict_valfind();
  1602.  
  1603.     if((dval = dict_valfind("Password-Expiration")) == (DICT_VALUE *)NULL) {
  1604.         expiration_seconds = (UINT4)0;
  1605.     }
  1606.     else {
  1607.         expiration_seconds = dval->value * (UINT4)SECONDS_PER_DAY;
  1608.     }
  1609.     if((dval = dict_valfind("Password-Warning")) == (DICT_VALUE *)NULL) {
  1610.         warning_seconds = (UINT4)0;
  1611.     }
  1612.     else {
  1613.         warning_seconds = dval->value * (UINT4)SECONDS_PER_DAY;
  1614.     }
  1615.     return(0);
  1616. }
  1617.  
  1618. /*************************************************************************
  1619.  *
  1620.  *    Function: set_expiration
  1621.  *
  1622.  *    Purpose: Set the new expiration time by updating or adding
  1623.          the Expiration attribute-value pair.
  1624.  *
  1625.  *************************************************************************/
  1626.  
  1627. set_expiration(user_check, expiration)
  1628. VALUE_PAIR    *user_check;
  1629. UINT4        expiration;
  1630. {
  1631.     VALUE_PAIR    *exppair;
  1632.     VALUE_PAIR    *prev;
  1633.     struct timeval    tp;
  1634.     struct timezone    tzp;
  1635.  
  1636.     if(user_check == (VALUE_PAIR *)NULL) {
  1637.         return(-1);
  1638.     }
  1639.  
  1640.     /* Look for an existing expiration entry */
  1641.     exppair = user_check;
  1642.     prev = (VALUE_PAIR *)NULL;
  1643.     while(exppair != (VALUE_PAIR *)NULL) {
  1644.         if(exppair->attribute == PW_EXPIRATION) {
  1645.             break;
  1646.         }
  1647.         prev = exppair;
  1648.         exppair = exppair->next;
  1649.     }
  1650.     if(exppair == (VALUE_PAIR *)NULL) {
  1651.         /* Add a new attr-value pair */
  1652.         if((exppair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
  1653.                     (VALUE_PAIR *)NULL) {
  1654.             fprintf(stderr, "%s: no memory\n", progname);
  1655.             exit(-1);
  1656.         }
  1657.         /* Initialize it */
  1658.         strcpy(exppair->name, "Expiration");
  1659.         exppair->attribute = PW_EXPIRATION;
  1660.         exppair->type = PW_TYPE_DATE;
  1661.         *exppair->strvalue = '\0';
  1662.         exppair->lvalue = (UINT4)0;
  1663.         exppair->next = (VALUE_PAIR *)NULL;
  1664.  
  1665.         /* Attach it to the list. */
  1666.         prev->next = exppair;
  1667.     }
  1668.  
  1669.     /* calculate a new expiration */
  1670.     gettimeofday(&tp, &tzp);
  1671.     exppair->lvalue = tp.tv_sec + expiration;
  1672.     return(0);
  1673. }
  1674.  
  1675. /*************************************************************************
  1676.  *
  1677.  *    Function: pw_expired
  1678.  *
  1679.  *    Purpose: Tests to see if the users password has expired.
  1680.  *
  1681.  *    Return: Number of days before expiration if a warning is required
  1682.  8        otherwise 0 for success and -1 for failure.
  1683.  *
  1684.  *************************************************************************/
  1685.  
  1686. pw_expired(exptime)
  1687. UINT4    exptime;
  1688. {
  1689.     struct timeval    tp;
  1690.     struct timezone    tzp;
  1691.     UINT4        exp_remain;
  1692.     int        exp_remain_int;
  1693.  
  1694.     if(expiration_seconds == (UINT4)0) {
  1695.         return(0);
  1696.     }
  1697.  
  1698.     gettimeofday(&tp, &tzp);
  1699.     if(tp.tv_sec > exptime) {
  1700.         return(-1);
  1701.     }
  1702.     if(warning_seconds != (UINT4)0) {
  1703.         if(tp.tv_sec > exptime - warning_seconds) {
  1704.             exp_remain = exptime - tp.tv_sec;
  1705.             exp_remain /= (UINT4)SECONDS_PER_DAY;
  1706.             exp_remain_int = exp_remain;
  1707.             return(exp_remain_int);
  1708.         }
  1709.     }
  1710.     return(0);
  1711. }
  1712.  
  1713. void
  1714. sig_fatal(sig)
  1715. int    sig;
  1716. {
  1717.     if(acct_pid > 0) {
  1718.         kill(acct_pid, SIGKILL);
  1719.     }
  1720.  
  1721.     fprintf(stderr, "%s: exit on signal (%d)\n", progname, sig);
  1722.     fflush(stderr);
  1723.     exit(1);
  1724. }
  1725.  
  1726. void
  1727. sig_hup(sig)
  1728. int    sig;
  1729. {
  1730.     return;
  1731. }
  1732.