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)) {