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