📄 gssapi.c
字号:
int user_result = SASL_OK; user_result = _plug_get_userid(params->utils, &text->user, prompt_need); if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) { sasl_gss_free_context_contents(text); return user_result; } /* free prompts we got */ if (prompt_need && *prompt_need) { params->utils->free(*prompt_need); *prompt_need = NULL; } /* if there are prompts not filled in */ if (user_result == SASL_INTERACT) { /* make the prompt list */ int result = _plug_make_prompts(params->utils, prompt_need, user_result == SASL_INTERACT ? "Please enter your authorization name" : NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (result != SASL_OK) return result; return SASL_INTERACT; } } if (text->server_name == GSS_C_NO_NAME) { /* only once */ name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN); name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char)); if (name_token.value == NULL) { sasl_gss_free_context_contents(text); return SASL_NOMEM; } if (params->serverFQDN == NULL || strlen(params->serverFQDN) == 0) { SETERROR(text->utils, "GSSAPI Failure: no serverFQDN"); return SASL_FAIL; } sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN); maj_stat = (*p_krb5_gss_import_name) (&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, &text->server_name); params->utils->free(name_token.value); name_token.value = NULL; if (GSS_ERROR(maj_stat)) { sasl_gss_seterror(text->utils, maj_stat, min_stat); sasl_gss_free_context_contents(text); return SASL_FAIL; } } if (serverinlen == 0) input_token = GSS_C_NO_BUFFER; if (serverinlen) { real_input_token.value = (void *)serverin; real_input_token.length = serverinlen; } else if (text->gss_ctx != GSS_C_NO_CONTEXT ) { /* This can't happen under GSSAPI: we have a non-null context * and no input from the server. However, thanks to Imap, * which discards our first output, this happens all the time. * Throw away the context and try again. */ maj_stat = (*p_krb5_gss_delete_sec_context) (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER); text->gss_ctx = GSS_C_NO_CONTEXT; } /* Setup req_flags properly */ req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG; if(params->props.max_ssf > params->external_ssf) { /* We are requesting a security layer */ req_flags |= GSS_C_INTEG_FLAG; /* Any SSF bigger than 1 is confidentiality. */ /* Let's check if the client of the API requires confidentiality, and it wasn't already provided by an external layer */ if(params->props.max_ssf - params->external_ssf > 1) { /* We want to try for privacy */ req_flags |= GSS_C_CONF_FLAG; } } maj_stat = (*p_krb5_gss_init_sec_context)(&min_stat, GSS_C_NO_CREDENTIAL, &text->gss_ctx, text->server_name, GSS_C_NO_OID, req_flags, 0, GSS_C_NO_CHANNEL_BINDINGS, input_token, NULL, output_token, &out_req_flags, NULL); if (GSS_ERROR(maj_stat)) { sasl_gss_seterror(text->utils, maj_stat, min_stat); if (output_token->value) (*p_krb5_gss_release_buffer)(&min_stat, output_token); sasl_gss_free_context_contents(text); return SASL_FAIL; } *clientoutlen = output_token->length; if (output_token->value) { if (clientout) { ret = _plug_buf_alloc(text->utils, &(text->out_buf), &(text->out_buf_len), *clientoutlen); if(ret != SASL_OK) { (*p_krb5_gss_release_buffer)(&min_stat, output_token); return ret; } memcpy(text->out_buf, output_token->value, *clientoutlen); *clientout = text->out_buf; } (*p_krb5_gss_release_buffer)(&min_stat, output_token); } if (maj_stat == GSS_S_COMPLETE) { maj_stat = (*p_krb5_gss_inquire_context)(&min_stat, text->gss_ctx, &text->client_name, NULL, /* targ_name */ NULL, /* lifetime */ NULL, /* mech */ /* FIX ME: Should check the resulting flags here */ NULL, /* flags */ NULL, /* local init */ NULL); /* open */ if (GSS_ERROR(maj_stat)) { sasl_gss_seterror(text->utils, maj_stat, min_stat); sasl_gss_free_context_contents(text); return SASL_FAIL; } name_token.length = 0; maj_stat = (*p_krb5_gss_display_name)(&min_stat, text->client_name, &name_token, NULL); if (GSS_ERROR(maj_stat)) { if (name_token.value) (*p_krb5_gss_release_buffer)(&min_stat, &name_token); SETERROR(text->utils, "GSSAPI Failure"); sasl_gss_free_context_contents(text); return SASL_FAIL; } if (text->user && text->user[0]) { ret = params->canon_user(params->utils->conn, text->user, 0, SASL_CU_AUTHZID, oparams); if (ret == SASL_OK) ret = params->canon_user(params->utils->conn, name_token.value, 0, SASL_CU_AUTHID, oparams); } else { ret = params->canon_user(params->utils->conn, name_token.value, 0, SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); } (*p_krb5_gss_release_buffer)(&min_stat, &name_token); if (ret != SASL_OK) return ret; /* Switch to ssf negotiation */ text->state = SASL_GSSAPI_STATE_SSFCAP; } return SASL_CONTINUE; case SASL_GSSAPI_STATE_SSFCAP: { sasl_security_properties_t *secprops = &(params->props); unsigned int alen, external = params->external_ssf; sasl_ssf_t need, allowed; char serverhas, mychoice; real_input_token.value = (void *) serverin; real_input_token.length = serverinlen; maj_stat = (*p_krb5_gss_unwrap)(&min_stat, text->gss_ctx, input_token, output_token, NULL, NULL); if (GSS_ERROR(maj_stat)) { sasl_gss_seterror(text->utils, maj_stat, min_stat); sasl_gss_free_context_contents(text); if (output_token->value) (*p_krb5_gss_release_buffer)(&min_stat, output_token); return SASL_FAIL; } /* taken from kerberos.c */ if (secprops->min_ssf > (K5_MAX_SSF + external)) { return SASL_TOOWEAK; } else if (secprops->min_ssf > secprops->max_ssf) { return SASL_BADPARAM; } /* need bits of layer -- sasl_ssf_t is unsigned so be careful */ if (secprops->max_ssf >= external) { allowed = secprops->max_ssf - external; } else { allowed = 0; } if (secprops->min_ssf >= external) { need = secprops->min_ssf - external; } else { /* good to go */ need = 0; } /* bit mask of server support */ serverhas = ((char *)output_token->value)[0]; /* if client didn't set use strongest layer available */ if (allowed >= K5_MAX_SSF && need <= K5_MAX_SSF && (serverhas & 4)) { /* encryption */ oparams->encode = &gssapi_privacy_encode; oparams->decode = &gssapi_decode; /* FIX ME: Need to extract the proper value here */ oparams->mech_ssf = K5_MAX_SSF; mychoice = 4; } else if (allowed >= 1 && need <= 1 && (serverhas & 2)) { /* integrity */ oparams->encode = &gssapi_integrity_encode; oparams->decode = &gssapi_decode; oparams->mech_ssf = 1; mychoice = 2; } else if (need <= 0 && (serverhas & 1)) { /* no layer */ oparams->encode = NULL; oparams->decode = NULL; oparams->mech_ssf = 0; mychoice = 1; } else { /* there's no appropriate layering for us! */ sasl_gss_free_context_contents(text); return SASL_TOOWEAK; } oparams->maxoutbuf = (((unsigned char *) output_token->value)[1] << 16) | (((unsigned char *) output_token->value)[2] << 8) | (((unsigned char *) output_token->value)[3] << 0); if(oparams->mech_ssf) { maj_stat = (*p_krb5_gss_wrap_size_limit)(&min_stat, text->gss_ctx, 1, GSS_C_QOP_DEFAULT, (OM_uint32) oparams->maxoutbuf, &max_input); if(max_input > oparams->maxoutbuf) { /* Heimdal appears to get this wrong */ oparams->maxoutbuf -= (max_input - oparams->maxoutbuf); } else { /* This code is actually correct */ oparams->maxoutbuf = max_input; } } (*p_krb5_gss_release_buffer)(&min_stat, output_token); /* oparams->user is always set, due to canon_user requirements. * Make sure the client actually requested it though, by checking * if our context was set. */ if (text->user && text->user[0]) alen = strlen(oparams->user); else alen = 0; input_token->length = 4 + alen; input_token->value = (char *)params->utils->malloc((input_token->length + 1)*sizeof(char)); if (input_token->value == NULL) { sasl_gss_free_context_contents(text); return SASL_NOMEM; } if (alen) memcpy((char *)input_token->value+4,oparams->user,alen); /* build up our security properties token */ if (params->props.maxbufsize > 0xFFFFFF) { /* make sure maxbufsize isn't too large */ /* maxbufsize = 0xFFFFFF */ ((unsigned char *)input_token->value)[1] = 0xFF; ((unsigned char *)input_token->value)[2] = 0xFF; ((unsigned char *)input_token->value)[3] = 0xFF; } else { ((unsigned char *)input_token->value)[1] = (params->props.maxbufsize >> 16) & 0xFF; ((unsigned char *)input_token->value)[2] = (params->props.maxbufsize >> 8) & 0xFF; ((unsigned char *)input_token->value)[3] = (params->props.maxbufsize >> 0) & 0xFF; } ((unsigned char *)input_token->value)[0] = mychoice; maj_stat = (*p_krb5_gss_wrap) (&min_stat, text->gss_ctx, 0, /* Just integrity checking here */ GSS_C_QOP_DEFAULT, input_token, NULL, output_token); params->utils->free(input_token->value); input_token->value = NULL; if (GSS_ERROR(maj_stat)) { sasl_gss_seterror(text->utils, maj_stat, min_stat); if (output_token->value) (*p_krb5_gss_release_buffer)(&min_stat, output_token); sasl_gss_free_context_contents(text); return SASL_FAIL; } if (clientoutlen) *clientoutlen = output_token->length; if (output_token->value) { if (clientout) { ret = _plug_buf_alloc(text->utils, &(text->out_buf), &(text->out_buf_len), *clientoutlen); if (ret != SASL_OK) { (*p_krb5_gss_release_buffer)(&min_stat, output_token); return ret; } memcpy(text->out_buf, output_token->value, *clientoutlen); *clientout = text->out_buf; } (*p_krb5_gss_release_buffer)(&min_stat, output_token); } text->state = SASL_GSSAPI_STATE_AUTHENTICATED; oparams->doneflag = 1; /* used by layers */ _plug_decode_init(&text->decode_context, text->utils, (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF : params->props.maxbufsize); return SASL_OK; } default: params->utils->log(NULL, SASL_LOG_ERR, "Invalid GSSAPI client step %d\n", text->state); return SASL_FAIL; } return SASL_FAIL; /* should never get here */}static const unsigned long gssapi_required_prompts[] = { SASL_CB_LIST_END}; static sasl_client_plug_t gssapi_client_plugins[] = { { "GSSAPI", /* mech_name */ K5_MAX_SSF, /* max_ssf */ SASL_SEC_NOPLAINTEXT | SASL_SEC_NOACTIVE | SASL_SEC_NOANONYMOUS | SASL_SEC_MUTUAL_AUTH, /* security_flags */ SASL_FEAT_NEEDSERVERFQDN | SASL_FEAT_WANT_CLIENT_FIRST | SASL_FEAT_ALLOWS_PROXY, /* features */ gssapi_required_prompts, /* required_prompts */ NULL, /* glob_context */ &gssapi_client_mech_new, /* mech_new */ &gssapi_client_mech_step, /* mech_step */ &gssapi_common_mech_dispose, /* mech_dispose */ NULL, /* mech_free */ NULL, /* idle */ NULL, /* spare */ NULL /* spare */ }};int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)), int maxversion, int *out_version, sasl_client_plug_t **pluglist, int *plugcount){ if (maxversion < SASL_CLIENT_PLUG_VERSION) { SETERROR(utils, "Version mismatch in GSSAPI"); return SASL_BADVERS; } *out_version = SASL_CLIENT_PLUG_VERSION; *pluglist = gssapi_client_plugins; *plugcount = 1; return SASL_OK;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -