Module Name:    src
Committed By:   manu
Date:           Sat Aug 28 03:46:21 UTC 2010

Modified Files:
        src/lib/libperfuse: ops.c perfuse.c

Log Message:
- set user/group ownership after object creation.

- enforce permissios checks. This needs to be  reviewed.


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/lib/libperfuse/ops.c
cvs rdiff -u -r1.2 -r1.3 src/lib/libperfuse/perfuse.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libperfuse/ops.c
diff -u src/lib/libperfuse/ops.c:1.3 src/lib/libperfuse/ops.c:1.4
--- src/lib/libperfuse/ops.c:1.3	Fri Aug 27 09:58:17 2010
+++ src/lib/libperfuse/ops.c	Sat Aug 28 03:46:21 2010
@@ -1,4 +1,4 @@
-/*  $NetBSD: ops.c,v 1.3 2010/08/27 09:58:17 manu Exp $ */
+/*  $NetBSD: ops.c,v 1.4 2010/08/28 03:46:21 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -41,6 +41,7 @@
 #include "perfuse_priv.h"
 #include "fuse.h"
 
+static int no_access(puffs_cookie_t, const struct puffs_cred *, mode_t);
 static void fuse_attr_to_vap(struct perfuse_state *,
     struct vattr *, struct fuse_attr *);
 static int node_lookup_dir_nodot(struct puffs_usermount *,
@@ -48,7 +49,8 @@
 static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t, 
     const char*, struct puffs_node **);
 static int node_mk_common(struct puffs_usermount *, puffs_cookie_t,
-    struct puffs_newinfo *, perfuse_msg_t *);
+    struct puffs_newinfo *, const struct puffs_cn *pcn,
+    const struct vattr *, perfuse_msg_t *);
 static const char *basename_r(const char *);
 static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t,
     struct fuse_dirent *, size_t);
@@ -90,6 +92,23 @@
 #define VTTOIF(indx) (vttoif_tab[(int)(indx)])
 
 
+static int
+no_access(opc, pcr, mode)
+	puffs_cookie_t opc;
+	const struct puffs_cred *pcr;
+	mode_t mode;
+{
+	struct puffs_node *pn;
+	struct vattr *va;
+
+	pn = (struct puffs_node *)opc;
+	va = puffs_pn_getvap(pn);
+
+	return puffs_access(va->va_type, va->va_mode, 
+			    va->va_uid, va->va_gid,
+			    mode, pcr);
+}
+
 static void
 fuse_attr_to_vap(ps, vap, fa)
 	struct perfuse_state *ps;
@@ -222,15 +241,18 @@
  * perfuse_node_symlink
  */
 static int
-node_mk_common(pu, opc, pni, pm)
+node_mk_common(pu, opc, pni, pcn, vap, pm)
 	struct puffs_usermount *pu;
 	puffs_cookie_t opc;
 	struct puffs_newinfo *pni;
+	const struct puffs_cn *pcn;
+	const struct vattr *vap;
 	perfuse_msg_t *pm;
 {
 	struct perfuse_state *ps;
 	struct puffs_node *pn;
 	struct fuse_entry_out *feo;
+	struct fuse_setattr_in *fsi;
 	int error;
 
 	ps =  puffs_getspecific(pu);
@@ -247,6 +269,25 @@
 
 	fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
 	puffs_newinfo_setcookie(pni, pn);
+	ps->ps_destroy_msg(pm);
+ 
+	/* 
+	 * Set owner and group
+	 */
+	(void)puffs_cred_getuid(pcn->pcn_cred, &pn->pn_va.va_uid);
+	(void)puffs_cred_getgid(pcn->pcn_cred, &pn->pn_va.va_gid);
+
+	pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, 
+			    FUSE_SETATTR, sizeof(*fsi), NULL);
+	fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
+	fsi->uid = pn->pn_va.va_uid;
+	fsi->gid = pn->pn_va.va_gid;
+	fsi->valid = FUSE_FATTR_UID|FUSE_FATTR_GID;
+
+	/*
+	 * A fuse_attr_out is returned, but we ignore it.
+	 */
+	error = XCHG_MSG(ps, pu, pm, sizeof(struct fuse_attr_out));
 
 out:
 	ps->ps_destroy_msg(pm);
@@ -807,6 +848,12 @@
 	int error;
 	
 	/*
+	 * Create an object require -WX permission in the parent directory
+	 */
+	if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
+		return EACCES;
+
+	/*
 	 * If create is unimplemented: Check that it does not
 	 * already exists, and if not, do mknod and open
 	 */
@@ -888,6 +935,28 @@
 	const char* path;
 	size_t len;
 	
+	/*
+	 * Only superuser can mknod objects other than 
+	 * directories, files, socks, fifo and links.
+	 *
+	 * Create an object require -WX permission in the parent directory
+	 */
+	switch (vap->va_type) {
+	case VDIR:	/* FALLTHROUGH */
+	case VREG:	/* FALLTHROUGH */
+	case VFIFO:	/* FALLTHROUGH */
+	case VSOCK:	/* FALLTHROUGH */
+	case VLNK:
+		if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
+			return EACCES;
+		break;
+	default:	/* VNON, VBLK, VCHR, VBAD */
+		if (!puffs_cred_isjuggernaut(pcn->pcn_cred))
+			return EACCES;
+		break;
+	}
+
+
 	ps = puffs_getspecific(pu);
 	path = basename_r((char *)PCNPATH(pcn));
 	len = sizeof(*fmi) + strlen(path) + 1; 
@@ -899,7 +968,7 @@
 	fmi->umask = 0; 	/* Seems unused bu libfuse */
 	(void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
 
-	return node_mk_common(pu, opc, pni, pm);
+	return node_mk_common(pu, opc, pni, pcn, vap, pm);
 }
 
 
@@ -912,6 +981,7 @@
 {
 	struct perfuse_state *ps;
 	perfuse_msg_t *pm;
+	mode_t pmode;
 	int op;
 	struct fuse_open_in *foi;
 	struct fuse_open_out *foo;
@@ -921,10 +991,28 @@
 	ps = puffs_getspecific(pu);
 
 	pn = (struct puffs_node *)opc;
-	if (puffs_pn_getvap(pn)->va_type == VDIR)
+	if (puffs_pn_getvap(pn)->va_type == VDIR) {
 		op = FUSE_OPENDIR;
-	else
+		pmode = PUFFS_VREAD|PUFFS_VEXEC;
+	} else {
 		op = FUSE_OPEN;
+		if (mode & (O_RDWR|O_WRONLY))
+			pmode = PUFFS_VWRITE;
+		else
+			pmode = PUFFS_VREAD;
+	}
+
+	/*
+	 * Opening a directory require R-X on the directory
+	 * Opening a file requires R-- for reading, -W- for writing
+	 * In both cases, --X is required on the parent.
+	 */
+	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
+	    pcr, PUFFS_VEXEC))
+		return EACCES;
+
+	if (no_access(opc, pcr, pmode))
+		return EACCES;
 
 	/*
 	 * libfuse docs say O_CREAT should not be set.
@@ -1007,7 +1095,6 @@
 
 	/*
 	 * Sync before close for files
-	 * XXX no pcr argument to pass
 	 */
 	if ((op == FUSE_RELEASE) && (pnd->pnd_flags & PND_DIRTY)) {
 #ifdef PERFUSE_DEBUG
@@ -1015,7 +1102,7 @@
 			DPRINTF("%s: SYNC opc = %p, file = \"%s\"\n", 
 				__func__, (void*)opc, (char *)PNPATH(pn));
 #endif
-		if ((error = perfuse_node_fsync(pu, opc, NULL, 0, 0, 0)) != 0)
+		if ((error = perfuse_node_fsync(pu, opc, pcr, 0, 0, 0)) != 0)
 			return error;
 
 		pnd->pnd_flags &= ~PND_DIRTY;
@@ -1151,6 +1238,13 @@
 	struct fuse_attr_out *fao;
 	int error;
 	
+	/*
+	 * getattr requires --X on the parent directory
+	 */
+	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
+	    pcr, PUFFS_VEXEC))
+		return EACCES;
+
 	ps = puffs_getspecific(pu);
 
 	/*
@@ -1196,7 +1290,51 @@
 	struct perfuse_state *ps;
 	struct fuse_setattr_in *fsi;
 	int error;
+	struct vattr *old_va;
+
+	/*
+	 * setattr requires --X on the parent directory
+	 */
+	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
+	    pcr, PUFFS_VEXEC))
+		return EACCES;
+
+	old_va = puffs_pn_getvap((struct puffs_node *)opc);
+
+	/*
+	 * Check for permission to change size
+	 */
+	if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
+	    no_access(opc, pcr, PUFFS_VWRITE))
+		return EACCES;
+
+	/*
+	 * Check for permission to change dates
+	 */
+	if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) ||
+	     (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) &&
+	    (puffs_access_times(old_va->va_uid, old_va->va_gid,
+				old_va->va_mode, 0, pcr) != 0))
+		return EACCES;
+
+	/*
+	 * Check for permission to change owner and group
+	 */
+	if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) ||
+	     (vap->va_gid != (gid_t)PUFFS_VNOVAL)) &&
+	    (puffs_access_chown(old_va->va_uid, old_va->va_gid,
+				vap->va_uid, vap->va_gid, pcr)) != 0)
+		return EACCES;
+
+	/*
+	 * Check for permission to change permissions
+	 */
+	if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) &&
+	    (puffs_access_chmod(old_va->va_uid, old_va->va_gid,
+				 old_va->va_type, vap->va_mode, pcr)) != 0)
+		return EACCES;
 	
+
 	ps = puffs_getspecific(pu);
 
 	pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
@@ -1445,6 +1583,14 @@
 	size_t len;
 	int error;
 	
+	/*
+	 * remove requires -WX on the parent directory 
+	 * no right required on the object.
+	 */
+	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
+	    pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
+		return EACCES;
+
 	ps = puffs_getspecific(pu);
 
 	if (targ == NULL)
@@ -1493,6 +1639,13 @@
 	struct fuse_link_in *fli;
 	int error;
 	
+	/*
+	 * Create an object require -WX permission in the parent directory
+	 */
+	if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
+		return EACCES;
+
+
 	ps = puffs_getspecific(pu);
 	pn = (struct puffs_node *)targ;
 	name = basename_r((char *)PCNPATH(pcn));
@@ -1533,6 +1686,13 @@
 	size_t newname_len;
 	size_t oldname_len;
 	
+	/*
+	 * move requires -WX on source and destination directory 
+	 */
+	if (no_access(src, pcn_src->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC) ||
+	    no_access(targ,  pcn_targ->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
+		return EACCES;
+
 	ps = puffs_getspecific(pu);
 	newname =  basename_r((char *)PCNPATH(pcn_targ));
 	newname_len = strlen(newname) + 1;
@@ -1579,6 +1739,12 @@
 	const char *path;
 	size_t len;
 	
+	/*
+	 * Create an object require -WX permission in the parent directory
+	 */
+	if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
+		return EACCES;
+
 	ps = puffs_getspecific(pu);
 	path = basename_r((char *)PCNPATH(pcn));
 	len = sizeof(*fmi) + strlen(path) + 1; 
@@ -1589,7 +1755,7 @@
 	fmi->umask = 0; 	/* Seems unused bu libfuse? */
 	(void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
 
-	return node_mk_common(pu, opc, pni, pm);
+	return node_mk_common(pu, opc, pni, pcn, vap, pm);
 }
 
 
@@ -1608,6 +1774,14 @@
 	size_t len;
 	int error;
 	
+	/*
+	 * remove requires -WX on the parent directory 
+	 * no right required on the object.
+	 */
+	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
+	    pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
+		return EACCES;
+
 	ps = puffs_getspecific(pu);
 	pn = (struct puffs_node *)targ;
 	name = basename_r((char *)PNPATH(pn));
@@ -1653,6 +1827,12 @@
 	size_t linkname_len;
 	size_t len;
 	
+	/*
+	 * Create an object require -WX permission in the parent directory
+	 */
+	if (no_access(opc, pcn_src->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
+		return EACCES;
+
 	ps = puffs_getspecific(pu);
 	path = basename_r((char *)PCNPATH(pcn_src));
 	path_len = strlen(path) + 1;
@@ -1665,7 +1845,7 @@
 	np += path_len;
 	(void)strlcpy(np, link_target, linkname_len);
 
-	return node_mk_common(pu, opc, pni, pm);
+	return node_mk_common(pu, opc, pni, pcn_src, vap, pm);
 }
 
 int 
@@ -1868,6 +2048,14 @@
 	size_t len;
 	struct fuse_out_header *foh;
 	
+	/* 
+	 * --X required on parent, R-- required on link
+	 */
+	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
+	    pcr, PUFFS_VEXEC) ||
+	   no_access(opc, pcr, PUFFS_VREAD))
+		return EACCES;
+
 	ps = puffs_getspecific(pu);
 
 	pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr);

Index: src/lib/libperfuse/perfuse.c
diff -u src/lib/libperfuse/perfuse.c:1.2 src/lib/libperfuse/perfuse.c:1.3
--- src/lib/libperfuse/perfuse.c:1.2	Fri Aug 27 09:58:17 2010
+++ src/lib/libperfuse/perfuse.c	Sat Aug 28 03:46:21 2010
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfuse.c,v 1.2 2010/08/27 09:58:17 manu Exp $ */
+/*  $NetBSD: perfuse.c,v 1.3 2010/08/28 03:46:21 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -362,6 +362,7 @@
 	 */
 	pn_root = perfuse_new_pn(pu, NULL);
 	PERFUSE_NODE_DATA(pn_root)->pnd_ino = FUSE_ROOT_ID; 
+	PERFUSE_NODE_DATA(pn_root)->pnd_parent = pn_root;
 	puffs_setroot(pu, pn_root);
 	ps->ps_fsid = pn_root->pn_va.va_fsid;
 	

Reply via email to