1/* $NetBSD$ */ 2 3/*++ 4/* NAME 5/* verify_clnt 3 6/* SUMMARY 7/* address verification client interface 8/* SYNOPSIS 9/* #include <verify_clnt.h> 10/* 11/* int verify_clnt_query(addr, status, why) 12/* const char *addr; 13/* int *status; 14/* VSTRING *why; 15/* 16/* int verify_clnt_update(addr, status, why) 17/* const char *addr; 18/* int status; 19/* const char *why; 20/* DESCRIPTION 21/* verify_clnt_query() requests information about the given address. 22/* The result value is one of the valid status values (see 23/* status description below). 24/* In all cases the \fBwhy\fR argument provides additional 25/* information. 26/* 27/* verify_clnt_update() requests that the status of the specified 28/* address be updated. The result status is DEL_REQ_RCPT_STAT_OK upon 29/* success, DEL_REQ_RCPT_STAT_DEFER upon failure. 30/* 31/* Arguments 32/* .IP addr 33/* The email address in question. 34/* .IP status 35/* One of the following status codes: 36/* .RS 37/* .IP DEL_REQ_RCPT_STAT_OK 38/* The mail system did not detect any problems. 39/* .IP DEL_REQ_RCPT_STAT_DEFER 40/* The status of the address is indeterminate. 41/* .IP DEL_REQ_RCPT_STAT_BOUNCE 42/* The address is permanently undeliverable. 43/* .RE 44/* .IP why 45/* textual description of the status. 46/* DIAGNOSTICS 47/* These functions return VRFY_STAT_OK in case of success, 48/* VRFY_STAT_BAD in case of a malformed request, and 49/* VRFY_STAT_FAIL when the operation failed. 50/* SEE ALSO 51/* verify(8) Postfix address verification server 52/* LICENSE 53/* .ad 54/* .fi 55/* The Secure Mailer license must be distributed with this software. 56/* AUTHOR(S) 57/* Wietse Venema 58/* IBM T.J. Watson Research 59/* P.O. Box 704 60/* Yorktown Heights, NY 10598, USA 61/*--*/ 62 63/* System library. */ 64 65#include <sys_defs.h> 66#include <unistd.h> 67#include <errno.h> 68 69/* Utility library. */ 70 71#include <msg.h> 72#include <vstream.h> 73#include <vstring.h> 74#include <attr.h> 75 76/* Global library. */ 77 78#include <mail_params.h> 79#include <mail_proto.h> 80#include <clnt_stream.h> 81#include <verify_clnt.h> 82 83CLNT_STREAM *vrfy_clnt; 84 85/* verify_clnt_init - initialize */ 86 87static void verify_clnt_init(void) 88{ 89 if (vrfy_clnt != 0) 90 msg_panic("verify_clnt_init: multiple initialization"); 91 vrfy_clnt = clnt_stream_create(MAIL_CLASS_PRIVATE, var_verify_service, 92 var_ipc_idle_limit, var_ipc_ttl_limit); 93} 94 95/* verify_clnt_query - request address verification status */ 96 97int verify_clnt_query(const char *addr, int *addr_status, VSTRING *why) 98{ 99 VSTREAM *stream; 100 int request_status; 101 int count = 0; 102 103 /* 104 * Do client-server plumbing. 105 */ 106 if (vrfy_clnt == 0) 107 verify_clnt_init(); 108 109 /* 110 * Request status for this address. 111 */ 112 for (;;) { 113 stream = clnt_stream_access(vrfy_clnt); 114 errno = 0; 115 count += 1; 116 if (attr_print(stream, ATTR_FLAG_NONE, 117 ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_QUERY, 118 ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr, 119 ATTR_TYPE_END) != 0 120 || vstream_fflush(stream) 121 || attr_scan(stream, ATTR_FLAG_MISSING, 122 ATTR_TYPE_INT, MAIL_ATTR_STATUS, &request_status, 123 ATTR_TYPE_INT, MAIL_ATTR_ADDR_STATUS, addr_status, 124 ATTR_TYPE_STR, MAIL_ATTR_WHY, why, 125 ATTR_TYPE_END) != 3) { 126 if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT)) 127 msg_warn("problem talking to service %s: %m", 128 var_verify_service); 129 } else { 130 break; 131 } 132 sleep(1); 133 clnt_stream_recover(vrfy_clnt); 134 } 135 return (request_status); 136} 137 138/* verify_clnt_update - request address status update */ 139 140int verify_clnt_update(const char *addr, int addr_status, const char *why) 141{ 142 VSTREAM *stream; 143 int request_status; 144 145 /* 146 * Do client-server plumbing. 147 */ 148 if (vrfy_clnt == 0) 149 verify_clnt_init(); 150 151 /* 152 * Send status for this address. Supply a default status if the address 153 * verification service is unavailable. 154 */ 155 for (;;) { 156 stream = clnt_stream_access(vrfy_clnt); 157 errno = 0; 158 if (attr_print(stream, ATTR_FLAG_NONE, 159 ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_UPDATE, 160 ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr, 161 ATTR_TYPE_INT, MAIL_ATTR_ADDR_STATUS, addr_status, 162 ATTR_TYPE_STR, MAIL_ATTR_WHY, why, 163 ATTR_TYPE_END) != 0 164 || attr_scan(stream, ATTR_FLAG_MISSING, 165 ATTR_TYPE_INT, MAIL_ATTR_STATUS, &request_status, 166 ATTR_TYPE_END) != 1) { 167 if (msg_verbose || (errno != EPIPE && errno != ENOENT)) 168 msg_warn("problem talking to service %s: %m", 169 var_verify_service); 170 } else { 171 break; 172 } 173 sleep(1); 174 clnt_stream_recover(vrfy_clnt); 175 } 176 return (request_status); 177} 178 179 /* 180 * Proof-of-concept test client program. 181 */ 182#ifdef TEST 183 184#include <stdlib.h> 185#include <ctype.h> 186#include <stdlib.h> 187#include <unistd.h> 188#include <signal.h> 189#include <msg_vstream.h> 190#include <stringops.h> 191#include <vstring_vstream.h> 192#include <mail_conf.h> 193 194#define STR(x) vstring_str(x) 195 196static NORETURN usage(char *myname) 197{ 198 msg_fatal("usage: %s [-v]", myname); 199} 200 201static void query(char *query, VSTRING *buf) 202{ 203 int status; 204 205 switch (verify_clnt_query(query, &status, buf)) { 206 case VRFY_STAT_OK: 207 vstream_printf("%-10s %d\n", "status", status); 208 vstream_printf("%-10s %s\n", "text", STR(buf)); 209 vstream_fflush(VSTREAM_OUT); 210 break; 211 case VRFY_STAT_BAD: 212 msg_warn("bad request format"); 213 break; 214 case VRFY_STAT_FAIL: 215 msg_warn("request failed"); 216 break; 217 } 218} 219 220static void update(char *query) 221{ 222 char *addr; 223 char *status_text; 224 char *cp = query; 225 226 if ((addr = mystrtok(&cp, " \t\r\n")) == 0 227 || (status_text = mystrtok(&cp, " \t\r\n")) == 0) { 228 msg_warn("bad request format"); 229 return; 230 } 231 while (*cp && ISSPACE(*cp)) 232 cp++; 233 if (*cp == 0) { 234 msg_warn("bad request format"); 235 return; 236 } 237 switch (verify_clnt_update(query, atoi(status_text), cp)) { 238 case VRFY_STAT_OK: 239 vstream_printf("OK\n"); 240 vstream_fflush(VSTREAM_OUT); 241 break; 242 case VRFY_STAT_BAD: 243 msg_warn("bad request format"); 244 break; 245 case VRFY_STAT_FAIL: 246 msg_warn("request failed"); 247 break; 248 } 249} 250 251int main(int argc, char **argv) 252{ 253 VSTRING *buffer = vstring_alloc(1); 254 char *cp; 255 int ch; 256 char *command; 257 258 signal(SIGPIPE, SIG_IGN); 259 260 msg_vstream_init(argv[0], VSTREAM_ERR); 261 262 mail_conf_read(); 263 msg_info("using config files in %s", var_config_dir); 264 if (chdir(var_queue_dir) < 0) 265 msg_fatal("chdir %s: %m", var_queue_dir); 266 267 while ((ch = GETOPT(argc, argv, "v")) > 0) { 268 switch (ch) { 269 case 'v': 270 msg_verbose++; 271 break; 272 default: 273 usage(argv[0]); 274 } 275 } 276 if (argc - optind > 1) 277 usage(argv[0]); 278 279 while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { 280 cp = STR(buffer); 281 if ((command = mystrtok(&cp, " \t\r\n")) == 0) 282 continue; 283 if (strcmp(command, "query") == 0) 284 query(cp, buffer); 285 else if (strcmp(command, "update") == 0) 286 update(cp); 287 else 288 msg_warn("unrecognized command: %s", command); 289 } 290 vstring_free(buffer); 291 return (0); 292} 293 294#endif 295