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 88 CLNT_STREAM *vrfy_clnt; 89 90 /* verify_clnt_handshake - receive server protocol announcement */ 91 92 static 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 101 static 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 112 int 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 156 int 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 213 static NORETURN usage(char *myname) 214 { 215 msg_fatal("usage: %s [-v]", myname); 216 } 217 218 static 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 237 static 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 268 int 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