Esempio n. 1
0
static void
wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
{
    gss_buffer_desc input_token, output_token, output_token2;
    OM_uint32 min_stat, maj_stat;
    gss_qop_t qop_state;
    int conf_state;

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

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

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

    gss_release_buffer(&min_stat, &output_token);
    gss_release_buffer(&min_stat, &output_token2);

#if 0 /* doesn't work for NTLM yet */
    if (!!conf_state != !!flags)
	errx(1, "conf_state mismatch");
#endif
}
Esempio n. 2
0
File: cssp.c Progetto: jeppeter/vbox
static RD_BOOL
cssp_gss_unwrap(gss_ctx_id_t * ctx, STREAM in, STREAM out)
{
	OM_uint32 major_status;
	OM_uint32 minor_status;
	gss_qop_t qop_state;
	gss_buffer_desc inbuf, outbuf;
	int conf_state;

	inbuf.value = in->data;
	inbuf.length = s_length(in);

	major_status = gss_unwrap(&minor_status, ctx, &inbuf, &outbuf, &conf_state, &qop_state);

	if (major_status != GSS_S_COMPLETE)
	{
		cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to decrypt message",
				      major_status, minor_status);
		return False;
	}

	out->data = out->p = xmalloc(outbuf.length);
	out->size = outbuf.length;
	out_uint8p(out, outbuf.value, outbuf.length);
	s_mark_end(out);

	gss_release_buffer(&minor_status, &outbuf);

	return True;
}
Esempio n. 3
0
static int
gss_decode(void *app_data, void *buf, int len, int level)
{
    OM_uint32 maj_stat, min_stat;
    gss_buffer_desc input, output;
    gss_qop_t qop_state;
    int conf_state;
    struct gss_data *d = app_data;
    size_t ret_len;

    input.length = len;
    input.value = buf;
    maj_stat = gss_unwrap (&min_stat,
			   d->context_hdl,
			   &input,
			   &output,
			   &conf_state,
			   &qop_state);
    if(GSS_ERROR(maj_stat))
	return -1;
    memmove(buf, output.value, output.length);
    ret_len = output.length;
    gss_release_buffer(&min_stat, &output);
    return ret_len;
}
Esempio n. 4
0
int Condor_Auth_X509 :: unwrap(char*  data_in, 
                               int    length_in, 
                               char*& data_out, 
                               int&   length_out)
{
    OM_uint32 major_status;
    OM_uint32 minor_status;
    
    gss_buffer_desc input_token_desc  = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    input_token       = &input_token_desc;
    gss_buffer_desc output_token_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t    output_token      = &output_token_desc;
    
    if (!isValid()) {
        return FALSE;
    }
    
    input_token -> value = (void *)data_in;
    input_token -> length = length_in;
    
    major_status = gss_unwrap(&minor_status,
                              context_handle,
                              input_token,
                              output_token,
                              NULL,
                              NULL);
    
    
    data_out = (char*)output_token -> value;
    length_out = output_token -> length;

	// return TRUE on success
    return (major_status == GSS_S_COMPLETE);
}
Esempio n. 5
0
OM_uint32 GSSAPI_CALLCONV _gss_spnego_unwrap
           (OM_uint32 * minor_status,
            gss_const_ctx_id_t context_handle,
            const gss_buffer_t input_message_buffer,
            gss_buffer_t output_message_buffer,
            int * conf_state,
            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_unwrap(minor_status,
		      ctx->negotiated_ctx_id,
		      input_message_buffer,
		      output_message_buffer,
		      conf_state,
		      qop_state);
}
Esempio n. 6
0
gss_client_response *authenticate_gss_client_unwrap(gss_client_state *state, const char *challenge) {
  OM_uint32 maj_stat;
  OM_uint32 min_stat;
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  gss_client_response *response = NULL;
  int ret = AUTH_GSS_CONTINUE;
    
  // Always clear out the old response
  if(state->response != NULL) {
    free(state->response);
    state->response = NULL;
  }
    
  // If there is a challenge (data from the server) we need to give it to GSS
  if(challenge && *challenge) {
    int len;
    input_token.value = base64_decode(challenge, &len);
    input_token.length = len;
  }
    
  // Do GSSAPI step
  maj_stat = gss_unwrap(&min_stat,
                          state->context,
                          &input_token,
                          &output_token,
                          NULL,
                          NULL);
    
  if(maj_stat != GSS_S_COMPLETE) {
    response = gss_error(__func__, "gss_unwrap", maj_stat, min_stat);
    response->return_code = AUTH_GSS_ERROR;
    goto end;
  } else {
    ret = AUTH_GSS_COMPLETE;    
  }
    
  // Grab the client response
  if(output_token.length) {
    state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);
    gss_release_buffer(&min_stat, &output_token);
  }
end:
  if(output_token.value)
    gss_release_buffer(&min_stat, &output_token);
  if(input_token.value)
    free(input_token.value);

  if(response == NULL) {
    response = calloc(1, sizeof(gss_client_response));
    if(response == NULL) die1("Memory allocation failed");
    response->return_code = ret;
  }

  // Return the response
  return response;
}
Esempio n. 7
0
static int unwrap(char *buf, int index, ei_x_buff *presult)
{
    ei_x_buff result = *presult;

    /*
      {unwrap, {Idx, Input}} -> {ok, {conf_state, Output}}
    */

    int arity;
    gss_buffer_desc in;
    gss_buffer_desc out;
    long idx;
    int conf_state;
    OM_uint32 maj_stat, min_stat;
    gss_qop_t qop;
	
    memset(&in, 0, sizeof(in));
    memset(&out, 0, sizeof(out));

    EI(ei_decode_tuple_header(buf, &index, &arity));
    
    EI(arity != 2);

    EI(ei_decode_long(buf, &index, &idx));

    EI(decode_gssapi_binary(buf, &index, &in));

    if (idx < 0 || idx >= MAX_SESSIONS || !g_sessions[idx])
	ENCODE_ERROR("bad_instance");

    maj_stat = gss_unwrap(&min_stat, g_sessions[idx],
			  &in, &out, &conf_state, &qop);

    if (!GSS_ERROR(maj_stat)) {
	const char *conf_str = conf_state ? "true":"false";

	EI(ei_x_encode_atom(&result, "ok") ||
	   ei_x_encode_tuple_header(&result, 2) ||
	   ei_x_encode_atom(&result, conf_str) ||
	   ei_x_encode_binary(&result, out.value, out.length)
	    );

    } else {
	EI(ei_x_encode_atom(&result, "error") || ei_x_encode_long(&result, maj_stat));
    }

error:
    if (in.value)
	gss_release_buffer(&min_stat, &in);

    if (out.value)
	gss_release_buffer(&min_stat, &out);

    *presult = result;
    return 0;
}
Esempio n. 8
0
int authenticate_gss_client_unwrap(gss_client_state *state, const char *challenge)
{
	OM_uint32 maj_stat;
	OM_uint32 min_stat;
	gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
	gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
	int ret = AUTH_GSS_CONTINUE;
    int conf = 0;
    
	// Always clear out the old response
	if (state->response != NULL)
	{
		free(state->response);
		state->response = NULL;
        state->responseConf = 0;
	}
    
	// If there is a challenge (data from the server) we need to give it to GSS
	if (challenge && *challenge)
	{
		size_t len;
		input_token.value = base64_decode(challenge, &len);
		input_token.length = len;
	}
    
	// Do GSSAPI step
	maj_stat = gss_unwrap(&min_stat,
                          state->context,
                          &input_token,
                          &output_token,
                          &conf,
                          NULL);
    
	if (maj_stat != GSS_S_COMPLETE)
	{
		set_gss_error(maj_stat, min_stat);
		ret = AUTH_GSS_ERROR;
		goto end;
	}
	else
		ret = AUTH_GSS_COMPLETE;
    
	// Grab the client response
	if (output_token.length)
	{
		state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);
        state->responseConf = conf;
		maj_stat = gss_release_buffer(&min_stat, &output_token);
	}
end:
	if (output_token.value)
		gss_release_buffer(&min_stat, &output_token);
	if (input_token.value)
		free(input_token.value);
	return ret;
}
Esempio n. 9
0
static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
{
	gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
	OM_uint32 ret = 0;
	OM_uint32 minor = 0;
	int flags_got = 0;
	gss_buffer_desc in_buf, out_buf;
	size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */

	if (buf_len < 8) {
		return NT_STATUS_BUFFER_TOO_SMALL;
	}

	in_buf.value = buf + 8;
	in_buf.length = buf_len - 8;

	ret = gss_unwrap(&minor,
			gss_ctx,
			&in_buf,
			&out_buf,
			&flags_got,		/* did we get sign+seal ? */
			(gss_qop_t *) NULL);

	if (ret != GSS_S_COMPLETE) {
		NTSTATUS status = NT_STATUS_ACCESS_DENIED;
		char *gss_err;

		gss_err = gssapi_error_string(talloc_tos(),
					      ret, minor,
					      GSS_C_NULL_OID);
		DEBUG(0,("common_gss_decrypt_buffer: gss_unwrap failed. "
			 "Error [%d/%d] - %s - %s\n",
			 ret, minor, nt_errstr(status),
			 gss_err ? gss_err : "<unknown>"));
		talloc_free(gss_err);

		return status;
	}

	if (out_buf.length > in_buf.length) {
		DEBUG(0,("common_gss_decrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
			(unsigned int)out_buf.length,
			(unsigned int)in_buf.length ));
		gss_release_buffer(&minor, &out_buf);
		return NT_STATUS_INVALID_PARAMETER;
	}

	memcpy(buf + 8, out_buf.value, out_buf.length);
	/* Reset the length and overwrite the header. */
	smb_setlen_nbt(buf, out_buf.length + 4);

	gss_release_buffer(&minor, &out_buf);
	return NT_STATUS_OK;
}
Esempio n. 10
0
uint32_t
sapgss_unwrap(
    uint32_t *minor_status,
    gss_ctx_id_t context_handle,
    gss_buffer_t input_message_buffer,
    gss_buffer_t output_message_buffer,
    int *conf_state,
    gss_qop_t *qop_state)
{
    return gss_unwrap(minor_status, context_handle, input_message_buffer,
		      output_message_buffer, conf_state, qop_state);
}
Esempio n. 11
0
int
_gsasl_gssapi_client_decode (Gsasl_session * sctx,
			     void *mech_data,
			     const char *input, size_t input_len,
			     char **output, size_t * output_len)
{
  _Gsasl_gssapi_client_state *state = mech_data;
  OM_uint32 min_stat, maj_stat;
  gss_buffer_desc foo;
  gss_buffer_t input_message_buffer = &foo;
  gss_buffer_desc output_message_buffer;

  foo.length = input_len;
  foo.value = (void *) input;

  if (state && state->step == 3 &&
      state->qop & (GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
    {
      maj_stat = gss_unwrap (&min_stat,
			     state->context,
			     input_message_buffer,
			     &output_message_buffer, NULL, NULL);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_UNWRAP_ERROR;
      *output_len = output_message_buffer.length;
      *output = malloc (input_len);
      if (!*output)
	{
	  maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
	  return GSASL_MALLOC_ERROR;
	}
      memcpy (*output, output_message_buffer.value,
	      output_message_buffer.length);

      maj_stat = gss_release_buffer (&min_stat, &output_message_buffer);
      if (GSS_ERROR (maj_stat))
	{
	  free (*output);
	  return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
	}
    }
  else
    {
      *output_len = input_len;
      *output = malloc (input_len);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      memcpy (*output, input, input_len);
    }

  return GSASL_OK;
}
Esempio n. 12
0
OM_uint32 GSSAPI_LIB_FUNCTION
gss_unseal(OM_uint32 *minor_status,
    gss_ctx_id_t context_handle,
    gss_buffer_t input_message_buffer,
    gss_buffer_t output_message_buffer,
    int *conf_state,
    int *qop_state)
{

	return (gss_unwrap(minor_status,
		    context_handle, input_message_buffer,
		    output_message_buffer, conf_state, (gss_qop_t *)qop_state));
}
Esempio n. 13
0
static int
HandleOP(Unwrap)
{
    OM_uint32 maj_stat, min_stat;
    int32_t hContext, flags, seqno;
    krb5_data token;
    gss_ctx_id_t ctx;
    gss_buffer_desc input_token, output_token;
    int conf_state;
    gss_qop_t qop_state;

    ret32(c, hContext);
    ret32(c, flags);
    ret32(c, seqno);
    retdata(c, token);

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

    input_token.length = token.length;
    input_token.value = token.data;

    maj_stat = gss_unwrap(&min_stat, ctx, &input_token,
			  &output_token, &conf_state, &qop_state);

    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);

    krb5_data_free(&token);
    if (maj_stat == GSS_S_COMPLETE) {
	token.data = output_token.value;
	token.length = output_token.length;
    } else {
	token.data = NULL;
	token.length = 0;
    }
    put32(c, 0); /* XXX fix gsm_error */
    putdata(c, token);

    if (maj_stat == GSS_S_COMPLETE)
	gss_release_buffer(&min_stat, &output_token);

    return 0;
}
Esempio n. 14
0
vchar_t *
gssapi_unwraphash(struct ph1handle *iph1)
{
	struct gssapi_ph1_state *gps;
	OM_uint32 maj_stat, min_stat;
	gss_buffer_desc hashbuf, hash_outbuf;
	gss_buffer_t hash_in = &hashbuf, hash_out = &hash_outbuf;
	vchar_t *outbuf;

	gps = gssapi_get_state(iph1);
	if (gps == NULL) {
		plog(LLV_ERROR, LOCATION, NULL,
		    "gssapi not yet initialized?\n");
		return NULL;
	}


	hashbuf.length = ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash);
	hashbuf.value = (char *)(iph1->pl_hash + 1);

	plog(LLV_DEBUG, LOCATION, NULL, "unwrapping HASH of len %d\n",
	    hashbuf.length);

	maj_stat = gss_unwrap(&min_stat, gps->gss_context, hash_in, hash_out,
	    NULL, NULL);
	if (GSS_ERROR(maj_stat)) {
		gssapi_error(min_stat, LOCATION, "unwrapping hash value\n");
		return NULL;
	}

	if (gssapi_gss2vmbuf(hash_out, &outbuf) < 0) {
		plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n");
		maj_stat = gss_release_buffer(&min_stat, hash_out);
		if (GSS_ERROR(maj_stat))
			gssapi_error(min_stat, LOCATION,
			    "release hash_out buffer\n");
		return NULL;
	}
	maj_stat = gss_release_buffer(&min_stat, hash_out);
	if (GSS_ERROR(maj_stat))
		gssapi_error(min_stat, LOCATION, "release hash_out buffer\n");

	return outbuf;
}
Esempio n. 15
0
OM_uint32
ntlm_gss_unwrap(
		OM_uint32 *minor_status,
		gss_ctx_id_t context_handle,
		gss_buffer_t input_message_buffer,
		gss_buffer_t output_message_buffer,
		int *conf_state,
		gss_qop_t *qop_state)
{
	OM_uint32 ret;
	ret = gss_unwrap(minor_status,
			context_handle,
			input_message_buffer,
			output_message_buffer,
			conf_state,
			qop_state);

	return (ret);
}
Esempio n. 16
0
static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, 
				     TALLOC_CTX *mem_ctx, 
				     const DATA_BLOB *in, 
				     DATA_BLOB *out)
{
	struct gensec_gssapi_state *gensec_gssapi_state
		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
	OM_uint32 maj_stat, min_stat;
	gss_buffer_desc input_token, output_token;
	int conf_state;
	gss_qop_t qop_state;
	input_token.length = in->length;
	input_token.value = in->data;
	
	if (gensec_gssapi_state->sasl) {
		size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
		if (max_wrapped_size < in->length) {
			DEBUG(1, ("gensec_gssapi_unwrap: WRAPPED data is larger than SASL negotiated maximum size\n"));
			return NT_STATUS_INVALID_PARAMETER;
		}
	}
	
	maj_stat = gss_unwrap(&min_stat, 
			      gensec_gssapi_state->gssapi_context, 
			      &input_token,
			      &output_token, 
			      &conf_state,
			      &qop_state);
	if (GSS_ERROR(maj_stat)) {
		DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n", 
			  gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
		return NT_STATUS_ACCESS_DENIED;
	}

	*out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
	gss_release_buffer(&min_stat, &output_token);
	
	if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
	    && !conf_state) {
		return NT_STATUS_ACCESS_DENIED;
	}
	return NT_STATUS_OK;
}
Esempio n. 17
0
static ADS_STATUS ads_sasl_gssapi_unwrap(struct ads_saslwrap *wrap)
{
	gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
	ADS_STATUS status;
	int gss_rc;
	uint32_t minor_status;
	gss_buffer_desc unwrapped, wrapped;
	int conf_state;

	wrapped.value	= wrap->in.buf + 4;
	wrapped.length	= wrap->in.ofs - 4;

	gss_rc = gss_unwrap(&minor_status, context_handle,
			    &wrapped, &unwrapped,
			    &conf_state, GSS_C_QOP_DEFAULT);
	status = ADS_ERROR_GSS(gss_rc, minor_status);
	if (!ADS_ERR_OK(status)) return status;

	if (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
		return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
	}

	if (wrapped.length < unwrapped.length) {
		return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
	}

	/* copy the wrapped blob to the right location */
	memcpy(wrap->in.buf + 4, unwrapped.value, unwrapped.length);

	/* set how many bytes must be written to the underlying socket */
	wrap->in.left	= unwrapped.length;
	wrap->in.ofs	= 4;

	gss_release_buffer(&minor_status, &unwrapped);

	return ADS_SUCCESS;
}
Esempio n. 18
0
int
receive_proxy(char **s, gss_ctx_id_t gss_context, int sck)
{
	char             *buf;
	int              return_status = BPR_RECEIVE_PROXY_ERROR;
	gss_buffer_desc  input_token;
	gss_buffer_desc  output_token;
	OM_uint32        maj_stat, min_stat;

	if (!(gss_context == GSS_C_NO_CONTEXT || get_token(&sck, &input_token.value, &input_token.length) != 0)) 
	{
		maj_stat = gss_unwrap(
				&min_stat,
				gss_context,
				&input_token,
				&output_token,
				NULL,
				NULL);

		if (!GSS_ERROR(maj_stat))
		{
			if ((buf = (char *)malloc(output_token.length + 1)) == NULL)
			{
				fprintf(stderr, "Error allocating buffer...\n");
				return(return_status);
			}
			memcpy(buf, output_token.value, output_token.length);
			buf[output_token.length] = 0;
			*s = buf;
			return_status = BPR_RECEIVE_PROXY_OK;
		}
		gss_release_buffer(&min_stat, &output_token);
		gss_release_buffer(&min_stat, &input_token);
	}
	return return_status;
}
Esempio n. 19
0
static int tunnel(struct gt_service *svc, int fd, struct sockaddr *cliaddr)
{
    AUTOCLEAN(char *tmbuf, autofreestr) = NULL;
    AUTOCLEAN(struct addrinfo *addr, autofreeaddrinfo) = NULL;
    AUTOCLEAN(int sd, autofreesocket) = -1;
    AUTOCLEAN(int efd, autofreesocket) = -1;
    AUTOCLEAN(gss_name_t name, autofreegssname) = GSS_C_NO_NAME;
    AUTOCLEAN(gss_name_t srcname, autofreegssname) = GSS_C_NO_NAME;
    AUTOCLEAN(gss_cred_id_t cred, autofreegsscred) = GSS_C_NO_CREDENTIAL;
    AUTOCLEAN(gss_ctx_id_t ctx, autofreegssctx) = GSS_C_NO_CONTEXT;
    AUTOCLEAN(gss_buffer_desc output, autofreegssbuf) = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc  namebuf;
    OM_uint32 maj, min;
    OM_uint32 ignore;
    struct epoll_event events[MAX_EVENTS];
    size_t tmlen;
    int pfd; /* plain text fd */
    int cfd; /* cipher text fd */
    int ret;

    /* We allocate a 1 MiB buffer for messages, that's also the maximum msg
     * size */
    tmbuf = malloc(MAX_MSG_SIZE);
    if (!tmbuf) return ENOMEM;

    if (svc->exec) {
        fprintf(stderr, "[%s] EXEC option not supported yet, sorry!\n",
                        svc->name);
        return ENOTSUP;
    }

    ret = string_to_addrinfo(svc->connect, &addr);
    if (ret) return ret;

    errno = 0;
    sd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    if (sd == -1) return errno;

    ret = connect(sd, addr->ai_addr, addr->ai_addrlen);
    if (ret != 0) {
        ret = errno;
        fprintf(stderr, "[%s] Failed to connect to server '%s': %s\n",
                        svc->name, svc->connect, strerror(ret));
        return ret;
    }

    if (svc->target_name) {
        namebuf.length = strlen(svc->target_name);
        namebuf.value = svc->target_name;
        maj = gss_import_name(&min, &namebuf,
                              GSS_C_NT_HOSTBASED_SERVICE, &name);
        if (maj != GSS_S_COMPLETE) {
            fprintf(stderr, "[%s] Failed to import name: '%s' (%d/%d)\n",
                            svc->name, svc->target_name,
                            (int)maj, (int)min);
            return EINVAL;
        }
    }

    if (svc->client) {
        pfd = fd;
        cfd = sd;

        do {
            maj = gss_init_sec_context(&min, cred, &ctx, name, GSS_C_NO_OID,
                                       GSS_C_MUTUAL_FLAG
                                        | GSS_C_REPLAY_FLAG
                                        | GSS_C_SEQUENCE_FLAG
                                        | GSS_C_CONF_FLAG
                                        | GSS_C_INTEG_FLAG, 0,
                                       GSS_C_NO_CHANNEL_BINDINGS,
                                       &input, NULL, &output, NULL, NULL);

            if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
                gt_gss_error(svc->name, GSS_C_NO_OID, maj, min);
                return EBADE;
            }

            if (output.length > MAX_MSG_SIZE) return ENOSPC;
            if (output.length > 0) {
                memcpy(tmbuf, output.value, output.length);
                tmlen = output.length;
                (void)gss_release_buffer(&ignore, &output);

                ret = send_msg(cfd, tmbuf, tmlen, true);
                if (ret) return ret;
            }

            if (maj == GSS_S_CONTINUE_NEEDED) {
                tmlen = MAX_MSG_SIZE;
                ret = recv_msg(cfd, tmbuf, &tmlen, true);
                if (ret) return ret;

                input.value = tmbuf;
                input.length = tmlen;
            }

        } while (maj == GSS_S_CONTINUE_NEEDED);

    } else {
        pfd = sd;
        cfd = fd;

        if (name != GSS_C_NO_NAME) {
            maj = gss_acquire_cred(&min, name, GSS_C_INDEFINITE,
                                   GSS_C_NO_OID_SET, GSS_C_ACCEPT,
                                   &cred, NULL, NULL);
            if (maj != GSS_S_COMPLETE) {
                fprintf(stderr,
                        "[%s] Failed to acquire creds for '%s' (%d/%d)\n",
                        svc->name, svc->target_name?svc->target_name:"",
                        (int)maj, (int)min);
                return EIO;
            }
        }

        do {
            tmlen = MAX_MSG_SIZE;
            ret = recv_msg(cfd, tmbuf, &tmlen, true);
            if (ret) return ret;

            input.value = tmbuf;
            input.length = tmlen;

            maj = gss_accept_sec_context(&min, &ctx, cred, &input,
                                         GSS_C_NO_CHANNEL_BINDINGS, &srcname,
                                         NULL, &output, NULL, NULL, NULL);

            if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
                gt_gss_error(svc->name, GSS_C_NO_OID, maj, min);
                return EBADE;
            }

            if (output.length > MAX_MSG_SIZE) return ENOSPC;
            if (output.length > 0) {
                memcpy(tmbuf, output.value, output.length);
                tmlen = output.length;
                (void)gss_release_buffer(&ignore, &output);

                ret = send_msg(cfd, tmbuf, tmlen, true);
                if (ret) return ret;
            }

        } while (maj == GSS_S_CONTINUE_NEEDED);
    }

    /* negotiation completed, now handle traffic */

    ret = init_epoll(cfd, pfd, &efd);
    if (ret) return ret;

    while (efd != -1) {
        struct epoll_event *ev;
        int n;
        n = epoll_wait(efd, events, MAX_EVENTS, -1);
        if (n == -1) {
            ret = errno;
            if (ret == EINTR) continue;
            return ret;
        }
        for (int i = 0; i < n; i++) {
            ev = &events[i];
            if (ev->events & (EPOLLERR|EPOLLHUP)) {
                /* one of the peers gave up */
                return ENOLINK;
            }

            /* RECEIVE */

            tmlen = MAX_MSG_SIZE;
            ret = recv_msg(ev->data.fd, tmbuf, &tmlen, (ev->data.fd == cfd));
            if (ret) return ret;

            if (ev->data.fd == cfd) {
                /* sender encrypts */
                input.value = tmbuf;
                input.length = tmlen;
                maj = gss_unwrap(&min, ctx, &input, &output, NULL, NULL);
                if (maj != GSS_S_COMPLETE) {
                    gt_gss_error(svc->name, GSS_C_NO_OID, maj, min);
                    return EIO;
                }
                if (output.length > MAX_MSG_SIZE) return ENOSPC;
                memcpy(tmbuf, output.value, output.length);
                tmlen = output.length;
                (void)gss_release_buffer(&ignore, &output);
            }

            /* RESEND */
            if (ev->data.fd == pfd) {
                /* receiver encrypts */
                input.value = tmbuf;
                input.length = tmlen;
                maj = gss_wrap(&min, ctx, 1, 0, &input, NULL, &output);
                if (maj != GSS_S_COMPLETE) {
                    gt_gss_error(svc->name, GSS_C_NO_OID, maj, min);
                    return EIO;
                }
                if (output.length > MAX_MSG_SIZE) return ENOSPC;
                memcpy(tmbuf, output.value, output.length);
                tmlen = output.length;
                (void)gss_release_buffer(&ignore, &output);
            }

            /* send to the other fd, add header only if we encrypted */
            ret = send_msg((ev->data.fd == pfd)?cfd:pfd,
                           tmbuf, tmlen, (ev->data.fd == pfd));
            if (ret) return ret;
        }
    }

    return 0;
}
Esempio n. 20
0
/* this performs a SASL/gssapi bind
   we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
   is very dependent on correctly configured DNS whereas
   this routine is much less fragile
   see RFC2078 and RFC2222 for details
*/
static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
{
	uint32_t minor_status;
	gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
	gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
	gss_OID mech_type = GSS_C_NULL_OID;
	gss_buffer_desc output_token, input_token;
	uint32_t req_flags, ret_flags;
	int conf_state;
	struct berval cred;
	struct berval *scred = NULL;
	int i=0;
	int gss_rc, rc;
	uint8_t *p;
	uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
	uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
	ADS_STATUS status;
	struct ads_saslwrap *wrap = &ads->ldap_wrap_data;

	input_token.value = NULL;
	input_token.length = 0;

	status = ads_init_gssapi_cred(ads, &gss_cred);
	if (!ADS_ERR_OK(status)) {
		goto failed;
	}

	/*
	 * Note: here we always ask the gssapi for sign and seal
	 *       as this is negotiated later after the mutal
	 *       authentication
	 */
	req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;

	for (i=0; i < MAX_GSS_PASSES; i++) {
		gss_rc = gss_init_sec_context(&minor_status,
					  gss_cred,
					  &context_handle,
					  serv_name,
					  mech_type,
					  req_flags,
					  0,
					  NULL,
					  &input_token,
					  NULL,
					  &output_token,
					  &ret_flags,
					  NULL);
		if (scred) {
			ber_bvfree(scred);
			scred = NULL;
		}
		if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
			status = ADS_ERROR_GSS(gss_rc, minor_status);
			goto failed;
		}

		cred.bv_val = (char *)output_token.value;
		cred.bv_len = output_token.length;

		rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
				      &scred);
		if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
			status = ADS_ERROR(rc);
			goto failed;
		}

		if (output_token.value) {
			gss_release_buffer(&minor_status, &output_token);
		}

		if (scred) {
			input_token.value = scred->bv_val;
			input_token.length = scred->bv_len;
		} else {
			input_token.value = NULL;
			input_token.length = 0;
		}

		if (gss_rc == 0) break;
	}

	gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
			    &conf_state,NULL);
	if (scred) {
		ber_bvfree(scred);
		scred = NULL;
	}
	if (gss_rc) {
		status = ADS_ERROR_GSS(gss_rc, minor_status);
		goto failed;
	}

	p = (uint8_t *)output_token.value;

#if 0
	file_save("sasl_gssapi.dat", output_token.value, output_token.length);
#endif

	if (p) {
		wrap_type = CVAL(p,0);
		SCVAL(p,0,0);
		max_msg_size = RIVAL(p,0);
	}

	gss_release_buffer(&minor_status, &output_token);

	if (!(wrap_type & wrap->wrap_type)) {
		/*
		 * the server doesn't supports the wrap
		 * type we want :-(
		 */
		DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
			wrap->wrap_type, wrap_type));
		DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
		status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
		goto failed;
	}

	/* 0x58 is the minimum windows accepts */
	if (max_msg_size < 0x58) {
		max_msg_size = 0x58;
	}

	output_token.length = 4;
	output_token.value = SMB_MALLOC(output_token.length);
	if (!output_token.value) {
		output_token.length = 0;
		status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
		goto failed;
	}
	p = (uint8_t *)output_token.value;

	RSIVAL(p,0,max_msg_size);
	SCVAL(p,0,wrap->wrap_type);

	/*
	 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
	 * but using ads->config.bind_path is the wrong! It should be
	 * the DN of the user object!
	 *
	 * w2k3 gives an error when we send an incorrect DN, but sending nothing
	 * is ok and matches the information flow used in GSS-SPNEGO.
	 */

	gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
			&output_token, /* used as *input* here. */
			&conf_state,
			&input_token); /* Used as *output* here. */
	if (gss_rc) {
		status = ADS_ERROR_GSS(gss_rc, minor_status);
		output_token.length = 0;
		SAFE_FREE(output_token.value);
		goto failed;
	}

	/* We've finished with output_token. */
	SAFE_FREE(output_token.value);
	output_token.length = 0;

	cred.bv_val = (char *)input_token.value;
	cred.bv_len = input_token.length;

	rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
			      &scred);
	gss_release_buffer(&minor_status, &input_token);
	status = ADS_ERROR(rc);
	if (!ADS_ERR_OK(status)) {
		goto failed;
	}

	if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
		gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
					     (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL),
					     GSS_C_QOP_DEFAULT,
					     max_msg_size, &wrap->out.max_unwrapped);
		if (gss_rc) {
			status = ADS_ERROR_GSS(gss_rc, minor_status);
			goto failed;
		}

		wrap->out.sig_size = max_msg_size - wrap->out.max_unwrapped;
		wrap->in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
		wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
		status = ads_setup_sasl_wrapping(wrap->wrap_private_data, ads->ldap.ld,
						 &ads_sasl_gssapi_ops,
						 context_handle);
		if (!ADS_ERR_OK(status)) {
			DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
				ads_errstr(status)));
			goto failed;
		}
		/* make sure we don't free context_handle */
		context_handle = GSS_C_NO_CONTEXT;
	}

failed:
	if (gss_cred != GSS_C_NO_CREDENTIAL)
		gss_release_cred(&minor_status, &gss_cred);
	if (context_handle != GSS_C_NO_CONTEXT)
		gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);

	if(scred)
		ber_bvfree(scred);
	return status;
}
Esempio n. 21
0
int ReadEncryptedToken (int                  inSocket, 
                        const gss_ctx_id_t   inContext, 
                        char               **outTokenValue, 
                        size_t              *outTokenLength)
{
    int err = 0;
    char *token = NULL;
    size_t tokenLength = 0;
    OM_uint32 majorStatus;
    OM_uint32 minorStatus = 0;
    gss_buffer_desc outputBuffer = { 0 , NULL};
    char *unencryptedToken = NULL;
    
    if (!inContext     ) { err = EINVAL; }
    if (!outTokenValue ) { err = EINVAL; }
    if (!outTokenLength) { err = EINVAL; }
    
    if (!err) {
        err = ReadToken (inSocket, &token, &tokenLength);
    }
    
    if (!err) {
        gss_buffer_desc inputBuffer = { tokenLength, token};
        int encrypted = 0; /* did mechanism encrypt/integrity protect? */

        majorStatus = gss_unwrap (&minorStatus, 
                                  inContext, 
                                  &inputBuffer, 
                                  &outputBuffer, 
                                  &encrypted, 
                                  NULL /* qop_state */);
        if (majorStatus != GSS_S_COMPLETE) { 
            printGSSErrors ("gss_unwrap", majorStatus, minorStatus);
            err = minorStatus ? minorStatus : majorStatus; 
        } else if (!encrypted) {
            fprintf (stderr, "WARNING!  Mechanism not using encryption!");
            err = EAUTH; /* You may not want to fail here. */
        }
    }
    
    if (!err) {
        unencryptedToken = malloc (outputBuffer.length);
        if (unencryptedToken == NULL) { err = ENOMEM; }
    }
    
    if (!err) {
        memcpy (unencryptedToken, outputBuffer.value, outputBuffer.length);
        
        printf ("Unencrypted token:\n");
        PrintBuffer (unencryptedToken, outputBuffer.length);
        
	*outTokenLength = outputBuffer.length;
        *outTokenValue = unencryptedToken;
        unencryptedToken = NULL; /* only free on error */
        
    } else { 
        printError (err, "ReadToken failed"); 
    }
    
    if (token             ) { free (token); }
    if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
    if (unencryptedToken  ) { free (unencryptedToken); }
    
    return err;
}
Esempio n. 22
0
/**
 * Recv response data from an XACML server
 * @ingroup xacml_io_gssapi
 *
 * @param arg
 *     Pointer to the #example_gss_state_t returned from example_gss_connect()
 * @param data
 *     Buffer to hold data returned from the server.
 * @param size
 *     Size of the @a data array.
 *
 * @return Number of bytes read into @a data.
 */
static
size_t
example_gss_recv(
    void                               *arg,
    char                               *data,
    size_t                              size)
{
    example_gss_state_t                *state = arg;
    size_t                              r;
    OM_uint32                           maj_stat, min_stat;
    gss_buffer_desc                     input;
    gss_buffer_desc                     output;

    /* Copy any previously-read data into the data buffer */
    if (state->buffer.length > 0)
    {
        r = state->buffer.length > size ? size : state->buffer.length;
        memcpy(data, state->buffer.value, r);
        
        if (state->buffer.length != r)
        {
            /* If there's still some in our buffer, return what we've copied
             * only
             */
            memmove(state->buffer.value, 
                    ((char *) state->buffer.value)+r, 
                    state->buffer.length - r);
            state->buffer.length -= r;

            return r;
        }
        else
        {
            free(state->buffer.value);
            state->buffer.length = 0;
        }
    }
    /* Read new data from the network and unwrap it */
    r = recv(state->socket, data, size, 0);
    if (r <= 0)
    {
        return 0;
    }

    input.value = data;
    input.length = r;

    output.value = NULL;
    output.length = 0;

    maj_stat = gss_unwrap(&min_stat, state->ctx, &input, &output, NULL, NULL);

    if (GSS_ERROR(maj_stat))
    {
        return 0;
    }

    if (output.length > 0)
    {
        /* Read a full token, copy as much as we can fit into the 
         * data array
         */
        r = output.length > size ? size : output.length;
        memcpy(data, output.value, r);
    }
    if (output.length != r)
    {
        /* Put remaining data into the state's buffer to copy when this
         * is called again
         */
        state->buffer.length = output.length - r;
        state->buffer.value = malloc(state->buffer.length);
        memcpy(state->buffer.value, ((char *)output.value)+r,
               state->buffer.length);
    }

    gss_release_buffer(&min_stat, &output);

    return r;
}
Esempio n. 23
0
CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                      struct connectdata *conn)
{
  struct SessionHandle *data = conn->data;
  curl_socket_t sock = conn->sock[sockindex];
  CURLcode code;
  ssize_t actualread;
  ssize_t written;
  int result;
  OM_uint32 gss_major_status, gss_minor_status, gss_status;
  OM_uint32 gss_ret_flags;
  int gss_conf_state, gss_enc;
  gss_buffer_desc  service = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc  gss_send_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc  gss_recv_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc  gss_w_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc* gss_token = GSS_C_NO_BUFFER;
  gss_name_t       server = GSS_C_NO_NAME;
  gss_name_t       gss_client_name = GSS_C_NO_NAME;
  unsigned short   us_length;
  char             *user=NULL;
  unsigned char socksreq[4]; /* room for gssapi exchange header only */
  char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];

  /*   GSSAPI request looks like
   * +----+------+-----+----------------+
   * |VER | MTYP | LEN |     TOKEN      |
   * +----+------+----------------------+
   * | 1  |  1   |  2  | up to 2^16 - 1 |
   * +----+------+-----+----------------+
   */

  /* prepare service name */
  if(strchr(serviceptr,'/')) {
    service.value = malloc(strlen(serviceptr));
    if(!service.value)
      return CURLE_OUT_OF_MEMORY;
    service.length = strlen(serviceptr);
    memcpy(service.value, serviceptr, service.length);

    gss_major_status = gss_import_name(&gss_minor_status, &service,
                                       (gss_OID) GSS_C_NULL_OID, &server);
  }
  else {
    service.value = malloc(strlen(serviceptr) +strlen(conn->proxy.name)+2);
    if(!service.value)
      return CURLE_OUT_OF_MEMORY;
    service.length = strlen(serviceptr) +strlen(conn->proxy.name)+1;
    snprintf(service.value, service.length+1, "%s@%s",
             serviceptr, conn->proxy.name);

    gss_major_status = gss_import_name(&gss_minor_status, &service,
                                       gss_nt_service_name, &server);
  }

  gss_release_buffer(&gss_status, &service); /* clear allocated memory */

  if(check_gss_err(data,gss_major_status,
                   gss_minor_status,"gss_import_name()")) {
    failf(data, "Failed to create service name.");
    gss_release_name(&gss_status, &server);
    return CURLE_COULDNT_CONNECT;
  }

  /* As long as we need to keep sending some context info, and there's no  */
  /* errors, keep sending it...                                            */
  for(;;) {
    gss_major_status = Curl_gss_init_sec_context(data,
                                                 &gss_minor_status,
                                                 &gss_context,
                                                 server,
                                                 NULL,
                                                 gss_token,
                                                 &gss_send_token,
                                                 &gss_ret_flags);

    if(gss_token != GSS_C_NO_BUFFER)
      gss_release_buffer(&gss_status, &gss_recv_token);
    if(check_gss_err(data,gss_major_status,
                     gss_minor_status,"gss_init_sec_context")) {
      gss_release_name(&gss_status, &server);
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_release_buffer(&gss_status, &gss_send_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to initial GSSAPI token.");
      return CURLE_COULDNT_CONNECT;
    }

    if(gss_send_token.length != 0) {
      socksreq[0] = 1;    /* gssapi subnegotiation version */
      socksreq[1] = 1;    /* authentication message type */
      us_length = htons((short)gss_send_token.length);
      memcpy(socksreq+2,&us_length,sizeof(short));

      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
      if((code != CURLE_OK) || (4 != written)) {
        failf(data, "Failed to send GSSAPI authentication request.");
        gss_release_name(&gss_status, &server);
        gss_release_buffer(&gss_status, &gss_recv_token);
        gss_release_buffer(&gss_status, &gss_send_token);
        gss_delete_sec_context(&gss_status, &gss_context, NULL);
        return CURLE_COULDNT_CONNECT;
      }

      code = Curl_write_plain(conn, sock, (char *)gss_send_token.value,
                              gss_send_token.length, &written);

      if((code != CURLE_OK) || ((ssize_t)gss_send_token.length != written)) {
        failf(data, "Failed to send GSSAPI authentication token.");
        gss_release_name(&gss_status, &server);
        gss_release_buffer(&gss_status, &gss_recv_token);
        gss_release_buffer(&gss_status, &gss_send_token);
        gss_delete_sec_context(&gss_status, &gss_context, NULL);
        return CURLE_COULDNT_CONNECT;
      }

    }

    gss_release_buffer(&gss_status, &gss_send_token);
    gss_release_buffer(&gss_status, &gss_recv_token);
    if(gss_major_status != GSS_S_CONTINUE_NEEDED) break;

    /* analyse response */

    /*   GSSAPI response looks like
     * +----+------+-----+----------------+
     * |VER | MTYP | LEN |     TOKEN      |
     * +----+------+----------------------+
     * | 1  |  1   |  2  | up to 2^16 - 1 |
     * +----+------+-----+----------------+
     */

    result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
    if(result != CURLE_OK || actualread != 4) {
      failf(data, "Failed to receive GSSAPI authentication response.");
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    /* ignore the first (VER) byte */
    if(socksreq[1] == 255) { /* status / message type */
      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
            socksreq[0], socksreq[1]);
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    if(socksreq[1] != 1) { /* status / messgae type */
      failf(data, "Invalid GSSAPI authentication response type (%d %d).",
            socksreq[0], socksreq[1]);
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(&us_length, socksreq+2, sizeof(short));
    us_length = ntohs(us_length);

    gss_recv_token.length=us_length;
    gss_recv_token.value=malloc(us_length);
    if(!gss_recv_token.value) {
      failf(data,
            "Could not allocate memory for GSSAPI authentication "
            "response token.");
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_OUT_OF_MEMORY;
    }

    result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
                              gss_recv_token.length, &actualread);

    if(result != CURLE_OK || actualread != us_length) {
      failf(data, "Failed to receive GSSAPI authentication token.");
      gss_release_name(&gss_status, &server);
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    gss_token = &gss_recv_token;
  }

  gss_release_name(&gss_status, &server);

  /* Everything is good so far, user was authenticated! */
  gss_major_status = gss_inquire_context (&gss_minor_status, gss_context,
                                          &gss_client_name, NULL, NULL, NULL,
                                          NULL, NULL, NULL);
  if(check_gss_err(data,gss_major_status,
                   gss_minor_status,"gss_inquire_context")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
                                      &gss_send_token, NULL);
  if(check_gss_err(data,gss_major_status,
                   gss_minor_status,"gss_display_name")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  user=malloc(gss_send_token.length+1);
  if(!user) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);
    return CURLE_OUT_OF_MEMORY;
  }

  memcpy(user, gss_send_token.value, gss_send_token.length);
  user[gss_send_token.length] = '\0';
  gss_release_name(&gss_status, &gss_client_name);
  gss_release_buffer(&gss_status, &gss_send_token);
  infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",user);
  free(user);
  user=NULL;

  /* Do encryption */
  socksreq[0] = 1;    /* gssapi subnegotiation version */
  socksreq[1] = 2;    /* encryption message type */

  gss_enc = 0; /* no data protection */
  /* do confidentiality protection if supported */
  if(gss_ret_flags & GSS_C_CONF_FLAG)
    gss_enc = 2;
  /* else do integrity protection */
  else if(gss_ret_flags & GSS_C_INTEG_FLAG)
    gss_enc = 1;

  infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
  /* force for the moment to no data protection */
  gss_enc = 0;
  /*
   * Sending the encryption type in clear seems wrong. It should be
   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
   * The NEC reference implementations on which this is based is
   * therefore at fault
   *
   *  +------+------+------+.......................+
   *  + ver  | mtyp | len  |   token               |
   *  +------+------+------+.......................+
   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
   *  +------+------+------+.......................+
   *
   *   Where:
   *
   *  - "ver" is the protocol version number, here 1 to represent the
   *    first version of the SOCKS/GSS-API protocol
   *
   *  - "mtyp" is the message type, here 2 to represent a protection
   *    -level negotiation message
   *
   *  - "len" is the length of the "token" field in octets
   *
   *  - "token" is the GSS-API encapsulated protection level
   *
   * The token is produced by encapsulating an octet containing the
   * required protection level using gss_seal()/gss_wrap() with conf_req
   * set to FALSE.  The token is verified using gss_unseal()/
   * gss_unwrap().
   *
   */
  if(data->set.socks5_gssapi_nec) {
    us_length = htons((short)1);
    memcpy(socksreq+2,&us_length,sizeof(short));
  }
  else {
    gss_send_token.length = 1;
    gss_send_token.value = malloc(1);
    if(!gss_send_token.value) {
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_OUT_OF_MEMORY;
    }
    memcpy(gss_send_token.value, &gss_enc, 1);

    gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
                                GSS_C_QOP_DEFAULT, &gss_send_token,
                                &gss_conf_state, &gss_w_token);

    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_wrap")) {
      gss_release_buffer(&gss_status, &gss_send_token);
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to wrap GSSAPI encryption value into token.");
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_send_token);

    us_length = htons((short)gss_w_token.length);
    memcpy(socksreq+2,&us_length,sizeof(short));
  }

  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
  if((code != CURLE_OK) || (4 != written)) {
    failf(data, "Failed to send GSSAPI encryption request.");
    gss_release_buffer(&gss_status, &gss_w_token);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  if(data->set.socks5_gssapi_nec) {
    memcpy(socksreq, &gss_enc, 1);
    code = Curl_write_plain(conn, sock, socksreq, 1, &written);
    if((code != CURLE_OK) || ( 1 != written)) {
      failf(data, "Failed to send GSSAPI encryption type.");
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }
  }
  else {
    code = Curl_write_plain(conn, sock, (char *)gss_w_token.value,
                            gss_w_token.length, &written);
    if((code != CURLE_OK) || ((ssize_t)gss_w_token.length != written)) {
      failf(data, "Failed to send GSSAPI encryption type.");
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_w_token);
  }

  result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
  if(result != CURLE_OK || actualread != 4) {
    failf(data, "Failed to receive GSSAPI encryption response.");
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  /* ignore the first (VER) byte */
  if(socksreq[1] == 255) { /* status / message type */
    failf(data, "User was rejected by the SOCKS5 server (%d %d).",
          socksreq[0], socksreq[1]);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  if(socksreq[1] != 2) { /* status / messgae type */
    failf(data, "Invalid GSSAPI encryption response type (%d %d).",
          socksreq[0], socksreq[1]);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  memcpy(&us_length, socksreq+2, sizeof(short));
  us_length = ntohs(us_length);

  gss_recv_token.length= us_length;
  gss_recv_token.value=malloc(gss_recv_token.length);
  if(!gss_recv_token.value) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_OUT_OF_MEMORY;
  }
  result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
                            gss_recv_token.length, &actualread);

  if(result != CURLE_OK || actualread != us_length) {
    failf(data, "Failed to receive GSSAPI encryptrion type.");
    gss_release_buffer(&gss_status, &gss_recv_token);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  if(!data->set.socks5_gssapi_nec) {
    gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
                                  &gss_recv_token, &gss_w_token,
                                  0, GSS_C_QOP_DEFAULT);

    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_unwrap")) {
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to unwrap GSSAPI encryption value into token.");
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_recv_token);

    if(gss_w_token.length != 1) {
      failf(data, "Invalid GSSAPI encryption response length (%d).",
            gss_w_token.length);
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(socksreq,gss_w_token.value,gss_w_token.length);
    gss_release_buffer(&gss_status, &gss_w_token);
  }
  else {
    if(gss_recv_token.length != 1) {
      failf(data, "Invalid GSSAPI encryption response length (%d).",
            gss_recv_token.length);
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(socksreq,gss_recv_token.value,gss_recv_token.length);
    gss_release_buffer(&gss_status, &gss_recv_token);
  }

  infof(data, "SOCKS5 access with%s protection granted.\n",
        (socksreq[0]==0)?"out gssapi data":
        ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));

  conn->socks5_gssapi_enctype = socksreq[0];
  if(socksreq[0] == 0)
    gss_delete_sec_context(&gss_status, &gss_context, NULL);

  return CURLE_OK;
}
Esempio n. 24
0
static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
				     TALLOC_CTX *out_mem_ctx,
				     struct tevent_context *ev,
				     const DATA_BLOB in, DATA_BLOB *out)
{
	struct gensec_gssapi_state *gensec_gssapi_state
		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
	NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
	OM_uint32 maj_stat, min_stat;
	OM_uint32 min_stat2;
	gss_buffer_desc input_token = { 0, NULL };
	gss_buffer_desc output_token = { 0, NULL };

	gss_OID gss_oid_p = NULL;
	OM_uint32 time_req = 0;
	OM_uint32 time_rec = 0;
	struct timeval tv;

	time_req = gensec_setting_int(gensec_security->settings,
				      "gensec_gssapi", "requested_life_time",
				      time_req);

	input_token.length = in.length;
	input_token.value = in.data;

	switch (gensec_gssapi_state->sasl_state) {
	case STAGE_GSS_NEG:
	{
		switch (gensec_security->gensec_role) {
		case GENSEC_CLIENT:
		{
#ifdef SAMBA4_USES_HEIMDAL
			struct gsskrb5_send_to_kdc send_to_kdc;
			krb5_error_code ret;
#endif

			nt_status = gensec_gssapi_client_creds(gensec_security, ev);
			if (!NT_STATUS_IS_OK(nt_status)) {
				return nt_status;
			}

#ifdef SAMBA4_USES_HEIMDAL
			send_to_kdc.func = smb_krb5_send_and_recv_func;
			send_to_kdc.ptr = ev;

			min_stat = gsskrb5_set_send_to_kdc(&send_to_kdc);
			if (min_stat) {
				DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
				return NT_STATUS_INTERNAL_ERROR;
			}
#endif
			maj_stat = gss_init_sec_context(&min_stat, 
							gensec_gssapi_state->client_cred->creds,
							&gensec_gssapi_state->gssapi_context, 
							gensec_gssapi_state->server_name, 
							gensec_gssapi_state->gss_oid,
							gensec_gssapi_state->gss_want_flags, 
							time_req,
							gensec_gssapi_state->input_chan_bindings,
							&input_token, 
							&gss_oid_p,
							&output_token, 
							&gensec_gssapi_state->gss_got_flags, /* ret flags */
							&time_rec);
			if (gss_oid_p) {
				gensec_gssapi_state->gss_oid = gss_oid_p;
			}

#ifdef SAMBA4_USES_HEIMDAL
			send_to_kdc.func = smb_krb5_send_and_recv_func;
			send_to_kdc.ptr = NULL;

			ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
			if (ret) {
				DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
				return NT_STATUS_INTERNAL_ERROR;
			}
#endif
			break;
		}
		case GENSEC_SERVER:
		{
			maj_stat = gss_accept_sec_context(&min_stat, 
							  &gensec_gssapi_state->gssapi_context, 
							  gensec_gssapi_state->server_cred->creds,
							  &input_token, 
							  gensec_gssapi_state->input_chan_bindings,
							  &gensec_gssapi_state->client_name, 
							  &gss_oid_p,
							  &output_token, 
							  &gensec_gssapi_state->gss_got_flags, 
							  &time_rec,
							  &gensec_gssapi_state->delegated_cred_handle);
			if (gss_oid_p) {
				gensec_gssapi_state->gss_oid = gss_oid_p;
			}
			break;
		}
		default:
			return NT_STATUS_INVALID_PARAMETER;
			
		}

		gensec_gssapi_state->gss_exchange_count++;

		if (maj_stat == GSS_S_COMPLETE) {
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat2, &output_token);
			
			if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
			    gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
				DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
			} else {
				DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
			}

			tv = timeval_current_ofs(time_rec, 0);
			gensec_gssapi_state->expire_time = timeval_to_nttime(&tv);

			/* We may have been invoked as SASL, so there
			 * is more work to do */
			if (gensec_gssapi_state->sasl) {
				gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
				return NT_STATUS_MORE_PROCESSING_REQUIRED;
			} else {
				gensec_gssapi_state->sasl_state = STAGE_DONE;

				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
					DEBUG(5, ("GSSAPI Connection will be cryptographically sealed\n"));
				} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
					DEBUG(5, ("GSSAPI Connection will be cryptographically signed\n"));
				} else {
					DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
				}

				return NT_STATUS_OK;
			}
		} else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat2, &output_token);
			
			return NT_STATUS_MORE_PROCESSING_REQUIRED;
		} else if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
			gss_cred_id_t creds = NULL;
			gss_name_t name;
			gss_buffer_desc buffer;
			OM_uint32 lifetime = 0;
			gss_cred_usage_t usage;
			const char *role = NULL;
			DEBUG(0, ("GSS %s Update(krb5)(%d) Update failed, credentials expired during GSSAPI handshake!\n",
				  role,
				  gensec_gssapi_state->gss_exchange_count));

			
			switch (gensec_security->gensec_role) {
			case GENSEC_CLIENT:
				creds = gensec_gssapi_state->client_cred->creds;
				role = "client";
				break;
			case GENSEC_SERVER:
				creds = gensec_gssapi_state->server_cred->creds;
				role = "server";
				break;
			}

			maj_stat = gss_inquire_cred(&min_stat, 
						    creds,
						    &name, &lifetime, &usage, NULL);

			if (maj_stat == GSS_S_COMPLETE) {
				const char *usage_string = NULL;
				switch (usage) {
				case GSS_C_BOTH:
					usage_string = "GSS_C_BOTH";
					break;
				case GSS_C_ACCEPT:
					usage_string = "GSS_C_ACCEPT";
					break;
				case GSS_C_INITIATE:
					usage_string = "GSS_C_INITIATE";
					break;
				}
				maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
				if (maj_stat) {
					buffer.value = NULL;
					buffer.length = 0;
				}
				if (lifetime > 0) {
					DEBUG(0, ("GSSAPI gss_inquire_cred indicates expiry of %*.*s in %u sec for %s\n", 
						  (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
						  lifetime, usage_string));
				} else {
					DEBUG(0, ("GSSAPI gss_inquire_cred indicates %*.*s has already expired for %s\n", 
						  (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
						  usage_string));
				}
				gss_release_buffer(&min_stat, &buffer);
				gss_release_name(&min_stat, &name);
			} else if (maj_stat != GSS_S_COMPLETE) {
				DEBUG(0, ("inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			}
			return NT_STATUS_INVALID_PARAMETER;
		} else if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
					     gss_mech_krb5)) {
			switch (min_stat) {
			case KRB5KRB_AP_ERR_TKT_NYV:
				DEBUG(1, ("Error with ticket to contact %s: possible clock skew between us and the KDC or target server: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_TIME_DIFFERENCE_AT_DC; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KRB_AP_ERR_TKT_EXPIRED:
				DEBUG(1, ("Error with ticket to contact %s: ticket is expired, possible clock skew between us and the KDC or target server: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5_KDC_UNREACH:
				DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticket to %s: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_NO_LOGON_SERVERS; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
				DEBUG(3, ("Server %s is not registered with our KDC: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KRB_AP_ERR_MSG_TYPE:
				/* garbage input, possibly from the auto-mech detection */
				return NT_STATUS_INVALID_PARAMETER;
			default:
				DEBUG(1, ("GSS %s Update(krb5)(%d) Update failed: %s\n",
					  gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
					  gensec_gssapi_state->gss_exchange_count,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_LOGON_FAILURE;
			}
		} else {
			DEBUG(1, ("GSS %s Update(%d) failed: %s\n",
				  gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
				  gensec_gssapi_state->gss_exchange_count,
				  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			return NT_STATUS_LOGON_FAILURE;
		}
		break;
	}

	/* These last two stages are only done if we were invoked as SASL */
	case STAGE_SASL_SSF_NEG:
	{
		switch (gensec_security->gensec_role) {
		case GENSEC_CLIENT:
		{
			uint8_t maxlength_proposed[4]; 
			uint8_t maxlength_accepted[4]; 
			uint8_t security_supported;
			int conf_state;
			gss_qop_t qop_state;
			input_token.length = in.length;
			input_token.value = in.data;

			/* As a client, we have just send a
			 * zero-length blob to the server (after the
			 * normal GSSAPI exchange), and it has replied
			 * with it's SASL negotiation */
			
			maj_stat = gss_unwrap(&min_stat, 
					      gensec_gssapi_state->gssapi_context, 
					      &input_token,
					      &output_token, 
					      &conf_state,
					      &qop_state);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			if (output_token.length < 4) {
				return NT_STATUS_INVALID_PARAMETER;
			}

			memcpy(maxlength_proposed, output_token.value, 4);
			gss_release_buffer(&min_stat, &output_token);

			/* first byte is the proposed security */
			security_supported = maxlength_proposed[0];
			maxlength_proposed[0] = '\0';
			
			/* Rest is the proposed max wrap length */
			gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0), 
								     gensec_gssapi_state->max_wrap_buf_size);
			gensec_gssapi_state->sasl_protection = 0;
			if (security_supported & NEG_SEAL) {
				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
					gensec_gssapi_state->sasl_protection |= NEG_SEAL;
				}
			}
			if (security_supported & NEG_SIGN) {
				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
					gensec_gssapi_state->sasl_protection |= NEG_SIGN;
				}
			}
			if (security_supported & NEG_NONE) {
				gensec_gssapi_state->sasl_protection |= NEG_NONE;
			}
			if (gensec_gssapi_state->sasl_protection == 0) {
				DEBUG(1, ("Remote server does not support unprotected connections\n"));
				return NT_STATUS_ACCESS_DENIED;
			}

			/* Send back the negotiated max length */

			RSIVAL(maxlength_accepted, 0, gensec_gssapi_state->max_wrap_buf_size);

			maxlength_accepted[0] = gensec_gssapi_state->sasl_protection;
			
			input_token.value = maxlength_accepted;
			input_token.length = sizeof(maxlength_accepted);

			maj_stat = gss_wrap(&min_stat, 
					    gensec_gssapi_state->gssapi_context, 
					    false,
					    GSS_C_QOP_DEFAULT,
					    &input_token,
					    &conf_state,
					    &output_token);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat, &output_token);

			/* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
			gensec_gssapi_state->sasl_state = STAGE_DONE;

			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically sealed\n"));
			} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically signed\n"));
			} else {
				DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographically protection\n"));
			}

			return NT_STATUS_OK;
		}
		case GENSEC_SERVER:
		{
			uint8_t maxlength_proposed[4]; 
			uint8_t security_supported = 0x0;
			int conf_state;

			/* As a server, we have just been sent a zero-length blob (note this, but it isn't fatal) */
			if (in.length != 0) {
				DEBUG(1, ("SASL/GSSAPI: client sent non-zero length starting SASL negotiation!\n"));
			}
			
			/* Give the client some idea what we will support */
			  
			RSIVAL(maxlength_proposed, 0, gensec_gssapi_state->max_wrap_buf_size);
			/* first byte is the proposed security */
			maxlength_proposed[0] = '\0';
			
			gensec_gssapi_state->sasl_protection = 0;
			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				security_supported |= NEG_SEAL;
			} 
			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				security_supported |= NEG_SIGN;
			}
			if (security_supported == 0) {
				/* If we don't support anything, this must be 0 */
				RSIVAL(maxlength_proposed, 0, 0x0);
			}

			/* TODO:  We may not wish to support this */
			security_supported |= NEG_NONE;
			maxlength_proposed[0] = security_supported;
			
			input_token.value = maxlength_proposed;
			input_token.length = sizeof(maxlength_proposed);

			maj_stat = gss_wrap(&min_stat, 
					    gensec_gssapi_state->gssapi_context, 
					    false,
					    GSS_C_QOP_DEFAULT,
					    &input_token,
					    &conf_state,
					    &output_token);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat, &output_token);

			gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
			return NT_STATUS_MORE_PROCESSING_REQUIRED;
		}
		default:
  			return NT_STATUS_INVALID_PARAMETER;
			
		}
	}
	/* This is s server-only stage */
	case STAGE_SASL_SSF_ACCEPT:
	{
		uint8_t maxlength_accepted[4]; 
		uint8_t security_accepted;
		int conf_state;
		gss_qop_t qop_state;
		input_token.length = in.length;
		input_token.value = in.data;
			
		maj_stat = gss_unwrap(&min_stat, 
				      gensec_gssapi_state->gssapi_context, 
				      &input_token,
				      &output_token, 
				      &conf_state,
				      &qop_state);
		if (GSS_ERROR(maj_stat)) {
			DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
				  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			return NT_STATUS_ACCESS_DENIED;
		}
			
		if (output_token.length < 4) {
			return NT_STATUS_INVALID_PARAMETER;
		}

		memcpy(maxlength_accepted, output_token.value, 4);
		gss_release_buffer(&min_stat, &output_token);
		
		/* first byte is the proposed security */
		security_accepted = maxlength_accepted[0];
		maxlength_accepted[0] = '\0';

		/* Rest is the proposed max wrap length */
		gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0), 
							     gensec_gssapi_state->max_wrap_buf_size);

		gensec_gssapi_state->sasl_protection = 0;
		if (security_accepted & NEG_SEAL) {
			if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				DEBUG(1, ("Remote client wanted seal, but gensec refused\n"));
				return NT_STATUS_ACCESS_DENIED;
			}
			gensec_gssapi_state->sasl_protection |= NEG_SEAL;
		}
		if (security_accepted & NEG_SIGN) {
			if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				DEBUG(1, ("Remote client wanted sign, but gensec refused\n"));
				return NT_STATUS_ACCESS_DENIED;
			}
			gensec_gssapi_state->sasl_protection |= NEG_SIGN;
		}
		if (security_accepted & NEG_NONE) {
			gensec_gssapi_state->sasl_protection |= NEG_NONE;
		}

		/* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
		gensec_gssapi_state->sasl_state = STAGE_DONE;
		if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
			DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically sealed\n"));
		} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
			DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically signed\n"));
		} else {
			DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
		}

		*out = data_blob(NULL, 0);
		return NT_STATUS_OK;	
	}
	default:
		return NT_STATUS_INVALID_PARAMETER;
	}
}
Esempio n. 25
0
int socks_gssapi_auth(struct openconnect_info *vpninfo)
{
	gss_buffer_desc in = GSS_C_EMPTY_BUFFER;
	gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
	gss_OID mech = GSS_C_NO_OID;
	OM_uint32 major, minor;
	unsigned char *pktbuf;
	int i;
	int ret = -EIO;

	if (gssapi_setup(vpninfo, "rcmd", 1))
		return -EIO;

	pktbuf = malloc(65538);
	if (!pktbuf)
		return -ENOMEM;
	while (1) {
		major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &vpninfo->gss_context[1],
					     vpninfo->gss_target_name[1], (gss_OID)&gss_mech_spnego,
					     GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_DELEG_FLAG | GSS_C_SEQUENCE_FLAG,
					     GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &in, &mech,
					     &out, NULL, NULL);
		in.value = NULL;
		if (major == GSS_S_COMPLETE) {
			/* If we still have a token to send, send it. */
			if (!out.length) {
				vpn_progress(vpninfo, PRG_DEBUG,
					     _("GSSAPI authentication completed\n"));
				gss_release_buffer(&minor, &out);
				ret = 0;
				break;
			}
		} else if (major != GSS_S_CONTINUE_NEEDED) {
			print_gss_err(vpninfo, "gss_init_sec_context()", mech, major, minor);
			break;
		}
		if (out.length > 65535) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("GSSAPI token too large (%zd bytes)\n"),
				     out.length);
			break;
		}

		pktbuf[0] = 1; /* ver */
		pktbuf[1] = 1; /* mtyp */
		store_be16(pktbuf + 2, out.length);
		memcpy(pktbuf + 4, out.value, out.length);

		free(out.value);

		vpn_progress(vpninfo, PRG_TRACE,
			     _("Sending GSSAPI token of %zu bytes\n"), out.length + 4);

		i = vpninfo->ssl_write(vpninfo, (void *)pktbuf, out.length + 4);
		if (i < 0) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Failed to send GSSAPI authentication token to proxy: %s\n"),
				     strerror(-i));
			break;
		}

		i = vpninfo->ssl_read(vpninfo, (void *)pktbuf, 4);
		if (i < 0) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Failed to receive GSSAPI authentication token from proxy: %s\n"),
				     strerror(-i));
			break;
		}
		if (pktbuf[1] == 0xff) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("SOCKS server reported GSSAPI context failure\n"));
			break;
		} else if (pktbuf[1] != 1) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Unknown GSSAPI status response (0x%02x) from SOCKS server\n"),
				     pktbuf[1]);
			break;
		}
		in.length = load_be16(pktbuf + 2);
		in.value = pktbuf;

		if (!in.length) {
			vpn_progress(vpninfo, PRG_DEBUG,
				     _("GSSAPI authentication completed\n"));
			ret = 0;
			break;
		}

		i = vpninfo->ssl_read(vpninfo, (void *)pktbuf, in.length);
		if (i < 0) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Failed to receive GSSAPI authentication token from proxy: %s\n"),
				     strerror(-i));
			break;
		}
		vpn_progress(vpninfo, PRG_TRACE, _("Got GSSAPI token of %zu bytes: %02x %02x %02x %02x\n"),
			     in.length, pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3]);
	}

	if (!ret) {
		ret = -EIO;

		pktbuf[0] = 0;
		in.value = pktbuf;
		in.length = 1;

		major = gss_wrap(&minor, vpninfo->gss_context[1], 0,
				 GSS_C_QOP_DEFAULT, &in, NULL, &out);
		if (major != GSS_S_COMPLETE) {
			print_gss_err(vpninfo, "gss_wrap()", mech, major, minor);
			goto err;
		}

		pktbuf[0] = 1;
		pktbuf[1] = 2;
		store_be16(pktbuf + 2, out.length);
		memcpy(pktbuf + 4, out.value, out.length);

		free(out.value);

		vpn_progress(vpninfo, PRG_TRACE,
			     _("Sending GSSAPI protection negotiation of %zu bytes\n"), out.length + 4);

		i = vpninfo->ssl_write(vpninfo, (void *)pktbuf, out.length + 4);
		if (i < 0) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Failed to send GSSAPI protection response to proxy: %s\n"),
				     strerror(-i));
			goto err;
		}

		i = vpninfo->ssl_read(vpninfo, (void *)pktbuf, 4);
		if (i < 0) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Failed to receive GSSAPI protection response from proxy: %s\n"),
				     strerror(-i));
			goto err;
		}
		in.length = load_be16(pktbuf + 2);
		in.value = pktbuf;

		i = vpninfo->ssl_read(vpninfo, (void *)pktbuf, in.length);
		if (i < 0) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Failed to receive GSSAPI protection response from proxy: %s\n"),
				     strerror(-i));
			goto err;
		}
		vpn_progress(vpninfo, PRG_TRACE,
			     _("Got GSSAPI protection response of %zu bytes: %02x %02x %02x %02x\n"),
			     in.length, pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3]);

		major = gss_unwrap(&minor, vpninfo->gss_context[1], &in, &out, NULL, GSS_C_QOP_DEFAULT);
		if (major != GSS_S_COMPLETE) {
			print_gss_err(vpninfo, "gss_unwrap()", mech, major, minor);
			goto err;
		}
		if (out.length != 1) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Invalid GSSAPI protection response from proxy (%zu bytes)\n"),
				     out.length);
			gss_release_buffer(&minor, &out);
			goto err;
		}
		i = *(char *)out.value;
		gss_release_buffer(&minor, &out);
		if (i == 1) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("SOCKS proxy demands message integrity, which is not supported\n"));
			goto err;
		} else if (i == 2) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("SOCKS proxy demands message confidentiality, which is not supported\n"));
			goto err;
		} else if (i) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("SOCKS proxy demands protection unknown type 0x%02x\n"),
				     (unsigned char)i);
			goto err;
		}
		ret = 0;
	}
 err:
	cleanup_gssapi_auth(vpninfo, 1, NULL);
	free(pktbuf);

	return ret;
}
int GSI_SOCKET_read_token(GSI_SOCKET *self,
			  unsigned char **pbuffer,
			  size_t *pbuffer_len)
{
    int			bytes_read;
    static unsigned char *saved_buffer = NULL; /* not thread safe! */
    static int          saved_buffer_len = 0;
    unsigned char	*buffer;
    int			return_status = GSI_SOCKET_ERROR;
    
    if (saved_buffer) {

	buffer = saved_buffer;
	bytes_read = saved_buffer_len;
	saved_buffer = NULL;
	saved_buffer_len = 0;

    } else {

	bytes_read = read_token(self->sock,
                            (char **) &buffer,
                            self->max_token_len);
    
	if (bytes_read == -1)
	{
	    self->error_number = errno;
	    GSI_SOCKET_set_error_string(self, "failed to read token");
	    goto error;
	}

    if (bytes_read == 0)
    {
	    self->error_number = errno;
	    GSI_SOCKET_set_error_string(self, "connection closed");
	    goto error;
    }

	if (self->gss_context != GSS_C_NO_CONTEXT)
	{
	    /* Need to unwrap read data */
	    gss_buffer_desc unwrapped_buffer;
	    gss_buffer_desc wrapped_buffer;
	    int conf_state;
	    gss_qop_t qop_state;

	    wrapped_buffer.value = buffer;
	    wrapped_buffer.length = bytes_read;

	    self->major_status = gss_unwrap(&self->minor_status,
					    self->gss_context,
					    &wrapped_buffer,
					    &unwrapped_buffer,
					    &conf_state,
					    &qop_state);

	    free(buffer);

	    if (self->major_status != GSS_S_COMPLETE)
	    {
		goto error;
	    }
	
	    buffer = unwrapped_buffer.value;
	    bytes_read = unwrapped_buffer.length;
	}

    }

    if (bytes_read == 0)
    {
	    self->error_number = errno;
	    GSI_SOCKET_set_error_string(self, "connection closed");
	    goto error;
    }

    /* HACK: We may have multiple tokens concatenated together here.
       Unfortunately, our protocol doesn't do a good job of message
       framing.  Still, we can find the start/end of some messages
       by looking for the standard VERSION string at the start. */
    if (strncmp((const char *)buffer, "VERSION", strlen("VERSION")) == 0) {
	size_t token_len = safe_strlen((const char *)buffer, bytes_read)+1;
	if (bytes_read > token_len) {

	    /* Our buffer is bigger than one message.  Just return the
	       one message here and save the rest for later. */

	    char *old_buffer;

	    old_buffer = (char *)buffer;
	    saved_buffer_len = bytes_read - token_len;
	    buffer = malloc(token_len);
	    memcpy(buffer, old_buffer, token_len);
	    saved_buffer = malloc(saved_buffer_len);
	    memcpy(saved_buffer, old_buffer+token_len, saved_buffer_len);
	    bytes_read = token_len;
	    free(old_buffer);
	}
    }

    /* Success */
    *pbuffer = buffer;
    *pbuffer_len = bytes_read;
    return_status = GSI_SOCKET_SUCCESS;
/*     fprintf(stderr, "\nread:\n%s\n", buffer); */

#if 0
    if (buffer[bytes_read-1] == '\0') {
	myproxy_debug("read a null-terminated message");
    } else {
	myproxy_debug("read a non-null-terminated message");
    }
#endif
    
  error:
    return return_status;
}
Esempio n. 27
0
int 
receive_delegated_proxy(char **s, gss_ctx_id_t gss_context, int sck)
{
	char             *buf;
	int              return_status = BPR_RECEIVE_DELEGATED_PROXY_ERROR;
	int              send_status;
	gss_buffer_desc  input_token,output_token;
	gss_buffer_desc  snd_token, rcv_token;
	gss_buffer_desc  cred_token;
	gss_cred_id_t    delegated_cred = GSS_C_NO_CREDENTIAL;
	OM_uint32        del_maj_stat, maj_stat, min_stat, time_rec;
	int conf_req_flag = 1; /* Non zero value to request confidentiality */

	del_maj_stat = GSS_S_CONTINUE_NEEDED;

	if (gss_context != GSS_C_NO_CONTEXT) 
	{
		while (del_maj_stat == GSS_S_CONTINUE_NEEDED)
		{
                        /* get_token can return -1 on error or GLOBUS_GSS_ASSIST_TOKEN_EOF==3 */
			if (get_token(&sck, &input_token.value, &input_token.length) != 0) break;
			maj_stat = gss_unwrap(
					&min_stat,
					gss_context,
					&input_token,
					&rcv_token,
					NULL,
					NULL);
	
			gss_release_buffer(&min_stat, &input_token);
	
			if (!GSS_ERROR(maj_stat))
			{
				del_maj_stat=gss_accept_delegation(&min_stat,
					gss_context,
					GSS_C_NO_OID_SET,
					GSS_C_NO_BUFFER_SET,
					&rcv_token,
					GSS_C_GLOBUS_SSL_COMPATIBLE,
					0,
					&time_rec,
					&delegated_cred,
					NULL,
					&snd_token);
			}
			else break;
	
			gss_release_buffer(&min_stat, &rcv_token);

			if (del_maj_stat != GSS_S_CONTINUE_NEEDED) break;

			maj_stat = gss_wrap(
					&min_stat,
					gss_context,
					conf_req_flag,
					GSS_C_QOP_DEFAULT,
					&snd_token,
					NULL,
					&output_token);
			gss_release_buffer(&min_stat, &snd_token);

			if (!GSS_ERROR(maj_stat))
			{
				send_status = send_token((void*)&sck, output_token.value, output_token.length);
				gss_release_buffer(&min_stat, &output_token);
				if (send_status < 0)
				{
					break;
				}
			}
			else 
			{
				break;
			}
		}
	}
	if (del_maj_stat == GSS_S_COMPLETE) 
	{
		/* Export credential to a string */
		maj_stat = gss_export_cred(&min_stat, 
					delegated_cred, 
					GSS_C_NO_OID,
					0,
					&cred_token);
		if (maj_stat == GSS_S_COMPLETE) {
			
			if (s != NULL) 
			{
				*s = (char *)malloc(cred_token.length + 1);
				if (*s != NULL)
				{
					memcpy(*s, cred_token.value, cred_token.length);
					(*s)[cred_token.length]='\000';
					return_status = BPR_RECEIVE_DELEGATED_PROXY_OK;
				}
			}
		}
		gss_release_buffer(&min_stat, &cred_token);
	}
	return return_status;
}
Esempio n. 28
0
/**
 * imap_auth_gss - GSS Authentication support
 * @param adata Imap Account data
 * @param method Name of this authentication method
 * @retval enum Result, e.g. #IMAP_AUTH_SUCCESS
 */
enum ImapAuthRes imap_auth_gss(struct ImapAccountData *adata, const char *method)
{
  gss_buffer_desc request_buf, send_token;
  gss_buffer_t sec_token;
  gss_name_t target_name;
  gss_ctx_id_t context;
  gss_OID mech_name;
  char server_conf_flags;
  gss_qop_t quality;
  int cflags;
  OM_uint32 maj_stat, min_stat;
  unsigned long buf_size;
  int rc, retval = IMAP_AUTH_FAILURE;

  if (!(adata->capabilities & IMAP_CAP_AUTH_GSSAPI))
    return IMAP_AUTH_UNAVAIL;

  if (mutt_account_getuser(&adata->conn->account) < 0)
    return IMAP_AUTH_FAILURE;

  struct Buffer *buf1 = mutt_buffer_pool_get();
  struct Buffer *buf2 = mutt_buffer_pool_get();

  /* get an IMAP service ticket for the server */
  mutt_buffer_printf(buf1, "imap@%s", adata->conn->account.host);
  request_buf.value = buf1->data;
  request_buf.length = mutt_buffer_len(buf1);

  maj_stat = gss_import_name(&min_stat, &request_buf, gss_nt_service_name, &target_name);
  if (maj_stat != GSS_S_COMPLETE)
  {
    mutt_debug(LL_DEBUG2, "Couldn't get service name for [%s]\n", buf1);
    retval = IMAP_AUTH_UNAVAIL;
    goto cleanup;
  }
  else if (C_DebugLevel >= 2)
  {
    gss_display_name(&min_stat, target_name, &request_buf, &mech_name);
    mutt_debug(LL_DEBUG2, "Using service name [%s]\n", (char *) request_buf.value);
    gss_release_buffer(&min_stat, &request_buf);
  }
  /* Acquire initial credentials - without a TGT GSSAPI is UNAVAIL */
  sec_token = GSS_C_NO_BUFFER;
  context = GSS_C_NO_CONTEXT;

  /* build token */
  maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &context, target_name,
                                  GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
                                  0, GSS_C_NO_CHANNEL_BINDINGS, sec_token, NULL,
                                  &send_token, (unsigned int *) &cflags, NULL);
  if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED))
  {
    print_gss_error(maj_stat, min_stat);
    mutt_debug(LL_DEBUG1, "Error acquiring credentials - no TGT?\n");
    gss_release_name(&min_stat, &target_name);

    retval = IMAP_AUTH_UNAVAIL;
    goto cleanup;
  }

  /* now begin login */
  mutt_message(_("Authenticating (GSSAPI)..."));

  imap_cmd_start(adata, "AUTHENTICATE GSSAPI");

  /* expect a null continuation response ("+") */
  do
    rc = imap_cmd_step(adata);
  while (rc == IMAP_CMD_CONTINUE);

  if (rc != IMAP_CMD_RESPOND)
  {
    mutt_debug(LL_DEBUG2, "Invalid response from server: %s\n", buf1);
    gss_release_name(&min_stat, &target_name);
    goto bail;
  }

  /* now start the security context initialisation loop... */
  mutt_debug(LL_DEBUG2, "Sending credentials\n");
  mutt_b64_buffer_encode(buf1, send_token.value, send_token.length);
  gss_release_buffer(&min_stat, &send_token);
  mutt_buffer_addstr(buf1, "\r\n");
  mutt_socket_send(adata->conn, mutt_b2s(buf1));

  while (maj_stat == GSS_S_CONTINUE_NEEDED)
  {
    /* Read server data */
    do
      rc = imap_cmd_step(adata);
    while (rc == IMAP_CMD_CONTINUE);

    if (rc != IMAP_CMD_RESPOND)
    {
      mutt_debug(LL_DEBUG1, "#1 Error receiving server response\n");
      gss_release_name(&min_stat, &target_name);
      goto bail;
    }

    if (mutt_b64_buffer_decode(buf2, adata->buf + 2) < 0)
    {
      mutt_debug(LL_DEBUG1, "Invalid base64 server response\n");
      gss_release_name(&min_stat, &target_name);
      goto err_abort_cmd;
    }
    request_buf.value = buf2->data;
    request_buf.length = mutt_buffer_len(buf2);
    sec_token = &request_buf;

    /* Write client data */
    maj_stat = gss_init_sec_context(
        &min_stat, GSS_C_NO_CREDENTIAL, &context, target_name, GSS_C_NO_OID,
        GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, 0, GSS_C_NO_CHANNEL_BINDINGS,
        sec_token, NULL, &send_token, (unsigned int *) &cflags, NULL);
    if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED))
    {
      print_gss_error(maj_stat, min_stat);
      mutt_debug(LL_DEBUG1, "Error exchanging credentials\n");
      gss_release_name(&min_stat, &target_name);

      goto err_abort_cmd;
    }
    mutt_b64_buffer_encode(buf1, send_token.value, send_token.length);
    gss_release_buffer(&min_stat, &send_token);
    mutt_buffer_addstr(buf1, "\r\n");
    mutt_socket_send(adata->conn, mutt_b2s(buf1));
  }

  gss_release_name(&min_stat, &target_name);

  /* get security flags and buffer size */
  do
    rc = imap_cmd_step(adata);
  while (rc == IMAP_CMD_CONTINUE);

  if (rc != IMAP_CMD_RESPOND)
  {
    mutt_debug(LL_DEBUG1, "#2 Error receiving server response\n");
    goto bail;
  }
  if (mutt_b64_buffer_decode(buf2, adata->buf + 2) < 0)
  {
    mutt_debug(LL_DEBUG1, "Invalid base64 server response\n");
    goto err_abort_cmd;
  }
  request_buf.value = buf2->data;
  request_buf.length = mutt_buffer_len(buf2);

  maj_stat = gss_unwrap(&min_stat, context, &request_buf, &send_token, &cflags, &quality);
  if (maj_stat != GSS_S_COMPLETE)
  {
    print_gss_error(maj_stat, min_stat);
    mutt_debug(LL_DEBUG2, "Couldn't unwrap security level data\n");
    gss_release_buffer(&min_stat, &send_token);
    goto err_abort_cmd;
  }
  mutt_debug(LL_DEBUG2, "Credential exchange complete\n");

  /* first octet is security levels supported. We want NONE */
  server_conf_flags = ((char *) send_token.value)[0];
  if (!(((char *) send_token.value)[0] & GSS_AUTH_P_NONE))
  {
    mutt_debug(LL_DEBUG2, "Server requires integrity or privacy\n");
    gss_release_buffer(&min_stat, &send_token);
    goto err_abort_cmd;
  }

  /* we don't care about buffer size if we don't wrap content. But here it is */
  ((char *) send_token.value)[0] = '\0';
  buf_size = ntohl(*((long *) send_token.value));
  gss_release_buffer(&min_stat, &send_token);
  mutt_debug(LL_DEBUG2, "Unwrapped security level flags: %c%c%c\n",
             (server_conf_flags & GSS_AUTH_P_NONE) ? 'N' : '-',
             (server_conf_flags & GSS_AUTH_P_INTEGRITY) ? 'I' : '-',
             (server_conf_flags & GSS_AUTH_P_PRIVACY) ? 'P' : '-');
  mutt_debug(LL_DEBUG2, "Maximum GSS token size is %ld\n", buf_size);

  /* agree to terms (hack!) */
  buf_size = htonl(buf_size); /* not relevant without integrity/privacy */
  mutt_buffer_reset(buf1);
  mutt_buffer_addch(buf1, GSS_AUTH_P_NONE);
  mutt_buffer_addstr_n(buf1, ((char *) &buf_size) + 1, 3);
  /* server decides if principal can log in as user */
  mutt_buffer_addstr(buf1, adata->conn->account.user);
  request_buf.value = buf1->data;
  request_buf.length = mutt_buffer_len(buf1);
  maj_stat = gss_wrap(&min_stat, context, 0, GSS_C_QOP_DEFAULT, &request_buf,
                      &cflags, &send_token);
  if (maj_stat != GSS_S_COMPLETE)
  {
    mutt_debug(LL_DEBUG2, "Error creating login request\n");
    goto err_abort_cmd;
  }

  mutt_b64_buffer_encode(buf1, send_token.value, send_token.length);
  mutt_debug(LL_DEBUG2, "Requesting authorisation as %s\n", adata->conn->account.user);
  mutt_buffer_addstr(buf1, "\r\n");
  mutt_socket_send(adata->conn, mutt_b2s(buf1));

  /* Joy of victory or agony of defeat? */
  do
    rc = imap_cmd_step(adata);
  while (rc == IMAP_CMD_CONTINUE);
  if (rc == IMAP_CMD_RESPOND)
  {
    mutt_debug(LL_DEBUG1, "Unexpected server continuation request\n");
    goto err_abort_cmd;
  }
  if (imap_code(adata->buf))
  {
    /* flush the security context */
    mutt_debug(LL_DEBUG2, "Releasing GSS credentials\n");
    maj_stat = gss_delete_sec_context(&min_stat, &context, &send_token);
    if (maj_stat != GSS_S_COMPLETE)
      mutt_debug(LL_DEBUG1, "Error releasing credentials\n");

    /* send_token may contain a notification to the server to flush
     * credentials. RFC1731 doesn't specify what to do, and since this
     * support is only for authentication, we'll assume the server knows
     * enough to flush its own credentials */
    gss_release_buffer(&min_stat, &send_token);

    retval = IMAP_AUTH_SUCCESS;
    goto cleanup;
  }
  else
    goto bail;

err_abort_cmd:
  mutt_socket_send(adata->conn, "*\r\n");
  do
    rc = imap_cmd_step(adata);
  while (rc == IMAP_CMD_CONTINUE);

bail:
  mutt_error(_("GSSAPI authentication failed"));
  retval = IMAP_AUTH_FAILURE;

cleanup:
  mutt_buffer_pool_release(&buf1);
  mutt_buffer_pool_release(&buf2);

  return retval;
}
Esempio n. 29
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);
}
Esempio n. 30
0
int
delegate_proxy(const char *proxy_file, gss_cred_id_t cred_handle, gss_ctx_id_t gss_context, int sck)
{
	int return_status = BPR_DELEGATE_PROXY_ERROR;
	int send_status;
	gss_buffer_desc  input_token, output_token;
	gss_buffer_desc  rcv_token, snd_token;
	OM_uint32        del_maj_stat, maj_stat, min_stat;
	int conf_req_flag = 1; /* Non zero value to request confidentiality */

	if (gss_context != GSS_C_NO_CONTEXT)
	{
		/* Bootstrap call */
		del_maj_stat = gss_init_delegation(&min_stat,
					gss_context,
				        cred_handle,
					GSS_C_NO_OID,
					GSS_C_NO_OID_SET,
					GSS_C_NO_BUFFER_SET,
					GSS_C_NO_BUFFER,
					GSS_C_GLOBUS_SSL_COMPATIBLE,
					0,
					&snd_token);

		while (1) /* Will break after the last token has been sent */
		{

			maj_stat = gss_wrap(
					&min_stat,
					gss_context,
					conf_req_flag,
					GSS_C_QOP_DEFAULT,
					&snd_token,
					NULL,
					&output_token);
			gss_release_buffer(&min_stat, &snd_token);

			if (!GSS_ERROR(maj_stat))
			{
				send_status = send_token((void*)&sck, output_token.value, output_token.length);
				gss_release_buffer(&min_stat, &output_token);
				if (send_status < 0)
				{
					break;
				}
			}
			else 
			{
				break;
			}
			if (del_maj_stat != GSS_S_CONTINUE_NEEDED) break;

			if (get_token(&sck, &input_token.value, &input_token.length) < 0) break;
			maj_stat = gss_unwrap(
					&min_stat,
					gss_context,
					&input_token,
					&rcv_token,
					NULL,
					NULL);
	
			gss_release_buffer(&min_stat, &input_token);

			del_maj_stat = gss_init_delegation(&min_stat,
						gss_context,
					        cred_handle,
						GSS_C_NO_OID,
						GSS_C_NO_OID_SET,
						GSS_C_NO_BUFFER_SET,
						&rcv_token,
						GSS_C_GLOBUS_SSL_COMPATIBLE,
						0,
						&snd_token);
			gss_release_buffer(&min_stat, &rcv_token);
		}
	}

	if (del_maj_stat == GSS_S_COMPLETE) return_status = BPR_DELEGATE_PROXY_OK;

	return return_status;

}