You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by pa...@apache.org on 2005/04/03 06:13:48 UTC

svn commit: r159881 - in spamassassin/trunk/spamc: libspamc.c libspamc.h spamc.c

Author: parker
Date: Sat Apr  2 20:13:47 2005
New Revision: 159881

URL: http://svn.apache.org/viewcvs?view=rev&rev=159881
Log:
Bug1201: Fix binary incompatibility in libspamc

Modified:
    spamassassin/trunk/spamc/libspamc.c
    spamassassin/trunk/spamc/libspamc.h
    spamassassin/trunk/spamc/spamc.c

Modified: spamassassin/trunk/spamc/libspamc.c
URL: http://svn.apache.org/viewcvs/spamassassin/trunk/spamc/libspamc.c?view=diff&r1=159880&r2=159881
==============================================================================
--- spamassassin/trunk/spamc/libspamc.c (original)
+++ spamassassin/trunk/spamc/libspamc.c Sat Apr  2 20:13:47 2005
@@ -765,7 +765,8 @@
 }
 
 static int
-_handle_spamd_header(struct message *m, int flags, char *buf, int len)
+_handle_spamd_header(struct message *m, int flags, char *buf, int len,
+		     int *islearned)
 {
     char is_spam[6];
     char s_str[21], t_str[21];
@@ -818,10 +819,10 @@
     }
     else if (sscanf(buf, "Learned: %3s", is_learned) == 1) {
         if(strcmp(is_learned, "yes") == 0 || strcmp(is_learned, "Yes") == 0) {
-	  m->is_learned = 1;
+	  *islearned = 1;
 	}
 	else if(strcmp(is_learned, "no") == 0 || strcmp(is_learned, "No") == 0) {
-	  m->is_learned = 0;
+	  *islearned = 0;
 	}
 	else {
 	  libspamc_log(flags, LOG_ERR, "spamd responded with bad Learned-state '%s'",
@@ -835,8 +836,8 @@
     return EX_PROTOCOL;
 }
 
-int message_filter(struct transport *tp, const char *username, int learntype,
-		   int flags, struct message *m)
+int message_filter(struct transport *tp, const char *username,
+                   int flags, struct message *m)
 {
     char buf[8192];
     size_t bufsiz = (sizeof(buf) / sizeof(*buf)) - 4; /* bit of breathing room */
@@ -844,7 +845,6 @@
     int sock = -1;
     int rc;
     char versbuf[20];
-    char strlearntype[1];
     float version;
     int response;
     int failureval;
@@ -876,7 +876,7 @@
     m->out_len = 0;
 
     /* Build spamd protocol header */
-    if(flags & SPAMC_CHECK_ONLY)
+    if (flags & SPAMC_CHECK_ONLY)
 	strcpy(buf, "CHECK ");
     else if (flags & SPAMC_REPORT_IFSPAM)
 	strcpy(buf, "REPORT_IFSPAM ");
@@ -884,8 +884,6 @@
 	strcpy(buf, "REPORT ");
     else if (flags & SPAMC_SYMBOLS)
 	strcpy(buf, "SYMBOLS ");
-    else if (flags & SPAMC_LEARN )
-        strcpy(buf, "LEARN ");
     else
 	strcpy(buf, "PROCESS ");
 
@@ -899,21 +897,6 @@
     strcat(buf, "\r\n");
     len = strlen(buf);
 
-
-    if (flags & SPAMC_LEARN) {
-        if ((learntype > 2) | (learntype < 0 )) {
-	  free(m->out);
-  	  m->out = m->msg;
-  	  m->out_len = m->msg_len;
-	  return EX_OSERR;
-	}
-	sprintf(strlearntype,"%d",learntype);
-	strcpy(buf + len, "Learn-type: ");
-	strcat(buf + len, strlearntype);
-	strcat(buf + len, "\r\n");
-	len += strlen(buf + len);
-    }
-
     if (username != NULL) {
 	if (strlen(username) + 8 >= (bufsiz - len)) {
 	    _use_msg_for_out(m);
@@ -988,7 +971,6 @@
     m->score = 0;
     m->threshold = 0;
     m->is_spam = EX_TOOBIG;
-    m->is_learned = 0;
     while (1) {
 	failureval =
 	    _spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
@@ -999,8 +981,8 @@
 	if (len == 0 && buf[0] == '\0') {
 	    break;		/* end of headers */
 	}
-
-	if (_handle_spamd_header(m, flags, buf, len) < 0) {
+	int throwaway;
+	if (_handle_spamd_header(m, flags, buf, len, &throwaway) < 0) {
 	    failureval = EX_PROTOCOL;
 	    goto failure;
 	}
@@ -1018,12 +1000,6 @@
 	}
 	return EX_OK;
     }
-    else if (flags & SPAMC_LEARN) {
-        shutdown(sock, SHUT_RD);
-	closesocket(sock);
-	sock = -1;
-	return EX_OK;
-    }
     else {
 	if (m->content_length < 0) {
 	    /* should have got a length too. */
@@ -1093,7 +1069,7 @@
 }
 
 
-int message_process(struct transport *trans, char *username, int learntype, int max_size,
+int message_process(struct transport *trans, char *username, int max_size,
 		    int in_fd, int out_fd, const int flags)
 {
     int ret;
@@ -1105,7 +1081,7 @@
     ret = message_read(in_fd, flags, &m);
     if (ret != EX_OK)
         goto FAIL;
-    ret = message_filter(trans, username, learntype, flags, &m);
+    ret = message_filter(trans, username, flags, &m);
     if (ret != EX_OK)
         goto FAIL;
     if (message_write(out_fd, &m) < 0)
@@ -1130,6 +1106,197 @@
     }
 }
 
+int message_learn(struct transport *tp, const char *username, int flags,
+		  struct message *m, int learntype, int *islearned)
+{
+    char buf[8192];
+    size_t bufsiz = (sizeof(buf) / sizeof(*buf)) - 4; /* bit of breathing room */
+    size_t len;
+    int sock = -1;
+    int rc;
+    char versbuf[20];
+    char strlearntype[1];
+    float version;
+    int response;
+    int failureval;
+    SSL_CTX *ctx = NULL;
+    SSL *ssl = NULL;
+    SSL_METHOD *meth;
+
+    if (flags & SPAMC_USE_SSL) {
+#ifdef SPAMC_SSL
+	SSLeay_add_ssl_algorithms();
+	meth = SSLv2_client_method();
+	SSL_load_error_strings();
+	ctx = SSL_CTX_new(meth);
+#else
+	UNUSED_VARIABLE(ssl);
+	UNUSED_VARIABLE(meth);
+	UNUSED_VARIABLE(ctx);
+	libspamc_log(flags, LOG_ERR, "spamc not built with SSL support");
+	return EX_SOFTWARE;
+#endif
+    }
+
+    m->is_spam = EX_TOOBIG;
+    if ((m->outbuf = malloc(m->max_len + EXPANSION_ALLOWANCE + 1)) == NULL) {
+	failureval = EX_OSERR;
+	goto failure;
+    }
+    m->out = m->outbuf;
+    m->out_len = 0;
+
+    /* Build spamd protocol header */
+    strcpy(buf, "LEARN ");
+
+    len = strlen(buf);
+    if (len + strlen(PROTOCOL_VERSION) + 2 >= bufsiz) {
+	_use_msg_for_out(m);
+	return EX_OSERR;
+    }
+
+    strcat(buf, PROTOCOL_VERSION);
+    strcat(buf, "\r\n");
+    len = strlen(buf);
+
+    if ((learntype > 2) | (learntype < 0 )) {
+      free(m->out);
+      m->out = m->msg;
+      m->out_len = m->msg_len;
+      return EX_OSERR;
+    }
+    sprintf(strlearntype,"%d",learntype);
+    strcpy(buf + len, "Learn-type: ");
+    strcat(buf + len, strlearntype);
+    strcat(buf + len, "\r\n");
+    len += strlen(buf + len);
+
+    if (username != NULL) {
+	if (strlen(username) + 8 >= (bufsiz - len)) {
+	    _use_msg_for_out(m);
+	    return EX_OSERR;
+	}
+	strcpy(buf + len, "User: ");
+	strcat(buf + len, username);
+	strcat(buf + len, "\r\n");
+	len += strlen(buf + len);
+    }
+    if ((m->msg_len > 9999999) || ((len + 27) >= (bufsiz - len))) {
+	_use_msg_for_out(m);
+	return EX_OSERR;
+    }
+    len += sprintf(buf + len, "Content-length: %d\r\n\r\n", m->msg_len);
+
+    libspamc_timeout = m->timeout;
+
+    if (tp->socketpath)
+	rc = _try_to_connect_unix(tp, &sock);
+    else
+	rc = _try_to_connect_tcp(tp, &sock);
+
+    if (rc != EX_OK) {
+	_use_msg_for_out(m);
+	return rc;      /* use the error code try_to_connect_*() gave us. */
+    }
+
+    if (flags & SPAMC_USE_SSL) {
+#ifdef SPAMC_SSL
+	ssl = SSL_new(ctx);
+	SSL_set_fd(ssl, sock);
+	SSL_connect(ssl);
+#endif
+    }
+
+    /* Send to spamd */
+    if (flags & SPAMC_USE_SSL) {
+#ifdef SPAMC_SSL
+	SSL_write(ssl, buf, len);
+	SSL_write(ssl, m->msg, m->msg_len);
+#endif
+    }
+    else {
+	full_write(sock, 0, buf, len);
+	full_write(sock, 0, m->msg, m->msg_len);
+	shutdown(sock, SHUT_WR);
+    }
+
+    /* ok, now read and parse it.  SPAMD/1.2 line first... */
+    failureval =
+	_spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
+    if (failureval != EX_OK) {
+	goto failure;
+    }
+
+    if (sscanf(buf, "SPAMD/%18s %d %*s", versbuf, &response) != 2) {
+	libspamc_log(flags, LOG_ERR, "spamd responded with bad string '%s'", buf);
+	failureval = EX_PROTOCOL;
+	goto failure;
+    }
+
+    versbuf[19] = '\0';
+    version = _locale_safe_string_to_float(versbuf, 20);
+    if (version < 1.0) {
+	libspamc_log(flags, LOG_ERR, "spamd responded with bad version string '%s'",
+	       versbuf);
+	failureval = EX_PROTOCOL;
+	goto failure;
+    }
+
+    m->score = 0;
+    m->threshold = 0;
+    m->is_spam = EX_TOOBIG;
+    *islearned = 0;
+    while (1) {
+	failureval =
+	    _spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
+	if (failureval != EX_OK) {
+	    goto failure;
+	}
+
+	if (len == 0 && buf[0] == '\0') {
+	    break;		/* end of headers */
+	}
+
+	if (_handle_spamd_header(m, flags, buf, len, islearned) < 0) {
+	    failureval = EX_PROTOCOL;
+	    goto failure;
+	}
+    }
+
+    len = 0;			/* overwrite those headers */
+
+    shutdown(sock, SHUT_RD);
+    closesocket(sock);
+    sock = -1;
+    return EX_OK;
+
+    libspamc_timeout = 0;
+
+    if (m->out_len != m->content_length) {
+	libspamc_log(flags, LOG_ERR,
+	       "failed sanity check, %d bytes claimed, %d bytes seen",
+	       m->content_length, m->out_len);
+	failureval = EX_PROTOCOL;
+	goto failure;
+    }
+
+    return EX_OK;
+
+  failure:
+	_use_msg_for_out(m);
+    if (sock != -1) {
+	closesocket(sock);
+    }
+    libspamc_timeout = 0;
+
+    if (flags & SPAMC_USE_SSL) {
+#ifdef SPAMC_SSL
+	SSL_free(ssl);
+	SSL_CTX_free(ctx);
+#endif
+    }
+    return failureval;
+}
 
 void message_cleanup(struct message *m)
 {
@@ -1143,9 +1310,9 @@
 }
 
 /* Aug 14, 2002 bj: Obsolete! */
-int process_message(struct transport *tp, char *username, int learntype,
-		    int max_size, int in_fd, int out_fd,
-		    const int my_check_only, const int my_safe_fallback)
+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)
 {
     int flags;
 
@@ -1155,7 +1322,7 @@
     if (my_safe_fallback)
         flags |= SPAMC_SAFE_FALLBACK;
 
-    return message_process(tp, username, learntype, max_size, in_fd, out_fd, flags);
+    return message_process(tp, username, max_size, in_fd, out_fd, flags);
 }
 
 /*

Modified: spamassassin/trunk/spamc/libspamc.h
URL: http://svn.apache.org/viewcvs/spamassassin/trunk/spamc/libspamc.h?view=diff&r1=159880&r2=159881
==============================================================================
--- spamassassin/trunk/spamc/libspamc.h (original)
+++ spamassassin/trunk/spamc/libspamc.h Sat Apr  2 20:13:47 2005
@@ -139,8 +139,6 @@
     int out_len;		/* Output from spamd. Either the filtered
 				   message, or the check-only response. Or else,
 				   a pointer to msg above. */
-    int is_learned;	        /* Output from spamd. Gives state
-				   about learn resp. unlearn process */
 
     /* these members added in SpamAssassin version 2.60: */
     struct libspamc_private_message *priv;
@@ -210,9 +208,17 @@
  * failover, more than one host is defined, but if there is only one there,
  * no failover is done.
  */
-int message_filter(struct transport *tp, const char *username, int learntype,
+int message_filter(struct transport *tp, const char *username,
 		   int flags, struct message *m);
 
+/* Process the message through the spamd learn, making as many connection
+ * attempts as are implied by the transport structure. To make this do
+ * failover, more than one host is defined, but if there is only one there,
+ * no failover is done.
+ */
+int message_learn(struct transport *tp, const char *username, int flags,
+		  struct message *m, int learntype, int *islearned);
+
 /* Dump the message. If there is any data in the message (typically, m->type
  * will be MESSAGE_ERROR) it will be message_writed. Then, fd_in will be piped
  * to fd_out intol EOF. This is particularly useful if you get back an
@@ -222,7 +228,7 @@
 /* Do a message_read->message_filter->message_write sequence, handling errors
  * appropriately with dump_message or appropriate CHECK_ONLY output. Returns
  * EX_OK or EX_ISSPAM/EX_NOTSPAM on success, some error EX on error. */
-int message_process(struct transport *trans, char *username, int learntype, int max_size,
+int message_process(struct transport *trans, char *username, int max_size,
 		    int in_fd, int out_fd, const int flags);
 
 /* Cleanup the resources we allocated for storing the message. Call after
@@ -230,7 +236,7 @@
 void message_cleanup(struct message *m);
 
 /* Aug 14, 2002 bj: This is now legacy, don't use it. */
-int process_message(struct transport *tp, char *username, int learntype,
+int process_message(struct transport *tp, char *username,
 		    int max_size, int in_fd, int out_fd,
 		    const int check_only, const int safe_fallback);
 

Modified: spamassassin/trunk/spamc/spamc.c
URL: http://svn.apache.org/viewcvs/spamassassin/trunk/spamc/spamc.c?view=diff&r1=159880&r2=159881
==============================================================================
--- spamassassin/trunk/spamc/spamc.c (original)
+++ spamassassin/trunk/spamc/spamc.c Sat Apr  2 20:13:47 2005
@@ -501,6 +501,7 @@
     int result;
     int ret;
     int learntype = 0;
+    int islearned = 0;
 
     transport_init(&trans);
 
@@ -560,7 +561,12 @@
 
 	if (ret == EX_OK) {
 
-	    ret = message_filter(&trans, username, learntype, flags, &m);
+ 	    if (flags & SPAMC_LEARN) {
+	      ret = message_learn(&trans, username, flags, &m, learntype, &islearned);
+	    }
+	    else {
+	      ret = message_filter(&trans, username, flags, &m);
+	    }
 
 	    free(username); username = NULL;
 	    
@@ -569,7 +575,7 @@
 		get_output_fd(&out_fd);
 
 		if (flags & SPAMC_LEARN) {
-		    if (m.is_learned == 1) {
+		    if (islearned == 1) {
   		        printf("Message successfully un/learned\n");
 		    }
 		    else {