Example #1
0
/*
 * Returns NULL if there was some system error.
 * Returns "" if the address was not bound, i.e the server crashed.
 * Returns the merged address otherwise.
 */
char *
mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
{
	struct fdlist *fdl;
	char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL;

	for (fdl = fdhead; fdl; fdl = fdl->next)
		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
			break;
	if (fdl == NULL)
		return (NULL);
	if (check_bound(fdl, uaddr) == FALSE)
		/* that server died */
		return strdup(emptystring);
	/*
	 * If saddr is not NULL, the remote client may have included the
	 * address by which it contacted us.  Use that for the "client" uaddr,
	 * otherwise use the info from the SVCXPRT.
	 */
	if (saddr != NULL) {
		c_uaddr = saddr;
	} else {
		c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
		if (c_uaddr == NULL) {
			syslog(LOG_ERR, "taddr2uaddr failed for %s",
				fdl->nconf->nc_netid);
			return (NULL);
		}
		allocated_uaddr = c_uaddr;
	}

#ifdef RPCBIND_DEBUG
	if (debugging) {
		if (saddr == NULL) {
			fprintf(stderr, "mergeaddr: client uaddr = %s\n",
			    c_uaddr);
		} else {
			fprintf(stderr, "mergeaddr: contact uaddr = %s\n",
			    c_uaddr);
		}
	}
#endif
	s_uaddr = uaddr;
	/*
	 * This is all we should need for IP 4 and 6
	 */
	m_uaddr = addrmerge(svc_getrpccaller(xprt), s_uaddr, c_uaddr, netid);
#ifdef RPCBIND_DEBUG
	if (debugging)
		fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
				uaddr, m_uaddr);
#endif
	if (allocated_uaddr != NULL)
		free(allocated_uaddr);
	return (m_uaddr);
}
Example #2
0
int 
check_access(SVCXPRT *xprt, rpcproc_t proc, rpcprog_t prog, unsigned int rpcbvers)
{
	struct netbuf *caller = svc_getrpccaller(xprt);
	struct sockaddr *addr = (struct sockaddr *)caller->buf;
#ifdef LIBWRAP
	struct request_info req;
#endif

	/*
	 * The older PMAP_* equivalents have the same numbers, so
	 * they are accounted for here as well.
	 */
	switch (proc) {
	case RPCBPROC_SET:
	case RPCBPROC_UNSET:
		if (!insecure && !is_loopback(caller)) {
#ifdef RPCBIND_DEBUG
			  if (debugging)
			    fprintf(stderr, " declined (non-loopback sender) \n");
#endif
			if (verboselog)
				logit(log_severity, addr, proc, prog,
				    " declined (non-loopback sender)");
			return 0;
		}
		break;
	case RPCBPROC_GETADDR:
	case RPCBPROC_CALLIT:
	case RPCBPROC_INDIRECT:
	case RPCBPROC_DUMP:
	case RPCBPROC_GETTIME:
	case RPCBPROC_UADDR2TADDR:
	case RPCBPROC_TADDR2UADDR:
	case RPCBPROC_GETVERSADDR:
	case RPCBPROC_GETADDRLIST:
	case RPCBPROC_GETSTAT:
	default:
		break;
	}

#ifdef LIBWRAP
	if (addr->sa_family == AF_LOCAL)
		return 1;
	request_init(&req, RQ_DAEMON, "rpcbind", RQ_CLIENT_SIN, addr, 0);
	sock_methods(&req);
	if(!hosts_access(&req)) {

	  logit(deny_severity, addr, proc, prog, ": request from unauthorized host");
		return 0;
	}
#endif
	if (verboselog)
		logit(log_severity, addr, proc, prog, "");
    	return 1;
}
Example #3
0
/*
 * find the address of the caller of an RPC procedure.
 */
struct sockaddr_in *
amu_svc_getcaller(SVCXPRT *xprt)
{
  struct netbuf *nbp = (struct netbuf *) NULL;

  if ((nbp = svc_getrpccaller(xprt)) != NULL)
    return (struct sockaddr_in *) nbp->buf; /* all OK */

  return NULL;			/* failed */
}
Example #4
0
/*
 * 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);
}
Example #5
0
/*
 * NLM_UNSHARE, NLM4_UNSHARE
 *
 * Release a DOS-style share reservation
 */
void
nlm_do_unshare(nlm4_shareargs *argp, nlm4_shareres *resp, struct svc_req *sr)
{
	struct nlm_globals *g;
	struct nlm_host *host;
	struct netbuf *addr;
	vnode_t *vp = NULL;
	char *netid;
	int error;
	struct shrlock shr;

	nlm_copy_netobj(&resp->cookie, &argp->cookie);

	netid = svc_getnetid(sr->rq_xprt);
	addr = svc_getrpccaller(sr->rq_xprt);

	g = zone_getspecific(nlm_zone_key, curzone);
	host = nlm_host_find(g, netid, addr);
	if (host == NULL) {
		resp->stat = nlm4_denied_nolocks;
		return;
	}

	DTRACE_PROBE3(unshare__start, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_shareargs *, argp);

	if (NLM_IN_GRACE(g)) {
		resp->stat = nlm4_denied_grace_period;
		goto out;
	}

	vp = nlm_fh_to_vp(&argp->share.fh);
	if (vp == NULL) {
		resp->stat = nlm4_stale_fh;
		goto out;
	}

	/* Convert to local form. */
	nlm_init_shrlock(&shr, &argp->share, host);
	error = VOP_SHRLOCK(vp, F_UNSHARE, &shr,
	    FREAD | FWRITE, CRED(), NULL);

	(void) error;
	resp->stat = nlm4_granted;

out:
	DTRACE_PROBE3(unshare__end, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_shareres *, resp);

	if (vp != NULL)
		VN_RELE(vp);

	nlm_host_release(g, host);
}
Example #6
0
/*
 * Purpose:	Log name of function called and source address
 * Returns:	Nothing
 * Notes:	Extracts the source address from the transport handle
 *		passed in as part of the called procedure specification
 */
static void
log_from_addr(const char *fun_name, struct svc_req *req)
{
	struct sockaddr *addr;
	char hostname_buf[NI_MAXHOST];

	addr = svc_getrpccaller(req->rq_xprt)->buf;
	if (getnameinfo(addr , addr->sa_len, hostname_buf, sizeof hostname_buf,
	    NULL, 0, 0) != 0)
		return;

	syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
}
Example #7
0
void *
nlm_test_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
{
	nlm_testres res;
	static char dummy;
	struct sockaddr *addr;
	CLIENT *cli;
	int success;
	struct timeval timeo;
	struct nlm4_lock arg4;
	struct nlm4_holder *holder;

	nlmtonlm4(&arg->alock, &arg4);

	if (debug_level)
		log_from_addr("nlm_test_msg", rqstp);

	holder = testlock(&arg4, arg->exclusive, 0);

	res.cookie = arg->cookie;
	if (holder == NULL) {
		res.stat.stat = nlm_granted;
	} else {
		res.stat.stat = nlm_denied;
		memcpy(&res.stat.nlm_testrply_u.holder, holder,
		    sizeof(struct nlm_holder));
		res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
		res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
	}

	/*
	 * nlm_test has different result type to the other operations, so
	 * can't use transmit_result() in this case
	 */
	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
		timeo.tv_sec = 0; /* No timeout - not expecting response */
		timeo.tv_usec = 0;

		success = clnt_call(cli, NLM_TEST_RES,
		    (xdrproc_t)xdr_nlm_testres, &res,
		    (xdrproc_t)xdr_void, &dummy, timeo);

		if (debug_level > 2)
			syslog(LOG_DEBUG, "clnt_call returns %d", success);
	}
	return (NULL);
}
Example #8
0
/* ARGSUSED */
static void *
rpcbproc_getaddr_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
			 rpcvers_t rpcbversnum /*__unused*/)
{
	RPCB *regp = (RPCB *)arg;
#ifdef RPCBIND_DEBUG
	if (debugging) {
		char *uaddr;

		uaddr =	taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
			    svc_getrpccaller(transp));
		fprintf(stderr, "RPCB_GETADDR req for (%lu, %lu, %s) from %s: ",
		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
		    regp->r_netid, uaddr);
		free(uaddr);
	}
#endif
	return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4,
					RPCB_ALLVERS));
}
Example #9
0
static int
root_auth(SVCXPRT *trans, struct svc_req *rqstp)
{
	uid_t uid;
	struct sockaddr *remote;

	remote = svc_getrpccaller(trans)->buf;
	if (remote->sa_family != AF_UNIX) {
		if (debugging)
			fprintf(stderr, "client didn't use AF_UNIX\n");
		return (0);
	}

	if (__rpc_get_local_uid(trans, &uid) < 0) {
		if (debugging)
			fprintf(stderr, "__rpc_get_local_uid failed\n");
		return (0);
	}

	if (debugging)
		fprintf(stderr, "local_uid  %ld\n", uid);
	if (uid == 0)
		return (1);
	if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
		if (((uid_t) ((struct authunix_parms *)
			rqstp->rq_clntcred)->aup_uid)
			== uid) {
			return (1);
		} else {
			if (debugging)
				fprintf(stderr,
			"local_uid  %ld mismatches auth %ld\n", uid,
((uid_t) ((struct authunix_parms *)rqstp->rq_clntcred)->aup_uid));
			return (0);
		}
	} else {
		if (debugging)
			fprintf(stderr, "Not auth sys\n");
		return (0);
	}
}
Example #10
0
/*
 * Handles server to client callbacks.
 */
static void
nfscb_program(struct svc_req *rqst, SVCXPRT *xprt)
{
	struct nfsrv_descript nd;
	int cacherep, credflavor;

	memset(&nd, 0, sizeof(nd));
	if (rqst->rq_proc != NFSPROC_NULL &&
	    rqst->rq_proc != NFSV4PROC_CBCOMPOUND) {
		svcerr_noproc(rqst);
		svc_freereq(rqst);
		return;
	}
	nd.nd_procnum = rqst->rq_proc;
	nd.nd_flag = (ND_NFSCB | ND_NFSV4);

	/*
	 * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 -
	 * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP
	 * mounts.
	 */
	nd.nd_mrep = rqst->rq_args;
	rqst->rq_args = NULL;
	newnfs_realign(&nd.nd_mrep, M_WAITOK);
	nd.nd_md = nd.nd_mrep;
	nd.nd_dpos = mtod(nd.nd_md, caddr_t);
	nd.nd_nam = svc_getrpccaller(rqst);
	nd.nd_nam2 = rqst->rq_addr;
	nd.nd_mreq = NULL;
	nd.nd_cred = NULL;

	NFSCL_DEBUG(1, "cbproc=%d\n",nd.nd_procnum);
	if (nd.nd_procnum != NFSPROC_NULL) {
		if (!svc_getcred(rqst, &nd.nd_cred, &credflavor)) {
			svcerr_weakauth(rqst);
			svc_freereq(rqst);
			m_freem(nd.nd_mrep);
			return;
		}

		/* For now, I don't care what credential flavor was used. */
#ifdef notyet
#ifdef MAC
		mac_cred_associate_nfsd(nd.nd_cred);
#endif
#endif
		cacherep = nfs_cbproc(&nd, rqst->rq_xid);
	} else {
		NFSMGET(nd.nd_mreq);
		nd.nd_mreq->m_len = 0;
		cacherep = RC_REPLY;
	}
	if (nd.nd_mrep != NULL)
		m_freem(nd.nd_mrep);

	if (nd.nd_cred != NULL)
		crfree(nd.nd_cred);

	if (cacherep == RC_DROPIT) {
		if (nd.nd_mreq != NULL)
			m_freem(nd.nd_mreq);
		svc_freereq(rqst);
		return;
	}

	if (nd.nd_mreq == NULL) {
		svcerr_decode(rqst);
		svc_freereq(rqst);
		return;
	}

	if (nd.nd_repstat & NFSERR_AUTHERR) {
		svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR);
		if (nd.nd_mreq != NULL)
			m_freem(nd.nd_mreq);
	} else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq))
		svcerr_systemerr(rqst);
	else
		NFSCL_DEBUG(1, "cbrep sent\n");
	svc_freereq(rqst);
}
Example #11
0
/*
 * Check for special multihomed host cookie in the key.  If there,
 * collect the addresses from the comma separated list and return
 * the one that's nearest the client.
 */
static int
multihomed(struct ypreq_key req, struct ypresp_val *resp,
		SVCXPRT *xprt, DBM *fdb)
{
	char *cp, *bp;
	ulong_t bestaddr, call_addr;
	struct netbuf *nbuf;
	char name[PATH_MAX];
	static char localbuf[_PBLKSIZ];	/* buffer for multihomed IPv6 addr */

	if (strcmp(req.map, "hosts.byname") &&
			strcmp(req.map, "ipnodes.byname"))
		/* default status is YP_NOKEY */
		return (0);

	if (strncmp(req.keydat.dptr, "YP_MULTI_", 9)) {
		datum tmpname;

		strncpy(name, "YP_MULTI_", 9);
		strncpy(name + 9, req.keydat.dptr, req.keydat.dsize);
		tmpname.dsize = req.keydat.dsize + 9;
		tmpname.dptr = name;
		resp->valdat = dbm_fetch(fdb, tmpname);
	} else {
		/*
		 * Return whole line (for debugging) if YP_MULTI_hostnam
		 * is specified.
		 */
		resp->valdat = dbm_fetch(fdb, req.keydat);
		if (resp->valdat.dptr != NULL)
			return (1);
	}

	if (resp->valdat.dptr == NULL)
		return (0);

	strncpy(name, req.keydat.dptr, req.keydat.dsize);
	name[req.keydat.dsize] = NULL;

	if (strcmp(req.map, "ipnodes.byname") == 0) {
		/*
		 * This section handles multihomed IPv6 addresses.
		 * It returns all the IPv6 addresses one per line and only
		 * the requested hostname is returned.  NO aliases will be
		 * returned.  This is done exactly the same way DNS forwarding
		 * daemon handles multihomed hosts.
		 * New IPv6 enabled clients should be able to handle this
		 * information returned.  The sorting is also the client's
		 * responsibility.
		 */

		char *buf, *endbuf;

		if ((buf = strdup(resp->valdat.dptr)) == NULL) /* no memory */
			return (0);
		if ((bp = strtok(buf, " \t")) == NULL) { /* no address field */
			free(buf);
			return (0);
		}
		if ((cp = strtok(NULL, "")) == NULL) { /* no host field */
			free(buf);
			return (0);
		}
		if ((cp = strtok(bp, ",")) != NULL) { /* multihomed host */
			int bsize;

			localbuf[0] = '\0';
			bsize = sizeof (localbuf);
			endbuf = localbuf;

			while (cp) {
				if ((strlen(cp) + strlen(name)) >= bsize) {
					/* out of range */
					break;
				}
				sprintf(endbuf, "%s %s\n", cp, name);
				cp = strtok(NULL, ",");
				endbuf = &endbuf[strlen(endbuf)];
				bsize = &localbuf[sizeof (localbuf)] - endbuf;
			}
			resp->valdat.dptr = localbuf;
			resp->valdat.dsize = strlen(localbuf);
		}

		free(buf);
		/* remove trailing newline */
		if (resp->valdat.dsize &&
			resp->valdat.dptr[resp->valdat.dsize-1] == '\n') {
			resp->valdat.dptr[resp->valdat.dsize-1] = '\0';
			resp->valdat.dsize -= 1;
		}

		resp->status = YP_TRUE;
		return (1);
	}
	nbuf = svc_getrpccaller(xprt);
	/*
	 * OK, now I have a netbuf structure which I'm supposed to
	 * treat as opaque...  I hate transport independance!
	 * So, we're just gonna doit wrong...  By wrong I mean that
	 * we assume that the buf part of the netbuf structure is going
	 * to be a sockaddr_in.  We'll then check the assumed family
	 * member and hope that we find AF_INET in there...  if not
	 * then we can't continue.
	 */
	if (((struct sockaddr_in *)(nbuf->buf))->sin_family != AF_INET)
		return (0);

	call_addr = ((struct sockaddr_in *)(nbuf->buf))->sin_addr.s_addr;

	cp = resp->valdat.dptr;
	if ((bp = strtok(cp, " \t")) == NULL) /* no address field */
		return (0);
	if ((cp = strtok(NULL, "")) == NULL)  /* no host field */
		return (0);
	bp = strtok(bp, ",");

	bestaddr = inet_addr(bp);
	while (cp = strtok(NULL, ",")) {
		ulong_t taddr;

		taddr = inet_addr(cp);
		if (ntohl(call_addr ^ taddr) < ntohl(call_addr ^ bestaddr))
			bestaddr = taddr;
	}
	cp = resp->valdat.dptr;
	sprintf(cp, "%s %s", inet_ntoa(*(struct in_addr *)&bestaddr), name);
	resp->valdat.dsize = strlen(cp);

	resp->status = YP_TRUE;

	return (1);
}
Example #12
0
static int
omultihomed(struct yprequest req,
	    struct ypresponse *resp, SVCXPRT *xprt, DBM *fdb)
{
	char *cp, *bp;
	char name[PATH_MAX];
	struct netbuf *nbuf;
	ulong_t bestaddr, call_addr;

	if (strcmp(req.ypmatch_req_map, "hosts.byname"))
		return (0);

	if (strncmp(req.ypmatch_req_keyptr, "YP_MULTI_", 9)) {
		datum tmpname;

		strncpy(name, "YP_MULTI_", 9);
		strncpy(name + 9, req.ypmatch_req_keyptr,
			req.ypmatch_req_keysize);
		tmpname.dsize = req.ypmatch_req_keysize + 9;
		tmpname.dptr = name;
		resp->ypmatch_resp_valdat = dbm_fetch(fdb, tmpname);
	} else {
		resp->ypmatch_resp_valdat =
			dbm_fetch(fdb, req.ypmatch_req_keydat);
		if (resp->ypmatch_resp_valptr != NULL)
			return (1);
	}

	if (resp->ypmatch_resp_valptr == NULL)
		return (0);

	strncpy(name, req.ypmatch_req_keyptr, req.ypmatch_req_keysize);
	name[req.ypmatch_req_keysize] = NULL;

	nbuf = svc_getrpccaller(xprt);

	/*
	 * OK, now I have a netbuf structure which I'm supposed to treat
	 * as opaque...  I hate transport independance!  So, we're just
	 * gonna doit wrong...  By wrong I mean that we assume that the
	 * buf part of the netbuf structure is going to be a sockaddr_in.
	 * We'll then check the assumed family member and hope that we
	 * find AF_INET in there...  if not then we can't continue.
	 */
	if (((struct sockaddr_in *)(nbuf->buf))->sin_family != AF_INET)
		return (0);

	call_addr = ((struct sockaddr_in *)(nbuf->buf))->sin_addr.s_addr;

	cp = resp->ypmatch_resp_valptr;
	if ((bp = strtok(cp, "\t")) == NULL)	/* No address field */
		return (0);
	if ((cp = strtok(NULL, "")) == NULL)	/* No host field */
		return (0);
	bp = strtok(bp, ",");

	bestaddr = inet_addr(bp);
	while (cp = strtok(NULL, ",")) {
		ulong_t taddr;

		taddr = inet_addr(cp);
		if (ntohl(call_addr ^ taddr) < ntohl(call_addr ^ bestaddr))
			bestaddr = taddr;
	}

	cp = resp->ypmatch_resp_valptr;
	sprintf(cp, "%s %s", inet_ntoa(*(struct in_addr *)&bestaddr), name);
	resp->ypmatch_resp_valsize = strlen(cp);

	resp->ypmatch_resp_status = YP_TRUE;

	return (1);
}
Example #13
0
/*
 * This determines whether or not a passed domain is served by this
 * server, and returns a boolean.  Used by both old and new protocol
 * versions.
 */
void
ypdomain(SVCXPRT *transp, bool always_respond)
{
	char domain_name[YPMAXDOMAIN + 1];
	char *pdomain_name = domain_name;
	bool isserved;
	char *fun = "ypdomain";
	struct netbuf *nbuf;
	sa_family_t af;

	memset(domain_name, 0, sizeof (domain_name));

	if (!svc_getargs(transp, (xdrproc_t)xdr_ypdomain_wrap_string,
				(caddr_t)&pdomain_name)) {
		svcerr_decode(transp);
		return;
	}

	/*
	 * If the file /var/yp/securenets is present on the server, and if
	 * the hostname is present in the file, then let the client bind to
	 * the server.
	 */
	nbuf = svc_getrpccaller(transp);
	af = ((struct sockaddr_storage *)nbuf->buf)->ss_family;
	if (af != AF_INET && af != AF_INET6) {
		logprintf("Protocol incorrect\n");
		return;
	}

	if (!(check_secure_net_ti(nbuf, fun))) {
		MAP_ERR;
		return;
	}

	isserved = ypcheck_domain(domain_name);

	if (isserved || always_respond) {

		if (!svc_sendreply(transp, xdr_bool, (char *)&isserved)) {
		    RESPOND_ERR;
		}
		if (!isserved)
			logprintf("Domain %s not supported\n",
					domain_name);

	} else {
		/*
		 * This case is the one in which the domain is not
		 * supported, and in which we are not to respond in the
		 * unsupported case.  We are going to make an error happen
		 * to allow the portmapper to end his wait without the
		 * normal timeout period.  The assumption here is that
		 * the only process in the world which is using the function
		 * in its no-answer-if-nack form is the portmapper, which is
		 * doing the krock for pseudo-broadcast.  If some poor fool
		 * calls this function as a single-cast message, the nack
		 * case will look like an incomprehensible error.  Sigh...
		 * (The traditional Unix disclaimer)
		 */

		svcerr_decode(transp);
		logprintf("Domain %s not supported (broadcast)\n",
				domain_name);
	}
}
Example #14
0
int
check_callit(SVCXPRT *xprt, struct r_rmtcall_args *args, int versnum /*__unused*/)
{
	struct sockaddr *sa = (struct sockaddr *)svc_getrpccaller(xprt)->buf;

	/*
	 * Always allow calling NULLPROC
	 */
	if (args->rmt_proc == 0)
		return 1;

	/*
	 * XXX - this special casing sucks.
	 */
	switch (args->rmt_prog) {
	case RPCBPROG:
		/*
		 * Allow indirect calls to ourselves in insecure mode.
		 * The is_loopback checks aren't useful then anyway.
		 */
		if (!insecure)
			goto deny;
		break;
	case MOUNTPROG:
		if (args->rmt_proc != MOUNTPROC_MNT &&
		    args->rmt_proc != MOUNTPROC_UMNT)
			break;
		goto deny;
	case YPBINDPROG:
		if (args->rmt_proc != YPBINDPROC_SETDOM)
			break;
		/* FALLTHROUGH */
	case YPPASSWDPROG:
	case NFS_PROGRAM:
	case RQUOTAPROG:
		goto deny;
	case YPPROG:
		switch (args->rmt_proc) {
		case YPPROC_ALL:
		case YPPROC_MATCH:
		case YPPROC_FIRST:
		case YPPROC_NEXT:
			goto deny;
		default:
			break;
		}
	default:
		break;
	}

	return 1;
deny:
#ifdef LIBWRAP
	logit(deny_severity, sa, args->rmt_proc, args->rmt_prog,
	    ": indirect call not allowed");
#else
	logit(0, sa, args->rmt_proc, args->rmt_prog,
	    ": indirect call not allowed");
#endif
	return 0;
}
Example #15
0
/*
 * NLM_LOCK, NLM_LOCK_MSG, NLM_NM_LOCK
 * NLM4_LOCK, NLM4_LOCK_MSG, NLM4_NM_LOCK
 *
 * Client request to set a lock, possibly blocking.
 *
 * If the lock needs to block, we return status blocked to
 * this RPC call, and then later call back the client with
 * a "granted" callback.  Tricky aspects of this include:
 * sending a reply before this function returns, and then
 * borrowing this thread from the RPC service pool for the
 * wait on the lock and doing the later granted callback.
 *
 * We also have to keep a list of locks (pending + granted)
 * both to handle retransmitted requests, and to keep the
 * vnodes for those locks active.
 */
void
nlm_do_lock(nlm4_lockargs *argp, nlm4_res *resp, struct svc_req *sr,
    nlm_reply_cb reply_cb, nlm_res_cb res_cb, nlm_testargs_cb grant_cb)
{
	struct nlm_globals *g;
	struct flock64 fl;
	struct nlm_host *host = NULL;
	struct netbuf *addr;
	struct nlm_vhold *nvp = NULL;
	nlm_rpc_t *rpcp = NULL;
	char *netid;
	char *name;
	int error, flags;
	bool_t do_blocking = FALSE;
	bool_t do_mon_req = FALSE;
	enum nlm4_stats status;

	nlm_copy_netobj(&resp->cookie, &argp->cookie);

	name = argp->alock.caller_name;
	netid = svc_getnetid(sr->rq_xprt);
	addr = svc_getrpccaller(sr->rq_xprt);

	g = zone_getspecific(nlm_zone_key, curzone);
	host = nlm_host_findcreate(g, name, netid, addr);
	if (host == NULL) {
		DTRACE_PROBE4(no__host, struct nlm_globals *, g,
		    char *, name, char *, netid, struct netbuf *, addr);
		status = nlm4_denied_nolocks;
		goto doreply;
	}

	DTRACE_PROBE3(start, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_lockargs *, argp);

	/*
	 * If we may need to do _msg_ call needing an RPC
	 * callback, get the RPC client handle now,
	 * so we know if we can bind to the NLM service on
	 * this client.
	 *
	 * Note: host object carries transport type.
	 * One client using multiple transports gets
	 * separate sysids for each of its transports.
	 */
	if (res_cb != NULL || (grant_cb != NULL && argp->block == TRUE)) {
		error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
		if (error != 0) {
			status = nlm4_denied_nolocks;
			goto doreply;
		}
	}

	/*
	 * During the "grace period", only allow reclaim.
	 */
	if (argp->reclaim == 0 && NLM_IN_GRACE(g)) {
		status = nlm4_denied_grace_period;
		goto doreply;
	}

	/*
	 * Check whether we missed host shutdown event
	 */
	if (nlm_host_get_state(host) != argp->state)
		nlm_host_notify_server(host, argp->state);

	/*
	 * Get a hold on the vnode for a lock operation.
	 * Only lock() and share() need vhold objects.
	 */
	nvp = nlm_fh_to_vhold(host, &argp->alock.fh);
	if (nvp == NULL) {
		status = nlm4_stale_fh;
		goto doreply;
	}

	/* Convert to local form. */
	error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers,
	    (argp->exclusive) ? F_WRLCK : F_RDLCK);
	if (error) {
		status = nlm4_failed;
		goto doreply;
	}

	/*
	 * Try to lock non-blocking first.  If we succeed
	 * getting the lock, we can reply with the granted
	 * status directly and avoid the complications of
	 * making the "granted" RPC callback later.
	 *
	 * This also let's us find out now about some
	 * possible errors like EROFS, etc.
	 */
	flags = F_REMOTELOCK | FREAD | FWRITE;
	error = nlm_vop_frlock(nvp->nv_vp, F_SETLK, &fl, flags,
	    (u_offset_t)0, NULL, CRED(), NULL);

	DTRACE_PROBE3(setlk__res, struct flock64 *, &fl,
	    int, flags, int, error);

	switch (error) {
	case 0:
		/* Got it without waiting! */
		status = nlm4_granted;
		do_mon_req = TRUE;
		break;

	/* EINPROGRESS too? */
	case EAGAIN:
		/* We did not get the lock. Should we block? */
		if (argp->block == FALSE || grant_cb == NULL) {
			status = nlm4_denied;
			break;
		}
		/*
		 * Should block.  Try to reserve this thread
		 * so we can use it to wait for the lock and
		 * later send the granted message.  If this
		 * reservation fails, say "no resources".
		 */
		if (!svc_reserve_thread(sr->rq_xprt)) {
			status = nlm4_denied_nolocks;
			break;
		}
		/*
		 * OK, can detach this thread, so this call
		 * will block below (after we reply).
		 */
		status = nlm4_blocked;
		do_blocking = TRUE;
		do_mon_req = TRUE;
		break;

	case ENOLCK:
		/* Failed for lack of resources. */
		status = nlm4_denied_nolocks;
		break;

	case EROFS:
		/* read-only file system */
		status = nlm4_rofs;
		break;

	case EFBIG:
		/* file too big */
		status = nlm4_fbig;
		break;

	case EDEADLK:
		/* dead lock condition */
		status = nlm4_deadlck;
		break;

	default:
		status = nlm4_denied;
		break;
	}

doreply:
	resp->stat.stat = status;

	/*
	 * We get one of two function pointers; one for a
	 * normal RPC reply, and another for doing an RPC
	 * "callback" _res reply for a _msg function.
	 * Use either of those to send the reply now.
	 *
	 * If sending this reply fails, just leave the
	 * lock in the list for retransmitted requests.
	 * Cleanup is via unlock or host rele (statmon).
	 */
	if (reply_cb != NULL) {
		/* i.e. nlm_lock_1_reply */
		if (!(*reply_cb)(sr->rq_xprt, resp))
			svcerr_systemerr(sr->rq_xprt);
	}
	if (res_cb != NULL && rpcp != NULL)
		NLM_INVOKE_CALLBACK("lock", rpcp, resp, res_cb);

	/*
	 * The reply has been sent to the client.
	 * Start monitoring this client (maybe).
	 *
	 * Note that the non-monitored (NM) calls pass grant_cb=NULL
	 * indicating that the client doesn't support RPC callbacks.
	 * No monitoring for these (lame) clients.
	 */
	if (do_mon_req && grant_cb != NULL)
		nlm_host_monitor(g, host, argp->state);

	if (do_blocking) {
		/*
		 * We need to block on this lock, and when that
		 * completes, do the granted RPC call. Note that
		 * we "reserved" this thread above, so we can now
		 * "detach" it from the RPC SVC pool, allowing it
		 * to block indefinitely if needed.
		 */
		ASSERT(rpcp != NULL);
		(void) svc_detach_thread(sr->rq_xprt);
		nlm_block(argp, host, nvp, rpcp, &fl, grant_cb);
	}

	DTRACE_PROBE3(lock__end, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_res *, resp);

	if (rpcp != NULL)
		nlm_host_rele_rpc(host, rpcp);

	nlm_vhold_release(host, nvp);
	nlm_host_release(g, host);
}
Example #16
0
/*
 * NLM_TEST, NLM_TEST_MSG,
 * NLM4_TEST, NLM4_TEST_MSG,
 * Client inquiry about locks, non-blocking.
 */
void
nlm_do_test(nlm4_testargs *argp, nlm4_testres *resp,
    struct svc_req *sr, nlm_testres_cb cb)
{
	struct nlm_globals *g;
	struct nlm_host *host;
	struct nlm4_holder *lh;
	struct nlm_owner_handle *oh;
	nlm_rpc_t *rpcp = NULL;
	vnode_t *vp = NULL;
	struct netbuf *addr;
	char *netid;
	char *name;
	int error;
	struct flock64 fl;

	nlm_copy_netobj(&resp->cookie, &argp->cookie);

	name = argp->alock.caller_name;
	netid = svc_getnetid(sr->rq_xprt);
	addr = svc_getrpccaller(sr->rq_xprt);

	g = zone_getspecific(nlm_zone_key, curzone);
	host = nlm_host_findcreate(g, name, netid, addr);
	if (host == NULL) {
		resp->stat.stat = nlm4_denied_nolocks;
		return;
	}
	if (cb != NULL) {
		error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
		if (error != 0) {
			resp->stat.stat = nlm4_denied_nolocks;
			goto out;
		}
	}

	vp = nlm_fh_to_vp(&argp->alock.fh);
	if (vp == NULL) {
		resp->stat.stat = nlm4_stale_fh;
		goto out;
	}

	if (NLM_IN_GRACE(g)) {
		resp->stat.stat = nlm4_denied_grace_period;
		goto out;
	}

	/* Convert to local form. */
	error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers,
	    (argp->exclusive) ? F_WRLCK : F_RDLCK);
	if (error) {
		resp->stat.stat = nlm4_failed;
		goto out;
	}

	/* BSD: VOP_ADVLOCK(nv->nv_vp, NULL, F_GETLK, &fl, F_REMOTE); */
	error = nlm_vop_frlock(vp, F_GETLK, &fl,
	    F_REMOTELOCK | FREAD | FWRITE,
	    (u_offset_t)0, NULL, CRED(), NULL);
	if (error) {
		resp->stat.stat = nlm4_failed;
		goto out;
	}

	if (fl.l_type == F_UNLCK) {
		resp->stat.stat = nlm4_granted;
		goto out;
	}
	resp->stat.stat = nlm4_denied;

	/*
	 * This lock "test" fails due to a conflicting lock.
	 *
	 * If this is a v1 client, make sure the conflicting
	 * lock range we report can be expressed with 32-bit
	 * offsets.  The lock range requested was expressed
	 * as 32-bit offset and length, so at least part of
	 * the conflicting lock should lie below MAX_UOFF32.
	 * If the conflicting lock extends past that, we'll
	 * trim the range to end at MAX_UOFF32 so this lock
	 * can be represented in a 32-bit response.  Check
	 * the start also (paranoid, but a low cost check).
	 */
	if (sr->rq_vers < NLM4_VERS) {
		uint64 maxlen;
		if (fl.l_start > MAX_UOFF32)
			fl.l_start = MAX_UOFF32;
		maxlen = MAX_UOFF32 + 1 - fl.l_start;
		if (fl.l_len > maxlen)
			fl.l_len = maxlen;
	}

	/*
	 * Build the nlm4_holder result structure.
	 *
	 * Note that lh->oh is freed via xdr_free,
	 * xdr_nlm4_holder, xdr_netobj, xdr_bytes.
	 */
	oh = kmem_zalloc(sizeof (*oh), KM_SLEEP);
	oh->oh_sysid = (sysid_t)fl.l_sysid;
	lh = &resp->stat.nlm4_testrply_u.holder;
	lh->exclusive = (fl.l_type == F_WRLCK);
	lh->svid = fl.l_pid;
	lh->oh.n_len = sizeof (*oh);
	lh->oh.n_bytes = (void *)oh;
	lh->l_offset = fl.l_start;
	lh->l_len = fl.l_len;

out:
	/*
	 * If we have a callback function, use that to
	 * deliver the response via another RPC call.
	 */
	if (cb != NULL && rpcp != NULL)
		NLM_INVOKE_CALLBACK("test", rpcp, resp, cb);

	if (vp != NULL)
		VN_RELE(vp);
	if (rpcp != NULL)
		nlm_host_rele_rpc(host, rpcp);

	nlm_host_release(g, host);
}
Example #17
0
/*
 * NLM_SHARE, NLM4_SHARE
 *
 * Request a DOS-style share reservation
 */
void
nlm_do_share(nlm4_shareargs *argp, nlm4_shareres *resp, struct svc_req *sr)
{
	struct nlm_globals *g;
	struct nlm_host *host;
	struct netbuf *addr;
	struct nlm_vhold *nvp = NULL;
	char *netid;
	char *name;
	int error;
	struct shrlock shr;

	nlm_copy_netobj(&resp->cookie, &argp->cookie);

	name = argp->share.caller_name;
	netid = svc_getnetid(sr->rq_xprt);
	addr = svc_getrpccaller(sr->rq_xprt);

	g = zone_getspecific(nlm_zone_key, curzone);
	host = nlm_host_findcreate(g, name, netid, addr);
	if (host == NULL) {
		resp->stat = nlm4_denied_nolocks;
		return;
	}

	DTRACE_PROBE3(share__start, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_shareargs *, argp);

	if (argp->reclaim == 0 && NLM_IN_GRACE(g)) {
		resp->stat = nlm4_denied_grace_period;
		goto out;
	}

	/*
	 * Get holded vnode when on lock operation.
	 * Only lock() and share() need vhold objects.
	 */
	nvp = nlm_fh_to_vhold(host, &argp->share.fh);
	if (nvp == NULL) {
		resp->stat = nlm4_stale_fh;
		goto out;
	}

	/* Convert to local form. */
	nlm_init_shrlock(&shr, &argp->share, host);
	error = VOP_SHRLOCK(nvp->nv_vp, F_SHARE, &shr,
	    FREAD | FWRITE, CRED(), NULL);

	if (error == 0) {
		resp->stat = nlm4_granted;
		nlm_host_monitor(g, host, 0);
	} else {
		resp->stat = nlm4_denied;
	}

out:
	DTRACE_PROBE3(share__end, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_shareres *, resp);

	nlm_vhold_release(host, nvp);
	nlm_host_release(g, host);
}
Example #18
0
static void
nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
{
	struct nfsrv_descript nd;
	struct nfsrvcache *rp = NULL;
	int cacherep, credflavor;

	memset(&nd, 0, sizeof(nd));
	if (rqst->rq_vers == NFS_VER2) {
		if (rqst->rq_proc > NFSV2PROC_STATFS) {
			svcerr_noproc(rqst);
			svc_freereq(rqst);
			goto out;
		}
		nd.nd_procnum = newnfs_nfsv3_procid[rqst->rq_proc];
		nd.nd_flag = ND_NFSV2;
	} else if (rqst->rq_vers == NFS_VER3) {
		if (rqst->rq_proc >= NFS_V3NPROCS) {
			svcerr_noproc(rqst);
			svc_freereq(rqst);
			goto out;
		}
		nd.nd_procnum = rqst->rq_proc;
		nd.nd_flag = ND_NFSV3;
	} else {
		if (rqst->rq_proc != NFSPROC_NULL &&
		    rqst->rq_proc != NFSV4PROC_COMPOUND) {
			svcerr_noproc(rqst);
			svc_freereq(rqst);
			goto out;
		}
		nd.nd_procnum = rqst->rq_proc;
		nd.nd_flag = ND_NFSV4;
	}

	/*
	 * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 -
	 * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP
	 * mounts.
	 */
	nd.nd_mrep = rqst->rq_args;
	rqst->rq_args = NULL;
	newnfs_realign(&nd.nd_mrep, M_WAITOK);
	nd.nd_md = nd.nd_mrep;
	nd.nd_dpos = mtod(nd.nd_md, caddr_t);
	nd.nd_nam = svc_getrpccaller(rqst);
	nd.nd_nam2 = rqst->rq_addr;
	nd.nd_mreq = NULL;
	nd.nd_cred = NULL;

	if (nfs_privport && (nd.nd_flag & ND_NFSV4) == 0) {
		/* Check if source port is privileged */
		u_short port;
		struct sockaddr *nam = nd.nd_nam;
		struct sockaddr_in *sin;

		sin = (struct sockaddr_in *)nam;
		/*
		 * INET/INET6 - same code:
		 *    sin_port and sin6_port are at same offset
		 */
		port = ntohs(sin->sin_port);
		if (port >= IPPORT_RESERVED &&
		    nd.nd_procnum != NFSPROC_NULL) {
#ifdef INET6
			char b6[INET6_ADDRSTRLEN];
#if defined(KLD_MODULE)
			/* Do not use ip6_sprintf: the nfs module should work without INET6. */
#define	ip6_sprintf(buf, a)						\
			(sprintf((buf), "%x:%x:%x:%x:%x:%x:%x:%x",	\
			    (a)->s6_addr16[0], (a)->s6_addr16[1],	\
			    (a)->s6_addr16[2], (a)->s6_addr16[3],	\
			    (a)->s6_addr16[4], (a)->s6_addr16[5],	\
			    (a)->s6_addr16[6], (a)->s6_addr16[7]),	\
			    (buf))
#endif
#endif
			printf("NFS request from unprivileged port (%s:%d)\n",
#ifdef INET6
			    sin->sin_family == AF_INET6 ?
			    ip6_sprintf(b6, &satosin6(sin)->sin6_addr) :
#if defined(KLD_MODULE)
#undef ip6_sprintf
#endif
#endif
			    inet_ntoa(sin->sin_addr), port);
			svcerr_weakauth(rqst);
			svc_freereq(rqst);
			m_freem(nd.nd_mrep);
			goto out;
		}
	}

	if (nd.nd_procnum != NFSPROC_NULL) {
		if (!svc_getcred(rqst, &nd.nd_cred, &credflavor)) {
			svcerr_weakauth(rqst);
			svc_freereq(rqst);
			m_freem(nd.nd_mrep);
			goto out;
		}

		/* Set the flag based on credflavor */
		if (credflavor == RPCSEC_GSS_KRB5) {
			nd.nd_flag |= ND_GSS;
		} else if (credflavor == RPCSEC_GSS_KRB5I) {
			nd.nd_flag |= (ND_GSS | ND_GSSINTEGRITY);
		} else if (credflavor == RPCSEC_GSS_KRB5P) {
			nd.nd_flag |= (ND_GSS | ND_GSSPRIVACY);
		} else if (credflavor != AUTH_SYS) {
			svcerr_weakauth(rqst);
			svc_freereq(rqst);
			m_freem(nd.nd_mrep);
			goto out;
		}

#ifdef MAC
		mac_cred_associate_nfsd(nd.nd_cred);
#endif
		/*
		 * Get a refcnt (shared lock) on nfsd_suspend_lock.
		 * NFSSVC_SUSPENDNFSD will take an exclusive lock on
		 * nfsd_suspend_lock to suspend these threads.
		 * This must be done here, before the check of
		 * nfsv4root exports by nfsvno_v4rootexport().
		 */
		NFSLOCKV4ROOTMUTEX();
		nfsv4_getref(&nfsd_suspend_lock, NULL, NFSV4ROOTLOCKMUTEXPTR,
		    NULL);
		NFSUNLOCKV4ROOTMUTEX();

		if ((nd.nd_flag & ND_NFSV4) != 0) {
			nd.nd_repstat = nfsvno_v4rootexport(&nd);
			if (nd.nd_repstat != 0) {
				NFSLOCKV4ROOTMUTEX();
				nfsv4_relref(&nfsd_suspend_lock);
				NFSUNLOCKV4ROOTMUTEX();
				svcerr_weakauth(rqst);
				svc_freereq(rqst);
				m_freem(nd.nd_mrep);
				goto out;
			}
		}

		cacherep = nfs_proc(&nd, rqst->rq_xid, xprt, &rp);
		NFSLOCKV4ROOTMUTEX();
		nfsv4_relref(&nfsd_suspend_lock);
		NFSUNLOCKV4ROOTMUTEX();
	} else {
		NFSMGET(nd.nd_mreq);
		nd.nd_mreq->m_len = 0;
		cacherep = RC_REPLY;
	}
	if (nd.nd_mrep != NULL)
		m_freem(nd.nd_mrep);

	if (nd.nd_cred != NULL)
		crfree(nd.nd_cred);

	if (cacherep == RC_DROPIT) {
		if (nd.nd_mreq != NULL)
			m_freem(nd.nd_mreq);
		svc_freereq(rqst);
		goto out;
	}

	if (nd.nd_mreq == NULL) {
		svcerr_decode(rqst);
		svc_freereq(rqst);
		goto out;
	}

	if (nd.nd_repstat & NFSERR_AUTHERR) {
		svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR);
		if (nd.nd_mreq != NULL)
			m_freem(nd.nd_mreq);
	} else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq)) {
		svcerr_systemerr(rqst);
	}
	if (rp != NULL) {
		nfsrvd_sentcache(rp, (rqst->rq_reply_seq != 0 ||
		    SVC_ACK(xprt, NULL)), rqst->rq_reply_seq);
	}
	svc_freereq(rqst);

out:
	NFSEXITCODE(0);
}
Example #19
0
int resolv_req(bool *fwding, CLIENT **client, int *pid, char *tp,
		SVCXPRT *xprt, struct ypreq_key *req, char *map)
{
	enum clnt_stat stat;
	struct timeval tv;
	struct ypfwdreq_key4 fwd_req4;
	struct ypfwdreq_key6 fwd_req6;
	struct in6_addr in6;
	int byname, byaddr;
	int byname_v6, byaddr_v6;
#ifdef TDRPC
	struct sockaddr_in *addrp;
#else
	struct netbuf *nb;
	char *uaddr;
	char *cp;
	int i;
	sa_family_t caller_af = AF_UNSPEC;
	struct sockaddr_in *sin4;
	struct sockaddr_in6 *sin6;
#endif


	if (! *fwding)
		return (FALSE);

	byname = strcmp(map, "hosts.byname") == 0;
	byaddr = strcmp(map, "hosts.byaddr") == 0;
	byname_v6 = strcmp(map, "ipnodes.byname") == 0;
	byaddr_v6 = strcmp(map, "ipnodes.byaddr") == 0;
	if ((!byname && !byaddr && !byname_v6 && !byaddr_v6) ||
				req->keydat.dsize == 0 ||
				req->keydat.dptr[0] == '\0' ||
				!isascii(req->keydat.dptr[0]) ||
				!isgraph(req->keydat.dptr[0])) {
		/* default status is YP_NOKEY */
		return (FALSE);
	}

#ifdef TDRPC
	fwd_req4.map = map;
	fwd_req4.keydat = req->keydat;
	fwd_req4.xid = svc_getxid(xprt);
	addrp = svc_getcaller(xprt);
	fwd_req4.ip = addrp->sin_addr.s_addr;
	fwd_req4.port = addrp->sin_port;
#else
	/*
	 * In order to tell if we have an IPv4 or IPv6 caller address,
	 * we must know that nb->buf is a (sockaddr_in *) or a
	 * (sockaddr_in6 *). Hence, we might as well dispense with the
	 * conversion to uaddr and parsing of same that this section
	 * of the code previously involved itself in.
	 */
	nb = svc_getrpccaller(xprt);
	if (nb != 0)
		caller_af = ((struct sockaddr_storage *)nb->buf)->ss_family;

	if (caller_af == AF_INET6) {
		fwd_req6.map = map;
		fwd_req6.keydat = req->keydat;
		fwd_req6.xid = svc_getxid(xprt);
		sin6 = (struct sockaddr_in6 *)nb->buf;
		fwd_req6.addr = (uint32_t *)&in6;
		memcpy(fwd_req6.addr, sin6->sin6_addr.s6_addr, sizeof (in6));
		fwd_req6.port = ntohs(sin6->sin6_port);
	} else if (caller_af == AF_INET) {
		fwd_req4.map = map;
		fwd_req4.keydat = req->keydat;
		fwd_req4.xid = svc_getxid(xprt);
		sin4 = (struct sockaddr_in *)nb->buf;
		fwd_req4.ip = ntohl(sin4->sin_addr.s_addr);
		fwd_req4.port = ntohs(sin4->sin_port);
	} else {
		syslog(LOG_ERR, "unknown caller IP address family %d",
			caller_af);
		return (FALSE);
	}
#endif

	/* Restart resolver if it died. (possible overkill) */
	if (kill(*pid, 0)) {
		syslog(LOG_INFO,
		"Restarting resolv server: old one (pid %d) died.\n", *pid);
		if (*client != NULL)
			clnt_destroy (*client);
		setup_resolv(fwding, pid, client, tp, 0 /* transient p# */);
		if (!*fwding) {
			syslog(LOG_ERR,
			"can't restart resolver: ending resolv service.\n");
			return (FALSE);
		}
	}

	/* may need to up timeout */
	tv.tv_sec = 10; tv.tv_usec = 0;
	if (caller_af == AF_INET6) {
		stat = clnt_call(*client, YPDNSPROC6, xdr_ypfwdreq_key6,
					(char *)&fwd_req6, xdr_void, 0, tv);
	} else {
		stat = clnt_call(*client, YPDNSPROC4, xdr_ypfwdreq_key4,
					(char *)&fwd_req4, xdr_void, 0, tv);
	}
	if (stat == RPC_SUCCESS) /* expected */
		return (TRUE);

	else { /* Over kill error recovery */
		/* make one attempt to restart service before turning off */
		syslog(LOG_INFO,
			"Restarting resolv server: old one not responding.\n");

		if (!kill(*pid, 0))
			kill (*pid, SIGINT); /* cleanup old one */

		if (*client != NULL)
			clnt_destroy (*client);
		setup_resolv(fwding, pid, client, tp, 0 /* transient p# */);
		if (!*fwding) {
			syslog(LOG_ERR,
			"can't restart resolver: ending resolv service.\n");
			return (FALSE);
		}

		if (caller_af == AF_INET6) {
			stat = clnt_call(*client, YPDNSPROC6, xdr_ypfwdreq_key6,
					(char *)&fwd_req6, xdr_void, 0, tv);
		} else {
			stat = clnt_call(*client, YPDNSPROC4, xdr_ypfwdreq_key4,
					(char *)&fwd_req4, xdr_void, 0, tv);
		}
		if (stat == RPC_SUCCESS) /* expected */
			return (TRUE);
		else {
			/* no more restarts */
			clnt_destroy (*client);
			*fwding = FALSE; /* turn off fwd'ing */
			syslog(LOG_ERR,
		"restarted resolver not responding: ending resolv service.\n");
			return (FALSE);
		}
	}
}
Example #20
0
/*
 * NLM_UNLOCK, NLM_UNLOCK_MSG,
 * NLM4_UNLOCK, NLM4_UNLOCK_MSG,
 * Client removes one of their locks.
 */
void
nlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *resp,
    struct svc_req *sr, nlm_res_cb cb)
{
	struct nlm_globals *g;
	struct nlm_host *host;
	struct netbuf *addr;
	nlm_rpc_t *rpcp = NULL;
	vnode_t *vp = NULL;
	char *netid;
	char *name;
	int error;
	struct flock64 fl;

	nlm_copy_netobj(&resp->cookie, &argp->cookie);

	netid = svc_getnetid(sr->rq_xprt);
	addr = svc_getrpccaller(sr->rq_xprt);
	name = argp->alock.caller_name;

	/*
	 * NLM_UNLOCK operation doesn't have an error code
	 * denoting that operation failed, so we always
	 * return nlm4_granted except when the server is
	 * in a grace period.
	 */
	resp->stat.stat = nlm4_granted;

	g = zone_getspecific(nlm_zone_key, curzone);
	host = nlm_host_findcreate(g, name, netid, addr);
	if (host == NULL)
		return;

	if (cb != NULL) {
		error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
		if (error != 0)
			goto out;
	}

	DTRACE_PROBE3(start, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_unlockargs *, argp);

	if (NLM_IN_GRACE(g)) {
		resp->stat.stat = nlm4_denied_grace_period;
		goto out;
	}

	vp = nlm_fh_to_vp(&argp->alock.fh);
	if (vp == NULL)
		goto out;

	/* Convert to local form. */
	error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers, F_UNLCK);
	if (error)
		goto out;

	/* BSD: VOP_ADVLOCK(nv->nv_vp, NULL, F_UNLCK, &fl, F_REMOTE); */
	error = nlm_vop_frlock(vp, F_SETLK, &fl,
	    F_REMOTELOCK | FREAD | FWRITE,
	    (u_offset_t)0, NULL, CRED(), NULL);

	DTRACE_PROBE1(unlock__res, int, error);
out:
	/*
	 * If we have a callback function, use that to
	 * deliver the response via another RPC call.
	 */
	if (cb != NULL && rpcp != NULL)
		NLM_INVOKE_CALLBACK("unlock", rpcp, resp, cb);

	DTRACE_PROBE3(unlock__end, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_res *, resp);

	if (vp != NULL)
		VN_RELE(vp);
	if (rpcp != NULL)
		nlm_host_rele_rpc(host, rpcp);

	nlm_host_release(g, host);
}
Example #21
0
/*
 * NLM_CANCEL, NLM_CANCEL_MSG,
 * NLM4_CANCEL, NLM4_CANCEL_MSG,
 * Client gives up waiting for a blocking lock.
 */
void
nlm_do_cancel(nlm4_cancargs *argp, nlm4_res *resp,
    struct svc_req *sr, nlm_res_cb cb)
{
	struct nlm_globals *g;
	struct nlm_host *host;
	struct netbuf *addr;
	struct nlm_vhold *nvp = NULL;
	nlm_rpc_t *rpcp = NULL;
	char *netid;
	char *name;
	int error;
	struct flock64 fl;

	nlm_copy_netobj(&resp->cookie, &argp->cookie);
	netid = svc_getnetid(sr->rq_xprt);
	addr = svc_getrpccaller(sr->rq_xprt);
	name = argp->alock.caller_name;

	g = zone_getspecific(nlm_zone_key, curzone);
	host = nlm_host_findcreate(g, name, netid, addr);
	if (host == NULL) {
		resp->stat.stat = nlm4_denied_nolocks;
		return;
	}
	if (cb != NULL) {
		error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
		if (error != 0) {
			resp->stat.stat = nlm4_denied_nolocks;
			goto out;
		}
	}

	DTRACE_PROBE3(start, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_cancargs *, argp);

	if (NLM_IN_GRACE(g)) {
		resp->stat.stat = nlm4_denied_grace_period;
		goto out;
	}

	nvp = nlm_fh_to_vhold(host, &argp->alock.fh);
	if (nvp == NULL) {
		resp->stat.stat = nlm4_stale_fh;
		goto out;
	}

	/* Convert to local form. */
	error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers,
	    (argp->exclusive) ? F_WRLCK : F_RDLCK);
	if (error) {
		resp->stat.stat = nlm4_failed;
		goto out;
	}

	error = nlm_slreq_unregister(host, nvp, &fl);
	if (error != 0) {
		/*
		 * There's no sleeping lock request corresponding
		 * to the lock. Then requested sleeping lock
		 * doesn't exist.
		 */
		resp->stat.stat = nlm4_denied;
		goto out;
	}

	fl.l_type = F_UNLCK;
	error = nlm_vop_frlock(nvp->nv_vp, F_SETLK, &fl,
	    F_REMOTELOCK | FREAD | FWRITE,
	    (u_offset_t)0, NULL, CRED(), NULL);

	resp->stat.stat = (error == 0) ?
	    nlm4_granted : nlm4_denied;

out:
	/*
	 * If we have a callback function, use that to
	 * deliver the response via another RPC call.
	 */
	if (cb != NULL && rpcp != NULL)
		NLM_INVOKE_CALLBACK("cancel", rpcp, resp, cb);

	DTRACE_PROBE3(cancel__end, struct nlm_globals *, g,
	    struct nlm_host *, host, nlm4_res *, resp);

	if (rpcp != NULL)
		nlm_host_rele_rpc(host, rpcp);

	nlm_vhold_release(host, nvp);
	nlm_host_release(g, host);
}
Example #22
0
/*
 * Get the access information from the cache or callup to the mountd
 * to get and cache the access information in the kernel.
 */
int
nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor)
{
	struct netbuf		  addr;
	struct netbuf		 *claddr;
	struct auth_cache	**head;
	struct auth_cache	 *ap;
	int			  access;
	varg_t			  varg = {0};
	nfsauth_res_t		  res = {0};
	XDR			  xdrs_a;
	XDR			  xdrs_r;
	size_t			  absz;
	caddr_t			  abuf;
	size_t			  rbsz = (size_t)(BYTES_PER_XDR_UNIT * 2);
	char			  result[BYTES_PER_XDR_UNIT * 2] = {0};
	caddr_t			  rbuf = (caddr_t)&result;
	int			  last = 0;
	door_arg_t		  da;
	door_info_t		  di;
	door_handle_t		  dh;
	uint_t			  ntries = 0;

	/*
	 * Now check whether this client already
	 * has an entry for this flavor in the cache
	 * for this export.
	 * Get the caller's address, mask off the
	 * parts of the address that do not identify
	 * the host (port number, etc), and then hash
	 * it to find the chain of cache entries.
	 */

	claddr = svc_getrpccaller(req->rq_xprt);
	addr = *claddr;
	addr.buf = kmem_alloc(addr.len, KM_SLEEP);
	bcopy(claddr->buf, addr.buf, claddr->len);
	addrmask(&addr, svc_getaddrmask(req->rq_xprt));
	head = &exi->exi_cache[hash(&addr)];

	rw_enter(&exi->exi_cache_lock, RW_READER);
	for (ap = *head; ap; ap = ap->auth_next) {
		if (EQADDR(&addr, &ap->auth_addr) && flavor == ap->auth_flavor)
			break;
	}
	if (ap) {				/* cache hit */
		access = ap->auth_access;
		ap->auth_time = gethrestime_sec();
		nfsauth_cache_hit++;
	}

	rw_exit(&exi->exi_cache_lock);

	if (ap) {
		kmem_free(addr.buf, addr.len);
		return (access);
	}

	nfsauth_cache_miss++;

	/*
	 * No entry in the cache for this client/flavor
	 * so we need to call the nfsauth service in the
	 * mount daemon.
	 */
retry:
	mutex_enter(&mountd_lock);
	dh = mountd_dh;
	if (dh)
		door_ki_hold(dh);
	mutex_exit(&mountd_lock);

	if (dh == NULL) {
		/*
		 * The rendezvous point has not been established yet !
		 * This could mean that either mountd(1m) has not yet
		 * been started or that _this_ routine nuked the door
		 * handle after receiving an EINTR for a REVOKED door.
		 *
		 * Returning NFSAUTH_DROP will cause the NFS client
		 * to retransmit the request, so let's try to be more
		 * rescillient and attempt for ntries before we bail.
		 */
		if (++ntries % NFSAUTH_DR_TRYCNT) {
			delay(hz);
			goto retry;
		}
		sys_log("nfsauth: mountd has not established door");
		kmem_free(addr.buf, addr.len);
		return (NFSAUTH_DROP);
	}
	ntries = 0;
	varg.vers = V_PROTO;
	varg.arg_u.arg.cmd = NFSAUTH_ACCESS;
	varg.arg_u.arg.areq.req_client.n_len = addr.len;
	varg.arg_u.arg.areq.req_client.n_bytes = addr.buf;
	varg.arg_u.arg.areq.req_netid = svc_getnetid(req->rq_xprt);
	varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path;
	varg.arg_u.arg.areq.req_flavor = flavor;

	/*
	 * Setup the XDR stream for encoding the arguments. Notice that
	 * in addition to the args having variable fields (req_netid and
	 * req_path), the argument data structure is itself versioned,
	 * so we need to make sure we can size the arguments buffer
	 * appropriately to encode all the args. If we can't get sizing
	 * info _or_ properly encode the arguments, there's really no
	 * point in continuting, so we fail the request.
	 */
	DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg);
	if ((absz = xdr_sizeof(xdr_varg, (void *)&varg)) == 0) {
		door_ki_rele(dh);
		kmem_free(addr.buf, addr.len);
		return (NFSAUTH_DENIED);
	}
	abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP);
	xdrmem_create(&xdrs_a, abuf, absz, XDR_ENCODE);
	if (!xdr_varg(&xdrs_a, &varg)) {
		door_ki_rele(dh);
		goto fail;
	}
	XDR_DESTROY(&xdrs_a);

	/*
	 * The result (nfsauth_res_t) is always two int's, so we don't
	 * have to dynamically size (or allocate) the results buffer.
	 * Now that we've got what we need, we prep the door arguments
	 * and place the call.
	 */
	da.data_ptr = (char *)abuf;
	da.data_size = absz;
	da.desc_ptr = NULL;
	da.desc_num = 0;
	da.rbuf = (char *)rbuf;
	da.rsize = rbsz;

	switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) {
		case 0:				/* Success */
			if (da.data_ptr != da.rbuf && da.data_size == 0) {
				/*
				 * The door_return that contained the data
				 * failed ! We're here because of the 2nd
				 * door_return (w/o data) such that we can
				 * get control of the thread (and exit
				 * gracefully).
				 */
				DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil,
				    door_arg_t *, &da);
				door_ki_rele(dh);
				goto fail;

			} else if (rbuf != da.rbuf) {