예제 #1
0
static void
svcudp_destroy(register SVCXPRT *xprt)
{
    register struct svcudp_data *su = su_data(xprt);

    xprt_unregister(xprt);
    if (xprt->xp_sock != INVALID_SOCKET)
        (void)closesocket(xprt->xp_sock);
    xprt->xp_sock = INVALID_SOCKET;
    if (xprt->xp_auth != NULL) {
        SVCAUTH_DESTROY(xprt->xp_auth);
        xprt->xp_auth = NULL;
    }
    XDR_DESTROY(&(su->su_xdrs));
    mem_free(rpc_buffer(xprt), su->su_iosz);
    mem_free((caddr_t)su, sizeof(struct svcudp_data));
    mem_free((caddr_t)xprt, sizeof(SVCXPRT));
}
예제 #2
0
enum auth_stat
_svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch)
{
	XDR	 		 xdrs;
	SVCAUTH			*auth;
	struct svc_rpc_gss_data	*gd;
	struct rpc_gss_cred	*gc;
	struct rpc_gss_init_res	 gr;
	int			 call_stat, offset;

	log_debug("in svcauth_gss()");

	/* Initialize reply. */
	rqst->rq_xprt->xp_verf = _null_auth;

	/* Allocate and set up server auth handle. */
	if (rqst->rq_xprt->xp_auth == NULL ||
	    rqst->rq_xprt->xp_auth == &svc_auth_none) {
		if ((auth = calloc(sizeof(*auth), 1)) == NULL) {
			fprintf(stderr, "svcauth_gss: out_of_memory\n");
			return (AUTH_FAILED);
		}
		if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
			fprintf(stderr, "svcauth_gss: out_of_memory\n");
			return (AUTH_FAILED);
		}
		auth->svc_ah_ops = &svc_auth_gss_ops;
		auth->svc_ah_private = (caddr_t) gd;
		rqst->rq_xprt->xp_auth = auth;
	}
	else gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);

	/* Deserialize client credentials. */
	if (rqst->rq_cred.oa_length <= 0)
		return (AUTH_BADCRED);

	gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
	memset(gc, 0, sizeof(*gc));

	xdrmem_create(&xdrs, rqst->rq_cred.oa_base,
		      rqst->rq_cred.oa_length, XDR_DECODE);

	if (!xdr_rpc_gss_cred(&xdrs, gc)) {
		XDR_DESTROY(&xdrs);
		return (AUTH_BADCRED);
	}
	XDR_DESTROY(&xdrs);

	/* Check version. */
	if (gc->gc_v != RPCSEC_GSS_VERSION)
		return (AUTH_BADCRED);

	/* Check RPCSEC_GSS service. */
	if (gc->gc_svc != RPCSEC_GSS_SVC_NONE &&
	    gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY &&
	    gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY)
		return (AUTH_BADCRED);

	/* Check sequence number. */
	if (gd->established) {
		if (gc->gc_seq > MAXSEQ)
			return (RPCSEC_GSS_CTXPROBLEM);

		if ((offset = gd->seqlast - gc->gc_seq) < 0) {
			gd->seqlast = gc->gc_seq;
			offset = 0 - offset;
			gd->seqmask <<= offset;
			offset = 0;
		}
		else if (offset >= gd->win || (gd->seqmask & (1 << offset))) {
			*no_dispatch = 1;
			return (RPCSEC_GSS_CTXPROBLEM);
		}
		gd->seq = gc->gc_seq;
		gd->seqmask |= (1 << offset);
	}

	if (gd->established) {
		rqst->rq_clntname = (char *)gd->client_name;
		rqst->rq_svcname = (char *)gd->ctx;
	}

	/* Handle RPCSEC_GSS control procedure. */
	switch (gc->gc_proc) {

	case RPCSEC_GSS_INIT:
	case RPCSEC_GSS_CONTINUE_INIT:
		if (rqst->rq_proc != NULLPROC)
			return (AUTH_FAILED);		/* XXX ? */

		if (_svcauth_gss_name == NULL) {
			if (!svcauth_gss_import_name("nfs"))
				return (AUTH_FAILED);
		}

		if (!svcauth_gss_acquire_cred())
			return (AUTH_FAILED);

		if (!svcauth_gss_accept_sec_context(rqst, &gr))
			return (AUTH_REJECTEDCRED);

		if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win)))
			return (AUTH_FAILED);

		*no_dispatch = TRUE;

		call_stat = svc_sendreply(rqst->rq_xprt, 
			(xdrproc_t)xdr_rpc_gss_init_res, (caddr_t)&gr);

		if (!call_stat)
			return (AUTH_FAILED);

		if (gr.gr_major == GSS_S_COMPLETE)
			gd->established = TRUE;

		break;

	case RPCSEC_GSS_DATA:
		if (!svcauth_gss_validate(gd, msg))
			return (RPCSEC_GSS_CREDPROBLEM);

		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
			return (AUTH_FAILED);
		break;

	case RPCSEC_GSS_DESTROY:
		if (rqst->rq_proc != NULLPROC)
			return (AUTH_FAILED);		/* XXX ? */

		if (!svcauth_gss_validate(gd, msg))
			return (RPCSEC_GSS_CREDPROBLEM);

		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
			return (AUTH_FAILED);

		if (!svcauth_gss_release_cred())
			return (AUTH_FAILED);

		SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth);
		rqst->rq_xprt->xp_auth = &svc_auth_none;

		break;

	default:
		return (AUTH_REJECTEDCRED);
		break;
	}
	return (AUTH_OK);
}
예제 #3
0
enum auth_stat
gssrpc__svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg,
	bool_t *no_dispatch)
{
	enum auth_stat		 retstat;
	XDR	 		 xdrs;
	SVCAUTH			*auth;
	struct svc_rpc_gss_data	*gd;
	struct rpc_gss_cred	*gc;
	struct rpc_gss_init_res	 gr;
	int			 call_stat, offset;
	OM_uint32		 min_stat;

	log_debug("in svcauth_gss()");

	/* Initialize reply. */
	rqst->rq_xprt->xp_verf = gssrpc__null_auth;

	/* Allocate and set up server auth handle. */
	if (rqst->rq_xprt->xp_auth == NULL ||
	    rqst->rq_xprt->xp_auth == &svc_auth_none) {
		if ((auth = calloc(sizeof(*auth), 1)) == NULL) {
			fprintf(stderr, "svcauth_gss: out_of_memory\n");
			return (AUTH_FAILED);
		}
		if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
			fprintf(stderr, "svcauth_gss: out_of_memory\n");
			return (AUTH_FAILED);
		}
		auth->svc_ah_ops = &svc_auth_gss_ops;
		SVCAUTH_PRIVATE(auth) = gd;
		rqst->rq_xprt->xp_auth = auth;
	}
	else gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);

	log_debug("xp_auth=%p, gd=%p", rqst->rq_xprt->xp_auth, gd);

	/* Deserialize client credentials. */
	if (rqst->rq_cred.oa_length <= 0)
		return (AUTH_BADCRED);

	gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
	memset(gc, 0, sizeof(*gc));

	log_debug("calling xdrmem_create()");
	log_debug("oa_base=%p, oa_length=%u", rqst->rq_cred.oa_base,
		  rqst->rq_cred.oa_length);
	xdrmem_create(&xdrs, rqst->rq_cred.oa_base,
		      rqst->rq_cred.oa_length, XDR_DECODE);
	log_debug("xdrmem_create() returned");

	if (!xdr_rpc_gss_cred(&xdrs, gc)) {
		log_debug("xdr_rpc_gss_cred() failed");
		XDR_DESTROY(&xdrs);
		return (AUTH_BADCRED);
	}
	XDR_DESTROY(&xdrs);

	retstat = AUTH_FAILED;

#define ret_freegc(code) do { retstat = code; goto freegc; } while (0)

	/* Check version. */
	if (gc->gc_v != RPCSEC_GSS_VERSION)
		ret_freegc (AUTH_BADCRED);

	/* Check RPCSEC_GSS service. */
	if (gc->gc_svc != RPCSEC_GSS_SVC_NONE &&
	    gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY &&
	    gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY)
		ret_freegc (AUTH_BADCRED);

	/* Check sequence number. */
	if (gd->established) {
		if (gc->gc_seq > MAXSEQ)
			ret_freegc (RPCSEC_GSS_CTXPROBLEM);

		if ((offset = gd->seqlast - gc->gc_seq) < 0) {
			gd->seqlast = gc->gc_seq;
			offset = 0 - offset;
			gd->seqmask <<= offset;
			offset = 0;
		} else if ((u_int)offset >= gd->win ||
			   (gd->seqmask & (1 << offset))) {
			*no_dispatch = 1;
			ret_freegc (RPCSEC_GSS_CTXPROBLEM);
		}
		gd->seq = gc->gc_seq;
		gd->seqmask |= (1 << offset);
	}

	if (gd->established) {
		rqst->rq_clntname = (char *)gd->client_name;
		rqst->rq_svccred = (char *)gd->ctx;
	}

	/* Handle RPCSEC_GSS control procedure. */
	switch (gc->gc_proc) {

	case RPCSEC_GSS_INIT:
	case RPCSEC_GSS_CONTINUE_INIT:
		if (rqst->rq_proc != NULLPROC)
			ret_freegc (AUTH_FAILED);		/* XXX ? */

		if (!svcauth_gss_acquire_cred())
			ret_freegc (AUTH_FAILED);

		if (!svcauth_gss_accept_sec_context(rqst, &gr))
			ret_freegc (AUTH_REJECTEDCRED);

		if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) {
			gss_release_buffer(&min_stat, &gr.gr_token);
			ret_freegc (AUTH_FAILED);
		}
		*no_dispatch = TRUE;

		call_stat = svc_sendreply(rqst->rq_xprt, xdr_rpc_gss_init_res,
					  (caddr_t)&gr);

		gss_release_buffer(&min_stat, &gr.gr_token);
		gss_release_buffer(&min_stat, &gd->checksum);
		if (!call_stat)
			ret_freegc (AUTH_FAILED);

		if (gr.gr_major == GSS_S_COMPLETE)
			gd->established = TRUE;

		break;

	case RPCSEC_GSS_DATA:
		if (!svcauth_gss_validate(rqst, gd, msg))
			ret_freegc (RPCSEC_GSS_CREDPROBLEM);

		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
 			ret_freegc (AUTH_FAILED);
		break;

	case RPCSEC_GSS_DESTROY:
		if (rqst->rq_proc != NULLPROC)
			ret_freegc (AUTH_FAILED);		/* XXX ? */

		if (!svcauth_gss_validate(rqst, gd, msg))
			ret_freegc (RPCSEC_GSS_CREDPROBLEM);

		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
			ret_freegc (AUTH_FAILED);

		*no_dispatch = TRUE;

		call_stat = svc_sendreply(rqst->rq_xprt,
					  xdr_void, (caddr_t)NULL);

		log_debug("sendreply in destroy: %d", call_stat);

		if (!svcauth_gss_release_cred())
			ret_freegc (AUTH_FAILED);

		SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth);
		rqst->rq_xprt->xp_auth = &svc_auth_none;

		break;

	default:
		ret_freegc (AUTH_REJECTEDCRED);
		break;
	}
	retstat = AUTH_OK;
freegc:
	xdr_free(xdr_rpc_gss_cred, gc);
	log_debug("returning %d from svcauth_gss()", retstat);
	return (retstat);
}
예제 #4
0
enum auth_stat
Gssrpc__svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t * no_dispatch)
{
  enum auth_stat retstat;
  XDR xdrs;
  SVCAUTH *auth;
  struct svc_rpc_gss_data *gd;
  struct rpc_gss_cred *gc;
  struct rpc_gss_init_res gr;
  int call_stat, offset;
  OM_uint32 min_stat;
  gss_union_ctx_id_desc *gss_ctx_data;
  char ctx_str[64];

  /* Used to update the hashtable entries. 
   * These should not be used for purposes other than updating
   * hashtable entries. */
  bool_t *p_established = NULL;
  u_int *p_seqlast = NULL;
  uint32_t *p_seqmask = NULL;

  /* Initialize reply. */
  LogFullDebug(COMPONENT_RPCSEC_GSS, "Gssrpc__svcauth_gss called");

  /* Allocate and set up server auth handle. */
  if(rqst->rq_xprt->xp_auth == NULL || rqst->rq_xprt->xp_auth == &Svc_auth_none)
    {
      if((auth = (SVCAUTH *)Mem_Calloc(1, sizeof(*auth))) == NULL)
        {
          LogCrit(COMPONENT_RPCSEC_GSS, "svcauth_gss: out_of_memory");
          return (AUTH_FAILED);
        }
      if((gd = (struct svc_rpc_gss_data *)Mem_Calloc(1, sizeof(*gd))) == NULL)
        {
          LogCrit(COMPONENT_RPCSEC_GSS, "svcauth_gss: out_of_memory");
          Mem_Free(auth);
          return (AUTH_FAILED);
        }
      auth->svc_ah_ops = &Svc_auth_gss_ops;
      auth->svc_ah_private = (void *)gd;
      rqst->rq_xprt->xp_auth = auth;
    }
  else
    gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);

  /* Deserialize client credentials. */
  if(rqst->rq_cred.oa_length <= 0)
    return (AUTH_BADCRED);

  gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
  memset(gc, 0, sizeof(*gc));

  xdrmem_create(&xdrs, rqst->rq_cred.oa_base, rqst->rq_cred.oa_length, XDR_DECODE);

  if(!xdr_rpc_gss_cred(&xdrs, gc))
    {
      XDR_DESTROY(&xdrs);
      return (AUTH_BADCRED);
    }
  XDR_DESTROY(&xdrs);

  if(gc->gc_ctx.length != 0)
    gss_ctx_data = (gss_union_ctx_id_desc *)(gc->gc_ctx.value);
  else
    gss_ctx_data = NULL;

  if(isFullDebug(COMPONENT_RPCSEC_GSS))
    {
      sprint_ctx(ctx_str, (char *)gc->gc_ctx.value, gc->gc_ctx.length);
      LogFullDebug(COMPONENT_RPCSEC_GSS,
                   "Gssrpc__svcauth_gss gc_proc (%u) %s context %s",
                   gc->gc_proc, str_gc_proc(gc->gc_proc), ctx_str);
    }

  /* If we do not retrieve gss data from the cache, then this important
   * variables could not possibly be meaningful. */
  gd->seqlast = 0;
  gd->seqmask = 0;
  gd->established = 0;

  /** @todo Think about restoring the correct lines */
  //if( gd->established == 0 && gc->gc_proc == RPCSEC_GSS_DATA   )
  if(gc->gc_proc == RPCSEC_GSS_DATA || gc->gc_proc == RPCSEC_GSS_DESTROY)
    {
      if(isFullDebug(COMPONENT_RPCSEC_GSS))
        {
          LogFullDebug(COMPONENT_RPCSEC_GSS,
                       "Dump context hash table");
          Gss_ctx_Hash_Print();
        }
      
      LogFullDebug(COMPONENT_RPCSEC_GSS, "Getting gss data struct from hashtable.");
      
      /* Fill in svc_rpc_gss_data from cache */
      if(!Gss_ctx_Hash_Get(gss_ctx_data,
			   gd,
			   &p_established,
			   &p_seqlast,
			   &p_seqmask))
	{
          LogCrit(COMPONENT_RPCSEC_GSS, "Could not find gss context ");
          ret_freegc(AUTH_REJECTEDCRED);
        }
      else
        {
          /* If you 'mount -o sec=krb5i' you will have gc->gc_proc > RPCSEC_GSS_SVN_NONE, but the
           * negociation will have been made as if option was -o sec=krb5, the value of sec.svc has to be updated
           * id the stored gd that we got fromn the hash */
          if(gc->gc_svc != gd->sec.svc)
            gd->sec.svc = gc->gc_svc;
        }
    }

  if(isFullDebug(COMPONENT_RPCSEC_GSS))
    {
      char ctx_str_2[64];

      sprint_ctx(ctx_str_2, (unsigned char *)gd->ctx, sizeof(gss_ctx_data));
      sprint_ctx(ctx_str, (unsigned char *)gc->gc_ctx.value, gc->gc_ctx.length);

      LogFullDebug(COMPONENT_RPCSEC_GSS,
                   "Call to Gssrpc__svcauth_gss ----> Client=%s length=%lu (GD: established=%u ctx=%s) (RQ:sock=%u) (GC: Proc=%u Svc=%u ctx=%s)",
                   (char *)gd->cname.value,
                   (long unsigned int)gd->cname.length,
                   gd->established,
                   ctx_str_2,
                   rqst->rq_xprt->XP_SOCK,
                   gc->gc_proc,
                   gc->gc_svc,
                   ctx_str);
    }

  retstat = AUTH_FAILED;

  /* Check version. */
  if(gc->gc_v != RPCSEC_GSS_VERSION)
    {
      LogDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: bad GSS version.");
      ret_freegc(AUTH_BADCRED);
    }

  /* Check RPCSEC_GSS service. */
  if(gc->gc_svc != RPCSEC_GSS_SVC_NONE &&
     gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY && gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY)
    {
      LogDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: bad GSS service (krb5, krb5i, krb5p)");
      ret_freegc(AUTH_BADCRED);
    }

  /* Check sequence number. */
  if(gd->established)
    {
      /* Sequence should be less than the max sequence number */
      if(gc->gc_seq > MAXSEQ)
	{
	  LogDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: max sequence number exceeded.");
	  ret_freegc(RPCSEC_GSS_CTXPROBLEM);
	}

      /* Check the difference between the current sequence number 
       * and the last sequence number. */
      LogFullDebug(COMPONENT_RPCSEC_GSS, "seqlast: %d  seqnum: %d offset: %d seqwin: %d seqmask: %x",
		   gd->seqlast, gc->gc_seq, gd->seqlast - gc->gc_seq, gd->win, gd->seqmask);

      if((offset = gd->seqlast - gc->gc_seq) < 0)
        {
          gd->seqlast = gc->gc_seq;
          offset = 0 - offset;
          gd->seqmask <<= offset;
          offset = 0;
        }
      else if((unsigned int)offset >= gd->win
              || (gd->seqmask & (1 << (unsigned int)offset)))
        {
	  if ((unsigned int)offset >= gd->win)
	    LogDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: the current seqnum is lower"
		     " than seqlast by %d and out of the seq window of size %d.", offset, gd->win);
	  else
	    LogDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: the current seqnum has already been used.");

          *no_dispatch = TRUE;
          ret_freegc(RPCSEC_GSS_CTXPROBLEM);
        }
      gd->seq = gc->gc_seq;
      gd->seqmask |= (1 << offset);
    }

  if(gd->established)
    {
      rqst->rq_clntname = (char *)gd->client_name;
#ifndef _USE_TIRPC
      rqst->rq_svccred = (char *)gd->ctx;
#else
      rqst->rq_svcname = (char *)gd->ctx;
#endif
    }

  /* Handle RPCSEC_GSS control procedure. */
  switch (gc->gc_proc)
    {

    case RPCSEC_GSS_INIT:
      LogFullDebug(COMPONENT_RPCSEC_GSS, "Reached RPCSEC_GSS_INIT:");
    case RPCSEC_GSS_CONTINUE_INIT:
      LogFullDebug(COMPONENT_RPCSEC_GSS, "Reached RPCSEC_GSS_CONTINUE_INIT:");
      if(rqst->rq_proc != NULLPROC)
	{
	  LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: request proc != NULL during INIT request");
	  ret_freegc(AUTH_FAILED);        /* XXX ? */
	}

      if(!Svcauth_gss_acquire_cred())
	{
	  LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Can't acquire credentials from RPC request.");
	  ret_freegc(AUTH_FAILED);
	}

      if(!Svcauth_gss_accept_sec_context(rqst, &gr))
	{
	  LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Can't accept the security context.");
	  ret_freegc(AUTH_REJECTEDCRED);
	}

      if(!Svcauth_gss_nextverf(rqst, htonl(gr.gr_win)))
        {
          gss_release_buffer(&min_stat, &gr.gr_token);
          Mem_Free(gr.gr_ctx.value);
	  LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Checksum verification failed");
          ret_freegc(AUTH_FAILED);
        }
      *no_dispatch = TRUE;

      if(isFullDebug(COMPONENT_RPCSEC_GSS))
        {
          sprint_ctx(ctx_str, (unsigned char *)gr.gr_ctx.value, gr.gr_ctx.length);
          LogFullDebug(COMPONENT_RPCSEC_GSS,
                       "Call to Gssrpc__svcauth_gss ----> Client=%s length=%lu (GD: established=%u) (RQ:sock=%u) (GR: maj=%u min=%u ctx=%s)",
                       (char *)gd->cname.value,
                       (long unsigned int)gd->cname.length,
                       gd->established,
                       rqst->rq_xprt->XP_SOCK,
                       gr.gr_major,
                       gr.gr_minor,
                       ctx_str);
        }
      call_stat = svc_sendreply(rqst->rq_xprt, (xdrproc_t)xdr_rpc_gss_init_res, (caddr_t) & gr);

      gss_release_buffer(&min_stat, &gr.gr_token);
      gss_release_buffer(&min_stat, &gd->checksum);
      Mem_Free(gr.gr_ctx.value);

      if(!call_stat)
	{
	  LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: svc_sendreply failed.");
	  ret_freegc(AUTH_FAILED);
	}

      if(gr.gr_major == GSS_S_COMPLETE)
        {
          gss_union_ctx_id_desc *gss_ctx_data2 = (gss_union_ctx_id_desc *)gd->ctx;

          gd->established = TRUE;

          /* Keep the gss context in a hash, gr.gr_ctx.value is used as key */
          (void) Gss_ctx_Hash_Set(gss_ctx_data2, gd);
        }

      break;

    case RPCSEC_GSS_DATA:
      LogFullDebug(COMPONENT_RPCSEC_GSS, "Reached RPCSEC_GSS_DATA:");
      if(!Svcauth_gss_validate(rqst, gd, msg))
	{
	  LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Couldn't validate request.");
	  ret_freegc(RPCSEC_GSS_CREDPROBLEM);
	}

      if(!Svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
	{
	  LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Checksum verification failed.");
	  ret_freegc(AUTH_FAILED);
	}

      /* Update a few important values in the hashtable entry */
      if ( p_established != NULL)
	*p_established = gd->established;
      if ( p_seqlast != NULL)
	*p_seqlast = gd->seqlast;
      if (p_seqmask != NULL)
	*p_seqmask = gd->seqmask;

      break;

    case RPCSEC_GSS_DESTROY:
      LogFullDebug(COMPONENT_RPCSEC_GSS, "Reached RPCSEC_GSS_DESTROY:");
      if(rqst->rq_proc != NULLPROC)
        ret_freegc(AUTH_FAILED);        /* XXX ? */

      if(!Svcauth_gss_validate(rqst, gd, msg))
        ret_freegc(RPCSEC_GSS_CREDPROBLEM);

      if(!Svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
	{
	  LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Checksum verification failed.");
	  ret_freegc(AUTH_FAILED);
	}

      *no_dispatch = TRUE;

      call_stat = svc_sendreply(rqst->rq_xprt, (xdrproc_t)xdr_void, (caddr_t) NULL);

      if(!Gss_ctx_Hash_Del(gss_ctx_data))
        {
          LogCrit(COMPONENT_RPCSEC_GSS,
                  "Could not delete Gss Context from hash");
        }
      else
        LogFullDebug(COMPONENT_RPCSEC_GSS, "Gss_ctx_Hash_Del OK");

      if(!Svcauth_gss_release_cred())
	{
	  LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Failed to release credentials.");
	  ret_freegc(AUTH_FAILED);
	}

      if(rqst->rq_xprt->xp_auth)
        SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth);
      rqst->rq_xprt->xp_auth = &Svc_auth_none;

      break;

    default:
      LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Request is not INIT, INIT_CONTINUE, DATA, OR DESTROY.");
      ret_freegc(AUTH_REJECTEDCRED);
      break;
    }

  LogFullDebug(COMPONENT_RPCSEC_GSS,
               "Call to Gssrpc__svcauth_gss - OK ---> (RQ:sock=%u)",
               rqst->rq_xprt->XP_SOCK);

  retstat = AUTH_OK;
 freegc:
  if(retstat != AUTH_OK)
    LogCrit(COMPONENT_RPCSEC_GSS,
            "Call to Gssrpc__svcauth_gss - FAILED ---> (RQ:sock=%u)",
            rqst->rq_xprt->XP_SOCK);

  xdr_free((xdrproc_t)xdr_rpc_gss_cred, gc);
  return (retstat);
}