diff --git a/postfix/HISTORY b/postfix/HISTORY index d9edf263a..239401f75 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -7235,6 +7235,22 @@ Apologies for any names omitted. send data into unauthorized ports. Files: *qmgr/qmgr_message.c, trivial-rewrite/resolve.c. +20021128 + + Feature: hashed hold queue support, with hashing turned on + by default. Omission spotted by Victor Duchovni, Morgan + Stanley. Files: global/hold_message.c, global/mail_params.h. + + Bugfix: the LMTP client lost the port(service) information + when parsing host:port information. Victor Duchovni, Morgan + Stanley. Fix is to have a new host_port(3) module that does + the parsing for the SMTP and LMTP clients. + + Cleanup: host_port() routine that parses host/port information + more consistently than the existing code in the LMTP and + SMTP clients. Files: smtp/smtp_connect.c, lmtp/lmtp_connect.c, + util/host_port.[hc]. + Open problems: Low: revise other local delivery agent duplicate filters. diff --git a/postfix/conf/access b/postfix/conf/access index 9810d5237..1d7e01e64 100644 --- a/postfix/conf/access +++ b/postfix/conf/access @@ -74,19 +74,18 @@ # Note: lookup of the null sender address is not possible # with some types of lookup table. By default, Postfix uses # <> as the lookup key for such addresses. The value is -# specified with the workaround is to specify -# smtpd_null_access_lookup_key parameter in the Postfix -# main.cf file. +# specified with the smtpd_null_access_lookup_key parameter +# in the Postfix main.cf file. # # ADDRESS EXTENSION # When a mail address localpart contains the optional recip- -# ient delimiter (e.g., user+foo@domain), the lookup order -# becomes: user+foo@domain, user@domain, domain, user+foo@, +# ient delimiter (e.g., user+foo@domain), the lookup order +# becomes: user+foo@domain, user@domain, domain, user+foo@, # and user@. # # HOST NAME/ADDRESS PATTERNS # With lookups from indexed files such as DB or DBM, or from -# networked tables such as NIS, LDAP or SQL, the following +# networked tables such as NIS, LDAP or SQL, the following # lookup patterns are examined in the order as listed: # # domain.tld @@ -94,9 +93,9 @@ # # The pattern domain.tld also matches subdomains, but # only when the string smtpd_access_maps is listed in -# the Postfix parent_domain_matches_subdomains con- +# the Postfix parent_domain_matches_subdomains con- # figuration setting. Otherwise, specify .domain.tld -# (note the initial dot) in order to match subdo- +# (note the initial dot) in order to match subdo- # mains. # # net.work.addr.ess @@ -105,67 +104,67 @@ # # net.work # -# net Matches any host address in the specified network. -# A network address is a sequence of one or more +# net Matches any host address in the specified network. +# A network address is a sequence of one or more # octets separated by ".". # # ACTIONS # [45]NN text -# Reject the address etc. that matches the pattern, +# Reject the address etc. that matches the pattern, # and respond with the numerical code and text. # # REJECT # # REJECT optional text... -# Reject the address etc. that matches the pattern. -# Reply with $reject_code optional text... when the -# optional text is specified, otherwise reply with a +# Reject the address etc. that matches the pattern. +# Reply with $reject_code optional text... when the +# optional text is specified, otherwise reply with a # generic error response message. # # OK Accept the address etc. that matches the pattern. # # all-numerical # An all-numerical result is treated as OK. This for- -# mat is generated by address-based relay authoriza- +# mat is generated by address-based relay authoriza- # tion schemes. # -# DUNNO Pretend that the lookup key was not found in this -# table, to prevents Postfix from trying substrings -# of the lookup key (such as a subdomain name, or a +# DUNNO Pretend that the lookup key was not found in this +# table, to prevents Postfix from trying substrings +# of the lookup key (such as a subdomain name, or a # network address subnetwork). # # HOLD # # HOLD optional text... -# Place the message on the hold queue, where it will -# sit until someone either deletes it or releases it -# for delivery. Log the optional text if specified, +# Place the message on the hold queue, where it will +# sit until someone either deletes it or releases it +# for delivery. Log the optional text if specified, # otherwise log a generic message. # -# Mail that is placed on hold can be examined with -# the postcat(1) command, and can be destroyed or +# Mail that is placed on hold can be examined with +# the postcat(1) command, and can be destroyed or # released with the postsuper(1) command. # -# Note: this action currently affects all recipients +# Note: this action currently affects all recipients # of the message. # # DISCARD # # DISCARD optional text... -# Claim successful delivery and silently discard the -# message. Log the optional text if specified, oth- +# Claim successful delivery and silently discard the +# message. Log the optional text if specified, oth- # erwise log a generic message. # -# Note: this action currently affects all recipients +# Note: this action currently affects all recipients # of the message. # # FILTER transport:destination -# After the message is queued, send the entire mes- -# sage through a content filter. More information +# After the message is queued, send the entire mes- +# sage through a content filter. More information # about content filters is in the Postfix FIL- # TER_README file. # -# Note: this action currently affects all recipients +# Note: this action currently affects all recipients # of the message. # # restriction... @@ -173,30 +172,30 @@ # reject_unauth_destination, and so on). # # REGULAR EXPRESSION TABLES -# This section describes how the table lookups change when +# This section describes how the table lookups change when # the table is given in the form of regular expressions. For -# a description of regular expression lookup table syntax, +# a description of regular expression lookup table syntax, # see regexp_table(5) or pcre_table(5). # -# Each pattern is a regular expression that is applied to +# Each pattern is a regular expression that is applied to # the entire string being looked up. Depending on the appli- -# cation, that string is an entire client hostname, an +# cation, that string is an entire client hostname, an # entire client IP address, or an entire mail address. Thus, # no parent domain or parent network search is done, -# user@domain mail addresses are not broken up into their +# user@domain mail addresses are not broken up into their # user@ and domain constituent parts, nor is user+foo broken # up into user and foo. # -# Patterns are applied in the order as specified in the -# table, until a pattern is found that matches the search +# Patterns are applied in the order as specified in the +# table, until a pattern is found that matches the search # string. # -# Actions are the same as with indexed file lookups, with -# the additional feature that parenthesized substrings from +# Actions are the same as with indexed file lookups, with +# the additional feature that parenthesized substrings from # the pattern can be interpolated as $1, $2 and so on. # # BUGS -# The table format does not understand quoting conventions. +# The table format does not understand quoting conventions. # # SEE ALSO # postmap(1) create mapping table @@ -205,7 +204,7 @@ # regexp_table(5) format of POSIX regular expression tables # # LICENSE -# The Secure Mailer license must be distributed with this +# The Secure Mailer license must be distributed with this # software. # # AUTHOR(S) diff --git a/postfix/html/access.5.html b/postfix/html/access.5.html index 64186e76d..71f575c84 100644 --- a/postfix/html/access.5.html +++ b/postfix/html/access.5.html @@ -75,19 +75,18 @@ ACCESS(5) ACCESS(5) Note: lookup of the null sender address is not possible with some types of lookup table. By default, Postfix uses <> as the lookup key for such addresses. The value is - specified with the workaround is to specify - smtpd_null_access_lookup_key parameter in the Postfix - main.cf file. + specified with the smtpd_null_access_lookup_key parameter + in the Postfix main.cf file. ADDRESS EXTENSION When a mail address localpart contains the optional recip- - ient delimiter (e.g., user+foo@domain), the lookup order - becomes: user+foo@domain, user@domain, domain, user+foo@, + ient delimiter (e.g., user+foo@domain), the lookup order + becomes: user+foo@domain, user@domain, domain, user+foo@, and user@. HOST NAME/ADDRESS PATTERNS With lookups from indexed files such as DB or DBM, or from - networked tables such as NIS, LDAP or SQL, the following + networked tables such as NIS, LDAP or SQL, the following lookup patterns are examined in the order as listed: domain.tld @@ -95,9 +94,9 @@ ACCESS(5) ACCESS(5) The pattern domain.tld also matches subdomains, but only when the string smtpd_access_maps is listed in - the Postfix parent_domain_matches_subdomains con- + the Postfix parent_domain_matches_subdomains con- figuration setting. Otherwise, specify .domain.tld - (note the initial dot) in order to match subdo- + (note the initial dot) in order to match subdo- mains. net.work.addr.ess @@ -106,67 +105,67 @@ ACCESS(5) ACCESS(5) net.work - net Matches any host address in the specified network. - A network address is a sequence of one or more + net Matches any host address in the specified network. + A network address is a sequence of one or more octets separated by ".". ACTIONS [45]NN text - Reject the address etc. that matches the pattern, + Reject the address etc. that matches the pattern, and respond with the numerical code and text. REJECT REJECT optional text... - Reject the address etc. that matches the pattern. - Reply with $reject_code optional text... when the - optional text is specified, otherwise reply with a + Reject the address etc. that matches the pattern. + Reply with $reject_code optional text... when the + optional text is specified, otherwise reply with a generic error response message. OK Accept the address etc. that matches the pattern. all-numerical An all-numerical result is treated as OK. This for- - mat is generated by address-based relay authoriza- + mat is generated by address-based relay authoriza- tion schemes. - DUNNO Pretend that the lookup key was not found in this - table, to prevents Postfix from trying substrings - of the lookup key (such as a subdomain name, or a + DUNNO Pretend that the lookup key was not found in this + table, to prevents Postfix from trying substrings + of the lookup key (such as a subdomain name, or a network address subnetwork). HOLD HOLD optional text... - Place the message on the hold queue, where it will - sit until someone either deletes it or releases it - for delivery. Log the optional text if specified, + Place the message on the hold queue, where it will + sit until someone either deletes it or releases it + for delivery. Log the optional text if specified, otherwise log a generic message. - Mail that is placed on hold can be examined with - the postcat(1) command, and can be destroyed or + Mail that is placed on hold can be examined with + the postcat(1) command, and can be destroyed or released with the postsuper(1) command. - Note: this action currently affects all recipients + Note: this action currently affects all recipients of the message. DISCARD DISCARD optional text... - Claim successful delivery and silently discard the - message. Log the optional text if specified, oth- + Claim successful delivery and silently discard the + message. Log the optional text if specified, oth- erwise log a generic message. - Note: this action currently affects all recipients + Note: this action currently affects all recipients of the message. FILTER transport:destination - After the message is queued, send the entire mes- - sage through a content filter. More information + After the message is queued, send the entire mes- + sage through a content filter. More information about content filters is in the Postfix FIL- TER_README file. - Note: this action currently affects all recipients + Note: this action currently affects all recipients of the message. restriction... @@ -174,30 +173,30 @@ ACCESS(5) ACCESS(5) reject_unauth_destination, and so on). REGULAR EXPRESSION TABLES - This section describes how the table lookups change when + This section describes how the table lookups change when the table is given in the form of regular expressions. For - a description of regular expression lookup table syntax, + a description of regular expression lookup table syntax, see regexp_table(5) or pcre_table(5). - Each pattern is a regular expression that is applied to + Each pattern is a regular expression that is applied to the entire string being looked up. Depending on the appli- - cation, that string is an entire client hostname, an + cation, that string is an entire client hostname, an entire client IP address, or an entire mail address. Thus, no parent domain or parent network search is done, - user@domain mail addresses are not broken up into their + user@domain mail addresses are not broken up into their user@ and domain constituent parts, nor is user+foo broken up into user and foo. - Patterns are applied in the order as specified in the - table, until a pattern is found that matches the search + Patterns are applied in the order as specified in the + table, until a pattern is found that matches the search string. - Actions are the same as with indexed file lookups, with - the additional feature that parenthesized substrings from + Actions are the same as with indexed file lookups, with + the additional feature that parenthesized substrings from the pattern can be interpolated as $1, $2 and so on. BUGS - The table format does not understand quoting conventions. + The table format does not understand quoting conventions. SEE ALSO postmap(1) create mapping table @@ -206,7 +205,7 @@ ACCESS(5) ACCESS(5) regexp_table(5) format of POSIX regular expression tables LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/man/man5/access.5 b/postfix/man/man5/access.5 index 23afae49b..54d9974da 100644 --- a/postfix/man/man5/access.5 +++ b/postfix/man/man5/access.5 @@ -73,8 +73,8 @@ Matches all mail addresses with the specified user part. Note: lookup of the null sender address is not possible with some types of lookup table. By default, Postfix uses \fB<>\fR as the lookup key for such addresses. The value is specified with -the workaround is to specify \fBsmtpd_null_access_lookup_key\fR -parameter in the Postfix \fBmain.cf\fR file. +the \fBsmtpd_null_access_lookup_key\fR parameter in the Postfix +\fBmain.cf\fR file. .SH ADDRESS EXTENSION .na .nf diff --git a/postfix/proto/access b/postfix/proto/access index 1fc1a6a42..d9e0d3680 100644 --- a/postfix/proto/access +++ b/postfix/proto/access @@ -63,8 +63,8 @@ # Note: lookup of the null sender address is not possible with # some types of lookup table. By default, Postfix uses \fB<>\fR # as the lookup key for such addresses. The value is specified with -# the workaround is to specify \fBsmtpd_null_access_lookup_key\fR -# parameter in the Postfix \fBmain.cf\fR file. +# the \fBsmtpd_null_access_lookup_key\fR parameter in the Postfix +# \fBmain.cf\fR file. # ADDRESS EXTENSION # .fi # .ad diff --git a/postfix/src/cleanup/cleanup_api.c b/postfix/src/cleanup/cleanup_api.c index 6464b4827..bb06cb1b6 100644 --- a/postfix/src/cleanup/cleanup_api.c +++ b/postfix/src/cleanup/cleanup_api.c @@ -213,7 +213,9 @@ int cleanup_flush(CLEANUP_STATE *state) */ if (state->errs == 0 && (state->flags & CLEANUP_FLAG_DISCARD) == 0) { if ((state->flags & CLEANUP_FLAG_HOLD) != 0) { - hold_message(state->temp1, state->queue_name, state->queue_id); + if (hold_message(state->temp1, state->queue_name, state->queue_id) < 0) + msg_fatal("%s: problem putting message on hold: %m", + state->queue_id); junk = cleanup_path; cleanup_path = mystrdup(vstring_str(state->temp1)); myfree(junk); diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index 329991927..6cf7e66aa 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -532,6 +532,7 @@ hold_message.o: hold_message.c hold_message.o: ../../include/sys_defs.h hold_message.o: ../../include/msg.h hold_message.o: ../../include/set_eugid.h +hold_message.o: ../../include/sane_fsops.h hold_message.o: mail_queue.h hold_message.o: ../../include/vstring.h hold_message.o: ../../include/vbuf.h diff --git a/postfix/src/global/hold_message.c b/postfix/src/global/hold_message.c index d360a3b63..9a79a1b95 100644 --- a/postfix/src/global/hold_message.c +++ b/postfix/src/global/hold_message.c @@ -6,7 +6,7 @@ /* SYNOPSIS /* #include /* -/* void hold_message(path_buf, queue_name, queue_id) +/* int hold_message(path_buf, queue_name, queue_id) /* VSTRING *path_buf; /* const char *queue_name; /* const char *queue_id; @@ -22,6 +22,8 @@ /* Queue name with the message that needs to be placed on hold. /* .IP queue_id /* Queue file name with the message that needs to be placed on hold. +/* DIAGNOSTICS +/* The result is -1 in case of failure, 0 in case of success. /* LICENSE /* .ad /* .fi @@ -45,6 +47,7 @@ #include #include +#include /* Global library. */ @@ -56,13 +59,14 @@ /* hold_message - move message to hold queue */ -void hold_message(VSTRING *path_buf, const char *queue_name, +int hold_message(VSTRING *path_buf, const char *queue_name, const char *queue_id) { VSTRING *old_path = vstring_alloc(100); VSTRING *new_path = 0; uid_t saved_uid; gid_t saved_gid; + int err; /* * If not running as the mail system, change privileges first. @@ -79,20 +83,16 @@ void hold_message(VSTRING *path_buf, const char *queue_name, new_path = path_buf = vstring_alloc(100); /* - * Grr. Don't do stupid things when this function is called multiple - * times. sane_rename() would emit a bogus warning about spurious NFS - * problems. + * This code duplicates mail_queue_rename(), except that it also returns + * the result pathname to the caller. */ (void) mail_queue_path(old_path, queue_name, queue_id); (void) mail_queue_path(path_buf, MAIL_QUEUE_HOLD, queue_id); - if (access(STR(old_path), F_OK) == 0) { - if (rename(STR(old_path), STR(path_buf)) == 0 - || (access(STR(old_path), F_OK) < 0 - && access(STR(path_buf), F_OK) == 0)) { - if (msg_verbose) - msg_info("%s: placed on hold", queue_id); - } else - msg_warn("%s: could not place message on hold: %m", queue_id); + if ((err = sane_rename(STR(old_path), STR(path_buf))) == 0 + || ((err = mail_queue_mkdirs(STR(path_buf)) == 0) + && (err = sane_rename(STR(old_path), STR(path_buf))) == 0)) { + if (msg_verbose) + msg_info("%s: placed on hold", queue_id); } /* @@ -107,4 +107,6 @@ void hold_message(VSTRING *path_buf, const char *queue_name, vstring_free(old_path); if (new_path) vstring_free(new_path); + + return (err); } diff --git a/postfix/src/global/hold_message.h b/postfix/src/global/hold_message.h index 0b30a0154..ff0728bf0 100644 --- a/postfix/src/global/hold_message.h +++ b/postfix/src/global/hold_message.h @@ -14,7 +14,7 @@ /* * External interface. */ -extern void hold_message(VSTRING *, const char *, const char *); +extern int hold_message(VSTRING *, const char *, const char *); /* LICENSE /* .ad diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index a7677b653..18e23e211 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -658,7 +658,7 @@ extern int var_debug_peer_level; * subdirectories, and how deep the forest is. */ #define VAR_HASH_QUEUE_NAMES "hash_queue_names" -#define DEF_HASH_QUEUE_NAMES "incoming,active,deferred,bounce,defer,flush" +#define DEF_HASH_QUEUE_NAMES "incoming,active,deferred,bounce,defer,flush,hold" extern char *var_hash_queue_names; #define VAR_HASH_QUEUE_DEPTH "hash_queue_depth" diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 042980ca8..5da134b90 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change the patchlevel and the release date. Snapshots change the * release date only, unless they include the same bugfix as a patch release. */ -#define MAIL_RELEASE_DATE "20021124" +#define MAIL_RELEASE_DATE "20021130" #define VAR_MAIL_VERSION "mail_version" #define DEF_MAIL_VERSION "1.1.12-" MAIL_RELEASE_DATE diff --git a/postfix/src/lmtp/Makefile.in b/postfix/src/lmtp/Makefile.in index ba92b2f78..41303b3bc 100644 --- a/postfix/src/lmtp/Makefile.in +++ b/postfix/src/lmtp/Makefile.in @@ -129,6 +129,7 @@ lmtp_connect.o: ../../include/mymalloc.h lmtp_connect.o: ../../include/iostuff.h lmtp_connect.o: ../../include/timed_connect.h lmtp_connect.o: ../../include/stringops.h +lmtp_connect.o: ../../include/host_port.h lmtp_connect.o: ../../include/mail_params.h lmtp_connect.o: ../../include/mail_proto.h lmtp_connect.o: ../../include/attr.h diff --git a/postfix/src/lmtp/lmtp_connect.c b/postfix/src/lmtp/lmtp_connect.c index 6479d634d..35afabbba 100644 --- a/postfix/src/lmtp/lmtp_connect.c +++ b/postfix/src/lmtp/lmtp_connect.c @@ -92,6 +92,7 @@ #include #include #include +#include /* Global library. */ @@ -298,35 +299,21 @@ static char *lmtp_parse_destination(const char *destination, char *def_service, { char *myname = "lmtp_parse_destination"; char *buf = mystrdup(destination); - char *host = buf; char *service; struct servent *sp; char *protocol = "tcp"; /* XXX configurable? */ unsigned port; + const char *err; if (msg_verbose) msg_info("%s: %s %s", myname, destination, def_service); /* - * Strip quoting. We're working with a copy of the destination argument - * so the stripping can be destructive. + * Parse the host/port information. We're working with a copy of the + * destination argument so the parsing can be destructive. */ - if (*host == '[') { - host++; - host[strcspn(host, "]")] = 0; - } - - /* - * Separate host and service information, or use the default service - * specified by the caller. XXX the ":" character is used in the IPV6 - * address notation, so using split_at_right() is not sufficient. We'd - * have to count the number of ":" instances. - */ - if ((service = split_at_right(host, ':')) == 0 || *service == 0) - service = def_service; - if (*service == 0) - msg_fatal("%s: empty service name: %s", myname, destination); - *hostp = host; + if ((err = host_port(buf, hostp, &service, def_service)) != 0) + msg_fatal("%s in LMTP server description: %s", err, destination); /* * Convert service to port number, network byte order. Since most folks diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index fcf2e243b..c518690ac 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -136,6 +136,7 @@ smtp_connect.o: ../../include/inet_addr_list.h smtp_connect.o: ../../include/iostuff.h smtp_connect.o: ../../include/timed_connect.h smtp_connect.o: ../../include/stringops.h +smtp_connect.o: ../../include/host_port.h smtp_connect.o: ../../include/mail_params.h smtp_connect.o: ../../include/own_inet_addr.h smtp_connect.o: ../../include/dns.h diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index 38d769a7b..b0d3681c5 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -111,6 +111,7 @@ #include #include #include +#include /* Global library. */ @@ -325,49 +326,21 @@ static char *smtp_parse_destination(char *destination, char *def_service, char **hostp, unsigned *portp) { char *buf = mystrdup(destination); - char *host = buf; char *service; struct servent *sp; char *protocol = "tcp"; /* XXX configurable? */ unsigned port; - char *cruft; + const char *err; if (msg_verbose) msg_info("smtp_parse_destination: %s %s", destination, def_service); /* - * Strip quoting. We're working with a copy of the destination argument - * so the stripping can be destructive. + * Parse the host/port information. We're working with a copy of the + * destination argument so the parsing can be destructive. */ - if (*host == '[') { - host++; - cruft = split_at(host, ']'); - } else - cruft = 0; - - /* - * Separate host and service information, or use the default service - * specified by the caller. XXX the ":" character is used in the IPV6 - * address notation, so we will have to deprecate the use of [host:port] - * in favor of [host]:port. - */ - if (cruft && *cruft) { - if ((service = split_at_right(cruft, ':')) == 0) - service = def_service; - } else { - if ((service = split_at_right(host, ':')) == 0) - service = def_service; -#if 0 - else if (cruft) { - msg_warn("old-style address form: %s", destination); - msg_warn("support for [host:port] forms will go away"); - msg_warn("specify [host]:port instead"); - } -#endif - } - if (*service == 0) - msg_fatal("empty service name: %s", destination); - *hostp = host; + if ((err = host_port(buf, hostp, &service, def_service)) != 0) + msg_fatal("%s in SMTP server description: %s", err, destination); /* * Convert service to port number, network byte order. diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 44c895691..bce2c74e6 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -26,7 +26,7 @@ SRCS = alldig.c argv.c argv_split.c attr_print0.c attr_print64.c \ unix_connect.c unix_listen.c unix_trigger.c unsafe.c username.c \ valid_hostname.c vbuf.c vbuf_print.c vstream.c vstream_popen.c \ vstring.c vstring_vstream.c watchdog.c writable.c write_buf.c \ - write_wait.c strcasecmp.c nvtable.c + write_wait.c strcasecmp.c nvtable.c host_port.c OBJS = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \ attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \ chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \ @@ -54,7 +54,7 @@ OBJS = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \ unix_connect.o unix_listen.o unix_trigger.o unsafe.o username.o \ valid_hostname.o vbuf.o vbuf_print.o vstream.o vstream_popen.o \ vstring.o vstring_vstream.o watchdog.o writable.o write_buf.o \ - write_wait.o nvtable.o $(STRCASE) + write_wait.o nvtable.o $(STRCASE) host_port.o HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \ connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \ dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \ @@ -72,7 +72,7 @@ HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \ split_at.h stat_as.h stringops.h sys_defs.h timed_connect.h \ timed_wait.h trigger.h username.h valid_hostname.h vbuf.h \ vbuf_print.h vstream.h vstring.h vstring_vstream.h watchdog.h \ - nvtable.h + nvtable.h host_port.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ @@ -90,7 +90,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \ vstring vstring_vstream doze select_bug stream_test mac_expand \ watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \ inet_addr_list attr_print64 attr_scan64 base64_code attr_print0 \ - attr_scan0 + attr_scan0 host_port LIB_DIR = ../../lib INC_DIR = ../../include @@ -319,6 +319,11 @@ attr_scan0: $(LIB) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o +host_port: $(LIB) + mv $@.o junk + $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) + mv junk $@.o + depend: $(MAKES) (sed '1,/^# do not edit/!d' Makefile.in; \ set -e; for i in [a-z][a-z0-9]*.c; do \ @@ -332,7 +337,7 @@ stream_test: stream_test.c $(LIB) tests: valid_hostname_test mac_expand_test dict_test unescape_test \ hex_quote_test ctable_test inet_addr_list_test base64_code_test \ - attr_scan64_test attr_scan0_test dict_pcre_test + attr_scan64_test attr_scan0_test dict_pcre_test host_port_test valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref ./valid_hostname valid_hostname.tmp @@ -398,6 +403,11 @@ dict_regexp_test: dict_open dict_regexp.in dict_regexp.map dict_regexp.ref diff dict_regexp.ref dict_regexp.tmp rm -f dict_regexp.tmp +host_port_test: host_port host_port.in host_port.ref + ./host_port host_port.tmp 2>&1 + diff host_port.ref host_port.tmp + rm -f host_port.tmp + # do not edit below this line - it is generated by 'make depend' alldig.o: alldig.c alldig.o: sys_defs.h @@ -745,6 +755,15 @@ hex_quote.o: msg.h hex_quote.o: vstring.h hex_quote.o: vbuf.h hex_quote.o: hex_quote.h +host_port.o: host_port.c +host_port.o: sys_defs.h +host_port.o: msg.h +host_port.o: split_at.h +host_port.o: stringops.h +host_port.o: vstring.h +host_port.o: vbuf.h +host_port.o: valid_hostname.h +host_port.o: host_port.h htable.o: htable.c htable.o: sys_defs.h htable.o: mymalloc.h diff --git a/postfix/src/util/host_port.c b/postfix/src/util/host_port.c new file mode 100644 index 000000000..d682918ea --- /dev/null +++ b/postfix/src/util/host_port.c @@ -0,0 +1,139 @@ +/*++ +/* NAME +/* host_port 3 +/* SUMMARY +/* split string into host and port, destroy string +/* SYNOPSIS +/* #include +/* +/* const char *host_port(string, host, port, def_service) +/* char *string; +/* char **host; +/* char **port; +/* char *def_service; +/* DESCRIPTION +/* host_port() splits a string into substrings with the host +/* name or address, and the service name or port number. +/* The input string is modified. +/* DIAGNOSTICS +/* The result is a null pointer in case of success. +/* In case of problems the result is a string pointer with +/* the problem type. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include + +/* Global library. */ + +#include + +/* host_port - parse string into host and port, destroy string */ + +const char *host_port(char *buf, char **host, char **port, + char *def_service) +{ + char *cp = buf; + + /* + * [host]:port, [host]:, [host]. + */ + if (*cp == '[') { + *host = ++cp; + if ((cp = split_at(cp, ']')) == 0) + return ("missing \"]\""); + if (*cp && *cp++ != ':') + return ("garbage after \"]\""); + if (*cp == 0) + *port = def_service; + else + *port = cp; + + /* + * [host:port], [host:]. These conflict with IPV6 address literals. + */ +#if 1 + if (strchr(*host, ':')) { + msg_warn("old-style address form: [%s]", *host); + msg_warn("support for [host:port] forms will go away"); + msg_warn("specify [host]:port instead"); + return (host_port(buf + 1, host, port, def_service)); + } +#endif + } + + /* + * host:port, host:, host. + */ + else { + *host = cp; + if ((cp = split_at_right(cp, ':')) == 0 || *cp == 0) + *port = def_service; + else + *port = cp; + } + + /* + * Final sanity checks. We're still sloppy, allowing bare numerical + * network addresses instead of requiring proper [ipaddress] forms. + */ + if (!valid_hostname(*host, DONT_GRIPE) + && !valid_hostaddr(*host, DONT_GRIPE)) + return ("valid hostname or network address required"); + if (ISDIGIT(**port) && !alldig(*port)) + return ("garbage after numerical service"); + return (0); +} + +#ifdef TEST + +#include +#include +#include + +#define STR(x) vstring_str(x) + +int main(int unused_argc, char **unused_argv) +{ + VSTRING *in_buf = vstring_alloc(10); + VSTRING *parse_buf = vstring_alloc(10); + char *host; + char *port; + const char *err; + + while (vstring_fgets_nonl(in_buf, VSTREAM_IN)) { + vstream_printf(">> %s\n", STR(in_buf)); + vstream_fflush(VSTREAM_OUT); + vstring_strcpy(parse_buf, STR(in_buf)); + if ((err = host_port(STR(parse_buf), &host, &port, "default-service")) != 0) { + msg_warn("%s in %s", err, STR(in_buf)); + } else { + vstream_printf("host %s port %s\n", host, port); + vstream_fflush(VSTREAM_OUT); + } + } + vstring_free(in_buf); + vstring_free(parse_buf); + return (0); +} + +#endif diff --git a/postfix/src/util/host_port.h b/postfix/src/util/host_port.h new file mode 100644 index 000000000..629943a9c --- /dev/null +++ b/postfix/src/util/host_port.h @@ -0,0 +1,29 @@ +#ifndef _HOST_PORT_H_INCLUDED_ +#define _HOST_PORT_H_INCLUDED_ + +/*++ +/* NAME +/* host_port 3h +/* SUMMARY +/* split string into host and port, destroy string +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* External interface. */ + +extern const char *host_port(char *, char **, char **, char *); + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +#endif diff --git a/postfix/src/util/host_port.in b/postfix/src/util/host_port.in new file mode 100644 index 000000000..34c834383 --- /dev/null +++ b/postfix/src/util/host_port.in @@ -0,0 +1,12 @@ +hhh:ppp +hhh: +hhh +[hhh]:ppp +[hhh]: +[hhh] +[hhh:ppp] +[hhh:] +hhh:1pp +[hh.] +hh. +999 diff --git a/postfix/src/util/host_port.ref b/postfix/src/util/host_port.ref new file mode 100644 index 000000000..fbf672170 --- /dev/null +++ b/postfix/src/util/host_port.ref @@ -0,0 +1,30 @@ +>> hhh:ppp +host hhh port ppp +>> hhh: +host hhh port default-service +>> hhh +host hhh port default-service +>> [hhh]:ppp +host hhh port ppp +>> [hhh]: +host hhh port default-service +>> [hhh] +host hhh port default-service +>> [hhh:ppp] +unknown: warning: old-style address form: [hhh:ppp] +unknown: warning: support for [host:port] forms will go away +unknown: warning: specify [host]:port instead +host hhh port ppp +>> [hhh:] +unknown: warning: old-style address form: [hhh:] +unknown: warning: support for [host:port] forms will go away +unknown: warning: specify [host]:port instead +host hhh port default-service +>> hhh:1pp +unknown: warning: garbage after numerical service in hhh:1pp +>> [hh.] +unknown: warning: valid hostname or network address required in [hh.] +>> hh. +unknown: warning: valid hostname or network address required in hh. +>> 999 +host 999 port default-service