xref: /titanic_41/usr/src/cmd/listen/listen.c (revision b1c95175797741d5c8a0d869f091db6c30bc3257)
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 2014 Garrett D'Amore
25  */
26 /*
27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
32 /*	  All Rights Reserved  	*/
33 
34 /*
35  * Network Listener Process
36  *
37  *		command line:
38  *
39  *		listen [ -m minor_prefix ] netspec
40  *
41  */
42 
43 /* system include files	*/
44 
45 #include <fcntl.h>
46 #include <signal.h>
47 #include <stdio.h>
48 #include <unistd.h>
49 #include <string.h>
50 #include <errno.h>
51 #include <memory.h>
52 #include <sys/utsname.h>
53 #include <sys/tiuser.h>
54 #include <sys/param.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <sys/mkdev.h>
58 #include <values.h>
59 #include <ctype.h>
60 #include <pwd.h>
61 #include <grp.h>
62 #include <sys/ipc.h>
63 #include <sys/poll.h>
64 #include <sys/stropts.h>
65 #include <sac.h>
66 #include <utmpx.h>
67 
68 /* listener include files */
69 
70 #include "lsparam.h"		/* listener parameters		*/
71 #include "lsfiles.h"		/* listener files info		*/
72 #include "lserror.h"		/* listener error codes		*/
73 #include "lsnlsmsg.h"		/* NLPS listener protocol	*/
74 #include "lssmbmsg.h"		/* MS_NET identifier		*/
75 #include "lsdbf.h"		/* data base file stuff		*/
76 #include "listen.h"
77 
78 /* defines	*/
79 
80 #define NAMESIZE	(NAMEBUFSZ-1)
81 
82 #define SPLhi()		Splflag = 1
83 #define SPLlo()		Splflag = 0
84 
85 #define GEN	1
86 #define LOGIN	0
87 
88 /* global variables	*/
89 
90 int	NLPS_proc = 0;	/* set if process is a listener child		*/
91 pid_t	Pid;		/* listener's process ID 			*/
92 char	*Progname;	/* listener's basename (from argv[0])		*/
93 static	char Provbuf[PATHSIZE];
94 char	*Provider = Provbuf;	/* name of transport provider		*/
95 char	*Netspec = NETSPEC;
96 char	*Minor_prefix;		/* prefix for minor device names	*/
97 int	Dbf_entries;		/* number of private addresses in dbf file*/
98 int	Valid_addrs;		/* number of addresses bound		*/
99 struct	pollfd *Pollfds;	/* for polling fds			*/
100 dbf_t	*Dbfhead;		/* Beginning of in-memory database	*/
101 dbf_t	*Newdbf;		/* Beginning of in-memory database (reread) */
102 char	*Server_cmd_lines;	/* database space			*/
103 char	*New_cmd_lines;		/* database space (reread) 		*/
104 long	Ndesc;			/* Number of per-process file descriptors */
105 int	Readdb;			/* set to TRUE by SAC_READDB message	*/
106 struct	netconfig *Netconf;	/* netconfig structure for this network	*/
107 
108 struct	call_list	Free_call;
109 struct	call_list	*Free_call_p = &Free_call; /* call free list 	*/
110 struct	call_list	*Priv_call;	/* call save pending list 	*/
111 
112 /* FILE DESCRIPTOR MANAGEMENT:
113  *
114  * The listener uses 6 (sometimes 7) file descriptors:
115  *	fd 0:	Originally opened to /dev/null, used to accept incoming calls.
116  *	fd 1:	In the parent, a connection to _sacpipe.  Closed in the child
117  *		and dup'ed to 0.
118  *	fd 2:	In the parent, a connection to _pmpipe.  Dup'ed in the child
119  *		to 0.
120  *	fd 3:	Originally opened to /dev/null, this file descriptor is
121  *		reserved to open the STREAMS pipe when passing the connection
122  *		to a standing server.
123  *	fd 4:	Opened to the pid file.  We have to keep it open to keep the
124  *		lock active.
125  *	fd 5:	Opened to the log file.
126  *	fd 6:	Opened to the debug file ONLY when compiled with DEBUGMODE.
127  *
128  * The remaining file descriptors are available for binding private addresses.
129  */
130 
131 #ifndef DEBUGMODE
132 #define USEDFDS	6
133 #else
134 #define	USEDFDS	7
135 FILE	*Debugfp;		/* for the debugging file	*/
136 #endif
137 
138 int	Acceptfd;		/* to accept connections (fd 0)	*/
139 int	Sacpipefd;		/* pipe TO sac process (fd 1)	*/
140 int	Pmpipefd;		/* pipe FROM sac process (fd 2) */
141 int	Passfd;			/* pipe used to pass FD (fd 3)	*/
142 int	Pidfd;			/* locked pid file (fd 4)	*/
143 FILE	*Logfp;			/* for logging listener activity*/
144 
145 struct	pmmsg	Pmmsg;		/* to respond to SAC		*/
146 int	State = PM_STARTING;	/* current SAC state		*/
147 char	Mytag[15];
148 
149 char	Lastmsg[BUFSIZ];	/* contains last msg logged (by stampbuf) */
150 int	Logmax = LOGMAX;	/* number of entriet to allow in logfile  */
151 
152 int	Splflag;		/* logfile critical region flag		  */
153 
154 static char *badnspmsg = "Bad netspec on command line ( Pathname too long )";
155 static char *badstart  = "Listener failed to start properly";
156 static char *nologfile = "Unable to open listener log file during initialization";
157 static char *usage     = "Usage: listen [ -m minor_prefix ] network_device";
158 static char *nopmtag   = "Fatal error: Unable to get PMTAG from environment";
159 static char tzenv[BUFSIZ];
160 
161 #define TZFILE	"/etc/default/init"
162 #define TZSTR	"TZ="
163 
164 void	check_sac_mesg();	/* routine to process messages from sac */
165 void	rpc_register();		/* routine to register rpc services */
166 void	rpc_unregister();	/* routine to unregister rpc services */
167 extern	struct	netconfig	*getnetconfigent();
168 extern	char	*t_alloc();
169 extern	void	logexit();
170 extern	int	t_errno;
171 extern	int	errno;
172 
173 #ifndef TRUE
174 #define	TRUE	1
175 #define FALSE	0
176 #endif
177 
178 static void mod_prvaddr(void);
179 static void pitchcall(struct call_list *pending, struct t_discon *discon);
180 static void clr_call(struct t_call *call);
181 static void trycon(struct call_list *phead, int fd);
182 static void send_dis(struct call_list *phead, int fd);
183 static void doevent(struct call_list *phead, int fd);
184 static void listen(void);
185 static void rst_signals(void);
186 static void catch_signals(void);
187 static void net_open(void);
188 static void init_files(void);
189 static void pid_open(void);
190 
191 int
main(int argc,char ** argv)192 main(int argc, char **argv)
193 {
194 	struct stat buf;
195 	int ret;
196 	char scratch[BUFSIZ];
197 	char log[BUFSIZ];
198 	char olog[BUFSIZ];
199 	char *scratch_p = scratch;
200 	char *mytag_p;
201 	FILE *fp;
202 	extern char *getenv();
203 	char *parse();
204 	int	c;
205 	extern	char *optarg;
206 	extern	int optind;
207 	int i;
208 	char	*Mytag_p = Mytag;
209 
210 	/* Get my port monitor tag out of the environment		*/
211 	if ((mytag_p = getenv("PMTAG")) == NULL) {
212 		/* no place to write */
213 		exit(1);
214 	}
215 	strcpy(Mytag, mytag_p);
216 
217 	/* open log file */
218 	sprintf(log, "%s/%s/%s", ALTDIR, Mytag_p, LOGNAME);
219 	sprintf(olog, "%s/%s/%s", ALTDIR, Mytag_p, OLOGNAME);
220 	if (stat(log, &buf) == 0) {
221 		/* file exists, try and save it but if we can't don't worry */
222 		unlink(olog);
223 		rename(log, olog);
224 	}
225 	if ((i = open(log, O_WRONLY|O_CREAT|O_APPEND, 0444)) < 0)
226 		logexit(1, nologfile);
227 	/* as stated above, the log file should be file descriptor 5 */
228 	if ((ret = fcntl(i, F_DUPFD, 5)) != 5)
229 		logexit(1, nologfile);
230 	Logfp = fdopen(ret, "a+");
231 
232 	/* Get my port monitor tag out of the environment		*/
233 	if ((mytag_p = getenv("PMTAG")) == NULL) {
234 		logexit(1, nopmtag);
235 	}
236 	strcpy(Mytag, mytag_p);
237 
238 	(void) umask(022);
239 	Readdb = FALSE;
240 
241 	if (geteuid() != (uid_t) 0) {
242 		logmessage("Must be root to start listener");
243 		logexit(1, badstart);
244 	}
245 
246 	while ((c = getopt(argc, argv, "m:")) != EOF)
247 		switch (c) {
248 		case 'm':
249 			Minor_prefix = optarg;
250 			break;
251 		default:
252 			logexit(1, usage);
253 			break;
254 		}
255 
256 	if ((Netspec = argv[optind]) == NULL) {
257 		logexit(1, usage);
258 	}
259 	if ((Netconf = getnetconfigent(Netspec)) == NULL) {
260 		sprintf(scratch, "no netconfig entry for <%s>", Netspec);
261 		logmessage(scratch);
262 		logexit(1, badstart);
263 	}
264 	if (!Minor_prefix)
265 		Minor_prefix = argv[optind];
266 
267 	if ((int) strlen(Netspec) > PATHSIZE)  {
268 		logmessage(badnspmsg);
269 		logexit(1, badstart);
270 	}
271 
272 	/*
273 	 * SAC will start the listener in the correct directory, so we
274 	 * don't need to chdir there, as we did in older versions
275 	 */
276 
277 	strcpy(Provbuf, "/dev/");
278 	strcat(Provbuf, Netspec);
279 
280 	(void) umask(0);
281 
282 	init_files();		/* open Accept, Sac, Pm, Pass files	*/
283 	pid_open();		/* create pid file			*/
284 
285 #ifdef	DEBUGMODE
286 	sprintf(scratch, "%s/%s/%s", ALTDIR, Mytag, DBGNAME);
287 	Debugfp = fopen(scratch, "w");
288 #endif
289 
290 
291 #ifdef	DEBUGMODE
292 	if ((!Logfp) || (!Debugfp))
293 #else
294 	if (!Logfp)
295 #endif
296 		logexit(1, badstart);
297 
298 /*
299  * In case we started with no environment, find out what timezone we're
300  * in.  This will get passed to children, so only need to do once.
301  */
302 
303 	if (getenv("TZ") == NULL) {
304 		fp = fopen(TZFILE, "r");
305 		if (fp) {
306 			while (fgets(tzenv, BUFSIZ, fp)) {
307 				if (tzenv[strlen(tzenv) - 1] == '\n')
308 					tzenv[strlen(tzenv) - 1] = '\0';
309 				if (!strncmp(TZSTR, tzenv, strlen(TZSTR))) {
310 					putenv(parse(tzenv));
311 					break;
312 				}
313 			}
314 			fclose(fp);
315 		}
316 		else {
317 			sprintf(scratch, "couldn't open %s, default to GMT",
318 			    TZFILE);
319 			logmessage(scratch);
320 		}
321 	}
322 
323 	logmessage("@(#)listen:listen.c	1.19.9.1");
324 
325 #ifdef	DEBUGMODE
326 	logmessage("Listener process with DEBUG capability");
327 #endif
328 
329 	sprintf(scratch, "Listener port monitor tag: %s", Mytag_p);
330 	logmessage(scratch);
331 	DEBUG((9, "Minor prefix: %s  Netspec %s", Minor_prefix, Netspec));
332 
333 	/* fill in Pmmesg fields that always stay the same */
334 
335 	Pmmsg.pm_maxclass = MAXCLASS;
336 	strcpy(Pmmsg.pm_tag, Mytag_p);
337 	Pmmsg.pm_size = 0;
338 
339 	/* Find out what state to start in.  If not in env, exit */
340 	if ((scratch_p = getenv("ISTATE")) == NULL)
341 		logexit(1, "ERROR: ISTATE variable not set in environment");
342 
343 	if (!strcmp(scratch_p, "enabled")) {
344 		State = PM_ENABLED;
345 		logmessage("Starting state: ENABLED");
346 	}
347 	else {
348 		State = PM_DISABLED;
349 		logmessage("Starting state: DISABLED");
350 	}
351 
352 	/* try to get my "basename"		*/
353 	Progname = strrchr(argv[0], '/');
354 	if (Progname && Progname[1])
355 		++Progname;
356 	else
357 		Progname = argv[0];
358 
359 	catch_signals();
360 
361 	/*
362 	 * Allocate memory for private address and file descriptor table
363 	 * Here we are assuming that no matter how many private addresses
364 	 * exist in the system if the system limit is 20 then we will only
365 	 * get 20 file descriptors
366 	 */
367 
368 	Ndesc = ulimit(4,0L);		/* get num of file des on system */
369 
370 	read_dbf(DB_INIT);
371 	net_open();			/* init, open, bind names 	*/
372 
373 	for (i = 3; i < Ndesc; i++)  {	/* leave stdout, stderr open	*/
374 		fcntl(i, F_SETFD, 1);	/* set close on exec flag*/
375 	}
376 
377 	logmessage("Initialization Complete");
378 
379 	listen();
380 	return (0);
381 }
382 
383 
384 /*
385  * pid_open:
386  *
387  * open pidfile with specified oflags and modes and lock it
388  *
389  */
390 
391 static char *pidopenmsg ="Can't create process ID file in home directory";
392 static char *pidlockmsg ="Can't lock PID file: listener may already be running";
393 
394 static void
pid_open(void)395 pid_open(void)
396 {
397 	int ret;
398 	unsigned int i;
399 	char pidstring[20];
400 
401 	if ((Pidfd = open(PIDNAME, PIDOFLAG, PIDMODE)) == -1)  {
402 		logmessage(pidopenmsg);
403 		error(E_CREAT, EXIT | NOCORE | NO_MSG);
404 	}
405 
406 	if (lockf(Pidfd, 2, 0L) == -1)  {
407 		logmessage(pidlockmsg);
408 		logexit(1, badstart);
409 	}
410 
411 	Pid = getpid();
412 	i = sprintf(pidstring, "%ld", Pid) + 1;
413 	ftruncate(Pidfd, 0);
414 
415 	while ((ret = write(Pidfd, pidstring, i)) != i) {
416 		if (errno == EINTR)
417 			continue;
418 		if (ret < 0)
419 			sys_error(E_PIDWRITE, EXIT);
420 		else
421 			error(E_PIDWRITE, EXIT);
422 	}
423 
424 }
425 
426 /*
427  * init_files: open initial files for the listener (see FILE DESC MGMT comment)
428  */
429 
430 static char *pmopenmsg = "Can't open pipe to read SAC messages";
431 static char *sacopenmsg = "Can't open pipe to respond to SAC messages";
432 
433 static void
init_files(void)434 init_files(void)
435 {
436 	close(0);
437         if ((Acceptfd = open("/dev/null", O_RDWR)) != 0) {
438 		logmessage("Trouble opening /dev/null");
439                 sys_error(E_SYS_ERROR, EXIT | NOCORE);
440 	}
441 
442 	close(1);
443 	if ((Sacpipefd = open(SACPIPE, O_RDWR|O_NDELAY)) != 1) {
444 		logmessage(sacopenmsg);
445 		error(E_CREAT, EXIT | NOCORE | NO_MSG);
446 	}
447 
448 	close(2);
449 	if ((Pmpipefd = open(PMPIPE, O_RDWR|O_NDELAY)) != 2) {
450 		logmessage(pmopenmsg);
451 		error(E_CREAT, EXIT | NOCORE | NO_MSG);
452 	}
453 
454 	close(3);
455 	if ((Passfd = dup(Acceptfd)) != 3) {
456 		logmessage("Trouble duping /dev/null");
457                 sys_error(E_SYS_ERROR, EXIT | NOCORE);
458 	}
459 
460 }
461 
462 
463 /*
464  * net_open: open and bind communications channels
465  *		The name generation code in net_open, open_bind and bind is,
466  * 		for the	most part, specific to STARLAN NETWORK.
467  *		This name generation code is included in the listener
468  *		as a developer debugging aid.
469  */
470 
471 static void
net_open(void)472 net_open(void)
473 {
474 #ifdef	CHARADDR
475 	char pbuf[NAMEBUFSZ + 1];
476 #endif	/* CHARADDR	*/
477 	int i;
478 	dbf_t *dp;
479 	char scratch[BUFSIZ];
480 
481 	DEBUG((9,"in net_open"));
482 
483 	/* set up free call list and pending connection lists */
484 
485 	Free_call_p->cl_head = (struct callsave *) NULL;
486 	Free_call_p->cl_tail = (struct callsave *) NULL;
487 
488 	/* Pending calls are linked in a structure, one per fild descriptor */
489 	if ((Priv_call = (struct call_list *) malloc(Ndesc *(sizeof(
490 				struct call_list)))) == NULL)
491 		error(E_MALLOC,NOCORE | EXIT);
492 
493 	i = 0;
494 	Valid_addrs = 0;
495 	/* first do static addrs */
496 	while ( (i < Dbf_entries) ) {
497 		dp = &Dbfhead[i];
498 		if (!(dp->dbf_sflags & DFLAG)) {
499 			if (add_prvaddr(dp) == 0)
500 				Valid_addrs++;
501 		}
502 		i++;
503 	}
504 	i = 0;
505 	/* second pass for dynamic addrs */
506 	while ( (i < Dbf_entries) ) {
507 		dp = &Dbfhead[i];
508 		if (dp->dbf_sflags & DFLAG) {
509 			if (add_prvaddr(dp) == 0)
510 				Valid_addrs++;
511 		}
512 		i++;
513 	}
514 
515 	sprintf(scratch, "Net opened, %d %s bound, %d fds free", Valid_addrs,
516 		(Valid_addrs == 1) ? "address" : "addresses",
517 		Ndesc-Valid_addrs-USEDFDS);
518 	logmessage(scratch);
519 }
520 
521 
522 /*
523  * Following are some general queueing routines.  The call list head contains
524  * a pointer to the head of the queue and to the tail of the queue.  Normally,
525  * calls are added to the tail and removed from the head to ensure they are
526  * processed in the order received, however, because of the possible interruption
527  * of an acceptance with the resulting requeueing, it is necessary to have a
528  * way to do a "priority queueing" which inserts at the head of the queue for
529  * immediate processing
530  */
531 
532 /*
533  * queue:
534  *
535  * add calls to tail of queue
536  */
537 
538 
539 void
queue(head,cp)540 queue(head, cp)
541 struct call_list *head;
542 struct callsave *cp;
543 {
544 	DEBUG((9,"in queue"));
545 	if (head->cl_tail == (struct callsave *) NULL) {
546 		cp->c_np = (struct callsave *) NULL;
547 		head->cl_head = head->cl_tail = cp;
548 	}
549 	else {
550 		cp->c_np = head->cl_tail->c_np;
551 		head->cl_tail->c_np = cp;
552 		head->cl_tail = cp;
553 	}
554 }
555 
556 
557 /*
558  * pqueue:
559  *
560  * priority queuer, add calls to head of queue
561  */
562 
563 void
pqueue(head,cp)564 pqueue(head, cp)
565 struct call_list *head;
566 struct callsave *cp;
567 {
568 	if (head->cl_head == (struct callsave *) NULL) {
569 		cp->c_np = (struct callsave *) NULL;
570 		head->cl_head = head->cl_tail = cp;
571 	}
572 	else {
573 		cp->c_np = head->cl_head;
574 		head->cl_head = cp;
575 	}
576 }
577 
578 
579 /*
580  * dequeue:
581  *
582  * remove a call from the head of queue
583  */
584 
585 
586 struct callsave *
dequeue(head)587 dequeue(head)
588 struct call_list *head;
589 {
590 	struct callsave *ret;
591 
592 	DEBUG((9,"in dequeue"));
593 	if (head->cl_head == (struct callsave *) NULL)  {
594 #ifdef OLD
595 		DEBUG((9,"cl_head = null"));
596 		error(E_CANT_HAPPEN, EXIT);
597 #endif
598 		DEBUG((9, "NULL return"));
599 		return((struct callsave *) NULL);
600 	}
601 	ret = head->cl_head;
602 	head->cl_head = ret->c_np;
603 	if (head->cl_head == (struct callsave *) NULL)
604 		head->cl_tail = (struct callsave *) NULL;
605 	return(ret);
606 }
607 
608 
609 /*
610  * open_bind:
611  *
612  * open the network and bind the endpoint to 'name'
613  * this routine is also used by listen(), so it can't exit
614  * under all error conditions:
615  *	if there are no minor devices avaliable in the network driver,
616  * 		open_bind returns -1.  (error message will be logged).
617  *	if the open fails because all file descriptors are in use,
618  *		open_bind returns -2.  (no message logged).  This should
619  *		only happen when too many private addresses are specified.
620  *	if the bind fails, open_bind returns -3  (no message logged).  This
621  *		happens when a duplicate address is bound, and the message
622  *		should be logged by the routine that calls open_bind.
623  * All other errors cause an exit.
624  *
625  * If clen is zero, transport provider picks the name and these
626  * routines (open_bind and bind) ignore name and qlen --
627  * this option is used when binding a name for accepting a connection
628  * (not for listening.)  You MUST supply a name, qlen and clen when
629  * opening/binding a name for listening.
630  *
631  * Assumptions: driver returns ENXIO when all devices are allocated.
632  */
633 
634 int
open_bind(name,qlen,clen,conp,adrp)635 open_bind(name, qlen, clen, conp, adrp)
636 char *name;
637 int qlen;
638 int clen;
639 unsigned int *conp;
640 char **adrp;
641 {
642 	int fd;
643 	int ret;
644 
645 	DEBUG((9,"in open_bind, qlen=%d clen=%d conp=%d",qlen,clen,conp));
646 	while ((fd = t_open(Provider, NETOFLAG, NULL)) < 0) {
647 		if (t_errno == TSYSERR) {
648 			switch (errno) {
649 			case EINTR:
650 				continue;
651 			case EMFILE:
652 				return(-2);
653 				break;
654 			case ENXIO:
655 			case ENOSR:
656 			case ENOSPC:
657 			case EAGAIN:
658 				tli_error(E_FD1OPEN, CONTINUE);
659 				logmessage("No network minor devices (ENXIO/ENOSR)");
660 				return(-1);
661 				break;
662 			}
663 			DEBUG((9,"problem in t_open"));
664 			tli_error(E_FD1OPEN, EXIT);
665 		}
666 	}
667 
668 	ret = bind(fd, name, qlen, clen, adrp);
669 	DEBUG((9, "bind returns %d", ret));
670 
671 	if (ret < 0) {
672 		t_close(fd);
673 		return(-3);
674 	}
675 	if (conp)
676 		*conp = ret;
677 	return(fd);
678 }
679 
680 
681 int
bind(fd,name,qlen,clen,ap)682 bind(fd, name, qlen, clen, ap)
683 int fd;
684 char *name;
685 int qlen;
686 int clen;
687 char **ap;
688 {
689 	struct t_bind *req = (struct t_bind *)0;
690 	struct t_bind *ret = (struct t_bind *)0;
691 	char	*p, *q;
692 	unsigned int	retval;
693 	extern void	nlsaddr2c();
694 	extern int	memcmp();
695 	extern int	errno;
696 
697 #ifdef	CHARADDR
698 	char pbuf[NAMEBUFSZ + 1];
699 #endif
700 	char scratch[BUFSIZ];
701 
702 	DEBUG((9,"in bind, fd = %d, clen = %d", fd, clen));
703 
704 	if (clen)  {
705 		errno = t_errno = 0;
706 		while (!(req = (struct t_bind *)t_alloc(fd,T_BIND,T_ALL)) ) {
707 			if ((t_errno != TSYSERR) || (errno != EAGAIN))
708 				tli_error( E_T_ALLOC, EXIT);
709 			else
710 				tli_error( E_T_ALLOC, CONTINUE);
711 		}
712 
713 		errno = t_errno = 0;
714 		while (!(ret = (struct t_bind *)t_alloc(fd,T_BIND,T_ALL)) ) {
715 			if ((t_errno != TSYSERR) || (errno != EAGAIN))
716 				tli_error( E_T_ALLOC, EXIT);
717 			else
718 				tli_error( E_T_ALLOC, CONTINUE);
719 		}
720 
721 		if (clen > (int) req->addr.maxlen)  {
722 			sprintf(scratch,"Truncating name size from %d to %d",
723 				clen, req->addr.maxlen);
724 			logmessage(scratch);
725 			clen = req->addr.maxlen;
726 		}
727 
728 		if (clen == -1) {
729 			req->addr.len = 0;
730 		}
731 		else {
732 			(void)memcpy(req->addr.buf, name, clen);
733 			req->addr.len = clen;
734 		}
735 		req->qlen = qlen;
736 
737 #if defined(CHARADDR) && defined(DEBUGMODE)
738 		(void)memcpy(pbuf, req->addr.buf, req->addr.len);
739 		pbuf[req->addr.len] = (char)0;
740 		DEBUG((3,"bind: fd=%d, logical name=%c%s%c, len=%d",
741 			fd, '\"',pbuf, '\"', req->addr.len));
742 #endif	/* CHARADDR  && DEBUGMODE */
743 
744 
745 #if defined(CHARADDR) && defined(DEBUGMODE)
746 		(void)memcpy(pbuf, req->addr.buf, req->addr.len);
747 		pbuf[req->addr.len] = (char)0;
748 		DEBUG((3,"bind: fd=%d, address=%c%s%c, len=%d",
749 			fd, '\"',pbuf, '\"', req->addr.len));
750 #endif	/* CHARADDR  && DEBUGMODE */
751 
752 
753 	}
754 
755 	if (t_bind(fd, req, ret))  {
756 		DEBUG((1,"t_bind failed; t_errno %d errno %d", t_errno, errno));
757 		if (qlen)	/* starup only */
758 			tli_error(E_T_BIND, EXIT | NOCORE);
759 		/* here during normal service */
760 		if ((t_errno == TNOADDR) || ((t_errno == TSYSERR) && (errno == EAGAIN))) {
761 			/* our name space is all used up */
762 			tli_error(E_T_BIND, CONTINUE);
763 			t_close(fd);
764 			if (clen)  {
765 				if ( t_free((char *)req, T_BIND) )
766 					tli_error(E_T_FREE, EXIT);
767 				if ( t_free((char *)ret, T_BIND) )
768 					tli_error(E_T_FREE, EXIT);
769 			}
770 			return(-1);
771 		}
772 		/* otherwise, irrecoverable error */
773 		tli_error(E_T_BIND, EXIT | NOCORE);
774 	}
775 	DEBUG((9, "t_bind succeeded"));
776 
777 	if (clen)  {
778 		retval = ret->qlen;
779 		if (clen == -1) {
780 			/* dynamic address */
781 			*ap = (char *) malloc(((ret->addr.len) << 1) + 3);
782 			if (*ap) {
783 				(*ap)[0] = '\\';
784 				(*ap)[1] = 'x';
785 				nlsaddr2c(*ap+2,ret->addr.buf,(int)ret->addr.len);
786 			}
787 		}
788 		else if ( (ret->addr.len != req->addr.len) ||
789 		     (memcmp( req->addr.buf, ret->addr.buf, (int) req->addr.len)) )  {
790 			p = (char *) malloc(((ret->addr.len) << 1) + 1);
791 			q = (char *) malloc(((req->addr.len) << 1) + 1);
792 			if (p && q) {
793 				nlsaddr2c(p, ret->addr.buf, (int)ret->addr.len);
794 				nlsaddr2c(q, req->addr.buf, (int)req->addr.len);
795 				sprintf(scratch, "Requested address \\x%s", q);
796 				logmessage(scratch);
797 				sprintf(scratch, "Actual address    \\x%s", p);
798 				logmessage(scratch);
799 				free(p);
800 				free(q);
801 			}
802 			DEBUG((9, "failed to bind requested address"));
803 			t_unbind(fd);
804 			t_close(fd);
805 			if ( t_free((char *)req, T_BIND) )
806 				tli_error(E_T_FREE, EXIT);
807 			if ( t_free((char *)ret, T_BIND) )
808 				tli_error(E_T_FREE, EXIT);
809 			return(-1);
810 		}
811 
812 		if ( t_free((char *)req, T_BIND) )
813 			tli_error(E_T_FREE, EXIT);
814 
815 		if ( t_free((char *)ret, T_BIND) )
816 			tli_error(E_T_FREE, EXIT);
817 		return(retval);
818 	}
819 	return((unsigned int) 0);
820 }
821 
822 
823 /*
824  * catch_signals:
825  *		Ignore some, catch the rest. Use SIGTERM to kill me.
826  */
827 
828 sigset_t Oset;
829 struct sigaction Sigterm;
830 struct sigaction Sigcld;
831 
832 static void
catch_signals(void)833 catch_signals(void)
834 {
835 	sigset_t sset;
836 	sigset_t eset;
837 	struct sigaction sigact;
838 	extern void sigterm();
839 
840 	(void) sigfillset(&sset);
841 	(void) sigdelset(&sset, SIGTERM);
842 	(void) sigdelset(&sset, SIGCLD);
843 	(void) sigprocmask(SIG_SETMASK, &sset, &Oset);
844 
845 	sigact.sa_flags = 0;
846 	sigact.sa_handler = sigterm;
847 	sigact.sa_mask = sset;
848 	sigaction(SIGTERM, &sigact, &Sigterm);
849 	sigact.sa_flags = SA_NOCLDWAIT;
850 	sigact.sa_handler = SIG_IGN;
851 	sigact.sa_mask = sset;
852 	sigaction(SIGCLD, &sigact, &Sigcld);
853 }
854 
855 
856 /*
857  * rst_signals:
858  *		After forking but before exec'ing a server,
859  *		reset all signals to original setting.
860  */
861 
862 static void
rst_signals(void)863 rst_signals(void)
864 {
865 	struct sigaction sigact;
866 
867 	sigaction(SIGTERM, &Sigterm, NULL);
868 	sigaction(SIGCLD, &Sigcld, NULL);
869 	sigprocmask(SIG_SETMASK, &Oset, NULL);
870 }
871 
872 
873 /*
874  * sigterm:	Clean up and exit.
875  */
876 
877 void
sigterm()878 sigterm()
879 {
880 	extern char *shaddr;
881 	extern char *sh2addr;
882 
883 	error(E_SIGTERM, EXIT | NORMAL | NOCORE);	/* calls cleanup */
884 }
885 
886 
887 /*
888  * listen:	listen for and process connection requests.
889  */
890 
891 static char *dbfnewdmsg = "Using new data base file";
892 
893 static void
listen(void)894 listen(void)
895 {
896 	int	i;
897 	dbf_t	*dbp	= Dbfhead;
898 	struct	pollfd	*sp;
899 	struct		call_list *phead; /* pending head */
900 
901 	DEBUG((9,"in listen, tag %s", Pmmsg.pm_tag));
902 
903 	if ((Pollfds = (struct pollfd *) malloc(Ndesc * sizeof(struct pollfd)))
904 			== NULL)
905 		error(E_MALLOC,NOCORE | EXIT);
906 
907 	/* setup poll structures for sac messages and private addresses */
908 	sp = Pollfds;
909 	sp->fd = Pmpipefd;
910 	sp->events = POLLIN;
911 	sp->revents = 0;
912 	sp++;
913 	for (dbp = Dbfhead; dbp && dbp->dbf_svc_code; dbp++) {
914 		if (dbp->dbf_fd >= 0) {
915 			sp->fd = dbp->dbf_fd;
916 			DEBUG((9, "adding %d to poll struct", dbp->dbf_fd));
917 			sp->events = POLLIN;
918 			sp->revents = 0;
919 			sp++;
920 		}
921 	}
922 	errno = t_errno = 0;
923 
924 	for (;;) {
925 		DEBUG((9,"listen(): TOP of loop"));
926 
927 		/* +1 for Pmpipefd */
928 		if (poll(Pollfds, Valid_addrs + 1, -1) < 0) {
929 			if (errno == EINTR)
930 				continue;
931 			/* poll error */
932 			sys_error(E_POLL, EXIT);
933 		}
934 		else {
935 			/* incoming request or message */
936 			for (i = 0, sp = Pollfds; i < Valid_addrs + 1; i++, sp++) {
937 				switch (sp->revents) {
938 				case POLLIN:
939 					if (sp->fd == Pmpipefd) {
940 						DEBUG((9,"sac message received"));
941 						check_sac_mesg();
942 					}
943 					else {
944 						DEBUG((9,"Connection requested "));
945 						phead = ((sp->fd) + Priv_call);
946 						doevent(phead, (sp->fd));
947 						if (State == PM_ENABLED)
948 							trycon(phead, (sp->fd));
949 						else
950 							send_dis(phead, (sp->fd));
951 					}
952 					break;
953 				case 0:
954 					break;
955 				/* distinguish the various errors for the user */
956 				case POLLERR:
957 					logmessage("poll() returned POLLERR");
958 					error(E_SYS_ERROR, EXIT | NO_MSG);
959 				case POLLHUP:
960 					logmessage("poll() returned POLLHUP");
961 					error(E_SYS_ERROR, EXIT | NO_MSG);
962 				case POLLNVAL:
963 					logmessage("poll() returned POLLNVAL");
964 					error(E_SYS_ERROR, EXIT | NO_MSG);
965 				case POLLPRI:
966 					logmessage("poll() returned POLLPRI");
967 					error(E_SYS_ERROR, EXIT | NO_MSG);
968 				case POLLOUT:
969 					logmessage("poll() returned POLLOUT");
970 					error(E_SYS_ERROR, EXIT | NO_MSG);
971 				default:
972 					logmessage("poll() returned unrecognized event");
973 					error(E_SYS_ERROR, EXIT | NO_MSG);
974 				}
975 				sp->revents = 0;
976 			}
977 		}
978 
979 		if (Readdb) {
980 			DEBUG((9,"dbf file has been modified"));
981 			logmessage("Re-reading database");
982 			/* have to close an fd because read_dbf needs it */
983 			close(Acceptfd);
984 			if (!read_dbf(DB_REREAD)) {
985 				/* MUST re-open Acceptfd to insure it is free later */
986 				dup(Passfd);
987 				mod_prvaddr();
988 			}
989 			else {
990 				dup(Passfd);
991 				logmessage(dbfnewdmsg);
992 			}
993 			Readdb = FALSE;
994 		}
995 	}
996 }
997 
998 
999 /*
1000  * check_sac_mesg:	check the pipe to see if SAC has sent a message
1001  */
1002 
1003 void
check_sac_mesg()1004 check_sac_mesg()
1005 {
1006 	int	length;
1007 	struct	sacmsg sacmsg;
1008 
1009 	DEBUG((9, "in check_sac_mesg..."));
1010 
1011 	/* read all messages out of pipe */
1012 	while ((length = read(Pmpipefd, &sacmsg, sizeof(sacmsg))) != 0) {
1013 		if (length < 0) {
1014 			if (errno == EINTR)
1015 				continue;
1016 			DEBUG((9, "read of _pmpipe failed"));
1017 			return;
1018 		}
1019 
1020 		switch (sacmsg.sc_type) {
1021 		case SC_STATUS:
1022 			DEBUG((9, "Got SC_STATUS message"));
1023 			Pmmsg.pm_type = PM_STATUS;
1024 			Pmmsg.pm_state = State;
1025 			break;
1026 		case SC_ENABLE:
1027 			DEBUG((9, "Got SC_ENABLE message"));
1028 			if (State != PM_ENABLED)
1029 				logmessage("New state: ENABLED");
1030 			Pmmsg.pm_type = PM_STATUS;
1031 			State = PM_ENABLED;
1032 			Pmmsg.pm_state = PM_ENABLED;
1033 			break;
1034 		case SC_DISABLE:
1035 			DEBUG((9, "Got SC_DISABLE message"));
1036 			if (State != PM_DISABLED)
1037 				logmessage("New state: DISABLED");
1038 			Pmmsg.pm_type = PM_STATUS;
1039 			State = PM_DISABLED;
1040 			Pmmsg.pm_state = PM_DISABLED;
1041 			break;
1042 		case SC_READDB:
1043 			DEBUG((9, "Got SC_READDB message"));
1044 			Readdb = TRUE;
1045 			Pmmsg.pm_type = PM_STATUS;
1046 			Pmmsg.pm_state = State;
1047 			break;
1048 		default:
1049 			DEBUG((9, "Got UNKNOWN message"));
1050 			Pmmsg.pm_type = PM_UNKNOWN;
1051 			Pmmsg.pm_state = State;
1052 			logmessage("Received unknown message from sac -- ignored");
1053 			break;
1054 		}
1055 		DEBUG((9, "Responding with state %d", Pmmsg.pm_state));
1056 		while (write(Sacpipefd, &Pmmsg, sizeof(Pmmsg)) != sizeof(Pmmsg)) {
1057 			if (errno == EINTR)
1058 				continue;
1059 			DEBUG((9, "sanity response failed"));
1060 			break;
1061 		}
1062 	}
1063 }
1064 
1065 
1066 /*
1067  * doevent:	handle an asynchronous event
1068  */
1069 
1070 static void
doevent(struct call_list * phead,int fd)1071 doevent(struct call_list *phead, int fd)
1072 {
1073 	static struct t_discon *disc;
1074 	struct callsave *current;
1075 	struct t_call *call;
1076 	char scratch[BUFSIZ];
1077 
1078 	DEBUG((9, "in doevent"));
1079 	switch (t_look(fd)) {
1080 	case 0:
1081 		sys_error(E_POLL, EXIT);
1082 		/* no return */
1083 	case T_LISTEN:
1084 	DEBUG((9, "case t_listen "));
1085 		current = dequeue(Free_call_p);
1086 		call = current->c_cp;
1087 		if (t_listen(fd, call) < 0) {
1088 			tli_error(E_T_LISTEN, CONTINUE);
1089 			clr_call(call);
1090 			queue(Free_call_p, current);
1091 			return;
1092 		}
1093 		queue(phead, current);
1094 		DEBUG((9, "incoming call seq # %d", call->sequence));
1095 		break;
1096 	case T_DISCONNECT:
1097 	DEBUG((9, "case t_disconnect"));
1098 		if (disc == NULL) {
1099 			while (!(disc = (struct t_discon *)t_alloc(fd, T_DIS, T_ALL)) ) {
1100 		   		if (t_errno == TBADF)
1101 					DEBUG((9,"listen - fd not transport end point"));
1102 				if ((t_errno != TSYSERR) || (errno != EAGAIN))
1103 					tli_error(E_T_ALLOC, EXIT);
1104 				else
1105 					tli_error(E_T_ALLOC, CONTINUE);
1106 			}
1107 		}
1108 		if (t_rcvdis(fd, disc) < 0) {
1109 			tli_error(E_T_RCVDIS, EXIT);
1110 			/* no return */
1111 		}
1112 		sprintf(scratch, "Disconnect on fd %d, seq # %d", fd, disc->sequence);
1113 		logmessage(scratch);
1114 		DEBUG((9, "incoming disconnect seq # %d", disc->sequence));
1115 		pitchcall(phead, disc);
1116 		break;
1117 	default:
1118 	DEBUG((9, "case default"));
1119 		tli_error(E_T_LOOK, CONTINUE);
1120 		break;
1121 
1122 	}
1123 }
1124 
1125 /*
1126  * send_dis:	send a disconnect
1127  *		called when we are in state PM_DISABLED
1128  */
1129 
1130 static void
send_dis(struct call_list * phead,int fd)1131 send_dis(struct call_list *phead, int fd)
1132 {
1133 	struct t_call *call;
1134 	struct callsave *current;
1135 	char	scratch[BUFSIZ];
1136 
1137 	DEBUG((9, "sending disconnect"));
1138 	while (!EMPTYLIST(phead)) {
1139 		current = dequeue(phead);
1140 		call = current->c_cp;
1141 		if (t_snddis(fd, call) < 0) {
1142 			if (t_errno == TLOOK) {
1143 				DEBUG((9, "collision during snddis"));
1144 				pqueue(phead, current);
1145 				return;
1146 			}
1147 			else
1148 				tli_error(E_T_SNDDIS, CONTINUE);
1149 		}
1150 		sprintf(scratch, "Incoming call while disabled: fd %d, seq %d", fd, call->sequence);
1151 		logmessage(scratch);
1152 		clr_call(call);
1153 		queue(Free_call_p, current);
1154 	}
1155 	return;
1156 }
1157 
1158 
1159 /*
1160  * trycon:	try to accept a connection
1161  */
1162 
1163 static void
trycon(struct call_list * phead,int fd)1164 trycon(struct call_list *phead, int fd)
1165 {
1166 	struct callsave *current;
1167 	struct t_call *call;
1168 	int i;
1169 	pid_t pid;
1170 	dbf_t *dbp;
1171 	char scratch[BUFSIZ];
1172 	extern dbf_t *getentry();
1173 
1174 	DEBUG((9, "in trycon"));
1175 	while (!EMPTYLIST(phead)) {
1176 		current = dequeue(phead);
1177 		call = current->c_cp;
1178 
1179 		if ((dbp = getentry(fd)) == NULL) {
1180 			sprintf(scratch, "No service bound to incoming fd %d: call disconnected", fd);
1181 			logmessage(scratch);
1182 			t_snddis(fd, call);
1183 			clr_call(call);
1184 			queue(Free_call_p, current);
1185 			continue;
1186 		}
1187 
1188 		if (dbp->dbf_flags & DBF_OFF) {
1189 			sprintf(scratch, "Request for service on fd %d denied: disabled", fd);
1190 			logmessage(scratch);
1191 			t_snddis(fd, call);
1192 			clr_call(call);
1193 			queue(Free_call_p, current);
1194 			continue;
1195 		}
1196 
1197 		DEBUG((9, "try to accept #%d", call->sequence));
1198 		SPLhi();
1199 		close(Acceptfd);
1200 		if ((Acceptfd = open_bind(NULL, 0, 0, (unsigned int *) 0, NULL)) != 0) {
1201 			error(E_OPENBIND, CONTINUE);
1202 			clr_call(call);
1203 			queue(Free_call_p, current);
1204 			continue;	/* let transport provider generate disconnect */
1205 		}
1206 		SPLlo();
1207 		if (t_accept(fd, Acceptfd, call) < 0) {
1208 			if (t_errno == TLOOK) {
1209 				t_close(Acceptfd);
1210 				SPLhi();
1211 				if (dup(Passfd) != 0)
1212 					logmessage("Trouble duping fd 0");
1213 				SPLlo();
1214 				logmessage("Incoming call during t_accept -- queueing current call");
1215 				DEBUG((9, "save call #%d", call->sequence));
1216 				pqueue(phead, current);
1217 				return;
1218 			}
1219 			else {
1220 				t_close(Acceptfd);
1221 				SPLhi();
1222 				if (dup(Passfd) != 0)
1223 					logmessage("Trouble duping fd 0");
1224 				SPLlo();
1225 				tli_error(E_T_ACCEPT, CONTINUE);
1226 				clr_call(call);
1227 				queue(Free_call_p, current);
1228 				continue;
1229 			}
1230 		}
1231 
1232 		sprintf(scratch, "Connect: fd %d, svctag %s, seq %d, type %s",
1233 			fd, dbp->dbf_svc_code, call->sequence,
1234 			(dbp->dbf_sflags & PFLAG) ? "passfd" : "exec");
1235 		logmessage(scratch);
1236 
1237 		DEBUG((9, "Accepted call %d", call->sequence));
1238 
1239 		if (dbp->dbf_sflags & PFLAG) {
1240 
1241 			close(Passfd);
1242 
1243 			if (pushmod(Acceptfd, dbp->dbf_modules)) {
1244 				sprintf(scratch, "Could not push modules: %s", dbp->dbf_modules);
1245 				logmessage(scratch);
1246 				goto cleanup;
1247 			}
1248 
1249 			/* doconfig needs a file descriptor, so use Passfd */
1250 			DEBUG((9, "Running doconfig on %s", dbp->dbf_svc_code));
1251 			if ((i = doconfig(Acceptfd, dbp->dbf_svc_code, NOASSIGN|NORUN)) != 0) {
1252 				DEBUG((9, "doconfig exited with code %d", i));
1253 				sprintf(scratch, "doconfig failed on line %d of script %s", i, dbp->dbf_svc_code);
1254 				logmessage(scratch);
1255 				goto cleanup;
1256 			}
1257 
1258 			/* open pipe to pass fd through */
1259 			if ((Passfd = open(dbp->dbf_cmd_line, O_WRONLY)) < 0) {
1260 				/* bad pipe? */
1261 				sprintf(scratch,"Open failed: %s", dbp->dbf_cmd_line);
1262 				logmessage(scratch);
1263 				goto cleanup;
1264 			}
1265 
1266 			if (ioctl(Passfd, I_SENDFD, Acceptfd) < 0) {
1267 				/* clean up call, log error */
1268 				sprintf(scratch,"Passfd failed: %s", dbp->dbf_cmd_line);
1269 				logmessage(scratch);
1270 			}
1271 cleanup:
1272 			/* clean up this call */
1273 			clr_call(call);
1274 			t_close(Acceptfd);
1275 			close(Passfd);
1276 			Acceptfd = open("/dev/null", O_RDWR);
1277 			Passfd = dup(Acceptfd);
1278 			queue(Free_call_p, current);
1279 		}
1280 		else {
1281 			if ((pid = fork()) < 0)
1282 				log(E_FORK_SERVICE);
1283 			else if (!pid) {
1284 				setpgrp();
1285 				/* so log files are correct */
1286 				Pid = getpid();
1287 
1288 				if (senviron(call))  {
1289 					logmessage("Can't expand server's environment");
1290 				}
1291 
1292 				start_server(Acceptfd, dbp);
1293 #ifdef	COREDUMP
1294 				abort();
1295 #endif
1296 				exit(1); /* server failed, don't log */
1297 					/* no return */
1298 			}
1299 			/* only parent gets here */
1300 			clr_call(call);
1301 			t_close(Acceptfd);
1302 			queue(Free_call_p, current);
1303 			SPLhi();
1304 			if (dup(Passfd) != 0)
1305 				logmessage("Trouble duping fd 0");
1306 			SPLlo();
1307 		}
1308 	}
1309 }
1310 
1311 /*
1312  * common code to  start a server process (for any service)
1313  * The first argument in argv is the full pathname of server.
1314  * Before exec-ing the server, the caller's
1315  * logical address, opt and udata are addded to the environment.
1316  */
1317 
1318 static char homeenv[BUFSIZ];
1319 static char pathenv[BUFSIZ];
1320 
1321 int
start_server(netfd,dbp)1322 start_server(netfd, dbp)
1323 int netfd;
1324 dbf_t *dbp;
1325 {
1326 	char	*path;
1327 	char	**argvp;
1328 	extern	char **environ;
1329 	extern	char **mkdbfargv();
1330 	struct passwd *pwdp;
1331 	struct	group *grpp;
1332 	char	msgbuf[256];
1333 	int	i;
1334 
1335 
1336 	argvp = mkdbfargv(dbp);
1337 	path = *argvp;
1338 
1339 	/* set up stdout and stderr before pushing optional modules	*/
1340 	/* this child doesn't need access to _sacpipe and _pmpipe	*/
1341 
1342 	(void) close(Sacpipefd);
1343 	(void) close(Pmpipefd);
1344 
1345 	if (dbp->dbf_flags & DBF_UTMP) {
1346 		pid_t	tmp;
1347 		struct	stat	sbuf;
1348 		char	device[20];
1349 		char	dummy[PMTAGSIZE + 1];
1350 		struct	utmpx utline;
1351 
1352 		/*
1353 		 * create a utmpx entry --
1354 		 * we do an extra fork here to make init this process's
1355 		 * parent.  this lets init clean up the utmpx entry when
1356 		 * this proc dies.
1357 		 *
1358 		 * the utmpx routines need a file descriptor!
1359 		 */
1360 
1361 		DEBUG((9, "Creating a utmpx entry for this service "));
1362 		if ((tmp = fork()) < 0) {
1363 			logmessage("Can't fork to create utmpx entry");
1364 			exit(2);
1365 		}
1366 		if (tmp)
1367 			exit(0);	/* kill parent */
1368 
1369 		/*
1370 		 * child continues processing, creating utmp and exec'ing
1371 		 * the service
1372 		 */
1373 
1374 		setpgrp();
1375 		if (fstat(0, &sbuf) < 0) {
1376 			logmessage("Stat failed on fd 0: no line field "
1377 			    "available for utmpx entry");
1378 			*device = '\0';
1379 		}
1380 		else {
1381 			if (minor(sbuf.st_rdev) < 100)
1382 				sprintf(device, "%.9s%02d", Minor_prefix,
1383 				    minor(sbuf.st_rdev));
1384 			else
1385 				sprintf(device, "%.8s%03d", Minor_prefix,
1386 				    minor(sbuf.st_rdev));
1387 			DEBUG((9, "Device: %s", device));
1388 		}
1389 		/*
1390 		 * prepend a "." so this can be distinguished as a "funny"
1391 		 * utmpx entry that may never get a DEAD_PROCESS entry in
1392 		 * the wtmpx file.
1393 		 */
1394 		sprintf(dummy, ".%s", Mytag);
1395 		/* XXX - utmp - fix login name length */
1396 		strncpy(utline.ut_user, dummy, sizeof (utline.ut_user) - 1);
1397 		sprintf(utline.ut_id, "ls%c%c", SC_WILDC, SC_WILDC);
1398 		strncpy(utline.ut_line, device, sizeof (utline.ut_line) - 1);
1399 		utline.ut_pid = getpid();
1400 		utline.ut_type = USER_PROCESS;
1401 		utline.ut_exit.e_termination = 0;
1402 		utline.ut_exit.e_exit = 0;
1403 		utline.ut_xtime = (time_t) time((time_t *)0);
1404 		makeutx(&utline);
1405 	}
1406 
1407 	if (dup(0) != 1 || dup(0) != 2) {
1408 		logmessage("Dup of fd 0 failed");
1409 		exit(2); /* server, don't log */
1410 	}
1411 
1412 
1413 	if (pushmod(netfd, dbp->dbf_modules)) {
1414 		logmessage("Can't push server's modules: exit");
1415 		exit(2); /* server, don't log */
1416 	}
1417 
1418 	rst_signals();
1419 
1420 	DEBUG((9, "Running doconfig on %s", dbp->dbf_svc_code));
1421 	if ((i = doconfig(Acceptfd, dbp->dbf_svc_code, 0)) != 0) {
1422 		DEBUG((9, "doconfig exited with code %d", i));
1423 		sprintf(msgbuf, "doconfig failed on line %d of script %s", i, dbp->dbf_svc_code);
1424 		logmessage(msgbuf);
1425 		exit(2);
1426 	}
1427 
1428 	if ((pwdp = getpwnam(dbp->dbf_id)) == NULL)  {
1429 		sprintf(msgbuf, "Missing or bad passwd entry for <%s>",dbp->dbf_id);
1430 		logmessage(msgbuf);
1431 		exit(2); /* server, don't log */
1432 	}
1433 
1434 	if (setgid(pwdp->pw_gid)) {
1435 		if ((grpp = getgrgid(pwdp->pw_gid)) == NULL) {
1436 			sprintf(msgbuf, "No group entry for %ld", pwdp->pw_gid);
1437 			logmessage(msgbuf);
1438 			exit(2); /* server, don't log */
1439 		}
1440 		sprintf(msgbuf, "Cannot set group id to %s", grpp->gr_name);
1441 		logmessage(msgbuf);
1442 		exit(2); /* server, don't log */
1443 	}
1444 
1445 	if (setuid(pwdp->pw_uid)) {
1446 		sprintf(msgbuf, "Cannot set user id to %s", dbp->dbf_id);
1447 		logmessage(msgbuf);
1448 		exit(2); /* server, don't log */
1449 	}
1450 
1451 	if (chdir(pwdp->pw_dir)) {
1452                 sprintf(msgbuf, "Cannot chdir to %s", pwdp->pw_dir);
1453                 logmessage(msgbuf);
1454                 exit(2); /* server, don't log */
1455         }
1456 
1457 
1458 	DEBUG((9, "New uid %ld New gid %ld", getuid(), getgid()));
1459 
1460 	sprintf(homeenv, "HOME=%s", pwdp->pw_dir);
1461 	putenv(homeenv);
1462 	if (pwdp->pw_uid)
1463 		sprintf(pathenv, "PATH=/usr/bin:");
1464 	else
1465 		sprintf(pathenv, "PATH=/usr/sbin:/usr/bin");
1466 	putenv(pathenv);
1467 
1468 	endpwent();
1469 
1470 	execve(path, argvp, environ);
1471 
1472 	/* exec returns only on failure!		*/
1473 
1474 	logmessage("ERROR: could not exec server");
1475 	sys_error(E_SYS_ERROR, CONTINUE);
1476 	return(-1);
1477 }
1478 
1479 
1480 /*
1481  * senviron:	Update environment before exec-ing the server:
1482  *		The callers logical address is placed in the
1483  *		environment in hex/ascii character representation.
1484  *
1485  * Note:	no need to free the malloc'ed buffers since this process
1486  *		will either exec or exit.
1487  */
1488 
1489 static char provenv[2*PATHSIZE];
1490 static char prefenv[2*PATHSIZE];
1491 
1492 int
senviron(call)1493 senviron(call)
1494 struct t_call *call;
1495 {
1496 	char *p;
1497 	extern void nlsaddr2c();
1498 	extern char *getenv();
1499 
1500 
1501 /*
1502  * The following code handles the case where the listener was started with
1503  * no environment.  If so, supply a reasonable default path.  Parent already
1504  * set TZ on startup if it wasn't, so don't need to do it here.
1505  */
1506 
1507 	if (getenv("PATH") == NULL)
1508 		putenv("PATH=/usr/sbin:/usr/bin");
1509 
1510 	if ((p = (char *)malloc(((call->addr.len)<<1) + 18)) == NULL)
1511 		return(-1);
1512 	strcpy(p, NLSADDR);
1513 	strcat(p, "=");
1514 	nlsaddr2c(p + strlen(p), call->addr.buf, (int)call->addr.len);
1515 	DEBUG((7, "Adding %s to server's environment", p));
1516 	putenv(p);
1517 
1518 	if ((p = (char *)malloc(((call->opt.len)<<1) + 16)) == NULL)
1519 		return(-1);
1520 	strcpy(p, NLSOPT);
1521 	strcat(p, "=");
1522 	nlsaddr2c(p + strlen(p), call->opt.buf, (int)call->opt.len);
1523 	DEBUG((7, "Adding %s to server's environment", p));
1524 	putenv(p);
1525 
1526 	p = provenv;
1527 	strcpy(p, NLSPROVIDER);
1528 	strcat(p, "=");
1529 	strcat(p, Netspec);
1530 	DEBUG((7, "Adding %s to environment", p));
1531 	putenv(p);
1532 
1533 	/*
1534 	 * MPREFIX is NEW for SVR4.0.  It tells the nlps_server what to use
1535 	 * as a minor device prefix.  THIS SHOULD BE DOCUMENTED!
1536 	 */
1537 	p = prefenv;
1538 	strcpy(p, "MPREFIX");
1539 	strcat(p, "=");
1540 	strcat(p, Minor_prefix);
1541 	DEBUG((7, "Adding %s to environment", p));
1542 	putenv(p);
1543 
1544 	if ((p = (char *)malloc(((call->udata.len)<<1) + 20)) == NULL)
1545 		return(-1);
1546 	strcpy(p, NLSUDATA);
1547 	strcat(p, "=");
1548 	if ((int)call->udata.len >= 0)
1549 		nlsaddr2c(p + strlen(p), call->udata.buf, (int)call->udata.len);
1550 	putenv(p);
1551 	return (0);
1552 }
1553 
1554 
1555 /*
1556  * parse:	Parse TZ= string like init does for consistency
1557  *		Work on string in place since result will
1558  *		either be the same or shorter.
1559  */
1560 
1561 char *
parse(s)1562 parse(s)
1563 char *s;
1564 {
1565 	char *p;
1566 	char *tp;
1567 	char scratch[BUFSIZ];
1568 	int delim;
1569 
1570 	tp = p = s + strlen("TZ=");	/* skip TZ= in parsing */
1571 	if ((*p == '"') || (*p == '\'')) {
1572 		/* it is quoted */
1573 		delim = *p++;
1574 		for (;;) {
1575 			if (*p == '\0') {
1576 				/* etc/default/init ill-formed, go without TZ */
1577 				sprintf(scratch, "%s ill-formed", TZFILE);
1578 				logmessage(scratch);
1579 				strcpy(s, "TZ=");
1580 				return(s);
1581 			}
1582 			if (*p == delim) {
1583 				*tp = '\0';
1584 				return(s);
1585 			}
1586 			else {
1587 				*tp++ = *p++;
1588 			}
1589 		}
1590 	}
1591 	else { /* look for comment or trailing whitespace */
1592 		for ( ; *p && !isspace(*p) && *p != '#'; ++p)
1593 			;
1594 		/* if a comment or trailing whitespace, trash it */
1595 		if (*p) {
1596 			*p = '\0';
1597 		}
1598 		return(s);
1599 	}
1600 }
1601 
1602 
1603 /*
1604  * clr_call:	clear out a call structure
1605  */
1606 
1607 static void
clr_call(struct t_call * call)1608 clr_call(struct t_call *call)
1609 {
1610 	call->sequence = 0;
1611 	call->addr.len = 0;
1612 	call->opt.len = 0;
1613 	call->udata.len = 0;
1614 	memset(call->addr.buf, 0, (int)call->addr.maxlen);
1615 	memset(call->opt.buf, 0, (int)call->opt.maxlen);
1616 	memset(call->udata.buf, 0, (int)call->udata.maxlen);
1617 }
1618 
1619 
1620 /*
1621  * pitchcall: remove call from pending list
1622  */
1623 
1624 static void
pitchcall(struct call_list * pending,struct t_discon * discon)1625 pitchcall(struct call_list *pending, struct t_discon *discon)
1626 {
1627 	struct callsave *p, *oldp;
1628 
1629 	DEBUG((9, "pitching call, sequence # is %d", discon->sequence));
1630 	if (EMPTYLIST(pending)) {
1631 		discon->sequence = -1;
1632 		return;
1633 	}
1634 	p = pending->cl_head;
1635 	oldp = (struct callsave *) NULL;
1636 	while (p) {
1637 		if (p->c_cp->sequence == discon->sequence) {
1638 			if (oldp == (struct callsave *) NULL) {
1639 				pending->cl_head = p->c_np;
1640 				if (pending->cl_head == (struct callsave *) NULL) {
1641 					pending->cl_tail = (struct callsave *) NULL;
1642 				}
1643 			}
1644 			else if (p == pending->cl_tail) {
1645 				oldp->c_np = p->c_np;
1646 				pending->cl_tail = oldp;
1647 			}
1648 			else {
1649 				oldp->c_np = p->c_np;
1650 			}
1651 			clr_call(p->c_cp);
1652 			queue(Free_call_p, p);
1653 			discon->sequence = -1;
1654 			return;
1655 		}
1656 		oldp = p;
1657 		p = p->c_np;
1658 	}
1659 	logmessage("received disconnect with no pending call");
1660 	discon->sequence = -1;
1661 	return;
1662 }
1663 
1664 /*
1665  * add_prvaddr:  open and bind the private address specified in the database
1666  *               entry passed into the routine.  Update the maxcon and fd
1667  *               entries in the database structure
1668  *
1669  *	This routine is very sloppy with malloc'ed memory, but addresses
1670  *	shouldn't ever change enough for this to matter.
1671  */
1672 
1673 int
add_prvaddr(dbp)1674 add_prvaddr(dbp)
1675 dbf_t *dbp;
1676 {
1677 	extern	char	*t_alloc();
1678 	int	j;
1679 	struct	call_list *temp_pend;
1680 	struct	callsave *tmp;
1681 	char	scratch[BUFSIZ];
1682 	int	bindfd;
1683 	extern	struct	netbuf *stoa();
1684 	char	str[NAMEBUFSZ];
1685 	char	*lstr = str;
1686 	struct	netbuf	netbuf;
1687 	int	maxcon;
1688 	char	*ap;
1689 	int	clen;
1690 
1691 	DEBUG((9,"in add_prvaddr, addr %s, svc %s",
1692 		(dbp->dbf_sflags & DFLAG) ? "DYNAMIC" : dbp->dbf_prv_adr,
1693 		dbp->dbf_svc_code));
1694 	netbuf.buf = NULL;
1695 	netbuf.maxlen = 0;
1696 	netbuf.len = 0;
1697 	if (!(dbp->dbf_sflags & DFLAG)) {
1698 		strcpy(lstr, dbp->dbf_prv_adr);
1699 
1700 		/* call stoa - convert from rfs address to netbuf */
1701 
1702 		if (stoa(lstr, &netbuf) == (struct netbuf *)NULL)  {
1703 			DEBUG((9,"stoa returned null, errno = %d\n",errno));
1704 			error(1, E_MALLOC);
1705 			return(-1);
1706 		}
1707 		clen = netbuf.len;
1708 	}
1709 	else {
1710 		clen = -1;
1711 	}
1712 	if ((bindfd = open_bind(netbuf.buf, MAXCON, clen, &maxcon, &ap)) < 0) {
1713 		switch (bindfd) {
1714 		case -1:
1715 			return(-1);
1716 			break;
1717 		case -2:
1718 			sprintf(scratch, "  Service %s ignored: out of file descriptors", dbp->dbf_svc_code);
1719 			logmessage(scratch);
1720 			return(-1);
1721 			break;
1722 		case -3:
1723 			sprintf(scratch, "  Service %s ignored: unable to bind requested address", dbp->dbf_svc_code);
1724 			logmessage(scratch);
1725 			return(-1);
1726 			break;
1727 		default:
1728 			error(E_OPENBIND, EXIT);
1729 		}
1730 	}
1731 	if (clen == -1) {
1732 		sprintf(scratch,"Service %s: fd %d dynamic addr %s", dbp->dbf_svc_code, bindfd, ap);
1733 		dbp->dbf_prv_adr = ap;
1734 	}
1735 	else {
1736 		sprintf(scratch,"Service %s: fd %d addr %s", dbp->dbf_svc_code, bindfd, dbp->dbf_prv_adr);
1737 	}
1738 	logmessage(scratch);
1739 	rpc_register(dbp);
1740 	temp_pend = Priv_call + bindfd;
1741 	dbp->dbf_fd = bindfd;
1742 	dbp->dbf_maxcon = maxcon;
1743 	temp_pend->cl_head = (struct callsave *) NULL;
1744 	temp_pend->cl_tail = (struct callsave *) NULL;
1745 	for (j=0; j < maxcon; ++j)  {
1746 		if ((tmp = (struct callsave *) malloc(sizeof(struct callsave))) == NULL)  {
1747 			error (E_MALLOC, NOCORE | EXIT);
1748 		}
1749 		if ((tmp->c_cp = (struct t_call *) t_alloc(bindfd, T_CALL,
1750 				T_ALL)) == NULL) {
1751 			tli_error(E_T_ALLOC,EXIT);
1752 		}
1753 		queue(Free_call_p, tmp);
1754 	}
1755 	return(0);
1756 }
1757 
1758 /*
1759  * mod_prvaddr -- after re-reading the database, take appropriate action for
1760  *		  new, deleted, or changed addresses.
1761  */
1762 static void
mod_prvaddr(void)1763 mod_prvaddr(void)
1764 {
1765 	dbf_t	*entry_p;
1766 	dbf_t	*oldentry_p;
1767 	char	scratch[BUFSIZ];
1768 	dbf_t	*svc_code_match();
1769 	int	bound;
1770 	struct	pollfd	*sp;
1771 
1772 	DEBUG((9, "in mod_prvaddr..."));
1773 	/*
1774 	 * for each entry in the new table, check for a svc code match.
1775 	 * if there is a svc code match and the address matches, all we
1776 	 * need to do is update the new table.  if the addresses are
1777 	 * different, we need to remove the old one and replace it.
1778 	 */
1779 	for (entry_p = Newdbf; entry_p && entry_p->dbf_svc_code; entry_p++) {
1780 		if ((oldentry_p = svc_code_match(entry_p->dbf_svc_code)) != NULL) {
1781 			/* matched svc code.  see if address matches. */
1782 			DEBUG((9, "MATCHED service code"));
1783 			if ((strcmp(oldentry_p->dbf_prv_adr, entry_p->dbf_prv_adr) == 0) || ((oldentry_p->dbf_sflags & DFLAG) && (entry_p->dbf_sflags & DFLAG))) {
1784 				DEBUG((9, "SAME addresses, old %s, new %s",
1785 				oldentry_p->dbf_prv_adr, entry_p->dbf_prv_adr));
1786 				/* update new table with fd, set old fd to -1 */
1787 				DEBUG((9, "Old fd %d",  oldentry_p->dbf_fd));
1788 				entry_p->dbf_fd = oldentry_p->dbf_fd;
1789 				entry_p->dbf_maxcon = oldentry_p->dbf_maxcon;
1790 				oldentry_p->dbf_fd = -1;
1791 				if ((oldentry_p->dbf_sflags & DFLAG) && (entry_p->dbf_sflags & DFLAG)) {
1792 					entry_p->dbf_prv_adr = oldentry_p->dbf_prv_adr;
1793 				}
1794 				if (entry_p->dbf_fd != -1) {
1795 					sprintf(scratch, "Service %s: fd %d addr %s",
1796 						entry_p->dbf_svc_code, entry_p->dbf_fd,
1797 						entry_p->dbf_prv_adr);
1798 					logmessage(scratch);
1799 				}
1800 				if ((oldentry_p->dbf_version != entry_p->dbf_version) || (oldentry_p->dbf_prognum != entry_p->dbf_prognum)) {
1801 					rpc_unregister(oldentry_p);
1802 					rpc_register(entry_p);
1803 				}
1804 			}
1805 		}
1806 	}
1807 
1808 	/* now unbind the remaining addresses in the old table (fd != -1) */
1809 
1810 	for (oldentry_p = Dbfhead; oldentry_p && oldentry_p->dbf_svc_code; oldentry_p++) {
1811 		if (oldentry_p->dbf_fd != -1) {
1812 			DEBUG((9, "deleting %s",  oldentry_p->dbf_svc_code));
1813 			if (del_prvaddr(oldentry_p) == 0)
1814 				Valid_addrs--;
1815 		}
1816 	}
1817 
1818 	/* now bind all of the new addresses (fd == -1) */
1819 	/*
1820 	 * this tries to bind any addresses that failed to bind successfully
1821 	 * when the address changed.  This means that if a service is moved to
1822 	 * an address that is being deleted, the first attempt to bind it will
1823 	 * fail, the old address will be removed, and this bind will succeed
1824 	 */
1825 
1826 	/* first the static addrs */
1827 	for (entry_p = Newdbf; entry_p && entry_p->dbf_svc_code; entry_p++) {
1828 		if ((entry_p->dbf_fd == -1) && (!(entry_p->dbf_sflags & DFLAG))) {
1829 			DEBUG((9, "adding %s",  entry_p->dbf_svc_code));
1830 			if (add_prvaddr(entry_p) == 0)
1831 				Valid_addrs++;
1832 		}
1833 	}
1834 	/* then the dynamic addrs */
1835 	for (entry_p = Newdbf; entry_p && entry_p->dbf_svc_code; entry_p++) {
1836 		if ((entry_p->dbf_fd == -1) && (entry_p->dbf_sflags & DFLAG)) {
1837 			DEBUG((9, "adding %s",  entry_p->dbf_svc_code));
1838 			if (add_prvaddr(entry_p) == 0)
1839 				Valid_addrs++;
1840 		}
1841 	}
1842 
1843 	/* free old database, set up new pollfd table, and we're done */
1844 
1845 	free(Dbfhead);
1846 	free(Server_cmd_lines);
1847 	Dbfhead = Newdbf;
1848 	Newdbf = NULL;
1849 	Server_cmd_lines = New_cmd_lines;
1850 	sprintf(scratch, "Re-read complete, %d %s bound, %d fds free", Valid_addrs,
1851 		(Valid_addrs == 1) ? "address" : "addresses",
1852 		Ndesc-Valid_addrs-USEDFDS);
1853 	logmessage(scratch);
1854 
1855 	/* Pollfds[0] is for _pmpipe */
1856 	sp = &Pollfds[1];
1857 	for (entry_p = Dbfhead; entry_p && entry_p->dbf_svc_code; entry_p++) {
1858 		if (entry_p->dbf_fd >= 0) {
1859 			sp->fd = entry_p->dbf_fd;
1860 			DEBUG((9, "adding %d to poll struct", entry_p->dbf_fd));
1861 			sp->events = POLLIN;
1862 			sp->revents = 0;
1863 			sp++;
1864 		}
1865 	}
1866 }
1867 
1868 /*
1869  * unbind the address, close the file descriptor, and free call structs
1870  */
1871 
1872 int
del_prvaddr(dbp)1873 del_prvaddr(dbp)
1874 dbf_t	*dbp;
1875 {
1876 	struct	callsave	*tmp;
1877 	struct	call_list	*q;
1878 	struct	t_call		*call;
1879 	int	i;
1880 	char	scratch[BUFSIZ];
1881 
1882 	DEBUG((9, "in del_prvaddr..."));
1883 	rpc_unregister(dbp);
1884 	if (dbp->dbf_fd < 0)
1885 		return -1;
1886 
1887 	q = Priv_call + dbp->dbf_fd;
1888 	i = 0;
1889 
1890 	/* delete pending calls */
1891 	while ((tmp = dequeue(q)) != NULL) {
1892 		i++;
1893 		call = tmp->c_cp;
1894 		t_snddis(dbp->dbf_fd, call);
1895 		t_free((char *)call, T_CALL);
1896 		free(tmp);
1897 	}
1898 
1899 	/* delete free call structs we don't need */
1900 	for ( ; i < dbp->dbf_maxcon; i++) {
1901 		tmp = dequeue(Free_call_p);
1902 		t_free((char *)tmp->c_cp, T_CALL);
1903 		free(tmp);
1904 	}
1905 
1906 	t_unbind(dbp->dbf_fd);
1907 	t_close(dbp->dbf_fd);
1908 	sprintf(scratch, "Unbind %s: fd %d addr %s", dbp->dbf_svc_code,
1909 		dbp->dbf_fd, dbp->dbf_prv_adr);
1910 	logmessage(scratch);
1911 	dbp->dbf_fd = -1;
1912 	return 0;
1913 }
1914 
1915 
1916 /*
1917  * look through the old database file to see if this service code matches
1918  * one already present
1919  */
1920 
1921 dbf_t *
svc_code_match(new_code)1922 svc_code_match(new_code)
1923 char	*new_code;
1924 {
1925 	dbf_t	*dbp;
1926 
1927 	for (dbp = Dbfhead; dbp && dbp->dbf_svc_code; dbp++) {
1928 		if (strcmp(dbp->dbf_svc_code, new_code) == 0)
1929 			return(dbp);
1930 	}
1931 	return((dbf_t *)NULL);
1932 }
1933 
1934 
1935 /*
1936  * register an rpc service with rpcbind
1937  */
1938 
1939 void
rpc_register(dbp)1940 rpc_register(dbp)
1941 dbf_t *dbp;
1942 {
1943 	char	str[NAMEBUFSZ];
1944 	char	scratch[BUFSIZ];
1945 	char	*lstr = str;
1946 	struct	netbuf	netbuf;
1947 	extern	struct	netbuf *stoa();
1948 	extern	int	errno;
1949 
1950 	DEBUG((9, "in rpc_register"));
1951 	if (dbp->dbf_prognum == -1 || dbp->dbf_version == -1)
1952 		/* not an rpc service */
1953 		return;
1954 
1955 	rpc_unregister(dbp);
1956 	netbuf.buf = NULL;
1957 	netbuf.maxlen = 0;
1958 	netbuf.len = 0;
1959 	strcpy(lstr, dbp->dbf_prv_adr);
1960 	if (stoa(lstr, &netbuf) == (struct netbuf *)NULL)  {
1961 		DEBUG((9,"stoa returned null, errno = %d\n",errno));
1962 		error(1, E_MALLOC);
1963 		return;
1964 	}
1965 	if (rpcb_set(dbp->dbf_prognum, dbp->dbf_version, Netconf, &netbuf)) {
1966 		sprintf(scratch,"  registered with rpcbind, prognum %d version %d", dbp->dbf_prognum, dbp->dbf_version);
1967 		logmessage(scratch);
1968 	}
1969 	else {
1970 		logmessage("rpcb_set failed, service not registered with rpcbind");
1971 	}
1972 	return;
1973 }
1974 
1975 
1976 /*
1977  * unregister an rpc service with rpcbind
1978  */
1979 
1980 void
rpc_unregister(dbp)1981 rpc_unregister(dbp)
1982 dbf_t *dbp;
1983 {
1984 	DEBUG((9, "in rpc_unregister"));
1985 	if (dbp->dbf_prognum == -1 || dbp->dbf_version == -1)
1986 		/* not an rpc service */
1987 		return;
1988 	(void) rpcb_unset(dbp->dbf_prognum, dbp->dbf_version, Netconf);
1989 }
1990