1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 32*0Sstevel@tonic-gate * The Regents of the University of California 33*0Sstevel@tonic-gate * All Rights Reserved 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 36*0Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 37*0Sstevel@tonic-gate * contributors. 38*0Sstevel@tonic-gate */ 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #include <stdio.h> 43*0Sstevel@tonic-gate #include <stdlib.h> 44*0Sstevel@tonic-gate #include <ftw.h> 45*0Sstevel@tonic-gate #include <signal.h> 46*0Sstevel@tonic-gate #include <string.h> 47*0Sstevel@tonic-gate #include <syslog.h> 48*0Sstevel@tonic-gate #include <netconfig.h> 49*0Sstevel@tonic-gate #include <unistd.h> 50*0Sstevel@tonic-gate #include <netdb.h> 51*0Sstevel@tonic-gate #include <rpc/rpc.h> 52*0Sstevel@tonic-gate #include <netinet/in.h> 53*0Sstevel@tonic-gate #include <sys/param.h> 54*0Sstevel@tonic-gate #include <sys/resource.h> 55*0Sstevel@tonic-gate #include <sys/file.h> 56*0Sstevel@tonic-gate #include <sys/types.h> 57*0Sstevel@tonic-gate #include <sys/stat.h> 58*0Sstevel@tonic-gate #include <sys/sockio.h> 59*0Sstevel@tonic-gate #include <dirent.h> 60*0Sstevel@tonic-gate #include <errno.h> 61*0Sstevel@tonic-gate #include <rpcsvc/sm_inter.h> 62*0Sstevel@tonic-gate #include <rpcsvc/nsm_addr.h> 63*0Sstevel@tonic-gate #include <thread.h> 64*0Sstevel@tonic-gate #include <synch.h> 65*0Sstevel@tonic-gate #include <net/if.h> 66*0Sstevel@tonic-gate #include <limits.h> 67*0Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h> 68*0Sstevel@tonic-gate #include <priv_utils.h> 69*0Sstevel@tonic-gate #include "sm_statd.h" 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate #define home0 "/var/statmon" 73*0Sstevel@tonic-gate #define current0 "/var/statmon/sm" 74*0Sstevel@tonic-gate #define backup0 "/var/statmon/sm.bak" 75*0Sstevel@tonic-gate #define state0 "/var/statmon/state" 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate #define home1 "statmon" 78*0Sstevel@tonic-gate #define current1 "statmon/sm/" 79*0Sstevel@tonic-gate #define backup1 "statmon/sm.bak/" 80*0Sstevel@tonic-gate #define state1 "statmon/state" 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* 83*0Sstevel@tonic-gate * User and group IDs to run as. These are hardwired, rather than looked 84*0Sstevel@tonic-gate * up at runtime, because they are very unlikely to change and because they 85*0Sstevel@tonic-gate * provide some protection against bogus changes to the passwd and group 86*0Sstevel@tonic-gate * files. 87*0Sstevel@tonic-gate */ 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN]; 90*0Sstevel@tonic-gate static char statd_home[MAXPATHLEN]; 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate int debug; 93*0Sstevel@tonic-gate int regfiles_only = 0; /* 1 => use symlinks in statmon, 0 => don't */ 94*0Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN]; 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate /* 97*0Sstevel@tonic-gate * These variables will be used to store all the 98*0Sstevel@tonic-gate * alias names for the host, as well as the -a 99*0Sstevel@tonic-gate * command line hostnames. 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate int host_name_count; 102*0Sstevel@tonic-gate char **host_name; /* store -a opts */ 103*0Sstevel@tonic-gate int addrix; /* # of -a entries */ 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate /* 107*0Sstevel@tonic-gate * The following 2 variables are meaningful 108*0Sstevel@tonic-gate * only under a HA configuration. 109*0Sstevel@tonic-gate * The path_name array is dynamically allocated in main() during 110*0Sstevel@tonic-gate * command line argument processing for the -p options. 111*0Sstevel@tonic-gate */ 112*0Sstevel@tonic-gate char **path_name = NULL; /* store -p opts */ 113*0Sstevel@tonic-gate int pathix = 0; /* # of -p entries */ 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate /* Global variables. Refer to sm_statd.h for description */ 116*0Sstevel@tonic-gate mutex_t crash_lock; 117*0Sstevel@tonic-gate int die; 118*0Sstevel@tonic-gate int in_crash; 119*0Sstevel@tonic-gate cond_t crash_finish; 120*0Sstevel@tonic-gate mutex_t sm_trylock; 121*0Sstevel@tonic-gate rwlock_t thr_rwlock; 122*0Sstevel@tonic-gate cond_t retrywait; 123*0Sstevel@tonic-gate mutex_t name_addrlock; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate /* forward references */ 126*0Sstevel@tonic-gate static void set_statmon_owner(void); 127*0Sstevel@tonic-gate static void copy_client_names(void); 128*0Sstevel@tonic-gate static void one_statmon_owner(const char *); 129*0Sstevel@tonic-gate static int nftw_owner(const char *, const struct stat *, int, struct FTW *); 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate /* 132*0Sstevel@tonic-gate * statd protocol 133*0Sstevel@tonic-gate * commands: 134*0Sstevel@tonic-gate * SM_STAT 135*0Sstevel@tonic-gate * returns stat_fail to caller 136*0Sstevel@tonic-gate * SM_MON 137*0Sstevel@tonic-gate * adds an entry to the monitor_q and the record_q 138*0Sstevel@tonic-gate * This message is sent by the server lockd to the server 139*0Sstevel@tonic-gate * statd, to indicate that a new client is to be monitored. 140*0Sstevel@tonic-gate * It is also sent by the server lockd to the client statd 141*0Sstevel@tonic-gate * to indicate that a new server is to be monitored. 142*0Sstevel@tonic-gate * SM_UNMON 143*0Sstevel@tonic-gate * removes an entry from the monitor_q and the record_q 144*0Sstevel@tonic-gate * SM_UNMON_ALL 145*0Sstevel@tonic-gate * removes all entries from a particular host from the 146*0Sstevel@tonic-gate * monitor_q and the record_q. Our statd has this 147*0Sstevel@tonic-gate * disabled. 148*0Sstevel@tonic-gate * SM_SIMU_CRASH 149*0Sstevel@tonic-gate * simulate a crash. removes everything from the 150*0Sstevel@tonic-gate * record_q and the recovery_q, then calls statd_init() 151*0Sstevel@tonic-gate * to restart things. This message is sent by the server 152*0Sstevel@tonic-gate * lockd to the server statd to have all clients notified 153*0Sstevel@tonic-gate * that they should reclaim locks. 154*0Sstevel@tonic-gate * SM_NOTIFY 155*0Sstevel@tonic-gate * Sent by statd on server to statd on client during 156*0Sstevel@tonic-gate * crash recovery. The client statd passes the info 157*0Sstevel@tonic-gate * to its lockd so it can attempt to reclaim the locks 158*0Sstevel@tonic-gate * held on the server. 159*0Sstevel@tonic-gate * 160*0Sstevel@tonic-gate * There are three main hash tables used to keep track of things. 161*0Sstevel@tonic-gate * mon_table 162*0Sstevel@tonic-gate * table that keeps track hosts statd must watch. If one of 163*0Sstevel@tonic-gate * these hosts crashes, then any locks held by that host must 164*0Sstevel@tonic-gate * be released. 165*0Sstevel@tonic-gate * record_table 166*0Sstevel@tonic-gate * used to keep track of all the hostname files stored in 167*0Sstevel@tonic-gate * the directory /var/statmon/sm. These are client hosts who 168*0Sstevel@tonic-gate * are holding or have held a lock at some point. Needed 169*0Sstevel@tonic-gate * to determine if a file needs to be created for host in 170*0Sstevel@tonic-gate * /var/statmon/sm. 171*0Sstevel@tonic-gate * recov_q 172*0Sstevel@tonic-gate * used to keep track hostnames during a recovery 173*0Sstevel@tonic-gate * 174*0Sstevel@tonic-gate * The entries are hashed based upon the name. 175*0Sstevel@tonic-gate * 176*0Sstevel@tonic-gate * There is a directory /var/statmon/sm which holds a file named 177*0Sstevel@tonic-gate * for each host that is holding (or has held) a lock. This is 178*0Sstevel@tonic-gate * used during initialization on startup, or after a simulated 179*0Sstevel@tonic-gate * crash. 180*0Sstevel@tonic-gate */ 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate static void 183*0Sstevel@tonic-gate sm_prog_1(rqstp, transp) 184*0Sstevel@tonic-gate struct svc_req *rqstp; 185*0Sstevel@tonic-gate SVCXPRT *transp; 186*0Sstevel@tonic-gate { 187*0Sstevel@tonic-gate union { 188*0Sstevel@tonic-gate struct sm_name sm_stat_1_arg; 189*0Sstevel@tonic-gate struct mon sm_mon_1_arg; 190*0Sstevel@tonic-gate struct mon_id sm_unmon_1_arg; 191*0Sstevel@tonic-gate struct my_id sm_unmon_all_1_arg; 192*0Sstevel@tonic-gate struct stat_chge ntf_arg; 193*0Sstevel@tonic-gate struct reg1args reg1_arg; 194*0Sstevel@tonic-gate } argument; 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate union { 197*0Sstevel@tonic-gate sm_stat_res stat_resp; 198*0Sstevel@tonic-gate sm_stat mon_resp; 199*0Sstevel@tonic-gate struct reg1res reg1_resp; 200*0Sstevel@tonic-gate } result; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate bool_t (*xdr_argument)(), (*xdr_result)(); 203*0Sstevel@tonic-gate char *(*local)(); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate /* 206*0Sstevel@tonic-gate * Dispatch according to which protocol is being used: 207*0Sstevel@tonic-gate * NSM_ADDR_PROGRAM is the private lockd address 208*0Sstevel@tonic-gate * registration protocol. 209*0Sstevel@tonic-gate * SM_PROG is the normal statd (NSM) protocol. 210*0Sstevel@tonic-gate */ 211*0Sstevel@tonic-gate if (rqstp->rq_prog == NSM_ADDR_PROGRAM) { 212*0Sstevel@tonic-gate switch (rqstp->rq_proc) { 213*0Sstevel@tonic-gate case NULLPROC: 214*0Sstevel@tonic-gate svc_sendreply(transp, xdr_void, (caddr_t)NULL); 215*0Sstevel@tonic-gate return; 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate case NSMADDRPROC1_REG: 218*0Sstevel@tonic-gate xdr_argument = xdr_reg1args; 219*0Sstevel@tonic-gate xdr_result = xdr_reg1res; 220*0Sstevel@tonic-gate local = (char *(*)()) nsmaddrproc1_reg; 221*0Sstevel@tonic-gate break; 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate default: 224*0Sstevel@tonic-gate svcerr_noproc(transp); 225*0Sstevel@tonic-gate return; 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate } else { 228*0Sstevel@tonic-gate switch (rqstp->rq_proc) { 229*0Sstevel@tonic-gate case NULLPROC: 230*0Sstevel@tonic-gate svc_sendreply(transp, xdr_void, (caddr_t)NULL); 231*0Sstevel@tonic-gate return; 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate case SM_STAT: 234*0Sstevel@tonic-gate xdr_argument = xdr_sm_name; 235*0Sstevel@tonic-gate xdr_result = xdr_sm_stat_res; 236*0Sstevel@tonic-gate local = (char *(*)()) sm_status; 237*0Sstevel@tonic-gate break; 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate case SM_MON: 240*0Sstevel@tonic-gate xdr_argument = xdr_mon; 241*0Sstevel@tonic-gate xdr_result = xdr_sm_stat_res; 242*0Sstevel@tonic-gate local = (char *(*)()) sm_mon; 243*0Sstevel@tonic-gate break; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate case SM_UNMON: 246*0Sstevel@tonic-gate xdr_argument = xdr_mon_id; 247*0Sstevel@tonic-gate xdr_result = xdr_sm_stat; 248*0Sstevel@tonic-gate local = (char *(*)()) sm_unmon; 249*0Sstevel@tonic-gate break; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate case SM_UNMON_ALL: 252*0Sstevel@tonic-gate xdr_argument = xdr_my_id; 253*0Sstevel@tonic-gate xdr_result = xdr_sm_stat; 254*0Sstevel@tonic-gate local = (char *(*)()) sm_unmon_all; 255*0Sstevel@tonic-gate break; 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate case SM_SIMU_CRASH: 258*0Sstevel@tonic-gate xdr_argument = xdr_void; 259*0Sstevel@tonic-gate xdr_result = xdr_void; 260*0Sstevel@tonic-gate local = (char *(*)()) sm_simu_crash; 261*0Sstevel@tonic-gate break; 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate case SM_NOTIFY: 264*0Sstevel@tonic-gate xdr_argument = xdr_stat_chge; 265*0Sstevel@tonic-gate xdr_result = xdr_void; 266*0Sstevel@tonic-gate local = (char *(*)()) sm_notify; 267*0Sstevel@tonic-gate break; 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate default: 270*0Sstevel@tonic-gate svcerr_noproc(transp); 271*0Sstevel@tonic-gate return; 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate (void) memset(&argument, 0, sizeof (argument)); 276*0Sstevel@tonic-gate if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 277*0Sstevel@tonic-gate svcerr_decode(transp); 278*0Sstevel@tonic-gate return; 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate (void) memset(&result, 0, sizeof (result)); 282*0Sstevel@tonic-gate (*local)(&argument, &result); 283*0Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_result, (caddr_t)&result)) { 284*0Sstevel@tonic-gate svcerr_systemerr(transp); 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 288*0Sstevel@tonic-gate syslog(LOG_ERR, "statd: unable to free arguments\n"); 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate /* 293*0Sstevel@tonic-gate * Remove all files under directory path_dir. 294*0Sstevel@tonic-gate */ 295*0Sstevel@tonic-gate static int 296*0Sstevel@tonic-gate remove_dir(path_dir) 297*0Sstevel@tonic-gate char *path_dir; 298*0Sstevel@tonic-gate { 299*0Sstevel@tonic-gate DIR *dp; 300*0Sstevel@tonic-gate struct dirent *dirp, *entp; 301*0Sstevel@tonic-gate char tmp_path[MAXPATHLEN]; 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate if ((dp = opendir(path_dir)) == (DIR *)NULL) { 304*0Sstevel@tonic-gate if (debug) 305*0Sstevel@tonic-gate syslog(LOG_ERR, 306*0Sstevel@tonic-gate "warning: open directory %s failed: %m\n", path_dir); 307*0Sstevel@tonic-gate return (1); 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate entp = (struct dirent *)xmalloc(MAXDIRENT); 311*0Sstevel@tonic-gate if (entp == NULL) { 312*0Sstevel@tonic-gate (void) closedir(dp); 313*0Sstevel@tonic-gate return (1); 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate while ((dirp = readdir_r(dp, entp)) != (struct dirent *)NULL) { 317*0Sstevel@tonic-gate if (strcmp(dirp->d_name, ".") != 0 && 318*0Sstevel@tonic-gate strcmp(dirp->d_name, "..") != 0) { 319*0Sstevel@tonic-gate if (strlen(path_dir) + strlen(dirp->d_name) +2 > 320*0Sstevel@tonic-gate MAXPATHLEN) { 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate syslog(LOG_ERR, 323*0Sstevel@tonic-gate "statd: remove dir %s/%s failed. Pathname too long.\n", 324*0Sstevel@tonic-gate path_dir, dirp->d_name); 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate continue; 327*0Sstevel@tonic-gate } 328*0Sstevel@tonic-gate (void) strcpy(tmp_path, path_dir); 329*0Sstevel@tonic-gate (void) strcat(tmp_path, "/"); 330*0Sstevel@tonic-gate (void) strcat(tmp_path, dirp->d_name); 331*0Sstevel@tonic-gate delete_file(tmp_path); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate free(entp); 336*0Sstevel@tonic-gate (void) closedir(dp); 337*0Sstevel@tonic-gate return (0); 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate /* 341*0Sstevel@tonic-gate * Copy all files from directory `from_dir' to directory `to_dir'. 342*0Sstevel@tonic-gate * Symlinks, if any, are preserved. 343*0Sstevel@tonic-gate */ 344*0Sstevel@tonic-gate void 345*0Sstevel@tonic-gate copydir_from_to(from_dir, to_dir) 346*0Sstevel@tonic-gate char *from_dir; 347*0Sstevel@tonic-gate char *to_dir; 348*0Sstevel@tonic-gate { 349*0Sstevel@tonic-gate int n; 350*0Sstevel@tonic-gate DIR *dp; 351*0Sstevel@tonic-gate struct dirent *dirp, *entp; 352*0Sstevel@tonic-gate char rname[MAXNAMELEN + 1]; 353*0Sstevel@tonic-gate char path[MAXPATHLEN+MAXNAMELEN+2]; 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate if ((dp = opendir(from_dir)) == (DIR *)NULL) { 356*0Sstevel@tonic-gate if (debug) 357*0Sstevel@tonic-gate syslog(LOG_ERR, 358*0Sstevel@tonic-gate "warning: open directory %s failed: %m\n", from_dir); 359*0Sstevel@tonic-gate return; 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate entp = (struct dirent *)xmalloc(MAXDIRENT); 363*0Sstevel@tonic-gate if (entp == NULL) { 364*0Sstevel@tonic-gate (void) closedir(dp); 365*0Sstevel@tonic-gate return; 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate while ((dirp = readdir_r(dp, entp)) != (struct dirent *)NULL) { 369*0Sstevel@tonic-gate if (strcmp(dirp->d_name, ".") == 0 || 370*0Sstevel@tonic-gate strcmp(dirp->d_name, "..") == 0) { 371*0Sstevel@tonic-gate continue; 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate (void) strcpy(path, from_dir); 375*0Sstevel@tonic-gate (void) strcat(path, "/"); 376*0Sstevel@tonic-gate (void) strcat(path, dirp->d_name); 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate if (is_symlink(path)) { 379*0Sstevel@tonic-gate /* 380*0Sstevel@tonic-gate * Follow the link to get the referenced file name 381*0Sstevel@tonic-gate * and make a new link for that file in to_dir. 382*0Sstevel@tonic-gate */ 383*0Sstevel@tonic-gate n = readlink(path, rname, MAXNAMELEN); 384*0Sstevel@tonic-gate if (n <= 0) { 385*0Sstevel@tonic-gate if (debug >= 2) { 386*0Sstevel@tonic-gate (void) printf( 387*0Sstevel@tonic-gate "copydir_from_to: can't read link %s\n", 388*0Sstevel@tonic-gate path); 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate continue; 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate rname[n] = '\0'; 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate (void) create_symlink(to_dir, rname, dirp->d_name); 395*0Sstevel@tonic-gate } else { 396*0Sstevel@tonic-gate /* 397*0Sstevel@tonic-gate * Simply copy regular files to to_dir. 398*0Sstevel@tonic-gate */ 399*0Sstevel@tonic-gate (void) strcpy(path, to_dir); 400*0Sstevel@tonic-gate (void) strcat(path, "/"); 401*0Sstevel@tonic-gate (void) strcat(path, dirp->d_name); 402*0Sstevel@tonic-gate (void) create_file(path); 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate free(entp); 407*0Sstevel@tonic-gate (void) closedir(dp); 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate static int 411*0Sstevel@tonic-gate init_hostname(void) 412*0Sstevel@tonic-gate { 413*0Sstevel@tonic-gate struct lifnum lifn; 414*0Sstevel@tonic-gate int sock; 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 417*0Sstevel@tonic-gate syslog(LOG_ERR, "statd:init_hostname, socket: %m"); 418*0Sstevel@tonic-gate return (-1); 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC; 422*0Sstevel@tonic-gate lifn.lifn_flags = 0; 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 425*0Sstevel@tonic-gate syslog(LOG_ERR, 426*0Sstevel@tonic-gate "statd:init_hostname, get number of interfaces, error: %m"); 427*0Sstevel@tonic-gate close(sock); 428*0Sstevel@tonic-gate return (-1); 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate host_name_count = lifn.lifn_count; 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate host_name = (char **)malloc(host_name_count * sizeof (char *)); 434*0Sstevel@tonic-gate if (host_name == NULL) { 435*0Sstevel@tonic-gate perror("statd -a can't get ip configuration\n"); 436*0Sstevel@tonic-gate close(sock); 437*0Sstevel@tonic-gate return (-1); 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate close(sock); 440*0Sstevel@tonic-gate return (0); 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate main(argc, argv) 444*0Sstevel@tonic-gate int argc; 445*0Sstevel@tonic-gate char **argv; 446*0Sstevel@tonic-gate { 447*0Sstevel@tonic-gate int c; 448*0Sstevel@tonic-gate int ppid; 449*0Sstevel@tonic-gate extern char *optarg; 450*0Sstevel@tonic-gate int choice = 0; 451*0Sstevel@tonic-gate struct rlimit rl; 452*0Sstevel@tonic-gate int mode; 453*0Sstevel@tonic-gate int sz; 454*0Sstevel@tonic-gate int connmaxrec = RPC_MAXDATASIZE; 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate addrix = 0; 457*0Sstevel@tonic-gate pathix = 0; 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate (void) gethostname(hostname, MAXHOSTNAMELEN); 460*0Sstevel@tonic-gate if (init_hostname() < 0) 461*0Sstevel@tonic-gate exit(1); 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate while ((c = getopt(argc, argv, "Dd:a:p:r")) != EOF) 464*0Sstevel@tonic-gate switch (c) { 465*0Sstevel@tonic-gate case 'd': 466*0Sstevel@tonic-gate (void) sscanf(optarg, "%d", &debug); 467*0Sstevel@tonic-gate break; 468*0Sstevel@tonic-gate case 'D': 469*0Sstevel@tonic-gate choice = 1; 470*0Sstevel@tonic-gate break; 471*0Sstevel@tonic-gate case 'a': 472*0Sstevel@tonic-gate if (addrix < host_name_count) { 473*0Sstevel@tonic-gate if (strcmp(hostname, optarg) != 0) { 474*0Sstevel@tonic-gate sz = strlen(optarg); 475*0Sstevel@tonic-gate if (sz < MAXHOSTNAMELEN) { 476*0Sstevel@tonic-gate host_name[addrix] = 477*0Sstevel@tonic-gate (char *)xmalloc(sz+1); 478*0Sstevel@tonic-gate if (host_name[addrix] != 479*0Sstevel@tonic-gate NULL) { 480*0Sstevel@tonic-gate (void) sscanf(optarg, "%s", 481*0Sstevel@tonic-gate host_name[addrix]); 482*0Sstevel@tonic-gate addrix++; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate } else 485*0Sstevel@tonic-gate (void) fprintf(stderr, 486*0Sstevel@tonic-gate "statd: -a name of host is too long.\n"); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate } else 489*0Sstevel@tonic-gate (void) fprintf(stderr, 490*0Sstevel@tonic-gate "statd: -a exceeding maximum hostnames\n"); 491*0Sstevel@tonic-gate break; 492*0Sstevel@tonic-gate case 'p': 493*0Sstevel@tonic-gate if (strlen(optarg) < MAXPATHLEN) { 494*0Sstevel@tonic-gate /* If the path_name array has not yet */ 495*0Sstevel@tonic-gate /* been malloc'ed, do that. The array */ 496*0Sstevel@tonic-gate /* should be big enough to hold all of the */ 497*0Sstevel@tonic-gate /* -p options we might have. An upper */ 498*0Sstevel@tonic-gate /* bound on the number of -p options is */ 499*0Sstevel@tonic-gate /* argc/2, because each -p option consumes */ 500*0Sstevel@tonic-gate /* two arguments. Here the upper bound */ 501*0Sstevel@tonic-gate /* is supposing that all the command line */ 502*0Sstevel@tonic-gate /* arguments are -p options, which would */ 503*0Sstevel@tonic-gate /* actually never be the case. */ 504*0Sstevel@tonic-gate if (path_name == NULL) { 505*0Sstevel@tonic-gate size_t sz = (argc/2) * sizeof (char *); 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate path_name = (char **)malloc(sz); 508*0Sstevel@tonic-gate if (path_name == NULL) { 509*0Sstevel@tonic-gate (void) fprintf(stderr, 510*0Sstevel@tonic-gate "statd: malloc failed\n"); 511*0Sstevel@tonic-gate exit(1); 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate (void) memset(path_name, 0, sz); 514*0Sstevel@tonic-gate } 515*0Sstevel@tonic-gate path_name[pathix] = optarg; 516*0Sstevel@tonic-gate pathix++; 517*0Sstevel@tonic-gate } else { 518*0Sstevel@tonic-gate (void) fprintf(stderr, 519*0Sstevel@tonic-gate "statd: -p pathname is too long.\n"); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate break; 522*0Sstevel@tonic-gate case 'r': 523*0Sstevel@tonic-gate regfiles_only = 1; 524*0Sstevel@tonic-gate break; 525*0Sstevel@tonic-gate default: 526*0Sstevel@tonic-gate (void) fprintf(stderr, 527*0Sstevel@tonic-gate "statd [-d level] [-D]\n"); 528*0Sstevel@tonic-gate return (1); 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate if (choice == 0) { 532*0Sstevel@tonic-gate (void) strcpy(statd_home, home0); 533*0Sstevel@tonic-gate (void) strcpy(CURRENT, current0); 534*0Sstevel@tonic-gate (void) strcpy(BACKUP, backup0); 535*0Sstevel@tonic-gate (void) strcpy(STATE, state0); 536*0Sstevel@tonic-gate } else { 537*0Sstevel@tonic-gate (void) strcpy(statd_home, home1); 538*0Sstevel@tonic-gate (void) strcpy(CURRENT, current1); 539*0Sstevel@tonic-gate (void) strcpy(BACKUP, backup1); 540*0Sstevel@tonic-gate (void) strcpy(STATE, state1); 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate if (debug) 543*0Sstevel@tonic-gate (void) printf("debug is on, create entry: %s, %s, %s\n", 544*0Sstevel@tonic-gate CURRENT, BACKUP, STATE); 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl)) 547*0Sstevel@tonic-gate (void) printf("statd: getrlimit failed. \n"); 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate /* Set maxfdlimit current soft limit */ 550*0Sstevel@tonic-gate rl.rlim_cur = MAX_FDS; 551*0Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) != 0) 552*0Sstevel@tonic-gate syslog(LOG_ERR, "statd: unable to set RLIMIT_NOFILE to %d\n", 553*0Sstevel@tonic-gate MAX_FDS); 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate if (!debug) { 556*0Sstevel@tonic-gate ppid = fork(); 557*0Sstevel@tonic-gate if (ppid == -1) { 558*0Sstevel@tonic-gate (void) fprintf(stderr, "statd: fork failure\n"); 559*0Sstevel@tonic-gate (void) fflush(stderr); 560*0Sstevel@tonic-gate abort(); 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate if (ppid != 0) { 563*0Sstevel@tonic-gate exit(0); 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate closefrom(0); 566*0Sstevel@tonic-gate (void) open("/dev/null", O_RDONLY); 567*0Sstevel@tonic-gate (void) open("/dev/null", O_WRONLY); 568*0Sstevel@tonic-gate (void) dup(1); 569*0Sstevel@tonic-gate (void) setsid(); 570*0Sstevel@tonic-gate openlog("statd", LOG_PID, LOG_DAEMON); 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate (void) _create_daemon_lock(STATD, DAEMON_UID, DAEMON_GID); 574*0Sstevel@tonic-gate /* 575*0Sstevel@tonic-gate * establish our lock on the lock file and write our pid to it. 576*0Sstevel@tonic-gate * exit if some other process holds the lock, or if there's any 577*0Sstevel@tonic-gate * error in writing/locking the file. 578*0Sstevel@tonic-gate */ 579*0Sstevel@tonic-gate ppid = _enter_daemon_lock(STATD); 580*0Sstevel@tonic-gate switch (ppid) { 581*0Sstevel@tonic-gate case 0: 582*0Sstevel@tonic-gate break; 583*0Sstevel@tonic-gate case -1: 584*0Sstevel@tonic-gate syslog(LOG_ERR, "error locking for %s: %s", STATD, 585*0Sstevel@tonic-gate strerror(errno)); 586*0Sstevel@tonic-gate exit(2); 587*0Sstevel@tonic-gate default: 588*0Sstevel@tonic-gate /* daemon was already running */ 589*0Sstevel@tonic-gate exit(0); 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* Get other aliases from each interface. */ 593*0Sstevel@tonic-gate merge_hosts(); 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate /* 596*0Sstevel@tonic-gate * Set to automatic mode such that threads are automatically 597*0Sstevel@tonic-gate * created 598*0Sstevel@tonic-gate */ 599*0Sstevel@tonic-gate mode = RPC_SVC_MT_AUTO; 600*0Sstevel@tonic-gate if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) { 601*0Sstevel@tonic-gate syslog(LOG_ERR, 602*0Sstevel@tonic-gate "statd:unable to set automatic MT mode."); 603*0Sstevel@tonic-gate exit(1); 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate /* 607*0Sstevel@tonic-gate * Set non-blocking mode and maximum record size for 608*0Sstevel@tonic-gate * connection oriented RPC transports. 609*0Sstevel@tonic-gate */ 610*0Sstevel@tonic-gate if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { 611*0Sstevel@tonic-gate syslog(LOG_INFO, "unable to set maximum RPC record size"); 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) { 615*0Sstevel@tonic-gate syslog(LOG_ERR, 616*0Sstevel@tonic-gate "statd: unable to create (SM_PROG, SM_VERS) for netpath."); 617*0Sstevel@tonic-gate exit(1); 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) { 621*0Sstevel@tonic-gate syslog(LOG_ERR, 622*0Sstevel@tonic-gate "statd: unable to create (NSM_ADDR_PROGRAM, NSM_ADDR_V1) for netpath."); 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /* 626*0Sstevel@tonic-gate * Make sure /var/statmon and any alternate (-p) statmon 627*0Sstevel@tonic-gate * directories exist and are owned by daemon. Then change our uid 628*0Sstevel@tonic-gate * to daemon. The uid change is to prevent attacks against local 629*0Sstevel@tonic-gate * daemons that trust any call from a local root process. 630*0Sstevel@tonic-gate */ 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate set_statmon_owner(); 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate /* 635*0Sstevel@tonic-gate * 636*0Sstevel@tonic-gate * statd now runs as a daemon rather than root and can not 637*0Sstevel@tonic-gate * dump core under / because of the permission. It is 638*0Sstevel@tonic-gate * important that current working directory of statd be 639*0Sstevel@tonic-gate * changed to writable directory /var/statmon so that it 640*0Sstevel@tonic-gate * can dump the core upon the receipt of the signal. 641*0Sstevel@tonic-gate * One still need to set allow_setid_core to non-zero in 642*0Sstevel@tonic-gate * /etc/system to get the core dump. 643*0Sstevel@tonic-gate * 644*0Sstevel@tonic-gate */ 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate if (chdir(statd_home) < 0) { 647*0Sstevel@tonic-gate syslog(LOG_ERR, "can't chdir %s: %m", statd_home); 648*0Sstevel@tonic-gate exit(1); 649*0Sstevel@tonic-gate } 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate copy_client_names(); 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate rwlock_init(&thr_rwlock, USYNC_THREAD, NULL); 654*0Sstevel@tonic-gate mutex_init(&crash_lock, USYNC_THREAD, NULL); 655*0Sstevel@tonic-gate mutex_init(&name_addrlock, USYNC_THREAD, NULL); 656*0Sstevel@tonic-gate cond_init(&crash_finish, USYNC_THREAD, NULL); 657*0Sstevel@tonic-gate cond_init(&retrywait, USYNC_THREAD, NULL); 658*0Sstevel@tonic-gate sm_inithash(); 659*0Sstevel@tonic-gate die = 0; 660*0Sstevel@tonic-gate /* 661*0Sstevel@tonic-gate * This variable is set to ensure that an sm_crash 662*0Sstevel@tonic-gate * request will not be done at the same time 663*0Sstevel@tonic-gate * when a statd_init is being done, since sm_crash 664*0Sstevel@tonic-gate * can reset some variables that statd_init will be using. 665*0Sstevel@tonic-gate */ 666*0Sstevel@tonic-gate in_crash = 1; 667*0Sstevel@tonic-gate statd_init(); 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate if (debug) 670*0Sstevel@tonic-gate (void) printf("Starting svc_run\n"); 671*0Sstevel@tonic-gate svc_run(); 672*0Sstevel@tonic-gate syslog(LOG_ERR, "statd: svc_run returned\n"); 673*0Sstevel@tonic-gate /* NOTREACHED */ 674*0Sstevel@tonic-gate thr_exit((void *) 1); 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate } 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate /* 679*0Sstevel@tonic-gate * Make sure the ownership of the statmon directories is correct, then 680*0Sstevel@tonic-gate * change our uid to match. If the top-level directories (/var/statmon, -p 681*0Sstevel@tonic-gate * arguments) don't exist, they are created first. The sm and sm.bak 682*0Sstevel@tonic-gate * directories are not created here, but if they already exist, they are 683*0Sstevel@tonic-gate * chowned to the correct uid, along with anything else in the 684*0Sstevel@tonic-gate * directories. 685*0Sstevel@tonic-gate */ 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate static void 688*0Sstevel@tonic-gate set_statmon_owner() 689*0Sstevel@tonic-gate { 690*0Sstevel@tonic-gate int i; 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate /* 693*0Sstevel@tonic-gate * Recursively chown/chgrp /var/statmon and the alternate paths, 694*0Sstevel@tonic-gate * creating them if necessary. 695*0Sstevel@tonic-gate */ 696*0Sstevel@tonic-gate one_statmon_owner(statd_home); 697*0Sstevel@tonic-gate for (i = 0; i < pathix; i++) { 698*0Sstevel@tonic-gate char alt_path[MAXPATHLEN]; 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate snprintf(alt_path, MAXPATHLEN, "%s/statmon", path_name[i]); 701*0Sstevel@tonic-gate one_statmon_owner(alt_path); 702*0Sstevel@tonic-gate } 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 705*0Sstevel@tonic-gate DAEMON_UID, DAEMON_GID, (char *)NULL) == -1) { 706*0Sstevel@tonic-gate syslog(LOG_ERR, "can't run unprivileged: %m"); 707*0Sstevel@tonic-gate exit(1); 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION, 711*0Sstevel@tonic-gate PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 712*0Sstevel@tonic-gate } 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate /* 715*0Sstevel@tonic-gate * Copy client names from the alternate statmon directories into 716*0Sstevel@tonic-gate * /var/statmon. The top-level (statmon) directories should already 717*0Sstevel@tonic-gate * exist, though the sm and sm.bak directories might not. 718*0Sstevel@tonic-gate */ 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate static void 721*0Sstevel@tonic-gate copy_client_names() 722*0Sstevel@tonic-gate { 723*0Sstevel@tonic-gate int i; 724*0Sstevel@tonic-gate char buf[MAXPATHLEN+SM_MAXPATHLEN]; 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate /* 727*0Sstevel@tonic-gate * Copy all clients from alternate paths to /var/statmon/sm 728*0Sstevel@tonic-gate * Remove the files in alternate directory when copying is done. 729*0Sstevel@tonic-gate */ 730*0Sstevel@tonic-gate for (i = 0; i < pathix; i++) { 731*0Sstevel@tonic-gate /* 732*0Sstevel@tonic-gate * If the alternate directories do not exist, create it. 733*0Sstevel@tonic-gate * If they do exist, just do the copy. 734*0Sstevel@tonic-gate */ 735*0Sstevel@tonic-gate snprintf(buf, sizeof (buf), "%s/statmon/sm", path_name[i]); 736*0Sstevel@tonic-gate if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) { 737*0Sstevel@tonic-gate if (errno != EEXIST) { 738*0Sstevel@tonic-gate syslog(LOG_ERR, 739*0Sstevel@tonic-gate "can't mkdir %s: %m\n", buf); 740*0Sstevel@tonic-gate continue; 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate copydir_from_to(buf, CURRENT); 743*0Sstevel@tonic-gate (void) remove_dir(buf); 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s/statmon/sm.bak", 747*0Sstevel@tonic-gate path_name[i]); 748*0Sstevel@tonic-gate if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) { 749*0Sstevel@tonic-gate if (errno != EEXIST) { 750*0Sstevel@tonic-gate syslog(LOG_ERR, 751*0Sstevel@tonic-gate "can't mkdir %s: %m\n", buf); 752*0Sstevel@tonic-gate continue; 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate copydir_from_to(buf, BACKUP); 755*0Sstevel@tonic-gate (void) remove_dir(buf); 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate /* 761*0Sstevel@tonic-gate * Create the given directory if it doesn't already exist. Set the user 762*0Sstevel@tonic-gate * and group to daemon for the directory and anything under it. 763*0Sstevel@tonic-gate */ 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate static void 766*0Sstevel@tonic-gate one_statmon_owner(const char *dir) 767*0Sstevel@tonic-gate { 768*0Sstevel@tonic-gate if ((mkdir(dir, SM_DIRECTORY_MODE)) == -1) { 769*0Sstevel@tonic-gate if (errno != EEXIST) { 770*0Sstevel@tonic-gate syslog(LOG_ERR, "can't mkdir %s: %m", 771*0Sstevel@tonic-gate dir); 772*0Sstevel@tonic-gate return; 773*0Sstevel@tonic-gate } 774*0Sstevel@tonic-gate } 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate if (debug) 777*0Sstevel@tonic-gate printf("Setting owner for %s\n", dir); 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate if (nftw(dir, nftw_owner, MAX_FDS, FTW_PHYS) != 0) { 780*0Sstevel@tonic-gate syslog(LOG_WARNING, "error setting owner for %s: %m", 781*0Sstevel@tonic-gate dir); 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate } 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate /* 786*0Sstevel@tonic-gate * Set the user and group to daemon for the given file or directory. If 787*0Sstevel@tonic-gate * it's a directory, also makes sure that it is mode 755. 788*0Sstevel@tonic-gate * Generates a syslog message but does not return an error if there were 789*0Sstevel@tonic-gate * problems. 790*0Sstevel@tonic-gate */ 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate /*ARGSUSED3*/ 793*0Sstevel@tonic-gate static int 794*0Sstevel@tonic-gate nftw_owner(const char *path, const struct stat *statp, int info, 795*0Sstevel@tonic-gate struct FTW *ftw) 796*0Sstevel@tonic-gate { 797*0Sstevel@tonic-gate if (!(info == FTW_F || info == FTW_D)) 798*0Sstevel@tonic-gate return (0); 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate /* 801*0Sstevel@tonic-gate * Some older systems might have mode 777 directories. Fix that. 802*0Sstevel@tonic-gate */ 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate if (info == FTW_D && (statp->st_mode & (S_IWGRP | S_IWOTH)) != 0) { 805*0Sstevel@tonic-gate mode_t newmode = (statp->st_mode & ~(S_IWGRP | S_IWOTH)) & 806*0Sstevel@tonic-gate S_IAMB; 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate if (debug) 809*0Sstevel@tonic-gate printf("chmod %03o %s\n", newmode, path); 810*0Sstevel@tonic-gate if (chmod(path, newmode) < 0) { 811*0Sstevel@tonic-gate int error = errno; 812*0Sstevel@tonic-gate 813*0Sstevel@tonic-gate syslog(LOG_WARNING, "can't chmod %s to %03o: %m", 814*0Sstevel@tonic-gate path, newmode); 815*0Sstevel@tonic-gate if (debug) 816*0Sstevel@tonic-gate printf(" FAILED: %s\n", strerror(error)); 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate } 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate /* If already owned by daemon, don't bother changing. */ 821*0Sstevel@tonic-gate if (statp->st_uid == DAEMON_UID && 822*0Sstevel@tonic-gate statp->st_gid == DAEMON_GID) 823*0Sstevel@tonic-gate return (0); 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate if (debug) 826*0Sstevel@tonic-gate printf("lchown %s daemon:daemon\n", path); 827*0Sstevel@tonic-gate if (lchown(path, DAEMON_UID, DAEMON_GID) < 0) { 828*0Sstevel@tonic-gate int error = errno; 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate syslog(LOG_WARNING, "can't chown %s to daemon: %m", 831*0Sstevel@tonic-gate path); 832*0Sstevel@tonic-gate if (debug) 833*0Sstevel@tonic-gate printf(" FAILED: %s\n", strerror(error)); 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate return (0); 837*0Sstevel@tonic-gate } 838