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