OM_uint32
_gss_spnego_verify_mechtypes_mic(OM_uint32 *minor_status,
				 gssspnego_ctx ctx,
				 heim_octet_string *mic)
{
    gss_buffer_desc mic_buf;
    OM_uint32 major_status;

    if (ctx->flags.verified_mic) {
	/* This doesn't make sense, we've already verified it? */
	*minor_status = 0;
	return GSS_S_DUPLICATE_TOKEN;
    }

    mic_buf.length = mic->length;
    mic_buf.value  = mic->data;

    major_status = gss_verify_mic(minor_status,
				  ctx->negotiated_ctx_id,
				  &ctx->NegTokenInit_mech_types,
				  &mic_buf,
				  NULL);
    if (major_status == GSS_S_UNAVAILABLE) {
	_gss_mg_log(10, "mech doesn't support MIC, allowing anyway");	
    } else if (major_status) {
	return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
				       GSS_S_DEFECTIVE_TOKEN, *minor_status,
				       "SPNEGO peer sent invalid mechListMIC");
    }
    ctx->flags.verified_mic = 1;

    *minor_status = 0;

    return GSS_S_COMPLETE;
}
Example #2
0
OM_uint32 GSSAPI_CALLCONV _gss_spnego_verify_mic
           (OM_uint32 * minor_status,
            gss_const_ctx_id_t context_handle,
            const gss_buffer_t message_buffer,
            const gss_buffer_t token_buffer,
            gss_qop_t * qop_state
           )
{
    gssspnego_ctx ctx;

    *minor_status = 0;

    if (context_handle == GSS_C_NO_CONTEXT) {
	return GSS_S_NO_CONTEXT;
    }

    ctx = (gssspnego_ctx)context_handle;

    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
	return GSS_S_NO_CONTEXT;
    }

    return gss_verify_mic(minor_status,
			  ctx->negotiated_ctx_id,
			  message_buffer,
			  token_buffer,
			  qop_state);
}
/*%
 * Verify.
 */
static isc_result_t
gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
	dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
	isc_region_t message, r;
	gss_buffer_desc gmessage, gsig;
	OM_uint32 minor, gret;
	gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
	unsigned char *buf;
	char err[1024];

	/*
	 * Convert the data we wish to sign into a structure gssapi can
	 * understand.
	 */
	isc_buffer_usedregion(ctx->buffer, &message);
	REGION_TO_GBUFFER(message, gmessage);

	/*
	 * XXXMLG
	 * It seem that gss_verify_mic() modifies the signature buffer,
	 * at least on Heimdal's implementation.  Copy it here to an allocated
	 * buffer.
	 */
	buf = isc_mem_allocate(dst__memory_pool, sig->length);
	if (buf == NULL)
		return (ISC_R_FAILURE);
	memmove(buf, sig->base, sig->length);
	r.base = buf;
	r.length = sig->length;
	REGION_TO_GBUFFER(r, gsig);

	/*
	 * Verify the data.
	 */
	gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);

	isc_mem_free(dst__memory_pool, buf);

	/*
	 * Convert return codes into something useful to us.
	 */
	if (gret != GSS_S_COMPLETE) {
		gss_log(3, "GSS verify error: %s",
			gss_error_tostring(gret, minor, err, sizeof(err)));
		if (gret == GSS_S_DEFECTIVE_TOKEN ||
		    gret == GSS_S_BAD_SIG ||
		    gret == GSS_S_DUPLICATE_TOKEN ||
		    gret == GSS_S_OLD_TOKEN ||
		    gret == GSS_S_UNSEQ_TOKEN ||
		    gret == GSS_S_GAP_TOKEN ||
		    gret == GSS_S_CONTEXT_EXPIRED ||
		    gret == GSS_S_NO_CONTEXT ||
		    gret == GSS_S_FAILURE)
			return(DST_R_VERIFYFAILURE);
		else
			return (ISC_R_FAILURE);
	}

	return (ISC_R_SUCCESS);
}
Example #4
0
/* Privileged */
OM_uint32
ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
{
	ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
	    gssbuf, gssmic, NULL);

	return (ctx->major);
}
Example #5
0
static bool_t
svcauth_gss_validate(struct svc_req *rqst, struct svc_rpc_gss_data *gd, struct rpc_msg *msg)
{
	struct opaque_auth	*oa;
	gss_buffer_desc		 rpcbuf, checksum;
	OM_uint32		 maj_stat, min_stat, qop_state;
	u_char			 rpchdr[128];
	int32_t			*buf;

	log_debug("in svcauth_gss_validate()");

	memset(rpchdr, 0, sizeof(rpchdr));

	/* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */
	oa = &msg->rm_call.cb_cred;
	if (oa->oa_length > MAX_AUTH_BYTES)
		return (FALSE);

	/* 8 XDR units from the IXDR macro calls. */
	if (sizeof(rpchdr) < (8 * BYTES_PER_XDR_UNIT +
			      RNDUP(oa->oa_length)))
		return (FALSE);

	buf = (int32_t *)(void *)rpchdr;
	IXDR_PUT_LONG(buf, msg->rm_xid);
	IXDR_PUT_ENUM(buf, msg->rm_direction);
	IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers);
	IXDR_PUT_LONG(buf, msg->rm_call.cb_prog);
	IXDR_PUT_LONG(buf, msg->rm_call.cb_vers);
	IXDR_PUT_LONG(buf, msg->rm_call.cb_proc);
	IXDR_PUT_ENUM(buf, oa->oa_flavor);
	IXDR_PUT_LONG(buf, oa->oa_length);
	if (oa->oa_length) {
		memcpy((caddr_t)buf, oa->oa_base, oa->oa_length);
		buf += RNDUP(oa->oa_length) / sizeof(int32_t);
	}
	rpcbuf.value = rpchdr;
	rpcbuf.length = (u_char *)buf - rpchdr;

	checksum.value = msg->rm_call.cb_verf.oa_base;
	checksum.length = msg->rm_call.cb_verf.oa_length;

	maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum,
				  &qop_state);

	if (maj_stat != GSS_S_COMPLETE) {
		log_status("gss_verify_mic", maj_stat, min_stat);
		if (log_badverf != NULL)
			(*log_badverf)(gd->client_name,
			       svcauth_gss_name,
			       rqst, msg, log_badverf_data);
		return (FALSE);
	}
	return (TRUE);
}
Example #6
0
uint32_t
sapgss_verify_mic(
    uint32_t *minor_status,
    gss_ctx_id_t context_handle,
    gss_buffer_t message_buffer,
    gss_buffer_t message_token,
    gss_qop_t *qop_state)
{
    return gss_verify_mic(minor_status, context_handle, message_buffer,
			  message_token, qop_state);
}
Example #7
0
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_verify(OM_uint32 *minor_status,
    gss_ctx_id_t context_handle,
    gss_buffer_t message_buffer,
    gss_buffer_t token_buffer,
    int *qop_state)
{

	return (gss_verify_mic(minor_status,
		    context_handle, message_buffer, token_buffer,
		    (gss_qop_t *)qop_state));
}
Example #8
0
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 = &num;
	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);
}
Example #9
0
static bool_t
rpc_gss_validate(AUTH *auth, struct opaque_auth *verf)
{
	struct rpc_gss_data	*gd;
	gss_qop_t		qop_state;
	uint32_t		num;
	gss_buffer_desc		signbuf, checksum;
	OM_uint32		maj_stat, min_stat;

	log_debug("in rpc_gss_validate()");
	
	gd = AUTH_PRIVATE(auth);

	if (gd->gd_state == RPCSEC_GSS_CONTEXT) {
		/*
		 * Save the on the wire verifier to validate last INIT
		 * phase packet after decode if the major status is
		 * GSS_S_COMPLETE.
		 */
		if (gd->gd_verf.value)
			xdr_free((xdrproc_t) xdr_gss_buffer_desc,
			    (char *) &gd->gd_verf);
		gd->gd_verf.value = mem_alloc(verf->oa_length);
		if (gd->gd_verf.value == NULL) {
			fprintf(stderr, "gss_validate: out of memory\n");
			_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
			return (FALSE);
		}
		memcpy(gd->gd_verf.value, verf->oa_base, verf->oa_length);
		gd->gd_verf.length = verf->oa_length;
		return (TRUE);
	}

	num = htonl(gd->gd_cred.gc_seq);
	signbuf.value = &num;
	signbuf.length = sizeof(num);
	
	checksum.value = verf->oa_base;
	checksum.length = verf->oa_length;
	
	maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx, &signbuf,
	    &checksum, &qop_state);
	if (maj_stat != GSS_S_COMPLETE || qop_state != gd->gd_qop) {
		log_status("gss_verify_mic", gd->gd_mech, maj_stat, min_stat);
		if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
			rpc_gss_destroy_context(auth, TRUE);
		}
		_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
		return (FALSE);
	}
	return (TRUE);
}
Example #10
0
static int
svcauth_gss_validate(struct svc_req *req,
		     struct svc_rpc_gss_data *gd,
		     struct rpc_msg *msg)
{
	struct opaque_auth *oa;
	gss_buffer_desc rpcbuf, checksum;
	OM_uint32 maj_stat, min_stat, qop_state;
	u_char rpchdr[RPCHDR_LEN];
	int32_t *buf;

	memset(rpchdr, 0, RPCHDR_LEN);

	/* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */
	oa = &msg->rm_call.cb_cred;
	if (oa->oa_length > MAX_AUTH_BYTES)
		return GSS_S_CALL_BAD_STRUCTURE;
	/* XXX since MAX_AUTH_BYTES is 400, the following code trivially
	 * overruns (up to 431 per Coverity, but compare RPCHDR_LEN with
	 * what is marshalled below). */

	buf = (int32_t *) rpchdr;
	IXDR_PUT_LONG(buf, msg->rm_xid);
	IXDR_PUT_ENUM(buf, msg->rm_direction);
	IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers);
	IXDR_PUT_LONG(buf, msg->rm_call.cb_prog);
	IXDR_PUT_LONG(buf, msg->rm_call.cb_vers);
	IXDR_PUT_LONG(buf, msg->rm_call.cb_proc);
	IXDR_PUT_ENUM(buf, oa->oa_flavor);
	IXDR_PUT_LONG(buf, oa->oa_length);
	if (oa->oa_length) {
		memcpy((caddr_t) buf, oa->oa_base, oa->oa_length);
		buf += RNDUP(oa->oa_length) / sizeof(int32_t);
	}
	rpcbuf.value = rpchdr;
	rpcbuf.length = (u_char *) buf - rpchdr;

	checksum.value = msg->rm_call.cb_verf.oa_base;
	checksum.length = msg->rm_call.cb_verf.oa_length;

	maj_stat =
	    gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum, &qop_state);

	if (maj_stat != GSS_S_COMPLETE) {
		__warnx(TIRPC_DEBUG_FLAG_AUTH, "%s: %d %d", __func__, maj_stat,
			min_stat);
		return (maj_stat);
	}
	return GSS_S_COMPLETE;
}
Example #11
0
OM_uint32
ntlm_gss_verify_mic(
		OM_uint32 *minor_status,
		const gss_ctx_id_t context_handle,
		const gss_buffer_t msg_buffer,
		const gss_buffer_t token_buffer,
		gss_qop_t *qop_state)
{
	OM_uint32 ret;
	ret = gss_verify_mic(minor_status,
			    context_handle,
			    msg_buffer,
			    token_buffer,
			    qop_state);
	return (ret);
}
Example #12
0
static isc_result_t
gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
	gssapi_ctx_t *ctx = dctx->opaque;
	isc_region_t message;
	gss_buffer_desc gmessage, gsig;
	OM_uint32 minor, gret;

	isc_buffer_usedregion(ctx->buffer, &message);
	REGION_TO_GBUFFER(message, gmessage);

	REGION_TO_GBUFFER(*sig, gsig);

	gret = gss_verify_mic(&minor, ctx->context_id, &gmessage, &gsig, NULL);
	if (gret != 0)
		return (ISC_R_FAILURE);

	return (ISC_R_SUCCESS);
}
Example #13
0
static int
HandleOP(Verify)
{
    OM_uint32 maj_stat, min_stat;
    int32_t hContext, flags, seqno;
    krb5_data msg, mic;
    gss_ctx_id_t ctx;
    gss_buffer_desc msg_token, mic_token;
    gss_qop_t qop;

    ret32(c, hContext);

    ctx = find_handle(c->handles, hContext, handle_context);
    if (ctx == NULL)
	errx(1, "verify: reference to unknown context");

    ret32(c, flags);
    ret32(c, seqno);
    retdata(c, msg);

    msg_token.length = msg.length;
    msg_token.value = msg.data;

    retdata(c, mic);

    mic_token.length = mic.length;
    mic_token.value = mic.data;

    maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token,
			      &mic_token, &qop);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_verify_mic failed");

    krb5_data_free(&mic);
    krb5_data_free(&msg);

    put32(c, 0); /* XXX fix gsm_error */

    return 0;
}
Example #14
0
static void
getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
{
    gss_buffer_desc input_token, output_token;
    OM_uint32 min_stat, maj_stat;
    gss_qop_t qop_state;

    input_token.value = "bar";
    input_token.length = 3;

    maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
			   &output_token);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_get_mic failed: %s",
	     gssapi_err(maj_stat, min_stat, mechoid));

    maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
			      &output_token, &qop_state);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_verify_mic failed: %s",
	     gssapi_err(maj_stat, min_stat, mechoid));

    gss_release_buffer(&min_stat, &output_token);
}
Example #15
0
static OM_uint32
verify_mechlist_mic
	   (OM_uint32 *minor_status,
	    gssspnego_ctx context_handle,
	    gss_buffer_t mech_buf,
	    heim_octet_string *mechListMIC
	   )
{
    OM_uint32 ret;
    gss_buffer_desc mic_buf;

    if (context_handle->verified_mic) {
	/* This doesn't make sense, we've already verified it? */
	*minor_status = 0;
	return GSS_S_DUPLICATE_TOKEN;
    }

    if (mechListMIC == NULL) {
	*minor_status = 0;
	return GSS_S_DEFECTIVE_TOKEN;
    }

    mic_buf.length = mechListMIC->length;
    mic_buf.value  = mechListMIC->data;

    ret = gss_verify_mic(minor_status,
			 context_handle->negotiated_ctx_id,
			 mech_buf,
			 &mic_buf,
			 NULL);

    if (ret != GSS_S_COMPLETE)
	ret = GSS_S_DEFECTIVE_TOKEN;

    return ret;
}
Example #16
0
static bool_t
authgss_refresh(AUTH *auth, struct rpc_msg *msg)
{
	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 || gd->inprogress)
		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 (;;) {
		gd->inprogress = TRUE;
		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 */
						GSS_C_NO_CHANNEL_BINDINGS, 
						recv_tokenp,
						NULL,		/* used mech */
						&send_token,
						&ret_flags,
						NULL);		/* time rec */
		
		log_status("gss_init_sec_context", maj_stat, min_stat);
		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 (error)", maj_stat, min_stat);
			break;
		}
		if (send_token.length != 0) {
			memset(&gr, 0, sizeof(gr));
			
			call_stat = clnt_call(gd->clnt, NULLPROC,
					      xdr_rpc_gss_init_args,
					      &send_token,
					      xdr_rpc_gss_init_res,
					      (caddr_t)&gr, AUTH_TIMEOUT);
			
			gss_release_buffer(&min_stat, &send_token);

			log_debug("authgss_refresh: call_stat=%d", call_stat);
			log_debug("%s", clnt_sperror(gd->clnt, "authgss_refresh"));
			if (call_stat != RPC_SUCCESS ||
			    (gr.gr_major != GSS_S_COMPLETE &&
			     gr.gr_major != GSS_S_CONTINUE_NEEDED))
				break;
			
			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;
			uint32_t seq;
			gss_qop_t qop_state = 0;

			seq = htonl(gr.gr_win);
			bufin.value = (u_char *)&seq;
			bufin.length = sizeof(seq);
			bufout.value = (u_char *)gd->gc_wire_verf.value;
			bufout.length = gd->gc_wire_verf.length;

			log_debug("authgss_refresh: GSS_S_COMPLETE: calling verify_mic");
			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);
				gss_release_buffer(&min_stat, &gd->gc_wire_verf);
				if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
					gd->established = FALSE;
					authgss_destroy_context(auth);
				}
				return (FALSE);
			}
			gss_release_buffer(&min_stat, &gd->gc_wire_verf);
			gd->established = TRUE;
			gd->inprogress = FALSE;
			gd->gc.gc_proc = RPCSEC_GSS_DATA;
			gd->gc.gc_seq = 0;
			gd->win = gr.gr_win;
			break;
		}
	}
	log_status("authgss_refresh: at end of context negotiation", maj_stat, min_stat);
	/* End context negotiation loop. */
	if (gd->gc.gc_proc != RPCSEC_GSS_DATA) {
		log_debug("authgss_refresh: returning ERROR (gc_proc %d)", gd->gc.gc_proc);
		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);
	}
	log_debug("authgss_refresh: returning SUCCESS");
	return (TRUE);
}
Example #17
0
static bool_t
rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
{
	struct rpc_gss_data	*gd;
	struct rpc_gss_init_res	 gr;
	gss_buffer_desc		*recv_tokenp, recv_token, send_token;
	OM_uint32		 maj_stat, min_stat, call_stat;
	const char		*mech;

	log_debug("in rpc_gss_refresh()");
	
	gd = AUTH_PRIVATE(auth);
	
	if (gd->gd_state != RPCSEC_GSS_START)
		return (TRUE);
	
	/* GSS context establishment loop. */
	gd->gd_state = RPCSEC_GSS_CONTEXT;
	gd->gd_cred.gc_proc = RPCSEC_GSS_INIT;
	gd->gd_cred.gc_seq = 0;

	memset(&recv_token, 0, sizeof(recv_token));
	memset(&gr, 0, sizeof(gr));
	recv_tokenp = GSS_C_NO_BUFFER;
	
	for (;;) {
		maj_stat = gss_init_sec_context(&min_stat,
		    gd->gd_options.my_cred,
		    &gd->gd_ctx,
		    gd->gd_name,
		    gd->gd_mech,
		    gd->gd_options.req_flags,
		    gd->gd_options.time_req,
		    gd->gd_options.input_channel_bindings,
		    recv_tokenp,
		    &gd->gd_mech,	/* used mech */
		    &send_token,
		    &options_ret->ret_flags,
		    &options_ret->time_req);
		
		/*
		 * Free the token which we got from the server (if
		 * any).  Remember that this was allocated by XDR, not
		 * GSS-API.
		 */
		if (recv_tokenp != GSS_C_NO_BUFFER) {
			xdr_free((xdrproc_t) xdr_gss_buffer_desc,
			    (char *) &recv_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", gd->gd_mech,
			    maj_stat, min_stat);
			options_ret->major_status = maj_stat;
			options_ret->minor_status = min_stat;
			break;
		}
		if (send_token.length != 0) {
			memset(&gr, 0, sizeof(gr));
			
			call_stat = clnt_call(gd->gd_clnt, NULLPROC,
			    (xdrproc_t)xdr_gss_buffer_desc,
			    &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)
				break;

			if (gr.gr_major != GSS_S_COMPLETE &&
			    gr.gr_major != GSS_S_CONTINUE_NEEDED) {
				log_status("server reply", gd->gd_mech,
				    gr.gr_major, gr.gr_minor);
				options_ret->major_status = gr.gr_major;
				options_ret->minor_status = gr.gr_minor;
				break;
			}
			
			/*
			 * Save the server's gr_handle value, freeing
			 * what we have already (remember that this
			 * was allocated by XDR, not GSS-API).
			 */
			if (gr.gr_handle.length != 0) {
				xdr_free((xdrproc_t) xdr_gss_buffer_desc,
				    (char *) &gd->gd_cred.gc_handle);
				gd->gd_cred.gc_handle = gr.gr_handle;
			}

			/*
			 * Save the server's token as well.
			 */
			if (gr.gr_token.length != 0) {
				recv_token = gr.gr_token;
				recv_tokenp = &recv_token;
			}

			/*
			 * Since we have copied out all the bits of gr
			 * which XDR allocated for us, we don't need
			 * to free it.
			 */
			gd->gd_cred.gc_proc = RPCSEC_GSS_CONTINUE_INIT;
		}

		if (maj_stat == GSS_S_COMPLETE) {
			gss_buffer_desc   bufin;
			u_int seq, qop_state = 0;

			/* 
			 * gss header verifier,
			 * usually checked in gss_validate
			 */
			seq = htonl(gr.gr_win);
			bufin.value = (unsigned char *)&seq;
			bufin.length = sizeof(seq);

			maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx,
			    &bufin, &gd->gd_verf, &qop_state);

			if (maj_stat != GSS_S_COMPLETE ||
			    qop_state != gd->gd_qop) {
				log_status("gss_verify_mic", gd->gd_mech,
				    maj_stat, min_stat);
				if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
					rpc_gss_destroy_context(auth, TRUE);
				}
				_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR,
				    EPERM);
				options_ret->major_status = maj_stat;
				options_ret->minor_status = min_stat;
				return (FALSE);
			}

			options_ret->major_status = GSS_S_COMPLETE;
			options_ret->minor_status = 0;
			options_ret->rpcsec_version = gd->gd_cred.gc_version;
			options_ret->gss_context = gd->gd_ctx;
			if (rpc_gss_oid_to_mech(gd->gd_mech, &mech)) {
				strlcpy(options_ret->actual_mechanism,
				    mech,
				    sizeof(options_ret->actual_mechanism));
			}

			gd->gd_state = RPCSEC_GSS_ESTABLISHED;
			gd->gd_cred.gc_proc = RPCSEC_GSS_DATA;
			gd->gd_cred.gc_seq = 0;
			gd->gd_win = gr.gr_win;
			break;
		}
	}
	xdr_free((xdrproc_t) xdr_gss_buffer_desc,
	    (char *) &gd->gd_verf);

	/* End context negotiation loop. */
	if (gd->gd_cred.gc_proc != RPCSEC_GSS_DATA) {
		rpc_createerr.cf_stat = RPC_AUTHERROR;
		_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
		return (FALSE);
	}
	
	return (TRUE);
}
static OM_uint32
spnego_reply
           (OM_uint32 * minor_status,
	    const gssspnego_cred cred,
            gss_ctx_id_t * context_handle,
            const gss_name_t target_name,
            const gss_OID mech_type,
            OM_uint32 req_flags,
            OM_uint32 time_req,
            const gss_channel_bindings_t input_chan_bindings,
            const gss_buffer_t input_token,
            gss_OID * actual_mech_type,
            gss_buffer_t output_token,
            OM_uint32 * ret_flags,
            OM_uint32 * time_rec
    )
{
    OM_uint32 ret, minor;
    NegTokenResp resp;
    u_char oidbuf[17];
    size_t oidlen;
    size_t len, taglen;
    gss_OID_desc mech;
    int require_mic;
    size_t buf_len;
    gss_buffer_desc mic_buf, mech_buf;
    gss_buffer_desc mech_output_token;
    gssspnego_ctx ctx;

    *minor_status = 0;

    ctx = (gssspnego_ctx)*context_handle;

    output_token->length = 0;
    output_token->value  = NULL;

    mech_output_token.length = 0;
    mech_output_token.value = NULL;

    mech_buf.value = NULL;
    mech_buf.length = 0;

    ret = der_match_tag_and_length(input_token->value, input_token->length,
				   ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
    if (ret)
	return ret;

    if (len > input_token->length - taglen)
	return ASN1_OVERRUN;

    ret = decode_NegTokenResp((const unsigned char *)input_token->value+taglen,
			      len, &resp, NULL);
    if (ret) {
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }

    if (resp.negResult == NULL
	|| *(resp.negResult) == reject
	|| resp.supportedMech == NULL) {
	free_NegTokenResp(&resp);
	return GSS_S_BAD_MECH;
    }

    ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
		      sizeof(oidbuf),
		      resp.supportedMech,
		      &oidlen);
    if (ret || (oidlen == GSS_SPNEGO_MECHANISM->length &&
		memcmp(oidbuf + sizeof(oidbuf) - oidlen,
		       GSS_SPNEGO_MECHANISM->elements,
		       oidlen) == 0)) {
	/* Avoid recursively embedded SPNEGO */
	free_NegTokenResp(&resp);
	return GSS_S_BAD_MECH;
    }

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    if (resp.responseToken != NULL) {
	gss_buffer_desc mech_input_token;

	mech_input_token.length = resp.responseToken->length;
	mech_input_token.value  = resp.responseToken->data;

	mech.length = oidlen;
	mech.elements = oidbuf + sizeof(oidbuf) - oidlen;

	/* Fall through as if the negotiated mechanism
	   was requested explicitly */
	ret = gss_init_sec_context(&minor,
				   (cred != NULL) ? cred->negotiated_cred_id :
				       GSS_C_NO_CREDENTIAL,
				   &ctx->negotiated_ctx_id,
				   target_name,
				   &mech,
				   req_flags,
				   time_req,
				   input_chan_bindings,
				   &mech_input_token,
				   &ctx->negotiated_mech_type,
				   &mech_output_token,
				   &ctx->mech_flags,
				   &ctx->mech_time_rec);
	if (GSS_ERROR(ret)) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free_NegTokenResp(&resp);
	    *minor_status = minor;
	    return ret;
	}
	if (ret == GSS_S_COMPLETE) {
	    ctx->open = 1;
	}
    }

    if (*(resp.negResult) == request_mic) {
	ctx->require_mic = 1;
    }

    if (ctx->open) {
	/*
	 * Verify the mechListMIC if one was provided or CFX was
	 * used and a non-preferred mechanism was selected
	 */
	if (resp.mechListMIC != NULL) {
	    require_mic = 1;
	} else {
	    ret = _gss_spnego_require_mechlist_mic(minor_status, ctx,
						   &require_mic);
	    if (ret) {
		HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
		free_NegTokenResp(&resp);
		gss_release_buffer(&minor, &mech_output_token);
		return ret;
	    }
	}
    } else {
	require_mic = 0;
    }

    if (require_mic) {
	ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
			   &ctx->initiator_mech_types, &buf_len, ret);
	if (ret) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free_NegTokenResp(&resp);
	    gss_release_buffer(&minor, &mech_output_token);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	if (mech_buf.length != buf_len)
	    abort();

	if (resp.mechListMIC == NULL) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free(mech_buf.value);
	    free_NegTokenResp(&resp);
	    *minor_status = 0;
	    return GSS_S_DEFECTIVE_TOKEN;
	}
	mic_buf.length = resp.mechListMIC->length;
	mic_buf.value  = resp.mechListMIC->data;

	if (mech_output_token.length == 0) {
	    ret = gss_verify_mic(minor_status,
				 ctx->negotiated_ctx_id,
				 &mech_buf,
				 &mic_buf,
				 NULL);
	   if (ret) {
		HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
		free(mech_buf.value);
		gss_release_buffer(&minor, &mech_output_token);
		free_NegTokenResp(&resp);
		return GSS_S_DEFECTIVE_TOKEN;
	    }
	    ctx->verified_mic = 1;
	}
    }

    ret = spnego_reply_internal(minor_status, ctx,
				require_mic ? &mech_buf : NULL,
				&mech_output_token,
				output_token);

    if (mech_buf.value != NULL)
	free(mech_buf.value);

    free_NegTokenResp(&resp);
    gss_release_buffer(&minor, &mech_output_token);

    if (actual_mech_type)
	*actual_mech_type = ctx->negotiated_mech_type;
    if (ret_flags)
	*ret_flags = ctx->mech_flags;
    if (time_rec)
	*time_rec = ctx->mech_time_rec;

    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    return ret;
}
Example #19
0
bool_t
xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
			gss_ctx_id_t ctx, gss_qop_t qop,
			rpc_gss_svc_t svc, u_int seq)
{
	XDR		tmpxdrs;
	gss_buffer_desc	databuf, wrapbuf;
	OM_uint32	maj_stat, min_stat;
	u_int		seq_num, qop_state;
	int			conf_state;
	bool_t		xdr_stat;

	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_GSS_SVC_INTEGRITY) {
		/* Decode databody_integ. */
		if (!xdr_rpc_gss_buf(xdrs, &databuf, (u_int)-1)) {
			log_debug("xdr decode databody_integ failed");
			return (FALSE);
		}
		/* Decode checksum. */
		if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
			gss_release_buffer(&min_stat, &databuf);
			log_debug("xdr decode checksum failed");
			return (FALSE);
		}
		/* Verify checksum and QOP. */
		maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
					  &wrapbuf, &qop_state);
		gss_release_buffer(&min_stat, &wrapbuf);

		if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
			gss_release_buffer(&min_stat, &databuf);
			log_status("gss_verify_mic", maj_stat, min_stat);
			return (FALSE);
		}
	}
	else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
		/* Decode databody_priv. */
		if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
			log_debug("xdr decode databody_priv failed");
			return (FALSE);
		}
		/* Decrypt databody. */
		maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
				      &conf_state, &qop_state);

		gss_release_buffer(&min_stat, &wrapbuf);

		/* Verify encryption and QOP. */
		if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
			conf_state != TRUE) {
			gss_release_buffer(&min_stat, &databuf);
			log_status("gss_unwrap", maj_stat, min_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);
	gss_release_buffer(&min_stat, &databuf);

	/* Verify sequence number. */
	if (xdr_stat == TRUE && seq_num != seq) {
		log_debug("wrong sequence number in databody");
		return (FALSE);
	}
	return (xdr_stat);
}
Example #20
0
int
main(int argc, char **argv)
{
	struct module_stat stat;
	int mod;
	int syscall_num;

	stat.version = sizeof(stat);
	mod = modfind("gsstest_syscall");
	if (mod < 0) {
		fprintf(stderr, "%s: kernel support not present\n", argv[0]);
		exit(1);
	}
	modstat(mod, &stat);
	syscall_num = stat.data.intval;

	switch (atoi(argv[1])) {
	case 1:
		syscall(syscall_num, 1, NULL, NULL);
		break;

	case 2: {
		struct gsstest_2_args args;
		struct gsstest_2_res res;
		char hostname[512];
		char token_buffer[8192];
		OM_uint32 maj_stat, min_stat;
		gss_ctx_id_t client_context = GSS_C_NO_CONTEXT;
		gss_cred_id_t client_cred;
		gss_OID mech_type = GSS_C_NO_OID;
		gss_buffer_desc name_buf, message_buf;
		gss_name_t name;
		int32_t enctypes[] = {
			ETYPE_DES_CBC_CRC,
			ETYPE_ARCFOUR_HMAC_MD5,
			ETYPE_ARCFOUR_HMAC_MD5_56,
			ETYPE_AES256_CTS_HMAC_SHA1_96,
			ETYPE_AES128_CTS_HMAC_SHA1_96,
			ETYPE_DES3_CBC_SHA1,
		};
		int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
		int established;
		int i;

		for (i = 0; i < num_enctypes; i++) {
			printf("testing etype %d\n", enctypes[i]);
			args.output_token.length = sizeof(token_buffer);
			args.output_token.value = token_buffer;

			gethostname(hostname, sizeof(hostname));
			snprintf(token_buffer, sizeof(token_buffer),
			    "nfs@%s", hostname);
			name_buf.length = strlen(token_buffer);
			name_buf.value = token_buffer;
			maj_stat = gss_import_name(&min_stat, &name_buf,
			    GSS_C_NT_HOSTBASED_SERVICE, &name);
			if (GSS_ERROR(maj_stat)) {
				printf("gss_import_name failed\n");
				report_error(mech_type, maj_stat, min_stat);
				goto out;
			}

			maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME,
			    0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred,
			    NULL, NULL);
			if (GSS_ERROR(maj_stat)) {
				printf("gss_acquire_cred (client) failed\n");
				report_error(mech_type, maj_stat, min_stat);
				goto out;
			}

			maj_stat = gss_krb5_set_allowable_enctypes(&min_stat,
			    client_cred, 1, &enctypes[i]);
			if (GSS_ERROR(maj_stat)) {
				printf("gss_krb5_set_allowable_enctypes failed\n");
				report_error(mech_type, maj_stat, min_stat);
				goto out;
			}

			res.output_token.length = 0;
			res.output_token.value = 0;
			established = 0;
			while (!established) {
				maj_stat = gss_init_sec_context(&min_stat,
				    client_cred,
				    &client_context,
				    name,
				    GSS_C_NO_OID,
				    (GSS_C_MUTUAL_FLAG
					|GSS_C_CONF_FLAG
					|GSS_C_INTEG_FLAG
					|GSS_C_SEQUENCE_FLAG
					|GSS_C_REPLAY_FLAG),
				    0,
				    GSS_C_NO_CHANNEL_BINDINGS,
				    &res.output_token,
				    &mech_type,
				    &args.input_token,
				    NULL,
				    NULL);
				if (GSS_ERROR(maj_stat)) {
					printf("gss_init_sec_context failed\n");
					report_error(mech_type, maj_stat, min_stat);
					goto out;
				}
				if (args.input_token.length) {
					args.step = 1;
					syscall(syscall_num, 2, &args, &res);
					gss_release_buffer(&min_stat,
					    &args.input_token);
					if (res.maj_stat != GSS_S_COMPLETE
					    && res.maj_stat != GSS_S_CONTINUE_NEEDED) {
						printf("gss_accept_sec_context (kernel) failed\n");
						report_error(mech_type, res.maj_stat,
						    res.min_stat);
						goto out;
					}
				}
				if (maj_stat == GSS_S_COMPLETE)
					established = 1;
			}

			message_buf.value = "Hello world";
			message_buf.length = strlen((char *) message_buf.value);

			maj_stat = gss_get_mic(&min_stat, client_context,
			    GSS_C_QOP_DEFAULT, &message_buf, &args.input_token);
			if (GSS_ERROR(maj_stat)) {
				printf("gss_get_mic failed\n");
				report_error(mech_type, maj_stat, min_stat);
				goto out;
			}
		
			args.step = 2;
			syscall(syscall_num, 2, &args, &res);
			gss_release_buffer(&min_stat, &args.input_token);
			if (GSS_ERROR(res.maj_stat)) {
				printf("kernel gss_verify_mic failed\n");
				report_error(mech_type, res.maj_stat, res.min_stat);
				goto out;
			}

			maj_stat = gss_verify_mic(&min_stat, client_context,
			    &message_buf, &res.output_token, NULL);
			if (GSS_ERROR(maj_stat)) {
				printf("gss_verify_mic failed\n");
				report_error(mech_type, maj_stat, min_stat);
				goto out;
			}

			maj_stat = gss_wrap(&min_stat, client_context,
			    TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL,
			    &args.input_token);
			if (GSS_ERROR(maj_stat)) {
				printf("gss_wrap failed\n");
				report_error(mech_type, maj_stat, min_stat);
				goto out;
			}

			args.step = 3;
			syscall(syscall_num, 2, &args, &res);
			gss_release_buffer(&min_stat, &args.input_token);
			if (GSS_ERROR(res.maj_stat)) {
				printf("kernel gss_unwrap failed\n");
				report_error(mech_type, res.maj_stat, res.min_stat);
				goto out;
			}

			maj_stat = gss_unwrap(&min_stat, client_context,
			    &res.output_token, &message_buf, NULL, NULL);
			if (GSS_ERROR(maj_stat)) {
				printf("gss_unwrap failed\n");
				report_error(mech_type, maj_stat, min_stat);
				goto out;
			}
			gss_release_buffer(&min_stat, &message_buf);

			maj_stat = gss_wrap(&min_stat, client_context,
			    FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL,
			    &args.input_token);
			if (GSS_ERROR(maj_stat)) {
				printf("gss_wrap failed\n");
				report_error(mech_type, maj_stat, min_stat);
				goto out;
			}

			args.step = 4;
			syscall(syscall_num, 2, &args, &res);
			gss_release_buffer(&min_stat, &args.input_token);
			if (GSS_ERROR(res.maj_stat)) {
				printf("kernel gss_unwrap failed\n");
				report_error(mech_type, res.maj_stat, res.min_stat);
				goto out;
			}

			maj_stat = gss_unwrap(&min_stat, client_context,
			    &res.output_token, &message_buf, NULL, NULL);
			if (GSS_ERROR(maj_stat)) {
				printf("gss_unwrap failed\n");
				report_error(mech_type, maj_stat, min_stat);
				goto out;
			}
			gss_release_buffer(&min_stat, &message_buf);

			args.step = 5;
			syscall(syscall_num, 2, &args, &res);

			gss_release_name(&min_stat, &name);
			gss_release_cred(&min_stat, &client_cred);
			gss_delete_sec_context(&min_stat, &client_context,
			    GSS_C_NO_BUFFER);
		}

		break;
	}
	case 3:
		syscall(syscall_num, 3, NULL, NULL);
		break;
	case 4:
		syscall(syscall_num, 4, NULL, NULL);
		break;
	}
	return (0);

out:
	return (1);
}
Example #21
0
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);
}
Example #22
0
bool_t
xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
			gss_ctx_id_t ctx, gss_qop_t qop,
			rpc_gss_service_t svc, u_int seq)
{
	XDR		tmpxdrs;
	gss_buffer_desc	databuf, wrapbuf;
	OM_uint32	maj_stat, min_stat;
	u_int		seq_num, conf_state, qop_state;
	bool_t		xdr_stat;

	if (xdr_func == (xdrproc_t) xdr_void || xdr_ptr == NULL)
		return (TRUE);
	
	memset(&databuf, 0, sizeof(databuf));
	memset(&wrapbuf, 0, sizeof(wrapbuf));
	
	if (svc == rpc_gss_svc_integrity) {
		/* Decode databody_integ. */
		if (!xdr_gss_buffer_desc(xdrs, &databuf)) {
			log_debug("xdr decode databody_integ failed");
			return (FALSE);
		}
		/* Decode checksum. */
		if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
			mem_free(databuf.value, databuf.length);
			log_debug("xdr decode checksum failed");
			return (FALSE);
		}
		/* Verify checksum and QOP. */
		maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
					  &wrapbuf, &qop_state);
		mem_free(wrapbuf.value, wrapbuf.length);
		
		if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
			mem_free(databuf.value, databuf.length);
			log_status("gss_verify_mic", NULL, maj_stat, min_stat);
			return (FALSE);
		}
	} else if (svc == rpc_gss_svc_privacy) {
		/* Decode databody_priv. */
		if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
			log_debug("xdr decode databody_priv failed");
			return (FALSE);
		}
		/* Decrypt databody. */
		maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
				      &conf_state, &qop_state);
		
		mem_free(wrapbuf.value, wrapbuf.length);
		
		/* Verify encryption and QOP. */
		if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
			conf_state != TRUE) {
			gss_release_buffer(&min_stat, &databuf);
			log_status("gss_unwrap", NULL, maj_stat, min_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);

	/*
	 * Integrity service allocates databuf via XDR so free it the
	 * same way.
	 */
	if (svc == rpc_gss_svc_integrity) {
		xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &databuf);
	} else {
		gss_release_buffer(&min_stat, &databuf);
	}
	
	/* Verify sequence number. */
	if (xdr_stat == TRUE && seq_num != seq) {
		log_debug("wrong sequence number in databody");
		return (FALSE);
	}
	return (xdr_stat);
}
Example #23
0
static OM_uint32
spnego_reply
           (OM_uint32 * minor_status,
	    const gssspnego_cred cred,
            gss_ctx_id_t * context_handle,
            const gss_name_t target_name,
            const gss_OID mech_type,
            OM_uint32 req_flags,
            OM_uint32 time_req,
            const gss_channel_bindings_t input_chan_bindings,
            const gss_buffer_t input_token,
            gss_OID * actual_mech_type,
            gss_buffer_t output_token,
            OM_uint32 * ret_flags,
            OM_uint32 * time_rec
    )
{
    OM_uint32 ret, minor;
    NegotiationToken resp;
    gss_OID_desc mech;
    int require_mic;
    size_t buf_len;
    gss_buffer_desc mic_buf, mech_buf;
    gss_buffer_desc mech_output_token;
    gssspnego_ctx ctx;

    *minor_status = 0;

    ctx = (gssspnego_ctx)*context_handle;

    output_token->length = 0;
    output_token->value  = NULL;

    mech_output_token.length = 0;
    mech_output_token.value = NULL;

    mech_buf.value = NULL;
    mech_buf.length = 0;

    ret = decode_NegotiationToken(input_token->value, input_token->length,
				  &resp, NULL);
    if (ret)
      return ret;

    if (resp.element != choice_NegotiationToken_negTokenResp) {
	free_NegotiationToken(&resp);
	*minor_status = 0;
	return GSS_S_BAD_MECH;
    }

    if (resp.u.negTokenResp.negResult == NULL
	|| *(resp.u.negTokenResp.negResult) == reject
	/* || resp.u.negTokenResp.supportedMech == NULL */
	)
    {
	free_NegotiationToken(&resp);
	return GSS_S_BAD_MECH;
    }

    /*
     * Pick up the mechanism that the acceptor selected, only allow it
     * to be sent in packet.
     */

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    if (resp.u.negTokenResp.supportedMech) {

	if (ctx->oidlen) {
	    free_NegotiationToken(&resp);
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    return GSS_S_BAD_MECH;
	}
	ret = der_put_oid(ctx->oidbuf + sizeof(ctx->oidbuf) - 1,
			  sizeof(ctx->oidbuf),
			  resp.u.negTokenResp.supportedMech,
			  &ctx->oidlen);
	/* Avoid recursively embedded SPNEGO */
	if (ret || (ctx->oidlen == GSS_SPNEGO_MECHANISM->length &&
		    memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen,
			   GSS_SPNEGO_MECHANISM->elements,
			   ctx->oidlen) == 0))
	{
	    free_NegotiationToken(&resp);
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    return GSS_S_BAD_MECH;
	}

	/* check if the acceptor took our optimistic token */
	if (ctx->oidlen != ctx->preferred_mech_type->length ||
	    memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen,
		   ctx->preferred_mech_type->elements,
		   ctx->oidlen) != 0)
	{
	    gss_delete_sec_context(&minor, &ctx->negotiated_ctx_id,
				   GSS_C_NO_BUFFER);
	    ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
	}
    } else if (ctx->oidlen == 0) {
	free_NegotiationToken(&resp);
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	return GSS_S_BAD_MECH;
    }

    /* if a token (of non zero length), or no context, pass to underlaying mech */
    if ((resp.u.negTokenResp.responseToken != NULL && resp.u.negTokenResp.responseToken->length) ||
	ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
	gss_buffer_desc mech_input_token;

	if (resp.u.negTokenResp.responseToken) {
	    mech_input_token.length = resp.u.negTokenResp.responseToken->length;
	    mech_input_token.value  = resp.u.negTokenResp.responseToken->data;
	} else {
	    mech_input_token.length = 0;
	    mech_input_token.value = NULL;
	}


	mech.length = ctx->oidlen;
	mech.elements = ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen;

	/* Fall through as if the negotiated mechanism
	   was requested explicitly */
	ret = gss_init_sec_context(&minor,
				   (cred != NULL) ? cred->negotiated_cred_id :
				       GSS_C_NO_CREDENTIAL,
				   &ctx->negotiated_ctx_id,
				   ctx->target_name,
				   &mech,
				   req_flags,
				   time_req,
				   input_chan_bindings,
				   &mech_input_token,
				   &ctx->negotiated_mech_type,
				   &mech_output_token,
				   &ctx->mech_flags,
				   &ctx->mech_time_rec);
	if (GSS_ERROR(ret)) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free_NegotiationToken(&resp);
	    gss_mg_collect_error(&mech, ret, minor);
	    *minor_status = minor;
	    return ret;
	}
	if (ret == GSS_S_COMPLETE) {
	    ctx->open = 1;
	}
    } else if (*(resp.u.negTokenResp.negResult) == accept_completed) {
	if (ctx->maybe_open)
	    ctx->open = 1;
    }

    if (*(resp.u.negTokenResp.negResult) == request_mic) {
	ctx->require_mic = 1;
    }

    if (ctx->open) {
	/*
	 * Verify the mechListMIC if one was provided or CFX was
	 * used and a non-preferred mechanism was selected
	 */
	if (resp.u.negTokenResp.mechListMIC != NULL) {
	    require_mic = 1;
	} else {
	    ret = _gss_spnego_require_mechlist_mic(minor_status, ctx,
						   &require_mic);
	    if (ret) {
		HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
		free_NegotiationToken(&resp);
		gss_release_buffer(&minor, &mech_output_token);
		return ret;
	    }
	}
    } else {
	require_mic = 0;
    }

    if (require_mic) {
	ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
			   &ctx->initiator_mech_types, &buf_len, ret);
	if (ret) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free_NegotiationToken(&resp);
	    gss_release_buffer(&minor, &mech_output_token);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	if (mech_buf.length != buf_len)
	    abort();

	if (resp.u.negTokenResp.mechListMIC == NULL) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free(mech_buf.value);
	    free_NegotiationToken(&resp);
	    *minor_status = 0;
	    return GSS_S_DEFECTIVE_TOKEN;
	}
	mic_buf.length = resp.u.negTokenResp.mechListMIC->length;
	mic_buf.value  = resp.u.negTokenResp.mechListMIC->data;

	if (mech_output_token.length == 0) {
	    ret = gss_verify_mic(minor_status,
				 ctx->negotiated_ctx_id,
				 &mech_buf,
				 &mic_buf,
				 NULL);
	   if (ret) {
		HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
		free(mech_buf.value);
		gss_release_buffer(&minor, &mech_output_token);
		free_NegotiationToken(&resp);
		return GSS_S_DEFECTIVE_TOKEN;
	    }
	    ctx->verified_mic = 1;
	}
    }

    ret = spnego_reply_internal(minor_status, ctx,
				require_mic ? &mech_buf : NULL,
				&mech_output_token,
				output_token);

    if (mech_buf.value != NULL)
	free(mech_buf.value);

    free_NegotiationToken(&resp);
    gss_release_buffer(&minor, &mech_output_token);

    if (actual_mech_type)
	*actual_mech_type = ctx->negotiated_mech_type;
    if (ret_flags)
	*ret_flags = ctx->mech_flags;
    if (time_rec)
	*time_rec = ctx->mech_time_rec;

    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    return ret;
}
Example #24
0
static bool_t
Svcauth_gss_validate(struct svc_req *rqst, struct svc_rpc_gss_data *gd,
                     struct rpc_msg *msg)
{
  struct opaque_auth *oa;
  gss_buffer_desc rpcbuf, checksum;
  OM_uint32 maj_stat, min_stat, qop_state;
  u_char rpchdr[128];
  int32_t *buf;
  char GssError[256];

  memset(rpchdr, 0, sizeof(rpchdr));

  /* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */
  oa = &msg->rm_call.cb_cred;

  LogFullDebug(COMPONENT_RPCSEC_GSS,
               "Call to Svcauth_gss_validate --> xid=%u dir=%u rpcvers=%u prog=%u vers=%u proc=%u flavor=%u len=%u base=%p ckeck.len=%u check.val=%p",
               msg->rm_xid,
               msg->rm_direction,
               msg->rm_call.cb_rpcvers,
               msg->rm_call.cb_prog,
               msg->rm_call.cb_vers,
               msg->rm_call.cb_proc,
               oa->oa_flavor,
               oa->oa_length,
               oa->oa_base,
               msg->rm_call.cb_verf.oa_length,
               msg->rm_call.cb_verf.oa_base);

  if(oa->oa_length > MAX_AUTH_BYTES)
    {
      LogCrit(COMPONENT_RPCSEC_GSS,
              "Svcauth_gss_validate oa->oa_length (%u) > MAX_AUTH_BYTES (%u)",
              oa->oa_length, MAX_AUTH_BYTES);
      return (FALSE);
    }
  
  /* 8 XDR units from the IXDR macro calls. */
  if(sizeof(rpchdr) < (8 * BYTES_PER_XDR_UNIT +
     RNDUP(oa->oa_length)))
    {
      LogCrit(COMPONENT_RPCSEC_GSS,
              "Svcauth_gss_validate sizeof(rpchdr) (%d) < (8 * BYTES_PER_XDR_UNIT (%d) + RNDUP(oa->oa_length (%u))) (%d)",
              (int) sizeof(rpchdr),
              (int) (8 * BYTES_PER_XDR_UNIT),
              oa->oa_length,
              (int) (8 * BYTES_PER_XDR_UNIT + RNDUP(oa->oa_length)));
      return (FALSE);
    }

  buf = (int32_t *) (void *)rpchdr;
  IXDR_PUT_LONG(buf, msg->rm_xid);
  IXDR_PUT_ENUM(buf, msg->rm_direction);
  IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers);
  IXDR_PUT_LONG(buf, msg->rm_call.cb_prog);
  IXDR_PUT_LONG(buf, msg->rm_call.cb_vers);
  IXDR_PUT_LONG(buf, msg->rm_call.cb_proc);
  IXDR_PUT_ENUM(buf, oa->oa_flavor);
  IXDR_PUT_LONG(buf, oa->oa_length);
  if(oa->oa_length)
    {
      memcpy((caddr_t) buf, oa->oa_base, oa->oa_length);
      buf += RNDUP(oa->oa_length) / sizeof(int32_t);
    }
  rpcbuf.value = rpchdr;
  rpcbuf.length = (u_char *) buf - rpchdr;

  checksum.value = msg->rm_call.cb_verf.oa_base;
  checksum.length = msg->rm_call.cb_verf.oa_length;

  if(isFullDebug(COMPONENT_RPCSEC_GSS))
    {
      char ctx_str[64];
      sprint_ctx(ctx_str, (unsigned char *)gd->ctx, sizeof(gss_union_ctx_id_desc));
      LogFullDebug(COMPONENT_RPCSEC_GSS,
                   "Svcauth_gss_validate context %s rpcbuf=%p:%u checksum=%p:$%u)",
                   ctx_str, rpcbuf.value, (unsigned int) rpcbuf.length,
                   checksum.value, (unsigned int) checksum.length);
    }

  maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum, &qop_state);

  if(maj_stat != GSS_S_COMPLETE)
    {
      log_sperror_gss(GssError, maj_stat, min_stat);
      LogCrit(COMPONENT_RPCSEC_GSS, "Error in gss_verify_mic: %s", GssError);
      return (FALSE);
    }
  return (TRUE);
}