libspf2
1.2.10
|
00001 /* 00002 * This program is free software; you can redistribute it and/or modify 00003 * it under the terms of either: 00004 * 00005 * a) The GNU Lesser General Public License as published by the Free 00006 * Software Foundation; either version 2.1, or (at your option) any 00007 * later version, 00008 * 00009 * OR 00010 * 00011 * b) The two-clause BSD license. 00012 * 00013 * These licenses can be found with the distribution in the file LICENSES 00014 */ 00015 00016 #include "spf_sys_config.h" 00017 00018 00019 00020 #ifdef STDC_HEADERS 00021 # include <stdio.h> /* stdin / stdout */ 00022 # include <stdlib.h> /* malloc / free */ 00023 # include <ctype.h> /* isupper / tolower */ 00024 #endif 00025 00026 #ifdef HAVE_INTTYPES_H 00027 #include <inttypes.h> 00028 #endif 00029 00030 #ifdef HAVE_STRING_H 00031 # include <string.h> /* strstr / strdup */ 00032 #else 00033 # ifdef HAVE_STRINGS_H 00034 # include <strings.h> /* strstr / strdup */ 00035 # endif 00036 #endif 00037 00038 00039 #include "spf.h" 00040 #include "spf_internal.h" 00041 00042 00043 static SPF_errcode_t 00044 SPF_record_stringify_data(SPF_data_t *data, SPF_data_t *data_end, 00045 char **p_p, char *p_end, 00046 int is_mod, int cidr_ok, int debug ) 00047 { 00048 char *p = *p_p; 00049 00050 size_t len; 00051 00052 SPF_data_t *cidr_data; 00053 00054 if (debug) 00055 SPF_debugf("%s", " string data: Building"); 00056 00057 if (p_end - p <= 0) 00058 return SPF_E_INTERNAL_ERROR; 00059 00060 cidr_data = NULL; 00061 if ( data < data_end && data->dc.parm_type == PARM_CIDR ) 00062 { 00063 if (debug) 00064 SPF_debugf(" string data: Found a CIDR at %p", data); 00065 if ( !cidr_ok ) 00066 return SPF_E_INTERNAL_ERROR; 00067 00068 cidr_data = data; 00069 data = SPF_data_next( data ); 00070 } 00071 00072 00073 for( ; data < data_end; data = SPF_data_next( data ) ) 00074 { 00075 if (debug) 00076 SPF_debugf(" string data: Handling data type %d at %p", 00077 data->ds.parm_type, data); 00078 if ( data->ds.parm_type == PARM_STRING ) 00079 { 00080 char *s = SPF_data_str( data ); 00081 char *s_end = s + data->ds.len; 00082 if (debug) 00083 SPF_debugf(" string data: String is [%d] '%*.*s'", 00084 data->ds.len, data->ds.len, data->ds.len, s); 00085 00086 if (p_end - (p + data->ds.len) <= 0) 00087 return SPF_E_INTERNAL_ERROR; 00088 00089 while (s < s_end) { 00090 if (*s == ' ') { 00091 *p++ = '%'; 00092 *p++ = '_'; 00093 s++; 00094 } 00095 else if (*s == '%') { 00096 *p++ = '%'; 00097 s++; 00098 if (s[0] == '2' && s[1] == '0') { 00099 *p++ = '-'; 00100 s += 2; 00101 } 00102 else { 00103 *p++ = '%'; 00104 // *p++ = '%'; 00105 } 00106 } 00107 else { 00108 *p++ = *s++; 00109 } 00110 } 00111 00112 if (p_end - p <= 0) 00113 return SPF_E_INTERNAL_ERROR; 00114 } 00115 else if (data->dc.parm_type == PARM_CIDR) { 00116 /* Two CIDRs in a row is invalid. */ 00117 return SPF_E_INVALID_CIDR; 00118 } 00119 else { 00120 len = snprintf( p, p_end - p, "%%{" ); 00121 p += len; 00122 if ( p_end - p <= 0 ) return SPF_E_INTERNAL_ERROR; 00123 00124 00125 if ( p_end - p <= 1 ) return SPF_E_INTERNAL_ERROR; 00126 switch( data->dv.parm_type ) 00127 { 00128 case PARM_LP_FROM: /* local-part of envelope-sender */ 00129 *p = 'l'; 00130 break; 00131 00132 case PARM_ENV_FROM: /* envelope-sender */ 00133 *p = 's'; 00134 break; 00135 00136 case PARM_DP_FROM: /* envelope-domain */ 00137 *p = 'o'; 00138 break; 00139 00140 case PARM_CUR_DOM: /* current-domain */ 00141 *p = 'd'; 00142 break; 00143 00144 case PARM_CLIENT_IP: /* SMTP client IP */ 00145 *p = 'i'; 00146 break; 00147 00148 case PARM_CLIENT_IP_P: /* SMTP client IP (pretty) */ 00149 *p = 'c'; 00150 break; 00151 00152 case PARM_TIME: /* time in UTC epoch secs */ 00153 if ( !is_mod ) 00154 return SPF_E_INVALID_VAR; 00155 *p = 't'; 00156 break; 00157 00158 case PARM_CLIENT_DOM: /* SMTP client domain name */ 00159 *p = 'p'; 00160 break; 00161 00162 case PARM_CLIENT_VER: /* IP ver str - in-addr/ip6 */ 00163 *p = 'v'; 00164 break; 00165 00166 case PARM_HELO_DOM: /* HELO/EHLO domain */ 00167 *p = 'h'; 00168 break; 00169 00170 case PARM_REC_DOM: /* receiving domain */ 00171 *p = 'r'; 00172 break; 00173 00174 default: 00175 return SPF_E_INVALID_VAR; 00176 break; 00177 } 00178 if ( data->dv.url_encode ) 00179 *p = toupper( *p ); 00180 p++; 00181 if ( p_end - p <= 0 ) return SPF_E_INTERNAL_ERROR; 00182 00183 00184 if ( data->dv.num_rhs ) 00185 { 00186 len = snprintf( p, p_end - p, "%d", data->dv.num_rhs ); 00187 p += len; 00188 if ( p_end - p <= 0 ) return SPF_E_INTERNAL_ERROR; 00189 } 00190 00191 00192 if ( p_end - p <= 8 ) return SPF_E_INTERNAL_ERROR; 00193 if ( data->dv.rev ) 00194 *p++ = 'r'; 00195 00196 if ( data->dv.delim_dot 00197 && ( data->dv.delim_dash 00198 || data->dv.delim_plus 00199 || data->dv.delim_equal 00200 || data->dv.delim_bar 00201 || data->dv.delim_under 00202 ) 00203 ) 00204 *p++ = '.'; 00205 if ( data->dv.delim_dash ) 00206 *p++ = '-'; 00207 if ( data->dv.delim_plus ) 00208 *p++ = '+'; 00209 if ( data->dv.delim_equal ) 00210 *p++ = '='; 00211 if ( data->dv.delim_bar ) 00212 *p++ = '|'; 00213 if ( data->dv.delim_under ) 00214 *p++ = '_'; 00215 00216 *p++ = '}'; 00217 if ( p_end - p <= 0 ) return SPF_E_INTERNAL_ERROR; 00218 } 00219 } 00220 00221 00222 if ( cidr_data ) 00223 { 00224 if ( cidr_data->dc.ipv4 ) 00225 { 00226 len = snprintf( p, p_end - p, "/%d", cidr_data->dc.ipv4 ); 00227 p += len; 00228 if ( p_end - p <= 0 ) return SPF_E_INTERNAL_ERROR; 00229 } 00230 00231 if ( cidr_data->dc.ipv6 ) 00232 { 00233 len = snprintf( p, p_end - p, "//%d", cidr_data->dc.ipv6 ); 00234 p += len; 00235 if ( p_end - p <= 0 ) return SPF_E_INTERNAL_ERROR; 00236 } 00237 } 00238 00239 *p_p = p; 00240 return SPF_E_SUCCESS; 00241 } 00242 00243 00244 SPF_errcode_t 00245 SPF_record_stringify( SPF_record_t *spf_record, char **bufp, size_t *buflenp) 00246 { 00247 int i; 00248 SPF_mech_t *mech; 00249 SPF_mod_t *mod; 00250 00251 SPF_data_t *data, *data_end; 00252 00253 size_t len; 00254 const char *p_err; 00255 char *p, *p_end; 00256 00257 char ip4_buf[ INET_ADDRSTRLEN ]; 00258 char ip6_buf[ INET6_ADDRSTRLEN ]; 00259 00260 int cidr_ok; 00261 SPF_errcode_t err; 00262 00263 #define debug spf_record->spf_server->debug 00264 00265 SPF_ASSERT_NOTNULL(spf_record); 00266 00267 /* 00268 * make sure the return buffer is big enough 00269 * 00270 * The worse case for the version string: 00271 * "v=spf1 " = 6 = 4 00272 * The worst cases for mechanisms 00273 * "ip4:111.222.333.444/31 " = 23 < 6 * 3.9 00274 * "ip6:<full-ipv6-spec>/126 " = 49 < 18 * 2.8 00275 * "-include:x " = 11 = 5 * 2.2 00276 * "-all " = 5 = 2 * 2.5 00277 * 00278 * The worst case for modifiers: 00279 * "a=%{i15r.-+=|_} " = 16 = 5 * 3.2 00280 */ 00281 00282 len = sizeof( SPF_VER_STR ) 00283 + spf_record->mech_len * 4 + spf_record->mod_len * 4 /* data */ 00284 + sizeof( "\0" ); 00285 00286 err = SPF_recalloc(bufp, buflenp, len); 00287 if (err != SPF_E_SUCCESS) 00288 return err; 00289 00290 p = *bufp; 00291 p_end = *bufp + *buflenp; 00292 00293 if (debug) 00294 SPF_debugf("stringify: Buffer length is %lu\n", (unsigned long)*buflenp); 00295 00296 00297 /* 00298 * generate SPF version string 00299 */ 00300 len = snprintf(p, p_end - p, "v=spf%d", spf_record->version); 00301 p += len; 00302 if (p_end - p <= 0) 00303 return SPF_E_INTERNAL_ERROR; 00304 00305 00306 /* 00307 * generate mechanisms 00308 */ 00309 00310 mech = spf_record->mech_first; 00311 for (i = 0; i < spf_record->num_mech; i++) { 00312 if (debug) 00313 SPF_debugf("stringify: Handling mechanism %d/%d at %p", 00314 i, spf_record->num_mech, mech); 00315 if ( p_end - p <= 1 ) return SPF_E_INTERNAL_ERROR; 00316 *p++ = ' '; 00317 00318 00319 if ( p_end - p <= 1 ) return SPF_E_INTERNAL_ERROR; 00320 switch( mech->prefix_type ) 00321 { 00322 case PREFIX_PASS: 00323 /* *p++ = '+'; */ 00324 break; 00325 00326 case PREFIX_FAIL: 00327 *p++ = '-'; 00328 break; 00329 00330 case PREFIX_SOFTFAIL: 00331 *p++ = '~'; 00332 break; 00333 00334 case PREFIX_NEUTRAL: 00335 *p++ = '?'; 00336 break; 00337 00338 case PREFIX_UNKNOWN: 00339 return SPF_E_RESULT_UNKNOWN; 00340 break; 00341 00342 default: 00343 return SPF_E_INVALID_PREFIX; 00344 break; 00345 } 00346 00347 if (debug) 00348 SPF_debugf("Mechanism type is %d", mech->mech_type); 00349 00350 switch( mech->mech_type ) 00351 { 00352 case MECH_A: 00353 len = snprintf( p, p_end - p, "a" ); 00354 break; 00355 00356 case MECH_MX: 00357 len = snprintf( p, p_end - p, "mx" ); 00358 break; 00359 00360 case MECH_PTR: 00361 len = snprintf( p, p_end - p, "ptr" ); 00362 break; 00363 00364 case MECH_INCLUDE: 00365 len = snprintf( p, p_end - p, "include" ); 00366 break; 00367 00368 case MECH_IP4: 00369 p_err = inet_ntop( AF_INET, SPF_mech_ip4_data( mech ), 00370 ip4_buf, sizeof( ip4_buf ) ); 00371 if ( p_err == NULL ) 00372 return SPF_E_INTERNAL_ERROR; 00373 if ( mech->mech_len ) 00374 len = snprintf( p, p_end - p, "ip4:%s/%d", 00375 ip4_buf, mech->mech_len ); 00376 else 00377 len = snprintf( p, p_end - p, "ip4:%s", ip4_buf ); 00378 break; 00379 00380 case MECH_IP6: 00381 p_err = inet_ntop( AF_INET6, SPF_mech_ip6_data( mech ), 00382 ip6_buf, sizeof( ip6_buf ) ); 00383 if ( p_err == NULL ) 00384 return SPF_E_INTERNAL_ERROR; 00385 if ( mech->mech_len ) 00386 len = snprintf( p, p_end - p, "ip6:%s/%d", 00387 ip6_buf, mech->mech_len ); 00388 else 00389 len = snprintf( p, p_end - p, "ip6:%s", ip6_buf ); 00390 break; 00391 00392 case MECH_EXISTS: 00393 len = snprintf( p, p_end - p, "exists" ); 00394 break; 00395 00396 case MECH_ALL: 00397 len = snprintf( p, p_end - p, "all" ); 00398 break; 00399 00400 case MECH_REDIRECT: 00401 len = snprintf( p, p_end - p, "redirect" ); 00402 break; 00403 00404 default: 00405 return SPF_E_UNKNOWN_MECH; 00406 break; 00407 } 00408 p += len; 00409 if ( p_end - p <= 0 ) return SPF_E_INTERNAL_ERROR; 00410 00411 if (debug) 00412 SPF_debugf("stringify: Buffer so far is %s", p); 00413 00414 if ( mech->mech_type != MECH_IP4 && mech->mech_type != MECH_IP6 ) 00415 { 00416 data = SPF_mech_data( mech ); 00417 data_end = SPF_mech_end_data( mech ); 00418 00419 if (SPF_mech_data_len(mech) > 0 00420 /* We have an immediate string literal */ 00421 && (data->dc.parm_type != PARM_CIDR 00422 /* Some data follows the CIDR */ 00423 || SPF_data_next( data ) < data_end) 00424 ) { 00425 *p++ = ':'; 00426 } 00427 00428 cidr_ok = mech->mech_type == MECH_A || mech->mech_type == MECH_MX; 00429 err = SPF_record_stringify_data( 00430 data, data_end, 00431 &p, p_end, 00432 FALSE, cidr_ok, debug ); 00433 00434 if ( err != SPF_E_SUCCESS ) 00435 return err; 00436 } 00437 00438 mech = SPF_mech_next( mech ); 00439 } 00440 00441 00442 /* 00443 * generate modifiers 00444 */ 00445 00446 mod = spf_record->mod_first; 00447 for( i = 0; i < spf_record->num_mod; i++ ) 00448 { 00449 if (debug) 00450 SPF_debugf("stringify: Handling modifier %d/%d at %p", 00451 i, spf_record->num_mod, mod); 00452 if ( p_end - p <= 1 ) return SPF_E_INTERNAL_ERROR; 00453 *p++ = ' '; 00454 00455 len = snprintf( p, p_end - p, "%.*s=", 00456 mod->name_len, SPF_mod_name( mod ) ); 00457 p += len; 00458 if ( p_end - p <= 0 ) return SPF_E_INTERNAL_ERROR; 00459 00460 data = SPF_mod_data( mod ); 00461 data_end = SPF_mod_end_data( mod ); 00462 00463 err = SPF_record_stringify_data( 00464 data, data_end, 00465 &p, p_end, 00466 TRUE, TRUE, debug ); 00467 00468 if ( err != SPF_E_SUCCESS ) 00469 return err; 00470 00471 00472 mod = SPF_mod_next( mod ); 00473 } 00474 00475 00476 00477 *p++ = '\0'; 00478 00479 return SPF_E_SUCCESS; 00480 }