X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=plugins%2Fgs2.c;h=5afe7bbbe1a96412424268cd538c2fba1a6e9c85;hb=5a0b9a5b556773b6c28e49f6a046c0eef79b106c;hp=917d9ed570664875d6cd7aab2d5c43fca1047822;hpb=09a5fa52cfa9afbe80a631f7ad12dc972c160cf0;p=cyrus-sasl.git diff --git a/plugins/gs2.c b/plugins/gs2.c index 917d9ed..5afe7bb 100644 --- a/plugins/gs2.c +++ b/plugins/gs2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 PADL Software Pty Ltd. + * Copyright (c) 2010, JANET(UK) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -13,28 +13,21 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * 3. Redistributions in any form must be accompanied by information on - * how to obtain complete source code for the GS2 software and any - * accompanying software that uses the GS2 software. The source code - * must either be included in the distribution or be available for no - * more than the cost of distribution plus a nominal fee, and must be - * freely redistributable under reasonable conditions. For an - * executable file, complete source code means the source code for all - * modules it contains. It does not include source code for modules or - * files that typically accompany the major components of the operating - * system on which the executable file runs. + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ /* * Copyright (c) 1998-2003 Carnegie Mellon University. @@ -79,7 +72,9 @@ #include #include +#ifdef HAVE_GSSAPI_GSSAPI_EXT_H #include +#endif #include #include #include @@ -128,11 +123,10 @@ typedef struct context { static gss_OID_set gs2_mechs = GSS_C_NO_OID_SET; -static int gs2_ask_user_info(context_t *context, - sasl_client_params_t *params, - char **realms, int nrealm, - sasl_interact_t **prompt_need, - sasl_out_params_t *oparams); +static int gs2_get_init_creds(context_t *context, + sasl_client_params_t *params, + sasl_interact_t **prompt_need, + sasl_out_params_t *oparams); static int gs2_verify_initial_message(context_t *text, sasl_server_params_t *sparams, @@ -193,7 +187,7 @@ sasl_gs2_new_context(const sasl_utils_t *utils) context_t *ret; ret = utils->malloc(sizeof(context_t)); - if (!ret) + if (ret == NULL) return NULL; memset(ret, 0, sizeof(context_t)); @@ -572,12 +566,12 @@ gs2_common_plug_init(const sasl_utils_t *utils, return SASL_NOMECH; } - plugs = utils->malloc(2 * gs2_mechs->count * plugsize); + plugs = utils->malloc(gs2_mechs->count * plugsize); if (plugs == NULL) { MEMERROR(utils); return SASL_NOMEM; } - memset(plugs, 0, 2 * gs2_mechs->count * plugsize); + memset(plugs, 0, gs2_mechs->count * plugsize); for (i = 0; i < gs2_mechs->count; i++) { gss_buffer_desc sasl_mech_name = GSS_C_EMPTY_BUFFER; @@ -703,11 +697,10 @@ static int gs2_client_mech_step(void *conn_context, *clientoutlen = 0; if (text->gss_ctx == GSS_C_NO_CONTEXT) { - ret = gs2_ask_user_info(text, params, NULL, 0, prompt_need, oparams); + ret = gs2_get_init_creds(text, params, prompt_need, oparams); if (ret != SASL_OK) goto cleanup; - initialContextToken = 1; } else initialContextToken = 0; @@ -729,10 +722,10 @@ static int gs2_client_mech_step(void *conn_context, snprintf(name_buf.value, name_buf.length + 1, "%s@%s", params->service, params->serverFQDN); - maj_stat = gss_import_name (&min_stat, - &name_buf, - GSS_C_NT_HOSTBASED_SERVICE, - &text->server_name); + maj_stat = gss_import_name(&min_stat, + &name_buf, + GSS_C_NT_HOSTBASED_SERVICE, + &text->server_name); params->utils->free(name_buf.value); name_buf.value = NULL; @@ -1490,55 +1483,153 @@ gs2_escape_authzid(const sasl_utils_t *utils, return SASL_OK; } +#define GOT_CREDS(text, params) ((text)->client_creds != NULL || (params)->gss_creds != NULL) +#define CRED_ERROR(status) ((status) == GSS_S_CRED_UNAVAIL || (status) == GSS_S_NO_CRED) + +/* + * Determine the authentication identity from the application supplied + * GSS credential, the application supplied identity, and the default + * GSS credential, in that order. Then, acquire credentials. + */ static int -gs2_ask_user_info(context_t *text, - sasl_client_params_t *params, - char **realms __attribute__((unused)), - int nrealm __attribute__((unused)), - sasl_interact_t **prompt_need, - sasl_out_params_t *oparams) +gs2_get_init_creds(context_t *text, + sasl_client_params_t *params, + sasl_interact_t **prompt_need, + sasl_out_params_t *oparams) { int result = SASL_OK; const char *authid = NULL, *userid = NULL; int user_result = SASL_OK; int auth_result = SASL_OK; int pass_result = SASL_OK; - OM_uint32 maj_stat, min_stat; - gss_buffer_desc authid_buf = GSS_C_EMPTY_BUFFER; + OM_uint32 maj_stat = GSS_S_COMPLETE, min_stat = 0; gss_OID_set_desc mechs; + gss_buffer_desc cred_authid = GSS_C_EMPTY_BUFFER; + gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER; - /* try to get the authid */ + mechs.count = 1; + mechs.elements = (gss_OID)text->mechanism; + + /* + * Get the authentication identity from the application. + */ if (oparams->authid == NULL) { auth_result = _plug_get_authid(params->utils, &authid, prompt_need); - if (auth_result != SASL_OK && auth_result != SASL_INTERACT) - return auth_result; + if (auth_result != SASL_OK && auth_result != SASL_INTERACT) { + result = auth_result; + goto cleanup; + } } - /* try to get the userid */ + /* + * Get the authorization identity from the application. + */ if (oparams->user == NULL) { user_result = _plug_get_userid(params->utils, &userid, prompt_need); - - if (user_result != SASL_OK && user_result != SASL_INTERACT) - return user_result; + if (user_result != SASL_OK && user_result != SASL_INTERACT) { + result = user_result; + goto cleanup; + } } - mechs.count = 1; - mechs.elements = (gss_OID)text->mechanism; + /* + * Canonicalize the authentication and authorization identities before + * calling GSS_Import_name. + */ + if (auth_result == SASL_OK && user_result == SASL_OK && + oparams->authid == NULL) { + if (userid == NULL || userid[0] == '\0') { + result = params->canon_user(params->utils->conn, authid, 0, + SASL_CU_AUTHID | SASL_CU_AUTHZID, + oparams); + } else { + result = params->canon_user(params->utils->conn, + authid, 0, SASL_CU_AUTHID, oparams); + if (result != SASL_OK) + goto cleanup; - if (authid != NULL) { - authid_buf.length = strlen(authid); - authid_buf.value = (void *)authid; + result = params->canon_user(params->utils->conn, + userid, 0, SASL_CU_AUTHZID, oparams); + if (result != SASL_OK) + goto cleanup; + } + + if (oparams->authid != NULL) { + name_buf.length = strlen(oparams->authid); + name_buf.value = (void *)oparams->authid; + + assert(text->client_name == GSS_C_NO_NAME); + + maj_stat = gss_import_name(&min_stat, + &name_buf, + GSS_C_NT_USER_NAME, + &text->client_name); + if (GSS_ERROR(maj_stat)) + goto cleanup; + } } - if (params->gss_creds == GSS_C_NO_CREDENTIAL && authid != NULL) { - maj_stat = gss_import_name(&min_stat, &authid_buf, - GSS_C_NT_USER_NAME, &text->client_name); - if (GSS_ERROR(maj_stat)) { - sasl_gs2_seterror(text->utils, maj_stat, min_stat); - return SASL_FAIL; + /* + * If application didn't provide an authid, then use the default + * credential. If that doesn't work, give up. + */ + if (!GOT_CREDS(text, params) && oparams->authid == NULL) { + maj_stat = gss_acquire_cred(&min_stat, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + &mechs, + GSS_C_INITIATE, + &text->client_creds, + NULL, + &text->lifetime); + if (GSS_ERROR(maj_stat)) + goto cleanup; + + assert(text->client_name == GSS_C_NO_NAME); + + maj_stat = gss_inquire_cred(&min_stat, + params->gss_creds + ? (gss_cred_id_t)params->gss_creds + : text->client_creds, + &text->client_name, + NULL, + NULL, + NULL); + if (GSS_ERROR(maj_stat)) + goto cleanup; + + maj_stat = gss_display_name(&min_stat, + text->client_name, + &cred_authid, + NULL); + if (GSS_ERROR(maj_stat)) + goto cleanup; + + if (userid == NULL || userid[0] == '\0') { + result = params->canon_user(params->utils->conn, + cred_authid.value, cred_authid.length, + SASL_CU_AUTHID | SASL_CU_AUTHZID, + oparams); + } else { + result = params->canon_user(params->utils->conn, + cred_authid.value, cred_authid.length, + SASL_CU_AUTHID, oparams); + if (result != SASL_OK) + goto cleanup; + + result = params->canon_user(params->utils->conn, + cred_authid.value, cred_authid.length, + SASL_CU_AUTHZID, oparams); + if (result != SASL_OK) + goto cleanup; } + } - /* See if we have a default credential */ + /* + * Armed with the authentication identity, try to get a credential without + * a password. + */ + if (!GOT_CREDS(text, params) && text->client_name != GSS_C_NO_NAME) { maj_stat = gss_acquire_cred(&min_stat, text->client_name, GSS_C_INDEFINITE, @@ -1547,22 +1638,24 @@ gs2_ask_user_info(context_t *text, &text->client_creds, NULL, &text->lifetime); - if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CRED_UNAVAIL) { - sasl_gs2_seterror(text->utils, maj_stat, min_stat); - return SASL_FAIL; - } + if (GSS_ERROR(maj_stat) && !CRED_ERROR(maj_stat)) + goto cleanup; } - /* try to get the password, only if necessary */ - if (text->password == NULL && - params->gss_creds == GSS_C_NO_CREDENTIAL && - text->client_creds == GSS_C_NO_CREDENTIAL) { - pass_result = _plug_get_password(params->utils, &text->password, - &text->free_password, prompt_need); - if (pass_result != SASL_OK && pass_result != SASL_INTERACT) - return pass_result; + /* + * If that failed, try to get a credential with a password. + */ + if (!GOT_CREDS(text, params)) { + if (text->password == NULL) { + pass_result = _plug_get_password(params->utils, &text->password, + &text->free_password, prompt_need); + if (pass_result != SASL_OK && pass_result != SASL_INTERACT) { + result = pass_result; + goto cleanup; + } + } - if (text->password != NULL && text->password->len != 0) { + if (text->password != NULL) { gss_buffer_desc password_buf; password_buf.length = text->password->len; @@ -1577,13 +1670,13 @@ gs2_ask_user_info(context_t *text, &text->client_creds, NULL, &text->lifetime); - if (GSS_ERROR(maj_stat)) { - sasl_gs2_seterror(text->utils, maj_stat, min_stat); - return SASL_FAIL; - } + if (GSS_ERROR(maj_stat)) + goto cleanup; } } + maj_stat = GSS_S_COMPLETE; + /* free prompts we got */ if (prompt_need && *prompt_need) { params->utils->free(*prompt_need); @@ -1593,7 +1686,6 @@ gs2_ask_user_info(context_t *text, /* if there are prompts not filled in */ if (user_result == SASL_INTERACT || auth_result == SASL_INTERACT || pass_result == SASL_INTERACT) { - /* make the prompt list */ result = _plug_make_prompts(params->utils, prompt_need, @@ -1609,29 +1701,17 @@ gs2_ask_user_info(context_t *text, NULL, NULL, NULL); if (result == SASL_OK) - return SASL_INTERACT; - - return result; + result = SASL_INTERACT; } - if (oparams->authid == NULL) { - if (userid == NULL || userid[0] == '\0') { - result = params->canon_user(params->utils->conn, authid, 0, - SASL_CU_AUTHID | SASL_CU_AUTHZID, - oparams); - } else { - result = params->canon_user(params->utils->conn, - authid, 0, SASL_CU_AUTHID, oparams); - if (result != SASL_OK) - return result; - - result = params->canon_user(params->utils->conn, - userid, 0, SASL_CU_AUTHZID, oparams); - } - if (result != SASL_OK) - return result; +cleanup: + if (result == SASL_OK && maj_stat != GSS_S_COMPLETE) { + sasl_gs2_seterror(text->utils, maj_stat, min_stat); + result = SASL_FAIL; } + gss_release_buffer(&min_stat, &cred_authid); + return result; } @@ -1645,7 +1725,7 @@ sasl_gs2_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min, int ret; char *out = NULL; unsigned int len, curlen = 0; - const char prefix[] = "GSSAPI Error: "; + const char prefix[] = "GS2 Error: "; len = sizeof(prefix); ret = _plug_buf_alloc(utils, &out, &curlen, 256);