SRCS = virtual.c mailbox.c recipient.c deliver_attr.c maildir.c unknown.c
OBJS = virtual.o mailbox.o recipient.o deliver_attr.o maildir.o unknown.o
HDRS = virtual.h
-TESTSRC =
+TESTSRC = mailbox_test.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
PROG = virtual
-TESTPROG=
+TESTPROG= mailbox_test
+TESTLIB= ../../lib/libptest.a
INC_DIR = ../../include
LIBS = ../../lib/lib$(LIB_PREFIX)master$(LIB_SUFFIX) \
../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
test: $(TESTPROG)
-tests:
+tests: test_mailbox
root_tests:
tidy: clean
+MAILBOX_TEST_OBJ = mailbox.o $(TESTLIB)
+
+mailbox_test: mailbox_test.o $(MAILBOX_TEST_OBJ) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(MAILBOX_TEST_OBJ) $(LIBS) $(SYSLIBS)
+
+test_mailbox: mailbox_test
+ $(SHLIB_ENV) $(VALGRIND) ./mailbox_test
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
mailbox.o: ../../include/pol_stats.h
mailbox.o: ../../include/recipient_list.h
mailbox.o: ../../include/safe_open.h
+mailbox.o: ../../include/sane_strtol.h
mailbox.o: ../../include/sent.h
mailbox.o: ../../include/set_eugid.h
mailbox.o: ../../include/stringops.h
mailbox.o: ../../include/vstring.h
mailbox.o: mailbox.c
mailbox.o: virtual.h
+mailbox_test.o: ../../include/argv.h
+mailbox_test.o: ../../include/attr.h
+mailbox_test.o: ../../include/bounce.h
+mailbox_test.o: ../../include/check_arg.h
+mailbox_test.o: ../../include/defer.h
+mailbox_test.o: ../../include/deliver_request.h
+mailbox_test.o: ../../include/dict.h
+mailbox_test.o: ../../include/dsn.h
+mailbox_test.o: ../../include/dsn_buf.h
+mailbox_test.o: ../../include/htable.h
+mailbox_test.o: ../../include/mail_params.h
+mailbox_test.o: ../../include/maps.h
+mailbox_test.o: ../../include/mbox_conf.h
+mailbox_test.o: ../../include/msg.h
+mailbox_test.o: ../../include/msg_jmp.h
+mailbox_test.o: ../../include/msg_output.h
+mailbox_test.o: ../../include/msg_stats.h
+mailbox_test.o: ../../include/msg_vstream.h
+mailbox_test.o: ../../include/myflock.h
+mailbox_test.o: ../../include/mymalloc.h
+mailbox_test.o: ../../include/myrand.h
+mailbox_test.o: ../../include/nvtable.h
+mailbox_test.o: ../../include/pmock_expect.h
+mailbox_test.o: ../../include/pol_stats.h
+mailbox_test.o: ../../include/ptest.h
+mailbox_test.o: ../../include/ptest_main.h
+mailbox_test.o: ../../include/recipient_list.h
+mailbox_test.o: ../../include/stringops.h
+mailbox_test.o: ../../include/sys_defs.h
+mailbox_test.o: ../../include/vbuf.h
+mailbox_test.o: ../../include/vstream.h
+mailbox_test.o: ../../include/vstring.h
+mailbox_test.o: mailbox_test.c
+mailbox_test.o: virtual.h
maildir.o: ../../include/argv.h
maildir.o: ../../include/attr.h
maildir.o: ../../include/bounce.h
--- /dev/null
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Global library.
+ */
+#include <bounce.h>
+#include <defer.h>
+#include <deliver_request.h>
+#include <mail_params.h>
+#include <maps.h>
+
+ /*
+ * Application-specific.
+ */
+#include <virtual.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * Test case and data.
+ */
+typedef struct PTEST_CASE {
+ char *testname;
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *);
+ char *user;
+ int minimum_uid;
+ char *mailbox_maps;
+ char *uid_maps;
+ char *gid_maps;
+ char *mailbox_base;
+ char *mailbox_lock;
+ char **want_log;
+ int want_status;
+ int want_known;
+} PTEST_CASE;
+
+#define STATUS_FINAL 0
+#define STATUS_DEFER 1
+#define STATUS_UNSET -1
+
+#define USER_UNKNOWN 0
+#define USER_KNOWN 1
+ /*
+ * Surriogate parameter dependencies.
+ */
+int var_virt_minimum_uid;
+char *var_virt_mailbox_maps;
+char *var_virt_uid_maps;
+char *var_virt_gid_maps;
+char *var_virt_mailbox_base;
+char *var_virt_mailbox_lock;
+bool var_strict_mbox_owner;
+int virtual_mbox_lock_mask;
+char *var_rcpt_delim = "+";
+
+ /*
+ * Data dependencies.
+ */
+MAPS *virtual_mailbox_maps;
+MAPS *virtual_uid_maps;
+MAPS *virtual_gid_maps;
+
+static LOCAL_STATE state;
+static USER_ATTR usr_attr;
+static DELIVER_REQUEST request;
+
+ /*
+ * Surrogate code dependencies.
+ *
+ * deliver_mailbox() will call deliver_mailbox_file() in the same file which
+ * has too many dependencies. Instead we trigger maildir-style delivery and
+ * use a fake deliver_maildir() to verify some of the arguments.
+ *
+ * defer_append() has too many dependencies. Instead we use a fake
+ * defer_append() to verify some of the arguments.
+ */
+int deliver_maildir(LOCAL_STATE state, USER_ATTR user_attr)
+{
+ msg_info("fake deliver_maildir: mailbox='%s', uid=%lu, gid=%lu",
+ user_attr.mailbox, (unsigned long) user_attr.uid,
+ (unsigned long) user_attr.gid);
+ return (0);
+}
+
+int defer_append(int flags, const char *id, MSG_STATS *stats,
+ RECIPIENT *rcpt, const char *relay,
+ const POL_STATS *tstats, DSN *dsn)
+{
+ msg_info("fake defer_append: dsn=%s reason=%s", dsn->status, dsn->reason);
+ return (1);
+}
+
+static void teardown_test(void)
+{
+ if (virtual_mailbox_maps) {
+ maps_free(virtual_mailbox_maps);
+ virtual_mailbox_maps = 0;
+ }
+ if (virtual_uid_maps) {
+ maps_free(virtual_uid_maps);
+ virtual_uid_maps = 0;
+ }
+ if (virtual_gid_maps) {
+ maps_free(virtual_gid_maps);
+ virtual_gid_maps = 0;
+ }
+ if (state.msg_attr.why) {
+ dsb_free(state.msg_attr.why);
+ state.msg_attr.why = 0;
+ }
+}
+
+static void setup_test(const PTEST_CASE *tp)
+{
+ /* In case a previous test failed. */
+ teardown_test();
+
+ /*
+ * Set parameters so that warning messages log as expected.
+ */
+ var_virt_minimum_uid = tp->minimum_uid;
+ var_virt_mailbox_maps = tp->mailbox_maps;
+ var_virt_uid_maps = tp->uid_maps;
+ var_virt_gid_maps = tp->gid_maps;
+ var_virt_mailbox_base = tp->mailbox_base;
+ var_virt_mailbox_lock = tp->mailbox_lock;
+
+ /*
+ * Open databases.
+ */
+ if (var_virt_mailbox_maps)
+ virtual_mailbox_maps =
+ maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
+ DICT_FLAG_LOCK | DICT_FLAG_PARANOID
+ | DICT_FLAG_UTF8_REQUEST);
+ if (var_virt_uid_maps)
+ virtual_uid_maps =
+ maps_create(VAR_VIRT_UID_MAPS, var_virt_uid_maps,
+ DICT_FLAG_LOCK | DICT_FLAG_PARANOID
+ | DICT_FLAG_UTF8_REQUEST);
+ if (var_virt_gid_maps)
+ virtual_gid_maps =
+ maps_create(VAR_VIRT_GID_MAPS, var_virt_gid_maps,
+ DICT_FLAG_LOCK | DICT_FLAG_PARANOID
+ | DICT_FLAG_UTF8_REQUEST);
+
+ /*
+ * Initialize local state, request, and user attributes.
+ */
+ state.msg_attr.why = dsb_create();;
+ state.msg_attr.user = tp->user;
+ state.msg_attr.rcpt.address = tp->user;
+ state.msg_attr.delivered = tp->user;
+ request.flags = 0;
+ state.request = &request;
+}
+
+static void test_deliver_mailbox(PTEST_CTX *t, const struct PTEST_CASE *tp)
+{
+ int got_status = STATUS_UNSET;
+ int got_known;
+ char **cpp;
+
+ if (sizeof(uid_t) > 4) {
+ ptest_info(t, "uid_t is too large -- skipping this test");
+ ptest_skip(t);
+ }
+ if (sizeof(long) <= 4) {
+ ptest_info(t, "long is too small -- skipping this test");
+ ptest_skip(t);
+ }
+ setup_test(tp);
+ if (tp->want_log)
+ for (cpp = (char **) tp->want_log; *cpp; cpp++)
+ expect_ptest_log_event(t, *cpp);
+ got_known = deliver_mailbox(state, usr_attr, &got_status);
+ if (got_known != tp->want_known)
+ ptest_error(t, "user known: got %d, want %d",
+ got_known, tp->want_known);
+ if (got_status != tp->want_status)
+ ptest_error(t, "user status: got %d, want %d",
+ got_status, tp->want_status);
+ teardown_test();
+}
+
+ /*
+ * Test cases.
+ */
+const PTEST_CASE ptestcases[] = {
+ {
+ .testname = "normal case",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .minimum_uid = 1,
+ .mailbox_maps = "static:user-1-1/",
+ .uid_maps = "static:1",
+ .gid_maps = "static:1",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {"mailbox='/base/user-1-1/', uid=1, gid=1", 0,},
+ .want_known = USER_KNOWN,
+ .want_status = USER_UNKNOWN,
+ },{
+ .testname = "relative base",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .mailbox_base = "base",
+ .want_log = (char *[]) {"do not specify relative pathname", 0,},
+ .want_known = USER_UNKNOWN,
+ .want_status = STATUS_UNSET,
+ },{
+ .testname = "user unknown",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .mailbox_maps = "inline:{x=x}",
+ .mailbox_base = "/base",
+ .want_known = USER_UNKNOWN,
+ .want_status = STATUS_UNSET,
+ },{
+ .testname = "trailing .. in path",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .mailbox_maps = "static:here/../",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {
+ "recipient example-user: bad mailbox path here/../",
+ "dsn=4.3.5 reason=mail system configuration error",
+ 0,
+ },
+ .want_known = USER_KNOWN,
+ .want_status = STATUS_DEFER,
+ },{
+ .testname = "leading .. in path",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .mailbox_maps = "static:../here/",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {
+ "recipient example-user: bad mailbox path ../here/",
+ "dsn=4.3.5 reason=mail system configuration error",
+ 0,
+ },
+ .want_known = USER_KNOWN,
+ .want_status = STATUS_DEFER,
+ },{
+ .testname = "missing entry in virtual_gid_maps",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .minimum_uid = 1,
+ .mailbox_maps = "static:user-1-1/",
+ .uid_maps = "static:1",
+ .gid_maps = "inline:{x=x}",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {
+ "recipient example-user: not found in virtual_gid_maps",
+ "dsn=4.3.5 reason=mail system configuration error",
+ 0,
+ },
+ .want_known = USER_KNOWN,
+ .want_status = STATUS_DEFER,
+ },{
+ .testname = "missing entry in virtual_uid_maps",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .minimum_uid = 1,
+ .mailbox_maps = "static:user-1-1/",
+ .uid_maps = "inline:{x=x}",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {
+ "recipient example-user: not found in virtual_uid_maps",
+ "dsn=4.3.5 reason=mail system configuration error",
+ 0,
+ },
+ .want_known = USER_KNOWN,
+ .want_status = STATUS_DEFER,
+ },{
+ .testname = "gid too large",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .minimum_uid = 1,
+ .mailbox_maps = "static:user-1-1/",
+ .uid_maps = "static:1",
+ .gid_maps = "static:9223372036854775807L",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {
+ "bad gid 9223372036854775807L in virtual_gid_maps",
+ "dsn=4.3.5 reason=mail system configuration error",
+ 0,
+ },
+ .want_known = USER_KNOWN,
+ .want_status = STATUS_DEFER,
+ },{
+ .testname = "uid too large",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .minimum_uid = 1,
+ .mailbox_maps = "static:user-1-1/",
+ .uid_maps = "static:9223372036854775807L",
+ .gid_maps = "static:1",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {
+ "bad uid 9223372036854775807L in virtual_uid_maps",
+ "dsn=4.3.5 reason=mail system configuration error",
+ 0,
+ },
+ .want_known = USER_KNOWN,
+ .want_status = STATUS_DEFER,
+ },{
+ .testname = "bad uid conversion",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .minimum_uid = 1,
+ .mailbox_maps = "static:user-1-1/",
+ .uid_maps = "static:9223372X36854775807L",
+ .gid_maps = "static:1",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {
+ "bad uid 9223372X36854775807L in virtual_uid_maps",
+ "dsn=4.3.5 reason=mail system configuration error",
+ 0,
+ },
+ .want_known = USER_KNOWN,
+ .want_status = STATUS_DEFER,
+ },{
+ .testname = "bad gid conversion",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .minimum_uid = 1,
+ .mailbox_maps = "static:user-1-1/",
+ .uid_maps = "static:1",
+ .gid_maps = "static:9223372X36854775807L",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {
+ "bad gid 9223372X36854775807L in virtual_gid_maps",
+ "dsn=4.3.5 reason=mail system configuration error",
+ 0,
+ },
+ .want_known = USER_KNOWN,
+ .want_status = STATUS_DEFER,
+ }, {
+ .testname = "uid too small",
+ .action = test_deliver_mailbox,
+ .user = "example-user",
+ .minimum_uid = 1,
+ .mailbox_maps = "static:user-1-1/",
+ .uid_maps = "static:0",
+ .gid_maps = "static:1",
+ .mailbox_base = "/base",
+ .want_log = (char *[]) {
+ "bad uid 0 in virtual_uid_maps",
+ "dsn=4.3.5 reason=mail system configuration error",
+ 0,
+ },
+ .want_known = USER_KNOWN,
+ .want_status = STATUS_DEFER,
+ },
+ /* TODO(wietse) database error returns. */
+};
+
+#include <ptest_main.h>