From b9494c3cccadeb8315fcd37cce9bc6efb6c32d84 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Tue, 30 Nov 2010 13:02:32 -0500 Subject: [PATCH] first stab at SSPI leaving gss calls in --- build.vc10/libtirpc.vcxproj | 5 +- build.vc10/libtirpc.vcxproj.filters | 9 + daemon/nfs41_rpc.c | 50 +- libtirpc/libtirpc/libtirpc.def | 2 + libtirpc/src/auth_none.c | 8 +- libtirpc/src/auth_sspi.c | 1485 +++++++++++++++------------ libtirpc/src/auth_unix.c | 10 +- libtirpc/src/authsspi_prot.c | 303 ++++++ libtirpc/src/clnt_dg.c | 4 +- libtirpc/src/clnt_raw.c | 6 +- libtirpc/src/clnt_vc.c | 5 +- libtirpc/src/sources | 5 +- libtirpc/src/xdr_rec.c | 26 +- libtirpc/tirpc/rpc/auth.h | 19 +- libtirpc/tirpc/rpc/auth_sspi.h | 117 +++ libtirpc/tirpc/rpc/xdr.h | 1 + sys/nfs41_driver.c | 2 +- 17 files changed, 1380 insertions(+), 677 deletions(-) create mode 100644 libtirpc/src/authsspi_prot.c create mode 100644 libtirpc/tirpc/rpc/auth_sspi.h diff --git a/build.vc10/libtirpc.vcxproj b/build.vc10/libtirpc.vcxproj index 993cbde..3a3d3e3 100644 --- a/build.vc10/libtirpc.vcxproj +++ b/build.vc10/libtirpc.vcxproj @@ -125,7 +125,7 @@ ProgramDatabase - ws2_32.lib;%(AdditionalDependencies) + ws2_32.lib;secur32.lib;%(AdditionalDependencies) ..\libtirpc\libtirpc\libtirpc.def true Windows @@ -187,7 +187,9 @@ + + @@ -257,6 +259,7 @@ + diff --git a/build.vc10/libtirpc.vcxproj.filters b/build.vc10/libtirpc.vcxproj.filters index d4485cc..d297f09 100644 --- a/build.vc10/libtirpc.vcxproj.filters +++ b/build.vc10/libtirpc.vcxproj.filters @@ -207,6 +207,12 @@ Source Files + + Source Files + + + Source Files + @@ -341,6 +347,9 @@ Header Files + + Header Files + diff --git a/daemon/nfs41_rpc.c b/daemon/nfs41_rpc.c index d61e6e6..5951bfe 100644 --- a/daemon/nfs41_rpc.c +++ b/daemon/nfs41_rpc.c @@ -27,6 +27,9 @@ #include "nfs41_callback.h" #include "rpc/rpc.h" +#define SECURITY_WIN32 +#include +#include "rpc/auth_sspi.h" static enum clnt_stat send_null(CLIENT *client) { @@ -42,6 +45,7 @@ static int get_client_for_netaddr( IN uint32_t wsize, IN uint32_t rsize, IN nfs41_rpc_clnt *rpc, + OUT char **server_name, OUT CLIENT **client_out) { int status = ERROR_NETWORK_UNREACHABLE; @@ -57,6 +61,13 @@ static int get_client_for_netaddr( if (addr == NULL) goto out_free_conf; + *server_name = calloc(NFS41_HOSTNAME_LEN, sizeof(char)); + if (*server_name == NULL) + goto out_free_addr; + + getnameinfo(addr->buf, addr->len, *server_name, NFS41_HOSTNAME_LEN, NULL, 0, 0); + dprintf(1, "servername is %s\n", *server_name); + dprintf(1, "callback function %p args %p\n", nfs41_handle_callback, rpc); client = clnt_tli_create(RPC_ANYFD, nconf, addr, NFS41_RPC_PROGRAM, NFS41_RPC_VERSION, wsize, rsize, @@ -79,6 +90,7 @@ static int get_client_for_multi_addr( IN uint32_t wsize, IN uint32_t rsize, IN nfs41_rpc_clnt *rpc, + OUT char **server_name, OUT CLIENT **client_out, OUT uint32_t *addr_index) { @@ -86,7 +98,7 @@ static int get_client_for_multi_addr( uint32_t i; for (i = 0; i < addrs->count; i++) { status = get_client_for_netaddr(&addrs->arr[i], - wsize, rsize, rpc, client_out); + wsize, rsize, rpc, server_name, client_out); if (status == NO_ERROR) { *addr_index = i; break; @@ -111,6 +123,7 @@ int nfs41_rpc_clnt_create( int status; char machname[MAXHOSTNAMELEN + 1]; gid_t gids[1]; + char *server_name = NULL; rpc = calloc(1, sizeof(nfs41_rpc_clnt)); if (rpc == NULL) { @@ -123,13 +136,19 @@ int nfs41_rpc_clnt_create( eprintf("CreateEvent failed %d\n", status); goto out_free_rpc_clnt; } - - status = get_client_for_multi_addr(addrs, - wsize, rsize, needcb?rpc:NULL, &client, &addr_index); + status = get_client_for_multi_addr(addrs, wsize, rsize, needcb?rpc:NULL, + &server_name, &client, &addr_index); if (status) { clnt_pcreateerror("connecting failed"); goto out_free_rpc_clnt; } + if (send_null(client) != RPC_SUCCESS) { + // XXX Do what here? + eprintf("nfs41_rpc_clnt_create: send_null failed\n"); + status = ERROR_NETWORK_UNREACHABLE; + goto out_err_auth; + } +#if 0 // XXX Pick credentials in better manner if (gethostname(machname, sizeof(machname)) == -1) { eprintf("nfs41_rpc_clnt_create: gethostname failed\n"); @@ -140,16 +159,22 @@ int nfs41_rpc_clnt_create( if (client->cl_auth == NULL) { // XXX log failure in auth creation somewhere // XXX Better error return + eprintf("nfs41_rpc_clnt_create: failed to create AUTHSYS\n"); status = ERROR_NETWORK_UNREACHABLE; goto out_err_client; - } - if (send_null(client) != RPC_SUCCESS) { - // XXX Do what here? - eprintf("nfs41_rpc_clnt_create: send_null failed\n"); + } else dprintf(1, "nfs41_rpc_clnt_create: successfully created AUTHSYS\n"); +#else + client->cl_auth = authsspi_create_default(client, server_name, RPCSEC_SSPI_SVC_NONE); +#endif + if (client->cl_auth == NULL) { + // XXX log failure in auth creation somewhere + // XXX Better error return + eprintf("nfs41_rpc_clnt_create: failed to create AUTHGSS\n"); status = ERROR_NETWORK_UNREACHABLE; - goto out_err_auth; - } + goto out_err_client; + } else dprintf(1, "nfs41_rpc_clnt_create: successfully created AUTHGSS\n"); + free(server_name); rpc->rpc = client; /* keep a copy of the address and buffer sizes for reconnect */ @@ -219,11 +244,12 @@ static int rpc_reconnect( CLIENT *client = NULL; uint32_t addr_index; int status; + char *server_name = NULL; AcquireSRWLockExclusive(&rpc->lock); - status = get_client_for_multi_addr(&rpc->addrs, - rpc->wsize, rpc->rsize, rpc, &client, &addr_index); + status = get_client_for_multi_addr(&rpc->addrs, rpc->wsize, rpc->rsize, + rpc, &server_name, &client, &addr_index); if (status) goto out_unlock; diff --git a/libtirpc/libtirpc/libtirpc.def b/libtirpc/libtirpc/libtirpc.def index ce2ff85..ca28582 100644 --- a/libtirpc/libtirpc/libtirpc.def +++ b/libtirpc/libtirpc/libtirpc.def @@ -3,6 +3,8 @@ EXPORTS authnone_create authunix_create authunix_create_default +authsspi_create +authsspi_create_default clnt_create clnt_broadcast clnt_pcreateerror diff --git a/libtirpc/src/auth_none.c b/libtirpc/src/auth_none.c index dcaf464..fc5654e 100644 --- a/libtirpc/src/auth_none.c +++ b/libtirpc/src/auth_none.c @@ -58,9 +58,9 @@ __FBSDID("$FreeBSD: src/lib/libc/rpc/auth_none.c,v 1.12 2002/03/22 23:18:35 obri * Authenticator operations routines */ -static bool_t authnone_marshal (AUTH *, XDR *); +static bool_t authnone_marshal (AUTH *, XDR *, u_int *); static void authnone_verf (AUTH *); -static bool_t authnone_validate (AUTH *, struct opaque_auth *); +static bool_t authnone_validate (AUTH *, struct opaque_auth *, u_int); static bool_t authnone_refresh (AUTH *, void *); static void authnone_destroy (AUTH *); @@ -108,7 +108,7 @@ authnone_create() /*ARGSUSED*/ static bool_t -authnone_marshal(AUTH *client, XDR *xdrs) +authnone_marshal(AUTH *client, XDR *xdrs, u_int *seq) { struct authnone_private *ap; bool_t dummy; @@ -136,7 +136,7 @@ authnone_verf(AUTH *client) /*ARGSUSED*/ static bool_t -authnone_validate(AUTH *client, struct opaque_auth *opaque) +authnone_validate(AUTH *client, struct opaque_auth *opaque, u_int seq) { return (TRUE); diff --git a/libtirpc/src/auth_sspi.c b/libtirpc/src/auth_sspi.c index 437ba85..e53b37a 100644 --- a/libtirpc/src/auth_sspi.c +++ b/libtirpc/src/auth_sspi.c @@ -1,634 +1,851 @@ -/* - * auth_sspi.c - * - * RPCSEC_GSS client routines (using the Windows SSPI rather than GSS-API). - * - * Copyright (c) 2000 Dug Song . - * All rights reserved, all wrongs reversed. - * - * COPYRIGHT (c) 2010 - * The Regents of the University of Michigan - * ALL RIGHTS RESERVED - * - * Permission is granted to use, copy, create derivative works - * and redistribute this software and such derivative works - * for any purpose, so long as the name of The University of - * Michigan is not used in any advertising or publicity - * pertaining to the use of distribution of this software - * without specific, written prior authorization. If the - * above copyright notice or any other identification of the - * University of Michigan is included in any copy of any - * portion of this software, then the disclaimer below must - * also be included. - * - * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION - * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY - * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF - * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING - * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE - * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE - * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING - * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN - * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGES. - * - */ - -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#include -//#include -//#include - -static void authgss_nextverf(); -static bool_t authgss_marshal(); -static bool_t authgss_refresh(); -static bool_t authgss_validate(); -static void authgss_destroy(); -static void authgss_destroy_context(); -static bool_t authgss_wrap(); -static bool_t authgss_unwrap(); - - -/* - * from mit-krb5-1.2.1 mechglue/mglueP.h: - * Array of context IDs typed by mechanism OID - */ -typedef struct gss_union_ctx_id_t { - gss_OID mech_type; - gss_ctx_id_t internal_ctx_id; -} gss_union_ctx_id_desc, *gss_union_ctx_id_t; - -static struct auth_ops authgss_ops = { - authgss_nextverf, - authgss_marshal, - authgss_validate, - authgss_refresh, - authgss_destroy, - authgss_wrap, - authgss_unwrap -}; - -#ifdef DEBUG - -/* useful as i add more mechanisms */ -void -print_rpc_gss_sec(struct rpc_gss_sec *ptr) -{ -int i; -char *p; - - log_debug("rpc_gss_sec:"); - if(ptr->mech == NULL) - log_debug("NULL gss_OID mech"); - else { - fprintf(stderr, " 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(stderr, " %u %u", first, second); - p++; - } - else { - fprintf(stderr, " %u", (unsigned char)*p++); - } - fprintf(stderr, " }\n"); - } - fprintf(stderr, " qop: %d\n", ptr->qop); - fprintf(stderr, " service: %d\n", ptr->svc); - fprintf(stderr, " cred: %p\n", ptr->cred); -} -#endif /*DEBUG*/ - -struct rpc_gss_data { - bool_t established; /* context established */ - gss_buffer_desc gc_wire_verf; /* save GSS_S_COMPLETE NULL RPC verfier - * to process at end of context negotiation*/ - CLIENT *clnt; /* client handle */ - gss_name_t name; /* service name */ - struct rpc_gss_sec sec; /* security tuple */ - gss_ctx_id_t ctx; /* context id */ - struct rpc_gss_cred gc; /* client credentials */ - u_int win; /* sequence window */ -}; - -#define AUTH_PRIVATE(auth) ((struct rpc_gss_data *)auth->ah_private) - -static struct timeval AUTH_TIMEOUT = { 25, 0 }; - -AUTH * -authgss_create(CLIENT *clnt, gss_name_t name, struct rpc_gss_sec *sec) -{ - AUTH *auth, *save_auth; - struct rpc_gss_data *gd; - OM_uint32 min_stat = 0; - - 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); - } -#ifdef DEBUG - fprintf(stderr, "authgss_create: name is %p\n", name); -#endif - if (name != GSS_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 - gd->name = name; - -#ifdef DEBUG - fprintf(stderr, "authgss_create: gd->name is %p\n", gd->name); -#endif - gd->clnt = clnt; - gd->ctx = GSS_C_NO_CONTEXT; - gd->sec = *sec; - - gd->gc.gc_v = RPCSEC_GSS_VERSION; - gd->gc.gc_proc = RPCSEC_GSS_INIT; - gd->gc.gc_svc = gd->sec.svc; - - auth->ah_ops = &authgss_ops; - auth->ah_private = (caddr_t)gd; - - save_auth = clnt->cl_auth; - clnt->cl_auth = auth; - - if (!authgss_refresh(auth)) - auth = NULL; - - clnt->cl_auth = save_auth; - - return (auth); -} - -AUTH * -authgss_create_default(CLIENT *clnt, char *service, struct rpc_gss_sec *sec) -{ - AUTH *auth; - OM_uint32 maj_stat = 0, min_stat = 0; - gss_buffer_desc sname; - gss_name_t name = GSS_C_NO_NAME; - - log_debug("in authgss_create_default()"); - - - sname.value = service; - sname.length = strlen(service); - - maj_stat = gss_import_name(&min_stat, &sname, - (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, - &name); - - if (maj_stat != GSS_S_COMPLETE) { - log_status("gss_import_name", maj_stat, min_stat); - rpc_createerr.cf_stat = RPC_AUTHERROR; - return (NULL); - } - - auth = authgss_create(clnt, name, sec); - - if (name != GSS_C_NO_NAME) { -#ifdef DEBUG - fprintf(stderr, "authgss_create_default: freeing name %p\n", name); -#endif - gss_release_name(&min_stat, &name); - } - - return (auth); -} - -bool_t -authgss_get_private_data(AUTH *auth, struct authgss_private_data *pd) -{ - struct rpc_gss_data *gd; - - log_debug("in authgss_get_private_data()"); - - if (!auth || !pd) - return (FALSE); - - gd = AUTH_PRIVATE(auth); - - if (!gd || !gd->established) - return (FALSE); - - pd->pd_ctx = gd->ctx; - pd->pd_ctx_hndl = gd->gc.gc_ctx; - pd->pd_seq_win = gd->win; - - return (TRUE); -} - -static void -authgss_nextverf(AUTH *auth) -{ - log_debug("in authgss_nextverf()"); - /* no action necessary */ -} - -static bool_t -authgss_marshal(AUTH *auth, XDR *xdrs) -{ - XDR tmpxdrs; - char tmp[MAX_AUTH_BYTES]; - struct rpc_gss_data *gd; - gss_buffer_desc rpcbuf, checksum; - OM_uint32 maj_stat, min_stat; - bool_t xdr_stat; - - log_debug("in authgss_marshal()"); - - gd = AUTH_PRIVATE(auth); - - if (gd->established) - gd->gc.gc_seq++; - - xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE); - - if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gc)) { - 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)) - return (FALSE); - - if (gd->gc.gc_proc == RPCSEC_GSS_INIT || - gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { - return (xdr_opaque_auth(xdrs, &_null_auth)); - } - /* Checksum serialized RPC header, up to and including credential. */ - rpcbuf.length = XDR_GETPOS(xdrs); - XDR_SETPOS(xdrs, 0); - rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length); - - maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, - &rpcbuf, &checksum); - - if (maj_stat != GSS_S_COMPLETE) { - log_status("gss_get_mic", maj_stat, min_stat); - if (maj_stat == GSS_S_CONTEXT_EXPIRED) { - gd->established = FALSE; - authgss_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); - gss_release_buffer(&min_stat, &checksum); - - return (xdr_stat); -} - -static bool_t -authgss_validate(AUTH *auth, struct opaque_auth *verf) -{ - struct rpc_gss_data *gd; - u_int num, qop_state; - gss_buffer_desc signbuf, checksum; - OM_uint32 maj_stat, min_stat; - - log_debug("in authgss_validate()"); - - 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) { - fprintf(stderr, "gss_validate: out of memory\n"); - 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_GSS_INIT || - gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { - num = htonl(gd->win); - } - else num = htonl(gd->gc.gc_seq); - - signbuf.value = # - signbuf.length = sizeof(num); - - checksum.value = verf->oa_base; - checksum.length = verf->oa_length; - - maj_stat = gss_verify_mic(&min_stat, gd->ctx, &signbuf, - &checksum, &qop_state); - if (maj_stat != GSS_S_COMPLETE || qop_state != gd->sec.qop) { - log_status("gss_verify_mic", maj_stat, min_stat); - if (maj_stat == GSS_S_CONTEXT_EXPIRED) { - gd->established = FALSE; - authgss_destroy_context(auth); - } - return (FALSE); - } - return (TRUE); -} - -static bool_t -authgss_refresh(AUTH *auth) -{ - struct rpc_gss_data *gd; - struct rpc_gss_init_res gr; - gss_buffer_desc *recv_tokenp, send_token; - OM_uint32 maj_stat, min_stat, call_stat, ret_flags; - - log_debug("in authgss_refresh()"); - - gd = AUTH_PRIVATE(auth); - - if (gd->established) - return (TRUE); - - /* GSS context establishment loop. */ - memset(&gr, 0, sizeof(gr)); - recv_tokenp = GSS_C_NO_BUFFER; - -#ifdef DEBUG - print_rpc_gss_sec(&gd->sec); -#endif /*DEBUG*/ - - for (;;) { -#ifdef DEBUG - /* print the token we just received */ - if (recv_tokenp != GSS_C_NO_BUFFER) { - log_debug("The token we just received (length %d):", - recv_tokenp->length); - log_hexdump(recv_tokenp->value, recv_tokenp->length, 0); - } -#endif - 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 */ - - if (recv_tokenp != GSS_C_NO_BUFFER) { - gss_release_buffer(&min_stat, &gr.gr_token); - recv_tokenp = GSS_C_NO_BUFFER; - } - if (maj_stat != GSS_S_COMPLETE && - maj_stat != GSS_S_CONTINUE_NEEDED) { - log_status("gss_init_sec_context", maj_stat, min_stat); - break; - } - if (send_token.length != 0) { - memset(&gr, 0, sizeof(gr)); - -#ifdef DEBUG - /* print the token we are about to send */ - log_debug("The token being sent (length %d):", - send_token.length); - log_hexdump(send_token.value, send_token.length, 0); -#endif - - call_stat = clnt_call(gd->clnt, NULLPROC, - (xdrproc_t)xdr_rpc_gss_init_args, - &send_token, - (xdrproc_t)xdr_rpc_gss_init_res, - (caddr_t)&gr, AUTH_TIMEOUT); - - gss_release_buffer(&min_stat, &send_token); - - if (call_stat != RPC_SUCCESS || - (gr.gr_major != GSS_S_COMPLETE && - gr.gr_major != GSS_S_CONTINUE_NEEDED)) - return FALSE; - - if (gr.gr_ctx.length != 0) { - if (gd->gc.gc_ctx.value) - gss_release_buffer(&min_stat, - &gd->gc.gc_ctx); - gd->gc.gc_ctx = gr.gr_ctx; - } - if (gr.gr_token.length != 0) { - if (maj_stat != GSS_S_CONTINUE_NEEDED) - break; - recv_tokenp = &gr.gr_token; - } - gd->gc.gc_proc = RPCSEC_GSS_CONTINUE_INIT; - } - - /* GSS_S_COMPLETE => check gss header verifier, - * usually checked in gss_validate - */ - if (maj_stat == GSS_S_COMPLETE) { - gss_buffer_desc bufin; - gss_buffer_desc bufout; - u_int seq, qop_state = 0; - - seq = htonl(gr.gr_win); - bufin.value = (unsigned char *)&seq; - bufin.length = sizeof(seq); - bufout.value = (unsigned char *)gd->gc_wire_verf.value; - bufout.length = gd->gc_wire_verf.length; - - maj_stat = gss_verify_mic(&min_stat, gd->ctx, - &bufin, &bufout, &qop_state); - - if (maj_stat != GSS_S_COMPLETE - || qop_state != gd->sec.qop) { - log_status("gss_verify_mic", maj_stat, min_stat); - if (maj_stat == GSS_S_CONTEXT_EXPIRED) { - gd->established = FALSE; - authgss_destroy_context(auth); - } - return (FALSE); - } - gd->established = TRUE; - gd->gc.gc_proc = RPCSEC_GSS_DATA; - gd->gc.gc_seq = 0; - gd->win = gr.gr_win; - break; - } - } - /* End context negotiation loop. */ - if (gd->gc.gc_proc != RPCSEC_GSS_DATA) { - if (gr.gr_token.length != 0) - gss_release_buffer(&min_stat, &gr.gr_token); - - authgss_destroy(auth); - auth = NULL; - rpc_createerr.cf_stat = RPC_AUTHERROR; - - return (FALSE); - } - return (TRUE); -} - -bool_t -authgss_service(AUTH *auth, int svc) -{ - struct rpc_gss_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 -authgss_destroy_context(AUTH *auth) -{ - struct rpc_gss_data *gd; - OM_uint32 min_stat; - - log_debug("in authgss_destroy_context()"); - - gd = AUTH_PRIVATE(auth); - - if (gd->gc.gc_ctx.length != 0) { - if (gd->established) { - gd->gc.gc_proc = RPCSEC_GSS_DESTROY; - clnt_call(gd->clnt, NULLPROC, (xdrproc_t)xdr_void, NULL, - (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT); - } - 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)); - } - if (gd->ctx != GSS_C_NO_CONTEXT) { - gss_delete_sec_context(&min_stat, &gd->ctx, NULL); - gd->ctx = GSS_C_NO_CONTEXT; - } - - /* 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 -authgss_destroy(AUTH *auth) -{ - struct rpc_gss_data *gd; - OM_uint32 min_stat; - - log_debug("in authgss_destroy()"); - - gd = AUTH_PRIVATE(auth); - - authgss_destroy_context(auth); - -#ifdef DEBUG - fprintf(stderr, "authgss_destroy: freeing name %p\n", gd->name); -#endif - if (gd->name != GSS_C_NO_NAME) - gss_release_name(&min_stat, &gd->name); - - free(gd); - free(auth); -} - -bool_t -authgss_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) -{ - struct rpc_gss_data *gd; - - log_debug("in authgss_wrap()"); - - gd = AUTH_PRIVATE(auth); - - if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { - return ((*xdr_func)(xdrs, xdr_ptr)); - } - return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, - gd->ctx, gd->sec.qop, - gd->sec.svc, gd->gc.gc_seq)); -} - -bool_t -authgss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) -{ - struct rpc_gss_data *gd; - - log_debug("in authgss_unwrap()"); - - gd = AUTH_PRIVATE(auth); - - if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { - return ((*xdr_func)(xdrs, xdr_ptr)); - } - return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, - gd->ctx, gd->sec.qop, - gd->sec.svc, gd->gc.gc_seq)); -} +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#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); + +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 */ + 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 = 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); + goto out_free_sec; + } + + auth = authsspi_create(clnt, name, sec); + if (auth == NULL) + goto out_free_cred; + +out: + if (name != SSPI_C_NO_NAME) { +#if 0 + gss_release_name(&min_stat, &name); +#else + free(name); +#endif + } + + return (auth); +out_free_cred: + FreeCredentialsHandle(&sec->cred); +out_free_sec: + 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_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 || qop_state != gd->sec->qop) { + 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) + return (TRUE); + + /* 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); + + 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 + 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)) + return FALSE; + + 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 || qop_state != gd->sec->qop) { + 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); + } + return (FALSE); + } + gd->established = TRUE; + 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 (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); + + 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) +{ + 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, gd->gc.gc_seq)); +} + +uint32_t sspi_get_mic(PCtxtHandle ctx, u_int qop, u_int seq, + sspi_buffer_desc *bufin, sspi_buffer_desc *bufout) +{ + 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; +} + +uint32_t sspi_verify_mic(PCtxtHandle ctx, u_int seq, sspi_buffer_desc *bufin, + sspi_buffer_desc *bufout, u_int *qop_state) +{ + 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; +} +/* 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, "%s\n", title); + 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 diff --git a/libtirpc/src/auth_unix.c b/libtirpc/src/auth_unix.c index 2aa550a..c3a69ad 100644 --- a/libtirpc/src/auth_unix.c +++ b/libtirpc/src/auth_unix.c @@ -58,8 +58,8 @@ /* auth_unix.c */ static void authunix_nextverf (AUTH *); -static bool_t authunix_marshal (AUTH *, XDR *); -static bool_t authunix_validate (AUTH *, struct opaque_auth *); +static bool_t authunix_marshal (AUTH *, XDR *, u_int *seq); +static bool_t authunix_validate (AUTH *, struct opaque_auth *, u_int); static bool_t authunix_refresh (AUTH *, void *); static void authunix_destroy (AUTH *); static void marshal_new_auth (AUTH *); @@ -213,9 +213,10 @@ authunix_nextverf(auth) } static bool_t -authunix_marshal(auth, xdrs) +authunix_marshal(auth, xdrs, seq) AUTH *auth; XDR *xdrs; + u_int *seq; { struct audata *au; @@ -227,9 +228,10 @@ authunix_marshal(auth, xdrs) } static bool_t -authunix_validate(auth, verf) +authunix_validate(auth, verf, seq) AUTH *auth; struct opaque_auth *verf; + u_int seq; { struct audata *au; XDR xdrs; diff --git a/libtirpc/src/authsspi_prot.c b/libtirpc/src/authsspi_prot.c new file mode 100644 index 0000000..09c0709 --- /dev/null +++ b/libtirpc/src/authsspi_prot.c @@ -0,0 +1,303 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include + +bool_t +xdr_rpc_sspi_cred(XDR *xdrs, struct rpc_sspi_cred *p) +{ + bool_t xdr_stat; + + xdr_stat = (xdr_u_int(xdrs, &p->gc_v) && + xdr_enum(xdrs, (enum_t *)&p->gc_proc) && + xdr_u_int(xdrs, &p->gc_seq) && + xdr_enum(xdrs, (enum_t *)&p->gc_svc) && + xdr_bytes(xdrs, (char **)&p->gc_ctx.value, + (u_int *)&p->gc_ctx.length, MAX_AUTH_BYTES)); + + log_debug("xdr_rpc_gss_cred: %s %s " + "(v %d, proc %d, seq %d, svc %d, ctx %p:%d)", + (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", + (xdr_stat == TRUE) ? "success" : "failure", + p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc, + p->gc_ctx.value, p->gc_ctx.length); + + return (xdr_stat); +} + +bool_t +xdr_rpc_sspi_init_args(XDR *xdrs, sspi_buffer_desc *p) +{ + bool_t xdr_stat; + + xdr_stat = xdr_bytes(xdrs, (char **)&p->value, + (u_int *)&p->length, MAX_NETOBJ_SZ); + + log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%d)", + (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", + (xdr_stat == TRUE) ? "success" : "failure", + p->value, p->length); + + return (xdr_stat); +} + +bool_t +xdr_rpc_sspi_init_res(XDR *xdrs, struct rpc_sspi_init_res *p) +{ + bool_t xdr_stat; + + xdr_stat = (xdr_bytes(xdrs, (char **)&p->gr_ctx.value, + (u_int *)&p->gr_ctx.length, MAX_NETOBJ_SZ) && + xdr_u_int(xdrs, &p->gr_major) && + xdr_u_int(xdrs, &p->gr_minor) && + xdr_u_int(xdrs, &p->gr_win) && + xdr_bytes(xdrs, (char **)&p->gr_token.value, + (u_int *)&p->gr_token.length, MAX_NETOBJ_SZ)); + + log_debug("xdr_rpc_gss_init_res %s %s " + "(ctx %p:%d, maj %d, min %d, win %d, token %p:%d)", + (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", + (xdr_stat == TRUE) ? "success" : "failure", + p->gr_ctx.value, p->gr_ctx.length, + p->gr_major, p->gr_minor, p->gr_win, + p->gr_token.value, p->gr_token.length); + + return (xdr_stat); +} + +bool_t +xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + PCtxtHandle ctx, sspi_qop_t qop, + rpc_sspi_svc_t svc, u_int seq) +{ + sspi_buffer_desc databuf, wrapbuf; + uint32_t maj_stat; + int start, end, conf_state; + bool_t xdr_stat; + + log_debug("in xdr_rpc_sspi_wrap_data()"); + + /* Skip databody length. */ + start = XDR_GETPOS(xdrs); + //XDR_SETPOS(xdrs, start + 4); + + /* Marshal rpc_gss_data_t (sequence number + arguments). */ + if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr)) + return (FALSE); + end = XDR_GETPOS(xdrs); + + /* Set databuf to marshalled rpc_gss_data_t. */ + databuf.length = end - start - 4; + //XDR_SETPOS(xdrs, start + 4); + //databuf.value = XDR_INLINE(xdrs, databuf.length); + databuf.value = xdrrec_getoutbase(xdrs) + 1; + + xdr_stat = FALSE; + + if (svc == RPCSEC_SSPI_SVC_INTEGRITY) { + /* Marshal databody_integ length. */ + //XDR_SETPOS(xdrs, start); + if (!xdr_u_int(xdrs, (u_int *)&databuf.length)) + return (FALSE); + + /* Checksum rpc_gss_data_t. */ +#if 0 + maj_stat = gss_get_mic(&min_stat, ctx, qop, + &databuf, &wrapbuf); +#else + maj_stat = sspi_get_mic(ctx, 0, seq, &databuf, &wrapbuf); +#endif + if (maj_stat != SEC_E_OK) { + log_debug("xdr_rpc_sspi_wrap_data: sspi_get_mic failed with %x", maj_stat); + return (FALSE); + } + /* Marshal checksum. */ + //XDR_SETPOS(xdrs, end); + xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value, + (u_int *)&wrapbuf.length, MAX_NETOBJ_SZ); +#if 0 + gss_release_buffer(&min_stat, &wrapbuf); +#else + sspi_release_buffer(&wrapbuf); +#endif + } + else if (svc == RPCSEC_SSPI_SVC_PRIVACY) { + /* Encrypt rpc_gss_data_t. */ +#if 0 + maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, + &conf_state, &wrapbuf); +#endif + if (maj_stat != SEC_E_OK) { + log_debug("xdr_rpc_sspi_wrap_data: sspi_wrap failed with %x", maj_stat); + return (FALSE); + } + /* Marshal databody_priv. */ + XDR_SETPOS(xdrs, start); + xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value, + (u_int *)&wrapbuf.length, MAX_NETOBJ_SZ); +#if 0 + gss_release_buffer(&min_stat, &wrapbuf); +#else + sspi_release_buffer(&wrapbuf); +#endif + } + return (xdr_stat); +} + +bool_t +xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + PCtxtHandle ctx, sspi_qop_t qop, + rpc_sspi_svc_t svc, u_int seq) +{ + XDR tmpxdrs; + sspi_buffer_desc databuf, wrapbuf; + uint32_t maj_stat; + u_int seq_num, qop_state; + int conf_state; + bool_t xdr_stat; + + log_debug("in xdr_rpc_sspi_unwrap_data()"); + + if (xdr_func == (xdrproc_t)xdr_void || xdr_ptr == NULL) + return (TRUE); + + memset(&databuf, 0, sizeof(databuf)); + memset(&wrapbuf, 0, sizeof(wrapbuf)); + + if (svc == RPCSEC_SSPI_SVC_INTEGRITY) { + /* Decode databody_integ. */ + if (!xdr_bytes(xdrs, (char **)&databuf.value, (u_int *)&databuf.length, + MAX_NETOBJ_SZ)) { + log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_integ failed"); + return (FALSE); + } + /* Decode checksum. */ + if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length, + MAX_NETOBJ_SZ)) { +#if 0 + gss_release_buffer(&min_stat, &databuf); +#else + sspi_release_buffer(&databuf); +#endif + log_debug("xdr_rpc_sspi_unwrap_data: xdr decode checksum failed"); + return (FALSE); + } + /* Verify checksum and QOP. */ +#if 0 + maj_stat = gss_verify_mic(&min_stat, ctx, &databuf, + &wrapbuf, &qop_state); +#else + maj_stat = sspi_verify_mic(ctx, seq, &databuf, &wrapbuf, &qop_state); +#endif +#if 0 + gss_release_buffer(&min_stat, &wrapbuf); +#else + sspi_release_buffer(&wrapbuf); +#endif + + if (maj_stat != SEC_E_OK || qop_state != qop) { +#if 0 + gss_release_buffer(&min_stat, &databuf); +#else + sspi_release_buffer(&databuf); +#endif + log_debug("xdr_rpc_sspi_unwrap_data: sspi_verify_mic " + "failed with %x", maj_stat); + return (FALSE); + } + } + else if (svc == RPCSEC_SSPI_SVC_PRIVACY) { + /* Decode databody_priv. */ + if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length, + MAX_NETOBJ_SZ)) { + log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_priv failed"); + return (FALSE); + } + /* Decrypt databody. */ +#if 0 + maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf, + &conf_state, &qop_state); +#endif +#if 0 + gss_release_buffer(&min_stat, &wrapbuf); +#else + sspi_release_buffer(&wrapbuf); +#endif + /* Verify encryption and QOP. */ + if (maj_stat != SEC_E_OK || qop_state != qop || + conf_state != TRUE) { +#if 0 + gss_release_buffer(&min_stat, &databuf); +#else + sspi_release_buffer(&databuf); +#endif + log_debug("xdr_rpc_sspi_unwrap_data: sspi_unwrap failed with %x", maj_stat); + return (FALSE); + } + } + /* Decode rpc_gss_data_t (sequence number + arguments). */ + xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE); + xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) && + (*xdr_func)(&tmpxdrs, xdr_ptr)); + XDR_DESTROY(&tmpxdrs); +#if 0 + gss_release_buffer(&min_stat, &databuf); +#else + sspi_release_buffer(&databuf); +#endif + /* Verify sequence number. */ + if (xdr_stat == TRUE && seq_num != seq) { + log_debug("wrong sequence number in databody"); + return (FALSE); + } + + return (xdr_stat); +} + +bool_t +xdr_rpc_sspi_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + PCtxtHandle ctx, sspi_qop_t qop, + rpc_sspi_svc_t svc, u_int seq) +{ + switch (xdrs->x_op) { + + case XDR_ENCODE: + return (xdr_rpc_sspi_wrap_data(xdrs, xdr_func, xdr_ptr, + ctx, qop, svc, seq)); + case XDR_DECODE: + return (xdr_rpc_sspi_unwrap_data(xdrs, xdr_func, xdr_ptr, + ctx, qop, svc, seq)); + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} diff --git a/libtirpc/src/clnt_dg.c b/libtirpc/src/clnt_dg.c index 145b5e1..a567b22 100644 --- a/libtirpc/src/clnt_dg.c +++ b/libtirpc/src/clnt_dg.c @@ -395,7 +395,7 @@ call_again: *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid); if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || - (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs, NULL)) || (! (*xargs)(xdrs, argsp))) { cu->cu_error.re_status = RPC_CANTENCODEARGS; goto out; @@ -541,7 +541,7 @@ get_reply: if (cu->cu_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(cl->cl_auth, - &reply_msg.acpted_rply.ar_verf)) { + &reply_msg.acpted_rply.ar_verf, 0)) { cu->cu_error.re_status = RPC_AUTHERROR; cu->cu_error.re_why = AUTH_INVALIDRESP; } diff --git a/libtirpc/src/clnt_raw.c b/libtirpc/src/clnt_raw.c index 6c433bc..3953324 100644 --- a/libtirpc/src/clnt_raw.c +++ b/libtirpc/src/clnt_raw.c @@ -166,7 +166,7 @@ call_again: clp->u.mashl_rpcmsg.rm_xid ++ ; if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) || (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || - (! AUTH_MARSHALL(h->cl_auth, xdrs)) || + (! AUTH_MARSHALL(h->cl_auth, xdrs, NULL)) || (! (*xargs)(xdrs, argsp))) { return (RPC_CANTENCODEARGS); } @@ -207,7 +207,7 @@ call_again: status = error.re_status; if (status == RPC_SUCCESS) { - if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf, 0)) { status = RPC_AUTHERROR; } } /* end successful completion */ @@ -217,7 +217,7 @@ call_again: } /* end of unsuccessful completion */ if (status == RPC_SUCCESS) { - if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf, 0)) { status = RPC_AUTHERROR; } if (msg.acpted_rply.ar_verf.oa_base != NULL) { diff --git a/libtirpc/src/clnt_vc.c b/libtirpc/src/clnt_vc.c index aea6992..d0c0ea6 100644 --- a/libtirpc/src/clnt_vc.c +++ b/libtirpc/src/clnt_vc.c @@ -488,6 +488,7 @@ clnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ bool_t shipnow; int refreshes = 2; + u_int seq = -1; #ifndef _WIN32 sigset_t mask, newmask; #else @@ -520,7 +521,7 @@ call_again: if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || - (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs, &seq)) || (! (*xdr_args)(xdrs, args_ptr))) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTENCODEARGS; @@ -607,7 +608,7 @@ call_again: _seterr_reply(&ct->reply_msg, &(ct->ct_error)); if (ct->ct_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(cl->cl_auth, - &ct->reply_msg.acpted_rply.ar_verf)) { + &ct->reply_msg.acpted_rply.ar_verf, seq)) { ct->ct_error.re_status = RPC_AUTHERROR; ct->ct_error.re_why = AUTH_INVALIDRESP; } else if (! (*xdr_results)(xdrs, results_ptr)) { diff --git a/libtirpc/src/sources b/libtirpc/src/sources index 0167b9b..80a6ae2 100644 --- a/libtirpc/src/sources +++ b/libtirpc/src/sources @@ -5,6 +5,8 @@ SOURCES=\ auth_none.c \ auth_time.c \ auth_unix.c \ + auth_sspi.c \ + authsspi_prot.c \ authunix_prot.c \ bindresvport.c \ clnt_bcast.c \ @@ -69,13 +71,12 @@ SOURCES=\ # crypt_client.c \ # des_crypt.c \ # svc_auth_sspi.c \ -# auth_sspi.c \ # auth_des.c \ # authdes_prot.c \ # authgss_prot.c \ UMTYPE=console -UNICODE=1 +#UNICODE=1 DLLBASE=0x1010000 #USE_NTDLL=1 #USE_MSVCRT=1 diff --git a/libtirpc/src/xdr_rec.c b/libtirpc/src/xdr_rec.c index 8e97ac6..9e2dee8 100644 --- a/libtirpc/src/xdr_rec.c +++ b/libtirpc/src/xdr_rec.c @@ -330,10 +330,10 @@ xdrrec_getpos(xdrs) XDR *xdrs; { RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; - off_t pos; + off_t pos = 0; //pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1); - pos = _lseek((int)PtrToUlong(rstrm->tcp_handle), (off_t)0, 1); + //pos = _lseek((int)PtrToUlong(rstrm->tcp_handle), (off_t)0, 1); if (pos != -1) switch (xdrs->x_op) { @@ -391,6 +391,28 @@ xdrrec_setpos(xdrs, pos) return (FALSE); } +int32_t * +xdrrec_getoutbase(xdrs) + XDR *xdrs; +{ + RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + int32_t *buf = NULL; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + buf = rstrm->out_base; + break; + + case XDR_DECODE: + break; + + case XDR_FREE: + break; + } + return (buf); +} + static int32_t * xdrrec_inline(xdrs, len) XDR *xdrs; diff --git a/libtirpc/tirpc/rpc/auth.h b/libtirpc/tirpc/rpc/auth.h index 5446af1..82e0e33 100644 --- a/libtirpc/tirpc/rpc/auth.h +++ b/libtirpc/tirpc/rpc/auth.h @@ -188,10 +188,9 @@ typedef struct __auth { struct auth_ops { void (*ah_nextverf) (struct __auth *); /* nextverf & serialize */ - int (*ah_marshal) (struct __auth *, XDR *); + int (*ah_marshal) (struct __auth *, XDR *, u_int *); /* validate verifier */ - int (*ah_validate) (struct __auth *, - struct opaque_auth *); + int (*ah_validate) (struct __auth *, struct opaque_auth *, u_int); /* refresh credentials */ int (*ah_refresh) (struct __auth *, void *); /* destroy this structure */ @@ -219,15 +218,15 @@ typedef struct __auth { #define auth_nextverf(auth) \ ((*((auth)->ah_ops->ah_nextverf))(auth)) -#define AUTH_MARSHALL(auth, xdrs) \ - ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) -#define auth_marshall(auth, xdrs) \ +#define AUTH_MARSHALL(auth, xdrs, seq) \ + ((*((auth)->ah_ops->ah_marshal))(auth, xdrs, seq)) +#define auth_marshall(auth, xdrs, seq) \ ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) -#define AUTH_VALIDATE(auth, verfp) \ - ((*((auth)->ah_ops->ah_validate))((auth), verfp)) -#define auth_validate(auth, verfp) \ - ((*((auth)->ah_ops->ah_validate))((auth), verfp)) +#define AUTH_VALIDATE(auth, verfp, seq) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp, seq)) +#define auth_validate(auth, verfp, seq) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp, seq)) #define AUTH_REFRESH(auth, msg) \ ((*((auth)->ah_ops->ah_refresh))(auth, msg)) diff --git a/libtirpc/tirpc/rpc/auth_sspi.h b/libtirpc/tirpc/rpc/auth_sspi.h new file mode 100644 index 0000000..5ebe4d8 --- /dev/null +++ b/libtirpc/tirpc/rpc/auth_sspi.h @@ -0,0 +1,117 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef _TIRPC_AUTH_GSS_H +#define _TIRPC_AUTH_GSS_H + +#include +#define SECURITY_WIN32 +#include + +/* RPCSEC_SSPI control procedures. */ +typedef enum { + RPCSEC_SSPI_DATA = 0, + RPCSEC_SSPI_INIT = 1, + RPCSEC_SSPI_CONTINUE_INIT = 2, + RPCSEC_SSPI_DESTROY = 3 +} rpc_sspi_proc_t; + +/* RPCSEC_SSPI services. */ +typedef enum { + RPCSEC_SSPI_SVC_NONE = 1, + RPCSEC_SSPI_SVC_INTEGRITY = 2, + RPCSEC_SSPI_SVC_PRIVACY = 3 +} rpc_sspi_svc_t; + +#define RPCSEC_SSPI_VERSION 1 + +#define sspi_name_t SEC_CHAR * +#define sspi_qop_t uint32_t + +typedef struct _sspi_OID_desc { + int length; + void *elements; +} sspi_OID_desc, *sspi_OID; + +typedef struct _sspi_buffer_desc { + int length; + void *value; +} sspi_buffer_desc, *sspi_buffer_t; + +#define SSPI_C_NO_NAME ((sspi_name_t) NULL) +#define SSPI_C_NO_BUFFER ((sspi_buffer_t) NULL) +#define SSPI_C_NO_CONTEXT ((PCtxtHandle) NULL) + +/* RPCSEC_SSPI security triple. */ +struct rpc_sspi_sec { + sspi_OID mech; /* mechanism */ + uint32_t qop; /* quality of protection */ + rpc_sspi_svc_t svc; /* service */ + CredHandle cred; /* cred handle */ + u_int req_flags; /* req flags for init_sec_context */ + TimeStamp expiry; +}; + +/* Credentials. */ +struct rpc_sspi_cred { + u_int gc_v; /* version */ + rpc_sspi_proc_t gc_proc; /* control procedure */ + u_int gc_seq; /* sequence number */ + rpc_sspi_svc_t gc_svc; /* service */ + sspi_buffer_desc gc_ctx; /* server's returned context handle */ +}; + +/* Context creation response. */ +struct rpc_sspi_init_res { + sspi_buffer_desc gr_ctx; /* context handle */ + u_int gr_major; /* major status */ + u_int gr_minor; /* minor status */ + u_int gr_win; /* sequence window */ + sspi_buffer_desc gr_token; /* token */ +}; + +/* Prototypes. */ +__BEGIN_DECLS +bool_t xdr_rpc_sspi_cred(XDR *xdrs, struct rpc_sspi_cred *p); +bool_t xdr_rpc_sspi_init_args(XDR *xdrs, sspi_buffer_desc *p); +bool_t xdr_rpc_sspi_init_res(XDR *xdrs, struct rpc_sspi_init_res *p); +bool_t xdr_rpc_sspi_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + PCtxtHandle ctx, sspi_qop_t qop, + rpc_sspi_svc_t svc, u_int seq); +AUTH *authsspi_create(CLIENT *, sspi_name_t, struct rpc_sspi_sec *); +AUTH *authsspi_create_default(CLIENT *, char *, int); +bool_t authsspi_service(AUTH *auth, int svc); +uint32_t sspi_get_mic(void *ctx, u_int qop, u_int seq, + sspi_buffer_desc *bufin, sspi_buffer_desc *bufout); +uint32_t sspi_verify_mic(void *ctx, u_int seq, sspi_buffer_desc *bufin, + sspi_buffer_desc *bufout, u_int *qop_state); +void sspi_release_buffer(sspi_buffer_desc *buf); +uint32_t sspi_import_name(sspi_buffer_desc *name_in, sspi_name_t *name_out); + +void log_debug(const char *fmt, ...); +void log_status(char *m, uint32_t major, uint32_t minor); +void log_hexdump(bool_t on, const u_char *title, const u_char *buf, int len, int offset); + +__END_DECLS + +#endif /* !_TIRPC_AUTH_GSS_H */ diff --git a/libtirpc/tirpc/rpc/xdr.h b/libtirpc/tirpc/rpc/xdr.h index 9c3e5e1..42bfb57 100644 --- a/libtirpc/tirpc/rpc/xdr.h +++ b/libtirpc/tirpc/rpc/xdr.h @@ -354,6 +354,7 @@ extern void xdrrec_create(XDR *, u_int, u_int, void *, /* make end of xdr record */ extern bool_t xdrrec_endofrecord(XDR *, int); +extern int32_t *xdrrec_getoutbase(XDR *); /* move to beginning of next record */ extern bool_t xdrrec_skiprecord(XDR *); diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index 3882c8d..627a01f 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -2704,7 +2704,7 @@ NTSTATUS nfs41_Create( status = map_open_errors(entry->status, SrvOpen->pAlreadyPrefixedName->Length); if (status != STATUS_SUCCESS) { - print_open_error(1, entry->status); + print_open_error(1, status); goto out_free; }