the enqueuer will revoke group and regain real gid right after mkstemp.
this would have prevented the symlink/hardlink attacks against offline, and
it will avoid having to deal with new ways users can mess with it.
ok eric@, ok millert@
-/* $OpenBSD: enqueue.c,v 1.96 2015/10/06 06:04:46 gilles Exp $ */
+/* $OpenBSD: enqueue.c,v 1.97 2015/10/09 14:37:38 gilles Exp $ */
/*
* Copyright (c) 2005 Henning Brauer <henning@bulabula.org>
#include <err.h>
#include <errno.h>
#include <event.h>
+#include <grp.h>
#include <imsg.h>
#include <inttypes.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sysexits.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>
static int open_connection(void);
static int get_responses(FILE *, int);
static int send_line(FILE *, int, char *, ...);
-static int enqueue_offline(int, char *[], FILE *);
+static int enqueue_offline(int, char *[], FILE *, FILE *);
static int savedeadletter(struct passwd *, FILE *);
-extern int srv_connect(void);
+extern int srv_connected(void);
enum headerfields {
HDR_NONE,
}
int
-enqueue(int argc, char *argv[])
+enqueue(int argc, char *argv[], FILE *ofp)
{
int i, ch, tflag = 0;
char *fake_from = NULL, *buf;
/* init session */
rewind(fp);
- /* try to connect */
+ /* check if working in offline mode */
/* If the server is not running, enqueue the message offline */
- if (!srv_connect())
- return (enqueue_offline(save_argc, save_argv, fp));
+ if (!srv_connected())
+ return (enqueue_offline(save_argc, save_argv, fp, ofp));
if ((msg.fd = open_connection()) == -1)
errx(EX_UNAVAILABLE, "server too busy");
}
static int
-enqueue_offline(int argc, char *argv[], FILE *ifile)
+enqueue_offline(int argc, char *argv[], FILE *ifile, FILE *ofile)
{
- char path[PATH_MAX];
- FILE *fp;
- int i, fd, ch;
- mode_t omode;
-
- if (ckdir(PATH_SPOOL PATH_OFFLINE, 01777, 0, 0, 0) == 0)
- errx(EX_UNAVAILABLE, "error in offline directory setup");
-
- if (! bsnprintf(path, sizeof(path), "%s%s/%lld.XXXXXXXXXX", PATH_SPOOL,
- PATH_OFFLINE, (long long int) time(NULL)))
- err(EX_UNAVAILABLE, "snprintf");
-
- omode = umask(07077);
- if ((fd = mkstemp(path)) == -1 || (fp = fdopen(fd, "w+")) == NULL) {
- warn("cannot create temporary file %s", path);
- if (fd != -1)
- unlink(path);
- exit(EX_UNAVAILABLE);
- }
- umask(omode);
-
- if (fchmod(fd, 0600) == -1) {
- unlink(path);
- exit(EX_SOFTWARE);
- }
+ int i, ch;
for (i = 1; i < argc; i++) {
if (strchr(argv[i], '|') != NULL) {
warnx("%s contains illegal character", argv[i]);
- unlink(path);
exit(EX_SOFTWARE);
}
- fprintf(fp, "%s%s", i == 1 ? "" : "|", argv[i]);
+ fprintf(ofile, "%s%s", i == 1 ? "" : "|", argv[i]);
}
- fprintf(fp, "\n");
+ fprintf(ofile, "\n");
while ((ch = fgetc(ifile)) != EOF)
- if (fputc(ch, fp) == EOF) {
+ if (fputc(ch, ofile) == EOF) {
warn("write error");
- unlink(path);
exit(EX_UNAVAILABLE);
}
if (ferror(ifile)) {
warn("read error");
- unlink(path);
exit(EX_UNAVAILABLE);
}
- fclose(fp);
+ fclose(ofile);
return (EX_TEMPFAIL);
}
-/* $OpenBSD: queue_backend.c,v 1.55 2015/01/20 17:37:54 deraadt Exp $ */
+/* $OpenBSD: queue_backend.c,v 1.56 2015/10/09 14:37:38 gilles Exp $ */
/*
* Copyright (c) 2011 Gilles Chehade <gilles@poolp.org>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
+#include <grp.h>
#include <imsg.h>
#include <limits.h>
#include <inttypes.h>
queue_init(const char *name, int server)
{
struct passwd *pwq;
+ struct group *gr;
int r;
pwq = getpwnam(SMTPD_QUEUE_USER);
if (pwq == NULL)
errx(1, "unknown user %s", SMTPD_QUEUE_USER);
+ gr = getgrnam(SMTPD_QUEUE_GROUP);
+ if (gr == NULL)
+ errx(1, "unknown group %s", SMTPD_QUEUE_GROUP);
+
tree_init(&evpcache_tree);
TAILQ_INIT(&evpcache_list);
if (server) {
if (ckdir(PATH_SPOOL, 0711, 0, 0, 1) == 0)
errx(1, "error in spool directory setup");
- if (ckdir(PATH_SPOOL PATH_OFFLINE, 01777, 0, 0, 1) == 0)
+ if (ckdir(PATH_SPOOL PATH_OFFLINE, 0770, 0, gr->gr_gid, 1) == 0)
errx(1, "error in offline directory setup");
if (ckdir(PATH_SPOOL PATH_PURGE, 0700, pwq->pw_uid, 0, 1) == 0)
errx(1, "error in purge directory setup");
-/* $OpenBSD: smtpctl.c,v 1.127 2015/10/06 06:07:28 gilles Exp $ */
+/* $OpenBSD: smtpctl.c,v 1.128 2015/10/09 14:37:38 gilles Exp $ */
/*
* Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
#include <sys/tree.h>
#include <sys/un.h>
#include <sys/wait.h>
+#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#define PATH_ENCRYPT "/usr/bin/encrypt"
int srv_connect(void);
+int srv_connected(void);
void usage(void);
static void show_queue_envelope(struct envelope *, int);
static int is_encrypted_fp(FILE *);
static int is_encrypted_buffer(const char *);
static int is_gzip_buffer(const char *);
+static FILE *offline_file(void);
extern char *__progname;
int sendmail;
return (1);
}
+int
+srv_connected(void)
+{
+ return ibuf != NULL ? 1 : 0;
+}
+
+FILE *
+offline_file(void)
+{
+ char path[PATH_MAX];
+ mode_t omode;
+ int fd;
+ FILE *fp;
+
+ if (! bsnprintf(path, sizeof(path), "%s%s/%lld.XXXXXXXXXX", PATH_SPOOL,
+ PATH_OFFLINE, (long long int) time(NULL)))
+ err(EX_UNAVAILABLE, "snprintf");
+
+ omode = umask(07077);
+ if ((fd = mkstemp(path)) == -1 || (fp = fdopen(fd, "w+")) == NULL) {
+ if (fd != -1)
+ unlink(path);
+ err(EX_UNAVAILABLE, "cannot create temporary file %s", path);
+ }
+ umask(omode);
+
+ if (fchmod(fd, 0600) == -1) {
+ unlink(path);
+ err(EX_SOFTWARE, "fchmod");
+ }
+
+ return fp;
+}
+
+
static void
srv_flush(void)
{
int
main(int argc, char **argv)
{
- char *argv_mailq[] = { "show", "queue", NULL };
+ gid_t gid;
+ char *argv_mailq[] = { "show", "queue", NULL };
+ FILE *offlinefp = NULL;
+ gid = getgid();
if (strcmp(__progname, "sendmail") == 0 ||
strcmp(__progname, "send-mail") == 0) {
+ if (!srv_connect())
+ offlinefp = offline_file();
+
+ if (setresgid(gid, gid, gid) == -1)
+ err(1, "setresgid");
+
sendmail = 1;
- return (enqueue(argc, argv));
+ return (enqueue(argc, argv, offlinefp));
}
if (geteuid())
errx(1, "need root privileges");
+ if (setresgid(gid, gid, gid) == -1)
+ err(1, "setresgid");
+
cmd_install("encrypt", do_encrypt);
cmd_install("encrypt <str>", do_encrypt);
cmd_install("pause mta from <addr> for <str>", do_block_mta);
-# $OpenBSD: Makefile,v 1.38 2015/10/06 00:30:32 deraadt Exp $
+# $OpenBSD: Makefile,v 1.39 2015/10/09 14:37:38 gilles Exp $
.PATH: ${.CURDIR}/..
PROG= smtpctl
BINOWN= root
+BINGRP= _smtpq
-BINMODE?=555
+BINMODE?=2555
BINDIR= /usr/sbin
MAN= smtpctl.8
-/* $OpenBSD: smtpd-defines.h,v 1.4 2015/01/20 17:37:54 deraadt Exp $ */
+/* $OpenBSD: smtpd-defines.h,v 1.5 2015/10/09 14:37:38 gilles Exp $ */
/*
* Copyright (c) 2013 Gilles Chehade <gilles@poolp.org>
#define SMTPD_USER "_smtpd"
#define PATH_CHROOT "/var/empty"
-#define SMTPD_QUEUE_USER "_smtpq"
+#define SMTPD_QUEUE_USER "_smtpq"
+#define SMTPD_QUEUE_GROUP "_smtpq"
#define PATH_SPOOL "/var/spool/smtpd"
#define TAG_CHAR '+'
+
+
+/* sendmail compat */
+
+#define EX_OK 0
+#define EX_NOHOST 68
+#define EX_UNAVAILABLE 69
+#define EX_SOFTWARE 70
+#define EX_TEMPFAIL 75
-/* $OpenBSD: smtpd.h,v 1.475 2015/09/07 15:36:53 gilles Exp $ */
+/* $OpenBSD: smtpd.h,v 1.476 2015/10/09 14:37:38 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
/* enqueue.c */
-int enqueue(int, char **);
+int enqueue(int, char **, FILE *);
/* envelope.c */