Blob


1 .\" $OpenBSD$
2 .\"
3 .\" Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
4 .\"
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.
8 .\"
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.
16 .\"
17 .Dd $Mdocdate$
18 .Dt OSMTPD_RUN 3
19 .Os
20 .Sh NAME
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 ,
55 .Nm osmtpd_need ,
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 ,
61 .Nm osmtpd_run ,
62 .Nm osmtpd_err ,
63 .Nm osmtpd_errx
64 .Nm osmtpd_warn ,
65 .Nm osmtpd_warnx ,
66 .Nm osmtpd_info ,
67 .Nm osmtpd_debug ,
68 .Nd C filter API for
69 .Xr smtpd 8
70 .Sh SYNOPSIS
71 .Lb libopensmtpd
72 .In opensmtpd.h
73 .Ft void
74 .Fo osmtpd_register_filter_connect
75 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *hostname, struct sockaddr_storage *ss)"
76 .Fc
77 .Ft void
78 .Fo osmtpd_register_filter_helo
79 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *helo)"
80 .Fc
81 .Ft void
82 .Fo osmtpd_register_filter_ehlo
83 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *ehlo)"
84 .Fc
85 .Ft void
86 .Fo osmtpd_register_filter_starttls
87 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
88 .Fc
89 .Ft void
90 .Fo osmtpd_register_filter_auth
91 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *auth)"
92 .Fc
93 .Ft void
94 .Fo osmtpd_register_filter_mailfrom
95 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *from)"
96 .Fc
97 .Ft void
98 .Fo osmtpd_register_filter_rcptto
99 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *rcpt)"
100 .Fc
101 .Ft void
102 .Fo osmtpd_register_filter_data
103 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
104 .Fc
105 .Ft void
106 .Fo osmtpd_register_filter_dataline
107 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *line)"
108 .Fc
109 .Ft void
110 .Fo osmtpd_register_filter_rset
111 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
112 .Fc
113 .Ft void
114 .Fo osmtpd_register_filter_quit
115 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
116 .Fc
117 .Ft void
118 .Fo osmtpd_register_filter_noop
119 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
120 .Fc
121 .Ft void
122 .Fo osmtpd_register_filter_help
123 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
124 .Fc
125 .Ft void
126 .Fo osmtpd_register_filter_wiz
127 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
128 .Fc
129 .Ft void
130 .Fo osmtpd_register_filter_commit
131 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
132 .Fc
133 .Ft void
134 .Fo osmtpd_register_report_connect
135 .Fa "int incoming"
136 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *rdns, enum osmtpd_status fcrdns, struct sockaddr_storage *src, struct sockaddr_storage *dst)"
137 .Fc
138 .Ft void
139 .Fo osmtpd_register_report_disconnect
140 .Fa "int incoming"
141 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
142 .Fc
143 .Ft void
144 .Fo osmtpd_register_report_identify
145 .Fa "int incoming"
146 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *identity)"
147 .Fc
148 .Ft void
149 .Fo osmtpd_register_report_tls
150 .Fa "int incoming"
151 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *ciphers)"
152 .Fc
153 .Ft void
154 .Fo osmtpd_register_report_auth
155 .Fa "int incoming"
156 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *username, enum osmtpd_auth_status status)"
157 .Fc
158 .Ft void
159 .Fo osmtpd_register_report_reset
160 .Fa "int incoming"
161 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
162 .Fc
163 .Ft void
164 .Fo osmtpd_register_report_begin
165 .Fa "int incoming"
166 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
167 .Fc
168 .Ft void
169 .Fo osmtpd_register_report_mail
170 .Fa "int incoming"
171 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *mailfrom, enum osmtpd_status status)"
172 .Fc
173 .Ft void
174 .Fo osmtpd_register_report_rcpt
175 .Fa "int incoming"
176 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *rcptto, enum osmtpd_status status)"
177 .Fc
178 .Ft void
179 .Fo osmtpd_register_report_envelope
180 .Fa "int incoming"
181 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, uint64_t evpid)"
182 .Fc
183 .Ft void
184 .Fo osmtpd_register_report_data
185 .Fa "int incoming"
186 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, enum osmtpd_status status)"
187 .Fc
188 .Ft void
189 .Fo osmtpd_register_report_commit
190 .Fa int incoming
191 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, size_t msgsz)"
192 .Fc
193 .Ft void
194 .Fo osmtpd_register_report_rollback
195 .Fa "int incoming"
196 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
197 .Fc
198 .Ft void
199 .Fo osmtpd_register_report_client
200 .Fa "int incoming"
201 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *cmd)"
202 .Fc
203 .Ft void
204 .Fo osmtpd_register_report_server
205 .Fa "int incoming"
206 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
207 .Fc
208 .Ft void
209 .Fo osmtpd_register_report_response
210 .Fa "int incoming"
211 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
212 .Fc
213 .Ft void
214 .Fo osmtpd_register_report_timeout
215 .Fa "int incoming"
216 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
217 .Fc
218 .Ft void
219 .Fo osmtpd_local_session
220 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
221 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
222 .Fc
223 .Ft void
224 .Fo osmtpd_local_message
225 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
226 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
227 .Fc
228 .Ft void
229 .Fn osmtpd_need "int needs"
230 .Ft void
231 .Fn osmtpd_filter_proceed "struct osmtpd_ctx *ctx"
232 .Ft void
233 .Fn osmtpd_filter_reject "struct osmtpd_ctx *ctx" "int error" "const char *msg" ...
234 .Ft void
235 .Fn osmtpd_filter_disconnect "struct osmtpd_ctx *ctx" "const char *msg" ...
236 .Ft void
237 .Fn osmtpd_filter_rewrite "struct osmtpd_ctx *ctx" "const char *value" ...
238 .Ft void
239 .Fn osmtpd_filter_dataline "struct osmtpd_ctx *ctx" "const char *line" ...
240 .Ft void
241 .Fn osmtpd_run void
242 .Ft void
243 .Fn osmtpd_err "int eval" "const char *fmt" ...
244 .Ft void
245 .Fn osmtpd_errx "int eval" "const char *fmt" ...
246 .Ft void
247 .Fn osmtpd_warn "struct osmtpd_ctx *ctx" "const char *fmt" ...
248 .Ft void
249 .Fn osmtpd_warnx "struct osmtpd_ctx *ctx" "const char *fmt" ...
250 .Ft void
251 .Fn osmtpd_info "struct osmtpd_ctx *ctx" "const char *fmt" ...
252 .Ft void
253 .Fn osmtpd_debug "struct osmtpd_ctx *ctx" "const char *fmt" ...
254 .Sh DESCRIPTION
255 The
256 .Nm osmtpd
257 API is an event based interface for writing
258 .Xr smtpd 8
259 filters.
260 Filter and report callbacks are registered via the
261 .Nm osmtpd_register
262 class of functions, followed by
263 .Nm osmtpd_run .
264 A callback should return
265 .Dv 0
266 in the case of success, or
267 .Dv -1
268 in the case of error which leads to disconnect of this session.
269 .Pp
270 .Nm osmtpd_run
271 starts the communication with the server and transforms network queries to
272 callbacks.
273 Internally it uses
274 .Xr event_dispatch 3 ,
275 which allows filters to be written fully asynchronously.
276 .Pp
277 Each callback
278 .Fa cb
279 gets at least a pointer of the type
280 .Fa struct osmtpd_ctx .
281 It contains the following elements:
282 .Bl -tag -width Ds
283 .It Fa "enum osmtpd_type type"
284 The type of request being made.
285 The possible values are
286 .Dv OSMTPD_TYPE_FILTER
287 and
288 .Dv OSMTPD_TYPE_REPORT .
289 .It Vt "enum osmtpd_phase" Va phase
290 The phase in the transaction which triggered the callback.
291 The following values match their respective
292 .Nm osmtpd_register
293 function:
294 .Bl -tag -compact -width OSMTPD_PHASE_LINK_DISCONNECT
295 .It Dv OSMTPD_PHASE_CONNECT
296 .Nm osmtpd_register_filter_connect
297 .It Dv OSMTPD_PHASE_HELO
298 .Nm osmtpd_register_filter_helo
299 .It Dv OSMTPD_PHASE_EHLO
300 .Nm osmtpd_register_filter_ehlo
301 .It Dv OSMTPD_PHASE_STARTTLS
302 .Nm osmtpd_register_filter_starttls
303 .It Dv OSMTPD_PHASE_AUTH
304 .Nm osmtpd_register_filter_auth
305 .It Dv OSMTPD_PHASE_MAIL_FROM
306 .Nm osmtpd_register_filter_mailfrom
307 .It Dv OSMTPD_PHASE_RCPT_TO
308 .Nm osmtpd_register_filter_rcptto
309 .It Dv OSMTPD_PHASE_DATA
310 .Nm osmtpd_register_filter_data
311 .It Dv OSMTPD_PHASE_DATA_LINE
312 .Nm osmtpd_register_filter_dataline
313 .It Dv OSMTPD_PHASE_RSET
314 .Nm osmtpd_register_filter_rset
315 .It Dv OSMTPD_PHASE_QUIT
316 .Nm osmtpd_register_filter_quit
317 .It Dv OSMTPD_PHASE_NOOP
318 .Nm osmtpd_register_filter_noop
319 .It Dv OSMTPD_PHASE_HELP
320 .Nm osmtpd_register_filter_help
321 .It Dv OSMTPD_PHASE_WIZ
322 .Nm osmtpd_register_filter_wiz
323 .It Dv OSMTPD_PHASE_COMMIT
324 .Nm osmtpd_register_filter_commit
325 .It Dv OSMTPD_PHASE_LINK_CONNECT
326 .Nm osmtpd_register_report_connect
327 .It OSMTPD_PHASE_LINK_DISCONNECT
328 .Nm osmtpd_register_report_disconnect
329 .It Dv OSMTPD_PHASE_LINK_IDENTIFY
330 .Nm osmtpd_register_report_identify
331 .It Dv OSMTPD_PHASE_LINK_TLS
332 .Nm osmtpd_register_report_tls
333 .It Dv OSMTPD_PHASE_LINK_AUTH
334 .Nm osmtpd_register_report_auth
335 .It Dv OSMTPD_PHASE_TX_RESET
336 .Nm osmtpd_register_report_reset
337 .It Dv OSMTPD_PHASE_TX_BEGIN
338 .Nm osmtpd_register_report_begin
339 .It Dv OSMTPD_PHASE_TX_MAIL
340 .Nm osmtpd_register_report_mail
341 .It Dv OSMTPD_PHASE_TX_RCPT
342 .Nm osmtpd_register_report_rcpt
343 .It Dv OSMTPD_PHASE_TX_ENVELOPE
344 .Nm osmtpd_register_report_envelope
345 .It Dv OSMTPD_PHASE_TX_DATA
346 .Nm osmtpd_register_report_data
347 .It Dv OSMTPD_PHASE_TX_COMMIT
348 .Nm osmtpd_register_report_commit
349 .It Dv OSMTPD_PHASE_TX_ROLLBACK
350 .Nm osmtpd_register_report_rollback
351 .It Dv OSMTPD_PHASE_PROTOCOL_CLIENT
352 .Nm osmtpd_register_report_client
353 .It Dv OSMTPD_PHASE_PROTOCOL_SERVER
354 .Nm osmtpd_register_report_server
355 .It Dv OSMTPD_PHASE_FILTER_RESPONSE
356 .Nm osmtpd_register_report_response
357 .It Dv OSMTPD_PHASE_TIMEOUT .
358 .Nm osmtpd_register_report_timeout
359 .El
360 .It Vt int Va version_major
361 The major version number of the protocol.
362 Most filters don't need this information.
363 .It Vt int Va version_minor
364 The minor version number of the protocol.
365 Most filters don't need this information.
366 .It Vt "struct timespec" Va tm
367 The time the event was triggered inside
368 .Xr smtpd 8 .
369 .It Vt int Va incoming
370 Set to 1 if the event was based on an incoming connection, 0 if it's an outgoing
371 connection.
372 The
373 .Nm osmtpd_register_filter
374 class of functions is always based on incoming connections.
375 .Nm osmtpd_register_report
376 can be both incoming and outgoing.
377 .It Vt uint64_t Va reqid
378 The request ID of the connection the event was issued on.
379 This value can be useful for logging.
380 Filters in need of filter specific data can use
381 .Nm osmtpd_local_session
382 and
383 .Va local_session .
384 .It Vt uint64_t Va token
385 The filter specific token.
386 Most filters don't need this information.
387 .It Vt "struct sockaddr_storage" Va src
388 The source address and port of the connection.
389 This needs to be cast to the appropriate sockaddr type based on the
390 .Va ss_family
391 attribute.
392 It can have the following families:
393 .Dv AF_INET ,
394 .Dv AF_INET6
395 and
396 .Dv AF_UNIX .
397 To use this attribute, initialize
398 .Nm osmtpd_need
399 with
400 .Dv OSMTPD_NEED_SRC .
401 If not available the entire attribute is zeroed out.
402 .It Vt "struct sockaddr_storage" Va dst
403 The destination address and port of the connection.
404 This needs to be cast to the appropriate sockaddr type based on the
405 .Va ss_family
406 attribute.
407 It can have the following families:
408 .Dv AF_INET ,
409 .Dv AF_INET6
410 and
411 .Dv AF_UNIX .
412 To use this attribute, initialize
413 .Nm osmtpd_need
414 with
415 .Dv OSMTPD_NEED_DST .
416 If not available the entire attribute is zeroed out.
417 .It Vt char Va *rdns
418 The reverse DNS hostname of the connection.
419 To use this attribute, initialize
420 .Nm osmtpd_need
421 with
422 .Dv OSMTPD_NEED_RDNS .
423 If not available the attribute is set to
424 .Dv NULL .
425 .It Vt enum osmtpd_status Va fcrdns
426 Whether the reverse DNS hostname is forward confirmed.
427 To use this attribute, initialize
428 .Nm osmtpd_need
429 with
430 .Dv OSMTPD_NEED_FCRDNS .
431 If not available the attribute is set to
432 .Dv OSMTPD_STATUS_TEMPFAIL .
433 .It Vt char Va *identity
434 The identity of the remote host as presented by the HELO or EHLO SMTP command.
435 To use this attribute, initialize
436 .Nm osmtpd_need
437 with
438 .Dv OSMTPD_NEED_IDENTITY .
439 If not available the attribute is set to
440 .Dv NULL .
441 .It Vt char Va *ciphers
442 The ciphers used during
443 .Po start Pc Ns tls .
444 To use this attribute, initialize
445 .Nm osmtpd_need
446 with
447 .Dv OSMTPD_NEED_CIPHERS .
448 If not available the attribute is set to
449 .Dv NULL .
450 .It Vt uint32_t Va msgid
451 The message ID of the current message being handled in the SMTP transaction.
452 This value can be useful for logging.
453 .Nm osmtpd_need
454 needs to be initialized with
455 .Dv OSMTPD_NEED_MSGID .
456 If not available the attribute is set to
457 .Dv 0 .
458 Filters in need of filter specific data can use
459 .Nm osmtpd_local_message
460 and
461 .Va local_message .
462 .It Vt char Va *username
463 The username with which the session was successfully authenticated.
464 .Nm osmtpd_need
465 needs to be initialized with
466 .DV OSMTPD_NEED_USERNAME .
467 If not available or authentication failed is set to
468 .Dv NULL .
469 .It Vt char Va *mailfrom
470 The envelope MAIL FROM address in the SMTP transaction.
471 .Nm osmtpd_need
472 needs to be initialized with
473 .Dv OSMTPD_NEED_MAILFROM .
474 If not available the attribute is set to
475 .Dv NULL .
476 .It Vt char Va **rcptto
477 The envelope RCPT TO address in the SMTP transaction.
478 .Nm osmtpd_need
479 needs to be initialized with
480 .Dv OSMTPD_NEED_RCPTTO .
481 This attribute is a NULL-terminated array of address strings.
482 If not available the first element in the array is set to
483 .Dv NULL .
484 .It Vt uint64_t Va evpid
485 The envelope ID we're currently working on.
486 .Nm osmtpd_need
487 needs to be initialized with
488 .Dv OSMTPD_NEED_EVPID .
489 If not available the attribute is set to
490 .Dv 0 .
491 .It Vt void Va *local_session
492 Any filter specific data that needs to be stored during the session.
493 This is initialized on
494 .Fa ctx
495 creation by calling
496 .Fa oncreate
497 argument from
498 .Nm osmtpd_local_session .
499 .It Vt void Va *local_message
500 Any filter specific data that needs to be stored during the message transaction.
501 This is initialized on
502 .Fa ctx
503 creation by calling
504 .Fa oncreate
505 argument from
506 .Nm osmtpd_local_message .
507 .El
508 .Pp
509 The
510 .Nm osmtpd_register_filter
511 class of functions must call one of
512 .Nm osmtpd_filter_proceed ,
513 .Nm osmtpd_filter_rewrite ,
514 .Nm osmtpd_filter_reject
515 and
516 .Nm osmtpd_filter_disconnect .
517 This can be done either in the callback function itself, or at a later moment
518 through another callback.
519 Note that the session stalls until the
520 .Nm osmtpd_filter
521 has been called.
522 .Pp
523 Exceptions to the above reply options are:
524 .Pp
525 .Bl -bullet -compact -width Ds
526 .It
527 .Nm osmtpd_register_filter_connect Ns 's
528 and
529 .Nm osmtpd_register_filter
530 functions' callbacks without argument can't use
531 .Nm osmtpd_filter_rewrite .
532 .It
533 .Nm osmtpd_register_filter_dataline Ns 's
534 callback can only use osmtpd_filter_dataline.
535 .El
536 .Pp
537 .Nm osmtpd_err ,
538 .Nm osmtpd_errx ,
539 .Nm osmtpd_warn ,
540 .Nm osmtpd_warnx ,
541 .Nm osmtpd_info ,
542 and
543 .Nm osmtpd_debug
544 are used for logging to
545 .Xr smtpd 8
546 at
547 .Xr syslog 3
548 levels
549 .Dv LOG_CRIT ,
550 .Dv LOG_WARNING ,
551 .Dv LOG_INFO,
552 and
553 .Dv LOG_DEBUG
554 respectively.
555 Additionally,
556 .Nm osmtpd_warn ,
557 .Nm osmtpd_warnx ,
558 .Nm osmtpd_info ,
559 and
560 .Nm osmtpd_debug
561 prints the request ID on the logline when
562 .Fa ctx
563 is not
564 .Dv NULL .
565 .Sh SEE ALSO
566 .Xr event_init 3 ,
567 .Xr smtpd.conf 5
568 .Sh HISTORY
569 The
570 .Nm osmtpd_run
571 API first appeared in
572 .Ox 6.6 .
573 .Sh AUTHORS
574 .An Martijn van Duren Aq Mt martijn@openbsd.org