/* This file is part of gacopyz. Copyright (C) 2006, 2007 Sergey Poznyakoff This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef __gacopyz_h__ # define __gacopyz_h__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define GACOPYZ_VERSION_MAJOR 1 #define GACOPYZ_VERSION_MINOR 0 /* Implementation version number */ #define SMFI_VERSION 2 /* commands: don't use anything smaller than ' ' */ #define SMFIC_ABORT 'A' /* Abort */ #define SMFIC_BODY 'B' /* Body chunk */ #define SMFIC_CONNECT 'C' /* Connection information */ #define SMFIC_MACRO 'D' /* Define macro */ #define SMFIC_BODYEOB 'E' /* final body chunk (End) */ #define SMFIC_HELO 'H' /* HELO/EHLO */ #define SMFIC_HEADER 'L' /* Header */ #define SMFIC_MAIL 'M' /* MAIL from */ #define SMFIC_EOH 'N' /* EOH */ #define SMFIC_OPTNEG 'O' /* Option negotiation */ #define SMFIC_QUIT 'Q' /* QUIT */ #define SMFIC_RCPT 'R' /* RCPT to */ #define SMFIC_DATA 'T' /* DATA (SMFI_VERSION > 3) */ #define SMFIC_UNKNOWN 'U' /* Any unknown command */ /* actions (replies) */ #define SMFIR_ADDRCPT '+' /* add recipient */ #define SMFIR_DELRCPT '-' /* remove recipient */ #define SMFIR_ACCEPT 'a' /* accept */ #define SMFIR_REPLBODY 'b' /* replace body (chunk) */ #define SMFIR_CONTINUE 'c' /* continue */ #define SMFIR_DISCARD 'd' /* discard */ #define SMFIR_CONN_FAIL 'f' /* cause a connection failure */ #define SMFIR_CHGHEADER 'm' /* change header */ #define SMFIR_PROGRESS 'p' /* progress */ #define SMFIR_REJECT 'r' /* reject */ #define SMFIR_TEMPFAIL 't' /* tempfail */ #define SMFIR_SHUTDOWN '4' /* 421: shutdown (internal to MTA) */ #define SMFIR_ADDHEADER 'h' /* add header */ #define SMFIR_INSHEADER 'i' /* insert header */ #define SMFIR_REPLYCODE 'y' /* reply code etc */ #define SMFIR_QUARANTINE 'q' /* quarantine */ /* What the MTA can send/filter wants in protocol */ #define SMFIP_NOCONNECT 0x00000001L /* MTA should not send connect info */ #define SMFIP_NOHELO 0x00000002L /* MTA should not send HELO info */ #define SMFIP_NOMAIL 0x00000004L /* MTA should not send MAIL info */ #define SMFIP_NORCPT 0x00000008L /* MTA should not send RCPT info */ #define SMFIP_NOBODY 0x00000010L /* MTA should not send body */ #define SMFIP_NOHDRS 0x00000020L /* MTA should not send headers */ #define SMFIP_NOEOH 0x00000040L /* MTA should not send EOH */ #define SMFIP_NOHREPL 0x00000080L /* No reply for headers */ #define SMFIP_NOUNKNOWN 0x00000100L /* MTA should not send unknown command */ #define SMFIP_NODATA 0x00000200L /* MTA should not send DATA */ /* The protocol of V1 filter */ #define SMFI_V1_PROT (SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NOMAIL|\ SMFIP_NORCPT|SMFIP_NOBODY|SMFIP_NOHDRS) /* The protocol of V2 filter */ #define SMFI_V2_PROT (SMFI_V1_PROT|SMFIP_NOEOH) /* Flags, defining milter capabilities */ #define SMFIF_NONE 0x00000000L /* no flags */ #define SMFIF_ADDHDRS 0x00000001L /* filter may add headers */ #define SMFIF_CHGBODY 0x00000002L /* filter may replace body */ #define SMFIF_MODBODY SMFIF_CHGBODY /* backwards compatible */ #define SMFIF_ADDRCPT 0x00000004L /* filter may add recipients */ #define SMFIF_DELRCPT 0x00000008L /* filter may delete recipients */ #define SMFIF_CHGHDRS 0x00000010L /* filter may change/delete headers */ #define SMFIF_QUARANTINE 0x00000020L /* filter may quarantine envelope */ #define SMFI_V1_ACTS (SMFIF_ADDHDRS|SMFIF_CHGBODY|SMFIF_ADDRCPT|SMFIF_DELRCPT) #define SMFI_V2_ACTS (SMFI_V1_ACTS|SMFIF_CHGHDRS|SMFIF_QUARANTINE) #define SMFI_DEFAULT_ACTS SMFI_V2_ACTS #define SMFI_DEFAULT_PROT SMFI_V2_PROT /* Log levels */ #define SMI_LOG_DEBUG 0 #define SMI_LOG_INFO 1 #define SMI_LOG_WARN 2 #define SMI_LOG_ERR 3 #define SMI_LOG_FATAL 4 #define SMI_LOG_MASK(n) (1<<(n)) #define SMI_LOG_UPTO(n) ((1 << ((n)+1))-1) /* all levels through n */ #define SMI_LOG_FROM(n) (SMI_LOG_UPTO(SMI_LOG_FATAL) & ~SMI_LOG_UPTO(n-1)) #define SMI_DEFAULT_LOG_MASK SMI_LOG_MASK(SMI_LOG_INFO) \ | SMI_LOG_MASK(SMI_LOG_WARN) \ | SMI_LOG_MASK(SMI_LOG_ERR) \ | SMI_LOG_MASK(SMI_LOG_FATAL) /* address families */ #define SMFIA_UNKNOWN 'U' /* unknown */ #define SMFIA_UNIX 'L' /* unix/local */ #define SMFIA_INET '4' /* inet */ #define SMFIA_INET6 '6' /* inet6 */ /* Function return codes */ #define MI_SUCCESS 0 #define MI_FAILURE (-1) /* Data types */ typedef struct smfi_str SMFICTX; typedef struct smfi_str *SMFICTX_PTR; typedef struct gacopyz_conn *gacopyz_conn_t; typedef struct gacopyz_iod *gacopyz_iod_t; /* Return type for the callbacks */ typedef enum { SMFIS_CONTINUE, SMFIS_REJECT, SMFIS_DISCARD, SMFIS_ACCEPT, SMFIS_TEMPFAIL } sfsistat; typedef union { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_un sunix; } milter_sockaddr_t; #define _SOCK_ADDR milter_sockaddr_t struct smfiDesc { char *xxfi_name; /* filter name */ int xxfi_version; /* version code */ unsigned long xxfi_flags; /* flags */ /* Filters: */ /* connection info */ sfsistat (*xxfi_connect) (SMFICTX *, char *, milter_sockaddr_t *); /* SMTP HELO command */ sfsistat (*xxfi_helo) (SMFICTX *, char *); /* envelope sender */ sfsistat (*xxfi_envfrom) (SMFICTX *, char **); /* envelope recipient */ sfsistat (*xxfi_envrcpt) (SMFICTX *, char **); /* header */ sfsistat (*xxfi_header) (SMFICTX *, char *, char *); /* end of header */ sfsistat (*xxfi_eoh) (SMFICTX *); /* body block */ sfsistat (*xxfi_body) (SMFICTX *, unsigned char *, size_t); /* end of message */ sfsistat (*xxfi_eom) (SMFICTX *); /* message aborted */ sfsistat (*xxfi_abort) (SMFICTX *); /* connection cleanup */ sfsistat (*xxfi_close) (SMFICTX *); /* any unrecognized or unimplemented command (SMFI_VERSION > 2) */ sfsistat (*xxfi_unknown) (SMFICTX *, char *); /* SMTP DATA command (SMFI_VERSION > 3) */ sfsistat (*xxfi_data) (SMFICTX *); /* Extensions: */ int (*xxfi_start) (void); /* Child start callback */ int (*xxfi_finish) (void); /* Child finish callback */ int (*xxfi_idle) (gacopyz_conn_t); /* Idle handler */ }; /* Standard API calls */ extern int smfi_opensocket (int); extern int smfi_register (struct smfiDesc); extern int smfi_main (void); extern int smfi_setbacklog (int); extern int smfi_setdbg (int); extern int smfi_settimeout (time_t); extern int smfi_setconn (char *); extern int smfi_stop (void); #define smfi_getsymval gacopyz_getsymval int smfi_addheader (SMFICTX *, char *, char *); int smfi_chgheader (SMFICTX *, char *, int, char *); int smfi_insheader (SMFICTX *, int, char *, char *); int smfi_addrcpt (SMFICTX *, char *); int smfi_delrcpt (SMFICTX *, char *); int smfi_progress (SMFICTX *); int smfi_replacebody (SMFICTX *, unsigned char *, int); int smfi_quarantine (SMFICTX *ctx, char *reason); #define smfi_setpriv gacopyz_setpriv #define smfi_getpriv gacopyz_getpriv size_t smfi_setmaxdatasize (size_t); /* Replies: */ extern int smfi_setreply (SMFICTX *, char *, char *, char *); int smfi_setmlreply (SMFICTX *, const char *, const char *, ...); /* Extensions */ extern int smfi_set_foreground(int val); extern int smfi_setlogmask(int logmask); /* New API calls: */ int gacopyz_init(gacopyz_conn_t *pconn, struct smfiDesc *desc); void gacopyz_free(gacopyz_conn_t conn); int gacopyz_set_logmask(gacopyz_conn_t conn, int mask); int gacopyz_get_logmask(gacopyz_conn_t conn, int *mask); int gacopyz_set_foreground(gacopyz_conn_t conn, int fg); int gacopyz_set_master_timeout(gacopyz_conn_t conn, struct timeval *timeout); int gacopyz_get_master_timeout(gacopyz_conn_t conn, struct timeval *timeout); int gacopyz_set_ctx_timeout(gacopyz_conn_t conn, struct timeval *timeout); int gacopyz_get_ctx_timeout(gacopyz_conn_t conn, struct timeval *timeout); int gacopyz_stop(gacopyz_conn_t conn); int gacopyz_open(gacopyz_conn_t conn, const char *cstr, int backlog, int rmsocket); int gacopyz_parse_connection(const char *cstr, char **pproto, char **pport, char **ppath); int gacopyz_connect(gacopyz_conn_t *, struct smfiDesc *, const char *, int backlog, int rmsocket); int gacopyz_get_fd(gacopyz_conn_t); int gacopyz_run(gacopyz_conn_t); int gacopyz_register_child(gacopyz_conn_t conn, pid_t pid); void gacopyz_cleanup_children(gacopyz_conn_t conn); void gacopyz_cleanup_conn(gacopyz_conn_t conn); void gacopyz_setup_signals(void); char *gacopyz_getsymval (SMFICTX *, char *); int gacopyz_setreply(SMFICTX *ctx, const char *rcode, const char *xcode, const char *message); int gacopyz_setmlreply_v(SMFICTX *ctx, const char *rcode, const char *xcode, ...); int gacopyz_setmlreply_va(SMFICTX *ctx, const char *rcode, const char *xcode, va_list ap); int _gacopyz_setmlreply_va(SMFICTX *ctx, size_t max, const char *rcode, const char *xcode, va_list ap); int gacopyz_add_header(SMFICTX *ctx, const char *headerf, const char *headerv); int gacopyz_insert_header(SMFICTX *ctx, int index, const char *headerf, const char *headerv); int gacopyz_change_header(SMFICTX *ctx, int index, const char *headerf, const char *headerv); int gacopyz_add_rcpt(SMFICTX *ctx, const char *rcpt); int gacopyz_del_rcpt(SMFICTX *ctx, const char *rcpt); int gacopyz_replace_body(SMFICTX *ctx, unsigned char *bodyp, size_t bodylen); int gacopyz_progress(SMFICTX *ctx); int gacopyz_quarantine(SMFICTX *ctx, const char *reason); int gacopyz_setpriv (SMFICTX *ctx, void *data); void *gacopyz_getpriv (SMFICTX *ctx); /* Logging (extensions) */ #define GACOPYZ_VBUFSIZE 69 size_t gacopyz_format_vbuf(char vbuf[GACOPYZ_VBUFSIZE], const char *buf, size_t size); void gacopyz_log(gacopyz_conn_t conn, int level, char *fmt, ...); void gacopyz_io_log(gacopyz_iod_t iod, int level, char *fmt, ...); void gacopyz_logmsg(int level, char *fmt, ...); void _gacopyz_logdump(int logmask, int level, const char *pfx, const char *buf, size_t size); void gacopyz_logdump(gacopyz_conn_t conn, int level, const char *pfx, const char *buf, size_t size); void gacopyz_io_logdump(gacopyz_iod_t iod, int level, const char *pfx, const char *buf, size_t size); void gacopyz_set_logger(void (*)(int, char *, va_list)); void gacopyz_stderr_log_printer(int level, char *fmt, va_list ap); void gacopyz_syslog_log_printer(int level, char *fmt, va_list ap); int gacopyz_string_to_log_level(const char *str); const char *gacopyz_log_level_to_string(int level); /* Server */ typedef struct gacopyz_srv *gacopyz_srv_t; int gacopyz_srv_create(gacopyz_srv_t *p, const char *name, const char *portspec, unsigned logmask); int gacopyz_srv_create_X(gacopyz_srv_t *p, const char *spec, unsigned logmask); void gacopyz_srv_destroy(gacopyz_srv_t *p); int gacopyz_srv_find_macro (gacopyz_srv_t srv, const char *name, const char **pval); void gacopyz_srv_define_macro (gacopyz_srv_t srv, const char *name, const char *value); void gacopyz_srv_define_macro0 (gacopyz_srv_t srv, const char *name, const char *value, int overwrite); void gacopyz_srv_del_macro (gacopyz_srv_t srv, const char *name); void gacopyz_srv_clear_macros (gacopyz_srv_t srv); void gacopyz_srv_iterate_macros (gacopyz_srv_t srv, int (*func) (const char *name, const char *value, void *data), void *data); void gacopyz_srv_count_macros (gacopyz_srv_t srv, size_t *count); int gacopyz_srv_connect (gacopyz_srv_t srv); int gacopyz_srv_init(gacopyz_srv_t srv); int gacopyz_srv_negotiate(gacopyz_srv_t srv); int gacopyz_srv_abort(gacopyz_srv_t srv); int gacopyz_srv_quit(gacopyz_srv_t srv); int gacopyz_srv_helo (gacopyz_srv_t p, const char *domain); int gacopyz_srv_envfrom (gacopyz_srv_t p, char **argv); int gacopyz_srv_envrcpt (gacopyz_srv_t p, char **argv); int gacopyz_srv_header (gacopyz_srv_t p, char *name, char *value); int gacopyz_srv_eoh (gacopyz_srv_t p); int gacopyz_srv_body (gacopyz_srv_t p, unsigned char *str, size_t size); int gacopyz_srv_eom (gacopyz_srv_t p, unsigned char *str, size_t size); int gacopyz_srv_abort (gacopyz_srv_t p); int gacopyz_srv_close (gacopyz_srv_t p); int gacopyz_srv_data (gacopyz_srv_t p); int gacopyz_srv_onerror(gacopyz_srv_t srv, int code); void gacopyz_srv_set_memerror(gacopyz_srv_t srv, void (*memerror)(gacopyz_srv_t, const char *, unsigned int)); int gacopyz_srv_set_source(gacopyz_srv_t srv, unsigned long addr); int gacopyz_srv_set_version(gacopyz_srv_t srv, int version); int gacopyz_srv_set_protocol(gacopyz_srv_t srv, int proto); int gacopyz_srv_set_actions(gacopyz_srv_t srv, int acts); #define GACOPYZ_WRITE_TIMEOUT 10 #define GACOPYZ_READ_TIMEOUT 10 #define GACOPYZ_EOM_TIMEOUT 300 #define GACOPYZ_CONNECT_TIMEOUT 300 #define GACOPYZ_TO_WRITE 0 /* Timeout for sending information */ #define GACOPYZ_TO_READ 1 /* Timeout waiting for a response */ #define GACOPYZ_TO_EOM 2 /* Timeout for ACK/NAK to EOM */ #define GACOPYZ_TO_CONNECT 3 /* Timeout for connect() */ #define GACOPYZ_TO_COUNT 4 void gacopyz_srv_set_all_timeouts(gacopyz_srv_t srv, struct timeval *tvp); int gacopyz_srv_set_timeout(gacopyz_srv_t srv, unsigned n, struct timeval *tvp); int gacopyz_srv_set_timeout_sec(gacopyz_srv_t srv, unsigned n, time_t t); void gacopyz_srv_reply(gacopyz_srv_t srv, char **msg, size_t *size); #ifdef __cplusplus } #endif #endif /* __gacopyz_h__ */