1 /* $NetBSD: verify_clnt.c,v 1.1.1.1 2009/06/23 10:08:48 tron 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 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 83 CLNT_STREAM *vrfy_clnt; 84 85 /* verify_clnt_init - initialize */ 86 87 static 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 97 int 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 140 int 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 196 static NORETURN usage(char *myname) 197 { 198 msg_fatal("usage: %s [-v]", myname); 199 } 200 201 static 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 220 static 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 251 int 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