00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00021 #include "spf_sys_config.h"
00022
00023
00024 #ifdef STDC_HEADERS
00025 # include <stdio.h>
00026 # include <stdlib.h>
00027 # include <ctype.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 #if TIME_WITH_SYS_TIME
00039 # include <sys/time.h>
00040 # include <time.h>
00041 #else
00042 # if HAVE_SYS_TIME_H
00043 # include <sys/time.h>
00044 # else
00045 # include <time.h>
00046 # endif
00047 #endif
00048 #ifdef HAVE_STRING_H
00049 #include <string.h>
00050 #endif
00051
00052
00053 #include "spf.h"
00054 #include "spf_internal.h"
00055 #include "spf_record.h"
00056
00057
00058 #define COMPUTE
00059
00060
00061 static const char client_ver_ipv4[] = "in-addr";
00062 static const char client_ver_ipv6[] = "ip6";
00063
00064
00065 static inline int
00066 SPF_delim_valid(SPF_data_t *d, char c)
00067 {
00068 return ( ( d->dv.delim_dot && c == '.' )
00069 || ( d->dv.delim_dash && c == '-' )
00070 || ( d->dv.delim_plus && c == '+' )
00071 || ( d->dv.delim_equal && c == '=' )
00072 || ( d->dv.delim_bar && c == '|' )
00073 || ( d->dv.delim_under && c == '_' ) );
00074 }
00075
00081 SPF_errcode_t
00082 SPF_record_expand_data(SPF_server_t *spf_server,
00083 SPF_request_t *spf_request,
00084 SPF_response_t *spf_response,
00085 SPF_data_t *data, size_t data_len,
00086 char **bufp, size_t *buflenp)
00087 {
00088 SPF_data_t *d, *data_end;
00089
00090 size_t len;
00091 const char *p_err;
00092 char *p, *p_end;
00093 const char *p_read;
00094 const char *p_read_end;
00095 char *p_write;
00096 char *p2, *p2_end;
00097
00098
00099 const char *var;
00100 char *munged_var = NULL;
00101 char *url_var = NULL;
00102
00103
00104 char ip4_buf[ INET_ADDRSTRLEN ];
00105 char ip6_buf[ INET6_ADDRSTRLEN ];
00106
00107 char ip6_rbuf[ sizeof( struct in6_addr ) * 4 + 1 ];
00108
00109 char time_buf[ sizeof( "4294967296" ) ];
00110
00111 int num_found;
00112 int i;
00113 #ifdef COMPUTE
00114 int buflen;
00115 int compute_length;
00116 SPF_errcode_t err;
00117
00118 buflen = 1;
00119 compute_length = 1;
00120 p = NULL;
00121 p_end = NULL;
00122 #endif
00123
00124
00125
00126
00127
00128 SPF_ASSERT_NOTNULL(spf_server);
00129 SPF_ASSERT_NOTNULL(data);
00130 SPF_ASSERT_NOTNULL(bufp);
00131 SPF_ASSERT_NOTNULL(buflenp);
00132
00133
00134 data_end = (SPF_data_t *)((char *)data + data_len);
00135
00136 #ifndef COMPUTE
00137
00138
00139
00140
00141
00142
00143 len = 0;
00144 for (d = data; d < data_end; d = SPF_data_next(d)) {
00145 switch (d->ds.parm_type) {
00146 case PARM_CIDR:
00147 break;
00148
00149 case PARM_STRING:
00150 len += d->ds.len;
00151 break;
00152
00153 case PARM_CLIENT_IP:
00154 len += sizeof( ip6_rbuf );
00155 break;
00156
00157 case PARM_CLIENT_IP_P:
00158 len += sizeof( ip6_buf );
00159 break;
00160
00161 default:
00162
00163
00164 if ( spf_request->max_var_len > 8 )
00165 len += spf_request->max_var_len * 3;
00166 else
00167 len += 8 * 3;
00168 break;
00169 }
00170 }
00171 len += sizeof('\0');
00172
00173 if (*buflenp < len) {
00174 char *new_rec;
00175 size_t new_len;
00176
00177
00178 new_len = len + 64;
00179
00180 new_rec = realloc(*bufp, new_len);
00181 if (new_rec == NULL)
00182 return SPF_E_NO_MEMORY;
00183
00184 *bufp = new_rec;
00185 *buflenp = new_len;
00186 }
00187 memset(*bufp, '\0', *buflenp);
00188 p = *bufp;
00189 p_end = *bufp + *buflenp;
00190 #endif
00191
00192
00193 #ifdef COMPUTE
00194 top:
00195 #ifdef DEBUG
00196 fprintf(stderr, "Pass start compute_length=%d\n", compute_length);
00197 #endif
00198 #endif
00199
00200
00201
00202 for (d = data; d < data_end; d = SPF_data_next(d)) {
00203 #ifdef DEBUG
00204 fprintf(stderr, " Item type=%d at %p\n", d->dc.parm_type, d);
00205 #endif
00206 if (d->dc.parm_type == PARM_CIDR)
00207 continue;
00208
00209 if (d->ds.parm_type == PARM_STRING) {
00210 #ifdef COMPUTE
00211 if (compute_length) {
00212 buflen += d->ds.len;
00213 continue;
00214 }
00215 #endif
00216
00217 if (p_end - (p + d->ds.len) <= 0)
00218 SPF_error("Failed to allocate enough memory "
00219 "to expand string.");
00220 memcpy(p, SPF_data_str(d), d->ds.len);
00221 p += d->ds.len;
00222 continue;
00223 }
00224
00225
00226
00227 var = NULL;
00228 switch (d->dv.parm_type) {
00229 case PARM_LP_FROM:
00230 var = spf_request->env_from_lp;
00231 break;
00232
00233 case PARM_ENV_FROM:
00234 var = spf_request->env_from;
00235 break;
00236
00237 case PARM_DP_FROM:
00238 var = spf_request->env_from_dp;
00239 break;
00240
00241 case PARM_CUR_DOM:
00242 var = spf_request->cur_dom;
00243 break;
00244
00245 case PARM_CLIENT_IP:
00246 #ifdef COMPUTE
00247 if (compute_length) {
00248 len = sizeof(ip6_buf);
00249 if (d->dv.url_encode)
00250 len *= 3;
00251 buflen += len;
00252 continue;
00253 }
00254 #endif
00255 if (spf_request->client_ver == AF_INET) {
00256 p_err = inet_ntop(AF_INET, &spf_request->ipv4,
00257 ip4_buf, sizeof(ip4_buf));
00258 var = ip4_buf;
00259 }
00260 else if (spf_request->client_ver == AF_INET6) {
00261 p2 = ip6_rbuf;
00262 p2_end = p2 + sizeof(ip6_rbuf);
00263
00264 for (i = 0; i < array_elem(spf_request->ipv6.s6_addr); i++) {
00265 p2 += snprintf(p2, p2_end - p2, "%.1x.%.1x.",
00266 spf_request->ipv6.s6_addr[i] >> 4,
00267 spf_request->ipv6.s6_addr[i] & 0xf);
00268 }
00269
00270
00271 ip6_rbuf[sizeof(struct in6_addr) * 4 - 1] = '\0';
00272
00273 var = ip6_rbuf;
00274 }
00275 break;
00276
00277 case PARM_CLIENT_IP_P:
00278 #ifdef COMPUTE
00279 if (compute_length) {
00280 len = sizeof(ip6_buf);
00281 if (d->dv.url_encode)
00282 len *= 3;
00283 buflen += len;
00284 continue;
00285 }
00286 #endif
00287 if (spf_request->client_ver == AF_INET) {
00288 p_err = inet_ntop(AF_INET, &spf_request->ipv4,
00289 ip4_buf, sizeof(ip4_buf));
00290 var = ip4_buf;
00291 }
00292 else if (spf_request->client_ver == AF_INET6) {
00293 p_err = inet_ntop(AF_INET6, &spf_request->ipv6,
00294 ip6_buf, sizeof(ip6_buf));
00295 var = ip6_buf;
00296 }
00297 break;
00298
00299 case PARM_TIME:
00300 #ifdef COMPUTE
00301 if (compute_length) {
00302 len = sizeof(time_buf);
00303
00304 buflen += len;
00305 continue;
00306 }
00307 #endif
00308 snprintf(time_buf, sizeof(time_buf), "%ld",
00309 (long)time(NULL));
00310 var = time_buf;
00311 break;
00312
00313 case PARM_CLIENT_DOM:
00314 var = SPF_request_get_client_dom(spf_request);
00315 if (! var)
00316 return SPF_E_NO_MEMORY;
00317 break;
00318
00319 case PARM_CLIENT_VER:
00320 if (spf_request->client_ver == AF_INET)
00321 var = client_ver_ipv4;
00322 else if (spf_request->client_ver == AF_INET6)
00323 var = client_ver_ipv6;
00324 break;
00325
00326 case PARM_HELO_DOM:
00327 var = spf_request->helo_dom;
00328 break;
00329
00330 case PARM_REC_DOM:
00331 var = SPF_request_get_rec_dom(spf_request);
00332 break;
00333
00334 default:
00335 #ifdef DEBUG
00336 fprintf(stderr, "Invalid variable %d\n", d->dv.parm_type);
00337 #endif
00338 return SPF_E_INVALID_VAR;
00339 break;
00340 }
00341
00342 if (var == NULL)
00343 return SPF_E_UNINIT_VAR;
00344
00345 len = strlen(var);
00346 #ifdef COMPUTE
00347 if (compute_length) {
00348 if (d->dv.url_encode)
00349 len *= 3;
00350 buflen += len;
00351 continue;
00352 }
00353 #endif
00354
00355
00356 munged_var = (char *)malloc(len + 1);
00357 if (munged_var == NULL)
00358 return SPF_E_NO_MEMORY;
00359 memset(munged_var, 0, len + 1);
00360
00361 p_read_end = var + len;
00362 p_write = munged_var;
00363
00364
00365
00366
00367
00368 if (d->dv.rev) {
00369 p_read = p_read_end - 1;
00370
00371 while ( p_read >= var ) {
00372 if ( SPF_delim_valid(d, *p_read) ) {
00373
00374
00375 len = p_read_end - p_read - 1;
00376 memcpy( p_write, p_read + 1, len );
00377 p_write += len;
00378 *p_write++ = '.';
00379
00380 p_read_end = p_read;
00381 }
00382 p_read--;
00383 }
00384
00385
00386
00387
00388 if (p_read_end >= p_read) {
00389 len = p_read_end - p_read - 1;
00390 memcpy( p_write, p_read + 1, len );
00391 p_write += len;
00392 *p_write++ = '.';
00393 }
00394
00395
00396 p_write--;
00397 *p_write = '\0';
00398 }
00399 else {
00400 p_read = var;
00401
00402 while (p_read < p_read_end) {
00403 if (SPF_delim_valid(d, *p_read))
00404 *p_write++ = '.';
00405 else
00406 *p_write++ = *p_read;
00407 p_read++;
00408 }
00409
00410 *p_write = '\0';
00411 }
00412
00413
00414
00415
00416
00417
00418 if (d->dv.num_rhs > 0) {
00419 p_read_end = munged_var + len;
00420 p_write = munged_var + len - 1;
00421 num_found = 0;
00422 while (p_write > munged_var) {
00423 if (*p_write == '.')
00424 num_found++;
00425 if (num_found == d->dv.num_rhs)
00426 break;
00427 p_write--;
00428 }
00429 p_write++;
00430
00431 len = p_read_end - p_write;
00432 memmove(munged_var, p_write, len + 1);
00433 }
00434
00435 var = munged_var;
00436
00437
00438
00439
00440 if (d->dv.url_encode) {
00441 url_var = malloc(len * 3 + 1);
00442 if (url_var == NULL) {
00443 if (munged_var)
00444 free(munged_var);
00445 return SPF_E_NO_MEMORY;
00446 }
00447
00448 p_read = var;
00449 p_write = url_var;
00450
00451
00452 while ( *p_read != '\0' )
00453 {
00454 if ( isalnum( (unsigned char)( *p_read ) ) )
00455 *p_write++ = *p_read++;
00456 else
00457 {
00458 switch( *p_read )
00459 {
00460 case '-':
00461 case '_':
00462 case '.':
00463 case '!':
00464 case '~':
00465 case '*':
00466 case '\'':
00467 case '(':
00468 case ')':
00469 *p_write++ = *p_read++;
00470 break;
00471
00472 default:
00473
00474
00475
00476 sprintf( p_write, "%%%02x", *p_read );
00477 p_write += 3;
00478 p_read++;
00479 break;
00480 }
00481 }
00482 }
00483 *p_write = '\0';
00484
00485 var = url_var;
00486 len = p_write - url_var;
00487 }
00488
00489
00490
00491 len = snprintf(p, p_end - p, "%s", var);
00492 p += len;
00493 if (p_end - p <= 0) {
00494 if (munged_var)
00495 free(munged_var);
00496 if (url_var)
00497 free(url_var);
00498 return SPF_E_INTERNAL_ERROR;
00499 }
00500
00501 if (munged_var)
00502 free(munged_var);
00503 munged_var = NULL;
00504 if (url_var)
00505 free(url_var);
00506 url_var = NULL;
00507 }
00508 #ifdef DEBUG
00509 fprintf(stderr, "Pass end compute_length=%d\n", compute_length);
00510 #endif
00511
00512 #ifdef COMPUTE
00513 if (compute_length) {
00514 compute_length = 0;
00515
00516 err = SPF_realloc(bufp, buflenp, buflen);
00517 if (err != SPF_E_SUCCESS)
00518 return err;
00519 p = *bufp;
00520 p_end = *bufp + *buflenp;
00521 goto top;
00522 }
00523 #endif
00524
00525 *p++ = '\0';
00526
00527 return SPF_E_SUCCESS;
00528 }