📄 gssapi.c
字号:
name_without_realm.length = strlen( (char *) name_without_realm.value ); maj_stat = (*p_krb5_gss_import_name) (&min_stat, &name_without_realm, /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here, so use GSS_C_NT_USER_NAME instead if available. */#ifdef HAVE_GSS_C_NT_USER_NAME GSS_C_NT_USER_NAME,#else GSS_C_NULL_OID,#endif &without); if (GSS_ERROR(maj_stat)) { params->utils->free(name_without_realm.value); if (name_token.value) (*p_krb5_gss_release_buffer)(&min_stat, &name_token); if (without) (*p_krb5_gss_release_name)(&min_stat, &without); SETERROR(text->utils, "GSSAPI Failure"); sasl_gss_free_context_contents(text); return SASL_BADAUTH; } maj_stat = (*p_krb5_gss_compare_name)(&min_stat, text->client_name, without, &equal); if (GSS_ERROR(maj_stat)) { params->utils->free(name_without_realm.value); if (name_token.value) (*p_krb5_gss_release_buffer)(&min_stat, &name_token); if (without) (*p_krb5_gss_release_name)(&min_stat, &without); SETERROR(text->utils, "GSSAPI Failure"); sasl_gss_free_context_contents(text); return SASL_BADAUTH; } (*p_krb5_gss_release_name)(&min_stat,&without); } else { equal = 0; } if (equal) { text->authid = strdup(name_without_realm.value); if (text->authid == NULL) { MEMERROR(params->utils); return SASL_NOMEM; } } else { text->authid = strdup(name_token.value); if (text->authid == NULL) { MEMERROR(params->utils); return SASL_NOMEM; } } if (name_token.value) (*p_krb5_gss_release_buffer)(&min_stat, &name_token); if (name_without_realm.value) params->utils->free(name_without_realm.value); /* we have to decide what sort of encryption/integrity/etc., we support */ if (params->props.max_ssf < params->external_ssf) { text->limitssf = 0; } else { text->limitssf = params->props.max_ssf - params->external_ssf; } if (params->props.min_ssf < params->external_ssf) { text->requiressf = 0; } else { text->requiressf = params->props.min_ssf - params->external_ssf; } /* build up our security properties token */ if (params->props.maxbufsize > 0xFFFFFF) { /* make sure maxbufsize isn't too large */ /* maxbufsize = 0xFFFFFF */ sasldata[1] = sasldata[2] = sasldata[3] = 0xFF; } else { sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF; sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF; sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF; } sasldata[0] = 0; if(text->requiressf != 0 && !params->props.maxbufsize) { params->utils->seterror(params->utils->conn, 0, "GSSAPI needs a security layer but one is forbidden"); return SASL_TOOWEAK; } if (text->requiressf == 0) { sasldata[0] |= 1; /* authentication */ } if (text->requiressf <= 1 && text->limitssf >= 1 && params->props.maxbufsize) { sasldata[0] |= 2; } if (text->requiressf <= K5_MAX_SSF && text->limitssf >= K5_MAX_SSF && params->props.maxbufsize) { sasldata[0] |= 4; } real_input_token.value = (void *)sasldata; real_input_token.length = 4; 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); 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 (serveroutlen) *serveroutlen = output_token->length; if (output_token->value) { if (serverout) { ret = _plug_buf_alloc(text->utils, &(text->out_buf), &(text->out_buf_len), *serveroutlen); if(ret != SASL_OK) { (*p_krb5_gss_release_buffer)(&min_stat, output_token); return ret; } memcpy(text->out_buf, output_token->value, *serveroutlen); *serverout = text->out_buf; } (*p_krb5_gss_release_buffer)(&min_stat, output_token); } /* Wait for ssf request and authid */ text->state = SASL_GSSAPI_STATE_SSFREQ; return SASL_CONTINUE; } case SASL_GSSAPI_STATE_SSFREQ: { int layerchoice; real_input_token.value = (void *)clientin; real_input_token.length = clientinlen; 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); return SASL_FAIL; } layerchoice = (int)(((char *)(output_token->value))[0]); if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */ oparams->encode = NULL; oparams->decode = NULL; oparams->mech_ssf = 0; } else if (layerchoice == 2 && text->requiressf <= 1 && text->limitssf >= 1) { /* integrity */ oparams->encode=&gssapi_integrity_encode; oparams->decode=&gssapi_decode; oparams->mech_ssf=1; } else if (layerchoice == 4 && text->requiressf <= K5_MAX_SSF && text->limitssf >= K5_MAX_SSF) { /* privacy */ oparams->encode = &gssapi_privacy_encode; oparams->decode = &gssapi_decode; /* FIX ME: Need to extract the proper value here */ oparams->mech_ssf = K5_MAX_SSF; } else { /* not a supported encryption layer */ SETERROR(text->utils, "protocol violation: client requested invalid layer"); /* Mark that we attempted negotiation */ oparams->mech_ssf = 2; if (output_token->value) (*p_krb5_gss_release_buffer)(&min_stat, output_token); sasl_gss_free_context_contents(text); return SASL_FAIL; } if (output_token->length > 4) { int ret; ret = params->canon_user(params->utils->conn, ((char *) output_token->value) + 4, (output_token->length - 4) * sizeof(char), SASL_CU_AUTHZID, oparams); if (ret != SASL_OK) { sasl_gss_free_context_contents(text); return ret; } ret = params->canon_user(params->utils->conn, text->authid, 0, /* strlen(text->authid) */ SASL_CU_AUTHID, oparams); if (ret != SASL_OK) { sasl_gss_free_context_contents(text); return ret; } } else if(output_token->length == 4) { /* null authzid */ int ret; ret = params->canon_user(params->utils->conn, text->authid, 0, /* strlen(text->authid) */ SASL_CU_AUTHZID | SASL_CU_AUTHID, oparams); if (ret != SASL_OK) { sasl_gss_free_context_contents(text); return ret; } } else { SETERROR(text->utils, "token too short"); (*p_krb5_gss_release_buffer)(&min_stat, output_token); sasl_gss_free_context_contents(text); return SASL_FAIL; } /* No matter what, set the rest of the oparams */ 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); text->state = SASL_GSSAPI_STATE_AUTHENTICATED; /* used by layers */ _plug_decode_init(&text->decode_context, text->utils, (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF : params->props.maxbufsize); oparams->doneflag = 1; return SASL_OK; } default: params->utils->log(NULL, SASL_LOG_ERR, "Invalid GSSAPI server step %d\n", text->state); return SASL_FAIL; } return SASL_FAIL; /* should never get here */}static sasl_server_plug_t gssapi_server_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_WANT_CLIENT_FIRST | SASL_FEAT_ALLOWS_PROXY, /* features */ NULL, /* glob_context */ &gssapi_server_mech_new, /* mech_new */ &gssapi_server_mech_step, /* mech_step */ &gssapi_common_mech_dispose, /* mech_dispose */ NULL, /* mech_free */ NULL, /* setpass */ NULL, /* user_query */ NULL, /* idle */ NULL, /* mech_avail */ NULL /* spare */ }};int gssapiv2_server_plug_init(#ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY const sasl_utils_t *utils __attribute__((unused)),#else const sasl_utils_t *utils,#endif int maxversion, int *out_version, sasl_server_plug_t **pluglist, int *plugcount){#ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY const char *keytab = NULL; char keytab_path[1024]; unsigned int rl;#endif if (maxversion < SASL_SERVER_PLUG_VERSION) { return SASL_BADVERS; } #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY /* unfortunately, we don't check for readability of keytab if it's the standard one, since we don't know where it is */ /* FIXME: This code is broken */ utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl); if (keytab != NULL) { if (access(keytab, R_OK) != 0) { utils->log(NULL, SASL_LOG_ERR, "Could not find keytab file: %s: %m", keytab, errno); return SASL_FAIL; } if(strlen(keytab) > 1024) { utils->log(NULL, SASL_LOG_ERR, "path to keytab is > 1024 characters"); return SASL_BUFOVER; } strncpy(keytab_path, keytab, 1024); gsskrb5_register_acceptor_identity(keytab_path); }#endif *out_version = SASL_SERVER_PLUG_VERSION; *pluglist = gssapi_server_plugins; *plugcount = 1; return SASL_OK;}/***************************** Client Section *****************************/static int gssapi_client_mech_new(void *glob_context __attribute__((unused)), sasl_client_params_t *params, void **conn_context){ context_t *text; /* holds state are in */ text = gss_new_context(params->utils); if (text == NULL) { MEMERROR(params->utils); return SASL_NOMEM; } text->state = SASL_GSSAPI_STATE_AUTHNEG; text->gss_ctx = GSS_C_NO_CONTEXT; text->client_name = GSS_C_NO_NAME; text->server_creds = GSS_C_NO_CREDENTIAL; *conn_context = text; return SASL_OK;}static int gssapi_client_mech_step(void *conn_context, sasl_client_params_t *params, const char *serverin, unsigned serverinlen, sasl_interact_t **prompt_need, const char **clientout, unsigned *clientoutlen, sasl_out_params_t *oparams){ context_t *text = (context_t *)conn_context; gss_buffer_t input_token, output_token; gss_buffer_desc real_input_token, real_output_token; OM_uint32 maj_stat = 0, min_stat = 0; OM_uint32 max_input; gss_buffer_desc name_token; int ret; OM_uint32 req_flags = 0, out_req_flags = 0; input_token = &real_input_token; output_token = &real_output_token; output_token->value = NULL; input_token->value = NULL; input_token->length = 0; *clientout = NULL; *clientoutlen = 0; if (sasl_gss_lib_init(text->utils) != SASL_OK) return SASL_FAIL; switch (text->state) { case SASL_GSSAPI_STATE_AUTHNEG: /* try to get the userid */ if (text->user == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -