xref: /netbsd-src/crypto/external/bsd/libsaslc/dist/man/libsaslc.3 (revision 46f5119e40af2e51998f686b2fdcc76b5488f7f3)
1.\"	$NetBSD: libsaslc.3,v 1.12 2011/03/22 09:42:00 wiz Exp $
2.\"
3.\" Copyright (c) 2010 The NetBSD Foundation, Inc.
4.\" All rights reserved.
5.\"
6.\" This code is derived from software contributed to The NetBSD Foundation
7.\" by Mateusz Kocielski.
8.\"
9.\" Redistribution and use in source and binary forms, with or without
10.\" modification, are permitted provided that the following conditions
11.\" are met:
12.\" 1. Redistributions of source code must retain the above copyright
13.\"    notice, this list of conditions and the following disclaimer.
14.\" 2. Redistributions in binary form must reproduce the above copyright
15.\"    notice, this list of conditions and the following disclaimer in the
16.\"    documentation and/or other materials provided with the distribution.
17.\" 3. All advertising materials mentioning features or use of this software
18.\"    must display the following acknowledgement:
19.\"        This product includes software developed by the NetBSD
20.\"        Foundation, Inc. and its contributors.
21.\" 4. Neither the name of The NetBSD Foundation nor the names of its
22.\"    contributors may be used to endorse or promote products derived
23.\"    from this software without specific prior written permission.
24.\"
25.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28.\" PURPOSE ARE DISCLAIMED.	IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35.\" POSSIBILITY OF SUCH DAMAGE.
36.\"
37.Dd March 22, 2011
38.Dt LIBSASLC 3
39.Os
40.Sh NAME
41.Nm saslc_alloc ,
42.Nm saslc_end ,
43.Nm saslc_init ,
44.Nm saslc_sess_init ,
45.Nm saslc_sess_end ,
46.Nm saslc_sess_getprop ,
47.Nm saslc_sess_setprop ,
48.Nm saslc_sess_cont ,
49.Nm saslc_sess_decode ,
50.Nm saslc_sess_encode ,
51.Nm saslc_sess_getmech ,
52.Nm saslc_sess_strerror ,
53.Nm saslc_strerror
54.Nd Simple Authentication and Security Layer client library
55.Sh LIBRARY
56.Lb libsaslc
57.Sh SYNOPSIS
58.In saslc.h
59.Ft saslc_t *
60.Fn saslc_alloc "void"
61.Ft int
62.Fn saslc_end "saslc_t *ctx"
63.Ft int
64.Fn saslc_init "saslc_t *ctx" "const char *appname" "const char *cfgpath"
65.Ft saslc_sess_t *
66.Fn saslc_sess_init "saslc_t *ctx" "const char *mechs" "const char *secopts"
67.Ft void
68.Fn saslc_sess_end "saslc_sess_t *sess"
69.Ft const char *
70.Fn saslc_sess_getprop "saslc_sess_t *sess" "const char *key"
71.Ft int
72.Fn saslc_sess_setprop "saslc_sess_t *sess" "const char *key" \
73"const char *value"
74.Ft int
75.Fn saslc_sess_cont "saslc_sess_t *sess" "const void *in" "size_t inlen" \
76"void* *out" "size_t *outlen"
77.Ft ssize_t
78.Fn saslc_sess_decode "saslc_sess_t *sess" "const void *in" "size_t inlen" \
79"void* *out" "size_t *outlen"
80.Ft ssize_t
81.Fn saslc_sess_encode "saslc_sess_t *sess" "const void *in" "size_t inlen" \
82"void* *out" "size_t *outlen"
83.Ft const char *
84.Fn saslc_sess_getmech "saslc_sess_t *sess"
85.Ft const char *
86.Fn saslc_sess_strerror "saslc_sess_t *sess"
87.Ft const char *
88.Fn saslc_strerror "saslc_t *ctx"
89.Sh DESCRIPTION
90The
91.Nm libsaslc
92library offers a client interface for the
93Simple Authentication and Security Layer
94.Pq Tn SASL .
95The library is heavily influenced by its use with
96.Xr postfix 1 .
97.Sh FUNCTIONS
98The following functions are available in the library.
99.Bl -tag -width compact
100.It Fn saslc_alloc ""
101The
102.Fn saslc_alloc
103function allocates and returns a new saslc context.
104The context is uninitialized: see
105.Fn saslc_init .
106Returns
107.Dv NULL
108on error.
109.It Fn saslc_end "ctx"
110The
111.Fn saslc_end
112function destroys and deallocate resources used by the context
113.Ar ctx .
114The context shouldn't have any sessions assigned to it.
115Returns 0 on success and \-1 if the context has active sessions and
116cannot be deallocated.
117.It Fn saslc_init "ctx" "appname" "cfgpath"
118The
119.Fn saslc_init
120function initializes the saslc context
121.Ar ctx .
122Based on the application name
123.Ar appname ,
124it also parses the configuration files as indicated by
125.Ar cfgpath ,
126sets up the context and mechanism dictionaries, and creates mechanism
127list for the context.
128If
129.Ar cfgpath
130is
131.Dv NULL ,
132it checks the environment variable
133.Ev SASLC_CONFIG
134for a location and if that is not found it uses the default path
135.Pa /etc/saslc.d .
136Returns 0 on success and \-1 on failure.
137.It Fn saslc_sess_init "ctx" "mechs" "secopts"
138The
139.Fn saslc_sess_init
140function creates new session assigned to the
141.Ar ctx
142context.
143The function chooses the mechanism to use for authentication from the
144.Ar mechs
145list taking into account the requirements from the
146.Ar secopts
147list.
148Both lists may be space or comma delimited.
149The first matching mechanism from the
150.Ar mechs
151list is used.
152See
153.Sx CONFIGURATION
154below for the supported mechanisms.
155The valid security options are
156.Pp
157.Bl -tag -width "nodictionaryxxx" -offset indent -compact
158.It Qo noanonymous Qc
159reject anonymous mechanisms
160.It Qo noplaintext Qc
161reject plaintext mechanisms
162.It Qo nodictionary Qc
163reject mechanisms prone to dictionary attack
164.It Qo noactive Qc
165reject mechanisms prone to active non-dictionary attacks
166.It Qo mutual Qc
167require mutual authentication mechanisms
168.El
169.Pp
170Unknown security options are ignored.
171Returns a session handle or
172.Dv NULL
173on error or no match.
174.It Fn saslc_sess_end "sess"
175The
176.Fn saslc_sess_end
177function ends the sasl session
178.Ar sess .
179It destroys and deallocates all internal resources.
180This does not fail.
181.It Fn saslc_sess_getprop "sess" "key"
182The
183.Fn saslc_sess_getprop
184function gets the property indicated by the
185.Ar key
186from the saslc dictionaries.
187Dictionaries are searched in following order: session
188.Ar sess
189dictionary,
190context dictionary (global configuration), and mechanism dictionary.
191Returns the property value or
192.Dv NULL
193if the property is not found.
194.It Fn saslc_sess_setprop "sess" "key" "value"
195The
196.Fn saslc_sess_setprop
197function sets the property indexed by
198.Ar key
199to the value
200.Ar value
201in the session
202.Ar sess
203dictionary.
204If the property already exists in the session dictionary, then the
205previous value is replaced by the new value.
206If
207.Ar value
208is
209.Dv NULL ,
210then any previous value in the session dictionary is removed.
211Returns 0 on success or \-1 on failure.
212.It Fn saslc_sess_cont "sess" "in" "inlen" "out" "outlen"
213The
214.Fn saslc_sess_cont
215function performs one step of the sasl authentication.
216It reads
217.Ar inlen
218bytes of input data
219.Pq from the server
220from the
221.Ar in
222buffer and stores
223.Ar outlen
224bytes of output data in
225.Ar out
226.Pq for the server .
227The user is responsible for freeing memory allocated for
228.Ar out .
229It returns 0 if the authentication process is completed, 1 if another
230step is required, and \-1 on error.
231Note that the completion of authentication process does not mean the
232client is authenticated; that is determined by the server.
233.It Fn saslc_sess_decode "sess" "in" "inlen" "out" "outlen"
234The
235.Fn saslc_sess_encode
236and
237.Fn saslc_sess_decode
238functions are used to provide the integrity
239.Pq Qq auth-int
240and  confidentiality
241.Pq Qq auth-int
242layers for mechanisms that provide them.
243They encode and, respectively, decode
244.Ar inlen
245bytes of data from the
246.Ar in
247buffer using the method negotiated during authentication.
248On error they return \-1.
249Otherwise, they return the number of bytes consumed from
250.Ar in
251and output
252.Ar outlen
253bytes of data in the
254.Ar out
255buffer.
256The user is responsible for freeing memory allocated for
257.Ar out .
258If
259.Ar outlen
260is 0, more data is needed before anything can be output.
261Unused input data is stored internally for use in subsequent calls.
262.Pp
263When decoding, the internal buffers can only be flushed by providing
264the missing packet data and it is an error to call
265.Fn ssalc_sess_decode
266with
267.Ar inlen
268= 0.
269The first call of
270.Fn saslc_sess_decode
271in a session must begin at the start of a packet.
272Subsequent calls need not be aligned on packet boundaries.
273.It Fn saslc_sess_encode "sess" "in" "inlen" "out" "outlen"
274As described above,
275.Fn saslc_sess_encode
276encodes
277.Ar inlen
278bytes of data from the
279.Ar in
280buffer.
281Note that unlike when decoding,
282the internal buffer may be flushed through the encoder
283by calling
284.Fn saslc_sess_encode
285with
286.Ar inlen
287= 0.
288In this case,
289.Fn saslc_sess_encode
290returns the number of bytes that were flushed from the internal buffer.
291.It Fn saslc_sess_getmech "sess"
292The
293.Fn saslc_sess_getmech
294function returns the name of the mechanism used in the session
295.Fa sess .
296The function does not fail.
297.It Fn saslc_sess_strerror "sess"
298The
299.Fn saslc_sess_strerror
300returns the error message associated with the session
301.Fa sess .
302.It Fn saslc_strerror "ctx"
303The
304.Fn saslc_strerror
305function operates as
306.Fn saslc_sess_strerror ,
307but instead returns the error message string for the last error in the context
308.Fa ctx .
309Neither function will ever return
310.Dv NULL .
311.El
312.Sh CONFIGURATION
313The library uses three types of dictionaries: context (or global),
314session, and mechanism, and they are searched in that order by
315.Fn saslc_getprop
316and the first matching entry is taken.
317The context and mechanism dictionaries are loaded from configuration
318files, while the session dictionary is loaded by the caller via
319.Fn saslc_setprop .
320.Pp
321The configuration file
322.Pa <cfgpath>/<appname>/saslc.conf
323is used for the configuration context.
324The
325.Pa <cfgpath>/<appname>/mech/<mechanism>.conf
326file is used for the mechanism configuration.
327The
328.Pa <cfgpath>
329is
330.Pa /etc/saslc.d
331by default, but this may be overridden by the environment variable
332.Ev SASLC_CONFIG ,
333which in turn may be overridden by
334.Fn saslc_init .
335The
336.Pa <appname>
337is
338.Pa saslc
339by default, but may also be overridden by
340.Fn saslc_init .
341Finally, the
342.Pa <mechanism>
343is the mechanism in use by the session as returned by
344.Fn saslc_sess_getmech .
345Note that this name is case sensitive.
346The currently supported mechanisms are
347.Bl -tag -width DIGEST-MD5 -offset indent
348.It ANONYMOUS
349See RFC 2245 and RFC 4505.
350.It CRAM-MD5
351See RFC 2195.
352.It DIGEST-MD5
353See RFC 2831.
354.It EXTERNAL
355See RFC 2222 section 7.4 and RFC 4422 appendix A.
356.It GSSAPI
357See RFC 2222 section 7.2 and RFC 4752.
358This requires GSS, Heimdal, or MIT Kerberos.
359.It LOGIN
360Non-standard, but common.
361.It PLAIN
362See RFC 2595 and RFC 4616.
363.El
364.Pp
365If any of the mechanism files are missing they are silently ignored,
366unless debugging is enabled.
367.Pp
368The configuration files consists of lines of the form:
369.Bd -literal -offset indent
370\fB#\fP comment line
371.Ao key Ac \~\~ Ao value Ac \~\~ Bo \fB#\fP comment Bc
372.Ed
373.Pp
374The
375.Aq key
376is a string beginning with an alpha character
377.Pq Xr isalpha 3
378followed by any number of alpha numeric
379.Pq Xr isalnum 3
380or underscore
381.Sq _
382characters; this is case sensitive.
383The
384.Aq value
385is a number or a quoted string.
386More than one
387.Aq key
388and
389.Aq value
390pair may occur on a single line, but they may not be broken across
391lines.
392A
393.Sq \fB#\fP
394character
395.Pq outside a quoted string
396indicates that the rest of the line is a comment.
397.Pp
398NOTE: Currently, no escaping is supported in strings, so they may not
399contain quotes.
400Numbers must be between 0 and
401.Dv LLONG_MAX ,
402inclusive.
403Any base supported by
404.Xr strtoll 3
405is allowed.
406.Sh PROPERTIES
407Most of the control of the library
408behavior is done via setting various properties in the context or
409mechanism dictionaries via the configuration files or in the session
410dictionary with
411.Fn saslc_setprop .
412The following properties are currently used, as defined in
413.Pa saslc.h :
414.Bl -tag -width indent
415.It SASLC_PROP_AUTHCID Po Qo AUTHCID Qc Pc
416The authentication name
417.Pq or username
418to authenticate with.
419Used by all mechanisms except EXTERNAL.
420.It SASLC_PROP_AUTHZID Po Qo AUTHZID Qc Pc
421The authorization string to use.
422By default, this string is empty.
423Used by the DIGEST-MD5, EXTERNAL, and PLAIN mechanisms.
424.It SASLC_PROP_BASE64IO Po Qo BASE64IO Qc Pc
425If true ("true", "yes", or nonzero), then input and output strings are
426base64 encoded.
427Any other value is false and the input and output strings are not
428base64 encoded.
429By default, this is assumed true.
430Used by all mechanisms.
431.It SASLC_PROP_CIPHERMASK Po Qo CIPHERMASK Qc Pc
432The mask of ciphers to use with the DIGEST-MD5 mechanism when using
433the
434.Qq auth-conf
435QOP.
436By default all supported ciphers are used, but they may be limited by
437a comma delimited list of cipher names.
438The recognized cipher names for DIGEST-MD5 are:
439.Pp
440.Bl -tag -offset indent -compact
441.It Li "3des"
442Triple-DES Cipher in CBC "two keys" mode with 112 bit key
443.It Li "aes"
444AES Cipher in CBC mode with 128 bit key
445.It Li "des"
446DES Cipher in CBC mode with 56 bit key
447.It Li "rc4"
448RC4 Cipher with 128 bit key
449.It Li "rc4-40"
450RC4 Cipher with 40 bit key
451.It Li "rc4-56"
452RC4 Cipher with 56 bit key
453.El
454.Pp
455The default value is
456.Qq des,3des,rc4,rc4_40,rc4_56,aes .
457.Po
458Note that
459.Qq aes
460is not part of the official standard.
461.Pc
462Used by the DIGEST-MD5 mechanism.
463.It SASLC_PROP_DEBUG Po Qo DEBUG Qc Pc
464If true, then enable debug messages.
465This is implemented as a global variable so it will affect all
466sessions.
467If set via
468.Fn saslc_sess_setprop ,
469it should be set before the first call to
470.Fn saslc_sess_cont .
471.Po
472Also see the environment variable
473.Ev SASLC_ENV_DEBUG
474in the
475.Sx ENVIRONMENT
476section below.
477.Pc
478.It SASLC_PROP_HOSTNAME Po Qo HOSTNAME Qc Pc
479The fully qualified domain name of the server host.
480Used by the DIGEST-MD5 and GSSAPI mechanisms.
481.It SASLC_PROP_MAXBUF Po Qo MAXBUF Qc Pc
482The size of the decode buffer.
483This info is sent to the server so that it doesn't send packets that
484won't fit in the decode buffer when decoded.
485Used by the DIGEST-MD5 and GSSAPI mechanisms.
486.It SASLC_PROP_PASSWD Po Qo PASSWD Qc Pc
487The password to authenticate with.
488Used by the CRAM-MD5, DIGEST-MD5, LOGIN, and PLAIN mechanisms.
489.It SASLC_PROP_QOPMASK Po Qo QOPMASK Qc Pc
490The mask of QOP (quality of protection) to use with the DIGEST-MD5
491and GSSAPI mechanisms.
492By default all supported QOP values are allowed, but they may be
493limited by a comma delimited list of QOP values.
494The recognized QOP values are:
495.Pp
496.Bl -tag -offset indent -compact
497.It Li "auth"
498authentication only
499.It Li "auth-int"
500authentication with integrity
501.It Li "auth-conf"
502authentication with confidentiality
503.El
504.Pp
505so the default value of the mask is
506.Qq auth,auth-int,auth-conf .
507Used by the DIGEST-MD5 and GSSAPI mechanisms.
508.It SASLC_PROP_REALM Po Qo REALM Qc Pc
509A comma delimited list of possible realms to use for authentication.
510The format of each element in the list is
511.Qq Oo Ao hostname Ac : Oc Ns Ao realm Ac .
512The user specified realm is the first realm in the list with a
513matching hostname or, if none is found, the first realm in the list
514with no hostname.
515If the server provides a list of realms, the one matching the user
516specified realm is selected.
517If no match is found or if the user didn't provide a realm, the first
518realm provided by the server is selected.
519If the server doesn't provide any realms, use the user specified realm
520if there is one, or the hostname if not.
521This is useful when the server provides multiple realms or no realm.
522Used by the DIGEST-MD5 mechanism.
523.It SASLC_PROP_SECURITY Po Qo SECURITY Qc Pc
524A comma delimited list of extra security option flags that will be
525.Qo or Qc Ns -ed
526together with those passed to
527.Fn saslc_sess_init .
528Since these flags are used to choose the session mechanism, they are
529only effective if they are in the context configuration file.
530.Po
531See the
532.Sx CONFIGURATION
533section and the
534.Fn saslc_sess_init
535function.
536.Pc
537.It SASLC_PROP_SERVICE Po Qo SERVICE Qc Pc
538The service being used, e.g., smtp, imap, etc.
539Used by the DIGEST-MD5 and GSSAPI mechanisms.
540.It SASLC_PROP_SERVNAME Po Qo SERVNAME Qc Pc
541A comma delimited list of possible service names with elements of the
542form
543.Qq Oo Ao hostname Ac : Oc Ns Ao serv-name Ac
544and with the same rules as for the SASLC_PROP_REALM list.
545This should only be used if the client uses a DNS name for the service
546that is different from the FQDN of the server.
547For example, the service name
548.Em example.com
549might resolve
550.Pq via SRV or MX records
551into a set of other DNS names, one of which,
552.Em mail3.example.com ,
553is the FQDN of the server.
554.Po
555See RFC 2831 section 2.1.2
556.Qq serv-name .
557.Pc
558Used by the DIGEST-MD5 mechanism.
559.El
560.Pp
561The defines in
562.Pa saslc.h
563should be used in code, but their values need to be used in the config
564files.
565.Sh ENVIRONMENT
566The following environment variables
567.Pq defined in Pa saslc.h
568affect the behavior of the library:
569.Bl -tag -width indent
570.It Ev SASLC_ENV_CONFIG Po Qo SASLC_CONFIG Qc Pc
571If the environment variable
572.Ev SASLC_CONFIG
573is set it overrides the default configuration file location of
574.Pa /etc/saslc.d .
575This may be overridden by
576.Fn saslc_init .
577.It Ev SASLC_ENV_DEBUG Po Qo SASLC_DEBUG Qc Pc
578If set, turn on debugging messages.
579This turns on debugging as early as possible and is a global setting.
580.El
581.Sh GSSAPI AND KERBEROS
582The following is a minimal
583.Pq Heimdal
584Kerberos 5 setup for use with an smtp server that has been configured
585to support
586.Em SASL
587with the
588.Em GSSAPI
589mechanism.
590It assumes that Kerberos and the smtp server will both run on
591.Em server.my.domain
592and that the client is on
593.Em client.my.domain .
594It also assumes that the smtp server runs as user
595.Em postfix
596and group
597.Em mail ,
598and that it is not chrooted.
599.Pp
600On
601.Em server.my.domain
602run the following script as
603.Em root
604and then start the Kerberos server
605.Xr kdc 8 .
606You will be prompted for a master password for Kerberos and a password
607for the
608.Em postfix
609principal.
610.Bd -literal -offset indent
611#/bin/sh
612.Pp
613cat <<- EOF >> /etc/krb5.conf
614[libdefaults]
615	default_realm = MY.DOMAIN
616[realms]
617	MY.DOMAIN = {
618		kdc = server.my.domain
619		admin_servers = server.my.domain
620	}
621[domain_realm]
622	.my.domain = MY.DOMAIN
623EOF
624.Pp
625mkdir /var/heimdal
626chown root:wheel /var/heimdal
627chmod 755 /var/heimdal
628.Pp
629kstash
630kadmin -l init --realm-max-ticket-life=unlimited \\
631               --realm-max-renewable-life=unlimited \\
632               MY.DOMAIN
633kadmin -l add  --max-ticket-life="1 day" \\
634               --max-renewable-life="1 week" \\
635               --expiration-time=never \\
636               --pw-expiration-time=never \\
637               --attributes="" \\
638               postfix
639kadmin -l add  --random-key \\
640               --max-ticket-life="1 day" \\
641               --max-renewable-life="1 week" \\
642               --expiration-time=never \\
643               --pw-expiration-time=never \\
644               --attributes="" \\
645               smtp/server.my.domain
646kadmin -l ext -k /etc/krb5.keytab smtp/server.my.domain
647chown root:mail /etc/krb5.keytab
648chmod 640 /etc/krb5.keytab
649.Ed
650.Pp
651Note that the keytab
652.Pa /etc/krb5.keytab
653must be readable by the smtp server or authentication will fail.
654The location of this keytab file may be changed with the environment
655variable
656.Ev KRB5_KTNAME .
657If postfix is the smtp server, note the
658.Em import_environment
659parameter
660.Pq see Xr postconf 5 .
661.Pp
662On
663.Em client.my.domain
664copy the keytab file from
665.Pa server.my.domain:/etc/krb5.keytab
666to
667.Pa /etc/krb5.keytab .
668Setup the
669.Pa /etc/saslc.d
670configuration directory
671.Po see Sx CONFIGURATION
672above
673.Pc .
674Add the line
675.Bd -literal -offset indent
676AUTHCID		"postfix"
677.Ed
678.Pp
679to the file
680.Pa /etc/saslc.d/postfix/mech/GSSAPI.conf
681so that the
682.Em postfix
683principle will be used for authentication.
684Enable
685.Em SASL
686in the smtp client.
687Assuming the smtp client is postfix, you will need to add the
688following to the
689.Pa /etc/postfix/main.cf
690file to do this:
691.Bd -literal -offset indent
692smtp_sasl_auth_enable = yes
693smtp_sasl_type = saslc
694smtp_sasl_mechanism_filter = GSSAPI
695relayhost = [server.my.domain]:submission
696.Ed
697.Pp
698Here we have assumed the
699.Em submission
700port is the port the server is listening to.
701Finally, as
702.Em root ,
703run the command
704.Bd -literal -offset indent
705su -m postfix -c kinit
706.Ed
707.Pp
708to obtain a ticket for the postfix user with the postfix credential
709and you should be good to go!
710.Sh EXAMPLES
711The following code fragments illustrate the possible use of the
712functions described above.
713.Bd -literal
714int
715decode_stream(saslc_sess_t *sess, int fdin, int fdout)
716{
717	uint8_t buf[BUFSIZE];
718	uint8_t *in;
719	void *out;
720	size_t inlen, outlen;
721	ssize_t n, rval;
722.Pp
723	for (;;) {
724		if ((rval = read(fdin, buf, sizeof(buf))) == \-1)
725			return \-1;
726		if (rval == 0)
727			break;
728		in = buf;
729		inlen = rval;
730		while (inlen > 0) {
731			rval = saslc_sess_decode(sess, in, inlen, &out,
732			    &outlen);
733			if (rval == \-1)
734				return \-1;
735			if (outlen > 0) {
736				n = write(fdout, out, outlen);
737				free(out);
738				if (n == \-1)
739					return \-1;
740			}
741			in += rval;
742			inlen -= rval;
743		}
744	}
745	return 0;
746}
747.Pp
748int
749encode_stream(saslc_sess_t *sess, int fdin, int fdout)
750{
751	uint8_t buf[BUFSIZE];
752	uint8_t *in;
753	void *out;
754	size_t inlen, outlen;
755	ssize_t n, rval;
756.Pp
757	for (;;) {
758		if ((rval = read(fdin, buf, sizeof(buf))) == \-1)
759			return \-1;
760		if (rval == 0)
761			break;
762		in = buf;
763		inlen = rval;
764		while (inlen > 0) {
765			rval = saslc_sess_encode(sess, in, inlen, &out,
766			    &outlen);
767			if (rval == \-1)
768				return \-1;
769			if (outlen > 0) {
770				n = write(fdout, out, outlen);
771				free(out);
772				if (n == \-1)
773					return \-1;
774			}
775			in += rval;
776			inlen -= rval;
777		}
778	}
779	/* flush internal encoder buffer */
780	if (saslc_sess_encode(sess, NULL, 0, &out, &outlen) == \-1)
781		return \-1;
782	if (outlen > 0)
783		if (write(fdout, out, outlen) == \-1)
784			return \-1;
785	return 0;
786}
787.Ed
788.Sh COMPATIBILITY
789There exist other SASL client library implementations including Cyrus SASL
790(http://asg.web.cmu.edu/sasl/sasl-library.html) and GNU SASL
791(http://www.gnu.org/software/gsasl/).
792.Sh STANDARDS
793RFC 2195, RFC 2222, RFC 2245, RFC 2595, RFC 2831, RFC 4422, RFC 4505,
794RFC 4616, RFC 4752.
795.Sh CAVEATS
796The API was heavily influenced by its use with
797.Xr postfix 1 .
798.Pp
799Currently the ANONYMOUS, LOGIN, PLAIN, CRAM-MD5, DIGEST-MD5, and
800GSSAPI mechanisms have been tested and shown to work for
801authentication with a
802.Xr postfix 1
803SMTP server using the cyrus-sasl library.
804LOGIN, PLAIN, CRAM-MD5, and DIGEST-MD5 have also been tested and shown
805to work with a
806.Xr postfix 1
807SMTP server using a dovecot backend for authentication.
808The DIGEST-MD5 and GSSAPI specs also provide for integrity and
809confidentiality layers via the
810.Fn saslc_sess_encode
811and
812.Fn saslc_sess_decode
813routines, but these have not yet been tested against any servers.
814