Merged the non-production REQUIRETLS branch.
-TODO
+20251115
- Decide whether or how to enable REQUIRETLS for non-SMTP
- inputs: qmqpd.c ot pickup (sendmail). The smtputf8 auto-detect
- strategy is not applicable because REQUIRETLS trumps
- "TLS-Required: no". It should be easy for sendmail submissions
- to choose whether TLS shall be required or optional.
+ Code cleanup: migrate "#ifdef TEST" code from foo.c to
+ foo_test.c. Files: util/Makefile.in, global/login_sender_match.c,
+ global/login_sender_match_test.c, util/hash_fnv.c,
+ util/hash_fnv_test.c. There are about 143 more of these.
+
+ Cleanup: fix malformed postconf(5) nroff source. The HTML
+ to MAN converter did not escape an initial ' in text after
+ a <dd> tag. This broke some smtp_log_tls_feature_status
+ examples. File: mantools/postconf2man.
+
+20250116
+
+ Cleanup: missing #include <stdlib.h>, missing #ifdef USE_TLS.
+ postconf/postconf_unused.c, posttls-finger/posttls-finger.c,
+ smtp/lmtp_params.c, smtp/smtp.h, smtp/smtp_params.c,
+ smtp/smtp_proto.c, smtp/smtp_state.c.
+
+ Documentation: added whitespace to make smtp_requiretls_policy
+ examples easier to read. Files: proto/REQUIRETLS_README.html,
+ proto/postconf.proto.
+
+ Testing: add 'update' to global library test targets. File:
+ global/Makefile.in.
4 lmtp_requiretls_policy = opportunistic
5 smtp_requiretls_policy =
6 inline:{
- 7 {${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 9 {localhost = opportunistic} }
+ 7 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 9 { localhost = opportunistic } }
10 cidr:{
- 11 {0.0.0.0/0 opportunistic}
- 12 {::/0 opportunistic} }
+ 11 { 0.0.0.0/0 opportunistic }
+ 12 { ::/0 opportunistic } }
13 ...to be completed in section "Communication with external
servers"...
4 requiretls_esmtp_header = yes
5 smtp_requiretls_policy =
6 inline:{
- 7 {${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 9 {localhost = opportunistic} }
+ 7 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 9 { localhost = opportunistic } }
10 cidr:{
- 11 {0.0.0.0/0 opportunistic}
- 12 {::/0 opportunistic} }
+ 11 { 0.0.0.0/0 opportunistic }
+ 12 { ::/0 opportunistic } }
13 enforce
* New at line 13: The 'enforce' policy for external destinations is
4 requiretls_esmtp_header = yes
5 smtp_requiretls_policy =
6 inline:{
- 7 {${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 9 {localhost = opportunistic} }
+ 7 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 9 { localhost = opportunistic } }
10 cidr:{
- 11 {0.0.0.0/0 opportunistic}
- 12 {::/0 opportunistic} }
+ 11 { 0.0.0.0/0 opportunistic }
+ 12 { ::/0 opportunistic } }
13 opportunistic+starttls
* New at line 13: the 'opportunistic+starttls' policy relaxes the requirement
4 <a href="postconf.5.html#lmtp_requiretls_policy">lmtp_requiretls_policy</a> = opportunistic
5 <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> =
6 <a href="DATABASE_README.html#types">inline</a>:{
- 7 {${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 8 {.${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 9 {localhost = opportunistic} }
+ 7 { ${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 8 { .${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 9 { localhost = opportunistic } }
10 <a href="cidr_table.5.html">cidr</a>:{
-11 {0.0.0.0/0 opportunistic}
-12 {::/0 opportunistic} }
+11 { 0.0.0.0/0 opportunistic }
+12 { ::/0 opportunistic } }
13 ...to be completed in section "<a href="#external">Communication with external servers</a>"...
</pre>
</blockquote>
4 <a href="postconf.5.html#requiretls_esmtp_header">requiretls_esmtp_header</a> = yes
5 <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> =
6 <a href="DATABASE_README.html#types">inline</a>:{
- 7 {${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 8 {.${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 9 {localhost = opportunistic} }
+ 7 { ${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 8 { .${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 9 { localhost = opportunistic } }
10 <a href="cidr_table.5.html">cidr</a>:{
-11 {0.0.0.0/0 opportunistic}
-12 {::/0 opportunistic} }
+11 { 0.0.0.0/0 opportunistic }
+12 { ::/0 opportunistic } }
13 enforce
</pre>
</blockquote>
4 <a href="postconf.5.html#requiretls_esmtp_header">requiretls_esmtp_header</a> = yes
5 <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> =
6 <a href="DATABASE_README.html#types">inline</a>:{
- 7 {${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 8 {.${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 9 {localhost = opportunistic} }
+ 7 { ${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 8 { .${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 9 { localhost = opportunistic } }
10 <a href="cidr_table.5.html">cidr</a>:{
-11 {0.0.0.0/0 opportunistic}
-12 {::/0 opportunistic} }
+11 { 0.0.0.0/0 opportunistic }
+12 { ::/0 opportunistic } }
13 opportunistic+starttls
</pre>
</blockquote>
contains the default setting: </p>
<pre>
<a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> = <a href="DATABASE_README.html#types">inline</a>:{
- {${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic },
- {.${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic },
- ... }
+ { ${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic },
+ { .${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic },
+ ...
</pre>
<li> <p> Example 1: when <a href="postconf.5.html#mydomain">mydomain</a> contains only ASCII characters,
<pre>
# postconf -o '<a href="postconf.5.html#mydomain">mydomain</a>=foo.example' -x <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a>
<a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> = <a href="DATABASE_README.html#types">inline</a>:{
- {foo.example = opportunistic},
- {.foo.example = opportunistic},
- ... }
+ { foo.example = opportunistic },
+ { .foo.example = opportunistic },
+ ...
</pre>
<li> <p> Example 2: when <a href="postconf.5.html#mydomain">mydomain</a> contains non-ASCII characters,
<pre>
# postconf -o '<a href="postconf.5.html#mydomain">mydomain</a>=π.example' -x <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a>
<a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> = <a href="DATABASE_README.html#types">inline</a>:{
- {xn--1xa.example = opportunistic},
- {.xn--1xa.example = opportunistic},
- ... }
+ { xn--1xa.example = opportunistic },
+ { .xn--1xa.example = opportunistic },
+ ...
</pre>
</ul>
3 <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = ...dane/sts plugin...
4 <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> =
5 <a href="DATABASE_README.html#types">inline</a>:{
- 6 {${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 7 {.${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 8 {localhost = opportunistic} }
+ 6 { ${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 7 { .${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 8 { localhost = opportunistic } }
9 <a href="cidr_table.5.html">cidr</a>:{
-10 {0.0.0.0/0 opportunistic},
-11 {::/0 opportunistic} },
+10 { 0.0.0.0/0 opportunistic },
+11 { ::/0 opportunistic } },
12 enforce
</pre>
3 <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = ...dane/sts plugin...
4 <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> =
5 <a href="DATABASE_README.html#types">inline</a>:{
- 6 {${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 7 {.${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- 8 {localhost = opportunistic} }
+ 6 { ${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 7 { .${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ 8 { localhost = opportunistic } }
9 <a href="cidr_table.5.html">cidr</a>:{
-10 {0.0.0.0/0 opportunistic},
-11 {::/0 opportunistic} },
+10 { 0.0.0.0/0 opportunistic },
+11 { ::/0 opportunistic } },
12 opportunistic+starttls
</pre>
<a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = ...dane/sts plugin...
<a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> =
<a href="DATABASE_README.html#types">inline</a>:{
- {${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- {.${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic}
- {localhost = opportunistic} }
+ { ${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ { .${<a href="postconf.5.html#domain_to_ascii">domain_to_ascii</a>{$<a href="postconf.5.html#mydomain">mydomain</a>}} = opportunistic }
+ { localhost = opportunistic } }
<a href="cidr_table.5.html">cidr</a>:{
- {0.0.0.0/0 opportunistic},
- {::/0 opportunistic} },
+ { 0.0.0.0/0 opportunistic },
+ { ::/0 opportunistic } },
<a href="DATABASE_README.html#types">hash</a>:/etc/postfix/requiretls-per-site
opportunistic+starttls
</pre>
.nf
.na
smtp_requiretls_policy = inline:{
- {${domain_to_ascii{$mydomain}} = opportunistic },
- {.${domain_to_ascii{$mydomain}} = opportunistic },
- ... }
+ { ${domain_to_ascii{$mydomain}} = opportunistic },
+ { .${domain_to_ascii{$mydomain}} = opportunistic },
+ ...
.fi
.ad
.IP \(bu
.na
# postconf \-o 'mydomain=foo.example' \-x smtp_requiretls_policy
smtp_requiretls_policy = inline:{
- {foo.example = opportunistic},
- {.foo.example = opportunistic},
- ... }
+ { foo.example = opportunistic },
+ { .foo.example = opportunistic },
+ ...
.fi
.ad
.IP \(bu
.na
# postconf \-o 'mydomain=π.example' \-x smtp_requiretls_policy
smtp_requiretls_policy = inline:{
- {xn\-\-1xa.example = opportunistic},
- {.xn\-\-1xa.example = opportunistic},
- ... }
+ { xn\-\-1xa.example = opportunistic },
+ { .xn\-\-1xa.example = opportunistic },
+ ...
.fi
.ad
.br
Examples for REQUIRETLS policies (set with smtp_requiretls_policy),
where "\fIxxx\fR" is a TLS security level:
.IP "tls=xxx/requiretls"
-'Enforce' policy compliant.
+\&ddEnforce' policy compliant.
After a successful TLS handshake that required a certificate match,
the remote server announced REQUIRETLS support, and the client sent
REQUIRETLS.
.IP "tls=xxx/!requiretls:nocertmatch"
-'Enforce' policy
+\&ddEnforce' policy
violation. The connection was not used because the remote server
certificate did not match as required by the TLS security policy,
or no connection was made because the TLS security policy disabled
server certificate matching.
.br
.IP "tls=xxx/requiretls:nocertmatch"
-'Opportunistic+starttls'
+\&ddOpportunistic+starttls'
or 'opportunistic' policy compliant. After a successful TLS handshake
that did not require a server certificate match, the remote server
announced REQUIRETLS support, and the client sent REQUIRETLS.
.br
.IP "tls=xxx/!requiretls:nostarttls"
-'Enforce' or
+\&ddEnforce' or
\&'opportunistic+starttls' policy violation. The connection was not
used because the remote server did not support STARTTLS.
.br
.IP "tls=xxx/!requiretls:noencryption"
-'Enforce' or
+\&ddEnforce' or
\&'opportunistic+starttls' policy violation. No connection was made
used because the TLS security policy disabled encryption.
.br
.IP "tls=xxx/!requiretls:none"
-'Enforce' policy violation.
+\&ddEnforce' policy violation.
After a successful TLS handshake, the connection was not used because
the remote server did not support REQUIRETLS.
.br
.IP "tls=xxx/requiretls:none"
-'Opportunistic+starttls'
+\&ddOpportunistic+starttls'
policy compliant. After a successful TLS handshake, the remote
server did not announce REQUIRETLS support, and the connection was
used without sending REQUIRETLS.
.br
.IP "tls=xxx/requiretls:none"
-'Opportunistic' policy
+\&ddOpportunistic' policy
compliant. The remote server did not announce support for STARTTLS
or REQUIRETLS, and the connection was used without sending REQUIRETLS.
.br
3 smtp_tls_policy_maps = ...dane/sts plugin...
4 smtp_requiretls_policy =
5 inline:{
- 6 {${domain_to_ascii{$mydomain}} = opportunistic}
- 7 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {localhost = opportunistic} }
+ 6 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 7 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { localhost = opportunistic } }
9 cidr:{
-10 {0.0.0.0/0 opportunistic},
-11 {::/0 opportunistic} },
+10 { 0.0.0.0/0 opportunistic },
+11 { ::/0 opportunistic } },
12 enforce
.fi
.ad
3 smtp_tls_policy_maps = ...dane/sts plugin...
4 smtp_requiretls_policy =
5 inline:{
- 6 {${domain_to_ascii{$mydomain}} = opportunistic}
- 7 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {localhost = opportunistic} }
+ 6 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 7 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { localhost = opportunistic } }
9 cidr:{
-10 {0.0.0.0/0 opportunistic},
-11 {::/0 opportunistic} },
+10 { 0.0.0.0/0 opportunistic },
+11 { ::/0 opportunistic } },
12 opportunistic+starttls
.fi
.ad
smtp_tls_policy_maps = ...dane/sts plugin...
smtp_requiretls_policy =
inline:{
- {${domain_to_ascii{$mydomain}} = opportunistic}
- {.${domain_to_ascii{$mydomain}} = opportunistic}
- {localhost = opportunistic} }
+ { ${domain_to_ascii{$mydomain}} = opportunistic }
+ { .${domain_to_ascii{$mydomain}} = opportunistic }
+ { localhost = opportunistic } }
cidr:{
- {0.0.0.0/0 opportunistic},
- {::/0 opportunistic} },
+ { 0.0.0.0/0 opportunistic },
+ { ::/0 opportunistic } },
hash:/etc/postfix/requiretls\-per\-site
opportunistic+starttls
.sp
#$block =~ s/\n\./\n\\\&./g;
$block =~ s/\n\./\n\134\&./g;
$block =~ s/\n'/\n\134\&'/g;
+ $block =~ s/(<(p|dd|br)+>\s*)(['.])/$1\134\&$2/g;
if ($block =~ /<H2>/) {
$block =~ s/<H2><a[^>]+>([^<]+)<\/a><\/H2>/\n.SH \1\n/g;
$block =~ tr/a-z/A-Z/;
4 lmtp_requiretls_policy = opportunistic
5 smtp_requiretls_policy =
6 inline:{
- 7 {${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 9 {localhost = opportunistic} }
+ 7 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 9 { localhost = opportunistic } }
10 cidr:{
-11 {0.0.0.0/0 opportunistic}
-12 {::/0 opportunistic} }
+11 { 0.0.0.0/0 opportunistic }
+12 { ::/0 opportunistic } }
13 ...to be completed in section "<a href="#external">Communication with external servers</a>"...
</pre>
</blockquote>
4 requiretls_esmtp_header = yes
5 smtp_requiretls_policy =
6 inline:{
- 7 {${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 9 {localhost = opportunistic} }
+ 7 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 9 { localhost = opportunistic } }
10 cidr:{
-11 {0.0.0.0/0 opportunistic}
-12 {::/0 opportunistic} }
+11 { 0.0.0.0/0 opportunistic }
+12 { ::/0 opportunistic } }
13 enforce
</pre>
</blockquote>
4 requiretls_esmtp_header = yes
5 smtp_requiretls_policy =
6 inline:{
- 7 {${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 9 {localhost = opportunistic} }
+ 7 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 9 { localhost = opportunistic } }
10 cidr:{
-11 {0.0.0.0/0 opportunistic}
-12 {::/0 opportunistic} }
+11 { 0.0.0.0/0 opportunistic }
+12 { ::/0 opportunistic } }
13 opportunistic+starttls
</pre>
</blockquote>
3 smtp_tls_policy_maps = ...dane/sts plugin...
4 smtp_requiretls_policy =
5 inline:{
- 6 {${domain_to_ascii{$mydomain}} = opportunistic}
- 7 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {localhost = opportunistic} }
+ 6 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 7 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { localhost = opportunistic } }
9 cidr:{
-10 {0.0.0.0/0 opportunistic},
-11 {::/0 opportunistic} },
+10 { 0.0.0.0/0 opportunistic },
+11 { ::/0 opportunistic } },
12 enforce
</pre>
3 smtp_tls_policy_maps = ...dane/sts plugin...
4 smtp_requiretls_policy =
5 inline:{
- 6 {${domain_to_ascii{$mydomain}} = opportunistic}
- 7 {.${domain_to_ascii{$mydomain}} = opportunistic}
- 8 {localhost = opportunistic} }
+ 6 { ${domain_to_ascii{$mydomain}} = opportunistic }
+ 7 { .${domain_to_ascii{$mydomain}} = opportunistic }
+ 8 { localhost = opportunistic } }
9 cidr:{
-10 {0.0.0.0/0 opportunistic},
-11 {::/0 opportunistic} },
+10 { 0.0.0.0/0 opportunistic },
+11 { ::/0 opportunistic } },
12 opportunistic+starttls
</pre>
smtp_tls_policy_maps = ...dane/sts plugin...
smtp_requiretls_policy =
inline:{
- {${domain_to_ascii{$mydomain}} = opportunistic}
- {.${domain_to_ascii{$mydomain}} = opportunistic}
- {localhost = opportunistic} }
+ { ${domain_to_ascii{$mydomain}} = opportunistic }
+ { .${domain_to_ascii{$mydomain}} = opportunistic }
+ { localhost = opportunistic } }
cidr:{
- {0.0.0.0/0 opportunistic},
- {::/0 opportunistic} },
+ { 0.0.0.0/0 opportunistic },
+ { ::/0 opportunistic } },
hash:/etc/postfix/requiretls-per-site
opportunistic+starttls
</pre>
contains the default setting: </p>
<pre>
smtp_requiretls_policy = inline:{
- {${domain_to_ascii{$mydomain}} = opportunistic },
- {.${domain_to_ascii{$mydomain}} = opportunistic },
- ... }
+ { ${domain_to_ascii{$mydomain}} = opportunistic },
+ { .${domain_to_ascii{$mydomain}} = opportunistic },
+ ...
</pre>
<li> <p> Example 1: when mydomain contains only ASCII characters,
<pre>
# postconf -o 'mydomain=foo.example' -x smtp_requiretls_policy
smtp_requiretls_policy = inline:{
- {foo.example = opportunistic},
- {.foo.example = opportunistic},
- ... }
+ { foo.example = opportunistic },
+ { .foo.example = opportunistic },
+ ...
</pre>
<li> <p> Example 2: when mydomain contains non-ASCII characters,
<pre>
# postconf -o 'mydomain=π.example' -x smtp_requiretls_policy
smtp_requiretls_policy = inline:{
- {xn--1xa.example = opportunistic},
- {.xn--1xa.example = opportunistic},
- ... }
+ { xn--1xa.example = opportunistic },
+ { .xn--1xa.example = opportunistic },
+ ...
</pre>
</ul>
showq showq c Ditto for sendmail O smtputf8 yes no
smtpd smtpd c smtp smtp_connect c smtp smtp_proto c
util mac_expand ref proto postconf proto proto Makefile in
+ smtp lmtp_params c smtp smtp h smtp smtp_params c
data_redirect addr_match_list safe_ultostr verify_sender_addr \
mail_version mail_dict server_acl uxtext mail_parm_split \
fold_addr smtp_reply_footer mail_addr_map normalize_mailhost_addr \
- haproxy_srvr_test map_search delivered_hdr login_sender_match \
+ haproxy_srvr_test map_search delivered_hdr login_sender_match_test \
compat_level config_known_tcp_ports hfrom_format rfc2047_code \
ascii_header_text sendopts_test dict_sqlite_test pol_stats_test
delivered_hdr: delivered_hdr.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-login_sender_match: login_sender_match.c $(LIB) $(LIBS)
+login_sender_match_test: login_sender_match_test.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
compat_level: compat_level.c $(LIB) $(LIBS)
smtp_reply_footer_test off_cvt_test mail_addr_crunch_test \
mail_addr_find_test mail_addr_map_test quote_822_local_test \
normalize_mailhost_addr_test test_haproxy_srvr map_search_test \
- delivered_hdr_test login_sender_match_test compat_level_test \
+ delivered_hdr_test test_login_sender_match compat_level_test \
config_known_tcp_ports_test hfrom_format_test rfc2047_code_test \
ascii_header_text_test test_sendopts test_dict_sqlite test_pol_stats
diff delivered_hdr.ref delivered_hdr.tmp
rm -f delivered_hdr.tmp
-login_sender_match_test: update login_sender_match login_sender_match.ref
- -$(SHLIB_ENV) $(VALGRIND) ./login_sender_match >login_sender_match.tmp 2>&1
- diff login_sender_match.ref login_sender_match.tmp
- rm -f login_sender_match.tmp
+test_login_sender_match: update login_sender_match_test
+ $(SHLIB_ENV) $(VALGRIND) ./login_sender_match_test
compat_level_test: compat_level_expand_test compat_level_convert_test
login_sender_match.o: quote_822_local.h
login_sender_match.o: quote_flags.h
login_sender_match.o: strip_addr.h
+login_sender_match_test.o: ../../include/argv.h
+login_sender_match_test.o: ../../include/check_arg.h
+login_sender_match_test.o: ../../include/dict.h
+login_sender_match_test.o: ../../include/msg.h
+login_sender_match_test.o: ../../include/msg_vstream.h
+login_sender_match_test.o: ../../include/myflock.h
+login_sender_match_test.o: ../../include/stringops.h
+login_sender_match_test.o: ../../include/sys_defs.h
+login_sender_match_test.o: ../../include/vbuf.h
+login_sender_match_test.o: ../../include/vstream.h
+login_sender_match_test.o: ../../include/vstring.h
+login_sender_match_test.o: login_sender_match.h
+login_sender_match_test.o: login_sender_match_test.c
+login_sender_match_test.o: mail_params.h
mail_addr.o: ../../include/check_arg.h
mail_addr.o: ../../include/stringops.h
mail_addr.o: ../../include/sys_defs.h
}
return (found_or_error);
}
-
-#ifdef TEST
-
-int main(int argc, char **argv)
-{
- struct testcase {
- const char *title;
- const char *map_names;
- const char *ext_delimiters;
- const char *null_sender;
- const char *wildcard;
- const char *login_name;
- const char *sender_addr;
- int exp_return;
- };
- struct testcase testcases[] = {
- {"wildcard works",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "root", "anything", LSM_STAT_FOUND
- },
- {"unknown user",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "toor", "anything", LSM_STAT_NOTFOUND
- },
- {"bare user",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "foo", LSM_STAT_FOUND
- },
- {"user@domain",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "foo@example.com", LSM_STAT_FOUND
- },
- {"user+ext@domain",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "foo+bar@example.com", LSM_STAT_FOUND
- },
- {"wrong sender",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "bar@example.com", LSM_STAT_NOTFOUND
- },
- {"@domain",
- "inline:{root=*, {foo = @example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "anyone@example.com", LSM_STAT_FOUND
- },
- {"wrong @domain",
- "inline:{root=*, {foo = @example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "anyone@example.org", LSM_STAT_NOTFOUND
- },
- {"null sender",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "bar", "", LSM_STAT_FOUND
- },
- {"wrong null sender",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "baz", "", LSM_STAT_NOTFOUND
- },
- {"error",
- "inline:{root=*}, fail:sorry",
- "+-", "<>", "*", "baz", "whatever", LSM_STAT_RETRY
- },
- {"no error",
- "inline:{root=*}, fail:sorry",
- "+-", "<>", "*", "root", "whatever", LSM_STAT_FOUND
- },
- {"unknown uid:number",
- "inline:{root=*, {uid:12345 = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "uid:54321", "foo", LSM_STAT_NOTFOUND
- },
- {"known uid:number",
- "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;
- int pass;
- int fail;
- LOGIN_SENDER_MATCH *lsm;
-
- /*
- * Fake variable settings.
- */
- var_double_bounce_sender = DEF_DOUBLE_BOUNCE;
- var_ownreq_special = DEF_OWNREQ_SPECIAL;
-
-#define NUM_TESTS sizeof(testcases)/sizeof(testcases[0])
-
- for (pass = fail = 0, tp = testcases; tp < testcases + NUM_TESTS; tp++) {
- msg_info("RUN test case %ld %s", (long) (tp - testcases), tp->title);
-#if 0
- msg_info("title=%s", tp->title);
- msg_info("map_names=%s", tp->map_names);
- msg_info("ext_delimiters=%s", tp->ext_delimiters);
- msg_info("null_sender=%s", tp->null_sender);
- msg_info("wildcard=%s", tp->wildcard);
- msg_info("login_name=%s", tp->login_name);
- msg_info("sender_addr=%s", tp->sender_addr);
- msg_info("exp_return=%d", tp->exp_return);
-#endif
- lsm = login_sender_create("test map", tp->map_names,
- tp->ext_delimiters, tp->null_sender,
- tp->wildcard);
- act_return = login_sender_match(lsm, tp->login_name, tp->sender_addr);
- if (act_return == tp->exp_return) {
- msg_info("PASS test %ld", (long) (tp - testcases));
- pass++;
- } else {
- msg_info("FAIL test %ld", (long) (tp - testcases));
- fail++;
- }
- login_sender_free(lsm);
- }
- return (fail > 0);
-}
-
-#endif /* TEST */
--- /dev/null
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <msg_vstream.h>
+#include <stringops.h>
+
+ /*
+ * Global library.
+ */
+#include <login_sender_match.h>
+#include <mail_params.h>
+
+int main(int argc, char **argv)
+{
+ struct testcase {
+ const char *title;
+ const char *map_names;
+ const char *ext_delimiters;
+ const char *null_sender;
+ const char *wildcard;
+ const char *login_name;
+ const char *sender_addr;
+ int exp_return;
+ };
+ struct testcase testcases[] = {
+ {"wildcard works",
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "root", "anything", LSM_STAT_FOUND
+ },
+ {"unknown user",
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "toor", "anything", LSM_STAT_NOTFOUND
+ },
+ {"bare user",
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "foo", LSM_STAT_FOUND
+ },
+ {"user@domain",
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "foo@example.com", LSM_STAT_FOUND
+ },
+ {"user+ext@domain",
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "foo+bar@example.com", LSM_STAT_FOUND
+ },
+ {"wrong sender",
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "bar@example.com", LSM_STAT_NOTFOUND
+ },
+ {"@domain",
+ "inline:{root=*, {foo = @example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "anyone@example.com", LSM_STAT_FOUND
+ },
+ {"wrong @domain",
+ "inline:{root=*, {foo = @example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "anyone@example.org", LSM_STAT_NOTFOUND
+ },
+ {"null sender",
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "bar", "", LSM_STAT_FOUND
+ },
+ {"wrong null sender",
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "baz", "", LSM_STAT_NOTFOUND
+ },
+ {"error",
+ "inline:{root=*}, fail:sorry",
+ "+-", "<>", "*", "baz", "whatever", LSM_STAT_RETRY
+ },
+ {"no error",
+ "inline:{root=*}, fail:sorry",
+ "+-", "<>", "*", "root", "whatever", LSM_STAT_FOUND
+ },
+ {"unknown uid:number",
+ "inline:{root=*, {uid:12345 = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "uid:54321", "foo", LSM_STAT_NOTFOUND
+ },
+ {"known uid:number",
+ "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;
+ int pass;
+ int fail;
+ LOGIN_SENDER_MATCH *lsm;
+
+ msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
+
+ /*
+ * Fake variable settings.
+ */
+ var_double_bounce_sender = DEF_DOUBLE_BOUNCE;
+ var_ownreq_special = DEF_OWNREQ_SPECIAL;
+
+#define NUM_TESTS sizeof(testcases)/sizeof(testcases[0])
+
+ for (pass = fail = 0, tp = testcases; tp < testcases + NUM_TESTS; tp++) {
+ msg_info("RUN test case %ld %s", (long) (tp - testcases), tp->title);
+#if 0
+ msg_info("title=%s", tp->title);
+ msg_info("map_names=%s", tp->map_names);
+ msg_info("ext_delimiters=%s", tp->ext_delimiters);
+ msg_info("null_sender=%s", tp->null_sender);
+ msg_info("wildcard=%s", tp->wildcard);
+ msg_info("login_name=%s", tp->login_name);
+ msg_info("sender_addr=%s", tp->sender_addr);
+ msg_info("exp_return=%d", tp->exp_return);
+#endif
+ lsm = login_sender_create("test map", tp->map_names,
+ tp->ext_delimiters, tp->null_sender,
+ tp->wildcard);
+ act_return = login_sender_match(lsm, tp->login_name, tp->sender_addr);
+ if (act_return == tp->exp_return) {
+ msg_info("PASS test %ld", (long) (tp - testcases));
+ pass++;
+ } else {
+ msg_info("FAIL test %ld", (long) (tp - testcases));
+ fail++;
+ }
+ login_sender_free(lsm);
+ }
+ msg_info("PASS=%d FAIL=%d", pass, fail);
+ return (fail > 0);
+}
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20251114"
+#define MAIL_RELEASE_DATE "20251116"
#define MAIL_VERSION_NUMBER "3.11"
#ifdef SNAPSHOT
/* System library. */
#include <sys_defs.h>
+#include <stdlib.h>
#include <string.h>
/* Utility library. */
exit(1);
}
-
+#ifdef USE_TLS
#ifndef OPENSSL_NO_SSL_TRACE
static void ssl_trace(int write_p, int version, int content_type,
const void *buf, size_t msglen, SSL *ssl, void *arg)
}
#endif
-
+#endif
/* tls_init - initialize application TLS library context */
VAR_LMTP_TLSRPT_SKIP_REUSED_HS, DEF_LMTP_TLSRPT_SKIP_REUSED_HS, &var_smtp_tlsrpt_skip_reused_hs,
#ifdef USE_TLS
VAR_LMTP_TLS_ENF_STS_MX_PAT, DEF_LMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat,
-#endif
- VAR_LMTP_TLS_ENF_STS_MX_PAT, DEF_LMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat,
VAR_LMTP_LOG_TLS_FEATURE_STATUS, DEF_LMTP_LOG_TLS_FEATURE_STATUS, &var_log_tls_feature_status,
+#endif
0,
};
struct TLSRPT_WRAPPER *tlsrpt;
#endif
int reqtls_level; /* from smtp_reqtls_policy */
- POL_STATS *tls_stats; /* TLS feature policy compliance */
#endif
+ POL_STATS *tls_stats; /* TLS feature policy compliance */
/*
* Connection cache support.
VAR_SMTP_TLSRPT_SKIP_REUSED_HS, DEF_SMTP_TLSRPT_SKIP_REUSED_HS, &var_smtp_tlsrpt_skip_reused_hs,
#ifdef USE_TLS
VAR_SMTP_TLS_ENF_STS_MX_PAT, DEF_SMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat,
-#endif
- VAR_SMTP_TLS_ENF_STS_MX_PAT, DEF_SMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat,
VAR_SMTP_LOG_TLS_FEATURE_STATUS, DEF_SMTP_LOG_TLS_FEATURE_STATUS, &var_log_tls_feature_status,
+#endif
0,
};
xtext_quote_append(next_command, request->dsn_envid, "+=");
}
/* Fix 20250825: limit content exposure in bounce. */
+#ifdef USE_TLS
if (state->reqtls_level > SMTP_REQTLS_POLICY_ACT_DISABLE
&& (session->features & SMTP_FEATURE_REQTLS) == 0)
vstring_sprintf_append(next_command, " RET=%s",
dsn_ret_str(DSN_RET_HDRS));
- else if (request->dsn_ret)
+ else
+#endif
+ if (request->dsn_ret)
vstring_sprintf_append(next_command, " RET=%s",
dsn_ret_str(request->dsn_ret));
}
if (var_log_tls_feature_status)
state->tls_stats = pol_stats_create();
else
- state->tls_stats = 0;
#endif
+ state->tls_stats = 0;
if (var_smtp_cache_conn) {
state->dest_label = vstring_alloc(10);
state->dest_prop = vstring_alloc(10);
valid_utf8_string ip_match base32_code msg_rate_delay netstring \
vstream timecmp dict_cache midna_domain casefold strcasecmp_utf8 \
vbuf_print split_qnameval vstream msg_logger byte_mask \
- known_tcp_ports dict_stream find_inet binhash hash_fnv argv \
+ known_tcp_ports dict_stream find_inet binhash hash_fnv_test argv \
clean_env inet_prefix_top printable readlline quote_for_json \
normalize_ws valid_uri_scheme clean_ascii_cntrl_space \
normalize_v4mapped_addr_test ossl_digest_test dict_pipe_test \
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
-hash_fnv: $(LIB)
- mv $@.o junk
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
- mv junk $@.o
+hash_fnv_test: $(LIB) update
+ $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
unix_recv_fd: $(LIB)
mv $@.o junk
valid_utf8_string_test readlline_test quote_for_json_test \
normalize_ws_test valid_uri_scheme_test clean_ascii_cntrl_space_test \
test_normalize_v4mapped_addr test_ossl_digest test_dict_pipe \
- test_dict_union
+ test_dict_union test_hash_fnv
dict_tests: all dict_test \
dict_pcre_tests dict_cidr_test dict_thash_test dict_static_test \
binhash_test: binhash /usr/share/dict/words
$(SHLIB_ENV) ${VALGRIND} ./binhash < /usr/share/dict/words
-hash_fnv_test: hash_fnv
- $(SHLIB_ENV) ${VALGRIND} ./hash_fnv
+test_hash_fnv: hash_fnv_test
+ $(SHLIB_ENV) ${VALGRIND} ./hash_fnv_test
hex_code_test: hex_code
$(SHLIB_ENV) ${VALGRIND} ./hex_code
hash_fnv.o: ldseed.h
hash_fnv.o: msg.h
hash_fnv.o: sys_defs.h
+hash_fnv_test.o: check_arg.h
+hash_fnv_test.o: hash_fnv.h
+hash_fnv_test.o: hash_fnv_test.c
+hash_fnv_test.o: msg.h
+hash_fnv_test.o: msg_vstream.h
+hash_fnv_test.o: stringops.h
+hash_fnv_test.o: sys_defs.h
+hash_fnv_test.o: vbuf.h
+hash_fnv_test.o: vstream.h
+hash_fnv_test.o: vstring.h
hex_code.o: check_arg.h
hex_code.o: hex_code.c
hex_code.o: hex_code.h
}
return (hash);
}
-
-#ifdef TEST
-#include <stdlib.h>
-#include <string.h>
-#include <msg.h>
-
-int main(void)
-{
- int pass = 0;
- int fail = 0;
-
- /*
- * Sanity check.
- */
-#ifdef STRICT_FNV1A
- msg_fatal("This test requires no STRICT_FNV1A");
-#endif
-
- /*
- * Force unseeded hash, to make tests predictable.
- */
- if (putenv("NORANDOMIZE=") != 0)
- msg_fatal("putenv(\"NORANDOMIZE=\"): %m");
-
- /*
- * Test: hashing produces the expected results.
- */
- {
- struct testcase {
- HASH_FNV_T hval;
- const char *str;
- };
- static struct testcase testcases[] =
- {
-#ifdef USE_FNV_32BIT
- 0x1c00fc06UL, "overdeeply",
- 0x1c00fc06UL, "undescript",
- 0x1e1e52a4UL, "fanfold",
- 0x1e1e52a4UL, "phrensied",
-#else
- 0xda19999ec0bda706ULL, "overdeeply",
- 0xd7b9e43f26396a66ULL, "undescript",
- 0xa50c585d385a2604ULL, "fanfold",
- 0x1ec3ef9bb2b734a4ULL, "phrensied",
-#endif
- 0,
- };
- struct testcase *tp;
- HASH_FNV_T hval;
- int test_failed;
-
- for (tp = testcases; tp->str; tp++) {
- test_failed = 0;
- if ((hval = hash_fnvz(tp->str)) != tp->hval) {
- msg_warn("hash_fnv(\"%s\") want %lu, got: %lu",
- tp->str, (unsigned long) tp->hval,
- (unsigned long) hval);
- test_failed = 1;
- }
- if (test_failed) {
- fail += 1;
- msg_info("FAIL: %s", tp->str);
- } else {
- pass += 1;
- msg_info("PASS: %s", tp->str);
- }
- }
- }
-
- /*
- * Test: hash_fnvz(s) is equivalent to hash_fnv(s, strlen(s)). No need to
- * verify the actual result; we already did that above.
- */
- {
- const char *strval = "foobar";
- HASH_FNV_T h1 = hash_fnv(strval, strlen(strval));
- HASH_FNV_T h2 = hash_fnvz(strval);
-
- if (h1 == h2) {
- pass += 1;
- msg_info("PASS: hash_fnvz(\"%s\") == hash_fnv(\"%s\", %ld)",
- strval, strval, (long) strlen(strval));
- } else {
- fail += 1;
- msg_info("FAIL: hash_fnvz(\"%s\") == hash_fnv(\"%s\", %ld)",
- strval, strval, (long) strlen(strval));
- }
- }
-
-
- /*
- * Wrap up.
- */
- msg_info("PASS=%d FAIL=%d", pass, fail);
- return (fail != 0);
-}
-
-#endif
--- /dev/null
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <msg_vstream.h>
+#include <stringops.h>
+#include <hash_fnv.h>
+
+int main(int srgc, char **argv)
+{
+ int pass = 0;
+ int fail = 0;
+
+ msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
+
+ /*
+ * Sanity check.
+ */
+#ifdef STRICT_FNV1A
+ msg_fatal("This test requires no STRICT_FNV1A");
+#endif
+
+ /*
+ * Force unseeded hash, to make tests predictable.
+ */
+ if (putenv("NORANDOMIZE=") != 0)
+ msg_fatal("putenv(\"NORANDOMIZE=\"): %m");
+
+ /*
+ * Test: hashing produces the expected results.
+ */
+ {
+ struct testcase {
+ HASH_FNV_T hval;
+ const char *str;
+ };
+ static struct testcase testcases[] =
+ {
+#ifdef USE_FNV_32BIT
+ 0x1c00fc06UL, "overdeeply",
+ 0x1c00fc06UL, "undescript",
+ 0x1e1e52a4UL, "fanfold",
+ 0x1e1e52a4UL, "phrensied",
+#else
+ 0xda19999ec0bda706ULL, "overdeeply",
+ 0xd7b9e43f26396a66ULL, "undescript",
+ 0xa50c585d385a2604ULL, "fanfold",
+ 0x1ec3ef9bb2b734a4ULL, "phrensied",
+#endif
+ 0,
+ };
+ struct testcase *tp;
+ HASH_FNV_T hval;
+ int test_failed;
+
+ for (tp = testcases; tp->str; tp++) {
+ test_failed = 0;
+ msg_info("RUN hash_fnvz(\"%s\")", tp->str);
+ if ((hval = hash_fnvz(tp->str)) != tp->hval) {
+ msg_warn("hash_fnv(\"%s\") want %lu, got: %lu",
+ tp->str, (unsigned long) tp->hval,
+ (unsigned long) hval);
+ test_failed = 1;
+ }
+ if (test_failed) {
+ fail += 1;
+ msg_info("FAIL hash_fnvz(\"%s\")", tp->str);
+ } else {
+ pass += 1;
+ msg_info("PASS hash_fnvz(\"%s\")", tp->str);
+ }
+ }
+ }
+
+ /*
+ * Test: hash_fnvz(s) is equivalent to hash_fnv(s, strlen(s)). No need to
+ * verify the actual result; we already did that above.
+ */
+ {
+ const char *strval = "foobar";
+ HASH_FNV_T h1;
+ HASH_FNV_T h2;
+
+ msg_info("RUN hash_fnvz(\"%s\") == hash_fnv(\"%s\", %ld)",
+ strval, strval, (long) strlen(strval));
+
+ h1 = hash_fnv(strval, strlen(strval));
+ h2 = hash_fnvz(strval);
+
+ if (h1 == h2) {
+ pass += 1;
+ msg_info("PASS: hash_fnvz(\"%s\") == hash_fnv(\"%s\", %ld)",
+ strval, strval, (long) strlen(strval));
+ } else {
+ fail += 1;
+ msg_info("FAIL: hash_fnvz(\"%s\") == hash_fnv(\"%s\", %ld)",
+ strval, strval, (long) strlen(strval));
+ }
+ }
+
+
+ /*
+ * Wrap up.
+ */
+ msg_info("PASS=%d FAIL=%d", pass, fail);
+ return (fail != 0);
+}