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

tcpmon.cpp

// Copyright (C) 2000 Open Source Telecom Corporation.
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include "server.h"
#include <pwd.h>
#include <grp.h>

#ifdef      CCXX_NAMESPACES
namespace ost {
using namespace std;
#endif

#ifdef HAVE_PAM

extern "C" {

#include <security/pam_appl.h>

static char *PAM_username;
static char *PAM_password;

static int PAM_conv (int num_msg,
                 const struct pam_message **msg,
                 struct pam_response **resp,
                 void *appdata_ptr) {
      int replies = 0;
      struct pam_response *reply = NULL;

#define COPY_STRING(s) (s) ? strdup(s) : NULL

      reply = (struct pam_response *)malloc(sizeof(struct pam_response) * num_msg);
      if(!reply) return PAM_CONV_ERR;

      for (replies = 0; replies < num_msg; replies++)
      {
            switch(msg[replies]->msg_style)
            {
            case PAM_PROMPT_ECHO_ON:
                  reply[replies].resp_retcode = PAM_SUCCESS;
                  reply[replies].resp = COPY_STRING(PAM_username);
                  break;
            case PAM_PROMPT_ECHO_OFF:
                  reply[replies].resp_retcode = PAM_SUCCESS;
                  reply[replies].resp = COPY_STRING(PAM_password);
                  break;
            case PAM_TEXT_INFO:
            case PAM_ERROR_MSG:
                  reply[replies].resp_retcode = PAM_SUCCESS;
                  reply[replies].resp = NULL;
                  break;
            default:
                  free(reply);
                  return PAM_CONV_ERR;
            }
      }
      if(reply)
            *resp = reply;
      return PAM_SUCCESS;
}

static struct pam_conv PAM_conversation = {
      &PAM_conv,
      NULL
};

};

#endif

class TcpMonitor : public TCPSocket, public Monitor, public Server
{
private:
      friend class MonSession;

      MonSession *first, *last;

      inline modtype_t getType(void)
            {return MODULE_FIFO;};

      inline char *getName(void)
            {return "tcpmon";};

      void stop(void);
      void run(void);
      bool onAccept(const InetHostAddress &ia, tpport_t port);
public:
      TcpMonitor();
      void monitorState(Trunk *trunk, char *state);
      void monitorStep(Trunk *trunk, Line *line);
} tcpmon;

class MonSession : public TCPSession
{
private:
      MonSession *next, *prev;
      const char *name;
      bool is_admin;
      bool is_auth;
      Trunk *trace;

      bool authenticate(const char *user, const char *pass);
      bool login(void);
      void run(void);
      void final(void);
      void putLine(char str[1024]);

        bool monVersion(char **argv, ostream *out);
        bool monStatus(char **argv, ostream *out);
        bool monDriver(char **argv, ostream *out);
        bool monCalls(char **argv, ostream *out);
        bool monDump(char **argv, ostream *out);
      bool monModules(char **argv, ostream *out);
      bool monTrace(char **argv, ostream *out);

      MonSession(TCPSocket &server);
      friend class TcpMonitor;
};

TcpMonitor::TcpMonitor() :
TCPSocket(keynetwork.getMonitorAddress(), keynetwork.getMonitorPort()),
Monitor(), Server(keythreads.priService())
{
      first = last = NULL;
}

void TcpMonitor::stop(void)
{
      MonSession *tcp, *next;

      terminate();
      tcp = first;
      while(tcp)
      {
            next = tcp->next;
            delete tcp;
            tcp = next;
      }
}

void TcpMonitor::run(void)
{
      MonSession *client;

      for(;;)
      {
            setCancel(cancelImmediate);
            if(isPendingConnection(~0))
            {
                  setCancel(cancelDeferred);
                  client = new MonSession(tcpmon);
                  client->start();
            }
      }
}

void TcpMonitor::monitorState(Trunk *trunk, char *state)
{
      MonSession *tcp, *next;
      char buffer[32];
      char logline[1024];

      if(first == last)
            return;

      trunk->getName(buffer);
      snprintf(logline, sizeof(logline), "%s: %s\n", buffer, state);
      tcp = first;
      while(tcp)
      {
            next = tcp->next;
            if(tcp->trace == trunk)
                  tcp->putLine(logline);
            tcp = next;
      }
}

void TcpMonitor::monitorStep(Trunk *trunk, Line *line)
{
      MonSession *tcp, *next;
      int i;
      char buffer[32];
      char logline[1024];
      unsigned len;

      if(first == last)
            return;

      trunk->getName(buffer);
      if(!line)
            snprintf(logline, sizeof(logline), "%s: exit\n", buffer);
      else
      {
            enterMutex();
            sprintf(logline, "%s: %08lx %s (", buffer, line->mask, line->cmd);
            for(i = 0; i < line->argc; ++i)
            {
                  len = strlen(logline);
                  if(len >= sizeof(logline))
                        break;
                  if(i)
                        logline[len++] = ',';
                  strncpy(logline + len, line->args[i], sizeof(logline) - len);
            }
            strcat(logline, ")\n");
            Monitor::leaveMutex();
      }

      tcp = first;
      while(tcp)
      {
            next = tcp->next;
            if(tcp->trace == trunk)
                  tcp->putLine(logline);
            tcp = next;
      }
}

bool TcpMonitor::onAccept(const InetHostAddress &ia, tpport_t port)
{
      slog(Slog::levelNotice) << "tcpmon: accepting connection " << ia.getHostname() << ":" << port << endl;
      return true;
}

MonSession::MonSession(TCPSocket &server) :
#ifdef      COMMON_OST_NAMESPACE
TCPSession(server)
#else
TCPSession(NULL, server)
#endif
{
      tcpmon.enterMutex();
      next = prev = NULL;

      if(tcpmon.last)
            tcpmon.last->next = this;

      prev = tcpmon.last;
      if(!tcpmon.first)
            tcpmon.first = this;
      tcpmon.last = this;
      tcpmon.leaveMutex();
}

void MonSession::final(void)
{
      delete this;
}

bool MonSession::authenticate(const char *user, const char *pass)
{
      char **mem;
      struct group *grp;
      is_auth = is_admin = false;

#ifdef HAVE_PAM
      pam_handle_t *pamh;

      PAM_username = (char *)user;
      PAM_password = (char *)pass;
      if(pam_start("bayonne", user, &PAM_conversation, &pamh) != PAM_SUCCESS)
      {
            pam_end(pamh, 0);
            return false;
      }
      if(pam_authenticate(pamh, PAM_SILENT) != PAM_SUCCESS)
      {
            pam_end(pamh, 0);
            return false;
      }
      pam_end(pamh, PAM_SUCCESS);
      name = (char *)user;
      if(!stricmp(user, "root") || !stricmp(user, "bayonne"))
      {
            slog(Slog::levelNotice) << "tcpmon: " << user << " admin login" << endl;
            is_auth = is_admin = true;
      }
      else
      {
            grp = getgrnam("bayonne");
            if(!grp)
            {
                  endgrent();
                  return false;
            }

            mem = grp->gr_mem;
            if(!mem)
            {
                  endgrent();
                  return false;
            }
            while(*mem)
            {
                  if(!stricmp(*mem, user))
                        break;
                  mem++;
            }
            if(!*mem)
            {
                  endgrent();
                  return false;
            }
            endgrent();
            slog(Slog::levelNotice) << "tcpmon: " << user << " user login" << endl;
            is_auth = true;
            is_admin = false;
      }
#else
      struct passwd *pwd = getpwnam(user);
      if(!pwd)
      {
            endpwent();
            return false;
      }
      if(strcmp(crypt(pass, user), pwd->pw_passwd))
      {
            endpwent();
            return false;
      }
      if(pwd->pw_uid && stricmp(user, "bayonne"))
      {
            grp = getgrnam("bayonne");
            if(!grp)
            {
                  endgrent();
                  endpwent();
                  return false;
            }
            mem = grp->gr_mem;
            if(!mem)
            {
                  endgrent();
                  endpwent();
                  return false;
            }
            while(*mem)
            {
                  if(!stricmp(*mem, user))
                        break;
                  ++mem;
            }
            if(!*mem)
            {
                  endgrent();
                  endpwent();
                  return false;
            }
            slog(Slog::levelNotice) << "tcpmon: " << user << " user login" << endl;
            name = (char *)user;
            is_admin = false;
            is_auth = true;
      }
      else
      {
            slog(Slog::levelNotice) << "tcpmon: " << user << " admin login" << endl;
            name = (char *)user;
            is_admin = is_auth = true;
      }
      endgrent();
      endpwent();
#endif
      return is_auth;
}

bool MonSession::login(void)
{
        char buffer[1024];
        char *spc, *tok, *username = "", *passwd;

        *tcp() << "Login: ";
        flush();
        while(isPending(pendingInput, 60000))
        {
                getline(buffer, 1024);
                if(eof())
                        return false;

                spc = buffer;
                while(*spc == ' ' || *spc == '\r' || *spc == '\n')
                        ++spc;

                if(!*spc)
                        return false;

                spc = strtok_r(buffer, " \t\r\n", &tok);
                username = strdup(spc);
                *this << "Password: ";
                flush();
            break;
      }
      
      while(isPending(pendingInput, 60000))
      {
            getline(buffer, 1024);
            if(eof())
                  return false;

            spc = buffer;
            while(*spc == ' ' || *spc == '\r' || *spc == '\n')
                  ++spc;

            if(!*spc)
            {
                  *this << "Login Failed" << endl << endl;
                  flush();
                  return false;
            }

            spc = strtok_r(buffer, " \t\r\n", &tok);
            passwd = strdup(spc);
            if(authenticate(username, passwd))
                  return true;
            else
            {
                  *this << "Login Failed" << endl << endl;
                  flush();
                  return false;
            }
      }
      return false;
}

void MonSession::run(void)
{
      const char *node = keyserver.getNode();
      char buffer[1024];
      char fcmd[1024];
      bool rts;
      char *args[65];
      int argc = 0, tries = 0;
      char **argv = args;
      char *arg;
      char *sp;
      char *spc;

      is_admin = is_auth = false;

      setCancel(cancelImmediate);
      *tcp() << "Welcome to Bayonne " << getenv("SERVER_VERSION") << endl;
      *this << endl;

      while(tries < 3)
      {
            if(login())
                  break;
            tries++;
      }

      if(is_admin && is_auth)
            *this << node << "# ";  
      else if(is_auth)
            *this << node << "> ";
      flush();

      while(isPending(pendingInput, 600000) && (is_auth))
      {
            getline(buffer, 1024);
            if(eof())
                  break;
      
            spc = buffer;
            while(*spc == ' ' || *spc == '\r' || *spc == '\n')
                  ++spc;

            if(!*spc)
            {
                  if(is_admin)
                        *this << node << "# ";
                  else
                        *this << node << "> ";
                  flush();
                  continue;
            }

            sprintf(fcmd, "%s", buffer);

            argv[argc++] = strtok_r(buffer, " \t\n\r", &sp);
            while(argc < 64)
            {
                  arg = strtok_r(NULL, " \t\n\r", &sp);
                  if(!arg)
                        break;
                  argv[argc++] = arg;
            }
            argv[argc] = NULL;
      
            if(!stricmp(argv[0], "bye") || !stricmp(argv[0], "quit") || 
               !stricmp(argv[0], "exit"))
                  break;
            else if(!stricmp(argv[0], "version"))
                  rts = monVersion(argv, tcp());
            else if(!stricmp(argv[0], "status"))
                  rts = monStatus(argv, tcp());
            else if(!stricmp(argv[0], "driver"))
                  rts = monDriver(argv, tcp());
            else if(!stricmp(argv[0], "calls"))
                  rts = monCalls(argv, tcp());
            else if(!stricmp(argv[0], "dump"))
                  rts = monDump(argv, tcp());
            else if(!stricmp(argv[0], "modules"))
                  rts = monModules(argv, tcp());
            else if(!stricmp(argv[0], "trace"))
                  rts = monTrace(argv, tcp());
            else
            {
                  if(is_admin)
                  {
                        setCancel(cancelDeferred);
                        rts = fifo.command(fcmd, this);
                        setCancel(cancelImmediate);
                  }
                  else
                        rts = false;
            }

                if(rts)
                        *this << "END/command" << endl;
                else
                        *this << "ERR/command" << endl;
            if(is_admin)
                  *this << node << "# ";
            else
                  *this << node << "> ";
                flush();      
      }
        tcpmon.enterMutex();
        if(tcpmon.first == this)
                tcpmon.first = next;
        if(tcpmon.last == this)
                tcpmon.last = prev;
        if(next)
                next->prev = prev;
        if(prev)
                prev->next = next;
        slog(Slog::levelNotice) << "tcpmon: client disconnecting..." << endl;
        tcpmon.leaveMutex();
}

bool MonSession::monVersion(char **argv, ostream *out)
{
      *out << "version " << getenv("SERVER_VERSION") << endl;
      return true;
}

bool MonSession::monStatus(char **argv, ostream *out)
{
      char nodestat[255];

      driver->getStatus(nodestat);
      *out << nodestat << endl;
      return true;
}

bool MonSession::monDriver(char **argv, ostream *out)
{
      *out << "driver: " << plugins.getDriverName() << endl;
      *out << "mixers: " << driver->getMixers() << endl;
      *out << "ports:  " << driver->getTrunkCount() << endl;
      *out << "used:   " << driver->getTrunkUsed() << endl;
      return true;
}

bool MonSession::monCalls(char **argv, ostream *out)
{
      Trunk *trunk;
      TrunkGroup *group;
      char nodestat[255];
      char buffer[1024];
      int port;

      driver->getStatus(nodestat);
      for(port = 0; port < driver->getTrunkCount(); ++ port)
      {
            trunk = driver->getTrunkPort(port);
            if(!trunk)
                  return false;
            group = driver->getTrunkGroup(port);
            trunk->getName(buffer); 
            if(trunk->isReady())
            {
                  *out << group->getName() << ": " << buffer << " idle" << endl;
                  continue;
            }
            *out << group->getName() << ": " << buffer << " ";
            *out << nodestat[port] << " ";
            *out << trunk->getObject()->name << " ";
            *out << trunk->getSymbol(SYM_CALLER) << " ";
            *out << trunk->getSymbol(SYM_DIALED) << " ";
            *out << trunk->getSymbol(SYM_DURATION) << " ";
            *out << trunk->getSymbol(SYM_LANGUAGE) << endl;
      }
      return true;
}

bool MonSession::monDump(char **argv, ostream *out)
{
      Trunk *trunk;
      ScriptSymbol::Symbol *index[64];
      unsigned pos, count;
      int port;
            
      if(!argv[1])
            return false;

      count = pos = 0;

      port = atoi(argv[1]);
      trunk = driver->getTrunkPort(port);
      if(!trunk)
            return false;

      memset(index, 0, sizeof(index));

      count = trunk->gather(index, 63, "", NULL);

      while(pos < count)
      {
            *out << index[pos]->id << " = " << index[pos]->data << endl;
            ++pos;
      }

      return true;
}

bool MonSession::monModules(char **argv, ostream *out)
{
      //Module *mod;

      //mod = tcpmon.getFirst();

      //if(!mod)
      //    return true;

      //while(mod)
      //{
      //    *out << mod->getName() << endl;
      //    mod = mod->getNext();
      //}
      return true;
}

bool MonSession::monTrace(char **argv, ostream *out)
{
      Trunk *trk;
      TrunkEvent event;
      int port;
      char buffer[1024];
      char *spc;

      if(!argv[1])
            return false;

      port = atoi(argv[1]);
      trk = driver->getTrunkPort(port);
      if(!trk)
            return false;

      trace = trk;

      while(isPending(pendingInput, 600000))
      {
            getline(buffer, 1024);
            if(eof())
                  break;

            spc = buffer;
            while(*spc == ' ' || *spc == '\r' || *spc == '\n')
                  ++spc;

            if(!*spc)
                        continue;

            switch(*spc)
            {
            case 'h':
                      event.id = TRUNK_STOP_DISCONNECT;
                  trk->postEvent(&event);
                  continue;
            case 'b':
                  event.id = TRUNK_MAKE_BUSY;
                  trk->postEvent(&event);
                  continue;
            case 'd':
                  monDump(argv, tcp());
                  continue;
            case 'q':
                  trace = NULL;
                  return true;
            }
      }

      trace = NULL;
      return true;
}

void MonSession::putLine(char *str)
{
      *tcp() << str;
      flush();
}
            
#ifdef      CCXX_NAMESPACES
};
#endif

Generated by  Doxygen 1.6.0   Back to index