Postfix3.3.1
data_redirect.c
[詳解]
1 /*++
2 /* NAME
3 /* data_redirect 3
4 /* SUMMARY
5 /* redirect legacy writes to Postfix-owned data directory
6 /* SYNOPSIS
7 /* #include <data_redirect.h>
8 /*
9 /* char *data_redirect_file(result, path)
10 /* VSTRING *result;
11 /* const char *path;
12 /*
13 /* char *data_redirect_map(result, map)
14 /* VSTRING *result;
15 /* const char *map;
16 /* DESCRIPTION
17 /* With Postfix version 2.5 and later, the tlsmgr(8) and
18 /* verify(8) servers no longer open cache files with root
19 /* privilege. This avoids a potential security loophole where
20 /* the ownership of a file (or directory) does not match the
21 /* trust level of the content of that file (or directory).
22 /*
23 /* This module implements a migration aid that allows a
24 /* transition without disruption of service.
25 /*
26 /* data_redirect_file() detects a request to open a file in a
27 /* non-Postfix directory, logs a warning, and redirects the
28 /* request to the Postfix-owned data_directory.
29 /*
30 /* data_redirect_map() performs the same function for a limited
31 /* subset of file-based lookup tables.
32 /*
33 /* Arguments:
34 /* .IP result
35 /* A possibly redirected copy of the input.
36 /* .IP path
37 /* The pathname that may be redirected.
38 /* .IP map
39 /* The "mapname" or "maptype:mapname" that may be redirected.
40 /* The result is always in "maptype:mapname" form.
41 /* BUGS
42 /* Only a few map types are redirected. This is acceptable for
43 /* a temporary migration tool.
44 /* DIAGNOSTICS
45 /* Fatal errors: memory allocation failure.
46 /* CONFIGURATION PARAMETERS
47 /* data_directory, location of Postfix-writable files
48 /* LICENSE
49 /* .ad
50 /* .fi
51 /* The Secure Mailer license must be distributed with this software.
52 /* AUTHOR(S)
53 /* Wietse Venema
54 /* IBM T.J. Watson Research
55 /* P.O. Box 704
56 /* Yorktown Heights, NY 10598, USA
57 /*--*/
58 
59 /* System library. */
60 
61 #include <sys_defs.h>
62 #include <sys/stat.h>
63 #include <string.h>
64 
65 /* Utility library. */
66 
67 #include <msg.h>
68 #include <vstring.h>
69 #include <stringops.h>
70 #include <split_at.h>
71 #include <name_code.h>
72 #include <dict_db.h>
73 #include <dict_dbm.h>
74 #include <dict_cdb.h>
75 #include <dict_lmdb.h>
76 #include <warn_stat.h>
77 
78 /* Global directory. */
79 
80 #include <mail_params.h>
81 #include <dict_proxy.h>
82 #include <data_redirect.h>
83 
84 /* Application-specific. */
85 
86 #define STR(x) vstring_str(x)
87 #define LEN(x) VSTRING_LEN(x)
88 
89  /*
90  * Redirect only these map types, so that we don't try stupid things with
91  * NIS, *SQL or LDAP. This is a transition feature for legacy TLS and verify
92  * configurations, so it does not have to cover every possible map type.
93  *
94  * XXX In this same spirit of imperfection we also use hard-coded map names,
95  * because maintainers may add map types that the official release doesn't
96  * even know about, because map types may be added dynamically on some
97  * platforms.
98  */
99 static const NAME_CODE data_redirect_map_types[] = {
100  DICT_TYPE_HASH, 1,
101  DICT_TYPE_BTREE, 1,
102  DICT_TYPE_DBM, 1,
103  DICT_TYPE_LMDB, 1,
104  DICT_TYPE_CDB, 1, /* not a read-write map type */
105  "sdbm", 1, /* legacy 3rd-party TLS */
106  "dbz", 1, /* just in case */
107  0, 0,
108 };
109 
110 /* data_redirect_path - redirect path to Postfix-owned directory */
111 
112 static char *data_redirect_path(VSTRING *result, const char *path,
113  const char *log_type, const char *log_name)
114 {
115  struct stat st;
116 
117 #define PATH_DELIMITER "/"
118 
119  (void) sane_dirname(result, path);
120  if (stat(STR(result), &st) != 0 || st.st_uid == var_owner_uid) {
121  vstring_strcpy(result, path);
122  } else {
123  msg_warn("request to update %s %s in non-%s directory %s",
124  log_type, log_name, var_mail_owner, STR(result));
125  msg_warn("redirecting the request to %s-owned %s %s",
127  (void) sane_basename(result, path);
128  vstring_prepend(result, PATH_DELIMITER, sizeof(PATH_DELIMITER) - 1);
129  vstring_prepend(result, var_data_dir, strlen(var_data_dir));
130  }
131  return (STR(result));
132 }
133 
134 /* data_redirect_file - redirect file to Postfix-owned directory */
135 
136 char *data_redirect_file(VSTRING *result, const char *path)
137 {
138 
139  /*
140  * Sanity check.
141  */
142  if (path == STR(result))
143  msg_panic("data_redirect_file: result clobbers input");
144 
145  return (data_redirect_path(result, path, "file", path));
146 }
147 
148 char *data_redirect_map(VSTRING *result, const char *map)
149 {
150  const char *path;
151  const char *map_type;
152  size_t map_type_len;
153 
154 #define MAP_DELIMITER ":"
155 
156  /*
157  * Sanity check.
158  */
159  if (map == STR(result))
160  msg_panic("data_redirect_map: result clobbers input");
161 
162  /*
163  * Parse the input into map type and map name.
164  */
165  path = strchr(map, MAP_DELIMITER[0]);
166  if (path != 0) {
167  map_type = map;
168  map_type_len = path - map;
169  path += 1;
170  } else {
171  map_type = var_db_type;
172  map_type_len = strlen(map_type);
173  path = map;
174  }
175 
176  /*
177  * Redirect the pathname.
178  */
179  vstring_strncpy(result, map_type, map_type_len);
180  if (name_code(data_redirect_map_types, NAME_CODE_FLAG_NONE, STR(result))) {
181  data_redirect_path(result, path, "table", map);
182  } else {
183  vstring_strcpy(result, path);
184  }
185 
186  /*
187  * (Re)combine the map type with the map name.
188  */
189  vstring_prepend(result, MAP_DELIMITER, sizeof(MAP_DELIMITER) - 1);
190  vstring_prepend(result, map_type, map_type_len);
191  return (STR(result));
192 }
193 
194  /*
195  * Proof-of-concept test program. This can't be run as automated regression
196  * test, because the result depends on main.cf information (mail_owner UID
197  * and data_directory pathname) and on local file system details.
198  */
199 #ifdef TEST
200 
201 #include <unistd.h>
202 #include <stdlib.h>
203 #include <vstring_vstream.h>
204 #include <mail_conf.h>
205 
206 int main(int argc, char **argv)
207 {
208  VSTRING *inbuf = vstring_alloc(100);
209  VSTRING *result = vstring_alloc(100);
210  char *bufp;
211  char *cmd;
212  char *target;
213  char *junk;
214 
215  mail_conf_read();
216 
217  while (vstring_get_nonl(inbuf, VSTREAM_IN) != VSTREAM_EOF) {
218  bufp = STR(inbuf);
219  if (!isatty(0)) {
220  vstream_printf("> %s\n", bufp);
222  }
223  if (*bufp == '#')
224  continue;
225  if ((cmd = mystrtok(&bufp, " \t")) == 0) {
226  vstream_printf("usage: file path|map maptype:mapname\n");
228  continue;
229  }
230  target = mystrtokq(&bufp, " \t");
231  junk = mystrtok(&bufp, " \t");
232  if (strcmp(cmd, "file") == 0 && target && !junk) {
233  data_redirect_file(result, target);
234  vstream_printf("%s -> %s\n", target, STR(result));
235  } else if (strcmp(cmd, "map") == 0 && target && !junk) {
236  data_redirect_map(result, target);
237  vstream_printf("%s -> %s\n", target, STR(result));
238  } else {
239  vstream_printf("usage: file path|map maptype:mapname\n");
240  }
242  }
243  vstring_free(inbuf);
244  return (0);
245 }
246 
247 #endif
#define VSTREAM_EOF
Definition: vstream.h:110
#define PATH_DELIMITER
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define VSTREAM_OUT
Definition: vstream.h:67
#define stat(p, s)
Definition: warn_stat.h:18
char * data_redirect_map(VSTRING *result, const char *map)
int main(int argc, char **argv)
Definition: anvil.c:1010
char * mystrtokq(char **src, const char *sep, const char *parens)
Definition: mystrtok.c:80
#define VSTREAM_IN
Definition: vstream.h:66
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
char * sane_dirname(VSTRING *bp, const char *path)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
void mail_conf_read(void)
Definition: mail_conf.c:178
#define DICT_TYPE_LMDB
Definition: dict_lmdb.h:22
VSTRING * vstring_prepend(VSTRING *vp, const char *buf, ssize_t len)
Definition: vstring.c:545
uid_t var_owner_uid
Definition: mail_params.c:234
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define NAME_CODE_FLAG_NONE
Definition: name_code.h:22
#define MAP_DELIMITER
char * data_redirect_file(VSTRING *result, const char *path)
int name_code(const NAME_CODE *table, int flags, const char *name)
Definition: name_code.c:65
char * var_data_dir
Definition: mail_params.c:243
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define DICT_TYPE_HASH
Definition: dict_db.h:22
#define STR(x)
Definition: data_redirect.c:86
char * sane_basename(VSTRING *bp, const char *path)
Definition: sane_basename.c:69
#define DICT_TYPE_BTREE
Definition: dict_db.h:23
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
char * var_mail_owner
Definition: mail_params.c:233
#define DICT_TYPE_DBM
Definition: dict_dbm.h:22
char * var_db_type
Definition: mail_params.c:270
VSTRING * vstring_strncpy(VSTRING *vp, const char *src, ssize_t len)
Definition: vstring.c:445
#define DICT_TYPE_CDB
Definition: dict_cdb.h:22
#define VAR_DATA_DIR
Definition: mail_params.h:310