Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / usr / src / cmd / listen / listen.c
blobba5c1a9643aa715bbbc6f29522715ecfc23ebbb7
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
24 * Copyright 2014 Garrett D'Amore
27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
35 * Network Listener Process
37 * command line:
39 * listen [ -m minor_prefix ] netspec
43 /* system include files */
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>
68 /* listener include files */
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"
78 /* defines */
80 #define NAMESIZE (NAMEBUFSZ-1)
82 #define SPLhi() Splflag = 1
83 #define SPLlo() Splflag = 0
85 #define GEN 1
86 #define LOGIN 0
88 /* global variables */
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 */
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 */
112 /* FILE DESCRIPTOR MANAGEMENT:
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.
128 * The remaining file descriptors are available for binding private addresses.
131 #ifndef DEBUGMODE
132 #define USEDFDS 6
133 #else
134 #define USEDFDS 7
135 FILE *Debugfp; /* for the debugging file */
136 #endif
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*/
145 struct pmmsg Pmmsg; /* to respond to SAC */
146 int State = PM_STARTING; /* current SAC state */
147 char Mytag[15];
149 char Lastmsg[BUFSIZ]; /* contains last msg logged (by stampbuf) */
150 int Logmax = LOGMAX; /* number of entriet to allow in logfile */
152 int Splflag; /* logfile critical region flag */
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];
161 #define TZFILE "/etc/default/init"
162 #define TZSTR "TZ="
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;
173 #ifndef TRUE
174 #define TRUE 1
175 #define FALSE 0
176 #endif
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);
192 main(int argc, char **argv)
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;
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);
215 strcpy(Mytag, mytag_p);
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);
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+");
232 /* Get my port monitor tag out of the environment */
233 if ((mytag_p = getenv("PMTAG")) == NULL) {
234 logexit(1, nopmtag);
236 strcpy(Mytag, mytag_p);
238 (void) umask(022);
239 Readdb = FALSE;
241 if (geteuid() != (uid_t) 0) {
242 logmessage("Must be root to start listener");
243 logexit(1, badstart);
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;
256 if ((Netspec = argv[optind]) == NULL) {
257 logexit(1, usage);
259 if ((Netconf = getnetconfigent(Netspec)) == NULL) {
260 sprintf(scratch, "no netconfig entry for <%s>", Netspec);
261 logmessage(scratch);
262 logexit(1, badstart);
264 if (!Minor_prefix)
265 Minor_prefix = argv[optind];
267 if ((int) strlen(Netspec) > PATHSIZE) {
268 logmessage(badnspmsg);
269 logexit(1, badstart);
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
277 strcpy(Provbuf, "/dev/");
278 strcat(Provbuf, Netspec);
280 (void) umask(0);
282 init_files(); /* open Accept, Sac, Pm, Pass files */
283 pid_open(); /* create pid file */
285 #ifdef DEBUGMODE
286 sprintf(scratch, "%s/%s/%s", ALTDIR, Mytag, DBGNAME);
287 Debugfp = fopen(scratch, "w");
288 #endif
291 #ifdef DEBUGMODE
292 if ((!Logfp) || (!Debugfp))
293 #else
294 if (!Logfp)
295 #endif
296 logexit(1, badstart);
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.
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;
314 fclose(fp);
316 else {
317 sprintf(scratch, "couldn't open %s, default to GMT",
318 TZFILE);
319 logmessage(scratch);
323 logmessage("@(#)listen:listen.c 1.19.9.1");
325 #ifdef DEBUGMODE
326 logmessage("Listener process with DEBUG capability");
327 #endif
329 sprintf(scratch, "Listener port monitor tag: %s", Mytag_p);
330 logmessage(scratch);
331 DEBUG((9, "Minor prefix: %s Netspec %s", Minor_prefix, Netspec));
333 /* fill in Pmmesg fields that always stay the same */
335 Pmmsg.pm_maxclass = MAXCLASS;
336 strcpy(Pmmsg.pm_tag, Mytag_p);
337 Pmmsg.pm_size = 0;
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");
343 if (!strcmp(scratch_p, "enabled")) {
344 State = PM_ENABLED;
345 logmessage("Starting state: ENABLED");
347 else {
348 State = PM_DISABLED;
349 logmessage("Starting state: DISABLED");
352 /* try to get my "basename" */
353 Progname = strrchr(argv[0], '/');
354 if (Progname && Progname[1])
355 ++Progname;
356 else
357 Progname = argv[0];
359 catch_signals();
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
368 Ndesc = ulimit(4,0L); /* get num of file des on system */
370 read_dbf(DB_INIT);
371 net_open(); /* init, open, bind names */
373 for (i = 3; i < Ndesc; i++) { /* leave stdout, stderr open */
374 fcntl(i, F_SETFD, 1); /* set close on exec flag*/
377 logmessage("Initialization Complete");
379 listen();
380 return (0);
385 * pid_open:
387 * open pidfile with specified oflags and modes and lock it
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";
394 static void
395 pid_open(void)
397 int ret;
398 unsigned int i;
399 char pidstring[20];
401 if ((Pidfd = open(PIDNAME, PIDOFLAG, PIDMODE)) == -1) {
402 logmessage(pidopenmsg);
403 error(E_CREAT, EXIT | NOCORE | NO_MSG);
406 if (lockf(Pidfd, 2, 0L) == -1) {
407 logmessage(pidlockmsg);
408 logexit(1, badstart);
411 Pid = getpid();
412 i = sprintf(pidstring, "%ld", Pid) + 1;
413 ftruncate(Pidfd, 0);
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);
427 * init_files: open initial files for the listener (see FILE DESC MGMT comment)
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";
433 static void
434 init_files(void)
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);
442 close(1);
443 if ((Sacpipefd = open(SACPIPE, O_RDWR|O_NDELAY)) != 1) {
444 logmessage(sacopenmsg);
445 error(E_CREAT, EXIT | NOCORE | NO_MSG);
448 close(2);
449 if ((Pmpipefd = open(PMPIPE, O_RDWR|O_NDELAY)) != 2) {
450 logmessage(pmopenmsg);
451 error(E_CREAT, EXIT | NOCORE | NO_MSG);
454 close(3);
455 if ((Passfd = dup(Acceptfd)) != 3) {
456 logmessage("Trouble duping /dev/null");
457 sys_error(E_SYS_ERROR, EXIT | NOCORE);
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.
471 static void
472 net_open(void)
474 #ifdef CHARADDR
475 char pbuf[NAMEBUFSZ + 1];
476 #endif /* CHARADDR */
477 int i;
478 dbf_t *dp;
479 char scratch[BUFSIZ];
481 DEBUG((9,"in net_open"));
483 /* set up free call list and pending connection lists */
485 Free_call_p->cl_head = NULL;
486 Free_call_p->cl_tail = NULL;
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);
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++;
502 i++;
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++;
512 i++;
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);
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
533 * queue:
535 * add calls to tail of queue
539 void
540 queue(head, cp)
541 struct call_list *head;
542 struct callsave *cp;
544 DEBUG((9,"in queue"));
545 if (head->cl_tail == NULL) {
546 cp->c_np = NULL;
547 head->cl_head = head->cl_tail = cp;
549 else {
550 cp->c_np = head->cl_tail->c_np;
551 head->cl_tail->c_np = cp;
552 head->cl_tail = cp;
558 * pqueue:
560 * priority queuer, add calls to head of queue
563 void
564 pqueue(head, cp)
565 struct call_list *head;
566 struct callsave *cp;
568 if (head->cl_head == NULL) {
569 cp->c_np = NULL;
570 head->cl_head = head->cl_tail = cp;
572 else {
573 cp->c_np = head->cl_head;
574 head->cl_head = cp;
580 * dequeue:
582 * remove a call from the head of queue
586 struct callsave *
587 dequeue(head)
588 struct call_list *head;
590 struct callsave *ret;
592 DEBUG((9,"in dequeue"));
593 if (head->cl_head == 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(NULL);
601 ret = head->cl_head;
602 head->cl_head = ret->c_np;
603 if (head->cl_head == NULL)
604 head->cl_tail = NULL;
605 return(ret);
610 * open_bind:
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.
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.
631 * Assumptions: driver returns ENXIO when all devices are allocated.
635 open_bind(name, qlen, clen, conp, adrp)
636 char *name;
637 int qlen;
638 int clen;
639 unsigned int *conp;
640 char **adrp;
642 int fd;
643 int ret;
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;
663 DEBUG((9,"problem in t_open"));
664 tli_error(E_FD1OPEN, EXIT);
668 ret = bind(fd, name, qlen, clen, adrp);
669 DEBUG((9, "bind returns %d", ret));
671 if (ret < 0) {
672 t_close(fd);
673 return(-3);
675 if (conp)
676 *conp = ret;
677 return(fd);
682 bind(fd, name, qlen, clen, ap)
683 int fd;
684 char *name;
685 int qlen;
686 int clen;
687 char **ap;
689 struct t_bind *req = NULL;
690 struct t_bind *ret = NULL;
691 char *p, *q;
692 unsigned int retval;
693 extern void nlsaddr2c();
694 extern int memcmp();
695 extern int errno;
697 #ifdef CHARADDR
698 char pbuf[NAMEBUFSZ + 1];
699 #endif
700 char scratch[BUFSIZ];
702 DEBUG((9,"in bind, fd = %d, clen = %d", fd, clen));
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);
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);
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;
728 if (clen == -1) {
729 req->addr.len = 0;
731 else {
732 (void)memcpy(req->addr.buf, name, clen);
733 req->addr.len = clen;
735 req->qlen = qlen;
737 #if defined(CHARADDR) && defined(DEBUGMODE)
738 (void)memcpy(pbuf, req->addr.buf, req->addr.len);
739 pbuf[req->addr.len] = '\0';
740 DEBUG((3,"bind: fd=%d, logical name=%c%s%c, len=%d",
741 fd, '\"',pbuf, '\"', req->addr.len));
742 #endif /* CHARADDR && DEBUGMODE */
745 #if defined(CHARADDR) && defined(DEBUGMODE)
746 (void)memcpy(pbuf, req->addr.buf, req->addr.len);
747 pbuf[req->addr.len] = '\0';
748 DEBUG((3,"bind: fd=%d, address=%c%s%c, len=%d",
749 fd, '\"',pbuf, '\"', req->addr.len));
750 #endif /* CHARADDR && DEBUGMODE */
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);
770 return(-1);
772 /* otherwise, irrecoverable error */
773 tli_error(E_T_BIND, EXIT | NOCORE);
775 DEBUG((9, "t_bind succeeded"));
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);
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);
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);
812 if ( t_free((char *)req, T_BIND) )
813 tli_error(E_T_FREE, EXIT);
815 if ( t_free((char *)ret, T_BIND) )
816 tli_error(E_T_FREE, EXIT);
817 return(retval);
819 return((unsigned int) 0);
824 * catch_signals:
825 * Ignore some, catch the rest. Use SIGTERM to kill me.
828 sigset_t Oset;
829 struct sigaction Sigterm;
830 struct sigaction Sigcld;
832 static void
833 catch_signals(void)
835 sigset_t sset;
836 sigset_t eset;
837 struct sigaction sigact;
838 extern void sigterm();
840 (void) sigfillset(&sset);
841 (void) sigdelset(&sset, SIGTERM);
842 (void) sigdelset(&sset, SIGCLD);
843 (void) sigprocmask(SIG_SETMASK, &sset, &Oset);
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);
857 * rst_signals:
858 * After forking but before exec'ing a server,
859 * reset all signals to original setting.
862 static void
863 rst_signals(void)
865 struct sigaction sigact;
867 sigaction(SIGTERM, &Sigterm, NULL);
868 sigaction(SIGCLD, &Sigcld, NULL);
869 sigprocmask(SIG_SETMASK, &Oset, NULL);
874 * sigterm: Clean up and exit.
877 void
878 sigterm()
880 extern char *shaddr;
881 extern char *sh2addr;
883 error(E_SIGTERM, EXIT | NORMAL | NOCORE); /* calls cleanup */
888 * listen: listen for and process connection requests.
891 static char *dbfnewdmsg = "Using new data base file";
893 static void
894 listen(void)
896 int i;
897 dbf_t *dbp = Dbfhead;
898 struct pollfd *sp;
899 struct call_list *phead; /* pending head */
901 DEBUG((9,"in listen, tag %s", Pmmsg.pm_tag));
903 if ((Pollfds = (struct pollfd *) malloc(Ndesc * sizeof(struct pollfd)))
904 == NULL)
905 error(E_MALLOC,NOCORE | EXIT);
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++;
922 errno = t_errno = 0;
924 for (;;) {
925 DEBUG((9,"listen(): TOP of loop"));
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);
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();
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));
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);
980 sp->revents = 0;
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();
994 else {
995 dup(Passfd);
996 logmessage(dbfnewdmsg);
998 Readdb = FALSE;
1005 * check_sac_mesg: check the pipe to see if SAC has sent a message
1008 void
1009 check_sac_mesg()
1011 int length;
1012 struct sacmsg sacmsg;
1014 DEBUG((9, "in check_sac_mesg..."));
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;
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;
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;
1072 * doevent: handle an asynchronous event
1075 static void
1076 doevent(struct call_list *phead, int fd)
1078 static struct t_discon *disc;
1079 struct callsave *current;
1080 struct t_call *call;
1081 char scratch[BUFSIZ];
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;
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);
1114 if (t_rcvdis(fd, disc) < 0) {
1115 tli_error(E_T_RCVDIS, EXIT);
1116 /* no return */
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;
1132 * send_dis: send a disconnect
1133 * called when we are in state PM_DISABLED
1136 static void
1137 send_dis(struct call_list *phead, int fd)
1139 struct t_call *call;
1140 struct callsave *current;
1141 char scratch[BUFSIZ];
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;
1153 else
1154 tli_error(E_T_SNDDIS, CONTINUE);
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);
1161 return;
1166 * trycon: try to accept a connection
1169 static void
1170 trycon(struct call_list *phead, int fd)
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();
1180 DEBUG((9, "in trycon"));
1181 while (!EMPTYLIST(phead)) {
1182 current = dequeue(phead);
1183 call = current->c_cp;
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;
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;
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 */
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;
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;
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);
1243 DEBUG((9, "Accepted call %d", call->sequence));
1245 if (dbp->dbf_sflags & PFLAG) {
1247 close(Passfd);
1249 if (pushmod(Acceptfd, dbp->dbf_modules)) {
1250 sprintf(scratch, "Could not push modules: %s", dbp->dbf_modules);
1251 logmessage(scratch);
1252 goto cleanup;
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;
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;
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);
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);
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();
1294 if (senviron(call)) {
1295 logmessage("Can't expand server's environment");
1298 start_server(Acceptfd, dbp);
1299 #ifdef COREDUMP
1300 abort();
1301 #endif
1302 exit(1); /* server failed, don't log */
1303 /* no return */
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();
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.
1324 static char homeenv[BUFSIZ];
1325 static char pathenv[BUFSIZ];
1328 start_server(netfd, dbp)
1329 int netfd;
1330 dbf_t *dbp;
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;
1342 argvp = mkdbfargv(dbp);
1343 path = *argvp;
1345 /* set up stdout and stderr before pushing optional modules */
1346 /* this child doesn't need access to _sacpipe and _pmpipe */
1348 (void) close(Sacpipefd);
1349 (void) close(Pmpipefd);
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;
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.
1364 * the utmpx routines need a file descriptor!
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);
1372 if (tmp)
1373 exit(0); /* kill parent */
1376 * child continues processing, creating utmp and exec'ing
1377 * the service
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';
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));
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.
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);
1413 if (dup(0) != 1 || dup(0) != 2) {
1414 logmessage("Dup of fd 0 failed");
1415 exit(2); /* server, don't log */
1419 if (pushmod(netfd, dbp->dbf_modules)) {
1420 logmessage("Can't push server's modules: exit");
1421 exit(2); /* server, don't log */
1424 rst_signals();
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);
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 */
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 */
1446 sprintf(msgbuf, "Cannot set group id to %s", grpp->gr_name);
1447 logmessage(msgbuf);
1448 exit(2); /* server, don't log */
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 */
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 */
1464 DEBUG((9, "New uid %ld New gid %ld", getuid(), getgid()));
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);
1474 endpwent();
1476 execve(path, argvp, environ);
1478 /* exec returns only on failure! */
1480 logmessage("ERROR: could not exec server");
1481 sys_error(E_SYS_ERROR, CONTINUE);
1482 return(-1);
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.
1491 * Note: no need to free the malloc'ed buffers since this process
1492 * will either exec or exit.
1495 static char provenv[2*PATHSIZE];
1496 static char prefenv[2*PATHSIZE];
1499 senviron(call)
1500 struct t_call *call;
1502 char *p;
1503 extern void nlsaddr2c();
1504 extern char *getenv();
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.
1513 if (getenv("PATH") == NULL)
1514 putenv("PATH=/usr/sbin:/usr/bin");
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);
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);
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);
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!
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);
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);
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.
1567 char *
1568 parse(s)
1569 char *s;
1571 char *p;
1572 char *tp;
1573 char scratch[BUFSIZ];
1574 int delim;
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);
1588 if (*p == delim) {
1589 *tp = '\0';
1590 return(s);
1592 else {
1593 *tp++ = *p++;
1597 else { /* look for comment or trailing whitespace */
1598 for ( ; *p && !isspace(*p) && *p != '#'; ++p)
1600 /* if a comment or trailing whitespace, trash it */
1601 if (*p) {
1602 *p = '\0';
1604 return(s);
1610 * clr_call: clear out a call structure
1613 static void
1614 clr_call(struct t_call *call)
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);
1627 * pitchcall: remove call from pending list
1630 static void
1631 pitchcall(struct call_list *pending, struct t_discon *discon)
1633 struct callsave *p, *oldp;
1635 DEBUG((9, "pitching call, sequence # is %d", discon->sequence));
1636 if (EMPTYLIST(pending)) {
1637 discon->sequence = -1;
1638 return;
1640 p = pending->cl_head;
1641 oldp = NULL;
1642 while (p) {
1643 if (p->c_cp->sequence == discon->sequence) {
1644 if (oldp == NULL) {
1645 pending->cl_head = p->c_np;
1646 if (pending->cl_head == NULL) {
1647 pending->cl_tail = NULL;
1650 else if (p == pending->cl_tail) {
1651 oldp->c_np = p->c_np;
1652 pending->cl_tail = oldp;
1654 else {
1655 oldp->c_np = p->c_np;
1657 clr_call(p->c_cp);
1658 queue(Free_call_p, p);
1659 discon->sequence = -1;
1660 return;
1662 oldp = p;
1663 p = p->c_np;
1665 logmessage("received disconnect with no pending call");
1666 discon->sequence = -1;
1667 return;
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
1675 * This routine is very sloppy with malloc'ed memory, but addresses
1676 * shouldn't ever change enough for this to matter.
1680 add_prvaddr(dbp)
1681 dbf_t *dbp;
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;
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);
1706 /* call stoa - convert from rfs address to netbuf */
1708 if (stoa(lstr, &netbuf) == NULL) {
1709 DEBUG((9,"stoa returned null, errno = %d\n",errno));
1710 error(1, E_MALLOC);
1711 return(-1);
1713 clen = netbuf.len;
1715 else {
1716 clen = -1;
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);
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;
1741 else {
1742 sprintf(scratch,"Service %s: fd %d addr %s", dbp->dbf_svc_code, bindfd, dbp->dbf_prv_adr);
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 = NULL;
1750 temp_pend->cl_tail = NULL;
1751 for (j=0; j < maxcon; ++j) {
1752 if ((tmp = (struct callsave *) malloc(sizeof(struct callsave))) == NULL) {
1753 error (E_MALLOC, NOCORE | EXIT);
1755 if ((tmp->c_cp = (struct t_call *) t_alloc(bindfd, T_CALL,
1756 T_ALL)) == NULL) {
1757 tli_error(E_T_ALLOC,EXIT);
1759 queue(Free_call_p, tmp);
1761 return(0);
1765 * mod_prvaddr -- after re-reading the database, take appropriate action for
1766 * new, deleted, or changed addresses.
1768 static void
1769 mod_prvaddr(void)
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;
1778 DEBUG((9, "in mod_prvaddr..."));
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.
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;
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);
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);
1814 /* now unbind the remaining addresses in the old table (fd != -1) */
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--;
1824 /* now bind all of the new addresses (fd == -1) */
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
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++;
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++;
1849 /* free old database, set up new pollfd table, and we're done */
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);
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++;
1875 * unbind the address, close the file descriptor, and free call structs
1879 del_prvaddr(dbp)
1880 dbf_t *dbp;
1882 struct callsave *tmp;
1883 struct call_list *q;
1884 struct t_call *call;
1885 int i;
1886 char scratch[BUFSIZ];
1888 DEBUG((9, "in del_prvaddr..."));
1889 rpc_unregister(dbp);
1890 if (dbp->dbf_fd < 0)
1891 return -1;
1893 q = Priv_call + dbp->dbf_fd;
1894 i = 0;
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);
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);
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;
1923 * look through the old database file to see if this service code matches
1924 * one already present
1927 dbf_t *
1928 svc_code_match(new_code)
1929 char *new_code;
1931 dbf_t *dbp;
1933 for (dbp = Dbfhead; dbp && dbp->dbf_svc_code; dbp++) {
1934 if (strcmp(dbp->dbf_svc_code, new_code) == 0)
1935 return(dbp);
1937 return((dbf_t *)NULL);
1942 * register an rpc service with rpcbind
1945 void
1946 rpc_register(dbp)
1947 dbf_t *dbp;
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;
1956 DEBUG((9, "in rpc_register"));
1957 if (dbp->dbf_prognum == -1 || dbp->dbf_version == -1)
1958 /* not an rpc service */
1959 return;
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) == NULL) {
1967 DEBUG((9,"stoa returned null, errno = %d\n",errno));
1968 error(1, E_MALLOC);
1969 return;
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);
1975 else {
1976 logmessage("rpcb_set failed, service not registered with rpcbind");
1978 return;
1983 * unregister an rpc service with rpcbind
1986 void
1987 rpc_unregister(dbp)
1988 dbf_t *dbp;
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);