1 // -*-c++-*-
2 /* $Id$ */
3 
4 /*
5  *
6  * Copyright (C) 2004 David Mazieres (dm@uun.org)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2, or (at
11  * your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21  * USA
22  *
23  */
24 
25 #include "async.h"
26 #include "dns.h"
27 #include "parseopt.h"
28 #include "rxx.h"
29 #include "aios.h"
30 #include "ihash.h"
31 #include "list.h"
32 #include "qhash.h"
33 
34 #ifdef SASL
35 #include <sasl.h>
36 #endif /* SASL */
37 
38 #define AVENGER "avenger"
39 
40 #define MAX_ADDR_LEN 1024    /* RFC 821 says 256, so this should do */
41 
42 enum trust_level {
43   TRUST_NONE = 0,		// Default sanity-checking
44   TRUST_MAIL = 1,		// Allow forged sender address (e.g., evite)
45   TRUST_AUTH = 2,		// Allow mail relaying for authenticated user
46   TRUST_RCPT = 3,		// Allow mail relaying from known address
47   TRUST_LOCAL = 4,		// No mail quotas (localhost)
48 };
49 
50 enum spf_result {
51   SPF_INVALID,			// An invalid return state
52   SPF_PASS,
53   SPF_FAIL,
54   SPF_SOFTFAIL,
55   SPF_NEUTRAL,
56   SPF_NONE,
57   SPF_ERROR,
58   SPF_UNKNOWN,
59 };
60 struct spf_t;
61 
62 /* asmtpd.C */
63 struct synfp_collect;
64 struct rbl_status;
65 struct ipinfo;
66 struct newcon {
67   const sockaddr_in sin;
68   const int fd;
69   str name;
70   ipinfo *ii;
71   str synfp;
72   trust_level t;
73   ptr<hostent> h;
74   ptr<rbl_status> rs;
75   str dns_error;
76 
77   newcon (int fd, const sockaddr_in &sin);
78   void init ();
79 
80 private:
81   int cbpending;
82   bool failed;
83 
84   void ident_cb (str nn, ptr<hostent> hh, int err);
85   void ptr_cb (ptr<hostent> hh, int err);
86   void rbl_cb ();
87   void synfp_cb (str fp);
88   void maybe_start ();
89 };
90 extern int opt_verbose;
91 extern synfp_collect *synfpc;
92 extern str path_avenger;
93 extern str path_bindir;
94 extern str path_pfos;
95 extern bool terminated;
96 void toggle_listen (bool force = false);
97 
98 /* rbl.C */
99 struct rbl {
100   enum {
101     QUERY_IP = 0x1,		// Lookup reversed IP address (normal RBLs)
102     QUERY_PTR = 0x2,		// Lookup domain name, not IP address
103     QUERY_ENV = 0x4,		// Lookup domain name in envelope sender
104     TRUSTED = 0x8,		// Whitelist (e.g., wl.trusted-forwarder.org)
105   };
106   const str domain;		// Domain in which to perform lookups
107   const u_int flags;
108   const int score;
109 
110   rbl (str domain, u_int flags, int score);
111 };
112 struct rbl_status {
113   struct result {
114     str name;
115     vec<in_addr,1> vals;
116     void addval (in_addr addr);
117     bool hasval (in_addr addr) const;
118     str tostr (bool env) const;
119   };
120   struct rblerr {
121     str name;
122     int error;
rblerrrbl_status::rblerr123     rblerr (str n, int e) : name (n), error (e) {}
124   };
125 
126   bool trusted;
127   int score;			// Score contributed by IP and PTR queries
128   vec<result> results;
129   vec<rblerr> errors;
130 
rbl_statusrbl_status131   rbl_status () : trusted (false), score (0) {}
132   void addresult (const rbl *rp, in_addr val);
133 };
134 void rbl_check_con (ref<rbl_status> rs, const vec<ref<rbl> > &rblv,
135 		    in_addr addr, str hostname, cbv cb);
136 void rbl_check_env (ref<rbl_status> rs, const vec<ref<rbl> > &rblv,
137 		    str hostname, cbv cb);
138 
139 /* config.C */
140 struct ipmask {
141   u_int32_t net;
142   u_int32_t mask;
143 };
144 struct options {
145   struct ofunc {
146     const char *name;
147     str (options::*fn) (vec<str> &);
148   };
149 
150   u_int64_t configno;
151   str hostname;
152   str logtag;
153   str logpriority;
154   u_int smtp_timeout;
155   u_int data_timeout;
156   u_int client_timeout;
157   u_int vrfy_delay;
158   u_int vrfy_cachetime;
159   u_int max_clients;
160   u_int max_revclients;
161   u_int max_rcpts;
162   u_int max_relay_rcpts;
163   size_t max_msgsize;
164 
165   u_int con_max_per_ip;
166   u_int msg_max_per_ip;
167   u_int msg_rate_per_ip;
168   u_int err_max_per_ip;
169   u_int err_rate_per_ip;
170   u_int msg_max_per_user;
171   u_int msg_rate_per_user;
172   str smtp_filter;
173 
174   char separator;
175   bool synfp;
176   bool netpath;
177   int smtpcb;
178   bool debug_smtpd;
179   bool debug_smtpc;
180   bool debug_avenger;
181   bool user_mail;
182   bool user_rcpt;
183   bool allow_percent;
184   int allow_dnsfail;
185 
186   vec<sockaddr_in> bindaddrv;
187   bhash<sockaddr_in> bindaddrh;
188 
189   unsigned ident_timeout;
190   u_int synfp_wait;
191   u_int synfp_buf;
192   u_int osguess_mtu;
193 
194   str spf_fail;
195   str spf_none;
196   str spf_local;
197   str spf_exp;
198 
199   vec<ipmask> trustednets;
200   vec<str> trusteddomains;
201   bool mxlocal_rcpt;
202   bhash<str> nocheck;
203   vec<ref<rbl> > rbls;
204 
205   vec<str> sendmail;
206   str emptysender;
207   bool sendmailpriv;
208   bool sendmailfromline;
209 
210   bhash<str> envb;
211   vec<str> env;
212 
213   qhash<str, time_t> warn_filter;
214   time_t warn_filter_clean;
215 
216   passwd *av_user;
217   vec<GETGROUPS_T> av_groups;
218   u_int avenger_max_per_user;
219   u_int avenger_timeout;
220   str etcdir;
221   str alias_file;
222   str domain_file;
223   str spfhosts_file;
224 #ifdef SASL
225   int sasl;
226   int insecuresasl;
227 #endif /* SASL */
228 #ifdef STARTTLS
229   u_int ssl_keylen;
230   str ssl_ca;
231   str ssl_crl;
232   str ssl_cert;
233   str ssl_key;
234   int ssl_status;
235   str ssl_ciphers;
236   int ssl;
237 #endif /* STARTTLS */
238 
239   options ();
240   ~options ();
241 private:
242   str do_line (vec<str> &av, str cf, int line, bool *errp, conftab *ctp);
243 public:
244   static passwd *copypw (passwd *pw);
245   static void delpw (passwd *pw);
246 
247   str do_bindaddr (vec<str> &av);
248   str do_trustednet (vec<str> &av);
249   str do_trusteddomain (vec<str> &av);
250   str do_separator (vec<str> &av);
251   str do_maxmsgsperip (vec<str> &av);
252   str do_maxerrorsperip (vec<str> &av);
253   str do_maxmsgsperuser (vec<str> &av);
254   str do_smtpfilter (vec<str> &av);
255   str do_rbl (vec<str> &av);
256   str do_sendmail (vec<str> &av);
257   str do_avengeruser (vec<str> &av);
258   str do_nocheck (vec<str> &av);
259   str do_env (vec<str> &av);
260   str do_spfxxx (vec<str> &av);
261 
262   friend bool parseconfig (options *op, str cf);
263 };
264 extern str config_file;
265 extern options *opt;
266 bool parseconfig (options *op, str cf);
267 void maybe_warn (str msg);
268 
269 /* addrparse.C */
270 str extract_addr (const char **dpp, const char *prefix);
271 str extract_addr (const str &in, const char *prefix);
272 //str extract_relay (const char *addr);
273 str extract_local (const char *addr);
274 bool validate_local (str addr);
275 str extract_domain (const char *addr);
276 str extract_relay (const char *addr);
277 str domain_tolower (const char *addr);
278 bool validate_domain (const char *addr, bool uok = false);
279 
280 /* quota.C */
281 struct traceroute;
282 void run_cmd (const char *cmd, const char *arg1, const char *arg2 = NULL);
283 struct quota {
284   enum { msgmult = 60 };
285   time_t last;
286 
287 protected:
288   quota ();
~quotaquota289   virtual ~quota () {}
decay_varquota290   void decay_var (u_int &var, u_int rate, u_int interval) {
291     u_int d = interval * rate;
292     var = var > d ? var - d : 0;
293   }
check_varquota294   bool check_var (u_int var, u_int maxval) {
295     return var + msgmult <= maxval * msgmult;
296   }
297   virtual void do_decay (bool del, u_int interval) = 0;
298 
299 public:
300   void decay (bool del = false);
maybe_deletequota301   void maybe_delete () { decay (true); }
302 };
303 
304 struct ipinfo : public quota {
305   const in_addr addr;
306   bool filt;
307   u_int ncon;
308   u_int ndeliv;			// msgmult * # of successful RCPT commands
309   u_int nerr;			// msgmult * # of errors
310 
311   traceroute *trp;
312   time_t netpath_time;
313   int nhops;
314   str netpath;
315 
316   ihash_entry<ipinfo> link;
317 
318   static ipinfo *lookup (in_addr a, bool create);
319 
320   ipinfo (in_addr a);
321   ~ipinfo ();
322   void setfilter (bool);
323   void setfilter ();
324   void do_decay (bool del, u_int interval);
325 
326   void do_netpath (in_addr src);
327   void netpath_cb (int total_hops, in_addr *ap, int ac);
328 
329   str addcon ();
delconipinfo330   void delcon () { assert (ncon); ncon--; decay (true); }
erroripinfo331   void error () { nerr += msgmult; setfilter (); }
332   str rcpt ();
333   str status ();
334 };
335 
336 struct userinfo : public quota {
337   const str user;
338   u_int ndeliv;
339   ihash_entry<userinfo> link;
340 
341   userinfo (str u);
342   ~userinfo ();
343   void do_decay (bool del, u_int interval);
344 
345   static userinfo *lookup (str user, bool create);
346   str rcpt ();
rcptuserinfo347   static str rcpt (str u) { return lookup (u, true)->rcpt (); }
348 };
349 
350 void clear_filters ();
351 void quota_dump (const strbuf &sb);
352 
353 /* smtpd.C */
354 struct enqmsg;
355 struct progout;
356 struct avcount;
357 class smtpd {
358   ipinfo *const ii;
359 
360   ref<aios> aio;
361   const str name;
362   str synfp;
363   str osguess;
364   in_addr myipaddr;
365   u_int16_t mytcpport;
366   in_addr ipaddr;
367   u_int16_t tcpport;
368   bool pipelining;
369   bool colonspace;
370   bool post;
371   bool encrypted;
372   trust_level trust;
373   const ptr<const rbl_status> rblcon;
374   str dns_error;
375 
376   str helohost;
377   str msgid;
378   str fromaddr;
379   ptr<rbl_status> rblenv;
380   bool mask_spf;
381   spf_result spfr;
382   str spf_expl;
383   str spf_mech;
384   str bounce_res;
385   str mail_error;
386   ptr<mxlist> mxl;
387 
388   str auth_user;
389 #ifdef SASL
390   sasl_conn_t *sasl;
391   vec<str> saslstr;
392 #endif /* SASL */
393   str quota_user;
394 
395   vec<str> toaddr;
396   bool body_set;
397   str body_user;
398   str body_cmd;
399 
400   enum data_state_t { MIDLINE, NEWLINE, CR, DOT, DOTCR } data_state;
401   size_t data_msgsize;
402   str data_err;
403   enqmsg *data_q;
404   bool cmdwait;
405 
406   static str datestr (bool includezone = true);
407   static void dispatch_tab_init ();
408 
409   static str msgid_gen ();
410   void reset ();
411   str received ();
412   void getcmd (str line, int err);
413   void respond (str resp, bool counterr = true);
414 
415   void data_1 (str data, int err);
416   void data_2 (bool end, str err);
417   void data_3 (avcount *avc, ref<progout> po);
418   void data_4 (str err);
419 
420   void cmd_mail_2 (str addr);
421   void cmd_mail_3 (str addr, spf_result res, str, str);
422   void cmd_mail_4 (str addr, str err, ptr<mxlist> mxl);
423   void cmd_rcpt_0 (str cmd, str arg, int, in_addr *, int);
424   void cmd_rcpt_2 (str addr, int err);
425   void cmd_rcpt_3 (str addr, str errmsg);
426   void cmd_rcpt_4 (str addr, str errmsg, int local);
427   void cmd_rcpt_5 (str addr, str errmsg, str err);
428   void cmd_rcpt_6 (str addr, str err);
429 
cmd_rset(str,str)430   void cmd_rset (str, str) { reset (); respond ("250 ok\r\n"); }
431   void cmd_mail (str, str);
432   void cmd_rcpt (str, str);
433   void cmd_data (str, str);
cmd_vrfy(str,str)434   void cmd_vrfy (str, str) { respond ("252 try delivery with RCPT\r\n"); }
435 
436 #ifdef STARTTLS
437   void cmd_starttls (str, str);
438   str helo_starttls ();
439   void received_starttls (strbuf r) const;
440   void env_starttls (vec<str> *envp) const;
441   void set_quota_user ();
442 #endif /* STARTTLS */
443 
444   void cmd_auth (str, str);
445 #ifdef SASL
446   void cmd_auth_2 (int res, const char *out, unsigned outlen);
447   void cmd_auth_3 (str line, int err);
448 #endif /* SASL */
449   str helo_auth ();
450 public:
451   static const str okstr;
452   static u_int num_smtpd;
453   static u_int num_indata;
454   const ptr<const hostent> ptr_cache;
455   list_entry<smtpd> link;
456 
457   static bool tmperr (int err);
458   static str line_wrap (str in);
459 
460   smtpd (ipinfo *ii, int fd, const sockaddr_in &sin,
461 	 str name, str synfp, trust_level trust,
462 	 ptr<rbl_status> rs, ptr<hostent> h, str dns_error);
463   ~smtpd ();
464 
465   str bodycheck (str user, str cmd, str defresp);
466 
get_addr()467   in_addr get_addr () const { return ipaddr; }
get_name()468   str get_name () const { return name; }
get_helo()469   str get_helo () const { return helohost; }
get_from()470   str get_from () const { return fromaddr; }
get_spfr()471   spf_result get_spfr () const { return spfr; }
get_spf_expl()472   str get_spf_expl () const { return spf_expl; }
get_mxl()473   ptr<const mxlist> get_mxl () const { return mxl; }
get_rbl()474   ptr<rbl_status> get_rbl () const { return rblenv; }
475   void envinit (vec<str> *envp, struct passwd *pw) const;
476 
477   void maybe_shutdown ();
478 };
479 extern list<smtpd, &smtpd::link> smtplist;
480 
481 /* runprog.C */
482 struct progout {
483   int status;
484   vec<str> output;
progoutprogout485   progout () : status (-1) {}
progoutprogout486   explicit progout (str line)
487     : status (-1) { output.push_back (line); }
488   str response (int errcode);
489 };
490 struct rpstate;
491 typedef callback<void, ref<progout> >::ref runprogcb_t;
492 rpstate *runprog (const char *prog, const char **av, int infd,
493 		  bool collect_err, runprogcb_t cb,
494 		  cbv::ptr postforkcb, const char *const *env = NULL);
495 void runprog_cancel (rpstate *rps);
496 void runprog_timeout (rpstate *rps, int sec);
497 struct passwd *validuser (const char *user, bool reqshell = true);
498 void become_user (struct passwd *pw, bool grouplist = true);
499 str exitstr (int status);
500 
501 /* avif.C */
502 struct avcount {
503   const uid_t uid;
504   int num;
505   vec<cbv> waiters;
506   bool release_lock;
507   ihash_entry<avcount> link;
508 
509   avcount (uid_t u);
510   ~avcount ();
511   bool acquire ();
512   void release ();
513   static avcount *get (uid_t u);
514 };
515 extern ihash<const uid_t, avcount, &avcount::uid, &avcount::link> avctab;
516 class avif {
517 public:
518   enum disp_t {
519     DONE,			// Finish immediately with status message
520     NEXT,			// Continue on to default rules
521     REDIR,			// Redirect to a particular user
522     BODY,			// Run command on body of message
523   };
524   typedef callback<void, disp_t, str>::ref cb_t;
525 private:
526   struct result {
527     str res;
528     tailq_entry<result> link;
529     cbv::ptr abortcb;
~resultresult530     ~result () { if (abortcb && !res) (*abortcb) (); }
531   };
532 
533   const cb_t cb;
534   const smtpd *const smtp;
535   pid_t pid;
536   const ref<aios> aio;
537   const str name;
538   avcount *const avc;
539   tailq<result, &result::link> reslist;
540 
541   str retcode;
542   strbuf retbuf;
543 
544   static void chldinit (struct passwd *pw, int fd, bool sys, str ext);
545 
546   avif (const smtpd *, str name, avcount *avc, pid_t pid, int fd, cb_t cb);
547   ~avif ();
548   void init ();
newres()549   result *newres ()
550     { result *rp = New result; reslist.insert_tail (rp); return rp; }
delres(result * rp)551   void delres (result *rp) { reslist.remove (rp); delete (rp); }
552   void input (str line, int err);
553   void badinput (str);
554   void spf_cb (str var, result *rp, bool one, spf_t *spf);
555   void dns_a_cb (str var, result *rp, ptr<hostent> h, int err);
556   void dns_ptr_cb (str var, result *rp, ptr<hostent> h, int err);
557   void dns_mx_cb (str var, result *rp, ptr<mxlist> mxl, int err);
558   void dns_txt_cb (str var, result *rp, ptr<txtlist> t, int err);
559   void netpath_cb1 (str var, int hops, result *rp, ptr<hostent> h, int err);
560   void netpath_cb2 (str var, result *rp, int nhops, in_addr *av, int an);
561   void maybe_reply ();
562   void reap (int status);
563 
564 public:
565   static void alloc (struct passwd *pw, const smtpd *s,
566 		     str recip, char mode, avcount *, str ext,
567 		     str avuser, cb_t cb, str extraenv = NULL);
568 };
569 
570 /* enqmsg.C */
571 class enqmsg {
572 public:
~enqmsg()573   virtual ~enqmsg () {}
574   virtual bool init (str from, const vec<str> &to, str received_line) = 0;
575   virtual void writev (suio *uiop, cbs) = 0;
576   virtual void commit (cbs) = 0;
getfd()577   virtual int getfd () { return -1; }
578   //virtual str name () { return ""; }
579 };
580 
581 class enqmsg_dummy : public enqmsg {
init(str from,const vec<str> & to,str received_line)582   bool init (str from, const vec<str> &to, str received_line)
583     { panic ("enqmsg_dummy::init\n"); }
writev(suio * uiop,cbs cb)584   void writev (suio *uiop, cbs cb) { (*cb) (strerror (EINVAL)); }
commit(cbs cb)585   void commit (cbs cb) { (*cb) (strerror (EINVAL)); }
586 };
587 
588 class enqmsg_file : public enqmsg {
589   int fd;
590   int efd;
591   bool error;
592   bool eof;
593   str from;
594   const vec<str> *top;
595   rpstate *rps;
596 
597   void smcb (str sm, cbs cb, ref<progout> po);
598 
599 public:
600   static vec<const char *> mini_env;
601   static str spooldir;
602   static str get_spooldir ();
603   static void init_mini_env ();
604 
605   str path;
606 
607   enqmsg_file ();
608   ~enqmsg_file ();
609   bool init (str from, const vec<str> &to, str received_line);
610   void writev (suio *uiop, cbs);
611   void commit (cbs);
612   int getfd ();
name()613   str name () { return path ? path : str (""); }
614 };
615 
616 /* vrfy.C */
617 typedef callback<void, str, ptr<mxlist> >::ref vrfycb_t;
618 void vrfy (in_addr bindaddr, str addr, in_addr cli, vrfycb_t cb);
619 
620 /* rcptcheck.C */
621 struct map_base {
622   qhash<str, str> table;
623   time_t latest;
624   u_int64_t loadno;
625 
map_basemap_base626   map_base () : loadno (0) {}
~map_basemap_base627   virtual ~map_base () {}
628   virtual str path () = 0;
629   virtual rxx &linerx ();
630   bool load ();
631 };
632 struct domain_map : public map_base {
pathdomain_map633   str path () { return opt->domain_file; }
634   bool lookup (str *avuser, str recip);
hasentrydomain_map635   int hasentry (str recip) {
636     if (!load ())
637       return -1;
638     str d = extract_domain (recip);
639     return d && table[mytolower (d)];
640   }
641 };
642 struct localcheck {
643   smtpd *const smtp;
644   const str recip;
645   const cbs cb;
646 
647   char mode;
648   bool try_user;
649   str unknown_user;		// If user doesn't exist
650   str fallback_user;		// If user exists and returns NULL
651 
652   bhash<str> loop;
653   u_int depth;
654   str avuser;
655   str execuser;
656   bool indefault;
657 
658   localcheck (smtpd *s, str recip, char mode, cbs cb);
659   void init ();
660 
661 private:
662   void reply (str res, str bodycmd = NULL);
663   void avenge ();
664   void avenge_1 ();
665   void dodefault ();
666   void avenge_2 (avif::disp_t disp, str res);
667   str modeenv ();
668 };
669 extern domain_map dmap;
670 /* mode:
671    'r' - Run user rcpt script or unknown, then default
672    'R' - Run secondary script
673    'm' - Run user mail script, then relay
674    'M' - Run relay
675  */
676 void rcptcheck (smtpd *s, str recip, char mode, cbs cb);
677 
678 /* mxcheck.C */
679 /* Returns:
680  *   0 if this host is highest-priority MX record,
681  *   -1 if this host is an MX record
682  *   NXDOMAIN or NXREC if this host is not an MX record
683  *   err if there is a temporary DNS error
684  */
685 void ismxlocal (str relay, cbi cb, ptr<mxlist> = NULL);
686 
687 /* spf.C */
688 struct spfhosts_map : public map_base {
pathspfhosts_map689   str path () { return opt->spfhosts_file; }
690   rxx &linerx ();
691   bool lookup (str *spfrecp, str domain);
692 };
693 struct spf_t {
694   typedef callback<void, spf_t *>::ref cb_t;
695 
696   cb_t::ptr cb;
697   const in_addr addr;
698   const str sender;
699   ptr<const hostent> ptr_cache;
700   str helo;
701   str domain;
702   spfhosts_map *fallback;
703   str spfrec;
704   str curmech;
705 
706   spf_result result;
707   str explain;
708   bool has_mx;
709 
710 private:
711   int tracedepth;
712   int recdepth;
713   ref<bhash<str> > loopcheck;
714 
715   int ptr_cache_err;
716   vec<str> mechv;
717   str expdn;
718   str redirect;
719 
720   char prefix;
721   dnsreq_t *dnsrq;
722   spf_t *recurse;
723 
ip4_maskspf_t724   static u_int32_t ip4_mask (u_int cidrlen) {
725     if (cidrlen >= 32)
726       return 0xffffffff;
727     return htonl (0xffffffffU << (32 - cidrlen));
728   }
729   static bool suffix_check (const char *targ, str suffix);
730   bool macro_subst_inner (const strbuf &sb, str in, bool exp);
731   bool macro_subst (str *out, str in, bool exp = false);
732   bool addr_check (int cidrlen, ref<hostent> h);
ptrokspf_t733   bool ptrok () { return ptr_cache || ptr_cache_err; }
734   void getptr (cbv cb);
735   void getptr_2 (cbv cb, ptr<hostent> h, int err);
736 
737   friend void spf_cancel (spf_t *);
738   ~spf_t ();
739   void finish (spf_result stat);
740   void getexp (cbv cb, ptr<txtlist> t, int err);
741   void gettxt (ptr<txtlist> t, int err);
742   void parse_spf ();
743 
744   void mech_start ();
745   void mech_end (spf_result res);
746   void mech_include (str targ);
747   void mech_include_2 (spf_t *);
748   void mech_a (str targ);
749   void mech_a_2 (int cidrlen, ptr<hostent> h, int err);
750   void mech_mx (str targ);
751   void mech_mx_2 (int cidrlen, ptr<mxlist> mxl, int err);
752   void mech_mx_3 (int cidrlen, ptr<mxlist> mxl, int n,
753 		  ptr<hostent> h, int err);
754   void mech_ptr (str targ);
755   void mech_ip4 (str targ);
756   void mech_ip6 (str targ);
757   void mech_exists (str targ);
758   void mech_exists_2 (str targ, ptr<hostent> h, int err);
759 
760 public:
761   spf_t (in_addr addr, str from,
762 	 ptr<bhash<str> > loopcheck = NULL, int recdepth = 0);
763   void init ();
764 };
765 inline void
spf_cancel(spf_t * spf)766 spf_cancel (spf_t *spf)
767 {
768   delete spf;
769 }
770 typedef callback<void, spf_result, str, str>::ref spfckcb_t;
771 extern spfhosts_map smap;
772 void spf_check (in_addr a, str from, spfckcb_t cb,
773 		str helo = NULL, ptr<const hostent> ptrc = NULL);
774 const char *spf_print (spf_result res);
775 const char *spf1_print (spf_result res);
776 
777 /* starttls.C */
778 #ifdef STARTTLS
779 bool ssl_init ();
780 #else /* !STARTTLS */
781 #define ssl_init()
782 #endif /* !STARTTLS */
783