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, 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 */
 123 
 124 /* Global variables.  Refer to sm_statd.h for description */
 125 mutex_t crash_lock;
 126 int die;
 127 int in_crash;
 128 mutex_t sm_trylock;
 129 rwlock_t thr_rwlock;
 130 cond_t retrywait;
 131 mutex_t name_addrlock;
 132 
 133 mutex_t merges_lock;
 134 cond_t merges_cond;
 135 boolean_t in_merges;
 136 
 137 /* forward references */
 138 static void set_statmon_owner(void);
 139 static void copy_client_names(void);
 140 static void one_statmon_owner(const char *);
 141 static int nftw_owner(const char *, const struct stat *, int, struct FTW *);
 142 
 143 /*
 144  * statd protocol
 145  *      commands:
 146  *              SM_STAT
 147  *                      returns stat_fail to caller
 148  *              SM_MON
 149  *                      adds an entry to the monitor_q and the record_q.
 150  *                      This message is sent by the server lockd to the server
 151  *                      statd, to indicate that a new client is to be monitored.
 152  *                      It is also sent by the server lockd to the client statd
 153  *                      to indicate that a new server is to be monitored.
 154  *              SM_UNMON
 155  *                      removes an entry from the monitor_q and the record_q
 156  *              SM_UNMON_ALL
 157  *                      removes all entries from a particular host from the
 158  *                      monitor_q and the record_q.  Our statd has this
 159  *                      disabled.
 160  *              SM_SIMU_CRASH
 161  *                      simulate a crash.  Removes everything from the
 162  *                      record_q and the recovery_q, then calls statd_init()
 163  *                      to restart things.  This message is sent by the server
 164  *                      lockd to the server statd to have all clients notified
 165  *                      that they should reclaim locks.
 166  *              SM_NOTIFY
 167  *                      Sent by statd on server to statd on client during
 168  *                      crash recovery.  The client statd passes the info
 169  *                      to its lockd so it can attempt to reclaim the locks
 170  *                      held on the server.
 171  *
 172  * There are three main hash tables used to keep track of things.
 173  *      mon_table
 174  *              table that keeps track hosts statd must watch.  If one of
 175  *              these hosts crashes, then any locks held by that host must
 176  *              be released.
 177  *      record_table
 178  *              used to keep track of all the hostname files stored in
 179  *              the directory /var/statmon/sm.  These are client hosts who
 180  *              are holding or have held a lock at some point.  Needed
 181  *              to determine if a file needs to be created for host in
 182  *              /var/statmon/sm.
 183  *      recov_q
 184  *              used to keep track hostnames during a recovery
 185  *
 186  * The entries are hashed based upon the name.
 187  *
 188  * There is a directory /var/statmon/sm which holds a file named
 189  * for each host that is holding (or has held) a lock.  This is
 190  * used during initialization on startup, or after a simulated
 191  * crash.
 192  */
 193 
 194 static void
 195 sm_prog_1(struct svc_req *rqstp, SVCXPRT *transp)
 196 {
 197         union {
 198                 struct sm_name sm_stat_1_arg;
 199                 struct mon sm_mon_1_arg;
 200                 struct mon_id sm_unmon_1_arg;
 201                 struct my_id sm_unmon_all_1_arg;
 202                 struct stat_chge ntf_arg;
 203                 struct reg1args reg1_arg;
 204         } argument;
 205 
 206         union {
 207                 sm_stat_res stat_resp;
 208                 sm_stat mon_resp;
 209                 struct reg1res reg1_resp;
 210         } result;
 211 
 212         bool_t (*xdr_argument)(), (*xdr_result)();
 213         char *(*local)();
 214 
 215         /*
 216          * Dispatch according to which protocol is being used:
 217          *      NSM_ADDR_PROGRAM is the private lockd address
 218          *              registration protocol.
 219          *      SM_PROG is the normal statd (NSM) protocol.
 220          */
 221         if (rqstp->rq_prog == NSM_ADDR_PROGRAM) {
 222                 switch (rqstp->rq_proc) {
 223                 case NULLPROC:
 224                         svc_sendreply(transp, xdr_void, (caddr_t)NULL);
 225                         return;
 226 
 227                 case NSMADDRPROC1_REG:
 228                         xdr_argument = xdr_reg1args;
 229                         xdr_result = xdr_reg1res;
 230                         local = (char *(*)()) nsmaddrproc1_reg;
 231                         break;
 232 
 233                 case NSMADDRPROC1_UNREG: /* Not impl. */
 234                 default:
 235                         svcerr_noproc(transp);
 236                         return;
 237                 }
 238         } else {
 239                 /* Must be SM_PROG */
 240                 switch (rqstp->rq_proc) {
 241                 case NULLPROC:
 242                         svc_sendreply(transp, xdr_void, (caddr_t)NULL);
 243                         return;
 244 
 245                 case SM_STAT:
 246                         xdr_argument = xdr_sm_name;
 247                         xdr_result = xdr_sm_stat_res;
 248                         local = (char *(*)()) sm_stat_svc;
 249                         break;
 250 
 251                 case SM_MON:
 252                         xdr_argument = xdr_mon;
 253                         xdr_result = xdr_sm_stat_res;
 254                         local = (char *(*)()) sm_mon_svc;
 255                         break;
 256 
 257                 case SM_UNMON:
 258                         xdr_argument = xdr_mon_id;
 259                         xdr_result = xdr_sm_stat;
 260                         local = (char *(*)()) sm_unmon_svc;
 261                         break;
 262 
 263                 case SM_UNMON_ALL:
 264                         xdr_argument = xdr_my_id;
 265                         xdr_result = xdr_sm_stat;
 266                         local = (char *(*)()) sm_unmon_all_svc;
 267                         break;
 268 
 269                 case SM_SIMU_CRASH:
 270                         xdr_argument = xdr_void;
 271                         xdr_result = xdr_void;
 272                         local = (char *(*)()) sm_simu_crash_svc;
 273                         break;
 274 
 275                 case SM_NOTIFY:
 276                         xdr_argument = xdr_stat_chge;
 277                         xdr_result = xdr_void;
 278                         local = (char *(*)()) sm_notify_svc;
 279                         break;
 280 
 281                 default:
 282                         svcerr_noproc(transp);
 283                         return;
 284                 }
 285         }
 286 
 287         (void) memset(&argument, 0, sizeof (argument));
 288         if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
 289                 svcerr_decode(transp);
 290                 return;
 291         }
 292 
 293         (void) memset(&result, 0, sizeof (result));
 294         (*local)(&argument, &result);
 295         if (!svc_sendreply(transp, xdr_result, (caddr_t)&result)) {
 296                 svcerr_systemerr(transp);
 297         }
 298 
 299         if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
 300                 syslog(LOG_ERR, "statd: unable to free arguments\n");
 301         }
 302 }
 303 
 304 /*
 305  * Remove all files under directory path_dir.
 306  */
 307 static int
 308 remove_dir(char *path_dir)
 309 {
 310         DIR     *dp;
 311         struct dirent   *dirp;
 312         char tmp_path[MAXPATHLEN];
 313 
 314         if ((dp = opendir(path_dir)) == NULL) {
 315                 if (debug)
 316                         syslog(LOG_ERR,
 317                             "warning: open directory %s failed: %m\n",
 318                             path_dir);
 319                 return (1);
 320         }
 321 
 322         while ((dirp = readdir(dp)) != NULL) {
 323                 if (strcmp(dirp->d_name, ".") != 0 &&
 324                     strcmp(dirp->d_name, "..") != 0) {
 325                         if (strlen(path_dir) + strlen(dirp->d_name) +2 >
 326                             MAXPATHLEN) {
 327 
 328                                 syslog(LOG_ERR, "statd: remove dir %s/%s "
 329                                     "failed.  Pathname too long.\n", path_dir,
 330                                     dirp->d_name);
 331 
 332                                 continue;
 333                         }
 334                         (void) strcpy(tmp_path, path_dir);
 335                         (void) strcat(tmp_path, "/");
 336                         (void) strcat(tmp_path, dirp->d_name);
 337                         delete_file(tmp_path);
 338                 }
 339         }
 340 
 341         (void) closedir(dp);
 342         return (0);
 343 }
 344 
 345 /*
 346  * Copy all files from directory `from_dir' to directory `to_dir'.
 347  * Symlinks, if any, are preserved.
 348  */
 349 void
 350 copydir_from_to(char *from_dir, char *to_dir)
 351 {
 352         int     n;
 353         DIR     *dp;
 354         struct dirent   *dirp;
 355         char rname[MAXNAMELEN + 1];
 356         char path[MAXPATHLEN+MAXNAMELEN+2];
 357 
 358         if ((dp = opendir(from_dir)) == NULL) {
 359                 if (debug)
 360                         syslog(LOG_ERR,
 361                             "warning: open directory %s failed: %m\n",
 362                             from_dir);
 363                 return;
 364         }
 365 
 366         while ((dirp = readdir(dp)) != NULL) {
 367                 if (strcmp(dirp->d_name, ".") == 0 ||
 368                     strcmp(dirp->d_name, "..") == 0) {
 369                         continue;
 370                 }
 371 
 372                 (void) strcpy(path, from_dir);
 373                 (void) strcat(path, "/");
 374                 (void) strcat(path, dirp->d_name);
 375 
 376                 if (is_symlink(path)) {
 377                         /*
 378                          * Follow the link to get the referenced file name
 379                          * and make a new link for that file in to_dir.
 380                          */
 381                         n = readlink(path, rname, MAXNAMELEN);
 382                         if (n <= 0) {
 383                                 if (debug >= 2) {
 384                                         (void) printf("copydir_from_to: can't "
 385                                             "read link %s\n", path);
 386                                 }
 387                                 continue;
 388                         }
 389                         rname[n] = '\0';
 390 
 391                         (void) create_symlink(to_dir, rname, dirp->d_name);
 392                 } else {
 393                         /*
 394                          * Simply copy regular files to to_dir.
 395                          */
 396                         (void) strcpy(path, to_dir);
 397                         (void) strcat(path, "/");
 398                         (void) strcat(path, dirp->d_name);
 399                         (void) create_file(path);
 400                 }
 401         }
 402 
 403         (void) closedir(dp);
 404 }
 405 
 406 static int
 407 init_hostname(void)
 408 {
 409         struct lifnum lifn;
 410         int sock;
 411 
 412         if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
 413                 syslog(LOG_ERR, "statd:init_hostname, socket: %m");
 414                 return (-1);
 415         }
 416 
 417         lifn.lifn_family = AF_UNSPEC;
 418         lifn.lifn_flags = 0;
 419 
 420         if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
 421                 syslog(LOG_ERR,
 422                 "statd:init_hostname, get number of interfaces, error: %m");
 423                 close(sock);
 424                 return (-1);
 425         }
 426 
 427         host_name_count = lifn.lifn_count;
 428 
 429         host_name = malloc(host_name_count * sizeof (char *));
 430         if (host_name == NULL) {
 431                 perror("statd -a can't get ip configuration\n");
 432                 close(sock);
 433                 return (-1);
 434         }
 435         close(sock);
 436         return (0);
 437 }
 438 
 439 static void
 440 thr_statd_merges(void)
 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                                                 }
 584                                         } else
 585                                         (void) fprintf(stderr,
 586                                     "statd: -a name of host is too long.\n");
 587                                 }
 588                         } else
 589                                 (void) fprintf(stderr,
 590                                     "statd: -a exceeding maximum hostnames\n");
 591                         break;
 592                 case 'U':
 593                         (void) sscanf(optarg, "%d", &daemon_uid);
 594                         break;
 595                 case 'G':
 596                         (void) sscanf(optarg, "%d", &daemon_gid);
 597                         break;
 598                 case 'p':
 599                         if (strlen(optarg) < MAXPATHLEN) {
 600                                 /* If the path_name array has not yet      */
 601                                 /* been malloc'ed, do that.  The array     */
 602                                 /* should be big enough to hold all of the */
 603                                 /* -p options we might have.  An upper     */
 604                                 /* bound on the number of -p options is    */
 605                                 /* argc/2, because each -p option consumes */
 606                                 /* two arguments.  Here the upper bound    */
 607                                 /* is supposing that all the command line  */
 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         }
 656         if (debug)
 657                 (void) printf("debug is on, create entry: %s, %s, %s\n",
 658                     CURRENT, BACKUP, STATE);
 659 
 660         if (getrlimit(RLIMIT_NOFILE, &rl))
 661                 (void) printf("statd: getrlimit failed. \n");
 662 
 663         /* Set maxfdlimit current soft limit */
 664         rl.rlim_cur = rl.rlim_max;
 665         if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
 666                 syslog(LOG_ERR, "statd: unable to set RLIMIT_NOFILE to %d\n",
 667                     rl.rlim_cur);
 668 
 669         (void) enable_extended_FILE_stdio(-1, -1);
 670 
 671         if (!debug) {
 672                 pipe_fd = daemonize_init();
 673 
 674                 openlog("statd", LOG_PID, LOG_DAEMON);
 675         }
 676 
 677         (void) _create_daemon_lock(STATD, daemon_uid, daemon_gid);
 678         /*
 679          * establish our lock on the lock file and write our pid to it.
 680          * exit if some other process holds the lock, or if there's any
 681          * error in writing/locking the file.
 682          */
 683         ppid = _enter_daemon_lock(STATD);
 684         switch (ppid) {
 685         case 0:
 686                 break;
 687         case -1:
 688                 syslog(LOG_ERR, "error locking for %s: %s", STATD,
 689                     strerror(errno));
 690                 exit(2);
 691         default:
 692                 /* daemon was already running */
 693                 exit(0);
 694         }
 695 
 696         mutex_init(&merges_lock, USYNC_THREAD, NULL);
 697         cond_init(&merges_cond, USYNC_THREAD, NULL);
 698         in_merges = B_TRUE;
 699 
 700         /*
 701          * Create thr_statd_merges() thread to populate the host_name list
 702          * asynchronously.
 703          */
 704         if (thr_create(NULL, 0, (void *(*)(void *))thr_statd_merges, NULL,
 705             THR_DETACHED, NULL) != 0) {
 706                 syslog(LOG_ERR, "statd: unable to create thread for "
 707                     "thr_statd_merges().");
 708                 exit(1);
 709         }
 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          *
 773          */
 774 
 775         if (chdir(statd_home) < 0) {
 776                 syslog(LOG_ERR, "can't chdir %s: %m", statd_home);
 777                 exit(1);
 778         }
 779 
 780         copy_client_names();
 781 
 782         rwlock_init(&thr_rwlock, USYNC_THREAD, NULL);
 783         mutex_init(&crash_lock, USYNC_THREAD, NULL);
 784         mutex_init(&name_addrlock, USYNC_THREAD, NULL);
 785         cond_init(&retrywait, USYNC_THREAD, NULL);
 786         sm_inithash();
 787         die = 0;
 788         /*
 789          * This variable is set to ensure that an sm_crash
 790          * request will not be done at the same time
 791          * when a statd_init is being done, since sm_crash
 792          * can reset some variables that statd_init will be using.
 793          */
 794         in_crash = 1;
 795         statd_init();
 796 
 797         /*
 798          * statd is up and running as far as we are concerned.
 799          */
 800         daemonize_fini(pipe_fd);
 801 
 802         if (debug)
 803                 (void) printf("Starting svc_run\n");
 804         svc_run();
 805         syslog(LOG_ERR, "statd: svc_run returned\n");
 806         /* NOTREACHED */
 807         thr_exit((void *)1);
 808         return (0);
 809 
 810 }
 811 
 812 /*
 813  * Make sure the ownership of the statmon directories is correct, then
 814  * change our uid to match.  If the top-level directories (/var/statmon, -p
 815  * arguments) don't exist, they are created first.  The sm and sm.bak
 816  * directories are not created here, but if they already exist, they are
 817  * chowned to the correct uid, along with anything else in the
 818  * directories.
 819  */
 820 
 821 static void
 822 set_statmon_owner(void)
 823 {
 824         int i;
 825         boolean_t can_do_mlp;
 826 
 827         /*
 828          * Recursively chown/chgrp /var/statmon and the alternate paths,
 829          * creating them if necessary.
 830          */
 831         one_statmon_owner(statd_home);
 832         for (i = 0; i < pathix; i++) {
 833                 char alt_path[MAXPATHLEN];
 834 
 835                 snprintf(alt_path, MAXPATHLEN, "%s/statmon", path_name[i]);
 836                 one_statmon_owner(alt_path);
 837         }
 838 
 839         can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
 840         if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
 841             daemon_uid, daemon_gid, can_do_mlp ? PRIV_NET_BINDMLP : NULL,
 842             NULL) == -1) {
 843                 syslog(LOG_ERR, "can't run unprivileged: %m");
 844                 exit(1);
 845         }
 846 
 847         __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION,
 848             PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL);
 849 }
 850 
 851 /*
 852  * Copy client names from the alternate statmon directories into
 853  * /var/statmon.  The top-level (statmon) directories should already
 854  * exist, though the sm and sm.bak directories might not.
 855  */
 856 
 857 static void
 858 copy_client_names(void)
 859 {
 860         int i;
 861         char buf[MAXPATHLEN+SM_MAXPATHLEN];
 862 
 863         /*
 864          * Copy all clients from alternate paths to /var/statmon/sm
 865          * Remove the files in alternate directory when copying is done.
 866          */
 867         for (i = 0; i < pathix; i++) {
 868                 /*
 869                  * If the alternate directories do not exist, create it.
 870                  * If they do exist, just do the copy.
 871                  */
 872                 snprintf(buf, sizeof (buf), "%s/statmon/sm", path_name[i]);
 873                 if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
 874                         if (errno != EEXIST) {
 875                                 syslog(LOG_ERR,
 876                                     "can't mkdir %s: %m\n", buf);
 877                                 continue;
 878                         }
 879                         copydir_from_to(buf, CURRENT);
 880                         (void) remove_dir(buf);
 881                 }
 882 
 883                 (void) snprintf(buf, sizeof (buf), "%s/statmon/sm.bak",
 884                     path_name[i]);
 885                 if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
 886                         if (errno != EEXIST) {
 887                                 syslog(LOG_ERR,
 888                                     "can't mkdir %s: %m\n", buf);
 889                                 continue;
 890                         }
 891                         copydir_from_to(buf, BACKUP);
 892                         (void) remove_dir(buf);
 893                 }
 894         }
 895 }
 896 
 897 /*
 898  * Create the given directory if it doesn't already exist.  Set the user
 899  * and group to daemon for the directory and anything under it.
 900  */
 901 
 902 static void
 903 one_statmon_owner(const char *dir)
 904 {
 905         if ((mkdir(dir, SM_DIRECTORY_MODE)) == -1) {
 906                 if (errno != EEXIST) {
 907                         syslog(LOG_ERR, "can't mkdir %s: %m",
 908                             dir);
 909                         return;
 910                 }
 911         }
 912 
 913         if (debug)
 914                 printf("Setting owner for %s\n", dir);
 915 
 916         if (nftw(dir, nftw_owner, MAX_FDS, FTW_PHYS) != 0) {
 917                 syslog(LOG_WARNING, "error setting owner for %s: %m",
 918                     dir);
 919         }
 920 }
 921 
 922 /*
 923  * Set the user and group to daemon for the given file or directory.  If
 924  * it's a directory, also makes sure that it is mode 755.
 925  * Generates a syslog message but does not return an error if there were
 926  * problems.
 927  */
 928 
 929 /*ARGSUSED3*/
 930 static int
 931 nftw_owner(const char *path, const struct stat *statp, int info,
 932     struct FTW *ftw)
 933 {
 934         if (!(info == FTW_F || info == FTW_D))
 935                 return (0);
 936 
 937         /*
 938          * Some older systems might have mode 777 directories.  Fix that.
 939          */
 940 
 941         if (info == FTW_D && (statp->st_mode & (S_IWGRP | S_IWOTH)) != 0) {
 942                 mode_t newmode = (statp->st_mode & ~(S_IWGRP | S_IWOTH)) &
 943                     S_IAMB;
 944 
 945                 if (debug)
 946                         printf("chmod %03o %s\n", newmode, path);
 947                 if (chmod(path, newmode) < 0) {
 948                         int error = errno;
 949 
 950                         syslog(LOG_WARNING, "can't chmod %s to %03o: %m",
 951                             path, newmode);
 952                         if (debug)
 953                                 printf("  FAILED: %s\n", strerror(error));
 954                 }
 955         }
 956 
 957         /* If already owned by daemon, don't bother changing. */
 958         if (statp->st_uid == daemon_uid &&
 959             statp->st_gid == daemon_gid)
 960                 return (0);
 961 
 962         if (debug)
 963                 printf("lchown %s daemon:daemon\n", path);
 964         if (lchown(path, daemon_uid, daemon_gid) < 0) {
 965                 int error = errno;
 966 
 967                 syslog(LOG_WARNING, "can't chown %s to daemon: %m",
 968                     path);
 969                 if (debug)
 970                         printf("  FAILED: %s\n", strerror(error));
 971         }
 972 
 973         return (0);
 974 }