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