1 /* canonusr.c - user canonicalization support
3 * $Id: canonusr.c,v 1.15 2004/02/20 23:54:51 rjs3 Exp $
6 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * 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
17 * the documentation and/or other materials provided with the
20 * 3. The name "Carnegie Mellon University" must not be used to
21 * endorse or promote products derived from this software without
22 * prior written permission. For permission or any other legal
23 * details, please contact
24 * Office of Technology Transfer
25 * Carnegie Mellon University
27 * Pittsburgh, PA 15213-3890
28 * (412) 268-4387, fax: (412) 268-7395
29 * tech-transfer@andrew.cmu.edu
31 * 4. Redistributions of any form whatsoever must retain the following
33 * "This product includes software developed by Computing Services
34 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
36 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
37 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
39 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
41 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
42 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
54 typedef struct canonuser_plug_list
56 struct canonuser_plug_list *next;
58 const sasl_canonuser_plug_t *plug;
59 } canonuser_plug_list_t;
61 static canonuser_plug_list_t *canonuser_head = NULL;
64 * eliminate leading & trailing whitespace,
65 * null-terminate, and get into the outparams
67 * (handled by INTERNAL plugin) */
68 /* Also does auxprop lookups once username is canonicalized */
69 /* a zero ulen or alen indicates that it is strlen(value) */
70 int _sasl_canon_user(sasl_conn_t *conn,
71 const char *user, unsigned ulen,
73 sasl_out_params_t *oparams)
75 canonuser_plug_list_t *ptr;
76 sasl_server_conn_t *sconn = NULL;
77 sasl_client_conn_t *cconn = NULL;
78 sasl_canon_user_t *cuser_cb;
79 sasl_getopt_t *getopt;
82 const char *plugin_name = NULL;
86 if(!conn) return SASL_BADPARAM;
87 if(!user || !oparams) return SASL_BADPARAM;
89 if(flags & SASL_CU_AUTHID) {
90 user_buf = conn->authid_buf;
91 lenp = &(oparams->alen);
92 } else if (flags & SASL_CU_AUTHZID) {
93 user_buf = conn->user_buf;
94 lenp = &(oparams->ulen);
99 if(conn->type == SASL_CONN_SERVER) sconn = (sasl_server_conn_t *)conn;
100 else if(conn->type == SASL_CONN_CLIENT) cconn = (sasl_client_conn_t *)conn;
101 else return SASL_FAIL;
103 if(!ulen) ulen = (unsigned int)strlen(user);
105 /* check to see if we have a callback to make*/
106 result = _sasl_getcallback(conn, SASL_CB_CANON_USER,
107 &cuser_cb, &context);
108 if(result == SASL_OK && cuser_cb) {
109 result = cuser_cb(conn, context,
111 flags, (conn->type == SASL_CONN_SERVER ?
112 ((sasl_server_conn_t *)conn)->user_realm :
114 user_buf, CANON_BUF_SIZE, lenp);
117 if (result != SASL_OK) return result;
119 /* Point the input copy at the stored buffer */
124 /* which plugin are we supposed to use? */
125 result = _sasl_getcallback(conn, SASL_CB_GETOPT,
127 if(result == SASL_OK && getopt) {
128 getopt(context, NULL, "canon_user_plugin", &plugin_name, NULL);
133 plugin_name = "INTERNAL";
136 for(ptr = canonuser_head; ptr; ptr = ptr->next) {
137 /* A match is if we match the internal name of the plugin, or if
138 * we match the filename (old-style) */
139 if((ptr->plug->name && !strcmp(plugin_name, ptr->plug->name))
140 || !strcmp(plugin_name, ptr->name)) break;
143 /* We clearly don't have this one! */
145 sasl_seterror(conn, 0, "desired canon_user plugin %s not found",
152 result = ptr->plug->canon_user_server(ptr->plug->glob_context,
157 CANON_BUF_SIZE, lenp);
160 result = ptr->plug->canon_user_client(ptr->plug->glob_context,
165 CANON_BUF_SIZE, lenp);
168 if(result != SASL_OK) return result;
170 if((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) {
171 /* We did both, so we need to copy the result into
172 * the buffer for the authzid from the buffer for the authid */
173 memcpy(conn->user_buf, conn->authid_buf, CANON_BUF_SIZE);
174 oparams->ulen = oparams->alen;
177 /* Set the appropriate oparams (lengths have already been set by lenp) */
178 if(flags & SASL_CU_AUTHID) {
179 oparams->authid = conn->authid_buf;
182 if (flags & SASL_CU_AUTHZID) {
183 oparams->user = conn->user_buf;
187 /* do auxprop lookups (server only) */
189 if(flags & SASL_CU_AUTHID) {
190 _sasl_auxprop_lookup(sconn->sparams, 0,
191 oparams->authid, oparams->alen);
193 if(flags & SASL_CU_AUTHZID) {
194 _sasl_auxprop_lookup(sconn->sparams, SASL_AUXPROP_AUTHZID,
195 oparams->user, oparams->ulen);
201 RETURN(conn, SASL_OK);
204 void _sasl_canonuser_free()
206 canonuser_plug_list_t *ptr, *ptr_next;
208 for(ptr = canonuser_head; ptr; ptr = ptr_next) {
209 ptr_next = ptr->next;
210 if(ptr->plug->canon_user_free)
211 ptr->plug->canon_user_free(ptr->plug->glob_context,
216 canonuser_head = NULL;
219 int sasl_canonuser_add_plugin(const char *plugname,
220 sasl_canonuser_init_t *canonuserfunc)
222 int result, out_version;
223 canonuser_plug_list_t *new_item;
224 sasl_canonuser_plug_t *plug;
226 if(!plugname || strlen(plugname) > (PATH_MAX - 1)) {
227 sasl_seterror(NULL, 0,
228 "bad plugname passed to sasl_canonuser_add_plugin\n");
229 return SASL_BADPARAM;
232 result = canonuserfunc(sasl_global_utils, SASL_CANONUSER_PLUG_VERSION,
233 &out_version, &plug, plugname);
235 if(result != SASL_OK) {
236 _sasl_log(NULL, SASL_LOG_ERR, "canonuserfunc error %i\n",result);
240 if(!plug->canon_user_server && !plug->canon_user_client) {
241 /* We need at least one of these implemented */
242 _sasl_log(NULL, SASL_LOG_ERR,
243 "canonuser plugin without either client or server side");
247 new_item = sasl_ALLOC(sizeof(canonuser_plug_list_t));
248 if(!new_item) return SASL_NOMEM;
250 strncpy(new_item->name, plugname, PATH_MAX);
252 new_item->plug = plug;
253 new_item->next = canonuser_head;
254 canonuser_head = new_item;
262 #define MIN(a,b) (((a) < (b))? (a):(b))
264 static int _canonuser_internal(const sasl_utils_t *utils,
265 const char *user, unsigned ulen,
266 unsigned flags __attribute__((unused)),
268 unsigned out_umax, unsigned *out_ulen)
271 char *in_buf, *userin;
273 size_t u_apprealm = 0;
274 sasl_server_conn_t *sconn = NULL;
276 if(!utils || !user) return SASL_BADPARAM;
278 in_buf = sasl_ALLOC((ulen + 2) * sizeof(char));
279 if(!in_buf) return SASL_NOMEM;
283 memcpy(userin, user, ulen);
287 for(i=0;isspace((int)userin[i]) && i<ulen;i++);
288 begin_u = &(userin[i]);
291 for(;ulen > 0 && isspace((int)begin_u[ulen-1]); ulen--);
292 if(begin_u == &(userin[ulen])) {
294 utils->seterror(utils->conn, 0, "All-whitespace username.");
298 if(utils->conn && utils->conn->type == SASL_CONN_SERVER)
299 sconn = (sasl_server_conn_t *)utils->conn;
301 /* Need to append realm if necessary (see sasl.h) */
302 if(sconn && sconn->user_realm && !strchr(user, '@')) {
303 u_apprealm = strlen(sconn->user_realm) + 1;
307 memcpy(out_user, begin_u, MIN(ulen, out_umax));
308 if(sconn && u_apprealm) {
309 if(ulen >= out_umax) return SASL_BUFOVER;
310 out_user[ulen] = '@';
311 memcpy(&(out_user[ulen+1]), sconn->user_realm,
312 MIN(u_apprealm-1, out_umax-ulen-1));
314 out_user[MIN(ulen + u_apprealm,out_umax)] = '\0';
316 if(ulen + u_apprealm > out_umax) return SASL_BUFOVER;
318 if(out_ulen) *out_ulen = MIN(ulen + u_apprealm,out_umax);
324 static int _cu_internal_server(void *glob_context __attribute__((unused)),
325 sasl_server_params_t *sparams,
326 const char *user, unsigned ulen,
329 unsigned out_umax, unsigned *out_ulen)
331 return _canonuser_internal(sparams->utils,
333 flags, out_user, out_umax, out_ulen);
336 static int _cu_internal_client(void *glob_context __attribute__((unused)),
337 sasl_client_params_t *cparams,
338 const char *user, unsigned ulen,
341 unsigned out_umax, unsigned *out_ulen)
343 return _canonuser_internal(cparams->utils,
345 flags, out_user, out_umax, out_ulen);
348 static sasl_canonuser_plug_t canonuser_internal_plugin = {
351 NULL, /* glob_context */
352 "INTERNAL", /* name */
353 NULL, /* canon_user_free */
361 int internal_canonuser_init(const sasl_utils_t *utils __attribute__((unused)),
364 sasl_canonuser_plug_t **plug,
365 const char *plugname __attribute__((unused)))
367 if(!out_version || !plug) return SASL_BADPARAM;
369 if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
371 *out_version = SASL_CANONUSER_PLUG_VERSION;
373 *plug = &canonuser_internal_plugin;