util.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 "util.h" 00046 #include "dns.h" 00047 00048 /* _printf_dbg 00049 * 00050 * Author: James Couzens <jcouzens@6o4.ca> 00051 * 00052 * Date: 12/25/03 00053 * Date: 02/18/04 (updated) 00054 * 00055 * Desc: 00056 * Tied to a compile time switch this can instantly and at little 00057 * to no real expense enable a discreet debugging with out hoards of 00058 * #ifdefs all over the place. 00059 * 00060 */ 00061 void _printf_dbg(u_int8_t level, const char *function, const char *format,...) 00062 { 00063 char _dbg_output[MAX_DEBUG_LEN]; 00064 va_list argptr; 00065 00066 #ifdef _SPF_DEBUG_LOGFILE 00067 FILE *fp = NULL; 00068 #endif 00069 00070 /*printf("Function (%s) calling us with format: (%s)\n", function, format);*/ 00071 00072 va_start(argptr, format); 00073 vsnprintf(_dbg_output, SIZEOF(_dbg_output), format, argptr); 00074 va_end(argptr); 00075 00076 if (f_bit_set(confg.level, level)) 00077 { 00078 #ifndef _SPF_DEBUG_LOGFILE 00079 printf("%s :: %s", function, _dbg_output); 00080 fflush(stdout); 00081 #else 00082 if ((fp = fopen(DEBUG_LOG_FILE, "a")) != NULL) 00083 { 00084 fprintf(fp, "%s", _dbg_output); 00085 fclose(fp); 00086 } 00087 #endif 00088 00089 } 00090 00091 return; 00092 } 00093 00094 00095 /* dummy_debug 00096 * 00097 * Author: James Couzens <jcouzens@6o4.ca> 00098 * 00099 * Date: 12/25/03 00100 * 00101 * Desc: 00102 * dummy function thats used instead of the _printf_dbg function 00103 * when compiling without debugging 00104 * 00105 */ 00106 void dummy_debug(const u_int8_t level, const char *function, 00107 const char *format,...) 00108 { 00109 return; 00110 } 00111 00112 00113 /* UTIL_printf 00114 * 00115 * Author: James Couzens <jcouzens@6o4.ca> 00116 * 00117 * Date: 12/25/03 00118 * 00119 * Desc: 00120 * Works on a static block of memory to operate like printf, 00121 * returning a pointer to the new string. Uses a static buffer 00122 * of 1K. 00123 * 00124 * THIS FUNCTION IS NOT THREAD SAFE !!!!! 00125 * 00126 */ 00127 char *UTIL_printf(char *format, ...) 00128 { 00129 va_list arg_ptr; 00130 static char s[1024]; 00131 00132 va_start (arg_ptr, format); 00133 vsnprintf (s, 1024, format, arg_ptr); 00134 va_end (arg_ptr); 00135 00136 xvprintf("Called with string: %s\n", s); 00137 00138 return(s); 00139 } 00140 00141 00142 /* UTIL_get_date 00143 * 00144 * Author: James Couzens <jcouzens@6o4.ca> 00145 * Date: Sun Jan 18 06:02:13 PST 2004 00146 * 00147 * Desc: 00148 * Opens up STDIN and reads up to 63 chars from it or until it reads 00149 * a newline. Data is written using the pointer passed from the calling 00150 * function. 00151 * 00152 */ 00153 char *UTIL_get_date(void) 00154 { 00155 struct tm *now; 00156 time_t curtime; 00157 static char my_time[22]; 00158 00159 curtime = time(NULL); 00160 now = localtime(&curtime); 00161 00162 strftime(my_time, sizeof(my_time), "%Y-%m-%d %H:%M:%S ", now); 00163 00164 return(my_time); 00165 } 00166 00167 00168 /* UTIL_log_result 00169 * 00170 * Author: James Couzens <jcouzens@6o4.ca> 00171 * 00172 * Date: 02/04/04 00173 * 00174 * Desc: 00175 * Tied to a compile time switch this can instantly and at little 00176 * to no real expense enable a discreet debugging with out hoards of 00177 * #ifdefs all over the place. 00178 * 00179 */ 00180 void UTIL_log_result(peer_info_t *peer_info) 00181 { 00182 FILE *fp = NULL; 00183 char buf[MAX_DEBUG_LEN]; 00184 char *date; 00185 00186 date = UTIL_get_date(); 00187 *(date + (strlen(date) - 1)) = '\0'; 00188 00189 if (peer_info->spf_ver == 0) 00190 { 00191 peer_info->spf_ver = SPF_VERSION; 00192 } 00193 00194 sprintf(buf, "[%s] result: %s :: %s [%s], ver: %i, depth: %i, error: (%s)\n", 00195 date, peer_info->spf_result[peer_info->RES].s, peer_info->from, 00196 peer_info->r_ip, spf_rlevel, peer_info->spf_ver, peer_info->error); 00197 00198 if ((fp = fopen(OUTPUT_LOG_FILE, "a")) != NULL) 00199 { 00200 fprintf(fp, "%s", buf); 00201 fclose(fp); 00202 } 00203 00204 return; 00205 } 00206 00207 00208 /* xstrndup 00209 * 00210 * Author: James Couzens <jcouzens@6o4.ca> 00211 * 00212 * Date: 12/25/03 00213 * 00214 * Desc: 00215 * n bytes are allocated and then filled with \0 chars. Char s 00216 * is copied over to the allocated memory writing n -1 bytes leaving the 00217 * new string NULL terminated. This new string is returned upon success 00218 * and NULL upon failure. 00219 * 00220 */ 00221 char *UTIL_strndup(const char *s, const size_t n) 00222 { 00223 char *ret_ptr = NULL; 00224 00225 if (s == NULL) 00226 { 00227 xeprintf("Passed string is NULL. Abort!.\n"); 00228 return(FALSE); 00229 } 00230 00231 ret_ptr = xmalloc(n); 00232 xvprintf("Allocated %u bytes of memory.\n", n); 00233 00234 memset(ret_ptr, '\0', n); 00235 memcpy(ret_ptr, s, (n - 1)); 00236 00237 xvprintf("Returning string: (%s)\n", 00238 ret_ptr); 00239 00240 return(ret_ptr); 00241 } 00242 00243 00244 /* xstrdup 00245 * 00246 * Author: Patrick Earl (http://patearl.net/) 00247 * Adapted from xstrndup() 00248 * 00249 * Date: 02/04/04 00250 * 00251 * Desc: 00252 * strlen(s)+1 bytes are allocated and s is copied into the 00253 * freshly allocated memory. If the allocation or copy fails, NULL 00254 * NULL will be returned. 00255 * 00256 */ 00257 char *UTIL_strdup(const char *s) 00258 { 00259 char *ret_ptr = NULL; 00260 00261 if (s == NULL) 00262 { 00263 xeprintf("Passed string is NULL. Abort!.\n"); 00264 return(FALSE); 00265 } 00266 00267 if ((ret_ptr = strdup(s)) == NULL) 00268 { 00269 xeprintf("Unable to allocate memory\n"); 00270 } 00271 00272 xvprintf("Returning string: (%s)\n", ret_ptr); 00273 00274 return(ret_ptr); 00275 } 00276 00277 00278 /* UTIL_malloc 00279 * 00280 * Author: Travis Anderson <travis@anthrax.ca> 00281 * Author: James Couzens <jcouzens@6o4.ca> 00282 * 00283 * Date: 02/17/04 00284 * 00285 * Desc: 00286 * Wrapper for malloc. Upon success, behaves as malloc does. 00287 * Wrapper functionality is to print an error message and exit upon failure. 00288 * 00289 */ 00290 void *UTIL_malloc(const int32_t n, const char *file, int32_t line, 00291 const char *func) 00292 { 00293 void *x = malloc(n); 00294 00295 if (x == NULL) 00296 { 00297 xvprintf("Unable to allocate %i bytes at %s:%i in %s\n", 00298 n, file, line, func); 00299 00300 exit(0); 00301 } 00302 00303 return(x); 00304 } 00305 00306 00307 /* UTIL_realloc 00308 * 00309 * Author: Travis Anderson <travis@anthrax.ca> 00310 * Author: James Couzens <jcouzens@6o4.ca> 00311 * 00312 * Date: 02/17/04 00313 * 00314 * Desc: 00315 * Wrapper for realloc. If 'p' is NULL, allocates memory via a call to 00316 * UTIL_malloc, otherwise if 'x' is assigned successfully, the behaviour is 00317 * identical to realloc. Wrapper functionality is to print an error message 00318 * and exit upon failure. 00319 * 00320 */ 00321 void *UTIL_realloc(void *p, const int32_t n, const char *file, const int32_t 00322 line, 00323 const char *func) 00324 { 00325 void *x = NULL; 00326 00327 if (p == NULL) 00328 { 00329 return(UTIL_malloc(n, file, line, func)); 00330 } 00331 00332 x = realloc(p, n); 00333 if (x == NULL) 00334 { 00335 xvprintf("Unable to reallocate %i bytes at %s:%i in %s; " \ 00336 "original address 0x%x\n", n, file, line, func, (uintptr_t)p); 00337 00338 exit(0); 00339 } 00340 00341 return(x); 00342 } 00343 00344 00345 /* UTIL_free 00346 * 00347 * Author: Travis Anderson <travis@anthrax.ca> 00348 * Author: James Couzens <jcouzens@6o4.ca> 00349 * 00350 * Date: 02/17/04 00351 * 00352 * Desc: 00353 * Wrapper for free. Upon success, behaves as free does. 00354 * Wrapper functionality is to print an error message and exit upon 00355 * failure. 00356 * 00357 */ 00358 void UTIL_free(void *p, const char *file, const int32_t line, const char *func) 00359 { 00360 if (p == NULL) 00361 { 00362 xvprintf("Unable to free() on NULL pointer at %s:%i in %s; " \ 00363 "address 0x%x.\n", file, line, func, (uintptr_t)p); 00364 return; 00365 } 00366 00367 xvprintf("Free address 0x%x by %s on line %i (%s)\n", 00368 (uintptr_t)p, func, line, file); 00369 00370 free(p); 00371 return; 00372 } 00373 00374 00375 /* UTIL_index 00376 * 00377 * Author: James Couzens <jcouzens@6o4.ca> 00378 * 00379 * Date: 12/19/03 00380 * 00381 * Desc: 00382 * s is walked until c is found, at which time i is returned 00383 * which is the number of bytes from the left it walked until c was 00384 * found (not including c its self); Returns 0 upon failure. 00385 * 00386 */ 00387 int16_t UTIL_index(const char *s, const char c) 00388 { 00389 int16_t i; /* utility */ 00390 00391 if (s == NULL) 00392 { 00393 xeprintf("Passed a NULL string. Abort!\n"); 00394 return(0); 00395 } 00396 00397 i = 0; 00398 while (*s) 00399 { 00400 if (*s == c) 00401 { 00402 xvprintf("Found search char: (%c); Returning: (%i)\n", *s, i); 00403 00404 return(i); 00405 } 00406 i++; 00407 s++; 00408 } 00409 return(0); 00410 } 00411 00412 00413 /* UTIL_split_str 00414 * 00415 * Author: James Couzens <jcouzens@6o4.ca> 00416 * 00417 * Date: 01/21/04 00418 * 00419 * Desc: 00420 * s is walked through to find 'delim' until it finds 'delim' 00421 * num times. Upon final match it returns the remainder of the string 00422 * in a newly allocated buffer. Upon failure returns NULL. 00423 * 00424 */ 00425 char *UTIL_split_str(const char *s, const char c, const u_int8_t num) 00426 { 00427 u_int8_t i = 0; 00428 00429 char *cp; 00430 char *p; 00431 char *ret; 00432 00433 if (s == NULL) 00434 { 00435 xeprintf("Passed a NULL string. Abort!\n"); 00436 return(NULL); 00437 } 00438 00439 p = cp = xstrndup(s, (strlen(s) + 1)); 00440 00441 while(*p) 00442 { 00443 if (*p == c) 00444 { 00445 i++; 00446 if (i == num) 00447 { 00448 p++; 00449 ret = xstrndup(p, (strlen(p) + 1)); 00450 xfree(cp); 00451 xvprintf("returning: %s\n", ret); 00452 return(ret); 00453 } 00454 } 00455 p++; 00456 } 00457 00458 return(NULL); 00459 } 00460 00461 00462 /* UTIL_split_strr 00463 * 00464 * Author: James Couzens <jcouzens@6o4.ca> 00465 * 00466 * Date: 01/30/04 00467 * 00468 * Desc: 00469 * s is walked to the end of its self, and then is walked back 00470 * towards the beginning of the string until it has found 'c' the 00471 * delimiter, 'num' times. Upon success memory is allocated and the 00472 * remainder of s is returned. Upon failure NULL is returned. 00473 * 00474 */ 00475 char *UTIL_split_strr(const char *s, const char c, const u_int8_t num) 00476 { 00477 u_int8_t i; /* number of times delim (c) is found */ 00478 00479 char *beg; /* ptr to beginning of s */ 00480 char *cp; /* copy of s */ 00481 char *p; /* working pointer */ 00482 char *ret; /* return buffer */ 00483 00484 if (s == NULL) 00485 { 00486 xeprintf("Passed a NULL string. Abort!\n"); 00487 return(NULL); 00488 } 00489 00490 xvprintf("Called with (%s)\n", s); 00491 00492 p = cp = xstrndup(s, (strlen(s) + 1)); 00493 beg = (char *)&s; 00494 00495 while (*p) 00496 { 00497 p++; 00498 } 00499 00500 i = 0; 00501 while(p != beg) 00502 { 00503 if (*p == c) 00504 { 00505 i++; 00506 if (i == num) 00507 { 00508 if (*p == '.') 00509 { 00510 p++; /* don't want that period */ 00511 } 00512 ret = xstrndup(p, (strlen(p) + 1)); 00513 xfree(cp); 00514 xvprintf("returning: %s\n", ret); 00515 return(ret); 00516 } 00517 } 00518 p--; 00519 } 00520 00521 xfree(cp); 00522 return(NULL); 00523 } 00524 00525 00526 /* UTIL_count_delim 00527 * 00528 * Author: James Couzens <jcouzens@6o4.ca> 00529 * 00530 * Date: 01/21/04 00531 * 00532 * Desc: 00533 * s is walked through and each time 'delim' is found a 00534 * counter is incremented and once complete, that integer is 00535 * returned to the calling function. Specifically for the purposees 00536 * of this project its limited by its type to 255. Returns any number 00537 * greater than 0 and less than or equal to 255. Upon failure returns 00538 * 0. 00539 * 00540 */ 00541 u_int8_t UTIL_count_delim(const char *s, const char c) 00542 { 00543 u_int8_t i = 0; 00544 00545 if (s == NULL) 00546 { 00547 xeprintf("Passed a NULL string. Abort!\n"); 00548 return(0); 00549 } 00550 00551 while (*s) 00552 { 00553 if (*s == c) 00554 { 00555 i++; 00556 } 00557 s++; 00558 } 00559 00560 xvprintf("returning: %i\n", i); 00561 return(i); 00562 } 00563 00564 00565 /* UTIL_guess_whats_in_the_box ?! 00566 * 00567 * Author: James Couzens <jcouzens@6o4.ca> 00568 * 00569 * Date: 01/21/04 00570 * 00571 * Desc: 00572 * s is walked through and each time 'delim' is found a 00573 * counter is incremented, all the while through each iteration the 00574 * overall byte count is decremented. When the number of delimiter 00575 * SPF_MATCHes found is identical to 'num' the number of bytes are 00576 * decremented once more (to remove the delimiter) and then returned. 00577 * Upon failure 0 is returned. 00578 * 00579 */ 00580 size_t UTIL_guess_whats_in_the_box(char *s, const char c, const u_int16_t num) 00581 { 00582 u_int8_t i = 0; 00583 size_t bytes = 0; 00584 00585 if (s == NULL) 00586 { 00587 xeprintf("Passed a NULL string. Abort!\n"); 00588 00589 return(0); 00590 } 00591 00592 bytes = strlen(s); 00593 00594 while (*s) 00595 { 00596 if (*s == c) 00597 { 00598 i++; 00599 } 00600 00601 if (i == num) 00602 { 00603 bytes--; 00604 s++; 00605 00606 xvprintf("return (%i bytes) (%s)\n", bytes, s); 00607 00608 return(bytes); 00609 } 00610 else 00611 { 00612 bytes--; 00613 s++; 00614 } 00615 } 00616 00617 xvprintf("[return (%i bytes) (%s)\n", bytes, s); 00618 00619 return(bytes); 00620 } 00621 00622 00623 /* UTIL_is_spf_delim 00624 * 00625 * Author: James Couzens <jcouzens@6o4.ca> 00626 * 00627 * Date: 01/21/04 00628 * 00629 * Desc: 00630 * c is compared against all the valid spf delimiters and 00631 * in the case of a SPF_PASS, the function returns true, otherwise it will 00632 * return false. 00633 * 00634 */ 00635 SPF_BOOL UTIL_is_spf_delim(const char c) 00636 { 00637 xvprintf("Called with char (%c)\n", c); 00638 00639 if (c == '.' || c == '-' || c == '+' || c == ',' 00640 || c == '|' || c == '_') 00641 { 00642 return(TRUE); 00643 } 00644 00645 return(FALSE); 00646 } 00647 00648 00649 /* UTIL_is_spf_result 00650 * 00651 * Author: James Couzens <jcouzens@6o4.ca> 00652 * 00653 * Date: 01/27/04 00654 * 00655 * Desc: 00656 * c is compared against all the valid spf prefixes and 00657 * in the case of a SPF_PASS, the function returns true, otherwise it will 00658 * return false. 00659 * 00660 */ 00661 SPF_BOOL UTIL_is_spf_result(const char c) 00662 { 00663 xvprintf("Called with char (%c)\n", c); 00664 00665 if (c == '+' || c == '-' || c == '~' || c == '?') 00666 { 00667 return(TRUE); 00668 } 00669 00670 return(FALSE); 00671 } 00672 00673 00674 /* UTIL_is_macro 00675 * 00676 * Author: James Couzens <jcouzens@6o4.ca> 00677 * 00678 * Date: 01/30/04 00679 * 00680 * Desc: 00681 * s is walked through in search of a macro which consist of 00682 * %{?}, ? being an SPF_UNKNOWN number of chars in between. An instance of 00683 * a macro is searched for. Upon success TRUE is returned. Upon failure 00684 * to find a macro, FALSE is returned. 00685 * 00686 */ 00687 SPF_BOOL UTIL_is_macro(const char *s) 00688 { 00689 if (s == NULL) 00690 { 00691 xeprintf("Passed a NULL string. Abort!\n"); 00692 00693 return(FALSE); 00694 } 00695 00696 xvprintf("Called with char (%s)\n", s); 00697 00698 while (*s++) 00699 { 00700 if (*s == '%' && *(s + 1) == '{') 00701 { 00702 if (strstr(s, "}")) 00703 { 00704 return(TRUE); 00705 } 00706 } 00707 } 00708 00709 return(FALSE); 00710 } 00711 00712 00713 /* UTIL_mx_cmp 00714 * 00715 * Author: James Couzens <jcouzens@6o4.ca> 00716 * 00717 * Date: 01/02/04 00718 * 00719 * Desc: 00720 * Using the domain name found in the passed peer_info 00721 * structure, the associated T_MX records are looked up and then their 00722 * respective hostnames resolved (if they happen to be IP addresses the 00723 * resolver library takes care of this. <3). Each IP is compared 00724 * against the remote peer's IP (from peer_info). Upon success returns 00725 * TRUE, upon failure returns FALSE. 00726 * 00727 */ 00728 SPF_BOOL UTIL_mx_cmp(peer_info_t *peer_info, const char *s, const int8_t cidr) 00729 { 00730 SPF_BOOL MX_SPF_MATCH = FALSE; /* true / false */ 00731 00732 char *rr_data = NULL; /* record */ 00733 char *token; /* token for splitting records */ 00734 char *token_ptr; 00735 char *peer_ip; /* remote host converted to string */ 00736 00737 token_ptr = rr_data; 00738 00739 if ((rr_data = DNS_query(peer_info, s, T_MX, NULL)) == NULL) 00740 { 00741 xeprintf("SPF_ERROR parsing DNS Query\n"); 00742 return(FALSE); 00743 } 00744 00745 xvprintf("rr_data is: (%s)\n", rr_data); 00746 00747 peer_ip = xstrndup(inet_ntoa(peer_info->addr), 16); 00748 token = strtok_r(rr_data, " ", &token_ptr); 00749 00750 while (token != NULL) 00751 { 00752 xvprintf("TOKEN: (%s)\n", token); 00753 00754 if (UTIL_validate_hostname(peer_info, token, cidr) == TRUE) 00755 { 00756 xvprintf("%s validated via (%s)\n", peer_info->from, token); 00757 00758 MX_SPF_MATCH = TRUE; 00759 UTIL_assoc_prefix(peer_info, SPF_PASS, NULL); 00760 token = NULL; 00761 } 00762 else 00763 { 00764 token = strtok_r(NULL, " ", &token_ptr); 00765 } 00766 } 00767 00768 xfree(peer_ip); 00769 xfree(rr_data); 00770 00771 return(MX_SPF_MATCH); 00772 } 00773 00774 00775 /* UTIL_a_cmp 00776 * 00777 * Author: James Couzens <jcouzens@6o4.ca> 00778 * 00779 * Date: 01/02/04 00780 * 00781 * Desc: 00782 * Calls gethostbyname to grab all records associated with a the 00783 * hostname contained within s. On success returns TRUE, on SPF_ERROR 00784 * returns FALSE. 00785 * 00786 * Note: 00787 * We need to define and set a limit on the number of recursive 00788 * lookups. I recall seeing this in the RFC, we should discuss this. 00789 * 00790 */ 00791 SPF_BOOL UTIL_a_cmp(peer_info_t *peer_info, const char *s, const int8_t cidr) 00792 { 00793 int16_t pos; 00794 00795 char *rr_data = NULL; 00796 char *token_ptr; 00797 00798 char *cp; 00799 char *copy; 00800 char **a; 00801 00802 size_t s_len; 00803 00804 struct hostent *host; 00805 00806 policy_addr_t *policy_addr; 00807 00808 if (s == NULL) 00809 { 00810 xeprintf("Passed string is NULL. Abort!.\n"); 00811 00812 return(FALSE); 00813 } 00814 00815 xvprintf("Called with (%s) and cidr: %i\n", s, cidr); 00816 00817 token_ptr = rr_data; 00818 s_len = strlen(s); 00819 00820 /* we're dealing with a:some.hostname/cidr */ 00821 if (s_len > 1 && *(s + 1) == ':') 00822 { 00823 if (cidr != 32) 00824 { 00825 /* We don't want a netmask, so lets remove it */ 00826 cp[s_len - 3] = '\0'; 00827 } 00828 00829 cp = copy = xstrndup(s, (s_len + 1)); 00830 00831 if ((pos = UTIL_index(cp, ':')) <= 0) 00832 { 00833 xeprintf("ERROR parsing passed mechanism token\n"); 00834 00835 xfree(copy); 00836 return(FALSE); 00837 } 00838 00839 /* move passed the mechanism text */ 00840 cp += (pos + 1); 00841 } 00842 else 00843 { 00844 cp = copy = xstrndup(peer_info->cur_dom, 00845 (strlen(peer_info->cur_dom) + 1)); 00846 } 00847 00848 policy_addr = xmalloc(sizeof(policy_addr_t)); 00849 00850 if ((host = gethostbyname(cp)) != NULL) 00851 { 00852 for (a = host->h_addr_list; *a; a++) 00853 { 00854 memcpy(&policy_addr->addr.s_addr, *a, sizeof(struct in_addr)); 00855 00856 xvprintf("Checking IP: %lu\n",policy_addr->addr.s_addr); 00857 00858 /* cidr is assumed checked by the calling function! */ 00859 policy_addr->cidr = cidr; 00860 00861 if (UTIL_cidr_cmp(peer_info, policy_addr, &peer_info->addr) == TRUE) 00862 { 00863 *a = NULL; 00864 xfree(policy_addr); 00865 xfree(copy); 00866 UTIL_assoc_prefix(peer_info, SPF_PASS, NULL); 00867 return(TRUE); 00868 } 00869 } 00870 00871 for (a = host->h_aliases; *a; a++) 00872 { 00873 memcpy(&policy_addr->addr.s_addr, *a, sizeof(struct in_addr)); 00874 00875 xvprintf("Checking ALIAS: %lu\n", policy_addr->addr.s_addr); 00876 00877 /* cidr is assumed checked by the calling function! */ 00878 policy_addr->cidr = cidr; 00879 00880 if (UTIL_cidr_cmp(peer_info, policy_addr, &peer_info->addr) == TRUE) 00881 { 00882 *a = NULL; 00883 xfree(policy_addr); 00884 xfree(copy); 00885 UTIL_assoc_prefix(peer_info, SPF_PASS, NULL); 00886 return(TRUE); 00887 } 00888 } 00889 } 00890 00891 xfree(policy_addr); 00892 xfree(copy); 00893 00894 return(FALSE); 00895 } 00896 00897 00898 /* UTIL_ptr_cmp 00899 * 00900 * Author: James Couzens <jcouzens@6o4.ca> 00901 * 00902 * Date: 01/08/04 00903 * 00904 * Desc: 00905 * gethostbyaddr is broken in linux. ?->h_aliases is not NULL, 00906 * however, it doesn't contain any valid pointers either. It grabs the 00907 * first (and of course this is random) hostname it gets and thats all. 00908 * As tested in FreeBSD however this call works. At any rate, I've 00909 * written a function to deal with this called DNS_ptr_answer. From here 00910 * that function is called which handles the reverse lookups and then 00911 * attempts to "validate" each returned hostname by in turn looking it up 00912 * to confirm if the ip address SPF_MATCHes. Returns TRUE on succes, and FALSE 00913 * on failure. 00914 * 00915 * When passed TRUE copies into peer_info->ptr_mhost, when FALSE copies 00916 * into peer_info->r_vhname 00917 * 00918 * Note: 00919 * We need to define and set a limit on the number of recursive 00920 * lookups. I recall seeing this in the RFC, we should discuss this. 00921 * 00922 */ 00923 SPF_BOOL UTIL_ptr_cmp(peer_info_t *peer_info, const char *s) 00924 { 00925 char *ptr_addr; /* reversed address into PTR format */ 00926 char *tmp_ptr; /* utility pointer */ 00927 00928 if (s == NULL) 00929 { 00930 xeprintf("Passed string is NULL. Abort!\n"); 00931 return(FALSE); 00932 } 00933 00934 xvprintf("Called with (%s)\n", s); 00935 00936 /* reverse of rpeer */ 00937 ptr_addr = UTIL_rev_addr(peer_info->r_ip); 00938 00939 xvprintf("address: %s\n", ptr_addr); 00940 00941 if ((strstr(s, ":")) != NULL) 00942 { 00943 tmp_ptr = xstrndup(s, (strlen(s) + 1)); 00944 } 00945 else 00946 { 00947 tmp_ptr = xstrndup(peer_info->cur_dom, 00948 (strlen(peer_info->cur_dom) + 1)); 00949 } 00950 00951 if (DNS_query(peer_info, ptr_addr, T_PTR, tmp_ptr) != (char *)TRUE) 00952 { 00953 xvprintf("PTR lookup failed: (%s) (%s)\n", peer_info->rs, peer_info->error); 00954 00955 xfree(ptr_addr); 00956 xfree(tmp_ptr); 00957 return(FALSE); 00958 } 00959 00960 xvprintf("PTR lookup succeeded: (%s):(%s)\n", peer_info->rs, 00961 peer_info->error); 00962 00963 xfree(ptr_addr); 00964 xfree(tmp_ptr); 00965 return(TRUE); 00966 } 00967 00968 00969 /* UTIL_get_policy_mech 00970 * 00971 * Author: James Couzens <jcouzens@6o4.ca> 00972 * 00973 * Date: 12/19/03 00974 * 00975 * Desc: 00976 * Examins s and attempts to determine which SPF_MECHANISM 00977 * enumeration the string SPF_MATCHes based on its conent. 00978 * 00979 */ 00980 SPF_MECHANISM UTIL_get_policy_mech(const char *s) 00981 { 00982 xvprintf("Called with: (%s)\n", s); 00983 00984 if (s == NULL || !s) 00985 { 00986 xeprintf("Passed a NULL string. Abort!\n"); 00987 return(NO_POLICY); 00988 } 00989 00990 if (strncmp(s, "v=", 2) == 0) 00991 { 00992 xvprintf("Returning %i (VERSION)\n", VERSION); 00993 return(VERSION); 00994 } 00995 else if (strncmp(s, "ip4:", 4) == 0 ) 00996 { 00997 xvprintf("Returning %i (IP4)\n", IP4); 00998 return(IP4); 00999 } 01000 else if (strncmp(s, "ip6:", 4) == 0) 01001 { 01002 xvprintf("Returning %i (IP6)\n", IP6); 01003 return(IP6); 01004 } 01005 else if (strncmp(s, "all", 3) == 0) 01006 { 01007 xvprintf("Returning %i (ALL)\n", ALL); 01008 return(ALL); 01009 } 01010 else if (strncmp(s, "mx", 2) == 0) 01011 { 01012 xvprintf("Returning %i (MX)\n", MX); 01013 return(MX); 01014 } 01015 else if (strncmp(s, "a:", 2) == 0 || (*s == 'a' && *(s + 1) == '/') 01016 || ((*s == 'a') && !*(s + 1))) 01017 { 01018 xvprintf("Returning %i (A)\n", A); 01019 return(A); 01020 } 01021 else if (strncmp(s, "ptr", 3) == 0) 01022 { 01023 xvprintf("Returning %i (PTR)\n", PTR); 01024 return(PTR); 01025 } 01026 else if (strncmp(s, "include", 7) == 0) 01027 { 01028 xvprintf("Returning %i (INCLUDE)\n", INCLUDE); 01029 return(INCLUDE); 01030 } 01031 else if (strncmp(s, "exists", 6) == 0) 01032 { 01033 xvprintf("Returning %i (EXISTS)\n", EXISTS); 01034 return(EXISTS); 01035 } 01036 else if (strncmp(s, "redirect", 8) == 0) 01037 { 01038 xvprintf("Returning %i (REDIRECT)\n", REDIRECT); 01039 return(REDIRECT); 01040 } 01041 else if (strncmp(s, "exp", 3) == 0) 01042 { 01043 xvprintf("Returning %i (EXPLAIN)\n", EXPLAIN); 01044 return(EXPLAIN); 01045 } 01046 else if (strncmp(s, "default", 7) == 0) 01047 { 01048 xvprintf("Returning %i (DEFAULT)\n", DEFAULT); 01049 return(DEFAULT); 01050 } 01051 else if (strstr(s, ":")) 01052 { 01053 xvprintf("Returning %i (UNMECH)\n", UNMECH); 01054 return(UNMECH); 01055 } 01056 01057 return(NO_POLICY); 01058 } 01059 01060 01061 /* UTIL_assoc_prefix 01062 * 01063 * Author: James Couzens <jcouzens@6o4.ca> 01064 * 01065 * Date: 01/28/04 01066 * 01067 * Desc: 01068 * Examins s and attempts to determine which SPF_MECHANISM_PREFIX 01069 * enumeration the string SPF_MATCHes based on the its contents (which is a 01070 * single char. Upon a SPF_PASS it stores the appropriate value inside of 01071 * the passed peer_info structure. TRUE upon success, FALSE upon failure. 01072 * Also upon failure SPF_ERROR (SPF_RESULT_TYPE) is stored in peer_info. 01073 * 01074 * 01075 */ 01076 SPF_BOOL UTIL_assoc_prefix(peer_info_t *peer_info, SPF_RESULT p, const char *s) 01077 { 01078 int16_t pos; /* position in s string */ 01079 01080 if (s != NULL) 01081 { 01082 xvprintf("(QID: %u) :: Entering function (%i) (%s)\n", spf_rlevel, p, s); 01083 01084 /* support for old school deprecated mechanism "default" */ 01085 if (strncmp(s, "default", 7) == 0 && (pos = UTIL_index(s, '=')) > 0) 01086 { 01087 s += (pos + 1); /* move past default= */ 01088 if (strncmp(s, "deny", 4) == 0) 01089 { 01090 xvprintf("(QID: %u) :: Stored SPF_H_FAIL (%i) (%i)\n", 01091 spf_rlevel, p, SPF_H_FAIL); 01092 01093 peer_info->RES = SPF_H_FAIL; 01094 peer_info->rs = peer_info->spf_result[SPF_H_FAIL].s; 01095 01096 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01097 "(%s)\n", peer_info->rs, peer_info->last_m); 01098 01099 return(TRUE); 01100 } 01101 else if (strncmp(s, "pass", 4) == 0) 01102 { 01103 xvprintf("(QID: %u) :: Stored SPF_PASS (%i) (%i)\n", 01104 spf_rlevel, p, SPF_PASS); 01105 01106 peer_info->RES = SPF_PASS; 01107 peer_info->rs = peer_info->spf_result[SPF_PASS].s; 01108 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01109 "(%s)\n", peer_info->rs, peer_info->last_m); 01110 return(TRUE); 01111 } 01112 else if (strncmp(s, "softdeny", 8) == 0) 01113 { 01114 xvprintf("(QID: %u) :: Stored SPF_S_FAIL (%i) (%i)\n", 01115 spf_rlevel, p, SPF_S_FAIL); 01116 01117 peer_info->RES = SPF_S_FAIL; 01118 peer_info->rs = peer_info->spf_result[SPF_S_FAIL].s; 01119 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01120 "(%s)\n", peer_info->rs, peer_info->last_m); 01121 return(TRUE); 01122 } 01123 else if (strncmp(s, "unknown", 7) == 0) 01124 { 01125 xvprintf("(QID: %u) :: Stored SPF_NEUTRAL (%i) (%i)\n", 01126 spf_rlevel, p, SPF_NEUTRAL); 01127 01128 peer_info->RES = SPF_NEUTRAL; 01129 peer_info->rs = peer_info->spf_result[SPF_NEUTRAL].s; 01130 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01131 "(%s)\n", peer_info->rs, peer_info->last_m); 01132 return(TRUE); 01133 } 01134 else if (strncmp(s, "include", 7) == 0) 01135 { 01136 xvprintf("(QID: %u) :: Stored SPF_UNKNOWN (%i) (%i)\n", 01137 spf_rlevel, p, SPF_UNKNOWN); 01138 01139 peer_info->RES = SPF_UNKNOWN; 01140 peer_info->rs = peer_info->spf_result[SPF_UNKNOWN].s; 01141 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01142 "(%s)\n", peer_info->rs, peer_info->last_m); 01143 return(TRUE); 01144 } 01145 else 01146 { 01147 xvprintf("(QID: %u) :: Stored SPF_ERROR (%i) (%i)\n", 01148 spf_rlevel, p, SPF_ERROR); 01149 01150 peer_info->RES = SPF_UNKNOWN; 01151 peer_info->rs = peer_info->spf_result[SPF_UNKNOWN].s; 01152 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01153 "(%s)\n", peer_info->rs, peer_info->last_m); 01154 return(FALSE); 01155 } 01156 } 01157 } 01158 01159 switch (p) 01160 { 01161 case SPF_PASS: 01162 xvprintf("(QID: %u) :: Stored SPF_PASS (%i) (%i)\n", 01163 spf_rlevel, p, SPF_PASS); 01164 01165 peer_info->RES = SPF_PASS; 01166 peer_info->rs = peer_info->spf_result[SPF_PASS].s; 01167 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01168 "(%s)\n", peer_info->rs, peer_info->last_m); 01169 return(TRUE); 01170 case SPF_NONE: 01171 xvprintf("(QID: %u) :: Stored SPF_NONE (%i) (%i)\n", 01172 spf_rlevel, p, SPF_NONE); 01173 01174 peer_info->RES = SPF_NONE; 01175 peer_info->rs = peer_info->spf_result[SPF_NONE].s; 01176 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01177 "(%s)\n", peer_info->rs, peer_info->last_m); 01178 return(TRUE); 01179 case SPF_S_FAIL: 01180 xvprintf("(QID: %u) :: Stored SPF_S_FAIL (%i) (%i)\n", 01181 spf_rlevel, p, SPF_S_FAIL); 01182 01183 peer_info->RES = SPF_S_FAIL; 01184 peer_info->rs = peer_info->spf_result[SPF_S_FAIL].s; 01185 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01186 "(%s)\n", peer_info->rs, peer_info->last_m); 01187 return(TRUE); 01188 case SPF_H_FAIL: 01189 xvprintf("(QID: %u) :: Stored SPF_H_FAIL (%i) (%i)\n", 01190 spf_rlevel, p, SPF_H_FAIL); 01191 01192 peer_info->RES = SPF_H_FAIL; 01193 peer_info->rs = peer_info->spf_result[SPF_H_FAIL].s; 01194 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01195 "(%s)\n", peer_info->rs, peer_info->last_m); 01196 return(TRUE); 01197 case SPF_NEUTRAL: 01198 xvprintf("(QID: %u) :: Stored SPF_NEUTRAL (%i) (%i)\n", 01199 spf_rlevel, p, SPF_NEUTRAL); 01200 01201 peer_info->RES = SPF_NEUTRAL; 01202 peer_info->rs = peer_info->spf_result[SPF_NEUTRAL].s; 01203 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01204 "(%s)\n", peer_info->rs, peer_info->last_m); 01205 return(TRUE); 01206 case SPF_UNKNOWN: 01207 xvprintf("(QID: %u) :: Stored SPF_UNKNOWN (%i) (%i)\n", 01208 spf_rlevel, p, SPF_UNKNOWN); 01209 01210 peer_info->RES = SPF_UNKNOWN; 01211 peer_info->rs = peer_info->spf_result[SPF_UNKNOWN].s; 01212 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01213 "(%s)\n", peer_info->rs, peer_info->last_m); 01214 return(TRUE); 01215 case SPF_ERROR: 01216 xvprintf("(QID: %u) :: Stored SPF_ERROR (%i) (%i)\n", 01217 spf_rlevel, p, SPF_ERROR); 01218 01219 peer_info->RES = SPF_ERROR; 01220 peer_info->rs = peer_info->spf_result[SPF_ERROR].s; 01221 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01222 "(%s)\n", peer_info->rs, peer_info->last_m); 01223 return(TRUE); 01224 case SPF_UNMECH: 01225 xvprintf("(QID: %u) :: Stored SPF_UNMECH (%i) (%i)\n", 01226 spf_rlevel, p, SPF_UNMECH); 01227 01228 peer_info->RES = SPF_UNMECH; 01229 peer_info->rs = peer_info->spf_result[SPF_UNMECH].s; 01230 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01231 "(%s)\n", peer_info->rs, peer_info->last_m); 01232 return(TRUE); 01233 01234 default: 01235 xvprintf("(QID: %u) :: Stored SPF_PASS (%i) (%i)\n", 01236 spf_rlevel, p, SPF_PASS); 01237 01238 peer_info->RES = SPF_PASS; 01239 peer_info->rs = peer_info->spf_result[SPF_PASS].s; 01240 snprintf(peer_info->error, MAX_ERROR, "policy result: (%s) from rule " \ 01241 "(%s)\n", peer_info->rs, peer_info->last_m); 01242 return(TRUE); 01243 } 01244 01245 return(FALSE); 01246 } 01247 01248 01249 /* UTIL_get_mech_prefix 01250 * 01251 * Author: James Couzens <jcouzens@6o4.ca> 01252 * 01253 * Date: 12/31/03 01254 * 01255 * Desc: 01256 * Examins s and attempts to determine which SPF_RESULT_P 01257 * enumeration the string SPF_MATCHes based on the its contents (which is a 01258 * single char. Returns SPF_PASS if a valid prefix is not specified. 01259 * Valid prefixes are: + (permit), - (deny), ~ (softfail) and ? (SPF_NEUTRAL). 01260 * 01261 */ 01262 SPF_RESULT UTIL_get_mech_prefix(peer_info_t *peer_info, const char *s) 01263 { 01264 int16_t pos; 01265 01266 if (s == NULL) 01267 { 01268 xeprintf("Passed a NULL string. Abort!\n"); 01269 return(SPF_ERROR); 01270 } 01271 01272 snprintf(peer_info->last_m, (strlen(s) +1), "%s", s); 01273 01274 switch (*s) 01275 { 01276 case '+': 01277 xvprintf("(QID: %u) :: Returning SPF_PASS (%s) %i\n", 01278 spf_rlevel, s, SPF_PASS); 01279 peer_info->RES_P = SPF_PASS; 01280 return(SPF_PASS); 01281 case '-': 01282 xvprintf("(QID: %u) :: Returning SPF_H_FAIL (%s) %i\n", 01283 spf_rlevel, s, SPF_H_FAIL); 01284 peer_info->RES_P = SPF_H_FAIL; 01285 return(SPF_H_FAIL); 01286 case '?': 01287 xvprintf("(QID: %u) :: Returning SPF_NEUTRAL (%s) %i\n", 01288 spf_rlevel, s, SPF_NEUTRAL); 01289 peer_info->RES_P = SPF_NEUTRAL; 01290 return(SPF_NEUTRAL); 01291 case '~': 01292 xvprintf("(QID: %u) :: Returning SPF_S_FAIL (%s) %i\n", 01293 spf_rlevel, s, SPF_S_FAIL); 01294 peer_info->RES_P = SPF_S_FAIL; 01295 return(SPF_S_FAIL); 01296 default: 01297 if (peer_info->ALL == TRUE) 01298 { 01299 xvprintf("(QID: %u) :: Returning (def) SPF_NEUTRAL (%s) %i\n", 01300 spf_rlevel, s, SPF_NEUTRAL); 01301 peer_info->RES_P = SPF_NEUTRAL; 01302 } 01303 else 01304 { 01305 xvprintf("(QID: %u) :: Returning (def) SPF_PASS (%s) %i\n", 01306 spf_rlevel, s, SPF_PASS); 01307 peer_info->RES_P = SPF_PASS; 01308 } 01309 return(peer_info->RES_P); 01310 } 01311 01312 /* support for old school deprecated mechanism "default" */ 01313 if ((pos = UTIL_index(s, '=')) > 0) 01314 { 01315 s += (pos + 1); /* move past default= */ 01316 01317 if (strncmp(s, "deny", 4) == 0) 01318 { 01319 peer_info->RES_P = SPF_H_FAIL; 01320 return(SPF_H_FAIL); 01321 } 01322 else if (strncmp(s, "pass", 4) == 0) 01323 { 01324 peer_info->RES_P = SPF_PASS; 01325 return(SPF_PASS); 01326 } 01327 else if (strncmp(s, "softdeny", 8) == 0) 01328 { 01329 peer_info->RES_P = SPF_S_FAIL; 01330 return(SPF_S_FAIL); 01331 } 01332 else if (strncmp(s, "unknown", 7) == 0) 01333 { 01334 peer_info->RES_P = SPF_NEUTRAL; 01335 return(SPF_NEUTRAL); 01336 } 01337 else 01338 { 01339 return(SPF_NEUTRAL); 01340 } 01341 } 01342 01343 xvprintf("Undetermined, returning " 01344 "SPF_PASS (%s)\n", s); 01345 01346 return(SPF_ERROR); 01347 } 01348 01349 01350 /* UTIL_expand_ip 01351 * 01352 * Author: James Couzens <jcouzens@6o4.ca> 01353 * 01354 * Date: 12/26/03 01355 * 01356 * Desc: 01357 * Expands an ip4 policy mechanism string into a policy_addr_t 01358 * structure which it allocates memory for and then returns. The RFC 01359 * specifies that if a cidr block is not specified then /32 isused. 01360 * 01361 * On success returns a pointer to a policy_addr_t structure, on 01362 * SPF_ERROR returns NULL. 01363 * 01364 */ 01365 policy_addr_t *UTIL_expand_ip(const char *s) 01366 { 01367 size_t len; /* length of string passed */ 01368 const char *token_ptr; /* our position in the token */ 01369 size_t pos; /* position of break points in string */ 01370 01371 char *ip; /* temporary storage for ip address */ 01372 int8_t cidr = 0; /* temporary storage for netmask */ 01373 01374 policy_addr_t *policy_addr; /* ip/mask return structure */ 01375 01376 if (s == NULL) 01377 { 01378 xeprintf("Passed a NULL string. Abort!\n"); 01379 return(NULL); 01380 } 01381 01382 len = strlen(s); 01383 token_ptr = s; 01384 01385 xvprintf("Called with string: (%s)\n", token_ptr); 01386 01387 if ((pos = UTIL_index(token_ptr, ':')) == 0) 01388 { 01389 xvprintf("SPF_ERROR: Unable to get position on token (%s)\n", 01390 token_ptr); 01391 01392 return(NULL); 01393 } 01394 01395 /* jump past the ip4: portion */ 01396 token_ptr += pos + 1; 01397 01398 policy_addr = xmalloc(sizeof(policy_addr_t)); 01399 01400 /* jump past the ip4: portion (to get length of ip) */ 01401 if ((pos = UTIL_index(token_ptr, '/')) == 0) 01402 { 01403 xvprintf("Unable to get position on token (%s), assuming /32 cidr " 01404 "block\n", token_ptr); 01405 01406 pos = strlen(token_ptr); 01407 cidr = 32; 01408 } 01409 01410 /* allocate space and dump the ip address there */ 01411 ip = xstrndup(token_ptr, (pos + 1)); 01412 01413 /* copy it over to the policy_addr structure */ 01414 if ((inet_pton(AF_INET, ip, &policy_addr->addr)) == 0) 01415 { 01416 xvprintf("SPF_ERROR: inet_pton unable to convert ip to binary " 01417 "(%s)\n", ip); 01418 01419 xfree(ip); 01420 return(NULL); 01421 } 01422 01423 if (cidr != 32) 01424 { 01425 token_ptr += (pos + 1); /* skip over the forward slash */ 01426 cidr = atoi(token_ptr); /* convert the string to an integer */ 01427 } 01428 01429 xfree(ip); /* don't need this memory anymore */ 01430 01431 if (cidr < 0 || cidr > 32) 01432 { 01433 xvprintf("SPF_ERROR: cidr violation (%u)\n", cidr); 01434 return(NULL); 01435 } 01436 01437 policy_addr->cidr = cidr; /* copy it over to the policy_addr structure */ 01438 01439 xvprintf("CIDR: (%i) IP: (%s)\n", policy_addr->cidr, 01440 inet_ntoa(policy_addr->addr)); 01441 01442 return(policy_addr); 01443 } 01444 01445 01446 /* UTIL_addnode 01447 * 01448 * Author: James Couzens <jcouzens@6o4.ca> 01449 * 01450 * Date: 01/18/04 01451 * 01452 * Desc: 01453 * Is the passed string (limited to between 0 - 255 by type) 01454 * contains a valid ip address or not. I'm not sure if this is useful 01455 * anymore but at one point I was using it to tell if the passed macro 01456 * contained an ip address or not when passed as a string. 01457 * 01458 */ 01459 SPF_BOOL UTIL_is_ip(const char *id) 01460 { 01461 u_int8_t i = 0; 01462 01463 while (*id) 01464 { 01465 if (*id == '.') 01466 { 01467 i++; 01468 } 01469 else if (isdigit(*id) == 0) 01470 { 01471 return(FALSE); 01472 } 01473 id++; 01474 } 01475 01476 if (i == 3) 01477 { 01478 return(TRUE); 01479 } 01480 01481 return(FALSE); 01482 } 01483 01484 01485 /* UTIL_rev_addr 01486 * 01487 * Author: James Couzens <jcouzens@6o4.ca> 01488 * 01489 * Date: 01/04/04 01490 * 01491 * Desc: 01492 * Using a passed ip address it will reverse it and slap 01493 * .in-addr.arpa on the end of it making it ready for a proper PTR query 01494 * 01495 * Notes: Write additional code to handle IP6 addresses 01496 * 01497 */ 01498 char *UTIL_rev_addr(const char *s) 01499 { 01500 u_int8_t i = 0; /* utility */ 01501 u_int16_t len = 0; /* length of to be allocated string */ 01502 u_int8_t tmp[4][1]; /* temporary storage for ip integers */ 01503 01504 char *cp; /* copy of passed string */ 01505 char *token; /* token for splitting apart ip address */ 01506 char *new_addr; /* allocate string for reversed address */ 01507 01508 if (s == NULL) 01509 { 01510 xeprintf("Passed a null string. Abort!\n"); 01511 return(NULL); 01512 } 01513 01514 xvprintf("Called with: (%s) len: %i\n", s, strlen(s)); 01515 01516 len = (strlen(s) + 1); 01517 cp = xstrndup(s, len); 01518 token = strtok(cp, "."); 01519 01520 while (token != NULL && i <= 3) 01521 { 01522 xvprintf("token : (%s)\n", token); 01523 tmp[i][0] = atoi(token); 01524 token = strtok(NULL, "."); 01525 i++; 01526 } 01527 01528 xfree(cp); 01529 01530 /* + .in-addr.arpa\0 */ 01531 new_addr = xmalloc(len + 13); 01532 01533 memset(new_addr, '\0', len); 01534 sprintf(new_addr, "%u.%u.%u.%u.in-addr.arpa", tmp[3][0], tmp[2][0], 01535 tmp[1][0], tmp[0][0]); 01536 01537 xvprintf("Returning reversed ip: %s\n", new_addr); 01538 01539 return(new_addr); 01540 } 01541 01542 01543 /* UTIL_get_dname 01544 * 01545 * Author: James Couzens <jcouzens@6o4.ca> 01546 * 01547 * Date: 01/27/04 01548 * 01549 * Desc: 01550 * s contains a hostname which is then looked through and split 01551 * apart, always leaving one '.' delimiter left so you are left with 01552 * domain.tld. domain.tld is then put into newly allocated memory and 01553 * returned to the calling function. Upon failure, returns NULL. 01554 * Calling function is required to free the memory. 01555 * 01556 */ 01557 char *UTIL_get_dname(const char *s) 01558 { 01559 u_int8_t i = 0; /* how many delimiters in s */ 01560 char *buf = NULL; /* return string to be allocated */ 01561 01562 if (s == NULL) 01563 { 01564 xeprintf("Called with NULL. Abort!\n"); 01565 01566 return(NULL); 01567 } 01568 01569 xvprintf("Called with (%s)\n", s); 01570 01571 i = UTIL_count_delim(s, '.'); 01572 01573 switch (i) 01574 { 01575 case 0: 01576 return(NULL); 01577 case 1: 01578 buf = xstrndup(s, (strlen(s) + 1)); 01579 return(buf); 01580 default: 01581 buf = UTIL_split_str(s, '.', (i - 1)); 01582 return(buf); 01583 } 01584 01585 return(NULL); 01586 } 01587 01588 01589 /* UTIL_cidr_cmp 01590 * 01591 * Author: James Couzens <jcouzens@6o4.ca> 01592 * 01593 * Date: 12/26/03 01594 * 01595 * Desc: 01596 * Compares an IP address (connected peer) against another IP 01597 * address (found in a policy lookup) using a netmask (also found from 01598 * a policy lookup) to see if the peer address is legal within that 01599 * netmask. Returns TRUE if its valid, FALSE if not. 01600 * 01601 * Notes: Write additional comparisons to handle IP6 addresses 01602 * 01603 */ 01604 SPF_BOOL UTIL_cidr_cmp(peer_info_t *peer_info, const policy_addr_t *policy_addr, 01605 const struct in_addr *peer_addr) 01606 { 01607 u_int32_t a; 01608 u_int32_t b; 01609 01610 char *peer_ip = NULL; 01611 char *policy_ip = NULL; 01612 01613 if ((policy_addr->addr.s_addr <= 0) && 01614 (peer_addr->s_addr <= 0)) 01615 { 01616 xeprintf("Passed with NULL chars. Aborting.\n"); 01617 return(FALSE); 01618 } 01619 01620 xvprintf("POL: %lu PEER: %lu CIDR: %i\n", policy_addr->addr.s_addr, 01621 peer_addr->s_addr, policy_addr->cidr); 01622 01623 a = ntohl(peer_addr->s_addr); 01624 b = ntohl(policy_addr->addr.s_addr); 01625 01626 if (policy_addr->cidr != 32) 01627 { 01628 if ((a&(~0U<<(32-policy_addr->cidr))) != (b&(~0U<<(32-policy_addr->cidr)))) 01629 { 01630 return(FALSE); 01631 } 01632 } 01633 else 01634 { 01635 if (peer_addr->s_addr != policy_addr->addr.s_addr) 01636 { 01637 xvprintf("%lu and %lu using 32 cidr do not match\n", peer_addr->s_addr, 01638 policy_addr->addr.s_addr); 01639 return(FALSE); 01640 } 01641 } 01642 01643 /* these are done here just for debugger remove later */ 01644 peer_ip = xstrndup(inet_ntoa(*peer_addr), IP_ADDR); 01645 policy_ip = xstrndup(inet_ntoa(policy_addr->addr), IP_ADDR); 01646 01647 xvprintf("Peer: (%s) matches address %s with network %i\n", peer_ip, 01648 policy_ip, policy_addr->cidr); 01649 01650 xfree(peer_ip); 01651 xfree(policy_ip); 01652 01653 return(TRUE); 01654 } 01655 01656 01657 /* UTIL_validate_ptr 01658 * 01659 * Author: James Couzens <jcouzens@6o4.ca> 01660 * 01661 * Date: 12/26/03 01662 * 01663 * Desc: 01664 * Using the ip address found in the passed peer_info structure, 01665 * a PTR lookup is made and if a record exists then this is record is compared 01666 * against the hostname the client wishes to send mail from. If the tld matches 01667 * the tld found during this query, this would be a 'valdiated' PTR. If a match 01668 * can not be found we return FALSE. If a match is made we return TRUE. 01669 * 01670 * Notes: Write additional comparisons to handle IP6 addresses 01671 * 01672 */ 01673 SPF_BOOL UTIL_validate_ptr(peer_info_t *peer_info) 01674 { 01675 char *ptr_addr; /* reversed address into PTR format */ 01676 char *tmp_ptr; /* utility pointer */ 01677 01678 /* reverse of the address in peer_info */ 01679 ptr_addr = UTIL_rev_addr(peer_info->r_ip); 01680 xvprintf("[address: %s]\n", ptr_addr); 01681 01682 tmp_ptr = xstrndup(peer_info->cur_dom, (strlen(peer_info->cur_dom) + 1)); 01683 01684 if (DNS_query(peer_info, ptr_addr, T_PTR, tmp_ptr) != (char *)TRUE) 01685 { 01686 xvprintf("PTR lookup failed: (%s) (%s)\n", peer_info->rs, 01687 peer_info->error); 01688 01689 xfree(ptr_addr); 01690 xfree(tmp_ptr); 01691 return(FALSE); 01692 } 01693 01694 xvprintf("Peer (%s) successfully validated hostname (%s)\n", 01695 peer_info->r_ip, peer_info->r_vhname); 01696 01697 xfree(ptr_addr); 01698 xfree(tmp_ptr); 01699 return(TRUE); 01700 } 01701 01702 01703 /* UTIL_validate_hostname 01704 * 01705 * Author: James Couzens <jcouzens@6o4.ca> 01706 * 01707 * Date: 01/08/04 01708 * 01709 * Desc: 01710 * s contains a hostname which is then looked up to find any 01711 * of the returned ip addresses SPF_PASS the remote peers. On a successful 01712 * SPF_PASS returns TRUE. When no SPF_PASS is made, returns FALSE. 01713 * 01714 * Note: 01715 * We need to define and set a limit on the number of recursive 01716 * lookups. I recall seeing this in the RFC, we should discuss this. 01717 * 01718 */ 01719 SPF_BOOL UTIL_validate_hostname(peer_info_t *peer_info, const char *s, 01720 const int8_t cidr) 01721 { 01722 char **a; 01723 char *val_ip; 01724 01725 struct in_addr addr; 01726 char *ip = NULL; 01727 01728 struct in_addr val_addr; 01729 struct hostent *hp; 01730 01731 policy_addr_t *policy_addr; 01732 01733 if (s == NULL) 01734 { 01735 xeprintf("Passed a NULL string.\n"); 01736 return(FALSE); 01737 } 01738 01739 xvprintf("Called with: (%lu) and (%s)\n", peer_info->r_ip, s); 01740 01741 if ((hp = gethostbyname(s)) != NULL) 01742 { 01743 for (a = hp->h_addr_list; *a; a++) 01744 { 01745 memcpy(&addr.s_addr, *a, sizeof(struct in_addr)); 01746 ip = xstrndup(inet_ntoa(addr), IP_ADDR); 01747 01748 xvprintf("CLI: %s (%lu) SRV: %s (%lu)\n", ip, addr.s_addr, 01749 peer_info->r_ip, peer_info->addr.s_addr); 01750 01751 if (cidr == 32) 01752 { 01753 if (((struct in_addr *)(*a))->s_addr == peer_info->addr.s_addr) 01754 { 01755 xvprintf("%s (%lu) matches %s (%lu)\n", ip, 01756 ((struct in_addr *)(*a))->s_addr, peer_info->r_ip, 01757 peer_info->addr.s_addr); 01758 01759 xfree(ip); 01760 UTIL_assoc_prefix(peer_info, SPF_PASS, NULL); 01761 return(TRUE); 01762 } 01763 } 01764 else if ((cidr < 32) && (cidr >= 8)) 01765 { 01766 memcpy(&val_addr.s_addr, hp->h_addr, hp->h_length); 01767 val_ip = xstrndup(inet_ntoa(val_addr), IP_ADDR); 01768 01769 xvprintf("IP: (%s)\n", val_ip); 01770 01771 policy_addr = xmalloc(sizeof(policy_addr_t)); 01772 01773 if ((inet_pton(AF_INET, val_ip, &policy_addr->addr)) == 0) 01774 { 01775 xeprintf("Unable to execute inet_pton()\n"); 01776 } 01777 01778 policy_addr->cidr = cidr; 01779 01780 if ((UTIL_cidr_cmp(peer_info, policy_addr, &peer_info->addr)) == TRUE) 01781 { 01782 xvprintf("(%lu) matches (%lu) with CIDR %u\n", 01783 policy_addr->addr.s_addr, peer_info->addr.s_addr, cidr); 01784 01785 xfree(ip); 01786 xfree(policy_addr); 01787 xfree(val_ip); 01788 UTIL_assoc_prefix(peer_info, SPF_PASS, NULL); 01789 return(TRUE); 01790 } 01791 else 01792 { 01793 xfree(policy_addr); 01794 xfree(val_ip); 01795 } 01796 } 01797 xfree(ip); 01798 } 01799 01800 for (a = hp->h_aliases; *a; a++) 01801 { 01802 memcpy(&addr.s_addr, *a, sizeof(struct in_addr)); 01803 ip = xstrndup(inet_ntoa(addr), IP_ADDR); 01804 01805 xvprintf("CLI: %s (%lu) SRV: %s (%lu)\n", ip, addr.s_addr, 01806 peer_info->r_ip, peer_info->addr.s_addr); 01807 01808 if (cidr == 32) 01809 { 01810 if (((struct in_addr *)(*a))->s_addr == peer_info->addr.s_addr) 01811 { 01812 xvprintf("%s (%lu) SPF_MATCHes %s (%lu)\n", ip, 01813 ((struct in_addr *)(*a))->s_addr, peer_info->r_ip, 01814 peer_info->addr.s_addr); 01815 01816 xfree(ip); 01817 return(TRUE); 01818 } 01819 } 01820 else if ((cidr < 32) && (cidr >= 8)) 01821 { 01822 memcpy(&val_addr.s_addr, hp->h_addr, hp->h_length); 01823 val_ip = xstrndup(inet_ntoa(val_addr), IP_ADDR); 01824 01825 xvprintf("ALIAS: (%s)\n", 01826 val_ip); 01827 01828 policy_addr = xmalloc(sizeof(policy_addr_t)); 01829 01830 if ((inet_pton(AF_INET, val_ip, &policy_addr->addr)) == 0) 01831 { 01832 xeprintf("Unable to execute inet_pton()\n"); 01833 } 01834 01835 policy_addr->cidr = cidr; 01836 01837 if ((UTIL_cidr_cmp(peer_info, policy_addr, &peer_info->addr)) == TRUE) 01838 { 01839 xvprintf("(%lu) matches (%lu) with CIDR %u\n", 01840 policy_addr->addr.s_addr, peer_info->addr.s_addr, cidr); 01841 01842 xfree(ip); 01843 xfree(policy_addr); 01844 xfree(val_ip); 01845 UTIL_assoc_prefix(peer_info, SPF_PASS, NULL); 01846 return(TRUE); 01847 } 01848 else 01849 { 01850 xfree(policy_addr); 01851 xfree(val_ip); 01852 } 01853 } 01854 xfree(ip); 01855 } 01856 } 01857 else 01858 { 01859 xvprintf("Unable to obtain ip address for (%s)\n", s); 01860 } 01861 01862 return(FALSE); 01863 } 01864 01865 01866 /* UTIL_url_encode 01867 * 01868 * Author: Sean Comeau <scomeau@obscurity.org> 01869 * 01870 * Date: 01/06/04 01871 * 01872 * Desc: 01873 * "URL-Encode" characters that are "unsafe" or "prohibited" from 01874 * a URL. Upon success returns a pointer to a newly allocated memory 01875 * containing the encoded string. Upon failure returns a NULL pointer. 01876 * Failure indicates either a failure to allocate new memory, or the 01877 * passed string did not contain any questionable characters and hence 01878 * did not require encoding. 01879 * 01880 */ 01881 char *UTIL_url_encode(const char *s) 01882 { 01883 int len; /* length of passed string * 3*/ 01884 char *new; /* newly allocated memory */ 01885 char *encoded; /* encoded return string */ 01886 01887 if (s != NULL) 01888 { 01889 /* length of the string * 3 is the maximum possible size an 01890 encoded string could ever expand to */ 01891 len = (strlen(s) * 3); 01892 } 01893 else 01894 { 01895 xeprintf("Passed a NULL string. Abort!\n"); 01896 return(NULL); 01897 } 01898 01899 encoded = new = xmalloc(len); 01900 01901 while (*s != '\0') 01902 { 01903 if (urlchr_test(*s) == 0) 01904 { 01905 *new++ = *s++; 01906 } 01907 else 01908 { 01909 snprintf(new, 4, "%%%x", *s); /* this NULL terminates do we want? */ 01910 new += 3; s++; 01911 } 01912 } 01913 01914 *new++ = '\0'; 01915 xvprintf("[%s] UTIL_url_encode :: Returning (%s)\n", encoded); 01916 01917 return(encoded); 01918 } 01919 01920 01921 /* UTIL_reverse 01922 * 01923 * Author: James Couzens <jcouzens@6o4.ca> 01924 * 01925 * Date: 01/06/04 01926 * 01927 * Desc: 01928 * Takes a string and rebuilds it in reverse order using the 01929 * supplied delimiter. The string will always be rebuilt using a 01930 * '.' char as per the RFC. 01931 * 01932 */ 01933 char *UTIL_reverse(const char *s, const char delim) 01934 { 01935 size_t len; /* length of s */ 01936 01937 split_str_t *master; /* list pointers */ 01938 split_str_node_t *c_node; /* c_node node */ 01939 split_str_node_t *kill_node; /* temp node used in destruction */ 01940 01941 char *buf; /* return buffer */ 01942 char *p; /* working pointer */ 01943 char *cp; /* working pointer */ 01944 char *c; /* working pointer */ 01945 01946 if (s == NULL) 01947 { 01948 xeprintf("Passed a NULL string. Abort!\n"); 01949 return(NULL); 01950 } 01951 01952 xvprintf("Called with (%s) and delim (%c)\n", 01953 s, delim); 01954 01955 len = strlen(s); 01956 cp = c = xstrndup(s, (len + 1)); 01957 01958 master = xmalloc(sizeof(split_str_t)); 01959 master->head = NULL; 01960 master->tail = NULL; 01961 master->elements = 0; 01962 01963 /* Comment: James Couzens <jcouzens@6o4.ca> 01964 * Date: 01/22/04 01965 * 01966 * we do not want the trailing delim so the first iteration of this 01967 * loop we call UTIL_addnode with 0, which tells it not to allocate 01968 * the extra byte for the trailing delimiter. This is done only 01969 * when passed an IP address, and this is because when reversing we 01970 * want: 1.0.168.192. and not .1.0.168.192 01971 * 01972 */ 01973 01974 buf = xmalloc(len + 1); 01975 memset(buf, '\0', (len + 1)); 01976 01977 while ((p = strrchr(cp, delim)) != NULL) 01978 { 01979 p++; /* remove period */ 01980 UTIL_addnode(master, p, TRUE); 01981 p--; /* bring it back */ 01982 *p = '\0'; 01983 } 01984 01985 UTIL_addnode(master, cp, FALSE); 01986 01987 c_node = master->head; 01988 while ((kill_node = c_node) != NULL) 01989 { 01990 strncat(buf, kill_node->s, kill_node->len); 01991 xfree(kill_node->s); 01992 c_node = c_node->next; 01993 xfree(kill_node); 01994 } 01995 01996 xfree(cp); 01997 xfree(master); 01998 01999 xvprintf("Returning (%s)\n", buf); 02000 02001 return(buf); 02002 } 02003 02004 02005 /* UTIL_addnode 02006 * 02007 * Author: James Couzens <jcouzens@6o4.ca> 02008 * 02009 * Date: 01/18/04 02010 * 02011 * Desc: 02012 * Allocates memory for a new node and slaps it on the end of 02013 * of the passed list. In the process of doing so, when it comes to 02014 * the last element in the list, which is indicated by the SPF_BOOL 02015 * that is passed, a final '.' is either appended (TRUE) or not 02016 * (FALSE). Function returns TRUE upon success, and FALSE upon 02017 * failure. 02018 * 02019 */ 02020 SPF_BOOL UTIL_addnode(split_str_t *master, const char *s, SPF_BOOL last) 02021 { 02022 size_t len; /* length of s */ 02023 02024 split_str_node_t *c_node; /* c_node working node */ 02025 split_str_node_t *new_node; /* newly allocated node */ 02026 split_str_node_t *prev_node; /* previous working node */ 02027 02028 if (s == NULL) 02029 { 02030 xeprintf("Passed a NULL string. Abort!\n"); 02031 return(FALSE); 02032 } 02033 02034 len = strlen(s); 02035 02036 if (last == TRUE) 02037 { 02038 len += 2; 02039 } 02040 else 02041 { 02042 len++; 02043 } 02044 02045 /* create new node */ 02046 new_node = xmalloc(sizeof(split_str_node_t)); 02047 02048 /* set the new nodes next value NULL, and store s */ 02049 new_node->next = NULL; 02050 02051 new_node->s = xmalloc(len); 02052 memset(new_node->s, '\0', len); 02053 02054 /* Comment: James Couzens <jcouzens@6o4.ca> 02055 * Date: 01/22/04 02056 * 02057 * section 7.1 (Macro definitions) of the RFC v02.9.5 indicates that we must 02058 * always rebuild the macro using the delimiter '.' and not the passed 02059 * delimiting character. 02060 * 02061 */ 02062 snprintf(new_node->s, len, "%s%c", s, last ? '.' : '\0'); 02063 new_node->len = (len - 1); /* don't count \0 */ 02064 02065 prev_node = NULL; 02066 c_node = master->head; 02067 02068 /* reorder the list with the NEW element on the end */ 02069 while (c_node != NULL) 02070 { 02071 prev_node = c_node; 02072 c_node = c_node->next; 02073 } 02074 02075 if (prev_node != NULL) 02076 { 02077 new_node->next = prev_node->next; 02078 prev_node->next = new_node; 02079 } 02080 else 02081 { 02082 master->head = new_node; 02083 } 02084 02085 master->tail = new_node; 02086 master->elements++; 02087 02088 return(TRUE); 02089 } 02090 02091 02092 /* end of util.c */

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