From owner-freebsd-hackers Sat Nov 8 20:38:10 1997 Return-Path: Received: (from root@localhost) by hub.freebsd.org (8.8.7/8.8.7) id UAA13122 for hackers-outgoing; Sat, 8 Nov 1997 20:38:10 -0800 (PST) (envelope-from owner-freebsd-hackers) Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (8.8.7/8.8.7) with ESMTP id UAA13113 for ; Sat, 8 Nov 1997 20:38:08 -0800 (PST) (envelope-from julian@FreeBSD.org) From: Julian Elischer Received: (from julian@localhost) by freefall.freebsd.org (8.8.6/8.8.5) id UAA26951 for hackers; Sat, 8 Nov 1997 20:36:20 -0800 (PST) Date: Sat, 8 Nov 1997 20:36:20 -0800 (PST) Message-Id: <199711090436.UAA26951@freefall.freebsd.org> To: hackers@FreeBSD.ORG Subject: How useful is this patch? Sender: owner-freebsd-hackers@FreeBSD.ORG X-Loop: FreeBSD.org Precedence: bulk In an application we have, several (many) naive PC and MAC users are using SAMBA, FTP, and NETATALK, to access a filesystem. (under FreeBSD) The problem is that there are cases where one unpriveliged user needs to put files in the 'home directories' of other users. This is OK as long as the owner of the directory can delete them. For single files this is the case, however when the other user needs to put a hierarchy of directories there, the poor owner of the original directory can't because the directories are owned by someone else, and they are not empty, so there is a catch 22, and they cannot be deleted. These users, as I said before are simplistic, there are thousands of them, and they (ALL OF THEM) don't like the answer "Oh that's the way UNIX works". it gets more complicated when you start adding .AppleDouble directories from netatalk, which may be created by an admin, using a MAC, but which are invisible to both the MAC and SAMBA users. They will be owned by the admin and the user can't see why he can't delete the directry. There are two answers. 1/ A CRAWLER that sets the ownerships of all user's directories contents to the user. Simple, but not immediate, and I don't think it's the right answer. 2/ A HACK to UFS. Here is the hack idea. if a mount option is specified, then setting the SUID bit on a directory specifies similar inheritance with UIDS as we presently have with GIDs. In other words, if the USER's home directory is SUID, then when user B places a hierarchy of files into USER A's directory, they become owned by user A. This corresponds exactly with how naive PC users expect things to work. "It's in my folder so it's mine" The SUID bits are hereditary to child directories, and a file 'given away' in this manner 1/ cannot be give n to root (would defeat quotas) 2/ has the execute bits stripped off (and suid) The advantage to this is that SAMBA and NETATALK, FTP and any other utilities one may think of, suddenly all start exhibiting 'DOS-USER friendly' behaviour, without needing to change and maintain those packages. It can also be turned on and off so that it would not be turned on in parts of the filesystem used by 'real' users. THOUGHTS PLEASE! (is it useful enough to add to the tree?) here's the patch. the first part is for making new directories, while the second part is for making new files. Index: ufs_vnops.c =================================================================== RCS file: /cvs/freebsd/src/sys/ufs/ufs/ufs_vnops.c,v retrieving revision 1.41.2.3 diff -c -r1.41.2.3 ufs_vnops.c *** 1.41.2.3 1997/06/29 08:48:50 --- ufs_vnops.c 1997/11/09 03:58:50 *************** *** 1301,1308 **** if (error) goto out; ip = VTOI(tvp); - ip->i_uid = cnp->cn_cred->cr_uid; ip->i_gid = dp->i_gid; #ifdef QUOTA if ((error = getinoquota(ip)) || (error = chkiq(ip, 1, cnp->cn_cred, 0))) { --- 1301,1358 ---- if (error) goto out; ip = VTOI(tvp); ip->i_gid = dp->i_gid; + #ifdef USE_SUIDDIR + { + #ifdef QUOTA + struct ucred ucred, *ucp; + ucp = cnp->cn_cred + #endif I + /* + * if we are hacking owners here, (only do this where told to) + * and we are not giving it TOO root, (would subvert quotas) + * then go ahead and give it to the other user. + * The new directory also inherits the SUID bit. + * If user's UID an ddir UID are the same, + * 'give it away' so that the SUID is still forced on. + */ + if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) + && (dp->i_mode & ISUID) + && dp->i_uid) { + dmode |= ISUID; + ip->i_uid = dp->i_uid; + #ifdef QUOTA + if (pdir->i_uid != cnp->cn_cred->cr_uid) { + /* + * make sure the correct user gets charged + * for the space. + * Make a dummy credential for the victim. + * XXX This seems to never be accessed out of + * our context so a stack variable is ok. + */ + ucred.cr_ref = 1 + ucred.cr_uid = ip->i_uid; + ucred.cr_ngroups = 1 + ucred.cr_groups[0] = dp->i_gid; + ucp = *ucred; + } + #endif I + } else { + ip->i_uid = cnp->cn_cred->cr_uid; + } + #ifdef QUOTA + if ((error = getinoquota(ip)) || + (error = chkiq(ip, 1, ucp, 0))) { + free(cnp->cn_pnbuf, M_NAMEI); + VOP_VFREE(tvp, ip->i_number, dmode); + vput(tvp); + vput(dvp); + return (error); + } + #endif + } + #else + ip->i_uid = cnp->cn_cred->cr_uid; #ifdef QUOTA if ((error = getinoquota(ip)) || (error = chkiq(ip, 1, cnp->cn_cred, 0))) { *************** *** 1313,1318 **** --- 1364,1370 ---- return (error); } #endif + #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = dmode; tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ *************** *** 2131,2136 **** --- 2183,2238 ---- } ip = VTOI(tvp); ip->i_gid = pdir->i_gid; + #ifdef USE_SUIDDIR + { + #ifdef QUOTA + struct ucred ucred, *ucp; + ucp = cnp->cn_cred + #endif I + /* + * if we are + * not the owner of the directory, + * and we are hacking owners here, (only do this where told to) + * and we are not giving it TOO root, (would subvert quotas) + * then go ahead and give it to the other user. + * Note that this drops off the execute bits for security. + */ + if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) + && (pdir->i_mode & ISUID) + && (pdir->i_uid != cnp->cn_cred->cr_uid) + && pdir->i_uid) { + ip->i_uid = pdir->i_uid; + mode &= ~07111; + #ifdef QUOTA + /* + * make sure the correct user gets charged + * for the space. + * Quickly knock up a dummy credential for the victim. + * XXX This seems to never be accessed out of our + * context so a stack variable is ok. + */ + ucred.cr_ref = 1 + ucred.cr_uid = ip->i_uid; + ucred.cr_ngroups = 1 + ucred.cr_groups[0] = pdir->i_gid; + ucp = *ucred; + #endif I + } else { + ip->i_uid = cnp->cn_cred->cr_uid; + } + + #ifdef QUOTA + if ((error = getinoquota(ip)) || + (error = chkiq(ip, 1, ucp, 0))) { + free(cnp->cn_pnbuf, M_NAMEI); + VOP_VFREE(tvp, ip->i_number, mode); + vput(tvp); + vput(dvp); + return (error); + } + #endif + } + #else ip->i_uid = cnp->cn_cred->cr_uid; #ifdef QUOTA if ((error = getinoquota(ip)) || *************** *** 2141,2146 **** --- 2244,2250 ---- vput(dvp); return (error); } + #endif #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = mode; ...--end--