xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/dict_pipe.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1 /*	$NetBSD: dict_pipe.c,v 1.2 2017/02/14 01:16:49 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	dict_pipe 3
6 /* SUMMARY
7 /*	dictionary manager interface for pipelined tables
8 /* SYNOPSIS
9 /*	#include <dict_pipe.h>
10 /*
11 /*	DICT	*dict_pipe_open(name, open_flags, dict_flags)
12 /*	const char *name;
13 /*	int	open_flags;
14 /*	int	dict_flags;
15 /* DESCRIPTION
16 /*	dict_pipe_open() opens a pipeline of one or more tables.
17 /*	Example: "\fBpipemap:{\fItype_1:name_1, ..., type_n:name_n\fR}".
18 /*
19 /*	Each "pipemap:" query is given to the first table.  Each
20 /*	lookup result becomes the query for the next table in the
21 /*	pipeline, and the last table produces the final result.
22 /*	When any table lookup produces no result, the pipeline
23 /*	produces no result.
24 /*
25 /*	The first and last characters of the "pipemap:" table name
26 /*	must be '{' and '}'. Within these, individual maps are
27 /*	separated with comma or whitespace.
28 /*
29 /*	The open_flags and dict_flags arguments are passed on to
30 /*	the underlying dictionaries.
31 /* SEE ALSO
32 /*	dict(3) generic dictionary manager
33 /* LICENSE
34 /* .ad
35 /* .fi
36 /*	The Secure Mailer license must be distributed with this software.
37 /* AUTHOR(S)
38 /*	Wietse Venema
39 /*	IBM T.J. Watson Research
40 /*	P.O. Box 704
41 /*	Yorktown Heights, NY 10598, USA
42 /*--*/
43 
44 /* System library. */
45 
46 #include <sys_defs.h>
47 #include <string.h>
48 
49 /* Utility library. */
50 
51 #include <msg.h>
52 #include "mymalloc.h"
53 #include "htable.h"
54 #include "dict.h"
55 #include "dict_pipe.h"
56 #include "stringops.h"
57 #include "vstring.h"
58 
59 /* Application-specific. */
60 
61 typedef struct {
62     DICT    dict;			/* generic members */
63     ARGV   *map_pipe;			/* pipelined tables */
64     VSTRING *qr_buf;			/* query/reply buffer */
65 } DICT_PIPE;
66 
67 #define STR(x) vstring_str(x)
68 
69 /* dict_pipe_lookup - search pipelined tables */
70 
dict_pipe_lookup(DICT * dict,const char * query)71 static const char *dict_pipe_lookup(DICT *dict, const char *query)
72 {
73     static const char myname[] = "dict_pipe_lookup";
74     DICT_PIPE *dict_pipe = (DICT_PIPE *) dict;
75     DICT   *map;
76     char  **cpp;
77     char   *dict_type_name;
78     const char *result = 0;
79 
80     vstring_strcpy(dict_pipe->qr_buf, query);
81     for (cpp = dict_pipe->map_pipe->argv; (dict_type_name = *cpp) != 0; cpp++) {
82 	if ((map = dict_handle(dict_type_name)) == 0)
83 	    msg_panic("%s: dictionary \"%s\" not found", myname, dict_type_name);
84 	if ((result = dict_get(map, STR(dict_pipe->qr_buf))) == 0)
85 	    DICT_ERR_VAL_RETURN(dict, map->error, result);
86 	vstring_strcpy(dict_pipe->qr_buf, result);
87     }
88     DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, STR(dict_pipe->qr_buf));
89 }
90 
91 /* dict_pipe_close - disassociate from pipelined tables */
92 
dict_pipe_close(DICT * dict)93 static void dict_pipe_close(DICT *dict)
94 {
95     DICT_PIPE *dict_pipe = (DICT_PIPE *) dict;
96     char  **cpp;
97     char   *dict_type_name;
98 
99     for (cpp = dict_pipe->map_pipe->argv; (dict_type_name = *cpp) != 0; cpp++)
100 	dict_unregister(dict_type_name);
101     argv_free(dict_pipe->map_pipe);
102     vstring_free(dict_pipe->qr_buf);
103     dict_free(dict);
104 }
105 
106 /* dict_pipe_open - open pipelined tables */
107 
dict_pipe_open(const char * name,int open_flags,int dict_flags)108 DICT   *dict_pipe_open(const char *name, int open_flags, int dict_flags)
109 {
110     static const char myname[] = "dict_pipe_open";
111     DICT_PIPE *dict_pipe;
112     char   *saved_name = 0;
113     char   *dict_type_name;
114     ARGV   *argv = 0;
115     char  **cpp;
116     DICT   *dict;
117     int     match_flags = 0;
118     struct DICT_OWNER aggr_owner;
119     size_t  len;
120 
121     /*
122      * Clarity first. Let the optimizer worry about redundant code.
123      */
124 #define DICT_PIPE_RETURN(x) do { \
125 	    if (saved_name != 0) \
126 		myfree(saved_name); \
127 	    if (argv != 0) \
128 		argv_free(argv); \
129 	    return (x); \
130 	} while (0)
131 
132     /*
133      * Sanity checks.
134      */
135     if (open_flags != O_RDONLY)
136 	DICT_PIPE_RETURN(dict_surrogate(DICT_TYPE_PIPE, name,
137 					open_flags, dict_flags,
138 				  "%s:%s map requires O_RDONLY access mode",
139 					DICT_TYPE_PIPE, name));
140 
141     /*
142      * Split the table name into its constituent parts.
143      */
144     if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0
145 	|| *(saved_name = mystrndup(name + 1, len - 2)) == 0
146 	|| ((argv = argv_splitq(saved_name, CHARS_COMMA_SP, CHARS_BRACE)),
147 	    (argv->argc == 0)))
148 	DICT_PIPE_RETURN(dict_surrogate(DICT_TYPE_PIPE, name,
149 					open_flags, dict_flags,
150 					"bad syntax: \"%s:%s\"; "
151 					"need \"%s:{type:name...}\"",
152 					DICT_TYPE_PIPE, name,
153 					DICT_TYPE_PIPE));
154 
155     /*
156      * The least-trusted table in the pipeline determines the over-all trust
157      * level. The first table determines the pattern-matching flags.
158      */
159     DICT_OWNER_AGGREGATE_INIT(aggr_owner);
160     for (cpp = argv->argv; (dict_type_name = *cpp) != 0; cpp++) {
161 	if (msg_verbose)
162 	    msg_info("%s: %s", myname, dict_type_name);
163 	if (strchr(dict_type_name, ':') == 0)
164 	    DICT_PIPE_RETURN(dict_surrogate(DICT_TYPE_PIPE, name,
165 					    open_flags, dict_flags,
166 					    "bad syntax: \"%s:%s\"; "
167 					    "need \"%s:{type:name...}\"",
168 					    DICT_TYPE_PIPE, name,
169 					    DICT_TYPE_PIPE));
170 	if ((dict = dict_handle(dict_type_name)) == 0)
171 	    dict = dict_open(dict_type_name, open_flags, dict_flags);
172 	dict_register(dict_type_name, dict);
173 	DICT_OWNER_AGGREGATE_UPDATE(aggr_owner, dict->owner);
174 	if (cpp == argv->argv)
175 	    match_flags = dict->flags & (DICT_FLAG_FIXED | DICT_FLAG_PATTERN);
176     }
177 
178     /*
179      * Bundle up the result.
180      */
181     dict_pipe =
182 	(DICT_PIPE *) dict_alloc(DICT_TYPE_PIPE, name, sizeof(*dict_pipe));
183     dict_pipe->dict.lookup = dict_pipe_lookup;
184     dict_pipe->dict.close = dict_pipe_close;
185     dict_pipe->dict.flags = dict_flags | match_flags;
186     dict_pipe->dict.owner = aggr_owner;
187     dict_pipe->qr_buf = vstring_alloc(100);
188     dict_pipe->map_pipe = argv;
189     argv = 0;
190     DICT_PIPE_RETURN(DICT_DEBUG (&dict_pipe->dict));
191 }
192