00001 /* libspf - Sender Policy Framework library 00002 * 00003 * ANSI C implementation of spf-draft-200405.txt 00004 * 00005 * Author: James Couzens <jcouzens@codeshare.ca> 00006 * Author: Sean Comeau <scomeau@obscurity.org> 00007 * 00008 * FILE: spf.h 00009 * DESC: main library header file 00010 * 00011 * License: 00012 * 00013 * The libspf Software License, Version 1.0 00014 * 00015 * Copyright (c) 2004 James Couzens & Sean Comeau All rights 00016 * reserved. 00017 * 00018 * Redistribution and use in source and binary forms, with or without 00019 * modification, are permitted provided that the following conditions 00020 * are met: 00021 * 00022 * 1. Redistributions of source code must retain the above copyright 00023 * notice, this list of conditions and the following disclaimer. 00024 * 00025 * 2. Redistributions in binary form must reproduce the above copyright 00026 * notice, this list of conditions and the following disclaimer in 00027 * the documentation and/or other materials provided with the 00028 * distribution. 00029 * 00030 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 00031 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00032 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00033 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS MAKING USE OF THIS LICESEN 00034 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00035 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00036 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 00037 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00038 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00039 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00040 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00041 * SUCH DAMAGE. 00042 * 00043 */ 00044 00045 00046 #ifndef _SPF_H 00047 #define _SPF_H 1 00048 00049 #include <sys/types.h> /* typedefs */ 00050 #include <netinet/in.h> /* in_addr struct fBSD */ 00051 #include <arpa/inet.h> /* in_addr struct */ 00052 00053 __BEGIN_DECLS 00054 00055 00056 /* spf protocol version we support */ 00057 #define SPF_VERSION 1 00058 00059 /* 00060 * For reference purposes commented out are the constants based on 00061 * RFC 883, RFC 1034, RFC 1035. 00062 * 00063 * #define PACKETSZ 512 max response packet size 00064 * #define MAXDNAME 1025 max uncompressed IN_TXT record 00065 * #define MAXCDNAME 255 max compressed IN_TXT record 00066 * 00067 */ 00068 00069 #define SPF_MAX_CNAME 5 /* we follow up max CNAMEs */ 00070 #define SPF_MAX_DEBUG 2048 /* maximum for debug code to malloc */ 00071 #define SPF_MAX_MACRO 1024 /* max length of an expanded macro */ 00072 #define SPF_MAX_STR 4096 /* max length of any dynamically allocated string */ 00073 #define SPF_MAX_DELIM 255 /* used by UTIL_count_delim() */ 00074 00075 #define SPF_MAX_LOCAL_PART 256 /* local-part, text before @ in email addy */ 00076 #define SPF_MAX_ENV_SENDER 512 /* entire FROM: string passed by MTA */ 00077 #define SPF_MAX_CUR_DOM 256 /* text after @ in email addy for cur query */ 00078 #define SPF_MAX_UTC_TIME 22 /* time since epoch */ 00079 #define SPF_MAX_IP_ADDR 17 /* ip of remote peer - DON'T CHANGE FROM 17!! */ 00080 #define SPF_MAX_IP_VER 8 /* ip protocol version */ 00081 #define SPF_MAX_ENV_HELO 512 /* entire HELO string passed by MTA */ 00082 00083 #define SPF_MAX_HNAME 256 /* hostname of MTA */ 00084 #define SPF_MAX_RESULT 64 /* human readable SPF result */ 00085 #define SPF_MAX_ERROR 96 /* human readable error reason */ 00086 #define SPF_MAX_EXPLAIN_S 256 /* change to EXPLAIN when cleaning up */ 00087 #define SPF_MAX_ENV_RECV 512 /* maximum length of RFC2821 header string */ 00088 #define SPF_MAX_RES_STR 12 /* maximum legnth of a res str eg: "pass" */ 00089 00090 #define SPF_MAX_MECHANISM 256 /* maximum length of a mechanism */ 00091 #define SPF_MAX_HEADER 512 /* maximum length of header for prepend */ 00092 #define SPF_MAX_SMTP_RES 256 /* maximum length of smtp resonse string */ 00093 00094 /* human readable string equivalents of spf responses */ 00095 #define HR_RFC2822 "Received-SPF: " 00096 #define HR_PASS "pass" 00097 #define HR_NONE "none" 00098 #define HR_S_FAIL "softfail" 00099 #define HR_H_FAIL "fail" 00100 #define HR_ERROR "error" 00101 #define HR_NEUTRAL "neutral" 00102 #define HR_UNKNOWN "unknown" 00103 #define HR_UNMECH "unknown mechanism" 00104 00105 /* default explanation */ 00106 #define SPF_EXPLAIN "See http://spf.pobox.com/why.html?sender=%{S}&" \ 00107 "ip=%{I}&receiver=%{xR}" 00108 00109 /* default best guess */ 00110 #define SPF_GUESS "v=spf1 a/24 mx/24 ptr " 00111 00112 /* trusted forwarder */ 00113 #define SPF_TRUSTED "v=spf1 include:spf.trusted-forwarder.org " 00114 00115 00116 /* SPF_BOOL 00117 * 00118 * Our own internal boolean enumeration, simple true or false. 00119 * 00120 * Sendmail has issues because it makes use of SPF_FALSE and SPF_TRUE 00121 * Simple way around it iis to simply check and see if they are 00122 * defined or not since we're declaring this enumeration 00123 * globally. 00124 * 00125 * A more graceful fix has been implemented in libspf 3.0 where 00126 * we now make use of SPF_SPF_TRUE and SPF_SPF_FALSE to steer clear of 00127 * problems such as this elsewhere. 00128 * 00129 */ 00130 00131 typedef enum SPF_BOOL 00132 { 00133 SPF_FALSE = 0, 00134 SPF_TRUE 00135 } SPF_BOOL; 00136 00137 00138 /* SPF_RESULT 00139 * 00140 * Error codes representing the result of an SPF policy examination 00141 * 00142 * sucessful parse (some match was made) (+all) 00143 * not participating (no SPF/TXT records) 00144 * ~all 00145 * failed parse (no match made) (-all) 00146 * dns problem / error 00147 * ?all 00148 * permanent parsing error during record examination 00149 * 00150 */ 00151 typedef enum SPF_RESULT 00152 { 00153 SPF_PASS = 0, /* + */ 00154 SPF_NONE, 00155 SPF_S_FAIL, /* ~ */ 00156 SPF_H_FAIL, /* - */ 00157 SPF_ERROR, 00158 SPF_NEUTRAL, /* ? */ 00159 SPF_UNKNOWN, 00160 SPF_UNMECH /* unknown mechanism */ 00161 } SPF_RESULT; 00162 00163 00164 /* SPF_ACTION 00165 * 00166 * Error codes representing the the action to be taken as a result 00167 * of the response the library was able to obtain whilst trying to 00168 * obtain or examin an SPF policy 00169 * 00170 */ 00171 typedef enum SPF_ACTION 00172 { 00173 DEFER = 0, 00174 TARPIT, 00175 ALLOW, 00176 REJECT 00177 } SPF_ACTION; 00178 00179 00180 /* SPF_MECHANISM 00181 * 00182 * Error codes representing the various mechanism types employed 00183 * as defined in the RFC 00184 * 00185 */ 00186 #undef VERSION /* autoconf */ 00187 typedef enum SPF_MECHANISM 00188 { 00189 NO_POLICY = 0, 00190 VERSION, 00191 ALL, 00192 INCLUDE, 00193 A, 00194 MX, 00195 PTR, 00196 IP4, 00197 IP6, 00198 EXISTS, 00199 REDIRECT, 00200 EXPLAIN, 00201 DEFAULT, /* this is OLD school for early adopters = ~,?,+,- */ 00202 UNMECH 00203 } SPF_MECHANISM; 00204 00205 00206 /* spf_result_t 00207 * 00208 * Storage container used to store the result of an SPF parse. 00209 * 00210 */ 00211 typedef struct spf_result_t 00212 { 00213 size_t sl; /* spf result string length */ 00214 char s[32]; /* spf result type string */ 00215 SPF_RESULT i; /* spf result type */ 00216 size_t hl; /* length of header string */ 00217 char h[512]; /* Received-SPF: header string */ 00218 char p; /* prefix identifier */ 00219 } spf_result_t; 00220 00221 00222 /* policy_addr_t 00223 * 00224 * Storage container used to store parsed out ip addresses in their 00225 * binary format (in_addr struct) and an unsigned integer containing 00226 * the netmask 00227 * 00228 */ 00229 typedef struct policy_addr_s 00230 { 00231 SPF_RESULT prefix; /* spf prefix (-,+,~,?) */ 00232 int8_t cidr; /* address cidr length */ 00233 struct in_addr addr; /* in_addr struct (unsigned long) */ 00234 } policy_addr_t; 00235 00236 00237 /* spf_config_t 00238 * 00239 * Global config structure 00240 * 00241 */ 00242 typedef struct spf_config_s 00243 { 00244 int level; /* debug level bit */ 00245 } spf_config_t; 00246 00247 00248 /* split_str_node_t 00249 * 00250 * This structure is used to store where the head and tail are when 00251 * creating a list of split_str_node_t structures. 00252 * 00253 */ 00254 typedef struct strbuf_node_s 00255 { 00256 size_t len; /* length of string */ 00257 char *s; /* expanded string macro */ 00258 struct strbuf_node_s *next; /* pointer to next node */ 00259 } strbuf_node_t; 00260 00261 00262 /* strbuf_t 00263 * 00264 * This structure is used exclusively by marco.c functions and is used 00265 * to store macros during parsing. 00266 * 00267 */ 00268 typedef struct strbuf_s 00269 { 00270 strbuf_node_t *head; /* head node */ 00271 u_int8_t elements; /* number of nodes in list */ 00272 } strbuf_t; 00273 00274 00275 /* split_str_node_t 00276 * 00277 * This structure is used to store where the head and tail are when 00278 * creating a list of split_str_node_t structures. 00279 * 00280 */ 00281 typedef struct split_str_node_s 00282 { 00283 size_t len; /* length of string */ 00284 char *s; /* expanded string macro */ 00285 struct split_str_node_s *next; /* pointer to next node */ 00286 } split_str_node_t; 00287 00288 00289 /* split_str_t 00290 * 00291 * This structure is used exclusively by the UTIL_reverse function and is 00292 * used to reverse a string using a semi-arbitrary delimiter (see 00293 * UTIL_is_spf_delim for valid delimiters, or the SPF RFC) 00294 */ 00295 typedef struct split_str_s 00296 { 00297 split_str_node_t *head; /* head node */ 00298 split_str_node_t *tail; /* tail node */ 00299 int elements; /* number of nodes in list */ 00300 } split_str_t; 00301 00302 00303 /* peer_info_t 00304 * 00305 * Used to store information about the connected peer. Only one of 00306 * SMTP protocol specific three strings will be necessarily be 00307 * populated in the following order of precedence: FROM, EHLO, HELO. 00308 * 00309 * The ip_ver string will contain 'in-addr' if the connecting peer 00310 * is using IPv4, or 'ip6' if the connect 00311 * 00312 * Various political and technical pressures have recently led to 00313 * the deprecation of the IP6.INT name space in favour of IP6.ARPA. 00314 * This makes IPv6 PTR data management difficult, since interim 00315 * clients will search IP6.INT while standard clients will search 00316 * IP6.ARPA. We present a simple method based on DNAME RR's 00317 * (see [RFC2672]) and ISC BIND9 whereby zone information can be 00318 * managed in a single location and then made visible in two 00319 * namespaces. (http://www.isc.org/tn/isc-tn-2002-1.html) 00320 * 00321 * RFC 937 (POP) states: The maximum length of a command line is 512 00322 * characters (including the command word and the CRLF). 00323 * POLICY_MATCH = SPF_TRUE 00324 * 00325 * Note: from can be removed and just work on local_part@cur_dom 00326 * 00327 */ 00328 typedef struct peer_info_s 00329 { 00330 SPF_BOOL ALL; /* Was 'all' mechanism parsed */ 00331 00332 SPF_RESULT RES; /* SPF error codes for result */ 00333 SPF_RESULT RES_P; /* prefix behaviour */ 00334 00335 SPF_BOOL use_trust; /* T / F trustedfwder */ 00336 SPF_BOOL use_guess; /* T / F best guess */ 00337 00338 u_int8_t spf_ver; /* version of SPF */ 00339 00340 char *p; /* prefix from all mechanism */ 00341 char *rs; /* ptr str result of SPF query */ 00342 char *helo; /* HELO string */ 00343 char *ehlo; /* pointer to HELO string */ 00344 char *from; /* FROM string */ 00345 char *explain; /* Result of an explain query */ 00346 char *guess; /* Query if result is TF fails */ 00347 char *trusted; /* Query if primary result is none */ 00348 char *ptr_mhost; /* validate against during ptr mech */ 00349 char *current_domain; /* @domain of the current query */ 00350 char *mta_hname; /* ptr to MTA hname eg: mail.foo.org */ 00351 char *r_ip; /* pointer to remote ip from MTA */ 00352 char *r_vhname; /* validated hostname of remotehost */ 00353 char *cur_eaddr; /* current email address */ 00354 00355 char ip_ver[SPF_MAX_IP_VER]; /* IP Protocol Version */ 00356 char local_part[SPF_MAX_LOCAL_PART]; /* local part of address (user) */ 00357 char utc_time[SPF_MAX_UTC_TIME]; /* The number of seconds since the Epoch */ 00358 char last_m[SPF_MAX_MECHANISM]; /* last mechanism parsed */ 00359 char error[SPF_MAX_ERROR]; /* error (if any) that caused failure */ 00360 00361 spf_result_t *spf_result; /* table of str, see spf_result_t */ 00362 00363 struct in_addr addr; /* IP of the remote host (peer) */ 00364 00365 /* 00366 * Vars below here are specific to recursion through layers of SPF queries 00367 * stemming from 'include' and 'redirect' use. In addition there is a 00368 * also a buffer for CNAME records. 00369 */ 00370 00371 uint8_t spf_rlevel; /* recursion level */ 00372 00373 char *cname_buf; /* buf for CNAME records */ 00374 char *include_buf; /* buf for 'include' instances */ 00375 char *redirect_buf; /* buf for 'redirect' instances */ 00376 00377 } peer_info_t; 00378 00379 extern spf_config_t confg; 00380 extern u_int8_t spf_rlevel; 00381 00382 /* Main library functions (main.c) */ 00383 extern peer_info_t *SPF_init(const char *, const char *, const char *, const char *, 00384 const char *, u_int32_t, u_int32_t); 00385 extern peer_info_t *SPF_close(peer_info_t *); 00386 extern SPF_RESULT SPF_policy_main(peer_info_t *); 00387 extern SPF_RESULT SPF_policy_main_rec(peer_info_t *); 00388 extern SPF_BOOL SPF_parse_policy(peer_info_t *, const char *); 00389 extern char *SPF_result(peer_info_t *); 00390 extern SPF_BOOL SPF_smtp_from(peer_info_t *, const char *); 00391 extern SPF_BOOL SPF_smtp_helo(peer_info_t *, const char *); 00392 00393 /* Functions that alter headers (header.c) */ 00394 extern char *SPF_build_header(peer_info_t *); 00395 extern char *SPF_get_explain(peer_info_t *); 00396 00397 00398 00399 __END_DECLS /* _SPF_H */ 00400 00401 #endif /* spf.h */