Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: dict_surrogate.c,v 1.3 2026/05/09 18:49:22 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	dict_surrogate 3
      6 /* SUMMARY
      7 /*	surrogate table for graceful "open" failure
      8 /* SYNOPSIS
      9 /*	#include <dict.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 
     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 
     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 
    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 
    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 
    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 
    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 | DICT_FLAG_SURROGATE;
    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 (&dp->dict);
    182 }
    183