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_auth ,
41 .Nm osmtpd_register_report_reset ,
42 .Nm osmtpd_register_report_begin ,
43 .Nm osmtpd_register_report_mail ,
44 .Nm osmtpd_register_report_rcpt ,
45 .Nm osmtpd_register_report_envelope ,
46 .Nm osmtpd_register_report_data ,
47 .Nm osmtpd_register_report_commit ,
48 .Nm osmtpd_register_report_rollback ,
49 .Nm osmtpd_register_report_client ,
50 .Nm osmtpd_register_report_server ,
51 .Nm osmtpd_register_report_response ,
52 .Nm osmtpd_register_report_timeout ,
53 .Nm osmtpd_local_session ,
54 .Nm osmtpd_local_message ,
56 .Nm osmtpd_filter_proceed ,
57 .Nm osmtpd_filter_reject ,
58 .Nm osmtpd_filter_disconnect ,
59 .Nm osmtpd_filter_rewrite ,
60 .Nm osmtpd_filter_dataline ,
72 .Fo osmtpd_register_filter_connect
73 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *hostname, struct sockaddr_storage *ss)"
76 .Fo osmtpd_register_filter_helo
77 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *helo)"
80 .Fo osmtpd_register_filter_ehlo
81 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *ehlo)"
84 .Fo osmtpd_register_filter_starttls
85 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
88 .Fo osmtpd_register_filter_auth
89 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *auth)"
92 .Fo osmtpd_register_filter_mailfrom
93 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *from)"
96 .Fo osmtpd_register_filter_rcptto
97 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *rcpt)"
100 .Fo osmtpd_register_filter_data
101 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
104 .Fo osmtpd_register_filter_dataline
105 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *line)"
108 .Fo osmtpd_register_filter_rset
109 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
112 .Fo osmtpd_register_filter_quit
113 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
116 .Fo osmtpd_register_filter_noop
117 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
120 .Fo osmtpd_register_filter_help
121 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
124 .Fo osmtpd_register_filter_wiz
125 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
128 .Fo osmtpd_register_filter_commit
129 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
132 .Fo osmtpd_register_report_connect
134 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *rdns, enum osmtpd_status fcrdns, struct sockaddr_storage *src, struct sockaddr_storage *dst)"
137 .Fo osmtpd_register_report_disconnect
139 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
142 .Fo osmtpd_register_report_identify
144 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *identity)"
147 .Fo osmtpd_register_report_tls
149 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *ciphers)"
152 .Fo osmtpd_register_report_auth
154 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *username, enum osmtpd_auth_status status)"
157 .Fo osmtpd_register_report_reset
159 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
162 .Fo osmtpd_register_report_begin
164 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
167 .Fo osmtpd_register_report_mail
169 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *mailfrom, enum osmtpd_status status)"
172 .Fo osmtpd_register_report_rcpt
174 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *rcptto, enum osmtpd_status status)"
177 .Fo osmtpd_register_report_envelope
179 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, uint64_t evpid)"
182 .Fo osmtpd_register_report_data
184 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, enum osmtpd_status status)"
187 .Fo osmtpd_register_report_commit
189 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, size_t msgsz)"
192 .Fo osmtpd_register_report_rollback
194 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
197 .Fo osmtpd_register_report_client
199 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *cmd)"
202 .Fo osmtpd_register_report_server
204 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
207 .Fo osmtpd_register_report_response
209 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
212 .Fo osmtpd_register_report_timeout
214 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
217 .Fo osmtpd_local_session
218 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
219 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
222 .Fo osmtpd_local_message
223 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
224 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
227 .Fn osmtpd_need "int needs"
229 .Fn osmtpd_filter_proceed "struct osmtpd_ctx *ctx"
231 .Fn osmtpd_filter_reject "struct osmtpd_ctx *ctx" "int error" "const char *msg" ...
233 .Fn osmtpd_filter_disconnect "struct osmtpd_ctx *ctx" "const char *msg" ...
235 .Fn osmtpd_filter_rewrite "struct osmtpd_ctx *ctx" "const char *value" ...
237 .Fn osmtpd_filter_dataline "struct osmtpd_ctx *ctx" "const char *line" ...
241 .Fn osmtpd_warn "struct osmtpd_ctx *ctx" "const char *fmt" ...
243 .Fn osmtpd_warnx "struct osmtpd_ctx *ctx" "const char *fmt" ...
245 .Fn osmtpd_err "int eval" "const char *fmt" ...
247 .Fn osmtpd_errx "int eval" "const char *fmt" ...
251 API is an event based interface for writing
254 Filter and report callbacks are registered via the
256 class of functions, followed by
258 A callback should return
260 in the case of success, or
262 in the case of error which leads to disconnect of this session.
265 starts the communication with the server and transforms network queries to
268 .Xr event_dispatch 3 ,
269 which allows filters to be written fully asynchronously.
273 gets at least a pointer of the type
274 .Fa struct osmtpd_ctx .
275 It contains the following elements:
277 .It Fa "enum osmtpd_type type"
278 The type of request being made.
279 The possible values are
280 .Dv OSMTPD_TYPE_FILTER
282 .Dv OSMTPD_TYPE_REPORT .
283 .It Vt "enum osmtpd_phase" Va phase
284 The phase in the transaction which triggered the callback.
285 The following values match their respective
288 .Bl -tag -compact -width OSMTPD_PHASE_LINK_DISCONNECT
289 .It Dv OSMTPD_PHASE_CONNECT
290 .Nm osmtpd_register_filter_connect
291 .It Dv OSMTPD_PHASE_HELO
292 .Nm osmtpd_register_filter_helo
293 .It Dv OSMTPD_PHASE_EHLO
294 .Nm osmtpd_register_filter_ehlo
295 .It Dv OSMTPD_PHASE_STARTTLS
296 .Nm osmtpd_register_filter_starttls
297 .It Dv OSMTPD_PHASE_AUTH
298 .Nm osmtpd_register_filter_auth
299 .It Dv OSMTPD_PHASE_MAIL_FROM
300 .Nm osmtpd_register_filter_mailfrom
301 .It Dv OSMTPD_PHASE_RCPT_TO
302 .Nm osmtpd_register_filter_rcptto
303 .It Dv OSMTPD_PHASE_DATA
304 .Nm osmtpd_register_filter_data
305 .It Dv OSMTPD_PHASE_DATA_LINE
306 .Nm osmtpd_register_filter_dataline
307 .It Dv OSMTPD_PHASE_RSET
308 .Nm osmtpd_register_filter_rset
309 .It Dv OSMTPD_PHASE_QUIT
310 .Nm osmtpd_register_filter_quit
311 .It Dv OSMTPD_PHASE_NOOP
312 .Nm osmtpd_register_filter_noop
313 .It Dv OSMTPD_PHASE_HELP
314 .Nm osmtpd_register_filter_help
315 .It Dv OSMTPD_PHASE_WIZ
316 .Nm osmtpd_register_filter_wiz
317 .It Dv OSMTPD_PHASE_COMMIT
318 .Nm osmtpd_register_filter_commit
319 .It Dv OSMTPD_PHASE_LINK_CONNECT
320 .Nm osmtpd_register_report_connect
321 .It OSMTPD_PHASE_LINK_DISCONNECT
322 .Nm osmtpd_register_report_disconnect
323 .It Dv OSMTPD_PHASE_LINK_IDENTIFY
324 .Nm osmtpd_register_report_identify
325 .It Dv OSMTPD_PHASE_LINK_TLS
326 .Nm osmtpd_register_report_tls
327 .It Dv OSMTPD_PHASE_LINK_AUTH
328 .Nm osmtpd_register_report_auth
329 .It Dv OSMTPD_PHASE_TX_RESET
330 .Nm osmtpd_register_report_reset
331 .It Dv OSMTPD_PHASE_TX_BEGIN
332 .Nm osmtpd_register_report_begin
333 .It Dv OSMTPD_PHASE_TX_MAIL
334 .Nm osmtpd_register_report_mail
335 .It Dv OSMTPD_PHASE_TX_RCPT
336 .Nm osmtpd_register_report_rcpt
337 .It Dv OSMTPD_PHASE_TX_ENVELOPE
338 .Nm osmtpd_register_report_envelope
339 .It Dv OSMTPD_PHASE_TX_DATA
340 .Nm osmtpd_register_report_data
341 .It Dv OSMTPD_PHASE_TX_COMMIT
342 .Nm osmtpd_register_report_commit
343 .It Dv OSMTPD_PHASE_TX_ROLLBACK
344 .Nm osmtpd_register_report_rollback
345 .It Dv OSMTPD_PHASE_PROTOCOL_CLIENT
346 .Nm osmtpd_register_report_client
347 .It Dv OSMTPD_PHASE_PROTOCOL_SERVER
348 .Nm osmtpd_register_report_server
349 .It Dv OSMTPD_PHASE_FILTER_RESPONSE
350 .Nm osmtpd_register_report_response
351 .It Dv OSMTPD_PHASE_TIMEOUT .
352 .Nm osmtpd_register_report_timeout
354 .It Vt int Va version_major
355 The major version number of the protocol.
356 Most filters don't need this information.
357 .It Vt int Va version_minor
358 The minor version number of the protocol.
359 Most filters don't need this information.
360 .It Vt "struct timespec" Va tm
361 The time the event was triggered inside
363 .It Vt int Va incoming
364 Set to 1 if the event was based on an incoming connection, 0 if it's an outgoing
367 .Nm osmtpd_register_filter
368 class of functions is always based on incoming connections.
369 .Nm osmtpd_register_report
370 can be both incoming and outgoing.
371 .It Vt uint64_t Va reqid
372 The request ID of the connection the event was issued on.
373 This value can be useful for logging.
374 Filters in need of filter specific data can use
375 .Nm osmtpd_local_session
378 .It Vt uint64_t Va token
379 The filter specific token.
380 Most filters don't need this information.
381 .It Vt "struct sockaddr_storage" Va src
382 The source address and port of the connection.
383 This needs to be cast to the appropriate sockaddr type based on the
386 It can have the following families:
391 To use this attribute, initialize
394 .Dv OSMTPD_NEED_SRC .
395 If not available the entire attribute is zeroed out.
396 .It Vt "struct sockaddr_storage" Va dst
397 The destination address and port of the connection.
398 This needs to be cast to the appropriate sockaddr type based on the
401 It can have the following families:
406 To use this attribute, initialize
409 .Dv OSMTPD_NEED_DST .
410 If not available the entire attribute is zeroed out.
412 The reverse DNS hostname of the connection.
413 To use this attribute, initialize
416 .Dv OSMTPD_NEED_RDNS .
417 If not available the attribute is set to
419 .It Vt enum osmtpd_status Va fcrdns
420 Whether the reverse DNS hostname is forward confirmed.
421 To use this attribute, initialize
424 .Dv OSMTPD_NEED_FCRDNS .
425 If not available the attribute is set to
426 .Dv OSMTPD_STATUS_TEMPFAIL .
427 .It Vt char Va *identity
428 The identity of the remote host as presented by the HELO or EHLO SMTP command.
429 To use this attribute, initialize
432 .Dv OSMTPD_NEED_IDENTITY .
433 If not available the attribute is set to
435 .It Vt char Va *ciphers
436 The ciphers used during
437 .Po start Pc Ns tls .
438 To use this attribute, initialize
441 .Dv OSMTPD_NEED_CIPHERS .
442 If not available the attribute is set to
444 .It Vt uint32_t Va msgid
445 The message ID of the current message being handled in the SMTP transaction.
446 This value can be useful for logging.
448 needs to be initialized with
449 .Dv OSMTPD_NEED_MSGID .
450 If not available the attribute is set to
452 Filters in need of filter specific data can use
453 .Nm osmtpd_local_message
456 .It Vt char Va *username
457 The username with which the session was successfully authenticated.
459 needs to be initialized with
460 .DV OSMTPD_NEED_USERNAME .
461 If not available or authentication failed is set to
463 .It Vt char Va *mailfrom
464 The envelope MAIL FROM address in the SMTP transaction.
466 needs to be initialized with
467 .Dv OSMTPD_NEED_MAILFROM .
468 If not available the attribute is set to
470 .It Vt char Va **rcptto
471 The envelope RCPT TO address in the SMTP transaction.
473 needs to be initialized with
474 .Dv OSMTPD_NEED_RCPTTO .
475 This attribute is a NULL-terminated array of address strings.
476 If not available the first element in the array is set to
478 .It Vt uint64_t Va evpid
479 The envelope ID we're currently working on.
481 needs to be initialized with
482 .Dv OSMTPD_NEED_EVPID .
483 If not available the attribute is set to
485 .It Vt void Va *local_session
486 Any filter specific data that needs to be stored during the session.
487 This is initialized on
492 .Nm osmtpd_local_session .
493 .It Vt void Va *local_message
494 Any filter specific data that needs to be stored during the message transaction.
495 This is initialized on
500 .Nm osmtpd_local_message .
504 .Nm osmtpd_register_filter
505 class of functions must call one of
506 .Nm osmtpd_filter_proceed ,
507 .Nm osmtpd_filter_rewrite ,
508 .Nm osmtpd_filter_reject
510 .Nm osmtpd_filter_disconnect .
511 This can be done either in the callback function itself, or at a later moment
512 through another callback.
513 Note that the session stalls until the
517 Exceptions to the above reply options are:
519 .Bl -bullet -compact -width Ds
521 .Nm osmtpd_register_filter_connect Ns 's
523 .Nm osmtpd_register_filter
524 functions' callbacks without argument can't use
525 .Nm osmtpd_filter_rewrite .
527 .Nm osmtpd_register_filter_dataline Ns 's
528 callback can only use osmtpd_filter_dataline.
536 can be used as a standin for
544 without printing the program name to stderr.
549 prints the request ID on the logline when
559 API first appeared in
562 .An Martijn van Duren Aq Mt martijn@openbsd.org