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