int valid_mailhost_literal(const char *addr, int gripe) { const char *myname = "valid_mailhost_literal"; MAI_HOSTADDR_STR hostaddr; const char *last; size_t address_bytes; if (*addr != '[') { if (gripe) msg_warn("%s: '[' expected at start: %.100s", myname, addr); return (0); } if ((last = strchr(addr, ']')) == 0) { if (gripe) msg_warn("%s: ']' expected at end: %.100s", myname, addr); return (0); } if (last[1]) { if (gripe) msg_warn("%s: unexpected text after ']': %.100s", myname, addr); return (0); } if ((address_bytes = last - addr - 1) >= sizeof(hostaddr.buf)) { if (gripe) msg_warn("%s: too much text: %.100s", myname, addr); return (0); } strncpy(hostaddr.buf, addr + 1, address_bytes); hostaddr.buf[address_bytes] = 0; return (valid_mailhost_addr(hostaddr.buf, gripe) != 0); }
int main(int unused_argc, char **argv) { VSTRING *buffer = vstring_alloc(1); msg_vstream_init(argv[0], VSTREAM_ERR); msg_verbose = 1; while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { msg_info("testing: \"%s\"", vstring_str(buffer)); if (vstring_str(buffer)[0] == '[') valid_mailhost_literal(vstring_str(buffer), DO_GRIPE); else valid_mailhost_addr(vstring_str(buffer), DO_GRIPE); } exit(0); }
int resolve_local(const char *addr) { char *saved_addr = mystrdup(addr); char *dest; const char *bare_dest; struct addrinfo *res0 = 0; ssize_t len; /* * The optimizer will eliminate tests that always fail. */ #define RETURN(x) \ do { \ myfree(saved_addr); \ if (res0) \ freeaddrinfo(res0); \ return(x); \ } while (0) if (resolve_local_list == 0) resolve_local_init(); /* * Strip one trailing dot but not dot-dot. * * XXX This should not be distributed all over the code. Problem is, * addresses can enter the system via multiple paths: networks, local * forward/alias/include files, even as the result of address rewriting. */ len = strlen(saved_addr); if (len == 0) RETURN(0); if (saved_addr[len - 1] == '.') saved_addr[--len] = 0; if (len == 0 || saved_addr[len - 1] == '.') RETURN(0); /* * Compare the destination against the list of destinations that we * consider local. */ if (string_list_match(resolve_local_list, saved_addr)) RETURN(1); if (resolve_local_list->error != 0) RETURN(resolve_local_list->error); /* * Compare the destination against the list of interface addresses that * we are supposed to listen on. * * The destination may be an IPv6 address literal that was buried somewhere * inside a deeply recursively nested address. This information comes * from an untrusted source, and Wietse is not confident that everyone's * getaddrinfo() etc. implementation is sufficiently robust. The syntax * is complex enough with null field compression and with IPv4-in-IPv6 * addresses that errors are likely. * * The solution below is ad-hoc. We neutralize the string as soon as we * realize that its contents could be harmful. We neutralize the string * here, instead of neutralizing it in every resolve_local() caller. * That's because resolve_local knows how the address is going to be * parsed and converted into binary form. * * There are several more structural solutions to this. * * - One solution is to disallow address literals. This is not as bad as it * seems: I have never seen actual legitimate use of address literals. * * - Another solution is to label each string with a trustworthiness label * and to expect that all Postfix infrastructure will exercise additional * caution when given a string with untrusted content. This is not likely * to happen. * * FIX 200501 IPv6 patch did not require "IPv6:" prefix in numerical * addresses. */ dest = saved_addr; if (*dest == '[' && dest[len - 1] == ']') { dest++; dest[len -= 2] = 0; if ((bare_dest = valid_mailhost_addr(dest, DO_GRIPE)) != 0 && hostaddr_to_sockaddr(bare_dest, (char *) 0, 0, &res0) == 0) { if (own_inet_addr(res0->ai_addr) || proxy_inet_addr(res0->ai_addr)) RETURN(1); } } /* * Must be remote, or a syntax error. */ RETURN(0); }