diff -uNr release-20010228/src/global/mail_params.h release-20010228.patched/src/global/mail_params.h --- release-20010228/src/global/mail_params.h Sun Feb 25 13:34:21 2001 +++ release-20010228.patched/src/global/mail_params.h Mon Aug 13 11:53:46 2001 @@ -1230,6 +1230,17 @@ #define DEF_VIRT_MAILBOX_LOCK "fcntl" extern char *var_virt_mailbox_lock; +/* + * Inbox size limiting. Only works for mbox type inboxes. + */ +#define VAR_DEFAULT_MAILBOX_SIZE "default_mailbox_size" +#define DEF_DEFAULT_MAILBOX_SIZE 0 +extern int var_default_mailbox_size; + +#define VAR_MAILBOX_SIZE_MAP "mailbox_size_map" +#define DEF_MAILBOX_SIZE_MAP "" +extern char *var_mailbox_size_map; + /* LICENSE /* .ad /* .fi diff -uNr release-20010228/src/local/local.c release-20010228.patched/src/local/local.c --- release-20010228/src/local/local.c Tue Feb 27 20:51:06 2001 +++ release-20010228.patched/src/local/local.c Mon Aug 13 11:53:46 2001 @@ -226,6 +226,23 @@ /* When those files are owned by the superuser, delivery is made with /* the rights specified with the \fBdefault_privs\fR configuration /* parameter. +/* MAILBOX SIZE LIMITING +/* .ad +/* .fi +/* In case of thousands of mailboxes and limited diskspace there may be +/* need for mailbox size limiting. +/* +/* There are two configurable parameters to accomplish this purpose: +/* \fBvar_default_mailbox_size\fR and \fBvar_mailbox_size_map\fR. See +/* the exact usage elsewhere in this document in the \fBONFIGURATION +/* PARAMETERS\fR section. +/* +/* Mailbox size limiting works only for \fBmail_spool_directory\fR and for +/* \fBhome_mailbox\fR, and not for \fBqmail\fR-compatible \fRmaildir\fB or +/* external file delivery. +/* +/* If mailbox size limit is exceeded the mail will be bounced back with +/* error message "Recipient's mailbox is full.". /* STANDARDS /* RFC 822 (ARPA Internet Text Messages) /* DIAGNOSTICS @@ -244,6 +261,12 @@ /* Mutually-recursive aliases or ~/.\fBforward\fR files are not detected /* early. The resulting mail forwarding loop is broken by the use of the /* \fBDelivered-To:\fR message header. +/* +/* The mailbox size limiting code does not work with maildir type mail- +/* spools, and worse yet, hasn't been proven to work on all systems +/* supported by the base postfix code. Using filesystem quotas is a more +/* generic solution. This code is provided to address those situations +/* where the use of filesystem quotas is either undesirable or impossible. /* CONFIGURATION PARAMETERS /* .ad /* .fi @@ -333,6 +356,12 @@ /* .fi /* .IP \fBcommand_time_limit\fR /* Limit the amount of time for delivery to external command. +/* .IP \fBdefault_mailbox_size\fR +/* Limit mailbox sizes in \fBmail_spool_directory\fR or in +/* \fBhome_mailbox\fR directory. Size is specified in in kbytes. +/* A setting of 0 disables size checking. +/* (The \fBmailbox_size_limit\fR parameter still applies.) +/* See also \fBmailbox_size_map\fR, \fBmailbox_size_limit\fR. /* .IP \fBduplicate_filter_limit\fR /* Limit the size of the duplicate filter for results from /* alias etc. expansion. @@ -351,6 +380,12 @@ /* Limit the size of a mailbox etc. file (any file that is /* written to upon delivery). /* Set to zero to disable the limit. +/* .IP \fBmailbox_size_map\fR +/* This parameter specifies a map which is per-user list of mailbox size +/* limits. It takes precedence over the \fBdefault_mailbox_size\fR. A +/* setting of 0 disables size limit checking for this user. (The +/* \fBmailbox_size_limit\fR parameter still applies.) +/* See also \fBdefault_mailbox_size\fR, \fBmailbox_size_limit\fR. /* .SH "Security controls" /* .ad /* .fi @@ -463,6 +498,8 @@ int var_mailtool_compat; char *var_mailbox_lock; int var_mailbox_limit; +int var_default_mailbox_size; +char *var_mailbox_size_map; int local_cmd_deliver_mask; int local_file_deliver_mask; @@ -665,6 +702,7 @@ static CONFIG_INT_TABLE int_table[] = { VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dup_filter_limit, 0, 0, VAR_MAILBOX_LIMIT, DEF_MAILBOX_LIMIT, &var_mailbox_limit, 0, 0, + VAR_DEFAULT_MAILBOX_SIZE, DEF_DEFAULT_MAILBOX_SIZE, &var_default_mailbox_size, 0, 0, 0, }; static CONFIG_STR_TABLE str_table[] = { @@ -681,6 +719,7 @@ VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0, VAR_DELIVER_HDR, DEF_DELIVER_HDR, &var_deliver_hdr, 0, 0, VAR_MAILBOX_LOCK, DEF_MAILBOX_LOCK, &var_mailbox_lock, 1, 0, + VAR_MAILBOX_SIZE_MAP, DEF_MAILBOX_SIZE_MAP, &var_mailbox_size_map, 0, 0, 0, }; static CONFIG_BOOL_TABLE bool_table[] = { diff -uNr release-20010228/src/local/mailbox.c release-20010228.patched/src/local/mailbox.c --- release-20010228/src/local/mailbox.c Sun Dec 3 20:34:59 2000 +++ release-20010228.patched/src/local/mailbox.c Mon Aug 13 11:53:46 2001 @@ -72,6 +72,9 @@ #include #include #include +#include +#include +#include #ifndef EDQUOT #define EDQUOT EFBIG @@ -85,6 +88,40 @@ #define YES 1 #define NO 0 +static long lookup_mailbox_size( char *map_names, char *user ) +{ + const char *value; + static MAPS *m=NULL; + + if (!m) + m = maps_create( + "mailbox size lookup", + map_names, + DICT_FLAG_LOCK + ); + value = maps_find(m, user, DICT_FLAG_FIXED); + return(value ? atol(value) : -1); +} + +static long mailbox_size( char *user ) +{ + long size; + + /* lookup per-user mailbox size */ + size = *var_mailbox_size_map ? + lookup_mailbox_size(var_mailbox_size_map, user) : + -1; + + /* no var_mailbox_size_map or per-user case specified. apply default */ + if( size == -1 ) + size = var_default_mailbox_size; + + /* turn into bytes */ + size <<= 10; + + return(size); +} + /* deliver_mailbox_file - deliver to recipient mailbox */ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) @@ -103,6 +140,10 @@ gid_t spool_gid; uid_t chown_uid; gid_t chown_gid; + int rec_type; + VSTRING *buffer; + long msg_size; + long size_limit; /* * Make verbose logging easier to understand. @@ -112,9 +153,30 @@ MSG_LOG_STATE(myname, state); /* - * Initialize. Assume the operation will fail. Set the delivered - * attribute to reflect the final recipient. + * Initialize. Assume the operation will fail. Read size of message from + * queue file. Set the delivered attribute to reflect the final recipient. */ + buffer = vstring_alloc(10); + rec_type = 0; + msg_size = 0; + size_limit = mailbox_size(state.msg_attr.user); + if (size_limit) + if (msg_verbose) + msg_info("%s: mailbox size limit for %s is %ld bytes.", + myname, state.msg_attr.user, size_limit); + if (vstream_fseek(state.msg_attr.fp, (off_t) 0, SEEK_SET) < 0) + msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); + for (;;) { + rec_type = rec_get(state.msg_attr.fp, buffer, 0); + if (rec_type == REC_TYPE_ERROR) + msg_fatal("record read error"); + if (rec_type == REC_TYPE_EOF) + break; + if (rec_type == REC_TYPE_SIZE) { + msg_size = atol(vstring_str(buffer)); + break; + } + } if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); state.msg_attr.delivered = state.msg_attr.recipient; @@ -188,9 +250,16 @@ vstring_sprintf(why, "destination is not a regular file"); errno = 0; } else { - end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END); - status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, - copy_flags, "\n", why); + /* Check if accepting message would put user over max inbox size */ + if (size_limit && msg_size + st.st_size > size_limit) { + vstream_fclose(mp->fp); + vstring_sprintf(why, "Destination is over size limit"); + errno = EFBIG; + } else { + end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END); + status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, + copy_flags, "\n", why); + } } if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid) set_eugid(spool_uid, spool_gid); @@ -202,11 +271,20 @@ * As the mail system, bounce, defer delivery, or report success. */ if (status != 0) { - status = (errno == EAGAIN || errno == ENOSPC ? - defer_append : bounce_append) - (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), - "cannot access mailbox %s for user %s. %s", - mailbox, state.msg_attr.user, vstring_str(why)); + if (errno == EAGAIN || errno == ENOSPC) + status = defer_append(BOUNCE_FLAG_KEEP, + BOUNCE_ATTR(state.msg_attr), + "cannot access mailbox %s for user %s. %s", + mailbox, state.msg_attr.user, vstring_str(why)); + if (errno == EDQUOT || errno == EFBIG) + status = bounce_append(BOUNCE_FLAG_KEEP, + BOUNCE_ATTR(state.msg_attr), + "Recipient's mailbox is full."); + else + status = defer_append(BOUNCE_FLAG_KEEP, + BOUNCE_ATTR(state.msg_attr), + "cannot append to file %s: %s", + mailbox, vstring_str(why)); } else { sent(SENT_ATTR(state.msg_attr), "mailbox"); if (var_biff) {