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