Print this page
7577 mountd support to run on a fixed port
Portions contributed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
@@ -18,12 +18,13 @@
*
* CDDL HEADER END
*/
/*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
@@ -115,14 +116,16 @@
static void umount(struct svc_req *);
static void umountall(struct svc_req *);
static int newopts(char *);
static tsol_tpent_t *get_client_template(struct sockaddr *);
+static int debug;
static int verbose;
static int rejecting;
static int mount_vers_min = MOUNTVERS;
static int mount_vers_max = MOUNTVERS3;
+static int mountd_port = 0;
extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
thread_t nfsauth_thread;
thread_t cmd_thread;
@@ -360,10 +363,86 @@
*val = (int)lval;
return (0);
}
+/*
+ * This function is called for each configured network type to
+ * bind and register our RPC service programs.
+ *
+ * On TCP or UDP, we may want to bind MOUNTPROG on a specific port
+ * (when mountd_port is specified) in which case we'll use the
+ * variant of svc_tp_create() that lets us pass a bind address.
+ */
+static void
+md_svc_tp_create(struct netconfig *nconf)
+{
+ char port_str[8];
+ struct nd_hostserv hs;
+ struct nd_addrlist *al = NULL;
+ SVCXPRT *xprt = NULL;
+ rpcvers_t vers;
+
+ vers = mount_vers_max;
+
+ /*
+ * If mountd_port is set and this is an inet transport,
+ * bind this service on the specified port. The TLI way
+ * to create such a bind address is netdir_getbyname()
+ * with the special "host" HOST_SELF_BIND. This builds
+ * an all-zeros IP address with the specified port.
+ */
+ if (mountd_port != 0 &&
+ (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
+ strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
+ int err;
+
+ snprintf(port_str, sizeof (port_str), "%u",
+ (unsigned short)mountd_port);
+
+ hs.h_host = HOST_SELF_BIND;
+ hs.h_serv = port_str;
+ err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
+ if (err == 0 && al != NULL) {
+ xprt = svc_tp_create_addr(mnt, MOUNTPROG, vers,
+ nconf, al->n_addrs);
+ netdir_free(al, ND_ADDRLIST);
+ }
+ if (xprt == NULL) {
+ syslog(LOG_ERR, "mountd: unable to create "
+ "(MOUNTD,%d) on transport %s (port %d)",
+ vers, nconf->nc_netid, mountd_port);
+ }
+ /* fall-back to default bind */
+ }
+ if (xprt == NULL) {
+ /*
+ * Had mountd_port=0, or non-inet transport,
+ * or the bind to a specific port failed.
+ * Do a default bind.
+ */
+ xprt = svc_tp_create(mnt, MOUNTPROG, vers, nconf);
+ }
+ if (xprt == NULL) {
+ syslog(LOG_ERR, "mountd: unable to create "
+ "(MOUNTD,%d) on transport %s",
+ vers, nconf->nc_netid);
+ return;
+ }
+
+ /*
+ * Register additional versions on this transport.
+ */
+ while (--vers >= mount_vers_min) {
+ if (!svc_reg(xprt, MOUNTPROG, vers, mnt, nconf)) {
+ (void) syslog(LOG_ERR, "mountd: "
+ "failed to register vers %d on %s",
+ vers, nconf->nc_netid);
+ }
+ }
+}
+
int
main(int argc, char *argv[])
{
int pid;
int c;
@@ -377,10 +456,12 @@
int defvers, ret, bufsz;
struct rlimit rl;
int listen_backlog = 0;
int max_threads = 0;
int tmp;
+ struct netconfig *nconf;
+ NCONF_HANDLE *nc;
int pipe_fd = -1;
/*
* Mountd requires uid 0 for:
@@ -396,10 +477,11 @@
* MLP
*/
can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
+ PRIV_NET_PRIVADDR,
can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
(void) fprintf(stderr,
"%s: must be run with sufficient privileges\n",
argv[0]);
exit(1);
@@ -420,12 +502,22 @@
if (ret != SA_OK) {
syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
"failed, using default value");
}
- while ((c = getopt(argc, argv, "vrm:")) != EOF) {
+ ret = nfs_smf_get_iprop("mountd_port", &mountd_port,
+ DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
+ if (ret != SA_OK) {
+ syslog(LOG_ERR, "Reading of mountd_port from SMF "
+ "failed, using default value");
+ }
+
+ while ((c = getopt(argc, argv, "dvrm:p:")) != EOF) {
switch (c) {
+ case 'd':
+ debug++;
+ break;
case 'v':
verbose++;
break;
case 'r':
rejecting = 1;
@@ -437,10 +529,19 @@
argv[0]);
break;
}
max_threads = tmp;
break;
+ case 'p':
+ if (convert_int(&tmp, optarg) != 0 || tmp < 1 ||
+ tmp > UINT16_MAX) {
+ (void) fprintf(stderr, "%s: invalid port "
+ "number\n", argv[0]);
+ break;
+ }
+ mountd_port = tmp;
+ break;
default:
fprintf(stderr, "usage: mountd [-v] [-r]\n");
exit(1);
}
}
@@ -486,10 +587,12 @@
/*
* Sanity check versions,
* even though we may get versions > MOUNTVERS3, we still need
* to start nfsauth service, so continue on regardless of values.
*/
+ if (mount_vers_max > MOUNTVERS3)
+ mount_vers_max = MOUNTVERS3;
if (mount_vers_min > mount_vers_max) {
fprintf(stderr, "server_versmin > server_versmax\n");
mount_vers_max = mount_vers_min;
}
(void) setlocale(LC_ALL, "");
@@ -506,18 +609,20 @@
(void) textdomain(TEXT_DOMAIN);
/* Don't drop core if the NFS module isn't loaded. */
(void) signal(SIGSYS, SIG_IGN);
+ if (!debug)
pipe_fd = daemonize_init();
/*
* If we coredump it'll be in /core
*/
if (chdir("/") < 0)
fprintf(stderr, "chdir /: %s\n", strerror(errno));
+ if (!debug)
openlog("mountd", LOG_PID, LOG_DAEMON);
/*
* establish our lock on the lock file and write our pid to it.
* exit if some other process holds the lock, or if there's any
@@ -599,10 +704,15 @@
if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
fprintf(stderr, "unable to set max_threads\n");
exit(1);
}
+ if (mountd_port < 0 || mountd_port > UINT16_MAX) {
+ fprintf(stderr, "unable to use specified port\n");
+ exit(1);
+ }
+
/*
* Make sure to unregister any previous versions in case the
* user is reconfiguring the server in interesting ways.
*/
svc_unreg(MOUNTPROG, MOUNTVERS);
@@ -643,53 +753,32 @@
syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
exit(2);
}
/*
- * Create datagram and connection oriented services
+ * Enumerate network transports and create service listeners
+ * as appropriate for each.
*/
- if (mount_vers_max >= MOUNTVERS) {
- if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) {
- fprintf(stderr,
- "couldn't register datagram_v MOUNTVERS\n");
- exit(1);
+ if ((nc = setnetconfig()) == NULL) {
+ syslog(LOG_ERR, "setnetconfig failed: %m");
+ return (-1);
}
- if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) {
- fprintf(stderr,
- "couldn't register circuit_v MOUNTVERS\n");
- exit(1);
- }
- }
+ while ((nconf = getnetconfig(nc)) != NULL) {
+ /*
+ * Skip things like tpi_raw, invisible...
+ */
+ if ((nconf->nc_flag & NC_VISIBLE) == 0)
+ continue;
+ if (nconf->nc_semantics != NC_TPI_CLTS &&
+ nconf->nc_semantics != NC_TPI_COTS &&
+ nconf->nc_semantics != NC_TPI_COTS_ORD)
+ continue;
- if (mount_vers_max >= MOUNTVERS_POSIX) {
- if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
- "datagram_v") == 0) {
- fprintf(stderr,
- "couldn't register datagram_v MOUNTVERS_POSIX\n");
- exit(1);
+ md_svc_tp_create(nconf);
}
- if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
- "circuit_v") == 0) {
- fprintf(stderr,
- "couldn't register circuit_v MOUNTVERS_POSIX\n");
- exit(1);
- }
- }
+ (void) endnetconfig(nc);
- if (mount_vers_max >= MOUNTVERS3) {
- if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) {
- fprintf(stderr,
- "couldn't register datagram_v MOUNTVERS3\n");
- exit(1);
- }
- if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) {
- fprintf(stderr,
- "couldn't register circuit_v MOUNTVERS3\n");
- exit(1);
- }
- }
-
/*
* Start serving
*/
rmtab_load();