Beispiel #1
0
int
_gsasl_anonymous_server_step (Gsasl_session * sctx,
			      void *mech_data,
			      const char *input, size_t input_len,
			      char **output, size_t * output_len)
{
  *output = NULL;
  *output_len = 0;

  if (!input)
    return GSASL_NEEDS_MORE;

  /* token       = 1*255TCHAR
     The <token> production is restricted to 255 UTF-8 encoded Unicode
     characters.   As the encoding of a characters uses a sequence of 1
     to 4 octets, a token may be long as 1020 octets. */
  if (input_len == 0 || input_len > 1020)
    return GSASL_MECHANISM_PARSE_ERROR;

  /* FIXME: Validate that input is UTF-8. */

  gsasl_property_set_raw (sctx, GSASL_ANONYMOUS_TOKEN, input, input_len);

  return gsasl_callback (NULL, sctx, GSASL_VALIDATE_ANONYMOUS);
}
Beispiel #2
0
/**
 * gsasl_property_get:
 * @sctx: session handle.
 * @prop: enumerated value of Gsasl_property type, indicating the
 *        type of data in @data.
 *
 * Retrieve the data stored in the session handle for given property
 * @prop, possibly invoking the application callback to get the value.
 *
 * The pointer is to live data, and must not be deallocated or
 * modified in any way.
 *
 * This function will invoke the application callback, using
 * gsasl_callback(), when a property value is not known.
 *
 * If no value is known, and no callback is specified or if the
 * callback fail to return data, and if any obsolete callback
 * functions has been set by the application, this function will try
 * to call these obsolete callbacks, and store the returned data as
 * the corresponding property.  This behaviour of this function will
 * be removed when the obsolete callback interfaces are removed.
 *
 * Return value: Return data for property, or NULL if no value known.
 *
 * Since: 0.2.0
 **/
const char *
gsasl_property_get (Gsasl_session * sctx, Gsasl_property prop)
{
  const char *p = gsasl_property_fast (sctx, prop);

  if (!p)
    {
      gsasl_callback (NULL, sctx, prop);
      p = gsasl_property_fast (sctx, prop);
    }

#ifndef GSASL_NO_OBSOLETE
  if (!p)
    p = _gsasl_obsolete_property_map (sctx, prop);
#endif

  return p;
}
Beispiel #3
0
int
_gsasl_securid_server_step (Gsasl_session * sctx,
			    void *mech_data,
			    const char *input, size_t input_len,
			    char **output, size_t * output_len)
{
  const char *authorization_id = NULL;
  const char *authentication_id = NULL;
  const char *passcode = NULL;
  const char *suggestedpin;
  char *pin = NULL;
  int res;
  size_t len;

  if (input_len == 0)
    {
      *output_len = 0;
      *output = NULL;
      return GSASL_NEEDS_MORE;
    }

  authorization_id = input;
  authentication_id = memchr (input, '\0', input_len - 1);
  if (authentication_id)
    {
      authentication_id++;
      passcode = memchr (authentication_id, '\0',
			 input_len - strlen (authorization_id) - 1 - 1);
      if (passcode)
	{
	  passcode++;
	  pin = memchr (passcode, '\0', input_len -
			strlen (authorization_id) - 1 -
			strlen (authentication_id) - 1 - 1);
	  if (pin)
	    {
	      pin++;
	      if (pin && !*pin)
		pin = NULL;
	    }
	}
    }

  if (passcode == NULL)
    return GSASL_MECHANISM_PARSE_ERROR;

  gsasl_property_set (sctx, GSASL_AUTHID, authentication_id);
  gsasl_property_set (sctx, GSASL_AUTHZID, authorization_id);
  gsasl_property_set (sctx, GSASL_PASSCODE, passcode);
  if (pin)
    gsasl_property_set (sctx, GSASL_PIN, pin);
  else
    gsasl_property_set (sctx, GSASL_PIN, NULL);

  res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_SECURID);
  switch (res)
    {
    case GSASL_SECURID_SERVER_NEED_ADDITIONAL_PASSCODE:
      *output = strdup (PASSCODE);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      *output_len = strlen (PASSCODE);
      res = GSASL_NEEDS_MORE;
      break;

    case GSASL_SECURID_SERVER_NEED_NEW_PIN:
      suggestedpin = gsasl_property_get (sctx, GSASL_SUGGESTED_PIN);
      if (suggestedpin)
	len = strlen (suggestedpin);
      else
	len = 0;
      *output_len = strlen (PIN) + len;
      *output = malloc (*output_len);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      memcpy (*output, PIN, strlen (PIN));
      if (suggestedpin)
	memcpy (*output + strlen (PIN), suggestedpin, len);
      res = GSASL_NEEDS_MORE;
      break;

    default:
      *output_len = 0;
      *output = NULL;
      break;
    }

  return res;
}
Beispiel #4
0
int
_gsasl_gssapi_server_step (Gsasl_session * sctx,
			   void *mech_data,
			   const char *input, size_t input_len,
			   char **output, size_t * output_len)
{
  _Gsasl_gssapi_server_state *state = mech_data;
  gss_buffer_desc bufdesc1, bufdesc2;
  OM_uint32 maj_stat, min_stat;
  gss_buffer_desc client_name;
  gss_OID mech_type;
  char tmp[4];
  int res;

  *output = NULL;
  *output_len = 0;

  switch (state->step)
    {
    case 0:
      if (input_len == 0)
	{
	  res = GSASL_NEEDS_MORE;
	  break;
	}
      state->step++;
      /* fall through */

    case 1:
      bufdesc1.value = (void *) input;
      bufdesc1.length = input_len;
      if (state->client)
	{
	  gss_release_name (&min_stat, &state->client);
	  state->client = GSS_C_NO_NAME;
	}

      maj_stat = gss_accept_sec_context (&min_stat,
					 &state->context,
					 state->cred,
					 &bufdesc1,
					 GSS_C_NO_CHANNEL_BINDINGS,
					 &state->client,
					 &mech_type,
					 &bufdesc2, NULL, NULL, NULL);
      if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
	return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR;

      *output = malloc (bufdesc2.length);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      memcpy (*output, bufdesc2.value, bufdesc2.length);
      *output_len = bufdesc2.length;

      maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;

      if (maj_stat == GSS_S_COMPLETE)
	state->step++;

      res = GSASL_NEEDS_MORE;
      break;

    case 2:
      memset (tmp, 0xFF, 4);
      tmp[0] = GSASL_QOP_AUTH;
      bufdesc1.length = 4;
      bufdesc1.value = tmp;
      maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
			   &bufdesc1, NULL, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_WRAP_ERROR;

      *output = malloc (bufdesc2.length);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      memcpy (*output, bufdesc2.value, bufdesc2.length);
      *output_len = bufdesc2.length;

      maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;

      state->step++;
      res = GSASL_NEEDS_MORE;
      break;

    case 3:
      bufdesc1.value = (void *) input;
      bufdesc1.length = input_len;
      maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc1,
			     &bufdesc2, NULL, NULL);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_UNWRAP_ERROR;

      /* [RFC 2222 section 7.2.1]:
         The client passes this token to GSS_Unwrap and interprets the
         first octet of resulting cleartext as a bit-mask specifying
         the security layers supported by the server and the second
         through fourth octets as the maximum size output_message to
         send to the server.  The client then constructs data, with
         the first octet containing the bit-mask specifying the
         selected security layer, the second through fourth octets
         containing in network byte order the maximum size
         output_message the client is able to receive, and the
         remaining octets containing the authorization identity.  The
         client passes the data to GSS_Wrap with conf_flag set to
         FALSE, and responds with the generated output_message.  The
         client can then consider the server authenticated. */

      if ((((char *) bufdesc2.value)[0] & GSASL_QOP_AUTH) == 0)
	{
	  /* Integrity or privacy unsupported */
	  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
	  return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
	}

      gsasl_property_set_raw (sctx, GSASL_AUTHZID,
			      (char *) bufdesc2.value + 4,
			      bufdesc2.length - 4);

      maj_stat = gss_display_name (&min_stat, state->client,
				   &client_name, &mech_type);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_DISPLAY_NAME_ERROR;

      gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME,
			      client_name.value, client_name.length);

      maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;

      res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);

      state->step++;
      break;

    default:
      res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
      break;
    }

  return res;
}
Beispiel #5
0
int
_gsasl_login_server_step (Gsasl_session * sctx,
			  void *mech_data,
			  const char *input, size_t input_len,
			  char **output, size_t * output_len)
{
  struct _Gsasl_login_server_state *state = mech_data;
  int res;

  switch (state->step)
    {
    case 0:
      *output = strdup (CHALLENGE_USERNAME);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      *output_len = strlen (CHALLENGE_USERNAME);

      state->step++;
      res = GSASL_NEEDS_MORE;
      break;

    case 1:
      if (input_len == 0)
	return GSASL_MECHANISM_PARSE_ERROR;

      state->username = malloc (input_len + 1);
      if (state->username == NULL)
	return GSASL_MALLOC_ERROR;

      memcpy (state->username, input, input_len);
      state->username[input_len] = '\0';

      *output = strdup (CHALLENGE_PASSWORD);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      *output_len = strlen (CHALLENGE_PASSWORD);

      state->step++;
      res = GSASL_NEEDS_MORE;
      break;

    case 2:
      if (input_len == 0)
	return GSASL_MECHANISM_PARSE_ERROR;

      state->password = malloc (input_len + 1);
      if (state->password == NULL)
	return GSASL_MALLOC_ERROR;

      memcpy (state->password, input, input_len);
      state->password[input_len] = '\0';

      if (input_len != strlen (state->password))
	return GSASL_MECHANISM_PARSE_ERROR;

      gsasl_property_set (sctx, GSASL_AUTHID, state->username);
      gsasl_property_set (sctx, GSASL_PASSWORD, state->password);

      res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_SIMPLE);
      if (res == GSASL_NO_CALLBACK)
	{
	  const char *key;

	  gsasl_property_set (sctx, GSASL_AUTHZID, NULL);
	  gsasl_property_set (sctx, GSASL_PASSWORD, NULL);

	  key = gsasl_property_get (sctx, GSASL_PASSWORD);

	  if (key && strlen (state->password) == strlen (key) &&
	      strcmp (state->password, key) == 0)
	    res = GSASL_OK;
	  else
	    res = GSASL_AUTHENTICATION_ERROR;
	}

      *output_len = 0;
      *output = NULL;
      state->step++;
      break;

    default:
      res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
      break;
    }

  return res;
}
Beispiel #6
0
int
_gsasl_openid20_client_step (Gsasl_session * sctx,
			     void *mech_data,
			     const char *input, size_t input_len,
			     char **output, size_t * output_len)
{
  struct openid20_client_state *state = mech_data;
  int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;

  switch (state->step)
    {
    case 0:
      {
	const char *authzid = gsasl_property_get (sctx, GSASL_AUTHZID);
	const char *authid = gsasl_property_get (sctx, GSASL_AUTHID);

	if (!authid || !*authid)
	  return GSASL_NO_AUTHID;

	res = _gsasl_gs2_generate_header (false, 'n', NULL, authzid,
					  strlen (authid), authid,
					  output, output_len);
	if (res != GSASL_OK)
	  return res;

	res = GSASL_NEEDS_MORE;
	state->step++;
      }
      break;

    case 1:
      {
	gsasl_property_set_raw (sctx, GSASL_OPENID20_REDIRECT_URL,
				input, input_len);

	res = gsasl_callback (NULL, sctx,
			      GSASL_OPENID20_AUTHENTICATE_IN_BROWSER);
	if (res != GSASL_OK)
	  return res;

	*output_len = 1;
	*output = strdup ("=");
	if (!*output)
	  return GSASL_MALLOC_ERROR;

	res = GSASL_OK;
	state->step++;
      }
      break;

      /* This step is optional.  The server could have approved
         authentication already.  Alternatively, it wanted to send
         some SREGs or error data and we end up here. */
    case 2:
      {
	gsasl_property_set_raw (sctx, GSASL_OPENID20_OUTCOME_DATA,
				input, input_len);

	/* In the case of failures, the response MUST follow this
	   syntax:

	   outcome_data = "openid.error" "=" sreg_val *( "," sregp_avp )

	   [RFC4422] Section 3.6 explicitly prohibits additional information in
	   an unsuccessful authentication outcome.  Therefore, the openid.error
	   and openid.error_code are to be sent as an additional challenge in
	   the event of an unsuccessful outcome.  In this case, as the protocol
	   is lock step,  the client will follow with an additional exchange
	   containing "=", after which the server will respond with an
	   application-level outcome.
	 */

#define ERR_PREFIX "openid.error="
	if (input_len > strlen (ERR_PREFIX)
	    && strncmp (ERR_PREFIX, input, strlen (ERR_PREFIX)) == 0)
	  {
	    *output_len = 1;
	    *output = strdup ("=");
	    if (!*output)
	      return GSASL_MALLOC_ERROR;

	    res = GSASL_NEEDS_MORE;
	  }
	else
	  {
	    *output_len = 0;
	    *output = NULL;

	    res = GSASL_OK;
	  }

	state->step++;
      }
      break;

    default:
      break;
    }

  return res;
}