xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/dict_surrogate.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
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