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@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) */
_sasl_canon_user(sasl_conn_t * conn,const char * user,unsigned ulen,unsigned flags,sasl_out_params_t * oparams)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