/*++
/* NAME
/* deliver_pass 3
/* SUMMARY
/* deliver request pass_through
/* SYNOPSIS
/* #include <deliver_request.h>
/*
/* int deliver_pass(class, service, request, recipient)
/* const char *class;
/* const char *service;
/* DELIVER_REQUEST *request;
/* RECIPIENT *recipient;
/*
/* int deliver_pass_all(class, service, request)
/* const char *class;
/* const char *service;
/* DELIVER_REQUEST *request;
/* DESCRIPTION
/* This module implements the client side of the `queue manager
/* to delivery agent' protocol, passing one recipient on from
/* one delivery agent to another.
/*
/* deliver_pass() delegates delivery of the named recipient.
/*
/* deliver_pass_all() delegates an entire delivery request.
/*
/* Arguments:
/* .IP class
/* Destination delivery agent service class
/* .IP service
/* String of the form \fItransport\fR:\fInexthop\fR. Either transport
/* or nexthop are optional. For details see the transport map manual page.
/* .IP request
/* Delivery request with queue file information.
/* .IP recipient
/* Recipient information. See recipient_list(3).
/* DIAGNOSTICS
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* BUGS
/* One recipient at a time; this is OK for mailbox deliveries.
/*
/* Hop status information cannot be passed back.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*
/* Wietse Venema
/* porcupine.org
/*--*/
/* System library. */
#include <sys_defs.h>
/* Utility library. */
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <split_at.h>
#include <mymalloc.h>
/* Global library. */
#include <mail_params.h>
#include <deliver_pass.h>
#include <dsb_scan.h>
#include <defer.h>
#include <rcpt_print.h>
#include <info_log_addr_form.h>
#define DELIVER_PASS_DEFER 1
#define DELIVER_PASS_UNKNOWN 2
/* deliver_pass_initial_reply - retrieve initial delivery process response */
static int deliver_pass_initial_reply(VSTREAM *stream)
{
if (attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_STREQ(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_DELIVER),
ATTR_TYPE_END) != 0 ) {
msg_warn("%s: malformed response" , VSTREAM_PATH(stream));
return (-1 );
}
return (0 );
}
/* deliver_pass_send_request - send delivery request to delivery process */
static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
const char *nexthop,
RECIPIENT *rcpt)
{
int stat;
attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_INT(MAIL_ATTR_FLAGS, request->flags),
SEND_ATTR_STR(MAIL_ATTR_QUEUE, request->queue_name),
SEND_ATTR_STR(MAIL_ATTR_QUEUEID, request->queue_id),
SEND_ATTR_LONG(MAIL_ATTR_OFFSET, request->data_offset),
SEND_ATTR_LONG(MAIL_ATTR_SIZE, request->data_size),
SEND_ATTR_STR(MAIL_ATTR_NEXTHOP, nexthop),
SEND_ATTR_STR(MAIL_ATTR_ENCODING, request->encoding),
SEND_ATTR_INT(MAIL_ATTR_SENDOPTS, request->sendopts),
SEND_ATTR_STR(MAIL_ATTR_SENDER, request->sender),
SEND_ATTR_STR(MAIL_ATTR_DSN_ENVID, request->dsn_envid),
SEND_ATTR_INT(MAIL_ATTR_DSN_RET, request->dsn_ret),
SEND_ATTR_FUNC(msg_stats_print, (const void *) &request->msg_stats),
/* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_NAME, request->client_name),
SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_ADDR, request->client_addr),
SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_PORT, request->client_port),
SEND_ATTR_STR(MAIL_ATTR_LOG_PROTO_NAME, request->client_proto),
SEND_ATTR_STR(MAIL_ATTR_LOG_HELO_NAME, request->client_helo),
/* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
SEND_ATTR_STR(MAIL_ATTR_SASL_METHOD, request->sasl_method),
SEND_ATTR_STR(MAIL_ATTR_SASL_USERNAME, request->sasl_username),
SEND_ATTR_STR(MAIL_ATTR_SASL_SENDER, request->sasl_sender),
/* XXX Ditto if we want to pass TLS certificate info. */
SEND_ATTR_STR(MAIL_ATTR_LOG_IDENT, request->log_ident),
SEND_ATTR_STR(MAIL_ATTR_RWR_CONTEXT, request->rewrite_context),
SEND_ATTR_INT(MAIL_ATTR_RCPT_COUNT, 1 ),
ATTR_TYPE_END);
attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_FUNC(rcpt_print, (const void *) rcpt),
ATTR_TYPE_END);
if (vstream_fflush(stream)) {
msg_warn("%s: bad write: %m" , VSTREAM_PATH(stream));
stat = -1 ;
} else {
stat = 0 ;
}
return (stat);
}
/* deliver_pass_final_reply - retrieve final delivery status response */
static int deliver_pass_final_reply(VSTREAM *stream, DSN_BUF *dsb)
{
int stat;
if (attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_FUNC(dsb_scan, (void *) dsb),
RECV_ATTR_INT(MAIL_ATTR_STATUS, &stat),
ATTR_TYPE_END) != 2 ) {
msg_warn("%s: malformed response" , VSTREAM_PATH(stream));
return (DELIVER_PASS_UNKNOWN);
} else {
return (stat ? DELIVER_PASS_DEFER : 0 );
}
}
/* deliver_pass - deliver one per-site queue entry */
int deliver_pass(const char *class , const char *service,
DELIVER_REQUEST *request,
RECIPIENT *rcpt)
{
VSTREAM *stream;
DSN_BUF *dsb;
DSN dsn;
int status;
char *saved_service;
char *transport;
char *nexthop;
/*
* Parse service into transport : nexthop form , and allow for omission of
* optional fields
*/
transport = saved_service = mystrdup(service);
if ((nexthop = split_at(saved_service, ':' )) == 0 || *nexthop == 0 )
nexthop = request->nexthop;
if (*transport == 0 )
msg_fatal("missing transport name in \" %s\"" , service);
/*
* Initialize .
*/
msg_info("%s: passing <%s> to transport=%s" ,
request->queue_id, info_log_addr_form_recipient(rcpt->address),
transport);
stream = mail_connect_wait(class , transport);
dsb = dsb_create();
/*
* Get the delivery process initial response . Send the queue file info
* and recipient info to the delivery process . Retrieve the delivery
* agent status report . The numerical status code indicates if delivery
* should be tried again . The reason text is sent only when a destination
* should be avoided for a while , so that the queue manager can log why
* it does not even try to schedule delivery to the affected recipients .
* XXX Can ' t pass back hop status info because the problem is with a
* different transport .
*/
if (deliver_pass_initial_reply(stream) != 0
|| deliver_pass_send_request(stream, request, nexthop, rcpt) != 0 ) {
(void ) DSN_SIMPLE(&dsn, "4.3.0" , "mail transport unavailable" );
status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id, &request->msg_stats,
rcpt, "none" , NO_TLS_STATS, &dsn);
} else if ((status = deliver_pass_final_reply(stream, dsb))
== DELIVER_PASS_UNKNOWN) {
(void ) DSN_SIMPLE(&dsn, "4.3.0" , "unknown mail transport error" );
status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id, &request->msg_stats,
rcpt, "none" , NO_TLS_STATS, &dsn);
}
/*
* Clean up .
*/
vstream_fclose(stream);
dsb_free(dsb);
myfree(saved_service);
return (status);
}
/* deliver_pass_all - pass entire delivery request */
int deliver_pass_all(const char *class , const char *service,
DELIVER_REQUEST *request)
{
RECIPIENT_LIST *list;
RECIPIENT *rcpt;
int status = 0 ;
/*
* XXX We should find out if the target transport can handle
* multi - recipient requests . Unfortunately such code is hard to test ,
* rarely used , and therefore will be buggy .
*/
list = &request->rcpt_list;
for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
status |= deliver_pass(class , service, request, rcpt);
return (status);
}
Messung V0.5 in Prozent C=75 H=96 G=86
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland