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