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;
}