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

pam_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
***
*************************************************************************/
/* $Id: pam_netams.c,v 1.6 2008-05-27 16:35:20 anton Exp $
 * Contributed to NeTAMS project by A.Rudenko aka RAV (2007/06/06)
 * pam_netams.c - driver for netams; contains PAM interface.
 * The pam_netams module supports the auth and acct.
 */

#include "config.h"

#ifdef HAVE_PAM
#include <security/pam_modules.h>
#include <security/pam_appl.h>
#endif

#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT

typedef struct pam_netams_t {
      char  *login;
      char  *password;
      char  *server;
      int   port;
      char  *rcfile;
      char  *type;
      char  *name;
      int   autoadd;
      int   syspolicy;
      char  *param;
      FILE  *fd;
      int   socket;
      char  buffer[1024];
} pam_netams_t;

static int pam_parse( pam_handle_t *pamh, pam_netams_t *data, int argc, const char **argv);
static int netams_connect_daemon(pam_netams_t *data);
static int netams_disconnect_daemon(pam_netams_t *data);
static int netams_cmd(pam_netams_t *data, const char *cmd);
static void netams_wait(pam_netams_t *data);
static void pam_syslog(int err, const char *format, ...);

/****
 * PAM management functions
 */

/* authentication management */

PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
                                    int argc, const char **argv)
{
      pam_netams_t *data;
      data = (pam_netams_t *)malloc(sizeof(*data));
      if (!data) return -1;
      memset(data, 0, sizeof(*data));
      int retval = PAM_AUTH_ERR;
      int i;

      if ( pam_parse( pamh, data, argc, argv ) == 0 ) {
                struct pam_conv *conv;
              struct pam_message *pmsg[3],msg[3];
              struct pam_response *response;

            if ( pam_get_item( pamh, PAM_CONV, (const void **) &conv ) == PAM_SUCCESS ) {
                  pmsg[0] = &msg[0];
                  msg[0].msg_style = PAM_PROMPT_ECHO_OFF;

                  if ( conv->conv(1, ( const struct pam_message ** ) pmsg, &response, conv->appdata_ptr) == PAM_SUCCESS ) {

                        if ( response->resp ) {

                            snprintf(data->buffer, 1023, "pam auth %s name %s password %s %s",data->type, data->name, response->resp, data->syspolicy?"syspolicy":" ");
                            i=netams_connect_daemon(data);

                            if (i==0 && netams_cmd(data, NULL) ) {

                              sscanf(data->buffer, "%d", &i);

                              if ( i==1 ) //success
                                  retval = PAM_SUCCESS;
                              else 
                                  pam_syslog(LOG_WARNING,"netams response:%s",data->buffer);

                            } else
                              pam_syslog(LOG_WARNING,"i can not communicate with daemon ...");

                            netams_disconnect_daemon(data);

                        } else
                            pam_syslog(LOG_WARNING,"the password is not received ...");

                  } else
                      pam_syslog(LOG_WARNING,"error in pam_convert ...");

            } else
                pam_syslog(LOG_WARNING,"error in pam_get_item ...");
      }
      
      if (data->login)  free(data->login);
      if (data->password)     free(data->password);
      if (data->server)       free(data->server);
      if (data->rcfile) free(data->rcfile);
      if (data->type)   free(data->type);
      if (data->name)   free(data->name);
      if (data->param)  free(data->param);
      free(data);

      return retval;
}

PAM_EXTERN
int pam_sm_setcred(pam_handle_t *pamh, int flags,
                              int argc, const char **argv)
{
      return PAM_IGNORE;
}

/* account management */

PAM_EXTERN
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
                        int argc, const char **argv)
{
      pam_netams_t *data;
      data = (pam_netams_t *)malloc(sizeof(*data));
      if (!data) return -1;
      memset(data, 0, sizeof(*data));
      int retval = PAM_USER_UNKNOWN;
      int i;

      if ( pam_parse( pamh, data, argc, argv ) == 0 ) {

            snprintf(data->buffer, 1023, "pam acct %s name %s %s",data->type, data->name, data->syspolicy?"syspolicy":" ");
            i=netams_connect_daemon(data);

            if (i==0 && netams_cmd(data, NULL) ) {
                  
                  sscanf(data->buffer, "%d", &i);

                  if ( i==1 ) //success
                        retval = PAM_SUCCESS;
                              
                  else if (i==0 && data->autoadd) { //create

                      if ( !strcmp(data->type,"unit") ) {

                        snprintf(data->buffer, 1023, "unit user name %s %s",data->name,data->param?data->param:" ");
                        if ( netams_cmd(data,"service processor") ) retval = PAM_SUCCESS;
                        pam_syslog(LOG_WARNING,"netams response:%s",data->buffer);

                      } else if (!strcmp(data->type,"login")) {

                        snprintf(data->buffer, 1023, "set name %s %s",data->name,data->param?data->param:" ");
                        if ( netams_cmd(data,"service login") ) retval = PAM_SUCCESS;
                        pam_syslog(LOG_WARNING,"netams response:%s",data->buffer);

                      } else if (!strcmp(data->type,"account")) {

                        snprintf(data->buffer, 1023, "account XXX name %s", data->name);
                        netams_cmd(data,"service billing");
                        pam_syslog(LOG_WARNING,"netams response:%s",data->buffer);
                        char *oid; oid=(char *)malloc(6+1);
                        sscanf(data->buffer, "account %s created", oid);
                        snprintf(data->buffer, 1023, "account %s unit name %s add", oid, data->name);

                        if ( oid && netams_cmd(data,NULL) ) {//oid received and command send

                            pam_syslog(LOG_WARNING,"netams response:%s",data->buffer);

                            if (data->param) {

                              char *p=data->param, *pp;

                              do {
                                    pp=strstr(p, "&&");
                                    if (pp) *pp='\0';
                                    snprintf(data->buffer, 1023, "account %s %s", oid, p);
                                    netams_cmd(data,NULL);
                                    pam_syslog(LOG_WARNING,"netams response:%s",data->buffer);
                                    p=pp+3;

                              } while (pp);

                            }
                            retval = PAM_SUCCESS;
                        }

                      }

                  } else  // not accept
                        pam_syslog(LOG_WARNING,"netams response:%s",data->buffer);

            } else
                  pam_syslog(LOG_WARNING,"i can not communicate with daemon ...");

            netams_disconnect_daemon(data);

      }
      
      if (data->login)  free(data->login);
      if (data->password)     free(data->password);
      if (data->server)       free(data->server);
      if (data->rcfile) free(data->rcfile);
      if (data->type)   free(data->type);
      if (data->name)   free(data->name);
      if (data->param)  free(data->param);
      free(data);

      return retval;
}

/****
 * local functions
 */


static int netams_cmd(pam_netams_t *data, const char *cmd)
{

        char *buffer;
      int i=0;

      if (fprintf(data->fd, "\r\n") <=0 )
          return 0;

        buffer=(char *)malloc(4*1024+1); 
      fgets(buffer, 4*1024, data->fd); 
      netams_wait(data);
      
      if (cmd) {
          if (!strcmp(cmd,"end")) {
            fprintf(data->fd, "end\r\n"); fgets(buffer, 4*1024, data->fd); netams_wait(data);
          } else {
            fprintf(data->fd, "enable\r\n"); fgets(buffer, 4*1024, data->fd); netams_wait(data);
            fprintf(data->fd, "conf t\r\n"); fgets(buffer, 4*1024, data->fd); netams_wait(data);
            fprintf(data->fd,"%s\r\n", cmd); fgets(buffer, 4*1024, data->fd); netams_wait(data);
          }
      }
      
      if ( fprintf(data->fd, "%s\r\n", data->buffer) > 0 ) { //netams accepted a command
          fgets(buffer, 4*1024, data->fd); 
          fgets(data->buffer, 1023, data->fd); i=strlen(data->buffer); if (i) data->buffer[i-1]=0;
          netams_wait(data);
          i = 1;
      }

      free(buffer);
      return i;
}

static void netams_wait(pam_netams_t *data)
{

      int i, prev=10;

      while (1) {
              i=fgetc(data->fd);
            if (feof(data->fd) || ((prev=='#' || prev=='>') && i==' ')) break;
            putchar(i);
            prev=i;
      }

}


static int pam_parse(pam_handle_t *pamh, pam_netams_t *data, int argc, const char **argv)
{

    data -> autoadd = 0;
    data -> syspolicy = 0;
    const char *pam_user = NULL;
    const char *default_type = NULL;
    char *buffer;
    int i;
    FILE *RCFILE=NULL;

    buffer=(char *)malloc(4*1024+1); 
    bzero(buffer, 4*1024);

    /* step through arguments */
    for (; argc-- > 0; ++argv) {
          if (!strncmp(*argv,"autoadd",7)) {
            data -> autoadd = 1;
            if (!strncmp(*argv,"autoadd=",8)) {
                i=strlen(*argv);
                strncat(buffer, *argv+8, i+1-8);
                if (strcmp(*argv+i-1,"\"")) {
                  for (++argv; argc-- > 0; ++argv) {
                      strcat(buffer, " ");
                      strcat(buffer, *argv);
                      if (!strcmp(*argv+strlen(*argv)-1,"\"")) break;
                  }
                }
            }
          } else if (!strcmp(*argv,"syspolicy")) {
              data -> syspolicy = 1;
          } else if (!strcmp(*argv,"unit")) {
            data -> type = (char *)malloc(strlen(*argv)+1);
            strcpy(data -> type, *argv);
          } else if (!strcmp(*argv,"user")) {
              data -> type = (char *)malloc(strlen(*argv)+1);
            strcpy(data -> type, *argv);
          } else if (!strcmp(*argv,"account")) {
              data -> type = (char *)malloc(strlen(*argv)+1);
            strcpy(data -> type, *argv);
          } else if (!strcmp(*argv,"login")) {
              data -> type = (char *)malloc(strlen(*argv)+1);
            strcpy(data -> type, *argv);
          } else if (!strncmp(*argv,"rcf=",4)) {
              data -> rcfile = (char *)malloc(strlen(*argv)+1-4);
              strcpy(data -> rcfile, *argv+4);
          }
    }
    
    if ( buffer ) {
      i = strlen(buffer);
      if (!bcmp(buffer,"\"",1)) {
            data -> param = (char *)malloc(i+1-2);
            buffer[i-1]=0;
          strcpy(data -> param, buffer+1);
      } else {
            data -> param = (char *)malloc(i+1);
          strcpy(data -> param, buffer);
      }
    }
    
    if ( !data -> type ) {
          if ( !default_type ) {
              pam_syslog(LOG_ERR,"pam_parse: unknown netams type");
            return -1;
            }
          data -> type = (char *)malloc(strlen(default_type)+1);
          strcpy(data -> type,default_type);
    }
    
    pam_get_user(pamh, &pam_user, NULL);
    
    if (!pam_user) {
          pam_syslog(LOG_ERR,"pam_parse: unknown pam_user");
          return -1;
          }     
    data -> name = (char *)malloc(strlen(pam_user)+1);
    strcpy(data -> name, pam_user);


    if (data -> rcfile) {
      RCFILE=fopen(data -> rcfile, "rt");
      if (!RCFILE) { pam_syslog(LOG_ERR,"pam_parse: not open rcfile"); return -1; }
    } else {
      char *homedir=getenv("HOME");
      if (homedir!=NULL) {
            char *str=(char*)malloc(256);
            sprintf(str, "%s/.netamsctl.rc", homedir);
            RCFILE=fopen(str, "rt");
      }
      if (!RCFILE) RCFILE=fopen(".netamsctl.rc", "rt");
      if (!RCFILE) RCFILE=fopen("/usr/local/etc/.netamsctl.rc", "rt");
      if (!RCFILE) RCFILE=fopen("/etc/.netamsctl.rc", "rt");
      if (!RCFILE) {pam_syslog(LOG_ERR,"pam_parse: not open rcfile"); return -1; }
    }

    bzero(buffer, 4*1024);
    while (!feof(RCFILE)){
      fgets(buffer, 4*1024, RCFILE);
      i=strlen(buffer);
      buffer[i-1]=0; //thus we remove \n
      
      if (!strncasecmp(buffer, "login=", 6)) { 
            i-=6;
            data->login=(char*)malloc(i+1);
            strncpy(data->login, buffer+6, i-1);
            data->login[i-1]=0;
            } 
      else if (!strncasecmp(buffer, "password=", 9)) { 
            i-=9;
            data->password=(char*)malloc(i+1);
            strncpy(data->password, buffer+9, i-1);
            data->password[i-1]=0;
            } 
      else if (!strncasecmp(buffer, "host=", 5)) { 
            i-=5;
            data->server=(char*)malloc(i+1);
            strncpy(data->server, buffer+5, i-1);
            data->server[i-1]=0;
            } 
      else if (!strncasecmp(buffer, "port=", 5)) { 
            data->port=strtol(buffer+5, NULL, 10);
            } 
      bzero(buffer, 4*1024);
    }  

    fclose(RCFILE);

    if (!data->login || !data->password) {pam_syslog(LOG_ERR,"pam_parse: the netams username or password not specified"); return -1; }
    if (!data->server) {
      data->server=(char*)malloc(strlen("localhost")+1);
      strcpy(data->server, "localhost");
      }
    if ( !data->port )
      data->port = 20001;

    return 0;
}

static int netams_connect_daemon(pam_netams_t *data)
{

      struct sockaddr_in addr;
      struct hostent *hp;
      int i;
      char buffer[1024];
      
      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) { pam_syslog(LOG_WARNING,"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)))) {  pam_syslog(LOG_WARNING,"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) { pam_syslog(LOG_WARNING,"fdopen of server socket() failed"); 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) {  pam_syslog(LOG_WARNING,"login failed"); 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]!='>') { pam_syslog(LOG_WARNING,"login: failed (hung daemon?)"); shutdown(data->socket, SHUT_RDWR); close(data->socket); return(-1); }

      //pam_syslog(LOG_WARNING,"connected.");
      return 0;
}


static int netams_disconnect_daemon(pam_netams_t *data)
{

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

      return 1;

}

static void pam_syslog(int err, const char *format, ...)
{
    va_list args;

    va_start(args, format);
    openlog("pam_netams", LOG_CONS|LOG_PID, LOG_AUTH);
    vsyslog(err, format, args);
    va_end(args);
    closelog();
}

/* if the module is compiled as static */
#ifdef PAM_STATIC

struct pam_module _pam_netams_modstruct = 
{
      "pam_netams",
      pam_sm_authenticate,
      pam_sm_setcred,
      pam_sm_acct_mgmt,
      NULL,
      NULL,
      NULL
};

#endif


Generated by  Doxygen 1.6.0   Back to index