#define  KILLMINUTES 15       /* Change this to change idle kill value */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <sys/types.h>
#include <syslog.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/param.h>
#include <dirent.h>
#include <signal.h>

/* Structure which holds information regarding users currently online.. */
/* This is the same structure written to/read from pid files. */
struct ONLINE
{
  char   username[24];
  int    groupid;
  char   tagline[64];
  char   status[41];
  char   host[256];
  char   currentdir[256];
  time_t login_time;
  time_t last_update;
  pid_t  procid;
  double last_rate;
  struct ONLINE *next;
  struct ONLINE *prev;
};

int debug = 0;
char config_file[] = "/etc/glftpd.conf";


/***************************************************************************
	TRIM
	Trims a string. ("    TEST    BBOY    " becomes "TEST BBOY")
***************************************************************************/

char *
trim( char *str )
{
	char *ibuf;
	char *obuf;

   if ( str )
   {
   	for ( ibuf = obuf = str; *ibuf; )
      {
        	while ( *ibuf && ( isspace ( *ibuf ) ) )
         	ibuf++;
        	if ( *ibuf && ( obuf != str ) )
            *( obuf++ ) = ' ';
        	while ( *ibuf && ( !isspace ( *ibuf ) ) )
            *( obuf++ ) = *( ibuf++ );
      }
      *obuf = '\0';
   }
   return( str );
}
/*-- end of trim() -------------------------------------------------------*/
				 

/***************************************************************************
	LOAD_SYSCONFIG
	Loads data from system configuration file.
***************************************************************************/

void 
load_sysconfig( void )
{
   FILE *configfile;
   char lvalue[ 64 ];
   char rvalue[ MAXPATHLEN ];
   int  x, y;
	char work_buff[ MAXPATHLEN ];

   sprintf( work_buff, "%s",config_file);

   if ( ( configfile = fopen( work_buff, "r" ) ) == NULL )
	{
		fprintf( stderr, "bad or missing 'CONFIG FILE', using defaults\n" );
      return;
	}

   while ( 1 )
   {
      if ( fgets( work_buff, sizeof( work_buff ), configfile ) == NULL )
      {
         fclose( configfile );
         return;
      }

      /* Clip out comments */
      for ( x = 0; x < strlen( work_buff ); x++ )
         if ( work_buff[ x ] == '#' )
            work_buff[ x ] = '\0';
				
		/* Trim */
		(void)trim( work_buff );
      
      /* Clear out old values */
      memset( lvalue, '\0', sizeof( lvalue ) );
      memset( rvalue, '\0', sizeof( rvalue ) );
													 
		/* The file allows spaces embedded, but clears leading & trailing 
			spaces */
		
      /* Parse lvalue */
      y = 0;
      for ( x = 0; x < strlen( work_buff ) && work_buff[ x ] != ' '; x++ )
         if ( isprint( work_buff[ x ] ) )
            lvalue[ y++ ] = work_buff[ x ];

      /* Parse rvalue */
      y = 0; x++;
      for ( ; x < strlen( work_buff ); x++ )
         if ( isprint( work_buff[ x ] ) )
            rvalue[ y++ ] = work_buff[ x ];
      
      if ( strcasecmp( lvalue, "datapath" ) == 0 )
	   	strncpy( cf.datapath, rvalue, sizeof( cf.datapath ) );
      if ( strcasecmp( lvalue, "rootpath" ) == 0 )
                strncpy( cf.rootpath, rvalue, sizeof( cf.rootpath ) );
   }

   return;
}
/*-- end of load_sysconfig() ----------------------------------------------*/




/***************************************************************************
  CHECKUSERS
***************************************************************************/

int
checkusers(void)
{
  DIR *dirf;
  struct dirent *dn;
  struct stat st;
  char temppath[256];
  FILE *fp;
  struct ONLINE newuser;
  int found = 0;
  int killthis = 0;
															
  /*
   * Open directory
   */							
	sprintf( temppath, "%s/%s/pids", cf.rootpath, cf.datapath );
  	dirf = opendir (temppath);
  	if (!dirf)
    {
      syslog (LOG_ERR, "[b/b]: Error opening dir '%s': %m", temppath);
      return 0;
    }
  
  /*
   * Scroll thru /.ftp-data/pids looking for files (processes)
   */
  
  	while (1)
   {
   	dn = readdir (dirf);	/* Read directory entry */
      if (!dn)			/* We done yet? */
			break;
      
      if (!strcmp (dn->d_name, ".") || !strcmp (dn->d_name, ".."))
			continue;

      sprintf (temppath, "%s/%s/pids/%s", cf.rootpath, cf.datapath, dn->d_name);
      stat (temppath, &st);	/* Stat file */
      
      if (S_ISREG (st.st_mode))	/* Found one? */
		{
	  		/* open the pidfile */
	  		if ((fp = fopen (temppath, "r")) == NULL)
	    	{
	      	if (errno != ENOENT)
				{
		  			syslog (LOG_ERR, "[b/b]: Error opening file '%s': %m", 
			  				  temppath);
				}
				
	      	continue;
	    	}

	  		fread (&newuser, sizeof( struct ONLINE ), 1, fp );
	  		fclose( fp );

			if ( kill( newuser.procid, 0 ) != 0 )
				killthis = 1;
			else
				killthis = 0; 

#ifndef CRC
			if ( (time( NULL ) - newuser.last_update) > (KILLMINUTES * 60) )
				killthis = 2;
#endif
			  
			if ( debug )
				fprintf( stdout, "%-8.8s %-36.36s %6d ------- %-6.6s",
							newuser.username, newuser.status, newuser.procid, 
							(killthis)?"KILL":"Cool" );
							
			if ( killthis )
			{
				unlink( temppath );
			}
			
			if ( killthis == 2 )
			{
				kill( newuser.procid, 9 );
			}

	  		found++;
		}
  	}

  (void) closedir (dirf);

  return (found);
}
/*-- end of checkusers() -------------------------------------------------*/


/***************************************************************************
	MAIN
***************************************************************************/
                                   
int
main( int argc, char **argv )
{
   int numusers = 0;
   
   if ( argc > 1 )
   {
      if ( strcasecmp( argv[ 1 ], "debug" ) == 0 )
         debug = 1;
      if ( strcasecmp( argv[ 1 ], "-r" ) == 0 )
	strcpy(config_file, argv[2]);
  }  
	
	openlog( "ftpghost", LOG_PID | LOG_NDELAY, LOG_DAEMON );
	
	load_sysconfig();
	
   if ( debug )
   {
      fprintf( stdout, "Username Status                               PROCID Minutes Action\n" );
      fprintf( stdout, "-------- ------------------------------------ ------ ------- ------\n" );
   }      
	
	numusers = checkusers();
   
   if ( debug )
      fprintf( stdout, "\n%d users online.\n", numusers );
      
   return 0;
}
/*-- end of main() -------------------------------------------------------*/

