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