File user_deny_db-once.patch of Package cyrus-imapd.import4736
From 1d6f0eedfb3a31695053ef0babe26e92b5fbbb2a Mon Sep 17 00:00:00 2001
From: murch <murch>
Date: Thu, 22 Apr 2010 17:29:53 +0000
Subject: Modified user_deny.db code to open database once at service startup time.
8 files changed, 325 insertions(+), 127 deletions(-)
diff --git a/imap/Makefile.in b/imap/Makefile.in
index 3dd823c..e9c5790 100644
--- a/imap/Makefile.in
+++ b/imap/Makefile.in
@@ -103,7 +103,7 @@ LOBJS= append.o mailbox.o mboxlist.o mupdate-client.o mboxname.o message.o \
annotate.o search_engines.o squat.o squat_internal.o mbdump.o \
imapparse.o telemetry.o user.o notify.o idle.o quota_db.o \
sync_log.o autosieve.o $(SEEN) mboxkey.o backend.o tls.o message_guid.o \
- statuscache_db.o
+ statuscache_db.o userdeny_db.o
IMAPDOBJS=pushstats.o imapd.o proxy.o imap_proxy.o index.o version.o
diff --git a/imap/global.c b/imap/global.c
index 30412b6..940f592 100644
--- a/imap/global.c
+++ b/imap/global.c
@@ -72,8 +72,8 @@
#include "mupdate_err.h"
#include "mutex.h"
#include "prot.h" /* for PROT_BUFSIZE */
+#include "userdeny.h"
#include "util.h"
-#include "wildmat.h"
#include "xmalloc.h"
#include "xstrlcpy.h"
#include "xstrlcat.h"
@@ -531,124 +531,6 @@ static int acl_ok(const char *user, struct auth_state *authstate)
return r;
}
-#define DENYDB config_userdeny_db
-#define FNAME_USERDENYDB "/user_deny.db"
-#define USERDENY_VERSION 2
-
-/*
- * access_ok() checks to see if 'user' is allowed access to 'service'
- * Returns 1 if so, 0 if not.
- */
-int access_ok(const char *user, const char *service, char *msgbuf, int size)
-{
- static char *fname = NULL;
- struct db *db = NULL;
- int r, ret = 1; /* access always granted by default */
-
- if (!fname) {
- /* create path to database */
- fname = xmalloc(strlen(config_dir) + sizeof(FNAME_USERDENYDB) + 1);
- strcpy(fname, config_dir);
- strcat(fname, FNAME_USERDENYDB);
- }
-
- /* try to open database */
- r = DENYDB->open(fname, 0, &db);
- if (r) {
- /* ignore non-existent DB, report all other errors */
- if (errno != ENOENT) {
- syslog(LOG_WARNING, "DENYDB_ERROR: error opening '%s': %s",
- fname, cyrusdb_strerror(r));
- }
-
- } else {
- /* fetch entry for user */
- const char *data = NULL;
- int datalen;
-
- syslog(LOG_DEBUG, "fetching user_deny.db entry for '%s'", user);
- do {
- r = DENYDB->fetch(db, user, strlen(user), &data, &datalen, NULL);
- } while (r == CYRUSDB_AGAIN);
-
- if (r || !data || !datalen) {
- /* ignore non-existent/empty entry, report all other errors */
- if (r != CYRUSDB_NOTFOUND) {
- syslog(LOG_WARNING,
- "DENYDB_ERROR: error reading entry '%s': %s",
- user, cyrusdb_strerror(r));
- }
- } else {
- /* parse the data */
- char *buf, *wild;
- unsigned long version;
-
- buf = xstrndup(data, datalen); /* use a working copy */
-
- /* check version */
- if (((version = strtoul(buf, &wild, 10)) < 1) ||
- (version > USERDENY_VERSION)) {
- syslog(LOG_WARNING,
- "DENYDB_ERROR: invalid version for entry '%s': %lu",
- user, version);
- } else if (*wild++ != '\t') {
- syslog(LOG_WARNING,
- "DENYDB_ERROR: missing wildmat for entry '%s'", user);
- } else {
- char *pat, *msg = "Access to this service has been blocked";
- int not;
-
- /* check if we have a deny message */
- switch (version) {
- case USERDENY_VERSION:
- if ((msg = strchr(wild, '\t'))) *msg++ = '\0';
- break;
- }
-
- /* scan wildmat right to left for a match against our service */
- syslog(LOG_DEBUG, "wild: '%s' service: '%s'", wild, service);
- do {
- /* isolate next pattern */
- if ((pat = strrchr(wild, ','))) {
- *pat++ = '\0';
- } else {
- pat = wild;
- }
-
- /* XXX trim leading & trailing whitespace? */
-
- /* is it a negated pattern? */
- not = (*pat == '!');
- if (not) ++pat;
-
- syslog(LOG_DEBUG, "pat %d:'%s'", not, pat);
-
- /* see if pattern matches our service */
- if (wildmat(service, pat)) {
- /* match ==> we're done */
- ret = not;
- if (msgbuf) strlcpy(msgbuf, msg, size);
- break;
- }
-
- /* continue until we reach head of wildmat */
- } while (pat != wild);
- }
-
- free(buf);
- }
-
-
- r = DENYDB->close(db);
- if (r) {
- syslog(LOG_WARNING, "DENYDB_ERROR: error closing: %s",
- cyrusdb_strerror(r));
- }
- }
-
- return ret;
-}
-
/* should we allow users to proxy? return SASL_OK if yes,
SASL_BADAUTH otherwise */
int mysasl_proxy_policy(sasl_conn_t *conn,
@@ -704,7 +586,7 @@ int mysasl_proxy_policy(sasl_conn_t *conn,
}
/* is requested_user denied access? authenticated admins are exempt */
- if (!userisadmin && !access_ok(requested_user, config_ident, NULL, 0)) {
+ if (!userisadmin && userdeny(requested_user, config_ident, NULL, 0)) {
syslog(LOG_ERR, "user '%s' denied access to service '%s'",
requested_user, config_ident);
sasl_seterror(conn, SASL_NOLOG,
diff --git a/imap/global.h b/imap/global.h
index ec3d54e..791c5c7 100644
--- a/imap/global.h
+++ b/imap/global.h
@@ -160,5 +160,6 @@ extern struct cyrusdb_backend *config_duplicate_db;
extern struct cyrusdb_backend *config_tlscache_db;
extern struct cyrusdb_backend *config_ptscache_db;
extern struct cyrusdb_backend *config_statuscache_db;
+extern struct cyrusdb_backend *config_userdeny_db;
#endif /* INCLUDED_GLOBAL_H */
diff --git a/imap/imapd.c b/imap/imapd.c
index ca837b9..3ebeb16 100644
--- a/imap/imapd.c
+++ b/imap/imapd.c
@@ -101,6 +101,7 @@
#include "telemetry.h"
#include "tls.h"
#include "user.h"
+#include "userdeny.h"
#include "util.h"
#include "version.h"
#include "xmalloc.h"
@@ -679,6 +680,10 @@ int service_init(int argc, char **argv, char **envp)
quotadb_init(0);
quotadb_open(NULL);
+ /* open the user deny db */
+ denydb_init(0);
+ denydb_open(NULL);
+
/* setup for sending IMAP IDLE notifications */
idle_enabled();
@@ -932,6 +937,9 @@ void shut_down(int code)
quotadb_close();
quotadb_done();
+ denydb_close();
+ denydb_done();
+
annotatemore_close();
annotatemore_done();
@@ -1104,7 +1112,7 @@ void cmdloop()
/* Check for shutdown file */
if ( !imapd_userisadmin && imapd_userid &&
(shutdown_file(shut, sizeof(shut)) ||
- !access_ok(imapd_userid, config_ident, shut, sizeof(shut)))) {
+ userdeny(imapd_userid, config_ident, shut, sizeof(shut)))) {
for (p = shut; *p == '['; p++); /* can't have [ be first char */
prot_printf(imapd_out, "* BYE [ALERT] %s\r\n", p);
shut_down(0);
@@ -2738,7 +2746,7 @@ void cmd_idle(char *tag)
if (!imapd_userisadmin &&
(shutdown_file(buf, sizeof(buf)) ||
(imapd_userid &&
- !access_ok(imapd_userid, config_ident, buf, sizeof(buf))))) {
+ userdeny(imapd_userid, config_ident, buf, sizeof(buf))))) {
shutdown = done = 1;
goto done;
}
@@ -2799,7 +2807,7 @@ void idle_update(idle_flags_t flags)
if (! imapd_userisadmin &&
(shutdown_file(shut, sizeof(shut)) ||
(imapd_userid &&
- !access_ok(imapd_userid, config_ident, shut, sizeof(shut))))) {
+ userdeny(imapd_userid, config_ident, shut, sizeof(shut))))) {
char *p;
for (p = shut; *p == '['; p++); /* can't have [ be first char */
prot_printf(imapd_out, "* BYE [ALERT] %s\r\n", p);
diff --git a/imap/nntpd.c b/imap/nntpd.c
index 4265abe..a495285 100644
--- a/imap/nntpd.c
+++ b/imap/nntpd.c
@@ -103,6 +103,7 @@
#include "sync_log.h"
#include "telemetry.h"
#include "tls.h"
+#include "userdeny.h"
#include "util.h"
#include "version.h"
#include "wildmat.h"
@@ -494,6 +495,10 @@ int service_init(int argc __attribute__((unused)),
quotadb_init(0);
quotadb_open(NULL);
+ /* open the user deny db */
+ denydb_init(0);
+ denydb_open(NULL);
+
/* setup for sending IMAP IDLE notifications */
idle_enabled();
@@ -704,6 +709,9 @@ void shut_down(int code)
quotadb_close();
quotadb_done();
+ denydb_close();
+ denydb_done();
+
annotatemore_close();
annotatemore_done();
@@ -815,7 +823,7 @@ static void cmdloop(void)
/* Check for shutdown file */
if (shutdown_file(buf, sizeof(buf)) ||
(nntp_userid &&
- !access_ok(nntp_userid, config_ident, buf, sizeof(buf)))) {
+ userdeny(nntp_userid, config_ident, buf, sizeof(buf)))) {
prot_printf(nntp_out, "400 %s\r\n", buf);
shut_down(0);
}
diff --git a/imap/pop3d.c b/imap/pop3d.c
index 1302e3c..84b928b 100644
--- a/imap/pop3d.c
+++ b/imap/pop3d.c
@@ -88,6 +88,7 @@
#include "backend.h"
#include "proxy.h"
#include "seen.h"
+#include "userdeny.h"
#include "sync_log.h"
#include "statuscache.h"
@@ -434,6 +435,10 @@ int service_init(int argc __attribute__((unused)),
quotadb_init(0);
quotadb_open(NULL);
+ /* open the user deny db */
+ denydb_init(0);
+ denydb_open(NULL);
+
if (config_getswitch(IMAPOPT_STATUSCACHE)) {
/* open statuscache db to optimize handling an empty maildrop */
statuscache_open(NULL);
@@ -643,6 +648,9 @@ void shut_down(int code)
quotadb_close();
quotadb_done();
+ denydb_close();
+ denydb_done();
+
if (popd_in) {
prot_NONBLOCK(popd_in);
prot_fill(popd_in);
@@ -804,7 +812,7 @@ static void cmdloop(void)
/* check for shutdown file */
if (shutdown_file(inputbuf, sizeof(inputbuf)) ||
(popd_userid &&
- !access_ok(popd_userid, config_ident, inputbuf, sizeof(inputbuf)))) {
+ userdeny(popd_userid, config_ident, inputbuf, sizeof(inputbuf)))) {
for (p = inputbuf; *p == '['; p++); /* can't have [ be first char */
prot_printf(popd_out, "-ERR [SYS/TEMP] %s\r\n", p);
shut_down(0);
@@ -2024,7 +2032,7 @@ static void bitpipe(void)
/* check for shutdown file */
if (shutdown_file(buf, sizeof(buf)) ||
- !access_ok(popd_userid, config_ident, buf, sizeof(buf))) {
+ userdeny(popd_userid, config_ident, buf, sizeof(buf))) {
shutdown = 1;
goto done;
}
diff --git a/imap/userdeny.h b/imap/userdeny.h
new file mode 100644
index 0000000..a4428c3
--- /dev/null
+++ b/imap/userdeny.h
@@ -0,0 +1,72 @@
+/* userdeny.h -- User deny definitions
+ *
+ * Copyright (c) 1994-2010 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, 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.
+ *
+ * $Id$
+ */
+
+#ifndef INCLUDED_USERDENY_H
+#define INCLUDED_USERDENY_H
+
+#include "cyrusdb.h"
+#include <config.h>
+
+#define FNAME_USERDENYDB "/user_deny.db"
+#define USERDENY_VERSION 2
+
+extern struct db *denydb;
+
+extern int userdeny(const char *user, const char *service,
+ char *msgbuf, size_t bufsiz);
+
+/* open the user deny db */
+void denydb_open(char *name);
+
+/* close the database */
+void denydb_close(void);
+
+/* initialize database structures */
+#define DENYDB_SYNC 0x02
+void denydb_init(int flags);
+
+/* done with database stuff */
+void denydb_done(void);
+
+#endif /* INCLUDED_USERDENY_H */
diff --git a/imap/userdeny_db.c b/imap/userdeny_db.c
new file mode 100644
index 0000000..8d8791d
--- /dev/null
+++ b/imap/userdeny_db.c
@@ -0,0 +1,219 @@
+/* userdeny_db.c -- User deny manipulation routines
+ *
+ * Copyright (c) 1994-2010 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, 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.
+ *
+ * $Id$
+ */
+
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+
+#include "cyrusdb.h"
+#include "global.h"
+#include "userdeny.h"
+#include "wildmat.h"
+#include "xmalloc.h"
+#include "xstrlcpy.h"
+#include "xstrlcat.h"
+
+#define DENYDB config_userdeny_db
+
+struct db *denydb;
+
+static int deny_dbopen = 0;
+
+
+/*
+ * userdeny() checks to see if 'user' is denied access to 'service'
+ * Returns 1 if a matching deny entry exists in DB, otherwise returns 0.
+ */
+int userdeny(const char *user, const char *service, char *msgbuf, size_t bufsiz)
+{
+ int r, ret = 0; /* allow access by default */
+ const char *data = NULL;
+ int datalen;
+
+ if (!deny_dbopen) return 0;
+
+ /* fetch entry for user */
+ syslog(LOG_DEBUG, "fetching user_deny.db entry for '%s'", user);
+ do {
+ r = DENYDB->fetch(denydb, user, strlen(user), &data, &datalen, NULL);
+ } while (r == CYRUSDB_AGAIN);
+
+ /* XXX Should we try to reopen the DB if we get IOERROR?
+ This might be necessary when using SQL backend
+ and we lose the connection.
+ */
+
+ if (r || !data || !datalen) {
+ /* ignore non-existent/empty entry, report all other errors */
+ if (r != CYRUSDB_NOTFOUND) {
+ syslog(LOG_WARNING,
+ "DENYDB_ERROR: error reading entry '%s': %s",
+ user, cyrusdb_strerror(r));
+ }
+ } else {
+ /* parse the data */
+ char *buf, *wild;
+ unsigned long version;
+
+ buf = xstrndup(data, datalen); /* use a working copy */
+
+ /* check version */
+ if (((version = strtoul(buf, &wild, 10)) < 1) ||
+ (version > USERDENY_VERSION)) {
+ syslog(LOG_WARNING,
+ "DENYDB_ERROR: invalid version for entry '%s': %lu",
+ user, version);
+ } else if (*wild++ != '\t') {
+ syslog(LOG_WARNING,
+ "DENYDB_ERROR: missing wildmat for entry '%s'", user);
+ } else {
+ char *pat, *msg = "Access to this service has been blocked";
+ int not;
+
+ /* check if we have a deny message */
+ switch (version) {
+ case USERDENY_VERSION:
+ if ((msg = strchr(wild, '\t'))) *msg++ = '\0';
+ break;
+ }
+
+ /* scan wildmat right to left for a match against our service */
+ syslog(LOG_DEBUG, "wild: '%s' service: '%s'", wild, service);
+ do {
+ /* isolate next pattern */
+ if ((pat = strrchr(wild, ','))) {
+ *pat++ = '\0';
+ } else {
+ pat = wild;
+ }
+
+ /* XXX trim leading & trailing whitespace? */
+
+ /* is it a negated pattern? */
+ not = (*pat == '!');
+ if (not) ++pat;
+
+ syslog(LOG_DEBUG, "pat %d:'%s'", not, pat);
+
+ /* see if pattern matches our service */
+ if (wildmat(service, pat)) {
+ /* match ==> we're done */
+ ret = !not;
+ if (msgbuf) strlcpy(msgbuf, msg, bufsiz);
+ break;
+ }
+
+ /* continue until we reach head of wildmat */
+ } while (pat != wild);
+ }
+
+ free(buf);
+ }
+
+ return ret;
+}
+
+/* must be called after cyrus_init */
+void denydb_init(int myflags)
+{
+ int r;
+
+ if (myflags & DENYDB_SYNC) {
+ r = DENYDB->sync();
+ }
+}
+
+void denydb_open(char *fname)
+{
+ int ret;
+ char *tofree = NULL;
+
+ /* create db file name */
+ if (!fname) {
+ size_t fname_len = strlen(config_dir)+strlen(FNAME_USERDENYDB)+1;
+
+ fname = xmalloc(fname_len);
+ tofree = fname;
+
+ strlcpy(fname, config_dir, fname_len);
+ strlcat(fname, FNAME_USERDENYDB, fname_len);
+ }
+
+ ret = (DENYDB->open)(fname, 0, &denydb);
+ if (ret == CYRUSDB_OK) {
+ deny_dbopen = 1;
+ } else if (errno != ENOENT) {
+ /* ignore non-existent DB, report all other errors */
+ syslog(LOG_WARNING, "DENYDB_ERROR: opening %s: %s", fname,
+ cyrusdb_strerror(ret));
+ }
+
+ if (tofree) free(tofree);
+}
+
+void denydb_close(void)
+{
+ int r;
+
+ if (deny_dbopen) {
+ r = (DENYDB->close)(denydb);
+ if (r) {
+ syslog(LOG_ERR, "DENYDB_ERROR: error closing: %s",
+ cyrusdb_strerror(r));
+ }
+ deny_dbopen = 0;
+ }
+}
+
+void denydb_done(void)
+{
+ /* DB->done() handled by cyrus_done() */
+}
--
1.7.0.3