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 (c) 2012 by Delphix. All rights reserved.
  25  * Copyright 2014 Nexenta Systems, Inc.  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 = 90,
  94         .retransmittimeout = 5
  95 };
  96 int max_servers = 256;
  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 wait for clients to re-establish locks. */
 176         propname = "grace_period"; /* also -g */
 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.grace = val;
 185         } else {
 186                 syslog(LOG_ERR, "Reading of %s from SMF failed, using default "
 187                     "value", propname);
 188         }
 189 
 190         propname = "lockd_listen_backlog"; /* also -l */
 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                         listen_backlog = val;
 199         } else {
 200                 syslog(LOG_ERR, "Reading of %s from SMF failed, using default "
 201                     "value", propname);
 202         }
 203 
 204         propname = "lockd_servers"; /* also argv[1] */
 205         ret = nfs_smf_get_iprop(propname, &val,
 206             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
 207         if (ret == SA_OK) {
 208                 if (val <= 0)
 209                         fprintf(stderr, gettext(
 210                             "Invalid %s from SMF"), propname);
 211                 else
 212                         max_servers = val;
 213         } else {
 214                 syslog(LOG_ERR, "Reading of %s from SMF failed, using default "
 215                     "value", propname);
 216         }
 217 
 218         propname = "lockd_retransmit_timeout"; /* also -t */
 219         ret = nfs_smf_get_iprop(propname, &val,
 220             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
 221         if (ret == SA_OK) {
 222                 if (val <= 0)
 223                         fprintf(stderr, gettext(
 224                             "Invalid %s from SMF"), propname);
 225                 else
 226                         lmargs.retransmittimeout = val;
 227         } else {
 228                 syslog(LOG_ERR, "Reading of %s from SMF failed, using default "
 229                     "value", propname);
 230         }
 231 
 232         while ((c = getopt(ac, av, "c:d:g:l:t:")) != EOF)
 233                 switch (c) {
 234                 case 'c': /* max_connections */
 235                         if ((val = atoi(optarg)) <= 0)
 236                                 goto badval;
 237                         max_conns_allowed = val;
 238                         break;
 239 
 240                 case 'd': /* debug */
 241                         lmargs.debug = atoi(optarg);
 242                         break;
 243 
 244                 case 'g': /* grace_period */
 245                         if ((val = atoi(optarg)) <= 0)
 246                                 goto badval;
 247                         lmargs.grace = val;
 248                         break;
 249 
 250                 case 'l': /* listen_backlog */
 251                         if ((val = atoi(optarg)) <= 0)
 252                                 goto badval;
 253                         listen_backlog = val;
 254                         break;
 255 
 256                 case 't': /* retrans_timeout */
 257                         if ((val = atoi(optarg)) <= 0)
 258                                 goto badval;
 259                         lmargs.retransmittimeout = val;
 260                         break;
 261 
 262                 badval:
 263                         fprintf(stderr, gettext(
 264                             "Invalid -%c option value"), c);
 265                         /* FALLTHROUGH */
 266                 default:
 267                         usage();
 268                         /* NOTREACHED */
 269                 }
 270 
 271         /*
 272          * If there is exactly one more argument, it is the number of
 273          * servers.
 274          */
 275         if (optind < ac) {
 276                 val = atoi(av[optind]);
 277                 if (val <= 0) {
 278                         fprintf(stderr, gettext(
 279                             "Invalid max_servers argument"));
 280                         usage();
 281                 }
 282                 max_servers = val;
 283                 optind++;
 284         }
 285         /*
 286          * If there are two or more arguments, then this is a usage error.
 287          */
 288         if (optind != ac)
 289                 usage();
 290 
 291         if (lmargs.debug) {
 292                 printf("%s: debug= %d, conn_idle_timout= %d,"
 293                     " grace_period= %d, listen_backlog= %d,"
 294                     " max_connections= %d, max_servers= %d,"
 295                     " retrans_timeout= %d\n",
 296                     MyName, lmargs.debug, lmargs.timout,
 297                     lmargs.grace, listen_backlog,
 298                     max_conns_allowed, max_servers,
 299                     lmargs.retransmittimeout);
 300         }
 301 
 302         /*
 303          * Set current dir to server root
 304          */
 305         if (chdir(dir) < 0) {
 306                 (void) fprintf(stderr, "%s:  ", MyName);
 307                 perror(dir);
 308                 exit(1);
 309         }
 310 
 311         /* Daemonize, if not debug. */
 312         if (lmargs.debug == 0)
 313                 pipe_fd = daemonize_init();
 314 
 315         openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
 316 
 317         /*
 318          * establish our lock on the lock file and write our pid to it.
 319          * exit if some other process holds the lock, or if there's any
 320          * error in writing/locking the file.
 321          */
 322         pid = _enter_daemon_lock(LOCKD);
 323         switch (pid) {
 324         case 0:
 325                 break;
 326         case -1:
 327                 fprintf(stderr, "error locking for %s: %s", LOCKD,
 328                     strerror(errno));
 329                 exit(2);
 330         default:
 331                 /* daemon was already running */
 332                 exit(0);
 333         }
 334 
 335         /*
 336          * Block all signals till we spawn other
 337          * threads.
 338          */
 339         (void) sigfillset(&sgset);
 340         (void) thr_sigsetmask(SIG_BLOCK, &sgset, NULL);
 341 
 342         /* Unregister any previous versions. */
 343         for (i = NLM_VERS; i < NLM4_VERS; i++) {
 344                 svc_unreg(NLM_PROG, i);
 345         }
 346 
 347         /*
 348          * Set up kernel RPC thread pool for the NLM server.
 349          */
 350         if (nlmsvcpool(max_servers)) {
 351                 fprintf(stderr, "Can't set up kernel NLM service: %s. Exiting",
 352                     strerror(errno));
 353                 exit(1);
 354         }
 355 
 356         /*
 357          * Set up blocked thread to do LWP creation on behalf of the kernel.
 358          */
 359         if (svcwait(NLM_SVCPOOL_ID)) {
 360                 fprintf(stderr, "Can't set up NLM pool creator: %s. Exiting",
 361                     strerror(errno));
 362                 exit(1);
 363         }
 364 
 365         /*
 366          * Install atexit and sigterm handlers
 367          */
 368         act.sa_handler = sigterm_handler;
 369         act.sa_flags = 0;
 370 
 371         (void) sigaction(SIGTERM, &act, NULL);
 372         (void) atexit(shutdown_lockd);
 373 
 374         /*
 375          * Now open up for signal delivery
 376          */
 377         (void) thr_sigsetmask(SIG_UNBLOCK, &sgset, NULL);
 378 
 379         /*
 380          * Build a protocol block list for registration.
 381          */
 382         protobp = (struct protob *)malloc(sizeof (struct protob));
 383         protobp->serv = "NLM";
 384         protobp->versmin = NLM_VERS;
 385         protobp->versmax = NLM4_VERS;
 386         protobp->program = NLM_PROG;
 387         protobp->next = (struct protob *)NULL;
 388 
 389         for (providerp = defaultproviders;
 390             *providerp != NULL; providerp++) {
 391                 provider = *providerp;
 392                 do_one(provider, NULL, protobp, nlmsvc);
 393         }
 394 
 395         free(protobp);
 396 
 397         if (num_fds == 0) {
 398                 fprintf(stderr, "Could not start NLM service for any protocol."
 399                     " Exiting");
 400                 exit(1);
 401         }
 402 
 403         end_listen_fds = num_fds;
 404 
 405         /*
 406          * lockd is up and running as far as we are concerned.
 407          */
 408         if (lmargs.debug == 0)
 409                 daemonize_fini(pipe_fd);
 410 
 411         /*
 412          * Get rid of unneeded privileges.
 413          */
 414         __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
 415             PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
 416 
 417         /*
 418          * Poll for non-data control events on the transport descriptors.
 419          */
 420         poll_for_action();
 421 
 422         /*
 423          * If we get here, something failed in poll_for_action().
 424          */
 425         return (1);
 426 }
 427 
 428 static int
 429 nlmsvcpool(int maxservers)
 430 {
 431         struct svcpool_args npa;
 432 
 433         npa.id = NLM_SVCPOOL_ID;
 434         npa.maxthreads = maxservers;
 435         npa.redline = 0;
 436         npa.qsize = 0;
 437         npa.timeout = 0;
 438         npa.stksize = 0;
 439         npa.max_same_xprt = 0;
 440         return (_nfssys(SVCPOOL_CREATE, &npa));
 441 }
 442 
 443 static int
 444 ncfmly_to_lmfmly(const char *ncfmly)
 445 {
 446         if (0 == strcmp(ncfmly, NC_INET))
 447                 return (LM_INET);
 448         if (0 == strcmp(ncfmly, NC_INET6))
 449                 return (LM_INET6);
 450         if (0 == strcmp(ncfmly, NC_LOOPBACK))
 451                 return (LM_LOOPBACK);
 452         return (-1);
 453 }
 454 
 455 static int
 456 nctype_to_lmprot(uint_t semantics)
 457 {
 458         switch (semantics) {
 459         case NC_TPI_CLTS:
 460                 return (LM_UDP);
 461         case NC_TPI_COTS_ORD:
 462                 return (LM_TCP);
 463         }
 464         return (-1);
 465 }
 466 
 467 static dev_t
 468 ncdev_to_rdev(const char *ncdev)
 469 {
 470         struct stat st;
 471 
 472         if (stat(ncdev, &st) < 0)
 473                 return (NODEV);
 474         return (st.st_rdev);
 475 }
 476 
 477 static void
 478 sigterm_handler(void)
 479 {
 480         /* to call atexit handler */
 481         exit(0);
 482 }
 483 
 484 static void
 485 shutdown_lockd(void)
 486 {
 487         (void) _nfssys(KILL_LOCKMGR, NULL);
 488 }
 489 
 490 
 491 /*
 492  * Establish NLM service thread.
 493  */
 494 static int
 495 nlmsvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
 496 {
 497         struct lm_svc_args lma;
 498 
 499         lma = lmargs; /* init by struct copy */
 500 
 501         /*
 502          * The kernel code needs to reconstruct a complete
 503          * knetconfig from n_fmly, n_proto.  We use these
 504          * two fields to convey the family and semantics.
 505          */
 506         lma.fd = fd;
 507         lma.n_fmly = ncfmly_to_lmfmly(nconf->nc_protofmly);
 508         lma.n_proto = nctype_to_lmprot(nconf->nc_semantics);
 509         lma.n_rdev = ncdev_to_rdev(nconf->nc_device);
 510 
 511         return (_nfssys(LM_SVC, &lma));
 512 }
 513 
 514 static void
 515 usage(void)
 516 {
 517         (void) fprintf(stderr, gettext(
 518             "usage: %s [options] [max_servers]\n"), MyName);
 519         (void) fprintf(stderr, gettext(
 520             "options:  (see SMF property descriptions)\n"));
 521         /* Note: don't translate these */
 522         (void) fprintf(stderr, "\t-c max_connections\n");
 523         (void) fprintf(stderr, "\t-d debug_level\n");
 524         (void) fprintf(stderr, "\t-g grace_period\n");
 525         (void) fprintf(stderr, "\t-l listen_backlog\n");
 526         (void) fprintf(stderr, "\t-t retransmit_timeout\n");
 527 
 528         exit(1);
 529 }