1/*	$NetBSD: dict_surrogate.c,v 1.2 2017/02/14 01:16:49 christos Exp $	*/
2
3/*++
4/* NAME
5/*	dict_surrogate 3
6/* SUMMARY
7/*	surrogate table for graceful "open" failure
8/* SYNOPSIS
9/*	#include <dict_surrogate.h>
10/*
11/*	DICT	*dict_surrogate(dict_type, dict_name,
12/*				open_flags, dict_flags,
13/*				format, ...)
14/*	const char *dict_type;
15/*	const char *dict_name;
16/*	int	open_flags;
17/*	int	dict_flags;
18/*	const char *format;
19/*
20/*	int	dict_allow_surrogate;
21/* DESCRIPTION
22/*	dict_surrogate() either terminates the program with a fatal
23/*	error, or provides a dummy dictionary that fails all
24/*	operations with an error message, allowing the program to
25/*	continue with reduced functionality.
26/*
27/*	The global dict_allow_surrogate variable controls the choice
28/*	between fatal error or reduced functionality. The default
29/*	value is zero (fatal error). This is appropriate for user
30/*	commands; the non-default is more appropriate for daemons.
31/*
32/*	Arguments:
33/* .IP dict_type
34/* .IP dict_name
35/* .IP open_flags
36/* .IP dict_flags
37/*	The parameters to the failed dictionary open() request.
38/* .IP format, ...
39/*	The reason why the table could not be opened. This text is
40/*	logged immediately as an "error" class message, and is logged
41/*	as a "warning" class message upon every attempt to access the
42/*	surrogate dictionary, before returning a "failed" completion
43/*	status.
44/* SEE ALSO
45/*	dict(3) generic dictionary manager
46/* LICENSE
47/* .ad
48/* .fi
49/*	The Secure Mailer license must be distributed with this software.
50/* AUTHOR(S)
51/*	Wietse Venema
52/*	IBM T.J. Watson Research
53/*	P.O. Box 704
54/*	Yorktown Heights, NY 10598, USA
55/*--*/
56
57/* System library. */
58
59#include <sys_defs.h>
60#include <errno.h>
61
62/* Utility library. */
63
64#include <mymalloc.h>
65#include <msg.h>
66#include <compat_va_copy.h>
67#include <dict.h>
68
69/* Application-specific. */
70
71typedef struct {
72    DICT    dict;			/* generic members */
73    char   *reason;			/* open failure reason */
74} DICT_SURROGATE;
75
76/* dict_surrogate_sequence - fail lookup */
77
78static int dict_surrogate_sequence(DICT *dict, int unused_func,
79			               const char **key, const char **value)
80{
81    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
82
83    msg_warn("%s:%s is unavailable. %s",
84	     dict->type, dict->name, dp->reason);
85    DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
86}
87
88/* dict_surrogate_update - fail lookup */
89
90static int dict_surrogate_update(DICT *dict, const char *unused_name,
91				         const char *unused_value)
92{
93    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
94
95    msg_warn("%s:%s is unavailable. %s",
96	     dict->type, dict->name, dp->reason);
97    DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
98}
99
100/* dict_surrogate_lookup - fail lookup */
101
102static const char *dict_surrogate_lookup(DICT *dict, const char *unused_name)
103{
104    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
105
106    msg_warn("%s:%s is unavailable. %s",
107	     dict->type, dict->name, dp->reason);
108    DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, (char *) 0);
109}
110
111/* dict_surrogate_delete - fail delete */
112
113static int dict_surrogate_delete(DICT *dict, const char *unused_name)
114{
115    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
116
117    msg_warn("%s:%s is unavailable. %s",
118	     dict->type, dict->name, dp->reason);
119    DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
120}
121
122/* dict_surrogate_close - close fail dictionary */
123
124static void dict_surrogate_close(DICT *dict)
125{
126    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;
127
128    myfree((void *) dp->reason);
129    dict_free(dict);
130}
131
132int     dict_allow_surrogate = 0;
133
134/* dict_surrogate - terminate or provide surrogate dictionary */
135
136DICT   *dict_surrogate(const char *dict_type, const char *dict_name,
137		               int open_flags, int dict_flags,
138		               const char *fmt,...)
139{
140    va_list ap;
141    va_list ap2;
142    DICT_SURROGATE *dp;
143    VSTRING *buf;
144    void    (*log_fn) (const char *, va_list);
145    int     saved_errno = errno;
146
147    /*
148     * Initialize argument lists.
149     */
150    va_start(ap, fmt);
151    VA_COPY(ap2, ap);
152
153    /*
154     * Log the problem immediately when it is detected. The table may not be
155     * accessed in every program execution (that is the whole point of
156     * continuing with reduced functionality) but we don't want the problem
157     * to remain unnoticed until long after a configuration mistake is made.
158     */
159    log_fn = dict_allow_surrogate ? vmsg_error : vmsg_fatal;
160    log_fn(fmt, ap);
161    va_end(ap);
162
163    /*
164     * Log the problem upon each access.
165     */
166    dp = (DICT_SURROGATE *) dict_alloc(dict_type, dict_name, sizeof(*dp));
167    dp->dict.lookup = dict_surrogate_lookup;
168    if (open_flags & O_RDWR) {
169	dp->dict.update = dict_surrogate_update;
170	dp->dict.delete = dict_surrogate_delete;
171    }
172    dp->dict.sequence = dict_surrogate_sequence;
173    dp->dict.close = dict_surrogate_close;
174    dp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
175    dp->dict.owner.status = DICT_OWNER_TRUSTED;
176    buf = vstring_alloc(10);
177    errno = saved_errno;
178    vstring_vsprintf(buf, fmt, ap2);
179    va_end(ap2);
180    dp->reason = vstring_export(buf);
181    return (DICT_DEBUG (&dp->dict));
182}
183