/*++ /* NAME /* verify_clnt 3 /* SUMMARY /* address verification client interface /* SYNOPSIS /* #include /* /* int verify_clnt_query(addr, status, why) /* const char *addr; /* int *status; /* VSTRING *why; /* /* int verify_clnt_update(addr, status, why) /* const char *addr; /* int status; /* const char *why; /* DESCRIPTION /* verify_clnt_query() requests information about the given address. /* The result value is one of the valid status values (see /* status description below). /* In all cases the \fBwhy\fR argument provides additional /* information. /* /* verify_clnt_update() requests that the status of the specified /* address be updated. The result status is DEL_REQ_RCPT_STAT_OK upon /* success, DEL_REQ_RCPT_STAT_DEFER upon failure. /* /* Arguments /* .IP addr /* The email address in question. /* .IP status /* One of the following status codes: /* .RS /* .IP DEL_REQ_RCPT_STAT_OK /* The mail system did not detect any problems. /* .IP DEL_REQ_RCPT_STAT_DEFER /* The status of the address is indeterminate. /* .IP DEL_REQ_RCPT_STAT_BOUNCE /* The address is permanently undeliverable. /* .RE /* .IP why /* textual description of the status. /* DIAGNOSTICS /* These functions return VRFY_STAT_OK in case of success, /* VRFY_STAT_BAD in case of a malformed request, and /* VRFY_STAT_FAIL when the operation failed. /* SEE ALSO /* verify(8) Postfix address verification server /* 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 /* /* Wietse Venema /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA /*--*/ /* System library. */ #include #include #include /* Utility library. */ #include #include #include #include /* Global library. */ #include #include #include #include CLNT_STREAM *vrfy_clnt; /* verify_clnt_handshake - receive server protocol announcement */ static int verify_clnt_handshake(VSTREAM *stream) { return (attr_scan(stream, ATTR_FLAG_STRICT, RECV_ATTR_STREQ(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_VERIFY), ATTR_TYPE_END)); } /* verify_clnt_init - initialize */ static void verify_clnt_init(void) { if (vrfy_clnt != 0) msg_panic("verify_clnt_init: multiple initialization"); vrfy_clnt = clnt_stream_create(MAIL_CLASS_PRIVATE, var_verify_service, var_ipc_idle_limit, var_ipc_ttl_limit, verify_clnt_handshake); } /* verify_clnt_query - request address verification status */ int verify_clnt_query(const char *addr, int *addr_status, VSTRING *why) { VSTREAM *stream; int request_status; int count = 0; /* * Do client-server plumbing. */ if (vrfy_clnt == 0) verify_clnt_init(); /* * Request status for this address. */ for (;;) { stream = clnt_stream_access(vrfy_clnt); errno = 0; count += 1; if (stream == 0 || attr_print(stream, ATTR_FLAG_NONE, SEND_ATTR_STR(MAIL_ATTR_REQ, VRFY_REQ_QUERY), SEND_ATTR_STR(MAIL_ATTR_ADDR, addr), ATTR_TYPE_END) != 0 || vstream_fflush(stream) || attr_scan(stream, ATTR_FLAG_MISSING, RECV_ATTR_INT(MAIL_ATTR_STATUS, &request_status), RECV_ATTR_INT(MAIL_ATTR_ADDR_STATUS, addr_status), RECV_ATTR_STR(MAIL_ATTR_WHY, why), ATTR_TYPE_END) != 3) { if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", var_verify_service); } else { break; } sleep(1); clnt_stream_recover(vrfy_clnt); } return (request_status); } /* verify_clnt_update - request address status update */ int verify_clnt_update(const char *addr, int addr_status, const char *why) { VSTREAM *stream; int request_status; /* * Do client-server plumbing. */ if (vrfy_clnt == 0) verify_clnt_init(); /* * Send status for this address. Supply a default status if the address * verification service is unavailable. */ for (;;) { stream = clnt_stream_access(vrfy_clnt); errno = 0; if (stream == 0 || attr_print(stream, ATTR_FLAG_NONE, SEND_ATTR_STR(MAIL_ATTR_REQ, VRFY_REQ_UPDATE), SEND_ATTR_STR(MAIL_ATTR_ADDR, addr), SEND_ATTR_INT(MAIL_ATTR_ADDR_STATUS, addr_status), SEND_ATTR_STR(MAIL_ATTR_WHY, why), ATTR_TYPE_END) != 0 || attr_scan(stream, ATTR_FLAG_MISSING, RECV_ATTR_INT(MAIL_ATTR_STATUS, &request_status), ATTR_TYPE_END) != 1) { if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", var_verify_service); } else { break; } sleep(1); clnt_stream_recover(vrfy_clnt); } return (request_status); } /* * Proof-of-concept test client program. */ #ifdef TEST #include #include #include #include #include #include #include #include #include #define STR(x) vstring_str(x) static NORETURN usage(char *myname) { msg_fatal("usage: %s [-v]", myname); } static void query(char *query, VSTRING *buf) { int status; switch (verify_clnt_query(query, &status, buf)) { case VRFY_STAT_OK: vstream_printf("%-10s %d\n", "status", status); vstream_printf("%-10s %s\n", "text", STR(buf)); vstream_fflush(VSTREAM_OUT); break; case VRFY_STAT_BAD: msg_warn("bad request format"); break; case VRFY_STAT_FAIL: msg_warn("request failed"); break; } } static void update(char *query) { char *addr; char *status_text; char *cp = query; if ((addr = mystrtok(&cp, CHARS_SPACE)) == 0 || (status_text = mystrtok(&cp, CHARS_SPACE)) == 0) { msg_warn("bad request format"); return; } while (*cp && ISSPACE(*cp)) cp++; if (*cp == 0) { msg_warn("bad request format"); return; } switch (verify_clnt_update(query, atoi(status_text), cp)) { case VRFY_STAT_OK: vstream_printf("OK\n"); vstream_fflush(VSTREAM_OUT); break; case VRFY_STAT_BAD: msg_warn("bad request format"); break; case VRFY_STAT_FAIL: msg_warn("request failed"); break; } } int main(int argc, char **argv) { VSTRING *buffer = vstring_alloc(1); char *cp; int ch; char *command; signal(SIGPIPE, SIG_IGN); msg_vstream_init(argv[0], VSTREAM_ERR); mail_conf_read(); msg_info("using config files in %s", var_config_dir); if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); while ((ch = GETOPT(argc, argv, "v")) > 0) { switch (ch) { case 'v': msg_verbose++; break; default: usage(argv[0]); } } if (argc - optind > 1) usage(argv[0]); while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { cp = STR(buffer); if ((command = mystrtok(&cp, CHARS_SPACE)) == 0) continue; if (strcmp(command, "query") == 0) query(cp, buffer); else if (strcmp(command, "update") == 0) update(cp); else msg_warn("unrecognized command: %s", command); } vstring_free(buffer); return (0); } #endif