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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  25  * Copyright (c) 2012 by Delphix. All rights reserved.
  26  */
  27 
  28 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T             */
  29 /*        All Rights Reserved   */
  30 
  31 /*
  32  * University Copyright- Copyright (c) 1982, 1986, 1988
  33  * The Regents of the University of California
  34  * All Rights Reserved
  35  *
  36  * University Acknowledgment- Portions of this document are derived from
  37  * software developed by the University of California, Berkeley, and its
  38  * contributors.
  39  */
  40 
  41 /* LINTLIBRARY */
  42 /* PROTOLIB1 */
  43 
  44 /*
  45  * NLM server
  46  *
  47  * Most of this copied from ../nfsd/nfsd.c
  48  * and then s:NFS:NLM: applied, etc.
  49  */
  50 
  51 #include <sys/param.h>
  52 #include <sys/types.h>
  53 #include <sys/stat.h>
  54 #include <syslog.h>
  55 #include <tiuser.h>
  56 #include <rpc/rpc.h>
  57 #include <errno.h>
  58 #include <thread.h>
  59 #include <sys/time.h>
  60 #include <sys/file.h>
  61 #include <nfs/nfs.h>
  62 #include <nfs/nfssys.h>
  63 #include <stdio.h>
  64 #include <stdio_ext.h>
  65 #include <stdlib.h>
  66 #include <signal.h>
  67 #include <netconfig.h>
  68 #include <netdir.h>
  69 #include <string.h>
  70 #include <unistd.h>
  71 #include <stropts.h>
  72 #include <sys/tihdr.h>
  73 #include <poll.h>
  74 #include <priv_utils.h>
  75 #include <sys/tiuser.h>
  76 #include <netinet/tcp.h>
  77 #include <deflt.h>
  78 #include <rpcsvc/daemon_utils.h>
  79 #include <rpcsvc/nlm_prot.h>
  80 #include <libintl.h>
  81 #include <libscf.h>
  82 #include <libshare.h>
  83 #include "nfs_tbind.h"
  84 #include "thrpool.h"
  85 #include "smfcfg.h"
  86 
  87 /* Option defaults.  See nfssys.h */
  88 struct lm_svc_args lmargs = {
  89         .version = LM_SVC_CUR_VERS,
  90         /* fd, n_fmly, n_proto, n_rdev (below) */
  91         .debug = 0,
  92         .timout = 5 * 60,
  93         .grace = 60,
  94         .retransmittimeout = 15
  95 };
  96 int max_servers = 20;
  97 
  98 
  99 #define RET_OK          0       /* return code for no error */
 100 #define RET_ERR         33      /* return code for error(s) */
 101 
 102 static  int     nlmsvc(int fd, struct netbuf addrmask,
 103                         struct netconfig *nconf);
 104 static int nlmsvcpool(int max_servers);
 105 static  void    usage(void);
 106 
 107 extern  int     _nfssys(int, void *);
 108 static void sigterm_handler(void);
 109 static void shutdown_lockd(void);
 110 
 111 extern int      daemonize_init(void);
 112 extern void     daemonize_fini(int fd);
 113 
 114 static  char    *MyName;
 115 
 116 /*
 117  * We want to bind to these TLI providers, and in this order,
 118  * because the kernel NLM needs the loopback first for its
 119  * initialization. (It uses it to talk to statd.)
 120  */
 121 static  NETSELDECL(defaultproviders)[] = {
 122         "/dev/ticotsord",
 123         "/dev/tcp",
 124         "/dev/udp",
 125         "/dev/tcp6",
 126         "/dev/udp6",
 127         NULL
 128 };
 129 
 130 /*
 131  * The following are all globals used by routines in nfs_tbind.c.
 132  */
 133 size_t  end_listen_fds;         /* used by conn_close_oldest() */
 134 size_t  num_fds = 0;            /* used by multiple routines */
 135 int     listen_backlog = 32;    /* used by bind_to_{provider,proto}() */
 136 int     (*Mysvc)(int, struct netbuf, struct netconfig *) = nlmsvc;
 137                                 /* used by cots_listen_event() */
 138 int     max_conns_allowed = -1; /* used by cots_listen_event() */
 139 
 140 int
 141 main(int ac, char *av[])
 142 {
 143         char *propname = NULL;
 144         char *dir = "/";
 145         char *provider = (char *)NULL;
 146         struct protob *protobp;
 147         NETSELPDECL(providerp);
 148         sigset_t sgset;
 149         int i, c, pid, ret, val;
 150         int pipe_fd = -1;
 151         struct sigaction act;
 152 
 153         MyName = *av;
 154 
 155         /*
 156          * Initializations that require more privileges than we need to run.
 157          */
 158         (void) _create_daemon_lock(LOCKD, DAEMON_UID, DAEMON_GID);
 159         svcsetprio();
 160 
 161         if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
 162             DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS, NULL) == -1) {
 163                 (void) fprintf(stderr, "%s should be run with"
 164                     " sufficient privileges\n", av[0]);
 165                 exit(1);
 166         }
 167 
 168         (void) enable_extended_FILE_stdio(-1, -1);
 169 
 170         /*
 171          * Read in the values from SMF first before we check
 172          * command line options so the options override SMF values.
 173          */
 174 
 175         /* How long to keep idle connections. */
 176         propname = "conn_idle_timeout"; /* also -t */
 177         ret = nfs_smf_get_iprop(propname, &val,
 178             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
 179         if (ret == SA_OK) {
 180                 if (val <= 0)
 181                         fprintf(stderr, gettext(
 182                             "Invalid %s from SMF"), propname);
 183                 else
 184                         lmargs.timout = val;
 185         }
 186 
 187         /* Note: debug_level can only be set by args. */
 188 
 189         /* How long to wait for clients to re-establish locks. */
 190         propname = "grace_period"; /* also -g */
 191         ret = nfs_smf_get_iprop(propname, &val,
 192             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
 193         if (ret == SA_OK) {
 194                 if (val <= 0)
 195                         fprintf(stderr, gettext(
 196                             "Invalid %s from SMF"), propname);
 197                 else
 198                         lmargs.grace = val;
 199         }
 200 
 201         propname = "listen_backlog"; /* also -l */
 202         ret = nfs_smf_get_iprop(propname, &val,
 203             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
 204         if (ret == SA_OK) {
 205                 if (val <= 0)
 206                         fprintf(stderr, gettext(
 207                             "Invalid %s from SMF"), propname);
 208                 else
 209                         listen_backlog = val;
 210         }
 211 
 212         propname = "max_connections"; /* also -c */
 213         ret = nfs_smf_get_iprop(propname, &val,
 214             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
 215         if (ret == SA_OK) {
 216                 if (val <= 0)
 217                         fprintf(stderr, gettext(
 218                             "Invalid %s from SMF"), propname);
 219                 else
 220                         max_conns_allowed = val;
 221         }
 222 
 223         propname = "max_servers"; /* also argv[1] */
 224         ret = nfs_smf_get_iprop(propname, &val,
 225             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
 226         if (ret == SA_OK) {
 227                 if (val <= 0)
 228                         fprintf(stderr, gettext(
 229                             "Invalid %s from SMF"), propname);
 230                 else
 231                         max_servers = val;
 232         }
 233 
 234         propname = "retrans_timeout"; /* also -r */
 235         ret = nfs_smf_get_iprop(propname, &val,
 236             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
 237         if (ret == SA_OK) {
 238                 if (val <= 0)
 239                         fprintf(stderr, gettext(
 240                             "Invalid %s from SMF"), propname);
 241                 else
 242                         lmargs.retransmittimeout = val;
 243         }
 244 
 245 
 246         while ((c = getopt(ac, av, "c:d:g:l:r:t:")) != EOF)
 247                 switch (c) {
 248                 case 'c': /* max_connections */
 249                         if ((val = atoi(optarg)) <= 0)
 250                                 goto badval;
 251                         max_conns_allowed = val;
 252                         break;
 253 
 254                 case 'd': /* debug */
 255                         lmargs.debug = atoi(optarg);
 256                         break;
 257 
 258                 case 'g': /* grace_period */
 259                         if ((val = atoi(optarg)) <= 0)
 260                                 goto badval;
 261                         lmargs.grace = val;
 262                         break;
 263 
 264                 case 'l': /* listen_backlog */
 265                         if ((val = atoi(optarg)) <= 0)
 266                                 goto badval;
 267                         listen_backlog = val;
 268                         break;
 269 
 270                 case 'r': /* retrans_timeout */
 271                         if ((val = atoi(optarg)) <= 0)
 272                                 goto badval;
 273                         lmargs.retransmittimeout = val;
 274                         break;
 275 
 276                 case 't': /* conn_idle_timeout */
 277                         if ((val = atoi(optarg)) <= 0)
 278                                 goto badval;
 279                         lmargs.timout = val;
 280                         break;
 281 
 282                 badval:
 283                         fprintf(stderr, gettext(
 284                             "Invalid -%c option value"), c);
 285                         /* FALLTHROUGH */
 286                 default:
 287                         usage();
 288                         /* NOTREACHED */
 289                 }
 290 
 291         /*
 292          * If there is exactly one more argument, it is the number of
 293          * servers.
 294          */
 295         if (optind < ac) {
 296                 val = atoi(av[optind]);
 297                 if (val <= 0) {
 298                         fprintf(stderr, gettext(
 299                             "Invalid max_servers argument"));
 300                         usage();
 301                 }
 302                 max_servers = val;
 303                 optind++;
 304         }
 305         /*
 306          * If there are two or more arguments, then this is a usage error.
 307          */
 308         if (optind != ac)
 309                 usage();
 310 
 311         if (lmargs.debug) {
 312                 printf("%s: debug= %d, conn_idle_timout= %d,"
 313                     " grace_period= %d, listen_backlog= %d,"
 314                     " max_connections= %d, max_servers= %d,"
 315                     " retrans_timeout= %d\n",
 316                     MyName, lmargs.debug, lmargs.timout,
 317                     lmargs.grace, listen_backlog,
 318                     max_conns_allowed, max_servers,
 319                     lmargs.retransmittimeout);
 320         }
 321 
 322         /*
 323          * Set current dir to server root
 324          */
 325         if (chdir(dir) < 0) {
 326                 (void) fprintf(stderr, "%s:  ", MyName);
 327                 perror(dir);
 328                 exit(1);
 329         }
 330 
 331         /* Daemonize, if not debug. */
 332         if (lmargs.debug == 0)
 333                 pipe_fd = daemonize_init();
 334 
 335         openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
 336 
 337         /*
 338          * establish our lock on the lock file and write our pid to it.
 339          * exit if some other process holds the lock, or if there's any
 340          * error in writing/locking the file.
 341          */
 342         pid = _enter_daemon_lock(LOCKD);
 343         switch (pid) {
 344         case 0:
 345                 break;
 346         case -1:
 347                 fprintf(stderr, "error locking for %s: %s", LOCKD,
 348                     strerror(errno));
 349                 exit(2);
 350         default:
 351                 /* daemon was already running */
 352                 exit(0);
 353         }
 354 
 355         /*
 356          * Block all signals till we spawn other
 357          * threads.
 358          */
 359         (void) sigfillset(&sgset);
 360         (void) thr_sigsetmask(SIG_BLOCK, &sgset, NULL);
 361 
 362         /* Unregister any previous versions. */
 363         for (i = NLM_VERS; i < NLM4_VERS; i++) {
 364                 svc_unreg(NLM_PROG, i);
 365         }
 366 
 367         /*
 368          * Set up kernel RPC thread pool for the NLM server.
 369          */
 370         if (nlmsvcpool(max_servers)) {
 371                 fprintf(stderr, "Can't set up kernel NLM service: %s. Exiting",
 372                     strerror(errno));
 373                 exit(1);
 374         }
 375 
 376         /*
 377          * Set up blocked thread to do LWP creation on behalf of the kernel.
 378          */
 379         if (svcwait(NLM_SVCPOOL_ID)) {
 380                 fprintf(stderr, "Can't set up NLM pool creator: %s. Exiting",
 381                     strerror(errno));
 382                 exit(1);
 383         }
 384 
 385         /*
 386          * Install atexit and sigterm handlers
 387          */
 388         act.sa_handler = sigterm_handler;
 389         act.sa_flags = 0;
 390 
 391         (void) sigaction(SIGTERM, &act, NULL);
 392         (void) atexit(shutdown_lockd);
 393 
 394         /*
 395          * Now open up for signal delivery
 396          */
 397         (void) thr_sigsetmask(SIG_UNBLOCK, &sgset, NULL);
 398 
 399         /*
 400          * Build a protocol block list for registration.
 401          */
 402         protobp = (struct protob *)malloc(sizeof (struct protob));
 403         protobp->serv = "NLM";
 404         protobp->versmin = NLM_VERS;
 405         protobp->versmax = NLM4_VERS;
 406         protobp->program = NLM_PROG;
 407         protobp->next = (struct protob *)NULL;
 408 
 409         for (providerp = defaultproviders;
 410             *providerp != NULL; providerp++) {
 411                 provider = *providerp;
 412                 do_one(provider, NULL, protobp, nlmsvc);
 413         }
 414 
 415         free(protobp);
 416 
 417         if (num_fds == 0) {
 418                 fprintf(stderr, "Could not start NLM service for any protocol."
 419                     " Exiting");
 420                 exit(1);
 421         }
 422 
 423         end_listen_fds = num_fds;
 424 
 425         /*
 426          * lockd is up and running as far as we are concerned.
 427          */
 428         if (lmargs.debug == 0)
 429                 daemonize_fini(pipe_fd);
 430 
 431         /*
 432          * Get rid of unneeded privileges.
 433          */
 434         __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
 435             PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
 436 
 437         /*
 438          * Poll for non-data control events on the transport descriptors.
 439          */
 440         poll_for_action();
 441 
 442         /*
 443          * If we get here, something failed in poll_for_action().
 444          */
 445         return (1);
 446 }
 447 
 448 static int
 449 nlmsvcpool(int maxservers)
 450 {
 451         struct svcpool_args npa;
 452 
 453         npa.id = NLM_SVCPOOL_ID;
 454         npa.maxthreads = maxservers;
 455         npa.redline = 0;
 456         npa.qsize = 0;
 457         npa.timeout = 0;
 458         npa.stksize = 0;
 459         npa.max_same_xprt = 0;
 460         return (_nfssys(SVCPOOL_CREATE, &npa));
 461 }
 462 
 463 static int
 464 ncfmly_to_lmfmly(const char *ncfmly)
 465 {
 466         if (0 == strcmp(ncfmly, NC_INET))
 467                 return (LM_INET);
 468         if (0 == strcmp(ncfmly, NC_INET6))
 469                 return (LM_INET6);
 470         if (0 == strcmp(ncfmly, NC_LOOPBACK))
 471                 return (LM_LOOPBACK);
 472         return (-1);
 473 }
 474 
 475 static int
 476 nctype_to_lmprot(uint_t semantics)
 477 {
 478         switch (semantics) {
 479         case NC_TPI_CLTS:
 480                 return (LM_UDP);
 481         case NC_TPI_COTS_ORD:
 482                 return (LM_TCP);
 483         }
 484         return (-1);
 485 }
 486 
 487 static dev_t
 488 ncdev_to_rdev(const char *ncdev)
 489 {
 490         struct stat st;
 491 
 492         if (stat(ncdev, &st) < 0)
 493                 return (NODEV);
 494         return (st.st_rdev);
 495 }
 496 
 497 static void
 498 sigterm_handler(void)
 499 {
 500         /* to call atexit handler */
 501         exit(0);
 502 }
 503 
 504 static void
 505 shutdown_lockd(void)
 506 {
 507         (void) _nfssys(KILL_LOCKMGR, NULL);
 508 }
 509 
 510 
 511 /*
 512  * Establish NLM service thread.
 513  */
 514 static int
 515 nlmsvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
 516 {
 517         struct lm_svc_args lma;
 518 
 519         lma = lmargs; /* init by struct copy */
 520 
 521         /*
 522          * The kernel code needs to reconstruct a complete
 523          * knetconfig from n_fmly, n_proto.  We use these
 524          * two fields to convey the family and semantics.
 525          */
 526         lma.fd = fd;
 527         lma.n_fmly = ncfmly_to_lmfmly(nconf->nc_protofmly);
 528         lma.n_proto = nctype_to_lmprot(nconf->nc_semantics);
 529         lma.n_rdev = ncdev_to_rdev(nconf->nc_device);
 530 
 531         return (_nfssys(LM_SVC, &lma));
 532 }
 533 
 534 static void
 535 usage(void)
 536 {
 537         (void) fprintf(stderr, gettext(
 538             "usage: %s [options] [max_servers]\n"), MyName);
 539         (void) fprintf(stderr, gettext(
 540             "options:  (see SMF property descriptions)\n"));
 541         /* Note: don't translate these */
 542         (void) fprintf(stderr, "\t-c max_connections\n");
 543         (void) fprintf(stderr, "\t-d debug_level\n");
 544         (void) fprintf(stderr, "\t-g grace_period\n");
 545         (void) fprintf(stderr, "\t-l listen_backlog\n");
 546         (void) fprintf(stderr, "\t-r retrans_timeout\n");
 547         (void) fprintf(stderr, "\t-t conn_idle_timeout\n");
 548 
 549         exit(1);
 550 }