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

s_login.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
***
*************************************************************************/
/* $Id: s_login.c,v 1.117 2009-08-01 09:23:55 anton Exp $ */

#include "netams.h"

static int initialized=0;
Service *Login=NULL;
//////////////////////////////////////////////////////////////////////////////////////////
void sLgObtainMac(struct in_addr *u, struct ether_addr *current_mac);
int cShowLogin          (struct cli_def *cli, const char *cmd, char **argv, int argc);
void FillLoginData(void *res, void *row, char* (*getRowData)(void*, void* , u_char));
int cLoginSet           (struct cli_def *cli, const char *cmd, char **argv, int argc);
int cLogin              (struct cli_def *cli, const char *cmd, char **argv, int argc);
//////////////////////////////////////////////////////////////////////////////////////////
//defined commands
static const  struct CMD_DB cmd_db[] = {
{ 2, 0, 0, "show",      PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL,        "shows various system parameters" },
{ 0, 2, 0, "login",     PRIVILEGE_UNPRIVILEGED, MODE_EXEC, cShowLogin,        "login status" },
{ 0, 0, 0, "default-inact", PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg, NULL },     
{ 0, 0, 0, "default-abs", PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,   NULL },
{ 0, 0, 0, "max-inact", PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,           NULL },
{ 0, 0, 0, "min-inact", PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,           NULL },
{ 0, 0, 0, "max-abs",   PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,           NULL },
{ 0, 0, 0, "min-abs",   PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,           NULL },
{ 0, 0, 0, "min-passwd-length", PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,   NULL },
{ 20, 0, 0, "set-user-ip",    PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,     NULL },
{ 0, 20, 0, "yes",      PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,           NULL },
{ 0, 20, 0, "no", PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,           NULL },
{ 21, 0, 0, "relogin",  PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,           NULL },
{ 0, 21, 0, "yes",      PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,           NULL },
{ 0, 21, 0, "no", PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceProcessCfg,           NULL },
{ 0, 0, 0, "set", PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cLoginSet,              NULL },
{ 0, 0, 0, "login",     PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cLogin,                 NULL },
{ 0, 0, 0, "logout",    PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cLogin,                 NULL },
{ 0, 0, 0, "start",     PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceStart,              NULL },
{ 0, 0, 0, "stop",      PRIVILEGE_UNPRIVILEGED, MODE_LOGIN, cServiceStop,               NULL },
{ -1, 0, 0, NULL,  0, 0, NULL, NULL }
};
//////////////////////////////////////////////////////////////////////////////////////////
#define DO_LOGIN  0x01
#define DO_LOGOUT 0x02
#define DO_FORCE  0x04

#define LG_NONE         0
#define LG_SET_USER_IP  0x01
#define LG_RELOGIN      0x02
//////////////////////////////////////////////////////////////////////////////////////////
class Service_Login: public Service {
      public:
            time_t default_inact;
            time_t min_inact;
            time_t max_inact;
            time_t default_abs;
            time_t min_abs;
            time_t max_abs;
            
            u_char login_flags;
            u_char min_passwd_length;

            u_char storage;
            Service *st;
            char *filename;
            
            pthread_rwlock_t rwlock; // for multiple threads access same config data

            Service_Login();
            ~Service_Login();

            void ShowCfg(struct cli_def *cli, u_char flags);
            int ProcessCfg(struct cli_def *cli, char **argv, int argc, u_char no_flag);
            void Worker();
            void Cancel();
        
            void ProcessData();
            void RestoreLogins();
            void aLogin(struct cli_def *cli, NetUnit *u, struct in_addr *ip_src, u_char flag);
};

Service* InitLoginService() {
      Service *s;
      if(!initialized) {
            InitCliCommands(cmd_db);
            initialized = 1;
      }
      s = (Service*)new Service_Login();
      s->serv_flags|=SERVICE_FLAG_SINGLE;
      return s;
}
//////////////////////////////////////////////////////////////////////////////////////////
Service_Login::Service_Login():Service(SERVICE_LOGIN) {
      default_inact=S_LOGIN_DEF_default_inact;
      default_abs=S_LOGIN_DEF_default_abs;
      max_inact=S_LOGIN_DEF_max_inact;
      min_inact=S_LOGIN_DEF_min_inact;
      max_abs=S_LOGIN_DEF_max_abs;
      min_abs=S_LOGIN_DEF_min_abs;
      min_passwd_length=S_LOGIN_DEF_min_passwd_length;

      login_flags=LG_NONE;

      storage=0;
      st=NULL;
      filename=NULL;
      print_to_string(&filename, "login.%u", instance);

        netams_rwlock_init(&rwlock, NULL);
      Login=this;
}

Service_Login::~Service_Login (){
      Login=NULL;
      netams_rwlock_destroy(&rwlock);
      aFree(filename);
}
//////////////////////////////////////////////////////////////////////////////////////////
int Service_Login::ProcessCfg(struct cli_def *cli, char **param, int argc, u_char no_flag){
      time_t t;

      netams_rwlock_wrlock(&rwlock);

      if (STRARG(param[0], "default-inact")) {
            t=strtol(param[1], NULL, 10);
            if (t<0 || t>60*60*24*7) return CLI_OK; // disallow negative and more than one week
            default_inact=t;
            cli_error(cli, "default inactivity timeout set to %lu seconds", (u_long)t);
      }
      else if (STRARG(param[0], "default-abs")) {
            t=strtol(param[1], NULL, 10);
            if (t<0 || t>60*60*24*7) return CLI_OK; // disallow negative and more than one week
            default_abs=t;
            cli_error(cli, "default absolute timeout set to %lu seconds", (u_long)t);
      }
      else if (STRARG(param[0], "max-inact")) {
            t=strtol(param[1], NULL, 10);
            if (t<0 || t>60*60*24*7) return CLI_OK; // disallow negative and more than one week
            max_inact=t;
            cli_error(cli, "maximum inactivity timeout set to %lu seconds", (u_long)t);
      }
      else if (STRARG(param[0], "min-inact")) {
            t=strtol(param[1], NULL, 10);
            if (t<0 || t>60*60*24*7) return CLI_OK; // disallow negative and more than one week
            min_inact=t;
            cli_error(cli, "minimum inactivity timeout set to %lu seconds", (u_long)t);
      }
      else if (STRARG(param[0], "max-abs")) {
            t=strtol(param[1], NULL, 10);
            if (t<0 || t>60*60*24*7) return CLI_OK; // disallow negative and more than one week
            max_abs=t;
            cli_error(cli, "maximum absolute timeout set to %lu seconds", (u_long)t);
      }
      else if (STRARG(param[0], "min-abs")) {
            t=strtol(param[1], NULL, 10);
            if (t<0 || t>60*60*24*7) return CLI_OK; // disallow negative and more than one week
            min_abs=t;
            cli_error(cli, "minimum absolute timeout set to %lu seconds", (u_long)t);
      }
      else if (STRARG(param[0], "min-passwd-length")) {
            t=strtol(param[1], NULL, 10);
            if (t<0 || t>60*60*24*7) return CLI_OK; // disallow negative and more than one week
            min_passwd_length=t;
            cli_error(cli, "minimum password length set to %lu symbols", (u_long)t);
      }
      else if (STREQ(param[0], "set-user-ip")) {
            if (STREQ(param[1], "yes") || strtol(param[1], NULL, 10)==1) {
                  cli_error(cli, "unit type user ip address will be set to current ip");
                  login_flags |= LG_SET_USER_IP;
            }
            else {
                  cli_error(cli, "unit type user ip address will be NOT set");
                  login_flags &= ~LG_SET_USER_IP;
            }
      }
      else if (STREQ(param[0], "relogin")) {
            if (STREQ(param[1], "no")) {
                  login_flags &= ~LG_RELOGIN;
                  cli_error(cli, "relogin parameter set to \"no\": disallow relogins");
            }
            else if (STREQ(param[1], "yes")) {
                  login_flags |= LG_RELOGIN;
                  cli_error(cli, "relogin parameter set to \"yes\": allow relogins");
            }
      }
      netams_rwlock_unlock(&rwlock);      
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////////////////////
void Service_Login::ShowCfg(struct cli_def *cli, u_char flags){
        if(netams_rwlock_rdlock(&rwlock)) return;

      if (default_inact!=S_LOGIN_DEF_default_inact) cli_print(cli, "default-inact %lu", (u_long)default_inact);
      if (default_abs!=S_LOGIN_DEF_default_abs) cli_print(cli, "default-abs %lu", (u_long)default_abs);
      if (max_inact!=S_LOGIN_DEF_max_inact) cli_print(cli, "max-inact %lu", (u_long)max_inact);
      if (min_inact!=S_LOGIN_DEF_min_inact) cli_print(cli, "min-inact %lu", (u_long)min_inact);
      if (max_abs!=S_LOGIN_DEF_max_abs) cli_print(cli, "max-abs %lu", (u_long)max_abs);
      if (min_abs!=S_LOGIN_DEF_min_abs) cli_print(cli, "min-abs %lu", (u_long)min_abs);
      if (min_passwd_length!=S_LOGIN_DEF_min_passwd_length) cli_print(cli, "min-passwd-length %u", min_passwd_length);
      cli_print(cli, "relogin %s", (login_flags&LG_RELOGIN)?"yes":"no");
      if (login_flags&LG_SET_USER_IP) cli_print(cli, "set-user-ip yes");
      
      netams_rwlock_unlock(&rwlock);
}
//////////////////////////////////////////////////////////////////////////////////////////
void Service_Login::Worker(){
      st = aStorageGetAccepted(ST_CONN_LOGIN);
      if (st==NULL) { 
            aLog(D_WARN, "login service requires at least one storage to be up, skipping\n");  
            return;
      }
      
      ((Service_Storage_Interface*)st)->SaveFile(filename,ST_CONN_LOGIN);
      
      while(!((Service_Storage_Interface*)st)->stLoad(ST_CONN_LOGIN, &FillLoginData)) {
            aLog(D_WARN, "Service login can't obtain data from storage:%u\n",st->instance);
            Sleep(10);
      }
      
      RestoreLogins(); //restore login status back

      aLog(D_DEBUG, "service login:%u checking every processor delay: %d seconds\n", instance, Processor->delay);

      while (1) {
            Sleep(0); // login timeouts will be checked every delay seconds
            aDebug(DEBUG_LOGIN, "Checking logins (every %d seconds)\n", Processor->delay);
            ProcessData();    
      }
}
//////////////////////////////////////////////////////////////////////////////////////////
void Service_Login::RestoreLogins() {
      sLoginData *ld;
      NetUnit *u;

      netams_rwlock_rdlock(&Units->rwlock);
      for (u=(NetUnit*)Units->root; u!=NULL; u=(NetUnit*)u->next) {                     
            ld=u->logindata;
            if(!ld) continue;
   
            if(ld->flags&LOGIN_ACTIVE) 
                  aLogin(NULL, u, NULL, (DO_LOGIN|DO_FORCE));
            else 
                  aLogin(NULL, u, NULL, (DO_LOGOUT|DO_FORCE));
            
            ld->flags&=~LOGIN_UPDATE;
            aDebug(DEBUG_LOGIN, "Unit: %06X inact %u abs %u %s %s\n", u->id, ld->inact, ld->abs, (ld->flags&LOGIN_ACTIVE)?"ACTIVE":"", (ld->flags&LOGIN_STRICT)?"STRICT":"");
      }
      netams_rwlock_unlock(&Units->rwlock);
}
//////////////////////////////////////////////////////////////////////////////////////////
void Service_Login::ProcessData() {
      time_t now=time(NULL);
      NetUnit *u;
        time_t last_used;
      FILE *file=NULL;
      sLoginData *ld;
      
      netams_rwlock_rdlock(&Units->rwlock);
      for (u=(NetUnit*)Units->root; u!=NULL; u=(NetUnit*)u->next) { 
            ld=u->logindata;
            if (!ld) continue;

            if (ld->flags&LOGIN_ACTIVE) {
                  if (ld->abs && (now - ld->opened) > ld->abs) {
                        aDebug(DEBUG_LOGIN, "Unit %06X absolute timeout reached: now=%ld, opened=%ld\n", u->id, now, ld->opened);
                        aLogin(NULL, u, NULL, (DO_LOGOUT|DO_FORCE));                
                  }
                  if(u->ap) last_used=u->ap->LastUsed();
                  else last_used=0;
                  if ((ld->inact && last_used && (now - last_used) > ld->inact)
                  || (ld->inact && !last_used && (now - ld->opened) > ld->inact)) {
                        aDebug(DEBUG_LOGIN, "Unit %06X inact timeout reached: now=%ld, opened=%ld, lastused=%ld\n", u->id, now, ld->opened, last_used);
                        aLogin(NULL, u, NULL,  (DO_LOGOUT|DO_FORCE));
                  }
            }
            if (ld->flags&LOGIN_UPDATE) {
                  if(!file) {
                        file=fopen(filename,"a");
                        if(!file) {
                              aLog(D_ERR, "Can't create temporary file %s: %s\n", filename, strerror(errno));
                              continue;
                        }
                        setlinebuf(file);
                  }
                  ld->flags&=~LOGIN_UPDATE;
                  fprintf (file, "%u,%s,%lu,%lu,%lu,%lu,%u,%s,%u\n",
                        u->id, ld->password?ld->password:"",
                        ld->inact, ld->abs, now, ld->opened,
                        ld->ip_from.s_addr, ether_ntoa(&ld->mac_from), ld->flags);
                }
      }
      netams_rwlock_unlock(&Units->rwlock);
      
      if(file) {
            fclose(file);
            ((Service_Storage_Interface*)st)->SaveFile(filename,ST_CONN_LOGIN);
      }
}
//////////////////////////////////////////////////////////////////////////////////////////
void Service_Login::Cancel(){
      ProcessData();
      if(st) ((Service_Storage_Interface*)st)->Close(ST_CONN_LOGIN);
}
//////////////////////////////////////////////////////////////////////////////////////////
int cShowLogin(struct cli_def *cli, const char *cmd, char **argv, int argc){
      NetUnit *u, *ut=NULL;
      unsigned total=0, enabled=0, opened=0, closed=0;
      static char buf1[32], buf2[32];
      char buffer[32];

      Service_Login *cfg=(Service_Login*)Login;
    if(!cfg) {
            cli_print(cli, "Service not enabled");
            return CLI_OK;
      }
      
      u_char i=2;
      ut = aParseUnit(argv, &i);
      
      netams_rwlock_rdlock(&cfg->rwlock);
      netams_rwlock_rdlock(&Units->rwlock);
      for (u=(NetUnit*)Units->root; u!=NULL; u=(NetUnit*)u->next){
            total++;
            if (u->logindata) {
                  enabled++;
                  if (u->logindata->flags&LOGIN_ACTIVE) opened++; else closed++;
                  if ((ut && ut==u) || !ut) {
                        cli_print(cli, "OID: %06X (%s) %s, inact:%lu, abs:%lu",
                              u->id, u->name?u->name:"<\?\?>",
                              u->logindata->flags&LOGIN_ACTIVE?"OPENED":"CLOSED",
                              (u_long)u->logindata->inact, (u_long)u->logindata->abs);
                        inet_ntop(AF_INET, &(u->logindata->last_ip_from), buffer, 32);
                        if (u->logindata->flags&LOGIN_ACTIVE)
                              cli_print(cli, " OP:%s, LU:%s, %s[%s]",
                                    timeU2T(u->logindata->opened, buf1),
                                    u->ap?timeU2T(u->ap->LastUsed(), buf2):"err",
                                    buffer,
                                    ether_ntoa(&u->logindata->last_mac_from));
                  }
            }
      }
      netams_rwlock_unlock(&Units->rwlock);
      netams_rwlock_unlock(&cfg->rwlock);
      cli_print(cli, "Total units: %u, enabled: %u, opened: %u, closed:%u", total, enabled, opened, closed);
      return CLI_OK;
}

//////////////////////////////////////////////////////////////////////////////////////////
int cLoginSet(struct cli_def *cli, const char *cmd, char **param, int argc) {
      if(!Login) {
            cli_error(cli, "Service Login not active");
            return CLI_OK;
      }
      Service_Login *sl=(Service_Login*)Login;
      NetUnit *u;
      time_t t_inact, t_abs;
      sLoginData *ld;
      
      u_char i=1;
      u=aParseUnit(param, &i);
      if(u==NULL) {
            cli_error(cli, "unit not exist");
            return CLI_OK;
      }
      
      ld=u->logindata;
      if (!ld) {
            ld = (sLoginData*)aMalloc(sizeof(sLoginData));
            ld->inact=sl->default_inact;
            ld->abs=sl->default_abs;
            ld->opened=0L;
            bzero(&ld->ip_from, sizeof (struct in_addr));
            bzero(&ld->mac_from, sizeof (struct ether_addr));
            ld->flags=0;
            ld->password=NULL;
            u->logindata=ld;
      }

      for(; i<argc; i+=2) {
            if (STRARG(param[i], "inact")){
                  t_inact=strtol(param[i+1], NULL, 10);
                  if (t_inact != 0 && (sl->min_inact > t_inact || t_inact > sl->max_inact))
                        cli_error(cli, "invalid inact value range, setting to default");
                  else
                        ld->inact=t_inact;
            }
            else if (STRARG(param[i], "abs")){
                  t_abs=strtol(param[i+1], NULL, 10);
                  if (t_abs != 0 && (sl->min_abs > t_abs || t_abs > sl->max_abs))
                        cli_error(cli, "invalid abs value range, setting to default");
                  else
                        ld->abs=t_abs;
            }
            else if (STRARG(param[i], "password")){
                  u_char j=strlen(param[i+1]);
                  if (j < sl->min_passwd_length) {
                        cli_error(cli, "password length is too small (real %d need at least %d)",
                              j, sl->min_passwd_length);
                        return CLI_OK;
                  }
                  ld->password=set_string(param[i+1]);
            }
            else if (STRARG(param[i], "ip")) {
                  inet_aton(param[i+1], &ld->ip_from);
            }
            else if (STRARG(param[i], "mac")){
                  struct ether_addr *o_mac;
                  o_mac=ether_aton(param[i+1]);
                  if (o_mac) memcpy(&ld->mac_from, o_mac, sizeof (struct ether_addr));
            }
            else if (STREQ(param[i], "strict")){
                  ld->flags|=LOGIN_STRICT; i--;
            }
            else if (STREQ(param[i], "nostrict")){
                  ld->flags&=~LOGIN_STRICT; i--;
            }
      }

      aDebug(DEBUG_LOGIN, "set/got: oid=%06X, inact:%ld, abs:%ld, pass:%s, %s, %s\n",
            u->id, ld->inact, ld->abs, ld->password?ld->password:"-",
            (ld->flags&LOGIN_ACTIVE)?"ACTIVE":"NOT ACTIVE",
            (ld->flags&LOGIN_STRICT)?"STRICT":"NOT STRICT");
      
      ld->flags|=LOGIN_UPDATE;
      cli_error(cli, "login set/got: oid=%06X, inact:%ld, abs:%ld, pass:%s, %s, %s\n",
            u->id, ld->inact, ld->abs, ld->password?ld->password:"-",
            (ld->flags&LOGIN_ACTIVE)?"ACTIVE":"NOT ACTIVE",
            (ld->flags&LOGIN_STRICT)?"STRICT":"NOT STRICT");
      return CLI_OK;
}

//////////////////////////////////////////////////////////////////////////////////////////
int cLogin(struct cli_def *cli, const char *cmd, char **param, int argc){
      NetUnit *u;
      char *password=NULL;
      char *name=NULL;
      struct in_addr o_ip;
      struct ether_addr o_mac;
      u_char flag=0;
      u_char pam=0;
      u_char i=1;

      if(!Login) {
            cli_error(cli, "Service Login not active");
            return CLI_OK;
      }

      if(STREQ(param[0], "login")) flag=DO_LOGIN;
      else if(STREQ(param[0], "logout")) flag=DO_LOGOUT;

      bzero(&o_ip, sizeof (struct in_addr));
      bzero(&o_mac, sizeof (struct ether_addr));

      for(;i<argc;i++){
            if (STRARG(param[i], "ip")){
                  inet_aton(param[i+1], &o_ip);
                  i++;
            }
            else if (STRARG(param[i], "mac")){
                  struct ether_addr *mac;
                  mac=ether_aton(param[i+1]);
                  if (!memcmp(mac, "\0\0\0\0\0\1", sizeof (struct ether_addr))) flag|=DO_FORCE;
                  i++;
            }
            else if (STRARG(param[i], "password")){
                  password=param[i+1];
                  i++;
            }
            else if (STRARG(param[i], "name")){
                  name=param[i+1];
                  i++;
            }
      }

#ifdef HAVE_PAM
      if ( name ) { // !oid
          if (!aAuthPam(name,password) ) {
            cli_error(cli, "FAIL: pam has not accepted");
            return CLI_OK;
          } else pam = 1;
      }
#endif

      i=1;
      u=aParseUnit(param, &i);
      if(u==NULL) {
            cli_error(cli, "unit not exist");
            return CLI_OK;
      }

      if (!u->logindata) {
            cli_error(cli, "FAIL: login service is not running for that unit");
            return CLI_OK;
      }

#ifdef DEBUG
      char buffer[32];
      aDebug(DEBUG_LOGIN, "login/got: oid=%06X, pass:%s(%s), ip=%s, mac=%s\n",
            u->id, password?password:"-",
            u->logindata->password?u->logindata->password:"-",
            inet_ntop(AF_INET, &o_ip, buffer, 32), ether_ntoa(&o_mac));
#endif

      if( !pam && ( !STREQ(password, u->logindata->password) ||
            (!u->logindata->password && !STREQ(password, u->password) ) ) ) { 
            cli_error(cli, "FAIL: login %s is not allowed", u->name); 
            return CLI_OK; 
      }
      
      ((Service_Login*)Login)->aLogin(cli, u, &o_ip, flag);
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////////////////////
void Service_Login::aLogin(struct cli_def *cli, NetUnit *u, struct in_addr *ip_src, u_char flag) {
      struct ether_addr zero_mac;
      struct ether_addr current_mac;
      sLoginData *ld=u->logindata;
      struct in_addr *ip;
      char buffer[32];

      bzero(&zero_mac, sizeof (struct ether_addr));
      bzero(&current_mac, sizeof (struct ether_addr));
      
      if(ip_src) ip=ip_src;
      else ip=(in_addr*)"\0\0\0\0";

      if(!(flag&DO_FORCE)) {
            // strict login processing
            if ((ld->flags&LOGIN_STRICT) && (ld->ip_from.s_addr!=ip->s_addr)) {
                  cli_error(cli, "FAIL: login is not allowed"); 
                  inet_ntop(AF_INET, ip, buffer, 32);             
                  LogEvent(LOGIN, u->id, 0, 0, "FAIL STRICT: login from wrong IP: %s", buffer);
                  return;
            }
      
            inet_ntop(AF_INET, ip, buffer, 32);             
            aDebug(DEBUG_LOGIN, "MAC: checking %s for mac address...\n", buffer);
            sLgObtainMac(ip, &current_mac);
            memcpy(&ld->last_mac_from, &current_mac, sizeof (struct ether_addr));

            // mac address processing
            if (memcmp(&ld->mac_from, &zero_mac, sizeof (struct ether_addr))) { // unit's MAC is not zero
                  if (memcmp(&ld->mac_from, &current_mac, sizeof (struct ether_addr))) { // unit's MAC != current
                        aDebug(DEBUG_LOGIN, "MAC: not match database: %s\n", ether_ntoa(&ld->mac_from));
                         cli_error(cli, "FAIL: login is not allowed"); 
                        LogEvent(LOGIN, u->id, 0, 0, "FAIL MAC: login from wrong mac: %s", ether_ntoa(&current_mac));
                        return;
                  }
            }
      } else {
            aDebug(DEBUG_LOGIN, "MAC: magic mac address is specified, check skiped\n");
      }
      
      if(flag&DO_LOGIN) { // login
            if(ld->flags&LOGIN_ACTIVE) {
                  if(login_flags&LG_RELOGIN) {
                        cli_error(cli, "Performing relogin");
                        LogEvent(LOGIN, u->id, 0, 0, "RELOGIN: relogin attempt from %s\n", inet_ntop(AF_INET, ip, buffer, 32));
                  } else {
                        cli_error(cli, "This unit already logged in");
                        LogEvent(LOGIN, u->id, 0, 0, "FAIL LOGIN: login attempt from %s when already logged in\n",\
                              inet_ntop(AF_INET, ip, buffer, 32));
                        return;
                  }
            }
            
            // if "set-user-ip" and DO_LOGIN, check other units currently using this IP address and logout them
            // this will use Login recursive call - hope this is OK
            if (login_flags&LG_SET_USER_IP){
                  NetUnit *t; NetUnit_user *ut;
                  for (t=(NetUnit*)Units->root; t!=NULL; t=(NetUnit*)t->next){
                        if (u->type==NETUNIT_USER) {
                              ut=(NetUnit_user*)t;
                              if (ut->logindata) {
                                    if (ut->logindata->flags&LOGIN_ACTIVE && 
                                          !memcmp(&ut->logindata->last_ip_from, ip, sizeof (struct in_addr)) &&
                                          !memcmp(&ut->ip, ip, sizeof (struct in_addr)) ) {
                                                aDebug (DEBUG_LOGIN, "unit user %s (%06X) was logged on there, forcibly log off it\n", ut->name?ut->name:"<\?\?>", ut->id);
                                                aLogin(cli, t, NULL, DO_LOGOUT);
                                                break;
                                          }
                              } 
                        }
                  }
            }
            
            cAccessScriptCall(DROP, u, "LOGIN OFF");

            ld->flags|=LOGIN_ACTIVE; // open the unit
            ld->opened=time(NULL);
            
            memcpy(&ld->last_ip_from, ip, sizeof (struct in_addr));
            if ((login_flags&LG_SET_USER_IP) && u->type==NETUNIT_USER) {
                  u->unit2trees(REMOVE);
                  NetUnit_user *uu = (NetUnit_user*)u;
                  if(ip_src) memcpy(&uu->ip, ip, sizeof (struct in_addr));
                  aDebug (DEBUG_LOGIN, "unit user ip address is set to %s\n", inet_ntop(AF_INET, ip, buffer, 32));
                  u->unit2trees(ADD);
            }
            u->SetSysPolicy(SP_DENY_LOGIN, REMOVE);
            cAccessScriptCall(PASS, u, "LOGIN ON");
            aDebug(DEBUG_LOGIN, "login success from ip:%s, mac:%s\n",
                  inet_ntop(AF_INET, ip, buffer, 32), ether_ntoa(&current_mac));
             cli_error(cli, "OK: login success from ip:%s, mac:%s",
                  inet_ntop(AF_INET, ip, buffer, 32), ether_ntoa(&current_mac));
            LogEvent(LOGIN, u->id, 0, 0, "OK login success from ip: %s mac: %s",
                  inet_ntop(AF_INET, ip, buffer, 32), ether_ntoa(&current_mac));
      } 
      else if(flag&DO_LOGOUT) { // logout
            u->SetSysPolicy(SP_DENY_LOGIN, ADD);
            cAccessScriptCall(DROP, u, "LOGIN OFF");
            if(u->ap) u->ap->ClearLastUsed(); //clear last_used

            aDebug(DEBUG_LOGIN, "logout success from ip:%s, mac:%s\n",
                  inet_ntop(AF_INET, ip, buffer, 32), ether_ntoa(&current_mac));
             cli_error(cli, "OK: logout success from ip:%s, mac:%s",
                  inet_ntop(AF_INET, ip, buffer, 32), ether_ntoa(&current_mac));
            LogEvent(LOGIN, u->id, 0, 0, "OK logout success from ip: %s mac: %s",
                  inet_ntop(AF_INET, ip, buffer, 32), ether_ntoa(&current_mac));    
            ld->flags&=~LOGIN_ACTIVE; // close the unit
            if ((login_flags&LG_SET_USER_IP) && u->type==NETUNIT_USER) {
                  u->unit2trees(REMOVE);
                  NetUnit_user *uu = (NetUnit_user*)u;
                  bzero(&uu->ip, sizeof (struct in_addr));
                  aDebug (DEBUG_LOGIN, "unit user ip address is cleared\n");
            }
      }
      u->logindata->flags|=LOGIN_UPDATE;
}
//////////////////////////////////////////////////////////////////////////////////////////
void sLgObtainMac(struct in_addr *u, struct ether_addr *current_mac){

#if defined(FREEBSD) || defined(OPENBSD)
      
#ifdef DEBUG
      char buffer[32];
#endif
      char *buf;
      char *e;
      int mib[6];
      size_t needed;
      char *lim, *next;
      struct rt_msghdr *rtm;
      struct sockaddr_inarp *sin;
      struct sockaddr_dl *sdl;

      mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_FLAGS; mib[5] = RTF_LLINFO;
      if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) return;
      if ((buf = (char*)aMalloc(needed)) == NULL) return;
      if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) return;

      lim = buf + needed;

      for (next = buf; next < lim; next += rtm->rtm_msglen) {
            rtm = (struct rt_msghdr *)next;
            sin = (struct sockaddr_inarp *)(rtm + 1);
            sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin_len));
            e=LLADDR(sdl);
            if (sin->sin_addr.s_addr==u->s_addr && memcmp(e, "\0\0\0\0\0\0", sizeof(struct ether_addr)))  {
                  memcpy(current_mac, e, sizeof (struct ether_addr));
#ifdef DEBUG
                  aDebug(DEBUG_LOGIN, "MAC for ip: %s is: %s found in ARP\n", inet_ntop(AF_INET, u, buffer, 32), ether_ntoa((struct ether_addr*)e));
#endif
                  aFree(buf);
                  return;
            }
      }

#ifdef DEBUG
      aDebug(DEBUG_LOGIN, "MAC for ip:%s is not found in ARP\n", inet_ntop(AF_INET, u, buffer, 32));
#endif
      aFree(buf);
#endif

#if defined(LINUX)
#ifdef DEBUG
      char buffer[32];
#endif      
      char *buf;

      char b_ip[32], b_hw[32], b_trash[32];
      struct in_addr in;
      struct ether_addr *e;
      FILE *arp;

      if ((buf = (char*)aMalloc(256)) == NULL) return;

      arp=fopen("/proc/net/arp", "rt");
      if (arp==NULL) { aDebug(DEBUG_LOGIN, "failed to open /proc/net/arp\n"); return; }

      if (NULL==fgets(buf, 255, arp)) goto FINISH_LINUX_CHECK;

      while (!feof(arp)){
            if (NULL==fgets(buf, 255, arp)) break;
            bzero(b_ip, 31); bzero(b_hw, 8);
            sscanf(buf, "%s%s%s%s", b_ip, b_trash, b_trash, b_hw);
            if (inet_aton(b_ip, &in) && (e=ether_aton(b_hw))){
                  if (u->s_addr==in.s_addr && memcmp(e, "\0\0\0\0\0\0", sizeof(struct ether_addr))) {
                        memcpy(current_mac, e, sizeof (struct ether_addr));
#ifdef DEBUG
                        aDebug(DEBUG_LOGIN, "MAC for ip: %s is: %s found in ARP\n", inet_ntop(AF_INET, u, buffer, 32), ether_ntoa((struct ether_addr*)e));
#endif
                        goto FINISH_LINUX_CHECK;
                  }
            }
      }
FINISH_LINUX_CHECK:
      fclose(arp);
      aFree(buf);
#endif
      return;
}
//////////////////////////////////////////////////////////////////////////////////////////
void FillLoginData(void *res, void *row, char* (*getRowData)(void*, void* , u_char)) {
        sLoginData *logindata;
        unsigned tmp;
        NetUnit *u=NULL;
        oid id;

        sscanf(getRowData(res, row, 0), "%u", &id);
        if(id && !(u=(NetUnit*)Units->getById(id))) return;
        if(u->logindata) {
                logindata=u->logindata;
                aFree(logindata->password);
        } else
                logindata = (sLoginData*)aMalloc(sizeof(sLoginData));

        logindata->password=set_string(getRowData(res, row, 1));
        sscanf(getRowData(res, row, 2), "%lu", (unsigned long*)&logindata->inact);
        sscanf(getRowData(res, row, 3), "%lu", (unsigned long*)&logindata->abs);
        sscanf(getRowData(res, row, 5), "%lu", (unsigned long*)&logindata->opened);
        sscanf(getRowData(res, row, 6), "%u", &logindata->ip_from.s_addr);
        memcpy(&logindata->mac_from, ether_aton(getRowData(res, row, 7)), sizeof (struct ether_addr));
        sscanf(getRowData(res, row, 8), "%u", &tmp); logindata->flags=tmp;

        u->logindata=logindata;
        aDebug(DEBUG_LOGIN, "Unit: %06X inact %lu abs %lu flags:%u\n", u->id, u->logindata->inact, u->logindata->abs, u->logindata->flags);
}
//////////////////////////////////////////////////////////////////////////////////////////


Generated by  Doxygen 1.6.0   Back to index