summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;