home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume07 / append < prev    next >
Encoding:
Text File  |  1988-09-11  |  32.4 KB  |  1,259 lines

  1. Subject:  v07i080:  Allow additions to 'protected' directories
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: ihnp4!yetti!lethe!dave
  6. Mod.sources: Volume 7, Issue 80
  7. Archive-name: append
  8.  
  9. Here is a shar archive of the program "append", which fixes a small
  10. security hole for large unix sites.  The files "append.c" and
  11. "append.1" are necessary, the rest (secur.r, append.web and append.r)
  12. are merely of interest:
  13.  
  14.  1) Source for append in C (the output of TANGLE, edited
  15.     for readability by humans. See 5, below).
  16.  2) The man-page for append(1) in nroff input format.
  17.  3) An essay on security -vs- freedom to donate programs
  18.     on a multi-user site.
  19.  4) The WEB input form of append (which was written in C
  20.     using Knuth's WEB "literate programming" system)
  21.  5) The nroff input form of append (after processing with
  22.     WEAVE), suitable for nroff -ms for a programming logic
  23.     manual.
  24.  
  25.    --dave
  26.  
  27. -----CUT HERE-----
  28. #!/bin/sh
  29. echo "x - append.c"
  30. sed "s/^X//" > append.c <<'!-E-o-F'
  31. X/* 4.0: */ 
  32. X#line 48 append.web
  33. X
  34. X/* 4.4: */ 
  35. X#line 253 append.web
  36. X
  37. X/*
  38. X * append -- a command to append a file to a directory to which 
  39. X *    one does not have write permission, using setgrp & ln. 
  40. X *    Placing append in a directory simulates the "sa a *.*" 
  41. X *    access control command of Multics. See also append.web. 
  42. X */
  43. X
  44. X/* :4.4 */
  45. X
  46. X#line 261 append.web
  47. X
  48. X
  49. X/* 4.2: */ 
  50. X#line 187 append.web
  51. X
  52. X#include <stdio.h>
  53. X#include <errno.h>
  54. X#include <sys/types.h>
  55. X#include <sys/stat.h>
  56. X
  57. X/* :4.2 */
  58. X
  59. X#line 193 append.web
  60. X
  61. X
  62. X/* 4.1: */ 
  63. X#line 104 append.web
  64. X
  65. X#define ERR (-1)
  66. X
  67. X/* :4.1 */
  68. X
  69. X#line 107 append.web
  70. X/* 4.2: */ 
  71. X#line 197 append.web
  72. X
  73. X#define DIRECTORY 0040000
  74. X#define SPECIAL (0020000 | 0060000)
  75. X
  76. X/* :4.2 */
  77. X
  78. X#line 201 append.web
  79. X
  80. X
  81. X/* 4.1: */ 
  82. X#line 61 append.web
  83. X
  84. X void
  85. Xmain(argc,argv) int argc; char *argv[]; {
  86. X    /* 4.2: */ 
  87. X#line 193 append.web
  88. X    
  89. X    struct stat s;    /* stat buffer */
  90. X    int    m;     /* file access mode */
  91. X    
  92. X    /* :4.2 */
  93. X    
  94. X#line 197 append.web
  95. X    /* 4.3: */ 
  96. X#line 246 append.web
  97. X    
  98. X    extern int errno;
  99. X    extern char *sys_errlist[];
  100. X    int    rc;
  101. X    
  102. X    /* :4.3 */
  103. X    
  104. X#line 251 append.web
  105. X
  106. X
  107. X    char    *progName, *fromName, *toName,
  108. X        *segmentPart(/* char * */);
  109. X
  110. X    progName = argv[0];
  111. X    if (argc < 2) {
  112. X        /* no parms, must be a request for information */
  113. X        /* 4.4: */ 
  114. X#line 261 append.web
  115. X        
  116. X        fprintf(stderr,"%s -- add (via link) a file to this directory, %s\n",
  117. X            progName, "even if you lack permission.");
  118. X        fprintf(stderr,"Usage: %s filename [newname]\n",progName);
  119. X        
  120. X        /* :4.4 */
  121. X        
  122. X#line 266 append.web
  123. X
  124. X
  125. X        exit(0);
  126. X    }
  127. X    else if (argc == 2) {
  128. X        /*  one parm, make names the same */
  129. X        fromName = argv[1];
  130. X        toName = segmentPart(argv[1]);
  131. X    }
  132. X    else if (argc == 3) {
  133. X        /* two parms, make second one the new name */
  134. X        fromName = argv[1];
  135. X        if (strcmp(argv[2],".")==0) {
  136. X            /* the directory */
  137. X            toName = segmentPart(fromName);
  138. X        }
  139. X        else {
  140. X            toName = segmentPart(argv[2]);
  141. X        }
  142. X    }
  143. X/* :4.1 */
  144. X
  145. X#line 90 append.web
  146. X/* 4.1: */ 
  147. X#line 96 append.web
  148. X
  149. X
  150. X    /* 4.2: */ 
  151. X#line 139 append.web
  152. X    
  153. X    if (stat(progName,&s) == ERR || s.st_mode & (DIRECTORY|SPECIAL)
  154. X       || (s.st_uid != geteuid() && s.st_gid != getegid())) {
  155. X        /* someone's trying to trick me by putting append in his path */
  156. X        fprintf(stderr,"%s: Can't append to current directory, %s\n",
  157. X            progName, "\"cd\" to target directory first");
  158. X        exit(1);
  159. X    }
  160. X    
  161. X    
  162. X    if (stat(fromName,&s) == ERR) {
  163. X        switch (errno) {
  164. X        case ENOTDIR: 
  165. X            fprintf(stderr,"%s: Can't access %s, %s.\n", progName,
  166. X                fromName, "part of the path is a non-directory");
  167. X            break;
  168. X        case ENOENT:
  169. X            fprintf(stderr,"%s: File %s doesn't exist.\n",
  170. X                progName,fromName);
  171. X            break;
  172. X        case EACCES:
  173. X            fprintf(stderr,"%s: Can't search a directory in %s.\n",
  174. X                progName,fromName);
  175. X            break;
  176. X        default:
  177. X            fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
  178. X                progName,sys_errlist[errno]);
  179. X        }
  180. X        exit(1);
  181. X    }
  182. X    else if ((m=s.st_mode) & SPECIAL) {
  183. X        fprintf(stderr,"%s: Can't append a special file.\n",progName);
  184. X        exit(1);
  185. X    }
  186. X    else if (m & DIRECTORY) {
  187. X        fprintf(stderr,"%s: Can't append a directory.\n",progName);
  188. X        exit(1);
  189. X    }
  190. X    
  191. X    if (stat(toName,&s) != ERR) {
  192. X        fprintf(stderr,"%s: Can't replace an existing file\n",
  193. X            progName);
  194. X        exit(1);
  195. X    }
  196. X    /* :4.2 */
  197. X    
  198. X#line 183 append.web
  199. X
  200. X    rc = link(fromName,toName);
  201. X    /* 4.3: */ 
  202. X#line 207 append.web
  203. X    
  204. X    if (rc == ERR) {
  205. X        switch (errno) {
  206. X        case EACCES: 
  207. X            fprintf(stderr,"%s: Cannot write to this directory (%s).\n",
  208. X                progName, "Can't happen, send mail to the owner");
  209. X            exit(3);
  210. X        case EXDEV:
  211. X            fprintf(stderr,"%s: Can't do a cross-device link.\n",
  212. X                progName);
  213. X            exit(1);
  214. X        case EROFS:
  215. X            fprintf(stderr,"%s: Can't link to a r/o file system.\n",
  216. X                progName);
  217. X            exit(1);
  218. X        case EMLINK:
  219. X            fprintf(stderr,"%s: Can't link, too many already exist.\n",
  220. X                progName);
  221. X            exit(1);
  222. X        case ENOSPC:
  223. X            fprintf(stderr,"%s: Can't link, directory full.\n",
  224. X                progName);
  225. X            exit(1);
  226. X        case ENOTDIR:
  227. X        case ENOENT:
  228. X        case EEXIST:
  229. X        case EPERM:
  230. X            fprintf(stderr,"%s: Can't link, impossible error \"%s\".\n",
  231. X                progName,sys_errlist[errno]);
  232. X            exit(3);
  233. X        default:
  234. X            fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
  235. X                progName,sys_errlist[errno]);
  236. X            exit(2);
  237. X        }
  238. X    }
  239. X    /* :4.3 */
  240. X    
  241. X#line 243 append.web
  242. X
  243. X
  244. X    exit(0);
  245. X}
  246. X
  247. X/* :4.1 */
  248. X
  249. X#line 104 append.web
  250. X
  251. X
  252. X/* 5.0: */ 
  253. X#line 272 append.web
  254. X
  255. X char *
  256. XsegmentPart(s) char *s; {
  257. X    char    *p, *strrchr(/* char *, char */);
  258. X
  259. X    if (s && (p=strrchr(s,'/'))) {
  260. X        return ++p;
  261. X    }
  262. X    return s;
  263. X}
  264. X
  265. X/* :5.0 */
  266. X
  267. X#line 282 append.web
  268. X
  269. X
  270. X
  271. X/* :4.0 */
  272. X
  273. X#line 55 append.web
  274. X
  275. !-E-o-F
  276. echo "x - append.1"
  277. sed "s/^X//" > append.1 <<'!-E-o-F'
  278. X.TH APPEND 1 Local
  279. X.SH NAME
  280. Xappend \- append a file to the current directory
  281. X.SH SYNOPSIS
  282. X.B append 
  283. Xfilename [newname]
  284. X.SH DESCRIPTION
  285. X.PP
  286. XAppend is a command to allow another person to put a file (actually
  287. Xa link) into a particular directory.  This simulates the "append only"
  288. Xaccess permission allowed by Multics but not Unix.
  289. X.PP
  290. XThe mechanism is quite simple: the program is setuid to the owner of
  291. Xthe directory, and when called checks the file for plausibility
  292. Xand links it into the current directory.
  293. X.PP
  294. XThe use of a link allows the author to modify (ie, maintain) the program
  295. Xwithout requiring the superuser to delete and reinstall the new version
  296. Xin the target directory.
  297. X.SH INSTALLATION
  298. X.PP
  299. XTo install append, place a copy into the directory you wish to
  300. Xhave accessable to others, chown it to yourself, and
  301. Xset it setuid and executable, but not writable.
  302. XThe chown command is:
  303. X.br
  304. X    chown your_name append
  305. X.br
  306. XThe chmod command for this is:
  307. X.nf
  308. X    chmod u+s,g-w,o-w,a+x append  -- can be used by anyone
  309. X      or
  310. X    chmod u+s,g-w,o-w,g+x append  -- can be used by group only
  311. X.fi
  312. X.SH "CHECKING THE ADVISABILITY OF APPENDING"
  313. X.PP
  314. XIt is inadvisable to append many kinds of file to a directory,
  315. Xsuch as directorys and special files, and of course the file
  316. Xshould be present and either readable or executable.
  317. XAppend checks for accessability and plausability.
  318. X.PP
  319. XPlease note that it is quite reasonable to append a setuid
  320. Xor setgid program to a directory. In fact, this is the proper
  321. Xway to place a "gate" to certain private or sensitive
  322. Xinformation in a generally accesable place.  It is not
  323. Xreasonable to contrive to chown and re-setuid a program
  324. Xto belong to root and append it to a directory, but this is dealt
  325. Xwith by chown and chmod directly, and does not affect append.
  326. X.PP
  327. XThis does not mean that giving anyone append permissions on /bin is
  328. Xa good idea: it is not hard to write a program which contains a
  329. Xtrapdoor to catch the superuser, and append on /bin or /usr/bin
  330. Xwould make it easy to put it in his way.
  331. X.PP
  332. XIn general, one places append permissions on directories like
  333. X/usr/local/bin (which superuser doesn't normally search for commands)
  334. Xand transfer directories.  Uucppublic would have been an excellent
  335. Xexample if the uucp author known about this technique...
  336. X.PP
  337. XOne can append a FIFO to a directory even though it
  338. Xis a type of "special" file, since this does not constitute an
  339. X(obvious) security problem.
  340. X.SH FILES
  341. XNone.
  342. X.SH "SEE ALSO"
  343. Xcp(1), section on "ln", append.web for detailed discussion of the 
  344. Xalgorithm.
  345. X.SH DIAGNOSTICS
  346. XSelf-explanatory, one hopes.
  347. X.SH BUGS
  348. X.PP
  349. XIt is possible, as mentioned above, to install a trapdoor program
  350. Xusing append in /bin, /usr/bin or /etc: do not grant append permissions
  351. Xto these directories.
  352. X.PP
  353. XThere is no companion "unappend" program, since that would be a
  354. Xsecurity bug of the first order.
  355. X.PP
  356. XYou must have cd'd to the target directory to use append.
  357. X
  358. X
  359. !-E-o-F
  360. echo "x - secur.r"
  361. sed "s/^X//" > secur.r <<'!-E-o-F'
  362. X.TL
  363. XA Short Essay on Unix Security
  364. X.AU
  365. XDavid R. Brown
  366. X(lethe!dave, watmath!watbun!drbrown)
  367. X.AB
  368. X.PP
  369. XThis note discusses a small disfeature in Unix 
  370. Xin light of
  371. Xthe Multics experience, and shows how to block it using a 
  372. Xclassical Unix technique.
  373. X.AE
  374. X
  375. X.SH
  376. XIntroduction
  377. X.PP
  378. XOn Unix systems where there are more than a few developers, an interesting
  379. Xproblem often occurs. To install a command in the user library,
  380. Xone has to be root.  To be root gives one the power to do
  381. Xserious damage accidentally, and is therefore inadvisable.
  382. XTo have to interrupt the systems administrator to have him (her)
  383. Xinstalling and deinstalling programs can make one unpopular.
  384. X.PP
  385. XTherefore numerous sites do not prohibit writing to /usr/bin or
  386. Xsome other site-specific bin directory.
  387. XAs you might expect, this is
  388. X.B
  389. Xnot
  390. Xa good idea.
  391. X.PP
  392. XConversely, numerous sites do not allow developers to add to any
  393. Xsharable library at all, thus making the developers little islands
  394. Xof private (indeed, peculiar) tools.
  395. X.PP
  396. XOthers officially refuse to allow access to shared libraries, but
  397. Xunofficially allow the root password to become widely known.
  398. X
  399. X.SH
  400. XConsequences
  401. X.PP
  402. XThis last technique, just pretending to prohibit access, 
  403. Xis by far the most common, since the administrator can
  404. Xclaim to be secure and the developers can still share the fruits
  405. Xof their efforts.  
  406. X.PP
  407. XIt is also a recipe for disaster.
  408. X.PP
  409. XTry to imagine the expression on a manager's face when he discovers
  410. Xthat the reorganization he just did resulted
  411. Xin the loss of about six months of his boss's work...  
  412. XImagine the expression when he can't figure out how to do a restore
  413. Xwithout asking operations.
  414. XFinally, imagine what it make him look like to the boss who was
  415. Xpromised that his data was secure from his subordinates.
  416. X.PP
  417. XI got to see this happen at more than one site in more than one company.
  418. XIt is humorous only to the onlooker.  It is a career-eater to the
  419. Xparticipants.
  420. X
  421. X.PP
  422. XRefusing to allow any access to the bin directories results in a maze
  423. Xof private, peculiar environments, one per programmer.  If the site
  424. Xis consistent in refusing access to other shared directories 
  425. X(xxx/include, xxx/lib), then when programmers try to cooperate on
  426. Xa project, they find themselves artificially prevented from sharing
  427. Xsource and libraries.  
  428. X.PP
  429. XThis tends to make a development team into a collection of independent
  430. Xindividuals, if not a collection of prima donnas.
  431. X
  432. X.PP
  433. XLeaving write permission on /usr/bin or the like, while guarding
  434. Xthe superuser password, leaves a different security hole open, the
  435. Xtraditional "trapdoor" hole.
  436. X.PP
  437. XA person with access to a bin directory writes a utility program which,
  438. Xwhile doing its normal task, checks to see if it is being executed by root,
  439. Xand if so creates a setuid-root shell for the author.
  440. XFrom that day onward, the author of the trapdoor program is root, even
  441. Xif the root password is changed and kept secret.
  442. X
  443. X.SH
  444. XOther Misfeatures
  445. X.PP
  446. XThere are some other problems, on first glance unrelated, that
  447. Xarise out of the same deficiency.
  448. X.PP
  449. XFirstly, one cannot place "gates" to sharable information in
  450. Xa public place unless the place is writable by all.  This makes
  451. Xit difficult to allow access to a file which you have saved
  452. Xaway down an unsearchable filetree, unless you put links to it
  453. Xin someone's home directory.  The person looking for the information
  454. Xcan find it, but has to remember where to look.
  455. X
  456. X.PP
  457. XAlso, one cannot easily have an accessible but private place for transfer
  458. Xprograms to put things: instead you get the UUCP public directory, 
  459. Xand the security (and administration!) problem that creates.
  460. X
  461. X.SH
  462. XAttempted Cures
  463. X.PP
  464. XThe most common attempt to cure the above lies in creating "project"
  465. Xor "public" accounts, into which project-specific and public information
  466. Xis placed.
  467. X.PP
  468. XThis really doesn't change a thing.  The bin directories of
  469. Xthe public account can be trapdoored by anyone, the data in the account
  470. Xcan be changed or lost by a careless mistake, and access to anyone with
  471. Xthe password is possible, even to private or confidential information.
  472. X.PP
  473. XIn other words, the password to superuser is unnecessary to a cracker.
  474. XThe password to the public account becomes sufficient for building
  475. Xtrapdoors.
  476. X.PP
  477. XThere are other kludges to allow controlled sharing, but all are as bad or
  478. Xworse than public accounts.  That does not mean that there is no real solution,
  479. Xmerely that it is not obvious.
  480. X
  481. X.SH
  482. XMultics
  483. X.PP
  484. XOnce upon a time, an operating system was written by Project MAC of M.I.T,
  485. XBell Laboratories and the General Electric Company.  This was Multics, the
  486. Xdirect predecessor of Unix.
  487. X.PP
  488. XOn Multics, security was a design consideration.  Sometimes too much of
  489. Xa design consideration according to the Hackers of the MIT AI Lab.
  490. XNevertheless, it was written with controled sharing in mind.
  491. X.PP
  492. XOne of the design features which security considerations affected was the
  493. Xpermissions applied to directories.  In Multics, one didn't have read,
  494. Xwrite and execute permissions on directories, one had search, modify
  495. Xand append.
  496. X.PP
  497. XThis made the directories different from ordinary files and therefore
  498. Xrequired more special-case code (to the detriment of elegance), but it
  499. Xwas a useful distinction.
  500. X.PP
  501. XSearch was permission to read a directory, modify permission to write
  502. Xit.  Append was permission to add a file to the directory. Therefore
  503. Xif on had "sa", one could see what was in the directory and add files
  504. Xor links, but one could not modify what was already there.
  505. X
  506. X.PP
  507. XThis made it easy to share things: one said "SetAccess sa *.MyProject"
  508. Xto allow anyone on your project (group) to search or append to a directory.
  509. X.PP
  510. XPrograms used it to allow anyone to add a "letter" to a "forum" (the Multics
  511. Xversion of news) without giving them the ability to modify or remove
  512. Xother person's letters.
  513. X.PP
  514. XPersons working on new commands would be granted append permission to the
  515. X"EXperimentalLibrary" to put programs out to beta-test (EXL would amount to
  516. Xsomething like /usr/local/experimental, or perhaps /usr/local/bin).
  517. X.PP
  518. XPersons alpha-testing programs would grant append permissions to their
  519. Xpersonal libraries ($HOME/bin) to let others add the new commands at
  520. Xtheir leisure.
  521. X
  522. X.SH
  523. XUnix
  524. X.PP
  525. XUnix does not have "sma" permissions on directories, and does not
  526. Xneed them.  Instead Unix has a mechanism to allow a program to 
  527. Xgrant permissions temporarily to its users, the "setuid" bit.
  528. X
  529. X.PP
  530. XSetuid allows controlled access to things which belong to individuals 
  531. Xto others.  Since a program may make quite complex decisions, it actually
  532. Xallows a finer degree of control than the Multics access control lists.
  533. X.PP
  534. XSetgid (set group id) allows similar access to things which belong to a central
  535. Xutility to selected groups of individuals.  For purely historical reasons 
  536. Xit is not often used.
  537. X
  538. X.PP
  539. XWith these capabilities, it is possible on Unix to write a program which
  540. Xallows the kind of controlled sharing for which Multics was designed.
  541. X
  542. X.SH
  543. XAppend Program
  544. X.PP
  545. XThe program in question is called "append", and allows either anyone in
  546. Xthe same group, or optionally anyone at all
  547. Xto append files to the current directory (only).
  548. X.PP
  549. XIt does this very simply: It checks that the file to be added is not a
  550. Xdirectory or special file, and links it into the current directory.
  551. XIt is able to do so because it is setuid (or setgid) to the owner or
  552. Xgroup of the directory.
  553. X.PP
  554. XVoila! Multics access control for Unix.
  555. X
  556. X.SH
  557. XImprovements
  558. X.PP
  559. XBecause the directory is not writable by others, append could optionally
  560. Xcheck for a ".acl" file and allow appending only by people listed in it.
  561. X.PP
  562. XThis would simulate the full set of access control directives provided
  563. Xon Unix's grampa.
  564. X
  565. X.SH
  566. XCaveats
  567. X.PP
  568. XOne should set append on /usr/local/bin, not on any directory in the
  569. Xcommand search-path of super-user, or you will have created one of
  570. Xthe security problems append is supposed to prevent.
  571. X
  572. X.nf
  573. X                -- Dave (Unix hack on a 'bun) Brown
  574. X                   yetti!lethe!dave 
  575. X                   (formerly DRBrown@HI-Multics.ARPA)
  576. X
  577. X
  578. !-E-o-F
  579. echo "x - append.web"
  580. sed "s/^X//" > append.web <<'!-E-o-F'
  581. X.TL
  582. XAppend,
  583. XA Program to Simulate "append" Permissions on Unix.
  584. X.AU
  585. XDave Brown
  586. X(yetti!lethe!dave, watmath!watbun!drbrown)
  587. X.AB
  588. XAppend.web is the (complete) implementation of a program
  589. Xwhich closes a small security hole in Unix, by allowing
  590. Xselected persons to add to (but not modify) the contents
  591. Xof a directory.
  592. X.PP
  593. XWith append permissions, one can add or update user-supported
  594. Xsoftware without requiring superuser priveleges, or can
  595. Xplace gateways to otherwise inaccessible programs or data 
  596. Xin publicly accessible places.
  597. X.AE
  598. X@*Append@>
  599. X.PP
  600. XAppend is a command to allow another person to put a file (actually
  601. Xa link) into a particular directory.  This simulates the "append only"
  602. Xaccess permission allowed by Multics but not Unix.
  603. X.PP
  604. XThe mechanism is quite simple: the program is setuid to the owner of
  605. Xthe directory, and when called simply checks the file for plausability
  606. Xand links it into the current directory.
  607. X
  608. X@*Installation@>
  609. X.PP
  610. XTo install append, place a copy into the directory you wish to
  611. Xhave accessible to others, set it setuid and executable, but not
  612. Xwritable.  The chmod command for this is:
  613. X.nf
  614. X    chmod u+s,g-w,o-w,a+x append -- accessible to anyone
  615. X      or
  616. X    chmod u+s,g-w,o-w,o-x,g+x append -- accessible to group
  617. X.fi
  618. X.PP
  619. XIf you take a copy of mine, you will also have to "chown" it to yourself 
  620. X.I
  621. Xbefore
  622. Xyou chmod it setuid.
  623. X
  624. X@*Implementation@>
  625. X.PP
  626. XThe program consists of a main routine and some ancillaries, thusly:
  627. X
  628. X@<Append@>=
  629. X<Header>
  630. X<Includes>
  631. X<Globals>
  632. X<Main>
  633. X<Utilities>
  634. X
  635. X@ Main Program@>
  636. X.PP
  637. XAppend consists of three basic operations.  First it checks to see
  638. Xif you want usage information, then it checks that the file is acceptable
  639. Xand finally it links it in.
  640. X
  641. X@<Main@>=
  642. X void
  643. Xmain(argc,argv) int argc; char *argv[]; {
  644. X    <Declarations>
  645. X    char    *progName, *fromName, *toName,
  646. X        *segmentPart(/* char * */);
  647. X
  648. X    progName = argv[0];
  649. X    if (argc < 2) {
  650. X        /* no parms, must be a request for information */
  651. X        <Provide Usage>
  652. X        exit(0);
  653. X    }
  654. X    else if (argc == 2) {
  655. X        /*  one parm, make names the same */
  656. X        fromName = argv[1];
  657. X        toName = segmentPart(argv[1]);
  658. X    }
  659. X    else if (argc == 3) {
  660. X        /* two parms, make second one the new name */
  661. X        fromName = argv[1];
  662. X        if (strcmp(argv[2],".")==0) {
  663. X            /* the directory */
  664. X            toName = segmentPart(fromName);
  665. X        }
  666. X        else {
  667. X            toName = segmentPart(argv[2]);
  668. X        }
  669. X    }
  670. X@t
  671. X.PP
  672. XNote, please that toName is always the segment (filename) part of
  673. Xthe desired location.  This prevents one from saying "append x ../x"
  674. Xand making x appear in some directory you don't want append permissions
  675. Xapplied to.
  676. X@p
  677. X
  678. X    <Validity Check> 
  679. X    rc = link(fromName,toName);
  680. X    <Completion Check>
  681. X    exit(0);
  682. X}
  683. X
  684. X@<Globals@>=
  685. X#define ERR (-1)
  686. X
  687. X@ Checking the Advisability of Appending@>
  688. X.PP
  689. XIt is inadvisable to append many kinds of file to a directory,
  690. Xsuch as directorys and special files, and of course the file
  691. Xshould be present and either readable or executable.
  692. XThis block checks for accessibility and plausibility.
  693. X
  694. X.PP
  695. XPlease note that it is reasonable to append a setuid
  696. Xor setgid program to a directory. In fact, this is the proper
  697. Xway to place a "gate" to certain private or sensitive
  698. Xinformation in a generally accessible place.  It is not
  699. Xreasonable to contrive to chown and re-setuid a program
  700. Xto belong to root and append it to a directory, but this is dealt
  701. Xwith by chown and chmod directly, and does not affect append.
  702. X.PP
  703. XThis does not mean that giving anyone append permissions on /bin is
  704. Xa good idea: it is not hard to write a program which contains a
  705. Xtrapdoor to catch the superuser, and append on /bin or /usr/bin
  706. Xwould make it easy to put it in his way.
  707. X.PP
  708. XIn general, one places append permissions on directories like
  709. X/usr/local/bin (which superuser doesn't normally search for commands),
  710. Xman-page directories and transfer directories.  
  711. XUucppublic would have been an excellent
  712. Xexample if the uucp author had thought of this technique...
  713. X
  714. X.PP
  715. XOne can append a FIFO to a directory even though it
  716. Xis a type of "special" file, since this does not constitute an
  717. X(obvious) security problem.
  718. X
  719. X@<Validity Check@>=
  720. Xif (stat(progName,&s) == ERR || s.st_mode & (DIRECTORY|SPECIAL)
  721. X   || (s.st_uid != geteuid() && s.st_gid != getegid())) {
  722. X    /* someone's trying to trick me by putting append in his path */
  723. X    fprintf(stderr,"%s: Can't append to current directory, %s\n",
  724. X        progName, "\"cd\" to target directory first");
  725. X    exit(1);
  726. X}
  727. X
  728. X
  729. Xif (stat(fromName,&s) == ERR) {
  730. X    switch (errno) {
  731. X    case ENOTDIR: 
  732. X        fprintf(stderr,"%s: Can't access %s, %s.\n", progName,
  733. X            fromName, "part of the path is a non-directory");
  734. X        break;
  735. X    case ENOENT:
  736. X        fprintf(stderr,"%s: File %s doesn't exist.\n",
  737. X            progName,fromName);
  738. X        break;
  739. X    case EACCES:
  740. X        fprintf(stderr,"%s: Can't search a directory in %s.\n",
  741. X            progName,fromName);
  742. X        break;
  743. X    default:
  744. X        fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
  745. X            progName,sys_errlist[errno]);
  746. X    }
  747. X    exit(1);
  748. X}
  749. Xelse if ((m=s.st_mode) & SPECIAL) {
  750. X    fprintf(stderr,"%s: Can't append a special file.\n",progName);
  751. X    exit(1);
  752. X}
  753. Xelse if (m & DIRECTORY) {
  754. X    fprintf(stderr,"%s: Can't append a directory.\n",progName);
  755. X    exit(1);
  756. X}
  757. X
  758. Xif (stat(toName,&s) != ERR) {
  759. X    fprintf(stderr,"%s: Can't replace an existing file\n",
  760. X        progName);
  761. X    exit(1);
  762. X}
  763. X@t
  764. X.PP
  765. XThe block depends upon the following declarations and includes:
  766. X
  767. X@<Includes@>=
  768. X#include <stdio.h>
  769. X#include <errno.h>
  770. X#include <sys/types.h>
  771. X#include <sys/stat.h>
  772. X
  773. X@<Declarations@>=
  774. Xstruct stat s;    /* stat buffer */
  775. Xint    m;     /* file access mode */
  776. X
  777. X@<Globals@>=
  778. X#define DIRECTORY 0040000
  779. X#define SPECIAL (0020000 | 0060000)
  780. X
  781. X@ Checking the Results of Appending@>
  782. X.PP
  783. XThe link can fail for several reasons, notably because Unix
  784. Xcan't do cross-device links, link to a read-only file system
  785. Xand so forth.
  786. X
  787. X@<Completion Check@>=
  788. Xif (rc == ERR) {
  789. X    switch (errno) {
  790. X    case EACCES: 
  791. X        fprintf(stderr,"%s: Cannot write to this directory (%s).\n",
  792. X            progName, "Can't happen, send mail to the owner");
  793. X        exit(3);
  794. X    case EXDEV:
  795. X        fprintf(stderr,"%s: Can't do a cross-device link.\n",
  796. X            progName);
  797. X        exit(1);
  798. X    case EROFS:
  799. X        fprintf(stderr,"%s: Can't link to a r/o file system.\n",
  800. X            progName);
  801. X        exit(1);
  802. X    case EMLINK:
  803. X        fprintf(stderr,"%s: Can't link, too many already exist.\n",
  804. X            progName);
  805. X        exit(1);
  806. X    case ENOSPC:
  807. X        fprintf(stderr,"%s: Can't link, directory full.\n",
  808. X            progName);
  809. X        exit(1);
  810. X    case ENOTDIR:
  811. X    case ENOENT:
  812. X    case EEXIST:
  813. X    case EPERM:
  814. X        fprintf(stderr,"%s: Can't link, impossible error \"%s\".\n",
  815. X            progName,sys_errlist[errno]);
  816. X        exit(3);
  817. X    default:
  818. X        fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
  819. X            progName,sys_errlist[errno]);
  820. X        exit(2);
  821. X    }
  822. X}
  823. X@t
  824. X.PP
  825. XThese depend in turn on the following:
  826. X@<Declarations@>=
  827. Xextern int errno;
  828. Xextern char *sys_errlist[];
  829. Xint    rc;
  830. X
  831. X@ User Header@>
  832. X
  833. X@<Header@>=
  834. X/*
  835. X * append -- a command to append a file to a directory to which 
  836. X *    one does not have write permission, using setgrp & ln. 
  837. X *    Placing append in a directory simulates the "sa a *.*" 
  838. X *    access control command of Multics. See also append.web. 
  839. X */
  840. X
  841. X@<Provide Usage@>=
  842. Xfprintf(stderr,"%s -- add (via link) a file to this directory, %s\n",
  843. X    progName, "even if you lack permission.");
  844. Xfprintf(stderr,"Usage: %s filename [newname]\n",progName);
  845. X
  846. X@*Utility Routines@>
  847. X.PP
  848. XThis program has a single utility routine, "segmentPart", which
  849. Xextracts the segment/filename part of a pathname string, by returning
  850. Xeverything right of the last "/".
  851. X
  852. X@<Utilities@>=
  853. X char *
  854. XsegmentPart(s) char *s; {
  855. X    char    *p, *strrchr(/* char *, char */);
  856. X
  857. X    if (s && (p=strrchr(s,'/'))) {
  858. X        return ++p;
  859. X    }
  860. X    return s;
  861. X}
  862. X
  863. !-E-o-F
  864. echo "x - append.r"
  865. sed "s/^X//" > append.r <<'!-E-o-F'
  866. X.DA
  867. X.TL
  868. XAppend,
  869. XA Program to Simulate "append" Permissions on Unix.
  870. X.AU
  871. XDave Brown
  872. X(yetti!lethe!dave, watmath!watbun!drbrown)
  873. X.AB
  874. XAppend.web is the (complete) implementation of a program
  875. Xwhich closes a small security hole in Unix, by allowing
  876. Xselected persons to add to (but not modify) the contents
  877. Xof a directory.
  878. X.PP
  879. XWith append permissions, one can add or update user-supported
  880. Xsoftware without requiring superuser priveleges, or can
  881. Xplace gateways to otherwise inaccessible programs or data 
  882. Xin publicly accessible places.
  883. X.AE
  884. X
  885. X.fi
  886. X.ec
  887. X.NH
  888. XAppend
  889. X.br
  890. X.PP
  891. XAppend is a command to allow another person to put a file (actually
  892. Xa link) into a particular directory.  This simulates the "append only"
  893. Xaccess permission allowed by Multics but not Unix.
  894. X.PP
  895. XThe mechanism is quite simple: the program is setuid to the owner of
  896. Xthe directory, and when called simply checks the file for plausability
  897. Xand links it into the current directory.
  898. X
  899. X
  900. X.fi
  901. X.ec
  902. X.NH
  903. XInstallation
  904. X.br
  905. X.PP
  906. XTo install append, place a copy into the directory you wish to
  907. Xhave accessible to others, set it setuid and executable, but not
  908. Xwritable.  The chmod command for this is:
  909. X.nf
  910. X    chmod u+s,g-w,o-w,a+x append -- accessible to anyone
  911. X      or
  912. X    chmod u+s,g-w,o-w,o-x,g+x append -- accessible to group
  913. X.fi
  914. X.PP
  915. XIf you take a copy of mine, you will also have to "chown" it to yourself 
  916. X.I
  917. Xbefore
  918. Xyou chmod it setuid.
  919. X
  920. X
  921. X.fi
  922. X.ec
  923. X.NH
  924. XImplementation
  925. X.br
  926. X.PP
  927. XThe program consists of a main routine and some ancillaries, thusly:
  928. X
  929. X.B
  930. X.br
  931. X<Append>=
  932. X.R
  933. X.eo
  934. X.nf
  935. X<Header>
  936. X<Includes>
  937. X<Globals>
  938. X<Main>
  939. X<Utilities>
  940. X
  941. X
  942. X.fi
  943. X.ec
  944. X.NH 2
  945. XMain Program
  946. X.br
  947. X.PP
  948. XAppend consists of three basic operations.  First it checks to see
  949. Xif you want usage information, then it checks that the file is acceptable
  950. Xand finally it links it in.
  951. X
  952. X.B
  953. X.br
  954. X<Main>=
  955. X.R
  956. X.eo
  957. X.nf
  958. X void
  959. Xmain(argc,argv) int argc; char *argv[]; {
  960. X    <Declarations>
  961. X    char    *progName, *fromName, *toName,
  962. X        *segmentPart(/* char * */);
  963. X
  964. X    progName = argv[0];
  965. X    if (argc < 2) {
  966. X        /* no parms, must be a request for information */
  967. X        <Provide Usage>
  968. X        exit(0);
  969. X    }
  970. X    else if (argc == 2) {
  971. X        /*  one parm, make names the same */
  972. X        fromName = argv[1];
  973. X        toName = segmentPart(argv[1]);
  974. X    }
  975. X    else if (argc == 3) {
  976. X        /* two parms, make second one the new name */
  977. X        fromName = argv[1];
  978. X        if (strcmp(argv[2],".")==0) {
  979. X            /* the directory */
  980. X            toName = segmentPart(fromName);
  981. X        }
  982. X        else {
  983. X            toName = segmentPart(argv[2]);
  984. X        }
  985. X    }
  986. X
  987. X.fi
  988. X.ec
  989. X.PP
  990. XNote, please that toName is always the segment (filename) part of
  991. Xthe desired location.  This prevents one from saying "append x ../x"
  992. Xand making x appear in some directory you don't want append permissions
  993. Xapplied to.
  994. X
  995. X.nf
  996. X.eo
  997. X
  998. X    <Validity Check> 
  999. X    rc = link(fromName,toName);
  1000. X    <Completion Check>
  1001. X    exit(0);
  1002. X}
  1003. X
  1004. X.B
  1005. X.br
  1006. X<Globals>=
  1007. X.R
  1008. X.eo
  1009. X.nf
  1010. X#define ERR (-1)
  1011. X
  1012. X
  1013. X.fi
  1014. X.ec
  1015. X.NH 2
  1016. XChecking the Advisability of Appending
  1017. X.br
  1018. X.PP
  1019. XIt is inadvisable to append many kinds of file to a directory,
  1020. Xsuch as directorys and special files, and of course the file
  1021. Xshould be present and either readable or executable.
  1022. XThis block checks for accessibility and plausibility.
  1023. X
  1024. X.PP
  1025. XPlease note that it is reasonable to append a setuid
  1026. Xor setgid program to a directory. In fact, this is the proper
  1027. Xway to place a "gate" to certain private or sensitive
  1028. Xinformation in a generally accessible place.  It is not
  1029. Xreasonable to contrive to chown and re-setuid a program
  1030. Xto belong to root and append it to a directory, but this is dealt
  1031. Xwith by chown and chmod directly, and does not affect append.
  1032. X.PP
  1033. XThis does not mean that giving anyone append permissions on /bin is
  1034. Xa good idea: it is not hard to write a program which contains a
  1035. Xtrapdoor to catch the superuser, and append on /bin or /usr/bin
  1036. Xwould make it easy to put it in his way.
  1037. X.PP
  1038. XIn general, one places append permissions on directories like
  1039. X/usr/local/bin (which superuser doesn't normally search for commands),
  1040. Xman-page directories and transfer directories.  
  1041. XUucppublic would have been an excellent
  1042. Xexample if the uucp author had thought of this technique...
  1043. X
  1044. X.PP
  1045. XOne can append a FIFO to a directory even though it
  1046. Xis a type of "special" file, since this does not constitute an
  1047. X(obvious) security problem.
  1048. X
  1049. X.B
  1050. X.br
  1051. X<Validity Check>=
  1052. X.R
  1053. X.eo
  1054. X.nf
  1055. Xif (stat(progName,&s) == ERR || s.st_mode & (DIRECTORY|SPECIAL)
  1056. X   || (s.st_uid != geteuid() && s.st_gid != getegid())) {
  1057. X    /* someone's trying to trick me by putting append in his path */
  1058. X    fprintf(stderr,"%s: Can't append to current directory, %s\n",
  1059. X        progName, "\"cd\" to target directory first");
  1060. X    exit(1);
  1061. X}
  1062. X
  1063. X
  1064. Xif (stat(fromName,&s) == ERR) {
  1065. X    switch (errno) {
  1066. X    case ENOTDIR: 
  1067. X        fprintf(stderr,"%s: Can't access %s, %s.\n", progName,
  1068. X            fromName, "part of the path is a non-directory");
  1069. X        break;
  1070. X    case ENOENT:
  1071. X        fprintf(stderr,"%s: File %s doesn't exist.\n",
  1072. X            progName,fromName);
  1073. X        break;
  1074. X    case EACCES:
  1075. X        fprintf(stderr,"%s: Can't search a directory in %s.\n",
  1076. X            progName,fromName);
  1077. X        break;
  1078. X    default:
  1079. X        fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
  1080. X            progName,sys_errlist[errno]);
  1081. X    }
  1082. X    exit(1);
  1083. X}
  1084. Xelse if ((m=s.st_mode) & SPECIAL) {
  1085. X    fprintf(stderr,"%s: Can't append a special file.\n",progName);
  1086. X    exit(1);
  1087. X}
  1088. Xelse if (m & DIRECTORY) {
  1089. X    fprintf(stderr,"%s: Can't append a directory.\n",progName);
  1090. X    exit(1);
  1091. X}
  1092. X
  1093. Xif (stat(toName,&s) != ERR) {
  1094. X    fprintf(stderr,"%s: Can't replace an existing file\n",
  1095. X        progName);
  1096. X    exit(1);
  1097. X}
  1098. X
  1099. X.fi
  1100. X.ec
  1101. X.PP
  1102. XThe block depends upon the following declarations and includes:
  1103. X
  1104. X.B
  1105. X.br
  1106. X<Includes>=
  1107. X.R
  1108. X.eo
  1109. X.nf
  1110. X#include <stdio.h>
  1111. X#include <errno.h>
  1112. X#include <sys/types.h>
  1113. X#include <sys/stat.h>
  1114. X
  1115. X.B
  1116. X.br
  1117. X<Declarations>=
  1118. X.R
  1119. X.eo
  1120. X.nf
  1121. Xstruct stat s;    /* stat buffer */
  1122. Xint    m;     /* file access mode */
  1123. X
  1124. X.B
  1125. X.br
  1126. X<Globals>=
  1127. X.R
  1128. X.eo
  1129. X.nf
  1130. X#define DIRECTORY 0040000
  1131. X#define SPECIAL (0020000 | 0060000)
  1132. X
  1133. X
  1134. X.fi
  1135. X.ec
  1136. X.NH 2
  1137. XChecking the Results of Appending
  1138. X.br
  1139. X.PP
  1140. XThe link can fail for several reasons, notably because Unix
  1141. Xcan't do cross-device links, link to a read-only file system
  1142. Xand so forth.
  1143. X
  1144. X.B
  1145. X.br
  1146. X<Completion Check>=
  1147. X.R
  1148. X.eo
  1149. X.nf
  1150. Xif (rc == ERR) {
  1151. X    switch (errno) {
  1152. X    case EACCES: 
  1153. X        fprintf(stderr,"%s: Cannot write to this directory (%s).\n",
  1154. X            progName, "Can't happen, send mail to the owner");
  1155. X        exit(3);
  1156. X    case EXDEV:
  1157. X        fprintf(stderr,"%s: Can't do a cross-device link.\n",
  1158. X            progName);
  1159. X        exit(1);
  1160. X    case EROFS:
  1161. X        fprintf(stderr,"%s: Can't link to a r/o file system.\n",
  1162. X            progName);
  1163. X        exit(1);
  1164. X    case EMLINK:
  1165. X        fprintf(stderr,"%s: Can't link, too many already exist.\n",
  1166. X            progName);
  1167. X        exit(1);
  1168. X    case ENOSPC:
  1169. X        fprintf(stderr,"%s: Can't link, directory full.\n",
  1170. X            progName);
  1171. X        exit(1);
  1172. X    case ENOTDIR:
  1173. X    case ENOENT:
  1174. X    case EEXIST:
  1175. X    case EPERM:
  1176. X        fprintf(stderr,"%s: Can't link, impossible error \"%s\".\n",
  1177. X            progName,sys_errlist[errno]);
  1178. X        exit(3);
  1179. X    default:
  1180. X        fprintf(stderr,"%s: Can't link, error is \"%s\".\n", 
  1181. X            progName,sys_errlist[errno]);
  1182. X        exit(2);
  1183. X    }
  1184. X}
  1185. X
  1186. X.fi
  1187. X.ec
  1188. X.PP
  1189. XThese depend in turn on the following:
  1190. X.B
  1191. X.br
  1192. X<Declarations>=
  1193. X.R
  1194. X.eo
  1195. X.nf
  1196. Xextern int errno;
  1197. Xextern char *sys_errlist[];
  1198. Xint    rc;
  1199. X
  1200. X
  1201. X.fi
  1202. X.ec
  1203. X.NH 2
  1204. XUser Header
  1205. X.br
  1206. X
  1207. X.B
  1208. X.br
  1209. X<Header>=
  1210. X.R
  1211. X.eo
  1212. X.nf
  1213. X/*
  1214. X * append -- a command to append a file to a directory to which 
  1215. X *    one does not have write permission, using setgrp & ln. 
  1216. X *    Placing append in a directory simulates the "sa a *.*" 
  1217. X *    access control command of Multics. See also append.web. 
  1218. X */
  1219. X
  1220. X.B
  1221. X.br
  1222. X<Provide Usage>=
  1223. X.R
  1224. X.eo
  1225. X.nf
  1226. Xfprintf(stderr,"%s -- add (via link) a file to this directory, %s\n",
  1227. X    progName, "even if you lack permission.");
  1228. Xfprintf(stderr,"Usage: %s filename [newname]\n",progName);
  1229. X
  1230. X
  1231. X.fi
  1232. X.ec
  1233. X.NH
  1234. XUtility Routines
  1235. X.br
  1236. X.PP
  1237. XThis program has a single utility routine, "segmentPart", which
  1238. Xextracts the segment/filename part of a pathname string, by returning
  1239. Xeverything right of the last "/".
  1240. X
  1241. X.B
  1242. X.br
  1243. X<Utilities>=
  1244. X.R
  1245. X.eo
  1246. X.nf
  1247. X char *
  1248. XsegmentPart(s) char *s; {
  1249. X    char    *p, *strrchr(/* char *, char */);
  1250. X
  1251. X    if (s && (p=strrchr(s,'/'))) {
  1252. X        return ++p;
  1253. X    }
  1254. X    return s;
  1255. X}
  1256. X
  1257. !-E-o-F
  1258.