diff options
Diffstat (limited to 'smtpd/mail.maildir.c')
-rw-r--r-- | smtpd/mail.maildir.c | 284 |
1 files changed, 0 insertions, 284 deletions
diff --git a/smtpd/mail.maildir.c b/smtpd/mail.maildir.c deleted file mode 100644 index fe6adba6..00000000 --- a/smtpd/mail.maildir.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2017 Gilles Chehade <gilles@poolp.org> - * - * 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. - */ - -#include "includes.h" - -#ifndef nitems -#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) -#endif - -#include <sys/types.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <sysexits.h> -#include <unistd.h> - -#define MAILADDR_ESCAPE "!#$%&'*/?^`{|}~" - -static int maildir_subdir(const char *, char *, size_t); -static void maildir_mkdirs(const char *); -static void maildir_engine(const char *, int); -static int mkdirs_component(const char *, mode_t); -static int mkdirs(const char *, mode_t); - -int -main(int argc, char *argv[]) -{ - int ch; - int junk = 0; - - if (! geteuid()) - errx(1, "mail.maildir: may not be executed as root"); - - while ((ch = getopt(argc, argv, "j")) != -1) { - switch (ch) { - case 'j': - junk = 1; - break; - default: - break; - } - } - argc -= optind; - argv += optind; - - if (argc > 1) - errx(1, "mail.maildir: only one maildir is allowed"); - - maildir_engine(argv[0], junk); - - return (0); -} - -static int -maildir_subdir(const char *extension, char *dest, size_t len) -{ - char *sanitized; - - if (strlcpy(dest, extension, len) >= len) - return 0; - - for (sanitized = dest; *sanitized; sanitized++) - if (strchr(MAILADDR_ESCAPE, *sanitized)) - *sanitized = ':'; - - return 1; -} - -static void -maildir_mkdirs(const char *dirname) -{ - uint i; - int ret; - char pathname[PATH_MAX]; - char *subdirs[] = { "cur", "tmp", "new" }; - - if (mkdirs(dirname, 0700) == -1 && errno != EEXIST) { - if (errno == EINVAL || errno == ENAMETOOLONG) - err(1, NULL); - err(EX_TEMPFAIL, NULL); - } - - for (i = 0; i < nitems(subdirs); ++i) { - ret = snprintf(pathname, sizeof pathname, "%s/%s", dirname, - subdirs[i]); - if (ret < 0 || (size_t)ret >= sizeof pathname) - errc(1, ENAMETOOLONG, "%s/%s", dirname, subdirs[i]); - if (mkdir(pathname, 0700) == -1 && errno != EEXIST) - err(EX_TEMPFAIL, NULL); - } -} - -static void -maildir_engine(const char *dirname, int junk) -{ - char rootpath[PATH_MAX]; - char junkpath[PATH_MAX]; - char extpath[PATH_MAX]; - char subdir[PATH_MAX]; - char filename[PATH_MAX]; - char hostname[HOST_NAME_MAX+1]; - - char tmp[PATH_MAX]; - char new[PATH_MAX]; - - int ret; - - int fd; - FILE *fp; - char *line = NULL; - size_t linesize = 0; - ssize_t linelen; - struct stat sb; - char *home; - char *extension; - - int is_junk = 0; - int in_hdr = 1; - - if (dirname == NULL) { - if ((home = getenv("HOME")) == NULL) - err(1, NULL); - ret = snprintf(rootpath, sizeof rootpath, "%s/Maildir", home); - if (ret < 0 || (size_t)ret >= sizeof rootpath) - errc(1, ENAMETOOLONG, "%s/Maildir", home); - dirname = rootpath; - } - maildir_mkdirs(dirname); - - if (junk) { - /* create Junk subdirectory */ - ret = snprintf(junkpath, sizeof junkpath, "%s/.Junk", dirname); - if (ret < 0 || (size_t)ret >= sizeof junkpath) - errc(1, ENAMETOOLONG, "%s/.Junk", dirname); - maildir_mkdirs(junkpath); - } - - if ((extension = getenv("EXTENSION")) != NULL) { - if (maildir_subdir(extension, subdir, sizeof(subdir)) && - subdir[0]) { - ret = snprintf(extpath, sizeof extpath, "%s/.%s", - dirname, subdir); - if (ret < 0 || (size_t)ret >= sizeof extpath) - errc(1, ENAMETOOLONG, "%s/.%s", - dirname, subdir); - if (stat(extpath, &sb) != -1) { - dirname = extpath; - maildir_mkdirs(dirname); - } - } - } - - if (gethostname(hostname, sizeof hostname) != 0) - (void)strlcpy(hostname, "localhost", sizeof hostname); - - (void)snprintf(filename, sizeof filename, "%lld.%08x.%s", - (long long int) time(NULL), - arc4random(), - hostname); - - (void)snprintf(tmp, sizeof tmp, "%s/tmp/%s", dirname, filename); - - fd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0600); - if (fd == -1) - err(EX_TEMPFAIL, NULL); - if ((fp = fdopen(fd, "w")) == NULL) - err(EX_TEMPFAIL, NULL); - - while ((linelen = getline(&line, &linesize, stdin)) != -1) { - line[strcspn(line, "\n")] = '\0'; - if (line[0] == '\0') - in_hdr = 0; - if (junk && in_hdr && - (strcasecmp(line, "x-spam: yes") == 0 || - strcasecmp(line, "x-spam-flag: yes") == 0)) - is_junk = 1; - fprintf(fp, "%s\n", line); - } - free(line); - if (ferror(stdin)) - err(EX_TEMPFAIL, NULL); - - if (fflush(fp) == EOF || - ferror(fp) || - fsync(fd) == -1 || - fclose(fp) == EOF) - err(EX_TEMPFAIL, NULL); - - (void)snprintf(new, sizeof new, "%s/new/%s", - is_junk ? junkpath : dirname, filename); - - if (rename(tmp, new) == -1) - err(EX_TEMPFAIL, NULL); - - exit(0); -} - - -static int -mkdirs_component(const char *path, mode_t mode) -{ - struct stat sb; - - if (stat(path, &sb) == -1) { - if (errno != ENOENT) - return 0; - if (mkdir(path, mode | S_IWUSR | S_IXUSR) == -1) - return 0; - } - else if (!S_ISDIR(sb.st_mode)) { - errno = ENOTDIR; - return 0; - } - - return 1; -} - -static int -mkdirs(const char *path, mode_t mode) -{ - char buf[PATH_MAX]; - int i = 0; - int done = 0; - const char *p; - - /* absolute path required */ - if (*path != '/') { - errno = EINVAL; - return 0; - } - - /* make sure we don't exceed PATH_MAX */ - if (strlen(path) >= sizeof buf) { - errno = ENAMETOOLONG; - return 0; - } - - memset(buf, 0, sizeof buf); - for (p = path; *p; p++) { - if (*p == '/') { - if (buf[0] != '\0') - if (!mkdirs_component(buf, mode)) - return 0; - while (*p == '/') - p++; - buf[i++] = '/'; - buf[i++] = *p; - if (*p == '\0' && ++done) - break; - continue; - } - buf[i++] = *p; - } - if (!done) - if (!mkdirs_component(buf, mode)) - return 0; - - if (chmod(path, mode) == -1) - return 0; - - return 1; -} |