/* * config.c * * Reads and stores the appropriate information from * the config file specifying the configuration of * (1) this machine * (2) the available domain name servers * (3) the available gateways */ #define CONFIG_DEF 1 /* * Includes */ #include #include #include #include "vtcpip.h" #include "dfault.h" #include "evtdef.h" #include "hstdef.h" #include "prodef.h" #include "prodat.h" #include "tcpdat.h" #include "bytprc.h" #include "mapskt.h" #include "server.h" #define NUMSPECS 114 /* last CON option for a machine specific option */ /* * States for config file reading state machine. * One for each type of keyword and some for controlling. */ #define CONNAME 101 #define CONHOST 102 #define CONIP 103 #define CONPORT 104 #define CONNS 105 #define CONGATE 106 #define CONRETR 107 #define CONTO 108 #define CONWIND 109 #define CONSEG 110 #define CONMTU 111 #define CONDELETE 112 #define CONCRMAP 113 #define CONDUP 114 /* * above this line are per machine entries */ #define CONFROM 115 /* * below this line are configuration entries */ #define CONMASK 116 #define CONMYIP 117 #define CONME 118 #define CONDEF 119 #define CONDOMTO 120 #define CONNDOM 121 #define CONARPTO 122 #define CONDTO 123 #define CONNWIND 124 #define CONNSEG 125 #define CONNMTU 126 #define CONSRVC 127 #define CONLOGSESSION 128 char *Smachfile = {"sy:tcpip.cfg"}; /* * Local Variables */ struct machinfo *Smachlist,*Smptr; int Spnum; static char Sflags[NUMSPECS-95], /* which parms we have or have not */ *Sspace; static int mno = 0, /* how many machines in host file */ lineno, /* line number in hosts file */ position, /* position for scanning string */ constate, /* state for config file parser */ inquote; /* flag, inside quotes now */ static char *Skeyw[] = { /*==0==*/ "", "name", /* name of session */ "host", /* name of host */ "hostip", /* IP number */ "port", /* TCP port to go for */ /*==5==*/ "nameserver", /* name server level */ "gateway", /* gateway level */ "retrans", /* initial retrans time */ "contime", /* timeout for opening connection */ "mwin", /* window to allow for this host */ /*==10==*/ "mseg", /* maximum transfer size(in) */ "mtu", /* transfer unit (out) */ "delete", /* character for character deletion */ "crmap", /* map for Berkeley 4.3 */ "duplex", /* half duplex for IBM machines */ /* * above are part of the data structure */ /*==15==*/ "copyfrom", /* copy from another machine */ /* * following are one-time entries */ "netmask", /* subnetting mask */ "myip", /* local machine's IP # */ "myname", /* identifying info */ "domain", /* default domain for lookup */ /*==20==*/ "nndomto", /* time-out for DOMAIN */ "nnretry", /* # of retries */ "nnarpto", /* time-out for ARPs */ "nndto", /* time-out for data layer */ "nnwin", /* default maximum window */ /*==25==*/ "nnseg", /* default maximum transfer size */ "nnmtu", /* default maximum transfer unit */ "service", /* enable service */ "logsession", /* log TCPIP activity */ "" }; /* * Sgetspace * * get some working space */ char *Sgetspace(siz) int siz; { char *s; s = (char *) malloc(siz); if(s == NULL) { Serrline(901); } return(s); } /* * Sreadhosts * * read in the hosts file into our in-memory data structure. * Handle everything by keyword, see docs for specifications about file. */ int Sreadhosts() { FILE *fp; int c,retval; Smachlist = Smptr = NULL; Spnum = 0; mno = 0; /* * state vars */ position = constate = inquote = lineno = 0; /* * open the configuration file */ if(NULL==(fp = fopen(Smachfile,"r"))) { Serrline(900); return(1); } /* * get room for gathering stuff */ Sspace = Sgetspace(256); if(Sspace==NULL) { return(1); } retval = 0; while(!retval) { c = getc(fp); if(c=='#' && !inquote) /* * skip to EOL */ while(c!=EOF && c!='\n' && c!='\r') c = getc(fp); if(c=='\n' || c=='\r') lineno++; /* * add character to token */ retval = Scontoken(c); } fclose(fp); free(Sspace); /* * make sure name is in list */ Smadd(-1,"default"); /* * EOF is normal end */ if(retval==EOF) return(0); else return(retval); } /* * ncstrcmp * * No case string compare. * Only returns 0=match, 1=no match, does not compare greater or less * There is a tiny bit of overlap with the | 32 trick, but shouldn't be * a problem. It causes some different symbols to match. */ int ncstrcmp(sa,sb) register char *sa,*sb; { /* * don't compare leading spaces */ while(*sa && *sa<33) sa++; while(*sb && *sb<33) sb++; while(*sa && *sb) { if((*sa!=*sb) && ((*sa | 32)!=(*sb | 32))) return(1); sa++; sb++; } /* * if both at end of string */ if(!*sa && !*sb) return(0); else return(1); } /* * Serrline * * prints the line number of the host file error and posts the event * for the line number error and posts the hosts file error. */ VOID Serrline(n) int n; { char *p; p = nterrstring(-1); sprintf(p,"Config file: error at line %4d",lineno+1); ntposterr(-1); ntposterr(n); } /* * Scontoken * * tokenize the strings which get passed to Sconfile. * Handles quotes and uses separators: <33, ;:= */ int Scontoken(c) int c; { int retval; if(c==EOF) { Sspace[position++] = '\0'; Sconfile(Sspace); /* * make sure last entry gets copied */ if(!Sflags[0]) { if(ncstrcmp("default",Smptr->sname)) Scopyfrom("default"); else Scopyfrom("=="); } return(-1); } /* * skip over junk before token */ if(!position && Sissep(c)) return(0); if(inquote || !Sissep(c)) { if(position>200) { Serrline(903); return(1); } /* * check for quotes, * a little mixed up here, could be reorganized */ if(c=='"' ) { /* * beginning of quotes */ if(!inquote) { inquote = 1; return(0); } else { /* * turn off flag and drop through */ inquote = 0; } } else { /* * check for EOL inside quotes */ if(c=='\n') { Serrline(904); return(1); } /* * include in current string */ Sspace[position++] = (char)c; return(0); } } Sspace[position++] = '\0'; /* * pass the token along */ retval = Sconfile(Sspace); position = 0; inquote = 0; Sspace[0] = '\0'; return(retval); } /* * Sconfile * * take the characters read from the file and parse them for keywords * which require configuration action. */ int Sconfile(s) register char *s; { int i,a,b,c,d; struct service *sp,*nsp; switch(constate) { case 0: /* lookup keyword */ if(!(*s)) /* * empty token */ return(0); /* * search the list for this keyword */ for(i=1; *Skeyw[i] && ncstrcmp(Skeyw[i],s); i++); if(!(*Skeyw[i])) { /* * not in list */ Serrline(902); return(0); } /* * change to state for keyword */ constate = 100+i; /* * check if this is a machine specific parm * without a machine to give it to. * "name" being the only machine specific * parm allowed, of course */ if(Smptr==NULL && constate>CONNAME && constate<=NUMSPECS) { Serrline(905); return(1); } break; case CONNAME: /* session name */ /* * allocate space for upcoming parameters */ if(Smachlist==NULL) { Smachlist = (struct machinfo *) Sgetspace(sizeof(struct machinfo)); if(Smachlist == NULL) return(2); Smptr = Smachlist; } else { if(!Sflags[0]) { /* * to make sure 'default' gets set */ if(ncstrcmp("default",Smptr->sname)) Scopyfrom("default"); else Scopyfrom("=="); } Smptr->next = (struct machinfo *) Sgetspace(sizeof(struct machinfo)); if(Smptr->next == NULL) return(2); Smptr = Smptr->next; } Smptr->next = NULL; /* * guarantee to be null */ Smptr->hname = NULL; /* * size of name string */ Smptr->sname = Sgetspace(position); if(Smptr->sname == NULL) return(2); /* * keep name field */ strcpy(Smptr->sname,s); /* * back to new keyword */ constate = 0; /* * we have no parms */ for(i=0; imno = ++mno; break; case CONHOST: /* also a host name */ Smptr->hname = Sgetspace(position); if(Smptr->hname == NULL) return(2); strcpy(Smptr->hname,s); constate = 0; /* * set the flag to indicate hostname is found */ Sflags[CONHOST-100] = 1; break; case CONIP: /* IP number for host */ if(4!=sscanf(s,"%d.%d.%d.%d",&a,&b,&c,&d)) { Serrline(906); return(3); } /* * keep number */ Smptr->hostip[0] = (char)a; Smptr->hostip[1] = (char)b; Smptr->hostip[2] = (char)c; Smptr->hostip[3] = (char)d; Smptr->mstat = HFILE; constate = 0; /* * set the flag to indicate ip number found */ Sflags[CONIP-100] = 1; break; case CONPORT: /* the port number */ i = atoi(s); if(i<1) i = 0; Smptr->port = i; Sflags[CONPORT-100] = 1; constate = 0; break; case CONNS: /* nameserver level */ Smptr->nameserv = (char)atoi(s); /* * keep NS */ if(!Sns || (Sns->nameserv>Smptr->nameserv)) Sns = Smptr; constate = 0; Sflags[CONNS-100] = 1; break; case CONGATE: /* this machine is a gateway */ /* * gateway level */ Smptr->gateway = (char)atoi(s); constate = 0; /* * set the flag for this name being a gateway */ Sflags[CONGATE-100] = 1; break; case CONRETR: /* how long before retransmitting */ Smptr->retrans = atoi(s) * TICKSPERSEC; constate = 0; Sflags[CONRETR-100] = 1; break; case CONTO: /* time until time out */ i = atoi(s); if(i>2) { Smptr->conto = i; Sflags[CONTO-100] = 1; } constate = 0; break; case CONWIND: /* transmission window for this host */ Smptr->window = atoi(s); constate = 0; Sflags[CONWIND-100] = 1; break; case CONSEG: /* segment size */ Smptr->maxseg = atoi(s); constate = 0; Sflags[CONSEG-100] = 1; break; case CONMTU: /* maximum transmission unit */ Smptr->mtu = atoi(s); constate = 0; Sflags[CONMTU-100] = 1; break; case CONDELETE: /* character deletion parameter */ if(!ncstrcmp(s,"backspace")) Smptr->delete = 8; else Smptr->delete = 127; constate = 0; Sflags[CONDELETE-100] = 1; break; case CONCRMAP: /* carriage return mapping */ if(!ncstrcmp(s,"4.3BSDCRNUL")) Smptr->crmap = 0; else Smptr->crmap = 10; Sflags[CONCRMAP-100] = 1; constate = 0; break; case CONDUP: /* duplex */ if(!ncstrcmp(s,"half")) { Smptr->halfdup = 1; Sflags[CONDUP-100] = 1; } constate = 0; break; case CONFROM: /* copy the rest from another entry */ Scopyfrom(s); Sflags[0] = 1; constate = 0; break; /* * now the one-time entries * Generally this information goes * into the "Scon" structure for later * retrieval by other routines. */ case CONME: /* what my name is */ strncpy(Scon.me,s,sizeof(Scon.me)); Scon.me[sizeof(Scon.me)-1] = '\0'; constate = 0; break; case CONMYIP: /* what my ip number is */ printf("MyIpString=[%s]\n",s); constate = 0; if(!ncstrcmp(s,"rarp")) { movebytes(Scon.myipnum,s,4); break; } if(!ncstrcmp(s,"bootp")) { movebytes(Scon.myipnum,s,4); break; } if(4!=sscanf(s,"%d.%d.%d.%d",&a,&b,&c,&d)) { Serrline(908); return(3); } /* * put number back in s */ Scon.myipnum[0] = (char)a; Scon.myipnum[1] = (char)b; Scon.myipnum[2] = (char)c; Scon.myipnum[3] = (char)d; break; case CONMASK: /* the subnet mask */ if(4!=sscanf(s,"%d.%d.%d.%d",&a,&b,&c,&d)) { Serrline(907); return(3); } Scon.netmask[0] = (char)a; Scon.netmask[1] = (char)b; Scon.netmask[2] = (char)c; Scon.netmask[3] = (char)d; Scon.havemask = 1; constate = 0; break; case CONDEF: /* default domain */ /* * space for name */ Scon.defdom = Sgetspace(position); if(Scon.defdom == NULL) return(2); /* * copy it in */ strcpy(Scon.defdom,s); constate = 0; break; case CONDOMTO: /* DOMAIN timeout value */ i = atoi(s); if(i>1) nndomto = i; constate = 0; break; case CONNDOM: /* DOMAIN number of retries */ i = atoi(s); if(i>1) nnretry = i; constate = 0; break; case CONARPTO: /* need to lengthen arp time-out (secs) */ i = atoi(s); if(i>0) nnarpto = i; constate = 0; break; case CONDTO: /* Data layer timeout */ i = atoi(s); if(i>0) nndto = i; constate = 0; break; case CONNWIND: /* default maximum window */ nnwin = atoi(s); if (nnwin>WINDOWSIZE) { nnwin = WINDOWSIZE; } else if (nnwinMAXSEG) { nnseg = MAXSEG; } else if (nnsegTMAXSIZE) { nnmtu = TMAXSIZE; } else if (nnmtunext) nsp = nsp->next; nsp->next = sp; } /* * load parameters */ sp->next = NULL; sp->port = 0; sp->maxses = 0; sp->cmdfil[0] = '\0'; if(3!=sscanf(s,"%d,%d,%15s", &(sp->port), &(sp->maxses), &(sp->cmdfil[0]))) { Serrline(909); return(3); } constate = 0; break; case CONLOGSESSION: /* log sessions */ tcplog(s); constate = 0; break; default: constate = 0; break; } return(0); } /* * Scopyfrom * * Look at the Sflags array to determine which elements to copy from * a previous machine's entries. If a machine name has been given as * "default", the state machine will fill in the fields from that * machine's entries. * * If the machine name to copyfrom is not present in the list, set the * program default values for each field. */ VOID Scopyfrom(s) register char *s; { register struct machinfo *m; int i; /* * search list through list of parms */ m = Shostlook(-1,s); for(i=3; i<=NUMSPECS-100; i++) { if(!Sflags[i]) { if(m) { /* * copy old value */ switch(100+i) { case CONHOST: Smptr->hname = m->hname; break; case CONIP: movebytes(Smptr->hostip,m->hostip,4); Smptr->mstat = m->mstat; break; case CONGATE: /* * gateways cannot be copied from */ Smptr->gateway = 0; break; case CONNS: /* * can't copy nameservers either */ Smptr->nameserv = 0; break; case CONRETR: Smptr->retrans = m->retrans; break; case CONWIND: Smptr->window = m->window; break; case CONSEG: Smptr->maxseg = m->maxseg; break; case CONMTU: Smptr->mtu = m->mtu; break; case CONDELETE: Smptr->delete = m->delete; break; case CONCRMAP: Smptr->crmap = m->crmap; break; case CONDUP: Smptr->halfdup = m->halfdup; break; case CONTO: Smptr->conto = m->conto; break; case CONPORT: Smptr->port = m->port; break; default: break; } } else { /* * m=NULL, install default values */ switch(100+i) { case CONHOST: Smptr->hname = NULL; break; case CONIP: Smptr->mstat = NOIP; break; case CONGATE: /* * gateways cannot be copied from */ Smptr->gateway = 0; break; case CONNS: /* * can't copy nameservers either */ Smptr->nameserv = 0; break; case CONRETR: Smptr->retrans = MINRTO; break; case CONWIND: Smptr->window = DEFWINDOW; break; case CONSEG: Smptr->maxseg = DEFSEG; break; case CONMTU: Smptr->mtu = TSENDSIZE; break; case CONTO: Smptr->conto = CONNWAITTIME; break; case CONDELETE: Smptr->delete = 127; break; case CONCRMAP: Smptr->crmap = 10; break; case CONDUP: Smptr->halfdup = 0; break; case CONPORT: /* * the default port */ Smptr->port = 0; break; default: break; } } } } /* * set that this machine was copied */ Sflags[0] = 1; } /* * Shostfile * * if the user wants to change the host file name from 'config.dat' to * something else. */ VOID Shostfile(ptr) char *ptr; { /* * note that the area with the file name must stay allocated for * later reference, typically it is in some argv[] parm. */ Smachfile = ptr; } /* * Sissep * * is the character a valid separator for the hosts file? * separators are white space, special chars and = */ int Sissep(c) register int c; { if(c<33 || c=='=') return(1); return(0); } /* * Smadd * * if(sknum<0) * If machine is there just returns pointer, else * Add a machine to the list. Increments machine number of machine. * Puts in parameters copied from the "default" entry. * * If(sknum>=0) * If machine is there copy to socket(sknum), * else put in parameters copied from the "default" entry. */ struct machinfo *Smadd(sknum,mname) int sknum; register char *mname; { int i; register struct machinfo *m; register struct socket *skt; if(sknum>=0) skt = (struct socket *) mapskt(sknum); /* * First, do we have the name already? */ m = Shostlook(sknum,mname); if(m) if(sknum<0) { return(m); } else { skt->mpp = &skt->mach; movebytes(skt->mpp,m,sizeof(struct machinfo)); skt->mach.port = skt->sktport; return(skt->mpp); } /* * Don't have name, add another record */ if(sknum<0) { Smptr = (struct machinfo *) malloc(sizeof(struct machinfo)); if(Smptr==NULL) return(NULL); } else { Smptr = skt->mpp = &skt->mach; } /* * we have no parms */ for(i=0; isname = NULL; if(sknum<0) { /* * internal machine list */ Smptr->hname = malloc(strlen(mname)+1); Smptr->mno = ++mno; Smptr->next = Smachlist; Smachlist = Smptr; } else { /* * socket machine data */ Smptr->hname = &skt->hname; Smptr->mno = sknum; Smptr->next = NULL; skt->mach.port = skt->sktport; } /* * copy in name of machine */ if(Smptr->hname) strcpy(Smptr->hname,mname); /* * No IP yet */ Smptr->mstat = NOIP; return(Smptr); } /* * Sgethost * * get host by name * Given the name of a host machine, search our database to see if we * have that host ip number. Search first the name field, and then the * hostname field. If the IP # is given, returns a ptr to the * default machine record with that IP # installed. * Returns the pointer to a valid record, or NULL if the IP # cannot * be deciphered. */ struct machinfo *Sgethost(sknum,machine) int sknum; register char *machine; { int i,j,k,l; char ipto[4],myipnum[4],xmask[4]; long hnum; register struct socket *skt; struct machinfo *mhost; mhost = NULL; /* * First, check for the '.' character which means we should * use the current netmask to build an IP number for the local * network. Take the host number, install it in the ipto[] array. * Then mask in my IP number's network portion to build the final * IP address. */ if(machine[0]=='.') { /* * on my local network */ ntgtip(myipnum); /* * mask of network portion of IP # */ ntgtmask(xmask); /* * host number for local network */ sscanf(&machine[1],"%ld",&hnum); for(i=3; i>=0; i--) { if(xmask[i]) { ipto[i] = myipnum[i]; } else { ipto[i] = hnum & 0xFFL; hnum >>= 8; } } } else /* * next, is it an IP number? We take it if the number is in four * parts, separated by periods. */ if(4==sscanf(machine,"%d.%d.%d.%d",&i,&j,&k,&l)) { /* * given ip num */ ipto[0] = (char)i; ipto[1] = (char)j; ipto[2] = (char)k; ipto[3] = (char)l; } else { /* * lastly, it must be a name, first check the local host table * A first number of 127 means that it doesn't have an IP number, but * is in the table(strange occurrence) */ /* * look it up */ mhost = Shostlook(sknum,machine); if(mhost==NULL) { ntposterr(805); return(NULL); } if(mhost->mstatmpp = &skt->mach; if(mhost) { movebytes(&skt->mach,mhost,sizeof(struct machinfo)); } else { mhost = Shostlook(-1,"default"); /* * set up internal parameters after loading defaults */ movebytes(&skt->mach,mhost,sizeof(struct machinfo)); movebytes(&skt->mach.hostip,ipto,4); skt->mach.mstat = HAVEIP; } /* * load names */ skt->mach.sname = skt->sname; if(skt->sname[0]=='\0') strncpy(skt->sname,mhost->sname,sizeof(skt->sname)-1); skt->mach.hname = skt->hname; if(skt->hname[0]=='\0') strncpy(skt->hname,mhost->hname,sizeof(skt->hname)-1); /* * port number */ skt->mach.port = skt->sktport; return(&skt->mach); } /* * Shostlook * * The straightforward list searcher. Looks for either the * session name matching or the host name matching. NULL if neither. */ struct machinfo *Shostlook(sknum,hname) int sknum; register char *hname; { register struct machinfo *m; register struct socket *skt; /* * Check socket machine record */ if(sknum>=0) { skt = (struct socket *) mapskt(sknum); m = skt->mpp; if(m) { if(m->sname && !ncstrcmp(hname,m->sname)) return(m); if(m->hname && !ncstrcmp(hname,m->hname)) return(m); } } /* * Check Internal machine list */ m = Smachlist; while(m!=NULL) { if(m->sname && !ncstrcmp(hname,m->sname)) return(m); if(m->hname && !ncstrcmp(hname,m->hname)) return(m); m = m->next; } return(NULL); } /* * Snewns * * Rotate to the next nameserver * Chooses the next highest number from the nameserv field */ int Snewns() { register struct machinfo *m,*low; int i; /* * safety, should never happen */ if(!Sns) Sns = Smachlist; low = Sns; /* * what is value now? */ i = Sns->nameserv; m = Smachlist; while(m) { if(m->nameserv==(char)i+1) { Sns = m; return(0); } if((m->nameserv>0) && (m->nameservnameserv)) low = m; m = m->next; } if(Sns==low) /* * no alternate */ return(1); else Sns = low; return(0); } /* * Ssetgates * * set up the gateway machines and the subnet mask */ VOID Ssetgates() { register struct machinfo *m; int level,again; /* * leave default unless specified */ if(Scon.havemask) { ntstmask(Scon.netmask); } /* * Search the list of machines for gateway flags. * Invoke ntstgate in increasing order of gateway level #s. * Terminates when it gets through list without * finding next higher number. */ level = 0; do { level++; again = 0; m = Smachlist; while(m!=NULL) { if(m->gateway == (char)level && m->mstat>=HAVEIP) { ntstgate(m->hostip); } if(m->gateway==(char)level+1) again = 1; m = m->next; } } while(again); }