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

Generated on Thu Sep 16 18:10:46 2004 for libSPF v1.0 by doxygen 1.3.8