static void
infinoted_startup_sasl_callback(InfSaslContextSession* session,
                                Gsasl_property prop,
                                gpointer session_data,
                                gpointer user_data)
{
  InfinotedStartup* startup;
  const char* username;
  const char* password;
  InfXmppConnection* xmpp;
  gchar cmp;
  gsize password_len;
  gsize i;

#ifdef LIBINFINITY_HAVE_PAM
  const gchar* pam_service;
  GError* error;
#endif
  gchar* remote_id;

  xmpp = INF_XMPP_CONNECTION(session_data);
  g_object_get(xmpp, "remote-id", &remote_id, NULL);

  switch(prop)
  {
  case GSASL_VALIDATE_SIMPLE:
    startup = (InfinotedStartup*)user_data;
    username = inf_sasl_context_session_get_property(session, GSASL_AUTHID);
    password = inf_sasl_context_session_get_property(session, GSASL_PASSWORD);
#ifdef LIBINFINITY_HAVE_PAM
    pam_service = startup->options->pam_service;
    if(pam_service != NULL)
    {
      error = NULL;
      if(!infinoted_pam_authenticate(pam_service, username, password))
      {
        infinoted_log_warning(
          startup->log,
          _("User %s failed to log in from %s: PAM authentication failed"),
          username,
          remote_id
        );

        infinoted_startup_sasl_callback_set_error(
          xmpp,
          INF_AUTHENTICATION_DETAIL_ERROR_AUTHENTICATION_FAILED,
          NULL
        );

        inf_sasl_context_session_continue(
          session,
          GSASL_AUTHENTICATION_ERROR
        );
      }
      else if(!infinoted_pam_user_is_allowed(startup, username, &error))
      {
        infinoted_log_warning(
          startup->log,
          _("User %s failed to log in from %s: PAM user not allowed"),
          username,
          remote_id
        );

        infinoted_startup_sasl_callback_set_error(
          xmpp,
          INF_AUTHENTICATION_DETAIL_ERROR_USER_NOT_AUTHORIZED,
          error
        );

        inf_sasl_context_session_continue(
          session,
          GSASL_AUTHENTICATION_ERROR
        );
      }
      else
      {
        infinoted_log_info(
          startup->log,
          _("User %s logged in from %s via PAM"),
          username,
          remote_id
        );

        inf_sasl_context_session_continue(session, GSASL_OK);
      }
    }
    else
#endif /* LIBINFINITY_HAVE_PAM */
    {
      g_assert(startup->options->password != NULL);

      /* length-independent string compare */
      cmp = 0;
      password_len = strlen(password);
      for(i = 0; i < startup->options->password_len; ++i)
      {
        if(i < password_len)
          cmp |= (startup->options->password[i] ^ password[i]);
        else
          cmp |= (startup->options->password[i] ^ 0x00);
      }

      if(startup->options->password_len != password_len)
        cmp |= 0xFF;

      if(cmp == 0)
      {
        infinoted_log_info(
          startup->log,
          _("User %s logged in from %s via password"),
          username,
          remote_id
        );

        inf_sasl_context_session_continue(session, GSASL_OK);
      }
      else
      {
        infinoted_log_warning(
          startup->log,
          _("User %s failed to log in from %s: wrong password"),
          username,
          remote_id
        );

        infinoted_startup_sasl_callback_set_error(
          xmpp,
          INF_AUTHENTICATION_DETAIL_ERROR_AUTHENTICATION_FAILED,
          NULL
        );

        inf_sasl_context_session_continue(
          session,
          GSASL_AUTHENTICATION_ERROR
        );
      }
    }

    break;
  default:
    inf_sasl_context_session_continue(session, GSASL_AUTHENTICATION_ERROR);
    break;
  }

  g_free(remote_id);
}
示例#2
0
void Gobby::AuthCommands::sasl_callback(InfSaslContextSession* session,
                                        InfXmppConnection* xmpp,
                                        Gsasl_property prop)
{
	const Glib::ustring username = m_preferences.user.name;
	const std::string correct_password = m_preferences.user.password;
	const char* password;
	gsize password_len;
	gchar cmp;

	switch(prop)
	{
	case GSASL_ANONYMOUS_TOKEN:
		inf_sasl_context_session_set_property(
			session, GSASL_ANONYMOUS_TOKEN, username.c_str());
		inf_sasl_context_session_continue(session, GSASL_OK);
		break;
	case GSASL_AUTHID:
		inf_sasl_context_session_set_property(
			session, GSASL_AUTHID, username.c_str());
		inf_sasl_context_session_continue(session, GSASL_OK);
		break;
	case GSASL_PASSWORD:
		{
			RetryMap::iterator i = m_retries.find(xmpp);
			if(i == m_retries.end())
				i = insert_retry_info(xmpp);
			RetryInfo& info(i->second);

			if(!info.last_password.empty())
			{
				inf_sasl_context_session_set_property(
					session, GSASL_PASSWORD,
					info.last_password.c_str());

				inf_sasl_context_session_continue(session,
				                                  GSASL_OK);
			}
			else
			{
				// Query user for password
				g_assert(info.password_dialog == NULL);

				gchar* remote_id;
				g_object_get(G_OBJECT(xmpp),
				             "remote-hostname", &remote_id,
					     NULL);
				Glib::ustring remote_id_(remote_id);
				g_free(remote_id);

				info.password_dialog = new PasswordDialog(
					m_parent, remote_id_, info.retries);
				info.password_dialog->add_button(
					_("_Cancel"), Gtk::RESPONSE_CANCEL);
				info.password_dialog->add_button(
					_("_Ok"), Gtk::RESPONSE_ACCEPT);

				Gtk::Dialog& dialog = *info.password_dialog;
				dialog.signal_response().connect(sigc::bind(
					sigc::mem_fun(
						*this,
						&AuthCommands::on_response),
					session, xmpp));

				info.password_dialog->present();
			}
		}

		break;
	case GSASL_VALIDATE_ANONYMOUS:
		if(m_preferences.user.require_password)
		{
			inf_sasl_context_session_continue(
				session,
				GSASL_AUTHENTICATION_ERROR
			);

			set_sasl_error(xmpp, _("Password required"));
		}
		else
		{
			inf_sasl_context_session_continue(session, GSASL_OK);
		}

		break;
	case GSASL_VALIDATE_SIMPLE:
		password = inf_sasl_context_session_get_property(
			session, GSASL_PASSWORD);

		/* length-independent string compare */
		cmp = 0;
		password_len = strlen(password);
		for(unsigned i = 0; i < correct_password.size(); ++i)
		{
			if(i < password_len)
				cmp |= (password[i] ^ correct_password[i]);
			else
				cmp |= (0x00 ^ correct_password[i]);
		}

		if(password_len != correct_password.size())
			cmp = 0xFF;

		if(cmp != 0)
		{
			inf_sasl_context_session_continue(
				session,
				GSASL_AUTHENTICATION_ERROR
			);

			set_sasl_error(xmpp, _("Incorrect password"));
		}
		else
		{
			inf_sasl_context_session_continue(session, GSASL_OK);
		}

		break;
	default:
		inf_sasl_context_session_continue(session, GSASL_NO_CALLBACK);
		break;
	}
}