xref: /netbsd-src/external/ibm-public/postfix/dist/src/xsasl/xsasl_saslc_client.c (revision b757af438b42b93f8c6571f026d8b8ef3eaf5fc9)
1 /*	$NetBSD: xsasl_saslc_client.c,v 1.1 2011/02/12 19:07:09 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	xsasl_saslc_client 3
6 /* SUMMARY
7 /*	saslc SASL client-side plug-in
8 /* SYNOPSIS
9 /*	#include <xsasl_saslc_client.h>
10 /*
11 /*	XSASL_CLIENT_IMPL *xsasl_saslc_client_init(client_type, path_info)
12 /*	const char *client_type;
13 /* DESCRIPTION
14 /*	This module implements the saslc SASL client-side authentication
15 /*	plug-in.
16 /*
17 /*	xsasl_saslc_client_init() initializes the saslc SASL library and
18 /*	returns an implementation handle that can be used to generate
19 /*	SASL client instances.
20 /*
21 /*	Arguments:
22 /* .IP client_type
23 /*	The plug-in SASL client type (saslc). This argument is
24 /*	ignored, but it could be used when one implementation
25 /*	provides multiple variants.
26 /* .IP path_info
27 /*	Implementation-specific information to specify the location
28 /*	of a configuration file, rendez-vous point, etc. This
29 /*	information is ignored by the saslc SASL client plug-in.
30 /* DIAGNOSTICS
31 /*	Fatal: out of memory.
32 /*
33 /*	Panic: interface violation.
34 /*
35 /*	Other: the routines log a warning and return an error result
36 /*	as specified in xsasl_client(3).
37 /* SEE ALSO
38 /*	xsasl_client(3) Client API
39 /* LICENSE
40 /* .ad
41 /* .fi
42 /*	The Secure Mailer license must be distributed with this software.
43 /* AUTHOR(S)
44 /*	Original author:
45 /*	Till Franke
46 /*	SuSE Rhein/Main AG
47 /*	65760 Eschborn, Germany
48 /*
49 /*	Adopted by:
50 /*	Wietse Venema
51 /*	IBM T.J. Watson Research
52 /*	P.O. Box 704
53 /*	Yorktown Heights, NY 10598, USA
54 /*--*/
55 
56 #if defined(USE_SASL_AUTH) && defined(USE_SASLC_SASL)
57 
58  /*
59   * System headers.
60   */
61 #include <errno.h>
62 #include <saslc.h>
63 #include <stdlib.h>
64 #include <string.h>
65 
66 #include "sys_defs.h"
67 
68  /*
69   * Utility library
70   */
71 #include "msg.h"
72 #include "mymalloc.h"
73 #include "stringops.h"
74 
75  /*
76   * Global library
77   */
78 #include "mail_params.h"
79 
80  /*
81   * Application-specific
82   */
83 #include "xsasl.h"
84 #include "xsasl_saslc.h"
85 
86 
87 #define XSASL_SASLC_APPNAME	"postfix"  /* The config files are in
88 					      /etc/saslc.d/<appname>/ */
89 typedef struct {
90 	XSASL_CLIENT_IMPL xsasl;	/* generic members, must be first */
91 	saslc_t *saslc;			/* saslc context */
92 } XSASL_SASLC_CLIENT_IMPL;
93 
94 typedef struct {
95 	XSASL_CLIENT xsasl;		/* generic members, must be first */
96 	saslc_t *saslc;			/* saslc context */
97 	saslc_sess_t *sess;		/* session context */
98 	const char *service;		/* service (smtp) */
99 	const char *hostname;		/* server host name */
100 	const char *sec_opts;		/* security options */
101 } XSASL_SASLC_CLIENT;
102 
103 static XSASL_CLIENT *xsasl_saslc_client_create(XSASL_CLIENT_IMPL *,
104     XSASL_CLIENT_CREATE_ARGS *);
105 static int xsasl_saslc_client_first(XSASL_CLIENT *, const char *,
106     const char *, const char *, const char **, VSTRING *);
107 static int xsasl_saslc_client_next(XSASL_CLIENT *, const char *,
108     VSTRING *);
109 static void xsasl_saslc_client_done(XSASL_CLIENT_IMPL *);
110 static void xsasl_saslc_client_free(XSASL_CLIENT *);
111 
112 static void
113 setprop(saslc_sess_t *sess, int overwrite, const char *key, const char *value)
114 {
115 
116 	if (overwrite != 0 ||
117 	    saslc_sess_getprop(sess, key) == NULL)
118 		saslc_sess_setprop(sess, key, value);
119 }
120 
121 /*
122  * Run authentication protocol: first step.
123  */
124 static int
125 xsasl_saslc_client_first(
126 	XSASL_CLIENT *xp,
127 	const char *mechanism_list,
128 	const char *username,
129 	const char *password,
130 	const char **mechanism,
131 	VSTRING *init_resp)
132 {
133 	XSASL_SASLC_CLIENT *client = (XSASL_SASLC_CLIENT *)xp;
134 	const char *mech;
135 	void *out;
136 	size_t outlen;
137 	int rv;
138 
139 	if (msg_verbose) {
140 		msg_info("%s: mechanism_list='%s'", __func__, mechanism_list);
141 		msg_info("%s: username='%s'", __func__, username);
142 /*		msg_info("%s: password='%s'", __func__, password); */
143 	}
144 	client->sess = saslc_sess_init(client->saslc, mechanism_list,
145 					client->sec_opts);
146 	if (client->sess == NULL) {
147 		msg_info("%s: saslc_sess_init failed", __func__);
148 		return XSASL_AUTH_FAIL;
149 	}
150 	mech = saslc_sess_getmech(client->sess);
151 	if (mechanism)
152 		*mechanism = mech;
153 	if (msg_verbose)
154 		msg_info("%s: mechanism='%s'", __func__, mech);
155 
156 	setprop(client->sess, 0, SASLC_PROP_AUTHCID,  username);
157 	setprop(client->sess, 1, SASLC_PROP_PASSWD,   password);
158 	setprop(client->sess, 1, SASLC_PROP_SERVICE,  client->service);
159 	setprop(client->sess, 1, SASLC_PROP_HOSTNAME, client->hostname);
160 	setprop(client->sess, 1, SASLC_PROP_BASE64IO, "true");
161 	setprop(client->sess, 0, SASLC_PROP_QOPMASK,  "auth");
162 
163 	if ((rv = saslc_sess_cont(client->sess, NULL, 0, &out, &outlen))
164 	    == -1) {
165 		msg_info("%s: saslc_sess_encode='%s'", __func__,
166 		    saslc_sess_strerror(client->sess));
167 		return XSASL_AUTH_FAIL;
168 	}
169 	vstring_strcpy(init_resp, outlen ? out : "");
170 	if (msg_verbose)
171 		msg_info("%s: client_reply='%s'", __func__, outlen ? out : "");
172 
173 	if (outlen > 0)
174 		memset(out, 0, outlen);		/* XXX: silly? */
175 	if (out != NULL)
176 		free (out);
177 
178 	return XSASL_AUTH_OK;
179 }
180 
181 /*
182  * Continue authentication.
183  */
184 static int
185 xsasl_saslc_client_next(XSASL_CLIENT *xp, const char *server_reply,
186     VSTRING *client_reply)
187 {
188 	XSASL_SASLC_CLIENT *client;
189 	void *out;
190 	size_t outlen;
191 
192 	client = (XSASL_SASLC_CLIENT *)xp;
193 
194 	if (msg_verbose)
195 		msg_info("%s: server_reply='%s'", __func__, server_reply);
196 
197 	if (saslc_sess_cont(client->sess, server_reply, strlen(server_reply),
198 	    &out, &outlen) == -1) {
199 		msg_info("%s: saslc_sess_encode='%s'", __func__,
200 		    saslc_sess_strerror(client->sess));
201 		return XSASL_AUTH_FAIL;
202 	}
203 	vstring_strcpy(client_reply, outlen ? out : "");
204 	if (msg_verbose)
205 		msg_info("%s: client_reply='%s'", __func__,
206 		    outlen ? out : "");
207 
208 	if (outlen > 0)
209 		memset(out, 0, outlen);		/* XXX: silly? */
210 	if (out != NULL)
211 		free (out);
212 
213 	return XSASL_AUTH_OK;
214 }
215 
216 /*
217  * Per-session cleanup.
218  */
219 void
220 xsasl_saslc_client_free(XSASL_CLIENT *xp)
221 {
222 	XSASL_SASLC_CLIENT *client;
223 
224 	client = (XSASL_SASLC_CLIENT *)xp;
225 	if (client->sess)
226 		saslc_sess_end(client->sess);
227 	myfree((char *)client);
228 }
229 
230 /*
231  * Per-session SASL initialization.
232  */
233 XSASL_CLIENT *
234 xsasl_saslc_client_create(XSASL_CLIENT_IMPL *impl,
235     XSASL_CLIENT_CREATE_ARGS *args)
236 {
237 	XSASL_SASLC_CLIENT_IMPL *xp;
238 	XSASL_SASLC_CLIENT *client;
239 
240 	xp = (XSASL_SASLC_CLIENT_IMPL *)impl;
241 	if (msg_verbose) {
242 		msg_info("%s: service='%s'", __func__, args->service);
243 		msg_info("%s: server_name='%s'", __func__, args->server_name);
244 		msg_info("%s: security_options='%s'", __func__,
245 		    args->security_options);
246 	}
247 
248 	/* NB: mymalloc never returns NULL, it calls _exit(3) instead */
249 	client = (XSASL_SASLC_CLIENT *)mymalloc(sizeof(*client));
250 
251 	client->xsasl.free  = xsasl_saslc_client_free;
252 	client->xsasl.first = xsasl_saslc_client_first;
253 	client->xsasl.next  = xsasl_saslc_client_next;
254 
255 	client->saslc = xp->saslc;
256 
257 	/* XXX: should these be strdup()ed? */
258 	client->service  = args->service;
259 	client->hostname = args->server_name;
260 	client->sec_opts = args->security_options;
261 
262 	return &client->xsasl;
263 }
264 
265 /*
266  * Dispose of implementation.
267  */
268 static void
269 xsasl_saslc_client_done(XSASL_CLIENT_IMPL *impl)
270 {
271 	XSASL_SASLC_CLIENT_IMPL *xp;
272 
273 	xp = (XSASL_SASLC_CLIENT_IMPL *)impl;
274 	if (xp->saslc) {
275 		saslc_end(xp->saslc);
276 		xp->saslc = NULL;  /* XXX: unnecessary as freeing impl */
277 	}
278 	myfree((char *)impl);
279 }
280 
281 /*
282  * Initialize saslc SASL library.
283  */
284 XSASL_CLIENT_IMPL *
285 xsasl_saslc_client_init(const char *client_type, const char *path_info)
286 {
287 	XSASL_SASLC_CLIENT_IMPL *xp;
288 
289 	/* XXX: This should be unnecessary! */
290 	if (strcmp(client_type, XSASL_TYPE_SASLC) != 0) {
291 		msg_info("%s: invalid client_type: '%s'", __func__,
292 		    client_type);
293 		return NULL;
294 	}
295 	if (msg_verbose) {
296 		msg_info("%s: client_type='%s'", __func__, client_type);
297 		msg_info("%s: path_info='%s'",   __func__, path_info);
298 	}
299 
300 	/* NB: mymalloc() never returns NULL, it calls _exit(3) instead */
301 	xp = (XSASL_SASLC_CLIENT_IMPL *)mymalloc(sizeof(*xp));
302 	xp->xsasl.create = xsasl_saslc_client_create;
303 	xp->xsasl.done = xsasl_saslc_client_done;
304 
305 	/* NB: msg_fatal() exits the program immediately after printing */
306 	if ((xp->saslc = saslc_alloc()) == NULL)
307 		msg_fatal("%s: saslc_alloc failed: %s", __func__,
308 		    strerror(errno));
309 
310 	if (saslc_init(xp->saslc, XSASL_SASLC_APPNAME, path_info) == -1)
311 		msg_fatal("%s: saslc_init failed: %s", __func__,
312 		    saslc_strerror(xp->saslc));
313 
314 	return &xp->xsasl;
315 }
316 
317 #endif /* defined(USE_SASL_AUTH) && defined(USE_SASLC_SASL) */
318