297 #include <sys/stat.h>
335 #define STR vstring_str
336 #define LEN VSTRING_LEN
338 #define POSTMAP_FLAG_AS_OWNER (1<<0)
339 #define POSTMAP_FLAG_SAVE_PERM (1<<1)
340 #define POSTMAP_FLAG_HEADER_KEY (1<<2)
341 #define POSTMAP_FLAG_BODY_KEY (1<<3)
342 #define POSTMAP_FLAG_MIME_KEY (1<<4)
344 #define POSTMAP_FLAG_HB_KEY (POSTMAP_FLAG_HEADER_KEY | POSTMAP_FLAG_BODY_KEY)
345 #define POSTMAP_FLAG_FULL_KEY (POSTMAP_FLAG_BODY_KEY | POSTMAP_FLAG_MIME_KEY)
346 #define POSTMAP_FLAG_ANY_KEY (POSTMAP_FLAG_HB_KEY | POSTMAP_FLAG_MIME_KEY)
363 static void postmap(
char *map_type,
char *path_name,
int postmap_flags,
364 int open_flags,
int dict_flags)
380 if ((open_flags & O_TRUNC) == 0) {
387 msg_fatal(
"can't create maps via the proxy service");
389 if ((source_fp =
vstream_fopen(path_name, O_RDONLY, 0)) == 0)
399 saved_mask = umask(022 | (~st.st_mode & 077));
407 && (st.st_uid != geteuid() || st.st_gid != getegid()))
415 mkmap =
mkmap_open(map_type, path_name, open_flags, dict_flags);
420 if ((postmap_flags & POSTMAP_FLAG_SAVE_PERM) && S_ISREG(st.st_mode))
438 while (
readllines(line_buffer, source_fp, &last_line, &lineno)) {
447 msg_warn(
"%s, line %d: non-UTF-8 input \"%s\""
448 " -- ignoring this line",
457 for (value =
STR(line_buffer); *value; value++) {
458 if (*value ==
'\\') {
464 }
else if (*value ==
'"') {
465 in_quotes = !in_quotes;
469 msg_warn(
"%s, line %d: unbalanced '\"' in '%s'"
470 " -- ignoring this line",
486 key =
STR(line_buffer);
492 if (*key == 0 || *value == 0) {
493 msg_warn(
"%s, line %d: expected format: key whitespace value",
497 if (key[strlen(key) - 1] ==
':')
498 msg_warn(
"%s, line %d: record is in \"key: value\" format; is this an alias file?",
507 msg_fatal(
"table %s:%s: write error: %m",
528 static void postmap_body(
void *ptr,
int unused_rec_type,
535 char **maps = state->
maps;
538 const char *map_name;
542 for (n = 0; n < map_count; n++) {
544 dicts[n] = ((map_name =
split_at(maps[n],
':')) != 0 ?
545 dict_open3(maps[n], map_name, O_RDONLY, dict_flags) :
547 if ((value =
dict_get(dicts[n], keybuf)) != 0) {
549 msg_warn(
"table %s:%s: key %s: empty string result is not allowed",
550 dicts[n]->type, dicts[n]->name, keybuf);
551 msg_warn(
"table %s:%s should return NO RESULT in case of NOT FOUND",
552 dicts[n]->type, dicts[n]->name);
559 msg_fatal(
"table %s:%s: query error: %m",
560 dicts[n]->type, dicts[n]->name);
566 static void postmap_header(
void *ptr,
int unused_header_class,
575 postmap_body(ptr, 0,
STR(header_buf),
LEN(header_buf), offset);
580 static void postmap_head_end(
void *ptr)
592 static int postmap_queries(
VSTREAM *in,
char **maps,
const int map_count,
593 const int postmap_flags,
594 const int dict_flags)
599 const char *map_name;
607 msg_panic(
"postmap_queries: bad map count");
613 for (n = 0; n < map_count; n++)
622 for (n = 0; n < map_count; n++) {
624 dicts[n] = ((map_name =
split_at(maps[n],
':')) != 0 ?
625 dict_open3(maps[n], map_name, O_RDONLY, dict_flags) :
627 if ((value =
dict_get(dicts[n],
STR(keybuf))) != 0) {
629 msg_warn(
"table %s:%s: key %s: empty string result is not allowed",
630 dicts[n]->type, dicts[n]->name,
STR(keybuf));
631 msg_warn(
"table %s:%s should return NO RESULT in case of NOT FOUND",
632 dicts[n]->type, dicts[n]->name);
639 msg_fatal(
"table %s:%s: query error: %m",
640 dicts[n]->type, dicts[n]->name);
651 key_state.
dicts = dicts;
652 key_state.
maps = maps;
668 (
void *) &key_state);
676 STR(keybuf),
LEN(keybuf));
687 found = key_state.
found;
695 for (n = 0; n < map_count; n++)
706 static int postmap_query(
const char *map_type,
const char *map_name,
707 const char *key,
int dict_flags)
712 dict =
dict_open3(map_type, map_name, O_RDONLY, dict_flags);
713 if ((value =
dict_get(dict, key)) != 0) {
715 msg_warn(
"table %s:%s: key %s: empty string result is not allowed",
716 map_type, map_name, key);
717 msg_warn(
"table %s:%s should return NO RESULT in case of NOT FOUND",
731 static int postmap_deletes(
VSTREAM *in,
char **maps,
const int map_count,
737 const char *map_name;
745 msg_panic(
"postmap_deletes: bad map count");
751 for (n = 0; n < map_count; n++) {
754 open_flags = O_RDWR | O_CREAT;
757 dicts[n] = (map_name != 0 ?
758 dict_open3(maps[n], map_name, open_flags, dict_flags) :
766 for (n = 0; n < map_count; n++) {
769 msg_fatal(
"table %s:%s: delete error: %m",
770 dicts[n]->type, dicts[n]->name);
777 for (n = 0; n < map_count; n++)
788 static int postmap_delete(
const char *map_type,
const char *map_name,
789 const char *key,
int dict_flags)
796 open_flags = O_RDWR | O_CREAT;
799 dict =
dict_open3(map_type, map_name, open_flags, dict_flags);
804 return (status == 0);
809 static void postmap_seq(
const char *map_type,
const char *map_name,
818 msg_fatal(
"can't sequence maps via the proxy service");
819 dict =
dict_open3(map_type, map_name, O_RDONLY, dict_flags);
821 if (
dict_seq(dict, func, &key, &value) != 0)
824 msg_warn(
"table %s:%s: empty lookup key value is not allowed",
826 }
else if (*value == 0) {
827 msg_warn(
"table %s:%s: key %s: empty string result is not allowed",
828 map_type, map_name, key);
829 msg_warn(
"table %s:%s should return NO RESULT in case of NOT FOUND",
844 msg_fatal(
"usage: %s [-NfinoprsuUvw] [-c config_dir] [-d key] [-q key] [map_type:]file...",
850 int main(
int argc,
char **argv)
858 int open_flags = O_RDWR | O_CREAT | O_TRUNC;
883 for (fd = 0; fd < 3; fd++)
884 if (
fstat(fd, &st) == -1
885 && (close(fd), open(
"/dev/null", O_RDWR, 0)) != fd)
899 if ((slash = strrchr(argv[0],
'/')) != 0 && slash[1])
912 while ((ch =
GETOPT(argc, argv,
"Nbc:d:fhimnopq:rsuUvw")) > 0) {
929 if (sequence || query || delkey)
930 msg_fatal(
"specify only one of -s -q or -d");
940 open_flags &= ~O_TRUNC;
950 postmap_flags &= ~POSTMAP_FLAG_AS_OWNER;
953 postmap_flags &= ~POSTMAP_FLAG_SAVE_PERM;
956 if (sequence || query || delkey)
957 msg_fatal(
"specify only one of -s -q or -d");
966 msg_fatal(
"specify only one of -s or -q or -d");
992 if ((query == 0 || strcmp(query,
"-") != 0)
994 msg_fatal(
"specify -b -h or -m only with \"-q -\"");
995 if ((postmap_flags & POSTMAP_FLAG_ANY_KEY) != 0
996 && (postmap_flags & POSTMAP_FLAG_ANY_KEY)
997 == (postmap_flags & POSTMAP_FLAG_MIME_KEY))
998 msg_warn(
"ignoring -m option without -b or -h");
999 if ((postmap_flags & (POSTMAP_FLAG_ANY_KEY & ~POSTMAP_FLAG_MIME_KEY))
1008 if (optind + 1 > argc)
1010 if (strcmp(delkey,
"-") == 0)
1011 exit(postmap_deletes(
VSTREAM_IN, argv + optind, argc - optind,
1014 while (optind < argc) {
1015 if ((path_name =
split_at(argv[optind],
':')) != 0) {
1016 found |= postmap_delete(argv[optind], path_name, delkey,
1019 found |= postmap_delete(
var_db_type, argv[optind], delkey,
1024 exit(found ? 0 : 1);
1026 if (optind + 1 > argc)
1028 if (strcmp(query,
"-") == 0)
1029 exit(postmap_queries(
VSTREAM_IN, argv + optind, argc - optind,
1031 while (optind < argc) {
1032 if ((path_name =
split_at(argv[optind],
':')) != 0) {
1033 found = postmap_query(argv[optind], path_name, query,
1036 found = postmap_query(
var_db_type, argv[optind], query,
1044 }
else if (sequence) {
1045 while (optind < argc) {
1046 if ((path_name =
split_at(argv[optind],
':')) != 0) {
1047 postmap_seq(argv[optind], path_name,
1057 if (optind + 1 > argc)
1059 while (optind < argc) {
1060 if ((path_name =
split_at(argv[optind],
':')) != 0) {
1061 postmap(argv[optind], path_name, postmap_flags,
1062 open_flags, dict_flags);
1065 open_flags, dict_flags);
#define DICT_FLAG_DUP_IGNORE
const char * mail_task(const char *argv0)
char * var_import_environ
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
#define POSTMAP_FLAG_MIME_KEY
MIME_STATE * mime_state_alloc(int flags, MIME_STATE_HEAD_OUT head_out, MIME_STATE_ANY_END head_end, MIME_STATE_BODY_OUT body_out, MIME_STATE_ANY_END body_end, MIME_STATE_ERR_PRINT err_print, void *context)
ARGV * argv_free(ARGV *argvp)
#define DICT_SEQ_FUN_FIRST
#define VAR_IMPORT_ENVIRON
NORETURN msg_panic(const char *fmt,...)
#define DICT_SEQ_FUN_NEXT
#define POSTMAP_FLAG_ANY_KEY
int valid_utf8_string(const char *, ssize_t)
#define DICT_FLAG_UTF8_REQUEST
#define POSTMAP_FLAG_HB_KEY
#define DICT_FLAG_FOLD_FIX
#define MIME_OPT_DISABLE_MIME
#define POSTMAP_FLAG_FULL_KEY
#define POSTMAP_FLAG_HEADER_KEY
void mail_conf_read(void)
VSTREAM * vstream_fopen(const char *path, int flags, mode_t mode)
DICT * dict_open3(const char *, const char *, int, int)
void(* MIME_STATE_BODY_OUT)(void *, int, const char *, ssize_t, off_t)
int mime_state_update(MIME_STATE *state, int rec_type, const char *text, ssize_t len)
ARGV * mail_parm_split(const char *name, const char *value)
#define dict_get(dp, key)
#define DICT_FLAG_DUP_REPLACE
MIME_STATE * mime_state_free(MIME_STATE *state)
int vstream_fclose(VSTREAM *stream)
void mkmap_close(MKMAP *)
#define DICT_FLAG_TRY1NULL
void(* MIME_STATE_ANY_END)(void *)
#define dict_seq(dp, f, key, val)
VSTREAM * vstream_printf(const char *fmt,...)
void(* MIME_STATE_HEAD_OUT)(void *, int, const HEADER_OPTS *, VSTRING *, off_t)
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
MKMAP * mkmap_open(const char *, const char *, int, int)
void mail_dict_init(void)
#define MAIL_VERSION_STAMP_ALLOCATE
const MIME_STATE_DETAIL * mime_state_detail(int error_code)
#define DICT_FLAG_DUP_WARN
char * trimblanks(char *, ssize_t)
NORETURN msg_fatal(const char *fmt,...)
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
#define MAIL_VERSION_CHECK
VSTRING * readllines(VSTRING *buf, VSTREAM *fp, int *lineno, int *first_line)
int vstream_fflush(VSTREAM *stream)
void update_env(char **preserve_list)
void set_eugid(uid_t euid, gid_t egid)
#define GETOPT(argc, argv, str)
void msg_syslog_init(const char *name, int logopt, int facility)
MAIL_VERSION_STAMP_DECLARE
#define dict_setjmp(dict)
#define POSTMAP_FLAG_SAVE_PERM
void(* MIME_STATE_ERR_PRINT)(void *, int, const char *, ssize_t)
VSTRING * vstring_free(VSTRING *vp)
char * split_at(char *string, int delimiter)
#define vstream_fileno(vp)
#define mkmap_append(map, key, val)
void msg_vstream_init(const char *name, VSTREAM *vp)
#define CA_VSTREAM_CTL_END
#define CA_VSTREAM_CTL_PATH(v)
#define POSTMAP_FLAG_BODY_KEY
int main(int argc, char **argv)
void vstream_control(VSTREAM *stream, int name,...)
#define dict_del(dp, key)
#define DICT_FLAG_BULK_UPDATE
#define DICT_FLAG_TRY0NULL
#define DICT_FLAG_UTF8_MASK
#define POSTMAP_FLAG_AS_OWNER
#define DICT_FLAG_UTF8_ACTIVE
void * mymalloc(ssize_t len)