/* * Copyright (c) 1999-2006 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * * $Id: pmfapi.h,v 1.37 2007/02/16 02:39:09 ca Exp $ */ /* ** PMFAPI.H -- Global definitions for policy mail filter library ** and policy mail filters. */ #ifndef PMFAPI_H #define PMFAPI_H 1 /* libpmilter version */ #define LPMILTER_VERSION_MAJOR 0x01 #define LPMILTER_VERSION_MINOR 0x0000 #define LPMILTER_VERSION_PL 0x00 #define LPMILTER_VERSION ((LPMILTER_VERSION_MAJOR << 24) + \ (LPMILTER_VERSION_MINOR << 8) + \ LPMILTER_VERSION_PL) #define SM_PM_VRS_MAJOR(v) (((v) & 0x7f000000) >> 24) #define SM_PM_VRS_MINOR(v) (((v) & 0x007fff00) >> 8) #define SM_PM_VRS_PLVL(v) ((v) & 0x0000007f) #ifdef WIN32 # include #endif #include "sm/pmfdef.h" #ifdef WIN32 /* ** The following ifdef block is the standard way of creating macros which make ** exporting from a DLL simpler. All files within this DLL are compiled with ** the LIBMILTER_EXPORTS symbol defined. LIBMILTER_EXPORTS should not be ** defined on any project that uses this DLL. This way any other project whose ** source files include this file see LIBSASL_API functions as being imported ** from a DLL, wheras this DLL sees symbols defined with this macro as being ** exported. ** Under UNIX, life is simpler: we just need to mark library functions ** as extern. (Technically, we don't even have to do that.) */ # ifdef WIN32_DLL # ifdef LIBMILTER_EXPORTS # define LIBMILTER_API __declspec( dllexport ) # else # define LIBMILTER_API __declspec( dllimport ) # endif # else # define LIBMILTER_API extern # endif #else /* WIN32 */ # define LIBMILTER_API extern #endif /* WIN32 */ #ifdef WIN32 /* ** Disable warning messages for differences in parameter lists. ** The Microsoft compiler spits out a warning message if a ** function pointer is assigned to another function pointer, ** but the formal parameter lists of the functions do not agree. ** The assignments are compiled without modification though, ** so it's safe to disable this warning message. */ #pragma warning( disable : 4113 ) #endif /* WIN32 */ /* Only need to export C interface if used by C++ source code */ #ifdef __cplusplus extern "C" { #endif #ifndef SM_NET_H #include #include #include #include #include /* ** generic sockaddr structure for sendmail ** make parts of this conditional, compare sendmail8/sendmail/sendmail.h */ union sm_sockaddr_U { struct sockaddr sa; /* general version */ struct sockaddr_un sunix; /* UNIX family */ struct sockaddr_in sin; /* INET family */ }; typedef union sm_sockaddr_U sm_sockaddr_T, *sm_sockaddr_P; #endif /* SM_NET_H */ /* ** libmilter functions return SM_PMI_SUCCESS to indicate success; ** a value < 0 indicates an error. */ #define SM_PMI_SUCCESS 0 #define SM_PMI_FAILURE (-1) /* ** Type which callbacks should return to indicate message status. ** This may take on one of the SMFIS_* values listed below. */ typedef int sfsistat_T; /* XREF: must be smaller than QSS_RC_MAXSZ, see sm/qmgrcomm.h */ #define PMILTER_CHUNK_SIZE (256 * 1024) #if defined(QSS_RC_MAXSZ) && QSS_RC_MAXSZ < PMILTER_CHUNK_SIZE ERROR: _QSS_RC_MAXSZ >= _PMILTER_CHUNK_SIZE #endif /* ** Filter Routine Details */ /* ** PMFI_NEGOTIATE -- check whether server capabilities and functions are ** acceptable/sufficient */ typedef sm_ret_T (*pmfi_negotiate_F)(pmss_ctx_P _pmss_ctx, uint32_t _srv_cap, uint32_t _srv_fct, uint32_t _srv_feat, uint32_t _srv_misc, uint32_t *_pm_cap, uint32_t *_pm_fct, uint32_t *_pm_feat, uint32_t *_pm_misc); /* ** PMFI_CONNECT -- SMTP connection ** ** hostname -- Host domain name, as determined by a reverse lookup ** on the host address. ** hostaddr -- Host address, as determined by a getpeername ** call on the SMTP socket. */ typedef sfsistat_T (*pmfi_connect_F)(pmse_ctx_P _pmse_ctx, const char *_hostname, sm_sockaddr_T *_hostaddr); /* ** PMFI_HELO -- SMTP HELO/EHLO command ** ** helohost -- Value passed to HELO/EHLO command, which should be ** the domain name of the sending host (but is, in practice, ** anything the sending host wants to send). ** ehlo -- was EHLO used? */ typedef sfsistat_T (*pmfi_helo_F)(pmse_ctx_P _pmse_ctx, const char *_helohost, bool _ehlo); /* ** PMFI_STARTTLS -- STARTTLS */ typedef sfsistat_T (*pmfi_starttls_F)(pmse_ctx_P _pmse_ctx); /* ** PMFI_AUTH -- AUTH */ typedef sfsistat_T (*pmfi_auth_F)(pmse_ctx_P _pmse_ctx, const char *_arg); /* ** PMFI_MAIL -- envelope MAIL From ** ** argv -- Null-terminated SMTP command arguments; */ typedef sfsistat_T (*pmfi_mail_F)(pmse_ctx_P _pmse_ctx, const char *_mail, char **_argv); /* ** PMFI_RCPT -- envelope recipient ** ** char **argv -- Null-terminated SMTP command arguments; */ typedef sfsistat_T (*pmfi_rcpt_F)(pmse_ctx_P _pmse_ctx, const char *_rcpt, char **_argv); /* ** PMFI_DATA -- DATA */ typedef sfsistat_T (*pmfi_data_F)(pmse_ctx_P _pmse_ctx); /* ** PMFI_UNKNOWN -- unknown/not implemented SMTP command ** ** cmd -- Null-terminated SMTP command */ typedef sfsistat_T (*pmfi_unknown_F)(pmse_ctx_P _pmse_ctx, const char *_cmd); /* ** PMFI_MSG -- message chunk ** There may be multiple message chunks passed to the filter. End-of-lines are ** represented as received from SMTP (normally Carriage-Return/Line-Feed). ** ** msgp -- Pointer to message data ** msglen -- Length of message data */ typedef sfsistat_T (*pmfi_msg_F)(pmse_ctx_P _pmse_ctx, unsigned char *_msgp, size_t _msglen); /* ** PMFI_EOM -- end of message. */ typedef sfsistat_T (*pmfi_eom_F)(pmse_ctx_P _pmse_ctx); /* ** PMFI_MSG_RPLC -- message replacement: send one chunk */ typedef sfsistat_T (*pmfi_msg_rplc_F)(pmse_ctx_P _pmse_ctx, const unsigned char **_pmsgchunk, size_t *_pmsglen); /* ** PMFI_MSG_RPLC_STAT -- message replacement status */ typedef sfsistat_T (*pmfi_msg_rplc_stat_F)(pmse_ctx_P _pmse_ctx, sm_ret_T _status); /* ** PMFI_ABORT -- message is aborted outside of the control of ** the filter, for example, if the SMTP sender issues an RSET command. If ** pmfi_abort is called, pmfi_eom will not be called and vice versa. */ typedef sm_ret_T (*pmfi_abort_F)(pmse_ctx_P _pmse_ctx); /* ** PMFI_CLOSE -- end of the connection. This is called on ** close even if the previous mail transaction was aborted. */ typedef sm_ret_T (*pmfi_close_F)(pmse_ctx_P _pmse_ctx); /* XXX which context? */ typedef sm_ret_T (*pmfi_signal_F)(pmg_ctx_P _pmg_ctx, int _sig); /* ** structure describing one milter */ struct pmilter_S { char *pmfi_name; /* filter name */ uint32_t pmfi_version; /* version code -- do not change */ /* what does the milter want by default? */ uint32_t pmfi_dfl_cap; /* capabilities */ uint32_t pmfi_dfl_fct; /* functions */ uint32_t pmfi_dfl_feat; /* features */ uint32_t pmfi_dfl_misc; /* misc. */ /* negotiate */ pmfi_negotiate_F pmfi_negotiate; /* connect */ pmfi_connect_F pmfi_connect; /* HELO/EHLO */ pmfi_helo_F pmfi_helo; /* MAIL */ pmfi_mail_F pmfi_mail; /* RCPT */ pmfi_rcpt_F pmfi_rcpt; /* DATA */ pmfi_data_F pmfi_data; /* msg block */ pmfi_msg_F pmfi_msg; /* end of message */ pmfi_eom_F pmfi_eom; /* message aborted */ pmfi_abort_F pmfi_abort; /* connection cleanup */ pmfi_close_F pmfi_close; /* any unrecognized or unimplemented command filter */ pmfi_unknown_F pmfi_unknown; pmfi_signal_F pmfi_signal; /* STARTTLS */ pmfi_starttls_F pmfi_starttls; /* AUTH */ pmfi_auth_F pmfi_auth; pmfi_msg_rplc_F pmfi_msg_rplc; pmfi_msg_rplc_stat_F pmfi_msg_rplc_stat; char pmfi_unused[64]; }; LIBMILTER_API sm_ret_T sm_pmfi_init(pmg_ctx_P *_pmg_ctx); LIBMILTER_API sm_ret_T sm_pmfi_version(pmg_ctx_P _pmg_ctx, uint32_t *_major, uint32_t *_minor, uint32_t *_patchlevel); LIBMILTER_API sm_ret_T sm_pmfi_setconn(pmg_ctx_P _pmg_ctx, const char *_path); LIBMILTER_API sm_ret_T sm_pmfi_start(pmg_ctx_P _pmg_ctx, pmilter_P _pmilter); LIBMILTER_API sm_ret_T sm_pmfi_setdbg(pmg_ctx_P _pmg_ctx, unsigned int _debuglevel); LIBMILTER_API sm_ret_T sm_pmfi_stop(pmg_ctx_P _pmg_ctx); #if 0 /* not yet implemented */ LIBMILTER_API sm_ret_T sm_pmfi_setbacklog(pmg_ctx_P _pmg_ctx, int _backlog); LIBMILTER_API sm_ret_T sm_pmfi_settimeout(pmg_ctx_P _pmg_ctx, int _timeout); /* is this needed?? */ LIBMILTER_API sm_ret_T sm_pmfi_opensocket(pmg_ctx_P _pmg_ctx, bool _rmsocket); /* not needed LIBMILTER_API sm_ret_T sm_pmfi_register(pmg_ctx_P _pmg_ctx, pmilter_P _pmilter); */ #endif /* ** set/get pmilter contexts */ /* "global" pmilter context: one per process */ LIBMILTER_API sm_ret_T sm_pmfi_set_ctx_g(pmg_ctx_P _pmg_ctx, void *_pmilter_g_ctx); LIBMILTER_API void *sm_pmfi_get_ctx_g(pmg_ctx_P _pmg_ctx); /* pmilter context per SMTP server */ LIBMILTER_API sm_ret_T sm_pmfi_set_ctx_ss(pmss_ctx_P _pmss_ctx, void *_pmilter_ss_ctx); LIBMILTER_API void *sm_pmfi_get_ctx_ss(pmss_ctx_P _pmss_ctx); /* get "global" context from ss context */ LIBMILTER_API void *sm_pmfi_get_ctx_g_ss(pmss_ctx_P _pmss_ctx); /* pmilter context per SMTP session */ LIBMILTER_API sm_ret_T sm_pmfi_set_ctx_se(pmse_ctx_P _pmse_ctx, void *_pmilter_se_ctx); LIBMILTER_API void *sm_pmfi_get_ctx_se(pmse_ctx_P _pmse_ctx); /* get ss context from session context */ LIBMILTER_API void *sm_pmfi_get_ctx_ss_se(pmse_ctx_P _pmse_ctx); /* ** Continue processing message/connection. */ #define SMFIS_CONTINUE SMTP_R_OK /* ** Reject the message/connection. ** No further routines will be called for this message ** (or connection, if returned from a connection-oriented routine). */ #define SMFIS_REJECT SMTP_R_REJECT /* ** Accept the command, but silently discard it. ** No further routines will be called for this message. ** This is only meaningful from message-oriented routines. */ #define SMFIS_DISCARD SMTP_R_DISCARD /* ** Accept the message/connection. ** No further routines will be called for this message ** (or connection, if returned from a connection-oriented routine; ** in this case, it causes all messages on this connection ** to be accepted without filtering). */ #define SMFIS_ACCEPT SMTP_R_SET_QUICK(SMTP_R_OK) /* ** Return a temporary failure, i.e., ** the corresponding SMTP command will return a 4xx status code. ** In some cases this may prevent further routines from ** being called on this message or connection, ** although in other cases (e.g., when processing an envelope ** recipient) processing of the message will continue. */ #define SMFIS_TEMPFAIL SMTP_R_TEMP /* ** Additional information is passed in to the vendor filter routines using ** symbols. Symbols correspond closely to sendmail macros. The symbols ** defined depend on the context. The value of a symbol is accessed using: */ /* ** Set list of macros that should be sent by MTA ** ** pmss_ctx -- Opaque context structure ** where -- Which stage? (PM_SMST_*, see pmfdef.h) ** macro -- The symbols to send (PMM_*, see pmfdef.h), ** must end with PMM_END */ LIBMILTER_API sm_ret_T sm_pmfi_setmaclist(pmss_ctx_P _pmss_ctx, uint _where, ...); /* ** Get value of a symbol. ** ** pmse_ctx_P ctx -- Opaque context structure ** macro -- The symbol to access (PMM_*, see pmfdef.h) ** value -- (pointer to) value of symbol */ LIBMILTER_API sm_ret_T sm_pmfi_getmac(pmse_ctx_P _pmse_ctx, uint32_t _macro, char **_pvalue); /* ** Set the specific reply code to be used in response to the active ** command. If not specified, a generic reply code is used. ** ** pmse_ctx -- Opaque context structure ** reply -- The text part of the SMTP reply (including error codes). */ LIBMILTER_API sm_ret_T sm_pmfi_setreply(pmse_ctx_P _pmse_ctx, const char *_reply); /* ** Set reply codes to be used in response to the active command if multiple ** replies are required. ** ** pmse_ctx -- Opaque context structure ** nreplies -- number of replies ** rcodes -- array of nreplies reply codes ** rtexts -- array of nreplies reply texts */ LIBMILTER_API sm_ret_T sm_pmfi_setreplies(pmse_ctx_P _pmse_ctx, uint _nreplies, int *_rcodes, const char **_rtexts); /* ** Get status of current SMTP command as set by SMTPS. ** Currently only available for RCPT (if requested) ** ** pmse_ctx -- Opaque context structure ** pstatus -- (pointer to) status (output) */ LIBMILTER_API sm_ret_T sm_pmfi_getstatus(pmse_ctx_P _pmse_ctx, sfsistat_T *_pstatus); /* ** Get index of current RCPT command as set by SMTPS. ** ** pmse_ctx -- Opaque context structure ** prcpt_idx -- (pointer to) recipient index (output) */ LIBMILTER_API sm_ret_T sm_pmfi_getrcpt_idx(pmse_ctx_P _pmse_ctx, rcpt_idx_T *_prcpt_idx); /* ** header modification request ** ** pmse_ctx -- Opaque context structure ** type -- type of modification ** pos -- header position ** header -- complete header field (name and value) */ LIBMILTER_API sm_ret_T sm_pmfi_hdr_mod(pmse_ctx_P _pmse_ctx, uint _type, uint _pos, const unsigned char *_header); /* ** recipient addition request ** ** pmse_ctx -- Opaque context structure ** rcpt_pa -- recipient address to add (RFC 2821 format) ** argv -- list of SMTP parameter for RCPT, NULL terminated list. ** argv == NULL: use original ** argv[0] == NULL: no parameters */ LIBMILTER_API sm_ret_T sm_pmfi_rcpt_add(pmse_ctx_P _pmse_ctx, const char *_rcpt_pa, char **_argv); /* ** recipient deletion request ** ** pmse_ctx -- Opaque context structure ** rcpt_pa -- recipient address to delete (RFC 2821 format) ** rcpt_idx -- index of recipient address to delete */ LIBMILTER_API sm_ret_T sm_pmfi_rcpt_del(pmse_ctx_P _pmse_ctx, const char *_rcpt_pa, rcpt_idx_T _rcpt_idx); /* ** MAIL replacement request ** ** pmse_ctx -- Opaque context structure ** mail_pa -- mail address to use instead of original (RFC 2821 format) ** args -- ESMTP parameters for MAIL ** args == NULL: use original ** args[0] == NUL: no parameters */ LIBMILTER_API sm_ret_T sm_pmfi_mail_rplc(pmse_ctx_P _pmse_ctx, const char *_mail_pa, char *_argv); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* ! PMFAPI_H */