Esempio n. 1
0
/*
 * XDR loopback unix auth parameters.
 * NOTE: this is an XDR_ENCODE only routine.
 */
bool_t
xdr_authloopback(XDR *xdrs)
{
	uid_t uid;
	gid_t gid;
	int len;
	caddr_t groups;
	char *name = uts_nodename();
	struct cred *cr;
	time_t now;

	if (xdrs->x_op != XDR_ENCODE)
		return (FALSE);

	cr = CRED();
	uid = crgetuid(cr);
	gid = crgetgid(cr);
	len = crgetngroups(cr);
	groups = (caddr_t)crgetgroups(cr);
	now = gethrestime_sec();
	if (xdr_uint32(xdrs, (uint32_t *)&now) &&
	    xdr_string(xdrs, &name, MAX_MACHINE_NAME) &&
	    xdr_uid_t(xdrs, &uid) &&
	    xdr_gid_t(xdrs, &gid) &&
	    xdr_array(xdrs, &groups, (uint_t *)&len, NGRPS_LOOPBACK,
	    sizeof (int), (xdrproc_t)xdr_int))
		return (TRUE);
	return (FALSE);
}
Esempio n. 2
0
File: dsl_deleg.c Progetto: ph7/zfs
/*
 * Load all permissions user based on cred belongs to.
 */
static void
dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
    char checkflag, cred_t *cr)
{
	//const	gid_t *gids;
	//int	ngids, i;
	uint64_t id;

	id = crgetuid(cr);
	(void) dsl_load_sets(mos, zapobj,
	    ZFS_DELEG_USER_SETS, checkflag, &id, avl);

	id = crgetgid(cr);
	(void) dsl_load_sets(mos, zapobj,
	    ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);

	(void) dsl_load_sets(mos, zapobj,
	    ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);

#if 0
	ngids = crgetngroups(cr);
	gids = crgetgroups(cr);
	for (i = 0; i != ngids; i++) {
		id = gids[i];
		(void) dsl_load_sets(mos, zapobj,
		    ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
	}
#endif
}
Esempio n. 3
0
static int
splat_cred_test1(struct file *file, void *arg)
{
	char str[GROUP_STR_SIZE];
	uid_t uid, ruid, suid;
	gid_t gid, rgid, sgid, *groups;
	int ngroups, i, count = 0;

	uid  = crgetuid(CRED());
	ruid = crgetruid(CRED());
	suid = crgetsuid(CRED());

	gid  = crgetgid(CRED());
	rgid = crgetrgid(CRED());
	sgid = crgetsgid(CRED());

	crhold(CRED());
	ngroups = crgetngroups(CRED());
	groups  = crgetgroups(CRED());

	memset(str, 0, GROUP_STR_SIZE);
	for (i = 0; i < ngroups; i++) {
		count += sprintf(str + count, "%d ", groups[i]);

		if (count > (GROUP_STR_SIZE - GROUP_STR_REDZONE)) {
			splat_vprint(file, SPLAT_CRED_TEST1_NAME,
				     "Failed too many group entries for temp "
				     "buffer: %d, %s\n", ngroups, str);
			return -ENOSPC;
		}
	}

	crfree(CRED());

	splat_vprint(file, SPLAT_CRED_TEST1_NAME,
		     "uid: %d ruid: %d suid: %d "
		     "gid: %d rgid: %d sgid: %d\n",
		     uid, ruid, suid, gid, rgid, sgid);
	splat_vprint(file, SPLAT_CRED_TEST1_NAME,
		     "ngroups: %d groups: %s\n", ngroups, str);

	if (uid || ruid || suid || gid || rgid || sgid) {
		splat_vprint(file, SPLAT_CRED_TEST1_NAME,
			     "Failed expected all uids+gids to be %d\n", 0);
		return -EIDRM;
	}

	if (ngroups > NGROUPS_MAX) {
		splat_vprint(file, SPLAT_CRED_TEST1_NAME,
			     "Failed ngroups must not exceed NGROUPS_MAX: "
			     "%d > %d\n", ngroups, NGROUPS_MAX);
		return -EIDRM;
	}

	splat_vprint(file, SPLAT_CRED_TEST1_NAME,
		     "Success sane CRED(): %d\n", 0);

        return 0;
} /* splat_cred_test1() */
Esempio n. 4
0
int
getgroups(int gidsetsize, gid_t *gidset)
{
    struct cred *cr;
    int n;

    cr = curthread->t_cred;
    n = crgetngroups(cr);

    if (gidsetsize != 0) {
        if (gidsetsize < n)
            return (set_errno(EINVAL));
        if (copyout(crgetgroups(cr), gidset, n * sizeof (gid_t)))
            return (set_errno(EFAULT));
    }

    return (n);
}
Esempio n. 5
0
File: dsl_deleg.c Progetto: ph7/zfs
/*
 * check a specified user/group for a requested permission
 */
static int
dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
    int checkflag, cred_t *cr)
{
	//const	gid_t *gids;
    //	int	ngids;
	//int	i;
	uint64_t id;

	/* check for user */
	id = crgetuid(cr);
	if (dsl_check_access(mos, zapobj,
	    ZFS_DELEG_USER, checkflag, &id, perm) == 0)
		return (0);

	/* check for users primary group */
	id = crgetgid(cr);
	if (dsl_check_access(mos, zapobj,
	    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
		return (0);

	/* check for everyone entry */
	id = -1;
	if (dsl_check_access(mos, zapobj,
	    ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
		return (0);

	/* check each supplemental group user is a member of */
/*XXX NOEL: get kauth equivs for the below, crgetngroups, crgetgroups*/
#ifndef __APPLE__

	ngids = crgetngroups(cr);
	gids = crgetgroups(cr);
	for (i = 0; i != ngids; i++) {
		id = gids[i];
		if (dsl_check_access(mos, zapobj,
		    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
			return (0);
	}

	return (EPERM);
#endif
    return 0;
}
/*
 *
 * Cachefs used to know too much about how creds looked; since it's
 * committed to persistent storage, we can't change the layout so
 * it now has a "dl_cred_t" which (unsurprisingly) looks exactly like
 * an old credential.
 *
 * The dst argument needs to point to:
 *		struct dl_cred_t;
 *		<buffer space>			buffer for groups
 *
 * The source is a proper kernel cred_t.
 *
 */
static size_t
copy_cred(cred_t *src, dl_cred_t *dst)
{
	int n;
	const gid_t *sgrp = crgetgroups(src);

	n = MIN(NGROUPS_MAX_DEFAULT, crgetngroups(src));

	/* copy the fixed fields */
	dst->cr_uid = crgetuid(src);
	dst->cr_ruid = crgetruid(src);
	dst->cr_suid = crgetsuid(src);
	dst->cr_gid = crgetgid(src);
	dst->cr_rgid = crgetrgid(src);
	dst->cr_sgid = crgetsgid(src);
	dst->cr_groups[0] = sgrp[0];

	dst->cr_ngroups = n;
	bcopy(sgrp, (void *)(dst + 1), (n - 1) * sizeof (gid_t));
	return (sizeof (dl_cred_t) + (n - 1) * sizeof (gid_t));
}
Esempio n. 7
0
/*
 * check a specified user/group for a requested permission
 */
static int
dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
    int checkflag, cred_t *cr)
{
	const	gid_t *gids;
	int	ngids;
	int	i;
	uint64_t id;

	/* check for user */
	id = crgetuid(cr);
	if (dsl_check_access(mos, zapobj,
	    ZFS_DELEG_USER, checkflag, &id, perm) == 0)
		return (0);

	/* check for users primary group */
	id = crgetgid(cr);
	if (dsl_check_access(mos, zapobj,
	    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
		return (0);

	/* check for everyone entry */
	id = -1;
	if (dsl_check_access(mos, zapobj,
	    ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
		return (0);

	/* check each supplemental group user is a member of */
	ngids = crgetngroups(cr);
	gids = crgetgroups(cr);
	for (i = 0; i != ngids; i++) {
		id = gids[i];
		if (dsl_check_access(mos, zapobj,
		    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
			return (0);
	}

	return (EPERM);
}
off_t
/*ARGSUSED*/
cachefs_dlog_setsecattr(fscache_t *fscp, vsecattr_t *vsec, int flags,
    cnode_t *cp, cred_t *cr)
{
	struct cfs_dlog_entry *entp;
	struct cfs_dlog_setsecattr *up;
	size_t alen, clen, len;
	off_t offset = 0;
	aclent_t *aclp;

	ASSERT(MUTEX_HELD(&cp->c_statelock));

	/* paranoia */
	ASSERT((vsec->vsa_mask & VSA_ACL) || (vsec->vsa_aclcnt == 0));
	ASSERT((vsec->vsa_mask & VSA_DFACL) || (vsec->vsa_dfaclcnt == 0));
	if ((vsec->vsa_mask & VSA_ACL) == 0)
		vsec->vsa_aclcnt = 0;
	if ((vsec->vsa_mask & VSA_DFACL) == 0)
		vsec->vsa_dfaclcnt = 0;

	/* calculate length of ACL and cred data */
	alen = sizeof (aclent_t) * (vsec->vsa_aclcnt + vsec->vsa_dfaclcnt);
	clen = sizeof (dl_cred_t) + (((long)crgetngroups(cr)) * sizeof (gid_t));

	/*
	 * allocate entry.  ACLs may be up to 24k currently, but they
	 * usually won't, so we don't want to make cfs_dlog_entry_t
	 * too big.  so, we must compute the length here.
	 */

	len = sizeof (cfs_dlog_entry_t) - sizeof (up->dl_buffer) -
		sizeof (up->dl_cred) + alen + clen;


#if 0
	/* make up for weird behavior in cachefs_dlog_output */
	/* XXX turn this on/off in sync with code in cachefs_dlog_output */
	entp = cachefs_kmem_alloc(len + 32 + sizeof (struct cfs_dlog_trailer),
	    KM_SLEEP);
#else
	entp = cachefs_kmem_alloc(len, KM_SLEEP);
#endif

	entp->dl_valid = CFS_DLOG_VAL_CRASH;
	entp->dl_op = CFS_DLOG_SETSECATTR;

	up = &entp->dl_u.dl_setsecattr;
	up->dl_cid = cp->c_id;

	CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_mtime,
		&up->dl_times.tm_mtime, "cachefs_dlog_setsecattr: ", "mtime");
	CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_ctime,
		&up->dl_times.tm_ctime, "cachefs_dlog_setsecattr: ", "ctime");

	/* get the creds */
	(void) copy_cred(cr, &up->dl_cred);

	/* mask and counts */
	up->dl_mask = vsec->vsa_mask;
	up->dl_aclcnt = vsec->vsa_aclcnt;
	up->dl_dfaclcnt = vsec->vsa_dfaclcnt;

	/* get the acls themselves */
	aclp = (aclent_t *)((uintptr_t)(&up->dl_cred) + clen);
	if (vsec->vsa_aclcnt > 0) {
		bcopy(vsec->vsa_aclentp, aclp,
		    vsec->vsa_aclcnt * sizeof (aclent_t));
		aclp += vsec->vsa_aclcnt;
	}
	if (vsec->vsa_dfaclcnt > 0) {
		bcopy(vsec->vsa_dfaclentp, aclp,
		    vsec->vsa_dfaclcnt * sizeof (aclent_t));
	}

	entp->dl_len = (int)len;

	offset = cachefs_dlog_output(fscp, entp, NULL);

#if 0
	/* XXX turn on/off in sync with code in cachefs_dlog_output */
	cachefs_kmem_free(entp, len + 32 + sizeof (struct cfs_dlog_trailer));
#else
	cachefs_kmem_free(entp, len);
#endif

	return (offset);
}
Esempio n. 9
0
static bool_t
authkern_marshal(AUTH *auth, XDR *xdrs, struct cred *cr)
{
	char *sercred;
	XDR xdrm;
	struct opaque_auth *cred;
	bool_t ret = FALSE;
	const gid_t *gp, *gpend;
	int gidlen, credsize, namelen, rounded_namelen;
	int32_t *ptr;
	char *nodename = uts_nodename();

	/*
	 * First we try a fast path to get through
	 * this very common operation.
	 */
	gp = crgetgroups(cr);
	gidlen = crgetngroups(cr);
	if (gidlen > NGRPS)
		gidlen = NGRPS;
	gpend = &gp[gidlen-1];

	namelen = (int)strlen(nodename);
	rounded_namelen = RNDUP(namelen);
	credsize = 4 + 4 + rounded_namelen + 4 + 4 + 4 + gidlen * 4;
	ptr = XDR_INLINE(xdrs, 4 + 4 + credsize + 4 + 4);
	if (ptr) {
		/*
		 * We can do the fast path.
		 */
		IXDR_PUT_INT32(ptr, AUTH_UNIX);	/* cred flavor */
		IXDR_PUT_INT32(ptr, credsize);	/* cred len */
		IXDR_PUT_INT32(ptr, gethrestime_sec());
		IXDR_PUT_INT32(ptr, namelen);
		bcopy(nodename, (caddr_t)ptr, namelen);
		if (rounded_namelen - namelen)
			bzero(((caddr_t)ptr) + namelen,
			    rounded_namelen - namelen);
		ptr += rounded_namelen / BYTES_PER_XDR_UNIT;
		IXDR_PUT_INT32(ptr, crgetuid(cr));
		IXDR_PUT_INT32(ptr, crgetgid(cr));
		IXDR_PUT_INT32(ptr, gidlen);
		while (gp <= gpend) {
			IXDR_PUT_INT32(ptr, *gp++);
		}
		IXDR_PUT_INT32(ptr, AUTH_NULL);	/* verf flavor */
		IXDR_PUT_INT32(ptr, 0);	/* verf len */
		return (TRUE);
	}
	sercred = kmem_alloc(MAX_AUTH_BYTES, KM_SLEEP);
	/*
	 * serialize u struct stuff into sercred
	 */
	xdrmem_create(&xdrm, sercred, MAX_AUTH_BYTES, XDR_ENCODE);
	if (!xdr_authkern(&xdrm)) {
		printf("authkern_marshal: xdr_authkern failed\n");
		ret = FALSE;
		goto done;
	}

	/*
	 * Make opaque auth credentials that point at serialized u struct
	 */
	cred = &(auth->ah_cred);
	cred->oa_length = XDR_GETPOS(&xdrm);
	cred->oa_base = sercred;

	/*
	 * serialize credentials and verifiers (null)
	 */
	if ((xdr_opaque_auth(xdrs, &(auth->ah_cred))) &&
	    (xdr_opaque_auth(xdrs, &(auth->ah_verf))))
		ret = TRUE;
	else
		ret = FALSE;
done:
	kmem_free(sercred, MAX_AUTH_BYTES);
	return (ret);
}
Esempio n. 10
0
/*
 * Callup to the mountd to get access information in the kernel.
 */
static bool_t
nfsauth_retrieve(struct exportinfo *exi, char *req_netid, int flavor,
    struct netbuf *addr, int *access, cred_t *clnt_cred, uid_t *srv_uid,
    gid_t *srv_gid, uint_t *srv_gids_cnt, gid_t **srv_gids)
{
	varg_t			  varg = {0};
	nfsauth_res_t		  res = {0};
	XDR			  xdrs;
	size_t			  absz;
	caddr_t			  abuf;
	int			  last = 0;
	door_arg_t		  da;
	door_info_t		  di;
	door_handle_t		  dh;
	uint_t			  ntries = 0;

	/*
	 * No entry in the cache for this client/flavor
	 * so we need to call the nfsauth service in the
	 * mount daemon.
	 */

	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 = req_netid;
	varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path;
	varg.arg_u.arg.areq.req_flavor = flavor;
	varg.arg_u.arg.areq.req_clnt_uid = crgetuid(clnt_cred);
	varg.arg_u.arg.areq.req_clnt_gid = crgetgid(clnt_cred);
	varg.arg_u.arg.areq.req_clnt_gids.len = crgetngroups(clnt_cred);
	varg.arg_u.arg.areq.req_clnt_gids.val = (gid_t *)crgetgroups(clnt_cred);

	DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg);

	/*
	 * 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.
	 */
	if ((absz = xdr_sizeof(xdr_varg, &varg)) == 0) {
		*access = NFSAUTH_DENIED;
		return (FALSE);
	}

	abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP);
	xdrmem_create(&xdrs, abuf, absz, XDR_ENCODE);
	if (!xdr_varg(&xdrs, &varg)) {
		XDR_DESTROY(&xdrs);
		goto fail;
	}
	XDR_DESTROY(&xdrs);

	/*
	 * Prepare the door arguments
	 *
	 * We don't know the size of the message the daemon
	 * will pass back to us.  By setting rbuf to NULL,
	 * we force the door code to allocate a buf of the
	 * appropriate size.  We must set rsize > 0, however,
	 * else the door code acts as if no response was
	 * expected and doesn't pass the data to us.
	 */
	da.data_ptr = (char *)abuf;
	da.data_size = absz;
	da.desc_ptr = NULL;
	da.desc_num = 0;
	da.rbuf = NULL;
	da.rsize = 1;

retry:
	mutex_enter(&mountd_lock);
	dh = mountd_dh;
	if (dh != NULL)
		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;
		}

		kmem_free(abuf, absz);

		sys_log("nfsauth: mountd has not established door");
		*access = NFSAUTH_DROP;
		return (FALSE);
	}

	ntries = 0;

	/*
	 * Now that we've got what we need, place the call.
	 */
	switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) {
	case 0:				/* Success */
		door_ki_rele(dh);

		if (da.data_ptr == NULL && 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);
			goto fail;
		}

		break;

	case EAGAIN:
		/*
		 * Server out of resources; back off for a bit
		 */
		door_ki_rele(dh);
		delay(hz);
		goto retry;
		/* NOTREACHED */

	case EINTR:
		if (!door_ki_info(dh, &di)) {
			door_ki_rele(dh);

			if (di.di_attributes & DOOR_REVOKED) {
				/*
				 * The server barfed and revoked
				 * the (existing) door on us; we
				 * want to wait to give smf(5) a
				 * chance to restart mountd(1m)
				 * and establish a new door handle.
				 */
				mutex_enter(&mountd_lock);
				if (dh == mountd_dh) {
					door_ki_rele(mountd_dh);
					mountd_dh = NULL;
				}
				mutex_exit(&mountd_lock);
				delay(hz);
				goto retry;
			}
			/*
			 * If the door was _not_ revoked on us,
			 * then more than likely we took an INTR,
			 * so we need to fail the operation.
			 */
			goto fail;
		}
		/*
		 * The only failure that can occur from getting
		 * the door info is EINVAL, so we let the code
		 * below handle it.
		 */
		/* FALLTHROUGH */

	case EBADF:
	case EINVAL:
	default:
		/*
		 * If we have a stale door handle, give smf a last
		 * chance to start it by sleeping for a little bit.
		 * If we're still hosed, we'll fail the call.
		 *
		 * Since we're going to reacquire the door handle
		 * upon the retry, we opt to sleep for a bit and
		 * _not_ to clear mountd_dh. If mountd restarted
		 * and was able to set mountd_dh, we should see
		 * the new instance; if not, we won't get caught
		 * up in the retry/DELAY loop.
		 */
		door_ki_rele(dh);
		if (!last) {
			delay(hz);
			last++;
			goto retry;
		}
		sys_log("nfsauth: stale mountd door handle");
		goto fail;
	}