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 }