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 {
50 } SPF_cidr_t;
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  if ((_avail) < sizeof(SPF_data_t)) \
459  return SPF_response_add_error_ptr(spf_response, \
460  SPF_E_BIG_STRING, NULL, src, \
461  "Out of memory for string literal");\
462  ds_avail = (_avail) - sizeof(SPF_data_t); \
463  ds_len = 0; \
464  } while(0)
465 
466 #define SPF_ENSURE_STRING_AVAIL(_len) do { \
467  if (ds_len + _len > ds_avail) \
468  return SPF_response_add_error_ptr(spf_response, \
469  SPF_E_BIG_STRING, NULL, src, \
470  "String literal fragment too long " \
471  "(%d chars, %d max)", \
472  ds_len, ds_avail); \
473  } while(0)
474 
475 #define SPF_FINI_STRING_LITERAL() do { \
476  if ( ds_len > 0 ) { \
477  if ( ds_len > SPF_MAX_STR_LEN ) { \
478  return SPF_response_add_error_ptr(spf_response, \
479  SPF_E_BIG_STRING, NULL, src, \
480  "String literal too long " \
481  "(%d chars, %d max)", \
482  ds_len, SPF_MAX_STR_LEN); \
483  } \
484  data->ds.len = ds_len; \
485  len = sizeof( *data ) + ds_len; \
486  SPF_ADD_LEN_TO(*data_used, len, data_avail); \
487  data = SPF_data_next( data ); \
488  ds_len = 0; \
489  } \
490  } while(0)
491 
509 static SPF_errcode_t
510 SPF_c_parse_macro(SPF_server_t *spf_server,
511  SPF_response_t *spf_response,
512  SPF_data_t *data, size_t *data_used, size_t data_avail,
513  const char *src, size_t src_len,
514  SPF_errcode_t big_err,
515  int is_mod)
516 {
517  SPF_errcode_t err;
518  /* Generic parsing iterators and boundaries */
519  size_t idx;
520  size_t len;
521  /* For parsing strings. */
522  char *dst;
523  size_t ds_avail;
524  size_t ds_len;
525 
526  if (spf_server->debug)
527  SPF_debugf("Parsing macro starting at %s", src);
528 
529 #if 0
530  if ((void *)data != _align_ptr((void *)data))
531  SPF_errorf("Data pointer %p is not aligned: Cannot compile.",
532  data);
533 #endif
534 
535  /*
536  * Create the data blocks
537  */
538  idx = 0;
539 
540  /* Initialise the block as a string. If ds_len == 0 later, we
541  * will just clobber it. */
542  SPF_INIT_STRING_LITERAL(data_avail - *data_used);
543 
544  // while ( p != end ) {
545  while (idx < src_len) {
546  if (spf_server->debug > 3)
547  SPF_debugf("Current data is at %p", data);
548  /* Either the unit is terminated by a space, or we hit a %.
549  * We should only hit a space if we run past src_len. */
550  len = strcspn(&src[idx], " %"); // XXX Also tab?
551  if (len > 0) { /* An optimisation */
552  /* Don't over-run into the CIDR. */
553  if (idx + len > src_len)
554  len = src_len - idx;
555  if (spf_server->debug > 3)
556  SPF_debugf("Adding string literal (%lu): '%*.*s'",
557  (unsigned long)len,
558  (int)len, (int)len, &src[idx]);
559  /* XXX Bounds-check here. */
561  memcpy(dst, &src[idx], len);
562  ds_len += len;
563  dst += len;
564  idx += len;
565 
566  /* If len == 0 then we never entered the while(). Thus
567  * if idx == src_len, then len != 0 and we reach this test.
568  */
569  }
570  /* However, this logic is overcomplex and I am a simpleton,
571  * so I have moved it out of the condition above. */
572  if (idx == src_len)
573  break;
574 
575  /* Now, we must have a %-escape code, since if we hit a
576  * space, then we are at the end.
577  * Incrementing idx consumes the % we hit first, and then
578  * we switch on the following character, which also
579  * increments idx. */
580  idx++;
581  switch (src[idx]) {
582  case '%':
583  if (spf_server->debug > 3)
584  SPF_debugf("Adding literal %%");
586  *dst++ = '%';
587  ds_len++;
588  idx++;
589  break;
590 
591  case '_':
592  if (spf_server->debug > 3)
593  SPF_debugf("Adding literal space");
595  *dst++ = ' ';
596  ds_len++;
597  idx++;
598  break;
599 
600  case '-':
601  if (spf_server->debug > 3)
602  SPF_debugf("Adding escaped space");
604  *dst++ = '%'; *dst++ = '2'; *dst++ = '0';
605  ds_len += 3;
606  idx++;
607  break;
608 
609  default:
610  if (spf_server->debug > 3)
611  SPF_debugf("Adding illegal %%-follower '%c' at %zu",
612  src[idx], idx);
613  /* SPF spec says to treat it as a literal, not
614  * SPF_E_INVALID_ESC */
615  /* FIXME issue a warning? */
617  *dst++ = '%';
618  ds_len++;
619  break;
620 
621  case '{': /*vi:}*/
623  if (spf_server->debug > 3)
624  SPF_debugf("Adding macro, data is at %p", data);
625 
626  /* this must be a variable */
627  idx++;
628  err = SPF_c_parse_var(spf_response, &data->dv, &src[idx], is_mod);
629  if (err != SPF_E_SUCCESS)
630  return err;
631  idx += strcspn(&src[idx], "} ");
632  if (src[idx] == '}')
633  idx++;
634  else if (src[idx] == ' ')
635  return SPF_response_add_error_ptr(spf_response,
637  src, &src[idx],
638  "Unterminated variable?");
639 
640 
641  len = SPF_data_len(data);
642  SPF_ADD_LEN_TO(*data_used, len, data_avail);
643  data = SPF_data_next( data );
644  if (spf_server->debug > 3)
645  SPF_debugf("Next data is at %p", data);
646 
647  SPF_INIT_STRING_LITERAL(data_avail - *data_used);
648 
649  break;
650  }
651  }
652 
654 
655  return SPF_E_SUCCESS;
656 
657 }
658 
659 /* What a fuck-ugly prototype. */
674 static SPF_errcode_t
675 SPF_c_parse_domainspec(SPF_server_t *spf_server,
676  SPF_response_t *spf_response,
677  SPF_data_t *data, size_t *data_used, size_t data_avail,
678  const char *src, size_t src_len,
679  SPF_errcode_t big_err,
680  SPF_cidr_t cidr_ok, int is_mod)
681 {
682  SPF_errcode_t err;
683  /* Generic parsing iterators and boundaries */
684  size_t len;
685 
686  if (spf_server->debug)
687  SPF_debugf("Parsing domainspec starting at %s, cidr is %s",
688  src,
689  cidr_ok == CIDR_OPTIONAL ? "optional" :
690  cidr_ok == CIDR_ONLY ? "only" :
691  cidr_ok == CIDR_NONE ? "forbidden" :
692  "ERROR!"
693  );
694 
695  /*
696  * create the CIDR length info
697  */
698  if (cidr_ok == CIDR_OPTIONAL || cidr_ok == CIDR_ONLY) {
699  err = SPF_c_parse_cidr(spf_response, &data->dc, src, &src_len);
700  if (err != SPF_E_SUCCESS)
701  return err;
702  if (data->dc.ipv4 != 0 || data->dc.ipv6 != 0) {
703  len = SPF_data_len(data);
704  SPF_ADD_LEN_TO(*data_used, len, data_avail);
705  data = SPF_data_next(data);
706  }
707 
708  if (cidr_ok == CIDR_ONLY && src_len > 0) {
709  /* We had a mechanism followed by a '/', thus it HAS to be
710  * a CIDR, and the peculiar-looking error message is
711  * justified. However, we don't know _which_ CIDR. */
712  return SPF_response_add_error_ptr(spf_response,
714  NULL, src,
715  "Invalid CIDR after mechanism");
716  }
717  }
718 
719  return SPF_c_parse_macro(spf_server, spf_response,
720  data, data_used, data_avail,
721  src, src_len, big_err, is_mod);
722 }
723 
724 
730 static SPF_errcode_t
731 SPF_c_parse_ip4(SPF_response_t *spf_response, SPF_mech_t *mech, char const *start)
732 {
733  const char *end;
734  const char *p;
735 
736  char buf[ INET6_ADDRSTRLEN ];
737  size_t len;
738  SPF_errcode_t err;
739 
740  unsigned char mask;
741  struct in_addr *addr;
742 
743  start++;
744  len = strcspn(start, " ");
745  end = start + len;
746  p = end - 1;
747 
748  mask = 0;
749  while (isdigit( (unsigned char)(*p) ))
750  p--;
751  if (p != (end - 1) && *p == '/') {
752  err = SPF_c_parse_cidr_ip4(spf_response, &mask, p);
753  if (err)
754  return err;
755  end = p;
756  }
757  mech->mech_len = mask;
758 
759  len = end - start;
760  if ( len > sizeof( buf ) - 1 )
761  return SPF_E_INVALID_IP4;
762 
763  memcpy( buf, start, len );
764  buf[ len ] = '\0';
765  addr = SPF_mech_ip4_data(mech);
766  err = inet_pton( AF_INET, buf, addr );
767  if ( err <= 0 )
768  return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_IP4,
769  NULL, buf, NULL);
770 
771  return SPF_E_SUCCESS;
772 }
773 
779 static SPF_errcode_t
780 SPF_c_parse_ip6(SPF_response_t *spf_response, SPF_mech_t *mech, char const *start)
781 {
782  const char *end;
783  const char *p;
784 
785  char buf[ INET6_ADDRSTRLEN ];
786  size_t len;
787  int err;
788 
789  unsigned char mask;
790  struct in6_addr *addr;
791 
792  start++;
793  len = strcspn(start, " ");
794  end = start + len;
795  p = end - 1;
796 
797  mask = 0;
798  while (isdigit( (unsigned char)(*p) ))
799  p--;
800  if (p != (end - 1) && *p == '/') {
801  err = SPF_c_parse_cidr_ip6(spf_response, &mask, p);
802  if (err)
803  return err;
804  end = p;
805  }
806  mech->mech_len = mask;
807 
808  len = end - start;
809  if ( len > sizeof( buf ) - 1 )
810  return SPF_E_INVALID_IP6;
811 
812  memcpy( buf, start, len );
813  buf[ len ] = '\0';
814  addr = SPF_mech_ip6_data(mech);
815  err = inet_pton( AF_INET6, buf, addr );
816  if ( err <= 0 )
817  return SPF_response_add_error_ptr(spf_response, SPF_E_INVALID_IP6,
818  NULL, buf, NULL);
819 
820  return SPF_E_SUCCESS;
821 }
822 
823 
824 /* XXX TODO: Make this take (const char *) instead of (const char **)
825  * because the caller ignores the modified value. */
826 __attribute__((warn_unused_result))
827 static SPF_errcode_t
828 SPF_c_mech_add(SPF_server_t *spf_server,
829  SPF_record_t *spf_record, SPF_response_t *spf_response,
830  const SPF_mechtype_t *mechtype, int prefix,
831  const char **mech_value)
832 {
833  /* If this buffer is an irregular size, intel gcc does not align
834  * it properly, and all hell breaks loose. */
835 ALIGN_DECL(
836  char buf[SPF_RECORD_BUFSIZ];
837 );
838  SPF_mech_t *spf_mechanism = (SPF_mech_t *)ALIGNED_DECL(buf);
839  SPF_data_t *data;
840  size_t data_len;
841  size_t len;
842  size_t src_len;
843 
844  SPF_errcode_t err;
845 
846  memset(u.buf, 'B', sizeof(u.buf)); /* Poison the buffer. */
847  memset(spf_mechanism, 0, sizeof(SPF_mech_t));
848 
849  if (spf_server->debug)
850  SPF_debugf("SPF_c_mech_add: type=%d, value=%s",
851  mechtype->mech_type, *mech_value);
852 
853  spf_mechanism->prefix_type = prefix;
854  spf_mechanism->mech_type = mechtype->mech_type;
855  spf_mechanism->mech_len = 0;
856 
857  len = sizeof( SPF_mech_t );
858 
859  if ( spf_record->mech_len + len > SPF_MAX_MECH_LEN )
860  return SPF_E_BIG_MECH;
861 
862  data = SPF_mech_data(spf_mechanism);
863  data_len = 0;
864 
865  src_len = strcspn(*mech_value, " ");
866 
867  switch (mechtype->mech_type) {
868  /* We know the properties of IP4 and IP6. */
869  case MECH_IP4:
870  if (**mech_value == ':') {
871  err = SPF_c_parse_ip4(spf_response, spf_mechanism, *mech_value);
872  data_len = sizeof(struct in_addr);
873  }
874  else {
875  err = SPF_E_MISSING_OPT;
876  SPF_response_add_error_ptr(spf_response, err,
877  NULL, *mech_value,
878  "Mechanism requires a value.");
879  }
880  break;
881 
882  case MECH_IP6:
883  if (**mech_value == ':') {
884  err = SPF_c_parse_ip6(spf_response, spf_mechanism, *mech_value);
885  data_len = sizeof(struct in6_addr);
886  }
887  else {
888  err = SPF_E_MISSING_OPT;
889  SPF_response_add_error_ptr(spf_response, err,
890  NULL, *mech_value,
891  "Mechanism requires a value.");
892  }
893  break;
894 
895  default:
896  if (**mech_value == ':' || **mech_value == '=') {
897  if (mechtype->has_domainspec == DOMSPEC_NONE) {
898  err = SPF_E_INVALID_OPT;
899  SPF_response_add_error_ptr(spf_response, err,
900  NULL, *mech_value,
901  "Mechanism does not permit a value.");
902  }
903  else {
904  (*mech_value)++; src_len--;
905  err = SPF_c_parse_domainspec(spf_server,
906  spf_response,
907  data, &data_len, SPF_MAX_MECH_LEN,
908  *mech_value, src_len,
910  mechtype->has_cidr, FALSE);
911  }
912  }
913  else if (**mech_value == '/') {
914  if (mechtype->has_domainspec == DOMSPEC_REQUIRED) {
915  err = SPF_E_MISSING_OPT;
916  SPF_response_add_error_ptr(spf_response, err,
917  NULL, *mech_value,
918  "Mechanism requires a value.");
919  }
920  else if (mechtype->has_cidr == CIDR_NONE) {
921  err = SPF_E_INVALID_CIDR;
922  SPF_response_add_error_ptr(spf_response, err,
923  NULL, *mech_value,
924  "Mechanism does not permit a CIDR.");
925  }
926  else {
927  err = SPF_c_parse_domainspec(spf_server,
928  spf_response,
929  data, &data_len, SPF_MAX_MECH_LEN,
930  *mech_value, src_len,
932  CIDR_ONLY, FALSE);
933  }
934  }
935  else if (**mech_value == ' ' || **mech_value == '\0') {
936  if (mechtype->has_domainspec == DOMSPEC_REQUIRED) {
937  err = SPF_E_MISSING_OPT;
938  SPF_response_add_error_ptr(spf_response, err,
939  NULL, *mech_value,
940  "Mechanism requires a value.");
941  }
942  else {
943  err = SPF_E_SUCCESS;
944  }
945  }
946  else {
947  err = SPF_E_SYNTAX;
948  SPF_response_add_error_ptr(spf_response, err,
949  NULL, *mech_value,
950  "Unknown character '%c' after mechanism.",
951  **mech_value);
952  }
953 
954  /* Does not apply to ip4/ip6 */
955  spf_mechanism->mech_len = data_len;
956  break;
957  }
958 
959  len += data_len;
960 
961  /* Copy the thing in. */
962  if (err == SPF_E_SUCCESS) {
963  if (mechtype->is_dns_mech)
964  spf_record->num_dns_mech++;
965  if (SPF_c_ensure_capacity((void **)&spf_record->mech_first,
966  &spf_record->mech_size,
967  spf_record->mech_len + len) < 0)
968  return SPF_response_add_error_ptr(spf_response,
970  NULL, NULL,
971  "Failed to allocate memory for mechanism");
972  memcpy( (char *)spf_record->mech_first + spf_record->mech_len,
973  spf_mechanism,
974  len);
975  spf_record->mech_len += len;
976  spf_record->num_mech++;
977  }
978 
979  *mech_value += src_len;
980 
981  return err;
982 }
983 
984 __attribute__((warn_unused_result))
985 static SPF_errcode_t
986 SPF_c_mod_add(SPF_server_t *spf_server,
987  SPF_record_t *spf_record, SPF_response_t *spf_response,
988  const char *mod_name, size_t name_len,
989  const char **mod_value)
990 {
991  /* If this buffer is an irregular size, intel gcc does not align
992  * it properly, and all hell breaks loose. */
993 ALIGN_DECL(
994  char buf[SPF_RECORD_BUFSIZ];
995 );
996  SPF_mod_t *spf_modifier = (SPF_mod_t *)u.buf;
997  SPF_data_t *data;
998  size_t data_len;
999  size_t len;
1000  size_t src_len;
1001 
1002  SPF_errcode_t err;
1003 
1004  if (spf_server->debug)
1005  SPF_debugf("Adding modifier name=%lu@%s, value=%s",
1006  (unsigned long)name_len, mod_name, *mod_value);
1007 
1008  memset(u.buf, 'A', sizeof(u.buf));
1009  memset(spf_modifier, 0, sizeof(SPF_mod_t));
1010 
1011  if ( name_len > SPF_MAX_MOD_LEN )
1012  return SPF_E_BIG_MOD;
1013 
1014  spf_modifier->name_len = name_len;
1015  spf_modifier->data_len = 0;
1016 
1017  /* So that spf_modifier + len == SPF_mod_data(spf_modifier) */
1018  len = _align_sz(sizeof( SPF_mod_t ) + name_len);
1019 
1020  if ( spf_record->mod_len + len > SPF_MAX_MOD_LEN )
1021  return SPF_E_BIG_MOD;
1022 
1023  memcpy(SPF_mod_name(spf_modifier), mod_name, name_len);
1024 
1025  data = SPF_mod_data(spf_modifier);
1026  data_len = 0;
1027 
1028  src_len = strcspn(*mod_value, " ");
1029 
1030  err = SPF_c_parse_macro(spf_server,
1031  spf_response,
1032  data, &data_len, SPF_MAX_MOD_LEN,
1033  *mod_value, src_len,
1034  SPF_E_BIG_MOD,
1035  TRUE );
1036  spf_modifier->data_len = data_len;
1037  len += data_len;
1038 
1039  /* Copy the thing in. */
1040  if (err == SPF_E_SUCCESS) {
1041  if (SPF_c_ensure_capacity((void **)&spf_record->mod_first,
1042  &spf_record->mod_size,
1043  spf_record->mod_len + len) < 0)
1044  return SPF_response_add_error_ptr(spf_response,
1046  NULL, NULL,
1047  "Failed to allocate memory for modifier");
1048  memcpy( (char *)spf_record->mod_first + spf_record->mod_len,
1049  spf_modifier,
1050  len);
1051  spf_record->mod_len += len;
1052  spf_record->num_mod++;
1053  }
1054 
1055  return err;
1056 }
1057 
1058 static void
1059 SPF_record_lint(SPF_server_t *spf_server,
1060  SPF_response_t *spf_response,
1061  SPF_record_t *spf_record)
1062 {
1063  SPF_data_t *d, *data_end;
1064 
1065  char *s;
1066  char *s_end;
1067 
1068  int found_non_ip;
1069  int found_valid_tld;
1070 
1071  SPF_mech_t *mech;
1072  SPF_data_t *data;
1073 
1074  int i;
1075 
1076  /* FIXME these warnings suck. Should call SPF_id2str to give more
1077  * context. */
1078 
1079  mech = spf_record->mech_first;
1080  for (i = 0;
1081  i < spf_record->num_mech;
1082  i++,
1083  mech = SPF_mech_next( mech ) )
1084  {
1085  if ( ( mech->mech_type == MECH_ALL
1086  || mech->mech_type == MECH_REDIRECT )
1087  && i != spf_record->num_mech - 1 )
1088  {
1090  "Mechanisms found after the \"all:\" "
1091  "mechanism will be ignored.");
1092  }
1093 
1094  /*
1095  * if we are dealing with a mechanism, make sure that the data
1096  * at least looks like a valid host name.
1097  *
1098  * note: this routine isn't called to handle ip4: and ip6: and all
1099  * the other mechanisms require a host name.
1100  */
1101 
1102  if ( mech->mech_type == MECH_IP4
1103  || mech->mech_type == MECH_IP6 )
1104  continue;
1105 
1106  data = SPF_mech_data( mech );
1107  data_end = SPF_mech_end_data( mech );
1108  if ( data == data_end )
1109  continue;
1110 
1111  if ( data->dc.parm_type == PARM_CIDR )
1112  {
1113  data = SPF_data_next( data );
1114  if ( data == data_end )
1115  continue;
1116  }
1117 
1118 
1119  found_valid_tld = FALSE;
1120  found_non_ip = FALSE;
1121 
1122  for( d = data; d < data_end; d = SPF_data_next( d ) )
1123  {
1124  switch( d->dv.parm_type )
1125  {
1126  case PARM_CIDR:
1127  SPF_error( "Multiple CIDR parameters found" );
1128  break;
1129 
1130  case PARM_CLIENT_IP:
1131  case PARM_CLIENT_IP_P:
1132  case PARM_LP_FROM:
1133  found_valid_tld = FALSE;
1134  break;
1135 
1136  case PARM_STRING:
1137  found_valid_tld = FALSE;
1138 
1139  s = SPF_data_str( d );
1140  s_end = s + d->ds.len;
1141  for( ; s < s_end; s++ ) {
1142  if ( !isdigit( (unsigned char)( *s ) ) && *s != '.' && *s != ':' )
1143  found_non_ip = TRUE;
1144 
1145  if ( *s == '.' )
1146  found_valid_tld = TRUE;
1147  else if ( !isalpha( (unsigned char)( *s ) ) )
1148  found_valid_tld = FALSE;
1149  }
1150  break;
1151 
1152  default:
1153  found_non_ip = TRUE;
1154  found_valid_tld = TRUE;
1155 
1156  break;
1157  }
1158  }
1159 
1160  if ( !found_valid_tld || !found_non_ip ) {
1161  if ( !found_non_ip )
1163  "Invalid hostname (an IP address?)");
1164  else if ( !found_valid_tld )
1166  "Hostname has a missing or invalid TLD");
1167  }
1168 
1169  }
1170 
1171  /* FIXME check for modifiers that should probably be mechanisms */
1172 }
1173 
1174 
1175 
1184 SPF_record_compile(SPF_server_t *spf_server,
1185  SPF_response_t *spf_response,
1186  SPF_record_t **spf_recordp,
1187  const char *record)
1188 {
1189  const SPF_mechtype_t*mechtype;
1190  SPF_record_t *spf_record;
1191  SPF_error_t *spf_error;
1192  SPF_errcode_t err;
1193 
1194  const char *name_start;
1195  size_t name_len;
1196 
1197  const char *val_start;
1198  const char *val_end;
1199 
1200  int prefix;
1201 
1202  const char *p;
1203  int i;
1204 
1205 
1206  /*
1207  * make sure we were passed valid data to work with
1208  */
1209  SPF_ASSERT_NOTNULL(spf_server);
1210  SPF_ASSERT_NOTNULL(spf_recordp);
1211  SPF_ASSERT_NOTNULL(record);
1212 
1213  if (spf_server->debug)
1214  SPF_debugf("Compiling record %s", record);
1215 
1216  /*
1217  * and make sure that we will always set *spf_recordp
1218  * just incase we can't find a valid SPF record
1219  */
1220  *spf_recordp = NULL;
1221 
1222  /*
1223  * See if this is record is even an SPF record
1224  */
1225  p = record;
1226 
1227  if (strncasecmp(p, SPF_VER_STR, sizeof(SPF_VER_STR) - 1) != 0)
1228  return SPF_response_add_error_ptr(spf_response, SPF_E_NOT_SPF,
1229  NULL, p,
1230  "Could not find a valid SPF record");
1231  p += sizeof( SPF_VER_STR ) - 1;
1232 
1233  if ( *p != '\0' && *p != ' ' )
1234  return SPF_response_add_error_ptr(spf_response, SPF_E_NOT_SPF,
1235  NULL, p,
1236  "Could not find a valid SPF record");
1237 
1238  spf_record = SPF_record_new(spf_server, record);
1239  if (spf_record == NULL) {
1240  *spf_recordp = NULL;
1241  return SPF_response_add_error_ptr(spf_response, SPF_E_NO_MEMORY,
1242  NULL, p,
1243  "Failed to allocate an SPF record");
1244  }
1245  spf_record->version = 1;
1246  *spf_recordp = spf_record;
1247 
1248  /*
1249  * parse the SPF record
1250  */
1251  while (*p != '\0') {
1252  /* TODO WARN: If it's a \n or a \t */
1253  /* skip to the next token */
1254  while (*p == ' ')
1255  p++;
1256 
1257  if (*p == '\0')
1258  break;
1259 
1260  /* see if we have a valid prefix */
1261  prefix = PREFIX_UNKNOWN;
1262  switch (*p) {
1263  case '+':
1264  prefix = PREFIX_PASS;
1265  p++;
1266  break;
1267 
1268  case '-':
1269  prefix = PREFIX_FAIL;
1270  p++;
1271  break;
1272 
1273  case '~':
1274  prefix = PREFIX_SOFTFAIL;
1275  p++;
1276  break;
1277 
1278  case '?':
1279  prefix = PREFIX_NEUTRAL;
1280  p++;
1281  break;
1282 
1283  default:
1284  while (ispunct((unsigned char)(*p))) {
1285  SPF_response_add_error_ptr(spf_response,
1287  "Invalid prefix '%c'", *p);
1288  p++;
1289  }
1290  break;
1291  }
1292 
1293  name_start = p;
1294  val_end = name_start + strcspn(p, " ");
1295 
1296  /* get the mechanism/modifier */
1297  if ( ! isalpha( (unsigned char)*p ) ) {
1298  /* We could just bail on this one. */
1299  SPF_response_add_error_ptr(spf_response,
1301  "Invalid character at start of mechanism");
1302  p += strcspn(p, " ");
1303  continue;
1304  }
1305  while ( isalnum( (unsigned char)*p ) || *p == '_' || *p == '-' )
1306  p++;
1307 
1308 /* TODO: These or macros like them are used in several places. Merge. */
1309 #define STREQ_SIZEOF(a, b) \
1310  (strncasecmp((a), (b), sizeof( (b) ) - 1) == 0)
1311 #define STREQ_SIZEOF_N(a, b, n) \
1312  (((n) == sizeof(b) - 1) && (strncasecmp((a),(b),(n)) == 0))
1313 
1314  /* See if we have a modifier or a prefix */
1315  name_len = p - name_start;
1316 
1317  if (spf_server->debug)
1318  SPF_debugf("Name starts at %s", name_start);
1319 
1320  switch ( *p )
1321  {
1322  case ':':
1323  case '/':
1324  case ' ':
1325  case '\0':
1326  compile_mech: /* A bona fide label */
1327 
1328  /*
1329  * parse the mechanism
1330  */
1331 
1332  /* mechanisms default to PREFIX_PASS */
1333  if ( prefix == PREFIX_UNKNOWN )
1334  prefix = PREFIX_PASS;
1335 
1336  if ( STREQ_SIZEOF_N(name_start, "a", name_len) )
1337  mechtype = SPF_mechtype_find(MECH_A);
1338  else if ( STREQ_SIZEOF_N(name_start, "mx", name_len) )
1339  mechtype = SPF_mechtype_find(MECH_MX);
1340  else if ( STREQ_SIZEOF_N(name_start, "ptr", name_len) )
1341  mechtype = SPF_mechtype_find(MECH_PTR);
1342  else if ( STREQ_SIZEOF_N(name_start, "include", name_len) )
1343  mechtype = SPF_mechtype_find(MECH_INCLUDE);
1344  else if ( STREQ_SIZEOF_N(name_start, "ip4", name_len) )
1345  mechtype = SPF_mechtype_find(MECH_IP4);
1346  else if ( STREQ_SIZEOF_N(name_start, "ip6", name_len) )
1347  mechtype = SPF_mechtype_find(MECH_IP6);
1348  else if ( STREQ_SIZEOF_N(name_start, "exists", name_len) )
1349  mechtype = SPF_mechtype_find(MECH_EXISTS);
1350  else if ( STREQ_SIZEOF_N(name_start, "all", name_len) )
1351  mechtype = SPF_mechtype_find(MECH_ALL);
1352 #ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1353  else if ( STREQ_SIZEOF_N(name_start,
1354  "default=allow", name_len) )
1355  {
1357  NULL, name_start,
1358  "Deprecated option 'default=allow'");
1359  mechtype = SPF_mechtype_find(MECH_ALL);
1360  prefix = PREFIX_PASS;
1361  }
1362  else if (STREQ_SIZEOF_N(name_start,
1363  "default=softfail",name_len))
1364  {
1366  NULL, name_start,
1367  "Deprecated option 'default=softfail'");
1368  mechtype = SPF_mechtype_find(MECH_ALL);
1369  prefix = PREFIX_SOFTFAIL;
1370  }
1371  else if ( STREQ_SIZEOF_N(name_start,
1372  "default=deny", name_len) )
1373  {
1375  NULL, name_start,
1376  "Deprecated option 'default=deny'");
1377  mechtype = SPF_mechtype_find(MECH_ALL);
1378  prefix = PREFIX_FAIL;
1379  }
1380  else if ( STREQ_SIZEOF(name_start, "default=") )
1381  {
1383  NULL, name_start,
1384  "Invalid modifier 'default=...'");
1385  p = val_end;
1386  continue;
1387  }
1388 #endif
1389  /* FIXME the redirect mechanism needs to be moved to
1390  * the very end */
1391  else if ( STREQ_SIZEOF_N(name_start, "redirect", name_len) )
1392  mechtype = SPF_mechtype_find(MECH_REDIRECT);
1393  else
1394  {
1396  NULL, name_start,
1397  "Unknown mechanism found");
1398  p = val_end;
1399  continue;
1400  }
1401 
1402  if (mechtype == NULL) {
1403  return SPF_response_add_error_ptr(spf_response,
1405  NULL, name_start,
1406  "Failed to find specification for "
1407  "a recognised mechanism");
1408  }
1409 
1410  if (spf_server->debug)
1411  SPF_debugf("Adding mechanism type %d",
1412  (int)mechtype->mech_type);
1413 
1414  val_start = p;
1415  err = SPF_c_mech_add(spf_server,
1416  spf_record, spf_response,
1417  mechtype, prefix, &val_start);
1418  if (err == SPF_E_NO_MEMORY)
1419  return err;
1420  /* XXX Else do nothing. Continue for the next error. */
1421  /* We shouldn't have to worry about the child function
1422  * updating the pointer. So we just use our 'well known'
1423  * copy. */
1424  p = val_end;
1425  break;
1426 
1427  case '=':
1428 
1429  /*
1430  * parse the modifier
1431  */
1432 
1433  /* modifiers can't have prefixes */
1434  if (prefix != PREFIX_UNKNOWN)
1436  NULL, name_start,
1437  "Modifiers may not have prefixes");
1438  prefix = PREFIX_UNKNOWN; /* For redirect/include */
1439 
1440 #ifdef SPF_ALLOW_DEPRECATED_DEFAULT
1441  /* Deal with legacy special case */
1442  if ( STREQ_SIZEOF(name_start, "default=") ) {
1443  /* Consider the whole 'default=foo' as a token. */
1444  p = val_end;
1445  name_len = p - name_start;
1446  goto compile_mech;
1447  }
1448 #endif
1449 
1450  /* We treat 'redirect' as a mechanism. */
1451  if ( STREQ_SIZEOF(name_start, "redirect=") )
1452  goto compile_mech;
1453 
1454  p++;
1455  val_start = p;
1456  err = SPF_c_mod_add(spf_server,
1457  spf_record, spf_response,
1458  name_start, name_len, &val_start);
1459  if (err == SPF_E_NO_MEMORY)
1460  return err;
1461  /* XXX Else do nothing. Continue for the next error. */
1462  p = val_end;
1463  break;
1464 
1465 
1466  default:
1468  NULL, p,
1469  "Invalid character in middle of mechanism");
1470  p = val_end;
1471  break;
1472  }
1473  }
1474 
1475 
1476  /*
1477  * check for common mistakes
1478  */
1479  SPF_record_lint(spf_server, spf_response, spf_record);
1480 
1481 
1482  /*
1483  * do final cleanup on the record
1484  */
1485 
1486  /* FIXME realloc (shrink) spfi buffers? */
1487 
1488  if (SPF_response_errors(spf_response) > 0) {
1489  for (i = 0; i < SPF_response_messages(spf_response); i++) {
1490  spf_error = SPF_response_message(spf_response, i);
1491  if (SPF_error_errorp(spf_error))
1492  return SPF_error_code(spf_error);
1493  }
1494  return SPF_response_add_error(spf_response,
1496  "Response has errors but can't find one!");
1497  }
1498 
1499  return SPF_E_SUCCESS;
1500 }
1501 
1503 SPF_record_compile_macro(SPF_server_t *spf_server,
1504  SPF_response_t *spf_response,
1505  SPF_macro_t **spf_macrop,
1506  const char *record)
1507 {
1508 ALIGN_DECL(
1509  char buf[sizeof(SPF_macro_t) + SPF_MAX_MOD_LEN];
1510 );
1511  SPF_macro_t *spf_macro = (SPF_macro_t *)ALIGNED_DECL(buf);
1512  SPF_data_t *data;
1513  SPF_errcode_t err;
1514  size_t size;
1515 
1516  data = SPF_macro_data(spf_macro);
1517  spf_macro->macro_len = 0;
1518 
1519  err = SPF_c_parse_macro(spf_server, spf_response,
1520  data, &spf_macro->macro_len, SPF_MAX_MOD_LEN,
1521  record, strlen(record),
1522  SPF_E_BIG_MOD, TRUE);
1523  if (err != SPF_E_SUCCESS)
1524  return err;
1525 
1526  /* XXX TODO: Tidy this up? */
1527  size = sizeof(SPF_macro_t) + spf_macro->macro_len;
1528  *spf_macrop = (SPF_macro_t *)malloc(size);
1529  if (!*spf_macrop)
1530  return SPF_E_NO_MEMORY;
1531  memcpy(*spf_macrop, ALIGNED_DECL(buf), size);
1532 
1533  return SPF_E_SUCCESS;
1534 }
#define SPF_CHECK_IN_MODIFIER()
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
#define SPF_MAX_MECH_LEN
Definition: spf_record.h:77
unsigned short delim_bar
Definition: spf_record.h:125
#define SPF_ASSERT_NOTNULL(x)
Definition: spf_log.h:118
#define SPF_FINI_STRING_LITERAL()
Definition: spf_compile.c:475
SPF_errcode_t SPF_error_code(SPF_error_t *err)
Definition: spf_response.c:314
SPF_data_cidr_t dc
Definition: spf_record.h:145
#define PREFIX_UNKNOWN
Definition: spf_record.h:157
#define PARM_CLIENT_IP
Definition: spf_record.h:92
unsigned char len
Definition: spf_record.h:107
int strncasecmp(const char *s1, const char *s2, size_t n)
Definition: strncasecmp.c:11
#define SPF_MAX_MOD_LEN
Definition: spf_record.h:78
SPF_errcode_t SPF_response_add_warn(SPF_response_t *rp, SPF_errcode_t code, const char *format,...)
Definition: spf_response.c:282
#define spf_num_mechanisms
Definition: spf_compile.c:91
unsigned char mech_type
Definition: spf_compile.c:72
#define MECH_ALL
Definition: spf_record.h:170
#define SPF_ADD_LEN_TO(_val, _len, _max)
Definition: spf_compile.c:441
unsigned short delim_under
Definition: spf_record.h:126
#define PREFIX_FAIL
Definition: spf_record.h:154
#define PARM_REC_DOM
Definition: spf_record.h:98
#define PARM_ENV_FROM
Definition: spf_record.h:89
void *size_t size
Definition: malloc.c:8
#define const
#define TRUE
Definition: spf_internal.h:23
#define STREQ_SIZEOF(a, b)
#define PARM_CLIENT_IP_P
Definition: spf_record.h:93
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:1184
unsigned char parm_type
Definition: spf_record.h:132
#define PREFIX_PASS
Definition: spf_record.h:153
#define STREQ_SIZEOF_N(a, b, n)
unsigned short delim_dash
Definition: spf_record.h:122
char SPF_error_errorp(SPF_error_t *err)
Definition: spf_response.c:326
SPF_record_t * SPF_record_new(SPF_server_t *spf_server, const char *text)
Definition: spf_record.c:48
SPF_errcode_t SPF_response_add_error(SPF_response_t *rp, SPF_errcode_t code, const char *format,...)
Definition: spf_response.c:256
#define MECH_IP6
Definition: spf_record.h:168
SPF_data_var_t dv
Definition: spf_record.h:143
if(optstring[0]== '-')
#define PREFIX_SOFTFAIL
Definition: spf_record.h:155
unsigned char parm_type
Definition: spf_record.h:117
size_t len
Definition: memcmp.c:10
unsigned short delim_dot
Definition: spf_record.h:121
#define SPF_ENSURE_STRING_AVAIL(_len)
Definition: spf_compile.c:466
#define ALIGNED_DECL(var)
Definition: spf_compile.c:65
#define SPF_RECORD_BUFSIZ
Definition: spf_compile.c:62
#define PARM_CLIENT_DOM
Definition: spf_record.h:95
#define SPF_error(errmsg)
Definition: spf_log.h:40
SPF_errcode_t
Definition: spf_response.h:118
unsigned short delim_equal
Definition: spf_record.h:124
unsigned short rev
Definition: spf_record.h:119
#define MECH_EXISTS
Definition: spf_record.h:169
#define MECH_PTR
Definition: spf_record.h:165
unsigned char num_rhs
Definition: spf_record.h:118
#define NULL
Definition: spf_internal.h:28
#define SPF_INIT_STRING_LITERAL(_avail)
Definition: spf_compile.c:452
#define PARM_CLIENT_VER
Definition: spf_record.h:96
#define PARM_CUR_DOM
Definition: spf_record.h:91
#define MECH_INCLUDE
Definition: spf_record.h:166
SPF_domspec_t has_domainspec
Definition: spf_compile.c:74
#define FALSE
Definition: spf_internal.h:24
#define PARM_DP_FROM
Definition: spf_record.h:90
SPF_data_str_t ds
Definition: spf_record.h:144
unsigned char ipv6
Definition: spf_record.h:134
#define PARM_HELO_DOM
Definition: spf_record.h:97
SPF_error_t * SPF_response_message(SPF_response_t *rp, int idx)
Definition: spf_response.c:308
#define MECH_A
Definition: spf_record.h:163
SPF_cidr_t has_cidr
Definition: spf_compile.c:75
unsigned short delim_plus
Definition: spf_record.h:123
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:1503
unsigned char is_dns_mech
Definition: spf_compile.c:73
#define PARM_CIDR
Definition: spf_record.h:99
int SPF_response_messages(SPF_response_t *rp)
Definition: spf_response.c:290
#define SPF_debugf
Definition: spf_log.h:80
#define MECH_MX
Definition: spf_record.h:164
#define ALIGN_DECL(decl)
Definition: spf_compile.c:64
#define SPF_errorf
Definition: spf_log.h:77
#define MECH_IP4
Definition: spf_record.h:167
unsigned short mech_len
Definition: spf_record.h:178
#define __attribute__(x)
Definition: spf.h:17
SPF_domspec_t
Definition: spf_compile.c:52
unsigned char ipv4
Definition: spf_record.h:133
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
#define MECH_REDIRECT
Definition: spf_record.h:171
#define MECH_UNKNOWN
Definition: spf_record.h:162
int SPF_response_errors(SPF_response_t *rp)
Definition: spf_response.c:296
#define PARM_TIME
Definition: spf_record.h:94
#define PREFIX_NEUTRAL
Definition: spf_record.h:156
#define PARM_STRING
Definition: spf_record.h:100
u_int const u_char * src
Definition: __ns_get16.c:16
unsigned short url_encode
Definition: spf_record.h:120
SPF_cidr_t
Definition: spf_compile.c:47
#define SPF_VER_STR
Definition: spf.h:35
#define PARM_LP_FROM
Definition: spf_record.h:88