summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgilles <gilles@openbsd.org>2011-05-17 18:54:32 +0000
committergilles <gilles@openbsd.org>2011-05-17 18:54:32 +0000
commit2ddfddf2e07ae121983bf6337e4fc3c5fe453cd2 (patch)
treec372e5ca5fe7d39c039c950ba23f1fcb84d5cbeb
parentUse the same define checks as used in machdep.c for the trampoline code. (diff)
downloadwireguard-openbsd-2ddfddf2e07ae121983bf6337e4fc3c5fe453cd2.tar.xz
wireguard-openbsd-2ddfddf2e07ae121983bf6337e4fc3c5fe453cd2.zip
introduce new user_backend API for smtpd to lookup the users it wants to
deliver mail to. the only backend supported for now is USER_GETPWNAM and it is not yet possible to switch to an alternate backend. yes this means that we're very close from smtpd being able to handle fully virtual accounts for both incoming and outgoing messages.
-rw-r--r--usr.sbin/smtpd/lka_session.c37
-rw-r--r--usr.sbin/smtpd/smtpd.c47
-rw-r--r--usr.sbin/smtpd/smtpd.h32
-rw-r--r--usr.sbin/smtpd/smtpd/Makefile4
-rw-r--r--usr.sbin/smtpd/user_backend.c107
-rw-r--r--usr.sbin/smtpd/util.c10
6 files changed, 192 insertions, 45 deletions
diff --git a/usr.sbin/smtpd/lka_session.c b/usr.sbin/smtpd/lka_session.c
index 5de03d265f4..c2d280cabfc 100644
--- a/usr.sbin/smtpd/lka_session.c
+++ b/usr.sbin/smtpd/lka_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lka_session.c,v 1.3 2011/05/16 21:52:53 gilles Exp $ */
+/* $OpenBSD: lka_session.c,v 1.4 2011/05/17 18:54:32 gilles Exp $ */
/*
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
@@ -29,7 +29,6 @@
#include <errno.h>
#include <event.h>
#include <imsg.h>
-#include <pwd.h>
#include <resolv.h>
#include <signal.h>
#include <stdio.h>
@@ -75,9 +74,10 @@ lka_session(struct submit_status *ss)
int
lka_session_envelope_expand(struct lka_session *lks, struct envelope *ep)
{
- struct passwd *pw;
char *user;
char *sep;
+ struct user_backend *ub;
+ struct user u;
char username[MAX_LOCALPART_SIZE];
/* remote delivery, no need to process further */
@@ -108,17 +108,20 @@ lka_session_envelope_expand(struct lka_session *lks, struct envelope *ep)
return 1;
}
- if ((pw = getpwnam(username)) == NULL)
+ bzero(&u, sizeof (u));
+ ub = user_backend_lookup(USER_GETPWNAM);
+ if (! ub->getbyname(&u, username))
return 0;
- (void)strlcpy(ep->delivery.agent.mda.as_user, pw->pw_name,
+ (void)strlcpy(ep->delivery.agent.mda.as_user, u.username,
sizeof (ep->delivery.agent.mda.as_user));
ep->delivery.type = D_MDA;
switch (ep->rule.r_action) {
case A_MBOX:
ep->delivery.agent.mda.method = A_MBOX;
- (void)strlcpy(ep->delivery.agent.mda.to.user, pw->pw_name,
+ (void)strlcpy(ep->delivery.agent.mda.to.user,
+ u.username,
sizeof (ep->delivery.agent.mda.to.user));
break;
case A_MAILDIR:
@@ -133,7 +136,7 @@ lka_session_envelope_expand(struct lka_session *lks, struct envelope *ep)
fatalx("lka_session_envelope_expand: unexpected rule action");
return 0;
}
- lka_session_request_forwardfile(lks, ep, pw->pw_name);
+ lka_session_request_forwardfile(lks, ep, u.username);
return 1;
}
@@ -474,7 +477,8 @@ lka_session_expand_format(char *buf, size_t len, struct envelope *ep)
{
char *p, *pbuf;
size_t ret, lret = 0;
- struct passwd *pw;
+ struct user_backend *ub;
+ struct user u;
char lbuffer[MAX_RULEBUFFER_LEN];
struct delivery *dlv = &ep->delivery;
@@ -486,11 +490,13 @@ lka_session_expand_format(char *buf, size_t len, struct envelope *ep)
++p, len -= lret, pbuf += lret, ret += lret) {
if (p == buf && *p == '~') {
if (*(p + 1) == '/' || *(p + 1) == '\0') {
- pw = getpwnam(dlv->agent.mda.as_user);
- if (pw == NULL)
+
+ bzero(&u, sizeof (u));
+ ub = user_backend_lookup(USER_GETPWNAM);
+ if (! ub->getbyname(&u, dlv->agent.mda.as_user))
return 0;
- lret = strlcat(pbuf, pw->pw_dir, len);
+ lret = strlcat(pbuf, u.directory, len);
if (lret >= len)
return 0;
continue;
@@ -509,12 +515,13 @@ lka_session_expand_format(char *buf, size_t len, struct envelope *ep)
if (delim == NULL)
goto copy;
*delim = '\0';
-
- pw = getpwnam(username);
- if (pw == NULL)
+
+ bzero(&u, sizeof (u));
+ ub = user_backend_lookup(USER_GETPWNAM);
+ if (! ub->getbyname(&u, username))
return 0;
- lret = strlcat(pbuf, pw->pw_dir, len);
+ lret = strlcat(pbuf, u.directory, len);
if (lret >= len)
return 0;
p += strlen(username);
diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c
index 2e4d1002cf8..a8333ed159f 100644
--- a/usr.sbin/smtpd/smtpd.c
+++ b/usr.sbin/smtpd/smtpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.c,v 1.125 2011/05/17 16:42:06 gilles Exp $ */
+/* $OpenBSD: smtpd.c,v 1.126 2011/05/17 18:54:32 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -687,16 +687,18 @@ forkmda(struct imsgev *iev, u_int32_t id,
struct deliver *deliver)
{
char ebuf[128], sfn[32];
- struct passwd *pw;
+ struct user_backend *ub;
+ struct user u;
struct child *child;
pid_t pid;
int n, allout, pipefd[2];
log_debug("forkmda: to %s as %s", deliver->to, deliver->user);
+ bzero(&u, sizeof (u));
+ ub = user_backend_lookup(USER_GETPWNAM);
errno = 0;
- pw = getpwnam(deliver->user);
- if (pw == NULL) {
+ if (! ub->getbyname(&u, deliver->user)) {
n = snprintf(ebuf, sizeof ebuf, "getpwnam: %s",
errno ? strerror(errno) : "no such user");
imsg_compose_event(iev, IMSG_MDA_DONE, id, 0, -1, ebuf, n + 1);
@@ -704,7 +706,7 @@ forkmda(struct imsgev *iev, u_int32_t id,
}
/* lower privs early to allow fork fail due to ulimit */
- if (seteuid(pw->pw_uid) < 0)
+ if (seteuid(u.uid) < 0)
fatal("cannot lower privileges");
if (pipe(pipefd) < 0) {
@@ -757,7 +759,7 @@ forkmda(struct imsgev *iev, u_int32_t id,
#define error(m) { perror(m); _exit(1); }
if (seteuid(0) < 0)
error("forkmda: cannot restore privileges");
- if (chdir(pw->pw_dir) < 0 && chdir("/") < 0)
+ if (chdir(u.directory) < 0 && chdir("/") < 0)
error("chdir");
if (dup2(pipefd[0], STDIN_FILENO) < 0 ||
dup2(allout, STDOUT_FILENO) < 0 ||
@@ -765,9 +767,9 @@ forkmda(struct imsgev *iev, u_int32_t id,
error("forkmda: dup2");
if (closefrom(STDERR_FILENO + 1) < 0)
error("closefrom");
- if (setgroups(1, &pw->pw_gid) ||
- setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
- setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ if (setgroups(1, &u.gid) ||
+ setresgid(u.gid, u.gid, u.gid) ||
+ setresuid(u.uid, u.uid, u.uid))
error("forkmda: cannot drop privileges");
if (setsid() < 0)
error("setsid");
@@ -888,7 +890,8 @@ static int
parent_enqueue_offline(char *runner_path)
{
char path[MAXPATHLEN];
- struct passwd *pw;
+ struct user_backend *ub;
+ struct user u;
struct stat sb;
pid_t pid;
@@ -916,8 +919,10 @@ parent_enqueue_offline(char *runner_path)
fatal("parent_enqueue_offline: chflags");
}
+ ub = user_backend_lookup(USER_GETPWNAM);
+ bzero(&u, sizeof (u));
errno = 0;
- if ((pw = getpwuid(sb.st_uid)) == NULL) {
+ if (! ub->getbyuid(&u, sb.st_uid)) {
log_warn("parent_enqueue_offline: getpwuid for uid %d failed",
sb.st_uid);
unlink(path);
@@ -944,9 +949,9 @@ parent_enqueue_offline(char *runner_path)
bzero(&args, sizeof(args));
- if (setgroups(1, &pw->pw_gid) ||
- setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
- setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) ||
+ if (setgroups(1, &u.gid) ||
+ setresgid(u.gid, u.gid, u.gid) ||
+ setresuid(u.uid, u.uid, u.uid) ||
closefrom(STDERR_FILENO + 1) == -1) {
unlink(path);
_exit(1);
@@ -958,7 +963,7 @@ parent_enqueue_offline(char *runner_path)
}
unlink(path);
- if (chdir(pw->pw_dir) == -1 && chdir("/") == -1)
+ if (chdir(u.directory) == -1 && chdir("/") == -1)
_exit(1);
if (setsid() == -1 ||
@@ -1033,15 +1038,17 @@ queueing_done(void)
static int
parent_forward_open(char *username)
{
- struct passwd *pw;
+ struct user_backend *ub;
+ struct user u;
char pathname[MAXPATHLEN];
int fd;
- pw = getpwnam(username);
- if (pw == NULL)
+ bzero(&u, sizeof (u));
+ ub = user_backend_lookup(USER_GETPWNAM);
+ if (! ub->getbyname(&u, username))
return -1;
- if (! bsnprintf(pathname, sizeof (pathname), "%s/.forward", pw->pw_dir))
+ if (! bsnprintf(pathname, sizeof (pathname), "%s/.forward", u.directory))
fatal("snprintf");
fd = open(pathname, O_RDONLY);
@@ -1052,7 +1059,7 @@ parent_forward_open(char *username)
return -1;
}
- if (! secure_file(fd, pathname, pw, 1)) {
+ if (! secure_file(fd, pathname, u.directory, u.uid, 1)) {
log_warnx("%s: unsecure file", pathname);
close(fd);
return -1;
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 187b56f16e0..eeca47252b0 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.223 2011/05/17 16:42:06 gilles Exp $ */
+/* $OpenBSD: smtpd.h,v 1.224 2011/05/17 18:54:32 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -914,7 +914,7 @@ struct queue_backend {
};
-/* queue structures */
+/* auth structures */
enum auth_type {
AUTH_INVALID=0,
AUTH_BSD,
@@ -927,6 +927,28 @@ struct auth_backend {
};
+/* user structures */
+enum user_type {
+ USER_INVALID=0,
+ USER_GETPWNAM,
+};
+
+#define MAXPASSWORDLEN 128
+struct user {
+ char username[MAXLOGNAME];
+ char directory[MAXPATHLEN];
+ char password[MAXPASSWORDLEN];
+ uid_t uid;
+ gid_t gid;
+};
+
+struct user_backend {
+ enum user_type type;
+ int (*getbyname)(struct user *, char *);
+ int (*getbyuid)(struct user *, uid_t);
+};
+
+
extern struct smtpd *env;
extern void (*imsg_callback)(struct imsgev *, struct imsg *);
@@ -1126,6 +1148,10 @@ int ssl_ctx_use_private_key(void *, char *, off_t);
int ssl_ctx_use_certificate_chain(void *, char *, off_t);
+/* user_backend.c */
+struct user_backend *user_backend_lookup(enum user_type);
+
+
/* util.c */
typedef struct arglist arglist;
struct arglist {
@@ -1146,7 +1172,7 @@ char *ss_to_text(struct sockaddr_storage *);
int valid_message_id(char *);
int valid_message_uid(char *);
char *time_to_text(time_t);
-int secure_file(int, char *, struct passwd *, int);
+int secure_file(int, char *, char *, uid_t, int);
void lowercase(char *, char *, size_t);
void envelope_set_errormsg(struct envelope *, char *, ...);
char *envelope_get_errormsg(struct envelope *);
diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile
index 742a1b05c6f..83d3e4f4cb4 100644
--- a/usr.sbin/smtpd/smtpd/Makefile
+++ b/usr.sbin/smtpd/smtpd/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.26 2011/05/17 16:42:06 gilles Exp $
+# $OpenBSD: Makefile,v 1.27 2011/05/17 18:54:32 gilles Exp $
PROG= smtpd
SRCS= aliases.c auth_backend.c bounce.c client.c \
@@ -8,7 +8,7 @@ SRCS= aliases.c auth_backend.c bounce.c client.c \
queue_shared.c ruleset.c runner.c smtp.c smtp_session.c \
smtpd.c ssl.c ssl_privsep.c util.c asr.c print.c pack.c \
dname.c res_random.c sockaddr.c ramqueue.c \
- queue_backend.c queue_fsqueue.c
+ queue_backend.c queue_fsqueue.c user_backend.c
MAN= smtpd.8 smtpd.conf.5
BINDIR= /usr/sbin
diff --git a/usr.sbin/smtpd/user_backend.c b/usr.sbin/smtpd/user_backend.c
new file mode 100644
index 00000000000..bd874629fd6
--- /dev/null
+++ b/usr.sbin/smtpd/user_backend.c
@@ -0,0 +1,107 @@
+/* $OpenBSD: user_backend.c,v 1.1 2011/05/17 18:54:32 gilles Exp $ */
+
+/*
+ * Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <event.h>
+#include <imsg.h>
+#include <libgen.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "smtpd.h"
+#include "log.h"
+
+int user_getpw_ret(struct user *, struct passwd *); /* helper */
+int user_getpwnam(struct user *, char *);
+int user_getpwuid(struct user *, uid_t);
+struct user_backend *user_backend_lookup(enum user_type);
+
+struct user_backend user_backends[] = {
+ { USER_GETPWNAM, user_getpwnam, user_getpwuid }
+};
+
+struct user_backend *
+user_backend_lookup(enum user_type type)
+{
+ u_int8_t i;
+
+ for (i = 0; i < nitems(user_backends); ++i)
+ if (user_backends[i].type == type)
+ break;
+
+ if (i == nitems(user_backends))
+ fatalx("invalid user type");
+
+ return &user_backends[i];
+}
+
+
+
+int
+user_getpw_ret(struct user *u, struct passwd *pw)
+{
+ if (strlcpy(u->username, pw->pw_name, sizeof (u->username))
+ >= sizeof (u->username))
+ return 0;
+
+ if (strlcpy(u->password, pw->pw_passwd, sizeof (u->password))
+ >= sizeof (u->password))
+ return 0;
+
+ if (strlcpy(u->directory, pw->pw_dir, sizeof (u->directory))
+ >= sizeof (u->directory))
+ return 0;
+
+ u->uid = pw->pw_uid;
+ u->gid = pw->pw_gid;
+
+ return 1;
+}
+
+int
+user_getpwnam(struct user *u, char *username)
+{
+ struct passwd *pw;
+
+ pw = getpwnam(username);
+ if (pw == NULL)
+ return 0;
+
+ return user_getpw_ret(u, pw);
+}
+
+int
+user_getpwuid(struct user *u, uid_t uid)
+{
+ struct passwd *pw;
+
+ pw = getpwuid(uid);
+ if (pw == NULL)
+ return 0;
+
+ return user_getpw_ret(u, pw);
+}
diff --git a/usr.sbin/smtpd/util.c b/usr.sbin/smtpd/util.c
index 5bdebec267d..afa5eef128f 100644
--- a/usr.sbin/smtpd/util.c
+++ b/usr.sbin/smtpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.46 2011/05/16 21:05:52 gilles Exp $ */
+/* $OpenBSD: util.c,v 1.47 2011/05/17 18:54:32 gilles Exp $ */
/*
* Copyright (c) 2000,2001 Markus Friedl. All rights reserved.
@@ -252,7 +252,7 @@ time_to_text(time_t when)
* Check file for security. Based on usr.bin/ssh/auth.c.
*/
int
-secure_file(int fd, char *path, struct passwd *pw, int mayread)
+secure_file(int fd, char *path, char *userdir, uid_t uid, int mayread)
{
char buf[MAXPATHLEN];
char homedir[MAXPATHLEN];
@@ -262,13 +262,13 @@ secure_file(int fd, char *path, struct passwd *pw, int mayread)
if (realpath(path, buf) == NULL)
return 0;
- if (realpath(pw->pw_dir, homedir) == NULL)
+ if (realpath(userdir, homedir) == NULL)
homedir[0] = '\0';
/* Check the open file to avoid races. */
if (fstat(fd, &st) < 0 ||
!S_ISREG(st.st_mode) ||
- (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+ (st.st_uid != 0 && st.st_uid != uid) ||
(st.st_mode & (mayread ? 022 : 066)) != 0)
return 0;
@@ -279,7 +279,7 @@ secure_file(int fd, char *path, struct passwd *pw, int mayread)
strlcpy(buf, cp, sizeof(buf));
if (stat(buf, &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+ (st.st_uid != 0 && st.st_uid != uid) ||
(st.st_mode & 022) != 0)
return 0;