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