2
0
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:
Wietse Venema 2018-12-29 00:00:00 -05:00 committed by Viktor Dukhovni
parent b15570215e
commit 7c27c10eb2
25 changed files with 227 additions and 462 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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,
};

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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=

View File

@ -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)

View File

@ -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=

View File

@ -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

View File

@ -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=

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}