3 .\" Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
5 .\" Permission to use, copy, modify, and distribute this software for any
6 .\" purpose with or without fee is hereby granted, provided that the above
7 .\" copyright notice and this permission notice appear in all copies.
9 .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 .Nm osmtpd_register_filter_connect ,
22 .Nm osmtpd_register_filter_helo ,
23 .Nm osmtpd_register_filter_ehlo ,
24 .Nm osmtpd_register_filter_starttls ,
25 .Nm osmtpd_register_filter_auth ,
26 .Nm osmtpd_register_filter_mailfrom ,
27 .Nm osmtpd_register_filter_rcptto ,
28 .Nm osmtpd_register_filter_data ,
29 .Nm osmtpd_register_filter_dataline ,
30 .Nm osmtpd_register_filter_rset ,
31 .Nm osmtpd_register_filter_quit ,
32 .Nm osmtpd_register_filter_noop ,
33 .Nm osmtpd_register_filter_help ,
34 .Nm osmtpd_register_filter_wiz ,
35 .Nm osmtpd_register_filter_commit ,
36 .Nm osmtpd_register_report_connect ,
37 .Nm osmtpd_register_report_disconnect ,
38 .Nm osmtpd_register_report_identify ,
39 .Nm osmtpd_register_report_tls ,
40 .Nm osmtpd_register_report_begin ,
41 .Nm osmtpd_register_report_mail ,
42 .Nm osmtpd_register_report_rcpt ,
43 .Nm osmtpd_register_report_envelope ,
44 .Nm osmtpd_register_report_data ,
45 .Nm osmtpd_register_report_commit ,
46 .Nm osmtpd_register_report_rollback ,
47 .Nm osmtpd_register_report_client ,
48 .Nm osmtpd_register_report_server ,
49 .Nm osmtpd_register_report_response ,
50 .Nm osmtpd_register_report_timeout ,
51 .Nm osmtpd_local_session ,
52 .Nm osmtpd_local_message ,
54 .Nm osmtpd_filter_proceed ,
55 .Nm osmtpd_filter_reject ,
56 .Nm osmtpd_filter_disconnect ,
57 .Nm osmtpd_filter_rewrite ,
58 .Nm osmtpd_filter_dataline ,
67 .Fo osmtpd_register_filter_connect
68 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *hostname, struct sockaddr_storage *ss)"
71 .Fo osmtpd_register_filter_helo
72 .Fa "void (cb*)(struct osmtpd_ctx *ctx, const char *helo)"
75 .Fo osmtpd_register_filter_ehlo
76 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *ehlo)"
79 .Fo osmtpd_register_filter_starttls
80 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
83 .Fo osmtpd_register_filter_auth
84 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *auth)"
87 .Fo osmtpd_register_filter_mailfrom
88 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *from)"
91 .Fo osmtpd_register_filter_rcptto
92 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *rcpt)"
95 .Fo osmtpd_register_filter_data
96 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
99 .Fo osmtpd_register_filter_dataline
100 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *line)"
103 .Fo osmtpd_register_filter_rset
104 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
107 .Fo osmtpd_register_filter_quit
108 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
111 .Fo osmtpd_register_filter_noop
112 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
115 .Fo osmtpd_register_filter_help
116 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
119 .Fo osmtpd_register_filter_wiz
120 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
123 .Fo osmtpd_register_filter_commit
124 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
127 .Fo osmtpd_register_report_connect
129 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *rdns, enum osmtpd_status fcrdns, struct sockaddr_storage *src, struct sockaddr_storage *dst)"
132 .Fo osmtpd_register_report_disconnect
134 .Fa "void (*ctx)(struct osmtpd_ctx *ctx)"
137 .Fo osmtpd_register_report_identify
139 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *identity)"
142 .Fo osmtpd_register_report_tls
144 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *ciphers)"
147 .Fo osmtpd_register_report_begin
149 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
152 .Fo osmtpd_register_report_mail
154 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *mailfrom, enum osmtpd_status status)"
157 .Fo osmtpd_register_report_rcpt
159 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *rcptto, enum osmtpd_status status)"
162 .Fo osmtpd_register_report_envelope
164 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, uint64_t evpid)"
167 .Fo osmtpd_register_report_data
169 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, enum osmtpd_status status)"
172 .Fo osmtpd_register_report_commit
174 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, size_t msgsz)"
177 .Fo osmtpd_register_report_rollback
179 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
182 .Fo osmtpd_register_report_client
184 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *cmd)"
187 .Fo osmtpd_register_report_server
189 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
192 .Fo osmtpd_register_report_response
194 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
197 .Fo osmtpd_register_report_timeout
199 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
202 .Fo osmtpd_local_session
203 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
204 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
207 .Fo osmtpd_local_message
208 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
209 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
212 .Fn osmtpd_need "int needs"
214 .Fn osmtpd_filter_proceed "struct osmtpd_ctx *ctx"
216 .Fn osmtpd_filter_reject "struct osmtpd_ctx *ctx" "int error" "const char *msg" ...
218 .Fn osmtpd_filter_disconnect "struct osmtpd_ctx *ctx" "const char *msg" ...
220 .Fn osmtpd_filter_rewrite "struct osmtpd_ctx *ctx" "const char *value" ...
222 .Fn osmtpd_filter_dataline "struct osmtpd_ctx *ctx" "const char *line" ...
226 .Fn osmtpd_err "int eval" "const char *fmt" ...
228 .Fn osmtpd_errx "int eval" "const char *fmt" ...
232 API is an event based interface for writing
235 Filter and report callbacks are registered via the
237 class of functions, followed by
241 starts the communication with the server and transforms network queries to
244 .Xr event_dispatch 3 ,
245 which allows filters to be written fully asynchronously.
249 gets at least a pointer of the type
250 .Fa struct osmtpd_ctx .
251 It contains the following elements:
253 .It Fa "enum osmtpd_type type"
254 The type of request being made.
255 The possible values are
256 .Dv OSMTPD_TYPE_FILTER
258 .Dv OSMTPD_TYPE_REPORT .
259 .It Vt "enum osmtpd_phase" Va phase
260 The phase in the transaction which triggered the callback.
261 The following values match their respective
264 .Bl -tag -compact -width OSMTPD_PHASE_LINK_DISCONNECT
265 .It Dv OSMTPD_PHASE_CONNECT
266 .Nm osmtpd_register_filter_connect
267 .It Dv OSMTPD_PHASE_HELO
268 .Nm osmtpd_register_filter_helo
269 .It Dv OSMTPD_PHASE_EHLO
270 .Nm osmtpd_register_filter_ehlo
271 .It Dv OSMTPD_PHASE_STARTTLS
272 .Nm osmtpd_register_filter_starttls
273 .It Dv OSMTPD_PHASE_AUTH
274 .Nm osmtpd_register_filter_auth
275 .It Dv OSMTPD_PHASE_MAIL_FROM
276 .Nm osmtpd_register_filter_mailfrom
277 .It Dv OSMTPD_PHASE_RCPT_TO
278 .Nm osmtpd_register_filter_rcptto
279 .It Dv OSMTPD_PHASE_DATA
280 .Nm osmtpd_register_filter_data
281 .It Dv OSMTPD_PHASE_DATA_LINE
282 .Nm osmtpd_register_filter_dataline
283 .It Dv OSMTPD_PHASE_RSET
284 .Nm osmtpd_register_filter_rset
285 .It Dv OSMTPD_PHASE_QUIT
286 .Nm osmtpd_register_filter_quit
287 .It Dv OSMTPD_PHASE_NOOP
288 .Nm osmtpd_register_filter_noop
289 .It Dv OSMTPD_PHASE_HELP
290 .Nm osmtpd_register_filter_help
291 .It Dv OSMTPD_PHASE_WIZ
292 .Nm osmtpd_register_filter_wiz
293 .It Dv OSMTPD_PHASE_COMMIT
294 .Nm osmtpd_register_filter_commit
295 .It Dv OSMTPD_PHASE_LINK_CONNECT
296 .Nm osmtpd_register_report_connect
297 .It OSMTPD_PHASE_LINK_DISCONNECT
298 .Nm osmtpd_register_report_disconnect
299 .It Dv OSMTPD_PHASE_LINK_IDENTIFY
300 .Nm osmtpd_register_report_identify
301 .It Dv OSMTPD_PHASE_LINK_TLS
302 .Nm osmtpd_register_report_tls
303 .It Dv OSMTPD_PHASE_TX_BEGIN
304 .Nm osmtpd_register_report_begin
305 .It Dv OSMTPD_PHASE_TX_MAIL
306 .Nm osmtpd_register_report_mail
307 .It Dv OSMTPD_PHASE_TX_RCPT
308 .Nm osmtpd_register_report_rcpt
309 .It Dv OSMTPD_PHASE_TX_ENVELOPE
310 .Nm osmtpd_register_report_envelope
311 .It Dv OSMTPD_PHASE_TX_DATA
312 .Nm osmtpd_register_report_data
313 .It Dv OSMTPD_PHASE_TX_COMMIT
314 .Nm osmtpd_register_report_commit
315 .It Dv OSMTPD_PHASE_TX_ROLLBACK
316 .Nm osmtpd_register_report_rollback
317 .It Dv OSMTPD_PHASE_PROTOCOL_CLIENT
318 .Nm osmtpd_register_report_client
319 .It Dv OSMTPD_PHASE_PROTOCOL_SERVER
320 .Nm osmtpd_register_report_server
321 .It Dv OSMTPD_PHASE_FILTER_RESPONSE
322 .Nm osmtpd_register_report_response
323 .It Dv OSMTPD_PHASE_TIMEOUT .
324 .Nm osmtpd_register_report_timeout
326 .It Vt int Va version_major
327 The major version number of the protocol.
328 Most filters don't need this information.
329 .It Vt int Va version_minor
330 The minor version number of the protocol.
331 Most filters don't need this information.
332 .It Vt "struct timespec" Va tm
333 The time the event was triggered inside
335 .It Vt int Va incoming
336 Set to 1 if the event was based on an incoming connection, 2 if it's an outgoing
339 .Nm osmtpd_register_filter
340 class of functions is always based on incoming connections.
341 .Nm osmtpd_register_report
342 can be both incoming and outgoing.
343 .It Vt uint64_t Va reqid
344 The request ID of the connection the event was issued on.
345 This value can be useful for logging.
346 Filters in need of filter specific data can use
347 .Nm osmtpd_local_session
350 .It Vt uint64_t Va token
351 The filter specific token.
352 Most filters don't need this information.
353 .It Vt "struct sockaddr_storage" Va src
354 The source address and port of the connection.
355 This needs to be cast to the appropriate sockaddr type based on the
358 It can have the following families:
363 To use this attribute, initialize
366 .Dv OSMTPD_NEED_SRC .
367 If not available the entire attribute is zeroed out.
368 .It Vt "struct sockaddr_storage" Va dst
369 The destination address and port of the connection.
370 This needs to be cast to the appropriate sockaddr type based on the
373 It can have the following families:
378 To use this attribute, initialize
381 .Dv OSMTPD_NEED_DST .
382 If not available the entire attribute is zeroed out.
384 The reverse DNS hostname of the connection.
385 To use this attribute, initialize
388 .Dv OSMTPD_NEED_RDNS .
389 If not available the attribute is set to
391 .It Vt enum osmtpd_status Va fcrdns
392 Whether the reverse DNS hostname is forward confirmed.
393 To use this attribute, initialize
396 .Dv OSMTPD_NEED_FCRDNS .
397 If not available the attribute is set to
398 .Dv OSMTPD_STATUS_TEMPFAIL .
399 .It Vt char Va *identity
400 The identity of the remote host as presented by the HELO or EHLO SMTP command.
401 To use this attribute, initialize
404 .Dv OSMTPD_NEED_IDENTITY .
405 If not available the attribute is set to
407 .It Vt char Va *ciphers
408 The ciphers used during
409 .Po start Pc Ns tls .
410 To use this attribute, initialize
413 .Dv OSMTPD_NEED_CIPHERS .
414 If not available the attribute is set to
416 .It Vt uint32_t Va msgid
417 The message ID of the current message being handled in the SMTP transaction.
418 This value can be useful for logging.
420 needs to be initialized with
421 .Dv OSMTPD_NEED_MSGID .
422 If not available the attribute is set to
424 Filters in need of filter specific data can use
425 .Nm osmtpd_local_message
428 .It Vt char Va *mailfrom
429 The envelope MAIL FROM address in the SMTP transaction.
431 needs to be initialized with
432 .Dv OSMTPD_NEED_MAILFROM .
433 If not available the attribute is set to
435 .It Vt char Va **rcptto
436 The envelope RCPT TO address in the SMTP transaction.
438 needs to be initialized with
439 .Dv OSMTPD_NEED_RCPTTO .
440 This attribute is a NULL-terminated array of address strings.
441 If not available the first element in the array is set to
443 .It Vt uint64_t Va evpid
444 The envelope ID we're currently working on.
446 needs to be initialized with
447 .Dv OSMTPD_NEED_EVPID .
448 If not available the attribute is set to
450 .It Vt void Va *local_session
451 Any filter specific data that needs to be stored during the session.
452 This is initialized on
457 .Nm osmtpd_local_session .
458 .It Vt void Va *local_message
459 Any filter specific data that needs to be stored during the message transaction.
460 This is initialized on
465 .Nm osmtpd_local_message .
469 .Nm osmtpd_register_filter
470 class of functions must call one of
471 .Nm osmtpd_filter_proceed ,
472 .Nm osmtpd_filter_rewrite ,
473 .Nm osmtpd_filter_reject
475 .Nm osmtpd_filter_disconnect .
476 This can be done either in the callback function itself, or at a later moment
477 through another callback.
478 Note that the session stalls until the
482 Exceptions to the above reply options are:
484 .Bl -bullet -compact -width Ds
486 .Nm osmtpd_register_filter_connect Ns 's
488 .Nm osmtpd_register_filter
489 functions' callbacks without argument can't use
490 .Nm osmtpd_filter_rewrite .
492 .Nm osmtpd_register_filter_dataline Ns 's
493 callback can only use osmtpd_filter_dataline.
499 can be used as a standin for
503 without printing the program name to stderr.
510 API first appeared in
513 .An Martijn van Duren Aq Mt martijn@openbsd.org