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