/* $NetBSD: dict_surrogate.c,v 1.2 2017/02/14 01:16:49 christos Exp $ */
/*++
/* 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));
}