xref: /netbsd-src/crypto/external/bsd/libsaslc/dist/src/xsess.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /* $Id: xsess.c,v 1.1.1.1 2010/11/27 21:23:59 agc Exp $ */
2 
3 /*
4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Mateusz Kocielski.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <stdio.h>
40 #include <string.h>
41 #include <saslc.h>
42 #include <assert.h>
43 #include "dict.h"
44 #include "error.h"
45 #include "mech.h"
46 #include "saslc_private.h"
47 
48 /* local headers */
49 
50 static const saslc__mech_t *
51 saslc__sess_choose_mech(saslc_t *, const char *);
52 
53 /**
54  * @brief chooses best mechanism form the mechs list for
55  * the sasl session.
56  * @param ctx sasl context
57  * @param mechs comma separated list of mechanisms eg. "PLAIN,LOGIN", note that
58  * this function is not case sensitive
59  * @return pointer to the mech on success, NULL if none mechanism was chose
60  */
61 
62 static const saslc__mech_t *
63 saslc__sess_choose_mech(saslc_t *ctx, const char *mechs)
64 {
65 	char *c, *e;
66 	const char *mech_name;
67 	const saslc__mech_list_node_t *m = NULL;
68 
69 	if ((c = strdup(mechs)) == NULL) {
70 		saslc__error_set_errno(ERR(ctx), ERROR_NOMEM);
71 		return NULL;
72 	}
73 
74 	mech_name = c;
75 	e = c;
76 
77 	/* check if mechs parameter is a list of the mechanisms */
78 	if (strchr(e, ',') != NULL) {
79 		while ((e = strchr(e, ',')) != NULL) {
80 			*e = '\0';
81 			if ((m = saslc__mech_list_get(ctx->mechanisms,
82 			    mech_name)) != NULL)
83 				goto out;
84 			e++;
85 			mech_name = e;
86 		}
87 	}
88 
89 	m = saslc__mech_list_get(ctx->mechanisms, mech_name);
90 out:
91 	free(c);
92 	return m != NULL ? m->mech : NULL;
93 }
94 
95 /**
96  * @brief sasl session initializaion. Function initializes session
97  * property dictionary, chooses best mechanism, creates mech session.
98  * @param ctx sasl context
99  * @param mechs comma separated list of mechanisms eg. "PLAIN,LOGIN", note that
100  * this function is not case sensitive
101  * @return pointer to the sasl session on success, NULL on failure
102  */
103 
104 saslc_sess_t	*
105 saslc_sess_init(saslc_t *ctx, const char *mechs)
106 {
107 	saslc_sess_t *sess;
108 
109 	if ((sess = calloc(1, sizeof(*sess))) == NULL) {
110 		saslc__error_set_errno(ERR(ctx), ERROR_NOMEM);
111 		return NULL;
112 	}
113 
114 	/* mechanism initialization */
115 	if ((sess->mech = saslc__sess_choose_mech(ctx, mechs)) == NULL) {
116 		free(sess);
117 		saslc__error_set(ERR(ctx), ERROR_MECH,
118 		    "mechanism is not supported");
119 		return NULL;
120 	}
121 
122 	/* create mechanism session */
123 	if (sess->mech->create(sess) < 0) {
124 		free(sess);
125 		return NULL;
126 	}
127 
128 	/* properties */
129 	if ((sess->prop = saslc__dict_create()) == NULL) {
130 		free(sess);
131 		saslc__error_set(ERR(ctx), ERROR_NOMEM, NULL);
132 		return NULL;
133 	}
134 
135 	sess->context = ctx;
136 	ctx->refcnt++;
137 
138 	return sess;
139 }
140 
141 /**
142  * @brief ends sasl session, destroys and deallocates internal
143  * resources
144  * @param sess sasl session
145  */
146 
147 void
148 saslc_sess_end(saslc_sess_t *sess)
149 {
150 	sess->mech->destroy(sess);
151 	saslc__dict_destroy(sess->prop);
152 	sess->context->refcnt--;
153 	free(sess);
154 }
155 
156 /**
157  * @brief sets property for the session. If property already
158  * exists in the session, then previous value is replaced by the new value.
159  * @param sess sasl session
160  * @param name property name
161  * @param value proprty value
162  * @return 0 on success, -1 on failure
163  */
164 
165 int
166 saslc_sess_setprop(saslc_sess_t *sess, const char *name, const char *value)
167 {
168 	/* check if key exists, if so then remove it from dictionary */
169 
170 	if (saslc__dict_get(sess->prop, name) != NULL) {
171 		if (saslc__dict_remove(sess->prop, name) != DICT_OK)
172 			assert(/*CONSTCOND*/0);
173 	}
174 
175 	switch (saslc__dict_insert(sess->prop, name, value)) {
176 	case DICT_VALBAD:
177 		saslc__error_set(ERR(sess), ERROR_BADARG, "bad value");
178 		return -1;
179 	case DICT_KEYINVALID:
180 		saslc__error_set(ERR(sess), ERROR_BADARG, "bad name");
181 		return -1;
182 	case DICT_NOMEM:
183 		saslc__error_set(ERR(sess), ERROR_NOMEM, NULL);
184 		return -1;
185 	case DICT_OK:
186 		break;
187 	case DICT_KEYEXISTS:
188 	default:
189 		assert(/*CONSTCOND*/0); /* impossible */
190 	}
191 
192 	return 0;
193 }
194 
195 /**
196  * @brief gets property from the session. Dictionaries are used
197  * in following order: session dictionary, context dictionary (global
198  * configuration), mechanism dicionary.
199  * @param sess sasl session
200  * @param name property name
201  * @return property value on success, NULL on failure.
202  */
203 
204 const char	*
205 saslc_sess_getprop(saslc_sess_t *sess, const char *name)
206 {
207 	const char *r;
208 	saslc__mech_list_node_t *m;
209 
210 	/* get property from the session dictionary */
211 	if ((r = saslc__dict_get(sess->prop, name)) != NULL)
212 		return r;
213 
214 	/* get property from the context dictionary */
215 	if ((r = saslc__dict_get(sess->context->prop, name)) != NULL)
216 		return r;
217 
218 	/* get property form the mechanism dictionary */
219 	if ((m = saslc__mech_list_get(sess->context->mechanisms,
220 	    sess->mech->name)) == NULL)
221 		return NULL;
222 
223 	return saslc__dict_get(m->prop, name);
224 }
225 
226 /**
227  * @brief do one step of the sasl authentication, input data
228  * and its lenght are stored in in and inlen, output is stored in out and
229  * outlen. This function is and wrapper for mechanism step functions.
230  * Additionaly it checks if session is not already authorized and handles
231  * steps mech_sess structure.
232  * @param sess saslc session
233  * @param in input data
234  * @param inlen input data length
235  * @param out output data
236  * @param outlen output data length
237  * @return MECH_OK - on success, no more steps are needed
238  * MECH_ERROR - on error, additionaly errno in sess is setup
239  * MECH_STEP - more steps are needed
240  */
241 
242 int
243 saslc_sess_cont(saslc_sess_t *sess, const void *in, size_t inlen, void **out,
244 	size_t *outlen)
245 {
246 	int r;
247 	saslc__mech_sess_t *ms = sess->mech_sess;
248 
249 	if (ms->status == STATUS_AUTHENTICATED) {
250 		saslc__error_set(ERR(sess), ERROR_MECH,
251 		    "session authenticated");
252 		return MECH_ERROR;
253 	}
254 
255 	r = sess->mech->cont(sess, in, inlen, out, outlen);
256 
257 	if (r == MECH_OK)
258 		ms->status = STATUS_AUTHENTICATED;
259 
260 	ms->step++;
261 	return r;
262 }
263 
264 /**
265  * @brief encodes data using method established during the
266  * authentication. Input data is stored in in and inlen and output data
267  * is stored in out and outlen.
268  * @param sess sasl session
269  * @param in input data
270  * @param inlen input data length
271  * @param out output data
272  * @param outlen output data length
273  * @return 0 on success, -1 on failure
274  */
275 
276 int
277 saslc_sess_encode(saslc_sess_t *sess, const void *in, size_t inlen,
278 	void **out, size_t *outlen)
279 {
280 	if (sess->mech->encode == NULL) {
281 		saslc__error_set(ERR(sess), ERROR_MECH,
282 		    "security layer is not supported by mechnism");
283 		return -1;
284 	}
285 
286 	return sess->mech->encode(sess, in, inlen, out, outlen);
287 }
288 
289 /**
290  * @brief decodes data using method established during the
291  * authentication. Input data is stored in in and inlen and output data
292  * is stored in out and outlen.
293  * @param sess sasl session
294  * @param in input data
295  * @param inlen input data length
296  * @param out output data
297  * @param outlen output data length
298  * @return 0 on success, -1 on failure
299  */
300 
301 int
302 saslc_sess_decode(saslc_sess_t *sess, const void *in, size_t inlen,
303     void **out, size_t *outlen)
304 {
305 	if (sess->mech->decode == NULL) {
306 		saslc__error_set(ERR(sess), ERROR_MECH,
307 		    "security layer is not supported by mechnism");
308 		return -1;
309 	}
310 
311 	return sess->mech->decode(sess, in, inlen, out, outlen);
312 }
313 
314 /**
315  * @brief gets string message of the error
316  * @param sess sasl session
317  * @return pointer to the error message
318  */
319 
320 const char *
321 saslc_sess_strerror(saslc_sess_t *sess)
322 {
323 	return saslc__error_get_strerror(ERR(sess));
324 }
325 
326 /**
327  * @brief gets name of the mechanism used in sasl session
328  * @param sess sasl session
329  * @return pointer to the mechanism name
330  */
331 
332 const char *
333 saslc_sess_strmech(saslc_sess_t *sess)
334 {
335 	return sess->mech->name;
336 }
337