macro.c

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

Generated on Thu Jul 1 14:05:44 2004 for libspf v1.0 by doxygen 1.3.7