diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-06-04 17:22:05 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-06-04 17:22:05 +0000 |
commit | e462754c736fbf815b20acea417333564f6b9981 (patch) | |
tree | 318824cab7988ea0acefb5e7463ff92d6fcfef05 | |
parent | 9263a485750e02a7115f71c086cc289ac5924dce (diff) | |
download | mailfromd-e462754c736fbf815b20acea417333564f6b9981.tar.gz mailfromd-e462754c736fbf815b20acea417333564f6b9981.tar.bz2 |
Moved to src/
git-svn-id: file:///svnroot/mailfromd/trunk@18 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r-- | daemon.c | 195 | ||||
-rw-r--r-- | dns.c | 194 | ||||
-rw-r--r-- | mailfrom.h | 43 | ||||
-rw-r--r-- | main.c | 1398 | ||||
-rw-r--r-- | obstack.c | 498 | ||||
-rw-r--r-- | obstack.h | 519 | ||||
-rw-r--r-- | snprintf.c | 830 | ||||
-rw-r--r-- | snprintf.h | 203 |
8 files changed, 0 insertions, 3880 deletions
diff --git a/daemon.c b/daemon.c deleted file mode 100644 index 25e51a62..00000000 --- a/daemon.c +++ /dev/null @@ -1,195 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include <stdio.h> -#include <fcntl.h> -#include <unistd.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/wait.h> - -#ifdef HAVE_PATHS_H -# include <paths.h> -#endif - -#ifndef _PATH_DEVNULL -# define _PATH_DEVNULL "/dev/null" -#endif - -/* - According to Unix-FAQ maintained by Andrew Gierth: - - 1.fork() so the parent can exit, this returns control to the command - line or shell invoking your program. This step is required so that the - new process is guaranteed not to be a process group leader. The next - step, setsid(), fails if you're a process group leader. - - 2.setsid() to become a process group and session group leader. Since a - controlling terminal is associated with a session, and this new session - has not yet acquired a controlling terminal our process now has no - controlling terminal, which is a Good Thing for daemons. - - 3.fork() again so the parent, (the session group leader), can exit. This - means that we, as a non-session group leader, can never regain a - controlling terminal. - - 4.chdir("/") to ensure that our process doesn't keep any directory in use. - Failure to do this could make it so that an administrator couldn't unmount - a filesystem, because it was our current directory. - [Equivalently, we could change to any directory containing files important - to the daemon's operation.] - - 5.umask(0) so that we have complete control over the permissions of - anything we write. We don't know what umask we may have inherited. - [This step is optional] - - 6.close() fds 0, 1, and 2. This releases the standard in, out, and error - we inherited from our parent process. We have no way of knowing where - these fds might have been redirected to. Note that many daemons use - sysconf() to determine the limit _SC_OPEN_MAX. _SC_OPEN_MAX tells you the - maximun open files/process. Then in a loop, the daemon can close all - possible file descriptors. You have to decide if you need to do this or not. - If you think that there might be file-descriptors open you should close - them, since there's a limit on number of concurrent file descriptors. - - 7.Establish new open descriptors for stdin, stdout and stderr. Even if - you don't plan to use them, it is still a good idea to have them open. - The precise handling of these is a matter of taste; if you have a logfile, - for example, you might wish to open it as stdout or stderr, and open - `/dev/null' as stdin; alternatively, you could open `/dev/console' as - stderr and/or stdout, and `/dev/null' as stdin, or any other combination - that makes sense for your particular daemon. */ - -#define MAXFD 64 - -void -waitdaemon_timeout (int signo ARG_UNUSED) -{ - int left; - - left = alarm (0); - signal (SIGALRM, SIG_DFL); - if (left == 0) - { - fprintf (stderr, "timed out waiting for child\n"); - exit (1); - } -} - -/* waitdaemon is like daemon, but optionally the parent pause up - until maxwait before exiting. Return -1, on error, otherwise - waitdaemon will return the pid of the parent. */ - -int -waitdaemon (int nochdir, int noclose, int maxwait) -{ - int fd; - pid_t childpid; - pid_t ppid; - - ppid = getpid (); - - switch (childpid = fork ()) - { - case -1: /* Something went wrong. */ - return (-1); - - case 0: /* In the child. */ - break; - - default: /* In the parent. */ - if (maxwait > 0) - { - signal (SIGALRM, waitdaemon_timeout); - alarm (maxwait); - pause (); - } - _exit(0); - } - - if (setsid () == -1) - return -1; - - /* SIGHUP is ignore because when the session leader terminates - all process in the session (the second child) are sent the SIGHUP. */ - signal (SIGHUP, SIG_IGN); - - switch (fork ()) - { - case 0: - break; - - case -1: - return -1; - - default: - _exit (0); - } - - if (!nochdir) - chdir ("/"); - - if (!noclose) - { - int i; - long fdlimit = -1; - -#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX) - fdlimit = sysconf (_SC_OPEN_MAX); -#elif defined (HAVE_GETDTABLESIZE) - fdlimit = getdtablesize (); -#endif - - if (fdlimit == -1) - fdlimit = MAXFD; - - for (i = 0; i < fdlimit; i++) - close (i); - - fd = open (_PATH_DEVNULL, O_RDWR, 0); - if (fd != -1) - { - dup2 (fd, STDIN_FILENO); - dup2 (fd, STDOUT_FILENO); - dup2 (fd, STDERR_FILENO); - if (fd > 2) - close (fd); - } - } - return ppid; -} - -int -daemon (int nochdir, int noclose) -{ - return (waitdaemon (nochdir, noclose, 0) == -1) ? -1 : 0; -} @@ -1,194 +0,0 @@ -/* This file is part of mailfrom filter. - Copyright (C) 2005, Sergey Poznyakoff - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301 USA */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdlib.h> -#include <resolv.h> -#include <arpa/nameser.h> -#include <netdb.h> -#include <pthread.h> -#include <mailutils/mailutils.h> -#include "mailfrom.h" - -struct mx_buffer { - unsigned pref; - char *name; -}; - -static int -comp_pref(const void *a, const void *b) -{ - const struct mx_buffer *ma = a, *mb = b; - if (ma->pref > mb->pref) - return 1; - else if (ma->pref < mb->pref) - return -1; - return 0; -} - -static void -free_mx_buffer(struct mx_buffer *mx_buffer, int nmx) -{ - int i; - for (i = 0; i < nmx; i++) - free(mx_buffer[i].name); -} - -static getmx_status -_getmx(char *host, char *answer, size_t answer_size, mxbuf_t mxbuf) -{ - int n, nmx, i, count; - ns_msg msg; - struct mx_buffer mx_buffer[MAXMXCOUNT]; - - debug(100,("Getting MX records for %s", host)); - n = res_query (host, C_IN, T_MX, answer, answer_size); - if (n < 0) { - debug(10, ("res_query failed (errno=%s, h_errno=%d)", - mu_strerror(errno), h_errno)); - switch (h_errno) { - case NO_DATA: - case NO_RECOVERY: - case HOST_NOT_FOUND: - return getmx_not_found; - - case TRY_AGAIN: - case -1: - return getmx_temp_failure; - - default: - mu_error("res_nsearch(%s) failed with unexpected h_errno %d", - host, h_errno); - return getmx_failure; - } - } - - if (ns_initparse(answer, n, &msg) < 0) { - debug(2,("ns_initparse(host %s) failed", host)); - return getmx_failure; - } - - /* Get number of MXs */ - count = ns_msg_count(msg, ns_s_an); - if (count == 0) - return getmx_not_found; - - /* Collect MX records */ - for (i = nmx = 0; i < count; i++) { - ns_rr rr; - - if (ns_parserr(&msg, ns_s_an, i, &rr) < 0) { - debug(2,("ns_parserrd(%d) failed (host %s)", - i, host)); - free_mx_buffer(mx_buffer, nmx); - return getmx_failure; - } - if (ns_rr_type(rr) == ns_t_mx) { - int s; - char tname[NS_MAXDNAME]; - const u_char *rdata; - int rdlen; - - rdata = ns_rr_rdata(rr); - rdlen = ns_rr_rdlen(rr); - - s = dn_expand(ns_msg_base(msg), ns_msg_end(msg), - rdata+NS_INT16SZ, tname, sizeof tname); - if (s < 0) { - debug(2,("dn_expand failed")); - free_mx_buffer(mx_buffer, nmx); - return getmx_failure; - } - mx_buffer[nmx].pref = ns_get16(rdata); - mx_buffer[nmx].name = strdup(tname); - debug(100,("MX %u %s", mx_buffer[nmx].pref, - mx_buffer[nmx].name)); - if (nmx++ > MAXMXCOUNT) - break; - } - } - - /* Sort according to preference value */ - qsort(mx_buffer, nmx, sizeof mx_buffer[0], comp_pref); - - /* Prepare return value */ - memset(mxbuf, 0, sizeof(mxbuf_t)); - for (i = 0; i < nmx; i++) - mxbuf[i] = mx_buffer[i].name; - return getmx_success; -} - -static int -is_ipaddr(char *str) -{ - for (; *str; str++) - if (!(isdigit(*str) || *str == '.')) - return 0; - return 1; -} - -static pthread_mutex_t getmx_mutex = PTHREAD_MUTEX_INITIALIZER; - -getmx_status -getmx(char *host, mxbuf_t mxbuf) -{ - char hbuf[NI_MAXHOST]; - getmx_status status = getmx_failure; - - pthread_mutex_lock(&getmx_mutex); - if (is_ipaddr(host)) { - struct sockaddr_in sa; - memset(&sa, 0, sizeof sa); - sa.sin_family = AF_INET; - if (inet_aton(host, &sa.sin_addr) - && getnameinfo((struct sockaddr *)&sa, sizeof sa, - hbuf, sizeof(hbuf), - NULL, 0, - 0) == 0 - && !is_ipaddr(hbuf)) - host = hbuf; - else - host = NULL; - } - - if (host) { - unsigned char *answer = malloc(MAXPACKET); - if (!answer) - status = getmx_failure; - else { - char *p; - - for (p = hbuf; p; ) { - status = _getmx(p, answer, MAXPACKET, mxbuf); - if (status == getmx_success) - break; - p = strchr(p, '.'); - if (!p) - break; - p++; - } - free(answer); - } - } - pthread_mutex_unlock(&getmx_mutex); - return status; -} - diff --git a/mailfrom.h b/mailfrom.h deleted file mode 100644 index 0dd25e44..00000000 --- a/mailfrom.h +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of mailfrom filter. - Copyright (C) 2005, Sergey Poznyakoff - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301 USA */ - -# ifndef MAXPACKET -# define MAXPACKET 8192 /* max packet size used internally by BIND */ -# endif /* ! MAXPACKET */ - -typedef enum { - getmx_success, - getmx_not_found, - getmx_failure, - getmx_temp_failure, -} getmx_status; - -#define MAXMXCOUNT 32 -typedef char *mxbuf_t[MAXMXCOUNT]; - -#define DEFAULT_PIDFILE LOCALSTATEDIR "/mailfromd.pid" - -#define debug(lev,c) do if (debug_level >= lev) {\ - debug_log("%s:%lu:%s: ", __FILE__, __LINE__, __FUNCTION__); \ - debug_log c; \ -} while (0) - -extern int debug_level; - -extern getmx_status getmx(char *ipstr, mxbuf_t mxbuf); - diff --git a/main.c b/main.c deleted file mode 100644 index a3c08c0f..00000000 --- a/main.c +++ /dev/null @@ -1,1398 +0,0 @@ -/* This file is part of mailfrom filter. - Copyright (C) 2005, Sergey Poznyakoff - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301 USA */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free -#include <obstack.h> -#include <syslog.h> -#include <pwd.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <pthread.h> - -#ifdef HAVE_SYSEXITS_H -# include <sysexits.h> -#else -# define EX_OK 0 /* successful termination */ -# define EX__BASE 64 /* base value for error messages */ -# define EX_USAGE 64 /* command line usage error */ -# define EX_DATAERR 65 /* data format error */ -# define EX_NOINPUT 66 /* cannot open input */ -# define EX_NOUSER 67 /* addressee unknown */ -# define EX_NOHOST 68 /* host name unknown */ -# define EX_UNAVAILABLE 69 /* service unavailable */ -# define EX_SOFTWARE 70 /* internal software error */ -# define EX_OSERR 71 /* system error (e.g., can't fork) */ -# define EX_OSFILE 72 /* critical OS file missing */ -# define EX_CANTCREAT 73 /* can't create (user) output file */ -# define EX_IOERR 74 /* input/output error */ -# define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ -# define EX_PROTOCOL 76 /* remote error in protocol */ -# define EX_NOPERM 77 /* permission denied */ -# define EX_CONFIG 78 /* configuration error */ -# define EX__MAX 78 /* maximum listed value */ -#endif - -#include <mailutils/mailutils.h> -#include <mailutils/argp.h> -#include <libmilter/mfapi.h> - -#include "mailfrom.h" - - -/* Verification methods */ -typedef sfsistat (*method_fp)(SMFICTX *ctx, char *email, char *client_addr); - -static sfsistat method_standard(SMFICTX *ctx, char *email, char *client_addr); -static sfsistat method_strict(SMFICTX *ctx, char *email, char *client_addr); - -struct method_tab { - char *name; - method_fp handler; -}; - -struct method_tab method_tab[] = { - { "standard", method_standard }, - { "strict", method_strict }, - NULL -}; - -static method_fp method = method_standard; - -static method_fp -find_method(char *name) -{ - struct method_tab *p; - - for (p = method_tab; p->name; p++) - if (strcmp(p->name, name) == 0) - return p->handler; - return NULL; -} - - -/* An actions is described by "action function", that actually performs - what should be done, and "action data", that supply necessary data to - the function. - - Action data may be of the following two types: */ - -/* 1. Return action. Describes what value to return to Milter and, optionally, - how to set the SMTP reply state. */ -struct return_action { - sfsistat status; /* Return status */ - char *code; /* State code. Three digits, e.g. "550" */ - char *xcode; /* Extended state code, e.g. "5.5.3" */ - char *message; /* Textual message */ -}; - -/* 2. Header action. Instructs mainfromd to add this header to the message */ -struct header_action { - char *name; /* Header name */ - char *value; /* Header value */ -}; - -/* Combine both structures */ -union action_data { - struct return_action ret; - struct header_action hdr; -}; - -/* Action function has the following type */ -typedef sfsistat (*action_fp)(SMFICTX *ctx, union action_data *data); - -/* Handy macro used to create bitmaps of allowed return values */ -#define MAP(c) (1<<(c)) - -/* Actions and corresponding closures. Apart from function/data pare, we - define a textual default action, and a map of allowed Milter return - codes. - All variables are in BSS. They are initialized to their values (either - explicit or default) by parse_opt() function below. */ -action_fp action_success; -union action_data action_success_data; -#define action_success_default "return:accept" -#define action_success_map MAP(SMFIS_ACCEPT)|MAP(SMFIS_CONTINUE) - -action_fp action_failure; -union action_data action_failure_data; -#define action_failure_default "return:accept" -#define action_failure_map MAP(SMFIS_ACCEPT)|MAP(SMFIS_CONTINUE)|\ - MAP(SMFIS_DISCARD)|MAP(SMFIS_REJECT) - -action_fp action_bad_sender; -union action_data action_bad_sender_data; -#define action_bad_sender_default "return:reject" -#define action_bad_sender_map MAP(SMFIS_DISCARD)|MAP(SMFIS_REJECT) - -action_fp action_temp_failure; -union action_data action_temp_failure_data; -#define action_temp_failure_default "return:tempfail" -#define action_temp_failure_map MAP(SMFIS_ACCEPT)|MAP(SMFIS_CONTINUE)|\ - MAP(SMFIS_DISCARD)|MAP(SMFIS_REJECT)|\ - MAP(SMFIS_TEMPFAIL) - -/* Add_header keeps the header to be added for mlfi_eom() function */ -struct header_action *add_header; - - -/* Configurable options */ -int do_transcript; /* Enable session transript */ -int debug_level; /* Debugging level */ -int test_mode; /* Enable test mode */ -int log_to_stderr; /* Use stderr for logging */ -char *smtp_domain; /* Default SMTP domain for EHLO command */ -char *portspec = DEFAULT_SOCKET; /* Communication socket specification */ -int force_remove; /* Remove local communication socket if it already - exists */ -int foreground; /* Stay in foreground */ - -char *pidfile = DEFAULT_PIDFILE; -char *user = DEFAULT_USER; /* Switch to this user privileges after startup */ -/* I/O settings */ -unsigned io_timeout = 3; -unsigned io_attempts = 3; - - -/* Logging & debugging */ -static const char *sfsistat_str(sfsistat stat); - -int -syslog_printer (int prio, const char *fmt, va_list ap) -{ -#ifdef HAVE_VSYSLOG - vsyslog (prio, fmt, ap); -#else - char buf[128]; - vsnprintf (buf, sizeof buf, fmt, ap); - syslog (prio, "%s", buf); -#endif - return 0; -} - -int -syslog_error_printer (const char *fmt, va_list ap) -{ - return syslog_printer(LOG_ERR, fmt, ap); -} - -void -vlogmsg(int prio, char *fmt, va_list ap) -{ - if (log_to_stderr) { - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - } else - syslog_printer(prio, fmt, ap); -} - -void -logmsg(int prio, char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vlogmsg(prio, fmt, ap); - va_end(ap); -} - -void -transcript(char *prefix, char *msg) -{ - if (do_transcript) { - int len = strlen(msg); - if (msg[len-1] == '\n') { - --len; - if (len > 0 && msg[len-1] == '\r') - --len; - } - if (len) - logmsg(LOG_INFO, "%s %*.*s", prefix, len, len, msg); - } -} - -void -debug_log(char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vlogmsg(LOG_DEBUG, fmt, ap); - va_end(ap); -} - - -/* Sendmail class file support */ - -static list_t domain_list; - -static int -compare_string(const void *item, const void *value) -{ - return strcmp(item, value); -} - -/* Read domains from sendmail-style domain file NAME and store them in - DOMAIN_LIST */ -void -read_domain_file(char *name) -{ - FILE *fp; - char buf[256]; - char *p; - - fp = fopen(name, "r"); - if (!fp) { - mu_error("cannot open file `%s': %s", - name, mu_strerror(errno)); - return; - } - - if (!domain_list) { - list_create(&domain_list); - list_set_comparator(domain_list, compare_string); - } - - while (p = fgets(buf, sizeof buf, fp)) { - char *q; - - while (*p && isspace(*p)) - p++; - if (*p == '#') - continue; - - for (q = p + strlen(p) - 1; q > p && isspace(*q); q--) - *q = 0; - - if (*p == 0) - continue; - - list_append(domain_list, strdup(p)); - } - - fclose(fp); -} - -/* Return true if we relay domain NAME */ -int -relayed_domain_p(char *name) -{ - char *p; - - for (p = strchr(name, '.'); p; p = strchr(p+1, '.')) - if (list_locate(domain_list, p+1, NULL) == 0) { - debug(10,("%s is in relayed domain %s", - name, p+1)); - return 1; - } - return 0; -} - -/* Return true if CLIENT represents a host we relay. CLIENT is a dotted-quad - IP address. */ -int -host_in_relayed_domain_p(char *client) -{ - int rc; - struct sockaddr_in sa; - char hbuf[NI_MAXHOST]; - - if (list_is_empty(domain_list)) - return 0; - - memset(&sa, 0, sizeof sa); - sa.sin_family = AF_INET; - if (inet_aton(client, &sa.sin_addr) == 0) - return 0; - rc = getnameinfo((struct sockaddr *)&sa, sizeof sa, - hbuf, sizeof(hbuf), - NULL, 0, - 0); - if (rc) - return 0; - return relayed_domain_p(hbuf); -} - - -/* Action functions */ - -/* Return */ -static sfsistat -action_return(SMFICTX *ctx, union action_data *data) -{ - if (data->ret.code) - smfi_setreply(ctx, data->ret.code, data->ret.xcode, - data->ret.message); - return data->ret.status; -} - -/* Add header */ -static sfsistat -action_add(SMFICTX *ctx, union action_data *data) -{ - add_header = &data->hdr; - return SMFIS_CONTINUE; -} - - -/* SMTP I/O functions */ - -#define MLFIPRIV(ctx) ((struct smtp_io_data*) smfi_getpriv(ctx)) - -struct smtp_io_data { - SMFICTX *ctx; /* Milter context */ - stream_t stream; /* I/O stream */ - size_t send_off; /* Send offset */ - size_t recv_off; /* Receive offset */ - struct obstack stk; /* Obstack for keeping commands/replies */ - char *command; /* Last issued command */ - char *reply; /* Last received reply */ - char *start; /* First line of the reply, if it was multiline */ - char buf[128]; /* Input buffer */ - size_t level; /* Number of bytes in buf */ - int code; /* Reply code */ -}; - -void -smtp_io_data_init(struct smtp_io_data *dat, SMFICTX *ctx, stream_t stream) -{ - obstack_init(&dat->stk); - dat->send_off = dat->recv_off = 0; - dat->stream = stream; - dat->start = dat->command = dat->reply = NULL; - dat->level = 0; - dat->ctx = ctx; - if (ctx) /* save the private data */ - smfi_setpriv(ctx, dat); -} - -void -smtp_io_data_destroy(struct smtp_io_data *dat) -{ - if (dat) { - stream_close (dat->stream); - stream_destroy(&dat->stream, stream_get_owner(dat->stream)); - obstack_free(&dat->stk, NULL); - if (dat->ctx) - smfi_setpriv(dat->ctx, NULL); - } -} - -void -smtp_stream_wait(stream_t stream, int flags) -{ - struct timeval tv; - tv.tv_sec = io_timeout; - tv.tv_usec = 0; - stream_wait(stream, &flags, &tv); -} - -void -smtp_wait(struct smtp_io_data *dat, int flags) -{ - return smtp_stream_wait(dat->stream, flags); -} - -int -smtp_send(struct smtp_io_data *dat, char *command) -{ - int attempt = 0; - size_t len = strlen(command); - - transcript("SEND:", command); - do { - size_t nb; - int rc = stream_write(dat->stream, command, len, - dat->send_off, &nb); - if (rc == 0) { - dat->send_off += nb; - len -= nb; - command += nb; - } else if (rc == EAGAIN) { - if (attempt > io_attempts) { - mu_error ("stream_write timed out"); - return -1; - } else { - smtp_wait(dat, MU_STREAM_READY_WR); - attempt++; - continue; - } - } else { - mu_error ("stream_write: %s", mu_strerror (rc)); - return -1; - } - } while (len > 0); - return 0; -} - -int -smtp_send2(struct smtp_io_data *dat, char *command, char *arg) -{ - int rc; - - obstack_grow(&dat->stk, command, strlen(command)); - if (arg) - obstack_grow(&dat->stk, arg, strlen(arg)); - obstack_1grow(&dat->stk, 0); - dat->command = obstack_finish(&dat->stk); - - rc = smtp_send(dat, dat->command); - if (rc == 0) - rc = smtp_send(dat, "\r\n"); - return rc; -} - -int -smtp_send3(struct smtp_io_data *dat, char *command, char *arg1, char *arg2) -{ - int rc; - - obstack_grow(&dat->stk, command, strlen(command)); - obstack_grow(&dat->stk, arg1, strlen(arg1)); - obstack_grow(&dat->stk, arg2, strlen(arg2)); - obstack_1grow(&dat->stk, 0); - dat->command = obstack_finish(&dat->stk); - - rc = smtp_send(dat, dat->command); - if (rc == 0) - rc = smtp_send(dat, "\r\n"); - - return rc; -} - -int -smtp_recvline(struct smtp_io_data *dat) -{ - size_t attempt = 0; - for (;;) { - char *p; - - if (dat->level == 0) { - int rc = stream_read(dat->stream, - dat->buf, sizeof dat->buf, - dat->recv_off, &dat->level); - if (rc == 0) { - if (dat->level == 0) { - mu_error("stream_read: read 0 bytes"); - return -1; - } - dat->recv_off += dat->level; - } else if (rc == EAGAIN) { - if (attempt > io_attempts) { - mu_error("stream_read timed out"); - return -1; - } - smtp_wait(dat, MU_STREAM_READY_RD); - continue; - } else { - mu_error ("stream_read: %s", mu_strerror (rc)); - return -1; - } - } - attempt = 0; - - p = memchr(dat->buf, '\n', dat->level); - if (!p) { - obstack_grow(&dat->stk, dat->buf, dat->level); - dat->level = 0; - continue; - } else { - size_t len = p - dat->buf + 1; - obstack_grow(&dat->stk, dat->buf, len); - obstack_1grow(&dat->stk, 0); - dat->reply = obstack_finish(&dat->stk); - dat->level -= len; - memmove(dat->buf, dat->buf + len, dat->level); - break; - } - } - return 0; -} - -int -smtp_recv(struct smtp_io_data *dat) -{ - char *p; - dat->start = NULL; - do { - int code; - int rc = smtp_recvline(dat); - if (rc) - return -1; - transcript("RECV:", dat->reply); - code = strtoul (dat->reply, &p, 0); - if (p - dat->reply != 3 || (*p != '-' && *p != ' ')) { - mu_error("Unexpected reply from server: %s", - dat->reply); - return -1; - } else if (!dat->start) { - dat->start = dat->reply; - dat->code = code; - } else if (dat->code != code) { - mu_error("Unexpected reply code from server: %d", - code); - return -1; - } - } while (*p == '-'); - obstack_1grow (&dat->stk, 0); - obstack_finish (&dat->stk); - return 0; -} - - -/* Milter-specific functions */ - -void -log_status(sfsistat status, SMFICTX *ctx, struct smtp_io_data *io) -{ - if (debug_level >= 1) { - char *id = smfi_getsymval(ctx, "i"); - const char *str = sfsistat_str(status); - if (status != SMFIS_ACCEPT && io) { - if (str) - logmsg(LOG_INFO, - "%s: %s, command=%s, reply=%s", - id ? id : "(nil)", str, - io->command, io->reply); - else - logmsg(LOG_INFO, - "%s: status %d, command=%s, reply=%s", - id ? id : "(nil)", status, - io->command, io->reply); - } else { - if (str) - logmsg(LOG_INFO, - "%s: %s", id ? id : "(nil)", str); - else - logmsg(LOG_INFO, - "%s: status %d", - id ? id : "(nil)", status); - } - } -} - -sfsistat -run_action(SMFICTX *ctx, getmx_status rc) -{ - sfsistat status; - - switch (rc) { - case getmx_temp_failure: - status = action_temp_failure(ctx, &action_temp_failure_data); - break; - - case getmx_failure: - status = action_failure(ctx, &action_failure_data); - break; - - case getmx_not_found: - status = action_bad_sender(ctx, &action_bad_sender_data); - break; - - case getmx_success: - status = action_success(ctx, &action_success_data); - } - log_status(status, ctx, NULL); - return status; -} - -/* Verify whether EMAIL address is served by host CLIENT_ADDR. */ -getmx_status -check_on_host(SMFICTX *ctx, char *email, char *client_addr) -{ - int rc; - stream_t stream; - struct smtp_io_data io; - getmx_status status = getmx_success; - int count = 0; - - debug(10, ("email = %s, client_addr = %s", email, client_addr)); - rc = tcp_stream_create (&stream, client_addr, 25, MU_STREAM_NONBLOCK); - if (rc) { - mu_error ("tcp_stream_create: %s", mu_strerror (rc)); - return getmx_temp_failure; - } - - while (rc = stream_open(stream)) { - if ((rc == EAGAIN || rc == EINPROGRESS) - && count <= io_attempts) { - count++; - smtp_stream_wait(stream, MU_STREAM_READY_WR); - continue; - } - mu_error("stream_open: %s, %d", mu_strerror(rc), count); - stream_destroy(&stream, stream_get_owner(stream)); - if (rc == EAGAIN || rc == EINPROGRESS) - return getmx_temp_failure; - else - return getmx_failure; - } - debug(100,("stream opened")); - - smtp_io_data_init(&io, ctx, stream); - - do { - char *buf; - char *descr; - if (smtp_recv(&io) || io. |