[aadk-commits] qwell: uClinux/trunk r249 - in
/uClinux/trunk/uClinux-dist: config/ user/ use...
aadk-commits at lists.digium.com
aadk-commits at lists.digium.com
Fri Mar 16 16:30:29 MST 2007
Author: qwell
Date: Fri Mar 16 18:30:29 2007
New Revision: 249
URL: http://svn.digium.com/view/aadk?view=rev&rev=249
Log:
Remove smtp-client from default build.
Add ssmtp sources and add to default build.
Added:
uClinux/trunk/uClinux-dist/user/ssmtp/
uClinux/trunk/uClinux-dist/user/ssmtp/Makefile (with props)
uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c (with props)
uClinux/trunk/uClinux-dist/user/ssmtp/base64.c (with props)
uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c (with props)
uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.conf (with props)
uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.h (with props)
Modified:
uClinux/trunk/uClinux-dist/config/.config
uClinux/trunk/uClinux-dist/config/Configure.help
uClinux/trunk/uClinux-dist/config/config.in
uClinux/trunk/uClinux-dist/user/Makefile
uClinux/trunk/uClinux-dist/vendors/Digium/S800I/Makefile
uClinux/trunk/uClinux-dist/vendors/Digium/S800I/config.linux-2.6.x
uClinux/trunk/uClinux-dist/vendors/Digium/S800I/config.vendor-2.6.x
uClinux/trunk/uClinux-dist/vendors/Digium/S800I/scripts/save_config
Modified: uClinux/trunk/uClinux-dist/config/.config
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/config/.config?view=diff&rev=249&r1=248&r2=249
==============================================================================
--- uClinux/trunk/uClinux-dist/config/.config (original)
+++ uClinux/trunk/uClinux-dist/config/.config Fri Mar 16 18:30:29 2007
@@ -201,7 +201,7 @@
# CONFIG_USER_LINUXIGD_LINUXIGD is not set
# CONFIG_USER_LOATTACH_LOATTACH is not set
# CONFIG_USER_LRPSTAT_LRPSTAT is not set
-CONFIG_USER_SMTP_SMTPCLIENT=y
+# CONFIG_USER_SMTP_SMTPCLIENT is not set
# CONFIG_USER_MAIL_MAIL_IP is not set
# CONFIG_USER_MINI_HTTPD_MINI_HTTPD is not set
# CONFIG_USER_MSNTP_MSNTP is not set
@@ -238,6 +238,7 @@
# CONFIG_USER_SPEEDTOUCH_MODEM_RUN is not set
# CONFIG_USER_STUNNEL_STUNNEL is not set
# CONFIG_USER_SSLWRAP_SSLWRAP is not set
+CONFIG_USER_SMTP_SSMTP=y
# CONFIG_USER_SQUID_SQUID is not set
# CONFIG_USER_SSH_SSH is not set
# CONFIG_USER_SSH_SSHD is not set
Modified: uClinux/trunk/uClinux-dist/config/Configure.help
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/config/Configure.help?view=diff&rev=249&r1=248&r2=249
==============================================================================
--- uClinux/trunk/uClinux-dist/config/Configure.help (original)
+++ uClinux/trunk/uClinux-dist/config/Configure.help Fri Mar 16 18:30:29 2007
@@ -1452,6 +1452,9 @@
CONFIG_USER_SMTP_SMTPCLIENT
Client which allows mail to be sent to other hosts that support SMTP
+CONFIG_USER_SMTP_SSMTP
+ Sendmail compatible client which allows mail to be sent to other hosts that support SMTP
+
CONFIG_USER_SNMPD_SNMPD
SNMP daemon
Approx. binary size: 20k with no modules
Modified: uClinux/trunk/uClinux-dist/config/config.in
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/config/config.in?view=diff&rev=249&r1=248&r2=249
==============================================================================
--- uClinux/trunk/uClinux-dist/config/config.in (original)
+++ uClinux/trunk/uClinux-dist/config/config.in Fri Mar 16 18:30:29 2007
@@ -553,6 +553,7 @@
bool 'speedtouch modem_run' CONFIG_USER_SPEEDTOUCH_MODEM_RUN
bool 'stunnel' CONFIG_USER_STUNNEL_STUNNEL
bool 'sslwrap' CONFIG_USER_SSLWRAP_SSLWRAP
+bool 'ssmtp' CONFIG_USER_SMTP_SSMTP
bool 'squid' CONFIG_USER_SQUID_SQUID
bool 'ssh' CONFIG_USER_SSH_SSH
Modified: uClinux/trunk/uClinux-dist/user/Makefile
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/Makefile?view=diff&rev=249&r1=248&r2=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/Makefile (original)
+++ uClinux/trunk/uClinux-dist/user/Makefile Fri Mar 16 18:30:29 2007
@@ -308,6 +308,7 @@
dir_$(CONFIG_USER_SNMPD_SNMPD) += snmpd
dir_$(CONFIG_USER_SNORT_SNORT) += snort
dir_$(CONFIG_USER_SPEEDTOUCH_MODEM_RUN) += speedtouch/src
+dir_$(CONFIG_USER_SMTP_SSMTP) += ssmtp
dir_$(CONFIG_USER_STUNNEL_STUNNEL) += stunnel
dir_$(CONFIG_USER_SSLWRAP_SSLWRAP) += sslwrap
dir_$(CONFIG_USER_SQUID_SQUID) += squid
Added: uClinux/trunk/uClinux-dist/user/ssmtp/Makefile
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/ssmtp/Makefile?view=auto&rev=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/ssmtp/Makefile (added)
+++ uClinux/trunk/uClinux-dist/user/ssmtp/Makefile Fri Mar 16 18:30:29 2007
@@ -1,0 +1,55 @@
+# Generated automatically from Makefile.in by configure.
+
+
+srcdir= .
+prefix=/
+exec_prefix=${prefix}
+libexecdir=${exec_prefix}/libexec
+bindir=$(prefix)/sbin
+mandir=$(prefix)/man/man8
+
+LN_S=ln -s
+
+etcdir=${prefix}/etc
+SSMTPCONFDIR=$(etcdir)/ssmtp
+# (End of relocation section)
+
+# Configuration files
+CONFIGURATION_FILE=$(SSMTPCONFDIR)/ssmtp.conf
+REVALIASES_FILE=$(SSMTPCONFDIR)/revaliases
+
+INSTALLED_CONFIGURATION_FILE=$(CONFIGURATION_FILE)
+INSTALLED_REVALIASES_FILE=$(REVALIASES_FILE)
+
+# Programs
+GEN_CONFIG=$(srcdir)/generate_config
+
+SRCS=ssmtp.c arpadate.c base64.c
+
+OBJS=$(SRCS:.c=.o)
+
+INSTALL=/usr/bin/install -c
+
+EXTRADEFS=\
+-DSSMTPCONFDIR=\"$(SSMTPCONFDIR)\" \
+-DCONFIGURATION_FILE=\"$(CONFIGURATION_FILE)\" \
+-DREVALIASES_FILE=\"$(REVALIASES_FILE)\" \
+
+
+CFLAGS+=-Wall -DLOGFILE -DSTDC_HEADERS=1 -DHAVE_LIMITS_H=1 -DHAVE_STRINGS_H=1 -DHAVE_UNISTD_H=1 -DHAVE_LIBNSL=1 -DRETSIGTYPE=void -DHAVE_VPRINTF=1 -DHAVE_GETHOSTNAME=1 -DHAVE_SOCKET=1 -DHAVE_STRDUP=1 -DHAVE_STRSTR=1 -DREWRITE_DOMAIN=1 $(EXTRADEFS) -g -O2
+
+.PHONY: all
+all: ssmtp
+
+# Binaries:
+ssmtp: $(OBJS)
+ $(CC) $(LDFLAGS) -o ssmtp $(OBJS) -lnsl
+
+romfs:
+ $(ROMFSINST) /bin/ssmtp
+ $(ROMFSINST) /etc/ssmtp/ssmtp.conf
+
+.PHONY: clean
+clean:
+ $(RM) ssmtp *.o md5auth/*.o core
+
Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/Makefile
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/Makefile
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c?view=auto&rev=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c (added)
+++ uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c Fri Mar 16 18:30:29 2007
@@ -1,0 +1,89 @@
+/*
+ * arpadate.c - get_arpadate() is a function returning the date in the
+ * ARPANET format (see RFC822 and RFC1123)
+ * Copyright (C) 1998 Hugo Haas
+ *
+ * Inspired by smail source code by Ronald S. Karr and Landon Curt Noll
+ *
+ * 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define ARPADATE_LENGTH 32
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+void
+get_arpadate (char *d_string)
+{
+ struct tm *date;
+#ifdef USE_OLD_ARPADATE
+ static char *week_day[] =
+ {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+ static char *month[] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+ "Aug", "Sep", "Oct", "Nov", "Dec"};
+ static char timezone[3];
+
+ time_t current;
+ int offset, gmt_yday, gmt_hour, gmt_min;
+
+ /* Get current time */
+ (void) time (¤t);
+
+ /* Get GMT and then local dates */
+ date = gmtime ((const time_t *) ¤t);
+ gmt_yday = date->tm_yday;
+ gmt_hour = date->tm_hour;
+ gmt_min = date->tm_min;
+ date = localtime ((const time_t *) ¤t);
+
+ /* Calculates offset */
+
+ offset = (date->tm_hour - gmt_hour) * 60 + (date->tm_min - gmt_min);
+ /* Be careful, there can be problems if the day has changed between the
+ evaluation of local and gmt's one */
+ if (date->tm_yday != gmt_yday)
+ {
+ if (date->tm_yday == (gmt_yday + 1))
+ offset += 1440;
+ else if (date->tm_yday == (gmt_yday - 1))
+ offset -= 1440;
+ else
+ offset += (date->tm_yday > gmt_yday) ? -1440 : 1440;
+ }
+
+ if (offset >= 0)
+ sprintf (timezone, "+%02d%02d", offset / 60, offset % 60);
+ else
+ sprintf (timezone, "-%02d%02d", -offset / 60, -offset % 60);
+
+ sprintf (d_string, "%s, %d %s %04d %02d:%02d:%02d %s",
+ week_day[date->tm_wday],
+ date->tm_mday, month[date->tm_mon], date->tm_year + 1900,
+ date->tm_hour, date->tm_min, date->tm_sec, timezone);
+#else
+ time_t now;
+
+ /* RFC822 format string borrowed from GNU shellutils date.c */
+ const char *format = "%a, %d %b %Y %H:%M:%S %z";
+
+ now = time(NULL);
+
+ date = localtime((const time_t *)&now);
+ (void)strftime(d_string, ARPADATE_LENGTH, format, date);
+#endif
+}
Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: uClinux/trunk/uClinux-dist/user/ssmtp/base64.c
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/ssmtp/base64.c?view=auto&rev=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/ssmtp/base64.c (added)
+++ uClinux/trunk/uClinux-dist/user/ssmtp/base64.c Fri Mar 16 18:30:29 2007
@@ -1,0 +1,103 @@
+/*
+ * base64.c -- base-64 conversion routines.
+ *
+ * For license terms, see the file COPYING in this directory.
+ *
+ * This base 64 encoding is defined in RFC2045 section 6.8,
+ * "Base64 Content-Transfer-Encoding", but lines must not be broken in the
+ * scheme used here.
+ */
+
+/*
+ * This code borrowed from fetchmail sources by
+ * Eric S. Raymond <esr at snark.thyrsus.com>.
+ */
+#include <ctype.h>
+
+
+static const char base64digits[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define BAD -1
+static const char base64val[] = {
+ BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+ BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+ BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,BAD,BAD, BAD,BAD,BAD,BAD,
+ BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,BAD, BAD,BAD,BAD,BAD,
+ BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,BAD, BAD,BAD,BAD,BAD
+};
+#define DECODE64(c) (isascii(c) ? base64val[c] : BAD)
+
+void to64frombits(unsigned char *out, const unsigned char *in, int inlen)
+/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
+{
+ for (; inlen >= 3; inlen -= 3)
+ {
+ *out++ = base64digits[in[0] >> 2];
+ *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+ *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+ *out++ = base64digits[in[2] & 0x3f];
+ in += 3;
+ }
+ if (inlen > 0)
+ {
+ unsigned char fragment;
+
+ *out++ = base64digits[in[0] >> 2];
+ fragment = (in[0] << 4) & 0x30;
+ if (inlen > 1)
+ fragment |= in[1] >> 4;
+ *out++ = base64digits[fragment];
+ *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
+ *out++ = '=';
+ }
+ *out = '\0';
+}
+
+int from64tobits(char *out, const char *in)
+/* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
+{
+ int len = 0;
+ register unsigned char digit1, digit2, digit3, digit4;
+
+ if (in[0] == '+' && in[1] == ' ')
+ in += 2;
+ if (*in == '\r')
+ return(0);
+
+ do {
+ digit1 = in[0];
+ if (DECODE64(digit1) == BAD)
+ return(-1);
+ digit2 = in[1];
+ if (DECODE64(digit2) == BAD)
+ return(-1);
+ digit3 = in[2];
+ if (digit3 != '=' && DECODE64(digit3) == BAD)
+ return(-1);
+ digit4 = in[3];
+ if (digit4 != '=' && DECODE64(digit4) == BAD)
+ return(-1);
+ in += 4;
+ *out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4);
+ ++len;
+ if (digit3 != '=')
+ {
+ *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2);
+ ++len;
+ if (digit4 != '=')
+ {
+ *out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4);
+ ++len;
+ }
+ }
+ } while
+ (*in && *in != '\r' && digit4 != '=');
+
+ return (len);
+}
+
+/* base64.c ends here */
Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/base64.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/base64.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c?view=auto&rev=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c (added)
+++ uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c Fri Mar 16 18:30:29 2007
@@ -1,0 +1,1876 @@
+/*
+
+ $Id: ssmtp.c,v 2.60 2003/08/17 14:17:57 matt Exp $
+
+ sSMTP -- send messages via SMTP to a mailhub for local delivery or forwarding.
+ This program is used in place of /usr/sbin/sendmail, called by "mail" (et all).
+ sSMTP does a selected subset of sendmail's standard tasks (including exactly
+ one rewriting task), and explains if you ask it to do something it can't. It
+ then sends the mail to the mailhub via an SMTP connection. Believe it or not,
+ this is nothing but a filter
+
+ See COPYRIGHT for the license
+
+*/
+#define VERSION "2.60.4"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <string.h>
+#include <ctype.h>
+#include <netdb.h>
+#ifdef HAVE_SSL
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#endif
+#ifdef MD5AUTH
+#include "md5auth/hmac_md5.h"
+#endif
+#include "ssmtp.h"
+
+
+bool_t have_date = False;
+bool_t have_from = False;
+#ifdef HASTO_OPTION
+bool_t have_to = False;
+#endif
+bool_t minus_t = False;
+bool_t minus_v = False;
+bool_t override_from = False;
+bool_t rewrite_domain = False;
+bool_t use_tls = False; /* Use SSL to transfer mail to HUB */
+bool_t use_starttls = False; /* SSL only after STARTTLS (RFC2487) */
+bool_t use_cert = False; /* Use a certificate to transfer SSL mail */
+
+#define ARPADATE_LENGTH 32 /* Current date in RFC format */
+char arpadate[ARPADATE_LENGTH];
+char *auth_user = (char)NULL;
+char *auth_pass = (char)NULL;
+char *auth_method = (char)NULL; /* Mechanism for SMTP authentication */
+char *mail_domain = (char)NULL;
+char *from = (char)NULL; /* Use this as the From: address */
+char hostname[MAXHOSTNAMELEN] = "localhost";
+char *mailhost = "mailhub";
+char *minus_f = (char)NULL;
+char *minus_F = (char)NULL;
+char *gecos;
+char *prog = (char)NULL;
+char *root = NULL;
+char *tls_cert = "/etc/ssl/certs/ssmtp.pem"; /* Default Certificate */
+char *uad = (char)NULL;
+
+headers_t headers, *ht;
+
+#ifdef DEBUG
+int log_level = 1;
+#else
+int log_level = 0;
+#endif
+int port = 25;
+#ifdef INET6
+int p_family = PF_UNSPEC; /* Protocol family used in SMTP connection */
+#endif
+
+jmp_buf TimeoutJmpBuf; /* Timeout waiting for input from network */
+
+rcpt_t rcpt_list, *rt;
+
+#ifdef HAVE_SSL
+SSL *ssl;
+#endif
+
+#ifdef MD5AUTH
+static char hextab[]="0123456789abcdef";
+#endif
+
+
+/*
+log_event() -- Write event to syslog (or log file if defined)
+*/
+void log_event(int priority, char *format, ...)
+{
+ char buf[(BUF_SZ + 1)];
+ va_list ap;
+
+ va_start(ap, format);
+ (void)vsnprintf(buf, BUF_SZ, format, ap);
+ va_end(ap);
+
+#ifdef LOGFILE
+ FILE *fp;
+
+ if((fp = fopen("/tmp/ssmtp.log", "a")) != (FILE *)NULL) {
+ (void)fprintf(fp, "%s\n", buf);
+ (void)fclose(fp);
+ }
+ else {
+ (void)fprintf(stderr, "Can't write to /tmp/ssmtp.log\n");
+ }
+#endif
+
+#if HAVE_SYSLOG_H
+#if OLDSYSLOG
+ openlog("sSMTP", LOG_PID);
+#else
+ openlog("sSMTP", LOG_PID, LOG_MAIL);
+#endif
+ syslog(priority, "%s", buf);
+ closelog();
+#endif
+}
+
+void smtp_write(int fd, char *format, ...);
+int smtp_read(int fd, char *response);
+int smtp_read_all(int fd, char *response);
+int smtp_okay(int fd, char *response);
+
+/*
+dead_letter() -- Save stdin to ~/dead.letter if possible
+*/
+void dead_letter(void)
+{
+ char path[(MAXPATHLEN + 1)], buf[(BUF_SZ + 1)];
+ struct passwd *pw;
+ uid_t uid;
+ FILE *fp;
+
+ uid = getuid();
+ pw = getpwuid(uid);
+
+ if(isatty(fileno(stdin))) {
+ if(log_level > 0) {
+ log_event(LOG_ERR,
+ "stdin is a TTY - not saving to %s/dead.letter, pw->pw_dir");
+ }
+ return;
+ }
+
+ if(pw == (struct passwd *)NULL) {
+ /* Far to early to save things */
+ if(log_level > 0) {
+ log_event(LOG_ERR, "No sender failing horribly!");
+ }
+ return;
+ }
+
+ if(snprintf(path, BUF_SZ, "%s/dead.letter", pw->pw_dir) == -1) {
+ /* Can't use die() here since dead_letter() is called from die() */
+ exit(1);
+ }
+
+ if((fp = fopen(path, "a")) == (FILE *)NULL) {
+ /* Perhaps the person doesn't have a homedir... */
+ if(log_level > 0) {
+ log_event(LOG_ERR, "Can't open %s failing horribly!", path);
+ }
+ return;
+ }
+
+ /* We start on a new line with a blank line separating messages */
+ (void)fprintf(fp, "\n\n");
+
+ while(fgets(buf, sizeof(buf), stdin)) {
+ (void)fputs(buf, fp);
+ }
+
+ if(fclose(fp) == -1) {
+ if(log_level > 0) {
+ log_event(LOG_ERR,
+ "Can't close %s/dead.letter, possibly truncated", pw->pw_dir);
+ }
+ }
+}
+
+/*
+die() -- Write error message, dead.letter and exit
+*/
+void die(char *format, ...)
+{
+ char buf[(BUF_SZ + 1)];
+ va_list ap;
+
+ va_start(ap, format);
+ (void)vsnprintf(buf, BUF_SZ, format, ap);
+ va_end(ap);
+
+ (void)fprintf(stderr, "%s: %s\n", prog, buf);
+ log_event(LOG_ERR, "%s", buf);
+
+ /* Send message to dead.letter */
+ (void)dead_letter();
+
+ exit(1);
+}
+
+/*
+basename() -- Return last element of path
+*/
+char *basename(char *str)
+{
+ char buf[MAXPATHLEN +1], *p;
+
+ if((p = strrchr(str, '/'))) {
+ if(strncpy(buf, ++p, MAXPATHLEN) == (char *)NULL) {
+ die("basename() -- strncpy() failed");
+ }
+ }
+ else {
+ if(strncpy(buf, str, MAXPATHLEN) == (char *)NULL) {
+ die("basename() -- strncpy() failed");
+ }
+ }
+ buf[MAXPATHLEN] = (char)NULL;
+
+ return(strdup(buf));
+}
+
+/*
+strip_pre_ws() -- Return pointer to first non-whitespace character
+*/
+char *strip_pre_ws(char *str)
+{
+ char *p;
+
+ p = str;
+ while(*p && isspace(*p)) p++;
+
+ return(p);
+}
+
+/*
+strip_post_ws() -- Return pointer to last non-whitespace character
+*/
+char *strip_post_ws(char *str)
+{
+ char *p;
+
+ p = (str + strlen(str));
+ while(isspace(*--p)) {
+ *p = (char)NULL;
+ }
+
+ return(p);
+}
+
+/*
+addr_parse() -- Parse <user at domain.com> from full email address
+*/
+char *addr_parse(char *str)
+{
+ char *p, *q;
+
+#if 0
+ (void)fprintf(stderr, "*** addr_parse(): str = [%s]\n", str);
+#endif
+
+ /* Simple case with email address enclosed in <> */
+ if((p = strdup(str)) == (char *)NULL) {
+ die("addr_parse(): strdup()");
+ }
+
+ if((q = strchr(p, '<'))) {
+ q++;
+
+ if((p = strchr(q, '>'))) {
+ *p = (char)NULL;
+ }
+
+#if 0
+ (void)fprintf(stderr, "*** addr_parse(): q = [%s]\n", q);
+#endif
+
+ return(q);
+ }
+
+ q = strip_pre_ws(p);
+ if(*q == '(') {
+ while((*q++ != ')'));
+ }
+ p = strip_pre_ws(q);
+
+#if 0
+ (void)fprintf(stderr, "*** addr_parse(): p = [%s]\n", p);
+#endif
+
+ q = strip_post_ws(p);
+ if(*q == ')') {
+ while((*--q != '('));
+ *q = (char)NULL;
+ }
+ (void)strip_post_ws(p);
+
+#if 0
+ (void)fprintf(stderr, "*** addr_parse(): p = [%s]\n", p);
+#endif
+
+ return(p);
+}
+
+/*
+append_domain() -- Fix up address with @domain.com
+*/
+char *append_domain(char *str)
+{
+ char buf[(BUF_SZ + 1)];
+
+ if(strchr(str, '@') == (char *)NULL) {
+ if(snprintf(buf, BUF_SZ, "%s@%s", str,
+#ifdef REWRITE_DOMAIN
+ rewrite_domain == True ? mail_domain : hostname
+#else
+ hostname
+#endif
+ ) == -1) {
+ die("append_domain() -- snprintf() failed");
+ }
+ return(strdup(buf));
+ }
+
+ return(strdup(str));
+}
+
+/*
+standardise() -- Trim off '\n's and double leading dots
+*/
+void standardise(char *str)
+{
+ size_t sl;
+ char *p;
+
+ if((p = strchr(str, '\n'))) {
+ *p = (char)NULL;
+ }
+
+ /* Any line beginning with a dot has an additional dot inserted;
+ not just a line consisting solely of a dot. Thus we have to slide
+ the buffer down one */
+ sl = strlen(str);
+
+ if(*str == '.') {
+ if((sl + 2) > BUF_SZ) {
+ die("standardise() -- Buffer overflow");
+ }
+ (void)memmove((str + 1), str, (sl + 1)); /* Copy trailing \0 */
+
+ *str = '.';
+ }
+}
+
+/*
+revaliases() -- Parse the reverse alias file
+ Fix globals to use any entry for sender
+*/
+void revaliases(struct passwd *pw)
+{
+ char buf[(BUF_SZ + 1)], *p;
+ FILE *fp;
+
+ /* Try to open the reverse aliases file */
+ if((fp = fopen(REVALIASES_FILE, "r"))) {
+ /* Search if a reverse alias is defined for the sender */
+ while(fgets(buf, sizeof(buf), fp)) {
+ /* Make comments invisible */
+ if((p = strchr(buf, '#'))) {
+ *p = (char)NULL;
+ }
+
+ /* Ignore malformed lines and comments */
+ if(strchr(buf, ':') == (char *)NULL) {
+ continue;
+ }
+
+ /* Parse the alias */
+ if(((p = strtok(buf, ":"))) && !strcmp(p, pw->pw_name)) {
+ if((p = strtok(NULL, ": \t\r\n"))) {
+ if((uad = strdup(p)) == (char *)NULL) {
+ die("revaliases() -- strdup() failed");
+ }
+ }
+
+ if((p = strtok(NULL, " \t\r\n:"))) {
+ if((mailhost = strdup(p)) == (char *)NULL) {
+ die("revaliases() -- strdup() failed");
+ }
+
+ if((p = strtok(NULL, " \t\r\n:"))) {
+ port = atoi(p);
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO, "Set MailHub=\"%s\"\n", mailhost);
+ log_event(LOG_INFO,
+ "via SMTP Port Number=\"%d\"\n", port);
+ }
+ }
+ }
+ }
+
+ fclose(fp);
+ }
+}
+
+/*
+from_strip() -- Transforms "Name <login at host>" into "login at host" or "login at host (Real name)"
+*/
+char *from_strip(char *str)
+{
+ char *p;
+
+#if 0
+ (void)fprintf(stderr, "*** from_strip(): str = [%s]\n", str);
+#endif
+
+ if(strncmp("From:", str, 5) == 0) {
+ str += 5;
+ }
+
+ /* Remove the real name if necessary - just send the address */
+ if((p = addr_parse(str)) == (char *)NULL) {
+ die("from_strip() -- addr_parse() failed");
+ }
+#if 0
+ (void)fprintf(stderr, "*** from_strip(): p = [%s]\n", p);
+#endif
+
+ return(strdup(p));
+}
+
+/*
+from_format() -- Generate standard From: line
+*/
+char *from_format(char *str, bool_t override_from)
+{
+ char buf[(BUF_SZ + 1)];
+
+ if(override_from) {
+ if(minus_f) {
+ str = append_domain(minus_f);
+ }
+
+ if(minus_F) {
+ if(snprintf(buf,
+ BUF_SZ, "\"%s\" <%s>", minus_F, str) == -1) {
+ die("from_format() -- snprintf() failed");
+ }
+ }
+ else if(gecos) {
+ if(snprintf(buf, BUF_SZ, "\"%s\" <%s>", gecos, str) == -1) {
+ die("from_format() -- snprintf() failed");
+ }
+ }
+ else {
+ if(snprintf(buf, BUF_SZ, "%s", str) == -1) {
+ die("from_format() -- snprintf() failed");
+ }
+ }
+ }
+ else {
+ if(gecos) {
+ if(snprintf(buf, BUF_SZ, "\"%s\" <%s>", gecos, str) == -1) {
+ die("from_format() -- snprintf() failed");
+ }
+ }
+ }
+
+#if 0
+ (void)fprintf(stderr, "*** from_format(): buf = [%s]\n", buf);
+#endif
+
+ return(strdup(buf));
+}
+
+/*
+rcpt_save() -- Store entry into RCPT list
+*/
+void rcpt_save(char *str)
+{
+ char *p;
+
+# if 1
+ /* Horrible botch for group stuff */
+ p = str;
+ while(*p) p++;
+
+ if(*--p == ';') {
+ return;
+ }
+#endif
+
+#if 0
+ (void)fprintf(stderr, "*** rcpt_save(): str = [%s]\n", str);
+#endif
+
+ /* Ignore missing usernames */
+ if(*str == (char)NULL) {
+ return;
+ }
+
+ if((rt->string = strdup(str)) == (char *)NULL) {
+ die("rcpt_save() -- strdup() failed");
+ }
+
+ rt->next = (rcpt_t *)malloc(sizeof(rcpt_t));
+ if(rt->next == (rcpt_t *)NULL) {
+ die("rcpt_save() -- malloc() failed");
+ }
+ rt = rt->next;
+
+ rt->next = (rcpt_t *)NULL;
+}
+
+/*
+rcpt_parse() -- Break To|Cc|Bcc into individual addresses
+*/
+void rcpt_parse(char *str)
+{
+ bool_t in_quotes = False, got_addr = False;
+ char *p, *q, *r;
+
+#if 0
+ (void)fprintf(stderr, "*** rcpt_parse(): str = [%s]\n", str);
+#endif
+
+ if((p = strdup(str)) == (char *)NULL) {
+ die("rcpt_parse(): strdup() failed");
+ }
+ q = p;
+
+ /* Replace <CR>, <LF> and <TAB> */
+ while(*q) {
+ switch(*q) {
+ case '\t':
+ case '\n':
+ case '\r':
+ *q = ' ';
+ }
+ q++;
+ }
+ q = p;
+
+#if 0
+ (void)fprintf(stderr, "*** rcpt_parse(): q = [%s]\n", q);
+#endif
+
+ r = q;
+ while(*q) {
+ if(*q == '"') {
+ in_quotes = (in_quotes ? False : True);
+ }
+
+ /* End of string? */
+ if(*(q + 1) == (char)NULL) {
+ got_addr = True;
+ }
+
+ /* End of address? */
+ if((*q == ',') && (in_quotes == False)) {
+ got_addr = True;
+
+ *q = (char)NULL;
+ }
+
+ if(got_addr) {
+ while(*r && isspace(*r)) r++;
+
+ rcpt_save(addr_parse(r));
+ r = (q + 1);
+#if 0
+ (void)fprintf(stderr, "*** rcpt_parse(): r = [%s]\n", r);
+#endif
+ got_addr = False;
+ }
+ q++;
+ }
+ free(p);
+}
+
+#ifdef MD5AUTH
+int crammd5(char *challengeb64, char *username, char *password, char *responseb64)
+{
+ int i;
+ unsigned char digest[MD5_DIGEST_LEN];
+ unsigned char digascii[MD5_DIGEST_LEN * 2];
+ unsigned char challenge[(BUF_SZ + 1)];
+ unsigned char response[(BUF_SZ + 1)];
+ unsigned char secret[(MD5_BLOCK_LEN + 1)];
+
+ memset (secret,0,sizeof(secret));
+ memset (challenge,0,sizeof(challenge));
+ strncpy (secret, password, sizeof(secret));
+ if (!challengeb64 || strlen(challengeb64) > sizeof(challenge) * 3 / 4)
+ return 0;
+ from64tobits(challenge, challengeb64);
+
+ hmac_md5(challenge, strlen(challenge), secret, strlen(secret), digest);
+
+ for (i = 0; i < MD5_DIGEST_LEN; i++) {
+ digascii[2 * i] = hextab[digest[i] >> 4];
+ digascii[2 * i + 1] = hextab[(digest[i] & 0x0F)];
+ }
+ digascii[MD5_DIGEST_LEN * 2] = '\0';
+
+ if (sizeof(response) <= strlen(username) + sizeof(digascii))
+ return 0;
+
+ strncpy (response, username, sizeof(response) - sizeof(digascii) - 2);
+ strcat (response, " ");
+ strcat (response, digascii);
+ to64frombits(responseb64, response, strlen(response));
+
+ return 1;
+}
+#endif
+
+/*
+rcpt_remap() -- Alias systems-level users to the person who
+ reads their mail. This is variously the owner of a workstation,
+ the sysadmin of a group of stations and the postmaster otherwise.
+ We don't just mail stuff off to root on the mailhub :-)
+*/
+char *rcpt_remap(char *str)
+{
+ struct passwd *pw;
+ if((root==NULL) || strlen(root)==0 || strchr(str, '@') ||
+ ((pw = getpwnam(str)) == NULL) || (pw->pw_uid > MAXSYSUID)) {
+ return(append_domain(str)); /* It's not a local systems-level user */
+ }
+ else {
+ return(append_domain(root));
+ }
+}
+
+/*
+header_save() -- Store entry into header list
+*/
+void header_save(char *str)
+{
+ char *p;
+
+#if 0
+ (void)fprintf(stderr, "header_save(): str = [%s]\n", str);
+#endif
+
+ if((p = strdup(str)) == (char *)NULL) {
+ die("header_save() -- strdup() failed");
+ }
+ ht->string = p;
+
+ if(strncasecmp(ht->string, "From:", 5) == 0) {
+#if 1
+ /* Hack check for NULL From: line */
+ if(*(p + 6) == (char)NULL) {
+ return;
+ }
+#endif
+
+#ifdef REWRITE_DOMAIN
+ if(override_from == True) {
+ uad = from_strip(ht->string);
+ }
+ else {
+ return;
+ }
+#endif
+ have_from = True;
+ }
+#ifdef HASTO_OPTION
+ else if(strncasecmp(ht->string, "To:" ,3) == 0) {
+ have_to = True;
+ }
+#endif
+ else if(strncasecmp(ht->string, "Date:", 5) == 0) {
+ have_date = True;
+ }
+
+ if(minus_t) {
+ /* Need to figure out recipients from the e-mail */
+ if(strncasecmp(ht->string, "To:", 3) == 0) {
+ p = (ht->string + 3);
+ rcpt_parse(p);
+ }
+ else if(strncasecmp(ht->string, "Bcc:", 4) == 0) {
+ p = (ht->string + 4);
+ rcpt_parse(p);
+ }
+ else if(strncasecmp(ht->string, "CC:", 3) == 0) {
+ p = (ht->string + 3);
+ rcpt_parse(p);
+ }
+ }
+
+#if 0
+ (void)fprintf(stderr, "header_save(): ht->string = [%s]\n", ht->string);
+#endif
+
+ ht->next = (headers_t *)malloc(sizeof(headers_t));
+ if(ht->next == (headers_t *)NULL) {
+ die("header_save() -- malloc() failed");
+ }
+ ht = ht->next;
+
+ ht->next = (headers_t *)NULL;
+}
+
+/*
+header_parse() -- Break headers into seperate entries
+*/
+void header_parse(FILE *stream)
+{
+ size_t size = BUF_SZ, len = 0;
+ char *p = (char *)NULL, *q;
+ bool_t in_header = True;
+ char l = (char)NULL;
+ int c;
+
+ while(in_header && ((c = fgetc(stream)) != EOF)) {
+ /* Must have space for up to two more characters, since we
+ may need to insert a '\r' */
+ if((p == (char *)NULL) || (len >= (size - 1))) {
+ size += BUF_SZ;
+
+ p = (char *)realloc(p, (size * sizeof(char)));
+ if(p == (char *)NULL) {
+ die("header_parse() -- realloc() failed");
+ }
+ q = (p + len);
+ }
+ len++;
+
+ if(l == '\n') {
+ switch(c) {
+ case ' ':
+ case '\t':
+ /* Must insert '\r' before '\n's embedded in header
+ fields otherwise qmail won't accept our mail
+ because a bare '\n' violates some RFC */
+
+ *(q - 1) = '\r'; /* Replace previous \n with \r */
+ *q++ = '\n'; /* Insert \n */
+ len++;
+
+ break;
+
+ case '\n':
+ in_header = False;
+
+ default:
+ *q = (char)NULL;
+ if((q = strrchr(p, '\n'))) {
+ *q = (char)NULL;
+ }
+ header_save(p);
+
+ q = p;
+ len = 0;
+ }
+ }
+ *q++ = c;
+
+ l = c;
+ }
+ (void)free(p);
+}
+
+/*
+read_config() -- Open and parse config file and extract values of variables
+*/
+bool_t read_config()
+{
+ char buf[(BUF_SZ + 1)], *p, *q, *r;
+ FILE *fp;
+
+ if((fp = fopen(CONFIGURATION_FILE, "r")) == NULL) {
+ return(False);
+ }
+
+ while(fgets(buf, sizeof(buf), fp)) {
+ /* Make comments invisible */
+ if((p = strchr(buf, '#'))) {
+ *p = (char)NULL;
+ }
+
+ /* Ignore malformed lines and comments */
+ if(strchr(buf, '=') == (char *)NULL) continue;
+
+ /* Parse out keywords */
+ if(((p = strtok(buf, "= \t\n")) != (char *)NULL)
+ && ((q = strtok(NULL, "= \t\n:")) != (char *)NULL)) {
+ if(strcasecmp(p, "Root") == 0) {
+ if((root = strdup(q)) == (char *)NULL) {
+ die("parse_config() -- strdup() failed");
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO, "Set Root=\"%s\"\n", root);
+ }
+ }
+ else if(strcasecmp(p, "MailHub") == 0) {
+ if((mailhost = strdup(q)) == (char *)NULL) {
+ die("parse_config() -- strdup() failed");
+ }
+
+ if((r = strtok(NULL, "= \t\n:")) != NULL) {
+ port = atoi(r);
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO, "Set MailHub=\"%s\"\n", mailhost);
+ log_event(LOG_INFO, "Set RemotePort=\"%d\"\n", port);
+ }
+ }
+ else if(strcasecmp(p, "HostName") == 0) {
+ if(strncpy(hostname, q, MAXHOSTNAMELEN) == NULL) {
+ die("parse_config() -- strncpy() failed");
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO, "Set HostName=\"%s\"\n", hostname);
+ }
+ }
+#ifdef REWRITE_DOMAIN
+ else if(strcasecmp(p, "RewriteDomain") == 0) {
+ if((p = strrchr(q, '@'))) {
+ mail_domain = strdup(++p);
+
+ log_event(LOG_ERR,
+ "Set RewriteDomain=\"%s\" is invalid\n", q);
+ log_event(LOG_ERR,
+ "Set RewriteDomain=\"%s\" used\n", mail_domain);
+ }
+ else {
+ mail_domain = strdup(q);
+ }
+
+ if(mail_domain == (char *)NULL) {
+ die("parse_config() -- strdup() failed");
+ }
+ rewrite_domain = True;
+
+ if(log_level > 0) {
+ log_event(LOG_INFO,
+ "Set RewriteDomain=\"%s\"\n", mail_domain);
+ }
+ }
+#endif
+ else if(strcasecmp(p, "FromLineOverride") == 0) {
+ if(strcasecmp(q, "YES") == 0) {
+ override_from = True;
+ }
+ else {
+ override_from = False;
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO,
+ "Set FromLineOverride=\"%s\"\n",
+ override_from ? "True" : "False");
+ }
+ }
+ else if(strcasecmp(p, "RemotePort") == 0) {
+ port = atoi(q);
+
+ if(log_level > 0) {
+ log_event(LOG_INFO, "Set RemotePort=\"%d\"\n", port);
+ }
+ }
+#ifdef HAVE_SSL
+ else if(strcasecmp(p, "UseTLS") == 0) {
+ if(strcasecmp(q, "YES") == 0) {
+ use_tls = True;
+ }
+ else {
+ use_tls = False;
+ use_starttls = False;
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO,
+ "Set UseTLS=\"%s\"\n", use_tls ? "True" : "False");
+ }
+ }
+ else if(strcasecmp(p, "UseSTARTTLS") == 0) {
+ if(strcasecmp(q, "YES") == 0) {
+ use_starttls = True;
+ use_tls = True;
+ }
+ else {
+ use_starttls = False;
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO,
+ "Set UseSTARTTLS=\"%s\"\n", use_tls ? "True" : "False");
+ }
+ }
+ else if(strcasecmp(p, "UseTLSCert") == 0) {
+ if(strcasecmp(q, "YES") == 0) {
+ use_cert = True;
+ }
+ else {
+ use_cert = False;
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO,
+ "Set UseTLSCert=\"%s\"\n",
+ use_cert ? "True" : "False");
+ }
+ }
+ else if(strcasecmp(p, "TLSCert") == 0) {
+ if((tls_cert = strdup(q)) == (char *)NULL) {
+ die("parse_config() -- strdup() failed");
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO, "Set TLSCert=\"%s\"\n", tls_cert);
+ }
+ }
+#endif
+ /* Command-line overrides these */
+ else if(strcasecmp(p, "AuthUser") == 0 && !auth_user) {
+ if((auth_user = strdup(q)) == (char *)NULL) {
+ die("parse_config() -- strdup() failed");
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO, "Set AuthUser=\"%s\"\n", auth_user);
+ }
+ }
+ else if(strcasecmp(p, "AuthPass") == 0 && !auth_pass) {
+ if((auth_pass = strdup(q)) == (char *)NULL) {
+ die("parse_config() -- strdup() failed");
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO, "Set AuthPass=\"%s\"\n", auth_pass);
+ }
+ }
+ else if(strcasecmp(p, "AuthMethod") == 0 && !auth_method) {
+ if((auth_method = strdup(q)) == (char *)NULL) {
+ die("parse_config() -- strdup() failed");
+ }
+
+ if(log_level > 0) {
+ log_event(LOG_INFO, "Set AuthMethod=\"%s\"\n", auth_method);
+ }
+ }
+ else {
+ log_event(LOG_INFO, "Unable to set %s=\"%s\"\n", p, q);
+ }
+ }
+ }
+ (void)fclose(fp);
+
+ return(True);
+}
+
+/*
+smtp_open() -- Open connection to a remote SMTP listener
+*/
+int smtp_open(char *host, int port)
+{
+#ifdef INET6
+ struct addrinfo hints, *ai0, *ai;
+ char servname[NI_MAXSERV];
+ int s;
+#else
+ struct sockaddr_in name;
+ struct hostent *hent;
+ int s, namelen;
+#endif
+
+#ifdef HAVE_SSL
+ int err;
+ char buf[(BUF_SZ + 1)];
+
+ /* Init SSL stuff */
+ SSL_CTX *ctx;
+ SSL_METHOD *meth;
+ X509 *server_cert;
+
+ SSL_load_error_strings();
+ SSLeay_add_ssl_algorithms();
+ meth=SSLv23_client_method();
+ ctx = SSL_CTX_new(meth);
+ if(!ctx) {
+ log_event(LOG_ERR, "No SSL support initiated\n");
+ return(-1);
+ }
+
+ if(use_cert == True) {
+ if(SSL_CTX_use_certificate_chain_file(ctx, tls_cert) <= 0) {
+ perror("Use certfile");
+ return(-1);
+ }
+
+ if(SSL_CTX_use_PrivateKey_file(ctx, tls_cert, SSL_FILETYPE_PEM) <= 0) {
+ perror("Use PrivateKey");
+ return(-1);
+ }
+
+ if(!SSL_CTX_check_private_key(ctx)) {
+ log_event(LOG_ERR, "Private key does not match the certificate public key\n");
+ return(-1);
+ }
+ }
+#endif
+
+#ifdef INET6
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = p_family;
+ hints.ai_socktype = SOCK_STREAM;
+ snprintf(servname, sizeof(servname), "%d", port);
+
+ /* Check we can reach the host */
+ if (getaddrinfo(host, servname, &hints, &ai0)) {
+ log_event(LOG_ERR, "Unable to locate %s", host);
+ return(-1);
+ }
+
+ for (ai = ai0; ai; ai = ai->ai_next) {
+ /* Create a socket for the connection */
+ s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (s < 0) {
+ continue;
+ }
+
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+ s = -1;
+ continue;
+ }
+ break;
+ }
+
+ if(s < 0) {
+ log_event (LOG_ERR,
+ "Unable to connect to \"%s\" port %d.\n", host, port);
+
+ return(-1);
+ }
+#else
+ /* Check we can reach the host */
+ if((hent = gethostbyname(host)) == (struct hostent *)NULL) {
+ log_event(LOG_ERR, "Unable to locate %s", host);
+ return(-1);
+ }
+
+ if(hent->h_length > sizeof(hent->h_addr)) {
+ log_event(LOG_ERR, "Buffer overflow in gethostbyname()");
+ return(-1);
+ }
+
+ /* Create a socket for the connection */
+ if((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ log_event(LOG_ERR, "Unable to create a socket");
+ return(-1);
+ }
+
+ /* This SHOULD already be in Network Byte Order from gethostbyname() */
+ name.sin_addr.s_addr = ((struct in_addr *)(hent->h_addr))->s_addr;
+ name.sin_family = hent->h_addrtype;
+ name.sin_port = htons(port);
+
+ namelen = sizeof(struct sockaddr_in);
+ if(connect(s, (struct sockaddr *)&name, namelen) < 0) {
+ log_event(LOG_ERR, "Unable to connect to %s:%d", host, port);
+ return(-1);
+ }
+#endif
+
+#ifdef HAVE_SSL
+ if(use_tls == True) {
+ log_event(LOG_INFO, "Creating SSL connection to host");
+
+ if (use_starttls == True)
+ {
+ use_tls=False; /* need to write plain text for a while */
+
+ if (smtp_okay(s, buf))
+ {
+ smtp_write(s, "EHLO %s", hostname);
+ if (smtp_okay(s, buf)) {
+ smtp_write(s, "STARTTLS"); /* assume STARTTLS regardless */
+ if (!smtp_okay(s, buf)) {
+ log_event(LOG_ERR, "STARTTLS not working");
+ return(-1);
+ }
+ }
+ else
+ {
+ log_event(LOG_ERR, "Invalid response: %s (%s)", buf, hostname);
+ }
+ }
+ else
+ {
+ log_event(LOG_ERR, "Invalid response SMTP Server (STARTTLS)");
+ return(-1);
+ }
+ use_tls=True; /* now continue as normal for SSL */
+ }
+
+ ssl = SSL_new(ctx);
+ if(!ssl) {
+ log_event(LOG_ERR, "SSL not working");
+ return(-1);
+ }
+ SSL_set_fd(ssl, s);
+
+ err = SSL_connect(ssl);
+ if(err < 0) {
+ perror("SSL_connect");
+ return(-1);
+ }
+
+ if(log_level > 0 || 1) {
+ log_event(LOG_INFO, "SSL connection using %s",
+ SSL_get_cipher(ssl));
+ }
+
+ server_cert = SSL_get_peer_certificate(ssl);
+ if(!server_cert) {
+ return(-1);
+ }
+ X509_free(server_cert);
+
+ /* TODO: Check server cert if changed! */
+ }
+#endif
+
+ return(s);
+}
+
+/*
+fd_getc() -- Read a character from an fd
+*/
+ssize_t fd_getc(int fd, void *c)
+{
+#ifdef HAVE_SSL
+ if(use_tls == True) {
+ return(SSL_read(ssl, c, 1));
+ }
+#endif
+ return(read(fd, c, 1));
+}
+
+/*
+fd_gets() -- Get characters from a fd instead of an fp
+*/
+char *fd_gets(char *buf, int size, int fd)
+{
+ int i = 0;
+ char c;
+
+ while((i < size) && (fd_getc(fd, &c) == 1)) {
+ if(c == '\r'); /* Strip <CR> */
+ else if(c == '\n') {
+ break;
+ }
+ else {
+ buf[i++] = c;
+ }
+ }
+ buf[i] = (char)NULL;
+
+ return(buf);
+}
+
+/*
+smtp_read() -- Get a line and return the initial digit
+*/
[... 1174 lines stripped ...]
More information about the aadk-commits
mailing list