Пример #1
0
OM_uint32 GSSAPI_CALLCONV _gss_spnego_process_context_token
           (OM_uint32 *minor_status,
            gss_const_ctx_id_t context_handle,
            const gss_buffer_t token_buffer
           )
{
    gss_ctx_id_t context;
    gssspnego_ctx ctx;
    OM_uint32 ret;

    if (context_handle == GSS_C_NO_CONTEXT)
	return GSS_S_NO_CONTEXT;

    context = (gss_ctx_id_t)context_handle;
    ctx = (gssspnego_ctx)context_handle;

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    ret = gss_process_context_token(minor_status,
				    ctx->negotiated_ctx_id,
				    token_buffer);
    if (ret != GSS_S_COMPLETE) {
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	return ret;
    }

    ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;

    return _gss_spnego_internal_delete_sec_context(minor_status,
					   &context,
					   GSS_C_NO_BUFFER);
}
Пример #2
0
OM_uint32 gssi_process_context_token(OM_uint32 *minor_status,
                                     gss_ctx_id_t context_handle,
                                     gss_buffer_t token_buffer)
{
    struct gpp_context_handle *ctx;
    OM_uint32 maj, min;

    GSSI_TRACE();

    ctx = (struct gpp_context_handle *)context_handle;
    if (!ctx) {
        return GSS_S_CALL_INACCESSIBLE_READ;
    }

    /* for now we have support only for some specific known
     * mechanisms for which we can export/import the context */
    if (ctx->remote && !ctx->local) {
        maj = gpp_remote_to_local_ctx(&min, &ctx->remote, &ctx->local);
        if (maj != GSS_S_COMPLETE) {
            *minor_status = gpp_map_error(min);
            return maj;
        }
    }

    return gss_process_context_token(minor_status, ctx->local, token_buffer);
}
Пример #3
0
uint32_t
sapgss_process_context_token(
    uint32_t *minor_status,
    gss_ctx_id_t context_handle,
    gss_buffer_t token_buffer)
{
    return gss_process_context_token(minor_status, context_handle,
				     token_buffer);
}
Пример #4
0
OM_uint32
ntlm_gss_process_context_token(
				OM_uint32	*minor_status,
				const gss_ctx_id_t context_handle,
				const gss_buffer_t token_buffer)
{
	OM_uint32 ret;
	ret = gss_process_context_token(minor_status,
					context_handle,
					token_buffer);

	return (ret);
}
Пример #5
0
enum auth_stat gssrpc__svcauth_gssapi(
     register struct svc_req *rqst,
     register struct rpc_msg *msg,
     bool_t *no_dispatch)
{
     XDR xdrs;
     auth_gssapi_creds creds;
     auth_gssapi_init_arg call_arg;
     auth_gssapi_init_res call_res;
     gss_buffer_desc output_token, in_buf, out_buf;
     gss_cred_id_t server_creds;
     struct gss_channel_bindings_struct bindings, *bindp;
     OM_uint32 gssstat, minor_stat, time_rec;
     struct opaque_auth *cred, *verf;
     svc_auth_gssapi_data *client_data;
     int i;
     enum auth_stat ret;
     OM_uint32 ret_flags;
     uint32_t seq_num;

     PRINTF(("svcauth_gssapi: starting\n"));
     
     /* clean up expired entries */
     clean_client();

     /* use AUTH_NONE until there is a client_handle */
     rqst->rq_xprt->xp_auth = &svc_auth_none;
     
     memset((char *) &call_res, 0, sizeof(call_res));
     creds.client_handle.length = 0;
     creds.client_handle.value = NULL;
     
     cred = &msg->rm_call.cb_cred;
     verf = &msg->rm_call.cb_verf;
     
     if (cred->oa_length == 0) {
	  PRINTF(("svcauth_gssapi: empty creds, failing\n"));
	  LOG_MISCERR("empty client credentials");
	  ret = AUTH_BADCRED;
	  goto error;
     }

     PRINTF(("svcauth_gssapi: decoding credentials\n"));
     xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); 
     memset((char *) &creds, 0, sizeof(creds));
     if (! xdr_authgssapi_creds(&xdrs, &creds)) {
	  PRINTF(("svcauth_gssapi: failed decoding creds\n"));
	  LOG_MISCERR("protocol error in client credentials");
	  xdr_free(xdr_authgssapi_creds, &creds);
	  XDR_DESTROY(&xdrs);
	  ret = AUTH_BADCRED;
	  goto error;
     }
     XDR_DESTROY(&xdrs);

     PRINTF(("svcauth_gssapi: got credentials, version %d, client_handle len %d\n",
	     creds.version, (int) creds.client_handle.length));

     if (creds.version != 2) {
 	  PRINTF(("svcauth_gssapi: bad credential version\n"));
 	  LOG_MISCERR("unsupported client credentials version");
 	  ret = AUTH_BADCRED;
 	  goto error;
     }

#ifdef DEBUG_GSSAPI
     if (svc_debug_gssapi) {
	  if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_EXIT) {
	       PRINTF(("svcauth_gssapi: GSSAPI_EXIT, cleaning up\n"));
	       svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
	       xdr_free(xdr_authgssapi_creds, &creds);
	       cleanup();
	       exit(0);
	  }
     }
#endif
	  
     /*
      * If this is an auth_msg and proc is GSSAPI_INIT, then create a
      * client handle for this client.  Otherwise, look up the
      * existing handle.
      */
     if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_INIT) {
	  if (creds.client_handle.length != 0) {
	       PRINTF(("svcauth_gssapi: non-empty handle on GSSAPI_INIT\n"));
	       LOG_MISCERR("protocol error in client handle");
	       ret = AUTH_FAILED;
	       goto error;
	  }
	       
	  PRINTF(("svcauth_gssapi: GSSAPI_INIT, creating client.\n"));
	  
	  client_data = create_client();
	  if (client_data == NULL) {
	       PRINTF(("svcauth_gssapi: create_client failed\n"));
	       LOG_MISCERR("internal error creating client record");
	       ret = AUTH_FAILED;
	       goto error;
	  }
     } else {
	  if (creds.client_handle.length == 0) {
	       PRINTF(("svcauth_gssapi: expected non-empty creds\n"));
	       LOG_MISCERR("protocol error in client credentials");
	       ret = AUTH_FAILED;
	       goto error;
	  }
	  
	  PRINTF(("svcauth_gssapi: incoming client_handle %d, len %d\n", 
		  *((uint32_t *) creds.client_handle.value),
		  (int) creds.client_handle.length));

	  client_data = get_client(&creds.client_handle);
	  if (client_data == NULL) {
	       PRINTF(("svcauth_gssapi: client_handle lookup failed\n"));
	       LOG_MISCERR("invalid client handle received");
	       ret = AUTH_BADCRED;
	       goto error;
	  }
	  PRINTF(("svcauth_gssapi: client_handle lookup succeeded\n"));
     }

     /* any response we send will use client_handle, so set it now */
     call_res.client_handle.length = sizeof(client_data->key);
     call_res.client_handle.value = (char *) &client_data->key;
     
     /* mark this call as using AUTH_GSSAPI via client_data's SVCAUTH */
     rqst->rq_xprt->xp_auth = &client_data->svcauth;

     if (client_data->established == FALSE) {
	  PRINTF(("svcauth_gssapi: context is not established\n"));

	  if (creds.auth_msg == FALSE) {
	       PRINTF(("svcauth_gssapi: expected auth_msg TRUE\n"));
	       LOG_MISCERR("protocol error on incomplete connection");
	       ret = AUTH_REJECTEDCRED;
	       goto error;
	  }

	  /*
	   * If the context is not established, then only GSSAPI_INIT
	   * and _CONTINUE requests are valid.
	   */
	  if (rqst->rq_proc != AUTH_GSSAPI_INIT && rqst->rq_proc !=
	      AUTH_GSSAPI_CONTINUE_INIT) {
	       PRINTF(("svcauth_gssapi: unacceptable procedure %d\n",
		       rqst->rq_proc));
	       LOG_MISCERR("protocol error on incomplete connection");
	       ret = AUTH_FAILED;
	       goto error;
	  }

	  /* call is for us, deserialize arguments */
	  memset(&call_arg, 0, sizeof(call_arg));
	  if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg,
			    &call_arg)) {
	       PRINTF(("svcauth_gssapi: cannot decode args\n"));
	       LOG_MISCERR("protocol error in procedure arguments");
	       ret = AUTH_BADCRED;
	       goto error;
	  }

	  /*
	   * Process the call arg version number.
	   * 
	   * Set the krb5_gss backwards-compatibility mode based on client
	   * version.  This controls whether the AP_REP message is
	   * encrypted with the session key (version 2+, correct) or the
	   * session subkey (version 1, incorrect).  This function can
	   * never fail, so we don't bother checking its return value.
	   */
	  switch (call_arg.version) {
	  case 1:
	  case 2:
	       LOG_MISCERR("Warning: Accepted old RPC protocol request");
	       call_res.version = 1;
	       break;
	  case 3:
	  case 4:
	       /* 3 and 4 are essentially the same, don't bother warning */
	       call_res.version = call_arg.version;
	       break;
	  default:
	       PRINTF(("svcauth_gssapi: bad GSSAPI_INIT version\n"));
	       LOG_MISCERR("unsupported GSSAPI_INIT version");
	       ret = AUTH_BADCRED;
	       goto error;
	  }

#ifdef GSS_BACKWARD_HACK
	  krb5_gss_set_backward_mode(&minor_stat, call_arg.version == 1);
#endif

	  if (call_arg.version >= 3) {
	       memset(&bindings, 0, sizeof(bindings));
	       bindings.application_data.length = 0;
	       bindings.initiator_addrtype = GSS_C_AF_INET;
	       bindings.initiator_address.length = 4;
	       bindings.initiator_address.value =
		    &svc_getcaller(rqst->rq_xprt)->sin_addr.s_addr;

	       if (rqst->rq_xprt->xp_laddrlen > 0) {
		    bindings.acceptor_addrtype = GSS_C_AF_INET;
		    bindings.acceptor_address.length = 4;
		    bindings.acceptor_address.value =
			 &rqst->rq_xprt->xp_laddr.sin_addr.s_addr;
	       } else {
		    LOG_MISCERR("cannot get local address");
		    ret = AUTH_FAILED;
		    goto error;
	       }


	       bindp = &bindings;
	  } else {
	       bindp = GSS_C_NO_CHANNEL_BINDINGS;
	  }

	  /*
	   * If the client's server_creds is already set, use it.
	   * Otherwise, try each credential in server_creds_list until
	   * one of them succeedes, then set the client server_creds
	   * to that.  If all fail, the client's server_creds isn't
	   * set (which is fine, because the client will be gc'ed
	   * anyway).
	   *
	   * If accept_sec_context returns something other than
	   * success and GSS_S_FAILURE, then assume different
	   * credentials won't help and stop looping.
	   * 
	   * Note that there are really two cases here: (1) the client
	   * has a server_creds already, and (2) it does not.  They
	   * are both written in the same loop so that there is only
	   * one textual call to gss_accept_sec_context; in fact, in
	   * case (1), the loop is executed exactly once.
	   */
	  for (i = 0; i < server_creds_count; i++) {
	       if (client_data->server_creds != NULL) {
		    PRINTF(("svcauth_gssapi: using's clients server_creds\n"));
		    server_creds = client_data->server_creds;
	       } else {
		    PRINTF(("svcauth_gssapi: trying creds %d\n", i));
		    server_creds = server_creds_list[i];
	       }
	       
	       /* Free previous output_token from loop */
	       if(i != 0) gss_release_buffer(&minor_stat, &output_token);

	       call_res.gss_major =
		    gss_accept_sec_context(&call_res.gss_minor,
					   &client_data->context,
					   server_creds,
					   &call_arg.token,
					   bindp,
					   &client_data->client_name,
					   NULL,
					   &output_token,
					   &ret_flags,
					   &time_rec,
					   NULL);

	       if (server_creds == client_data->server_creds)
		    break;

	       PRINTF(("accept_sec_context returned 0x%x 0x%x wrong-princ=%#x\n",
		       call_res.gss_major, call_res.gss_minor, (int) KRB5KRB_AP_WRONG_PRINC));
	       if (call_res.gss_major == GSS_S_COMPLETE ||
		   call_res.gss_major == GSS_S_CONTINUE_NEEDED) {
		    /* server_creds was right, set it! */
		    PRINTF(("svcauth_gssapi: creds are correct, storing\n"));
		    client_data->server_creds = server_creds;
		    client_data->server_name = server_name_list[i];
		    break;
	       } else if (call_res.gss_major != GSS_S_FAILURE
#ifdef GSSAPI_KRB5
			  /*
			   * hard-coded because there is no other way
			   * to prevent all GSS_S_FAILURES from
			   * returning a "wrong principal in request"
			   * error
			   */
			  || ((krb5_error_code) call_res.gss_minor !=
			      (krb5_error_code) KRB5KRB_AP_WRONG_PRINC)
#endif
			  ) {
		    break;
	       }
	  }
	  
	  gssstat = call_res.gss_major;
	  minor_stat = call_res.gss_minor;

	  /* done with call args */
	  xdr_free(xdr_authgssapi_init_arg, &call_arg);

	  PRINTF(("svcauth_gssapi: accept_sec_context returned %#x %#x\n",
		  call_res.gss_major, call_res.gss_minor));
	  if (call_res.gss_major != GSS_S_COMPLETE &&
	      call_res.gss_major != GSS_S_CONTINUE_NEEDED) {
	       AUTH_GSSAPI_DISPLAY_STATUS(("accepting context",
					   call_res.gss_major,
					   call_res.gss_minor));

	       if (log_badauth != NULL)
		    (*log_badauth)(call_res.gss_major,
				   call_res.gss_minor,
				   &rqst->rq_xprt->xp_raddr,
				   log_badauth_data);
	       
	       gss_release_buffer(&minor_stat, &output_token);
	       svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res,
			     (caddr_t) &call_res);
	       *no_dispatch = TRUE;
	       ret = AUTH_OK;
	       goto error;
	  }
	      
	  if (output_token.length != 0) {
	       PRINTF(("svcauth_gssapi: got new output token\n"));
	       GSS_COPY_BUFFER(call_res.token, output_token);
	  }

	  if (gssstat == GSS_S_COMPLETE) {
	       client_data->seq_num = rand();
	       client_expire(client_data,
			     (time_rec == GSS_C_INDEFINITE ?
			      INDEF_EXPIRE : time_rec) + time(0));

	       PRINTF(("svcauth_gssapi: context established, isn %d\n", 
		       client_data->seq_num));

	       if (auth_gssapi_seal_seq(client_data->context,
					client_data->seq_num,
					&call_res.signed_isn) ==
		   FALSE) {
		    ret = AUTH_FAILED;
		    LOG_MISCERR("internal error sealing sequence number");
		    gss_release_buffer(&minor_stat, &output_token);
		    goto error;
	       }
	  }

	  PRINTF(("svcauth_gssapi: sending reply\n"));
	  svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res,
			(caddr_t) &call_res);
	  *no_dispatch = TRUE;

	  /*
	   * If appropriate, set established to TRUE *after* sending
	   * response (otherwise, the client will receive the final
	   * token encrypted)
	   */
	  if (gssstat == GSS_S_COMPLETE) {
	       gss_release_buffer(&minor_stat, &call_res.signed_isn);
	       client_data->established = TRUE;
	  }
	  gss_release_buffer(&minor_stat, &output_token);
     } else {
	  PRINTF(("svcauth_gssapi: context is established\n"));

	  /* check the verifier */
	  PRINTF(("svcauth_gssapi: checking verifier, len %d\n",
		  verf->oa_length));
	  
	  in_buf.length = verf->oa_length;
	  in_buf.value = verf->oa_base;
	  
	  if (auth_gssapi_unseal_seq(client_data->context, &in_buf,
				     &seq_num) == FALSE) {
	       ret = AUTH_BADVERF;
	       LOG_MISCERR("internal error unsealing sequence number");
	       goto error;
	  }
	  
	  if (seq_num != client_data->seq_num + 1) {
	       PRINTF(("svcauth_gssapi: expected isn %d, got %d\n",
		       client_data->seq_num + 1, seq_num));
	       if (log_badverf != NULL)
		    (*log_badverf)(client_data->client_name,
				   client_data->server_name,
				   rqst, msg, log_badverf_data);
	       
	       ret = AUTH_REJECTEDVERF;
	       goto error;
	  }
	  client_data->seq_num++;
	  
	  PRINTF(("svcauth_gssapi: seq_num %d okay\n", seq_num));

	  /* free previous response verifier, if any */
	  if (client_data->prev_verf.length != 0) {
	       gss_release_buffer(&minor_stat, &client_data->prev_verf);
	       client_data->prev_verf.length = 0;
	  }
	  
	  /* prepare response verifier */
	  seq_num = client_data->seq_num + 1;
	  if (auth_gssapi_seal_seq(client_data->context, seq_num,
				   &out_buf) == FALSE) {
	       ret = AUTH_FAILED;
	       LOG_MISCERR("internal error sealing sequence number");
	       goto error;
	  }
	  
	  client_data->seq_num++;
	  
	  PRINTF(("svcauth_gssapi; response seq_num %d\n", seq_num));
	  
	  rqst->rq_xprt->xp_verf.oa_flavor = AUTH_GSSAPI;
	  rqst->rq_xprt->xp_verf.oa_base = out_buf.value; 
	  rqst->rq_xprt->xp_verf.oa_length = out_buf.length;

	  /* save verifier so it can be freed next time */
	  client_data->prev_verf.value = out_buf.value; 
	  client_data->prev_verf.length = out_buf.length;

	  /*
	   * Message is authentic.  If auth_msg if true, process the
	   * call; otherwise, return AUTH_OK so it will be dispatched
	   * to the application server.
	   */

	  if (creds.auth_msg == TRUE) {
	       /*
		* If process_token fails, then the token probably came
		* from an attacker.  No response (error or otherwise)
		* should be returned to the client, since it won't be
		* accepting one.
		*/

	       switch (rqst->rq_proc) {
	       case AUTH_GSSAPI_MSG:
		    PRINTF(("svcauth_gssapi: GSSAPI_MSG, getting args\n"));
		    memset(&call_arg, 0, sizeof(call_arg));
		    if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg,
				      &call_arg)) {
			 PRINTF(("svcauth_gssapi: cannot decode args\n"));
			 LOG_MISCERR("protocol error in call arguments");
			 xdr_free(xdr_authgssapi_init_arg, &call_arg);
			 ret = AUTH_BADCRED;
			 goto error;
		    }

		    PRINTF(("svcauth_gssapi: processing token\n"));
		    gssstat = gss_process_context_token(&minor_stat,
							client_data->context,
							&call_arg.token);

		    /* done with call args */
		    xdr_free(xdr_authgssapi_init_arg, &call_arg);
		    
		    if (gssstat != GSS_S_COMPLETE) {
			 AUTH_GSSAPI_DISPLAY_STATUS(("processing token",
						     gssstat, minor_stat));
			 ret = AUTH_FAILED;
			 goto error;
		    }

		    svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
		    *no_dispatch = TRUE;
		    break;

	       case AUTH_GSSAPI_DESTROY:
		    PRINTF(("svcauth_gssapi: GSSAPI_DESTROY\n"));
		    
		    PRINTF(("svcauth_gssapi: sending reply\n"));
		    svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
		    *no_dispatch = TRUE;

		    destroy_client(client_data);
		    rqst->rq_xprt->xp_auth = NULL;
		    break;

	       default:
		    PRINTF(("svcauth_gssapi: unacceptable procedure %d\n",
			    rqst->rq_proc));
		    LOG_MISCERR("invalid call procedure number");
		    ret = AUTH_FAILED;
		    goto error;
	       }
	  } else {
	       /* set credentials for app server; comment in svc.c */
	       /* seems to imply this is incorrect, but I don't see */
	       /* any problem with it... */
	       rqst->rq_clntcred = (char *)client_data->client_name;
	       rqst->rq_svccred = (char *)client_data->context;
	  }
     }

     if (creds.client_handle.length != 0) {
	  PRINTF(("svcauth_gssapi: freeing client_handle len %d\n",
		  (int) creds.client_handle.length));
	  xdr_free(xdr_authgssapi_creds, &creds);
     }
     
     PRINTF(("\n"));
     return AUTH_OK;

error:
     if (creds.client_handle.length != 0) {
	  PRINTF(("svcauth_gssapi: freeing client_handle len %d\n",
		  (int) creds.client_handle.length));
	  xdr_free(xdr_authgssapi_creds, &creds);
     }
     
     PRINTF(("\n"));
     return ret;
}
Пример #6
0
/**
 * @brief
 *	 encode a Job Credential Batch Request
 *
 * @param[in] c - socket descriptor
 * @param[in] type - credential type
 * @param[in] buf - credentials
 * @param[in] len - credential length
 * @param[in] rpp - indication for whether to use rpp
 * @param[in] msgid - msg id
 *
 * @return	int
 * @retval	0		success
 * @retval	!0(pbse error)	error
 *
 */
int
PBSD_jcred(int c, int type, char *buf, int len, int rpp, char **msgid)
{
	int			rc;
	struct batch_reply	*reply = NULL;
	int			sock;

	if (!rpp) {
		sock = connection[c].ch_socket;
		DIS_tcp_setup(sock);
	} else {
		sock = c;
		if ((rc = is_compose_cmd(sock, IS_CMD, msgid)) != DIS_SUCCESS)
			return rc;
	}

#ifdef  PBS_CRED_GRIDPROXY
	if (type == PBS_CREDTYPE_GRIDPROXY) {
		OM_uint32		major, minor;
		gss_buffer_desc		input, output;
		/*
		 OM_uint32		flag = GSS_C_CONF_FLAG|GSS_C_DELEG_FLAG;
		 */
		OM_uint32		flag = GSS_C_CONF_FLAG;
		gss_ctx_id_t		context = GSS_C_NO_CONTEXT;
		OM_uint32		life;
		int			ret;

		output.length = 0;
		input.length = 0;

		for (;;) {
			major = gss_init_sec_context(&minor,
				GSS_C_NO_CREDENTIAL, &context,
				GSS_C_NO_NAME, GSS_C_NO_OID, flag, 0,
				GSS_C_NO_CHANNEL_BINDINGS, &input, NULL,
				&output, NULL, NULL);

			if (reply)
				PBSD_FreeReply(reply);

			rc = PBSD_GSS_context(sock, output.value, output.length);
			if (rc) {
				connection[c].ch_errtxt = strdup(dis_emsg[rc]);
				if (connection[c].ch_errtxt == NULL)
					return (pbs_errno = PBSE_SYSTEM);
				return (pbs_errno = PBSE_PROTOCOL);
			}

			if (GSS_ERROR(major)) {
				connection[c].ch_errtxt =
					pbs_gss_error("gss_init_sec_context",
					major, minor);
				return (pbs_errno = PBSE_PROTOCOL);
			}

			reply = PBSD_rdrpy(c);
			if (reply == NULL)
				return (pbs_errno = PBSE_PROTOCOL);
			if (pbs_errno != PBSE_NONE) {
				PBSD_FreeReply(reply);
				return pbs_errno;
			}
			if (reply->brp_choice == BATCH_REPLY_CHOICE_Text) {
				input.length = reply->brp_un.brp_txt.brp_txtlen;
				input.value = reply->brp_un.brp_txt.brp_str;
			}
			else {
				input.length = 0;
				input.value = NULL;
			}
			if (input.length == 0 &&
				(major & GSS_S_CONTINUE_NEEDED) == 0)
				break;
		}
		if (reply)
			PBSD_FreeReply(reply);

		(void)gss_release_buffer(&minor, &output);
		if (major != GSS_S_COMPLETE || context == GSS_C_NO_CONTEXT) {
			connection[c].ch_errtxt =
				strdup("context could not be established");
			if (connection[c].ch_errtxt == NULL)
				return (pbs_errno = PBSE_SYSTEM);
			return (pbs_errno = PBSE_PROTOCOL);
		}

		input.value = buf;
		input.length = len;
		output.length = 0;
		major = gss_seal(&minor, context, 1, GSS_C_QOP_DEFAULT,
			&input, &ret, &output);
		if (major != GSS_S_COMPLETE) {
			connection[c].ch_errtxt =
				pbs_gss_error("gss_seal", major, minor);
			return (pbs_errno = PBSE_PROTOCOL);
		}
		if (ret == 0) {
			connection[c].ch_errtxt =
				strdup("confidentiality not available");
			if (connection[c].ch_errtxt == NULL)
				return (pbs_errno = PBSE_SYSTEM);
			return (pbs_errno = PBSE_PROTOCOL);
		}

		buf = output.value;
		len = output.length;

		output.length = 0;
		major = gss_delete_sec_context(&minor, &context, &output);
		if (major == GSS_S_COMPLETE && output.length > 0) {
			(void)gss_process_context_token(&minor,
				context, &output);
			(void)gss_release_buffer(&minor, &output);
		}
	}
#endif

	if ((rc =encode_DIS_ReqHdr(sock, PBS_BATCH_JobCred, pbs_current_user)) ||
		(rc = encode_DIS_JobCred(sock, type, buf, len)) ||
		(rc = encode_DIS_ReqExtend(sock, (char *)0))) {
		if (!rpp) {
			connection[c].ch_errtxt = strdup(dis_emsg[rc]);
			if (connection[c].ch_errtxt == NULL)
				return (pbs_errno = PBSE_SYSTEM);
		}
		return (pbs_errno = PBSE_PROTOCOL);
	}

	if (rpp) {
		pbs_errno = PBSE_NONE;
		if (rpp_flush(sock))
			pbs_errno = PBSE_PROTOCOL;

		return (pbs_errno);
	}

	if (DIS_tcp_wflush(sock)) {
		return (pbs_errno = PBSE_PROTOCOL);
	}

	reply = PBSD_rdrpy(c);

	PBSD_FreeReply(reply);

	return connection[c].ch_errno;
}