123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 |
- /* canonusr.c - user canonicalization support
- * Rob Siemborski
- */
- /*
- * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The name "Carnegie Mellon University" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For permission or any other legal
- * details, please contact
- * Carnegie Mellon University
- * Center for Technology Transfer and Enterprise Creation
- * 4615 Forbes Avenue
- * Suite 302
- * Pittsburgh, PA 15213
- * (412) 268-7393, fax: (412) 268-7395
- * innovation@andrew.cmu.edu
- *
- * 4. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by Computing Services
- * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
- *
- * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
- * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
- * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <config.h>
- #include <sasl.h>
- #include <string.h>
- #include <ctype.h>
- #include <prop.h>
- #include <stdio.h>
- #include "saslint.h"
- typedef struct canonuser_plug_list
- {
- struct canonuser_plug_list *next;
- char name[PATH_MAX];
- const sasl_canonuser_plug_t *plug;
- } canonuser_plug_list_t;
- static canonuser_plug_list_t *canonuser_head = NULL;
- /* default behavior:
- * eliminate leading & trailing whitespace,
- * null-terminate, and get into the outparams
- * (handled by INTERNAL plugin) */
- /* a zero ulen or alen indicates that it is strlen(value) */
- int _sasl_canon_user(sasl_conn_t *conn,
- const char *user, unsigned ulen,
- unsigned flags,
- sasl_out_params_t *oparams)
- {
- canonuser_plug_list_t *ptr;
- sasl_server_conn_t *sconn = NULL;
- sasl_client_conn_t *cconn = NULL;
- sasl_canon_user_t *cuser_cb;
- sasl_getopt_t *getopt;
- void *context;
- int result;
- const char *plugin_name = NULL;
- char *user_buf;
- unsigned *lenp;
- if(!conn) return SASL_BADPARAM;
- if(!user || !oparams) return SASL_BADPARAM;
- if(flags & SASL_CU_AUTHID) {
- user_buf = conn->authid_buf;
- lenp = &(oparams->alen);
- } else if (flags & SASL_CU_AUTHZID) {
- user_buf = conn->user_buf;
- lenp = &(oparams->ulen);
- } else {
- return SASL_BADPARAM;
- }
-
- if (conn->type == SASL_CONN_SERVER)
- sconn = (sasl_server_conn_t *)conn;
- else if (conn->type == SASL_CONN_CLIENT)
- cconn = (sasl_client_conn_t *)conn;
- else return SASL_FAIL;
-
- if(!ulen) ulen = (unsigned int)strlen(user);
-
- /* check to see if we have a callback to make*/
- result = _sasl_getcallback(conn,
- SASL_CB_CANON_USER,
- (sasl_callback_ft *)&cuser_cb,
- &context);
- if(result == SASL_OK && cuser_cb) {
- result = cuser_cb(conn,
- context,
- user,
- ulen,
- flags,
- (sconn ?
- sconn->user_realm :
- NULL),
- user_buf,
- CANON_BUF_SIZE,
- lenp);
-
- if (result != SASL_OK) return result;
- /* Point the input copy at the stored buffer */
- user = user_buf;
- ulen = *lenp;
- }
- /* which plugin are we supposed to use? */
- result = _sasl_getcallback(conn,
- SASL_CB_GETOPT,
- (sasl_callback_ft *)&getopt,
- &context);
- if (result == SASL_OK && getopt) {
- getopt(context, NULL, "canon_user_plugin", &plugin_name, NULL);
- }
- if (!plugin_name) {
- /* Use Default */
- plugin_name = "INTERNAL";
- }
-
- for (ptr = canonuser_head; ptr; ptr = ptr->next) {
- /* A match is if we match the internal name of the plugin, or if
- * we match the filename (old-style) */
- if ((ptr->plug->name && !strcmp(plugin_name, ptr->plug->name))
- || !strcmp(plugin_name, ptr->name)) break;
- }
- /* We clearly don't have this one! */
- if (!ptr) {
- sasl_seterror(conn, 0, "desired canon_user plugin %s not found",
- plugin_name);
- return SASL_NOMECH;
- }
-
- if (sconn) {
- /* we're a server */
- result = ptr->plug->canon_user_server(ptr->plug->glob_context,
- sconn->sparams,
- user, ulen,
- flags,
- user_buf,
- CANON_BUF_SIZE, lenp);
- } else {
- /* we're a client */
- result = ptr->plug->canon_user_client(ptr->plug->glob_context,
- cconn->cparams,
- user, ulen,
- flags,
- user_buf,
- CANON_BUF_SIZE, lenp);
- }
- if (result != SASL_OK) return result;
- if ((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) {
- /* We did both, so we need to copy the result into
- * the buffer for the authzid from the buffer for the authid */
- memcpy(conn->user_buf, conn->authid_buf, CANON_BUF_SIZE);
- oparams->ulen = oparams->alen;
- }
-
- /* Set the appropriate oparams (lengths have already been set by lenp) */
- if (flags & SASL_CU_AUTHID) {
- oparams->authid = conn->authid_buf;
- }
- if (flags & SASL_CU_AUTHZID) {
- oparams->user = conn->user_buf;
- }
- RETURN(conn, result);
- }
- /* Lookup all properties for authentication and/or authorization identity. */
- static int _sasl_auxprop_lookup_user_props (sasl_conn_t *conn,
- unsigned flags,
- sasl_out_params_t *oparams)
- {
- sasl_server_conn_t *sconn = NULL;
- int result = SASL_OK;
- if (!conn) return SASL_BADPARAM;
- if (!oparams) return SASL_BADPARAM;
- #ifndef macintosh
- if (conn->type == SASL_CONN_SERVER) sconn = (sasl_server_conn_t *)conn;
- /* do auxprop lookups (server only) */
- if (sconn) {
- int authz_result;
- unsigned auxprop_lookup_flags = flags & SASL_CU_ASIS_MASK;
- if (flags & SASL_CU_OVERRIDE) {
- auxprop_lookup_flags |= SASL_AUXPROP_OVERRIDE;
- }
- if (flags & SASL_CU_AUTHID) {
- result = _sasl_auxprop_lookup(sconn->sparams,
- auxprop_lookup_flags,
- oparams->authid,
- oparams->alen);
- } else {
- result = SASL_CONTINUE;
- }
- if (flags & SASL_CU_AUTHZID) {
- authz_result = _sasl_auxprop_lookup(sconn->sparams,
- auxprop_lookup_flags | SASL_AUXPROP_AUTHZID,
- oparams->user,
- oparams->ulen);
- if (result == SASL_CONTINUE) {
- /* Only SASL_CU_AUTHZID was requested.
- The authz_result value is authoritative. */
- result = authz_result;
- } else if (result == SASL_OK && authz_result != SASL_NOUSER) {
- /* Use the authz_result value, unless "result"
- already contains an error */
- result = authz_result;
- }
- }
- if ((flags & SASL_CU_EXTERNALLY_VERIFIED) && (result == SASL_NOUSER || result == SASL_NOMECH)) {
- /* The called has explicitly told us that the authentication identity
- was already verified or will be verified independently.
- So a failure to retrieve any associated properties
- is not an error. For example the caller is using Kerberos to verify user,
- but the LDAPDB/SASLDB auxprop plugin doesn't contain any auxprops for
- the user.
- Another case is PLAIN/LOGIN not using auxprop to verify user passwords. */
- result = SASL_OK;
- }
- }
- #endif
- RETURN(conn, result);
- }
- /* default behavior:
- * Eliminate leading & trailing whitespace,
- * null-terminate, and get into the outparams
- * (handled by INTERNAL plugin).
- *
- * Server only: Also does auxprop lookups once username
- * is canonicalized. */
- int _sasl_canon_user_lookup (sasl_conn_t *conn,
- const char *user,
- unsigned ulen,
- unsigned flags,
- sasl_out_params_t *oparams)
- {
- int result;
- result = _sasl_canon_user (conn,
- user,
- ulen,
- flags,
- oparams);
- if (result == SASL_OK) {
- result = _sasl_auxprop_lookup_user_props (conn,
- flags,
- oparams);
- }
- RETURN(conn, result);
- }
- void _sasl_canonuser_free()
- {
- canonuser_plug_list_t *ptr, *ptr_next;
-
- for(ptr = canonuser_head; ptr; ptr = ptr_next) {
- ptr_next = ptr->next;
- if(ptr->plug->canon_user_free)
- ptr->plug->canon_user_free(ptr->plug->glob_context,
- sasl_global_utils);
- sasl_FREE(ptr);
- }
- canonuser_head = NULL;
- }
- int sasl_canonuser_add_plugin(const char *plugname,
- sasl_canonuser_init_t *canonuserfunc)
- {
- int result, out_version;
- canonuser_plug_list_t *new_item;
- sasl_canonuser_plug_t *plug;
- if(!plugname || strlen(plugname) > (PATH_MAX - 1)) {
- sasl_seterror(NULL, 0,
- "bad plugname passed to sasl_canonuser_add_plugin\n");
- return SASL_BADPARAM;
- }
-
- result = canonuserfunc(sasl_global_utils, SASL_CANONUSER_PLUG_VERSION,
- &out_version, &plug, plugname);
- if(result != SASL_OK) {
- _sasl_log(NULL, SASL_LOG_ERR, "%s_canonuser_plug_init() failed in sasl_canonuser_add_plugin(): %z\n",
- plugname, result);
- return result;
- }
- if(!plug->canon_user_server && !plug->canon_user_client) {
- /* We need at least one of these implemented */
- _sasl_log(NULL, SASL_LOG_ERR,
- "canonuser plugin '%s' without either client or server side", plugname);
- return SASL_BADPROT;
- }
-
- new_item = sasl_ALLOC(sizeof(canonuser_plug_list_t));
- if(!new_item) return SASL_NOMEM;
- strncpy(new_item->name, plugname, PATH_MAX - 1);
- new_item->name[strlen(plugname)] = '\0';
- new_item->plug = plug;
- new_item->next = canonuser_head;
- canonuser_head = new_item;
- return SASL_OK;
- }
- #ifdef MIN
- #undef MIN
- #endif
- #define MIN(a,b) (((a) < (b))? (a):(b))
- static int _canonuser_internal(const sasl_utils_t *utils,
- const char *user, unsigned ulen,
- unsigned flags __attribute__((unused)),
- char *out_user,
- unsigned out_umax, unsigned *out_ulen)
- {
- unsigned i;
- char *in_buf, *userin;
- const char *begin_u;
- unsigned u_apprealm = 0;
- sasl_server_conn_t *sconn = NULL;
- if(!utils || !user) return SASL_BADPARAM;
- in_buf = sasl_ALLOC((ulen + 2) * sizeof(char));
- if(!in_buf) return SASL_NOMEM;
- userin = in_buf;
- memcpy(userin, user, ulen);
- userin[ulen] = '\0';
-
- /* Strip User ID */
- for(i=0;isspace((int)userin[i]) && i<ulen;i++);
- begin_u = &(userin[i]);
- if(i>0) ulen -= i;
- for(;ulen > 0 && isspace((int)begin_u[ulen-1]); ulen--);
- if(begin_u == &(userin[ulen])) {
- sasl_FREE(in_buf);
- utils->seterror(utils->conn, 0, "All-whitespace username.");
- return SASL_FAIL;
- }
- if(utils->conn && utils->conn->type == SASL_CONN_SERVER)
- sconn = (sasl_server_conn_t *)utils->conn;
- /* Need to append realm if necessary (see sasl.h) */
- if(sconn && sconn->user_realm && !strchr(user, '@')) {
- u_apprealm = (unsigned) strlen(sconn->user_realm) + 1;
- }
-
- /* Now Copy */
- memcpy(out_user, begin_u, MIN(ulen, out_umax));
- if(sconn && u_apprealm) {
- if(ulen >= out_umax) return SASL_BUFOVER;
- out_user[ulen] = '@';
- memcpy(&(out_user[ulen+1]), sconn->user_realm,
- MIN(u_apprealm-1, out_umax-ulen-1));
- }
- out_user[MIN(ulen + u_apprealm,out_umax)] = '\0';
- if(ulen + u_apprealm > out_umax) return SASL_BUFOVER;
- if(out_ulen) *out_ulen = MIN(ulen + u_apprealm,out_umax);
-
- sasl_FREE(in_buf);
- return SASL_OK;
- }
- static int _cu_internal_server(void *glob_context __attribute__((unused)),
- sasl_server_params_t *sparams,
- const char *user, unsigned ulen,
- unsigned flags,
- char *out_user,
- unsigned out_umax, unsigned *out_ulen)
- {
- return _canonuser_internal(sparams->utils,
- user, ulen,
- flags, out_user, out_umax, out_ulen);
- }
- static int _cu_internal_client(void *glob_context __attribute__((unused)),
- sasl_client_params_t *cparams,
- const char *user, unsigned ulen,
- unsigned flags,
- char *out_user,
- unsigned out_umax, unsigned *out_ulen)
- {
- return _canonuser_internal(cparams->utils,
- user, ulen,
- flags, out_user, out_umax, out_ulen);
- }
- static sasl_canonuser_plug_t canonuser_internal_plugin = {
- 0, /* features */
- 0, /* spare */
- NULL, /* glob_context */
- "INTERNAL", /* name */
- NULL, /* canon_user_free */
- _cu_internal_server,
- _cu_internal_client,
- NULL,
- NULL,
- NULL
- };
- int internal_canonuser_init(const sasl_utils_t *utils __attribute__((unused)),
- int max_version,
- int *out_version,
- sasl_canonuser_plug_t **plug,
- const char *plugname __attribute__((unused)))
- {
- if(!out_version || !plug) return SASL_BADPARAM;
- if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
-
- *out_version = SASL_CANONUSER_PLUG_VERSION;
- *plug = &canonuser_internal_plugin;
- return SASL_OK;
- }
|