diff options
author | aaron <aaron@7b491191-dbf0-0310-aff6-d879d4d69008> | 2006-08-14 17:46:47 +0000 |
---|---|---|
committer | aaron <aaron@7b491191-dbf0-0310-aff6-d879d4d69008> | 2006-08-14 17:46:47 +0000 |
commit | 5065b5c0d78990db6e30fdaac750ee1ec498edf6 (patch) | |
tree | ec4f1564648487f3fd7c6724dfe7f248a90b6306 | |
parent | b7cc57dade6c9cc541739add39ec532214ef8f42 (diff) |
* dbmailtypes.h, db.h, db.c:
Added source argument to the db_create_mailbox_with_parents function
to determine if permission checks should be skipped or not.
* main.c, man/dbmail-smtp.txt:
Added -M flag, like -m, but skip all permission checks and Sieve
scripts (closes bug #391 and bug #393).
* imapcommands.c, sort.c:
Updated calls to the lower level mailbox creation and delivery
functions with the additional source arguments.
* debug.h, debug.c:
Added argument to the newtrace function to know if it was called from
the trace or TRACE macro.
git-svn-id: https://svn.ic-s.nl/svn/dbmail/trunk/dbmail@2224 7b491191-dbf0-0310-aff6-d879d4d69008
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | db.c | 31 | ||||
-rw-r--r-- | db.h | 5 | ||||
-rw-r--r-- | dbmailtypes.h | 1 | ||||
-rw-r--r-- | debug.c | 30 | ||||
-rw-r--r-- | debug.h | 8 | ||||
-rw-r--r-- | imapcommands.c | 2 | ||||
-rw-r--r-- | main.c | 27 | ||||
-rw-r--r-- | man/dbmail-smtp.txt | 11 | ||||
-rw-r--r-- | sort.c | 95 |
10 files changed, 145 insertions, 80 deletions
@@ -1,3 +1,18 @@ +2006-08-14 Aaron Stone <aaron@serendipity.cx> + + * dbmailtypes.h, db.h, db.c: + Added source argument to the db_create_mailbox_with_parents function + to determine if permission checks should be skipped or not. + * main.c, man/dbmail-smtp.txt: + Added -M flag, like -m, but skip all permission checks and Sieve + scripts (closes bug #391 and bug #393). + * imapcommands.c, sort.c: + Updated calls to the lower level mailbox creation and delivery + functions with the additional source arguments. + * debug.h, debug.c: + Added argument to the newtrace function to know if it was called from + the trace or TRACE macro. + 2006-08-13 Aaron Stone <aaron@serendipity.cx> * export.c: @@ -2919,8 +2919,8 @@ egeneral: * DM_EGENERAL Cannot create mailbox * DM_EQUERY Database error */ -int db_mailbox_create_with_parents(const char * mailbox, u64_t owner_idnr, - u64_t * mailbox_idnr, const char * * message) +int db_mailbox_create_with_parents(const char * mailbox, mailbox_source_t source, + u64_t owner_idnr, u64_t * mailbox_idnr, const char * * message) { int parent_right_to_create = -1; int other_namespace = 0; @@ -2932,37 +2932,31 @@ int db_mailbox_create_with_parents(const char * mailbox, u64_t owner_idnr, assert(mailbox); assert(mailbox_idnr); assert(message); + + TRACE(TRACE_INFO, "Creating mailbox [%s] source [%d] for user [%llu]", + mailbox, source, owner_idnr); /* check if new name is valid */ if (!checkmailboxname(mailbox)) { *message = "New mailbox name contains invalid characters"; + TRACE(TRACE_MESSAGE, "New mailbox name contains invalid characters. Aborting create."); return DM_EGENERAL; } /* There used to be a removal of slashes here. Why? */ if (db_findmailbox(mailbox, owner_idnr, mailbox_idnr) == 1) { *message = "Mailbox already exists"; + TRACE(TRACE_ERROR, "Asked to create mailbox which already exists. Aborting create."); return DM_EGENERAL; } if (db_imap_split_mailbox(mailbox, owner_idnr, &mailboxes, message) != DM_SUCCESS) { - // Message was set by the function. + TRACE(TRACE_ERROR, "Negative return code from db_imap_split_mailbox."); + // Message pointer was set by the function. return DM_EGENERAL; } - /* FIXME: Change these to TRACE calls. - printf("\n"); - GList *mailboxes_temp; - mailboxes_temp = g_list_first(mailboxes); - while (mailboxes_temp) { - mailbox_t *mbox = (mailbox_t *)mailboxes_temp->data; - printf("%s\n", mbox->name); - mailboxes_temp = g_list_next(mailboxes_temp); - } - printf("\n"); - */ - mailboxes = g_list_first(mailboxes); while (mailboxes) { mailbox_t *mbox = (mailbox_t *)mailboxes->data; @@ -3006,6 +3000,10 @@ int db_mailbox_create_with_parents(const char * mailbox, u64_t owner_idnr, skip_and_free = DM_EGENERAL; } + } else if (source == BOX_BRUTEFORCE) { + TRACE(TRACE_INFO, "Mailbox requested with BRUTEFORCE creation status; " + "pretending that all permissions have been granted to create it."); + parent_right_to_create = 1; } else { /* Mailbox does exist, failure if no_inferiors flag set. */ if ( ((result = db_noinferiors(mbox->uid)) == DM_EGENERAL) ) { @@ -3138,10 +3136,11 @@ int db_find_create_mailbox(const char *name, mailbox_source_t source, if (db_findmailbox(name, owner_idnr, &mboxidnr) != 1) { /* Who specified this mailbox? */ if (source == BOX_COMMANDLINE + || source == BOX_BRUTEFORCE || source == BOX_SORTING || source == BOX_DEFAULT) { /* Did we fail to create the mailbox? */ - if (db_mailbox_create_with_parents(name, owner_idnr, &mboxidnr, &message) != DM_SUCCESS) { + if (db_mailbox_create_with_parents(name, source, owner_idnr, &mboxidnr, &message) != DM_SUCCESS) { TRACE(TRACE_ERROR, "could not create mailbox [%s] because [%s]", name, message); return DM_EQUERY; @@ -982,6 +982,7 @@ int db_createmailbox(const char *name, u64_t owner_idnr, /** * \brief Create a mailbox, recursively creating its parents. * \param mailbox Name of the mailbox to create + * \param source Upstream source of this mailbox spec * \param owner_idnr Owner of the mailbox * \param mailbox_idnr Fills the pointer with the mailbox id * \param message Fills the pointer with a static pointer to a message @@ -990,8 +991,8 @@ int db_createmailbox(const char *name, u64_t owner_idnr, * - 1 on failure * - -1 on error */ -int db_mailbox_create_with_parents(const char * mailbox, u64_t owner_idnr, - u64_t * mailbox_idnr, const char * * message); +int db_mailbox_create_with_parents(const char * mailbox, mailbox_source_t source, + u64_t owner_idnr, u64_t * mailbox_idnr, const char * * message); /** * \brief Splits a mailbox name into pieces on '/' diff --git a/dbmailtypes.h b/dbmailtypes.h index 3dd7a48d..10377c0a 100644 --- a/dbmailtypes.h +++ b/dbmailtypes.h @@ -428,6 +428,7 @@ typedef enum { BOX_NONE, /* No mailbox yet. */ BOX_UNKNOWN, /* Not gonna create. */ BOX_ADDRESSPART, /* Not gonna create. */ + BOX_BRUTEFORCE, /* Autocreate, no perms checks and skip Sieve scripts. */ BOX_COMMANDLINE, /* Autocreate. */ BOX_SORTING, /* Autocreate. */ BOX_DEFAULT /* Autocreate. */ @@ -71,7 +71,7 @@ static const char * trace_to_text(trace_t level) * */ -void newtrace(trace_t level, const char * module, +void newtrace(int isnew, trace_t level, const char * module, const char * file, const char * function, char *formatstring, ...) { @@ -82,8 +82,8 @@ void newtrace(trace_t level, const char * module, va_start(argp, formatstring); - /* TODO: make use of the module, file, function arguments. - if (TRACE_SYSLOG >= 5) { + /* + if (isnew && TRACE_SYSLOG >= 5) { // If the global trace level is really high formatstring_verbose = g_strdup_printf("from %s, %s, %s: %s", module, file, function, formatstring); @@ -100,7 +100,12 @@ void newtrace(trace_t level, const char * module, l = strlen(message); if (level <= TRACE_STDERR) { - fprintf(stderr, "%s %s", trace_to_text(level), message); + if (isnew) { + // FIXME: Add file, function, etc. + fprintf(stderr, "%s %s", trace_to_text(level), message); + } else { + fprintf(stderr, "%s %s", trace_to_text(level), message); + } if (message[l] != '\n') fprintf(stderr, "\n"); fflush(stderr); @@ -111,9 +116,20 @@ void newtrace(trace_t level, const char * module, message[l] = '\0'; if (level <= TRACE_WARNING) { /* set LOG_ALERT at warnings */ - syslog(LOG_ALERT, "%s %s", trace_to_text(level), message); - } else - syslog(LOG_NOTICE, "%s %s", trace_to_text(level), message); + if (isnew) { + // FIXME: Add file, function, etc. + syslog(LOG_ALERT, "%s %s", trace_to_text(level), message); + } else { + syslog(LOG_ALERT, "%s %s", trace_to_text(level), message); + } + } else { + if (isnew) { + // FIXME: Add file, function, etc. + syslog(LOG_NOTICE, "%s %s", trace_to_text(level), message); + } else { + syslog(LOG_NOTICE, "%s %s", trace_to_text(level), message); + } + } } g_free(message); @@ -77,11 +77,11 @@ typedef enum { void func_memtst(const char *filename, int line, int tst); -#define trace(level, fmt...) newtrace(level, "", "", "", fmt) -#define TRACE(level, fmt...) newtrace(level, THIS_MODULE, __FILE__, __func__, fmt) -void newtrace(trace_t level, const char * module, +#define trace(level, fmt...) newtrace(0, level, "", "", "", fmt) +#define TRACE(level, fmt...) newtrace(1, level, THIS_MODULE, __FILE__, __func__, fmt) +void newtrace(int isnew, trace_t level, const char * module, const char * file, const char * function, - char *formatstring, ...) PRINTF_ARGS(5, 6); + char *formatstring, ...) PRINTF_ARGS(6, 7); void configure_debug(trace_t trace_syslog, trace_t trace_stderr); diff --git a/imapcommands.c b/imapcommands.c index 96e6a293..c33b09f6 100644 --- a/imapcommands.c +++ b/imapcommands.c @@ -331,7 +331,7 @@ int _ic_create(struct ImapSession *self) return 1; /* Create the mailbox and its parents. */ - result = db_mailbox_create_with_parents(self->args[0], ud->userid, &mboxid, &message); + result = db_mailbox_create_with_parents(self->args[0], BOX_COMMANDLINE, ud->userid, &mboxid, &message); if (result > 0) { dbmail_imap_session_printf(self, "%s NO %s\r\n", self->tag, message); @@ -23,6 +23,7 @@ * main file for dbmail-smtp */ #include "dbmail.h" +#define THIS_MODULE "smtp" #define MESSAGEIDSIZE 100 #define NORMAL_DELIVERY 1 @@ -47,6 +48,7 @@ extern db_param_t _db_params; /* set up database login data */ deliver_to_user_t dsnuser; //char *header = NULL; +int brute_force = 0; char *deliver_to_header = NULL; char *deliver_to_mailbox = NULL; @@ -61,7 +63,8 @@ int do_showhelp(void) { printf(" -t [headerfield] for normal deliveries (default is \"delivered-to\")\n"); printf(" -d [addresses] for delivery without using scanner\n"); printf(" -u [usernames] for direct delivery to users\n"); - printf(" -m \"mailbox\" for delivery to a specific mailbox\n"); + printf(" -m \"mailbox\" for delivery to a specific mailbox\n"); + printf(" -M \"mailbox\" as -m, but skip permissions checks and Sieve scripts\n"); printf(" -r return path for address of bounces and other error reports\n"); printf("\nCommon options for all DBMail utilities:\n"); @@ -97,7 +100,7 @@ int main(int argc, char *argv[]) * with an immediately preceding option are return with option * value '1'. We will use this to allow for multiple values to * follow after each of the supported options. */ - while ((c = getopt(argc, argv, "-t::m:u:d:r: f:qnyvVh")) != EOF) { + while ((c = getopt(argc, argv, "-t::m:M:u:d:r: f:qnyvVh")) != EOF) { /* Received an n-th value following the last option, * so recall the last known option to be used in the switch. */ if (c == 1) @@ -121,6 +124,15 @@ int main(int argc, char *argv[]) break; + case 'M': + TRACE(TRACE_INFO, "using BRUTE FORCE delivery"); + + if (brute_force) { + printf("Only one mailbox name may be specified.\n"); + usage_error = 1; + } else + brute_force = 1; + /* Fall through. */ case 'm': trace(TRACE_INFO, "%s,%s: using SPECIAL_DELIVERY to mailbox", __FILE__, __func__); @@ -310,7 +322,11 @@ int main(int argc, char *argv[]) /* Loop through the dsnusers list, setting the destination mailbox. */ for (tmp = dm_list_getstart(&dsnusers); tmp != NULL; tmp = tmp->nextnode) { ((deliver_to_user_t *)tmp->data)->mailbox = dm_strdup(deliver_to_mailbox); - ((deliver_to_user_t *)tmp->data)->source = BOX_COMMANDLINE; + if (brute_force) { + ((deliver_to_user_t *)tmp->data)->source = BOX_BRUTEFORCE; + } else { + ((deliver_to_user_t *)tmp->data)->source = BOX_COMMANDLINE; + } } } @@ -365,7 +381,7 @@ int main(int argc, char *argv[]) g_list_foreach(userlist, (GFunc)g_free, NULL); g_list_free(userlist); - trace(TRACE_DEBUG, "%s,%s: they're all free. we're done.", __FILE__, __func__); + TRACE(TRACE_DEBUG, "they're all free. we're done."); db_disconnect(); auth_disconnect(); @@ -373,6 +389,7 @@ int main(int argc, char *argv[]) g_mime_shutdown(); - trace(TRACE_DEBUG, "%s,%s: exit code is [%d].", __FILE__, __func__, exitcode); + TRACE(TRACE_DEBUG, "exit code is [%d].", exitcode); return exitcode; } + diff --git a/man/dbmail-smtp.txt b/man/dbmail-smtp.txt index 5cbe4cca..165b431d 100644 --- a/man/dbmail-smtp.txt +++ b/man/dbmail-smtp.txt @@ -8,7 +8,7 @@ dbmail-smtp - inserts messages into the DBMail mailsystem. SYNOPSIS -------- -dbmail-smtp [-t headerfield] [-d addresses] [-u usernames] [-m mailboxname] +dbmail-smtp [-t headerfield] [-d addresses] [-u usernames] [-m|-M mailboxname] [-r return path] [-f configFile] DESCRIPTION @@ -35,7 +35,14 @@ OPTIONS -m mailboxname:: Deliver messages to mailbox mailboxname of the recipient. If - this mailbox does not exist yet, it is created. + this mailbox does not exist yet, it is created. Sieve scripts + will be run normally, possibly altering the destination mailbox. + +-M mailboxname:: + Deliver messages to mailbox mailboxname of the recipient. If + this mailbox does not exist yet, it is created. Sieve scripts + are not run. Permission checks are not performed for mailbox creation + or message delivery. -r returnpath:: Set return path for bounces and other error reports to return path. @@ -24,7 +24,16 @@ dsn_class_t sort_and_deliver(struct DbmailMessage *message, dsn_class_t ret; field_t val; - TRACE(TRACE_INFO, "destination [%s] useridnr [%llu], mailbox [%s], source [%d]", + /* Catch the brute force delivery right away. + * We skip the Sieve scripts, and down the call + * chain we don't check permissions on the mailbox. */ + if (source == BOX_BRUTEFORCE) { + TRACE(TRACE_MESSAGE, "Beginning brute force delivery for user [%llu] to mailbox [%s].", + useridnr, mailbox); + return sort_deliver_to_mailbox(message, useridnr, mailbox, source, NULL); + } + + TRACE(TRACE_INFO, "Destination [%s] useridnr [%llu], mailbox [%s], source [%d]", destination, useridnr, mailbox, source); /* This is the only condition when called from pipe.c, actually. */ @@ -45,8 +54,7 @@ dsn_class_t sort_and_deliver(struct DbmailMessage *message, // FIXME: I forget who frees the mailbox. mailbox = subaddress; source = BOX_ADDRESSPART; - trace(TRACE_INFO, "%s, %s: Setting BOX_ADDRESSPART mailbox to [%s]", - __FILE__, __func__, mailbox); + TRACE(TRACE_INFO, "Setting BOX_ADDRESSPART mailbox to [%s]", mailbox); } } @@ -57,8 +65,7 @@ dsn_class_t sort_and_deliver(struct DbmailMessage *message, config_get_value("SIEVE", "DELIVERY", val); if (strcasecmp(val, "yes") == 0 && db_check_sievescript_active(useridnr) == 0) { - trace(TRACE_INFO, "%s, %s: Calling for a Sieve sort", - __FILE__, __func__); + TRACE(TRACE_INFO, "Calling for a Sieve sort"); sort_result_t *sort_result; sort_result = sort_process(useridnr, message); if (sort_result) { @@ -83,20 +90,17 @@ dsn_class_t sort_and_deliver(struct DbmailMessage *message, // This may necessarily imply that the message // is being discarded -- dropped flat on the floor. ret = DSN_CLASS_OK; - trace(TRACE_INFO, "%s, %s: Keep was cancelled. Message may be discarded.", - __FILE__, __func__); + TRACE(TRACE_INFO, "Keep was cancelled. Message may be discarded."); } else { ret = sort_deliver_to_mailbox(message, useridnr, mailbox, source, NULL); - trace(TRACE_INFO, "%s, %s: Keep was not cancelled. Message will be delivered by default.", - __FILE__, __func__); + TRACE(TRACE_INFO, "Keep was not cancelled. Message will be delivered by default."); } /* Reject probably implies cancelkeep, * but we'll not assume that and instead * just test this as a separate block. */ if (reject) { - trace(TRACE_INFO, "%s, %s: Message will be rejected.", - __FILE__, __func__); + TRACE(TRACE_INFO, "Message will be rejected."); ret = DSN_CLASS_FAIL; } @@ -116,40 +120,45 @@ dsn_class_t sort_deliver_to_mailbox(struct DbmailMessage *message, TRACE(TRACE_ERROR, "mailbox [%s] not found", mailbox); return DSN_CLASS_FAIL; } - // Check ACL's on the mailbox. It must be read-write, - // it must not be no_select, and it may require an ACL for - // the user whose Sieve script this is, since it's possible that - // we've looked up a #Public or a #Users mailbox. - TRACE(TRACE_DEBUG, "Checking if we have the right to post incoming messages"); - - mailbox_t mbox; - memset(&mbox, '\0', sizeof(mbox)); - mbox.uid = mboxidnr; - - switch (acl_has_right(&mbox, useridnr, ACL_RIGHT_POST)) { - case -1: - TRACE(TRACE_MESSAGE, "error retrieving right for [%llu] to deliver mail to [%s]", - useridnr, mailbox); - return DSN_CLASS_TEMP; - case 0: - // No right. - TRACE(TRACE_MESSAGE, "user [%llu] does not have right to deliver mail to [%s]", - useridnr, mailbox); - // Switch to INBOX. - if (strcmp(mailbox, "INBOX") == 0) { - // Except if we've already been down this path. - TRACE(TRACE_MESSAGE, "already tried to deliver to INBOX"); + + if (source == BOX_BRUTEFORCE) { + TRACE(TRACE_INFO, "Brute force delivery; skipping ACL checks on mailbox."); + } else { + // Check ACL's on the mailbox. It must be read-write, + // it must not be no_select, and it may require an ACL for + // the user whose Sieve script this is, since it's possible that + // we've looked up a #Public or a #Users mailbox. + TRACE(TRACE_DEBUG, "Checking if we have the right to post incoming messages"); + + mailbox_t mbox; + memset(&mbox, '\0', sizeof(mbox)); + mbox.uid = mboxidnr; + + switch (acl_has_right(&mbox, useridnr, ACL_RIGHT_POST)) { + case -1: + TRACE(TRACE_MESSAGE, "error retrieving right for [%llu] to deliver mail to [%s]", + useridnr, mailbox); + return DSN_CLASS_TEMP; + case 0: + // No right. + TRACE(TRACE_MESSAGE, "user [%llu] does not have right to deliver mail to [%s]", + useridnr, mailbox); + // Switch to INBOX. + if (strcmp(mailbox, "INBOX") == 0) { + // Except if we've already been down this path. + TRACE(TRACE_MESSAGE, "already tried to deliver to INBOX"); + return DSN_CLASS_FAIL; + } + return sort_deliver_to_mailbox(message, useridnr, "INBOX", BOX_DEFAULT, msgflags); + case 1: + // Has right. + TRACE(TRACE_INFO, "user [%llu] has right to deliver mail to [%s]", + useridnr, mailbox); + break; + default: + TRACE(TRACE_ERROR, "invalid return value from acl_has_right"); return DSN_CLASS_FAIL; } - return sort_deliver_to_mailbox(message, useridnr, "INBOX", BOX_DEFAULT, msgflags); - case 1: - // Has right. - TRACE(TRACE_INFO, "user [%llu] has right to deliver mail to [%s]", - useridnr, mailbox); - break; - default: - TRACE(TRACE_ERROR, "invalid return value from acl_has_right"); - return DSN_CLASS_FAIL; } // Ok, we have the ACL right, time to deliver the message. |