]> git.ipfire.org Git - people/ms/dma.git/blobdiff - spool.c
Merge pull request #34 from mtremer/better-authentication
[people/ms/dma.git] / spool.c
diff --git a/spool.c b/spool.c
index 69f29f310953647b37c5d2c21e17fcbfcbdcf940..e9c9c4355ab45e62c26b0582aa81228c9653fa32 100644 (file)
--- a/spool.c
+++ b/spool.c
@@ -1,8 +1,9 @@
 /*
+ * 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 <corecode@fs.ei.tum.de>.
+ * 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
@@ -32,6 +33,9 @@
  * SUCH DAMAGE.
  */
 
+#include "dfcompat.h"
+
+#include <sys/file.h>
 #include <sys/stat.h>
 
 #include <ctype.h>
@@ -72,12 +76,15 @@ newspoolf(struct queue *queue)
        struct stritem *t;
        int fd;
 
-       if (snprintf(fn, sizeof(fn), "%s/%s", config->spooldir, "tmp_XXXXXXXXXX") <= 0)
+       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);
@@ -89,7 +96,7 @@ newspoolf(struct queue *queue)
         */
        if (fstat(fd, &st) != 0)
                goto fail;
-       if (asprintf(&queue->id, "%"PRIxMAX, st.st_ino) < 0)
+       if (asprintf(&queue->id, "%"PRIxMAX, (uintmax_t)st.st_ino) < 0)
                goto fail;
 
        queue->mailf = fdopen(fd, "r+");
@@ -117,9 +124,11 @@ writequeuef(struct qitem *it)
        int error;
        int queuefd;
 
-       queuefd = open_locked(it->queuefn, O_CREAT|O_EXCL|O_RDWR, 0600);
+       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);
@@ -173,7 +182,7 @@ readqueuef(struct queue *queue, char *queuefn)
                        s++;
 
                s = strdup(s);
-               if (s == NULL || s[0] == 0)
+               if (s == NULL)
                        goto malformed;
 
                if (strcmp(line, "ID") == 0) {
@@ -189,7 +198,8 @@ readqueuef(struct queue *queue, char *queuefn)
                }
        }
 
-       if (queueid == NULL || sender == NULL || addr == NULL) {
+       if (queueid == NULL || sender == NULL || addr == NULL ||
+           *queueid == 0 || *addr == 0) {
 malformed:
                errno = EINVAL;
                syslog(LOG_ERR, "malformed queue file `%s'", queuefn);
@@ -233,9 +243,9 @@ linkspool(struct queue *queue)
        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)
+               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)
+               if (asprintf(&it->mailfn, "%s/M%s", config.spooldir, it->queueid) <= 0)
                        goto delfiles;
 
                /* Neither file may not exist yet */
@@ -275,27 +285,37 @@ load_queue(struct queue *queue)
        char *queuefn;
        char *mailfn;
 
-       bzero(queue, sizeof(queue));
+       bzero(queue, sizeof(*queue));
        LIST_INIT(&queue->queue);
 
-       spooldir = opendir(config->spooldir);
+       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 temp files */
-               if (strncmp(de->d_name, "tmp_", 4) == 0 || de->d_type != DT_REG)
-                       continue;
+               /* ignore non-queue files */
                if (de->d_name[0] != 'Q')
                        continue;
-               if (asprintf(&queuefn, "%s/Q%s", config->spooldir, de->d_name + 1) < 0)
+               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)
+               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;
 
@@ -311,7 +331,7 @@ skip_item:
                if (queuefn != NULL)
                        free(queuefn);
                if (mailfn != NULL)
-                       free(queuefn);
+                       free(mailfn);
        }
        closedir(spooldir);
        return (0);
@@ -355,6 +375,8 @@ acquirespool(struct qitem *it)
        return (0);
 
 fail:
+       if (errno == EWOULDBLOCK)
+               return (1);
        syslog(LOG_INFO, "could not acquire queue file: %m");
        return (-1);
 }
@@ -374,3 +396,46 @@ dropspool(struct queue *queue, struct qitem *keep)
                        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 + 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);
+}