diff --git a/WHATSNEW.30 b/WHATSNEW.30 index 52e23d6b..5e3e23f4 100644 --- a/WHATSNEW.30 +++ b/WHATSNEW.30 @@ -13,12 +13,13 @@ CHANGES TO REMIND `remind -p ...' to an HTML table. The script was contributed by Don Schwarz -- New security features: Because of the risk of statically-allocated - buffer, REMIND now refuses to run if it is installed set-uid or set-gid. +- New security features: Because of the risks of statically-allocated + buffers, REMIND now refuses to run if it is installed set-uid or set-gid. If REMIND is run as root, it refuses to read files not owned by root. It also won't open group- or world-writable files, no matter who is - running it. REMIND doesn't do security checks on stdin, though, so - be careful if you run it as root in a script. + running it. Finally, if you read a file you don't own, REMIND disables + RUN and shell(). REMIND doesn't do these security checks on stdin, + though, so be careful if you run it as root in a script. NOTE: REMIND doesn't do the world- and group-writable checks on devices, FIFOs, etc. Otherwise "remind /dev/null" fails... diff --git a/files.c b/files.c index d9eb596a..d3803bc0 100644 --- a/files.c +++ b/files.c @@ -12,7 +12,7 @@ /***************************************************************/ #include "config.h" -static char const RCSID[] = "$Id: files.c,v 1.8 1997-07-31 01:52:46 dfs Exp $"; +static char const RCSID[] = "$Id: files.c,v 1.9 1997-08-31 17:03:25 dfs Exp $"; #include #ifdef HAVE_STDLIB_H @@ -59,6 +59,9 @@ typedef struct cheader { struct cheader *next; char *filename; CachedLine *cache; +#ifdef UNIX + int ownedByMe; +#endif } CachedFile; /* Define the structures needed by the INCLUDE file system */ @@ -69,6 +72,9 @@ typedef struct { int NumIfs; long offset; CachedLine *CLine; +#ifdef UNIX + int ownedByMe; +#endif } IncludeStruct; static CachedFile *CachedFiles = (CachedFile *) NULL; @@ -181,6 +187,9 @@ char *fname; CachedFile *h = CachedFiles; int r; +/* Assume we own the file for now */ + RunDisabled &= ~RUN_NOTOWNER; + /* If it's in the cache, get it from there. */ while (h) { @@ -188,6 +197,11 @@ char *fname; CLine = h->cache; STRSET(FileName, fname); LineNo = 0; +#ifdef UNIX + if (!h->ownedByMe) { + RunDisabled |= RUN_NOTOWNER; + } +#endif if (FileName) return OK; else return E_NO_MEM; } h = h->next; @@ -254,6 +268,13 @@ char *fname; return E_NO_MEM; } +#ifdef UNIX + if (RunDisabled & RUN_NOTOWNER) { + cf->ownedByMe = 0; + } else { + cf->ownedByMe = 1; + } +#endif /* Read the file */ while(fp) { r = ReadLineFromFile(); @@ -320,6 +341,9 @@ int PopFile() { IncludeStruct *i; + /* Assume we own the file for now */ + RunDisabled &= ~RUN_NOTOWNER; + if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]); if (!IStackPtr) return E_EOF; IStackPtr--; @@ -331,6 +355,11 @@ int PopFile() CLine = i->CLine; fp = NULL; STRSET(FileName, i->filename); +#ifdef UNIX + if (!i->ownedByMe) { + RunDisabled |= RUN_NOTOWNER; + } +#endif if (!CLine && (i->offset != -1L)) { /* We must open the file, then seek to specified position */ if (strcmp(i->filename, "-")) { @@ -389,6 +418,7 @@ char *fname; { IncludeStruct *i; int r; + int oldRunDisabled; if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE; i = &IStack[IStackPtr]; @@ -400,6 +430,13 @@ char *fname; i->IfFlags = IfFlags; i->CLine = CLine; i->offset = -1L; +#ifdef UNIX + if (RunDisabled & RUN_NOTOWNER) { + i->ownedByMe = 0; + } else { + i->ownedByMe = 1; + } +#endif if (fp) { i->offset = ftell(fp); FCLOSE(fp); @@ -407,10 +444,12 @@ char *fname; IStackPtr++; + oldRunDisabled = RunDisabled; /* Try to open the new file */ if (!OpenFile(fname)) { return OK; } + RunDisabled = oldRunDisabled; /* Ugh! We failed! */ if ( (r=PopFile()) ) return r; Eprint("%s: %s", ErrMsg[E_CANT_OPEN], fname); @@ -573,6 +612,7 @@ int TopLevel() /* root, we refuse to open files not owned by root. */ /* We also reject group- or world-writable files, no matter */ /* who we're running as. */ +/* As a side effect, if we don't own the file, we disable RUN */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE int CheckSafety(void) @@ -615,6 +655,12 @@ static int CheckSafety() fp = NULL; return 0; } + +/* If file is not owned by me, disable RUN command */ + if (statbuf.st_uid != geteuid()) { + RunDisabled |= RUN_NOTOWNER; + } + #endif return 1; } diff --git a/french.h b/french.h index 816f9638..c7a80aa9 100644 --- a/french.h +++ b/french.h @@ -14,7 +14,7 @@ /* */ /***************************************************************/ -/* $Id: french.h,v 1.4 1997-01-16 04:14:23 dfs Exp $ */ +/* $Id: french.h,v 1.5 1997-08-31 17:03:25 dfs Exp $ */ /* The very first define in a language support file must be L_LANGNAME: */ #define L_LANGNAME "French" @@ -361,7 +361,7 @@ PUBLIC void Usage(void) void Usage() #endif /* HAVE_PROTOS */ { - fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1996 by David F. Skoll\n", VERSION, L_LANGNAME); + fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1997 by David F. Skoll\n", VERSION, L_LANGNAME); #ifdef BETA fprintf(ErrFp, ">>>> BETA VERSION <<<<\n"); #endif diff --git a/init.c b/init.c index d1b6dbb7..b479432e 100644 --- a/init.c +++ b/init.c @@ -12,7 +12,7 @@ /***************************************************************/ #include "config.h" -static char const RCSID[] = "$Id: init.c,v 1.6 1997-07-30 01:30:56 dfs Exp $"; +static char const RCSID[] = "$Id: init.c,v 1.7 1997-08-31 17:03:26 dfs Exp $"; #define L_IN_INIT 1 #include @@ -180,7 +180,7 @@ char *argv[]; case 'r': case 'R': - RunDisabled = 1; + RunDisabled = RUN_CMDLINE; break; case 'm': @@ -234,7 +234,7 @@ char *argv[]; case 'u': case 'U': ChgUser(arg); - RunDisabled = 1; + RunDisabled = RUN_CMDLINE; while (*arg) arg++; break; #endif @@ -465,7 +465,7 @@ PUBLIC void Usage(void) void Usage() #endif /* HAVE_PROTOS */ { - fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1996 by David F. Skoll\n", VERSION, L_LANGNAME); + fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1997 by David F. Skoll\n", VERSION, L_LANGNAME); #ifdef BETA fprintf(ErrFp, ">>>> BETA VERSION <<<<\n"); #endif diff --git a/remind.1 b/remind.1 index 1901e87a..15ec8f44 100644 --- a/remind.1 +++ b/remind.1 @@ -1,4 +1,4 @@ -.\" $Id: remind.1,v 1.9 1997-08-01 02:28:31 dfs Exp $ +.\" $Id: remind.1,v 1.10 1997-08-31 17:03:26 dfs Exp $ .TH REMIND 1 "31 July 1997" .UC 4 .SH NAME @@ -1206,10 +1206,11 @@ your main .reminders file, include the following lines: RUN ON # Re-enable RUN .fi .PP -In addition, \fBRemind\fR contains a few other security features. It -will not read a file which is group- or world-writable. It will not -run set-uid. And if it is run as \fIroot\fR, it will only read files -owned by \fIroot\fR. +In addition, \fBRemind\fR on UNIX contains a few other security +features. It will not read a file which is group- or world-writable. +It will not run set-uid. If it reads a file you don't own, it will +disable RUN and the shell() function. And if it is run as \fIroot\fR, +it will only read files owned by \fIroot\fR. .PP .SH THE BANNER COMMAND .PP diff --git a/types.h b/types.h index 97cd9f0f..486298d0 100644 --- a/types.h +++ b/types.h @@ -9,7 +9,7 @@ /* */ /***************************************************************/ -/* $Id: types.h,v 1.3 1997-01-16 04:14:33 dfs Exp $ */ +/* $Id: types.h,v 1.4 1997-08-31 17:03:27 dfs Exp $ */ /* Values */ typedef struct { @@ -164,8 +164,9 @@ typedef struct { #define QUOTE_MARKER 1 /* Unlikely character to appear in reminder */ /* Flags for disabling run */ -#define RUN_CMDLINE 1 -#define RUN_SCRIPT 2 +#define RUN_CMDLINE 1 +#define RUN_SCRIPT 2 +#define RUN_NOTOWNER 4 /* Flags for the SimpleCalendar format */ #define SC_AMPM 0 /* Time shown as 3:00am, etc. */