xref: /illumos-gate/usr/src/cmd/listen/lsdbf.c (revision 1a3a3bd4)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 
32 /*
33  * data base routines for the network listener process
34  */
35 
36 /* system include files	*/
37 
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/tiuser.h>
45 #include <sys/stropts.h>
46 
47 /* listener include files */
48 
49 #include "lsparam.h"		/* listener parameters		*/
50 #include "listen.h"		/* listener includes 		*/
51 #include "lsfiles.h"		/* listener files info		*/
52 #include "lserror.h"		/* listener error codes		*/
53 #include "lsdbf.h"		/* data base file stuff		*/
54 /* #include "nsaddr.h"		nls includes			*/
55 
56 #define SUPPRESS	1	/* suppress messages during scan*/
57 #define NOSUPPRESS	0	/* don't suppress messages 	*/
58 
59 /* static data		*/
60 
61 static char *dbfopenmsg = "Trouble opening data base file";
62 static char *dbfrderror = "Error reading data base file: line %d";
63 static char *dbfbadlmsg = "Data base file: Error on line %d";
64 static char *dbfdupcmsg = "Data base file: Duplicate service code: <%s>";
65 static char *dbfunknown = "Unknown error reading data base file: line %d";
66 static char *dbfsvccmsg = "Data base file: Illegal service code: <%s>";
67 static char *dbfcorrupt = "Data base file has been corrupted";
68 
69 static int   Dbflineno;		/* current line number in dbf		*/
70 static unsigned Dbfentries;	/* number of non-comment lines		*/
71 extern char  *Server_cmd_lines; /* contains svc_code, cmd_line, mod_list */
72 extern char  *New_cmd_lines; /* svc_code, cmd_line, mod_list (on reread)*/
73 
74 /* public variables */
75 
76 
77 /*
78  * read_dbf:
79  *
80  * read the data base file into internal structures
81  *
82  * all data base routines under read_dbf log there own errors and return -1
83  * in case of an error.
84  *
85  * if 're_read' is non-zero, this stuff is being called to read a new
86  * data base file after the listener's initialization.
87  */
88 
89 int
read_dbf(re_read)90 read_dbf(re_read)
91 int	re_read;	/* zero means first time	*/
92 {
93 	register unsigned size;
94 	int exit_flag = EXIT | NOCORE;
95 	register dbf_t *dbf_p;
96 	register char  *cmd_p;
97 	unsigned scan_dbf();
98 	extern dbf_t *Dbfhead;		/* Dbfentries (when allocated)	*/
99 	extern dbf_t *Newdbf;		/* Dbfentries (on re-read)	*/
100 	extern char *calloc();
101 
102 	DEBUG((9,"in read_dbf"));
103 
104 	if (check_version())
105 		error(E_BADVER, EXIT | NOCORE);
106 
107 	if (re_read)	{			/* not first time */
108 		exit_flag = CONTINUE;
109 	}
110 
111 	/*
112 	 * note: data base routines log their own error messages
113 	 */
114 
115 	Dbfentries = 0;
116 	DEBUG((9,"read_dbf: open file here:  %s", DBFNAME));
117 	if ( (size = scan_dbf(DBFNAME)) == (unsigned)(-1) )
118 		error( E_SCAN_DBF, exit_flag | NO_MSG );
119 
120 	DEBUG((5,"read_dbf: scan complete: non-commented lines: %u, size: %u",
121 		Dbfentries, size));
122 
123 	if (!size)  {
124 		logmessage("No database?  0 entries?");
125 		return(0);
126 	}
127 
128 	/*
129 	 * allocate enough space for Dbfentries of 'size' bytes (total)
130 	 * The +1 is to insure a NULL last entry!
131 	 */
132 
133 	if (!(dbf_p = (dbf_t *)calloc(Dbfentries+1,sizeof(dbf_t)))
134 	   || !(cmd_p = calloc(size, 1)))  {
135 		DEBUG((1,"cannot calloc %u + %u bytes", size,
136 			(Dbfentries+1)*(unsigned)sizeof(dbf_t)));
137 		error( E_DBF_ALLOC, exit_flag);	/* if init, exit */
138 
139 		/* if still here, this is a re-read	*/
140 
141 		if (dbf_p)
142 			free(dbf_p);
143 		if (cmd_p)
144 			free(cmd_p);
145 		return(-1);
146 	}
147 
148 	if (get_dbf(dbf_p, cmd_p))  {
149 		DEBUG((9, "get_dbf FAILED"));
150 		error(E_DBF_IO, exit_flag | NO_MSG);
151 
152 		/* if still here, this is a re_read */
153 		free(dbf_p);
154 		free(cmd_p);
155 		return(-1);
156 	}
157 
158 	if (re_read)  {
159 		Newdbf = dbf_p;
160 		New_cmd_lines = cmd_p;
161 #ifdef	DEBUGMODE
162 		DEBUG((7,"read_dbf: NEW data base dump..."));
163 		if (Newdbf)
164 			for (dbf_p = Newdbf; dbf_p->dbf_svc_code; ++dbf_p)
165 				DEBUG((7, "svc code <%s>; id: %s; private address: %s; modules: %s; cmd line: %s; sflags: %x, prognum: %d version: %d",
166 				dbf_p->dbf_svc_code, dbf_p->dbf_id, dbf_p->dbf_prv_adr, dbf_p->dbf_modules, dbf_p->dbf_cmd_line, dbf_p->dbf_sflags, dbf_p->dbf_prognum, dbf_p->dbf_version));
167 #endif	/* DEBUGMODE */
168 	}
169 	else {
170 		Dbfhead = dbf_p;
171 		Server_cmd_lines = cmd_p;
172 #ifdef	DEBUGMODE
173 		DEBUG((7,"read_dbf: data base dump..."));
174 		if (Dbfhead)
175 			for (dbf_p = Dbfhead; dbf_p->dbf_svc_code; ++dbf_p)
176 				DEBUG((7, "svc code <%s>; id: %s; r1: %s; r2: %s; r3: %s; private address: %s; modules: %s; cmd line: %s; sflags: %x, prognum: %d version: %d",
177 				dbf_p->dbf_svc_code, dbf_p->dbf_id, dbf_p->dbf_res1, dbf_p->dbf_res2, dbf_p->dbf_res3, dbf_p->dbf_prv_adr, dbf_p->dbf_modules, dbf_p->dbf_cmd_line, dbf_p->dbf_sflags, dbf_p->dbf_prognum, dbf_p->dbf_version));
178 #endif	/* DEBUGMODE */
179 	}
180 
181 	return(0);
182 }
183 
184 
185 /*
186  * get_dbf: read the file and fill the structures
187  *	    checking for duplicate entries as we go
188  */
189 
190 int
get_dbf(dbf_p,cmd_p)191 get_dbf(dbf_p, cmd_p)
192 register dbf_t *dbf_p;
193 register char *cmd_p;
194 {
195 	dbf_t *dbfhead = dbf_p;
196 	register int n, i;
197 	char buf[DBFLINESZ];
198 	register char *p = buf;
199 	char scratch[128];
200 	FILE *dbfilep;
201 	char *cmd_line_p;
202 	int flags;
203 	char *svc_code_p;
204 	char *id_p;
205 	char *res1_p;
206 	char *res2_p;
207 	char *res3_p;
208 	char *private_p;
209 	int sflags;
210 	int prognum;
211 	int vernum;
212 	char *module_p;
213 	register dbf_t *tdbf_p;
214 	extern int atoi();
215 	extern int Dbf_entries;
216 	extern int NLPS_proc;
217 	extern int errno;
218 
219 	Dbflineno = 0;
220 	Dbf_entries = 0;  /* number of private addresses in dbf file */
221 
222 	DEBUG((9,"in get_dbf: "));
223 	if (!(dbfilep = fopen(DBFNAME,"r")))  {
224 		logmessage(dbfopenmsg);
225 		error(E_DBF_IO, EXIT | NOCORE | NO_MSG);
226 	}
227 
228 	while (n = rd_dbf_line(dbfilep,p,&svc_code_p,&flags,&id_p,&res1_p,&res2_p,&res3_p,&private_p,&prognum,&vernum,&module_p,&sflags,&cmd_line_p,NOSUPPRESS))  {
229 
230 		if (n == -1)  {			/* read error	*/
231 			fclose(dbfilep);
232 			return(-1);
233 		}
234 
235 		/* make sure service code is legal 			*/
236 
237 		i = strlen(svc_code_p);
238 		if ( (i == 0) || (i >= SVC_CODE_SZ) )
239 			goto reject;
240 
241 		/* check for duplicate service code			*/
242 		tdbf_p = dbfhead;
243 		while (tdbf_p->dbf_svc_code)  {	/* duplicate svc code?	*/
244 			if (!strcmp(svc_code_p, tdbf_p->dbf_svc_code))  {
245 				sprintf(scratch, dbfdupcmsg, svc_code_p);
246 				logmessage(scratch);
247 				return(-1);
248 			}
249 			++tdbf_p;
250 		}
251 
252 		/* NLPS_proc is set by the nlps_server, which also uses these
253 		 * routines.  The actual listener child shouldn't ever need
254 		 * to read a database, so it will never be here
255 		 */
256 		if (!NLPS_proc && (strlen(private_p) == 0) && !(sflags & DFLAG))
257 			continue;	/* ignore entries with no address */
258 
259 		/*
260 		 * child doesn't care about private addresses
261 		 */
262 
263 		if (!NLPS_proc) {
264 			i = strlen(private_p);
265 			if (i >= PRV_ADR_SZ) {
266 				goto p_reject;
267 			}
268 			Dbf_entries++;
269 		}
270 
271 		/*
272 		 * legal, non-duplicate entry: copy it into internal data base
273 		 */
274 
275 		dbf_p->dbf_fd = -1;	/* set to actual fd in add_prvaddr */
276 		dbf_p->dbf_flags = flags;
277 		dbf_p->dbf_sflags = sflags;
278 		dbf_p->dbf_prognum = prognum;
279 		dbf_p->dbf_version = vernum;
280 		strcpy(cmd_p, svc_code_p);
281 		dbf_p->dbf_svc_code = cmd_p;
282 		cmd_p += strlen(svc_code_p) + 1;	/* +1 for null */
283 		strcpy(cmd_p, cmd_line_p);
284 		dbf_p->dbf_cmd_line = cmd_p;
285 		cmd_p += strlen(cmd_line_p) + 1;
286 		strcpy(cmd_p, id_p);
287 		dbf_p->dbf_id = cmd_p;
288 		cmd_p += strlen(id_p) + 1;
289 		strcpy(cmd_p, res1_p);
290 		dbf_p->dbf_res1 = cmd_p;
291 		cmd_p += strlen(res1_p) + 1;
292 		strcpy(cmd_p, res2_p);
293 		dbf_p->dbf_res2 = cmd_p;
294 		cmd_p += strlen(res2_p) + 1;
295 		strcpy(cmd_p, res3_p);
296 		dbf_p->dbf_res3 = cmd_p;
297 		cmd_p += strlen(res3_p) + 1;
298 		if (strlen(private_p) != 0) {
299 			strcpy(cmd_p, private_p);
300 			dbf_p->dbf_prv_adr = cmd_p;
301 			cmd_p += strlen(private_p) + 1;
302 		}
303 		else
304 			dbf_p->dbf_prv_adr = NULL;
305 		strcpy(cmd_p, module_p);
306 		dbf_p->dbf_modules = cmd_p;
307 		cmd_p += strlen(module_p) + 1;	/* cmd line + null char */
308 		++dbf_p;
309 	}
310 
311 	fclose(dbfilep);
312 	return(0);
313 
314 reject:
315 	DEBUG((9, "svc_code <%s> failed validation test", svc_code_p));
316 	sprintf(scratch, dbfsvccmsg, svc_code_p);
317 	logmessage(scratch);
318 	return(-1);
319 p_reject:
320 	DEBUG((9,"private address <%s> failed validation test", private_p));
321 	sprintf(scratch, "Invalid private address ignored: \\x%x", private_p);
322 	logmessage(scratch);
323 	return(-1);
324 }
325 
326 
327 /*
328  * scan_dbf:	Take a quick pass through the data base file to figure out
329  *		approx. how many items in the file we'll need to
330  *		allocate storage for.  Essentially, returns the number
331  *		of non-null, non-comment lines in the data base file.
332  *
333  *		return: -1 == error.
334  *			other == number of non-comment characters.
335  *			Dbfentries set.
336  */
337 
338 unsigned
scan_dbf(path)339 scan_dbf(path)
340 register char *path;
341 {
342 	register unsigned int size = 0;
343 	register int n;
344 	register FILE *dbfilep;
345 	char buf[DBFLINESZ];
346 	register char *p = buf;
347 	char *svc_code_p;
348 	int flags;
349 	char *cmd_line_p;
350 	char *module_p;
351 	char *id_p;
352 	char *res1_p;
353 	char *res2_p;
354 	char *res3_p;
355 	int sflags;
356 	int prognum;
357 	int vernum;
358 	char *private_p;
359 	extern int errno;
360 
361 	DEBUG((9, "In scan_dbf.  Scanning data base file %s.", path));
362 
363 	if (!(dbfilep = fopen(path,"r")))  {
364 		DEBUG((9,"errorno = %d", errno));
365 		logmessage(dbfopenmsg);
366 		return(-1);
367 	}
368 
369 	do {
370 		n = rd_dbf_line(dbfilep,p,&svc_code_p,&flags,&id_p,&res1_p,&res2_p,&res3_p,&private_p,&prognum,&vernum,&module_p,&sflags,&cmd_line_p,SUPPRESS);
371 		if (n == -1)  {
372 			fclose(dbfilep);
373 			return(-1);
374 		}
375 		size += (unsigned)n;
376 		if (n)
377 			++Dbfentries;
378 	} while (n);
379 
380 	fclose(dbfilep);
381 	return(size);
382 }
383 
384 
385 /*
386  * rd_dbf_line:	Returns the next non-comment line into the
387  *		given buffer (up to DBFLINESZ bytes).
388  *		Skips 'ignore' lines.
389  *
390  *		Returns:	0 = done, -1 = error,
391  * 				other = cmd line size incl. terminating null.
392  *				*svc_code_p = service code;
393  *				*id_p = user id string;
394  *				*res1_p = reserved string;
395  *				*res2_p = reserved string;
396  *				*res3_p = reserved string;
397  *				*private_p = contains private address;
398  *				*flags_p = decoded flags;
399  *				prognum = RPC program #;
400  *				vernum = RPC version $;
401  *				cnd_line_p points to null terminated cmd line;
402  *
403  * When logging errors, the extern Dbflineno is used.
404  */
405 
406 int
rd_dbf_line(fp,bp,svc_code_p,flags_p,id_p,res1_p,res2_p,res3_p,private_p,prognum,vernum,module_p,sflags,cmd_line_p,mflag)407 rd_dbf_line(fp, bp, svc_code_p, flags_p, id_p, res1_p, res2_p, res3_p, private_p, prognum, vernum, module_p, sflags, cmd_line_p, mflag)
408 register FILE *fp;
409 register char *bp;
410 char **svc_code_p;
411 int *flags_p;
412 char **id_p;
413 char **res1_p;
414 char **res2_p;
415 char **res3_p;
416 char **private_p;
417 int *prognum;
418 int *vernum;
419 char **module_p;
420 int *sflags;
421 char **cmd_line_p;
422 int mflag;
423 {
424 	register int length;
425 	register char *p;
426 
427 	do {
428 		++Dbflineno;
429 		length = 0;
430 
431 		if (!fgets(bp, DBFLINESZ, fp))  {
432 			if (feof(fp))  {
433 				return(0);	/* EOF	*/
434 			}
435 			if (ferror(fp))  {
436 				sprintf(bp,dbfrderror,Dbflineno);
437 				logmessage(bp);
438 				return(-1);
439 			}
440 			sprintf(bp,dbfunknown,Dbflineno);
441 			logmessage(bp);
442 			return(-1);		/* Unknown error (?)	*/
443 		}
444 
445 		if (*(bp+strlen(bp)-1) != '\n')  {  /* terminating newline? */
446 			sprintf(bp, dbfbadlmsg, Dbflineno);
447 			logmessage(bp);
448 			return(-1);
449 		}
450 
451 		*(bp + strlen(bp) -1) = (char)0; /* delete newline	*/
452 
453 		if (strlen(bp) && (p = strchr(bp, DBFCOMMENT)))
454 			*p = (char)0;		/* delete comments	*/
455 		if (!strlen(bp))
456 			continue;
457 
458 		p = bp + strlen(bp) - 1;	/* bp->start; p->end	*/
459 		while ((p != bp) && (isspace(*p)))  {
460 			*p = (char)0;		/* delete terminating spaces */
461 			--p;
462 		}
463 
464 		while (*bp)			/* del beginning white space*/
465 			if (isspace(*bp))
466 				++bp;
467 			else
468 				break;
469 
470 		if (strlen(bp)) {		/* anything left?	*/
471 
472 		   if (!(length=scan_line(bp,svc_code_p,flags_p,id_p,res1_p,res2_p,res3_p,private_p,prognum,vernum,module_p,sflags,cmd_line_p,mflag))) {
473 
474 			DEBUG((1, "rd_dbf_line line %d, error while scanning entry",
475 			  Dbflineno));
476 			sprintf(bp, dbfbadlmsg, Dbflineno);
477 			logmessage(bp);
478 			return(-1);
479 		    }
480 		}
481 
482 	}  while (!length);		/* until we have something */
483 
484 	DEBUG((5,"rd_dbf_line: line: %d,cmd line len: %d",Dbflineno, length+1));
485 
486 	return(length+1); /* +1 for the trailing NULL */
487 
488 }
489 
490 
491 /*
492  * scan a non-white space line
493  *		0 = error;
494  *		other = length of cmd line;
495  *
496  *	non-null lines have the following format:
497  *
498  *	service_code: flags: id: res1: res2: res3: private address: rpcdata: sflags: modules: cmd_line # comments
499  *
500  * mflag is set to suppress messages (scan_line is called both for parsing
501  * and counting, messages should only be output once)
502  */
503 
504 int
scan_line(bp,svc_code_p,flags_p,id_p,res1_p,res2_p,res3_p,private_p,prognum,vernum,module_p,sflags,cmd_line_p,mflag)505 scan_line(bp, svc_code_p, flags_p, id_p, res1_p, res2_p, res3_p, private_p, prognum, vernum, module_p, sflags, cmd_line_p, mflag)
506 register char *bp;
507 char **svc_code_p;
508 register int *flags_p;
509 char **id_p;
510 char **res1_p;
511 char **res2_p;
512 char **res3_p;
513 char **private_p;
514 int *prognum;
515 int *vernum;
516 char **module_p;
517 int *sflags;
518 register char **cmd_line_p;
519 int mflag;
520 {
521 	register char *p;
522 	register char *nexttok;
523 	register char *ptr;
524 	int sawsep = 0;
525 	char scratch[BUFSIZ];
526 
527 	*flags_p = 0;
528 
529 	if (!(p = strchr(bp, DBFTOKSEP ))) {	/* look for service code string */
530 		DEBUG((9,"scan_line failed svc_code strchr"));
531 		return(0);
532 	}
533 	*p = '\0';
534 	*svc_code_p = bp;
535 	nexttok = ++p;
536 
537 	if (!(p = strchr(nexttok, DBFTOKSEP )))  {
538 		DEBUG((9,"scan_line failed flags strchr"));
539 		return(0);
540 	}
541 	*p = '\0';
542 
543 	while (*nexttok)  {
544 		switch (*nexttok)  {
545 		case 'x':		/* service is turned off	*/
546 		case 'X':
547 			*flags_p |= DBF_OFF;
548 			break;
549 		case 'u':		/* create utmp entry		*/
550 			*flags_p |= DBF_UTMP;
551 			break;
552 		default:
553 			DEBUG((1,"scan_line: unknown flag char: 0x%x",*nexttok));
554 			*flags_p = DBF_UNKNOWN;
555 			break;
556 		}
557 		++nexttok;
558 	}
559 	nexttok = ++p;
560 
561 	if (!(p = strchr(nexttok, DBFTOKSEP ))) {
562 		DEBUG((9,"scan_line failed id strchr"));
563 		return(0);
564 	}
565 	*p = '\0';
566 	*id_p = nexttok;
567 	nexttok = ++p;
568 
569 	if (!(p = strchr(nexttok, DBFTOKSEP ))) {
570 		DEBUG((9,"scan_line failed res1 strchr"));
571 		return(0);
572 	}
573 	*p = '\0';
574 	*res1_p = nexttok;
575 	nexttok = ++p;
576 
577 	if (!(p = strchr(nexttok, DBFTOKSEP ))) {
578 		DEBUG((9,"scan_line failed res2 strchr"));
579 		return(0);
580 	}
581 	*p = '\0';
582 	*res2_p = nexttok;
583 	nexttok = ++p;
584 
585 	if (!(p = strchr(nexttok, DBFTOKSEP ))) {
586 		DEBUG((9,"scan_line failed res3 strchr"));
587 		return(0);
588 	}
589 	*p = '\0';
590 	*res3_p = nexttok;
591 	nexttok = ++p;
592 
593 	if (!(p = strchr(nexttok, DBFTOKSEP ))) {
594 		DEBUG((9,"scan_line failed private strchr"));
595 		return(0);
596 	}
597 	*p = '\0';
598 	*private_p = nexttok;
599 	nexttok = ++p;
600 
601 	if (!(p = strchr(nexttok, DBFTOKSEP ))) {
602 		DEBUG((9,"scan_line failed rpc strchr"));
603 		return(0);
604 	}
605 	*p = '\0';
606 
607 	*prognum = -1;
608 	*vernum = -1;
609 	if (*nexttok) {
610 		/* there is rpc info */
611 		for (ptr = nexttok; *ptr; ++ptr) {
612 			if ((*ptr == ',') && !sawsep) {
613 				/*
614 				 * skip separator - note that if
615 				 * separator has been seen, it's not
616 				 * a digit so it will fail below
617 				 */
618 				sawsep++;
619 				continue;
620 			}
621 			if (!isdigit(*ptr)) {
622 				sprintf(scratch, "service code <%s> specifies non-integer rpc info", *svc_code_p);
623 				logmessage(scratch);
624 				return(0);
625 			}
626 		}
627 		ptr = strchr(nexttok, ',');
628 		if (ptr) {
629 			if ((*prognum = atoi(nexttok)) < 0) {
630 				if (!mflag) {
631 					/* messages aren't suppressed */
632 					sprintf(scratch, "service code <%s> specifies negative program number", *svc_code_p);
633 					logmessage(scratch);
634 				}
635 				return(0);
636 			}
637 			if ((*vernum = atoi(ptr + 1)) < 0) {
638 				if (!mflag) {
639 					sprintf(scratch, "service code <%s> specifies negative version number", *svc_code_p);
640 					logmessage(scratch);
641 				}
642 				return(0);
643 			}
644 		}
645 		else {
646 			if (!mflag) {
647 				sprintf(scratch, "service code <%s> - invalid rpcinfo", *svc_code_p);
648 				logmessage(scratch);
649 			}
650 			return(0);
651 		}
652 	}
653 	nexttok = ++p;
654 
655 	if (!(p = strchr(nexttok, DBFTOKSEP ))) {
656 		DEBUG((9,"scan_line failed sflags strchr"));
657 		return(0);
658 	}
659 	*p = '\0';
660 
661 	*sflags = 0;
662 	while (*nexttok)  {
663 		switch (*nexttok)  {
664 		case 'c':	/* dbf_cmd_line is a command */
665 			*sflags |= CFLAG;
666 			break;
667 		case 'd':	/* dynamic address */
668 			if ((int) strlen(*private_p) > 0) {
669 				if (!mflag) {
670 					sprintf(scratch, "service code <%s> specifies static and dynamic address", *svc_code_p);
671 					logmessage(scratch);
672 					logmessage("  address info ignored");
673 				}
674 				/* don't set DFLAG and wipe out private addr */
675 				**private_p = '\0';
676 			}
677 			else {
678 				*sflags |= DFLAG;
679 			}
680 			break;
681 		case 'p':	/* dbf_cmd_line is a pipe */
682 			*sflags |= PFLAG;
683 			break;
684 		default:
685 			if (!mflag) {
686 				sprintf(scratch, "service code <%s> unknown flag <%c> ignored", *svc_code_p, *nexttok);
687 				logmessage(scratch);
688 			}
689 			break;
690 		}
691 		++nexttok;
692 	}
693 	nexttok = ++p;
694 
695 	if (!(p = strchr(nexttok, DBFTOKSEP ))) {
696 		DEBUG((9,"scan_line failed module strchr"));
697 		return(0);
698 	}
699 	*p = '\0';
700 	*module_p = nexttok;
701 	nexttok = ++p;
702 
703 	*cmd_line_p = nexttok;
704 
705 	DEBUG((9,"scan_line: modules: %s; line: %s; len: %d", *module_p, *cmd_line_p, strlen(*svc_code_p)+strlen(*id_p)+strlen(*res1_p)+strlen(*res2_p)+strlen(*res3_p)+strlen(*private_p)+strlen(*module_p)+strlen(*cmd_line_p)+9));
706 	/*
707 	 * return the length of the buffer.  Add 9 for the NULLs after each
708 	 * string
709 	 */
710 	return(strlen(*svc_code_p)+strlen(*id_p)+strlen(*res1_p)+strlen(*res2_p)+strlen(*res3_p)+strlen(*private_p)+strlen(*module_p)+strlen(*cmd_line_p)+9);
711 }
712 
713 
714 
715 #define VERSIONSTR	"# VERSION="
716 
717 int
check_version(void)718 check_version(void)
719 {
720 	FILE *fp;
721 	char *line, *p, *tmp;
722 	int version;
723 
724 	if ((fp = fopen(DBFNAME, "r")) == NULL) {
725 		logmessage(dbfopenmsg);
726 		error(E_DBF_IO, EXIT | NOCORE | NO_MSG);
727 	}
728 	if ((line = (char *) malloc(DBFLINESZ)) == NULL)
729 		error(E_DBF_ALLOC, EXIT | NOCORE);
730 	p = line;
731 	while (fgets(p, DBFLINESZ, fp)) {
732 		if (!strncmp(p, VERSIONSTR, strlen(VERSIONSTR))) {
733 			/* pitch the newline */
734 			tmp = strchr(p, '\n');
735 			if (tmp)
736 				*tmp = '\0';
737 			else {
738 				logmessage(dbfcorrupt);
739 				error(E_DBF_CORRUPT, EXIT | NOCORE);
740 			}
741 			p += strlen(VERSIONSTR);
742 			if (*p)
743 				version = atoi(p);
744 			else {
745 				logmessage(dbfcorrupt);
746 				error(E_DBF_CORRUPT, EXIT | NOCORE);
747 			}
748 			free(line);
749 			fclose(fp);
750 			if (version != VERSION)
751 				return(1);	/* wrong version */
752 			else
753 				return(0);	/* version ok */
754 		}
755 		p = line;
756 	}
757 	logmessage(dbfcorrupt);
758 	error(E_DBF_CORRUPT, EXIT | NOCORE);
759 	return(1);
760 }
761 
762 
763 /*
764  * mkdbfargv:	Given a pointer to a dbf_t, construct argv
765  *		for an exec system call.
766  *		Warning: returns a pointer to static data which are
767  *			 overritten by each call.
768  *
769  *		There is a practical limit of 50 arguments (including argv[0])
770  *
771  *		Warning: calling mkdbfargv destroys the data (by writing null
772  *		characters via strtok) pointed to by dbp->dbf_cmd_line.
773  */
774 
775 static char *dbfargv[50];
776 static char *delim = " \t'\"";		/* delimiters */
777 
778 char **
mkdbfargv(dbp)779 mkdbfargv(dbp)
780 register dbf_t	*dbp;
781 {
782 	register char **argvp = dbfargv;
783 	register char *p = dbp->dbf_cmd_line;
784 	char delch;
785 	register char *savep;
786 	register char *tp;
787 	char scratch[BUFSIZ];
788 	char *strpbrk();
789 #ifdef	DEBUGMODE
790 	register int i = 0;
791 #endif
792 
793 	*argvp = 0;
794 	savep = p;
795 	while (p && *p) {
796 		if (p = strpbrk(p, delim)) {
797 			switch (*p) {
798 			case ' ':
799 			case '\t':
800 				/* "normal" cases */
801 				*p++ = '\0';
802 				*argvp++ = savep;
803 				DEBUG((9, "argv[%d] = %s", i++, savep));
804 				/* zap trailing white space */
805 				while (isspace(*p))
806 					p++;
807 				savep = p;
808 				break;
809 			case '"':
810 			case '\'':
811 				/* found a string */
812 				delch = *p; /* remember the delimiter */
813 				savep = ++p;
814 
815 /*
816  * We work the string in place, embedded instances of the string delimiter,
817  * i.e. \" must have the '\' removed.  Since we'd have to do a compare to
818  * decide if a copy were needed, it's less work to just do the copy, even
819  * though it is most likely unnecessary.
820  */
821 
822 				tp = p;
823 				for (;;) {
824 					if (*p == '\0') {
825 						sprintf(scratch, "invalid command line, non-terminated string for service code %s", dbp->dbf_svc_code);
826 						logmessage(scratch);
827 						exit(2); /* server, don't log */
828 					}
829 					if (*p == delch) {
830 						if (*(tp - 1) == '\\') { /* \delim */
831 							*(tp - 1) = *p;
832 							p++;
833 						}
834 						else { /* end of string */
835 							*tp = 0;
836 							*argvp++ = savep;
837 							DEBUG((9, "argv[%d] = %s", i++, savep));
838 							p++;
839 							/* zap trailing white space */
840 							while (isspace(*p))
841 								p++;
842 							savep = p;
843 							break;
844 						}
845 					}
846 					else {
847 						*tp++ = *p++;
848 					}
849 				}
850 				break;
851 			default:
852 				logmessage("Internal error in parse routine");
853 				exit(2); /* server, don't log */
854 			}
855 		}
856 		else {
857 			*argvp++ = savep;
858 			DEBUG((9, "argv[%d] = %s", i++, savep));
859 		}
860 	}
861 	*argvp = 0;
862 	return(dbfargv);
863 }
864 
865 
866 
867 /*
868  *
869  * getentry: Given a fd, this routine will return a
870  *		    dbf entry.  If the entry doesn't exist it will
871  *		    return NULL.
872  */
873 
874 dbf_t *
getentry(fd)875 getentry(fd)
876 int	fd;
877 {
878 	extern dbf_t *Dbfhead;		/* Dbfentries (when allocated)	*/
879 	register dbf_t 	*dbp = Dbfhead;
880 
881 	if (!Dbfhead) {		/* no private address in database file */
882 		DEBUG((9, "getdbfentry - nothing in Dbfhead = %s ",Dbfhead));
883 		return((dbf_t *)0);
884 	}
885 	else
886 		for (dbp = Dbfhead;  dbp->dbf_prv_adr;   ++dbp)
887 			if (fd == dbp->dbf_fd) {
888 				return(dbp);
889 			}
890 
891 	return((dbf_t *)0);	/* requested private address not in list */
892 
893 }
894 
895 
896 /*
897  * pushmod:	push modules if defined in the data base entry.
898  *
899  *		WARNING: This routine writes into the in-memory copy
900  *		of the database file.  Therefore, after it is called,
901  *		the incore copy of the database file will no longer be valid.
902  */
903 
904 int
pushmod(fd,mp)905 pushmod(fd, mp)
906 int fd;
907 register char *mp;
908 {
909 	register char *cp;
910 	register char *bufp = mp;
911 	char name[32];
912 	extern int errno;
913 
914 	DEBUG((9,"in pushmod:"));
915 	if (!mp || *mp == '\0') {
916 		DEBUG((9,"NULL list: exiting pushmod"));
917 		return(0);
918 	}
919 	/* pop timod if it is on the stack */
920 	if (ioctl(fd, I_LOOK, name) >= 0) {
921 		if (strcmp(name, "timod") == 0) {
922 			if (ioctl(fd, I_POP, 0) < 0)
923 				DEBUG((9,"pushmod: I_POP failed"));
924 		}
925 	}
926 	while ((cp = strtok(bufp, ",")) != NULL) {
927 		bufp = NULL;
928 		DEBUG((9,"pushmod: about to push %s", cp));
929 		if (ioctl(fd, I_PUSH, cp) < 0) {
930 			DEBUG((9,"pushmod: ioctl failed, errno = %d",errno));
931 			return(1);
932 		}
933 	}
934 	DEBUG((9,"exiting pushmod:"));
935 	return(0);
936 }
937