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