home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-09-11 | 32.4 KB | 1,259 lines |
- Subject: v07i080: Allow additions to 'protected' directories
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- 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@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@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@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@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@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
-