Exemple #1
0
static void
client (Gsasl * ctx)
{
  Gsasl_session *session;
  const char *mech = "PLAIN";
  int rc;

  /* Create new authentication session. */
  if ((rc = gsasl_client_start (ctx, mech, &session)) != GSASL_OK)
    {
      printf ("Cannot initialize client (%d): %s\n", rc, gsasl_strerror (rc));
      return;
    }

  /* Set username and password in session handle.  This info will be
     lost when this session is deallocated below.  */
  gsasl_property_set (session, GSASL_AUTHID, "jas");
  gsasl_property_set (session, GSASL_PASSWORD, "secret");

  /* Do it. */
  client_authenticate (session);

  /* Cleanup. */
  gsasl_finish (session);
}
Exemple #2
0
static int
callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
{
  int rc = GSASL_NO_CALLBACK;

  switch (prop)
    {
    case GSASL_AUTHZID:
      if (*AUTHZID[i])
	{
	  gsasl_property_set (sctx, GSASL_AUTHZID, AUTHZID[i]);
	  rc = GSASL_OK;
	}
      break;

    case GSASL_SERVICE:
      gsasl_property_set (sctx, prop, SERVICE);
      rc = GSASL_OK;
      break;

    case GSASL_HOSTNAME:
      gsasl_property_set (sctx, prop, HOST);
      rc = GSASL_OK;
      break;

    case GSASL_VALIDATE_GSSAPI:
      {
	const char *client_name =
	  gsasl_property_fast (sctx, GSASL_GSSAPI_DISPLAY_NAME);
	const char *authzid = gsasl_property_fast (sctx, GSASL_AUTHZID);

	if (client_name)
	  printf ("GSSAPI user: %s\n", client_name);
	else
	  fail ("no client name\n");
	if (authzid)
	  printf ("Authorization ID: %s\n", authzid);

	if (client_name && strcmp (client_name, GSSAPI_USER) == 0 &&
	    ((authzid == NULL && *AUTHZID[i] == '\0')
	     || strcmp (authzid, AUTHZID[i]) == 0))
	  rc = GSASL_OK;
	else
	  rc = GSASL_AUTHENTICATION_ERROR;
      }
      break;

    default:
      fail ("Unknown callback property %d\n", prop);
      break;
    }

  return rc;
}
Exemple #3
0
static int
callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
{
  char buf[BUFSIZ] = "";
  int rc = GSASL_NO_CALLBACK;
  char *p;

  /* Get user info from user. */

  printf ("Callback invoked, for property %d.\n", prop);

  switch (prop)
    {
    case GSASL_PASSCODE:
      printf ("Enter passcode:\n");
      p = fgets (buf, sizeof (buf) - 1, stdin);
      if (p == NULL)
	{
	  perror ("fgets");
	  break;
	}
      buf[strlen (buf) - 1] = '\0';

      gsasl_property_set (sctx, GSASL_PASSCODE, buf);
      rc = GSASL_OK;
      break;

    case GSASL_AUTHID:
      printf ("Enter username:\n");
      p = fgets (buf, sizeof (buf) - 1, stdin);
      if (p == NULL)
	{
	  perror ("fgets");
	  break;
	}
      buf[strlen (buf) - 1] = '\0';

      gsasl_property_set (sctx, GSASL_AUTHID, buf);
      rc = GSASL_OK;
      break;

    default:
      printf ("Unknown property!  Don't worry.\n");
      break;
    }

  return rc;
}
// static
int SASLSession::gsaslCallback
	(Gsasl* ctx, Gsasl_session* sctx, Gsasl_property prop)
{
	SASLSession* sess = reinterpret_cast <SASLSession*>(gsasl_callback_hook_get(ctx));
	if (!sess) return GSASL_AUTHENTICATION_ERROR;

	shared_ptr <authenticator> auth = sess->getAuthenticator();

	try
	{
		string res;

		switch (prop)
		{
		case GSASL_AUTHID:

			res = auth->getUsername();
			break;

		case GSASL_PASSWORD:

			res = auth->getPassword();
			break;

		case GSASL_ANONYMOUS_TOKEN:

			res = auth->getAnonymousToken();
			break;

		case GSASL_HOSTNAME:

			res = auth->getHostname();
			break;

		case GSASL_SERVICE:

			res = auth->getServiceName();
			break;

		case GSASL_AUTHZID:
		case GSASL_GSSAPI_DISPLAY_NAME:
		case GSASL_PASSCODE:
		case GSASL_SUGGESTED_PIN:
		case GSASL_PIN:
		case GSASL_REALM:

		default:

			return GSASL_NO_CALLBACK;
		}

		gsasl_property_set(sctx, prop, res.c_str());

		return GSASL_OK;
	}
	catch (...)
	{
		return GSASL_NO_CALLBACK;
	}
}
Exemple #5
0
static int
callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
{
  int rc = GSASL_NO_CALLBACK;

  /* Get user info from user. */

  switch (prop)
    {
    case GSASL_SAML20_IDP_IDENTIFIER:
      gsasl_property_set (sctx, prop, "https://saml.example.org/");
      rc = GSASL_OK;
      break;

    case GSASL_SAML20_AUTHENTICATE_IN_BROWSER:
      printf ("client got redirect URL: %s\n",
	      gsasl_property_get (sctx, GSASL_SAML20_REDIRECT_URL));
      rc = GSASL_OK;
      break;

    default:
      printf ("Unknown property %d!  Don't worry.\n", prop);
      break;
    }

  return rc;
}
Exemple #6
0
static char *
sasl_auth_plain(
	char *user,
	char *pass)
{
	Gsasl *ctx = NULL;
	Gsasl_session *session;
	char *p = NULL;
	const char *mech = "PLAIN";

	if (gsasl_init(&ctx) != GSASL_OK) /* TODO: do this only once at startup */
		return p;
	if (gsasl_client_start(ctx, mech, &session) != GSASL_OK) {
		gsasl_done(ctx);
		return p;
	}
	gsasl_property_set(session, GSASL_AUTHID, user);
	gsasl_property_set(session, GSASL_PASSWORD, pass);
	if (gsasl_step64(session, NULL, &p) != GSASL_OK)
		FreeAndNull(p);
	gsasl_finish(session);
	gsasl_done(ctx);
	return p;
}
Exemple #7
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;
}
Exemple #8
0
static int
callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
{
    int rc = GSASL_OK;
    struct sasl_data *pdata;
    const char *user;
    char *string;

    switch (prop) {
    case GSASL_PASSWORD:
	pdata = gsasl_callback_hook_get(ctx);
	user = pdata->username;
	if (!user) {
	    user = gsasl_property_get(sctx, GSASL_AUTHID);
	    if (!user) {
		dico_log(L_ERR, 0, _("user name not supplied"));
		return GSASL_NO_AUTHID;
	    }
	    pdata->username = user;
	}
	if (dico_udb_get_password(user_db, user, &string)) {
	    dico_log(L_ERR, 0,
		     _("failed to get password for `%s' from the database"),
		     user);
	    return GSASL_NO_PASSWORD;
	} 
	gsasl_property_set(sctx, prop, string);
	free(string);
	break;

    case GSASL_SERVICE:
	gsasl_property_set(sctx, prop, sasl_service);
	break;

    case GSASL_REALM:
	gsasl_property_set(sctx, prop, sasl_realm ? sasl_realm : hostname);
	break;

    case GSASL_HOSTNAME:
	gsasl_property_set(sctx, prop, hostname);
	break;

    case GSASL_VALIDATE_SIMPLE:
	rc = cb_validate(ctx, sctx);
	break;

#if 0
    FIXME:
    case GSASL_VALIDATE_EXTERNAL:
    case GSASL_VALIDATE_SECURID:
#endif

    case GSASL_VALIDATE_ANONYMOUS:
	pdata = gsasl_callback_hook_get(ctx);
	user = gsasl_property_get(sctx, GSASL_ANONYMOUS_TOKEN);
	pdata->username = user;
	pdata->anon = 1;
	break;

    case GSASL_VALIDATE_GSSAPI:
	pdata = gsasl_callback_hook_get(ctx);
	user = gsasl_property_get(sctx, GSASL_AUTHZID);
	pdata->username = user;
	break;
	
    default:
	rc = GSASL_NO_CALLBACK;
	/*dico_log(L_NOTICE, 0, _("Unsupported callback property %d"), prop);*/
	break;
    }

    return rc;
}
static void sasl_authenticate( SV *client, mongo_link *link ) { 
  Gsasl *ctx = NULL;
  Gsasl_session *session;
  SV *username, *mechanism, *conv_id;
  HV *result;       /* response document from mongod */
  char *p, *buf;    /* I/O buffers for gsasl */
  int rc;
  char out_buf[8192];

  mechanism = perl_mongo_call_method( client, "sasl_mechanism", 0, 0 );
  if ( !SvOK( mechanism ) ) { 
    croak( "MongoDB: Could not retrieve SASL mechanism from client object\n" );
  }

  if ( strncmp( "PLAIN", SvPV_nolen( mechanism ), 5 ) == 0 ) { 
    /* SASL PLAIN does not require a libgsasl conversation loop, so we can handle it elsewhere */
    return perl_mongo_call_method( client, "_sasl_plain_authenticate", 0, 0 );
  }

  if ( ( rc = gsasl_init( &ctx ) ) != GSASL_OK ) { 
    croak( "MongoDB: Cannot initialize libgsasl (%d): %s\n", rc, gsasl_strerror(rc) );  
  }

  if ( ( rc = gsasl_client_start( ctx, SvPV_nolen( mechanism ), &session ) ) != GSASL_OK ) { 
    croak( "MongoDB: Cannot initialize SASL client (%d): %s\n", rc, gsasl_strerror(rc) );
  }

  username = perl_mongo_call_method( client, "username", 0, 0 );
  if ( !SvOK( username ) ) { 
    croak( "MongoDB: Cannot start SASL session without username. Specify username in constructor\n" );
  }
 
  gsasl_property_set( session, GSASL_SERVICE,  "mongodb" );
  gsasl_property_set( session, GSASL_HOSTNAME, link->master->host );
  gsasl_property_set( session, GSASL_AUTHID,   SvPV_nolen( username ) ); 

  rc = gsasl_step64( session, "", &p );
  if ( ( rc != GSASL_OK ) && ( rc != GSASL_NEEDS_MORE ) ) { 
    croak( "MongoDB: No data from GSSAPI. Did you run kinit?\n" );
  }

  if ( ! strncpy( out_buf, p, 8192 ) ) {
    croak( "MongoDB: Unable to copy SASL output buffer\n" );
  }
  gsasl_free( p );

  result = (HV *)SvRV( perl_mongo_call_method( client, "_sasl_start", 0, 2, newSVpv( out_buf, 0 ), mechanism ) );

#if 0  
  fprintf( stderr, "result conv id = [%s]\n", SvPV_nolen( *hv_fetch( result, "conversationId", 14, FALSE ) ) );
  fprintf( stderr, "result payload = [%s]\n", SvPV_nolen( *hv_fetch( result, "payload",         7, FALSE ) ) );
#endif

  buf = SvPV_nolen( *hv_fetch( result, "payload", 7, FALSE ) );
  conv_id = *hv_fetch( result, "conversationId", 14, FALSE ); 
 
  do { 
    rc = gsasl_step64( session, buf, &p );
    if ( ( rc != GSASL_OK ) && ( rc != GSASL_NEEDS_MORE ) ) {
      croak( "MongoDB: SASL step error (%d): %s\n", rc, gsasl_strerror(rc) );
    }

    if ( ! strncpy( out_buf, p, 8192 ) ) { 
      croak( "MongoDB: Unable to copy SASL output buffer\n" );
    }
    gsasl_free( p );

    result = (HV *)SvRV( perl_mongo_call_method( client, "_sasl_continue", 0, 2, newSVpv( out_buf, 0 ), conv_id ) );
#if 0 
    fprintf( stderr, "result conv id = [%s]\n", SvPV_nolen( *hv_fetch( result, "conversationId", 14, FALSE ) ) );
    fprintf( stderr, "result payload = [%s]\n", SvPV_nolen( *hv_fetch( result, "payload",         7, FALSE ) ) );
#endif

    buf = SvPV_nolen( *hv_fetch( result, "payload", 7, FALSE ) );

  } while( rc == GSASL_NEEDS_MORE );

  if ( rc != GSASL_OK ) { 
    croak( "MongoDB: SASL Authentication error (%d): %s\n", rc, gsasl_strerror(rc) );
  }

  gsasl_finish( session );
  gsasl_done( ctx );
}
Exemple #10
0
static int
callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
{
  int rc = GSASL_NO_CALLBACK;
  struct cfg *cfg = gsasl_callback_hook_get (ctx);

  switch (prop)
    {
    case GSASL_SAML20_REDIRECT_URL:
      {
	FILE *fh;
	char *reqid, *redirect_url, *tmp;
	size_t n = 0;
	const char *idp =
	  gsasl_property_get (sctx, GSASL_SAML20_IDP_IDENTIFIER);

	/* User did not provide a SAML IdP identifier. */
	if (!idp)
	  return GSASL_AUTHENTICATION_ERROR;

	/* Sanitize input. */
	if (strcmp (idp, ".") == 0 || strcmp (idp, "..") == 0)
	  return GSASL_AUTHENTICATION_ERROR;
	for (n = 0; idp[n]; n++)
	  if (!((idp[n] >= 'a' && idp[n] <= 'z')
		|| (idp[n] >= 'A' && idp[n] <= 'Z')
		|| (idp[n] >= '0' && idp[n] <= '9') || idp[n] == '.'))
	    {
	      printf ("Cannot handle identifier (%ld): %s\n",
		      (unsigned long) n, idp);
	      return GSASL_AUTHENTICATION_ERROR;
	    }

	/* Run helper to generate SAML AuthnRequest.   Read out request ID. */
	rc = asprintf (&tmp, "gsasl-saml20-request %s %s %s %s "
		       "%s/%s/idp-metadata.xml",
		       cfg->state_path, cfg->sp_metadata,
		       cfg->sp_key, cfg->sp_cert, cfg->cfg_path, idp);
	if (rc <= 0)
	  return GSASL_AUTHENTICATION_ERROR;
	fh = popen (tmp, "r");
	free (tmp);
	if (!fh)
	  {
	    perror ("popen");
	    return GSASL_AUTHENTICATION_ERROR;
	  }
	reqid = NULL;
	n = 0;
	if (getline (&reqid, &n, fh) <= 0)
	  {
	    perror ("getline");
	    return GSASL_AUTHENTICATION_ERROR;
	  }
	if (reqid[strlen (reqid) - 1] == '\n')
	  reqid[strlen (reqid) - 1] = '\0';
	if (reqid[strlen (reqid) - 1] == '\r')
	  reqid[strlen (reqid) - 1] = '\0';
	rc = pclose (fh);
	if (rc != 0)
	  {
	    perror ("pclose");
	    return GSASL_AUTHENTICATION_ERROR;
	  }

	/* Read URL to redirect to.  Written by gsasl-saml20-request. */
	rc = asprintf (&tmp, "%s/%s/redirect_url", cfg->state_path, reqid);
	if (rc <= 0)
	  return GSASL_AUTHENTICATION_ERROR;
	fh = fopen (tmp, "r");
	free (tmp);
	if (!fh)
	  {
	    perror ("fopen");
	    return GSASL_AUTHENTICATION_ERROR;
	  }
	redirect_url = NULL;
	n = 0;
	if (getline (&redirect_url, &n, fh) <= 0)
	  {
	    perror ("getline");
	    return GSASL_AUTHENTICATION_ERROR;
	  }
	rc = fclose (fh);
	if (rc != 0)
	  {
	    perror ("fclose");
	    return GSASL_AUTHENTICATION_ERROR;
	  }

	/* We are done */
	gsasl_session_hook_set (sctx, reqid);
	gsasl_property_set (sctx, prop, redirect_url);

	printf ("read id: %s\n", reqid);
	printf ("url: %s\n", redirect_url);

	free (redirect_url);

	return GSASL_OK;
      }
      break;

    case GSASL_VALIDATE_SAML20:
      {
	time_t start = time (NULL);
	char *id = (char *) gsasl_session_hook_get (sctx);
	char *tmp, *line;
	size_t n;
	FILE *fh;

	if (!id)
	  return GSASL_AUTHENTICATION_ERROR;

	do
	  {
	    sleep (1);

	    rc = asprintf (&tmp, "%s/%s/success", cfg->state_path, id);
	    if (rc <= 0)
	      return GSASL_AUTHENTICATION_ERROR;
	    fh = fopen (tmp, "r");
	    free (tmp);
	    if (!fh)
	      {
		rc = asprintf (&tmp, "%s/%s/fail", cfg->state_path, id);
		if (rc <= 0)
		  return GSASL_AUTHENTICATION_ERROR;
		fh = fopen (tmp, "r");
		free (tmp);
		if (!fh)
		  {
		    puts ("waiting");
		    continue;
		  }
		rc = fclose (fh);
		if (rc != 0)
		  {
		    perror ("fclose");
		    return GSASL_AUTHENTICATION_ERROR;
		  }

		return GSASL_AUTHENTICATION_ERROR;
	      }

	    rc = fclose (fh);
	    if (rc != 0)
	      {
		perror ("fclose");
		return GSASL_AUTHENTICATION_ERROR;
	      }

	    rc = asprintf (&tmp, "%s/%s/subject", cfg->state_path, id);
	    if (rc <= 0)
	      return GSASL_AUTHENTICATION_ERROR;
	    fh = fopen (tmp, "r");
	    free (tmp);
	    if (!fh)
	      {
		perror ("fopen");
		return GSASL_AUTHENTICATION_ERROR;
	      }

	    line = NULL;
	    n = 0;
	    if (getline (&line, &n, fh) <= 0)
	      {
		perror ("getline");
		return GSASL_AUTHENTICATION_ERROR;
	      }

	    printf ("subject: %s\n", line);
	    gsasl_property_set (sctx, GSASL_AUTHID, line);
	    free (line);

	    rc = fclose (fh);
	    if (rc != 0)
	      {
		perror ("fclose");
		return GSASL_AUTHENTICATION_ERROR;
	      }

	    free (id);

	    return GSASL_OK;
	  }
	while (time (NULL) - start < 30);

	printf ("timeout\n");

	return GSASL_AUTHENTICATION_ERROR;
      }
      break;

    case GSASL_PASSWORD:
      gsasl_property_set (sctx, prop, "sesam");
      rc = GSASL_OK;
      break;

    default:
      /* You may want to log (at debug verbosity level) that an
         unknown property was requested here, possibly after filtering
         known rejected property requests. */
      break;
    }

  return rc;
}
Exemple #11
0
static int
cb (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
{
  int rc = GSASL_NO_CALLBACK;
  int i = 0, j = 0;

  if (gsasl_callback_hook_get (ctx))
    i = *(int *) gsasl_callback_hook_get (ctx);
  if (gsasl_session_hook_get (sctx))
    j = *(int *) gsasl_session_hook_get (sctx);

  if (j < 0 || j > 5)
    fail ("j out of bounds: %d\n", j);

  switch (prop)
    {
    case GSASL_AUTHID:
      gsasl_property_set (sctx, prop, sasltv[i].authid);
      rc = GSASL_OK;
      break;

    case GSASL_AUTHZID:
      gsasl_property_set (sctx, prop, sasltv[i].authzid);
      rc = GSASL_OK;
      break;

    case GSASL_PASSWORD:
      gsasl_property_set (sctx, prop, sasltv[i].password);
      rc = GSASL_OK;
      break;

    case GSASL_ANONYMOUS_TOKEN:
      gsasl_property_set (sctx, prop, sasltv[i].anonymous);
      rc = GSASL_OK;
      break;

    case GSASL_SERVICE:
      rc = GSASL_OK;
      break;

    case GSASL_PASSCODE:
      gsasl_property_set (sctx, prop, sasltv[i].passcode);
      rc = GSASL_OK;
      break;

    case GSASL_SUGGESTED_PIN:
    case GSASL_PIN:
      {
	const char *suggestion =
	  gsasl_property_fast (sctx, GSASL_SUGGESTED_PIN);
	if (suggestion && sasltv[i].suggestpin
	    && strcmp (suggestion, sasltv[i].suggestpin) != 0)
	  return GSASL_AUTHENTICATION_ERROR;

	if ((suggestion == NULL && sasltv[i].suggestpin != NULL) ||
	    (suggestion != NULL && sasltv[i].suggestpin == NULL))
	  return GSASL_AUTHENTICATION_ERROR;

	gsasl_property_set (sctx, prop, sasltv[i].pin);
	rc = GSASL_OK;
      }

    case GSASL_REALM:
      break;

    case GSASL_VALIDATE_EXTERNAL:
      rc = GSASL_OK;
      break;

    case GSASL_VALIDATE_ANONYMOUS:
      if (strcmp (sasltv[i].anonymous,
		  gsasl_property_fast (sctx, GSASL_ANONYMOUS_TOKEN)) == 0)
	rc = GSASL_OK;
      else
	rc = GSASL_AUTHENTICATION_ERROR;
      break;

    case GSASL_VALIDATE_SECURID:
      {
	const char *passcode = gsasl_property_fast (sctx, GSASL_PASSCODE);
	const char *pin = gsasl_property_fast (sctx, GSASL_PIN);

	if (strcmp (passcode, sasltv[i].passcode) != 0)
	  return GSASL_AUTHENTICATION_ERROR;

	if (sasltv[i].securidrc == GSASL_SECURID_SERVER_NEED_NEW_PIN)
	  {
	    rc = sasltv[i].securidrc;
	    sasltv[i].securidrc = GSASL_OK;

	    if (sasltv[i].suggestpin)
	      {
		gsasl_property_set (sctx, GSASL_SUGGESTED_PIN,
				    sasltv[i].suggestpin);
	      }
	  }
	else if (sasltv[i].securidrc ==
		 GSASL_SECURID_SERVER_NEED_ADDITIONAL_PASSCODE)
	  {
	    rc = sasltv[i].securidrc;
	    sasltv[i].securidrc = GSASL_OK;
	  }
	else
	  {
	    rc = sasltv[i].securidrc;

	    if (pin && sasltv[i].pin && strcmp (pin, sasltv[i].pin) != 0)
	      return GSASL_AUTHENTICATION_ERROR;

	    if ((pin == NULL && sasltv[i].pin != NULL) ||
		(pin != NULL && sasltv[i].pin == NULL))
	      return GSASL_AUTHENTICATION_ERROR;
	  }
      }
      break;

    default:
      printf ("Unknown property %d\n", prop);
      break;
    }

  return rc;
}
Exemple #12
0
int
callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
{
  int rc = GSASL_NO_CALLBACK;

  switch (prop)
    {
    case GSASL_ANONYMOUS_TOKEN:
      if (args_info.anonymous_token_arg == NULL)
	args_info.anonymous_token_arg =
	  readutf8line ("Enter anonymous token (e.g., email address): ");

      gsasl_property_set (sctx, GSASL_ANONYMOUS_TOKEN,
			  args_info.anonymous_token_arg);

      rc = GSASL_OK;
      break;

    case GSASL_CB_TLS_UNIQUE:
      if (!args_info.no_cb_flag && b64cbtlsunique == NULL
	  && args_info.hostname_arg == NULL)
	b64cbtlsunique =
	  readutf8line ("Enter base64 encoded tls-unique channel binding: ");
      if (!args_info.no_cb_flag && b64cbtlsunique && *b64cbtlsunique)
	gsasl_property_set (sctx, prop, b64cbtlsunique);
      rc = GSASL_OK;
      break;

    case GSASL_PASSWORD:
      if (args_info.password_arg == NULL)
	args_info.password_arg = readutf8pass ("Enter password: "******"Enter passcode: ");

      gsasl_property_set (sctx, GSASL_PASSCODE, args_info.passcode_arg);

      rc = GSASL_OK;
      break;

    case GSASL_AUTHID:
      if (args_info.authentication_id_arg == NULL)
	{
#if HAVE_GETPWUID
	  uid_t uid;
	  struct passwd *pw;

	  uid = getuid ();
	  pw = getpwuid (uid);

	  if (pw && pw->pw_name)
	    {
	      printf ("Using system username `%s' as "
		      "authentication identity.\n", pw->pw_name);
	      args_info.authentication_id_arg = xstrdup (pw->pw_name);
	    }
	  else
#endif
	    args_info.authentication_id_arg =
	      readutf8line ("Enter authentication ID: ");
	}

      gsasl_property_set (sctx, GSASL_AUTHID,
			  args_info.authentication_id_arg);
      rc = GSASL_OK;
      break;

    case GSASL_AUTHZID:
      gsasl_property_set (sctx, GSASL_AUTHZID,
			  args_info.authorization_id_arg);
      rc = GSASL_OK;
      break;

    case GSASL_SERVICE:
      if (args_info.service_arg == NULL)
	args_info.service_arg =
	  readutf8line ("Enter GSSAPI service name (e.g. \"imap\"): ");

      gsasl_property_set (sctx, GSASL_SERVICE, args_info.service_arg);

      rc = GSASL_OK;
      break;

    case GSASL_HOSTNAME:
      if (args_info.hostname_arg == NULL)
	args_info.hostname_arg = readutf8line ("Enter hostname of server: ");

      gsasl_property_set (sctx, GSASL_HOSTNAME, args_info.hostname_arg);

      rc = GSASL_OK;
      break;

    case GSASL_REALM:
      if (args_info.realm_arg == NULL)
	args_info.realm_arg =
	  readutf8line ("Enter realm of server (optional): ");

      if (args_info.realm_arg && *args_info.realm_arg)
	gsasl_property_set (sctx, GSASL_REALM, args_info.realm_arg);

      rc = GSASL_OK;
      break;

    case GSASL_QOP:
      if (args_info.quality_of_protection_arg == NULL)
	args_info.quality_of_protection_arg = readutf8line
	  ("Enter quality of protection (optional, e.g. 'qop-int'): ");
      if (args_info.quality_of_protection_arg
	  && *args_info.quality_of_protection_arg)
	gsasl_property_set (sctx, GSASL_QOP,
			    args_info.quality_of_protection_arg);
      rc = GSASL_OK;
      break;

    case GSASL_VALIDATE_GSSAPI:
      {
	char *str;
	printf ("Authzid: %s\nDisplay Name: %s\n",
		gsasl_property_fast (sctx, GSASL_AUTHZID),
		gsasl_property_fast (sctx, GSASL_GSSAPI_DISPLAY_NAME));
	str = readutf8line ("Validate GSS-API user? (y/n) ");
	if (strcmp (str, "y") == 0 || strcmp (str, "Y") == 0)
	  rc = GSASL_OK;
	else
	  rc = GSASL_AUTHENTICATION_ERROR;
	free (str);
      }
      break;

    case GSASL_SCRAM_SALTED_PASSWORD:
    case GSASL_SCRAM_ITER:
    case GSASL_SCRAM_SALT:
      break;

    case GSASL_SAML20_IDP_IDENTIFIER:
      {
	char *str = readutf8line ("Enter SAML authentication identifier "
				  "(e.g. \"http://example.org/\"): ");

	gsasl_property_set (sctx, GSASL_SAML20_IDP_IDENTIFIER, str);

	rc = GSASL_OK;
      }
      break;

    case GSASL_SAML20_AUTHENTICATE_IN_BROWSER:
      {
	const char *url = gsasl_property_get (sctx, GSASL_SAML20_REDIRECT_URL);

	printf ("Proceed to this URL to authenticate using SAML 2.0:\n%s\n",
		url);

	rc = GSASL_OK;
      }
      break;

    case GSASL_OPENID20_AUTHENTICATE_IN_BROWSER:
      {
	const char *url = gsasl_property_get (sctx,
					      GSASL_OPENID20_REDIRECT_URL);

	printf ("Proceed to this URL to authenticate using OpenID 2.0:\n%s\n",
		url);

	rc = GSASL_OK;
      }
      break;

    default:
      fprintf (stderr,
	       "warning: mechanism requested unsupported property `%d'\n",
	       prop);
      break;
    }

  return rc;
}
Exemple #13
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;
}
Exemple #14
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;
}
Exemple #15
0
int
_gsasl_scram_sha1_server_step (Gsasl_session * sctx,
			       void *mech_data,
			       const char *input,
			       size_t input_len,
			       char **output, size_t * output_len)
{
  struct scram_server_state *state = mech_data;
  int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
  int rc;

  *output = NULL;
  *output_len = 0;

  switch (state->step)
    {
    case 0:
      {
	if (input_len == 0)
	  return GSASL_NEEDS_MORE;

	if (scram_parse_client_first (input, input_len, &state->cf) < 0)
	  return GSASL_MECHANISM_PARSE_ERROR;

	/* In PLUS server mode, we require use of channel bindings. */
	if (state->plus && state->cf.cbflag != 'p')
	  return GSASL_AUTHENTICATION_ERROR;

	/* In non-PLUS mode, but where have channel bindings data (and
	   thus advertised PLUS) we reject a client 'y' cbflag. */
	if (!state->plus
	    && state->cbtlsuniquelen > 0 && state->cf.cbflag == 'y')
	  return GSASL_AUTHENTICATION_ERROR;

	/* Check that username doesn't fail SASLprep. */
	{
	  char *tmp;
	  rc = gsasl_saslprep (state->cf.username, GSASL_ALLOW_UNASSIGNED,
			       &tmp, NULL);
	  if (rc != GSASL_OK || *tmp == '\0')
	    return GSASL_AUTHENTICATION_ERROR;
	  gsasl_free (tmp);
	}

	{
	  const char *p;

	  /* Save "gs2-header" and "message-bare" for next step. */
	  p = memchr (input, ',', input_len);
	  if (!p)
	    return GSASL_AUTHENTICATION_ERROR;
	  p++;
	  p = memchr (p, ',', input_len - (p - input));
	  if (!p)
	    return GSASL_AUTHENTICATION_ERROR;
	  p++;

	  state->gs2header = malloc (p - input + 1);
	  if (!state->gs2header)
	    return GSASL_MALLOC_ERROR;
	  memcpy (state->gs2header, input, p - input);
	  state->gs2header[p - input] = '\0';

	  state->cfmb_str = malloc (input_len - (p - input) + 1);
	  if (!state->cfmb_str)
	    return GSASL_MALLOC_ERROR;
	  memcpy (state->cfmb_str, p, input_len - (p - input));
	  state->cfmb_str[input_len - (p - input)] = '\0';
	}

	/* Create new nonce. */
	{
	  size_t cnlen = strlen (state->cf.client_nonce);

	  state->sf.nonce = malloc (cnlen + SNONCE_ENTROPY_BYTES + 1);
	  if (!state->sf.nonce)
	    return GSASL_MALLOC_ERROR;

	  memcpy (state->sf.nonce, state->cf.client_nonce, cnlen);
	  memcpy (state->sf.nonce + cnlen, state->snonce,
		  SNONCE_ENTROPY_BYTES);
	  state->sf.nonce[cnlen + SNONCE_ENTROPY_BYTES] = '\0';
	}

	gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username);
	gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid);

	{
	  const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER);
	  if (p)
	    state->sf.iter = strtoul (p, NULL, 10);
	  if (!p || state->sf.iter == 0 || state->sf.iter == ULONG_MAX)
	    state->sf.iter = 4096;
	}

	{
	  const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT);
	  if (p)
	    {
	      free (state->sf.salt);
	      state->sf.salt = strdup (p);
	    }
	}

	rc = scram_print_server_first (&state->sf, &state->sf_str);
	if (rc != 0)
	  return GSASL_MALLOC_ERROR;

	*output = strdup (state->sf_str);
	if (!*output)
	  return GSASL_MALLOC_ERROR;
	*output_len = strlen (*output);

	state->step++;
	return GSASL_NEEDS_MORE;
	break;
      }

    case 1:
      {
	if (scram_parse_client_final (input, input_len, &state->cl) < 0)
	  return GSASL_MECHANISM_PARSE_ERROR;

	if (strcmp (state->cl.nonce, state->sf.nonce) != 0)
	  return GSASL_AUTHENTICATION_ERROR;

	/* Base64 decode the c= field and check that it matches
	   client-first.  Also check channel binding data. */
	{
	  size_t len;

	  rc = gsasl_base64_from (state->cl.cbind, strlen (state->cl.cbind),
				  &state->cbind, &len);
	  if (rc != 0)
	    return rc;

	  if (state->cf.cbflag == 'p')
	    {
	      if (len < strlen (state->gs2header))
		return GSASL_AUTHENTICATION_ERROR;

	      if (memcmp (state->cbind, state->gs2header,
			  strlen (state->gs2header)) != 0)
		return GSASL_AUTHENTICATION_ERROR;

	      if (len - strlen (state->gs2header) != state->cbtlsuniquelen)
		return GSASL_AUTHENTICATION_ERROR;

	      if (memcmp (state->cbind + strlen (state->gs2header),
			  state->cbtlsunique, state->cbtlsuniquelen) != 0)
		return GSASL_AUTHENTICATION_ERROR;
	    }
	  else
	    {
	      if (len != strlen (state->gs2header))
		return GSASL_AUTHENTICATION_ERROR;

	      if (memcmp (state->cbind, state->gs2header, len) != 0)
		return GSASL_AUTHENTICATION_ERROR;
	    }
	}

	/* Base64 decode client proof and check that length matches
	   SHA-1 size. */
	{
	  size_t len;

	  rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof),
				  &state->clientproof, &len);
	  if (rc != 0)
	    return rc;
	  if (len != 20)
	    return GSASL_MECHANISM_PARSE_ERROR;
	}

	{
	  const char *p;

	  /* Get StoredKey and ServerKey */
	  if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)))
	    {
	      Gc_rc err;
	      char *salt;
	      size_t saltlen;
	      char saltedpassword[20];
	      char *clientkey;
	      char *preppasswd;

	      rc = gsasl_saslprep (p, 0, &preppasswd, NULL);
	      if (rc != GSASL_OK)
		return rc;

	      rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
				      &salt, &saltlen);
	      if (rc != 0)
		{
		  gsasl_free (preppasswd);
		  return rc;
		}

	      /* SaltedPassword := Hi(password, salt) */
	      err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd),
				    salt, saltlen,
				    state->sf.iter, saltedpassword, 20);
	      gsasl_free (preppasswd);
	      gsasl_free (salt);
	      if (err != GC_OK)
		return GSASL_MALLOC_ERROR;

	      /* ClientKey := HMAC(SaltedPassword, "Client Key") */
#define CLIENT_KEY "Client Key"
	      rc = gsasl_hmac_sha1 (saltedpassword, 20,
				    CLIENT_KEY, strlen (CLIENT_KEY),
				    &clientkey);
	      if (rc != 0)
		return rc;

	      /* StoredKey := H(ClientKey) */
	      rc = gsasl_sha1 (clientkey, 20, &state->storedkey);
	      free (clientkey);
	      if (rc != 0)
		return rc;

	      /* ServerKey := HMAC(SaltedPassword, "Server Key") */
#define SERVER_KEY "Server Key"
	      rc = gsasl_hmac_sha1 (saltedpassword, 20,
				    SERVER_KEY, strlen (SERVER_KEY),
				    &state->serverkey);
	      if (rc != 0)
		return rc;
	    }
	  else
	    return GSASL_NO_PASSWORD;

	  /* Compute AuthMessage */
	  {
	    size_t len;
	    int n;

	    /* Get client-final-message-without-proof. */
	    p = memmem (input, input_len, ",p=", 3);
	    if (!p)
	      return GSASL_MECHANISM_PARSE_ERROR;
	    len = p - input;

	    n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
			  state->cfmb_str,
			  (int) strlen (state->sf_str), state->sf_str,
			  (int) len, input);
	    if (n <= 0 || !state->authmessage)
	      return GSASL_MALLOC_ERROR;
	  }

	  /* Check client proof. */
	  {
	    char *clientsignature;
	    char *maybe_storedkey;

	    /* ClientSignature := HMAC(StoredKey, AuthMessage) */
	    rc = gsasl_hmac_sha1 (state->storedkey, 20,
				  state->authmessage,
				  strlen (state->authmessage),
				  &clientsignature);
	    if (rc != 0)
	      return rc;

	    /* ClientKey := ClientProof XOR ClientSignature */
	    memxor (clientsignature, state->clientproof, 20);

	    rc = gsasl_sha1 (clientsignature, 20, &maybe_storedkey);
	    free (clientsignature);
	    if (rc != 0)
	      return rc;

	    rc = memcmp (state->storedkey, maybe_storedkey, 20);
	    free (maybe_storedkey);
	    if (rc != 0)
	      return GSASL_AUTHENTICATION_ERROR;
	  }

	  /* Generate server verifier. */
	  {
	    char *serversignature;

	    /* ServerSignature := HMAC(ServerKey, AuthMessage) */
	    rc = gsasl_hmac_sha1 (state->serverkey, 20,
				  state->authmessage,
				  strlen (state->authmessage),
				  &serversignature);
	    if (rc != 0)
	      return rc;

	    rc = gsasl_base64_to (serversignature, 20,
				  &state->sl.verifier, NULL);
	    free (serversignature);
	    if (rc != 0)
	      return rc;
	  }
	}

	rc = scram_print_server_final (&state->sl, output);
	if (rc != 0)
	  return GSASL_MALLOC_ERROR;
	*output_len = strlen (*output);

	state->step++;
	return GSASL_OK;
	break;
      }

    default:
      break;
    }

  return res;
}
Exemple #16
0
int
_gsasl_digest_md5_server_step (Gsasl_session * sctx,
                               void *mech_data,
                               const char *input,
                               size_t input_len,
                               char **output, size_t * output_len)
{
    _Gsasl_digest_md5_server_state *state = mech_data;
    int rc, res;

    *output = NULL;
    *output_len = 0;

    switch (state->step)
    {
    case 0:
        /* Set realm. */
    {
        const char *c;
        c = gsasl_property_get (sctx, GSASL_REALM);
        if (c)
        {
            state->challenge.nrealms = 1;

            state->challenge.realms =
                malloc (sizeof (*state->challenge.realms));
            if (!state->challenge.realms)
                return GSASL_MALLOC_ERROR;

            state->challenge.realms[0] = strdup (c);
            if (!state->challenge.realms[0])
                return GSASL_MALLOC_ERROR;
        }
    }

        /* Set QOP */
    {
        const char *qopstr = gsasl_property_get (sctx, GSASL_QOPS);

        if (qopstr)
        {
            int qops = digest_md5_qopstr2qops (qopstr);

            if (qops == -1)
                return GSASL_MALLOC_ERROR;

            /* We don't support confidentiality right now. */
            if (qops & DIGEST_MD5_QOP_AUTH_CONF)
                return GSASL_AUTHENTICATION_ERROR;

            if (qops)
                state->challenge.qops = qops;
        }
    }

        /* FIXME: cipher, maxbuf, more realms. */

        /* Create challenge. */
    *output = digest_md5_print_challenge (&state->challenge);
    if (!*output)
        return GSASL_AUTHENTICATION_ERROR;

    *output_len = strlen (*output);
    state->step++;
    res = GSASL_NEEDS_MORE;
    break;

    case 1:
        if (digest_md5_parse_response (input, input_len, &state->response) < 0)
            return GSASL_MECHANISM_PARSE_ERROR;

        /* Make sure response is consistent with challenge. */
        if (digest_md5_validate (&state->challenge, &state->response) < 0)
            return GSASL_MECHANISM_PARSE_ERROR;

        /* Store properties, from the client response. */
        if (state->response.utf8)
        {
            gsasl_property_set (sctx, GSASL_AUTHID, state->response.username);
            gsasl_property_set (sctx, GSASL_REALM, state->response.realm);
        }
        else
        {
            /* Client provided username/realm in ISO-8859-1 form,
               convert it to UTF-8 since the library is all-UTF-8. */
            char *tmp;

            tmp = latin1toutf8 (state->response.username);
            if (!tmp)
                return GSASL_MALLOC_ERROR;
            gsasl_property_set (sctx, GSASL_AUTHID, tmp);
            free (tmp);

            tmp = latin1toutf8 (state->response.realm);
            if (!tmp)
                return GSASL_MALLOC_ERROR;
            gsasl_property_set (sctx, GSASL_REALM, tmp);
            free (tmp);
        }
        gsasl_property_set (sctx, GSASL_AUTHZID, state->response.authzid);

        /* FIXME: cipher, maxbuf.  */

        /* Compute secret. */
        {
            const char *passwd;
            const char *hashed_passwd;

            hashed_passwd =
                gsasl_property_get (sctx, GSASL_DIGEST_MD5_HASHED_PASSWORD);
            if (hashed_passwd)
            {
                if (strlen (hashed_passwd) != (DIGEST_MD5_LENGTH * 2))
                    return GSASL_AUTHENTICATION_ERROR;

                rc = _gsasl_digest_md5_set_hashed_secret (state->secret,
                        hashed_passwd);
                if (rc != GSASL_OK)
                    return rc;
            }
            else if ((passwd = gsasl_property_get (sctx, GSASL_PASSWORD)) != NULL)
            {
                char *tmp, *tmp2;

                tmp2 = utf8tolatin1ifpossible (passwd);

                rc = asprintf (&tmp, "%s:%s:%s", state->response.username,
                               state->response.realm ?
                               state->response.realm : "", tmp2);
                free (tmp2);
                if (rc < 0)
                    return GSASL_MALLOC_ERROR;

                rc = gsasl_md5 (tmp, strlen (tmp), &tmp2);
                free (tmp);
                if (rc != GSASL_OK)
                    return rc;

                memcpy (state->secret, tmp2, DIGEST_MD5_LENGTH);
                free (tmp2);
            }
            else
            {
                return GSASL_NO_PASSWORD;
            }
        }

        /* Check client response. */
        {
            char check[DIGEST_MD5_RESPONSE_LENGTH + 1];

            rc = digest_md5_hmac (check, state->secret,
                                  state->response.nonce, state->response.nc,
                                  state->response.cnonce, state->response.qop,
                                  state->response.authzid,
                                  state->response.digesturi, 0,
                                  state->response.cipher,
                                  state->kic, state->kis, state->kcc, state->kcs);
            if (rc)
                return GSASL_AUTHENTICATION_ERROR;

            if (strcmp (state->response.response, check) != 0)
                return GSASL_AUTHENTICATION_ERROR;
        }

        /* Create finish token. */
        rc = digest_md5_hmac (state->finish.rspauth, state->secret,
                              state->response.nonce, state->response.nc,
                              state->response.cnonce, state->response.qop,
                              state->response.authzid,
                              state->response.digesturi, 1,
                              state->response.cipher, NULL, NULL, NULL, NULL);
        if (rc)
            return GSASL_AUTHENTICATION_ERROR;

        *output = digest_md5_print_finish (&state->finish);
        if (!*output)
            return GSASL_MALLOC_ERROR;

        *output_len = strlen (*output);

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

    default:
        res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
        break;
    }

    return res;
}
END_TEST

START_TEST (test_saslplugin_request_scram_sha_1)
{
    g_print("Starting test_saslplugin_request_scram_sha_1\n");
    gpointer plugin;
    Gsasl *gsasl_context;
    Gsasl_session *gsasl_session;    
    
    plugin = g_object_new(GSIGNOND_TYPE_SASL_PLUGIN, NULL);
    fail_if(plugin == NULL);
    
    fail_if (gsasl_init (&gsasl_context) != GSASL_OK);
    fail_if (gsasl_server_start (gsasl_context, 
                                 "SCRAM-SHA-1", 
                                 &gsasl_session) != GSASL_OK);
    
    GSignondSessionData* result = NULL;
    GSignondSessionData* result_final = NULL;
    GError* error = NULL;

    g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), &result_final);
    g_signal_connect(plugin, "response", 
                     G_CALLBACK(response_callback), &result);
    g_signal_connect(plugin, "error", G_CALLBACK(error_callback), &error);

    GSignondSessionData* data = gsignond_dictionary_new();

    char* server_challenge;
    fail_if(gsasl_step64(gsasl_session, "", &server_challenge) != GSASL_NEEDS_MORE);
    
    gsignond_dictionary_set_string(data, "ChallengeBase64", server_challenge);
    free(server_challenge);
    gsignond_session_data_set_username(data, "*****@*****.**");
    gsignond_session_data_set_secret(data, "megapassword");
   
    gsignond_plugin_request_initial(plugin, data, NULL, "SCRAM-SHA-1");

    fail_if(result == NULL);    
    fail_if(result_final != NULL);
    fail_if(error != NULL);
    gsasl_property_set(gsasl_session, GSASL_PASSWORD, "megapassword");
    fail_if (gsasl_step64(gsasl_session, 
                          gsignond_dictionary_get_string(result,
                                                         "ResponseBase64"), 
                          &server_challenge) != GSASL_NEEDS_MORE);
     gsignond_dictionary_unref(result);
    result = NULL;

    gsignond_dictionary_set_string(data, "ChallengeBase64", server_challenge);
    free(server_challenge);
    gsignond_plugin_request(plugin, data);

    fail_if(result == NULL);    
    fail_if(result_final != NULL);
    fail_if(error != NULL);

    fail_if (gsasl_step64(gsasl_session, 
                          gsignond_dictionary_get_string(result,
                                                         "ResponseBase64"), 
                          &server_challenge) != GSASL_OK);
     gsignond_dictionary_unref(result);
    result = NULL;

    gsignond_dictionary_set_string(data, "ChallengeBase64", server_challenge);
    free(server_challenge);
    gsignond_plugin_request(plugin, data);

    fail_if(result != NULL);    
    fail_if(result_final == NULL);
    fail_if(error != NULL);
    
    fail_if(strlen(gsignond_dictionary_get_string(result_final,
                                                           "ResponseBase64")) > 0);
     gsignond_dictionary_unref(result_final);
    result_final = NULL;    
    
    gsasl_finish(gsasl_session);
    gsasl_done(gsasl_context);
    gsignond_dictionary_unref(data);
    g_object_unref(plugin);
}