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