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