mirror of
https://github.com/openbsd/src.git
synced 2025-01-09 22:38:01 -08:00
fsqueue queue backend will implement a filesystem queue:
- fsqueue->setup() performs the queue initialization; - fsqueue->message() controls messages; - fsqueue->envelope() controls envelopes; This commit brings the following to fsbackend: fsqueue_setup(), fsqueue_message_delete(), fsqueue_envelope_load(), fsqueue_envelope_update(), fsqueue_envelope_delete(). It also makes smtpd use the queue_backend API for these operations.
This commit is contained in:
parent
7eda92f409
commit
3f522ce892
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: bounce.c,v 1.26 2011/03/26 10:59:59 gilles Exp $ */
|
||||
/* $OpenBSD: bounce.c,v 1.27 2011/04/14 20:11:08 gilles Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Gilles Chehade <gilles@openbsd.org>
|
||||
@ -147,14 +147,14 @@ bounce_event(int fd, short event, void *p)
|
||||
|
||||
out:
|
||||
if (*ep == '2')
|
||||
queue_remove_envelope(&cc->m);
|
||||
queue_envelope_delete(cc->env, Q_QUEUE, &cc->m);
|
||||
else {
|
||||
if (*ep == '5' || *ep == '6')
|
||||
cc->m.status = S_MESSAGE_PERMFAILURE;
|
||||
else
|
||||
cc->m.status = S_MESSAGE_TEMPFAILURE;
|
||||
message_set_errormsg(&cc->m, "%s", ep);
|
||||
queue_message_update(&cc->m);
|
||||
queue_message_update(cc->env, &cc->m);
|
||||
}
|
||||
|
||||
cc->env->stats->runner.active--;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: queue_backend.c,v 1.5 2011/04/14 17:06:43 gilles Exp $ */
|
||||
/* $OpenBSD: queue_backend.c,v 1.6 2011/04/14 20:11:08 gilles Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
|
||||
@ -35,15 +35,19 @@
|
||||
#include "smtpd.h"
|
||||
#include "log.h"
|
||||
|
||||
int queue_fsqueue_message(struct smtpd *, enum queue_kind,
|
||||
/* fsqueue backend */
|
||||
int fsqueue_init(struct smtpd *);
|
||||
int fsqueue_message(struct smtpd *, enum queue_kind,
|
||||
enum queue_op, char *);
|
||||
int queue_fsqueue_envelope(struct smtpd *, enum queue_kind,
|
||||
int fsqueue_envelope(struct smtpd *, enum queue_kind,
|
||||
enum queue_op , struct message *);
|
||||
|
||||
|
||||
struct queue_backend queue_backends[] = {
|
||||
{ QT_FS,
|
||||
queue_fsqueue_message,
|
||||
queue_fsqueue_envelope }
|
||||
fsqueue_init,
|
||||
fsqueue_message,
|
||||
fsqueue_envelope }
|
||||
};
|
||||
|
||||
struct queue_backend *
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: queue_fsqueue.c,v 1.1 2011/04/14 17:06:43 gilles Exp $ */
|
||||
/* $OpenBSD: queue_fsqueue.c,v 1.2 2011/04/14 20:11:08 gilles Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
|
||||
@ -23,6 +23,8 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <imsg.h>
|
||||
#include <libgen.h>
|
||||
@ -35,21 +37,391 @@
|
||||
#include "smtpd.h"
|
||||
#include "log.h"
|
||||
|
||||
int queue_fsqueue_message(struct smtpd *, enum queue_kind,
|
||||
static char *fsqueue_getpath(enum queue_kind);
|
||||
static u_int16_t fsqueue_hash(char *);
|
||||
|
||||
static int fsqueue_envelope_load(struct smtpd *, enum queue_kind, struct message *);
|
||||
static int fsqueue_envelope_update(struct smtpd *, enum queue_kind, struct message *);
|
||||
static int fsqueue_envelope_delete(struct smtpd *, enum queue_kind, struct message *);
|
||||
|
||||
static int fsqueue_message_delete(struct smtpd *, enum queue_kind, char *);
|
||||
|
||||
int fsqueue_init(struct smtpd *);
|
||||
int fsqueue_message(struct smtpd *, enum queue_kind,
|
||||
enum queue_op, char *);
|
||||
int queue_fsqueue_envelope(struct smtpd *, enum queue_kind,
|
||||
int fsqueue_envelope(struct smtpd *, enum queue_kind,
|
||||
enum queue_op , struct message *);
|
||||
|
||||
int
|
||||
queue_fsqueue_message(struct smtpd *env, enum queue_kind qkind,
|
||||
enum queue_op qop, char *msgid)
|
||||
static char *
|
||||
fsqueue_getpath(enum queue_kind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case Q_INCOMING:
|
||||
return (PATH_INCOMING);
|
||||
|
||||
case Q_ENQUEUE:
|
||||
return (PATH_INCOMING);
|
||||
|
||||
case Q_QUEUE:
|
||||
return (PATH_QUEUE);
|
||||
|
||||
case Q_PURGE:
|
||||
return (PATH_PURGE);
|
||||
|
||||
case Q_OFFLINE:
|
||||
return (PATH_OFFLINE);
|
||||
|
||||
case Q_BOUNCE:
|
||||
return (PATH_BOUNCE);
|
||||
|
||||
default:
|
||||
fatalx("queue_fsqueue_getpath: unsupported queue kind.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u_int16_t
|
||||
fsqueue_hash(char *msgid)
|
||||
{
|
||||
u_int16_t h;
|
||||
|
||||
for (h = 5381; *msgid; msgid++)
|
||||
h = ((h << 5) + h) + *msgid;
|
||||
|
||||
return (h % DIRHASH_BUCKETS);
|
||||
}
|
||||
|
||||
static int
|
||||
fsqueue_envelope_load(struct smtpd *env, enum queue_kind qkind,
|
||||
struct message *envelope)
|
||||
{
|
||||
char pathname[MAXPATHLEN];
|
||||
char msgid[MAX_ID_SIZE];
|
||||
FILE *fp;
|
||||
|
||||
if (strlcpy(msgid, envelope->message_uid, sizeof(msgid)) >= sizeof(msgid))
|
||||
return 0;
|
||||
|
||||
*strrchr(msgid, '.') = '\0';
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s/%d/%s%s/%s",
|
||||
fsqueue_getpath(qkind),
|
||||
fsqueue_hash(msgid), msgid, PATH_ENVELOPES, envelope->message_uid))
|
||||
fatalx("fsqueue_envelope_load: snprintf");
|
||||
|
||||
fp = fopen(pathname, "r");
|
||||
if (fp == NULL) {
|
||||
if (errno == ENOENT || errno == ENFILE)
|
||||
return 0;
|
||||
fatal("fsqueue_envelope_load: fopen");
|
||||
}
|
||||
if (fread(envelope, sizeof(struct message), 1, fp) != 1)
|
||||
fatal("fsqueue_envelope_load: fread");
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fsqueue_envelope_update(struct smtpd *env, enum queue_kind qkind,
|
||||
struct message *envelope)
|
||||
{
|
||||
char temp[MAXPATHLEN];
|
||||
char dest[MAXPATHLEN];
|
||||
FILE *fp;
|
||||
u_int64_t batch_id;
|
||||
|
||||
batch_id = envelope->batch_id;
|
||||
envelope->batch_id = 0;
|
||||
|
||||
if (! bsnprintf(temp, sizeof(temp), "%s/envelope.tmp", PATH_QUEUE))
|
||||
fatalx("fsqueue_envelope_update");
|
||||
|
||||
if (! bsnprintf(dest, sizeof(dest), "%s/%d/%s%s/%s",
|
||||
fsqueue_getpath(qkind),
|
||||
fsqueue_hash(envelope->message_id),
|
||||
envelope->message_id,
|
||||
PATH_ENVELOPES, envelope->message_uid))
|
||||
fatal("fsqueue_envelope_update: snprintf");
|
||||
|
||||
fp = fopen(temp, "w");
|
||||
if (fp == NULL) {
|
||||
if (errno == ENOSPC || errno == ENFILE)
|
||||
goto tempfail;
|
||||
fatal("fsqueue_envelope_update: open");
|
||||
}
|
||||
if (fwrite(envelope, sizeof(struct message), 1, fp) != 1) {
|
||||
if (errno == ENOSPC)
|
||||
goto tempfail;
|
||||
fatal("fsqueue_envelope_update: fwrite");
|
||||
}
|
||||
if (! safe_fclose(fp))
|
||||
goto tempfail;
|
||||
|
||||
if (rename(temp, dest) == -1) {
|
||||
if (errno == ENOSPC)
|
||||
goto tempfail;
|
||||
fatal("fsqueue_envelope_update: rename");
|
||||
}
|
||||
|
||||
envelope->batch_id = batch_id;
|
||||
return 1;
|
||||
|
||||
tempfail:
|
||||
if (unlink(temp) == -1)
|
||||
fatal("fsqueue_envelope_update: unlink");
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
envelope->batch_id = batch_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
queue_fsqueue_envelope(struct smtpd *env, enum queue_kind qkind,
|
||||
enum queue_op qop, struct message *envelope)
|
||||
fsqueue_envelope_delete(struct smtpd *env, enum queue_kind qkind,
|
||||
struct message *envelope)
|
||||
{
|
||||
char pathname[MAXPATHLEN];
|
||||
u_int16_t hval;
|
||||
|
||||
hval = fsqueue_hash(envelope->message_id);
|
||||
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s/%d/%s%s/%s",
|
||||
fsqueue_getpath(qkind),
|
||||
hval, envelope->message_id, PATH_ENVELOPES,
|
||||
envelope->message_uid))
|
||||
fatal("fsqueue_envelope_delete: snprintf");
|
||||
|
||||
if (unlink(pathname) == -1)
|
||||
fatal("fsqueue_envelope_delete: unlink");
|
||||
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s/%d/%s%s", PATH_QUEUE,
|
||||
hval, envelope->message_id, PATH_ENVELOPES))
|
||||
fatal("fsqueue_envelope_delete: snprintf");
|
||||
|
||||
if (rmdir(pathname) != -1)
|
||||
fsqueue_message_delete(env, qkind, envelope->message_id);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fsqueue_message_delete(struct smtpd *env, enum queue_kind qkind, char *msgid)
|
||||
{
|
||||
char rootdir[MAXPATHLEN];
|
||||
char evpdir[MAXPATHLEN];
|
||||
char msgpath[MAXPATHLEN];
|
||||
u_int16_t hval;
|
||||
|
||||
hval = queue_hash(msgid);
|
||||
if (! bsnprintf(rootdir, sizeof(rootdir), "%s/%d/%s", PATH_QUEUE,
|
||||
hval, msgid))
|
||||
fatal("queue_delete_message: snprintf");
|
||||
|
||||
if (! bsnprintf(evpdir, sizeof(evpdir), "%s%s", rootdir,
|
||||
PATH_ENVELOPES))
|
||||
fatal("queue_delete_message: snprintf");
|
||||
|
||||
if (! bsnprintf(msgpath, sizeof(msgpath), "%s/message", rootdir))
|
||||
fatal("queue_delete_message: snprintf");
|
||||
|
||||
if (unlink(msgpath) == -1)
|
||||
fatal("queue_delete_message: unlink");
|
||||
|
||||
if (rmdir(evpdir) == -1) {
|
||||
/* It is ok to fail rmdir with ENOENT here
|
||||
* because upon successful delivery of the
|
||||
* last envelope, we remove the directory.
|
||||
*/
|
||||
if (errno != ENOENT)
|
||||
fatal("queue_delete_message: rmdir");
|
||||
}
|
||||
|
||||
if (rmdir(rootdir) == -1)
|
||||
fatal("#2 queue_delete_message: rmdir");
|
||||
|
||||
if (! bsnprintf(rootdir, sizeof(rootdir), "%s/%d", PATH_QUEUE, hval))
|
||||
fatal("queue_delete_message: snprintf");
|
||||
|
||||
rmdir(rootdir);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fsqueue_init(struct smtpd *env)
|
||||
{
|
||||
unsigned int n;
|
||||
char *paths[] = { PATH_INCOMING, PATH_ENQUEUE, PATH_QUEUE,
|
||||
PATH_PURGE, PATH_OFFLINE, PATH_BOUNCE };
|
||||
char pathname[MAXPATHLEN];
|
||||
struct stat sb;
|
||||
int ret;
|
||||
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s", PATH_SPOOL))
|
||||
fatal("snprintf");
|
||||
|
||||
if (stat(pathname, &sb) == -1) {
|
||||
if (errno != ENOENT) {
|
||||
warn("stat: %s", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mkdir(pathname, 0711) == -1) {
|
||||
warn("mkdir: %s", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (chown(pathname, 0, 0) == -1) {
|
||||
warn("chown: %s", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stat(pathname, &sb) == -1)
|
||||
err(1, "stat: %s", pathname);
|
||||
}
|
||||
|
||||
/* check if it's a directory */
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
warnx("%s is not a directory", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check that it is owned by uid/gid */
|
||||
if (sb.st_uid != 0 || sb.st_gid != 0) {
|
||||
warnx("%s must be owned by root:wheel", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check permission */
|
||||
if ((sb.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR)) != (S_IRUSR|S_IWUSR|S_IXUSR) ||
|
||||
(sb.st_mode & (S_IRGRP|S_IWGRP|S_IXGRP)) != S_IXGRP ||
|
||||
(sb.st_mode & (S_IROTH|S_IWOTH|S_IXOTH)) != S_IXOTH) {
|
||||
warnx("%s must be rwx--x--x (0711)", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
for (n = 0; n < nitems(paths); n++) {
|
||||
mode_t mode;
|
||||
uid_t owner;
|
||||
gid_t group;
|
||||
|
||||
if (!strcmp(paths[n], PATH_OFFLINE)) {
|
||||
mode = 01777;
|
||||
owner = 0;
|
||||
group = 0;
|
||||
} else {
|
||||
mode = 0700;
|
||||
owner = env->sc_pw->pw_uid;
|
||||
group = env->sc_pw->pw_gid;
|
||||
}
|
||||
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s%s", PATH_SPOOL,
|
||||
paths[n]))
|
||||
fatal("snprintf");
|
||||
|
||||
if (stat(pathname, &sb) == -1) {
|
||||
if (errno != ENOENT) {
|
||||
warn("stat: %s", pathname);
|
||||
ret = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* chmod is deffered to avoid umask effect */
|
||||
if (mkdir(pathname, 0) == -1) {
|
||||
ret = 0;
|
||||
warn("mkdir: %s", pathname);
|
||||
}
|
||||
|
||||
if (chown(pathname, owner, group) == -1) {
|
||||
ret = 0;
|
||||
warn("chown: %s", pathname);
|
||||
}
|
||||
|
||||
if (chmod(pathname, mode) == -1) {
|
||||
ret = 0;
|
||||
warn("chmod: %s", pathname);
|
||||
}
|
||||
|
||||
if (stat(pathname, &sb) == -1)
|
||||
err(1, "stat: %s", pathname);
|
||||
}
|
||||
|
||||
/* check if it's a directory */
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
ret = 0;
|
||||
warnx("%s is not a directory", pathname);
|
||||
}
|
||||
|
||||
/* check that it is owned by owner/group */
|
||||
if (sb.st_uid != owner) {
|
||||
ret = 0;
|
||||
warnx("%s is not owned by uid %d", pathname, owner);
|
||||
}
|
||||
if (sb.st_gid != group) {
|
||||
ret = 0;
|
||||
warnx("%s is not owned by gid %d", pathname, group);
|
||||
}
|
||||
|
||||
/* check permission */
|
||||
if ((sb.st_mode & 07777) != mode) {
|
||||
char mode_str[12];
|
||||
|
||||
ret = 0;
|
||||
strmode(mode, mode_str);
|
||||
mode_str[10] = '\0';
|
||||
warnx("%s must be %s (%o)", pathname, mode_str + 1, mode);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
fsqueue_message(struct smtpd *env, enum queue_kind qkind,
|
||||
enum queue_op qop, char *msgid)
|
||||
{
|
||||
switch (qop) {
|
||||
case QOP_CREATE:
|
||||
return 0;
|
||||
|
||||
case QOP_DELETE:
|
||||
return fsqueue_message_delete(env, qkind, msgid);
|
||||
|
||||
case QOP_COMMIT:
|
||||
return 0;
|
||||
|
||||
case QOP_FD_R:
|
||||
return 0;
|
||||
|
||||
case QOP_FD_RW:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
fatalx("queue_fsqueue_message: unsupported operation.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fsqueue_envelope(struct smtpd *env, enum queue_kind qkind,
|
||||
enum queue_op qop, struct message *envelope)
|
||||
{
|
||||
switch (qop) {
|
||||
case QOP_CREATE:
|
||||
return 0;
|
||||
|
||||
case QOP_DELETE:
|
||||
return fsqueue_envelope_delete(env, qkind, envelope);
|
||||
|
||||
case QOP_LOAD:
|
||||
return fsqueue_envelope_load(env, qkind, envelope);
|
||||
|
||||
case QOP_UPDATE:
|
||||
return fsqueue_envelope_update(env, qkind, envelope);
|
||||
|
||||
default:
|
||||
fatalx("queue_fsqueue_envelope: unsupported operation.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: queue_shared.c,v 1.37 2011/04/13 20:53:18 gilles Exp $ */
|
||||
/* $OpenBSD: queue_shared.c,v 1.38 2011/04/14 20:11:08 gilles Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
|
||||
@ -404,50 +404,7 @@ queue_open_message_file(char *msgid)
|
||||
}
|
||||
|
||||
void
|
||||
queue_delete_message(char *msgid)
|
||||
{
|
||||
char rootdir[MAXPATHLEN];
|
||||
char evpdir[MAXPATHLEN];
|
||||
char msgpath[MAXPATHLEN];
|
||||
u_int16_t hval;
|
||||
|
||||
hval = queue_hash(msgid);
|
||||
if (! bsnprintf(rootdir, sizeof(rootdir), "%s/%d/%s", PATH_QUEUE,
|
||||
hval, msgid))
|
||||
fatal("queue_delete_message: snprintf");
|
||||
|
||||
if (! bsnprintf(evpdir, sizeof(evpdir), "%s%s", rootdir,
|
||||
PATH_ENVELOPES))
|
||||
fatal("queue_delete_message: snprintf");
|
||||
|
||||
if (! bsnprintf(msgpath, sizeof(msgpath), "%s/message", rootdir))
|
||||
fatal("queue_delete_message: snprintf");
|
||||
|
||||
if (unlink(msgpath) == -1)
|
||||
fatal("queue_delete_message: unlink");
|
||||
|
||||
if (rmdir(evpdir) == -1) {
|
||||
/* It is ok to fail rmdir with ENOENT here
|
||||
* because upon successful delivery of the
|
||||
* last envelope, we remove the directory.
|
||||
*/
|
||||
if (errno != ENOENT)
|
||||
fatal("queue_delete_message: rmdir");
|
||||
}
|
||||
|
||||
if (rmdir(rootdir) == -1)
|
||||
fatal("#2 queue_delete_message: rmdir");
|
||||
|
||||
if (! bsnprintf(rootdir, sizeof(rootdir), "%s/%d", PATH_QUEUE, hval))
|
||||
fatal("queue_delete_message: snprintf");
|
||||
|
||||
rmdir(rootdir);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
queue_message_update(struct message *messagep)
|
||||
queue_message_update(struct smtpd *env, struct message *messagep)
|
||||
{
|
||||
messagep->flags &= ~F_MESSAGE_PROCESSING;
|
||||
messagep->status &= ~(S_MESSAGE_ACCEPTED|S_MESSAGE_REJECTED);
|
||||
@ -461,124 +418,18 @@ queue_message_update(struct message *messagep)
|
||||
|
||||
bounce_record_message(messagep, &bounce);
|
||||
}
|
||||
queue_remove_envelope(messagep);
|
||||
queue_envelope_delete(env, Q_QUEUE, messagep);
|
||||
return;
|
||||
}
|
||||
|
||||
if (messagep->status & S_MESSAGE_TEMPFAILURE) {
|
||||
messagep->status &= ~S_MESSAGE_TEMPFAILURE;
|
||||
queue_update_envelope(messagep);
|
||||
queue_envelope_update(env, Q_QUEUE, messagep);
|
||||
return;
|
||||
}
|
||||
|
||||
/* no error, remove envelope */
|
||||
queue_remove_envelope(messagep);
|
||||
}
|
||||
|
||||
int
|
||||
queue_remove_envelope(struct message *messagep)
|
||||
{
|
||||
char pathname[MAXPATHLEN];
|
||||
u_int16_t hval;
|
||||
|
||||
hval = queue_hash(messagep->message_id);
|
||||
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s/%d/%s%s/%s",
|
||||
PATH_QUEUE, hval, messagep->message_id, PATH_ENVELOPES,
|
||||
messagep->message_uid))
|
||||
fatal("queue_remove_envelope: snprintf");
|
||||
|
||||
if (unlink(pathname) == -1)
|
||||
fatal("queue_remove_envelope: unlink");
|
||||
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s/%d/%s%s", PATH_QUEUE,
|
||||
hval, messagep->message_id, PATH_ENVELOPES))
|
||||
fatal("queue_remove_envelope: snprintf");
|
||||
|
||||
if (rmdir(pathname) != -1)
|
||||
queue_delete_message(messagep->message_id);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
queue_update_envelope(struct message *messagep)
|
||||
{
|
||||
char temp[MAXPATHLEN];
|
||||
char dest[MAXPATHLEN];
|
||||
FILE *fp;
|
||||
u_int64_t batch_id;
|
||||
|
||||
batch_id = messagep->batch_id;
|
||||
messagep->batch_id = 0;
|
||||
|
||||
if (! bsnprintf(temp, sizeof(temp), "%s/envelope.tmp", PATH_QUEUE))
|
||||
fatalx("queue_update_envelope");
|
||||
|
||||
if (! bsnprintf(dest, sizeof(dest), "%s/%d/%s%s/%s", PATH_QUEUE,
|
||||
queue_hash(messagep->message_id), messagep->message_id,
|
||||
PATH_ENVELOPES, messagep->message_uid))
|
||||
fatal("queue_update_envelope: snprintf");
|
||||
|
||||
fp = fopen(temp, "w");
|
||||
if (fp == NULL) {
|
||||
if (errno == ENOSPC || errno == ENFILE)
|
||||
goto tempfail;
|
||||
fatal("queue_update_envelope: open");
|
||||
}
|
||||
if (fwrite(messagep, sizeof(struct message), 1, fp) != 1) {
|
||||
if (errno == ENOSPC)
|
||||
goto tempfail;
|
||||
fatal("queue_update_envelope: fwrite");
|
||||
}
|
||||
if (! safe_fclose(fp))
|
||||
goto tempfail;
|
||||
|
||||
if (rename(temp, dest) == -1) {
|
||||
if (errno == ENOSPC)
|
||||
goto tempfail;
|
||||
fatal("queue_update_envelope: rename");
|
||||
}
|
||||
|
||||
messagep->batch_id = batch_id;
|
||||
return 1;
|
||||
|
||||
tempfail:
|
||||
if (unlink(temp) == -1)
|
||||
fatal("queue_update_envelope: unlink");
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
messagep->batch_id = batch_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
queue_load_envelope(struct message *messagep, char *evpid)
|
||||
{
|
||||
char pathname[MAXPATHLEN];
|
||||
char msgid[MAX_ID_SIZE];
|
||||
FILE *fp;
|
||||
|
||||
if (strlcpy(msgid, evpid, sizeof(msgid)) >= sizeof(msgid))
|
||||
fatalx("queue_load_envelope: truncation");
|
||||
*strrchr(msgid, '.') = '\0';
|
||||
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s/%d/%s%s/%s", PATH_QUEUE,
|
||||
queue_hash(msgid), msgid, PATH_ENVELOPES, evpid))
|
||||
fatalx("queue_load_envelope: snprintf");
|
||||
|
||||
fp = fopen(pathname, "r");
|
||||
if (fp == NULL) {
|
||||
if (errno == ENOENT || errno == ENFILE)
|
||||
return 0;
|
||||
fatal("queue_load_envelope: fopen");
|
||||
}
|
||||
if (fread(messagep, sizeof(struct message), 1, fp) != 1)
|
||||
fatal("queue_load_envelope: fread");
|
||||
fclose(fp);
|
||||
|
||||
return 1;
|
||||
queue_envelope_delete(env, Q_QUEUE, messagep);
|
||||
}
|
||||
|
||||
u_int16_t
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ramqueue.c,v 1.1 2011/04/13 20:53:18 gilles Exp $ */
|
||||
/* $OpenBSD: ramqueue.c,v 1.2 2011/04/14 20:11:08 gilles Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
|
||||
@ -140,7 +140,8 @@ ramqueue_load(struct ramqueue *rqueue, time_t *nsched)
|
||||
while (qwalk(q, path)) {
|
||||
curtm = time(NULL);
|
||||
|
||||
if (! queue_load_envelope(&envelope, basename(path)))
|
||||
if (! queue_envelope_load(rqueue->env, Q_QUEUE,
|
||||
basename(path), &envelope))
|
||||
continue;
|
||||
if (ramqueue_expire(rqueue->env, &envelope, curtm))
|
||||
continue;
|
||||
@ -216,7 +217,7 @@ ramqueue_expire(struct smtpd *env, struct message *envelope, time_t curtm)
|
||||
envelope->expire / 60 / 60 / 24);
|
||||
bounce_record_message(envelope, &bounce);
|
||||
ramqueue_insert(&env->sc_rqueue, &bounce, time(NULL));
|
||||
queue_remove_envelope(envelope);
|
||||
queue_envelope_delete(env, Q_QUEUE, envelope);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: runner.c,v 1.96 2011/04/13 20:53:18 gilles Exp $ */
|
||||
/* $OpenBSD: runner.c,v 1.97 2011/04/14 20:11:08 gilles Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
|
||||
@ -84,7 +84,7 @@ runner_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg)
|
||||
*/
|
||||
if (m->status & S_MESSAGE_TEMPFAILURE) {
|
||||
m->status &= ~S_MESSAGE_TEMPFAILURE;
|
||||
queue_update_envelope(m);
|
||||
queue_envelope_update(env, Q_QUEUE, m);
|
||||
ramqueue_insert(&env->sc_rqueue, m, time(NULL));
|
||||
runner_setup_events(env);
|
||||
return;
|
||||
@ -107,7 +107,7 @@ runner_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg)
|
||||
/* successful delivery or permanent failure,
|
||||
* remove envelope from queue.
|
||||
*/
|
||||
queue_remove_envelope(m);
|
||||
queue_envelope_delete(env, Q_QUEUE, m);
|
||||
return;
|
||||
|
||||
case IMSG_MDA_SESS_NEW:
|
||||
@ -126,7 +126,7 @@ runner_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg)
|
||||
m = imsg->data;
|
||||
if (imsg->fd < 0 || !bounce_session(env, imsg->fd, m)) {
|
||||
m->status = 0;
|
||||
queue_update_envelope(m);
|
||||
queue_envelope_update(env, Q_QUEUE, m);
|
||||
ramqueue_insert(&env->sc_rqueue, m, time(NULL));
|
||||
runner_setup_events(env);
|
||||
return;
|
||||
@ -339,7 +339,7 @@ runner_process_envelope(struct smtpd *env, struct ramqueue_envelope *rq_evp, tim
|
||||
mda_av = env->sc_maxconn - env->stats->mda.sessions_active;
|
||||
bnc_av = env->sc_maxconn - env->stats->runner.bounces_active;
|
||||
|
||||
if (! queue_load_envelope(&envelope, rq_evp->id))
|
||||
if (! queue_envelope_load(env, Q_QUEUE, rq_evp->id, &envelope))
|
||||
return 0;
|
||||
|
||||
if (envelope.type & T_MDA_MESSAGE) {
|
||||
@ -370,7 +370,7 @@ runner_process_envelope(struct smtpd *env, struct ramqueue_envelope *rq_evp, tim
|
||||
bounce_record_message(&envelope, &bounce);
|
||||
ramqueue_insert(&env->sc_rqueue, &bounce, time(NULL));
|
||||
runner_setup_events(env);
|
||||
queue_remove_envelope(&envelope);
|
||||
queue_envelope_delete(env, Q_QUEUE, &envelope);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -395,7 +395,8 @@ runner_process_batch(struct smtpd *env, struct ramqueue_envelope *rq_evp, time_t
|
||||
switch (batch->type) {
|
||||
case T_BOUNCE_MESSAGE:
|
||||
while ((rq_evp = ramqueue_batch_first_envelope(batch))) {
|
||||
if (! queue_load_envelope(&envelope, rq_evp->id))
|
||||
if (! queue_envelope_load(env, Q_QUEUE, rq_evp->id,
|
||||
&envelope))
|
||||
return;
|
||||
envelope.lasttry = curtm;
|
||||
imsg_compose_event(env->sc_ievs[PROC_QUEUE],
|
||||
@ -416,7 +417,8 @@ runner_process_batch(struct smtpd *env, struct ramqueue_envelope *rq_evp, time_t
|
||||
case T_MDA_MESSAGE:
|
||||
|
||||
rq_evp = ramqueue_batch_first_envelope(batch);
|
||||
if (! queue_load_envelope(&envelope, rq_evp->id))
|
||||
if (! queue_envelope_load(env, Q_QUEUE, rq_evp->id,
|
||||
&envelope))
|
||||
return;
|
||||
envelope.lasttry = curtm;
|
||||
fd = queue_open_message_file(envelope.message_id);
|
||||
@ -440,7 +442,8 @@ runner_process_batch(struct smtpd *env, struct ramqueue_envelope *rq_evp, time_t
|
||||
IMSG_BATCH_CREATE, PROC_MTA, 0, -1, batch,
|
||||
sizeof *batch);
|
||||
while ((rq_evp = ramqueue_batch_first_envelope(batch))) {
|
||||
if (! queue_load_envelope(&envelope, rq_evp->id))
|
||||
if (! queue_envelope_load(env, Q_QUEUE, rq_evp->id,
|
||||
&envelope))
|
||||
return;
|
||||
envelope.lasttry = curtm;
|
||||
envelope.batch_id = batch->b_id;
|
||||
@ -502,7 +505,8 @@ runner_force_message_to_ramqueue(struct ramqueue *rqueue, char *mid)
|
||||
curtm = time(NULL);
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (valid_message_uid(dp->d_name)) {
|
||||
if (! queue_load_envelope(&envelope, dp->d_name))
|
||||
if (! queue_envelope_load(rqueue->env, Q_QUEUE, dp->d_name,
|
||||
&envelope))
|
||||
continue;
|
||||
ramqueue_insert(rqueue, &envelope, curtm);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $OpenBSD: Makefile,v 1.16 2010/10/09 22:05:35 gilles Exp $
|
||||
# $OpenBSD: Makefile,v 1.17 2011/04/14 20:11:08 gilles Exp $
|
||||
|
||||
.PATH: ${.CURDIR}/..
|
||||
|
||||
@ -17,7 +17,7 @@ CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
|
||||
CFLAGS+= -Wsign-compare -Wbounded
|
||||
CFLAGS+= -DCLIENT_NO_SSL
|
||||
|
||||
SRCS= smtpctl.c parser.c log.c enqueue.c queue_shared.c util.c client.c
|
||||
SRCS= smtpctl.c parser.c log.c enqueue.c queue_shared.c util.c client.c queue_backend.c queue_fsqueue.c
|
||||
LDADD+= -lutil -levent
|
||||
DPADD+= ${LIBUTIL} ${LIBEVENT}
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: smtpd.c,v 1.118 2011/04/14 17:06:43 gilles Exp $ */
|
||||
/* $OpenBSD: smtpd.c,v 1.119 2011/04/14 20:11:08 gilles Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
|
||||
@ -488,13 +488,13 @@ main(int argc, char *argv[])
|
||||
if ((env.sc_pw = getpwnam(SMTPD_USER)) == NULL)
|
||||
errx(1, "unknown user %s", SMTPD_USER);
|
||||
|
||||
if (!setup_spool(env.sc_pw->pw_uid, 0))
|
||||
errx(1, "invalid directory permissions");
|
||||
|
||||
env.sc_queue = queue_backend_lookup(QT_FS);
|
||||
if (env.sc_queue == NULL)
|
||||
errx(1, "could not find queue backend");
|
||||
|
||||
if (!env.sc_queue->setup(&env))
|
||||
errx(1, "invalid directory permissions");
|
||||
|
||||
log_init(debug);
|
||||
log_verbose(verbose);
|
||||
|
||||
@ -637,135 +637,6 @@ child_lookup(struct smtpd *env, pid_t pid)
|
||||
return SPLAY_FIND(childtree, &env->children, &key);
|
||||
}
|
||||
|
||||
int
|
||||
setup_spool(uid_t uid, gid_t gid)
|
||||
{
|
||||
unsigned int n;
|
||||
char *paths[] = { PATH_INCOMING, PATH_ENQUEUE, PATH_QUEUE,
|
||||
PATH_PURGE, PATH_OFFLINE, PATH_BOUNCE };
|
||||
char pathname[MAXPATHLEN];
|
||||
struct stat sb;
|
||||
int ret;
|
||||
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s", PATH_SPOOL))
|
||||
fatal("snprintf");
|
||||
|
||||
if (stat(pathname, &sb) == -1) {
|
||||
if (errno != ENOENT) {
|
||||
warn("stat: %s", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mkdir(pathname, 0711) == -1) {
|
||||
warn("mkdir: %s", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (chown(pathname, 0, 0) == -1) {
|
||||
warn("chown: %s", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stat(pathname, &sb) == -1)
|
||||
err(1, "stat: %s", pathname);
|
||||
}
|
||||
|
||||
/* check if it's a directory */
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
warnx("%s is not a directory", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check that it is owned by uid/gid */
|
||||
if (sb.st_uid != 0 || sb.st_gid != 0) {
|
||||
warnx("%s must be owned by root:wheel", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check permission */
|
||||
if ((sb.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR)) != (S_IRUSR|S_IWUSR|S_IXUSR) ||
|
||||
(sb.st_mode & (S_IRGRP|S_IWGRP|S_IXGRP)) != S_IXGRP ||
|
||||
(sb.st_mode & (S_IROTH|S_IWOTH|S_IXOTH)) != S_IXOTH) {
|
||||
warnx("%s must be rwx--x--x (0711)", pathname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
for (n = 0; n < nitems(paths); n++) {
|
||||
mode_t mode;
|
||||
uid_t owner;
|
||||
gid_t group;
|
||||
|
||||
if (!strcmp(paths[n], PATH_OFFLINE)) {
|
||||
mode = 01777;
|
||||
owner = 0;
|
||||
group = 0;
|
||||
} else {
|
||||
mode = 0700;
|
||||
owner = uid;
|
||||
group = gid;
|
||||
}
|
||||
|
||||
if (! bsnprintf(pathname, sizeof(pathname), "%s%s", PATH_SPOOL,
|
||||
paths[n]))
|
||||
fatal("snprintf");
|
||||
|
||||
if (stat(pathname, &sb) == -1) {
|
||||
if (errno != ENOENT) {
|
||||
warn("stat: %s", pathname);
|
||||
ret = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* chmod is deffered to avoid umask effect */
|
||||
if (mkdir(pathname, 0) == -1) {
|
||||
ret = 0;
|
||||
warn("mkdir: %s", pathname);
|
||||
}
|
||||
|
||||
if (chown(pathname, owner, group) == -1) {
|
||||
ret = 0;
|
||||
warn("chown: %s", pathname);
|
||||
}
|
||||
|
||||
if (chmod(pathname, mode) == -1) {
|
||||
ret = 0;
|
||||
warn("chmod: %s", pathname);
|
||||
}
|
||||
|
||||
if (stat(pathname, &sb) == -1)
|
||||
err(1, "stat: %s", pathname);
|
||||
}
|
||||
|
||||
/* check if it's a directory */
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
ret = 0;
|
||||
warnx("%s is not a directory", pathname);
|
||||
}
|
||||
|
||||
/* check that it is owned by owner/group */
|
||||
if (sb.st_uid != owner) {
|
||||
ret = 0;
|
||||
warnx("%s is not owned by uid %d", pathname, owner);
|
||||
}
|
||||
if (sb.st_gid != group) {
|
||||
ret = 0;
|
||||
warnx("%s is not owned by gid %d", pathname, group);
|
||||
}
|
||||
|
||||
/* check permission */
|
||||
if ((sb.st_mode & 07777) != mode) {
|
||||
char mode_str[12];
|
||||
|
||||
ret = 0;
|
||||
strmode(mode, mode_str);
|
||||
mode_str[10] = '\0';
|
||||
warnx("%s must be %s (%o)", pathname, mode_str + 1, mode);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
imsg_event_add(struct imsgev *iev)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: smtpd.h,v 1.209 2011/04/14 17:06:43 gilles Exp $ */
|
||||
/* $OpenBSD: smtpd.h,v 1.210 2011/04/14 20:11:08 gilles Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
|
||||
@ -931,6 +931,7 @@ enum queue_op {
|
||||
|
||||
struct queue_backend {
|
||||
enum queue_type type;
|
||||
int (*setup)(struct smtpd *);
|
||||
int (*message)(struct smtpd *, enum queue_kind, enum queue_op, char *);
|
||||
int (*envelope)(struct smtpd *, enum queue_kind, enum queue_op,
|
||||
struct message *);
|
||||
@ -1097,7 +1098,7 @@ int queue_remove_incoming_envelope(struct message *);
|
||||
int queue_commit_incoming_message(struct message *);
|
||||
int queue_open_incoming_message_file(struct message *);
|
||||
int queue_open_message_file(char *msgid);
|
||||
void queue_message_update(struct message *);
|
||||
void queue_message_update(struct smtpd *, struct message *);
|
||||
void queue_delete_message(char *);
|
||||
struct qwalk *qwalk_new(char *);
|
||||
int qwalk(struct qwalk *, char *);
|
||||
|
Loading…
Reference in New Issue
Block a user