You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by so...@apache.org on 2005/08/29 20:03:30 UTC

svn commit: r264188 - in /httpd/mod_smtpd/trunk: Makefile.in mod_smtpd.h smtp.h smtp_core.c smtp_protocol.c

Author: soc-rian
Date: Mon Aug 29 11:03:27 2005
New Revision: 264188

URL: http://svn.apache.org/viewcvs?rev=264188&view=rev
Log:
added support for input filters

Modified:
    httpd/mod_smtpd/trunk/Makefile.in
    httpd/mod_smtpd/trunk/mod_smtpd.h
    httpd/mod_smtpd/trunk/smtp.h
    httpd/mod_smtpd/trunk/smtp_core.c
    httpd/mod_smtpd/trunk/smtp_protocol.c

Modified: httpd/mod_smtpd/trunk/Makefile.in
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/Makefile.in?rev=264188&r1=264187&r2=264188&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/Makefile.in (original)
+++ httpd/mod_smtpd/trunk/Makefile.in Mon Aug 29 11:03:27 2005
@@ -1,12 +1,14 @@
 APXS=@APXS_BIN@
 CFLAGS=-Wall
-APXSFLAGS=
+APXSFLAGS=-L`$(APXS) -q LIBDIR`
+LIBS=-lapreq2
 SMTPD_SRC=smtp_core.c smtp_protocol.c
 
 all: mod_smtpd.la
 
 mod_smtpd.la: $(SMTPD_SRC)
-	$(APXS) -Wc,"$(CFLAGS)" $(APXSFLAGS) -o mod_smtpd.la -c $(SMTPD_SRC)
+	$(APXS) -Wc,"$(CFLAGS)" $(APXSFLAGS) -o mod_smtpd.la -c $(SMTPD_SRC)\
+	$(LIBS)
 
 install: all
 	$(APXS) -i -a -n smtpd mod_smtpd.la

Modified: httpd/mod_smtpd/trunk/mod_smtpd.h
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/mod_smtpd.h?rev=264188&r1=264187&r2=264188&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/mod_smtpd.h (original)
+++ httpd/mod_smtpd/trunk/mod_smtpd.h Mon Aug 29 11:03:27 2005
@@ -66,6 +66,11 @@
 } smtpd_trans_state;
 
 typedef enum {
+    SMTPD_READ_COMMAND,
+    SMTPD_READ_DATA
+} smtpd_read_type;
+
+typedef enum {
     SMTPD_PROTOCOL_SMTP,
     SMTPD_PROTOCOL_ESMTP
 } smtpd_protocol_type;
@@ -97,6 +102,12 @@
 
     /* spooled data file pointer */
     apr_file_t *tfp;
+
+    /* headers */
+    apr_table_t *headers;
+
+    /* filters in */
+    ap_filter_t *input_filters;
 } smtpd_trans_rec;
 
 typedef struct smtpd_conn_rec {
@@ -125,7 +136,8 @@
 
 SMTPD_DECLARE_NONSTD(apr_status_t) smtpd_getline(smtpd_conn_rec *scr,
                                                  char *data, apr_size_t dlen,
-                                                 apr_size_t *outlen);
+                                                 apr_size_t *outlen,
+                                                 smtpd_read_type read_type);
 
 SMTPD_DECLARE_NONSTD(apr_status_t) smtpd_respond_multiline(smtpd_conn_rec *scr,
                                                            int code,
@@ -136,6 +148,10 @@
                                                          int code,
                                                          char *message);
 
+SMTPD_DECLARE_NONSTD(ap_filter_t *)
+         smtpd_add_input_filter_handle(ap_filter_rec_t *frec, void *ctx, 
+                                       smtpd_conn_rec *scr);
+
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode,
                           unrecognized_command,
                           (smtpd_conn_rec *scr, smtpd_return_data *in,
@@ -166,6 +182,8 @@
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, data_post,
                           (smtpd_conn_rec *scr, smtpd_return_data *in));
 APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, queue,
+                          (smtpd_conn_rec *scr, smtpd_return_data *in));
+APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, headers_parsed,
                           (smtpd_conn_rec *scr, smtpd_return_data *in));
 
 #ifdef __cplusplus

Modified: httpd/mod_smtpd/trunk/smtp.h
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/smtp.h?rev=264188&r1=264187&r2=264188&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/smtp.h (original)
+++ httpd/mod_smtpd/trunk/smtp.h Mon Aug 29 11:03:27 2005
@@ -86,7 +86,7 @@
 
 void smtpd_process_connection_internal(smtpd_conn_rec *str);
 
-void smtpd_clear_trans_rec(smtpd_trans_rec *);
+void smtpd_clear_trans_rec(smtpd_conn_rec *);
 
 apr_hash_t *smtpd_get_handlers(void);
 

Modified: httpd/mod_smtpd/trunk/smtp_core.c
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/smtp_core.c?rev=264188&r1=264187&r2=264188&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/smtp_core.c (original)
+++ httpd/mod_smtpd/trunk/smtp_core.c Mon Aug 29 11:03:27 2005
@@ -41,6 +41,7 @@
 #include "smtp.h"
 
 module AP_MODULE_DECLARE_DATA smtpd_module;
+ap_filter_rec_t *smtpd_smtp_input_filter_handle;
 
 static apr_hash_t *smtpd_handlers;
 
@@ -119,6 +120,13 @@
 					 smtpd_return_data *in),
 					(scr, in),
 					SMTPD_OK, SMTPD_DECLINED);
+/* Implement 'smtpd_run_headers_parsed'. */
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL_MOD(smtpd, SMTPD, smtpd_retcode,
+                                        headers_parsed,
+					(smtpd_conn_rec *scr,
+					 smtpd_return_data *in),
+					(scr, in),
+					SMTPD_OK, SMTPD_DECLINED);
 
 /* public methods */
 /* functions other modules can use */
@@ -143,22 +151,25 @@
    */
     smtpd_run_reset_transaction(scr);
 
-    smtpd_clear_trans_rec(scr->transaction);
+    smtpd_clear_trans_rec(scr);
 }
 
-
 SMTPD_DECLARE_NONSTD(apr_status_t) smtpd_getline(smtpd_conn_rec *scr,
                                                  char *data, apr_size_t dlen,
-                                                 apr_size_t *outlen)
+                                                 apr_size_t *outlen,
+                                                 smtpd_read_type read_type)
 {
     apr_status_t rc;
     apr_bucket *e;
     const char *str;
     char *pos, *last_char = data;
     apr_size_t len, bytes_handled = 0;
-    
+    ap_filter_t *input_filters = read_type == SMTPD_READ_DATA ?
+      scr->transaction->input_filters :
+      scr->c->input_filters;
+
     while (1) {
-        rc = ap_get_brigade(scr->c->input_filters, scr->bb_in, AP_MODE_GETLINE,
+        rc = ap_get_brigade(input_filters, scr->bb_in, AP_MODE_GETLINE,
                             APR_BLOCK_READ, 0);
         if (rc != APR_SUCCESS)
             return rc;
@@ -172,7 +183,8 @@
 
             apr_bucket_delete(e);
             
-            if (len == 0) continue;
+            if (len == 0)
+                continue;
             
             /* Would this overrun our buffer?  If so, we'll die. */
             if (dlen < bytes_handled + len) {
@@ -195,12 +207,9 @@
             
             /* We've now processed that new data - update accordingly. */
             bytes_handled += len;
+
         }
         
-        /* brigade was empty from the beginning, no block? */
-        if (!bytes_handled)
-            return APR_EGENERAL;
-        
         /* If we got a full line of input, stop reading */
         if (last_char && (*last_char == APR_ASCII_LF)) {
             break;
@@ -250,11 +259,46 @@
     return APR_SUCCESS;
 }
 
+#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
+                           || (before_this)->frec->ftype > (f)->frec->ftype \
+                           || (before_this)->r != (f)->r)
+SMTPD_DECLARE_NONSTD(ap_filter_t *)
+     smtpd_add_input_filter_handle(ap_filter_rec_t *frec, void *ctx, 
+                                   smtpd_conn_rec *scr)
+{
+    apr_pool_t* p = scr->p;
+    ap_filter_t *f = apr_palloc(p, sizeof(*f));
+    ap_filter_t **outf;
+
+    outf = &(scr->transaction->input_filters);
+
+    f->frec = frec;
+    f->ctx = ctx;
+    f->c = scr->c;
+    f->next = NULL;
+
+    if (INSERT_BEFORE(f, *outf)) {
+        f->next = *outf;
+        *outf = f;
+    }
+    else {
+        ap_filter_t *fscan = *outf;
+        while (!INSERT_BEFORE(f, fscan->next))
+            fscan = fscan->next;
+
+        f->next = fscan->next;
+	fscan->next = f;
+    }
+
+    return f;
+}
+
 /* friend methods */
 /* only our sources can call these */
 
-void smtpd_clear_trans_rec(smtpd_trans_rec *str)
+void smtpd_clear_trans_rec(smtpd_conn_rec *scr)
 {
+    smtpd_trans_rec *str = scr->transaction;
     apr_pool_clear(str->p);
     str->trans_state = SMTPD_STATE_GOT_NOTHING;
     str->tfp = NULL;
@@ -262,12 +306,41 @@
     str->rcpt_to = apr_array_make(str->p, 5, sizeof(char *));
     str->mail_from = NULL;
     str->helo = NULL;
+    str->headers = apr_table_make(str->p, 5);
+    str->input_filters = scr->c->input_filters;
 }
 
 apr_hash_t *smtpd_get_handlers() {
     return smtpd_handlers;
 }
 
+apr_status_t smtpd_smtp_filter(ap_filter_t *f, apr_bucket_brigade *b,
+                               ap_input_mode_t mode, apr_read_type_e block,
+                               apr_off_t readbytes)
+{
+    apr_bucket_brigade *old_bb = f->ctx;
+
+    /* if our input brigade is empty, just go on */
+    if (APR_BRIGADE_EMPTY(old_bb))
+        return ap_get_brigade(f->next, b, mode, block, readbytes);
+    
+    if (mode == AP_MODE_GETLINE) {
+        apr_off_t bb_len;
+        apr_brigade_split_line(b, old_bb, block, 1000);
+        /* if we have one last empty bucket
+           our brigade is empty */
+        apr_brigade_length(old_bb, 1, &bb_len);
+        if (!bb_len)
+            apr_brigade_cleanup(old_bb);
+    }
+    /* XXX: since we are only using AP_MODE_GETLINE in mod_smtpd
+       the other read types are ignored, but this can be robustified */
+    else {
+        APR_BRIGADE_CONCAT(b, old_bb);
+    }
+    return APR_SUCCESS;
+}
+
 /* private methods */
 /* only used in this file */
 
@@ -306,10 +379,6 @@
     scr->bb_in = apr_brigade_create(scr->p, scr->c->bucket_alloc);
     scr->bb_out = apr_brigade_create(scr->p, scr->c->bucket_alloc);
     
-    /* REVIEW: does scr need a request_config?
-     * r->request_config  = ap_create_request_config(r->pool);
-     */
-    
     apr_socket_t *csd =
       ((core_net_rec *)conn->input_filters->ctx)->client_socket;
     apr_socket_timeout_set(csd, APR_INT64_C(10000000000000));
@@ -319,10 +388,10 @@
     
     apr_pool_create(&sp, scr->p);
     str->p = sp;
-    smtpd_clear_trans_rec(str);
-    
+
     scr->transaction = str;
-    
+    smtpd_clear_trans_rec(scr);
+        
     return scr;
 }
 
@@ -415,6 +484,10 @@
     /* register connection processor  */
     ap_hook_process_connection(process_smtp_connection, NULL, NULL,
                                APR_HOOK_MIDDLE);
+
+    smtpd_smtp_input_filter_handle =
+        ap_register_input_filter("SMTP_IN", smtpd_smtp_filter,
+                                 NULL, AP_FTYPE_PROTOCOL);
     
     smtpd_handlers = apr_hash_make(p);
     

Modified: httpd/mod_smtpd/trunk/smtp_protocol.c
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/smtp_protocol.c?rev=264188&r1=264187&r2=264188&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/smtp_protocol.c (original)
+++ httpd/mod_smtpd/trunk/smtp_protocol.c Mon Aug 29 11:03:27 2005
@@ -31,10 +31,13 @@
 #include "apr_errno.h"
 #include "scoreboard.h"
 
+#include "apreq2/apreq_parser.h"
+
 #include "smtp.h"
 #include "mod_smtpd.h"
 
 extern module AP_MODULE_DECLARE_DATA smtpd_module;
+extern ap_filter_rec_t *smtpd_smtp_input_filter_handle;
 
 inline static int smtpd_handle_unrecognized_command(smtpd_conn_rec *scr,
                                                     smtpd_return_data *in_data,
@@ -92,7 +95,8 @@
         break;
     }
     
-    while (smtpd_getline(scr, buffer, BUFFER_STR_LEN, NULL) == APR_SUCCESS) {
+    while (smtpd_getline(scr, buffer, BUFFER_STR_LEN, NULL,
+                         SMTPD_READ_COMMAND) == APR_SUCCESS) {
         apr_pool_clear(p);
         command = ap_getword_white_nc(p, &buffer);
         ap_str_tolower(command);
@@ -455,6 +459,66 @@
     }
 }
 
+static int ascii_printable(unsigned char character) {
+    return ((character <= 126) &&
+            (character >= 33));
+}
+
+static int is_ascii(unsigned char character) {
+    return (character <= 127);
+}
+
+static int is_rfc822_header(char *line) {
+    int i;
+    int header_len = 0;
+    enum {
+        HEADER_NAME,
+        HEADER_GAP,
+        HEADER_VALUE
+    } state = HEADER_NAME;
+    
+    for (i = 0; line[i] != '\0'; ++i) {
+        switch(state) {
+        case HEADER_NAME:
+            if (!ascii_printable(line[i])) {
+                return 0;
+            }
+            else if (line[i] == ':') {
+                if (!header_len) {
+                    return 0;
+                } else {
+                    state = HEADER_GAP;
+                }
+            }
+            else {
+                header_len = 1;
+            }
+            break;
+        case HEADER_GAP:
+            if ((line[i] == APR_ASCII_BLANK) ||
+                (line[i] == APR_ASCII_TAB)) {
+                break;
+            }
+            
+            if (line[i] == APR_ASCII_LF) {
+                return 0;
+            }
+
+            state = HEADER_VALUE;
+            /* fall through */
+        case HEADER_VALUE:
+            if (!is_ascii(line[i])) {
+                return 0;
+            }
+            else if (line[i] == APR_ASCII_LF) {
+                return 1;
+            }
+            break;
+        }
+    }
+
+    return (state == HEADER_VALUE);
+}
 
 HANDLER_DECLARE(data)
 {
@@ -467,7 +531,9 @@
     char our_buffer[BUFFER_STR_LEN];
     apr_file_t *tfp;
     apr_size_t len, total_data = 0;
-    
+    apreq_parser_t *rfc822_parser;
+    apr_bucket_brigade *bb;
+
     switch(smtpd_run_data(scr, in_data)) {
     case SMTPD_DONE:
         return 1;
@@ -517,9 +583,7 @@
         smtpd_respond_oneline(scr, 503, "Error: need RCPT command");
         return 503;
     }
-    
-    smtpd_respond_oneline(scr, 354, "End data with <CR><LF>.<CR><LF>");
-    
+
     tempfile = apr_pstrdup(str->p, "/tmp/tmp.XXXXXX");
     rv = apr_file_mktemp(&tfp, tempfile,
                          APR_CREATE | APR_WRITE | APR_READ |
@@ -530,11 +594,55 @@
         /* file error close connection */
         return 0;
     }
+
+    smtpd_respond_oneline(scr, 354, "End data with <CR><LF>.<CR><LF>");
+
+    bb = apr_brigade_create(str->p, scr->c->bucket_alloc);
     
+    /* get a line after the data command */
+    smtpd_getline(scr, our_buffer, BUFFER_STR_LEN - 3, &len,
+                  SMTPD_READ_COMMAND);
+    /* but put it back in the bucket brigade */
+    {
+        apr_bucket *temp_bucket;
+
+        our_buffer[len] = '\r';
+        our_buffer[len+1] = '\n';
+        our_buffer[len+2] = '\0';
+        temp_bucket = apr_bucket_transient_create(our_buffer, len+2,
+                                                  scr->c->bucket_alloc);
+        apr_bucket_setaside(temp_bucket, str->p);
+        APR_BRIGADE_INSERT_HEAD(bb, temp_bucket);
+    }
+
+    /* if the first line is a header, then parse the rest as header */
+    if (is_rfc822_header(our_buffer)) {
+        rfc822_parser = apreq_parser_make(str->p, scr->c->bucket_alloc,
+                                          "text/rfc822", apreq_parse_headers,
+                                          1000, NULL, NULL, NULL);
+        do {
+            ap_get_brigade(scr->c->input_filters, bb,
+                           AP_MODE_READBYTES, APR_BLOCK_READ, 1000);
+            
+            rv = apreq_parser_run(rfc822_parser, str->headers, bb);
+        } while (rv == APR_INCOMPLETE);
+    }
+   
+    /* add filter that returns data just read */
+    smtpd_add_input_filter_handle(smtpd_smtp_input_filter_handle, bb, scr);
+
+    /* by convention this is where most filters
+       should be inserted, but no action can be taken here
+       right in the middle of the data command
+       it is called even when there are no headers.
+    */
+    smtpd_run_headers_parsed(scr, in_data);
+
     /* just wait until we get the line with a dot. */
     /* or until we can't read anymore. */
     /* or until we have too much data */
-    while ((smtpd_getline(scr, our_buffer, BUFFER_STR_LEN, &len)
+    while (((rv = smtpd_getline(scr, our_buffer, BUFFER_STR_LEN, &len,
+                                SMTPD_READ_DATA))
             == APR_SUCCESS) &&
            (strcmp(our_buffer, ".")) &&
            (total_data < pConfig->max_data)) {