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