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
verify_clnt_handshake(VSTREAM * stream)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
verify_clnt_init(void)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
verify_clnt_query(const char * addr,int * addr_status,VSTRING * why)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
verify_clnt_update(const char * addr,int addr_status,const char * why)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
usage(char * myname)213 static NORETURN usage(char *myname)
214 {
215 msg_fatal("usage: %s [-v]", myname);
216 }
217
query(char * query,VSTRING * buf)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
update(char * query)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
main(int argc,char ** argv)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