Exemple #1
0
/*
 * execute the given command
 */
static int func_exec(struct filter_op *fop)
{
   pid_t pid;
   
   DEBUG_MSG("filter engine: func_exec: %s", fop->op.func.string);
   
   /* 
    * the command must be executed by a child.
    * we are forwding packets, and we cannot wait 
    * for the execution of the command 
    */
   pid = fork();
   
   /* check if the fork was successfull */
   if (pid == -1)
      SEMIFATAL_ERROR("filter engine: fork() failed, cannot execute %s", fop->op.func.string);
   
   /* differentiate between the parent and the child */
   if (!pid) {
      char **param = NULL;
      char *q = fop->op.func.string;
      char *p;
      int i = 0;

      /* split the string */
      for (p = strsep(&q, " "); p != NULL; p = strsep(&q, " ")) {
         /* allocate the array */
         SAFE_REALLOC(param, (i + 1) * sizeof(char *));
         
         /* copy the tokens in the array */
         param[i++] = strdup(p); 
      }
      
      /* NULL terminate the array */
      SAFE_REALLOC(param, (i + 1) * sizeof(char *));
      
      param[i] = NULL;
     
      /* 
       * close input, output and error.
       * we don't want to clobber the interface 
       * with output from the child
       */
      close(fileno(stdin));
      close(fileno(stdout));
      close(fileno(stderr));
      
      /* execute the command */
      execve(param[0], param, NULL);

      /* reached on errors */
      exit(-1);
   }
      
   return ESUCCESS;
}
static void join_print_po(struct packet_object *po)
{
   int ret;
   
   /* check if the object exists */
   if (wdg_conndata == NULL || wdg_join == NULL)
      return;

   /* if not focused don't refresh it */
   if (!(wdg_conndata->flags & WDG_OBJ_FOCUSED))
      return;
   
   /* check the regex filter */
   if (GBL_OPTIONS->regex && 
       regexec(GBL_OPTIONS->regex, (const char*)po->DATA.disp_data, 0, NULL, 0) != 0) {
      return;
   }
   
   /* use the global to reuse the same memory region */
   SAFE_REALLOC(dispbuf, hex_len(po->DATA.disp_len) * sizeof(u_char) + 1);
      
   /* format the data */
   ret = GBL_FORMAT(po->DATA.disp_data, po->DATA.disp_len, dispbuf);
   dispbuf[ret] = 0;
        
   if (!ip_addr_cmp(&po->L3.src, &curr_conn->L3_addr1))
      wdg_scroll_print(wdg_join, EC_COLOR_JOIN1, "%s", dispbuf);
   else
      wdg_scroll_print(wdg_join, EC_COLOR_JOIN2, "%s", dispbuf);
}
HRESULT CStorageBuffer::SetSize(	ULARGE_INTEGER libNewSize)		//Specifies the new size of the stream object
{
	HRESULT hr = STG_E_MEDIUMFULL;
	void* pBuffer = m_pBuffer;

	//The value of the libNewSize parameter is not valid. 
	//Since streams cannot be greater than 2^32 bytes in the COM-provided 
	//implementation, the high DWORD of libNewSize must be 0. 
	//If it is nonzero, this parameter is not valid. 
	if(libNewSize.QuadPart > ULONG_MAX)
	{
		hr = STG_E_INVALIDFUNCTION;
		goto CLEANUP;
	}
	
	//Use a copy variable, incase allocations fail...
	SAFE_REALLOC(pBuffer, BYTE, libNewSize.QuadPart);

	m_pBuffer = pBuffer;
	m_cMaxSize = (ULONG)libNewSize.QuadPart;
	hr = S_OK;

CLEANUP:
	TRACE_METHOD(hr, L"\tIStream::SetSize(%d)", (ULONG)libNewSize.QuadPart);
	return hr;
}
static void split_print_po(struct packet_object *po)
{
   int ret;
   
   /* if not open don't refresh it */
   if (!data_window)
      return;
   
   /* check the regex filter */
   if (GBL_OPTIONS->regex && 
       regexec(GBL_OPTIONS->regex, po->DATA.disp_data, 0, NULL, 0) != 0) {
      return;
   }
   
   /* use the global to reuse the same memory region */
   SAFE_REALLOC(dispbuf, hex_len(po->DATA.disp_len) * sizeof(u_char) + 1);
      
   /* format the data */
   ret = GBL_FORMAT(po->DATA.disp_data, po->DATA.disp_len, dispbuf);
   dispbuf[ret] = 0;
        
   if (!ip_addr_cmp(&po->L3.src, &curr_conn->L3_addr1))
      gtkui_data_print(1, dispbuf, 0);
   else
      gtkui_data_print(2, dispbuf, 0);
}
/////////////////////////////////////////////////////////////////
// HRESULT CDataset::GetCellData
//
/////////////////////////////////////////////////////////////////
HRESULT CDataset::GetCellData(DBORDINAL ulStartCell, DBORDINAL ulEndCell)
{
	HRESULT hr = E_FAIL;
	
	if(m_pIMDDataset)
	{
		//NOTE: Using cbRowSize of IAccessor::CreateAccessor
		//Because this method fetches properties for more than one cell, 
		//the provider should know how long each row is. In this context, a "row" means the area 
		//allocated in the consumer's buffer to hold all properties pertaining to one cell. 
		//This information should be given in the cbRowSize parameter of IAccessor::CreateAccessor. 
		//If the value of this parameter is zero, the consumer wants to fetch only one row of data 
		//(one cell). In this case, it is an error to specify a ulStartCell different from the 
		//ulEndCell.
		
		//Because of the above in the OLAP spec, we need to make sure our buffer is large enough
		//to hold the number of requested cells...
		if(ulEndCell > ulStartCell && m_cbRowSize)
			SAFE_REALLOC(m_pData, BYTE, m_cbRowSize * (ulEndCell - ulStartCell + 1));

		//IMDDataset::GetCellData
		XTEST(hr = m_pIMDDataset->GetCellData(m_hAccessor, ulStartCell, ulEndCell, m_pData));
		TESTC(TRACE_METHOD(hr, L"IMDDataset::GetCellData(0x%p, 0x%Id, 0x%Id, 0x%p)", m_hAccessor, ulStartCell, ulEndCell, m_pData));
 	}

CLEANUP:
	return hr;
}
Exemple #6
0
int replacer_feed(void *self, const char *in, int inl) {
   struct replacer_obj *rep = (struct replacer_obj *) self;

   /* sanity check */
   if (self == NULL)
      return 0;

   /* append the data to the buffer */
   SAFE_REALLOC(rep->buf, rep->bsize + inl + sizeof(char));
   memcpy(rep->buf + rep->bsize, in, inl);
   rep->bsize += inl;
   /* null terminate */
   memset(rep->buf + rep->bsize, '\0', sizeof(char));

   /* sanity check */
   if (rep->search == NULL || rep->replace == NULL) {
      DEBUG_MSG(D_ERROR, "replacer_feed: cannot search for NULL");
      return rep->bsize;
   }

   /* replace the 'search' string with the 'replace' one */
   str_replace(&rep->buf, rep->search, rep->replace);

   /* calculate the new size */
   rep->bsize = strlen(rep->buf);

   return rep->bsize;
}
Exemple #7
0
/*
 * callback function for displaying the plugin list 
 */
static void curses_wdg_plugin(char active, struct plugin_ops *ops)
{
   /* enlarge the array */ 
   SAFE_REALLOC(wdg_plugin_elements, (nplug + 1) * sizeof(struct wdg_list));

   /* fill the element */
   SAFE_CALLOC(wdg_plugin_elements[nplug].desc, MAX_DESC_LEN + 1, sizeof(char));
   snprintf(wdg_plugin_elements[nplug].desc, MAX_DESC_LEN, "[%d] %15s %4s  %s", active, ops->name, ops->version, ops->info);  
   wdg_plugin_elements[nplug].value = ops->name;
   
   nplug++;
   
   /* null terminate the array */ 
   SAFE_REALLOC(wdg_plugin_elements, (nplug + 1) * sizeof(struct wdg_list));
   wdg_plugin_elements[nplug].desc = NULL;
   wdg_plugin_elements[nplug].value = NULL;
}
/*
 * inject output of a executable into the communication
 */
static int func_execinject(struct filter_op *fop, struct packet_object *po)
{
   FILE *pstream = NULL;
   unsigned char *output = NULL;
   size_t n = 0, offset = 0, size = 128;
   unsigned char buf[size];
   
   /* check the offensiveness */
   if (GBL_OPTIONS->unoffensive)
      JIT_FAULT("Cannot inject packets in unoffensive mode");
   

   DEBUG_MSG("filter engine: func_execinject %s", fop->op.func.string);
   
   /* open the pipe */
   if ((pstream = popen((const char*)fop->op.func.string, "r")) == NULL) {
      USER_MSG("filter engine: execinject(): Command not found (%s)\n", fop->op.func.string);
      return -E_FATAL;
   }
   
   while ((n = read(fileno(pstream), buf, size)) != 0) {
      if (output == NULL) {
         SAFE_CALLOC(output, offset+n, sizeof(unsigned char));
      }
      else {
         SAFE_REALLOC(output, sizeof(unsigned char)*(offset+n));
      }

      memcpy(output+offset, buf, n);
      offset += n;
   }
   
   /* close pipe stream */
   pclose(pstream);

   /* check if we are overflowing pcap buffer */
   if(GBL_PCAP->snaplen - (po->L4.header - (po->packet + po->L2.len) + po->L4.len) <= po->DATA.len + (unsigned)offset)
      JIT_FAULT("injected output too long");
         
   /* copy the output into the buffer */
   memcpy(po->DATA.data + po->DATA.len, output, offset);

   /* Adjust packet len and delta */
   po->DATA.delta += offset;
   po->DATA.len += offset;    

   /* mark the packet as modified */
   po->flags |= PO_MODIFIED;
   
   /* unset the flag to be dropped */
   if (po->flags & PO_DROPPED)
      po->flags ^= PO_DROPPED;

   /* free memory */
   SAFE_FREE(output);
   
   return E_SUCCESS;
}
Exemple #9
0
/*
 * disable segmentation offload on interface
 * this prevents L3 send errors (payload too large)
 */
void disable_interface_offload(void)
{
	int param_length= 0;
	char *command;
	char **param = NULL;
	char *p;
	int ret_val, i = 0;

	SAFE_CALLOC(command, 100, sizeof(char));

	BUG_IF(command==NULL);

	memset(command, '\0', 100);	
	snprintf(command, 99, "ethtool -K %s tso off gso off gro off lro off", EC_GBL_OPTIONS->iface);

	DEBUG_MSG("disable_interface_offload: Disabling offload on %s", EC_GBL_OPTIONS->iface);

	for(p = strsep(&command, " "); p != NULL; p = strsep(&command, " ")) {
		SAFE_REALLOC(param, (i+1) * sizeof(char *));
		param[i++] = strdup(p);	
	}

	SAFE_REALLOC(param, (i+1) * sizeof(char *));
	param[i] = NULL;
	param_length= i + 1; //because there is a SAFE_REALLOC after the for.

	switch(fork()) {
		case 0:
#ifndef DEBUG
			/* don't print on console if the ethtool cannot disable some offloads unless you are in debug mode */
			close(2);
#endif
			execvp(param[0], param);
			WARN_MSG("cannot disable offload on %s, do you have ethtool installed?", EC_GBL_OPTIONS->iface);
			safe_free_mem(param, &param_length, command);
			_exit(-E_INVALID);
		case -1:
			safe_free_mem(param, &param_length, command);
         break;
		default:
			safe_free_mem(param, &param_length, command);
			wait(&ret_val);
	} 	
}
Exemple #10
0
static int add_filter_to_list(struct filter_list *f, void *data)
{
   SAFE_REALLOC(wdg_filters_elements, (n_filters + 1) * sizeof(struct wdg_list));
   SAFE_CALLOC(wdg_filters_elements[n_filters].desc, MAX_DESC_LEN + 1, sizeof(char));
   snprintf(wdg_filters_elements[n_filters].desc, MAX_DESC_LEN, "[%c] %s", f->enabled?'X':' ', f->name);
   wdg_filters_elements[n_filters].value = f;
   n_filters++;

   return 1;
}
Exemple #11
0
void ui_msg(const char *fmt, ...)
{
   va_list ap;
   struct ui_message *msg;
   int n;
   size_t size = 50;

   SAFE_CALLOC(msg, 1, sizeof(struct ui_message));

   /* 
    * we hope the message is shorter
    * than 'size', else realloc it
    */
    
   SAFE_CALLOC(msg->message, size, sizeof(char));

   while (1) {
      /* Try to print in the allocated space. */
      va_start(ap, fmt);
      n = vsnprintf (msg->message, size, fmt, ap);
      va_end(ap);
      
      /* If that worked, we have finished. */
      if (n > -1 && (size_t)n < size)
         break;
   
      /* Else try again with more space. */
      if (n > -1)    /* glibc 2.1 */
         size = n+1; /* precisely what is needed */
      else           /* glibc 2.0 */
         size *= 2;  /* twice the old size */
      
      SAFE_REALLOC(msg->message, size);
   }

   /* log the messages if needed */
   if (GBL_OPTIONS->msg_fd) {
      fprintf(GBL_OPTIONS->msg_fd, "%s", msg->message);
      fflush(GBL_OPTIONS->msg_fd);
   }
   
   /* 
    * MUST use the mutex.
    * this MAY be a different thread !!
    */
   UI_MSG_LOCK;
   
   /* add the message to the queue */
   STAILQ_INSERT_TAIL(&messages_queue, msg, next);

   UI_MSG_UNLOCK;
   
}
Exemple #12
0
void rates_queue::putItem(rates_queue_item *pItem, int nMinDelay)
{
	int bFound = FALSE;

	if (!ppro->icqOnline())
		return;

	ppro->NetLog_Server("Rates: Delaying %s.", szDescr);

	listsMutex->Enter();
	if (pendingListSize)
	{
		for (int i = 0; i < pendingListSize; i++)
		{
			if (pendingList[i]->isEqual(pItem))
			{ 
				if (duplicates == -1)
				{ // discard existing, append new item
					SAFE_DELETE((void_struct**)&pendingList[i]);
					memcpy(&pendingList[i], &pendingList[i + 1], (pendingListSize - i - 1) * sizeof(rates_queue_item*));
					bFound = TRUE;
				}
				else if (duplicates == 1)
				{ // keep existing, ignore new
					listsMutex->Leave();
					return;
				}
				// otherwise keep existing and append new
			}
		}
	}
	if (!bFound)
	{ // not found, enlarge the queue
		pendingListSize++;
		pendingList = (rates_queue_item**)SAFE_REALLOC(pendingList, pendingListSize * sizeof(rates_queue_item*));
	}
	pendingList[pendingListSize - 1] = pItem->copyItem();

	if (pendingListSize == 1)
	{ // queue was empty setup timer
		listsMutex->Leave();
		ppro->m_ratesMutex->Enter();
		int nDelay = ppro->m_rates->getDelayToLimitLevel(pItem->wGroup, waitLevel);
		ppro->m_ratesMutex->Leave();

		if (nDelay < 10) nDelay = 10;
		if (nDelay < nMinDelay) nDelay = nMinDelay;
		initDelay(nDelay, &rates_queue::processQueue);
	}
	else
		listsMutex->Leave();
}
Exemple #13
0
static void build_filter_list(void)
{
   while (wdg_filters_elements && n_filters > 0) {
      SAFE_FREE(wdg_filters_elements[n_filters-1].desc);
      n_filters--;
   }
   SAFE_FREE(wdg_filters_elements);

   n_filters = 0;
   filter_walk_list( add_filter_to_list, &n_filters );

   SAFE_REALLOC(wdg_filters_elements, (n_filters + 1) * sizeof(struct wdg_list));
   /* 0-terminate the array */
   wdg_filters_elements[n_filters].desc = NULL;
   wdg_filters_elements[n_filters].value = NULL;
}
Exemple #14
0
/*
 * the FATAL_MSG error handling function
 */
void ui_error(const char *fmt, ...)
{
   va_list ap;
   int n;
   size_t size = 50;
   char *msg;

   /* 
    * we hope the message is shorter
    * than 'size', else realloc it
    */
    
   SAFE_CALLOC(msg, size, sizeof(char));

   while (1) {
      /* Try to print in the allocated space. */
      va_start(ap, fmt);
      n = vsnprintf (msg, size, fmt, ap);
      va_end(ap);
      
      /* If that worked, we have finished. */
      if (n > -1 && (size_t)n < size)
         break;
   
      /* Else try again with more space. */
      if (n > -1)    /* glibc 2.1 */
         size = n+1; /* precisely what is needed */
      else           /* glibc 2.0 */
         size *= 2;  /* twice the old size */
      
      SAFE_REALLOC(msg, size);
   }

   /* dump the error in the debug file */
   DEBUG_MSG("%s", msg);
   
   /* call the function */
   if (GBL_UI->error)
      EXECUTE(GBL_UI->error, msg);
   /* the interface is not yet initialized */
   else
      fprintf(stderr, "\n%s\n", msg);
   
   /* free the message */
   SAFE_FREE(msg);
}
Exemple #15
0
/* 
 * add a string to the buffer 
 */
static size_t add_data_segment(u_char **data, size_t base, u_char **string, size_t slen)
{
   /* make room for the new string */
   SAFE_REALLOC(*data, base + slen + 1);

   /* copy the string, NULL separated */
   memcpy(*data + base, *string, slen + 1);

   /* 
    * change the pointer to the new string location 
    * it is an offset from the base of the data segment
    */
   *string = (u_char *)base;
   
   /* retur the len of the added string */
   return slen + 1;
}
Exemple #16
0
void text_print_packet(struct packet_object *po)
{
   /* 
    * keep it static so it is always the same
    * memory region used for this operation
    */
   static u_char *tmp = NULL;
   int ret;

   /* don't display the packet */
   if (GBL_OPTIONS->quiet)
      return;
   
   /* 
    * if the regex does not match, the packet is not interesting 
    *
    * should we put this after the format function ?
    * in this way we can match e.t.t.e.r.c.a.p in TEXT mode with
    * the "ettercap" regex
    */
   if (GBL_OPTIONS->regex && 
       regexec(GBL_OPTIONS->regex, po->DATA.disp_data, 0, NULL, 0) != 0) {
      return;
   }
               
   /* 
    * prepare the buffer,
    * the max length is hex_fomat
    * so use its length for the buffer
    */
   SAFE_REALLOC(tmp, hex_len(po->DATA.disp_len) * sizeof(u_char));

   /* 
    * format the packet with the function set by the user
    */
   ret = GBL_FORMAT(po->DATA.disp_data, po->DATA.disp_len, tmp);

   /* print the headers */
   display_headers(po);
   
   /* print it */
   write(fileno(stdout), tmp, ret);

   printf("\n");
}     
Exemple #17
0
char *BinaryToEscapes(char *str)
{
    int extra=10,len=strlennull(str)+11,i;
    char *out,*pout;

    out=pout=(char*)SAFE_MALLOC(len);
    for(; *str; str++)
    {
        if((unsigned char)*str>=' ')
        {
            *pout++=*str;
            continue;
        }
        if(str[0]=='\r' && str[1]=='\n')
        {
            *pout++='\\';
            *pout++='n';
            str++;
            continue;
        }
        if(extra<3)
        {
            extra+=8;
            len+=8;
            pout=out=(char*)SAFE_REALLOC(out,len);
        }
        *pout++='\\';
        for(i = 0; i < SIZEOF(escapes); i += 2)
            if(*str==escapes[i+1])
            {
                *pout++=escapes[i];
                extra--;
                break;
            }
        if(i < SIZEOF(escapes)) continue;
        *pout++='0';
        extra--;
        if(*str>=8)
        {
            *pout++=(*str>>3)+'0';
            extra--;
        }
        *pout++=(*str&7)+'0';
        extra--;
    }
Exemple #18
0
void del_decoder(u_int8 level, u_int32 type)
{
    struct dec_entry *e;

    if(e = find_entry(level, type)) {
        DECODERS_LOCK;
        /* Replace this entry with the last one */
        memcpy(e, &protocols_table[protocols_num-1], sizeof(struct dec_entry));
        /* Resize the array */
        SAFE_REALLOC(protocols_table, --protocols_num*sizeof(struct dec_entry));
        /* And mark as unsorted */
        table_sorted = false;

        DECODERS_UNLOCK;
    }

    return;
}
/*
 * add a decoder to the decoders table 
 */
void add_decoder(u_int8 level, u_int32 type, FUNC_DECODER_PTR(decoder))
{
   struct dec_entry *e;
   bool found = false;

   DECODERS_LOCK;

   /* in case this is the first call and no tables are allocated */
   if(protocols_table == NULL) {
      /* the numbers are kindly provided by /usr/bin/grep and /usr/bin/wc */
      SAFE_CALLOC(protocols_table, protocols_num = 19 + 52, sizeof(struct dec_entry));
   }

   e = &protocols_table[protocols_num];

   /* searching for an empty entry */
   while(e --> protocols_table) 
      if(e->level == 0 && e->type == 0 && e->decoder == NULL) {
         /* We got it! */
         found = true;
         break;
      }
   /*
    * wc and grep are a part of The Conspiracy!
    * but we can allocate a little bit more, cant we?
    * and no kidding plz, its a serious code from now on
    */
   if(!found) {
      SAFE_REALLOC(protocols_table, ++protocols_num * sizeof(struct dec_entry));
      e = &protocols_table[protocols_num - 1];
   }

   /* We win, they lose, ha-ha! */
   e->level = level;
   e->type = type;
   e->decoder = decoder;
   e->active = true;

   table_sorted = false;

   DECODERS_UNLOCK;
   
   return;
}
static void split_print(u_char *text, size_t len, struct ip_addr *L3_src)
{
   int ret;
   
   /* check the regex filter */
   if (GBL_OPTIONS->regex && 
       regexec(GBL_OPTIONS->regex, text, 0, NULL, 0) != 0) {
      return;
   }

   /* use the global to reuse the same memory region */
   SAFE_REALLOC(dispbuf, hex_len(len) * sizeof(u_char) + 1);
   
   /* format the data */
   ret = GBL_FORMAT(text, len, dispbuf);
   dispbuf[ret] = 0;

   if (!ip_addr_cmp(L3_src, &curr_conn->L3_addr1))
      gtkui_data_print(1, dispbuf, 0);
   else
      gtkui_data_print(2, dispbuf, 0);
}
static void join_print(u_char *text, size_t len, struct ip_addr *L3_src)
{
   int ret;
   
   /* check the regex filter */
   if (GBL_OPTIONS->regex && 
       regexec(GBL_OPTIONS->regex, (const char*)text, 0, NULL, 0) != 0) {
      return;
   }
   
   /* use the global to reuse the same memory region */
   SAFE_REALLOC(dispbuf, hex_len(len) * sizeof(u_char) + 1);
   
   /* format the data */
   ret = GBL_FORMAT(text, len, dispbuf);
   dispbuf[ret] = 0;
   
   if (!ip_addr_cmp(L3_src, &curr_conn->L3_addr1))
      wdg_scroll_print(wdg_join, EC_COLOR_JOIN1, "%s", dispbuf);
   else
      wdg_scroll_print(wdg_join, EC_COLOR_JOIN2, "%s", dispbuf);
}
/*
 * inject interactively with the user
 */
static void curses_connection_inject(void)
{
   wdg_t *in;
   
   DEBUG_MSG("curses_connection_inject");
   
   SAFE_REALLOC(injectbuf, 501 * sizeof(char));
   memset(injectbuf, 0, 501);
   
   wdg_create_object(&in, WDG_INPUT, WDG_OBJ_WANT_FOCUS | WDG_OBJ_FOCUS_MODAL);
   wdg_set_color(in, WDG_COLOR_SCREEN, EC_COLOR);
   wdg_set_color(in, WDG_COLOR_WINDOW, EC_COLOR);
   wdg_set_color(in, WDG_COLOR_FOCUS, EC_COLOR_FOCUS);
   wdg_set_color(in, WDG_COLOR_TITLE, EC_COLOR_MENU);
   wdg_input_size(in, 75, 12);
   wdg_input_add(in, 1, 1, "Chars to be injected  :", (char*)injectbuf, 50, 10);
   wdg_input_set_callback(in, inject_user);
   
   wdg_draw_object(in);
      
   wdg_set_focus(in);
}
Exemple #23
0
/*
 * search a pattern into the stream 
 * returns  - NULL if not found
 *          - the packet containing the string if found
 */
struct so_list * stream_search(struct stream_object *so, u_char *buf, size_t buflen, int mode)
{
   u_char *tmpbuf = NULL, *find;
   size_t offset = 0, len = 0;
   struct so_list *so_curr = NULL, *first;
   size_t po_off = 0;
   
   /* get the values into temp variable */
   switch (mode) {
      case STREAM_SIDE1:
         so_curr = so->side1.so_curr;
         po_off = so->side1.po_off;
         break;
      case STREAM_SIDE2:
         so_curr = so->side2.so_curr;
         po_off = so->side2.po_off;
         break;
   }

   first = so_curr;
   
   /* create the buffer from the current position to the end */ 
   for ( ; so_curr != TAILQ_END(so->so_head); so_curr = TAILQ_NEXT(so_curr, next)) {
     
      /* skip packet in the wrong side */
      if (so_curr->side != mode) {
         po_off = 0;
         continue;
      }
      
      if (so_curr == first)
         len += so_curr->po.DATA.len - po_off;
      else
         len += so_curr->po.DATA.len;
         
      
      SAFE_REALLOC(tmpbuf, len);
      
      /* 
       * add the packet to the end of the buffer 
       * containing the whole conversation 
       */
      if (so_curr == first)
         memcpy(tmpbuf, so_curr->po.DATA.data + po_off, so_curr->po.DATA.len - po_off);
      else
         memcpy(tmpbuf + len - so_curr->po.DATA.len, so_curr->po.DATA.data, so_curr->po.DATA.len);
   }

   /* the buffer is found in the conversation */
   if ((find = memmem(tmpbuf, len, buf, buflen)) != NULL) {
      offset = find - tmpbuf;
     
      SAFE_FREE(tmpbuf);

      /* move the stream pointers to the buffer found */
      stream_move(so, offset, SEEK_CUR, mode);

      switch (mode) {
         case STREAM_SIDE1:
            return so->side1.so_curr;
         case STREAM_SIDE2:
            return so->side2.so_curr;
      }
   } 

   SAFE_FREE(tmpbuf);
  
   return NULL;
}
void handleAccept(int i)
{
	struct sockaddr addr;
	struct sockaddr_in *sin;
	unsigned char address[4];
	char addressText[64];
	int j;
	int addrlen;
	int index = -1;
	int o;
	SOCKET nfd;
	addrlen = sizeof(addr);
	nfd = accept(seFds[i], &addr, &addrlen);
	if (nfd == INVALID_SOCKET) {
		log(-1, i, logAcceptFailed);
		return;
	}
#ifndef WIN32
	if (nfd > maxfd) {
		maxfd = nfd;
	}
#endif /* WIN32 */
	j = 1;
	ioctlsocket(nfd, FIONBIO, &j);
	j = 0;
#ifndef WIN32
	setsockopt(nfd, SOL_SOCKET, SO_LINGER, &j, sizeof(j));
#endif
	for (j = 0; (j < coTotal); j++) {	
		if (coClosed[j]) {
			index = j;
			break;
		}
	}
	if (index == -1) {
		o = coTotal;
		coTotal *= 2;
		if (!SAFE_REALLOC(&reFds, sizeof(int) * o,
			sizeof(SOCKET) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&loFds, sizeof(int) * o,
			sizeof(SOCKET) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coInputRPos, 
			sizeof(int) * o, sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coInputWPos, 
			sizeof(int) * o, sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coOutputRPos, 
			sizeof(int) * o, sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coOutputWPos, sizeof(int) * o, 
			sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coClosed, sizeof(int) * o, 
			sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coClosing, sizeof(int) * o, 
			sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&reClosed, sizeof(int) * o, 
			sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&loClosed, sizeof(int) * o, 
			sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coLog, sizeof(int) * o, 
			sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coSe, sizeof(int) * o, 
			sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coBytesInput, sizeof(int) * o, 
			sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&reAddresses, 4 * o, 
			4 * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coBytesOutput, sizeof(int) * o, 
			sizeof(int) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coInput, sizeof(char *) * o,
			sizeof(char *) * coTotal)) 
		{
			goto shortage;
		}
		if (!SAFE_REALLOC(&coOutput, sizeof(char *) * o,
			sizeof(char *) * coTotal)) 
		{
			goto shortage;
		}
		for (j = o; (j < coTotal); j++) {
			coClosed[j] = 1;
			coInput[j] = (char *) 
				malloc(sizeof(char) * bufferSpace);
			if (!coInput[j]) {
				int k;
				for (k = o; (k < j); k++) {
					free(coInput[k]);
					free(coOutput[k]);
				}
				goto shortage;
			}
			coOutput[j] = (char *) 
				malloc(sizeof(char) * bufferSpace);
			if (!coOutput[j]) {
				int k;
				free(coInput[j]);
				for (k = o; (k < j); k++) {
					free(coInput[k]);
					free(coOutput[k]);
				}
				goto shortage;
			}
		}
		index = o;
	}
	coInputRPos[index] = 0;
	coInputWPos[index] = 0;
	coOutputRPos[index] = 0;
	coOutputWPos[index] = 0;
	coClosed[index] = 0;
	coClosing[index] = 0;
	reClosed[index] = 0;
	loClosed[index] = 0;
	reFds[index] = nfd;
	coBytesInput[index] = 0;
	coBytesOutput[index] = 0;
	coLog[index] = 0;
	coSe[index] = i;
	sin = (struct sockaddr_in *) &addr;
	memcpy(address, &(sin->sin_addr.s_addr), 4);
	memcpy(reAddresses + index * 4, address, 4);
	/* Now, do we want to accept this connection? 
		Format it for comparison to a pattern. */
	sprintf(addressText, "%d.%d.%d.%d",
		address[0], address[1], address[2], address[3]);
	/* 1. Check global allow rules. If there are no
		global allow rules, it's presumed OK at
		this step. If there are any, and it doesn't
		match at least one, kick it out. */
	if (globalAllowRules) {
		int good = 0;
		for (j = 0; (j < globalAllowRules); j++) {
			if (match(addressText, allowRules[j])) {
				good = 1;
				break;
			}
		}
		if (!good) {
			refuse(index, logNotAllowed);
			return;
		}	
	}
	/* 2. Check global deny rules. If it matches
		any of the global deny rules, kick it out. */
	if (globalDenyRules) {			
		for (j = 0; (j < globalDenyRules); j++) {
			if (match(addressText, denyRules[j])) {
				refuse(index, logDenied);
			}
		}
	}
	/* 3. Check allow rules specific to this forwarding rule.
		If there are none, it's OK. If there are any,
		it must match at least one. */
	if (seAllowRulesTotal[i]) {
		int good = 0;
		for (j = 0; (j < seAllowRulesTotal[i]); j++) {
			if (match(addressText, 
				allowRules[seAllowRules[i] + j])) {
				good = 1;
				break;
			}
		}
		if (!good) {
			refuse(index, logNotAllowed);
			return;
		}	
	}
	/* 2. Check deny rules specific to this forwarding rule. If 
		it matches any of the deny rules, kick it out. */
	if (seDenyRulesTotal[i]) {			
		for (j = 0; (j < seDenyRulesTotal[i]); j++) {
			if (match(addressText, 
				denyRules[seDenyRules[i] + j])) {
				refuse(index, logDenied);
			}
		}
	}
	/* Now open a connection to the local server.
		This, too, is nonblocking. Why wait
		for anything when you don't have to? */
	openLocalFd(i, index);	
	return;
shortage:
	fprintf(stderr, "rinetd: not enough memory to "
		"add slots. Currently %d slots.\n", o);
	/* Go back to the previous total number of slots */
	coTotal = o;	
}
/////////////////////////////////////////////////////////////////
// HRESULT CRow::SetupColAccess
//
/////////////////////////////////////////////////////////////////
HRESULT CRow::SetupColAccess(BINDCOLS eBindCols)
{
	HRESULT hr = S_OK;
	DBLENGTH dwOffset = 0;
	ULONG i;

	//Only capable of the Following Converions (for Display)
	DWORD  dwMaxLength		= GetOptions()->m_dwMaxLength;
	DWORD  dwAccessorOpts	= GetOptions()->m_dwAccessorOpts;
	
	if(m_pIColumnsInfo == NULL)
		return E_FAIL;

	//GetColumnInfo
	GetColInfo();

	//Alloc the space to hold the ColumnAccess structs
	ULONG cBindings = 0;
	DBBINDING* rgBindings = NULL;
	SAFE_ALLOC(m_rgColAccess, DBCOLUMNACCESS, m_ColumnInfo.GetCount());
	SAFE_ALLOC(rgBindings, DBBINDING, m_ColumnInfo.GetCount());

	//Figure out how big to make the buffer...
	for(i=0; i<m_ColumnInfo.GetCount(); i++)
	{
		//Offset
		m_rgColAccess[i].cbMaxLen = GetMaxDisplaySize(GetOptions()->GetBindingType(m_ColumnInfo[i].wType), m_ColumnInfo[i].wType, m_ColumnInfo[i].ulColumnSize, dwMaxLength);
		dwOffset = ROUNDUP( dwOffset + m_rgColAccess[i].cbMaxLen );
	}

	//Size for pData
	SAFE_REALLOC(m_pData, BYTE, dwOffset);
	
	dwOffset = 0;
	m_cColAccess = 0;
	cBindings = 0;
	for(i=0; i<m_ColumnInfo.GetCount(); i++) 
	{
		DBCOLUMNINFO*	pColInfo	= &m_ColumnInfo[i];
		DBCOLUMNACCESS*	pColAccess	= &m_rgColAccess[m_cColAccess];
		DBBINDING*		pBinding	= &rgBindings[cBindings];

		//Setup the Bindings
		pColAccess->columnid		= pColInfo->columnid;
		pColAccess->bPrecision		= pColInfo->bPrecision;
		pColAccess->bScale			= pColInfo->bScale;
		pColAccess->wType			= GetOptions()->GetBindingType(pColInfo->wType);
		pColAccess->cbDataLen		= 0;

		//NOTE: This is setup above in the Previous for loop...
		pColAccess->cbMaxLen		= m_rgColAccess[i].cbMaxLen; 
		
		//BLOB or IUnknown Bindings
		if(pColAccess->wType == DBTYPE_IUNKNOWN || pColInfo->wType == DBTYPE_IUNKNOWN || 
			(pColInfo->dwFlags & DBCOLUMNFLAGS_ISLONG && (dwAccessorOpts & (ACCESSOR_BLOB_ISEQSTREAM|ACCESSOR_BLOB_ILOCKBYTES|ACCESSOR_BLOB_ISTORAGE|ACCESSOR_BLOB_ISTREAM))))
		{
			pColAccess->wType		= DBTYPE_IUNKNOWN;
			pColAccess->cbMaxLen	= sizeof(IUnknown*);
		}	
		
		//If the consumer requested not to bind the Value in Options, then set pData = NULL
		//This is how the 2.5 spec says to indicate VALUE is not bound (since their is no dwPart).
		pColAccess->pData			= NULL;
		if(dwAccessorOpts & ACCESSOR_BIND_VALUE)
			pColAccess->pData		= (BYTE*)m_pData + dwOffset;
						
		//Initialize the Status to an error, so we don't end up freeing outofline 
		//data we haven't retreived yet...
		pColAccess->dwStatus		= DBSTATUS_E_UNAVAILABLE;

		//Special Handling for other non-OLE DB defined convertable types to WSTR
		//NOTE: The spec requires all supported types to be converted to 
		//WSTR, but this only applies where the OLE DB conversion is defined.
		//Some are not defined so we need to bind nativly.
		switch(pColInfo->wType)
		{
			case DBTYPE_IUNKNOWN:
			case DBTYPE_IDISPATCH:
				pColAccess->wType		= pColInfo->wType;
				pColAccess->cbMaxLen	= sizeof(IUnknown*);
				break;

			case DBTYPE_HCHAPTER:
				pColAccess->wType		= pColInfo->wType;
				pColAccess->cbMaxLen	= sizeof(HCHAPTER);
				break;

			default:
				//DBTYPE_VECTOR
				if(pColInfo->wType	& DBTYPE_VECTOR)
				{
					pColAccess->wType	= pColInfo->wType;
					pColAccess->cbMaxLen= sizeof(DBVECTOR);
				}
				
				//DBTYPE_ARRAY
				if(pColInfo->wType	& DBTYPE_ARRAY)
				{
					pColAccess->wType	= pColInfo->wType;
					pColAccess->cbMaxLen= sizeof(SAFEARRAY*);
				}
				break;
		};

		//Offset
		dwOffset += pColAccess->cbMaxLen;
		dwOffset = ROUNDUP( dwOffset );

		//Build a real simple binding on top of this ColumnAccess struct.
		//The reason is all of our data manipulations routines deal with binding structs, so instead
		//have having numerous code lines, we will just map this to a binding struct...
		pBinding->iOrdinal		= pColInfo->iOrdinal;
		pBinding->obStatus		= (DBBYTEOFFSET)((BYTE*)&pColAccess->dwStatus - (BYTE*)m_pData);
		pBinding->obLength		= (DBBYTEOFFSET)((BYTE*)&pColAccess->cbDataLen - (BYTE*)m_pData);
		pBinding->obValue		= (DBBYTEOFFSET)((BYTE*)pColAccess->pData - (BYTE*)m_pData);

		pBinding->pTypeInfo		= NULL;
		pBinding->pObject		= NULL;
		pBinding->pBindExt		= NULL;

		pBinding->dwPart		= DBPART_LENGTH|DBPART_STATUS;
		if(pColAccess->pData)
			pBinding->dwPart	|= DBPART_VALUE;

		pBinding->dwMemOwner	= (dwAccessorOpts & ACCESSOR_OWNED_PROVIDER) ? DBMEMOWNER_PROVIDEROWNED : DBMEMOWNER_CLIENTOWNED;
		pBinding->eParamIO		= DBPARAMIO_NOTPARAM;
		
		pBinding->cbMaxLen		= pColAccess->cbMaxLen;
		pBinding->dwFlags		= 0;
		pBinding->wType			= pColAccess->wType;

		pBinding->bPrecision	= pColAccess->bPrecision;
		pBinding->bScale		= pColAccess->bScale;

		//Do we real want this column?		
		switch(eBindCols)
		{
			case BIND_ALLCOLS:
				m_cColAccess++;
				cBindings++;
				break;

			case BIND_ALLCOLSEXPECTBOOKMARK:
				if(pColInfo->iOrdinal != 0)
				{
					m_cColAccess++;
					cBindings++;
				}
				break;

			case BIND_UPDATEABLECOLS:
				if(pColInfo->dwFlags & DBCOLUMNFLAGS_WRITE || pColInfo->dwFlags & DBCOLUMNFLAGS_WRITEUNKNOWN)
				{
					m_cColAccess++;
					cBindings++;
				}
				break;

			default:
				ASSERT(!"Unhandled Type!");
				break;
		}
	}

CLEANUP:
	m_Bindings.Attach(cBindings, rgBindings);
	return hr;
}
/* 
 * parse the packet and send the fake reply
 */
static void remote_browser(struct packet_object *po)
{
   char *tmp, *p, *q;
   char *url, *host;
   char *command;
   char **param = NULL;
   int i = 0, k = 0;
   
   /* the client is making a request */
   if (po->DATA.disp_len != 0 && strstr((const char*)po->DATA.disp_data, "GET")) {
      /* I'm the sender, opening a browser with a request coming by me will trigger a loop in this function! */
      if(ip_addr_is_ours(&po->L3.src) == E_FOUND || ip_addr_is_ours(&po->L3.src) == E_BRIDGE)
         return;

      /* I'm not the sender, I can safely open the browser, the GET triggered by it shouldn't cause bad effects */
      tmp = strdup((const char*)po->DATA.disp_data);

      /* get the Host: directive */
      host = strstr(tmp, "Host: ");
      if (host != NULL) {
         host = host + 6; // 6 is like strlen("Host: ");
         if ((p = strstr(host, "\r\n")) != NULL)
            *p = 0;
      } else
         goto bad;
      
      /* null terminate the request before the HTTP/x.x */
      p = strstr(tmp, " HTTP");
      if (p != NULL)
         *p = 0;
      else
         goto bad;
     
      /* get the requested url */
     url = tmp + 4; // 4 is like strlen("GET ");
      
      /* parse only pages, not images or other amenities */
      if (!good_page(url))
         goto bad;
           
      /* fill the command */
      command = strdup(GBL_CONF->remote_browser);
      str_replace(&command, "%host", host);
      str_replace(&command, "%url", url);
      
      USER_MSG("REMOTE COMMAND: %s\n", command);
      
      /* split the string in the parameter array */
      for (p = ec_strtok(command, " ", &q); p != NULL; p = ec_strtok(NULL, " ", &q)) {
         /* allocate the array */
         SAFE_REALLOC(param, (i + 1) * sizeof(char *));
                        
         /* copy the tokens in the array */
         param[i++] = strdup(p);
      }
   
      /* NULL terminate the array */
      SAFE_REALLOC(param, (i + 1) * sizeof(char *));
      param[i] = NULL;
      /* execute the script */ 
      if (fork() == 0) {
         /* chrome won't start as root, changing UID in order to prevent this and for more security in the browser context */
         /* the following line has been commented since some Penetration Testing distros can run only as root */
         /*setuid(1000);*/
         u_int uid, gid;
         DEBUG_MSG("drop_privs: getuid(%d) \n", getuid());

         /* are we root ? */
         if (getuid() == 0)
         {
            gid = uid = 1000;
            DEBUG_MSG("drop_privs: setuid(%d) setgid(%d)\n", uid, gid);

            /* drop to a good uid/gid ;) */
            if ( setgid(gid) < 0 )
               DEBUG_MSG("setgid() FAILED\n");
            if ( setuid(uid) < 0 )
               DEBUG_MSG("setuid() FAILED\n");
            DEBUG_MSG("privs: UID: %d %d  GID: %d %d\n", (int)getuid(), (int)geteuid(), (int)getgid(), (int)getegid() );
            DEBUG_MSG("Privileges dropped to UID %d GID %d...\n\n", (int)getuid(), (int)getgid() );
         /* "nobody" cannot open a browser */
         } else if(getuid() == 65535)
            WARN_MSG("your ec_gid and ec_uid in etter.conf file are set to nobody (65535), you probably cannot open a new browser\n");

         execvp(param[0], param);
         WARN_MSG("Cannot launch the default browser (command: %s), please edit your etter.conf file and put a valid value in remote_browser field\n", GBL_CONF->remote_browser);
         _exit(-E_INVALID);
      }
         
      //to free the char **param
      for(k= 0; k < i; ++k)
    	  SAFE_FREE(param[k]);
      SAFE_FREE(param);

      SAFE_FREE(command);
bad:
      SAFE_FREE(tmp);
   }
   
}
/*
 * inject interactively with the user
 */
static void gtkui_connection_inject(void)
{
   GtkWidget *dialog, *text, *label, *vbox, *frame;
   GtkWidget *button1, *button2, *hbox;
   GtkTextBuffer *buf;
   GtkTextIter start, end;
   char tmp[MAX_ASCII_ADDR_LEN];
   gint response = 0;

   DEBUG_MSG("gtk_connection_inject");

   if(curr_conn == NULL)
      return;

   dialog = gtk_dialog_new_with_buttons("Character Injection", GTK_WINDOW (window),
                                        GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK,
                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
   gtk_window_set_default_size(GTK_WINDOW (dialog), 400, 200);
   gtk_dialog_set_has_separator(GTK_DIALOG (dialog), FALSE);
   gtk_container_set_border_width(GTK_CONTAINER (dialog), 5);
   vbox = GTK_DIALOG (dialog)->vbox;

   label = gtk_label_new ("Packet destination:");
   gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5);
   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
   gtk_widget_show(label);

   hbox = gtk_hbox_new(FALSE, 5);
   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
   gtk_widget_show(hbox);

   button1 = gtk_radio_button_new_with_label(NULL, ip_addr_ntoa(&curr_conn->L3_addr2, tmp));
   gtk_box_pack_start(GTK_BOX(hbox), button1, FALSE, FALSE, 0);
   gtk_widget_show(button1);

   button2 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON (button1),
               ip_addr_ntoa(&curr_conn->L3_addr1, tmp));
   gtk_box_pack_start(GTK_BOX(hbox), button2, FALSE, FALSE, 0);
   gtk_widget_show(button2);

   label = gtk_label_new ("Characters to be injected:");
   gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5);
   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
   gtk_widget_show(label);

   frame = gtk_frame_new(NULL);
   gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_IN);
   gtk_box_pack_start(GTK_BOX (vbox), frame, TRUE, TRUE, 5);
   gtk_widget_show(frame);

   text = gtk_text_view_new();
   gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW (text), GTK_WRAP_CHAR);
   gtk_container_add(GTK_CONTAINER (frame), text);
   gtk_widget_show(text);
    
   response = gtk_dialog_run(GTK_DIALOG(dialog));
   if(response == GTK_RESPONSE_OK) {
      gtk_widget_hide(dialog);

      SAFE_REALLOC(injectbuf, 501 * sizeof(char));
      memset(injectbuf, 0, 501);

      buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW (text));

      /* initialize iters for get text */
      gtk_text_buffer_get_start_iter(buf, &start);
      gtk_text_buffer_get_start_iter(buf, &end);
      /* advance end iter to end of text, 500 char max */
      gtk_text_iter_forward_chars(&end, 500);
      
      strncpy(injectbuf, gtk_text_buffer_get_text(buf, &start, &end, FALSE), 501);

      if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button1)))
         gtkui_inject_user(1);
      else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button2)))
         gtkui_inject_user(2);
   }

   gtk_widget_destroy(dialog);
}
////////////////////////////////////////////////////////////////
// HRESULT CSession::GetProviderTypes
//
////////////////////////////////////////////////////////////////
HRESULT CSession::GetProviderTypes()
{
	HRESULT			hr	= S_OK;

	HROW rghRows[MAX_BLOCK_SIZE];
	HROW* phRows = rghRows;
	DBCOUNTITEM cRowsObtained = 0;
	CComPtr<IUnknown>	spUnknown;
	CRowset cRowset(m_pCMainWindow);
	HACCESSOR hAccessor = DB_NULL_HACCESSOR;

	//Setup the Bindings
	const static DBCOUNTITEM cBindings = 4;
	const static DBBINDING rgBindings[cBindings] = 
		{
			1,	 			
			offsetof(PROVTYPEINFO, wszTypeName),
			0,
			0,	
			NULL,			
			NULL, 		
			NULL,		
			DBPART_VALUE,
			DBMEMOWNER_CLIENTOWNED,		
			DBPARAMIO_NOTPARAM, 
			MAX_NAME_LEN,
			0, 				
			DBTYPE_WSTR,
			0,	
			0, 				

			2,	 			
			offsetof(PROVTYPEINFO, wType),
			0,
			0,	
			NULL,			
			NULL, 		
			NULL,		
			DBPART_VALUE,
			DBMEMOWNER_CLIENTOWNED,		
			DBPARAMIO_NOTPARAM, 
			sizeof(DBTYPE),
			0, 				
			DBTYPE_UI2,
			0,	
			0, 				

			3,	 			
			offsetof(PROVTYPEINFO, ulColumnSize),
			0,
			0,	
			NULL,			
			NULL, 		
			NULL,		
			DBPART_VALUE,
			DBMEMOWNER_CLIENTOWNED,		
			DBPARAMIO_NOTPARAM, 
			sizeof(DBLENGTH),	//TODO64: So is this schema going to be updated to allow for more than 4gig size?
			0, 				
			DBTYPE_UI4,			//TODO64: Sure would be nice to have defined type that toggels for the OS?
			0,	
			0, 				

			15,	 			
			offsetof(PROVTYPEINFO, iMaxScale),
			0,
			0,	
			NULL,			
			NULL, 		
			NULL,		
			DBPART_VALUE,
			DBMEMOWNER_CLIENTOWNED,		
			DBPARAMIO_NOTPARAM, 
			sizeof(SHORT),
			0, 				
			DBTYPE_I2,
			0,	
			0,
		};

	//IDBSchemaRowset is optional
	//Only need to obtain this info once, so if already done, just exit
	if(m_pIDBSchemaRowset == NULL || m_cProvTypes != 0)
		goto CLEANUP;

	//PROVIDER_TYPES Rowset (is required if Schemas are supported)
	TESTC(hr = GetSchemaRowset(NULL, DBSCHEMA_PROVIDER_TYPES, 0, NULL, IID_IUnknown, 0, NULL, &spUnknown));
	TESTC(hr = cRowset.CreateObject(this, IID_IUnknown, spUnknown));
	
	//IAccessor::CreateAccessor
	TESTC(hr = cRowset.CreateAccessor(DBACCESSOR_ROWDATA, cBindings, (DBBINDING*)rgBindings, 0, &hAccessor));

	//Loop through the entire returned rowset
	while(TRUE)
	{
		TESTC(hr = cRowset.GetNextRows(0, MAX_BLOCK_SIZE, &cRowsObtained, &phRows));
		
		//ENDOFROWSET
		if(cRowsObtained==0) 
			break;
		
		//Alloc room for ProviderInfo (in chunks)
		SAFE_REALLOC(m_rgProvTypes, PROVTYPEINFO, m_cProvTypes + cRowsObtained);
		memset(&m_rgProvTypes[m_cProvTypes], 0, sizeof(PROVTYPEINFO) * (size_t)cRowsObtained);

		//Loop over rows obtained and get ProviderInfo
		for(ULONG i=0; i<cRowsObtained; i++) 
		{	
			//Get the Data
			TESTC(hr = cRowset.GetData(rghRows[i], hAccessor, (void*)&m_rgProvTypes[m_cProvTypes]));
			m_cProvTypes++;
		}
			
		//Release all the rows
		TESTC(hr = cRowset.ReleaseRows(cRowsObtained, rghRows));
	}

CLEANUP:
	cRowset.ReleaseAccessor(&hAccessor);
	return hr;
}