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