struct strlist tmpfs = SLIST_HEAD_INITIALIZER(tmpfs);
struct virtusers virtusers = LIST_HEAD_INITIALIZER(virtusers);
struct authusers authusers = LIST_HEAD_INITIALIZER(authusers);
-static int daemonize = 1;
struct config *config;
-static const char *username;
-static uid_t uid;
-static const char *logident_base;
+const char *username;
+static int daemonize = 1;
+static const char *logident_base;
const char *
hostname(void)
{
struct passwd *pwd;
char *u = NULL;
+ uid_t uid;
uid = getuid();
username = check_username(getlogin(), uid);
{
char line[1000]; /* by RFC2822 */
size_t linelen;
- int error;
+ size_t error;
int had_headers = 0;
int had_from = 0;
int had_messagid = 0;
int had_date = 0;
- error = snprintf(line, sizeof(line),
+ 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, uid,
+ username, getuid(),
sender,
queue->id,
hostname(), VERSION,
rfc822date());
- if (error < 0 || (size_t)error >= sizeof(line))
- return (-1);
- if (write(queue->mailfd, line, error) != error)
+ if ((ssize_t)error < 0)
return (-1);
while (!feof(stdin)) {
had_from = 1;
snprintf(line, sizeof(line), "From: <%s>\n", sender);
}
- if ((size_t)write(queue->mailfd, line, strlen(line)) != strlen(line))
+ if (fwrite(line, strlen(line), 1, queue->mailf) != 1)
return (-1);
}
strcpy(line, "\n");
}
if (!nodot && linelen == 2 && line[0] == '.')
break;
- if ((size_t)write(queue->mailfd, line, linelen) != linelen)
+ if (fwrite(line, strlen(line), 1, queue->mailf) != 1)
return (-1);
}
- if (fsync(queue->mailfd) != 0)
- return (-1);
-
- syslog(LOG_INFO, "new mail from user=%s uid=%d envelope_from=<%s>",
- username, uid, sender);
return (0);
}
LIST_FOREACH(it, &queue->queue, next) {
/* No need to fork for the last dest */
- if (LIST_NEXT(it, next) == NULL) {
- setlogident("%s", it->queueid);
- return (it);
- }
+ if (LIST_NEXT(it, next) == NULL)
+ goto retit;
pid = fork();
switch (pid) {
*
* return and deliver mail
*/
+retit:
+ /*
+ * If necessary, aquire the queue and * mail files.
+ * If this fails, we probably were raced by another
+ * process.
+ */
setlogident("%s", it->queueid);
+ if (aquirespool(it) < 0)
+ exit(1);
+ dropspool(queue, it);
return (it);
default:
}
LIST_INIT(&bounceq.queue);
- if (add_recp(&bounceq, it->sender, "", 1) != 0)
- goto fail;
if (newspoolf(&bounceq, "") != 0)
goto fail;
syslog(LOG_ERR, "delivery failed, bouncing as %s", bounceq.id);
setlogident("%s", bounceq.id);
- bit = LIST_FIRST(&bounceq.queue);
- error = fprintf(bit->mailf,
+ error = fprintf(bounceq.mailf,
"Received: from MAILER-DAEMON\n"
"\tid %s\n"
"\tby %s (%s)\n"
"Message headers follow.");
if (error < 0)
goto fail;
- if (fflush(bit->mailf) != 0)
+
+ if (add_recp(&bounceq, it->sender, "", 1) != 0)
goto fail;
if (fseek(it->mailf, it->hdrlen, SEEK_SET) != 0)
goto fail;
if (config->features & FULLBOUNCE) {
while ((pos = fread(line, 1, sizeof(line), it->mailf)) > 0) {
- if ((size_t)write(bounceq.mailfd, line, pos) != pos)
+ if (fwrite(line, 1, pos, bounceq.mailf) != pos)
goto fail;
}
} else {
break;
if (line[0] == '\n')
break;
- if ((size_t)write(bounceq.mailfd, line, strlen(line)) != strlen(line))
+ if (fwrite(line, strlen(line), 1, bounceq.mailf) != 1)
goto fail;
}
}
- if (fsync(bounceq.mailfd) != 0)
- goto fail;
- if (linkspool(&bounceq) != 0)
+
+ if (linkspool(&bounceq, "MAILER-DAEMON") != 0)
goto fail;
/* bounce is safe */
show_queue(struct queue *queue)
{
struct qitem *it;
+ int locked = 0; /* XXX */
if (LIST_EMPTY(&queue->queue)) {
printf("Mail queue is empty\n");
"To\t: %s\n"
"--\n",
it->queueid,
- it->locked ? "*" : "",
+ locked ? "*" : "",
it->sender, it->addr);
}
}
err(1, "can not read SMTP authentication file");
if (showq) {
- load_queue(&lqueue, 1);
+ load_queue(&lqueue);
show_queue(&lqueue);
return (0);
}
if (doqueue) {
- load_queue(&lqueue, 0);
+ load_queue(&lqueue);
run_queue(&lqueue);
return (0);
}
if (readmail(&queue, sender, nodot) != 0)
err(1, "can not read mail");
- if (linkspool(&queue) != 0)
+ if (linkspool(&queue, sender) != 0)
err(1, "can not create spools");
/* From here on the mail is safe. */
char *queuefn;
char *mailfn;
char *queueid;
+ FILE *queuef;
FILE *mailf;
- int queuefd;
off_t hdrlen;
int remote;
- int locked;
};
LIST_HEAD(queueh, qitem);
struct queue {
struct queueh queue;
char *id;
- int mailfd;
+ FILE *mailf;
char *tmpf;
};
extern struct strlist tmpfs;
extern struct virtusers virtusers;
extern struct authusers authusers;
+extern const char *username;
extern char neterr[BUF_SIZE];
/* spool.c */
int newspoolf(struct queue *, const char *);
-int linkspool(struct queue *);
-void load_queue(struct queue *, int);
+int linkspool(struct queue *, const char *);
+void load_queue(struct queue *);
void delqueue(struct qitem *);
+int aquirespool(struct qitem *);
+void dropspool(struct queue *, struct qitem *);
/* local.c */
int deliver_local(struct qitem *, const char **errmsg);
int
newspoolf(struct queue *queue, const char *sender)
{
- char line[1000]; /* by RFC2822 */
char fn[PATH_MAX+1];
struct stat st;
struct stritem *t;
struct qitem *it;
- FILE *mailf;
off_t hdrlen;
- int error;
+ int fd;
if (snprintf(fn, sizeof(fn), "%s/%s", config->spooldir, "tmp_XXXXXXXXXX") <= 0)
return (-1);
- queue->mailfd = mkstemp(fn);
- if (queue->mailfd < 0)
- return (-1);
- if (flock(queue->mailfd, LOCK_EX) == -1)
+ fd = mkstemp(fn);
+ if (fd < 0)
return (-1);
-
+ if (flock(fd, LOCK_EX) == -1)
+ goto fail;
queue->tmpf = strdup(fn);
if (queue->tmpf == NULL)
goto fail;
- error = snprintf(line, sizeof(line), "%s\n", sender);
- if (error < 0 || (size_t)error >= sizeof(line)) {
- errno = E2BIG;
+ /*
+ * Assign queue id
+ */
+ if (fstat(fd, &st) != 0)
goto fail;
- }
- if (write(queue->mailfd, line, error) != error)
+ if (asprintf(&queue->id, "%"PRIxMAX, st.st_ino) < 0)
goto fail;
- hdrlen = lseek(queue->mailfd, 0, SEEK_CUR);
+ queue->mailf = fdopen(fd, "r+");
+ if (queue->mailf == NULL)
+ goto fail;
- mailf = fdopen(queue->mailfd, "r+");
- if (mailf == NULL)
+ if (fprintf(queue->mailf, "%s\n", sender) < 0)
goto fail;
+
+ hdrlen = ftello(queue->mailf);
+
LIST_FOREACH(it, &queue->queue, next) {
- it->mailf = mailf;
+ it->mailf = queue->mailf;
it->hdrlen = hdrlen;
}
- /*
- * Assign queue id
- */
- if (fstat(queue->mailfd, &st) != 0)
- return (-1);
- if (asprintf(&queue->id, "%"PRIxMAX, st.st_ino) < 0)
- return (-1);
-
t = malloc(sizeof(*t));
if (t != NULL) {
t->str = queue->tmpf;
return (0);
fail:
- close(queue->mailfd);
+ if (queue->mailf != NULL)
+ fclose(queue->mailf);
+ close(fd);
unlink(fn);
return (-1);
}
int
-linkspool(struct queue *queue)
+linkspool(struct queue *queue, const char *sender)
{
char line[1000]; /* by RFC2822 */
struct stat st;
- int error;
+ size_t error;
int queuefd;
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(), sender);
+
LIST_FOREACH(it, &queue->queue, next) {
if (asprintf(&it->queueid, "%s.%"PRIxPTR, queue->id, (uintptr_t)it) <= 0)
goto delfiles;
goto delfiles;
error = snprintf(line, sizeof(line), "%s %s\n", it->queueid, it->addr);
- if (error < 0 || (size_t)error >= sizeof(line))
+ if ((ssize_t)error < 0 || error >= sizeof(line))
goto delfiles;
+
queuefd = open_locked(it->queuefn, O_CREAT|O_EXCL|O_RDWR, 0600);
if (queuefd == -1)
goto delfiles;
- if (write(queuefd, line, error) != error) {
- close(queuefd);
+ it->queuef = fdopen(queuefd, "w+");
+ if (it->queuef == NULL)
+ goto delfiles;
+
+ if (fwrite(line, strlen(line), 1, it->queuef) != 1)
+ goto delfiles;
+ if (fflush(it->queuef) != 0 || fsync(fileno(it->queuef)) != 0)
goto delfiles;
- }
- it->queuefd = queuefd;
if (link(queue->tmpf, it->mailfn) != 0)
goto delfiles;
}
void
-load_queue(struct queue *queue, int ignorelock)
+load_queue(struct queue *queue)
{
struct qitem *it;
//struct queue queue, itmqueue;
char *queuefn;
char *mailfn;
off_t hdrlen;
- int fd;
- int locked;
LIST_INIT(&queue->queue);
err(1, "reading queue");
while ((de = readdir(spooldir)) != NULL) {
- fd = -1;
sender = NULL;
queuef = NULL;
mailf = NULL;
queueid = NULL;
queuefn = NULL;
- locked = 1;
LIST_INIT(&itmqueue.queue);
/* ignore temp files */
if (asprintf(&mailfn, "%s/M%s", config->spooldir, de->d_name + 1) < 0)
goto fail;
- fd = open_locked(queuefn, O_RDONLY|O_NONBLOCK);
- if (ignorelock) {
- if (fd < 0)
- fd = open(queuefn, O_RDONLY);
- else
- locked = 0;
- }
- if (fd < 0) {
- /* Ignore locked files */
- if (errno == EWOULDBLOCK)
- continue;
- goto skip_item;
- }
-
mailf = fopen(mailfn, "r");
if (mailf == NULL)
goto skip_item;
hdrlen = ftell(mailf);
- queuef = fdopen(fd, "r");
+ queuef = fopen(queuefn, "r");
if (queuef == NULL)
goto skip_item;
if (add_recp(&itmqueue, addr, sender, 0) != 0)
goto skip_item;
+
it = LIST_FIRST(&itmqueue.queue);
- it->queuefd = fd;
- it->mailf = mailf;
it->queueid = queueid;
it->queuefn = queuefn;
it->mailfn = mailfn;
it->hdrlen = hdrlen;
- it->locked = locked;
LIST_INSERT_HEAD(&queue->queue, it, next);
+ if (queuef != NULL)
+ fclose(queuef);
+ if (mailf != NULL)
+ fclose(mailf);
continue;
skip_item:
fclose(queuef);
if (mailf != NULL)
fclose(mailf);
- close(fd);
}
closedir(spooldir);
return;
delqueue(struct qitem *it)
{
unlink(it->queuefn);
- close(it->queuefd);
unlink(it->mailfn);
- fclose(it->mailf);
+ if (it->queuef != NULL)
+ fclose(it->queuef);
+ if (it->mailf != NULL)
+ fclose(it->mailf);
free(it);
}
+
+int
+aquirespool(struct qitem *it)
+{
+ int queuefd;
+
+ if (it->queuef == NULL) {
+ queuefd = open_locked(it->queuefn, O_RDWR);
+ if (queuefd < 0)
+ return (-1);
+ it->queuef = fdopen(queuefd, "r+");
+ if (it->queuef == NULL)
+ return (-1);
+ }
+
+ if (it->mailf == NULL) {
+ it->mailf = fopen(it->mailfn, "r");
+ if (it->mailf == NULL)
+ return (-1);
+ }
+
+ return (0);
+}
+
+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);
+ }
+}