summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgilles <gilles@openbsd.org>2015-10-09 14:37:38 +0000
committergilles <gilles@openbsd.org>2015-10-09 14:37:38 +0000
commit8351d18b7f05448e5b0f3db78cda27c47849c49e (patch)
tree342a3ed51e00b341446b60a264002b3b0ea50ed3
parentRemove evil hack. I've never seen the printf fire, and xenocara no longer (diff)
downloadwireguard-openbsd-8351d18b7f05448e5b0f3db78cda27c47849c49e.tar.xz
wireguard-openbsd-8351d18b7f05448e5b0f3db78cda27c47849c49e.zip
turn our local enqueuer setgid _smtpq and restrict access to offline queue,
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@
-rw-r--r--usr.sbin/smtpd/enqueue.c55
-rw-r--r--usr.sbin/smtpd/queue_backend.c10
-rw-r--r--usr.sbin/smtpd/smtpctl.c56
-rw-r--r--usr.sbin/smtpd/smtpctl/Makefile5
-rw-r--r--usr.sbin/smtpd/smtpd-defines.h14
-rw-r--r--usr.sbin/smtpd/smtpd.h4
6 files changed, 92 insertions, 52 deletions
diff --git a/usr.sbin/smtpd/enqueue.c b/usr.sbin/smtpd/enqueue.c
index 004a040b08f..cd65e34aa17 100644
--- a/usr.sbin/smtpd/enqueue.c
+++ b/usr.sbin/smtpd/enqueue.c
@@ -1,4 +1,4 @@
-/* $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>
@@ -28,6 +28,7 @@
#include <err.h>
#include <errno.h>
#include <event.h>
+#include <grp.h>
#include <imsg.h>
#include <inttypes.h>
#include <pwd.h>
@@ -35,7 +36,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sysexits.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>
@@ -54,10 +54,10 @@ static void rcpt_add(char *);
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,
@@ -163,7 +163,7 @@ qp_encoded_write(FILE *fp, char *buf, size_t len)
}
int
-enqueue(int argc, char *argv[])
+enqueue(int argc, char *argv[], FILE *ofp)
{
int i, ch, tflag = 0;
char *fake_from = NULL, *buf;
@@ -283,11 +283,11 @@ enqueue(int argc, char *argv[])
/* 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");
@@ -804,59 +804,32 @@ open_connection(void)
}
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);
}
diff --git a/usr.sbin/smtpd/queue_backend.c b/usr.sbin/smtpd/queue_backend.c
index 1acb938184b..ced1c81472d 100644
--- a/usr.sbin/smtpd/queue_backend.c
+++ b/usr.sbin/smtpd/queue_backend.c
@@ -1,4 +1,4 @@
-/* $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>
@@ -27,6 +27,7 @@
#include <errno.h>
#include <event.h>
#include <fcntl.h>
+#include <grp.h>
#include <imsg.h>
#include <limits.h>
#include <inttypes.h>
@@ -113,12 +114,17 @@ int
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);
@@ -134,7 +140,7 @@ queue_init(const char *name, int server)
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");
diff --git a/usr.sbin/smtpd/smtpctl.c b/usr.sbin/smtpd/smtpctl.c
index eeb9e3d3bc9..b53d2c20326 100644
--- a/usr.sbin/smtpd/smtpctl.c
+++ b/usr.sbin/smtpd/smtpctl.c
@@ -1,4 +1,4 @@
-/* $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>
@@ -27,6 +27,7 @@
#include <sys/tree.h>
#include <sys/un.h>
#include <sys/wait.h>
+#include <sys/stat.h>
#include <err.h>
#include <errno.h>
@@ -52,6 +53,7 @@
#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);
@@ -64,6 +66,7 @@ static int is_gzip_fp(FILE *);
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;
@@ -126,6 +129,41 @@ srv_connect(void)
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)
{
@@ -883,17 +921,29 @@ do_show_mta_block(int argc, struct parameter *argv)
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);
diff --git a/usr.sbin/smtpd/smtpctl/Makefile b/usr.sbin/smtpd/smtpctl/Makefile
index d83abc1cae8..08950cdf14f 100644
--- a/usr.sbin/smtpd/smtpctl/Makefile
+++ b/usr.sbin/smtpd/smtpctl/Makefile
@@ -1,11 +1,12 @@
-# $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
diff --git a/usr.sbin/smtpd/smtpd-defines.h b/usr.sbin/smtpd/smtpd-defines.h
index 870405624a9..4c3be1f2f36 100644
--- a/usr.sbin/smtpd/smtpd-defines.h
+++ b/usr.sbin/smtpd/smtpd-defines.h
@@ -1,4 +1,4 @@
-/* $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>
@@ -25,7 +25,17 @@
#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
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 30c192c8d2d..5441f12923e 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $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>
@@ -1125,7 +1125,7 @@ void dns_imsg(struct mproc *, struct imsg *);
/* enqueue.c */
-int enqueue(int, char **);
+int enqueue(int, char **, FILE *);
/* envelope.c */