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  * Copyright 2017 Gary Mills
  24  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  29 /*        All Rights Reserved   */
  30 
  31 /*
  32  * Portions of this source code were derived from Berkeley 4.3 BSD
  33  * under license from the Regents of the University of California.
  34  */
  35 
  36 /*
  37  * This contains the mainline code for the YP server.  Data
  38  * structures which are process-global are also in this module.
  39  */
  40 
  41 /* this is so that ypserv will compile under 5.5 */
  42 #define _SVID_GETTOD
  43 #include <sys/time.h>
  44 extern int gettimeofday(struct timeval *);
  45 
  46 #include "ypsym.h"
  47 #include <sys/types.h>
  48 #include <sys/wait.h>
  49 #include <fcntl.h>
  50 #include <rpc/rpc.h>
  51 #include <netconfig.h>
  52 #include <netdir.h>
  53 #include <sys/select.h>
  54 #include <stdlib.h>
  55 #include <unistd.h>
  56 #include <stdio.h>
  57 #include <stdarg.h>
  58 #include <signal.h>
  59 #include "shim.h"
  60 #include "yptol.h"
  61 #include <syslog.h>
  62 
  63 static char register_failed[] = "ypserv:  Unable to register service for ";
  64 bool silent = TRUE;
  65 
  66 /*
  67  * client_setup_failure will be TRUE, if setup of the
  68  * connection to rpc.nisd_resolv failed
  69  */
  70 bool client_setup_failure = FALSE;
  71 
  72 /* N2L options */
  73 bool init_dit = FALSE;
  74 bool init_containers = FALSE;
  75 bool init_maps = FALSE;
  76 char **ldapCLA = NULL;
  77 
  78 /* For DNS forwarding command line option (-d) */
  79 bool dnsforward = FALSE;
  80 int resolv_pid = 0;
  81 CLIENT *resolv_client = NULL;
  82 char *resolv_tp = "ticots";
  83 
  84 #ifdef MINUS_C_OPTION
  85 /* For cluster support (-c) */
  86 bool multiflag = FALSE;
  87 #endif
  88 
  89 static char logfile[] = "/var/yp/ypserv.log";
  90 void logprintf(char *format, ...);
  91 
  92 static void ypexit(void);
  93 static void ypinit(int argc, char **argv);
  94 static void ypdispatch(struct svc_req *rqstp, SVCXPRT *transp);
  95 static void ypolddispatch(struct svc_req *rqstp, SVCXPRT *transp);
  96 static void ypget_command_line_args(int argc, char **argv);
  97 extern void setup_resolv(bool *fwding, int *child,
  98                         CLIENT **client, char *tp_type, long prognum);
  99 static void cleanup_resolv(int);
 100 
 101 /*
 102  * This is the main line code for the yp server.
 103  */
 104 int
 105 main(int argc, char **argv)
 106 {
 107         if (geteuid() != 0) {
 108                 fprintf(stderr, "must be root to run %s\n", argv[0]);
 109                 exit(1);
 110         }
 111 
 112         /* Set up shop */
 113         ypinit(argc, argv);
 114 
 115         /* If requested set up the N2L maps. May take a while */
 116         if (init_dit)
 117                 if (FAILURE == dump_maps_to_dit(init_containers)) {
 118                         fprintf(stderr, "Fatal error dumping maps to DIT."
 119                         " See syslog and LDAP server logs for details.\n");
 120                         exit(1);
 121                 }
 122 
 123         if (init_maps)
 124                 if (FAILURE == dump_dit_to_maps()) {
 125                         fprintf(stderr, "Fatal error dumping DIT to maps."
 126                         " See syslog and LDAP server logs for details.\n");
 127                         exit(1);
 128                 }
 129 
 130         /*
 131          * If we were asked to init the maps now exit. User will then use
 132          * ypstart to restart ypserv and all the other NIS daemons.
 133          */
 134         if (init_dit || init_maps) {
 135                 printf("Map setup complete. Please now restart NIS daemons "
 136                         "with ypstart.\n");
 137                 exit(0);
 138         }
 139 
 140         svc_run();
 141 
 142         /*
 143          * This is stupid, but the compiler likes to warn us about the
 144          * absence of returns from main()
 145          */
 146         return (0);
 147 }
 148 
 149 typedef struct {
 150         char            *netid;
 151         int             fd;
 152         int             olddispatch;    /* Register on protocol version 1 ? */
 153         int             class;          /* Other services that must succeed */
 154         SVCXPRT         *xprt;
 155         int             ok;             /* Registered successfully ? */
 156 } ypservice_t;
 157 
 158 ypservice_t     service[] = {
 159         { "udp", -1, 1, 4, 0, 0 },
 160         { "tcp", -1, 1, 4, 0, 0 },
 161         { "udp6", -1, 0, 6, 0, 0 },
 162         { "tcp6", -1, 0, 6, 0, 0 }
 163 };
 164 
 165 #define MAXSERVICES     (sizeof (service)/sizeof (service[0]))
 166 
 167 int             service_classes[MAXSERVICES];
 168 
 169 /*
 170  * Does startup processing for the yp server.
 171  */
 172 static void
 173 ypinit(int argc, char **argv)
 174 {
 175         int pid;
 176         int stat;
 177         struct sigaction act;
 178         int ufd, tfd;
 179         SVCXPRT *utransp, *ttransp;
 180         struct netconfig *nconf;
 181         int connmaxrec = RPC_MAXDATASIZE;
 182         int i, j, services = 0;
 183 
 184 
 185         /*
 186          * Init yptol flags. Will get redone by init_lock_system() but we need
 187          * to know if we should parse yptol cmd line options.
 188          */
 189         init_yptol_flag();
 190 
 191         ypget_command_line_args(argc, argv);
 192 
 193         if (silent) {
 194                 pid = (int)fork();
 195 
 196                 if (pid == -1) {
 197                     logprintf("ypserv:  ypinit fork failure.\n");
 198                     ypexit();
 199                 }
 200 
 201                 if (pid != 0) {
 202                     exit(0);
 203                 }
 204         }
 205 
 206         if (!init_lock_system(FALSE)) {
 207                 ypexit();
 208         }
 209 
 210         get_secure_nets(argv[0]);
 211 
 212         if (silent) {
 213                 closelog();
 214                 closefrom(3);
 215         }
 216 
 217         if (yptol_mode) {
 218                 stat = parseConfig(ldapCLA, NTOL_MAP_FILE);
 219                 if (stat == 1) {
 220                         logprintf("NIS to LDAP mapping inactive.\n");
 221                 } else if (stat != 0) {
 222                         logprintf("Aborting after NIS to LDAP mapping "
 223                                                         "error.\n");
 224                         fflush(stderr);
 225                         exit(-1);
 226                 }
 227         }
 228 
 229         if (silent) {
 230                 freopen("/dev/null", "r", stdin);
 231                 if (access(logfile, _IOWRT)) {
 232                     freopen("/dev/null", "w", stdout);
 233                     freopen("/dev/null", "w", stderr);
 234                 } else {
 235                     freopen(logfile, "a", stdout);
 236                     freopen(logfile, "a", stderr);
 237                 }
 238 
 239                 (void) open("/dev/tty", 2);
 240 
 241                 setpgrp();
 242         }
 243 
 244 #ifdef  SYSVCONFIG
 245         sigset(SIGHUP, (void (*)())sysvconfig);
 246 #else
 247         sigset(SIGHUP, SIG_IGN);
 248 #endif
 249 
 250         /*
 251          * Setting disposition to SIG_IGN will not create zombies when child
 252          * processes terminate.
 253          */
 254         sigset(SIGCHLD, SIG_IGN);
 255 
 256         act.sa_handler = cleanup_resolv;
 257         sigemptyset(&act.sa_mask);
 258         act.sa_flags = SA_RESETHAND;
 259         sigaction(SIGTERM, &act, (struct sigaction *)NULL);
 260         sigaction(SIGQUIT, &act, (struct sigaction *)NULL);
 261         sigaction(SIGABRT, &act, (struct sigaction *)NULL);
 262         sigaction(SIGBUS, &act, (struct sigaction *)NULL);
 263         sigaction(SIGSEGV, &act, (struct sigaction *)NULL);
 264 
 265         /*
 266          * Set non-blocking mode and maximum record size for
 267          * connection oriented RPC transports.
 268          */
 269         if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
 270                 logprintf("unable to set maximum RPC record size");
 271         }
 272 
 273         svc_unreg(YPPROG, YPVERS);
 274         svc_unreg(YPPROG, YPVERS_ORIG);
 275 
 276         for (i = 0; i < sizeof (service)/sizeof (ypservice_t); i++) {
 277 
 278                 service_classes[i] = -1;
 279 
 280                 if ((nconf = getnetconfigent(service[i].netid)) == NULL) {
 281                         logprintf("getnetconfigent(\"%s\") failed\n",
 282                                         service[i].netid);
 283                         continue;
 284                 }
 285 
 286                 if ((service[i].fd = t_open(nconf->nc_device, O_RDWR, NULL)) <
 287                         0) {
 288                         logprintf("t_open failed for %s\n", service[i].netid);
 289                         freenetconfigent(nconf);
 290                         continue;
 291                 }
 292 
 293                 if (netdir_options(nconf, ND_SET_RESERVEDPORT, service[i].fd,
 294                         NULL) < 0) {
 295                         logprintf("could not set reserved port for %s\n",
 296                                 service[i].netid);
 297                         (void) close(service[i].fd);
 298                         service[i].fd = -1;
 299                         freenetconfigent(nconf);
 300                         continue;
 301                 }
 302 
 303                 if ((service[i].xprt = svc_tli_create(service[i].fd, nconf,
 304                         NULL, 0, 0)) == NULL) {
 305                         logprintf("svc_tli_create failed for %s\n",
 306                                 service[i].netid);
 307                         (void) close(service[i].fd);
 308                         service[i].fd = -1;
 309                         freenetconfigent(nconf);
 310                         continue;
 311                 }
 312 
 313                 if (!svc_reg(service[i].xprt, YPPROG, YPVERS, ypdispatch,
 314                         nconf)) {
 315                         logprintf("%s %s\n", service[i].netid, register_failed);
 316                         svc_destroy(service[i].xprt);
 317                         service[i].xprt = 0;
 318                         (void) close(service[i].fd);
 319                         service[i].fd = -1;
 320                         freenetconfigent(nconf);
 321                         continue;
 322                 }
 323 
 324                 if (service[i].olddispatch && !svc_reg(service[i].xprt, YPPROG,
 325                                         YPVERS_ORIG, ypolddispatch, nconf)) {
 326                         logprintf("old %s %s\n",
 327                                 service[i].netid, register_failed);
 328                         /* Can only unregister prognum/versnum */
 329                         svc_destroy(service[i].xprt);
 330                         service[i].xprt = 0;
 331                         (void) close(service[i].fd);
 332                         service[i].fd = -1;
 333                         freenetconfigent(nconf);
 334                         continue;
 335                 }
 336 
 337                 services++;
 338                 service[i].ok = 1;
 339                 service_classes[i] = service[i].class;
 340 
 341                 freenetconfigent(nconf);
 342 
 343         }
 344 
 345         /*
 346          * Check if we managed to register enough services to continue.
 347          * It's OK if we managed to register all IPv4 services but no
 348          * IPv6, or the other way around, but not if we (say) registered
 349          * IPv4 UDP but not TCP.
 350          */
 351         if (services > 0) {
 352                 for (j = 0; j < MAXSERVICES; j++) {
 353                         if (service_classes[j] >= 0) {
 354                                 /*
 355                                  * Must have all services of this class
 356                                  * registered.
 357                                  */
 358                                 for (i = 0; i < MAXSERVICES; i++) {
 359                                         if (service[i].ok == 0 &&
 360                                                 service[i].class ==
 361                                                 service_classes[j]) {
 362                                                 logprintf(
 363                         "unable to register all services for class %d\n",
 364                                                         service[i].class);
 365                                                 ypexit();
 366                                         }
 367                                 }
 368                         }
 369                 }
 370         } else {
 371                 logprintf("unable to register any services\n");
 372                 ypexit();
 373         }
 374 
 375         /* Now we setup circuit_n or yp_all() and yp_update() will not work */
 376         if (!svc_create(ypdispatch, YPPROG, YPVERS, "circuit_n")) {
 377                 logprintf("circuit_n %s\n", register_failed);
 378                 ypexit();
 379         }
 380 
 381         if (dnsforward) {
 382                 setup_resolv(&dnsforward, &resolv_pid,
 383                                 &resolv_client, resolv_tp, 0);
 384                 if (resolv_client == NULL)
 385                         client_setup_failure = TRUE;
 386         }
 387 }
 388 
 389 void
 390 cleanup_resolv(int sig)
 391 {
 392         if (resolv_pid)
 393                 kill(resolv_pid, sig);
 394 
 395         kill(getpid(), sig);
 396 }
 397 
 398 /*
 399  * This picks up any command line args passed from the process invocation.
 400  */
 401 static void
 402 ypget_command_line_args(int argc, char **argv)
 403 {
 404         for (argv++; --argc; argv++) {
 405 
 406                 if ((*argv)[0] == '-') {
 407 
 408                         switch ((*argv)[1]) {
 409 #ifdef  MINUS_C_OPTION
 410                         case 'c':
 411                                 multiflag = TRUE;
 412                                 break;
 413 #endif
 414                         case 'd':
 415                                 if (access("/etc/resolv.conf", F_OK) == -1) {
 416                                         fprintf(stderr,
 417                         "No /etc/resolv.conf file, -d option ignored\n");
 418                                 } else {
 419                                         dnsforward = TRUE;
 420                                 }
 421                                 break;
 422                         case 'I':
 423                                 init_containers = TRUE;
 424                                 /* ... and also do -i stuff */
 425                         case 'i':
 426                                 if (yptol_mode) {
 427                                         init_dit = TRUE;
 428                                 } else {
 429                                         fprintf(stderr, "-%c option is illegal "
 430                                         "if not in NIS to LDAP mode. Exiting\n",
 431                                                 (*argv)[1]);
 432                                         fflush(stderr);
 433                                         exit(-1);
 434                                 }
 435 
 436                                 /* Handle -ir */
 437                                 if ('r' != (*argv)[2])
 438                                         break;
 439 
 440                         case 'r':
 441                                 if (yptol_mode) {
 442                                         init_maps = TRUE;
 443                                 } else {
 444                                         fprintf(stderr, "-r option is illegal "
 445                                                 "if not in NIS to LDAP mode. "
 446                                                 "Exiting\n");
 447                                         fflush(stderr);
 448                                         exit(-1);
 449                                 }
 450                                 break;
 451                         case 'v':
 452                                 silent = FALSE;
 453                                 break;
 454                         }
 455                 }
 456         }
 457 
 458         /* If setting up don't run silent or demonize */
 459         if (init_dit || init_maps)
 460                 silent = FALSE;
 461 
 462 }
 463 
 464 /*
 465  * This dispatches to server action routines based on the input procedure
 466  * number.  ypdispatch is called from the RPC function svc_run.
 467  */
 468 static void
 469 ypdispatch(struct svc_req *rqstp, SVCXPRT *transp)
 470 {
 471         sigset_t set, oset;
 472 
 473 
 474 #ifdef  SYSVCONFIG
 475         /* prepare to answer questions about system v filesystem aliases */
 476         sysvconfig();
 477 #endif
 478 
 479         sigemptyset(&set);
 480         sigaddset(&set, SIGCHLD);
 481         sigprocmask(SIG_BLOCK, &set, &oset);
 482 
 483         switch (rqstp->rq_proc) {
 484 
 485         case YPPROC_NULL:
 486 
 487                 if (!svc_sendreply(transp, xdr_void, 0))
 488                         logprintf("ypserv:  Can't reply to rpc call.\n");
 489                 break;
 490 
 491         case YPPROC_DOMAIN:
 492                 ypdomain(transp, TRUE);
 493                 break;
 494 
 495         case YPPROC_DOMAIN_NONACK:
 496                 ypdomain(transp, FALSE);
 497                 break;
 498 
 499         case YPPROC_MATCH:
 500                 ypmatch(transp, rqstp);
 501                 break;
 502 
 503         case YPPROC_FIRST:
 504                 ypfirst(transp);
 505                 break;
 506 
 507         case YPPROC_NEXT:
 508                 ypnext(transp);
 509                 break;
 510 
 511         case YPPROC_XFR:
 512                 ypxfr(transp, YPPROC_XFR);
 513                 break;
 514 
 515         case YPPROC_NEWXFR:
 516                 ypxfr(transp, YPPROC_NEWXFR);
 517                 break;
 518 
 519         case YPPROC_CLEAR:
 520                 ypclr_current_map();
 521 
 522                 if (!svc_sendreply(transp, xdr_void, 0))
 523                         logprintf("ypserv:  Can't reply to rpc call.\n");
 524                 break;
 525 
 526         case YPPROC_ALL:
 527                 ypall(transp);
 528                 break;
 529 
 530         case YPPROC_MASTER:
 531                 ypmaster(transp);
 532                 break;
 533 
 534         case YPPROC_ORDER:
 535                 yporder(transp);
 536                 break;
 537 
 538         case YPPROC_MAPLIST:
 539                 ypmaplist(transp);
 540                 break;
 541 
 542         default:
 543                 svcerr_noproc(transp);
 544                 break;
 545 
 546         }
 547 
 548         sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
 549 
 550 }
 551 
 552 static void
 553 ypolddispatch(struct svc_req *rqstp, SVCXPRT *transp)
 554 {
 555         sigset_t set, oset;
 556 
 557         sigemptyset(&set);
 558         sigaddset(&set, SIGCHLD);
 559         sigprocmask(SIG_BLOCK, &set, &oset);
 560 
 561         switch (rqstp->rq_proc) {
 562 
 563         case YPOLDPROC_NULL:
 564                 if (!svc_sendreply(transp, xdr_void, 0))
 565                         logprintf("ypserv:  Can't replay to rpc call.\n");
 566                 break;
 567 
 568         case YPOLDPROC_DOMAIN:
 569                 ypdomain(transp, TRUE);
 570                 break;
 571 
 572         case YPOLDPROC_DOMAIN_NONACK:
 573                 ypdomain(transp, FALSE);
 574                 break;
 575 
 576         case YPOLDPROC_MATCH:
 577                 ypoldmatch(transp, rqstp);
 578                 break;
 579 
 580         case YPOLDPROC_FIRST:
 581                 ypoldfirst(transp);
 582                 break;
 583 
 584         case YPOLDPROC_NEXT:
 585                 ypoldnext(transp);
 586                 break;
 587 
 588         case YPOLDPROC_POLL:
 589                 ypoldpoll(transp);
 590                 break;
 591 
 592         case YPOLDPROC_PUSH:
 593                 ypoldpush(transp);
 594                 break;
 595 
 596         case YPOLDPROC_PULL:
 597                 ypoldpull(transp);
 598                 break;
 599 
 600         case YPOLDPROC_GET:
 601                 ypoldget(transp);
 602 
 603         default:
 604                 svcerr_noproc(transp);
 605                 break;
 606         }
 607 
 608         sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
 609 }
 610 
 611 /*
 612  * This flushes output to stderr, then aborts the server process to leave a
 613  * core dump.
 614  */
 615 static void
 616 ypexit(void)
 617 {
 618         fflush(stderr);
 619         abort();
 620 }
 621 
 622 /*
 623  * This constructs a logging record.
 624  */
 625 void
 626 logprintf(char *format, ...)
 627 {
 628         va_list ap;
 629         struct timeval t;
 630 
 631         va_start(ap, format);
 632 
 633         if (silent) {
 634                 gettimeofday(&t);
 635                 fseek(stderr, 0, 2);
 636                 fprintf(stderr, "%19.19s: ", ctime(&t.tv_sec));
 637         }
 638 
 639         vfprintf(stderr, format, ap);
 640         va_end(ap);
 641         fflush(stderr);
 642 }