/* NFSv4.1 client for Windows * Copyright © 2012 The Regents of the University of Michigan * * Olga Kornievskaia * Casey Bodley * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, but * without any warranty; without even the implied warranty of merchantability * or fitness for a particular purpose. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA */ #include #include #include //#include #include #include #include #include #include #include #include static void authsspi_nextverf(AUTH *auth); static bool_t authsspi_marshal(AUTH *auth, XDR *xdrs, u_int *seq); static bool_t authsspi_refresh(AUTH *auth, void *); static bool_t authsspi_validate(AUTH *auth, struct opaque_auth *verf, u_int seq); static void authsspi_destroy(AUTH *auth); static void authsspi_destroy_context(AUTH *auth); static bool_t authsspi_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr); static bool_t authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, u_int seq); static struct auth_ops authsspi_ops = { authsspi_nextverf, authsspi_marshal, authsspi_validate, authsspi_refresh, authsspi_destroy, authsspi_wrap, authsspi_unwrap }; struct rpc_sspi_data { bool_t established; /* context established */ bool_t inprogress; sspi_buffer_desc gc_wire_verf; /* save GSS_S_COMPLETE NULL RPC verfier * to process at end of context negotiation*/ CLIENT *clnt; /* client handle */ sspi_name_t name; /* service name */ struct rpc_sspi_sec *sec; /* security tuple */ CtxtHandle ctx; /* context id */ struct rpc_sspi_cred gc; /* client credentials */ u_int win; /* sequence window */ TimeStamp expiry; }; #define AUTH_PRIVATE(auth) ((struct rpc_sspi_data *)auth->ah_private) static struct timeval AUTH_TIMEOUT = { 25, 0 }; void print_rpc_gss_sec(struct rpc_sspi_sec *ptr); void print_negotiated_attrs(PCtxtHandle ctx); AUTH * authsspi_create(CLIENT *clnt, sspi_name_t name, struct rpc_sspi_sec *sec) { AUTH *auth, *save_auth; struct rpc_sspi_data *gd; log_debug("in authgss_create()"); memset(&rpc_createerr, 0, sizeof(rpc_createerr)); if ((auth = calloc(sizeof(*auth), 1)) == NULL) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = ENOMEM; return (NULL); } if ((gd = calloc(sizeof(*gd), 1)) == NULL) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = ENOMEM; free(auth); return (NULL); } #if 0 if (name != SSPI_C_NO_NAME) { if (gss_duplicate_name(&min_stat, name, &gd->name) != GSS_S_COMPLETE) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = ENOMEM; free(auth); return (NULL); } } else #else gd->name = strdup(name); #endif gd->clnt = clnt; SecInvalidateHandle(&gd->ctx); gd->sec = sec; gd->gc.gc_v = RPCSEC_SSPI_VERSION; gd->gc.gc_proc = RPCSEC_SSPI_INIT; gd->gc.gc_svc = gd->sec->svc; auth->ah_ops = &authsspi_ops; auth->ah_private = (caddr_t)gd; save_auth = clnt->cl_auth; clnt->cl_auth = auth; if (!authsspi_refresh(auth, NULL)) auth = NULL; clnt->cl_auth = save_auth; return (auth); } AUTH * authsspi_create_default(CLIENT *clnt, char *service, int svc) { AUTH *auth = NULL; uint32_t maj_stat = 0; sspi_buffer_desc sname; sspi_name_t name = SSPI_C_NO_NAME; unsigned char sec_pkg_name[] = "Kerberos"; struct rpc_sspi_sec *sec; log_debug("in authgss_create_default() for %s", service); sname.value = service; sname.length = (int)strlen(service); #if 0 maj_stat = gss_import_name(&min_stat, &sname, (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &name); #else maj_stat = sspi_import_name(&sname, &name); #endif if (maj_stat != SEC_E_OK) { log_debug("authgss_create_default: sspi_import_name failed with %x", maj_stat); return (NULL); } sec = calloc(1, sizeof(struct rpc_sspi_sec)); if (sec == NULL) goto out_err; sec->svc = svc; // Let's acquire creds here for now maj_stat = AcquireCredentialsHandleA(NULL, sec_pkg_name, SECPKG_CRED_BOTH, NULL, NULL, NULL, NULL, &sec->cred, &sec->expiry); if (maj_stat != SEC_E_OK) { log_debug("authgss_create_default: AcquireCredentialsHandleA failed with %x", maj_stat); free(sec); goto out; } auth = authsspi_create(clnt, name, sec); if (auth == NULL) goto out_free_sec; out: if (name != SSPI_C_NO_NAME) { #if 0 gss_release_name(&min_stat, &name); #else free(name); #endif } return (auth); out_free_sec: if (rpc_createerr.cf_error.re_errno == ENOMEM) { FreeCredentialsHandle(&sec->cred); free(sec); } out_err: rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = ENOMEM; goto out; } static void authsspi_nextverf(AUTH *auth) { log_debug("in authgss_nextverf()"); /* no action necessary */ } static bool_t authsspi_marshal(AUTH *auth, XDR *xdrs, u_int *seq) { XDR tmpxdrs; char tmp[MAX_AUTH_BYTES]; struct rpc_sspi_data *gd; sspi_buffer_desc rpcbuf, checksum; uint32_t maj_stat; bool_t xdr_stat; log_debug("in authgss_marshal()"); gd = AUTH_PRIVATE(auth); if (gd->established) { gd->gc.gc_seq++; *seq = gd->gc.gc_seq; } xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE); if (!xdr_rpc_sspi_cred(&tmpxdrs, &gd->gc)) { log_debug("authsspi_marshal: xdr_rpc_sspi_cred failed"); XDR_DESTROY(&tmpxdrs); return (FALSE); } auth->ah_cred.oa_flavor = RPCSEC_GSS; auth->ah_cred.oa_base = tmp; auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs); XDR_DESTROY(&tmpxdrs); if (!xdr_opaque_auth(xdrs, &auth->ah_cred)) { log_debug("authsspi_marshal: failed to xdr GSS CRED"); return (FALSE); } if (gd->gc.gc_proc == RPCSEC_SSPI_INIT || gd->gc.gc_proc == RPCSEC_SSPI_CONTINUE_INIT) { return (xdr_opaque_auth(xdrs, &_null_auth)); } /* Checksum serialized RPC header, up to and including credential. */ rpcbuf.length = XDR_GETPOS(xdrs) - 4; //XDR_SETPOS(xdrs, 0); //rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length); rpcbuf.value = xdrrec_getoutbase(xdrs) + 1; #if 0 maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, &rpcbuf, &checksum); #else maj_stat = sspi_get_mic(&gd->ctx, 0, gd->gc.gc_seq, &rpcbuf, &checksum); #endif if (maj_stat != SEC_E_OK) { log_debug("authsspi_marshal: sspi_get_mic failed with %x", maj_stat); if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) { gd->established = FALSE; authsspi_destroy_context(auth); } return (FALSE); } auth->ah_verf.oa_flavor = RPCSEC_GSS; auth->ah_verf.oa_base = checksum.value; auth->ah_verf.oa_length = checksum.length; xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf); #if 0 gss_release_buffer(&min_stat, &checksum); #else sspi_release_buffer(&checksum); #endif return (xdr_stat); } static bool_t authsspi_validate(AUTH *auth, struct opaque_auth *verf, u_int seq) { struct rpc_sspi_data *gd; u_int num, qop_state, cur_seq; sspi_buffer_desc signbuf, checksum; uint32_t maj_stat; log_debug("in authgss_validate(for seq=%d)", seq); gd = AUTH_PRIVATE(auth); if (gd->established == FALSE) { /* would like to do this only on NULL rpc -- * gc->established is good enough. * save the on the wire verifier to validate last * INIT phase packet after decode if the major * status is GSS_S_COMPLETE */ if ((gd->gc_wire_verf.value = mem_alloc(verf->oa_length)) == NULL) { return (FALSE); } memcpy(gd->gc_wire_verf.value, verf->oa_base, verf->oa_length); gd->gc_wire_verf.length = verf->oa_length; return (TRUE); } if (gd->gc.gc_proc == RPCSEC_SSPI_DESTROY) return TRUE; if (gd->gc.gc_proc == RPCSEC_SSPI_INIT || gd->gc.gc_proc == RPCSEC_SSPI_CONTINUE_INIT) { num = htonl(gd->win); } else { if (seq == -1) { num = htonl(gd->gc.gc_seq); cur_seq = gd->gc.gc_seq; } else { num = htonl(seq); cur_seq = seq; } } signbuf.value = # signbuf.length = sizeof(num); checksum.value = verf->oa_base; checksum.length = verf->oa_length; #if 0 maj_stat = gss_verify_mic(&min_stat, gd->ctx, &signbuf, &checksum, &qop_state); #else maj_stat = sspi_verify_mic(&gd->ctx, cur_seq, &signbuf, &checksum, &qop_state); #endif if (maj_stat != SEC_E_OK) { log_debug("authsspi_validate: VerifySignature failed with %x", maj_stat); if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) { gd->established = FALSE; authsspi_destroy_context(auth); } return (FALSE); } return (TRUE); } static bool_t authsspi_refresh(AUTH *auth, void *tmp) { struct rpc_sspi_data *gd; struct rpc_sspi_init_res gr; sspi_buffer_desc *recv_tokenp, send_token; uint32_t maj_stat, call_stat, ret_flags, i; unsigned long flags = ISC_REQ_MUTUAL_AUTH|ISC_REQ_INTEGRITY|ISC_REQ_ALLOCATE_MEMORY; SecBufferDesc out_desc, in_desc; SecBuffer wtkn[1], rtkn[1]; log_debug("in authgss_refresh()"); gd = AUTH_PRIVATE(auth); if ((gd->established && tmp == NULL) || gd->inprogress) return (TRUE); else if (tmp) { log_debug("trying to refresh credentials\n"); DeleteSecurityContext(&gd->ctx); sspi_release_buffer(&gd->gc.gc_ctx); SecInvalidateHandle(&gd->ctx); mem_free(gd->gc_wire_verf.value, gd->gc_wire_verf.length); gd->gc_wire_verf.value = NULL; gd->gc_wire_verf.length = 0; gd->established = FALSE; gd->gc.gc_proc = RPCSEC_SSPI_INIT; } /* GSS context establishment loop. */ memset(&gr, 0, sizeof(gr)); recv_tokenp = SSPI_C_NO_BUFFER; send_token.length = 0; send_token.value = NULL; print_rpc_gss_sec(gd->sec); if (gd->sec->svc == RPCSEC_SSPI_SVC_PRIVACY) flags |= ISC_REQ_CONFIDENTIALITY; for (i=0;;i++) { /* print the token we just received */ if (recv_tokenp != SSPI_C_NO_BUFFER) { log_debug("The token we just received (length %d):", recv_tokenp->length); log_hexdump(0, "", recv_tokenp->value, recv_tokenp->length, 0); } #if 0 maj_stat = gss_init_sec_context(&min_stat, gd->sec.cred, &gd->ctx, gd->name, gd->sec.mech, gd->sec.req_flags, 0, /* time req */ NULL, /* channel */ recv_tokenp, NULL, /* used mech */ &send_token, &ret_flags, NULL); /* time rec */ #else gd->inprogress = TRUE; out_desc.cBuffers = 1; out_desc.pBuffers = wtkn; out_desc.ulVersion = SECBUFFER_VERSION; wtkn[0].BufferType = SECBUFFER_TOKEN; wtkn[0].cbBuffer = send_token.length; wtkn[0].pvBuffer = send_token.value; log_debug("calling InitializeSecurityContextA for %s", gd->name); maj_stat = InitializeSecurityContextA( &gd->sec->cred, ((i==0)?NULL:&gd->ctx), gd->name, flags, 0, SECURITY_NATIVE_DREP, ((i==0)?NULL:&in_desc), 0, &gd->ctx, &out_desc, &ret_flags, &gd->expiry); #endif if (recv_tokenp != SSPI_C_NO_BUFFER) { #if 0 gss_release_buffer(&min_stat, &gr.gr_token); #else sspi_release_buffer(&gr.gr_token); #endif recv_tokenp = SSPI_C_NO_BUFFER; } if (maj_stat != SEC_E_OK && maj_stat != SEC_I_CONTINUE_NEEDED) { log_debug("InitializeSecurityContext failed with %x", maj_stat); break; } send_token.length = wtkn[0].cbBuffer; send_token.value = wtkn[0].pvBuffer; if (send_token.length != 0) { memset(&gr, 0, sizeof(gr)); /* print the token we are about to send */ log_debug("The token being sent (length %d):", send_token.length); log_hexdump(0, "", send_token.value, send_token.length, 0); call_stat = clnt_call(gd->clnt, NULLPROC, (xdrproc_t)xdr_rpc_sspi_init_args, &send_token, (xdrproc_t)xdr_rpc_sspi_init_res, (caddr_t)&gr, AUTH_TIMEOUT); #if 0 gss_release_buffer(&min_stat, &send_token); #else // 11/29/2010 [aglo] can't call sspi_relase_buffer, causes heap // corruption (later) to try and free the buffer directly. FreeContextBuffer(send_token.value); #endif if (call_stat != RPC_SUCCESS || (gr.gr_major != SEC_E_OK && gr.gr_major != SEC_I_CONTINUE_NEEDED)) break; if (gr.gr_ctx.length != 0) { #if 0 if (gd->gc.gc_ctx.value) gss_release_buffer(&min_stat, &gd->gc.gc_ctx); #else sspi_release_buffer(&gd->gc.gc_ctx); #endif gd->gc.gc_ctx = gr.gr_ctx; } if (gr.gr_token.length != 0) { if (maj_stat != SEC_I_CONTINUE_NEEDED) break; recv_tokenp = &gr.gr_token; in_desc.cBuffers = 1; in_desc.pBuffers = rtkn; in_desc.ulVersion = SECBUFFER_VERSION; rtkn[0].BufferType = SECBUFFER_TOKEN; rtkn[0].cbBuffer = gr.gr_token.length; rtkn[0].pvBuffer = gr.gr_token.value; } gd->gc.gc_proc = RPCSEC_SSPI_CONTINUE_INIT; } /* GSS_S_COMPLETE => check gss header verifier, * usually checked in gss_validate */ if (maj_stat == SEC_E_OK) { sspi_buffer_desc bufin; u_int seq, qop_state = 0; print_negotiated_attrs(&gd->ctx); seq = htonl(gr.gr_win); bufin.value = (unsigned char *)&seq; bufin.length = sizeof(seq); #if 0 maj_stat = gss_verify_mic(&min_stat, gd->ctx, &bufin, &bufout, &qop_state); #else maj_stat = sspi_verify_mic(&gd->ctx, 0, &bufin, &gd->gc_wire_verf, &qop_state); #endif if (maj_stat != SEC_E_OK) { log_debug("authgss_refresh: sspi_verify_mic failed with %x", maj_stat); if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) { gd->established = FALSE; authsspi_destroy_context(auth); } break; } gd->established = TRUE; gd->inprogress = FALSE; gd->gc.gc_proc = RPCSEC_SSPI_DATA; gd->gc.gc_seq = 0; gd->win = gr.gr_win; log_debug("authgss_refresh: established GSS context"); break; } } /* End context negotiation loop. */ if (gd->gc.gc_proc != RPCSEC_SSPI_DATA) { if (gr.gr_token.length != 0) #if 0 gss_release_buffer(&min_stat, &gr.gr_token); #else sspi_release_buffer(&gr.gr_token); #endif authsspi_destroy(auth); auth = NULL; rpc_createerr.cf_stat = RPC_AUTHERROR; return (FALSE); } return (TRUE); } bool_t authsspi_service(AUTH *auth, int svc) { struct rpc_sspi_data *gd; log_debug("in authgss_service()"); if (!auth) return(FALSE); gd = AUTH_PRIVATE(auth); if (!gd || !gd->established) return (FALSE); gd->sec->svc = svc; gd->gc.gc_svc = svc; return (TRUE); } static void authsspi_destroy_context(AUTH *auth) { struct rpc_sspi_data *gd; log_debug("in authgss_destroy_context()"); gd = AUTH_PRIVATE(auth); if (gd == NULL) return; if (SecIsValidHandle(&gd->ctx)) { if (gd->established) { gd->gc.gc_proc = RPCSEC_SSPI_DESTROY; clnt_call(gd->clnt, NULLPROC, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT); DeleteSecurityContext(&gd->ctx); } sspi_release_buffer(&gd->gc.gc_ctx); SecInvalidateHandle(&gd->ctx); #if 0 gss_release_buffer(&min_stat, &gd->gc.gc_ctx); /* XXX ANDROS check size of context - should be 8 */ memset(&gd->gc.gc_ctx, 0, sizeof(gd->gc.gc_ctx)); gss_delete_sec_context(&min_stat, &gd->ctx, NULL); #endif } /* free saved wire verifier (if any) */ mem_free(gd->gc_wire_verf.value, gd->gc_wire_verf.length); gd->gc_wire_verf.value = NULL; gd->gc_wire_verf.length = 0; gd->established = FALSE; } static void authsspi_destroy(AUTH *auth) { struct rpc_sspi_data *gd; log_debug("in authgss_destroy()"); gd = AUTH_PRIVATE(auth); if (gd == NULL) return; authsspi_destroy_context(auth); #if 0 if (gd->name != SSPI_C_NO_NAME) gss_release_name(&min_stat, &gd->name); #else free(gd->name); #endif FreeCredentialsHandle(&gd->sec->cred); free(gd->sec); free(gd); free(auth); } bool_t authsspi_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) { struct rpc_sspi_data *gd; log_debug("in authgss_wrap()"); gd = AUTH_PRIVATE(auth); if (!gd->established || gd->sec->svc == RPCSEC_SSPI_SVC_NONE) { return ((*xdr_func)(xdrs, xdr_ptr)); } return (xdr_rpc_sspi_data(xdrs, xdr_func, xdr_ptr, &gd->ctx, gd->sec->qop, gd->sec->svc, gd->gc.gc_seq)); } bool_t authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, u_int seq) { struct rpc_sspi_data *gd; log_debug("in authgss_unwrap()"); gd = AUTH_PRIVATE(auth); if (!gd->established || gd->sec->svc == RPCSEC_SSPI_SVC_NONE) { return ((*xdr_func)(xdrs, xdr_ptr)); } return (xdr_rpc_sspi_data(xdrs, xdr_func, xdr_ptr, &gd->ctx, gd->sec->qop, gd->sec->svc, seq)); } #ifdef __REACTOS__ uint32_t sspi_get_mic(void *dummy, u_int qop, u_int seq, sspi_buffer_desc *bufin, sspi_buffer_desc *bufout) { PCtxtHandle ctx = dummy; #else uint32_t sspi_get_mic(PCtxtHandle ctx, u_int qop, u_int seq, sspi_buffer_desc *bufin, sspi_buffer_desc *bufout) { #endif uint32_t maj_stat; SecPkgContext_Sizes ContextSizes; SecBufferDesc desc; SecBuffer sec_tkn[2]; log_hexdump(0, "sspi_get_mic: calculating checksum of", bufin->value, bufin->length, 0); memset(&ContextSizes, 0, sizeof(ContextSizes)); maj_stat = QueryContextAttributesA(ctx, SECPKG_ATTR_SIZES, &ContextSizes); if (maj_stat != SEC_E_OK) return maj_stat; if (ContextSizes.cbMaxSignature == 0) return SEC_E_INTERNAL_ERROR; desc.cBuffers = 2; desc.pBuffers = sec_tkn; desc.ulVersion = SECBUFFER_VERSION; sec_tkn[0].BufferType = SECBUFFER_DATA; sec_tkn[0].cbBuffer = bufin->length; sec_tkn[0].pvBuffer = bufin->value; sec_tkn[1].BufferType = SECBUFFER_TOKEN; sec_tkn[1].cbBuffer = ContextSizes.cbMaxSignature; sec_tkn[1].pvBuffer = calloc(ContextSizes.cbMaxSignature, sizeof(char)); if (sec_tkn[1].pvBuffer == NULL) return SEC_E_INSUFFICIENT_MEMORY; maj_stat = MakeSignature(ctx, 0, &desc, seq); if (maj_stat == SEC_E_OK) { bufout->length = sec_tkn[1].cbBuffer; bufout->value = sec_tkn[1].pvBuffer; log_hexdump(0, "sspi_get_mic: verifier is", bufout->value, bufout->length, 0); } else free(sec_tkn[1].pvBuffer); return maj_stat; } #ifndef __REACTOS__ uint32_t sspi_verify_mic(PCtxtHandle ctx, u_int seq, sspi_buffer_desc *bufin, sspi_buffer_desc *bufout, u_int *qop_state) { #else uint32_t sspi_verify_mic(void *dummy, u_int seq, sspi_buffer_desc *bufin, sspi_buffer_desc *bufout, u_int *qop_state) { PCtxtHandle ctx = dummy; #endif SecBufferDesc desc; SecBuffer sec_tkn[2]; desc.cBuffers = 2; desc.pBuffers = sec_tkn; desc.ulVersion = SECBUFFER_VERSION; sec_tkn[0].BufferType = SECBUFFER_DATA; sec_tkn[0].cbBuffer = bufin->length; sec_tkn[0].pvBuffer = bufin->value; sec_tkn[1].BufferType = SECBUFFER_TOKEN; sec_tkn[1].cbBuffer = bufout->length; sec_tkn[1].pvBuffer = bufout->value; log_hexdump(0, "sspi_verify_mic: calculating checksum over", bufin->value, bufin->length, 0); log_hexdump(0, "sspi_verify_mic: received checksum ", bufout->value, bufout->length, 0); return VerifySignature(ctx, &desc, seq, qop_state); } void sspi_release_buffer(sspi_buffer_desc *buf) { if (buf->value) free(buf->value); buf->value = NULL; buf->length = 0; } uint32_t sspi_import_name(sspi_buffer_desc *name_in, sspi_name_t *name_out) { *name_out = calloc(name_in->length + 5, sizeof(char)); if (*name_out == NULL) return SEC_E_INSUFFICIENT_MEMORY; strcpy(*name_out, "nfs/"); strncat(*name_out, name_in->value, name_in->length); log_debug("imported service name is: %s\n", *name_out); return SEC_E_OK; } #ifndef __REACTOS__ uint32_t sspi_wrap(PCtxtHandle ctx, u_int seq, sspi_buffer_desc *bufin, sspi_buffer_desc *bufout, u_int *conf_state) { #else uint32_t sspi_wrap(void *dummy, u_int seq, sspi_buffer_desc *bufin, sspi_buffer_desc *bufout, u_int *conf_state) { PCtxtHandle ctx = dummy; #endif uint32_t maj_stat; SecBufferDesc BuffDesc; SecBuffer SecBuff[3]; ULONG ulQop = 0; SecPkgContext_Sizes ContextSizes; PBYTE p; maj_stat = QueryContextAttributes(ctx, SECPKG_ATTR_SIZES, &ContextSizes); if (maj_stat != SEC_E_OK) goto out; BuffDesc.ulVersion = 0; BuffDesc.cBuffers = 3; BuffDesc.pBuffers = SecBuff; SecBuff[0].cbBuffer = ContextSizes.cbSecurityTrailer; SecBuff[0].BufferType = SECBUFFER_TOKEN; SecBuff[0].pvBuffer = malloc(ContextSizes.cbSecurityTrailer); SecBuff[1].cbBuffer = bufin->length; SecBuff[1].BufferType = SECBUFFER_DATA; SecBuff[1].pvBuffer = bufin->value; log_hexdump(0, "plaintext:", bufin->value, bufin->length, 0); SecBuff[2].cbBuffer = ContextSizes.cbBlockSize; SecBuff[2].BufferType = SECBUFFER_PADDING; SecBuff[2].pvBuffer = malloc(ContextSizes.cbBlockSize); maj_stat = EncryptMessage(ctx, ulQop, &BuffDesc, seq); if (maj_stat != SEC_E_OK) goto out_free; bufout->length = SecBuff[0].cbBuffer + SecBuff[1].cbBuffer + SecBuff[2].cbBuffer; p = bufout->value = malloc(bufout->length); memcpy(p, SecBuff[0].pvBuffer, SecBuff[0].cbBuffer); p += SecBuff[0].cbBuffer; memcpy(p, SecBuff[1].pvBuffer, SecBuff[1].cbBuffer); p += SecBuff[1].cbBuffer; memcpy(p, SecBuff[2].pvBuffer, SecBuff[2].cbBuffer); out_free: free(SecBuff[0].pvBuffer); free(SecBuff[2].pvBuffer); if (!maj_stat) log_hexdump(0, "cipher:", bufout->value, bufout->length, 0); out: return maj_stat; } #ifndef __REACTOS__ uint32_t sspi_unwrap(PCtxtHandle ctx, u_int seq, sspi_buffer_desc *bufin, sspi_buffer_desc *bufout, u_int *conf_state, u_int *qop_state) { #else uint32_t sspi_unwrap(void *dummy, u_int seq, sspi_buffer_desc *bufin, sspi_buffer_desc *bufout, u_int *conf_state, u_int *qop_state) { PCtxtHandle ctx = dummy; #endif uint32_t maj_stat; SecBufferDesc BuffDesc; SecBuffer SecBuff[2]; ULONG ulQop = 0; BuffDesc.ulVersion = 0; BuffDesc.cBuffers = 2; BuffDesc.pBuffers = SecBuff; SecBuff[0].cbBuffer = bufin->length; SecBuff[0].BufferType = SECBUFFER_STREAM; SecBuff[0].pvBuffer = bufin->value; SecBuff[1].cbBuffer = 0; SecBuff[1].BufferType = SECBUFFER_DATA; SecBuff[1].pvBuffer = NULL; log_hexdump(0, "cipher:", bufin->value, bufin->length, 0); maj_stat = DecryptMessage(ctx, &BuffDesc, seq, &ulQop); if (maj_stat != SEC_E_OK) return maj_stat; bufout->length = SecBuff[1].cbBuffer; bufout->value = malloc(bufout->length); memcpy(bufout->value, SecBuff[1].pvBuffer, bufout->length); log_hexdump(0, "data:", bufout->value, bufout->length, 0); *conf_state = 1; *qop_state = 0; return SEC_E_OK; } /* useful as i add more mechanisms */ #define DEBUG #ifdef DEBUG #define fd_out stdout void print_rpc_gss_sec(struct rpc_sspi_sec *ptr) { int i; char *p; fprintf(fd_out, "rpc_gss_sec:"); if(ptr->mech == NULL) fprintf(fd_out, "NULL gss_OID mech"); else { fprintf(fd_out, " mechanism_OID: {"); p = (char *)ptr->mech->elements; for (i=0; i < ptr->mech->length; i++) /* First byte of OIDs encoded to save a byte */ if (i == 0) { int first, second; if (*p < 40) { first = 0; second = *p; } else if (40 <= *p && *p < 80) { first = 1; second = *p - 40; } else if (80 <= *p && *p < 127) { first = 2; second = *p - 80; } else { /* Invalid value! */ first = -1; second = -1; } fprintf(fd_out, " %u %u", first, second); p++; } else { fprintf(fd_out, " %u", (unsigned char)*p++); } fprintf(fd_out, " }\n"); } fprintf(fd_out, " qop: %d\n", ptr->qop); fprintf(fd_out, " service: %d\n", ptr->svc); fprintf(fd_out, " cred: %p\n", ptr->cred); } void print_negotiated_attrs(PCtxtHandle ctx) { SecPkgContext_Sizes ContextSizes; unsigned long flags; uint32_t maj_stat; maj_stat = QueryContextAttributesA(ctx, SECPKG_ATTR_FLAGS, &flags); if (maj_stat != SEC_E_OK) return; log_debug("negotiated flags %x\n", flags); if (flags & ISC_REQ_DELEGATE) log_debug("ISC_REQ_DELEGATE"); if (flags & ISC_REQ_MUTUAL_AUTH) log_debug("ISC_REQ_MUTUAL_AUTH"); if (flags & ISC_REQ_REPLAY_DETECT) log_debug("ISC_REQ_REPLAY_DETECT"); if (flags & ISC_REQ_SEQUENCE_DETECT) log_debug("ISC_REQ_SEQUENCE_DETECT"); if (flags & ISC_REQ_CONFIDENTIALITY) log_debug("ISC_REQ_CONFIDENTIALITY"); if (flags & ISC_REQ_USE_SESSION_KEY) log_debug("ISC_REQ_USE_SESSION_KEY"); if (flags & ISC_REQ_PROMPT_FOR_CREDS) log_debug("ISC_REQ_PROMPT_FOR_CREDS"); if (flags & ISC_REQ_USE_SUPPLIED_CREDS) log_debug("ISC_REQ_USE_SUPPLIED_CREDS"); if (flags & ISC_REQ_ALLOCATE_MEMORY) log_debug("ISC_REQ_ALLOCATE_MEMORY"); if (flags & ISC_REQ_USE_DCE_STYLE) log_debug("ISC_REQ_USE_DCE_STYLE"); if (flags & ISC_REQ_DATAGRAM) log_debug("ISC_REQ_DATAGRAM"); if (flags & ISC_REQ_CONNECTION) log_debug("ISC_REQ_CONNECTION"); if (flags & ISC_REQ_CALL_LEVEL) log_debug("ISC_REQ_CALL_LEVEL"); if (flags & ISC_REQ_FRAGMENT_SUPPLIED) log_debug("ISC_REQ_FRAGMENT_SUPPLIED"); if (flags & ISC_REQ_EXTENDED_ERROR) log_debug("ISC_REQ_EXTENDED_ERROR"); if (flags & ISC_REQ_STREAM) log_debug("ISC_REQ_STREAM"); if (flags & ISC_REQ_INTEGRITY) log_debug("ISC_REQ_INTEGRITY"); if (flags & ISC_REQ_IDENTIFY) log_debug("ISC_REQ_IDENTIFY"); if (flags & ISC_REQ_NULL_SESSION) log_debug("ISC_REQ_NULL_SESSION"); if (flags & ISC_REQ_MANUAL_CRED_VALIDATION) log_debug("ISC_REQ_MANUAL_CRED_VALIDATION"); maj_stat = QueryContextAttributesA(ctx, SECPKG_ATTR_SIZES, &ContextSizes); if (maj_stat != SEC_E_OK) return; log_debug("signature size is %d\n", ContextSizes.cbMaxSignature); } void log_hexdump(bool_t on, const u_char *title, const u_char *buf, int len, int offset) { int i, j, jm, c; if (!on) return; fprintf(fd_out, "%04x: %s (len=%d)\n", GetCurrentThreadId(), title, len); for (i = 0; i < len; i += 0x10) { fprintf(fd_out, " %04x: ", (u_int)(i + offset)); jm = len - i; jm = jm > 16 ? 16 : jm; for (j = 0; j < jm; j++) { if ((j % 2) == 1) fprintf(fd_out, "%02x ", (u_int) buf[i+j]); else fprintf(fd_out, "%02x", (u_int) buf[i+j]); } for (; j < 16; j++) { if ((j % 2) == 1) fprintf(fd_out, " "); else fprintf(fd_out, " "); } fprintf(fd_out, " "); for (j = 0; j < jm; j++) { c = buf[i+j]; c = isprint(c) ? c : '.'; fprintf(fd_out, "%c", c); } fprintf(fd_out, "\n"); } fflush(fd_out); } void log_debug(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(fd_out, "%04x: rpcsec_gss: ", GetCurrentThreadId()); vfprintf(fd_out, fmt, ap); fprintf(fd_out, "\n"); fflush(fd_out); va_end(ap); } #else void print_rpc_gss_sec(struct rpc_sspi_sec *ptr) { return; } void print_negotiated_flags(unsigned long flags) {return; } void log_hexdump(bool_t on, const u_char *title, const u_char *buf, int len, int offset) { return; } void log_debug(const char *fmt, ...) { return; } #endif