├── .cvsignore ├── .gitignore ├── CHANGES ├── MANUAL ├── Makefile.am ├── README ├── TODO ├── array.h ├── attach.c ├── autogen.sh ├── buffer.c ├── cache-op.c ├── child-deliver.c ├── child-fetch.c ├── child.c ├── cleanup.c ├── command.c ├── compat ├── base64.c ├── queue.h ├── strlcat.c ├── strlcpy.c ├── strtonum.c └── tree.h ├── configure.ac ├── connect.c ├── db-tdb.c ├── deliver-add-header.c ├── deliver-add-to-cache.c ├── deliver-drop.c ├── deliver-imap.c ├── deliver-keep.c ├── deliver-lmtp.c ├── deliver-maildir.c ├── deliver-mbox.c ├── deliver-pipe.c ├── deliver-remove-from-cache.c ├── deliver-remove-header.c ├── deliver-rewrite.c ├── deliver-smtp.c ├── deliver-stdout.c ├── deliver-tag.c ├── deliver-write.c ├── deliver.h ├── examples ├── example_imap_folder.conf ├── f-terbeck.conf ├── g-lando.conf ├── n-marriott.conf ├── t-ulmer.conf └── w-maier.conf ├── fdm-sanitize ├── fdm.1 ├── fdm.c ├── fdm.conf.5 ├── fdm.h ├── fetch-imap.c ├── fetch-imappipe.c ├── fetch-maildir.c ├── fetch-mbox.c ├── fetch-nntp.c ├── fetch-pop3.c ├── fetch-pop3pipe.c ├── fetch-stdin.c ├── fetch.h ├── file.c ├── imap-common.c ├── io.c ├── io.h ├── lex.c ├── log.c ├── lookup-passwd.c ├── lookup.c ├── mail-state.c ├── mail-time.c ├── mail.c ├── match-account.c ├── match-age.c ├── match-all.c ├── match-attachment.c ├── match-command.c ├── match-in-cache.c ├── match-matched.c ├── match-regexp.c ├── match-size.c ├── match-string.c ├── match-tagged.c ├── match-unmatched.c ├── match.h ├── netrc.c ├── parent-deliver.c ├── parent-fetch.c ├── parse-fn.c ├── parse.y ├── pcre.c ├── pop3-common.c ├── privsep.c ├── re.c ├── replace.c ├── shm-mmap.c ├── strb.c ├── timer.c └── xmalloc.c /.cvsignore: -------------------------------------------------------------------------------- 1 | fdm 2 | y.tab.c 3 | y.tab.h 4 | test.conf 5 | stress 6 | saved 7 | rfcs 8 | releases 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *~ 3 | *.diff 4 | *.patch 5 | *.core 6 | core 7 | tags 8 | .deps/ 9 | compat/.dirstamp 10 | aclocal.m4 11 | autom4te.cache/ 12 | config.log 13 | config.status 14 | etc/ 15 | fdm 16 | Makefile 17 | Makefile.in 18 | configure 19 | parse.c 20 | parse.h 21 | index.html 22 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # $Id$ 2 | 3 | bin_PROGRAMS = fdm 4 | CLEANFILES = parse.c parse.h 5 | BUILT_SOURCES = parse.c parse.h 6 | 7 | EXTRA_DIST = \ 8 | CHANGES README MANUAL \ 9 | examples compat/*.[ch] fdm-sanitize \ 10 | array.h \ 11 | deliver.h \ 12 | fdm.h \ 13 | fetch.h \ 14 | io.h \ 15 | match.h 16 | dist-hook: 17 | make clean 18 | 19 | CPPFLAGS += \ 20 | -DSYSCONFFILE="\"$(sysconfdir)/fdm.conf\"" \ 21 | -DSYSLOCKFILE="\"$(localstatedir)/run/fdm.lock\"" 22 | CFLAGS += -D_GNU_SOURCE -std=gnu99 -O2 23 | if IS_DEBUG 24 | CFLAGS += -g 25 | CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 26 | CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations 27 | CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare 28 | CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align 29 | CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign 30 | CPPFLAGS += -DDEBUG 31 | endif 32 | YFLAGS += -d 33 | 34 | dist_man1_MANS = fdm.1 35 | dist_man5_MANS = fdm.conf.5 36 | 37 | dist_fdm_SOURCES = \ 38 | attach.c \ 39 | buffer.c \ 40 | cache-op.c \ 41 | child-deliver.c \ 42 | child-fetch.c \ 43 | child.c \ 44 | cleanup.c \ 45 | command.c \ 46 | connect.c \ 47 | db-tdb.c \ 48 | deliver-add-header.c \ 49 | deliver-add-to-cache.c \ 50 | deliver-drop.c \ 51 | deliver-imap.c \ 52 | deliver-keep.c \ 53 | deliver-lmtp.c \ 54 | deliver-maildir.c \ 55 | deliver-mbox.c \ 56 | deliver-pipe.c \ 57 | deliver-remove-from-cache.c \ 58 | deliver-remove-header.c \ 59 | deliver-rewrite.c \ 60 | deliver-smtp.c \ 61 | deliver-stdout.c \ 62 | deliver-tag.c \ 63 | deliver-write.c \ 64 | fdm.c \ 65 | fetch-imap.c \ 66 | fetch-imappipe.c \ 67 | fetch-maildir.c \ 68 | fetch-mbox.c \ 69 | fetch-nntp.c \ 70 | fetch-pop3.c \ 71 | fetch-pop3pipe.c \ 72 | fetch-stdin.c \ 73 | fetch.h \ 74 | file.c \ 75 | imap-common.c \ 76 | io.c \ 77 | io.h \ 78 | log.c \ 79 | lookup-passwd.c \ 80 | lookup.c \ 81 | mail-state.c \ 82 | mail-time.c \ 83 | mail.c \ 84 | match-account.c \ 85 | match-age.c \ 86 | match-all.c \ 87 | match-attachment.c \ 88 | match-command.c \ 89 | match-in-cache.c \ 90 | match-matched.c \ 91 | match-regexp.c \ 92 | match-size.c \ 93 | match-string.c \ 94 | match-tagged.c \ 95 | match-unmatched.c \ 96 | match.h \ 97 | netrc.c \ 98 | parent-deliver.c \ 99 | parent-fetch.c \ 100 | parse-fn.c \ 101 | pcre.c \ 102 | pop3-common.c \ 103 | privsep.c \ 104 | re.c \ 105 | replace.c \ 106 | shm-mmap.c \ 107 | strb.c \ 108 | timer.c \ 109 | xmalloc.c \ 110 | \ 111 | parse.y \ 112 | lex.c 113 | 114 | nodist_fdm_SOURCES = 115 | if NO_B64_NTOP 116 | nodist_fdm_SOURCES += compat/base64.c 117 | endif 118 | if NO_STRLCAT 119 | nodist_fdm_SOURCES += compat/strlcat.c 120 | endif 121 | if NO_STRLCPY 122 | nodist_fdm_SOURCES += compat/strlcpy.c 123 | endif 124 | if NO_STRTONUM 125 | nodist_fdm_SOURCES += compat/strtonum.c 126 | endif 127 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | fdm is a program designed to fetch mail from POP3 or IMAP servers, or receive 2 | local mail from stdin, and deliver it in various ways. 3 | 4 | As of fdm 0.9, the caching has been changed, so Berkeley DB is no longer 5 | required. 6 | 7 | As of fdm 1.4, TDB is a required dependency. 8 | 9 | See the included MANUAL file and the fdm(1) and fdm.conf(5) man pages for 10 | installation and usage instructions. Some example configurations are included 11 | in the examples directory. 12 | 13 | Feedback, bug reports, suggestions, etc, are welcome. 14 | 15 | Nicholas Marriott 16 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - SMTP AUTH, SSL and/or TLS 2 | - auth on http proxying 3 | - http (hotmail) fetching 4 | - redo chrooting properly (resolver needs to be in parent) 5 | - match attachment expressions: 6 | match attachment (index > 1 and size < 200 and type "fnmatch") 7 | - attach get name from content-disposition 8 | - more attachment stuff: remove-attachment, write-/pipe-attachment etc 9 | - refactor & clean up privsep mail transfer code 10 | - is there any reason struct mail shouldn't point to a struct account? 11 | - cumulative effect of a compound action sucks 12 | - better website 13 | - fetch from compressed mbox: have to change fetch-mbox to not use mmap 14 | - all timeouts should be in seconds or milliseconds, decide which and make it so 15 | - use TOP to grab only header and return to get body only if actually necessary 16 | - automatically delete old mail on server once it reaches a certain age... 17 | does this break the barrier of what fdm is designed for? 18 | - does imap need a to-fetch list a la pop3? having mails marked read that have 19 | not been successfully delivered is still a problem though. how can this be 20 | fixed? 21 | - string match as regexp, attachment as fnmatch sucks 22 | - common comparison code? num/str 23 | - pop3 over pipe lack of .netrc sucks 24 | - generic flags on account so that no-verify/no-apop don't have to be in the 25 | right order also fix man page 26 | - NNTP should warn if mail is dropped - generic flag 27 | - make-style filtering for tags :S/// etc 28 | - docs from Thomas@BIC: 29 | clarify that first match stops without continue 30 | shell commands: when evaluated (done?) 31 | clarify keep for NNTP (done?) 32 | clarify action tag use/updating, and wrt lambda actions 33 | man page: "The name of the last action executed for this mail." 34 | (last or current?) 35 | attach size units (same as maximum-size) 36 | case sensitivity 37 | mention short-circuit evaluation 38 | check pipe command user 39 | - when doing .netrc lookup, match the username if given as well to allow 40 | multiple users on the same server 41 | - set secondary groups when changing user 42 | - regress fails as root 43 | - rml could be stored as actual tags, then command0-9 could go... means 44 | copying... get rid of %0 45 | - add FAQ entry about no-apop since there are several servers out there 46 | which claim to support it but do not 47 | - option to relax group ownership checks to permit secondary groups, 48 | for shared mailboxes 49 | - examples should have more explanation 50 | - some sort of against-file or matches-file command to match against 51 | a whitelist. bloat vs grep? 52 | - privsep/child error handling is crappy. audit. how to do this better? 53 | - NNTP over ssh/pipe 54 | 55 | -------------------------------------------------------------------------------- /array.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef ARRAY_H 20 | #define ARRAY_H 21 | 22 | #define ARRAY_INITIALIZER { NULL, 0, 0 } 23 | 24 | #define ARRAY_DECL(n, c) \ 25 | struct n { \ 26 | c *list; \ 27 | u_int num; \ 28 | size_t space; \ 29 | } 30 | 31 | #define ARRAY_ITEM(a, i) ((a)->list[i]) 32 | #define ARRAY_ITEMSIZE(a) (sizeof *(a)->list) 33 | #define ARRAY_INITIALSPACE(a) (10 * ARRAY_ITEMSIZE(a)) 34 | 35 | #define ARRAY_ENSURE(a, n) do { \ 36 | if (UINT_MAX - (n) < (a)->num) \ 37 | fatalx("number too big"); \ 38 | if (SIZE_MAX / ((a)->num + (n)) < ARRAY_ITEMSIZE(a)) \ 39 | fatalx("size too big"); \ 40 | if ((a)->space == 0) { \ 41 | (a)->space = ARRAY_INITIALSPACE(a); \ 42 | (a)->list = xrealloc((a)->list, 1, (a)->space); \ 43 | } \ 44 | while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) { \ 45 | (a)->list = xrealloc((a)->list, 2, (a)->space); \ 46 | (a)->space *= 2; \ 47 | } \ 48 | } while (0) 49 | 50 | #define ARRAY_EMPTY(a) (((void *) (a)) == NULL || (a)->num == 0) 51 | #define ARRAY_LENGTH(a) ((a)->num) 52 | #define ARRAY_DATA(a) ((a)->list) 53 | 54 | #define ARRAY_FIRST(a) ARRAY_ITEM(a, 0) 55 | #define ARRAY_LAST(a) ARRAY_ITEM(a, (a)->num - 1) 56 | 57 | #define ARRAY_INIT(a) do { \ 58 | (a)->num = 0; \ 59 | (a)->list = NULL; \ 60 | (a)->space = 0; \ 61 | } while (0) 62 | #define ARRAY_CLEAR(a) do { \ 63 | (a)->num = 0; \ 64 | } while (0) 65 | 66 | #define ARRAY_SET(a, i, s) do { \ 67 | (a)->list[i] = s; \ 68 | } while (0) 69 | 70 | #define ARRAY_ADD(a, s) do { \ 71 | ARRAY_ENSURE(a, 1); \ 72 | (a)->list[(a)->num] = s; \ 73 | (a)->num++; \ 74 | } while (0) 75 | #define ARRAY_INSERT(a, i, s) do { \ 76 | ARRAY_ENSURE(a, 1); \ 77 | if ((i) < (a)->num) { \ 78 | memmove((a)->list + (i) + 1, (a)->list + (i), \ 79 | ARRAY_ITEMSIZE(a) * ((a)->num - (i))); \ 80 | } \ 81 | (a)->list[i] = s; \ 82 | (a)->num++; \ 83 | } while (0) 84 | #define ARRAY_REMOVE(a, i) do { \ 85 | if ((i) < (a)->num - 1) { \ 86 | memmove((a)->list + (i), (a)->list + (i) + 1, \ 87 | ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1)); \ 88 | } \ 89 | (a)->num--; \ 90 | if ((a)->num == 0) \ 91 | ARRAY_FREE(a); \ 92 | } while (0) 93 | 94 | #define ARRAY_EXPAND(a, n) do { \ 95 | ARRAY_ENSURE(a, n); \ 96 | (a)->num += n; \ 97 | } while (0) 98 | #define ARRAY_TRUNC(a, n) do { \ 99 | if ((a)->num > n) \ 100 | (a)->num -= n; \ 101 | else \ 102 | ARRAY_FREE(a); \ 103 | } while (0) 104 | 105 | #define ARRAY_CONCAT(a, b) do { \ 106 | ARRAY_ENSURE(a, (b)->num); \ 107 | memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)); \ 108 | (a)->num += (b)->num; \ 109 | } while (0) 110 | 111 | #define ARRAY_FREE(a) do { \ 112 | if ((a)->list != NULL) \ 113 | xfree((a)->list); \ 114 | ARRAY_INIT(a); \ 115 | } while (0) 116 | #define ARRAY_FREEALL(a) do { \ 117 | ARRAY_FREE(a); \ 118 | xfree(a); \ 119 | } while (0) 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # $Id$ 3 | 4 | if [ "x$(uname)" = "xOpenBSD" ]; then 5 | [ -z "$AUTOMAKE_VERSION" ] && export AUTOMAKE_VERSION=1.15 6 | [ -z "$AUTOCONF_VERSION" ] && export AUTOCONF_VERSION=2.69 7 | fi 8 | 9 | die() 10 | { 11 | echo "$@" >&2 12 | exit 1 13 | } 14 | 15 | mkdir -p etc 16 | aclocal || die "aclocal failed" 17 | automake --add-missing --force-missing --copy --foreign || die "automake failed" 18 | autoreconf || die "autoreconf failed" 19 | -------------------------------------------------------------------------------- /buffer.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | 25 | /* Create a buffer. */ 26 | struct buffer * 27 | buffer_create(size_t size) 28 | { 29 | struct buffer *b; 30 | 31 | if (size == 0) 32 | fatalx("zero size"); 33 | 34 | b = xcalloc(1, sizeof *b); 35 | 36 | b->base = xmalloc(size); 37 | b->space = size; 38 | 39 | return (b); 40 | } 41 | 42 | /* Destroy a buffer. */ 43 | void 44 | buffer_destroy(struct buffer *b) 45 | { 46 | xfree(b->base); 47 | xfree(b); 48 | } 49 | 50 | /* Empty a buffer. */ 51 | void 52 | buffer_clear(struct buffer *b) 53 | { 54 | b->size = 0; 55 | b->off = 0; 56 | } 57 | 58 | /* Ensure free space for size in buffer. */ 59 | void 60 | buffer_ensure(struct buffer *b, size_t size) 61 | { 62 | if (size == 0) 63 | fatalx("zero size"); 64 | 65 | if (BUFFER_FREE(b) >= size) 66 | return; 67 | 68 | if (b->off > 0) { 69 | if (b->size > 0) 70 | memmove(b->base, b->base + b->off, b->size); 71 | b->off = 0; 72 | } 73 | 74 | if (SIZE_MAX - b->size < size) 75 | fatalx("size too big"); 76 | while (b->space < b->size + size) { 77 | b->base = xrealloc(b->base, 2, b->space); 78 | b->space *= 2; 79 | } 80 | } 81 | 82 | /* Adjust buffer after data appended. */ 83 | void 84 | buffer_add(struct buffer *b, size_t size) 85 | { 86 | if (size == 0) 87 | fatalx("zero size"); 88 | if (size > b->space - b->size) 89 | fatalx("overflow"); 90 | 91 | b->size += size; 92 | } 93 | 94 | /* Reverse buffer add. */ 95 | void 96 | buffer_reverse_add(struct buffer *b, size_t size) 97 | { 98 | if (size == 0) 99 | fatalx("zero size"); 100 | if (size > b->size) 101 | fatalx("underflow"); 102 | 103 | b->size -= size; 104 | } 105 | 106 | /* Adjust buffer after data removed. */ 107 | void 108 | buffer_remove(struct buffer *b, size_t size) 109 | { 110 | if (size == 0) 111 | fatalx("zero size"); 112 | if (size > b->size) 113 | fatalx("underflow"); 114 | 115 | b->size -= size; 116 | b->off += size; 117 | } 118 | 119 | /* Reverse buffer remove. */ 120 | void 121 | buffer_reverse_remove(struct buffer *b, size_t size) 122 | { 123 | if (size == 0) 124 | fatalx("zero size"); 125 | if (size > b->off) 126 | fatalx("overflow"); 127 | 128 | b->size += size; 129 | b->off -= size; 130 | } 131 | 132 | /* Insert a section into the buffer. */ 133 | void 134 | buffer_insert_range(struct buffer *b, size_t base, size_t size) 135 | { 136 | if (size == 0) 137 | fatalx("zero size"); 138 | if (base > b->size) 139 | fatalx("range outside buffer"); 140 | 141 | buffer_ensure(b, size); 142 | memmove(b->base + b->off + base + size, 143 | b->base + b->off + base, b->size - base); 144 | b->size += size; 145 | } 146 | 147 | /* Delete a section from the buffer. */ 148 | void 149 | buffer_delete_range(struct buffer *b, size_t base, size_t size) 150 | { 151 | if (size == 0) 152 | fatalx("zero size"); 153 | if (size > b->size) 154 | fatalx("size too big"); 155 | if (base + size > b->size) 156 | fatalx("range outside buffer"); 157 | 158 | memmove(b->base + b->off + base, 159 | b->base + b->off + base + size, b->size - base - size); 160 | b->size -= size; 161 | } 162 | 163 | /* Copy data into a buffer. */ 164 | void 165 | buffer_write(struct buffer *b, const void *data, size_t size) 166 | { 167 | if (size == 0) 168 | fatalx("zero size"); 169 | 170 | buffer_ensure(b, size); 171 | memcpy(BUFFER_IN(b), data, size); 172 | buffer_add(b, size); 173 | } 174 | 175 | /* Copy data out of a buffer. */ 176 | void 177 | buffer_read(struct buffer *b, void *data, size_t size) 178 | { 179 | if (size == 0) 180 | fatalx("zero size"); 181 | if (size > b->size) 182 | fatalx("underflow"); 183 | 184 | memcpy(data, BUFFER_OUT(b), size); 185 | buffer_remove(b, size); 186 | } 187 | 188 | /* Store an 8-bit value. */ 189 | void 190 | buffer_write8(struct buffer *b, uint8_t n) 191 | { 192 | buffer_ensure(b, 1); 193 | BUFFER_IN(b)[0] = n; 194 | buffer_add(b, 1); 195 | } 196 | 197 | /* Store a 16-bit value. */ 198 | void 199 | buffer_write16(struct buffer *b, uint16_t n) 200 | { 201 | buffer_ensure(b, 2); 202 | BUFFER_IN(b)[0] = n & 0xff; 203 | BUFFER_IN(b)[1] = n >> 8; 204 | buffer_add(b, 2); 205 | } 206 | 207 | /* Extract an 8-bit value. */ 208 | uint8_t 209 | buffer_read8(struct buffer *b) 210 | { 211 | uint8_t n; 212 | 213 | n = BUFFER_OUT(b)[0]; 214 | buffer_remove(b, 1); 215 | return (n); 216 | } 217 | 218 | /* Extract a 16-bit value. */ 219 | uint16_t 220 | buffer_read16(struct buffer *b) 221 | { 222 | uint16_t n; 223 | 224 | n = BUFFER_OUT(b)[0] | (BUFFER_OUT(b)[1] << 8); 225 | buffer_remove(b, 2); 226 | return (n); 227 | } 228 | -------------------------------------------------------------------------------- /cache-op.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | 25 | __dead void cache_op_add(int, char **); 26 | __dead void cache_op_remove(int , char **); 27 | __dead void cache_op_list(int, char **); 28 | __dead void cache_op_dump(int, char **); 29 | __dead void cache_op_clear(int, char **); 30 | 31 | __dead void 32 | cache_op(int argc, char **argv) 33 | { 34 | char *cmd; 35 | 36 | if (argc < 1) 37 | usage(); 38 | cmd = argv[0]; 39 | argc--; 40 | argv++; 41 | 42 | if (strncmp(cmd, "add", strlen(cmd)) == 0) 43 | cache_op_add(argc, argv); 44 | if (strncmp(cmd, "remove", strlen(cmd)) == 0) 45 | cache_op_remove(argc, argv); 46 | if (strncmp(cmd, "list", strlen(cmd)) == 0) 47 | cache_op_list(argc, argv); 48 | if (strncmp(cmd, "dump", strlen(cmd)) == 0) 49 | cache_op_dump(argc, argv); 50 | if (strncmp(cmd, "clear", strlen(cmd)) == 0) 51 | cache_op_clear(argc, argv); 52 | usage(); 53 | } 54 | 55 | __dead void 56 | cache_op_add(int argc, char **argv) 57 | { 58 | TDB_CONTEXT *db; 59 | 60 | if (argc != 2) 61 | usage(); 62 | 63 | if ((db = db_open(argv[0])) == NULL) { 64 | log_warn("%s", argv[0]); 65 | exit(1); 66 | } 67 | 68 | if (db_add(db, argv[1]) != 0) { 69 | log_warnx("%s: cache error", argv[0]); 70 | exit(1); 71 | } 72 | 73 | exit(0); 74 | } 75 | 76 | __dead void 77 | cache_op_remove(int argc, char **argv) 78 | { 79 | TDB_CONTEXT *db; 80 | 81 | if (argc != 2) 82 | usage(); 83 | 84 | if ((db = db_open(argv[0])) == NULL) { 85 | log_warn("%s", argv[0]); 86 | exit(1); 87 | } 88 | 89 | if (!db_contains(db, argv[1])) { 90 | log_warnx("%s: key not found: %s", argv[0], argv[1]); 91 | exit(1); 92 | } 93 | if (db_remove(db, argv[1]) != 0) { 94 | log_warnx("%s: cache error", argv[0]); 95 | exit(1); 96 | } 97 | 98 | exit(0); 99 | } 100 | 101 | __dead void 102 | cache_op_list(int argc, char **argv) 103 | { 104 | struct cache *cache; 105 | TDB_CONTEXT *db; 106 | 107 | if (argc == 1) { 108 | if ((db = db_open(argv[0])) == NULL) { 109 | log_warn("%s", argv[0]); 110 | exit(1); 111 | } 112 | 113 | log_info("%s: %u keys", argv[0], db_size(db)); 114 | 115 | db_close(db); 116 | exit(0); 117 | } 118 | 119 | if (argc != 0) 120 | usage(); 121 | 122 | TAILQ_FOREACH(cache, &conf.caches, entry) { 123 | if ((cache->db = db_open(cache->path)) == NULL) { 124 | log_warn("%s", cache->path); 125 | exit(1); 126 | } 127 | 128 | log_info("%s: %u keys", cache->path, db_size(cache->db)); 129 | 130 | db_close(cache->db); 131 | } 132 | 133 | exit(0); 134 | } 135 | 136 | __dead void 137 | cache_op_dump(int argc, char **argv) 138 | { 139 | TDB_CONTEXT *db; 140 | 141 | if (argc != 1) 142 | usage(); 143 | 144 | if ((db = db_open(argv[0])) == NULL) { 145 | log_warn("%s", argv[0]); 146 | exit(1); 147 | } 148 | 149 | if (db_print(db, log_info) != 0) { 150 | log_warnx("%s: cache error", argv[0]); 151 | exit(1); 152 | } 153 | 154 | exit(0); 155 | } 156 | 157 | __dead void 158 | cache_op_clear(int argc, char **argv) 159 | { 160 | TDB_CONTEXT *db; 161 | 162 | if (argc != 1) 163 | usage(); 164 | 165 | if ((db = db_open(argv[0])) == NULL) { 166 | log_warn("%s", argv[0]); 167 | exit(1); 168 | } 169 | 170 | if (db_clear(db) != 0) { 171 | log_warnx("%s: cache error", argv[0]); 172 | exit(1); 173 | } 174 | 175 | exit(0); 176 | } 177 | 178 | -------------------------------------------------------------------------------- /child-deliver.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "fdm.h" 26 | #include "match.h" 27 | 28 | int child_deliver(struct child *, struct io *); 29 | 30 | int 31 | child_deliver(struct child *child, struct io *pio) 32 | { 33 | struct child_deliver_data *data = child->data; 34 | struct account *a = data->account; 35 | struct mail *m = data->mail; 36 | struct msg msg; 37 | struct msgbuf msgbuf; 38 | int error = 0; 39 | 40 | log_debug2("%s: deliver started, pid %ld", a->name, (long) getpid()); 41 | 42 | #ifdef HAVE_SETPROCTITLE 43 | setproctitle("%s[%lu]", data->name, (u_long) geteuid()); 44 | #endif 45 | 46 | /* Call the hook. */ 47 | memset(&msg, 0, sizeof msg); 48 | data->hook(0, a, &msg, data, &msg.data.error); 49 | 50 | /* Inform parent we're done. */ 51 | msg.type = MSG_DONE; 52 | msg.id = 0; 53 | 54 | msgbuf.buf = m->tags; 55 | msgbuf.len = STRB_SIZE(m->tags); 56 | 57 | if (privsep_send(pio, &msg, &msgbuf) != 0) 58 | fatalx("privsep_send error"); 59 | do { 60 | if (privsep_recv(pio, &msg, NULL) != 0) 61 | fatalx("privsep_recv error"); 62 | } while (msg.type != MSG_EXIT); 63 | 64 | return (error); 65 | } 66 | 67 | void 68 | child_deliver_action_hook(pid_t pid, struct account *a, struct msg *msg, 69 | struct child_deliver_data *data, int *result) 70 | { 71 | struct actitem *ti = data->actitem; 72 | struct deliver_ctx *dctx = data->dctx; 73 | struct mail *m = data->mail; 74 | struct mail *md = &dctx->wr_mail; 75 | 76 | /* Check if this is the parent. */ 77 | if (pid != 0) { 78 | /* Use new mail if necessary. */ 79 | if (ti->deliver->type != DELIVER_WRBACK) { 80 | xfree(dctx); 81 | return; 82 | } 83 | 84 | if (*result != DELIVER_SUCCESS) 85 | mail_destroy(md); 86 | else { 87 | mail_close(md); 88 | if (mail_receive(m, msg, 0) != 0) { 89 | log_warn("parent_deliver: can't receive mail"); 90 | *result = DELIVER_FAILURE; 91 | } 92 | } 93 | 94 | xfree(dctx); 95 | return; 96 | } 97 | 98 | dctx->udata = xmalloc(sizeof *dctx->udata); 99 | dctx->udata->uid = data->uid; 100 | dctx->udata->gid = data->gid; 101 | dctx->udata->name = xstrdup(find_tag(m->tags, "user")); 102 | dctx->udata->home = xstrdup(find_tag(m->tags, "home")); 103 | log_debug2("%s: deliver user is: %s (%lu/%lu), home is: %s", a->name, 104 | dctx->udata->name, (u_long) dctx->udata->uid, 105 | (u_long) dctx->udata->gid, dctx->udata->home); 106 | 107 | /* This is the child. do the delivery. */ 108 | *result = ti->deliver->deliver(dctx, ti); 109 | if (ti->deliver->type != DELIVER_WRBACK || *result != DELIVER_SUCCESS) { 110 | user_free(dctx->udata); 111 | return; 112 | } 113 | user_free(dctx->udata); 114 | 115 | mail_send(md, msg); 116 | log_debug2("%s: using new mail, size %zu", a->name, md->size); 117 | } 118 | 119 | void 120 | child_deliver_cmd_hook(pid_t pid, struct account *a, unused struct msg *msg, 121 | struct child_deliver_data *data, int *result) 122 | { 123 | struct mail_ctx *mctx = data->mctx; 124 | struct mail *m = data->mail; 125 | struct match_command_data *cmddata = data->cmddata; 126 | int flags, status, found = 0; 127 | char *s, *cause, *lbuf, *out, *err, tag[24]; 128 | size_t llen; 129 | struct cmd *cmd = NULL; 130 | struct rmlist rml; 131 | u_int i; 132 | 133 | /* If this is the parent, do nothing. */ 134 | if (pid != 0) { 135 | xfree(mctx); 136 | return; 137 | } 138 | 139 | /* Sort out the command. */ 140 | s = replacepath( 141 | &cmddata->cmd, m->tags, m, &m->rml, find_tag(m->tags, "home")); 142 | if (s == NULL || *s == '\0') { 143 | log_warnx("%s: empty command", a->name); 144 | goto error; 145 | } 146 | 147 | log_debug2("%s: %s: started (ret=%d re=%s)", a->name, s, cmddata->ret, 148 | cmddata->re.str == NULL ? "none" : cmddata->re.str); 149 | flags = CMD_ONCE; 150 | if (cmddata->pipe) 151 | flags |= CMD_IN; 152 | if (cmddata->re.str != NULL) 153 | flags |= CMD_OUT; 154 | cmd = cmd_start(s, flags, m->data, m->size, &cause); 155 | if (cmd == NULL) { 156 | log_warnx("%s: %s: %s", a->name, s, cause); 157 | goto error; 158 | } 159 | 160 | llen = IO_LINESIZE; 161 | lbuf = xmalloc(llen); 162 | 163 | for (;;) { 164 | /* Stop early if looking for regexp only. */ 165 | if (found && cmddata->ret == -1) { 166 | log_debug3("%s: %s: found. stopping early", a->name, s); 167 | status = 1; 168 | break; 169 | } 170 | 171 | status = cmd_poll( 172 | cmd, &out, &err, &lbuf, &llen, conf.timeout, &cause); 173 | if (status == -1) { 174 | log_warnx("%s: %s: %s", a->name, s, cause); 175 | goto error; 176 | } 177 | if (status != 0) 178 | break; 179 | if (err != NULL) 180 | log_warnx("%s: %s: %s", a->name, s, err); 181 | if (out == NULL) 182 | continue; 183 | log_debug3("%s: %s: out: %s", a->name, s, out); 184 | if (found) 185 | continue; 186 | 187 | found = re_string(&cmddata->re, out, &rml, &cause); 188 | if (found == -1) { 189 | log_warnx("%s: %s", a->name, cause); 190 | goto error; 191 | } 192 | if (found != 1) 193 | continue; 194 | /* Save the matches. */ 195 | if (!rml.valid) 196 | continue; 197 | for (i = 0; i < NPMATCH; i++) { 198 | if (!rml.list[i].valid) 199 | break; 200 | xsnprintf(tag, sizeof tag, "command%u", i); 201 | add_tag(&m->tags, tag, "%.*s", (int) (rml.list[i].eo - 202 | rml.list[i].so), out + rml.list[i].so); 203 | } 204 | } 205 | status--; 206 | 207 | log_debug2("%s: %s: returned %d, found %d", a->name, s, status, found); 208 | 209 | cmd_free(cmd); 210 | xfree(s); 211 | xfree(lbuf); 212 | 213 | status = cmddata->ret == status; 214 | if (cmddata->ret != -1 && cmddata->re.str != NULL) 215 | *result = (found && status) ? MATCH_TRUE : MATCH_FALSE; 216 | else if (cmddata->ret != -1 && cmddata->re.str == NULL) 217 | *result = status ? MATCH_TRUE : MATCH_FALSE; 218 | else if (cmddata->ret == -1 && cmddata->re.str != NULL) 219 | *result = found ? MATCH_TRUE : MATCH_FALSE; 220 | else 221 | *result = MATCH_ERROR; 222 | return; 223 | 224 | error: 225 | if (cause != NULL) 226 | xfree(cause); 227 | if (cmd != NULL) 228 | cmd_free(cmd); 229 | if (s != NULL) 230 | xfree(s); 231 | if (lbuf != NULL) 232 | xfree(lbuf); 233 | *result = MATCH_ERROR; 234 | } 235 | -------------------------------------------------------------------------------- /child.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "fdm.h" 26 | 27 | void child_sighandler(int); 28 | 29 | void 30 | child_sighandler(int sig) 31 | { 32 | switch (sig) { 33 | #ifdef SIGINFO 34 | case SIGINFO: 35 | #endif 36 | case SIGUSR1: 37 | sigusr1 = 1; 38 | break; 39 | case SIGCHLD: 40 | break; 41 | case SIGTERM: 42 | cleanup_purge(); 43 | _exit(1); 44 | } 45 | } 46 | 47 | int 48 | child_fork(void) 49 | { 50 | pid_t pid; 51 | struct sigaction act; 52 | 53 | switch (pid = fork()) { 54 | case -1: 55 | fatal("fork failed"); 56 | case 0: 57 | cleanup_flush(); 58 | 59 | sigemptyset(&act.sa_mask); 60 | #ifdef SIGINFO 61 | sigaddset(&act.sa_mask, SIGINFO); 62 | #endif 63 | sigaddset(&act.sa_mask, SIGUSR1); 64 | sigaddset(&act.sa_mask, SIGINT); 65 | sigaddset(&act.sa_mask, SIGTERM); 66 | sigaddset(&act.sa_mask, SIGCHLD); 67 | act.sa_flags = SA_RESTART; 68 | 69 | act.sa_handler = SIG_IGN; 70 | if (sigaction(SIGINT, &act, NULL) < 0) 71 | fatal("sigaction failed"); 72 | 73 | act.sa_handler = child_sighandler; 74 | #ifdef SIGINFO 75 | if (sigaction(SIGINFO, &act, NULL) < 0) 76 | fatal("sigaction failed"); 77 | #endif 78 | if (sigaction(SIGUSR1, &act, NULL) < 0) 79 | fatal("sigaction failed"); 80 | if (sigaction(SIGTERM, &act, NULL) < 0) 81 | fatal("sigaction failed"); 82 | if (sigaction(SIGCHLD, &act, NULL) < 0) 83 | fatal("sigaction failed"); 84 | 85 | return (0); 86 | default: 87 | return (pid); 88 | } 89 | } 90 | 91 | __dead void 92 | child_exit(int status) 93 | { 94 | cleanup_check(); 95 | _exit(status); 96 | } 97 | 98 | struct child * 99 | child_start(struct children *children, uid_t uid, gid_t gid, 100 | int (*start)(struct child *, struct io *), 101 | int (*msg)(struct child *, struct msg *, struct msgbuf *), 102 | void *data, struct child *parent) 103 | { 104 | struct child *child, *childp; 105 | int fds[2], n; 106 | u_int i; 107 | struct io *io; 108 | 109 | if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fds) != 0) 110 | fatal("socketpair failed"); 111 | 112 | child = xcalloc(1, sizeof *child); 113 | child->io = io_create(fds[0], NULL, IO_CRLF); 114 | child->data = data; 115 | child->msg = msg; 116 | child->parent = parent; 117 | 118 | if ((child->pid = child_fork()) == 0) { 119 | for (i = 0; i < ARRAY_LENGTH(children); i++) { 120 | childp = ARRAY_ITEM(children, i); 121 | if (childp->io != NULL) { 122 | io_close(childp->io); 123 | io_free(childp->io); 124 | } 125 | } 126 | io_close(child->io); 127 | io_free(child->io); 128 | 129 | if (geteuid() == 0) 130 | dropto(uid, gid); 131 | 132 | io = io_create(fds[1], NULL, IO_LF); 133 | n = start(child, io); 134 | io_close(io); 135 | io_free(io); 136 | 137 | child_exit(n); 138 | } 139 | close(fds[1]); 140 | 141 | ARRAY_ADD(children, child); 142 | return (child); 143 | } 144 | -------------------------------------------------------------------------------- /cleanup.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "fdm.h" 26 | 27 | struct cleanent { 28 | char *path; 29 | 30 | TAILQ_ENTRY(cleanent) entry; 31 | }; 32 | TAILQ_HEAD(, cleanent) cleanlist; 33 | 34 | void 35 | cleanup_check(void) 36 | { 37 | struct cleanent *cent; 38 | 39 | if (!TAILQ_EMPTY(&cleanlist)) { 40 | TAILQ_FOREACH(cent, &cleanlist, entry) 41 | log_debug("cleanup: %s", cent->path); 42 | fatalx("list not empty"); 43 | } 44 | } 45 | 46 | void 47 | cleanup_purge(void) 48 | { 49 | struct cleanent *cent; 50 | int saved_errno; 51 | 52 | /* 53 | * This must be signal safe. 54 | */ 55 | 56 | saved_errno = errno; 57 | TAILQ_FOREACH(cent, &cleanlist, entry) { 58 | if (unlink(cent->path) != 0) { 59 | write(STDERR_FILENO, "unlink failed\n", 14); 60 | _exit(1); 61 | } 62 | } 63 | errno = saved_errno; 64 | } 65 | 66 | void 67 | cleanup_flush(void) 68 | { 69 | sigset_t set, oset; 70 | struct cleanent *cent; 71 | 72 | sigfillset(&set); 73 | if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) 74 | fatal("sigprocmask failed"); 75 | 76 | while (!TAILQ_EMPTY(&cleanlist)) { 77 | cent = TAILQ_FIRST(&cleanlist); 78 | TAILQ_REMOVE(&cleanlist, cent, entry); 79 | xfree(cent->path); 80 | xfree(cent); 81 | } 82 | 83 | if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) 84 | fatal("sigprocmask failed"); 85 | } 86 | 87 | void 88 | cleanup_register(const char *path) 89 | { 90 | sigset_t set, oset; 91 | struct cleanent *cent; 92 | 93 | #if 0 94 | log_debug("cleanup_register: %s by %ld", path, (long) getpid()); 95 | #endif 96 | 97 | if (path == NULL || *path == '\0') 98 | fatalx("empty path"); 99 | 100 | cent = xmalloc(sizeof *cent); 101 | cent->path = xstrdup(path); 102 | 103 | sigfillset(&set); 104 | if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) 105 | fatal("sigprocmask failed"); 106 | 107 | TAILQ_INSERT_HEAD(&cleanlist, cent, entry); 108 | 109 | if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) 110 | fatal("sigprocmask failed"); 111 | } 112 | 113 | void 114 | cleanup_deregister(const char *path) 115 | { 116 | sigset_t set, oset; 117 | struct cleanent *cent; 118 | 119 | #if 0 120 | log_debug("cleanup_deregister: %s by %ld", path, (long) getpid()); 121 | #endif 122 | 123 | if (path == NULL || *path == '\0') 124 | fatalx("empty path"); 125 | 126 | sigfillset(&set); 127 | if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) 128 | fatal("sigprocmask failed"); 129 | 130 | TAILQ_FOREACH(cent, &cleanlist, entry) { 131 | if (strcmp(cent->path, path) == 0) { 132 | TAILQ_REMOVE(&cleanlist, cent, entry); 133 | xfree(cent->path); 134 | xfree(cent); 135 | goto out; 136 | } 137 | } 138 | 139 | fatalx("entry not found"); 140 | 141 | out: 142 | if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) 143 | fatal("sigprocmask failed"); 144 | } 145 | -------------------------------------------------------------------------------- /compat/strlcat.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 1998 Todd C. Miller 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "fdm.h" 24 | 25 | /* 26 | * Appends src to string dst of size siz (unlike strncat, siz is the 27 | * full size of dst, not space left). At most siz-1 characters 28 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). 29 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). 30 | * If retval >= siz, truncation occurred. 31 | */ 32 | size_t 33 | strlcat(char *dst, const char *src, size_t siz) 34 | { 35 | char *d = dst; 36 | const char *s = src; 37 | size_t n = siz; 38 | size_t dlen; 39 | 40 | /* Find the end of dst and adjust bytes left but don't go past end */ 41 | while (n-- != 0 && *d != '\0') 42 | d++; 43 | dlen = d - dst; 44 | n = siz - dlen; 45 | 46 | if (n == 0) 47 | return(dlen + strlen(s)); 48 | while (*s != '\0') { 49 | if (n != 1) { 50 | *d++ = *s; 51 | n--; 52 | } 53 | s++; 54 | } 55 | *d = '\0'; 56 | 57 | return(dlen + (s - src)); /* count does not include NUL */ 58 | } 59 | -------------------------------------------------------------------------------- /compat/strlcpy.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | /* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 1998 Todd C. Miller 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "fdm.h" 24 | 25 | /* 26 | * Copy src to string dst of size siz. At most siz-1 characters 27 | * will be copied. Always NUL terminates (unless siz == 0). 28 | * Returns strlen(src); if retval >= siz, truncation occurred. 29 | */ 30 | size_t 31 | strlcpy(char *dst, const char *src, size_t siz) 32 | { 33 | char *d = dst; 34 | const char *s = src; 35 | size_t n = siz; 36 | 37 | /* Copy as many bytes as will fit */ 38 | if (n != 0 && --n != 0) { 39 | do { 40 | if ((*d++ = *s++) == 0) 41 | break; 42 | } while (--n != 0); 43 | } 44 | 45 | /* Not enough room in dst, add NUL and traverse rest of src */ 46 | if (n == 0) { 47 | if (siz != 0) 48 | *d = '\0'; /* NUL-terminate dst */ 49 | while (*s++) 50 | ; 51 | } 52 | 53 | return(s - src - 1); /* count does not include NUL */ 54 | } 55 | -------------------------------------------------------------------------------- /compat/strtonum.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | /* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 2004 Ted Unangst and Todd Miller 6 | * All rights reserved. 7 | * 8 | * Permission to use, copy, modify, and distribute this software for any 9 | * purpose with or without fee is hereby granted, provided that the above 10 | * copyright notice and this permission notice appear in all copies. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "fdm.h" 26 | 27 | #define INVALID 1 28 | #define TOOSMALL 2 29 | #define TOOLARGE 3 30 | 31 | long long 32 | strtonum(const char *numstr, long long minval, long long maxval, 33 | const char **errstrp) 34 | { 35 | long long ll = 0; 36 | char *ep; 37 | int error = 0; 38 | struct errval { 39 | const char *errstr; 40 | int err; 41 | } ev[4] = { 42 | { NULL, 0 }, 43 | { "invalid", EINVAL }, 44 | { "too small", ERANGE }, 45 | { "too large", ERANGE }, 46 | }; 47 | 48 | ev[0].err = errno; 49 | errno = 0; 50 | if (minval > maxval) 51 | error = INVALID; 52 | else { 53 | ll = strtoll(numstr, &ep, 10); 54 | if (numstr == ep || *ep != '\0') 55 | error = INVALID; 56 | else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) 57 | error = TOOSMALL; 58 | else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) 59 | error = TOOLARGE; 60 | } 61 | if (errstrp != NULL) 62 | *errstrp = ev[error].errstr; 63 | errno = ev[error].err; 64 | if (error) 65 | ll = 0; 66 | 67 | return (ll); 68 | } 69 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # $Id$ 2 | 3 | AC_INIT(fdm, 2.2) 4 | RELEASE=2.2 5 | AC_SUBST(RELEASE) 6 | 7 | AC_CONFIG_AUX_DIR(etc) 8 | AM_INIT_AUTOMAKE([foreign subdir-objects]) 9 | 10 | AC_CANONICAL_HOST 11 | 12 | : ${CFLAGS=""} 13 | 14 | CPPFLAGS="$CPPFLAGS -I/usr/local/include" 15 | LDFLAGS="$LDFLAGS -L/usr/local/lib" 16 | 17 | AC_PROG_CC 18 | AM_PROG_CC_C_O 19 | AC_PROG_INSTALL 20 | AC_PROG_YACC 21 | 22 | test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc 23 | test "$localstatedir" = '${prefix}/var' && localstatedir=/var 24 | 25 | AC_ARG_ENABLE( 26 | debug, 27 | AS_HELP_STRING(--enable-debug, create a debug build), 28 | found_debug=$enable_debug 29 | ) 30 | AM_CONDITIONAL(IS_DEBUG, test "x$found_debug" = xyes) 31 | 32 | AC_ARG_ENABLE( 33 | static, 34 | AS_HELP_STRING(--enable-static, create a static build), 35 | found_static=$enable_static 36 | ) 37 | if test "x$found_static" = xyes; then 38 | LDFLAGS="$LDFLAGS -static" 39 | fi 40 | 41 | AC_ARG_ENABLE( 42 | pcre2, 43 | AS_HELP_STRING(--enable-pcre2, use PCRE2), 44 | found_pcre2=$enable_pcre2 45 | ) 46 | if test "x$found_pcre2" = xyes; then 47 | CPPFLAGS="$CPPFLAGS -DPCRE2" 48 | 49 | AC_SEARCH_LIBS( 50 | pcre2_compile_8, 51 | [pcre2-8], 52 | found_pcre=yes, 53 | found_pcre=no 54 | ) 55 | if test "x$found_pcre" = xno; then 56 | AC_MSG_ERROR("libpcre2 not found") 57 | fi 58 | fi 59 | 60 | AC_CHECK_HEADERS( 61 | [ \ 62 | sys/queue.h \ 63 | sys/tree.h \ 64 | ] 65 | ) 66 | AC_CHECK_FUNCS( 67 | [ \ 68 | setproctitle \ 69 | setresuid \ 70 | setresgid \ 71 | ] 72 | ) 73 | AC_CHECK_DECL( 74 | MREMAP_MAYMOVE, 75 | AC_CHECK_FUNC([mremap]), 76 | , 77 | [ 78 | #define _GNU_SOURCE 79 | #include 80 | ] 81 | ) 82 | 83 | AC_SEARCH_LIBS( 84 | tdb_open, 85 | [tdb], 86 | found_libtdb=yes, 87 | found_libtdb=no 88 | ) 89 | if test "x$found_libtdb" = xno; then 90 | AC_MSG_ERROR("libtdb not found") 91 | fi 92 | 93 | AC_SEARCH_LIBS( 94 | gzflush, 95 | [z], 96 | found_libz=yes, 97 | found_libz=no 98 | ) 99 | if test "x$found_libz" = xno; then 100 | AC_MSG_ERROR("libz not found") 101 | fi 102 | 103 | AC_SEARCH_LIBS( 104 | BIO_new, 105 | [crypto], 106 | found_libcrypto=yes, 107 | found_libcrypto=no 108 | ) 109 | if test "x$found_libcrypto" = xno; then 110 | AC_MSG_ERROR("libcrypto not found") 111 | fi 112 | AC_SEARCH_LIBS( 113 | OPENSSL_init_ssl, 114 | [ssl], 115 | found_libssl=yes, 116 | found_libssl=no 117 | ) 118 | AC_SEARCH_LIBS( 119 | SSL_library_init, 120 | [ssl], 121 | found_libssl=yes 122 | ) 123 | if test "x$found_libssl" = xno; then 124 | AC_MSG_ERROR("libssl not found") 125 | fi 126 | 127 | AC_CHECK_DECL(strlcpy, found_strlcpy=yes, found_strlcpy=no) 128 | if test "x$found_strlcpy" = xyes; then 129 | AC_DEFINE(HAVE_STRLCPY) 130 | fi 131 | AM_CONDITIONAL(NO_STRLCPY, [test "x$found_strlcpy" = xno]) 132 | 133 | AC_CHECK_DECL(strlcat, found_strlcat=yes, found_strlcat=no) 134 | if test "x$found_strlcat" = xyes; then 135 | AC_DEFINE(HAVE_STRLCAT) 136 | fi 137 | AM_CONDITIONAL(NO_STRLCAT, [test "x$found_strlcat" = xno]) 138 | 139 | AC_CHECK_FUNC(strtonum, found_strtonum=yes, found_strtonum=no) 140 | if test "x$found_strtonum" = xyes; then 141 | AC_DEFINE(HAVE_STRTONUM) 142 | fi 143 | AM_CONDITIONAL(NO_STRTONUM, [test "x$found_strtonum" = xno]) 144 | 145 | AC_MSG_CHECKING(for b64_ntop) 146 | AC_LINK_IFELSE([AC_LANG_PROGRAM( 147 | [ 148 | #include 149 | #include 150 | #include 151 | ], 152 | [ 153 | b64_ntop(NULL, 0, NULL, 0); 154 | ])], 155 | found_b64_ntop=yes, 156 | found_b64_ntop=no 157 | ) 158 | if test "x$found_b64_ntop" = xno; then 159 | AC_MSG_RESULT(no) 160 | 161 | AC_MSG_CHECKING(for b64_ntop with -lresolv) 162 | LIBS="$LIBS -lresolv" 163 | AC_LINK_IFELSE([AC_LANG_PROGRAM( 164 | [ 165 | #include 166 | #include 167 | #include 168 | ], 169 | [ 170 | b64_ntop(NULL, 0, NULL, 0); 171 | ])], 172 | found_b64_ntop=yes, 173 | found_b64_ntop=no 174 | ) 175 | if test "x$found_b64_ntop" = xno; then 176 | AC_MSG_RESULT(no) 177 | fi 178 | fi 179 | if test "x$found_b64_ntop" = xyes; then 180 | AC_DEFINE(HAVE_B64_NTOP) 181 | AC_MSG_RESULT(yes) 182 | fi 183 | AM_CONDITIONAL(NO_B64_NTOP, [test "x$found_b64_ntop" = xno]) 184 | 185 | AC_CONFIG_FILES(Makefile) 186 | AC_OUTPUT 187 | -------------------------------------------------------------------------------- /db-tdb.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #ifndef _PUBLIC_ 26 | #define _PUBLIC_ 27 | #endif 28 | #include 29 | 30 | #include "fdm.h" 31 | 32 | int db_print_item(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *); 33 | int db_expire_item(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *); 34 | int db_clear_item(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *); 35 | 36 | TDB_CONTEXT * 37 | db_open(char *path) 38 | { 39 | TDB_CONTEXT *db; 40 | 41 | #ifndef DB_UNSAFE 42 | db = tdb_open(path, 0, 0, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); 43 | #else 44 | db = tdb_open(path, 0, TDB_NOLOCK, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); 45 | #endif 46 | return (db); 47 | } 48 | 49 | void 50 | db_close(TDB_CONTEXT *db) 51 | { 52 | tdb_close(db); 53 | } 54 | 55 | int 56 | db_add(TDB_CONTEXT *db, char *k) 57 | { 58 | TDB_DATA key, value; 59 | struct cacheitem v; 60 | uint64_t tim; 61 | 62 | memset(&v, 0, sizeof v); 63 | tim = time(NULL); 64 | v.tim = htole64(tim); 65 | 66 | key.dptr = k; 67 | key.dsize = strlen(k); 68 | 69 | value.dptr = (char *) &v; 70 | value.dsize = sizeof v; 71 | 72 | return (tdb_store(db, key, value, TDB_REPLACE)); 73 | } 74 | 75 | int 76 | db_remove(TDB_CONTEXT *db, char *k) 77 | { 78 | TDB_DATA key; 79 | 80 | key.dptr = k; 81 | key.dsize = strlen(k); 82 | 83 | return (tdb_delete(db, key)); 84 | } 85 | 86 | int 87 | db_contains(TDB_CONTEXT *db, char *k) 88 | { 89 | TDB_DATA key; 90 | 91 | key.dptr = k; 92 | key.dsize = strlen(k); 93 | 94 | return (tdb_exists(db, key)); 95 | } 96 | 97 | int 98 | db_size(TDB_CONTEXT *db) 99 | { 100 | return (tdb_traverse(db, NULL, NULL)); 101 | } 102 | 103 | int 104 | db_print_item( 105 | unused TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, void *ptr) 106 | { 107 | void (*p)(const char *, ...) = ptr; 108 | struct cacheitem v; 109 | uint64_t tim; 110 | 111 | if (value.dsize != sizeof v) 112 | return (-1); 113 | memcpy(&v, value.dptr, sizeof v); 114 | 115 | tim = letoh64(v.tim); 116 | p("%.*s %llu", key.dsize, key.dptr, (unsigned long long) tim); 117 | 118 | return (0); 119 | } 120 | 121 | int 122 | db_print(TDB_CONTEXT *db, void (*p)(const char *, ...)) 123 | { 124 | if (tdb_traverse(db, db_print_item, p) == -1) 125 | return (-1); 126 | return (0); 127 | } 128 | 129 | int 130 | db_expire_item(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, void *ptr) 131 | { 132 | uint64_t *lim = ptr; 133 | struct cacheitem v; 134 | 135 | if (value.dsize != sizeof v) 136 | return (-1); 137 | memcpy(&v, value.dptr, sizeof v); 138 | 139 | if (letoh64(v.tim) < *lim) 140 | return (tdb_delete(tdb, key)); 141 | return (0); 142 | } 143 | 144 | int 145 | db_expire(TDB_CONTEXT *db, uint64_t age) 146 | { 147 | uint64_t lim; 148 | 149 | lim = time(NULL); 150 | if (lim <= age) 151 | return (0); 152 | lim -= age; 153 | 154 | if (tdb_traverse(db, db_expire_item, &lim) == -1) 155 | return (-1); 156 | return (0); 157 | } 158 | 159 | int 160 | db_clear_item(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, unused void *ptr) 161 | { 162 | if (value.dsize != sizeof (struct cacheitem)) 163 | return (-1); 164 | 165 | return (tdb_delete(tdb, key)); 166 | } 167 | 168 | int 169 | db_clear(TDB_CONTEXT *db) 170 | { 171 | if (tdb_traverse(db, db_clear_item, NULL) == -1) 172 | return (-1); 173 | return (0); 174 | } 175 | -------------------------------------------------------------------------------- /deliver-add-header.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "deliver.h" 25 | 26 | int deliver_add_header_deliver(struct deliver_ctx *, struct actitem *); 27 | void deliver_add_header_desc(struct actitem *, char *, size_t); 28 | 29 | struct deliver deliver_add_header = { 30 | "add-header", 31 | DELIVER_INCHILD, 32 | deliver_add_header_deliver, 33 | deliver_add_header_desc 34 | }; 35 | 36 | int 37 | deliver_add_header_deliver(struct deliver_ctx *dctx, struct actitem *ti) 38 | { 39 | struct account *a = dctx->account; 40 | struct mail *m = dctx->mail; 41 | struct deliver_add_header_data *data = ti->data; 42 | char *hdr, *value = NULL; 43 | 44 | hdr = replacestr(&data->hdr, m->tags, m, &m->rml); 45 | if (hdr == NULL || *hdr == '\0') { 46 | log_warnx("%s: empty header", a->name); 47 | goto error; 48 | } 49 | value = replacestr(&data->value, m->tags, m, &m->rml); 50 | if (value == NULL) { 51 | log_warnx("%s: bad value for header %s", a->name, hdr); 52 | goto error; 53 | } 54 | log_debug2("%s: adding header: %s", a->name, hdr); 55 | 56 | if (insert_header(m, NULL, "%s: %s", hdr, value) != 0) { 57 | log_warnx("%s: failed to add header %s (%s)", a->name, 58 | hdr, value); 59 | goto error; 60 | } 61 | 62 | ARRAY_FREE(&m->wrapped); 63 | m->wrapchar = '\0'; 64 | fill_wrapped(m); 65 | 66 | /* Invalidate the match data since stuff may have moved. */ 67 | m->rml.valid = 0; 68 | 69 | xfree(hdr); 70 | xfree(value); 71 | return (DELIVER_SUCCESS); 72 | 73 | error: 74 | if (hdr != NULL) 75 | xfree(hdr); 76 | if (value != NULL) 77 | xfree(value); 78 | return (DELIVER_FAILURE); 79 | } 80 | 81 | void 82 | deliver_add_header_desc(struct actitem *ti, char *buf, size_t len) 83 | { 84 | struct deliver_add_header_data *data = ti->data; 85 | 86 | xsnprintf(buf, len, 87 | "add-header \"%s\" value \"%s\"", data->hdr.str, data->value.str); 88 | } 89 | -------------------------------------------------------------------------------- /deliver-add-to-cache.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "deliver.h" 25 | 26 | int deliver_add_to_cache_deliver(struct deliver_ctx *, struct actitem *); 27 | void deliver_add_to_cache_desc(struct actitem *, char *, size_t); 28 | 29 | struct deliver deliver_add_to_cache = { 30 | "add-to-cache", 31 | DELIVER_INCHILD, 32 | deliver_add_to_cache_deliver, 33 | deliver_add_to_cache_desc 34 | }; 35 | 36 | int 37 | deliver_add_to_cache_deliver(struct deliver_ctx *dctx, struct actitem *ti) 38 | { 39 | struct account *a = dctx->account; 40 | struct mail *m = dctx->mail; 41 | struct deliver_add_to_cache_data *data = ti->data; 42 | char *key; 43 | struct cache *cache; 44 | 45 | key = replacestr(&data->key, m->tags, m, &m->rml); 46 | if (key == NULL || *key == '\0') { 47 | log_warnx("%s: empty key", a->name); 48 | goto error; 49 | } 50 | log_debug2("%s: saving to cache %s: %s", a->name, data->path, key); 51 | 52 | TAILQ_FOREACH(cache, &conf.caches, entry) { 53 | if (strcmp(data->path, cache->path) == 0) { 54 | if (open_cache(a, cache) != 0) 55 | goto error; 56 | if (db_add(cache->db, key) != 0) { 57 | log_warnx("%s: error adding to cache %s: %s", 58 | a->name, cache->path, key); 59 | goto error; 60 | } 61 | xfree(key); 62 | return (DELIVER_SUCCESS); 63 | } 64 | } 65 | log_warnx("%s: cache %s not declared", a->name, data->path); 66 | 67 | error: 68 | if (key != NULL) 69 | xfree(key); 70 | return (DELIVER_FAILURE); 71 | } 72 | 73 | void 74 | deliver_add_to_cache_desc(struct actitem *ti, char *buf, size_t len) 75 | { 76 | struct deliver_add_to_cache_data *data = ti->data; 77 | 78 | xsnprintf(buf, len, 79 | "add-to-cache \"%s\" key \"%s\"", data->path, data->key.str); 80 | } 81 | -------------------------------------------------------------------------------- /deliver-drop.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "deliver.h" 25 | 26 | int deliver_drop_deliver(struct deliver_ctx *, struct actitem *); 27 | void deliver_drop_desc(struct actitem *, char *, size_t); 28 | 29 | struct deliver deliver_drop = { 30 | "drop", 31 | DELIVER_INCHILD, 32 | deliver_drop_deliver, 33 | deliver_drop_desc 34 | }; 35 | 36 | int 37 | deliver_drop_deliver(struct deliver_ctx *dctx, unused struct actitem *ti) 38 | { 39 | struct mail *m = dctx->mail; 40 | 41 | m->decision = DECISION_DROP; 42 | 43 | return (DELIVER_SUCCESS); 44 | } 45 | 46 | void 47 | deliver_drop_desc(unused struct actitem *ti, char *buf, size_t len) 48 | { 49 | strlcpy(buf, "drop", len); 50 | } 51 | -------------------------------------------------------------------------------- /deliver-keep.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "deliver.h" 25 | 26 | int deliver_keep_deliver(struct deliver_ctx *, struct actitem *); 27 | void deliver_keep_desc(struct actitem *, char *, size_t); 28 | 29 | struct deliver deliver_keep = { 30 | "keep", 31 | DELIVER_INCHILD, 32 | deliver_keep_deliver, 33 | deliver_keep_desc 34 | }; 35 | 36 | int 37 | deliver_keep_deliver(struct deliver_ctx *dctx, unused struct actitem *ti) 38 | { 39 | struct mail *m = dctx->mail; 40 | 41 | m->decision = DECISION_KEEP; 42 | 43 | return (DELIVER_SUCCESS); 44 | } 45 | 46 | void 47 | deliver_keep_desc(unused struct actitem *ti, char *buf, size_t len) 48 | { 49 | strlcpy(buf, "keep", len); 50 | } 51 | -------------------------------------------------------------------------------- /deliver-lmtp.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * Copyright (c) 2021 Anonymous 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 16 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 17 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "fdm.h" 30 | #include "deliver.h" 31 | 32 | int deliver_lmtp_deliver(struct deliver_ctx *, struct actitem *); 33 | void deliver_lmtp_desc(struct actitem *, char *, size_t); 34 | 35 | int deliver_lmtp_code(char *); 36 | 37 | enum deliver_lmtp_state { 38 | LMTP_CONNECTING, 39 | LMTP_LHLO, 40 | LMTP_FROM, 41 | LMTP_TO, 42 | LMTP_DATA, 43 | LMTP_DONE, 44 | LMTP_QUIT 45 | }; 46 | 47 | struct deliver deliver_lmtp = { 48 | "lmtp", 49 | DELIVER_ASUSER, 50 | deliver_lmtp_deliver, 51 | deliver_lmtp_desc 52 | }; 53 | 54 | int 55 | deliver_lmtp_code(char *line) 56 | { 57 | char ch; 58 | const char *errstr; 59 | int n; 60 | size_t len; 61 | 62 | len = strspn(line, "0123456789"); 63 | if (len == 0) 64 | return (-1); 65 | ch = line[len]; 66 | line[len] = '\0'; 67 | 68 | n = strtonum(line, 100, 999, &errstr); 69 | line[len] = ch; 70 | if (errstr != NULL) 71 | return (-1); 72 | 73 | return (n); 74 | } 75 | 76 | int 77 | deliver_lmtp_deliver(struct deliver_ctx *dctx, struct actitem *ti) 78 | { 79 | struct account *a = dctx->account; 80 | struct mail *m = dctx->mail; 81 | struct deliver_lmtp_data *data = ti->data; 82 | int done, code; 83 | struct io *io; 84 | char *cause = NULL, *to, *from, *line, *ptr; 85 | char *lbuf; 86 | enum deliver_lmtp_state state; 87 | size_t len, llen; 88 | 89 | if (data->socket != NULL) 90 | io = connectunix(data->socket, &cause); 91 | else { 92 | io = connectio(&data->server, conf.verify_certs, IO_CRLF, 93 | conf.timeout, &cause); 94 | } 95 | 96 | if (io == NULL) { 97 | log_warnx("%s: %s", a->name, cause); 98 | xfree(cause); 99 | return (DELIVER_FAILURE); 100 | } 101 | 102 | if (conf.debug > 3 && !conf.syslog) 103 | io->dup_fd = STDOUT_FILENO; 104 | 105 | 106 | llen = IO_LINESIZE; 107 | lbuf = xmalloc(llen); 108 | 109 | if (conf.host_fqdn != NULL) 110 | xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_fqdn); 111 | else 112 | xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_name); 113 | if (data->to.str == NULL) 114 | to = xstrdup(ptr); 115 | else { 116 | to = replacestr(&data->to, m->tags, m, &m->rml); 117 | if (to == NULL || *to == '\0') { 118 | xasprintf(&cause, "%s: empty to", a->name); 119 | from = NULL; 120 | goto error; 121 | } 122 | } 123 | if (data->from.str == NULL) 124 | from = xstrdup(ptr); 125 | else { 126 | from = replacestr(&data->from, m->tags, m, &m->rml); 127 | if (from == NULL || *from == '\0') { 128 | xasprintf(&cause, "%s: empty from", a->name); 129 | goto error; 130 | } 131 | } 132 | xfree(ptr); 133 | 134 | state = LMTP_CONNECTING; 135 | done = 0; 136 | do { 137 | switch (io_pollline2(io, &line, &lbuf, &llen, conf.timeout, 138 | &cause)) { 139 | case 0: 140 | cause = xstrdup("connection unexpectedly closed"); 141 | goto error; 142 | case -1: 143 | goto error; 144 | } 145 | code = deliver_lmtp_code(line); 146 | 147 | switch (state) { 148 | case LMTP_CONNECTING: 149 | if (code != 220) 150 | goto error; 151 | 152 | state = LMTP_LHLO; 153 | if (conf.host_fqdn != NULL) 154 | io_writeline(io, "LHLO %s", conf.host_fqdn); 155 | else 156 | io_writeline(io, "LHLO %s", conf.host_name); 157 | break; 158 | case LMTP_LHLO: 159 | if (code != 250) 160 | goto error; 161 | 162 | if (line[3] == ' ') { 163 | state = LMTP_FROM; 164 | io_writeline(io, "MAIL FROM:<%s>", from); 165 | } 166 | break; 167 | case LMTP_FROM: 168 | if (code != 250) 169 | goto error; 170 | state = LMTP_TO; 171 | io_writeline(io, "RCPT TO:<%s>", to); 172 | break; 173 | case LMTP_TO: 174 | if (code != 250) 175 | goto error; 176 | state = LMTP_DATA; 177 | io_writeline(io, "DATA"); 178 | break; 179 | case LMTP_DATA: 180 | if (code != 354) 181 | goto error; 182 | line_init(m, &ptr, &len); 183 | while (ptr != NULL) { 184 | if (len > 1) { 185 | if (*ptr == '.') 186 | io_write(io, ".", 1); 187 | io_write(io, ptr, len - 1); 188 | } 189 | io_writeline(io, NULL); 190 | 191 | /* Update if necessary. */ 192 | if (io_update(io, conf.timeout, &cause) != 1) 193 | goto error; 194 | 195 | line_next(m, &ptr, &len); 196 | } 197 | state = LMTP_DONE; 198 | io_writeline(io, "."); 199 | io_flush(io, conf.timeout, NULL); 200 | break; 201 | case LMTP_DONE: 202 | if (code != 250) 203 | goto error; 204 | state = LMTP_QUIT; 205 | io_writeline(io, "QUIT"); 206 | break; 207 | case LMTP_QUIT: 208 | /* 209 | * Exchange sometimes refuses to accept QUIT as a valid 210 | * command, but since we got a 250 the mail has been 211 | * accepted. So, allow 500 here too. 212 | */ 213 | if (code != 500 && code != 221) 214 | goto error; 215 | done = 1; 216 | break; 217 | } 218 | } while (!done); 219 | 220 | xfree(lbuf); 221 | xfree(from); 222 | xfree(to); 223 | 224 | io_close(io); 225 | io_free(io); 226 | 227 | return (DELIVER_SUCCESS); 228 | 229 | error: 230 | if (cause != NULL) { 231 | log_warnx("%s: %s", a->name, cause); 232 | xfree(cause); 233 | } else 234 | log_warnx("%s: unexpected response: %s", a->name, line); 235 | 236 | io_writeline(io, "QUIT"); 237 | io_flush(io, conf.timeout, NULL); 238 | 239 | xfree(lbuf); 240 | if (from != NULL) 241 | xfree(from); 242 | if (to != NULL) 243 | xfree(to); 244 | 245 | io_close(io); 246 | io_free(io); 247 | 248 | return (DELIVER_FAILURE); 249 | } 250 | 251 | void 252 | deliver_lmtp_desc(struct actitem *ti, char *buf, size_t len) 253 | { 254 | struct deliver_lmtp_data *data = ti->data; 255 | 256 | if (data->socket != NULL) { 257 | xsnprintf(buf, len, "lmtp-unix \"%s\" to \"%s\"", 258 | data->socket, data->to.str); 259 | } else { 260 | xsnprintf(buf, len, "lmtp-inet \"%s\" port \"%s\" to \"%s\"", 261 | data->server.host, data->server.port, data->to.str); 262 | } 263 | } 264 | 265 | -------------------------------------------------------------------------------- /deliver-pipe.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "fdm.h" 28 | #include "deliver.h" 29 | 30 | int deliver_pipe_deliver(struct deliver_ctx *, struct actitem *); 31 | void deliver_pipe_desc(struct actitem *, char *, size_t); 32 | 33 | struct deliver deliver_pipe = { 34 | "pipe", 35 | DELIVER_ASUSER, 36 | deliver_pipe_deliver, 37 | deliver_pipe_desc 38 | }; 39 | 40 | int 41 | deliver_pipe_deliver(struct deliver_ctx *dctx, struct actitem *ti) 42 | { 43 | struct account *a = dctx->account; 44 | struct mail *m = dctx->mail; 45 | struct deliver_pipe_data *data = ti->data; 46 | char *s, *cause, *err; 47 | int status; 48 | struct cmd *cmd = NULL; 49 | char *lbuf; 50 | size_t llen; 51 | 52 | s = replacepath(&data->cmd, m->tags, m, &m->rml, dctx->udata->home); 53 | if (s == NULL || *s == '\0') { 54 | log_warnx("%s: empty command", a->name); 55 | goto error; 56 | } 57 | 58 | if (data->pipe) { 59 | log_debug2("%s: piping to \"%s\"", a->name, s); 60 | cmd = cmd_start(s, CMD_IN|CMD_ONCE, m->data, m->size, &cause); 61 | } else { 62 | log_debug2("%s: executing \"%s\"", a->name, s); 63 | cmd = cmd_start(s, 0, NULL, 0, &cause); 64 | } 65 | if (cmd == NULL) 66 | goto error_cause; 67 | log_debug3("%s: %s: started", a->name, s); 68 | 69 | llen = IO_LINESIZE; 70 | lbuf = xmalloc(llen); 71 | 72 | do { 73 | status = cmd_poll( 74 | cmd, NULL, &err, &lbuf, &llen, conf.timeout, &cause); 75 | if (status == -1) { 76 | xfree(lbuf); 77 | goto error_cause; 78 | } 79 | if (status == 0 && err != NULL) 80 | log_warnx("%s: %s: %s", a->name, s, err); 81 | } while (status == 0); 82 | status--; 83 | 84 | xfree(lbuf); 85 | 86 | if (status != 0) { 87 | log_warnx("%s: %s: command returned %d", a->name, s, status); 88 | goto error; 89 | } 90 | 91 | cmd_free(cmd); 92 | xfree(s); 93 | return (DELIVER_SUCCESS); 94 | 95 | error_cause: 96 | log_warnx("%s: %s: %s", a->name, s, cause); 97 | xfree(cause); 98 | 99 | error: 100 | if (cmd != NULL) 101 | cmd_free(cmd); 102 | if (s != NULL) 103 | xfree(s); 104 | return (DELIVER_FAILURE); 105 | } 106 | 107 | void 108 | deliver_pipe_desc(struct actitem *ti, char *buf, size_t len) 109 | { 110 | struct deliver_pipe_data *data = ti->data; 111 | 112 | if (data->pipe) 113 | xsnprintf(buf, len, "pipe \"%s\"", data->cmd.str); 114 | else 115 | xsnprintf(buf, len, "exec \"%s\"", data->cmd.str); 116 | } 117 | -------------------------------------------------------------------------------- /deliver-remove-from-cache.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "deliver.h" 25 | 26 | int deliver_remove_from_cache_deliver( 27 | struct deliver_ctx *, struct actitem *); 28 | void deliver_remove_from_cache_desc(struct actitem *, char *, size_t); 29 | 30 | struct deliver deliver_remove_from_cache = { 31 | "remove-from-cache", 32 | DELIVER_INCHILD, 33 | deliver_remove_from_cache_deliver, 34 | deliver_remove_from_cache_desc 35 | }; 36 | 37 | int 38 | deliver_remove_from_cache_deliver(struct deliver_ctx *dctx, struct actitem *ti) 39 | { 40 | struct account *a = dctx->account; 41 | struct mail *m = dctx->mail; 42 | struct deliver_remove_from_cache_data *data = ti->data; 43 | char *key; 44 | struct cache *cache; 45 | 46 | key = replacestr(&data->key, m->tags, m, &m->rml); 47 | if (key == NULL || *key == '\0') { 48 | log_warnx("%s: empty key", a->name); 49 | goto error; 50 | } 51 | log_debug2("%s: removing from cache %s: %s", a->name, data->path, key); 52 | 53 | TAILQ_FOREACH(cache, &conf.caches, entry) { 54 | if (strcmp(data->path, cache->path) == 0) { 55 | if (open_cache(a, cache) != 0) 56 | goto error; 57 | if (db_contains(cache->db, key) && 58 | db_remove(cache->db, key) != 0) { 59 | log_warnx( 60 | "%s: error removing from cache %s: %s", 61 | a->name, cache->path, key); 62 | goto error; 63 | } 64 | xfree(key); 65 | return (DELIVER_SUCCESS); 66 | } 67 | } 68 | log_warnx("%s: cache %s not declared", a->name, data->path); 69 | 70 | error: 71 | if (key != NULL) 72 | xfree(key); 73 | return (DELIVER_FAILURE); 74 | } 75 | 76 | void 77 | deliver_remove_from_cache_desc(struct actitem *ti, char *buf, size_t len) 78 | { 79 | struct deliver_remove_from_cache_data *data = ti->data; 80 | 81 | xsnprintf(buf, len, 82 | "remove-from-cache \"%s\" key \"%s\"", data->path, data->key.str); 83 | } 84 | -------------------------------------------------------------------------------- /deliver-remove-header.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "deliver.h" 25 | 26 | int deliver_remove_header_deliver(struct deliver_ctx *, struct actitem *); 27 | void deliver_remove_header_desc(struct actitem *, char *, size_t); 28 | 29 | struct deliver deliver_remove_header = { 30 | "remove-header", 31 | DELIVER_INCHILD, 32 | deliver_remove_header_deliver, 33 | deliver_remove_header_desc 34 | }; 35 | 36 | int 37 | deliver_remove_header_deliver(struct deliver_ctx *dctx, struct actitem *ti) 38 | { 39 | struct account *a = dctx->account; 40 | struct mail *m = dctx->mail; 41 | struct deliver_remove_header_data *data = ti->data; 42 | char *ptr, *hdr; 43 | size_t len, off, wrap; 44 | u_int i, j; 45 | 46 | 47 | for (j = 0; j < ARRAY_LENGTH(data->hdrs); j++) { 48 | hdr = replacestr( 49 | &ARRAY_ITEM(data->hdrs, j), m->tags, m, &m->rml); 50 | if (hdr == NULL || *hdr == '\0') { 51 | if (hdr != NULL) 52 | xfree(hdr); 53 | log_warnx("%s: empty header", a->name); 54 | return (DELIVER_FAILURE); 55 | } 56 | log_debug2("%s: removing header: %s", a->name, hdr); 57 | 58 | ARRAY_FREE(&m->wrapped); 59 | m->wrapchar = '\0'; 60 | fill_wrapped(m); 61 | 62 | set_wrapped(m, ' '); 63 | 64 | while ((ptr = match_header(m, hdr, &len, 0)) != NULL) { 65 | log_debug3("%s: found header to remove: %.*s", a->name, 66 | (int) len, ptr); 67 | 68 | /* Remove the header. */ 69 | memmove( 70 | ptr, ptr + len, m->size - len - (ptr - m->data)); 71 | m->size -= len; 72 | m->body -= len; 73 | 74 | /* Fix up the wrapped array. */ 75 | off = ptr - m->data; 76 | i = 0; 77 | while (i < ARRAY_LENGTH(&m->wrapped)) { 78 | wrap = ARRAY_ITEM(&m->wrapped, i); 79 | if (wrap >= off + len) { 80 | ARRAY_SET(&m->wrapped, i, wrap - len); 81 | i++; 82 | } else if (wrap >= off) 83 | ARRAY_REMOVE(&m->wrapped, i); 84 | else 85 | i++; 86 | } 87 | } 88 | } 89 | 90 | /* Invalidate the match data since stuff may have moved. */ 91 | m->rml.valid = 0; 92 | 93 | set_wrapped(m, '\n'); 94 | return (DELIVER_SUCCESS); 95 | } 96 | 97 | void 98 | deliver_remove_header_desc(struct actitem *ti, char *buf, size_t len) 99 | { 100 | struct deliver_remove_header_data *data = ti->data; 101 | char *hdrs; 102 | 103 | hdrs = fmt_replstrs("remove-header ", data->hdrs); 104 | strlcpy(buf, hdrs, len); 105 | xfree(hdrs); 106 | } 107 | -------------------------------------------------------------------------------- /deliver-rewrite.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "fdm.h" 30 | #include "deliver.h" 31 | 32 | int deliver_rewrite_deliver(struct deliver_ctx *, struct actitem *); 33 | void deliver_rewrite_desc(struct actitem *, char *, size_t); 34 | 35 | struct deliver deliver_rewrite = { 36 | "rewrite", 37 | DELIVER_WRBACK, 38 | deliver_rewrite_deliver, 39 | deliver_rewrite_desc 40 | }; 41 | 42 | int 43 | deliver_rewrite_deliver(struct deliver_ctx *dctx, struct actitem *ti) 44 | { 45 | struct account *a = dctx->account; 46 | struct mail *m = dctx->mail; 47 | struct deliver_rewrite_data *data = ti->data; 48 | struct mail *md = &dctx->wr_mail; 49 | char *s, *cause, *out, *err; 50 | int status; 51 | struct cmd *cmd = NULL; 52 | char *lbuf; 53 | size_t llen; 54 | 55 | s = replacepath(&data->cmd, m->tags, m, &m->rml, dctx->udata->home); 56 | if (s == NULL || *s == '\0') { 57 | log_warnx("%s: empty command", a->name); 58 | goto error; 59 | } 60 | 61 | log_debug2("%s: rewriting using \"%s\"", a->name, s); 62 | 63 | md->size = 0; 64 | 65 | cmd = cmd_start(s, CMD_IN|CMD_OUT|CMD_ONCE, m->data, m->size, &cause); 66 | if (cmd == NULL) 67 | goto error_cause; 68 | log_debug3("%s: %s: started", a->name, s); 69 | 70 | llen = IO_LINESIZE; 71 | lbuf = xmalloc(llen); 72 | 73 | do { 74 | status = cmd_poll( 75 | cmd, &out, &err, &lbuf, &llen, conf.timeout, &cause); 76 | if (status == -1) { 77 | xfree(lbuf); 78 | goto error_cause; 79 | } 80 | if (status != 0) 81 | continue; 82 | if (err != NULL) 83 | log_warnx("%s: %s: %s", a->name, s, err); 84 | if (out == NULL) 85 | continue; 86 | log_debug3("%s: %s: out: %s", a->name, s, out); 87 | 88 | if (append_line(md, out, strlen(out)) != 0) { 89 | log_warnx("%s: %s: failed to resize mail", s, a->name); 90 | goto error; 91 | } 92 | if (md->size > conf.max_size) { 93 | log_warnx("%s: %s: oversize mail returned", s, a->name); 94 | goto error; 95 | } 96 | } while (status == 0); 97 | status--; 98 | 99 | xfree(lbuf); 100 | 101 | if (status != 0) { 102 | log_warnx("%s: %s: command returned %d", a->name, s, status); 103 | goto error; 104 | } 105 | 106 | if (md->size == 0) { 107 | log_warnx("%s: %s: empty mail returned", a->name, s); 108 | goto error; 109 | } 110 | md->body = find_body(md); 111 | 112 | cmd_free(cmd); 113 | xfree(s); 114 | return (DELIVER_SUCCESS); 115 | 116 | error_cause: 117 | log_warnx("%s: %s: %s", a->name, s, cause); 118 | xfree(cause); 119 | 120 | error: 121 | if (cmd != NULL) 122 | cmd_free(cmd); 123 | if (s != NULL) 124 | xfree(s); 125 | return (DELIVER_FAILURE); 126 | } 127 | 128 | void 129 | deliver_rewrite_desc(struct actitem *ti, char *buf, size_t len) 130 | { 131 | struct deliver_rewrite_data *data = ti->data; 132 | 133 | xsnprintf(buf, len, "rewrite \"%s\"", data->cmd.str); 134 | } 135 | -------------------------------------------------------------------------------- /deliver-smtp.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "fdm.h" 29 | #include "deliver.h" 30 | 31 | int deliver_smtp_deliver(struct deliver_ctx *, struct actitem *); 32 | void deliver_smtp_desc(struct actitem *, char *, size_t); 33 | 34 | int deliver_smtp_code(char *); 35 | 36 | struct deliver deliver_smtp = { 37 | "smtp", 38 | DELIVER_ASUSER, 39 | deliver_smtp_deliver, 40 | deliver_smtp_desc 41 | }; 42 | 43 | int 44 | deliver_smtp_code(char *line) 45 | { 46 | char ch; 47 | const char *errstr; 48 | int n; 49 | size_t len; 50 | 51 | len = strspn(line, "0123456789"); 52 | if (len == 0) 53 | return (-1); 54 | ch = line[len]; 55 | line[len] = '\0'; 56 | 57 | n = strtonum(line, 100, 999, &errstr); 58 | line[len] = ch; 59 | if (errstr != NULL) 60 | return (-1); 61 | 62 | return (n); 63 | } 64 | 65 | int 66 | deliver_smtp_deliver(struct deliver_ctx *dctx, struct actitem *ti) 67 | { 68 | struct account *a = dctx->account; 69 | struct mail *m = dctx->mail; 70 | struct deliver_smtp_data *data = ti->data; 71 | int done, code; 72 | struct io *io; 73 | char *cause, *to, *from, *line, *ptr, *lbuf; 74 | enum deliver_smtp_state state; 75 | size_t len, llen; 76 | 77 | io = connectproxy(&data->server, 78 | conf.verify_certs, conf.proxy, IO_CRLF, conf.timeout, &cause); 79 | if (io == NULL) { 80 | log_warnx("%s: %s", a->name, cause); 81 | xfree(cause); 82 | return (DELIVER_FAILURE); 83 | } 84 | if (conf.debug > 3 && !conf.syslog) 85 | io->dup_fd = STDOUT_FILENO; 86 | 87 | llen = IO_LINESIZE; 88 | lbuf = xmalloc(llen); 89 | 90 | if (conf.host_fqdn != NULL) 91 | xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_fqdn); 92 | else 93 | xasprintf(&ptr, "%s@%s", dctx->udata->name, conf.host_name); 94 | if (data->to.str == NULL) 95 | to = xstrdup(ptr); 96 | else { 97 | to = replacestr(&data->to, m->tags, m, &m->rml); 98 | if (to == NULL || *to == '\0') { 99 | xasprintf(&cause, "%s: empty to", a->name); 100 | from = NULL; 101 | goto error; 102 | } 103 | } 104 | if (data->from.str == NULL) 105 | from = xstrdup(ptr); 106 | else { 107 | from = replacestr(&data->from, m->tags, m, &m->rml); 108 | if (from == NULL) { 109 | xasprintf(&cause, "%s: empty from", a->name); 110 | goto error; 111 | } 112 | } 113 | xfree(ptr); 114 | 115 | state = SMTP_CONNECTING; 116 | line = NULL; 117 | done = 0; 118 | do { 119 | switch (io_pollline2(io, 120 | &line, &lbuf, &llen, conf.timeout, &cause)) { 121 | case 0: 122 | cause = xstrdup("connection unexpectedly closed"); 123 | goto error; 124 | case -1: 125 | goto error; 126 | } 127 | code = deliver_smtp_code(line); 128 | 129 | cause = NULL; 130 | switch (state) { 131 | case SMTP_CONNECTING: 132 | if (code != 220) 133 | goto error; 134 | state = SMTP_HELO; 135 | if (conf.host_fqdn != NULL) 136 | io_writeline(io, "HELO %s", conf.host_fqdn); 137 | else 138 | io_writeline(io, "HELO %s", conf.host_name); 139 | break; 140 | case SMTP_HELO: 141 | if (code != 250) 142 | goto error; 143 | state = SMTP_FROM; 144 | io_writeline(io, "MAIL FROM:<%s>", from); 145 | break; 146 | case SMTP_FROM: 147 | if (code != 250) 148 | goto error; 149 | state = SMTP_TO; 150 | io_writeline(io, "RCPT TO:<%s>", to); 151 | break; 152 | case SMTP_TO: 153 | if (code != 250) 154 | goto error; 155 | state = SMTP_DATA; 156 | io_writeline(io, "DATA"); 157 | break; 158 | case SMTP_DATA: 159 | if (code != 354) 160 | goto error; 161 | line_init(m, &ptr, &len); 162 | while (ptr != NULL) { 163 | if (len > 1) { 164 | if (*ptr == '.') 165 | io_write(io, ".", 1); 166 | io_write(io, ptr, len - 1); 167 | } 168 | io_writeline(io, NULL); 169 | 170 | /* Update if necessary. */ 171 | if (io_update(io, conf.timeout, &cause) != 1) 172 | goto error; 173 | 174 | line_next(m, &ptr, &len); 175 | } 176 | state = SMTP_DONE; 177 | io_writeline(io, "."); 178 | io_flush(io, conf.timeout, NULL); 179 | break; 180 | case SMTP_DONE: 181 | if (code != 250) 182 | goto error; 183 | state = SMTP_QUIT; 184 | io_writeline(io, "QUIT"); 185 | break; 186 | case SMTP_QUIT: 187 | /* 188 | * Exchange sometimes refuses to accept QUIT as a valid 189 | * command, but since we got a 250 the mail has been 190 | * accepted. So, allow 500 here too. 191 | */ 192 | if (code != 500 && code != 221) 193 | goto error; 194 | done = 1; 195 | break; 196 | } 197 | } while (!done); 198 | 199 | xfree(lbuf); 200 | xfree(from); 201 | xfree(to); 202 | 203 | io_close(io); 204 | io_free(io); 205 | 206 | return (DELIVER_SUCCESS); 207 | 208 | error: 209 | if (cause != NULL) { 210 | log_warnx("%s: %s", a->name, cause); 211 | xfree(cause); 212 | } else 213 | log_warnx("%s: unexpected response: %s", a->name, line); 214 | 215 | io_writeline(io, "QUIT"); 216 | io_flush(io, conf.timeout, NULL); 217 | 218 | xfree(lbuf); 219 | if (from != NULL) 220 | xfree(from); 221 | if (to != NULL) 222 | xfree(to); 223 | 224 | io_close(io); 225 | io_free(io); 226 | 227 | return (DELIVER_FAILURE); 228 | } 229 | 230 | void 231 | deliver_smtp_desc(struct actitem *ti, char *buf, size_t len) 232 | { 233 | struct deliver_smtp_data *data = ti->data; 234 | 235 | xsnprintf(buf, len, "smtp%s server \"%s\" port %s to \"%s\"", 236 | data->server.ssl ? "s" : "", data->server.host, data->server.port, 237 | data->to.str == NULL ? "" : data->to.str); 238 | } 239 | -------------------------------------------------------------------------------- /deliver-stdout.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "fdm.h" 25 | #include "deliver.h" 26 | 27 | int deliver_stdout_deliver(struct deliver_ctx *, struct actitem *); 28 | void deliver_stdout_desc(struct actitem *, char *, size_t); 29 | 30 | struct deliver deliver_stdout = { 31 | "stdout", 32 | DELIVER_INCHILD, 33 | deliver_stdout_deliver, 34 | deliver_stdout_desc 35 | }; 36 | 37 | int 38 | deliver_stdout_deliver(struct deliver_ctx *dctx, unused struct actitem *ti) 39 | { 40 | struct account *a = dctx->account; 41 | struct mail *m = dctx->mail; 42 | 43 | log_debug2("%s: writing to stdout", a->name); 44 | 45 | if (fwrite(m->data, m->size, 1, stdout) != 1) { 46 | log_warn("%s: fwrite", a->name); 47 | return (DELIVER_FAILURE); 48 | } 49 | 50 | fflush(stdout); 51 | return (DELIVER_SUCCESS); 52 | } 53 | 54 | void 55 | deliver_stdout_desc(unused struct actitem *ti, char *buf, size_t len) 56 | { 57 | strlcpy(buf, "stdout", len); 58 | } 59 | -------------------------------------------------------------------------------- /deliver-tag.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "deliver.h" 25 | 26 | int deliver_tag_deliver(struct deliver_ctx *, struct actitem *); 27 | void deliver_tag_desc(struct actitem *, char *, size_t); 28 | 29 | struct deliver deliver_tag = { 30 | "tag", 31 | DELIVER_INCHILD, 32 | deliver_tag_deliver, 33 | deliver_tag_desc 34 | }; 35 | 36 | int 37 | deliver_tag_deliver(struct deliver_ctx *dctx, struct actitem *ti) 38 | { 39 | struct account *a = dctx->account; 40 | struct mail *m = dctx->mail; 41 | struct deliver_tag_data *data = ti->data; 42 | char *tk, *tv; 43 | 44 | tk = replacestr(&data->key, m->tags, m, &m->rml); 45 | if (data->value.str != NULL) 46 | tv = replacestr(&data->value, m->tags, m, &m->rml); 47 | else 48 | tv = xstrdup(""); 49 | 50 | if (tk == NULL || tv == NULL) { 51 | if (tk != NULL) 52 | xfree(tk); 53 | if (tv != NULL) 54 | xfree(tv); 55 | return (DELIVER_SUCCESS); 56 | } 57 | 58 | if (*tk != '\0') { 59 | log_debug2("%s: tagging message: %s (%s)", a->name, tk, tv); 60 | add_tag(&m->tags, tk, "%s", tv); 61 | } 62 | 63 | xfree(tk); 64 | xfree(tv); 65 | 66 | return (DELIVER_SUCCESS); 67 | } 68 | 69 | void 70 | deliver_tag_desc(struct actitem *ti, char *buf, size_t len) 71 | { 72 | struct deliver_tag_data *data = ti->data; 73 | 74 | if (data->value.str == NULL) 75 | xsnprintf(buf, len, "tag \"%s\"", data->key.str); 76 | else { 77 | xsnprintf(buf, len, 78 | "tag \"%s\" value \"%s\"", data->key.str, data->value.str); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /deliver-write.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "fdm.h" 28 | #include "deliver.h" 29 | 30 | int deliver_write_deliver(struct deliver_ctx *, struct actitem *); 31 | void deliver_write_desc(struct actitem *, char *, size_t); 32 | 33 | struct deliver deliver_write = { 34 | "write", 35 | DELIVER_ASUSER, 36 | deliver_write_deliver, 37 | deliver_write_desc 38 | }; 39 | 40 | int 41 | deliver_write_deliver(struct deliver_ctx *dctx, struct actitem *ti) 42 | { 43 | struct account *a = dctx->account; 44 | struct mail *m = dctx->mail; 45 | struct deliver_write_data *data = ti->data; 46 | char *path; 47 | FILE *f; 48 | 49 | path = replacepath(&data->path, m->tags, m, &m->rml, dctx->udata->home); 50 | if (path == NULL || *path == '\0') { 51 | if (path != NULL) 52 | xfree(path); 53 | log_warnx("%s: empty command", a->name); 54 | return (DELIVER_FAILURE); 55 | } 56 | 57 | if (data->append) { 58 | log_debug2("%s: appending to %s", a->name, path); 59 | f = fopen(path, "a"); 60 | } else { 61 | log_debug2("%s: writing to %s", a->name, path); 62 | f = fopen(path, "w"); 63 | } 64 | if (f == NULL) { 65 | log_warn("%s: %s: fopen", a->name, path); 66 | goto error; 67 | } 68 | if (fwrite(m->data, m->size, 1, f) != 1) { 69 | log_warn("%s: %s: fwrite", a->name, path); 70 | goto error; 71 | } 72 | if (fflush(f) != 0) { 73 | log_warn("%s: %s: fflush", a->name, path); 74 | goto error; 75 | } 76 | if (fsync(fileno(f)) != 0) { 77 | log_warn("%s: %s: fsync", a->name, path); 78 | goto error; 79 | } 80 | fclose(f); 81 | 82 | xfree(path); 83 | return (DELIVER_SUCCESS); 84 | 85 | error: 86 | xfree(path); 87 | return (DELIVER_FAILURE); 88 | } 89 | 90 | 91 | void 92 | deliver_write_desc(struct actitem *ti, char *buf, size_t len) 93 | { 94 | struct deliver_write_data *data = ti->data; 95 | 96 | if (data->append) 97 | xsnprintf(buf, len, "append \"%s\"", data->path.str); 98 | else 99 | xsnprintf(buf, len, "write \"%s\"", data->path.str); 100 | } 101 | -------------------------------------------------------------------------------- /deliver.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef DELIVER_H 20 | #define DELIVER_H 21 | 22 | /* Deliver return codes. */ 23 | #define DELIVER_SUCCESS 0 24 | #define DELIVER_FAILURE 1 25 | 26 | /* Deliver context. */ 27 | struct deliver_ctx { 28 | double tim; 29 | 30 | struct action *action; 31 | struct actitem *actitem; 32 | struct rule *rule; 33 | 34 | struct account *account; 35 | struct mail *mail; 36 | 37 | struct userdata *udata; 38 | 39 | struct mail wr_mail; 40 | 41 | TAILQ_ENTRY(deliver_ctx) entry; 42 | }; 43 | 44 | /* Delivery types. */ 45 | enum delivertype { 46 | DELIVER_INCHILD,/* don't pass to parent */ 47 | DELIVER_ASUSER, /* pass to parent to drop privs */ 48 | DELIVER_WRBACK /* modifies mail: pass to parent and receive new mail */ 49 | }; 50 | 51 | /* Deliver functions. */ 52 | struct deliver { 53 | const char *name; 54 | enum delivertype type; 55 | 56 | int (*deliver)(struct deliver_ctx *, struct actitem *); 57 | void (*desc)(struct actitem *, char *, size_t); 58 | }; 59 | 60 | /* Deliver smtp states. */ 61 | enum deliver_smtp_state { 62 | SMTP_CONNECTING, 63 | SMTP_HELO, 64 | SMTP_FROM, 65 | SMTP_TO, 66 | SMTP_DATA, 67 | SMTP_DONE, 68 | SMTP_QUIT 69 | }; 70 | 71 | /* Deliver smtp data. */ 72 | struct deliver_smtp_data { 73 | struct server server; 74 | struct replstr to; 75 | struct replstr from; 76 | }; 77 | 78 | /* Deliver lmtp data */ 79 | struct deliver_lmtp_data { 80 | char *socket; 81 | struct server server; 82 | struct replstr to; 83 | struct replstr from; 84 | }; 85 | 86 | /* Deliver imap data. */ 87 | struct deliver_imap_data { 88 | char *user; 89 | char *pass; 90 | struct server server; 91 | int nocrammd5; 92 | int noplain; 93 | int nologin; 94 | int oauthbearer; 95 | int xoauth2; 96 | int starttls; 97 | 98 | struct replstr folder; 99 | }; 100 | 101 | /* Deliver mbox data. */ 102 | struct deliver_mbox_data { 103 | struct replpath path; 104 | int compress; 105 | }; 106 | 107 | /* Deliver add-header data. */ 108 | struct deliver_add_header_data { 109 | struct replstr hdr; 110 | struct replstr value; 111 | }; 112 | 113 | /* Deliver remove-header data. */ 114 | struct deliver_remove_header_data { 115 | struct replstrs *hdrs; 116 | }; 117 | 118 | /* Deliver write data. */ 119 | struct deliver_write_data { 120 | struct replpath path; 121 | int append; 122 | }; 123 | 124 | /* Deliver maildir data. */ 125 | struct deliver_maildir_data { 126 | struct replpath path; 127 | }; 128 | 129 | /* Deliver rewrite data. */ 130 | struct deliver_rewrite_data { 131 | struct replpath cmd; 132 | }; 133 | 134 | /* Deliver pipe data. */ 135 | struct deliver_pipe_data { 136 | struct replpath cmd; 137 | int pipe; 138 | }; 139 | 140 | /* Deliver tag data. */ 141 | struct deliver_tag_data { 142 | struct replstr key; 143 | struct replstr value; 144 | }; 145 | 146 | /* Deliver action data. */ 147 | struct deliver_action_data { 148 | struct replstrs *actions; 149 | }; 150 | 151 | /* Deliver add-to-cache data. */ 152 | struct deliver_add_to_cache_data { 153 | char *path; 154 | struct replstr key; 155 | }; 156 | 157 | /* Deliver remove-from-cache data. */ 158 | struct deliver_remove_from_cache_data { 159 | char *path; 160 | struct replstr key; 161 | }; 162 | 163 | /* deliver-smtp.c */ 164 | extern struct deliver deliver_smtp; 165 | 166 | /* deliver-lmtp.c */ 167 | extern struct deliver deliver_lmtp; 168 | 169 | /* deliver-imap.c */ 170 | extern struct deliver deliver_imap; 171 | 172 | /* deliver-stdout.c */ 173 | extern struct deliver deliver_stdout; 174 | 175 | /* deliver-tag.c */ 176 | extern struct deliver deliver_tag; 177 | 178 | /* deliver-pipe.c */ 179 | extern struct deliver deliver_pipe; 180 | 181 | /* deliver-drop.c */ 182 | extern struct deliver deliver_drop; 183 | 184 | /* deliver-keep.c */ 185 | extern struct deliver deliver_keep; 186 | 187 | /* deliver-maildir.c */ 188 | extern struct deliver deliver_maildir; 189 | 190 | /* deliver-remove-header.c */ 191 | extern struct deliver deliver_remove_header; 192 | 193 | /* deliver-add-header.c */ 194 | extern struct deliver deliver_add_header; 195 | 196 | /* deliver-mbox.c */ 197 | extern struct deliver deliver_mbox; 198 | 199 | /* deliver-write.c */ 200 | extern struct deliver deliver_write; 201 | 202 | /* deliver-rewrite.c */ 203 | extern struct deliver deliver_rewrite; 204 | 205 | /* deliver-add-to-cache.c */ 206 | extern struct deliver deliver_add_to_cache; 207 | 208 | /* deliver-remove-from-cache.c */ 209 | extern struct deliver deliver_remove_from_cache; 210 | 211 | #endif 212 | -------------------------------------------------------------------------------- /examples/example_imap_folder.conf: -------------------------------------------------------------------------------- 1 | # Example synchronizing Imap folders to maildir 2 | 3 | # An action to save to the maildir ~/mail/inbox. 4 | $path = "%h/mail" 5 | action "inbox" maildir "${path}" 6 | action "sent" maildir "${path}/sent" 7 | action "junk" maildir "${path}/junk" 8 | 9 | # Accounts: POP3, POP3S and IMAP. Note the double escaping of the '\' 10 | # character in the password. If the port is omitted, the default 11 | # ("pop3", "pop3s", "imap" or "imaps" in the services(5) db) is used. 12 | account "imaps" imaps 13 | server "" 14 | user "" 15 | pass "" 16 | folders { "INBOX" "INBOX.Sent" "INBOX.Junk" } 17 | 18 | # Match folders to correct maildirs 19 | # The order of the matching is important since "match string "%[folder]" to "INBOX" " also triggers for "INBOX.Sent" or "INBOX.Junk" 20 | match string "%[folder]" to "INBOX.Sent" action "sent" 21 | match string "%[folder]" to "INBOX.Junk" action "junk" 22 | match string "%[folder]" to "INBOX" action "inbox" 23 | 24 | # Match all other mail and deliver using the 'inbox' action. 25 | match all action "inbox" 26 | -------------------------------------------------------------------------------- /examples/g-lando.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicm/fdm/0918b78a82a789d63cebe44b7662f0a8dc603000/examples/g-lando.conf -------------------------------------------------------------------------------- /examples/t-ulmer.conf: -------------------------------------------------------------------------------- 1 | account "tmux" imaps server "host" user "tobiasu" pass "password" 2 | account "spam-box" maildir "%h/mail/.spam.train" 3 | 4 | # Actions 5 | action "inbox" maildir "%h/mail" 6 | action "friends" maildir "%h/mail/.friends" 7 | action "tendra-dev" maildir "%h/mail/.tendra-dev" 8 | action "edri" maildir "%h/mail/.edri" 9 | action "fitug" maildir "%h/mail/.fitug" 10 | action "nanog" maildir "%h/mail/.nanog" 11 | action "cryptogram" maildir "%h/mail/.cryptogram" 12 | action "bibliothek" maildir "%h/mail/.bibliothek" 13 | action "arcor" maildir "%h/mail/.arcor" 14 | 15 | action "obsd-advocacy" maildir "%h/mail/.openbsd.advocacy" 16 | action "obsd-alpha" maildir "%h/mail/.openbsd.alpha" 17 | action "obsd-arm" maildir "%h/mail/.openbsd.arm" 18 | action "obsd-bugs" maildir "%h/mail/.openbsd.bugs" 19 | action "obsd-hppa" maildir "%h/mail/.openbsd.hppa" 20 | action "obsd-ipv6" maildir "%h/mail/.openbsd.ipv6" 21 | action "obsd-mac68k" maildir "%h/mail/.openbsd.mac68k" 22 | action "obsd-misc" maildir "%h/mail/.openbsd.misc" 23 | action "obsd-ports" maildir "%h/mail/.openbsd.ports" 24 | action "obsd-ports-changes" maildir "%h/mail/.openbsd.ports-changes" 25 | action "obsd-ppc" maildir "%h/mail/.openbsd.ppc" 26 | action "obsd-source-changes" maildir "%h/mail/.openbsd.source-changes" 27 | action "obsd-sparc" maildir "%h/mail/.openbsd.sparc" 28 | action "obsd-tech" maildir "%h/mail/.openbsd.tech" 29 | action "obsd-vax" maildir "%h/mail/.openbsd.vax" 30 | action "obsd-www" maildir "%h/mail/.openbsd.www" 31 | action "obsd-x11" maildir "%h/mail/.openbsd.x11" 32 | 33 | action "sec-bugtraq" maildir "%h/mail/.security.bugtraq" 34 | action "sec-fd" maildir "%h/mail/.security.full-disclosure" 35 | action "sec-secunia" maildir "%h/mail/.security.secunia" 36 | 37 | action "suck-wmii" maildir "%h/mail/.suckless.wmii" 38 | action "suck-dwm" maildir "%h/mail/.suckless.dwm" 39 | 40 | action "spam-new" maildir "%h/mail/.spam.new" 41 | action "spam-train" maildir "%h/mail/.spam.train" 42 | action "spam-archive" mbox "%h/mail/archive/trained-spam" 43 | 44 | action "drop" drop 45 | action "bf-unreg-nospam" rewrite "bogofilter -e -p -N" 46 | action "bf-reg-spam" rewrite "bogofilter -e -p -s" 47 | action "bf-update" rewrite "bogofilter -e -p -u" 48 | action "strip-bullshit" rewrite "reformail -IX-HE-Virus-Scanned: -IX-HE-Spam-Level: -IX-HE-Spam-Score: -IX-HE-Spam-Report: -IX-Antivirus-Scanner: -IX-AntiAbuse: -IX-Spam: -IX-SPAM-FLAG: -IX-Virus-Scanned: -IX-ELNK-Trace: -IX-Converted-To-Plain-Text: -IX-Priority: -IX-Greylist: -IX-OriginalArrivalTime: -IX-Sun-Charset: -IX-MSMail-Priority: -IImportance: -IX-MimeOLE: -IPriority:" 49 | action "strip-fd" rewrite "sed 's/^\\(Subject:.*\\)\\[Full-disclosure\\] /\\1/'" 50 | 51 | # spam-box rules 52 | match account "spam-box" { 53 | match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" 54 | match "^X-MySecretSpamHeader: No" in headers action "bf-unreg-nospam" continue 55 | 56 | match all action "bf-reg-spam" continue 57 | match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" 58 | match all action "bf-reg-spam" continue 59 | match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" 60 | match all action "bf-reg-spam" continue 61 | match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" 62 | match all action "bf-reg-spam" continue 63 | match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" 64 | match all action "bf-reg-spam" continue 65 | match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" 66 | match all action "bf-reg-spam" continue 67 | 68 | # ok, we've tried 5 times, just put the thing into the spam archive 69 | match all action "spam-archive" 70 | } 71 | 72 | # tmux rules 73 | match all action "strip-bullshit" continue 74 | match all action "bf-update" continue 75 | match "^X-MySecretSpamHeader: Yes" in headers action "spam-new" 76 | 77 | match "^sender: owner.*@openbsd\\.org" in headers { 78 | match "^sender:.*advocacy" in headers action "obsd-advocacy" 79 | match "^sender:.*alpha" in headers action "obsd-alpha" 80 | match "^sender:.*arm" in headers action "obsd-arm" 81 | match "^sender:.*bugs" in headers action "obsd-bugs" 82 | match "^sender:.*hppa" in headers action "obsd-hppa" 83 | match "^sender:.*ipv6" in headers action "obsd-ipv6" 84 | match "^sender:.*mac68k" in headers action "obsd-mac68k" 85 | match "^sender:.*misc" in headers action "obsd-misc" 86 | match "^sender:.*ports-changes" in headers action "obsd-ports-changes" # first! 87 | match "^sender:.*ports" in headers action "obsd-ports" 88 | match "^sender:.*ppc" in headers action "obsd-ppc" 89 | match "^sender:.*source-changes" in headers action "obsd-source-changes" 90 | match "^sender:.*sparc" in headers action "obsd-sparc" 91 | match "^sender:.*tech" in headers action "obsd-tech" 92 | match "^sender:.*vax" in headers action "obsd-vax" 93 | match "^sender:.*www" in headers action "obsd-www" 94 | match "^sender:.*x11" in headers action "obsd-x11" 95 | } 96 | 97 | match "^from: secunia security advisories " in headers 100 | or "^list-id: " in headers { 101 | 102 | match "^subject:.*\\[full-disclosure\\]" in headers action "strip-fd" continue 103 | 104 | match "^subject: \\[ glsa" in headers action "drop" 105 | match "^subject: \\[usn-" in headers action "drop" 106 | match "^subject: \\[ mdksa" in headers action "drop" 107 | match "^subject: \\[security\\] \\[dsa" in headers action "drop" 108 | match "^from:.*announce-noreply@rpath\\.com" in headers action "drop" 109 | 110 | match "^list-post: " in headers action "sec-fd" 111 | match "^list-id: " in headers action "sec-bugtraq" 112 | } 113 | 114 | match "^list-id: wmii community " in headers action "fitug" 122 | 123 | match "^list-id: edri-news\\.mailman\\.edri\\.org" in headers action "edri" 124 | 125 | match "^To: CRYPTO-GRAM-LIST@LISTSERV\\.MODWEST\\.COM" in headers action "cryptogram" 126 | 127 | match "^From: L-Service@bsz-bw\\.de" in headers action "bibliothek" 128 | 129 | match "^from:.*rechnung\\.arcor\\.de" in headers action "arcor" 130 | 131 | match "^from:.*friend1@googlemail\\.com" in headers 132 | or "^from:.*friend2@yahoo\\.de" in headers 133 | # ... 134 | action "friends" 135 | 136 | match "^sender: tendra-dev-bounces@lists\\.tendra\\.org" in headers 137 | action "tendra-dev" 138 | 139 | match all action "inbox" 140 | -------------------------------------------------------------------------------- /fdm-sanitize: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | # 3 | # $Id$ 4 | # 5 | # Copyright (c) 2006 Nicholas Marriott 6 | # 7 | # Permission to use, copy, modify, and distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 16 | # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 17 | # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | # 20 | # If the output of fdm -vvvv is piped to this script, it will remove usernames 21 | # and passwords from IMAP/POP3 output, for example: 22 | # 23 | # fdm -vvvv f 2>&1|fdm-sanitize|tee saved-output 24 | # 25 | 26 | BEGIN { 27 | imap_user = 0; 28 | imap_pass = 0; 29 | } 30 | 31 | /> [0-9]+ LOGIN \{[0-9]+\}/ { 32 | imap_user = 1; 33 | print ($1 " " $2 " " $3 " {*}"); 34 | fflush(); 35 | next; 36 | } 37 | 38 | /> .+ ?\{[0-9]+\}/ { 39 | if (imap_user) { 40 | print ("> * {*}"); 41 | fflush(); 42 | imap_user = 0; 43 | imap_pass = 1; 44 | next; 45 | } 46 | print ($0); 47 | fflush(); 48 | next; 49 | } 50 | 51 | /> APOP .+/ { 52 | print ("> APOP * *"); 53 | fflush(); 54 | next; 55 | } 56 | 57 | /> USER .+/ { 58 | print ("> USER *"); 59 | fflush(); 60 | next; 61 | } 62 | 63 | /> PASS .+/ { 64 | print ("> PASS *"); 65 | fflush(); 66 | next; 67 | } 68 | 69 | /> .+/ { 70 | if (imap_pass) { 71 | print ("> *"); 72 | fflush(); 73 | imap_pass = 0; 74 | next; 75 | } 76 | print ($0); 77 | fflush(); 78 | next; 79 | } 80 | 81 | /.*/ { 82 | print ($0); 83 | fflush(); 84 | } 85 | -------------------------------------------------------------------------------- /fdm.1: -------------------------------------------------------------------------------- 1 | .\" $Id$ 2 | .\" 3 | .\" Copyright (c) 2006 Nicholas Marriott 4 | .\" 5 | .\" Permission to use, copy, modify, and distribute this software for any 6 | .\" purpose with or without fee is hereby granted, provided that the above 7 | .\" copyright notice and this permission notice appear in all copies. 8 | .\" 9 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | .\" WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 14 | .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 15 | .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | .\" 17 | .Dd December 22, 2008 18 | .Dt FDM 1 19 | .Os 20 | .Sh NAME 21 | .Nm fdm 22 | .Nd "fetch and deliver mail" 23 | .Sh SYNOPSIS 24 | .Nm fdm 25 | .Bk -words 26 | .Op Fl hklmnqv 27 | .Op Fl a Ar account 28 | .Op Fl D Ar name Ns = Ns Ar value 29 | .Op Fl f Ar conffile 30 | .Op Fl u Ar user 31 | .Op Fl x Ar account 32 | .Op Cm fetch | poll | cache 33 | .Ek 34 | .Sh DESCRIPTION 35 | The 36 | .Nm 37 | program fetches mail from a POP3 or IMAP server or from 38 | .Dv stdin 39 | and delivers it based on a ruleset in the configuration file. 40 | .Pp 41 | The options are as follows: 42 | .Bl -tag -width Ds 43 | .It Fl a Ar name 44 | Process only the specified account. 45 | This option may appear multiple times. 46 | The account name may include shell glob characters to match multiple accounts. 47 | .It Fl D Ar name Ns = Ns Ar value 48 | This option defines a macro for use when parsing the configuration file. 49 | The macro name must be prefixed with 50 | .Li $ 51 | or 52 | .Li % 53 | to specify a string or numeric macro. 54 | This option may appear multiple times. 55 | .It Fl f Ar conffile 56 | Specify the configuration file location. 57 | Default is 58 | .Pa ~/.fdm.conf , 59 | or 60 | .Pa /etc/fdm.conf 61 | if that doesn't exist. 62 | .It Fl h 63 | Look at the 64 | .Ev HOME 65 | environment variable to ascertain the user's home directory. 66 | .It Fl k 67 | Keep all mail after delivery, regardless of whether it matches a 68 | .Ic drop 69 | action. 70 | Note that mails kept in this way will be refetched by 71 | .Nm 72 | if it is run again on the same account. 73 | .It Fl l 74 | Log using 75 | .Xr syslog 3 76 | rather than to 77 | .Dv stderr . 78 | .It Fl m 79 | Ignore the lock file and run regardless of other instances of 80 | .Nm . 81 | .It Fl n 82 | Do not process any accounts, just verify the configuration file syntax and exit. 83 | .It Fl q 84 | Quiet mode. Only print errors. 85 | .It Fl u Ar user 86 | Specify the default user for delivery. 87 | This overrides the 88 | .Ic default-user 89 | option in the configuration file. 90 | .It Fl v 91 | Request verbose logging. 92 | This option may be specified multiple times. 93 | .Fl vv 94 | will print information on configuration (useful with 95 | .Fl n ) . 96 | .Fl vvvv 97 | duplicates all traffic to and from remote servers to 98 | .Dv stdout . 99 | This feature is disabled when using the 100 | .Fl l 101 | flag. 102 | .It Fl x Ar name 103 | Exclude the named account. 104 | Multiple 105 | .Fl x 106 | options may be specified. 107 | As with 108 | .Fl a , 109 | shell glob characters may be used. 110 | .It Cm fetch | poll | cache 111 | The 112 | .Cm fetch 113 | command instructs 114 | .Nm 115 | to fetch and deliver messages. 116 | The 117 | .Cm poll 118 | command polls the accounts in the configuration file and reports a message 119 | count for each. 120 | .Cm cache 121 | allows 122 | .Nm 123 | cache files to be manipulated: see the next section. 124 | .El 125 | .Sh CACHE COMMANDS 126 | The following cache manipulation commands are supported: 127 | .Bl -tag -width Ds 128 | .It Ic cache Ic add Ar path Ar string 129 | .It Ic cache Ic remove Ar path Ar string 130 | Add or remove 131 | .Ar string 132 | as a key in the cache at 133 | .Ar path . 134 | .It Ic cache Ic list Op Ar path 135 | List the number of keys in the specified cache, or if 136 | .Ar path 137 | is omitted, in all caches declared in the configuration file. 138 | .It Ic cache Ic dump Ar path 139 | Dump the contents of the cache 140 | .Ar path 141 | to 142 | .Dv stdout . 143 | Each key is printed followed by a space and the timestamp as Unix time. 144 | .It Ic cache Ic clear Ar path 145 | Delete all keys from the cache at 146 | .Ar path . 147 | .El 148 | .Sh FILES 149 | .Bl -tag -width Ds -compact 150 | .It Pa ~/.fdm.conf 151 | default 152 | .Nm 153 | configuration file 154 | .It Pa /etc/fdm.conf 155 | default system-wide configuration file 156 | .It Pa ~/.fdm.lock 157 | default lock file 158 | .It Pa /var/db/fdm.lock 159 | lock file for root user 160 | .El 161 | .Sh SEE ALSO 162 | .Xr mail 1 , 163 | .Xr fdm.conf 5 , 164 | .Xr sendmail 8 165 | .Sh AUTHORS 166 | .An Nicholas Marriott Aq Mt nicholas.marriott@gmail.com 167 | -------------------------------------------------------------------------------- /fetch-imap.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "fetch.h" 25 | 26 | void fetch_imap_fill(struct account *, struct iolist *); 27 | void fetch_imap_desc(struct account *, char *, size_t); 28 | 29 | int fetch_imap_connect(struct account *); 30 | void fetch_imap_disconnect(struct account *); 31 | 32 | struct fetch fetch_imap = { 33 | "imap", 34 | fetch_imap_state_init, 35 | 36 | fetch_imap_fill, 37 | imap_commit, /* from imap-common.c */ 38 | imap_abort, /* from imap-common.c */ 39 | imap_total, /* from imap-common.c */ 40 | fetch_imap_desc 41 | }; 42 | 43 | /* Write line to server. */ 44 | int 45 | fetch_imap_putln(struct account *a, const char *fmt, va_list ap) 46 | { 47 | struct fetch_imap_data *data = a->data; 48 | 49 | io_vwriteline(data->io, fmt, ap); 50 | 51 | return (0); 52 | } 53 | 54 | /* Write buffer to server. */ 55 | int 56 | fetch_imap_putn(struct account *a, const char *buf, size_t len) 57 | { 58 | struct fetch_imap_data *data = a->data; 59 | 60 | io_write(data->io, buf, len); 61 | 62 | return (0); 63 | } 64 | 65 | /* Get line from server. */ 66 | int 67 | fetch_imap_getln(struct account *a, struct fetch_ctx *fctx, char **line) 68 | { 69 | struct fetch_imap_data *data = a->data; 70 | 71 | *line = io_readline2(data->io, &fctx->lbuf, &fctx->llen); 72 | return (0); 73 | } 74 | 75 | /* Fill io list. */ 76 | void 77 | fetch_imap_fill(struct account *a, struct iolist *iol) 78 | { 79 | struct fetch_imap_data *data = a->data; 80 | 81 | ARRAY_ADD(iol, data->io); 82 | } 83 | 84 | /* Connect to server. */ 85 | int 86 | fetch_imap_connect(struct account *a) 87 | { 88 | struct fetch_imap_data *data = a->data; 89 | char *cause; 90 | 91 | data->io = connectproxy(&data->server, 92 | conf.verify_certs, conf.proxy, IO_CRLF, conf.timeout, &cause); 93 | if (data->io == NULL) { 94 | log_warnx("%s: %s", a->name, cause); 95 | xfree(cause); 96 | return (-1); 97 | } 98 | if (conf.debug > 3 && !conf.syslog) 99 | data->io->dup_fd = STDOUT_FILENO; 100 | 101 | return (0); 102 | } 103 | 104 | /* Close connection. */ 105 | void 106 | fetch_imap_disconnect(struct account *a) 107 | { 108 | struct fetch_imap_data *data = a->data; 109 | 110 | if (data->io != NULL) { 111 | io_close(data->io); 112 | io_free(data->io); 113 | data->io = NULL; 114 | } 115 | } 116 | 117 | /* IMAP initial state. */ 118 | int 119 | fetch_imap_state_init(struct account *a, struct fetch_ctx *fctx) 120 | { 121 | struct fetch_imap_data *data = a->data; 122 | 123 | data->connect = fetch_imap_connect; 124 | data->getln = fetch_imap_getln; 125 | data->putln = fetch_imap_putln; 126 | data->putn = fetch_imap_putn; 127 | data->disconnect = fetch_imap_disconnect; 128 | 129 | data->src = data->server.host; 130 | 131 | return (imap_state_init(a, fctx)); 132 | } 133 | 134 | void 135 | fetch_imap_desc(struct account *a, char *buf, size_t len) 136 | { 137 | struct fetch_imap_data *data = a->data; 138 | char *folders; 139 | 140 | folders = fmt_strings("folders ", data->folders); 141 | xsnprintf(buf, len, 142 | "imap%s server \"%s\" port %s user \"%s\" %s", 143 | data->server.ssl ? "s" : "", data->server.host, data->server.port, 144 | data->user, folders); 145 | xfree(folders); 146 | } 147 | -------------------------------------------------------------------------------- /fetch-imappipe.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "fdm.h" 25 | #include "fetch.h" 26 | 27 | void fetch_imappipe_fill(struct account *, struct iolist *); 28 | void fetch_imappipe_desc(struct account *, char *, size_t); 29 | 30 | int fetch_imappipe_connect(struct account *); 31 | void fetch_imappipe_disconnect(struct account *); 32 | int fetch_imappipe_putln(struct account *, const char *, va_list); 33 | int fetch_imappipe_getln(struct account *, struct fetch_ctx *, char **); 34 | 35 | int fetch_imappipe_state_init(struct account *, struct fetch_ctx *); 36 | 37 | struct fetch fetch_imappipe = { 38 | "imap", 39 | fetch_imappipe_state_init, 40 | 41 | fetch_imappipe_fill, 42 | imap_commit, /* from imap-common.c */ 43 | imap_abort, /* from imap-common.c */ 44 | imap_total, /* from imap-common.c */ 45 | fetch_imappipe_desc 46 | }; 47 | 48 | /* Write line to server. */ 49 | int 50 | fetch_imappipe_putln(struct account *a, const char *fmt, va_list ap) 51 | { 52 | struct fetch_imap_data *data = a->data; 53 | 54 | if (data->cmd->io_in == NULL) { 55 | log_warnx("%s: %s", a->name, strerror(EPIPE)); 56 | return (-1); 57 | } 58 | 59 | io_vwriteline(data->cmd->io_in, fmt, ap); 60 | return (0); 61 | } 62 | 63 | /* Write buffer to server. */ 64 | int 65 | fetch_imappipe_putn(struct account *a, const char *buf, size_t len) 66 | { 67 | struct fetch_imap_data *data = a->data; 68 | 69 | if (data->cmd->io_in == NULL) { 70 | log_warnx("%s: %s", a->name, strerror(EPIPE)); 71 | return (-1); 72 | } 73 | 74 | io_write(data->cmd->io_in, buf, len); 75 | return (0); 76 | } 77 | 78 | /* Get line from server. */ 79 | int 80 | fetch_imappipe_getln(struct account *a, struct fetch_ctx *fctx, char **line) 81 | { 82 | struct fetch_imap_data *data = a->data; 83 | char *out, *err, *cause; 84 | 85 | switch (cmd_poll( 86 | data->cmd, &out, &err, &fctx->lbuf, &fctx->llen, 0, &cause)) { 87 | case 0: 88 | break; 89 | case -1: 90 | log_warnx("%s: %s", a->name, cause); 91 | xfree(cause); 92 | return (-1); 93 | default: 94 | log_warnx("%s: connection unexpectedly closed", a->name); 95 | return (-1); 96 | } 97 | 98 | if (err != NULL) 99 | log_warnx("%s: %s: %s", a->name, data->pipecmd, err); 100 | *line = out; 101 | return (0); 102 | } 103 | 104 | /* Fill io list. */ 105 | void 106 | fetch_imappipe_fill(struct account *a, struct iolist *iol) 107 | { 108 | struct fetch_imap_data *data = a->data; 109 | 110 | if (data->cmd->io_in != NULL) 111 | ARRAY_ADD(iol, data->cmd->io_in); 112 | if (data->cmd->io_out != NULL) 113 | ARRAY_ADD(iol, data->cmd->io_out); 114 | if (data->cmd->io_err != NULL) 115 | ARRAY_ADD(iol, data->cmd->io_err); 116 | } 117 | 118 | /* Connect to server. */ 119 | int 120 | fetch_imappipe_connect(struct account *a) 121 | { 122 | struct fetch_imap_data *data = a->data; 123 | char *cause; 124 | 125 | data->cmd = cmd_start(data->pipecmd, CMD_IN|CMD_OUT, NULL, 0, &cause); 126 | if (data->cmd == NULL) { 127 | log_warnx("%s: %s", a->name, cause); 128 | xfree(cause); 129 | return (-1); 130 | } 131 | if (conf.debug > 3 && !conf.syslog) { 132 | data->cmd->io_in->dup_fd = STDOUT_FILENO; 133 | data->cmd->io_out->dup_fd = STDOUT_FILENO; 134 | } 135 | 136 | return (0); 137 | } 138 | 139 | /* Close connection. */ 140 | void 141 | fetch_imappipe_disconnect(struct account *a) 142 | { 143 | struct fetch_imap_data *data = a->data; 144 | 145 | if (data->cmd != NULL) 146 | cmd_free(data->cmd); 147 | } 148 | 149 | /* IMAP over pipe initial state. */ 150 | int 151 | fetch_imappipe_state_init(struct account *a, struct fetch_ctx *fctx) 152 | { 153 | struct fetch_imap_data *data = a->data; 154 | 155 | data->connect = fetch_imappipe_connect; 156 | data->getln = fetch_imappipe_getln; 157 | data->putln = fetch_imappipe_putln; 158 | data->putn = fetch_imappipe_putn; 159 | data->disconnect = fetch_imappipe_disconnect; 160 | 161 | data->src = NULL; 162 | 163 | return (imap_state_init(a, fctx)); 164 | } 165 | 166 | void 167 | fetch_imappipe_desc(struct account *a, char *buf, size_t len) 168 | { 169 | struct fetch_imap_data *data = a->data; 170 | char *folders; 171 | 172 | folders = fmt_strings("folders ", data->folders); 173 | if (data->user == NULL) { 174 | xsnprintf(buf, len, "imap pipe \"%s\" %s", 175 | data->pipecmd, folders); 176 | } else { 177 | xsnprintf(buf, len, "imap pipe \"%s\" user \"%s\" %s", 178 | data->pipecmd, data->user, folders); 179 | } 180 | xfree(folders); 181 | } 182 | -------------------------------------------------------------------------------- /fetch-pop3.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "fetch.h" 25 | 26 | void fetch_pop3_fill(struct account *, struct iolist *); 27 | void fetch_pop3_desc(struct account *, char *, size_t); 28 | 29 | int fetch_pop3_connect(struct account *); 30 | void fetch_pop3_disconnect(struct account *); 31 | int fetch_pop3_putln(struct account *, const char *, va_list); 32 | int fetch_pop3_getln(struct account *, struct fetch_ctx *, char **); 33 | 34 | int fetch_pop3_state_init(struct account *, struct fetch_ctx *); 35 | 36 | struct fetch fetch_pop3 = { 37 | "pop3", 38 | fetch_pop3_state_init, 39 | 40 | fetch_pop3_fill, 41 | pop3_commit, /* from pop3-common.c */ 42 | pop3_abort, /* from pop3-common.c */ 43 | pop3_total, /* from pop3-common.c */ 44 | fetch_pop3_desc 45 | }; 46 | 47 | /* Write line to server. */ 48 | int 49 | fetch_pop3_putln(struct account *a, const char *fmt, va_list ap) 50 | { 51 | struct fetch_pop3_data *data = a->data; 52 | 53 | io_vwriteline(data->io, fmt, ap); 54 | 55 | return (0); 56 | } 57 | 58 | /* Get line from server. */ 59 | int 60 | fetch_pop3_getln(struct account *a, struct fetch_ctx *fctx, char **line) 61 | { 62 | struct fetch_pop3_data *data = a->data; 63 | 64 | *line = io_readline2(data->io, &fctx->lbuf, &fctx->llen); 65 | return (0); 66 | } 67 | 68 | /* Fill io list. */ 69 | void 70 | fetch_pop3_fill(struct account *a, struct iolist *iol) 71 | { 72 | struct fetch_pop3_data *data = a->data; 73 | 74 | ARRAY_ADD(iol, data->io); 75 | } 76 | 77 | /* Connect to server. */ 78 | int 79 | fetch_pop3_connect(struct account *a) 80 | { 81 | struct fetch_pop3_data *data = a->data; 82 | char *cause; 83 | 84 | data->io = connectproxy(&data->server, 85 | conf.verify_certs, conf.proxy, IO_CRLF, conf.timeout, &cause); 86 | if (data->io == NULL) { 87 | log_warnx("%s: %s", a->name, cause); 88 | xfree(cause); 89 | return (-1); 90 | } 91 | if (conf.debug > 3 && !conf.syslog) 92 | data->io->dup_fd = STDOUT_FILENO; 93 | 94 | return (0); 95 | } 96 | 97 | /* Close connection. */ 98 | void 99 | fetch_pop3_disconnect(struct account *a) 100 | { 101 | struct fetch_pop3_data *data = a->data; 102 | 103 | if (data->io != NULL) { 104 | io_close(data->io); 105 | io_free(data->io); 106 | data->io = NULL; 107 | } 108 | } 109 | 110 | /* Initial POP3 state. */ 111 | int 112 | fetch_pop3_state_init(struct account *a, struct fetch_ctx *fctx) 113 | { 114 | struct fetch_pop3_data *data = a->data; 115 | 116 | data->connect = fetch_pop3_connect; 117 | data->getln = fetch_pop3_getln; 118 | data->putln = fetch_pop3_putln; 119 | data->disconnect = fetch_pop3_disconnect; 120 | 121 | data->src = data->server.host; 122 | 123 | return (pop3_state_init(a, fctx)); 124 | } 125 | 126 | void 127 | fetch_pop3_desc(struct account *a, char *buf, size_t len) 128 | { 129 | struct fetch_pop3_data *data = a->data; 130 | 131 | xsnprintf(buf, len, "pop3%s server \"%s\" port %s user \"%s\"", 132 | data->server.ssl ? "s" : "", data->server.host, data->server.port, 133 | data->user); 134 | } 135 | -------------------------------------------------------------------------------- /fetch-pop3pipe.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "fdm.h" 25 | #include "fetch.h" 26 | 27 | void fetch_pop3pipe_fill(struct account *, struct iolist *); 28 | void fetch_pop3pipe_desc(struct account *, char *, size_t); 29 | 30 | int fetch_pop3pipe_connect(struct account *); 31 | void fetch_pop3pipe_disconnect(struct account *); 32 | int fetch_pop3pipe_putln(struct account *, const char *, va_list); 33 | int fetch_pop3pipe_getln(struct account *, struct fetch_ctx *, char **); 34 | 35 | int fetch_pop3pipe_state_init(struct account *, struct fetch_ctx *); 36 | 37 | struct fetch fetch_pop3pipe = { 38 | "pop3", 39 | fetch_pop3pipe_state_init, 40 | 41 | fetch_pop3pipe_fill, 42 | pop3_commit, /* from pop3-common.c */ 43 | pop3_abort, /* from pop3-common.c */ 44 | pop3_total, /* from pop3-common.c */ 45 | fetch_pop3pipe_desc 46 | }; 47 | 48 | /* Write line to server. */ 49 | int 50 | fetch_pop3pipe_putln(struct account *a, const char *fmt, va_list ap) 51 | { 52 | struct fetch_pop3_data *data = a->data; 53 | 54 | if (data->cmd->io_in == NULL) { 55 | log_warnx("%s: %s", a->name, strerror(EPIPE)); 56 | return (-1); 57 | } 58 | 59 | io_vwriteline(data->cmd->io_in, fmt, ap); 60 | return (0); 61 | } 62 | 63 | /* Get line from server. */ 64 | int 65 | fetch_pop3pipe_getln(struct account *a, struct fetch_ctx *fctx, char **line) 66 | { 67 | struct fetch_pop3_data *data = a->data; 68 | char *out, *err, *cause; 69 | 70 | switch (cmd_poll( 71 | data->cmd, &out, &err, &fctx->lbuf, &fctx->llen, 0, &cause)) { 72 | case 0: 73 | break; 74 | case -1: 75 | log_warnx("%s: %s", a->name, cause); 76 | xfree(cause); 77 | return (-1); 78 | default: 79 | log_warnx("%s: connection unexpectedly closed", a->name); 80 | return (-1); 81 | } 82 | 83 | if (err != NULL) 84 | log_warnx("%s: %s: %s", a->name, data->pipecmd, err); 85 | *line = out; 86 | return (0); 87 | } 88 | 89 | /* Fill io list. */ 90 | void 91 | fetch_pop3pipe_fill(struct account *a, struct iolist *iol) 92 | { 93 | struct fetch_pop3_data *data = a->data; 94 | 95 | if (data->cmd->io_in != NULL) 96 | ARRAY_ADD(iol, data->cmd->io_in); 97 | if (data->cmd->io_out != NULL) 98 | ARRAY_ADD(iol, data->cmd->io_out); 99 | if (data->cmd->io_err != NULL) 100 | ARRAY_ADD(iol, data->cmd->io_err); 101 | } 102 | 103 | /* Connect to server. */ 104 | int 105 | fetch_pop3pipe_connect(struct account *a) 106 | { 107 | struct fetch_pop3_data *data = a->data; 108 | char *cause; 109 | 110 | data->cmd = cmd_start(data->pipecmd, CMD_IN|CMD_OUT, NULL, 0, &cause); 111 | if (data->cmd == NULL) { 112 | log_warnx("%s: %s", a->name, cause); 113 | xfree(cause); 114 | return (-1); 115 | } 116 | if (conf.debug > 3 && !conf.syslog) { 117 | data->cmd->io_in->dup_fd = STDOUT_FILENO; 118 | data->cmd->io_out->dup_fd = STDOUT_FILENO; 119 | } 120 | 121 | return (0); 122 | } 123 | 124 | /* Close connection. */ 125 | void 126 | fetch_pop3pipe_disconnect(struct account *a) 127 | { 128 | struct fetch_pop3_data *data = a->data; 129 | 130 | if (data->cmd != NULL) 131 | cmd_free(data->cmd); 132 | } 133 | 134 | /* POP3 over pipe initial state. */ 135 | int 136 | fetch_pop3pipe_state_init(struct account *a, struct fetch_ctx *fctx) 137 | { 138 | struct fetch_pop3_data *data = a->data; 139 | 140 | data->connect = fetch_pop3pipe_connect; 141 | data->getln = fetch_pop3pipe_getln; 142 | data->putln = fetch_pop3pipe_putln; 143 | data->disconnect = fetch_pop3pipe_disconnect; 144 | 145 | data->src = NULL; 146 | 147 | return (pop3_state_init(a, fctx)); 148 | } 149 | 150 | void 151 | fetch_pop3pipe_desc(struct account *a, char *buf, size_t len) 152 | { 153 | struct fetch_pop3_data *data = a->data; 154 | 155 | if (data->user == NULL) 156 | xsnprintf(buf, len, "pop3 pipe \"%s\"", data->pipecmd); 157 | else { 158 | xsnprintf(buf, len, 159 | "pop3 pipe \"%s\" user \"%s\"", data->pipecmd, data->user); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /fetch-stdin.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "fdm.h" 29 | #include "fetch.h" 30 | 31 | void fetch_stdin_abort(struct account *); 32 | u_int fetch_stdin_total(struct account *); 33 | void fetch_stdin_desc(struct account *, char *, size_t); 34 | 35 | int fetch_stdin_state_init(struct account *, struct fetch_ctx *); 36 | int fetch_stdin_state_mail(struct account *, struct fetch_ctx *); 37 | int fetch_stdin_state_exit(struct account *, struct fetch_ctx *); 38 | 39 | struct fetch fetch_stdin = { 40 | "stdin", 41 | fetch_stdin_state_init, 42 | 43 | NULL, 44 | NULL, 45 | fetch_stdin_abort, 46 | NULL, 47 | fetch_stdin_desc 48 | }; 49 | 50 | /* Abort; close stdin. */ 51 | void 52 | fetch_stdin_abort(unused struct account *a) 53 | { 54 | close(STDIN_FILENO); 55 | } 56 | 57 | /* Initialise stdin fetch. */ 58 | int 59 | fetch_stdin_state_init(struct account *a, struct fetch_ctx *fctx) 60 | { 61 | /* Check stdin is valid. */ 62 | if (isatty(STDIN_FILENO)) { 63 | log_warnx("%s: stdin is a tty. ignoring", a->name); 64 | return (FETCH_ERROR); 65 | } 66 | if (fcntl(STDIN_FILENO, F_GETFL) == -1) { 67 | if (errno != EBADF) 68 | fatal("fcntl failed"); 69 | log_warnx("%s: stdin is invalid", a->name); 70 | return (FETCH_ERROR); 71 | } 72 | 73 | fctx->state = fetch_stdin_state_mail; 74 | return (FETCH_AGAIN); 75 | } 76 | 77 | /* Fetch mail from stdin. */ 78 | int 79 | fetch_stdin_state_mail(struct account *a, struct fetch_ctx *fctx) 80 | { 81 | struct mail *m = fctx->mail; 82 | struct io *io; 83 | char *line, *cause; 84 | 85 | /* Open io for stdin. */ 86 | io = io_create(STDIN_FILENO, NULL, IO_LF); 87 | if (conf.debug > 3 && !conf.syslog) 88 | io->dup_fd = STDOUT_FILENO; 89 | 90 | /* Initialise the mail. */ 91 | if (mail_open(m, IO_BLOCKSIZE) != 0) { 92 | log_warn("%s: failed to create mail", a->name); 93 | goto error; 94 | } 95 | m->size = 0; 96 | 97 | /* Add default tags. */ 98 | default_tags(&m->tags, NULL); 99 | 100 | /* Loop reading the mail. */ 101 | for (;;) { 102 | /* 103 | * There can only be one mail on stdin so reentrancy is 104 | * irrelevent. This is a good thing since we want to check for 105 | * close which means end of mail. 106 | */ 107 | switch (io_pollline2(io, 108 | &line, &fctx->lbuf, &fctx->llen, conf.timeout, &cause)) { 109 | case 0: 110 | /* Normal close is fine. */ 111 | goto out; 112 | case -1: 113 | if (errno == EAGAIN) 114 | continue; 115 | log_warnx("%s: %s", a->name, cause); 116 | xfree(cause); 117 | goto error; 118 | } 119 | 120 | if (append_line(m, line, strlen(line)) != 0) { 121 | log_warn("%s: failed to resize mail", a->name); 122 | goto error; 123 | } 124 | if (m->size > conf.max_size) 125 | break; 126 | } 127 | 128 | out: 129 | if (io != NULL) 130 | io_free(io); 131 | 132 | fctx->state = fetch_stdin_state_exit; 133 | return (FETCH_MAIL); 134 | 135 | 136 | error: 137 | if (io != NULL) 138 | io_free(io); 139 | 140 | return (FETCH_ERROR); 141 | } 142 | 143 | /* Fetch finished; return exit. */ 144 | int 145 | fetch_stdin_state_exit(unused struct account *a, unused struct fetch_ctx *fctx) 146 | { 147 | close(STDIN_FILENO); 148 | return (FETCH_EXIT); 149 | } 150 | 151 | void 152 | fetch_stdin_desc(unused struct account *a, char *buf, size_t len) 153 | { 154 | strlcpy(buf, "stdin", len); 155 | } 156 | -------------------------------------------------------------------------------- /io.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef IO_H 20 | #define IO_H 21 | 22 | /* Buffer macros. */ 23 | #define BUFFER_USED(b) ((b)->size) 24 | #define BUFFER_FREE(b) ((b)->space - (b)->off - (b)->size) 25 | #define BUFFER_IN(b) ((b)->base + (b)->off + (b)->size) 26 | #define BUFFER_OUT(b) ((b)->base + (b)->off) 27 | 28 | /* Buffer structure. */ 29 | struct buffer { 30 | u_char *base; /* buffer start */ 31 | size_t space; /* total size of buffer */ 32 | 33 | size_t size; /* size of data in buffer */ 34 | size_t off; /* offset of data in buffer */ 35 | }; 36 | 37 | /* Limits at which to fail. */ 38 | #define IO_MAXLINELEN (16 * 1024 * 1024) /* 16 MB */ 39 | 40 | /* IO line endings. */ 41 | #define IO_CRLF "\r\n" 42 | #define IO_CR "\r" 43 | #define IO_LF "\n" 44 | 45 | /* Initial block size of buffer and minimum amount to try to read. */ 46 | #define IO_BLOCKSIZE 16384 47 | #define IO_WATERMARK 12288 48 | 49 | /* Initial line buffer length. */ 50 | #define IO_LINESIZE 256 51 | 52 | /* Amount to poll after in io_update. */ 53 | #define IO_FLUSHSIZE (2 * IO_BLOCKSIZE) 54 | 55 | /* IO macros. */ 56 | #define IO_ROUND(n) (((n / IO_BLOCKSIZE) + 1) * IO_BLOCKSIZE) 57 | #define IO_CLOSED(io) ((io)->flags & IOF_CLOSED) 58 | #define IO_ERROR(io) ((io)->error) 59 | #define IO_RDSIZE(io) (BUFFER_USED((io)->rd)) 60 | #define IO_WRSIZE(io) (BUFFER_USED((io)->wr)) 61 | 62 | /* IO structure. */ 63 | struct io { 64 | int fd; 65 | int dup_fd; /* duplicate all data to this fd */ 66 | SSL *ssl; 67 | 68 | char *error; 69 | 70 | int flags; 71 | #define IOF_NEEDFILL 0x1 72 | #define IOF_NEEDPUSH 0x2 73 | #define IOF_CLOSED 0x4 74 | #define IOF_MUSTWR 0x8 75 | 76 | struct buffer *rd; 77 | struct buffer *wr; 78 | 79 | char *lbuf; /* line buffer */ 80 | size_t llen; /* line buffer size */ 81 | 82 | const char *eol; 83 | }; 84 | 85 | /* List of ios. */ 86 | ARRAY_DECL(iolist, struct io *); 87 | 88 | /* buffer.c */ 89 | struct buffer *buffer_create(size_t); 90 | void buffer_destroy(struct buffer *); 91 | void buffer_clear(struct buffer *); 92 | void buffer_ensure(struct buffer *, size_t); 93 | void buffer_add(struct buffer *, size_t); 94 | void buffer_reverse_add(struct buffer *, size_t); 95 | void buffer_remove(struct buffer *, size_t); 96 | void buffer_reverse_remove(struct buffer *, size_t); 97 | void buffer_insert_range(struct buffer *, size_t, size_t); 98 | void buffer_delete_range(struct buffer *, size_t, size_t); 99 | void buffer_write(struct buffer *, const void *, size_t); 100 | void buffer_read(struct buffer *, void *, size_t); 101 | void buffer_write8(struct buffer *, uint8_t); 102 | void buffer_write16(struct buffer *, uint16_t); 103 | uint8_t buffer_read8(struct buffer *); 104 | uint16_t buffer_read16(struct buffer *); 105 | 106 | /* io.c */ 107 | struct io *io_create(int, SSL *, const char *); 108 | void io_readonly(struct io *); 109 | void io_writeonly(struct io *); 110 | void io_free(struct io *); 111 | void io_close(struct io *); 112 | int io_polln(struct io **, u_int, struct io **, int, char **); 113 | int io_poll(struct io *, int, char **); 114 | int io_read2(struct io *, void *, size_t); 115 | void *io_read(struct io *, size_t); 116 | void io_write(struct io *, const void *, size_t); 117 | char *io_readline2(struct io *, char **, size_t *); 118 | char *io_readline(struct io *); 119 | void printflike2 io_writeline(struct io *, const char *, ...); 120 | void io_vwriteline(struct io *, const char *, va_list); 121 | int io_pollline2(struct io *, char **, char **, size_t *, int, 122 | char **); 123 | int io_pollline(struct io *, char **, int, char **); 124 | int io_flush(struct io *, int, char **); 125 | int io_wait(struct io *, size_t, int, char **); 126 | int io_update(struct io *, int, char **); 127 | 128 | #endif /* IO_H */ 129 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "fdm.h" 28 | 29 | /* Logging type. */ 30 | #define LOG_TYPE_OFF 0 31 | #define LOG_TYPE_SYSLOG 1 32 | #define LOG_TYPE_TTY 2 33 | #define LOG_TYPE_FILE 3 34 | int log_type = LOG_TYPE_OFF; 35 | 36 | /* Log file, if needed. */ 37 | FILE *log_file; 38 | 39 | /* Debug level. */ 40 | int log_level; 41 | 42 | /* Open logging to syslog. */ 43 | void 44 | log_open_syslog(int level) 45 | { 46 | log_type = LOG_TYPE_SYSLOG; 47 | log_level = level; 48 | 49 | openlog(__progname, LOG_PID|LOG_NDELAY, LOG_FACILITY); 50 | 51 | tzset(); 52 | } 53 | 54 | /* Open logging to tty. */ 55 | void 56 | log_open_tty(int level) 57 | { 58 | log_type = LOG_TYPE_TTY; 59 | log_level = level; 60 | 61 | setlinebuf(stderr); 62 | setlinebuf(stdout); 63 | 64 | tzset(); 65 | } 66 | 67 | /* Open logging to tty. */ 68 | void 69 | log_open_file(int level, const char *path) 70 | { 71 | log_file = fopen(path, "w"); 72 | if (log_file == NULL) 73 | return; 74 | 75 | log_type = LOG_TYPE_FILE; 76 | log_level = level; 77 | 78 | setlinebuf(log_file); 79 | 80 | tzset(); 81 | } 82 | 83 | /* Close logging. */ 84 | void 85 | log_close(void) 86 | { 87 | if (log_type == LOG_TYPE_FILE) 88 | fclose(log_file); 89 | 90 | log_type = LOG_TYPE_OFF; 91 | } 92 | 93 | /* Write a log message. */ 94 | void 95 | log_write(int pri, const char *msg, ...) 96 | { 97 | va_list ap; 98 | 99 | va_start(ap, msg); 100 | log_vwrite(pri, msg, ap); 101 | va_end(ap); 102 | } 103 | 104 | /* Write a log message. */ 105 | void 106 | log_vwrite(int pri, const char *msg, va_list ap) 107 | { 108 | char *fmt; 109 | FILE *f = log_file; 110 | 111 | switch (log_type) { 112 | case LOG_TYPE_SYSLOG: 113 | vsyslog(pri, msg, ap); 114 | break; 115 | case LOG_TYPE_TTY: 116 | if (pri == LOG_INFO) 117 | f = stdout; 118 | else 119 | f = stderr; 120 | /* FALLTHROUGH */ 121 | case LOG_TYPE_FILE: 122 | if (asprintf(&fmt, "%s\n", msg) == -1) 123 | exit(1); 124 | if (vfprintf(f, fmt, ap) == -1) 125 | exit(1); 126 | fflush(f); 127 | free(fmt); 128 | break; 129 | } 130 | } 131 | 132 | /* Log a warning with error string. */ 133 | void printflike1 134 | log_warn(const char *msg, ...) 135 | { 136 | va_list ap; 137 | char *fmt; 138 | 139 | va_start(ap, msg); 140 | if (asprintf(&fmt, "%s: %s", msg, strerror(errno)) == -1) 141 | exit(1); 142 | log_vwrite(LOG_CRIT, fmt, ap); 143 | free(fmt); 144 | va_end(ap); 145 | } 146 | 147 | /* Log a warning. */ 148 | void printflike1 149 | log_warnx(const char *msg, ...) 150 | { 151 | va_list ap; 152 | 153 | va_start(ap, msg); 154 | log_vwrite(LOG_CRIT, msg, ap); 155 | va_end(ap); 156 | } 157 | 158 | /* Log an informational message. */ 159 | void printflike1 160 | log_info(const char *msg, ...) 161 | { 162 | va_list ap; 163 | 164 | if (log_level > -1) { 165 | va_start(ap, msg); 166 | log_vwrite(LOG_INFO, msg, ap); 167 | va_end(ap); 168 | } 169 | } 170 | 171 | /* Log a debug message. */ 172 | void printflike1 173 | log_debug(const char *msg, ...) 174 | { 175 | va_list ap; 176 | 177 | if (log_level > 0) { 178 | va_start(ap, msg); 179 | log_vwrite(LOG_DEBUG, msg, ap); 180 | va_end(ap); 181 | } 182 | } 183 | 184 | /* Log a debug message at level 2. */ 185 | void printflike1 186 | log_debug2(const char *msg, ...) 187 | { 188 | va_list ap; 189 | 190 | if (log_level > 1) { 191 | va_start(ap, msg); 192 | log_vwrite(LOG_DEBUG, msg, ap); 193 | va_end(ap); 194 | } 195 | } 196 | 197 | /* Log a debug message at level 3. */ 198 | void printflike1 199 | log_debug3(const char *msg, ...) 200 | { 201 | va_list ap; 202 | 203 | if (log_level > 2) { 204 | va_start(ap, msg); 205 | log_vwrite(LOG_DEBUG, msg, ap); 206 | va_end(ap); 207 | } 208 | } 209 | 210 | /* Log a critical error, with error string if necessary, and die. */ 211 | __dead void 212 | log_vfatal(const char *msg, va_list ap) 213 | { 214 | char *fmt; 215 | 216 | if (errno != 0) { 217 | if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1) 218 | exit(1); 219 | log_vwrite(LOG_CRIT, fmt, ap); 220 | } else { 221 | if (asprintf(&fmt, "fatal: %s", msg) == -1) 222 | exit(1); 223 | log_vwrite(LOG_CRIT, fmt, ap); 224 | } 225 | free(fmt); 226 | 227 | exit(1); 228 | } 229 | 230 | /* Log a critical error, with error string, and die. */ 231 | __dead void printflike1 232 | log_fatal(const char *msg, ...) 233 | { 234 | va_list ap; 235 | 236 | va_start(ap, msg); 237 | log_vfatal(msg, ap); 238 | } 239 | 240 | /* Log a critical error and die. */ 241 | __dead void printflike1 242 | log_fatalx(const char *msg, ...) 243 | { 244 | va_list ap; 245 | 246 | errno = 0; 247 | va_start(ap, msg); 248 | log_vfatal(msg, ap); 249 | } 250 | -------------------------------------------------------------------------------- /lookup-passwd.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2008 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "fdm.h" 25 | 26 | struct userdata * 27 | passwd_lookup(const char *user) 28 | { 29 | struct passwd *pw; 30 | struct userdata *ud; 31 | uid_t uid; 32 | const char *errstr; 33 | 34 | if ((pw = getpwnam(user)) == NULL) { 35 | endpwent(); 36 | uid = strtonum(user, 0, UID_MAX, &errstr); 37 | if (errstr != NULL) 38 | return (NULL); 39 | if ((pw = getpwuid(uid)) == NULL) { 40 | endpwent(); 41 | return (NULL); 42 | } 43 | } 44 | 45 | ud = xmalloc(sizeof *ud); 46 | 47 | ud->name = xstrdup(pw->pw_name); 48 | if (pw->pw_uid == getuid()) 49 | ud->home = xstrdup(conf.user_home); 50 | else 51 | ud->home = xstrdup(pw->pw_dir); 52 | 53 | ud->uid = pw->pw_uid; 54 | ud->gid = pw->pw_gid; 55 | 56 | endpwent(); 57 | return (ud); 58 | } 59 | -------------------------------------------------------------------------------- /lookup.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2008 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | 25 | struct userdata * 26 | user_lookup(const char *user, struct userfunctions *order) 27 | { 28 | struct userdata *ud; 29 | u_int i; 30 | 31 | if (user == NULL) 32 | return (NULL); 33 | for (i = 0; i < ARRAY_LENGTH(order); i++) { 34 | if ((ud = ARRAY_ITEM(order, i)(user)) != NULL) 35 | return (ud); 36 | } 37 | return (NULL); 38 | } 39 | 40 | void 41 | user_free(struct userdata *ud) 42 | { 43 | xfree(ud->name); 44 | xfree(ud->home); 45 | xfree(ud); 46 | } 47 | 48 | struct userdata * 49 | user_copy(struct userdata *ud) 50 | { 51 | struct userdata *ue; 52 | 53 | ue = xmalloc(sizeof *ue); 54 | ue->uid = ud->uid; 55 | ue->gid = ud->gid; 56 | ue->name = xstrdup(ud->name); 57 | ue->home = xstrdup(ud->home); 58 | 59 | return (ue); 60 | } 61 | -------------------------------------------------------------------------------- /mail-time.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "fdm.h" 27 | 28 | int tzlookup(const char *, int *); 29 | 30 | char * 31 | rfc822time(time_t t, char *buf, size_t len) 32 | { 33 | struct tm *tm; 34 | size_t n; 35 | 36 | tm = localtime(&t); 37 | if ((n = strftime(buf, len, "%a, %d %b %Y %H:%M:%S %z", tm)) == 0) 38 | return (NULL); 39 | if (n == len) 40 | return (NULL); 41 | return (buf); 42 | } 43 | 44 | /* 45 | * Some mailers, notably AOL's, use the timezone string instead of an offset 46 | * from UTC. A limited set of these are permitted by RFC822, but it is still 47 | * highly annoying: others can appear, and since there are duplicate 48 | * abbreviations it cannot be converted with absolute certainty. As it is only 49 | * a few clients do this anyway, don't even try particularly hard, just try to 50 | * look it up using tzset, which catches the few most common abbreviations. 51 | */ 52 | int 53 | tzlookup(const char *tz, int *off) 54 | { 55 | char *saved_tz; 56 | struct tm *tm; 57 | time_t t; 58 | 59 | saved_tz = getenv("TZ"); 60 | if (saved_tz != NULL) 61 | saved_tz = xstrdup(saved_tz); 62 | 63 | /* Set the new timezone. */ 64 | if (setenv("TZ", tz, 1) != 0) 65 | goto error; 66 | tzset(); 67 | 68 | /* Get the time at epoch + one year. */ 69 | t = TIME_YEAR; 70 | tm = localtime(&t); 71 | 72 | /* And work out the timezone. */ 73 | if (strcmp(tz, tm->tm_zone) != 0) 74 | goto error; 75 | *off = tm->tm_gmtoff; 76 | 77 | /* Restore the old timezone. */ 78 | if (saved_tz != NULL) { 79 | if (setenv("TZ", saved_tz, 1) != 0) 80 | goto error; 81 | xfree(saved_tz); 82 | } else 83 | unsetenv("TZ"); 84 | tzset(); 85 | 86 | return (0); 87 | 88 | error: 89 | if (saved_tz != NULL) 90 | xfree(saved_tz); 91 | return (-1); 92 | } 93 | 94 | int 95 | mailtime(struct mail *m, time_t *tim) 96 | { 97 | char *s, *ptr, *endptr, *hdr; 98 | const char *errstr; 99 | size_t len; 100 | struct tm tm; 101 | int tz; 102 | 103 | hdr = find_header(m, "date", &len, 1); 104 | if (hdr == NULL || len == 0) 105 | return (-1); 106 | /* Make a copy of the header. */ 107 | s = xmalloc(len + 1); 108 | strlcpy(s, hdr, len + 1); 109 | 110 | /* Skip spaces. */ 111 | ptr = s; 112 | while (*ptr != '\0' && isspace((u_char) *ptr)) 113 | ptr++; 114 | 115 | /* Parse the date. */ 116 | memset(&tm, 0, sizeof tm); 117 | endptr = strptime(ptr, "%a, %d %b %Y %H:%M:%S", &tm); 118 | if (endptr == NULL) 119 | endptr = strptime(ptr, "%d %b %Y %H:%M:%S", &tm); 120 | if (endptr == NULL) 121 | goto invalid; 122 | *tim = mktime(&tm); 123 | 124 | /* Skip spaces. */ 125 | while (*endptr != '\0' && isspace((u_char) *endptr)) 126 | endptr++; 127 | 128 | /* Terminate the timezone. */ 129 | ptr = endptr; 130 | while (*ptr != '\0' && !isspace((u_char) *ptr)) 131 | ptr++; 132 | *ptr = '\0'; 133 | 134 | tz = strtonum(endptr, -2359, 2359, &errstr); 135 | if (errstr != NULL) { 136 | /* Try it using tzset. */ 137 | if (tzlookup(endptr, &tz) != 0) 138 | goto invalid; 139 | } 140 | *tim -= (tz / 100) * TIME_HOUR + (tz % 100) * TIME_MINUTE; 141 | if (*tim < 0) 142 | goto invalid; 143 | 144 | xfree(s); 145 | return (0); 146 | 147 | invalid: 148 | xfree(s); 149 | return (-1); 150 | } 151 | -------------------------------------------------------------------------------- /match-account.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "fdm.h" 25 | #include "match.h" 26 | 27 | int match_account_match(struct mail_ctx *, struct expritem *); 28 | void match_account_desc(struct expritem *, char *, size_t); 29 | 30 | struct match match_account = { 31 | "account", 32 | match_account_match, 33 | match_account_desc 34 | }; 35 | 36 | int 37 | match_account_match(struct mail_ctx *mctx, struct expritem *ei) 38 | { 39 | struct match_account_data *data = ei->data; 40 | struct account *a = mctx->account; 41 | struct mail *m = mctx->mail; 42 | char *s; 43 | u_int i; 44 | 45 | for (i = 0; i < ARRAY_LENGTH(data->accounts); i++) { 46 | s = replacestr( 47 | &ARRAY_ITEM(data->accounts, i), m->tags, m, &m->rml); 48 | if (s == NULL || *s == '\0') { 49 | if (s != NULL) 50 | xfree(s); 51 | log_warnx("%s: empty account", a->name); 52 | return (MATCH_ERROR); 53 | } 54 | if (account_match(s, a->name)) { 55 | xfree(s); 56 | return (MATCH_TRUE); 57 | } 58 | xfree(s); 59 | } 60 | 61 | return (MATCH_FALSE); 62 | } 63 | 64 | void 65 | match_account_desc(struct expritem *ei, char *buf, size_t len) 66 | { 67 | struct match_account_data *data = ei->data; 68 | char *accounts; 69 | 70 | accounts = fmt_replstrs("account ", data->accounts); 71 | strlcpy(buf, accounts, len); 72 | xfree(accounts); 73 | } 74 | -------------------------------------------------------------------------------- /match-age.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "fdm.h" 25 | #include "match.h" 26 | 27 | int match_age_match(struct mail_ctx *, struct expritem *); 28 | void match_age_desc(struct expritem *, char *, size_t); 29 | 30 | struct match match_age = { 31 | "age", 32 | match_age_match, 33 | match_age_desc 34 | }; 35 | 36 | int 37 | match_age_match(struct mail_ctx *mctx, struct expritem *ei) 38 | { 39 | struct match_age_data *data = ei->data; 40 | struct account *a = mctx->account; 41 | struct mail *m = mctx->mail; 42 | time_t then, now; 43 | long long diff; 44 | 45 | /* Get current and mail time. */ 46 | now = time(NULL); 47 | if (mailtime(m, &then) != 0) { 48 | /* Invalid, so return true if testing validity, else false. */ 49 | if (data->time < 0) 50 | return (MATCH_TRUE); 51 | return (MATCH_FALSE); 52 | } 53 | /* Not invalid, so return false if validity is being tested for. */ 54 | if (data->time < 0) 55 | return (MATCH_FALSE); 56 | 57 | /* Work out the time difference. */ 58 | diff = difftime(now, then); 59 | log_debug2("%s: time difference is %lld (now %lld, then %lld)", a->name, 60 | diff, (long long) now, (long long) then); 61 | if (diff < 0) { 62 | /* Reset all ages in the future to zero. */ 63 | diff = 0; 64 | } 65 | 66 | if (data->cmp == CMP_LT && diff < data->time) 67 | return (MATCH_TRUE); 68 | else if (data->cmp == CMP_GT && diff > data->time) 69 | return (MATCH_TRUE); 70 | return (MATCH_FALSE); 71 | } 72 | 73 | void 74 | match_age_desc(struct expritem *ei, char *buf, size_t len) 75 | { 76 | struct match_age_data *data = ei->data; 77 | const char *cmp = ""; 78 | 79 | if (data->time < 0) { 80 | strlcpy(buf, "age invalid", len); 81 | return; 82 | } 83 | 84 | if (data->cmp == CMP_LT) 85 | cmp = "<"; 86 | else if (data->cmp == CMP_GT) 87 | cmp = ">"; 88 | xsnprintf(buf, len, "age %s %lld seconds", cmp, data->time); 89 | } 90 | -------------------------------------------------------------------------------- /match-all.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "match.h" 25 | 26 | int match_all_match(struct mail_ctx *, struct expritem *); 27 | void match_all_desc(struct expritem *, char *, size_t); 28 | 29 | struct match match_all = { 30 | "all", 31 | match_all_match, 32 | match_all_desc 33 | }; 34 | 35 | int 36 | match_all_match(unused struct mail_ctx *mctx, unused struct expritem *ei) 37 | { 38 | return (MATCH_TRUE); 39 | } 40 | 41 | void 42 | match_all_desc(unused struct expritem *ei, char *buf, size_t len) 43 | { 44 | strlcpy(buf, "all", len); 45 | } 46 | -------------------------------------------------------------------------------- /match-attachment.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "match.h" 25 | 26 | int match_attachment_match(struct mail_ctx *, struct expritem *); 27 | void match_attachment_desc(struct expritem *, char *, size_t); 28 | 29 | struct match match_attachment = { 30 | "attachment", 31 | match_attachment_match, 32 | match_attachment_desc 33 | }; 34 | 35 | int 36 | match_attachment_match(struct mail_ctx *mctx, struct expritem *ei) 37 | { 38 | struct match_attachment_data *data = ei->data; 39 | struct account *a = mctx->account; 40 | struct mail *m = mctx->mail; 41 | struct attach *at; 42 | size_t size; 43 | u_int n; 44 | char *value = NULL; 45 | 46 | if (!m->attach_built) { 47 | /* Fill attachments. */ 48 | m->attach = attach_build(m); 49 | if (m->attach != NULL) 50 | attach_log(m->attach, "%s: attachment", a->name); 51 | else 52 | log_debug3("%s: no attachments", a->name); 53 | m->attach_built = 1; 54 | } 55 | 56 | if (data->op == ATTACHOP_COUNT || data->op == ATTACHOP_TOTALSIZE) { 57 | size = 0; 58 | n = 0; 59 | at = m->attach; 60 | while (at != NULL) { 61 | size += at->size; 62 | n++; 63 | 64 | at = attach_visit(at, NULL); 65 | } 66 | switch (data->op) { 67 | case ATTACHOP_COUNT: 68 | switch (data->cmp) { 69 | case CMP_EQ: 70 | if (n == data->value.num) 71 | return (MATCH_TRUE); 72 | return (MATCH_FALSE); 73 | case CMP_NE: 74 | if (n != data->value.num) 75 | return (MATCH_TRUE); 76 | return (MATCH_FALSE); 77 | case CMP_LT: 78 | if (n < data->value.num) 79 | return (MATCH_TRUE); 80 | return (MATCH_FALSE); 81 | case CMP_GT: 82 | if (n > data->value.num) 83 | return (MATCH_TRUE); 84 | return (MATCH_FALSE); 85 | default: 86 | return (MATCH_ERROR); 87 | } 88 | case ATTACHOP_TOTALSIZE: 89 | switch (data->cmp) { 90 | case CMP_LT: 91 | if (size < data->value.size) 92 | return (MATCH_TRUE); 93 | return (MATCH_FALSE); 94 | case CMP_GT: 95 | if (size > data->value.size) 96 | return (MATCH_TRUE); 97 | return (MATCH_FALSE); 98 | default: 99 | return (MATCH_ERROR); 100 | } 101 | default: 102 | return (MATCH_ERROR); 103 | } 104 | } 105 | 106 | /* If no attachments, none of the following conditions are true. */ 107 | if (m->attach == NULL) 108 | return (MATCH_FALSE); 109 | 110 | /* For any type or name matches, construct the value. */ 111 | if (data->op == ATTACHOP_ANYTYPE || data->op == ATTACHOP_ANYNAME) 112 | value = replacestr(&data->value.str, m->tags, m, &m->rml); 113 | 114 | at = m->attach; 115 | while (at != NULL) { 116 | switch (data->op) { 117 | case ATTACHOP_ANYSIZE: 118 | switch (data->cmp) { 119 | case CMP_LT: 120 | if (at->size < data->value.size) 121 | return (MATCH_TRUE); 122 | break; 123 | case CMP_GT: 124 | if (at->size > data->value.size) 125 | return (MATCH_TRUE); 126 | break; 127 | default: 128 | return (MATCH_ERROR); 129 | } 130 | break; 131 | case ATTACHOP_ANYTYPE: 132 | if (at->type == NULL) 133 | break; 134 | 135 | if (fnmatch(value, at->type, FNM_CASEFOLD) == 0) { 136 | xfree(value); 137 | return (MATCH_TRUE); 138 | } 139 | break; 140 | case ATTACHOP_ANYNAME: 141 | if (at->name == NULL) 142 | break; 143 | 144 | if (fnmatch(value, at->name, FNM_CASEFOLD) == 0) { 145 | xfree(value); 146 | return (MATCH_TRUE); 147 | } 148 | break; 149 | default: 150 | return (MATCH_ERROR); 151 | } 152 | 153 | at = attach_visit(at, NULL); 154 | } 155 | 156 | if (value != NULL) 157 | xfree(value); 158 | return (MATCH_FALSE); 159 | } 160 | 161 | void 162 | match_attachment_desc(struct expritem *ei, char *buf, size_t len) 163 | { 164 | struct match_attachment_data *data = ei->data; 165 | const char *cmp = ""; 166 | 167 | if (data->cmp == CMP_LT) 168 | cmp = "<"; 169 | else if (data->cmp == CMP_GT) 170 | cmp = ">"; 171 | else if (data->cmp == CMP_EQ) 172 | cmp = "=="; 173 | else if (data->cmp == CMP_NE) 174 | cmp = "!="; 175 | 176 | switch (data->op) { 177 | case ATTACHOP_COUNT: 178 | xsnprintf(buf, len, 179 | "attachment count %s %lld", cmp, data->value.num); 180 | break; 181 | case ATTACHOP_TOTALSIZE: 182 | xsnprintf(buf, len, 183 | "attachment total-size %s %lld", cmp, data->value.num); 184 | break; 185 | case ATTACHOP_ANYSIZE: 186 | xsnprintf(buf, len, 187 | "attachment any-size %s %lld", cmp, data->value.num); 188 | break; 189 | case ATTACHOP_ANYTYPE: 190 | xsnprintf(buf, len, 191 | "attachment any-type \"%s\"", data->value.str.str); 192 | break; 193 | case ATTACHOP_ANYNAME: 194 | xsnprintf(buf, len, 195 | "attachment any-name \"%s\"", data->value.str.str); 196 | break; 197 | default: 198 | if (len > 0) 199 | *buf = '\0'; 200 | break; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /match-command.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "match.h" 25 | 26 | int match_command_match(struct mail_ctx *, struct expritem *); 27 | void match_command_desc(struct expritem *, char *, size_t); 28 | 29 | struct match match_command = { 30 | "command", 31 | match_command_match, 32 | match_command_desc 33 | }; 34 | 35 | int 36 | match_command_match(struct mail_ctx *mctx, struct expritem *ei) 37 | { 38 | struct match_command_data *data = ei->data; 39 | struct account *a = mctx->account; 40 | struct mail *m = mctx->mail; 41 | struct io *io = mctx->io; 42 | struct msg msg; 43 | struct msgbuf msgbuf; 44 | struct userdata *ud; 45 | char *user; 46 | 47 | set_wrapped(m, '\n'); 48 | 49 | /* 50 | * We are called as the child so to change uid this needs to be done 51 | * largely in the parent. 52 | */ 53 | memset(&msg, 0, sizeof msg); 54 | msg.type = MSG_COMMAND; 55 | msg.id = m->idx; 56 | 57 | msg.data.account = a; 58 | msg.data.cmddata = data; 59 | 60 | user = conf.cmd_user; 61 | if (data->user.str != NULL) 62 | user = replacestr(&data->user, m->tags, m, &m->rml); 63 | if ((ud = user_lookup(user, conf.user_order)) == NULL) { 64 | log_warnx("%s: bad user: %s", a->name, user); 65 | return (MATCH_ERROR); 66 | } 67 | if (data->user.str != NULL) 68 | xfree(user); 69 | 70 | msg.data.uid = ud->uid; 71 | msg.data.gid = ud->gid; 72 | update_tags(&m->tags, ud); 73 | user_free(ud); 74 | 75 | msgbuf.buf = m->tags; 76 | msgbuf.len = STRB_SIZE(m->tags); 77 | 78 | mail_send(m, &msg); 79 | 80 | if (privsep_send(io, &msg, &msgbuf) != 0) 81 | fatalx("privsep_send error"); 82 | 83 | reset_tags(&m->tags); 84 | 85 | mctx->msgid = msg.id; 86 | return (MATCH_PARENT); 87 | } 88 | 89 | void 90 | match_command_desc(struct expritem *ei, char *buf, size_t len) 91 | { 92 | struct match_command_data *data = ei->data; 93 | char ret[11]; 94 | const char *type; 95 | 96 | *ret = '\0'; 97 | if (data->ret != -1) 98 | xsnprintf(ret, sizeof ret, "%d", data->ret); 99 | type = data->pipe ? "pipe" : "exec"; 100 | 101 | if (data->re.str == NULL) { 102 | if (data->user.str != NULL) { 103 | xsnprintf(buf, len, 104 | "%s \"%s\" user \"%s\" returns (%s, )", 105 | type, data->cmd.str, data->user.str, ret); 106 | } else { 107 | xsnprintf(buf, len, "%s \"%s\" returns (%s, )", type, 108 | data->cmd.str, ret); 109 | } 110 | } else { 111 | if (data->user.str != NULL) { 112 | xsnprintf(buf, len, 113 | "%s \"%s\" user \"%s\" returns (%s, \"%s\")", 114 | type, data->cmd.str, data->user.str, ret, 115 | data->re.str); 116 | } else { 117 | xsnprintf(buf, len, 118 | "%s \"%s\" returns (%s, \"%s\")", 119 | type, data->cmd.str, ret, data->re.str); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /match-in-cache.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "match.h" 25 | 26 | int match_in_cache_match(struct mail_ctx *, struct expritem *); 27 | void match_in_cache_desc(struct expritem *, char *, size_t); 28 | 29 | struct match match_in_cache = { 30 | "in-cache", 31 | match_in_cache_match, 32 | match_in_cache_desc 33 | }; 34 | 35 | int 36 | match_in_cache_match(struct mail_ctx *mctx, struct expritem *ei) 37 | { 38 | struct match_in_cache_data *data = ei->data; 39 | struct account *a = mctx->account; 40 | struct mail *m = mctx->mail; 41 | char *key; 42 | struct cache *cache; 43 | 44 | key = replacestr(&data->key, m->tags, m, &m->rml); 45 | if (key == NULL || *key == '\0') { 46 | log_warnx("%s: empty key", a->name); 47 | goto error; 48 | } 49 | log_debug2("%s: matching to cache %s: %s", a->name, data->path, key); 50 | 51 | TAILQ_FOREACH(cache, &conf.caches, entry) { 52 | if (strcmp(data->path, cache->path) == 0) { 53 | if (open_cache(a, cache) != 0) 54 | goto error; 55 | if (db_contains(cache->db, key)) { 56 | xfree(key); 57 | return (MATCH_TRUE); 58 | } 59 | xfree(key); 60 | return (MATCH_FALSE); 61 | } 62 | } 63 | log_warnx("%s: cache %s not declared", a->name, data->path); 64 | 65 | error: 66 | if (key != NULL) 67 | xfree(key); 68 | return (MATCH_ERROR); 69 | } 70 | 71 | void 72 | match_in_cache_desc(struct expritem *ei, char *buf, size_t len) 73 | { 74 | struct match_in_cache_data *data = ei->data; 75 | 76 | xsnprintf(buf, len, 77 | "in-cache \"%s\" key \"%s\"", data->path, data->key.str); 78 | } 79 | -------------------------------------------------------------------------------- /match-matched.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "match.h" 25 | 26 | int match_matched_match(struct mail_ctx *, struct expritem *); 27 | void match_matched_desc(struct expritem *, char *, size_t); 28 | 29 | struct match match_matched = { 30 | "matched", 31 | match_matched_match, 32 | match_matched_desc 33 | }; 34 | 35 | int 36 | match_matched_match(struct mail_ctx *mctx, unused struct expritem *ei) 37 | { 38 | if (mctx->matched) 39 | return (MATCH_TRUE); 40 | return (MATCH_FALSE); 41 | } 42 | 43 | void 44 | match_matched_desc(unused struct expritem *ei, char *buf, size_t len) 45 | { 46 | strlcpy(buf, "matched", len); 47 | } 48 | -------------------------------------------------------------------------------- /match-regexp.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "match.h" 25 | 26 | int match_regexp_match(struct mail_ctx *, struct expritem *); 27 | void match_regexp_desc(struct expritem *, char *, size_t); 28 | 29 | struct match match_regexp = { 30 | "regexp", 31 | match_regexp_match, 32 | match_regexp_desc 33 | }; 34 | 35 | int 36 | match_regexp_match(struct mail_ctx *mctx, struct expritem *ei) 37 | { 38 | struct match_regexp_data *data = ei->data; 39 | struct account *a = mctx->account; 40 | struct mail *m = mctx->mail; 41 | int res; 42 | char *cause; 43 | size_t so, eo; 44 | 45 | so = 0; 46 | eo = m->size; 47 | switch (data->area) { 48 | case AREA_HEADERS: 49 | if (m->body == 0) 50 | return (MATCH_FALSE); 51 | eo = m->body; 52 | break; 53 | case AREA_BODY: 54 | so = m->body; 55 | break; 56 | case AREA_ANY: 57 | break; 58 | } 59 | log_debug3("%s: matching from %zu to %zu (size=%zu, body=%zu)", a->name, 60 | so, eo, m->size, m->body); 61 | 62 | res = re_block(&data->re, m->data + so, eo - so, &m->rml, &cause); 63 | if (res == -1) { 64 | log_warnx("%s: %s", a->name, cause); 65 | xfree(cause); 66 | return (MATCH_ERROR); 67 | } 68 | if (res == 0) 69 | return (MATCH_FALSE); 70 | return (MATCH_TRUE); 71 | } 72 | 73 | void 74 | match_regexp_desc(struct expritem *ei, char *buf, size_t len) 75 | { 76 | struct match_regexp_data *data = ei->data; 77 | const char *area = NULL; 78 | 79 | switch (data->area) { 80 | case AREA_BODY: 81 | area = "body"; 82 | break; 83 | case AREA_HEADERS: 84 | area = "headers"; 85 | break; 86 | case AREA_ANY: 87 | area = "any"; 88 | break; 89 | } 90 | 91 | xsnprintf(buf, len, "regexp \"%s\" in %s", data->re.str, area); 92 | } 93 | -------------------------------------------------------------------------------- /match-size.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "match.h" 25 | 26 | int match_size_match(struct mail_ctx *, struct expritem *); 27 | void match_size_desc(struct expritem *, char *, size_t); 28 | 29 | struct match match_size = { 30 | "size", 31 | match_size_match, 32 | match_size_desc 33 | }; 34 | 35 | int 36 | match_size_match(struct mail_ctx *mctx, struct expritem *ei) 37 | { 38 | struct match_size_data *data = ei->data; 39 | struct mail *m = mctx->mail; 40 | 41 | if (data->cmp == CMP_LT && m->size < data->size) 42 | return (MATCH_TRUE); 43 | else if (data->cmp == CMP_GT && m->size > data->size) 44 | return (MATCH_TRUE); 45 | return (MATCH_FALSE); 46 | } 47 | 48 | void 49 | match_size_desc(struct expritem *ei, char *buf, size_t len) 50 | { 51 | struct match_size_data *data = ei->data; 52 | const char *cmp = ""; 53 | 54 | if (data->cmp == CMP_LT) 55 | cmp = "<"; 56 | else if (data->cmp == CMP_GT) 57 | cmp = ">"; 58 | xsnprintf(buf, len, "size %s %zu", cmp, data->size); 59 | } 60 | -------------------------------------------------------------------------------- /match-string.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "fdm.h" 25 | #include "match.h" 26 | 27 | int match_string_match(struct mail_ctx *, struct expritem *); 28 | void match_string_desc(struct expritem *, char *, size_t); 29 | 30 | struct match match_string = { 31 | "string", 32 | match_string_match, 33 | match_string_desc 34 | }; 35 | 36 | int 37 | match_string_match(struct mail_ctx *mctx, struct expritem *ei) 38 | { 39 | struct match_string_data *data = ei->data; 40 | struct account *a = mctx->account; 41 | struct mail *m = mctx->mail; 42 | char *s, *cause; 43 | int n; 44 | 45 | s = replacestr(&data->str, m->tags, m, &m->rml); 46 | if ((n = re_string(&data->re, s, NULL, &cause)) == -1) { 47 | xfree(s); 48 | log_warnx("%s: %s", a->name, cause); 49 | xfree(cause); 50 | return (MATCH_ERROR); 51 | } 52 | xfree(s); 53 | 54 | if (n == 0) 55 | return (MATCH_FALSE); 56 | return (MATCH_TRUE); 57 | } 58 | 59 | void 60 | match_string_desc(struct expritem *ei, char *buf, size_t len) 61 | { 62 | struct match_string_data *data = ei->data; 63 | 64 | xsnprintf( 65 | buf, len, "string \"%s\" to \"%s\"", data->str.str, data->re.str); 66 | } 67 | -------------------------------------------------------------------------------- /match-tagged.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "fdm.h" 25 | #include "match.h" 26 | 27 | int match_tagged_match(struct mail_ctx *, struct expritem *); 28 | void match_tagged_desc(struct expritem *, char *, size_t); 29 | 30 | struct match match_tagged = { 31 | "tagged", 32 | match_tagged_match, 33 | match_tagged_desc 34 | }; 35 | 36 | int 37 | match_tagged_match(struct mail_ctx *mctx, struct expritem *ei) 38 | { 39 | struct match_tagged_data *data = ei->data; 40 | struct mail *m = mctx->mail; 41 | char *tag; 42 | 43 | tag = replacestr(&data->tag, m->tags, m, &m->rml); 44 | if (match_tag(m->tags, tag) != NULL) { 45 | xfree(tag); 46 | return (MATCH_TRUE); 47 | } 48 | xfree(tag); 49 | return (MATCH_FALSE); 50 | } 51 | 52 | void 53 | match_tagged_desc(struct expritem *ei, char *buf, size_t len) 54 | { 55 | struct match_tagged_data *data = ei->data; 56 | 57 | xsnprintf(buf, len, "tagged %s", data->tag.str); 58 | } 59 | -------------------------------------------------------------------------------- /match-unmatched.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "fdm.h" 24 | #include "match.h" 25 | 26 | int match_unmatched_match(struct mail_ctx *, struct expritem *); 27 | void match_unmatched_desc(struct expritem *, char *, size_t); 28 | 29 | struct match match_unmatched = { 30 | "unmatched", 31 | match_unmatched_match, 32 | match_unmatched_desc 33 | }; 34 | 35 | int 36 | match_unmatched_match(struct mail_ctx *mctx, unused struct expritem *ei) 37 | { 38 | if (mctx->matched) 39 | return (MATCH_FALSE); 40 | return (MATCH_TRUE); 41 | } 42 | 43 | void 44 | match_unmatched_desc(unused struct expritem *ei, char *buf, size_t len) 45 | { 46 | strlcpy(buf, "unmatched", len); 47 | } 48 | -------------------------------------------------------------------------------- /match.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef MATCH_H 20 | #define MATCH_H 21 | 22 | #include "deliver.h" 23 | 24 | /* Match return codes. */ 25 | #define MATCH_FALSE 0 26 | #define MATCH_TRUE 1 27 | #define MATCH_ERROR 2 28 | #define MATCH_PARENT 3 29 | 30 | /* Match functions. */ 31 | struct match { 32 | const char *name; 33 | 34 | int (*match)(struct mail_ctx *, struct expritem *); 35 | void (*desc)(struct expritem *, char *, size_t); 36 | }; 37 | 38 | /* Match attachment data. */ 39 | struct match_attachment_data { 40 | enum { 41 | ATTACHOP_COUNT, 42 | ATTACHOP_TOTALSIZE, 43 | ATTACHOP_ANYSIZE, 44 | ATTACHOP_ANYTYPE, 45 | ATTACHOP_ANYNAME 46 | } op; 47 | 48 | enum cmp cmp; 49 | union { 50 | size_t size; 51 | long long num; 52 | struct replstr str; 53 | struct re re; 54 | } value; 55 | }; 56 | 57 | /* Match account data. */ 58 | struct match_account_data { 59 | struct replstrs *accounts; 60 | }; 61 | 62 | /* Match age data. */ 63 | struct match_age_data { 64 | long long time; 65 | enum cmp cmp; 66 | }; 67 | 68 | /* Match size data. */ 69 | struct match_size_data { 70 | size_t size; 71 | enum cmp cmp; 72 | }; 73 | 74 | /* Match tagged data. */ 75 | struct match_tagged_data { 76 | struct replstr tag; 77 | }; 78 | 79 | /* Match string data. */ 80 | struct match_string_data { 81 | struct replstr str; 82 | struct re re; 83 | }; 84 | 85 | /* Match regexp data. */ 86 | struct match_regexp_data { 87 | struct re re; 88 | 89 | enum area area; 90 | }; 91 | 92 | /* Match command data. */ 93 | struct match_command_data { 94 | struct replpath cmd; 95 | struct replstr user; 96 | int pipe; /* pipe mail to command */ 97 | 98 | struct re re; /* re->str NULL to not check */ 99 | int ret; /* -1 to not check */ 100 | }; 101 | 102 | /* Match in-cache data. */ 103 | struct match_in_cache_data { 104 | char *path; 105 | struct replstr key; 106 | }; 107 | 108 | /* match-age.c */ 109 | extern struct match match_age; 110 | 111 | /* match-all.c */ 112 | extern struct match match_all; 113 | 114 | /* match-account.c */ 115 | extern struct match match_account; 116 | 117 | /* match-attachment.c */ 118 | extern struct match match_attachment; 119 | 120 | /* match-matched.c */ 121 | extern struct match match_matched; 122 | 123 | /* match-unmatched.c */ 124 | extern struct match match_unmatched; 125 | 126 | /* match-size.c */ 127 | extern struct match match_size; 128 | 129 | /* match-tagged.c */ 130 | extern struct match match_tagged; 131 | 132 | /* match-string.c */ 133 | extern struct match match_string; 134 | 135 | /* match-command.c */ 136 | extern struct match match_command; 137 | 138 | /* match-regexp.c */ 139 | extern struct match match_regexp; 140 | 141 | /* match-in-cache.c */ 142 | extern struct match match_in_cache; 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /parent-deliver.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "fdm.h" 29 | #include "deliver.h" 30 | #include "match.h" 31 | 32 | int 33 | parent_deliver(struct child *child, struct msg *msg, struct msgbuf *msgbuf) 34 | { 35 | struct child_deliver_data *data = child->data; 36 | struct account *a = data->account; 37 | struct mail *m = data->mail; 38 | 39 | if (msg->type != MSG_DONE) 40 | fatalx("unexpected message"); 41 | 42 | if (msgbuf->buf == NULL || msgbuf->len == 0) 43 | fatalx("bad tags"); 44 | strb_destroy(&m->tags); 45 | m->tags = msgbuf->buf; 46 | 47 | /* Call the hook. */ 48 | data->hook(1, a, msg, data, &msg->data.error); 49 | 50 | msg->type = MSG_DONE; 51 | msg->id = data->msgid; 52 | 53 | msgbuf->buf = m->tags; 54 | msgbuf->len = STRB_SIZE(m->tags); 55 | 56 | mail_send(m, msg); 57 | 58 | /* 59 | * Try to send to child. Ignore failures which mean the fetch child 60 | * has exited - not much can do about it now. 61 | */ 62 | child = data->child; 63 | if (child->io == NULL || privsep_send(child->io, msg, msgbuf) != 0) 64 | log_debug2("%s: child %ld missing", a->name, (long) child->pid); 65 | 66 | mail_close(m); 67 | xfree(m); 68 | 69 | return (-1); 70 | } 71 | -------------------------------------------------------------------------------- /parent-fetch.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "fdm.h" 29 | #include "deliver.h" 30 | #include "match.h" 31 | 32 | void parent_fetch_error(struct child *, struct msg *); 33 | void parent_fetch_action(struct child *, struct children *, 34 | struct deliver_ctx *, struct msg *); 35 | void parent_fetch_cmd(struct child *, struct children *, struct mail_ctx *, 36 | struct msg *); 37 | 38 | int 39 | parent_fetch(struct child *child, struct msg *msg, struct msgbuf *msgbuf) 40 | { 41 | struct child_fetch_data *data = child->data; 42 | struct children *children = data->children; 43 | struct deliver_ctx *dctx; 44 | struct mail_ctx *mctx; 45 | struct mail *m; 46 | 47 | switch (msg->type) { 48 | case MSG_ACTION: 49 | if (msgbuf->buf == NULL || msgbuf->len == 0) 50 | fatalx("bad tags"); 51 | m = xcalloc(1, sizeof *m); 52 | if (mail_receive(m, msg, 0) != 0) { 53 | log_warn("parent: can't receive mail"); 54 | parent_fetch_error(child, msg); 55 | break; 56 | } 57 | m->tags = msgbuf->buf; 58 | 59 | dctx = xcalloc(1, sizeof *dctx); 60 | dctx->account = msg->data.account; 61 | dctx->mail = m; 62 | 63 | parent_fetch_action(child, children, dctx, msg); 64 | break; 65 | case MSG_COMMAND: 66 | if (msgbuf->buf == NULL || msgbuf->len == 0) 67 | fatalx("bad tags"); 68 | m = xcalloc(1, sizeof *m); 69 | if (mail_receive(m, msg, 0) != 0) { 70 | log_warn("parent: can't receive mail"); 71 | parent_fetch_error(child, msg); 72 | break; 73 | } 74 | m->tags = msgbuf->buf; 75 | 76 | mctx = xcalloc(1, sizeof *mctx); 77 | mctx->account = msg->data.account; 78 | mctx->mail = m; 79 | 80 | parent_fetch_cmd(child, children, mctx, msg); 81 | break; 82 | case MSG_DONE: 83 | fatalx("unexpected message"); 84 | case MSG_EXIT: 85 | return (-1); 86 | } 87 | 88 | return (0); 89 | } 90 | 91 | void 92 | parent_fetch_error(struct child *child, struct msg *msg) 93 | { 94 | msg->type = MSG_DONE; 95 | msg->data.error = DELIVER_FAILURE; 96 | if (privsep_send(child->io, msg, NULL) != 0) 97 | fatalx("privsep_send error"); 98 | } 99 | 100 | void 101 | parent_fetch_action(struct child *child, struct children *children, 102 | struct deliver_ctx *dctx, struct msg *msg) 103 | { 104 | struct actitem *ti = msg->data.actitem; 105 | struct mail *m = dctx->mail; 106 | struct mail *md = &dctx->wr_mail; 107 | struct child_deliver_data *data; 108 | uid_t uid = msg->data.uid; 109 | gid_t gid = msg->data.gid; 110 | 111 | memset(md, 0, sizeof *md); 112 | /* 113 | * If writing back, open a new mail now and set its ownership so it 114 | * can be accessed by the child. 115 | */ 116 | if (ti->deliver->type == DELIVER_WRBACK) { 117 | if (mail_open(md, IO_BLOCKSIZE) != 0) { 118 | log_warn("parent: failed to create mail"); 119 | parent_fetch_error(child, msg); 120 | return; 121 | } 122 | if (geteuid() == 0 && 123 | shm_owner(&md->shm, conf.child_uid, conf.child_gid) != 0) { 124 | mail_destroy(md); 125 | log_warn("parent: failed to set mail ownership"); 126 | parent_fetch_error(child, msg); 127 | return; 128 | } 129 | md->decision = m->decision; 130 | } 131 | 132 | data = xmalloc(sizeof *data); 133 | data->child = child; 134 | data->msgid = msg->id; 135 | data->account = dctx->account; 136 | data->hook = child_deliver_action_hook; 137 | data->actitem = ti; 138 | data->dctx = dctx; 139 | data->mail = m; 140 | data->name = "deliver"; 141 | data->uid = uid; 142 | data->gid = gid; 143 | child = child_start( 144 | children, uid, gid, child_deliver, parent_deliver, data, child); 145 | log_debug3("parent: deliver " 146 | "child %ld started (uid %lu)", (long) child->pid, (u_long) uid); 147 | } 148 | 149 | void 150 | parent_fetch_cmd(struct child *child, struct children *children, 151 | struct mail_ctx *mctx, struct msg *msg) 152 | { 153 | struct mail *m = mctx->mail; 154 | struct child_deliver_data *data; 155 | uid_t uid = msg->data.uid; 156 | gid_t gid = msg->data.gid; 157 | 158 | data = xmalloc(sizeof *data); 159 | data->child = child; 160 | data->msgid = msg->id; 161 | data->account = mctx->account; 162 | data->hook = child_deliver_cmd_hook; 163 | data->mctx = mctx; 164 | data->cmddata = msg->data.cmddata; 165 | data->mail = m; 166 | data->name = "command"; 167 | data->uid = uid; 168 | data->gid = gid; 169 | child = child_start( 170 | children, uid, gid, child_deliver, parent_deliver, data, child); 171 | log_debug3("parent: command " 172 | "child %ld started (uid %lu)", (long) child->pid, (u_long) uid); 173 | } 174 | -------------------------------------------------------------------------------- /pcre.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifdef PCRE2 20 | 21 | #include 22 | 23 | #define PCRE2_CODE_UNIT_WIDTH 8 24 | 25 | #include 26 | #include 27 | 28 | #include "fdm.h" 29 | 30 | int 31 | re_compile(struct re *re, const char *s, int flags, char **cause) 32 | { 33 | char error[256]; 34 | PCRE2_SIZE off; 35 | int errorcode; 36 | 37 | if (s == NULL) 38 | fatalx("null regexp"); 39 | re->str = xstrdup(s); 40 | if (*s == '\0') 41 | return (0); 42 | re->flags = flags; 43 | 44 | flags = PCRE2_MULTILINE; 45 | if (re->flags & RE_IGNCASE) 46 | flags |= PCRE2_CASELESS; 47 | 48 | re->pcre2 = pcre2_compile(s, PCRE2_ZERO_TERMINATED, flags, &errorcode, 49 | &off, NULL); 50 | if (re->pcre2 == NULL) { 51 | pcre2_get_error_message(errorcode, error, sizeof(error)); 52 | *cause = xstrdup(error); 53 | return (-1); 54 | } 55 | 56 | return (0); 57 | } 58 | 59 | int 60 | re_string(struct re *re, const char *s, struct rmlist *rml, char **cause) 61 | { 62 | return (re_block(re, s, strlen(s), rml, cause)); 63 | } 64 | 65 | int 66 | re_block(struct re *re, const void *buf, size_t len, struct rmlist *rml, 67 | char **cause) 68 | { 69 | int res, ret; 70 | pcre2_match_data *pmd; 71 | PCRE2_SIZE *ovector; 72 | u_int i, j; 73 | 74 | if (len > INT_MAX) 75 | fatalx("buffer too big"); 76 | 77 | if (rml != NULL) 78 | memset(rml, 0, sizeof *rml); 79 | 80 | /* If the regexp is empty, just check whether the buffer is empty. */ 81 | if (*re->str == '\0') { 82 | if (len == 0) 83 | return (1); 84 | return (0); 85 | } 86 | 87 | pmd = pcre2_match_data_create_from_pattern(re->pcre2, NULL); 88 | if (pmd == NULL) 89 | fatalx("pcre2_match_data_create_from_pattern failed"); 90 | 91 | res = pcre2_match(re->pcre2, buf, len, 0, 0, pmd, NULL); 92 | if (res > 0) { 93 | if (rml != NULL) { 94 | if (res > NPMATCH) 95 | res = NPMATCH; 96 | ovector = pcre2_get_ovector_pointer(pmd); 97 | for (i = 0; i < res; i++) { 98 | j = i * 2; 99 | if (ovector[j + 1] < ovector[j]) 100 | break; 101 | rml->list[i].valid = 1; 102 | rml->list[i].so = ovector[j]; 103 | rml->list[i].eo = ovector[j + 1]; 104 | } 105 | rml->valid = 1; 106 | } 107 | ret = 1; 108 | } else if (res == PCRE2_ERROR_NOMATCH) 109 | ret = 0; 110 | else { 111 | xasprintf(cause, "%s: regexec failed", re->str); 112 | ret = -1; 113 | } 114 | pcre2_match_data_free(pmd); 115 | return (ret); 116 | } 117 | 118 | void 119 | re_free(struct re *re) 120 | { 121 | xfree(re->str); 122 | pcre2_code_free(re->pcre2); 123 | } 124 | 125 | #endif /* PCRE2 */ 126 | -------------------------------------------------------------------------------- /privsep.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include "fdm.h" 22 | 23 | int 24 | privsep_send(struct io *io, struct msg *msg, struct msgbuf *msgbuf) 25 | { 26 | char *cause; 27 | 28 | msg->size = 0; 29 | if (msgbuf != NULL && msgbuf->buf != NULL && msgbuf->len > 0) 30 | msg->size = msgbuf->len; 31 | 32 | io_write(io, msg, sizeof *msg); 33 | if (io_flush(io, INFTIM, &cause) != 0) 34 | return (-1); 35 | 36 | if (msg->size != 0) { 37 | io_write(io, msgbuf->buf, msgbuf->len); 38 | if (io_flush(io, INFTIM, &cause) != 0) 39 | return (-1); 40 | } 41 | 42 | return (0); 43 | } 44 | 45 | int 46 | privsep_check(struct io *io) 47 | { 48 | return (IO_RDSIZE(io) >= sizeof (struct msg)); 49 | } 50 | 51 | int 52 | privsep_recv(struct io *io, struct msg *msg, struct msgbuf *msgbuf) 53 | { 54 | char *tmpbuf; 55 | 56 | if (msgbuf != NULL) { 57 | msgbuf->buf = NULL; 58 | msgbuf->len = 0; 59 | } 60 | 61 | if (io_wait(io, sizeof *msg, INFTIM, NULL) != 0) 62 | return (-1); 63 | if (io_read2(io, msg, sizeof *msg) != 0) 64 | return (-1); 65 | 66 | if (msg->size == 0) 67 | return (0); 68 | 69 | if (io_wait(io, msg->size, INFTIM, NULL) != 0) 70 | return (-1); 71 | if (msgbuf == NULL) { 72 | if ((tmpbuf = io_read(io, msg->size)) == NULL) 73 | return (-1); 74 | xfree(tmpbuf); 75 | } else { 76 | if ((msgbuf->buf = io_read(io, msg->size)) == NULL) 77 | return (-1); 78 | msgbuf->len = msg->size; 79 | } 80 | 81 | return (0); 82 | } 83 | -------------------------------------------------------------------------------- /re.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef PCRE2 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include "fdm.h" 26 | 27 | int 28 | re_compile(struct re *re, const char *s, int flags, char **cause) 29 | { 30 | int error; 31 | size_t len; 32 | char *buf; 33 | 34 | if (s == NULL) 35 | fatalx("null regexp"); 36 | re->str = xstrdup(s); 37 | if (*s == '\0') 38 | return (0); 39 | re->flags = flags; 40 | 41 | flags = REG_EXTENDED|REG_NEWLINE; 42 | if (re->flags & RE_NOSUBST) 43 | flags |= REG_NOSUB; 44 | if (re->flags & RE_IGNCASE) 45 | flags |= REG_ICASE; 46 | 47 | if ((error = regcomp(&re->re, s, flags)) != 0) { 48 | len = regerror(error, &re->re, NULL, 0); 49 | buf = xmalloc(len); 50 | regerror(error, &re->re, buf, len); 51 | xasprintf(cause, "%s%s", s, buf); 52 | return (-1); 53 | } 54 | 55 | return (0); 56 | } 57 | 58 | int 59 | re_string(struct re *re, const char *s, struct rmlist *rml, char **cause) 60 | { 61 | return (re_block(re, s, strlen(s), rml, cause)); 62 | } 63 | 64 | int 65 | re_block(struct re *re, const void *buf, size_t len, struct rmlist *rml, 66 | char **cause) 67 | { 68 | int res; 69 | regmatch_t pm[NPMATCH]; 70 | u_int i; 71 | 72 | if (rml != NULL) 73 | memset(rml, 0, sizeof *rml); 74 | 75 | /* If the regexp is empty, just check whether the buffer is empty. */ 76 | if (*re->str == '\0') { 77 | if (len == 0) 78 | return (1); 79 | return (0); 80 | } 81 | 82 | memset(pm, 0, sizeof pm); 83 | pm[0].rm_so = 0; 84 | pm[0].rm_eo = len; 85 | res = regexec(&re->re, buf, NPMATCH, pm, REG_STARTEND); 86 | if (res != 0 && res != REG_NOMATCH) { 87 | xasprintf(cause, "%s: regexec failed", re->str); 88 | return (-1); 89 | } 90 | 91 | if (rml != NULL) { 92 | for (i = 0; i < NPMATCH; i++) { 93 | if (pm[i].rm_eo <= pm[i].rm_so) 94 | break; 95 | rml->list[i].valid = 1; 96 | rml->list[i].so = pm[i].rm_so; 97 | rml->list[i].eo = pm[i].rm_eo; 98 | } 99 | rml->valid = 1; 100 | } 101 | 102 | return (res == 0); 103 | } 104 | 105 | void 106 | re_free(struct re *re) 107 | { 108 | xfree(re->str); 109 | regfree(&re->re); 110 | } 111 | 112 | #endif /* !PCRE2 */ 113 | -------------------------------------------------------------------------------- /shm-mmap.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2006 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "fdm.h" 27 | 28 | /* 29 | * This implements shared memory using mmap'd files in TMPDIR. 30 | */ 31 | 32 | int shm_expand(struct shm *, size_t); 33 | 34 | char shm_block[BUFSIZ]; 35 | 36 | #ifdef MAP_NOSYNC 37 | #define SHM_FLAGS MAP_SHARED|MAP_NOSYNC 38 | #else 39 | #define SHM_FLAGS MAP_SHARED 40 | #endif 41 | #define SHM_PROT PROT_READ|PROT_WRITE 42 | 43 | /* Work out shm path. */ 44 | char * 45 | shm_path(struct shm *shm) 46 | { 47 | static char path[MAXPATHLEN]; 48 | 49 | if (ppath(path, sizeof path, "%s/%s", conf.tmp_dir, shm->name) != 0) 50 | return (NULL); 51 | return (path); 52 | } 53 | 54 | /* Expand or reduce shm file to size. */ 55 | int 56 | shm_expand(struct shm *shm, size_t size) 57 | { 58 | ssize_t n; 59 | 60 | if (size == shm->size) 61 | return (0); 62 | 63 | if (size < shm->size) 64 | return (ftruncate(shm->fd, size) != 0); 65 | 66 | if (lseek(shm->fd, shm->size, SEEK_SET) == -1) 67 | return (-1); 68 | 69 | /* 70 | * Fill the file using write(2) to avoid fragmentation problems on 71 | * FreeBSD and also to detect disk full. 72 | */ 73 | while (size > sizeof shm_block) { 74 | if ((n = write(shm->fd, shm_block, sizeof shm_block)) == -1) 75 | return (-1); 76 | if (n != sizeof shm_block) { 77 | errno = EIO; 78 | return (-1); 79 | } 80 | size -= sizeof shm_block; 81 | } 82 | if (size > 0) { 83 | if ((n = write(shm->fd, shm_block, size)) == -1) 84 | return (-1); 85 | if ((size_t) n != size) { 86 | errno = EIO; 87 | return (-1); 88 | } 89 | } 90 | 91 | /* 92 | * Sync the fd, should hopefully fail if disk full. 93 | */ 94 | if (fsync(shm->fd) != 0) 95 | return (-1); 96 | 97 | return (0); 98 | } 99 | 100 | /* Create an shm file and map it. */ 101 | void * 102 | shm_create(struct shm *shm, size_t size) 103 | { 104 | int saved_errno; 105 | char *path; 106 | 107 | if (size == 0) 108 | fatalx("zero size"); 109 | 110 | if (ppath( 111 | shm->name, sizeof shm->name, "%s.XXXXXXXXXX", __progname) != 0) 112 | return (NULL); 113 | if ((path = shm_path(shm)) == NULL) 114 | return (NULL); 115 | if ((shm->fd = mkstemp(path)) == -1) 116 | return (NULL); 117 | strlcpy(shm->name, xbasename(path), sizeof shm->name); 118 | 119 | if (shm_expand(shm, size) != 0) 120 | goto error; 121 | 122 | shm->data = mmap(NULL, size, SHM_PROT, SHM_FLAGS, shm->fd, 0); 123 | if (shm->data == MAP_FAILED) 124 | goto error; 125 | madvise(shm->data, size, MADV_SEQUENTIAL); 126 | 127 | shm->size = size; 128 | return (shm->data); 129 | 130 | error: 131 | saved_errno = errno; 132 | unlink(path); 133 | errno = saved_errno; 134 | return (NULL); 135 | } 136 | 137 | /* Destroy shm file. */ 138 | void 139 | shm_destroy(struct shm *shm) 140 | { 141 | char *path; 142 | 143 | if (*shm->name == '\0') 144 | return; 145 | 146 | shm_close(shm); 147 | 148 | if ((path = shm_path(shm)) == NULL) 149 | fatal("unlink failed"); 150 | if (unlink(path) != 0) 151 | fatal("unlink failed"); 152 | 153 | *shm->name = '\0'; 154 | } 155 | 156 | /* Close and unmap shm without destroying file. */ 157 | void 158 | shm_close(struct shm *shm) 159 | { 160 | if (shm->fd == -1) 161 | return; 162 | 163 | if (munmap(shm->data, shm->size) != 0) 164 | fatal("munmap failed"); 165 | shm->data = NULL; 166 | 167 | close(shm->fd); 168 | shm->fd = -1; 169 | } 170 | 171 | /* Reopen and map shm file. */ 172 | void * 173 | shm_reopen(struct shm *shm) 174 | { 175 | char *path; 176 | 177 | if ((path = shm_path(shm)) == NULL) 178 | return (NULL); 179 | if ((shm->fd = open(path, O_RDWR, 0)) == -1) 180 | return (NULL); 181 | 182 | shm->data = mmap(NULL, shm->size, SHM_PROT, SHM_FLAGS, shm->fd, 0); 183 | if (shm->data == MAP_FAILED) 184 | return (NULL); 185 | madvise(shm->data, shm->size, MADV_SEQUENTIAL); 186 | 187 | return (shm->data); 188 | } 189 | 190 | /* Set ownership of shm file. */ 191 | int 192 | shm_owner(struct shm *shm, uid_t uid, gid_t gid) 193 | { 194 | if (fchown(shm->fd, uid, gid) != 0) 195 | return (-1); 196 | 197 | return (0); 198 | } 199 | 200 | /* Resize an shm file. */ 201 | void * 202 | shm_resize(struct shm *shm, size_t nmemb, size_t size) 203 | { 204 | size_t newsize = nmemb * size; 205 | 206 | if (size == 0) 207 | fatalx("zero size"); 208 | if (SIZE_MAX / nmemb < size) 209 | fatalx("nmemb * size > SIZE_MAX"); 210 | 211 | #ifndef HAVE_MREMAP 212 | if (munmap(shm->data, shm->size) != 0) 213 | fatal("munmap failed"); 214 | shm->data = NULL; 215 | #endif 216 | 217 | if (shm_expand(shm, newsize) != 0) 218 | return (NULL); 219 | 220 | #ifdef HAVE_MREMAP 221 | shm->data = mremap(shm->data, shm->size, newsize, MREMAP_MAYMOVE); 222 | #else 223 | shm->data = mmap(NULL, newsize, SHM_PROT, SHM_FLAGS, shm->fd, 0); 224 | #endif 225 | if (shm->data == MAP_FAILED) 226 | return (NULL); 227 | madvise(shm->data, newsize, MADV_SEQUENTIAL); 228 | 229 | shm->size = newsize; 230 | return (shm->data); 231 | } 232 | -------------------------------------------------------------------------------- /strb.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "fdm.h" 27 | 28 | void *strb_address(struct strb *, const char *); 29 | 30 | void 31 | strb_create(struct strb **sbp) 32 | { 33 | *sbp = xcalloc(1, STRBOFFSET); 34 | strb_clear(sbp); 35 | } 36 | 37 | void 38 | strb_clear(struct strb **sbp) 39 | { 40 | struct strb *sb = *sbp; 41 | 42 | sb->ent_used = 0; 43 | sb->ent_max = STRBENTRIES; 44 | 45 | sb->str_size = STRBBLOCK; 46 | sb->str_used = 0; 47 | 48 | sb = *sbp = xrealloc(sb, 1, STRB_SIZE(sb)); 49 | memset(STRB_BASE(sb), 0, sb->str_size + STRB_ENTSIZE(sb)); 50 | } 51 | 52 | void 53 | strb_destroy(struct strb **sbp) 54 | { 55 | xfree(*sbp); 56 | *sbp = NULL; 57 | } 58 | 59 | void 60 | strb_dump(struct strb *sb, const char *prefix, void (*p)(const char *, ...)) 61 | { 62 | struct strbent *sbe; 63 | u_int i; 64 | 65 | for (i = 0; i < sb->ent_used; i++) { 66 | sbe = STRB_ENTRY(sb, i); 67 | p("%s: %s: %s", prefix, STRB_KEY(sb, sbe), STRB_VALUE(sb, sbe)); 68 | } 69 | } 70 | 71 | void printflike3 72 | strb_add(struct strb **sbp, const char *key, const char *value, ...) 73 | { 74 | va_list ap; 75 | 76 | va_start(ap, value); 77 | strb_vadd(sbp, key, value, ap); 78 | va_end(ap); 79 | } 80 | 81 | void 82 | strb_vadd(struct strb **sbp, const char *key, const char *value, va_list ap) 83 | { 84 | struct strb *sb = *sbp; 85 | size_t size, keylen, valuelen; 86 | u_int n; 87 | struct strbent sbe, *sbep; 88 | va_list aq; 89 | 90 | keylen = strlen(key) + 1; 91 | 92 | va_copy(aq, ap); 93 | valuelen = xvsnprintf(NULL, 0, value, aq) + 1; 94 | va_end(aq); 95 | 96 | size = sb->str_size; 97 | while (sb->str_size - sb->str_used < keylen + valuelen) { 98 | if (STRB_SIZE(sb) > SIZE_MAX / 2) 99 | fatalx("size too large"); 100 | sb->str_size *= 2; 101 | } 102 | if (size != sb->str_size) { 103 | sb = *sbp = xrealloc(sb, 1, STRB_SIZE(sb)); 104 | memmove( 105 | STRB_ENTBASE(sb), STRB_BASE(sb) + size, STRB_ENTSIZE(sb)); 106 | memset(STRB_BASE(sb) + size, 0, sb->str_size - size); 107 | } 108 | 109 | sbep = strb_address(sb, key); 110 | if (sbep == NULL) { 111 | if (sb->ent_used > sb->ent_max) { 112 | /* Allocate some more entries. */ 113 | n = sb->ent_max; 114 | 115 | size = STRB_SIZE(sb); 116 | if (sb->ent_max > UINT_MAX / 2) 117 | fatalx("ent_max too large"); 118 | sb->ent_max *= 2; 119 | if (STRB_SIZE(sb) < size) 120 | fatalx("size too large"); 121 | 122 | sb = *sbp = xrealloc(sb, 1, STRB_SIZE(sb)); 123 | 124 | memset(STRB_ENTRY(sb, n), 0, STRB_ENTSIZE(sb) / 2); 125 | } 126 | 127 | sbep = STRB_ENTRY(sb, sb->ent_used); 128 | sb->ent_used++; 129 | 130 | sbe.key = sb->str_used; 131 | memcpy(STRB_KEY(sb, &sbe), key, keylen); 132 | sb->str_used += keylen; 133 | } else 134 | memcpy(&sbe, sbep, sizeof sbe); 135 | sbe.value = sb->str_used; 136 | xvsnprintf(STRB_VALUE(sb, &sbe), valuelen, value, ap); 137 | sb->str_used += valuelen; 138 | 139 | memcpy(sbep, &sbe, sizeof sbe); 140 | } 141 | 142 | void * 143 | strb_address(struct strb *sb, const char *key) 144 | { 145 | struct strbent sbe; 146 | u_int i; 147 | 148 | for (i = 0; i < sb->ent_used; i++) { 149 | memcpy(&sbe, STRB_ENTRY(sb, i), sizeof sbe); 150 | if (strcmp(key, STRB_KEY(sb, &sbe)) == 0) 151 | return (STRB_ENTRY(sb, i)); 152 | } 153 | return (NULL); 154 | } 155 | 156 | struct strbent * 157 | strb_find(struct strb *sb, const char *key) 158 | { 159 | static struct strbent sbe; 160 | void *sbep; 161 | 162 | sbep = strb_address(sb, key); 163 | if (sbep == NULL) 164 | return (NULL); 165 | memcpy(&sbe, sbep, sizeof sbe); 166 | return (&sbe); 167 | } 168 | 169 | struct strbent * 170 | strb_match(struct strb *sb, const char *patt) 171 | { 172 | static struct strbent sbe; 173 | u_int i; 174 | 175 | for (i = 0; i < sb->ent_used; i++) { 176 | memcpy(&sbe, STRB_ENTRY(sb, i), sizeof sbe); 177 | if (fnmatch(patt, STRB_KEY(sb, &sbe), 0) == 0) 178 | return (&sbe); 179 | } 180 | return (NULL); 181 | } 182 | -------------------------------------------------------------------------------- /timer.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2007 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include "fdm.h" 26 | 27 | volatile sig_atomic_t timer_value; 28 | 29 | void timer_handler(int); 30 | 31 | /* Signal handler for SIGALRM setitimer timeout. */ 32 | void 33 | timer_handler(unused int sig) 34 | { 35 | timer_value = 1; 36 | } 37 | 38 | /* Return timer state. */ 39 | int 40 | timer_expired(void) 41 | { 42 | return (timer_value); 43 | } 44 | 45 | /* Set timer with setitimer. */ 46 | void 47 | timer_set(int seconds) 48 | { 49 | struct itimerval itv; 50 | struct sigaction act; 51 | 52 | if (seconds == 0) 53 | fatalx("zero timeout"); 54 | timer_value = 0; 55 | 56 | memset(&act, 0, sizeof act); 57 | sigemptyset(&act.sa_mask); 58 | act.sa_handler = timer_handler; 59 | if (sigaction(SIGALRM, &act, NULL) != 0) 60 | fatal("sigaction failed"); 61 | 62 | memset(&itv, 0, sizeof itv); 63 | itv.it_value.tv_sec = seconds; 64 | while (setitimer(ITIMER_REAL, &itv, NULL) != 0) { 65 | /* 66 | * If the timeout is too large (EINVAL), keep trying it until 67 | * it reaches a minimum of 30 seconds. 68 | */ 69 | if (errno != EINVAL || itv.it_value.tv_sec < 30) 70 | fatal("setitimer failed"); 71 | itv.it_value.tv_sec /= 2; 72 | } 73 | } 74 | 75 | /* Unset timer. */ 76 | void 77 | timer_cancel(void) 78 | { 79 | struct itimerval itv; 80 | struct sigaction act; 81 | 82 | memset(&itv, 0, sizeof itv); 83 | if (setitimer(ITIMER_REAL, &itv, NULL) != 0) 84 | fatal("setitimer failed"); 85 | 86 | memset(&act, 0, sizeof act); 87 | sigemptyset(&act.sa_mask); 88 | act.sa_handler = SIG_DFL; 89 | if (sigaction(SIGALRM, &act, NULL) != 0) 90 | fatal("sigaction failed"); 91 | } 92 | -------------------------------------------------------------------------------- /xmalloc.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | 3 | /* 4 | * Copyright (c) 2004 Nicholas Marriott 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "fdm.h" 27 | 28 | void * 29 | ensure_for(void *buf, size_t *len, size_t size, size_t adj) 30 | { 31 | if (adj == 0) 32 | fatalx("zero adj"); 33 | 34 | if (SIZE_MAX - size < adj) 35 | fatalx("size + adj > SIZE_MAX"); 36 | size += adj; 37 | 38 | if (*len == 0) { 39 | *len = BUFSIZ; 40 | buf = xmalloc(*len); 41 | } 42 | 43 | while (*len <= size) { 44 | buf = xrealloc(buf, 2, *len); 45 | *len *= 2; 46 | } 47 | 48 | return (buf); 49 | } 50 | 51 | void * 52 | ensure_size(void *buf, size_t *len, size_t nmemb, size_t size) 53 | { 54 | if (nmemb == 0 || size == 0) 55 | fatalx("zero size"); 56 | if (SIZE_MAX / nmemb < size) 57 | fatalx("nmemb * size > SIZE_MAX"); 58 | 59 | if (*len == 0) { 60 | *len = BUFSIZ; 61 | buf = xmalloc(*len); 62 | } 63 | 64 | while (*len <= nmemb * size) { 65 | buf = xrealloc(buf, 2, *len); 66 | *len *= 2; 67 | } 68 | 69 | return (buf); 70 | } 71 | 72 | char * 73 | xstrdup(const char *s) 74 | { 75 | void *ptr; 76 | size_t len; 77 | 78 | len = strlen(s) + 1; 79 | ptr = xmalloc(len); 80 | 81 | return (strncpy(ptr, s, len)); 82 | } 83 | 84 | void * 85 | xcalloc(size_t nmemb, size_t size) 86 | { 87 | void *ptr; 88 | 89 | if (size == 0 || nmemb == 0) 90 | fatalx("zero size"); 91 | if (SIZE_MAX / nmemb < size) 92 | fatalx("nmemb * size > SIZE_MAX"); 93 | if ((ptr = calloc(nmemb, size)) == NULL) 94 | fatal("xcalloc failed"); 95 | return (ptr); 96 | } 97 | 98 | void * 99 | xmalloc(size_t size) 100 | { 101 | void *ptr; 102 | 103 | if (size == 0) 104 | fatalx("zero size"); 105 | if ((ptr = malloc(size)) == NULL) 106 | fatal("xmalloc failed"); 107 | return (ptr); 108 | } 109 | 110 | void * 111 | xrealloc(void *oldptr, size_t nmemb, size_t size) 112 | { 113 | size_t newsize = nmemb * size; 114 | void *newptr; 115 | 116 | if (newsize == 0) 117 | fatalx("zero size"); 118 | if (SIZE_MAX / nmemb < size) 119 | fatalx("nmemb * size > SIZE_MAX"); 120 | if ((newptr = realloc(oldptr, newsize)) == NULL) 121 | fatal("xrealloc failed"); 122 | return (newptr); 123 | } 124 | 125 | void 126 | xfree(void *ptr) 127 | { 128 | if (ptr == NULL) 129 | fatalx("null pointer"); 130 | free(ptr); 131 | } 132 | 133 | int printflike2 134 | xasprintf(char **ret, const char *fmt, ...) 135 | { 136 | va_list ap; 137 | int i; 138 | 139 | va_start(ap, fmt); 140 | i = xvasprintf(ret, fmt, ap); 141 | va_end(ap); 142 | 143 | return (i); 144 | } 145 | 146 | int 147 | xvasprintf(char **ret, const char *fmt, va_list ap) 148 | { 149 | int i; 150 | 151 | i = vasprintf(ret, fmt, ap); 152 | if (i < 0 || *ret == NULL) 153 | fatal("xvasprintf failed"); 154 | return (i); 155 | } 156 | 157 | int printflike3 158 | xsnprintf(char *buf, size_t len, const char *fmt, ...) 159 | { 160 | va_list ap; 161 | int i; 162 | 163 | va_start(ap, fmt); 164 | i = xvsnprintf(buf, len, fmt, ap); 165 | va_end(ap); 166 | 167 | return (i); 168 | } 169 | 170 | int 171 | xvsnprintf(char *buf, size_t len, const char *fmt, va_list ap) 172 | { 173 | int i; 174 | 175 | if (len > INT_MAX) 176 | fatalx("len > INT_MAX"); 177 | 178 | i = vsnprintf(buf, len, fmt, ap); 179 | if (i < 0) 180 | fatal("vsnprintf failed"); 181 | 182 | return (i); 183 | } 184 | 185 | /* 186 | * Some systems modify the path in place. This function and xbasename below 187 | * avoid that by using a temporary buffer. 188 | */ 189 | char * 190 | xdirname(const char *src) 191 | { 192 | static char dst[MAXPATHLEN]; 193 | 194 | strlcpy(dst, src, sizeof dst); 195 | return (dirname(dst)); 196 | } 197 | 198 | char * 199 | xbasename(const char *src) 200 | { 201 | static char dst[MAXPATHLEN]; 202 | 203 | strlcpy(dst, src, sizeof dst); 204 | return (basename(dst)); 205 | } 206 | --------------------------------------------------------------------------------