Bug 37785 - glimmer crashes on certain valid C files
Summary: glimmer crashes on certain valid C files
Status: Closed FIXED
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-ports (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2002-05-06 10:20 UTC by Larry Rosenman
Modified: 2002-05-07 19:58 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Larry Rosenman freebsd_committer 2002-05-06 10:20:03 UTC
try to load the included C file into glimmer, and it crashes.  I've tried
to send mail to the glimmer author, but the mail hung in my queue unable
to resolve the domain name.

How-To-Repeat: try to load the following as netmaster.c:

/*---------------------------------------------------
   commands:
   HELO USERID PW
   identifies who is making requests
   USERID is the PostgreSQL username for the user using the socket
   PW is the PostgreSQL password for the user using the socket.
   This command can ONLY be issued as the first command of
   a session.  If you need to change USERID's, you need to QUIT and
   start a new session.
   responses:
      200 HELO OK %s\r\n
          the %s substitution is the username from the HELO command.
	  500 Can't get DB connection (most likely invalid ID/PW) '%s'\r\n
          The PostgreSQL database rejected the connection.
              The %s substitution is the database error message.
          NOTE: this error can be generated at ANY time, if the database is
          cycled/crashed/etc.  The wording may be slightly different,
          but means the same thing.
--------------------------------------------
   CUSTID REFERENCE="xxxxxxxxx"
   asks if DB knows about a customer, returns unique ID
   REFERENCE field is 256 bytes of CHARACTER VARYING data.
   responses:
      250 CUSTID ID %s %s\r\n
          the first %s substitution is the unique ID
          for the REFERENCE number xxxxxx.
	  the 2nd %s substitution is (new) or (existing).
      500 no arguments given\r\n
          obvious error
      500 CUSTID command not followed by REFERENCE=\r\n
          obvious error
      590 DB ERROR: Report %s-%d-%d to networking\r\n
          The database returned an error.  The subsitution is a code to
	  correlate to syslog information on the host where netmaster runs.
	  will *ALWAYS* be followed by
The 595 message is at the moment #ifdef'd out
      595 Details Follow
          and a dump of the query, with \r\n.\r\n after it.
	  there is *NO* HTML escaping in these messages, HOWEVER they *ARE*
	  written to syslog on the  host where netmaster is running.
--------------------------------------------
   CUSTINFO id  NAME="xxxxxxxxxxxxxxxxxxx"
   adds/changes HUMAN name to xxxxxxxxxxxxxxx for unique id
         name is a 256 byte character varying field.
   responses:
      200 OK custinfo %s\r\n",
          means we've updated the table. The %s substitution is the
          id as supplied by you.
      500 no arguments given\r\n
          Obvious error message
      500 Invalid Character in id field, 0-9 ONLY are accepted\r\n
          Obvious error message
NB: 590/595 as described for CUSTID is ALWAYS possible.
--------------------------------------------
   CUSTINFO id ADDR="xxxxxxxxxxxxxxxxxxx"
   adds/changes address to xxxxxxxxxxxxxxx for unique id
         address is a 256 byte character varying field.
   responses:
      200 OK custinfo %s\r\n",
          means we've updated the table. The %s substitution is the
          id as supplied by you.
	  500 no arguments given\r\n
          Obvious error message
      500 Invalid Character in id field, 0-9 ONLY are accepted\r\n
          Obvious error message
NB: 590/595 as described for CUSTID is ALWAYS possible.
--------------------------------------------
   CUSTINFO id ADDR2="xxxxxxxxxxxxxxxxxxx"
          addr2 is a 256 byte character varying field.
   CUSTINFO id CITY="xxxxxxxxxxxxxxxxxxx"
          city is a 256 byte character varying field.
   CUSTINFO id STATE="xxxxxxxxxxxxxxxxxxx"
          State is a 256 byte character varying field.
   CUSTINFO id ZIP="xxxxxxxxxxxxxxxxxxx"
          Zip is a 256 byte character varying field.
   CUSTINFO id TEL="xxxxxxxxxxxxxxxxxxx"
          Zip is a 256 byte character varying field.
   CUSTINFO id COMPANY="xxxxxxxxxxxxxxxxxxx"
          Company is a 256 byte character varying field.
   CUSTINFO id COMMENT="xxxxxxxxxxxxxxxxxxx"
          comment is a 256 byte character varying field.
   CUSTINFO id EMAIL="xxxxxxxxxxxxxxxxxxx"
          email is a 256 byte character varying field.
   CUSTINFO id CORPORATE="Y|N|T|F"
          corporate is a 1 byte character field.
          T or Y means it *IS* a corporate account.
          F or N means it *IS NOT* a corporate account.
   same idea as previous 2.  NOTE: all KEYWORD="value" options may be spec'd
   in same command.
--------------------------------------------
   PROVASSIGN product id ASN SIZE ROUTERIP
   finds a block of SIZE in ASN for ROUTERIP and product
   and returns it, provisonally
   assigning it to CUSTID ID.
   responses:
      250 PROVASSIGN OK %s %s %s %s\r\n
          where the first %s substitution is the netblock in CIDR
          notation.
          the 2nd %s substitution is the base address of the netblock.
          the 3rd %s substitution is the mask length (/nn, without the
                  /)
          the 4th %s substitution is the netmask in dotted-decimal form
                  (255.255.255.0 for example for a /24).

      500 CUSTID NOT PROVIDED\r\n
      500 ASN NOT PROVIDED\r\n
      500 SIZE NOT PROVIDED\r\n
      500 ROUTERIP NOT PROVIDED\r\n
          the above 4 messages are obvious.
      500 Impossible size /%d\r\n
          for whatever reason, we can't deliver the %d substitution size.
      500 NO SUCH CUSTOMER ID (%s)\r\n
          Obvious.  The %s substitution is the id as supplied.
      500 IA doesn't issue /31's\r\n
          obvious
      500 IMPOSSIBLE NETBLOCK SIZE! /0\r\n
          obvious
      500 can't split to more than /17\r\n
          You asked for something in length, and there was none available
          and the split logic doesn't handle shorter than /17's.
      500 Invalid Routerip: %s\r\n
          The RouterIP isn't a valid IP address.
      500 No such product
      400 No Netblock available for request. Contact Networking.\r\n
      590 inet_aton on '%s' failed!!!!!\r\n",
          the system returned a netblock that the system inet_aton
          function failed.  SHOULD NOT OCCUR. REPORT THIS TO THE AUTHOR
          or current CODE owner. THIS IS A BUG!

NB: 590/595 as described in CUSTID is ALWAYS POSSIBLE.
    PROVASSIGN runs inside a DB transaction.  If you get a 590, the database is
    rolled back to the state it had before PROVASSIGN started.
--------------------------------------------
   ASSIGN id block JUSTNOW="x" JUST1YR="x" [FORCE="Y"|"N"]
   checks that block is assigned to CUSTID ID (unless FORCE=Y)
   sets the justification fields for BLOCK
   the justnow and just1yr fields are an integer and must pass the
   validation in the DB for an integer.
   responses:
      200 OK
      450 BLOCK ASSIGNED TO %s (%s) NOT UPDATED\r\n
          the 1st %s substitution is the UNIQUE id of who this
          block belongs to.
          the 2nd %s substitution is the billing reference number.
      500 CUSTID NOT PROVIDED\r\n
      500 Invalid characters in custid 0 through 9 only accepted\r\n
      500 BLOCK NOT PROVIDED\r\n

NB: 590/595 as described in CUSTID is ALWAYS POSSIBLE.
--------------------------------------------
   ASSIGN id block CUST_ASN="xxxx" [FORCE="Y"|"N"]
          the cust_asn field is an integer.  The RFC spec is a
          short unsigned integer.  The system does NOT enforce the values
          at the present time.  If the system was to enforce it,
          a violation would cause an UPDATE FAILED message.
   ASSIGN id block MISTOKEN="xxxx" [FORCE="Y"|"N"]
          the MISTOKEN field is a 16 byte field of characters.  The format
          is owned by MIS.  This is for future use.
   ASSIGN id block DESTIP="xxxx" [FORCE="Y"|"N"]
          The destip field is an INET field, and must be acceptable to the
          INET input routines of PostgreSQL.  When we pass the value
          to the database we strip leading and trailing spaces.  If the format
          is not acceptable, an UPDATE FAILED message will be generated.
   ASSIGN id block PURPOSE="xxx" [FORCE="Y"|"N"]
          The purpose field is a 256 Byte CHARACTER VARYING field.  It
          to a number from another table.  If you specify a name that is
          NOT in the purpose_table, you will get an SQL NULL in the field
          and it will display as blanks.  This *MAY* be changed later to force
          a pupose, and if so, an UPDATE FAILED message will be generated.
   ASSIGN id block INTERFACE="xxx" [FORCE="Y"|"N"]
          The INTERFACE field is a 256 Byte Character varying field.  It is
          for documentation at present.
   same ideas as JUSTxxx fields.
   same responses as above.
--------------------------------------------
   RETURN id block [STATUS="xxxxx"] [FORCE="Y"|"N"]
   returns netblock to available (or other status)
   status defaults to pending_available, which means the
   block can be recovered in case of screwups.  a block
   will stay in this state for 7 calendar days.
   The status field is a 256 byte character varying field that is
   turned into a number internally.  You must give a valid value.
   the default is pending_available.  If you give a NON valid value
   you will get an UPDATE FAILED message about NULL in NON-NULL.
   additional status' can be added at any time.
   responses:
      200 RETURN OK block
      450 BLOCK ASSIGNED TO %s (%s) NOT UPDATED\r\n
          the 1st %s substitution is the UNIQUE id of who this
          block belongs to.
          the 2nd %s substitution is the billing reference number.
      500 CUSTID NOT PROVIDED\r\n
      500 BLOCK NOT PROVIDED\r\n

NB: 590/595 as described in CUSTID is ALWAYS POSSIBLE.
--------------------------------------------
   EXAMINE netblock
         data is netblock in CIDR notation.  Missing /nn is NOT fatal.
   Responses:
   215 EXAMINE DATA FOLLOWS:\r\n
    keyword='value'
    keyword=SQL_NULL
   .
   This will dump known information about a netblock/IP and all
   netblocks that contain that netblock.  It will also dump information
   about the customers as well that are referenced from that netblock.

NB: 590/595 as described in CUSTID is ALWAYS POSSIBLE.
    keyword=SQL_NULL means there is NO data in that field.
--------------------------------------------
   MOVEBLOCK id1 block routerip1 id2 routerip2
        will move the netblock (in CIDR notation) from
	customer id1 on routerip1 to customer id2
	on routerip2.  NOTE: if you say the block is with one customer
	but it is NOT, the command will be rejected, same goes for
	routerip.
    500 CUSTID1 NOT PROVIDED\r\n
    500 CUSTID2 NOT PROVIDED\r\n
    500 BLOCK NOT PROVIDED\r\n
    500 ROUTERIP NOT PROVIDED\r\n
    500 ROUTERIP2 NOT PROVIDED\r\n
    500 no matching block found to move\r\n

NB: 590/595 as described in CUSTID is ALWAYS POSSIBLE.
    and in this case means you probably gave bogus information
    on the setting side.
--------------------------------------------
   POOLCREATE sizeblock sizepoolentries routerip name
       creates a pool of IP's of size sizeblock (/24,/25,/26,/27,/28)
       of sizepoolentries(/32,/30) taking into account the
       network and broadcast addresses of the requested pool
       for routerip and named name.
--------------------------------------------
   POOLASSIGN custid size routerip name
       assigns a /size block out of pool name for routerip
       to custid.
--------------------------------------------
   POOLRETURN custid block routerip name
       returns block to routerip's pool name
--------------------------------------------
   QUIT ends session.
        200 QUIT OK\r\n
--------------------------------------------
NB: All FORCE="Y"|"N" options are parsed but
    are NO-OPS.
---------------------------------------------------*/

/* $Id: netmaster.c,v 1.43 2001/10/10 21:30:06 ler Exp $ */


#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <ctype.h>
#include "libpq-fe.h"


#define IA_NETDB_NAME "netmaster"
#define IA_NETDB_HOST "localhost"
#define IA_NETDB_PORT 5432
#define NETMASTER_SYSLOG_FAC LOG_LOCAL0

static PGconn  *pgconn = NULL;
static char     db_error_message_buffer[32768];

typedef struct current_state {
	char            userid[32];
	char            pw[32];
	int             hello;
	int             quit;
	char            command[32];
	char            response[512];
	char            name[256];
	char            company[256];
	char            addr[256];
	char            addr2[256];
	char            city[256];
	char            state[256];
	char            zip[256];
	char            tel[256];
	char            comment[256];
	char            justnow[256];
	char            just1yr[256];
	char            cust_asn[256];
	char            mistoken[256];
	char            destip[256];
	char            status[256];
	char            force[256];
	char            id_char[256];
	char            id_char2[256];
	char            reference[256];
	char            asn[256];
	char            size[256];
	char            routerip[256];
	char            routerip2[256];
	char            block[256];
	char            purpose[256];
	char            email[256];
	char            interface[256];
	char            splitting_block[256];
	char            corporate[256];
	char            product[256];
}
                CURRENT_STATE;

char           *
myPQerrorMessage(PGconn * pgconn)
{
	static char     error_buffer[32768];
	memset(error_buffer, '\0', sizeof(error_buffer));
	strcpy(error_buffer, PQerrorMessage(pgconn));
	error_buffer[strlen(error_buffer) - 1] = '\0';	/* nuke the linefeed */
	return error_buffer;
}


#ifndef NM_SYSLOG_LIMIT
#define NM_SYSLOG_LIMIT 128
#endif

/*
 * Write a message line to syslog if the syslog option is set.
 * 
 * Our problem here is that many syslog implementations don't handle long
 * messages in an acceptable manner. While this function doesn't help that
 * fact, it does work around by splitting up messages into smaller pieces.
 */
static void
write_syslog(const char *line)
{
	static int      openlog_done = 0;
	static unsigned long seq = 0;
	static int      syslog_fac = NETMASTER_SYSLOG_FAC;

	int             len = strlen(line);


	if (!openlog_done) {
		openlog("NETMASTER", LOG_PID | LOG_NDELAY, syslog_fac);
		openlog_done = 1;
	}
	/*
	 * We add a sequence number to each log message to suppress "same"
	 * messages.
	 */
	seq++;

	/* divide into multiple syslog() calls if message is too long */
	/* or if the message contains embedded NewLine(s) '\n' */
	if (len > NM_SYSLOG_LIMIT || strchr(line, '\n') != NULL) {
		int             chunk_nr = 0;

		while (len > 0) {
			char            buf[NM_SYSLOG_LIMIT + 1];
			int             buflen;
			int             l;
			int             i;

			/* if we start at a newline, move ahead one char */
			if (line[0] == '\n') {
				line++;
				len--;
				continue;
			}
			strncpy(buf, line, NM_SYSLOG_LIMIT);
			buf[NM_SYSLOG_LIMIT] = '\0';
			if (strchr(buf, '\n') != NULL)
				*strchr(buf, '\n') = '\0';

			l = strlen(buf);
			/* already word boundary? */
			if (isspace((unsigned char)line[l]) || line[l] == '\0')
				buflen = l;
			else {
				/* try to divide at word boundary */
				i = l - 1;
				while (i > 0 && !isspace((unsigned char)buf[i]))
					i--;

				if (i <= 0)	/* couldn't divide word
						 * boundary */
					buflen = l;
				else {
					buflen = i;
					buf[i] = '\0';
				}
			}

			chunk_nr++;

			syslog(LOG_DEBUG, "[%lu-%d] %s", seq, chunk_nr, buf);
#if 0
			fprintf(stdout, "%s\r\n", buf);
#endif
			line += buflen;
			len -= buflen;
		}
	} else {
		/* message short enough */
		syslog(LOG_DEBUG, "[%lu] %s", seq, line);
#if 0
		fprintf(stdout, "%s\r\n", line);
#endif
	}
}

void
prepare_error_message(const char *query_string, const char *db_error_message)
{

	snprintf(db_error_message_buffer, sizeof(db_error_message_buffer),
		 "%s-%d-%d\nQuery='%s'\nDBerror='%s'",
		 IA_NETDB_HOST,
		 (int)getpid(), (int)time(NULL), query_string,
		 db_error_message);
#if 0
	fprintf(stdout, "595 Details Follow:\r\n");
	fflush(stdout);
#endif
	write_syslog(db_error_message_buffer);
#if 0
	fprintf(stdout, "\r\n.\r\n");
	fflush(stdout);
#endif
}

char           *
cleanse_field(char *string)
{
	int             i;
	static char     buffer[32768];
	char           *char_ptr = &(buffer[0]);
	char           *char_ptr2 = &(string[0]);
	memset(buffer, '\0', sizeof(buffer));
	for (i = 0; i < strlen(string); i++) {
		if (*char_ptr2 == '\'') {
			*char_ptr++ = '\'';
		}
		*char_ptr++ = *char_ptr2++;
	}
	return buffer;
}

/*
 * make a new set of blocks of size from a /24 (or split something larger)
 */
int
split_block(CURRENT_STATE * cur_state, char *resp_buffer, int size, int asn)
{
	char            query_string[8192];
	char            result_string[8192];
	struct in_addr  work_addr1;
#ifdef NON_VLSM_ALLOWED
	int             i;
#endif
	int             vlsm = 0;	/* =0 means break up /24's into equal
					 * sizes, =1 means find size one
					 * bigger, and break in half */
	int             numaddr = 0;
	PGresult       *pgres;

	query_string[0] = '\0';
	switch (size) {
	case 32:
		numaddr = 1;
		sprintf(resp_buffer, "500 Splitting to /32 should be done in "
			"address pool logic\r\n");
		return 1;
		break;
	case 31:
		sprintf(resp_buffer, "500 IA doesn't issue /31's\r\n");
		return 1;
	case 30:
		numaddr = 4;
		break;
	case 29:
		numaddr = 8;
		break;
	case 28:
		numaddr = 16;
		break;
	case 27:
		numaddr = 32;
		break;
	case 26:
		numaddr = 64;
		break;
	case 25:
		numaddr = 128;
		break;
	case 24:
		numaddr = 256;
		break;
#ifdef HANDLE_SHORTER_THAN_24
	case 23:
		numaddr = 512;
		break;
	case 22:
		numaddr = 1024;
		break;
	case 21:
		numaddr = 2048;
		break;
	case 20:
		numaddr = 4096;
		break;
	case 19:
		numaddr = 8192;
		break;
	case 18:
		numaddr = 16384;
		break;
	case 17:
		numaddr = 32768;
		break;
#endif
	case 0:
		sprintf(resp_buffer, "500 IMPOSSIBLE NETBLOCK SIZE! /0\r\n");
		return 0;
	default:
		sprintf(resp_buffer,
			"500 request for a netblock less than /24 in length "
			"needs NETWORKING action\r\n");
		return 2;
	}
#ifdef DALLAS_NON_VLSM
	if (asn != 4278)
#endif
		vlsm = 1;
retry_block_split:
	snprintf(query_string, sizeof(query_string),
		 "SELECT host(netblock), masklen(netblock), netblock, "
		 "broadcast(netblock) "
		 "FROM networks "
		 "WHERE parent_asn=%d AND "
		 "status=get_status_code('available') AND "
		 "masklen(netblock) = %d "
		 "FOR UPDATE "
	      "LIMIT 1", asn, ((vlsm == 0) && (size > 24) ? 24 : size - 1));
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_TUPLES_OK || PQntuples(pgres) != 1) {
		/* need to recurse in the vlsm case */
		if ((size - 1) < 24) {
			sprintf(resp_buffer,
				"400 No Netblock available for request. Contact Networking.\r\n");
			PQexec(pgconn, "ROLLBACK TRANSACTION");
			return 1;
		}
		if (split_block(cur_state, resp_buffer, size - 1, asn) != 0) {
			return 1;
		}
		goto retry_block_split;
	}
	strcpy(result_string, PQgetvalue(pgres, 0, 0));
	if (inet_aton(result_string, &work_addr1) != 1) {
		sprintf(resp_buffer, "590 inet_aton on '%s' failed!!!!!\r\n",
			result_string);
		PQclear(pgres);
		PQexec(pgconn, "ROLLBACK TRANSACTION");
		return 1;
	}
#ifdef NON_VLSM_ALLOWED
	/*
	 * deal with /32 on net/bcast
	 *//* also, nothing < /24 w/o networking approval */
	for (i = 0; i < (size > 24 ? 256 : 32768); i += numaddr) {
		snprintf(query_string, sizeof(query_string),
			 "INSERT INTO networks(netblock,status, "
			 "last_update_by,last_update_at, "
			 "parent_asn) VALUES('%s/%d', "
			 "get_status_code('available'), "
			 "'SPLIT_NETBLOCK',now(),%d) ",
			 inet_ntoa(work_addr1), size, asn);
		pgres = PQexec(pgconn, query_string);
		if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
			sprintf(resp_buffer,
			  "590 DB ERROR: Report %s-%d-%d to networking\r\n",
			     IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
			fprintf(stdout, resp_buffer);
			prepare_error_message(query_string, myPQerrorMessage(pgconn));
			fflush(stdout);
			PQexec(pgconn, "ROLLBACK TRANSACTION");
			PQclear(pgres);
			return 1;
		}
		work_addr1.s_addr = htonl(ntohl(work_addr1.s_addr) + numaddr);
		PQclear(pgres);
	}
#endif
#ifndef NON_VLSM_ALLOWED	/* break in half */
	snprintf(query_string, sizeof(query_string),
		 "INSERT INTO networks(netblock,status, "
		 "last_update_by,last_update_at, "
		 "parent_asn) VALUES('%s/%d', "
		 "get_status_code('available'), "
		 "'SPLIT_NETBLOCK', now(), %d)", inet_ntoa(work_addr1), size,
		 asn);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer, "590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQexec(pgconn, "ROLLBACK TRANSACTION");
		PQclear(pgres);
		return 1;
	}
	work_addr1.s_addr = htonl(ntohl(work_addr1.s_addr) + numaddr);
	PQclear(pgres);
	snprintf(query_string, sizeof(query_string),
		 "INSERT INTO networks(netblock,status, "
		 "last_update_by,last_update_at, "
		 "parent_asn) VALUES('%s/%d', "
		 "get_status_code('available'), "
	   "'SPLIT_NETBLOCK',now(), %d)", inet_ntoa(work_addr1), size, asn);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQexec(pgconn, "ROLLBACK TRANSACTION");
		PQclear(pgres);
		return 1;
	}
	work_addr1.s_addr = htonl(ntohl(work_addr1.s_addr) + numaddr);
	PQclear(pgres);
#endif
	snprintf(query_string, sizeof(query_string),
		 "UPDATE networks "
		 "SET status=get_status_code('subdivided'), "
		 "last_update_by='SPLIT_NETBLOCK',last_update_at=now() "
		 "WHERE netblock='%s/%d'", result_string,
		 ((vlsm == 0) && (size > 24) ? 24 : size - 1));
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQexec(pgconn, "ROLLBACK TRANSACTION");
		PQclear(pgres);
		return 1;

	}
	PQclear(pgres);
	return 0;
}

int
get_netblock_provisionally(CURRENT_STATE * cur_state, char *resp_buffer,
			   int size, int asn, char *block)
{
	char            query_string[8192];
	char            result_netblock_cidr[8192];
	char            result_netblock[8192];
	char            result_masklen[8192];
	char            result_netmask[8192];
	PGresult       *pgres;

	if (size == 0 || size == 31 || size < 17 || size > 32 || size < 0) {
		sprintf(resp_buffer, "500 Impossible size /%d\r\n", size);
		return 1;
	}
	query_string[0] = '\0';
	if (PQstatus(pgconn) == CONNECTION_BAD) {
		snprintf(query_string, sizeof(query_string),
			 "dbname=%s user=%s password=%s host=%s port=%d",
			 IA_NETDB_NAME, cur_state->userid,
			 cur_state->pw, IA_NETDB_HOST, IA_NETDB_PORT);
		pgconn = PQconnectdb(query_string);
		if (PQstatus(pgconn) == CONNECTION_BAD) {
			sprintf(resp_buffer, "500 Can't get DB connection '%s'\r\n",
				myPQerrorMessage(pgconn));
			cur_state->quit = 1;
			return 0;
		}
	}
	pgres = PQexec(pgconn, "BEGIN TRANSACTION");
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message("BEGIN TRANSACTION", myPQerrorMessage(pgconn));
		PQexec(pgconn, "ROLLBACK TRANSACTION");
		PQclear(pgres);
		return 0;

		PQclear(pgres);
		return 0;
	}
	snprintf(query_string, sizeof(query_string),
	      "SELECT id FROM customer " 
              "WHERE id=%s", cur_state->id_char);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_TUPLES_OK || PQntuples(pgres) == 0) {
		sprintf(resp_buffer, "500 NO SUCH CUSTOMER ID (%s)\r\n",
			cur_state->id_char);
		PQexec(pgconn, "ROLLBACK TRANSACTION");
		PQclear(pgres);
		return 1;
	}
        snprintf(query_string,"
retry_block:
	snprintf(query_string, sizeof(query_string),
		 "SELECT host(netblock),masklen(netblock),netblock,"
		 "netmask(netblock) "
		 "FROM networks "
		 "WHERE parent_asn=%d AND "
		 "status=get_status_code('available') AND "
		 "masklen(netblock) = %d FOR UPDATE LIMIT 1", asn, size);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_TUPLES_OK || PQntuples(pgres) == 0) {
		if (split_block(cur_state, resp_buffer, size, asn) != 0) {
			return 2;
		}
		goto retry_block;
	}
	if (PQntuples(pgres) != 1) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQexec(pgconn, "ROLLBACK TRANSACTION");
		PQclear(pgres);
		return 0;

	}
	/* get NetBlock in CIDR notation */
	strcpy(result_netblock_cidr, PQgetvalue(pgres, 0, 2));
	/* get NetBlock */
	strcpy(result_netblock, PQgetvalue(pgres, 0, 0));
	/* get MaskLen */
	strcpy(result_masklen, PQgetvalue(pgres, 0, 1));
	strcpy(result_netmask, PQgetvalue(pgres, 0, 3));
	PQclear(pgres);
	snprintf(query_string, sizeof(query_string),
		 "UPDATE networks "
		 "SET status=get_status_code('provisionally_assigned'), "
		 "last_update_by='%s',last_update_at=now(), "
		 "assigned_date=now(),assigned_by='%s', "
		 "router=get_router_id('%s'::inet), "
		 "customer_reference=%s "
		 "WHERE netblock='%s'",
		 cur_state->userid,
		 cur_state->userid, cur_state->routerip,
		 cur_state->id_char, result_netblock_cidr);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQexec(pgconn, "ROLLBACK TRANSACTION");
		PQclear(pgres);
		return 0;

	}
	pgres = PQexec(pgconn, "COMMIT TRANSACTION");
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message("COMMIT TRANSACTION", myPQerrorMessage(pgconn));
		PQexec(pgconn, "ROLLBACK TRANSACTION");
		PQclear(pgres);
		return 0;

		/* bad PG, commit failed */
	}
	sprintf(resp_buffer, "250 PROVASSIGN OK %s %s %s %s\r\n",
		result_netblock_cidr,
		result_netblock, result_masklen, result_netmask);
	strcpy(block, result_netblock_cidr);
	PQclear(pgres);
	return 0;
}

void
reset_state(CURRENT_STATE * cur_state)
{
	cur_state->command[0] = '\0';
	cur_state->response[0] = '\0';
	cur_state->name[0] = '\0';
	cur_state->company[0] = '\0';
	cur_state->addr[0] = '\0';
	cur_state->addr2[0] = '\0';
	cur_state->city[0] = '\0';
	cur_state->state[0] = '\0';
	cur_state->zip[0] = '\0';
	cur_state->tel[0] = '\0';
	cur_state->comment[0] = '\0';
	cur_state->justnow[0] = '\0';
	cur_state->just1yr[0] = '\0';
	cur_state->cust_asn[0] = '\0';
	cur_state->mistoken[0] = '\0';
	cur_state->destip[0] = '\0';
	cur_state->status[0] = '\0';
	cur_state->force[0] = '\0';
	cur_state->id_char[0] = '\0';
	cur_state->id_char2[0] = '\0';
	cur_state->reference[0] = '\0';
	cur_state->asn[0] = '\0';
	cur_state->size[0] = '\0';
	cur_state->routerip[0] = '\0';
	cur_state->routerip2[0] = '\0';
	cur_state->block[0] = '\0';
	cur_state->purpose[0] = '\0';
	cur_state->email[0] = '\0';
	cur_state->interface[0] = '\0';
}

int
process_helo(CURRENT_STATE * cur_state, char *resp_buffer)
{
	char            query_string[8192];
	query_string[0] = '\0';
	if (PQstatus(pgconn) == CONNECTION_BAD) {
		snprintf(query_string, sizeof(query_string),
			 "dbname=%s user=%s password=%s host=%s port=%d",
			 IA_NETDB_NAME, cur_state->userid,
			 cur_state->pw, IA_NETDB_HOST, IA_NETDB_PORT);
		pgconn = PQconnectdb(query_string);
		if (PQstatus(pgconn) == CONNECTION_BAD) {
			sprintf(resp_buffer, "500 Can't get DB connection"
				" (most likely invalid ID/PW) '%s'\r\n",
				myPQerrorMessage(pgconn));
			cur_state->quit = 1;
			return 0;
		}
	}
	sprintf(resp_buffer, "200 HELO OK %s\r\n", cur_state->userid);
	return 0;
}

int
process_custid(CURRENT_STATE * cur_state,
	       char *work_buffer, char *resp_buffer)
{
	char            token[8192];
	char            query_string[8192];
	char           *tkn;
	int             made_new_id = 0;
	PGresult       *pgres;

	query_string[0] = '\0';
	tkn = strtok(NULL, "=");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 no arguments given\r\n");
		return 0;
	}
	strcpy(token, tkn);
	if (strcasecmp(token, "REFERENCE") != 0) {
		sprintf(resp_buffer,
			"500 CUSTID command not followed by REFERENCE=\r\n");
		cur_state->quit = 1;
		return 0;
	}
	strcpy(cur_state->reference, strtok(NULL, "\""));
	if (PQstatus(pgconn) == CONNECTION_BAD) {
		snprintf(query_string, sizeof(query_string),
			 "dbname=%s user=%s password=%s host=%s port=%d",
			 IA_NETDB_NAME, cur_state->userid,
			 cur_state->pw, IA_NETDB_HOST, IA_NETDB_PORT);
		pgconn = PQconnectdb(query_string);
		if (PQstatus(pgconn) == CONNECTION_BAD) {
			sprintf(resp_buffer, "500 Can't get DB connection '%s'\r\n",
				myPQerrorMessage(pgconn));
			cur_state->quit = 1;
			return 0;
		}
	}
retry_id_custid:
	snprintf(query_string, sizeof(query_string),
		 "SELECT get_customer_id('%s')", cur_state->reference);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_TUPLES_OK ||
	    PQntuples(pgres) == 0 || PQgetisnull(pgres, 0, 0) == 1) {
		/* assign new id */
		PQclear(pgres);
		snprintf(query_string, sizeof(query_string),
			 "INSERT INTO customer(reference_number) "
			 "VALUES('%s')", cur_state->reference);
		pgres = PQexec(pgconn, query_string);
		if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
			sprintf(resp_buffer,
			  "590 DB ERROR: Report %s-%d-%d to networking\r\n",
			     IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
			prepare_error_message(query_string, myPQerrorMessage(pgconn));
			PQclear(pgres);

			cur_state->quit = 1;
			return 0;
		}
		PQclear(pgres);
		made_new_id = 1;
		goto retry_id_custid;
	}
	sprintf(resp_buffer, "250 CUSTID %s %s\r\n",
	     PQgetvalue(pgres, 0, 0), made_new_id ? "(new)" : "(existing)");
	return 0;
}

int
process_custinfo(CURRENT_STATE * cur_state,
		 char *work_buffer, char *resp_buffer)
{
	char            token[8192];
	char            value[8192];
	int             done = 0;
	char           *tkn;
	PGresult       *pgres;
	char            query_string[8192];
	char            fields[8192];

	query_string[0] = '\0';
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 no arguments given\r\n");
		return 0;
	}
	strcpy(cur_state->id_char, tkn);
	if (strspn(cur_state->id_char, "0123456789") !=
	    strlen(cur_state->id_char)) {
		strcpy(resp_buffer,
		       "500 Invalid Character in id field, 0-9 ONLY are accepted\r\n");
		return 0;
	}
	fields[0] = '\0';

	while (!done) {
		tkn = strtok(NULL, "= \r\n");
		if (tkn == NULL) {
			done = 1;
			continue;
		}
		strcpy(token, tkn);
		tkn = strtok(NULL, "\"");
		if (tkn == NULL) {
			done = 1;
			continue;
		}
		strcpy(value, tkn);
		strcpy(value, cleanse_field(value));
		if (strcasecmp(token, "NAME") == 0) {
			strncpy(cur_state->name, value, sizeof(cur_state->name));
		}
		if (strcasecmp(token, "ADDR") == 0) {
			strncpy(cur_state->addr, value, sizeof(cur_state->addr));

		}
		if (strcasecmp(token, "ADDR2") == 0)
			strncpy(cur_state->addr2, value, sizeof(cur_state->addr2));
		if (strcasecmp(token, "CITY") == 0)
			strncpy(cur_state->city, value, sizeof(cur_state->city));
		if (strcasecmp(token, "STATE") == 0)
			strncpy(cur_state->state, value, sizeof(cur_state->state));
		if (strcasecmp(token, "ZIP") == 0)
			strncpy(cur_state->zip, value, sizeof(cur_state->zip));
		if (strcasecmp(token, "TEL") == 0)
			strncpy(cur_state->tel, value, sizeof(cur_state->tel));
		if (strcasecmp(token, "COMPANY") == 0)
			strncpy(cur_state->company, value, sizeof(cur_state->company));
		if (strcasecmp(token, "COMMENT") == 0)
			strncpy(cur_state->comment, value, sizeof(cur_state->comment));
		if (strcasecmp(token, "EMAIL") == 0)
			strncpy(cur_state->email, value, sizeof(cur_state->email));
		if (strcasecmp(token, "CORPORATE") == 0) {
			value[1] = '\0';
			if (value[0] == 'Y' || value[0] == 'T' ||
			    value[0] == 'y' ||
			    value[0] == 't') {
				value[0] = 't';
			}
			if (value[0] == 'N' || value[0] == 'n' ||
			    value[0] == 'F' ||
			    value[0] == 'f') {
				value[0] = 'f';
			}
			strncpy(cur_state->corporate, value, sizeof(cur_state->corporate));
		}
	}
	if (PQstatus(pgconn) == CONNECTION_BAD) {
		snprintf(query_string, sizeof(query_string),
			 "dbname=%s user=%s password=%s host=%s port=%d",
			 IA_NETDB_NAME, cur_state->userid,
			 cur_state->pw, IA_NETDB_HOST, IA_NETDB_PORT);
		pgconn = PQconnectdb(query_string);
		if (PQstatus(pgconn) == CONNECTION_BAD) {
			sprintf(resp_buffer, "500 Can't get DB connection '%s'\r\n",
				myPQerrorMessage(pgconn));
			cur_state->quit = 1;
			return 0;
		}
	}
	if (strlen(cur_state->name) != 0) {
		snprintf(value, sizeof(value), "name='%s'", cur_state->name);
		strcat(fields, value);
	}
	if (strlen(cur_state->addr) != 0) {
		snprintf(value, sizeof(value),
			 "%saddress='%s'", strlen(fields) ? "," : "",
			 cur_state->addr);
		strcat(fields, value);
	}
	if (strlen(cur_state->addr2) != 0) {
		snprintf(value, sizeof(value),
			 "%saddress2='%s'", strlen(fields) ? "," : "",
			 cur_state->addr2);
		strcat(fields, value);
	}
	if (strlen(cur_state->city) != 0) {
		snprintf(value, sizeof(value),
		 "%scity='%s'", strlen(fields) ? "," : "", cur_state->city);
		strcat(fields, value);
	}
	if (strlen(cur_state->state) != 0) {
		snprintf(value, sizeof(value),
		"%sstate='%s'", strlen(fields) ? "," : "", cur_state->state);
		strcat(fields, value);
	}
	if (strlen(cur_state->zip) != 0) {
		snprintf(value, sizeof(value),
		   "%szip='%s'", strlen(fields) ? "," : "", cur_state->zip);
		strcat(fields, value);
	}
	if (strlen(cur_state->email) != 0) {
		snprintf(value, sizeof(value),
		"%semail='%s'", strlen(fields) ? "," : "", cur_state->email);
		strcat(fields, value);
	}
	if (strlen(cur_state->tel) != 0) {
		snprintf(value, sizeof(value),
			 "%stelephone='%s'", strlen(fields) ? "," : "",
			 cur_state->tel);
		strcat(fields, value);
	}
	if (strlen(cur_state->comment) != 0) {
		snprintf(value, sizeof(value),
			 "%scomment='%s'", strlen(fields) ? "," : "",
			 cur_state->comment);
		strcat(fields, value);
	}
	if (strlen(cur_state->company) != 0) {
		snprintf(value, sizeof(value),
			 "%scompany='%s'", strlen(fields) ? "," : "",
			 cur_state->company);
		strcat(fields, value);
	}
	if (strlen(cur_state->corporate) != 0) {
		snprintf(value, sizeof(value),
			 "%scorporate='%s'", strlen(fields) ? "," : "",
			 cur_state->corporate);
		strcat(fields, value);
	}
	snprintf(query_string, sizeof(query_string),
		 "UPDATE customer SET %s "
		 "WHERE id=%s", fields, cur_state->id_char);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQclear(pgres);
		return 0;
	}
	sprintf(resp_buffer, "200 OK custinfo %s\r\n", cur_state->id_char);
	return 0;
}

int
process_moveblock(CURRENT_STATE * cur_state,
		  char *work_buffer, char *resp_buffer)
{
	char           *tkn;
	char            query_string[8192];
	PGresult       *pgres;

	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 CUSTID1 NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->id_char, tkn, sizeof(cur_state->id_char));
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 BLOCK NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->block, tkn, sizeof(cur_state->block));
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 ROUTERIP1 NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->routerip, tkn, sizeof(cur_state->routerip));
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 CUSTID2 NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->id_char2, tkn, sizeof(cur_state->id_char2));
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 ROUTERIP2 NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->routerip2, tkn, sizeof(cur_state->routerip2));
	pgres = PQexec(pgconn, "BEGIN WORK");
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message("BEGIN WORK", myPQerrorMessage(pgconn));
		PQclear(pgres);
		return 0;
	}
	snprintf(query_string, sizeof(query_string),
		 "SELECT netblock FROM networks "
		 "WHERE netblock='%s' AND customer_reference=%s "
		 "AND router=get_router_id('%s'::inet) "
		 "FOR UPDATE LIMIT 1",
		 cur_state->block, cur_state->id_char, cur_state->routerip);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_TUPLES_OK || PQntuples(pgres) != 1) {
		strcpy(resp_buffer, "500 no matching block found to move\r\n");
		PQclear(pgres);
		pgres = PQexec(pgconn, "ROLLBACK WORK");
		if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
			sprintf(resp_buffer,
			  "590 DB ERROR: Report %s-%d-%d to networking\r\n",
			     IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
			prepare_error_message("ROLLBACK WORK", myPQerrorMessage(pgconn));
			PQclear(pgres);
			return 0;
		}
		return 0;
	}
	snprintf(query_string, sizeof(query_string),
		 "UPDATE networks "
		 "SET customer_reference=%s,router=get_router_id('%s'::inet),"
		 "other_reference=get_customer_reference(%s),"
		 "last_update_at=now(),last_update_by='%s' "
		 "WHERE netblock='%s' AND customer_reference=%s "
		 "AND router=get_router_id('%s'::inet) ",
		 cur_state->id_char2, cur_state->routerip2,
	         cur_state->id_char2,cur_state->userid,
		 cur_state->block, cur_state->id_char, cur_state->routerip);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQclear(pgres);
		PQexec(pgconn, "ROLLBACK WORK");
		if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
			sprintf(resp_buffer,
			  "590 DB ERROR: Report %s-%d-%d to networking\r\n",
			     IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
			prepare_error_message("ROLLBACK WORK", myPQerrorMessage(pgconn));
			PQclear(pgres);
			return 0;
		}
		return 0;
	}
	strcpy(resp_buffer, "200 MOVEBLOCK OK\r\n");
	PQexec(pgconn, "COMMIT WORK");
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message("COMMIT WORK", myPQerrorMessage(pgconn));
		PQclear(pgres);
		return 0;
	}
	return 0;
}

int
process_provassign(CURRENT_STATE * cur_state,
		   char *work_buffer, char *resp_buffer)
{
	char           *tkn;
	int             asn, size;
	struct in_addr  work_addr1;

	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 CUSTID NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->id_char, tkn, sizeof(cur_state->id_char));
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 ASN NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->asn, tkn, sizeof(cur_state->asn));
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 SIZE NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->size, tkn, sizeof(cur_state->size));
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 ROUTERIP NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->routerip, tkn, sizeof(cur_state->routerip));
	if (inet_aton(cur_state->routerip, &work_addr1) != 1) {
		sprintf(resp_buffer, "500 Invalid Routerip: %s\r\n",
			cur_state->routerip);
		return 0;
	}
	asn = strtol(cur_state->asn, NULL, 10);
	size = strtol(cur_state->size, NULL, 10);

	return get_netblock_provisionally(cur_state, resp_buffer,
					  size, asn, work_buffer);
}

int
process_assign(CURRENT_STATE * cur_state,
	       char *work_buffer, char *resp_buffer)
{
	char            token[8192];
	char            value[8192];
	char            fields[8192];
	char           *ptr;
	char            query_string[8192];
	PGresult       *pgres;
	int             done = 0;
	char           *tkn;

	query_string[0] = '\0';
	fields[0] = '\0';
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 CUSTID NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->id_char, tkn, sizeof(cur_state->id_char));
	if (strspn(cur_state->id_char, "0123456789") !=
	    strlen(cur_state->id_char)) {
		sprintf(resp_buffer,
			"500 Invalid characters in custid 0 through 9 only accepted\r\n");
		return 0;
	}
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 BLOCK NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->block, tkn, sizeof(cur_state->block));
	while (!done) {
		tkn = strtok(NULL, "= \r\n");
		if (tkn == NULL) {
			done = 1;
			continue;
		}
		strcpy(token, tkn);
		if (strcasecmp(token, "") == 0) {
			done = 1;
			continue;
		}
		strcpy(value, strtok(NULL, "\""));
		strcpy(value, cleanse_field(value));
		if (strcasecmp(value, "") == 0) {
			done = 1;
			continue;
		}
		if (strcasecmp(token, "CUST_ASN") == 0)
			strncpy(cur_state->cust_asn, value, sizeof(cur_state->cust_asn));
		if (strcasecmp(token, "MISTOKEN") == 0)
			strncpy(cur_state->mistoken, value, sizeof(cur_state->mistoken));
		if (strcasecmp(token, "DESTIP") == 0) {
			strncpy(cur_state->destip, value, sizeof(cur_state->destip));
			ptr = strchr(cur_state->destip, ' ');
			if (ptr != NULL)
				*ptr = '\0';
		}
		if (strcasecmp(token, "PURPOSE") == 0)
			strncpy(cur_state->purpose, value, sizeof(cur_state->purpose));
		if (strcasecmp(token, "FORCE") == 0)
			strncpy(cur_state->force, value, sizeof(cur_state->force));
		if (strcasecmp(token, "JUSTNOW") == 0)
			strncpy(cur_state->justnow, value, sizeof(cur_state->justnow));
		if (strcasecmp(token, "JUST1YR") == 0)
			strncpy(cur_state->just1yr, value, sizeof(cur_state->just1yr));
		if (strcasecmp(token, "INTERFACE") == 0)
			strncpy(cur_state->interface, value, sizeof(cur_state->interface));
	}
	if (PQstatus(pgconn) == CONNECTION_BAD) {
		snprintf(query_string, sizeof(query_string),
			 "dbname=%s user=%s password=%s host=%s port=%d",
			 IA_NETDB_NAME, cur_state->userid,
			 cur_state->pw, IA_NETDB_HOST, IA_NETDB_PORT);
		pgconn = PQconnectdb(query_string);
		if (PQstatus(pgconn) == CONNECTION_BAD) {
			sprintf(resp_buffer, "500 Can't get DB connection '%s'\r\n",
				myPQerrorMessage(pgconn));
			cur_state->quit = 1;
			return 0;
		}
	}
	pgres = PQexec(pgconn, "BEGIN WORK");
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message("BEGIN WORK", myPQerrorMessage(pgconn));
		PQclear(pgres);
		return 0;
	}
	snprintf(query_string, sizeof(query_string),
		 "SELECT netblock,customer_reference,"
		 "get_customer_reference(customer_reference) "
		 "FROM   networks "
		 "WHERE  netblock='%s' FOR UPDATE ", cur_state->block);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_TUPLES_OK || PQntuples(pgres) != 1) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQclear(pgres);
		pgres = PQexec(pgconn, "ROLLBACK WORK");
		if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
			sprintf(resp_buffer,
			  "590 DB ERROR: Report %s-%d-%d to networking\r\n",
			     IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
			prepare_error_message("ROLLBACK WORK", myPQerrorMessage(pgconn));
			PQclear(pgres);
			return 0;
		}
		return 0;
	}
	if (strcmp(cur_state->id_char, PQgetvalue(pgres, 0, 1)) != 0) {
		sprintf(resp_buffer, "450 BLOCK ASSIGNED TO %s (%s) NOT UPDATED\r\n",
			PQgetvalue(pgres, 0, 1), PQgetvalue(pgres, 0, 2));
		pgres = PQexec(pgconn, "ROLLBACK WORK");
		if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
			sprintf(resp_buffer,
			  "590 DB ERROR: Report %s-%d-%d to networking\r\n",
			     IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
			prepare_error_message("ROLLBACK WORK", myPQerrorMessage(pgconn));
			PQclear(pgres);
			return 0;
		}
		return 0;
	}
	if (strlen(cur_state->justnow) != 0) {
		snprintf(value, sizeof(value),
			 "justification_now=%s", cur_state->justnow);
		strcat(fields, value);
	}
	if (strlen(cur_state->just1yr) != 0) {
		snprintf(value, sizeof(value),
			 "%sjustification_1yr=%s", strlen(fields) ? "," : "",
			 cur_state->just1yr);
		strcat(fields, value);
	}
	if (strlen(cur_state->cust_asn) != 0) {
		snprintf(value, sizeof(value),
			 "%scust_asn=%s", strlen(fields) ? "," : "",
			 cur_state->cust_asn);
		strcat(fields, value);
	}
	if (strlen(cur_state->mistoken) != 0) {
		snprintf(value, sizeof(value),
			 "%smistoken='%s'", strlen(fields) ? "," : "",
			 cur_state->mistoken);
		strcat(fields, value);
	}
	if (strlen(cur_state->destip) != 0) {
		snprintf(value, sizeof(value),
			 "%sdest_ip='%s'", strlen(fields) ? "," : "",
			 cur_state->destip);
		strcat(fields, value);
	}
	if (strlen(cur_state->interface) != 0) {
		snprintf(value, sizeof(value),
			 "%sinterface='%s'", strlen(fields) ? "," : "",
			 cur_state->interface);
		strcat(fields, value);
	}
	if (strlen(cur_state->purpose) != 0) {
		snprintf(value, sizeof(value),
			 "%spurpose=get_purpose_code('%s')",
			 strlen(fields) ? "," : "", cur_state->purpose);
		strcat(fields, value);
	}
	snprintf(value, sizeof(value),
		 "%sstatus=get_status_code('assigned')",
		 strlen(fields) ? "," : "");
	strcat(fields, value);
	snprintf(value, sizeof(value),
		 "%sother_reference=get_customer_reference(%s)",
		 strlen(fields) ? "," : "", cur_state->id_char);
	strcat(fields, value);
	snprintf(value, sizeof(value),
		 "%slast_update_at=now(),last_update_by='%s'",
		 strlen(fields) ? "," : "", cur_state->userid);
	strcat(fields, value);
	snprintf(query_string, sizeof(query_string),
		 "UPDATE networks "
		 "SET %s " "WHERE netblock='%s'", fields, cur_state->block);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQclear(pgres);
		pgres = PQexec(pgconn, "ROLLBACK WORK");
		if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
			sprintf(resp_buffer,
			  "590 DB ERROR: Report %s-%d-%d to networking\r\n",
			     IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
			prepare_error_message("ROLLBACK WORK", myPQerrorMessage(pgconn));
			PQclear(pgres);

			return 0;
		}
		return 0;
	}
	sprintf(resp_buffer, "200 ASSIGN OK\r\n");
	pgres = PQexec(pgconn, "COMMIT WORK");
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message("COMMIT WORK", myPQerrorMessage(pgconn));
		PQclear(pgres);
		return 0;
	}
	return 0;
}

int
process_examine(CURRENT_STATE * cur_state,
		char *work_buffer, char *resp_buffer)
{
	char            query_string[8192];
	PGresult       *pgres;
	int             i = 0, j = 0;
	char           *tkn;

	query_string[0] = '\0';
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 BLOCK NOT PROVIDED\r\n");
		return 0;
	}
	strcpy(cur_state->block, cleanse_field(tkn));
	if (strlen(cur_state->block) > 40) {
		strcpy(resp_buffer, "500 Invalid Block\r\n");
		return 0;
	}
	snprintf(query_string, sizeof(query_string),
		 "SELECT netblock,get_status(status) as netblock_status, "
		 "parent_asn as asn,cust_asn, "
		 "get_customer_name(customer_reference) as customer_name,"
	     "get_customer_company(customer_reference) as customer_company,"
	     "get_customer_address(customer_reference) as customer_address,"
	   "get_customer_address2(customer_reference) as customer_address2,"
		 "get_customer_city(customer_reference) as customer_city,"
		 "get_customer_state(customer_reference) as customer_state,"
		 "get_customer_zip(customer_reference) as customer_zip,"
	       "get_customer_telephone(customer_reference) as customer_tel,"
		 "get_customer_email(customer_reference) as customer_email,"
		 "get_customer_reference(customer_reference) as reference,"
	       "get_customer_comments(customer_reference) as cust_comments,"
		 "justification_now as just_now,"
		 "justification_1yr as just_1yr,"
		 "get_router_name(router) as router_name,"
		 "get_router_ip(router) as router_ip,"
		 "interface as router_interface,"
		 "dest_ip as destip,"
		 "comments as net_comments "
		 "FROM networks "
		 "WHERE '%s' <<= netblock " "ORDER BY netblock DESC",
		 cur_state->block);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQclear(pgres);
		return 0;
	}
	/* print a tuple or 2 */
	fprintf(stdout, "215 EXAMINE DATA FOLLOWS:\r\n");
	fflush(stdout);
	for (i = 0; i < PQntuples(pgres); i++) {
		for (j = 0; j < PQnfields(pgres); j++) {
			if (PQgetisnull(pgres, i, j)) {
				fprintf(stdout, " %s=SQL_NULL\r\n", PQfname(pgres, j));
			} else
				fprintf(stdout, " %s='%s'\r\n", PQfname(pgres, j),
					PQgetvalue(pgres, i, j));
		}
	}
	sprintf(resp_buffer, ".\r\n");
	return 0;
}

int
process_return(CURRENT_STATE * cur_state,
	       char *work_buffer, char *resp_buffer)
{
	char            token[8192];
	char            value[8192];
	char            query_string[8192];
	PGresult       *pgres;
	int             done = 0;
	char           *tkn;

	query_string[0] = '\0';
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 CUSTID NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->id_char, tkn, sizeof(cur_state->id_char));
	tkn = strtok(NULL, " \r\n");
	if (tkn == NULL) {
		strcpy(resp_buffer, "500 BLOCK NOT PROVIDED\r\n");
		return 0;
	}
	strncpy(cur_state->block, tkn, sizeof(cur_state->block));
	while (!done) {
		tkn = strtok(NULL, "= \r\n");
		if (tkn == NULL) {
			done = 1;
			continue;
		}
		strcpy(token, tkn);
		if (strcasecmp(token, "") == 0) {
			done = 1;
			continue;
		}
		strcpy(value, strtok(NULL, "\""));
		strcpy(value, cleanse_field(value));
		if (strcasecmp(value, "") == 0) {
			done = 1;
			continue;
		}
		if (strcasecmp(token, "STATUS") == 0)
			strncpy(cur_state->status, value, sizeof(cur_state->status));
		if (strcasecmp(token, "FORCE") == 0)
			strncpy(cur_state->force, value, sizeof(cur_state->force));
	}
	if (PQstatus(pgconn) == CONNECTION_BAD) {
		snprintf(query_string, sizeof(query_string),
			 "dbname=%s user=%s password=%s host=%s port=%d",
			 IA_NETDB_NAME, cur_state->userid,
			 cur_state->pw, IA_NETDB_HOST, IA_NETDB_PORT);
		pgconn = PQconnectdb(query_string);
		if (PQstatus(pgconn) == CONNECTION_BAD) {
			sprintf(resp_buffer, "500 Can't get DB connection '%s'\r\n",
				myPQerrorMessage(pgconn));
			cur_state->quit = 1;
			return 0;
		}
	}
	pgres = PQexec(pgconn, "BEGIN WORK");
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message("BEGIN WORK", myPQerrorMessage(pgconn));
		PQclear(pgres);
		return 0;
	}
	snprintf(query_string, sizeof(query_string),
		 "SELECT netblock,customer_reference,"
		 "get_customer_reference(customer_reference) "
		 "FROM   networks "
		 "WHERE  netblock='%s' FOR UPDATE ", cur_state->block);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_TUPLES_OK || PQntuples(pgres) != 1) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQclear(pgres);
		return 0;
	}
	if (strcmp(cur_state->id_char, PQgetvalue(pgres, 0, 1)) != 0) {
		sprintf(resp_buffer, "450 BLOCK ASSIGNED TO %s (%s) NOT UPDATED\r\n",
			PQgetvalue(pgres, 0, 1), PQgetvalue(pgres, 0, 2));
		pgres = PQexec(pgconn, "ROLLBACK WORK");
		if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
			sprintf(resp_buffer,
			  "590 DB ERROR: Report %s-%d-%d to networking\r\n",
			     IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
			prepare_error_message("ROLLBACK WORK", myPQerrorMessage(pgconn));
			PQclear(pgres);
			return 0;
		}
		return 0;
	}
	if (strlen(cur_state->status) == 0) {
		strcpy(cur_state->status, "pending_available");
	}
	snprintf(query_string, sizeof(query_string),
		 "UPDATE networks "
		 "SET status=get_status_code('%s'),last_update_at=now(),"
		 "last_update_by='%s' "
		 "WHERE netblock='%s'",
		 cur_state->status, cur_state->userid, cur_state->block);
	pgres = PQexec(pgconn, query_string);
	if (PQresultStatus(pgres) != PGRES_COMMAND_OK) {
		sprintf(resp_buffer,
			"590 DB ERROR: Report %s-%d-%d to networking\r\n",
			IA_NETDB_HOST, (int)getpid(), (int)time(NULL));
		prepare_error_message(query_string, myPQerrorMessage(pgconn));
		PQclear(pgres);
		return 0;

	}
	pgres = PQexec(pgconn, "COMMIT WORK");
	sprintf(resp_buffer, "200 RETURN OK %s\r\n", cur_state->block);
	return 0;
}

int
process_buffer(char *buffer, char *resp_buffer, CURRENT_STATE * cur_state)
{
	char            token[8192];
	char            work_buffer[16384];
	char           *tkn;

	strcpy(work_buffer, buffer);
	strcpy(token, strtok(work_buffer, " \r\n"));
	if (strcasecmp(token, "QUIT") == 0) {
		strcpy(resp_buffer, "200 QUIT OK\r\n");
		cur_state->quit = 1;
		return 0;
	}
	if (cur_state->hello != 1) {
		if (strcasecmp(token, "HELO") != 0) {
			strcpy(resp_buffer, "500 HELO REQUIRED\r\n");
			return 0;
		}
		tkn = strtok(NULL, " ");
		if (tkn == NULL) {
			strcpy(resp_buffer, "500 USERID not provided\r\n");
			return 0;
		}
		strcpy(cur_state->userid, tkn);
		tkn = strtok(NULL, " \r\n");
		if (tkn == NULL) {
			strcpy(resp_buffer, "500 Password not provided\r\n");
			return 0;
		}
		strcpy(cur_state->pw, tkn);
		cur_state->hello = 1;
		return process_helo(cur_state, resp_buffer);
	}
	if (strcasecmp(token, "CUSTID") == 0)
		return process_custid(cur_state, work_buffer, resp_buffer);
	if (strcasecmp(token, "CUSTINFO") == 0)
		return process_custinfo(cur_state, work_buffer, resp_buffer);
	if (strcasecmp(token, "PROVASSIGN") == 0)
		return process_provassign(cur_state, work_buffer, resp_buffer);
	if (strcasecmp(token, "ASSIGN") == 0)
		return process_assign(cur_state, work_buffer, resp_buffer);
	if (strcasecmp(token, "RETURN") == 0)
		return process_return(cur_state, work_buffer, resp_buffer);
	if (strcasecmp(token, "EXAMINE") == 0)
		return process_examine(cur_state, work_buffer, resp_buffer);
	if (strcasecmp(token, "MOVEBLOCK") == 0)
		return process_moveblock(cur_state, work_buffer, resp_buffer);
	if (strcasecmp(token, "QUIT") == 0) {
		strcpy(resp_buffer, "200 QUIT OK\r\n");
		cur_state->quit = 1;
		return 0;
	}
	sprintf(resp_buffer, "500 WHAT? %s\r\n", token);
	return 0;
}

int
main(int argc, char **argv)
{
	char            buffer[16384];
	char            resp_buffer[16384];
	CURRENT_STATE   cur_state;

	memset(&cur_state, '\0', sizeof(cur_state));
	memset(buffer, '\0', sizeof(buffer));

	snprintf(buffer, sizeof(buffer),
		 "250-Welcome to Netmaster ($Id: netmaster.c,v 1.43 2001/10/10 21:30:06 ler Exp $).\r\n250 READY\r\n");
	fprintf(stdout, buffer);
	fflush(stdout);
	memset(buffer, '\0', sizeof(buffer));
	while ((!feof(stdin)) && (cur_state.quit != 1)) {
		memset(buffer, '\0', sizeof(buffer));
		if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
			if (strlen(buffer) < 5) {
				fprintf(stdout, "500 WHAT?\r\n");
				fflush(stdout);
				continue;
			}
			if (process_buffer(buffer, resp_buffer, &cur_state) == 0) {
				fprintf(stdout, resp_buffer);
				fflush(stdout);

			} else {
				fprintf(stdout, resp_buffer);
				fflush(stdout);
			}
		}
		reset_state(&cur_state);
	}
	return 0;
}
Comment 1 Larry Rosenman freebsd_committer 2002-05-07 16:37:23 UTC
Backtrace:
0x8079592 in file_pos_changed ()
(gdb) bt
#0  0x8079592 in file_pos_changed ()
#1  0x283b0123 in gtk_marshal_NONE () from /usr/X11R6/lib/libgtk12.so.2
#2  0x283e0a2e in gtk_handlers_run () from /usr/X11R6/lib/libgtk12.so.2
#3  0x283dfe9d in gtk_signal_real_emit () from
/usr/X11R6/lib/libgtk12.so.2
#4  0x283de262 in gtk_signal_emit_by_name () from
/usr/X11R6/lib/libgtk12.so.2
#5  0x809e064 in text_get_text_no_replace ()
#6  0x809ce7e in gap_to ()
#7  0x80a7640 in gtk_extext_set_position ()
#8  0x809d0df in gap_to ()
#9  0x80a71de in gtk_extext_insert_text ()
#10 0x806db67 in open_file_full ()
#11 0x806bb77 in open_file_real ()
#12 0x8077f4c in main_finish ()
#13 0x8073254 in initialize_macro_language ()
#14 0x8077bd5 in main ()
#15 0x8064975 in _start ()
(gdb) quit
The program is running.  Exit anyway? (y or n) y
$ 

-- 
Larry Rosenman                     http://www.lerctr.org/~ler
Phone: +1 972-414-9812                 E-Mail: ler@lerctr.org
US Mail: 1905 Steamboat Springs Drive, Garland, TX 75044-6749
Comment 2 Joe Marcus Clarke freebsd_committer 2002-05-07 19:58:31 UTC
State Changed
From-To: open->closed

The fix has been committed to glimmer-1.2.1_1.