summaryrefslogtreecommitdiffstats
path: root/src/util/dict_surrogate.c
blob: a23cba3589326fafefbc089122dff65ff9a8613e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*++
/* NAME
/*	dict_surrogate 3
/* SUMMARY
/*	surrogate table for graceful "open" failure
/* SYNOPSIS
/*	#include <dict_surrogate.h>
/*
/*	DICT	*dict_surrogate(dict_type, dict_name,
/*				open_flags, dict_flags,
/*				format, ...)
/*	const char *dict_type;
/*	const char *dict_name;
/*	int	open_flags;
/*	int	dict_flags;
/*	const char *format;
/*
/*	int	dict_allow_surrogate;
/* DESCRIPTION
/*	dict_surrogate() either terminates the program with a fatal
/*	error, or provides a dummy dictionary that fails all
/*	operations with an error message, allowing the program to
/*	continue with reduced functionality.
/*
/*	The global dict_allow_surrogate variable controls the choice
/*	between fatal error or reduced functionality. The default
/*	value is zero (fatal error). This is appropriate for user
/*	commands; the non-default is more appropriate for daemons.
/*
/*	Arguments:
/* .IP dict_type
/* .IP dict_name
/* .IP open_flags
/* .IP dict_flags
/*	The parameters to the failed dictionary open() request.
/* .IP format, ...
/*	The reason why the table could not be opened. This text is
/*	logged immediately as an "error" class message, and is logged
/*	as a "warning" class message upon every attempt to access the
/*	surrogate dictionary, before returning a "failed" completion
/*	status.
/* SEE ALSO
/*	dict(3) generic dictionary manager
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/

/* System library. */

#include <sys_defs.h>
#include <errno.h>

/* Utility library. */

#include <mymalloc.h>
#include <msg.h>
#include <compat_va_copy.h>
#include <dict.h>

/* Application-specific. */

typedef struct {
    DICT    dict;			/* generic members */
    char   *reason;			/* open failure reason */
} DICT_SURROGATE;

/* dict_surrogate_sequence - fail lookup */

static int dict_surrogate_sequence(DICT *dict, int unused_func,
			               const char **key, const char **value)
{
    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;

    msg_warn("%s:%s is unavailable. %s",
	     dict->type, dict->name, dp->reason);
    DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
}

/* dict_surrogate_update - fail lookup */

static int dict_surrogate_update(DICT *dict, const char *unused_name,
				         const char *unused_value)
{
    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;

    msg_warn("%s:%s is unavailable. %s",
	     dict->type, dict->name, dp->reason);
    DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
}

/* dict_surrogate_lookup - fail lookup */

static const char *dict_surrogate_lookup(DICT *dict, const char *unused_name)
{
    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;

    msg_warn("%s:%s is unavailable. %s",
	     dict->type, dict->name, dp->reason);
    DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, (char *) 0);
}

/* dict_surrogate_delete - fail delete */

static int dict_surrogate_delete(DICT *dict, const char *unused_name)
{
    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;

    msg_warn("%s:%s is unavailable. %s",
	     dict->type, dict->name, dp->reason);
    DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
}

/* dict_surrogate_close - close fail dictionary */

static void dict_surrogate_close(DICT *dict)
{
    DICT_SURROGATE *dp = (DICT_SURROGATE *) dict;

    myfree((void *) dp->reason);
    dict_free(dict);
}

int     dict_allow_surrogate = 0;

/* dict_surrogate - terminate or provide surrogate dictionary */

DICT   *dict_surrogate(const char *dict_type, const char *dict_name,
		               int open_flags, int dict_flags,
		               const char *fmt,...)
{
    va_list ap;
    va_list ap2;
    DICT_SURROGATE *dp;
    VSTRING *buf;
    void    (*log_fn) (const char *, va_list);
    int     saved_errno = errno;

    /*
     * Initialize argument lists.
     */
    va_start(ap, fmt);
    VA_COPY(ap2, ap);

    /*
     * Log the problem immediately when it is detected. The table may not be
     * accessed in every program execution (that is the whole point of
     * continuing with reduced functionality) but we don't want the problem
     * to remain unnoticed until long after a configuration mistake is made.
     */
    log_fn = dict_allow_surrogate ? vmsg_error : vmsg_fatal;
    log_fn(fmt, ap);
    va_end(ap);

    /*
     * Log the problem upon each access.
     */
    dp = (DICT_SURROGATE *) dict_alloc(dict_type, dict_name, sizeof(*dp));
    dp->dict.lookup = dict_surrogate_lookup;
    if (open_flags & O_RDWR) {
	dp->dict.update = dict_surrogate_update;
	dp->dict.delete = dict_surrogate_delete;
    }
    dp->dict.sequence = dict_surrogate_sequence;
    dp->dict.close = dict_surrogate_close;
    dp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
    dp->dict.owner.status = DICT_OWNER_TRUSTED;
    buf = vstring_alloc(10);
    errno = saved_errno;
    vstring_vsprintf(buf, fmt, ap2);
    va_end(ap2);
    dp->reason = vstring_export(buf);
    return (DICT_DEBUG (&dp->dict));
}