spf_request.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 #ifdef STDC_HEADERS
00019 # include <stdio.h>        /* stdin / stdout */
00020 # include <stdlib.h>       /* malloc / free */
00021 #endif
00022 
00023 #ifdef HAVE_STRING_H
00024 # include <string.h>       /* strstr / strdup */
00025 #else
00026 # ifdef HAVE_STRINGS_H
00027 #  include <strings.h>       /* strstr / strdup */
00028 # endif
00029 #endif
00030 
00031 
00032 #include "spf.h"
00033 #include "spf_dns.h"
00034 #include "spf_request.h"
00035 #include "spf_internal.h"
00036 
00037 #include <idn2.h>
00038 
00039 #define SPF_FREE(x) \
00040                 do { if (x) free(x); (x) = NULL; } while(0)
00041 
00042 SPF_request_t *
00043 SPF_request_new(SPF_server_t *spf_server)
00044 {
00045         SPF_request_t   *sr;
00046 
00047         sr = (SPF_request_t *)malloc(sizeof(SPF_request_t));
00048         if (! sr)
00049                 return sr;
00050         memset(sr, 0, sizeof(SPF_request_t));
00051 
00052         sr->spf_server = spf_server;
00053         sr->client_ver = AF_UNSPEC;
00054         sr->ipv4.s_addr = htonl(INADDR_ANY);
00055         sr->ipv6 = in6addr_any;
00056 
00057         return sr;
00058 }
00059 
00060 void
00061 SPF_request_free(SPF_request_t *sr)
00062 {
00063         SPF_ASSERT_NOTNULL(sr);
00064         SPF_FREE(sr->client_dom);
00065         SPF_FREE(sr->helo_dom);
00066         SPF_FREE(sr->env_from);
00067         SPF_FREE(sr->env_from_lp);
00068         SPF_FREE(sr->env_from_dp);
00069         free(sr);
00070 }
00071 
00072 SPF_errcode_t
00073 SPF_request_set_ipv4(SPF_request_t *sr, struct in_addr addr)
00074 {
00075         if (sr->client_dom) {
00076                 free(sr->client_dom);
00077                 sr->client_dom = NULL;
00078         }
00079         sr->client_ver = AF_INET;
00080         sr->ipv4 = addr;
00081         return SPF_E_SUCCESS;
00082 }
00083 
00084 SPF_errcode_t
00085 SPF_request_set_ipv6(SPF_request_t *sr, struct in6_addr addr)
00086 {
00087         if (sr->client_dom) {
00088                 free(sr->client_dom);
00089                 sr->client_dom = NULL;
00090         }
00091         sr->client_ver = AF_INET6;
00092         sr->ipv6 = addr;
00093         return SPF_E_SUCCESS;
00094 }
00095 
00096 SPF_errcode_t
00097 SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
00098 {
00099         struct in_addr  addr;
00100         if (astr == NULL)
00101                 astr = "0.0.0.0";
00102         if (inet_pton(AF_INET, astr, &addr) <= 0)
00103                 return SPF_E_INVALID_IP4;
00104         return SPF_request_set_ipv4(sr, addr);
00105 }
00106 
00107 SPF_errcode_t
00108 SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
00109 {
00110         struct in6_addr addr;
00111         if (astr == NULL)
00112                 astr = "::";
00113         if (inet_pton(AF_INET6, astr, &addr) <= 0)
00114                 return SPF_E_INVALID_IP6;
00115         return SPF_request_set_ipv6(sr, addr);
00116 }
00117 
00118 /* is a string an EAI address with UTF-8 ? */
00119 static int
00120    is_eai(const char *dom)
00121 {
00122         char *s = (char *)dom;
00123 
00124         while(*s)
00125                 if(*s++ & 0x80) return 1;
00126         return 0;
00127 }
00128 
00129 SPF_errcode_t
00130 SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
00131 {
00132         SPF_ASSERT_NOTNULL(dom);
00133         SPF_FREE(sr->helo_dom);
00134         if(is_eai(dom)) {               /* turn U-labels in helo into A-labels */
00135                 int i;
00136                 char *adom;
00137 
00138                 i = idn2_to_ascii_8z(dom, &adom, 0);
00139                 if(i == IDN2_OK) {
00140                         sr->helo_dom = adom;
00141                 } else {
00142                         sr->helo_dom = 0;
00143                         return SPF_E_INVALID_CHAR;
00144                 }
00145         } else
00146                 sr->helo_dom = strdup(dom);
00147         if (! sr->helo_dom)
00148                 return SPF_E_NO_MEMORY;
00149         /* set cur_dom and env_from? */
00150         if (sr->env_from == NULL)
00151                 return SPF_request_set_env_from(sr, sr->helo_dom);
00152         return SPF_E_SUCCESS;
00153 }
00154 
00155 const char *
00156 SPF_request_get_rec_dom(SPF_request_t *sr)
00157 {
00158         SPF_server_t    *spf_server;
00159         spf_server = sr->spf_server;
00160         return spf_server->rec_dom;
00161 }
00162 
00163 int
00164 SPF_request_set_env_from(SPF_request_t *sr, const char *from)
00165 {
00166         char    *cp;
00167         size_t   len;
00168 
00169         SPF_ASSERT_NOTNULL(from);
00170         SPF_FREE(sr->env_from);
00171         SPF_FREE(sr->env_from_lp);
00172         SPF_FREE(sr->env_from_dp);
00173 
00174         if (*from == '\0' && sr->helo_dom != NULL)
00175                 from = sr->helo_dom;
00176         cp = strrchr(from, '@');
00177         if (cp && (cp != from)) {
00178                 sr->env_from = strdup(from);
00179                 if (! sr->env_from)
00180                         return SPF_E_NO_MEMORY;
00181 
00182                 len = cp - from;
00183                 sr->env_from_lp = malloc(len + 1);
00184                 if (!sr->env_from_lp) {
00185                         SPF_FREE(sr->env_from);
00186                         return SPF_E_NO_MEMORY;
00187                 }
00188                 strncpy(sr->env_from_lp, from, len);
00189                 sr->env_from_lp[len] = '\0';
00190                 if(is_eai(cp+1)) {
00191                         int i;
00192                         char *adom;
00193 
00194                         i = idn2_to_ascii_8z(cp+1, &adom, 0);
00195                         if(i == IDN2_OK) {
00196                                 sr->env_from_dp = adom;
00197                         } else {
00198                                 SPF_FREE(sr->env_from);
00199                                 SPF_FREE(sr->env_from_lp);
00200                                 return SPF_E_INVALID_CHAR;
00201                         }
00202                 } else
00203                         sr->env_from_dp = strdup(cp + 1);
00204                 if (!sr->env_from_dp) {
00205                         SPF_FREE(sr->env_from);
00206                         SPF_FREE(sr->env_from_lp);
00207                         return SPF_E_NO_MEMORY;
00208                 }
00209         }
00210         else {
00211                 if (cp == from) from++; /* "@domain.example" */
00212                 if(is_eai(from)) {
00213                         int i;
00214                         char *adom;
00215 
00216                         i = idn2_to_ascii_8z(cp+1, &adom, 0);
00217                         if(i == IDN2_OK) {
00218                                 from = adom;
00219                         } else
00220                                 return SPF_E_INVALID_CHAR;
00221                 }
00222                 len = sizeof("postmaster@") + strlen(from);
00223                 sr->env_from = malloc(len + 1); /* sizeof("") == 1? */
00224                 if (! sr->env_from)
00225                         return SPF_E_NO_MEMORY;
00226                 sprintf(sr->env_from, "postmaster@%s", from);
00227                 sr->env_from_lp = strdup("postmaster");
00228                 if (!sr->env_from_lp) {
00229                         SPF_FREE(sr->env_from);
00230                         return SPF_E_NO_MEMORY;
00231                 }
00232                 sr->env_from_dp = strdup(from);
00233                 if (!sr->env_from_dp) {
00234                         SPF_FREE(sr->env_from);
00235                         SPF_FREE(sr->env_from_lp);
00236                         return SPF_E_NO_MEMORY;
00237                 }
00238         }
00239 
00240         return 0;       // SPF_E_SUCCESS
00241 }
00242 
00243 const char *
00244 SPF_request_get_client_dom(SPF_request_t *sr)
00245 {
00246         SPF_server_t    *spf_server;
00247 
00248         SPF_ASSERT_NOTNULL(sr);
00249         spf_server = sr->spf_server;
00250         SPF_ASSERT_NOTNULL(spf_server);
00251 
00252         if (sr->client_dom == NULL) {
00253                 sr->client_dom = SPF_dns_get_client_dom(spf_server->resolver,
00254                                                 sr);
00255         }
00256         return sr->client_dom;
00257 }
00258 
00259 int
00260 SPF_request_is_loopback(SPF_request_t *sr)
00261 {
00262     if (sr->client_ver == AF_INET) {
00263                 if ((ntohl(sr->ipv4.s_addr) & IN_CLASSA_NET) ==
00264                                                 (IN_LOOPBACKNET << 24)) {
00265                         return TRUE;
00266                 }
00267     }
00268     else if (sr->client_ver == AF_INET6) {
00269                 if (IN6_IS_ADDR_LOOPBACK(&sr->ipv6))
00270                         return TRUE;
00271     }
00272     return FALSE;
00273 }
00274 
00275 static SPF_errcode_t
00276 SPF_request_prepare(SPF_request_t *sr)
00277 {
00278         if (sr->use_helo)
00279                 sr->cur_dom = sr->helo_dom;
00280         else
00281                 sr->cur_dom = sr->env_from_dp;
00282         return SPF_E_SUCCESS;
00283 }
00284  
00288 static SPF_errcode_t
00289 SPF_request_query_record(SPF_request_t *spf_request,
00290                                 SPF_response_t *spf_response,
00291                                 SPF_record_t *spf_record,
00292                                 SPF_errcode_t err)
00293 {
00294         if (err != SPF_E_SUCCESS) {
00295                 if (spf_record)
00296                         SPF_record_free(spf_record);
00297                 SPF_i_done(spf_response, spf_response->result, spf_response->reason, spf_response->err);
00298                 return err;
00299         }
00300         /* Now, in theory, SPF_response_errors(spf_response) == 0 */
00301         if (SPF_response_errors(spf_response) > 0)
00302                 SPF_infof("Warning: %d errors in response, "
00303                                                 "but no error code. Evaluating.",
00304                                                 SPF_response_errors(spf_response));
00305         /* If we get here, spf_record better not be NULL */
00306         spf_response->spf_record_exp = spf_record;
00307         err = SPF_record_interpret(spf_record,
00308                                         spf_request, spf_response, 0);
00309         SPF_record_free(spf_record);
00310         spf_response->spf_record_exp = NULL;
00311 
00312         return err;
00313 }
00314 
00318 SPF_errcode_t
00319 SPF_request_query_mailfrom(SPF_request_t *spf_request,
00320                                 SPF_response_t **spf_responsep)
00321 {
00322         SPF_server_t    *spf_server;
00323         SPF_record_t    *spf_record;
00324         SPF_errcode_t    err;
00325 
00326         SPF_ASSERT_NOTNULL(spf_request);
00327         spf_server = spf_request->spf_server;
00328         SPF_ASSERT_NOTNULL(spf_server);
00329 
00330         *spf_responsep = SPF_response_new(spf_request);
00331         if (! *spf_responsep)
00332                 return SPF_E_NO_MEMORY;
00333 
00334         /* Give localhost a free ride */
00335         if (SPF_request_is_loopback(spf_request))
00336                 return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
00337                                                 SPF_REASON_LOCALHOST, SPF_E_SUCCESS);
00338 
00339         SPF_request_prepare(spf_request);
00340 
00341         err = SPF_server_get_record(spf_server, spf_request,
00342                                         *spf_responsep, &spf_record);
00343         return SPF_request_query_record(spf_request, *spf_responsep,
00344                                         spf_record, err);
00345 }
00346 
00347 /* This interface isn't finalised. */
00348 SPF_errcode_t
00349 SPF_request_query_fallback(SPF_request_t *spf_request,
00350                                 SPF_response_t **spf_responsep,
00351                                 const char *record)
00352 {
00353         SPF_server_t    *spf_server;
00354         SPF_record_t    *spf_record;
00355         SPF_errcode_t    err;
00356 
00357         SPF_ASSERT_NOTNULL(spf_request);
00358         spf_server = spf_request->spf_server;
00359         SPF_ASSERT_NOTNULL(spf_server);
00360 
00361         *spf_responsep = SPF_response_new(spf_request);
00362         if (! *spf_responsep)
00363                 return SPF_E_NO_MEMORY;
00364 
00365         /* Give localhost a free ride */
00366         if (SPF_request_is_loopback(spf_request))
00367                 return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
00368                                                 SPF_REASON_LOCALHOST, SPF_E_SUCCESS);
00369 
00370         SPF_request_prepare(spf_request);
00371 
00372         err = SPF_record_compile(spf_server,
00373                                         *spf_responsep, &spf_record,
00374                                         record);
00375         return SPF_request_query_record(spf_request, *spf_responsep,
00376                                         spf_record, err);
00377 }
00378 
00387 /* FIXME: Check the implementation of this. */
00388 SPF_errcode_t
00389 SPF_request_query_rcptto(SPF_request_t *spf_request,
00390                                 SPF_response_t **spf_responsep,
00391                                 const char *rcpt_to)
00392 {
00393         SPF_server_t    *spf_server;
00394         SPF_record_t    *spf_record;
00395         SPF_errcode_t    err;
00396         const char              *rcpt_to_dom;
00397         char                    *record;
00398         char                    *eai_dom = NULL;
00399         size_t                   len;
00400 
00401         SPF_ASSERT_NOTNULL(spf_request);
00402         spf_server = spf_request->spf_server;
00403         SPF_ASSERT_NOTNULL(spf_server);
00404 
00405         *spf_responsep = SPF_response_new(spf_request);
00406         if (! *spf_responsep)
00407                 return SPF_E_NO_MEMORY;
00408 
00409         /* Give localhost a free ride */
00410         if (SPF_request_is_loopback(spf_request))
00411                 return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
00412                                                 SPF_REASON_LOCALHOST, SPF_E_SUCCESS);
00413 
00414         rcpt_to_dom = strchr(rcpt_to, '@');
00415         if (rcpt_to_dom == NULL)
00416                 rcpt_to_dom = rcpt_to;
00417         else
00418                 rcpt_to_dom++;
00419         if(is_eai(rcpt_to_dom)) {
00420                 int i;
00421 
00422                 i = idn2_to_ascii_8z(rcpt_to_dom, &eai_dom, 0);
00423                 if(i == IDN2_OK) {
00424                         spf_request->cur_dom = eai_dom;
00425                 } else
00426                         return SPF_E_INVALID_CHAR;
00427         } else
00428                 spf_request->cur_dom = rcpt_to_dom;
00429 
00430         len = sizeof(SPF_VER_STR) + 64 + strlen(rcpt_to_dom);
00431         record = malloc(len);
00432         if (! record)
00433                 return SPF_E_NO_MEMORY;
00434         snprintf(record, len, SPF_VER_STR " mx:%s", rcpt_to_dom);
00435         err = SPF_record_compile(spf_server,
00436                                         *spf_responsep, &spf_record,
00437                                         record);
00438         free(record);
00439         if(eai_dom) free(eai_dom);
00440         return SPF_request_query_record(spf_request, *spf_responsep,
00441                                         spf_record, err);
00442 }

Generated on 20 May 2019 for libspf2 by  doxygen 1.6.1