From 0a1d0011f65ee20dc5fb5f64cb110867782a1da1 Mon Sep 17 00:00:00 2001 From: Dianne Skoll Date: Tue, 5 Oct 2021 12:04:44 -0400 Subject: [PATCH] Add "-+username" option to trust "username" for the purpose of allowing RUN. --- configure | 2 +- configure.in | 2 +- man/remind.1 | 12 ++++++++++++ src/config.h.in | 3 +++ src/files.c | 22 +++++++++++++++++----- src/globals.h | 9 +++++++++ src/init.c | 48 ++++++++++++++++++++++++++++++++++++------------ 7 files changed, 79 insertions(+), 19 deletions(-) diff --git a/configure b/configure index 67177360..2b626f73 100755 --- a/configure +++ b/configure @@ -3820,7 +3820,7 @@ _ACEOF -for ac_header in sys/file.h glob.h wctype.h locale.h +for ac_header in sys/types.h sys/file.h glob.h wctype.h locale.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" diff --git a/configure.in b/configure.in index 71fe799c..24301990 100644 --- a/configure.in +++ b/configure.in @@ -61,7 +61,7 @@ AC_CHECK_SIZEOF(unsigned int) AC_CHECK_SIZEOF(unsigned long) dnl Checks for header files. -AC_CHECK_HEADERS(sys/file.h glob.h wctype.h locale.h) +AC_CHECK_HEADERS(sys/types.h sys/file.h glob.h wctype.h locale.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_STRUCT_TM diff --git a/man/remind.1 b/man/remind.1 index 896cf865..9e54e68d 100644 --- a/man/remind.1 +++ b/man/remind.1 @@ -318,6 +318,13 @@ case, it only changes the environment variables as described above. It does not change the effective uid or gid. .RE .TP +\fB\-+\fIusername\fR +Causes \fBRemind\fR to trust files owned by the user \fIusername\fR. +Normally, if \fBRemind\fR reads a file that you do not own, it disables +RUN and the shell() function. This option causes it to also trust files +owned by \fIusername\fR. You can supply multiple \fB\-+\fR options +to trust multiple users, up to a limit of 20 trusted users. +.TP \fB-y\fR Causes \fBRemind\fR to synthesize a tag for any reminder that lacks a TAG clause. @@ -1580,6 +1587,11 @@ features. It will not read a file that 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 +Note that if \fBRemind\fR reads standard input, it does \fInot\fR +attempt to check the ownership of standard input, even if it is +coming from a file, and hence does \fInot\fR disable RUN and shell() +in this situation. .SH THE INCLUDECMD COMMAND .PP diff --git a/src/config.h.in b/src/config.h.in index 5518ca8d..f280ac02 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -10,6 +10,9 @@ /* Define if you have the header file. */ #undef HAVE_SYS_FILE_H +/* Define if you have the header file. */ +#undef HAVE_SYS_TYPES_H + /* Define if you have the header file */ #undef HAVE_GLOB_H diff --git a/src/files.c b/src/files.c index 026078ca..2d890096 100644 --- a/src/files.c +++ b/src/files.c @@ -1039,7 +1039,8 @@ int TopLevel(void) /* root, we refuse to open files not owned by root. */ /* We also reject world-writable files, no matter */ /* who we're running as. */ -/* As a side effect, if we don't own the file, we disable RUN */ +/* As a side effect, if we don't own the file, or it's not */ +/* owned by a trusted user, we disable RUN */ /***************************************************************/ static int CheckSafety(void) { @@ -1077,11 +1078,22 @@ static int CheckSafety(void) return 0; } -/* If file is not owned by me, disable RUN command */ - if (statbuf.st_uid != geteuid()) { - RunDisabled |= RUN_NOTOWNER; - } else { + /* If file is not owned by me or a trusted user, disable RUN command */ + + /* Assume unsafe */ + RunDisabled |= RUN_NOTOWNER; + if (statbuf.st_uid == geteuid()) { + /* Owned by me... safe */ RunDisabled &= ~RUN_NOTOWNER; + } else { + int i; + for (i=0; i +#endif + +#define MAX_TRUSTED_USERS 20 + #define MINUTES_PER_DAY 1440 #define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 )) @@ -36,6 +42,9 @@ EXTERN int CurMon; EXTERN int CurYear; EXTERN int LineNo; EXTERN int FreshLine; +EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS]; + +EXTERN INIT( int NumTrustedUsers, 0); EXTERN INIT( char const *MsgCommand, NULL); EXTERN INIT( int ShowAllErrors, 0); EXTERN INIT( int DebugFlag, 0); diff --git a/src/init.c b/src/init.c index 4aec9fa3..f924c2b8 100644 --- a/src/init.c +++ b/src/init.c @@ -89,6 +89,7 @@ static void ChgUser(char const *u); static void InitializeVar(char const *str); static char const *BadDate = "Illegal date on command line\n"; +static void AddTrustedUser(char const *username); static DynamicBuffer default_filename_buf; @@ -114,7 +115,7 @@ static char const *DefaultFilename(void) s = getenv("HOME"); if (!s) { fprintf(stderr, "HOME environment variable not set. Unable to determine reminder file.\n"); - exit(1); + exit(EXIT_FAILURE); } DBufPuts(&default_filename_buf, s); DBufPuts(&default_filename_buf, "/.reminders"); @@ -172,7 +173,7 @@ void InitRemind(int argc, char const *argv[]) if (getgid() != getegid() || getuid() != geteuid()) { fprintf(ErrFp, "\nRemind should not be installed set-uid or set-gid.\nCHECK YOUR SYSTEM SECURITY.\n"); - exit(1); + exit(EXIT_FAILURE); } y = NO_YR; @@ -183,7 +184,7 @@ void InitRemind(int argc, char const *argv[]) RealToday = SystemDate(&CurYear, &CurMon, &CurDay); if (RealToday < 0) { fprintf(ErrFp, ErrMsg[M_BAD_SYS_DATE], BASE); - exit(1); + exit(EXIT_FAILURE); } JulianToday = RealToday; FromJulian(JulianToday, &CurYear, &CurMon, &CurDay); @@ -217,6 +218,10 @@ void InitRemind(int argc, char const *argv[]) } while (*arg) { switch(*arg++) { + case '+': + AddTrustedUser(arg); + while(*arg) arg++; + break; case '@': UseVTColors = 1; @@ -535,7 +540,7 @@ void InitRemind(int argc, char const *argv[]) if (!InvokedAsRem) { if (i >= argc) { Usage(); - exit(1); + exit(EXIT_FAILURE); } InitialFile = argv[i++]; } else { @@ -682,7 +687,7 @@ void Usage(void) fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n"); fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n"); fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n"); - exit(1); + exit(EXIT_FAILURE); } #endif /* L_USAGE_OVERRIDE */ /***************************************************************/ @@ -711,23 +716,23 @@ static void ChgUser(char const *user) if (!pwent) { fprintf(ErrFp, ErrMsg[M_BAD_USER], user); - exit(1); + exit(EXIT_FAILURE); } if (!myuid && setgid(pwent->pw_gid)) { fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid); - exit(1); + exit(EXIT_FAILURE); } if (!myuid && setuid(pwent->pw_uid)) { fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid); - exit(1); + exit(EXIT_FAILURE); } home = malloc(strlen(pwent->pw_dir) + 6); if (!home) { fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]); - exit(1); + exit(EXIT_FAILURE); } sprintf(home, "HOME=%s", pwent->pw_dir); putenv(home); @@ -735,7 +740,7 @@ static void ChgUser(char const *user) shell = malloc(strlen(pwent->pw_shell) + 7); if (!shell) { fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]); - exit(1); + exit(EXIT_FAILURE); } sprintf(shell, "SHELL=%s", pwent->pw_shell); putenv(shell); @@ -744,14 +749,14 @@ static void ChgUser(char const *user) username = malloc(strlen(pwent->pw_name) + 6); if (!username) { fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]); - exit(1); + exit(EXIT_FAILURE); } sprintf(username, "USER=%s", pwent->pw_name); putenv(username); logname= malloc(strlen(pwent->pw_name) + 9); if (!logname) { fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]); - exit(1); + exit(EXIT_FAILURE); } sprintf(logname, "LOGNAME=%s", pwent->pw_name); putenv(logname); @@ -838,6 +843,25 @@ static void InitializeVar(char const *str) return; } +static void +AddTrustedUser(char const *username) +{ + struct passwd *pwent; + if (NumTrustedUsers >= MAX_TRUSTED_USERS) { + fprintf(stderr, "Too many trusted users (%d max)\n", + MAX_TRUSTED_USERS); + exit(EXIT_FAILURE); + } + + pwent = getpwnam(username); + if (!pwent) { + fprintf(ErrFp, ErrMsg[M_BAD_USER], username); + exit(EXIT_FAILURE); + } + TrustedUsers[NumTrustedUsers] = pwent->pw_uid; + NumTrustedUsers++; +} + #if defined(__APPLE__) || defined(__CYGWIN__) static char const pmsg1[] = { 0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,