Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      6 
      7 /* SASL server API implementation
      8  * Rob Siemborski
      9  * Tim Martin
     10  * $Id: external.c,v 1.19 2003/04/08 17:30:54 rjs3 Exp $
     11  */
     12 /*
     13  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
     14  *
     15  * Redistribution and use in source and binary forms, with or without
     16  * modification, are permitted provided that the following conditions
     17  * are met:
     18  *
     19  * 1. Redistributions of source code must retain the above copyright
     20  *    notice, this list of conditions and the following disclaimer.
     21  *
     22  * 2. Redistributions in binary form must reproduce the above copyright
     23  *    notice, this list of conditions and the following disclaimer in
     24  *    the documentation and/or other materials provided with the
     25  *    distribution.
     26  *
     27  * 3. The name "Carnegie Mellon University" must not be used to
     28  *    endorse or promote products derived from this software without
     29  *    prior written permission. For permission or any other legal
     30  *    details, please contact
     31  *      Office of Technology Transfer
     32  *      Carnegie Mellon University
     33  *      5000 Forbes Avenue
     34  *      Pittsburgh, PA  15213-3890
     35  *      (412) 268-4387, fax: (412) 268-7395
     36  *      tech-transfer (at) andrew.cmu.edu
     37  *
     38  * 4. Redistributions of any form whatsoever must retain the following
     39  *    acknowledgment:
     40  *    "This product includes software developed by Computing Services
     41  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     42  *
     43  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     44  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     45  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     46  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     47  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     48  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     49  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     50  */
     51 
     52 #include <config.h>
     53 #include <stdio.h>
     54 #include <stdlib.h>
     55 #include <limits.h>
     56 #include <ctype.h>
     57 #include <string.h>
     58 #include <sasl.h>
     59 #include <saslplug.h>
     60 #include "saslint.h"
     61 
     62 #include <plugin_common.h>
     63 
     64 /*****************************  Common Section  *****************************/
     65 
     66 #ifndef _SUN_SDK_
     67 static const char plugin_id[] = "$Id: external.c,v 1.19 2003/04/08 17:30:54 rjs3 Exp $";
     68 #endif /* !_SUN_SDK_ */
     69 
     70 /*****************************  Server Section  *****************************/
     71 
     72 static int
     73 external_server_mech_new(void *glob_context __attribute__((unused)),
     74 			 sasl_server_params_t *sparams,
     75 			 const char *challenge __attribute__((unused)),
     76 			 unsigned challen __attribute__((unused)),
     77 			 void **conn_context)
     78 {
     79     if (!conn_context
     80 	|| !sparams
     81 	|| !sparams->utils
     82 	|| !sparams->utils->conn)
     83 	return SASL_BADPARAM;
     84 
     85     if (!sparams->utils->conn->external.auth_id)
     86 	return SASL_NOMECH;
     87 
     88     *conn_context = NULL;
     89 
     90     return SASL_OK;
     91 }
     92 
     93 static int
     94 external_server_mech_step(void *conn_context __attribute__((unused)),
     95 			  sasl_server_params_t *sparams,
     96 			  const char *clientin,
     97 			  unsigned clientinlen,
     98 			  const char **serverout,
     99 			  unsigned *serveroutlen,
    100 			  sasl_out_params_t *oparams)
    101 {
    102     int result;
    103 
    104     if (!sparams
    105 	|| !sparams->utils
    106 	|| !sparams->utils->conn
    107 	|| !sparams->utils->getcallback
    108 	|| !serverout
    109 	|| !serveroutlen
    110 	|| !oparams)
    111 	return SASL_BADPARAM;
    112 
    113     if (!sparams->utils->conn->external.auth_id)
    114 	return SASL_BADPROT;
    115 
    116     if ((sparams->props.security_flags & SASL_SEC_NOANONYMOUS) &&
    117 	(!strcmp(sparams->utils->conn->external.auth_id, "anonymous"))) {
    118 #ifdef _INTEGRATED_SOLARIS_
    119 	sasl_seterror(sparams->utils->conn,0,
    120 		gettext("anonymous login not allowed"));
    121 #else
    122 	sasl_seterror(sparams->utils->conn,0,"anonymous login not allowed");
    123 #endif /* _INTEGRATED_SOLARIS_ */
    124 	return SASL_NOAUTHZ;
    125     }
    126 
    127     *serverout = NULL;
    128     *serveroutlen = 0;
    129 
    130     if (!clientin) {
    131 	/* No initial data; we're in a protocol which doesn't support it.
    132 	 * So we let the server app know that we need some... */
    133 	return SASL_CONTINUE;
    134     }
    135 
    136     if (clientinlen) {		/* if we have a non-zero authorization id */
    137 	/* The user's trying to authorize as someone they didn't
    138 	 * authenticate as */
    139 	result = sparams->canon_user(sparams->utils->conn,
    140 				     clientin, 0, SASL_CU_AUTHZID, oparams);
    141 	if(result != SASL_OK) return result;
    142 
    143 	result = sparams->canon_user(sparams->utils->conn,
    144 				     sparams->utils->conn->external.auth_id, 0,
    145 				     SASL_CU_AUTHID, oparams);
    146     } else {
    147 	result = sparams->canon_user(sparams->utils->conn,
    148 				     sparams->utils->conn->external.auth_id, 0,
    149 				     SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
    150     }
    151 
    152     if (result != SASL_OK) return result;
    153 
    154     /* set oparams */
    155     oparams->doneflag = 1;
    156     oparams->mech_ssf = 0;
    157     oparams->maxoutbuf = 0;
    158     oparams->encode_context = NULL;
    159     oparams->encode = NULL;
    160     oparams->decode_context = NULL;
    161     oparams->decode = NULL;
    162     oparams->param_version = 0;
    163 
    164     return SASL_OK;
    165 }
    166 
    167 static int
    168 external_server_mech_avail(void *glob_context __attribute__((unused)),
    169 			   sasl_server_params_t *sparams,
    170 			   void **conn_context __attribute__((unused)))
    171 {
    172     if (!sparams->utils->conn->external.auth_id)
    173 	return SASL_NOMECH;
    174     return SASL_OK;
    175 }
    176 
    177 static sasl_server_plug_t external_server_plugins[] =
    178 {
    179     {
    180 	"EXTERNAL",			/* mech_name */
    181 	0,				/* max_ssf */
    182 	SASL_SEC_NOPLAINTEXT
    183 	| SASL_SEC_NOANONYMOUS
    184 	| SASL_SEC_NODICTIONARY,	/* security_flags */
    185 	SASL_FEAT_WANT_CLIENT_FIRST
    186 	| SASL_FEAT_ALLOWS_PROXY,	/* features */
    187 	NULL,				/* glob_context */
    188 	&external_server_mech_new,	/* mech_new */
    189 	&external_server_mech_step,	/* mech_step */
    190 	NULL,				/* mech_dispose */
    191 	NULL,				/* mech_free */
    192 	NULL,				/* setpass */
    193 	NULL,				/* user_query */
    194 	NULL,				/* idle */
    195 	&external_server_mech_avail,	/* mech_avail */
    196 	NULL				/* spare */
    197     }
    198 };
    199 
    200 int external_server_plug_init(const sasl_utils_t *utils,
    201 			      int max_version,
    202 			      int *out_version,
    203 			      sasl_server_plug_t **pluglist,
    204 			      int *plugcount)
    205 {
    206     if (!out_version || !pluglist || !plugcount)
    207 	return SASL_BADPARAM;
    208 
    209     if (max_version != SASL_SERVER_PLUG_VERSION) {
    210 #ifdef _SUN_SDK_
    211 	utils->log(utils->conn, SASL_LOG_ERR, "EXTERNAL version mismatch");
    212 #else
    213 	SETERROR( utils, "EXTERNAL version mismatch" );
    214 #endif /* _SUN_SDK_ */
    215 	return SASL_BADVERS;
    216     }
    217 
    218     *out_version = SASL_SERVER_PLUG_VERSION;
    219     *pluglist = external_server_plugins;
    220     *plugcount = 1;
    221     return SASL_OK;
    222 }
    223 
    224 /*****************************  Client Section  *****************************/
    225 
    226 typedef struct client_context
    227 {
    228     char *out_buf;
    229 #ifdef _SUN_SDK_
    230     unsigned out_buf_len;
    231 #else
    232     size_t out_buf_len;
    233 #endif /* _SUN_SDK_ */
    234 #ifdef _INTEGRATED_SOLARIS_
    235     void *h;
    236 #endif /* _INTEGRATED_SOLARIS_ */
    237 } client_context_t;
    238 
    239 static int external_client_mech_new(void *glob_context __attribute__((unused)),
    240 				    sasl_client_params_t *params,
    241 				    void **conn_context)
    242 {
    243     client_context_t *text;
    244 
    245     if (!params
    246 	|| !params->utils
    247 	|| !params->utils->conn
    248 	|| !conn_context)
    249 	return SASL_BADPARAM;
    250 
    251     if (!params->utils->conn->external.auth_id)
    252 	return SASL_NOMECH;
    253 
    254 #ifdef _SUN_SDK_
    255     text = params->utils->malloc(sizeof(client_context_t));
    256 #else
    257     text = sasl_ALLOC(sizeof(client_context_t));
    258 #endif /* _SUN_SDK_ */
    259     if(!text) return SASL_NOMEM;
    260 
    261     memset(text, 0, sizeof(client_context_t));
    262 
    263     *conn_context = text;
    264 
    265     return SASL_OK;
    266 }
    267 
    268 static int
    269 external_client_mech_step(void *conn_context,
    270 			  sasl_client_params_t *params,
    271 			  const char *serverin __attribute__((unused)),
    272 			  unsigned serverinlen,
    273 			  sasl_interact_t **prompt_need,
    274 			  const char **clientout,
    275 			  unsigned *clientoutlen,
    276 			  sasl_out_params_t *oparams)
    277 {
    278     client_context_t *text = (client_context_t *)conn_context;
    279     const char *user = NULL;
    280     int user_result = SASL_OK;
    281     int result;
    282 
    283     if (!params
    284 	|| !params->utils
    285 	|| !params->utils->conn
    286 	|| !params->utils->getcallback
    287 	|| !clientout
    288 	|| !clientoutlen
    289 	|| !oparams)
    290 	return SASL_BADPARAM;
    291 
    292     if (!params->utils->conn->external.auth_id)
    293 	return SASL_BADPROT;
    294 
    295     if (serverinlen != 0)
    296 	return SASL_BADPROT;
    297 
    298     *clientout = NULL;
    299     *clientoutlen = 0;
    300 
    301     /* try to get the userid */
    302     if (user == NULL) {
    303 	user_result = _plug_get_userid(params->utils, &user, prompt_need);
    304 
    305 	if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
    306 	    return user_result;
    307     }
    308 
    309     /* free prompts we got */
    310     if (prompt_need && *prompt_need) {
    311 	params->utils->free(*prompt_need);
    312 	*prompt_need = NULL;
    313     }
    314 
    315     /* if there are prompts not filled in */
    316     if (user_result == SASL_INTERACT) {
    317 	/* make the prompt list */
    318 	int result =
    319 #ifdef _INTEGRATED_SOLARIS_
    320 	    _plug_make_prompts(params->utils, &text->h, prompt_need,
    321 			       user_result == SASL_INTERACT ?
    322 			       convert_prompt(params->utils, &text->h,
    323 			       gettext("Please enter your authorization name"))
    324 				 : NULL,
    325 #else
    326 	    _plug_make_prompts(params->utils, prompt_need,
    327 			       user_result == SASL_INTERACT ?
    328 			       "Please enter your authorization name" : NULL,
    329 #endif /* _INTEGRATED_SOLARIS_ */
    330 			       "",
    331 			       NULL, NULL,
    332 			       NULL, NULL,
    333 			       NULL, NULL, NULL,
    334 			       NULL, NULL, NULL);
    335 	if (result != SASL_OK) return result;
    336 
    337 	return SASL_INTERACT;
    338     }
    339 
    340     *clientoutlen = user ? strlen(user) : 0;
    341 
    342 #ifdef _SUN_SDK_
    343     result = _plug_buf_alloc(params->utils, &text->out_buf,
    344         &text->out_buf_len, *clientoutlen + 1);
    345 #else
    346     result = _buf_alloc(&text->out_buf, &text->out_buf_len, *clientoutlen + 1);
    347 #endif /* _SUN_SDK_ */
    348 
    349     if (result != SASL_OK) return result;
    350 
    351     if (user && *user) {
    352 	result = params->canon_user(params->utils->conn,
    353 				    user, 0, SASL_CU_AUTHZID, oparams);
    354 	if (result != SASL_OK) return result;
    355 
    356 	result = params->canon_user(params->utils->conn,
    357 				    params->utils->conn->external.auth_id, 0,
    358 				    SASL_CU_AUTHID, oparams);
    359 	if (result != SASL_OK) return result;
    360 
    361 	memcpy(text->out_buf, user, *clientoutlen);
    362     } else {
    363 	result = params->canon_user(params->utils->conn,
    364 				    params->utils->conn->external.auth_id, 0,
    365 				    SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
    366 	if (result != SASL_OK) return result;
    367     }
    368 
    369     text->out_buf[*clientoutlen] = '\0';
    370 
    371     *clientout = text->out_buf;
    372 
    373     /* set oparams */
    374     oparams->doneflag = 1;
    375     oparams->mech_ssf = 0;
    376     oparams->maxoutbuf = 0;
    377     oparams->encode_context = NULL;
    378     oparams->encode = NULL;
    379     oparams->decode_context = NULL;
    380     oparams->decode = NULL;
    381     oparams->param_version = 0;
    382 
    383     return SASL_OK;
    384 }
    385 
    386 static void
    387 external_client_mech_dispose(void *conn_context,
    388 			     const sasl_utils_t *utils __attribute__((unused)))
    389 {
    390     client_context_t *text = (client_context_t *) conn_context;
    391 
    392     if (!text) return;
    393 
    394 #ifdef _INTEGRATED_SOLARIS_
    395     convert_prompt(utils, &text->h, NULL);
    396 #endif /* _INTEGRATED_SOLARIS_ */
    397 
    398 #ifdef _SUN_SDK_
    399     if(text->out_buf) utils->free(text->out_buf);
    400 
    401     utils->free(text);
    402 #else
    403     if(text->out_buf) sasl_FREE(text->out_buf);
    404 
    405     sasl_FREE(text);
    406 #endif /* _SUN_SDK_ */
    407 }
    408 
    409 #ifdef _SUN_SDK_
    410 static const unsigned long external_required_prompts[] = {
    411 #else
    412 static const long external_required_prompts[] = {
    413 #endif /* _SUN_SDK_ */
    414     SASL_CB_LIST_END
    415 };
    416 
    417 static sasl_client_plug_t external_client_plugins[] =
    418 {
    419     {
    420 	"EXTERNAL",			/* mech_name */
    421 	0,				/* max_ssf */
    422 	SASL_SEC_NOPLAINTEXT
    423 	| SASL_SEC_NOANONYMOUS
    424 	| SASL_SEC_NODICTIONARY,	/* security_flags */
    425 	SASL_FEAT_WANT_CLIENT_FIRST
    426 	| SASL_FEAT_ALLOWS_PROXY,	/* features */
    427 	external_required_prompts,	/* required_prompts */
    428 	NULL,				/* glob_context */
    429 	&external_client_mech_new,	/* mech_new */
    430 	&external_client_mech_step,	/* mech_step */
    431 	&external_client_mech_dispose,	/* mech_dispose */
    432 	NULL,				/* mech_free */
    433 	NULL,				/* idle */
    434 	NULL,				/* spare */
    435 	NULL				/* spare */
    436     }
    437 };
    438 
    439 int external_client_plug_init(const sasl_utils_t *utils,
    440 			      int max_version,
    441 			      int *out_version,
    442 			      sasl_client_plug_t **pluglist,
    443 			      int *plugcount)
    444 {
    445     if (!utils || !out_version || !pluglist || !plugcount)
    446 	return SASL_BADPARAM;
    447 
    448     if (max_version != SASL_CLIENT_PLUG_VERSION) {
    449 #ifdef _SUN_SDK_
    450 	utils->log(utils->conn, SASL_LOG_ERR, "EXTERNAL version mismatch");
    451 #else
    452 	SETERROR( utils, "EXTERNAL version mismatch" );
    453 #endif /* _SUN_SDK_ */
    454 	return SASL_BADVERS;
    455     }
    456 
    457     *out_version = SASL_CLIENT_PLUG_VERSION;
    458     *pluglist = external_client_plugins;
    459     *plugcount = 1;
    460 
    461     return SASL_OK;
    462 }
    463