libspf2  1.2.11
spf_compile.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of either:
4  *
5  * a) The GNU Lesser General Public License as published by the Free
6  * Software Foundation; either version 2.1, or (at your option) any
7  * later version,
8  *
9  * OR
10  *
11  * b) The two-clause BSD license.
12  *
13  * These licenses can be found with the distribution in the file LICENSES
14  */
15 
16 #include "spf_sys_config.h"
17 #include "spf_internal.h"
18 
19 
20 #ifdef STDC_HEADERS
21 # include <stdio.h> /* stdin / stdout */
22 # include <stdlib.h> /* malloc / free */
23 # include <ctype.h> /* isupper / tolower */
24 #endif
25 
26 #ifdef HAVE_INTTYPES_H
27 #include <inttypes.h>
28 #endif
29 
30 #ifdef HAVE_STRING_H
31 # include <string.h> /* strstr / strdup */
32 #else
33 # ifdef HAVE_STRINGS_H
34 # include <strings.h> /* strstr / strdup */
35 # endif
36 #endif
37 
38 
39 
40 #undef SPF_ALLOW_DEPRECATED_DEFAULT
41 
42 #include "spf.h"
43 #include "spf_internal.h"
44 #include "spf_response.h"
45 #include "spf_record.h"
46 
47 typedef
48 enum SPF_cidr_enum {
51 
52 typedef
53 enum SPF_domspec_enum {
56 
62 #define SPF_RECORD_BUFSIZ 4096
63 
64 #define ALIGN_DECL(decl) union { double d; long l; decl } __attribute__((aligned(_ALIGN_SZ))) u
65 #define ALIGNED_DECL(var) u.var
66 
67 
68 
69 typedef
70 struct SPF_mechtype_struct
71 {
72  unsigned char mech_type;
73  unsigned char is_dns_mech;
77 
78 static const SPF_mechtype_t spf_mechtypes[] = {
89 };
90 
91 #define spf_num_mechanisms \
92  sizeof(spf_mechtypes) / sizeof(spf_mechtypes[0])
93 
94 static const SPF_mechtype_t *
95 SPF_mechtype_find(int mech_type)
96 {
97  size_t i;
98  for (i = 0; i < spf_num_mechanisms; i++) {
99  if (spf_mechtypes[i].mech_type == mech_type)
100  return &spf_mechtypes[i];
101  }
102  return NULL;
103 }
104 
105 __attribute__((warn_unused_result))
106 static int
107 SPF_c_ensure_capacity(void **datap, size_t *sizep, size_t length)
108 {
109  size_t size = *sizep;
110  if (length > size)
111  size = length + (length / 4);
112  if (size > *sizep) {
113  void *tmp = realloc(*datap, size);
114  if (!tmp)
115  return -1;
116  // memset(tmp + *sizep, 'C', (size - *sizep));
117  *datap = tmp;
118  *sizep = size;
119  }
120  return 0;
121 }
122 
132 static SPF_errcode_t
133 SPF_c_parse_cidr_ip6(SPF_response_t *spf_response,
134  unsigned char *maskp,
135  const char *src)
136 {
137  int mask;
138 
139  /*
140  if (spf_server->debug > 2)
141  SPF_debugf("Parsing ip6 CIDR starting at %s", src);
142  */
143 
144  mask = strtoul(src + 1, NULL, 10);
145 
146  if (mask > 128) {
147  return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_CIDR,
148  NULL, src,
149  "Invalid IPv6 CIDR netmask (>128)");
150  }
151  else if (mask == 0) {
152  return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_CIDR,
153  NULL, src,
154  "Invalid IPv6 CIDR netmask (=0)");
155  }
156  else if (mask == 128) {
157  mask = 0;
158  }
159 
160  *maskp = mask;
161 
162  return SPF_E_SUCCESS;
163 }
164 
174 static SPF_errcode_t
175 SPF_c_parse_cidr_ip4(SPF_response_t *spf_response,
176  unsigned char *maskp,
177  const char *src)
178 {
179  int mask;
180 
181  /*
182  if (spf_server->debug > 2)
183  SPF_debugf("Parsing ip4 CIDR starting at %s", src);
184  */
185 
186  mask = strtoul(src + 1, NULL, 10);
187 
188  if ( mask > 32 ) {
189  return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_CIDR,
190  NULL, src,
191  "Invalid IPv4 CIDR netmask (>32)");
192  }
193  else if ( mask == 0 ) {
194  return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_CIDR,
195  NULL, src,
196  "Invalid IPv4 CIDR netmask (=0)");
197  }
198  else if ( mask == 32 ) {
199  mask = 0;
200  }
201 
202  *maskp = mask;
203 
204  return SPF_E_SUCCESS;
205 }
206 
212 static SPF_errcode_t
213 SPF_c_parse_cidr(SPF_response_t *spf_response,
214  SPF_data_cidr_t *data,
215  const char *src, size_t *src_len)
216 {
217  SPF_errcode_t err;
218  size_t idx;
219 
220  memset(data, 0, sizeof(SPF_data_cidr_t));
221  data->parm_type = PARM_CIDR;
222 
223  /* Find the beginning of the CIDR length notation.
224  * XXX This assumes that there is a non-digit in the string.
225  * This is always true for SPF records with domainspecs, since
226  * there has to be an = or a : before it. */
227  idx = *src_len - 1;
228  while (idx > 0 && isdigit( (unsigned char)(src[idx]) ))
229  idx--;
230 
231  /* Something is frying my brain and I can't pull an invariant
232  * out of this suitable for resetting *endp. So I nested the
233  * 'if's instead. Perhaps I'll manage to refactor later. */
234 
235  /* If we have a slash which isn't the last character. */
236  if (idx < (*src_len - 1) && src[idx] == '/') {
237  if (idx > 0 && src[idx - 1] == '/') {
238  /* get IPv6 CIDR length */
239  err = SPF_c_parse_cidr_ip6(spf_response, &data->ipv6, &src[idx]);
240  if (err)
241  return err;
242  /* now back up and see if there is a ipv4 cidr length */
243  *src_len = idx - 1; /* The index of the first '/' */
244  idx = *src_len - 1; /* Last character of what is before. */
245  while (idx > 0 && isdigit( (unsigned char)(src[idx]) ))
246  idx--;
247 
248  /* get IPv4 CIDR length */
249  if (idx < (*src_len - 1) && src[idx] == '/') {
250  /* - we know that strtoul terminates on the
251  * '/' so we don't need to null-terminate the
252  * input string. */
253  err = SPF_c_parse_cidr_ip4(spf_response, &data->ipv4, &src[idx]);
254  if (err)
255  return err;
256  *src_len = idx;
257  }
258  }
259  else {
260  /* get IPv4 CIDR length */
261  err = SPF_c_parse_cidr_ip4(spf_response, &data->ipv4, &src[idx]);
262  if (err)
263  return err;
264  *src_len = idx;
265  }
266  }
267 
268  return SPF_E_SUCCESS;
269 }
270 
271 static SPF_errcode_t
272 SPF_c_parse_var(SPF_response_t *spf_response, SPF_data_var_t *data,
273  const char *src, int is_mod)
274 {
275  const char *token;
276  const char *p;
277  char c;
278  int val;
279 
280  memset(data, 0, sizeof(SPF_data_var_t));
281 
282  p = src;
283 
284  /* URL encoding */
285  c = *p;
286  if ( isupper( (unsigned char)( c ) ) )
287  {
288  data->url_encode = TRUE;
289  c = tolower(c);
290  }
291  else
292  data->url_encode = FALSE;
293 
294 #define SPF_CHECK_IN_MODIFIER() \
295  if ( !is_mod ) \
296  return SPF_response_add_error_ptr(spf_response, \
297  SPF_E_INVALID_VAR, NULL, p, \
298  "'%c' macro is only valid in modifiers", c);
299 
300  switch ( c )
301  {
302  case 'l': /* local-part of envelope-sender */
303  data->parm_type = PARM_LP_FROM;
304  break;
305 
306  case 's': /* envelope-sender */
307  data->parm_type = PARM_ENV_FROM;
308  break;
309 
310  case 'o': /* envelope-domain */
311  data->parm_type = PARM_DP_FROM;
312  break;
313 
314  case 'd': /* current-domain */
315  data->parm_type = PARM_CUR_DOM;
316  break;
317 
318  case 'i': /* SMTP client IP */
319  data->parm_type = PARM_CLIENT_IP;
320  break;
321 
322  case 'c': /* SMTP client IP (pretty) */
324  data->parm_type = PARM_CLIENT_IP_P;
325  break;
326 
327  case 't': /* time in UTC epoch secs */
329  data->parm_type = PARM_TIME;
330  break;
331 
332  case 'p': /* SMTP client domain name */
333  data->parm_type = PARM_CLIENT_DOM;
334  break;
335 
336  case 'v': /* IP ver str - in-addr/ip6 */
337  data->parm_type = PARM_CLIENT_VER;
338  break;
339 
340  case 'h': /* HELO/EHLO domain */
341  data->parm_type = PARM_HELO_DOM;
342  break;
343 
344  case 'r': /* receiving domain */
346  data->parm_type = PARM_REC_DOM;
347  break;
348 
349  default:
350  return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_VAR,
351  NULL, p,
352  "Unknown variable '%c'", c);
353  }
354  p++;
355  token = p;
356 
357  /* get the number of subdomains to truncate to */
358  val = 0;
359  while ( isdigit( (unsigned char)( *p ) ) )
360  {
361  val *= 10;
362  val += *p - '0';
363  p++;
364  }
365  if ( val > 128 || (val <= 0 && p != token) )
366  return SPF_response_add_error_ptr(spf_response, SPF_E_BIG_SUBDOM,
367  NULL, token,
368  "Subdomain truncation depth too large");
369  data->num_rhs = val;
370  token = p;
371 
372  /* should the string be reversed? */
373  if ( *p == 'r' )
374  {
375  data->rev = 1;
376  p++;
377  }
378  else
379  data->rev = FALSE;
380  token = p;
381 
382 
383  /* check for delimiters */
384  data->delim_dot = FALSE;
385  data->delim_dash = FALSE;
386  data->delim_plus = FALSE;
387  data->delim_equal = FALSE;
388  data->delim_bar = FALSE;
389  data->delim_under = FALSE;
390 
391  /*vi:{*/
392  if ( *p == '}' )
393  data->delim_dot = TRUE;
394 
395  /*vi:{*/
396  while( *p != '}' )
397  {
398  token = p;
399  switch( *p )
400  {
401  case '.':
402  data->delim_dot = TRUE;
403  break;
404 
405  case '-':
406  data->delim_dash = TRUE;
407  break;
408 
409  case '+':
410  data->delim_plus = TRUE;
411  break;
412 
413  case '=':
414  data->delim_equal = TRUE;
415  break;
416 
417  case '|':
418  data->delim_bar = TRUE;
419  break;
420 
421  case '_':
422  data->delim_under = TRUE;
423  break;
424 
425  default:
426  return SPF_response_add_error_ptr(spf_response,
428  "Invalid delimiter '%c'", *p);
429  }
430  p++;
431  }
432  p++;
433  token = p;
434 
435 
436  return SPF_E_SUCCESS;
437 }
438 
439 
440  /* Sorry, Wayne. */
441 #define SPF_ADD_LEN_TO(_val, _len, _max) do { \
442  if ( (_val) + _align_sz(_len) > (_max) ) { \
443  return SPF_response_add_error_ptr(spf_response, \
444  big_err, NULL, src, \
445  "SPF domainspec too long " \
446  "(%d chars, %d max)", \
447  (_val) + (_len), _max); \
448  } \
449  (_val) += _align_sz(_len); \
450  } while(0)
451 
452 #define SPF_INIT_STRING_LITERAL(_avail) do { \
453  data->ds.parm_type = PARM_STRING; \
454  data->ds.len = 0; \
455  /* Magic numbers for x/Nc in gdb. */ \
456  data->ds.__unused0 = 0xba; data->ds.__unused1 = 0xbe; \
457  dst = SPF_data_str( data ); \
458  ds_avail = _avail - sizeof(SPF_data_t); \
459  ds_len = 0; \
460  } while(0)
461 
462 #define SPF_ENSURE_STRING_AVAIL(_len) do { \
463  if (ds_len + _len > ds_avail) \
464  return SPF_response_add_error_ptr(spf_response, \
465  SPF_E_BIG_STRING, NULL, src, \
466  "String literal fragment too long " \
467  "(%d chars, %d max)", \
468  ds_len, ds_avail); \
469  } while(0)
470 
471 #define SPF_FINI_STRING_LITERAL() do { \
472  if ( ds_len > 0 ) { \
473  if ( ds_len > SPF_MAX_STR_LEN ) { \
474  return SPF_response_add_error_ptr(spf_response, \
475  SPF_E_BIG_STRING, NULL, src, \
476  "String literal too long " \
477  "(%d chars, %d max)", \
478  ds_len, SPF_MAX_STR_LEN); \
479  } \
480  data->ds.len = ds_len; \
481  len = sizeof( *data ) + ds_len; \
482  SPF_ADD_LEN_TO(*data_used, len, data_avail); \
483  data = SPF_data_next( data ); \
484  ds_len = 0; \
485  } \
486  } while(0)
487 
505 static SPF_errcode_t
506 SPF_c_parse_macro(SPF_server_t *spf_server,
507  SPF_response_t *spf_response,
508  SPF_data_t *data, size_t *data_used, size_t data_avail,
509  const char *src, size_t src_len,
510  SPF_errcode_t big_err,
511  int is_mod)
512 {
513  SPF_errcode_t err;
514  /* Generic parsing iterators and boundaries */
515  size_t idx;
516  size_t len;
517  /* For parsing strings. */
518  char *dst;
519  size_t ds_avail;
520  size_t ds_len;
521 
522  if (spf_server->debug)
523  SPF_debugf("Parsing macro starting at %s", src);
524 
525 #if 0
526  if ((void *)data != _align_ptr((void *)data))
527  SPF_errorf("Data pointer %p is not aligned: Cannot compile.",
528  data);
529 #endif
530 
531  /*
532  * Create the data blocks
533  */
534  idx = 0;
535 
536  /* Initialise the block as a string. If ds_len == 0 later, we
537  * will just clobber it. */
538  SPF_INIT_STRING_LITERAL(data_avail - *data_used);
539 
540  // while ( p != end ) {
541  while (idx < src_len) {
542  if (spf_server->debug > 3)
543  SPF_debugf("Current data is at %p", data);
544  /* Either the unit is terminated by a space, or we hit a %.
545  * We should only hit a space if we run past src_len. */
546  len = strcspn(&src[idx], " %"); // XXX Also tab?
547  if (len > 0) { /* An optimisation */
548  /* Don't over-run into the CIDR. */
549  if (idx + len > src_len)
550  len = src_len - idx;
551  if (spf_server->debug > 3)
552  SPF_debugf("Adding string literal (%lu): '%*.*s'",
553  (unsigned long)len,
554  (int)len, (int)len, &src[idx]);
555  /* XXX Bounds-check here. */
557  memcpy(dst, &src[idx], len);
558  ds_len += len;
559  dst += len;
560  idx += len;
561 
562  /* If len == 0 then we never entered the while(). Thus
563  * if idx == src_len, then len != 0 and we reach this test.
564  */
565  }
566  /* However, this logic is overcomplex and I am a simpleton,
567  * so I have moved it out of the condition above. */
568  if (idx == src_len)
569  break;
570 
571  /* Now, we must have a %-escape code, since if we hit a
572  * space, then we are at the end.
573  * Incrementing idx consumes the % we hit first, and then
574  * we switch on the following character, which also
575  * increments idx. */
576  idx++;
577  switch (src[idx]) {
578  case '%':
579  if (spf_server->debug > 3)
580  SPF_debugf("Adding literal %%");
582  *dst++ = '%';
583  ds_len++;
584  idx++;
585  break;
586 
587  case '_':
588  if (spf_server->debug > 3)
589  SPF_debugf("Adding literal space");
591  *dst++ = ' ';
592  ds_len++;
593  idx++;
594  break;
595 
596  case '-':
597  if (spf_server->debug > 3)
598  SPF_debugf("Adding escaped space");
600  *dst++ = '%'; *dst++ = '2'; *dst++ = '0';
601  ds_len += 3;
602  idx++;
603  break;
604 
605  default:
606  if (spf_server->debug > 3)
607  SPF_debugf("Adding illegal %%-follower '%c' at %d",
608  src[idx], idx);
609  /* SPF spec says to treat it as a literal, not
610  * SPF_E_INVALID_ESC */
611  /* FIXME issue a warning? */
613  *dst++ = '%';
614  ds_len++;
615  break;
616 
617  case '{': /*vi:}*/
619  if (spf_server->debug > 3)
620  SPF_debugf("Adding macro, data is at %p", data);
621 
622  /* this must be a variable */
623  idx++;
624  err = SPF_c_parse_var(spf_response, &data->dv, &src[idx], is_mod);
625  if (err != SPF_E_SUCCESS)
626  return err;
627  idx += strcspn(&src[idx], "} ");
628  if (src[idx] == '}')
629  idx++;
630  else if (src[idx] == ' ')
631  return SPF_response_add_error_ptr(spf_response,
633  src, &src[idx],
634  "Unterminated variable?");
635 
636 
637  len = SPF_data_len(data);
638  SPF_ADD_LEN_TO(*data_used, len, data_avail);
639  data = SPF_data_next( data );
640  if (spf_server->debug > 3)
641  SPF_debugf("Next data is at %p", data);
642 
643  SPF_INIT_STRING_LITERAL(data_avail - *data_used);
644 
645  break;
646  }
647  }
648 
650 
651  return SPF_E_SUCCESS;
652 
653 }
654 
655 /* What a fuck-ugly prototype. */
670 static SPF_errcode_t
671 SPF_c_parse_domainspec(SPF_server_t *spf_server,
672  SPF_response_t *spf_response,
673  SPF_data_t *data, size_t *data_used, size_t data_avail,
674  const char *src, size_t src_len,
675  SPF_errcode_t big_err,
676  SPF_cidr_t cidr_ok, int is_mod)
677 {
678  SPF_errcode_t err;
679  /* Generic parsing iterators and boundaries */
680  size_t len;
681 
682  if (spf_server->debug)
683  SPF_debugf("Parsing domainspec starting at %s, cidr is %s",
684  src,
685  cidr_ok == CIDR_OPTIONAL ? "optional" :
686  cidr_ok == CIDR_ONLY ? "only" :
687  cidr_ok == CIDR_NONE ? "forbidden" :
688  "ERROR!"
689  );
690 
691  /*
692  * create the CIDR length info
693  */
694  if (cidr_ok == CIDR_OPTIONAL || cidr_ok == CIDR_ONLY) {
695  err = SPF_c_parse_cidr(spf_response, &data->dc, src, &src_len);
696  if (err != SPF_E_SUCCESS)
697  return err;
698  if (data->dc.ipv4 != 0 || data->dc.ipv6 != 0) {
699  len = SPF_data_len(data);
700  SPF_ADD_LEN_TO(*data_used, len, data_avail);
701  data = SPF_data_next(data);
702  }
703 
704  if (cidr_ok == CIDR_ONLY && src_len > 0) {
705  /* We had a mechanism followed by a '/', thus it HAS to be
706  * a CIDR, and the peculiar-looking error message is
707  * justified. However, we don't know _which_ CIDR. */
708  return SPF_response_add_error_ptr(spf_response,
710  NULL, src,
711  "Invalid CIDR after mechanism");
712  }
713  }
714 
715  return SPF_c_parse_macro(spf_server, spf_response,
716  data, data_used, data_avail,
717  src, src_len, big_err, is_mod);
718 }
719 
720 
726 static SPF_errcode_t
727 SPF_c_parse_ip4(SPF_response_t *spf_response, SPF_mech_t *mech, char const *start)
728 {
729  const char *end;
730  const char *p;
731 
732  char buf[ INET6_ADDRSTRLEN ];
733  size_t len;
734  SPF_errcode_t err;
735 
736  unsigned char mask;
737  struct in_addr *addr;
738 
739  start++;
740  len = strcspn(start, " ");
741  end = start + len;
742  p = end - 1;
743 
744  mask = 0;
745  while (isdigit( (unsigned char)(*p) ))
746  p--;
747  if (p != (end - 1) && *p == '/') {
748  err = SPF_c_parse_cidr_ip4(spf_response, &mask, p);
749  if (err)
750  return err;
751  end = p;
752  }
753  mech->mech_len = mask;
754 
755  len = end - start;
756  if ( len > sizeof( buf ) - 1 )
757  return SPF_E_INVALID_IP4;
758 
759  memcpy( buf, start, len );
760  buf[ len ] = '\0';
761  addr = SPF_mech_ip4_data(mech);
762  err = inet_pton( AF_INET, buf, addr );
763  if ( err <= 0 )
764  return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_IP4,
765  NULL, buf, NULL);
766 
767  return SPF_E_SUCCESS;
768 }
769 
775 static SPF_errcode_t
776 SPF_c_parse_ip6(SPF_response_t *spf_response, SPF_mech_t *mech, char const *start)
777 {
778  const char *end;
779  const char *p;
780 
781  char buf[ INET6_ADDRSTRLEN ];
782  size_t len;
783  int err;
784 
785  unsigned char mask;
786  struct in6_addr *addr;
787 
788  start++;
789  len = strcspn(start, " ");
790  end = start + len;
791  p = end - 1;
792 
793  mask = 0;
794  while (isdigit( (unsigned char)(*p) ))
795  p--;
796  if (p != (end - 1) && *p == '/') {
797  err = SPF_c_parse_cidr_ip6(spf_response, &mask, p);
798  if (err)
799  return err;
800  end = p;
801  }
802  mech->mech_len = mask;
803 
804  len = end - start;
805  if ( len > sizeof( buf ) - 1 )
806  return SPF_E_INVALID_IP6;
807 
808  memcpy( buf, start, len );
809  buf[ len ] = '\0';
810  addr = SPF_mech_ip6_data(mech);
811  err = inet_pton( AF_INET6, buf, addr );
812  if ( err <= 0 )
813  return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_IP6,
814  NULL, buf, NULL);
815 
816  return SPF_E_SUCCESS;
817 }
818 
819 
820 /* XXX TODO: Make this take (const char *) instead of (const char **)
821  * because the caller ignores the modified value. */
822 __attribute__((warn_unused_result))
823 static SPF_errcode_t
824 SPF_c_mech_add(SPF_server_t *spf_server,
825  SPF_record_t *spf_record, SPF_response_t *spf_response,
826  const SPF_mechtype_t *mechtype, int prefix,
827  const char **mech_value)
828 {
829  /* If this buffer is an irregular size, intel gcc does not align
830  * it properly, and all hell breaks loose. */
831 ALIGN_DECL(
832  char buf[SPF_RECORD_BUFSIZ];
833 );
834  SPF_mech_t *spf_mechanism = (SPF_mech_t *)ALIGNED_DECL(buf);
835  SPF_data_t *data;
836  size_t data_len;
837  size_t len;
838  size_t src_len;
839 
840  SPF_errcode_t err;
841 
842  memset(u.buf, 'B', sizeof(u.buf)); /* Poison the buffer. */
843  memset(spf_mechanism, 0, sizeof(SPF_mech_t));
844 
845  if (spf_server->debug)
846  SPF_debugf("SPF_c_mech_add: type=%d, value=%s",
847  mechtype->mech_type, *mech_value);
848 
849  spf_mechanism->prefix_type = prefix;
850  spf_mechanism->mech_type = mechtype->mech_type;
851  spf_mechanism->mech_len = 0;
852 
853  len = sizeof( SPF_mech_t );
854 
855  if ( spf_record->mech_len + len > SPF_MAX_MECH_LEN )
856  return SPF_E_BIG_MECH;
857 
858  data = SPF_mech_data(spf_mechanism);
859  data_len = 0;
860 
861  src_len = strcspn(*mech_value, " ");
862 
863  switch (mechtype->mech_type) {
864  /* We know the properties of IP4 and IP6. */
865  case MECH_IP4:
866  if (**mech_value == ':') {
867  err = SPF_c_parse_ip4(spf_response, spf_mechanism, *mech_value);
868  data_len = sizeof(struct in_addr);
869  }
870  else {
871  err = SPF_E_MISSING_OPT;
872  SPF_response_add_error_ptr(spf_response, err,
873  NULL, *mech_value,
874  "Mechanism requires a value.");
875  }
876  break;
877 
878  case MECH_IP6:
879  if (**mech_value == ':') {
880  err = SPF_c_parse_ip6(spf_response, spf_mechanism, *mech_value);
881  data_len = sizeof(struct in6_addr);
882  }
883  else {
884  err = SPF_E_MISSING_OPT;
885  SPF_response_add_error_ptr(spf_response, err,
886  NULL, *mech_value,
887  "Mechanism requires a value.");
888  }
889  break;
890 
891  default:
892  if (**mech_value == ':' || **mech_value == '=') {
893  if (mechtype->has_domainspec == DOMSPEC_NONE) {
894  err = SPF_E_INVALID_OPT;
895  SPF_response_add_error_ptr(spf_response, err,
896  NULL, *mech_value,
897  "Mechanism does not permit a value.");
898  }
899  else {
900  (*mech_value)++; src_len--;
901  err = SPF_c_parse_domainspec(spf_server,
902  spf_response,
903  data, &data_len, SPF_MAX_MECH_LEN,
904  *mech_value, src_len,
906  mechtype->has_cidr, FALSE);
907  }
908  }
909  else if (**mech_value == '/') {
910  if (mechtype->has_domainspec == DOMSPEC_REQUIRED) {
911  err = SPF_E_MISSING_OPT;
912  SPF_response_add_error_ptr(spf_response, err,
913  NULL, *mech_value,
914  "Mechanism requires a value.");
915  }
916  else if (mechtype->has_cidr == CIDR_NONE) {
917  err = SPF_E_INVALID_CIDR;
918  SPF_response_add_error_ptr(spf_response, err,
919  NULL, *mech_value,
920  "Mechanism does not permit a CIDR.");
921  }
922  else {
923  err = SPF_c_parse_domainspec(spf_server,
924  spf_response,
925  data, &data_len, SPF_MAX_MECH_LEN,
926  *mech_value, src_len,
928  CIDR_ONLY, FALSE);
929  }
930  }
931  else if (**mech_value == ' ' || **mech_value == '\0') {
932  if (mechtype->has_domainspec == DOMSPEC_REQUIRED) {
933  err = SPF_E_MISSING_OPT;
934  SPF_response_add_error_ptr(spf_response, err,
935  NULL, *mech_value,
936  "Mechanism requires a value.");
937  }
938  else {
939  err = SPF_E_SUCCESS;
940  }
941  }
942  else {
943  err = SPF_E_SYNTAX;
944  SPF_response_add_error_ptr(spf_response, err,
945  NULL, *mech_value,
946  "Unknown character '%c' after mechanism.",
947  **mech_value);
948  }
949 
950  /* Does not apply to ip4/ip6 */
951  spf_mechanism->mech_len = data_len;
952  break;
953  }
954 
955  len += data_len;
956 
957  /* Copy the thing in. */
958  if (err == SPF_E_SUCCESS) {
959  if (mechtype->is_dns_mech)
960  spf_record->num_dns_mech++;
961  if (SPF_c_ensure_capacity((void **)&spf_record->mech_first,
962  &spf_record->mech_size,
963  spf_record->mech_len + len) < 0)
964  return SPF_response_add_error_ptr(spf_response,
966  NULL, NULL,
967  "Failed to allocate memory for mechanism");
968  memcpy( (char *)spf_record->mech_first + spf_record->mech_len,
969  spf_mechanism,
970  len);
971  spf_record->mech_len += len;
972  spf_record->num_mech++;
973  }
974 
975  *mech_value += src_len;
976 
977  return err;
978 }
979 
980 __attribute__((warn_unused_result))
981 static SPF_errcode_t
982 SPF_c_mod_add(SPF_server_t *spf_server,
983  SPF_record_t *spf_record, SPF_response_t *spf_response,
984  const char *mod_name, size_t name_len,
985  const char **mod_value)
986 {
987  /* If this buffer is an irregular size, intel gcc does not align
988  * it properly, and all hell breaks loose. */
989 ALIGN_DECL(
990  char buf[SPF_RECORD_BUFSIZ];
991 );
992  SPF_mod_t *spf_modifier = (SPF_mod_t *)u.buf;
993  SPF_data_t *data;
994  size_t data_len;
995  size_t len;
996  size_t src_len;
997 
998  SPF_errcode_t err;
999 
1000  if (spf_server->debug)
1001  SPF_debugf("Adding modifier name=%lu@%s, value=%s",
1002  (unsigned long)name_len, mod_name, *mod_value);
1003 
1004  memset(u.buf, 'A', sizeof(u.buf));
1005  memset(spf_modifier, 0, sizeof(SPF_mod_t));
1006 
1007  if ( name_len > SPF_MAX_MOD_LEN )
1008  return SPF_E_BIG_MOD;
1009 
1010  spf_modifier->name_len = name_len;
1011  spf_modifier->data_len = 0;
1012 
1013  /* So that spf_modifier + len == SPF_mod_data(spf_modifier) */
1014  len = _align_sz(sizeof( SPF_mod_t ) + name_len);
1015 
1016  if ( spf_record->mod_len + len > SPF_MAX_MOD_LEN )
1017  return SPF_E_BIG_MOD;
1018 
1019  memcpy(SPF_mod_name(spf_modifier), mod_name, name_len);
1020 
1021  data = SPF_mod_data(spf_modifier);
1022  data_len = 0;
1023 
1024  src_len = strcspn(*mod_value, " ");
1025 
1026  err = SPF_c_parse_macro(spf_server,
1027  spf_response,
1028  data, &data_len, SPF_MAX_MOD_LEN,
1029  *mod_value, src_len,
1030  SPF_E_BIG_MOD,
1031  TRUE );
1032  spf_modifier->data_len = data_len;
1033  len += data_len;
1034 
1035  /* Copy the thing in. */
1036  if (err == SPF_E_SUCCESS) {
1037  if (SPF_c_ensure_capacity((void **)&spf_record->mod_first,
1038  &spf_record->mod_size,
1039  spf_record->mod_len + len) < 0)
1040  return SPF_response_add_error_ptr(spf_response,
1042  NULL, NULL,
1043  "Failed to allocate memory for modifier");
1044  memcpy( (char *)spf_record->mod_first + spf_record->mod_len,
1045  spf_modifier,
1046  len);
1047  spf_record->mod_len += len;
1048  spf_record->num_mod++;
1049  }
1050 
1051  return err;
1052 }
1053 
1054 static void
1055 SPF_record_lint(SPF_server_t *spf_server,
1056  SPF_response_t *spf_response,
1057  SPF_record_t *spf_record)
1058 {
1059  SPF_data_t *d, *data_end;
1060 
1061  char *s;
1062  char *s_end;
1063 
1064  int found_non_ip;
1065  int found_valid_tld;
1066 
1067  SPF_mech_t *mech;
1068  SPF_data_t *data;
1069 
1070  int i;
1071 
1072  /* FIXME these warnings suck. Should call SPF_id2str to give more
1073  * context. */
1074 
1075  mech = spf_record->mech_first;
1076  for (i = 0;
1077  i < spf_record->num_mech;
1078  i++,
1079  mech = SPF_mech_next( mech ) )
1080  {
1081  if ( ( mech->mech_type == MECH_ALL
1082  || mech->mech_type == MECH_REDIRECT )
1083  && i != spf_record->num_mech - 1 )
1084  {
1086  "Mechanisms found after the \"all:\" "
1087  "mechanism will be ignored.");
1088  }
1089 
1090  /*
1091  * if we are dealing with a mechanism, make sure that the data
1092  * at least looks like a valid host name.
1093  *
1094  * note: this routine isn't called to handle ip4: and ip6: and all
1095  * the other mechanisms require a host name.
1096  */
1097 
1098  if ( mech->mech_type == MECH_IP4
1099  || mech->mech_type == MECH_IP6 )
1100  continue;
1101 
1102  data = SPF_mech_data( mech );
1103  data_end = SPF_mech_end_data( mech );
1104  if ( data == data_end )
1105  continue;
1106 
1107  if ( data->dc.parm_type == PARM_CIDR )
1108  {
1109  data = SPF_data_next( data );
1110  if ( data == data_end )
1111  continue;
1112  }
1113 
1114 
1115  found_valid_tld = FALSE;
1116  found_non_ip = FALSE;
1117 
1118  for( d = data; d < data_end; d = SPF_data_next( d ) )
1119  {
1120  switch( d->dv.parm_type )
1121  {
1122  case PARM_CIDR:
1123  SPF_error( "Multiple CIDR parameters found" );
1124  break;
1125 
1126  case PARM_CLIENT_IP:
1127  case PARM_CLIENT_IP_P:
1128  case PARM_LP_FROM:
1129  found_valid_tld = FALSE;
1130  break;
1131 
1132  case PARM_STRING:
1133  found_valid_tld = FALSE;
1134 
1135  s = SPF_data_str( d );
1136  s_end = s + d->ds.len;
1137  for( ; s < s_end; s++ ) {
1138  if ( !isdigit( (unsigned char)( *s ) ) && *s != '.' && *s != ':' )
1139  found_non_ip = TRUE;
1140 
1141  if ( *s == '.' )
1142  found_valid_tld = TRUE;
1143  else if ( !isalpha( (unsigned char)( *s ) ) )
1144  found_valid_tld = FALSE;
1145  }
1146  break;
1147 
1148  default:
1149  found_non_ip = TRUE;
1150  found_valid_tld = TRUE;
1151 
1152  break;
1153  }
1154  }
1155 
1156  if ( !found_valid_tld || !found_non_ip ) {
1157  if ( !found_non_ip )
1159  "Invalid hostname (an IP address?)");
1160  else if ( !found_valid_tld )
1162  "Hostname has a missing or invalid TLD");
1163  }
1164 
1165  }
1166 
1167  /* FIXME check for modifiers that should probably be mechanisms */
1168 }
1169 
1170 
1171 
1180 SPF_record_compile(SPF_server_t *spf_server,
1181  SPF_response_t *spf_response,
1182  SPF_record_t **spf_recordp,
1183  const char *record)
1184 {
1185  const SPF_mechtype_t*mechtype;
1186  SPF_record_t *spf_record;
1187  SPF_error_t *spf_error;
1188  SPF_errcode_t err;
1189 
1190  const char *name_start;
1191  size_t name_len;
1192 
1193  const char *val_start;
1194  const char *val_end;
1195 
1196  int prefix;
1197 
1198  const char *p;
1199  int i;
1200 
1201 
1202  /*
1203  * make sure we were passed valid data to work with
1204  */
1205  SPF_ASSERT_NOTNULL(spf_server);
1206  SPF_ASSERT_NOTNULL(spf_recordp);
1207  SPF_ASSERT_NOTNULL(record);
1208 
1209  if (spf_server->debug)
1210  SPF_debugf("Compiling record %s", record);
1211 
1212  /*
1213  * and make sure that we will always set *spf_recordp
1214  * just incase we can't find a valid SPF record
1215  */
1216  *spf_recordp = NULL;
1217 
1218  /*
1219  * See if this is record is even an SPF record
1220  */
1221  p = record;
1222 
1223  if (strncasecmp(p, SPF_VER_STR, sizeof(SPF_VER_STR) - 1) != 0)
1224  return SPF_response_add_error_ptr(spf_response, SPF_E_NOT_SPF,
1225  NULL, p,
1226  "Could not find a valid SPF record");
1227  p += sizeof( SPF_VER_STR ) - 1;
1228 
1229  if ( *p != '\0' && *p != ' ' )
1230  return SPF_response_add_error_ptr(spf_response, SPF_E_NOT_SPF,
1231  NULL, p,
1232  "Could not find a valid SPF record");
1233 
1234  spf_record = SPF_record_new(spf_server, record);
1235  if (spf_record == NULL) {
1236  *spf_recordp = NULL;
1237  return SPF_response_add_error_ptr(spf_response, SPF_E_NO_MEMORY,
1238  NULL, p,
1239  "Failed to allocate an SPF record");
1240  }
1241  spf_record->version = 1;
1242  *spf_recordp = spf_record;
1243 
1244  /*
1245  * parse the SPF record
1246  */
1247  while (*p != '\0') {
1248  /* TODO WARN: If it's a \n or a \t */
1249  /* skip to the next token */
1250  while (*p == ' ')
1251  p++;
1252 
1253  if (*p == '\0')
1254  break;
1255 
1256  /* see if we have a valid prefix */
1257  prefix = PREFIX_UNKNOWN;
1258  switch (*p) {
1259  case '+':
1260  prefix = PREFIX_PASS;
1261  p++;
1262  break;
1263 
1264  case '-':
1265  prefix = PREFIX_FAIL;
1266  p++;
1267  break;
1268 
1269  case '~':
1270  prefix = PREFIX_SOFTFAIL;
1271  p++;
1272  break;
1273 
1274  case '?':
1275  prefix = PREFIX_NEUTRAL;
1276  p++;
1277  break;
1278 
1279  default:
1280  while (ispunct((unsigned char)(*p))) {
1281  SPF_response_add_error_ptr(spf_response,
1283  "Invalid prefix '%c'", *p);
1284  p++;
1285  }
1286  break;
1287  }
1288 
1289  name_start = p;
1290  val_end = name_start + strcspn(p, " ");
1291 
1292  /* get the mechanism/modifier */
1293  if ( ! isalpha( (unsigned char)*p ) ) {
1294  /* We could just bail on this one. */
1295  SPF_response_add_error_ptr(spf_response,
1297  "Invalid character at start of mechanism");
1298  p += strcspn(p, " ");
1299  continue;
1300  }
1301  while ( isalnum( (unsigned char)*p ) || *p == '_' || *p == '-' )
1302  p++;
1303 
1304 /* TODO: These or macros like them are used in several places. Merge. */
1305 #define STREQ_SIZEOF(a, b) \
1306  (strncasecmp((a), (b), sizeof( (b) ) - 1) == 0)
1307 #define STREQ_SIZEOF_N(a, b, n) \
1308  (((n) == sizeof(b) - 1) && (strncasecmp((a),(b),(n)) == 0))
1309 
1310  /* See if we have a modifier or a prefix */
1311  name_len = p - name_start;
1312 
1313  if (spf_server->debug)
1314  SPF_debugf("Name starts at %s", name_start);
1315 
1316  switch ( *p )
1317  {
1318  case ':':
1319  case '/':
1320  case ' ':
1321  case '\0':
1322  compile_mech: /* A bona fide label */
1323 
1324  /*
1325  * parse the mechanism
1326  */
1327 
1328  /* mechanisms default to PREFIX_PASS */
1329  if ( prefix == PREFIX_UNKNOWN )
1330  prefix = PREFIX_PASS;
1331 
1332  if ( STREQ_SIZEOF_N(name_start, "a", name_len) )
1333  mechtype = SPF_mechtype_find(MECH_A);
1334  else if ( STREQ_SIZEOF_N(name_start, "mx", name_len) )
1335  mechtype = SPF_mechtype_find(MECH_MX);
1336  else if ( STREQ_SIZEOF_N(name_start, "ptr", name_len) )
1337  mechtype = SPF_mechtype_find(MECH_PTR);
1338  else if ( STREQ_SIZEOF_N(name_start, "include", name_len) )
1339  mechtype = SPF_mechtype_find(MECH_INCLUDE);
1340  else if ( STREQ_SIZEOF_N(name_start, "ip4", name_len) )
1341  mechtype = SPF_mechtype_find(MECH_IP4);
1342  else if ( STREQ_SIZEOF_N(name_start, "ip6", name_len) )
1343  mechtype = SPF_mechtype_find(MECH_IP6);
1344  else if ( STREQ_SIZEOF_N(name_start, "exists", name_len) )
1345  mechtype = SPF_mechtype_find(MECH_EXISTS);
1346  else if ( STREQ_SIZEOF_N(name_start, "all", name_len) )
1347  mechtype = SPF_mechtype_find(MECH_ALL);
1348 #ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1349  else if ( STREQ_SIZEOF_N(name_start,
1350  "default=allow", name_len) )
1351  {
1353  NULL, name_start,
1354  "Deprecated option 'default=allow'");
1355  mechtype = SPF_mechtype_find(MECH_ALL);
1356  prefix = PREFIX_PASS;
1357  }
1358  else if (STREQ_SIZEOF_N(name_start,
1359  "default=softfail",name_len))
1360  {
1362  NULL, name_start,
1363  "Deprecated option 'default=softfail'");
1364  mechtype = SPF_mechtype_find(MECH_ALL);
1365  prefix = PREFIX_SOFTFAIL;
1366  }
1367  else if ( STREQ_SIZEOF_N(name_start,
1368  "default=deny", name_len) )
1369  {
1371  NULL, name_start,
1372  "Deprecated option 'default=deny'");
1373  mechtype = SPF_mechtype_find(MECH_ALL);
1374  prefix = PREFIX_FAIL;
1375  }
1376  else if ( STREQ_SIZEOF(name_start, "default=") )
1377  {
1379  NULL, name_start,
1380  "Invalid modifier 'default=...'");
1381  p = val_end;
1382  continue;
1383  }
1384 #endif
1385  /* FIXME the redirect mechanism needs to be moved to
1386  * the very end */
1387  else if ( STREQ_SIZEOF_N(name_start, "redirect", name_len) )
1388  mechtype = SPF_mechtype_find(MECH_REDIRECT);
1389  else
1390  {
1392  NULL, name_start,
1393  "Unknown mechanism found");
1394  p = val_end;
1395  continue;
1396  }
1397 
1398  if (mechtype == NULL) {
1399  return SPF_response_add_error_ptr(spf_response,
1401  NULL, name_start,
1402  "Failed to find specification for "
1403  "a recognised mechanism");
1404  }
1405 
1406  if (spf_server->debug)
1407  SPF_debugf("Adding mechanism type %d",
1408  (int)mechtype->mech_type);
1409 
1410  val_start = p;
1411  err = SPF_c_mech_add(spf_server,
1412  spf_record, spf_response,
1413  mechtype, prefix, &val_start);
1414  if (err == SPF_E_NO_MEMORY)
1415  return err;
1416  /* XXX Else do nothing. Continue for the next error. */
1417  /* We shouldn't have to worry about the child function
1418  * updating the pointer. So we just use our 'well known'
1419  * copy. */
1420  p = val_end;
1421  break;
1422 
1423  case '=':
1424 
1425  /*
1426  * parse the modifier
1427  */
1428 
1429  /* modifiers can't have prefixes */
1430  if (prefix != PREFIX_UNKNOWN)
1432  NULL, name_start,
1433  "Modifiers may not have prefixes");
1434  prefix = PREFIX_UNKNOWN; /* For redirect/include */
1435 
1436 #ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1437  /* Deal with legacy special case */
1438  if ( STREQ_SIZEOF(name_start, "default=") ) {
1439  /* Consider the whole 'default=foo' as a token. */
1440  p = val_end;
1441  name_len = p - name_start;
1442  goto compile_mech;
1443  }
1444 #endif
1445 
1446  /* We treat 'redirect' as a mechanism. */
1447  if ( STREQ_SIZEOF(name_start, "redirect=") )
1448  goto compile_mech;
1449 
1450  p++;
1451  val_start = p;
1452  err = SPF_c_mod_add(spf_server,
1453  spf_record, spf_response,
1454  name_start, name_len, &val_start);
1455  if (err == SPF_E_NO_MEMORY)
1456  return err;
1457  /* XXX Else do nothing. Continue for the next error. */
1458  p = val_end;
1459  break;
1460 
1461 
1462  default:
1464  NULL, p,
1465  "Invalid character in middle of mechanism");
1466  p = val_end;
1467  break;
1468  }
1469  }
1470 
1471 
1472  /*
1473  * check for common mistakes
1474  */
1475  SPF_record_lint(spf_server, spf_response, spf_record);
1476 
1477 
1478  /*
1479  * do final cleanup on the record
1480  */
1481 
1482  /* FIXME realloc (shrink) spfi buffers? */
1483 
1484  if (SPF_response_errors(spf_response) > 0) {
1485  for (i = 0; i < SPF_response_messages(spf_response); i++) {
1486  spf_error = SPF_response_message(spf_response, i);
1487  if (SPF_error_errorp(spf_error))
1488  return SPF_error_code(spf_error);
1489  }
1490  return SPF_response_add_error(spf_response,
1492  "Response has errors but can't find one!");
1493  }
1494 
1495  return SPF_E_SUCCESS;
1496 }
1497 
1499 SPF_record_compile_macro(SPF_server_t *spf_server,
1500  SPF_response_t *spf_response,
1501  SPF_macro_t **spf_macrop,
1502  const char *record)
1503 {
1504 ALIGN_DECL(
1505  char buf[sizeof(SPF_macro_t) + SPF_MAX_MOD_LEN];
1506 );
1507  SPF_macro_t *spf_macro = (SPF_macro_t *)ALIGNED_DECL(buf);
1508  SPF_data_t *data;
1509  SPF_errcode_t err;
1510  size_t size;
1511 
1512  data = SPF_macro_data(spf_macro);
1513  spf_macro->macro_len = 0;
1514 
1515  err = SPF_c_parse_macro(spf_server, spf_response,
1516  data, &spf_macro->macro_len, SPF_MAX_MOD_LEN,
1517  record, strlen(record),
1518  SPF_E_BIG_MOD, TRUE);
1519  if (err != SPF_E_SUCCESS)
1520  return err;
1521 
1522  /* XXX TODO: Tidy this up? */
1523  size = sizeof(SPF_macro_t) + spf_macro->macro_len;
1524  *spf_macrop = (SPF_macro_t *)malloc(size);
1525  if (!*spf_macrop)
1526  return SPF_E_NO_MEMORY;
1527  memcpy(*spf_macrop, ALIGNED_DECL(buf), size);
1528 
1529  return SPF_E_SUCCESS;
1530 }
#define SPF_VER_STR
Definition: spf.h:35
#define NULL
Definition: spf_internal.h:28
#define TRUE
Definition: spf_internal.h:23
#define FALSE
Definition: spf_internal.h:24
#define SPF_errorf
Definition: spf_log.h:77
#define SPF_ASSERT_NOTNULL(x)
Definition: spf_log.h:118
#define SPF_error(errmsg)
Definition: spf_log.h:40
#define SPF_debugf
Definition: spf_log.h:80
#define PARM_LP_FROM
Definition: spf_record.h:88
#define PARM_CUR_DOM
Definition: spf_record.h:91
#define MECH_EXISTS
Definition: spf_record.h:169
#define PREFIX_PASS
Definition: spf_record.h:153
#define PARM_CLIENT_VER
Definition: spf_record.h:96
#define PARM_REC_DOM
Definition: spf_record.h:98
#define MECH_REDIRECT
Definition: spf_record.h:171
#define PARM_STRING
Definition: spf_record.h:100
#define PREFIX_NEUTRAL
Definition: spf_record.h:156
#define MECH_INCLUDE
Definition: spf_record.h:166
#define PARM_HELO_DOM
Definition: spf_record.h:97
#define PARM_CLIENT_IP_P
Definition: spf_record.h:93
#define MECH_IP6
Definition: spf_record.h:168
#define PARM_CIDR
Definition: spf_record.h:99
#define MECH_IP4
Definition: spf_record.h:167
#define PARM_CLIENT_DOM
Definition: spf_record.h:95
#define MECH_MX
Definition: spf_record.h:164
#define MECH_PTR
Definition: spf_record.h:165
#define PARM_ENV_FROM
Definition: spf_record.h:89
#define PREFIX_UNKNOWN
Definition: spf_record.h:157
SPF_record_t * SPF_record_new(SPF_server_t *spf_server, const char *text)
Definition: spf_record.c:48
#define SPF_MAX_MOD_LEN
Definition: spf_record.h:78
#define MECH_ALL
Definition: spf_record.h:170
#define MECH_UNKNOWN
Definition: spf_record.h:162
#define SPF_MAX_MECH_LEN
Definition: spf_record.h:77
#define MECH_A
Definition: spf_record.h:163
#define PARM_TIME
Definition: spf_record.h:94
#define PARM_CLIENT_IP
Definition: spf_record.h:92
#define PARM_DP_FROM
Definition: spf_record.h:90
#define PREFIX_SOFTFAIL
Definition: spf_record.h:155
#define PREFIX_FAIL
Definition: spf_record.h:154
SPF_errcode_t SPF_response_add_warn_ptr(SPF_response_t *rp, SPF_errcode_t code, const char *text, const char *tptr, const char *format,...)
Definition: spf_response.c:264
SPF_errcode_t SPF_response_add_error_ptr(SPF_response_t *rp, SPF_errcode_t code, const char *text, const char *tptr, const char *format,...)
Definition: spf_response.c:238
SPF_error_t * SPF_response_message(SPF_response_t *rp, int idx)
Definition: spf_response.c:308
SPF_errcode_t SPF_response_add_warn(SPF_response_t *rp, SPF_errcode_t code, const char *format,...)
Definition: spf_response.c:282
SPF_errcode_t SPF_response_add_error(SPF_response_t *rp, SPF_errcode_t code, const char *format,...)
Definition: spf_response.c:256
int SPF_response_messages(SPF_response_t *rp)
Definition: spf_response.c:290
char SPF_error_errorp(SPF_error_t *err)
Definition: spf_response.c:326
SPF_errcode_t SPF_error_code(SPF_error_t *err)
Definition: spf_response.c:314
SPF_errcode_t
Definition: spf_response.h:119
@ SPF_E_MECH_AFTER_ALL
Definition: spf_response.h:149
@ SPF_E_MOD_W_PREF
Definition: spf_response.h:124
@ SPF_E_UNKNOWN_MECH
Definition: spf_response.h:126
@ SPF_E_INVALID_CHAR
Definition: spf_response.h:125
@ SPF_E_SYNTAX
Definition: spf_response.h:123
@ SPF_E_INVALID_IP6
Definition: spf_response.h:140
@ SPF_E_INTERNAL_ERROR
Definition: spf_response.h:130
@ SPF_E_INVALID_OPT
Definition: spf_response.h:127
@ SPF_E_BAD_HOST_TLD
Definition: spf_response.h:148
@ SPF_E_NO_MEMORY
Definition: spf_response.h:121
@ SPF_E_BAD_HOST_IP
Definition: spf_response.h:147
@ SPF_E_INVALID_VAR
Definition: spf_response.h:132
@ SPF_E_BIG_SUBDOM
Definition: spf_response.h:133
@ SPF_E_NOT_SPF
Definition: spf_response.h:122
@ SPF_E_INVALID_DELIM
Definition: spf_response.h:134
@ SPF_E_MISSING_OPT
Definition: spf_response.h:129
@ SPF_E_INVALID_IP4
Definition: spf_response.h:139
@ SPF_E_BIG_MECH
Definition: spf_response.h:136
@ SPF_E_INVALID_CIDR
Definition: spf_response.h:128
@ SPF_E_SUCCESS
Definition: spf_response.h:120
@ SPF_E_INVALID_PREFIX
Definition: spf_response.h:141
@ SPF_E_BIG_MOD
Definition: spf_response.h:137
int SPF_response_errors(SPF_response_t *rp)
Definition: spf_response.c:296
int strncasecmp(const char *s1, const char *s2, size_t n)
Definition: strncasecmp.c:11
#define SPF_ENSURE_STRING_AVAIL(_len)
Definition: spf_compile.c:462
#define SPF_RECORD_BUFSIZ
Definition: spf_compile.c:62
#define ALIGN_DECL(decl)
Definition: spf_compile.c:64
#define STREQ_SIZEOF(a, b)
__attribute__((warn_unused_result))
Definition: spf_compile.c:105
#define SPF_ADD_LEN_TO(_val, _len, _max)
Definition: spf_compile.c:441
SPF_domspec_t
Definition: spf_compile.c:53
@ DOMSPEC_REQUIRED
Definition: spf_compile.c:54
@ DOMSPEC_OPTIONAL
Definition: spf_compile.c:54
@ DOMSPEC_NONE
Definition: spf_compile.c:54
#define SPF_FINI_STRING_LITERAL()
Definition: spf_compile.c:471
SPF_cidr_t
Definition: spf_compile.c:48
@ CIDR_ONLY
Definition: spf_compile.c:49
@ CIDR_NONE
Definition: spf_compile.c:49
@ CIDR_OPTIONAL
Definition: spf_compile.c:49
SPF_errcode_t SPF_record_compile(SPF_server_t *spf_server, SPF_response_t *spf_response, SPF_record_t **spf_recordp, const char *record)
Definition: spf_compile.c:1180
#define ALIGNED_DECL(var)
Definition: spf_compile.c:65
#define STREQ_SIZEOF_N(a, b, n)
#define SPF_INIT_STRING_LITERAL(_avail)
Definition: spf_compile.c:452
#define SPF_CHECK_IN_MODIFIER()
#define spf_num_mechanisms
Definition: spf_compile.c:91
SPF_errcode_t SPF_record_compile_macro(SPF_server_t *spf_server, SPF_response_t *spf_response, SPF_macro_t **spf_macrop, const char *record)
Definition: spf_compile.c:1499
unsigned char len
Definition: spf_record.h:107
unsigned short rev
Definition: spf_record.h:119
unsigned short delim_under
Definition: spf_record.h:126
unsigned short delim_dot
Definition: spf_record.h:121
unsigned char num_rhs
Definition: spf_record.h:118
unsigned short delim_bar
Definition: spf_record.h:125
unsigned char parm_type
Definition: spf_record.h:117
unsigned short delim_dash
Definition: spf_record.h:122
unsigned short delim_plus
Definition: spf_record.h:123
unsigned short delim_equal
Definition: spf_record.h:124
unsigned short url_encode
Definition: spf_record.h:120
unsigned char ipv6
Definition: spf_record.h:134
unsigned char ipv4
Definition: spf_record.h:133
unsigned char parm_type
Definition: spf_record.h:132
SPF_data_str_t ds
Definition: spf_record.h:144
SPF_data_cidr_t dc
Definition: spf_record.h:145
SPF_data_var_t dv
Definition: spf_record.h:143
unsigned short mech_len
Definition: spf_record.h:178
SPF_cidr_t has_cidr
Definition: spf_compile.c:75
unsigned char mech_type
Definition: spf_compile.c:72
unsigned char is_dns_mech
Definition: spf_compile.c:73
SPF_domspec_t has_domainspec
Definition: spf_compile.c:74