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_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 ,
53 .Nm osmtpd_need ,
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 ,
59 .Nm osmtpd_run ,
60 .Nm osmtpd_err ,
61 .Nm osmtpd_errx
62 .Nd C filter API for
63 .Xr smtpd 8
64 .Sh SYNOPSIS
65 .In opensmtpd.h
66 .Ft void
67 .Fo osmtpd_register_filter_connect
68 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *hostname, struct sockaddr_storage *ss)"
69 .Fc
70 .Ft void
71 .Fo osmtpd_register_filter_helo
72 .Fa "void (cb*)(struct osmtpd_ctx *ctx, const char *helo)"
73 .Fc
74 .Ft void
75 .Fo osmtpd_register_filter_ehlo
76 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *ehlo)"
77 .Fc
78 .Ft void
79 .Fo osmtpd_register_filter_starttls
80 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
81 .Fc
82 .Ft void
83 .Fo osmtpd_register_filter_auth
84 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *auth)"
85 .Fc
86 .Ft void
87 .Fo osmtpd_register_filter_mailfrom
88 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *from)"
89 .Fc
90 .Ft void
91 .Fo osmtpd_register_filter_rcptto
92 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *rcpt)"
93 .Fc
94 .Ft void
95 .Fo osmtpd_register_filter_data
96 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
97 .Fc
98 .Ft void
99 .Fo osmtpd_register_filter_dataline
100 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *line)"
101 .Fc
102 .Ft void
103 .Fo osmtpd_register_filter_rset
104 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
105 .Fc
106 .Ft void
107 .Fo osmtpd_register_filter_quit
108 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
109 .Fc
110 .Ft void
111 .Fo osmtpd_register_filter_noop
112 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
113 .Fc
114 .Ft void
115 .Fo osmtpd_register_filter_help
116 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
117 .Fc
118 .Ft void
119 .Fo osmtpd_register_filter_wiz
120 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
121 .Fc
122 .Ft void
123 .Fo osmtpd_register_filter_commit
124 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
125 .Fc
126 .Ft void
127 .Fo osmtpd_register_report_connect
128 .Fa "int incoming"
129 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *rdns, enum osmtpd_status fcrdns, struct sockaddr_storage *src, struct sockaddr_storage *dst)"
130 .Fc
131 .Ft void
132 .Fo osmtpd_register_report_disconnect
133 .Fa "int incoming"
134 .Fa "void (*ctx)(struct osmtpd_ctx *ctx)"
135 .Fc
136 .Ft void
137 .Fo osmtpd_register_report_identify
138 .Fa "int incoming"
139 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *identity)"
140 .Fc
141 .Ft void
142 .Fo osmtpd_register_report_tls
143 .Fa "int incoming"
144 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *ciphers)"
145 .Fc
146 .Ft void
147 .Fo osmtpd_register_report_begin
148 .Fa "int incoming"
149 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
150 .Fc
151 .Ft void
152 .Fo osmtpd_register_report_mail
153 .Fa "int incoming"
154 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *mailfrom, enum osmtpd_status status)"
155 .Fc
156 .Ft void
157 .Fo osmtpd_register_report_rcpt
158 .Fa "int incoming"
159 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, const char *rcptto, enum osmtpd_status status)"
160 .Fc
161 .Ft void
162 .Fo osmtpd_register_report_envelope
163 .Fa "int incoming"
164 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, uint64_t evpid)"
165 .Fc
166 .Ft void
167 .Fo osmtpd_register_report_data
168 .Fa "int incoming"
169 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, enum osmtpd_status status)"
170 .Fc
171 .Ft void
172 .Fo osmtpd_register_report_commit
173 .Fa int incoming
174 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid, size_t msgsz)"
175 .Fc
176 .Ft void
177 .Fo osmtpd_register_report_rollback
178 .Fa "int incoming"
179 .Fa "void (*cb)(struct osmtpd_ctx *ctx, uint32_t msgid)"
180 .Fc
181 .Ft void
182 .Fo osmtpd_register_report_client
183 .Fa "int incoming"
184 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *cmd)"
185 .Fc
186 .Ft void
187 .Fo osmtpd_register_report_server
188 .Fa "int incoming"
189 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
190 .Fc
191 .Ft void
192 .Fo osmtpd_register_report_response
193 .Fa "int incoming"
194 .Fa "void (*cb)(struct osmtpd_ctx *ctx, const char *resp)"
195 .Fc
196 .Ft void
197 .Fo osmtpd_register_report_timeout
198 .Fa "int incoming"
199 .Fa "void (*cb)(struct osmtpd_ctx *ctx)"
200 .Fc
201 .Ft void
202 .Fo osmtpd_local_session
203 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
204 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
205 .Fc
206 .Ft void
207 .Fo osmtpd_local_message
208 .Fa "void *(*oncreate)(struct osmtpd_ctx *ctx)"
209 .Fa "void (*ondelete)(struct osmtpd_ctx *ctx, void *data)"
210 .Fc
211 .Ft void
212 .Fn osmtpd_need "int needs"
213 .Ft void
214 .Fn osmtpd_filter_proceed "struct osmtpd_ctx *ctx"
215 .Ft void
216 .Fn osmtpd_filter_reject "struct osmtpd_ctx *ctx" "int error" "const char *msg" ...
217 .Ft void
218 .Fn osmtpd_filter_disconnect "struct osmtpd_ctx *ctx" "const char *msg" ...
219 .Ft void
220 .Fn osmtpd_filter_rewrite "struct osmtpd_ctx *ctx" "const char *value" ...
221 .Ft void
222 .Fn osmtpd_filter_dataline "struct osmtpd_ctx *ctx" "const char *line" ...
223 .Ft void
224 .Fn osmtpd_run void
225 .Ft void
226 .Fn osmtpd_err "int eval" "const char *fmt" ...
227 .Ft void
228 .Fn osmtpd_errx "int eval" "const char *fmt" ...
229 .Sh DESCRIPTION
230 The
231 .Nm osmtpd
232 API is an event based interface for writing
233 .Xr smtpd 8
234 filters.
235 Filter and report callbacks are registered via the
236 .Nm osmtpd_register
237 class of functions, followed by
238 .Nm osmtpd_run .
239 .Pp
240 .Nm osmtpd_run
241 starts the communication with the server and transforms network queries to
242 callbacks.
243 Internally it uses
244 .Xr event_dispatch 3 ,
245 which allows filters to be written fully asynchronously.
246 .Pp
247 Each callback
248 .Fa cb
249 gets at least a pointer of the type
250 .Fa struct osmtpd_ctx .
251 It contains the following elements:
252 .Bl -tag -width Ds
253 .It Fa "enum osmtpd_type type"
254 The type of request being made.
255 The possible values are
256 .Dv OSMTPD_TYPE_FILTER
257 and
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
262 .Nm osmtpd_register
263 function:
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
325 .El
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
334 .Xr smtpd 8 .
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
337 connection.
338 The
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
348 and
349 .Va 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
356 .Va ss_family
357 attribute.
358 It can have the following families:
359 .Dv AF_INET ,
360 .Dv AF_INET6
361 and
362 .Dv AF_UNIX .
363 To use this attribute, initialize
364 .Nm osmtpd_need
365 with
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
371 .Va ss_family
372 attribute.
373 It can have the following families:
374 .Dv AF_INET ,
375 .Dv AF_INET6
376 and
377 .Dv AF_UNIX .
378 To use this attribute, initialize
379 .Nm osmtpd_need
380 with
381 .Dv OSMTPD_NEED_DST .
382 If not available the entire attribute is zeroed out.
383 .It Vt char Va *rdns
384 The reverse DNS hostname of the connection.
385 To use this attribute, initialize
386 .Nm osmtpd_need
387 with
388 .Dv OSMTPD_NEED_RDNS .
389 If not available the attribute is set to
390 .Dv NULL .
391 .It Vt enum osmtpd_status Va fcrdns
392 Whether the reverse DNS hostname is forward confirmed.
393 To use this attribute, initialize
394 .Nm osmtpd_need
395 with
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
402 .Nm osmtpd_need
403 with
404 .Dv OSMTPD_NEED_IDENTITY .
405 If not available the attribute is set to
406 .Dv NULL .
407 .It Vt char Va *ciphers
408 The ciphers used during
409 .Po start Pc Ns tls .
410 To use this attribute, initialize
411 .Nm osmtpd_need
412 with
413 .Dv OSMTPD_NEED_CIPHERS .
414 If not available the attribute is set to
415 .Dv NULL .
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.
419 .Nm osmtpd_need
420 needs to be initialized with
421 .Dv OSMTPD_NEED_MSGID .
422 If not available the attribute is set to
423 .Dv 0 .
424 Filters in need of filter specific data can use
425 .Nm osmtpd_local_message
426 and
427 .Va local_message .
428 .It Vt char Va *mailfrom
429 The envelope MAIL FROM address in the SMTP transaction.
430 .Nm osmtpd_need
431 needs to be initialized with
432 .Dv OSMTPD_NEED_MAILFROM .
433 If not available the attribute is set to
434 .Dv NULL .
435 .It Vt char Va **rcptto
436 The envelope RCPT TO address in the SMTP transaction.
437 .Nm osmtpd_need
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
442 .Dv NULL .
443 .It Vt uint64_t Va evpid
444 The envelope ID we're currently working on.
445 .Nm osmtpd_need
446 needs to be initialized with
447 .Dv OSMTPD_NEED_EVPID .
448 If not available the attribute is set to
449 .Dv 0 .
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
453 .Fa ctx
454 creation by calling
455 .Fa oncreate
456 argument from
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
461 .Fa ctx
462 creation by calling
463 .Fa oncreate
464 argument from
465 .Nm osmtpd_local_message .
466 .El
467 .Pp
468 The
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
474 and
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
479 .Nm osmtpd_filter
480 has been called.
481 .Pp
482 Exceptions to the above reply options are:
483 .Pp
484 .Bl -bullet -compact -width Ds
485 .It
486 .Nm osmtpd_register_filter_connect Ns 's
487 and
488 .Nm osmtpd_register_filter
489 functions' callbacks without argument can't use
490 .Nm osmtpd_filter_rewrite .
491 .It
492 .Nm osmtpd_register_filter_dataline Ns 's
493 callback can only use osmtpd_filter_dataline.
494 .El
495 .Pp
496 .Nm osmtpd_err
497 and
498 .Nm osmtpd_errx
499 can be used as a standin for
500 .Xr err 3
501 and
502 .Xr errx 3
503 without printing the program name to stderr.
504 .Sh SEE ALSO
505 .Xr event_init 3 ,
506 .Xr smtpd.conf 5
507 .Sh HISTORY
508 The
509 .Nm osmtpd_run
510 API first appeared in
511 .Ox 6.6 .
512 .Sh AUTHORS
513 .An Martijn van Duren Aq Mt martijn@openbsd.org