#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#ifdef _WIN32
 #include <arpa/inet.h>
#endif

#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "parse_ip.h"

extern char *optarg;
extern int optind;
extern int errno;

char *outputfile = NULL; /* where to put output */
char *userfile = NULL;   /* where to get usernames */
char *passfile = NULL;   /* where to get passwords */
FILE *userfd = NULL;     /* userlist file stream */
FILE *passfd = NULL;     /* passlist file stream */

struct vuln_res {
  u_long vr_vulid;
  char **vr_output;
  struct vuln_res *vr_next;
};

void natprintf(char *format, ...);
struct vuln_res *module_16000();

int main(argc, argv)
int argc;
char **argv;
{
   struct vuln_res *vr;
   u_long ipaddr;
   int opt;
   char *progname;
   struct ipstr *hosts;

   progname = strdup(argv[0]);

   while ((opt = getopt(argc, argv, "o:u:p:")) != -1)
      switch(opt) {
         case 'o': outputfile = strdup(optarg);
                   break;
         case 'u': userfile = strdup(optarg);
                   break;
         case 'p': passfile = strdup(optarg);
                   break;
         default : exit(-1);
      }

   argc -= optind;
   argv += optind;

   if (argc < 1) {
      fprintf(stderr,"usage: %s [-o filename] [-u userlist] [-p passlist]"\
              " <address>\n", progname);
      exit(1);
   }

   if (userfile) {
      if ((userfd = fopen(userfile, "r")))
         natprintf("[*]--- Reading usernames from %s\n", userfile);
      else {
         natprintf("[*]--- Error: cannot open %s\n", userfile);
         exit(-1);
      }
   }

   if (passfile) {
      if ((passfd = fopen(passfile, "r")))
         natprintf("[*]--- Reading passwords from %s\n", passfile);
      else {
         natprintf("[*]--- Error: cannot open %s\n", passfile);
         exit(-1);
      }
   }

   if ((passfile && !userfile) || (userfile && !passfile)) {
      natprintf("[*]--- Please specify both userlist and password list\n");
      exit(-1);
   }

   for (hosts=(struct ipstr *)parse_ip(argv[0]); hosts; hosts=hosts->next) {
      natprintf("\n[*]--- Checking host: %s\n", hosts->name);

      if (userfd)
         rewind(userfd);
      if (passfd)
         rewind(passfd);

      /*
       * Run the checks
       */
      if ((vr=module_16000(inet_addr(hosts->name)))==NULL) {
       natprintf("[*]--- Was not able to obtain any information from "\
                 "remote server\n");
      }
   }

   if (userfd)
      fclose(userfd);
   if (passfd)
      fclose(passfd);

#ifndef VERBOSE
   for (; vr; vr = vr->vr_next) {
      char **ptr;

      natprintf("\n");
      for (ptr = vr->vr_output; *ptr; ptr++)
	natprintf("%lu: %s\n", vr->vr_vulid, *ptr);
   }
#endif
   exit(0);
}

struct vuln_res * bugblk;	/* generic one to build a chain thereof */
struct vuln_res * bughead;	/* start of [malloced] chain */
struct vuln_res * prev_bugblk;	/* temporary "backlink" pointer */
int ptr_vuln = 0;
int idx_vuln = 1;
int cur_vuln = 0;
char * vuln_strings[128] = {
  "", "", "", ""			/* will be filled in later on */
};
int vuln_ids [128];			/* corresponding bug-ID block */
char * vvr_strings[256];		/* ptr block for selected items */
int ptr_vvr = 0;			/* and *its* index */

static u_long prev_ip = { 0L };		/* really shd be in_addr */
static int prev_res = 0;

void donothing () {}			/* printf / fprintf fakeout */

extern char * get_block();
extern int fill_block();

int fill_vuln (char * flag, char * str)
{
  char buf [128];
  register char * p;
  register int x;

  if (! flag)				/* various safety checks */
    return (0);
  if (cur_vuln <= 0)
    return (0);
  if (ptr_vuln > 127)
    return (0);
  StrnCpy (buf, flag, 40);
  x = strlen (buf);
  p = buf + x;
  x = 79 - x;
  StrnCpy (p, str, x);			/* jam it in where we can */
  buf[79] = '\0';
  x = fill_block (vuln_strings, buf);
  if (x >= 0) {
    vuln_ids[x] = cur_vuln;		/* stash bugid of this string, too */
    ptr_vuln++;
  }
  return (x);				/* preserve returned idx! */
} /* fill_vuln */

char * get_vuln (int id)
{
  register int x;

  while (ptr_vuln < 127) {
    ptr_vuln++;				/* preindex; first item is [1] */
    if (vuln_ids[ptr_vuln] == id) {
      x = ptr_vuln;
      return (get_block (vuln_strings, x));
    }
  } /* while ptr_vuln */
  return (NULL);			/* oops, no more vulns! */
} /* get_vuln */

int clear_block (blk, idx)
  char ** blk;
  int idx;
{
  static char * nullstr = "";
  register int x = idx;

  if (x <= 0)				/* entry 0 is special */
    goto cbbogus;
  if (! blk)
    goto cbbogus;
  while (x < 128) {			/* more runaway protection */
    if (blk[x] == NULL)
      break;				/* done! */
    if (blk[x][0]) {
      blk[x][0] = '\0';			/* zap any old content */
      free (blk[x]);			/* and throw this fish back in */
    }
    blk[x] = nullstr;
    x++;
  }
  return (1);
cbbogus:
  fprintf (stderr, "OOPS! clear_block tried to clear bogus entry %d @ %x\n",
    idx, blk);
  return (0);
} /* clear_block */

struct vuln_res * module_16000(ipaddr)
u_long ipaddr;
{
  register int i;
  register char * pp;
  char *buf, **ptr;
  int strsize;

  if (ipaddr == 0L)
    return ((struct vuln_res *) -1);
  if (ipaddr != prev_ip) {		/* got a new host to check? */
    clear_block (vuln_strings, 1);	/* in case it contains old stuff */
    for (i = 1; i < 127; i++) {
      vuln_strings[i] = vuln_strings[0];
      vuln_ids[i] = 0;
    }
    vuln_strings[127] = NULL;		/* put in end-of-block indicator */
    i = nas_step (ipaddr);		/* summon the big ol' monster */
    prev_ip = ipaddr;			/* record the fact that we did */
    prev_res = i;			/* and the outcome */
  } /* if new ipaddr */

  if (prev_res == 0)
    return ((struct vuln_res *) NULL);	/* no netbios there, buckaroo */

  ptr_vvr = 0;
  prev_bugblk = NULL;
  bughead = NULL;
  for (i = 16000 ; i <= 16010 ; i++) {	/* applicable bug-ID range */
    ptr_vuln = 0;			/* restart results index */
    pp = get_vuln (i);			/* anything for this bug-ID? */
    if (!pp)
      continue;				/* nope, skip it */

    bugblk = (struct vuln_res *) malloc (sizeof (struct vuln_res));
    if (!bugblk)
      continue;				/* or try to, anyway.. */

    if (prev_bugblk) {
      prev_bugblk->vr_next = bugblk;	/* hook up the chain */
    } else {
      bughead = bugblk;			/* save the start point */
    }

    prev_bugblk = bugblk;		/* and dangle the next link */
    bugblk->vr_vulid = i;
    bugblk->vr_output = &vvr_strings[ptr_vvr];	/* ack!! */
    bugblk->vr_next = NULL;
    vvr_strings[ptr_vvr] = pp;		/* chain off to real result string */
    ptr_vvr++;

    while (pp = get_vuln (i)) {		/* collect the rest of 'em */
      vvr_strings[ptr_vvr] = pp;
      ptr_vvr++;
    }
    vvr_strings[ptr_vvr] = NULL;	/* terminate this block */
    ptr_vvr++;				/* and point just past it */

  } /* for i = bugid */

  for (prev_bugblk = bughead; prev_bugblk;
       prev_bugblk = prev_bugblk->vr_next) {
    strsize = 0;
    for (ptr = prev_bugblk->vr_output; *ptr; ptr++)
       strsize += strlen(*ptr)+10;
    buf = (char *)malloc(strsize+100);
    memset(buf, 0, strsize+100);
    for (ptr = prev_bugblk->vr_output; *ptr; ptr++) {
       strcat(buf, *ptr);
       strcat(buf, "\n");
    }
    prev_bugblk->vr_output = (char **)malloc(2);
    prev_bugblk->vr_output[0] = buf;
    prev_bugblk->vr_output[1] = NULL;
  }

  return (bughead);
}

/*
 * Write format to file, opening file if it's not open
 */
#ifdef __STDC__
void natprintf(char *format, ...)
{
#else
void natprintf(va_alist)
va_dcl
{
  char *format;
#endif
  va_list ap;
  static FILE *outfd = NULL;
  char *s;

#ifdef __STDC__
   va_start(ap, format);
#else
   va_start(ap);
   format = va_arg(ap,char *);
#endif

   vfprintf(stdout, format, ap);

   if (!outputfile)
      return;

   if (!outfd) {
      if (!(outfd = fopen(outputfile, "a"))) {
         fprintf(stderr, "[*]--- Error: Unable to open: %s\n", outputfile); 
         exit(-1);
      }
   }

   vfprintf(outfd, format, ap);
   return;
}
