Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      6 
      7 /* canonusr.c - user canonicalization support
      8  * Rob Siemborski
      9  * $Id: canonusr.c,v 1.12 2003/02/13 19:55:53 rjs3 Exp $
     10  */
     11 /*
     12  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
     13  *
     14  * Redistribution and use in source and binary forms, with or without
     15  * modification, are permitted provided that the following conditions
     16  * are met:
     17  *
     18  * 1. Redistributions of source code must retain the above copyright
     19  *    notice, this list of conditions and the following disclaimer.
     20  *
     21  * 2. Redistributions in binary form must reproduce the above copyright
     22  *    notice, this list of conditions and the following disclaimer in
     23  *    the documentation and/or other materials provided with the
     24  *    distribution.
     25  *
     26  * 3. The name "Carnegie Mellon University" must not be used to
     27  *    endorse or promote products derived from this software without
     28  *    prior written permission. For permission or any other legal
     29  *    details, please contact
     30  *      Office of Technology Transfer
     31  *      Carnegie Mellon University
     32  *      5000 Forbes Avenue
     33  *      Pittsburgh, PA  15213-3890
     34  *      (412) 268-4387, fax: (412) 268-7395
     35  *      tech-transfer (at) andrew.cmu.edu
     36  *
     37  * 4. Redistributions of any form whatsoever must retain the following
     38  *    acknowledgment:
     39  *    "This product includes software developed by Computing Services
     40  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     41  *
     42  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     43  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     44  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     45  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     47  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     48  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     49  */
     50 
     51 #include <config.h>
     52 #include <sasl.h>
     53 #include <string.h>
     54 #include <ctype.h>
     55 #include <prop.h>
     56 #include <stdio.h>
     57 
     58 #include "saslint.h"
     59 
     60 typedef struct canonuser_plug_list
     61 {
     62     struct canonuser_plug_list *next;
     63 #ifdef _SUN_SDK_
     64     char *name;
     65 #else
     66     char name[PATH_MAX];
     67 #endif /* _SUN_SDK_ */
     68     const sasl_canonuser_plug_t *plug;
     69 } canonuser_plug_list_t;
     70 
     71 #ifndef _SUN_SDK_
     72 static canonuser_plug_list_t *canonuser_head = NULL;
     73 #endif /* !_SUN_SDK_ */
     74 
     75 /* default behavior:
     76  *                   eliminate leading & trailing whitespace,
     77  *                   null-terminate, and get into the outparams
     78  *
     79  *                   (handled by INTERNAL plugin) */
     80 /* Also does auxprop lookups once username is canonoicalized */
     81 /* a zero ulen or alen indicates that it is strlen(value) */
     82 int _sasl_canon_user(sasl_conn_t *conn,
     83                      const char *user, unsigned ulen,
     84                      unsigned flags,
     85                      sasl_out_params_t *oparams)
     86 {
     87     canonuser_plug_list_t *ptr;
     88     sasl_server_conn_t *sconn = NULL;
     89     sasl_client_conn_t *cconn = NULL;
     90     sasl_canon_user_t *cuser_cb;
     91     sasl_getopt_t *getopt;
     92     void *context;
     93     int result;
     94     const char *plugin_name = NULL;
     95     char *user_buf;
     96     unsigned *lenp;
     97 
     98     if(!conn) return SASL_BADPARAM;
     99     if(!user || !oparams) return SASL_BADPARAM;
    100 
    101     if(flags & SASL_CU_AUTHID) {
    102 	user_buf = conn->authid_buf;
    103 	lenp = &(oparams->alen);
    104     } else if (flags & SASL_CU_AUTHZID) {
    105 	user_buf = conn->user_buf;
    106 	lenp = &(oparams->ulen);
    107     } else {
    108 	return SASL_BADPARAM;
    109     }
    110 
    111     if(conn->type == SASL_CONN_SERVER) sconn = (sasl_server_conn_t *)conn;
    112     else if(conn->type == SASL_CONN_CLIENT) cconn = (sasl_client_conn_t *)conn;
    113     else return SASL_FAIL;
    114 
    115     if(!ulen) ulen = (unsigned int)strlen(user);
    116 
    117     /* check to see if we have a callback to make*/
    118     result = _sasl_getcallback(conn, SASL_CB_CANON_USER,
    119 			       &cuser_cb, &context);
    120     if(result == SASL_OK && cuser_cb) {
    121 	result = cuser_cb(conn, context,
    122 			user, ulen,
    123 			flags, (conn->type == SASL_CONN_SERVER ?
    124 				((sasl_server_conn_t *)conn)->user_realm :
    125 				NULL),
    126 			user_buf, CANON_BUF_SIZE, lenp);
    127 
    128 
    129 	if (result != SASL_OK) return result;
    130 
    131 	/* Point the input copy at the stored buffer */
    132 	user = user_buf;
    133 	ulen = *lenp;
    134     }
    135 
    136     /* which plugin are we supposed to use? */
    137     result = _sasl_getcallback(conn, SASL_CB_GETOPT,
    138 			       &getopt, &context);
    139     if(result == SASL_OK && getopt) {
    140 	getopt(context, NULL, "canon_user_plugin", &plugin_name, NULL);
    141     }
    142 
    143     if(!plugin_name) {
    144 	/* Use Defualt */
    145 	plugin_name = "INTERNAL";
    146     }
    147 
    148 #ifdef _SUN_SDK_
    149     for(ptr = conn->gctx->canonuser_head; ptr; ptr = ptr->next) {
    150 #else
    151     for(ptr = canonuser_head; ptr; ptr = ptr->next) {
    152 #endif /* _SUN_SDK_ */
    153 	/* A match is if we match the internal name of the plugin, or if
    154 	 * we match the filename (old-style) */
    155 	if((ptr->plug->name && !strcmp(plugin_name, ptr->plug->name))
    156 	   || !strcmp(plugin_name, ptr->name)) break;
    157     }
    158 
    159     /* We clearly don't have this one! */
    160     if(!ptr) {
    161 #ifdef _INTEGRATED_SOLARIS_
    162 	if (conn->type == SASL_CONN_CLIENT)
    163 		sasl_seterror(conn, 0,
    164 		      gettext("desired canon_user plugin %s not found"),
    165 		      plugin_name);
    166 	else
    167 		_sasl_log(conn, SASL_LOG_ERR,
    168 		      "desired canon_user plugin %s not found",
    169 		      plugin_name);
    170 #else
    171 	sasl_seterror(conn, 0, "desired canon_user plugin %s not found",
    172 		      plugin_name);
    173 #endif /* _INTEGRATED_SOLARIS_ */
    174 	return SASL_NOMECH;
    175     }
    176 
    177     if(sconn) {
    178 	/* we're a server */
    179 	result = ptr->plug->canon_user_server(ptr->plug->glob_context,
    180 					      sconn->sparams,
    181 					      user, ulen,
    182 					      flags,
    183 					      user_buf,
    184 					      CANON_BUF_SIZE, lenp);
    185     } else {
    186 	/* we're a client */
    187 	result = ptr->plug->canon_user_client(ptr->plug->glob_context,
    188 					      cconn->cparams,
    189 					      user, ulen,
    190 					      flags,
    191 					      user_buf,
    192 					      CANON_BUF_SIZE, lenp);
    193     }
    194 
    195     if(result != SASL_OK) return result;
    196 
    197     if((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) {
    198 	/* We did both, so we need to copy the result into
    199 	 * the buffer for the authzid from the buffer for the authid */
    200 	memcpy(conn->user_buf, conn->authid_buf, CANON_BUF_SIZE);
    201 	oparams->ulen = oparams->alen;
    202     }
    203 
    204     /* Set the appropriate oparams (lengths have already been set by lenp) */
    205     if(flags & SASL_CU_AUTHID) {
    206 	oparams->authid = conn->authid_buf;
    207     }
    208 
    209     if (flags & SASL_CU_AUTHZID) {
    210 	oparams->user = conn->user_buf;
    211     }
    212 
    213 #ifndef macintosh
    214     /* do auxprop lookups (server only) */
    215     if(sconn) {
    216 	if(flags & SASL_CU_AUTHID) {
    217 	    _sasl_auxprop_lookup(sconn->sparams, 0,
    218 				 oparams->authid, oparams->alen);
    219 	}
    220 	if(flags & SASL_CU_AUTHZID) {
    221 	    _sasl_auxprop_lookup(sconn->sparams, SASL_AUXPROP_AUTHZID,
    222 				 oparams->user, oparams->ulen);
    223 	}
    224     }
    225 #endif
    226 
    227 
    228 #ifdef _SUN_SDK_
    229     return (SASL_OK);
    230 #else
    231     RETURN(conn, SASL_OK);
    232 #endif /* _SUN_SDK_ */
    233 }
    234 
    235 #ifdef _SUN_SDK_
    236 void _sasl_canonuser_free(_sasl_global_context_t *gctx)
    237 {
    238     canonuser_plug_list_t *ptr, *ptr_next;
    239     const sasl_utils_t *sasl_global_utils = gctx->sasl_canonusr_global_utils;
    240 
    241     for(ptr = (canonuser_plug_list_t *)gctx->canonuser_head;
    242 		ptr; ptr = ptr_next) {
    243 	ptr_next = ptr->next;
    244 	if(ptr->plug->canon_user_free)
    245 	    ptr->plug->canon_user_free(ptr->plug->glob_context,
    246 				       sasl_global_utils);
    247 	sasl_FREE(ptr->name);
    248 	sasl_FREE(ptr);
    249     }
    250 
    251     gctx->canonuser_head = NULL;
    252 }
    253 #else
    254 void _sasl_canonuser_free()
    255 {
    256     canonuser_plug_list_t *ptr, *ptr_next;
    257 
    258     for(ptr = canonuser_head; ptr; ptr = ptr_next) {
    259 	ptr_next = ptr->next;
    260 	if(ptr->plug->canon_user_free)
    261 	    ptr->plug->canon_user_free(ptr->plug->glob_context,
    262 				       sasl_global_utils);
    263 	sasl_FREE(ptr);
    264     }
    265 
    266     canonuser_head = NULL;
    267 }
    268 #endif /* _SUN_SDK_ */
    269 
    270 #ifdef _SUN_SDK_
    271 int sasl_canonuser_add_plugin(const char *plugname,
    272                               sasl_canonuser_init_t *canonuserfunc)
    273 {
    274     return (_sasl_canonuser_add_plugin(_sasl_gbl_ctx(), plugname,
    275         canonuserfunc));
    276 }
    277 
    278 int _sasl_canonuser_add_plugin(void *ctx,
    279                                const char *plugname,
    280                                sasl_canonuser_init_t *canonuserfunc)
    281 #else
    282 int sasl_canonuser_add_plugin(const char *plugname,
    283 			      sasl_canonuser_init_t *canonuserfunc)
    284 #endif /* _SUN_SDK_ */
    285 {
    286     int result, out_version;
    287     canonuser_plug_list_t *new_item;
    288     sasl_canonuser_plug_t *plug;
    289 #ifdef _SUN_SDK_
    290     _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
    291     const sasl_utils_t *sasl_global_utils;
    292     canonuser_plug_list_t *l;
    293 
    294   /* Check to see if this plugin has already been registered */
    295     for (l = gctx->canonuser_head; l != NULL; l = l->next) {
    296 	if (strcmp(plugname, l->name) == 0) {
    297 	    return SASL_OK;
    298 	}
    299     }
    300     sasl_global_utils = gctx->sasl_canonusr_global_utils;
    301 #endif /* _SUN_SDK_ */
    302 
    303     if(!plugname || strlen(plugname) > (PATH_MAX - 1)) {
    304 	sasl_seterror(NULL, 0,
    305 		      "bad plugname passed to sasl_canonuser_add_plugin\n");
    306 	return SASL_BADPARAM;
    307     }
    308 
    309     result = canonuserfunc(sasl_global_utils, SASL_CANONUSER_PLUG_VERSION,
    310 			   &out_version, &plug, plugname);
    311 
    312     if(result != SASL_OK) {
    313 #ifdef _SUN_SDK_
    314 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks == NULL ?
    315 	    	   gctx->client_global_callbacks.callbacks :
    316 	    	   gctx->server_global_callbacks.callbacks,
    317 		   SASL_LOG_ERR, "canonuserfunc error %i\n",result);
    318 #else
    319 	_sasl_log(NULL, SASL_LOG_ERR, "canonuserfunc error %i\n",result);
    320 #endif /* _SUN_SDK_ */
    321 	return result;
    322     }
    323 
    324     if(!plug->canon_user_server && !plug->canon_user_client) {
    325 	/* We need atleast one of these implemented */
    326 #ifdef _SUN_SDK_
    327 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks == NULL ?
    328 	    	   gctx->client_global_callbacks.callbacks :
    329 	    	   gctx->server_global_callbacks.callbacks, SASL_LOG_ERR,
    330 		   "canonuser plugin without either client or server side");
    331 #else
    332 	_sasl_log(NULL, SASL_LOG_ERR,
    333 		  "canonuser plugin without either client or server side");
    334 #endif /* _SUN_SDK_ */
    335 	return SASL_BADPROT;
    336     }
    337 
    338 #ifdef _SUN_SDK_
    339     /* Check plugin to make sure name is non-NULL */
    340     if (plug->name == NULL) {
    341 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks == NULL ?
    342 	    	   gctx->client_global_callbacks.callbacks :
    343 	    	   gctx->server_global_callbacks.callbacks,
    344 		   SASL_LOG_ERR, "invalid canonusr plugin %s", plugname);
    345 	return SASL_BADPROT;
    346     }
    347 #endif /* _SUN_SDK_ */
    348 
    349     new_item = sasl_ALLOC(sizeof(canonuser_plug_list_t));
    350     if(!new_item) return SASL_NOMEM;
    351 
    352 #ifdef _SUN_SDK_
    353     if(_sasl_strdup(plugname, &new_item->name, NULL) != SASL_OK) {
    354 	sasl_FREE(new_item);
    355 	return SASL_NOMEM;
    356     }
    357 #else
    358     strncpy(new_item->name, plugname, PATH_MAX);
    359 #endif /* _SUN_SDK_ */
    360 
    361     new_item->plug = plug;
    362 #ifdef _SUN_SDK_
    363     new_item->next = gctx->canonuser_head;
    364     gctx->canonuser_head = new_item;
    365 #else
    366     new_item->next = canonuser_head;
    367     canonuser_head = new_item;
    368 #endif /* _SUN_SDK_ */
    369 
    370     return SASL_OK;
    371 }
    372 
    373 #ifdef MIN
    374 #undef MIN
    375 #endif
    376 #define MIN(a,b) (((a) < (b))? (a):(b))
    377 
    378 static int _canonuser_internal(const sasl_utils_t *utils,
    379 			       const char *user, unsigned ulen,
    380 			       unsigned flags __attribute__((unused)),
    381 			       char *out_user,
    382 			       unsigned out_umax, unsigned *out_ulen)
    383 {
    384     unsigned i;
    385     char *in_buf, *userin;
    386     const char *begin_u;
    387     unsigned u_apprealm = 0;
    388     sasl_server_conn_t *sconn = NULL;
    389 
    390     if(!utils || !user) return SASL_BADPARAM;
    391 
    392 #ifdef _SUN_SDK_
    393     in_buf = utils->malloc((ulen + 2) * sizeof(char));
    394 #else
    395     in_buf = sasl_ALLOC((ulen + 2) * sizeof(char));
    396 #endif /* _SUN_SDK_ */
    397     if(!in_buf) return SASL_NOMEM;
    398 
    399     userin = in_buf;
    400 
    401     memcpy(userin, user, ulen);
    402     userin[ulen] = '\0';
    403 
    404     /* Strip User ID */
    405     for(i=0;isspace((int)userin[i]) && i<ulen;i++);
    406     begin_u = &(userin[i]);
    407     if(i>0) ulen -= i;
    408 
    409     for(;ulen > 0 && isspace((int)begin_u[ulen-1]); ulen--);
    410     if(begin_u == &(userin[ulen])) {
    411 #ifdef _SUN_SDK_
    412 	utils->free(in_buf);
    413 #else
    414 	sasl_FREE(in_buf);
    415 #endif /* _SUN_SDK_ */
    416 #ifdef _INTEGRATED_SOLARIS_
    417 	utils->seterror(utils->conn, 0, gettext("All-whitespace username."));
    418 #else
    419 	utils->seterror(utils->conn, 0, "All-whitespace username.");
    420 #endif /* _INTEGRATED_SOLARIS_ */
    421 	return SASL_FAIL;
    422     }
    423 
    424     if(utils->conn && utils->conn->type == SASL_CONN_SERVER)
    425 	sconn = (sasl_server_conn_t *)utils->conn;
    426 
    427     /* Need to append realm if necessary (see sasl.h) */
    428     if(sconn && sconn->user_realm && !strchr(user, '@')) {
    429 	u_apprealm = strlen(sconn->user_realm) + 1;
    430     }
    431 
    432     /* Now Copy */
    433     memcpy(out_user, begin_u, MIN(ulen, out_umax));
    434     if(sconn && u_apprealm) {
    435 	if(ulen >= out_umax) return SASL_BUFOVER;
    436 	out_user[ulen] = '@';
    437 	memcpy(&(out_user[ulen+1]), sconn->user_realm,
    438 	       MIN(u_apprealm-1, out_umax-ulen-1));
    439     }
    440     out_user[MIN(ulen + u_apprealm,out_umax)] = '\0';
    441 
    442     if(ulen + u_apprealm > out_umax) return SASL_BUFOVER;
    443 
    444     if(out_ulen) *out_ulen = MIN(ulen + u_apprealm,out_umax);
    445 
    446 #ifdef _SUN_SDK_
    447     utils->free(in_buf);
    448 #else
    449     sasl_FREE(in_buf);
    450 #endif /* _SUN_SDK_ */
    451     return SASL_OK;
    452 }
    453 
    454 static int _cu_internal_server(void *glob_context __attribute__((unused)),
    455 			       sasl_server_params_t *sparams,
    456 			       const char *user, unsigned ulen,
    457 			       unsigned flags,
    458 			       char *out_user,
    459 			       unsigned out_umax, unsigned *out_ulen)
    460 {
    461     return _canonuser_internal(sparams->utils,
    462 			       user, ulen,
    463 			       flags, out_user, out_umax, out_ulen);
    464 }
    465 
    466 static int _cu_internal_client(void *glob_context __attribute__((unused)),
    467 			       sasl_client_params_t *cparams,
    468 			       const char *user, unsigned ulen,
    469 			       unsigned flags,
    470 			       char *out_user,
    471 			       unsigned out_umax, unsigned *out_ulen)
    472 {
    473     return _canonuser_internal(cparams->utils,
    474 			       user, ulen,
    475 			       flags, out_user, out_umax, out_ulen);
    476 }
    477 
    478 static sasl_canonuser_plug_t canonuser_internal_plugin = {
    479         0, /* features */
    480 	0, /* spare */
    481 	NULL, /* glob_context */
    482 	"INTERNAL", /* name */
    483 	NULL, /* canon_user_free */
    484 	_cu_internal_server,
    485 	_cu_internal_client,
    486 	NULL,
    487 	NULL,
    488 	NULL
    489 };
    490 
    491 int internal_canonuser_init(const sasl_utils_t *utils __attribute__((unused)),
    492                             int max_version,
    493                             int *out_version,
    494                             sasl_canonuser_plug_t **plug,
    495                             const char *plugname __attribute__((unused)))
    496 {
    497     if(!out_version || !plug) return SASL_BADPARAM;
    498 
    499     if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
    500 
    501     *out_version = SASL_CANONUSER_PLUG_VERSION;
    502 
    503     *plug = &canonuser_internal_plugin;
    504 
    505     return SASL_OK;
    506 }
    507