v07i080: Allow additions to 'protected' directories

sources-request at mirror.TMC.COM sources-request at mirror.TMC.COM
Sat Dec 6 08:09:52 AEST 1986


Submitted by: ihnp4!yetti!lethe!dave
Mod.sources: Volume 7, Issue 80
Archive-name: append

Here is a shar archive of the program "append", which fixes a small
security hole for large unix sites.  The files "append.c" and
"append.1" are necessary, the rest (secur.r, append.web and append.r)
are merely of interest:

 1) Source for append in C (the output of TANGLE, edited
    for readability by humans. See 5, below).
 2) The man-page for append(1) in nroff input format.
 3) An essay on security -vs- freedom to donate programs
    on a multi-user site.
 4) The WEB input form of append (which was written in C
    using Knuth's WEB "literate programming" system)
 5) The nroff input form of append (after processing with
    WEAVE), suitable for nroff -ms for a programming logic
    manual.

   --dave

-----CUT HERE-----
#!/bin/sh
echo "x - append.c"
sed "s/^X//" > append.c <<'!-E-o-F'
X/* 4.0: */ 
X#line 48 append.web
X
X/* 4.4: */ 
X#line 253 append.web
X
X/*
X * append -- a command to append a file to a directory to which 
X *	one does not have write permission, using setgrp & ln. 
X *	Placing append in a directory simulates the "sa a *.*" 
X *	access control command of Multics. See also append.web. 
X */
X
X/* :4.4 */
X
X#line 261 append.web
X
X
X/* 4.2: */ 
X#line 187 append.web
X
X#include <stdio.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X/* :4.2 */
X
X#line 193 append.web
X
X
X/* 4.1: */ 
X#line 104 append.web
X
X#define ERR (-1)
X
X/* :4.1 */
X
X#line 107 append.web
X/* 4.2: */ 
X#line 197 append.web
X
X#define DIRECTORY 0040000
X#define SPECIAL (0020000 | 0060000)
X
X/* :4.2 */
X
X#line 201 append.web
X
X
X/* 4.1: */ 
X#line 61 append.web
X
X void
Xmain(argc,argv) int argc; char *argv[]; {
X	/* 4.2: */ 
X#line 193 append.web
X	
X	struct stat s;	/* stat buffer */
X	int	m; 	/* file access mode */
X	
X	/* :4.2 */
X	
X#line 197 append.web
X	/* 4.3: */ 
X#line 246 append.web
X	
X	extern int errno;
X	extern char *sys_errlist[];
X	int	rc;
X	
X	/* :4.3 */
X	
X#line 251 append.web
X
X
X	char	*progName, *fromName, *toName,
X		*segmentPart(/* char * */);
X
X	progName = argv[0];
X	if (argc < 2) {
X		/* no parms, must be a request for information */
X		/* 4.4: */ 
X#line 261 append.web
X		
X		fprintf(stderr,"%s -- add (via link) a file to this directory, %s\n",
X			progName, "even if you lack permission.");
X		fprintf(stderr,"Usage: %s filename [newname]\n",progName);
X		
X		/* :4.4 */
X		
X#line 266 append.web
X
X
X		exit(0);
X	}
X	else if (argc == 2) {
X		/*  one parm, make names the same */
X		fromName = argv[1];
X		toName = segmentPart(argv[1]);
X	}
X	else if (argc == 3) {
X		/* two parms, make second one the new name */
X		fromName = argv[1];
X		if (strcmp(argv[2],".")==0) {
X			/* the directory */
X			toName = segmentPart(fromName);
X		}
X		else {
X			toName = segmentPart(argv[2]);
X		}
X	}
X/* :4.1 */
X
X#line 90 append.web
X/* 4.1: */ 
X#line 96 append.web
X
X
X	/* 4.2: */ 
X#line 139 append.web
X	
X	if (stat(progName,&s) == ERR || s.st_mode & (DIRECTORY|SPECIAL)
X	   || (s.st_uid != geteuid() && s.st_gid != getegid())) {
X		/* someone's trying to trick me by putting append in his path */
X		fprintf(stderr,"%s: Can't append to current directory, %s\n",
X			progName, "\"cd\" to target directory first");
X		exit(1);
X	}
X	
X	
X	if (stat(fromName,&s) == ERR) {
X		switch (errno) {
X		case ENOTDIR: 
X			fprintf(stderr,"%s: Can't access %s, %s.\n", progName,
X				fromName, "part of the path is a non-directory");
X			break;
X		case ENOENT:
X			fprintf(stderr,"%s: File %s doesn't exist.\n",
X				progName,fromName);
X			break;
X		case EACCES:
X			fprintf(stderr,"%s: Can't search a directory in %s.\n",
X				progName,fromName);
X			break;
X		default:
X			fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
X				progName,sys_errlist[errno]);
X		}
X		exit(1);
X	}
X	else if ((m=s.st_mode) & SPECIAL) {
X		fprintf(stderr,"%s: Can't append a special file.\n",progName);
X		exit(1);
X	}
X	else if (m & DIRECTORY) {
X		fprintf(stderr,"%s: Can't append a directory.\n",progName);
X		exit(1);
X	}
X	
X	if (stat(toName,&s) != ERR) {
X		fprintf(stderr,"%s: Can't replace an existing file\n",
X			progName);
X		exit(1);
X	}
X	/* :4.2 */
X	
X#line 183 append.web
X
X 
X	rc = link(fromName,toName);
X	/* 4.3: */ 
X#line 207 append.web
X	
X	if (rc == ERR) {
X		switch (errno) {
X		case EACCES: 
X			fprintf(stderr,"%s: Cannot write to this directory (%s).\n",
X				progName, "Can't happen, send mail to the owner");
X			exit(3);
X		case EXDEV:
X			fprintf(stderr,"%s: Can't do a cross-device link.\n",
X				progName);
X			exit(1);
X		case EROFS:
X			fprintf(stderr,"%s: Can't link to a r/o file system.\n",
X				progName);
X			exit(1);
X		case EMLINK:
X			fprintf(stderr,"%s: Can't link, too many already exist.\n",
X				progName);
X			exit(1);
X		case ENOSPC:
X			fprintf(stderr,"%s: Can't link, directory full.\n",
X				progName);
X			exit(1);
X		case ENOTDIR:
X		case ENOENT:
X		case EEXIST:
X		case EPERM:
X			fprintf(stderr,"%s: Can't link, impossible error \"%s\".\n",
X				progName,sys_errlist[errno]);
X			exit(3);
X		default:
X			fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
X				progName,sys_errlist[errno]);
X			exit(2);
X		}
X	}
X	/* :4.3 */
X	
X#line 243 append.web
X
X
X	exit(0);
X}
X
X/* :4.1 */
X
X#line 104 append.web
X
X
X/* 5.0: */ 
X#line 272 append.web
X
X char *
XsegmentPart(s) char *s; {
X	char	*p, *strrchr(/* char *, char */);
X
X	if (s && (p=strrchr(s,'/'))) {
X		return ++p;
X	}
X	return s;
X}
X
X/* :5.0 */
X
X#line 282 append.web
X
X
X
X/* :4.0 */
X
X#line 55 append.web
X
!-E-o-F
echo "x - append.1"
sed "s/^X//" > append.1 <<'!-E-o-F'
X.TH APPEND 1 Local
X.SH NAME
Xappend \- append a file to the current directory
X.SH SYNOPSIS
X.B append 
Xfilename [newname]
X.SH DESCRIPTION
X.PP
XAppend is a command to allow another person to put a file (actually
Xa link) into a particular directory.  This simulates the "append only"
Xaccess permission allowed by Multics but not Unix.
X.PP
XThe mechanism is quite simple: the program is setuid to the owner of
Xthe directory, and when called checks the file for plausibility
Xand links it into the current directory.
X.PP
XThe use of a link allows the author to modify (ie, maintain) the program
Xwithout requiring the superuser to delete and reinstall the new version
Xin the target directory.
X.SH INSTALLATION
X.PP
XTo install append, place a copy into the directory you wish to
Xhave accessable to others, chown it to yourself, and
Xset it setuid and executable, but not writable.
XThe chown command is:
X.br
X    chown your_name append
X.br
XThe chmod command for this is:
X.nf
X    chmod u+s,g-w,o-w,a+x append  -- can be used by anyone
X      or
X    chmod u+s,g-w,o-w,g+x append  -- can be used by group only
X.fi
X.SH "CHECKING THE ADVISABILITY OF APPENDING"
X.PP
XIt is inadvisable to append many kinds of file to a directory,
Xsuch as directorys and special files, and of course the file
Xshould be present and either readable or executable.
XAppend checks for accessability and plausability.
X.PP
XPlease note that it is quite reasonable to append a setuid
Xor setgid program to a directory. In fact, this is the proper
Xway to place a "gate" to certain private or sensitive
Xinformation in a generally accesable place.  It is not
Xreasonable to contrive to chown and re-setuid a program
Xto belong to root and append it to a directory, but this is dealt
Xwith by chown and chmod directly, and does not affect append.
X.PP
XThis does not mean that giving anyone append permissions on /bin is
Xa good idea: it is not hard to write a program which contains a
Xtrapdoor to catch the superuser, and append on /bin or /usr/bin
Xwould make it easy to put it in his way.
X.PP
XIn general, one places append permissions on directories like
X/usr/local/bin (which superuser doesn't normally search for commands)
Xand transfer directories.  Uucppublic would have been an excellent
Xexample if the uucp author known about this technique...
X.PP
XOne can append a FIFO to a directory even though it
Xis a type of "special" file, since this does not constitute an
X(obvious) security problem.
X.SH FILES
XNone.
X.SH "SEE ALSO"
Xcp(1), section on "ln", append.web for detailed discussion of the 
Xalgorithm.
X.SH DIAGNOSTICS
XSelf-explanatory, one hopes.
X.SH BUGS
X.PP
XIt is possible, as mentioned above, to install a trapdoor program
Xusing append in /bin, /usr/bin or /etc: do not grant append permissions
Xto these directories.
X.PP
XThere is no companion "unappend" program, since that would be a
Xsecurity bug of the first order.
X.PP
XYou must have cd'd to the target directory to use append.
X
X
!-E-o-F
echo "x - secur.r"
sed "s/^X//" > secur.r <<'!-E-o-F'
X.TL
XA Short Essay on Unix Security
X.AU
XDavid R. Brown
X(lethe!dave, watmath!watbun!drbrown)
X.AB
X.PP
XThis note discusses a small disfeature in Unix 
Xin light of
Xthe Multics experience, and shows how to block it using a 
Xclassical Unix technique.
X.AE
X
X.SH
XIntroduction
X.PP
XOn Unix systems where there are more than a few developers, an interesting
Xproblem often occurs. To install a command in the user library,
Xone has to be root.  To be root gives one the power to do
Xserious damage accidentally, and is therefore inadvisable.
XTo have to interrupt the systems administrator to have him (her)
Xinstalling and deinstalling programs can make one unpopular.
X.PP
XTherefore numerous sites do not prohibit writing to /usr/bin or
Xsome other site-specific bin directory.
XAs you might expect, this is
X.B
Xnot
Xa good idea.
X.PP
XConversely, numerous sites do not allow developers to add to any
Xsharable library at all, thus making the developers little islands
Xof private (indeed, peculiar) tools.
X.PP
XOthers officially refuse to allow access to shared libraries, but
Xunofficially allow the root password to become widely known.
X
X.SH
XConsequences
X.PP
XThis last technique, just pretending to prohibit access, 
Xis by far the most common, since the administrator can
Xclaim to be secure and the developers can still share the fruits
Xof their efforts.  
X.PP
XIt is also a recipe for disaster.
X.PP
XTry to imagine the expression on a manager's face when he discovers
Xthat the reorganization he just did resulted
Xin the loss of about six months of his boss's work...  
XImagine the expression when he can't figure out how to do a restore
Xwithout asking operations.
XFinally, imagine what it make him look like to the boss who was
Xpromised that his data was secure from his subordinates.
X.PP
XI got to see this happen at more than one site in more than one company.
XIt is humorous only to the onlooker.  It is a career-eater to the
Xparticipants.
X
X.PP
XRefusing to allow any access to the bin directories results in a maze
Xof private, peculiar environments, one per programmer.  If the site
Xis consistent in refusing access to other shared directories 
X(xxx/include, xxx/lib), then when programmers try to cooperate on
Xa project, they find themselves artificially prevented from sharing
Xsource and libraries.  
X.PP
XThis tends to make a development team into a collection of independent
Xindividuals, if not a collection of prima donnas.
X
X.PP
XLeaving write permission on /usr/bin or the like, while guarding
Xthe superuser password, leaves a different security hole open, the
Xtraditional "trapdoor" hole.
X.PP
XA person with access to a bin directory writes a utility program which,
Xwhile doing its normal task, checks to see if it is being executed by root,
Xand if so creates a setuid-root shell for the author.
XFrom that day onward, the author of the trapdoor program is root, even
Xif the root password is changed and kept secret.
X
X.SH
XOther Misfeatures
X.PP
XThere are some other problems, on first glance unrelated, that
Xarise out of the same deficiency.
X.PP
XFirstly, one cannot place "gates" to sharable information in
Xa public place unless the place is writable by all.  This makes
Xit difficult to allow access to a file which you have saved
Xaway down an unsearchable filetree, unless you put links to it
Xin someone's home directory.  The person looking for the information
Xcan find it, but has to remember where to look.
X
X.PP
XAlso, one cannot easily have an accessible but private place for transfer
Xprograms to put things: instead you get the UUCP public directory, 
Xand the security (and administration!) problem that creates.
X
X.SH
XAttempted Cures
X.PP
XThe most common attempt to cure the above lies in creating "project"
Xor "public" accounts, into which project-specific and public information
Xis placed.
X.PP
XThis really doesn't change a thing.  The bin directories of
Xthe public account can be trapdoored by anyone, the data in the account
Xcan be changed or lost by a careless mistake, and access to anyone with
Xthe password is possible, even to private or confidential information.
X.PP
XIn other words, the password to superuser is unnecessary to a cracker.
XThe password to the public account becomes sufficient for building
Xtrapdoors.
X.PP
XThere are other kludges to allow controlled sharing, but all are as bad or
Xworse than public accounts.  That does not mean that there is no real solution,
Xmerely that it is not obvious.
X
X.SH
XMultics
X.PP
XOnce upon a time, an operating system was written by Project MAC of M.I.T,
XBell Laboratories and the General Electric Company.  This was Multics, the
Xdirect predecessor of Unix.
X.PP
XOn Multics, security was a design consideration.  Sometimes too much of
Xa design consideration according to the Hackers of the MIT AI Lab.
XNevertheless, it was written with controled sharing in mind.
X.PP
XOne of the design features which security considerations affected was the
Xpermissions applied to directories.  In Multics, one didn't have read,
Xwrite and execute permissions on directories, one had search, modify
Xand append.
X.PP
XThis made the directories different from ordinary files and therefore
Xrequired more special-case code (to the detriment of elegance), but it
Xwas a useful distinction.
X.PP
XSearch was permission to read a directory, modify permission to write
Xit.  Append was permission to add a file to the directory. Therefore
Xif on had "sa", one could see what was in the directory and add files
Xor links, but one could not modify what was already there.
X
X.PP
XThis made it easy to share things: one said "SetAccess sa *.MyProject"
Xto allow anyone on your project (group) to search or append to a directory.
X.PP
XPrograms used it to allow anyone to add a "letter" to a "forum" (the Multics
Xversion of news) without giving them the ability to modify or remove
Xother person's letters.
X.PP
XPersons working on new commands would be granted append permission to the
X"EXperimentalLibrary" to put programs out to beta-test (EXL would amount to
Xsomething like /usr/local/experimental, or perhaps /usr/local/bin).
X.PP
XPersons alpha-testing programs would grant append permissions to their
Xpersonal libraries ($HOME/bin) to let others add the new commands at
Xtheir leisure.
X
X.SH
XUnix
X.PP
XUnix does not have "sma" permissions on directories, and does not
Xneed them.  Instead Unix has a mechanism to allow a program to 
Xgrant permissions temporarily to its users, the "setuid" bit.
X
X.PP
XSetuid allows controlled access to things which belong to individuals 
Xto others.  Since a program may make quite complex decisions, it actually
Xallows a finer degree of control than the Multics access control lists.
X.PP
XSetgid (set group id) allows similar access to things which belong to a central
Xutility to selected groups of individuals.  For purely historical reasons 
Xit is not often used.
X
X.PP
XWith these capabilities, it is possible on Unix to write a program which
Xallows the kind of controlled sharing for which Multics was designed.
X
X.SH
XAppend Program
X.PP
XThe program in question is called "append", and allows either anyone in
Xthe same group, or optionally anyone at all
Xto append files to the current directory (only).
X.PP
XIt does this very simply: It checks that the file to be added is not a
Xdirectory or special file, and links it into the current directory.
XIt is able to do so because it is setuid (or setgid) to the owner or
Xgroup of the directory.
X.PP
XVoila! Multics access control for Unix.
X
X.SH
XImprovements
X.PP
XBecause the directory is not writable by others, append could optionally
Xcheck for a ".acl" file and allow appending only by people listed in it.
X.PP
XThis would simulate the full set of access control directives provided
Xon Unix's grampa.
X
X.SH
XCaveats
X.PP
XOne should set append on /usr/local/bin, not on any directory in the
Xcommand search-path of super-user, or you will have created one of
Xthe security problems append is supposed to prevent.
X
X.nf
X				-- Dave (Unix hack on a 'bun) Brown
X				   yetti!lethe!dave 
X				   (formerly DRBrown at HI-Multics.ARPA)
X
X
!-E-o-F
echo "x - append.web"
sed "s/^X//" > append.web <<'!-E-o-F'
X.TL
XAppend,
XA Program to Simulate "append" Permissions on Unix.
X.AU
XDave Brown
X(yetti!lethe!dave, watmath!watbun!drbrown)
X.AB
XAppend.web is the (complete) implementation of a program
Xwhich closes a small security hole in Unix, by allowing
Xselected persons to add to (but not modify) the contents
Xof a directory.
X.PP
XWith append permissions, one can add or update user-supported
Xsoftware without requiring superuser priveleges, or can
Xplace gateways to otherwise inaccessible programs or data 
Xin publicly accessible places.
X.AE
X@*Append@>
X.PP
XAppend is a command to allow another person to put a file (actually
Xa link) into a particular directory.  This simulates the "append only"
Xaccess permission allowed by Multics but not Unix.
X.PP
XThe mechanism is quite simple: the program is setuid to the owner of
Xthe directory, and when called simply checks the file for plausability
Xand links it into the current directory.
X
X@*Installation@>
X.PP
XTo install append, place a copy into the directory you wish to
Xhave accessible to others, set it setuid and executable, but not
Xwritable.  The chmod command for this is:
X.nf
X	chmod u+s,g-w,o-w,a+x append -- accessible to anyone
X	  or
X	chmod u+s,g-w,o-w,o-x,g+x append -- accessible to group
X.fi
X.PP
XIf you take a copy of mine, you will also have to "chown" it to yourself 
X.I
Xbefore
Xyou chmod it setuid.
X
X@*Implementation@>
X.PP
XThe program consists of a main routine and some ancillaries, thusly:
X
X@<Append@>=
X<Header>
X<Includes>
X<Globals>
X<Main>
X<Utilities>
X
X@ Main Program@>
X.PP
XAppend consists of three basic operations.  First it checks to see
Xif you want usage information, then it checks that the file is acceptable
Xand finally it links it in.
X
X@<Main@>=
X void
Xmain(argc,argv) int argc; char *argv[]; {
X	<Declarations>
X	char	*progName, *fromName, *toName,
X		*segmentPart(/* char * */);
X
X	progName = argv[0];
X	if (argc < 2) {
X		/* no parms, must be a request for information */
X		<Provide Usage>
X		exit(0);
X	}
X	else if (argc == 2) {
X		/*  one parm, make names the same */
X		fromName = argv[1];
X		toName = segmentPart(argv[1]);
X	}
X	else if (argc == 3) {
X		/* two parms, make second one the new name */
X		fromName = argv[1];
X		if (strcmp(argv[2],".")==0) {
X			/* the directory */
X			toName = segmentPart(fromName);
X		}
X		else {
X			toName = segmentPart(argv[2]);
X		}
X	}
X at t
X.PP
XNote, please that toName is always the segment (filename) part of
Xthe desired location.  This prevents one from saying "append x ../x"
Xand making x appear in some directory you don't want append permissions
Xapplied to.
X at p
X
X	<Validity Check> 
X	rc = link(fromName,toName);
X	<Completion Check>
X	exit(0);
X}
X
X@<Globals@>=
X#define ERR (-1)
X
X@ Checking the Advisability of Appending@>
X.PP
XIt is inadvisable to append many kinds of file to a directory,
Xsuch as directorys and special files, and of course the file
Xshould be present and either readable or executable.
XThis block checks for accessibility and plausibility.
X
X.PP
XPlease note that it is reasonable to append a setuid
Xor setgid program to a directory. In fact, this is the proper
Xway to place a "gate" to certain private or sensitive
Xinformation in a generally accessible place.  It is not
Xreasonable to contrive to chown and re-setuid a program
Xto belong to root and append it to a directory, but this is dealt
Xwith by chown and chmod directly, and does not affect append.
X.PP
XThis does not mean that giving anyone append permissions on /bin is
Xa good idea: it is not hard to write a program which contains a
Xtrapdoor to catch the superuser, and append on /bin or /usr/bin
Xwould make it easy to put it in his way.
X.PP
XIn general, one places append permissions on directories like
X/usr/local/bin (which superuser doesn't normally search for commands),
Xman-page directories and transfer directories.  
XUucppublic would have been an excellent
Xexample if the uucp author had thought of this technique...
X
X.PP
XOne can append a FIFO to a directory even though it
Xis a type of "special" file, since this does not constitute an
X(obvious) security problem.
X
X@<Validity Check@>=
Xif (stat(progName,&s) == ERR || s.st_mode & (DIRECTORY|SPECIAL)
X   || (s.st_uid != geteuid() && s.st_gid != getegid())) {
X	/* someone's trying to trick me by putting append in his path */
X	fprintf(stderr,"%s: Can't append to current directory, %s\n",
X		progName, "\"cd\" to target directory first");
X	exit(1);
X}
X
X
Xif (stat(fromName,&s) == ERR) {
X	switch (errno) {
X	case ENOTDIR: 
X		fprintf(stderr,"%s: Can't access %s, %s.\n", progName,
X			fromName, "part of the path is a non-directory");
X		break;
X	case ENOENT:
X		fprintf(stderr,"%s: File %s doesn't exist.\n",
X			progName,fromName);
X		break;
X	case EACCES:
X		fprintf(stderr,"%s: Can't search a directory in %s.\n",
X			progName,fromName);
X		break;
X	default:
X		fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
X			progName,sys_errlist[errno]);
X	}
X	exit(1);
X}
Xelse if ((m=s.st_mode) & SPECIAL) {
X	fprintf(stderr,"%s: Can't append a special file.\n",progName);
X	exit(1);
X}
Xelse if (m & DIRECTORY) {
X	fprintf(stderr,"%s: Can't append a directory.\n",progName);
X	exit(1);
X}
X
Xif (stat(toName,&s) != ERR) {
X	fprintf(stderr,"%s: Can't replace an existing file\n",
X		progName);
X	exit(1);
X}
X at t
X.PP
XThe block depends upon the following declarations and includes:
X
X@<Includes@>=
X#include <stdio.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X@<Declarations@>=
Xstruct stat s;	/* stat buffer */
Xint	m; 	/* file access mode */
X
X@<Globals@>=
X#define DIRECTORY 0040000
X#define SPECIAL (0020000 | 0060000)
X
X@ Checking the Results of Appending@>
X.PP
XThe link can fail for several reasons, notably because Unix
Xcan't do cross-device links, link to a read-only file system
Xand so forth.
X
X@<Completion Check@>=
Xif (rc == ERR) {
X	switch (errno) {
X	case EACCES: 
X		fprintf(stderr,"%s: Cannot write to this directory (%s).\n",
X			progName, "Can't happen, send mail to the owner");
X		exit(3);
X	case EXDEV:
X		fprintf(stderr,"%s: Can't do a cross-device link.\n",
X			progName);
X		exit(1);
X	case EROFS:
X		fprintf(stderr,"%s: Can't link to a r/o file system.\n",
X			progName);
X		exit(1);
X	case EMLINK:
X		fprintf(stderr,"%s: Can't link, too many already exist.\n",
X			progName);
X		exit(1);
X	case ENOSPC:
X		fprintf(stderr,"%s: Can't link, directory full.\n",
X			progName);
X		exit(1);
X	case ENOTDIR:
X	case ENOENT:
X	case EEXIST:
X	case EPERM:
X		fprintf(stderr,"%s: Can't link, impossible error \"%s\".\n",
X			progName,sys_errlist[errno]);
X		exit(3);
X	default:
X		fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
X			progName,sys_errlist[errno]);
X		exit(2);
X	}
X}
X at t
X.PP
XThese depend in turn on the following:
X@<Declarations@>=
Xextern int errno;
Xextern char *sys_errlist[];
Xint	rc;
X
X@ User Header@>
X
X@<Header@>=
X/*
X * append -- a command to append a file to a directory to which 
X *	one does not have write permission, using setgrp & ln. 
X *	Placing append in a directory simulates the "sa a *.*" 
X *	access control command of Multics. See also append.web. 
X */
X
X@<Provide Usage@>=
Xfprintf(stderr,"%s -- add (via link) a file to this directory, %s\n",
X	progName, "even if you lack permission.");
Xfprintf(stderr,"Usage: %s filename [newname]\n",progName);
X
X@*Utility Routines@>
X.PP
XThis program has a single utility routine, "segmentPart", which
Xextracts the segment/filename part of a pathname string, by returning
Xeverything right of the last "/".
X
X@<Utilities@>=
X char *
XsegmentPart(s) char *s; {
X	char	*p, *strrchr(/* char *, char */);
X
X	if (s && (p=strrchr(s,'/'))) {
X		return ++p;
X	}
X	return s;
X}
X
!-E-o-F
echo "x - append.r"
sed "s/^X//" > append.r <<'!-E-o-F'
X.DA
X.TL
XAppend,
XA Program to Simulate "append" Permissions on Unix.
X.AU
XDave Brown
X(yetti!lethe!dave, watmath!watbun!drbrown)
X.AB
XAppend.web is the (complete) implementation of a program
Xwhich closes a small security hole in Unix, by allowing
Xselected persons to add to (but not modify) the contents
Xof a directory.
X.PP
XWith append permissions, one can add or update user-supported
Xsoftware without requiring superuser priveleges, or can
Xplace gateways to otherwise inaccessible programs or data 
Xin publicly accessible places.
X.AE
X
X.fi
X.ec
X.NH
XAppend
X.br
X.PP
XAppend is a command to allow another person to put a file (actually
Xa link) into a particular directory.  This simulates the "append only"
Xaccess permission allowed by Multics but not Unix.
X.PP
XThe mechanism is quite simple: the program is setuid to the owner of
Xthe directory, and when called simply checks the file for plausability
Xand links it into the current directory.
X
X
X.fi
X.ec
X.NH
XInstallation
X.br
X.PP
XTo install append, place a copy into the directory you wish to
Xhave accessible to others, set it setuid and executable, but not
Xwritable.  The chmod command for this is:
X.nf
X	chmod u+s,g-w,o-w,a+x append -- accessible to anyone
X	  or
X	chmod u+s,g-w,o-w,o-x,g+x append -- accessible to group
X.fi
X.PP
XIf you take a copy of mine, you will also have to "chown" it to yourself 
X.I
Xbefore
Xyou chmod it setuid.
X
X
X.fi
X.ec
X.NH
XImplementation
X.br
X.PP
XThe program consists of a main routine and some ancillaries, thusly:
X
X.B
X.br
X<Append>=
X.R
X.eo
X.nf
X<Header>
X<Includes>
X<Globals>
X<Main>
X<Utilities>
X
X
X.fi
X.ec
X.NH 2
XMain Program
X.br
X.PP
XAppend consists of three basic operations.  First it checks to see
Xif you want usage information, then it checks that the file is acceptable
Xand finally it links it in.
X
X.B
X.br
X<Main>=
X.R
X.eo
X.nf
X void
Xmain(argc,argv) int argc; char *argv[]; {
X	<Declarations>
X	char	*progName, *fromName, *toName,
X		*segmentPart(/* char * */);
X
X	progName = argv[0];
X	if (argc < 2) {
X		/* no parms, must be a request for information */
X		<Provide Usage>
X		exit(0);
X	}
X	else if (argc == 2) {
X		/*  one parm, make names the same */
X		fromName = argv[1];
X		toName = segmentPart(argv[1]);
X	}
X	else if (argc == 3) {
X		/* two parms, make second one the new name */
X		fromName = argv[1];
X		if (strcmp(argv[2],".")==0) {
X			/* the directory */
X			toName = segmentPart(fromName);
X		}
X		else {
X			toName = segmentPart(argv[2]);
X		}
X	}
X
X.fi
X.ec
X.PP
XNote, please that toName is always the segment (filename) part of
Xthe desired location.  This prevents one from saying "append x ../x"
Xand making x appear in some directory you don't want append permissions
Xapplied to.
X
X.nf
X.eo
X
X	<Validity Check> 
X	rc = link(fromName,toName);
X	<Completion Check>
X	exit(0);
X}
X
X.B
X.br
X<Globals>=
X.R
X.eo
X.nf
X#define ERR (-1)
X
X
X.fi
X.ec
X.NH 2
XChecking the Advisability of Appending
X.br
X.PP
XIt is inadvisable to append many kinds of file to a directory,
Xsuch as directorys and special files, and of course the file
Xshould be present and either readable or executable.
XThis block checks for accessibility and plausibility.
X
X.PP
XPlease note that it is reasonable to append a setuid
Xor setgid program to a directory. In fact, this is the proper
Xway to place a "gate" to certain private or sensitive
Xinformation in a generally accessible place.  It is not
Xreasonable to contrive to chown and re-setuid a program
Xto belong to root and append it to a directory, but this is dealt
Xwith by chown and chmod directly, and does not affect append.
X.PP
XThis does not mean that giving anyone append permissions on /bin is
Xa good idea: it is not hard to write a program which contains a
Xtrapdoor to catch the superuser, and append on /bin or /usr/bin
Xwould make it easy to put it in his way.
X.PP
XIn general, one places append permissions on directories like
X/usr/local/bin (which superuser doesn't normally search for commands),
Xman-page directories and transfer directories.  
XUucppublic would have been an excellent
Xexample if the uucp author had thought of this technique...
X
X.PP
XOne can append a FIFO to a directory even though it
Xis a type of "special" file, since this does not constitute an
X(obvious) security problem.
X
X.B
X.br
X<Validity Check>=
X.R
X.eo
X.nf
Xif (stat(progName,&s) == ERR || s.st_mode & (DIRECTORY|SPECIAL)
X   || (s.st_uid != geteuid() && s.st_gid != getegid())) {
X	/* someone's trying to trick me by putting append in his path */
X	fprintf(stderr,"%s: Can't append to current directory, %s\n",
X		progName, "\"cd\" to target directory first");
X	exit(1);
X}
X
X
Xif (stat(fromName,&s) == ERR) {
X	switch (errno) {
X	case ENOTDIR: 
X		fprintf(stderr,"%s: Can't access %s, %s.\n", progName,
X			fromName, "part of the path is a non-directory");
X		break;
X	case ENOENT:
X		fprintf(stderr,"%s: File %s doesn't exist.\n",
X			progName,fromName);
X		break;
X	case EACCES:
X		fprintf(stderr,"%s: Can't search a directory in %s.\n",
X			progName,fromName);
X		break;
X	default:
X		fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
X			progName,sys_errlist[errno]);
X	}
X	exit(1);
X}
Xelse if ((m=s.st_mode) & SPECIAL) {
X	fprintf(stderr,"%s: Can't append a special file.\n",progName);
X	exit(1);
X}
Xelse if (m & DIRECTORY) {
X	fprintf(stderr,"%s: Can't append a directory.\n",progName);
X	exit(1);
X}
X
Xif (stat(toName,&s) != ERR) {
X	fprintf(stderr,"%s: Can't replace an existing file\n",
X		progName);
X	exit(1);
X}
X
X.fi
X.ec
X.PP
XThe block depends upon the following declarations and includes:
X
X.B
X.br
X<Includes>=
X.R
X.eo
X.nf
X#include <stdio.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X.B
X.br
X<Declarations>=
X.R
X.eo
X.nf
Xstruct stat s;	/* stat buffer */
Xint	m; 	/* file access mode */
X
X.B
X.br
X<Globals>=
X.R
X.eo
X.nf
X#define DIRECTORY 0040000
X#define SPECIAL (0020000 | 0060000)
X
X
X.fi
X.ec
X.NH 2
XChecking the Results of Appending
X.br
X.PP
XThe link can fail for several reasons, notably because Unix
Xcan't do cross-device links, link to a read-only file system
Xand so forth.
X
X.B
X.br
X<Completion Check>=
X.R
X.eo
X.nf
Xif (rc == ERR) {
X	switch (errno) {
X	case EACCES: 
X		fprintf(stderr,"%s: Cannot write to this directory (%s).\n",
X			progName, "Can't happen, send mail to the owner");
X		exit(3);
X	case EXDEV:
X		fprintf(stderr,"%s: Can't do a cross-device link.\n",
X			progName);
X		exit(1);
X	case EROFS:
X		fprintf(stderr,"%s: Can't link to a r/o file system.\n",
X			progName);
X		exit(1);
X	case EMLINK:
X		fprintf(stderr,"%s: Can't link, too many already exist.\n",
X			progName);
X		exit(1);
X	case ENOSPC:
X		fprintf(stderr,"%s: Can't link, directory full.\n",
X			progName);
X		exit(1);
X	case ENOTDIR:
X	case ENOENT:
X	case EEXIST:
X	case EPERM:
X		fprintf(stderr,"%s: Can't link, impossible error \"%s\".\n",
X			progName,sys_errlist[errno]);
X		exit(3);
X	default:
X		fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
X			progName,sys_errlist[errno]);
X		exit(2);
X	}
X}
X
X.fi
X.ec
X.PP
XThese depend in turn on the following:
X.B
X.br
X<Declarations>=
X.R
X.eo
X.nf
Xextern int errno;
Xextern char *sys_errlist[];
Xint	rc;
X
X
X.fi
X.ec
X.NH 2
XUser Header
X.br
X
X.B
X.br
X<Header>=
X.R
X.eo
X.nf
X/*
X * append -- a command to append a file to a directory to which 
X *	one does not have write permission, using setgrp & ln. 
X *	Placing append in a directory simulates the "sa a *.*" 
X *	access control command of Multics. See also append.web. 
X */
X
X.B
X.br
X<Provide Usage>=
X.R
X.eo
X.nf
Xfprintf(stderr,"%s -- add (via link) a file to this directory, %s\n",
X	progName, "even if you lack permission.");
Xfprintf(stderr,"Usage: %s filename [newname]\n",progName);
X
X
X.fi
X.ec
X.NH
XUtility Routines
X.br
X.PP
XThis program has a single utility routine, "segmentPart", which
Xextracts the segment/filename part of a pathname string, by returning
Xeverything right of the last "/".
X
X.B
X.br
X<Utilities>=
X.R
X.eo
X.nf
X char *
XsegmentPart(s) char *s; {
X	char	*p, *strrchr(/* char *, char */);
X
X	if (s && (p=strrchr(s,'/'))) {
X		return ++p;
X	}
X	return s;
X}
X
!-E-o-F



More information about the Mod.sources mailing list