10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1676Sjpk * Common Development and Distribution License (the "License"). 6*1676Sjpk * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*1676Sjpk * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 270Sstevel@tonic-gate /* All Rights Reserved */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 310Sstevel@tonic-gate * The Regents of the University of California 320Sstevel@tonic-gate * All Rights Reserved 330Sstevel@tonic-gate * 340Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 350Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 360Sstevel@tonic-gate * contributors. 370Sstevel@tonic-gate */ 380Sstevel@tonic-gate 390Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 400Sstevel@tonic-gate 410Sstevel@tonic-gate #include <stdio.h> 420Sstevel@tonic-gate #include <stdlib.h> 430Sstevel@tonic-gate #include <ftw.h> 440Sstevel@tonic-gate #include <signal.h> 450Sstevel@tonic-gate #include <string.h> 460Sstevel@tonic-gate #include <syslog.h> 470Sstevel@tonic-gate #include <netconfig.h> 480Sstevel@tonic-gate #include <unistd.h> 490Sstevel@tonic-gate #include <netdb.h> 500Sstevel@tonic-gate #include <rpc/rpc.h> 510Sstevel@tonic-gate #include <netinet/in.h> 520Sstevel@tonic-gate #include <sys/param.h> 530Sstevel@tonic-gate #include <sys/resource.h> 540Sstevel@tonic-gate #include <sys/file.h> 550Sstevel@tonic-gate #include <sys/types.h> 560Sstevel@tonic-gate #include <sys/stat.h> 570Sstevel@tonic-gate #include <sys/sockio.h> 580Sstevel@tonic-gate #include <dirent.h> 590Sstevel@tonic-gate #include <errno.h> 600Sstevel@tonic-gate #include <rpcsvc/sm_inter.h> 610Sstevel@tonic-gate #include <rpcsvc/nsm_addr.h> 620Sstevel@tonic-gate #include <thread.h> 630Sstevel@tonic-gate #include <synch.h> 640Sstevel@tonic-gate #include <net/if.h> 650Sstevel@tonic-gate #include <limits.h> 660Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h> 670Sstevel@tonic-gate #include <priv_utils.h> 680Sstevel@tonic-gate #include "sm_statd.h" 690Sstevel@tonic-gate 700Sstevel@tonic-gate 710Sstevel@tonic-gate #define home0 "/var/statmon" 720Sstevel@tonic-gate #define current0 "/var/statmon/sm" 730Sstevel@tonic-gate #define backup0 "/var/statmon/sm.bak" 740Sstevel@tonic-gate #define state0 "/var/statmon/state" 750Sstevel@tonic-gate 760Sstevel@tonic-gate #define home1 "statmon" 770Sstevel@tonic-gate #define current1 "statmon/sm/" 780Sstevel@tonic-gate #define backup1 "statmon/sm.bak/" 790Sstevel@tonic-gate #define state1 "statmon/state" 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* 820Sstevel@tonic-gate * User and group IDs to run as. These are hardwired, rather than looked 830Sstevel@tonic-gate * up at runtime, because they are very unlikely to change and because they 840Sstevel@tonic-gate * provide some protection against bogus changes to the passwd and group 850Sstevel@tonic-gate * files. 860Sstevel@tonic-gate */ 870Sstevel@tonic-gate 880Sstevel@tonic-gate char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN]; 890Sstevel@tonic-gate static char statd_home[MAXPATHLEN]; 900Sstevel@tonic-gate 910Sstevel@tonic-gate int debug; 920Sstevel@tonic-gate int regfiles_only = 0; /* 1 => use symlinks in statmon, 0 => don't */ 930Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN]; 940Sstevel@tonic-gate 950Sstevel@tonic-gate /* 960Sstevel@tonic-gate * These variables will be used to store all the 970Sstevel@tonic-gate * alias names for the host, as well as the -a 980Sstevel@tonic-gate * command line hostnames. 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate int host_name_count; 1010Sstevel@tonic-gate char **host_name; /* store -a opts */ 1020Sstevel@tonic-gate int addrix; /* # of -a entries */ 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate /* 1060Sstevel@tonic-gate * The following 2 variables are meaningful 1070Sstevel@tonic-gate * only under a HA configuration. 1080Sstevel@tonic-gate * The path_name array is dynamically allocated in main() during 1090Sstevel@tonic-gate * command line argument processing for the -p options. 1100Sstevel@tonic-gate */ 1110Sstevel@tonic-gate char **path_name = NULL; /* store -p opts */ 1120Sstevel@tonic-gate int pathix = 0; /* # of -p entries */ 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* Global variables. Refer to sm_statd.h for description */ 1150Sstevel@tonic-gate mutex_t crash_lock; 1160Sstevel@tonic-gate int die; 1170Sstevel@tonic-gate int in_crash; 1180Sstevel@tonic-gate cond_t crash_finish; 1190Sstevel@tonic-gate mutex_t sm_trylock; 1200Sstevel@tonic-gate rwlock_t thr_rwlock; 1210Sstevel@tonic-gate cond_t retrywait; 1220Sstevel@tonic-gate mutex_t name_addrlock; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate /* forward references */ 1250Sstevel@tonic-gate static void set_statmon_owner(void); 1260Sstevel@tonic-gate static void copy_client_names(void); 1270Sstevel@tonic-gate static void one_statmon_owner(const char *); 1280Sstevel@tonic-gate static int nftw_owner(const char *, const struct stat *, int, struct FTW *); 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * statd protocol 1320Sstevel@tonic-gate * commands: 1330Sstevel@tonic-gate * SM_STAT 1340Sstevel@tonic-gate * returns stat_fail to caller 1350Sstevel@tonic-gate * SM_MON 1360Sstevel@tonic-gate * adds an entry to the monitor_q and the record_q 1370Sstevel@tonic-gate * This message is sent by the server lockd to the server 1380Sstevel@tonic-gate * statd, to indicate that a new client is to be monitored. 1390Sstevel@tonic-gate * It is also sent by the server lockd to the client statd 1400Sstevel@tonic-gate * to indicate that a new server is to be monitored. 1410Sstevel@tonic-gate * SM_UNMON 1420Sstevel@tonic-gate * removes an entry from the monitor_q and the record_q 1430Sstevel@tonic-gate * SM_UNMON_ALL 1440Sstevel@tonic-gate * removes all entries from a particular host from the 1450Sstevel@tonic-gate * monitor_q and the record_q. Our statd has this 1460Sstevel@tonic-gate * disabled. 1470Sstevel@tonic-gate * SM_SIMU_CRASH 1480Sstevel@tonic-gate * simulate a crash. removes everything from the 1490Sstevel@tonic-gate * record_q and the recovery_q, then calls statd_init() 1500Sstevel@tonic-gate * to restart things. This message is sent by the server 1510Sstevel@tonic-gate * lockd to the server statd to have all clients notified 1520Sstevel@tonic-gate * that they should reclaim locks. 1530Sstevel@tonic-gate * SM_NOTIFY 1540Sstevel@tonic-gate * Sent by statd on server to statd on client during 1550Sstevel@tonic-gate * crash recovery. The client statd passes the info 1560Sstevel@tonic-gate * to its lockd so it can attempt to reclaim the locks 1570Sstevel@tonic-gate * held on the server. 1580Sstevel@tonic-gate * 1590Sstevel@tonic-gate * There are three main hash tables used to keep track of things. 1600Sstevel@tonic-gate * mon_table 1610Sstevel@tonic-gate * table that keeps track hosts statd must watch. If one of 1620Sstevel@tonic-gate * these hosts crashes, then any locks held by that host must 1630Sstevel@tonic-gate * be released. 1640Sstevel@tonic-gate * record_table 1650Sstevel@tonic-gate * used to keep track of all the hostname files stored in 1660Sstevel@tonic-gate * the directory /var/statmon/sm. These are client hosts who 1670Sstevel@tonic-gate * are holding or have held a lock at some point. Needed 1680Sstevel@tonic-gate * to determine if a file needs to be created for host in 1690Sstevel@tonic-gate * /var/statmon/sm. 1700Sstevel@tonic-gate * recov_q 1710Sstevel@tonic-gate * used to keep track hostnames during a recovery 1720Sstevel@tonic-gate * 1730Sstevel@tonic-gate * The entries are hashed based upon the name. 1740Sstevel@tonic-gate * 1750Sstevel@tonic-gate * There is a directory /var/statmon/sm which holds a file named 1760Sstevel@tonic-gate * for each host that is holding (or has held) a lock. This is 1770Sstevel@tonic-gate * used during initialization on startup, or after a simulated 1780Sstevel@tonic-gate * crash. 1790Sstevel@tonic-gate */ 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate static void 1820Sstevel@tonic-gate sm_prog_1(rqstp, transp) 1830Sstevel@tonic-gate struct svc_req *rqstp; 1840Sstevel@tonic-gate SVCXPRT *transp; 1850Sstevel@tonic-gate { 1860Sstevel@tonic-gate union { 1870Sstevel@tonic-gate struct sm_name sm_stat_1_arg; 1880Sstevel@tonic-gate struct mon sm_mon_1_arg; 1890Sstevel@tonic-gate struct mon_id sm_unmon_1_arg; 1900Sstevel@tonic-gate struct my_id sm_unmon_all_1_arg; 1910Sstevel@tonic-gate struct stat_chge ntf_arg; 1920Sstevel@tonic-gate struct reg1args reg1_arg; 1930Sstevel@tonic-gate } argument; 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate union { 1960Sstevel@tonic-gate sm_stat_res stat_resp; 1970Sstevel@tonic-gate sm_stat mon_resp; 1980Sstevel@tonic-gate struct reg1res reg1_resp; 1990Sstevel@tonic-gate } result; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate bool_t (*xdr_argument)(), (*xdr_result)(); 2020Sstevel@tonic-gate char *(*local)(); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * Dispatch according to which protocol is being used: 2060Sstevel@tonic-gate * NSM_ADDR_PROGRAM is the private lockd address 2070Sstevel@tonic-gate * registration protocol. 2080Sstevel@tonic-gate * SM_PROG is the normal statd (NSM) protocol. 2090Sstevel@tonic-gate */ 2100Sstevel@tonic-gate if (rqstp->rq_prog == NSM_ADDR_PROGRAM) { 2110Sstevel@tonic-gate switch (rqstp->rq_proc) { 2120Sstevel@tonic-gate case NULLPROC: 2130Sstevel@tonic-gate svc_sendreply(transp, xdr_void, (caddr_t)NULL); 2140Sstevel@tonic-gate return; 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate case NSMADDRPROC1_REG: 2170Sstevel@tonic-gate xdr_argument = xdr_reg1args; 2180Sstevel@tonic-gate xdr_result = xdr_reg1res; 2190Sstevel@tonic-gate local = (char *(*)()) nsmaddrproc1_reg; 2200Sstevel@tonic-gate break; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate default: 2230Sstevel@tonic-gate svcerr_noproc(transp); 2240Sstevel@tonic-gate return; 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate } else { 2270Sstevel@tonic-gate switch (rqstp->rq_proc) { 2280Sstevel@tonic-gate case NULLPROC: 2290Sstevel@tonic-gate svc_sendreply(transp, xdr_void, (caddr_t)NULL); 2300Sstevel@tonic-gate return; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate case SM_STAT: 2330Sstevel@tonic-gate xdr_argument = xdr_sm_name; 2340Sstevel@tonic-gate xdr_result = xdr_sm_stat_res; 2350Sstevel@tonic-gate local = (char *(*)()) sm_status; 2360Sstevel@tonic-gate break; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate case SM_MON: 2390Sstevel@tonic-gate xdr_argument = xdr_mon; 2400Sstevel@tonic-gate xdr_result = xdr_sm_stat_res; 2410Sstevel@tonic-gate local = (char *(*)()) sm_mon; 2420Sstevel@tonic-gate break; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate case SM_UNMON: 2450Sstevel@tonic-gate xdr_argument = xdr_mon_id; 2460Sstevel@tonic-gate xdr_result = xdr_sm_stat; 2470Sstevel@tonic-gate local = (char *(*)()) sm_unmon; 2480Sstevel@tonic-gate break; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate case SM_UNMON_ALL: 2510Sstevel@tonic-gate xdr_argument = xdr_my_id; 2520Sstevel@tonic-gate xdr_result = xdr_sm_stat; 2530Sstevel@tonic-gate local = (char *(*)()) sm_unmon_all; 2540Sstevel@tonic-gate break; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate case SM_SIMU_CRASH: 2570Sstevel@tonic-gate xdr_argument = xdr_void; 2580Sstevel@tonic-gate xdr_result = xdr_void; 2590Sstevel@tonic-gate local = (char *(*)()) sm_simu_crash; 2600Sstevel@tonic-gate break; 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate case SM_NOTIFY: 2630Sstevel@tonic-gate xdr_argument = xdr_stat_chge; 2640Sstevel@tonic-gate xdr_result = xdr_void; 2650Sstevel@tonic-gate local = (char *(*)()) sm_notify; 2660Sstevel@tonic-gate break; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate default: 2690Sstevel@tonic-gate svcerr_noproc(transp); 2700Sstevel@tonic-gate return; 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate (void) memset(&argument, 0, sizeof (argument)); 2750Sstevel@tonic-gate if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 2760Sstevel@tonic-gate svcerr_decode(transp); 2770Sstevel@tonic-gate return; 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate (void) memset(&result, 0, sizeof (result)); 2810Sstevel@tonic-gate (*local)(&argument, &result); 2820Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_result, (caddr_t)&result)) { 2830Sstevel@tonic-gate svcerr_systemerr(transp); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 2870Sstevel@tonic-gate syslog(LOG_ERR, "statd: unable to free arguments\n"); 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * Remove all files under directory path_dir. 2930Sstevel@tonic-gate */ 2940Sstevel@tonic-gate static int 2950Sstevel@tonic-gate remove_dir(path_dir) 2960Sstevel@tonic-gate char *path_dir; 2970Sstevel@tonic-gate { 2980Sstevel@tonic-gate DIR *dp; 299871Scasper struct dirent *dirp; 3000Sstevel@tonic-gate char tmp_path[MAXPATHLEN]; 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate if ((dp = opendir(path_dir)) == (DIR *)NULL) { 3030Sstevel@tonic-gate if (debug) 3040Sstevel@tonic-gate syslog(LOG_ERR, 3050Sstevel@tonic-gate "warning: open directory %s failed: %m\n", path_dir); 3060Sstevel@tonic-gate return (1); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate 309871Scasper while ((dirp = readdir(dp)) != NULL) { 3100Sstevel@tonic-gate if (strcmp(dirp->d_name, ".") != 0 && 3110Sstevel@tonic-gate strcmp(dirp->d_name, "..") != 0) { 3120Sstevel@tonic-gate if (strlen(path_dir) + strlen(dirp->d_name) +2 > 3130Sstevel@tonic-gate MAXPATHLEN) { 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate syslog(LOG_ERR, 3160Sstevel@tonic-gate "statd: remove dir %s/%s failed. Pathname too long.\n", 3170Sstevel@tonic-gate path_dir, dirp->d_name); 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate continue; 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate (void) strcpy(tmp_path, path_dir); 3220Sstevel@tonic-gate (void) strcat(tmp_path, "/"); 3230Sstevel@tonic-gate (void) strcat(tmp_path, dirp->d_name); 3240Sstevel@tonic-gate delete_file(tmp_path); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate (void) closedir(dp); 3290Sstevel@tonic-gate return (0); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * Copy all files from directory `from_dir' to directory `to_dir'. 3340Sstevel@tonic-gate * Symlinks, if any, are preserved. 3350Sstevel@tonic-gate */ 3360Sstevel@tonic-gate void 3370Sstevel@tonic-gate copydir_from_to(from_dir, to_dir) 3380Sstevel@tonic-gate char *from_dir; 3390Sstevel@tonic-gate char *to_dir; 3400Sstevel@tonic-gate { 3410Sstevel@tonic-gate int n; 3420Sstevel@tonic-gate DIR *dp; 343871Scasper struct dirent *dirp; 3440Sstevel@tonic-gate char rname[MAXNAMELEN + 1]; 3450Sstevel@tonic-gate char path[MAXPATHLEN+MAXNAMELEN+2]; 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate if ((dp = opendir(from_dir)) == (DIR *)NULL) { 3480Sstevel@tonic-gate if (debug) 3490Sstevel@tonic-gate syslog(LOG_ERR, 3500Sstevel@tonic-gate "warning: open directory %s failed: %m\n", from_dir); 3510Sstevel@tonic-gate return; 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 354871Scasper while ((dirp = readdir(dp)) != NULL) { 3550Sstevel@tonic-gate if (strcmp(dirp->d_name, ".") == 0 || 3560Sstevel@tonic-gate strcmp(dirp->d_name, "..") == 0) { 3570Sstevel@tonic-gate continue; 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate (void) strcpy(path, from_dir); 3610Sstevel@tonic-gate (void) strcat(path, "/"); 3620Sstevel@tonic-gate (void) strcat(path, dirp->d_name); 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate if (is_symlink(path)) { 3650Sstevel@tonic-gate /* 3660Sstevel@tonic-gate * Follow the link to get the referenced file name 3670Sstevel@tonic-gate * and make a new link for that file in to_dir. 3680Sstevel@tonic-gate */ 3690Sstevel@tonic-gate n = readlink(path, rname, MAXNAMELEN); 3700Sstevel@tonic-gate if (n <= 0) { 3710Sstevel@tonic-gate if (debug >= 2) { 3720Sstevel@tonic-gate (void) printf( 3730Sstevel@tonic-gate "copydir_from_to: can't read link %s\n", 3740Sstevel@tonic-gate path); 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate continue; 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate rname[n] = '\0'; 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate (void) create_symlink(to_dir, rname, dirp->d_name); 3810Sstevel@tonic-gate } else { 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * Simply copy regular files to to_dir. 3840Sstevel@tonic-gate */ 3850Sstevel@tonic-gate (void) strcpy(path, to_dir); 3860Sstevel@tonic-gate (void) strcat(path, "/"); 3870Sstevel@tonic-gate (void) strcat(path, dirp->d_name); 3880Sstevel@tonic-gate (void) create_file(path); 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate (void) closedir(dp); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate static int 3960Sstevel@tonic-gate init_hostname(void) 3970Sstevel@tonic-gate { 3980Sstevel@tonic-gate struct lifnum lifn; 3990Sstevel@tonic-gate int sock; 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 4020Sstevel@tonic-gate syslog(LOG_ERR, "statd:init_hostname, socket: %m"); 4030Sstevel@tonic-gate return (-1); 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC; 4070Sstevel@tonic-gate lifn.lifn_flags = 0; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 4100Sstevel@tonic-gate syslog(LOG_ERR, 4110Sstevel@tonic-gate "statd:init_hostname, get number of interfaces, error: %m"); 4120Sstevel@tonic-gate close(sock); 4130Sstevel@tonic-gate return (-1); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate host_name_count = lifn.lifn_count; 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate host_name = (char **)malloc(host_name_count * sizeof (char *)); 4190Sstevel@tonic-gate if (host_name == NULL) { 4200Sstevel@tonic-gate perror("statd -a can't get ip configuration\n"); 4210Sstevel@tonic-gate close(sock); 4220Sstevel@tonic-gate return (-1); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate close(sock); 4250Sstevel@tonic-gate return (0); 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate 428249Sjwahlig int 429249Sjwahlig main(int argc, char *argv[]) 4300Sstevel@tonic-gate { 4310Sstevel@tonic-gate int c; 4320Sstevel@tonic-gate int ppid; 4330Sstevel@tonic-gate extern char *optarg; 4340Sstevel@tonic-gate int choice = 0; 4350Sstevel@tonic-gate struct rlimit rl; 4360Sstevel@tonic-gate int mode; 4370Sstevel@tonic-gate int sz; 4380Sstevel@tonic-gate int connmaxrec = RPC_MAXDATASIZE; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate addrix = 0; 4410Sstevel@tonic-gate pathix = 0; 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate (void) gethostname(hostname, MAXHOSTNAMELEN); 4440Sstevel@tonic-gate if (init_hostname() < 0) 4450Sstevel@tonic-gate exit(1); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate while ((c = getopt(argc, argv, "Dd:a:p:r")) != EOF) 4480Sstevel@tonic-gate switch (c) { 4490Sstevel@tonic-gate case 'd': 4500Sstevel@tonic-gate (void) sscanf(optarg, "%d", &debug); 4510Sstevel@tonic-gate break; 4520Sstevel@tonic-gate case 'D': 4530Sstevel@tonic-gate choice = 1; 4540Sstevel@tonic-gate break; 4550Sstevel@tonic-gate case 'a': 4560Sstevel@tonic-gate if (addrix < host_name_count) { 4570Sstevel@tonic-gate if (strcmp(hostname, optarg) != 0) { 4580Sstevel@tonic-gate sz = strlen(optarg); 4590Sstevel@tonic-gate if (sz < MAXHOSTNAMELEN) { 4600Sstevel@tonic-gate host_name[addrix] = 4610Sstevel@tonic-gate (char *)xmalloc(sz+1); 4620Sstevel@tonic-gate if (host_name[addrix] != 4630Sstevel@tonic-gate NULL) { 4640Sstevel@tonic-gate (void) sscanf(optarg, "%s", 4650Sstevel@tonic-gate host_name[addrix]); 4660Sstevel@tonic-gate addrix++; 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate } else 4690Sstevel@tonic-gate (void) fprintf(stderr, 4700Sstevel@tonic-gate "statd: -a name of host is too long.\n"); 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate } else 4730Sstevel@tonic-gate (void) fprintf(stderr, 4740Sstevel@tonic-gate "statd: -a exceeding maximum hostnames\n"); 4750Sstevel@tonic-gate break; 4760Sstevel@tonic-gate case 'p': 4770Sstevel@tonic-gate if (strlen(optarg) < MAXPATHLEN) { 4780Sstevel@tonic-gate /* If the path_name array has not yet */ 4790Sstevel@tonic-gate /* been malloc'ed, do that. The array */ 4800Sstevel@tonic-gate /* should be big enough to hold all of the */ 4810Sstevel@tonic-gate /* -p options we might have. An upper */ 4820Sstevel@tonic-gate /* bound on the number of -p options is */ 4830Sstevel@tonic-gate /* argc/2, because each -p option consumes */ 4840Sstevel@tonic-gate /* two arguments. Here the upper bound */ 4850Sstevel@tonic-gate /* is supposing that all the command line */ 4860Sstevel@tonic-gate /* arguments are -p options, which would */ 4870Sstevel@tonic-gate /* actually never be the case. */ 4880Sstevel@tonic-gate if (path_name == NULL) { 4890Sstevel@tonic-gate size_t sz = (argc/2) * sizeof (char *); 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate path_name = (char **)malloc(sz); 4920Sstevel@tonic-gate if (path_name == NULL) { 4930Sstevel@tonic-gate (void) fprintf(stderr, 4940Sstevel@tonic-gate "statd: malloc failed\n"); 4950Sstevel@tonic-gate exit(1); 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate (void) memset(path_name, 0, sz); 4980Sstevel@tonic-gate } 4990Sstevel@tonic-gate path_name[pathix] = optarg; 5000Sstevel@tonic-gate pathix++; 5010Sstevel@tonic-gate } else { 5020Sstevel@tonic-gate (void) fprintf(stderr, 5030Sstevel@tonic-gate "statd: -p pathname is too long.\n"); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate break; 5060Sstevel@tonic-gate case 'r': 5070Sstevel@tonic-gate regfiles_only = 1; 5080Sstevel@tonic-gate break; 5090Sstevel@tonic-gate default: 5100Sstevel@tonic-gate (void) fprintf(stderr, 5110Sstevel@tonic-gate "statd [-d level] [-D]\n"); 5120Sstevel@tonic-gate return (1); 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate if (choice == 0) { 5160Sstevel@tonic-gate (void) strcpy(statd_home, home0); 5170Sstevel@tonic-gate (void) strcpy(CURRENT, current0); 5180Sstevel@tonic-gate (void) strcpy(BACKUP, backup0); 5190Sstevel@tonic-gate (void) strcpy(STATE, state0); 5200Sstevel@tonic-gate } else { 5210Sstevel@tonic-gate (void) strcpy(statd_home, home1); 5220Sstevel@tonic-gate (void) strcpy(CURRENT, current1); 5230Sstevel@tonic-gate (void) strcpy(BACKUP, backup1); 5240Sstevel@tonic-gate (void) strcpy(STATE, state1); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate if (debug) 5270Sstevel@tonic-gate (void) printf("debug is on, create entry: %s, %s, %s\n", 5280Sstevel@tonic-gate CURRENT, BACKUP, STATE); 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl)) 5310Sstevel@tonic-gate (void) printf("statd: getrlimit failed. \n"); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate /* Set maxfdlimit current soft limit */ 5340Sstevel@tonic-gate rl.rlim_cur = MAX_FDS; 5350Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) != 0) 5360Sstevel@tonic-gate syslog(LOG_ERR, "statd: unable to set RLIMIT_NOFILE to %d\n", 5370Sstevel@tonic-gate MAX_FDS); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate if (!debug) { 5400Sstevel@tonic-gate ppid = fork(); 5410Sstevel@tonic-gate if (ppid == -1) { 5420Sstevel@tonic-gate (void) fprintf(stderr, "statd: fork failure\n"); 5430Sstevel@tonic-gate (void) fflush(stderr); 5440Sstevel@tonic-gate abort(); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate if (ppid != 0) { 5470Sstevel@tonic-gate exit(0); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate closefrom(0); 5500Sstevel@tonic-gate (void) open("/dev/null", O_RDONLY); 5510Sstevel@tonic-gate (void) open("/dev/null", O_WRONLY); 5520Sstevel@tonic-gate (void) dup(1); 5530Sstevel@tonic-gate (void) setsid(); 5540Sstevel@tonic-gate openlog("statd", LOG_PID, LOG_DAEMON); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate (void) _create_daemon_lock(STATD, DAEMON_UID, DAEMON_GID); 5580Sstevel@tonic-gate /* 5590Sstevel@tonic-gate * establish our lock on the lock file and write our pid to it. 5600Sstevel@tonic-gate * exit if some other process holds the lock, or if there's any 5610Sstevel@tonic-gate * error in writing/locking the file. 5620Sstevel@tonic-gate */ 5630Sstevel@tonic-gate ppid = _enter_daemon_lock(STATD); 5640Sstevel@tonic-gate switch (ppid) { 5650Sstevel@tonic-gate case 0: 5660Sstevel@tonic-gate break; 5670Sstevel@tonic-gate case -1: 5680Sstevel@tonic-gate syslog(LOG_ERR, "error locking for %s: %s", STATD, 5690Sstevel@tonic-gate strerror(errno)); 5700Sstevel@tonic-gate exit(2); 5710Sstevel@tonic-gate default: 5720Sstevel@tonic-gate /* daemon was already running */ 5730Sstevel@tonic-gate exit(0); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate /* Get other aliases from each interface. */ 5770Sstevel@tonic-gate merge_hosts(); 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate /* 5800Sstevel@tonic-gate * Set to automatic mode such that threads are automatically 5810Sstevel@tonic-gate * created 5820Sstevel@tonic-gate */ 5830Sstevel@tonic-gate mode = RPC_SVC_MT_AUTO; 5840Sstevel@tonic-gate if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) { 5850Sstevel@tonic-gate syslog(LOG_ERR, 5860Sstevel@tonic-gate "statd:unable to set automatic MT mode."); 5870Sstevel@tonic-gate exit(1); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate /* 5910Sstevel@tonic-gate * Set non-blocking mode and maximum record size for 5920Sstevel@tonic-gate * connection oriented RPC transports. 5930Sstevel@tonic-gate */ 5940Sstevel@tonic-gate if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { 5950Sstevel@tonic-gate syslog(LOG_INFO, "unable to set maximum RPC record size"); 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) { 5990Sstevel@tonic-gate syslog(LOG_ERR, 6000Sstevel@tonic-gate "statd: unable to create (SM_PROG, SM_VERS) for netpath."); 6010Sstevel@tonic-gate exit(1); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) { 6050Sstevel@tonic-gate syslog(LOG_ERR, 6060Sstevel@tonic-gate "statd: unable to create (NSM_ADDR_PROGRAM, NSM_ADDR_V1) for netpath."); 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate /* 6100Sstevel@tonic-gate * Make sure /var/statmon and any alternate (-p) statmon 6110Sstevel@tonic-gate * directories exist and are owned by daemon. Then change our uid 6120Sstevel@tonic-gate * to daemon. The uid change is to prevent attacks against local 6130Sstevel@tonic-gate * daemons that trust any call from a local root process. 6140Sstevel@tonic-gate */ 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate set_statmon_owner(); 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate /* 6190Sstevel@tonic-gate * 6200Sstevel@tonic-gate * statd now runs as a daemon rather than root and can not 6210Sstevel@tonic-gate * dump core under / because of the permission. It is 6220Sstevel@tonic-gate * important that current working directory of statd be 6230Sstevel@tonic-gate * changed to writable directory /var/statmon so that it 6240Sstevel@tonic-gate * can dump the core upon the receipt of the signal. 6250Sstevel@tonic-gate * One still need to set allow_setid_core to non-zero in 6260Sstevel@tonic-gate * /etc/system to get the core dump. 6270Sstevel@tonic-gate * 6280Sstevel@tonic-gate */ 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate if (chdir(statd_home) < 0) { 6310Sstevel@tonic-gate syslog(LOG_ERR, "can't chdir %s: %m", statd_home); 6320Sstevel@tonic-gate exit(1); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate copy_client_names(); 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate rwlock_init(&thr_rwlock, USYNC_THREAD, NULL); 6380Sstevel@tonic-gate mutex_init(&crash_lock, USYNC_THREAD, NULL); 6390Sstevel@tonic-gate mutex_init(&name_addrlock, USYNC_THREAD, NULL); 6400Sstevel@tonic-gate cond_init(&crash_finish, USYNC_THREAD, NULL); 6410Sstevel@tonic-gate cond_init(&retrywait, USYNC_THREAD, NULL); 6420Sstevel@tonic-gate sm_inithash(); 6430Sstevel@tonic-gate die = 0; 6440Sstevel@tonic-gate /* 6450Sstevel@tonic-gate * This variable is set to ensure that an sm_crash 6460Sstevel@tonic-gate * request will not be done at the same time 6470Sstevel@tonic-gate * when a statd_init is being done, since sm_crash 6480Sstevel@tonic-gate * can reset some variables that statd_init will be using. 6490Sstevel@tonic-gate */ 6500Sstevel@tonic-gate in_crash = 1; 6510Sstevel@tonic-gate statd_init(); 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate if (debug) 6540Sstevel@tonic-gate (void) printf("Starting svc_run\n"); 6550Sstevel@tonic-gate svc_run(); 6560Sstevel@tonic-gate syslog(LOG_ERR, "statd: svc_run returned\n"); 6570Sstevel@tonic-gate /* NOTREACHED */ 6580Sstevel@tonic-gate thr_exit((void *) 1); 659249Sjwahlig return (0); 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate /* 6640Sstevel@tonic-gate * Make sure the ownership of the statmon directories is correct, then 6650Sstevel@tonic-gate * change our uid to match. If the top-level directories (/var/statmon, -p 6660Sstevel@tonic-gate * arguments) don't exist, they are created first. The sm and sm.bak 6670Sstevel@tonic-gate * directories are not created here, but if they already exist, they are 6680Sstevel@tonic-gate * chowned to the correct uid, along with anything else in the 6690Sstevel@tonic-gate * directories. 6700Sstevel@tonic-gate */ 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate static void 673*1676Sjpk set_statmon_owner(void) 6740Sstevel@tonic-gate { 6750Sstevel@tonic-gate int i; 676*1676Sjpk boolean_t can_do_mlp; 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate /* 6790Sstevel@tonic-gate * Recursively chown/chgrp /var/statmon and the alternate paths, 6800Sstevel@tonic-gate * creating them if necessary. 6810Sstevel@tonic-gate */ 6820Sstevel@tonic-gate one_statmon_owner(statd_home); 6830Sstevel@tonic-gate for (i = 0; i < pathix; i++) { 6840Sstevel@tonic-gate char alt_path[MAXPATHLEN]; 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate snprintf(alt_path, MAXPATHLEN, "%s/statmon", path_name[i]); 6870Sstevel@tonic-gate one_statmon_owner(alt_path); 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 690*1676Sjpk can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP); 6910Sstevel@tonic-gate if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 692*1676Sjpk DAEMON_UID, DAEMON_GID, can_do_mlp ? PRIV_NET_BINDMLP : NULL, 693*1676Sjpk NULL) == -1) { 6940Sstevel@tonic-gate syslog(LOG_ERR, "can't run unprivileged: %m"); 6950Sstevel@tonic-gate exit(1); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION, 6990Sstevel@tonic-gate PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate /* 7030Sstevel@tonic-gate * Copy client names from the alternate statmon directories into 7040Sstevel@tonic-gate * /var/statmon. The top-level (statmon) directories should already 7050Sstevel@tonic-gate * exist, though the sm and sm.bak directories might not. 7060Sstevel@tonic-gate */ 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate static void 7090Sstevel@tonic-gate copy_client_names() 7100Sstevel@tonic-gate { 7110Sstevel@tonic-gate int i; 7120Sstevel@tonic-gate char buf[MAXPATHLEN+SM_MAXPATHLEN]; 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate /* 7150Sstevel@tonic-gate * Copy all clients from alternate paths to /var/statmon/sm 7160Sstevel@tonic-gate * Remove the files in alternate directory when copying is done. 7170Sstevel@tonic-gate */ 7180Sstevel@tonic-gate for (i = 0; i < pathix; i++) { 7190Sstevel@tonic-gate /* 7200Sstevel@tonic-gate * If the alternate directories do not exist, create it. 7210Sstevel@tonic-gate * If they do exist, just do the copy. 7220Sstevel@tonic-gate */ 7230Sstevel@tonic-gate snprintf(buf, sizeof (buf), "%s/statmon/sm", path_name[i]); 7240Sstevel@tonic-gate if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) { 7250Sstevel@tonic-gate if (errno != EEXIST) { 7260Sstevel@tonic-gate syslog(LOG_ERR, 7270Sstevel@tonic-gate "can't mkdir %s: %m\n", buf); 7280Sstevel@tonic-gate continue; 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate copydir_from_to(buf, CURRENT); 7310Sstevel@tonic-gate (void) remove_dir(buf); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s/statmon/sm.bak", 7350Sstevel@tonic-gate path_name[i]); 7360Sstevel@tonic-gate if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) { 7370Sstevel@tonic-gate if (errno != EEXIST) { 7380Sstevel@tonic-gate syslog(LOG_ERR, 7390Sstevel@tonic-gate "can't mkdir %s: %m\n", buf); 7400Sstevel@tonic-gate continue; 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate copydir_from_to(buf, BACKUP); 7430Sstevel@tonic-gate (void) remove_dir(buf); 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate /* 7490Sstevel@tonic-gate * Create the given directory if it doesn't already exist. Set the user 7500Sstevel@tonic-gate * and group to daemon for the directory and anything under it. 7510Sstevel@tonic-gate */ 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate static void 7540Sstevel@tonic-gate one_statmon_owner(const char *dir) 7550Sstevel@tonic-gate { 7560Sstevel@tonic-gate if ((mkdir(dir, SM_DIRECTORY_MODE)) == -1) { 7570Sstevel@tonic-gate if (errno != EEXIST) { 7580Sstevel@tonic-gate syslog(LOG_ERR, "can't mkdir %s: %m", 7590Sstevel@tonic-gate dir); 7600Sstevel@tonic-gate return; 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate if (debug) 7650Sstevel@tonic-gate printf("Setting owner for %s\n", dir); 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate if (nftw(dir, nftw_owner, MAX_FDS, FTW_PHYS) != 0) { 7680Sstevel@tonic-gate syslog(LOG_WARNING, "error setting owner for %s: %m", 7690Sstevel@tonic-gate dir); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate /* 7740Sstevel@tonic-gate * Set the user and group to daemon for the given file or directory. If 7750Sstevel@tonic-gate * it's a directory, also makes sure that it is mode 755. 7760Sstevel@tonic-gate * Generates a syslog message but does not return an error if there were 7770Sstevel@tonic-gate * problems. 7780Sstevel@tonic-gate */ 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate /*ARGSUSED3*/ 7810Sstevel@tonic-gate static int 7820Sstevel@tonic-gate nftw_owner(const char *path, const struct stat *statp, int info, 7830Sstevel@tonic-gate struct FTW *ftw) 7840Sstevel@tonic-gate { 7850Sstevel@tonic-gate if (!(info == FTW_F || info == FTW_D)) 7860Sstevel@tonic-gate return (0); 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate /* 7890Sstevel@tonic-gate * Some older systems might have mode 777 directories. Fix that. 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate if (info == FTW_D && (statp->st_mode & (S_IWGRP | S_IWOTH)) != 0) { 7930Sstevel@tonic-gate mode_t newmode = (statp->st_mode & ~(S_IWGRP | S_IWOTH)) & 7940Sstevel@tonic-gate S_IAMB; 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate if (debug) 7970Sstevel@tonic-gate printf("chmod %03o %s\n", newmode, path); 7980Sstevel@tonic-gate if (chmod(path, newmode) < 0) { 7990Sstevel@tonic-gate int error = errno; 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate syslog(LOG_WARNING, "can't chmod %s to %03o: %m", 8020Sstevel@tonic-gate path, newmode); 8030Sstevel@tonic-gate if (debug) 8040Sstevel@tonic-gate printf(" FAILED: %s\n", strerror(error)); 8050Sstevel@tonic-gate } 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate /* If already owned by daemon, don't bother changing. */ 8090Sstevel@tonic-gate if (statp->st_uid == DAEMON_UID && 8100Sstevel@tonic-gate statp->st_gid == DAEMON_GID) 8110Sstevel@tonic-gate return (0); 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate if (debug) 8140Sstevel@tonic-gate printf("lchown %s daemon:daemon\n", path); 8150Sstevel@tonic-gate if (lchown(path, DAEMON_UID, DAEMON_GID) < 0) { 8160Sstevel@tonic-gate int error = errno; 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate syslog(LOG_WARNING, "can't chown %s to daemon: %m", 8190Sstevel@tonic-gate path); 8200Sstevel@tonic-gate if (debug) 8210Sstevel@tonic-gate printf(" FAILED: %s\n", strerror(error)); 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate return (0); 8250Sstevel@tonic-gate } 826