Ejemplo n.º 1
0
bool_t
nlm_granted_msg_1_svc(struct nlm_testargs *argp, void *result, struct svc_req *rqstp)
{
	nlm4_testargs args4;
	nlm4_res res4;
	nlm_res res;
	CLIENT *rpc;
	char dummy;

	args4.cookie = argp->cookie;
	args4.exclusive = argp->exclusive;
	nlm_convert_to_nlm4_lock(&args4.alock, &argp->alock);

	if (nlm_do_granted(&args4, &res4, rqstp, &rpc))
		return (FALSE);

	nlm_convert_to_nlm_res(&res, &res4);

	if (rpc) {
		nlm_granted_res_1(&res, &dummy, rpc, NULL, nlm_zero_tv);
		CLNT_RELEASE(rpc);
	}
	xdr_free((xdrproc_t) xdr_nlm_res, &res);

	return (FALSE);
}
Ejemplo n.º 2
0
OM_uint32
gss_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle)
{
	struct release_cred_res res;
	struct release_cred_args args;
	enum clnt_stat stat;
	CLIENT *cl;

	*minor_status = 0;

	if (!kgss_gssd_handle)
		return (GSS_S_FAILURE);

	if (*cred_handle) {
		args.cred = (*cred_handle)->handle;

		cl = kgss_gssd_client();
		if (cl == NULL)
			return (GSS_S_FAILURE);
		stat = gssd_release_cred_1(&args, &res, cl);
		CLNT_RELEASE(cl);
		if (stat != RPC_SUCCESS) {
			*minor_status = stat;
			return (GSS_S_FAILURE);
		}

		free((*cred_handle), M_GSSAPI);
		*cred_handle = NULL;

		*minor_status = res.minor_status;
		return (res.major_status);
	}

	return (GSS_S_COMPLETE);
}
Ejemplo n.º 3
0
bool_t
nlm_test_msg_1_svc(struct nlm_testargs *argp, void *result, struct svc_req *rqstp)
{
	nlm4_testargs args4;
	nlm4_testres res4;
	nlm_testres res;
	CLIENT *rpc;
	char dummy;

	args4.cookie = argp->cookie;
	args4.exclusive = argp->exclusive;
	nlm_convert_to_nlm4_lock(&args4.alock, &argp->alock);

	if (nlm_do_test(&args4, &res4, rqstp, &rpc))
		return (FALSE);

	res.cookie = res4.cookie;
	res.stat.stat = nlm_convert_to_nlm_stats(res4.stat.stat);
	if (res.stat.stat == nlm_denied)
		nlm_convert_to_nlm_holder(
			&res.stat.nlm_testrply_u.holder,
			&res4.stat.nlm4_testrply_u.holder);

	if (rpc) {
		nlm_test_res_1(&res, &dummy, rpc, NULL, nlm_zero_tv);
		CLNT_RELEASE(rpc);
	}
	xdr_free((xdrproc_t) xdr_nlm_testres, &res);

	return (FALSE);
}
Ejemplo n.º 4
0
OM_uint32
gss_export_name(OM_uint32 *minor_status, gss_name_t input_name,
    gss_buffer_t exported_name)
{
	struct export_name_res res;
	struct export_name_args args;
	enum clnt_stat stat;
	CLIENT *cl;

	*minor_status = 0;
	cl = kgss_gssd_client();
	if (cl == NULL)
		return (GSS_S_FAILURE);

	args.input_name = input_name->handle;

	bzero(&res, sizeof(res));
	stat = gssd_export_name_1(&args, &res, cl);
	CLNT_RELEASE(cl);
	if (stat != RPC_SUCCESS) {
		*minor_status = stat;
		return (GSS_S_FAILURE);
	}

	if (res.major_status != GSS_S_COMPLETE) {
		*minor_status = res.minor_status;
		return (res.major_status);
	}

	kgss_copy_buffer(&res.exported_name, exported_name);
	xdr_free((xdrproc_t) xdr_export_name_res, &res);

	return (GSS_S_COMPLETE);
}
OM_uint32
gss_delete_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle,
	gss_buffer_t output_token)
{
	struct delete_sec_context_res res;
	struct delete_sec_context_args args;
	enum clnt_stat stat;
	gss_ctx_id_t ctx;
	CLIENT *cl;

	*minor_status = 0;

	if (!kgss_gssd_handle)
		return (GSS_S_FAILURE);

	if (*context_handle) {
		ctx = *context_handle;

		/*
		 * If we are past the context establishment phase, let
		 * the in-kernel code do the delete, otherwise
		 * userland needs to deal with it.
		 */
		if (ctx->handle) {
			args.ctx = ctx->handle;
			cl = kgss_gssd_client();
			if (cl == NULL)
				return (GSS_S_FAILURE);
	
			bzero(&res, sizeof(res));
			stat = gssd_delete_sec_context_1(&args, &res, cl);
			CLNT_RELEASE(cl);
			if (stat != RPC_SUCCESS) {
				*minor_status = stat;
				return (GSS_S_FAILURE);
			}

			if (output_token)
				kgss_copy_buffer(&res.output_token,
				    output_token);
			xdr_free((xdrproc_t) xdr_delete_sec_context_res, &res);

			kgss_delete_context(ctx, NULL);
		} else {
			kgss_delete_context(ctx, output_token);
		}
		*context_handle = NULL;
	} else {
		if (output_token) {
			output_token->length = 0;
			output_token->value = NULL;
		}
	}

	return (GSS_S_COMPLETE);
}
Ejemplo n.º 6
0
OM_uint32
gss_pname_to_unix_cred(OM_uint32 *minor_status, const gss_name_t pname,
    const gss_OID mech, uid_t *uidp, gid_t *gidp,
    int *numgroups, gid_t *groups)
	      
{
	struct pname_to_uid_res res;
	struct pname_to_uid_args args;
	enum clnt_stat stat;
	int i, n;
	CLIENT *cl;

	*minor_status = 0;

	if (pname == GSS_C_NO_NAME)
		return (GSS_S_BAD_NAME);

	cl = kgss_gssd_client();
	if (cl == NULL)
		return (GSS_S_FAILURE);

	args.pname = pname->handle;
	args.mech = mech;

	bzero(&res, sizeof(res));
	stat = gssd_pname_to_uid_1(&args, &res, cl);
	CLNT_RELEASE(cl);
	if (stat != RPC_SUCCESS) {
		*minor_status = stat;
		return (GSS_S_FAILURE);
	}

	if (res.major_status != GSS_S_COMPLETE) {
		*minor_status = res.minor_status;
		return (res.major_status);
	}

	*uidp = res.uid;
	*gidp = res.gid;
	n = res.gidlist.gidlist_len;
	if (n > *numgroups)
		n = *numgroups;
	for (i = 0; i < n; i++)
		groups[i] = res.gidlist.gidlist_val[i];
	*numgroups = n;

	xdr_free((xdrproc_t) xdr_pname_to_uid_res, &res);

	return (GSS_S_COMPLETE);
}
Ejemplo n.º 7
0
/*
 * NFS disconnect.  Clean up and unlink.
 */
void
nfs_disconnect(struct nfsmount *nmp)
{
	CLIENT *client;

	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_client) {
		client = nmp->nm_client;
		nmp->nm_client = NULL;
		mtx_unlock(&nmp->nm_mtx);
		rpc_gss_secpurge_call(client);
		CLNT_CLOSE(client);
		CLNT_RELEASE(client);
	} else
		mtx_unlock(&nmp->nm_mtx);
}
Ejemplo n.º 8
0
bool_t
nlm4_granted_msg_4_svc(nlm4_testargs *argp, void *result, struct svc_req *rqstp)
{
	nlm4_res res4;
	CLIENT *rpc;
	char dummy;

	if (nlm_do_granted(argp, &res4, rqstp, &rpc))
		return (FALSE);
	if (rpc) {
		nlm4_granted_res_4(&res4, &dummy, rpc, NULL, nlm_zero_tv);
		CLNT_RELEASE(rpc);
	}
	xdr_free((xdrproc_t) xdr_nlm4_res, &res4);

	return (FALSE);
}
Ejemplo n.º 9
0
/*
 * NFS disconnect. Clean up and unlink.
 */
void
nfs_disconnect(struct nfsmount *nmp)
{
	CLIENT *client;

	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_client) {
		client = nmp->nm_client;
		nmp->nm_client = NULL;
		mtx_unlock(&nmp->nm_mtx);
#ifdef KGSSAPI
		rpc_gss_secpurge(client);
#endif
		CLNT_CLOSE(client);
		CLNT_RELEASE(client);
	} else {
		mtx_unlock(&nmp->nm_mtx);
	}
}
Ejemplo n.º 10
0
OM_uint32
gss_display_status(OM_uint32 *minor_status,
    OM_uint32 status_value,
    int status_type,
    const gss_OID mech_type,
    OM_uint32 *message_context,
    gss_buffer_t status_string)            /* status_string */
{
	struct display_status_res res;
	struct display_status_args args;
	enum clnt_stat stat;
	CLIENT *cl;

	*minor_status = 0;
	cl = kgss_gssd_client();
	if (cl == NULL)
		return (GSS_S_FAILURE);

	args.status_value = status_value;
	args.status_type = status_type;
	args.mech_type = mech_type;
	args.message_context = *message_context;
	
	bzero(&res, sizeof(res));
	stat = gssd_display_status_1(&args, &res, cl);
	CLNT_RELEASE(cl);
	if (stat != RPC_SUCCESS) {
		*minor_status = stat;
		return (GSS_S_FAILURE);
	}

	if (res.major_status != GSS_S_COMPLETE) {
		*minor_status = res.minor_status;
		return (res.major_status);
	}

	*message_context = res.message_context;
	kgss_copy_buffer(&res.status_string, status_string);
	xdr_free((xdrproc_t) xdr_display_status_res, &res);

	return (GSS_S_COMPLETE);
}
Ejemplo n.º 11
0
OM_uint32
gss_import_name(OM_uint32 *minor_status,
    const gss_buffer_t input_name_buffer,
    const gss_OID input_name_type,
    gss_name_t *output_name)
{
	struct import_name_res res;
	struct import_name_args args;
	enum clnt_stat stat;
	gss_name_t name;
	CLIENT *cl;

	*minor_status = 0;
	*output_name = GSS_C_NO_NAME;

	cl = kgss_gssd_client();
	if (cl == NULL)
		return (GSS_S_FAILURE);

	args.input_name_buffer = *input_name_buffer;
	args.input_name_type = input_name_type;
	
	bzero(&res, sizeof(res));
	stat = gssd_import_name_1(&args, &res, cl);
	CLNT_RELEASE(cl);
	if (stat != RPC_SUCCESS) {
		*minor_status = stat;
		return (GSS_S_FAILURE);
	}

	if (res.major_status != GSS_S_COMPLETE) {
		*minor_status = res.minor_status;
		return (res.major_status);
	}

	name = malloc(sizeof(struct _gss_name_t), M_GSSAPI, M_WAITOK);
	name->handle = res.output_name;
	*minor_status = 0;
	*output_name = name;

	return (GSS_S_COMPLETE);
}
Ejemplo n.º 12
0
OM_uint32
gss_release_name(OM_uint32 *minor_status, gss_name_t *input_name)
{
	struct release_name_res res;
	struct release_name_args args;
	enum clnt_stat stat;
	gss_name_t name;
	CLIENT *cl;

	*minor_status = 0;

	if (!kgss_gssd_handle)
		return (GSS_S_FAILURE);

	if (*input_name) {
		name = *input_name;
		args.input_name = name->handle;
	
		cl = kgss_gssd_client();
		if (cl == NULL)
			return (GSS_S_FAILURE);
		stat = gssd_release_name_1(&args, &res, cl);
		CLNT_RELEASE(cl);
		if (stat != RPC_SUCCESS) {
			*minor_status = stat;
			return (GSS_S_FAILURE);
		}

		free(name, M_GSSAPI);
		*input_name = NULL;

		if (res.major_status != GSS_S_COMPLETE) {
			*minor_status = res.minor_status;
			return (res.major_status);
		}
	}

	return (GSS_S_COMPLETE);
}
Ejemplo n.º 13
0
OM_uint32
gss_pname_to_uid(OM_uint32 *minor_status, const gss_name_t pname,
    const gss_OID mech, uid_t *uidp)
{
	struct pname_to_uid_res res;
	struct pname_to_uid_args args;
	enum clnt_stat stat;
	CLIENT *cl;

	*minor_status = 0;

	if (pname == GSS_C_NO_NAME)
		return (GSS_S_BAD_NAME);

	cl = kgss_gssd_client();
	if (cl == NULL)
		return (GSS_S_FAILURE);

	args.pname = pname->handle;
	args.mech = mech;

	bzero(&res, sizeof(res));
	stat = gssd_pname_to_uid_1(&args, &res, cl);
	CLNT_RELEASE(cl);
	if (stat != RPC_SUCCESS) {
		*minor_status = stat;
		return (GSS_S_FAILURE);
	}

	if (res.major_status != GSS_S_COMPLETE) {
		*minor_status = res.minor_status;
		return (res.major_status);
	}

	*uidp = res.uid;
	return (GSS_S_COMPLETE);
}
Ejemplo n.º 14
0
static void
clnt_reconnect_close(CLIENT *cl)
{
	struct rc_data *rc = (struct rc_data *)cl->cl_private;
	CLIENT *client;

	mtx_lock(&rc->rc_lock);

	if (rc->rc_closed) {
		mtx_unlock(&rc->rc_lock);
		return;
	}

	rc->rc_closed = TRUE;
	client = rc->rc_client;
	rc->rc_client = NULL;

	mtx_unlock(&rc->rc_lock);

	if (client) {
		CLNT_CLOSE(client);
		CLNT_RELEASE(client);
	}
}
Ejemplo n.º 15
0
static enum clnt_stat
clnt_reconnect_connect(CLIENT *cl)
{
	struct thread *td = curthread;
	struct rc_data *rc = (struct rc_data *)cl->cl_private;
	struct socket *so;
	enum clnt_stat stat;
	int error;
	int one = 1;
	struct ucred *oldcred;
	CLIENT *newclient = NULL;

	mtx_lock(&rc->rc_lock);
	while (rc->rc_connecting) {
		error = msleep(rc, &rc->rc_lock,
		    rc->rc_intr ? PCATCH : 0, "rpcrecon", 0);
		if (error) {
			mtx_unlock(&rc->rc_lock);
			return (RPC_INTR);
		}
	}
	if (rc->rc_closed) {
		mtx_unlock(&rc->rc_lock);
		return (RPC_CANTSEND);
	}
	if (rc->rc_client) {
		mtx_unlock(&rc->rc_lock);
		return (RPC_SUCCESS);
	}

	/*
	 * My turn to attempt a connect. The rc_connecting variable
	 * serializes the following code sequence, so it is guaranteed
	 * that rc_client will still be NULL after it is re-locked below,
	 * since that is the only place it is set non-NULL.
	 */
	rc->rc_connecting = TRUE;
	mtx_unlock(&rc->rc_lock);

	oldcred = td->td_ucred;
	td->td_ucred = rc->rc_ucred;
	so = __rpc_nconf2socket(rc->rc_nconf);
	if (!so) {
		stat = rpc_createerr.cf_stat = RPC_TLIERROR;
		rpc_createerr.cf_error.re_errno = 0;
		td->td_ucred = oldcred;
		goto out;
	}

	if (rc->rc_privport)
		bindresvport(so, NULL);

	if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS)
		newclient = clnt_dg_create(so,
		    (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
		    rc->rc_sendsz, rc->rc_recvsz);
	else
		newclient = clnt_vc_create(so,
		    (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
		    rc->rc_sendsz, rc->rc_recvsz, rc->rc_intr);
	td->td_ucred = oldcred;

	if (!newclient) {
		soclose(so);
		rc->rc_err = rpc_createerr.cf_error;
		stat = rpc_createerr.cf_stat;
		goto out;
	}

	CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0);
	CLNT_CONTROL(newclient, CLSET_CONNECT, &one);
	CLNT_CONTROL(newclient, CLSET_TIMEOUT, &rc->rc_timeout);
	CLNT_CONTROL(newclient, CLSET_RETRY_TIMEOUT, &rc->rc_retry);
	CLNT_CONTROL(newclient, CLSET_WAITCHAN, rc->rc_waitchan);
	CLNT_CONTROL(newclient, CLSET_INTERRUPTIBLE, &rc->rc_intr);
	if (rc->rc_backchannel != NULL)
		CLNT_CONTROL(newclient, CLSET_BACKCHANNEL, rc->rc_backchannel);
	stat = RPC_SUCCESS;

out:
	mtx_lock(&rc->rc_lock);
	KASSERT(rc->rc_client == NULL, ("rc_client not null"));
	if (!rc->rc_closed) {
		rc->rc_client = newclient;
		newclient = NULL;
	}
	rc->rc_connecting = FALSE;
	wakeup(rc);
	mtx_unlock(&rc->rc_lock);

	if (newclient) {
		/*
		 * It has been closed, so discard the new client.
		 * nb: clnt_[dg|vc]_close()/clnt_[dg|vc]_destroy() cannot
		 * be called with the rc_lock mutex held, since they may
		 * msleep() while holding a different mutex.
		 */
		CLNT_CLOSE(newclient);
		CLNT_RELEASE(newclient);
	}

	return (stat);
}
Ejemplo n.º 16
0
/*
 * Initialize sockets and congestion for a new NFS connection.
 * We do not free the sockaddr if error.
 */
int
nfs_connect(struct nfsmount *nmp)
{
	int rcvreserve, sndreserve;
	int pktscale;
	struct sockaddr *saddr;
	struct ucred *origcred;
	struct thread *td = curthread;
	CLIENT *client;
	struct netconfig *nconf;
	rpcvers_t vers;
	int one = 1, retries;

	/*
	 * We need to establish the socket using the credentials of
	 * the mountpoint.  Some parts of this process (such as
	 * sobind() and soconnect()) will use the curent thread's
	 * credential instead of the socket credential.  To work
	 * around this, temporarily change the current thread's
	 * credential to that of the mountpoint.
	 *
	 * XXX: It would be better to explicitly pass the correct
	 * credential to sobind() and soconnect().
	 */
	origcred = td->td_ucred;
	td->td_ucred = nmp->nm_mountp->mnt_cred;
	saddr = nmp->nm_nam;

	vers = NFS_VER2;
	if (nmp->nm_flag & NFSMNT_NFSV3)
		vers = NFS_VER3;
	else if (nmp->nm_flag & NFSMNT_NFSV4)
		vers = NFS_VER4;
	if (saddr->sa_family == AF_INET)
		if (nmp->nm_sotype == SOCK_DGRAM)
			nconf = getnetconfigent("udp");
		else
			nconf = getnetconfigent("tcp");
	else
		if (nmp->nm_sotype == SOCK_DGRAM)
			nconf = getnetconfigent("udp6");
		else
			nconf = getnetconfigent("tcp6");

	/*
	 * Get buffer reservation size from sysctl, but impose reasonable
	 * limits.
	 */
	pktscale = nfs_bufpackets;
	if (pktscale < 2)
		pktscale = 2;
	if (pktscale > 64)
		pktscale = 64;
	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_sotype == SOCK_DGRAM) {
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
		    NFS_MAXPKTHDR) * pktscale;
	} else if (nmp->nm_sotype == SOCK_SEQPACKET) {
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
		    NFS_MAXPKTHDR) * pktscale;
	} else {
		if (nmp->nm_sotype != SOCK_STREAM)
			panic("nfscon sotype");
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
		    sizeof (u_int32_t)) * pktscale;
		rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
		    sizeof (u_int32_t)) * pktscale;
	}
	mtx_unlock(&nmp->nm_mtx);

	client = clnt_reconnect_create(nconf, saddr, NFS_PROG, vers,
	    sndreserve, rcvreserve);
	CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq");
	if (nmp->nm_flag & NFSMNT_INT)
		CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
	if (nmp->nm_flag & NFSMNT_RESVPORT)
		CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
	if (nmp->nm_flag & NFSMNT_SOFT)
		retries = nmp->nm_retry;
	else
		retries = INT_MAX;
	CLNT_CONTROL(client, CLSET_RETRIES, &retries);

	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_client) {
		/*
		 * Someone else already connected.
		 */
		CLNT_RELEASE(client);
	} else
		nmp->nm_client = client;

	/*
	 * Protocols that do not require connections may be optionally left
	 * unconnected for servers that reply from a port other than NFS_PORT.
	 */
	if (!(nmp->nm_flag & NFSMNT_NOCONN)) {
		mtx_unlock(&nmp->nm_mtx);
		CLNT_CONTROL(client, CLSET_CONNECT, &one);
	} else
		mtx_unlock(&nmp->nm_mtx);

	/* Restore current thread's credentials. */
	td->td_ucred = origcred;

	mtx_lock(&nmp->nm_mtx);
	/* Initialize other non-zero congestion variables. */
	nfs_init_rtt(nmp);
	mtx_unlock(&nmp->nm_mtx);
	return (0);
}
Ejemplo n.º 17
0
/*
 * Initialize sockets and congestion for a new NFS connection.
 * We do not free the sockaddr if error.
 */
int
nfs_connect(struct nfsmount *nmp)
{
	int rcvreserve, sndreserve;
	int pktscale;
	struct sockaddr *saddr;
	struct ucred *origcred;
	struct thread *td = curthread;
	CLIENT *client;
	struct netconfig *nconf;
	rpcvers_t vers;
	int one = 1, retries;
	struct timeval timo;

	/*
	 * We need to establish the socket using the credentials of
	 * the mountpoint.  Some parts of this process (such as
	 * sobind() and soconnect()) will use the curent thread's
	 * credential instead of the socket credential.  To work
	 * around this, temporarily change the current thread's
	 * credential to that of the mountpoint.
	 *
	 * XXX: It would be better to explicitly pass the correct
	 * credential to sobind() and soconnect().
	 */
	origcred = td->td_ucred;
	td->td_ucred = nmp->nm_mountp->mnt_cred;
	saddr = nmp->nm_nam;

	vers = NFS_VER2;
	if (nmp->nm_flag & NFSMNT_NFSV3)
		vers = NFS_VER3;
	else if (nmp->nm_flag & NFSMNT_NFSV4)
		vers = NFS_VER4;
	if (saddr->sa_family == AF_INET)
		if (nmp->nm_sotype == SOCK_DGRAM)
			nconf = getnetconfigent("udp");
		else
			nconf = getnetconfigent("tcp");
	else
		if (nmp->nm_sotype == SOCK_DGRAM)
			nconf = getnetconfigent("udp6");
		else
			nconf = getnetconfigent("tcp6");

	/*
	 * Get buffer reservation size from sysctl, but impose reasonable
	 * limits.
	 */
	pktscale = nfs_bufpackets;
	if (pktscale < 2)
		pktscale = 2;
	if (pktscale > 64)
		pktscale = 64;
	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_sotype == SOCK_DGRAM) {
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
		    NFS_MAXPKTHDR) * pktscale;
	} else if (nmp->nm_sotype == SOCK_SEQPACKET) {
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
		    NFS_MAXPKTHDR) * pktscale;
	} else {
		if (nmp->nm_sotype != SOCK_STREAM)
			panic("nfscon sotype");
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
		    sizeof (u_int32_t)) * pktscale;
		rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
		    sizeof (u_int32_t)) * pktscale;
	}
	mtx_unlock(&nmp->nm_mtx);

	client = clnt_reconnect_create(nconf, saddr, NFS_PROG, vers,
	    sndreserve, rcvreserve);
	CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq");
	if (nmp->nm_flag & NFSMNT_INT)
		CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
	if (nmp->nm_flag & NFSMNT_RESVPORT)
		CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
	if ((nmp->nm_flag & NFSMNT_SOFT) != 0) {
		if (nmp->nm_sotype == SOCK_DGRAM)
			/*
			 * For UDP, the large timeout for a reconnect will
			 * be set to "nm_retry * nm_timeo / 2", so we only
			 * want to do 2 reconnect timeout retries.
			 */
			retries = 2;
		else
			retries = nmp->nm_retry;
	} else
		retries = INT_MAX;
	CLNT_CONTROL(client, CLSET_RETRIES, &retries);

	/*
	 * For UDP, there are 2 timeouts:
	 * - CLSET_RETRY_TIMEOUT sets the initial timeout for the timer
	 *   that does a retransmit of an RPC request using the same socket
	 *   and xid. This is what you normally want to do, since NFS
	 *   servers depend on "same xid" for their Duplicate Request Cache.
	 * - timeout specified in CLNT_CALL_MBUF(), which specifies when
	 *   retransmits on the same socket should fail and a fresh socket
	 *   created. Each of these timeouts counts as one CLSET_RETRIES,
	 *   as set above.
	 * Set the initial retransmit timeout for UDP. This timeout doesn't
	 * exist for TCP and the following call just fails, which is ok.
	 */
	timo.tv_sec = nmp->nm_timeo / NFS_HZ;
	timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ;
	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, &timo);

	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_client) {
		/*
		 * Someone else already connected.
		 */
		CLNT_RELEASE(client);
	} else
		nmp->nm_client = client;

	/*
	 * Protocols that do not require connections may be optionally left
	 * unconnected for servers that reply from a port other than NFS_PORT.
	 */
	if (!(nmp->nm_flag & NFSMNT_NOCONN)) {
		mtx_unlock(&nmp->nm_mtx);
		CLNT_CONTROL(client, CLSET_CONNECT, &one);
	} else
		mtx_unlock(&nmp->nm_mtx);

	/* Restore current thread's credentials. */
	td->td_ucred = origcred;

	mtx_lock(&nmp->nm_mtx);
	/* Initialize other non-zero congestion variables. */
	nfs_init_rtt(nmp);
	mtx_unlock(&nmp->nm_mtx);
	return (0);
}
Ejemplo n.º 18
0
OM_uint32
gss_acquire_cred(OM_uint32 *minor_status,
    const gss_name_t desired_name,
    OM_uint32 time_req,
    const gss_OID_set desired_mechs,
    gss_cred_usage_t cred_usage,
    gss_cred_id_t *output_cred_handle,
    gss_OID_set *actual_mechs,
    OM_uint32 *time_rec)
{
	OM_uint32 major_status;
	struct acquire_cred_res res;
	struct acquire_cred_args args;
	enum clnt_stat stat;
	gss_cred_id_t cred;
	int i;
	CLIENT *cl;

	*minor_status = 0;
	cl = kgss_gssd_client();
	if (cl == NULL)
		return (GSS_S_FAILURE);

	args.uid = curthread->td_ucred->cr_uid;
	if (desired_name)
		args.desired_name = desired_name->handle;
	else
		args.desired_name = 0;
	args.time_req = time_req;
	args.desired_mechs = desired_mechs;
	args.cred_usage = cred_usage;

	bzero(&res, sizeof(res));
	stat = gssd_acquire_cred_1(&args, &res, cl);
	CLNT_RELEASE(cl);
	if (stat != RPC_SUCCESS) {
		*minor_status = stat;
		return (GSS_S_FAILURE);
	}

	if (res.major_status != GSS_S_COMPLETE) {
		*minor_status = res.minor_status;
		return (res.major_status);
	}

	cred = malloc(sizeof(struct _gss_cred_id_t), M_GSSAPI, M_WAITOK);
	cred->handle = res.output_cred;
	*output_cred_handle = cred;
	if (actual_mechs) {
		major_status = gss_create_empty_oid_set(minor_status,
		    actual_mechs);
		if (major_status)
			return (major_status);
		for (i = 0; i < res.actual_mechs->count; i++) {
			major_status = gss_add_oid_set_member(minor_status,
			    &res.actual_mechs->elements[i], actual_mechs);
			if (major_status)
				return (major_status);
		}
	}
	if (time_rec)
		*time_rec = res.time_rec;

	xdr_free((xdrproc_t) xdr_acquire_cred_res, &res);

	return (GSS_S_COMPLETE);
}
Ejemplo n.º 19
0
static enum clnt_stat
clnt_reconnect_call(
	CLIENT		*cl,		/* client handle */
	struct rpc_callextra *ext,	/* call metadata */
	rpcproc_t	proc,		/* procedure number */
	struct mbuf	*args,		/* pointer to args */
	struct mbuf	**resultsp,	/* pointer to results */
	struct timeval	utimeout)
{
	struct rc_data *rc = (struct rc_data *)cl->cl_private;
	CLIENT *client;
	enum clnt_stat stat;
	int tries, error;

	tries = 0;
	do {
		mtx_lock(&rc->rc_lock);
		if (rc->rc_closed) {
			mtx_unlock(&rc->rc_lock);
			return (RPC_CANTSEND);
		}

		if (!rc->rc_client) {
			mtx_unlock(&rc->rc_lock);
			stat = clnt_reconnect_connect(cl);
			if (stat == RPC_SYSTEMERROR) {
				error = tsleep(&fake_wchan,
				    rc->rc_intr ? PCATCH | PBDRY : 0, "rpccon",
				    hz);
				if (error == EINTR || error == ERESTART)
					return (RPC_INTR);
				tries++;
				if (tries >= rc->rc_retries)
					return (stat);
				continue;
			}
			if (stat != RPC_SUCCESS)
				return (stat);
			mtx_lock(&rc->rc_lock);
		}

		if (!rc->rc_client) {
			mtx_unlock(&rc->rc_lock);
			stat = RPC_FAILED;
			continue;
		}
		CLNT_ACQUIRE(rc->rc_client);
		client = rc->rc_client;
		mtx_unlock(&rc->rc_lock);
		stat = CLNT_CALL_MBUF(client, ext, proc, args,
		    resultsp, utimeout);

		if (stat != RPC_SUCCESS) {
			if (!ext)
				CLNT_GETERR(client, &rc->rc_err);
		}

		if (stat == RPC_TIMEDOUT) {
			/*
			 * Check for async send misfeature for NLM
			 * protocol.
			 */
			if ((rc->rc_timeout.tv_sec == 0
				&& rc->rc_timeout.tv_usec == 0)
			    || (rc->rc_timeout.tv_sec == -1
				&& utimeout.tv_sec == 0
				&& utimeout.tv_usec == 0)) {
				CLNT_RELEASE(client);
				break;
			}
		}

		if (stat == RPC_TIMEDOUT || stat == RPC_CANTSEND
		    || stat == RPC_CANTRECV) {
			tries++;
			if (tries >= rc->rc_retries) {
				CLNT_RELEASE(client);
				break;
			}

			if (ext && ext->rc_feedback)
				ext->rc_feedback(FEEDBACK_RECONNECT, proc,
				    ext->rc_feedback_arg);

			mtx_lock(&rc->rc_lock);
			/*
			 * Make sure that someone else hasn't already
			 * reconnected by checking if rc_client has changed.
			 * If not, we are done with the client and must
			 * do CLNT_RELEASE(client) twice to dispose of it,
			 * because there is both an initial refcnt and one
			 * acquired by CLNT_ACQUIRE() above.
			 */
			if (rc->rc_client == client) {
				rc->rc_client = NULL;
				mtx_unlock(&rc->rc_lock);
				CLNT_RELEASE(client);
			} else {
				mtx_unlock(&rc->rc_lock);
			}
			CLNT_RELEASE(client);
		} else {
			CLNT_RELEASE(client);
			break;
		}
	} while (stat != RPC_SUCCESS);

	KASSERT(stat != RPC_SUCCESS || *resultsp,
	    ("RPC_SUCCESS without reply"));

	return (stat);
}