Skip to content

Instantly share code, notes, and snippets.

@fat-lobyte
Created February 24, 2013 17:31
Show Gist options
  • Save fat-lobyte/5024715 to your computer and use it in GitHub Desktop.
Save fat-lobyte/5024715 to your computer and use it in GitHub Desktop.
# HG changeset patch
# Parent 680e46fecff055a80d84843a45ba4a195541da88
# User Jan Horak <jhorak@redhat.com>
# Bug: #309807 Allows storing Master password to Gnome Keyring
diff --git a/config/system-headers b/config/system-headers
--- a/config/system-headers
+++ b/config/system-headers
@@ -1061,16 +1061,19 @@ hildon-uri.h
hildon-mime.h
hildon-file-chooser-dialog.h
libosso.h
osso-mem.h
#endif
#ifdef MOZ_ENABLE_GIO
gio/gio.h
#endif
+#ifdef MOZ_ENABLE_LIBSECRET
+libsecret/secret.h
+#endif
#ifdef MOZ_ENABLE_LIBCONIC
conic/conicconnection.h
conic/conicconnectionevent.h
conic/conicstatisticsevent.h
#endif
#if MOZ_NATIVE_LIBEVENT==1
event.h
#endif
diff --git a/configure.in b/configure.in
--- a/configure.in
+++ b/configure.in
@@ -66,16 +66,17 @@ CAIRO_VERSION=1.10
PANGO_VERSION=1.14.0
GTK2_VERSION=2.10.0
WINDRES_VERSION=2.14.90
W32API_VERSION=3.14
GNOMEVFS_VERSION=2.0
GNOMEUI_VERSION=2.2.0
GCONF_VERSION=1.2.1
GIO_VERSION=2.20
+LIBSECRET_VERSION=0.12
STARTUP_NOTIFICATION_VERSION=0.8
DBUS_VERSION=0.60
SQLITE_VERSION=3.7.15.2
MSMANIFEST_TOOL=
dnl Set various checks
dnl ========================================================
@@ -4874,17 +4875,17 @@ then
else
PKG_CHECK_MODULES(FT2, freetype2 > 6.1.0)
AC_SUBST(FT2_CFLAGS)
AC_SUBST(FT2_LIBS)
fi
fi
dnl ========================================================
-dnl = GnomeVFS, GIO and GConf support module
+dnl = GnomeVFS, GIO, GConf, Libsecret support module
dnl ========================================================
if test "$MOZ_X11"
then
dnl build the GIO extension by default only when the
dnl GTK2 toolkit is in use.
if test "$MOZ_ENABLE_GTK2"
then
@@ -4972,16 +4973,43 @@ then
if test "$MOZ_ENABLE_GCONF"; then
AC_DEFINE(MOZ_ENABLE_GCONF)
fi
AC_SUBST(MOZ_ENABLE_GCONF)
AC_SUBST(MOZ_GCONF_CFLAGS)
AC_SUBST(MOZ_GCONF_LIBS)
+
+ dnl ========================================================
+ dnl = Libsecret support module
+ dnl ========================================================
+ MOZ_ARG_ENABLE_BOOL(libsecret,
+ [ --enable-libsecret Enable Libsecret to store master password (default: disabled)],
+ MOZ_ENABLE_LIBSECRET=force,
+ MOZ_ENABLE_LIBSECRET=)
+
+ if test "$MOZ_ENABLE_LIBSECRET"
+ then
+ PKG_CHECK_MODULES(MOZ_LIBSECRET, libsecret-1 >= $LIBSECRET_VERSION,[
+ MOZ_ENABLE_LIBSECRET=1
+ AC_DEFINE(MOZ_ENABLE_LIBSECRET)
+ ],[
+ if test "$MOZ_ENABLE_LIBSECRET" = "force"
+ then
+ AC_MSG_ERROR([* * * Could not find libsecret-1 >= $LIBSECRET_VERSION])
+ fi
+ MOZ_ENABLE_LIBSECRET=
+ ])
+ fi
+
+ AC_SUBST(MOZ_ENABLE_LIBSECRET)
+ AC_SUBST(MOZ_LIBSECRET_CFLAGS)
+ AC_SUBST(MOZ_LIBSECRET_LIBS)
+
fi
dnl ========================================================
dnl = libproxy support
dnl ========================================================
if test "$MOZ_ENABLE_GTK2" -o "$MOZ_ENABLE_QT"
then
diff --git a/js/src/config/system-headers b/js/src/config/system-headers
--- a/js/src/config/system-headers
+++ b/js/src/config/system-headers
@@ -1061,16 +1061,19 @@ hildon-uri.h
hildon-mime.h
hildon-file-chooser-dialog.h
libosso.h
osso-mem.h
#endif
#ifdef MOZ_ENABLE_GIO
gio/gio.h
#endif
+#ifdef MOZ_ENABLE_LIBSECRET
+libsecret/secret.h
+#endif
#ifdef MOZ_ENABLE_LIBCONIC
conic/conicconnection.h
conic/conicconnectionevent.h
conic/conicstatisticsevent.h
#endif
#if MOZ_NATIVE_LIBEVENT==1
event.h
#endif
diff --git a/security/manager/locales/en-US/chrome/pipnss/pipnss.properties b/security/manager/locales/en-US/chrome/pipnss/pipnss.properties
--- a/security/manager/locales/en-US/chrome/pipnss/pipnss.properties
+++ b/security/manager/locales/en-US/chrome/pipnss/pipnss.properties
@@ -370,8 +370,9 @@ CaCertExists=This certificate is already
NotACACert=This is not a certificate authority certificate, so it can't be imported into the certificate authority list.
NotImportingUnverifiedCert=This certificate can't be verified and will not be imported. The certificate issuer might be unknown or untrusted, the certificate might have expired or been revoked, or the certificate might not have been approved.
UserCertIgnoredNoPrivateKey=This personal certificate can't be installed because you do not own the corresponding private key which was created when the certificate was requested.
UserCertImported=Your personal certificate has been installed. You should keep a backup copy of this certificate.
CertOrgUnknown=(Unknown)
CertNotStored=(Not Stored)
CertExceptionPermanent=Permanent
CertExceptionTemporary=Temporary
+LibsecretSavePrompt=Do you want to save master password to system password manager?
diff --git a/security/manager/ssl/src/Makefile.in b/security/manager/ssl/src/Makefile.in
--- a/security/manager/ssl/src/Makefile.in
+++ b/security/manager/ssl/src/Makefile.in
@@ -98,10 +98,15 @@ EXPORTS += \
$(NULL)
EXPORTS_NAMESPACES = mozilla
EXPORTS_mozilla += \
PublicSSL.h \
$(NULL)
+ifdef MOZ_ENABLE_LIBSECRET
+LOCAL_INCLUDES = $(MOZ_LIBSECRET_CFLAGS)
+DEFINES += -DMOZ_ENABLE_LIBSECRET
+endif
+
include $(topsrcdir)/config/rules.mk
diff --git a/security/manager/ssl/src/libsecretMozillaSchema.h b/security/manager/ssl/src/libsecretMozillaSchema.h
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/src/libsecretMozillaSchema.h
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef libsecretMozillaSchema_h__
+#define libsecretMozillaSchema_h__
+
+#ifdef MOZ_ENABLE_LIBSECRET
+
+#include "libsecret/secret.h"
+
+#define MOZILLA_SECRET_SCHEMA get_mozilla_secret_schema()
+
+/**
+ * Construct schema use for storing master password to Libsecret. Schema
+ * contains application name and user profile.
+ **/
+static const SecretSchema *
+get_mozilla_secret_schema (void)
+{
+ static const SecretSchema the_schema = {
+ "org.mozilla.MasterPassword", SECRET_SCHEMA_NONE,
+ {
+ { "application", SECRET_SCHEMA_ATTRIBUTE_STRING }, // application name
+ { "profile", SECRET_SCHEMA_ATTRIBUTE_STRING }, // profile name
+ { "NULL", (SecretSchemaAttributeType)0 },
+ }
+ };
+ return &the_schema;
+}
+
+#endif // MOZ_ENABLE_LIBSECRET
+
+#endif // libsecretMozillaSchema_h__
\ No newline at end of file
diff --git a/security/manager/ssl/src/nsNSSCallbacks.cpp b/security/manager/ssl/src/nsNSSCallbacks.cpp
--- a/security/manager/ssl/src/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/src/nsNSSCallbacks.cpp
@@ -25,16 +25,24 @@
#include "nsCRT.h"
#include "SharedSSLState.h"
#include "ssl.h"
#include "sslproto.h"
#include "ocsp.h"
#include "nssb64.h"
+#ifdef MOZ_ENABLE_LIBSECRET
+#include "libsecret/secret.h"
+#include "libsecretMozillaSchema.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsIXULAppInfo.h"
+#include "nsXPCOMCIDInternal.h"
+#endif
+
using namespace mozilla;
using namespace mozilla::psm;
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
#ifdef PR_LOGGING
extern PRLogModuleInfo* gPIPNSSLog;
#endif
@@ -723,16 +731,99 @@ ShowProtectedAuthPrompt(PK11SlotInfo* sl
}
NS_RELEASE(dialogs);
}
return protAuthRetVal;
}
+#ifdef MOZ_ENABLE_LIBSECRET
+class LibsecretPromptRunnable : public SyncRunnableBase
+{
+public:
+ LibsecretPromptRunnable(PRBool retry)
+ : mResult(nullptr), mRetry(retry)
+ {
+ }
+ char *mResult; //out, is freed by PORT_Free in PK11_DoPassword
+ bool mRetry;
+ bool mRunning; /// When true, we're calling gtk main loop from RunOnTargetThread
+
+ virtual void RunOnTargetThread();
+};
+
+static void
+on_lookup_finished(GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ GError *err = nullptr;
+
+ gchar *pwd = secret_password_lookup_finish(result, &err);
+ if (err) {
+ nsCString warning_msg("Unable to lookup master password in libsecret: ");
+ warning_msg.Append(err->message);
+ NS_WARNING(warning_msg.get());
+ g_error_free(err);
+ }
+
+ LibsecretPromptRunnable * token = (LibsecretPromptRunnable*) data;
+ if (pwd) {
+ token->mResult = PORT_Strdup(pwd);
+ secret_password_free(pwd);
+ }
+
+ token->mRunning = false;
+}
+
+void LibsecretPromptRunnable::RunOnTargetThread()
+{
+ nsNSSShutDownPreventionLock locker;
+ nsresult rv;
+
+ // The mRetry=true means that password stored in Gnome Keyring is invalid.
+ // In this case we have to return now and keep mResult set to nullptr
+ // to make fallback to PK11PasswordPromptRunnable possible and avoid endless
+ // loop.
+ if (mRetry)
+ return;
+
+ nsCOMPtr<nsIFile> profileDir;
+ rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
+ if (rv != NS_OK)
+ return;
+
+ // Construct key item name and attributes
+ nsCString profileName;
+ rv = profileDir->GetNativeLeafName(profileName);
+ if (rv != NS_OK)
+ return;
+
+ nsCOMPtr<nsIXULAppInfo> appInfo(do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
+ nsCString keyDescription;
+ nsCString appName;
+ appInfo->GetName(appName);
+ keyDescription.Assign(appName);
+ keyDescription.Append(" - ");
+ keyDescription.Append(profileName);
+ mRunning = true;
+
+ secret_password_lookup(MOZILLA_SECRET_SCHEMA, nullptr, on_lookup_finished, this,
+ "application", appName.get(),
+ "profile", profileName.get(),
+ NULL);
+
+ // Wait until keyring operation is done
+ while (mRunning) {
+ g_main_context_iteration(nullptr, TRUE);
+ }
+}
+#endif //MOZ_ENABLE_LIBSECRET
+
class PK11PasswordPromptRunnable : public SyncRunnableBase
{
public:
PK11PasswordPromptRunnable(PK11SlotInfo* slot,
nsIInterfaceRequestor* ir)
: mResult(nullptr),
mSlot(slot),
mIR(ir)
@@ -812,16 +903,24 @@ void PK11PasswordPromptRunnable::RunOnTa
mResult = ToNewUTF8String(nsDependentString(password));
NS_Free(password);
}
}
char*
PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg)
{
+#ifdef MOZ_ENABLE_LIBSECRET
+ RefPtr<LibsecretPromptRunnable> libsecret_keyring_runnable(
+ new LibsecretPromptRunnable(retry));
+ libsecret_keyring_runnable->DispatchToMainThreadAndWait();
+ if (libsecret_keyring_runnable->mResult)
+ return libsecret_keyring_runnable->mResult;
+#endif
+
RefPtr<PK11PasswordPromptRunnable> runnable(
new PK11PasswordPromptRunnable(slot,
static_cast<nsIInterfaceRequestor*>(arg)));
runnable->DispatchToMainThreadAndWait();
return runnable->mResult;
}
void HandshakeCallback(PRFileDesc* fd, void* client_data) {
diff --git a/security/manager/ssl/src/nsPK11TokenDB.cpp b/security/manager/ssl/src/nsPK11TokenDB.cpp
--- a/security/manager/ssl/src/nsPK11TokenDB.cpp
+++ b/security/manager/ssl/src/nsPK11TokenDB.cpp
@@ -4,19 +4,29 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.h"
#include "nsIPK11TokenDB.h"
#include "prerror.h"
#include "secerr.h"
#include "nsReadableUtils.h"
#include "nsNSSComponent.h"
+#include "nsThreadUtils.h"
#include "nsPK11TokenDB.h"
+#ifdef MOZ_ENABLE_LIBSECRET
+#include "libsecret/secret.h"
+#include "libsecretMozillaSchema.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsIPrompt.h"
+#include "nsIXULAppInfo.h"
+#include "nsXPCOMCIDInternal.h"
+#endif
+
#ifdef PR_LOGGING
extern PRLogModuleInfo* gPIPNSSLog;
#endif
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
NS_IMPL_ISUPPORTS1(nsPK11Token, nsIPK11Token)
@@ -357,31 +367,173 @@ nsPK11Token::SetAskPasswordDefaults(cons
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown())
return NS_ERROR_NOT_AVAILABLE;
PK11_SetSlotPWValues(mSlot, askTimes, askTimeout);
return NS_OK;
}
+#ifdef MOZ_ENABLE_LIBSECRET
+// Use libsecret to store master password to system password management
+/**
+ * Called on main thread when async function secret_password_store finishes.
+ *
+ * @param data pointer to nsPK11Token.
+ **/
+static void
+on_libsecret_password_stored(GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+
+ nsresult res = NS_OK;
+ GError *err = nullptr;
+
+ secret_password_store_finish(result, &err);
+ if (err) {
+ nsCString warning_msg("Unable to store master password to libsecret: ");
+ warning_msg.Append(err->message);
+ NS_WARNING(warning_msg.get());
+ res = NS_ERROR_FAILURE;
+ g_error_free(err);
+ }
+
+ nsPK11Token * token = (nsPK11Token*) data;
+ token->mSecretOpResult = res;
+ token->mRunning = false;
+}
+
+/**
+ * Called on main thread when async function secret_password_clear finishes.
+ *
+ * @param data pointer to nsPK11Token.
+ **/
+static void
+on_libsecret_password_cleared(GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ nsresult res = NS_OK;
+ GError *err = nullptr;
+
+ secret_password_clear_finish(result, &err);
+ if (err) {
+ nsCString warning_msg("Unable to clear master password to libsecret: ");
+ warning_msg.Append(err->message);
+ NS_WARNING(warning_msg.get());
+ res = NS_ERROR_FAILURE;
+ g_error_free(err);
+ }
+
+
+ nsPK11Token * token = (nsPK11Token*) data;
+ token->mSecretOpResult = res;
+ token->mRunning = false;
+}
+#endif // MOZ_ENABLE_LIBSECRET
+
/* void changePassword (in wstring oldPassword, in wstring newPassword); */
NS_IMETHODIMP nsPK11Token::ChangePassword(const PRUnichar *oldPassword, const PRUnichar *newPassword)
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown())
return NS_ERROR_NOT_AVAILABLE;
- SECStatus rv;
+ SECStatus pk11_rv;
NS_ConvertUTF16toUTF8 aUtf8OldPassword(oldPassword);
NS_ConvertUTF16toUTF8 aUtf8NewPassword(newPassword);
- rv = PK11_ChangePW(mSlot,
+ pk11_rv = PK11_ChangePW(mSlot,
(oldPassword ? const_cast<char *>(aUtf8OldPassword.get()) : nullptr),
(newPassword ? const_cast<char *>(aUtf8NewPassword.get()) : nullptr));
- return (rv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
+
+ if (pk11_rv != SECSuccess)
+ return NS_ERROR_FAILURE;
+
+#ifdef MOZ_ENABLE_LIBSECRET
+ // Use Libsecret to store master password.
+ // Ask user if he wants to store master password to system password storage.
+ // Don't ask if user wants to remove password.
+ nsresult rv;
+ if (!aUtf8NewPassword.IsEmpty())
+ {
+ nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsString promptString;
+ rv = nssComponent->GetPIPNSSBundleString("LibsecretSavePrompt",
+ promptString);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIPrompt> useLibsecretPrompt;
+ nsNSSComponent::GetNewPrompter(getter_AddRefs(useLibsecretPrompt));
+ bool checkState = false;
+ int choice;
+ rv = useLibsecretPrompt->ConfirmEx(nullptr,
+ promptString.get(),
+ nsIPrompt::STD_YES_NO_BUTTONS,
+ nullptr, nullptr, nullptr, nullptr,
+ &checkState, &choice);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // User doesn't want to use Gnome Keyring, return with success
+ if (choice != 0)
+ return NS_OK;
+ }
+
+ // Get profile directory to allow storing passwords of multiple profiles
+ nsCOMPtr<nsIFile> profileDir;
+ rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Construct key label name and attributes
+ nsCString profileName;
+ rv = profileDir->GetNativeLeafName(profileName);
+ nsCOMPtr<nsIXULAppInfo> appInfo(do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
+
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCString keyLabel;
+ nsCString appName;
+ appInfo->GetName(appName);
+ keyLabel.Assign(appName);
+ keyLabel.Append(" Master Password for profile ");
+ keyLabel.Append(profileName);
+
+ mRunning = true;
+ if (aUtf8NewPassword.IsEmpty())
+ {
+ // Delete password from keyring
+ secret_password_clear(MOZILLA_SECRET_SCHEMA, nullptr,
+ on_libsecret_password_cleared,
+ this,
+ "application", appName.get(),
+ "profile", profileName.get(),
+ NULL);
+ }
+ else
+ {
+ // Save password to keyring
+ secret_password_store(MOZILLA_SECRET_SCHEMA, SECRET_COLLECTION_DEFAULT,
+ keyLabel.get(),
+ aUtf8NewPassword.get(), NULL,
+ on_libsecret_password_stored,
+ this,
+ "application", appName.get(),
+ "profile", profileName.get(),
+ NULL);
+ }
+
+ // Keep redraw loop running until secret async calls are not completed
+ while (mRunning) {
+ g_main_context_iteration(nullptr, TRUE);
+ }
+ return mSecretOpResult;
+#endif //MOZ_ENABLE_LIBSECRET
+ return NS_OK;
}
/* boolean isHardwareToken (); */
NS_IMETHODIMP nsPK11Token::IsHardwareToken(bool *_retval)
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown())
return NS_ERROR_NOT_AVAILABLE;
diff --git a/security/manager/ssl/src/nsPK11TokenDB.h b/security/manager/ssl/src/nsPK11TokenDB.h
--- a/security/manager/ssl/src/nsPK11TokenDB.h
+++ b/security/manager/ssl/src/nsPK11TokenDB.h
@@ -21,16 +21,20 @@ class nsPK11Token : public nsIPK11Token,
public nsNSSShutDownObject
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPK11TOKEN
nsPK11Token(PK11SlotInfo *slot);
virtual ~nsPK11Token();
+#ifdef MOZ_ENABLE_LIBSECRET
+ bool mRunning; /// When true, we're calling gtk main loop from ChangePassword
+ nsresult mSecretOpResult; /// Result of storage/clear password operation
+#endif
/* additional members */
private:
friend class nsPK11TokenDB;
void refreshTokenInfo();
nsString mTokenName;
nsString mTokenLabel, mTokenManID, mTokenHWVersion, mTokenFWVersion;
diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -642,16 +642,20 @@ endif
ifdef MOZ_ENABLE_QT
EXTRA_DSO_LDOPTS += $(MOZ_QT_LDFLAGS) $(XEXT_LIBS)
endif
ifdef MOZ_GSTREAMER
EXTRA_DSO_LDOPTS += $(GSTREAMER_LIBS)
endif
+ifdef MOZ_ENABLE_LIBSECRET
+EXTRA_DSO_LDOPTS += $(MOZ_LIBSECRET_LIBS)
+endif
+
include $(topsrcdir)/config/rules.mk
export:: $(RDF_UTIL_SRC_CPPSRCS) $(INTL_UNICHARUTIL_UTIL_CPPSRCS)
$(INSTALL) $^ .
# need widget/windows for resource.h (included from widget.rc)
LOCAL_INCLUDES += \
-I$(topsrcdir)/config \
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment