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 /*
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 /*
41 * Copyright (c) 2012 by Delphix. All rights reserved.
42 */
43
44 #include <stdio.h>
45 #include <stdio_ext.h>
46 #include <stdlib.h>
47 #include <ftw.h>
48 #include <signal.h>
49 #include <string.h>
50 #include <syslog.h>
51 #include <netconfig.h>
52 #include <unistd.h>
53 #include <netdb.h>
54 #include <rpc/rpc.h>
55 #include <netinet/in.h>
56 #include <sys/param.h>
57 #include <sys/resource.h>
58 #include <sys/file.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <sys/sockio.h>
62 #include <dirent.h>
63 #include <errno.h>
64 #include <rpcsvc/sm_inter.h>
65 #include <rpcsvc/nsm_addr.h>
66 #include <thread.h>
67 #include <synch.h>
68 #include <net/if.h>
69 #include <limits.h>
70 #include <rpcsvc/daemon_utils.h>
71 #include <priv_utils.h>
72 #include "sm_statd.h"
73
74
75 #define home0 "/var/statmon"
76 #define current0 "/var/statmon/sm"
77 #define backup0 "/var/statmon/sm.bak"
78 #define state0 "/var/statmon/state"
79
80 #define home1 "statmon"
81 #define current1 "statmon/sm/"
82 #define backup1 "statmon/sm.bak/"
83 #define state1 "statmon/state"
84
85 extern int daemonize_init(void);
86 extern void daemonize_fini(int fd);
87
88 /*
89 * User and group IDs to run as. These are hardwired, rather than looked
90 * up at runtime, because they are very unlikely to change and because they
91 * provide some protection against bogus changes to the passwd and group
92 * files.
93 */
94 uid_t daemon_uid = DAEMON_UID;
95 gid_t daemon_gid = DAEMON_GID;
96
97 char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN];
98 static char statd_home[MAXPATHLEN];
99
100 int debug;
101 int regfiles_only = 0; /* 1 => use symlinks in statmon, 0 => don't */
102 char hostname[MAXHOSTNAMELEN];
103
104 /*
105 * These variables will be used to store all the
106 * alias names for the host, as well as the -a
107 * command line hostnames.
108 */
109 int host_name_count;
110 char **host_name; /* store -a opts */
111 int addrix; /* # of -a entries */
112
113
114 /*
115 * The following 2 variables are meaningful
116 * only under a HA configuration.
117 * The path_name array is dynamically allocated in main() during
118 * command line argument processing for the -p options.
119 */
120 char **path_name = NULL; /* store -p opts */
121 int pathix = 0; /* # of -p entries */
440 {
441 /*
442 * Get other aliases from each interface.
443 */
444 merge_hosts();
445
446 /*
447 * Get all of the configured IP addresses.
448 */
449 merge_ips();
450
451 /*
452 * Notify the waiters.
453 */
454 (void) mutex_lock(&merges_lock);
455 in_merges = B_FALSE;
456 (void) cond_broadcast(&merges_cond);
457 (void) mutex_unlock(&merges_lock);
458 }
459
460 int
461 main(int argc, char *argv[])
462 {
463 int c;
464 int ppid;
465 extern char *optarg;
466 int choice = 0;
467 struct rlimit rl;
468 int mode;
469 int sz;
470 int pipe_fd = -1;
471 int connmaxrec = RPC_MAXDATASIZE;
472
473 addrix = 0;
474 pathix = 0;
475
476 (void) gethostname(hostname, MAXHOSTNAMELEN);
477 if (init_hostname() < 0)
478 exit(1);
479
480 while ((c = getopt(argc, argv, "Dd:a:G:p:rU:")) != EOF)
481 switch (c) {
482 case 'd':
483 (void) sscanf(optarg, "%d", &debug);
484 break;
485 case 'D':
486 choice = 1;
487 break;
488 case 'a':
489 if (addrix < host_name_count) {
490 if (strcmp(hostname, optarg) != 0) {
491 sz = strlen(optarg);
492 if (sz < MAXHOSTNAMELEN) {
493 host_name[addrix] =
494 (char *)xmalloc(sz+1);
495 if (host_name[addrix] !=
496 NULL) {
497 (void) sscanf(optarg, "%s",
498 host_name[addrix]);
499 addrix++;
500 }
525 /* arguments are -p options, which would */
526 /* actually never be the case. */
527 if (path_name == NULL) {
528 size_t sz = (argc/2) * sizeof (char *);
529
530 path_name = (char **)malloc(sz);
531 if (path_name == NULL) {
532 (void) fprintf(stderr,
533 "statd: malloc failed\n");
534 exit(1);
535 }
536 (void) memset(path_name, 0, sz);
537 }
538 path_name[pathix] = optarg;
539 pathix++;
540 } else {
541 (void) fprintf(stderr,
542 "statd: -p pathname is too long.\n");
543 }
544 break;
545 case 'r':
546 regfiles_only = 1;
547 break;
548 default:
549 (void) fprintf(stderr,
550 "statd [-d level] [-D]\n");
551 return (1);
552 }
553
554 if (choice == 0) {
555 (void) strcpy(statd_home, home0);
556 (void) strcpy(CURRENT, current0);
557 (void) strcpy(BACKUP, backup0);
558 (void) strcpy(STATE, state0);
559 } else {
560 (void) strcpy(statd_home, home1);
561 (void) strcpy(CURRENT, current1);
562 (void) strcpy(BACKUP, backup1);
563 (void) strcpy(STATE, state1);
564 }
619
620 /*
621 * Set to automatic mode such that threads are automatically
622 * created
623 */
624 mode = RPC_SVC_MT_AUTO;
625 if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) {
626 syslog(LOG_ERR,
627 "statd:unable to set automatic MT mode.");
628 exit(1);
629 }
630
631 /*
632 * Set non-blocking mode and maximum record size for
633 * connection oriented RPC transports.
634 */
635 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
636 syslog(LOG_INFO, "unable to set maximum RPC record size");
637 }
638
639 if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) {
640 syslog(LOG_ERR, "statd: unable to create (SM_PROG, SM_VERS) "
641 "for netpath.");
642 exit(1);
643 }
644
645 if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) {
646 syslog(LOG_ERR, "statd: unable to create (NSM_ADDR_PROGRAM, "
647 "NSM_ADDR_V1) for netpath.");
648 }
649
650 /*
651 * Make sure /var/statmon and any alternate (-p) statmon
652 * directories exist and are owned by daemon. Then change our uid
653 * to daemon. The uid change is to prevent attacks against local
654 * daemons that trust any call from a local root process.
655 */
656
657 set_statmon_owner();
658
659 /*
660 *
661 * statd now runs as a daemon rather than root and can not
662 * dump core under / because of the permission. It is
663 * important that current working directory of statd be
664 * changed to writable directory /var/statmon so that it
665 * can dump the core upon the receipt of the signal.
666 * One still need to set allow_setid_core to non-zero in
667 * /etc/system to get the core dump.
668 *
|
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 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
25 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 /*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
41 #include <stdio.h>
42 #include <stdio_ext.h>
43 #include <stdlib.h>
44 #include <ftw.h>
45 #include <signal.h>
46 #include <string.h>
47 #include <syslog.h>
48 #include <netconfig.h>
49 #include <netdir.h>
50 #include <unistd.h>
51 #include <netdb.h>
52 #include <rpc/rpc.h>
53 #include <rpc/svc.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 "smfcfg.h"
72 #include "sm_statd.h"
73
74
75 #define home0 "/var/statmon"
76 #define current0 "/var/statmon/sm"
77 #define backup0 "/var/statmon/sm.bak"
78 #define state0 "/var/statmon/state"
79
80 #define home1 "statmon"
81 #define current1 "statmon/sm/"
82 #define backup1 "statmon/sm.bak/"
83 #define state1 "statmon/state"
84
85 extern int daemonize_init(void);
86 extern void daemonize_fini(int fd);
87
88 /*
89 * User and group IDs to run as. These are hardwired, rather than looked
90 * up at runtime, because they are very unlikely to change and because they
91 * provide some protection against bogus changes to the passwd and group
92 * files.
93 */
94 uid_t daemon_uid = DAEMON_UID;
95 gid_t daemon_gid = DAEMON_GID;
96
97 char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN];
98 static char statd_home[MAXPATHLEN];
99
100 int debug;
101 int regfiles_only = 0; /* 1 => use symlinks in statmon, 0 => don't */
102 int statd_port = 0;
103 char hostname[MAXHOSTNAMELEN];
104
105 /*
106 * These variables will be used to store all the
107 * alias names for the host, as well as the -a
108 * command line hostnames.
109 */
110 int host_name_count;
111 char **host_name; /* store -a opts */
112 int addrix; /* # of -a entries */
113
114
115 /*
116 * The following 2 variables are meaningful
117 * only under a HA configuration.
118 * The path_name array is dynamically allocated in main() during
119 * command line argument processing for the -p options.
120 */
121 char **path_name = NULL; /* store -p opts */
122 int pathix = 0; /* # of -p entries */
441 {
442 /*
443 * Get other aliases from each interface.
444 */
445 merge_hosts();
446
447 /*
448 * Get all of the configured IP addresses.
449 */
450 merge_ips();
451
452 /*
453 * Notify the waiters.
454 */
455 (void) mutex_lock(&merges_lock);
456 in_merges = B_FALSE;
457 (void) cond_broadcast(&merges_cond);
458 (void) mutex_unlock(&merges_lock);
459 }
460
461 /*
462 * This function is called for each configured network type to
463 * bind and register our RPC service programs.
464 *
465 * On TCP or UDP, we may want to bind SM_PROG on a specific port
466 * (when statd_port is specified) in which case we'll use the
467 * variant of svc_tp_create() that lets us pass a bind address.
468 */
469 static void
470 sm_svc_tp_create(struct netconfig *nconf)
471 {
472 char port_str[8];
473 struct nd_hostserv hs;
474 struct nd_addrlist *al = NULL;
475 SVCXPRT *xprt = NULL;
476
477 /*
478 * If statd_port is set and this is an inet transport,
479 * bind this service on the specified port. The TLI way
480 * to create such a bind address is netdir_getbyname()
481 * with the special "host" HOST_SELF_BIND. This builds
482 * an all-zeros IP address with the specified port.
483 */
484 if (statd_port != 0 &&
485 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
486 strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
487 int err;
488
489 snprintf(port_str, sizeof (port_str), "%u",
490 (unsigned short)statd_port);
491
492 hs.h_host = HOST_SELF_BIND;
493 hs.h_serv = port_str;
494 err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
495 if (err == 0 && al != NULL) {
496 xprt = svc_tp_create_addr(sm_prog_1, SM_PROG, SM_VERS,
497 nconf, al->n_addrs);
498 netdir_free(al, ND_ADDRLIST);
499 }
500 if (xprt == NULL) {
501 syslog(LOG_ERR, "statd: unable to create "
502 "(SM_PROG, SM_VERS) on transport %s (port %d)",
503 nconf->nc_netid, statd_port);
504 }
505 /* fall-back to default bind */
506 }
507 if (xprt == NULL) {
508 /*
509 * Had statd_port=0, or non-inet transport,
510 * or the bind to a specific port failed.
511 * Do a default bind.
512 */
513 xprt = svc_tp_create(sm_prog_1, SM_PROG, SM_VERS, nconf);
514 }
515 if (xprt == NULL) {
516 syslog(LOG_ERR, "statd: unable to create "
517 "(SM_PROG, SM_VERS) for transport %s",
518 nconf->nc_netid);
519 return;
520 }
521
522 /*
523 * Also register the NSM_ADDR program on this
524 * transport handle (same dispatch function).
525 */
526 if (!svc_reg(xprt, NSM_ADDR_PROGRAM, NSM_ADDR_V1, sm_prog_1, nconf)) {
527 syslog(LOG_ERR, "statd: failed to register "
528 "(NSM_ADDR_PROGRAM, NSM_ADDR_V1) for "
529 "netconfig %s", nconf->nc_netid);
530 }
531 }
532
533 int
534 main(int argc, char *argv[])
535 {
536 int c;
537 int ppid;
538 extern char *optarg;
539 int choice = 0;
540 struct rlimit rl;
541 int mode;
542 int sz;
543 int pipe_fd = -1;
544 int ret;
545 int connmaxrec = RPC_MAXDATASIZE;
546 struct netconfig *nconf;
547 NCONF_HANDLE *nc;
548
549 addrix = 0;
550 pathix = 0;
551
552 (void) gethostname(hostname, MAXHOSTNAMELEN);
553 if (init_hostname() < 0)
554 exit(1);
555
556 ret = nfs_smf_get_iprop("statd_port", &statd_port,
557 DEFAULT_INSTANCE, SCF_TYPE_INTEGER, STATD);
558 if (ret != SA_OK) {
559 syslog(LOG_ERR, "Reading of statd_port from SMF "
560 "failed, using default value");
561 }
562
563 while ((c = getopt(argc, argv, "Dd:a:G:p:P:rU:")) != EOF)
564 switch (c) {
565 case 'd':
566 (void) sscanf(optarg, "%d", &debug);
567 break;
568 case 'D':
569 choice = 1;
570 break;
571 case 'a':
572 if (addrix < host_name_count) {
573 if (strcmp(hostname, optarg) != 0) {
574 sz = strlen(optarg);
575 if (sz < MAXHOSTNAMELEN) {
576 host_name[addrix] =
577 (char *)xmalloc(sz+1);
578 if (host_name[addrix] !=
579 NULL) {
580 (void) sscanf(optarg, "%s",
581 host_name[addrix]);
582 addrix++;
583 }
608 /* arguments are -p options, which would */
609 /* actually never be the case. */
610 if (path_name == NULL) {
611 size_t sz = (argc/2) * sizeof (char *);
612
613 path_name = (char **)malloc(sz);
614 if (path_name == NULL) {
615 (void) fprintf(stderr,
616 "statd: malloc failed\n");
617 exit(1);
618 }
619 (void) memset(path_name, 0, sz);
620 }
621 path_name[pathix] = optarg;
622 pathix++;
623 } else {
624 (void) fprintf(stderr,
625 "statd: -p pathname is too long.\n");
626 }
627 break;
628 case 'P':
629 (void) sscanf(optarg, "%d", &statd_port);
630 if (statd_port < 1 || statd_port > UINT16_MAX) {
631 (void) fprintf(stderr,
632 "statd: -P port invalid.\n");
633 statd_port = 0;
634 }
635 break;
636 case 'r':
637 regfiles_only = 1;
638 break;
639 default:
640 (void) fprintf(stderr,
641 "statd [-d level] [-D]\n");
642 return (1);
643 }
644
645 if (choice == 0) {
646 (void) strcpy(statd_home, home0);
647 (void) strcpy(CURRENT, current0);
648 (void) strcpy(BACKUP, backup0);
649 (void) strcpy(STATE, state0);
650 } else {
651 (void) strcpy(statd_home, home1);
652 (void) strcpy(CURRENT, current1);
653 (void) strcpy(BACKUP, backup1);
654 (void) strcpy(STATE, state1);
655 }
710
711 /*
712 * Set to automatic mode such that threads are automatically
713 * created
714 */
715 mode = RPC_SVC_MT_AUTO;
716 if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) {
717 syslog(LOG_ERR,
718 "statd:unable to set automatic MT mode.");
719 exit(1);
720 }
721
722 /*
723 * Set non-blocking mode and maximum record size for
724 * connection oriented RPC transports.
725 */
726 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
727 syslog(LOG_INFO, "unable to set maximum RPC record size");
728 }
729
730 /*
731 * Enumerate network transports and create service listeners
732 * as appropriate for each.
733 */
734 if ((nc = setnetconfig()) == NULL) {
735 syslog(LOG_ERR, "setnetconfig failed: %m");
736 return (-1);
737 }
738 while ((nconf = getnetconfig(nc)) != NULL) {
739
740 /*
741 * Skip things like tpi_raw, invisible...
742 */
743 if ((nconf->nc_flag & NC_VISIBLE) == 0)
744 continue;
745 if (nconf->nc_semantics != NC_TPI_CLTS &&
746 nconf->nc_semantics != NC_TPI_COTS &&
747 nconf->nc_semantics != NC_TPI_COTS_ORD)
748 continue;
749
750 sm_svc_tp_create(nconf);
751 }
752 (void) endnetconfig(nc);
753
754 /*
755 * Make sure /var/statmon and any alternate (-p) statmon
756 * directories exist and are owned by daemon. Then change our uid
757 * to daemon. The uid change is to prevent attacks against local
758 * daemons that trust any call from a local root process.
759 */
760
761 set_statmon_owner();
762
763 /*
764 *
765 * statd now runs as a daemon rather than root and can not
766 * dump core under / because of the permission. It is
767 * important that current working directory of statd be
768 * changed to writable directory /var/statmon so that it
769 * can dump the core upon the receipt of the signal.
770 * One still need to set allow_setid_core to non-zero in
771 * /etc/system to get the core dump.
772 *
|