From: gilles Date: Fri, 9 Oct 2015 14:37:38 +0000 (+0000) Subject: turn our local enqueuer setgid _smtpq and restrict access to offline queue, X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=8351d18b7f05448e5b0f3db78cda27c47849c49e;p=openbsd 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@ --- 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 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -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 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -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 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -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 ", do_encrypt); cmd_install("pause mta from for ", 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 @@ -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 @@ -1125,7 +1125,7 @@ void dns_imsg(struct mproc *, struct imsg *); /* enqueue.c */ -int enqueue(int, char **); +int enqueue(int, char **, FILE *); /* envelope.c */