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