[comp.os.minix] Wmail 2.7 Posted on behalf of Fred van Kempen

ast@cs.vu.nl (Andy Tanenbaum) (11/11/89)

Oops!

I am VERY sorry for this (actually I am ashamed...), but here
is the first "official patch" for W-MAIL version 2.6, which
was posted for me by Dr. Tanenbaum last week.

This update kit consists of TWO updates:

	1) In the process of editing W-MAIL from 2.5 to 2.6 I
	   inserted a typo. The bug causes W-MAIL to behave very
	   strange in 'interactive' mode (e.g. the command mode).
	   It will refuse to print letters, and it always shows
	   an extra newline after a command has been typed.
	   The cure for this typo is contained in the cdiff-file
	   called 'patch1A.cdiff'.

	2) The second patch is about a VERY serious bug, which
	   was brought to my attention by Rich Salz. Thanks, Rich!
	   Since W-MAIL is setuid-root, problems may arise with
	   system security. In fact, W-MAIL DOES NOT CHECK PERMISSIONS
	   AT ALL. For example, it is possible to set the environ-
	   mental variable "DEADLETTER" to some serious file like
	   "/etc/passwd", and then create a situation in which WMAIL
	   dumps the message in DEADLETTER. What will happen?
	   Correct, since the program is SetUID-root the message will
	   be dumped on the file /etc/passwd: CRASH !
	   This sort of problem also arises with saving messages, and
	   with the "SIGNATURE" variable.

	   Since this is a VERY serious problem, I immediately started
	   hacking on the fix. During that process (I tried various
	   solutions, and only this one seems to be OK) I found some
	   other minor things as well.

	   The second patch cures all this.
	   W-MAIL 2.7 has been tested VERY thorougly; it should be OK
	   now. Please let me know if it isn't.....

It also contains the new README file.

Regards,
	Fred van Kempen.
---------------------------- cut here ----------------------------------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
#		"End of archive"
# Contents:
#	README        	patch1A.cdiff 	patch1B.cdiff 
#
# Wrapped by root@minixug on Sat Nov 11 04:19:19 1989
#
PATH=/bin:/usr/bin:/usr/local/bin:/usr/ucb:/tmp ; export PATH
if test -f 'README' -a "${1}" != "-c"
then
   echo "$0: Will not overwrite existing file: 'README'"
else
   echo "x - README"
sed 's/^X//' <<\END_OF_SHAR >'README'
X		W-MAIL Local Mail Agent (MINIX)
X
X		     MicroWalt W-MAIL V2.7
X		     =====================
X
XThis archive contains the sources of the W-MAIL program, which
Xis a MINIX version of the MAILX program available on most UNIXes.
X
XIt does not need the presence of UUCP in order to run. However,
Xfor non-local mail delivery a remote mailer (like MicroWalt UMAIL)
Xis required to be present.
X
XRevision History:
X2.5	10/10/89	Initial posting.
X
X2.6	11/07/89	General fixes and a cleanup.
X	- The Makefile-macro 'OTHERS' now contains 'wmail.h'
X	  as well. This caused incomplete archives to be
X	  distributed. Also, the parameters to 'shar' and 'tar'
X	  have been adapted to the new tar(1) and shar(1) programs.
X
X	- Fixed '.' problem in edit_mail().
X
X	- The strings 'findbuff', 'lbuff' and 'inbuff' have been
X	  moved to the routines in which they are used.
X
X	- The bug in the more() code has been fixed. This bug
X	  cause gargabe to be printed in some circumstances.
X
X	- The dead_letter() function no longer puts the file
X	  in the user's HOME directory. It now looks if there
X	  is an environmental variable "DEADLETTER"; if it 
X	  exists its value will be used as the file name. 
X	  Otherwise, the message will be dumped in the file
X	  "dead.letter" in the current directory.
X
X	- All references to 'NIL' have been changed into 'NULL'.
X	  It was a bit confusing to have both around.
X
X	- The code to scan message-headers has been changed
X	  radically. All message fields are now stored in the
X	  'LETTER' structure dynamically. This saves a lot of
X	  memory, and thus allows for larger mailboxes.
X
X	- The 'reply' bug has been fixed. This bug was caused
X	  by the UMAIL mailer, because it generated the wrong
X	  type of "From_" header. The header is now scanned by
X	  a separate routine in 'ummain.c' called 'old_hdr()'.
X
X	- The source has been edited to make it conform to the
X	  new MINIX Style Sheet as posted by Andrew Tanenbaum.
X
X	- The version-number has been increased to 2.6.
X
X2.7	11/10/89	Bug fixes:
X	- The typo in wminteract() has been corrected. It said
X	  "interrupted = TRUE" where it should be "== TRUE".
X
X	- Also, fixed all security problems within W-MAIL. This
X	  is done by calling the new 'allowed()' routine before
X	  a file is opened or created.
X
X	- Some minor (cosmetic) changes.
X
X	- The version-number has been increased to 2.6.
X
X
XOne last note:
X	If you are compiling this program, and you get a lot of
X	"illegal conversion of int to pointer" errors, please make
X	sure that your header files in /usr/include have the
X	"extern" declarations. Do NOT add them to this program...
X
XEnjoy!
X
X+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
X| MINIX User Group (Holland)   UUCP: hp4nl!kyber!minixug!waltje	|
X| c/o Fred van Kempen,		 or: minixug!waltje@kyber.UUCP	|
X| Hoefbladhof  27						|
X| 2215 DV  VOORHOUT						|
X| The Netherlands	"A good programmer knows his Sources"	|
X+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
X
END_OF_SHAR
fi
if test -f 'patch1A.cdiff' -a "${1}" != "-c"
then
   echo "$0: Will not overwrite existing file: 'patch1A.cdiff'"
else
   echo "x - patch1A.cdiff"
sed 's/^X//' <<\END_OF_SHAR >'patch1A.cdiff'
X*** wmail.h.old	Wed Nov  8 17:01:45 1989
X--- wmail.h	Wed Nov  8 17:01:52 1989
X***************
X*** 17,23 ****
X  #include <setjmp.h>
X  
X  
X! #define VERSION			"2.6 (11/07/89)"
X  
X  #define DROPNAME 	     "/usr/spool/mail/%s"   /* User Mailbox */
X  #define LOCKNAME	"/usr/spool/mail/%s.lock"   /* lockfile for box */
X--- 17,23 ----
X  #include <setjmp.h>
X  
X  
X! #define VERSION			"2.6 (11/08/89)"
X  
X  #define DROPNAME 	     "/usr/spool/mail/%s"   /* User Mailbox */
X  #define LOCKNAME	"/usr/spool/mail/%s.lock"   /* lockfile for box */
X*** wminteract.c.o	Wed Nov  8 16:57:42 1989
X--- wminteract.c	Wed Nov  8 16:57:47 1989
X***************
X*** 240,246 ****
X  		signal(SIGINT, onint);
X         	}
X  
X!       	if (interrupted = TRUE) printf("\n");
X        	printf(PROMPT, let->seqno);
X        	fflush(stdout);
X  
X--- 240,246 ----
X  		signal(SIGINT, onint);
X         	}
X  
X!       	if (interrupted == TRUE) printf("\n");
X        	printf(PROMPT, let->seqno);
X        	fflush(stdout);
X
END_OF_SHAR
fi
if test -f 'patch1B.cdiff' -a "${1}" != "-c"
then
   echo "$0: Will not overwrite existing file: 'patch1B.cdiff'"
else
   echo "x - patch1B.cdiff"
sed 's/^X//' <<\END_OF_SHAR >'patch1B.cdiff'
X*** old/wmail.h	Sat Nov 11 03:50:44 1989
X--- wmail.h	Sat Nov 11 02:40:02 1989
X***************
X*** 17,23 ****
X  #include <setjmp.h>
X  
X  
X! #define VERSION			"2.6 (11/08/89)"
X  
X  #define DROPNAME 	     "/usr/spool/mail/%s"   /* User Mailbox */
X  #define LOCKNAME	"/usr/spool/mail/%s.lock"   /* lockfile for box */
X--- 17,23 ----
X  #include <setjmp.h>
X  
X  
X! #define VERSION			"2.7 (11/10/89)"
X  
X  #define DROPNAME 	     "/usr/spool/mail/%s"   /* User Mailbox */
X  #define LOCKNAME	"/usr/spool/mail/%s.lock"   /* lockfile for box */
X***************
X*** 63,71 ****
X  
X  
X  extern char *Version;
X! extern int remote;			/* use RMAIL to deliver (if any) */
X! extern int loclink;			/* LMAIL: local delivery only! */
X! extern int old_uid, old_gid;		/* UID/GID of calling user */
X  extern int printmode;			/* print-and-exit mode */
X  extern int immediate;			/* send remote immediately! */
X  extern int quitmode;			/* take interrupts */
X--- 63,71 ----
X  
X  
X  extern char *Version;
X! extern int old_uid, old_gid;		/* "real" ID's of caller */
X! extern int remote;			/* use RMAIL to deliver (if any) */
X! extern int loclink;			/* LMAIL: local delivery only! */
X  extern int printmode;			/* print-and-exit mode */
X  extern int immediate;			/* send remote immediately! */
X  extern int quitmode;			/* take interrupts */
X***************
X*** 99,104 ****
X--- 99,105 ----
X  extern char *basename(/* char *name */);
X  extern char *basepath(/* char *name */);
X  extern char *whoami(/* void */);
X+ extern int allowed(/* char *name, int mode */);
X  extern void showlet(/* LETTER *let */);
X  extern void printlet(/* LETTER *let, FILE *tofp */);
X  extern void printall(/* void */);
X*** old/wmcreate.c	Sat Nov 11 03:51:41 1989
X--- wmcreate.c	Sat Nov 11 02:28:11 1989
X***************
X*** 15,20 ****
X--- 15,21 ----
X   *
X   * Revisions:
X   *		11/07/89 FvK	Edited a little for the new MSS.
X+  *		11/10/89 FvK	Fixed the overall security-bug.
X   */
X  #include <stdio.h>
X  #include <string.h>
X***************
X*** 96,101 ****
X--- 97,103 ----
X  	/*
X  	 * Add a .signature file after the message.
X  	 * Skip this if infp is a file.
X+ 	 * Check first for security!
X  	 */
X  	if (isatty(fileno(infp))) {
X  		sp = getenv("SIGNATURE");
X***************
X*** 108,116 ****
X                		strcat(tmp, SIGNATURE);
X  	 	} else strcpy(tmp, sp);
X  
X! 		if ((sigfp = fopen(tmp, "r")) != (FILE *)NULL) {
X! 			while ((c = fgetc(sigfp)) != EOF) fputc(c, tempfp);
X! 	        	fclose(sigfp);
X  		}
X    	}
X    } else {	/* Fast file copy for local delivery. */
X--- 110,125 ----
X                		strcat(tmp, SIGNATURE);
X  	 	} else strcpy(tmp, sp);
X  
X! 		/* Check if we may read the file. */
X! 		if (allowed(tmp, 04) == TRUE) {
X! 			if ((sigfp = fopen(tmp, "r")) != (FILE *)NULL) {
X! 				while ((c = fgetc(sigfp)) != EOF)
X! 							fputc(c, tempfp);
X! 	        		fclose(sigfp);
X! 			}
X! 		} else {
X! 			fprintf(stderr, "%s: cannot read file \"%s\"\n",
X! 							progname, tmp);
X  		}
X    	}
X    } else {	/* Fast file copy for local delivery. */
X*** old/wmdeliver.c	Sat Nov 11 03:52:30 1989
X--- wmdeliver.c	Sat Nov 11 02:32:43 1989
X***************
X*** 16,21 ****
X--- 16,22 ----
X   * Revisions:
X   *		11/07/89 FvK	Edited a little for the new MSS.
X   *				Fixed "dead.letter" pathname.
X+  *		11/10/89 FvK	Fixed the overall security-bug.
X   *
X   * To Do:
X   *		- Aliases.
X***************
X*** 185,191 ****
X        	if ((pw = getpwnam(adressee)) == (struct passwd *)NULL) {
X  		fprintf(stderr, "%s: user %s unknown\n", progname, adressee);
X  		++errs;
X- 		dead_letter();
X  		continue;
X         	} else {
X  	   	sprintf(mailbox, DROPNAME, adressee);
X--- 186,191 ----
X***************
X*** 210,216 ****
X  					"%s: forward-user %s unknown\n",
X  							progname, adressee);
X  		   		++errs;
X- 				dead_letter();
X  		   		continue;
X  	          	} else {
X  		         	sprintf(mailbox, DROPNAME, adressee);
X--- 210,215 ----
X***************
X*** 236,242 ****
X  				 "%s: could not create maildrop for %s\n",
X  		      					  progname, vec[i]);
X  				++errs;
X- 				dead_letter();
X  				continue;
X            		}
X  	  		++created;
X--- 235,240 ----
X***************
X*** 247,253 ****
X  				  "%s: could not lock maildrop for %s\n",
X  		      					progname, vec[i]);
X  				++errs;
X- 				dead_letter();
X  	      	   		continue;
X  	     	  	}
X  	   	 	sleep(LOCKWAIT);
X--- 245,250 ----
X***************
X*** 265,271 ****
X  							progname, vec[i]);
X          	unlink(lockname);
X          	++errs;
X- 		dead_letter();
X          	continue;
X         	}
X  
X--- 262,267 ----
X***************
X*** 274,280 ****
X  							progname, vec[i]);
X  		unlink(lockname);
X  		++errs;
X- 		dead_letter();
X  		continue;
X         	}
X  
X--- 270,275 ----
X***************
X*** 291,297 ****
X  		fprintf(stderr, "%s: error delivering to user %s",
X  							progname, vec[i]);
X  		perror("");
X- 		dead_letter();
X  		++errs;
X         	}
X  
X--- 286,291 ----
X***************
X*** 305,346 ****
X    signal(SIGHUP, sighup);
X    signal(SIGQUIT, sigquit);
X  
X!   return((errs == 0) ? FALSE : TRUE);
X  }
X  
X  
X  /* 
X   * Save the current message to file 'dead.letter'.
X-  * This is sometimes needed when delivery fails.
X   *
X   * If the environmental variable "DEADLETTER" is defined,
X   * use its value as the file name. Otherwise, use DEADLETTER
X!  * in the current directory.
X   */
X  void dead_letter(void)
X  {
X    char cpbuff[1024];
X    char fname[PATHLEN];
X!   char *sp;
X!   register FILE *inf, *outf;
X  
X    fname[0] = '\0';
X    inf = fopen(msg_temp, "r");
X    if ((sp = getenv("DEADLETTER")) != NULL) strcpy(fname, sp);
X      else strcpy(fname, DEADLETTER);
X  
X!   inf = fopen(msg_temp, "r");
X!   if (inf == (FILE *)NULL) {
X  	fprintf(stderr, "%s: cannot open \"%s\"\n", progname, msg_temp);
X  	return;
X    }
X  
X!   outf = fopen(fname, "w");
X!   if (outf == (FILE *)NULL) {
X! 	fprintf(stderr, "%s: cannot create \"%s\"\n", progname, fname);
X  	return;
X    }
X  
X    /* Copy temp. file to dead.letter. */
X    while (TRUE) {
X  	if (fgets(cpbuff, sizeof(cpbuff), inf) == (char *)NULL) break;
X--- 299,348 ----
X    signal(SIGHUP, sighup);
X    signal(SIGQUIT, sigquit);
X  
X!   return((errs == 0) ? 0 : -1);
X  }
X  
X  
X  /* 
X   * Save the current message to file 'dead.letter'.
X   *
X   * If the environmental variable "DEADLETTER" is defined,
X   * use its value as the file name. Otherwise, use DEADLETTER
X!  * in the current directory. Check if we may write to that file!
X   */
X  void dead_letter(void)
X  {
X    char cpbuff[1024];
X    char fname[PATHLEN];
X!   register FILE *inf, *outf;
X!   char *sp;
X  
X    fname[0] = '\0';
X    inf = fopen(msg_temp, "r");
X    if ((sp = getenv("DEADLETTER")) != NULL) strcpy(fname, sp);
X      else strcpy(fname, DEADLETTER);
X  
X!   /* Open the message file. */
X!   if ((inf = fopen(msg_temp, "r")) == (FILE *)NULL) {
X  	fprintf(stderr, "%s: cannot open \"%s\"\n", progname, msg_temp);
X  	return;
X    }
X  
X!   /* Check if we may create/write that file. */
X!   if (allowed(fname, 02) == FALSE) {
X! 	/* We may not. Say so! */
X! 	fprintf(stderr, "%s: cannot create \"%s\"\n", progname, fname);
X! 	fclose(inf);
X  	return;
X    }
X  
X+   /* We may, create the dump-file. */
X+   if ((outf = fopen(fname, "w")) == (FILE *)NULL) {
X+ 	fprintf(stderr, "%s: cannot create \"%s\"\n", progname, fname);
X+ 	fclose(inf);
X+ 	return;
X+   }
X+ 
X    /* Copy temp. file to dead.letter. */
X    while (TRUE) {
X  	if (fgets(cpbuff, sizeof(cpbuff), inf) == (char *)NULL) break;
X***************
X*** 350,355 ****
X    fclose(inf);
X    fclose(outf);
X  
X!   chown(fname, old_uid, old_gid);
X!   fprintf(stderr, "%s: dumped message on file \"%s\"\n", progname, fname);
X! }
X--- 352,356 ----
X    fclose(inf);
X    fclose(outf);
X  
X!   fprintf(stderr, "%s: dumped message on file \"%s\"\n", progname, fname);
X! }
X*** old/wminteract.c	Sat Nov 11 03:52:03 1989
X--- wminteract.c	Sat Nov 11 02:37:24 1989
X***************
X*** 15,26 ****
X--- 15,28 ----
X   *
X   * Revisions:
X   *		11/07/89 FvK	Edited a little for the new MSS.
X+  *		11/10/89 FvK	Fixed the overall security-bug.
X   *
X   * To Do:
X   *		- Builtin escapes (~i and friends)
X   */
X  #include <stdio.h>
X  #include <ctype.h>
X+ #include <errno.h>
X  #include <string.h>
X  #include <signal.h>
X  #include <unistd.h>
X***************
X*** 61,68 ****
X    if ((shell = getenv("SHELL")) == NULL) shell = SHELL;
X  
X    if ((pid = fork()) == 0) {
X! 	setgid(old_gid);	/* UUCP or USER */
X! 	setuid(old_uid);	/* UUCP or USER */
X  	umask(oldmask);
X  
X  	execl(shell, shell, "-c", command, NULL);
X--- 63,70 ----
X    if ((shell = getenv("SHELL")) == NULL) shell = SHELL;
X  
X    if ((pid = fork()) == 0) {
X! 	setuid(old_uid);	/* security! */
X! 	setgid(old_gid);
X  	umask(oldmask);
X  
X  	execl(shell, shell, "-c", command, NULL);
X***************
X*** 112,117 ****
X--- 114,121 ----
X  
X  /*
X   * Save the current letter to a disk-file.
X+  * Do this as a child process to make sure we
X+  * do not violate system security!
X   */
X  void savelet(let, savefile, withhead)
X  LETTER *let;
X***************
X*** 121,138 ****
X    off_t curr, limit, oldpos;
X    register char *bp;
X    FILE *savefp;
X!   int c;
X  
X    bp = savefile;
X    while (*bp && *bp!='\n') bp++;
X    *bp = '\0';
X  
X!   if ((savefp = fopen(savefile, "a")) == (FILE *)NULL) {
X  	fprintf(stderr, "%s: cannot append to savefile \"%s\"\n",
X  							progname, savefile);
X  	return;
X    }
X  
X    oldpos = ftell(boxfp);
X    fseek(boxfp, (curr = let->location), SEEK_SET);
X    limit = (let->next != NIL_LET) ? let->next->location : -1L;
X--- 125,152 ----
X    off_t curr, limit, oldpos;
X    register char *bp;
X    FILE *savefp;
X!   int c, temp;
X  
X    bp = savefile;
X    while (*bp && *bp!='\n') bp++;
X    *bp = '\0';
X  
X!   /* Check if we may write to that file. */
X!   if (allowed(savefile, 02) == FALSE) {
X  	fprintf(stderr, "%s: cannot append to savefile \"%s\"\n",
X  							progname, savefile);
X  	return;
X    }
X  
X+   /* We may, go ahead! */
X+   if ((savefp = fopen(savefile, "a")) == (FILE *)NULL) {
X+ 	fprintf(stderr, "%s: cannot append to savefile \"%s\"\n",
X+ 							progname, savefile);
X+ 	return;
X+   }
X+ 
X+   temp = umask(oldmask);	/* set previous umask() */
X+ 
X    oldpos = ftell(boxfp);
X    fseek(boxfp, (curr = let->location), SEEK_SET);
X    limit = (let->next != NIL_LET) ? let->next->location : -1L;
X***************
X*** 149,154 ****
X--- 163,170 ----
X  	fprintf(stderr, "%s: savefile write error:", progname);
X    }
X  
X+   umask(temp);		/* set previous umask() */
X+ 
X    chown(savefile, old_uid, old_gid);
X  }
X  
X*** old/wmmain.c	Sat Nov 11 03:51:15 1989
X--- wmmain.c	Sat Nov 11 03:46:34 1989
X***************
X*** 17,22 ****
X--- 17,23 ----
X   *				it uses too much space now.
X   *				Fixed the "reply" bug that was caused
X   *				by a badly-decoded "From_" line.
X+  *		11/10/89 FvK	Fixed the overall security-bug.
X   */
X  #include <sys/stat.h>
X  #include <stdio.h>
X***************
X*** 29,37 ****
X  
X  
X  char *Version = VERSION;
X! int remote = FALSE;			/* use RMAIL to deliver (if any) */
X! int loclink = FALSE;			/* LMAIL: local delivery only! */
X! int old_uid, old_gid;			/* UID/GID of calling user */
X  int printmode = FALSE;			/* print-and-exit mode */
X  int immediate = FALSE;			/* send remote immediately! */
X  int quitmode = FALSE;			/* take interrupts */
X--- 30,38 ----
X  
X  
X  char *Version = VERSION;
X! int old_uid, old_gid;			/* "real" ID's of caller */
X! int remote = FALSE;			/* use RMAIL to deliver (if any) */
X! int loclink = FALSE;			/* LMAIL: local delivery only! */
X  int printmode = FALSE;			/* print-and-exit mode */
X  int immediate = FALSE;			/* send remote immediately! */
X  int quitmode = FALSE;			/* take interrupts */
X***************
X*** 110,194 ****
X  
X  
X  /*
X!  * Find the given entry in the mail-header
X!  * Search for the first occurence of string 'text' in the header.
X!  * Copy the text following it into the 'let' structure.
X!  * Return buffer if found, else NULL.
X!  */
X! char *find_string(let, text)
X! LETTER *let;
X! char *text;
X! {
X!   static char findbuff[128];
X!   static char inbuff[512];
X!   off_t curr, limit;
X!   register char *sp;
X!   int all;
X! 
X!   fseek(boxfp, let->location, SEEK_SET);
X!   limit = (off_t) -1L;
X!   if (let->next != NIL_LET) limit = let->next->location;
X! 
X!   all = FALSE;
X!   curr = let->location;
X!   while (curr != limit && all==FALSE) {
X! 	if (fgets(inbuff, sizeof(inbuff), boxfp) == NULL) all = TRUE;
X!       	if (inbuff[0] == '\0') all = TRUE; /* end-of-header */
X! 
X!       	if (!strncmp(inbuff, text, strlen(text))) {
X! 		sp = &inbuff[0];		/* remove '\n' */
X!       		while (*sp && *sp!='\n') sp++;
X!       		*sp = '\0';
X! 		sp = &inbuff[0] + strlen(text);	/* copy to static buff */
X! 		strcpy(findbuff, sp);
X! 		return(findbuff);		/* return adress of buff */
X!        	}
X! 
X! 	curr += (off_t) strlen(inbuff);		/* update message offset */
X! 
X! 	if (all==FALSE && limit > 0L)		/* quit if past message */
X! 		if (curr >= limit) all = TRUE;
X!   }
X!   return(NULL);
X  }
X  
X  
X  /*
X!  * Check is the first line of the mailbox contains a line like
X!  *
X!  *	Forward to XXXX
X!  *
X!  * then all mail for the calling user is being forwarded
X!  * to user XXXX. Return a 1 value if this is the case.
X!  * Otherwise, return 0 (or -1 for error).
X!  */
X! int chk_box(void)
X! {
X!   char xbuf[128];
X!   FILE *fp;
X!   char *bp;
X! 
X!   if (access(mailbox, 4) < 0 || 
X!     (fp = fopen(mailbox, "r")) == (FILE *)NULL) {
X! 	if (usedrop && errno==ENOENT) return(-1);
X!      	fprintf(stderr, "%s: cannot access mailbox ", progname);
X!       	perror(mailbox);
X!       	exit(1);
X!   }
X! 
X!   bp = fgets(xbuf, sizeof(xbuf), fp);
X!   fclose(fp);
X! 
X!   if (bp!=NULL && !strncmp(xbuf, "Forward to ", 11)) {
X! 	strcpy(forward, strrchr(xbuf, ' ') + 1);	/* get username */
X! 	forward[strlen(forward)-1] = '\0';		/* remove \n */
X! 	return(1);
X!   }
X!   return(0);
X  }
X  
X  
X  /*
X   * Decode an old-style (V6/V7) mail header.
X   * This is a line like:
X   *
X--- 111,238 ----
X  
X  
X  /*
X!  * Check if we may perform operation 'mode' on
X!  * file 'name'. System Security!
X!  * If the error is 'ENOENT', then test the parent
X!  * directory for the desired access.
X!  */
X! int allowed(name, mode)
X! char *name;			/* name of file to be checked */
X! unsigned short mode;		/* mode to check (R=4, W=2, X=1) */
X! {
X!   char abuf[1024];		/* temp. buf for filename */
X!   struct stat stb;
X!   char *p;
X! 
X!   /* Is this 'The Master' calling? */
X!   if (old_uid == 0 && old_gid == 0) return(TRUE);
X! 
X!   if (stat(name, &stb) < 0) {
X! 	if (errno == ENOENT) {			/* file does not exist */
X! 		strcpy(abuf, name);		/* so check its parent dir */
X! 		p = strrchr(abuf, '/');	
X! 		if (p == (char *)NULL)		/* plain filename, */
X! 			getcwd(abuf, 1023);	/* get current dir */
X! 		  else *p = '\0';		/* strip 'file' part */
X! 		if (stat(abuf, &stb) < 0) return(FALSE);	/* error? */
X! 	} else return(FALSE);			/* it exists, other error! */
X!   }
X! 
X!   /* We now have the status of the file or its parent dir. */
X!   if (stb.st_uid == old_uid) {			/* we are owner! */
X! 	if ((stb.st_mode >> 6) & mode)
X! 				 return(TRUE);	/* OK, we may do it. */
X!   	  else return(FALSE);			/* Alas... */
X!   } else if (stb.st_uid == old_gid) {		/* are we the same group? */
X! 	if ((stb.st_mode >>3) & mode)
X! 				 return(TRUE);	/* OK, we may do it. */
X!   	  else return(FALSE);			/* Alas... */
X!   } else if (stb.st_mode & mode)		/* we are 'others' */
X! 				 return(TRUE);	/* OK, we may do it. */
X!   return(FALSE);				/* Alas... */
X  }
X  
X  
X  /*
X!  * Find the given entry in the mail-header
X!  * Search for the first occurence of string 'text' in the header.
X!  * Copy the text following it into the 'let' structure.
X!  * Return buffer if found, else NULL.
X!  */
X! char *find_string(let, text)
X! LETTER *let;
X! char *text;
X! {
X!   static char findbuff[128];
X!   static char inbuff[512];
X!   off_t curr, limit;
X!   register char *sp;
X!   int all;
X! 
X!   fseek(boxfp, let->location, SEEK_SET);
X!   limit = (off_t) -1L;
X!   if (let->next != NIL_LET) limit = let->next->location;
X! 
X!   all = FALSE;
X!   curr = let->location;
X!   while (curr != limit && all==FALSE) {
X! 	if (fgets(inbuff, sizeof(inbuff), boxfp) == NULL) all = TRUE;
X!       	if (inbuff[0] == '\0') all = TRUE; /* end-of-header */
X! 
X!       	if (!strncmp(inbuff, text, strlen(text))) {
X! 		sp = &inbuff[0];		/* remove '\n' */
X!       		while (*sp && *sp!='\n') sp++;
X!       		*sp = '\0';
X! 		sp = &inbuff[0] + strlen(text);	/* copy to static buff */
X! 		strcpy(findbuff, sp);
X! 		return(findbuff);		/* return adress of buff */
X!        	}
X! 
X! 	curr += (off_t) strlen(inbuff);		/* update message offset */
X! 
X! 	if (all==FALSE && limit > 0L)		/* quit if past message */
X! 		if (curr >= limit) all = TRUE;
X!   }
X!   return(NULL);
X  }
X  
X  
X  /*
X+  * Check is the first line of the mailbox contains a line like
X+  *
X+  *	Forward to XXXX
X+  *
X+  * then all mail for the calling user is being forwarded
X+  * to user XXXX. Return a 1 value if this is the case.
X+  * Otherwise, return 0 (or -1 for error).
X+  */
X+ int chk_box(void)
X+ {
X+   char xbuf[128];
X+   FILE *fp;
X+   char *bp;
X+ 
X+   if (access(mailbox, 4) < 0 || 
X+     (fp = fopen(mailbox, "r")) == (FILE *)NULL) {
X+ 	if (usedrop && errno==ENOENT) return(-1);
X+      	fprintf(stderr, "%s: cannot access mailbox ", progname);
X+       	perror(mailbox);
X+       	exit(1);
X+   }
X+ 
X+   bp = fgets(xbuf, sizeof(xbuf), fp);
X+   fclose(fp);
X+ 
X+   if (bp!=NULL && !strncmp(xbuf, "Forward to ", 11)) {
X+ 	strcpy(forward, strrchr(xbuf, ' ') + 1);	/* get username */
X+ 	forward[strlen(forward)-1] = '\0';		/* remove \n */
X+ 	return(1);
X+   }
X+   return(0);
X+ }
X+ 
X+ 
X+ /*
X   * Decode an old-style (V6/V7) mail header.
X   * This is a line like:
X   *
X***************
X*** 361,371 ****
X  {
X    int c, st;
X  
X!   strcpy(sender, whoami());
X!   old_uid = getuid();			/* get calling user and save */
X!   old_gid = getgid();
X!   setuid(geteuid());			/* set UID to ROOT (SU) */
X!   setgid(getegid());			/* set GID to ROOT (SU) */
X  
X    progname = basename(argv[0]);		/* how are we called? */
X    if (*progname == 'l') {
X--- 405,416 ----
X  {
X    int c, st;
X  
X!   strcpy(sender, whoami());		/* get our real name */
X! 
X!   old_uid = getuid();			/* This is dangerous, but */
X!   old_gid = getgid();			/* is is necessary for the */
X!   setuid(geteuid());			/* message delivery! */
X!   setgid(getegid());
X  
X    progname = basename(argv[0]);		/* how are we called? */
X    if (*progname == 'l') {
X***************
X*** 385,393 ****
X  		checkonly++;
X  		break;
X  	case 'f':	/* use another mailbox. */
X! 		setuid(old_uid);
X! 		setgid(old_gid);
X! 		usedrop = FALSE;
X  		strncpy(mailbox, optarg, PATHLEN - 1);
X  		break;
X  	case 'i':	/* Use another input-file. */
X--- 430,438 ----
X  		checkonly++;
X  		break;
X  	case 'f':	/* use another mailbox. */
X! 		usedrop = FALSE;
X! 		setuid(old_uid);	/* security! */
X! 		setgid(old_gid);
X  		strncpy(mailbox, optarg, PATHLEN - 1);
X  		break;
X  	case 'i':	/* Use another input-file. */
X***************
X*** 442,449 ****
X  
X  		 if (needupdate) updatebox();
X  	}
X!     } else st = deliver(argc - optind, argv + optind);
X! 
X!   unlink(msg_temp);
X!   exit(st);    
X! }
X--- 487,497 ----
X  
X  		 if (needupdate) updatebox();
X  	}
X!   } else {
X! 	  st = deliver(argc - optind, argv + optind);
X! 
X! 	  if (st != 0) dead_letter();	/* something went wrong... */
X!   }
X!   unlink(msg_temp);
X!   exit(st);    
X! }
X*** old/wmread.c	Sat Nov 11 03:51:30 1989
X--- wmread.c	Sat Nov 11 01:34:47 1989
X***************
X*** 15,20 ****
X--- 15,21 ----
X   *
X   * Revisions:
X   *		11/07/89 FvK	Edited a little for the new MSS.
X+  *		11/10/89 FvK	Increased more() buffer size.
X   *
X   * To Do:
X   *		- TERMCAP/TERMINFO use !
X***************
X*** 26,32 ****
X  #include "wmail.h"
X  
X  
X! static char mobuf[128];		/* output buffer */
X  static int mline;		/* current terminal line */
X  static int mcol;		/* current terminal column */
X  static int mobc;		/* position in output buffer (== chars in) */
X--- 27,33 ----
X  #include "wmail.h"
X  
X  
X! static char mobuf[512];		/* output buffer */
X  static int mline;		/* current terminal line */
X  static int mcol;		/* current terminal column */
X  static int mobc;		/* position in output buffer (== chars in) */
X***************
X*** 159,166 ****
X    st = mline = mcol = mobc = misdone = 0;
X    printf("Message %d:\n", let->seqno);
X    while(curr != limit && ((c = fgetc(boxfp)) != EOF) && st==0) {
X! 	if (mobc == 128) {
X! 		st = lwrite(fd, mobuf, 128);
X          	mobc = 0;
X         	}
X        	mobuf[mobc++] = (char) c;
X--- 160,167 ----
X    st = mline = mcol = mobc = misdone = 0;
X    printf("Message %d:\n", let->seqno);
X    while(curr != limit && ((c = fgetc(boxfp)) != EOF) && st==0) {
X! 	if (mobc == 512) {
X! 		st = lwrite(fd, mobuf, mobc);
X          	mobc = 0;
X         	}
X        	mobuf[mobc++] = (char) c;
X
END_OF_SHAR
fi
echo "		End of archive"
rm -f /tmp/uudecode
exit 0
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
| MINIX User Group (Holland)   UUCP: hp4nl!kyber!minixug!waltje	|
| c/o Fred van Kempen,		 or: minixug!waltje@kyber.UUCP	|
| Hoefbladhof  27						|
| 2215 DV  VOORHOUT						|
| The Netherlands	"A good programmer knows his Sources"	|
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+