mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +00:00
postfix-3.4-20181229
This commit is contained in:
parent
b15570215e
commit
7c27c10eb2
@ -23917,11 +23917,14 @@ Apologies for any names omitted.
|
||||
message to the postscreen_pre_queue_limit. Problem reported
|
||||
by Michael Orlitzky. File: proto/POSTSCREEN_README.html.
|
||||
|
||||
20181228
|
||||
20181229
|
||||
|
||||
Explicit maps_file_find() and dict_file_lookup() methods
|
||||
that decode base64 content. Decoding content is not built
|
||||
into the dict->lookup() method, because that would complicate
|
||||
the implementation of map nesting (inline, thash), map
|
||||
composition (pipemap, unionmap), and map proxying. For
|
||||
consistency, decoding base64 file content is also not built
|
||||
into the maps_find() method. Files: util/dict.h.
|
||||
util/dict_file.c, global/maps.[hc], postmap/postmap.c.
|
||||
|
||||
Cleanup: generic wrapper infrastructure for Postfix maps
|
||||
(dictionaries) that is the basis for UTF8 checks and for
|
||||
base64 decoding of lookup results. Files: global/mkmap_open.c,
|
||||
postmap/postmap.c, util/dict.c, util/dict.h, util/dict_alloc.c,
|
||||
util/dict_file.c, util/dict_open.c, util/dict_pipe.c,
|
||||
util/dict_union.c, util/dict_utf8.c, util/dict_wrapper.c.
|
||||
|
@ -1,8 +1,7 @@
|
||||
Wish list:
|
||||
|
||||
Add sequence support to dictionary wrappers, and remove
|
||||
ad-hoc decoding from the postmap command. What about invalid
|
||||
base64? Warn and skip?
|
||||
With DICT_FLAG_RHS_IS_FILE, should dict_update() open a
|
||||
file? base64-encode the value?
|
||||
|
||||
In smtpd(8) and postscreen(8), set the ehlo_discard_mask
|
||||
to ~0 so that STARTTLS, BDAT, DSN, etc. work only for clients
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20181228"
|
||||
#define MAIL_RELEASE_DATE "20181229"
|
||||
#define MAIL_VERSION_NUMBER "3.4"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -16,6 +16,11 @@
|
||||
/* const char *key;
|
||||
/* int flags;
|
||||
/*
|
||||
/* const char *maps_file_find(maps, key, flags)
|
||||
/* MAPS *maps;
|
||||
/* const char *key;
|
||||
/* int flags;
|
||||
/*
|
||||
/* MAPS *maps_free(maps)
|
||||
/* MAPS *maps;
|
||||
/* DESCRIPTION
|
||||
@ -39,6 +44,10 @@
|
||||
/* for example, DICT_FLAG_FIXED | DICT_FLAG_PATTERN selects
|
||||
/* dictionaries that have fixed keys or pattern keys.
|
||||
/*
|
||||
/* maps_file_find() implements maps_find() but also decodes
|
||||
/* the base64 lookup result. This requires that the maps are
|
||||
/* opened with DICT_FLAG_SRC_RHS_IS_FILE.
|
||||
/*
|
||||
/* maps_free() releases storage claimed by maps_create()
|
||||
/* and conveniently returns a null pointer.
|
||||
/*
|
||||
@ -189,15 +198,81 @@ const char *maps_find(MAPS *maps, const char *name, int flags)
|
||||
maps->title, name);
|
||||
msg_warn("%s should return NO RESULT in case of NOT FOUND",
|
||||
maps->title);
|
||||
maps->error = DICT_ERR_RETRY;
|
||||
maps->error = DICT_ERR_CONFIG;
|
||||
return (0);
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: %s: %s = %s", myname, maps->title,
|
||||
*map_name, name, expansion);
|
||||
msg_info("%s: %s: %s: %s = %.100s%s", myname, maps->title,
|
||||
*map_name, name, expansion,
|
||||
strlen(expansion) > 100 ? "..." : "");
|
||||
return (expansion);
|
||||
} else if ((maps->error = dict->error) != 0) {
|
||||
msg_warn("%s:%s lookup error for \"%.100s\"",
|
||||
msg_warn("%s:%s lookup error for \"%s\"",
|
||||
dict->type, dict->name, name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: %s: %s", myname, maps->title, name, maps->error ?
|
||||
"search aborted" : "not found");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* maps_file_find - search a list of dictionaries and base64 decode */
|
||||
|
||||
const char *maps_file_find(MAPS *maps, const char *name, int flags)
|
||||
{
|
||||
const char *myname = "maps_file_find";
|
||||
char **map_name;
|
||||
const char *expansion;
|
||||
DICT *dict;
|
||||
VSTRING *unb64;
|
||||
char *err;
|
||||
|
||||
/*
|
||||
* In case of return without map lookup (empty name or no maps).
|
||||
*/
|
||||
maps->error = 0;
|
||||
|
||||
/*
|
||||
* Temp. workaround, for buggy callers that pass zero-length keys when
|
||||
* given partial addresses.
|
||||
*/
|
||||
if (*name == 0)
|
||||
return (0);
|
||||
|
||||
for (map_name = maps->argv->argv; *map_name; map_name++) {
|
||||
if ((dict = dict_handle(*map_name)) == 0)
|
||||
msg_panic("%s: dictionary not found: %s", myname, *map_name);
|
||||
if ((dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) == 0)
|
||||
msg_panic("%s: %s: opened without DICT_FLAG_SRC_RHS_IS_FILE",
|
||||
myname, maps->title);
|
||||
if (flags != 0 && (dict->flags & flags) == 0)
|
||||
continue;
|
||||
if ((expansion = dict_get(dict, name)) != 0) {
|
||||
if (*expansion == 0) {
|
||||
msg_warn("%s lookup of %s returns an empty string result",
|
||||
maps->title, name);
|
||||
msg_warn("%s should return NO RESULT in case of NOT FOUND",
|
||||
maps->title);
|
||||
maps->error = DICT_ERR_CONFIG;
|
||||
return (0);
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: %s: %s = %.100s%s", myname, maps->title,
|
||||
*map_name, name, expansion,
|
||||
strlen(expansion) > 100 ? "..." : "");
|
||||
if ((unb64 = dict_file_from_b64(dict, expansion)) == 0) {
|
||||
err = dict_file_get_error(dict);
|
||||
msg_warn("table %s:%s: key %s: %s",
|
||||
dict->type, dict->name, name, err);
|
||||
myfree(err);
|
||||
maps->error = DICT_ERR_CONFIG;
|
||||
return (0);
|
||||
}
|
||||
return (vstring_str(unb64));
|
||||
} else if ((maps->error = dict->error) != 0) {
|
||||
msg_warn("%s:%s lookup error for \"%s\"",
|
||||
dict->type, dict->name, name);
|
||||
break;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ typedef struct MAPS {
|
||||
|
||||
extern MAPS *maps_create(const char *, const char *, int);
|
||||
extern const char *maps_find(MAPS *, const char *, int);
|
||||
extern const char *maps_file_find(MAPS *, const char *, int);
|
||||
extern MAPS *maps_free(MAPS *);
|
||||
|
||||
/* LICENSE
|
||||
|
@ -301,12 +301,7 @@ MKMAP *mkmap_open(const char *type, const char *path,
|
||||
*/
|
||||
if ((mkmap->dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0
|
||||
&& DICT_NEED_UTF8_ACTIVATION(util_utf8_enable, dict_flags))
|
||||
dict_utf8_wrapper_activate(mkmap->dict);
|
||||
|
||||
/* Insert wrapper for base64 decoding file content. */
|
||||
if ((mkmap->dict->flags & DICT_FLAG_UNB64_ACTIVE) == 0
|
||||
&& (mkmap->dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) != 0)
|
||||
dict_file_wrapper_activate(mkmap->dict);
|
||||
mkmap->dict = dict_utf8_activate(mkmap->dict);
|
||||
|
||||
/*
|
||||
* Resume signal delivery if multi-writer safe.
|
||||
|
@ -11,4 +11,4 @@ file-2 this-is-file2
|
||||
this-is-file1
|
||||
this-is-file2
|
||||
postmap: warning: table hash:file_test_map.db: key entry-4: malformed BASE64 value: postmap-entry-4
|
||||
postmap: fatal: table hash:file_test_map.db: query error: No such file or directory
|
||||
postmap: fatal: table hash:file_test_map.db: query error
|
||||
|
@ -651,34 +651,30 @@ static int postmap_queries(VSTREAM *in, char **maps, const int map_count,
|
||||
dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ?
|
||||
dict_open3(maps[n], map_name, O_RDONLY, dict_flags) :
|
||||
dict_open3(var_db_type, maps[n], O_RDONLY, dict_flags));
|
||||
if ((value = dict_get(dicts[n], STR(keybuf))) != 0) {
|
||||
value = ((dict_flags & DICT_FLAG_SRC_RHS_IS_FILE) ?
|
||||
dict_file_lookup : dicts[n]->lookup)
|
||||
(dicts[n], STR(keybuf));
|
||||
if (value != 0) {
|
||||
if (*value == 0) {
|
||||
msg_warn("table %s:%s: key %s: empty string result is not allowed",
|
||||
dicts[n]->type, dicts[n]->name, STR(keybuf));
|
||||
msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
|
||||
dicts[n]->type, dicts[n]->name);
|
||||
}
|
||||
#if 0
|
||||
if (dict_flags & DICT_FLAG_SRC_RHS_IS_FILE) {
|
||||
VSTRING *unb64;
|
||||
char *err;
|
||||
|
||||
if ((unb64 = dict_file_from_b64(dicts[n], value)) == 0) {
|
||||
err = dict_file_get_error(dicts[n]);
|
||||
msg_fatal("table %s:%s: key %s: %s",
|
||||
dicts[n]->type, dicts[n]->name,
|
||||
STR(keybuf), err);
|
||||
}
|
||||
value = STR(unb64);
|
||||
}
|
||||
#endif
|
||||
vstream_printf("%s %s\n", STR(keybuf), value);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (dicts[n]->error)
|
||||
switch (dicts[n]->error) {
|
||||
case 0:
|
||||
break;
|
||||
case DICT_ERR_CONFIG:
|
||||
msg_fatal("table %s:%s: query error",
|
||||
dicts[n]->type, dicts[n]->name);
|
||||
default:
|
||||
msg_fatal("table %s:%s: query error: %m",
|
||||
dicts[n]->type, dicts[n]->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -752,31 +748,27 @@ static int postmap_query(const char *map_type, const char *map_name,
|
||||
const char *value;
|
||||
|
||||
dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
|
||||
if ((value = dict_get(dict, key)) != 0) {
|
||||
value = ((dict_flags & DICT_FLAG_SRC_RHS_IS_FILE) ?
|
||||
dict_file_lookup : dict->lookup) (dict, key);
|
||||
if (value != 0) {
|
||||
if (*value == 0) {
|
||||
msg_warn("table %s:%s: key %s: empty string result is not allowed",
|
||||
map_type, map_name, key);
|
||||
msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
|
||||
map_type, map_name);
|
||||
}
|
||||
#if 0
|
||||
if (dict_flags & DICT_FLAG_SRC_RHS_IS_FILE) {
|
||||
VSTRING *unb64;
|
||||
char *err;
|
||||
|
||||
if ((unb64 = dict_file_from_b64(dict, value)) == 0) {
|
||||
err = dict_file_get_error(dict);
|
||||
msg_fatal("table %s:%s: key %s: %s",
|
||||
dict->type, dict->name,
|
||||
key, err);
|
||||
}
|
||||
value = STR(unb64);
|
||||
}
|
||||
#endif
|
||||
vstream_printf("%s\n", value);
|
||||
}
|
||||
if (dict->error)
|
||||
msg_fatal("table %s:%s: query error: %m", dict->type, dict->name);
|
||||
switch (dict->error) {
|
||||
case 0:
|
||||
break;
|
||||
case DICT_ERR_CONFIG:
|
||||
msg_fatal("table %s:%s: query error",
|
||||
dict->type, dict->name);
|
||||
default:
|
||||
msg_fatal("table %s:%s: query error: %m",
|
||||
dict->type, dict->name);
|
||||
}
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
dict_close(dict);
|
||||
return (value != 0);
|
||||
@ -885,7 +877,6 @@ static void postmap_seq(const char *map_type, const char *map_name,
|
||||
msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
|
||||
map_type, map_name);
|
||||
}
|
||||
#if 1
|
||||
if (dict_flags & DICT_FLAG_SRC_RHS_IS_FILE) {
|
||||
VSTRING *unb64;
|
||||
char *err;
|
||||
@ -900,7 +891,6 @@ static void postmap_seq(const char *map_type, const char *map_name,
|
||||
}
|
||||
value = STR(unb64);
|
||||
}
|
||||
#endif
|
||||
vstream_printf("%s %s\n", key, value);
|
||||
}
|
||||
if (dict->error)
|
||||
|
@ -7,7 +7,7 @@
|
||||
/* #include "smtpd.h"
|
||||
/* #include "smtpd_sasl_proto.h"
|
||||
/*
|
||||
/* void smtpd_sasl_auth_cmd(state, argc, argv)
|
||||
/* int smtpd_sasl_auth_cmd(state, argc, argv)
|
||||
/* SMTPD_STATE *state;
|
||||
/* int argc;
|
||||
/* SMTPD_TOKEN *argv;
|
||||
|
@ -40,8 +40,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
|
||||
poll_fd.c timecmp.c slmdb.c dict_pipe.c dict_random.c \
|
||||
valid_utf8_hostname.c midna_domain.c argv_splitq.c balpar.c dict_union.c \
|
||||
extpar.c dict_inline.c casefold.c dict_utf8.c strcasecmp_utf8.c \
|
||||
split_qnameval.c argv_attr_print.c argv_attr_scan.c dict_file.c \
|
||||
dict_wrapper.c
|
||||
split_qnameval.c argv_attr_print.c argv_attr_scan.c dict_file.c
|
||||
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
|
||||
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
|
||||
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
|
||||
@ -83,8 +82,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
|
||||
poll_fd.o timecmp.o $(NON_PLUGIN_MAP_OBJ) dict_pipe.o dict_random.o \
|
||||
valid_utf8_hostname.o midna_domain.o argv_splitq.o balpar.o dict_union.o \
|
||||
extpar.o dict_inline.o casefold.o dict_utf8.o strcasecmp_utf8.o \
|
||||
split_qnameval.o argv_attr_print.o argv_attr_scan.o dict_file.o \
|
||||
dict_wrapper.o
|
||||
split_qnameval.o argv_attr_print.o argv_attr_scan.o dict_file.o
|
||||
# MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
|
||||
# When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
|
||||
# otherwise it sets the PLUGIN_* macros.
|
||||
@ -1342,6 +1340,7 @@ dict_ht.o: sys_defs.h
|
||||
dict_ht.o: vbuf.h
|
||||
dict_ht.o: vstream.h
|
||||
dict_ht.o: vstring.h
|
||||
dict_inline.cdict_static.o: dict_inline.cdict_static.c
|
||||
dict_inline.o: argv.h
|
||||
dict_inline.o: check_arg.h
|
||||
dict_inline.o: dict.h
|
||||
@ -1648,18 +1647,6 @@ dict_utf8.o: sys_defs.h
|
||||
dict_utf8.o: vbuf.h
|
||||
dict_utf8.o: vstream.h
|
||||
dict_utf8.o: vstring.h
|
||||
dict_wrapper.o: argv.h
|
||||
dict_wrapper.o: check_arg.h
|
||||
dict_wrapper.o: dict.h
|
||||
dict_wrapper.o: dict_wrapper.c
|
||||
dict_wrapper.o: msg.h
|
||||
dict_wrapper.o: myflock.h
|
||||
dict_wrapper.o: mymalloc.h
|
||||
dict_wrapper.o: stringops.h
|
||||
dict_wrapper.o: sys_defs.h
|
||||
dict_wrapper.o: vbuf.h
|
||||
dict_wrapper.o: vstream.h
|
||||
dict_wrapper.o: vstring.h
|
||||
dir_forest.o: check_arg.h
|
||||
dir_forest.o: dir_forest.c
|
||||
dir_forest.o: dir_forest.h
|
||||
@ -1917,6 +1904,8 @@ load_file.o: vbuf.h
|
||||
load_file.o: vstream.h
|
||||
load_file.o: warn_stat.h
|
||||
load_lib.o: load_lib.c
|
||||
load_lib.o: load_lib.h
|
||||
load_lib.o: msg.h
|
||||
load_lib.o: sys_defs.h
|
||||
lowercase.o: check_arg.h
|
||||
lowercase.o: lowercase.c
|
||||
|
@ -640,7 +640,6 @@ static const NAME_MASK dict_mask[] = {
|
||||
"utf8_request", DICT_FLAG_UTF8_REQUEST, /* request UTF-8 activation */
|
||||
"utf8_active", DICT_FLAG_UTF8_ACTIVE, /* UTF-8 is activated */
|
||||
"src_rhs_is_file", DICT_FLAG_SRC_RHS_IS_FILE, /* value from file */
|
||||
"unb64_active", DICT_FLAG_UNB64_ACTIVE, /* base64 decode activated */
|
||||
0,
|
||||
};
|
||||
|
||||
|
@ -93,7 +93,7 @@ typedef struct DICT {
|
||||
DICT_OWNER owner; /* provenance */
|
||||
int error; /* last operation only */
|
||||
DICT_JMP_BUF *jbuf; /* exception handling */
|
||||
struct DICT_WRAPPER *wrapper; /* see below */
|
||||
struct DICT_UTF8_BACKUP *utf8_backup; /* see below */
|
||||
struct VSTRING *file_buf; /* dict_file_to_buf() */
|
||||
struct VSTRING *file_b64; /* dict_file_to_b64() */
|
||||
} DICT;
|
||||
@ -133,7 +133,6 @@ extern DICT *dict_debug(DICT *);
|
||||
#define DICT_FLAG_UTF8_ACTIVE (1<<20) /* UTF-8 proxy layer is present */
|
||||
#define DICT_FLAG_SRC_RHS_IS_FILE \
|
||||
(1<<21) /* Map source RHS is a file */
|
||||
#define DICT_FLAG_UNB64_ACTIVE (1<<22) /* File decode proxy layer is present */
|
||||
|
||||
#define DICT_FLAG_UTF8_MASK (DICT_FLAG_UTF8_REQUEST)
|
||||
|
||||
@ -252,29 +251,15 @@ extern int dict_flags_mask(const char *);
|
||||
extern void dict_type_override(DICT *, const char *);
|
||||
|
||||
/*
|
||||
* Wrappers for DICT methods. Usage: create an "trivial" wrapper object with
|
||||
* dict_wrapper_alloc(), then for each method that requires special
|
||||
* processing, specify a pointer to function that calls the 'next' wrapper's
|
||||
* method of the same type, with the 'next' wrapper as the first argument
|
||||
* (the 'self' pointer).
|
||||
* Check and convert UTF-8 keys and values.
|
||||
*/
|
||||
typedef struct DICT_WRAPPER {
|
||||
const char *name; /* for literal constant */
|
||||
const char *(*lookup) (struct DICT_WRAPPER *, DICT *, const char *);
|
||||
int (*update) (struct DICT_WRAPPER *, DICT *, const char *, const char *);
|
||||
int (*delete) (struct DICT_WRAPPER *, DICT *, const char *);
|
||||
struct DICT_WRAPPER *next;
|
||||
} DICT_WRAPPER;
|
||||
typedef struct DICT_UTF8_BACKUP {
|
||||
const char *(*lookup) (struct DICT *, const char *);
|
||||
int (*update) (struct DICT *, const char *, const char *);
|
||||
int (*delete) (struct DICT *, const char *);
|
||||
} DICT_UTF8_BACKUP;
|
||||
|
||||
extern void dict_wrapper_prepend(DICT *, DICT_WRAPPER *);
|
||||
extern DICT_WRAPPER *dict_wrapper_alloc(ssize_t);
|
||||
extern void dict_wrapper_free(DICT_WRAPPER *);
|
||||
|
||||
/*
|
||||
* Things that build on DICT_WRAPPER.
|
||||
*/
|
||||
extern void dict_utf8_wrapper_activate(DICT *);
|
||||
extern void dict_file_wrapper_activate(DICT *);
|
||||
extern DICT *dict_utf8_activate(DICT *);
|
||||
|
||||
/*
|
||||
* Driver for interactive or scripted tests.
|
||||
@ -327,6 +312,7 @@ extern struct VSTRING *dict_file_to_b64(DICT *, const char *);
|
||||
extern struct VSTRING *dict_file_from_b64(DICT *, const char *);
|
||||
extern char *dict_file_get_error(DICT *);
|
||||
extern void dict_file_purge_buffers(DICT *);
|
||||
extern const char *dict_file_lookup(DICT *dict, const char *);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
|
@ -159,7 +159,7 @@ DICT *dict_alloc(const char *dict_type, const char *dict_name, ssize_t size)
|
||||
dict->owner.uid = INT_MAX;
|
||||
dict->error = DICT_ERR_NONE;
|
||||
dict->jbuf = 0;
|
||||
dict->wrapper = 0;
|
||||
dict->utf8_backup = 0;
|
||||
dict->file_buf = 0;
|
||||
dict->file_b64 = 0;
|
||||
return dict;
|
||||
@ -173,8 +173,8 @@ void dict_free(DICT *dict)
|
||||
myfree(dict->name);
|
||||
if (dict->jbuf)
|
||||
myfree((void *) dict->jbuf);
|
||||
if (dict->wrapper)
|
||||
dict_wrapper_free(dict->wrapper);
|
||||
if (dict->utf8_backup)
|
||||
myfree((void *) dict->utf8_backup);
|
||||
if (dict->file_buf)
|
||||
vstring_free(dict->file_buf);
|
||||
if (dict->file_b64)
|
||||
|
@ -1,10 +1,8 @@
|
||||
./dict_open: warning: cidr map dict_cidr_file.map, line 3: open dict_cidr_file3: No such file or directory: skipping this rule
|
||||
owner=untrusted (uid=USER)
|
||||
> get 1.1.1.1
|
||||
1.1.1.1=this-is-file1
|
||||
|
||||
1.1.1.1=dGhpcy1pcy1maWxlMQo=
|
||||
> get 2.2.2.2
|
||||
2.2.2.2=this-is-file2
|
||||
|
||||
2.2.2.2=dGhpcy1pcy1maWxlMgo=
|
||||
> get 3.3.3.3
|
||||
3.3.3.3: not found
|
||||
|
@ -24,7 +24,7 @@
|
||||
/* void dict_file_purge_buffers(
|
||||
/* DICT *dict)
|
||||
/*
|
||||
/* void dict_file_wrapper_activate(
|
||||
/* const char *dict_file_lookup(
|
||||
/* DICT *dict)
|
||||
/* DESCRIPTION
|
||||
/* dict_file_to_buf() reads the content of the specified files,
|
||||
@ -48,10 +48,17 @@
|
||||
/* it returns a desciption of the problem. Storage is owned
|
||||
/* by the caller.
|
||||
/*
|
||||
/* dict_file_wrapper_activate() activates a wrapper that
|
||||
/* automatically base64-decodes lookup results.
|
||||
/* dict_file_lookup() wraps the dictionary lookup method and
|
||||
/* decodes the base64 lookup result. The dictionary must be
|
||||
/* opened with DICT_FLAG_SRC_RHS_IS_FILE. Sets dict->error to
|
||||
/* DICT_ERR_CONFIG if the content is invalid. Decoding is not
|
||||
/* built into the dict->lookup() method, because that would
|
||||
/* complicate the implementation of map nesting (inline, thash),
|
||||
/* map composition (pipemap, unionmap), and map proxying.
|
||||
/* DIAGNOSTICS
|
||||
/* In case of error the result value is a null pointer, and
|
||||
/* Panic: interface violation.
|
||||
/*
|
||||
/* In case of error the VSTRING result value is a null pointer, and
|
||||
/* an error description can be retrieved with dict_file_get_error().
|
||||
/* The storage is owned by the caller.
|
||||
/* LICENSE
|
||||
@ -199,56 +206,28 @@ void dict_file_purge_buffers(DICT *dict)
|
||||
}
|
||||
}
|
||||
|
||||
/* dict_file_wrapper_lookup - wrap the lookup method */
|
||||
/* dict_file_lookup - look up and decode dictionary entry */
|
||||
|
||||
static const char *dict_file_wrapper_lookup(DICT_WRAPPER *wrapper,
|
||||
DICT *dict, const char *key)
|
||||
const char *dict_file_lookup(DICT *dict, const char *key)
|
||||
{
|
||||
DICT_WRAPPER *next_wrapper;
|
||||
const char myname[] = "dict_file_lookup";
|
||||
const char *res;
|
||||
VSTRING *unb64;
|
||||
char *err;
|
||||
|
||||
next_wrapper = wrapper->next;
|
||||
if ((res = next_wrapper->lookup(next_wrapper, dict, key)) != 0) {
|
||||
if ((unb64 = dict_file_from_b64(dict, res)) == 0) {
|
||||
err = dict_file_get_error(dict);
|
||||
msg_warn("table %s:%s: key %s: %s",
|
||||
dict->type, dict->name, key, err);
|
||||
myfree(err);
|
||||
dict->error = DICT_ERR_CONFIG;
|
||||
res = 0;
|
||||
} else {
|
||||
res = vstring_str(unb64);
|
||||
}
|
||||
if ((dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) == 0)
|
||||
msg_panic("%s: dictionary opened without DICT_FLAG_SRC_RHS_IS_FILE",
|
||||
myname);
|
||||
if ((res = dict->lookup(dict, key)) == 0)
|
||||
return (0);
|
||||
if ((unb64 = dict_file_from_b64(dict, res)) == 0) {
|
||||
err = dict_file_get_error(dict);
|
||||
msg_warn("table %s:%s: key %s: %s",
|
||||
dict->type, dict->name,
|
||||
key, err);
|
||||
myfree(err);
|
||||
dict->error = DICT_ERR_CONFIG;
|
||||
return (0);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/* dict_file_wrapper_activate - wrap the lookup method */
|
||||
|
||||
void dict_file_wrapper_activate(DICT *dict)
|
||||
{
|
||||
const char myname[] = "dict_file_wrapper_activate";
|
||||
DICT_WRAPPER *wrapper;
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
if ((dict->flags & DICT_FLAG_UNB64_ACTIVE))
|
||||
msg_panic("%s: %s:%s Base64 decoding support is already activated",
|
||||
myname, dict->type, dict->name);
|
||||
|
||||
/*
|
||||
* Interpose on the lookup method.
|
||||
*/
|
||||
wrapper = dict_wrapper_alloc(sizeof(*wrapper));
|
||||
wrapper->name = "file";
|
||||
wrapper->lookup = dict_file_wrapper_lookup;
|
||||
dict_wrapper_prepend(dict, wrapper);
|
||||
|
||||
/*
|
||||
* Leave our mark. See sanity check above.
|
||||
*/
|
||||
dict->flags |= DICT_FLAG_UNB64_ACTIVE;
|
||||
return STR(unb64);
|
||||
}
|
||||
|
@ -5,10 +5,8 @@ owner=trusted (uid=2147483647)
|
||||
foo: error
|
||||
owner=trusted (uid=2147483647)
|
||||
> get file1
|
||||
file1=this-is-file1
|
||||
|
||||
file1=dGhpcy1pcy1maWxlMQo=
|
||||
> get file2
|
||||
file2=this-is-file2
|
||||
|
||||
file2=dGhpcy1pcy1maWxlMgo=
|
||||
> get file3
|
||||
file3: not found
|
||||
|
@ -479,16 +479,10 @@ DICT *dict_open3(const char *dict_type, const char *dict_name,
|
||||
msg_fatal("%s:%s: unable to get exclusive lock: %m",
|
||||
dict_type, dict_name);
|
||||
}
|
||||
/* Insert wrapper for UTF-8 syntax checks and casefolding. */
|
||||
/* Last step: insert proxy for UTF-8 syntax checks and casefolding. */
|
||||
if ((dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0
|
||||
&& DICT_NEED_UTF8_ACTIVATION(util_utf8_enable, dict_flags))
|
||||
dict_utf8_wrapper_activate(dict);
|
||||
|
||||
/* Insert wrapper for base64 decoding file content. */
|
||||
if ((dict->flags & DICT_FLAG_UNB64_ACTIVE) == 0
|
||||
&& dict->flags & DICT_FLAG_SRC_RHS_IS_FILE)
|
||||
dict_file_wrapper_activate(dict);
|
||||
|
||||
dict = dict_utf8_activate(dict);
|
||||
return (dict);
|
||||
}
|
||||
|
||||
|
@ -3,15 +3,10 @@
|
||||
./dict_open: warning: pcre map dict_pcre_file.map, line 6: empty pathname list: >>,<<': skipping this rule
|
||||
owner=untrusted (uid=USER)
|
||||
> get file1
|
||||
file1=this-is-file1
|
||||
|
||||
file1=dGhpcy1pcy1maWxlMQo=
|
||||
> get file2
|
||||
file2=this-is-file2
|
||||
|
||||
file2=dGhpcy1pcy1maWxlMgo=
|
||||
> get file3
|
||||
file3: not found
|
||||
> get files12
|
||||
files12=this-is-file1
|
||||
|
||||
this-is-file2
|
||||
|
||||
files12=dGhpcy1pcy1maWxlMQoKdGhpcy1pcy1maWxlMgo=
|
||||
|
@ -166,8 +166,7 @@ DICT *dict_pipe_open(const char *name, int open_flags, int dict_flags)
|
||||
DICT_TYPE_PIPE, name,
|
||||
DICT_TYPE_PIPE));
|
||||
if ((dict = dict_handle(dict_type_name)) == 0)
|
||||
dict = dict_open(dict_type_name, open_flags,
|
||||
dict_flags & ~DICT_FLAG_SRC_RHS_IS_FILE);
|
||||
dict = dict_open(dict_type_name, open_flags, dict_flags);
|
||||
dict_register(dict_type_name, dict);
|
||||
DICT_OWNER_AGGREGATE_UPDATE(aggr_owner, dict->owner);
|
||||
if (cpp == argv->argv)
|
||||
|
@ -5,8 +5,6 @@ owner=trusted (uid=2147483647)
|
||||
foo: error
|
||||
owner=trusted (uid=0)
|
||||
> get foo
|
||||
foo=this-is-file1
|
||||
|
||||
foo=dGhpcy1pcy1maWxlMQo=
|
||||
> get bar
|
||||
bar=this-is-file1
|
||||
|
||||
bar=dGhpcy1pcy1maWxlMQo=
|
||||
|
@ -1,10 +1,8 @@
|
||||
./dict_open: warning: regexp map dict_regexp_file.map, line 3: open dict_regexp_file3: No such file or directory: skipping this rule
|
||||
owner=untrusted (uid=USER)
|
||||
> get file1
|
||||
file1=this-is-file1
|
||||
|
||||
file1=dGhpcy1pcy1maWxlMQo=
|
||||
> get file2
|
||||
file2=this-is-file2
|
||||
|
||||
file2=dGhpcy1pcy1maWxlMgo=
|
||||
> get file3
|
||||
file3: not found
|
||||
|
@ -5,8 +5,6 @@ owner=trusted (uid=2147483647)
|
||||
foo: error
|
||||
owner=trusted (uid=2147483647)
|
||||
> get file1
|
||||
file1=this-is-file1
|
||||
|
||||
file1=dGhpcy1pcy1maWxlMQo=
|
||||
> get file2
|
||||
file2=this-is-file1
|
||||
|
||||
file2=dGhpcy1pcy1maWxlMQo=
|
||||
|
@ -179,8 +179,7 @@ DICT *dict_union_open(const char *name, int open_flags, int dict_flags)
|
||||
DICT_TYPE_UNION, name,
|
||||
DICT_TYPE_UNION));
|
||||
if ((dict = dict_handle(dict_type_name)) == 0)
|
||||
dict = dict_open(dict_type_name, open_flags,
|
||||
dict_flags & ~DICT_FLAG_SRC_RHS_IS_FILE);
|
||||
dict = dict_open(dict_type_name, open_flags, dict_flags);
|
||||
dict_register(dict_type_name, dict);
|
||||
DICT_OWNER_AGGREGATE_UPDATE(aggr_owner, dict->owner);
|
||||
if (cpp == argv->argv)
|
||||
|
@ -6,13 +6,13 @@
|
||||
/* SYNOPSIS
|
||||
/* #include <dict.h>
|
||||
/*
|
||||
/* void dict_utf8_wrapper_activate(
|
||||
/* DICT *dict_utf8_activate(
|
||||
/* DICT *dict)
|
||||
/* DESCRIPTION
|
||||
/* dict_utf8_wrapper_activate() wraps a dictionary's lookup/update/delete
|
||||
/* dict_utf8_activate() wraps a dictionary's lookup/update/delete
|
||||
/* methods with code that enforces UTF-8 checks on keys and
|
||||
/* values, and that logs a warning when incorrect UTF-8 is
|
||||
/* encountered.
|
||||
/* encountered. The original dictionary handle becomes invalid.
|
||||
/*
|
||||
/* The wrapper code enforces a policy that maximizes application
|
||||
/* robustness (it avoids the need for new error-handling code
|
||||
@ -22,6 +22,8 @@
|
||||
/* skipped while reporting a non-error status, and lookup
|
||||
/* results that contain a non-UTF-8 value are blocked while
|
||||
/* reporting a configuration error.
|
||||
/* BUGS
|
||||
/* dict_utf8_activate() does not nest.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
@ -131,10 +133,9 @@ static int dict_utf8_check(const char *string, CONST_CHAR_STAR *err)
|
||||
|
||||
/* dict_utf8_lookup - UTF-8 lookup method wrapper */
|
||||
|
||||
static const char *dict_utf8_lookup(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
const char *key)
|
||||
static const char *dict_utf8_lookup(DICT *dict, const char *key)
|
||||
{
|
||||
DICT_WRAPPER *next_wrapper;
|
||||
DICT_UTF8_BACKUP *backup;
|
||||
const char *utf8_err;
|
||||
const char *fold_res;
|
||||
const char *value;
|
||||
@ -155,8 +156,8 @@ static const char *dict_utf8_lookup(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
*/
|
||||
saved_flags = (dict->flags & DICT_FLAG_FOLD_ANY);
|
||||
dict->flags &= ~DICT_FLAG_FOLD_ANY;
|
||||
next_wrapper = wrapper->next;
|
||||
value = next_wrapper->lookup(next_wrapper, dict, fold_res);
|
||||
backup = dict->utf8_backup;
|
||||
value = backup->lookup(dict, fold_res);
|
||||
dict->flags |= saved_flags;
|
||||
|
||||
/*
|
||||
@ -174,10 +175,9 @@ static const char *dict_utf8_lookup(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
|
||||
/* dict_utf8_update - UTF-8 update method wrapper */
|
||||
|
||||
static int dict_utf8_update(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
const char *key, const char *value)
|
||||
static int dict_utf8_update(DICT *dict, const char *key, const char *value)
|
||||
{
|
||||
DICT_WRAPPER *next_wrapper;
|
||||
DICT_UTF8_BACKUP *backup;
|
||||
const char *utf8_err;
|
||||
const char *fold_res;
|
||||
int saved_flags;
|
||||
@ -209,8 +209,8 @@ static int dict_utf8_update(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
else {
|
||||
saved_flags = (dict->flags & DICT_FLAG_FOLD_ANY);
|
||||
dict->flags &= ~DICT_FLAG_FOLD_ANY;
|
||||
next_wrapper = wrapper->next;
|
||||
status = next_wrapper->update(next_wrapper, dict, fold_res, value);
|
||||
backup = dict->utf8_backup;
|
||||
status = backup->update(dict, fold_res, value);
|
||||
dict->flags |= saved_flags;
|
||||
return (status);
|
||||
}
|
||||
@ -218,9 +218,9 @@ static int dict_utf8_update(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
|
||||
/* dict_utf8_delete - UTF-8 delete method wrapper */
|
||||
|
||||
static int dict_utf8_delete(DICT_WRAPPER *wrapper, DICT *dict, const char *key)
|
||||
static int dict_utf8_delete(DICT *dict, const char *key)
|
||||
{
|
||||
DICT_WRAPPER *next_wrapper;
|
||||
DICT_UTF8_BACKUP *backup;
|
||||
const char *utf8_err;
|
||||
const char *fold_res;
|
||||
int saved_flags;
|
||||
@ -242,19 +242,19 @@ static int dict_utf8_delete(DICT_WRAPPER *wrapper, DICT *dict, const char *key)
|
||||
else {
|
||||
saved_flags = (dict->flags & DICT_FLAG_FOLD_ANY);
|
||||
dict->flags &= ~DICT_FLAG_FOLD_ANY;
|
||||
next_wrapper = wrapper->next;
|
||||
status = next_wrapper->delete(next_wrapper, dict, fold_res);
|
||||
backup = dict->utf8_backup;
|
||||
status = backup->delete(dict, fold_res);
|
||||
dict->flags |= saved_flags;
|
||||
return (status);
|
||||
}
|
||||
}
|
||||
|
||||
/* dict_utf8_wrapper_activate - wrap legacy dict object for UTF-8 processing */
|
||||
/* dict_utf8_activate - wrap a legacy dict object for UTF-8 processing */
|
||||
|
||||
void dict_utf8_wrapper_activate(DICT *dict)
|
||||
DICT *dict_utf8_activate(DICT *dict)
|
||||
{
|
||||
const char myname[] = "dict_utf8_wrapper_activate";
|
||||
DICT_WRAPPER *wrapper;
|
||||
const char myname[] = "dict_utf8_activate";
|
||||
DICT_UTF8_BACKUP *backup;
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
@ -264,22 +264,37 @@ void dict_utf8_wrapper_activate(DICT *dict)
|
||||
if ((dict->flags & DICT_FLAG_UTF8_REQUEST) == 0)
|
||||
msg_panic("%s: %s:%s does not request Unicode support",
|
||||
myname, dict->type, dict->name);
|
||||
if ((dict->flags & DICT_FLAG_UTF8_ACTIVE))
|
||||
if ((dict->flags & DICT_FLAG_UTF8_ACTIVE) || dict->utf8_backup != 0)
|
||||
msg_panic("%s: %s:%s Unicode support is already activated",
|
||||
myname, dict->type, dict->name);
|
||||
|
||||
/*
|
||||
* Interpose on the lookup/update/delete methods.
|
||||
* Unlike dict_debug(3) we do not put a proxy dict object in front of the
|
||||
* encapsulated object, because then we would have to bidirectionally
|
||||
* propagate changes in the data members (errors, flags, jbuf, and so on)
|
||||
* between proxy object and encapsulated object.
|
||||
*
|
||||
* Instead we attach ourselves behind the encapsulated dict object, and
|
||||
* redirect some function pointers to ourselves.
|
||||
*/
|
||||
wrapper = dict_wrapper_alloc(sizeof(*wrapper));
|
||||
wrapper->name = "utf8";
|
||||
wrapper->lookup = dict_utf8_lookup;
|
||||
wrapper->update = dict_utf8_update;
|
||||
wrapper->delete = dict_utf8_delete;
|
||||
dict_wrapper_prepend(dict, wrapper);
|
||||
backup = dict->utf8_backup = (DICT_UTF8_BACKUP *) mymalloc(sizeof(*backup));
|
||||
|
||||
/*
|
||||
* Interpose on the lookup/update/delete methods. It is a conscious
|
||||
* decision not to tinker with the iterator or destructor.
|
||||
*/
|
||||
backup->lookup = dict->lookup;
|
||||
backup->update = dict->update;
|
||||
backup->delete = dict->delete;
|
||||
|
||||
dict->lookup = dict_utf8_lookup;
|
||||
dict->update = dict_utf8_update;
|
||||
dict->delete = dict_utf8_delete;
|
||||
|
||||
/*
|
||||
* Leave our mark. See sanity check above.
|
||||
*/
|
||||
dict->flags |= DICT_FLAG_UTF8_ACTIVE;
|
||||
|
||||
return (dict);
|
||||
}
|
||||
|
@ -1,243 +0,0 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* dict_wrapper 3
|
||||
/* SUMMARY
|
||||
/* dictionary method wrappers
|
||||
/* SYNOPSIS
|
||||
/* #include <dict.h>
|
||||
/*
|
||||
/* void dict_wrapper_prepend(
|
||||
/* DICT *dict,
|
||||
/* DICT_WRAPPER *wrapper)
|
||||
/*
|
||||
/* DICT_WRAPPER *dict_wrapper_alloc(
|
||||
/* ssize_t size)
|
||||
/*
|
||||
/* void dict_wrapper_free(
|
||||
/* DICT_WRAPPER *wrapper)
|
||||
/* DESCRIPTION
|
||||
/* dict_wrapper_prepend() prepends the specified dictionary
|
||||
/* lookup/update/delete wrappers to a chain that is evaluated
|
||||
/* in reverse order. dict_wrapper_prepend() takes ownership
|
||||
/* of the wrapper.
|
||||
/*
|
||||
/* dict_wrapper_alloc() allocates memory for a dictionary
|
||||
/* wrapper object and initializes all wrapper methods to
|
||||
/* empty (no override).
|
||||
/*
|
||||
/* dict_wrapper_free() destroys a chain of dictionary wrappers.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/*
|
||||
* System library.
|
||||
*/
|
||||
#include <sys_defs.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Utility library.
|
||||
*/
|
||||
#include <msg.h>
|
||||
#include <stringops.h>
|
||||
#include <dict.h>
|
||||
#include <mymalloc.h>
|
||||
#include <msg.h>
|
||||
|
||||
/*
|
||||
* The final DICT_WRAPPER is installed first, and also contains the original
|
||||
* DICT's methods.
|
||||
*/
|
||||
typedef struct {
|
||||
DICT_WRAPPER wrapper; /* parent class, must be first */
|
||||
const char *(*saved_lookup) (DICT *, const char *);
|
||||
int (*saved_update) (DICT *, const char *, const char *);
|
||||
int (*saved_delete) (DICT *, const char *);
|
||||
} DICT_FINAL_WRAPPER;
|
||||
|
||||
/*
|
||||
* Functions that override DICT methods, and that call into the head of
|
||||
* the dict wrapper chain.
|
||||
*/
|
||||
|
||||
/* dict_wrapper_lookup - DICT method to call into wrapper chain head */
|
||||
|
||||
static const char *dict_wrapper_lookup(DICT *dict, const char *key)
|
||||
{
|
||||
DICT_WRAPPER *head_wrapper = dict->wrapper;
|
||||
|
||||
return (head_wrapper->lookup(head_wrapper, dict, key));
|
||||
}
|
||||
|
||||
/* dict_wrapper_update - DICT method to call into wrapper chain head */
|
||||
|
||||
static int dict_wrapper_update(DICT *dict, const char *key, const char *value)
|
||||
{
|
||||
DICT_WRAPPER *head_wrapper = dict->wrapper;
|
||||
|
||||
return (head_wrapper->update(head_wrapper, dict, key, value));
|
||||
}
|
||||
|
||||
/* dict_wrapper_delete - DICT method to call into wrapper chain head */
|
||||
|
||||
static int dict_wrapper_delete(DICT *dict, const char *key)
|
||||
{
|
||||
DICT_WRAPPER *head_wrapper = dict->wrapper;
|
||||
|
||||
return (head_wrapper->delete(head_wrapper, dict, key));
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty methods for wrappers that override only some methods. These ensure
|
||||
* that the next wrapper's methods are called with the right 'self' pointer.
|
||||
*/
|
||||
|
||||
/* empty_wrapper_lookup - wrapper method to call into next wrapper */
|
||||
|
||||
static const char *empty_wrapper_lookup(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
const char *key)
|
||||
{
|
||||
DICT_WRAPPER *next_wrapper = wrapper->next;
|
||||
|
||||
return (next_wrapper->lookup(next_wrapper, dict, key));
|
||||
}
|
||||
|
||||
/* empty_wrapper_update - wrapper method to call into next wrapper */
|
||||
|
||||
static int empty_wrapper_update(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
const char *key, const char *value)
|
||||
{
|
||||
DICT_WRAPPER *next_wrapper = wrapper->next;
|
||||
|
||||
return (next_wrapper->update(next_wrapper, dict, key, value));
|
||||
}
|
||||
|
||||
/* empty_wrapper_delete - wrapper method to call into next wrapper */
|
||||
|
||||
static int empty_wrapper_delete(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
const char *key)
|
||||
{
|
||||
DICT_WRAPPER *next_wrapper = wrapper->next;
|
||||
|
||||
return (next_wrapper->delete(next_wrapper, dict, key));
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper methods for the final dict wrapper in the chain. These call into
|
||||
* the saved DICT methods.
|
||||
*/
|
||||
|
||||
/* final_wrapper_lookup - wrapper method to call saved DICT method */
|
||||
|
||||
static const char *final_wrapper_lookup(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
const char *key)
|
||||
{
|
||||
DICT_FINAL_WRAPPER *final_wrapper = (DICT_FINAL_WRAPPER *) wrapper;
|
||||
|
||||
return (final_wrapper->saved_lookup(dict, key));
|
||||
}
|
||||
|
||||
/* final_wrapper_update - wrapper method to call saved DICT method */
|
||||
|
||||
static int final_wrapper_update(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
const char *key, const char *value)
|
||||
{
|
||||
DICT_FINAL_WRAPPER *final_wrapper = (DICT_FINAL_WRAPPER *) wrapper;
|
||||
|
||||
return (final_wrapper->saved_update(dict, key, value));
|
||||
}
|
||||
|
||||
/* final_wrapper_delete - wrapper method to call saved DICT method */
|
||||
|
||||
static int final_wrapper_delete(DICT_WRAPPER *wrapper, DICT *dict,
|
||||
const char *key)
|
||||
{
|
||||
DICT_FINAL_WRAPPER *final_wrapper = (DICT_FINAL_WRAPPER *) wrapper;
|
||||
|
||||
return (final_wrapper->saved_delete(dict, key));
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, the functions that build the wrapper chain.
|
||||
*/
|
||||
|
||||
/* dict_wrapper_activate - wrap a DICT object for additional processing */
|
||||
|
||||
static void dict_wrapper_activate(DICT *dict)
|
||||
{
|
||||
const char myname[] = "dict_wrapper_activate";
|
||||
DICT_FINAL_WRAPPER *final_wrapper;
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
if (dict->wrapper != 0)
|
||||
msg_panic("%s: %s:%s wrapper support is already activated",
|
||||
myname, dict->type, dict->name);
|
||||
|
||||
/*
|
||||
* Install the final wrapper object that calls the original DICT's
|
||||
* methods, and redirect DICT's method calls to ourselves. All other
|
||||
* dictionary wrappers will be prepended to a chain that ends in the
|
||||
* final wrapper object.
|
||||
*/
|
||||
final_wrapper = (DICT_FINAL_WRAPPER *) mymalloc(sizeof(*final_wrapper));
|
||||
final_wrapper->wrapper.name = "final";
|
||||
final_wrapper->wrapper.lookup = final_wrapper_lookup;
|
||||
final_wrapper->wrapper.update = final_wrapper_update;
|
||||
final_wrapper->wrapper.delete = final_wrapper_delete;
|
||||
final_wrapper->wrapper.next = 0;
|
||||
dict->wrapper = &final_wrapper->wrapper;
|
||||
|
||||
/*
|
||||
* Interpose on the DICT's lookup/update/delete methods.
|
||||
*/
|
||||
final_wrapper->saved_lookup = dict->lookup;
|
||||
final_wrapper->saved_update = dict->update;
|
||||
final_wrapper->saved_delete = dict->delete;
|
||||
|
||||
dict->lookup = dict_wrapper_lookup;
|
||||
dict->update = dict_wrapper_update;
|
||||
dict->delete = dict_wrapper_delete;
|
||||
}
|
||||
|
||||
/* dict_wrapper_alloc - allocate and initialize dictionary wrapper */
|
||||
|
||||
DICT_WRAPPER *dict_wrapper_alloc(ssize_t size)
|
||||
{
|
||||
DICT_WRAPPER *wrapper;
|
||||
|
||||
wrapper = (DICT_WRAPPER *) mymalloc(size);
|
||||
wrapper->lookup = empty_wrapper_lookup;
|
||||
wrapper->update = empty_wrapper_update;
|
||||
wrapper->delete = empty_wrapper_delete;
|
||||
return (wrapper);
|
||||
}
|
||||
|
||||
/* dict_wrapper_prepend - prepend dict method overrides */
|
||||
|
||||
void dict_wrapper_prepend(DICT *dict, DICT_WRAPPER *wrapper)
|
||||
{
|
||||
if (dict->wrapper == 0)
|
||||
dict_wrapper_activate(dict);
|
||||
|
||||
wrapper->next = dict->wrapper;
|
||||
dict->wrapper = wrapper;
|
||||
}
|
||||
|
||||
/* dict_wrapper_free - wrapper destructor */
|
||||
|
||||
void dict_wrapper_free(DICT_WRAPPER *wrapper)
|
||||
{
|
||||
if (wrapper->next)
|
||||
dict_wrapper_free(wrapper->next);
|
||||
myfree((void *) wrapper);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user