xref: /illumos-gate/usr/src/lib/libsasl/lib/canonusr.c (revision 1da57d55)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /* canonusr.c - user canonicalization support
77c478bd9Sstevel@tonic-gate  * Rob Siemborski
87c478bd9Sstevel@tonic-gate  * $Id: canonusr.c,v 1.12 2003/02/13 19:55:53 rjs3 Exp $
97c478bd9Sstevel@tonic-gate  */
10*1da57d55SToomas Soome /*
117c478bd9Sstevel@tonic-gate  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
147c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
157c478bd9Sstevel@tonic-gate  * are met:
167c478bd9Sstevel@tonic-gate  *
177c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
18*1da57d55SToomas Soome  *    notice, this list of conditions and the following disclaimer.
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
217c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
227c478bd9Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
237c478bd9Sstevel@tonic-gate  *    distribution.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * 3. The name "Carnegie Mellon University" must not be used to
267c478bd9Sstevel@tonic-gate  *    endorse or promote products derived from this software without
277c478bd9Sstevel@tonic-gate  *    prior written permission. For permission or any other legal
28*1da57d55SToomas Soome  *    details, please contact
297c478bd9Sstevel@tonic-gate  *      Office of Technology Transfer
307c478bd9Sstevel@tonic-gate  *      Carnegie Mellon University
317c478bd9Sstevel@tonic-gate  *      5000 Forbes Avenue
327c478bd9Sstevel@tonic-gate  *      Pittsburgh, PA  15213-3890
337c478bd9Sstevel@tonic-gate  *      (412) 268-4387, fax: (412) 268-7395
347c478bd9Sstevel@tonic-gate  *      tech-transfer@andrew.cmu.edu
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * 4. Redistributions of any form whatsoever must retain the following
377c478bd9Sstevel@tonic-gate  *    acknowledgment:
387c478bd9Sstevel@tonic-gate  *    "This product includes software developed by Computing Services
397c478bd9Sstevel@tonic-gate  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
427c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
437c478bd9Sstevel@tonic-gate  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
447c478bd9Sstevel@tonic-gate  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
457c478bd9Sstevel@tonic-gate  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
467c478bd9Sstevel@tonic-gate  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
477c478bd9Sstevel@tonic-gate  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include <config.h>
517c478bd9Sstevel@tonic-gate #include <sasl.h>
527c478bd9Sstevel@tonic-gate #include <string.h>
537c478bd9Sstevel@tonic-gate #include <ctype.h>
547c478bd9Sstevel@tonic-gate #include <prop.h>
557c478bd9Sstevel@tonic-gate #include <stdio.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #include "saslint.h"
587c478bd9Sstevel@tonic-gate 
59*1da57d55SToomas Soome typedef struct canonuser_plug_list
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate     struct canonuser_plug_list *next;
627c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
637c478bd9Sstevel@tonic-gate     char *name;
647c478bd9Sstevel@tonic-gate #else
657c478bd9Sstevel@tonic-gate     char name[PATH_MAX];
667c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
677c478bd9Sstevel@tonic-gate     const sasl_canonuser_plug_t *plug;
687c478bd9Sstevel@tonic-gate } canonuser_plug_list_t;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
717c478bd9Sstevel@tonic-gate static canonuser_plug_list_t *canonuser_head = NULL;
727c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /* default behavior:
757c478bd9Sstevel@tonic-gate  *                   eliminate leading & trailing whitespace,
767c478bd9Sstevel@tonic-gate  *                   null-terminate, and get into the outparams
777c478bd9Sstevel@tonic-gate  *
787c478bd9Sstevel@tonic-gate  *                   (handled by INTERNAL plugin) */
797c478bd9Sstevel@tonic-gate /* Also does auxprop lookups once username is canonoicalized */
807c478bd9Sstevel@tonic-gate /* a zero ulen or alen indicates that it is strlen(value) */
_sasl_canon_user(sasl_conn_t * conn,const char * user,unsigned ulen,unsigned flags,sasl_out_params_t * oparams)817c478bd9Sstevel@tonic-gate int _sasl_canon_user(sasl_conn_t *conn,
827c478bd9Sstevel@tonic-gate                      const char *user, unsigned ulen,
837c478bd9Sstevel@tonic-gate                      unsigned flags,
847c478bd9Sstevel@tonic-gate                      sasl_out_params_t *oparams)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate     canonuser_plug_list_t *ptr;
877c478bd9Sstevel@tonic-gate     sasl_server_conn_t *sconn = NULL;
887c478bd9Sstevel@tonic-gate     sasl_client_conn_t *cconn = NULL;
897c478bd9Sstevel@tonic-gate     sasl_canon_user_t *cuser_cb;
907c478bd9Sstevel@tonic-gate     sasl_getopt_t *getopt;
917c478bd9Sstevel@tonic-gate     void *context;
927c478bd9Sstevel@tonic-gate     int result;
937c478bd9Sstevel@tonic-gate     const char *plugin_name = NULL;
947c478bd9Sstevel@tonic-gate     char *user_buf;
957c478bd9Sstevel@tonic-gate     unsigned *lenp;
967c478bd9Sstevel@tonic-gate 
97*1da57d55SToomas Soome     if(!conn) return SASL_BADPARAM;
987c478bd9Sstevel@tonic-gate     if(!user || !oparams) return SASL_BADPARAM;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate     if(flags & SASL_CU_AUTHID) {
1017c478bd9Sstevel@tonic-gate 	user_buf = conn->authid_buf;
1027c478bd9Sstevel@tonic-gate 	lenp = &(oparams->alen);
1037c478bd9Sstevel@tonic-gate     } else if (flags & SASL_CU_AUTHZID) {
1047c478bd9Sstevel@tonic-gate 	user_buf = conn->user_buf;
1057c478bd9Sstevel@tonic-gate 	lenp = &(oparams->ulen);
1067c478bd9Sstevel@tonic-gate     } else {
1077c478bd9Sstevel@tonic-gate 	return SASL_BADPARAM;
1087c478bd9Sstevel@tonic-gate     }
109*1da57d55SToomas Soome 
1107c478bd9Sstevel@tonic-gate     if(conn->type == SASL_CONN_SERVER) sconn = (sasl_server_conn_t *)conn;
1117c478bd9Sstevel@tonic-gate     else if(conn->type == SASL_CONN_CLIENT) cconn = (sasl_client_conn_t *)conn;
1127c478bd9Sstevel@tonic-gate     else return SASL_FAIL;
113*1da57d55SToomas Soome 
1147c478bd9Sstevel@tonic-gate     if(!ulen) ulen = (unsigned int)strlen(user);
115*1da57d55SToomas Soome 
1167c478bd9Sstevel@tonic-gate     /* check to see if we have a callback to make*/
1177c478bd9Sstevel@tonic-gate     result = _sasl_getcallback(conn, SASL_CB_CANON_USER,
1187c478bd9Sstevel@tonic-gate 			       &cuser_cb, &context);
1197c478bd9Sstevel@tonic-gate     if(result == SASL_OK && cuser_cb) {
1207c478bd9Sstevel@tonic-gate 	result = cuser_cb(conn, context,
1217c478bd9Sstevel@tonic-gate 			user, ulen,
1227c478bd9Sstevel@tonic-gate 			flags, (conn->type == SASL_CONN_SERVER ?
1237c478bd9Sstevel@tonic-gate 				((sasl_server_conn_t *)conn)->user_realm :
1247c478bd9Sstevel@tonic-gate 				NULL),
1257c478bd9Sstevel@tonic-gate 			user_buf, CANON_BUF_SIZE, lenp);
126*1da57d55SToomas Soome 
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	if (result != SASL_OK) return result;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	/* Point the input copy at the stored buffer */
1317c478bd9Sstevel@tonic-gate 	user = user_buf;
1327c478bd9Sstevel@tonic-gate 	ulen = *lenp;
1337c478bd9Sstevel@tonic-gate     }
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate     /* which plugin are we supposed to use? */
1367c478bd9Sstevel@tonic-gate     result = _sasl_getcallback(conn, SASL_CB_GETOPT,
1377c478bd9Sstevel@tonic-gate 			       &getopt, &context);
1387c478bd9Sstevel@tonic-gate     if(result == SASL_OK && getopt) {
1397c478bd9Sstevel@tonic-gate 	getopt(context, NULL, "canon_user_plugin", &plugin_name, NULL);
1407c478bd9Sstevel@tonic-gate     }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate     if(!plugin_name) {
1437c478bd9Sstevel@tonic-gate 	/* Use Defualt */
1447c478bd9Sstevel@tonic-gate 	plugin_name = "INTERNAL";
1457c478bd9Sstevel@tonic-gate     }
146*1da57d55SToomas Soome 
1477c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
1487c478bd9Sstevel@tonic-gate     for(ptr = conn->gctx->canonuser_head; ptr; ptr = ptr->next) {
1497c478bd9Sstevel@tonic-gate #else
1507c478bd9Sstevel@tonic-gate     for(ptr = canonuser_head; ptr; ptr = ptr->next) {
1517c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
1527c478bd9Sstevel@tonic-gate 	/* A match is if we match the internal name of the plugin, or if
1537c478bd9Sstevel@tonic-gate 	 * we match the filename (old-style) */
1547c478bd9Sstevel@tonic-gate 	if((ptr->plug->name && !strcmp(plugin_name, ptr->plug->name))
1557c478bd9Sstevel@tonic-gate 	   || !strcmp(plugin_name, ptr->name)) break;
1567c478bd9Sstevel@tonic-gate     }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate     /* We clearly don't have this one! */
1597c478bd9Sstevel@tonic-gate     if(!ptr) {
1607c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
1617c478bd9Sstevel@tonic-gate 	if (conn->type == SASL_CONN_CLIENT)
1627c478bd9Sstevel@tonic-gate 		sasl_seterror(conn, 0,
1637c478bd9Sstevel@tonic-gate 		      gettext("desired canon_user plugin %s not found"),
1647c478bd9Sstevel@tonic-gate 		      plugin_name);
1657c478bd9Sstevel@tonic-gate 	else
1667c478bd9Sstevel@tonic-gate 		_sasl_log(conn, SASL_LOG_ERR,
1677c478bd9Sstevel@tonic-gate 		      "desired canon_user plugin %s not found",
1687c478bd9Sstevel@tonic-gate 		      plugin_name);
1697c478bd9Sstevel@tonic-gate #else
1707c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, "desired canon_user plugin %s not found",
1717c478bd9Sstevel@tonic-gate 		      plugin_name);
1727c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
1737c478bd9Sstevel@tonic-gate 	return SASL_NOMECH;
1747c478bd9Sstevel@tonic-gate     }
175*1da57d55SToomas Soome 
1767c478bd9Sstevel@tonic-gate     if(sconn) {
1777c478bd9Sstevel@tonic-gate 	/* we're a server */
1787c478bd9Sstevel@tonic-gate 	result = ptr->plug->canon_user_server(ptr->plug->glob_context,
1797c478bd9Sstevel@tonic-gate 					      sconn->sparams,
1807c478bd9Sstevel@tonic-gate 					      user, ulen,
1817c478bd9Sstevel@tonic-gate 					      flags,
1827c478bd9Sstevel@tonic-gate 					      user_buf,
1837c478bd9Sstevel@tonic-gate 					      CANON_BUF_SIZE, lenp);
1847c478bd9Sstevel@tonic-gate     } else {
1857c478bd9Sstevel@tonic-gate 	/* we're a client */
1867c478bd9Sstevel@tonic-gate 	result = ptr->plug->canon_user_client(ptr->plug->glob_context,
1877c478bd9Sstevel@tonic-gate 					      cconn->cparams,
1887c478bd9Sstevel@tonic-gate 					      user, ulen,
1897c478bd9Sstevel@tonic-gate 					      flags,
1907c478bd9Sstevel@tonic-gate 					      user_buf,
1917c478bd9Sstevel@tonic-gate 					      CANON_BUF_SIZE, lenp);
1927c478bd9Sstevel@tonic-gate     }
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate     if(result != SASL_OK) return result;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate     if((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) {
1977c478bd9Sstevel@tonic-gate 	/* We did both, so we need to copy the result into
1987c478bd9Sstevel@tonic-gate 	 * the buffer for the authzid from the buffer for the authid */
1997c478bd9Sstevel@tonic-gate 	memcpy(conn->user_buf, conn->authid_buf, CANON_BUF_SIZE);
2007c478bd9Sstevel@tonic-gate 	oparams->ulen = oparams->alen;
2017c478bd9Sstevel@tonic-gate     }
202*1da57d55SToomas Soome 
2037c478bd9Sstevel@tonic-gate     /* Set the appropriate oparams (lengths have already been set by lenp) */
2047c478bd9Sstevel@tonic-gate     if(flags & SASL_CU_AUTHID) {
2057c478bd9Sstevel@tonic-gate 	oparams->authid = conn->authid_buf;
2067c478bd9Sstevel@tonic-gate     }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate     if (flags & SASL_CU_AUTHZID) {
2097c478bd9Sstevel@tonic-gate 	oparams->user = conn->user_buf;
2107c478bd9Sstevel@tonic-gate     }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate #ifndef macintosh
2137c478bd9Sstevel@tonic-gate     /* do auxprop lookups (server only) */
2147c478bd9Sstevel@tonic-gate     if(sconn) {
2157c478bd9Sstevel@tonic-gate 	if(flags & SASL_CU_AUTHID) {
2167c478bd9Sstevel@tonic-gate 	    _sasl_auxprop_lookup(sconn->sparams, 0,
2177c478bd9Sstevel@tonic-gate 				 oparams->authid, oparams->alen);
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 	if(flags & SASL_CU_AUTHZID) {
2207c478bd9Sstevel@tonic-gate 	    _sasl_auxprop_lookup(sconn->sparams, SASL_AUXPROP_AUTHZID,
2217c478bd9Sstevel@tonic-gate 				 oparams->user, oparams->ulen);
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate     }
2247c478bd9Sstevel@tonic-gate #endif
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
2287c478bd9Sstevel@tonic-gate     return (SASL_OK);
2297c478bd9Sstevel@tonic-gate #else
2307c478bd9Sstevel@tonic-gate     RETURN(conn, SASL_OK);
2317c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
2357c478bd9Sstevel@tonic-gate void _sasl_canonuser_free(_sasl_global_context_t *gctx)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate     canonuser_plug_list_t *ptr, *ptr_next;
2387c478bd9Sstevel@tonic-gate     const sasl_utils_t *sasl_global_utils = gctx->sasl_canonusr_global_utils;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate     for(ptr = (canonuser_plug_list_t *)gctx->canonuser_head;
2417c478bd9Sstevel@tonic-gate 		ptr; ptr = ptr_next) {
2427c478bd9Sstevel@tonic-gate 	ptr_next = ptr->next;
2437c478bd9Sstevel@tonic-gate 	if(ptr->plug->canon_user_free)
2447c478bd9Sstevel@tonic-gate 	    ptr->plug->canon_user_free(ptr->plug->glob_context,
2457c478bd9Sstevel@tonic-gate 				       sasl_global_utils);
2467c478bd9Sstevel@tonic-gate 	sasl_FREE(ptr->name);
2477c478bd9Sstevel@tonic-gate 	sasl_FREE(ptr);
2487c478bd9Sstevel@tonic-gate     }
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate     gctx->canonuser_head = NULL;
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate #else
253*1da57d55SToomas Soome void _sasl_canonuser_free()
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate     canonuser_plug_list_t *ptr, *ptr_next;
256*1da57d55SToomas Soome 
2577c478bd9Sstevel@tonic-gate     for(ptr = canonuser_head; ptr; ptr = ptr_next) {
2587c478bd9Sstevel@tonic-gate 	ptr_next = ptr->next;
2597c478bd9Sstevel@tonic-gate 	if(ptr->plug->canon_user_free)
2607c478bd9Sstevel@tonic-gate 	    ptr->plug->canon_user_free(ptr->plug->glob_context,
2617c478bd9Sstevel@tonic-gate 				       sasl_global_utils);
2627c478bd9Sstevel@tonic-gate 	sasl_FREE(ptr);
2637c478bd9Sstevel@tonic-gate     }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate     canonuser_head = NULL;
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
2707c478bd9Sstevel@tonic-gate int sasl_canonuser_add_plugin(const char *plugname,
2717c478bd9Sstevel@tonic-gate                               sasl_canonuser_init_t *canonuserfunc)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate     return (_sasl_canonuser_add_plugin(_sasl_gbl_ctx(), plugname,
2747c478bd9Sstevel@tonic-gate         canonuserfunc));
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate int _sasl_canonuser_add_plugin(void *ctx,
2787c478bd9Sstevel@tonic-gate                                const char *plugname,
2797c478bd9Sstevel@tonic-gate                                sasl_canonuser_init_t *canonuserfunc)
2807c478bd9Sstevel@tonic-gate #else
2817c478bd9Sstevel@tonic-gate int sasl_canonuser_add_plugin(const char *plugname,
282*1da57d55SToomas Soome 			      sasl_canonuser_init_t *canonuserfunc)
2837c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate     int result, out_version;
2867c478bd9Sstevel@tonic-gate     canonuser_plug_list_t *new_item;
2877c478bd9Sstevel@tonic-gate     sasl_canonuser_plug_t *plug;
2887c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
2897c478bd9Sstevel@tonic-gate     _sasl_global_context_t *gctx = ctx == NULL ? _sasl_gbl_ctx() : ctx;
2907c478bd9Sstevel@tonic-gate     const sasl_utils_t *sasl_global_utils;
2917c478bd9Sstevel@tonic-gate     canonuser_plug_list_t *l;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate   /* Check to see if this plugin has already been registered */
2947c478bd9Sstevel@tonic-gate     for (l = gctx->canonuser_head; l != NULL; l = l->next) {
2957c478bd9Sstevel@tonic-gate 	if (strcmp(plugname, l->name) == 0) {
2967c478bd9Sstevel@tonic-gate 	    return SASL_OK;
2977c478bd9Sstevel@tonic-gate 	}
2987c478bd9Sstevel@tonic-gate     }
2997c478bd9Sstevel@tonic-gate     sasl_global_utils = gctx->sasl_canonusr_global_utils;
3007c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate     if(!plugname || strlen(plugname) > (PATH_MAX - 1)) {
3037c478bd9Sstevel@tonic-gate 	sasl_seterror(NULL, 0,
3047c478bd9Sstevel@tonic-gate 		      "bad plugname passed to sasl_canonuser_add_plugin\n");
3057c478bd9Sstevel@tonic-gate 	return SASL_BADPARAM;
3067c478bd9Sstevel@tonic-gate     }
307*1da57d55SToomas Soome 
3087c478bd9Sstevel@tonic-gate     result = canonuserfunc(sasl_global_utils, SASL_CANONUSER_PLUG_VERSION,
3097c478bd9Sstevel@tonic-gate 			   &out_version, &plug, plugname);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate     if(result != SASL_OK) {
3127c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3137c478bd9Sstevel@tonic-gate 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks == NULL ?
3147c478bd9Sstevel@tonic-gate 	    	   gctx->client_global_callbacks.callbacks :
3157c478bd9Sstevel@tonic-gate 	    	   gctx->server_global_callbacks.callbacks,
3167c478bd9Sstevel@tonic-gate 		   SASL_LOG_ERR, "canonuserfunc error %i\n",result);
3177c478bd9Sstevel@tonic-gate #else
3187c478bd9Sstevel@tonic-gate 	_sasl_log(NULL, SASL_LOG_ERR, "canonuserfunc error %i\n",result);
3197c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3207c478bd9Sstevel@tonic-gate 	return result;
3217c478bd9Sstevel@tonic-gate     }
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate     if(!plug->canon_user_server && !plug->canon_user_client) {
3247c478bd9Sstevel@tonic-gate 	/* We need atleast one of these implemented */
3257c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3267c478bd9Sstevel@tonic-gate 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks == NULL ?
3277c478bd9Sstevel@tonic-gate 	    	   gctx->client_global_callbacks.callbacks :
3287c478bd9Sstevel@tonic-gate 	    	   gctx->server_global_callbacks.callbacks, SASL_LOG_ERR,
3297c478bd9Sstevel@tonic-gate 		   "canonuser plugin without either client or server side");
3307c478bd9Sstevel@tonic-gate #else
3317c478bd9Sstevel@tonic-gate 	_sasl_log(NULL, SASL_LOG_ERR,
3327c478bd9Sstevel@tonic-gate 		  "canonuser plugin without either client or server side");
3337c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3347c478bd9Sstevel@tonic-gate 	return SASL_BADPROT;
3357c478bd9Sstevel@tonic-gate     }
336*1da57d55SToomas Soome 
3377c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3387c478bd9Sstevel@tonic-gate     /* Check plugin to make sure name is non-NULL */
3397c478bd9Sstevel@tonic-gate     if (plug->name == NULL) {
3407c478bd9Sstevel@tonic-gate 	__sasl_log(gctx, gctx->server_global_callbacks.callbacks == NULL ?
3417c478bd9Sstevel@tonic-gate 	    	   gctx->client_global_callbacks.callbacks :
3427c478bd9Sstevel@tonic-gate 	    	   gctx->server_global_callbacks.callbacks,
3437c478bd9Sstevel@tonic-gate 		   SASL_LOG_ERR, "invalid canonusr plugin %s", plugname);
3447c478bd9Sstevel@tonic-gate 	return SASL_BADPROT;
3457c478bd9Sstevel@tonic-gate     }
3467c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate     new_item = sasl_ALLOC(sizeof(canonuser_plug_list_t));
3497c478bd9Sstevel@tonic-gate     if(!new_item) return SASL_NOMEM;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3527c478bd9Sstevel@tonic-gate     if(_sasl_strdup(plugname, &new_item->name, NULL) != SASL_OK) {
3537c478bd9Sstevel@tonic-gate 	sasl_FREE(new_item);
3547c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
3557c478bd9Sstevel@tonic-gate     }
3567c478bd9Sstevel@tonic-gate #else
3577c478bd9Sstevel@tonic-gate     strncpy(new_item->name, plugname, PATH_MAX);
3587c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate     new_item->plug = plug;
3617c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3627c478bd9Sstevel@tonic-gate     new_item->next = gctx->canonuser_head;
3637c478bd9Sstevel@tonic-gate     gctx->canonuser_head = new_item;
3647c478bd9Sstevel@tonic-gate #else
3657c478bd9Sstevel@tonic-gate     new_item->next = canonuser_head;
3667c478bd9Sstevel@tonic-gate     canonuser_head = new_item;
3677c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate     return SASL_OK;
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate #ifdef MIN
3737c478bd9Sstevel@tonic-gate #undef MIN
3747c478bd9Sstevel@tonic-gate #endif
3757c478bd9Sstevel@tonic-gate #define MIN(a,b) (((a) < (b))? (a):(b))
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate static int _canonuser_internal(const sasl_utils_t *utils,
3787c478bd9Sstevel@tonic-gate 			       const char *user, unsigned ulen,
3797c478bd9Sstevel@tonic-gate 			       unsigned flags __attribute__((unused)),
3807c478bd9Sstevel@tonic-gate 			       char *out_user,
381*1da57d55SToomas Soome 			       unsigned out_umax, unsigned *out_ulen)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate     unsigned i;
3847c478bd9Sstevel@tonic-gate     char *in_buf, *userin;
3857c478bd9Sstevel@tonic-gate     const char *begin_u;
3867c478bd9Sstevel@tonic-gate     unsigned u_apprealm = 0;
3877c478bd9Sstevel@tonic-gate     sasl_server_conn_t *sconn = NULL;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate     if(!utils || !user) return SASL_BADPARAM;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3927c478bd9Sstevel@tonic-gate     in_buf = utils->malloc((ulen + 2) * sizeof(char));
3937c478bd9Sstevel@tonic-gate #else
3947c478bd9Sstevel@tonic-gate     in_buf = sasl_ALLOC((ulen + 2) * sizeof(char));
3957c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3967c478bd9Sstevel@tonic-gate     if(!in_buf) return SASL_NOMEM;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate     userin = in_buf;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate     memcpy(userin, user, ulen);
4017c478bd9Sstevel@tonic-gate     userin[ulen] = '\0';
402*1da57d55SToomas Soome 
4037c478bd9Sstevel@tonic-gate     /* Strip User ID */
4047c478bd9Sstevel@tonic-gate     for(i=0;isspace((int)userin[i]) && i<ulen;i++);
4057c478bd9Sstevel@tonic-gate     begin_u = &(userin[i]);
4067c478bd9Sstevel@tonic-gate     if(i>0) ulen -= i;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate     for(;ulen > 0 && isspace((int)begin_u[ulen-1]); ulen--);
4097c478bd9Sstevel@tonic-gate     if(begin_u == &(userin[ulen])) {
4107c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
4117c478bd9Sstevel@tonic-gate 	utils->free(in_buf);
4127c478bd9Sstevel@tonic-gate #else
4137c478bd9Sstevel@tonic-gate 	sasl_FREE(in_buf);
4147c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
4157c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
4167c478bd9Sstevel@tonic-gate 	utils->seterror(utils->conn, 0, gettext("All-whitespace username."));
4177c478bd9Sstevel@tonic-gate #else
4187c478bd9Sstevel@tonic-gate 	utils->seterror(utils->conn, 0, "All-whitespace username.");
4197c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
4207c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
4217c478bd9Sstevel@tonic-gate     }
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate     if(utils->conn && utils->conn->type == SASL_CONN_SERVER)
4247c478bd9Sstevel@tonic-gate 	sconn = (sasl_server_conn_t *)utils->conn;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate     /* Need to append realm if necessary (see sasl.h) */
4277c478bd9Sstevel@tonic-gate     if(sconn && sconn->user_realm && !strchr(user, '@')) {
4287c478bd9Sstevel@tonic-gate 	u_apprealm = strlen(sconn->user_realm) + 1;
4297c478bd9Sstevel@tonic-gate     }
430*1da57d55SToomas Soome 
4317c478bd9Sstevel@tonic-gate     /* Now Copy */
4327c478bd9Sstevel@tonic-gate     memcpy(out_user, begin_u, MIN(ulen, out_umax));
4337c478bd9Sstevel@tonic-gate     if(sconn && u_apprealm) {
4347c478bd9Sstevel@tonic-gate 	if(ulen >= out_umax) return SASL_BUFOVER;
4357c478bd9Sstevel@tonic-gate 	out_user[ulen] = '@';
4367c478bd9Sstevel@tonic-gate 	memcpy(&(out_user[ulen+1]), sconn->user_realm,
4377c478bd9Sstevel@tonic-gate 	       MIN(u_apprealm-1, out_umax-ulen-1));
4387c478bd9Sstevel@tonic-gate     }
4397c478bd9Sstevel@tonic-gate     out_user[MIN(ulen + u_apprealm,out_umax)] = '\0';
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate     if(ulen + u_apprealm > out_umax) return SASL_BUFOVER;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate     if(out_ulen) *out_ulen = MIN(ulen + u_apprealm,out_umax);
444*1da57d55SToomas Soome 
4457c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
4467c478bd9Sstevel@tonic-gate     utils->free(in_buf);
4477c478bd9Sstevel@tonic-gate #else
4487c478bd9Sstevel@tonic-gate     sasl_FREE(in_buf);
4497c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
4507c478bd9Sstevel@tonic-gate     return SASL_OK;
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate static int _cu_internal_server(void *glob_context __attribute__((unused)),
4547c478bd9Sstevel@tonic-gate 			       sasl_server_params_t *sparams,
4557c478bd9Sstevel@tonic-gate 			       const char *user, unsigned ulen,
4567c478bd9Sstevel@tonic-gate 			       unsigned flags,
4577c478bd9Sstevel@tonic-gate 			       char *out_user,
458*1da57d55SToomas Soome 			       unsigned out_umax, unsigned *out_ulen)
4597c478bd9Sstevel@tonic-gate {
4607c478bd9Sstevel@tonic-gate     return _canonuser_internal(sparams->utils,
4617c478bd9Sstevel@tonic-gate 			       user, ulen,
4627c478bd9Sstevel@tonic-gate 			       flags, out_user, out_umax, out_ulen);
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate static int _cu_internal_client(void *glob_context __attribute__((unused)),
4667c478bd9Sstevel@tonic-gate 			       sasl_client_params_t *cparams,
4677c478bd9Sstevel@tonic-gate 			       const char *user, unsigned ulen,
4687c478bd9Sstevel@tonic-gate 			       unsigned flags,
4697c478bd9Sstevel@tonic-gate 			       char *out_user,
470*1da57d55SToomas Soome 			       unsigned out_umax, unsigned *out_ulen)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate     return _canonuser_internal(cparams->utils,
4737c478bd9Sstevel@tonic-gate 			       user, ulen,
4747c478bd9Sstevel@tonic-gate 			       flags, out_user, out_umax, out_ulen);
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate static sasl_canonuser_plug_t canonuser_internal_plugin = {
4787c478bd9Sstevel@tonic-gate         0, /* features */
4797c478bd9Sstevel@tonic-gate 	0, /* spare */
4807c478bd9Sstevel@tonic-gate 	NULL, /* glob_context */
4817c478bd9Sstevel@tonic-gate 	"INTERNAL", /* name */
4827c478bd9Sstevel@tonic-gate 	NULL, /* canon_user_free */
4837c478bd9Sstevel@tonic-gate 	_cu_internal_server,
4847c478bd9Sstevel@tonic-gate 	_cu_internal_client,
4857c478bd9Sstevel@tonic-gate 	NULL,
4867c478bd9Sstevel@tonic-gate 	NULL,
4877c478bd9Sstevel@tonic-gate 	NULL
4887c478bd9Sstevel@tonic-gate };
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate int internal_canonuser_init(const sasl_utils_t *utils __attribute__((unused)),
4917c478bd9Sstevel@tonic-gate                             int max_version,
4927c478bd9Sstevel@tonic-gate                             int *out_version,
4937c478bd9Sstevel@tonic-gate                             sasl_canonuser_plug_t **plug,
494*1da57d55SToomas Soome                             const char *plugname __attribute__((unused)))
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate     if(!out_version || !plug) return SASL_BADPARAM;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate     if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
499*1da57d55SToomas Soome 
5007c478bd9Sstevel@tonic-gate     *out_version = SASL_CANONUSER_PLUG_VERSION;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate     *plug = &canonuser_internal_plugin;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate     return SASL_OK;
5057c478bd9Sstevel@tonic-gate }
506