Subject: bin/4239: Quota support for mail.local
To: None <gnats-bugs@gnats.netbsd.org>
From: None <jmarin@jmp.fi>
List: netbsd-bugs
Date: 10/08/1997 11:50:31
>Number: 4239
>Category: bin
>Synopsis: Adding user quota support to mail.local
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Wed Oct 8 02:05:01 1997
>Last-Modified:
>Originator: Jukka Marin
>Organization:
JMP-Electronics
>Release: 1.2
>Environment:
NetBSD 1.2 and -current
>Description:
mail.local doesn't check the user quota, so mail boxes can grow
and fill the entire disk partition. The supplied fix adds a
new command line option to mail.local to enable quota checking.
>How-To-Repeat:
Send huge mail messages -> the spool partition fills up.
>Fix:
Apply this patch to mail.local of NetBSD 1.2:
*** mail.local.c.orig Wed Oct 8 11:40:30 1997
--- mail.local.c Wed Oct 8 11:40:47 1997
***************
*** 53,58 ****
--- 53,59 ----
#include <time.h>
#include <unistd.h>
#include <errno.h>
+ #include <sysexits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
***************
*** 61,67 ****
#define FATAL 1
#define NOTFATAL 0
! int deliver __P((int, char *, int));
void err __P((int, const char *, ...));
void notifybiff __P((char *));
int store __P((char *));
--- 62,68 ----
#define FATAL 1
#define NOTFATAL 0
! int deliver __P((int, char *, int, int));
void err __P((int, const char *, ...));
void notifybiff __P((char *));
int store __P((char *));
***************
*** 74,87 ****
extern int optind;
extern char *optarg;
struct passwd *pw;
! int ch, fd, eval, lockfile=0;
uid_t uid;
char *from;
openlog("mail.local", LOG_PERROR, LOG_MAIL);
from = NULL;
! while ((ch = getopt(argc, argv, "ldf:r:")) != EOF)
switch(ch) {
case 'd': /* backward compatible */
break;
--- 75,88 ----
extern int optind;
extern char *optarg;
struct passwd *pw;
! int ch, fd, eval, lockfile=0, quota=0;
uid_t uid;
char *from;
openlog("mail.local", LOG_PERROR, LOG_MAIL);
from = NULL;
! while ((ch = getopt(argc, argv, "ldf:qr:")) != EOF)
switch(ch) {
case 'd': /* backward compatible */
break;
***************
*** 94,99 ****
--- 95,103 ----
case 'l':
lockfile++;
break;
+ case 'q':
+ quota++;
+ break;
case '?':
default:
usage();
***************
*** 116,122 ****
fd = store(from);
for (eval = 0; *argv; ++argv)
! eval |= deliver(fd, *argv, lockfile);
exit(eval);
}
--- 120,126 ----
fd = store(from);
for (eval = 0; *argv; ++argv)
! eval |= deliver(fd, *argv, lockfile, quota);
exit(eval);
}
***************
*** 163,169 ****
return(fd);
}
! deliver(fd, name, lockfile)
int fd;
char *name;
int lockfile;
--- 167,173 ----
return(fd);
}
! deliver(fd, name, lockfile, quota)
int fd;
char *name;
int lockfile;
***************
*** 173,178 ****
--- 177,183 ----
int created, mbfd, nr, nw, off, rval=0, lfd=-1;
char biffmsg[100], buf[8*1024], path[MAXPATHLEN], lpath[MAXPATHLEN];
off_t curoff;
+ uid_t oeuid;
/*
* Disallow delivery to unknown names -- special mailboxes can be
***************
*** 200,213 ****
err(NOTFATAL, "%s: linked file", path);
return(1);
}
! if((mbfd = open(path, O_APPEND|O_WRONLY|O_EXLOCK,
! S_IRUSR|S_IWUSR)) < 0) {
if ((mbfd = open(path, O_APPEND|O_CREAT|O_WRONLY|O_EXLOCK,
S_IRUSR|S_IWUSR)) < 0) {
err(NOTFATAL, "%s: %s", path, strerror(errno));
return(1);
}
- }
curoff = lseek(mbfd, 0, SEEK_END);
(void)sprintf(biffmsg, "%s@%qd\n", name, curoff);
--- 205,235 ----
err(NOTFATAL, "%s: linked file", path);
return(1);
}
!
! /* if mailbox does not exist, create it */
! if (created) {
if ((mbfd = open(path, O_APPEND|O_CREAT|O_WRONLY|O_EXLOCK,
S_IRUSR|S_IWUSR)) < 0) {
+ err(NOTFATAL, "%s: %s", path, strerror(errno));
+ return(1);
+ }
+ (void)fchown(mbfd, pw->pw_uid, pw->pw_gid);
+ (void)close(mbfd);
+ }
+
+ /* save original effective uid */
+ oeuid = geteuid();
+
+ /* if told to look for quota limits, use user privileges */
+ if (quota)
+ seteuid(pw->pw_uid);
+
+ if((mbfd = open(path, O_APPEND|O_WRONLY|O_EXLOCK,
+ S_IRUSR|S_IWUSR)) < 0) {
err(NOTFATAL, "%s: %s", path, strerror(errno));
+ /* return original euid */
return(1);
}
curoff = lseek(mbfd, 0, SEEK_END);
(void)sprintf(biffmsg, "%s@%qd\n", name, curoff);
***************
*** 220,249 ****
while ((nr = read(fd, buf, sizeof(buf))) > 0)
for (off = 0; off < nr; off += nw)
if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
err(NOTFATAL, "%s: %s", path, strerror(errno));
! goto trunc;
}
if (nr < 0) {
err(FATAL, "temporary file: %s", strerror(errno));
- trunc: (void)ftruncate(mbfd, curoff);
rval = 1;
}
- /*
- * Set the owner and group. Historically, binmail repeated this at
- * each mail delivery. We no longer do this, assuming that if the
- * ownership or permissions were changed there was a reason for doing
- * so.
- */
bad:
if(lockfile) {
if(lfd >= 0) {
unlink(lpath);
close(lfd);
}
}
- if (created)
- (void)fchown(mbfd, pw->pw_uid, pw->pw_gid);
(void)fsync(mbfd); /* Don't wait for update. */
(void)close(mbfd); /* Implicit unlock. */
--- 242,273 ----
while ((nr = read(fd, buf, sizeof(buf))) > 0)
for (off = 0; off < nr; off += nw)
if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
+ if (errno == EDQUOT) {
+ err(NOTFATAL, "User %s mailbox is full (%s)",
+ pw->pw_name, strerror(errno));
+ rval = 1 /*EX_TEMPFAIL*/;
+ } else {
err(NOTFATAL, "%s: %s", path, strerror(errno));
! rval = 1;
! }
! goto trunc;
}
if (nr < 0) {
err(FATAL, "temporary file: %s", strerror(errno));
rval = 1;
+ trunc: (void)ftruncate(mbfd, curoff);
}
bad:
+ /* return original euid */
+ seteuid(oeuid);
+
if(lockfile) {
if(lfd >= 0) {
unlink(lpath);
close(lfd);
}
}
(void)fsync(mbfd); /* Don't wait for update. */
(void)close(mbfd); /* Implicit unlock. */
***************
*** 289,295 ****
void
usage()
{
! err(FATAL, "usage: mail.local [-f from] user ...");
}
#if __STDC__
--- 313,319 ----
void
usage()
{
! err(FATAL, "usage: mail.local [-f from] [-q] user ...");
}
#if __STDC__
>Audit-Trail:
>Unformatted: