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