1/* $NetBSD: verify_clnt.c,v 1.3 2022/10/08 16:12:45 christos Exp $ */ 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/* Wietse Venema 63/* Google, Inc. 64/* 111 8th Avenue 65/* New York, NY 10011, USA 66/*--*/ 67 68/* System library. */ 69 70#include <sys_defs.h> 71#include <unistd.h> 72#include <errno.h> 73 74/* Utility library. */ 75 76#include <msg.h> 77#include <vstream.h> 78#include <vstring.h> 79#include <attr.h> 80 81/* Global library. */ 82 83#include <mail_params.h> 84#include <mail_proto.h> 85#include <clnt_stream.h> 86#include <verify_clnt.h> 87 88CLNT_STREAM *vrfy_clnt; 89 90/* verify_clnt_handshake - receive server protocol announcement */ 91 92static int verify_clnt_handshake(VSTREAM *stream) 93{ 94 return (attr_scan(stream, ATTR_FLAG_STRICT, 95 RECV_ATTR_STREQ(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_VERIFY), 96 ATTR_TYPE_END)); 97} 98 99/* verify_clnt_init - initialize */ 100 101static void verify_clnt_init(void) 102{ 103 if (vrfy_clnt != 0) 104 msg_panic("verify_clnt_init: multiple initialization"); 105 vrfy_clnt = clnt_stream_create(MAIL_CLASS_PRIVATE, var_verify_service, 106 var_ipc_idle_limit, var_ipc_ttl_limit, 107 verify_clnt_handshake); 108} 109 110/* verify_clnt_query - request address verification status */ 111 112int verify_clnt_query(const char *addr, int *addr_status, VSTRING *why) 113{ 114 VSTREAM *stream; 115 int request_status; 116 int count = 0; 117 118 /* 119 * Do client-server plumbing. 120 */ 121 if (vrfy_clnt == 0) 122 verify_clnt_init(); 123 124 /* 125 * Request status for this address. 126 */ 127 for (;;) { 128 stream = clnt_stream_access(vrfy_clnt); 129 errno = 0; 130 count += 1; 131 if (stream == 0 132 || attr_print(stream, ATTR_FLAG_NONE, 133 SEND_ATTR_STR(MAIL_ATTR_REQ, VRFY_REQ_QUERY), 134 SEND_ATTR_STR(MAIL_ATTR_ADDR, addr), 135 ATTR_TYPE_END) != 0 136 || vstream_fflush(stream) 137 || attr_scan(stream, ATTR_FLAG_MISSING, 138 RECV_ATTR_INT(MAIL_ATTR_STATUS, &request_status), 139 RECV_ATTR_INT(MAIL_ATTR_ADDR_STATUS, addr_status), 140 RECV_ATTR_STR(MAIL_ATTR_WHY, why), 141 ATTR_TYPE_END) != 3) { 142 if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT)) 143 msg_warn("problem talking to service %s: %m", 144 var_verify_service); 145 } else { 146 break; 147 } 148 sleep(1); 149 clnt_stream_recover(vrfy_clnt); 150 } 151 return (request_status); 152} 153 154/* verify_clnt_update - request address status update */ 155 156int verify_clnt_update(const char *addr, int addr_status, const char *why) 157{ 158 VSTREAM *stream; 159 int request_status; 160 161 /* 162 * Do client-server plumbing. 163 */ 164 if (vrfy_clnt == 0) 165 verify_clnt_init(); 166 167 /* 168 * Send status for this address. Supply a default status if the address 169 * verification service is unavailable. 170 */ 171 for (;;) { 172 stream = clnt_stream_access(vrfy_clnt); 173 errno = 0; 174 if (stream == 0 175 || attr_print(stream, ATTR_FLAG_NONE, 176 SEND_ATTR_STR(MAIL_ATTR_REQ, VRFY_REQ_UPDATE), 177 SEND_ATTR_STR(MAIL_ATTR_ADDR, addr), 178 SEND_ATTR_INT(MAIL_ATTR_ADDR_STATUS, addr_status), 179 SEND_ATTR_STR(MAIL_ATTR_WHY, why), 180 ATTR_TYPE_END) != 0 181 || attr_scan(stream, ATTR_FLAG_MISSING, 182 RECV_ATTR_INT(MAIL_ATTR_STATUS, &request_status), 183 ATTR_TYPE_END) != 1) { 184 if (msg_verbose || (errno != EPIPE && errno != ENOENT)) 185 msg_warn("problem talking to service %s: %m", 186 var_verify_service); 187 } else { 188 break; 189 } 190 sleep(1); 191 clnt_stream_recover(vrfy_clnt); 192 } 193 return (request_status); 194} 195 196 /* 197 * Proof-of-concept test client program. 198 */ 199#ifdef TEST 200 201#include <stdlib.h> 202#include <ctype.h> 203#include <stdlib.h> 204#include <unistd.h> 205#include <signal.h> 206#include <msg_vstream.h> 207#include <stringops.h> 208#include <vstring_vstream.h> 209#include <mail_conf.h> 210 211#define STR(x) vstring_str(x) 212 213static NORETURN usage(char *myname) 214{ 215 msg_fatal("usage: %s [-v]", myname); 216} 217 218static void query(char *query, VSTRING *buf) 219{ 220 int status; 221 222 switch (verify_clnt_query(query, &status, buf)) { 223 case VRFY_STAT_OK: 224 vstream_printf("%-10s %d\n", "status", status); 225 vstream_printf("%-10s %s\n", "text", STR(buf)); 226 vstream_fflush(VSTREAM_OUT); 227 break; 228 case VRFY_STAT_BAD: 229 msg_warn("bad request format"); 230 break; 231 case VRFY_STAT_FAIL: 232 msg_warn("request failed"); 233 break; 234 } 235} 236 237static void update(char *query) 238{ 239 char *addr; 240 char *status_text; 241 char *cp = query; 242 243 if ((addr = mystrtok(&cp, CHARS_SPACE)) == 0 244 || (status_text = mystrtok(&cp, CHARS_SPACE)) == 0) { 245 msg_warn("bad request format"); 246 return; 247 } 248 while (*cp && ISSPACE(*cp)) 249 cp++; 250 if (*cp == 0) { 251 msg_warn("bad request format"); 252 return; 253 } 254 switch (verify_clnt_update(query, atoi(status_text), cp)) { 255 case VRFY_STAT_OK: 256 vstream_printf("OK\n"); 257 vstream_fflush(VSTREAM_OUT); 258 break; 259 case VRFY_STAT_BAD: 260 msg_warn("bad request format"); 261 break; 262 case VRFY_STAT_FAIL: 263 msg_warn("request failed"); 264 break; 265 } 266} 267 268int main(int argc, char **argv) 269{ 270 VSTRING *buffer = vstring_alloc(1); 271 char *cp; 272 int ch; 273 char *command; 274 275 signal(SIGPIPE, SIG_IGN); 276 277 msg_vstream_init(argv[0], VSTREAM_ERR); 278 279 mail_conf_read(); 280 msg_info("using config files in %s", var_config_dir); 281 if (chdir(var_queue_dir) < 0) 282 msg_fatal("chdir %s: %m", var_queue_dir); 283 284 while ((ch = GETOPT(argc, argv, "v")) > 0) { 285 switch (ch) { 286 case 'v': 287 msg_verbose++; 288 break; 289 default: 290 usage(argv[0]); 291 } 292 } 293 if (argc - optind > 1) 294 usage(argv[0]); 295 296 while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { 297 cp = STR(buffer); 298 if ((command = mystrtok(&cp, CHARS_SPACE)) == 0) 299 continue; 300 if (strcmp(command, "query") == 0) 301 query(cp, buffer); 302 else if (strcmp(command, "update") == 0) 303 update(cp); 304 else 305 msg_warn("unrecognized command: %s", command); 306 } 307 vstring_free(buffer); 308 return (0); 309} 310 311#endif 312