diff --git a/WHATSNEW.30 b/WHATSNEW.30 index 99cdc5d0..52e23d6b 100644 --- a/WHATSNEW.30 +++ b/WHATSNEW.30 @@ -4,7 +4,7 @@ CHANGES TO REMIND + MINOR ENHANCEMENTS -- Made Remind accept date specs like "Jan 6, 1998" -- the comma is +- Made REMIND accept date specs like "Jan 6, 1998" -- the comma is ignored. This was suggested by John Conover . You can even do "REM 27, Aug, 1998, msg bar". (But I don't know why you'd want to.) @@ -13,12 +13,20 @@ 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. + 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. + + NOTE: REMIND doesn't do the world- and group-writable checks + on devices, FIFOs, etc. Otherwise "remind /dev/null" fails... + + BUG FIXES - Increased sizes of some statically-allocated buffers. This doesn't - really fix the problem, but makes it more manageable. Because of - the risk of statically-allocated buffers, REMIND now refuses to - run if it is installed set-uid or set-gid. + really fix the problem, but makes it more manageable. - Using the "-u" option now implies the "-r" option. This is a security feature. diff --git a/files.c b/files.c index e6f74508..81cd5fe7 100644 --- a/files.c +++ b/files.c @@ -12,7 +12,7 @@ /***************************************************************/ #include "config.h" -static char const RCSID[] = "$Id: files.c,v 1.5 1997-03-30 19:07:39 dfs Exp $"; +static char const RCSID[] = "$Id: files.c,v 1.6 1997-07-31 01:49:38 dfs Exp $"; #include #ifdef HAVE_STDLIB_H @@ -27,6 +27,10 @@ static char const RCSID[] = "$Id: files.c,v 1.5 1997-03-30 19:07:39 dfs Exp $"; #include #include +#ifdef HAVE_UNISTD +#include +#endif + #if defined(__MSDOS__) #include #endif @@ -78,6 +82,7 @@ static int IStackPtr = 0; PRIVATE int ReadLineFromFile ARGS ((void)); PRIVATE int CacheFile ARGS ((const char *fname)); PRIVATE void DestroyCache ARGS ((CachedFile *cf)); +PRIVATE int CheckSafety ARGS ((void)); /***************************************************************/ /* */ @@ -194,7 +199,7 @@ char *fname; } else { fp = fopen(fname, "r"); } - if (!fp) return E_CANT_OPEN; + if (!fp || !CheckSafety()) return E_CANT_OPEN; CLine = NULL; if (ShouldCache) { LineNo = 0; @@ -203,11 +208,12 @@ char *fname; fp = NULL; CLine = CachedFiles->cache; } else { - if (strcmp(fname, "-")) + if (strcmp(fname, "-")) { fp = fopen(fname, "r"); - else + if (!fp || !CheckSafety()) return E_CANT_OPEN; + } else { fp = stdin; - if (!fp) return E_CANT_OPEN; + } } } STRSET(FileName, fname); @@ -327,11 +333,12 @@ int PopFile() STRSET(FileName, i->filename); if (!CLine && (i->offset != -1L)) { /* We must open the file, then seek to specified position */ - if (strcmp(i->filename, "-")) + if (strcmp(i->filename, "-")) { fp = fopen(i->filename, "r"); - else + if (!fp || !CheckSafety()) return E_CANT_OPEN; + } else { fp = stdin; - if (!fp) return E_CANT_OPEN; + } if (fp != stdin) (void) fseek(fp, i->offset, 0); /* Trust that it works... */ } @@ -556,3 +563,54 @@ int TopLevel() { return !IStackPtr; } + +/***************************************************************/ +/* */ +/* CheckSafety */ +/* */ +/* Returns 1 if current file is safe to read; 0 otherwise. */ +/* Currently only meaningful for UNIX. If we are running as */ +/* 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. */ +/***************************************************************/ +#ifdef HAVE_PROTOS +PRIVATE int CheckSafety(void) +#else +static int CheckSafety() +#endif +{ +#ifdef UNIX + struct stat statbuf; + + if (fstat(fileno(fp), &statbuf)) { + fclose(fp); + fp = NULL; + return 0; + } + + /* Under UNIX, take extra precautions if running as root */ + if (!geteuid()) { + /* Reject files not owned by root or group/world writable */ + if (statbuf.st_uid != 0) { + fprintf(ErrFp, "SECURITY: Won't read non-root-owned file when running as root!\n"); + fclose(fp); + fp = NULL; + return 0; + } + } + /* Sigh... /dev/null is usually world-writable, so ignore devices, + FIFOs, sockets, etc. */ + if (!S_ISREG(statbuf.st_mode)) { + return 1; + } + if ((statbuf.st_mode & S_IWGRP) || + (statbuf.st_mode & S_IWOTH)) { + fprintf(ErrFp, "SECURITY: Won't read group- or world-writable file!"); + fclose(fp); + fp = NULL; + return 0; + } +#endif + return 1; +}