Print this page
7569 statd support to run on a fixed port
Portions contributed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>


   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 2015 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.


  25  */
  26 
  27 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 /*
  31  * University Copyright- Copyright (c) 1982, 1986, 1988
  32  * The Regents of the University of California
  33  * All Rights Reserved
  34  *
  35  * University Acknowledgment- Portions of this document are derived from
  36  * software developed by the University of California, Berkeley, and its
  37  * contributors.
  38  */
  39 
  40 /*
  41  * Copyright (c) 2012 by Delphix. All rights reserved.
  42  */
  43 
  44 #include <stdio.h>
  45 #include <stdio_ext.h>
  46 #include <stdlib.h>
  47 #include <ftw.h>
  48 #include <signal.h>
  49 #include <string.h>
  50 #include <syslog.h>
  51 #include <netconfig.h>

  52 #include <unistd.h>
  53 #include <netdb.h>
  54 #include <rpc/rpc.h>

  55 #include <netinet/in.h>
  56 #include <sys/param.h>
  57 #include <sys/resource.h>
  58 #include <sys/file.h>
  59 #include <sys/types.h>
  60 #include <sys/stat.h>
  61 #include <sys/sockio.h>
  62 #include <dirent.h>
  63 #include <errno.h>
  64 #include <rpcsvc/sm_inter.h>
  65 #include <rpcsvc/nsm_addr.h>
  66 #include <thread.h>
  67 #include <synch.h>
  68 #include <net/if.h>
  69 #include <limits.h>
  70 #include <rpcsvc/daemon_utils.h>
  71 #include <priv_utils.h>

  72 #include "sm_statd.h"
  73 
  74 
  75 #define home0           "/var/statmon"
  76 #define current0        "/var/statmon/sm"
  77 #define backup0         "/var/statmon/sm.bak"
  78 #define state0          "/var/statmon/state"
  79 
  80 #define home1           "statmon"
  81 #define current1        "statmon/sm/"
  82 #define backup1         "statmon/sm.bak/"
  83 #define state1          "statmon/state"
  84 
  85 extern int      daemonize_init(void);
  86 extern void     daemonize_fini(int fd);
  87 
  88 /*
  89  * User and group IDs to run as.  These are hardwired, rather than looked
  90  * up at runtime, because they are very unlikely to change and because they
  91  * provide some protection against bogus changes to the passwd and group
  92  * files.
  93  */
  94 uid_t   daemon_uid = DAEMON_UID;
  95 gid_t   daemon_gid = DAEMON_GID;
  96 
  97 char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN];
  98 static char statd_home[MAXPATHLEN];
  99 
 100 int debug;
 101 int regfiles_only = 0;          /* 1 => use symlinks in statmon, 0 => don't */

 102 char hostname[MAXHOSTNAMELEN];
 103 
 104 /*
 105  * These variables will be used to store all the
 106  * alias names for the host, as well as the -a
 107  * command line hostnames.
 108  */
 109 int host_name_count;
 110 char **host_name; /* store -a opts */
 111 int  addrix; /* # of -a entries */
 112 
 113 
 114 /*
 115  * The following 2 variables are meaningful
 116  * only under a HA configuration.
 117  * The path_name array is dynamically allocated in main() during
 118  * command line argument processing for the -p options.
 119  */
 120 char **path_name = NULL;  /* store -p opts */
 121 int  pathix = 0;  /* # of -p entries */


 440 {
 441         /*
 442          * Get other aliases from each interface.
 443          */
 444         merge_hosts();
 445 
 446         /*
 447          * Get all of the configured IP addresses.
 448          */
 449         merge_ips();
 450 
 451         /*
 452          * Notify the waiters.
 453          */
 454         (void) mutex_lock(&merges_lock);
 455         in_merges = B_FALSE;
 456         (void) cond_broadcast(&merges_cond);
 457         (void) mutex_unlock(&merges_lock);
 458 }
 459 








































































 460 int
 461 main(int argc, char *argv[])
 462 {
 463         int c;
 464         int ppid;
 465         extern char *optarg;
 466         int choice = 0;
 467         struct rlimit rl;
 468         int mode;
 469         int sz;
 470         int pipe_fd = -1;

 471         int connmaxrec = RPC_MAXDATASIZE;


 472 
 473         addrix = 0;
 474         pathix = 0;
 475 
 476         (void) gethostname(hostname, MAXHOSTNAMELEN);
 477         if (init_hostname() < 0)
 478                 exit(1);
 479 
 480         while ((c = getopt(argc, argv, "Dd:a:G:p:rU:")) != EOF)







 481                 switch (c) {
 482                 case 'd':
 483                         (void) sscanf(optarg, "%d", &debug);
 484                         break;
 485                 case 'D':
 486                         choice = 1;
 487                         break;
 488                 case 'a':
 489                         if (addrix < host_name_count) {
 490                                 if (strcmp(hostname, optarg) != 0) {
 491                                         sz = strlen(optarg);
 492                                         if (sz < MAXHOSTNAMELEN) {
 493                                                 host_name[addrix] =
 494                                                     (char *)xmalloc(sz+1);
 495                                                 if (host_name[addrix] !=
 496                                                     NULL) {
 497                                                 (void) sscanf(optarg, "%s",
 498                                                     host_name[addrix]);
 499                                                         addrix++;
 500                                                 }


 525                                 /* arguments are -p options, which would   */
 526                                 /* actually never be the case.             */
 527                                 if (path_name == NULL) {
 528                                         size_t sz = (argc/2) * sizeof (char *);
 529 
 530                                         path_name = (char **)malloc(sz);
 531                                         if (path_name == NULL) {
 532                                                 (void) fprintf(stderr,
 533                                                 "statd: malloc failed\n");
 534                                                 exit(1);
 535                                         }
 536                                         (void) memset(path_name, 0, sz);
 537                                 }
 538                                 path_name[pathix] = optarg;
 539                                 pathix++;
 540                         } else {
 541                                 (void) fprintf(stderr,
 542                                 "statd: -p pathname is too long.\n");
 543                         }
 544                         break;








 545                 case 'r':
 546                         regfiles_only = 1;
 547                         break;
 548                 default:
 549                         (void) fprintf(stderr,
 550                         "statd [-d level] [-D]\n");
 551                         return (1);
 552                 }
 553 
 554         if (choice == 0) {
 555                 (void) strcpy(statd_home, home0);
 556                 (void) strcpy(CURRENT, current0);
 557                 (void) strcpy(BACKUP, backup0);
 558                 (void) strcpy(STATE, state0);
 559         } else {
 560                 (void) strcpy(statd_home, home1);
 561                 (void) strcpy(CURRENT, current1);
 562                 (void) strcpy(BACKUP, backup1);
 563                 (void) strcpy(STATE, state1);
 564         }


 619 
 620         /*
 621          * Set to automatic mode such that threads are automatically
 622          * created
 623          */
 624         mode = RPC_SVC_MT_AUTO;
 625         if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) {
 626                 syslog(LOG_ERR,
 627                     "statd:unable to set automatic MT mode.");
 628                 exit(1);
 629         }
 630 
 631         /*
 632          * Set non-blocking mode and maximum record size for
 633          * connection oriented RPC transports.
 634          */
 635         if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
 636                 syslog(LOG_INFO, "unable to set maximum RPC record size");
 637         }
 638 
 639         if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) {
 640                 syslog(LOG_ERR, "statd: unable to create (SM_PROG, SM_VERS) "
 641                     "for netpath.");
 642                 exit(1);



 643         }

 644 
 645         if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) {
 646                 syslog(LOG_ERR, "statd: unable to create (NSM_ADDR_PROGRAM, "
 647                     "NSM_ADDR_V1) for netpath.");








 648         }

 649 
 650         /*
 651          * Make sure /var/statmon and any alternate (-p) statmon
 652          * directories exist and are owned by daemon.  Then change our uid
 653          * to daemon.  The uid change is to prevent attacks against local
 654          * daemons that trust any call from a local root process.
 655          */
 656 
 657         set_statmon_owner();
 658 
 659         /*
 660          *
 661          * statd now runs as a daemon rather than root and can not
 662          * dump core under / because of the permission. It is
 663          * important that current working directory of statd be
 664          * changed to writable directory /var/statmon so that it
 665          * can dump the core upon the receipt of the signal.
 666          * One still need to set allow_setid_core to non-zero in
 667          * /etc/system to get the core dump.
 668          *




   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, 2016 by Delphix. All rights reserved.
  25  * Copyright 2016 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 #include <stdio.h>
  42 #include <stdio_ext.h>
  43 #include <stdlib.h>
  44 #include <ftw.h>
  45 #include <signal.h>
  46 #include <string.h>
  47 #include <syslog.h>
  48 #include <netconfig.h>
  49 #include <netdir.h>
  50 #include <unistd.h>
  51 #include <netdb.h>
  52 #include <rpc/rpc.h>
  53 #include <rpc/svc.h>
  54 #include <netinet/in.h>
  55 #include <sys/param.h>
  56 #include <sys/resource.h>
  57 #include <sys/file.h>
  58 #include <sys/types.h>
  59 #include <sys/stat.h>
  60 #include <sys/sockio.h>
  61 #include <dirent.h>
  62 #include <errno.h>
  63 #include <rpcsvc/sm_inter.h>
  64 #include <rpcsvc/nsm_addr.h>
  65 #include <thread.h>
  66 #include <synch.h>
  67 #include <net/if.h>
  68 #include <limits.h>
  69 #include <rpcsvc/daemon_utils.h>
  70 #include <priv_utils.h>
  71 #include "smfcfg.h"
  72 #include "sm_statd.h"
  73 
  74 
  75 #define home0           "/var/statmon"
  76 #define current0        "/var/statmon/sm"
  77 #define backup0         "/var/statmon/sm.bak"
  78 #define state0          "/var/statmon/state"
  79 
  80 #define home1           "statmon"
  81 #define current1        "statmon/sm/"
  82 #define backup1         "statmon/sm.bak/"
  83 #define state1          "statmon/state"
  84 
  85 extern int      daemonize_init(void);
  86 extern void     daemonize_fini(int fd);
  87 
  88 /*
  89  * User and group IDs to run as.  These are hardwired, rather than looked
  90  * up at runtime, because they are very unlikely to change and because they
  91  * provide some protection against bogus changes to the passwd and group
  92  * files.
  93  */
  94 uid_t   daemon_uid = DAEMON_UID;
  95 gid_t   daemon_gid = DAEMON_GID;
  96 
  97 char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN];
  98 static char statd_home[MAXPATHLEN];
  99 
 100 int debug;
 101 int regfiles_only = 0;          /* 1 => use symlinks in statmon, 0 => don't */
 102 int statd_port = 0;
 103 char hostname[MAXHOSTNAMELEN];
 104 
 105 /*
 106  * These variables will be used to store all the
 107  * alias names for the host, as well as the -a
 108  * command line hostnames.
 109  */
 110 int host_name_count;
 111 char **host_name; /* store -a opts */
 112 int  addrix; /* # of -a entries */
 113 
 114 
 115 /*
 116  * The following 2 variables are meaningful
 117  * only under a HA configuration.
 118  * The path_name array is dynamically allocated in main() during
 119  * command line argument processing for the -p options.
 120  */
 121 char **path_name = NULL;  /* store -p opts */
 122 int  pathix = 0;  /* # of -p entries */


 441 {
 442         /*
 443          * Get other aliases from each interface.
 444          */
 445         merge_hosts();
 446 
 447         /*
 448          * Get all of the configured IP addresses.
 449          */
 450         merge_ips();
 451 
 452         /*
 453          * Notify the waiters.
 454          */
 455         (void) mutex_lock(&merges_lock);
 456         in_merges = B_FALSE;
 457         (void) cond_broadcast(&merges_cond);
 458         (void) mutex_unlock(&merges_lock);
 459 }
 460 
 461 /*
 462  * This function is called for each configured network type to
 463  * bind and register our RPC service programs.
 464  *
 465  * On TCP or UDP, we may want to bind SM_PROG on a specific port
 466  * (when statd_port is specified) in which case we'll use the
 467  * variant of svc_tp_create() that lets us pass a bind address.
 468  */
 469 static void
 470 sm_svc_tp_create(struct netconfig *nconf)
 471 {
 472         char port_str[8];
 473         struct nd_hostserv hs;
 474         struct nd_addrlist *al = NULL;
 475         SVCXPRT *xprt = NULL;
 476 
 477         /*
 478          * If statd_port is set and this is an inet transport,
 479          * bind this service on the specified port.  The TLI way
 480          * to create such a bind address is netdir_getbyname()
 481          * with the special "host" HOST_SELF_BIND.  This builds
 482          * an all-zeros IP address with the specified port.
 483          */
 484         if (statd_port != 0 &&
 485             (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
 486             strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
 487                 int err;
 488 
 489                 snprintf(port_str, sizeof (port_str), "%u",
 490                     (unsigned short)statd_port);
 491 
 492                 hs.h_host = HOST_SELF_BIND;
 493                 hs.h_serv = port_str;
 494                 err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
 495                 if (err == 0 && al != NULL) {
 496                         xprt = svc_tp_create_addr(sm_prog_1, SM_PROG, SM_VERS,
 497                             nconf, al->n_addrs);
 498                         netdir_free(al, ND_ADDRLIST);
 499                 }
 500                 if (xprt == NULL) {
 501                         syslog(LOG_ERR, "statd: unable to create "
 502                             "(SM_PROG, SM_VERS) on transport %s (port %d)",
 503                             nconf->nc_netid, statd_port);
 504                 }
 505                 /* fall-back to default bind */
 506         }
 507         if (xprt == NULL) {
 508                 /*
 509                  * Had statd_port=0, or non-inet transport,
 510                  * or the bind to a specific port failed.
 511                  * Do a default bind.
 512                  */
 513                 xprt = svc_tp_create(sm_prog_1, SM_PROG, SM_VERS, nconf);
 514         }
 515         if (xprt == NULL) {
 516                 syslog(LOG_ERR, "statd: unable to create "
 517                     "(SM_PROG, SM_VERS) for transport %s",
 518                     nconf->nc_netid);
 519                 return;
 520         }
 521 
 522         /*
 523          * Also register the NSM_ADDR program on this
 524          * transport handle (same dispatch function).
 525          */
 526         if (!svc_reg(xprt, NSM_ADDR_PROGRAM, NSM_ADDR_V1, sm_prog_1, nconf)) {
 527                 syslog(LOG_ERR, "statd: failed to register "
 528                     "(NSM_ADDR_PROGRAM, NSM_ADDR_V1) for "
 529                     "netconfig %s", nconf->nc_netid);
 530         }
 531 }
 532 
 533 int
 534 main(int argc, char *argv[])
 535 {
 536         int c;
 537         int ppid;
 538         extern char *optarg;
 539         int choice = 0;
 540         struct rlimit rl;
 541         int mode;
 542         int sz;
 543         int pipe_fd = -1;
 544         int ret;
 545         int connmaxrec = RPC_MAXDATASIZE;
 546         struct netconfig *nconf;
 547         NCONF_HANDLE *nc;
 548 
 549         addrix = 0;
 550         pathix = 0;
 551 
 552         (void) gethostname(hostname, MAXHOSTNAMELEN);
 553         if (init_hostname() < 0)
 554                 exit(1);
 555 
 556         ret = nfs_smf_get_iprop("statd_port", &statd_port,
 557             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, STATD);
 558         if (ret != SA_OK) {
 559                 syslog(LOG_ERR, "Reading of statd_port from SMF "
 560                     "failed, using default value");
 561         }
 562 
 563         while ((c = getopt(argc, argv, "Dd:a:G:p:P:rU:")) != EOF)
 564                 switch (c) {
 565                 case 'd':
 566                         (void) sscanf(optarg, "%d", &debug);
 567                         break;
 568                 case 'D':
 569                         choice = 1;
 570                         break;
 571                 case 'a':
 572                         if (addrix < host_name_count) {
 573                                 if (strcmp(hostname, optarg) != 0) {
 574                                         sz = strlen(optarg);
 575                                         if (sz < MAXHOSTNAMELEN) {
 576                                                 host_name[addrix] =
 577                                                     (char *)xmalloc(sz+1);
 578                                                 if (host_name[addrix] !=
 579                                                     NULL) {
 580                                                 (void) sscanf(optarg, "%s",
 581                                                     host_name[addrix]);
 582                                                         addrix++;
 583                                                 }


 608                                 /* arguments are -p options, which would   */
 609                                 /* actually never be the case.             */
 610                                 if (path_name == NULL) {
 611                                         size_t sz = (argc/2) * sizeof (char *);
 612 
 613                                         path_name = (char **)malloc(sz);
 614                                         if (path_name == NULL) {
 615                                                 (void) fprintf(stderr,
 616                                                 "statd: malloc failed\n");
 617                                                 exit(1);
 618                                         }
 619                                         (void) memset(path_name, 0, sz);
 620                                 }
 621                                 path_name[pathix] = optarg;
 622                                 pathix++;
 623                         } else {
 624                                 (void) fprintf(stderr,
 625                                     "statd: -p pathname is too long.\n");
 626                         }
 627                         break;
 628                 case 'P':
 629                         (void) sscanf(optarg, "%d", &statd_port);
 630                         if (statd_port < 1 || statd_port > UINT16_MAX) {
 631                                 (void) fprintf(stderr,
 632                                     "statd: -P port invalid.\n");
 633                                 statd_port = 0;
 634                         }
 635                         break;
 636                 case 'r':
 637                         regfiles_only = 1;
 638                         break;
 639                 default:
 640                         (void) fprintf(stderr,
 641                             "statd [-d level] [-D]\n");
 642                         return (1);
 643                 }
 644 
 645         if (choice == 0) {
 646                 (void) strcpy(statd_home, home0);
 647                 (void) strcpy(CURRENT, current0);
 648                 (void) strcpy(BACKUP, backup0);
 649                 (void) strcpy(STATE, state0);
 650         } else {
 651                 (void) strcpy(statd_home, home1);
 652                 (void) strcpy(CURRENT, current1);
 653                 (void) strcpy(BACKUP, backup1);
 654                 (void) strcpy(STATE, state1);
 655         }


 710 
 711         /*
 712          * Set to automatic mode such that threads are automatically
 713          * created
 714          */
 715         mode = RPC_SVC_MT_AUTO;
 716         if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) {
 717                 syslog(LOG_ERR,
 718                     "statd:unable to set automatic MT mode.");
 719                 exit(1);
 720         }
 721 
 722         /*
 723          * Set non-blocking mode and maximum record size for
 724          * connection oriented RPC transports.
 725          */
 726         if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
 727                 syslog(LOG_INFO, "unable to set maximum RPC record size");
 728         }
 729 
 730         /*
 731          * Enumerate network transports and create service listeners
 732          * as appropriate for each.
 733          */
 734         if ((nc = setnetconfig()) == NULL) {
 735                 syslog(LOG_ERR, "setnetconfig failed: %m");
 736                 return (-1);
 737         }
 738         while ((nconf = getnetconfig(nc)) != NULL) {
 739 
 740                 /*
 741                  * Skip things like tpi_raw, invisible...
 742                  */
 743                 if ((nconf->nc_flag & NC_VISIBLE) == 0)
 744                         continue;
 745                 if (nconf->nc_semantics != NC_TPI_CLTS &&
 746                     nconf->nc_semantics != NC_TPI_COTS &&
 747                     nconf->nc_semantics != NC_TPI_COTS_ORD)
 748                         continue;
 749 
 750                 sm_svc_tp_create(nconf);
 751         }
 752         (void) endnetconfig(nc);
 753 
 754         /*
 755          * Make sure /var/statmon and any alternate (-p) statmon
 756          * directories exist and are owned by daemon.  Then change our uid
 757          * to daemon.  The uid change is to prevent attacks against local
 758          * daemons that trust any call from a local root process.
 759          */
 760 
 761         set_statmon_owner();
 762 
 763         /*
 764          *
 765          * statd now runs as a daemon rather than root and can not
 766          * dump core under / because of the permission. It is
 767          * important that current working directory of statd be
 768          * changed to writable directory /var/statmon so that it
 769          * can dump the core upon the receipt of the signal.
 770          * One still need to set allow_setid_core to non-zero in
 771          * /etc/system to get the core dump.
 772          *