xref: /illumos-gate/usr/src/cmd/listen/listen.c (revision 25b601ca)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2014 Garrett D'Amore
25  */
26 /*
27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
32 /*	  All Rights Reserved  	*/
33 
34 /*
35  * Network Listener Process
36  *
37  *		command line:
38  *
39  *		listen [ -m minor_prefix ] netspec
40  *
41  */
42 
43 /* system include files	*/
44 
45 #include <fcntl.h>
46 #include <signal.h>
47 #include <stdio.h>
48 #include <unistd.h>
49 #include <string.h>
50 #include <errno.h>
51 #include <memory.h>
52 #include <sys/utsname.h>
53 #include <sys/tiuser.h>
54 #include <sys/param.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <sys/mkdev.h>
58 #include <values.h>
59 #include <ctype.h>
60 #include <pwd.h>
61 #include <grp.h>
62 #include <sys/ipc.h>
63 #include <sys/poll.h>
64 #include <sys/stropts.h>
65 #include <sac.h>
66 #include <utmpx.h>
67 
68 /* listener include files */
69 
70 #include "lsparam.h"		/* listener parameters		*/
71 #include "lsfiles.h"		/* listener files info		*/
72 #include "lserror.h"		/* listener error codes		*/
73 #include "lsnlsmsg.h"		/* NLPS listener protocol	*/
74 #include "lssmbmsg.h"		/* MS_NET identifier		*/
75 #include "lsdbf.h"		/* data base file stuff		*/
76 #include "listen.h"
77 
78 /* defines	*/
79 
80 #define NAMESIZE	(NAMEBUFSZ-1)
81 
82 #define SPLhi()		Splflag = 1
83 #define SPLlo()		Splflag = 0
84 
85 #define GEN	1
86 #define LOGIN	0
87 
88 /* global variables	*/
89 
90 int	NLPS_proc = 0;	/* set if process is a listener child		*/
91 pid_t	Pid;		/* listener's process ID 			*/
92 char	*Progname;	/* listener's basename (from argv[0])		*/
93 static	char Provbuf[PATHSIZE];
94 char	*Provider = Provbuf;	/* name of transport provider		*/
95 char	*Netspec = NETSPEC;
96 char	*Minor_prefix;		/* prefix for minor device names	*/
97 int	Dbf_entries;		/* number of private addresses in dbf file*/
98 int	Valid_addrs;		/* number of addresses bound		*/
99 struct	pollfd *Pollfds;	/* for polling fds			*/
100 dbf_t	*Dbfhead;		/* Beginning of in-memory database	*/
101 dbf_t	*Newdbf;		/* Beginning of in-memory database (reread) */
102 char	*Server_cmd_lines;	/* database space			*/
103 char	*New_cmd_lines;		/* database space (reread) 		*/
104 long	Ndesc;			/* Number of per-process file descriptors */
105 int	Readdb;			/* set to TRUE by SAC_READDB message	*/
106 struct	netconfig *Netconf;	/* netconfig structure for this network	*/
107 
108 struct	call_list	Free_call;
109 struct	call_list	*Free_call_p = &Free_call; /* call free list 	*/
110 struct	call_list	*Priv_call;	/* call save pending list 	*/
111 
112 /* FILE DESCRIPTOR MANAGEMENT:
113  *
114  * The listener uses 6 (sometimes 7) file descriptors:
115  *	fd 0:	Originally opened to /dev/null, used to accept incoming calls.
116  *	fd 1:	In the parent, a connection to _sacpipe.  Closed in the child
117  *		and dup'ed to 0.
118  *	fd 2:	In the parent, a connection to _pmpipe.  Dup'ed in the child
119  *		to 0.
120  *	fd 3:	Originally opened to /dev/null, this file descriptor is
121  *		reserved to open the STREAMS pipe when passing the connection
122  *		to a standing server.
123  *	fd 4:	Opened to the pid file.  We have to keep it open to keep the
124  *		lock active.
125  *	fd 5:	Opened to the log file.
126  *	fd 6:	Opened to the debug file ONLY when compiled with DEBUGMODE.
127  *
128  * The remaining file descriptors are available for binding private addresses.
129  */
130 
131 #ifndef DEBUGMODE
132 #define USEDFDS	6
133 #else
134 #define	USEDFDS	7
135 FILE	*Debugfp;		/* for the debugging file	*/
136 #endif
137 
138 int	Acceptfd;		/* to accept connections (fd 0)	*/
139 int	Sacpipefd;		/* pipe TO sac process (fd 1)	*/
140 int	Pmpipefd;		/* pipe FROM sac process (fd 2) */
141 int	Passfd;			/* pipe used to pass FD (fd 3)	*/
142 int	Pidfd;			/* locked pid file (fd 4)	*/
143 FILE	*Logfp;			/* for logging listener activity*/
144 
145 struct	pmmsg	Pmmsg;		/* to respond to SAC		*/
146 int	State = PM_STARTING;	/* current SAC state		*/
147 char	Mytag[15];
148 
149 char	Lastmsg[BUFSIZ];	/* contains last msg logged (by stampbuf) */
150 int	Logmax = LOGMAX;	/* number of entriet to allow in logfile  */
151 
152 int	Splflag;		/* logfile critical region flag		  */
153 
154 static char *badnspmsg = "Bad netspec on command line ( Pathname too long )";
155 static char *badstart  = "Listener failed to start properly";
156 static char *nologfile = "Unable to open listener log file during initialization";
157 static char *usage     = "Usage: listen [ -m minor_prefix ] network_device";
158 static char *nopmtag   = "Fatal error: Unable to get PMTAG from environment";
159 static char tzenv[BUFSIZ];
160 
161 #define TZFILE	"/etc/default/init"
162 #define TZSTR	"TZ="
163 
164 void	check_sac_mesg();	/* routine to process messages from sac */
165 void	rpc_register();		/* routine to register rpc services */
166 void	rpc_unregister();	/* routine to unregister rpc services */
167 extern	struct	netconfig	*getnetconfigent();
168 extern	char	*t_alloc();
169 extern	void	logexit();
170 extern	int	t_errno;
171 extern	int	errno;
172 
173 #ifndef TRUE
174 #define	TRUE	1
175 #define FALSE	0
176 #endif
177 
178 static void mod_prvaddr(void);
179 static void pitchcall(struct call_list *pending, struct t_discon *discon);
180 static void clr_call(struct t_call *call);
181 static void trycon(struct call_list *phead, int fd);
182 static void send_dis(struct call_list *phead, int fd);
183 static void doevent(struct call_list *phead, int fd);
184 static void listen(void);
185 static void rst_signals(void);
186 static void catch_signals(void);
187 static void net_open(void);
188 static void init_files(void);
189 static void pid_open(void);
190 
191 int
main(int argc,char ** argv)192 main(int argc, char **argv)
193 {
194 	struct stat buf;
195 	int ret;
196 	char scratch[BUFSIZ];
197 	char log[BUFSIZ];
198 	char olog[BUFSIZ];
199 	char *scratch_p = scratch;
200 	char *mytag_p;
201 	FILE *fp;
202 	extern char *getenv();
203 	char *parse();
204 	int	c;
205 	extern	char *optarg;
206 	extern	int optind;
207 	int i;
208 	char	*Mytag_p = Mytag;
209 
210 	/* Get my port monitor tag out of the environment		*/
211 	if ((mytag_p = getenv("PMTAG")) == NULL) {
212 		/* no place to write */
213 		exit(1);
214 	}
215 	strcpy(Mytag, mytag_p);
216 
217 	/* open log file */
218 	sprintf(log, "%s/%s/%s", ALTDIR, Mytag_p, LOGNAME);
219 	sprintf(olog, "%s/%s/%s", ALTDIR, Mytag_p, OLOGNAME);
220 	if (stat(log, &buf) == 0) {
221 		/* file exists, try and save it but if we can't don't worry */
222 		unlink(olog);
223 		rename(log, olog);
224 	}
225 	if ((i = open(log, O_WRONLY|O_CREAT|O_APPEND, 0444)) < 0)
226 		logexit(1, nologfile);
227 	/* as stated above, the log file should be file descriptor 5 */
228 	if ((ret = fcntl(i, F_DUPFD, 5)) != 5)
229 		logexit(1, nologfile);
230 	Logfp = fdopen(ret, "a+");
231 
232 	/* Get my port monitor tag out of the environment		*/
233 	if ((mytag_p = getenv("PMTAG")) == NULL) {
234 		logexit(1, nopmtag);
235 	}
236 	strcpy(Mytag, mytag_p);
237 
238 	(void) umask(022);
239 	Readdb = FALSE;
240 
241 	if (geteuid() != (uid_t) 0) {
242 		logmessage("Must be root to start listener");
243 		logexit(1, badstart);
244 	}
245 
246 	while ((c = getopt(argc, argv, "m:")) != EOF)
247 		switch (c) {
248 		case 'm':
249 			Minor_prefix = optarg;
250 			break;
251 		default:
252 			logexit(1, usage);
253 			break;
254 		}
255 
256 	if ((Netspec = argv[optind]) == NULL) {
257 		logexit(1, usage);
258 	}
259 	if ((Netconf = getnetconfigent(Netspec)) == NULL) {
260 		sprintf(scratch, "no netconfig entry for <%s>", Netspec);
261 		logmessage(scratch);
262 		logexit(1, badstart);
263 	}
264 	if (!Minor_prefix)
265 		Minor_prefix = argv[optind];
266 
267 	if ((int) strlen(Netspec) > PATHSIZE)  {
268 		logmessage(badnspmsg);
269 		logexit(1, badstart);
270 	}
271 
272 	/*
273 	 * SAC will start the listener in the correct directory, so we
274 	 * don't need to chdir there, as we did in older versions
275 	 */
276 
277 	strcpy(Provbuf, "/dev/");
278 	strcat(Provbuf, Netspec);
279 
280 	(void) umask(0);
281 
282 	init_files();		/* open Accept, Sac, Pm, Pass files	*/
283 	pid_open();		/* create pid file			*/
284 
285 #ifdef	DEBUGMODE
286 	sprintf(scratch, "%s/%s/%s", ALTDIR, Mytag, DBGNAME);
287 	Debugfp = fopen(scratch, "w");
288 #endif
289 
290 
291 #ifdef	DEBUGMODE
292 	if ((!Logfp) || (!Debugfp))
293 #else
294 	if (!Logfp)
295 #endif
296 		logexit(1, badstart);
297 
298 /*
299  * In case we started with no environment, find out what timezone we're
300  * in.  This will get passed to children, so only need to do once.
301  */
302 
303 	if (getenv("TZ") == NULL) {
304 		fp = fopen(TZFILE, "r");
305 		if (fp) {
306 			while (fgets(tzenv, BUFSIZ, fp)) {
307 				if (tzenv[strlen(tzenv) - 1] == '\n')
308 					tzenv[strlen(tzenv) - 1] = '\0';
309 				if (!strncmp(TZSTR, tzenv, strlen(TZSTR))) {
310 					putenv(parse(tzenv));
311 					break;
312 				}
313 			}
314 			fclose(fp);
315 		}
316 		else {
317 			sprintf(scratch, "couldn't open %s, default to GMT",
318 			    TZFILE);
319 			logmessage(scratch);
320 		}
321 	}
322 
323 	logmessage("@(#)listen:listen.c	1.19.9.1");
324 
325 #ifdef	DEBUGMODE
326 	logmessage("Listener process with DEBUG capability");
327 #endif
328 
329 	sprintf(scratch, "Listener port monitor tag: %s", Mytag_p);
330 	logmessage(scratch);
331 	DEBUG((9, "Minor prefix: %s  Netspec %s", Minor_prefix, Netspec));
332 
333 	/* fill in Pmmesg fields that always stay the same */
334 
335 	Pmmsg.pm_maxclass = MAXCLASS;
336 	strcpy(Pmmsg.pm_tag, Mytag_p);
337 	Pmmsg.pm_size = 0;
338 
339 	/* Find out what state to start in.  If not in env, exit */
340 	if ((scratch_p = getenv("ISTATE")) == NULL)
341 		logexit(1, "ERROR: ISTATE variable not set in environment");
342 
343 	if (!strcmp(scratch_p, "enabled")) {
344 		State = PM_ENABLED;
345 		logmessage("Starting state: ENABLED");
346 	}
347 	else {
348 		State = PM_DISABLED;
349 		logmessage("Starting state: DISABLED");
350 	}
351 
352 	/* try to get my "basename"		*/
353 	Progname = strrchr(argv[0], '/');
354 	if (Progname && Progname[1])
355 		++Progname;
356 	else
357 		Progname = argv[0];
358 
359 	catch_signals();
360 
361 	/*
362 	 * Allocate memory for private address and file descriptor table
363 	 * Here we are assuming that no matter how many private addresses
364 	 * exist in the system if the system limit is 20 then we will only
365 	 * get 20 file descriptors
366 	 */
367 
368 	Ndesc = ulimit(4,0L);		/* get num of file des on system */
369 
370 	read_dbf(DB_INIT);
371 	net_open();			/* init, open, bind names 	*/
372 
373 	for (i = 3; i < Ndesc; i++)  {	/* leave stdout, stderr open	*/
374 		fcntl(i, F_SETFD, 1);	/* set close on exec flag*/
375 	}
376 
377 	logmessage("Initialization Complete");
378 
379 	listen();
380 	return (0);
381 }
382 
383 
384 /*
385  * pid_open:
386  *
387  * open pidfile with specified oflags and modes and lock it
388  *
389  */
390 
391 static char *pidopenmsg ="Can't create process ID file in home directory";
392 static char *pidlockmsg ="Can't lock PID file: listener may already be running";
393 
394 static void
pid_open(void)395 pid_open(void)
396 {
397 	int ret;
398 	unsigned int i;
399 	char pidstring[20];
400 
401 	if ((Pidfd = open(PIDNAME, PIDOFLAG, PIDMODE)) == -1)  {
402 		logmessage(pidopenmsg);
403 		error(E_CREAT, EXIT | NOCORE | NO_MSG);
404 	}
405 
406 	if (lockf(Pidfd, 2, 0L) == -1)  {
407 		logmessage(pidlockmsg);
408 		logexit(1, badstart);
409 	}
410 
411 	Pid = getpid();
412 	i = sprintf(pidstring, "%ld", Pid) + 1;
413 	ftruncate(Pidfd, 0);
414 
415 	while ((ret = write(Pidfd, pidstring, i)) != i) {
416 		if (errno == EINTR)
417 			continue;
418 		if (ret < 0)
419 			sys_error(E_PIDWRITE, EXIT);
420 		else
421 			error(E_PIDWRITE, EXIT);
422 	}
423 
424 }
425 
426 /*
427  * init_files: open initial files for the listener (see FILE DESC MGMT comment)
428  */
429 
430 static char *pmopenmsg = "Can't open pipe to read SAC messages";
431 static char *sacopenmsg = "Can't open pipe to respond to SAC messages";
432 
433 static void
init_files(void)434 init_files(void)
435 {
436 	close(0);
437         if ((Acceptfd = open("/dev/null", O_RDWR)) != 0) {
438 		logmessage("Trouble opening /dev/null");
439                 sys_error(E_SYS_ERROR, EXIT | NOCORE);
440 	}
441 
442 	close(1);
443 	if ((Sacpipefd = open(SACPIPE, O_RDWR|O_NDELAY)) != 1) {
444 		logmessage(sacopenmsg);
445 		error(E_CREAT, EXIT | NOCORE | NO_MSG);
446 	}
447 
448 	close(2);
449 	if ((Pmpipefd = open(PMPIPE, O_RDWR|O_NDELAY)) != 2) {
450 		logmessage(pmopenmsg);
451 		error(E_CREAT, EXIT | NOCORE | NO_MSG);
452 	}
453 
454 	close(3);
455 	if ((Passfd = dup(Acceptfd)) != 3) {
456 		logmessage("Trouble duping /dev/null");
457                 sys_error(E_SYS_ERROR, EXIT | NOCORE);
458 	}
459 
460 }
461 
462 
463 /*
464  * net_open: open and bind communications channels
465  *		The name generation code in net_open, open_bind and bind is,
466  * 		for the	most part, specific to STARLAN NETWORK.
467  *		This name generation code is included in the listener
468  *		as a developer debugging aid.
469  */
470 
471 static void
net_open(void)472 net_open(void)
473 {
474 #ifdef	CHARADDR
475 	char pbuf[NAMEBUFSZ + 1];
476 #endif	/* CHARADDR	*/
477 	int i;
478 	dbf_t *dp;
479 	char scratch[BUFSIZ];
480 
481 	DEBUG((9,"in net_open"));
482 
483 	/* set up free call list and pending connection lists */
484 
485 	Free_call_p->cl_head = (struct callsave *) NULL;
486 	Free_call_p->cl_tail = (struct callsave *) NULL;
487 
488 	/* Pending calls are linked in a structure, one per fild descriptor */
489 	if ((Priv_call = (struct call_list *) malloc(Ndesc *(sizeof(
490 				struct call_list)))) == NULL)
491 		error(E_MALLOC,NOCORE | EXIT);
492 
493 	i = 0;
494 	Valid_addrs = 0;
495 	/* first do static addrs */
496 	while ( (i < Dbf_entries) ) {
497 		dp = &Dbfhead[i];
498 		if (!(dp->dbf_sflags & DFLAG)) {
499 			if (add_prvaddr(dp) == 0)
500 				Valid_addrs++;
501 		}
502 		i++;
503 	}
504 	i = 0;
505 	/* second pass for dynamic addrs */
506 	while ( (i < Dbf_entries) ) {
507 		dp = &Dbfhead[i];
508 		if (dp->dbf_sflags & DFLAG) {
509 			if (add_prvaddr(dp) == 0)
510 				Valid_addrs++;
511 		}
512 		i++;
513 	}
514 
515 	sprintf(scratch, "Net opened, %d %s bound, %d fds free", Valid_addrs,
516 		(Valid_addrs == 1) ? "address" : "addresses",
517 		Ndesc-Valid_addrs-USEDFDS);
518 	logmessage(scratch);
519 }
520 
521 
522 /*
523  * Following are some general queueing routines.  The call list head contains
524  * a pointer to the head of the queue and to the tail of the queue.  Normally,
525  * calls are added to the tail and removed from the head to ensure they are
526  * processed in the order received, however, because of the possible interruption
527  * of an acceptance with the resulting requeueing, it is necessary to have a
528  * way to do a "priority queueing" which inserts at the head of the queue for
529  * immediate processing
530  */
531 
532 /*
533  * queue:
534  *
535  * add calls to tail of queue
536  */
537 
538 
539 void
queue(head,cp)540 queue(head, cp)
541 struct call_list *head;
542 struct callsave *cp;
543 {
544 	DEBUG((9,"in queue"));
545 	if (head->cl_tail == (struct callsave *) NULL) {
546 		cp->c_np = (struct callsave *) NULL;
547 		head->cl_head = head->cl_tail = cp;
548 	}
549 	else {
550 		cp->c_np = head->cl_tail->c_np;
551 		head->cl_tail->c_np = cp;
552 		head->cl_tail = cp;
553 	}
554 }
555 
556 
557 /*
558  * pqueue:
559  *
560  * priority queuer, add calls to head of queue
561  */
562 
563 void
pqueue(head,cp)564 pqueue(head, cp)
565 struct call_list *head;
566 struct callsave *cp;
567 {
568 	if (head->cl_head == (struct callsave *) NULL) {
569 		cp->c_np = (struct callsave *) NULL;
570 		head->cl_head = head->cl_tail = cp;
571 	}
572 	else {
573 		cp->c_np = head->cl_head;
574 		head->cl_head = cp;
575 	}
576 }
577 
578 
579 /*
580  * dequeue:
581  *
582  * remove a call from the head of queue
583  */
584 
585 
586 struct callsave *
dequeue(head)587 dequeue(head)
588 struct call_list *head;
589 {
590 	struct callsave *ret;
591 
592 	DEBUG((9,"in dequeue"));
593 	if (head->cl_head == (struct callsave *) NULL)  {
594 #ifdef OLD
595 		DEBUG((9,"cl_head = null"));
596 		error(E_CANT_HAPPEN, EXIT);
597 #endif
598 		DEBUG((9, "NULL return"));
599 		return((struct callsave *) NULL);
600 	}
601 	ret = head->cl_head;
602 	head->cl_head = ret->c_np;
603 	if (head->cl_head == (struct callsave *) NULL)
604 		head->cl_tail = (struct callsave *) NULL;
605 	return(ret);
606 }
607 
608 
609 /*
610  * open_bind:
611  *
612  * open the network and bind the endpoint to 'name'
613  * this routine is also used by listen(), so it can't exit
614  * under all error conditions:
615  *	if there are no minor devices avaliable in the network driver,
616  * 		open_bind returns -1.  (error message will be logged).
617  *	if the open fails because all file descriptors are in use,
618  *		open_bind returns -2.  (no message logged).  This should
619  *		only happen when too many private addresses are specified.
620  *	if the bind fails, open_bind returns -3  (no message logged).  This
621  *		happens when a duplicate address is bound, and the message
622  *		should be logged by the routine that calls open_bind.
623  * All other errors cause an exit.
624  *
625  * If clen is zero, transport provider picks the name and these
626  * routines (open_bind and bind) ignore name and qlen --
627  * this option is used when binding a name for accepting a connection
628  * (not for listening.)  You MUST supply a name, qlen and clen when
629  * opening/binding a name for listening.
630  *
631  * Assumptions: driver returns ENXIO when all devices are allocated.
632  */
633 
634 int
open_bind(name,qlen,clen,conp,adrp)635 open_bind(name, qlen, clen, conp, adrp)
636 char *name;
637 int qlen;
638 int clen;
639 unsigned int *conp;
640 char **adrp;
641 {
642 	int fd;
643 	int ret;
644 
645 	DEBUG((9,"in open_bind, qlen=%d clen=%d conp=%d",qlen,clen,conp));
646 	while ((fd = t_open(Provider, NETOFLAG, NULL)) < 0) {
647 		if (t_errno == TSYSERR) {
648 			switch (errno) {
649 			case EINTR:
650 				continue;
651 			case EMFILE:
652 				return(-2);
653 				break;
654 			case ENXIO:
655 			case ENOSR:
656 			case ENOSPC:
657 			case EAGAIN:
658 				tli_error(E_FD1OPEN, CONTINUE);
659 				logmessage("No network minor devices (ENXIO/ENOSR)");
660 				return(-1);
661 				break;
662 			}
663 			DEBUG((9,"problem in t_open"));
664 			tli_error(E_FD1OPEN, EXIT);
665 		}
666 	}
667 
668 	ret = bind(fd, name, qlen, clen, adrp);
669 	DEBUG((9, "bind returns %d", ret));
670 
671 	if (ret < 0) {
672 		t_close(fd);
673 		return(-3);
674 	}
675 	if (conp)
676 		*conp = ret;
677 	return(fd);
678 }
679 
680 
681 int
bind(fd,name,qlen,clen,ap)682 bind(fd, name, qlen, clen, ap)
683 int fd;
684 char *name;
685 int qlen;
686 int clen;
687 char **ap;
688 {
689 	struct t_bind *req = (struct t_bind *)0;
690 	struct t_bind *ret = (struct t_bind *)0;
691 	char	*p, *q;
692 	unsigned int	retval;
693 	extern void	nlsaddr2c();
694 	extern int	memcmp();
695 	extern int	errno;
696 
697 #ifdef	CHARADDR
698 	char pbuf[NAMEBUFSZ + 1];
699 #endif
700 	char scratch[BUFSIZ];
701 
702 	DEBUG((9,"in bind, fd = %d, clen = %d", fd, clen));
703 
704 	if (clen)  {
705 		errno = t_errno = 0;
706 		while (!(req = (struct t_bind *)t_alloc(fd,T_BIND,T_ALL)) ) {
707 			if ((t_errno != TSYSERR) || (errno != EAGAIN))
708 				tli_error( E_T_ALLOC, EXIT);
709 			else
710 				tli_error( E_T_ALLOC, CONTINUE);
711 		}
712 
713 		errno = t_errno = 0;
714 		while (!(ret = (struct t_bind *)t_alloc(fd,T_BIND,T_ALL)) ) {
715 			if ((t_errno != TSYSERR) || (errno != EAGAIN))
716 				tli_error( E_T_ALLOC, EXIT);
717 			else
718 				tli_error( E_T_ALLOC, CONTINUE);
719 		}
720 
721 		if (clen > (int) req->addr.maxlen)  {
722 			sprintf(scratch,"Truncating name size from %d to %d",
723 				clen, req->addr.maxlen);
724 			logmessage(scratch);
725 			clen = req->addr.maxlen;
726 		}
727 
728 		if (clen == -1) {
729 			req->addr.len = 0;
730 		}
731 		else {
732 			(void)memcpy(req->addr.buf, name, clen);
733 			req->addr.len = clen;
734 		}
735 		req->qlen = qlen;
736 
737 #if defined(CHARADDR) && defined(DEBUGMODE)
738 		(void)memcpy(pbuf, req->addr.buf, req->addr.len);
739 		pbuf[req->addr.len] = (char)0;
740 		DEBUG((3,"bind: fd=%d, logical name=%c%s%c, len=%d",
741 			fd, '\"',pbuf, '\"', req->addr.len));
742 #endif	/* CHARADDR  && DEBUGMODE */
743 
744 
745 #if defined(CHARADDR) && defined(DEBUGMODE)
746 		(void)memcpy(pbuf, req->addr.buf, req->addr.len);
747 		pbuf[req->addr.len] = (char)0;
748 		DEBUG((3,"bind: fd=%d, address=%c%s%c, len=%d",
749 			fd, '\"',pbuf, '\"', req->addr.len));
750 #endif	/* CHARADDR  && DEBUGMODE */
751 
752 
753 	}
754 
755 	if (t_bind(fd, req, ret))  {
756 		DEBUG((1,"t_bind failed; t_errno %d errno %d", t_errno, errno));
757 		if (qlen)	/* starup only */
758 			tli_error(E_T_BIND, EXIT | NOCORE);
759 		/* here during normal service */
760 		if ((t_errno == TNOADDR) || ((t_errno == TSYSERR) && (errno == EAGAIN))) {
761 			/* our name space is all used up */
762 			tli_error(E_T_BIND, CONTINUE);
763 			t_close(fd);
764 			if (clen)  {
765 				if ( t_free((char *)req, T_BIND) )
766 					tli_error(E_T_FREE, EXIT);
767 				if ( t_free((char *)ret, T_BIND) )
768 					tli_error(E_T_FREE, EXIT);
769 			}
770 			return(-1);
771 		}
772 		/* otherwise, irrecoverable error */
773 		tli_error(E_T_BIND, EXIT | NOCORE);
774 	}
775 	DEBUG((9, "t_bind succeeded"));
776 
777 	if (clen)  {
778 		retval = ret->qlen;
779 		if (clen == -1) {
780 			/* dynamic address */
781 			*ap = (char *) malloc(((ret->addr.len) << 1) + 3);
782 			if (*ap) {
783 				(*ap)[0] = '\\';
784 				(*ap)[1] = 'x';
785 				nlsaddr2c(*ap+2,ret->addr.buf,(int)ret->addr.len);
786 			}
787 		}
788 		else if ( (ret->addr.len != req->addr.len) ||
789 		     (memcmp( req->addr.buf, ret->addr.buf, (int) req->addr.len)) )  {
790 			p = (char *) malloc(((ret->addr.len) << 1) + 1);
791 			q = (char *) malloc(((req->addr.len) << 1) + 1);
792 			if (p && q) {
793 				nlsaddr2c(p, ret->addr.buf, (int)ret->addr.len);
794 				nlsaddr2c(q, req->addr.buf, (int)req->addr.len);
795 				sprintf(scratch, "Requested address \\x%s", q);
796 				logmessage(scratch);
797 				sprintf(scratch, "Actual address    \\x%s", p);
798 				logmessage(scratch);
799 				free(p);
800 				free(q);
801 			}
802 			DEBUG((9, "failed to bind requested address"));
803 			t_unbind(fd);
804 			t_close(fd);
805 			if ( t_free((char *)req, T_BIND) )
806 				tli_error(E_T_FREE, EXIT);
807 			if ( t_free((char *)ret, T_BIND) )
808 				tli_error(E_T_FREE, EXIT);
809 			return(-1);
810 		}
811 
812 		if ( t_free((char *)req, T_BIND) )
813 			tli_error(E_T_FREE, EXIT);
814 
815 		if ( t_free((char *)ret, T_BIND) )
816 			tli_error(E_T_FREE, EXIT);
817 		return(retval);
818 	}
819 	return((unsigned int) 0);
820 }
821 
822 
823 /*
824  * catch_signals:
825  *		Ignore some, catch the rest. Use SIGTERM to kill me.
826  */
827 
828 sigset_t Oset;
829 struct sigaction Sigterm;
830 struct sigaction Sigcld;
831 
832 static void
catch_signals(void)833 catch_signals(void)
834 {
835 	sigset_t sset;
836 	sigset_t eset;
837 	struct sigaction sigact;
838 	extern void sigterm();
839 
840 	(void) sigfillset(&sset);
841 	(void) sigdelset(&sset, SIGTERM);
842 	(void) sigdelset(&sset, SIGCLD);
843 	(void) sigprocmask(SIG_SETMASK, &sset, &Oset);
844 
845 	sigact.sa_flags = 0;
846 	sigact.sa_handler = sigterm;
847 	sigact.sa_mask = sset;
848 	sigaction(SIGTERM, &sigact, &Sigterm);
849 	sigact.sa_flags = SA_NOCLDWAIT;
850 	sigact.sa_handler = SIG_IGN;
851 	sigact.sa_mask = sset;
852 	sigaction(SIGCLD, &sigact, &Sigcld);
853 }
854 
855 
856 /*
857  * rst_signals:
858  *		After forking but before exec'ing a server,
859  *		reset all signals to original setting.
860  */
861 
862 static void
rst_signals(void)863 rst_signals(void)
864 {
865 	struct sigaction sigact;
866 
867 	sigaction(SIGTERM, &Sigterm, NULL);
868 	sigaction(SIGCLD, &Sigcld, NULL);
869 	sigprocmask(SIG_SETMASK, &Oset, NULL);
870 }
871 
872 
873 /*
874  * sigterm:	Clean up and exit.
875  */
876 
877 void
sigterm()878 sigterm()
879 {
880 	extern char *shaddr;
881 	extern char *sh2addr;
882 
883 	error(E_SIGTERM, EXIT | NORMAL | NOCORE);	/* calls cleanup */
884 }
885 
886 
887 /*
888  * listen:	listen for and process connection requests.
889  */
890 
891 static char *dbfnewdmsg = "Using new data base file";
892 
893 static void
listen(void)894 listen(void)
895 {
896 	int	i;
897 	dbf_t	*dbp	= Dbfhead;
898 	struct	pollfd	*sp;
899 	struct		call_list *phead; /* pending head */
900 
901 	DEBUG((9,"in listen, tag %s", Pmmsg.pm_tag));
902 
903 	if ((Pollfds = (struct pollfd *) malloc(Ndesc * sizeof(struct pollfd)))
904 			== NULL)
905 		error(E_MALLOC,NOCORE | EXIT);
906 
907 	/* setup poll structures for sac messages and private addresses */
908 	sp = Pollfds;
909 	sp->fd = Pmpipefd;
910 	sp->events = POLLIN;
911 	sp->revents = 0;
912 	sp++;
913 	for (dbp = Dbfhead; dbp && dbp->dbf_svc_code; dbp++) {
914 		if (dbp->dbf_fd >= 0) {
915 			sp->fd = dbp->dbf_fd;
916 			DEBUG((9, "adding %d to poll struct", dbp->dbf_fd));
917 			sp->events = POLLIN;
918 			sp->revents = 0;
919 			sp++;
920 		}
921 	}
922 	errno = t_errno = 0;
923 
924 	for (;;) {
925 		DEBUG((9,"listen(): TOP of loop"));
926 
927 		/* +1 for Pmpipefd */
928 		if (poll(Pollfds, Valid_addrs + 1, -1) < 0) {
929 			if (errno == EINTR)
930 				continue;
931 			/* poll error */
932 			sys_error(E_POLL, EXIT);
933 		}
934 		else {
935 			/* incoming request or message */
936 			for (i = 0, sp = Pollfds; i < Valid_addrs + 1; i++, sp++) {
937 				switch (sp->revents) {
938 				case POLLIN:
939 					if (sp->fd == Pmpipefd) {
940 						DEBUG((9,"sac message received"));
941 						check_sac_mesg();
942 					}
943 					else {
944 						DEBUG((9,"Connection requested "));
945 						phead = ((sp->fd) + Priv_call);
946 						doevent(phead, (sp->fd));
947 						if (State == PM_ENABLED)
948 							trycon(phead, (sp->fd));
949 						else
950 							send_dis(phead, (sp->fd));
951 					}
952 					break;
953 				case 0:
954 					break;
955 				/* distinguish the various errors for the user */
956 				case POLLERR:
957 					logmessage("poll() returned POLLERR");
958 					error(E_SYS_ERROR, EXIT | NO_MSG);
959 					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 
1008 void
check_sac_mesg()1009 check_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 
1075 static void
doevent(struct call_list * phead,int fd)1076 doevent(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 
1136 static void
send_dis(struct call_list * phead,int fd)1137 send_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 
1169 static void
trycon(struct call_list * phead,int fd)1170 trycon(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 			}
1277 cleanup:
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 
1324 static char homeenv[BUFSIZ];
1325 static char pathenv[BUFSIZ];
1326 
1327 int
start_server(netfd,dbp)1328 start_server(netfd, dbp)
1329 int netfd;
1330 dbf_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 
1495 static char provenv[2*PATHSIZE];
1496 static char prefenv[2*PATHSIZE];
1497 
1498 int
senviron(call)1499 senviron(call)
1500 struct 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 
1567 char *
parse(s)1568 parse(s)
1569 char *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 
1613 static void
clr_call(struct t_call * call)1614 clr_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 
1630 static void
pitchcall(struct call_list * pending,struct t_discon * discon)1631 pitchcall(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 
1679 int
add_prvaddr(dbp)1680 add_prvaddr(dbp)
1681 dbf_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  */
1768 static void
mod_prvaddr(void)1769 mod_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 
1878 int
del_prvaddr(dbp)1879 del_prvaddr(dbp)
1880 dbf_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 
1927 dbf_t *
svc_code_match(new_code)1928 svc_code_match(new_code)
1929 char	*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 
1945 void
rpc_register(dbp)1946 rpc_register(dbp)
1947 dbf_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 
1986 void
rpc_unregister(dbp)1987 rpc_unregister(dbp)
1988 dbf_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