Main Page | Class List | Directories | File List | Class Members | File Members

libspamc.c File Reference

#include "config.h"
#include "libspamc.h"
#include "utils.h"
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

Go to the source code of this file.

Classes

struct  libspamc_private_message

Defines

#define closesocket(x)   close(x)
#define SHUT_RD   0
#define SHUT_WR   1
#define SHUT_RDWR   2
#define h_errno   errno
#define spamc_get_errno()   errno
#define INADDR_NONE   ((in_addr_t) 0xffffffff)
#define EX__MAX   200
#define SPAMC_MAXHOST   256
#define SPAMC_MAXSERV   256
#define CRNLCRNL   "\r\n\r\n"
#define CRNLCRNL_LEN   4
#define NLNL   "\n\n"
#define NLNL_LEN   2
#define LOG_BUFSIZ   1023

Functions

static int _translate_connect_errno (int err)
static int _opensocket (int flags, int type, int *psock)
static int _try_to_connect_unix (struct transport *tp, int *sockptr)
static int _try_to_connect_tcp (const struct transport *tp, int *sockptr)
static void _clear_message (struct message *m)
static void _use_msg_for_out (struct message *m)
static int _message_read_raw (int fd, struct message *m)
static int _message_read_bsmtp (int fd, struct message *m)
int message_read (int fd, int flags, struct message *m)
long message_write (int fd, struct message *m)
void message_dump (int in_fd, int out_fd, struct message *m)
static int _spamc_read_full_line (struct message *m, int flags, SSL *ssl, int sock, char *buf, size_t *lenp, size_t bufsiz)
static float _locale_safe_string_to_float (char *buf, int siz)
static int _handle_spamd_header (struct message *m, int flags, char *buf, int len, unsigned int *didtellflags)
static int _zlib_compress (char *m_msg, int m_msg_len, unsigned char **zlib_buf, int *zlib_bufsiz, int flags)
int _append_original_body (struct message *m, int flags)
int message_filter (struct transport *tp, const char *username, int flags, struct message *m)
int message_process (struct transport *trans, char *username, int max_size, int in_fd, int out_fd, const int flags)
int message_tell (struct transport *tp, const char *username, int flags, struct message *m, int msg_class, unsigned int tellflags, unsigned int *didtellflags)
void message_cleanup (struct message *m)
int process_message (struct transport *tp, char *username, int max_size, int in_fd, int out_fd, const int my_check_only, const int my_safe_fallback)
void transport_init (struct transport *tp)
static void _randomize_hosts (struct transport *tp)
int transport_setup (struct transport *tp, int flags)
void libspamc_log (int flags, int level, char *msg,...)

Variables

char * optarg
static const int EXPANSION_ALLOWANCE = 16384
static const char * PROTOCOL_VERSION = "SPAMC/1.4"
int libspamc_timeout = 0


Define Documentation

#define closesocket  )     close(x)
 

Definition at line 49 of file libspamc.c.

Referenced by _opensocket(), _try_to_connect_tcp(), _try_to_connect_unix(), message_filter(), and message_tell().

#define CRNLCRNL   "\r\n\r\n"
 

Referenced by _append_original_body().

#define CRNLCRNL_LEN   4
 

Referenced by _append_original_body().

#define EX__MAX   200
 

Definition at line 107 of file libspamc.c.

#define h_errno   errno
 

Definition at line 85 of file libspamc.c.

Referenced by transport_setup().

#define INADDR_NONE   ((in_addr_t) 0xffffffff)
 

Definition at line 99 of file libspamc.c.

#define LOG_BUFSIZ   1023
 

Definition at line 2028 of file libspamc.c.

Referenced by libspamc_log().

#define NLNL   "\n\n"
 

Referenced by _append_original_body().

#define NLNL_LEN   2
 

Referenced by _append_original_body().

#define SHUT_RD   0
 

Definition at line 75 of file libspamc.c.

Referenced by message_filter(), and message_tell().

#define SHUT_RDWR   2
 

Definition at line 81 of file libspamc.c.

#define SHUT_WR   1
 

Definition at line 78 of file libspamc.c.

Referenced by message_filter(), and message_tell().

 
#define spamc_get_errno  )     errno
 

Definition at line 91 of file libspamc.c.

Referenced by _opensocket(), and _try_to_connect_tcp().

#define SPAMC_MAXHOST   256
 

Definition at line 120 of file libspamc.c.

Referenced by _try_to_connect_tcp().

#define SPAMC_MAXSERV   256
 

Definition at line 126 of file libspamc.c.

Referenced by _try_to_connect_tcp().


Function Documentation

int _append_original_body struct message m,
int  flags
 

Definition at line 1096 of file libspamc.c.

References libspamc_private_message::alloced_size, CRNLCRNL, CRNLCRNL_LEN, EX_OK, EX_SOFTWARE, libspamc_log(), LOG_ERR, NLNL, NLNL_LEN, message::out, message::out_len, message::priv, message::raw, and message::raw_len.

Referenced by message_filter().

01097 {
01098     char *cp, *cpend, *bodystart;
01099     int bodylen, outspaceleft, towrite;
01100 
01101     /* at this stage, m->out now contains the rewritten headers.
01102      * find and append the raw message's body, up to m->priv->alloced_size
01103      * bytes.
01104      */
01105 
01106 #define CRNLCRNL        "\r\n\r\n"
01107 #define CRNLCRNL_LEN    4
01108 #define NLNL            "\n\n"
01109 #define NLNL_LEN        2
01110 
01111     cpend = m->raw + m->raw_len;
01112     bodystart = NULL;
01113 
01114     for (cp = m->raw; cp < cpend; cp++) {
01115         if (*cp == '\r' && cpend - cp >= CRNLCRNL_LEN && 
01116                             !strncmp(cp, CRNLCRNL, CRNLCRNL_LEN))
01117         {
01118             bodystart = cp + CRNLCRNL_LEN;
01119             break;
01120         }
01121         else if (*cp == '\n' && cpend - cp >= NLNL_LEN && 
01122                            !strncmp(cp, NLNL, NLNL_LEN))
01123         {
01124             bodystart = cp + NLNL_LEN;
01125             break;
01126         }
01127     }
01128 
01129     if (bodystart == NULL) {
01130         libspamc_log(flags, LOG_ERR, "failed to find end-of-headers");
01131         return EX_SOFTWARE;
01132     }
01133 
01134     bodylen = cpend - bodystart;
01135     outspaceleft = (m->priv->alloced_size-1) - m->out_len;
01136     towrite = (bodylen < outspaceleft ? bodylen : outspaceleft);
01137 
01138     /* copy in the body; careful not to overflow */
01139     strncpy (m->out + m->out_len, bodystart, towrite);
01140     m->out_len += towrite;
01141     return EX_OK;
01142 }

static void _clear_message struct message m  )  [static]
 

Definition at line 606 of file libspamc.c.

References message::content_length, EX_TOOBIG, message::is_spam, MESSAGE_NONE, message::msg, message::msg_len, message::out, message::out_len, message::outbuf, message::post, message::post_len, message::pre, message::pre_len, message::raw, message::raw_len, message::score, message::threshold, and message::type.

Referenced by _message_read_bsmtp(), _message_read_raw(), message_cleanup(), and message_read().

00607 {
00608     m->type = MESSAGE_NONE;
00609     m->raw = NULL;
00610     m->raw_len = 0;
00611     m->pre = NULL;
00612     m->pre_len = 0;
00613     m->msg = NULL;
00614     m->msg_len = 0;
00615     m->post = NULL;
00616     m->post_len = 0;
00617     m->is_spam = EX_TOOBIG;
00618     m->score = 0.0;
00619     m->threshold = 0.0;
00620     m->outbuf = NULL;
00621     m->out = NULL;
00622     m->out_len = 0;
00623     m->content_length = -1;
00624 }

static int _handle_spamd_header struct message m,
int  flags,
char *  buf,
int  len,
unsigned int *  didtellflags
[static]
 

Definition at line 965 of file libspamc.c.

References _locale_safe_string_to_float(), message::content_length, EX_ISSPAM, EX_NOTSPAM, EX_OK, EX_PROTOCOL, message::is_spam, libspamc_log(), LOG_ERR, message::out, message::out_len, message::score, SPAMC_CHECK_ONLY, SPAMC_REMOVE_LOCAL, SPAMC_REMOVE_REMOTE, SPAMC_REPORT, SPAMC_REPORT_IFSPAM, SPAMC_SET_LOCAL, SPAMC_SET_REMOTE, message::threshold, and UNUSED_VARIABLE.

Referenced by message_filter(), and message_tell().

00967 {
00968     char is_spam[6];
00969     char s_str[21], t_str[21];
00970     char didset_ret[15];
00971     char didremove_ret[15];
00972 
00973     UNUSED_VARIABLE(len);
00974 
00975     /* Feb 12 2003 jm: actually, I think sccanf is working fine here ;)
00976      * let's stick with it for this parser.
00977      * May  7 2003 jm: using %f is bad where LC_NUMERIC is "," in the locale.
00978      * work around using our own locale-independent float-parser code.
00979      */
00980     if (sscanf(buf, "Spam: %5s ; %20s / %20s", is_spam, s_str, t_str) == 3) {
00981         m->score = _locale_safe_string_to_float(s_str, 20);
00982         m->threshold = _locale_safe_string_to_float(t_str, 20);
00983 
00984         /* set bounds on these to ensure no buffer overflow in the sprintf */
00985         if (m->score > 1e10)
00986             m->score = 1e10;
00987         else if (m->score < -1e10)
00988             m->score = -1e10;
00989         if (m->threshold > 1e10)
00990             m->threshold = 1e10;
00991         else if (m->threshold < -1e10)
00992             m->threshold = -1e10;
00993 
00994         /* Format is "Spam: x; y / x" */
00995         m->is_spam =
00996             strcasecmp("true", is_spam) == 0 ? EX_ISSPAM : EX_NOTSPAM;
00997 
00998         if (flags & SPAMC_CHECK_ONLY) {
00999             m->out_len = sprintf(m->out,
01000                                  "%.1f/%.1f\n", m->score, m->threshold);
01001         }
01002         else if ((flags & SPAMC_REPORT_IFSPAM && m->is_spam == EX_ISSPAM)
01003                  || (flags & SPAMC_REPORT)) {
01004             m->out_len = sprintf(m->out,
01005                                  "%.1f/%.1f\n", m->score, m->threshold);
01006         }
01007         return EX_OK;
01008 
01009     }
01010     else if (sscanf(buf, "Content-length: %d", &m->content_length) == 1) {
01011         if (m->content_length < 0) {
01012             libspamc_log(flags, LOG_ERR, "spamd responded with bad Content-length '%s'",
01013                    buf);
01014             return EX_PROTOCOL;
01015         }
01016         return EX_OK;
01017     }
01018     else if (sscanf(buf, "DidSet: %14s", didset_ret) == 1) {
01019       if (strstr(didset_ret, "local")) {
01020           *didtellflags |= SPAMC_SET_LOCAL;
01021         }
01022         if (strstr(didset_ret, "remote")) {
01023           *didtellflags |= SPAMC_SET_REMOTE;
01024         }
01025     }
01026     else if (sscanf(buf, "DidRemove: %14s", didremove_ret) == 1) {
01027         if (strstr(didremove_ret, "local")) {
01028           *didtellflags |= SPAMC_REMOVE_LOCAL;
01029         }
01030         if (strstr(didremove_ret, "remote")) {
01031           *didtellflags |= SPAMC_REMOVE_REMOTE;
01032         }
01033     }
01034 
01035     return EX_OK;
01036 }

static float _locale_safe_string_to_float char *  buf,
int  siz
[static]
 

Definition at line 904 of file libspamc.c.

Referenced by _handle_spamd_header(), message_filter(), and message_tell().

00905 {
00906     int is_neg;
00907     char *cp, *dot;
00908     int divider;
00909     float ret, postdot;
00910 
00911     buf[siz - 1] = '\0';        /* ensure termination */
00912 
00913     /* ok, let's illustrate using "100.033" as an example... */
00914 
00915     is_neg = 0;
00916     if (*buf == '-') {
00917         is_neg = 1;
00918     }
00919 
00920     ret = (float) (strtol(buf, &dot, 10));
00921     if (dot == NULL) {
00922         return 0.0;
00923     }
00924     if (dot != NULL && *dot != '.') {
00925         return ret;
00926     }
00927 
00928     /* ex: ret == 100.0 */
00929 
00930     cp = (dot + 1);
00931     postdot = (float) (strtol(cp, NULL, 10));
00932     /* note: don't compare floats == 0.0, it's unsafe.  use a range */
00933     if (postdot >= -0.00001 && postdot <= 0.00001) {
00934         return ret;
00935     }
00936 
00937     /* ex: postdot == 33.0, cp="033" */
00938 
00939     /* now count the number of decimal places and figure out what power of 10 to use */
00940     divider = 1;
00941     while (*cp != '\0') {
00942         divider *= 10;
00943         cp++;
00944     }
00945 
00946     /* ex:
00947      * cp="033", divider=1
00948      * cp="33", divider=10
00949      * cp="3", divider=100
00950      * cp="", divider=1000
00951      */
00952 
00953     if (is_neg) {
00954         ret -= (postdot / ((float) divider));
00955     }
00956     else {
00957         ret += (postdot / ((float) divider));
00958     }
00959     /* ex: ret == 100.033, tada! ... hopefully */
00960 
00961     return ret;
00962 }

static int _message_read_bsmtp int  fd,
struct message m
[static]
 

Definition at line 663 of file libspamc.c.

References _clear_message(), EX_DATAERR, EX_IOERR, EX_OK, EX_OSERR, EX_SOFTWARE, EX_TOOBIG, full_read(), message::max_len, MESSAGE_BSMTP, MESSAGE_ERROR, message::msg, message::msg_len, message::out, message::out_len, message::post, message::post_len, message::pre, message::pre_len, message::raw, message::raw_len, and message::type.

Referenced by message_read().

00664 {
00665     unsigned int i, j, p_len;
00666     char prev;
00667     char* p;
00668 
00669     _clear_message(m);
00670     if ((m->raw = malloc(m->max_len + 1)) == NULL)
00671         return EX_OSERR;
00672 
00673     /* Find the DATA line */
00674     m->raw_len = full_read(fd, 1, m->raw, m->max_len + 1, m->max_len + 1);
00675     if (m->raw_len <= 0) {
00676         free(m->raw);
00677         m->raw = NULL;
00678         m->raw_len = 0;
00679         return EX_IOERR;
00680     }
00681     m->type = MESSAGE_ERROR;
00682     if (m->raw_len > (int) m->max_len)
00683         return EX_TOOBIG;
00684     p = m->pre = m->raw;
00685     /* Search for \nDATA\n which marks start of actual message */
00686     while ((p_len = (m->raw_len - (p - m->raw))) > 8) { /* leave room for at least \nDATA\n.\n */
00687       char* q = memchr(p, '\n', p_len - 8);  /* find next \n then see if start of \nDATA\n */
00688       if (q == NULL) break;
00689       q++;
00690       if (((q[0]|0x20) == 'd') && /* case-insensitive ASCII comparison */
00691           ((q[1]|0x20) == 'a') &&
00692           ((q[2]|0x20) == 't') &&
00693           ((q[3]|0x20) == 'a')) {
00694         q+=4;
00695         if (q[0] == '\r') ++q;
00696         if (*(q++) == '\n') {  /* leave q at start of message if we found it */
00697           m->msg = q;
00698           m->pre_len = q - m->raw;
00699           m->msg_len = m->raw_len - m->pre_len;
00700           break;
00701         }
00702       }
00703       p = q; /* the above code ensures no other '\n' comes before q */
00704     }
00705     if (m->msg == NULL)
00706         return EX_DATAERR;
00707 
00708     /* ensure this is >= 0 */
00709     if (m->msg_len < 0) {
00710         return EX_SOFTWARE;
00711     }
00712 
00713     /* Find the end-of-DATA line */
00714     prev = '\n';
00715     for (i = j = 0; i < (unsigned int) m->msg_len; i++) {
00716         if (prev == '\n' && m->msg[i] == '.') {
00717             /* Dot at the beginning of a line */
00718             if (((int) (i+1) == m->msg_len)
00719                 || ((int) (i+1) < m->msg_len && m->msg[i + 1] == '\n')
00720                 || ((int) (i+2) < m->msg_len && m->msg[i + 1] == '\r' && m->msg[i + 2] == '\n')) {
00721                 /* Lone dot! That's all, folks */
00722                 m->post = m->msg + i;
00723                 m->post_len = m->msg_len - i;
00724                 m->msg_len = j;
00725                 break;
00726             }
00727             else if ((int) (i+1) < m->msg_len && m->msg[i + 1] == '.') {
00728                 /* Escaping dot, eliminate. */
00729                 prev = '.';
00730                 continue;
00731             }                   /* Else an ordinary dot, drop down to ordinary char handler */
00732         }
00733         prev = m->msg[i];
00734         m->msg[j++] = m->msg[i];
00735     }
00736 
00737     /* if bad format with no end "\n.\n", error out */
00738     if (m->post == NULL)
00739         return EX_DATAERR;
00740     m->type = MESSAGE_BSMTP;
00741     m->out = m->msg;
00742     m->out_len = m->msg_len;
00743     return EX_OK;
00744 }

static int _message_read_raw int  fd,
struct message m
[static]
 

Definition at line 635 of file libspamc.c.

References _clear_message(), EX_IOERR, EX_OK, EX_OSERR, EX_TOOBIG, libspamc_private_message::flags, full_read(), libspamc_log(), LOG_ERR, message::max_len, MESSAGE_ERROR, MESSAGE_RAW, message::msg, message::msg_len, message::out, message::out_len, message::priv, message::raw, message::raw_len, and message::type.

Referenced by message_read().

00636 {
00637     _clear_message(m);
00638     if ((m->raw = malloc(m->max_len + 1)) == NULL)
00639         return EX_OSERR;
00640     m->raw_len = full_read(fd, 1, m->raw, m->max_len + 1, m->max_len + 1);
00641     if (m->raw_len <= 0) {
00642         free(m->raw);
00643         m->raw = NULL;
00644         m->raw_len = 0;
00645         return EX_IOERR;
00646     }
00647     m->type = MESSAGE_ERROR;
00648     if (m->raw_len > (int) m->max_len)
00649     {
00650         libspamc_log(m->priv->flags, LOG_ERR,
00651                 "skipped message, greater than max message size (%d bytes)",
00652                 m->max_len);
00653         return EX_TOOBIG;
00654     }
00655     m->type = MESSAGE_RAW;
00656     m->msg = m->raw;
00657     m->msg_len = m->raw_len;
00658     m->out = m->msg;
00659     m->out_len = m->msg_len;
00660     return EX_OK;
00661 }

static int _opensocket int  flags,
int  type,
int *  psock
[static]
 

Definition at line 205 of file libspamc.c.

References closesocket, EX_NOPERM, EX_OSERR, EX_SOFTWARE, libspamc_log(), libspamc_timeout, LOG_ERR, and spamc_get_errno.

Referenced by _try_to_connect_tcp(), and _try_to_connect_unix().

00206 {
00207     int proto = 0;
00208 #endif
00209     const char *typename;
00210     int origerr;
00211 #ifdef _WIN32
00212     int socktout;
00213 #endif
00214 
00215     assert(psock != 0);
00216 
00217         /*----------------------------------------------------------------
00218          * Create a few induction variables that are implied by the socket
00219          * type given by the user. The typename is strictly used for debug
00220          * reporting.
00221          */
00222 #ifdef SPAMC_HAS_ADDRINFO
00223     switch(res->ai_family) {
00224        case PF_UNIX:
00225           typename = "PF_UNIX";
00226           break;
00227        case PF_INET:
00228           typename = "PF_INET";
00229           break;
00230        case PF_INET6:
00231           typename = "PF_INET6";
00232           break;
00233        default:
00234           typename = "Unknown";
00235           break;
00236     }
00237 #else
00238     if (type == PF_UNIX) {
00239         typename = "PF_UNIX";
00240     }
00241     else {
00242         typename = "PF_INET";
00243         proto = IPPROTO_TCP;
00244     }
00245 #endif
00246 
00247 #ifdef DO_CONNECT_DEBUG_SYSLOGS
00248     libspamc_log(flags, CONNECT_DEBUG_LEVEL, "dbg: create socket(%s)", typename);
00249 #endif
00250 
00251 #ifdef SPAMC_HAS_ADDRINFO
00252     if ((*psock = socket(res->ai_family, res->ai_socktype, res->ai_protocol))
00253 #else
00254     if ((*psock = socket(type, SOCK_STREAM, proto))
00255 #endif
00256 #ifndef _WIN32
00257         < 0
00258 #else
00259         == INVALID_SOCKET
00260 #endif
00261         ) {
00262 
00263                 /*--------------------------------------------------------
00264                  * At this point we had a failure creating the socket, and
00265                  * this is pretty much fatal. Translate the error reason
00266                  * into something the user can understand.
00267                  */
00268         origerr = spamc_get_errno();
00269 #ifndef _WIN32
00270         libspamc_log(flags, LOG_ERR, "socket(%s) to spamd failed: %s", typename, strerror(origerr));
00271 #else
00272         libspamc_log(flags, LOG_ERR, "socket(%s) to spamd failed: %d", typename, origerr);
00273 #endif
00274 
00275         switch (origerr) {
00276         case EPROTONOSUPPORT:
00277         case EINVAL:
00278             return EX_SOFTWARE;
00279 
00280         case EACCES:
00281             return EX_NOPERM;
00282 
00283         case ENFILE:
00284         case EMFILE:
00285         case ENOBUFS:
00286         case ENOMEM:
00287             return EX_OSERR;
00288 
00289         default:
00290             return EX_SOFTWARE;
00291         }
00292     }
00293 
00294 #ifdef _WIN32
00295     /* bug 4344: makes timeout functional on Win32 */
00296     socktout = libspamc_timeout * 1000;
00297     if (type == PF_INET
00298         && setsockopt(*psock, SOL_SOCKET, SO_RCVTIMEO, (char *)&socktout, sizeof(socktout)) != 0)
00299     {
00300 
00301         origerr = spamc_get_errno();
00302         switch (origerr)
00303         {
00304         case EBADF:
00305         case ENOTSOCK:
00306         case ENOPROTOOPT:
00307         case EFAULT:
00308             libspamc_log(flags, LOG_ERR, "setsockopt(SO_RCVTIMEO) failed: %d", origerr);
00309             closesocket(*psock);
00310             return EX_SOFTWARE;
00311 
00312         default:
00313             break;              /* ignored */
00314         }
00315     }
00316 #endif
00317 
00318         /*----------------------------------------------------------------
00319          * Do a bit of setup on the TCP socket if required. Notes above
00320          * suggest this is probably not set
00321          */
00322 #ifdef USE_TCP_NODELAY
00323     {
00324         int one = 1;
00325 
00326         if (type == PF_INET
00327             && setsockopt(*psock, 0, TCP_NODELAY, &one, sizeof one) != 0) {
00328             origerr = spamc_get_errno();
00329             switch (origerr) {
00330             case EBADF:
00331             case ENOTSOCK:
00332             case ENOPROTOOPT:
00333             case EFAULT:
00334                 libspamc_log(flags, LOG_ERR,
00335 #ifndef _WIN32
00336                        "setsockopt(TCP_NODELAY) failed: %s", strerror(origerr));
00337 #else
00338                        "setsockopt(TCP_NODELAY) failed: %d", origerr);
00339 #endif
00340                 closesocket(*psock);
00341                 return EX_SOFTWARE;
00342 
00343             default:
00344                 break;          /* ignored */
00345             }
00346         }
00347     }
00348 #endif /* USE_TCP_NODELAY */
00349 
00350     return EX_OK;               /* all is well */
00351 }

static void _randomize_hosts struct transport tp  )  [static]
 

Definition at line 1749 of file libspamc.c.

References transport::hosts, and transport::nhosts.

Referenced by transport_setup().

01750 {
01751 #ifdef SPAMC_HAS_ADDRINFO
01752     struct addrinfo *tmp;
01753 #else
01754     struct in_addr tmp;
01755 #endif
01756     int i;
01757     int rnum;
01758 
01759     assert(tp != 0);
01760 
01761     if (tp->nhosts <= 1)
01762         return;
01763 
01764     rnum = rand() % tp->nhosts;
01765 
01766     while (rnum-- > 0) {
01767         tmp = tp->hosts[0];
01768 
01769         /* TODO: free using freeaddrinfo() */
01770         for (i = 1; i < tp->nhosts; i++)
01771             tp->hosts[i - 1] = tp->hosts[i];
01772 
01773         tp->hosts[i - 1] = tmp;
01774     }
01775 }

static int _spamc_read_full_line struct message m,
int  flags,
SSL ssl,
int  sock,
char *  buf,
size_t *  lenp,
size_t  bufsiz
[static]
 

Definition at line 858 of file libspamc.c.

References EX_IOERR, EX_OK, EX_TOOBIG, fd_timeout_read(), libspamc_log(), LOG_ERR, SPAMC_USE_SSL, ssl_timeout_read(), and UNUSED_VARIABLE.

Referenced by message_filter(), and message_tell().

00860 {
00861     int failureval;
00862     int bytesread = 0;
00863     size_t len;
00864 
00865     UNUSED_VARIABLE(m);
00866 
00867     *lenp = 0;
00868     /* Now, read from spamd */
00869     for (len = 0; len < bufsiz - 1; len++) {
00870         if (flags & SPAMC_USE_SSL) {
00871             bytesread = ssl_timeout_read(ssl, buf + len, 1);
00872         }
00873         else {
00874             bytesread = fd_timeout_read(sock, 0, buf + len, 1);
00875         }
00876 
00877         if (bytesread <= 0) {
00878             failureval = EX_IOERR;
00879             goto failure;
00880         }
00881 
00882         if (buf[len] == '\n') {
00883             buf[len] = '\0';
00884             if (len > 0 && buf[len - 1] == '\r') {
00885                 len--;
00886                 buf[len] = '\0';
00887             }
00888             *lenp = len;
00889             return EX_OK;
00890         }
00891     }
00892 
00893     libspamc_log(flags, LOG_ERR, "spamd responded with line of %d bytes, dying", len);
00894     failureval = EX_TOOBIG;
00895 
00896   failure:
00897     return failureval;
00898 }

static int _translate_connect_errno int  err  )  [static]
 

Definition at line 165 of file libspamc.c.

References EX_NOPERM, EX_SOFTWARE, and EX_UNAVAILABLE.

Referenced by _try_to_connect_tcp(), and _try_to_connect_unix().

00166 {
00167     switch (err) {
00168     case EBADF:
00169     case EFAULT:
00170     case ENOTSOCK:
00171     case EISCONN:
00172     case EADDRINUSE:
00173     case EINPROGRESS:
00174     case EALREADY:
00175     case EAFNOSUPPORT:
00176         return EX_SOFTWARE;
00177 
00178     case ECONNREFUSED:
00179     case ETIMEDOUT:
00180     case ENETUNREACH:
00181         return EX_UNAVAILABLE;
00182 
00183     case EACCES:
00184         return EX_NOPERM;
00185 
00186     default:
00187         return EX_SOFTWARE;
00188     }
00189 }

static int _try_to_connect_tcp const struct transport tp,
int *  sockptr
[static]
 

Definition at line 435 of file libspamc.c.

References _opensocket(), _translate_connect_errno(), closesocket, transport::connect_retries, EX_OK, transport::flags, transport::hosts, libspamc_log(), LOG_DEBUG, LOG_ERR, transport::nhosts, transport::port, transport::retry_sleep, spamc_get_errno, SPAMC_MAXHOST, SPAMC_MAXSERV, and timeout_connect().

Referenced by message_filter(), and message_tell().

00436 {
00437     int numloops;
00438     int origerr = 0;
00439     int ret;
00440 #ifdef SPAMC_HAS_ADDRINFO
00441     struct addrinfo *res = NULL;
00442 #else
00443     int res = PF_INET;
00444 #endif
00445 
00446     char host[SPAMC_MAXHOST-1]; /* hostname, for logging */
00447     char port[SPAMC_MAXSERV-1]; /* port, for logging */
00448 
00449     int connect_retries, retry_sleep;
00450 
00451     assert(tp != 0);
00452     assert(sockptr != 0);
00453     assert(tp->nhosts > 0);
00454 
00455     /* default values */
00456     retry_sleep = tp->retry_sleep;
00457     connect_retries = tp->connect_retries;
00458     if (connect_retries == 0) {
00459       connect_retries = 3;
00460     }
00461     if (retry_sleep < 0) {
00462       retry_sleep = 1;
00463     }
00464 
00465     for (numloops = 0; numloops < connect_retries; numloops++) {
00466         const int hostix = numloops % tp->nhosts;
00467         int status, mysock;
00468 
00469                 /*--------------------------------------------------------
00470                 * We always start by creating the socket, as we get only
00471                 * one attempt to connect() on each one. If this fails,
00472                 * we're done.
00473                 */
00474 
00475 #ifdef SPAMC_HAS_ADDRINFO
00476         res = tp->hosts[hostix];
00477         while(res) {
00478             char *family = NULL;
00479             switch(res->ai_family) {
00480             case AF_INET:
00481                 family = "AF_INET";
00482                 break;
00483             case AF_INET6:
00484                 family = "AF_INET6";
00485                 break;
00486             default:
00487                 family = "Unknown";
00488                 break;
00489             }
00490 
00491             if ((ret = _opensocket(tp->flags, res, &mysock)) != EX_OK) {
00492                 res = res->ai_next;
00493                 continue;
00494             }
00495 
00496             getnameinfo(res->ai_addr, res->ai_addrlen,
00497                   host, sizeof(host),
00498                   port, sizeof(port),
00499                   NI_NUMERICHOST|NI_NUMERICSERV);
00500 
00501 #ifdef DO_CONNECT_DEBUG_SYSLOGS
00502             libspamc_log(tp->flags, CONNECT_DEBUG_LEVEL,
00503               "dbg: connect(%s) to spamd (host %s, port %s) (try #%d of %d)",
00504                       family, host, port, numloops + 1, connect_retries);
00505 #endif
00506 
00507             /* this is special-cased so that we have an address we can
00508              * safely use as an "always fail" test case */
00509             if (!strcmp(host, "255.255.255.255")) {
00510               libspamc_log(tp->flags, LOG_ERR,
00511                           "connect to spamd on %s failed, broadcast addr",
00512                           host);
00513               status = -1;
00514             }
00515             else {
00516               status = timeout_connect(mysock, res->ai_addr, res->ai_addrlen);
00517             }
00518 
00519 #else
00520             struct sockaddr_in addrbuf;
00521             const char *ipaddr;
00522             const char* family="AF_INET";
00523             if ((ret = _opensocket(tp->flags, PF_INET, &mysock)) != EX_OK)
00524               return ret;
00525             
00526             memset(&addrbuf, 0, sizeof(addrbuf));
00527             
00528             addrbuf.sin_family = AF_INET;
00529             addrbuf.sin_port = htons(tp->port);
00530             addrbuf.sin_addr = tp->hosts[hostix];
00531             
00532             ipaddr = inet_ntoa(addrbuf.sin_addr);
00533 
00534             /* make a copy in host, for logging (bug 5577) */
00535             strncpy (host, ipaddr, sizeof(host) - 1);
00536 
00537 #ifdef DO_CONNECT_DEBUG_SYSLOGS
00538             libspamc_log(tp->flags, LOG_DEBUG,
00539                          "dbg: connect(AF_INET) to spamd at %s (try #%d of %d)",
00540                          ipaddr, numloops + 1, connect_retries);
00541 #endif
00542 
00543             /* this is special-cased so that we have an address we can
00544              * safely use as an "always fail" test case */
00545             if (!strcmp(ipaddr, "255.255.255.255")) {
00546               libspamc_log(tp->flags, LOG_ERR,
00547                           "connect to spamd on %s failed, broadcast addr",
00548                           ipaddr);
00549               status = -1;
00550             }
00551             else {
00552               status = timeout_connect(mysock, (struct sockaddr *) &addrbuf,
00553                         sizeof(addrbuf));
00554             }
00555 
00556 #endif
00557 
00558             if (status != 0) {
00559                   origerr = spamc_get_errno();
00560                   closesocket(mysock);
00561 
00562 #ifndef _WIN32
00563                   libspamc_log(tp->flags, LOG_ERR,
00564                       "connect to spamd on %s failed, retrying (#%d of %d): %s",
00565                       host, numloops+1, connect_retries, strerror(origerr));
00566 #else
00567                   libspamc_log(tp->flags, LOG_ERR,
00568                       "connect to spamd on %s failed, retrying (#%d of %d): %d",
00569                       host, numloops+1, connect_retries, origerr);
00570 #endif
00571 
00572             } else {
00573 #ifdef DO_CONNECT_DEBUG_SYSLOGS
00574                   libspamc_log(tp->flags, CONNECT_DEBUG_LEVEL,
00575                           "dbg: connect(%s) to spamd done",family);
00576 #endif
00577                   *sockptr = mysock;
00578 
00579                   return EX_OK;
00580             }
00581 #ifdef SPAMC_HAS_ADDRINFO
00582             res = res->ai_next;
00583         }
00584 #endif
00585         sleep(retry_sleep);
00586     } /* for(numloops...) */
00587 
00588 #ifdef SPAMC_HAS_ADDRINFO
00589     for(numloops=0;numloops<tp->nhosts;numloops++) {
00590         freeaddrinfo(tp->hosts[numloops]);
00591     }
00592 #endif
00593 
00594     libspamc_log(tp->flags, LOG_ERR,
00595               "connection attempt to spamd aborted after %d retries",
00596               connect_retries);
00597 
00598     return _translate_connect_errno(origerr);
00599 }

static int _try_to_connect_unix struct transport tp,
int *  sockptr
[static]
 

Definition at line 361 of file libspamc.c.

References _opensocket(), _translate_connect_errno(), closesocket, EX_OK, EX_OSERR, transport::flags, libspamc_log(), LOG_ERR, transport::socketpath, and timeout_connect().

Referenced by message_filter(), and message_tell().

00362 {
00363 #ifndef _WIN32
00364     int mysock, status, origerr;
00365     struct sockaddr_un addrbuf;
00366 #ifdef SPAMC_HAS_ADDRINFO
00367     struct addrinfo hints, *res;
00368 #else
00369     int res = PF_UNIX;
00370 #endif
00371     int ret;
00372 
00373     assert(tp != 0);
00374     assert(sockptr != 0);
00375     assert(tp->socketpath != 0);
00376 
00377 #ifdef SPAMC_HAS_ADDRINFO
00378     memset(&hints, 0, sizeof(hints));
00379     hints.ai_family = PF_UNIX;
00380     hints.ai_socktype = SOCK_STREAM;
00381     hints.ai_protocol = 0;
00382     res = &hints;
00383 #endif
00384         /*----------------------------------------------------------------
00385          * If the socket itself can't be created, this is a fatal error.
00386          */
00387     if ((ret = _opensocket(tp->flags, res, &mysock)) != EX_OK)
00388         return ret;
00389 
00390     /* set up the UNIX domain socket */
00391     memset(&addrbuf, 0, sizeof addrbuf);
00392     addrbuf.sun_family = AF_UNIX;
00393     strncpy(addrbuf.sun_path, tp->socketpath, sizeof addrbuf.sun_path - 1);
00394     addrbuf.sun_path[sizeof addrbuf.sun_path - 1] = '\0';
00395 
00396 #ifdef DO_CONNECT_DEBUG_SYSLOGS
00397     libspamc_log(tp->flags, CONNECT_DEBUG_LEVEL, "dbg: connect(AF_UNIX) to spamd at %s",
00398            addrbuf.sun_path);
00399 #endif
00400 
00401     status = timeout_connect(mysock, (struct sockaddr *) &addrbuf, sizeof(addrbuf));
00402 
00403     origerr = errno;
00404 
00405     if (status >= 0) {
00406 #ifdef DO_CONNECT_DEBUG_SYSLOGS
00407         libspamc_log(tp->flags, CONNECT_DEBUG_LEVEL, "dbg: connect(AF_UNIX) ok");
00408 #endif
00409 
00410         *sockptr = mysock;
00411 
00412         return EX_OK;
00413     }
00414 
00415     libspamc_log(tp->flags, LOG_ERR, "connect(AF_UNIX) to spamd %s failed: %s",
00416            addrbuf.sun_path, strerror(origerr));
00417     closesocket(mysock);
00418 
00419     return _translate_connect_errno(origerr);
00420 #else
00421     (void) tp; /* not used. suppress compiler warning */
00422     (void) sockptr; /* not used. suppress compiler warning */
00423     return EX_OSERR;
00424 #endif
00425 }