Logo Search packages:      
Sourcecode: netams version File versions  Download package

rlm_netams.c

/*************************************************************************
***   Authentication, authorization, accounting + firewalling package
***   Copyright 1998-2002 Anton Vinokurov <anton@netams.com>
***   Copyright 2002-2008 NeTAMS Development Team
***   This code is GPL v3
***   For latest version and more info, visit this project web page
***   located at http://www.netams.com
***
*** Code netams taken from rlm_netams.c, 
*** (c) 2000  The FreeRADIUS server project
*************************************************************************/
/* $Id: rlm_netams.c,v 1.20 2008-02-23 08:35:05 anton Exp $ */

#include "autoconf.h"
#include "libradius.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

#include "radiusd.h"
#include "modules.h"
#include "conffile.h"

typedef struct rlm_netams_t {
      char *login;
      char *password;
      char *server;
      int port;
      char *defaultpolicy;
      char *swap_inout;
      char *billing_login;    

      FILE *fd;
      int socket;
      char buffer[1024];
} rlm_netams_t;
static int netams_connect_daemon(rlm_netams_t *data);

static CONF_PARSER module_config[] = {
  { "login",  PW_TYPE_STRING_PTR, offsetof(rlm_netams_t,login), NULL,  "admin"},
  { "password",  PW_TYPE_STRING_PTR, offsetof(rlm_netams_t,password), NULL,  "aaa"},
  { "server",  PW_TYPE_STRING_PTR, offsetof(rlm_netams_t,server), NULL,  "localhost"},
  { "port", PW_TYPE_INTEGER,    offsetof(rlm_netams_t,port), NULL,   "20001" },
  { "defaultpolicy", PW_TYPE_STRING_PTR,    offsetof(rlm_netams_t,defaultpolicy), NULL,  NULL },
  { "swap-inout",  PW_TYPE_STRING_PTR, offsetof(rlm_netams_t,swap_inout), NULL,  "yes"},
  { "billing-login", PW_TYPE_STRING_PTR, offsetof(rlm_netams_t,billing_login), NULL, "no"},
  { NULL, -1, 0, NULL, NULL }       /* end the list */
};

static int netams_connect_daemon(rlm_netams_t *data){
      
      struct sockaddr_in addr;
      struct hostent *hp;
      int i;
      char buffer[1024];
      
      DEBUG2("rlm_netams: connecting to daemon...");
      
      if ((data->socket=socket(AF_INET,SOCK_STREAM,0))==-1 )return -1;

      bzero(&addr, sizeof(addr));
      addr.sin_family=AF_INET;
      hp=gethostbyname(data->server);
      if(!hp) { DEBUG2("rlm_netams: gethostbyname failed "); return(-1); }
      
      memcpy((char*)&addr.sin_addr, hp->h_addr_list[0], hp->h_length);
      addr.sin_port=htons((unsigned short)(data->port));
      
      if ((i=connect(data->socket, (struct sockaddr*)&addr, sizeof(addr)))) { DEBUG2("rlm_netams: Connect failed. Possibly NeTAMS is not running?\n"); return -1; }

      data->fd = fdopen(data->socket, "w+");
      setvbuf(data->fd, NULL, _IONBF, 0);
      if (data->fd==NULL) { DEBUG2("rlm_netams: fdopen of server socket() failed\n"); return -1; } 

      /* Login to NETAMS */
      fgets(buffer, 1023, data->fd); // printf("got: %s", buffer); 
      fgets(buffer, 1023, data->fd); // printf("got: %s", buffer); 
      bzero(buffer, 1023); fread(buffer, strlen("Username:"), 1, data->fd); 
      fprintf(data->fd, "%s\r\n", data->login); fflush(data->fd);                                            
      bzero(buffer, 1023); fread(buffer, strlen(data->login)+3, 1, data->fd);
      bzero(buffer, 1023); fread(buffer, 9, 1, data->fd);
      if (strncmp(buffer, "Password:", 9)!=0) { DEBUG2("rlm_netams: login failed\n"); return -1; }

      fprintf(data->fd, "%s\r\n", data->password); fflush(data->fd);
      fgets(buffer, 4*1024, data->fd);
      fgets(buffer, 4*1024, data->fd);  
      bzero(buffer, 1023); fread(buffer, 1, 1, data->fd); 
      if (buffer[0]!='>') { DEBUG2("rlm_netams: login: failed (hung daemon?)\n"); shutdown(data->socket, SHUT_RDWR); close(data->socket); return(-1); }

      DEBUG2("rlm_netams: connected.");
      return 0;
      }
      
static int netams_instantiate(CONF_SECTION *conf, void **instance)
{
      /* allocate instance structure and parse config */
      rlm_netams_t *data;
      int i;
      data = rad_malloc(sizeof(*data));
      if (!data) return -1;
      memset(data, 0, sizeof(*data));
      if (cf_section_parse(conf, data, module_config) < 0) {      free(data); return -1; }

      i=netams_connect_daemon(data);
      if (i) DEBUG("rlm_netams: initial connect to daemon failed, will try later\n");
      
      *instance = data;
      return 0;
}

/*    Find the named user in this modules database.  Create the set
 *    of attribute-value pairs to check and reply with for this user
 *    from the database. The authentication code only needs to check
 *    the password, the rest is done here.
 */
static int netams_authorize(void *instance, REQUEST *request)
{
      VALUE_PAIR *reply;
      VALUE_PAIR *vp;
      VALUE_PAIR *user_password=NULL;
      rlm_netams_t *data=instance;
      char *nas=NULL;
      char *nas_ip=NULL;
      char *callback=NULL;
      int web_auth=0;
      int i, j, k, code, prev=10;
      char *login_type;

  if (strcasecmp(data->billing_login, "yes")==0) login_type="account"; else login_type="login"; 
      user_password = pairfind(request->packet->vps, PW_PASSWORD);

      if (!user_password) { DEBUG("rlm_netams: authorize attempt by \"%s\" with no plain password", request->username->strvalue); }
      else { DEBUG("rlm_netams: authorize attempt by \"%s\" with password %s", request->username->strvalue, user_password->strvalue); }
      
      if (strlen(request->username->strvalue)==0) return RLM_MODULE_INVALID;
      else {
            // make a request string for netams
            bzero(data->buffer, 1023);
            
            if ((vp = pairfind(request->packet->vps, PW_NAS_IDENTIFIER)) != NULL) {
                  nas = (char*)malloc(strlen(vp->strvalue)+32);
                  sprintf(nas, " nas-id %s ", vp->strvalue); 
            }

            if ((vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS)) != NULL) {
                  struct in_addr in;
                  in.s_addr = vp->lvalue;
                  nas_ip= (char*)malloc(28);
                  sprintf(nas_ip, " nas-ip %s ", inet_ntoa(in)); 
            }

            if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL) {
                  callback = (char*)malloc(strlen(vp->strvalue)+42);
                  sprintf(callback, " callback-id %s ", vp->strvalue); 
            }

            if ((vp = pairfind(request->packet->vps, PW_SERVICE_TYPE)) != NULL) {
                  if (vp->lvalue==PW_AUTHENTICATE_ONLY) web_auth=1;
            }

/*          for (vp = request->packet->vps; vp; vp = vp->next) {
                  printf("\trlm_netams: VP: name=%s, attribute=%d, value=%s\n", vp->name, vp->attribute, vp->strvalue);
            }
*/                      
                                
            
            if (user_password) { // PAP - send password to daemon
                  if (web_auth) snprintf(data->buffer, 1023, "radius auth web %s \"%s\" password \"%s\"%s",login_type, request->username->strvalue, user_password->strvalue, nas?nas:" ");
                  else snprintf(data->buffer, 1023, "radius auth nas %s \"%s\" password \"%s\"%s%s%s",login_type, request->username->strvalue, user_password->strvalue, nas?nas:" ", nas_ip?nas_ip:"", callback?callback:" ");
            }
            else { // CHAP or other - don't send password to daemon, instead, expect to get it
                  snprintf(data->buffer, 1023, "radius auth nas %s \"%s\" %s%s",login_type, request->username->strvalue, nas?nas:" ", callback?callback:" ");
            }
            
            if (nas) free(nas);
            if (callback) free(callback);
            
            if (data->fd==NULL) {
                  i=netams_connect_daemon(data);
                  if (i==-1) return RLM_MODULE_INVALID; // we cannot communicate with the daemon
            }

            i=fprintf(data->fd, "%s\r\n", data->buffer);
            if (i==-1 ) { // try to reconnect first
                  i=netams_connect_daemon(data);
                  if (i==-1) return RLM_MODULE_INVALID; // we cannot communicate with the daemon
                  i=fprintf(data->fd, "%s\r\n", data->buffer);
                  if (i==-1) return RLM_MODULE_INVALID; // we cannot communicate with the daemon
            }
            fgets(data->buffer, 4*1024, data->fd); 
      
            fgets(data->buffer, 1023, data->fd); j=strlen(data->buffer); if (j) data->buffer[j-1]=0;
            char *p=strchr(data->buffer, ' ');
            sscanf(data->buffer, "%d", &i);

            DEBUG2("rlm_netams: reply status %d message %s", i, p+1);

            if (i==1) { //success
                  
                  if (user_password) {
                        code=RLM_MODULE_HANDLED;
                        request->reply->code = PW_AUTHENTICATION_ACK;
                  } else 
                        code=RLM_MODULE_OK;

                  sscanf(p+1, "%d", &i);
                  DEBUG2("rlm_netams: lines in reply: %d", i);
                  for (k=1; k<=i; k++) {
                        fgets(data->buffer, 1023, data->fd); j=strlen(data->buffer); if (j) data->buffer[j-2]=0;

                        p=strstr(data->buffer, "Framed-IP-Address: ");
                        if (p) {
                              pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
                              reply = pairmake("Framed-IP-Address", p+19, T_OP_EQ);
                              pairadd(&request->reply->vps, reply);
                        }

                        p=strstr(data->buffer, "Filter-ID: ");
                        if (p) {
                              reply = pairmake("Filter-ID", p+11, T_OP_EQ);
                              pairadd(&request->reply->vps, reply);
                        }

                        p=strstr(data->buffer, "User-Password: "); 
                        if (p && !user_password) { // put plain password onto config_items
                              user_password = paircreate(PW_PASSWORD, PW_TYPE_STRING);
                              strcpy(user_password->strvalue,p+15);
                              user_password->length=strlen(user_password->strvalue);
                              pairadd(&request->config_items,user_password);
                        }

                  }
            }
            else { //failure
                  radlog(L_AUTH, "rlm_netams: auth failed: %s", p);
                  request->reply->code = PW_AUTHENTICATION_REJECT;
                  code=RLM_MODULE_REJECT;
            }

            //drain reply
            while (1) {
                  i=fgetc(data->fd);
                  if (feof(data->fd) || (i=='#' && (prev!=10 && prev!=13) ) || (i=='>' && (prev==10 || prev==13))) break;
                  putchar(i);
                  prev=i;
            }
            return code;
      }

      return RLM_MODULE_NOOP;
}

/*
 *    Authenticate the user with the given password.
 */
static int netams_authenticate(void *instance, REQUEST *request)
{
      /* quiet the compiler */
      instance = instance;
      request = request;

      DEBUG("rlm_netams: authenticate attempt by \"%s\" with password %s", request->username->strvalue, request->password->strvalue);

      return RLM_MODULE_OK;
}

/*
 *    Massage the request before recording it or proxying it
 */
static int netams_preacct(void *instance, REQUEST *request)
{
      /* quiet the compiler */
      instance = instance;
      request = request;

      return RLM_MODULE_OK;
}

/*
 *    Write accounting information to this modules database.
 */
static int netams_accounting(void *instance, REQUEST *request)
{
      VALUE_PAIR *vp;
      rlm_netams_t *data=instance;
      const char *acct_type=NULL;
      int i, j, prev=10;
      int swap_inout=0;
      if (strcasecmp(data->swap_inout, "yes")==0) swap_inout=1;
            
      if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL) {
            switch (vp->lvalue){
                  case PW_STATUS_START: acct_type="start"; break;
                  case PW_STATUS_STOP: acct_type="stop"; break;
                  case PW_STATUS_ALIVE: acct_type="update"; break;
                  }
        }

      if (strlen(request->username->strvalue)==0 || acct_type==NULL) return RLM_MODULE_INVALID;

      DEBUG("rlm_netams: acct %s attempt by \"%s\"", acct_type, request->username->strvalue);
      bzero(data->buffer, 1023);

      sprintf(data->buffer, "radius acct %s login %s", acct_type, request->username->strvalue);

      if ((vp = pairfind(request->packet->vps, PW_NAS_IDENTIFIER)) != NULL) {
            sprintf(data->buffer+strlen(data->buffer), " nas-id %s", vp->strvalue); 
      }

      if ((vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS)) != NULL) {
            struct in_addr in;
            in.s_addr = vp->lvalue;
            sprintf(data->buffer+strlen(data->buffer), " nas-ip %s", inet_ntoa(in)); 
      }

      if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL) {
            struct in_addr in;
            in.s_addr = vp->lvalue;
            sprintf(data->buffer+strlen(data->buffer), " framed-ip %s", inet_ntoa(in)); 
      }
                               
      if ((vp = pairfind(request->packet->vps, PW_FILTER_ID)) != NULL) {
            sprintf(data->buffer+strlen(data->buffer), " policy %s", vp->strvalue); 
      } else if (data->defaultpolicy) {
            sprintf(data->buffer+strlen(data->buffer), " policy %s", data->defaultpolicy); 
      }

      if ((vp = pairfind(request->packet->vps, PW_ACCT_INPUT_OCTETS)) != NULL) {
            sprintf(data->buffer+strlen(data->buffer), " %s %u", swap_inout?"out":"in", vp->lvalue); 
      }

      if ((vp = pairfind(request->packet->vps, PW_ACCT_OUTPUT_OCTETS)) != NULL) {
            sprintf(data->buffer+strlen(data->buffer), " %s %u", swap_inout?"in":"out", vp->lvalue); 
      }

      if (data->fd==NULL) {
            i=netams_connect_daemon(data);
            if (i==-1) return RLM_MODULE_INVALID; // we cannot communicate with the daemon
      }


      DEBUG2("rlm_netams: sending '%s'", data->buffer);
      i=fprintf(data->fd, "%s\r\n", data->buffer);

      if (i==-1 ) { // try to reconnect first
            i=netams_connect_daemon(data);
            if (i==-1) return RLM_MODULE_INVALID; // we cannot communicate with the daemon
            i=fprintf(data->fd, "%s\r\n", data->buffer);
            if (i==-1) return RLM_MODULE_INVALID; // we cannot communicate with the daemon
      }
      fgets(data->buffer, 4*1024, data->fd); 

      fgets(data->buffer, 1023, data->fd); j=strlen(data->buffer); if (j) data->buffer[j-1]=0;
      sscanf(data->buffer, "%d", &i);
      DEBUG2("rlm_netams: reply2 status %d message='%s'", i, data->buffer);

      //drain reply
      while (1) {
            i=fgetc(data->fd);
            if (feof(data->fd) || (i=='#' && (prev!=10 && prev!=13) ) || (i=='>' && (prev==10 || prev==13))) break;
            putchar(i);
            prev=i;
      }
      return RLM_MODULE_OK;

}

/*
 *    See if a user is already logged in. Sets request->simul_count to the
 *    current session count for this user and sets request->simul_mpp to 2
 *    if it looks like a multilink attempt based on the requested IP
 *    address, otherwise leaves request->simul_mpp alone.
 *
 *    Check twice. If on the first pass the user exceeds his
 *    max. number of logins, do a second pass and validate all
 *    logins by querying the terminal server (using eg. SNMP).
 */
static int netams_checksimul(void *instance, REQUEST *request)
{
  instance = instance;

  request->simul_count=0;

  return RLM_MODULE_OK;
}

static int netams_detach(void *instance)
{
      rlm_netams_t *data = (rlm_netams_t *)instance;

      shutdown(data->socket, SHUT_RDWR);
      close(data->socket); 

      free(((struct rlm_netams_t *)instance)->login);
      free(((struct rlm_netams_t *)instance)->password);
      free(((struct rlm_netams_t *)instance)->server);
      free(((struct rlm_netams_t *)instance)->swap_inout);
      if (((struct rlm_netams_t *)instance)->defaultpolicy) free(((struct rlm_netams_t *)instance)->defaultpolicy);
      free(instance);
      return 0;
}

module_t rlm_netams = {
      "netams",
      RLM_TYPE_THREAD_SAFE,         /* type */
      NULL,                         /* initialization */
      netams_instantiate,           /* instantiation */
      {
            netams_authenticate,    /* authentication */
            netams_authorize, /* authorization */
            netams_preacct,   /* preaccounting */
            netams_accounting,      /* accounting */
            netams_checksimul,      /* checksimul */
            NULL,             /* pre-proxy */
            NULL,             /* post-proxy */
            NULL              /* post-auth */
      },
      netams_detach,                /* detach */
      NULL,                   /* destroy */
};

Generated by  Doxygen 1.6.0   Back to index