/* Nessus
 * Copyright (C) 1998 Renaud Deraison
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Plugins Loader
 *
 */
 
#include <includes.h>


#ifdef NESSUSNT
#include "wstuff.h"
#endif

#include "pluginload.h"
#include "log.h"


static void nes_plugin_add(char *, char *, struct arglist *, struct arglist *);
/*
 * main function for loading all the
 * plugins that are in folder <folder>
 */
struct arglist * 
plugins_init(preferences)
 struct arglist * preferences;
{
#ifndef NESSUSNT
  DIR * dir;
  struct dirent * dp;
#ifdef USE_PTHREADS
  struct dirent * dp2;
#endif

#else
  WIN32_FIND_DATA filedata;
  HANDLE search;
  int finished = 0;
#endif
  struct arglist * plugins;
  struct arglist * scanners;
  struct arglist * ret;
  char * folder = arg_get_value(preferences, "plugins_folder");
  if(!folder)
    {
#ifdef DEBUG
      log_write("%s:%d : folder == NULL\n", __FILE__, __LINE__);
#endif
      print_error("could not determine the value of <plugins_folder>. Check %s\n",
      	(char *)arg_get_value(preferences, "config_file"));
      DO_EXIT(0);
    }
#ifndef NESSUSNT
  if(!(dir = opendir(folder)))
#else
  SetCurrentDirectory(folder);
  search = FindFirstFile("*.nes", &filedata);
  if(search == INVALID_HANDLE_VALUE)
#endif
    {
      print_error("Couldn't open the directory called \"%s\"\nCheck %s\n", folder,
      		   (char *)arg_get_value(preferences, "config_file"));
      DO_EXIT(1);
    }
  plugins = emalloc(sizeof(struct arglist));
  scanners = emalloc(sizeof(struct arglist));
  ret = emalloc(sizeof(struct arglist));
  arg_add_value(ret, "plugins", ARG_ARGLIST, -1, plugins);
  arg_add_value(ret, "scanners", ARG_ARGLIST, -1, scanners);
  /*
   * Add the the .nes plugins
   */
#ifndef NESSUSNT
#ifndef USE_PTHREADS
  while((dp = readdir(dir)))
#else
   dp = NULL;
   dp2 = emalloc(sizeof(struct dirent));
   readdir_r(dir,dp2, &dp); 
   while(dp)
#endif
   {
    if ((NAMLEN(dp)>4) && !strcmp(".nes", (dp->d_name+NAMLEN(dp)-4)))
     nes_plugin_add(folder, dp->d_name, ret, preferences);
#ifdef USE_PTHREADS
    dp = NULL;
    if(readdir_r(dir, dp2, &dp))dp = NULL;
#endif
   }
#else
   while(!finished)
     {
      nes_plugin_add(folder, filedata.cFileName, ret, preferences);
      if(!FindNextFile(search, &filedata))finished = 1;
     }
#endif

#ifndef NESSUSNT
  rewinddir(dir);
#ifdef USE_PTHREADS
  efree(&dp2);
#endif
#else
  FindClose(search);
#endif  
  return(ret);
}

/*
 * add *one* .nes (shared lib) plugin to the server list
 */
static void 
nes_plugin_add(folder, name, plugins_all, preferences)
     char * folder;
     char * name;
     struct arglist * plugins_all;
     struct arglist * preferences;
{
 ext_library_t ptr = NULL; 
 char * fullname = NULL;
 struct arglist * plugins = arg_get_value(plugins_all, "plugins");
 struct arglist * scanners = arg_get_value(plugins_all, "scanners");
#ifndef NESSUSNT
  fullname = emalloc(strlen(folder)+strlen(name)+2);
  sprintf(fullname, "%s/%s", folder, name);
#else
 fullname = emalloc(strlen(name)+1);
 strncpy(fullname, name, strlen(name));
#endif /* not defined(NESSUSNT) */

  if((ptr = LOAD_LIBRARY(fullname))==NULL){
    log_write("Couldn't load %s\n", name);
#ifndef NESSUSNT
    log_write("Error : %s\n", LIB_LAST_ERROR());
#else
    log_write("Error : %d\n", LIB_LAST_ERROR());
#endif
  }
  else {
    struct arglist * plugin;
    plugin_init_t  f_init;
    struct arglist * p_args;
    struct arglist * args;
    plugin = emalloc(sizeof(struct arglist));   
    if((f_init = (plugin_init_t)LOAD_FUNCTION(ptr, "plugin_init")) ||
    	(f_init = (plugin_init_t)LOAD_FUNCTION(ptr, "_plugin_init")))
      {
      	p_args = emalloc(sizeof(struct arglist));
      	arg_add_value(p_args, "preferences", ARG_ARGLIST, -1, (void*)preferences);
      	(*f_init)(p_args);
        args = emalloc(sizeof(struct arglist));
        arg_dup(args, p_args);
        arg_free(p_args);
 	arg_add_value(plugin, "plugin_args", ARG_ARGLIST, -1, (void *)args);
        arg_add_value(plugin, "full_name", ARG_STRING, -1, fullname);
 	plug_set_launch(args, 0);
        if((int)arg_get_value(args, "CATEGORY")==ACT_SCANNER)
         arg_add_value(scanners, name, ARG_ARGLIST, -1, (void *)plugin);
        else
 	 arg_add_value(plugins, name, ARG_ARGLIST, -1, (void *)plugin);
      }
    else log_write("Couldn't find the entry point in %s [%s]\n", name,LIB_LAST_ERROR());
    CLOSE_LIBRARY(ptr);
  }
}
 
/*
 * Put our socket somewhere in the plugins
 * arguments
 */
void 
plugins_set_socket(struct arglist * plugins, int soc)
{
  struct arglist * t, *v;

  t = plugins;
  while(t && t->next)
    {
     v = arg_get_value(t->value, "plugin_args");
     if(v)arg_add_value(v, "SOCKET", ARG_INT, sizeof(int), (void *)soc);
     t = t->next;
    }
}
