Index: Makefile.PL =================================================================== RCS file: /cvsroot/spamassassin/spamassassin/Makefile.PL,v retrieving revision 1.119 diff -u -d -b -B -r1.119 Makefile.PL --- Makefile.PL 15 Oct 2003 16:01:40 -0000 1.119 +++ Makefile.PL 27 Dec 2003 00:01:53 -0000 @@ -149,10 +149,12 @@ my @datafiles = map { s,^rules/,,; $_ } (); my $datafiles = join(' ', (grep { /^[0-6][0-9]_/ } @datafiles), qw(user_prefs.template triplets.txt languages)); -# Only build spamd and spamc on non-Windows platforms +# Only build spamd on non-Windows platforms my @SPAMD_EXE_FILES = (); if (!RUNNING_ON_WINDOWS) { @SPAMD_EXE_FILES = ('spamd/spamc$(EXE_EXT)', 'spamd/spamd'); +} else { + @SPAMD_EXE_FILES = ('spamd/spamc$(EXE_EXT)'); } # See lib/ExtUtils/MakeMaker.pm for details of how to influence @@ -208,7 +210,7 @@ 'spamd/libspamc.so', 'spamd/libsslspamc.so', 'spamd/binaries.mk', 'spamd/config.h', 'spamd/config.status', 'spamd/config.cache', 'spamd/config.log', 'spamd/autom4te.cache', - 'qmail/qmail-spamc', + 'qmail/qmail-spamc', 'spamd/*.o', 'spamd/*.obj', 't/do_net', 't/log', ) }, @@ -847,6 +848,16 @@ } } + push(@code, "PREPROCESS = \$(PERL) build/preprocessor"); + + my($repository); + $repository = uc($SELF->{INSTALLDIRS}) || 'SITE'; + + foreach my $macro (qw(PREFIX SYSCONFDIR)) { + push(@code, macro_def('I_' . $macro, + macro_ref($repository . $macro))); + } + clean_MY_globals($self); return join("\n", @code); } @@ -859,10 +870,6 @@ my($repository); $repository = uc($SELF->{INSTALLDIRS}) || 'SITE'; - foreach my $macro (qw(PREFIX SYSCONFDIR)) { - push(@code, macro_def('I_' . $macro, - macro_ref($repository . $macro))); - } foreach my $macro (qw(DATA CONF LIB)) { push(@code, macro_def('I_' . $macro . 'DIR', macro_ref('INSTALL' . repository($repository) . $macro))); @@ -881,8 +888,6 @@ $code .= <<' EOD'; -PREPROCESS = $(PERL) build/preprocessor - FIXVARS = -Mvars \ -DVERSION="$(VERSION)" \ -DPREFIX="$(I_PREFIX)" \ @@ -911,24 +916,32 @@ spamd/libspamc.so: spamd/binaries.mk $(SPAMC_SOURCES) $(MAKE) -f spamd/binaries.mk $@ -spamd/libspamc.dll: spamd/binaries.mk $(SPAMC_SOURCES) - $(MAKE) -f spamd/binaries.mk $@ - spamd/spamc$(EXE_EXT): spamd/binaries.mk $(SPAMC_SOURCES) $(MAKE) -f spamd/binaries.mk $@ spamd/libsslspamc.so: spamd/binaries.mk $(SPAMC_SOURCES) $(MAKE) -f spamd/binaries.mk $@ -spamd/libsslspamc.dll: spamd/binaries.mk $(SPAMC_SOURCES) - $(MAKE) -f spamd/binaries.mk $@ - qmail/qmail-spamc: spamd/binaries.mk $(SPAMC_SOURCES) $(MAKE) -f spamd/binaries.mk $@ + EOD + if (!($^O =~ /^(?:mswin|dos|os2)/oi)) { + $code .= <<' EOD'; spamd/binaries.mk: spamd/configure cd spamd; ./configure --prefix="$(I_PREFIX)" --sysconfdir="$(I_SYSCONFDIR)" --datadir="$(I_DATADIR)" --enable-ssl="$(ENABLE_SSL)" + EOD + } else { + $code .= <<' EOD'; +spamd/binaries.mk: spamd/win32.config spamd/win32.mak + $(PERL) -MFile::SPec -MFile::Copy \ + -e "copy(q{spamd/win32.config}, q{spamd/config.h}); copy(q{spamd/win32.mak}, q{spamd/binaries.mk});" + EOD + + } + + $code .= <<' EOD'; conf__install: -$(MKPATH) $(B_CONFDIR) $(PERL) -MFile::Spec -MFile::Copy \ Index: spamd/libspamc.c =================================================================== RCS file: /cvsroot/spamassassin/spamassassin/spamd/libspamc.c,v retrieving revision 1.43 diff -u -d -b -B -r1.43 libspamc.c --- spamd/libspamc.c 25 Nov 2003 07:01:52 -0000 1.43 +++ spamd/libspamc.c 27 Dec 2003 00:01:54 -0000 @@ -10,18 +10,26 @@ #include "libspamc.h" #include "utils.h" -#include #include #include #include #include +#ifdef _WIN32 +/* simple macro that works for single strings without %m */ +#define syslog(x, y) fprintf(stderr, #y "\n") +#define strcasecmp stricmp +#define sleep Sleep +#else #include +#include #include #include #include #include #include #include +#define closesocket(x) close(x) +#endif #ifdef HAVE_SYSEXITS_H #include @@ -173,11 +181,20 @@ } #ifdef DO_CONNECT_DEBUG_SYSLOGS +#ifndef _WIN32 syslog (DEBUG_LEVEL, "dbg: create socket(%s)", typename); +#else + fprintf (stderr, "dbg: create socket(%s)\n", typename); +#endif #endif - if ( (*psock = socket(type, SOCK_STREAM, proto)) < 0 ) - { + if ( (*psock = socket(type, SOCK_STREAM, proto)) +#ifndef _WIN32 + < 0 +#else + == INVALID_SOCKET +#endif + ) { int origerr; /*-------------------------------------------------------- @@ -185,9 +202,13 @@ * this is pretty much fatal. Translate the error reason * into something the user can understand. */ +#ifndef _WIN32 origerr = errno; /* take a copy before syslog() */ - syslog (LOG_ERR, "socket(%s) to spamd failed: %m", typename); +#else + origerr = WSAGetLastError(); + printf ("socket(%s) to spamd failed: %d\n", typename, origerr); +#endif switch (origerr) { @@ -221,15 +242,26 @@ if ( type == PF_INET && setsockopt(*psock, 0, TCP_NODELAY, &one, sizeof one) != 0 ) { - switch(errno) + int origerrno; +#ifndef _WIN32 + origerr = errno; +#else + origerrno = WSAGetLastError(); +#endif + switch(origerr) { case EBADF: case ENOTSOCK: case ENOPROTOOPT: case EFAULT: +#ifndef _WIN32 syslog(LOG_ERR, "setsockopt(TCP_NODELAY) failed: %m"); - close (*psock); +#else + fprintf(stderr, + "setsockopt(TCP_NODELAY) failed: %d\n", origerr)); +#endif + closesocket (*psock); return EX_SOFTWARE; default: @@ -253,6 +285,7 @@ static int try_to_connect_unix (struct transport *tp, int *sockptr) { +#ifndef _WIN32 int mysock, status, origerr; struct sockaddr_un addrbuf; int ret; @@ -295,10 +327,12 @@ syslog(LOG_ERR, "connect(AF_UNIX) to spamd %s failed: %m", addrbuf.sun_path); - - close(mysock); + closesocket(mysock); return translate_connect_errno(origerr); +#else + return EX_OSERR; +#endif } /* @@ -323,7 +357,13 @@ #ifdef DO_CONNECT_DEBUG_SYSLOGS for (numloops = 0; numloops < tp->nhosts; numloops++) { - syslog(LOG_ERR, "dbg: %d/%d: %s", +#ifndef _WIN32 + syslog(LOG_ERR, + "dbg: %d/%d: %s", +#else + fprintf(stderr, + "dbg: %d/%d: %s\n", +#endif numloops+1, tp->nhosts, inet_ntoa(tp->hosts[numloops])); } #endif @@ -352,8 +392,13 @@ ipaddr = inet_ntoa(addrbuf.sin_addr); #ifdef DO_CONNECT_DEBUG_SYSLOGS - syslog (DEBUG_LEVEL, +#ifndef _WIN32 + syslog(DEBUG_LEVEL, "dbg: connect(AF_INET) to spamd at %s (try #%d of %d)", +#else + fprintf(stderr, + "dbg: connect(AF_INET) to spamd at %s (try #%d of %d\)\n", +#endif ipaddr, numloops+1, MAX_CONNECT_RETRIES); @@ -363,20 +407,33 @@ if (status != 0) { +#ifndef _WIN32 + origerr = errno; syslog (LOG_ERR, "connect(AF_INET) to spamd at %s failed, retrying (#%d of %d): %m", ipaddr, numloops+1, MAX_CONNECT_RETRIES); - - close(mysock); +#else + origerr = WSAGetLastError(); + fprintf (stderr, + "connect(AF_INET) to spamd at %s failed, retrying (#%d of %d): %d\n", + ipaddr, numloops+1, MAX_CONNECT_RETRIES, origerr); +#endif + closesocket(mysock); sleep(CONNECT_RETRY_SLEEP); } else { #ifdef DO_CONNECT_DEBUG_SYSLOGS +#ifndef _WIN32 syslog(DEBUG_LEVEL, "dbg: connect(AF_INET) to spamd at %s done", ipaddr); +#else + fprintf(stderr, + "dbg: connect(AF_INET) to spamd at %s done\n", + ipaddr); +#endif #endif *sockptr = mysock; @@ -384,7 +441,13 @@ } } - syslog (LOG_ERR, "connection attempt to spamd aborted after %d retries", +#ifndef _WIN32 + syslog (LOG_ERR, + "connection attempt to spamd aborted after %d retries", +#else + fprintf(stderr, + "connection attempt to spamd aborted after %d retries\n", +#endif MAX_CONNECT_RETRIES); return translate_connect_errno(origerr); @@ -411,7 +474,7 @@ message_read_raw(int fd, struct message *m){ clear_message(m); if((m->raw=malloc(m->max_len+1))==NULL) return EX_OSERR; - m->raw_len=full_read(fd, m->raw, m->max_len+1, m->max_len+1); + m->raw_len=full_read(fd, 1, m->raw, m->max_len+1, m->max_len+1); if(m->raw_len<=0){ free(m->raw); m->raw=NULL; m->raw_len=0; return EX_IOERR; @@ -434,7 +497,7 @@ if((m->raw=malloc(m->max_len+1))==NULL) return EX_OSERR; /* Find the DATA line */ - m->raw_len=full_read(fd, m->raw, m->max_len+1, m->max_len+1); + m->raw_len=full_read(fd, 1, m->raw, m->max_len+1, m->max_len+1); if(m->raw_len<=0){ free(m->raw); m->raw=NULL; m->raw_len=0; return EX_IOERR; @@ -506,7 +569,12 @@ return message_read_bsmtp(fd, m); default: - syslog(LOG_ERR, "message_read: Unknown mode %d\n", flags&SPAMC_MODE_MASK); +#ifndef _WIN32 + syslog(LOG_ERR, "message_read: Unknown mode %d", +#else + fprintf(stderr, "message_read: Unknown mode %d\n", +#endif + flags&SPAMC_MODE_MASK); return EX_USAGE; } } @@ -519,10 +587,14 @@ if (m->priv->flags&SPAMC_CHECK_ONLY) { if(m->is_spam==EX_ISSPAM || m->is_spam==EX_NOTSPAM){ - return full_write(fd, m->out, m->out_len); + return full_write(fd, 1, m->out, m->out_len); } else { - syslog(LOG_ERR, "oops! SPAMC_CHECK_ONLY is_spam: %d\n", m->is_spam); +#ifndef _WIN32 + syslog(LOG_ERR, "oops! SPAMC_CHECK_ONLY is_spam: %d", m->is_spam); +#else + fprintf(stderr, "oops! SPAMC_CHECK_ONLY is_spam: %d\n", m->is_spam); +#endif return -1; } } @@ -530,17 +602,17 @@ /* else we're not in CHECK_ONLY mode */ switch(m->type){ case MESSAGE_NONE: - syslog(LOG_ERR, "Cannot write this message, it's MESSAGE_NONE!\n"); + syslog(LOG_ERR, "Cannot write this message, it's MESSAGE_NONE!"); return -1; case MESSAGE_ERROR: - return full_write(fd, m->raw, m->raw_len); + return full_write(fd, 1, m->raw, m->raw_len); case MESSAGE_RAW: - return full_write(fd, m->out, m->out_len); + return full_write(fd, 1, m->out, m->out_len); case MESSAGE_BSMTP: - total=full_write(fd, m->pre, m->pre_len); + total=full_write(fd, 1, m->pre, m->pre_len); for(i=0; iout_len; ){ jlimit = (off_t) (sizeof(buffer)/sizeof(*buffer)-4); for(j=0; i < (off_t) m->out_len && @@ -557,12 +629,16 @@ buffer[j++]=m->out[i++]; } } - total+=full_write(fd, buffer, j); + total+=full_write(fd, 1, buffer, j); } - return total+full_write(fd, m->post, m->post_len); + return total+full_write(fd, 1, m->post, m->post_len); default: - syslog(LOG_ERR, "Unknown message type %d\n", m->type); +#ifndef _WIN32 + syslog(LOG_ERR, "Unknown message type %d", m->type); +#else + fprintf(stderr, "Unknown message type %d\n", m->type); +#endif return -1; } } @@ -574,9 +650,13 @@ if(m!=NULL && m->type!=MESSAGE_NONE) { message_write(out_fd, m); } - while((bytes=full_read(in_fd, buf, 8192, 8192))>0){ - if (bytes!=full_write(out_fd, buf, bytes)) { + while((bytes=full_read(in_fd, 1, buf, 8192, 8192))>0){ + if (bytes!=full_write(out_fd, 1, buf, bytes)) { +#ifndef _WIN32 syslog(LOG_ERR, "oops! message_dump of %d returned different", bytes); +#else + fprintf(stderr, "oops! message_dump of %d returned different\n", bytes); +#endif } } } @@ -596,7 +676,7 @@ if(flags&SPAMC_USE_SSL) { bytesread = ssl_timeout_read (ssl, buf+len, 1); } else { - bytesread = fd_timeout_read (sock, buf+len, 1); + bytesread = fd_timeout_read (sock, 0, buf+len, 1); } if(buf[len]=='\n') { @@ -614,7 +694,11 @@ } } +#ifndef _WIN32 syslog(LOG_ERR, "spamd responded with line of %d bytes, dying", len); +#else + fprintf(stderr, "spamd responded with line of %d bytes, dying\n", len); +#endif failureval = EX_TOOBIG; failure: @@ -693,30 +777,48 @@ m->score = _locale_safe_string_to_float (s_str, 20); m->threshold = _locale_safe_string_to_float (t_str, 20); + /* set bounds on these to ensure no buffer overflow in the sprintf */ + if (m->score > 1e10) + m->score = 1e10; + else if (m->score < -1e10) + m->score = -1e10; + if (m->threshold > 1e10) + m->threshold = 1e10; + else if (m->threshold < -1e10) + m->threshold = -1e10; + /* Format is "Spam: x; y / x" */ m->is_spam=strcasecmp("true", is_spam) == 0 ? EX_ISSPAM: EX_NOTSPAM; if(flags&SPAMC_CHECK_ONLY) { - m->out_len=snprintf (m->out, m->max_len+EXPANSION_ALLOWANCE, + m->out_len=sprintf (m->out, "%.1f/%.1f\n", m->score, m->threshold); } else if ((flags & SPAMC_REPORT_IFSPAM && m->is_spam == EX_ISSPAM) || (flags & SPAMC_REPORT)) { - m->out_len=snprintf (m->out, m->max_len+EXPANSION_ALLOWANCE, + m->out_len=sprintf (m->out, "%.1f/%.1f\n", m->score, m->threshold); } return EX_OK; } else if(sscanf(buf, "Content-length: %d", &m->content_length) == 1) { if (m->content_length < 0) { +#ifndef _WIN32 syslog(LOG_ERR, "spamd responded with bad Content-length '%s'", buf); +#else + fprintf(stderr, "spamd responded with bad Content-length '%s'\n", buf); +#endif return EX_PROTOCOL; } return EX_OK; } +#ifndef _WIN32 syslog(LOG_ERR, "spamd responded with bad header '%s'", buf); +#else + fprintf(stderr, "spamd responded with bad header '%s'\n", buf); +#endif return EX_PROTOCOL; } @@ -733,7 +835,7 @@ int response; int failureval; SSL_CTX* ctx; - SSL* ssl; + SSL* ssl = NULL; SSL_METHOD *meth; if (flags&SPAMC_USE_SSL) { @@ -760,25 +862,35 @@ /* Build spamd protocol header */ if(flags & SPAMC_CHECK_ONLY) - len=snprintf(buf, bufsiz, "CHECK %s\r\n", PROTOCOL_VERSION); + strcpy(buf, "CHECK "); else if(flags & SPAMC_REPORT_IFSPAM) - len=snprintf(buf, bufsiz, "REPORT_IFSPAM %s\r\n", PROTOCOL_VERSION); + strcpy(buf, "REPORT_IFSPAM "); else if(flags & SPAMC_REPORT) - len=snprintf(buf, bufsiz, "REPORT %s\r\n", PROTOCOL_VERSION); + strcpy(buf, "REPORT "); else if(flags & SPAMC_SYMBOLS) - len=snprintf(buf, bufsiz, "SYMBOLS %s\r\n", PROTOCOL_VERSION); + strcpy(buf, "SYMBOLS "); else - len=snprintf(buf, bufsiz, "PROCESS %s\r\n", PROTOCOL_VERSION); + strcpy(buf, "PROCESS "); - if(len<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; } - if(username!=NULL){ - len+=i=snprintf(buf+len, bufsiz-len, "User: %s\r\n", username); - if(i<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; } + len = strlen(buf); + if(len+strlen(PROTOCOL_VERSION)+2 >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; } + + strcat(buf, PROTOCOL_VERSION); + strcat(buf, "\r\n"); + len = strlen(buf); + + if(username!=NULL) { + if (strlen(username)+8 >= (bufsiz - len)) { free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; } + strcpy(buf+len, "User: "); + strcat(buf+len, username); + strcat(buf+len, "\r\n"); + len += strlen(buf+len); } - len+=i=snprintf(buf+len, bufsiz-len, "Content-length: %d\r\n", m->msg_len); - if(i<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; } - len+=i=snprintf(buf+len, bufsiz-len, "\r\n"); - if(i<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; } + if ((m->msg_len > 9999999) || ((len + 27) >= (bufsiz - len))) { + free(m->out); m->out=m->msg; m->out_len=m->msg_len; + return EX_OSERR; + } + len += sprintf(buf+len, "Content-length: %d\r\n\r\n", m->msg_len); libspamc_timeout = m->timeout; @@ -790,7 +902,7 @@ if ( rc != EX_OK ) { free(m->out); m->out=m->msg; m->out_len=m->msg_len; - return i; + return EX_OSERR; } if(flags&SPAMC_USE_SSL) { @@ -808,8 +920,8 @@ SSL_write(ssl, m->msg, m->msg_len); #endif } else { - full_write(sock, buf, len); - full_write(sock, m->msg, m->msg_len); + full_write(sock, 0, buf, len); + full_write(sock, 0, m->msg, m->msg_len); shutdown(sock, SHUT_WR); } @@ -818,14 +930,22 @@ if (failureval != EX_OK) { goto failure; } if(sscanf(buf, "SPAMD/%18s %d %*s", versbuf, &response)!=2) { +#ifndef _WIN32 syslog(LOG_ERR, "spamd responded with bad string '%s'", buf); +#else + fprintf(stderr, "spamd responded with bad string '%s'\n", buf); +#endif failureval = EX_PROTOCOL; goto failure; } versbuf[19] = '\0'; version = _locale_safe_string_to_float (versbuf, 20); if (version < 1.0) { +#ifndef _WIN32 syslog(LOG_ERR, "spamd responded with bad version string '%s'", versbuf); +#else + fprintf(stderr, "spamd responded with bad version string '%s'\n", versbuf); +#endif failureval = EX_PROTOCOL; goto failure; } @@ -848,7 +968,7 @@ len = 0; /* overwrite those headers */ if (flags&SPAMC_CHECK_ONLY) { - close(sock); sock = -1; + closesocket(sock); sock = -1; if (m->is_spam == EX_TOOBIG) { /* We should have gotten headers back... Damnit. */ failureval = EX_PROTOCOL; goto failure; @@ -874,7 +994,7 @@ m->max_len+EXPANSION_ALLOWANCE+1-m->out_len, m->max_len+EXPANSION_ALLOWANCE+1-m->out_len); } else{ - len = full_read (sock, m->out+m->out_len, + len = full_read (sock, 0, m->out+m->out_len, m->max_len+EXPANSION_ALLOWANCE+1-m->out_len, m->max_len+EXPANSION_ALLOWANCE+1-m->out_len); } @@ -886,12 +1006,16 @@ m->out_len+=len; shutdown(sock, SHUT_RD); - close(sock); sock = -1; + closesocket(sock); sock = -1; } libspamc_timeout = 0; if(m->out_len!=m->content_length) { +#ifndef _WIN32 syslog(LOG_ERR, "failed sanity check, %d bytes claimed, %d bytes seen", +#else + fprintf(stderr, "failed sanity check, %d bytes claimed, %d bytes seen\n", +#endif m->content_length, m->out_len); failureval = EX_PROTOCOL; goto failure; } @@ -901,7 +1025,7 @@ failure: free(m->out); m->out=m->msg; m->out_len=m->msg_len; if (sock != -1) { - close(sock); + closesocket(sock); } libspamc_timeout = 0; @@ -936,7 +1060,7 @@ FAIL: if(flags&SPAMC_CHECK_ONLY){ - full_write(out_fd, "0/0\n", 4); + full_write(out_fd, 1, "0/0\n", 4); message_cleanup(&m); return EX_NOTSPAM; } else { @@ -1032,14 +1156,26 @@ struct hostent *hp = 0; char **addrp; +#ifdef _WIN32 + // Start Winsock up + WSADATA wsaData; + int nCode; + if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) { + printf("WSAStartup() returned error code %d\n", nCode); + return EX_OSERR; + } + +#endif + assert(tp != 0); switch ( tp->type ) { +#ifndef _WIN32 case TRANSPORT_UNIX: assert(tp->socketpath != 0); return EX_OK; - +#endif case TRANSPORT_LOCALHOST: tp->hosts[0].s_addr = inet_addr("127.0.0.1"); tp->nhosts = 1; @@ -1050,7 +1186,11 @@ { int origherr = h_errno; /* take a copy before syslog() */ +#ifndef _WIN32 syslog (LOG_ERR, "gethostbyname(%s) failed: h_errno=%d", +#else + fprintf (stderr, "gethostbyname(%s) failed: h_errno=%d\n", +#endif tp->hostname, origherr); switch (origherr) { @@ -1094,7 +1234,11 @@ for (addrp = hp->h_addr_list; *addrp; addrp++) { if (tp->nhosts >= TRANSPORT_MAX_HOSTS-1) { +#ifndef _WIN32 syslog (LOG_ERR, "hit limit of %d hosts, ignoring remainder", TRANSPORT_MAX_HOSTS-1); +#else + fprintf (stderr, "hit limit of %d hosts, ignoring remainder\n", TRANSPORT_MAX_HOSTS-1); +#endif break; } @@ -1148,13 +1292,14 @@ char inputstr[99], cmpbuf1[99], cmpbuf2[99]; float output; - snprintf (inputstr, 99, "%f", input); + /* sprintf instead of snprintf is safe here because it is only a controlled test */ + sprintf (inputstr, "%f", input); output = _locale_safe_string_to_float (inputstr, 99); if (input == output) { return; } /* could be a rounding error. print as string and compare those */ - snprintf (cmpbuf1, 98, "%f", input); - snprintf (cmpbuf2, 98, "%f", output); + sprintf (cmpbuf1, "%f", input); + sprintf (cmpbuf2, "%f", output); if (!strcmp (cmpbuf1, cmpbuf2)) { return; } printf ("FAIL: input=%f != output=%f\n", input, output); Index: spamd/libspamc.h =================================================================== RCS file: /cvsroot/spamassassin/spamassassin/spamd/libspamc.h,v retrieving revision 1.15 diff -u -d -b -B -r1.15 libspamc.h --- spamd/libspamc.h 14 Aug 2003 18:23:32 -0000 1.15 +++ spamd/libspamc.h 27 Dec 2003 00:01:55 -0000 @@ -9,11 +9,38 @@ #ifndef LIBSPAMC_H #define LIBSPAMC_H 1 +#ifdef _WIN32 +#include +#else +#include #include #include #include -#include +#endif #include + +#ifdef _WIN32 +#define EX_OK 0 +#define EX_USAGE 64 +#define EX_DATAERR 65 +#define EX_NOINPUT 66 +#define EX_NOUSER 67 +#define EX_NOHOST 68 +#define EX_UNAVAILABLE 69 +#define EX_SOFTWARE 70 +#define EX_OSERR 71 +#define EX_OSFILE 72 +#define EX_CANTCREAT 73 +#define EX_IOERR 74 +#define EX_TEMPFAIL 75 +#define EX_PROTOCOL 76 +#define EX_NOPERM 77 +#define EX_CONFIG 78 + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 + +#endif #define EX_NOTSPAM 0 #define EX_ISSPAM 1 Index: spamd/spamc.c =================================================================== RCS file: /cvsroot/spamassassin/spamassassin/spamd/spamc.c,v retrieving revision 1.78 diff -u -d -b -B -r1.78 spamc.c --- spamd/spamc.c 15 Nov 2003 02:46:25 -0000 1.78 +++ spamd/spamc.c 27 Dec 2003 00:01:55 -0000 @@ -9,17 +8,21 @@ #include "libspamc.h" #include "utils.h" -#include #include #include #include +#ifdef _WIN32 +#define syslog(x, y) fprintf(stderr, #y "\n") +#else #include +#include +#include #include #include #include #include -#include #include +#endif #ifdef HAVE_SYSEXITS_H #include @@ -48,13 +51,19 @@ || (defined(__sgi)) /* IRIX */ \ || (defined(__osf__)) /* Digital UNIX */ \ || (defined(hpux) || defined(__hpux)) /* HPUX */ \ - || (defined(_WIN32) || defined(__CYGWIN__)) /* CygWin, Win32 */ + || (defined(__CYGWIN__)) /* CygWin, Win32 */ extern int optind; extern char *optarg; #endif +#ifdef _WIN32 +#include "getopt.h" +char* __progname = "spamc"; +#endif + + /* safe fallback defaults to on now - CRH */ int flags = SPAMC_RAW_MODE | SPAMC_SAFE_FALLBACK; @@ -93,7 +102,13 @@ { int opt, i, j; - while(-1 != (opt = getopt(argc,argv,"-BcrRd:e:fhyp:t:s:u:xSHU:"))) + while(-1 != (opt = getopt(argc,argv, +#ifndef _WIN32 + "-BcrRd:e:fhyp:t:s:u:xSHU:" +#else + "-BcrRd:fhyp:t:s:u:xSH" +#endif +))) { switch(opt) { @@ -102,12 +117,14 @@ flags |= SPAMC_RANDOMIZE_HOSTS; break; } +#ifndef _WIN32 case 'U': { ptrn->type = TRANSPORT_UNIX; ptrn->socketpath = optarg; break; } +#endif case 'B': { flags = (flags & ~SPAMC_MODE_MASK) | SPAMC_BSMTP_MODE; @@ -139,6 +156,7 @@ ptrn->hostname = optarg; /* fix the ptr to point to this string */ break; } +#ifndef _WIN32 case 'e': { if((exec_argv=malloc(sizeof(*exec_argv)*(argc-optind+2)))==NULL) @@ -149,6 +167,7 @@ exec_argv[i]=NULL; return EX_OK; } +#endif case 'p': { ptrn->port = atoi(optarg); @@ -210,6 +229,7 @@ *fd=STDOUT_FILENO; return; } +#ifndef _WIN32 if(pipe(fds)){ syslog(LOG_ERR, "pipe creation failed: %m"); exit(EX_OSERR); @@ -237,6 +257,9 @@ close(fds[0]); /* no point in leaving extra fds lying around */ execv(exec_argv[0], exec_argv); syslog(LOG_ERR, "exec failed: %m"); +#else + fprintf(stderr, "exec failed: %d\n", errno); +#endif exit(EX_OSERR); } @@ -256,8 +279,10 @@ do_libspamc_unit_tests(); #endif +#ifndef _WIN32 openlog ("spamc", LOG_CONS|LOG_PID, LOG_MAIL); signal (SIGPIPE, SIG_IGN); +#endif read_args(argc,argv, &max_size, &username, &trans); @@ -274,6 +299,7 @@ * to our own buffer - then this won't arise as a problem. */ +#ifndef _WIN32 if(NULL == username) { static char userbuf[256]; @@ -289,6 +315,7 @@ userbuf[sizeof userbuf - 1] = '\0'; username = userbuf; } +#endif if ((flags & SPAMC_RANDOMIZE_HOSTS) != 0) { /* we don't need strong randomness; this is just so we pick @@ -304,57 +331,59 @@ * we connect to the spam daemon. Mainly this involves lookup up the * hostname and getting the IP addresses to connect to. */ - if ( (ret = transport_setup(&trans, flags)) != EX_OK ) - goto FAIL; - - + if ( (ret = transport_setup(&trans, flags)) == EX_OK ) { out_fd=-1; m.type = MESSAGE_NONE; m.max_len = max_size; m.timeout = timeout; ret=message_read(STDIN_FILENO, flags, &m); - if(ret!=EX_OK) goto FAIL; + if(ret==EX_OK) { ret=message_filter(&trans, username, flags, &m); - if(ret!=EX_OK) goto FAIL; + if(ret==EX_OK) { get_output_fd(&out_fd); - if(message_write(out_fd, &m)<0) { - goto FAIL; - } + if(message_write(out_fd, &m)>=0) { result = m.is_spam; if ((flags&SPAMC_CHECK_ONLY) && result != EX_TOOBIG) { message_cleanup (&m); - return result; + ret = result; } else { message_cleanup (&m); + } +#ifdef _WIN32 + WSACleanup(); +#endif return ret; } + } + } + } -FAIL: + FAIL: get_output_fd(&out_fd); result = m.is_spam; if((flags&SPAMC_CHECK_ONLY) && result != EX_TOOBIG) { /* probably, the write to stdout failed; we can still report exit code */ message_cleanup (&m); - return result; - + ret = result; } else if(flags&SPAMC_CHECK_ONLY || flags&SPAMC_REPORT || flags&SPAMC_REPORT_IFSPAM) { - full_write(out_fd, "0/0\n", 4); + full_write(out_fd, 1, "0/0\n", 4); message_cleanup (&m); - return EX_NOTSPAM; - + ret = EX_NOTSPAM; } else { message_dump(STDIN_FILENO, out_fd, &m); message_cleanup (&m); if (ret == EX_TOOBIG) { - return 0; + ret = 0; } else if (flags & SPAMC_SAFE_FALLBACK) { - return EX_OK; - } else { - return ret; + ret = EX_OK; } } +#ifdef _WIN32 + WSACleanup(); +#endif + return ret; } Index: spamd/spamd.raw =================================================================== RCS file: /cvsroot/spamassassin/spamassassin/spamd/spamd.raw,v retrieving revision 1.234 diff -u -d -b -B -r1.234 spamd.raw --- spamd/spamd.raw 4 Dec 2003 21:20:30 -0000 1.234 +++ spamd/spamd.raw 27 Dec 2003 00:01:58 -0000 @@ -141,6 +141,7 @@ 'ssl' => \$opt{'ssl'}, 'server-key=s' => \$opt{'server-key'}, 'server-cert=s' => \$opt{'server-cert'}, + 'stdout=s' => \$opt{'stdout'}, # will be stripped in future release 'add-from!' => sub { warn "The --add-from option has been removed\n" }, @@ -152,6 +153,13 @@ $opt{'help'} and pod2usage(-exitval => $resphash{'EX_USAGE'}, -verbose => 0, -message => 'For more details, use "man spamd"'); +if (!$opt{'daemonize'} && defined($opt{'stdout'})) { + STDOUT->autoflush(1); + STDERR->autoflush(1); + open STDOUT,">$opt{'stdout'}" or die "Could not redirect STDOUT: $!\n"; + open STDERR,'>&STDOUT' or die "Can't duplicate stdout: $!\n"; +} + # bug 2228: make the values of (almost) all parameters which accept file paths # absolute, so they are still valid after daemonize() foreach my $opt (qw( @@ -280,7 +288,7 @@ # Do whitelist later in tmp dir. Side effect: this will be done as -u user. -if ($log_facility ne 'stderr') { +if (($log_facility ne 'stderr') && ($log_socket ne 'none')) { eval { setlogsock($log_socket); syslog('debug', "spamd starting"); # required to actually open the socket Index: spamd/utils.c =================================================================== RCS file: /cvsroot/spamassassin/spamassassin/spamd/utils.c,v retrieving revision 1.8 diff -u -d -b -B -r1.8 utils.c --- spamd/utils.c 28 May 2003 06:19:01 -0000 1.8 +++ spamd/utils.c 27 Dec 2003 00:01:58 -0000 @@ -6,12 +6,15 @@ * "License". */ +#ifndef _WIN32 #include +#include +#else +typedef int ssize_t; +#endif #include #include #include -#include -#include #include #include "utils.h" @@ -25,7 +28,7 @@ /* Apr 24, 2003 sjf: made full_read and full_write void* params */ /* -------------------------------------------------------------------------- */ - +#ifndef _WIN32 typedef void sigfunc(int); /* for signal handlers */ sigfunc* sig_catch(int sig, void (*f)(int)) @@ -41,23 +44,38 @@ static void catch_alrm(int x) { UNUSED_VARIABLE(x); } +#endif ssize_t -fd_timeout_read (int fd, void *buf, size_t nbytes) +fd_timeout_read (int fd, char fdflag, void *buf, size_t nbytes) { ssize_t nred; + int origerr; +#ifndef _WIN32 sigfunc* sig; sig = sig_catch(SIGALRM, catch_alrm); if (libspamc_timeout > 0) { alarm(libspamc_timeout); } +#endif do { + if (fdflag) { nred = read (fd, buf, nbytes); - } while(nred < 0 && errno == EAGAIN); + origerr = errno; + } else { + nred = recv (fd, buf, nbytes, 0); +#ifndef _WIN32 + origerr = errno; +#else + origerr = WSAGetLastError(); +#endif + } + } while(nred < 0 && origerr == EWOULDBLOCK); - if(nred < 0 && errno == EINTR) +#ifndef _WIN32 + if(nred < 0 && origerr == EINTR) errno = ETIMEDOUT; if (libspamc_timeout > 0) { @@ -66,6 +84,7 @@ /* restore old signal handler */ sig_catch(SIGALRM, sig); +#endif return nred; } @@ -74,7 +93,6 @@ ssl_timeout_read (SSL *ssl, void *buf, int nbytes) { int nred; - sigfunc* sig; #ifndef SPAMC_SSL UNUSED_VARIABLE(ssl); @@ -82,10 +100,14 @@ UNUSED_VARIABLE(nbytes); #endif +#ifndef _WIN32 + sigfunc* sig; + sig = sig_catch(SIGALRM, catch_alrm); if (libspamc_timeout > 0) { alarm(libspamc_timeout); } +#endif do { #ifdef SPAMC_SSL @@ -93,8 +115,9 @@ #else nred = 0; /* never used */ #endif - } while(nred < 0 && errno == EAGAIN); + } while(nred < 0 && errno == EWOULDBLOCK); +#ifndef _WIN32 if(nred < 0 && errno == EINTR) errno = ETIMEDOUT; @@ -104,6 +127,7 @@ /* restore old signal handler */ sig_catch(SIGALRM, sig); +#endif return nred; } @@ -111,14 +135,14 @@ /* -------------------------------------------------------------------------- */ int -full_read (int fd, void *vbuf, int min, int len) +full_read (int fd, char fdflag, void *vbuf, int min, int len) { unsigned char *buf = (unsigned char *)vbuf; int total; int thistime; for (total = 0; total < min; ) { - thistime = fd_timeout_read (fd, buf+total, len-total); + thistime = fd_timeout_read (fd, fdflag, buf+total, len-total); if (thistime < 0) { return -1; @@ -156,17 +180,27 @@ } int -full_write (int fd, const void *vbuf, int len) +full_write (int fd, char fdflag, const void *vbuf, int len) { const unsigned char *buf = (const unsigned char *)vbuf; int total; int thistime; + int origerr; for (total = 0; total < len; ) { + if (fdflag) { thistime = write (fd, buf+total, len-total); - + origerr = errno; + } else { + thistime = send (fd, buf+total, len-total, 0); +#ifndef _WIN32 + origerr = errno; +#else + origerr = WSAGetLastError(); +#endif + } if (thistime < 0) { - if(EINTR == errno || EAGAIN == errno) continue; + if(EINTR == origerr || EWOULDBLOCK == origerr) continue; return thistime; /* always an error for writes */ } total += thistime; Index: spamd/utils.h =================================================================== RCS file: /cvsroot/spamassassin/spamassassin/spamd/utils.h,v retrieving revision 1.6 diff -u -d -b -B -r1.6 utils.h --- spamd/utils.h 9 Jun 2003 18:21:28 -0000 1.6 +++ spamd/utils.h 27 Dec 2003 00:01:58 -0000 @@ -15,13 +15,65 @@ typedef int SSL_CTX; typedef int SSL_METHOD; #endif +#ifdef _WIN32 +#include +typedef int ssize_t; +// +// BSD-compatible socket error codes for Win32 +// -ssize_t fd_timeout_read (int fd, void *, size_t ); +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY +#define ENOTSOCK WSAENOTSOCK +#define EDESTADDRREQ WSAEDESTADDRREQ +#define EMSGSIZE WSAEMSGSIZE +#define EPROTOTYPE WSAEPROTOTYPE +#define ENOPROTOOPT WSAENOPROTOOPT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EADDRINUSE WSAEADDRINUSE +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define ENETDOWN WSAENETDOWN +#define ENETUNREACH WSAENETUNREACH +#define ENETRESET WSAENETRESET +#define ECONNABORTED WSAECONNABORTED +#define ECONNRESET WSAECONNRESET +#define ENOBUFS WSAENOBUFS +#define EISCONN WSAEISCONN +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define ELOOP WSAELOOP +// #define ENAMETOOLONG WSAENAMETOOLONG +#define EHOSTDOWN WSAEHOSTDOWN +#define EHOSTUNREACH WSAEHOSTUNREACH +// #define ENOTEMPTY WSAENOTEMPTY +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE + +// NOTE: these are not errno constants in UNIX! +#define HOST_NOT_FOUND WSAHOST_NOT_FOUND +#define TRY_AGAIN WSATRY_AGAIN +#define NO_RECOVERY WSANO_RECOVERY +#define NO_DATA WSANO_DATA + +#endif + +ssize_t fd_timeout_read (int fd, char fdflag, void *, size_t ); int ssl_timeout_read (SSL *ssl, void *, int ); /* these are fd-only, no SSL support */ -int full_read(int fd, void *buf, int min, int len); +int full_read(int fd, char fdflag, void *buf, int min, int len); int full_read_ssl(SSL *ssl, unsigned char *buf, int min, int len); -int full_write(int fd, const void *buf, int len); +int full_write(int fd, char fdflag, const void *buf, int len); #endif