summaryrefslogtreecommitdiffstats
path: root/src/util/dict_surrogate.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 01:46:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 01:46:30 +0000
commitb5896ba9f6047e7031e2bdee0622d543e11a6734 (patch)
treefd7b460593a2fee1be579bec5697e6d887ea3421 /src/util/dict_surrogate.c
parentInitial commit. (diff)
downloadpostfix-upstream.tar.xz
postfix-upstream.zip
Adding upstream version 3.4.23.upstream/3.4.23upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/util/dict_surrogate.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/util/dict_surrogate.c b/src/util/dict_surrogate.c
new file mode 100644
index 0000000..a23cba3
--- /dev/null
+++ b/src/util/dict_surrogate.c
@@ -0,0 +1,180 @@
+/*++
+/* NAME
+/* dict_surrogate 3
+/* SUMMARY
+/* surrogate table for graceful "open" failure
+/* SYNOPSIS
+/* #include <dict_surrogate.h>
+/*
+/* DICT *dict_surrogate(dict_type, dict_name,
+/* open_flags, dict_flags,
+/* format, ...)
+/* const char *dict_type;
+/* const char *dict_name;
+/* int open_flags;
+/* int dict_flags;
+/* const char *format;
+/*
+/* int dict_allow_surrogate;
+/* DESCRIPTION
+/* dict_surrogate() either terminates the program with a fatal
+/* error, or provides a dummy dictionary that fails all
+/* operations with an error message, allowing the program to
+/* continue with reduced functionality.
+/*
+/* The global dict_allow_surrogate variable controls the choice
+/* between fatal error or reduced functionality. The default
+/* value is zero (fatal error). This is appropriate for user
+/* commands; the non-default is more appropriate for daemons.
+/*
+/* Arguments:
+/* .IP dict_type
+/* .IP dict_name
+/* .IP open_flags
+/* .IP dict_flags
+/* The parameters to the failed dictionary open() request.
+/* .IP format, ...
+/* The reason why the table could not be opened. This text is
+/* logged immediately as an "error" class message, and is logged
+/* as a "warning" class message upon every attempt to access the
+/* surrogate dictionary, before returning a "failed" completion
+/* status.
+/* SEE ALSO
+/* dict(3) generic dictionary manager
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <msg.h>
+#include <compat_va_copy.h>
+#include <dict.h>
+
+/* Application-specific. */
+
+typedef struct {
+ DICT dict; /* generic members */
+ char *reason; /* open failure reason */
+} DICT_SURROGATE;
+
+/* dict_surrogate_sequence - fail lookup */
+
+static int dict_surrogate_sequence(DICT *dict, int unused_func,
+ const char **key, const char **value)
+{
+ DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
+
+ msg_warn("%s:%s is unavailable. %s",
+ dict->type, dict->name, dp->reason);
+ DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
+}
+
+/* dict_surrogate_update - fail lookup */
+
+static int dict_surrogate_update(DICT *dict, const char *unused_name,
+ const char *unused_value)
+{
+ DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
+
+ msg_warn("%s:%s is unavailable. %s",
+ dict->type, dict->name, dp->reason);
+ DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
+}
+
+/* dict_surrogate_lookup - fail lookup */
+
+static const char *dict_surrogate_lookup(DICT *dict, const char *unused_name)
+{
+ DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
+
+ msg_warn("%s:%s is unavailable. %s",
+ dict->type, dict->name, dp->reason);
+ DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, (char *) 0);
+}
+
+/* dict_surrogate_delete - fail delete */
+
+static int dict_surrogate_delete(DICT *dict, const char *unused_name)
+{
+ DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
+
+ msg_warn("%s:%s is unavailable. %s",
+ dict->type, dict->name, dp->reason);
+ DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
+}
+
+/* dict_surrogate_close - close fail dictionary */
+
+static void dict_surrogate_close(DICT *dict)
+{
+ DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
+
+ myfree((void *) dp->reason);
+ dict_free(dict);
+}
+
+int dict_allow_surrogate = 0;
+
+/* dict_surrogate - terminate or provide surrogate dictionary */
+
+DICT *dict_surrogate(const char *dict_type, const char *dict_name,
+ int open_flags, int dict_flags,
+ const char *fmt,...)
+{
+ va_list ap;
+ va_list ap2;
+ DICT_SURROGATE *dp;
+ VSTRING *buf;
+ void (*log_fn) (const char *, va_list);
+ int saved_errno = errno;
+
+ /*
+ * Initialize argument lists.
+ */
+ va_start(ap, fmt);
+ VA_COPY(ap2, ap);
+
+ /*
+ * Log the problem immediately when it is detected. The table may not be
+ * accessed in every program execution (that is the whole point of
+ * continuing with reduced functionality) but we don't want the problem
+ * to remain unnoticed until long after a configuration mistake is made.
+ */
+ log_fn = dict_allow_surrogate ? vmsg_error : vmsg_fatal;
+ log_fn(fmt, ap);
+ va_end(ap);
+
+ /*
+ * Log the problem upon each access.
+ */
+ dp = (DICT_SURROGATE *) dict_alloc(dict_type, dict_name, sizeof(*dp));
+ dp->dict.lookup = dict_surrogate_lookup;
+ if (open_flags & O_RDWR) {
+ dp->dict.update = dict_surrogate_update;
+ dp->dict.delete = dict_surrogate_delete;
+ }
+ dp->dict.sequence = dict_surrogate_sequence;
+ dp->dict.close = dict_surrogate_close;
+ dp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
+ dp->dict.owner.status = DICT_OWNER_TRUSTED;
+ buf = vstring_alloc(10);
+ errno = saved_errno;
+ vstring_vsprintf(buf, fmt, ap2);
+ va_end(ap2);
+ dp->reason = vstring_export(buf);
+ return (DICT_DEBUG (&dp->dict));
+}