xref: /netbsd-src/external/ibm-public/postfix/dist/src/postscreen/postscreen.h (revision ca453df649ce9db45b64d73678ba06cbccf9aa11)
1 /*	$NetBSD: postscreen.h,v 1.1.1.1 2011/03/02 19:32:26 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	postscreen 3h
6 /* SUMMARY
7 /*	postscreen internal interfaces
8 /* SYNOPSIS
9 /*	#include <postscreen.h>
10 /* DESCRIPTION
11 /* .nf
12 
13  /*
14   * System library.
15   */
16 
17  /*
18   * Utility library.
19   */
20 #include <dict_cache.h>
21 #include <vstream.h>
22 #include <vstring.h>
23 #include <events.h>
24 #include <htable.h>
25 
26  /*
27   * Global library.
28   */
29 #include <addr_match_list.h>
30 #include <string_list.h>
31 #include <maps.h>
32 
33  /*
34   * Preliminary stuff, to be fixed.
35   */
36 #define PSC_READ_BUF_SIZE	1024
37 
38  /*
39   * Per-session state.
40   */
41 typedef struct {
42     int     flags;			/* see below */
43     /* Socket state. */
44     VSTREAM *smtp_client_stream;	/* remote SMTP client */
45     int     smtp_server_fd;		/* real SMTP server */
46     char   *smtp_client_addr;		/* client address */
47     char   *smtp_client_port;		/* client port */
48     int     client_concurrency;		/* per-client */
49     const char *final_reply;		/* cause for hanging up */
50     VSTRING *send_buf;			/* pending output */
51     /* Test context. */
52     struct timeval start_time;		/* start of current test */
53     const char *test_name;		/* name of current test */
54     /* Before-handshake tests. */
55     time_t  pregr_stamp;		/* pregreet expiration time */
56     time_t  dnsbl_stamp;		/* dnsbl expiration time */
57     VSTRING *dnsbl_reply;		/* dnsbl reject text */
58     int     dnsbl_index;		/* dnsbl request index */
59     time_t  penal_stamp;		/* penalty expiration time */
60     /* Built-in SMTP protocol engine. */
61     time_t  pipel_stamp;		/* pipelining expiration time */
62     time_t  nsmtp_stamp;		/* non-smtp command expiration time */
63     time_t  barlf_stamp;		/* bare newline expiration time */
64     const char *rcpt_reply;		/* how to reject recipients */
65     int     command_count;		/* error + junk command count */
66     const char *protocol;		/* SMTP or ESMTP */
67     char   *helo_name;			/* SMTP helo/ehlo */
68     char   *sender;			/* MAIL FROM */
69     VSTRING *cmd_buffer;		/* command read buffer */
70     int     read_state;			/* command read state machine */
71     /* smtpd(8) compatibility */
72     int     ehlo_discard_mask;		/* EHLO filter */
73     VSTRING *expand_buf;		/* macro expansion */
74 } PSC_STATE;
75 
76 #define PSC_TIME_STAMP_NEW		(0)	/* test was never passed */
77 #define PSC_TIME_STAMP_DISABLED		(1)	/* never passed but disabled */
78 #define PSC_TIME_STAMP_INVALID		(-1)	/* must not be cached */
79 
80 #define PSC_STATE_FLAG_NOFORWARD	(1<<0)	/* don't forward this session */
81 #define PSC_STATE_FLAG_USING_TLS	(1<<1)	/* using the TLS proxy */
82 #define PSC_STATE_FLAG_UNUSED2		(1<<2)	/* use me! */
83 #define PSC_STATE_FLAG_NEW		(1<<3)	/* some test was never passed */
84 #define PSC_STATE_FLAG_BLIST_FAIL	(1<<4)	/* blacklisted */
85 #define PSC_STATE_FLAG_HANGUP		(1<<5)	/* NOT a test failure */
86 #define PSC_STATE_FLAG_CACHE_EXPIRED	(1<<6)	/* cache retention expired */
87 
88  /*
89   * Important: every MUMBLE_TODO flag must have a MUMBLE_PASS flag, such that
90   * MUMBLE_PASS == PSC_STATE_FLAGS_TODO_TO_PASS(MUMBLE_TODO).
91   *
92   * MUMBLE_TODO flags must not be cleared once raised. The _TODO_TO_PASS and
93   * _TODO_TO_DONE macros depend on this to decide that a group of tests is
94   * passed or completed.
95   *
96   * MUMBLE_DONE flags are used for "early" tests that have final results.
97   *
98   * MUMBLE_SKIP flags are used for "deep" tests where the client messed up.
99   * These flags look like MUMBLE_DONE but they are different. Deep tests can
100   * tentatively pass, but can still fail later in a session. The "ignore"
101   * action introduces an additional complication. MUMBLE_PASS indicates
102   * either that a deep test passed tentatively, or that the test failed but
103   * the result was ignored. MUMBLE_FAIL, on the other hand, is always final.
104   * We use MUMBLE_SKIP to indicate that a decision was either "fail" or
105   * forced "pass".
106   */
107 #define PSC_STATE_FLAGS_TODO_TO_PASS(todo_flags) ((todo_flags) >> 1)
108 #define PSC_STATE_FLAGS_TODO_TO_DONE(todo_flags) ((todo_flags) << 1)
109 
110 #define PSC_STATE_FLAG_PENAL_UPDATE	(1<<6)	/* save new penalty */
111 #define PSC_STATE_FLAG_PENAL_FAIL	(1<<7)	/* penalty is active */
112 
113 #define PSC_STATE_FLAG_PREGR_FAIL	(1<<8)	/* failed pregreet test */
114 #define PSC_STATE_FLAG_PREGR_PASS	(1<<9)	/* passed pregreet test */
115 #define PSC_STATE_FLAG_PREGR_TODO	(1<<10)	/* pregreet test expired */
116 #define PSC_STATE_FLAG_PREGR_DONE	(1<<11)	/* decision is final */
117 
118 #define PSC_STATE_FLAG_DNSBL_FAIL	(1<<12)	/* failed DNSBL test */
119 #define PSC_STATE_FLAG_DNSBL_PASS	(1<<13)	/* passed DNSBL test */
120 #define PSC_STATE_FLAG_DNSBL_TODO	(1<<14)	/* DNSBL test expired */
121 #define PSC_STATE_FLAG_DNSBL_DONE	(1<<15)	/* decision is final */
122 
123  /* Room here for one more after-handshake test. */
124 
125 #define PSC_STATE_FLAG_PIPEL_FAIL	(1<<20)	/* failed pipelining test */
126 #define PSC_STATE_FLAG_PIPEL_PASS	(1<<21)	/* passed pipelining test */
127 #define PSC_STATE_FLAG_PIPEL_TODO	(1<<22)	/* pipelining test expired */
128 #define PSC_STATE_FLAG_PIPEL_SKIP	(1<<23)	/* action is already logged */
129 
130 #define PSC_STATE_FLAG_NSMTP_FAIL	(1<<24)	/* failed non-SMTP test */
131 #define PSC_STATE_FLAG_NSMTP_PASS	(1<<25)	/* passed non-SMTP test */
132 #define PSC_STATE_FLAG_NSMTP_TODO	(1<<26)	/* non-SMTP test expired */
133 #define PSC_STATE_FLAG_NSMTP_SKIP	(1<<27)	/* action is already logged */
134 
135 #define PSC_STATE_FLAG_BARLF_FAIL	(1<<28)	/* failed bare newline test */
136 #define PSC_STATE_FLAG_BARLF_PASS	(1<<29)	/* passed bare newline test */
137 #define PSC_STATE_FLAG_BARLF_TODO	(1<<30)	/* bare newline test expired */
138 #define PSC_STATE_FLAG_BARLF_SKIP	(1<<31)	/* action is already logged */
139 
140  /*
141   * Aggregates for individual tests.
142   */
143 #define PSC_STATE_MASK_PREGR_TODO_FAIL \
144 	(PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_PREGR_FAIL)
145 #define PSC_STATE_MASK_DNSBL_TODO_FAIL \
146 	(PSC_STATE_FLAG_DNSBL_TODO | PSC_STATE_FLAG_DNSBL_FAIL)
147 #define PSC_STATE_MASK_PIPEL_TODO_FAIL \
148 	(PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_FAIL)
149 #define PSC_STATE_MASK_NSMTP_TODO_FAIL \
150 	(PSC_STATE_FLAG_NSMTP_TODO | PSC_STATE_FLAG_NSMTP_FAIL)
151 #define PSC_STATE_MASK_BARLF_TODO_FAIL \
152 	(PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_FAIL)
153 
154 #define PSC_STATE_MASK_PIPEL_TODO_SKIP \
155 	(PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_SKIP)
156 #define PSC_STATE_MASK_NSMTP_TODO_SKIP \
157 	(PSC_STATE_FLAG_NSMTP_TODO | PSC_STATE_FLAG_NSMTP_SKIP)
158 #define PSC_STATE_MASK_BARLF_TODO_SKIP \
159 	(PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_SKIP)
160 
161 #define PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL \
162 	(PSC_STATE_MASK_PIPEL_TODO_FAIL | PSC_STATE_FLAG_PIPEL_PASS)
163 #define PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL \
164 	(PSC_STATE_MASK_NSMTP_TODO_FAIL | PSC_STATE_FLAG_NSMTP_PASS)
165 #define PSC_STATE_MASK_BARLF_TODO_PASS_FAIL \
166 	(PSC_STATE_MASK_BARLF_TODO_FAIL | PSC_STATE_FLAG_BARLF_PASS)
167 
168  /*
169   * Separate aggregates for early tests and deep tests.
170   */
171 #define PSC_STATE_MASK_EARLY_DONE \
172 	(PSC_STATE_FLAG_PREGR_DONE | PSC_STATE_FLAG_DNSBL_DONE)
173 #define PSC_STATE_MASK_EARLY_TODO \
174 	(PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_DNSBL_TODO)
175 #define PSC_STATE_MASK_EARLY_PASS \
176 	(PSC_STATE_FLAG_PREGR_PASS | PSC_STATE_FLAG_DNSBL_PASS)
177 #define PSC_STATE_MASK_EARLY_FAIL \
178 	(PSC_STATE_FLAG_PREGR_FAIL | PSC_STATE_FLAG_DNSBL_FAIL)
179 
180 #define PSC_STATE_MASK_SMTPD_TODO \
181 	(PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_NSMTP_TODO | \
182 	PSC_STATE_FLAG_BARLF_TODO)
183 #define PSC_STATE_MASK_SMTPD_PASS \
184 	(PSC_STATE_FLAG_PIPEL_PASS | PSC_STATE_FLAG_NSMTP_PASS | \
185 	PSC_STATE_FLAG_BARLF_PASS)
186 #define PSC_STATE_MASK_SMTPD_FAIL \
187 	(PSC_STATE_FLAG_PIPEL_FAIL | PSC_STATE_FLAG_NSMTP_FAIL | \
188 	PSC_STATE_FLAG_BARLF_FAIL)
189 
190  /*
191   * Super-aggregates for all tests combined.
192   */
193 #define PSC_STATE_MASK_ANY_FAIL \
194 	(PSC_STATE_FLAG_BLIST_FAIL | PSC_STATE_FLAG_PENAL_FAIL | \
195 	PSC_STATE_MASK_EARLY_FAIL | PSC_STATE_MASK_SMTPD_FAIL)
196 
197 #define PSC_STATE_MASK_ANY_PASS \
198 	(PSC_STATE_MASK_EARLY_PASS | PSC_STATE_MASK_SMTPD_PASS)
199 
200 #define PSC_STATE_MASK_ANY_TODO \
201 	(PSC_STATE_MASK_EARLY_TODO | PSC_STATE_MASK_SMTPD_TODO)
202 
203 #define PSC_STATE_MASK_ANY_TODO_FAIL \
204 	(PSC_STATE_MASK_ANY_TODO | PSC_STATE_MASK_ANY_FAIL)
205 
206 #define PSC_STATE_MASK_ANY_UPDATE \
207 	(PSC_STATE_MASK_ANY_PASS | PSC_STATE_FLAG_PENAL_UPDATE)
208 
209  /*
210   * See log_adhoc.c for discussion.
211   */
212 typedef struct {
213     int     dt_sec;			/* make sure it's signed */
214     int     dt_usec;			/* make sure it's signed */
215 } DELTA_TIME;
216 
217 #define PSC_CALC_DELTA(x, y, z) \
218     do { \
219 	(x).dt_sec = (y).tv_sec - (z).tv_sec; \
220 	(x).dt_usec = (y).tv_usec - (z).tv_usec; \
221 	while ((x).dt_usec < 0) { \
222 	    (x).dt_usec += 1000000; \
223 	    (x).dt_sec -= 1; \
224 	} \
225 	while ((x).dt_usec >= 1000000) { \
226 	    (x).dt_usec -= 1000000; \
227 	    (x).dt_sec += 1; \
228 	} \
229 	if ((x).dt_sec < 0) \
230 	    (x).dt_sec = (x).dt_usec = 0; \
231     } while (0)
232 
233 #define SIG_DIGS        2
234 
235  /*
236   * Event management.
237   */
238 
239 /* PSC_READ_EVENT_REQUEST - prepare for transition to next state */
240 
241 #define PSC_READ_EVENT_REQUEST(fd, action, context, timeout) do { \
242 	if (msg_verbose > 1) \
243 	    msg_info("%s: read-request fd=%d", myname, (fd)); \
244 	event_enable_read((fd), (action), (context)); \
245 	event_request_timer((action), (context), (timeout)); \
246     } while (0)
247 
248 #define PSC_READ_EVENT_REQUEST2(fd, read_act, time_act, context, timeout) do { \
249 	if (msg_verbose > 1) \
250 	    msg_info("%s: read-request fd=%d", myname, (fd)); \
251 	event_enable_read((fd), (read_act), (context)); \
252 	event_request_timer((time_act), (context), (timeout)); \
253     } while (0)
254 
255 /* PSC_CLEAR_EVENT_REQUEST - complete state transition */
256 
257 #define PSC_CLEAR_EVENT_REQUEST(fd, time_act, context) do { \
258 	if (msg_verbose > 1) \
259 	    msg_info("%s: clear-request fd=%d", myname, (fd)); \
260 	event_disable_readwrite(fd); \
261 	event_cancel_timer((time_act), (context)); \
262     } while (0)
263 
264  /*
265   * Failure enforcement policies.
266   */
267 #define PSC_NAME_ACT_DROP	"drop"
268 #define PSC_NAME_ACT_ENFORCE	"enforce"
269 #define PSC_NAME_ACT_IGNORE	"ignore"
270 #define PSC_NAME_ACT_CONT	"continue"
271 
272 #define PSC_ACT_DROP		1
273 #define PSC_ACT_ENFORCE		2
274 #define PSC_ACT_IGNORE		3
275 
276  /*
277   * Global variables.
278   */
279 extern int psc_check_queue_length;	/* connections being checked */
280 extern int psc_post_queue_length;	/* being sent to real SMTPD */
281 extern DICT_CACHE *psc_cache_map;	/* cache table handle */
282 extern VSTRING *psc_temp;		/* scratchpad */
283 extern char *psc_smtpd_service_name;	/* path to real SMTPD */
284 extern int psc_pregr_action;		/* PSC_ACT_DROP etc. */
285 extern int psc_dnsbl_action;		/* PSC_ACT_DROP etc. */
286 extern int psc_pipel_action;		/* PSC_ACT_DROP etc. */
287 extern int psc_nsmtp_action;		/* PSC_ACT_DROP etc. */
288 extern int psc_barlf_action;		/* PSC_ACT_DROP etc. */
289 extern int psc_min_ttl;			/* Update with new tests! */
290 extern int psc_max_ttl;			/* Update with new tests! */
291 extern STRING_LIST *psc_forbid_cmds;	/* CONNECT GET POST */
292 extern int psc_stress_greet_wait;	/* stressed greet wait */
293 extern int psc_normal_greet_wait;	/* stressed greet wait */
294 extern int psc_stress_cmd_time_limit;	/* stressed command limit */
295 extern int psc_normal_cmd_time_limit;	/* normal command time limit */
296 extern int psc_stress;			/* stress level */
297 extern int psc_lowat_check_queue_length;/* stress low-water mark */
298 extern int psc_hiwat_check_queue_length;/* stress high-water mark */
299 extern DICT *psc_dnsbl_reply;		/* DNSBL name mapper */
300 extern HTABLE *psc_client_concurrency;	/* per-client concurrency */
301 
302 #define PSC_EFF_GREET_WAIT \
303 	(psc_stress ? psc_stress_greet_wait : psc_normal_greet_wait)
304 #define PSC_EFF_CMD_TIME_LIMIT \
305 	(psc_stress ? psc_stress_cmd_time_limit : psc_normal_cmd_time_limit)
306 
307  /*
308   * String plumbing macros.
309   */
310 #define PSC_STRING_UPDATE(str, text) do { \
311 	if (str) myfree(str); \
312 	(str) = ((text) ? mystrdup(text) : 0); \
313     } while (0)
314 
315 #define PSC_STRING_RESET(str) do { \
316 	if (str) { \
317 	    myfree(str); \
318 	    (str) = 0; \
319 	} \
320     } while (0)
321 
322  /*
323   * SLMs.
324   */
325 #define STR(x)  vstring_str(x)
326 #define LEN(x)  VSTRING_LEN(x)
327 
328  /*
329   * postscreen_state.c
330   */
331 #define PSC_CLIENT_ADDR_PORT(state) \
332 	(state)->smtp_client_addr, (state)->smtp_client_port
333 
334 #define PSC_PASS_SESSION_STATE(state, what, bits) do { \
335 	if (msg_verbose) \
336 	    msg_info("PASS %s [%s]:%s", (what), PSC_CLIENT_ADDR_PORT(state)); \
337 	(state)->flags |= (bits); \
338     } while (0)
339 #define PSC_FAIL_SESSION_STATE(state, bits) do { \
340 	if (msg_verbose) \
341 	    msg_info("FAIL [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
342 	(state)->flags |= (bits); \
343     } while (0)
344 #define PSC_SKIP_SESSION_STATE(state, what, bits) do { \
345 	if (msg_verbose) \
346 	    msg_info("SKIP %s [%s]:%s", (what), PSC_CLIENT_ADDR_PORT(state)); \
347 	(state)->flags |= (bits); \
348     } while (0)
349 #define PSC_DROP_SESSION_STATE(state, reply) do { \
350 	if (msg_verbose) \
351 	    msg_info("DROP [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
352 	(state)->flags |= PSC_STATE_FLAG_NOFORWARD; \
353 	(state)->final_reply = (reply); \
354 	psc_conclude(state); \
355     } while (0)
356 #define PSC_ENFORCE_SESSION_STATE(state, reply) do { \
357 	if (msg_verbose) \
358 	    msg_info("ENFORCE [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
359 	(state)->rcpt_reply = (reply); \
360 	(state)->flags |= PSC_STATE_FLAG_NOFORWARD; \
361     } while (0)
362 #define PSC_UNPASS_SESSION_STATE(state, bits) do { \
363 	if (msg_verbose) \
364 	    msg_info("UNPASS [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
365 	(state)->flags &= ~(bits); \
366     } while (0)
367 #define PSC_UNFAIL_SESSION_STATE(state, bits) do { \
368 	if (msg_verbose) \
369 	    msg_info("UNFAIL [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
370 	(state)->flags &= ~(bits); \
371     } while (0)
372 #define PSC_ADD_SERVER_STATE(state, fd) do { \
373 	(state)->smtp_server_fd = (fd); \
374 	psc_post_queue_length++; \
375     } while (0)
376 #define PSC_DEL_CLIENT_STATE(state) do { \
377 	event_server_disconnect((state)->smtp_client_stream); \
378 	(state)->smtp_client_stream = 0; \
379 	psc_check_queue_length--; \
380     } while (0)
381 extern PSC_STATE *psc_new_session_state(VSTREAM *, const char *, const char *);
382 extern void psc_free_session_state(PSC_STATE *);
383 extern const char *psc_print_state_flags(int, const char *);
384 
385  /*
386   * postscreen_dict.c
387   */
388 extern int psc_addr_match_list_match(ADDR_MATCH_LIST *, const char *);
389 extern const char *psc_cache_lookup(DICT_CACHE *, const char *);
390 extern void psc_cache_update(DICT_CACHE *, const char *, const char *);
391 const char *psc_dict_get(DICT *, const char *);
392 const char *psc_maps_find(MAPS *, const char *, int);
393 
394  /*
395   * postscreen_dnsbl.c
396   */
397 extern void psc_dnsbl_init(void);
398 extern int psc_dnsbl_retrieve(const char *, const char **, int);
399 extern int psc_dnsbl_request(const char *, void (*) (int, char *), char *);
400 
401  /*
402   * postscreen_tests.c
403   */
404 #define PSC_INIT_TESTS(dst) do { \
405 	(dst)->flags = 0; \
406 	(dst)->pregr_stamp = PSC_TIME_STAMP_INVALID; \
407 	(dst)->dnsbl_stamp = PSC_TIME_STAMP_INVALID; \
408 	(dst)->pipel_stamp = PSC_TIME_STAMP_INVALID; \
409 	(dst)->barlf_stamp = PSC_TIME_STAMP_INVALID; \
410 	(dst)->penal_stamp = PSC_TIME_STAMP_INVALID; \
411     } while (0)
412 #define PSC_BEGIN_TESTS(state, name) do { \
413 	(state)->test_name = (name); \
414 	GETTIMEOFDAY(&(state)->start_time); \
415     } while (0)
416 extern void psc_new_tests(PSC_STATE *);
417 extern void psc_parse_tests(PSC_STATE *, const char *, time_t);
418 extern char *psc_print_tests(VSTRING *, PSC_STATE *);
419 extern char *psc_print_grey_key(VSTRING *, const char *, const char *,
420 				        const char *, const char *);
421 
422 #define PSC_MIN(x, y) ((x) < (y) ? (x) : (y))
423 #define PSC_MAX(x, y) ((x) > (y) ? (x) : (y))
424 
425  /*
426   * postscreen_early.c
427   */
428 extern void psc_early_tests(PSC_STATE *);
429 extern void psc_early_init(void);
430 
431  /*
432   * postscreen_smtpd.c
433   */
434 extern void psc_smtpd_tests(PSC_STATE *);
435 extern void psc_smtpd_init(void);
436 extern void psc_smtpd_pre_jail_init(void);
437 
438  /*
439   * postscreen_misc.c
440   */
441 extern char *psc_format_delta_time(VSTRING *, struct timeval, DELTA_TIME *);
442 extern void psc_conclude(PSC_STATE *);
443 extern void psc_hangup_event(PSC_STATE *);
444 
445  /*
446   * postscreen_send.c
447   */
448 #define PSC_SEND_REPLY psc_send_reply	/* legacy macro */
449 extern int psc_send_reply(PSC_STATE *, const char *);
450 extern void psc_send_socket(PSC_STATE *);
451 
452  /*
453   * postscreen_starttls.c
454   */
455 extern void psc_starttls_open(PSC_STATE *, EVENT_NOTIFY_FN);
456 
457  /*
458   * postscreen_expand.c
459   */
460 extern VSTRING *psc_expand_filter;
461 extern void psc_expand_init(void);
462 extern const char *psc_expand_lookup(const char *, int, char *);
463 
464  /*
465   * postscreen_access.c
466   */
467 #define PSC_ACL_ACT_WHITELIST	1
468 #define PSC_ACL_ACT_DUNNO	0
469 #define PSC_ACL_ACT_BLACKLIST	(-1)
470 #define PSC_ACL_ACT_ERROR	(-2)
471 
472 extern void psc_acl_pre_jail_init(void);
473 extern ARGV *psc_acl_parse(const char *, const char *);
474 extern int psc_acl_eval(PSC_STATE *, ARGV *, const char *);
475 
476 /* LICENSE
477 /* .ad
478 /* .fi
479 /*	The Secure Mailer license must be distributed with this software.
480 /* AUTHOR(S)
481 /*	Wietse Venema
482 /*	IBM T.J. Watson Research
483 /*	P.O. Box 704
484 /*	Yorktown Heights, NY 10598, USA
485 /*--*/
486