mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-29 13:18:12 +00:00
postfix-3.6-20201101
This commit is contained in:
parent
5671f91c4d
commit
225d645d4e
@ -25251,4 +25251,10 @@ Apologies for any names omitted.
|
||||
|
||||
Cleanup: changed the postdrop numerical UID prefix from "#"
|
||||
to "uid:", and tweaked some local_login_sender_maps
|
||||
documentatin. Files: proto/postconf.proto, postdrop/postdrop.c.
|
||||
documentation. Files: proto/postconf.proto, postdrop/postdrop.c.
|
||||
|
||||
20201031
|
||||
|
||||
Cleanup: don't split a space-comma separated address list
|
||||
on on space or comma inside a quoted string. Files:
|
||||
util/mystrtok.c, util/mystetok.ref, global/login_sender_match.c.
|
||||
|
@ -53,7 +53,7 @@ r* The lookup table(s) with (login name, sender patterns) entries.
|
||||
/* .IP ext_delimiters
|
||||
/* The set of address extension delimiters.
|
||||
/* .IP null_sender
|
||||
/* If a sender pattern equals the null_sender pattern, then
|
||||
/* If a sender pattern equals the null_sender pattern, then
|
||||
/* the empty address is matched.
|
||||
/* .IP wildcard
|
||||
/* Null pointer, or non-empty string with a wildcard pattern.
|
||||
@ -196,16 +196,16 @@ int login_sender_match(LOGIN_SENDER_MATCH *lsm, const char *login_name,
|
||||
/* flags= */ 0)) != 0) {
|
||||
|
||||
/*
|
||||
* Match the sender. TODO: don't break a sender pattern on a
|
||||
* comma/space inside a quoted localpart.
|
||||
* Match the sender. Don't break a sender pattern between double
|
||||
* quotes.
|
||||
*/
|
||||
cp = saved_sender_patterns = mystrdup(sender_patterns);
|
||||
while (found_or_error == LSM_STAT_NOTFOUND
|
||||
&& (sender_pattern = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
|
||||
&& (sender_pattern = mystrtokdq(&cp, CHARS_COMMA_SP)) != 0) {
|
||||
/* Special pattern: @domain. */
|
||||
if (*sender_pattern == '@') {
|
||||
if ((at_sender_domain = strrchr(sender_addr, '@')) != 0
|
||||
&& strcasecmp_utf8(sender_pattern, at_sender_domain) == 0)
|
||||
&& strcasecmp_utf8(sender_pattern, at_sender_domain) == 0)
|
||||
found_or_error = LSM_STAT_FOUND;
|
||||
}
|
||||
/* Special pattern: wildcard. */
|
||||
@ -218,13 +218,15 @@ int login_sender_match(LOGIN_SENDER_MATCH *lsm, const char *login_name,
|
||||
found_or_error = LSM_STAT_FOUND;
|
||||
}
|
||||
/* Literal pattern: match the stripped and externalized sender. */
|
||||
if (ext_stripped_sender == 0)
|
||||
ext_stripped_sender =
|
||||
STR(strip_externalize_addr(lsm->ext_stripped_sender,
|
||||
sender_addr,
|
||||
lsm->ext_delimiters));
|
||||
if (strcasecmp_utf8(sender_pattern, ext_stripped_sender) == 0)
|
||||
found_or_error = LSM_STAT_FOUND;
|
||||
else {
|
||||
if (ext_stripped_sender == 0)
|
||||
ext_stripped_sender =
|
||||
STR(strip_externalize_addr(lsm->ext_stripped_sender,
|
||||
sender_addr,
|
||||
lsm->ext_delimiters));
|
||||
if (strcasecmp_utf8(sender_pattern, ext_stripped_sender) == 0)
|
||||
found_or_error = LSM_STAT_FOUND;
|
||||
}
|
||||
}
|
||||
myfree(saved_sender_patterns);
|
||||
} else {
|
||||
@ -304,6 +306,18 @@ int main(int argc, char **argv)
|
||||
"inline:{root=*, {uid:12345 = foo,foo@example.com}, bar=<>}",
|
||||
"+-", "<>", "*", "uid:12345", "foo", LSM_STAT_FOUND
|
||||
},
|
||||
{"unknown \"other last\"",
|
||||
"inline:{root=*, {foo = \"first last\",\"first last\"@example.com}, bar=<>}",
|
||||
"+-", "<>", "*", "foo", "other last", LSM_STAT_NOTFOUND
|
||||
},
|
||||
{"bare \"first last\"",
|
||||
"inline:{root=*, {foo = \"first last\",\"first last\"@example.com}, bar=<>}",
|
||||
"+-", "<>", "*", "foo", "first last", LSM_STAT_FOUND
|
||||
},
|
||||
{"\"first last\"@domain",
|
||||
"inline:{root=*, {foo = \"first last\",\"first last\"@example.com}, bar=<>}",
|
||||
"+-", "<>", "*", "foo", "first last@example.com", LSM_STAT_FOUND
|
||||
},
|
||||
};
|
||||
struct testcase *tp;
|
||||
int act_return;
|
||||
|
@ -27,3 +27,9 @@ unknown: RUN test case 12 unknown uid:number
|
||||
unknown: PASS test 12
|
||||
unknown: RUN test case 13 known uid:number
|
||||
unknown: PASS test 13
|
||||
unknown: RUN test case 14 unknown "other last"
|
||||
unknown: PASS test 14
|
||||
unknown: RUN test case 15 bare "first last"
|
||||
unknown: PASS test 15
|
||||
unknown: RUN test case 16 "first last"@domain
|
||||
unknown: PASS test 16
|
||||
|
@ -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 "20201026"
|
||||
#define MAIL_RELEASE_DATE "20201101"
|
||||
#define MAIL_VERSION_NUMBER "3.6"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -261,8 +261,10 @@ static int check_login_sender_acl(uid_t uid, VSTRING *sender_buf,
|
||||
/*
|
||||
* Optimization.
|
||||
*/
|
||||
#ifndef SNAPSHOT
|
||||
if (strcmp(var_local_login_snd_maps, DEF_LOCAL_LOGIN_SND_MAPS) == 0)
|
||||
return (CLEANUP_STAT_OK);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the username.
|
||||
|
@ -559,7 +559,8 @@ tests: all valid_hostname_test mac_expand_test dict_test unescape_test \
|
||||
miss_endif_pcre_test miss_endif_regexp_test split_qnameval_test \
|
||||
vstring_test vstream_test dict_pcre_file_test dict_regexp_file_test \
|
||||
dict_cidr_file_test dict_static_file_test dict_random_test \
|
||||
dict_random_file_test dict_inline_file_test byte_mask_tests
|
||||
dict_random_file_test dict_inline_file_test byte_mask_tests \
|
||||
mystrtok_test
|
||||
|
||||
root_tests:
|
||||
|
||||
@ -957,6 +958,11 @@ vstream_test: vstream vstream_test.in vstream_test.ref
|
||||
diff vstream_test.ref vstream_test.tmp
|
||||
rm -f vstream_test.tmp
|
||||
|
||||
mystrtok_test: mystrtok mystrtok.ref
|
||||
$(SHLIB_ENV) ${VALGRIND} ./mystrtok >mystrtok.tmp 2>&1
|
||||
diff mystrtok.ref mystrtok.tmp
|
||||
rm -f mystrtok.tmp
|
||||
|
||||
depend: $(MAKES)
|
||||
(sed '1,/^# do not edit/!d' Makefile.in; \
|
||||
set -e; for i in [a-z][a-z0-9]*.c; do \
|
||||
|
@ -14,6 +14,10 @@
|
||||
/* char **bufp;
|
||||
/* const char *delimiters;
|
||||
/* const char *parens;
|
||||
/*
|
||||
/* char *mystrtokdq(bufp, delimiters)
|
||||
/* char **bufp;
|
||||
/* const char *delimiters;
|
||||
/* DESCRIPTION
|
||||
/* mystrtok() splits a buffer on the specified \fIdelimiters\fR.
|
||||
/* Tokens are delimited by runs of delimiters, so this routine
|
||||
@ -24,6 +28,11 @@
|
||||
/* opening and closing parenthesis (one of each). The set of
|
||||
/* \fIparens\fR must be distinct from the set of \fIdelimiters\fR.
|
||||
/*
|
||||
/* mystrtokdq() is like mystrtok() but will not split text
|
||||
/* between double quotes. The backslash character may be used
|
||||
/* to escape characters. The double quote and backslash
|
||||
/* character must not appear in the set of \fIdelimiters\fR.
|
||||
/*
|
||||
/* The \fIbufp\fR argument specifies the start of the search; it
|
||||
/* is updated with each call. The input is destroyed.
|
||||
/*
|
||||
@ -80,7 +89,7 @@ char *mystrtok(char **src, const char *sep)
|
||||
char *mystrtokq(char **src, const char *sep, const char *parens)
|
||||
{
|
||||
char *start = *src;
|
||||
static char *cp;
|
||||
static char *cp;
|
||||
int ch;
|
||||
int level;
|
||||
|
||||
@ -99,7 +108,7 @@ char *mystrtokq(char **src, const char *sep, const char *parens)
|
||||
for (level = 0, cp = start; (ch = *(unsigned char *) cp) != 0; cp++) {
|
||||
if (ch == parens[0]) {
|
||||
level++;
|
||||
} else if (level > 0 && ch == parens[1]) {
|
||||
} else if (level > 0 && ch == parens[1]) {
|
||||
level--;
|
||||
} else if (level == 0 && strchr(sep, ch) != 0) {
|
||||
*cp++ = 0;
|
||||
@ -110,34 +119,135 @@ char *mystrtokq(char **src, const char *sep, const char *parens)
|
||||
return (start);
|
||||
}
|
||||
|
||||
/* mystrtokdq - safe tokenizer, double quote and backslash support */
|
||||
|
||||
char *mystrtokdq(char **src, const char *sep)
|
||||
{
|
||||
char *cp = *src;
|
||||
char *start;
|
||||
|
||||
/*
|
||||
* Skip leading delimiters.
|
||||
*/
|
||||
cp += strspn(cp, sep);
|
||||
|
||||
/*
|
||||
* Skip to next unquoted space or comma.
|
||||
*/
|
||||
if (*cp == 0) {
|
||||
start = 0;
|
||||
} else {
|
||||
int in_quotes;
|
||||
|
||||
for (in_quotes = 0, start = cp; *cp; cp++) {
|
||||
if (*cp == '\\') {
|
||||
if (*++cp == 0)
|
||||
break;
|
||||
} else if (*cp == '"') {
|
||||
in_quotes = !in_quotes;
|
||||
} else if (!in_quotes && strchr(sep, *(unsigned char *) cp) != 0) {
|
||||
*cp++ = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*src = cp;
|
||||
return (start);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
* Test program: read lines from stdin, split on whitespace.
|
||||
* Test program.
|
||||
*/
|
||||
#include "vstring.h"
|
||||
#include "vstream.h"
|
||||
#include "vstring_vstream.h"
|
||||
#include "msg.h"
|
||||
#include "mymalloc.h"
|
||||
|
||||
/*
|
||||
* The following needs to be large enough to include a null terminator in
|
||||
* every testcase.expected field.
|
||||
*/
|
||||
#define EXPECT_SIZE 5
|
||||
|
||||
struct testcase {
|
||||
const char *action;
|
||||
const char *input;
|
||||
const char *expected[EXPECT_SIZE];
|
||||
};
|
||||
static const struct testcase testcases[] = {
|
||||
{"mystrtok", ""},
|
||||
{"mystrtok", " foo ", {"foo"}},
|
||||
{"mystrtok", " foo bar ", {"foo", "bar"}},
|
||||
{"mystrtokq", ""},
|
||||
{"mystrtokq", "foo bar", {"foo", "bar"}},
|
||||
{"mystrtokq", "{ bar } ", {"{ bar }"}},
|
||||
{"mystrtokq", "foo { bar } baz", {"foo", "{ bar }", "baz"}},
|
||||
{"mystrtokq", "foo{ bar } baz", {"foo{ bar }", "baz"}},
|
||||
{"mystrtokq", "foo { bar }baz", {"foo", "{ bar }baz"}},
|
||||
{"mystrtokdq", ""},
|
||||
{"mystrtokdq", " foo ", {"foo"}},
|
||||
{"mystrtokdq", " foo bar ", {"foo", "bar"}},
|
||||
{"mystrtokdq", " foo\\ bar ", {"foo\\ bar"}},
|
||||
{"mystrtokdq", " foo \\\" bar", {"foo", "\\\"", "bar"}},
|
||||
{"mystrtokdq", " foo \" bar baz\" ", {"foo", "\" bar baz\""}},
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
VSTRING *vp = vstring_alloc(100);
|
||||
char *start;
|
||||
char *str;
|
||||
const struct testcase *tp;
|
||||
char *actual;
|
||||
int pass;
|
||||
int fail;
|
||||
int match;
|
||||
int n;
|
||||
|
||||
while (vstring_fgets(vp, VSTREAM_IN) && VSTRING_LEN(vp) > 0) {
|
||||
start = vstring_str(vp);
|
||||
if (strchr(start, CHARS_BRACE[0]) == 0) {
|
||||
while ((str = mystrtok(&start, CHARS_SPACE)) != 0)
|
||||
vstream_printf(">%s<\n", str);
|
||||
} else {
|
||||
while ((str = mystrtokq(&start, CHARS_SPACE, CHARS_BRACE)) != 0)
|
||||
vstream_printf(">%s<\n", str);
|
||||
#define NUM_TESTS sizeof(testcases)/sizeof(testcases[0])
|
||||
#define STR_OR_NULL(s) ((s) ? (s) : "null")
|
||||
|
||||
for (pass = fail = 0, tp = testcases; tp < testcases + NUM_TESTS; tp++) {
|
||||
char *saved_input = mystrdup(tp->input);
|
||||
char *cp = saved_input;
|
||||
|
||||
msg_info("RUN test case %ld %s >%s<",
|
||||
(long) (tp - testcases), tp->action, tp->input);
|
||||
#if 0
|
||||
msg_info("action=%s", tp->action);
|
||||
msg_info("input=%s", tp->input);
|
||||
for (n = 0; tp->expected[n]; tp++)
|
||||
msg_info("expected[%d]=%s", n, tp->expected[n]);
|
||||
#endif
|
||||
|
||||
for (n = 0; n < EXPECT_SIZE; n++) {
|
||||
if (strcmp(tp->action, "mystrtok") == 0) {
|
||||
actual = mystrtok(&cp, CHARS_SPACE);
|
||||
} else if (strcmp(tp->action, "mystrtokq") == 0) {
|
||||
actual = mystrtokq(&cp, CHARS_SPACE, CHARS_BRACE);
|
||||
} else if (strcmp(tp->action, "mystrtokdq") == 0) {
|
||||
actual = mystrtokdq(&cp, CHARS_SPACE);
|
||||
} else {
|
||||
msg_panic("invalid command: %s", tp->action);
|
||||
}
|
||||
if ((match = (actual && tp->expected[n]) ?
|
||||
(strcmp(actual, tp->expected[n]) == 0) :
|
||||
(actual == tp->expected[n])) != 0) {
|
||||
if (actual == 0) {
|
||||
msg_info("PASS test %ld", (long) (tp - testcases));
|
||||
pass++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
msg_warn("expected: >%s<, got: >%s<",
|
||||
STR_OR_NULL(tp->expected[n]), STR_OR_NULL(actual));
|
||||
msg_info("FAIL test %ld", (long) (tp - testcases));
|
||||
fail++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
if (n >= EXPECT_SIZE)
|
||||
msg_panic("need to increase EXPECT_SIZE");
|
||||
myfree(saved_input);
|
||||
}
|
||||
vstring_free(vp);
|
||||
return (0);
|
||||
return (fail > 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
30
postfix/src/util/mystrtok.ref
Normal file
30
postfix/src/util/mystrtok.ref
Normal file
@ -0,0 +1,30 @@
|
||||
unknown: RUN test case 0 mystrtok ><
|
||||
unknown: PASS test 0
|
||||
unknown: RUN test case 1 mystrtok > foo <
|
||||
unknown: PASS test 1
|
||||
unknown: RUN test case 2 mystrtok > foo bar <
|
||||
unknown: PASS test 2
|
||||
unknown: RUN test case 3 mystrtokq ><
|
||||
unknown: PASS test 3
|
||||
unknown: RUN test case 4 mystrtokq >foo bar<
|
||||
unknown: PASS test 4
|
||||
unknown: RUN test case 5 mystrtokq >{ bar } <
|
||||
unknown: PASS test 5
|
||||
unknown: RUN test case 6 mystrtokq >foo { bar } baz<
|
||||
unknown: PASS test 6
|
||||
unknown: RUN test case 7 mystrtokq >foo{ bar } baz<
|
||||
unknown: PASS test 7
|
||||
unknown: RUN test case 8 mystrtokq >foo { bar }baz<
|
||||
unknown: PASS test 8
|
||||
unknown: RUN test case 9 mystrtokdq ><
|
||||
unknown: PASS test 9
|
||||
unknown: RUN test case 10 mystrtokdq > foo <
|
||||
unknown: PASS test 10
|
||||
unknown: RUN test case 11 mystrtokdq > foo bar <
|
||||
unknown: PASS test 11
|
||||
unknown: RUN test case 12 mystrtokdq > foo\ bar <
|
||||
unknown: PASS test 12
|
||||
unknown: RUN test case 13 mystrtokdq > foo \" bar<
|
||||
unknown: PASS test 13
|
||||
unknown: RUN test case 14 mystrtokdq > foo " bar baz" <
|
||||
unknown: PASS test 14
|
@ -30,6 +30,7 @@ extern char *trimblanks(char *, ssize_t);
|
||||
extern char *concatenate(const char *,...);
|
||||
extern char *mystrtok(char **, const char *);
|
||||
extern char *mystrtokq(char **, const char *, const char *);
|
||||
extern char *mystrtokdq(char **, const char *);
|
||||
extern char *translit(char *, const char *, const char *);
|
||||
|
||||
#define printable(string, replacement) \
|
||||
|
Loading…
x
Reference in New Issue
Block a user