mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +00:00
snapshot-20011015
This commit is contained in:
parent
6f7a3806f8
commit
d9c14900c6
@ -5490,7 +5490,17 @@ Apologies for any names omitted.
|
||||
20011010-14
|
||||
|
||||
Replaced the internal protocols by (name,value) attribute
|
||||
lists. This is more extensible.
|
||||
lists. This gives better error detection when we start
|
||||
making changes to internal protocols.
|
||||
|
||||
20011015
|
||||
|
||||
Put base 64 encoding into place on the replced internal
|
||||
protocols. Files: util/base64_code.[hc].
|
||||
|
||||
Feature: header/body REJECT rules can now end in text that
|
||||
is sent to the originator. Files: cleanup/cleanup.c,
|
||||
cleanup/cleanup_message.c, conf/sample-filter.cf.
|
||||
|
||||
Open problems:
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
#
|
||||
# REJECT the entire message is rejected.
|
||||
#
|
||||
# REJECT text.... The text is sent to the originator.
|
||||
#
|
||||
# IGNORE the header line is silently discarded.
|
||||
#
|
||||
# OK Nothing happens. the message will still be rejected when some
|
||||
|
@ -142,11 +142,12 @@ static int bounce_append_proto(char *service_name, VSTREAM *client)
|
||||
/*
|
||||
* Read the and validate the client request.
|
||||
*/
|
||||
if (mail_command_server(client, "%d %s %s %s",
|
||||
if (mail_command_server(client,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_WHY, why, 0) != 4) {
|
||||
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
|
||||
ATTR_TYPE_END) != 4) {
|
||||
msg_warn("malformed request");
|
||||
return (-1);
|
||||
}
|
||||
@ -181,11 +182,12 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush)
|
||||
/*
|
||||
* Read and validate the client request.
|
||||
*/
|
||||
if (mail_command_server(client, ATTR_FLAG_MISSING,
|
||||
if (mail_command_server(client,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, 0) != 4) {
|
||||
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
|
||||
ATTR_TYPE_END) != 4) {
|
||||
msg_warn("malformed request");
|
||||
return (-1);
|
||||
}
|
||||
@ -230,7 +232,8 @@ static int bounce_verp_proto(char *service_name, VSTREAM *client, int flush)
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims, 0) != 5) {
|
||||
ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims,
|
||||
ATTR_TYPE_END) != 5) {
|
||||
msg_warn("malformed request");
|
||||
return (-1);
|
||||
}
|
||||
|
@ -235,8 +235,10 @@ static void cleanup_service(VSTREAM *src, char *unused_service, char **argv)
|
||||
*/
|
||||
attr_print(src, ATTR_FLAG_NONE,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, cleanup_close(state),
|
||||
ATTR_TYPE_STR, MAIL_ATTR_WHY, "",
|
||||
ATTR_TYPE_STR, MAIL_ATTR_WHY, state->why_rejected ?
|
||||
vstring_str(state->why_rejected) : "",
|
||||
ATTR_TYPE_END);
|
||||
cleanup_free(state);
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
|
@ -59,6 +59,7 @@ typedef struct CLEANUP_STATE {
|
||||
off_t xtra_offset; /* start of extra segment */
|
||||
int end_seen; /* REC_TYPE_END seen */
|
||||
int rcpt_count; /* recipient count */
|
||||
VSTRING *why_rejected; /* REJECT reason */
|
||||
} CLEANUP_STATE;
|
||||
|
||||
/*
|
||||
@ -104,6 +105,7 @@ extern void cleanup_state_free(CLEANUP_STATE *);
|
||||
extern CLEANUP_STATE *cleanup_open(void);
|
||||
extern void cleanup_control(CLEANUP_STATE *, int);
|
||||
extern int cleanup_close(CLEANUP_STATE *);
|
||||
extern void cleanup_free(CLEANUP_STATE *);
|
||||
extern void cleanup_all(void);
|
||||
extern void cleanup_pre_jail(char *, char **);
|
||||
extern void cleanup_post_jail(char *, char **);
|
||||
|
@ -20,6 +20,9 @@
|
||||
/*
|
||||
/* int cleanup_close(state)
|
||||
/* CLEANUP_STATE *state;
|
||||
/*
|
||||
/* int cleanup_free(state)
|
||||
/* CLEANUP_STATE *state;
|
||||
/* DESCRIPTION
|
||||
/* This module implements a callable interface to the cleanup service
|
||||
/* for processing one message and for writing it to queue file.
|
||||
@ -27,7 +30,8 @@
|
||||
/*
|
||||
/* cleanup_open() creates a new queue file and performs other
|
||||
/* per-message initialization. The result is a handle that should be
|
||||
/* given to the cleanup_control(), cleanup_record() and cleanup_close()
|
||||
/* given to the cleanup_control(), cleanup_record(), cleanup_close()
|
||||
/* and cleanup_close()
|
||||
/* routines. The name of the queue file is in the queue_id result
|
||||
/* structure member.
|
||||
/*
|
||||
@ -43,10 +47,12 @@
|
||||
/* The result is false when further message processing is futile.
|
||||
/* In that case, it is safe to call cleanup_close() immediately.
|
||||
/*
|
||||
/* cleanup_close() finishes a queue file. In case of any errors,
|
||||
/* cleanup_close() closes a queue file. In case of any errors,
|
||||
/* the file is removed. The result value is non-zero in case of
|
||||
/* problems. Use cleanup_strerror() to translate the result into
|
||||
/* human_readable text.
|
||||
/*
|
||||
/* cleanup_free() destroys its argument.
|
||||
/* DIAGNOSTICS
|
||||
/* Problems and transactions are logged to \fBsyslogd\fR(8).
|
||||
/* SEE ALSO
|
||||
@ -161,6 +167,7 @@ int cleanup_close(CLEANUP_STATE *state)
|
||||
{
|
||||
char *junk;
|
||||
int status;
|
||||
const char *reason;
|
||||
|
||||
/*
|
||||
* See if there are any errors. For example, the message is incomplete,
|
||||
@ -181,7 +188,7 @@ int cleanup_close(CLEANUP_STATE *state)
|
||||
* copy of the message.
|
||||
*/
|
||||
if ((state->errs & CLEANUP_STAT_LETHAL) == 0)
|
||||
state->errs |= mail_stream_finish(state->handle);
|
||||
state->errs |= mail_stream_finish(state->handle, (VSTRING *) 0);
|
||||
else
|
||||
mail_stream_cleanup(state->handle);
|
||||
state->handle = 0;
|
||||
@ -216,11 +223,14 @@ int cleanup_close(CLEANUP_STATE *state)
|
||||
|
||||
if (state->errs & CLEANUP_STAT_LETHAL) {
|
||||
if (CAN_BOUNCE()) {
|
||||
reason = cleanup_strerror(state->errs);
|
||||
if (reason == cleanup_strerror(CLEANUP_STAT_CONT))
|
||||
reason = vstring_str(state->why_rejected);
|
||||
if (bounce_append(BOUNCE_FLAG_CLEAN, state->queue_id,
|
||||
state->recip ? state->recip : "unknown",
|
||||
"cleanup", state->time,
|
||||
"Message processing aborted: %s",
|
||||
cleanup_strerror(state->errs)) == 0
|
||||
reason) == 0
|
||||
&& bounce_flush(BOUNCE_FLAG_CLEAN, MAIL_QUEUE_INCOMING,
|
||||
state->queue_id, state->sender) == 0) {
|
||||
state->errs = 0;
|
||||
@ -249,6 +259,12 @@ int cleanup_close(CLEANUP_STATE *state)
|
||||
if (msg_verbose)
|
||||
msg_info("cleanup_close: status %d", state->errs);
|
||||
status = state->errs & CLEANUP_STAT_LETHAL;
|
||||
cleanup_state_free(state);
|
||||
return (status);
|
||||
}
|
||||
|
||||
/* cleanup_close - pay the last respects */
|
||||
|
||||
void cleanup_free(CLEANUP_STATE *state)
|
||||
{
|
||||
cleanup_state_free(state);
|
||||
}
|
||||
|
@ -254,6 +254,38 @@ static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts)
|
||||
cleanup_fold_header(state);
|
||||
}
|
||||
|
||||
/* cleanup_parse_reject - parse REJECT liune and pick up the reason */
|
||||
|
||||
static const char *cleanup_parse_reject(CLEANUP_STATE *state, const char *value)
|
||||
{
|
||||
const char *reason;
|
||||
|
||||
/*
|
||||
* See if they spelled REJECT right.
|
||||
*/
|
||||
if (strcasecmp(value, "REJECT") == 0) {
|
||||
reason = "Content rejected";
|
||||
} else if (strncasecmp(value, "REJECT ", 7) == 0
|
||||
|| strncasecmp(value, "REJECT\t", 7) == 0) {
|
||||
reason = value + 7;
|
||||
while (*reason && ISSPACE(*reason))
|
||||
reason++;
|
||||
if (*reason == 0)
|
||||
reason = "Content rejected";
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the remembered reason if none was stored.
|
||||
*/
|
||||
if (state->why_rejected == 0) {
|
||||
state->why_rejected = vstring_alloc(10);
|
||||
vstring_strcpy(state->why_rejected, reason);
|
||||
}
|
||||
return (reason);
|
||||
}
|
||||
|
||||
/* cleanup_header - process one complete header line */
|
||||
|
||||
static void cleanup_header(CLEANUP_STATE *state)
|
||||
@ -267,12 +299,13 @@ static void cleanup_header(CLEANUP_STATE *state)
|
||||
if ((state->flags & CLEANUP_FLAG_FILTER) && cleanup_header_checks) {
|
||||
char *header = vstring_str(state->header_buf);
|
||||
const char *value;
|
||||
const char *reason;
|
||||
|
||||
if ((value = maps_find(cleanup_header_checks, header, 0)) != 0) {
|
||||
if (strcasecmp(value, "REJECT") == 0) {
|
||||
msg_info("%s: reject: header %.200s; from=<%s> to=<%s>",
|
||||
if ((reason = cleanup_parse_reject(state, value)) != 0) {
|
||||
msg_info("%s: reject: header %.200s; from=<%s> to=<%s>: %s",
|
||||
state->queue_id, header, state->sender,
|
||||
state->recip ? state->recip : "unknown");
|
||||
state->recip ? state->recip : "unknown", reason);
|
||||
state->errs |= CLEANUP_STAT_CONT;
|
||||
} else if (strcasecmp(value, "IGNORE") == 0) {
|
||||
return;
|
||||
@ -547,12 +580,13 @@ static void cleanup_message_body(CLEANUP_STATE *state, int type, char *buf, int
|
||||
*/
|
||||
if ((state->flags & CLEANUP_FLAG_FILTER) && cleanup_body_checks) {
|
||||
const char *value;
|
||||
const char *reason;
|
||||
|
||||
if ((value = maps_find(cleanup_body_checks, buf, 0)) != 0) {
|
||||
if (strcasecmp(value, "REJECT") == 0) {
|
||||
msg_info("%s: reject: body %.200s; from=<%s> to=<%s>",
|
||||
if ((reason = cleanup_parse_reject(state, value)) != 0) {
|
||||
msg_info("%s: reject: body %.200s; from=<%s> to=<%s>: %s",
|
||||
state->queue_id, buf, state->sender,
|
||||
state->recip ? state->recip : "unknown");
|
||||
state->recip ? state->recip : "unknown", reason);
|
||||
state->errs |= CLEANUP_STAT_CONT;
|
||||
} else if (strcasecmp(value, "IGNORE") == 0) {
|
||||
return;
|
||||
|
@ -84,6 +84,7 @@ CLEANUP_STATE *cleanup_state_alloc(void)
|
||||
state->xtra_offset = -1;
|
||||
state->end_seen = 0;
|
||||
state->rcpt_count = 0;
|
||||
state->why_rejected = 0;
|
||||
return (state);
|
||||
}
|
||||
|
||||
@ -113,5 +114,7 @@ void cleanup_state_free(CLEANUP_STATE *state)
|
||||
if (state->queue_id)
|
||||
myfree(state->queue_id);
|
||||
been_here_free(state->dups);
|
||||
if (state->why_rejected)
|
||||
vstring_free(state->why_rejected);
|
||||
myfree((char *) state);
|
||||
}
|
||||
|
@ -547,8 +547,8 @@ static void flush_service(VSTREAM *client_stream, char *unused_service,
|
||||
site = vstring_alloc(10);
|
||||
queue_id = vstring_alloc(10);
|
||||
if (attr_scan(client_stream, ATTR_FLAG_MISSING | ATTR_FLAG_EXTRA,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_SITE, site, ATTR_FLAG_MISSING,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_SITE, queue_id,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_SITE, site,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
|
||||
ATTR_TYPE_END) == 2
|
||||
&& mail_queue_id_ok(STR(queue_id)))
|
||||
status = flush_add_service(lowercase(STR(site)), STR(queue_id));
|
||||
|
@ -144,7 +144,7 @@ int vbounce_append(int flags, const char *id, const char *recipient,
|
||||
vstring_vsprintf(why, fmt, ap);
|
||||
if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ?
|
||||
MAIL_SERVICE_DEFER : MAIL_SERVICE_BOUNCE,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_REQ, BOUNCE_CMD_APPEND,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
|
||||
@ -177,7 +177,7 @@ int bounce_flush(int flags, const char *queue, const char *id,
|
||||
if (var_soft_bounce)
|
||||
return (-1);
|
||||
if (mail_command_client(MAIL_CLASS_PRIVATE, MAIL_SERVICE_BOUNCE,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_REQ, BOUNCE_CMD_FLUSH,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
|
||||
|
@ -146,7 +146,7 @@ int vdefer_append(int flags, const char *id, const char *recipient,
|
||||
|
||||
vstring_vsprintf(why, fmt, ap);
|
||||
if (mail_command_client(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_REQ, BOUNCE_CMD_APPEND,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
|
||||
@ -180,7 +180,7 @@ int defer_flush(int flags, const char *queue, const char *id,
|
||||
const char *sender)
|
||||
{
|
||||
if (mail_command_client(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_REQ, BOUNCE_CMD_FLUSH,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
|
||||
@ -199,7 +199,7 @@ int defer_warn(int flags, const char *queue, const char *id,
|
||||
const char *sender)
|
||||
{
|
||||
if (mail_command_client(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_REQ, BOUNCE_CMD_WARN,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_WARN,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
|
||||
|
39
postfix/src/global/mail_attr.h
Normal file
39
postfix/src/global/mail_attr.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef _MAIL_ATTR_H_INCLUDED_
|
||||
#define _MAIL_ATTR_H_INCLUDED_
|
||||
|
||||
/*++
|
||||
/* NAME
|
||||
/* mail_attr 3h
|
||||
/* SUMMARY
|
||||
/* mail internal IPC support
|
||||
/* SYNOPSIS
|
||||
/* #include <mail_attr.h>
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* Request attribute. Values are defined by individual applications.
|
||||
*/
|
||||
#define MAIL_REQUEST "request"
|
||||
|
||||
/*
|
||||
* Request completion status.
|
||||
*/
|
||||
#define MAIL_STATUS "status"
|
||||
#define MAIL_STAT_OK "success"
|
||||
#define MAIL_STAT_FAIL "failed"
|
||||
#define MAIL_STAT_RETRY "retry"
|
||||
#define MAIL_STAT_REJECT "reject"
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
#endif
|
69
postfix/src/global/mail_command_read.c
Normal file
69
postfix/src/global/mail_command_read.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* mail_command_read 3
|
||||
/* SUMMARY
|
||||
/* single-command server
|
||||
/* SYNOPSIS
|
||||
/* #include <mail_proto.h>
|
||||
/*
|
||||
/* int mail_command_read(stream, format, ...)
|
||||
/* VSTREAM *stream;
|
||||
/* char *format;
|
||||
/* DESCRIPTION
|
||||
/* This module implements the server interface for single-command
|
||||
/* requests: a clients sends a single command and expects a single
|
||||
/* completion status code.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP stream
|
||||
/* Server endpoint.
|
||||
/* .IP format
|
||||
/* Format string understood by mail_print(3) and mail_scan(3).
|
||||
/* DIAGNOSTICS
|
||||
/* Fatal: out of memory.
|
||||
/* SEE ALSO
|
||||
/* mail_scan(3)
|
||||
/* mail_command_write(3) client interface
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <vstring.h>
|
||||
#include <vstream.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include "mail_proto.h"
|
||||
|
||||
/* mail_command_read - read single-command request */
|
||||
|
||||
int mail_command_read(VSTREAM *stream, char *fmt,...)
|
||||
{
|
||||
VSTRING *eof = vstring_alloc(10);
|
||||
va_list ap;
|
||||
int count;
|
||||
|
||||
va_start(ap, fmt);
|
||||
count = mail_vscan(stream, fmt, ap);
|
||||
va_end(ap);
|
||||
if (mail_scan(stream, "%s", eof) != 1 || strcmp(vstring_str(eof), MAIL_EOF))
|
||||
count = -1;
|
||||
vstring_free(eof);
|
||||
return (count);
|
||||
}
|
82
postfix/src/global/mail_command_write.c
Normal file
82
postfix/src/global/mail_command_write.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* mail_command_write 3
|
||||
/* SUMMARY
|
||||
/* single-command client
|
||||
/* SYNOPSIS
|
||||
/* #include <mail_proto.h>
|
||||
/*
|
||||
/* int mail_command_write(class, name, format, ...)
|
||||
/* const char *class;
|
||||
/* const char *name;
|
||||
/* const char *format;
|
||||
/* DESCRIPTION
|
||||
/* This module implements a client interface for single-command
|
||||
/* clients: a client that sends a single command and expects
|
||||
/* a single completion status code.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP class
|
||||
/* Service type: MAIL_CLASS_PUBLIC or MAIL_CLASS_PRIVATE
|
||||
/* .IP name
|
||||
/* Service name (master.cf).
|
||||
/* .IP format
|
||||
/* Format string understood by mail_print(3).
|
||||
/* DIAGNOSTICS
|
||||
/* The result is -1 if the request could not be sent, otherwise
|
||||
/* the result is the status reported by the server.
|
||||
/* Warnings: problems connecting to the requested service.
|
||||
/* Fatal: out of memory.
|
||||
/* SEE ALSO
|
||||
/* mail_command_read(3), server interface
|
||||
/* mail_proto(5h), client-server protocol
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <vstream.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include "mail_proto.h"
|
||||
|
||||
/* mail_command_write - single-command transaction with completion status */
|
||||
|
||||
int mail_command_write(const char *class, const char *name,
|
||||
const char *fmt,...)
|
||||
{
|
||||
va_list ap;
|
||||
VSTREAM *stream;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Talk a little protocol with the specified service.
|
||||
*/
|
||||
if ((stream = mail_connect(class, name, BLOCKING)) == 0)
|
||||
return (-1);
|
||||
va_start(ap, fmt);
|
||||
status = mail_vprint(stream, fmt, ap);
|
||||
va_end(ap);
|
||||
if (status != 0
|
||||
|| mail_print(stream, "%s", MAIL_EOF) != 0
|
||||
|| vstream_fflush(stream) != 0
|
||||
|| mail_scan(stream, "%d", &status) != 1)
|
||||
status = -1;
|
||||
(void) vstream_fclose(stream);
|
||||
return (status);
|
||||
}
|
@ -66,6 +66,7 @@
|
||||
#include <connect.h>
|
||||
#include <mymalloc.h>
|
||||
#include <iostuff.h>
|
||||
#include <stringops.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
@ -79,6 +80,7 @@ VSTREAM *mail_connect(const char *class, const char *name, int block_mode)
|
||||
char *path;
|
||||
VSTREAM *stream;
|
||||
int fd;
|
||||
char *sock_name;
|
||||
|
||||
path = mail_pathname(class, name);
|
||||
if ((fd = LOCAL_CONNECT(path, block_mode, 0)) < 0) {
|
||||
@ -90,9 +92,11 @@ VSTREAM *mail_connect(const char *class, const char *name, int block_mode)
|
||||
msg_info("connect to subsystem %s", path);
|
||||
stream = vstream_fdopen(fd, O_RDWR);
|
||||
timed_ipc_setup(stream);
|
||||
sock_name = concatenate("socket ", path, (char *) 0);
|
||||
vstream_control(stream,
|
||||
VSTREAM_CTL_PATH, path,
|
||||
VSTREAM_CTL_PATH, sock_name,
|
||||
VSTREAM_CTL_END);
|
||||
myfree(sock_name);
|
||||
}
|
||||
myfree(path);
|
||||
return (stream);
|
||||
|
@ -116,7 +116,7 @@ void mail_stream_cleanup(MAIL_STREAM * info)
|
||||
|
||||
/* mail_stream_finish_file - finish file mail stream */
|
||||
|
||||
static int mail_stream_finish_file(MAIL_STREAM * info)
|
||||
static int mail_stream_finish_file(MAIL_STREAM * info, VSTRING *unused_why)
|
||||
{
|
||||
int status = 0;
|
||||
static char wakeup[] = {TRIGGER_REQ_WAKEUP};
|
||||
@ -161,7 +161,7 @@ static int mail_stream_finish_file(MAIL_STREAM * info)
|
||||
|
||||
/* mail_stream_finish_ipc - finish IPC mail stream */
|
||||
|
||||
static int mail_stream_finish_ipc(MAIL_STREAM * info)
|
||||
static int mail_stream_finish_ipc(MAIL_STREAM * info, VSTRING *why)
|
||||
{
|
||||
int status = CLEANUP_STAT_WRITE;
|
||||
|
||||
@ -169,7 +169,9 @@ static int mail_stream_finish_ipc(MAIL_STREAM * info)
|
||||
* Receive the peer's completion status.
|
||||
*/
|
||||
if (attr_scan(info->stream, ATTR_FLAG_MISSING | ATTR_FLAG_EXTRA,
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status, 0) != 1)
|
||||
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
|
||||
ATTR_TYPE_END) != 2)
|
||||
status = CLEANUP_STAT_WRITE;
|
||||
|
||||
/*
|
||||
@ -181,9 +183,9 @@ static int mail_stream_finish_ipc(MAIL_STREAM * info)
|
||||
|
||||
/* mail_stream_finish - finish action */
|
||||
|
||||
int mail_stream_finish(MAIL_STREAM * info)
|
||||
int mail_stream_finish(MAIL_STREAM * info, VSTRING *why)
|
||||
{
|
||||
return (info->finish(info));
|
||||
return (info->finish(info, why));
|
||||
}
|
||||
|
||||
/* mail_stream_file - destination is file */
|
||||
|
@ -22,7 +22,7 @@
|
||||
*/
|
||||
typedef struct MAIL_STREAM MAIL_STREAM;
|
||||
|
||||
typedef int (*MAIL_STREAM_FINISH_FN) (MAIL_STREAM *);
|
||||
typedef int (*MAIL_STREAM_FINISH_FN) (MAIL_STREAM *, VSTRING *);
|
||||
typedef int (*MAIL_STREAM_CLOSE_FN) (VSTREAM *);
|
||||
|
||||
struct MAIL_STREAM {
|
||||
@ -38,7 +38,7 @@ extern MAIL_STREAM *mail_stream_file(const char *, const char *, const char *);
|
||||
extern MAIL_STREAM *mail_stream_service(const char *, const char *);
|
||||
extern MAIL_STREAM *mail_stream_command(const char *);
|
||||
extern void mail_stream_cleanup(MAIL_STREAM *);
|
||||
extern int mail_stream_finish(MAIL_STREAM *);
|
||||
extern int mail_stream_finish(MAIL_STREAM *, VSTRING *);
|
||||
|
||||
|
||||
/* LICENSE
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Version of this program.
|
||||
*/
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20011014"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20011015"
|
||||
extern char *var_mail_version;
|
||||
|
||||
/* LICENSE
|
||||
|
@ -289,7 +289,7 @@ int main(int argc, char **argv)
|
||||
/*
|
||||
* Finish the file.
|
||||
*/
|
||||
if ((status = mail_stream_finish(dst)) != 0)
|
||||
if ((status = mail_stream_finish(dst, (VSTRING *) 0)) != 0)
|
||||
msg_fatal("uid=%ld: %s", (long) uid, cleanup_strerror(status));
|
||||
|
||||
/*
|
||||
|
@ -394,7 +394,7 @@ static void qmqpd_close_file(QMQPD_STATE *state)
|
||||
* Finish the queue file or finish the cleanup conversation.
|
||||
*/
|
||||
if (state->err == 0)
|
||||
state->err = mail_stream_finish(state->dest);
|
||||
state->err = mail_stream_finish(state->dest, state->why_rejected);
|
||||
else
|
||||
mail_stream_cleanup(state->dest);
|
||||
state->dest = 0;
|
||||
@ -453,7 +453,7 @@ static int qmqpd_send_status(QMQPD_STATE *state)
|
||||
"Error: too many hops");
|
||||
} else if ((state->err & CLEANUP_STAT_CONT) != 0) {
|
||||
qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
|
||||
"Error: content rejected");
|
||||
"Error: %s", STR(state->why_rejected));
|
||||
} else if ((state->err & CLEANUP_STAT_WRITE) != 0) {
|
||||
qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
|
||||
"Error: queue file write error");
|
||||
|
@ -45,6 +45,7 @@ typedef struct {
|
||||
char *recipient; /* recipient address */
|
||||
char *protocol; /* protocol name */
|
||||
char *where; /* protocol state */
|
||||
VSTRING *why_rejected; /* REJECT reason */
|
||||
} QMQPD_STATE;
|
||||
|
||||
/*
|
||||
|
@ -74,6 +74,7 @@ QMQPD_STATE *qmqpd_state_alloc(VSTREAM *stream)
|
||||
state->recipient = 0;
|
||||
state->protocol = "QMQP";
|
||||
state->where = "initializing client connection";
|
||||
state->why_rejected = vstring_alloc(10);
|
||||
return (state);
|
||||
}
|
||||
|
||||
@ -92,5 +93,6 @@ void qmqpd_state_free(QMQPD_STATE *state)
|
||||
myfree(state->sender);
|
||||
if (state->recipient)
|
||||
myfree(state->recipient);
|
||||
vstring_free(state->why_rejected);
|
||||
myfree((char *) state);
|
||||
}
|
||||
|
@ -516,7 +516,7 @@ static void enqueue(const int flags, const char *sender, const char *full_name,
|
||||
if (vstream_ferror(VSTREAM_IN))
|
||||
msg_fatal("%s(%ld): error reading input: %m",
|
||||
saved_sender, (long) uid);
|
||||
if ((status = mail_stream_finish(handle)) != 0)
|
||||
if ((status = mail_stream_finish(handle, buf)) != 0)
|
||||
msg_fatal("%s(%ld): %s", saved_sender,
|
||||
(long) uid, cleanup_strerror(status));
|
||||
if (sendmail_path) {
|
||||
|
@ -891,6 +891,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
int curr_rec_type;
|
||||
int prev_rec_type;
|
||||
int first = 1;
|
||||
VSTRING *why = 0;
|
||||
|
||||
/*
|
||||
* Sanity checks. With ESMTP command pipelining the client can send DATA
|
||||
@ -999,7 +1000,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
* Finish the queue file or finish the cleanup conversation.
|
||||
*/
|
||||
if (state->err == 0)
|
||||
state->err |= mail_stream_finish(state->dest);
|
||||
state->err |= mail_stream_finish(state->dest, why = vstring_alloc(10));
|
||||
else
|
||||
mail_stream_cleanup(state->dest);
|
||||
state->dest = 0;
|
||||
@ -1040,7 +1041,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
smtpd_chat_reply(state, "554 Error: too many hops");
|
||||
} else if ((state->err & CLEANUP_STAT_CONT) != 0) {
|
||||
state->error_mask |= MAIL_ERROR_POLICY;
|
||||
smtpd_chat_reply(state, "552 Error: content rejected");
|
||||
smtpd_chat_reply(state, "552 Error: %s", STR(why));
|
||||
} else if ((state->err & CLEANUP_STAT_WRITE) != 0) {
|
||||
state->error_mask |= MAIL_ERROR_RESOURCE;
|
||||
smtpd_chat_reply(state, "451 Error: queue file write error");
|
||||
@ -1062,6 +1063,8 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
*/
|
||||
mail_reset(state);
|
||||
rcpt_reset(state);
|
||||
if (why)
|
||||
vstring_free(why);
|
||||
return (state->err);
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ SRCS = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \
|
||||
sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \
|
||||
hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \
|
||||
sane_socketpair.c myrand.c netstring.c ctable.c attr_print.c intv.c \
|
||||
attr_scan.c attr_table.c
|
||||
attr_scan.c attr_table.c base64_code.c
|
||||
OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
|
||||
close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
|
||||
dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
|
||||
@ -50,7 +50,7 @@ OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
|
||||
sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \
|
||||
hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \
|
||||
sane_socketpair.o myrand.o netstring.o ctable.o attr_print.o intv.o \
|
||||
attr_scan.o attr_table.o
|
||||
attr_scan.o attr_table.o base64_code.o
|
||||
HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
|
||||
dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
|
||||
dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
|
||||
@ -67,7 +67,7 @@ HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
|
||||
dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \
|
||||
watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \
|
||||
sane_time.h sane_socketpair.h myrand.h netstring.h ctable.h \
|
||||
intv.h
|
||||
intv.h base64_code.h
|
||||
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
|
||||
stream_test.c dup2_pass_on_exec.c
|
||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||
@ -84,7 +84,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
|
||||
mystrtok sigdelay translit valid_hostname vstream_popen \
|
||||
vstring vstring_vstream doze select_bug stream_test mac_expand \
|
||||
watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \
|
||||
inet_addr_list attr_print attr_scan attr_table
|
||||
inet_addr_list attr_print attr_scan attr_table base64_code
|
||||
|
||||
LIB_DIR = ../../lib
|
||||
INC_DIR = ../../include
|
||||
@ -303,6 +303,11 @@ attr_table: $(LIB) $@.o
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
|
||||
mv junk $@.o
|
||||
|
||||
base64_code: $(LIB) $@.o
|
||||
mv $@.o junk
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
|
||||
mv junk $@.o
|
||||
|
||||
depend: $(MAKES)
|
||||
(sed '1,/^# do not edit/!d' Makefile.in; \
|
||||
set -e; for i in [a-z][a-z0-9]*.c; do \
|
||||
@ -315,7 +320,7 @@ stream_test: stream_test.c $(LIB)
|
||||
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
|
||||
|
||||
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
|
||||
hex_quote_test ctable_test inet_addr_list_test
|
||||
hex_quote_test ctable_test inet_addr_list_test base64_code_test
|
||||
|
||||
valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
|
||||
./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
|
||||
@ -348,6 +353,9 @@ inet_addr_list_test: inet_addr_list
|
||||
diff inet_addr_list.ref inet_addr_list.tmp
|
||||
rm -f inet_addr_list.tmp
|
||||
|
||||
base64_code_test: base64_code
|
||||
./base64_code
|
||||
|
||||
DB_TYPE = `../postconf/postconf -h default_database_type`
|
||||
|
||||
dict_test: dict_open testdb dict_test.in dict_test.ref
|
||||
@ -387,6 +395,8 @@ attr_print.o: mymalloc.h
|
||||
attr_print.o: vstream.h
|
||||
attr_print.o: vbuf.h
|
||||
attr_print.o: htable.h
|
||||
attr_print.o: base64_code.h
|
||||
attr_print.o: vstring.h
|
||||
attr_print.o: attr.h
|
||||
attr_scan.o: attr_scan.c
|
||||
attr_scan.o: sys_defs.h
|
||||
@ -397,6 +407,7 @@ attr_scan.o: vbuf.h
|
||||
attr_scan.o: vstring.h
|
||||
attr_scan.o: argv.h
|
||||
attr_scan.o: intv.h
|
||||
attr_scan.o: base64_code.h
|
||||
attr_scan.o: attr.h
|
||||
attr_scan.o: htable.h
|
||||
attr_table.o: attr_table.c
|
||||
@ -411,6 +422,13 @@ attr_table.o: vstring_vstream.h
|
||||
attr_table.o: argv.h
|
||||
attr_table.o: intv.h
|
||||
attr_table.o: attr.h
|
||||
base64_code.o: base64_code.c
|
||||
base64_code.o: sys_defs.h
|
||||
base64_code.o: msg.h
|
||||
base64_code.o: mymalloc.h
|
||||
base64_code.o: vstring.h
|
||||
base64_code.o: vbuf.h
|
||||
base64_code.o: base64_code.h
|
||||
basename.o: basename.c
|
||||
basename.o: sys_defs.h
|
||||
basename.o: stringops.h
|
||||
|
@ -92,17 +92,34 @@
|
||||
#include <mymalloc.h>
|
||||
#include <vstream.h>
|
||||
#include <htable.h>
|
||||
#include <base64_code.h>
|
||||
#include <attr.h>
|
||||
|
||||
/* attr_fprintf - encode attribute information on the fly */
|
||||
#define STR(x) vstring_str(x)
|
||||
#define LEN(x) VSTRING_LEN(x)
|
||||
|
||||
static void PRINTFLIKE(2, 3) attr_fprintf(VSTREAM *fp, const char *format,...)
|
||||
/* attr_print_str - encode and send attribute information */
|
||||
|
||||
static void attr_print_str(VSTREAM *fp, const char *str, int len)
|
||||
{
|
||||
va_list ap;
|
||||
static VSTRING *base64_buf;
|
||||
|
||||
va_start(ap, format);
|
||||
vstream_vfprintf(fp, format, ap);
|
||||
va_end(ap);
|
||||
if (base64_buf == 0)
|
||||
base64_buf = vstring_alloc(10);
|
||||
|
||||
base64_encode(base64_buf, str, len);
|
||||
vstream_fputs(STR(base64_buf), fp);
|
||||
}
|
||||
|
||||
static void attr_print_num(VSTREAM *fp, unsigned num)
|
||||
{
|
||||
static VSTRING *plain;
|
||||
|
||||
if (plain == 0)
|
||||
plain = vstring_alloc(10);
|
||||
|
||||
vstring_sprintf(plain, "%u", num);
|
||||
attr_print_str(fp, STR(plain), LEN(plain));
|
||||
}
|
||||
|
||||
/* attr_vprint - send attribute list to stream */
|
||||
@ -136,46 +153,52 @@ int attr_vprint(VSTREAM *fp, int flags, va_list ap)
|
||||
switch (attr_type) {
|
||||
case ATTR_TYPE_NUM:
|
||||
attr_name = va_arg(ap, char *);
|
||||
attr_fprintf(fp, "%s", attr_name);
|
||||
attr_print_str(fp, attr_name, strlen(attr_name));
|
||||
int_val = va_arg(ap, int);
|
||||
attr_fprintf(fp, ":%u", (unsigned) int_val);
|
||||
VSTREAM_PUTC(':', fp);
|
||||
attr_print_num(fp, (unsigned) int_val);
|
||||
if (msg_verbose)
|
||||
msg_info("send attr name %s value %u", attr_name, int_val);
|
||||
msg_info("send attr %s = %u", attr_name, int_val);
|
||||
break;
|
||||
case ATTR_TYPE_STR:
|
||||
attr_name = va_arg(ap, char *);
|
||||
attr_fprintf(fp, "%s", attr_name);
|
||||
attr_print_str(fp, attr_name, strlen(attr_name));
|
||||
str_val = va_arg(ap, char *);
|
||||
attr_fprintf(fp, ":%s", str_val);
|
||||
VSTREAM_PUTC(':', fp);
|
||||
attr_print_str(fp, str_val, strlen(str_val));
|
||||
if (msg_verbose)
|
||||
msg_info("send attr name %s value %s", attr_name, str_val);
|
||||
msg_info("send attr %s = %s", attr_name, str_val);
|
||||
break;
|
||||
case ATTR_TYPE_NUM_ARRAY:
|
||||
attr_name = va_arg(ap, char *);
|
||||
attr_fprintf(fp, "%s", attr_name);
|
||||
attr_print_str(fp, attr_name, strlen(attr_name));
|
||||
ip_val = va_arg(ap, int *);
|
||||
count_val = va_arg(ap, int);
|
||||
for (i = 0; i < count_val; i++)
|
||||
attr_fprintf(fp, ":%u", (unsigned) *ip_val++);
|
||||
for (i = 0; i < count_val; i++) {
|
||||
VSTREAM_PUTC(':', fp);
|
||||
attr_print_num(fp, (unsigned) *ip_val++);}
|
||||
if (msg_verbose)
|
||||
msg_info("send attr name %s values %d", attr_name, count_val);
|
||||
msg_info("send attr %s values %d", attr_name, count_val);
|
||||
break;
|
||||
case ATTR_TYPE_STR_ARRAY:
|
||||
attr_name = va_arg(ap, char *);
|
||||
attr_fprintf(fp, "%s", attr_name);
|
||||
attr_print_str(fp, attr_name, strlen(attr_name));
|
||||
cpp_val = va_arg(ap, char **);
|
||||
count_val = va_arg(ap, int);
|
||||
for (i = 0; i < count_val; i++) {
|
||||
str_val = *cpp_val++;
|
||||
attr_fprintf(fp, ":%s", str_val);
|
||||
VSTREAM_PUTC(':', fp);
|
||||
attr_print_str(fp, str_val, strlen(str_val));
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("send attr name %s values %d", attr_name, count_val);
|
||||
msg_info("send attr %s values %d", attr_name, count_val);
|
||||
break;
|
||||
case ATTR_TYPE_HASH:
|
||||
ht_info_list = htable_list(va_arg(ap, HTABLE *));
|
||||
for (ht = ht_info_list; *ht; ht++) {
|
||||
attr_fprintf(fp, "%s:%s", ht[0]->key, ht[0]->value);
|
||||
attr_print_str(fp, ht[0]->key, strlen(ht[0]->key));
|
||||
VSTREAM_PUTC(':', fp);
|
||||
attr_print_str(fp, ht[0]->value, strlen(ht[0]->value));
|
||||
if (msg_verbose)
|
||||
msg_info("send attr name %s value %s",
|
||||
ht[0]->key, ht[0]->value);
|
||||
|
@ -83,7 +83,7 @@
|
||||
/* For convenience, this value requests none of the above.
|
||||
/* .RE
|
||||
/* .IP type
|
||||
/* The type determines the arguments that follow.
|
||||
/* The type argument determines the arguments that follow.
|
||||
/* .RS
|
||||
/* .IP "ATTR_TYPE_NUM (char *, int *)"
|
||||
/* This argument is followed by an attribute name and an integer pointer.
|
||||
@ -100,15 +100,21 @@
|
||||
/* This is used for recovering a string array attribute value.
|
||||
/* Values from the input stream are appended to the array.
|
||||
/* .IP "ATTR_TYPE_HASH (HTABLE *)"
|
||||
/* All further attributes are stored into the given hash table as simple
|
||||
/* string-valued attributes, under keys equal to the attribute name.
|
||||
/* All further input attributes are required to be simple string or
|
||||
/* integer attributes.
|
||||
/* Their string values are stored in the specified hash table under
|
||||
/* keys equal to the attribute name (obtained from the input stream).
|
||||
/* Values from the input stream are added to the hash table, but existing
|
||||
/* hash table entries are not replaced.
|
||||
/* .sp
|
||||
/* N.B. This must be followed by an ATTR_TYPE_END argument.
|
||||
/* N.B. This construct must be followed by an ATTR_TYPE_END argument.
|
||||
/* .IP ATTR_TYPE_END
|
||||
/* This terminates the requested attribute list.
|
||||
/* This argument terminates the requested attribute list.
|
||||
/* .RE
|
||||
/* BUGS
|
||||
/* ATTR_TYPE_HASH accepts attributes with arbitrary names from an
|
||||
/* untrusted source. This is safe only if the resulting table is
|
||||
/* queried for specific names.
|
||||
/* DIAGNOSTICS
|
||||
/* The result value is the number of attributes that were successfully
|
||||
/* recovered from the input stream (an array-valued attribute counts
|
||||
@ -143,6 +149,7 @@
|
||||
#include <vstring.h>
|
||||
#include <argv.h>
|
||||
#include <intv.h>
|
||||
#include <base64_code.h>
|
||||
#include <attr.h>
|
||||
|
||||
/* Application specific. */
|
||||
@ -155,8 +162,12 @@
|
||||
static int attr_scan_string(VSTREAM *fp, VSTRING *plain_buf, const char *context)
|
||||
{
|
||||
static VSTRING *base64_buf = 0;
|
||||
|
||||
#if 0
|
||||
extern int var_line_limit; /* XXX */
|
||||
int limit = var_line_limit * 5 / 4;
|
||||
|
||||
#endif
|
||||
int ch;
|
||||
|
||||
if (base64_buf == 0)
|
||||
@ -170,14 +181,16 @@ static int attr_scan_string(VSTREAM *fp, VSTRING *plain_buf, const char *context
|
||||
return (-1);
|
||||
}
|
||||
VSTRING_ADDCH(base64_buf, ch);
|
||||
#if 0
|
||||
if (LEN(base64_buf) > limit) {
|
||||
msg_warn("string length > %d characters from %s while reading %s",
|
||||
limit, VSTREAM_PATH(fp), context);
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
VSTRING_TERMINATE(base64_buf);
|
||||
if (BASE64_DECODE(plain_buf, STR(base64_buf), LEN(base64_buf)) == 0) {
|
||||
if (base64_decode(plain_buf, STR(base64_buf), LEN(base64_buf)) == 0) {
|
||||
msg_warn("malformed base64 data from %s: %.100s",
|
||||
VSTREAM_PATH(fp), STR(base64_buf));
|
||||
return (-1);
|
||||
@ -335,7 +348,7 @@ int attr_vscan(VSTREAM *fp, int flags, va_list ap)
|
||||
"attribute value")) < 0)
|
||||
return (conversions);
|
||||
if (ch != '\n') {
|
||||
msg_warn("too many values for number attribute %s from %s",
|
||||
msg_warn("multiple values for attribute %s from %s",
|
||||
STR(name_buf), VSTREAM_PATH(fp));
|
||||
return (conversions);
|
||||
}
|
||||
@ -350,7 +363,7 @@ int attr_vscan(VSTREAM *fp, int flags, va_list ap)
|
||||
if ((ch = attr_scan_string(fp, string, "attribute value")) < 0)
|
||||
return (conversions);
|
||||
if (ch != '\n') {
|
||||
msg_warn("too many values for string attribute %s from %s",
|
||||
msg_warn("multiple values for attribute %s from %s",
|
||||
STR(name_buf), VSTREAM_PATH(fp));
|
||||
return (conversions);
|
||||
}
|
||||
@ -364,7 +377,7 @@ int attr_vscan(VSTREAM *fp, int flags, va_list ap)
|
||||
if ((ch = attr_scan_string(fp, str_buf, "attribute value")) < 0)
|
||||
return (conversions);
|
||||
if (ch != '\n') {
|
||||
msg_warn("too many values for string attribute %s from %s",
|
||||
msg_warn("multiple values for attribute %s from %s",
|
||||
STR(name_buf), VSTREAM_PATH(fp));
|
||||
return (conversions);
|
||||
}
|
||||
|
200
postfix/src/util/base64_code.c
Normal file
200
postfix/src/util/base64_code.c
Normal file
@ -0,0 +1,200 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* base64_code 3
|
||||
/* SUMMARY
|
||||
/* encode/decode data, base 64 style
|
||||
/* SYNOPSIS
|
||||
/* #include <base64_code.h>
|
||||
/*
|
||||
/* VSTRING *base64_encode(result, in, len)
|
||||
/* VSTRING *result;
|
||||
/* const char *in;
|
||||
/* int len;
|
||||
/*
|
||||
/* VSTRING *base64_decode(result, in, len)
|
||||
/* VSTRING *result;
|
||||
/* const char *in;
|
||||
/* int len;
|
||||
/* DESCRIPTION
|
||||
/* base64_encode() takes a block of len bytes and encodes it as one
|
||||
/* null-terminated string. The result value is the result argument.
|
||||
/*
|
||||
/* base64_decode() performs the opposite transformation. The result
|
||||
/* value is the result argument. The result is null terminated, whether
|
||||
/* or not that makes sense.
|
||||
/* DIAGNOSTICS
|
||||
/* base64_decode () returns a null pointer when the input contains
|
||||
/* characters not in the base 64 alphabet.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include "sys_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <mymalloc.h>
|
||||
#include <vstring.h>
|
||||
#include <base64_code.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
static unsigned char to_b64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
#define UNSIG_CHAR_PTR(x) ((unsigned char *)(x))
|
||||
|
||||
/* base64_encode - raw data to encoded */
|
||||
|
||||
VSTRING *base64_encode(VSTRING *result, const char *in, int len)
|
||||
{
|
||||
const unsigned char *cp;
|
||||
int count;
|
||||
|
||||
/*
|
||||
* Encode 3 -> 4.
|
||||
*/
|
||||
VSTRING_RESET(result);
|
||||
for (cp = UNSIG_CHAR_PTR(in), count = len; count > 0; count -= 3, cp += 3) {
|
||||
VSTRING_ADDCH(result, to_b64[cp[0] >> 2]);
|
||||
if (count > 1) {
|
||||
VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4 | cp[1] >> 4]);
|
||||
if (count > 2) {
|
||||
VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2 | cp[2] >> 6]);
|
||||
VSTRING_ADDCH(result, to_b64[cp[2] & 0x3f]);
|
||||
} else {
|
||||
VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2]);
|
||||
VSTRING_ADDCH(result, '=');
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4]);
|
||||
VSTRING_ADDCH(result, '=');
|
||||
VSTRING_ADDCH(result, '=');
|
||||
break;
|
||||
}
|
||||
}
|
||||
VSTRING_TERMINATE(result);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* base64_decode - encoded data to raw */
|
||||
|
||||
VSTRING *base64_decode(VSTRING *result, const char *in, int len)
|
||||
{
|
||||
static char *un_b64 = 0;
|
||||
const unsigned char *cp;
|
||||
int count;
|
||||
int ch0;
|
||||
int ch1;
|
||||
int ch2;
|
||||
int ch3;
|
||||
|
||||
#define CHARS_PER_BYTE 256
|
||||
#define INVALID 0xff
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
if (len % 4)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Once: initialize the decoding lookup table on the fly.
|
||||
*/
|
||||
if (un_b64 == 0) {
|
||||
un_b64 = mymalloc(CHARS_PER_BYTE);
|
||||
memset(un_b64, INVALID, CHARS_PER_BYTE);
|
||||
for (cp = to_b64; cp < to_b64 + sizeof(to_b64); cp++)
|
||||
un_b64[*cp] = cp - to_b64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode 4 -> 3.
|
||||
*/
|
||||
VSTRING_RESET(result);
|
||||
for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 4) {
|
||||
if ((ch0 = un_b64[*cp++]) == INVALID
|
||||
|| (ch1 = un_b64[*cp++]) == INVALID)
|
||||
return (0);
|
||||
VSTRING_ADDCH(result, ch0 << 2 | ch1 >> 4);
|
||||
if ((ch2 = *cp++) == '=')
|
||||
break;
|
||||
if ((ch2 = un_b64[ch2]) == INVALID)
|
||||
return (0);
|
||||
VSTRING_ADDCH(result, ch1 << 4 | ch2 >> 2);
|
||||
if ((ch3 = *cp++) == '=')
|
||||
break;
|
||||
if ((ch3 = un_b64[ch3]) == INVALID)
|
||||
return (0);
|
||||
VSTRING_ADDCH(result, ch2 << 6 | ch3);
|
||||
}
|
||||
VSTRING_TERMINATE(result);
|
||||
return (result);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
* Proof-of-concept test program: convert to base 64 and back.
|
||||
*/
|
||||
|
||||
#define STR(x) vstring_str(x)
|
||||
#define LEN(x) VSTRING_LEN(x)
|
||||
|
||||
int main(int unused_argc, char **unused_argv)
|
||||
{
|
||||
VSTRING *b1 = vstring_alloc(1);
|
||||
VSTRING *b2 = vstring_alloc(1);
|
||||
char *test = "this is a test";
|
||||
|
||||
#define DECODE(b,s,l) { \
|
||||
if (base64_decode((b),(s),(l)) == 0) \
|
||||
msg_panic("bad base64: %s", (s)); \
|
||||
}
|
||||
#define VERIFY(b,t) { \
|
||||
if (strcmp((b), (t)) != 0) \
|
||||
msg_panic("bad test: %s", (b)); \
|
||||
}
|
||||
|
||||
base64_encode(b1, test, strlen(test));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
VERIFY(STR(b2), test);
|
||||
|
||||
base64_encode(b1, test, strlen(test));
|
||||
base64_encode(b2, STR(b1), LEN(b1));
|
||||
base64_encode(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
DECODE(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
VERIFY(STR(b2), test);
|
||||
|
||||
base64_encode(b1, test, strlen(test));
|
||||
base64_encode(b2, STR(b1), LEN(b1));
|
||||
base64_encode(b1, STR(b2), LEN(b2));
|
||||
base64_encode(b2, STR(b1), LEN(b1));
|
||||
base64_encode(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
DECODE(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
DECODE(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
VERIFY(STR(b2), test);
|
||||
|
||||
vstring_free(b1);
|
||||
vstring_free(b2);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
36
postfix/src/util/base64_code.h
Normal file
36
postfix/src/util/base64_code.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef _BASE64_CODE_H_INCLUDED_
|
||||
#define _BASE64_CODE_H_INCLUDED_
|
||||
|
||||
/*++
|
||||
/* NAME
|
||||
/* base64_code 3h
|
||||
/* SUMMARY
|
||||
/* encode/decode data, base 64 style
|
||||
/* SYNOPSIS
|
||||
/* #include <base64_code.h>
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* Utility library.
|
||||
*/
|
||||
#include <vstring.h>
|
||||
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
extern VSTRING *base64_encode(VSTRING *, const char *, int);
|
||||
extern VSTRING *base64_decode(VSTRING *, const char *, int);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user