
/****************************************************************************/
/*                                                                          */
/*      NNstat -- Internet Statistics Collection Package                    */
/*                                                                          */
/*            Written by: Bob Braden & Annette DeSchon                      */
/*            USC Information Sciences Institute                            */
/*            Marina del Rey, California                                    */
/*                                                                          */
/*      Copyright (c) 1991 University of Southern California.               */
/*      All rights reserved.                                                */
/*                                                                          */
/*      Redistribution and use in source and binary forms are permitted     */
/*      provided that the above copyright notice and this paragraph are     */
/*      duplicated in all such forms and that any documentation,            */
/*      advertising materials, and other materials related to such          */
/*      distribution and use acknowledge that the software was              */
/*      developed by the University of Southern California, Information     */
/*      Sciences Institute.  The name of the University may not be used     */
/*      to endorse or promote products derived from this software           */
/*      without specific prior written permission.                          */
/*      THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR        */
/*      IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
/*      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR          */
/*      PURPOSE.                                                            */
/*                                                                          */
/****************************************************************************/

static char rcsid[]=
  "$Header: rspy.c,v 1.4 93/09/27 13:10:59 mogul Locked $";

/*
 *  Main rspy module -- remote control of statspy.
 *
 */
 
/*
 *  CHANGES:
 *     13Oct89 Merit: Add access controls
 *     17Oct89 AKS/RTB: subnet in help
 *       R2.4:
 *     30Nov89 ISI: Ask remote statspy for version #.
 *       Rel 3.0:
 *     Cisco: Config file error msg show line number.
 *     SGI: Support tersemode, one-column mode.
 *     SGI: Sys V changes.
 *     Aug93/DECWRL: Alpha/OSF port
 *     
 */
 
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <netdb.h>
#include <rpc/rpc.h>
#include "stat.h"
#include "sobj.h"

extern int  errno ;
extern Poller();    /* timer interrupt routine */
extern BrokenPipe();
 
struct sockaddr_in fromhost ;
int fromlen = sizeof(fromhost) ;
int TCP_port = STATD_PORT;
 
#define TIMEOUT  60 
int netclose() ; 

extern boolean tersemode, onecolmode;
extern int Xdebug;
extern char *SOBJ_error; 
time_t CurrTime;
#ifdef XPARSE
long CurrTimeMS;
#endif

FILE *TTYfp = NULL, *ninfp = NULL, *noutfp = NULL;
FILE *fpinit = NULL ;    /* File pointer -- initial config file */
FILE *logfp = stdout, *tracefp = stdout;
char rd_filename[256];   /* file name from 'file' command, or nul */
char *TraceFile = "";
            
#define POLLDEFAULT  60  
char Pollarg[64];
int Interval = 0;
int lsock = -1;
char rhost[256];
struct in_addr rhost_addr;
int Xdebug;
boolean isrspy = TRUE;


XDR W_XDR, R_XDR ;

#define LEXCALL  yylex(fp)
            
main(argc, argv)
    int argc ;
    char **argv ;
    {
    char *argscan();
    int rc, oldmask;
    extern u_long line_number;
    
    Xdebug = 0;
    gethostname(rhost, sizeof(rhost));
    
    if (--argc > 0 && **++argv == '?') {
        Usage() ;
        exit(0) ;
    }
        
    while (argc > 0 && **argv == '-') {
        switch (argv[0][1]) {
        
            case 'x':   /* -x    -- Debug flag  */
                Xdebug = 1 ;
                break ;
                
            case 'h':   /* -h host */
                strcpy(rhost, argscan(&argc, &argv));
                break;
                
            case 'p':  /* -p <TCP port#> */             
                TCP_port = atoi(argscan(&argc, &argv));
                break;

            case 't':   /* terse */
                tersemode = TRUE;
                break;

            case '1':   /* one column in read output */
                onecolmode = TRUE;
                break;

            default:    
                Usage() ;
                exit(1) ;
        } ;
        argv++;
        argc--;
    }
    
    if (argc > 0) {
            /* File contains configuration data */
    
        if (NULL == (fpinit = fopen(argv[0], "r"))) {
            perror("Cannot open parm file") ;
            exit(1) ;
        }
    }
        
    if (resolve_name(rhost, &rhost_addr, 1) < 1) {
        printf("Bad host: %s\n", rhost);
        exit(1);
    }
    CurrTime = time(0) ; 
    oldmask = sigblock(sigmask(SIGTTIN));  
        /* Block TTIN signal, so Read in background will not stop process */
       
    printf("Remote Access to ISI Statspy  %s", ctime(&CurrTime));
    signal(SIGALRM, Poller) ;
    signal(SIGPIPE, BrokenPipe);
    
    TTYfp = stdin;
    logfp = tracefp = stdout;
    
    /* Set up remote connection now, before possible call to Scan_Cmd() */
    if (!Rconnect()) {
	fprintf(stderr, "rspy: remote connect to %s failed\n", rhost);
	exit(1);
    }

    if (fpinit) { 
               /* Process configuration file */
        while ((rc = Scan_Cmd(fpinit, &W_XDR)) == CMD_OK);
        if (rc != CMD_EOF) {
            fprintf(stderr, "CONFIG FILE ERROR ON LINE %d\n", line_number);
            fflush(stdout);
            exit(1);
        }
    };
        
        /*
         *  MAIN LOOP ... awaiting console command
         */
    
    while (1) { 
            /* Prompt for new command line */           
        printf("Rspy>");
        fflush(stdout);
        
        rc = Scan_Cmd(TTYfp, &W_XDR);
        switch (rc) {
    
        case CMD_EOF:
            exit(1);
                            
        case CMD_OK:           
        case CMD_ERR:
            netclose();
            break;
        }
    };
}


Usage() {
    fprintf(stderr, 
  "Usage: rspy [-h host] [-p port#] [-t|-1] [-x] [enumfile]\n") ;
}

netclose() {
    if (lsock != -1) {
        xdr_destroy(&W_XDR);
        fclose(ninfp);
        fclose(noutfp);
    }
    lsock = -1 ;
}
       

BrokenPipe() {
    netclose;
}
                
SetPoll(interval, title)
    int interval;
    char *title;
    {
    strcpy(Pollarg, (title&&*title)?title:"*");
    Interval = (interval != -1) ? interval : POLLDEFAULT; 
    if (Interval) {
        alarm(Interval);
        printf("Polling Started -- %d secs\n", Interval);
    }
    else
        printf("Polling Stopped\n");
}
        
Poller()
    {   
    if (!Read_SOBJ(&W_XDR, Pollarg,0))
        printf("\nconn failed\n");  
    printf("\n");
    netclose();  /*19Feb88*/
    fflush(stdout);
    alarm(Interval);
}
    
            
char *argscan(argcp, argvp)
    int *argcp;
    register char ***argvp;
    {
    register char *cp;
    
    if (*(cp = 2+**argvp)) 
        return(cp);
    else if  (--*argcp > 0)
        return(*++*argvp);
    Usage();
    exit(1);
}

#define MAX_VERSION 256  /* Version number, or error reply */
    
boolean Rconnect()
    {
    int Vcode = VERSION_op, VResp_code, VResp_op;
    char temp[MAX_VERSION], *tempp= temp;
    char StatspyVersion[10];
    boolean Ropen();
    char *cp;
        
    resolve_name(rhost, &rhost_addr, 1);  /* already verified... */    
    if (lsock != -1) return(TRUE);
    
        /* Not open, open the TCP connection now */
    if (!Ropen(&rhost_addr)) return(FALSE);
    
        /* Now ask remote statspy for his version # */
    strcpy(StatspyVersion, "R<2.4");           
    if (!xdr_int(&W_XDR, &Vcode))  return(FALSE);
    Flush(&W_XDR);
    if (!xdr_int(&R_XDR, &VResp_code)) return(FALSE);
    if (VResp_code == RESP_OK) {
        if (!xdr_int(&R_XDR, &VResp_op) ||
            !xdr_string(&R_XDR, &tempp, MAX_VERSION))
                return(FALSE);
        for (cp= temp; *++cp != ' ';);  /* find first blank */
        *cp = '\0';
        strcpy(StatspyVersion, temp);
    }
    else {  /* Was old version that did not recognize the Version command,
             *  and rejected it with an error and closed the connection.
             */
        if (!xdr_string(&R_XDR, &tempp, MAX_VERSION))  /* ignore Err msg */
             return(FALSE);
        netclose();
        if (!Ropen(&rhost_addr)) return(FALSE);
    }
    printf("Connected to Statspy (%s) on Host: %s\n", StatspyVersion, rhost);   
    return(TRUE);
} /* Rconnect */


boolean Ropen(inetaddr)
   struct in_addr *inetaddr;
   {
    struct sockaddr_in sin ;
    extern char *SOBJ_error, Error_msg[], *sys_errlist[];
    int lsock2; /* for SYS V */
          
    if ((lsock = socket(AF_INET, SOCK_STREAM, 0))< 0) {
        perror("Socket Error") ;
        exit(2) ;
    } 
    sin.sin_family = AF_INET;
    sin.sin_port = htons((u_short) TCP_port);
    sin.sin_addr.s_addr = inetaddr->s_addr; 
    if (connect(lsock, &sin, sizeof(sin)) < 0) {
        sprintf(SOBJ_error = Error_msg, "Conn failed -- %s",
                          sys_errlist[errno]);
        close(lsock);
        lsock = -1;
        return(FALSE);
    }
#ifdef SYSV
    lsock2 = dup(lsock);
#endif
    if ((ninfp = fdopen(lsock, "r")) == NULL||
#ifdef SYSV
        (noutfp = fdopen(lsock2, "w")) == NULL) {
#else
        (noutfp = fdopen(lsock, "w")) == NULL) {
#endif
           perror("fdopen fail--");
        exit(2);
    }
         
    xdrstdio_create(&W_XDR, noutfp, XDR_ENCODE);
    xdrstdio_create(&R_XDR, ninfp, XDR_DECODE);
    return(TRUE);
}  /* Ropen() */


boolean Start_Read(rdh, rspP)
    int rdh;
    OBJ *rspP;
    {
      /* Stub... function unneeded */
    return(TRUE);
}

End_Read()
    {
      /* Stub... function unneeded */
}


Do_help()
    {
    printf(
"Remote cmds:\n\
     read <obj-spec>      read ?     clear <obj-spec> \n\
     show <field-spec>    show ?     subnet <addr> <mask>   subnet ?\n\
     attach {<attach-parms>}     detach <obj-spec>\n\
Local cmds:\n\
    enum  {<enum-parms>}        enum ?\n\
    host <name/number>          quit\n\
    poll <time> <obj-spec>\n\n");
}


Do_host(hname)
    char *hname;
    {
    strcpy(rhost, hname);
    if (resolve_name(rhost, &rhost_addr, 1) < 1) 
        printf("Bad host: %s\n", rhost);
}


boolean Do_restrict(rw, parm)
    boolean rw;
    struct restrict_parm parm;
    {
    printf("Cannot execute remotely\n");
    return(CMD_ERR);
}

Show_restrict()
    {
    printf("Cannot execute remotely\n");
    return(CMD_ERR);
}
