util.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 #ifdef _WITH_PTHREADS 00046 #include <pthread.h> /* pthread_mutex_t */ 00047 #endif /* _WITH_PTHREADS */ 00048 00049 #include "util.h" /* Utility functions */ 00050 #include "dns.h" /* DNS Functions */ 00051 00052 #undef VERSION /* autoconf */ 00053 00054 00055 #ifdef _WITH_PTHREADS 00056 /* 00057 * pthread mutex used to facilitate reentrant competence within the 00058 * utility functions (generally the debugging functionality, you 00059 * could (after some poking around) probably safely remove this if 00060 * debugging was disabled) 00061 */ 00062 pthread_mutex_t util_mutex; 00063 00064 #else 00065 /* utility functions dummy pthread mutex wrapper */ 00066 void *util_mutex; 00067 00068 #endif /* _WITH_PTHREADS */ 00069 00070 00071 00072 /* 00073 * globals 00074 * 00075 */ 00076 00077 extern int errno; 00078 00079 00080 00081 /* _pprintf_dbg 00082 * 00083 * Author: James Couzens <jcouzens@codeshare.ca> 00084 * 00085 * Date: 09/08/04 00086 * 00087 * Desc: 00088 * Handles debugging output when no variadic macro's are desired 00089 * and the caller simply wishes to send a single string to output but 00090 * wishes to have the appropriate function and other identifiers 00091 * prepended. 00092 * 00093 * Referenced by xpprintf (formerly used for profile output) 00094 * and xepprintf. 00095 * 00096 */ 00097 void _pprintf_dbg(u_int8_t level, const char *func, const char * file, 00098 const size_t line, const char *s) 00099 { 00100 char *buf; /* working buffer */ 00101 00102 00103 if (!s) 00104 { 00105 fprintf(stderr, "_eprintf_dbg passed a NULL string\n"); 00106 fflush(stderr); 00107 00108 return; 00109 } 00110 00111 buf = xmalloc(SPF_MAX_DEBUG + 1); 00112 snprintf(buf, SPF_MAX_DEBUG, "[%s :: %s->%i]; %s", func, file, line, s); 00113 00114 if (f_bit_set(confg.level, level)) 00115 { 00116 if (level == FL_D) /* xpprintf */ 00117 { 00118 fprintf(stdout, buf); 00119 fflush(stdout); 00120 } 00121 } 00122 00123 if (level == FL_F) /* xepprintf */ 00124 { 00125 fprintf(stderr, buf); 00126 fflush(stderr); 00127 } 00128 00129 xfree(buf); 00130 00131 return; 00132 } 00133 00134 00135 /* _printf_dbg 00136 * 00137 * Author: James Couzens <jcouzens@codeshare.ca> 00138 * 00139 * Date: 12/25/03 00140 * Date: 02/18/04 (updated) 00141 * 00142 * Desc: 00143 * Tied to a compile time switch this can instantly and at little 00144 * to no real expense enable a discreet debugging with out hoards of 00145 * #ifdefs all over the place. 00146 * 00147 * Date: 09/08/04 - James Couzens <jcouzens@codeshare.ca> 00148 * 00149 * Desc: 00150 * Modified to handle output for xeprintf (behaviour adjusted to call 00151 * here instead) so that its actually clear where errors are being raised from. 00152 * 00153 */ 00154 void _printf_dbg(u_int8_t level, const char *func, const char *file, 00155 const size_t line, const char *format,...) 00156 { 00157 #ifdef _SPF_DEBUG_LOGFILE 00158 FILE *fp = NULL; /* file pointer */ 00159 #endif /* _SPF_DEBUG_LOGFILE */ 00160 00161 char *buf; /* working buffer */ 00162 char *tbuf; /* working buffer for eprintf */ 00163 00164 va_list argptr; /* pointer to current argument from array */ 00165 00166 00167 xpthread_mutex_lock(&util_mutex); 00168 00169 if (!format || *format == '\0') 00170 { 00171 fprintf(stderr, "_printf_dbg passed null format array\n"); 00172 fflush(stderr); 00173 00174 return; 00175 } 00176 00177 buf = xmalloc(SPF_MAX_DEBUG + 1); 00178 tbuf = xmalloc(SPF_MAX_DEBUG + 1); 00179 00180 va_start(argptr, format); 00181 vsnprintf(buf, SPF_MAX_DEBUG, format, argptr); 00182 va_end(argptr); 00183 00184 snprintf(tbuf, SPF_MAX_DEBUG, "[%s :: %s->%i]; %s", func, file, line, buf); 00185 00186 /* xepprintf */ 00187 if (level == FL_E) 00188 { 00189 fprintf(stderr, tbuf); 00190 fflush(stderr); 00191 } 00192 else 00193 { 00194 if (f_bit_set(confg.level, level)) 00195 { 00196 #ifndef _SPF_DEBUG_LOGFILE 00197 fprintf(stdout, tbuf); 00198 fflush(stdout); 00199 #else 00200 if ((fp = fopen(DEBUG_LOG_FILE, "a")) != NULL) 00201 { 00202 fprintf(fp, "[%s :: %s->%i]; %s", func, file, line, buf); 00203 fclose(fp); 00204 } 00205 else 00206 { 00207 fprintf(stderr, "libSPF can't open file (%s) for writing!\n", 00208 DEBUG_LOG_FILE); 00209 fflush(stderr); 00210 perror(func); 00211 } 00212 #endif /* _SPF_DEBUG_LOGFILE */ 00213 } 00214 } /* else */ 00215 00216 free(buf); 00217 free(tbuf); 00218 00219 xpthread_mutex_unlock(&util_mutex); 00220 00221 return; 00222 } 00223 00224 00225 #ifndef _SPF_DEBUG_LOGFILE 00226 /* dummy_debug 00227 * 00228 * Author: James Couzens <jcouzens@codeshare.ca> 00229 * 00230 * Date: 12/25/03 00231 * 00232 * Desc: 00233 * dummy function thats used instead of the _printf_dbg function 00234 * when compiling without debugging 00235 * 00236 */ 00237 void _dummy_debug(const u_int8_t level, const char *func, const char *file, 00238 const size_t line, const char *format,...) 00239 { 00240 return; 00241 } 00242 00243 00244 /* dummy_debug 00245 * 00246 * Author: James Couzens <jcouzens@codeshare.ca> 00247 * 00248 * Date: 12/25/03 00249 * 00250 * Desc: 00251 * dummy function thats used instead of the _printf_dbg function 00252 * when compiling without debugging 00253 * 00254 */ 00255 void _dummy_pdebug(const u_int8_t level, const char *func, const char *file, 00256 const size_t line, const char *s) 00257 { 00258 return; 00259 } 00260 00261 #endif 00262 00263 00264 /* UTIL_get_date 00265 * 00266 * Author: James Couzens <jcouzens@codeshare.ca> 00267 * Date: Sun Jan 18 06:02:13 PST 2004 00268 * 00269 * Desc: 00270 * Returns in a buffer that must be freed by the caller, the date 00271 * in the format YY-MM-DD HH:MM:SS and is derived from UTC time. 00272 * 00273 * Date: 09/08/04 - James Couzens <jcouzens@codeshare.ca> 00274 * 00275 * Desc: 00276 * Added pthread mutex lock during body of this function because it 00277 * appears as those inspite of the use of localtime_r there is some un-safe 00278 * behaviour that goes on here so for now the mutex here appears to solve 00279 * the problem. 00280 * 00281 */ 00282 char *UTIL_get_date(void) 00283 { 00284 struct tm *now; /* time in tm struct format */ 00285 struct tm tmbuf; /* reentrant buffer for localtime_r */ 00286 00287 time_t curtime; /* current time time_t struct format */ 00288 00289 char *my_time; /* time in human readable format */ 00290 00291 00292 xpthread_mutex_lock(&util_mutex); 00293 00294 curtime = time(NULL); 00295 now = localtime_r(&curtime, &tmbuf); 00296 my_time = xmalloc(SPF_MAX_DATETIME); 00297 00298 strftime(my_time, SPF_MAX_DATETIME, "%Y-%m-%d %H:%M:%S ", now); 00299 my_time[(SPF_MAX_DATETIME - 1)] = '\0'; 00300 00301 xpthread_mutex_unlock(&util_mutex); 00302 00303 return(my_time); 00304 } 00305 00306 00307 /* UTIL_log_result 00308 * 00309 * Author: James Couzens <jcouzens@codeshare.ca> 00310 * 00311 * Date: 02/04/04 00312 * 00313 * Desc: 00314 * Tied to a compile time switch this can instantly and at little 00315 * to no real expense enable a discreet debugging with out hoards of 00316 * #ifdefs all over the place. 00317 * 00318 * Date: 09/08/04 - James Couzens <jcouzens@codeshare.ca> 00319 * 00320 * Desc: 00321 * Added pthread mutex lock during body of this function because it 00322 * is to the detriment of stability to have multiple threads attempting to 00323 * open/write/close the same file at the same time! :-) 00324 * 00325 */ 00326 void UTIL_log_result(peer_info_t *p) 00327 { 00328 FILE *fp = NULL; /* file pointer */ 00329 00330 char *buf; /* working buffer */ 00331 char *date; /* date/time stamp */ 00332 00333 00334 date = UTIL_get_date(); 00335 buf = xmalloc(SPF_MAX_DEBUG); 00336 *(date + (strlen(date) - 1)) = '\0'; 00337 00338 if (p->spf_ver == 0) 00339 { 00340 p->spf_ver = SPF_VERSION; 00341 } 00342 00343 xpthread_mutex_lock(&util_mutex); 00344 00345 snprintf(buf, SPF_MAX_DEBUG, 00346 "[%s] result: %s :: %s [%s], ver: %i, depth: %i, error: (%s)\n", 00347 date, p->spf_result[p->RES].s, p->from, 00348 p->r_ip, p->spf_rlevel, p->spf_ver, p->error); 00349 00350 if ((fp = fopen(OUTPUT_LOG_FILE, "a")) != NULL) 00351 { 00352 fprintf(fp, "%s", buf); 00353 fclose(fp); 00354 } 00355 00356 xpthread_mutex_unlock(&util_mutex); 00357 00358 xfree(date); 00359 xfree(buf); 00360 00361 return; 00362 } 00363 00364 00365 /* xstrndup 00366 * 00367 * Author: James Couzens <jcouzens@codeshare.ca> 00368 * 00369 * Date: 12/25/03 00370 * 00371 * Desc: 00372 * n bytes are allocated and then filled with \0 chars. Char s 00373 * is copied over to the allocated memory writing n -1 bytes leaving the 00374 * new string NULL terminated. This new string is returned upon success 00375 * and NULL upon failure. 00376 * 00377 */ 00378 char *UTIL_strndup(const char *s, const size_t n) 00379 { 00380 char *ret_ptr = NULL; /* return buffer */ 00381 00382 00383 if ((s == NULL) || (n <= 0)) 00384 { 00385 xepprintf("Passed string is NULL. Abort!.\n"); 00386 00387 return(SPF_FALSE); 00388 } 00389 00390 ret_ptr = xmalloc(n + 1); 00391 xvprintf("Allocated %u bytes of memory.\n", n); 00392 snprintf(ret_ptr, n, s); 00393 xvprintf("leaving function; returning string: (%s)\n", ret_ptr); 00394 00395 return(ret_ptr); 00396 } 00397 00398 00399 /* xstrdup 00400 * 00401 * Author: Patrick Earl (http://patearl.net/) 00402 * Adapted from xstrndup() 00403 * 00404 * Date: 02/04/04 00405 * 00406 * Desc: 00407 * strlen(s)+1 bytes are allocated and s is copied into the 00408 * freshly allocated memory. If the allocation or copy fails, NULL 00409 * NULL will be returned. 00410 * 00411 */ 00412 char *UTIL_strdup(const char *s) 00413 { 00414 char *ret_ptr = NULL; /* return buffer */ 00415 00416 00417 if (s == NULL) 00418 { 00419 xepprintf("Passed string is NULL. Abort!.\n"); 00420 00421 return(SPF_FALSE); 00422 } 00423 00424 if ((ret_ptr = strdup(s)) == NULL) 00425 { 00426 xepprintf("Unable to allocate memory\n"); 00427 } 00428 00429 xvprintf("leaving function; returning string: (%s)\n", ret_ptr); 00430 00431 return(ret_ptr); 00432 } 00433 00434 00435 /* UTIL_malloc 00436 * 00437 * Author: Travis Anderson <travis@anthrax.ca> 00438 * Author: James Couzens <jcouzens@codeshare.ca> 00439 * 00440 * Date: 02/17/04 00441 * 00442 * Desc: 00443 * Wrapper for malloc. Upon success, behaves as malloc does. 00444 * Wrapper functionality is to print an error message and exit upon failure. 00445 * 00446 */ 00447 void *UTIL_malloc(const int32_t n, const char *file, int32_t line, 00448 const char *func) 00449 { 00450 void *x = malloc(n); 00451 00452 if (x == NULL) 00453 { 00454 xvprintf("Unable to allocate %i bytes at %s:%i in %s\n", 00455 n, file, line, func); 00456 00457 /* 00458 * Be advised this is the only place I do this, because quite 00459 * honestly, if this library can't get a few bytes of memory, 00460 * your mailserver segfaulting as a result of this exit, or 00461 * quitting or whatever is the LEAST of your problems! 00462 */ 00463 exit(0); 00464 } 00465 00466 memset(x, '\0', n); 00467 00468 return(x); 00469 } 00470 00471 00472 /* UTIL_realloc 00473 * 00474 * Author: Travis Anderson <travis@anthrax.ca> 00475 * Author: James Couzens <jcouzens@codeshare.ca> 00476 * 00477 * Date: 02/17/04 00478 * 00479 * Desc: 00480 * Wrapper for realloc. If 'p' is NULL, allocates memory via a call to 00481 * UTIL_malloc, otherwise if 'x' is assigned successfully, the behaviour is 00482 * identical to realloc. Wrapper functionality is to print an error message 00483 * and exit upon failure. 00484 * 00485 */ 00486 void *UTIL_realloc(void *p, const int32_t n, const char *file, 00487 const int32_t line, const char *func) 00488 { 00489 void *x = NULL; 00490 00491 if (p == NULL) 00492 { 00493 return(UTIL_malloc(n, file, line, func)); 00494 } 00495 00496 x = realloc(p, n); 00497 if (x == NULL) 00498 { 00499 xvprintf("Unable to reallocate %i bytes at %s:%i in %s; " \ 00500 "original address 0x%x\n", n, file, line, func, (uintptr_t)p); 00501 00502 exit(0); 00503 } 00504 00505 return(x); 00506 } 00507 00508 00509 /* UTIL_free 00510 * 00511 * Author: Travis Anderson <travis@anthrax.ca> 00512 * Author: James Couzens <jcouzens@codeshare.ca> 00513 * 00514 * Date: 02/17/04 00515 * 00516 * Desc: 00517 * Wrapper for free. Upon success, behaves as free does. 00518 * Wrapper functionality is to print an error message and exit upon 00519 * failure. 00520 * 00521 */ 00522 void UTIL_free(void *p, const char *file, const int32_t line, const char *func) 00523 { 00524 if (p == NULL) 00525 { 00526 xvprintf("Unable to free() on NULL pointer at %s:%i in %s; " \ 00527 "address 0x%x.\n", file, line, func, (uintptr_t)p); 00528 00529 return; 00530 } 00531 00532 xvprintf("Free address 0x%x by %s on line %i (%s)\n", 00533 (uintptr_t)p, func, line, file); 00534 00535 free(p); 00536 00537 return; 00538 } 00539 00540 00541 /* UTIL_index 00542 * 00543 * Author: James Couzens <jcouzens@codeshare.ca> 00544 * 00545 * Date: 12/19/03 00546 * 00547 * Desc: 00548 * s is walked until c is found, at which time i is returned 00549 * which is the number of bytes from the left it walked until c was 00550 * found (not including c its self); 00551 * 00552 * Date: 09/01/04 - Roger Moser 00553 * 00554 * Desc: 00555 * The return upon an error (s being NULL for exmaple) is now 00556 * -1 because returning 0 was really ambiguous. 00557 * 00558 * Returns: -1 upon error 00559 * Returns: 0 upon no match 00560 * Returns: > 0 upon success which is the number of bytes from the left 00561 * the string was walked until 'c' was found. 00562 * 00563 */ 00564 int16_t UTIL_index(const char *s, const char c) 00565 { 00566 int16_t i; /* utility */ 00567 00568 00569 if (s == NULL) 00570 { 00571 xepprintf("passed a NULL string. Abort!\n"); 00572 00573 return(-1); 00574 } 00575 00576 xvprintf("called with string: (%s); char: %c\n", s, c); 00577 00578 i = 0; 00579 while (*s) 00580 { 00581 if (*s == c) 00582 { 00583 xvprintf("Found search char: (%c); Returning: (%i)\n", *s, i); 00584 00585 return(i); 00586 } 00587 i++; 00588 s++; 00589 } 00590 00591 xpprintf("leaving function\n"); 00592 00593 return(0); 00594 } 00595 00596 00597 /* UTIL_split_str 00598 * 00599 * Author: James Couzens <jcouzens@codeshare.ca> 00600 * 00601 * Date: 01/21/04 00602 * 00603 * Desc: 00604 * s is walked through to find 'delim' until it finds 'delim' 00605 * num times. Upon final match it returns the remainder of the string 00606 * in a newly allocated buffer. Upon failure returns NULL. 00607 * 00608 * Date: 09/01/04 - Roger Moser 00609 * 00610 * Desc: 00611 * 'cp' was not being freed upon exiting the function when 'c' 00612 * was not found within the string. 00613 * 00614 */ 00615 char *UTIL_split_str(const char *s, const char c, const u_int8_t num) 00616 { 00617 u_int8_t i; /* utility */ 00618 00619 char *cp; /* copy buffer of s */ 00620 char *p; /* pointer to copy */ 00621 char *ret; /* return buffer */ 00622 00623 00624 if (s == NULL) 00625 { 00626 xepprintf("passed a NULL string. Abort!\n"); 00627 00628 return(NULL); 00629 } 00630 00631 xvprintf("called with string: (%s); char (%c); int: (%i)\n", 00632 s, c, num); 00633 00634 p = cp = xstrndup(s, SPF_MAX_STR); 00635 00636 i = 0; 00637 while(*p) 00638 { 00639 if (*p == c) 00640 { 00641 i++; 00642 if (i == num) 00643 { 00644 p++; 00645 ret = xstrndup(p, SPF_MAX_STR); 00646 00647 xfree(cp); 00648 00649 xvprintf("returning: %s\n", ret); 00650 00651 return(ret); 00652 } 00653 } 00654 p++; 00655 } 00656 00657 xfree(cp); 00658 xvprintf("[%i] returning NULL\n", i); 00659 00660 return(NULL); 00661 } 00662 00663 00664 /* UTIL_split_strr 00665 * 00666 * Author: James Couzens <jcouzens@codeshare.ca> 00667 * 00668 * Date: 01/30/04 00669 * 00670 * Desc: 00671 * s is walked to the end of its self, and then is walked back 00672 * towards the beginning of the string until it has found 'c' the 00673 * delimiter, 'num' times. Upon success memory is allocated and the 00674 * remainder of s is returned. Upon failure NULL is returned. 00675 * 00676 * Date: 09/01/04 - Roger Moser 00677 * 00678 * Desc: 00679 * Replaced 'p = (char *)&(s[strlen(s) - 1]);' with a more 00680 * optimized 'p = strchr(s, '\0') - 1;'. Also applied a fix so that 00681 * the function properly returns NULL when 's' is an empty string. 00682 * 00683 */ 00684 char *UTIL_split_strr(const char *s, const char c, const u_int8_t num) 00685 { 00686 u_int8_t i; /* number of times delim (c) is found */ 00687 00688 char *p; /* pointer to the last character of s before the \0 */ 00689 char *ret; /* return buffer */ 00690 00691 00692 if ((s == NULL) || (*s == '\0')) 00693 { 00694 xepprintf("passed a NULL string. Abort!\n"); 00695 00696 return(NULL); 00697 } 00698 00699 xvprintf("called with (%s)\n", s); 00700 00701 00702 /* assign 'p' to the last char before the null termination of 's'*/ 00703 /*p = (char *)&(s[strlen(s) - 1]);*/ 00704 p = (strchr(s, '\0') - 1); 00705 00706 i = 0; 00707 while(p != s) 00708 { 00709 if (*p == c) 00710 { 00711 i++; 00712 if (i == num) 00713 { 00714 if (*p == '.') 00715 { 00716 p++; /* don't want that period */ 00717 } 00718 00719 ret = xstrdup(p); 00720 00721 xvprintf("delimiter found (%i) times; returning (%s).\n", i, ret); 00722 00723 return(ret); 00724 } 00725 } 00726 p--; 00727 } 00728 00729 xvprintf("delimiter (%c) found (%u) times; returing NULL\n", c, i); 00730 00731 return(NULL); 00732 } 00733 00734 00735 /* UTIL_count_delim 00736 * 00737 * Author: James Couzens <jcouzens@codeshare.ca> 00738 * 00739 * Date: 01/21/04 00740 * 00741 * Desc: 00742 * s is walked through and each time 'delim' is found a counter is 00743 * incremented and once complete, that integer is returned to the calling 00744 * function. Specifically for the purposes of this project i is limited by its 00745 * type to 255. 00746 * 00747 * Returns: > 0 && <= 255 upon success 00748 * Returns: 0 upon failure 00749 * 00750 */ 00751 u_int8_t UTIL_count_delim(const char *s, const char c) 00752 { 00753 u_int8_t i = 0; /* utility */ 00754 00755 00756 if (s == NULL) 00757 { 00758 xepprintf("passed a NULL string. Abort!\n"); 00759 00760 return(0); 00761 } 00762 00763 while (*s && i < SPF_MAX_DELIM) 00764 { 00765 if (*s == c) 00766 { 00767 i++; 00768 } 00769 s++; 00770 } 00771 00772 xvprintf("found (%i) number of delimiters; returning.\n", i); 00773 00774 return(i); 00775 } 00776 00777 00778 /* UTIL_is_spf_delim 00779 * 00780 * Author: James Couzens <jcouzens@codeshare.ca> 00781 * 00782 * Date: 01/21/04 00783 * 00784 * Desc: 00785 * c is compared against all the valid spf delimiters and 00786 * in the case of a SPF_PASS, the function returns true, otherwise it will 00787 * return false. 00788 * 00789 */ 00790 SPF_BOOL UTIL_is_spf_delim(const char c) 00791 { 00792 00793 if (!c) 00794 { 00795 xepprintf("called with a NULL char! Aborting check.\n"); 00796 00797 return(SPF_FALSE); 00798 } 00799 00800 xvprintf("called with char (%c)\n", c); 00801 00802 if (c == '.' || 00803 c == '-' || 00804 c == '+' || 00805 c == ',' || 00806 c == '|' || 00807 c == '_') 00808 { 00809 xpprintf("leaving function; returning SPF_FALSE\n"); 00810 00811 return(SPF_TRUE); 00812 } 00813 00814 xpprintf("leaving function; returning SPF_FALSE\n"); 00815 00816 return(SPF_FALSE); 00817 } 00818 00819 00820 /* UTIL_is_spf_result 00821 * 00822 * Author: James Couzens <jcouzens@codeshare.ca> 00823 * 00824 * Date: 01/27/04 00825 * 00826 * Desc: 00827 * c is compared against all the valid spf prefixes and 00828 * in the case of a SPF_PASS, the function returns true, otherwise it will 00829 * return false. 00830 * 00831 */ 00832 SPF_BOOL UTIL_is_spf_result(const char c) 00833 { 00834 if (!c) 00835 { 00836 xpprintf("passed a NULL or empty char!\n"); 00837 00838 return(SPF_FALSE); 00839 } 00840 00841 xvprintf("called with char (%c)\n", c); 00842 00843 if (c == '+' || c == '-' || c == '~' || c == '?') 00844 { 00845 xpprintf("leaving function; returning SPF_TRUE\n"); 00846 00847 return(SPF_TRUE); 00848 } 00849 00850 xpprintf("leaving function; returning SPF_FALSE\n"); 00851 00852 return(SPF_FALSE); 00853 } 00854 00855 00856 /* UTIL_is_macro 00857 * 00858 * Author: James Couzens <jcouzens@codeshare.ca> 00859 * 00860 * Date: 01/30/04 00861 * 00862 * Desc: 00863 * s is walked through in search of a macro which consist of 00864 * %{?}, ? being an SPF_UNKNOWN number of chars in between. An instance of 00865 * a macro is searched for. Upon success SPF_TRUE is returned. Upon failure 00866 * to find a macro, SPF_FALSE is returned. 00867 * 00868 */ 00869 SPF_BOOL UTIL_is_macro(const char *s) 00870 { 00871 if (s == NULL) 00872 { 00873 xepprintf("passed a NULL string. Abort!\n"); 00874 00875 return(SPF_FALSE); 00876 } 00877 00878 xvprintf("called with string (%s)\n", s); 00879 00880 while (*s++) 00881 { 00882 if ((*s == '%') && (*(s + 1) == '{')) 00883 { 00884 if (strstr(s, "}")) 00885 { 00886 xpprintf("leaving function; returning SPF_TRUE\n"); 00887 00888 return(SPF_TRUE); 00889 } 00890 } 00891 } 00892 00893 xpprintf("leaving function; returning SPF_FALSE\n"); 00894 00895 return(SPF_FALSE); 00896 } 00897 00898 00899 /* UTIL_mx_cmp 00900 * 00901 * Author: James Couzens <jcouzens@codeshare.ca> 00902 * 00903 * Date: 01/02/04 00904 * 00905 * Desc: 00906 * Using the domain name found in the passed peer_info 00907 * structure, the associated T_MX records are looked up and then their 00908 * respective hostnames resolved (if they happen to be IP addresses the 00909 * resolver library takes care of this. <3). Each IP is compared 00910 * against the remote peer's IP (from peer_info). Upon success returns 00911 * SPF_TRUE, upon failure returns SPF_FALSE. 00912 * 00913 */ 00914 SPF_BOOL UTIL_mx_cmp(peer_info_t *p, const char *s, const int8_t cidr) 00915 { 00916 SPF_BOOL MX_SPF_MATCH; /* true / false */ 00917 00918 char *rr_data = NULL; /* record */ 00919 char *token; /* token for splitting records */ 00920 char *token_ptr; /* working pointer when tokenizing */ 00921 char *peer_ip; /* remote host converted to string */ 00922 00923 00924 MX_SPF_MATCH = SPF_FALSE; 00925 token_ptr = rr_data; 00926 00927 if ((rr_data = DNS_query(p, s, T_MX, NULL)) == NULL) 00928 { 00929 xpprintf("SPF_ERROR parsing DNS Query\n"); 00930 00931 return(SPF_FALSE); 00932 } 00933 00934 xvprintf("rr_data is: (%s)\n", rr_data); 00935 00936 peer_ip = xstrndup(inet_ntoa(p->addr), 16); 00937 token = strtok_r(rr_data, " ", &token_ptr); 00938 00939 while (token != NULL) 00940 { 00941 xvprintf("TOKEN: (%s)\n", token); 00942 00943 if (UTIL_validate_hostname(p, token, cidr) == SPF_TRUE) 00944 { 00945 xvprintf("%s validated via (%s)\n", p->from, token); 00946 00947 MX_SPF_MATCH = SPF_TRUE; 00948 UTIL_assoc_prefix(p, SPF_PASS, NULL); 00949 token = NULL; 00950 } 00951 else 00952 { 00953 token = strtok_r(NULL, " ", &token_ptr); 00954 } 00955 } 00956 00957 xfree(peer_ip); 00958 xfree(rr_data); 00959 00960 return(MX_SPF_MATCH); 00961 } 00962 00963 00964 /* UTIL_a_cmp 00965 * 00966 * Author: James Couzens <jcouzens@codeshare.ca> 00967 * 00968 * Date: 01/02/04 00969 * 00970 * Desc: 00971 * Calls gethostbyname to grab all records associated with a the 00972 * hostname contained within s. On success returns SPF_TRUE, on SPF_ERROR 00973 * returns SPF_FALSE. 00974 * 00975 * Note: 00976 * We need to define and set a limit on the number of recursive 00977 * lookups. I recall seeing this in the RFC, we should discuss this. 00978 * 00979 */ 00980 SPF_BOOL UTIL_a_cmp(peer_info_t *p, const char *s, const int8_t cidr) 00981 { 00982 int16_t pos; /* position in DNS packet */ 00983 00984 int tmp_errno = 0; /* temporary errno placeholder */ 00985 00986 size_t s_len; /* length of s (hostname) */ 00987 00988 char *rr_data = NULL; /* data storage for DNS query */ 00989 char *token_ptr = NULL; /* token pointer */ 00990 char *gbuf = NULL; /* buf for reentrant gethostbyname call */ 00991 char *copy = NULL; /* copy of s */ 00992 char *cp = NULL; /* pointer to copy of s */ 00993 00994 char **a; 00995 00996 struct hostent *hp = NULL; /* hostent structure */ 00997 struct hostent tmp_hp; /* temporary hostent (xgethostbyname) */ 00998 00999 policy_addr_t policy_addr; /* used during CIDR comparisons */ 01000 01001 01002 if (s == NULL) 01003 { 01004 xepprintf("Passed string is NULL. Abort!.\n"); 01005 01006 return(SPF_FALSE); 01007 } 01008 01009 xvprintf("called with (%s) and cidr: %i\n", s, cidr); 01010 01011 gbuf = xmalloc(SPF_MAX_GHBNR_DBUF); 01012 s_len = strlen(s); 01013 token_ptr = rr_data; 01014 01015 /* we're dealing with a:some.hostname/cidr */ 01016 if ((s_len > 1) && (*(s + 1) == ':')) 01017 { 01018 cp = copy = xstrndup(s, (s_len + 1)); 01019 01020 if (cidr != 32) 01021 { 01022 /* We don't want a netmask, so lets remove it */ 01023 cp[s_len - 3] = '\0'; 01024 } 01025 01026 if ((pos = UTIL_index(cp, ':')) <= 0) 01027 { 01028 xeprintf("ERROR parsing passed mechanism token (%s)\n", cp); 01029 01030 xfree(copy); 01031 xfree(gbuf); 01032 01033 return(SPF_FALSE); 01034 } 01035 01036 /* move passed the mechanism text */ 01037 cp += (pos + 1); 01038 } 01039 else 01040 { 01041 cp = copy = xstrndup(p->current_domain, SPF_MAX_HNAME); 01042 } 01043 01044 if ((hp = xgethostbyname(cp, &tmp_hp, gbuf, SPF_MAX_GHBNR_DBUF, 01045 &tmp_errno)) != NULL) 01046 { 01047 for (a = hp->h_addr_list; *a; a++) 01048 { 01049 memcpy(&policy_addr.addr.s_addr, *a, SIZEOF(struct in_addr)); 01050 01051 xvprintf("IN ADDR; Checking: %lu\n", policy_addr.addr.s_addr); 01052 01053 /* cidr is assumed checked by the calling function! */ 01054 policy_addr.cidr = cidr; 01055 01056 if (UTIL_cidr_cmp(&policy_addr, &p->addr) == SPF_TRUE) 01057 { 01058 *a = NULL; 01059 01060 UTIL_assoc_prefix(p, SPF_PASS, NULL); 01061 01062 xfree(copy); 01063 xfree(gbuf); 01064 01065 xgethostbyname_free(); /* unlock mutex */ 01066 01067 return(SPF_TRUE); 01068 } 01069 } /* for */ 01070 01071 for (a = hp->h_aliases; *a; a++) 01072 { 01073 memcpy(&policy_addr.addr.s_addr, *a, SIZEOF(struct in_addr)); 01074 01075 xvprintf("IN CNAME; Checking: %lu\n", policy_addr.addr.s_addr); 01076 01077 /* cidr is assumed checked by the calling function! */ 01078 policy_addr.cidr = cidr; 01079 01080 if (UTIL_cidr_cmp(&policy_addr, &p->addr) == SPF_TRUE) 01081 { 01082 *a = NULL; 01083 01084 UTIL_assoc_prefix(p, SPF_PASS, NULL); 01085 01086 xfree(copy); 01087 xfree(gbuf); 01088 01089 xgethostbyname_free(); /* unlock mutex */ 01090 01091 return(SPF_TRUE); 01092 } 01093 } /* for */ 01094 } /* if .. xgethostbyname */ 01095 else 01096 { 01097 xvprintf("No address associated with hostname (%s); Reason: %s\n", 01098 s, hstrerror(tmp_errno)); 01099 } 01100 01101 xfree(copy); 01102 xfree(gbuf); 01103 01104 xgethostbyname_free(); 01105 01106 return(SPF_FALSE); 01107 } 01108 01109 01110 /* UTIL_ptr_cmp 01111 * 01112 * Author: James Couzens <jcouzens@codeshare.ca> 01113 * 01114 * Date: 01/08/04 01115 * 01116 * Desc: 01117 * gethostbyaddr is broken in linux. ?->h_aliases is not NULL, 01118 * however, it doesn't contain any valid pointers either. It grabs the 01119 * first (and of course this is random) hostname it gets and thats all. 01120 * As tested in FreeBSD however this call works. At any rate, I've 01121 * written a function to deal with this called DNS_ptr_answer. From here 01122 * that function is called which handles the reverse lookups and then 01123 * attempts to "validate" each returned hostname by in turn looking it up 01124 * to confirm if the ip address SPF_MATCHes. Returns SPF_TRUE on succes, and SPF_FALSE 01125 * on failure. 01126 * 01127 * When passed SPF_TRUE copies into p->ptr_mhost, when SPF_FALSE copies 01128 * into p->r_vhname 01129 * 01130 * Note: 01131 * We need to define and set a limit on the number of recursive 01132 * lookups. I recall seeing this in the RFC, we should discuss this. 01133 * 01134 */ 01135 SPF_BOOL UTIL_ptr_cmp(peer_info_t *p, const char *s) 01136 { 01137 char *ptr_addr; /* reversed address into PTR format */ 01138 char *tmp_ptr; /* utility pointer */ 01139 01140 01141 if (s == NULL) 01142 { 01143 xepprintf("Passed string is NULL. Abort!\n"); 01144 01145 return(SPF_FALSE); 01146 } 01147 01148 xvprintf("called with (%s)\n", s); 01149 01150 /* reverse of rpeer */ 01151 ptr_addr = UTIL_rev_addr(p->r_ip); 01152 01153 xvprintf("address: %s\n", ptr_addr); 01154 01155 if ((s = strstr(s, ":")) != NULL) 01156 { 01157 s++; 01158 tmp_ptr = xstrndup(s, (strlen(s) + 1)); 01159 } 01160 else 01161 { 01162 tmp_ptr = xstrndup(p->current_domain, SPF_MAX_HNAME); 01163 } 01164 01165 if (DNS_query(p, ptr_addr, T_PTR, tmp_ptr) != (char *)SPF_TRUE) 01166 { 01167 xvprintf("Failed to pass SPF PTR mechanism check:%s\n", ""); 01168 xvprintf("the domain pointed to by %s is not a valid subdomain of %s\n", 01169 ptr_addr, tmp_ptr); 01170 01171 xfree(ptr_addr); 01172 xfree(tmp_ptr); 01173 01174 return(SPF_FALSE); 01175 } 01176 01177 xvprintf("PTR lookup succeeded: (%s):(%s)\n", p->rs, 01178 p->error); 01179 01180 xfree(ptr_addr); 01181 xfree(tmp_ptr); 01182 01183 return(SPF_TRUE); 01184 } 01185 01186 01187 /* UTIL_get_policy_mech 01188 * 01189 * Author: James Couzens <jcouzens@codeshare.ca> 01190 * 01191 * Date: 12/19/03 01192 * 01193 * Desc: 01194 * Examins s and attempts to determine which SPF_MECHANISM 01195 * enumeration the string SPF_MATCHes based on its conent. 01196 * 01197 */ 01198 SPF_MECHANISM UTIL_get_policy_mech(const char *s) 01199 { 01200 if (s == NULL || !s) 01201 { 01202 xepprintf("passed a NULL string. Abort!\n"); 01203 01204 return(NO_POLICY); 01205 } 01206 01207 xvprintf("called with: (%s)\n", s); 01208 01209 if (strncmp(s, "v=", 2) == 0) 01210 { 01211 xvprintf("leaving function; returning %i (VERSION)\n", VERSION); 01212 01213 return(VERSION); 01214 } 01215 else if (strncmp(s, "ip4:", 4) == 0 ) 01216 { 01217 xvprintf("leaving function; returning %i (IP4)\n", IP4); 01218 01219 return(IP4); 01220 } 01221 else if (strncmp(s, "ip6:", 4) == 0) 01222 { 01223 xvprintf("leaving function; returning %i (IP6)\n", IP6); 01224 01225 return(IP6); 01226 } 01227 else if (strncmp(s, "all", 3) == 0) 01228 { 01229 xvprintf("leaving function; returning %i (ALL)\n", ALL); 01230 01231 return(ALL); 01232 } 01233 else if (strncmp(s, "mx", 2) == 0) 01234 { 01235 xvprintf("leaving function; returning %i (MX)\n", MX); 01236 01237 return(MX); 01238 } 01239 else if (strncmp(s, "a:", 2) == 0 || (*s == 'a' && *(s + 1) == '/') 01240 || ((*s == 'a') && !*(s + 1))) 01241 { 01242 xvprintf("leaving function; returning %i (A)\n", A); 01243 01244 return(A); 01245 } 01246 else if (strncmp(s, "ptr", 3) == 0) 01247 { 01248 xvprintf("leaving function; returning %i (PTR)\n", PTR); 01249 01250 return(PTR); 01251 } 01252 else if (strncmp(s, "include:", 7) == 0) 01253 { 01254 xvprintf("leaving function; returning %i (INCLUDE)\n", INCLUDE); 01255 01256 return(INCLUDE); 01257 } 01258 else if (strncmp(s, "exists:", 6) == 0) 01259 { 01260 xvprintf("leaving function; returning %i (EXISTS)\n", EXISTS); 01261 01262 return(EXISTS); 01263 } 01264 else if (strncmp(s, "redirect=", 9) == 0) 01265 { 01266 xvprintf("leaving function; returning %i (REDIRECT)\n", REDIRECT); 01267 01268 return(REDIRECT); 01269 } 01270 else if (strncmp(s, "exp=", 3) == 0) 01271 { 01272 xvprintf("leaving function; returning %i (EXPLAIN)\n", EXPLAIN); 01273 01274 return(EXPLAIN); 01275 } 01276 else if (strncmp(s, "default", 7) == 0) 01277 { 01278 xvprintf("leaving function; returning %i (DEFAULT)\n", DEFAULT); 01279 01280 return(DEFAULT); 01281 } 01282 else if (strstr(s, ":")) 01283 { 01284 xvprintf("leaving function; returning %i (UNMECH)\n", UNMECH); 01285 01286 return(UNMECH); 01287 } 01288 01289 xpprintf("leaving function; returning NO_POLICY\n"); 01290 return(NO_POLICY); 01291 } 01292 01293 01294 /* UTIL_assoc_prefix 01295 * 01296 * Author: James Couzens <jcouzens@codeshare.ca> 01297 * 01298 * Date: 01/28/04 01299 * 01300 * Desc: 01301 * Examins s and attempts to determine which SPF_MECHANISM_PREFIX 01302 * enumeration the string SPF_MATCHes based on the its contents (which is a 01303 * single char. Upon a SPF_PASS it stores the appropriate value inside of 01304 * the passed peer_info structure. SPF_TRUE upon success, SPF_FALSE upon failure. 01305 * Also upon failure SPF_ERROR (SPF_RESULT_TYPE) is stored in peer_info. 01306 * 01307 * 01308 */ 01309 SPF_BOOL UTIL_assoc_prefix(peer_info_t *p, SPF_RESULT res, const char *s) 01310 { 01311 int16_t pos; /* position in s string */ 01312 01313 01314 /* 01315 * for whatever result happens to match the case, a debug string is 01316 * printed (if compiled with), the level of recursion is made known through 01317 * this. An appropriate SPF_RESULT is assigned to the passed peer_info_t 01318 * structure's 'p->RES' variable. In addition a short SPF_RESULT string 01319 * (here is an example use of the spf_result_t structure spoke of in SPF_init) 01320 * is stored in 'p->rs', and finally an error string is stored in 01321 * 'p->error'. This string encompasses all SPF query return types though, 01322 * it is not only populated upon a parse error, so don't hesitate to reference 01323 * it when looking for a verbose explanation as to the result of an SPF parse. 01324 */ 01325 01326 if (s != NULL) 01327 { 01328 xvprintf("Entering function (%i) (%s)\n", res, s); 01329 01330 /* support for old school deprecated mechanism "default" */ 01331 if (strncmp(s, "default", 7) == 0 && (pos = UTIL_index(s, '=')) > 0) 01332 { 01333 s += (pos + 1); /* move past default= */ 01334 if (strncmp(s, "deny", 4) == 0) 01335 { 01336 xvprintf("Stored SPF_H_FAIL (%i) (%i)\n", 01337 res, SPF_H_FAIL); 01338 01339 p->RES = SPF_H_FAIL; 01340 p->rs = p->spf_result[SPF_H_FAIL].s; 01341 01342 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01343 p->rs, p->last_m); 01344 01345 return(SPF_TRUE); 01346 } 01347 else if (strncmp(s, "pass", 4) == 0) 01348 { 01349 xvprintf("Stored SPF_PASS (%i) (%i)\n", 01350 res, SPF_PASS); 01351 01352 p->RES = SPF_PASS; 01353 p->rs = p->spf_result[SPF_PASS].s; 01354 01355 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01356 p->rs, p->last_m); 01357 01358 return(SPF_TRUE); 01359 } 01360 else if (strncmp(s, "softdeny", 8) == 0) 01361 { 01362 xvprintf("Stored SPF_S_FAIL (%i) (%i)\n", 01363 res, SPF_S_FAIL); 01364 01365 p->RES = SPF_S_FAIL; 01366 p->rs = p->spf_result[SPF_S_FAIL].s; 01367 01368 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01369 p->rs, p->last_m); 01370 01371 return(SPF_TRUE); 01372 } 01373 else if (strncmp(s, "unknown", 7) == 0) 01374 { 01375 xvprintf("Stored SPF_NEUTRAL (%i) (%i)\n", 01376 res, SPF_NEUTRAL); 01377 01378 p->RES = SPF_NEUTRAL; 01379 p->rs = p->spf_result[SPF_NEUTRAL].s; 01380 01381 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01382 p->rs, p->last_m); 01383 01384 return(SPF_TRUE); 01385 } 01386 else if (strncmp(s, "include", 7) == 0) 01387 { 01388 xvprintf("Stored SPF_UNKNOWN (%i) (%i)\n", 01389 res, SPF_UNKNOWN); 01390 01391 p->RES = SPF_UNKNOWN; 01392 p->rs = p->spf_result[SPF_UNKNOWN].s; 01393 01394 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01395 p->rs, p->last_m); 01396 01397 return(SPF_TRUE); 01398 } 01399 else 01400 { 01401 xvprintf("Stored SPF_ERROR (%i) (%i)\n", 01402 res, SPF_ERROR); 01403 01404 p->RES = SPF_UNKNOWN; 01405 p->rs = p->spf_result[SPF_UNKNOWN].s; 01406 01407 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01408 p->rs, p->last_m); 01409 01410 return(SPF_FALSE); 01411 } 01412 } 01413 } 01414 01415 switch (res) 01416 { 01417 01418 /* */ 01419 case SPF_PASS: 01420 xvprintf("Stored SPF_PASS (%i) (%i)\n", 01421 res, SPF_PASS); 01422 01423 p->RES = SPF_PASS; 01424 p->rs = p->spf_result[SPF_PASS].s; 01425 01426 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01427 p->rs, p->last_m); 01428 01429 return(SPF_TRUE); 01430 01431 /* */ 01432 case SPF_NONE: 01433 xvprintf("Stored SPF_NONE (%i) (%i)\n", 01434 res, SPF_NONE); 01435 01436 p->RES = SPF_NONE; 01437 p->rs = p->spf_result[SPF_NONE].s; 01438 01439 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01440 p->rs, p->last_m); 01441 01442 return(SPF_TRUE); 01443 01444 /* */ 01445 case SPF_S_FAIL: 01446 xvprintf("Stored SPF_S_FAIL (%i) (%i)\n", 01447 res, SPF_S_FAIL); 01448 01449 p->RES = SPF_S_FAIL; 01450 p->rs = p->spf_result[SPF_S_FAIL].s; 01451 01452 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01453 p->rs, p->last_m); 01454 01455 return(SPF_TRUE); 01456 01457 /* */ 01458 case SPF_H_FAIL: 01459 xvprintf("Stored SPF_H_FAIL (%i) (%i)\n", 01460 res, SPF_H_FAIL); 01461 01462 p->RES = SPF_H_FAIL; 01463 p->rs = p->spf_result[SPF_H_FAIL].s; 01464 01465 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01466 p->rs, p->last_m); 01467 01468 return(SPF_TRUE); 01469 01470 /* */ 01471 case SPF_NEUTRAL: 01472 xvprintf("Stored SPF_NEUTRAL (%i) (%i)\n", 01473 res, SPF_NEUTRAL); 01474 01475 p->RES = SPF_NEUTRAL; 01476 p->rs = p->spf_result[SPF_NEUTRAL].s; 01477 01478 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01479 p->rs, p->last_m); 01480 01481 return(SPF_TRUE); 01482 01483 /* */ 01484 case SPF_UNKNOWN: 01485 xvprintf("Stored SPF_UNKNOWN (%i) (%i)\n", 01486 res, SPF_UNKNOWN); 01487 01488 p->RES = SPF_UNKNOWN; 01489 p->rs = p->spf_result[SPF_UNKNOWN].s; 01490 01491 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01492 p->rs, p->last_m); 01493 01494 return(SPF_TRUE); 01495 01496 /* */ 01497 case SPF_ERROR: 01498 xvprintf("Stored SPF_ERROR (%i) (%i)\n", 01499 p, SPF_ERROR); 01500 01501 p->RES = SPF_ERROR; 01502 p->rs = p->spf_result[SPF_ERROR].s; 01503 01504 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01505 p->rs, p->last_m); 01506 01507 return(SPF_TRUE); 01508 01509 /* */ 01510 case SPF_UNMECH: 01511 xvprintf("Stored SPF_UNMECH (%i) (%i)\n", 01512 res, SPF_UNMECH); 01513 01514 p->RES = SPF_UNMECH; 01515 p->rs = p->spf_result[SPF_UNMECH].s; 01516 01517 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01518 p->rs, p->last_m); 01519 01520 return(SPF_TRUE); 01521 01522 /* */ 01523 default: 01524 xvprintf("Stored SPF_PASS (%i) (%i)\n", 01525 res, SPF_PASS); 01526 01527 p->RES = SPF_PASS; 01528 p->rs = p->spf_result[SPF_PASS].s; 01529 01530 snprintf(p->error, SPF_MAX_ERROR, "policy result: (%s) from rule (%s)", 01531 p->rs, p->last_m); 01532 01533 return(SPF_TRUE); 01534 } 01535 01536 xepprintf("leaving function; returning SPF_FALSE.\n"); 01537 01538 return(SPF_FALSE); 01539 } 01540 01541 01542 /* UTIL_get_mech_prefix 01543 * 01544 * Author: James Couzens <jcouzens@codeshare.ca> 01545 * 01546 * Date: 12/31/03 01547 * 01548 * Desc: 01549 * Examins s and attempts to determine which SPF_RESULT_P 01550 * enumeration the string SPF_MATCHes based on the its contents (which is a 01551 * single char. Returns SPF_PASS if a valid prefix is not specified. 01552 * Valid prefixes are: + (permit), - (deny), ~ (softfail) and ? (SPF_NEUTRAL). 01553 * 01554 */ 01555 SPF_RESULT UTIL_get_mech_prefix(peer_info_t *p, const char *s) 01556 { 01557 int16_t pos; /* position in s */ 01558 01559 01560 if (s == NULL) 01561 { 01562 xepprintf("passed a NULL string. Abort!\n"); 01563 01564 return(SPF_ERROR); 01565 } 01566 01567 xprintf("called with char: (%s)\n", s); 01568 snprintf(p->last_m, SPF_MAX_HNAME, "%s", s); 01569 01570 switch (*s) 01571 { 01572 01573 /* */ 01574 case '+': 01575 p->RES_P = SPF_PASS; 01576 xvprintf("leaving function; returning SPF_PASS (%s) %i\n", 01577 s, SPF_PASS); 01578 01579 return(SPF_PASS); 01580 01581 01582 /* */ 01583 case '-': 01584 p->RES_P = SPF_H_FAIL; 01585 xvprintf("leaving function; returning SPF_H_FAIL (%s) %i\n", 01586 s, SPF_H_FAIL); 01587 01588 return(SPF_H_FAIL); 01589 01590 /* */ 01591 case '?': 01592 p->RES_P = SPF_NEUTRAL; 01593 xvprintf("leaving function; returning SPF_NEUTRAL (%s) %i\n", 01594 s, SPF_NEUTRAL); 01595 01596 return(SPF_NEUTRAL); 01597 01598 /* */ 01599 case '~': 01600 p->RES_P = SPF_S_FAIL; 01601 xvprintf("leaving function; returning SPF_S_FAIL (%s) %i\n", 01602 s, SPF_S_FAIL); 01603 01604 return(SPF_S_FAIL); 01605 01606 /* */ 01607 default: 01608 if (p->ALL == SPF_TRUE) 01609 { 01610 p->RES_P = SPF_NEUTRAL; 01611 xvprintf("leaving function; returning (def) SPF_NEUTRAL (%s) %i\n", 01612 s, SPF_NEUTRAL); 01613 } 01614 else 01615 { 01616 p->RES_P = SPF_PASS; 01617 xvprintf("leaving function; returning (def) SPF_PASS (%s) %i\n", 01618 s, SPF_PASS); 01619 } 01620 01621 xvprintf("leaving function; returning (%i)\n", p->RES_P); 01622 01623 return(p->RES_P); 01624 } /* switch */ 01625 01626 /* 01627 * The code in the following statement is for the 01628 * deprecated mechanism "default" and is only here to attempt 01629 * to support exceptionally tardy early adopters whom likely 01630 * at this time no longer exist. As such this code is not 01631 * present in the current development versions of this library 01632 */ 01633 if ((pos = UTIL_index(s, '=')) > 0) 01634 { 01635 s += (pos + 1); /* move past default= */ 01636 01637 if (strncmp(s, "deny", 4) == 0) 01638 { 01639 p->RES_P = SPF_H_FAIL; 01640 xvprintf("leaving function; returning SPF_H_FAIL on (%s)\n", s); 01641 01642 return(SPF_H_FAIL); 01643 } 01644 else if (strncmp(s, "pass", 4) == 0) 01645 { 01646 p->RES_P = SPF_PASS; 01647 xvprintf("leaving function; returning SPF_PASS on (%s)\n", s); 01648 01649 return(SPF_PASS); 01650 } 01651 else if (strncmp(s, "softdeny", 8) == 0) 01652 { 01653 p->RES_P = SPF_S_FAIL; 01654 xvprintf("leaving function; returning SPF_S_FAIL on (%s)\n", s); 01655 01656 return(SPF_S_FAIL); 01657 } 01658 else if (strncmp(s, "unknown", 7) == 0) 01659 { 01660 p->RES_P = SPF_NEUTRAL; 01661 xvprintf("leaving function; returning SPF_NEUTRAL on (%s)\n", s); 01662 01663 return(SPF_NEUTRAL); 01664 } 01665 else 01666 { 01667 xvprintf("leaving function; returning SPF_NEUTRAL on (%s)\n", s); 01668 01669 return(SPF_NEUTRAL); 01670 } 01671 } 01672 01673 xvprintf("leaving function; returning SPF_ERROR on (%s)\n", s); 01674 01675 return(SPF_ERROR); 01676 } 01677 01678 01679 /* UTIL_expand_ip 01680 * 01681 * Author: James Couzens <jcouzens@codeshare.ca> 01682 * 01683 * Date: 12/26/03 01684 * 01685 * Desc: 01686 * Expands an ip4 policy mechanism string into a policy_addr_t 01687 * structure which it allocates memory for and then returns. The RFC 01688 * specifies that if a cidr block is not specified then /32 isused. 01689 * 01690 * On success returns a pointer to a policy_addr_t structure, on 01691 * SPF_ERROR returns NULL. 01692 * 01693 */ 01694 policy_addr_t *UTIL_expand_ip(const char *s) 01695 { 01696 int8_t cidr = 0; /* temporary storage for netmask */ 01697 01698 size_t len; /* length of string passed */ 01699 size_t pos; /* position of break points in string */ 01700 01701 char *ip; /* temporary storage for ip address */ 01702 01703 const char *token_ptr; /* our position in the token */ 01704 01705 policy_addr_t *policy_addr; /* ip/mask return structure */ 01706 01707 01708 if (s == NULL) 01709 { 01710 xepprintf("passed a NULL string. Abort!\n"); 01711 01712 return(NULL); 01713 } 01714 01715 len = strlen(s); 01716 token_ptr = s; 01717 01718 xvprintf("called with string: (%s)\n", token_ptr); 01719 01720 if ((pos = UTIL_index(token_ptr, ':')) == 0) 01721 { 01722 xvprintf("SPF_ERROR: Unable to get position on token (%s)\n", 01723 token_ptr); 01724 01725 return(NULL); 01726 } 01727 01728 /* jump past the ip4: portion */ 01729 token_ptr += pos + 1; 01730 01731 policy_addr = xmalloc(SIZEOF(policy_addr_t)); 01732 01733 /* jump past the ip4: portion (to get length of ip) */ 01734 if ((pos = UTIL_index(token_ptr, '/')) == 0) 01735 { 01736 xvprintf("Unable to get position on token (%s), assuming /32 cidr " \ 01737 "block\n", token_ptr); 01738 01739 pos = strlen(token_ptr); 01740 cidr = 32; 01741 } 01742 01743 /* allocate space and dump the ip address there */ 01744 ip = xstrndup(token_ptr, (pos + 1)); 01745 01746 /* copy it over to the policy_addr structure */ 01747 if ((inet_pton(AF_INET, ip, &policy_addr->addr)) == 0) 01748 { 01749 xvprintf("SPF_ERROR: inet_pton unable to convert ip to binary " \ 01750 "(%s)\n", ip); 01751 01752 xfree(ip); 01753 return(NULL); 01754 } 01755 01756 if (cidr != 32) 01757 { 01758 token_ptr += (pos + 1); /* skip over the forward slash */ 01759 cidr = atoi(token_ptr); /* convert the string to an integer */ 01760 } 01761 01762 xfree(ip); 01763 01764 if ((cidr < 0) || (cidr > 32)) 01765 { 01766 xvprintf("ERROR: cidr violation (%u)\n", cidr); 01767 01768 return(NULL); 01769 } 01770 01771 policy_addr->cidr = cidr; /* copy it over to the policy_addr structure */ 01772 01773 xvprintf("CIDR: (%i) IP: (%s)\n", 01774 policy_addr->cidr, inet_ntoa(policy_addr->addr)); 01775 01776 return(policy_addr); 01777 } 01778 01779 01780 /* UTIL_is_ip 01781 * 01782 * Author: James Couzens <jcouzens@codeshare.ca> 01783 * 01784 * Date: 01/18/04 01785 * 01786 * Desc: 01787 * Is the passed string (limited to between 0 - 255 by type) 01788 * contains a valid ip address or not. I'm not sure if this is useful 01789 * anymore but at one point I was using it to tell if the passed macro 01790 * contained an ip address or not when passed as a string. 01791 * 01792 */ 01793 SPF_BOOL UTIL_is_ip(const char *id) 01794 { 01795 u_int8_t i = 0; /* utility */ 01796 01797 if (!id) 01798 { 01799 xepprintf("called without an IP address!\n"); 01800 01801 return(SPF_FALSE); 01802 } 01803 01804 xvprintf("called with address: (%s)\n", id); 01805 01806 while (*id) 01807 { 01808 if (*id == '.') 01809 { 01810 i++; 01811 } 01812 else if (isdigit(*id) == 0) 01813 { 01814 return(SPF_FALSE); 01815 } 01816 id++; 01817 } 01818 01819 if (i == 3) 01820 { 01821 return(SPF_TRUE); 01822 } 01823 01824 xpprintf("leaving function; returning SPF_FALSE\n"); 01825 01826 return(SPF_FALSE); 01827 } 01828 01829 01830 /* UTIL_rev_addr 01831 * 01832 * Author: James Couzens <jcouzens@codeshare.ca> 01833 * 01834 * Date: 01/04/04 01835 * 01836 * Desc: 01837 * Using a passed ip address it will reverse it and slap 01838 * .in-addr.arpa on the end of it making it ready for a proper PTR query 01839 * 01840 * Notes: Write additional code to handle IP6 addresses 01841 * 01842 */ 01843 char *UTIL_rev_addr(const char *s) 01844 { 01845 u_int8_t i = 0; /* utility */ 01846 u_int8_t tmp[4][1]; /* temporary storage for ip integers */ 01847 01848 u_int16_t len = 0; /* length of to be allocated string */ 01849 01850 char *cp; /* copy of passed string */ 01851 char *token; /* token for splitting apart ip address */ 01852 char *new_addr; /* allocate string for reversed address */ 01853 01854 01855 if (s == NULL) 01856 { 01857 xepprintf("passed a null string. Abort!\n"); 01858 01859 return(NULL); 01860 } 01861 01862 len = (strlen(s) + 1); 01863 01864 xprintf("called with: (%s) len: (%i)\n", s, (len - 1)); 01865 01866 cp = xstrndup(s, len); 01867 token = strtok(cp, "."); 01868 01869 while ((token != NULL) && (i <= 3)) 01870 { 01871 xvprintf("token : (%s)\n", token); 01872 01873 tmp[i][0] = atoi(token); 01874 token = strtok(NULL, "."); 01875 i++; 01876 } 01877 01878 xfree(cp); 01879 01880 /* + .in-addr.arpa\0 */ 01881 new_addr = xmalloc(len + 13); 01882 01883 snprintf(new_addr, (len + 13), "%u.%u.%u.%u.in-addr.arpa", 01884 tmp[3][0], tmp[2][0], tmp[1][0], tmp[0][0]); 01885 01886 xvprintf("leaving function; returning reversed ip: %s\n", new_addr); 01887 01888 return(new_addr); 01889 } 01890 01891 01892 /* UTIL_get_dname 01893 * 01894 * Author: James Couzens <jcouzens@codeshare.ca> 01895 * 01896 * Date: 01/27/04 01897 * 01898 * Desc: 01899 * s contains a hostname which is then looked through and split 01900 * apart, always leaving one '.' delimiter left so you are left with 01901 * domain.tld. domain.tld is then put into newly allocated memory and 01902 * returned to the calling function. Upon failure, returns NULL. 01903 * Calling function is required to free the memory. 01904 * 01905 */ 01906 char *UTIL_get_dname(const char *s) 01907 { 01908 u_int8_t i = 0; /* how many delimiters in s */ 01909 01910 char *buf = NULL; /* return string to be allocated */ 01911 01912 01913 if (s == NULL) 01914 { 01915 xepprintf("called with NULL. Abort!\n"); 01916 01917 return(NULL); 01918 } 01919 01920 xvprintf("called with (%s)\n", s); 01921 01922 i = UTIL_count_delim(s, '.'); 01923 01924 switch (i) 01925 { 01926 case 0: 01927 break; 01928 case 1: 01929 buf = xstrndup(s, (strlen(s) + 1)); 01930 xprintf("leaving function; returning buffer: (%s)\n", buf); 01931 01932 return(buf); 01933 default: 01934 buf = UTIL_split_str(s, '.', (i - 1)); 01935 xprintf("leaving function; returning buffer: (%s)\n", buf); 01936 01937 return(buf); 01938 } 01939 01940 xepprintf("leaving function; returning NULL\n"); 01941 01942 return(NULL); 01943 } 01944 01945 01946 /* UTIL_cidr_cmp 01947 * 01948 * Author: James Couzens <jcouzens@codeshare.ca> 01949 * 01950 * Date: 12/26/03 01951 * 01952 * Desc: 01953 * Compares an IP address (connected peer) against another IP 01954 * address (found in a policy lookup) using a netmask (also found from 01955 * a policy lookup) to see if the peer address is legal within that 01956 * netmask. Returns SPF_TRUE if its valid, SPF_FALSE if not. 01957 * 01958 * Notes: Write additional comparisons to handle IP6 addresses 01959 * 01960 */ 01961 SPF_BOOL UTIL_cidr_cmp(const policy_addr_t *policy_addr, const struct in_addr 01962 *peer_addr) 01963 { 01964 u_int32_t a; /* working buf */ 01965 u_int32_t b; /* working buf */ 01966 01967 char *peer_ip = NULL; /* ip address of connected peer */ 01968 char *policy_ip = NULL; /* ip address of current SPF policy */ 01969 01970 01971 if ((policy_addr->addr.s_addr <= 0) && (peer_addr->s_addr <= 0)) 01972 { 01973 xepprintf("Passed with NULL chars. Aborting.\n"); 01974 01975 return(SPF_FALSE); 01976 } 01977 01978 xvprintf("POL: %lu PEER: %lu CIDR: %i\n", policy_addr->addr.s_addr, 01979 peer_addr->s_addr, policy_addr->cidr); 01980 01981 /* 01982 * Packets come in off the wire in whats called "network byte order" 01983 * which does't work very well when trying to compute if one address 01984 * is masked by another using a CIDR calculation so the 'ntohl' is 01985 * issued on them to change their byte order 01986 */ 01987 a = ntohl(peer_addr->s_addr); 01988 b = ntohl(policy_addr->addr.s_addr); 01989 01990 if (policy_addr->cidr != 32) 01991 { 01992 if ((a&(~0U<<(32-policy_addr->cidr))) != (b&(~0U<<(32-policy_addr->cidr)))) 01993 { 01994 return(SPF_FALSE); 01995 } 01996 } 01997 else 01998 { 01999 if (peer_addr->s_addr != policy_addr->addr.s_addr) 02000 { 02001 xvprintf("%lu and %lu using 32 cidr do not match\n", 02002 peer_addr->s_addr, policy_addr->addr.s_addr); 02003 02004 return(SPF_FALSE); 02005 } 02006 } 02007 02008 /* these are done here just for debugger remove later */ 02009 peer_ip = xstrndup(inet_ntoa(*peer_addr), SPF_MAX_IP_ADDR); 02010 policy_ip = xstrndup(inet_ntoa(policy_addr->addr), SPF_MAX_IP_ADDR); 02011 02012 xvprintf("Peer: (%s) matches address %s with network %i\n", 02013 peer_ip, policy_ip, policy_addr->cidr); 02014 02015 xfree(peer_ip); 02016 xfree(policy_ip); 02017 02018 return(SPF_TRUE); 02019 } 02020 02021 02022 /* UTIL_validate_ptr 02023 * 02024 * Author: James Couzens <jcouzens@codeshare.ca> 02025 * 02026 * Date: 12/26/03 02027 * 02028 * Desc: 02029 * Using the ip address found in the passed peer_info structure, 02030 * a PTR lookup is made and if a record exists then this is record is compared 02031 * against the hostname the client wishes to send mail from. If the tld matches 02032 * the tld found during this query, this would be a 'valdiated' PTR. If a match 02033 * can not be found we return SPF_FALSE. If a match is made we return SPF_TRUE. 02034 * 02035 * Notes: Write additional comparisons to handle IP6 addresses 02036 * 02037 */ 02038 SPF_BOOL UTIL_validate_ptr(peer_info_t *p) 02039 { 02040 char *ptr_addr; /* reversed address into PTR format */ 02041 char *tmp_ptr; /* utility pointer */ 02042 02043 02044 if (!p) 02045 { 02046 xepprintf("called with an invalid peer info structure!\n"); 02047 02048 return(SPF_FALSE); 02049 } 02050 02051 /* reverse of the address in peer_info */ 02052 ptr_addr = UTIL_rev_addr(p->r_ip); 02053 xvprintf("[address: %s]\n", ptr_addr); 02054 02055 tmp_ptr = xstrndup(p->current_domain, SPF_MAX_HNAME); 02056 02057 if (DNS_query(p, ptr_addr, T_PTR, tmp_ptr) != (char *)SPF_TRUE) 02058 { 02059 xvprintf("PTR lookup failed: (%s) (%s)\n", p->rs, p->error); 02060 02061 xfree(ptr_addr); 02062 xfree(tmp_ptr); 02063 02064 return(SPF_FALSE); 02065 } 02066 02067 xvprintf("Peer (%s) successfully validated hostname (%s)\n", 02068 p->r_ip, p->r_vhname); 02069 02070 xfree(ptr_addr); 02071 xfree(tmp_ptr); 02072 02073 return(SPF_TRUE); 02074 } 02075 02076 02077 /* UTIL_validate_hostname 02078 * 02079 * Author: James Couzens <jcouzens@codeshare.ca> 02080 * 02081 * Date: 01/08/04 02082 * 02083 * Desc: 02084 * s contains a hostname which is then looked up to find any 02085 * of the returned ip addresses SPF_PASS the remote peers. On a successful 02086 * SPF_PASS returns SPF_TRUE. When no SPF_PASS is made, returns SPF_FALSE. 02087 * 02088 * Note: 02089 * We need to define and set a limit on the number of recursive 02090 * lookups. I recall seeing this in the RFC, we should discuss this. 02091 * 02092 * Date: 08/28/04 by James 02093 * 02094 * Desc: 02095 * Added buffer for reentrant gethostbyname wrapper 02096 * and change gethostbyname calls to use the MACRO wrapper 02097 * xgethostbyname() 02098 * 02099 */ 02100 SPF_BOOL UTIL_validate_hostname(peer_info_t *p, const char *s, const int8_t cidr) 02101 { 02102 int tmp_errno = 0; /* temporary errno placeholder */ 02103 02104 char **a = NULL; /* work ptr for list recursion */ 02105 02106 char *ip = NULL; /* ip address */ 02107 char *gbuf = NULL; /* reentrant buffer for gethostbyname_r */ 02108 02109 struct in_addr addr; /* connected peer's address */ 02110 struct hostent *hp = NULL; /* hostent structure */ 02111 struct hostent tmp_hp; /* temporary hostent structure */ 02112 02113 policy_addr_t policy_addr; /* used for cidr calculations */ 02114 02115 02116 if (s == NULL) 02117 { 02118 xepprintf("passed a NULL string.\n"); 02119 02120 return(SPF_FALSE); 02121 } 02122 02123 xvprintf("called with: (%lu) and (%s)\n", p->r_ip, s); 02124 02125 gbuf = xmalloc(SPF_MAX_GHBNR_DBUF); 02126 02127 if ((hp = xgethostbyname(s, &tmp_hp, gbuf, SPF_MAX_GHBNR_DBUF, 02128 &tmp_errno)) != NULL) 02129 { 02130 /* for each hostname in the list, perform CIDR checks */ 02131 for (a = hp->h_addr_list; *a; a++) 02132 { 02133 memcpy(&addr.s_addr, *a, SIZEOF(struct in_addr)); 02134 ip = xstrndup(inet_ntoa(addr), SPF_MAX_IP_ADDR); 02135 02136 xvprintf("CLI: %s (%lu) SRV: %s (%lu)\n", ip, addr.s_addr, 02137 p->r_ip, p->addr.s_addr); 02138 02139 if (cidr == 32) 02140 { 02141 if (((struct in_addr *)(*a))->s_addr == p->addr.s_addr) 02142 { 02143 xvprintf("%s (%lu) matches %s (%lu)\n", ip, 02144 ((struct in_addr *)(*a))->s_addr, p->r_ip, p->addr.s_addr); 02145 02146 UTIL_assoc_prefix(p, SPF_PASS, NULL); 02147 02148 xfree(ip); 02149 xfree(gbuf); 02150 02151 xgethostbyname_free(); /* unlock mutex */ 02152 02153 return(SPF_TRUE); 02154 } 02155 } 02156 else if ((cidr < 32) && (cidr >= 8)) 02157 { 02158 /* convert from character string to dotted quad notation */ 02159 if ((inet_pton(AF_INET, ip, &policy_addr.addr)) == 0) 02160 { 02161 xepprintf("Unable to execute inet_pton()\n"); 02162 } 02163 02164 policy_addr.cidr = cidr; 02165 02166 xvprintf("Address: %lu with CIDR %i\n", 02167 policy_addr.addr.s_addr, policy_addr.cidr); 02168 02169 /* perform CIDR comparison of 'policy_addr' vs 'p->addr' */ 02170 if ((UTIL_cidr_cmp(&policy_addr, &p->addr)) == SPF_TRUE) 02171 { 02172 xvprintf("(%lu) matches (%lu) with CIDR %u\n", 02173 policy_addr.addr.s_addr, p->addr.s_addr, cidr); 02174 02175 /* associate an SPF prefix (-,+,~,?) with this check */ 02176 UTIL_assoc_prefix(p, SPF_PASS, NULL); 02177 02178 xfree(ip); 02179 xfree(gbuf); 02180 02181 xgethostbyname_free(); 02182 02183 return(SPF_TRUE); 02184 } 02185 } /* else if */ 02186 02187 xfree(ip); 02188 02189 } /* for */ 02190 02191 /* for each alias (CNAME) perform a CIDR check */ 02192 for (a = hp->h_aliases; *a; a++) 02193 { 02194 memcpy(&addr.s_addr, *a, SIZEOF(struct in_addr)); 02195 ip = xstrndup(inet_ntoa(addr), SPF_MAX_IP_ADDR); 02196 02197 xvprintf("client: %s (%lu); policy: %s (%lu)\n", 02198 ip, addr.s_addr, p->r_ip, p->addr.s_addr); 02199 02200 if (cidr == 32) 02201 { 02202 if (((struct in_addr *)(*a))->s_addr == p->addr.s_addr) 02203 { 02204 xvprintf("IN A: client: %s (%lu) matches policy: %s (%lu)\n", 02205 ip, ((struct in_addr *)(*a))->s_addr, p->r_ip, p->addr.s_addr); 02206 02207 xfree(ip); 02208 xfree(gbuf); 02209 02210 return(SPF_TRUE); 02211 } 02212 } 02213 else if ((cidr < 32) && (cidr >= 8)) 02214 { 02215 if (inet_pton(AF_INET, ip, &policy_addr.addr) == 0) 02216 { 02217 xepprintf("Unable to execute inet_pton()\n"); 02218 } 02219 02220 policy_addr.cidr = cidr; 02221 02222 if (UTIL_cidr_cmp(&policy_addr, &p->addr) == SPF_TRUE) 02223 { 02224 xvprintf("client: (%lu) matches policy (%lu) with CIDR %u\n", 02225 policy_addr.addr.s_addr, p->addr.s_addr, cidr); 02226 02227 xfree(ip); 02228 xfree(gbuf); 02229 02230 /* associate an SPF prefix (-,+,~,?) with this check */ 02231 UTIL_assoc_prefix(p, SPF_PASS, NULL); 02232 02233 return(SPF_TRUE); 02234 } 02235 } /* else */ 02236 02237 xfree(ip); 02238 02239 } /* for */ 02240 } /* if .. xgethostbyname() */ 02241 else 02242 { 02243 xvprintf("No address associated with hostname (%s); Reason: %s\n", 02244 s, hstrerror(tmp_errno)); 02245 } 02246 02247 xfree(gbuf); 02248 02249 xgethostbyname_free(); 02250 02251 xpprintf("leaving function; returning SPF_FALSE\n"); 02252 02253 return(SPF_FALSE); 02254 } 02255 02256 02257 /* UTIL_url_encode 02258 * 02259 * Author: Sean Comeau <scomeau@obscurity.org> 02260 * 02261 * Date: 01/06/04 02262 * 02263 * Desc: 02264 * "URL-Encode" characters that are "unsafe" or "prohibited" from a URL. 02265 * Upon success returns a pointer to a newly allocated memory containing the 02266 * encoded string. Upon failure returns a NULL pointer. Failure 02267 * indicates either a failure to allocate new memory, or the passed string 02268 * did not contain any questionable characters and hence did not require 02269 * encoding. 02270 * 02271 */ 02272 char *UTIL_url_encode(const char *s) 02273 { 02274 int len; /* length of passed string * 3*/ 02275 02276 char *new; /* newly allocated memory */ 02277 char *encoded; /* encoded return string */ 02278 02279 02280 if (s != NULL) 02281 { 02282 /* 02283 * length of the string times 3 is the maximum possible size a 02284 * URL encoded string should ever be able to expand to. 02285 */ 02286 len = (strlen(s) * 3); 02287 } 02288 else 02289 { 02290 xepprintf("passed a NULL string. Abort!\n"); 02291 02292 return(NULL); 02293 } 02294 02295 encoded = new = xmalloc(len); 02296 02297 while (*s != '\0') 02298 { 02299 if (urlchr_test(*s) == 0) 02300 { 02301 *new++ = *s++; 02302 } 02303 else 02304 { 02305 /* this obviously NULL terminates, do we want this? */ 02306 snprintf(new, 4, "%%%x", *s); 02307 new += 3; 02308 s++; 02309 } 02310 } 02311 02312 *new++ = '\0'; 02313 xvprintf("leaving function; returning (%s)\n", encoded); 02314 02315 return(encoded); 02316 } 02317 02318 02319 /* UTIL_reverse 02320 * 02321 * Author: James Couzens <jcouzens@codeshare.ca> 02322 * 02323 * Date: 01/06/04 02324 * 02325 * Desc: 02326 * Takes a string and rebuilds it in reverse order using the 02327 * supplied delimiter. The string will always be rebuilt using a 02328 * '.' char as per the RFC. 02329 * 02330 */ 02331 char *UTIL_reverse(const char *s, const char delim) 02332 { 02333 size_t len; /* length of s */ 02334 02335 char *buf; /* return buffer */ 02336 char *p; /* working pointer */ 02337 char *cp; /* working pointer */ 02338 char *c; /* working pointer */ 02339 02340 split_str_t *master; /* list pointers */ 02341 02342 split_str_node_t *c_node; /* c_node node */ 02343 split_str_node_t *kill_node; /* temp node used in destruction */ 02344 02345 02346 if (s == NULL) 02347 { 02348 xepprintf("passed a NULL string. Abort!\n"); 02349 02350 return(NULL); 02351 } 02352 02353 xvprintf("called with (%s) and delim (%c)\n", s, delim); 02354 02355 len = strlen(s); 02356 cp = c = xstrndup(s, (len + 1)); 02357 02358 master = xmalloc(SIZEOF(split_str_t)); 02359 master->head = NULL; 02360 master->tail = NULL; 02361 master->elements = 0; 02362 02363 /* 02364 * Comment: James Couzens <jcouzens@codeshare.ca> 02365 * 02366 * Date: 01/22/04 02367 * 02368 * we do not want the trailing delim so the first iteration of this 02369 * loop we call UTIL_addnode with 0, which tells it not to allocate 02370 * the extra byte for the trailing delimiter. This is done only 02371 * when passed an IP address, and this is because when reversing we 02372 * want: 1.0.168.192. and not .1.0.168.192 02373 * 02374 */ 02375 02376 len++; 02377 buf = xmalloc(len); 02378 while ((p = strrchr(cp, delim)) != NULL) 02379 { 02380 p++; /* remove period */ 02381 UTIL_addnode(master, p, SPF_TRUE); 02382 p--; /* bring it back */ 02383 *p = '\0'; 02384 } 02385 02386 UTIL_addnode(master, cp, SPF_FALSE); 02387 02388 c_node = master->head; 02389 while ((kill_node = c_node) != NULL) 02390 { 02391 strncat(buf, kill_node->s, kill_node->len); 02392 xfree(kill_node->s); 02393 c_node = c_node->next; 02394 xfree(kill_node); 02395 } 02396 02397 xfree(cp); 02398 xfree(master); 02399 02400 xvprintf("leaving function; returning (%s)\n", buf); 02401 02402 return(buf); 02403 } 02404 02405 02406 /* UTIL_addnode 02407 * 02408 * Author: James Couzens <jcouzens@codeshare.ca> 02409 * 02410 * Date: 01/18/04 02411 * 02412 * Desc: 02413 * Allocates memory for a new node and slaps it on the end of 02414 * of the passed list. In the process of doing so, when it comes to 02415 * the last element in the list, which is indicated by the SPF_BOOL 02416 * that is passed, a final '.' is either appended (SPF_TRUE) or not 02417 * (SPF_FALSE). Function returns SPF_TRUE upon success, and SPF_FALSE upon 02418 * failure. 02419 * 02420 */ 02421 SPF_BOOL UTIL_addnode(split_str_t *master, const char *s, SPF_BOOL last) 02422 { 02423 size_t len; /* length of s */ 02424 02425 split_str_node_t *c_node; /* c_node working node */ 02426 split_str_node_t *new_node; /* newly allocated node */ 02427 split_str_node_t *prev_node; /* previous working node */ 02428 02429 02430 if (!s || (s == NULL)) 02431 { 02432 xepprintf("passed a NULL string. Abort!\n"); 02433 02434 return(SPF_FALSE); 02435 } 02436 02437 xvprintf("called with string: (%s); boolean: (%s)\n", s, 02438 last ? "FALSE" : "TRUE"); 02439 02440 len = strlen(s); 02441 02442 if (last == SPF_TRUE) 02443 { 02444 len += 2; 02445 } 02446 else 02447 { 02448 len++; 02449 } 02450 02451 /* create new node */ 02452 new_node = xmalloc(SIZEOF(split_str_node_t)); 02453 02454 /* set the new nodes next value NULL, and store s */ 02455 new_node->next = NULL; 02456 02457 new_node->s = xmalloc(len); 02458 02459 /* 02460 * Comment: James Couzens <jcouzens@codeshare.ca> 02461 * 02462 * Date: 01/22/04 02463 * 02464 * section 7.1 (Macro definitions) of the RFC v02.9.5 indicates that we must 02465 * always rebuild the macro using the delimiter '.' and not the passed 02466 * delimiting character. 02467 * 02468 */ 02469 snprintf(new_node->s, len, "%s%c", s, last ? '.' : '\0'); 02470 new_node->len = (len - 1); /* don't count \0 */ 02471 02472 prev_node = NULL; 02473 c_node = master->head; 02474 02475 /* reorder the list with the NEW element on the end */ 02476 while (c_node != NULL) 02477 { 02478 prev_node = c_node; 02479 c_node = c_node->next; 02480 } 02481 02482 if (prev_node != NULL) 02483 { 02484 new_node->next = prev_node->next; 02485 prev_node->next = new_node; 02486 } 02487 else 02488 { 02489 master->head = new_node; 02490 } 02491 02492 master->tail = new_node; 02493 master->elements++; 02494 02495 xpprintf("leaving function; returning SPF_TRUE\n"); 02496 02497 return(SPF_TRUE); 02498 } 02499 02500 02501 /* _UTIL_pthread_mutex 02502 * 02503 * Author: James Couzens <jcouzens@codeshare.ca> 02504 * 02505 * Date: 09/08/04 02506 * 02507 * Desc: 02508 * Locks or unlocks the passed mutex based on the additional value 02509 * which is and enumerattion (SPF_BOOL) 02510 * 02511 */ 02512 void _UTIL_pthread_mutex(void *mutex, SPF_BOOL action) 02513 { 02514 02515 #ifdef _WITH_PTHREADS 02516 02517 switch (action) 02518 { 02519 case SPF_TRUE: 02520 pthread_mutex_lock((pthread_mutex_t *)mutex); 02521 return; 02522 02523 case SPF_FALSE: 02524 pthread_mutex_unlock((pthread_mutex_t *)mutex); 02525 return; 02526 } 02527 02528 #endif /* _WITH_PTHREADS */ 02529 02530 return; 02531 } 02532 02533 02534 /* end of util.c */

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