Index: head/contrib/dma/debian/dma.dirs =================================================================== --- head/contrib/dma/debian/dma.dirs (revision 289122) +++ head/contrib/dma/debian/dma.dirs (nonexistent) @@ -1,4 +0,0 @@ -etc/dma -usr/sbin -usr/share/lintian/overrides -usr/share/man/man8 Index: head/contrib/dma/debian/dma-migrate.install =================================================================== --- head/contrib/dma/debian/dma-migrate.install (revision 289122) +++ head/contrib/dma/debian/dma-migrate.install (nonexistent) @@ -1 +0,0 @@ -debian/migrate/dma-migrate usr/sbin Index: head/contrib/dma/debian/copyright =================================================================== --- head/contrib/dma/debian/copyright (revision 289122) +++ head/contrib/dma/debian/copyright (nonexistent) @@ -1,91 +0,0 @@ -Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135 -Name: dma - -Files: base64.c -Copyright: Copyright (c) 1995-2001 Kungliga Tekniska Högskolan - (Royal Institute of Technology, Stockholm, Sweden). - All rights reserved. -License: BSD-3 - -Files: conf.c crypto.c net.c -Copyright: Copyright (c) 2008 The DragonFly Project. All rights reserved. - This code is derived from software contributed to The DragonFly Project - by Matthias Schmidt , University of Marburg, - Germany. -License: BSD-3 - -Files: dfcompat.c -Copyright: Copyright (c) 1998 Todd C. Miller - Copyright (c) 1998, M. Warner Losh All rights reserved. -License: BSD-1 BSD-2 - -Files: dma.8 -Copyright: Copyright (c) 2008 The DragonFly Project. All rights reserved. -License: BSD-3 - -Files: dma.c dns.c mail.c spool.c util.c -Copyright: Copyright (c) 2008 The DragonFly Project. All rights reserved. - This code is derived from software contributed to The DragonFly Project - by Simon 'corecode' Schubert . -License: BSD-3 - -Files: dma.h -Copyright: Copyright (c) 2008 The DragonFly Project. All rights reserved. - This code is derived from software contributed to The DragonFly Project - by Simon 'corecode' Schubert and - Matthias Schmidt . -License: BSD-3 - -Files: debian/* -Copyright: Copyright (c) 2009, 2010 Peter Pentchev. -License: BSD-3 - -License: BSD-3 - 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. - 3. Neither the name of The DragonFly Project nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific, prior written permission. - -License: BSD-1 - Permission to use, copy, modify, and distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - . - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -License: BSD-2 - 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. - . - THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. Index: head/contrib/dma/debian/dma-migrate.dirs =================================================================== --- head/contrib/dma/debian/dma-migrate.dirs (revision 289122) +++ head/contrib/dma/debian/dma-migrate.dirs (nonexistent) @@ -1,2 +0,0 @@ -usr/sbin -usr/share/man/man8 Index: head/contrib/dma/debian/source/format =================================================================== --- head/contrib/dma/debian/source/format (revision 289122) +++ head/contrib/dma/debian/source/format (nonexistent) @@ -1 +0,0 @@ -3.0 (native) Index: head/contrib/dma/debian/source/options =================================================================== --- head/contrib/dma/debian/source/options (revision 289122) +++ head/contrib/dma/debian/source/options (nonexistent) @@ -1,2 +0,0 @@ -compression = "bzip2" -compression-level = 9 Index: head/contrib/dma/debian/changelog =================================================================== --- head/contrib/dma/debian/changelog (revision 289122) +++ head/contrib/dma/debian/changelog (nonexistent) @@ -1,297 +0,0 @@ -dma (0.9) unstable; urgency=low - - [ Ed Maste ] - * Be explicit about missing user. - * Allow DMA_ROOT_USER & DMA_GROUP to be overridden. - * Add compat #ifdef for older OpenSSL - * Add CONF_DIR, as in Makefile - * More detailed error message for tmp file failure. - - [ Simon Schubert ] - * spool.c: bzero contents of pointer - - -- Simon Schubert <2@0x2c.org> Mon, 03 Jun 2013 15:58:44 +0200 - -dma (0.8) unstable; urgency=low - - [ Gert van den Berg ] - * Added some more documentation on compiling - * Make Makefile and README consistent with INSTALL - - [ Sascha Wildner ] - * dma.8: Fix a few small issues. - - [ Simon Schubert ] - * dma.8: we only have 2 config files at the moment - * Merge pull request #2 from mohag/master - * don't treat -options following -q as argument to it - * deliver_remote: propagate back DNS errors - * don't complain when we can't lock a queue file during flush - * implement queue flushing prod - - -- Simon Schubert <2@0x2c.org> Fri, 30 Mar 2012 12:03:54 +0200 - -dma (0.7) unstable; urgency=low - - [ Simon Schubert ] - * add semicolon before date in Received: header - * parse_conf: fix bug with masqueraded domains - * clear up warnings found by clang static analysis - * mark printf-alike functions - - -- Simon Schubert <2@0x2c.org> Tue, 03 Jan 2012 14:53:43 +0100 - -dma (0.6) unstable; urgency=low - - [ Simon Schubert ] - * deliver_local: quote "From " more liberally - - -- Simon Schubert <2@0x2c.org> Wed, 07 Dec 2011 12:42:22 +0100 - -dma (0.5) unstable; urgency=low - - [ Simon Schubert ] - * implement masquerading using the MASQUERADE config option - * access config files at CONF_PATH, add makefile target to install conf files - * implement the "*" catch-all alias - - -- Simon Schubert <2@0x2c.org> Wed, 16 Nov 2011 13:34:43 +0100 - -dma (0.4) unstable; urgency=low - - [ Simon Schubert ] - * Makefile: put libraries at the end when linking - * LICENSE: add - * Merge commit 'refs/merge-requests/3' of git://gitorious.org/dma/dma - * Merge commit 'refs/merge-requests/4' of git://gitorious.org/dma/dma - * Add symlink for sendmail which is expected by many packages - * Makefile: create spool directories in a separate target - * Makefile: add symlink for mailq - * README: elaborate, use markdown - - [ Peter Pentchev ] - * Fix straight SSL/TLS delivery to remote MX's. - * Fix a minor memory leak discovered by cppcheck. - - -- Simon Schubert <2@0x2c.org> Wed, 16 Nov 2011 00:08:28 +0100 - -dma (0.3) unstable; urgency=low - - [ Simon Schubert ] - * todo: we create mboxes properly now - * dma-mbox-create: group mail only needs to write to mboxes - * errlog: preserve errno - * dma-mbox-create: add error/status logging - * dns_get_mx_list: handle errors properly - - [ Peter Pentchev ] - * Make add_host() really return an error code. - - [ Simon Schubert ] - * readmail: accept mail without newline at the end - - [ Peter Pentchev ] - * In OpenSSL 1.0, TLSv1_client_method() returns a const pointer. - - [ Simon Schubert ] - * make dma compile again on DragonFly - * parse_addrs: fix parsing for multiple - - -- Simon Schubert <2@0x2c.org> Sat, 09 Jul 2011 02:38:05 +0200 - -dma (0.2) unstable; urgency=low - - * Update to dma 0.2 - - debian: better mark as UNRELEASED - - add ppa makefile recipe - - TODO: suggest way to run a queue flush on boot - - partially adopt 34-manpage-defaults.patch: AUTHPATH is not set by default - - Revert "debian: better mark as UNRELEASED" - - setlogident: openlog() wants a static variable - - writequeuef: create files with g+rw - - drop privileges when run by root - - implement mbox creation via setuid helper - - debian: build with consistent flags - - debian: remove unused files - - debian: fix lintian warnings and errors - - make ppa: force lower version number - - make ppa: proper name - - -- Simon Schubert <2@0x2c.org> Sun, 31 Oct 2010 23:57:50 +0100 - -dma (0.1) unstable; urgency=low - - * Update dma to 0.1 - - -- Simon Schubert <2@0x2c.org> Fri, 29 Oct 2010 00:57:26 +0200 - -dma (0.0.2010.06.17-6) unstable; urgency=low - - * Add the 37-gnu-hurd patch to really fix the FTBFS on GNU/Hurd. - * Convert several shell output assignments from = to := - * Switch to bzip2 compression for the Debian tarball. - - -- Peter Pentchev Sun, 17 Oct 2010 00:08:33 +0300 - -dma (0.0.2010.06.17-5) unstable; urgency=low - - * Only use SA_NOCLDWAIT if available to fix the Hurd FTBFS. - - -- Peter Pentchev Thu, 07 Oct 2010 11:42:23 +0300 - -dma (0.0.2010.06.17-4) unstable; urgency=low - - * Fix an infinite loop in dma-migrate if char is unsigned. - Closes: #599172 - * Switch to Git and point the Vcs-* fields to Gitorious. - - -- Peter Pentchev Wed, 06 Oct 2010 17:30:29 +0300 - -dma (0.0.2010.06.17-3) unstable; urgency=low - - * Update the debconf translations: - - French by Steve Petruzzello; Closes: #587883 - * Bump Standards-Version to 3.9.1 with no changes. - * Disable deferred delivery by default, as in the upstream version: - - in the 03-debian-locations patch, comment the DEFER keyword in dma.conf, - as it is upstream - - refresh the 11-double-bounce.patch - - reword the README.Debian section on deferred delivery a bit - - add a news blurb - - -- Peter Pentchev Tue, 27 Jul 2010 13:34:27 +0300 - -dma (0.0.2010.06.17-2) unstable; urgency=low - - * Quick on the heels of -1 to fix a momentary lapse of reason on my part: - in the 03-debian-locations patch, revert part of the 0.0.2010.06.17-1 - change: do not set a un-overrideable default for the deferred delivery! - Closes: #587593 - * Update the debconf translations: - - Japanese by Hideki Yamane; Closes: #587543 - - -- Peter Pentchev Wed, 30 Jun 2010 11:59:46 +0300 - -dma (0.0.2010.06.17-1) unstable; urgency=low - - * New upstream version: - - no longer reports the remote port number; Closes: #544820 - - fixes some queue locking problems; Closes: #582593 - - adapt the rules file to use the GNU Makefile instead of the BSD one - - drop pmake from Build-Depends - - remove the 01-debian-build patch, overtaken by upstream changes - - in the 03-debian-locations patch, make the Debian defaults actual - defaults for the dma binary, not just in the dma.conf file - - adapt the 04-debian-setgid patch for the GNU Makefile - - in the 10-liblockfile patch, change the GNU Makefile, too - - enhance the 11-double-bounce patch a bit: - - use dma's own delqueue() function instead of a naive unlink() so - all the queue files are cleaned up - - document the Debian default for DBOUNCEPROG in the manual page - - resurrect the 13-hardening patch, correcting a couple of - unchecked asprintf(3) and vasprintf(3) invocations - - the functionality of the 20-parse-recipient patch was implemented - upstream in a different way, so replace it with a small bugfix - - remove the 22-openfiles patch, overtaken by upstream changes - - in the 24-random-message-id patch, change the GNU Makefile, too - - add the 27-int-size patch to cast a variable to the correct type - - add the 28-valid-recipient patch to fix parsing recipients out of - the message body - - add the 29-double-free patch to fix a double-free error - - add the 30-ldflags patch to honor LDFLAGS if specified - - refresh the 09-typos, 17-mailname, 23-dirent-d_type, and - 25-unsupported-starttls patches - - teach the dbounce-simple-safecat handler about the M*/Q* spool - files scheme - * Bump Standards-Version to 3.9.0 with no changes. - * Update the copyright file: - - bring it up to the latest revision of the DEP 5 - - update the upstream copyright notices - - bump the year on my copyright notice - * Remove the diffsrc rules target which was intended for my own - internal use, but has outlived its time. - * Use dpkg-buildflags from dpkg-dev >= 1.15.7~ to get the default - values for CFLAGS, CPPFLAGS, and LDFLAGS; no longer rely on - dpkg-buildpackage to set them by default. - * Add the dma-migrate utility (in a separate binary package) to convert - spool files to the new queue format (M* and Q* files for each message) - * Add a dma-migrate invocation to dma.cron.d - * Shorten the Vcs-Browser URL. - * Add the 31-sigalrm-backoff patch to force a delivery attempt on SIGALRM. - * Properly substitute the debconf-supplied values for DBOUNCEPROG and - SMARTHOST into dma.conf even if they are empty without generating - an invalid dma.conf file. - * Remove the smarthost default; dma does MX lookups now, so it doesn't - really *need* one anymore. - * Reword the debconf relayhost question - dma does not really need - a smarthost anymore. - * Update the debconf translations: - - Bulgarian - - Portuguese by Américo Monteiro - - German by Helge Kreutzmann; Closes: #586531 - - Russian by Yuri Kozlov; Closes: #586579 - - Czech by Michal Simunek; Closes: #586791 - - Swedish by Martin Bagge; Closes: #586825 - - Spanish by Francisco Javier Cuadrado; Closes: #587088 - * Update the smarthost configuration information in README.Debian. - * Add the 32-comment-uncomment patch to correct the manual page wording. - * Add the 33-opportunistic-tls patch to allow remote connections to proceed - even if the STARTTLS negotiation fails. - * Fix the 25-unsupported-starttls patch to actually error out if the SSL - negotiation fails. - * Forward all the non-Debian-specific patches upstream to Simon Schubert. - * Add the 34-manpage-defaults patch to properly document what dma will use - as default values if not specified in the config file instead of what - the default config file specifies. Closes: #544748 - * Add the 35-delivery-retry patch to try local deliveries a bit more often - and to randomize the delivery timeout to avoid locking issues. - - -- Peter Pentchev Mon, 28 Jun 2010 23:26:36 +0300 - -dma (0.0.2009.07.17-3) unstable; urgency=low - - * Really install the files in /etc/dma/ as root/mail/640 and - change the ownership of the existing files in the postinst script - when upgrading from older versions. Closes: #544664 - * Install the /usr/bin/mailq and /usr/bin/newaliases symlinks. - Closes: #558421 - * Switch to the 3.0 (quilt) source format. - * Update the debconf translations: - - add German. Closes: #552754 - - add Japanese. Closes: #554515 - - remove a double space and unfuzzy the translations. Closes: #552586 - * Fix a crash when the SMTP server does not support STARTTLS. - Closes: #547594 - * Always use the user-supplied value from the debconf query for - the smarthost and the double-bounce program. This may result in - debconf overriding a manually-edited config file, so add a note to - dma.conf stating that these values are handled via debconf. - Closes: #544663 - * Fix a misspelling of dma/dbounceprog as dma/defer in the debconf - configuration script. Oops. - - -- Peter Pentchev Sat, 19 Dec 2009 14:35:10 +0200 - -dma (0.0.2009.07.17-2) unstable; urgency=low - - * Allow the spool directory to live on a filesystem that does not - set the d_type member of the dirent structure, like XFS. - Closes: #544357 - * Randomize the Message-Id a bit more. Closes: #544475 - * Bump Standards-Version to 3.8.3 with no changes. - * Only enable the build hardening wrapper if the "hardening" build - option is specified. - * Switch the copyright file header from the Wiki to DEP 5. - * Remove the manual page ".Dx" patch - the groff version in Squeeze - knows about the .Dx mdoc macro. Add a lintian override for - the "Unknown DragonFly version" error. - * Convert the patch file headers to the DEP 3 format. - - -- Peter Pentchev Tue, 01 Sep 2009 13:36:33 +0300 - -dma (0.0.2009.07.17-1) unstable; urgency=low - - * Initial release - (Closes: #511410, #533458, #533614, #533890, #534101, #534860) - - -- Peter Pentchev Tue, 11 Aug 2009 16:08:41 +0300 Index: head/contrib/dma/debian/control =================================================================== --- head/contrib/dma/debian/control (revision 289122) +++ head/contrib/dma/debian/control (nonexistent) @@ -1,37 +0,0 @@ -Source: dma -Section: mail -Priority: optional -Maintainer: Peter Pentchev -DM-Upload-Allowed: yes -Build-Depends: debhelper (>= 7.0.50), byacc, dpkg-dev (>= 1.15.7~), flex, hardening-wrapper, libssl-dev, po-debconf -Standards-Version: 3.9.1 -Homepage: http://devel.ringlet.net/mail/dma/ -Vcs-Git: git://gitorious.org/dma-roam/pkg-debian.git -Vcs-Browser: http://gitorious.org/dma-roam/pkg-debian - -Package: dma -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Provides: mail-transport-agent -Conflicts: mail-transport-agent -Replaces: mail-transport-agent -Recommends: dma-migrate -Description: lightweight mail transport agent - The DragonFly Mail Agent is a small Mail Transport Agent (MTA), - designed for home and office use. It accepts mails from local Mail - User Agents (MUA) and delivers them either to local mailboxes or - remote SMTP servers. Remote delivery includes support for features - such as TLS/SSL and SMTP authentication. - . - dma is not intended as a replacement for full-featured MTAs like - Sendmail, Postfix, or Exim. Consequently, dma does not listen on - port 25 for incoming connections. - -Package: dma-migrate -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Enhances: dma -Description: migration utility for the DragonFly Mail Agent's spool files - The dma-migrate utility examines the DragonFly Mail Agent's mail queue - and performs any conversions from old message file formats to the most - recent one as needed. Index: head/contrib/dma/debian/NEWS =================================================================== --- head/contrib/dma/debian/NEWS (revision 289122) +++ head/contrib/dma/debian/NEWS (nonexistent) @@ -1,29 +0,0 @@ -dma (0.0.2010.06.17-3) unstable; urgency=low - - The default delivery mode has been changed to immediate, as it is in - the upstream version of dma; the DEFER keyword is now disabled by default - in dma.conf. - - -- Peter Pentchev Tue, 27 Jul 2010 13:26:48 +0300 - -dma (0.0.2010.06.17-1) unstable; urgency=low - - The dma spool directory format has changed. The Debian package of dma now - recommends a separate package containing the dma-migrate utility; if it is - present, it will be invoked at each periodic dma queue flush and attempt to - convert the existing old-style queued messages to the new format. In most - cases, this should not incur any performance penalties in normal operation, - since dma-migrate will scan the spool directory and ignore any new messages - (they should already be in the new format); however, if it appears that - the periodic queue flush runs take longer than usual to start up, you may - remove the dma-migrate package once you have ascertained that your queue - directory (/var/spool/dma) only contains files with names beginning with - the letters M or Q. - - This version of dma knows how to perform MX lookups, so remote delivery is - now possible directly, not through a smarthost. However, a smarthost setup - might still be preferred on many systems for various reasons - e.g. dynamic - address assignment, a central outgoing mailserver, a roaming laptop, etc. - - -- Peter Pentchev Mon, 21 Jun 2010 11:03:57 +0300 - Index: head/contrib/dma/debian/dma.links =================================================================== --- head/contrib/dma/debian/dma.links (revision 289122) +++ head/contrib/dma/debian/dma.links (nonexistent) @@ -1,6 +0,0 @@ -usr/sbin/dma usr/bin/mailq -usr/sbin/dma usr/bin/newaliases -usr/sbin/dma usr/sbin/sendmail -usr/share/man/man8/dma.8 usr/share/man/man8/mailq.8 -usr/share/man/man8/dma.8 usr/share/man/man8/newaliases.8 -usr/share/man/man8/dma.8 usr/share/man/man8/sendmail.8 Index: head/contrib/dma/debian/migrate/NEWS =================================================================== --- head/contrib/dma/debian/migrate/NEWS (revision 289122) +++ head/contrib/dma/debian/migrate/NEWS (nonexistent) @@ -1,6 +0,0 @@ -Change log for dma-migrate, the DragonFly Mail Agent queue migration utility. - -0.01 not yet ;) - - first public release - -Comments: Peter Pentchev Index: head/contrib/dma/debian/migrate/dma-migrate.c =================================================================== --- head/contrib/dma/debian/migrate/dma-migrate.c (revision 289122) +++ head/contrib/dma/debian/migrate/dma-migrate.c (nonexistent) @@ -1,413 +0,0 @@ -/*- - * Copyright (c) 2010 Peter Pentchev - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - */ - -#define _GNU_SOURCE - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __printflike -#ifdef __GNUC__ -#define __printflike(fmtarg, firstvararg) \ - __attribute__((__format__ (__printf__, fmtarg, firstvararg))) -#else -#define __printflike(fmtarg, firstvararg) -#endif -#endif - -#define DEFAULT_SPOOLDIR "/var/spool/dma" - -static int verbose = 0; -static char copybuf[BUFSIZ]; - -static int dma_migrate(int, const char *); - -static int open_locked(const char *, int, ...); -static void cleanup_file(int, char *); - -static void usage(int); -static void version(void); -static void debug(const char *, ...) __printflike(1, 2); - -int -main(int argc, char **argv) -{ - const char *spooldir; - int hflag, Vflag, errs, fd, res; - int ch; - DIR *d; - struct dirent *e; - struct stat sb; - - srandom((unsigned long)((time(NULL) ^ getpid()) + ((uintptr_t)argv))); - - hflag = Vflag = 0; - spooldir = DEFAULT_SPOOLDIR; - while (ch = getopt(argc, argv, "d:hVv"), ch != -1) - switch (ch) { - case 'd': - spooldir = optarg; - break; - - case 'h': - hflag = 1; - break; - - case 'V': - Vflag = 1; - break; - - case 'v': - verbose = 1; - break; - - case '?': - default: - usage(1); - /* NOTREACHED */ - } - if (Vflag) - version(); - if (hflag) - usage(0); - if (hflag || Vflag) - exit(0); - - argc -= optind; - argv += optind; - - /* Let's roll! */ - if (chdir(spooldir) == -1) - err(1, "Could not change into spool directory %s", spooldir); - if (d = opendir("."), d == NULL) - err(1, "Could not read spool directory %s", spooldir); - errs = 0; - while (e = readdir(d), e != NULL) { - /* Do we care about this entry? */ - debug("Read a directory entry: %s\n", e->d_name); - if (strncmp(e->d_name, "tmp_", 4) == 0 || - e->d_name[0] == 'M' || e->d_name[0] == 'Q' || - (e->d_type != DT_REG && e->d_type != DT_UNKNOWN)) - continue; - if (e->d_type == DT_UNKNOWN) - if (stat(e->d_name, &sb) == -1 || !S_ISREG(sb.st_mode)) - continue; - debug("- want to process it\n"); - - /* Try to lock it - skip it if dma is delivering the message */ - if (fd = open_locked(e->d_name, O_RDONLY|O_NDELAY), fd == -1) { - debug("- seems to be locked, skipping\n"); - continue; - } - - /* Okay, convert it to the M/Q schema */ - res = dma_migrate(fd, e->d_name); - close(fd); - if (res == -1) - errs++; - } - if (errs) - debug("Finished, %d conversion errors\n", errs); - else - debug("Everything seems to be all right\n"); - return (errs && 1); -} - -static int -dma_migrate(int fd, const char *fname) -{ - const char *id; - char *mname, *qname, *tempname, *sender, *recp, *line, *recpline; - int mfd, qfd, tempfd; - struct stat sb; - FILE *fp, *qfp, *mfp; - size_t sz, len; - static regex_t *qidreg = NULL; - - mfd = tempfd = qfd = -1; - mname = qname = sender = recp = line = NULL; - fp = qfp = NULL; - - if (fstat(fd, &sb) == -1) { - warn("Could not fstat(%s)", fname); - return (-1); - } - /* - * Let's just blithely assume that the queue ID *is* the filename, - * since that's the way dma did things so far. - * Well, okay, let's check it. - */ - if (qidreg == NULL) { - regex_t *nreg; - - if ((nreg = malloc(sizeof(*qidreg))) == NULL) { - warn("Could not allocate memory for a regex"); - return (-1); - } - if (regcomp(nreg, "^[a-fA-F0-9]\\+\\.[a-fA-F0-9]\\+$", 0) - != 0) { - warnx("Could not compile a dma queue ID regex"); - free(nreg); - return (-1); - } - qidreg = nreg; - } - if (regexec(qidreg, fname, 0, NULL, 0) != 0) { - warnx("The name '%s' is not a valid dma queue ID", fname); - return (-1); - } - id = fname; - debug(" - queue ID %s\n", id); - if (asprintf(&mname, "M%s", id) == -1 || - asprintf(&tempname, "tmp_%s", id) == -1 || - asprintf(&qname, "Q%s", id) == -1 || - mname == NULL || tempname == NULL || qname == NULL) - goto fail; - - /* Create the message placeholder early to avoid races */ - mfd = open_locked(mname, O_CREAT | O_EXCL | O_RDWR, 0600); - if (mfd == -1) { - warn("Could not create temporary file %s", mname); - goto fail; - } - if (stat(qname, &sb) != -1 || errno != ENOENT || - stat(tempname, &sb) != -1 || errno != ENOENT) { - warnx("Some of the queue files for %s already exist", fname); - goto fail; - } - debug(" - mfd %d names %s, %s, %s\n", mfd, mname, tempname, qname); - - fp = fdopen(fd, "r"); - if (fp == NULL) { - warn("Could not reopen the descriptor for %s", fname); - goto fail; - } - - /* Parse the header of the old-format message file */ - /* ...sender... */ - if (getline(&sender, &sz, fp) == -1) { - warn("Could not read the initial line from %s", fname); - goto fail; - } - sz = strlen(sender); - while (sz > 0 && (sender[sz - 1] == '\n' || sender[sz - 1] == '\r')) - sender[--sz] = '\0'; - if (sz == 0) { - warnx("Empty sender line in %s", fname); - goto fail; - } - debug(" - sender %s\n", sender); - /* ...recipient(s)... */ - len = strlen(fname); - recpline = NULL; - while (1) { - if (getline(&line, &sz, fp) == -1) { - warn("Could not read a recipient line from %s", fname); - goto fail; - } - sz = strlen(line); - while (sz > 0 && - (line[sz - 1] == '\n' || line[sz - 1] == '\r')) - line[--sz] = '\0'; - if (sz == 0) { - free(line); - line = NULL; - break; - } - if (recp == NULL && - strncmp(line, fname, len) == 0 && line[len] == ' ') { - recp = line + len + 1; - recpline = line; - } else { - free(line); - } - line = NULL; - } - if (recp == NULL) { - warnx("Could not find its own recipient line in %s", fname); - goto fail; - } - /* ..phew, finished with the header. */ - - tempfd = open_locked(tempname, O_CREAT | O_EXCL | O_RDWR, 0600); - if (tempfd == -1) { - warn("Could not create a queue file for %s", fname); - goto fail; - } - qfp = fdopen(tempfd, "w"); - if (qfp == NULL) { - warn("Could not fdopen(%s) for %s", tempname, fname); - goto fail; - } - mfp = fdopen(mfd, "w"); - if (mfp == NULL) { - warn("Could not fdopen(%s) for %s", mname, fname); - goto fail; - } - fprintf(qfp, "ID: %s\nSender: %s\nRecipient: %s\n", id, sender, recp); - fflush(qfp); - fsync(tempfd); - - /* Copy the message file over to mname */ - while ((sz = fread(copybuf, 1, sizeof(copybuf), fp)) > 0) - if (fwrite(copybuf, 1, sz, mfp) != sz) { - warn("Could not copy the message from %s to %s", - fname, mname); - goto fail; - } - if (ferror(fp)) { - warn("Could not read the full message from %s", fname); - goto fail; - } - fflush(mfp); - fsync(mfd); - - if (rename(tempname, qname) == -1) { - warn("Could not rename the queue file for %s", fname); - goto fail; - } - qfd = tempfd; - tempfd = -1; - if (unlink(fname) == -1) { - warn("Could not remove the old converted file %s", fname); - goto fail; - } - - fclose(fp); - fclose(qfp); - free(sender); - free(line); - free(recpline); - free(mname); - free(qname); - free(tempname); - return (0); - -fail: - if (fp != NULL) - fclose(fp); - if (qfp != NULL) - fclose(qfp); - if (sender != NULL) - free(sender); - if (line != NULL) - free(line); - if (recpline != NULL) - free(recpline); - cleanup_file(mfd, mname); - cleanup_file(qfd, qname); - cleanup_file(tempfd, tempname); - return (-1); -} - -static void -cleanup_file(int fd, char *fname) -{ - if (fd != -1) { - close(fd); - unlink(fname); - } - if (fname != NULL) - free(fname); -} - -static void -usage(int ferr) -{ - const char *s = - "Usage:\tdma-migrate [-hVv] [-d spooldir]\n" - "\t-d\tspecify the spool directory (" DEFAULT_SPOOLDIR ")\n" - "\t-h\tdisplay program usage information and exit\n" - "\t-V\tdisplay program version information and exit\n" - "\t-v\tverbose operation - display diagnostic messages"; - - if (ferr) - errx(1, "%s", s); - puts(s); -} - -static void -version(void) -{ - printf("dma-migrate 0.01 (dma 0.0.2010.06.17)\n"); -} - -static void -debug(const char *fmt, ...) -{ - va_list v; - - if (verbose < 1) - return; - va_start(v, fmt); - vfprintf(stderr, fmt, v); - va_end(v); -} - -static int -open_locked(const char *fname, int flags, ...) -{ - int mode = 0; -#ifndef O_EXLOCK - int fd, save_errno; -#endif - - if (flags & O_CREAT) { - va_list ap; - va_start(ap, flags); - mode = va_arg(ap, int); - va_end(ap); - } - -#ifndef O_EXLOCK - fd = open(fname, flags, mode); - if (fd < 0) - return(fd); - if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) { - save_errno = errno; - close(fd); - errno = save_errno; - return(-1); - } - return(fd); -#else - return(open(fname, flags|O_EXLOCK, mode)); -#endif -} Property changes on: head/contrib/dma/debian/migrate/dma-migrate.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/dma/debian/migrate/Makefile =================================================================== --- head/contrib/dma/debian/migrate/Makefile (revision 289122) +++ head/contrib/dma/debian/migrate/Makefile (nonexistent) @@ -1,4 +0,0 @@ -all: dma-migrate - -clean: - rm -f dma-migrate dma-migrate.o Property changes on: head/contrib/dma/debian/migrate/Makefile ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/dma/debian/migrate/dma-migrate.8 =================================================================== --- head/contrib/dma/debian/migrate/dma-migrate.8 (revision 289122) +++ head/contrib/dma/debian/migrate/dma-migrate.8 (nonexistent) @@ -1,98 +0,0 @@ -.\" Copyright (c) 2010 Peter Pentchev -.\" 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. -.\" -.Dd May 11, 2009 -.Dt dma-migrate 8 -.Os -.Sh NAME -.Nm dma-migrate -.Nd convert the DragonFly Mail Agent's queue files -.Sh SYNOPSIS -.Nm -.Op Fl v -.Op Fl d Ar spooldir -.Nm -.Op Fl h | Fl V -.Sh DESCRIPTION -The -.Nm -utility is used to convert the mail queue files in the -.Xr dma 8 -spool directory to the latest spool directory format supported by -the installed version of -.Xr dma 8 . -Currently it only handles the conversion from a single file containing -both message and delivery metadata to the M/Q format. -.Pp -The following command-line options are available: -.Bl -tag -width indent -.It Fl d -Specify the location of the -.Xr dma 8 -spool directory, default -.Pa /var/spool/dma . -.It Fl h -Display usage information and exit. -.It Fl V -Display program version information and exit. -.It Fl v -Verbose output - display diagnostic messages. -.El -.Sh ENVIRONMENT -The operation of the -.Nm -utility is currently not influenced by environment variables. -.Sh FILES -The -.Nm -utility looks for the -.Xr dma 8 -mail queue files in the -.Pa /var/spool/dma -directory, unless another location is specified by the -.Fl d -command-line option. -.Sh EXIT STATUS -The -.Nm -utility will scan the whole spool directory and attempt to convert all -suitable files there. -If there are no files to be converted, or if all the conversions are -successful, it will complete with an exit code of zero. -If any conversion errors are encountered, a message will be displayed -to the standard error stream and -.Nm -will exit with an exit code of 1 after attempting to convert the rest of -the suitable files in the spool directory. -.Sh SEE ALSO -.Xr dma 8 -.Sh STANDARDS -No standards documentation was harmed in the process of creating -.Nm . -.Sh BUGS -Please report any bugs in -.Nm -to the author. -.Sh AUTHOR -.An Peter Pentchev Aq roam@ringlet.net Property changes on: head/contrib/dma/debian/migrate/dma-migrate.8 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/contrib/dma/debian/rules =================================================================== --- head/contrib/dma/debian/rules (revision 289122) +++ head/contrib/dma/debian/rules (nonexistent) @@ -1,49 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# Debian build rules for dma, the DragonFly mail agent - -DDIR= $(CURDIR)/debian -D= $(DDIR)/dma - -BUILDDEFS= DESTDIR=$D PREFIX=/usr - -CFLAGS:= $(shell dpkg-buildflags --get CFLAGS) -CPPFLAGS:= $(shell dpkg-buildflags --get CPPFLAGS) -LDFLAGS:= $(shell dpkg-buildflags --get LDFLAGS) - -CONFFILES= dma.conf auth.conf - -ifneq (,$(filter werror,$(DEB_BUILD_OPTIONS))) - CFLAGS+= -Werror -endif -ifneq (,$(filter nostrip,$(DEB_BUILD_OPTIONS))) - export STRIPFLAG= -endif -ifneq (,$(filter hardening,$(DEB_BUILD_OPTIONS))) -export DEB_BUILD_HARDENING=1 -else -export DEB_BUILD_HARDENING=0 -endif - -export CFLAGS CPPFLAGS LDFLAGS - -override_dh_auto_build: - $(MAKE) -f Makefile ${BUILDDEFS} - $(MAKE) -C $(DDIR)/migrate - -override_dh_auto_clean: - $(MAKE) -f Makefile clean - $(MAKE) -C $(DDIR)/migrate clean - -override_dh_auto_install: - $(MAKE) -f Makefile ${BUILDDEFS} install sendmail-link mailq-link install-spool-dirs install-etc - -override_dh_fixperms: - dh_fixperms -Xusr/sbin/dma -Xusr/lib/dma-mbox-create -Xvar/spool/dma -Xetc/dma - -override_dh_installchangelogs: - dh_installchangelogs -p dma - dh_installchangelogs -p dma-migrate debian/migrate/NEWS - -%: - dh $@ Property changes on: head/contrib/dma/debian/rules ___________________________________________________________________ Deleted: svn:executable ## -1 +0,0 ## -* \ No newline at end of property Index: head/contrib/dma/debian/README.Debian =================================================================== --- head/contrib/dma/debian/README.Debian (revision 289122) +++ head/contrib/dma/debian/README.Debian (nonexistent) @@ -1,12 +0,0 @@ -dma for Debian --------------- - -Smarthost operation by default - needs to be configured! - -After first installing dma, you need to configure it for proper operation - -whether it should deliver all outgoing e-mail messages through a single -smarthost or attempt to contact the remote mail servers directly. This should -be configured through the debconf questions, but you may change the setting -using the SMARTHOST directive in the /etc/dma/dma.conf file. - - -- Simon Schubert <2@0x2c.org> Fri, 29 Oct 2010 00:25:48 +0200 Index: head/contrib/dma/debian/compat =================================================================== --- head/contrib/dma/debian/compat (revision 289122) +++ head/contrib/dma/debian/compat (nonexistent) @@ -1 +0,0 @@ -7 Index: head/contrib/dma/debian/dma-migrate.manpages =================================================================== --- head/contrib/dma/debian/dma-migrate.manpages (revision 289122) +++ head/contrib/dma/debian/dma-migrate.manpages (nonexistent) @@ -1 +0,0 @@ -debian/migrate/dma-migrate.8 Index: head/contrib/dma/debian/dma.lintian-overrides =================================================================== --- head/contrib/dma/debian/dma.lintian-overrides (revision 289122) +++ head/contrib/dma/debian/dma.lintian-overrides (nonexistent) @@ -1,8 +0,0 @@ -dma: manpage-has-errors-from-man *Unknown DragonFly version* -dma: non-standard-dir-in-var var/mail/ -dma: non-standard-dir-perm var/spool/dma/ 0770 != 0755 -dma: non-standard-dir-perm var/spool/dma/ 2775 != 0755 -dma: non-standard-file-perm etc/dma/auth.conf 0640 != 0644 -dma: no-upstream-changelog -dma: setgid-binary usr/sbin/dma 2755 root/mail -dma: setuid-binary usr/lib/dma-mbox-create 4754 root/mail Index: head/contrib/dma/BSDmakefile =================================================================== --- head/contrib/dma/BSDmakefile (revision 289122) +++ head/contrib/dma/BSDmakefile (nonexistent) @@ -1,28 +0,0 @@ -# $DragonFly: src/libexec/dma/Makefile,v 1.5 2008/09/19 00:36:57 corecode Exp $ -# - -version!= sh get-version.sh - -CFLAGS+= -I${.CURDIR} -CFLAGS+= -DHAVE_REALLOCF -DHAVE_STRLCPY -DHAVE_GETPROGNAME -CFLAGS+= -DLIBEXEC_PATH='"${LIBEXEC}"' -DDMA_VERSION='"${version}"' -CFLAGS+= -DCONF_PATH='"${CONFDIR}"' - -DPADD= ${LIBSSL} ${LIBCRYPTO} -LDADD= -lssl -lcrypto - -PROG= dma -SRCS= aliases_parse.y aliases_scan.l base64.c conf.c crypto.c -SRCS+= dma.c dns.c local.c mail.c net.c spool.c util.c -MAN= dma.8 - -PREFIX?= /usr/local -LIBEXEC?= ${PREFIX}/libexec -CONFDIR?= ${PREFIX}/etc/dma - -BINOWN= root -BINGRP= mail -BINMODE=2555 -WARNS?= 6 - -.include Index: head/contrib/dma/LICENSE =================================================================== --- head/contrib/dma/LICENSE (revision 289122) +++ head/contrib/dma/LICENSE (revision 289123) @@ -1,109 +1,109 @@ +Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. Copyright (c) 2008 The DragonFly Project. -Copyright (c) 2008-2011, Simon Schubert <2@0x2c.org>. All rights reserved. This code is derived from software contributed to The DragonFly Project by Simon Schubert <2@0x2c.org>. This code is derived from software contributed to The DragonFly Project by Matthias Schmidt , University of Marburg, Germany. 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. 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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. -Copyright (c) 1995-2001 Kungliga Tekniska Högskolan +Copyright (c) 1995-2001 Kungliga Tekniska Högskolan (Royal Institute of Technology, Stockholm, Sweden). 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. 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. Copyright (c) 1998 Todd C. Miller Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Copyright (c) 1998, M. Warner Losh 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. THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. Index: head/contrib/dma/README.markdown =================================================================== --- head/contrib/dma/README.markdown (revision 289122) +++ head/contrib/dma/README.markdown (revision 289123) @@ -1,32 +1,37 @@ dma -- DragonFly Mail Agent =========================== dma is a small Mail Transport Agent (MTA), designed for home and office use. It accepts mails from locally installed Mail User Agents (MUA) and delivers the mails either locally or to a remote destination. Remote delivery includes several features like TLS/SSL support and SMTP authentication. dma is not intended as a replacement for real, big MTAs like sendmail(8) or postfix(1). Consequently, dma does not listen on port 25 for incoming connections. Building -------- +In Linux: + make +In BSD: + + cd bsd && make Installation ------------ make install sendmail-link mailq-link install-spool-dirs install-etc See INSTALL for requirements and configuration options. Contact ------- Simon Schubert <2@0x2c.org> Index: head/contrib/dma/TODO =================================================================== --- head/contrib/dma/TODO (revision 289122) +++ head/contrib/dma/TODO (revision 289123) @@ -1,5 +1,4 @@ - unquote/handle quoted local recipients -- use proper sysexit codes - handle/use ESMTP extensions - .forward support - suggest way to run a queue flush on boot Index: head/contrib/dma/VERSION =================================================================== --- head/contrib/dma/VERSION (revision 289122) +++ head/contrib/dma/VERSION (revision 289123) @@ -1 +1 @@ -v0.9 +v0.10 Index: head/contrib/dma/aliases_parse.y =================================================================== --- head/contrib/dma/aliases_parse.y (revision 289122) +++ head/contrib/dma/aliases_parse.y (revision 289123) @@ -1,112 +1,110 @@ %{ #include #include #include #include "dma.h" extern int yylineno; static void yyerror(const char *); -int yywrap(void); -int yylex(void); static void yyerror(const char *msg) { /** * Because we do error '\n' below, we need to report the error * one line above of what yylineno points to. */ syslog(LOG_CRIT, "aliases line %d: %s", yylineno - 1, msg); fprintf(stderr, "aliases line %d: %s\n", yylineno - 1, msg); } int yywrap(void) { return (1); } %} %union { char *ident; struct stritem *strit; struct alias *alias; } %token T_IDENT %token T_ERROR %token T_EOF 0 %type dests %type alias aliases %% start : aliases T_EOF { LIST_FIRST(&aliases) = $1; } aliases : /* EMPTY */ { $$ = NULL; } | alias aliases { if ($2 != NULL && $1 != NULL) LIST_INSERT_AFTER($2, $1, next); else if ($2 == NULL) $2 = $1; $$ = $2; } ; alias : T_IDENT ':' dests '\n' { struct alias *al; if ($1 == NULL) YYABORT; al = calloc(1, sizeof(*al)); if (al == NULL) YYABORT; al->alias = $1; SLIST_FIRST(&al->dests) = $3; $$ = al; } | error '\n' { YYABORT; } ; dests : T_IDENT { struct stritem *it; if ($1 == NULL) YYABORT; it = calloc(1, sizeof(*it)); if (it == NULL) YYABORT; it->str = $1; $$ = it; } | T_IDENT ',' dests { struct stritem *it; if ($1 == NULL) YYABORT; it = calloc(1, sizeof(*it)); if (it == NULL) YYABORT; it->str = $1; SLIST_NEXT(it, next) = $3; $$ = it; } ; %% Index: head/contrib/dma/aliases_scan.l =================================================================== --- head/contrib/dma/aliases_scan.l (revision 289122) +++ head/contrib/dma/aliases_scan.l (revision 289123) @@ -1,24 +1,24 @@ %{ #include +#include "dma.h" #include "aliases_parse.h" #define YY_NO_INPUT -int yylex(void); %} %option yylineno %option nounput %% [^:,#[:space:][:cntrl:]]+ {yylval.ident = strdup(yytext); return T_IDENT;} ^([[:blank:]]*(#.*)?\n)+ ;/* ignore empty lines */ [:,\n] return yytext[0]; (\n?[[:blank:]]+|#.*)+ ;/* ignore whitespace and continuation */ \\\n ;/* ignore continuation. not allowed in comments */ . return T_ERROR; <> return T_EOF; %% Index: head/contrib/dma/conf.c =================================================================== --- head/contrib/dma/conf.c (revision 289122) +++ head/contrib/dma/conf.c (revision 289123) @@ -1,246 +1,245 @@ /* * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Matthias Schmidt , University of Marburg, * Germany. * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ #include #include #include #include #include #include #include #include "dma.h" #define DP ": \t" #define EQS " \t" /* * Remove trailing \n's */ void trim_line(char *line) { size_t linelen; char *p; if ((p = strchr(line, '\n'))) *p = (char)0; /* Escape leading dot in every case */ linelen = strlen(line); if (line[0] == '.') { if ((linelen + 2) > 1000) { syslog(LOG_CRIT, "Cannot escape leading dot. Buffer overflow"); - exit(1); + exit(EX_DATAERR); } memmove((line + 1), line, (linelen + 1)); line[0] = '.'; } } static void chomp(char *str) { size_t len = strlen(str); if (len == 0) return; if (str[len - 1] == '\n') str[len - 1] = 0; } /* * Read the SMTP authentication config file * * file format is: * user|host:password * * A line starting with # is treated as comment and ignored. */ void parse_authfile(const char *path) { char line[2048]; struct authuser *au; FILE *a; char *data; int lineno = 0; a = fopen(path, "r"); if (a == NULL) { - errlog(1, "can not open auth file `%s'", path); + errlog(EX_NOINPUT, "can not open auth file `%s'", path); /* NOTREACHED */ } while (!feof(a)) { if (fgets(line, sizeof(line), a) == NULL) break; lineno++; chomp(line); /* We hit a comment */ if (*line == '#') continue; /* Ignore empty lines */ if (*line == 0) continue; au = calloc(1, sizeof(*au)); if (au == NULL) - errlog(1, "calloc failed"); + errlog(EX_OSERR, NULL); data = strdup(line); au->login = strsep(&data, "|"); au->host = strsep(&data, DP); au->password = data; if (au->login == NULL || au->host == NULL || au->password == NULL) { - errlogx(1, "syntax error in authfile %s:%d", - path, lineno); + errlogx(EX_CONFIG, "syntax error in authfile %s:%d", path, lineno); /* NOTREACHED */ } SLIST_INSERT_HEAD(&authusers, au, next); } fclose(a); } /* * XXX TODO * Check for bad things[TM] */ void parse_conf(const char *config_path) { char *word; char *data; FILE *conf; char line[2048]; int lineno = 0; conf = fopen(config_path, "r"); if (conf == NULL) { /* Don't treat a non-existing config file as error */ if (errno == ENOENT) return; - errlog(1, "can not open config `%s'", config_path); + errlog(EX_NOINPUT, "can not open config `%s'", config_path); /* NOTREACHED */ } while (!feof(conf)) { if (fgets(line, sizeof(line), conf) == NULL) break; lineno++; chomp(line); /* We hit a comment */ if (strchr(line, '#')) *strchr(line, '#') = 0; data = line; word = strsep(&data, EQS); /* Ignore empty lines */ if (word == NULL || *word == 0) continue; if (data != NULL && *data != 0) data = strdup(data); else data = NULL; if (strcmp(word, "SMARTHOST") == 0 && data != NULL) config.smarthost = data; else if (strcmp(word, "PORT") == 0 && data != NULL) config.port = atoi(data); else if (strcmp(word, "ALIASES") == 0 && data != NULL) config.aliases = data; else if (strcmp(word, "SPOOLDIR") == 0 && data != NULL) config.spooldir = data; else if (strcmp(word, "AUTHPATH") == 0 && data != NULL) config.authpath= data; else if (strcmp(word, "CERTFILE") == 0 && data != NULL) config.certfile = data; else if (strcmp(word, "MAILNAME") == 0 && data != NULL) config.mailname = data; else if (strcmp(word, "MASQUERADE") == 0 && data != NULL) { char *user = NULL, *host = NULL; if (strrchr(data, '@')) { host = strrchr(data, '@'); *host = 0; host++; user = data; } else { host = data; } - if (host && *host == 0) + if (host && *host == 0) host = NULL; if (user && *user == 0) user = NULL; config.masquerade_host = host; config.masquerade_user = user; } else if (strcmp(word, "STARTTLS") == 0 && data == NULL) config.features |= STARTTLS; else if (strcmp(word, "OPPORTUNISTIC_TLS") == 0 && data == NULL) config.features |= TLS_OPP; else if (strcmp(word, "SECURETRANSFER") == 0 && data == NULL) config.features |= SECURETRANS; else if (strcmp(word, "DEFER") == 0 && data == NULL) config.features |= DEFER; else if (strcmp(word, "INSECURE") == 0 && data == NULL) config.features |= INSECURE; else if (strcmp(word, "FULLBOUNCE") == 0 && data == NULL) config.features |= FULLBOUNCE; else if (strcmp(word, "NULLCLIENT") == 0 && data == NULL) config.features |= NULLCLIENT; else { - errlogx(1, "syntax error in %s:%d", config_path, lineno); + errlogx(EX_CONFIG, "syntax error in %s:%d", config_path, lineno); /* NOTREACHED */ } } if ((config.features & NULLCLIENT) && config.smarthost == NULL) { - errlogx(1, "%s: NULLCLIENT requires SMARTHOST", config_path); + errlogx(EX_CONFIG, "%s: NULLCLIENT requires SMARTHOST", config_path); /* NOTREACHED */ } fclose(conf); } Index: head/contrib/dma/dma-mbox-create.c =================================================================== --- head/contrib/dma/dma-mbox-create.c (revision 289122) +++ head/contrib/dma/dma-mbox-create.c (revision 289123) @@ -1,160 +1,160 @@ /* - * Copyright (c) 2010 Simon Schubert <2@0x2c.org> + * Copyright (c) 2010-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project - * by Simon 'corecode' Schubert . + * by Simon Schubert <2@0x2c.org>. * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ /* * This binary is setuid root. Use extreme caution when touching * user-supplied information. Keep the root window as small as possible. */ #include #include #include #include #include #include #include #include #include #include #include "dma.h" static void -logfail(const char *fmt, ...) +logfail(int exitcode, const char *fmt, ...) { int oerrno = errno; va_list ap; char outs[1024]; outs[0] = 0; if (fmt != NULL) { va_start(ap, fmt); vsnprintf(outs, sizeof(outs), fmt, ap); va_end(ap); } errno = oerrno; if (*outs != 0) syslog(LOG_ERR, errno ? "%s: %m" : "%s", outs); else syslog(LOG_ERR, errno ? "%m" : "unknown error"); - exit(1); + exit(exitcode); } /* * Create a mbox in /var/mail for a given user, or make sure * the permissions are correct for dma. */ int main(int argc, char **argv) { const char *user; struct passwd *pw; struct group *gr; uid_t user_uid; gid_t mail_gid; int error; char fn[PATH_MAX+1]; int f; openlog("dma-mbox-create", 0, LOG_MAIL); errno = 0; gr = getgrnam(DMA_GROUP); if (!gr) - logfail("cannot find dma group `%s'", DMA_GROUP); + logfail(EX_CONFIG, "cannot find dma group `%s'", DMA_GROUP); mail_gid = gr->gr_gid; if (setgid(mail_gid) != 0) - logfail("cannot set gid to %d (%s)", mail_gid, DMA_GROUP); + logfail(EX_NOPERM, "cannot set gid to %d (%s)", mail_gid, DMA_GROUP); if (getegid() != mail_gid) - logfail("cannot set gid to %d (%s), still at %d", mail_gid, DMA_GROUP, getegid()); + logfail(EX_NOPERM, "cannot set gid to %d (%s), still at %d", mail_gid, DMA_GROUP, getegid()); /* * We take exactly one argument: the username. */ if (argc != 2) { errno = 0; - logfail("no arguments"); + logfail(EX_USAGE, "no arguments"); } user = argv[1]; syslog(LOG_NOTICE, "creating mbox for `%s'", user); /* the username may not contain a pathname separator */ if (strchr(user, '/')) { errno = 0; - logfail("path separator in username `%s'", user); + logfail(EX_DATAERR, "path separator in username `%s'", user); exit(1); } /* verify the user exists */ errno = 0; pw = getpwnam(user); if (!pw) - logfail("cannot find user `%s'", user); + logfail(EX_NOUSER, "cannot find user `%s'", user); user_uid = pw->pw_uid; error = snprintf(fn, sizeof(fn), "%s/%s", _PATH_MAILDIR, user); if (error < 0 || (size_t)error >= sizeof(fn)) { if (error >= 0) { errno = 0; - logfail("mbox path too long"); + logfail(EX_USAGE, "mbox path too long"); } - logfail("cannot build mbox path for `%s/%s'", _PATH_MAILDIR, user); + logfail(EX_CANTCREAT, "cannot build mbox path for `%s/%s'", _PATH_MAILDIR, user); } f = open(fn, O_RDONLY|O_CREAT, 0600); if (f < 0) - logfail("cannot open mbox `%s'", fn); + logfail(EX_NOINPUT, "cannt open mbox `%s'", fn); if (fchown(f, user_uid, mail_gid)) - logfail("cannot change owner of mbox `%s'", fn); + logfail(EX_OSERR, "cannot change owner of mbox `%s'", fn); if (fchmod(f, 0620)) - logfail("cannot change permissions of mbox `%s'", fn); + logfail(EX_OSERR, "cannot change permissions of mbox `%s'", fn); /* file should be present with the right owner and permissions */ syslog(LOG_NOTICE, "successfully created mbox for `%s'", user); return (0); } Index: head/contrib/dma/dma.8 =================================================================== --- head/contrib/dma/dma.8 (revision 289122) +++ head/contrib/dma/dma.8 (revision 289123) @@ -1,363 +1,364 @@ .\" +.\" Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. .\" Copyright (c) 2008 .\" The DragonFly Project. 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. .\" 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 .\" COPYRIGHT HOLDERS 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. .\" .Dd February 13, 2014 .Dt DMA 8 .Os .Sh NAME .Nm dma .Nd DragonFly Mail Agent .Sh SYNOPSIS .Nm .Op Fl DiOt .Op Fl A Ns Ar mode .Op Fl b Ns Ar mode .Op Fl f Ar sender .Op Fl L Ar tag .Op Fl o Ns Ar option .Op Fl r Ar sender .Op Fl q Ns Op Ar arg .Op Ar recipient ... .Sh DESCRIPTION .Nm is a small Mail Transport Agent (MTA), designed for home and office use. It accepts mails from locally installed Mail User Agents (MUA) and delivers the mails either locally or to a remote destination. Remote delivery includes several features like TLS/SSL support and SMTP authentication. .Pp .Nm is not intended as a replacement for real, big MTAs like .Xr sendmail 8 or .Xr postfix 1 . Consequently, .Nm does not listen on port 25 for incoming connections. .Pp The options are as follows: .Bl -tag -width indent .It Fl A Ns Ar mode .Fl \&Ac acts as a compatibility option for sendmail. .It Fl b Ns Ar mode .Bl -tag -width indent .It Fl bp List all mails currently stored in the mail queue. .It Fl bq Queue the mail, but don't attempt to deliver it. See also the .Sq DEFER config file setting below. .El .Pp All other .Ar mode Ns s are are ignored. .It Fl D Don't run in the background. Useful for debugging. .It Fl f Ar sender Set sender address (envelope-from) to .Ar sender . This overrides the value of the environment variable .Ev EMAIL . .It Fl i Ignore dots alone on lines by themselves in incoming messages. This should be set if you are reading data from a file. .It Fl L Ar tag Set the identifier used in syslog messages to the supplied .Ar tag . This is a compatibility option for sendmail. .It Fl O This is a compatibility option for sendmail. .It Fl o Ns Ar option Specifying .Fl oi is synonymous to .Fl i . All other options are ignored. .It Fl q Ns Op Ar arg Process saved messages in the queue. The argument is optional and ignored. .It Fl r Ar sender Same as .Fl f . .It Fl t Obtain recipient addresses from the message header. .Nm will parse the .Li To: , .Li Cc: , and .Li Bcc: headers. The .Li Bcc: header will be removed independent of whether .Fl t is specified or not. .El .Sh CONFIGURATION .Nm can be configured with two config files: .Pp .Bl -bullet -compact .It auth.conf .It dma.conf .El .Pp These two files are stored per default in .Pa /etc/dma . .Sh FILE FORMAT Every file contains parameters of the form .Sq name value . Lines containing boolean values are set to .Sq NO if the line is commented and to .Sq YES if the line is uncommented. Empty lines or lines beginning with a .Sq # are ignored. Parameter names and their values are case sensitive. .Sh PARAMETERS .Ss auth.conf SMTP authentication can be configured in .Pa auth.conf . Each line has the format .Dq Li user|smarthost:password . .Ss dma.conf Most of the behaviour of .Nm can be configured in .Pa dma.conf . .Bl -tag -width 4n .It Ic SMARTHOST Xo (string, default=empty) .Xc If you want to send outgoing mails via a smarthost, set this variable to your smarthosts address. .It Ic PORT Xo (numeric, default=25) .Xc Use this port to deliver remote emails. Only useful together with the .Sq SMARTHOST option, because .Nm will deliver all mails to this port, regardless of whether a smarthost is set or not. .It Ic ALIASES Xo (string, default=/etc/aliases) .Xc Path to the local aliases file. Just stick with the default. The aliases file is of the format .Dl nam: dest1 dest2 ... In this case, mails to .Li nam will instead be delivered to .Li dest1 and .Li dest2 , which in turn could be entries in .Pa /etc/aliases . The special name .Ql * can be used to create a catch-all alias, which gets used if no other matching alias is found. Use the catch-all alias only if you don't want any local mail to be delivered. .It Ic SPOOLDIR Xo (string, default=/var/spool/dma) .Xc Path to .Nm Ap s spool directory. Just stick with the default. .It Ic AUTHPATH Xo (string, default=not set) .Xc Path to the .Sq auth.conf file. .It Ic SECURETRANS Xo (boolean, default=commented) .Xc Uncomment if you want TLS/SSL secured transfer. .It Ic STARTTLS Xo (boolean, default=commented) .Xc Uncomment if you want to use STARTTLS. Only useful together with .Sq SECURETRANS . .It Ic OPPORTUNISTIC_TLS Xo (boolean, default=commented) .Xc Uncomment if you want to allow the STARTTLS negotiation to fail. Most useful when .Nm is used without a smarthost, delivering remote messages directly to the outside mail exchangers; in opportunistic TLS mode, the connection will be encrypted if the remote server supports STARTTLS, but an unencrypted delivery will still be made if the negotiation fails. Only useful together with .Sq SECURETRANS and .Sq STARTTLS . .It Ic CERTFILE Xo (string, default=empty) .Xc Path to your SSL certificate file. .It Ic SECURE Xo (boolean, default=commented) .Xc Uncomment this entry and change it to .Sq INSECURE to use plain text SMTP login over an insecure connection. You have to rename this variable manually to prevent that you send your password accidentally over an insecure connection. .It Ic DEFER Xo (boolean, default=commented) .Xc Uncomment if you want that .Nm defers your mail. You have to flush your mail queue manually with the .Fl q option. This option is handy if you are behind a dialup line. .It Ic FULLBOUNCE Xo (boolean, default=commented) .Xc Uncomment if you want the bounce message to include the complete original message, not just the headers. .It Ic MAILNAME Xo (string, default=empty) .Xc The internet hostname .Nm uses to identify the host. If not set or empty, the result of .Xr gethostname 3 is used. If .Sq MAILNAME is an absolute path to a file, the first line of this file will be used as the hostname. .It Ic MASQUERADE Xo (string, default=empty) .Xc Masquerade the envelope-from addresses with this address/hostname. Use this setting if mails are not accepted by destination mail servers because your sender domain is invalid. This setting is overridden by the .Fl f flag and the .Ev EMAIL environment variable. .Pp If .Sq MASQUERADE does not contain a .Li @ sign, the string is interpreted as a host name. For example, setting .Sq MASQUERADE to .Ql john@ on host .Ql hamlet will send all mails as .Ql john@hamlet ; setting it to .Ql percolator will send all mails as .Ql Sm off Va username @percolator . .Sm on .It Ic NULLCLIENT Xo .Xc Bypass aliases and local delivery, and instead forward all mails to the defined .Sq SMARTHOST . .Sq NULLCLIENT requires .Sq SMARTHOST to be set. .El .Ss Environment variables The behavior of .Nm can be influenced by some environment variables. .Bl -tag -width 4n .It Ev EMAIL Xo .Xc Used to set the sender address (envelope-from). Use a plain address, in the form of .Li user@example.com . This value will be overridden when the .Fl f flag is used. .El .Sh SEE ALSO .Xr mailaddr 7 , .Xr mailwrapper 8 , .Xr sendmail 8 .Rs .%A "J. B. Postel" .%T "Simple Mail Transfer Protocol" .%O RFC 821 .Re .Rs .%A "J. Myers" .%T "SMTP Service Extension for Authentication" .%O RFC 2554 .Re .Rs .%A "P. Hoffman" .%T "SMTP Service Extension for Secure SMTP over TLS" .%O RFC 2487 .Re .Sh HISTORY The .Nm utility first appeared in .Dx 1.11 . .Sh AUTHORS .An -nosplit .Nm was written by .An Matthias Schmidt Aq Mt matthias@dragonflybsd.org and .An Simon Schubert Aq Mt 2@0x2c.org . Index: head/contrib/dma/dma.c =================================================================== --- head/contrib/dma/dma.c (revision 289122) +++ head/contrib/dma/dma.c (revision 289123) @@ -1,631 +1,632 @@ /* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project - * by Simon 'corecode' Schubert . + * by Simon Schubert <2@0x2c.org>. * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ #include "dfcompat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dma.h" static void deliver(struct qitem *); struct aliases aliases = LIST_HEAD_INITIALIZER(aliases); struct strlist tmpfs = SLIST_HEAD_INITIALIZER(tmpfs); struct authusers authusers = LIST_HEAD_INITIALIZER(authusers); char username[USERNAME_SIZE]; uid_t useruid; const char *logident_base; char errmsg[ERRMSG_SIZE]; static int daemonize = 1; static int doqueue = 0; struct config config = { .smarthost = NULL, .port = 25, .aliases = "/etc/aliases", .spooldir = "/var/spool/dma", .authpath = NULL, .certfile = NULL, .features = 0, .mailname = NULL, .masquerade_host = NULL, .masquerade_user = NULL, }; static void sighup_handler(int signo) { (void)signo; /* so that gcc doesn't complain */ } static char * set_from(struct queue *queue, const char *osender) { const char *addr; char *sender; if (osender) { addr = osender; } else if (getenv("EMAIL") != NULL) { addr = getenv("EMAIL"); } else { if (config.masquerade_user) addr = config.masquerade_user; else addr = username; } if (!strchr(addr, '@')) { const char *from_host = hostname(); if (config.masquerade_host) from_host = config.masquerade_host; if (asprintf(&sender, "%s@%s", addr, from_host) <= 0) return (NULL); } else { sender = strdup(addr); if (sender == NULL) return (NULL); } if (strchr(sender, '\n') != NULL) { errno = EINVAL; return (NULL); } queue->sender = sender; return (sender); } static int read_aliases(void) { yyin = fopen(config.aliases, "r"); if (yyin == NULL) { /* * Non-existing aliases file is not a fatal error */ if (errno == ENOENT) return (0); /* Other problems are. */ return (-1); } if (yyparse()) return (-1); /* fatal error, probably malloc() */ fclose(yyin); return (0); } static int do_alias(struct queue *queue, const char *addr) { struct alias *al; struct stritem *sit; int aliased = 0; LIST_FOREACH(al, &aliases, next) { if (strcmp(al->alias, addr) != 0) continue; SLIST_FOREACH(sit, &al->dests, next) { if (add_recp(queue, sit->str, EXPAND_ADDR) != 0) return (-1); } aliased = 1; } return (aliased); } int add_recp(struct queue *queue, const char *str, int expand) { struct qitem *it, *tit; struct passwd *pw; char *host; int aliased = 0; it = calloc(1, sizeof(*it)); if (it == NULL) return (-1); it->addr = strdup(str); if (it->addr == NULL) return (-1); it->sender = queue->sender; host = strrchr(it->addr, '@'); if (host != NULL && (strcmp(host + 1, hostname()) == 0 || strcmp(host + 1, "localhost") == 0)) { *host = 0; } LIST_FOREACH(tit, &queue->queue, next) { /* weed out duplicate dests */ if (strcmp(tit->addr, it->addr) == 0) { free(it->addr); free(it); return (0); } } LIST_INSERT_HEAD(&queue->queue, it, next); /** * Do local delivery if there is no @. * Do not do local delivery when NULLCLIENT is set. */ if (strrchr(it->addr, '@') == NULL && (config.features & NULLCLIENT) == 0) { it->remote = 0; if (expand) { aliased = do_alias(queue, it->addr); if (!aliased && expand == EXPAND_WILDCARD) aliased = do_alias(queue, "*"); if (aliased < 0) return (-1); if (aliased) { LIST_REMOVE(it, next); } else { /* Local destination, check */ pw = getpwnam(it->addr); if (pw == NULL) goto out; /* XXX read .forward */ endpwent(); } } } else { it->remote = 1; } return (0); out: free(it->addr); free(it); return (-1); } static struct qitem * go_background(struct queue *queue) { struct sigaction sa; struct qitem *it; pid_t pid; if (daemonize && daemon(0, 0) != 0) { syslog(LOG_ERR, "can not daemonize: %m"); - exit(1); + exit(EX_OSERR); } daemonize = 0; bzero(&sa, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); LIST_FOREACH(it, &queue->queue, next) { /* No need to fork for the last dest */ if (LIST_NEXT(it, next) == NULL) goto retit; pid = fork(); switch (pid) { case -1: syslog(LOG_ERR, "can not fork: %m"); - exit(1); + exit(EX_OSERR); break; case 0: /* * Child: * * return and deliver mail */ retit: /* * If necessary, acquire the queue and * mail files. * If this fails, we probably were raced by another * process. It is okay to be raced if we're supposed * to flush the queue. */ setlogident("%s", it->queueid); switch (acquirespool(it)) { case 0: break; case 1: if (doqueue) - exit(0); + exit(EX_OK); syslog(LOG_WARNING, "could not lock queue file"); - exit(1); + exit(EX_SOFTWARE); default: - exit(1); + exit(EX_SOFTWARE); } dropspool(queue, it); return (it); default: /* * Parent: * * fork next child */ break; } } syslog(LOG_CRIT, "reached dead code"); - exit(1); + exit(EX_SOFTWARE); } static void deliver(struct qitem *it) { int error; unsigned int backoff = MIN_RETRY, slept; struct timeval now; struct stat st; snprintf(errmsg, sizeof(errmsg), "unknown bounce reason"); retry: syslog(LOG_INFO, "trying delivery"); if (it->remote) error = deliver_remote(it); else error = deliver_local(it); switch (error) { case 0: delqueue(it); syslog(LOG_INFO, "delivery successful"); - exit(0); + exit(EX_OK); case 1: if (stat(it->queuefn, &st) != 0) { syslog(LOG_ERR, "lost queue file `%s'", it->queuefn); - exit(1); + exit(EX_SOFTWARE); } if (gettimeofday(&now, NULL) == 0 && (now.tv_sec - st.st_mtim.tv_sec > MAX_TIMEOUT)) { snprintf(errmsg, sizeof(errmsg), "Could not deliver for the last %d seconds. Giving up.", MAX_TIMEOUT); goto bounce; } for (slept = 0; slept < backoff;) { slept += SLEEP_TIMEOUT - sleep(SLEEP_TIMEOUT); if (flushqueue_since(slept)) { backoff = MIN_RETRY; goto retry; } } if (slept >= backoff) { /* pick the next backoff between [1.5, 2.5) times backoff */ backoff = backoff + backoff / 2 + random() % backoff; if (backoff > MAX_RETRY) backoff = MAX_RETRY; } goto retry; case -1: default: break; } bounce: bounce(it, errmsg); /* NOTREACHED */ } void run_queue(struct queue *queue) { struct qitem *it; if (LIST_EMPTY(&queue->queue)) return; it = go_background(queue); deliver(it); /* NOTREACHED */ } static void show_queue(struct queue *queue) { struct qitem *it; int locked = 0; /* XXX */ if (LIST_EMPTY(&queue->queue)) { printf("Mail queue is empty\n"); return; } LIST_FOREACH(it, &queue->queue, next) { printf("ID\t: %s%s\n" "From\t: %s\n" "To\t: %s\n", it->queueid, locked ? "*" : "", it->sender, it->addr); if (LIST_NEXT(it, next) != NULL) printf("--\n"); } } /* * TODO: * * - alias processing * - use group permissions * - proper sysexit codes */ int main(int argc, char **argv) { struct sigaction act; char *sender = NULL; struct queue queue; int i, ch; int nodot = 0, showq = 0, queue_only = 0; int recp_from_header = 0; set_username(); /* * We never run as root. If called by root, drop permissions * to the mail user. */ if (geteuid() == 0 || getuid() == 0) { struct passwd *pw; errno = 0; pw = getpwnam(DMA_ROOT_USER); if (pw == NULL) { if (errno == 0) - errx(1, "user '%s' not found", DMA_ROOT_USER); + errx(EX_CONFIG, "user '%s' not found", DMA_ROOT_USER); else - err(1, "cannot drop root privileges"); + err(EX_OSERR, "cannot drop root privileges"); } if (setuid(pw->pw_uid) != 0) - err(1, "cannot drop root privileges"); + err(EX_OSERR, "cannot drop root privileges"); if (geteuid() == 0 || getuid() == 0) - errx(1, "cannot drop root privileges"); + errx(EX_OSERR, "cannot drop root privileges"); } atexit(deltmp); init_random(); bzero(&queue, sizeof(queue)); LIST_INIT(&queue.queue); if (strcmp(argv[0], "mailq") == 0) { argv++; argc--; showq = 1; if (argc != 0) - errx(1, "invalid arguments"); + errx(EX_USAGE, "invalid arguments"); goto skipopts; } else if (strcmp(argv[0], "newaliases") == 0) { logident_base = "dma"; setlogident("%s", logident_base); if (read_aliases() != 0) - errx(1, "could not parse aliases file `%s'", config.aliases); - exit(0); + errx(EX_SOFTWARE, "could not parse aliases file `%s'", config.aliases); + exit(EX_OK); } opterr = 0; while ((ch = getopt(argc, argv, ":A:b:B:C:d:Df:F:h:iL:N:no:O:q:r:R:tUV:vX:")) != -1) { switch (ch) { case 'A': /* -AX is being ignored, except for -A{c,m} */ if (optarg[0] == 'c' || optarg[0] == 'm') { break; } /* else FALLTRHOUGH */ case 'b': /* -bX is being ignored, except for -bp */ if (optarg[0] == 'p') { showq = 1; break; } else if (optarg[0] == 'q') { queue_only = 1; break; } /* else FALLTRHOUGH */ case 'D': daemonize = 0; break; case 'L': logident_base = optarg; break; case 'f': case 'r': sender = optarg; break; case 't': recp_from_header = 1; break; case 'o': /* -oX is being ignored, except for -oi */ if (optarg[0] != 'i') break; /* else FALLTRHOUGH */ case 'O': break; case 'i': nodot = 1; break; case 'q': /* Don't let getopt slup up other arguments */ if (optarg && *optarg == '-') optind--; doqueue = 1; break; /* Ignored options */ case 'B': case 'C': case 'd': case 'F': case 'h': case 'N': case 'n': case 'R': case 'U': case 'V': case 'v': case 'X': break; case ':': if (optopt == 'q') { doqueue = 1; break; } /* FALLTHROUGH */ default: fprintf(stderr, "invalid argument: `-%c'\n", optopt); - exit(1); + exit(EX_USAGE); } } argc -= optind; argv += optind; opterr = 1; if (argc != 0 && (showq || doqueue)) - errx(1, "sending mail and queue operations are mutually exclusive"); + errx(EX_USAGE, "sending mail and queue operations are mutually exclusive"); if (showq + doqueue > 1) - errx(1, "conflicting queue operations"); + errx(EX_USAGE, "conflicting queue operations"); skipopts: if (logident_base == NULL) logident_base = "dma"; setlogident("%s", logident_base); act.sa_handler = sighup_handler; act.sa_flags = 0; sigemptyset(&act.sa_mask); if (sigaction(SIGHUP, &act, NULL) != 0) syslog(LOG_WARNING, "can not set signal handler: %m"); parse_conf(CONF_PATH "/dma.conf"); if (config.authpath != NULL) parse_authfile(config.authpath); if (showq) { if (load_queue(&queue) < 0) - errlog(1, "can not load queue"); + errlog(EX_NOINPUT, "can not load queue"); show_queue(&queue); return (0); } if (doqueue) { flushqueue_signal(); if (load_queue(&queue) < 0) - errlog(1, "can not load queue"); + errlog(EX_NOINPUT, "can not load queue"); run_queue(&queue); return (0); } if (read_aliases() != 0) - errlog(1, "could not parse aliases file `%s'", config.aliases); + errlog(EX_SOFTWARE, "could not parse aliases file `%s'", config.aliases); if ((sender = set_from(&queue, sender)) == NULL) - errlog(1, "set_from failed"); + errlog(EX_SOFTWARE, NULL); if (newspoolf(&queue) != 0) - errlog(1, "can not create temp file in `%s'", config.spooldir); + errlog(EX_CANTCREAT, "can not create temp file in `%s'", config.spooldir); setlogident("%s", queue.id); for (i = 0; i < argc; i++) { if (add_recp(&queue, argv[i], EXPAND_WILDCARD) != 0) - errlogx(1, "invalid recipient `%s'", argv[i]); + errlogx(EX_DATAERR, "invalid recipient `%s'", argv[i]); } if (LIST_EMPTY(&queue.queue) && !recp_from_header) - errlogx(1, "no recipients"); + errlogx(EX_NOINPUT, "no recipients"); if (readmail(&queue, nodot, recp_from_header) != 0) - errlog(1, "can not read mail"); + errlog(EX_NOINPUT, "can not read mail"); if (LIST_EMPTY(&queue.queue)) - errlogx(1, "no recipients"); + errlogx(EX_NOINPUT, "no recipients"); if (linkspool(&queue) != 0) - errlog(1, "can not create spools"); + errlog(EX_CANTCREAT, "can not create spools"); /* From here on the mail is safe. */ if (config.features & DEFER || queue_only) return (0); run_queue(&queue); /* NOTREACHED */ return (0); } Index: head/contrib/dma/dma.h =================================================================== --- head/contrib/dma/dma.h (revision 289122) +++ head/contrib/dma/dma.h (revision 289123) @@ -1,237 +1,241 @@ /* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project - * by Simon 'corecode' Schubert and + * by Simon Schubert <2@0x2c.org> and * Matthias Schmidt . * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ #ifndef DMA_H #define DMA_H #include #include #include #include #include #include #include +#include #define VERSION "DragonFly Mail Agent " DMA_VERSION #define BUF_SIZE 2048 #define ERRMSG_SIZE 200 #define USERNAME_SIZE 50 #define MIN_RETRY 300 /* 5 minutes */ #define MAX_RETRY (3*60*60) /* retry at least every 3 hours */ #define MAX_TIMEOUT (5*24*60*60) /* give up after 5 days */ #define SLEEP_TIMEOUT 30 /* check for queue flush every 30 seconds */ #ifndef PATH_MAX #define PATH_MAX 1024 /* Max path len */ #endif #define SMTP_PORT 25 /* Default SMTP port */ #define CON_TIMEOUT (5*60) /* Connection timeout per RFC5321 */ #define STARTTLS 0x002 /* StartTLS support */ #define SECURETRANS 0x004 /* SSL/TLS in general */ #define NOSSL 0x008 /* Do not use SSL */ #define DEFER 0x010 /* Defer mails */ #define INSECURE 0x020 /* Allow plain login w/o encryption */ #define FULLBOUNCE 0x040 /* Bounce the full message */ #define TLS_OPP 0x080 /* Opportunistic STARTTLS */ #define NULLCLIENT 0x100 /* Nullclient support */ #ifndef CONF_PATH #error Please define CONF_PATH #endif #ifndef LIBEXEC_PATH #error Please define LIBEXEC_PATH #endif #define SPOOL_FLUSHFILE "flush" #ifndef DMA_ROOT_USER #define DMA_ROOT_USER "mail" #endif #ifndef DMA_GROUP #define DMA_GROUP "mail" #endif #ifndef MBOX_STRICT #define MBOX_STRICT 0 #endif struct stritem { SLIST_ENTRY(stritem) next; char *str; }; SLIST_HEAD(strlist, stritem); struct alias { LIST_ENTRY(alias) next; char *alias; struct strlist dests; }; LIST_HEAD(aliases, alias); struct qitem { LIST_ENTRY(qitem) next; const char *sender; char *addr; char *queuefn; char *mailfn; char *queueid; FILE *queuef; FILE *mailf; int remote; }; LIST_HEAD(queueh, qitem); struct queue { struct queueh queue; char *id; FILE *mailf; char *tmpf; const char *sender; }; struct config { const char *smarthost; int port; const char *aliases; const char *spooldir; const char *authpath; const char *certfile; int features; const char *mailname; const char *masquerade_host; const char *masquerade_user; /* XXX does not belong into config */ SSL *ssl; }; struct authuser { SLIST_ENTRY(authuser) next; char *login; char *password; char *host; }; SLIST_HEAD(authusers, authuser); struct mx_hostentry { char host[MAXDNAME]; char addr[INET6_ADDRSTRLEN]; int pref; struct addrinfo ai; struct sockaddr_storage sa; }; /* global variables */ extern struct aliases aliases; extern struct config config; extern struct strlist tmpfs; extern struct authusers authusers; extern char username[USERNAME_SIZE]; extern uid_t useruid; extern const char *logident_base; extern char neterr[ERRMSG_SIZE]; extern char errmsg[ERRMSG_SIZE]; /* aliases_parse.y */ int yyparse(void); +int yywrap(void); +int yylex(void); extern FILE *yyin; /* conf.c */ void trim_line(char *); void parse_conf(const char *); void parse_authfile(const char *); /* crypto.c */ void hmac_md5(unsigned char *, int, unsigned char *, int, unsigned char *); int smtp_auth_md5(int, char *, char *); int smtp_init_crypto(int, int); /* dns.c */ int dns_get_mx_list(const char *, int, struct mx_hostentry **, int); /* net.c */ char *ssl_errstr(void); int read_remote(int, int, char *); ssize_t send_remote_command(int, const char*, ...) __attribute__((__nonnull__(2), __format__ (__printf__, 2, 3))); int deliver_remote(struct qitem *); /* base64.c */ int base64_encode(const void *, int, char **); int base64_decode(const char *, void *); /* dma.c */ #define EXPAND_ADDR 1 #define EXPAND_WILDCARD 2 int add_recp(struct queue *, const char *, int); void run_queue(struct queue *); /* spool.c */ int newspoolf(struct queue *); int linkspool(struct queue *); int load_queue(struct queue *); void delqueue(struct qitem *); int acquirespool(struct qitem *); void dropspool(struct queue *, struct qitem *); int flushqueue_since(unsigned int); int flushqueue_signal(void); /* local.c */ int deliver_local(struct qitem *); /* mail.c */ void bounce(struct qitem *, const char *); int readmail(struct queue *, int, int); /* util.c */ const char *hostname(void); void setlogident(const char *, ...) __attribute__((__format__ (__printf__, 1, 2))); void errlog(int, const char *, ...) __attribute__((__format__ (__printf__, 2, 3))); void errlogx(int, const char *, ...) __attribute__((__format__ (__printf__, 2, 3))); void set_username(void); void deltmp(void); int do_timeout(int, int); int open_locked(const char *, int, ...); char *rfc822date(void); int strprefixcmp(const char *, const char *); void init_random(void); #endif Index: head/contrib/dma/dns.c =================================================================== --- head/contrib/dma/dns.c (revision 289122) +++ head/contrib/dma/dns.c (revision 289123) @@ -1,280 +1,297 @@ /* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project - * by Simon 'corecode' Schubert + * by Simon Schubert <2@0x2c.org>. * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ #include #include #include #include #include #include #include #include #include #include "dma.h" static int sort_pref(const void *a, const void *b) { const struct mx_hostentry *ha = a, *hb = b; int v; /* sort increasing by preference primarily */ v = ha->pref - hb->pref; if (v != 0) return (v); /* sort PF_INET6 before PF_INET */ v = - (ha->ai.ai_family - hb->ai.ai_family); return (v); } static int add_host(int pref, const char *host, int port, struct mx_hostentry **he, size_t *ps) { struct addrinfo hints, *res, *res0 = NULL; char servname[10]; struct mx_hostentry *p; const int count_inc = 10; - int err; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; snprintf(servname, sizeof(servname), "%d", port); - err = getaddrinfo(host, servname, &hints, &res0); - if (err) - return (err == EAI_AGAIN ? 1 : -1); + switch (getaddrinfo(host, servname, &hints, &res0)) { + case 0: + break; + case EAI_AGAIN: + case EAI_NONAME: + /* + * EAI_NONAME gets returned for: + * SMARTHOST set but DNS server not reachable -> defer + * SMARTHOST set but DNS server returns "host does not exist" + * -> buggy configuration + * -> either defer or bounce would be ok -> defer + * MX entry was returned by DNS server but name doesn't resolve + * -> hopefully transient situation -> defer + * all other DNS problems should have been caught earlier + * in dns_get_mx_list(). + */ + goto out; + default: + return(-1); + } for (res = res0; res != NULL; res = res->ai_next) { if (*ps + 1 >= roundup(*ps, count_inc)) { size_t newsz = roundup(*ps + 2, count_inc); *he = reallocf(*he, newsz * sizeof(**he)); if (*he == NULL) goto out; } p = &(*he)[*ps]; strlcpy(p->host, host, sizeof(p->host)); p->pref = pref; p->ai = *res; p->ai.ai_addr = NULL; bcopy(res->ai_addr, &p->sa, p->ai.ai_addrlen); getnameinfo((struct sockaddr *)&p->sa, p->ai.ai_addrlen, p->addr, sizeof(p->addr), NULL, 0, NI_NUMERICHOST); (*ps)++; } freeaddrinfo(res0); return (0); out: if (res0 != NULL) freeaddrinfo(res0); return (1); } int dns_get_mx_list(const char *host, int port, struct mx_hostentry **he, int no_mx) { char outname[MAXDNAME]; ns_msg msg; ns_rr rr; const char *searchhost; const unsigned char *cp; unsigned char *ans; struct mx_hostentry *hosts = NULL; size_t nhosts = 0; size_t anssz; int pref; int cname_recurse; int have_mx = 0; int err; int i; res_init(); searchhost = host; cname_recurse = 0; anssz = 65536; ans = malloc(anssz); if (ans == NULL) return (1); if (no_mx) goto out; repeat: err = res_search(searchhost, ns_c_in, ns_t_mx, ans, anssz); if (err < 0) { switch (h_errno) { case NO_DATA: /* * Host exists, but no MX (or CNAME) entry. * Not an error, use host name instead. */ goto out; case TRY_AGAIN: /* transient error */ goto transerr; case NO_RECOVERY: case HOST_NOT_FOUND: default: errno = ENOENT; goto err; } } if (!ns_initparse(ans, anssz, &msg)) goto transerr; switch (ns_msg_getflag(msg, ns_f_rcode)) { case ns_r_noerror: break; case ns_r_nxdomain: goto err; default: goto transerr; } for (i = 0; i < ns_msg_count(msg, ns_s_an); i++) { if (ns_parserr(&msg, ns_s_an, i, &rr)) goto transerr; cp = ns_rr_rdata(rr); switch (ns_rr_type(rr)) { case ns_t_mx: have_mx = 1; pref = ns_get16(cp); cp += 2; err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), cp, outname, sizeof(outname)); if (err < 0) goto transerr; err = add_host(pref, outname, port, &hosts, &nhosts); if (err == -1) goto err; break; case ns_t_cname: err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), cp, outname, sizeof(outname)); if (err < 0) goto transerr; /* Prevent a CNAME loop */ if (cname_recurse++ > 10) goto err; searchhost = outname; goto repeat; default: break; } } out: err = 0; if (0) { transerr: if (nhosts == 0) err = 1; } if (0) { err: err = -1; } free(ans); if (err == 0) { if (!have_mx) { /* * If we didn't find any MX, use the hostname instead. */ err = add_host(0, host, port, &hosts, &nhosts); } else if (nhosts == 0) { /* * We did get MX, but couldn't resolve any of them * due to transient errors. */ err = 1; } } if (nhosts > 0) { qsort(hosts, nhosts, sizeof(*hosts), sort_pref); /* terminate list */ *hosts[nhosts].host = 0; } else { if (hosts != NULL) free(hosts); hosts = NULL; } *he = hosts; return (err); free(ans); if (hosts != NULL) free(hosts); return (err); } #if defined(TESTING) int main(int argc, char **argv) { struct mx_hostentry *he, *p; int err; err = dns_get_mx_list(argv[1], 53, &he, 0); if (err) return (err); for (p = he; *p->host != 0; p++) { printf("%d\t%s\t%s\n", p->pref, p->host, p->addr); } return (0); } #endif Index: head/contrib/dma/get-version.sh =================================================================== --- head/contrib/dma/get-version.sh (revision 289122) +++ head/contrib/dma/get-version.sh (revision 289123) @@ -1,9 +1,11 @@ #!/bin/sh +tmp=$1 +file=${tmp:=VERSION} gitver=$(git describe 2>/dev/null | tr - .) -filever=$(cat VERSION) +filever=$(cat ${file} 2>/dev/null) version=${gitver} : ${version:=$filever} echo "$version" Index: head/contrib/dma/local.c =================================================================== --- head/contrib/dma/local.c (revision 289122) +++ head/contrib/dma/local.c (revision 289123) @@ -1,253 +1,254 @@ /* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project - * by Simon 'corecode' Schubert . + * by Simon Schubert <2@0x2c.org>. * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dma.h" static int create_mbox(const char *name) { struct sigaction sa, osa; pid_t child, waitchild; int status; int i; long maxfd; int e; int r = -1; /* * We need to enable SIGCHLD temporarily so that waitpid works. */ bzero(&sa, sizeof(sa)); sa.sa_handler = SIG_DFL; sigaction(SIGCHLD, &sa, &osa); do_timeout(100, 0); child = fork(); switch (child) { case 0: /* child */ maxfd = sysconf(_SC_OPEN_MAX); if (maxfd == -1) maxfd = 1024; /* what can we do... */ for (i = 3; i <= maxfd; ++i) close(i); execl(LIBEXEC_PATH "/dma-mbox-create", "dma-mbox-create", name, NULL); syslog(LOG_ERR, "cannot execute "LIBEXEC_PATH"/dma-mbox-create: %m"); - exit(1); + exit(EX_SOFTWARE); default: /* parent */ waitchild = waitpid(child, &status, 0); e = errno; do_timeout(0, 0); if (waitchild == -1 && e == EINTR) { syslog(LOG_ERR, "hung child while creating mbox `%s': %m", name); break; } if (waitchild == -1) { syslog(LOG_ERR, "child disappeared while creating mbox `%s': %m", name); break; } if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { syslog(LOG_ERR, "error creating mbox `%s'", name); break; } /* success */ r = 0; break; case -1: /* error */ syslog(LOG_ERR, "error creating mbox"); break; } sigaction(SIGCHLD, &osa, NULL); return (r); } int deliver_local(struct qitem *it) { char fn[PATH_MAX+1]; char line[1000]; const char *sender; const char *newline = "\n"; size_t linelen; int tries = 0; int mbox; int error; int hadnl = 0; off_t mboxlen; time_t now = time(NULL); error = snprintf(fn, sizeof(fn), "%s/%s", _PATH_MAILDIR, it->addr); if (error < 0 || (size_t)error >= sizeof(fn)) { syslog(LOG_NOTICE, "local delivery deferred: %m"); return (1); } retry: /* wait for a maximum of 100s to get the lock to the file */ do_timeout(100, 0); /* don't use O_CREAT here, because we might be running as the wrong user. */ mbox = open_locked(fn, O_WRONLY|O_APPEND); if (mbox < 0) { int e = errno; do_timeout(0, 0); switch (e) { case EACCES: case ENOENT: /* * The file does not exist or we can't access it. * Call dma-mbox-create to create it and fix permissions. */ if (tries > 0 || create_mbox(it->addr) != 0) { syslog(LOG_ERR, "local delivery deferred: can not create `%s'", fn); return (1); } ++tries; goto retry; case EINTR: syslog(LOG_NOTICE, "local delivery deferred: can not lock `%s'", fn); break; default: syslog(LOG_NOTICE, "local delivery deferred: can not open `%s': %m", fn); break; } return (1); } do_timeout(0, 0); mboxlen = lseek(mbox, 0, SEEK_END); /* New mails start with \nFrom ...., unless we're at the beginning of the mbox */ if (mboxlen == 0) newline = ""; /* If we're bouncing a message, claim it comes from MAILER-DAEMON */ sender = it->sender; if (strcmp(sender, "") == 0) sender = "MAILER-DAEMON"; if (fseek(it->mailf, 0, SEEK_SET) != 0) { syslog(LOG_NOTICE, "local delivery deferred: can not seek: %m"); goto out; } error = snprintf(line, sizeof(line), "%sFrom %s\t%s", newline, sender, ctime(&now)); if (error < 0 || (size_t)error >= sizeof(line)) { syslog(LOG_NOTICE, "local delivery deferred: can not write header: %m"); goto out; } if (write(mbox, line, error) != error) goto wrerror; while (!feof(it->mailf)) { if (fgets(line, sizeof(line), it->mailf) == NULL) break; linelen = strlen(line); if (linelen == 0 || line[linelen - 1] != '\n') { syslog(LOG_CRIT, "local delivery failed: corrupted queue file"); snprintf(errmsg, sizeof(errmsg), "corrupted queue file"); error = -1; goto chop; } /* * mboxro processing: * - escape lines that start with "From " with a > sign. * - be reversable by escaping lines that contain an arbitrary * number of > signs, followed by "From ", i.e. />*From / in regexp. * - strict mbox processing only requires escaping after empty lines, * yet most MUAs seem to relax this requirement and will treat any * line starting with "From " as the beginning of a new mail. */ if ((!MBOX_STRICT || hadnl) && strncmp(&line[strspn(line, ">")], "From ", 5) == 0) { const char *gt = ">"; if (write(mbox, gt, 1) != 1) goto wrerror; hadnl = 0; } else if (strcmp(line, "\n") == 0) { hadnl = 1; } else { hadnl = 0; } if ((size_t)write(mbox, line, linelen) != linelen) goto wrerror; } close(mbox); return (0); wrerror: syslog(LOG_ERR, "local delivery failed: write error: %m"); error = 1; chop: if (ftruncate(mbox, mboxlen) != 0) syslog(LOG_WARNING, "error recovering mbox `%s': %m", fn); out: close(mbox); return (error); } Index: head/contrib/dma/mail.c =================================================================== --- head/contrib/dma/mail.c (revision 289122) +++ head/contrib/dma/mail.c (revision 289123) @@ -1,457 +1,460 @@ /* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project - * by Simon 'corecode' Schubert . + * by Simon Schubert <2@0x2c.org>. * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ #include #include #include #include #include #include "dma.h" void bounce(struct qitem *it, const char *reason) { struct queue bounceq; char line[1000]; size_t pos; int error; /* Don't bounce bounced mails */ if (it->sender[0] == 0) { syslog(LOG_INFO, "can not bounce a bounce message, discarding"); - exit(1); + exit(EX_SOFTWARE); } bzero(&bounceq, sizeof(bounceq)); LIST_INIT(&bounceq.queue); bounceq.sender = ""; if (add_recp(&bounceq, it->sender, EXPAND_WILDCARD) != 0) goto fail; if (newspoolf(&bounceq) != 0) goto fail; syslog(LOG_ERR, "delivery failed, bouncing as %s", bounceq.id); setlogident("%s", bounceq.id); error = fprintf(bounceq.mailf, "Received: from MAILER-DAEMON\n" "\tid %s\n" "\tby %s (%s);\n" "\t%s\n" "X-Original-To: <%s>\n" "From: MAILER-DAEMON <>\n" "To: %s\n" "Subject: Mail delivery failed\n" "Message-Id: <%s@%s>\n" "Date: %s\n" "\n" "This is the %s at %s.\n" "\n" "There was an error delivering your mail to <%s>.\n" "\n" "%s\n" "\n" "%s\n" "\n", bounceq.id, hostname(), VERSION, rfc822date(), it->addr, it->sender, bounceq.id, hostname(), rfc822date(), VERSION, hostname(), it->addr, reason, config.features & FULLBOUNCE ? "Original message follows." : "Message headers follow."); if (error < 0) goto fail; if (fseek(it->mailf, 0, SEEK_SET) != 0) goto fail; if (config.features & FULLBOUNCE) { while ((pos = fread(line, 1, sizeof(line), it->mailf)) > 0) { if (fwrite(line, 1, pos, bounceq.mailf) != pos) goto fail; } } else { while (!feof(it->mailf)) { if (fgets(line, sizeof(line), it->mailf) == NULL) break; if (line[0] == '\n') break; if (fwrite(line, strlen(line), 1, bounceq.mailf) != 1) goto fail; } } if (linkspool(&bounceq) != 0) goto fail; /* bounce is safe */ delqueue(it); run_queue(&bounceq); /* NOTREACHED */ fail: syslog(LOG_CRIT, "error creating bounce: %m"); delqueue(it); - exit(1); + exit(EX_IOERR); } struct parse_state { char addr[1000]; int pos; enum { NONE = 0, START, MAIN, EOL, QUIT } state; int comment; int quote; int brackets; int esc; }; /* * Simplified RFC2822 header/address parsing. * We copy escapes and quoted strings directly, since * we have to pass them like this to the mail server anyways. * XXX local addresses will need treatment */ static int parse_addrs(struct parse_state *ps, char *s, struct queue *queue) { char *addr; again: switch (ps->state) { case NONE: return (-1); case START: /* init our data */ bzero(ps, sizeof(*ps)); /* skip over header name */ while (*s != ':') s++; s++; ps->state = MAIN; break; case MAIN: /* all fine */ break; case EOL: switch (*s) { case ' ': case '\t': s++; /* continue */ break; default: ps->state = QUIT; if (ps->pos != 0) goto newaddr; return (0); } case QUIT: return (0); } for (; *s != 0; s++) { if (ps->esc) { ps->esc = 0; switch (*s) { case '\r': case '\n': goto err; default: goto copy; } } if (ps->quote) { switch (*s) { case '"': ps->quote = 0; goto copy; case '\\': ps->esc = 1; goto copy; case '\r': case '\n': goto eol; default: goto copy; } } switch (*s) { case '(': ps->comment++; break; case ')': if (ps->comment) ps->comment--; else goto err; goto skip; case '"': ps->quote = 1; goto copy; case '\\': ps->esc = 1; goto copy; case '\r': case '\n': goto eol; } if (ps->comment) goto skip; switch (*s) { case ' ': case '\t': /* ignore whitespace */ goto skip; case '<': /* this is the real address now */ ps->brackets = 1; ps->pos = 0; goto skip; case '>': if (!ps->brackets) goto err; ps->brackets = 0; s++; goto newaddr; case ':': /* group - ignore */ ps->pos = 0; goto skip; case ',': case ';': /* * Next address, copy previous one. * However, we might be directly after * a
, or have two consecutive * commas. * Skip the comma unless there is * really something to copy. */ if (ps->pos == 0) goto skip; s++; goto newaddr; default: goto copy; } copy: if (ps->comment) goto skip; if (ps->pos + 1 == sizeof(ps->addr)) goto err; ps->addr[ps->pos++] = *s; skip: ; } eol: ps->state = EOL; return (0); err: ps->state = QUIT; return (-1); newaddr: ps->addr[ps->pos] = 0; ps->pos = 0; addr = strdup(ps->addr); if (addr == NULL) - errlog(1, "strdup failed"); + errlog(EX_SOFTWARE, NULL); if (add_recp(queue, addr, EXPAND_WILDCARD) != 0) - errlogx(1, "invalid recipient `%s'", addr); + errlogx(EX_DATAERR, "invalid recipient `%s'", addr); goto again; } int readmail(struct queue *queue, int nodot, int recp_from_header) { struct parse_state parse_state; char line[1000]; /* by RFC2822 */ size_t linelen; size_t error; int had_headers = 0; int had_from = 0; int had_messagid = 0; int had_date = 0; int had_last_line = 0; int nocopy = 0; parse_state.state = NONE; error = fprintf(queue->mailf, "Received: from %s (uid %d)\n" "\t(envelope-from %s)\n" "\tid %s\n" "\tby %s (%s);\n" "\t%s\n", username, useruid, queue->sender, queue->id, hostname(), VERSION, rfc822date()); if ((ssize_t)error < 0) return (-1); while (!feof(stdin)) { if (fgets(line, sizeof(line) - 1, stdin) == NULL) break; if (had_last_line) - errlogx(1, "bad mail input format"); + errlogx(EX_DATAERR, "bad mail input format:" + " from %s (uid %d) (envelope-from %s)", + username, useruid, queue->sender); linelen = strlen(line); if (linelen == 0 || line[linelen - 1] != '\n') { /* * This line did not end with a newline character. * If we fix it, it better be the last line of * the file. */ line[linelen] = '\n'; line[linelen + 1] = 0; had_last_line = 1; } if (!had_headers) { /* * Unless this is a continuation, switch of * the Bcc: nocopy flag. */ if (!(line[0] == ' ' || line[0] == '\t')) nocopy = 0; if (strprefixcmp(line, "Date:") == 0) had_date = 1; else if (strprefixcmp(line, "Message-Id:") == 0) had_messagid = 1; else if (strprefixcmp(line, "From:") == 0) had_from = 1; else if (strprefixcmp(line, "Bcc:") == 0) nocopy = 1; if (parse_state.state != NONE) { if (parse_addrs(&parse_state, line, queue) < 0) { - errlogx(1, "invalid address in header\n"); + errlogx(EX_DATAERR, "invalid address in header\n"); /* NOTREACHED */ } } if (recp_from_header && ( strprefixcmp(line, "To:") == 0 || strprefixcmp(line, "Cc:") == 0 || strprefixcmp(line, "Bcc:") == 0)) { parse_state.state = START; if (parse_addrs(&parse_state, line, queue) < 0) { - errlogx(1, "invalid address in header\n"); + errlogx(EX_DATAERR, "invalid address in header\n"); /* NOTREACHED */ } } } if (strcmp(line, "\n") == 0 && !had_headers) { had_headers = 1; while (!had_date || !had_messagid || !had_from) { if (!had_date) { had_date = 1; snprintf(line, sizeof(line), "Date: %s\n", rfc822date()); } else if (!had_messagid) { /* XXX msgid, assign earlier and log? */ had_messagid = 1; snprintf(line, sizeof(line), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n", (uintmax_t)time(NULL), queue->id, (uintmax_t)random(), hostname()); } else if (!had_from) { had_from = 1; snprintf(line, sizeof(line), "From: <%s>\n", queue->sender); } if (fwrite(line, strlen(line), 1, queue->mailf) != 1) return (-1); } strcpy(line, "\n"); } if (!nodot && linelen == 2 && line[0] == '.') break; if (!nocopy) { if (fwrite(line, strlen(line), 1, queue->mailf) != 1) return (-1); } } return (0); } Index: head/contrib/dma/net.c =================================================================== --- head/contrib/dma/net.c (revision 289122) +++ head/contrib/dma/net.c (revision 289123) @@ -1,546 +1,547 @@ /* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Matthias Schmidt , University of Marburg, * Germany. * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ #include "dfcompat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dma.h" char neterr[ERRMSG_SIZE]; char * ssl_errstr(void) { long oerr, nerr; oerr = 0; while ((nerr = ERR_get_error()) != 0) oerr = nerr; return (ERR_error_string(oerr, NULL)); } ssize_t send_remote_command(int fd, const char* fmt, ...) { va_list va; char cmd[4096]; size_t len, pos; int s; ssize_t n; va_start(va, fmt); s = vsnprintf(cmd, sizeof(cmd) - 2, fmt, va); va_end(va); if (s == sizeof(cmd) - 2 || s < 0) { strcpy(neterr, "Internal error: oversized command string"); return (-1); } /* We *know* there are at least two more bytes available */ strcat(cmd, "\r\n"); len = strlen(cmd); if (((config.features & SECURETRANS) != 0) && ((config.features & NOSSL) == 0)) { while ((s = SSL_write(config.ssl, (const char*)cmd, len)) <= 0) { s = SSL_get_error(config.ssl, s); if (s != SSL_ERROR_WANT_READ && s != SSL_ERROR_WANT_WRITE) { strncpy(neterr, ssl_errstr(), sizeof(neterr)); return (-1); } } } else { pos = 0; while (pos < len) { n = write(fd, cmd + pos, len - pos); if (n < 0) return (-1); pos += n; } } return (len); } int read_remote(int fd, int extbufsize, char *extbuf) { ssize_t rlen = 0; size_t pos, len, copysize; char buff[BUF_SIZE]; int done = 0, status = 0, status_running = 0, extbufpos = 0; enum { parse_status, parse_spacedash, parse_rest } parsestate; if (do_timeout(CON_TIMEOUT, 1) != 0) { snprintf(neterr, sizeof(neterr), "Timeout reached"); return (-1); } /* * Remote reading code from femail.c written by Henning Brauer of * OpenBSD and released under a BSD style license. */ len = 0; pos = 0; parsestate = parse_status; neterr[0] = 0; while (!(done && parsestate == parse_status)) { rlen = 0; if (pos == 0 || (pos > 0 && memchr(buff + pos, '\n', len - pos) == NULL)) { memmove(buff, buff + pos, len - pos); len -= pos; pos = 0; if (((config.features & SECURETRANS) != 0) && (config.features & NOSSL) == 0) { if ((rlen = SSL_read(config.ssl, buff + len, sizeof(buff) - len)) == -1) { strncpy(neterr, ssl_errstr(), sizeof(neterr)); goto error; } } else { if ((rlen = read(fd, buff + len, sizeof(buff) - len)) == -1) { strncpy(neterr, strerror(errno), sizeof(neterr)); goto error; } } len += rlen; copysize = sizeof(neterr) - strlen(neterr) - 1; if (copysize > len) copysize = len; strncat(neterr, buff, copysize); } /* * If there is an external buffer with a size bigger than zero * and as long as there is space in the external buffer and * there are new characters read from the mailserver * copy them to the external buffer */ if (extbufpos <= (extbufsize - 1) && rlen > 0 && extbufsize > 0 && extbuf != NULL) { /* do not write over the bounds of the buffer */ if(extbufpos + rlen > (extbufsize - 1)) { rlen = extbufsize - extbufpos; } memcpy(extbuf + extbufpos, buff + len - rlen, rlen); extbufpos += rlen; } if (pos == len) continue; switch (parsestate) { case parse_status: for (; pos < len; pos++) { if (isdigit(buff[pos])) { status_running = status_running * 10 + (buff[pos] - '0'); } else { status = status_running; status_running = 0; parsestate = parse_spacedash; break; } } continue; case parse_spacedash: switch (buff[pos]) { case ' ': done = 1; break; case '-': /* ignore */ /* XXX read capabilities */ break; default: strcpy(neterr, "invalid syntax in reply from server"); goto error; } pos++; parsestate = parse_rest; continue; case parse_rest: /* skip up to \n */ for (; pos < len; pos++) { if (buff[pos] == '\n') { pos++; parsestate = parse_status; break; } } } } do_timeout(0, 0); /* chop off trailing newlines */ while (neterr[0] != 0 && strchr("\r\n", neterr[strlen(neterr) - 1]) != 0) neterr[strlen(neterr) - 1] = 0; return (status/100); error: do_timeout(0, 0); return (-1); } /* * Handle SMTP authentication */ static int smtp_login(int fd, char *login, char* password) { char *temp; int len, res = 0; res = smtp_auth_md5(fd, login, password); if (res == 0) { return (0); } else if (res == -2) { /* * If the return code is -2, then then the login attempt failed, * do not try other login mechanisms */ return (1); } if ((config.features & INSECURE) != 0 || (config.features & SECURETRANS) != 0) { /* Send AUTH command according to RFC 2554 */ send_remote_command(fd, "AUTH LOGIN"); if (read_remote(fd, 0, NULL) != 3) { syslog(LOG_NOTICE, "remote delivery deferred:" " AUTH login not available: %s", neterr); return (1); } len = base64_encode(login, strlen(login), &temp); if (len < 0) { encerr: syslog(LOG_ERR, "can not encode auth reply: %m"); return (1); } send_remote_command(fd, "%s", temp); free(temp); res = read_remote(fd, 0, NULL); if (res != 3) { syslog(LOG_NOTICE, "remote delivery %s: AUTH login failed: %s", res == 5 ? "failed" : "deferred", neterr); return (res == 5 ? -1 : 1); } len = base64_encode(password, strlen(password), &temp); if (len < 0) goto encerr; send_remote_command(fd, "%s", temp); free(temp); res = read_remote(fd, 0, NULL); if (res != 2) { syslog(LOG_NOTICE, "remote delivery %s: Authentication failed: %s", res == 5 ? "failed" : "deferred", neterr); return (res == 5 ? -1 : 1); } } else { syslog(LOG_WARNING, "non-encrypted SMTP login is disabled in config, so skipping it. "); return (1); } return (0); } static int open_connection(struct mx_hostentry *h) { int fd; syslog(LOG_INFO, "trying remote delivery to %s [%s] pref %d", h->host, h->addr, h->pref); fd = socket(h->ai.ai_family, h->ai.ai_socktype, h->ai.ai_protocol); if (fd < 0) { syslog(LOG_INFO, "socket for %s [%s] failed: %m", h->host, h->addr); return (-1); } if (connect(fd, (struct sockaddr *)&h->sa, h->ai.ai_addrlen) < 0) { syslog(LOG_INFO, "connect to %s [%s] failed: %m", h->host, h->addr); close(fd); return (-1); } return (fd); } static void close_connection(int fd) { if (config.ssl != NULL) { if (((config.features & SECURETRANS) != 0) && ((config.features & NOSSL) == 0)) SSL_shutdown(config.ssl); SSL_free(config.ssl); } close(fd); } static int deliver_to_host(struct qitem *it, struct mx_hostentry *host) { struct authuser *a; char line[1000]; size_t linelen; int fd, error = 0, do_auth = 0, res = 0; if (fseek(it->mailf, 0, SEEK_SET) != 0) { snprintf(errmsg, sizeof(errmsg), "can not seek: %s", strerror(errno)); return (-1); } fd = open_connection(host); if (fd < 0) return (1); #define READ_REMOTE_CHECK(c, exp) \ res = read_remote(fd, 0, NULL); \ if (res == 5) { \ syslog(LOG_ERR, "remote delivery to %s [%s] failed after %s: %s", \ host->host, host->addr, c, neterr); \ snprintf(errmsg, sizeof(errmsg), "%s [%s] did not like our %s:\n%s", \ host->host, host->addr, c, neterr); \ return (-1); \ } else if (res != exp) { \ syslog(LOG_NOTICE, "remote delivery deferred: %s [%s] failed after %s: %s", \ host->host, host->addr, c, neterr); \ return (1); \ } /* Check first reply from remote host */ if ((config.features & SECURETRANS) == 0 || (config.features & STARTTLS) != 0) { config.features |= NOSSL; READ_REMOTE_CHECK("connect", 2); config.features &= ~NOSSL; } if ((config.features & SECURETRANS) != 0) { error = smtp_init_crypto(fd, config.features); if (error == 0) syslog(LOG_DEBUG, "SSL initialization successful"); else goto out; if ((config.features & STARTTLS) == 0) READ_REMOTE_CHECK("connect", 2); } /* XXX allow HELO fallback */ /* XXX record ESMTP keywords */ send_remote_command(fd, "EHLO %s", hostname()); READ_REMOTE_CHECK("EHLO", 2); /* * Use SMTP authentication if the user defined an entry for the remote * or smarthost */ SLIST_FOREACH(a, &authusers, next) { if (strcmp(a->host, host->host) == 0) { do_auth = 1; break; } } if (do_auth == 1) { /* * Check if the user wants plain text login without using * encryption. */ syslog(LOG_INFO, "using SMTP authentication for user %s", a->login); error = smtp_login(fd, a->login, a->password); if (error < 0) { syslog(LOG_ERR, "remote delivery failed:" " SMTP login failed: %m"); snprintf(errmsg, sizeof(errmsg), "SMTP login to %s failed", host->host); return (-1); } /* SMTP login is not available, so try without */ else if (error > 0) { syslog(LOG_WARNING, "SMTP login not available. Trying without."); } } /* XXX send ESMTP ENVID, RET (FULL/HDRS) and 8BITMIME */ send_remote_command(fd, "MAIL FROM:<%s>", it->sender); READ_REMOTE_CHECK("MAIL FROM", 2); /* XXX send ESMTP ORCPT */ send_remote_command(fd, "RCPT TO:<%s>", it->addr); READ_REMOTE_CHECK("RCPT TO", 2); send_remote_command(fd, "DATA"); READ_REMOTE_CHECK("DATA", 3); error = 0; while (!feof(it->mailf)) { if (fgets(line, sizeof(line), it->mailf) == NULL) break; linelen = strlen(line); if (linelen == 0 || line[linelen - 1] != '\n') { syslog(LOG_CRIT, "remote delivery failed: corrupted queue file"); snprintf(errmsg, sizeof(errmsg), "corrupted queue file"); error = -1; goto out; } /* Remove trailing \n's and escape leading dots */ trim_line(line); /* * If the first character is a dot, we escape it so the line * length increases */ if (line[0] == '.') linelen++; if (send_remote_command(fd, "%s", line) != (ssize_t)linelen+1) { syslog(LOG_NOTICE, "remote delivery deferred: write error"); error = 1; goto out; } } send_remote_command(fd, "."); READ_REMOTE_CHECK("final DATA", 2); send_remote_command(fd, "QUIT"); if (read_remote(fd, 0, NULL) != 2) syslog(LOG_INFO, "remote delivery succeeded but QUIT failed: %s", neterr); out: close_connection(fd); return (error); } int deliver_remote(struct qitem *it) { struct mx_hostentry *hosts, *h; const char *host; int port; int error = 1, smarthost = 0; port = SMTP_PORT; /* Smarthost support? */ if (config.smarthost != NULL) { host = config.smarthost; port = config.port; syslog(LOG_INFO, "using smarthost (%s:%i)", host, port); smarthost = 1; } else { host = strrchr(it->addr, '@'); /* Should not happen */ if (host == NULL) { snprintf(errmsg, sizeof(errmsg), "Internal error: badly formed address %s", it->addr); return(-1); } else { /* Step over the @ */ host++; } } error = dns_get_mx_list(host, port, &hosts, smarthost); if (error) { snprintf(errmsg, sizeof(errmsg), "DNS lookup failure: host %s not found", host); syslog(LOG_NOTICE, "remote delivery %s: DNS lookup failure: host %s not found", error < 0 ? "failed" : "deferred", host); return (error); } for (h = hosts; *h->host != 0; h++) { switch (deliver_to_host(it, h)) { case 0: /* success */ error = 0; goto out; case 1: /* temp failure */ error = 1; break; default: /* perm failure */ error = -1; goto out; } } out: free(hosts); return (error); } Index: head/contrib/dma/spool.c =================================================================== --- head/contrib/dma/spool.c (revision 289122) +++ head/contrib/dma/spool.c (revision 289123) @@ -1,440 +1,441 @@ /* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project - * by Simon 'corecode' Schubert . + * by Simon Schubert <2@0x2c.org>. * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ #include "dfcompat.h" #include #include #include #include #include #include #include #include #include #include #include "dma.h" /* * Spool file format: * * 'Q'id files (queue): * Organized like an RFC822 header, field: value. Ignores unknown fields. * ID: id * Sender: envelope-from * Recipient: envelope-to * * 'M'id files (data): * mail data * * Each queue file needs to have a corresponding data file. * One data file might be shared by linking it several times. * * Queue ids are unique, formed from the inode of the data file * and a unique identifier. */ int newspoolf(struct queue *queue) { char fn[PATH_MAX+1]; struct stat st; struct stritem *t; int fd; if (snprintf(fn, sizeof(fn), "%s/%s", config.spooldir, "tmp_XXXXXXXXXX") <= 0) return (-1); fd = mkstemp(fn); if (fd < 0) return (-1); /* XXX group rights */ if (fchmod(fd, 0660) < 0) goto fail; if (flock(fd, LOCK_EX) == -1) goto fail; queue->tmpf = strdup(fn); if (queue->tmpf == NULL) goto fail; /* * Assign queue id */ if (fstat(fd, &st) != 0) goto fail; if (asprintf(&queue->id, "%"PRIxMAX, (uintmax_t)st.st_ino) < 0) goto fail; queue->mailf = fdopen(fd, "r+"); if (queue->mailf == NULL) goto fail; t = malloc(sizeof(*t)); if (t != NULL) { t->str = queue->tmpf; SLIST_INSERT_HEAD(&tmpfs, t, next); } return (0); fail: if (queue->mailf != NULL) fclose(queue->mailf); close(fd); unlink(fn); return (-1); } static int writequeuef(struct qitem *it) { int error; int queuefd; queuefd = open_locked(it->queuefn, O_CREAT|O_EXCL|O_RDWR, 0660); if (queuefd == -1) return (-1); if (fchmod(queuefd, 0660) < 0) return (-1); it->queuef = fdopen(queuefd, "w+"); if (it->queuef == NULL) return (-1); error = fprintf(it->queuef, "ID: %s\n" "Sender: %s\n" "Recipient: %s\n", it->queueid, it->sender, it->addr); if (error <= 0) return (-1); if (fflush(it->queuef) != 0 || fsync(fileno(it->queuef)) != 0) return (-1); return (0); } static struct qitem * readqueuef(struct queue *queue, char *queuefn) { char line[1000]; struct queue itmqueue; FILE *queuef = NULL; char *s; char *queueid = NULL, *sender = NULL, *addr = NULL; struct qitem *it = NULL; bzero(&itmqueue, sizeof(itmqueue)); LIST_INIT(&itmqueue.queue); queuef = fopen(queuefn, "r"); if (queuef == NULL) goto out; while (!feof(queuef)) { if (fgets(line, sizeof(line), queuef) == NULL || line[0] == 0) break; line[strlen(line) - 1] = 0; /* chop newline */ s = strchr(line, ':'); if (s == NULL) goto malformed; *s = 0; s++; while (isspace(*s)) s++; s = strdup(s); if (s == NULL) goto malformed; if (strcmp(line, "ID") == 0) { queueid = s; } else if (strcmp(line, "Sender") == 0) { sender = s; } else if (strcmp(line, "Recipient") == 0) { addr = s; } else { syslog(LOG_DEBUG, "ignoring unknown queue info `%s' in `%s'", line, queuefn); free(s); } } if (queueid == NULL || sender == NULL || addr == NULL || *queueid == 0 || *addr == 0) { malformed: errno = EINVAL; syslog(LOG_ERR, "malformed queue file `%s'", queuefn); goto out; } if (add_recp(&itmqueue, addr, 0) != 0) goto out; it = LIST_FIRST(&itmqueue.queue); it->sender = sender; sender = NULL; it->queueid = queueid; queueid = NULL; it->queuefn = queuefn; queuefn = NULL; LIST_INSERT_HEAD(&queue->queue, it, next); out: if (sender != NULL) free(sender); if (queueid != NULL) free(queueid); if (addr != NULL) free(addr); if (queuef != NULL) fclose(queuef); return (it); } int linkspool(struct queue *queue) { struct stat st; struct qitem *it; if (fflush(queue->mailf) != 0 || fsync(fileno(queue->mailf)) != 0) goto delfiles; syslog(LOG_INFO, "new mail from user=%s uid=%d envelope_from=<%s>", username, getuid(), queue->sender); LIST_FOREACH(it, &queue->queue, next) { if (asprintf(&it->queueid, "%s.%"PRIxPTR, queue->id, (uintptr_t)it) <= 0) goto delfiles; if (asprintf(&it->queuefn, "%s/Q%s", config.spooldir, it->queueid) <= 0) goto delfiles; if (asprintf(&it->mailfn, "%s/M%s", config.spooldir, it->queueid) <= 0) goto delfiles; /* Neither file may not exist yet */ if (stat(it->queuefn, &st) == 0 || stat(it->mailfn, &st) == 0) goto delfiles; if (writequeuef(it) != 0) goto delfiles; if (link(queue->tmpf, it->mailfn) != 0) goto delfiles; } LIST_FOREACH(it, &queue->queue, next) { syslog(LOG_INFO, "mail to=<%s> queued as %s", it->addr, it->queueid); } unlink(queue->tmpf); return (0); delfiles: LIST_FOREACH(it, &queue->queue, next) { unlink(it->mailfn); unlink(it->queuefn); } return (-1); } int load_queue(struct queue *queue) { struct stat sb; struct qitem *it; DIR *spooldir; struct dirent *de; char *queuefn; char *mailfn; bzero(queue, sizeof(*queue)); LIST_INIT(&queue->queue); spooldir = opendir(config.spooldir); if (spooldir == NULL) - err(1, "reading queue"); + err(EX_NOINPUT, "reading queue"); while ((de = readdir(spooldir)) != NULL) { queuefn = NULL; mailfn = NULL; /* ignore non-queue files */ if (de->d_name[0] != 'Q') continue; if (asprintf(&queuefn, "%s/Q%s", config.spooldir, de->d_name + 1) < 0) goto fail; if (asprintf(&mailfn, "%s/M%s", config.spooldir, de->d_name + 1) < 0) goto fail; /* * Some file systems don't provide a de->d_type, so we have to * do an explicit stat on the queue file. * Move on if it turns out to be something else than a file. */ if (stat(queuefn, &sb) != 0) goto skip_item; if (!S_ISREG(sb.st_mode)) { errno = EINVAL; goto skip_item; } if (stat(mailfn, &sb) != 0) goto skip_item; it = readqueuef(queue, queuefn); if (it == NULL) goto skip_item; it->mailfn = mailfn; continue; skip_item: syslog(LOG_INFO, "could not pick up queue file: `%s'/`%s': %m", queuefn, mailfn); if (queuefn != NULL) free(queuefn); if (mailfn != NULL) free(mailfn); } closedir(spooldir); return (0); fail: return (-1); } void delqueue(struct qitem *it) { unlink(it->mailfn); unlink(it->queuefn); if (it->queuef != NULL) fclose(it->queuef); if (it->mailf != NULL) fclose(it->mailf); free(it); } int acquirespool(struct qitem *it) { int queuefd; if (it->queuef == NULL) { queuefd = open_locked(it->queuefn, O_RDWR|O_NONBLOCK); if (queuefd < 0) goto fail; it->queuef = fdopen(queuefd, "r+"); if (it->queuef == NULL) goto fail; } if (it->mailf == NULL) { it->mailf = fopen(it->mailfn, "r"); if (it->mailf == NULL) goto fail; } return (0); fail: if (errno == EWOULDBLOCK) return (1); syslog(LOG_INFO, "could not acquire queue file: %m"); return (-1); } void dropspool(struct queue *queue, struct qitem *keep) { struct qitem *it; LIST_FOREACH(it, &queue->queue, next) { if (it == keep) continue; if (it->queuef != NULL) fclose(it->queuef); if (it->mailf != NULL) fclose(it->mailf); } } int flushqueue_since(unsigned int period) { struct stat st; struct timeval now; char *flushfn = NULL; if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0) return (0); if (stat(flushfn, &st) < 0) { free(flushfn); return (0); } free(flushfn); flushfn = NULL; if (gettimeofday(&now, 0) != 0) return (0); /* Did the flush file get touched within the last period seconds? */ if (st.st_mtim.tv_sec + (int)period >= now.tv_sec) return (1); else return (0); } int flushqueue_signal(void) { char *flushfn = NULL; int fd; if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0) return (-1); fd = open(flushfn, O_CREAT|O_WRONLY|O_TRUNC, 0660); free(flushfn); if (fd < 0) { syslog(LOG_ERR, "could not open flush file: %m"); return (-1); } close(fd); return (0); } Index: head/contrib/dma/util.c =================================================================== --- head/contrib/dma/util.c (revision 289122) +++ head/contrib/dma/util.c (revision 289123) @@ -1,345 +1,346 @@ /* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. * Copyright (c) 2008 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project - * by Simon 'corecode' Schubert . + * by Simon Schubert <2@0x2c.org>. * * 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. * 3. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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 * COPYRIGHT HOLDERS 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dma.h" const char * hostname(void) { #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 255 #endif static char name[HOST_NAME_MAX+1]; static int initialized = 0; char *s; if (initialized) return (name); if (config.mailname == NULL || !*config.mailname) goto local; if (config.mailname[0] == '/') { /* * If the mailname looks like an absolute path, * treat it as a file. */ FILE *fp; fp = fopen(config.mailname, "r"); if (fp == NULL) goto local; s = fgets(name, sizeof(name), fp); fclose(fp); if (s == NULL) goto local; for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s) /* NOTHING */; *s = 0; if (!*name) goto local; initialized = 1; return (name); } else { snprintf(name, sizeof(name), "%s", config.mailname); initialized = 1; return (name); } local: if (gethostname(name, sizeof(name)) != 0) *name = 0; /* * gethostname() is allowed to truncate name without NUL-termination * and at the same time not return an error. */ name[sizeof(name) - 1] = 0; for (s = name; *s != 0 && (isalnum(*s) || strchr("_.-", *s)); ++s) /* NOTHING */; *s = 0; if (!*name) snprintf(name, sizeof(name), "unknown-hostname"); initialized = 1; return (name); } void setlogident(const char *fmt, ...) { static char tag[50]; snprintf(tag, sizeof(tag), "%s", logident_base); if (fmt != NULL) { va_list ap; char sufx[50]; va_start(ap, fmt); vsnprintf(sufx, sizeof(sufx), fmt, ap); va_end(ap); snprintf(tag, sizeof(tag), "%s[%s]", logident_base, sufx); } closelog(); openlog(tag, 0, LOG_MAIL); } void errlog(int exitcode, const char *fmt, ...) { int oerrno = errno; va_list ap; char outs[ERRMSG_SIZE]; outs[0] = 0; if (fmt != NULL) { va_start(ap, fmt); vsnprintf(outs, sizeof(outs), fmt, ap); va_end(ap); } errno = oerrno; if (*outs != 0) { syslog(LOG_ERR, "%s: %m", outs); fprintf(stderr, "%s: %s: %s\n", getprogname(), outs, strerror(oerrno)); } else { syslog(LOG_ERR, "%m"); fprintf(stderr, "%s: %s\n", getprogname(), strerror(oerrno)); } exit(exitcode); } void errlogx(int exitcode, const char *fmt, ...) { va_list ap; char outs[ERRMSG_SIZE]; outs[0] = 0; if (fmt != NULL) { va_start(ap, fmt); vsnprintf(outs, sizeof(outs), fmt, ap); va_end(ap); } if (*outs != 0) { syslog(LOG_ERR, "%s", outs); fprintf(stderr, "%s: %s\n", getprogname(), outs); } else { syslog(LOG_ERR, "Unknown error"); fprintf(stderr, "%s: Unknown error\n", getprogname()); } exit(exitcode); } static int check_username(const char *name, uid_t ckuid) { struct passwd *pwd; if (name == NULL) return (0); pwd = getpwnam(name); if (pwd == NULL || pwd->pw_uid != ckuid) return (0); snprintf(username, sizeof(username), "%s", name); return (1); } void set_username(void) { struct passwd *pwd; useruid = getuid(); if (check_username(getlogin(), useruid)) return; if (check_username(getenv("LOGNAME"), useruid)) return; if (check_username(getenv("USER"), useruid)) return; pwd = getpwuid(useruid); if (pwd != NULL && pwd->pw_name != NULL && pwd->pw_name[0] != '\0') { if (check_username(pwd->pw_name, useruid)) return; } snprintf(username, sizeof(username), "uid=%ld", (long)useruid); } void deltmp(void) { struct stritem *t; SLIST_FOREACH(t, &tmpfs, next) { unlink(t->str); } } static sigjmp_buf sigbuf; static int sigbuf_valid; static void sigalrm_handler(int signo) { (void)signo; /* so that gcc doesn't complain */ if (sigbuf_valid) siglongjmp(sigbuf, 1); } int do_timeout(int timeout, int dojmp) { struct sigaction act; int ret = 0; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (timeout) { act.sa_handler = sigalrm_handler; if (sigaction(SIGALRM, &act, NULL) != 0) syslog(LOG_WARNING, "can not set signal handler: %m"); if (dojmp) { ret = sigsetjmp(sigbuf, 1); if (ret) goto disable; /* else just programmed */ sigbuf_valid = 1; } alarm(timeout); } else { disable: alarm(0); act.sa_handler = SIG_IGN; if (sigaction(SIGALRM, &act, NULL) != 0) syslog(LOG_WARNING, "can not remove signal handler: %m"); sigbuf_valid = 0; } return (ret); } int open_locked(const char *fname, int flags, ...) { int mode = 0; if (flags & O_CREAT) { va_list ap; va_start(ap, flags); mode = va_arg(ap, int); va_end(ap); } #ifndef O_EXLOCK int fd, save_errno; fd = open(fname, flags, mode); if (fd < 0) return(fd); if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) { save_errno = errno; close(fd); errno = save_errno; return(-1); } return(fd); #else return(open(fname, flags|O_EXLOCK, mode)); #endif } char * rfc822date(void) { static char str[50]; size_t error; time_t now; now = time(NULL); error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z", localtime(&now)); if (error == 0) strcpy(str, "(date fail)"); return (str); } int strprefixcmp(const char *str, const char *prefix) { return (strncasecmp(str, prefix, strlen(prefix))); } void init_random(void) { unsigned int seed; int rf; rf = open("/dev/urandom", O_RDONLY); if (rf == -1) rf = open("/dev/random", O_RDONLY); if (!(rf != -1 && read(rf, &seed, sizeof(seed)) == sizeof(seed))) seed = (time(NULL) ^ getpid()) + (uintptr_t)&seed; srandom(seed); if (rf != -1) close(rf); } Index: head/contrib/dma =================================================================== --- head/contrib/dma (revision 289122) +++ head/contrib/dma (revision 289123) Property changes on: head/contrib/dma ___________________________________________________________________ Added: svn:mergeinfo ## -0,0 +0,25 ## Merged /user/delphij/zfs-arc-rebase/contrib/dma:r281754 Merged /projects/pf/head/contrib/dma:r263908 Merged /projects/clang-trunk/contrib/dma:r283596-287505 Merged /projects/zfsd/head/contrib/dma:r266519,269993 Merged /projects/building-blocks/contrib/dma:r275142-275143,275198,275297,275306-275307,275309,275311,275556,275558,275600,277445,277670,277673 Merged /projects/release-embedded/contrib/dma:r262314,262504,262510-262511,262580,262660,262662,262700,262713,262774,262786-262788,262790-262792,262798,262802,262808 Merged /projects/clang-sparc64/contrib/dma:r262258-262612 Merged /vendor/resolver/dist/contrib/dma:r1540-186085 Merged /projects/clang350-import/contrib/dma:r274961-275126,275128-275133,275135-276476 Merged /projects/largeSMP/contrib/dma:r221273-222812,222815-223757 Merged /projects/clang360-import/contrib/dma:r277327-280030 Merged /projects/clang370-import/contrib/dma:r287506-288928 Merged /projects/head_mfi/contrib/dma:r233621 Merged /projects/pms/contrib/dma:r285199-285661 Merged /projects/quota64/contrib/dma:r184125-207707 Merged /vendor/dma/dist:r262282-289122 Merged /projects/random_number_generator/contrib/dma:r254613-256243 Merged /projects/lldb-r201577/contrib/dma:r262185-262527 Merged /projects/release-arm-redux/contrib/dma:r278203,278595-278597,278610,280643-280650,280652,280655,282539-282546,282548,282553-282557,282564,282566,282570,282573,282587-282593,282596-282607,282615-282616,282624-282629,282631,282633,282635-282640,282642,282647-282648,282653-282654,282656-282657,282659,282662-282667,282682,282691 Merged /projects/release-arm64/contrib/dma:r281786,281788,281792 Merged /projects/elftoolchain-update-r3130/contrib/dma:r276164,276167,276170-276172 Merged /projects/multi-fibv6/head/contrib/dma:r230929-231848 Merged /projects/elftoolchain/contrib/dma:r260687-261245 Merged /projects/ipfw/contrib/dma:r267383-272837 Merged /user/ngie/more-tests/contrib/dma:r281427-281428,281430,281432,281450,281460,281464-281465,281485,281489-281491,281515,281519,281589,281593-281597,281619,284388,288316,288321-288327,288422,288476,288478-288481,288483,288578,288650-288651,288655-288656,288659-288661,288663,288673-288676,288828 Index: head/libexec/dma/Makefile.inc =================================================================== --- head/libexec/dma/Makefile.inc (revision 289122) +++ head/libexec/dma/Makefile.inc (revision 289123) @@ -1,13 +1,13 @@ # $FreeBSD$ .sinclude "${.CURDIR}/../../Makefile.inc" DMA_SOURCES= ${.CURDIR}/../../../contrib/dma .PATH: ${DMA_SOURCES} CFLAGS= -I${DMA_SOURCES} \ -DHAVE_REALLOCF -DHAVE_STRLCPY -DHAVE_GETPROGNAME \ -DCONF_PATH='"/etc/dma"' \ - -DLIBEXEC_PATH='"/usr/libexec"' -DDMA_VERSION='"v0.9+"' \ + -DLIBEXEC_PATH='"/usr/libexec"' -DDMA_VERSION='"v0.10"' \ -DDMA_ROOT_USER='"mailnull"' \ -DDMA_GROUP='"mail"' BINGRP= mail