source: trunk/third/cyrus-sasl/lib/canonusr.c @ 18842

Revision 18842, 10.8 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18841, which included commits to RCS files with non-trunk default branches.
Line 
1/* canonusr.c - user canonicalization support
2 * Rob Siemborski
3 * $Id: canonusr.c,v 1.1.1.2 2003-02-12 22:33:47 ghudson Exp $
4 */
5/*
6 * Copyright (c) 2001 Carnegie Mellon University.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
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
18 *    distribution.
19 *
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
26 *      5000 Forbes Avenue
27 *      Pittsburgh, PA  15213-3890
28 *      (412) 268-4387, fax: (412) 268-7395
29 *      tech-transfer@andrew.cmu.edu
30 *
31 * 4. Redistributions of any form whatsoever must retain the following
32 *    acknowledgment:
33 *    "This product includes software developed by Computing Services
34 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35 *
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.
43 */
44
45#include <config.h>
46#include <sasl.h>
47#include <string.h>
48#include <ctype.h>
49#include <prop.h>
50#include <stdio.h>
51
52#include "saslint.h"
53
54typedef struct canonuser_plug_list
55{
56    struct canonuser_plug_list *next;
57    char name[PATH_MAX];
58    const sasl_canonuser_plug_t *plug;
59} canonuser_plug_list_t;
60
61static canonuser_plug_list_t *canonuser_head = NULL;
62
63/* default behavior:
64 *                   eliminate leading & trailing whitespace,
65 *                   null-terminate, and get into the outparams
66 *
67 *                   (handled by INTERNAL plugin) */
68/* Also does auxprop lookups once username is canonoicalized */
69/* a zero ulen or alen indicates that it is strlen(value) */
70int _sasl_canon_user(sasl_conn_t *conn,
71                     const char *user, unsigned ulen,
72                     unsigned flags,
73                     sasl_out_params_t *oparams)
74{
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;
80    void *context;
81    int result;
82    const char *plugin_name = NULL;
83    char *user_buf;
84    unsigned *lenp;
85
86    if(!conn) return SASL_BADPARAM;   
87    if(!user || !oparams) return SASL_BADPARAM;
88
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);
95    } else {
96        return SASL_BADPARAM;
97    }
98   
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;
102   
103    if(!ulen) ulen = (unsigned int)strlen(user);
104   
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,
110                        user, ulen,
111                        flags, (conn->type == SASL_CONN_SERVER ?
112                                ((sasl_server_conn_t *)conn)->user_realm :
113                                NULL),
114                        user_buf, CANON_BUF_SIZE, lenp);
115       
116
117        if (result != SASL_OK) return result;
118
119        /* Point the input copy at the stored buffer */
120        user = user_buf;
121        ulen = *lenp;
122    }
123
124    /* which plugin are we supposed to use? */
125    result = _sasl_getcallback(conn, SASL_CB_GETOPT,
126                               &getopt, &context);
127    if(result == SASL_OK && getopt) {
128        getopt(context, NULL, "canon_user_plugin", &plugin_name, NULL);
129    }
130
131    if(!plugin_name) {
132        /* Use Defualt */
133        plugin_name = "INTERNAL";
134    }
135   
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;
141    }
142
143    /* We clearly don't have this one! */
144    if(!ptr) {
145        sasl_seterror(conn, 0, "desired canon_user plugin %s not found",
146                      plugin_name);
147        return SASL_NOMECH;
148    }
149   
150    if(sconn) {
151        /* we're a server */
152        result = ptr->plug->canon_user_server(ptr->plug->glob_context,
153                                              sconn->sparams,
154                                              user, ulen,
155                                              flags,
156                                              user_buf,
157                                              CANON_BUF_SIZE, lenp);
158    } else {
159        /* we're a client */
160        result = ptr->plug->canon_user_client(ptr->plug->glob_context,
161                                              cconn->cparams,
162                                              user, ulen,
163                                              flags,
164                                              user_buf,
165                                              CANON_BUF_SIZE, lenp);
166    }
167
168    if(result != SASL_OK) return result;
169
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;
175    }
176       
177    /* Set the appropriate oparams (lengths have already been set by lenp) */
178    if(flags & SASL_CU_AUTHID) {
179        oparams->authid = conn->authid_buf;
180    }
181
182    if (flags & SASL_CU_AUTHZID) {
183        oparams->user = conn->user_buf;
184    }
185
186#ifndef macintosh
187    /* do auxprop lookups (server only) */
188    if(sconn) {
189        if(flags & SASL_CU_AUTHID) {
190            _sasl_auxprop_lookup(sconn->sparams, 0,
191                                 oparams->authid, oparams->alen);
192        }
193        if(flags & SASL_CU_AUTHZID) {
194            _sasl_auxprop_lookup(sconn->sparams, SASL_AUXPROP_AUTHZID,
195                                 oparams->user, oparams->ulen);
196        }
197    }
198#endif
199
200
201    RETURN(conn, SASL_OK);
202}
203
204void _sasl_canonuser_free()
205{
206    canonuser_plug_list_t *ptr, *ptr_next;
207   
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,
212                                       sasl_global_utils);
213        sasl_FREE(ptr);
214    }
215
216    canonuser_head = NULL;
217}
218
219int sasl_canonuser_add_plugin(const char *plugname,
220                              sasl_canonuser_init_t *canonuserfunc)
221{
222    int result, out_version;
223    canonuser_plug_list_t *new_item;
224    sasl_canonuser_plug_t *plug;
225
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;
230    }
231   
232    result = canonuserfunc(sasl_global_utils, SASL_CANONUSER_PLUG_VERSION,
233                           &out_version, &plug, plugname);
234
235    if(result != SASL_OK) {
236        _sasl_log(NULL, SASL_LOG_ERR, "canonuserfunc error %i\n",result);
237        return result;
238    }
239
240    if(!plug->canon_user_server && !plug->canon_user_client) {
241        /* We need atleast one of these implemented */
242        _sasl_log(NULL, SASL_LOG_ERR,
243                  "canonuser plugin without either client or server side");
244        return SASL_BADPROT;
245    }
246   
247    new_item = sasl_ALLOC(sizeof(canonuser_plug_list_t));
248    if(!new_item) return SASL_NOMEM;
249
250    strncpy(new_item->name, plugname, PATH_MAX);
251
252    new_item->plug = plug;
253    new_item->next = canonuser_head;
254    canonuser_head = new_item;
255
256    return SASL_OK;
257}
258
259#ifdef MIN
260#undef MIN
261#endif
262#define MIN(a,b) (((a) < (b))? (a):(b))
263
264static int _canonuser_internal(const sasl_utils_t *utils,
265                               const char *user, unsigned ulen,
266                               unsigned flags __attribute__((unused)),
267                               char *out_user,
268                               unsigned out_umax, unsigned *out_ulen)
269{
270    unsigned i;
271    char *in_buf, *userin;
272    const char *begin_u;
273    unsigned u_apprealm = 0;
274    sasl_server_conn_t *sconn = NULL;
275
276    if(!utils || !user) return SASL_BADPARAM;
277
278    in_buf = sasl_ALLOC((ulen + 2) * sizeof(char));
279    if(!in_buf) return SASL_NOMEM;
280
281    userin = in_buf;
282
283    memcpy(userin, user, ulen);
284    userin[ulen] = '\0';
285   
286    /* Strip User ID */
287    for(i=0;isspace((int)userin[i]) && i<ulen;i++);
288    begin_u = &(userin[i]);
289    if(i>0) ulen -= i;
290
291    for(;ulen > 0 && isspace((int)begin_u[ulen-1]); ulen--);
292    if(begin_u == &(userin[ulen])) {
293        sasl_FREE(in_buf);
294        utils->seterror(utils->conn, 0, "All-whitespace username.");
295        return SASL_FAIL;
296    }
297
298    if(utils->conn && utils->conn->type == SASL_CONN_SERVER)
299        sconn = (sasl_server_conn_t *)utils->conn;
300
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;
304    }
305   
306    /* Now Copy */
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));
313    }
314    out_user[MIN(ulen + u_apprealm,out_umax)] = '\0';
315
316    if(ulen + u_apprealm > out_umax) return SASL_BUFOVER;
317
318    if(out_ulen) *out_ulen = MIN(ulen + u_apprealm,out_umax);
319   
320    sasl_FREE(in_buf);
321    return SASL_OK;
322}
323
324static int _cu_internal_server(void *glob_context __attribute__((unused)),
325                               sasl_server_params_t *sparams,
326                               const char *user, unsigned ulen,
327                               unsigned flags,
328                               char *out_user,
329                               unsigned out_umax, unsigned *out_ulen)
330{
331    return _canonuser_internal(sparams->utils,
332                               user, ulen,
333                               flags, out_user, out_umax, out_ulen);
334}
335
336static int _cu_internal_client(void *glob_context __attribute__((unused)),
337                               sasl_client_params_t *cparams,
338                               const char *user, unsigned ulen,
339                               unsigned flags,
340                               char *out_user,
341                               unsigned out_umax, unsigned *out_ulen)
342{
343    return _canonuser_internal(cparams->utils,
344                               user, ulen,
345                               flags, out_user, out_umax, out_ulen);
346}
347
348static sasl_canonuser_plug_t canonuser_internal_plugin = {
349        0, /* features */
350        0, /* spare */
351        NULL, /* glob_context */
352        "INTERNAL", /* name */
353        NULL, /* canon_user_free */
354        _cu_internal_server,
355        _cu_internal_client,
356        NULL,
357        NULL,
358        NULL
359};
360
361int internal_canonuser_init(const sasl_utils_t *utils __attribute__((unused)),
362                            int max_version,
363                            int *out_version,
364                            sasl_canonuser_plug_t **plug,
365                            const char *plugname __attribute__((unused)))
366{
367    if(!out_version || !plug) return SASL_BADPARAM;
368
369    if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
370   
371    *out_version = SASL_CANONUSER_PLUG_VERSION;
372
373    *plug = &canonuser_internal_plugin;
374
375    return SASL_OK;
376}
Note: See TracBrowser for help on using the repository browser.