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_warn ,
63 .Nm osmtpd_warnx ,
64 .Nm osmtpd_err ,
65 .Nm osmtpd_errx
66 .Nd C filter API for
67 .Xr smtpd 8
68 .Sh SYNOPSIS
69 .Lb libopensmtpd
70 .In opensmtpd.h
71 .Ft void
72 .Fo osmtpd_register_filter_connect
73 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *hostname, struct sockaddr_storage *ss)"
74 .Fc
75 .Ft void
76 .Fo osmtpd_register_filter_helo
77 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *helo)"
78 .Fc
79 .Ft void
80 .Fo osmtpd_register_filter_ehlo
81 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *ehlo)"
82 .Fc
83 .Ft void
84 .Fo osmtpd_register_filter_starttls
85 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
86 .Fc
87 .Ft void
88 .Fo osmtpd_register_filter_auth
89 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *auth)"
90 .Fc
91 .Ft void
92 .Fo osmtpd_register_filter_mailfrom
93 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *from)"
94 .Fc
95 .Ft void
96 .Fo osmtpd_register_filter_rcptto
97 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *rcpt)"
98 .Fc
99 .Ft void
100 .Fo osmtpd_register_filter_data
101 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
102 .Fc
103 .Ft void
104 .Fo osmtpd_register_filter_dataline
105 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *line)"
106 .Fc
107 .Ft void
108 .Fo osmtpd_register_filter_rset
109 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
110 .Fc
111 .Ft void
112 .Fo osmtpd_register_filter_quit
113 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
114 .Fc
115 .Ft void
116 .Fo osmtpd_register_filter_noop
117 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
118 .Fc
119 .Ft void
120 .Fo osmtpd_register_filter_help
121 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
122 .Fc
123 .Ft void
124 .Fo osmtpd_register_filter_wiz
125 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
126 .Fc
127 .Ft void
128 .Fo osmtpd_register_filter_commit
129 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
130 .Fc
131 .Ft void
132 .Fo osmtpd_register_report_connect
133 .Fa "int incoming"
134 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *rdns, enum osmtpd_status fcrdns, struct sockaddr_storage *src, struct sockaddr_storage *dst)"
135 .Fc
136 .Ft void
137 .Fo osmtpd_register_report_disconnect
138 .Fa "int incoming"
139 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
140 .Fc
141 .Ft void
142 .Fo osmtpd_register_report_identify
143 .Fa "int incoming"
144 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *identity)"
145 .Fc
146 .Ft void
147 .Fo osmtpd_register_report_tls
148 .Fa "int incoming"
149 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *ciphers)"
150 .Fc
151 .Ft void
152 .Fo osmtpd_register_report_auth
153 .Fa "int incoming"
154 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *username, enum osmtpd_auth_status status)"
155 .Fc
156 .Ft void
157 .Fo osmtpd_register_report_reset
158 .Fa "int incoming"
159 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
160 .Fc
161 .Ft void
162 .Fo osmtpd_register_report_begin
163 .Fa "int incoming"
164 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
165 .Fc
166 .Ft void
167 .Fo osmtpd_register_report_mail
168 .Fa "int incoming"
169 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *mailfrom, enum osmtpd_status status)"
170 .Fc
171 .Ft void
172 .Fo osmtpd_register_report_rcpt
173 .Fa "int incoming"
174 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *rcptto, enum osmtpd_status status)"
175 .Fc
176 .Ft void
177 .Fo osmtpd_register_report_envelope
178 .Fa "int incoming"
179 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, uint64_t evpid)"
180 .Fc
181 .Ft void
182 .Fo osmtpd_register_report_data
183 .Fa "int incoming"
184 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, enum osmtpd_status status)"
185 .Fc
186 .Ft void
187 .Fo osmtpd_register_report_commit
188 .Fa int incoming
189 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, size_t msgsz)"
190 .Fc
191 .Ft void
192 .Fo osmtpd_register_report_rollback
193 .Fa "int incoming"
194 .Fa "int (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
195 .Fc
196 .Ft void
197 .Fo osmtpd_register_report_client
198 .Fa "int incoming"
199 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *cmd)"
200 .Fc
201 .Ft void
202 .Fo osmtpd_register_report_server
203 .Fa "int incoming"
204 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
205 .Fc
206 .Ft void
207 .Fo osmtpd_register_report_response
208 .Fa "int incoming"
209 .Fa "int (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
210 .Fc
211 .Ft void
212 .Fo osmtpd_register_report_timeout
213 .Fa "int incoming"
214 .Fa "int (*cb)(struct osmtpd_ctx *ctx)"
215 .Fc
216 .Ft void
217 .Fo osmtpd_local_session
218 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
219 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
220 .Fc
221 .Ft void
222 .Fo osmtpd_local_message
223 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
224 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
225 .Fc
226 .Ft void
227 .Fn osmtpd_need "int needs"
228 .Ft void
229 .Fn osmtpd_filter_proceed "struct osmtpd_ctx *ctx"
230 .Ft void
231 .Fn osmtpd_filter_reject "struct osmtpd_ctx *ctx" "int error" "const char *msg" ...
232 .Ft void
233 .Fn osmtpd_filter_disconnect "struct osmtpd_ctx *ctx" "const char *msg" ...
234 .Ft void
235 .Fn osmtpd_filter_rewrite "struct osmtpd_ctx *ctx" "const char *value" ...
236 .Ft void
237 .Fn osmtpd_filter_dataline "struct osmtpd_ctx *ctx" "const char *line" ...
238 .Ft void
239 .Fn osmtpd_run void
240 .Ft void
241 .Fn osmtpd_warn "struct osmtpd_ctx *ctx" "const char *fmt" ...
242 .Ft void
243 .Fn osmtpd_warnx "struct osmtpd_ctx *ctx" "const char *fmt" ...
244 .Ft void
245 .Fn osmtpd_err "int eval" "const char *fmt" ...
246 .Ft void
247 .Fn osmtpd_errx "int eval" "const char *fmt" ...
248 .Sh DESCRIPTION
249 The
250 .Nm osmtpd
251 API is an event based interface for writing
252 .Xr smtpd 8
253 filters.
254 Filter and report callbacks are registered via the
255 .Nm osmtpd_register
256 class of functions, followed by
257 .Nm osmtpd_run .
258 A callback should return
259 .Dv 0
260 in the case of success, or
261 .Dv -1
262 in the case of error which leads to disconnect of this session.
263 .Pp
264 .Nm osmtpd_run
265 starts the communication with the server and transforms network queries to
266 callbacks.
267 Internally it uses
268 .Xr event_dispatch 3 ,
269 which allows filters to be written fully asynchronously.
270 .Pp
271 Each callback
272 .Fa cb
273 gets at least a pointer of the type
274 .Fa struct osmtpd_ctx .
275 It contains the following elements:
276 .Bl -tag -width Ds
277 .It Fa "enum osmtpd_type type"
278 The type of request being made.
279 The possible values are
280 .Dv OSMTPD_TYPE_FILTER
281 and
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
286 .Nm osmtpd_register
287 function:
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
353 .El
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
362 .Xr smtpd 8 .
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
365 connection.
366 The
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
376 and
377 .Va 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
384 .Va ss_family
385 attribute.
386 It can have the following families:
387 .Dv AF_INET ,
388 .Dv AF_INET6
389 and
390 .Dv AF_UNIX .
391 To use this attribute, initialize
392 .Nm osmtpd_need
393 with
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
399 .Va ss_family
400 attribute.
401 It can have the following families:
402 .Dv AF_INET ,
403 .Dv AF_INET6
404 and
405 .Dv AF_UNIX .
406 To use this attribute, initialize
407 .Nm osmtpd_need
408 with
409 .Dv OSMTPD_NEED_DST .
410 If not available the entire attribute is zeroed out.
411 .It Vt char Va *rdns
412 The reverse DNS hostname of the connection.
413 To use this attribute, initialize
414 .Nm osmtpd_need
415 with
416 .Dv OSMTPD_NEED_RDNS .
417 If not available the attribute is set to
418 .Dv NULL .
419 .It Vt enum osmtpd_status Va fcrdns
420 Whether the reverse DNS hostname is forward confirmed.
421 To use this attribute, initialize
422 .Nm osmtpd_need
423 with
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
430 .Nm osmtpd_need
431 with
432 .Dv OSMTPD_NEED_IDENTITY .
433 If not available the attribute is set to
434 .Dv NULL .
435 .It Vt char Va *ciphers
436 The ciphers used during
437 .Po start Pc Ns tls .
438 To use this attribute, initialize
439 .Nm osmtpd_need
440 with
441 .Dv OSMTPD_NEED_CIPHERS .
442 If not available the attribute is set to
443 .Dv NULL .
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.
447 .Nm osmtpd_need
448 needs to be initialized with
449 .Dv OSMTPD_NEED_MSGID .
450 If not available the attribute is set to
451 .Dv 0 .
452 Filters in need of filter specific data can use
453 .Nm osmtpd_local_message
454 and
455 .Va local_message .
456 .It Vt char Va *username
457 The username with which the session was successfully authenticated.
458 .Nm osmtpd_need
459 needs to be initialized with
460 .DV OSMTPD_NEED_USERNAME .
461 If not available or authentication failed is set to
462 .Dv NULL .
463 .It Vt char Va *mailfrom
464 The envelope MAIL FROM address in the SMTP transaction.
465 .Nm osmtpd_need
466 needs to be initialized with
467 .Dv OSMTPD_NEED_MAILFROM .
468 If not available the attribute is set to
469 .Dv NULL .
470 .It Vt char Va **rcptto
471 The envelope RCPT TO address in the SMTP transaction.
472 .Nm osmtpd_need
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
477 .Dv NULL .
478 .It Vt uint64_t Va evpid
479 The envelope ID we're currently working on.
480 .Nm osmtpd_need
481 needs to be initialized with
482 .Dv OSMTPD_NEED_EVPID .
483 If not available the attribute is set to
484 .Dv 0 .
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
488 .Fa ctx
489 creation by calling
490 .Fa oncreate
491 argument from
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
496 .Fa ctx
497 creation by calling
498 .Fa oncreate
499 argument from
500 .Nm osmtpd_local_message .
501 .El
502 .Pp
503 The
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
509 and
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
514 .Nm osmtpd_filter
515 has been called.
516 .Pp
517 Exceptions to the above reply options are:
518 .Pp
519 .Bl -bullet -compact -width Ds
520 .It
521 .Nm osmtpd_register_filter_connect Ns 's
522 and
523 .Nm osmtpd_register_filter
524 functions' callbacks without argument can't use
525 .Nm osmtpd_filter_rewrite .
526 .It
527 .Nm osmtpd_register_filter_dataline Ns 's
528 callback can only use osmtpd_filter_dataline.
529 .El
530 .Pp
531 .Nm osmtpd_warn ,
532 .Nm osmtpd_warnx ,
533 .Nm osmtpd_err
534 and
535 .Nm osmtpd_errx
536 can be used as a standin for
537 .Xr warn 3
539 .Xr warnx 3
541 .Xr err 3
542 and
543 .Xr errx 3
544 without printing the program name to stderr.
545 Additionally,
546 .Nm osmtpd_warn
547 and
548 .Nm osmtpd_warnx
549 prints the request ID on the logline when
550 .Fa ctx
551 is not
552 .Dv NULL .
553 .Sh SEE ALSO
554 .Xr event_init 3 ,
555 .Xr smtpd.conf 5
556 .Sh HISTORY
557 The
558 .Nm osmtpd_run
559 API first appeared in
560 .Ox 6.6 .
561 .Sh AUTHORS
562 .An Martijn van Duren Aq Mt martijn@openbsd.org