Example #1
0
File: server.c Project: cktan/tool2
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);
}
Example #2
0
/**
 * gsasl_callback:
 * @ctx: handle received from gsasl_init(), may be NULL to derive it
 *   from @sctx.
 * @sctx: session handle.
 * @prop: enumerated value of Gsasl_property type.
 *
 * Invoke the application callback.  The @prop value indicate what the
 * callback is expected to do.  For example, for
 * GSASL_ANONYMOUS_TOKEN, the function is expected to invoke
 * gsasl_property_set(SCTX, GSASL_ANONYMOUS_TOKEN, "token") where
 * "token" is the anonymous token the application wishes the SASL
 * mechanism to use.  See the manual for the meaning of all
 * parameters.
 *
 * Note that if no callback has been set by the application, but the
 * obsolete callback interface has been used, this function will
 * translate the old callback interface into the new.  This interface
 * should be sufficient to invoke all callbacks, both new and old.
 *
 * Return value: Returns whatever the application callback return, or
 *   GSASL_NO_CALLBACK if no application was known.
 *
 * Since: 0.2.0
 **/
int
gsasl_callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
{
  if (ctx == NULL && sctx == NULL)
    return GSASL_NO_CALLBACK;

  if (ctx == NULL)
    ctx = sctx->ctx;

  if (ctx->cb)
    return ctx->cb (ctx, sctx, prop);

#ifndef GSASL_NO_OBSOLETE
  {
    /* Call obsolete callbacks.  Remove this when the obsolete
     * callbacks are no longer supported.  */
    Gsasl_server_callback_anonymous cb_anonymous;
    Gsasl_server_callback_external cb_external;
    Gsasl_server_callback_securid cb_securid;
    Gsasl_server_callback_gssapi cb_gssapi;
    Gsasl_server_callback_validate cb_validate;
    Gsasl_server_callback_retrieve cb_retrieve;
    char buf[BUFSIZ];
    size_t buflen = BUFSIZ - 1;
    int res;

    switch (prop)
      {
      case GSASL_VALIDATE_ANONYMOUS:
	if (!sctx->anonymous_token)
	  break;
	cb_anonymous = gsasl_server_callback_anonymous_get (sctx->ctx);
	if (!cb_anonymous)
	  break;
	res = cb_anonymous (sctx, sctx->anonymous_token);
	return res;
	break;

      case GSASL_VALIDATE_EXTERNAL:
	cb_external = gsasl_server_callback_external_get (sctx->ctx);
	if (!cb_external)
	  break;
	res = cb_external (sctx);
	return res;
	break;

      case GSASL_VALIDATE_SECURID:
	cb_securid = gsasl_server_callback_securid_get (sctx->ctx);
	if (!cb_securid)
	  break;
	res = cb_securid (sctx, sctx->authid, sctx->authzid, sctx->passcode,
			  sctx->pin, buf, &buflen);
	if (buflen > 0 && buflen < BUFSIZ - 1)
	  {
	    buf[buflen] = '\0';
	    gsasl_property_set (sctx, GSASL_SUGGESTED_PIN, buf);
	  }
	return res;
	break;

      case GSASL_VALIDATE_GSSAPI:
	cb_gssapi = gsasl_server_callback_gssapi_get (sctx->ctx);
	if (!cb_gssapi)
	  break;
	res = cb_gssapi (sctx, sctx->gssapi_display_name, sctx->authzid);
	return res;
	break;

      case GSASL_VALIDATE_SIMPLE:
	cb_validate = gsasl_server_callback_validate_get (sctx->ctx);
	if (!cb_validate)
	  break;
	res = cb_validate (sctx, sctx->authzid, sctx->authid, sctx->password);
	return res;
	break;

      case GSASL_PASSWORD:
	cb_retrieve = gsasl_server_callback_retrieve_get (sctx->ctx);
	if (!cb_retrieve)
	  break;
	res = cb_retrieve (sctx, sctx->authid, sctx->authzid,
			   sctx->hostname, &buf, &buflen);
	if (res == GSASL_OK)
	  gsasl_property_set_raw (sctx, GSASL_PASSWORD, buf, buflen);
	/* FIXME else if (res == GSASL_TOO_SMALL_BUFFER)... */
	return res;
	break;

      default:
	break;
      }
  }
#endif

  return GSASL_NO_CALLBACK;
}
Example #3
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;
}
Example #4
0
/**
 * gsasl_property_set:
 * @sctx: session handle.
 * @prop: enumerated value of Gsasl_property type, indicating the
 *        type of data in @data.
 * @data: zero terminated character string to store.
 *
 * Make a copy of @data and store it in the session handle for the
 * indicated property @prop.
 *
 * You can immediately deallocate @data after calling this function,
 * without affecting the data stored in the session handle.
 *
 * Since: 0.2.0
 **/
void
gsasl_property_set (Gsasl_session * sctx, Gsasl_property prop,
		    const char *data)
{
  gsasl_property_set_raw (sctx, prop, data, data ? strlen (data) : 0);
}
Example #5
0
File: client.c Project: cktan/tool2
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;
}