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