spf_id2str.c

Go to the documentation of this file.
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(" 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_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          * 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 }

Generated on Tue Nov 4 13:27:39 2008 for libspf2 by  doxygen 1.5.4