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
71 typedef struct {
72 DICT dict; /* generic members */
73 char *reason; /* open failure reason */
74 } DICT_SURROGATE;
75
76 /* dict_surrogate_sequence - fail lookup */
77
dict_surrogate_sequence(DICT * dict,int unused_func,const char ** key,const char ** value)78 static 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
dict_surrogate_update(DICT * dict,const char * unused_name,const char * unused_value)90 static 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
dict_surrogate_lookup(DICT * dict,const char * unused_name)102 static 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
dict_surrogate_delete(DICT * dict,const char * unused_name)113 static 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
dict_surrogate_close(DICT * dict)124 static 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
132 int dict_allow_surrogate = 0;
133
134 /* dict_surrogate - terminate or provide surrogate dictionary */
135
dict_surrogate(const char * dict_type,const char * dict_name,int open_flags,int dict_flags,const char * fmt,...)136 DICT *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