Print this page
8330 Add svc_tp_create_addr to libnsl
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>

*** 18,29 **** * * CDDL HEADER END */ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ --- 18,29 ---- * * CDDL HEADER END */ /* + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */
*** 85,94 **** --- 85,98 ---- extern mutex_t xprtlist_lock; static SVCXPRT * svc_tli_create_common(int, const struct netconfig *, const struct t_bind *, uint_t, uint_t, boolean_t); + static SVCXPRT *svc_tp_create_bind(void (*dispatch)(), + const rpcprog_t, const rpcvers_t, + const struct netconfig *, const struct t_bind *); + boolean_t is_multilevel(rpcprog_t prognum) { /* This is a list of identified multilevel service provider */ if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
*** 174,189 **** } /* * The high level interface to svc_tli_create(). * It tries to create a server for "nconf" and registers the service ! * with the rpcbind. It calls svc_tli_create(); */ SVCXPRT * svc_tp_create(void (*dispatch)(), const rpcprog_t prognum, const rpcvers_t versnum, const struct netconfig *nconf) { SVCXPRT *xprt; boolean_t anon_mlp = B_FALSE; if (nconf == NULL) { (void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig " --- 178,232 ---- } /* * The high level interface to svc_tli_create(). * It tries to create a server for "nconf" and registers the service ! * with the rpcbind. */ SVCXPRT * svc_tp_create(void (*dispatch)(), const rpcprog_t prognum, const rpcvers_t versnum, const struct netconfig *nconf) { + return (svc_tp_create_bind(dispatch, prognum, versnum, nconf, NULL)); + } + + /* + * svc_tp_create_addr() + * Variant of svc_tp_create() that allows specifying just the + * the binding address, for convenience. + */ + SVCXPRT * + svc_tp_create_addr(void (*dispatch)(), const rpcprog_t prognum, + const rpcvers_t versnum, const struct netconfig *nconf, + const struct netbuf *addr) + { + struct t_bind bind; + struct t_bind *bindp = NULL; + + if (addr != NULL) { + + bind.addr = *addr; + if (!rpc_control(__RPC_SVC_LSTNBKLOG_GET, &bind.qlen)) { + syslog(LOG_ERR, + "svc_tp_create: can't get listen backlog"); + return (NULL); + } + bindp = &bind; + } + + /* + * When bindp == NULL, this is the same as svc_tp_create(). + */ + return (svc_tp_create_bind(dispatch, prognum, versnum, + nconf, bindp)); + } + + static SVCXPRT * + svc_tp_create_bind(void (*dispatch)(), const rpcprog_t prognum, + const rpcvers_t versnum, const struct netconfig *nconf, + const struct t_bind *bindaddr) + { SVCXPRT *xprt; boolean_t anon_mlp = B_FALSE; if (nconf == NULL) { (void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig "
*** 192,202 **** } /* Some programs need to allocate MLP for multilevel services */ if (is_system_labeled() && is_multilevel(prognum)) anon_mlp = B_TRUE; ! xprt = svc_tli_create_common(RPC_ANYFD, nconf, NULL, 0, 0, anon_mlp); if (xprt == NULL) return (NULL); (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf); if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { --- 235,246 ---- } /* Some programs need to allocate MLP for multilevel services */ if (is_system_labeled() && is_multilevel(prognum)) anon_mlp = B_TRUE; ! xprt = svc_tli_create_common(RPC_ANYFD, nconf, bindaddr, 0, 0, ! anon_mlp); if (xprt == NULL) return (NULL); (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf); if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
*** 322,332 **** (void) syslog(LOG_ERR, "svc_tli_create: No memory!"); goto freedata; } switch (state) { - bool_t tcp, exclbind; case T_UNBND: /* If this is a labeled system, then ask for an MLP */ if (is_system_labeled() && (strcmp(nconf->nc_protofmly, NC_INET) == 0 || strcmp(nconf->nc_protofmly, NC_INET6) == 0)) { --- 366,375 ----
*** 335,370 **** if (mlp_flag) (void) __rpc_tli_set_options(fd, SOL_SOCKET, SO_ANON_MLP, 1); } /* ! * SO_EXCLBIND has the following properties ! * - an fd bound to port P via IPv4 will prevent an IPv6 ! * bind to port P (and vice versa) ! * - an fd bound to a wildcard IP address for port P will ! * prevent a more specific IP address bind to port P ! * (see {tcp,udp}.c for details) ! * ! * We use the latter property to prevent hijacking of RPC ! * services that reside at non-privileged ports. */ ! tcp = nconf ? (strcmp(nconf->nc_proto, NC_TCP) == 0) : 0; ! if (nconf && ! (tcp || (strcmp(nconf->nc_proto, NC_UDP) == 0)) && ! rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind)) { ! if (exclbind) { ! if (__rpc_tli_set_options(fd, SOL_SOCKET, ! SO_EXCLBIND, 1) < 0) { ! syslog(LOG_ERR, ! "svc_tli_create: can't set EXCLBIND [netid='%s']", ! nconf->nc_netid); ! goto freedata; ! } ! } ! } ! if (bindaddr) { if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) { char errorstr[100]; __tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno); --- 378,396 ---- if (mlp_flag) (void) __rpc_tli_set_options(fd, SOL_SOCKET, SO_ANON_MLP, 1); } + if (bindaddr) { /* ! * Services that specify a bind address typically ! * use a fixed service (IP port) so we need to set ! * SO_REUSEADDR to prevent bind errors on restart. */ ! if (bindaddr->addr.len != 0) ! (void) __rpc_tli_set_options(fd, SOL_SOCKET, ! SO_REUSEADDR, 1); if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) { char errorstr[100]; __tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno);
*** 401,410 **** --- 427,477 ---- (void) syslog(LOG_ERR, "svc_tli_create: could not bind: %s", errorstr); goto freedata; } + } + + /* + * If requested, set SO_EXCLBIND on each binding. + * + * SO_EXCLBIND has the following properties + * - an fd bound to port P via IPv4 will prevent an IPv6 + * bind to port P (and vice versa) + * - an fd bound to a wildcard IP address for port P will + * prevent a more specific IP address bind to port P + * (see {tcp,udp}.c for details) + * + * We use the latter property to prevent hijacking of RPC + * services that reside at non-privileged ports. + * + * When the bind address is not specified, each bind gets a + * new port number, and (for IP transports) we should set + * the exclusive flag after every IP bind. That's the + * strcmp nc_proto part of the expression below. + * + * When the bind address IS specified, we need to set the + * exclusive flag only after we've bound both IPv6+IPv4, + * or the IPv4 bind will fail. Setting the exclusive flag + * after the "tcp" or "udp" transport bind does that. + * That's the strcmp nc_netid part below. + */ + if (nconf != NULL && ((bindaddr == NULL && + (strcmp(nconf->nc_proto, NC_TCP) == 0 || + strcmp(nconf->nc_proto, NC_UDP) == 0)) || + (strcmp(nconf->nc_netid, "tcp") == 0 || + strcmp(nconf->nc_netid, "udp") == 0))) { + bool_t exclbind = FALSE; + (void) rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind); + if (exclbind && + __rpc_tli_set_options(fd, SOL_SOCKET, + SO_EXCLBIND, 1) < 0) { + syslog(LOG_ERR, + "svc_tli_create: can't set EXCLBIND [netid='%s']", + nconf->nc_netid); + goto freedata; + } } /* Enable options of returning the ip's for udp */ if (nconf) { int ret = 0;