From 900c29f67a4de398a1ead486e665903c749ade36 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 2 Jun 1997 06:24:52 +0000 Subject: [PATCH] Submitted by: Whistle Communications (archie Cobbs) These changes add the ability to specify that a UFS file/directory cannot be unlinked. This is basically a scaled back version of the IMMUTABLE flag. The reason is to allow an administrator to create a directory hierarchy that a group of users can arbitrarily add/delete files from, but that the hierarchy itself is safe from removal by them. If the NOUNLINK definition is set to 0 then this results in no change to what happens normally. (and results in identical binary (in the kernel)). It can be proven that if this bit is never set by the admin, no new behaviour is introduced.. Several "good idea" comments from reviewers plus one grumble about creeping featurism. This code is in production in 2.2 based systems --- bin/chflags/chflags.1 | 5 ++++- bin/ls/stat_flags.c | 10 +++++++++- lib/libc/gen/setflags.c | 10 +++++++++- lib/libc/gen/setflagsbyname.c | 10 +++++++++- lib/libc/gen/strtofflags.c | 10 +++++++++- lib/libc/sys/chflags.2 | 12 ++++++++++-- lib/libutil/stat_flags.c | 10 +++++++++- sys/sys/stat.h | 5 ++++- sys/ufs/ufs/ufs_vnops.c | 18 +++++++++++------- usr.bin/chflags/chflags.1 | 5 ++++- 10 files changed, 78 insertions(+), 17 deletions(-) diff --git a/bin/chflags/chflags.1 b/bin/chflags/chflags.1 index 9c808a0094b3..9ab880f597b8 100644 --- a/bin/chflags/chflags.1 +++ b/bin/chflags/chflags.1 @@ -83,9 +83,12 @@ arch set the archived flag (super-user only) dump set the dump flag sappnd set the system append-only flag (super-user only) schg set the system immutable flag (super-user only) +sunlnk set the system undeletable flag (super-user only) uappnd set the user append-only flag (owner or super-user only) uchg set the user immutable flag (owner or super-user only) -archived, sappend, schange, simmutable, uappend, uchange, uimmutable +uunlnk set the user undeletable flag (owner or super-user only) +archived, sappend, schange, simmutable, uappend, uchange, uimmutable, +sunlink, uunlink aliases for the above .Ed .Pp diff --git a/bin/ls/stat_flags.c b/bin/ls/stat_flags.c index f0092fed9c49..b1e70628e527 100644 --- a/bin/ls/stat_flags.c +++ b/bin/ls/stat_flags.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: stat_flags.c,v 1.5 1997/02/22 14:04:02 peter Exp $ */ #ifndef lint @@ -69,6 +69,8 @@ flags_to_string(flags, def) SAPPEND("uappnd"); if (flags & UF_IMMUTABLE) SAPPEND("uchg"); + if (flags & UF_NOUNLINK) + SAPPEND("uunlnk"); if (flags & UF_NODUMP) SAPPEND("nodump"); if (flags & UF_OPAQUE) @@ -79,6 +81,8 @@ flags_to_string(flags, def) SAPPEND("arch"); if (flags & SF_IMMUTABLE) SAPPEND("schg"); + if (flags & SF_NOUNLINK) + SAPPEND("sunlnk"); return (prefix == NULL && def != NULL ? def : string); } @@ -139,6 +143,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "schg", SF_IMMUTABLE); TEST(p, "schange", SF_IMMUTABLE); TEST(p, "simmutable", SF_IMMUTABLE); + TEST(p, "sunlnk", SF_NOUNLINK); + TEST(p, "sunlink", SF_NOUNLINK); return (1); case 'u': TEST(p, "uappnd", UF_APPEND); @@ -146,6 +152,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "uchg", UF_IMMUTABLE); TEST(p, "uchange", UF_IMMUTABLE); TEST(p, "uimmutable", UF_IMMUTABLE); + TEST(p, "uunlnk", UF_NOUNLINK); + TEST(p, "uunlink", UF_NOUNLINK); /* FALLTHROUGH */ default: return (1); diff --git a/lib/libc/gen/setflags.c b/lib/libc/gen/setflags.c index f0092fed9c49..b1e70628e527 100644 --- a/lib/libc/gen/setflags.c +++ b/lib/libc/gen/setflags.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: stat_flags.c,v 1.5 1997/02/22 14:04:02 peter Exp $ */ #ifndef lint @@ -69,6 +69,8 @@ flags_to_string(flags, def) SAPPEND("uappnd"); if (flags & UF_IMMUTABLE) SAPPEND("uchg"); + if (flags & UF_NOUNLINK) + SAPPEND("uunlnk"); if (flags & UF_NODUMP) SAPPEND("nodump"); if (flags & UF_OPAQUE) @@ -79,6 +81,8 @@ flags_to_string(flags, def) SAPPEND("arch"); if (flags & SF_IMMUTABLE) SAPPEND("schg"); + if (flags & SF_NOUNLINK) + SAPPEND("sunlnk"); return (prefix == NULL && def != NULL ? def : string); } @@ -139,6 +143,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "schg", SF_IMMUTABLE); TEST(p, "schange", SF_IMMUTABLE); TEST(p, "simmutable", SF_IMMUTABLE); + TEST(p, "sunlnk", SF_NOUNLINK); + TEST(p, "sunlink", SF_NOUNLINK); return (1); case 'u': TEST(p, "uappnd", UF_APPEND); @@ -146,6 +152,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "uchg", UF_IMMUTABLE); TEST(p, "uchange", UF_IMMUTABLE); TEST(p, "uimmutable", UF_IMMUTABLE); + TEST(p, "uunlnk", UF_NOUNLINK); + TEST(p, "uunlink", UF_NOUNLINK); /* FALLTHROUGH */ default: return (1); diff --git a/lib/libc/gen/setflagsbyname.c b/lib/libc/gen/setflagsbyname.c index f0092fed9c49..b1e70628e527 100644 --- a/lib/libc/gen/setflagsbyname.c +++ b/lib/libc/gen/setflagsbyname.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: stat_flags.c,v 1.5 1997/02/22 14:04:02 peter Exp $ */ #ifndef lint @@ -69,6 +69,8 @@ flags_to_string(flags, def) SAPPEND("uappnd"); if (flags & UF_IMMUTABLE) SAPPEND("uchg"); + if (flags & UF_NOUNLINK) + SAPPEND("uunlnk"); if (flags & UF_NODUMP) SAPPEND("nodump"); if (flags & UF_OPAQUE) @@ -79,6 +81,8 @@ flags_to_string(flags, def) SAPPEND("arch"); if (flags & SF_IMMUTABLE) SAPPEND("schg"); + if (flags & SF_NOUNLINK) + SAPPEND("sunlnk"); return (prefix == NULL && def != NULL ? def : string); } @@ -139,6 +143,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "schg", SF_IMMUTABLE); TEST(p, "schange", SF_IMMUTABLE); TEST(p, "simmutable", SF_IMMUTABLE); + TEST(p, "sunlnk", SF_NOUNLINK); + TEST(p, "sunlink", SF_NOUNLINK); return (1); case 'u': TEST(p, "uappnd", UF_APPEND); @@ -146,6 +152,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "uchg", UF_IMMUTABLE); TEST(p, "uchange", UF_IMMUTABLE); TEST(p, "uimmutable", UF_IMMUTABLE); + TEST(p, "uunlnk", UF_NOUNLINK); + TEST(p, "uunlink", UF_NOUNLINK); /* FALLTHROUGH */ default: return (1); diff --git a/lib/libc/gen/strtofflags.c b/lib/libc/gen/strtofflags.c index f0092fed9c49..b1e70628e527 100644 --- a/lib/libc/gen/strtofflags.c +++ b/lib/libc/gen/strtofflags.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: stat_flags.c,v 1.5 1997/02/22 14:04:02 peter Exp $ */ #ifndef lint @@ -69,6 +69,8 @@ flags_to_string(flags, def) SAPPEND("uappnd"); if (flags & UF_IMMUTABLE) SAPPEND("uchg"); + if (flags & UF_NOUNLINK) + SAPPEND("uunlnk"); if (flags & UF_NODUMP) SAPPEND("nodump"); if (flags & UF_OPAQUE) @@ -79,6 +81,8 @@ flags_to_string(flags, def) SAPPEND("arch"); if (flags & SF_IMMUTABLE) SAPPEND("schg"); + if (flags & SF_NOUNLINK) + SAPPEND("sunlnk"); return (prefix == NULL && def != NULL ? def : string); } @@ -139,6 +143,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "schg", SF_IMMUTABLE); TEST(p, "schange", SF_IMMUTABLE); TEST(p, "simmutable", SF_IMMUTABLE); + TEST(p, "sunlnk", SF_NOUNLINK); + TEST(p, "sunlink", SF_NOUNLINK); return (1); case 'u': TEST(p, "uappnd", UF_APPEND); @@ -146,6 +152,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "uchg", UF_IMMUTABLE); TEST(p, "uchange", UF_IMMUTABLE); TEST(p, "uimmutable", UF_IMMUTABLE); + TEST(p, "uunlnk", UF_NOUNLINK); + TEST(p, "uunlink", UF_NOUNLINK); /* FALLTHROUGH */ default: return (1); diff --git a/lib/libc/sys/chflags.2 b/lib/libc/sys/chflags.2 index 94b744ca9c80..3305b3a2aef5 100644 --- a/lib/libc/sys/chflags.2 +++ b/lib/libc/sys/chflags.2 @@ -65,6 +65,8 @@ Do not dump the file. The file may not be changed. .It UF_APPEND The file may only be appended to. +.It UF_NOUNLINK +The file may not be renamed or deleted. .It UF_OPAQUE The directory is opaque when viewed through a union stack. .\".It ARCHIVED @@ -73,18 +75,24 @@ The directory is opaque when viewed through a union stack. The file may not be changed. .It SF_APPEND The file may only be appended to. +.It SF_NOUNLINK +The file may not be renamed or deleted. .El .Pp The .Dq UF_IMMUTABLE -and +, .Dq UF_APPEND +and +.Dq UF_NOUNLINK flags may be set or unset by either the owner of a file or the super-user. .Pp The .Dq SF_IMMUTABLE -and +, .Dq SF_APPEND +and +.Dq SF_NOUNLINK flags may only be set or unset by the super-user. Attempts by the non-super-user to set the super-user only flags are silently ignored. diff --git a/lib/libutil/stat_flags.c b/lib/libutil/stat_flags.c index f0092fed9c49..b1e70628e527 100644 --- a/lib/libutil/stat_flags.c +++ b/lib/libutil/stat_flags.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: stat_flags.c,v 1.5 1997/02/22 14:04:02 peter Exp $ */ #ifndef lint @@ -69,6 +69,8 @@ flags_to_string(flags, def) SAPPEND("uappnd"); if (flags & UF_IMMUTABLE) SAPPEND("uchg"); + if (flags & UF_NOUNLINK) + SAPPEND("uunlnk"); if (flags & UF_NODUMP) SAPPEND("nodump"); if (flags & UF_OPAQUE) @@ -79,6 +81,8 @@ flags_to_string(flags, def) SAPPEND("arch"); if (flags & SF_IMMUTABLE) SAPPEND("schg"); + if (flags & SF_NOUNLINK) + SAPPEND("sunlnk"); return (prefix == NULL && def != NULL ? def : string); } @@ -139,6 +143,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "schg", SF_IMMUTABLE); TEST(p, "schange", SF_IMMUTABLE); TEST(p, "simmutable", SF_IMMUTABLE); + TEST(p, "sunlnk", SF_NOUNLINK); + TEST(p, "sunlink", SF_NOUNLINK); return (1); case 'u': TEST(p, "uappnd", UF_APPEND); @@ -146,6 +152,8 @@ string_to_flags(stringp, setp, clrp) TEST(p, "uchg", UF_IMMUTABLE); TEST(p, "uchange", UF_IMMUTABLE); TEST(p, "uimmutable", UF_IMMUTABLE); + TEST(p, "uunlnk", UF_NOUNLINK); + TEST(p, "uunlink", UF_NOUNLINK); /* FALLTHROUGH */ default: return (1); diff --git a/sys/sys/stat.h b/sys/sys/stat.h index e017fd098ca0..fb156045d06c 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)stat.h 8.12 (Berkeley) 6/16/95 - * $Id: stat.h,v 1.11 1997/02/22 09:45:58 peter Exp $ + * $Id: stat.h,v 1.12 1997/04/09 16:32:23 bde Exp $ */ #ifndef _SYS_STAT_H_ @@ -175,6 +175,7 @@ struct stat { #define UF_IMMUTABLE 0x00000002 /* file may not be changed */ #define UF_APPEND 0x00000004 /* writes to file may only append */ #define UF_OPAQUE 0x00000008 /* directory is opaque wrt. union */ +#define UF_NOUNLINK 0x00000010 /* file may not be removed or renamed */ /* * Super-user changeable flags. */ @@ -182,6 +183,7 @@ struct stat { #define SF_ARCHIVED 0x00010000 /* file is archived */ #define SF_IMMUTABLE 0x00020000 /* file may not be changed */ #define SF_APPEND 0x00040000 /* writes to file may only append */ +#define SF_NOUNLINK 0x00100000 /* file may not be removed or renamed */ #ifdef KERNEL /* @@ -190,6 +192,7 @@ struct stat { #define OPAQUE (UF_OPAQUE) #define APPEND (UF_APPEND | SF_APPEND) #define IMMUTABLE (UF_IMMUTABLE | SF_IMMUTABLE) +#define NOUNLINK (UF_NOUNLINK | SF_NOUNLINK) #endif #endif /* !_POSIX_SOURCE */ diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index e1e6ebc9a289..8180761377bf 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95 - * $Id: ufs_vnops.c,v 1.49 1997/03/31 12:02:53 peter Exp $ + * $Id: ufs_vnops.c,v 1.50 1997/05/17 18:32:53 phk Exp $ */ #include "opt_quota.h" @@ -376,12 +376,14 @@ ufs_setattr(ap) (error = suser(cred, &p->p_acflag))) return (error); if (cred->cr_uid == 0) { - if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) && + if ((ip->i_flags + & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) && securelevel > 0) return (EPERM); ip->i_flags = vap->va_flags; } else { - if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND) || + if (ip->i_flags + & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || (vap->va_flags & UF_SETTABLE) != vap->va_flags) return (EPERM); ip->i_flags &= SF_SETTABLE; @@ -674,7 +676,7 @@ ufs_remove(ap) int error; ip = VTOI(vp); - if ((ip->i_flags & (IMMUTABLE | APPEND)) || + if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || (VTOI(dvp)->i_flags & APPEND)) { error = EPERM; goto out; @@ -904,7 +906,7 @@ ufs_rename(ap) return (error); } - if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) || + if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || (VTOI(tdvp)->i_flags & APPEND))) { error = EPERM; goto abortit; @@ -965,7 +967,8 @@ ufs_rename(ap) goto abortit; dp = VTOI(fdvp); ip = VTOI(fvp); - if ((ip->i_flags & (IMMUTABLE | APPEND)) || (dp->i_flags & APPEND)) { + if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) + || (dp->i_flags & APPEND)) { VOP_UNLOCK(fvp, 0, p); error = EPERM; goto abortit; @@ -1504,7 +1507,8 @@ ufs_rmdir(ap) error = ENOTEMPTY; goto out; } - if ((dp->i_flags & APPEND) || (ip->i_flags & (IMMUTABLE | APPEND))) { + if ((dp->i_flags & APPEND) + || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) { error = EPERM; goto out; } diff --git a/usr.bin/chflags/chflags.1 b/usr.bin/chflags/chflags.1 index 9c808a0094b3..9ab880f597b8 100644 --- a/usr.bin/chflags/chflags.1 +++ b/usr.bin/chflags/chflags.1 @@ -83,9 +83,12 @@ arch set the archived flag (super-user only) dump set the dump flag sappnd set the system append-only flag (super-user only) schg set the system immutable flag (super-user only) +sunlnk set the system undeletable flag (super-user only) uappnd set the user append-only flag (owner or super-user only) uchg set the user immutable flag (owner or super-user only) -archived, sappend, schange, simmutable, uappend, uchange, uimmutable +uunlnk set the user undeletable flag (owner or super-user only) +archived, sappend, schange, simmutable, uappend, uchange, uimmutable, +sunlink, uunlink aliases for the above .Ed .Pp