X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=plugins%2Fgs2.c;h=6e102adcbde58cd8e7db15a1961fc935f7fedd57;hb=93c0b2dd62f05032895aefedf36c6ef48033d5ca;hp=5b8706239a43953c14569e50bf29d6c3e78de384;hpb=96935f443c908e1e751a25bd91ea4640969fd9cb;p=cyrus-sasl.git diff --git a/plugins/gs2.c b/plugins/gs2.c index 5b87062..6e102ad 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 @@ -192,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)); @@ -445,11 +440,6 @@ gs2_server_mech_step(void *conn_context, assert(maj_stat == GSS_S_COMPLETE); - if ((out_flags & GSS_C_SEQUENCE_FLAG) == 0) { - ret = SASL_BADAUTH; - goto cleanup; - } - maj_stat = gss_display_name(&min_stat, text->client_name, &name_buf, NULL); if (GSS_ERROR(maj_stat)) @@ -544,7 +534,7 @@ cleanup: sasl_gs2_seterror(text->utils, maj_stat, min_stat); ret = SASL_FAIL; } - if (ret != SASL_OK && ret != SASL_CONTINUE) + if (ret < SASL_OK) sasl_gs2_free_context_contents(text); return ret; @@ -571,12 +561,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; @@ -694,7 +684,7 @@ static int gs2_client_mech_step(void *conn_context, gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER; OM_uint32 maj_stat = GSS_S_FAILURE, min_stat = 0; - OM_uint32 req_flags, ret_flags; + OM_uint32 ret_flags; int ret = SASL_FAIL; int initialContextToken; @@ -771,8 +761,6 @@ static int gs2_client_mech_step(void *conn_context, goto cleanup; } - req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG; - maj_stat = gss_init_sec_context(&min_stat, (params->gss_creds != GSS_C_NO_CREDENTIAL) ? (gss_cred_id_t)params->gss_creds @@ -780,7 +768,7 @@ static int gs2_client_mech_step(void *conn_context, &text->gss_ctx, text->server_name, (gss_OID)text->mechanism, - req_flags, + GSS_C_MUTUAL_FLAG, GSS_C_INDEFINITE, &text->gss_cbindings, serverinlen ? &input_token : GSS_C_NO_BUFFER, @@ -819,7 +807,8 @@ static int gs2_client_mech_step(void *conn_context, if (GSS_ERROR(maj_stat)) goto cleanup; - if ((ret_flags & req_flags) != req_flags) { + if (params->cbindingdisp != SASL_CB_DISP_NONE && + (ret_flags & GSS_C_MUTUAL_FLAG) == 0) { maj_stat = SASL_BADAUTH; goto cleanup; } @@ -847,7 +836,7 @@ cleanup: sasl_gs2_seterror(text->utils, maj_stat, min_stat); ret = SASL_FAIL; } - if (ret != SASL_OK && ret != SASL_CONTINUE) + if (ret < SASL_OK) sasl_gs2_free_context_contents(text); return ret; @@ -1018,6 +1007,7 @@ gs2_verify_initial_message(context_t *text, unsigned inlen, gss_buffer_t token) { + OM_uint32 major, minor; char *p = (char *)in; unsigned remain = inlen; int ret; @@ -1093,32 +1083,29 @@ gs2_verify_initial_message(context_t *text, if (ret != SASL_OK) return ret; - buf.length = remain; - buf.value = p; - if (text->gs2_flags & GS2_NONSTD_FLAG) { - token->value = text->utils->malloc(buf.length); - if (token->value == NULL) - return SASL_NOMEM; - - token->length = buf.length; - memcpy(token->value, buf.value, buf.length); + buf.length = remain; + buf.value = p; } else { - unsigned int token_size; + gss_buffer_desc tmp; - /* create a properly formed GSS token */ - token_size = gs2_token_size(text->mechanism, buf.length); - token->value = text->utils->malloc(token_size); - if (token->value == NULL) + tmp.length = remain; + tmp.value = p; + + major = gss_encapsulate_token(&tmp, text->mechanism, &buf); + if (GSS_ERROR(major)) return SASL_NOMEM; + } - token->length = token_size; + token->value = text->utils->malloc(buf.length); + if (token->value == NULL) + return SASL_NOMEM; - p = (char *)token->value; - gs2_make_token_header(text->mechanism, buf.length, - (unsigned char **)&p); - memcpy(p, buf.value, buf.length); - } + token->length = buf.length; + memcpy(token->value, buf.value, buf.length); + + if ((text->gs2_flags & GS2_NONSTD_FLAG) == 0) + gss_release_buffer(&minor, &buf); return SASL_OK; } @@ -1236,36 +1223,32 @@ gs2_make_message(context_t *text, unsigned *outlen) { OM_uint32 major, minor; - unsigned char *mech_token_data; - size_t mech_token_size; - char *p; - unsigned header_len = 0; int ret; - - mech_token_size = token->length; - mech_token_data = (unsigned char *)token->value; + unsigned header_len = 0; + gss_buffer_desc decap_token = GSS_C_EMPTY_BUFFER; if (initialContextToken) { header_len = *outlen; - major = gs2_verify_token_header(&minor, text->mechanism, - &mech_token_size, &mech_token_data, - token->length); + major = gss_decapsulate_token(token, text->mechanism, &decap_token); if ((major == GSS_S_DEFECTIVE_TOKEN && (text->plug.client->features & SASL_FEAT_GSS_FRAMING)) || GSS_ERROR(major)) return SASL_FAIL; + + token = &decap_token; } ret = _plug_buf_alloc(text->utils, out, outlen, - header_len + mech_token_size); + header_len + token->length); if (ret != 0) return ret; - p = *out + header_len; - memcpy(p, mech_token_data, mech_token_size); + memcpy(*out + header_len, token->value, token->length); + *outlen = header_len + token->length; - *outlen = header_len + mech_token_size; + if (initialContextToken) + gss_release_buffer(&minor, &decap_token); return SASL_OK; } @@ -1296,7 +1279,7 @@ gs2_get_mech_attrs(const sasl_utils_t *utils, } *security_flags = SASL_SEC_NOPLAINTEXT | SASL_SEC_NOACTIVE; - *features = SASL_FEAT_WANT_CLIENT_FIRST | SASL_FEAT_CHANNEL_BINDING; + *features = SASL_FEAT_WANT_CLIENT_FIRST; if (prompts != NULL) *prompts = gs2_required_prompts; @@ -1310,8 +1293,10 @@ gs2_get_mech_attrs(const sasl_utils_t *utils, *security_flags |= SASL_SEC_NOANONYMOUS; if (MA_PRESENT(GSS_C_MA_DELEG_CRED)) *security_flags |= SASL_SEC_PASS_CREDENTIALS; - if (MA_PRESENT(GSS_C_MA_AUTH_TARG)) + if (MA_PRESENT(GSS_C_MA_AUTH_TARG)) { + *features |= SASL_FEAT_CHANNEL_BINDING; *security_flags |= SASL_SEC_MUTUAL_AUTH; + } if (MA_PRESENT(GSS_C_MA_AUTH_INIT_INIT) && prompts != NULL) *prompts = NULL; if (MA_PRESENT(GSS_C_MA_ITOK_FRAMED)) @@ -1328,7 +1313,7 @@ gs2_get_mech_attrs(const sasl_utils_t *utils, static int gs2_indicate_mechs(const sasl_utils_t *utils) { OM_uint32 major, minor; - gss_OID_desc desired_oids[3]; + gss_OID_desc desired_oids[2]; gss_OID_set_desc desired_attrs; gss_OID_desc except_oids[3]; gss_OID_set_desc except_attrs; @@ -1337,8 +1322,7 @@ static int gs2_indicate_mechs(const sasl_utils_t *utils) return SASL_OK; desired_oids[0] = *GSS_C_MA_AUTH_INIT; - desired_oids[1] = *GSS_C_MA_AUTH_TARG; - desired_oids[2] = *GSS_C_MA_CBINDINGS; + desired_oids[1] = *GSS_C_MA_CBINDINGS; desired_attrs.count = sizeof(desired_oids)/sizeof(desired_oids[0]); desired_attrs.elements = desired_oids; @@ -1489,7 +1473,13 @@ gs2_escape_authzid(const sasl_utils_t *utils, } #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_get_init_creds(context_t *text, sasl_client_params_t *params, @@ -1501,67 +1491,27 @@ gs2_get_init_creds(context_t *text, int user_result = SASL_OK; int auth_result = SASL_OK; int pass_result = SASL_OK; - OM_uint32 maj_stat, min_stat; + 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; mechs.count = 1; mechs.elements = (gss_OID)text->mechanism; /* - * Determine the authentication identity from the application supplied - * GSS credential, the default GSS credential, and the application - * supplied identity, in that order. + * Get the authentication identity from the application. */ if (oparams->authid == NULL) { - assert(text->client_name == GSS_C_NO_NAME); - - if (!GOT_CREDS(text, params)) { - maj_stat = gss_acquire_cred(&min_stat, - GSS_C_NO_NAME, - GSS_C_INDEFINITE, - &mechs, - GSS_C_INITIATE, - &text->client_creds, - NULL, - &text->lifetime); - } else - maj_stat = GSS_S_COMPLETE; - - if (maj_stat == GSS_S_COMPLETE) { - 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; - } else if (maj_stat != GSS_S_CRED_UNAVAIL) + auth_result = _plug_get_authid(params->utils, &authid, prompt_need); + if (auth_result != SASL_OK && auth_result != SASL_INTERACT) { + result = auth_result; goto cleanup; - - if (text->client_name != GSS_C_NO_NAME) { - maj_stat = gss_display_name(&min_stat, - text->client_name, - &cred_authid, - NULL); - if (GSS_ERROR(maj_stat)) - goto cleanup; - - authid = cred_authid.value; - } else { - auth_result = _plug_get_authid(params->utils, &authid, prompt_need); - if (auth_result != SASL_OK && auth_result != SASL_INTERACT) { - result = auth_result; - goto cleanup; - } } } /* - * Get the authorization identity. + * Get the authorization identity from the application. */ if (oparams->user == NULL) { user_result = _plug_get_userid(params->utils, &userid, prompt_need); @@ -1571,6 +1521,10 @@ gs2_get_init_creds(context_t *text, } } + /* + * 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') { @@ -1589,25 +1543,81 @@ gs2_get_init_creds(context_t *text, goto cleanup; } - assert(oparams->authid != NULL); + 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; + + /* The authid may have changed after prompting, so free any creds */ + gss_release_cred(&min_stat, &text->client_creds); + } } /* - * If the application has provided an authentication identity, parse it. + * If application didn't provide an authid, then use the default + * credential. If that doesn't work, give up. */ - if (text->client_name == GSS_C_NO_NAME && - oparams->authid != NULL && oparams->authid[0] != '\0') { - gss_buffer_desc name_buf; + 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; - 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); + 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)) { + /* Maybe there was no default credential */ + auth_result = SASL_INTERACT; + goto interact; + } + + 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; + } } /* @@ -1623,7 +1633,7 @@ gs2_get_init_creds(context_t *text, &text->client_creds, NULL, &text->lifetime); - if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CRED_UNAVAIL) + if (GSS_ERROR(maj_stat) && !CRED_ERROR(maj_stat)) goto cleanup; } @@ -1662,6 +1672,8 @@ gs2_get_init_creds(context_t *text, maj_stat = GSS_S_COMPLETE; +interact: + /* free prompts we got */ if (prompt_need && *prompt_need) { params->utils->free(*prompt_need);