libSPF v1.0: macro.c Source File

Main Page | Data Structures | File List | Data Fields | Globals | Search for

# macro.c

Go to the documentation of this file.

    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:   util.c
    00009 *  Desc:   Utility functions
    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 #include "spf.h"
    00046 #include "dns.h"
    00047 #include "macro.h"
    00048 #include "util.h"
    00049
    00050
    00051 /* MACRO_expand
    00052 *
    00053 *  Author: Sean Comeau <scomeau@obscurity.org>
    00054 *  Author: James Couzens <jcouzens@codeshare.ca>
    00055 *
    00056 *  Date:    01/18/04
    00057 *  Updated: 06/29/04 Roger Moser <Roger.Moser@pamho.net>
    00058 *
    00059 *  Desc:
    00060 *        Walks a string of macros tokenizing and expanding them along the
    00061 *  way, each token being inserted as a node into a linked list.  Once the
    00062 *  walk is complete the list is walked and the nodes are copied back out
    00063 *  in the order they were added as expanded macros into a string which is
    00064 *  then passed back to the calling function.
    00065 *
    00066 *  MACRO_freebuf is removed and I moved the code inside of this function since
    00067 *  before calling it, it was being walked anyway to copy out each string into
    00068 *  the return buffer, so now it just free's directly after and then destructs.
    00069 *
    00070 */
    00071 char *MACRO_expand(peer_info_t *p, const char *s)
    00072 {
    00073   const char * const macro_p = "%";     /* % (literal) */
    00074   const char * const macro_d = "%20";   /* "URL" space */
    00075   const char * const macro_u = " ";     /* whitespace */
    00076
    00077   char *buf;                            /* return buffer */
    00078   char *ptr;                            /* working pointer */
    00079   char *cp;                             /* working pointer */
    00080   char *macro;
    00081   char *s_macro;                        /* single char macro */
    00082
    00083   strbuf_t *master;                     /* list pointers */
    00084   strbuf_node_t *c_node;                /* c_node node */
    00085   strbuf_node_t *kill_node;             /* temp node used in destruct */
    00086
    00087   size_t len;                           /* leng of passed string */
    00088   size_t i = 0;                         /* index on a str */
    00089   size_t length = 0;                    /* overall len of expanded str */
    00090
    00091
    00092   if (s == NULL)
    00093   {
    00094     xepprintf("Passed a NULL string.  Abort!\n");
    00095     return(NULL);
    00096   }
    00097
    00098   len = strlen(s);
    00099   ptr = cp = xstrndup(s, (len + 1));
    00100
    00101   master = xmalloc(SIZEOF(strbuf_t));
    00102   master->head      = NULL;
    00103   master->elements  = 0;
    00104   length            = 0;
    00105
    00106   while (*ptr)
    00107   {
    00108      /*
    00109      * This works by moving through the string and replacing non-essential
    00110      * elements with NULL chars until the character designating an expansion
    00111      * mechanism is found.  The character is then sent off to MACRO_process
    00112      * for expansion
    00113     */
    00114     if (*ptr == '%') /* start of macro */
    00115     {
    00116       switch (*(ptr + 1))
    00117       {
    00118         case '%':
    00119
    00120           /* convert %% into % */
    00121           if (MACRO_addbuf(master, (char *)macro_p, 1) == SPF_FALSE)
    00122           {
    00123             xvprintf("Unable to allocate list node with (%c)!\n", macro_p);
    00124
    00125             return(NULL);
    00126           }
    00127
    00128           ptr += 2;
    00129           length++;
    00130           break;
    00131
    00132         case '_':
    00133
    00134           /* convert %_ to a white space */
    00135           if (MACRO_addbuf(master, (char *)macro_u, 1) == SPF_FALSE)
    00136           {
    00137             xvprintf("Unable to allocate list node with (%c)!\n", macro_u);
    00138
    00139             return(NULL);
    00140           }
    00141
    00142           ptr += 2;
    00143           length++;
    00144           break;
    00145
    00146         case '-':
    00147
    00148           /* convert %- into URL encoded '%20' */
    00149           if (MACRO_addbuf(master, (char *)macro_d, 3) == SPF_FALSE)
    00150           {
    00151             xvprintf("Unable to allocate list node with (%s)!\n", macro_d);
    00152
    00153             return(NULL);
    00154           }
    00155
    00156           ptr    += 2;
    00157           length += 3;
    00158           break;
    00159
    00160         case '{':
    00161
    00162           *ptr++ = '\0'; /* % */
    00163           *ptr++ = '\0'; /* { */
    00164
    00165           if ((i = UTIL_index(ptr, '}')) == 0)
    00166           {
    00167             xvprintf("'}' Invalid Macro (%c)\n", *(s + 1));
    00168
    00169             return(NULL);  /* not closed, invalid macro */
    00170           }
    00171
    00172           *(ptr + i) = '\0'; /* } */
    00173
    00174           xvprintf("Actual macro (%s)\n", ptr);
    00175           if ((macro = MACRO_process(p, ptr, (i + 1))) == NULL)
    00176           {
    00177             xepprintf("macro process returned null!\n");
    00178           }
    00179           else
    00180           {
    00181             length += strlen(macro);
    00182             xvprintf("Macro expanded to: (%s) %i bytes\n", macro,
    00183               strlen(macro));
    00184
    00185             if (MACRO_addbuf(master, macro, strlen(macro)) == SPF_FALSE)
    00186             {
    00187               xvprintf("Unable to allocate list node with (%s)!\n", macro);
    00188               xfree(macro);
    00189
    00190               return(NULL);  /* not closed, invalid macro */
    00191             }
    00192             xfree(macro);
    00193           }
    00194           ptr += i;
    00195           break;
    00196
    00197         default:
    00198
    00199           xvprintf("ERROR: Invalid macro. (%s) Abort!\n", *(ptr + 1));
    00200
    00201           /* need cleanup function call perhaps */
    00202           return(NULL);
    00203           break;
    00204
    00205       } /* switch */
    00206     } /* if */
    00207     else
    00208     {
    00209       if ((i = UTIL_index(ptr, '%')) == 0)
    00210       {
    00211         while (*(ptr + i))
    00212         {
    00213           i++;
    00214         }
    00215         s_macro = xmalloc(i + 1);
    00216         memcpy(s_macro, ptr, (i + 1));
    00217       }
    00218       else
    00219       {
    00220         s_macro = xmalloc(i + 1);
    00221         memcpy(s_macro, ptr, i);
    00222       }
    00223
    00224       length += i;
    00225
    00226       if (MACRO_addbuf(master, s_macro, (i + 1)) == SPF_FALSE)
    00227       {
    00228         xvprintf("Unable to allocate list node with (%s)!\n", s_macro);
    00229
    00230         return(NULL);
    00231       }
    00232
    00233       ptr += (i - 1);
    00234       xvprintf("Freeing s_macro temp buf (%s)\n", s_macro);
    00235       xfree(s_macro);
    00236     }
    00237     ptr++;
    00238     xvprintf("Remaining buffer (%s)\n", ptr);
    00239   } /* while */
    00240
    00241   xprintf("Allocated %i bytes for return buf\n", length);
    00242   buf = xmalloc(length + 1);
    00243
    00244   c_node = master->head;
    00245   while (c_node != NULL)
    00246   {
    00247     kill_node = c_node;
    00248
    00249     if (kill_node->len > 1)
    00250     {
    00251       xvprintf("NODE: (%s) LEN: %i\n", kill_node->s, kill_node->len);
    00252     }
    00253     else
    00254     {
    00255       xvprintf("NODE: (%c) LEN: %i\n", kill_node->s, kill_node->len);
    00256     }
    00257
    00258     strncat(buf, kill_node->s, kill_node->len);
    00259     xfree(kill_node->s);
    00260     c_node = c_node->next;
    00261     xfree(kill_node);
    00262   }
    00263
    00264   xfree(cp);
    00265   xfree(master);
    00266
    00267   xvprintf("Returning expanded macro: (%s)\n", buf);
    00268
    00269   return(buf);
    00270 }
    00271
    00272
    00273 /* MACRO_process
    00274 *
    00275 *  Author: James Couzens <jcouzens@codeshare.ca>
    00276 *
    00277 *  Date:   01/21/04
    00278 *
    00279 *  Desc:
    00280 *         This function takes a NULL terminated string containing only one
    00281 *  macro. It returns a new string containing whatever that macro expanded to.
    00282 *  Returns NULL if the macro can not be expanded.
    00283 *
    00284 *  exists:%{ir}.%{l1r+-}._spf.%{d}
    00285 *
    00286 *  Date:   08/??/04 - Travis Anderson <tanderson@codeshare.ca>
    00287 *
    00288 *  Desc:
    00289 *          Fixed problematic 'p' macro with the addition of new DNS function
    00290 *  DNS_check_client_reverse.
    00291 *
    00292 *  Date:   09/11/04 - James Couzens <jcouzens@codeshare.ca>
    00293 *
    00294 *  Desc:
    00295 *          Removed strlen calls originally intended for replacement
    00296 *  with either a generic limit (SPF_MAX_STR), or a more stringent limit safely
    00297 *  imposed upon the malloc.
    00298 *
    00299 *
    00300 */
    00301 char *MACRO_process(peer_info_t *p, char *macro, const size_t size)
    00302 {
    00303   int c;             /* stores a lower case version of the macro if necessary */
    00304
    00305   size_t i;          /* utility for string lengths */
    00306
    00307   char *rev_addr;    /* used by p macro */
    00308
    00309
    00310   if (macro == NULL)
    00311   {
    00312     xepprintf("Passed a NULL string.  Abort!\n");
    00313
    00314     return(SPF_FALSE);
    00315   }
    00316
    00317   xprintf("called with (%s) and len: %i\n",macro, size);
    00318
    00319   rev_addr = NULL;
    00320   i = 0;
    00321
    00322   if (isupper(*macro))
    00323   {
    00324     c = tolower(*macro);
    00325   }
    00326   else
    00327   {
    00328     c = *macro;
    00329   }
    00330
    00331   switch (c)
    00332   {
    00333     /* */
    00334     case 'd':
    00335       if (*(macro + 1))
    00336       {
    00337         return(MACRO_eatmore(macro, p->current_domain));
    00338       }
    00339       else
    00340       {
    00341         xvprintf("macro 'd' expands to: (%s)\n",
    00342           p->current_domain);
    00343
    00344         return(xstrndup(p->current_domain, SPF_MAX_STR));
    00345       }
    00346     /* */
    00347     case 'h':
    00348       if (*(macro + 1))
    00349       {
    00350         return(MACRO_eatmore(macro, p->helo));
    00351       }
    00352       else
    00353       {
    00354         xvprintf("macro 'h' expands to: (%s)\n", p->helo);
    00355
    00356         if (p->helo != NULL)
    00357         {
    00358           return(xstrndup(p->helo, SPF_MAX_ENV_HELO));
    00359         }
    00360         else
    00361         {
    00362           return(xstrndup(p->ehlo, SPF_MAX_ENV_HELO));
    00363         }
    00364       }
    00365     /* */
    00366     case 'i':
    00367       if (*(macro + 1))
    00368       {
    00369         return(MACRO_eatmore(macro, p->r_ip));
    00370       }
    00371       else
    00372       {
    00373         xvprintf("macro 'i' expands to: (%s)\n", p->r_ip);
    00374
    00375         return(xstrndup(p->r_ip, SPF_MAX_IP_ADDR));
    00376       }
    00377     /* */
    00378     case 'l':
    00379       if (*(macro + 1))
    00380       {
    00381         return(MACRO_eatmore(macro, p->local_part));
    00382       }
    00383       else
    00384       {
    00385         xvprintf("macro 'l' expands to: (%s)\n", p->local_part);
    00386
    00387         return(xstrndup(p->local_part, SPF_MAX_LOCAL_PART));
    00388       }
    00389     /* */
    00390     case 'o':
    00391       if (*(macro + 1))
    00392       {
    00393         return(MACRO_eatmore(macro, p->current_domain));
    00394       }
    00395       else
    00396       {
    00397         xvprintf("macro 'o' expands to: (%s)\n",
    00398           p->current_domain);
    00399
    00400         return(xstrndup(p->current_domain, SPF_MAX_STR));
    00401       }
    00402     /* */
    00403     case 'p':
    00404       if (DNS_check_client_reverse(p) == SPF_FALSE)
    00405       {
    00406         p->r_vhname = xmalloc(8);
    00407         snprintf(p->r_vhname, 8, "unknown");
    00408       }
    00409
    00410       if (*(macro + 1))
    00411       {
    00412         xvprintf("macro 'p' expands to: (%s)\n", p->r_vhname);
    00413
    00414         return(MACRO_eatmore(macro, p->r_vhname));
    00415       }
    00416       else
    00417       {
    00418         xvprintf("macro 'p' expands to: (%s)\n", p->r_vhname);
    00419
    00420         return(xstrndup(p->r_vhname, SPF_MAX_STR));
    00421       }
    00422     /* */
    00423     case 's':
    00424
    00425       if ((p->cur_eaddr != NULL) || p->cur_eaddr)
    00426       {
    00427         xfree(p->cur_eaddr);
    00428       }
    00429
    00430       xprintf("local-part: (%s); current domain: (%s)\n",
    00431         p->local_part, p->current_domain);
    00432       i = ((strlen(p->local_part) + strlen(p->current_domain) + 2));
    00433       p->cur_eaddr = xmalloc(i);
    00434       snprintf(p->cur_eaddr, i, "%s@%s",
    00435         p->local_part, p->current_domain);
    00436
    00437       if (*(macro + 1))
    00438       {
    00439         return(MACRO_eatmore(macro, p->cur_eaddr));
    00440       }
    00441       else
    00442       {
    00443         xvprintf("macro 's' expands to: (%s)\n", p->cur_eaddr);
    00444
    00445         return(xstrndup(p->cur_eaddr, SPF_MAX_STR));
    00446       }
    00447     /* */
    00448     case 't':
    00449       if (*(macro + 1))
    00450       {
    00451         return(MACRO_eatmore(macro, p->utc_time));
    00452       }
    00453       else
    00454       {
    00455         xvprintf("macro 't' expands to: (%s)\n", p->utc_time);
    00456
    00457         return(xstrndup(p->utc_time, SPF_MAX_UTC_TIME));
    00458       }
    00459     /* */
    00460     case 'v':
    00461       if (*(macro + 1))
    00462       {
    00463         return(MACRO_eatmore(macro, p->ip_ver));
    00464       }
    00465       else
    00466       {
    00467         xvprintf("macro 'v' expands to: (%s)\n", p->ip_ver);
    00468         return(xstrndup(p->ip_ver, SPF_MAX_IP_ADDR));
    00469       }
    00470     /* */
    00471     case 'x':
    00472       if (size > 1)
    00473       {
    00474         if (*(macro + 1) == 'R' || *(macro + 1) == 'r')
    00475         {
    00476           return(xstrndup(p->mta_hname, SPF_MAX_HNAME));
    00477         }
    00478       }
    00479       break;
    00480
    00481     default:
    00482       return(xstrndup(macro, SPF_MAX_STR));
    00483   } /* switch */
    00484
    00485   return(NULL);
    00486 }
    00487
    00488
    00489 /* MACRO_eatmore
    00490 *
    00491 *  Author: James Couzens <jcouzens@codeshare.ca>
    00492 *
    00493 *  Date:   01/22/04
    00494 *  Date:   07/02/04 James Couzens <jcouzens@codeshare.ca> (compiler warnings)
    00495 *
    00496 *  Desc:
    00497 *         This function is called whenever a macro is more than one character
    00498 *  long and so we have to 'eatmore' ;-)  macro is the unexpanded macro and
    00499 *  s is the expanded string of the original macro would have been returned as
    00500 *  had it been single.  Returns the expanded macro using dynamically allocated
    00501 *  memory upon success and in the process will FREE s after allocating more
    00502 *  memory (if necessary) and copying it over.  Returns NULL upon failure.
    00503 *
    00504 */
    00505 char *MACRO_eatmore(char *macro, char *s)
    00506 {
    00507   size_t i;          /* how much of the buffer we are using */
    00508
    00509   char delim;        /* marco is a delimiter modifier */
    00510
    00511   char *cp;          /* working pointer */
    00512   char *buf;         /* return buffer */
    00513   char *rev_str;     /* temporary buffer */
    00514   char *d_buf;       /* temporary buffer */
    00515
    00516   u_int8_t n_dot;    /* number of 'delimiter' items in a string */
    00517   u_int8_t rev;      /* string to be reversed */
    00518   u_int8_t digit;    /* macro is a digit modifier */
    00519
    00520
    00521   if (macro == NULL)
    00522   {
    00523     xepprintf("Passed a NULL string.  Abort!\n");
    00524     return(NULL);
    00525   }
    00526
    00527   xprintf("Called with macro (%s) and string (%s)\n", macro, s);
    00528
    00529   /* need a proper value for this not just SPF_MAX_MACRO need to know the MAXIMUM
    00530    * expandable length of a macro. */
    00531
    00532   cp      = macro;
    00533   rev     = 0;
    00534   digit   = 0;
    00535   delim   = '.';
    00536   buf     = NULL;
    00537   rev_str = NULL;
    00538
    00539   while (*cp)
    00540   {
    00541     if (isdigit(*cp))
    00542     {
    00543       digit = atoi(cp);
    00544     }
    00545     else if (UTIL_is_spf_delim(*cp) == SPF_TRUE)
    00546     {
    00547       delim = *cp;
    00548     }
    00549     else if ((*cp == 'r') || (*cp == 'R'))
    00550     {
    00551       rev = 1;
    00552     }
    00553     cp++;
    00554   }
    00555
    00556   xvprintf("mac:(%s) r:(%i) dig:(%i) dlm: (%c)\n",
    00557     macro, rev, digit, delim);
    00558
    00559   i = 0;
    00560   /* reverse the string */
    00561   if (rev == 1)
    00562   {
    00563     /*delim = '.';*/
    00564     rev_str = UTIL_reverse(s, delim);
    00565     s = NULL;
    00566   }
    00567
    00568   if (s == NULL)
    00569   {
    00570     cp = rev_str;
    00571   }
    00572   else
    00573   {
    00574     cp = s;
    00575   }
    00576
    00577   /* exercise digit modifier on string */
    00578   if (digit > 0)
    00579   {
    00580     n_dot = UTIL_count_delim(cp, delim);
    00581
    00582     if (digit > n_dot)
    00583     {
    00584       digit = n_dot;
    00585     }
    00586
    00587     if ((d_buf = UTIL_split_strr(cp, delim, digit)) != NULL)
    00588     {
    00589       i = strlen(d_buf);
    00590     }
    00591     else
    00592     {
    00593       d_buf = cp;
    00594       i = strlen(d_buf);
    00595     }
    00596
    00597     buf = xmalloc(i + 1);
    00598     memcpy(buf, d_buf, (i + 1));
    00599
    00600     if (d_buf != cp)
    00601     {
    00602       xfree(d_buf);
    00603     }
    00604   }
    00605   else if (rev == 1)
    00606   {
    00607     buf = xstrndup(rev_str, SPF_MAX_MACRO);
    00608   }
    00609
    00610   xvprintf("Returning (%s) (%i bytes)\n", buf, strlen(buf));
    00611
    00612   if (rev == 1)
    00613   {
    00614     xfree(rev_str);
    00615   }
    00616
    00617   return(buf);
    00618 }
    00619
    00620
    00621 /* MACRO_addbuf
    00622 *
    00623 *  Author: Sean Comeau <scomeau@obscurity.org>
    00624 *  Author: James Couznes <jcouzens@codeshare.ca>
    00625 *
    00626 *  Date:    01/18/04
    00627 *  Updated: 01/24/04
    00628 *
    00629 *
    00630 *  Desc:
    00631 *         Appends nodes to a master list which is passed of type
    00632 *  strbuf_t.  The nodes are of type strbuf_node_t and appended on
    00633 *  the end and the list is reordered to reflect this.  Returns
    00634 *  SPF_TRUE upon success and SPF_FALSE
    00635 *  upon failure.
    00636 *
    00637 */
    00638 SPF_BOOL MACRO_addbuf(strbuf_t *master, char *s, size_t size)
    00639 {
    00640   strbuf_node_t *c_node     = NULL;  /* c_node working node */
    00641   strbuf_node_t *new_node   = NULL;  /* newly allocated node */
    00642   strbuf_node_t *prev_node  = NULL;  /* previous working node */
    00643
    00644
    00645   if (s == NULL)
    00646   {
    00647     xepprintf("Passed a NULL string.  Abort!\n");
    00648
    00649     return(SPF_FALSE);
    00650   }
    00651
    00652   xvprintf("Called with (%s) %i (%i) bytes.\n", s, size, strlen(s));
    00653
    00654   new_node    = xmalloc(SIZEOF(strbuf_node_t));
    00655   new_node->s = xmalloc(size + 1);
    00656
    00657   strncpy(new_node->s, s, size);
    00658   new_node->len   = size;
    00659   new_node->next  = NULL;
    00660
    00661   xvprintf("Added (%s) to node of len: %i)\n", new_node->s,
    00662     new_node->len);
    00663
    00664   prev_node = NULL;
    00665   c_node    = master->head;
    00666
    00667   /* reorder the list with the NEW element on the end */
    00668   while (c_node != NULL)
    00669   {
    00670     prev_node = c_node;
    00671     c_node    = c_node->next;
    00672   }
    00673
    00674   if (prev_node != NULL)
    00675   {
    00676     new_node->next  = prev_node->next;
    00677     prev_node->next = new_node;
    00678   }
    00679   else
    00680   {
    00681     master->head = new_node;
    00682   }
    00683
    00684   master->elements++;
    00685
    00686   return(SPF_TRUE);
    00687 }
    00688
    00689 /* end macro.c */
    00690