/* * Remove the mapping between program, version and port. * Calls the pmap service remotely to do the un-mapping. */ bool_t pmap_unset(u_long program, u_long version) { struct netconfig *nconf; bool_t udp_rslt = FALSE; bool_t tcp_rslt = FALSE; nconf = __rpc_getconfip("udp"); if (nconf != NULL) { udp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version, nconf); freenetconfigent(nconf); } nconf = __rpc_getconfip("tcp"); if (nconf != NULL) { tcp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version, nconf); freenetconfigent(nconf); } /* * XXX: The call may still succeed even if only one of the * calls succeeded. This was the best that could be * done for backward compatibility. */ return (tcp_rslt || udp_rslt); }
bool_t pmap_set(u_long program, u_long version, int protocol, int port) { bool_t rslt; struct netbuf *na; struct netconfig *nconf; char buf[32]; if ((protocol != IPPROTO_UDP) && (protocol != IPPROTO_TCP)) { return (FALSE); } nconf = __rpc_getconfip(protocol == IPPROTO_UDP ? "udp" : "tcp"); if (nconf == NULL) { return (FALSE); } snprintf(buf, sizeof buf, "0.0.0.0.%d.%d", (((u_int32_t)port) >> 8) & 0xff, port & 0xff); na = uaddr2taddr(nconf, buf); if (na == NULL) { freenetconfigent(nconf); return (FALSE); } rslt = rpcb_set((rpcprog_t)program, (rpcvers_t)version, nconf, na); free(na); freenetconfigent(nconf); return (rslt); }
/* * A common server create routine */ static SVCXPRT * svc_com_create(int fd, u_int sendsize, u_int recvsize, const char *netid) { struct netconfig *nconf; SVCXPRT *svc; int madefd = FALSE; int port; struct sockaddr_in sccsin; _DIAGASSERT(netid != NULL); if ((nconf = __rpc_getconfip(netid)) == NULL) { (void) syslog(LOG_ERR, "Could not get %s transport", netid); return (NULL); } if (fd == RPC_ANYSOCK) { fd = __rpc_nconf2fd(nconf); if (fd == -1) { (void) freenetconfigent(nconf); (void) syslog(LOG_ERR, "svc%s_create: could not open connection", netid); return (NULL); } madefd = TRUE; } memset(&sccsin, 0, sizeof sccsin); sccsin.sin_family = AF_INET; (void)bindresvport(fd, &sccsin); switch (nconf->nc_semantics) { case NC_TPI_COTS: case NC_TPI_COTS_ORD: if (listen(fd, SOMAXCONN) == -1) { (void) syslog(LOG_ERR, "svc%s_create: listen(2) failed: %s", netid, strerror(errno)); (void) freenetconfigent(nconf); goto out; } break; default: break; } svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); (void) freenetconfigent(nconf); if (svc == NULL) goto out; port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); svc->xp_port = ntohs(port); return svc; out: if (madefd) (void) close(fd); return NULL; }
/* * Get the client's hostname from the transport handle * If the name is not available then return "(anon)". */ void getclientsnames(SVCXPRT *transp, struct netbuf **nbuf, struct nd_hostservlist **serv) { struct netconfig *nconf; char tmp[MAXIPADDRLEN]; char *host = NULL; nconf = getnetconfigent(transp->xp_netid); if (nconf == NULL) { syslog(LOG_ERR, "%s: getnetconfigent failed", transp->xp_netid); *serv = anon_client(host); return; } *nbuf = svc_getrpccaller(transp); if (*nbuf == NULL) { freenetconfigent(nconf); *serv = anon_client(host); return; } /* * Use the this API instead of the netdir_getbyaddr() * to avoid service lookup. */ if (__netdir_getbyaddr_nosrv(nconf, serv, *nbuf)) { host = &tmp[0]; if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { struct sockaddr_in *sa; /* LINTED pointer alignment */ sa = (struct sockaddr_in *)((*nbuf)->buf); (void) inet_ntoa_r(sa->sin_addr, tmp); *serv = anon_client(host); freenetconfigent(nconf); return; } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { struct sockaddr_in6 *sa; /* LINTED pointer alignment */ sa = (struct sockaddr_in6 *)((*nbuf)->buf); (void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr, tmp, INET6_ADDRSTRLEN); *serv = anon_client(host); freenetconfigent(nconf); return; } freenetconfigent(nconf); *serv = anon_client(host); return; } freenetconfigent(nconf); }
/* Unregister all the registrations done by register_rpc_service */ void unregister_rpc_service(const char *fmri, const rpc_info_t *rpc) { int ver; struct netconfig *nconf; debug_msg("Entering unregister_rpc_service, instance: %s", fmri); if ((nconf = getnetconfigent(rpc->netid)) == NULL) { /* * Don't output an error message if getnetconfigent() fails for * a v6 netid when an IPv6 interface isn't configured. */ if (!(is_v6_netid(rpc->netid) && !can_use_af(AF_INET6))) { error_msg(gettext( "Failed to lookup netid '%s' for instance %s: %s"), rpc->netid, fmri, nc_sperror()); } return; } for (ver = rpc->lowver; ver <= rpc->highver; ver++) (void) rpcb_unset(rpc->prognum, ver, nconf); freenetconfigent(nconf); }
int add_bndlist(struct netconfig *nconf, struct netbuf *baddr) { struct fdlist *fdl; struct netconfig *newnconf; newnconf = getnetconfigent(nconf->nc_netid); if (newnconf == NULL) return (-1); fdl = (struct fdlist *)malloc((u_int)sizeof (struct fdlist)); if (fdl == NULL) { freenetconfigent(newnconf); syslog(LOG_ERR, "no memory!"); return (-1); } fdl->nconf = newnconf; fdl->next = NULL; if (fdhead == NULL) { fdhead = fdl; fdtail = fdl; } else { fdtail->next = fdl; fdtail = fdl; } /* XXX no bound checking for now */ fdl->check_binding = FALSE; return 0; }
struct servent * getservbyport_r(int port, const char *proto, struct servent *result, char *buffer, int buflen) { struct netconfig *nconf; struct nss_netdirbyaddr_in nssin; union nss_netdirbyaddr_out nssout; int neterr; if ((nconf = __rpc_getconfip("udp")) == NULL && (nconf = __rpc_getconfip("tcp")) == NULL) { return ((struct servent *)NULL); } nssin.op_t = NSS_SERV; nssin.arg.nss.serv.port = port; nssin.arg.nss.serv.proto = proto; nssin.arg.nss.serv.buf = buffer; nssin.arg.nss.serv.buflen = buflen; nssout.nss.serv = result; /* * We pass in nconf and let the implementation of this long-named func * decide whether to use the switch based on nc_nlookups. */ neterr = _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); (void) freenetconfigent(nconf); if (neterr != ND_OK) { return ((struct servent *)NULL); } return (nssout.nss.serv); }
/* * Create the client des authentication object. Obsoleted by * authdes_seccreate(). */ AUTH * authdes_create(char *servername, uint_t window, struct sockaddr_in *syncaddr, des_block *ckey) { char *hostname = NULL; if (syncaddr) { /* * Change addr to hostname, because that is the way * new interface takes it. */ struct netconfig *nconf; struct netbuf nb_syncaddr; struct nd_hostservlist *hlist; AUTH *nauth; int fd; struct t_info tinfo; if ((nconf = __rpc_getconfip("udp")) == NULL && (nconf = __rpc_getconfip("tcp")) == NULL) goto fallback; /* Transform sockaddr_in to netbuf */ if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) == -1) { (void) freenetconfigent(nconf); goto fallback; } (void) t_close(fd); nb_syncaddr.maxlen = nb_syncaddr.len = __rpc_get_a_size(tinfo.addr); nb_syncaddr.buf = (char *)syncaddr; if (netdir_getbyaddr(nconf, &hlist, &nb_syncaddr)) { (void) freenetconfigent(nconf); goto fallback; } if (hlist && hlist->h_cnt > 0 && hlist->h_hostservs) hostname = hlist->h_hostservs->h_host; nauth = authdes_seccreate(servername, window, hostname, ckey); (void) netdir_free((char *)hlist, ND_HOSTSERVLIST); (void) freenetconfigent(nconf); return (nauth); } fallback: return (authdes_seccreate(servername, window, hostname, ckey)); }
/* * Registers with rpcbind the program number with all versions, from low to * high, with the netid, all specified in 'rpc'. If registration fails, * returns -1, else 0. */ int register_rpc_service(const char *fmri, const rpc_info_t *rpc) { struct netconfig *nconf; int ver; debug_msg("Entering register_rpc_service: instance: %s", fmri); if ((nconf = getnetconfigent(rpc->netid)) == NULL) { /* * Check whether getnetconfigent() failed as a result of * having no IPv6 interfaces configured for a v6 netid, or * as a result of a 'real' error, and output an appropriate * message with an appropriate severity. */ if (is_v6_netid(rpc->netid) && !can_use_af(AF_INET6)) { warn_msg(gettext( "Couldn't register netid %s for RPC instance %s " "because no IPv6 interfaces are plumbed"), rpc->netid, fmri); } else { error_msg(gettext( "Failed to lookup netid '%s' for instance %s: %s"), rpc->netid, fmri, nc_sperror()); } return (-1); } for (ver = rpc->lowver; ver <= rpc->highver; ver++) { if (!rpcb_set(rpc->prognum, ver, nconf, &(rpc->netbuf))) { error_msg(gettext("Failed to register version %d " "of RPC service instance %s, netid %s"), ver, fmri, rpc->netid); for (ver--; ver >= rpc->lowver; ver--) (void) rpcb_unset(rpc->prognum, ver, nconf); freenetconfigent(nconf); return (-1); } } freenetconfigent(nconf); return (0); }
/* * A common server create routine */ static SVCXPRT * svc_com_create(int fd, uint_t sendsize, uint_t recvsize, char *netid) { struct netconfig *nconf; SVCXPRT *svc; int madefd = FALSE; int port; int res; if ((nconf = __rpc_getconfip(netid)) == NULL) { (void) syslog(LOG_ERR, "Could not get %s transport", netid); return (NULL); } if (fd == RPC_ANYSOCK) { fd = t_open(nconf->nc_device, O_RDWR, NULL); if (fd == -1) { char errorstr[100]; __tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno); (void) syslog(LOG_ERR, "svc%s_create: could not open connection : %s", netid, errorstr); (void) freenetconfigent(nconf); return (NULL); } madefd = TRUE; } res = __rpc_bindresvport(fd, NULL, &port, 8); svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); (void) freenetconfigent(nconf); if (svc == NULL) { if (madefd) (void) t_close(fd); return (NULL); } if (res == -1) /* LINTED pointer cast */ port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); svc->xp_port = ntohs(port); return (svc); }
/* * Find netconfig info for TCP/UDP device, and fill in the knetconfig * structure. If in_ncp is not NULL, use that instead of defaulting * to a TCP/UDP service. If in_ncp is NULL, then use the service type * specified in nc_protoname (which may be either "tcp" or "udp"). If * nc_protoname is NULL, default to UDP. */ int get_knetconfig(struct knetconfig **kncpp, struct netconfig *in_ncp, char *nc_protoname) { struct netconfig *ncp = NULL; struct stat statbuf; if (in_ncp) ncp = in_ncp; else { if (nc_protoname) ncp = getnetconfigent(nc_protoname); else ncp = getnetconfigent(NC_UDP); } if (!ncp) return -2; *kncpp = (struct knetconfig *) xzalloc(sizeof(struct knetconfig)); if (*kncpp == (struct knetconfig *) NULL) { if (!in_ncp) freenetconfigent(ncp); return -3; } (*kncpp)->knc_semantics = ncp->nc_semantics; (*kncpp)->knc_protofmly = strdup(ncp->nc_protofmly); (*kncpp)->knc_proto = strdup(ncp->nc_proto); if (stat(ncp->nc_device, &statbuf) < 0) { plog(XLOG_ERROR, "could not stat() %s: %m", ncp->nc_device); XFREE(*kncpp); *kncpp = NULL; if (!in_ncp) freenetconfigent(ncp); return -3; /* amd will end (free not needed) */ } (*kncpp)->knc_rdev = (dev_t) statbuf.st_rdev; if (!in_ncp) { /* free only if argument not passed */ freenetconfigent(ncp); ncp = NULL; } return 0; }
/* * A common server create routine */ static SVCXPRT * svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid) { struct netconfig *nconf; SVCXPRT *svc; int madefd = FALSE; int port; struct sockaddr_in sin; if ((nconf = __rpc_getconfip(netid)) == NULL) { (void) syslog(LOG_ERR, "Could not get %s transport", netid); return (NULL); } if (fd == RPC_ANYSOCK) { fd = __rpc_nconf2fd(nconf); if (fd == -1) { (void) freenetconfigent(nconf); (void) syslog(LOG_ERR, "svc%s_create: could not open connection", netid); return (NULL); } madefd = TRUE; } memset(&sin, 0, sizeof sin); sin.sin_family = AF_INET; bindresvport(fd, &sin); _listen(fd, SOMAXCONN); svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); (void) freenetconfigent(nconf); if (svc == NULL) { if (madefd) (void)_close(fd); return (NULL); } port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); svc->xp_port = ntohs(port); return (svc); }
static PyObject * portmap_unset(PyObject *self, PyObject *args) { unsigned long program, version; struct netconfig *nconf; if (!PyArg_ParseTuple(args, "kk:unset", &program, &version)) return NULL; pmap_unset(program, version); nconf = getnetconfigent("udp6"); if (nconf != NULL) { rpcb_unset((rpcprog_t)program, (rpcvers_t)version, nconf); freenetconfigent(nconf); } nconf = getnetconfigent("tcp6"); if (nconf != NULL) { rpcb_unset((rpcprog_t)program, (rpcvers_t)version, nconf); freenetconfigent(nconf); } Py_INCREF(Py_None); return Py_None; }
static int tryconf(struct conf *cfg, int t, int reregister) { struct addrinfo hints; int ecode; memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = cfg_family[t]; hints.ai_socktype = cfg_socktype[t]; hints.ai_protocol = cfg_protocol[t]; ecode = getaddrinfo(NULL, "nfs", &hints, &cfg->ai); if (ecode != 0) { logit(LOG_ERR, "getaddrinfo %s: %s", cfg_netconf[t], gai_strerror(ecode)); return -1; } cfg->nc = getnetconfigent(cfg_netconf[t]); if (cfg->nc == NULL) { logit(LOG_ERR, "getnetconfigent %s failed: %s", cfg_netconf[t], strerror(errno)); goto out; } cfg->nb.buf = cfg->ai->ai_addr; cfg->nb.len = cfg->nb.maxlen = cfg->ai->ai_addrlen; if (reregister) if (!rpcb_set(RPCPROG_NFS, 2, cfg->nc, &cfg->nb)) { logit(LOG_ERR, "rpcb_set %s failed", cfg_netconf[t]); goto out1; } return 0; out1: freenetconfigent(cfg->nc); cfg->nc = NULL; out: freeaddrinfo(cfg->ai); cfg->ai = NULL; return -1; }
/* * If 'proto' is a valid netid, and no memory allocations fail, returns a * pointer to an allocated and initialized rpc_info_t, else NULL. */ static rpc_info_t * create_rpc_info(const char *proto, int pnum, int low_ver, int high_ver) { struct netconfig *nconf; rpc_info_t *ret; if ((ret = calloc(1, sizeof (rpc_info_t))) == NULL) return (NULL); ret->netbuf.maxlen = sizeof (struct sockaddr_storage); if ((ret->netbuf.buf = malloc(ret->netbuf.maxlen)) == NULL) { free(ret); return (NULL); } ret->prognum = pnum; ret->lowver = low_ver; ret->highver = high_ver; if ((ret->netid = strdup(proto)) == NULL) { destroy_rpc_info(ret); return (NULL); } /* * Determine whether this is a loopback transport. If getnetconfigent() * fails, we check to see whether it was the result of a v6 proto * being specified and no IPv6 interface was configured on the system; * if this holds, we know it must not be a loopback transport, else * getnetconfigent() must be miss-behaving, so return an error. */ if ((nconf = getnetconfigent(proto)) != NULL) { if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) ret->is_loopback = B_TRUE; freenetconfigent(nconf); } else if (!v6_proto(proto)) { destroy_rpc_info(ret); return (NULL); } return (ret); }
/* netconfig(3) fallback approach */ static char * __so_socket_path_netconfig(int domain, int type, int protocol) { int semantics1 = 0, semantics2 = 0; const char *proto = NULL; const char *family = NULL; struct netconfig *nc; char *result = NULL; if (__so_map_socket_to_netconfig(domain, type, protocol, &semantics1, &semantics2, &family, &proto) == -1) return (NULL); if ((nc = getnetconfigent(proto)) != NULL) { if ((result = strdup(nc->nc_device)) == NULL) nc_error = NC_NOMEM; freenetconfigent(nc); } if (!result) { nc_perror("socklib"); } return (result); }
/* * A common clnt create routine */ static CLIENT * clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers, int *sockp, uint_t sendsz, uint_t recvsz, char *tp) { CLIENT *cl; int madefd = FALSE; int fd = *sockp; struct t_info tinfo; struct netconfig *nconf; int port; struct netbuf bindaddr; bool_t locked = TRUE; (void) mutex_lock(&rpcsoc_lock); if ((nconf = __rpc_getconfip(tp)) == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; (void) mutex_unlock(&rpcsoc_lock); return (NULL); } if (fd == RPC_ANYSOCK) { fd = t_open(nconf->nc_device, O_RDWR, &tinfo); if (fd == -1) goto syserror; RPC_RAISEFD(fd); madefd = TRUE; } else { if (t_getinfo(fd, &tinfo) == -1) goto syserror; } if (raddr->sin_port == 0) { uint_t proto; ushort_t sport; /* pmap_getport is recursive */ (void) mutex_unlock(&rpcsoc_lock); proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; sport = pmap_getport(raddr, prog, vers, proto); if (sport == 0) { locked = FALSE; goto err; } raddr->sin_port = htons(sport); /* pmap_getport is recursive */ (void) mutex_lock(&rpcsoc_lock); } /* Transform sockaddr_in to netbuf */ bindaddr.maxlen = bindaddr.len = __rpc_get_a_size(tinfo.addr); bindaddr.buf = (char *)raddr; (void) __rpc_bindresvport(fd, NULL, &port, 0); cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, sendsz, recvsz); if (cl) { if (madefd == TRUE) { /* * The fd should be closed while destroying the handle. */ (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); *sockp = fd; } (void) freenetconfigent(nconf); (void) mutex_unlock(&rpcsoc_lock); return (cl); } goto err; syserror: rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; rpc_createerr.cf_error.re_terrno = t_errno; err: if (madefd == TRUE) (void) t_close(fd); (void) freenetconfigent(nconf); if (locked == TRUE) (void) mutex_unlock(&rpcsoc_lock); return (NULL); }
/* * This is the IPv6 interface for "gethostbyaddr". */ struct hostent * getipnodebyaddr(const void *src, size_t len, int type, int *error_num) { struct in6_addr *addr6 = 0; struct in_addr *addr4 = 0; nss_XbyY_buf_t *buf = 0; nss_XbyY_buf_t *res = 0; struct netconfig *nconf; struct hostent *hp = 0; struct nss_netdirbyaddr_in nssin; union nss_netdirbyaddr_out nssout; int neterr; char tmpbuf[64]; if (type == AF_INET6) { if ((addr6 = (struct in6_addr *)src) == NULL) { *error_num = HOST_NOT_FOUND; return (NULL); } } else if (type == AF_INET) { if ((addr4 = (struct in_addr *)src) == NULL) { *error_num = HOST_NOT_FOUND; return (NULL); } } else { *error_num = HOST_NOT_FOUND; return (NULL); } /* * Specific case: query for "::" */ if (type == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(addr6)) { *error_num = HOST_NOT_FOUND; return (NULL); } /* * Step 1: IPv4-mapped address or IPv4 Compat */ if ((type == AF_INET6 && len == 16) && ((IN6_IS_ADDR_V4MAPPED(addr6)) || (IN6_IS_ADDR_V4COMPAT(addr6)))) { if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { *error_num = NO_RECOVERY; return (NULL); } if ((nconf = __rpc_getconfip("udp")) == NULL && (nconf = __rpc_getconfip("tcp")) == NULL) { *error_num = NO_RECOVERY; __IPv6_cleanup(buf); return (NULL); } nssin.op_t = NSS_HOST6; if (IN6_IS_ADDR_V4COMPAT(addr6)) { (void) memcpy(tmpbuf, addr6, sizeof (*addr6)); tmpbuf[10] = 0xffU; tmpbuf[11] = 0xffU; nssin.arg.nss.host.addr = (const char *)tmpbuf; } else { nssin.arg.nss.host.addr = (const char *)addr6; } nssin.arg.nss.host.len = sizeof (struct in6_addr); nssin.arg.nss.host.type = AF_INET6; nssin.arg.nss.host.buf = buf->buffer; nssin.arg.nss.host.buflen = buf->buflen; nssout.nss.host.hent = buf->result; nssout.nss.host.herrno_p = error_num; /* * We pass in nconf and let the implementation of the * long-named func decide whether to use the switch based on * nc_nlookups. */ neterr = _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); (void) freenetconfigent(nconf); if (neterr != ND_OK) { /* Failover case, try hosts db for v4 address */ if (!gethostbyaddr_r(((char *)addr6) + 12, sizeof (in_addr_t), AF_INET, buf->result, buf->buffer, buf->buflen, error_num)) { __IPv6_cleanup(buf); return (NULL); } /* Found one, now format it into mapped/compat addr */ if ((res = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { __IPv6_cleanup(buf); *error_num = NO_RECOVERY; return (NULL); } /* Convert IPv4 to mapped/compat address w/name */ hp = res->result; (void) __mapv4tov6(buf->result, 0, res, IN6_IS_ADDR_V4MAPPED(addr6)); __IPv6_cleanup(buf); free(res); return (hp); } /* * At this point, we'll have a v4mapped hostent. If that's * what was passed in, just return. If the request was a compat, * twiggle the two bytes to make the mapped address a compat. */ hp = buf->result; if (IN6_IS_ADDR_V4COMPAT(addr6)) { /* LINTED pointer cast */ addr6 = (struct in6_addr *)hp->h_addr_list[0]; addr6->s6_addr[10] = 0; addr6->s6_addr[11] = 0; } free(buf); return (hp); } /* * Step 2: AF_INET, v4 lookup. Since we're going to search the * ipnodes (v6) path first, we need to treat this as a v4mapped * address. nscd(1m) caches v4 from ipnodes as mapped v6's. The * switch backend knows to lookup v4's (not v4mapped) from the * name services. */ if (type == AF_INET) { struct in6_addr v4mapbuf; addr6 = &v4mapbuf; IN6_INADDR_TO_V4MAPPED(addr4, addr6); if ((nconf = __rpc_getconfip("udp")) == NULL && (nconf = __rpc_getconfip("tcp")) == NULL) { *error_num = NO_RECOVERY; return (NULL); } if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { *error_num = NO_RECOVERY; freenetconfigent(nconf); return (NULL); } nssin.op_t = NSS_HOST6; nssin.arg.nss.host.addr = (const char *)addr6; nssin.arg.nss.host.len = sizeof (struct in6_addr); nssin.arg.nss.host.type = AF_INET6; nssin.arg.nss.host.buf = buf->buffer; nssin.arg.nss.host.buflen = buf->buflen; nssout.nss.host.hent = buf->result; nssout.nss.host.herrno_p = error_num; /* * We pass in nconf and let the implementation of the * long-named func decide whether to use the switch based on * nc_nlookups. */ neterr = _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); (void) freenetconfigent(nconf); if (neterr != ND_OK) { /* Failover case, try hosts db for v4 address */ hp = buf->result; if (!gethostbyaddr_r(src, len, type, buf->result, buf->buffer, buf->buflen, error_num)) { __IPv6_cleanup(buf); return (NULL); } free(buf); return (hp); } if ((hp = __mappedtov4(buf->result, error_num)) == NULL) { __IPv6_cleanup(buf); return (NULL); } __IPv6_cleanup(buf); return (hp); } /* * Step 3: AF_INET6, plain vanilla v6 getipnodebyaddr() call. */ if (type == AF_INET6) { if ((nconf = __rpc_getconfip("udp")) == NULL && (nconf = __rpc_getconfip("tcp")) == NULL) { *error_num = NO_RECOVERY; return (NULL); } if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) { *error_num = NO_RECOVERY; freenetconfigent(nconf); return (NULL); } nssin.op_t = NSS_HOST6; nssin.arg.nss.host.addr = (const char *)addr6; nssin.arg.nss.host.len = len; nssin.arg.nss.host.type = type; nssin.arg.nss.host.buf = buf->buffer; nssin.arg.nss.host.buflen = buf->buflen; nssout.nss.host.hent = buf->result; nssout.nss.host.herrno_p = error_num; /* * We pass in nconf and let the implementation of the * long-named func decide whether to use the switch based on * nc_nlookups. */ neterr = _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout); (void) freenetconfigent(nconf); if (neterr != ND_OK) { __IPv6_cleanup(buf); return (NULL); } free(buf); return (nssout.nss.host.hent); } /* * If we got here, unknown type. */ *error_num = HOST_NOT_FOUND; return (NULL); }
struct hostent * getipnodebyname(const char *name, int af, int flags, int *error_num) { struct hostent *hp = NULL; nss_XbyY_buf_t *buf4 = NULL; nss_XbyY_buf_t *buf6 = NULL; struct netconfig *nconf; struct nss_netdirbyname_in nssin; union nss_netdirbyname_out nssout; int ret; uint_t ipnode_bits; if ((nconf = __rpc_getconfip("udp")) == NULL && (nconf = __rpc_getconfip("tcp")) == NULL) { *error_num = NO_RECOVERY; return (NULL); } ipnode_bits = getipnodebyname_processflags(name, af, flags); /* Make sure we have something to look up. */ if (!(ipnode_bits & (IPNODE_WANTIPV6 | IPNODE_WANTIPV4))) { *error_num = HOST_NOT_FOUND; goto cleanup; } /* * Perform the requested lookups. We always look through * ipnodes first for both IPv4 and IPv6 addresses. Depending * on what was returned and what was needed, we either filter * out the garbage, or ask for more using hosts. */ if (ipnode_bits & IPNODE_LOOKUPIPNODES) { if ((buf6 = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == NULL) { *error_num = NO_RECOVERY; goto cleanup; } nssin.op_t = NSS_HOST6; nssin.arg.nss.host6.name = name; nssin.arg.nss.host6.buf = buf6->buffer; nssin.arg.nss.host6.buflen = buf6->buflen; nssin.arg.nss.host6.af_family = af; nssin.arg.nss.host6.flags = flags; nssout.nss.host.hent = buf6->result; nssout.nss.host.herrno_p = error_num; ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout); if (ret != ND_OK) { __IPv6_cleanup(buf6); buf6 = NULL; } else if (ipnode_bits & IPNODE_WANTIPV4) { /* * buf6 may have all that we need if we either * only wanted IPv4 addresses if there were no * IPv6 addresses returned, or if there are * IPv4-mapped addresses in buf6. If either * of these are true, then there's no need to * look in hosts. */ if (ipnode_bits & IPNODE_IPV4IFNOIPV6 || __find_mapped(buf6->result, 0) != 0) { ipnode_bits &= ~IPNODE_LOOKUPHOSTS; } else if (!(ipnode_bits & IPNODE_WANTIPV6)) { /* * If all we're looking for are IPv4 * addresses and there are none in * buf6 then buf6 is now useless. */ __IPv6_cleanup(buf6); buf6 = NULL; } } } if (ipnode_bits & IPNODE_LOOKUPHOSTS) { if ((buf4 = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == NULL) { *error_num = NO_RECOVERY; goto cleanup; } nssin.op_t = NSS_HOST; nssin.arg.nss.host.name = name; nssin.arg.nss.host.buf = buf4->buffer; nssin.arg.nss.host.buflen = buf4->buflen; nssout.nss.host.hent = buf4->result; nssout.nss.host.herrno_p = error_num; ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout); if (ret != ND_OK) { __IPv6_cleanup(buf4); buf4 = NULL; } } if (buf6 == NULL && buf4 == NULL) { *error_num = HOST_NOT_FOUND; goto cleanup; } /* Extract the appropriate addresses from the returned buffer(s). */ switch (af) { case AF_INET6: { if (buf4 != NULL) { nss_XbyY_buf_t *mergebuf; /* * The IPv4 results we have need to be * converted to IPv4-mapped addresses, * conditionally merged with the IPv6 * results, and the end result needs to be * re-ordered. */ mergebuf = __IPv6_alloc(NSS_BUFLEN_IPNODES); if (mergebuf == NULL) { *error_num = NO_RECOVERY; goto cleanup; } hp = __mapv4tov6(buf4->result, ((buf6 != NULL) ? buf6->result : NULL), mergebuf, 1); if (hp != NULL) order_haddrlist_af(AF_INET6, hp->h_addr_list); else *error_num = NO_RECOVERY; free(mergebuf); } if (buf4 == NULL && buf6 != NULL) { hp = buf6->result; /* * We have what we need in buf6, but we may need * to filter out some addresses depending on what * is being asked for. */ if (!(ipnode_bits & IPNODE_WANTIPV4)) hp = __filter_addresses(AF_INET, buf6->result); else if (!(ipnode_bits & IPNODE_WANTIPV6)) hp = __filter_addresses(AF_INET6, buf6->result); /* * We've been asked to unmap v4 addresses. This * situation implies IPNODE_WANTIPV4 and * !IPNODE_WANTIPV6. */ if (hp != NULL && (ipnode_bits & IPNODE_UNMAP)) { /* * Just set hp to a new value, cleanup: will * free the old one */ hp = __mappedtov4(hp, error_num); } else if (hp == NULL) *error_num = NO_ADDRESS; } break; } case AF_INET: /* We could have results in buf6 or buf4, not both */ if (buf6 != NULL) { /* * Extract the IPv4-mapped addresses from buf6 * into hp. */ hp = __mappedtov4(buf6->result, error_num); } else { /* We have what we need in buf4. */ hp = buf4->result; if (ipnode_bits & IPNODE_LITERAL) { /* * There is a special case here for literal * IPv4 address strings. The hosts * front-end sets h_aliases to a one * element array containing a single NULL * pointer (in ndaddr2hent()), while * getipnodebyname() requires h_aliases to * be a NULL pointer itself. We're not * going to change the front-end since it * needs to remain backward compatible for * gethostbyname() and friends. Just set * h_aliases to NULL here instead. */ hp->h_aliases = NULL; } } break; default: break; } cleanup: /* * Free the memory we allocated, but make sure we don't free * the memory we're returning to the caller. */ if (buf6 != NULL) { if (buf6->result == hp) buf6->result = NULL; __IPv6_cleanup(buf6); } if (buf4 != NULL) { if (buf4->result == hp) buf4->result = NULL; __IPv6_cleanup(buf4); } (void) freenetconfigent(nconf); return (hp); }
/* * A common clnt create routine */ static CLIENT * clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers, int *sockp, u_int sendsz, u_int recvsz, const char *tp) { CLIENT *cl; int madefd = FALSE; int fd; struct netconfig *nconf; struct netbuf bindaddr; _DIAGASSERT(raddr != NULL); _DIAGASSERT(sockp != NULL); _DIAGASSERT(tp != NULL); fd = *sockp; mutex_lock(&rpcsoc_lock); if ((nconf = __rpc_getconfip(tp)) == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; mutex_unlock(&rpcsoc_lock); return (NULL); } if (fd == RPC_ANYSOCK) { fd = __rpc_nconf2fd(nconf); if (fd == -1) goto syserror; madefd = TRUE; } if (raddr->sin_port == 0) { u_int proto; u_short sport; mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */ proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; sport = pmap_getport(raddr, (u_long)prog, (u_long)vers, proto); if (sport == 0) { goto err; } raddr->sin_port = htons(sport); mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */ } /* Transform sockaddr_in to netbuf */ bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in); bindaddr.buf = raddr; (void)bindresvport(fd, NULL); cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, sendsz, recvsz); if (cl) { if (madefd == TRUE) { /* * The fd should be closed while destroying the handle. */ (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); *sockp = fd; } (void) freenetconfigent(nconf); mutex_unlock(&rpcsoc_lock); return (cl); } goto err; syserror: rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; err: if (madefd == TRUE) (void) close(fd); (void) freenetconfigent(nconf); mutex_unlock(&rpcsoc_lock); return (NULL); }
int main(int argc, char *argv[]) { pid_t pid; int i; int connmaxrec = RPC_MAXDATASIZE; /* * Set non-blocking mode and maximum record size for * connection oriented RPC transports. */ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { msgout("unable to set maximum RPC record size"); } /* * If stdin looks like a TLI endpoint, we assume * that we were started by a port monitor. If * t_getstate fails with TBADF, this is not a * TLI endpoint. */ if (t_getstate(0) != -1 || t_errno != TBADF) { char *netid; struct netconfig *nconf = NULL; SVCXPRT *transp; int pmclose; extern char *getenv(); _rpcpmstart = 1; openlog("rusers", LOG_PID, LOG_DAEMON); if ((netid = getenv("NLSPROVIDER")) == NULL) { #ifdef DEBUG msgout("cannot get transport name"); #endif } else if ((nconf = getnetconfigent(netid)) == NULL) { #ifdef DEBUG msgout("cannot get transport info"); #endif } if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { msgout("cannot create server handle"); exit(1); } if (nconf) freenetconfigent(nconf); if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_3, rusers_service, 0)) { msgout("unable to register (RUSERSPROG, RUSERSVERS_3)."); exit(1); } if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_IDLE, rusers_service, 0)) { msgout("unable to register (RUSERSPROG, RUSERSVERS_IDLE)."); exit(1); } (void) signal(SIGALRM, closedown); (void) alarm(_RPCSVC_CLOSEDOWN); svc_run(); msgout("svc_run returned"); exit(1); /* NOTREACHED */ } #ifndef RPC_SVC_FG pid = fork(); if (pid < 0) { perror("rpc.rusersd: cannot fork"); exit(1); } if (pid) exit(0); for (i = 0; i < 20; i++) (void) close(i); setsid(); openlog("rusers", LOG_PID, LOG_DAEMON); #endif if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_3, "netpath")) { msgout("unable to create (RUSERSPROG, RUSERSVERS_3) for netpath"); exit(1); } if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_IDLE, "netpath")) { msgout( "unable to create (RUSERSPROG, RUSERSVERS_IDLE) for netpath"); exit(1); } svc_run(); msgout("svc_run returned"); return (1); }
/* * Create the autofs service for amd */ int create_autofs_service(void) { struct t_bind *tbp = 0; int fd = -1, err = 1; /* assume failed */ plog(XLOG_INFO, "creating autofs service listener"); autofs_ncp = getnetconfigent(autofs_conftype); if (autofs_ncp == NULL) { plog(XLOG_ERROR, "create_autofs_service: cannot getnetconfigent for %s", autofs_conftype); goto out; } fd = t_open(autofs_ncp->nc_device, O_RDWR, NULL); if (fd < 0) { plog(XLOG_ERROR, "create_autofs_service: t_open failed (%s)", t_errlist[t_errno]); goto out; } tbp = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR); if (!tbp) { plog(XLOG_ERROR, "create_autofs_service: t_alloca failed"); goto out; } if (get_autofs_address(autofs_ncp, tbp) != 0) { plog(XLOG_ERROR, "create_autofs_service: get_autofs_address failed"); goto out; } autofs_xprt = svc_tli_create(fd, autofs_ncp, tbp, 0, 0); if (autofs_xprt == NULL) { plog(XLOG_ERROR, "cannot create autofs tli service for amd"); goto out; } rpcb_unset(AUTOFS_PROG, AUTOFS_VERS, autofs_ncp); if (svc_reg(autofs_xprt, AUTOFS_PROG, AUTOFS_VERS, autofs_program_1, autofs_ncp) == FALSE) { plog(XLOG_ERROR, "could not register amd AUTOFS service"); goto out; } err = 0; goto really_out; out: if (autofs_ncp) freenetconfigent(autofs_ncp); if (autofs_xprt) SVC_DESTROY(autofs_xprt); else { if (fd > 0) t_close(fd); } really_out: if (tbp) t_free((char *) tbp, T_BIND); dlog("create_autofs_service: returning %d\n", err); return err; }
/* * Create an rpc client attached to the mount daemon. */ CLIENT * get_mount_client(char *host, struct sockaddr_in *unused_sin, struct timeval *tv, int *sock, u_long mnt_version) { CLIENT *client; struct netbuf nb; struct netconfig *nc = NULL; struct sockaddr_in sin; nb.maxlen = sizeof(sin); nb.buf = (char *) &sin; /* * First try a TCP handler */ /* * Find mountd address on TCP */ if ((nc = getnetconfigent(NC_TCP)) == NULL) { plog(XLOG_ERROR, "getnetconfig for tcp failed: %s", nc_sperror()); goto tryudp; } if (!rpcb_getaddr(MOUNTPROG, mnt_version, nc, &nb, host)) { /* * don't print error messages here, since mountd might legitimately * serve udp only */ goto tryudp; } /* * Create privileged TCP socket */ *sock = t_open(nc->nc_device, O_RDWR, 0); if (*sock < 0) { plog(XLOG_ERROR, "t_open %s: %m", nc->nc_device); goto tryudp; } if (bind_resv_port(*sock, (u_short *) 0) < 0) plog(XLOG_ERROR, "couldn't bind mountd socket to privileged port"); if ((client = clnt_vc_create(*sock, &nb, MOUNTPROG, mnt_version, 0, 0)) == (CLIENT *) NULL) { plog(XLOG_ERROR, "clnt_vc_create failed"); t_close(*sock); goto tryudp; } /* tcp succeeded */ dlog("get_mount_client: using tcp, port %d", sin.sin_port); if (nc) freenetconfigent(nc); return client; tryudp: /* first free possibly previously allocated netconfig entry */ if (nc) freenetconfigent(nc); /* * TCP failed so try UDP */ /* * Find mountd address on UDP */ if ((nc = getnetconfigent(NC_UDP)) == NULL) { plog(XLOG_ERROR, "getnetconfig for udp failed: %s", nc_sperror()); goto badout; } if (!rpcb_getaddr(MOUNTPROG, mnt_version, nc, &nb, host)) { plog(XLOG_ERROR, "%s", clnt_spcreateerror("couldn't get mountd address on udp")); goto badout; } /* * Create privileged UDP socket */ *sock = t_open(nc->nc_device, O_RDWR, 0); if (*sock < 0) { plog(XLOG_ERROR, "t_open %s: %m", nc->nc_device); goto badout; /* neither tcp not udp succeeded */ } if (bind_resv_port(*sock, (u_short *) 0) < 0) plog(XLOG_ERROR, "couldn't bind mountd socket to privileged port"); if ((client = clnt_dg_create(*sock, &nb, MOUNTPROG, mnt_version, 0, 0)) == (CLIENT *) NULL) { plog(XLOG_ERROR, "clnt_dg_create failed"); t_close(*sock); goto badout; /* neither tcp not udp succeeded */ } if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) { plog(XLOG_ERROR, "clnt_control CLSET_RETRY_TIMEOUT for udp failed"); clnt_destroy(client); goto badout; /* neither tcp not udp succeeded */ } /* udp succeeded */ dlog("get_mount_client: using udp, port %d", sin.sin_port); return client; badout: /* failed */ if (nc) freenetconfigent(nc); return NULL; }
/*ARGSUSED*/ int main(int argc, char *argv[]) { register SVCXPRT *transp; load_libzfs(); /* * If stdin looks like a TLI endpoint, we assume * that we were started by a port monitor. If * t_getstate fails with TBADF, this is not a * TLI endpoint. */ if (t_getstate(0) != -1 || t_errno != TBADF) { char *netid; struct netconfig *nconf = NULL; openlog("rquotad", LOG_PID, LOG_DAEMON); if ((netid = getenv("NLSPROVIDER")) == NULL) { struct t_info tinfo; if (t_sync(0) == -1) { syslog(LOG_ERR, "could not do t_sync"); zexit(1); } if (t_getinfo(0, &tinfo) == -1) { syslog(LOG_ERR, "t_getinfo failed"); zexit(1); } if (tinfo.servtype == T_CLTS) { if (tinfo.addr == INET_ADDRSTRLEN) netid = "udp"; else netid = "udp6"; } else { syslog(LOG_ERR, "wrong transport"); zexit(1); } } if ((nconf = getnetconfigent(netid)) == NULL) { syslog(LOG_ERR, "cannot get transport info"); } if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { syslog(LOG_ERR, "cannot create server handle"); zexit(1); } if (nconf) freenetconfigent(nconf); if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, dispatch, 0)) { syslog(LOG_ERR, "unable to register (RQUOTAPROG, RQUOTAVERS)."); zexit(1); } (void) sigset(SIGALRM, (void(*)(int)) closedown); (void) alarm(RPCSVC_CLOSEDOWN); svc_run(); zexit(1); /* NOTREACHED */ } /* * Started from a shell - fork the daemon. */ switch (fork()) { case 0: /* child */ break; case -1: perror("rquotad: can't fork"); zexit(1); default: /* parent */ zexit(0); } /* * Close existing file descriptors, open "/dev/null" as * standard input, output, and error, and detach from * controlling terminal. */ closefrom(0); (void) open("/dev/null", O_RDONLY); (void) open("/dev/null", O_WRONLY); (void) dup(1); (void) setsid(); openlog("rquotad", LOG_PID, LOG_DAEMON); /* * Create datagram service */ if (svc_create(dispatch, RQUOTAPROG, RQUOTAVERS, "datagram_v") == 0) { syslog(LOG_ERR, "couldn't register datagram_v service"); zexit(1); } /* * Start serving */ svc_run(); syslog(LOG_ERR, "Error: svc_run shouldn't have returned"); return (1); }
int nfs41_server_resolve( IN const char *hostname, IN unsigned short port, OUT multi_addr4 *addrs) { int status = ERROR_BAD_NET_NAME; char service[16]; struct addrinfo hints = { 0 }, *res, *info; struct netconfig *nconf; struct netbuf addr; char *netid, *uaddr; dprintf(SRVLVL, "--> nfs41_server_resolve(%s:%u)\n", hostname, port); addrs->count = 0; StringCchPrintfA(service, 16, "%u", port); /* request a list of tcp addrs for the given hostname,port */ hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (getaddrinfo(hostname, service, &hints, &res) != 0) goto out; for (info = res; info != NULL; info = info->ai_next) { /* find the appropriate entry in /etc/netconfig */ switch (info->ai_family) { case AF_INET: netid = "tcp"; break; case AF_INET6: netid = "tcp6"; break; default: continue; } nconf = getnetconfigent(netid); if (nconf == NULL) continue; /* convert to a transport-independent universal address */ addr.buf = info->ai_addr; addr.maxlen = addr.len = (unsigned int)info->ai_addrlen; uaddr = taddr2uaddr(nconf, &addr); freenetconfigent(nconf); if (uaddr == NULL) continue; StringCchCopyA(addrs->arr[addrs->count].netid, NFS41_NETWORK_ID_LEN+1, netid); StringCchCopyA(addrs->arr[addrs->count].uaddr, NFS41_UNIVERSAL_ADDR_LEN+1, uaddr); freeuaddr(uaddr); status = NO_ERROR; if (++addrs->count >= NFS41_ADDRS_PER_SERVER) break; } freeaddrinfo(res); out: if (status) dprintf(SRVLVL, "<-- nfs41_server_resolve(%s:%u) returning " "error %d\n", hostname, port, status); else dprintf(SRVLVL, "<-- nfs41_server_resolve(%s:%u) returning " "%s\n", hostname, port, addrs->arr[0].uaddr); return status; }
int main(int argc, char *argv[]) { pid_t pid; int c; char *progname = argv[0]; int connmaxrec = RPC_MAXDATASIZE; while ((c = getopt(argc, argv, "d")) != -1) switch ((char)c) { case 'd': debug++; break; default: (void) fprintf(stderr, "usage: %s [-d]\n", progname); exit(EXIT_FAILURE); } /* * Set non-blocking mode and maximum record size for * connection oriented RPC transports. */ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { msgout("unable to set maximum RPC record size"); } /* * If stdin looks like a TLI endpoint, we assume * that we were started by a port monitor. If * t_getstate fails with TBADF, this is not a * TLI endpoint. */ if (t_getstate(0) != -1 || t_errno != TBADF) { char *netid; struct netconfig *nconf = NULL; SVCXPRT *transp; int pmclose; if ((netid = getenv("NLSPROVIDER")) == NULL) { if (debug) msgout("cannot get transport name"); } else if ((nconf = getnetconfigent(netid)) == NULL) { if (debug) msgout("cannot get transport info"); } pmclose = (t_getstate(0) != T_DATAXFER); if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { msgout("cannot create server handle"); exit(EXIT_FAILURE); } if (nconf) freenetconfigent(nconf); if (!svc_reg(transp, BOOTPARAMPROG, BOOTPARAMVERS, bootparamprog_1, 0)) { msgout("unable to register (BOOTPARAMPROG, " "BOOTPARAMVERS)."); exit(EXIT_FAILURE); } if (pmclose) { (void) signal(SIGALRM, closedown); (void) alarm(_RPCSVC_CLOSEDOWN); } svc_run(); exit(EXIT_FAILURE); /* NOTREACHED */ } /* * run this process in the background only if it was started from * a shell and the debug flag was not given. */ if (!server_child && !debug) { pid = fork(); if (pid < 0) { perror("cannot fork"); exit(EXIT_FAILURE); } if (pid) exit(EXIT_SUCCESS); closefrom(0); (void) setsid(); } /* * messges go to syslog if the program was started by * another server, or if it was run from the command line without * the debug flag. */ if (server_child || !debug) openlog("bootparam_prot", LOG_PID, LOG_DAEMON); if (debug) { if (debug == 1) msgout("in debug mode."); else msgout("in debug mode (level %d).", debug); } if (!svc_create(bootparamprog_1, BOOTPARAMPROG, BOOTPARAMVERS, "netpath")) { msgout("unable to create (BOOTPARAMPROG, BOOTPARAMVERS) " "for netpath."); exit(EXIT_FAILURE); } svc_run(); msgout("svc_run returned"); return (EXIT_FAILURE); }
static void get_xdmcp_sock(void) { #ifdef STREAMSCONN struct netconfig *nconf; if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) { XdmcpWarning("t_open() of /dev/udp failed"); return; } if (t_bind(xdmcpSocket, NULL, NULL) < 0) { XdmcpWarning("UDP socket creation failed"); t_error("t_bind(xdmcpSocket) failed"); t_close(xdmcpSocket); return; } /* * This part of the code looks contrived. It will actually fit in nicely * when the CLTS part of Xtrans is implemented. */ if ((nconf = getnetconfigent("udp")) == NULL) { XdmcpWarning("UDP socket creation failed: getnetconfigent()"); t_unbind(xdmcpSocket); t_close(xdmcpSocket); return; } if (netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL)) { XdmcpWarning("UDP set broadcast option failed: netdir_options()"); freenetconfigent(nconf); t_unbind(xdmcpSocket); t_close(xdmcpSocket); return; } freenetconfigent(nconf); #else int soopts = 1; #if defined(IPv6) && defined(AF_INET6) if ((xdmcpSocket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) XdmcpWarning("INET6 UDP socket creation failed"); #endif if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) XdmcpWarning("UDP socket creation failed"); #ifdef SO_BROADCAST else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, (char *) &soopts, sizeof(soopts)) < 0) XdmcpWarning("UDP set broadcast socket-option failed"); #endif /* SO_BROADCAST */ if (xdmcpSocket >= 0 && xdm_from != NULL) { if (bind(xdmcpSocket, (struct sockaddr *) &FromAddress, FromAddressLen) < 0) { FatalError("Xserver: failed to bind to -from address: %s\n", xdm_from); } } #endif /* STREAMSCONN */ }
CLIENT * get_client(struct sockaddr *host_addr, rpcvers_t vers) { CLIENT *client; struct timeval retry_time, time_now; int error, i; const char *netid; struct netconfig *nconf; char host[NI_MAXHOST]; uid_t old_euid; int clnt_fd; gettimeofday(&time_now, NULL); /* * Search for the given client in the cache, zapping any expired * entries that we happen to notice in passing. */ for (i = 0; i < CLIENT_CACHE_SIZE; i++) { client = clnt_cache_ptr[i]; if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) < time_now.tv_sec)) { /* Cache entry has expired. */ if (debug_level > 3) syslog(LOG_DEBUG, "Expired CLIENT* in cache"); clnt_cache_time[i] = 0L; clnt_destroy(client); clnt_cache_ptr[i] = NULL; client = NULL; } if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i], host_addr) && clnt_cache_vers[i] == vers) { /* Found it! */ if (debug_level > 3) syslog(LOG_DEBUG, "Found CLIENT* in cache"); return (client); } } if (debug_level > 3) syslog(LOG_DEBUG, "CLIENT* not found in cache, creating"); /* Not found in cache. Free the next entry if it is in use. */ if (clnt_cache_ptr[clnt_cache_next_to_use]) { clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]); clnt_cache_ptr[clnt_cache_next_to_use] = NULL; } /* * Need a host string for clnt_tp_create. Use NI_NUMERICHOST * to avoid DNS lookups. */ error = getnameinfo(host_addr, host_addr->sa_len, host, sizeof host, NULL, 0, NI_NUMERICHOST); if (error != 0) { syslog(LOG_ERR, "unable to get name string for caller: %s", gai_strerror(error)); return NULL; } #if 1 if (host_addr->sa_family == AF_INET6) netid = "udp6"; else netid = "udp"; #else if (host_addr->sa_family == AF_INET6) netid = "tcp6"; else netid = "tcp"; #endif nconf = getnetconfigent(netid); if (nconf == NULL) { syslog(LOG_ERR, "could not get netconfig info for '%s': " "no /etc/netconfig file?", netid); return NULL; } client = clnt_tp_create(host, NLM_PROG, vers, nconf); freenetconfigent(nconf); if (!client) { syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create")); syslog(LOG_ERR, "Unable to return result to %s", host); return NULL; } /* Get the FD of the client, for bindresvport. */ clnt_control(client, CLGET_FD, &clnt_fd); /* Regain root privileges, for bindresvport. */ old_euid = geteuid(); seteuid(0); /* * Bind the client FD to a reserved port. * Some NFS servers reject any NLM request from a non-reserved port. */ bindresvport(clnt_fd, NULL); /* Drop root privileges again. */ seteuid(old_euid); /* Success - update the cache entry */ clnt_cache_ptr[clnt_cache_next_to_use] = client; memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr, host_addr->sa_len); clnt_cache_vers[clnt_cache_next_to_use] = vers; clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec; if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE) clnt_cache_next_to_use = 0; /* * Disable the default timeout, so we can specify our own in calls * to clnt_call(). (Note that the timeout is a different concept * from the retry period set in clnt_udp_create() above.) */ retry_time.tv_sec = -1; retry_time.tv_usec = -1; clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time); if (debug_level > 3) syslog(LOG_DEBUG, "Created CLIENT* for %s", host); return client; }
/* * valid_props validates all the properties in an array of inetd_prop_t's, * marking each property as valid or invalid. If any properties are invalid, * it returns B_FALSE, otherwise it returns B_TRUE. Note that some properties * are interdependent, so if one is invalid, it leaves others in an * indeterminate state (such as ISRPC and SVC_NAME). In this case, the * indeterminate property will be marked valid. IE, the only properties * marked invalid are those that are KNOWN to be invalid. * * Piggy-backed onto this validation if 'fmri' is non-NULL is the construction * of a structured configuration, a basic_cfg_t, which is used by inetd. * If 'fmri' is set then the latter three parameters need to be set to * non-NULL values, and if the configuration is valid, the storage referenced * by cfgpp is set to point at an initialized basic_cfg_t. */ boolean_t valid_props(inetd_prop_t *prop, const char *fmri, basic_cfg_t **cfgpp, uu_list_pool_t *proto_info_pool, uu_list_pool_t *tlx_ci_pool) { char *bufp, *cp; boolean_t ret = B_TRUE; int i; long uidl; boolean_t isrpc; int sock_type_id; int rpc_pnum; int rpc_lv, rpc_hv; basic_cfg_t *cfg; char *proto = NULL; int pi; char **netids = NULL; int ni = 0; if (fmri != NULL) assert((cfgpp != NULL) && (proto_info_pool != NULL) && (tlx_ci_pool != NULL)); /* * Set all checkable properties to valid as a baseline. We'll be * marking all invalid properties. */ for (i = 0; prop[i].ip_name != NULL; i++) { if (prop[i].ip_error != IVE_UNSET) prop[i].ip_error = IVE_VALID; } if (((cfg = calloc(1, sizeof (basic_cfg_t))) == NULL) || ((fmri != NULL) && ((cfg->proto_list = uu_list_create(proto_info_pool, NULL, 0)) == NULL))) { free(cfg); return (B_FALSE); } /* Check a service name was supplied */ if ((prop[PT_SVC_NAME_INDEX].ip_error == IVE_UNSET) || ((cfg->svc_name = strdup(prop[PT_SVC_NAME_INDEX].ip_value.iv_string)) == NULL)) prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID; /* Check that iswait and isrpc have valid boolean values */ if ((prop[PT_ISWAIT_INDEX].ip_error == IVE_UNSET) || (((cfg->iswait = prop[PT_ISWAIT_INDEX].ip_value.iv_boolean) != B_TRUE) && (cfg->iswait != B_FALSE))) prop[PT_ISWAIT_INDEX].ip_error = IVE_INVALID; if ((prop[PT_ISRPC_INDEX].ip_error == IVE_UNSET) || (((isrpc = prop[PT_ISRPC_INDEX].ip_value.iv_boolean) != B_TRUE) && (isrpc != B_FALSE))) { prop[PT_ISRPC_INDEX].ip_error = IVE_INVALID; } else if (isrpc) { /* * This is an RPC service, so ensure that the RPC version * numbers are zero or greater, that the low version isn't * greater than the high version and a valid program name * is supplied. */ if ((prop[PT_RPC_LW_VER_INDEX].ip_error == IVE_UNSET) || ((rpc_lv = prop[PT_RPC_LW_VER_INDEX].ip_value.iv_int) < 0)) prop[PT_RPC_LW_VER_INDEX].ip_error = IVE_INVALID; if ((prop[PT_RPC_HI_VER_INDEX].ip_error == IVE_UNSET) || ((rpc_hv = prop[PT_RPC_HI_VER_INDEX].ip_value.iv_int) < 0)) prop[PT_RPC_HI_VER_INDEX].ip_error = IVE_INVALID; if ((prop[PT_RPC_LW_VER_INDEX].ip_error != IVE_INVALID) && (prop[PT_RPC_HI_VER_INDEX].ip_error != IVE_INVALID) && (rpc_lv > rpc_hv)) { prop[PT_RPC_LW_VER_INDEX].ip_error = IVE_INVALID; prop[PT_RPC_HI_VER_INDEX].ip_error = IVE_INVALID; } if ((cfg->svc_name != NULL) && ((rpc_pnum = get_rpc_prognum(cfg->svc_name)) == -1)) prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID; } /* Check that the socket type is one of the acceptable values. */ cfg->istlx = B_FALSE; if ((prop[PT_SOCK_TYPE_INDEX].ip_error == IVE_UNSET) || ((sock_type_id = get_sock_type_id( prop[PT_SOCK_TYPE_INDEX].ip_value.iv_string)) == -1) && !(cfg->istlx = is_tlx_service(prop))) prop[PT_SOCK_TYPE_INDEX].ip_error = IVE_INVALID; /* Get the bind address */ if (!cfg->istlx && prop[PT_BIND_ADDR_INDEX].ip_error != IVE_UNSET && (cfg->bind_addr = strdup(prop[PT_BIND_ADDR_INDEX].ip_value.iv_string)) == NULL) prop[PT_BIND_ADDR_INDEX].ip_error = IVE_INVALID; /* * Iterate through all the different protos/netids resulting from the * proto property and check that they're valid and perform checks on * other fields that are tied-in with the proto. */ pi = 0; do { socket_info_t *si = NULL; tlx_info_t *ti = NULL; proto_info_t *p_inf = NULL; boolean_t v6only = B_FALSE; char *only; boolean_t invalid_proto = B_FALSE; char **protos; struct protoent pe; char gpbuf[1024]; struct netconfig *nconf = NULL; /* * If we don't know whether it's an rpc service or its * endpoint type, we can't do any of the proto checks as we * have no context; break out. */ if ((prop[PT_ISRPC_INDEX].ip_error != IVE_VALID) || (prop[PT_SOCK_TYPE_INDEX].ip_error != IVE_VALID)) break; /* skip proto specific processing if the proto isn't set. */ if (prop[PT_PROTO_INDEX].ip_error == IVE_UNSET) { invalid_proto = B_TRUE; goto past_proto_processing; } protos = prop[PT_PROTO_INDEX].ip_value.iv_string_list; /* * Get the next netid/proto. */ if (!cfg->istlx || !isrpc) { proto = protos[pi++]; /* * This is a TLI/RPC service, so get the next netid, expanding * any supplied nettype. */ } else if ((netids == NULL) || ((proto = netids[ni++]) == NULL)) { /* * Either this is the first time around or * we've exhausted the last set of netids, so * try and get the next set using the currently * indexed proto entry. */ if (netids != NULL) { destroy_strings(netids); netids = NULL; } if (protos[pi] != NULL) { if ((netids = get_netids(protos[pi++])) == NULL) { invalid_proto = B_TRUE; proto = protos[pi - 1]; } else { ni = 0; proto = netids[ni++]; } } else { proto = NULL; } } if (proto == NULL) break; if (invalid_proto) goto past_proto_processing; /* strip a trailing only to simplify further processing */ only = proto + strlen(proto) - (sizeof ("6only") - 1); if ((only > proto) && (strcmp(only, "6only") == 0)) { *++only = '\0'; v6only = B_TRUE; } /* validate the proto/netid */ if (!cfg->istlx) { if (!valid_socket_proto(proto)) invalid_proto = B_TRUE; } else { /* * Check if we've got a valid netid. If * getnetconfigent() fails, we check to see whether * we've got a v6 netid that may have been rejected * because no IPv6 interface was configured before * flagging 'proto' as invalid. If the latter condition * holds, we don't flag the proto as invalid, and * leave inetd to handle the value appropriately * when it tries to listen on behalf of the service. */ if (((nconf = getnetconfigent(proto)) == NULL) && !v6_proto(proto)) invalid_proto = B_TRUE; } if (invalid_proto) goto past_proto_processing; /* * dissallow datagram type nowait services */ if ((prop[PT_ISWAIT_INDEX].ip_error == IVE_VALID) && !cfg->iswait) { if (strncmp(proto, SOCKET_PROTO_UDP, sizeof (SOCKET_PROTO_UDP) - 1) == 0) { invalid_proto = B_TRUE; } else if (cfg->istlx && (nconf != NULL) && (nconf->nc_semantics == NC_TPI_CLTS)) { invalid_proto = B_TRUE; } if (invalid_proto) { prop[PT_ISWAIT_INDEX].ip_error = IVE_INVALID; goto past_proto_processing; } } /* * We're running in validate only mode. Don't bother creating * any proto structures (they don't do any further validation). */ if (fmri == NULL) goto past_proto_processing; /* * Create the apropriate transport info structure. */ if (cfg->istlx) { if ((ti = create_tlx_info(proto, tlx_ci_pool)) != NULL) p_inf = (proto_info_t *)ti; } else { struct sockaddr_storage *ss; if ((si = calloc(1, sizeof (socket_info_t))) != NULL) { p_inf = (proto_info_t *)si; si->type = sock_type_id; ss = &si->local_addr; if (v6_socket_proto(proto)) { ss->ss_family = AF_INET6; /* already in network order */ ((struct sockaddr_in6 *)ss)->sin6_addr = in6addr_any; } else { ss->ss_family = AF_INET; ((struct sockaddr_in *)ss)->sin_addr. s_addr = htonl(INADDR_ANY); } if (set_bind_addr(ss, cfg->bind_addr) != 0) { prop[PT_BIND_ADDR_INDEX].ip_error = IVE_INVALID; } } } if (p_inf == NULL) { invalid_proto = B_TRUE; goto past_proto_processing; } p_inf->v6only = v6only; /* * Store the supplied proto string for error reporting, * re-attaching the 'only' suffix if one was taken off. */ if ((p_inf->proto = malloc(strlen(proto) + 5)) == NULL) { invalid_proto = B_TRUE; goto past_proto_processing; } else { (void) strlcpy(p_inf->proto, proto, strlen(proto) + 5); if (v6only) (void) strlcat(p_inf->proto, "only", strlen(proto) + 5); } /* * Validate and setup RPC/non-RPC specifics. */ if (isrpc) { rpc_info_t *ri; if ((rpc_pnum != -1) && (rpc_lv != -1) && (rpc_hv != -1)) { if ((ri = create_rpc_info(proto, rpc_pnum, rpc_lv, rpc_hv)) == NULL) { invalid_proto = B_TRUE; } else { p_inf->ri = ri; } } } past_proto_processing: /* validate non-RPC service name */ if (!isrpc && (cfg->svc_name != NULL)) { struct servent se; char gsbuf[NSS_BUFLEN_SERVICES]; char *gsproto = proto; if (invalid_proto) { /* * Make getservbyname_r do its lookup without a * proto. */ gsproto = NULL; } else if (gsproto != NULL) { /* * Since getservbyname & getprotobyname don't * support tcp6, udp6 or sctp6 take off the 6 * digit from protocol. */ if (v6_socket_proto(gsproto)) gsproto[strlen(gsproto) - 1] = '\0'; } if (getservbyname_r(cfg->svc_name, gsproto, &se, gsbuf, sizeof (gsbuf)) == NULL) { if (gsproto != NULL) invalid_proto = B_TRUE; prop[PT_SVC_NAME_INDEX].ip_error = IVE_INVALID; } else if (cfg->istlx && (ti != NULL)) { /* LINTED E_BAD_PTR_CAST_ALIGN */ SS_SETPORT(*(struct sockaddr_storage *) ti->local_addr.buf, se.s_port); } else if (!cfg->istlx && (si != NULL)) { if ((gsproto != NULL) && getprotobyname_r(gsproto, &pe, gpbuf, sizeof (gpbuf)) == NULL) { invalid_proto = B_TRUE; } else { si->protocol = pe.p_proto; } SS_SETPORT(si->local_addr, se.s_port); } } if (p_inf != NULL) { p_inf->listen_fd = -1; /* add new proto entry to proto_list */ uu_list_node_init(p_inf, &p_inf->link, proto_info_pool); (void) uu_list_insert_after(cfg->proto_list, NULL, p_inf); } if (nconf != NULL) freenetconfigent(nconf); if (invalid_proto) prop[PT_PROTO_INDEX].ip_error = IVE_INVALID; } while (proto != NULL); /* while just processed a proto */ /* * Check that the exec string for the start method actually exists and * that the user is either a valid username or uid. Note we don't * mandate the setting of these fields, and don't do any checks * for arg0, hence its absence. */ if (prop[PT_EXEC_INDEX].ip_error != IVE_UNSET) { /* Don't pass any arguments to access() */ if ((bufp = strdup( prop[PT_EXEC_INDEX].ip_value.iv_string)) == NULL) { prop[PT_EXEC_INDEX].ip_error = IVE_INVALID; } else { if ((cp = strpbrk(bufp, " \t")) != NULL) *cp = '\0'; if ((access(bufp, F_OK) == -1) && (errno == ENOENT)) prop[PT_EXEC_INDEX].ip_error = IVE_INVALID; free(bufp); } } if (prop[PT_USER_INDEX].ip_error != IVE_UNSET) { char pw_buf[NSS_BUFLEN_PASSWD]; struct passwd pw; if (getpwnam_r(prop[PT_USER_INDEX].ip_value.iv_string, &pw, pw_buf, NSS_BUFLEN_PASSWD) == NULL) { errno = 0; uidl = strtol(prop[PT_USER_INDEX].ip_value.iv_string, &bufp, 10); if ((errno != 0) || (*bufp != '\0') || (getpwuid_r(uidl, &pw, pw_buf, NSS_BUFLEN_PASSWD) == NULL)) prop[PT_USER_INDEX].ip_error = IVE_INVALID; } } /* * Iterate through the properties in the array verifying that any * default properties are valid, and setting the return boolean * according to whether any properties were marked invalid. */ for (i = 0; prop[i].ip_name != NULL; i++) { if (prop[i].ip_error == IVE_UNSET) continue; if (prop[i].ip_default && !valid_default_prop(prop[i].ip_name, &prop[i].ip_value)) prop[i].ip_error = IVE_INVALID; if (prop[i].ip_error == IVE_INVALID) ret = B_FALSE; } /* pass back the basic_cfg_t if requested and it's a valid config */ if ((cfgpp != NULL) && ret) { *cfgpp = cfg; } else { destroy_basic_cfg(cfg); } return (ret); }
CreateWellKnownSockets () { struct t_bind bind_addr; struct netconfig *nconf; struct nd_hostserv service; struct nd_addrlist *servaddrs; char *name, *localHostname(); char bindbuf[15]; int it; if (request_port == 0) return; Debug ("creating UDP stream %d\n", request_port); nconf = getnetconfigent("udp"); if (!nconf) { t_error("getnetconfigent udp"); return; } xdmcpFd = t_open(nconf->nc_device, O_RDWR, NULL); if (xdmcpFd == -1) { LogError ("XDMCP stream creation failed\n"); t_error ("t_open"); return; } name = localHostname (); registerHostname (name, strlen (name)); RegisterCloseOnFork (xdmcpFd); service.h_host = HOST_SELF; sprintf(bindbuf, "%d", request_port); service.h_serv = bindbuf; netdir_getbyname(nconf, &service, &servaddrs); freenetconfigent(nconf); bind_addr.qlen = 5; bind_addr.addr.buf = servaddrs->n_addrs[0].buf; bind_addr.addr.len = servaddrs->n_addrs[0].len; it = t_bind(xdmcpFd, &bind_addr, &bind_addr); netdir_free(servaddrs, ND_ADDRLIST); if (it < 0) { LogError ("error binding STREAMS address %d\n", request_port); t_error("t_bind"); /* also goes to log file */ t_close (xdmcpFd); xdmcpFd = -1; return; } WellKnownSocketsMax = xdmcpFd; FD_SET (xdmcpFd, &WellKnownSocketsMask); chooserFd = t_open ("/dev/tcp", O_RDWR, NULL); Debug ("Created chooser fd %d\n", chooserFd); if (chooserFd == -1) { LogError ("chooser stream creation failed\n"); t_error("t_open chooser"); return; } if (chooserFd > WellKnownSocketsMax) WellKnownSocketsMax = chooserFd; FD_SET (chooserFd, &WellKnownSocketsMask); }