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