/* * find the IP address that can be used to connect autofs service to. */ static int get_autofs_address(struct netconfig *ncp, struct t_bind *tbp) { int ret; struct nd_addrlist *addrs = (struct nd_addrlist *) NULL; struct nd_hostserv service; service.h_host = HOST_SELF_CONNECT; service.h_serv = "autofs"; ret = netdir_getbyname(ncp, &service, &addrs); if (ret) { plog(XLOG_FATAL, "get_autofs_address: cannot get local host address: %s", netdir_sperror()); goto out; } /* * XXX: there may be more more than one address for this local * host. Maybe something can be done with those. */ tbp->addr.len = addrs->n_addrs->len; tbp->addr.maxlen = addrs->n_addrs->len; memcpy(tbp->addr.buf, addrs->n_addrs->buf, addrs->n_addrs->len); tbp->qlen = 8; /* arbitrary? who cares really */ /* all OK */ netdir_free((voidp) addrs, ND_ADDRLIST); out: return ret; }
/* * find the IP address that can be used to connect to the local host */ void amu_get_myaddress(struct in_addr *iap) { int ret; voidp handlep; struct netconfig *ncp; struct nd_addrlist *addrs = (struct nd_addrlist *) NULL; struct nd_hostserv service; handlep = setnetconfig(); ncp = getnetconfig(handlep); service.h_host = HOST_SELF_CONNECT; service.h_serv = (char *) NULL; ret = netdir_getbyname(ncp, &service, &addrs); if (ret || !addrs || addrs->n_cnt < 1) { plog(XLOG_FATAL, "cannot get local host address. using 127.0.0.1"); iap->s_addr = 0x7f000001; } else { /* * XXX: there may be more more than one address for this local * host. Maybe something can be done with those. */ struct sockaddr_in *sinp = (struct sockaddr_in *) addrs->n_addrs[0].buf; iap->s_addr = htonl(sinp->sin_addr.s_addr); } endnetconfig(handlep); /* free's up internal resources too */ netdir_free((voidp) addrs, ND_ADDRLIST); }
/* * find the IP address that can be used to connect to the local host */ void amu_get_myaddress(struct in_addr *iap, const char *preferred_localhost) { int ret; voidp handlep; struct netconfig *ncp; struct nd_addrlist *addrs = (struct nd_addrlist *) NULL; struct nd_hostserv service; handlep = setnetconfig(); ncp = getnetconfig(handlep); service.h_host = (preferred_localhost ? (char *) preferred_localhost : HOST_SELF_CONNECT); service.h_serv = (char *) NULL; ret = netdir_getbyname(ncp, &service, &addrs); if (ret || !addrs || addrs->n_cnt < 1) { plog(XLOG_FATAL, "cannot get local host address. using 127.0.0.1"); iap->s_addr = htonl(INADDR_LOOPBACK); } else { /* * XXX: there may be more more than one address for this local * host. Maybe something can be done with those. */ struct sockaddr_in *sinp = (struct sockaddr_in *) addrs->n_addrs[0].buf; char dq[20]; if (preferred_localhost) plog(XLOG_INFO, "localhost_address \"%s\" requested, using %s", preferred_localhost, inet_dquad(dq, sizeof(dq), iap->s_addr)); iap->s_addr = sinp->sin_addr.s_addr; /* XXX: used to be htonl() */ } endnetconfig(handlep); /* free's up internal resources too */ netdir_free((voidp) addrs, ND_ADDRLIST); }
int do_connect(const char *host, const char *serv) { int tfd, i; void *handle; struct t_call tcall; struct t_discon tdiscon; struct netconfig *ncp; struct nd_hostserv hs; struct nd_addrlist *alp; struct netbuf *np; handle = Setnetpath(); hs.h_host = (char *) host; hs.h_serv = (char *) serv; while ( (ncp = getnetpath(handle)) != NULL) { if (strcmp(ncp->nc_netid, "ticotsord") != 0) continue; if (netdir_getbyname(ncp, &hs, &alp) != 0) continue; /* try each server address */ for (i = 0, np = alp->n_addrs; i < alp->n_cnt; i++, np++) { printf("device = %s\n", ncp->nc_device); if ( (tfd = t_open(ncp->nc_device, O_RDWR, NULL)) < 0) err_xti("t_open error for %s", ncp->nc_device); if (t_bind(tfd, NULL, NULL) < 0) err_xti("t_bind error"); tcall.addr.len = np->len; tcall.addr.buf = np->buf; /* pointer copy */ printf("addr.len = %d\n", tcall.addr.len); printf("addr.buf = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", tcall.addr.buf[0], tcall.addr.buf[1], tcall.addr.buf[2], tcall.addr.buf[3], tcall.addr.buf[4], tcall.addr.buf[5], tcall.addr.buf[6], tcall.addr.buf[7], tcall.addr.buf[8], tcall.addr.buf[9], tcall.addr.buf[10]); } netdir_free(alp, ND_ADDRLIST); } endnetpath(handle); return(-1); }
/* * Remove an entry from mounted list */ static void umount(struct svc_req *rqstp) { char *host, *path, *remove_path; char rpath[MAXPATHLEN]; struct nd_hostservlist *clnames = NULL; SVCXPRT *transp; struct netbuf *nb; transp = rqstp->rq_xprt; path = NULL; if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { svcerr_decode(transp); return; } errno = 0; if (!svc_sendreply(transp, xdr_void, (char *)NULL)) log_cant_reply(transp); getclientsnames(transp, &nb, &clnames); if (clnames == NULL) { /* * Without the hostname we can't do audit or delete * this host from the mount entries. */ svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); return; } host = clnames->h_hostservs[0].h_host; if (verbose) syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path); audit_mountd_umount(host, path); remove_path = rpath; /* assume we will use the cannonical path */ if (realpath(path, rpath) == NULL) { if (verbose) syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path); remove_path = path; /* use path provided instead */ } mntlist_delete(host, remove_path); /* remove from mount list */ svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); netdir_free(clnames, ND_HOSTSERVLIST); }
/* * 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)); }
int udp_client(const char *host, const char *serv, void **vptr, socklen_t *lenp) { int tfd; void *handle; struct netconfig *ncp; struct nd_hostserv hs; struct nd_addrlist *alp; struct netbuf *np; struct t_unitdata *tudptr; handle = Setnetpath(); hs.h_host = (char *) host; hs.h_serv = (char *) serv; while ( (ncp = getnetpath(handle)) != NULL) { if (strcmp(ncp->nc_proto, "udp") != 0) continue; if (netdir_getbyname(ncp, &hs, &alp) != 0) continue; tfd = T_open(ncp->nc_device, O_RDWR, NULL); T_bind(tfd, NULL, NULL); tudptr = T_alloc(tfd, T_UNITDATA, T_ADDR); np = alp->n_addrs; /* use first server address */ tudptr->addr.len = min(tudptr->addr.maxlen, np->len); memcpy(tudptr->addr.buf, np->buf, tudptr->addr.len); endnetpath(handle); netdir_free(alp, ND_ADDRLIST); *vptr = tudptr; /* return pointer to t_unitdata{} */ *lenp = tudptr->addr.maxlen;/* and size of addresses */ return(tfd); } endnetpath(handle); return(-1); }
int udp_server(const char *host, const char *serv, socklen_t *addrlenp) { int tfd; void *handle; struct t_bind tbind; struct t_info tinfo; struct netconfig *ncp; struct nd_hostserv hs; struct nd_addrlist *alp; struct netbuf *np; handle = Setnetconfig(); hs.h_host = (host == NULL) ? HOST_SELF : (char *) host; hs.h_serv = (char *) serv; while ( (ncp = getnetconfig(handle)) != NULL && strcmp(ncp->nc_proto, "udp") != 0) ; if (ncp == NULL) return(-1); if (netdir_getbyname(ncp, &hs, &alp) != 0) return(-2); np = alp->n_addrs; /* use first address */ tfd = T_open(ncp->nc_device, O_RDWR, &tinfo); tbind.addr = *np; /* copy entire netbuf{} */ tbind.qlen = 0; /* not used for connectionless server */ T_bind(tfd, &tbind, NULL); endnetconfig(handle); netdir_free(alp, ND_ADDRLIST); if (addrlenp) *addrlenp = tinfo.addr; /* size of protocol addresses */ return(tfd); }
void log_cant_reply(SVCXPRT *transp) { int saverrno; struct nd_hostservlist *clnames = NULL; register char *host; struct netbuf *nb; saverrno = errno; /* save error code */ getclientsnames(transp, &nb, &clnames); if (clnames == NULL) return; host = clnames->h_hostservs->h_host; errno = saverrno; if (errno == 0) syslog(LOG_ERR, "couldn't send reply to %s", host); else syslog(LOG_ERR, "couldn't send reply to %s: %m", host); netdir_free(clnames, ND_HOSTSERVLIST); }
/* * Remove all entries for one machine from mounted list */ static void umountall(struct svc_req *rqstp) { struct nd_hostservlist *clnames = NULL; SVCXPRT *transp; char *host; struct netbuf *nb; transp = rqstp->rq_xprt; if (!svc_getargs(transp, xdr_void, NULL)) { svcerr_decode(transp); return; } /* * We assume that this call is asynchronous and made via rpcbind * callit routine. Therefore return control immediately. The error * causes rpcbind to remain silent, as opposed to every machine * on the net blasting the requester with a response. */ svcerr_systemerr(transp); getclientsnames(transp, &nb, &clnames); if (clnames == NULL) { /* Can't do anything without the name of the client */ return; } host = clnames->h_hostservs[0].h_host; /* * Remove all hosts entries from mount list */ mntlist_delete_all(host); if (verbose) syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host); netdir_free(clnames, ND_HOSTSERVLIST); }
/* * __yp_all_cflookup() is a variant of the yp_all() code, * which adds a 'hardlookup' parameter. This parameter is passed * to __yp_dobind_cflookup(), and determines whether the server * binding attempt is hard (try forever) of soft (retry a compiled- * in number of times). */ int __yp_all_cflookup(char *domain, char *map, struct ypall_callback *callback, int hardlookup) { size_t domlen; size_t maplen; struct ypreq_nokey req; int reason; struct dom_binding *pdomb; enum clnt_stat s; CLIENT *allc; char server_name[MAXHOSTNAMELEN]; char errbuf[BUFSIZ]; if ((map == NULL) || (domain == NULL)) return (YPERR_BADARGS); domlen = strlen(domain); maplen = strlen(map); if ((domlen == 0) || (domlen > YPMAXDOMAIN) || (maplen == 0) || (maplen > YPMAXMAP) || (callback == NULL)) return (YPERR_BADARGS); if (reason = __yp_dobind_cflookup(domain, &pdomb, hardlookup)) return (reason); if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) { __yp_rel_binding(pdomb); return (YPERR_VERS); } (void) mutex_lock(&pdomb->server_name_lock); if (!pdomb->dom_binding->ypbind_servername) { (void) mutex_unlock(&pdomb->server_name_lock); __yp_rel_binding(pdomb); syslog(LOG_ERR, "yp_all: failed to get server's name\n"); return (YPERR_RPC); } (void) strcpy(server_name, pdomb->dom_binding->ypbind_servername); (void) mutex_unlock(&pdomb->server_name_lock); if (strcmp(server_name, nullstring) == 0) { /* * This is the case where ypbind is running in broadcast mode, * we have to do the jugglery to get the * ypserv's address on COTS transport based * on the CLTS address ypbind gave us ! */ struct nd_hostservlist *nhs; if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf, &nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) { syslog(LOG_ERR, "yp_all: failed to get server's name\n"); __yp_rel_binding(pdomb); return (YPERR_RPC); } /* check server name again, some other thread may have set it */ (void) mutex_lock(&pdomb->server_name_lock); if (strcmp(pdomb->dom_binding->ypbind_servername, nullstring) == 0) { pdomb->dom_binding->ypbind_servername = (char *)strdup(nhs->h_hostservs->h_host); } (void) strcpy(server_name, pdomb->dom_binding->ypbind_servername); (void) mutex_unlock(&pdomb->server_name_lock); netdir_free((char *)nhs, ND_HOSTSERVLIST); } __yp_rel_binding(pdomb); if ((allc = clnt_create(server_name, YPPROG, YPVERS, "circuit_n")) == NULL) { (void) snprintf(errbuf, BUFSIZ, "yp_all \ - transport level create failure for domain %s / map %s", domain, map); syslog(LOG_ERR, "%s", clnt_spcreateerror(errbuf)); return (YPERR_RPC); }
/* * Called to read and interpret the event on a connectionless descriptor. * Returns 0 if successful, or a UNIX error code if failure. */ static int do_poll_clts_action(int fd, int conn_index) { int error; int ret; int flags; struct netconfig *nconf = &conn_polled[conn_index].nc; static struct t_unitdata *unitdata = NULL; static struct t_uderr *uderr = NULL; static int oldfd = -1; struct nd_hostservlist *host = NULL; struct strbuf ctl[1], data[1]; /* * We just need to have some space to consume the * message in the event we can't use the TLI interface to do the * job. * * We flush the message using getmsg(). For the control part * we allocate enough for any TPI header plus 32 bytes for address * and options. For the data part, there is nothing magic about * the size of the array, but 256 bytes is probably better than * 1 byte, and we don't expect any data portion anyway. * * If the array sizes are too small, we handle this because getmsg() * (called to consume the message) will return MOREDATA|MORECTL. * Thus we just call getmsg() until it's read the message. */ char ctlbuf[sizeof (union T_primitives) + 32]; char databuf[256]; /* * If this is the same descriptor as the last time * do_poll_clts_action was called, we can save some * de-allocation and allocation. */ if (oldfd != fd) { oldfd = fd; if (unitdata) { (void) t_free((char *)unitdata, T_UNITDATA); unitdata = NULL; } if (uderr) { (void) t_free((char *)uderr, T_UDERROR); uderr = NULL; } } /* * Allocate a unitdata structure for receiving the event. */ if (unitdata == NULL) { /* LINTED pointer alignment */ unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL); if (unitdata == NULL) { if (t_errno == TSYSERR) { /* * Save the error code across * syslog(), just in case * syslog() gets its own error * and therefore overwrites errno. */ error = errno; (void) syslog(LOG_ERR, "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m", fd, nconf->nc_proto); return (error); } (void) syslog(LOG_ERR, "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d", fd, nconf->nc_proto, t_errno); goto flush_it; } } try_again: flags = 0; /* * The idea is we wait for T_UNITDATA_IND's. Of course, * we don't get any, because rpcmod filters them out. * However, we need to call t_rcvudata() to let TLI * tell us we have a T_UDERROR_IND. * * algorithm is: * t_rcvudata(), expecting TLOOK. * t_look(), expecting T_UDERR. * t_rcvuderr(), expecting success (0). * expand destination address into ASCII, * and dump it. */ ret = t_rcvudata(fd, unitdata, &flags); if (ret == 0 || t_errno == TBUFOVFLW) { (void) syslog(LOG_WARNING, "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes", fd, nconf->nc_proto, unitdata->udata.len); /* * Even though we don't expect any data, in case we do, * keep reading until there is no more. */ if (flags & T_MORE) goto try_again; return (0); } switch (t_errno) { case TNODATA: return (0); case TSYSERR: /* * System errors are returned to caller. * Save the error code across * syslog(), just in case * syslog() gets its own error * and therefore overwrites errno. */ error = errno; (void) syslog(LOG_ERR, "t_rcvudata(file descriptor %d/transport %s) %m", fd, nconf->nc_proto); return (error); case TLOOK: break; default: (void) syslog(LOG_ERR, "t_rcvudata(file descriptor %d/transport %s) TLI error %d", fd, nconf->nc_proto, t_errno); goto flush_it; } ret = t_look(fd); switch (ret) { case 0: return (0); case -1: /* * System errors are returned to caller. */ if (t_errno == TSYSERR) { /* * Save the error code across * syslog(), just in case * syslog() gets its own error * and therefore overwrites errno. */ error = errno; (void) syslog(LOG_ERR, "t_look(file descriptor %d/transport %s) %m", fd, nconf->nc_proto); return (error); } (void) syslog(LOG_ERR, "t_look(file descriptor %d/transport %s) TLI error %d", fd, nconf->nc_proto, t_errno); goto flush_it; case T_UDERR: break; default: (void) syslog(LOG_WARNING, "t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)", fd, nconf->nc_proto, ret, T_UDERR); } if (uderr == NULL) { /* LINTED pointer alignment */ uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL); if (uderr == NULL) { if (t_errno == TSYSERR) { /* * Save the error code across * syslog(), just in case * syslog() gets its own error * and therefore overwrites errno. */ error = errno; (void) syslog(LOG_ERR, "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m", fd, nconf->nc_proto); return (error); } (void) syslog(LOG_ERR, "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d", fd, nconf->nc_proto, t_errno); goto flush_it; } } ret = t_rcvuderr(fd, uderr); if (ret == 0) { /* * Save the datagram error in errno, so that the * %m argument to syslog picks up the error string. */ errno = uderr->error; /* * Log the datagram error, then log the host that * probably triggerred. Cannot log both in the * same transaction because of packet size limitations * in /dev/log. */ (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, "NFS response over <file descriptor %d/transport %s> generated error: %m", fd, nconf->nc_proto); /* * Try to map the client's address back to a * name. */ ret = netdir_getbyaddr(nconf, &host, &uderr->addr); if (ret != -1 && host && host->h_cnt > 0 && host->h_hostservs) { (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, "Bad NFS response was sent to client with host name: %s; service port: %s", host->h_hostservs->h_host, host->h_hostservs->h_serv); } else { int i, j; char *buf; char *hex = "0123456789abcdef"; /* * Mapping failed, print the whole thing * in ASCII hex. */ buf = (char *)malloc(uderr->addr.len * 2 + 1); for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) { buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf]; buf[j+1] = hex[uderr->addr.buf[i] & 0xf]; } buf[j] = '\0'; (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, "Bad NFS response was sent to client with transport address: 0x%s", buf); free((void *)buf); } if (ret == 0 && host != NULL) netdir_free((void *)host, ND_HOSTSERVLIST); return (0); }
/* * The highest level interface for server creation. * Copied from svc_generic.c and cmd/keyserv/key_generic.c, but adapted * to work only for TPI_CLTS semantics, and to be called only once * from kwarnd.c. Returns 1 (interface created) on success and 0 * (no interfaces created) on failure. */ int svc_create_local_service(void (*dispatch) (), /* Dispatch function */ u_long prognum, /* Program number */ u_long versnum, /* Version number */ char *nettype, /* Networktype token */ char *servname) /* name of the srvc */ { int num = 0; SVCXPRT *xprt; struct netconfig *nconf; struct t_bind *bind_addr; void *net; int fd; struct nd_hostserv ns; struct nd_addrlist *nas; if ((net = __rpc_setconf(nettype)) == 0) { (void) syslog(LOG_ERR, gettext("svc_create: could not read netconfig database")); return (0); } while (nconf = __rpc_getconf(net)) { if ((strcmp(nconf->nc_protofmly, NC_LOOPBACK)) || (nconf->nc_semantics != NC_TPI_COTS_ORD)) continue; if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) { (void) syslog(LOG_ERR, gettext("svc_create: %s: cannot open connection: %s"), nconf->nc_netid, t_errlist[t_errno]); break; } /* * Negotiate for returning the uid of the caller. * This should be done before enabling the endpoint for * service via t_bind() (called in svc_tli_create()) * so that requests to kwarnd contain the uid. */ if (__rpc_negotiate_uid(fd) != 0) { syslog(LOG_ERR, gettext("Could not negotiate for" " uid with loopback transport %s"), nconf->nc_netid); t_close(fd); break; } /* LINTED pointer alignment */ bind_addr = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR); if ((bind_addr == NULL)) { (void) t_close(fd); (void) syslog(LOG_ERR, gettext("svc_create: t_alloc failed\n")); break; } ns.h_host = HOST_SELF; ns.h_serv = servname; if (!netdir_getbyname(nconf, &ns, &nas)) { /* Copy the address */ bind_addr->addr.len = nas->n_addrs->len; (void) memcpy(bind_addr->addr.buf, nas->n_addrs->buf, (int) nas->n_addrs->len); bind_addr->qlen = 8; netdir_free((char *) nas, ND_ADDRLIST); } else { (void) syslog(LOG_ERR, gettext("svc_create: no well known " "address for %s on %s\n"), servname, nconf->nc_netid); (void) t_free((char *) bind_addr, T_BIND); bind_addr = NULL; } xprt = svc_tli_create(fd, nconf, bind_addr, 0, 0); if (bind_addr) (void) t_free((char *) bind_addr, T_BIND); if (xprt == NULL) { (void) t_close(fd); (void) syslog(LOG_ERR, gettext("svc_create: svc_tli_create failed\n")); break; } else { (void) rpcb_unset(prognum, versnum, nconf); if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { (void) syslog(LOG_ERR, gettext("svc_create: cannot" " register %d vers %d on %s"), prognum, versnum, nconf->nc_netid); SVC_DESTROY(xprt); /* also t_closes fd */ break; } num = 1; break; } } __rpc_endconf(net); return (num); }
struct nd_hostservlist * _netdir_getbyaddr(struct netconfig *netconfigp, struct netbuf *netbufp) { char fulladdr[BUFSIZ]; /* a copy of the address string */ char servbuf[BUFSIZ]; /* a buffer for service string */ char hostbuf[BUFSIZ]; /* points to list of host names */ char *hostname; /* the "first" path of the string */ char *servname; /* the "second" part of string */ struct nd_hostservlist *retp; /* the return structure */ char *serv; /* resultant service name obtained */ int nhost; /* the number of hosts in hostpp */ struct nd_hostserv *nd_hostservp; /* traverses the host structures */ char *nexttok; /* next token to process */ /* * Separate the two parts of the address string. */ (void) strlcpy(fulladdr, netbufp->buf, sizeof (fulladdr)); hostname = strtok_r(fulladdr, ".", &nexttok); if (hostname == NULL) { _nderror = ND_NOHOST; return (NULL); } servname = strtok_r(NULL, " \n\t", &nexttok); /* * Search for all the hosts associated with the * first part of the address string. */ nhost = searchhost(netconfigp, hostname, FIELD1, hostbuf); if (nhost == 0) { _nderror = ND_NOHOST; return (NULL); } /* * Search for the service associated with the second * path of the address string. */ if (servname == NULL) { _nderror = ND_NOSERV; return (NULL); } servbuf[0] = '\0'; serv = servbuf; if (searchserv(netconfigp, servname, FIELD2, servbuf) == 0) { serv = _taddr2uaddr(netconfigp, netbufp); (void) strcpy(servbuf, serv); free(serv); serv = servbuf; while (*serv != '.') serv++; } /* * Allocate space to hold the return structure, set the number * of hosts, and allocate space to hold them. */ if ((retp = malloc(sizeof (struct nd_hostservlist))) == NULL) { _nderror = ND_NOMEM; return (NULL); } retp->h_cnt = nhost; retp->h_hostservs = calloc(nhost, sizeof (struct nd_hostserv)); if (retp->h_hostservs == NULL) { free(retp); _nderror = ND_NOMEM; return (NULL); } /* * Loop through the host structues and fill them in with * each host name (and service name). */ nd_hostservp = retp->h_hostservs; hostname = strtok_r(hostbuf, ",", &nexttok); while (hostname && nhost--) { if (((nd_hostservp->h_host = strdup(hostname)) == NULL) || ((nd_hostservp->h_serv = strdup(serv)) == NULL)) { netdir_free(retp, ND_HOSTSERVLIST); _nderror = ND_NOMEM; return (NULL); } nd_hostservp++; hostname = strtok_r(NULL, ",", &nexttok); } _nderror = ND_OK; return (retp); }
static void nfsauth_access(auth_req *argp, auth_res *result) { struct netconfig *nconf; struct nd_hostservlist *clnames = NULL; struct netbuf nbuf; struct share *sh; char tmp[MAXIPADDRLEN]; char *host = NULL; result->auth_perm = NFSAUTH_DENIED; /* * Convert the client's address to a hostname */ nconf = getnetconfigent(argp->req_netid); if (nconf == NULL) { syslog(LOG_ERR, "No netconfig entry for %s", argp->req_netid); return; } nbuf.len = argp->req_client.n_len; nbuf.buf = argp->req_client.n_bytes; if (netdir_getbyaddr(nconf, &clnames, &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); } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { struct sockaddr_in6 *sa; /* LINTED pointer */ sa = (struct sockaddr_in6 *)nbuf.buf; (void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr, tmp, INET6_ADDRSTRLEN); } clnames = anon_client(host); } /* * Now find the export */ sh = findentry(argp->req_path); if (sh == NULL) { syslog(LOG_ERR, "%s not exported", argp->req_path); goto done; } result->auth_perm = check_client(sh, &nbuf, clnames, argp->req_flavor); sharefree(sh); if (result->auth_perm == NFSAUTH_DENIED) { syslog(LOG_ERR, "%s denied access to %s", clnames->h_hostservs[0].h_host, argp->req_path); } done: freenetconfigent(nconf); if (clnames) netdir_free(clnames, ND_HOSTSERVLIST); }
int tcp_connect(const char *host, const char *serv) { int tfd, i; void *handle; struct t_call tcall; struct t_discon tdiscon; struct netconfig *ncp; struct nd_hostserv hs; struct nd_addrlist *alp; struct netbuf *np; struct t_opthdr *topt; handle = Setnetpath(); hs.h_host = (char *) host; hs.h_serv = (char *) serv; while ( (ncp = getnetpath(handle)) != NULL) { if (strcmp(ncp->nc_proto, "tcp") != 0) continue; if (netdir_getbyname(ncp, &hs, &alp) != 0) continue; /* try each server address */ for (i = 0, np = alp->n_addrs; i < alp->n_cnt; i++, np++) { tfd = T_open(ncp->nc_device, O_RDWR, NULL); T_bind(tfd, NULL, NULL); tcall.addr.len = np->len; tcall.addr.buf = np->buf; /* pointer copy */ tcall.opt.len = 0; /* no options */ tcall.udata.len = 0; /* no user data with connect */ if (t_connect(tfd, &tcall, NULL) == 0) { endnetpath(handle); /* success, connected to server */ netdir_free(alp, ND_ADDRLIST); req = T_alloc(fd, T_OPTMGMT, T_ALL); ret = T_alloc(fd, T_OPTMGMT, T_ALL); topt = (struct t_opthdr *) req->opt.buf; topt->level = T_INET_TCP; topt->name = T_TCP_MAXSEG; topt->len = sizeof(struct t_opthdr) + sizeof(u_long); req->opt.len = topt->len; topt = OPT_NEXTHDR(req->opt.buf, req->opt.maxlen, topt); topt->level = XTI_GENERIC; topt->name = XTI_SNDBUF; topt->len = sizeof(struct t_opthdr) + sizeof(u_long); req->opt.len += topt->len; return(tfd); } if (t_errno == TLOOK && t_look(tfd) == T_DISCONNECT) { t_rcvdis(tfd, &tdiscon); errno = tdiscon.reason; } t_close(tfd); } netdir_free(alp, ND_ADDRLIST); } endnetpath(handle); return(-1); }
/* * Check mount requests, add to mounted list if ok */ static void mount(struct svc_req *rqstp) { SVCXPRT *transp; int version, vers; struct fhstatus fhs; struct mountres3 mountres3; char fh[FHSIZE3]; int len = FHSIZE3; char *path, rpath[MAXPATHLEN]; struct share *sh = NULL; struct nd_hostservlist *clnames = NULL; char *host = NULL; int error = 0, lofs_tried = 0; int flavor_list[MAX_FLAVORS]; int flavor_count; struct netbuf *nb; transp = rqstp->rq_xprt; version = rqstp->rq_vers; path = NULL; if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { svcerr_decode(transp); return; } getclientsnames(transp, &nb, &clnames); if (clnames == NULL || nb == NULL) { /* * We failed to get a name for the client, even 'anon', * probably because we ran out of memory. In this situation * it doesn't make sense to allow the mount to succeed. */ error = EACCES; goto reply; } host = clnames->h_hostservs[0].h_host; /* * If the version being used is less than the minimum version, * the filehandle translation should not be provided to the * client. */ if (rejecting || version < mount_vers_min) { if (verbose) syslog(LOG_NOTICE, "Rejected mount: %s for %s", host, path); error = EACCES; goto reply; } /* * Trusted Extension doesn't support older versions of nfs(v2, v3). * To prevent circumventing TX label policy via using an older * version of nfs client, reject the mount request and log an * error. */ if (is_system_labeled()) { syslog(LOG_ERR, "mount rejected: Solaris TX only supports nfs4 clients"); error = EACCES; goto reply; } /* * Get the real path (no symbolic links in it) */ if (realpath(path, rpath) == NULL) { error = errno; if (verbose) syslog(LOG_ERR, "mount request: realpath: %s: %m", path); if (error == ENOENT) error = mount_enoent_error(path, rpath, clnames, nb, flavor_list); goto reply; } if ((sh = findentry(rpath)) == NULL && (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) { error = EACCES; goto reply; } /* * Check if this is a "nosub" only export, in which case, mounting * subdirectories isn't allowed. Bug 1184573. */ if (checkrootmount(sh, rpath) == 0) { error = EACCES; goto reply; } if (newopts(sh->sh_opts)) flavor_count = getclientsflavors_new(sh, nb, clnames, flavor_list); else flavor_count = getclientsflavors_old(sh, nb, clnames, flavor_list); if (flavor_count == 0) { error = EACCES; goto reply; } /* * Now get the filehandle. * * NFS V2 clients get a 32 byte filehandle. * NFS V3 clients get a 32 or 64 byte filehandle, depending on * the embedded FIDs. */ vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION; /* LINTED pointer alignment */ while (nfs_getfh(rpath, vers, &len, fh) < 0) { if (errno == EINVAL && (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) { errno = 0; continue; } error = errno == EINVAL ? EACCES : errno; syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m", path); break; } if (version == MOUNTVERS3) { mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len; mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh; } else { bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE); } reply: switch (version) { case MOUNTVERS: case MOUNTVERS_POSIX: if (error == EINVAL) fhs.fhs_status = NFSERR_ACCES; else if (error == EREMOTE) fhs.fhs_status = NFSERR_REMOTE; else fhs.fhs_status = error; if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs)) log_cant_reply(transp); audit_mountd_mount(host, path, fhs.fhs_status); /* BSM */ break; case MOUNTVERS3: if (!error) { mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = flavor_list; mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = flavor_count; } else if (error == ENAMETOOLONG) error = MNT3ERR_NAMETOOLONG; mountres3.fhs_status = error; if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3)) log_cant_reply(transp); audit_mountd_mount(host, path, mountres3.fhs_status); /* BSM */ break; } if (verbose) syslog(LOG_NOTICE, "MOUNT: %s %s %s", (host == NULL) ? "unknown host" : host, error ? "denied" : "mounted", path); if (path != NULL) svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); if (!error) mntlist_new(host, rpath); /* add entry to mount list */ done: if (sh) sharefree(sh); netdir_free(clnames, ND_HOSTSERVLIST); }
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); }
int nfslib_bindit(struct netconfig *nconf, struct netbuf **addr, struct nd_hostserv *hs, int backlog) { int fd; struct t_bind *ntb; struct t_bind tb; struct nd_addrlist *addrlist; struct t_optmgmt req, resp; struct opthdr *opt; char reqbuf[128]; bool_t use_any = FALSE; bool_t gzone = TRUE; if ((fd = nfslib_transport_open(nconf)) == -1) { syslog(LOG_ERR, "cannot establish transport service over %s", nconf->nc_device); return (-1); } addrlist = (struct nd_addrlist *)NULL; /* nfs4_callback service does not used a fieed port number */ if (strcmp(hs->h_serv, "nfs4_callback") == 0) { tb.addr.maxlen = 0; tb.addr.len = 0; tb.addr.buf = 0; use_any = TRUE; gzone = (getzoneid() == GLOBAL_ZONEID); } else if (netdir_getbyname(nconf, hs, &addrlist) != 0) { syslog(LOG_ERR, "Cannot get address for transport %s host %s service %s", nconf->nc_netid, hs->h_host, hs->h_serv); (void) t_close(fd); return (-1); } if (strcmp(nconf->nc_proto, "tcp") == 0) { /* * If we're running over TCP, then set the * SO_REUSEADDR option so that we can bind * to our preferred address even if previously * left connections exist in FIN_WAIT states. * This is somewhat bogus, but otherwise you have * to wait 2 minutes to restart after killing it. */ if (reuseaddr(fd) == -1) { syslog(LOG_WARNING, "couldn't set SO_REUSEADDR option on transport"); } } else if (strcmp(nconf->nc_proto, "udp") == 0) { /* * In order to run MLP on UDP, we need to handle creds. */ if (recvucred(fd) == -1) { syslog(LOG_WARNING, "couldn't set SO_RECVUCRED option on transport"); } } /* * Make non global zone nfs4_callback port MLP */ if (use_any && is_system_labeled() && !gzone) { if (anonmlp(fd) == -1) { /* * failing to set this option means nfs4_callback * could fail silently later. So fail it with * with an error message now. */ syslog(LOG_ERR, "couldn't set SO_ANON_MLP option on transport"); (void) t_close(fd); return (-1); } } if (nconf->nc_semantics == NC_TPI_CLTS) tb.qlen = 0; else tb.qlen = backlog; /* LINTED pointer alignment */ ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL); if (ntb == (struct t_bind *)NULL) { syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno); (void) t_close(fd); netdir_free((void *)addrlist, ND_ADDRLIST); return (-1); } /* * XXX - what about the space tb->addr.buf points to? This should * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,) * should't be called with T_ALL. */ if (addrlist) tb.addr = *(addrlist->n_addrs); /* structure copy */ if (t_bind(fd, &tb, ntb) == -1) { syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno); (void) t_free((char *)ntb, T_BIND); netdir_free((void *)addrlist, ND_ADDRLIST); (void) t_close(fd); return (-1); } /* make sure we bound to the right address */ if (use_any == FALSE && (tb.addr.len != ntb->addr.len || memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) { syslog(LOG_ERR, "t_bind to wrong address"); (void) t_free((char *)ntb, T_BIND); netdir_free((void *)addrlist, ND_ADDRLIST); (void) t_close(fd); return (-1); } /* * Call nfs4svc_setport so that the kernel can be * informed what port number the daemon is listing * for incoming connection requests. */ if ((nconf->nc_semantics == NC_TPI_COTS || nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL) (*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr); *addr = &ntb->addr; netdir_free((void *)addrlist, ND_ADDRLIST); if (strcmp(nconf->nc_proto, "tcp") == 0) { /* * Disable the Nagle algorithm on TCP connections. * Connections accepted from this listener will * inherit the listener options. */ /* LINTED pointer alignment */ opt = (struct opthdr *)reqbuf; opt->level = IPPROTO_TCP; opt->name = TCP_NODELAY; opt->len = sizeof (int); /* LINTED pointer alignment */ *(int *)((char *)opt + sizeof (*opt)) = 1; req.flags = T_NEGOTIATE; req.opt.len = sizeof (*opt) + opt->len; req.opt.buf = (char *)opt; resp.flags = 0; resp.opt.buf = reqbuf; resp.opt.maxlen = sizeof (reqbuf); if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { syslog(LOG_ERR, "couldn't set NODELAY option for proto %s: t_errno = %d, %m", nconf->nc_proto, t_errno); } nfslib_set_sockbuf(fd); } return (fd); }
/* * check for trusted host and user */ static int check_host( struct svc_req *rqstp /* RPC stuff */ ) { struct authsys_parms *sys_credp; SVCXPRT *transp = rqstp->rq_xprt; struct netconfig *nconfp = NULL; struct nd_hostservlist *hservlistp = NULL; int i; int rval = -1; char *inplace = NULL; /* check for root */ /*LINTED*/ sys_credp = (struct authsys_parms *)rqstp->rq_clntcred; assert(sys_credp != NULL); if (sys_credp->aup_uid != 0) goto out; /* get hostnames */ if (transp->xp_netid == NULL) { md_eprintf("transp->xp_netid == NULL\n"); goto out; } if ((nconfp = getnetconfigent(transp->xp_netid)) == NULL) { #ifdef DEBUG nc_perror("getnetconfigent(transp->xp_netid)"); #endif goto out; } if ((__netdir_getbyaddr_nosrv(nconfp, &hservlistp, &transp->xp_rtaddr) != 0) || (hservlistp == NULL)) { #ifdef DEBUG netdir_perror("netdir_getbyaddr(transp->xp_rtaddr)"); #endif goto out; } /* check hostnames */ for (i = 0; (i < hservlistp->h_cnt); ++i) { struct nd_hostserv *hservp = &hservlistp->h_hostservs[i]; char *hostname = hservp->h_host; inplace = strdup(hostname); /* localhost is OK */ if (strcmp(hostname, mynode()) == 0) { rval = 0; goto out; } /* check for remote root access */ if (ruserok(hostname, 1, "root", "root") == 0) { rval = 0; goto out; } sdssc_cm_nm2nid(inplace); if (strcmp(inplace, hostname)) { /* * If the names are now different it indicates * that hostname was converted to a nodeid. This * will only occur if hostname is part of the same * cluster that the current node is in. * If the machine is not running in a cluster than * sdssc_cm_nm2nid is a noop which leaves inplace * alone. */ rval = 0; goto out; } } /* cleanup, return success */ out: if (inplace) free(inplace); if (hservlistp != NULL) netdir_free(hservlistp, ND_HOSTSERVLIST); if (nconfp != NULL) Free(nconfp); return (rval); }