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