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