1 /*        $NetBSD: xsasl_server.c,v 1.3 2025/02/25 19:15:53 christos Exp $      */
2 
3 /*++
4 /* NAME
5 /*        xsasl-server 3
6 /* SUMMARY
7 /*        Postfix SASL server plug-in interface
8 /* SYNOPSIS
9 /*        #include <xsasl.h>
10 /*
11 /*        XSASL_SERVER_IMPL *xsasl_server_init(server_type, path_info)
12 /*        const char *server_type;
13 /*        const char *path_info;
14 /*
15 /*        void      xsasl_server_done(implementation)
16 /*        XSASL_SERVER_IMPL *implementation;
17 /*
18 /*        ARGV      *xsasl_server_types()
19 /*
20 /* .in +4
21 /*        typedef struct XSASL_SERVER_CREATE_ARGS {
22 /*                  VSTREAM *stream;
23 /*                  const char *server_addr;
24 /*                  const char *client_addr;
25 /*                  const char *service;
26 /*                  const char *user_realm;
27 /*                  const char *security_options;
28 /*                  int     tls_flag;
29 /*        } XSASL_SERVER_CREATE_ARGS;
30 /* .in -4
31 /*
32 /*        XSASL_SERVER *xsasl_server_create(implementation, args)
33 /*        XSASL_SERVER_IMPL *implementation;
34 /*        XSASL_SERVER_CREATE_ARGS *args;
35 /*
36 /*        XSASL_SERVER *XSASL_SERVER_CREATE(implementation, args,
37 /*                                                stream = stream_value,
38 /*                                                ...,
39 /*                                                tls_flag = tls_flag_value)
40 /*        XSASL_SERVER_IMPL *implementation;
41 /*        XSASL_SERVER_CREATE_ARGS *args;
42 /*
43 /*        void xsasl_server_free(server)
44 /*        XSASL_SERVER *server;
45 /*
46 /*        int       xsasl_server_first(server, auth_method, init_resp, server_reply)
47 /*        XSASL_SERVER *server;
48 /*        const char *auth_method;
49 /*        const char *init_resp;
50 /*        VSTRING *server_reply;
51 /*
52 /*        int       xsasl_server_next(server, client_request, server_reply)
53 /*        XSASL_SERVER *server;
54 /*        const char *client_request;
55 /*        VSTRING *server_reply;
56 /*
57 /*        const char *xsasl_server_get_mechanism_list(server)
58 /*        XSASL_SERVER *server;
59 /*
60 /*        const char *xsasl_server_get_username(server)
61 /*        XSASL_SERVER *server;
62 /* DESCRIPTION
63 /*        The XSASL_SERVER abstraction implements a generic interface
64 /*        to one or more SASL authentication implementations.
65 /*
66 /*        xsasl_server_init() is called once during process initialization.
67 /*        It selects a SASL implementation by name, specifies the
68 /*        location of a configuration file or rendez-vous point, and
69 /*        returns an implementation handle that can be used to generate
70 /*        SASL server instances. This function is typically used to
71 /*        initialize the underlying implementation.
72 /*
73 /*        xsasl_server_done() disposes of an implementation handle,
74 /*        and allows the underlying implementation to release resources.
75 /*
76 /*        xsasl_server_types() lists the available implementation types.
77 /*        The result should be destroyed by the caller.
78 /*
79 /*        xsasl_server_create() is called at the start of an SMTP
80 /*        session. It generates a Postfix SASL plug-in server instance
81 /*        for the specified service and authentication realm, and
82 /*        with the specified security properties. Specify a null
83 /*        pointer when no realm should be used. The stream handle is
84 /*        stored so that encryption can be turned on after successful
85 /*        negotiations. Specify zero-length strings when a client or
86 /*        server address is unavailable.
87 /*
88 /*        XSASL_SERVER_CREATE() is a macro that provides an interface
89 /*        with named parameters.  Named parameters do not have to
90 /*        appear in a fixed order. The parameter names correspond to
91 /*        the member names of the XSASL_SERVER_CREATE_ARGS structure.
92 /*
93 /*        xsasl_server_free() is called at the end of an SMTP session.
94 /*        It destroys a SASL server instance, and disables further
95 /*        read/write operations if encryption was turned on.
96 /*
97 /*        xsasl_server_first() produces the server response for the
98 /*        client AUTH command. The client input are an authentication
99 /*        method, and an optional initial response or null pointer.
100 /*        The initial response and server non-error replies are BASE64
101 /*        encoded.  Server error replies are 7-bit ASCII text without
102 /*        control characters, without BASE64 encoding, and without
103 /*        SMTP reply code or enhanced status code.
104 /*
105 /*        The result is one of the following:
106 /* .IP XSASL_AUTH_MORE
107 /*        More client input is needed. The server reply specifies
108 /*        what.
109 /* .IP XSASL_AUTH_DONE
110 /*        Authentication completed successfully.
111 /* .IP XSASL_AUTH_FORM
112 /*        The client input is incorrectly formatted. The server error
113 /*        reply explains why.
114 /* .IP XSASL_AUTH_FAIL
115 /*        Authentication failed. The server error reply explains why.
116 /* .PP
117 /*        xsasl_server_next() supports the subsequent stages of the
118 /*        client-server AUTH protocol. Both the client input and
119 /*        server non-error responses are BASE64 encoded.  See
120 /*        xsasl_server_first() for other details.
121 /*
122 /*        xsasl_server_get_mechanism_list() returns the authentication
123 /*        mechanisms that match the security properties, as a white-space
124 /*        separated list. This is meant to be used in the SMTP EHLO
125 /*        reply.
126 /*
127 /*        xsasl_server_get_username() returns the stored username
128 /*        after successful authentication. The username may be null
129 /*        after authentication failure, depending on the kind of
130 /*        failure and on authentication backend implementation
131 /*        details. A non-null result is converted to printable text.
132 /*
133 /*        Arguments:
134 /* .IP addr_family
135 /*        The network address family: AF_INET6 or AF_INET.
136 /* .IP auth_method
137 /*        AUTH command authentication method.
138 /* .IP client_addr
139 /*        IPv4 or IPv6 address (no surrounding [] or ipv6: prefix),
140 /*        or zero-length string if unavailable.
141 /* .IP client_port
142 /*        TCP port or zero-length string if unavailable.
143 /* .IP init_resp
144 /*        AUTH command initial response or null pointer.
145 /* .IP implementation
146 /*        Implementation handle that was obtained with xsasl_server_init().
147 /* .IP path_info
148 /*        The value of the smtpd_sasl_path parameter or equivalent.
149 /*        This specifies the implementation-dependent location of a
150 /*        configuration file, rendez-vous point, etc., and is passed
151 /*        unchanged to the plug-in.
152 /* .IP security_options
153 /*        The value of the smtpd_security_options parameter or
154 /*        equivalent. This is passed unchanged to the plug-in.
155 /* .IP server
156 /*        SASL plug-in server handle.
157 /* .IP server_addr
158 /*        IPv4 or IPv6 address (no surrounding [] or ipv6: prefix),
159 /*        or zero-length string if unavailable.
160 /* .IP server_port
161 /*        TCP port or zero-length string if unavailable.
162 /* .IP server_reply
163 /*        BASE64 encoded server non-error reply (without SMTP reply
164 /*        code or enhanced status code), or ASCII error description.
165 /* .IP server_type
166 /*        The name of a Postfix SASL server plug_in implementation.
167 /* .IP server_types
168 /*        Null-terminated array of strings with SASL server plug-in
169 /*        implementation names.
170 /* .IP service
171 /*        The service that is implemented by the local server, typically
172 /*        "smtp" or "lmtp".
173 /* .IP stream
174 /*        The connection between client and server.  When SASL
175 /*        encryption is negotiated, the plug-in will transparently
176 /*        intercept the socket read/write operations.
177 /* .IP user_realm
178 /*        Authentication domain or null pointer.
179 /* SECURITY
180 /* .ad
181 /* .fi
182 /*        The caller does not sanitize client input. It is the
183 /*        responsibility of the underlying SASL server implementation
184 /*        to produce 7-bit ASCII without control characters as server
185 /*        non-error and error replies, and as the result from
186 /*        xsasl_server_method() and xsasl_server_username().
187 /* DIAGNOSTICS
188 /*        In case of failure, xsasl_server_init(), xsasl_server_create(),
189 /*        xsasl_server_get_mechanism_list() and xsasl_server_get_username()
190 /*        log a warning and return a null pointer.
191 /*
192 /*        Functions that normally return XSASL_AUTH_OK will log a warning
193 /*        and return an appropriate result value.
194 /*
195 /*        Fatal errors: out of memory.
196 /*
197 /*        Panic: interface violations.
198 /* SEE ALSO
199 /*        cyrus_security(3) Cyrus SASL security features
200 /* LICENSE
201 /* .ad
202 /* .fi
203 /*        The Secure Mailer license must be distributed with this
204 /*        software.
205 /* AUTHOR(S)
206 /*        Wietse Venema
207 /*        IBM T.J. Watson Research
208 /*        P.O. Box 704
209 /*        Yorktown Heights, NY 10598, USA
210 /*
211 /*        Wietse Venema
212 /*        Google, Inc.
213 /*        111 8th Avenue
214 /*        New York, NY 10011, USA
215 /*
216 /*        Wietse Venema
217 /*        porcupine.org
218 /*        Amawalk, NY 10501, USA
219 /*--*/
220 
221 /* System library. */
222 
223 #include <sys_defs.h>
224 #include <string.h>
225 
226 /* Utility library. */
227 
228 #include <msg.h>
229 #include <mymalloc.h>
230 
231 /* SASL implementations. */
232 
233 #include <xsasl.h>
234 #include <xsasl_cyrus.h>
235 #include <xsasl_dovecot.h>
236 
237  /*
238   * Lookup table for available SASL server implementations.
239   */
240 typedef struct {
241     char   *server_type;
242     struct XSASL_SERVER_IMPL *(*server_init) (const char *, const char *);
243 } XSASL_SERVER_IMPL_INFO;
244 
245 static const XSASL_SERVER_IMPL_INFO server_impl_info[] = {
246 #ifdef XSASL_TYPE_CYRUS
247     {XSASL_TYPE_CYRUS, xsasl_cyrus_server_init},
248 #endif
249 #ifdef XSASL_TYPE_DOVECOT
250     {XSASL_TYPE_DOVECOT, xsasl_dovecot_server_init},
251 #endif
252     {0, 0}
253 };
254 
255 /* xsasl_server_init - look up server implementation by name */
256 
xsasl_server_init(const char * server_type,const char * path_info)257 XSASL_SERVER_IMPL *xsasl_server_init(const char *server_type,
258                                                      const char *path_info)
259 {
260     const XSASL_SERVER_IMPL_INFO *xp;
261 
262     for (xp = server_impl_info; xp->server_type; xp++)
263           if (strcmp(server_type, xp->server_type) == 0)
264               return (xp->server_init(server_type, path_info));
265     msg_warn("unsupported SASL server implementation: %s", server_type);
266     return (0);
267 }
268 
269 /* xsasl_server_types - report available implementation types */
270 
xsasl_server_types(void)271 ARGV   *xsasl_server_types(void)
272 {
273     const XSASL_SERVER_IMPL_INFO *xp;
274     ARGV   *argv = argv_alloc(1);
275 
276     for (xp = server_impl_info; xp->server_type; xp++)
277           argv_add(argv, xp->server_type, ARGV_END);
278     return (argv);
279 }
280