/* $Id: fdm.h,v 1.330 2007/09/25 21:01:52 nicm Exp $ */ /* * Copyright (c) 2006 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef FDM_H #define FDM_H #include #include #include #ifndef NO_QUEUE_H #include #else #include "compat/queue.h" #endif #ifndef NO_TREE_H #include #else #include "compat/tree.h" #endif #include #include #include #include #include #include #ifdef PCRE #include #endif #include #include #define CHILDUSER "_fdm" #define CONFFILE ".fdm.conf" #define SYSCONFFILE "/usr/local/etc/fdm.conf" #define LOCKFILE ".fdm.lock" #define SYSLOCKFILE "/var/run/fdm.lock" #define MAXQUEUEVALUE 50 #define DEFMAILQUEUE 2 #define DEFMAILSIZE (32 * 1024 * 1024) /* 32 MB */ #define MAXMAILSIZE (1 * 1024 * 1024 * 1024) /* 1 GB */ #define DEFSTRIPCHARS "\\<>$%^&*|{}[]\"'`;" #define MAXACTIONCHAIN 5 #define DEFTIMEOUT (900 * 1000) #define LOCKSLEEPTIME 10000 /* 0.1 seconds */ #define LOCKTOTALTIME 10000000 /* 10 seconds */ #define MAXNAMESIZE 64 #define DEFUMASK (S_IRWXG|S_IRWXO) #define FILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) #define DIRMODE (S_IRWXU|S_IRWXG|S_IRWXO) extern char *__progname; /* Linux compatibility bullshit. */ #ifndef UID_MAX #define UID_MAX UINT_MAX #endif #ifndef GID_MAX #define GID_MAX UINT_MAX #endif #ifndef INFTIM #define INFTIM -1 #endif #ifndef __dead #define __dead __attribute__ ((__noreturn__)) #endif #ifndef __packed #define __packed __attribute__ ((__packed__)) #endif /* Databases are not portable between endiness on OSs without these. */ #ifndef htole64 #define htole64 #endif #ifndef letoh64 #define letoh64 #endif #ifdef DEBUG #define NFDS 64 #define COUNTFDS(s) do { \ int fd_i, fd_n; \ fd_n = 0; \ for (fd_i = 0; fd_i < NFDS; fd_i++) { \ if (fcntl(fd_i, F_GETFL) != -1) \ fd_n++; \ } \ log_debug2("%s: %d file descriptors in use", s, fd_n); \ } while (0) #endif /* Fatal errors. */ #define fatal(msg) log_fatal("%s: %s", __func__, msg); #define fatalx(msg) log_fatalx("%s: %s", __func__, msg); /* Apply umask. */ #define UMASK(mask) ((mask) & ~conf.file_umask) /* Convert a file mode for %o%o%o printf. */ #define MODE(m) \ (m & S_IRUSR ? 4 : 0) + (m & S_IWUSR ? 2 : 0) + (m & S_IXUSR ? 1 : 0), \ (m & S_IRGRP ? 4 : 0) + (m & S_IWGRP ? 2 : 0) + (m & S_IXGRP ? 1 : 0), \ (m & S_IROTH ? 4 : 0) + (m & S_IWOTH ? 2 : 0) + (m & S_IXOTH ? 1 : 0) /* Definition to shut gcc up about unused arguments. */ #define unused __attribute__ ((unused)) /* Attribute to make gcc check printf-like arguments. */ #define printflike1 __attribute__ ((format (printf, 1, 2))) #define printflike2 __attribute__ ((format (printf, 2, 3))) #define printflike3 __attribute__ ((format (printf, 3, 4))) #define printflike4 __attribute__ ((format (printf, 4, 5))) #define printflike5 __attribute__ ((format (printf, 5, 6))) #define printflike6 __attribute__ ((format (printf, 6, 7))) /* Ensure buffer size. */ #define ENSURE_SIZE(buf, len, size) do { \ (buf) = ensure_size(buf, &(len), 1, size); \ } while (0) #define ENSURE_SIZE2(buf, len, nmemb, size) do { \ (buf) = ensure_size(buf, &(len), nmemb, size); \ } while (0) #define ENSURE_FOR(buf, len, size, adj) do { \ (buf) = ensure_for(buf, &(len), size, adj); \ } while (0) /* Description buffer size. */ #define DESCBUFSIZE 512 /* Replace buffer size. */ #define REPLBUFSIZE 64 /* Lengths of time. */ #define TIME_MINUTE 60LL #define TIME_HOUR 3600LL #define TIME_DAY 86400LL #define TIME_WEEK 604800LL #define TIME_MONTH 2419200LL #define TIME_YEAR 29030400LL /* Number of matches to use. */ #define NPMATCH 10 /* Account and action name match. */ #define account_match(p, n) (fnmatch(p, n, 0) == 0) #define action_match(p, n) (fnmatch(p, n, 0) == 0) #include "array.h" #include "io.h" /* Macros in configuration file. */ struct macro { char name[MAXNAMESIZE]; union { long long num; char *str; } value; enum { MACRO_NUMBER, MACRO_STRING } type; TAILQ_ENTRY(macro) entry; }; TAILQ_HEAD(macros, macro); /* Command-line commands. */ enum fdmop { FDMOP_NONE = 0, FDMOP_POLL, FDMOP_FETCH }; /* * Wrapper struct for a string that needs tag replacement before it is used. * This is used for anything that needs to be replaced after account and mail * data are available, everything else is replaced at parse time. */ struct replstr { char *str; } __packed; ARRAY_DECL(replstrs, struct replstr); /* Similar to replstr but needs expand_path too. */ struct replpath { char *str; } __packed; /* Server description. */ struct server { char *host; char *port; struct addrinfo *ai; int ssl; int verify; }; /* Proxy type. */ enum proxytype { PROXY_HTTP, PROXY_HTTPS, PROXY_SOCKS5 }; /* Proxy definition. */ struct proxy { enum proxytype type; char *user; char *pass; struct server server; }; /* Shared memory. */ struct shm { char name[MAXNAMLEN]; int fd; #define SHM_REGISTER(shm) cleanup_register(shm_path(shm)) #define SHM_DEREGISTER(shm) cleanup_deregister(shm_path(shm)) void *data; size_t size; }; /* Generic array of strings. */ ARRAY_DECL(strings, char *); /* Options for final mail handling. */ enum decision { DECISION_NONE, DECISION_DROP, DECISION_KEEP }; /* String block entry. */ struct strbent { size_t key; size_t value; }; /* String block header. */ struct strb { u_int ent_used; u_int ent_max; size_t str_used; size_t str_size; }; /* Initial string block slots and block size. */ #define STRBOFFSET (((sizeof (struct strb)) + 0x3f) & ~0x3f) #define STRBENTRIES 64 #define STRBBLOCK 1024 /* String block access macros. */ #define STRB_BASE(sb) (((char *) (sb)) + STRBOFFSET) #define STRB_KEY(sb, sbe) (STRB_BASE(sb) + (sbe)->key) #define STRB_VALUE(sb, sbe) (STRB_BASE(sb) + (sbe)->value) #define STRB_ENTBASE(sb) (STRB_BASE(sb) + (sb)->str_size) #define STRB_ENTOFF(sb, n) ((n) * (sizeof (struct strbent))) #define STRB_ENTSIZE(sb) STRB_ENTOFF(sb, (sb)->ent_max) #define STRB_ENTRY(sb, n) ((void *) (STRB_ENTBASE(sb) + STRB_ENTOFF(sb, n))) #define STRB_SIZE(sb) (STRBOFFSET + (sb)->str_size + STRB_ENTSIZE((sb))) /* Regexp wrapper structs. */ struct re { char *str; #ifndef PCRE regex_t re; #else pcre *pcre; #endif int flags; }; struct rm { int valid; size_t so; size_t eo; }; struct rmlist { int valid; struct rm list[NPMATCH]; }; /* Regexp flags. */ #define RE_IGNCASE 0x1 #define RE_NOSUBST 0x2 /* Cache data. */ struct cache { TDB_CONTEXT *db; char *path; uint64_t expire; TAILQ_ENTRY(cache) entry; }; struct cacheitem { uint64_t tim; uint32_t pad[4]; } __packed; /* A single mail. */ struct mail { u_int idx; double tim; struct strb *tags; struct shm shm; struct attach *attach; int attach_built; char *base; char *data; size_t off; size_t size; /* size of mail */ size_t space; /* size of allocated area */ size_t body; /* offset of body */ ARRAY_DECL(, size_t) wrapped; /* list of wrapped lines */ char wrapchar; /* wrapped character */ /* XXX move below into special struct and just cp it in mail_*? */ struct rmlist rml; /* regexp matches */ enum decision decision; /* final deliver decision */ void (*auxfree)(void *); void *auxdata; }; /* Mail match/delivery return codes. */ #define MAIL_CONTINUE 0 #define MAIL_DELIVER 1 #define MAIL_MATCH 2 #define MAIL_ERROR 3 #define MAIL_BLOCKED 4 #define MAIL_DONE 5 /* Mail match/delivery context. */ struct mail_ctx { int done; u_int msgid; struct account *account; struct io *io; struct mail *mail; struct rule *rule; ARRAY_DECL(, struct rule *) stack; struct expritem *expritem; int result; int matched; TAILQ_HEAD(, deliver_ctx) dqueue; TAILQ_ENTRY(mail_ctx) entry; }; TAILQ_HEAD(mail_queue, mail_ctx); /* An attachment. */ struct attach { u_int idx; size_t data; size_t body; size_t size; char *type; char *name; struct attach *parent; TAILQ_HEAD(, attach) children; TAILQ_ENTRY(attach) entry; }; /* Privsep message types. */ enum msgtype { MSG_ACTION, MSG_EXIT, MSG_DONE, MSG_COMMAND }; /* Privsep message data. */ struct msgdata { int error; struct mail mail; /* These only work so long as they aren't moved in either process. */ struct account *account; struct actitem *actitem; struct match_command_data *cmddata; uid_t uid; }; /* Privsep message buffer. */ struct msgbuf { void *buf; size_t len; }; /* Privsep message. */ struct msg { u_int id; enum msgtype type; size_t size; struct msgdata data; }; /* A single child. */ struct child { pid_t pid; struct io *io; void *data; int (*msg)(struct child *, struct msg *, struct msgbuf *); void *buf; size_t len; }; /* List of children. */ ARRAY_DECL(children, struct child *); /* Fetch child data. */ struct child_fetch_data { struct account *account; enum fdmop op; struct children *children; }; /* Deliver child data. */ struct child_deliver_data { void (*hook)(int, struct account *, struct msg *, struct child_deliver_data *, int *); struct child *child; /* the source of the request */ u_int msgid; const char *name; struct account *account; struct mail *mail; struct actitem *actitem; struct deliver_ctx *dctx; struct mail_ctx *mctx; struct match_command_data *cmddata; }; /* Users list. */ ARRAY_DECL(users, uid_t); /* Account entry. */ struct account { u_int idx; char name[MAXNAMESIZE]; struct users *users; int find_uid; int disabled; int keep; struct fetch *fetch; void *data; TAILQ_ENTRY(account) entry; }; /* Action item. */ struct actitem { u_int idx; struct deliver *deliver; void *data; TAILQ_ENTRY(actitem) entry; }; /* Action list. */ TAILQ_HEAD(actlist, actitem); /* Action definition. */ struct action { char name[MAXNAMESIZE]; struct users *users; int find_uid; struct actlist *list; TAILQ_ENTRY(action) entry; }; /* Actions arrays. */ ARRAY_DECL(actions, struct action *); /* Match areas. */ enum area { AREA_BODY, AREA_HEADERS, AREA_ANY }; /* Expression operators. */ enum exprop { OP_NONE, OP_AND, OP_OR }; /* Expression item. */ struct expritem { struct match *match; void *data; enum exprop op; int inverted; TAILQ_ENTRY(expritem) entry; }; /* Expression struct. */ TAILQ_HEAD(expr, expritem); /* Rule list. */ TAILQ_HEAD(rules, rule); /* Rule entry. */ struct rule { u_int idx; struct expr *expr; struct users *users; int find_uid; /* find uids from headers */ int stop; /* stop matching at this rule */ struct rules rules; struct action *lambda; struct replstrs *actions; TAILQ_ENTRY(rule) entry; }; /* Lock types. */ #define LOCK_FCNTL 0x1 #define LOCK_FLOCK 0x2 #define LOCK_DOTLOCK 0x4 /* Configuration settings. */ struct conf { int debug; int syslog; uid_t child_uid; gid_t child_gid; char *tmp_dir; struct strings incl; struct strings excl; struct proxy *proxy; struct strings *domains; /* domains to look for with users */ struct strings *headers; /* headers to search for users */ struct { int valid; uid_t last_uid; char *home; char *user; char *uid; char *host; char *fqdn; char *addr; } info; char *conf_file; char *lock_file; char *strip_chars; int check_only; int allow_many; int keep_all; int no_received; int verify_certs; u_int purge_after; enum decision impl_act; int queue_high; int queue_low; mode_t file_umask; gid_t file_group; size_t max_size; int timeout; int del_big; u_int lock_types; uid_t def_user; TAILQ_HEAD(, cache) caches; TAILQ_HEAD(, account) accounts; TAILQ_HEAD(, action) actions; struct rules rules; }; extern struct conf conf; /* Command flags. */ #define CMD_IN 0x1 #define CMD_OUT 0x2 #define CMD_ONCE 0x4 /* Command data. */ struct cmd { pid_t pid; int status; int flags; const char *buf; size_t len; struct io *io_in; struct io *io_out; struct io *io_err; }; /* Comparison operators. */ enum cmp { CMP_EQ, CMP_NE, CMP_LT, CMP_GT }; /* Configuration file (used by parser). */ struct file { FILE *f; int line; int rule_line; /* XXX */ const char *path; }; ARRAY_DECL(files, struct file *); #ifdef NO_SETRESUID #define setresuid(r, e, s) setreuid(r, e) #endif #ifdef NO_SETRESGID #define setresgid(r, e, s) setregid(r, e) #endif #ifdef NO_STRTONUM /* strtonum.c */ long long strtonum(const char *, long long, long long, const char **); #endif #ifdef NO_STRLCPY /* strlcpy.c */ size_t strlcpy(char *, const char *, size_t); #endif #ifdef NO_STRLCAT /* strlcat.c */ size_t strlcat(char *, const char *, size_t); #endif /* shm.c */ char *shm_path(struct shm *); void *shm_create(struct shm *, size_t); int shm_owner(struct shm *, uid_t, gid_t); void shm_destroy(struct shm *); void shm_close(struct shm *); void *shm_reopen(struct shm *); void *shm_resize(struct shm *, size_t, size_t); /* lex.c */ int yylex(void); /* parse.y */ extern struct macros parse_macros; extern struct files parse_filestack; extern struct file *parse_file; extern struct strb *parse_tags; int parse_conf(const char *, struct strings *); __dead printflike1 void yyerror(const char *, ...); printflike1 void yywarn(const char *, ...); /* parse-fn.c */ char *expand_path(const char *); char *run_command(const char *, const char *); char *fmt_replstrs(const char *, struct replstrs *); char *fmt_strings(const char *, struct strings *); char *fmt_users(const char *, struct users *); int have_accounts(char *); struct account *find_account(char *); struct action *find_action(char *); struct actions *match_actions(const char *); struct macro *extract_macro(char *); struct macro *find_macro(const char *); void find_netrc(const char *, char **, char **); void free_account(struct account *); void free_action(struct action *); void free_actitem(struct actitem *); void free_cache(struct cache *); void free_replstrs(struct replstrs *); void free_rule(struct rule *); void free_strings(struct strings *); void make_actlist(struct actlist *, char *, size_t); void print_action(struct action *); void print_rule(struct rule *); /* netrc.c */ FILE *netrc_open(const char *, char **); void netrc_close(FILE *); int netrc_lookup(FILE *, const char *, char **, char **); /* fdm.c */ double get_time(void); void dropto(uid_t); int check_incl(const char *); int check_excl(const char *); int use_account(struct account *, char **); void fill_info(const char *); /* re.c */ int re_compile(struct re *, const char *, int, char **); int re_string(struct re *, const char *, struct rmlist *, char **); int re_block(struct re *, const void *, size_t, struct rmlist *, char **); void re_free(struct re *); /* attach.c */ struct attach *attach_visit(struct attach *, u_int *); void printflike2 attach_log(struct attach *, const char *, ...); struct attach *attach_build(struct mail *); void attach_free(struct attach *); /* privsep.c */ int privsep_send(struct io *, struct msg *, struct msgbuf *); int privsep_check(struct io *); int privsep_recv(struct io *, struct msg *, struct msgbuf *); /* command.c */ struct cmd *cmd_start(const char *, int, const char *, size_t, char **); int cmd_poll(struct cmd *, char **, char **, char **, size_t *, int, char **); void cmd_free(struct cmd *); /* child.c */ int child_fork(void); __dead void child_exit(int); struct child *child_start(struct children *, uid_t, int (*)(struct child *, struct io *), int (*)(struct child *, struct msg *, struct msgbuf *), void *); /* child-fetch.c */ int open_cache(struct account *, struct cache *); int child_fetch(struct child *, struct io *); /* child-deliver.c */ int child_deliver(struct child *, struct io *); void child_deliver_action_hook(int, struct account *, struct msg *, struct child_deliver_data *, int *); void child_deliver_cmd_hook(int, struct account *, struct msg *, struct child_deliver_data *, int *); /* parent-fetch.c */ int parent_fetch(struct child *, struct msg *, struct msgbuf *); /* parent-deliver.c */ int parent_deliver(struct child *, struct msg *, struct msgbuf *); /* timer.c */ int timer_expired(void); void timer_set(int); void timer_cancel(void); /* connect.c */ char *sslerror(const char *); char *sslerror2(int, const char *); void getaddrs(const char *, char **, char **); struct proxy *getproxy(const char *); struct io *connectproxy(struct server *, int, struct proxy *, const char *, int, char **); struct io *connectio(struct server *, int, const char *, int, char **); /* file.c */ int printflike3 mkpath(char *, size_t, const char *, ...); int vmkpath(char *, size_t, const char *, va_list); int openlock(const char *, int, u_int); int createlock(const char *, int, uid_t, gid_t, mode_t, u_int); void closelock(int, const char *, u_int); int locksleep(const char *, const char *, long long *); int xcreate(const char *, int, uid_t, gid_t, mode_t); int xmkdir(const char *, uid_t, gid_t, mode_t); const char *checkmode(struct stat *, mode_t); const char *checkowner(struct stat *, uid_t); const char *checkgroup(struct stat *, gid_t); /* mail.c */ int mail_open(struct mail *, size_t); void mail_send(struct mail *, struct msg *); int mail_receive(struct mail *, struct msg *, int); void mail_close(struct mail *); void mail_destroy(struct mail *); int mail_resize(struct mail *, size_t); void line_init(struct mail *, char **, size_t *); void line_next(struct mail *, char **, size_t *); int printflike3 insert_header(struct mail *, const char *, const char *, ...); int remove_header(struct mail *, const char *); char *find_header(struct mail *, const char *, size_t *, int); char *match_header(struct mail *, const char *, size_t *, int); size_t find_body(struct mail *); void count_lines(struct mail *, u_int *, u_int *); int append_line(struct mail *, const char *, size_t); struct users *find_users(struct mail *); char *find_address(char *, size_t, size_t *); void trim_from(struct mail *); char *make_from(struct mail *); u_int fill_wrapped(struct mail *); void set_wrapped(struct mail *, char); /* mail-time.c */ char *rfc822time(time_t, char *, size_t); int mailtime(struct mail *, time_t *); /* mail-state.c */ int mail_match(struct mail_ctx *, struct msg *, struct msgbuf *); int mail_deliver(struct mail_ctx *, struct msg *, struct msgbuf *); /* db-tdb.c */ TDB_CONTEXT *db_open(char *); void db_close(TDB_CONTEXT *); int db_add(TDB_CONTEXT *, char *); int db_contains(TDB_CONTEXT *, char *); int db_size(TDB_CONTEXT *); int db_expire(TDB_CONTEXT *, uint64_t); /* cleanup.c */ void cleanup_check(void); void cleanup_flush(void); void cleanup_purge(void); void cleanup_register(const char *); void cleanup_deregister(const char *); /* strb.c */ void strb_create(struct strb **); void strb_clear(struct strb **); void strb_destroy(struct strb **); void strb_dump(struct strb *, const char *, void (*)(const char *, ...)); void printflike3 strb_add(struct strb **, const char *, const char *, ...); void strb_vadd(struct strb **, const char *, const char *, va_list); struct strbent *strb_find(struct strb *, const char *); struct strbent *strb_match(struct strb *, const char *); /* replace.c */ void printflike3 add_tag(struct strb **, const char *, const char *, ...); const char *find_tag(struct strb *, const char *); const char *match_tag(struct strb *, const char *); void default_tags(struct strb **, const char *); void update_tags(struct strb **); char *replacestr(struct replstr *, struct strb *, struct mail *, struct rmlist *); char *replacepath(struct replpath *, struct strb *, struct mail *, struct rmlist *); /* log.c */ void log_open(FILE *, int, int); void log_close(void); void log_vwrite(FILE *, int, const char *, va_list); void log_write(FILE *, int, const char *, ...); void printflike1 log_warn(const char *, ...); void printflike1 log_warnx(const char *, ...); void printflike1 log_info(const char *, ...); void printflike1 log_debug(const char *, ...); void printflike1 log_debug2(const char *, ...); void printflike1 log_debug3(const char *, ...); __dead void log_vfatal(const char *, va_list); __dead void log_fatal(const char *, ...); __dead void log_fatalx(const char *, ...); /* xmalloc.c */ void *ensure_size(void *, size_t *, size_t, size_t); void *ensure_for(void *, size_t *, size_t, size_t); char *xmemstrdup(const char *, size_t); char *xstrdup(const char *); void *xcalloc(size_t, size_t); void *xmalloc(size_t); void *xrealloc(void *, size_t, size_t); void xfree(void *); int printflike2 xasprintf(char **, const char *, ...); int xvasprintf(char **, const char *, va_list); int printflike3 xsnprintf(char *, size_t, const char *, ...); int xvsnprintf(char *, size_t, const char *, va_list); int printflike3 printpath(char *, size_t, const char *, ...); char *xdirname(const char *); char *xbasename(const char *); /* xmalloc-debug.c */ #ifdef DEBUG #define xmalloc_caller() __builtin_return_address(0) void xmalloc_clear(void); void xmalloc_report(pid_t, const char *); void xmalloc_new(void *, void *, size_t); void xmalloc_change(void *, void *, void *, size_t); void xmalloc_free(void *); #endif #endif /* FDM_H */