OM_uint32 _gss_spnego_unseal (OM_uint32 * minor_status, gss_ctx_id_t context_handle, gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int * conf_state, int * qop_state ) { gssspnego_ctx ctx; *minor_status = 0; if (context_handle == GSS_C_NO_CONTEXT) { return GSS_S_NO_CONTEXT; } ctx = (gssspnego_ctx)context_handle; if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { return GSS_S_NO_CONTEXT; } return gss_unseal(minor_status, ctx->negotiated_ctx_id, input_message_buffer, output_message_buffer, conf_state, qop_state); }
static int krb5_decode(void *app_data, void *buf, int len, int level, struct connectdata *conn) { gss_ctx_id_t *context = app_data; OM_uint32 maj, min; gss_buffer_desc enc, dec; /* shut gcc up */ level = 0; conn = NULL; enc.value = buf; enc.length = len; maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL); if(maj != GSS_S_COMPLETE) { if(len >= 4) strcpy(buf, "599 "); return -1; } memcpy(buf, dec.value, dec.length); len = dec.length; gss_release_buffer(&min, &dec); return len; }
bool_t auth_gssapi_unseal_seq( gss_ctx_id_t context, gss_buffer_t in_buf, uint32_t *seq_num) { gss_buffer_desc out_buf; OM_uint32 gssstat, minor_stat; uint32_t nl_seq_num; gssstat = gss_unseal(&minor_stat, context, in_buf, &out_buf, NULL, NULL); if (gssstat != GSS_S_COMPLETE) { PRINTF(("gssapi_unseal_seq: failed\n")); AUTH_GSSAPI_DISPLAY_STATUS(("unsealing sequence number", gssstat, minor_stat)); return FALSE; } else if (out_buf.length != sizeof(uint32_t)) { PRINTF(("gssapi_unseal_seq: unseal gave %d bytes\n", (int) out_buf.length)); gss_release_buffer(&minor_stat, &out_buf); return FALSE; } nl_seq_num = *((uint32_t *) out_buf.value); *seq_num = (uint32_t) ntohl(nl_seq_num); gss_release_buffer(&minor_stat, &out_buf); return TRUE; }
static int k5_decrypt( void *cookie, void *buf, ssize_t buflen, void **decbuf, ssize_t *decbuflen) { struct tcp_conn *rc = cookie; gss_buffer_desc enctok; gss_buffer_desc dectok; OM_uint32 maj_stat, min_stat; int conf_state, qop_state; if (rc->conf_fn && rc->conf_fn("kencrypt", rc->datap)) { auth_debug(1, _("krb5: k5_decrypt: enter\n")); if (rc->auth == 1) { enctok.length = buflen; enctok.value = buf; auth_debug(1, _("krb5: k5_decrypt: decrypting %zu bytes\n"), enctok.length); assert(rc->gss_context != GSS_C_NO_CONTEXT); maj_stat = gss_unseal(&min_stat, rc->gss_context, &enctok, &dectok, &conf_state, &qop_state); if (maj_stat != (OM_uint32)GSS_S_COMPLETE) { auth_debug(1, _("krb5 decrypt error from %s: %s\n"), rc->hostname, gss_error(maj_stat, min_stat)); return (-1); } auth_debug(1, _("krb5: k5_decrypt: give %zu bytes\n"), dectok.length); *decbuf = dectok.value; *decbuflen = dectok.length; } else { *decbuf = buf; *decbuflen = buflen; } auth_debug(1, _("krb5: k5_decrypt: exit\n")); } else { *decbuf = buf; *decbuflen = buflen; } return (0); }
static int krb5_decode(void *app_data, void *buf, int len, int level UNUSED_PARAM, struct connectdata *conn UNUSED_PARAM) { gss_ctx_id_t *context = app_data; OM_uint32 maj, min; gss_buffer_desc enc, dec; (void)level; (void)conn; enc.value = buf; enc.length = len; maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL); if(maj != GSS_S_COMPLETE) { if(len >= 4) strcpy(buf, "599 "); return -1; } memcpy(buf, dec.value, dec.length); len = curlx_uztosi(dec.length); gss_release_buffer(&min, &dec); return len; } static int krb5_overhead(void *app_data, int level, int len)
/* * Function: auth_gssapi_create * * Purpose: Create a GSS-API style authenticator, with all the * options, and return the handle. * * Effects: See design document, section XXX. */ AUTH *auth_gssapi_create( CLIENT *clnt, OM_uint32 *gssstat, OM_uint32 *minor_stat, gss_cred_id_t claimant_cred_handle, gss_name_t target_name, gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, gss_OID *actual_mech_type, OM_uint32 *ret_flags, OM_uint32 *time_rec) { AUTH *auth, *save_auth; struct auth_gssapi_data *pdata; struct gss_channel_bindings_struct bindings, *bindp; struct sockaddr_in laddr, raddr; enum clnt_stat callstat; struct timeval timeout; int bindings_failed; rpcproc_t init_func; auth_gssapi_init_arg call_arg; auth_gssapi_init_res call_res; gss_buffer_desc *input_token, isn_buf; memset(&rpc_createerr, 0, sizeof(rpc_createerr)); /* this timeout is only used if clnt_control(clnt, CLSET_TIMEOUT) */ /* has not already been called.. therefore, we can just pick */ /* something reasonable-sounding.. */ timeout.tv_sec = 30; timeout.tv_usec = 0; auth = NULL; pdata = NULL; /* don't assume the caller will want to change clnt->cl_auth */ save_auth = clnt->cl_auth; auth = (AUTH *) malloc(sizeof(*auth)); pdata = (struct auth_gssapi_data *) malloc(sizeof(*pdata)); if (auth == NULL || pdata == NULL) { /* They needn't both have failed; clean up. */ free(auth); free(pdata); auth = NULL; pdata = NULL; rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = ENOMEM; goto cleanup; } memset((char *) auth, 0, sizeof(*auth)); memset((char *) pdata, 0, sizeof(*pdata)); auth->ah_ops = &auth_gssapi_ops; auth->ah_private = (caddr_t) pdata; /* initial creds are auth_msg TRUE and no handle */ marshall_new_creds(auth, TRUE, NULL); /* initial verifier is empty */ auth->ah_verf.oa_flavor = AUTH_GSSAPI; auth->ah_verf.oa_base = NULL; auth->ah_verf.oa_length = 0; AUTH_PRIVATE(auth)->established = FALSE; AUTH_PRIVATE(auth)->clnt = clnt; AUTH_PRIVATE(auth)->def_cred = (claimant_cred_handle == GSS_C_NO_CREDENTIAL); clnt->cl_auth = auth; /* start by trying latest version */ call_arg.version = 4; bindings_failed = 0; try_new_version: /* set state for initial call to init_sec_context */ input_token = GSS_C_NO_BUFFER; AUTH_PRIVATE(auth)->context = GSS_C_NO_CONTEXT; init_func = AUTH_GSSAPI_INIT; #ifdef GSSAPI_KRB5 /* * OV servers up to version 3 used the old mech id. Beta 7 * servers used version 3 with the new mech id; however, the beta * 7 gss-api accept_sec_context accepts either mech id. Thus, if * any server rejects version 4, we fall back to version 3 with * the old mech id; for the OV server it will be right, and for * the beta 7 server it will be accepted. Not ideal, but it * works. */ if (call_arg.version < 4 && (mech_type == gss_mech_krb5 || mech_type == GSS_C_NULL_OID)) mech_type = (gss_OID) gss_mech_krb5_old; #endif if (!bindings_failed && call_arg.version >= 3) { if (clnt_control(clnt, CLGET_LOCAL_ADDR, &laddr) == FALSE) { PRINTF(("gssapi_create: CLGET_LOCAL_ADDR failed")); goto cleanup; } if (clnt_control(clnt, CLGET_SERVER_ADDR, &raddr) == FALSE) { PRINTF(("gssapi_create: CLGET_SERVER_ADDR failed")); goto cleanup; } memset(&bindings, 0, sizeof(bindings)); bindings.application_data.length = 0; bindings.initiator_addrtype = GSS_C_AF_INET; bindings.initiator_address.length = 4; bindings.initiator_address.value = &laddr.sin_addr.s_addr; bindings.acceptor_addrtype = GSS_C_AF_INET; bindings.acceptor_address.length = 4; bindings.acceptor_address.value = &raddr.sin_addr.s_addr; bindp = &bindings; } else { bindp = NULL; } memset((char *) &call_res, 0, sizeof(call_res)); next_token: *gssstat = gss_init_sec_context(minor_stat, claimant_cred_handle, &AUTH_PRIVATE(auth)->context, target_name, mech_type, req_flags, time_req, bindp, input_token, actual_mech_type, &call_arg.token, ret_flags, time_rec); if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) { AUTH_GSSAPI_DISPLAY_STATUS(("initializing context", *gssstat, *minor_stat)); goto cleanup; } /* if we got a token, pass it on */ if (call_arg.token.length != 0) { /* * sanity check: if we received a signed isn in the last * response then there *cannot* be another token to send */ if (call_res.signed_isn.length != 0) { PRINTF(("gssapi_create: unexpected token from init_sec\n")); goto cleanup; } PRINTF(("gssapi_create: calling GSSAPI_INIT (%d)\n", init_func)); memset((char *) &call_res, 0, sizeof(call_res)); callstat = clnt_call(clnt, init_func, xdr_authgssapi_init_arg, &call_arg, xdr_authgssapi_init_res, &call_res, timeout); gss_release_buffer(minor_stat, &call_arg.token); if (callstat != RPC_SUCCESS) { struct rpc_err err; clnt_geterr(clnt, &err); if (callstat == RPC_AUTHERROR && (err.re_why == AUTH_BADCRED || err.re_why == AUTH_FAILED) && call_arg.version >= 1) { L_PRINTF(1, ("call_arg protocol version %d rejected, trying %d.\n", call_arg.version, call_arg.version-1)); call_arg.version--; goto try_new_version; } else { PRINTF(("gssapi_create: GSSAPI_INIT (%d) failed, stat %d\n", init_func, callstat)); } goto cleanup; } else if (call_res.version != call_arg.version && !(call_arg.version == 2 && call_res.version == 1)) { /* * The Secure 1.1 servers always respond with version * 1. Thus, if we just tried a version >=3, fall all * the way back to version 1 since that is all they * understand */ if (call_arg.version > 2 && call_res.version == 1) { L_PRINTF(1, ("Talking to Secure 1.1 server, using version 1.\n")); call_arg.version = 1; goto try_new_version; } PRINTF(("gssapi_create: invalid call_res vers %d\n", call_res.version)); goto cleanup; } else if (call_res.gss_major != GSS_S_COMPLETE) { AUTH_GSSAPI_DISPLAY_STATUS(("in response from server", call_res.gss_major, call_res.gss_minor)); goto cleanup; } PRINTF(("gssapi_create: GSSAPI_INIT (%d) succeeded\n", init_func)); init_func = AUTH_GSSAPI_CONTINUE_INIT; /* check for client_handle */ if (AUTH_PRIVATE(auth)->client_handle.length == 0) { if (call_res.client_handle.length == 0) { PRINTF(("gssapi_create: expected client_handle\n")); goto cleanup; } else { PRINTF(("gssapi_create: got client_handle %d\n", *((uint32_t *)call_res.client_handle.value))); GSS_DUP_BUFFER(AUTH_PRIVATE(auth)->client_handle, call_res.client_handle); /* auth_msg is TRUE; there may be more tokens */ marshall_new_creds(auth, TRUE, &AUTH_PRIVATE(auth)->client_handle); } } else if (!GSS_BUFFERS_EQUAL(AUTH_PRIVATE(auth)->client_handle, call_res.client_handle)) { PRINTF(("gssapi_create: got different client_handle\n")); goto cleanup; } /* check for token */ if (call_res.token.length==0 && *gssstat==GSS_S_CONTINUE_NEEDED) { PRINTF(("gssapi_create: expected token\n")); goto cleanup; } else if (call_res.token.length != 0) { if (*gssstat == GSS_S_COMPLETE) { PRINTF(("gssapi_create: got unexpected token\n")); goto cleanup; } else { /* assumes call_res is safe until init_sec_context */ input_token = &call_res.token; PRINTF(("gssapi_create: got new token\n")); } } } /* check for isn */ if (*gssstat == GSS_S_COMPLETE) { if (call_res.signed_isn.length == 0) { PRINTF(("gssapi_created: expected signed isn\n")); goto cleanup; } else { PRINTF(("gssapi_create: processing signed isn\n")); /* don't check conf (integ only) or qop (accpet default) */ *gssstat = gss_unseal(minor_stat, AUTH_PRIVATE(auth)->context, &call_res.signed_isn, &isn_buf, NULL, NULL); if (*gssstat != GSS_S_COMPLETE) { AUTH_GSSAPI_DISPLAY_STATUS(("unsealing isn", *gssstat, *minor_stat)); goto cleanup; } else if (isn_buf.length != sizeof(uint32_t)) { PRINTF(("gssapi_create: gss_unseal gave %d bytes\n", (int) isn_buf.length)); goto cleanup; } AUTH_PRIVATE(auth)->seq_num = (uint32_t) ntohl(*((uint32_t*)isn_buf.value)); *gssstat = gss_release_buffer(minor_stat, &isn_buf); if (*gssstat != GSS_S_COMPLETE) { AUTH_GSSAPI_DISPLAY_STATUS(("releasing unsealed isn", *gssstat, *minor_stat)); goto cleanup; } PRINTF(("gssapi_create: isn is %d\n", AUTH_PRIVATE(auth)->seq_num)); /* we no longer need these results.. */ xdr_free(xdr_authgssapi_init_res, &call_res); } } else if (call_res.signed_isn.length != 0) { PRINTF(("gssapi_create: got signed isn, can't check yet\n")); } /* results were okay.. continue if necessary */ if (*gssstat == GSS_S_CONTINUE_NEEDED) { PRINTF(("gssapi_create: not done, continuing\n")); goto next_token; } /* * Done! Context is established, we have client_handle and isn. */ AUTH_PRIVATE(auth)->established = TRUE; marshall_new_creds(auth, FALSE, &AUTH_PRIVATE(auth)->client_handle); PRINTF(("gssapi_create: done. client_handle %#x, isn %d\n\n", *((uint32_t *)AUTH_PRIVATE(auth)->client_handle.value), AUTH_PRIVATE(auth)->seq_num)); /* don't assume the caller will want to change clnt->cl_auth */ clnt->cl_auth = save_auth; return auth; /******************************************************************/ cleanup: PRINTF(("gssapi_create: bailing\n\n")); if (auth) { if (AUTH_PRIVATE(auth)) auth_gssapi_destroy(auth); else free(auth); auth = NULL; } /* don't assume the caller will want to change clnt->cl_auth */ clnt->cl_auth = save_auth; if (rpc_createerr.cf_stat == 0) rpc_createerr.cf_stat = RPC_AUTHERROR; return auth; }
bool_t auth_gssapi_unwrap_data( OM_uint32 *major, OM_uint32 *minor, gss_ctx_id_t context, uint32_t seq_num, XDR *in_xdrs, bool_t (*xdr_func)(), caddr_t xdr_ptr) { gss_buffer_desc in_buf, out_buf; XDR temp_xdrs; uint32_t verf_seq_num; int conf, qop; unsigned int length; PRINTF(("gssapi_unwrap_data: starting\n")); *major = GSS_S_COMPLETE; *minor = 0; /* assumption */ in_buf.value = NULL; out_buf.value = NULL; if (! xdr_bytes(in_xdrs, (char **) &in_buf.value, &length, (unsigned int) -1)) { PRINTF(("gssapi_unwrap_data: deserializing encrypted data failed\n")); temp_xdrs.x_op = XDR_FREE; (void)xdr_bytes(&temp_xdrs, (char **) &in_buf.value, &length, (unsigned int) -1); return FALSE; } in_buf.length = length; *major = gss_unseal(minor, context, &in_buf, &out_buf, &conf, &qop); free(in_buf.value); if (*major != GSS_S_COMPLETE) return FALSE; PRINTF(("gssapi_unwrap_data: %d bytes data, %d bytes sealed\n", out_buf.length, in_buf.length)); xdrmem_create(&temp_xdrs, out_buf.value, out_buf.length, XDR_DECODE); /* deserialize the sequence number */ if (! xdr_u_int32(&temp_xdrs, &verf_seq_num)) { PRINTF(("gssapi_unwrap_data: deserializing verf_seq_num failed\n")); gss_release_buffer(minor, &out_buf); XDR_DESTROY(&temp_xdrs); return FALSE; } if (verf_seq_num != seq_num) { PRINTF(("gssapi_unwrap_data: seq %d specified, read %d\n", seq_num, verf_seq_num)); gss_release_buffer(minor, &out_buf); XDR_DESTROY(&temp_xdrs); return FALSE; } PRINTF(("gssapi_unwrap_data: unwrap seq_num %d okay\n", verf_seq_num)); /* deserialize the arguments into xdr_ptr */ if (! (*xdr_func)(&temp_xdrs, xdr_ptr)) { PRINTF(("gssapi_unwrap_data: deserializing arguments failed\n")); gss_release_buffer(minor, &out_buf); xdr_free(xdr_func, xdr_ptr); XDR_DESTROY(&temp_xdrs); return FALSE; } PRINTF(("gssapi_unwrap_data: succeeding\n\n")); gss_release_buffer(minor, &out_buf); XDR_DESTROY(&temp_xdrs); return TRUE; }