00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "spf_sys_config.h"
00017
00018
00019
00020 #ifdef STDC_HEADERS
00021 # include <stdio.h>
00022 # include <stdlib.h>
00023 # include <ctype.h>
00024 #endif
00025
00026 #ifdef HAVE_INTTYPES_H
00027 #include <inttypes.h>
00028 #endif
00029
00030 #ifdef HAVE_STRING_H
00031 # include <string.h>
00032 #else
00033 # ifdef HAVE_STRINGS_H
00034 # include <strings.h>
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(" 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
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
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:
00129 *p = 'l';
00130 break;
00131
00132 case PARM_ENV_FROM:
00133 *p = 's';
00134 break;
00135
00136 case PARM_DP_FROM:
00137 *p = 'o';
00138 break;
00139
00140 case PARM_CUR_DOM:
00141 *p = 'd';
00142 break;
00143
00144 case PARM_CLIENT_IP:
00145 *p = 'i';
00146 break;
00147
00148 case PARM_CLIENT_IP_P:
00149 *p = 'c';
00150 break;
00151
00152 case PARM_TIME:
00153 if ( !is_mod )
00154 return SPF_E_INVALID_VAR;
00155 *p = 't';
00156 break;
00157
00158 case PARM_CLIENT_DOM:
00159 *p = 'p';
00160 break;
00161
00162 case PARM_CLIENT_VER:
00163 *p = 'v';
00164 break;
00165
00166 case PARM_HELO_DOM:
00167 *p = 'h';
00168 break;
00169
00170 case PARM_REC_DOM:
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
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 len = sizeof( SPF_VER_STR )
00283 + spf_record->mech_len * 4 + spf_record->mod_len * 4
00284 + sizeof( "\0" );
00285
00286 err = SPF_realloc(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
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
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
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
00421 && (data->dc.parm_type != PARM_CIDR
00422
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
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 }