tor-commits
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
October 2011
- 18 participants
- 1256 discussions
commit f799f2a0b743a185b4aa6b1cb5b058c7a51f5670
Author: Mike Perry <mikeperry-git(a)fscked.org>
Date: Sat Aug 20 10:23:09 2011 -0700
Fix the 3rd firefox patch.
---
...-Make-Intermediate-Cert-Store-memory-only.patch | 18 +++++++++---------
1 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/current-patches/0003-Firefox6-Make-Intermediate-Cert-Store-memory-only.patch b/src/current-patches/0003-Firefox6-Make-Intermediate-Cert-Store-memory-only.patch
index 9c568a0..68d426d 100644
--- a/src/current-patches/0003-Firefox6-Make-Intermediate-Cert-Store-memory-only.patch
+++ b/src/current-patches/0003-Firefox6-Make-Intermediate-Cert-Store-memory-only.patch
@@ -1,4 +1,4 @@
-From 2bdee82990bbda960d23d6122bf89d422bb63211 Mon Sep 17 00:00:00 2001
+From c50f65a9f11e09332c2c97678b685d2bdcad7d62 Mon Sep 17 00:00:00 2001
From: Mike Perry <mikeperry-git(a)fscked.org>
Date: Fri, 19 Aug 2011 17:58:23 -0700
Subject: [PATCH 3/3] Firefox6: Make Intermediate Cert Store memory-only.
@@ -8,17 +8,18 @@ This patch makes the intermediate SSL cert store exist in memory only.
The pref must be set before startup in prefs.js.
https://trac.torproject.org/projects/tor/ticket/2949
---
- security/manager/ssl/src/nsNSSComponent.cpp | 16 ++++++++++++++++
- 1 files changed, 16 insertions(+), 0 deletions(-)
+ security/manager/ssl/src/nsNSSComponent.cpp | 15 ++++++++++++++-
+ 1 files changed, 14 insertions(+), 1 deletions(-)
diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp
-index 7a8569b..5261c5e 100644
+index 7a8569b..828c3eb 100644
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
-@@ -1729,6 +1729,22 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
+@@ -1729,8 +1729,21 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
// Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
// "/usr/lib/nss/libnssckbi.so".
PRUint32 init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
+- SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
+ PRBool nocertdb = false;
+ mPrefBranch->GetBoolPref("security.nocertdb", &nocertdb);
+
@@ -32,12 +33,11 @@ index 7a8569b..5261c5e 100644
+ init_rv = ::NSS_NoDB_Init(NULL);
+ } else {
+ init_rv = ::NSS_Initialize(profileStr.get(), "", "",
-+ SECMOD_DB, init_flags);
-+ }
-+
- SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
SECMOD_DB, init_flags);
++ }
+ if (init_rv != SECSuccess) {
+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init NSS r/w in %s\n", profileStr.get()));
--
1.7.3.4
1
0

[torbrowser/master] Merge branches 'ff6-minimal' and 'maint-2.2' into maint-2.2
by erinn@torproject.org 23 Oct '11
by erinn@torproject.org 23 Oct '11
23 Oct '11
commit 47c49cd1a98edf4dee0cfb72a2183c02cd43ca82
Author: Erinn Clark <erinn(a)torproject.org>
Date: Sat Aug 20 16:14:28 2011 +0200
Merge branches 'ff6-minimal' and 'maint-2.2' into maint-2.2
1
0
commit a818cff3a7d842ebcab7ca9efc7fb191f16e419e
Author: Erinn Clark <erinn(a)torproject.org>
Date: Sat Aug 20 16:41:12 2011 +0200
update firefox-build target
---
build-scripts/osx.mk | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/build-scripts/osx.mk b/build-scripts/osx.mk
index 1a59db4..7151ddf 100644
--- a/build-scripts/osx.mk
+++ b/build-scripts/osx.mk
@@ -103,7 +103,7 @@ build-tor:
FIREFOX_DIR=$(FETCH_DIR)/mozilla-release
build-firefox:
- cp ../src/current-patches/*Firefox5* $(FIREFOX_DIR)
+ cp ../src/current-patches/*Firefox* $(FIREFOX_DIR)
cp patch-firefox-src.sh $(FIREFOX_DIR)
cp $(CONFIG_SRC)/mozconfig-osx-$(ARCH_TYPE) $(FIREFOX_DIR)/mozconfig
cd $(FIREFOX_DIR) && ./patch-firefox-src.sh
1
0

[torbrowser/master] bump experimental TBBs to 2.2.31, tor to 0.2.2.31-rc, Firefox to 6.0, update other versions too
by erinn@torproject.org 23 Oct '11
by erinn@torproject.org 23 Oct '11
23 Oct '11
commit cdc9067b126c9cf6e9ea5c62e16d816b83e8e8e9
Author: Erinn Clark <erinn(a)torproject.org>
Date: Sat Aug 20 21:02:03 2011 +0200
bump experimental TBBs to 2.2.31, tor to 0.2.2.31-rc, Firefox to 6.0, update other versions too
---
README.LINUX-2.2 | 9 ++++-----
README.OSX-2.2 | 9 ++++-----
README.WIN-2.2 | 9 ++++-----
build-scripts/versions.mk | 14 +++++++-------
changelog.linux-2.2 | 12 ++++++++++++
changelog.osx-2.2 | 14 +++++++++++++-
changelog.win-2.2 | 14 +++++++++++++-
7 files changed, 57 insertions(+), 24 deletions(-)
diff --git a/README.LINUX-2.2 b/README.LINUX-2.2
index c871c74..47f2684 100644
--- a/README.LINUX-2.2
+++ b/README.LINUX-2.2
@@ -5,12 +5,11 @@ Included applications
---------------------
Vidalia 0.2.12 (with Qt 4.6.2)
-Tor 0.2.2.30-rc (with libevent-2.0.12-stable, zlib-1.2.5 and openssl-1.0.0d)
-Firefox (Aurora) 5.0.1
+Tor 0.2.2.31-rc (with libevent-2.0.13-stable, zlib-1.2.5 and openssl-1.0.0d)
+Firefox (Aurora) 6.0
\_ Torbutton 1.4.0
- |_ NoScript 2.1.1.2
- |_ HTTPS-Everywhere 1.0.0development.4
- |_ BetterPrivacy 1.51
+ |_ NoScript 2.1.2.6
+ |_ HTTPS-Everywhere 1.0.0development.5
Usage
-----
diff --git a/README.OSX-2.2 b/README.OSX-2.2
index 88564a6..750e540 100644
--- a/README.OSX-2.2
+++ b/README.OSX-2.2
@@ -5,12 +5,11 @@ Included applications
---------------------
Vidalia 0.2.12 (with Qt 4.6.2)
-Tor 0.2.2.30-rc (with libevent-2.0.12-stable, zlib-1.2.5 and openssl-1.0.0d)
-Firefox (Aurora) 5.0.1
+Tor 0.2.2.31-rc (with libevent-2.0.13-stable, zlib-1.2.5 and openssl-1.0.0d)
+Firefox (Aurora) 6.0
\_ Torbutton 1.4.0
- |_ NoScript 2.1.1.2
- |_ HTTPS-Everywhere 1.0.0development.4
- |_ BetterPrivacy 1.51
+ |_ NoScript 2.1.2.6
+ |_ HTTPS-Everywhere 1.0.0development.5
Usage
-----
diff --git a/README.WIN-2.2 b/README.WIN-2.2
index dbe8ffb..519c64f 100644
--- a/README.WIN-2.2
+++ b/README.WIN-2.2
@@ -5,13 +5,12 @@ Included applications
---------------------
Vidalia 0.2.12 (with Qt 4.6.2)
-Tor 0.2.2.30-rc (with libevent-2.0.12-stable, zlib-1.2.5 and openssl-1.0.0d)
+Tor 0.2.2.31-rc (with libevent-2.0.13-stable, zlib-1.2.5 and openssl-1.0.0d)
FirefoxPortable 5.0.1
- \_ Firefox (Aurora) 5.0.1
+ \_ Firefox (Aurora) 6.0
\_ Torbutton 1.4.0
- |_ NoScript 2.1.1.2
- |_ HTTPS-Everywhere 1.0.0development.4
- |_ BetterPrivacy 1.51
+ |_ NoScript 2.1.2.6
+ |_ HTTPS-Everywhere 1.0.0development.5
Usage
-----
diff --git a/build-scripts/versions.mk b/build-scripts/versions.mk
index af23c30..e116326 100644
--- a/build-scripts/versions.mk
+++ b/build-scripts/versions.mk
@@ -1,21 +1,21 @@
#!/usr/bin/make
-RELEASE_VER=2.2.30
+RELEASE_VER=2.2.31
-HTTPSEVERY_VER=1.0.0development.4
-FIREFOX_VER=5.0.1
-LIBEVENT_VER=2.0.12-stable
+HTTPSEVERY_VER=1.0.0development.5
+FIREFOX_VER=6.0
+LIBEVENT_VER=2.0.13-stable
LIBPNG_VER=1.4.3
-NOSCRIPT_VER=2.1.1.2
+NOSCRIPT_VER=2.1.2.6
OPENSSL_VER=1.0.0d
OTR_VER=3.2.0
PIDGIN_VER=2.6.4
POLIPO_VER=1.0.4.1
QT_VER=4.6.2
-TOR_VER=0.2.2.30-rc
+TOR_VER=0.2.2.31-rc
TORBUTTON_VER=1.4.0
VIDALIA_VER=0.2.12
-ZLIB_VER=1.2.5
+ZLIB_VER=1.4.0
## Extension IDs
FF_VENDOR_ID:=\{ec8030f7-c20a-464f-9b0e-13a3a9e97384\}
diff --git a/changelog.linux-2.2 b/changelog.linux-2.2
index f9119c5..20d8bc5 100644
--- a/changelog.linux-2.2
+++ b/changelog.linux-2.2
@@ -1,3 +1,15 @@
+Tor Browser Bundle (2.2.30-1) alpha; suite=osx
+
+ * Update Tor to 0.2.2.31-rc
+ * Update Firefox to 6.0
+ * Update Libevent to 2.0.13-stable
+ * Update NoScript to 2.1.2.6
+ * Update HTTPS Everywhere to 1.0.0development.5
+ * Remove BetterPrivacy until we can figure out how to make it safe in all
+ bundles (see #3597)
+
+ -- Erinn Clark <erinn(a)torproject.org> Sat Aug 20 20:40:52 CEST 2011
+
Tor Browser Bundle (2.2.30-1) alpha; suite=linux
* Update Tor to 0.2.2.30-rc
diff --git a/changelog.osx-2.2 b/changelog.osx-2.2
index 888aaf5..ff6763d 100644
--- a/changelog.osx-2.2
+++ b/changelog.osx-2.2
@@ -1,8 +1,20 @@
+Tor Browser Bundle (2.2.30-1) alpha; suite=osx
+
+ * Update Tor to 0.2.2.31-rc
+ * Update Firefox to 6.0
+ * Update Libevent to 2.0.13-stable
+ * Update NoScript to 2.1.2.6
+ * Update HTTPS Everywhere to 1.0.0development.5
+ * Remove BetterPrivacy until we can figure out how to make it safe in all
+ bundles (see #3597)
+
+ -- Erinn Clark <erinn(a)torproject.org> Sat Aug 20 20:40:52 CEST 2011
+
Tor Browser Bundle (2.2.30-2) alpha; suite=osx
* Update Firefox to 5.0.1
- - Erinn Clark <erinn(a)torproject.org> Wed Jul 13 09:07:41 ART 2011
+ -- Erinn Clark <erinn(a)torproject.org> Wed Jul 13 09:07:41 ART 2011
Tor Browser Bundle (2.2.30-1) alpha; suite=osx
diff --git a/changelog.win-2.2 b/changelog.win-2.2
index ee916bc..bde8ad4 100644
--- a/changelog.win-2.2
+++ b/changelog.win-2.2
@@ -1,8 +1,20 @@
+Tor Browser Bundle (2.2.30-1) alpha; suite=osx
+
+ * Update Tor to 0.2.2.31-rc
+ * Update Firefox to 6.0
+ * Update Libevent to 2.0.13-stable
+ * Update NoScript to 2.1.2.6
+ * Update HTTPS Everywhere to 1.0.0development.5
+ * Remove BetterPrivacy until we can figure out how to make it safe in all
+ bundles (see #3597)
+
+ -- Erinn Clark <erinn(a)torproject.org> Sat Aug 20 20:40:52 CEST 2011
+
Tor Browser Bundle (2.2.30-2) alpha; suite=windows
* Update Firefox to 5.0.1
- - Erinn Clark <erinn(a)torproject.org> Wed Jul 13 09:07:41 ART 2011
+ -- Erinn Clark <erinn(a)torproject.org> Wed Jul 13 09:07:41 ART 2011
Tor Browser Bundle (2.2.30-1) alpha; suite=windows
1
0

[torbrowser/master] re-enable addon update checking. closes #3554.
by erinn@torproject.org 23 Oct '11
by erinn@torproject.org 23 Oct '11
23 Oct '11
commit 726d52ef79a8c2d49ebca70d66c7731d5a0568dc
Author: Erinn Clark <erinn(a)torproject.org>
Date: Sun Jul 10 09:35:19 2011 -0300
re-enable addon update checking. closes #3554.
---
build-scripts/config/no-polipo-4.0.js | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/build-scripts/config/no-polipo-4.0.js b/build-scripts/config/no-polipo-4.0.js
index 06a8f4d..2437752 100644
--- a/build-scripts/config/no-polipo-4.0.js
+++ b/build-scripts/config/no-polipo-4.0.js
@@ -61,7 +61,7 @@ user_pref("extensions.bprivacy.donotaskforfolder", true);
user_pref("extensions.bprivacy.donotaskonexit", true);
user_pref("extensions.bprivacy.initiated", true);
user_pref("extensions.checkCompatibility.4.*", false);
-user_pref("extensions.checkUpdateSecurity", false);
+user_pref("extensions.checkUpdateSecurity", true);
user_pref("extensions.databaseSchema", 3);
user_pref("extensions.enabledAddons", "https-everywhere@eff.org:0.9.9.development.4,{73a6fe31-595d-460b-a920-fcc0f8843232}:2.1.0.3,{d40f5e7b-d2cf-4856-b441-cc613eeffbe3}:1.50,{e0204bd5-9d31-402b-a99d-a6aa8ffebdca}:1.3.3-alpha");
user_pref("extensions.enabledItems", "langpack-en-US@firefox.mozilla.org:,{73a6fe31-595d-460b-a920-fcc0f8843232}:1.9.9.57,{e0204bd5-9d31-402b-a99d-a6aa8ffebdca}:1.2.4,{972ce4c6-7e08-4474-a285-3208198ce6fd}:3.5.8");
@@ -80,7 +80,7 @@ user_pref("extensions.torbutton.socks_port", 9050);
user_pref("extensions.torbutton.tor_enabled", true);
user_pref("extensions.torbutton.tor_memory_jar", true);
user_pref("extensions.torbutton.tz_string", "UTC+00:00");
-user_pref("extensions.update.enabled", false);
+user_pref("extensions.update.enabled", true);
user_pref("extensions.update.notifyUser", false);
user_pref("general.appname.override", "Netscape");
user_pref("general.appversion.override", "5.0 (Windows; en-US)");
1
0

[torbrowser/master] Add missing header to intermediate cert store patch
by erinn@torproject.org 23 Oct '11
by erinn@torproject.org 23 Oct '11
23 Oct '11
commit 7e288fdc4bdac4e4533f2cdc09bd0a7ec47ffdac
Author: Sebastian Hahn <sebastian(a)torproject.org>
Date: Sun Jul 10 00:06:12 2011 +0200
Add missing header to intermediate cert store patch
The patch omitted the changes necessary in nsNSSComponent.h and only
contained the changes for nsNSSComponent.cpp. This would mean that the
patch could be applied, but the build failed. Add the missing part of
the patch.
---
...-Make-Intermediate-Cert-Store-memory-only.patch | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/src/current-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch b/src/current-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch
index 17ad3a2..2bd11e8 100644
--- a/src/current-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch
+++ b/src/current-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch
@@ -278,6 +278,23 @@ index d3ae772..fa37ace 100644
}
void
+--- a/security/manager/ssl/src/nsNSSComponent.h
++++ b/security/manager/ssl/src/nsNSSComponent.h
+@@ -321,10 +321,10 @@
+
+ // Methods that we use to handle the profile change notifications (and to
+ // synthesize a full profile change when we're just doing a profile startup):
+- void DoProfileApproveChange(nsISupports* aSubject);
++ PRBool DoProfileApproveChange(nsISupports* aSubject);
+ void DoProfileChangeNetTeardown();
+- void DoProfileChangeTeardown(nsISupports* aSubject);
+- void DoProfileBeforeChange(nsISupports* aSubject);
++ PRBool DoProfileChangeTeardown(nsISupports* aSubject);
++ PRBool DoProfileBeforeChange(nsISupports* aSubject);
+ void DoProfileChangeNetRestore();
+
+ Mutex mutex;
+
--
1.7.3.4
1
0

[torbrowser/master] add torbutton target back to makefile now that I no longer need to change the privoxy setting
by erinn@torproject.org 23 Oct '11
by erinn@torproject.org 23 Oct '11
23 Oct '11
commit 350e140f1b3dbef7f2f6004961cb816013cc1089
Author: Erinn Clark <erinn(a)torproject.org>
Date: Sun Jul 10 09:02:31 2011 -0300
add torbutton target back to makefile now that I no longer need to change the privoxy setting
---
build-scripts/osx.mk | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/build-scripts/osx.mk b/build-scripts/osx.mk
index 5f00421..e8303f1 100644
--- a/build-scripts/osx.mk
+++ b/build-scripts/osx.mk
@@ -315,8 +315,8 @@ strip-it-stripper:
##
## Torbutton development version
-#torbutton.xpi:
-# $(WGET) --no-check-certificate -O $@ $(TORBUTTON)
+torbutton.xpi:
+ $(WGET) --no-check-certificate -O $@ $(TORBUTTON)
## BetterPrivacy
betterprivacy.xpi:
1
0

[torbrowser/master] remove unnecessary file extension from https-everywhere version string
by erinn@torproject.org 23 Oct '11
by erinn@torproject.org 23 Oct '11
23 Oct '11
commit a89d9b1919f621918a874762fc9d57da50e768d5
Author: Erinn Clark <erinn(a)torproject.org>
Date: Sun Jul 10 09:04:06 2011 -0300
remove unnecessary file extension from https-everywhere version string
---
build-scripts/versions.mk | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/build-scripts/versions.mk b/build-scripts/versions.mk
index e7d092a..4dc8589 100644
--- a/build-scripts/versions.mk
+++ b/build-scripts/versions.mk
@@ -2,7 +2,7 @@
RELEASE_VER=2.2.30
-HTTPSEVERY_VER=1.0.0development.4.xpi
+HTTPSEVERY_VER=1.0.0development.4
FIREFOX_VER=5.0
LIBEVENT_VER=2.0.12-stable
LIBPNG_VER=1.4.3
1
0

[torbrowser/master] Update Firefox patches for FF6, and slim them down.
by erinn@torproject.org 23 Oct '11
by erinn@torproject.org 23 Oct '11
23 Oct '11
commit 9fc85439ccb46e6b589fbac814631b35a5284bd8
Author: Mike Perry <mikeperry-git(a)fscked.org>
Date: Fri Aug 19 18:13:23 2011 -0700
Update Firefox patches for FF6, and slim them down.
Relocate old firefox patches to archive.
---
.../0001-Firefox4-Fix-SOCKS-timeout.patch | 1500 ++++++++++++++++++++
...ock-Components.interfaces-lookupMethod-fr.patch | 50 +
...ock-Components.interfaces-lookupMethod-fr.patch | 50 +
...-Make-Intermediate-Cert-Store-memory-only.patch | 300 ++++
...-Make-Intermediate-Cert-Store-memory-only.patch | 283 ++++
...fox5-Make-Permissions-Manager-memory-only.patch | 94 ++
...fox4-Make-Permissions-Manager-memory-only.patch | 94 ++
.../0001-Firefox4-Fix-SOCKS-timeout.patch | 1500 --------------------
...ock-Components.interfaces-lookupMethod-fr.patch | 50 -
...ock-Components.interfaces-lookupMethod-fr.patch | 50 +
...ock-Components.interfaces-lookupMethod-fr.patch | 50 -
...-Make-Intermediate-Cert-Store-memory-only.patch | 300 ----
...fox6-Make-Permissions-Manager-memory-only.patch | 94 ++
...-Make-Intermediate-Cert-Store-memory-only.patch | 283 ----
...fox5-Make-Permissions-Manager-memory-only.patch | 94 --
...-Make-Intermediate-Cert-Store-memory-only.patch | 43 +
...fox4-Make-Permissions-Manager-memory-only.patch | 94 --
17 files changed, 2558 insertions(+), 2371 deletions(-)
diff --git a/src/archived-patches/0001-Firefox4-Fix-SOCKS-timeout.patch b/src/archived-patches/0001-Firefox4-Fix-SOCKS-timeout.patch
new file mode 100644
index 0000000..3b9343e
--- /dev/null
+++ b/src/archived-patches/0001-Firefox4-Fix-SOCKS-timeout.patch
@@ -0,0 +1,1500 @@
+From d37dce07b9eb9b40244d2fa867728e7a57a33f0f Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Mon, 20 Jun 2011 17:07:33 -0700
+Subject: [PATCH 1/4] Firefox4: Fix SOCKS timeout
+
+This patch by chrisd removes the hardcoded SOCKS timeout by rewriting the
+Firefox SOCKS code to use non-blocking IO.
+
+See also: https://bugzilla.mozilla.org/show_bug.cgi?id=280661
+https://trac.torproject.org/projects/tor/ticket/3247
+---
+ netwerk/base/src/nsSocketTransport2.cpp | 21 +-
+ netwerk/socket/nsSOCKSIOLayer.cpp | 1273 ++++++++++++++++++-------------
+ 2 files changed, 775 insertions(+), 519 deletions(-)
+
+diff --git a/netwerk/base/src/nsSocketTransport2.cpp b/netwerk/base/src/nsSocketTransport2.cpp
+index 3f95dfd..fb363db 100644
+--- a/netwerk/base/src/nsSocketTransport2.cpp
++++ b/netwerk/base/src/nsSocketTransport2.cpp
+@@ -1227,6 +1227,16 @@ nsSocketTransport::InitiateSocket()
+ }
+ }
+ //
++ // A SOCKS request was rejected; get the actual error code from
++ // the OS error
++ //
++ else if (PR_UNKNOWN_ERROR == code &&
++ mProxyTransparent &&
++ !mProxyHost.IsEmpty()) {
++ code = PR_GetOSError();
++ rv = ErrorAccordingToNSPR(code);
++ }
++ //
+ // The connection was refused...
+ //
+ else {
+@@ -1549,7 +1559,16 @@ nsSocketTransport::OnSocketReady(PRFileDesc *fd, PRInt16 outFlags)
+ mPollFlags = (PR_POLL_EXCEPT | PR_POLL_WRITE);
+ // Update poll timeout in case it was changed
+ mPollTimeout = mTimeouts[TIMEOUT_CONNECT];
+- }
++ }
++ //
++ // The SOCKS proxy rejected our request. Find out why.
++ //
++ else if (PR_UNKNOWN_ERROR == code &&
++ mProxyTransparent &&
++ !mProxyHost.IsEmpty()) {
++ code = PR_GetOSError();
++ mCondition = ErrorAccordingToNSPR(code);
++ }
+ else {
+ //
+ // else, the connection failed...
+diff --git a/netwerk/socket/nsSOCKSIOLayer.cpp b/netwerk/socket/nsSOCKSIOLayer.cpp
+index 9a15667..4d3a4e8 100644
+--- a/netwerk/socket/nsSOCKSIOLayer.cpp
++++ b/netwerk/socket/nsSOCKSIOLayer.cpp
+@@ -25,6 +25,7 @@
+ * Bradley Baetz <bbaetz(a)acm.org>
+ * Darin Fisher <darin(a)meer.net>
+ * Malcolm Smith <malsmith(a)cs.rmit.edu.au>
++ * Christopher Davis <chrisd(a)torproject.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+@@ -68,9 +69,28 @@ static PRLogModuleInfo *gSOCKSLog;
+
+ class nsSOCKSSocketInfo : public nsISOCKSSocketInfo
+ {
++ enum State {
++ SOCKS_INITIAL,
++ SOCKS_CONNECTING_TO_PROXY,
++ SOCKS4_WRITE_CONNECT_REQUEST,
++ SOCKS4_READ_CONNECT_RESPONSE,
++ SOCKS5_WRITE_AUTH_REQUEST,
++ SOCKS5_READ_AUTH_RESPONSE,
++ SOCKS5_WRITE_CONNECT_REQUEST,
++ SOCKS5_READ_CONNECT_RESPONSE_TOP,
++ SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
++ SOCKS_CONNECTED,
++ SOCKS_FAILED
++ };
++
++ // A buffer of 262 bytes should be enough for any request and response
++ // in case of SOCKS4 as well as SOCKS5
++ static const PRUint32 BUFFER_SIZE = 262;
++ static const PRUint32 MAX_HOSTNAME_LEN = 255;
++
+ public:
+ nsSOCKSSocketInfo();
+- virtual ~nsSOCKSSocketInfo() {}
++ virtual ~nsSOCKSSocketInfo() { HandshakeFinished(); }
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISOCKSSOCKETINFO
+@@ -81,13 +101,50 @@ public:
+ const char *destinationHost,
+ PRUint32 flags);
+
+- const nsCString &DestinationHost() { return mDestinationHost; }
+- const nsCString &ProxyHost() { return mProxyHost; }
+- PRInt32 ProxyPort() { return mProxyPort; }
+- PRInt32 Version() { return mVersion; }
+- PRUint32 Flags() { return mFlags; }
++ void SetConnectTimeout(PRIntervalTime to);
++ PRStatus DoHandshake(PRFileDesc *fd, PRInt16 oflags = -1);
++ PRInt16 GetPollFlags() const;
++ bool IsConnected() const { return mState == SOCKS_CONNECTED; }
++
++private:
++ void HandshakeFinished(PRErrorCode err = 0);
++ PRStatus ConnectToProxy(PRFileDesc *fd);
++ PRStatus ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags);
++ PRStatus WriteV4ConnectRequest();
++ PRStatus ReadV4ConnectResponse();
++ PRStatus WriteV5AuthRequest();
++ PRStatus ReadV5AuthResponse();
++ PRStatus WriteV5ConnectRequest();
++ PRStatus ReadV5AddrTypeAndLength(PRUint8 *type, PRUint32 *len);
++ PRStatus ReadV5ConnectResponseTop();
++ PRStatus ReadV5ConnectResponseBottom();
++
++ void WriteUint8(PRUint8 d);
++ void WriteUint16(PRUint16 d);
++ void WriteUint32(PRUint32 d);
++ void WriteNetAddr(const PRNetAddr *addr);
++ void WriteNetPort(const PRNetAddr *addr);
++ void WriteString(const nsACString &str);
++
++ PRUint8 ReadUint8();
++ PRUint16 ReadUint16();
++ PRUint32 ReadUint32();
++ void ReadNetAddr(PRNetAddr *addr, PRUint16 fam);
++ void ReadNetPort(PRNetAddr *addr);
++
++ void WantRead(PRUint32 sz);
++ PRStatus ReadFromSocket(PRFileDesc *fd);
++ PRStatus WriteToSocket(PRFileDesc *fd);
+
+ private:
++ State mState;
++ PRUint8 * mData;
++ PRUint8 * mDataIoPtr;
++ PRUint32 mDataLength;
++ PRUint32 mReadOffset;
++ PRUint32 mAmountToRead;
++ nsCOMPtr<nsIDNSRecord> mDnsRec;
++
+ nsCString mDestinationHost;
+ nsCString mProxyHost;
+ PRInt32 mProxyPort;
+@@ -96,13 +153,21 @@ private:
+ PRNetAddr mInternalProxyAddr;
+ PRNetAddr mExternalProxyAddr;
+ PRNetAddr mDestinationAddr;
++ PRIntervalTime mTimeout;
+ };
+
+ nsSOCKSSocketInfo::nsSOCKSSocketInfo()
+- : mProxyPort(-1)
++ : mState(SOCKS_INITIAL)
++ , mDataIoPtr(nsnull)
++ , mDataLength(0)
++ , mReadOffset(0)
++ , mAmountToRead(0)
++ , mProxyPort(-1)
+ , mVersion(-1)
+ , mFlags(0)
++ , mTimeout(PR_INTERVAL_NO_TIMEOUT)
+ {
++ mData = new PRUint8[BUFFER_SIZE];
+ PR_InitializeNetAddr(PR_IpAddrAny, 0, &mInternalProxyAddr);
+ PR_InitializeNetAddr(PR_IpAddrAny, 0, &mExternalProxyAddr);
+ PR_InitializeNetAddr(PR_IpAddrAny, 0, &mDestinationAddr);
+@@ -162,637 +227,807 @@ nsSOCKSSocketInfo::SetInternalProxyAddr(PRNetAddr *aInternalProxyAddr)
+ return NS_OK;
+ }
+
+-static PRInt32
+-pr_RecvAll(PRFileDesc *fd, unsigned char *buf, PRInt32 amount, PRIntn flags,
+- PRIntervalTime *timeout)
++// There needs to be a means of distinguishing between connection errors
++// that the SOCKS server reports when it rejects a connection request, and
++// connection errors that happen while attempting to connect to the SOCKS
++// server. Otherwise, Firefox will report incorrectly that the proxy server
++// is refusing connections when a SOCKS request is rejected by the proxy.
++// When a SOCKS handshake failure occurs, the PR error is set to
++// PR_UNKNOWN_ERROR, and the real error code is returned via the OS error.
++void
++nsSOCKSSocketInfo::HandshakeFinished(PRErrorCode err)
+ {
+- PRInt32 bytesRead = 0;
+- PRInt32 offset = 0;
++ if (err == 0) {
++ mState = SOCKS_CONNECTED;
++ } else {
++ mState = SOCKS_FAILED;
++ PR_SetError(PR_UNKNOWN_ERROR, err);
++ }
+
+- while (offset < amount) {
+- PRIntervalTime start_time = PR_IntervalNow();
+- bytesRead = PR_Recv(fd, buf + offset, amount - offset, flags, *timeout);
+- PRIntervalTime elapsed = PR_IntervalNow() - start_time;
++ // We don't need the buffer any longer, so free it.
++ delete [] mData;
++ mData = nsnull;
++ mDataIoPtr = nsnull;
++ mDataLength = 0;
++ mReadOffset = 0;
++ mAmountToRead = 0;
++}
+
+- if (elapsed > *timeout) {
+- *timeout = 0;
+- } else {
+- *timeout -= elapsed;
+- }
++PRStatus
++nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc *fd)
++{
++ PRStatus status;
++ nsresult rv;
+
+- if (bytesRead > 0) {
+- offset += bytesRead;
+- } else if (bytesRead == 0 || offset != 0) {
+- return offset;
+- } else {
+- return bytesRead;
+- }
++ NS_ABORT_IF_FALSE(mState == SOCKS_INITIAL,
++ "Must be in initial state to make connection!");
+
+- if (*timeout == 0) {
+- LOGERROR(("PR_Recv() timed out. amount = %d. offset = %d.",
+- amount, offset));
+- return offset;
++ // If we haven't performed the DNS lookup, do that now.
++ if (!mDnsRec) {
++ nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
++ if (!dns)
++ return PR_FAILURE;
++
++ rv = dns->Resolve(mProxyHost, 0, getter_AddRefs(mDnsRec));
++ if (NS_FAILED(rv)) {
++ LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed",
++ mProxyHost.get()));
++ return PR_FAILURE;
+ }
+ }
+- return offset;
+-}
+
+-static PRInt32
+-pr_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+- PRIntervalTime *timeout)
+-{
+- PRIntervalTime start_time = PR_IntervalNow();
+- PRInt32 retval = PR_Send(fd, buf, amount, flags, *timeout);
+- PRIntervalTime elapsed = PR_IntervalNow() - start_time;
+-
+- if (elapsed > *timeout) {
+- *timeout = 0;
+- LOGERROR(("PR_Send() timed out. amount = %d. retval = %d.",
+- amount, retval));
+- return retval;
+- } else {
+- *timeout -= elapsed;
+- }
++ do {
++ rv = mDnsRec->GetNextAddr(mProxyPort, &mInternalProxyAddr);
++ // No more addresses to try? If so, we'll need to bail
++ if (NS_FAILED(rv)) {
++ LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
++ mProxyHost.get()));
++ return PR_FAILURE;
++ }
+
+- if (retval <= 0) {
+- LOGERROR(("PR_Send() failed. amount = %d. retval = %d.",
+- amount, retval));
+- }
++#if defined(PR_LOGGING)
++ char buf[64];
++ PR_NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
++ LOGDEBUG(("socks: trying proxy server, %s:%hu",
++ buf, PR_ntohs(PR_NetAddrInetPort(&mInternalProxyAddr))));
++#endif
++ status = fd->lower->methods->connect(fd->lower,
++ &mInternalProxyAddr, mTimeout);
++ if (status != PR_SUCCESS) {
++ PRErrorCode c = PR_GetError();
++ // If EINPROGRESS, return now and check back later after polling
++ if (c == PR_WOULD_BLOCK_ERROR || c == PR_IN_PROGRESS_ERROR) {
++ mState = SOCKS_CONNECTING_TO_PROXY;
++ return status;
++ }
++ }
++ } while (status != PR_SUCCESS);
+
+- return retval;
++ // Connected now, start SOCKS
++ if (mVersion == 4)
++ return WriteV4ConnectRequest();
++ return WriteV5AuthRequest();
+ }
+
+-// Negotiate a SOCKS 5 connection. Assumes the TCP connection to the socks
+-// server port has been established.
+-static nsresult
+-ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRIntervalTime timeout)
++PRStatus
++nsSOCKSSocketInfo::ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags)
+ {
+- int request_len = 0;
+- int response_len = 0;
+- int desired_len = 0;
+- unsigned char request[22];
+- unsigned char response[262];
+-
+- NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
+- NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
+- NS_ENSURE_TRUE(extAddr, NS_ERROR_NOT_INITIALIZED);
+-
+- request[0] = 0x05; // SOCKS version 5
+- request[1] = 0x01; // number of auth procotols we recognize
+- // auth protocols
+- request[2] = 0x00; // no authentication required
+- // compliant implementations MUST implement GSSAPI
+- // and SHOULD implement username/password and MAY
+- // implement CHAP
+- // TODO: we don't implement these
+- //request[3] = 0x01; // GSSAPI
+- //request[4] = 0x02; // username/password
+- //request[5] = 0x03; // CHAP
++ PRStatus status;
+
+- request_len = 2 + request[1];
+- int write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- return NS_ERROR_FAILURE;
+- }
++ NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
++ "Continuing connection in wrong state!");
+
+- // get the server's response.
+- desired_len = 2;
+- response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
++ LOGDEBUG(("socks: continuing connection to proxy"));
+
+- if (response_len < desired_len) {
+- LOGERROR(("pr_RecvAll() failed. response_len = %d.", response_len));
+- return NS_ERROR_FAILURE;
+- }
++ status = fd->lower->methods->connectcontinue(fd->lower, oflags);
++ if (status != PR_SUCCESS) {
++ PRErrorCode c = PR_GetError();
++ if (c != PR_WOULD_BLOCK_ERROR && c != PR_IN_PROGRESS_ERROR) {
++ // A connection failure occured, try another address
++ mState = SOCKS_INITIAL;
++ return ConnectToProxy(fd);
++ }
+
+- if (response[0] != 0x05) {
+- // it's a either not SOCKS or not our version
+- LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));
+- return NS_ERROR_FAILURE;
+- }
+- switch (response[1]) {
+- case 0x00:
+- // no auth
+- break;
+- case 0x01:
+- // GSSAPI
+- // TODO: implement
+- LOGERROR(("Server want to use GSSAPI to authenticate, but we don't support it."));
+- return NS_ERROR_FAILURE;
+- case 0x02:
+- // username/password
+- // TODO: implement
+- LOGERROR(("Server want to use username/password to authenticate, but we don't support it."));
+- return NS_ERROR_FAILURE;
+- case 0x03:
+- // CHAP
+- // TODO: implement?
+- LOGERROR(("Server want to use CHAP to authenticate, but we don't support it."));
+- return NS_ERROR_FAILURE;
+- default:
+- // unrecognized auth method
+- LOGERROR(("Uncrecognized authentication method received: %x", response[1]));
+- return NS_ERROR_FAILURE;
++ // We're still connecting
++ return PR_FAILURE;
+ }
+
+- // we are now authenticated, so lets tell
+- // the server where to connect to
++ // Connected now, start SOCKS
++ if (mVersion == 4)
++ return WriteV4ConnectRequest();
++ return WriteV5AuthRequest();
++}
+
+- request_len = 0;
++PRStatus
++nsSOCKSSocketInfo::WriteV4ConnectRequest()
++{
++ PRNetAddr *addr = &mDestinationAddr;
++ PRInt32 proxy_resolve;
+
+- request[0] = 0x05; // SOCKS version 5
+- request[1] = 0x01; // CONNECT command
+- request[2] = 0x00; // obligatory reserved field (perfect for MS tampering!)
++ NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
++ "Invalid state!");
++
++ proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
++
++ mDataLength = 0;
++ mState = SOCKS4_WRITE_CONNECT_REQUEST;
++
++ LOGDEBUG(("socks4: sending connection request (socks4a resolve? %s)",
++ proxy_resolve? "yes" : "no"));
++
++ // Send a SOCKS 4 connect request.
++ WriteUint8(0x04); // version -- 4
++ WriteUint8(0x01); // command -- connect
++ WriteNetPort(addr);
++ if (proxy_resolve) {
++ // Add the full name, null-terminated, to the request
++ // according to SOCKS 4a. A fake IP address, with the first
++ // four bytes set to 0 and the last byte set to something other
++ // than 0, is used to notify the proxy that this is a SOCKS 4a
++ // request. This request type works for Tor and perhaps others.
++ WriteUint32(PR_htonl(0x00000001)); // Fake IP
++ WriteUint8(0x00); // Send an emtpy username
++ if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
++ LOGERROR(("socks4: destination host name is too long!"));
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
++ }
++ WriteString(mDestinationHost); // Hostname
++ WriteUint8(0x00);
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
++ WriteNetAddr(addr); // Add the IPv4 address
++ WriteUint8(0x00); // Send an emtpy username
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
++ LOGERROR(("socks: SOCKS 4 can't handle IPv6 addresses!"));
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
++ }
+
+- // get destination port
+- PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
+- nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
++ return PR_SUCCESS;
++}
+
+- if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
++PRStatus
++nsSOCKSSocketInfo::ReadV4ConnectResponse()
++{
++ NS_ABORT_IF_FALSE(mState == SOCKS4_READ_CONNECT_RESPONSE,
++ "Handling SOCKS 4 connection reply in wrong state!");
++ NS_ABORT_IF_FALSE(mDataLength == 8,
++ "SOCKS 4 connection reply must be 8 bytes!");
+
+- LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
++ LOGDEBUG(("socks4: checking connection reply"));
+
+- // if the PROXY_RESOLVES_HOST flag is set, we assume
+- // that the transport wants us to pass the SOCKS server the
+- // hostname and port and let it do the name resolution.
++ if (ReadUint8() != 0x00) {
++ LOGERROR(("socks4: wrong connection reply"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ }
+
+- // the real destination hostname and port was stored
+- // in our info object earlier when this layer was created.
++ // See if our connection request was granted
++ if (ReadUint8() == 90) {
++ LOGDEBUG(("socks4: connection successful!"));
++ HandshakeFinished();
++ return PR_SUCCESS;
++ }
+
+- const nsCString& destHost = info->DestinationHost();
++ LOGERROR(("socks4: unable to connect"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++}
+
+- LOGDEBUG(("host:port -> %s:%li", destHost.get(), destPort));
++PRStatus
++nsSOCKSSocketInfo::WriteV5AuthRequest()
++{
++ NS_ABORT_IF_FALSE(mVersion == 5, "SOCKS version must be 5!");
+
+- request[3] = 0x03; // encoding of destination address (3 == hostname)
++ mState = SOCKS5_WRITE_AUTH_REQUEST;
+
+- int host_len = destHost.Length();
+- if (host_len > 255) {
+- // SOCKS5 transmits the length of the hostname in a single char.
+- // This gives us an absolute limit of 255 chars in a hostname, and
+- // there's nothing we can do to extend it. I don't think many
+- // hostnames will ever be bigger than this, so hopefully it's an
+- // uneventful abort condition.
+- LOGERROR (("Hostname too big for SOCKS5."));
+- return NS_ERROR_INVALID_ARG;
+- }
+- request[4] = (char) host_len;
+- request_len = 5;
+-
+- // Send the initial header first...
+- write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- // bad write
+- return NS_ERROR_FAILURE;
+- }
++ // Send an initial SOCKS 5 greeting
++ LOGDEBUG(("socks5: sending auth methods"));
++ WriteUint8(0x05); // version -- 5
++ WriteUint8(0x01); // # auth methods -- 1
++ WriteUint8(0x00); // we don't support authentication
+
+- // Now send the hostname...
+- write_len = pr_Send(fd, destHost.get(), host_len, 0, &timeout);
+- if (write_len != host_len) {
+- // bad write
+- return NS_ERROR_FAILURE;
+- }
++ return PR_SUCCESS;
++}
+
+- // There's no data left because we just sent it.
+- request_len = 0;
++PRStatus
++nsSOCKSSocketInfo::ReadV5AuthResponse()
++{
++ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_AUTH_RESPONSE,
++ "Handling SOCKS 5 auth method reply in wrong state!");
++ NS_ABORT_IF_FALSE(mDataLength == 2,
++ "SOCKS 5 auth method reply must be 2 bytes!");
+
+- } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
++ LOGDEBUG(("socks5: checking auth method reply"));
+
+- request[3] = 0x01; // encoding of destination address (1 == IPv4)
+- request_len = 8; // 4 for address, 4 SOCKS headers
++ // Check version number
++ if (ReadUint8() != 0x05) {
++ LOGERROR(("socks5: unexpected version in the reply"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ }
+
+- char * ip = (char*)(&addr->inet.ip);
+- request[4] = *ip++;
+- request[5] = *ip++;
+- request[6] = *ip++;
+- request[7] = *ip++;
++ // Make sure our authentication choice was accepted
++ if (ReadUint8() != 0x00) {
++ LOGERROR(("socks5: server did not accept our authentication method"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ }
+
+- } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
++ return WriteV5ConnectRequest();
++}
+
+- request[3] = 0x04; // encoding of destination address (4 == IPv6)
+- request_len = 20; // 16 for address, 4 SOCKS headers
+-
+- char * ip = (char*)(&addr->ipv6.ip.pr_s6_addr);
+- request[4] = *ip++; request[5] = *ip++;
+- request[6] = *ip++; request[7] = *ip++;
+- request[8] = *ip++; request[9] = *ip++;
+- request[10] = *ip++; request[11] = *ip++;
+- request[12] = *ip++; request[13] = *ip++;
+- request[14] = *ip++; request[15] = *ip++;
+- request[16] = *ip++; request[17] = *ip++;
+- request[18] = *ip++; request[19] = *ip++;
+-
+- // we're going to test to see if this address can
+- // be mapped back into IPv4 without loss. if so,
+- // we'll use IPv4 instead, as reliable SOCKS server
+- // support for IPv6 is probably questionable.
+-
+- if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
+- request[3] = 0x01; // ipv4 encoding
+- request[4] = request[16];
+- request[5] = request[17];
+- request[6] = request[18];
+- request[7] = request[19];
+- request_len -= 12;
++PRStatus
++nsSOCKSSocketInfo::WriteV5ConnectRequest()
++{
++ // Send SOCKS 5 connect request
++ PRNetAddr *addr = &mDestinationAddr;
++ PRInt32 proxy_resolve;
++ proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
++
++ LOGDEBUG(("socks5: sending connection request (socks5 resolve? %s)",
++ proxy_resolve? "yes" : "no"));
++
++ mDataLength = 0;
++ mState = SOCKS5_WRITE_CONNECT_REQUEST;
++
++ WriteUint8(0x05); // version -- 5
++ WriteUint8(0x01); // command -- connect
++ WriteUint8(0x00); // reserved
++
++ // Add the address to the SOCKS 5 request. SOCKS 5 supports several
++ // address types, so we pick the one that works best for us.
++ if (proxy_resolve) {
++ // Add the host name. Only a single byte is used to store the length,
++ // so we must prevent long names from being used.
++ if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
++ LOGERROR(("socks5: destination host name is too long!"));
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
+ }
++ WriteUint8(0x03); // addr type -- domainname
++ WriteUint8(mDestinationHost.Length()); // name length
++ WriteString(mDestinationHost);
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
++ WriteUint8(0x01); // addr type -- IPv4
++ WriteNetAddr(addr);
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
++ WriteUint8(0x04); // addr type -- IPv6
++ WriteNetAddr(addr);
+ } else {
+- // Unknown address type
+- LOGERROR(("Don't know what kind of IP address this is."));
+- return NS_ERROR_FAILURE;
+- }
+-
+- // add the destination port to the request
+- request[request_len] = (unsigned char)(destPort >> 8);
+- request[request_len+1] = (unsigned char)destPort;
+- request_len += 2;
+-
+- write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- // bad write
+- return NS_ERROR_FAILURE;
++ LOGERROR(("socks5: destination address of unknown type!"));
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
+ }
+
+- desired_len = 5;
+- response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
+- if (response_len < desired_len) { // bad read
+- LOGERROR(("pr_RecvAll() failed getting connect command reply. response_len = %d.", response_len));
+- return NS_ERROR_FAILURE;
+- }
++ WriteNetPort(addr); // port
+
+- if (response[0] != 0x05) {
+- // bad response
+- LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));
+- return NS_ERROR_FAILURE;
+- }
++ return PR_SUCCESS;
++}
+
+- switch(response[1]) {
+- case 0x00: break; // success
+- case 0x01: LOGERROR(("SOCKS 5 server rejected connect request: 01, General SOCKS server failure."));
+- return NS_ERROR_FAILURE;
+- case 0x02: LOGERROR(("SOCKS 5 server rejected connect request: 02, Connection not allowed by ruleset."));
+- return NS_ERROR_FAILURE;
+- case 0x03: LOGERROR(("SOCKS 5 server rejected connect request: 03, Network unreachable."));
+- return NS_ERROR_FAILURE;
+- case 0x04: LOGERROR(("SOCKS 5 server rejected connect request: 04, Host unreachable."));
+- return NS_ERROR_FAILURE;
+- case 0x05: LOGERROR(("SOCKS 5 server rejected connect request: 05, Connection refused."));
+- return NS_ERROR_FAILURE;
+- case 0x06: LOGERROR(("SOCKS 5 server rejected connect request: 06, TTL expired."));
+- return NS_ERROR_FAILURE;
+- case 0x07: LOGERROR(("SOCKS 5 server rejected connect request: 07, Command not supported."));
+- return NS_ERROR_FAILURE;
+- case 0x08: LOGERROR(("SOCKS 5 server rejected connect request: 08, Address type not supported."));
+- return NS_ERROR_FAILURE;
+- default: LOGERROR(("SOCKS 5 server rejected connect request: %x.", response[1]));
+- return NS_ERROR_FAILURE;
+-
+-
+- }
+-
+- switch (response[3]) {
+- case 0x01: // IPv4
+- desired_len = 4 + 2 - 1;
+- break;
+- case 0x03: // FQDN
+- desired_len = response[4] + 2;
++PRStatus
++nsSOCKSSocketInfo::ReadV5AddrTypeAndLength(PRUint8 *type, PRUint32 *len)
++{
++ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP ||
++ mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
++ "Invalid state!");
++ NS_ABORT_IF_FALSE(mDataLength >= 5,
++ "SOCKS 5 connection reply must be at least 5 bytes!");
++
++ // Seek to the address location
++ mReadOffset = 3;
++
++ *type = ReadUint8();
++
++ switch (*type) {
++ case 0x01: // ipv4
++ *len = 4 - 1;
+ break;
+- case 0x04: // IPv6
+- desired_len = 16 + 2 - 1;
++ case 0x04: // ipv6
++ *len = 16 - 1;
+ break;
+- default: // unknown format
+- return NS_ERROR_FAILURE;
++ case 0x03: // fqdn
++ *len = ReadUint8();
+ break;
++ default: // wrong address type
++ LOGERROR(("socks5: wrong address type in connection reply!"));
++ return PR_FAILURE;
+ }
+- response_len = pr_RecvAll(fd, response + 5, desired_len, 0, &timeout);
+- if (response_len < desired_len) { // bad read
+- LOGERROR(("pr_RecvAll() failed getting connect command reply. response_len = %d.", response_len));
+- return NS_ERROR_FAILURE;
+- }
+- response_len += 5;
+
+- // get external bound address (this is what
+- // the outside world sees as "us")
+- char *ip = nsnull;
+- PRUint16 extPort = 0;
++ return PR_SUCCESS;
++}
+
+- switch (response[3]) {
+- case 0x01: // IPv4
++PRStatus
++nsSOCKSSocketInfo::ReadV5ConnectResponseTop()
++{
++ PRUint8 res;
++ PRUint32 len;
+
+- extPort = (response[8] << 8) | response[9];
++ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP,
++ "Invalid state!");
++ NS_ABORT_IF_FALSE(mDataLength == 5,
++ "SOCKS 5 connection reply must be exactly 5 bytes!");
+
+- PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, extPort, extAddr);
++ LOGDEBUG(("socks5: checking connection reply"));
+
+- ip = (char*)(&extAddr->inet.ip);
+- *ip++ = response[4];
+- *ip++ = response[5];
+- *ip++ = response[6];
+- *ip++ = response[7];
++ // Check version number
++ if (ReadUint8() != 0x05) {
++ LOGERROR(("socks5: unexpected version in the reply"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ }
+
+- break;
+- case 0x04: // IPv6
++ // Check response
++ res = ReadUint8();
++ if (res != 0x00) {
++ PRErrorCode c = PR_CONNECT_REFUSED_ERROR;
++
++ switch (res) {
++ case 0x01:
++ LOGERROR(("socks5: connect failed: "
++ "01, General SOCKS server failure."));
++ break;
++ case 0x02:
++ LOGERROR(("socks5: connect failed: "
++ "02, Connection not allowed by ruleset."));
++ break;
++ case 0x03:
++ LOGERROR(("socks5: connect failed: 03, Network unreachable."));
++ c = PR_NETWORK_UNREACHABLE_ERROR;
++ break;
++ case 0x04:
++ LOGERROR(("socks5: connect failed: 04, Host unreachable."));
++ break;
++ case 0x05:
++ LOGERROR(("socks5: connect failed: 05, Connection refused."));
++ break;
++ case 0x06:
++ LOGERROR(("socks5: connect failed: 06, TTL expired."));
++ c = PR_CONNECT_TIMEOUT_ERROR;
++ break;
++ case 0x07:
++ LOGERROR(("socks5: connect failed: "
++ "07, Command not supported."));
++ break;
++ case 0x08:
++ LOGERROR(("socks5: connect failed: "
++ "08, Address type not supported."));
++ c = PR_BAD_ADDRESS_ERROR;
++ break;
++ default:
++ LOGERROR(("socks5: connect failed."));
++ break;
++ }
+
+- extPort = (response[20] << 8) | response[21];
++ HandshakeFinished(c);
++ return PR_FAILURE;
++ }
+
+- PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, extPort, extAddr);
++ if (ReadV5AddrTypeAndLength(&res, &len) != PR_SUCCESS) {
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
++ }
+
+- ip = (char*)(&extAddr->ipv6.ip.pr_s6_addr);
+- *ip++ = response[4]; *ip++ = response[5];
+- *ip++ = response[6]; *ip++ = response[7];
+- *ip++ = response[8]; *ip++ = response[9];
+- *ip++ = response[10]; *ip++ = response[11];
+- *ip++ = response[12]; *ip++ = response[13];
+- *ip++ = response[14]; *ip++ = response[15];
+- *ip++ = response[16]; *ip++ = response[17];
+- *ip++ = response[18]; *ip++ = response[19];
++ mState = SOCKS5_READ_CONNECT_RESPONSE_BOTTOM;
++ WantRead(len + 2);
+
+- break;
+- case 0x03: // FQDN
+- // if we get here, we don't know our external address.
+- // however, as that's possibly not critical to the user,
+- // we let it slide.
+- extPort = (response[response_len - 2] << 8) |
+- response[response_len - 1];
+- PR_InitializeNetAddr(PR_IpAddrNull, extPort, extAddr);
+- break;
+- }
+- return NS_OK;
++ return PR_SUCCESS;
+ }
+
+-// Negotiate a SOCKS 4 connection. Assumes the TCP connection to the socks
+-// server port has been established.
+-static nsresult
+-ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
++PRStatus
++nsSOCKSSocketInfo::ReadV5ConnectResponseBottom()
+ {
+- int request_len = 0;
+- int write_len;
+- int response_len = 0;
+- int desired_len = 0;
+- char *ip = nsnull;
+- unsigned char request[12];
+- unsigned char response[10];
++ PRUint8 type;
++ PRUint32 len;
+
+- NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
+- NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
++ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
++ "Invalid state!");
+
+- request[0] = 0x04; // SOCKS version 4
+- request[1] = 0x01; // CD command code -- 1 for connect
+-
+- // destination port
+- PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
+-
+- // store the port
+- request[2] = (unsigned char)(destPort >> 8);
+- request[3] = (unsigned char)destPort;
+-
+- // username
+- request[8] = 'M';
+- request[9] = 'O';
+- request[10] = 'Z';
+-
+- request[11] = 0x00;
+-
+- request_len = 12;
+-
+- nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
++ if (ReadV5AddrTypeAndLength(&type, &len) != PR_SUCCESS) {
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
++ }
+
+- if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
++ NS_ABORT_IF_FALSE(mDataLength == 7+len,
++ "SOCKS 5 unexpected length of connection reply!");
+
+- LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
++ LOGDEBUG(("socks5: loading source addr and port"));
++ // Read what the proxy says is our source address
++ switch (type) {
++ case 0x01: // ipv4
++ ReadNetAddr(&mExternalProxyAddr, PR_AF_INET);
++ break;
++ case 0x04: // ipv6
++ ReadNetAddr(&mExternalProxyAddr, PR_AF_INET6);
++ break;
++ case 0x03: // fqdn (skip)
++ mReadOffset += len;
++ mExternalProxyAddr.raw.family = PR_AF_INET;
++ break;
++ }
+
+- // if the PROXY_RESOLVES_HOST flag is set, we assume that the
+- // transport wants us to pass the SOCKS server the hostname
+- // and port and let it do the name resolution.
++ ReadNetPort(&mExternalProxyAddr);
+
+- // an extension to SOCKS 4, called 4a, specifies a way
+- // to do this, so we'll try that and hope the
+- // server supports it.
++ LOGDEBUG(("socks5: connected!"));
++ HandshakeFinished();
+
+- // the real destination hostname and port was stored
+- // in our info object earlier when this layer was created.
++ return PR_SUCCESS;
++}
+
+- const nsCString& destHost = info->DestinationHost();
++void
++nsSOCKSSocketInfo::SetConnectTimeout(PRIntervalTime to)
++{
++ mTimeout = to;
++}
+
+- LOGDEBUG(("host:port -> %s:%li\n", destHost.get(), destPort));
++PRStatus
++nsSOCKSSocketInfo::DoHandshake(PRFileDesc *fd, PRInt16 oflags)
++{
++ LOGDEBUG(("socks: DoHandshake(), state = %d", mState));
++
++ switch (mState) {
++ case SOCKS_INITIAL:
++ return ConnectToProxy(fd);
++ case SOCKS_CONNECTING_TO_PROXY:
++ return ContinueConnectingToProxy(fd, oflags);
++ case SOCKS4_WRITE_CONNECT_REQUEST:
++ if (WriteToSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ WantRead(8);
++ mState = SOCKS4_READ_CONNECT_RESPONSE;
++ return PR_SUCCESS;
++ case SOCKS4_READ_CONNECT_RESPONSE:
++ if (ReadFromSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ return ReadV4ConnectResponse();
++
++ case SOCKS5_WRITE_AUTH_REQUEST:
++ if (WriteToSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ WantRead(2);
++ mState = SOCKS5_READ_AUTH_RESPONSE;
++ return PR_SUCCESS;
++ case SOCKS5_READ_AUTH_RESPONSE:
++ if (ReadFromSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ return ReadV5AuthResponse();
++ case SOCKS5_WRITE_CONNECT_REQUEST:
++ if (WriteToSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++
++ // The SOCKS 5 response to the connection request is variable
++ // length. First, we'll read enough to tell how long the response
++ // is, and will read the rest later.
++ WantRead(5);
++ mState = SOCKS5_READ_CONNECT_RESPONSE_TOP;
++ return PR_SUCCESS;
++ case SOCKS5_READ_CONNECT_RESPONSE_TOP:
++ if (ReadFromSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ return ReadV5ConnectResponseTop();
++ case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
++ if (ReadFromSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ return ReadV5ConnectResponseBottom();
++
++ case SOCKS_CONNECTED:
++ LOGERROR(("socks: already connected"));
++ HandshakeFinished(PR_IS_CONNECTED_ERROR);
++ return PR_FAILURE;
++ case SOCKS_FAILED:
++ LOGERROR(("socks: already failed"));
++ return PR_FAILURE;
++ }
+
+- // the IP portion of the query is set to this special address.
+- request[4] = 0;
+- request[5] = 0;
+- request[6] = 0;
+- request[7] = 1;
++ LOGERROR(("socks: executing handshake in invalid state, %d", mState));
++ HandshakeFinished(PR_INVALID_STATE_ERROR);
+
+- write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- return NS_ERROR_FAILURE;
+- }
++ return PR_FAILURE;
++}
+
+- // Remember the NULL.
+- int host_len = destHost.Length() + 1;
++PRInt16
++nsSOCKSSocketInfo::GetPollFlags() const
++{
++ switch (mState) {
++ case SOCKS_CONNECTING_TO_PROXY:
++ return PR_POLL_EXCEPT | PR_POLL_WRITE;
++ case SOCKS4_WRITE_CONNECT_REQUEST:
++ case SOCKS5_WRITE_AUTH_REQUEST:
++ case SOCKS5_WRITE_CONNECT_REQUEST:
++ return PR_POLL_WRITE;
++ case SOCKS4_READ_CONNECT_RESPONSE:
++ case SOCKS5_READ_AUTH_RESPONSE:
++ case SOCKS5_READ_CONNECT_RESPONSE_TOP:
++ case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
++ return PR_POLL_READ;
++ default:
++ break;
++ }
+
+- write_len = pr_Send(fd, destHost.get(), host_len, 0, &timeout);
+- if (write_len != host_len) {
+- return NS_ERROR_FAILURE;
+- }
++ return 0;
++}
+
+- // No data to send, just sent it.
+- request_len = 0;
+-
+- } else if (PR_NetAddrFamily(addr) == PR_AF_INET) { // IPv4
+-
+- // store the ip
+- ip = (char*)(&addr->inet.ip);
+- request[4] = *ip++;
+- request[5] = *ip++;
+- request[6] = *ip++;
+- request[7] = *ip++;
+-
+- } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) { // IPv6
+-
+- // IPv4 address encoded in an IPv6 address
+- if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
+- // store the ip
+- ip = (char*)(&addr->ipv6.ip.pr_s6_addr[12]);
+- request[4] = *ip++;
+- request[5] = *ip++;
+- request[6] = *ip++;
+- request[7] = *ip++;
+- } else {
+- LOGERROR(("IPv6 is not supported in SOCKS 4."));
+- return NS_ERROR_FAILURE; // SOCKS 4 can't do IPv6
+- }
++inline void
++nsSOCKSSocketInfo::WriteUint8(PRUint8 v)
++{
++ NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
++ "Can't write that much data!");
++ mData[mDataLength] = v;
++ mDataLength += sizeof(v);
++}
+
+- } else {
+- LOGERROR(("Don't know what kind of IP address this is."));
+- return NS_ERROR_FAILURE; // don't recognize this type
+- }
++inline void
++nsSOCKSSocketInfo::WriteUint16(PRUint16 v)
++{
++ NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
++ "Can't write that much data!");
++ memcpy(mData + mDataLength, &v, sizeof(v));
++ mDataLength += sizeof(v);
++}
+
+- if (request_len > 0) {
+- write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- return NS_ERROR_FAILURE;
+- }
+- }
++inline void
++nsSOCKSSocketInfo::WriteUint32(PRUint32 v)
++{
++ NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
++ "Can't write that much data!");
++ memcpy(mData + mDataLength, &v, sizeof(v));
++ mDataLength += sizeof(v);
++}
+
+- // get the server's response
+- desired_len = 8; // size of the response
+- response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
+- if (response_len < desired_len) {
+- LOGERROR(("pr_RecvAll() failed. response_len = %d.", response_len));
+- return NS_ERROR_FAILURE;
+- }
++void
++nsSOCKSSocketInfo::WriteNetAddr(const PRNetAddr *addr)
++{
++ const char *ip = NULL;
++ PRUint32 len = 0;
+
+- if ((response[0] != 0x00) && (response[0] != 0x04)) {
+- // Novell BorderManager sends a response of type 4, should be zero
+- // According to the spec. Cope with this brokenness.
+- // it's not a SOCKS 4 reply or version 0 of the reply code
+- LOGERROR(("Not a SOCKS 4 reply. Expected: 0; received: %x.", response[0]));
+- return NS_ERROR_FAILURE;
++ if (PR_NetAddrFamily(addr) == PR_AF_INET) {
++ ip = (const char*)&addr->inet.ip;
++ len = sizeof(addr->inet.ip);
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
++ ip = (const char*)addr->ipv6.ip.pr_s6_addr;
++ len = sizeof(addr->ipv6.ip.pr_s6_addr);
+ }
+
+- if (response[1] != 0x5A) { // = 90: request granted
+- // connect request not granted
+- LOGERROR(("Connection request refused. Expected: 90; received: %d.", response[1]));
+- return NS_ERROR_FAILURE;
+- }
++ NS_ABORT_IF_FALSE(ip != NULL, "Unknown address");
++ NS_ABORT_IF_FALSE(mDataLength + len <= BUFFER_SIZE,
++ "Can't write that much data!");
+
+- return NS_OK;
++ memcpy(mData + mDataLength, ip, len);
++ mDataLength += len;
++}
+
++void
++nsSOCKSSocketInfo::WriteNetPort(const PRNetAddr *addr)
++{
++ WriteUint16(PR_NetAddrInetPort(addr));
+ }
+
++void
++nsSOCKSSocketInfo::WriteString(const nsACString &str)
++{
++ NS_ABORT_IF_FALSE(mDataLength + str.Length() <= BUFFER_SIZE,
++ "Can't write that much data!");
++ memcpy(mData + mDataLength, str.Data(), str.Length());
++ mDataLength += str.Length();
++}
+
+-static PRStatus
+-nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime /*timeout*/)
++inline PRUint8
++nsSOCKSSocketInfo::ReadUint8()
+ {
++ PRUint8 rv;
++ NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
++ "Not enough space to pop a uint8!");
++ rv = mData[mReadOffset];
++ mReadOffset += sizeof(rv);
++ return rv;
++}
+
+- PRStatus status;
++inline PRUint16
++nsSOCKSSocketInfo::ReadUint16()
++{
++ PRUint16 rv;
++ NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
++ "Not enough space to pop a uint16!");
++ memcpy(&rv, mData + mReadOffset, sizeof(rv));
++ mReadOffset += sizeof(rv);
++ return rv;
++}
+
+- nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
+- if (info == NULL) return PR_FAILURE;
++inline PRUint32
++nsSOCKSSocketInfo::ReadUint32()
++{
++ PRUint32 rv;
++ NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
++ "Not enough space to pop a uint32!");
++ memcpy(&rv, mData + mReadOffset, sizeof(rv));
++ mReadOffset += sizeof(rv);
++ return rv;
++}
+
+- // First, we need to look up our proxy...
+- const nsCString &proxyHost = info->ProxyHost();
++void
++nsSOCKSSocketInfo::ReadNetAddr(PRNetAddr *addr, PRUint16 fam)
++{
++ PRUint32 amt;
++ const PRUint8 *ip = mData + mReadOffset;
++
++ addr->raw.family = fam;
++ if (fam == PR_AF_INET) {
++ amt = sizeof(addr->inet.ip);
++ NS_ABORT_IF_FALSE(mReadOffset + amt <= mDataLength,
++ "Not enough space to pop an ipv4 addr!");
++ memcpy(&addr->inet.ip, ip, amt);
++ } else if (fam == PR_AF_INET6) {
++ amt = sizeof(addr->ipv6.ip.pr_s6_addr);
++ NS_ABORT_IF_FALSE(mReadOffset + amt <= mDataLength,
++ "Not enough space to pop an ipv6 addr!");
++ memcpy(addr->ipv6.ip.pr_s6_addr, ip, amt);
++ }
+
+- if (proxyHost.IsEmpty())
+- return PR_FAILURE;
++ mReadOffset += amt;
++}
+
+- PRInt32 socksVersion = info->Version();
++void
++nsSOCKSSocketInfo::ReadNetPort(PRNetAddr *addr)
++{
++ addr->inet.port = ReadUint16();
++}
+
+- LOGDEBUG(("nsSOCKSIOLayerConnect SOCKS %u; proxyHost: %s.", socksVersion, proxyHost.get()));
++void
++nsSOCKSSocketInfo::WantRead(PRUint32 sz)
++{
++ NS_ABORT_IF_FALSE(mDataIoPtr == NULL,
++ "WantRead() called while I/O already in progress!");
++ NS_ABORT_IF_FALSE(mDataLength + sz <= BUFFER_SIZE,
++ "Can't read that much data!");
++ mAmountToRead = sz;
++}
+
+- // Sync resolve the proxy hostname.
+- PRNetAddr proxyAddr;
+- nsCOMPtr<nsIDNSRecord> rec;
+- nsresult rv;
+- {
+- nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
+- if (!dns)
+- return PR_FAILURE;
++PRStatus
++nsSOCKSSocketInfo::ReadFromSocket(PRFileDesc *fd)
++{
++ PRInt32 rc;
++ const PRUint8 *end;
+
+- rv = dns->Resolve(proxyHost, 0, getter_AddRefs(rec));
+- if (NS_FAILED(rv))
+- return PR_FAILURE;
++ if (!mAmountToRead) {
++ LOGDEBUG(("socks: ReadFromSocket(), nothing to do"));
++ return PR_SUCCESS;
+ }
+
+- info->SetInternalProxyAddr(&proxyAddr);
++ if (!mDataIoPtr) {
++ mDataIoPtr = mData + mDataLength;
++ mDataLength += mAmountToRead;
++ }
+
+- // For now, we'll do this as a blocking connect,
+- // but with nspr 4.1, the necessary functions to
+- // do a non-blocking connect will be available
++ end = mData + mDataLength;
++
++ while (mDataIoPtr < end) {
++ rc = PR_Read(fd, mDataIoPtr, end - mDataIoPtr);
++ if (rc <= 0) {
++ if (rc == 0) {
++ LOGERROR(("socks: proxy server closed connection"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ } else if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
++ LOGDEBUG(("socks: ReadFromSocket(), want read"));
++ }
++ break;
++ }
+
+- // Preserve the non-blocking state of the socket
+- PRBool nonblocking;
+- PRSocketOptionData sockopt;
+- sockopt.option = PR_SockOpt_Nonblocking;
+- status = PR_GetSocketOption(fd, &sockopt);
++ mDataIoPtr += rc;
++ }
+
+- if (PR_SUCCESS != status) {
+- LOGERROR(("PR_GetSocketOption() failed. status = %x.", status));
+- return status;
++ LOGDEBUG(("socks: ReadFromSocket(), have %u bytes total",
++ unsigned(mDataIoPtr - mData)));
++ if (mDataIoPtr == end) {
++ mDataIoPtr = nsnull;
++ mAmountToRead = 0;
++ mReadOffset = 0;
++ return PR_SUCCESS;
+ }
+
+- // Store blocking option
+- nonblocking = sockopt.value.non_blocking;
++ return PR_FAILURE;
++}
+
+- sockopt.option = PR_SockOpt_Nonblocking;
+- sockopt.value.non_blocking = PR_FALSE;
+- status = PR_SetSocketOption(fd, &sockopt);
++PRStatus
++nsSOCKSSocketInfo::WriteToSocket(PRFileDesc *fd)
++{
++ PRInt32 rc;
++ const PRUint8 *end;
+
+- if (PR_SUCCESS != status) {
+- LOGERROR(("PR_SetSocketOption() failed. status = %x.", status));
+- return status;
++ if (!mDataLength) {
++ LOGDEBUG(("socks: WriteToSocket(), nothing to do"));
++ return PR_SUCCESS;
+ }
+
+- // Now setup sockopts, so we can restore the value later.
+- sockopt.option = PR_SockOpt_Nonblocking;
+- sockopt.value.non_blocking = nonblocking;
++ if (!mDataIoPtr)
++ mDataIoPtr = mData;
+
+- // This connectWait should be long enough to connect to local proxy
+- // servers, but not much longer. Since this protocol negotiation
+- // uses blocking network calls, the app can appear to hang for a maximum
+- // of this time if the user presses the STOP button during the SOCKS
+- // connection negotiation. Note that this value only applies to the
+- // connecting to the SOCKS server: once the SOCKS connection has been
+- // established, the value is not used anywhere else.
+- PRIntervalTime connectWait = PR_SecondsToInterval(10);
++ end = mData + mDataLength;
+
+- // Connect to the proxy server.
+- PRInt32 addresses = 0;
+- do {
+- rv = rec->GetNextAddr(info->ProxyPort(), &proxyAddr);
+- if (NS_FAILED(rv)) {
+- status = PR_FAILURE;
++ while (mDataIoPtr < end) {
++ rc = PR_Write(fd, mDataIoPtr, end - mDataIoPtr);
++ if (rc < 0) {
++ if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
++ LOGDEBUG(("socks: WriteToSocket(), want write"));
++ }
+ break;
+ }
+- ++addresses;
+- status = fd->lower->methods->connect(fd->lower, &proxyAddr, connectWait);
+- } while (PR_SUCCESS != status);
++
++ mDataIoPtr += rc;
++ }
+
+- if (PR_SUCCESS != status) {
+- LOGERROR(("Failed to TCP connect to the proxy server (%s): timeout = %d, status = %x, tried %d addresses.", proxyHost.get(), connectWait, status, addresses));
+- PR_SetSocketOption(fd, &sockopt);
+- return status;
++ if (mDataIoPtr == end) {
++ mDataIoPtr = nsnull;
++ mDataLength = 0;
++ mReadOffset = 0;
++ return PR_SUCCESS;
+ }
++
++ return PR_FAILURE;
++}
+
++static PRStatus
++nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime to)
++{
++ PRStatus status;
++ PRNetAddr dst;
+
+- // We are now connected to the SOCKS proxy server.
+- // Now we will negotiate a connection to the desired server.
++ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
++ if (info == NULL) return PR_FAILURE;
+
+- // External IP address returned from ConnectSOCKS5(). Not supported in SOCKS4.
+- PRNetAddr extAddr;
+- PR_InitializeNetAddr(PR_IpAddrNull, 0, &extAddr);
++ if (PR_NetAddrFamily(addr) == PR_AF_INET6 &&
++ PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
++ const PRUint8 *srcp;
+
+- NS_ASSERTION((socksVersion == 4) || (socksVersion == 5), "SOCKS Version must be selected");
++ LOGDEBUG(("socks: converting ipv4-mapped ipv6 address to ipv4"));
+
+- // Try to connect via SOCKS 5.
+- if (socksVersion == 5) {
+- rv = ConnectSOCKS5(fd, addr, &extAddr, connectWait);
++ // copied from _PR_ConvertToIpv4NetAddr()
++ PR_InitializeNetAddr(PR_IpAddrAny, 0, &dst);
++ srcp = addr->ipv6.ip.pr_s6_addr;
++ memcpy(&dst.inet.ip, srcp + 12, 4);
++ dst.inet.family = PR_AF_INET;
++ dst.inet.port = addr->ipv6.port;
++ } else {
++ memcpy(&dst, addr, sizeof(dst));
++ }
+
+- if (NS_FAILED(rv)) {
+- PR_SetSocketOption(fd, &sockopt);
+- return PR_FAILURE;
+- }
++ info->SetDestinationAddr(&dst);
++ info->SetConnectTimeout(to);
+
+- }
++ do {
++ status = info->DoHandshake(fd, -1);
++ } while (status == PR_SUCCESS && !info->IsConnected());
+
+- // Try to connect via SOCKS 4.
+- else {
+- rv = ConnectSOCKS4(fd, addr, connectWait);
++ return status;
++}
+
+- if (NS_FAILED(rv)) {
+- PR_SetSocketOption(fd, &sockopt);
+- return PR_FAILURE;
+- }
++static PRStatus
++nsSOCKSIOLayerConnectContinue(PRFileDesc *fd, PRInt16 oflags)
++{
++ PRStatus status;
+
+- }
++ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
++ if (info == NULL) return PR_FAILURE;
+
++ do {
++ status = info->DoHandshake(fd, oflags);
++ } while (status == PR_SUCCESS && !info->IsConnected());
+
+- info->SetDestinationAddr((PRNetAddr*)addr);
+- info->SetExternalProxyAddr(&extAddr);
++ return status;
++}
+
+- // restore non-blocking option
+- PR_SetSocketOption(fd, &sockopt);
++static PRInt16
++nsSOCKSIOLayerPoll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
++{
++ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
++ if (info == NULL) return PR_FAILURE;
+
+- // we're set-up and connected.
+- // this socket can be used as normal now.
++ if (!info->IsConnected()) {
++ *out_flags = 0;
++ return info->GetPollFlags();
++ }
+
+- return PR_SUCCESS;
++ return fd->lower->methods->poll(fd->lower, in_flags, out_flags);
+ }
+
+ static PRStatus
+@@ -885,6 +1120,8 @@ nsSOCKSIOLayerAddToSocket(PRInt32 family,
+ nsSOCKSIOLayerMethods = *PR_GetDefaultIOMethods();
+
+ nsSOCKSIOLayerMethods.connect = nsSOCKSIOLayerConnect;
++ nsSOCKSIOLayerMethods.connectcontinue = nsSOCKSIOLayerConnectContinue;
++ nsSOCKSIOLayerMethods.poll = nsSOCKSIOLayerPoll;
+ nsSOCKSIOLayerMethods.bind = nsSOCKSIOLayerBind;
+ nsSOCKSIOLayerMethods.acceptread = nsSOCKSIOLayerAcceptRead;
+ nsSOCKSIOLayerMethods.getsockname = nsSOCKSIOLayerGetName;
+--
+1.7.3.4
+
diff --git a/src/archived-patches/0001-Firefox5-Block-Components.interfaces-lookupMethod-fr.patch b/src/archived-patches/0001-Firefox5-Block-Components.interfaces-lookupMethod-fr.patch
new file mode 100644
index 0000000..816e2d2
--- /dev/null
+++ b/src/archived-patches/0001-Firefox5-Block-Components.interfaces-lookupMethod-fr.patch
@@ -0,0 +1,50 @@
+From cb6df58b95028693007936e423d43223609e17cc Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Mon, 20 Jun 2011 17:07:41 -0700
+Subject: [PATCH 1/3] Firefox5: Block Components.interfaces,lookupMethod from content
+
+This patch removes the ability of content script to access
+Components.interfaces.* as well as call or access Components.lookupMethod.
+
+These two interfaces seem to be exposed to content script only to make our
+lives difficult. Components.lookupMethod can undo our JS hooks, and
+Components.interfaces is useful for fingerprinting the platform, OS, and
+Firebox version.
+
+They appear to have no other legitimate use. See also:
+https://bugzilla.mozilla.org/show_bug.cgi?id=429070
+https://trac.torproject.org/projects/tor/ticket/2873
+https://trac.torproject.org/projects/tor/ticket/2874
+---
+ js/src/xpconnect/src/xpccomponents.cpp | 8 ++++++--
+ 1 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp
+index 5e789e7..5c76981 100644
+--- a/js/src/xpconnect/src/xpccomponents.cpp
++++ b/js/src/xpconnect/src/xpccomponents.cpp
+@@ -4287,7 +4287,9 @@ nsXPCComponents::CanCreateWrapper(const nsIID * iid, char **_retval)
+ NS_IMETHODIMP
+ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
+ {
+- static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
++ // XXX: Pref observer? Also, is this what we want? Seems like a plan
++ //static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
++ static const char* allowed[] = { "isSuccessCode", nsnull };
+ *_retval = xpc_CheckAccessList(methodName, allowed);
+ return NS_OK;
+ }
+@@ -4296,7 +4298,9 @@ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, c
+ NS_IMETHODIMP
+ nsXPCComponents::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
+ {
+- static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
++ // XXX: Pref observer? Also, is this what we want? Seems like a plan
++ // static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
++ static const char* allowed[] = { "results", nsnull};
+ *_retval = xpc_CheckAccessList(propertyName, allowed);
+ return NS_OK;
+ }
+--
+1.7.3.4
+
diff --git a/src/archived-patches/0002-Firefox4-Block-Components.interfaces-lookupMethod-fr.patch b/src/archived-patches/0002-Firefox4-Block-Components.interfaces-lookupMethod-fr.patch
new file mode 100644
index 0000000..8e34500
--- /dev/null
+++ b/src/archived-patches/0002-Firefox4-Block-Components.interfaces-lookupMethod-fr.patch
@@ -0,0 +1,50 @@
+From ebaf58a014f98942886ae829da83fadd662df948 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Mon, 20 Jun 2011 17:07:41 -0700
+Subject: [PATCH 2/4] Firefox4: Block Components.interfaces,lookupMethod from content
+
+This patch removes the ability of content script to access
+Components.interfaces.* as well as call or access Components.lookupMethod.
+
+These two interfaces seem to be exposed to content script only to make our
+lives difficult. Components.lookupMethod can undo our JS hooks, and
+Components.interfaces is useful for fingerprinting the platform, OS, and
+Firebox version.
+
+They appear to have no other legitimate use. See also:
+https://bugzilla.mozilla.org/show_bug.cgi?id=429070
+https://trac.torproject.org/projects/tor/ticket/2873
+https://trac.torproject.org/projects/tor/ticket/2874
+---
+ js/src/xpconnect/src/xpccomponents.cpp | 8 ++++++--
+ 1 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp
+index 1c141f9..85a2b4e 100644
+--- a/js/src/xpconnect/src/xpccomponents.cpp
++++ b/js/src/xpconnect/src/xpccomponents.cpp
+@@ -4294,7 +4294,9 @@ nsXPCComponents::CanCreateWrapper(const nsIID * iid, char **_retval)
+ NS_IMETHODIMP
+ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
+ {
+- static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
++ // XXX: Pref observer? Also, is this what we want? Seems like a plan
++ //static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
++ static const char* allowed[] = { "isSuccessCode", nsnull };
+ *_retval = xpc_CheckAccessList(methodName, allowed);
+ return NS_OK;
+ }
+@@ -4303,7 +4305,9 @@ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, c
+ NS_IMETHODIMP
+ nsXPCComponents::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
+ {
+- static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
++ // XXX: Pref observer? Also, is this what we want? Seems like a plan
++ // static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
++ static const char* allowed[] = { "results", nsnull};
+ *_retval = xpc_CheckAccessList(propertyName, allowed);
+ return NS_OK;
+ }
+--
+1.7.3.4
+
diff --git a/src/archived-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch b/src/archived-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch
new file mode 100644
index 0000000..2bd11e8
--- /dev/null
+++ b/src/archived-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch
@@ -0,0 +1,300 @@
+From 16b89c54032d1ad0acf2d6fa005b292a6f434791 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Mon, 20 Jun 2011 17:07:49 -0700
+Subject: [PATCH 2/3] Firefox5: Make Intermediate Cert Store memory-only.
+
+This patch makes the intermediate SSL cert store exist in memory only. It
+exposes a pref ('security.nocertdb') to toggle to clear the store, but this
+seems buggy.
+
+The pref must be set before startup in prefs.js.
+https://trac.torproject.org/projects/tor/ticket/2949
+---
+ security/manager/ssl/src/nsNSSComponent.cpp | 180 ++++++++++++++++++---------
+ 1 files changed, 120 insertions(+), 60 deletions(-)
+
+diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp
+index d3ae772..fa37ace 100644
+--- a/security/manager/ssl/src/nsNSSComponent.cpp
++++ b/security/manager/ssl/src/nsNSSComponent.cpp
+@@ -1658,8 +1658,21 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
+ // Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
+ // "/usr/lib/nss/libnssckbi.so".
+ PRUint32 init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
+- SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
++ PRBool nocertdb = false;
++ mPrefBranch->GetBoolPref("security.nocertdb", &nocertdb);
++
++ // XXX: We can also do the the following to only disable the certdb.
++ // Leaving this codepath in as a fallback in case InitNODB fails
++ if (nocertdb)
++ init_flags |= NSS_INIT_NOCERTDB;
++
++ SECStatus init_rv;
++ if (nocertdb) {
++ init_rv = ::NSS_NoDB_Init(NULL);
++ } else {
++ init_rv = ::NSS_Initialize(profileStr.get(), "", "",
+ SECMOD_DB, init_flags);
++ }
+
+ if (init_rv != SECSuccess) {
+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init NSS r/w in %s\n", profileStr.get()));
+@@ -2215,70 +2228,106 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
+ }
+ }
+ }
+- else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
+- nsNSSShutDownPreventionLock locker;
+- PRBool clearSessionCache = PR_FALSE;
+- PRBool enabled;
++ else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
+ NS_ConvertUTF16toUTF8 prefName(someData);
++ // XXX: This should be an observer notification, so we can properly cancel it
++ if (prefName.Equals("security.nocertdb")) {
++ // XXX: If these functions tell us to cancel, the browser seems to get left in an
++ // indeterminate state that prevents SSL from being used.
++ //
++ // We apparently need to wait for all SSL sockets to shut down on their
++ // own (this can take up to a minute!) and then attempt to alter the pref
++ // again before doing anything.
++ //
++ // So any implementation of New Identity based on this code will need to keep
++ // attempting to send the notification until it is not canceled. Ugh...
++ if (!DoProfileApproveChange(aSubject)) {
++ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled\n"));
++ return NS_OK;
++ }
+
+- if (prefName.Equals("security.enable_ssl2")) {
+- mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
+- SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
+- clearSessionCache = PR_TRUE;
+- } else if (prefName.Equals("security.enable_ssl3")) {
+- mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
+- clearSessionCache = PR_TRUE;
+- } else if (prefName.Equals("security.enable_tls")) {
+- mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
+- clearSessionCache = PR_TRUE;
+- } else if (prefName.Equals("security.enable_tls_session_tickets")) {
+- mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
+- } else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
+- mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
+- SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
+- } else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
+- mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
+- enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
+- } else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
+- char *unrestricted_hosts=nsnull;
+- mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
+- if (unrestricted_hosts) {
+- nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
+- nsMemory::Free(unrestricted_hosts);
++ DoProfileChangeNetTeardown();
++ if (!DoProfileChangeTeardown(aSubject)) {
++ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled\n"));
++ return NS_OK;
++ }
++
++ if (!DoProfileBeforeChange(aSubject)) {
++ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled by NSS shutdown\n"));
++ // Need to re-add observer because ShutdownNSS removed it.
++ nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(mPrefBranch);
++ pbi->AddObserver("security.", this, PR_FALSE);
++ return NS_OK;
+ }
+- } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
+- mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
+- nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
+- } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
+- PRInt32 warnLevel = 1;
+- mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
+- nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
++
++ DoProfileChangeNetRestore();
++ InitializeNSS(PR_FALSE);
++ InitializeCRLUpdateTimer();
++ return NS_OK;
++ } else {
++ nsNSSShutDownPreventionLock locker;
++ PRBool clearSessionCache = PR_FALSE;
++ PRBool enabled;
++
++ if (prefName.Equals("security.enable_ssl2")) {
++ mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
++ SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
++ clearSessionCache = PR_TRUE;
++ } else if (prefName.Equals("security.enable_ssl3")) {
++ mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
++ clearSessionCache = PR_TRUE;
++ } else if (prefName.Equals("security.enable_tls")) {
++ mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
++ clearSessionCache = PR_TRUE;
++ } else if (prefName.Equals("security.enable_tls_session_tickets")) {
++ mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
++ } else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
++ mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
++ SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
++ } else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
++ mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
++ enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
++ } else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
++ char *unrestricted_hosts=nsnull;
++ mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
++ if (unrestricted_hosts) {
++ nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
++ nsMemory::Free(unrestricted_hosts);
++ }
++ } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
++ mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
++ nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
++ } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
++ PRInt32 warnLevel = 1;
++ mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
++ nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
+ #ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8
+- } else if (prefName.Equals("security.ssl.enable_false_start")) {
+- mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
++ } else if (prefName.Equals("security.ssl.enable_false_start")) {
++ mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
+ #endif
+- } else if (prefName.Equals("security.OCSP.enabled")
+- || prefName.Equals("security.OCSP.require")) {
+- setOCSPOptions(mPrefBranch);
+- } else {
+- /* Look through the cipher table and set according to pref setting */
+- for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
+- if (prefName.Equals(cp->pref)) {
+- mPrefBranch->GetBoolPref(cp->pref, &enabled);
+- SSL_CipherPrefSetDefault(cp->id, enabled);
+- clearSessionCache = PR_TRUE;
+- break;
++ } else if (prefName.Equals("security.OCSP.enabled")
++ || prefName.Equals("security.OCSP.require")) {
++ setOCSPOptions(mPrefBranch);
++ } else {
++ /* Look through the cipher table and set according to pref setting */
++ for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
++ if (prefName.Equals(cp->pref)) {
++ mPrefBranch->GetBoolPref(cp->pref, &enabled);
++ SSL_CipherPrefSetDefault(cp->id, enabled);
++ clearSessionCache = PR_TRUE;
++ break;
++ }
+ }
+ }
++ if (clearSessionCache)
++ SSL_ClearSessionCache();
+ }
+- if (clearSessionCache)
+- SSL_ClearSessionCache();
+ }
+ else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_TEARDOWN_TOPIC) == 0) {
+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network teardown topic\n"));
+@@ -2447,16 +2496,19 @@ nsNSSComponent::RememberCert(CERTCertificate *cert)
+ return NS_OK;
+ }
+
+-void
++PRBool
+ nsNSSComponent::DoProfileApproveChange(nsISupports* aSubject)
+ {
+ if (mShutdownObjectList->isUIActive()) {
++ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS UI active in profile change!\n"));
+ ShowAlert(ai_crypto_ui_active);
+ nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
+ if (status) {
+ status->VetoChange();
+ }
++ return false;
+ }
++ return true;
+ }
+
+ void
+@@ -2469,16 +2521,18 @@ nsNSSComponent::DoProfileChangeNetTeardown()
+ mIsNetworkDown = PR_TRUE;
+ }
+
+-void
++PRBool
+ nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject)
+ {
+ PRBool callVeto = PR_FALSE;
+
+ if (!mShutdownObjectList->ifPossibleDisallowUI()) {
+ callVeto = PR_TRUE;
++ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: Not possible to disallow UI!\n"));
+ ShowAlert(ai_crypto_ui_active);
+ }
+ else if (mShutdownObjectList->areSSLSocketsActive()) {
++ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: SSL Sockets are active!\n"));
+ callVeto = PR_TRUE;
+ ShowAlert(ai_sockets_still_active);
+ }
+@@ -2489,9 +2543,11 @@ nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject)
+ status->VetoChange();
+ }
+ }
++
++ return !callVeto;
+ }
+
+-void
++PRBool
+ nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject)
+ {
+ NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
+@@ -2510,16 +2566,20 @@ nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject)
+ }
+
+ StopCRLUpdateTimer();
++ PRBool allow_change = PR_TRUE;
+
+ if (needsCleanup) {
+ if (NS_FAILED(ShutdownNSS())) {
++ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: Shutdown failed\n"));
+ nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
+ if (status) {
+ status->ChangeFailed();
+ }
++ allow_change = PR_FALSE;
+ }
+ }
+ mShutdownObjectList->allowUI();
++ return allow_change;
+ }
+
+ void
+--- a/security/manager/ssl/src/nsNSSComponent.h
++++ b/security/manager/ssl/src/nsNSSComponent.h
+@@ -321,10 +321,10 @@
+
+ // Methods that we use to handle the profile change notifications (and to
+ // synthesize a full profile change when we're just doing a profile startup):
+- void DoProfileApproveChange(nsISupports* aSubject);
++ PRBool DoProfileApproveChange(nsISupports* aSubject);
+ void DoProfileChangeNetTeardown();
+- void DoProfileChangeTeardown(nsISupports* aSubject);
+- void DoProfileBeforeChange(nsISupports* aSubject);
++ PRBool DoProfileChangeTeardown(nsISupports* aSubject);
++ PRBool DoProfileBeforeChange(nsISupports* aSubject);
+ void DoProfileChangeNetRestore();
+
+ Mutex mutex;
+
+--
+1.7.3.4
+
diff --git a/src/archived-patches/0003-Firefox4-Make-Intermediate-Cert-Store-memory-only.patch b/src/archived-patches/0003-Firefox4-Make-Intermediate-Cert-Store-memory-only.patch
new file mode 100644
index 0000000..d4f7b73
--- /dev/null
+++ b/src/archived-patches/0003-Firefox4-Make-Intermediate-Cert-Store-memory-only.patch
@@ -0,0 +1,283 @@
+From 4db14cbb5a0aff6102189d30b9202555dcc39ff4 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Mon, 20 Jun 2011 17:07:49 -0700
+Subject: [PATCH 3/4] Firefox4: Make Intermediate Cert Store memory-only.
+
+This patch makes the intermediate SSL cert store exist in memory only. It
+exposes a pref ('security.nocertdb') to toggle to clear the store, but this
+seems buggy.
+
+The pref must be set before startup in prefs.js.
+https://trac.torproject.org/projects/tor/ticket/2949
+---
+ security/manager/ssl/src/nsNSSComponent.cpp | 180 ++++++++++++++++++---------
+ 1 files changed, 120 insertions(+), 60 deletions(-)
+
+diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp
+index 33377ac..716bcee 100644
+--- a/security/manager/ssl/src/nsNSSComponent.cpp
++++ b/security/manager/ssl/src/nsNSSComponent.cpp
+@@ -1674,8 +1674,21 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
+ // Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
+ // "/usr/lib/nss/libnssckbi.so".
+ PRUint32 init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
+- SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
++ PRBool nocertdb = false;
++ mPrefBranch->GetBoolPref("security.nocertdb", &nocertdb);
++
++ // XXX: We can also do the the following to only disable the certdb.
++ // Leaving this codepath in as a fallback in case InitNODB fails
++ if (nocertdb)
++ init_flags |= NSS_INIT_NOCERTDB;
++
++ SECStatus init_rv;
++ if (nocertdb) {
++ init_rv = ::NSS_NoDB_Init(NULL);
++ } else {
++ init_rv = ::NSS_Initialize(profileStr.get(), "", "",
+ SECMOD_DB, init_flags);
++ }
+
+ if (init_rv != SECSuccess) {
+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init NSS r/w in %s\n", profileStr.get()));
+@@ -2231,70 +2244,106 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
+ }
+ }
+ }
+- else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
+- nsNSSShutDownPreventionLock locker;
+- PRBool clearSessionCache = PR_FALSE;
+- PRBool enabled;
++ else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
+ NS_ConvertUTF16toUTF8 prefName(someData);
++ // XXX: This should be an observer notification, so we can properly cancel it
++ if (prefName.Equals("security.nocertdb")) {
++ // XXX: If these functions tell us to cancel, the browser seems to get left in an
++ // indeterminate state that prevents SSL from being used.
++ //
++ // We apparently need to wait for all SSL sockets to shut down on their
++ // own (this can take up to a minute!) and then attempt to alter the pref
++ // again before doing anything.
++ //
++ // So any implementation of New Identity based on this code will need to keep
++ // attempting to send the notification until it is not canceled. Ugh...
++ if (!DoProfileApproveChange(aSubject)) {
++ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled\n"));
++ return NS_OK;
++ }
+
+- if (prefName.Equals("security.enable_ssl2")) {
+- mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
+- SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
+- clearSessionCache = PR_TRUE;
+- } else if (prefName.Equals("security.enable_ssl3")) {
+- mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
+- clearSessionCache = PR_TRUE;
+- } else if (prefName.Equals("security.enable_tls")) {
+- mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
+- clearSessionCache = PR_TRUE;
+- } else if (prefName.Equals("security.enable_tls_session_tickets")) {
+- mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
+- } else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
+- mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
+- SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
+- } else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
+- mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
+- enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
+- } else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
+- char *unrestricted_hosts=nsnull;
+- mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
+- if (unrestricted_hosts) {
+- nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
+- nsMemory::Free(unrestricted_hosts);
++ DoProfileChangeNetTeardown();
++ if (!DoProfileChangeTeardown(aSubject)) {
++ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled\n"));
++ return NS_OK;
++ }
++
++ if (!DoProfileBeforeChange(aSubject)) {
++ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled by NSS shutdown\n"));
++ // Need to re-add observer because ShutdownNSS removed it.
++ nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(mPrefBranch);
++ pbi->AddObserver("security.", this, PR_FALSE);
++ return NS_OK;
+ }
+- } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
+- mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
+- nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
+- } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
+- PRInt32 warnLevel = 1;
+- mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
+- nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
++
++ DoProfileChangeNetRestore();
++ InitializeNSS(PR_FALSE);
++ InitializeCRLUpdateTimer();
++ return NS_OK;
++ } else {
++ nsNSSShutDownPreventionLock locker;
++ PRBool clearSessionCache = PR_FALSE;
++ PRBool enabled;
++
++ if (prefName.Equals("security.enable_ssl2")) {
++ mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
++ SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
++ clearSessionCache = PR_TRUE;
++ } else if (prefName.Equals("security.enable_ssl3")) {
++ mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
++ clearSessionCache = PR_TRUE;
++ } else if (prefName.Equals("security.enable_tls")) {
++ mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
++ clearSessionCache = PR_TRUE;
++ } else if (prefName.Equals("security.enable_tls_session_tickets")) {
++ mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
++ } else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
++ mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
++ SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
++ } else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
++ mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
++ enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
++ } else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
++ char *unrestricted_hosts=nsnull;
++ mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
++ if (unrestricted_hosts) {
++ nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
++ nsMemory::Free(unrestricted_hosts);
++ }
++ } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
++ mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
++ nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
++ } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
++ PRInt32 warnLevel = 1;
++ mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
++ nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
+ #ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8
+- } else if (prefName.Equals("security.ssl.enable_false_start")) {
+- mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
+- SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
++ } else if (prefName.Equals("security.ssl.enable_false_start")) {
++ mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
++ SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
+ #endif
+- } else if (prefName.Equals("security.OCSP.enabled")
+- || prefName.Equals("security.OCSP.require")) {
+- setOCSPOptions(mPrefBranch);
+- } else {
+- /* Look through the cipher table and set according to pref setting */
+- for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
+- if (prefName.Equals(cp->pref)) {
+- mPrefBranch->GetBoolPref(cp->pref, &enabled);
+- SSL_CipherPrefSetDefault(cp->id, enabled);
+- clearSessionCache = PR_TRUE;
+- break;
++ } else if (prefName.Equals("security.OCSP.enabled")
++ || prefName.Equals("security.OCSP.require")) {
++ setOCSPOptions(mPrefBranch);
++ } else {
++ /* Look through the cipher table and set according to pref setting */
++ for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
++ if (prefName.Equals(cp->pref)) {
++ mPrefBranch->GetBoolPref(cp->pref, &enabled);
++ SSL_CipherPrefSetDefault(cp->id, enabled);
++ clearSessionCache = PR_TRUE;
++ break;
++ }
+ }
+ }
++ if (clearSessionCache)
++ SSL_ClearSessionCache();
+ }
+- if (clearSessionCache)
+- SSL_ClearSessionCache();
+ }
+ else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_TEARDOWN_TOPIC) == 0) {
+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network teardown topic\n"));
+@@ -2463,16 +2512,19 @@ nsNSSComponent::RememberCert(CERTCertificate *cert)
+ return NS_OK;
+ }
+
+-void
++PRBool
+ nsNSSComponent::DoProfileApproveChange(nsISupports* aSubject)
+ {
+ if (mShutdownObjectList->isUIActive()) {
++ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS UI active in profile change!\n"));
+ ShowAlert(ai_crypto_ui_active);
+ nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
+ if (status) {
+ status->VetoChange();
+ }
++ return false;
+ }
++ return true;
+ }
+
+ void
+@@ -2485,16 +2537,18 @@ nsNSSComponent::DoProfileChangeNetTeardown()
+ mIsNetworkDown = PR_TRUE;
+ }
+
+-void
++PRBool
+ nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject)
+ {
+ PRBool callVeto = PR_FALSE;
+
+ if (!mShutdownObjectList->ifPossibleDisallowUI()) {
+ callVeto = PR_TRUE;
++ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: Not possible to disallow UI!\n"));
+ ShowAlert(ai_crypto_ui_active);
+ }
+ else if (mShutdownObjectList->areSSLSocketsActive()) {
++ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: SSL Sockets are active!\n"));
+ callVeto = PR_TRUE;
+ ShowAlert(ai_sockets_still_active);
+ }
+@@ -2505,9 +2559,11 @@ nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject)
+ status->VetoChange();
+ }
+ }
++
++ return !callVeto;
+ }
+
+-void
++PRBool
+ nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject)
+ {
+ NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
+@@ -2526,16 +2582,20 @@ nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject)
+ }
+
+ StopCRLUpdateTimer();
++ PRBool allow_change = PR_TRUE;
+
+ if (needsCleanup) {
+ if (NS_FAILED(ShutdownNSS())) {
++ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: Shutdown failed\n"));
+ nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
+ if (status) {
+ status->ChangeFailed();
+ }
++ allow_change = PR_FALSE;
+ }
+ }
+ mShutdownObjectList->allowUI();
++ return allow_change;
+ }
+
+ void
+--
+1.7.3.4
+
diff --git a/src/archived-patches/0003-Firefox5-Make-Permissions-Manager-memory-only.patch b/src/archived-patches/0003-Firefox5-Make-Permissions-Manager-memory-only.patch
new file mode 100644
index 0000000..1384245
--- /dev/null
+++ b/src/archived-patches/0003-Firefox5-Make-Permissions-Manager-memory-only.patch
@@ -0,0 +1,94 @@
+From 16bafbf39c89cce901af6500255822677bc4c36d Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Mon, 20 Jun 2011 17:07:56 -0700
+Subject: [PATCH 3/3] Firefox5: Make Permissions Manager memory-only
+
+This patch exposes a pref 'permissions.memory_only' that properly isolates the
+permissions manager to memory, which is responsible for all user specified
+site permissions, as well as stored STS policy.
+
+The pref does successfully clear the permissions manager memory if toggled. It
+does not need to be set in prefs.js, and can be handled by Torbutton.
+
+https://trac.torproject.org/projects/tor/ticket/2950
+---
+ extensions/cookie/nsPermissionManager.cpp | 34 ++++++++++++++++++++++++++--
+ 1 files changed, 31 insertions(+), 3 deletions(-)
+
+diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp
+index 773a973..5387397 100644
+--- a/extensions/cookie/nsPermissionManager.cpp
++++ b/extensions/cookie/nsPermissionManager.cpp
+@@ -58,6 +58,10 @@
+ #include "mozStorageHelper.h"
+ #include "mozStorageCID.h"
+ #include "nsXULAppAPI.h"
++#include "nsCOMPtr.h"
++#include "nsIPrefService.h"
++#include "nsIPrefBranch.h"
++#include "nsIPrefBranch2.h"
+
+ static nsPermissionManager *gPermissionManager = nsnull;
+
+@@ -227,6 +231,11 @@ nsPermissionManager::Init()
+ mObserverService->AddObserver(this, "profile-do-change", PR_TRUE);
+ }
+
++ nsCOMPtr<nsIPrefBranch2> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
++ if (pbi) {
++ pbi->AddObserver("permissions.", this, PR_FALSE);
++ }
++
+ if (IsChildProcess()) {
+ // Get the permissions from the parent process
+ InfallibleTArray<IPC::Permission> perms;
+@@ -275,8 +284,18 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
+ if (!storage)
+ return NS_ERROR_UNEXPECTED;
+
++ PRBool memory_db = false;
++ nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
++ if (prefs) {
++ prefs->GetBoolPref("permissions.memory_only", &memory_db);
++ }
++
+ // cache a connection to the hosts database
+- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ if (memory_db) {
++ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
++ } else {
++ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ }
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRBool ready;
+@@ -286,7 +305,11 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
+ rv = permissionsFile->Remove(PR_FALSE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ if (memory_db) {
++ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
++ } else {
++ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ }
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mDBConn->GetConnectionReady(&ready);
+@@ -805,7 +828,12 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
+ {
+ ENSURE_NOT_CHILD_PROCESS;
+
+- if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
++ if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
++ if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("permissions.memory_only").get())) {
++ // XXX: Should we remove the file? Probably not..
++ InitDB(PR_FALSE);
++ }
++ } else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
+ // The profile is about to change,
+ // or is going away because the application is shutting down.
+ if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
+--
+1.7.3.4
+
diff --git a/src/archived-patches/0004-Firefox4-Make-Permissions-Manager-memory-only.patch b/src/archived-patches/0004-Firefox4-Make-Permissions-Manager-memory-only.patch
new file mode 100644
index 0000000..8f7ddd9
--- /dev/null
+++ b/src/archived-patches/0004-Firefox4-Make-Permissions-Manager-memory-only.patch
@@ -0,0 +1,94 @@
+From 6f37edd80181906c37ace589fc26eabf6731b09d Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Mon, 20 Jun 2011 17:07:56 -0700
+Subject: [PATCH 4/4] Firefox4: Make Permissions Manager memory-only
+
+This patch exposes a pref 'permissions.memory_only' that properly isolates the
+permissions manager to memory, which is responsible for all user specified
+site permissions, as well as stored STS policy.
+
+The pref does successfully clear the permissions manager memory if toggled. It
+does not need to be set in prefs.js, and can be handled by Torbutton.
+
+https://trac.torproject.org/projects/tor/ticket/2950
+---
+ extensions/cookie/nsPermissionManager.cpp | 34 ++++++++++++++++++++++++++--
+ 1 files changed, 31 insertions(+), 3 deletions(-)
+
+diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp
+index d182013..0a1aea6 100644
+--- a/extensions/cookie/nsPermissionManager.cpp
++++ b/extensions/cookie/nsPermissionManager.cpp
+@@ -60,6 +60,10 @@
+ #include "mozStorageHelper.h"
+ #include "mozStorageCID.h"
+ #include "nsXULAppAPI.h"
++#include "nsCOMPtr.h"
++#include "nsIPrefService.h"
++#include "nsIPrefBranch.h"
++#include "nsIPrefBranch2.h"
+
+ static nsPermissionManager *gPermissionManager = nsnull;
+
+@@ -233,6 +237,11 @@ nsPermissionManager::Init()
+ mObserverService->AddObserver(this, "profile-do-change", PR_TRUE);
+ }
+
++ nsCOMPtr<nsIPrefBranch2> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
++ if (pbi) {
++ pbi->AddObserver("permissions.", this, PR_FALSE);
++ }
++
+ #ifdef MOZ_IPC
+ if (IsChildProcess()) {
+ // Get the permissions from the parent process
+@@ -283,8 +292,18 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
+ if (!storage)
+ return NS_ERROR_UNEXPECTED;
+
++ PRBool memory_db = false;
++ nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
++ if (prefs) {
++ prefs->GetBoolPref("permissions.memory_only", &memory_db);
++ }
++
+ // cache a connection to the hosts database
+- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ if (memory_db) {
++ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
++ } else {
++ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ }
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRBool ready;
+@@ -294,7 +313,11 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
+ rv = permissionsFile->Remove(PR_FALSE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ if (memory_db) {
++ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
++ } else {
++ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ }
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mDBConn->GetConnectionReady(&ready);
+@@ -825,7 +848,12 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
+ ENSURE_NOT_CHILD_PROCESS;
+ #endif
+
+- if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
++ if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
++ if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("permissions.memory_only").get())) {
++ // XXX: Should we remove the file? Probably not..
++ InitDB(PR_FALSE);
++ }
++ } else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
+ // The profile is about to change,
+ // or is going away because the application is shutting down.
+ if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
+--
+1.7.3.4
+
diff --git a/src/current-patches/0001-Firefox4-Fix-SOCKS-timeout.patch b/src/current-patches/0001-Firefox4-Fix-SOCKS-timeout.patch
deleted file mode 100644
index 3b9343e..0000000
--- a/src/current-patches/0001-Firefox4-Fix-SOCKS-timeout.patch
+++ /dev/null
@@ -1,1500 +0,0 @@
-From d37dce07b9eb9b40244d2fa867728e7a57a33f0f Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git(a)fscked.org>
-Date: Mon, 20 Jun 2011 17:07:33 -0700
-Subject: [PATCH 1/4] Firefox4: Fix SOCKS timeout
-
-This patch by chrisd removes the hardcoded SOCKS timeout by rewriting the
-Firefox SOCKS code to use non-blocking IO.
-
-See also: https://bugzilla.mozilla.org/show_bug.cgi?id=280661
-https://trac.torproject.org/projects/tor/ticket/3247
----
- netwerk/base/src/nsSocketTransport2.cpp | 21 +-
- netwerk/socket/nsSOCKSIOLayer.cpp | 1273 ++++++++++++++++++-------------
- 2 files changed, 775 insertions(+), 519 deletions(-)
-
-diff --git a/netwerk/base/src/nsSocketTransport2.cpp b/netwerk/base/src/nsSocketTransport2.cpp
-index 3f95dfd..fb363db 100644
---- a/netwerk/base/src/nsSocketTransport2.cpp
-+++ b/netwerk/base/src/nsSocketTransport2.cpp
-@@ -1227,6 +1227,16 @@ nsSocketTransport::InitiateSocket()
- }
- }
- //
-+ // A SOCKS request was rejected; get the actual error code from
-+ // the OS error
-+ //
-+ else if (PR_UNKNOWN_ERROR == code &&
-+ mProxyTransparent &&
-+ !mProxyHost.IsEmpty()) {
-+ code = PR_GetOSError();
-+ rv = ErrorAccordingToNSPR(code);
-+ }
-+ //
- // The connection was refused...
- //
- else {
-@@ -1549,7 +1559,16 @@ nsSocketTransport::OnSocketReady(PRFileDesc *fd, PRInt16 outFlags)
- mPollFlags = (PR_POLL_EXCEPT | PR_POLL_WRITE);
- // Update poll timeout in case it was changed
- mPollTimeout = mTimeouts[TIMEOUT_CONNECT];
-- }
-+ }
-+ //
-+ // The SOCKS proxy rejected our request. Find out why.
-+ //
-+ else if (PR_UNKNOWN_ERROR == code &&
-+ mProxyTransparent &&
-+ !mProxyHost.IsEmpty()) {
-+ code = PR_GetOSError();
-+ mCondition = ErrorAccordingToNSPR(code);
-+ }
- else {
- //
- // else, the connection failed...
-diff --git a/netwerk/socket/nsSOCKSIOLayer.cpp b/netwerk/socket/nsSOCKSIOLayer.cpp
-index 9a15667..4d3a4e8 100644
---- a/netwerk/socket/nsSOCKSIOLayer.cpp
-+++ b/netwerk/socket/nsSOCKSIOLayer.cpp
-@@ -25,6 +25,7 @@
- * Bradley Baetz <bbaetz(a)acm.org>
- * Darin Fisher <darin(a)meer.net>
- * Malcolm Smith <malsmith(a)cs.rmit.edu.au>
-+ * Christopher Davis <chrisd(a)torproject.org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
-@@ -68,9 +69,28 @@ static PRLogModuleInfo *gSOCKSLog;
-
- class nsSOCKSSocketInfo : public nsISOCKSSocketInfo
- {
-+ enum State {
-+ SOCKS_INITIAL,
-+ SOCKS_CONNECTING_TO_PROXY,
-+ SOCKS4_WRITE_CONNECT_REQUEST,
-+ SOCKS4_READ_CONNECT_RESPONSE,
-+ SOCKS5_WRITE_AUTH_REQUEST,
-+ SOCKS5_READ_AUTH_RESPONSE,
-+ SOCKS5_WRITE_CONNECT_REQUEST,
-+ SOCKS5_READ_CONNECT_RESPONSE_TOP,
-+ SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
-+ SOCKS_CONNECTED,
-+ SOCKS_FAILED
-+ };
-+
-+ // A buffer of 262 bytes should be enough for any request and response
-+ // in case of SOCKS4 as well as SOCKS5
-+ static const PRUint32 BUFFER_SIZE = 262;
-+ static const PRUint32 MAX_HOSTNAME_LEN = 255;
-+
- public:
- nsSOCKSSocketInfo();
-- virtual ~nsSOCKSSocketInfo() {}
-+ virtual ~nsSOCKSSocketInfo() { HandshakeFinished(); }
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSISOCKSSOCKETINFO
-@@ -81,13 +101,50 @@ public:
- const char *destinationHost,
- PRUint32 flags);
-
-- const nsCString &DestinationHost() { return mDestinationHost; }
-- const nsCString &ProxyHost() { return mProxyHost; }
-- PRInt32 ProxyPort() { return mProxyPort; }
-- PRInt32 Version() { return mVersion; }
-- PRUint32 Flags() { return mFlags; }
-+ void SetConnectTimeout(PRIntervalTime to);
-+ PRStatus DoHandshake(PRFileDesc *fd, PRInt16 oflags = -1);
-+ PRInt16 GetPollFlags() const;
-+ bool IsConnected() const { return mState == SOCKS_CONNECTED; }
-+
-+private:
-+ void HandshakeFinished(PRErrorCode err = 0);
-+ PRStatus ConnectToProxy(PRFileDesc *fd);
-+ PRStatus ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags);
-+ PRStatus WriteV4ConnectRequest();
-+ PRStatus ReadV4ConnectResponse();
-+ PRStatus WriteV5AuthRequest();
-+ PRStatus ReadV5AuthResponse();
-+ PRStatus WriteV5ConnectRequest();
-+ PRStatus ReadV5AddrTypeAndLength(PRUint8 *type, PRUint32 *len);
-+ PRStatus ReadV5ConnectResponseTop();
-+ PRStatus ReadV5ConnectResponseBottom();
-+
-+ void WriteUint8(PRUint8 d);
-+ void WriteUint16(PRUint16 d);
-+ void WriteUint32(PRUint32 d);
-+ void WriteNetAddr(const PRNetAddr *addr);
-+ void WriteNetPort(const PRNetAddr *addr);
-+ void WriteString(const nsACString &str);
-+
-+ PRUint8 ReadUint8();
-+ PRUint16 ReadUint16();
-+ PRUint32 ReadUint32();
-+ void ReadNetAddr(PRNetAddr *addr, PRUint16 fam);
-+ void ReadNetPort(PRNetAddr *addr);
-+
-+ void WantRead(PRUint32 sz);
-+ PRStatus ReadFromSocket(PRFileDesc *fd);
-+ PRStatus WriteToSocket(PRFileDesc *fd);
-
- private:
-+ State mState;
-+ PRUint8 * mData;
-+ PRUint8 * mDataIoPtr;
-+ PRUint32 mDataLength;
-+ PRUint32 mReadOffset;
-+ PRUint32 mAmountToRead;
-+ nsCOMPtr<nsIDNSRecord> mDnsRec;
-+
- nsCString mDestinationHost;
- nsCString mProxyHost;
- PRInt32 mProxyPort;
-@@ -96,13 +153,21 @@ private:
- PRNetAddr mInternalProxyAddr;
- PRNetAddr mExternalProxyAddr;
- PRNetAddr mDestinationAddr;
-+ PRIntervalTime mTimeout;
- };
-
- nsSOCKSSocketInfo::nsSOCKSSocketInfo()
-- : mProxyPort(-1)
-+ : mState(SOCKS_INITIAL)
-+ , mDataIoPtr(nsnull)
-+ , mDataLength(0)
-+ , mReadOffset(0)
-+ , mAmountToRead(0)
-+ , mProxyPort(-1)
- , mVersion(-1)
- , mFlags(0)
-+ , mTimeout(PR_INTERVAL_NO_TIMEOUT)
- {
-+ mData = new PRUint8[BUFFER_SIZE];
- PR_InitializeNetAddr(PR_IpAddrAny, 0, &mInternalProxyAddr);
- PR_InitializeNetAddr(PR_IpAddrAny, 0, &mExternalProxyAddr);
- PR_InitializeNetAddr(PR_IpAddrAny, 0, &mDestinationAddr);
-@@ -162,637 +227,807 @@ nsSOCKSSocketInfo::SetInternalProxyAddr(PRNetAddr *aInternalProxyAddr)
- return NS_OK;
- }
-
--static PRInt32
--pr_RecvAll(PRFileDesc *fd, unsigned char *buf, PRInt32 amount, PRIntn flags,
-- PRIntervalTime *timeout)
-+// There needs to be a means of distinguishing between connection errors
-+// that the SOCKS server reports when it rejects a connection request, and
-+// connection errors that happen while attempting to connect to the SOCKS
-+// server. Otherwise, Firefox will report incorrectly that the proxy server
-+// is refusing connections when a SOCKS request is rejected by the proxy.
-+// When a SOCKS handshake failure occurs, the PR error is set to
-+// PR_UNKNOWN_ERROR, and the real error code is returned via the OS error.
-+void
-+nsSOCKSSocketInfo::HandshakeFinished(PRErrorCode err)
- {
-- PRInt32 bytesRead = 0;
-- PRInt32 offset = 0;
-+ if (err == 0) {
-+ mState = SOCKS_CONNECTED;
-+ } else {
-+ mState = SOCKS_FAILED;
-+ PR_SetError(PR_UNKNOWN_ERROR, err);
-+ }
-
-- while (offset < amount) {
-- PRIntervalTime start_time = PR_IntervalNow();
-- bytesRead = PR_Recv(fd, buf + offset, amount - offset, flags, *timeout);
-- PRIntervalTime elapsed = PR_IntervalNow() - start_time;
-+ // We don't need the buffer any longer, so free it.
-+ delete [] mData;
-+ mData = nsnull;
-+ mDataIoPtr = nsnull;
-+ mDataLength = 0;
-+ mReadOffset = 0;
-+ mAmountToRead = 0;
-+}
-
-- if (elapsed > *timeout) {
-- *timeout = 0;
-- } else {
-- *timeout -= elapsed;
-- }
-+PRStatus
-+nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc *fd)
-+{
-+ PRStatus status;
-+ nsresult rv;
-
-- if (bytesRead > 0) {
-- offset += bytesRead;
-- } else if (bytesRead == 0 || offset != 0) {
-- return offset;
-- } else {
-- return bytesRead;
-- }
-+ NS_ABORT_IF_FALSE(mState == SOCKS_INITIAL,
-+ "Must be in initial state to make connection!");
-
-- if (*timeout == 0) {
-- LOGERROR(("PR_Recv() timed out. amount = %d. offset = %d.",
-- amount, offset));
-- return offset;
-+ // If we haven't performed the DNS lookup, do that now.
-+ if (!mDnsRec) {
-+ nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
-+ if (!dns)
-+ return PR_FAILURE;
-+
-+ rv = dns->Resolve(mProxyHost, 0, getter_AddRefs(mDnsRec));
-+ if (NS_FAILED(rv)) {
-+ LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed",
-+ mProxyHost.get()));
-+ return PR_FAILURE;
- }
- }
-- return offset;
--}
-
--static PRInt32
--pr_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
-- PRIntervalTime *timeout)
--{
-- PRIntervalTime start_time = PR_IntervalNow();
-- PRInt32 retval = PR_Send(fd, buf, amount, flags, *timeout);
-- PRIntervalTime elapsed = PR_IntervalNow() - start_time;
--
-- if (elapsed > *timeout) {
-- *timeout = 0;
-- LOGERROR(("PR_Send() timed out. amount = %d. retval = %d.",
-- amount, retval));
-- return retval;
-- } else {
-- *timeout -= elapsed;
-- }
-+ do {
-+ rv = mDnsRec->GetNextAddr(mProxyPort, &mInternalProxyAddr);
-+ // No more addresses to try? If so, we'll need to bail
-+ if (NS_FAILED(rv)) {
-+ LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
-+ mProxyHost.get()));
-+ return PR_FAILURE;
-+ }
-
-- if (retval <= 0) {
-- LOGERROR(("PR_Send() failed. amount = %d. retval = %d.",
-- amount, retval));
-- }
-+#if defined(PR_LOGGING)
-+ char buf[64];
-+ PR_NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
-+ LOGDEBUG(("socks: trying proxy server, %s:%hu",
-+ buf, PR_ntohs(PR_NetAddrInetPort(&mInternalProxyAddr))));
-+#endif
-+ status = fd->lower->methods->connect(fd->lower,
-+ &mInternalProxyAddr, mTimeout);
-+ if (status != PR_SUCCESS) {
-+ PRErrorCode c = PR_GetError();
-+ // If EINPROGRESS, return now and check back later after polling
-+ if (c == PR_WOULD_BLOCK_ERROR || c == PR_IN_PROGRESS_ERROR) {
-+ mState = SOCKS_CONNECTING_TO_PROXY;
-+ return status;
-+ }
-+ }
-+ } while (status != PR_SUCCESS);
-
-- return retval;
-+ // Connected now, start SOCKS
-+ if (mVersion == 4)
-+ return WriteV4ConnectRequest();
-+ return WriteV5AuthRequest();
- }
-
--// Negotiate a SOCKS 5 connection. Assumes the TCP connection to the socks
--// server port has been established.
--static nsresult
--ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRIntervalTime timeout)
-+PRStatus
-+nsSOCKSSocketInfo::ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags)
- {
-- int request_len = 0;
-- int response_len = 0;
-- int desired_len = 0;
-- unsigned char request[22];
-- unsigned char response[262];
--
-- NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
-- NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
-- NS_ENSURE_TRUE(extAddr, NS_ERROR_NOT_INITIALIZED);
--
-- request[0] = 0x05; // SOCKS version 5
-- request[1] = 0x01; // number of auth procotols we recognize
-- // auth protocols
-- request[2] = 0x00; // no authentication required
-- // compliant implementations MUST implement GSSAPI
-- // and SHOULD implement username/password and MAY
-- // implement CHAP
-- // TODO: we don't implement these
-- //request[3] = 0x01; // GSSAPI
-- //request[4] = 0x02; // username/password
-- //request[5] = 0x03; // CHAP
-+ PRStatus status;
-
-- request_len = 2 + request[1];
-- int write_len = pr_Send(fd, request, request_len, 0, &timeout);
-- if (write_len != request_len) {
-- return NS_ERROR_FAILURE;
-- }
-+ NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
-+ "Continuing connection in wrong state!");
-
-- // get the server's response.
-- desired_len = 2;
-- response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
-+ LOGDEBUG(("socks: continuing connection to proxy"));
-
-- if (response_len < desired_len) {
-- LOGERROR(("pr_RecvAll() failed. response_len = %d.", response_len));
-- return NS_ERROR_FAILURE;
-- }
-+ status = fd->lower->methods->connectcontinue(fd->lower, oflags);
-+ if (status != PR_SUCCESS) {
-+ PRErrorCode c = PR_GetError();
-+ if (c != PR_WOULD_BLOCK_ERROR && c != PR_IN_PROGRESS_ERROR) {
-+ // A connection failure occured, try another address
-+ mState = SOCKS_INITIAL;
-+ return ConnectToProxy(fd);
-+ }
-
-- if (response[0] != 0x05) {
-- // it's a either not SOCKS or not our version
-- LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));
-- return NS_ERROR_FAILURE;
-- }
-- switch (response[1]) {
-- case 0x00:
-- // no auth
-- break;
-- case 0x01:
-- // GSSAPI
-- // TODO: implement
-- LOGERROR(("Server want to use GSSAPI to authenticate, but we don't support it."));
-- return NS_ERROR_FAILURE;
-- case 0x02:
-- // username/password
-- // TODO: implement
-- LOGERROR(("Server want to use username/password to authenticate, but we don't support it."));
-- return NS_ERROR_FAILURE;
-- case 0x03:
-- // CHAP
-- // TODO: implement?
-- LOGERROR(("Server want to use CHAP to authenticate, but we don't support it."));
-- return NS_ERROR_FAILURE;
-- default:
-- // unrecognized auth method
-- LOGERROR(("Uncrecognized authentication method received: %x", response[1]));
-- return NS_ERROR_FAILURE;
-+ // We're still connecting
-+ return PR_FAILURE;
- }
-
-- // we are now authenticated, so lets tell
-- // the server where to connect to
-+ // Connected now, start SOCKS
-+ if (mVersion == 4)
-+ return WriteV4ConnectRequest();
-+ return WriteV5AuthRequest();
-+}
-
-- request_len = 0;
-+PRStatus
-+nsSOCKSSocketInfo::WriteV4ConnectRequest()
-+{
-+ PRNetAddr *addr = &mDestinationAddr;
-+ PRInt32 proxy_resolve;
-
-- request[0] = 0x05; // SOCKS version 5
-- request[1] = 0x01; // CONNECT command
-- request[2] = 0x00; // obligatory reserved field (perfect for MS tampering!)
-+ NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
-+ "Invalid state!");
-+
-+ proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
-+
-+ mDataLength = 0;
-+ mState = SOCKS4_WRITE_CONNECT_REQUEST;
-+
-+ LOGDEBUG(("socks4: sending connection request (socks4a resolve? %s)",
-+ proxy_resolve? "yes" : "no"));
-+
-+ // Send a SOCKS 4 connect request.
-+ WriteUint8(0x04); // version -- 4
-+ WriteUint8(0x01); // command -- connect
-+ WriteNetPort(addr);
-+ if (proxy_resolve) {
-+ // Add the full name, null-terminated, to the request
-+ // according to SOCKS 4a. A fake IP address, with the first
-+ // four bytes set to 0 and the last byte set to something other
-+ // than 0, is used to notify the proxy that this is a SOCKS 4a
-+ // request. This request type works for Tor and perhaps others.
-+ WriteUint32(PR_htonl(0x00000001)); // Fake IP
-+ WriteUint8(0x00); // Send an emtpy username
-+ if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
-+ LOGERROR(("socks4: destination host name is too long!"));
-+ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
-+ return PR_FAILURE;
-+ }
-+ WriteString(mDestinationHost); // Hostname
-+ WriteUint8(0x00);
-+ } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
-+ WriteNetAddr(addr); // Add the IPv4 address
-+ WriteUint8(0x00); // Send an emtpy username
-+ } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
-+ LOGERROR(("socks: SOCKS 4 can't handle IPv6 addresses!"));
-+ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
-+ return PR_FAILURE;
-+ }
-
-- // get destination port
-- PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
-- nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
-+ return PR_SUCCESS;
-+}
-
-- if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
-+PRStatus
-+nsSOCKSSocketInfo::ReadV4ConnectResponse()
-+{
-+ NS_ABORT_IF_FALSE(mState == SOCKS4_READ_CONNECT_RESPONSE,
-+ "Handling SOCKS 4 connection reply in wrong state!");
-+ NS_ABORT_IF_FALSE(mDataLength == 8,
-+ "SOCKS 4 connection reply must be 8 bytes!");
-
-- LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
-+ LOGDEBUG(("socks4: checking connection reply"));
-
-- // if the PROXY_RESOLVES_HOST flag is set, we assume
-- // that the transport wants us to pass the SOCKS server the
-- // hostname and port and let it do the name resolution.
-+ if (ReadUint8() != 0x00) {
-+ LOGERROR(("socks4: wrong connection reply"));
-+ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
-+ return PR_FAILURE;
-+ }
-
-- // the real destination hostname and port was stored
-- // in our info object earlier when this layer was created.
-+ // See if our connection request was granted
-+ if (ReadUint8() == 90) {
-+ LOGDEBUG(("socks4: connection successful!"));
-+ HandshakeFinished();
-+ return PR_SUCCESS;
-+ }
-
-- const nsCString& destHost = info->DestinationHost();
-+ LOGERROR(("socks4: unable to connect"));
-+ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
-+ return PR_FAILURE;
-+}
-
-- LOGDEBUG(("host:port -> %s:%li", destHost.get(), destPort));
-+PRStatus
-+nsSOCKSSocketInfo::WriteV5AuthRequest()
-+{
-+ NS_ABORT_IF_FALSE(mVersion == 5, "SOCKS version must be 5!");
-
-- request[3] = 0x03; // encoding of destination address (3 == hostname)
-+ mState = SOCKS5_WRITE_AUTH_REQUEST;
-
-- int host_len = destHost.Length();
-- if (host_len > 255) {
-- // SOCKS5 transmits the length of the hostname in a single char.
-- // This gives us an absolute limit of 255 chars in a hostname, and
-- // there's nothing we can do to extend it. I don't think many
-- // hostnames will ever be bigger than this, so hopefully it's an
-- // uneventful abort condition.
-- LOGERROR (("Hostname too big for SOCKS5."));
-- return NS_ERROR_INVALID_ARG;
-- }
-- request[4] = (char) host_len;
-- request_len = 5;
--
-- // Send the initial header first...
-- write_len = pr_Send(fd, request, request_len, 0, &timeout);
-- if (write_len != request_len) {
-- // bad write
-- return NS_ERROR_FAILURE;
-- }
-+ // Send an initial SOCKS 5 greeting
-+ LOGDEBUG(("socks5: sending auth methods"));
-+ WriteUint8(0x05); // version -- 5
-+ WriteUint8(0x01); // # auth methods -- 1
-+ WriteUint8(0x00); // we don't support authentication
-
-- // Now send the hostname...
-- write_len = pr_Send(fd, destHost.get(), host_len, 0, &timeout);
-- if (write_len != host_len) {
-- // bad write
-- return NS_ERROR_FAILURE;
-- }
-+ return PR_SUCCESS;
-+}
-
-- // There's no data left because we just sent it.
-- request_len = 0;
-+PRStatus
-+nsSOCKSSocketInfo::ReadV5AuthResponse()
-+{
-+ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_AUTH_RESPONSE,
-+ "Handling SOCKS 5 auth method reply in wrong state!");
-+ NS_ABORT_IF_FALSE(mDataLength == 2,
-+ "SOCKS 5 auth method reply must be 2 bytes!");
-
-- } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
-+ LOGDEBUG(("socks5: checking auth method reply"));
-
-- request[3] = 0x01; // encoding of destination address (1 == IPv4)
-- request_len = 8; // 4 for address, 4 SOCKS headers
-+ // Check version number
-+ if (ReadUint8() != 0x05) {
-+ LOGERROR(("socks5: unexpected version in the reply"));
-+ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
-+ return PR_FAILURE;
-+ }
-
-- char * ip = (char*)(&addr->inet.ip);
-- request[4] = *ip++;
-- request[5] = *ip++;
-- request[6] = *ip++;
-- request[7] = *ip++;
-+ // Make sure our authentication choice was accepted
-+ if (ReadUint8() != 0x00) {
-+ LOGERROR(("socks5: server did not accept our authentication method"));
-+ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
-+ return PR_FAILURE;
-+ }
-
-- } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
-+ return WriteV5ConnectRequest();
-+}
-
-- request[3] = 0x04; // encoding of destination address (4 == IPv6)
-- request_len = 20; // 16 for address, 4 SOCKS headers
--
-- char * ip = (char*)(&addr->ipv6.ip.pr_s6_addr);
-- request[4] = *ip++; request[5] = *ip++;
-- request[6] = *ip++; request[7] = *ip++;
-- request[8] = *ip++; request[9] = *ip++;
-- request[10] = *ip++; request[11] = *ip++;
-- request[12] = *ip++; request[13] = *ip++;
-- request[14] = *ip++; request[15] = *ip++;
-- request[16] = *ip++; request[17] = *ip++;
-- request[18] = *ip++; request[19] = *ip++;
--
-- // we're going to test to see if this address can
-- // be mapped back into IPv4 without loss. if so,
-- // we'll use IPv4 instead, as reliable SOCKS server
-- // support for IPv6 is probably questionable.
--
-- if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
-- request[3] = 0x01; // ipv4 encoding
-- request[4] = request[16];
-- request[5] = request[17];
-- request[6] = request[18];
-- request[7] = request[19];
-- request_len -= 12;
-+PRStatus
-+nsSOCKSSocketInfo::WriteV5ConnectRequest()
-+{
-+ // Send SOCKS 5 connect request
-+ PRNetAddr *addr = &mDestinationAddr;
-+ PRInt32 proxy_resolve;
-+ proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
-+
-+ LOGDEBUG(("socks5: sending connection request (socks5 resolve? %s)",
-+ proxy_resolve? "yes" : "no"));
-+
-+ mDataLength = 0;
-+ mState = SOCKS5_WRITE_CONNECT_REQUEST;
-+
-+ WriteUint8(0x05); // version -- 5
-+ WriteUint8(0x01); // command -- connect
-+ WriteUint8(0x00); // reserved
-+
-+ // Add the address to the SOCKS 5 request. SOCKS 5 supports several
-+ // address types, so we pick the one that works best for us.
-+ if (proxy_resolve) {
-+ // Add the host name. Only a single byte is used to store the length,
-+ // so we must prevent long names from being used.
-+ if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
-+ LOGERROR(("socks5: destination host name is too long!"));
-+ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
-+ return PR_FAILURE;
- }
-+ WriteUint8(0x03); // addr type -- domainname
-+ WriteUint8(mDestinationHost.Length()); // name length
-+ WriteString(mDestinationHost);
-+ } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
-+ WriteUint8(0x01); // addr type -- IPv4
-+ WriteNetAddr(addr);
-+ } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
-+ WriteUint8(0x04); // addr type -- IPv6
-+ WriteNetAddr(addr);
- } else {
-- // Unknown address type
-- LOGERROR(("Don't know what kind of IP address this is."));
-- return NS_ERROR_FAILURE;
-- }
--
-- // add the destination port to the request
-- request[request_len] = (unsigned char)(destPort >> 8);
-- request[request_len+1] = (unsigned char)destPort;
-- request_len += 2;
--
-- write_len = pr_Send(fd, request, request_len, 0, &timeout);
-- if (write_len != request_len) {
-- // bad write
-- return NS_ERROR_FAILURE;
-+ LOGERROR(("socks5: destination address of unknown type!"));
-+ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
-+ return PR_FAILURE;
- }
-
-- desired_len = 5;
-- response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
-- if (response_len < desired_len) { // bad read
-- LOGERROR(("pr_RecvAll() failed getting connect command reply. response_len = %d.", response_len));
-- return NS_ERROR_FAILURE;
-- }
-+ WriteNetPort(addr); // port
-
-- if (response[0] != 0x05) {
-- // bad response
-- LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));
-- return NS_ERROR_FAILURE;
-- }
-+ return PR_SUCCESS;
-+}
-
-- switch(response[1]) {
-- case 0x00: break; // success
-- case 0x01: LOGERROR(("SOCKS 5 server rejected connect request: 01, General SOCKS server failure."));
-- return NS_ERROR_FAILURE;
-- case 0x02: LOGERROR(("SOCKS 5 server rejected connect request: 02, Connection not allowed by ruleset."));
-- return NS_ERROR_FAILURE;
-- case 0x03: LOGERROR(("SOCKS 5 server rejected connect request: 03, Network unreachable."));
-- return NS_ERROR_FAILURE;
-- case 0x04: LOGERROR(("SOCKS 5 server rejected connect request: 04, Host unreachable."));
-- return NS_ERROR_FAILURE;
-- case 0x05: LOGERROR(("SOCKS 5 server rejected connect request: 05, Connection refused."));
-- return NS_ERROR_FAILURE;
-- case 0x06: LOGERROR(("SOCKS 5 server rejected connect request: 06, TTL expired."));
-- return NS_ERROR_FAILURE;
-- case 0x07: LOGERROR(("SOCKS 5 server rejected connect request: 07, Command not supported."));
-- return NS_ERROR_FAILURE;
-- case 0x08: LOGERROR(("SOCKS 5 server rejected connect request: 08, Address type not supported."));
-- return NS_ERROR_FAILURE;
-- default: LOGERROR(("SOCKS 5 server rejected connect request: %x.", response[1]));
-- return NS_ERROR_FAILURE;
--
--
-- }
--
-- switch (response[3]) {
-- case 0x01: // IPv4
-- desired_len = 4 + 2 - 1;
-- break;
-- case 0x03: // FQDN
-- desired_len = response[4] + 2;
-+PRStatus
-+nsSOCKSSocketInfo::ReadV5AddrTypeAndLength(PRUint8 *type, PRUint32 *len)
-+{
-+ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP ||
-+ mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
-+ "Invalid state!");
-+ NS_ABORT_IF_FALSE(mDataLength >= 5,
-+ "SOCKS 5 connection reply must be at least 5 bytes!");
-+
-+ // Seek to the address location
-+ mReadOffset = 3;
-+
-+ *type = ReadUint8();
-+
-+ switch (*type) {
-+ case 0x01: // ipv4
-+ *len = 4 - 1;
- break;
-- case 0x04: // IPv6
-- desired_len = 16 + 2 - 1;
-+ case 0x04: // ipv6
-+ *len = 16 - 1;
- break;
-- default: // unknown format
-- return NS_ERROR_FAILURE;
-+ case 0x03: // fqdn
-+ *len = ReadUint8();
- break;
-+ default: // wrong address type
-+ LOGERROR(("socks5: wrong address type in connection reply!"));
-+ return PR_FAILURE;
- }
-- response_len = pr_RecvAll(fd, response + 5, desired_len, 0, &timeout);
-- if (response_len < desired_len) { // bad read
-- LOGERROR(("pr_RecvAll() failed getting connect command reply. response_len = %d.", response_len));
-- return NS_ERROR_FAILURE;
-- }
-- response_len += 5;
-
-- // get external bound address (this is what
-- // the outside world sees as "us")
-- char *ip = nsnull;
-- PRUint16 extPort = 0;
-+ return PR_SUCCESS;
-+}
-
-- switch (response[3]) {
-- case 0x01: // IPv4
-+PRStatus
-+nsSOCKSSocketInfo::ReadV5ConnectResponseTop()
-+{
-+ PRUint8 res;
-+ PRUint32 len;
-
-- extPort = (response[8] << 8) | response[9];
-+ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP,
-+ "Invalid state!");
-+ NS_ABORT_IF_FALSE(mDataLength == 5,
-+ "SOCKS 5 connection reply must be exactly 5 bytes!");
-
-- PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, extPort, extAddr);
-+ LOGDEBUG(("socks5: checking connection reply"));
-
-- ip = (char*)(&extAddr->inet.ip);
-- *ip++ = response[4];
-- *ip++ = response[5];
-- *ip++ = response[6];
-- *ip++ = response[7];
-+ // Check version number
-+ if (ReadUint8() != 0x05) {
-+ LOGERROR(("socks5: unexpected version in the reply"));
-+ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
-+ return PR_FAILURE;
-+ }
-
-- break;
-- case 0x04: // IPv6
-+ // Check response
-+ res = ReadUint8();
-+ if (res != 0x00) {
-+ PRErrorCode c = PR_CONNECT_REFUSED_ERROR;
-+
-+ switch (res) {
-+ case 0x01:
-+ LOGERROR(("socks5: connect failed: "
-+ "01, General SOCKS server failure."));
-+ break;
-+ case 0x02:
-+ LOGERROR(("socks5: connect failed: "
-+ "02, Connection not allowed by ruleset."));
-+ break;
-+ case 0x03:
-+ LOGERROR(("socks5: connect failed: 03, Network unreachable."));
-+ c = PR_NETWORK_UNREACHABLE_ERROR;
-+ break;
-+ case 0x04:
-+ LOGERROR(("socks5: connect failed: 04, Host unreachable."));
-+ break;
-+ case 0x05:
-+ LOGERROR(("socks5: connect failed: 05, Connection refused."));
-+ break;
-+ case 0x06:
-+ LOGERROR(("socks5: connect failed: 06, TTL expired."));
-+ c = PR_CONNECT_TIMEOUT_ERROR;
-+ break;
-+ case 0x07:
-+ LOGERROR(("socks5: connect failed: "
-+ "07, Command not supported."));
-+ break;
-+ case 0x08:
-+ LOGERROR(("socks5: connect failed: "
-+ "08, Address type not supported."));
-+ c = PR_BAD_ADDRESS_ERROR;
-+ break;
-+ default:
-+ LOGERROR(("socks5: connect failed."));
-+ break;
-+ }
-
-- extPort = (response[20] << 8) | response[21];
-+ HandshakeFinished(c);
-+ return PR_FAILURE;
-+ }
-
-- PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, extPort, extAddr);
-+ if (ReadV5AddrTypeAndLength(&res, &len) != PR_SUCCESS) {
-+ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
-+ return PR_FAILURE;
-+ }
-
-- ip = (char*)(&extAddr->ipv6.ip.pr_s6_addr);
-- *ip++ = response[4]; *ip++ = response[5];
-- *ip++ = response[6]; *ip++ = response[7];
-- *ip++ = response[8]; *ip++ = response[9];
-- *ip++ = response[10]; *ip++ = response[11];
-- *ip++ = response[12]; *ip++ = response[13];
-- *ip++ = response[14]; *ip++ = response[15];
-- *ip++ = response[16]; *ip++ = response[17];
-- *ip++ = response[18]; *ip++ = response[19];
-+ mState = SOCKS5_READ_CONNECT_RESPONSE_BOTTOM;
-+ WantRead(len + 2);
-
-- break;
-- case 0x03: // FQDN
-- // if we get here, we don't know our external address.
-- // however, as that's possibly not critical to the user,
-- // we let it slide.
-- extPort = (response[response_len - 2] << 8) |
-- response[response_len - 1];
-- PR_InitializeNetAddr(PR_IpAddrNull, extPort, extAddr);
-- break;
-- }
-- return NS_OK;
-+ return PR_SUCCESS;
- }
-
--// Negotiate a SOCKS 4 connection. Assumes the TCP connection to the socks
--// server port has been established.
--static nsresult
--ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
-+PRStatus
-+nsSOCKSSocketInfo::ReadV5ConnectResponseBottom()
- {
-- int request_len = 0;
-- int write_len;
-- int response_len = 0;
-- int desired_len = 0;
-- char *ip = nsnull;
-- unsigned char request[12];
-- unsigned char response[10];
-+ PRUint8 type;
-+ PRUint32 len;
-
-- NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
-- NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
-+ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
-+ "Invalid state!");
-
-- request[0] = 0x04; // SOCKS version 4
-- request[1] = 0x01; // CD command code -- 1 for connect
--
-- // destination port
-- PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
--
-- // store the port
-- request[2] = (unsigned char)(destPort >> 8);
-- request[3] = (unsigned char)destPort;
--
-- // username
-- request[8] = 'M';
-- request[9] = 'O';
-- request[10] = 'Z';
--
-- request[11] = 0x00;
--
-- request_len = 12;
--
-- nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
-+ if (ReadV5AddrTypeAndLength(&type, &len) != PR_SUCCESS) {
-+ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
-+ return PR_FAILURE;
-+ }
-
-- if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
-+ NS_ABORT_IF_FALSE(mDataLength == 7+len,
-+ "SOCKS 5 unexpected length of connection reply!");
-
-- LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
-+ LOGDEBUG(("socks5: loading source addr and port"));
-+ // Read what the proxy says is our source address
-+ switch (type) {
-+ case 0x01: // ipv4
-+ ReadNetAddr(&mExternalProxyAddr, PR_AF_INET);
-+ break;
-+ case 0x04: // ipv6
-+ ReadNetAddr(&mExternalProxyAddr, PR_AF_INET6);
-+ break;
-+ case 0x03: // fqdn (skip)
-+ mReadOffset += len;
-+ mExternalProxyAddr.raw.family = PR_AF_INET;
-+ break;
-+ }
-
-- // if the PROXY_RESOLVES_HOST flag is set, we assume that the
-- // transport wants us to pass the SOCKS server the hostname
-- // and port and let it do the name resolution.
-+ ReadNetPort(&mExternalProxyAddr);
-
-- // an extension to SOCKS 4, called 4a, specifies a way
-- // to do this, so we'll try that and hope the
-- // server supports it.
-+ LOGDEBUG(("socks5: connected!"));
-+ HandshakeFinished();
-
-- // the real destination hostname and port was stored
-- // in our info object earlier when this layer was created.
-+ return PR_SUCCESS;
-+}
-
-- const nsCString& destHost = info->DestinationHost();
-+void
-+nsSOCKSSocketInfo::SetConnectTimeout(PRIntervalTime to)
-+{
-+ mTimeout = to;
-+}
-
-- LOGDEBUG(("host:port -> %s:%li\n", destHost.get(), destPort));
-+PRStatus
-+nsSOCKSSocketInfo::DoHandshake(PRFileDesc *fd, PRInt16 oflags)
-+{
-+ LOGDEBUG(("socks: DoHandshake(), state = %d", mState));
-+
-+ switch (mState) {
-+ case SOCKS_INITIAL:
-+ return ConnectToProxy(fd);
-+ case SOCKS_CONNECTING_TO_PROXY:
-+ return ContinueConnectingToProxy(fd, oflags);
-+ case SOCKS4_WRITE_CONNECT_REQUEST:
-+ if (WriteToSocket(fd) != PR_SUCCESS)
-+ return PR_FAILURE;
-+ WantRead(8);
-+ mState = SOCKS4_READ_CONNECT_RESPONSE;
-+ return PR_SUCCESS;
-+ case SOCKS4_READ_CONNECT_RESPONSE:
-+ if (ReadFromSocket(fd) != PR_SUCCESS)
-+ return PR_FAILURE;
-+ return ReadV4ConnectResponse();
-+
-+ case SOCKS5_WRITE_AUTH_REQUEST:
-+ if (WriteToSocket(fd) != PR_SUCCESS)
-+ return PR_FAILURE;
-+ WantRead(2);
-+ mState = SOCKS5_READ_AUTH_RESPONSE;
-+ return PR_SUCCESS;
-+ case SOCKS5_READ_AUTH_RESPONSE:
-+ if (ReadFromSocket(fd) != PR_SUCCESS)
-+ return PR_FAILURE;
-+ return ReadV5AuthResponse();
-+ case SOCKS5_WRITE_CONNECT_REQUEST:
-+ if (WriteToSocket(fd) != PR_SUCCESS)
-+ return PR_FAILURE;
-+
-+ // The SOCKS 5 response to the connection request is variable
-+ // length. First, we'll read enough to tell how long the response
-+ // is, and will read the rest later.
-+ WantRead(5);
-+ mState = SOCKS5_READ_CONNECT_RESPONSE_TOP;
-+ return PR_SUCCESS;
-+ case SOCKS5_READ_CONNECT_RESPONSE_TOP:
-+ if (ReadFromSocket(fd) != PR_SUCCESS)
-+ return PR_FAILURE;
-+ return ReadV5ConnectResponseTop();
-+ case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
-+ if (ReadFromSocket(fd) != PR_SUCCESS)
-+ return PR_FAILURE;
-+ return ReadV5ConnectResponseBottom();
-+
-+ case SOCKS_CONNECTED:
-+ LOGERROR(("socks: already connected"));
-+ HandshakeFinished(PR_IS_CONNECTED_ERROR);
-+ return PR_FAILURE;
-+ case SOCKS_FAILED:
-+ LOGERROR(("socks: already failed"));
-+ return PR_FAILURE;
-+ }
-
-- // the IP portion of the query is set to this special address.
-- request[4] = 0;
-- request[5] = 0;
-- request[6] = 0;
-- request[7] = 1;
-+ LOGERROR(("socks: executing handshake in invalid state, %d", mState));
-+ HandshakeFinished(PR_INVALID_STATE_ERROR);
-
-- write_len = pr_Send(fd, request, request_len, 0, &timeout);
-- if (write_len != request_len) {
-- return NS_ERROR_FAILURE;
-- }
-+ return PR_FAILURE;
-+}
-
-- // Remember the NULL.
-- int host_len = destHost.Length() + 1;
-+PRInt16
-+nsSOCKSSocketInfo::GetPollFlags() const
-+{
-+ switch (mState) {
-+ case SOCKS_CONNECTING_TO_PROXY:
-+ return PR_POLL_EXCEPT | PR_POLL_WRITE;
-+ case SOCKS4_WRITE_CONNECT_REQUEST:
-+ case SOCKS5_WRITE_AUTH_REQUEST:
-+ case SOCKS5_WRITE_CONNECT_REQUEST:
-+ return PR_POLL_WRITE;
-+ case SOCKS4_READ_CONNECT_RESPONSE:
-+ case SOCKS5_READ_AUTH_RESPONSE:
-+ case SOCKS5_READ_CONNECT_RESPONSE_TOP:
-+ case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
-+ return PR_POLL_READ;
-+ default:
-+ break;
-+ }
-
-- write_len = pr_Send(fd, destHost.get(), host_len, 0, &timeout);
-- if (write_len != host_len) {
-- return NS_ERROR_FAILURE;
-- }
-+ return 0;
-+}
-
-- // No data to send, just sent it.
-- request_len = 0;
--
-- } else if (PR_NetAddrFamily(addr) == PR_AF_INET) { // IPv4
--
-- // store the ip
-- ip = (char*)(&addr->inet.ip);
-- request[4] = *ip++;
-- request[5] = *ip++;
-- request[6] = *ip++;
-- request[7] = *ip++;
--
-- } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) { // IPv6
--
-- // IPv4 address encoded in an IPv6 address
-- if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
-- // store the ip
-- ip = (char*)(&addr->ipv6.ip.pr_s6_addr[12]);
-- request[4] = *ip++;
-- request[5] = *ip++;
-- request[6] = *ip++;
-- request[7] = *ip++;
-- } else {
-- LOGERROR(("IPv6 is not supported in SOCKS 4."));
-- return NS_ERROR_FAILURE; // SOCKS 4 can't do IPv6
-- }
-+inline void
-+nsSOCKSSocketInfo::WriteUint8(PRUint8 v)
-+{
-+ NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
-+ "Can't write that much data!");
-+ mData[mDataLength] = v;
-+ mDataLength += sizeof(v);
-+}
-
-- } else {
-- LOGERROR(("Don't know what kind of IP address this is."));
-- return NS_ERROR_FAILURE; // don't recognize this type
-- }
-+inline void
-+nsSOCKSSocketInfo::WriteUint16(PRUint16 v)
-+{
-+ NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
-+ "Can't write that much data!");
-+ memcpy(mData + mDataLength, &v, sizeof(v));
-+ mDataLength += sizeof(v);
-+}
-
-- if (request_len > 0) {
-- write_len = pr_Send(fd, request, request_len, 0, &timeout);
-- if (write_len != request_len) {
-- return NS_ERROR_FAILURE;
-- }
-- }
-+inline void
-+nsSOCKSSocketInfo::WriteUint32(PRUint32 v)
-+{
-+ NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
-+ "Can't write that much data!");
-+ memcpy(mData + mDataLength, &v, sizeof(v));
-+ mDataLength += sizeof(v);
-+}
-
-- // get the server's response
-- desired_len = 8; // size of the response
-- response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
-- if (response_len < desired_len) {
-- LOGERROR(("pr_RecvAll() failed. response_len = %d.", response_len));
-- return NS_ERROR_FAILURE;
-- }
-+void
-+nsSOCKSSocketInfo::WriteNetAddr(const PRNetAddr *addr)
-+{
-+ const char *ip = NULL;
-+ PRUint32 len = 0;
-
-- if ((response[0] != 0x00) && (response[0] != 0x04)) {
-- // Novell BorderManager sends a response of type 4, should be zero
-- // According to the spec. Cope with this brokenness.
-- // it's not a SOCKS 4 reply or version 0 of the reply code
-- LOGERROR(("Not a SOCKS 4 reply. Expected: 0; received: %x.", response[0]));
-- return NS_ERROR_FAILURE;
-+ if (PR_NetAddrFamily(addr) == PR_AF_INET) {
-+ ip = (const char*)&addr->inet.ip;
-+ len = sizeof(addr->inet.ip);
-+ } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
-+ ip = (const char*)addr->ipv6.ip.pr_s6_addr;
-+ len = sizeof(addr->ipv6.ip.pr_s6_addr);
- }
-
-- if (response[1] != 0x5A) { // = 90: request granted
-- // connect request not granted
-- LOGERROR(("Connection request refused. Expected: 90; received: %d.", response[1]));
-- return NS_ERROR_FAILURE;
-- }
-+ NS_ABORT_IF_FALSE(ip != NULL, "Unknown address");
-+ NS_ABORT_IF_FALSE(mDataLength + len <= BUFFER_SIZE,
-+ "Can't write that much data!");
-
-- return NS_OK;
-+ memcpy(mData + mDataLength, ip, len);
-+ mDataLength += len;
-+}
-
-+void
-+nsSOCKSSocketInfo::WriteNetPort(const PRNetAddr *addr)
-+{
-+ WriteUint16(PR_NetAddrInetPort(addr));
- }
-
-+void
-+nsSOCKSSocketInfo::WriteString(const nsACString &str)
-+{
-+ NS_ABORT_IF_FALSE(mDataLength + str.Length() <= BUFFER_SIZE,
-+ "Can't write that much data!");
-+ memcpy(mData + mDataLength, str.Data(), str.Length());
-+ mDataLength += str.Length();
-+}
-
--static PRStatus
--nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime /*timeout*/)
-+inline PRUint8
-+nsSOCKSSocketInfo::ReadUint8()
- {
-+ PRUint8 rv;
-+ NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
-+ "Not enough space to pop a uint8!");
-+ rv = mData[mReadOffset];
-+ mReadOffset += sizeof(rv);
-+ return rv;
-+}
-
-- PRStatus status;
-+inline PRUint16
-+nsSOCKSSocketInfo::ReadUint16()
-+{
-+ PRUint16 rv;
-+ NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
-+ "Not enough space to pop a uint16!");
-+ memcpy(&rv, mData + mReadOffset, sizeof(rv));
-+ mReadOffset += sizeof(rv);
-+ return rv;
-+}
-
-- nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
-- if (info == NULL) return PR_FAILURE;
-+inline PRUint32
-+nsSOCKSSocketInfo::ReadUint32()
-+{
-+ PRUint32 rv;
-+ NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
-+ "Not enough space to pop a uint32!");
-+ memcpy(&rv, mData + mReadOffset, sizeof(rv));
-+ mReadOffset += sizeof(rv);
-+ return rv;
-+}
-
-- // First, we need to look up our proxy...
-- const nsCString &proxyHost = info->ProxyHost();
-+void
-+nsSOCKSSocketInfo::ReadNetAddr(PRNetAddr *addr, PRUint16 fam)
-+{
-+ PRUint32 amt;
-+ const PRUint8 *ip = mData + mReadOffset;
-+
-+ addr->raw.family = fam;
-+ if (fam == PR_AF_INET) {
-+ amt = sizeof(addr->inet.ip);
-+ NS_ABORT_IF_FALSE(mReadOffset + amt <= mDataLength,
-+ "Not enough space to pop an ipv4 addr!");
-+ memcpy(&addr->inet.ip, ip, amt);
-+ } else if (fam == PR_AF_INET6) {
-+ amt = sizeof(addr->ipv6.ip.pr_s6_addr);
-+ NS_ABORT_IF_FALSE(mReadOffset + amt <= mDataLength,
-+ "Not enough space to pop an ipv6 addr!");
-+ memcpy(addr->ipv6.ip.pr_s6_addr, ip, amt);
-+ }
-
-- if (proxyHost.IsEmpty())
-- return PR_FAILURE;
-+ mReadOffset += amt;
-+}
-
-- PRInt32 socksVersion = info->Version();
-+void
-+nsSOCKSSocketInfo::ReadNetPort(PRNetAddr *addr)
-+{
-+ addr->inet.port = ReadUint16();
-+}
-
-- LOGDEBUG(("nsSOCKSIOLayerConnect SOCKS %u; proxyHost: %s.", socksVersion, proxyHost.get()));
-+void
-+nsSOCKSSocketInfo::WantRead(PRUint32 sz)
-+{
-+ NS_ABORT_IF_FALSE(mDataIoPtr == NULL,
-+ "WantRead() called while I/O already in progress!");
-+ NS_ABORT_IF_FALSE(mDataLength + sz <= BUFFER_SIZE,
-+ "Can't read that much data!");
-+ mAmountToRead = sz;
-+}
-
-- // Sync resolve the proxy hostname.
-- PRNetAddr proxyAddr;
-- nsCOMPtr<nsIDNSRecord> rec;
-- nsresult rv;
-- {
-- nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
-- if (!dns)
-- return PR_FAILURE;
-+PRStatus
-+nsSOCKSSocketInfo::ReadFromSocket(PRFileDesc *fd)
-+{
-+ PRInt32 rc;
-+ const PRUint8 *end;
-
-- rv = dns->Resolve(proxyHost, 0, getter_AddRefs(rec));
-- if (NS_FAILED(rv))
-- return PR_FAILURE;
-+ if (!mAmountToRead) {
-+ LOGDEBUG(("socks: ReadFromSocket(), nothing to do"));
-+ return PR_SUCCESS;
- }
-
-- info->SetInternalProxyAddr(&proxyAddr);
-+ if (!mDataIoPtr) {
-+ mDataIoPtr = mData + mDataLength;
-+ mDataLength += mAmountToRead;
-+ }
-
-- // For now, we'll do this as a blocking connect,
-- // but with nspr 4.1, the necessary functions to
-- // do a non-blocking connect will be available
-+ end = mData + mDataLength;
-+
-+ while (mDataIoPtr < end) {
-+ rc = PR_Read(fd, mDataIoPtr, end - mDataIoPtr);
-+ if (rc <= 0) {
-+ if (rc == 0) {
-+ LOGERROR(("socks: proxy server closed connection"));
-+ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
-+ return PR_FAILURE;
-+ } else if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
-+ LOGDEBUG(("socks: ReadFromSocket(), want read"));
-+ }
-+ break;
-+ }
-
-- // Preserve the non-blocking state of the socket
-- PRBool nonblocking;
-- PRSocketOptionData sockopt;
-- sockopt.option = PR_SockOpt_Nonblocking;
-- status = PR_GetSocketOption(fd, &sockopt);
-+ mDataIoPtr += rc;
-+ }
-
-- if (PR_SUCCESS != status) {
-- LOGERROR(("PR_GetSocketOption() failed. status = %x.", status));
-- return status;
-+ LOGDEBUG(("socks: ReadFromSocket(), have %u bytes total",
-+ unsigned(mDataIoPtr - mData)));
-+ if (mDataIoPtr == end) {
-+ mDataIoPtr = nsnull;
-+ mAmountToRead = 0;
-+ mReadOffset = 0;
-+ return PR_SUCCESS;
- }
-
-- // Store blocking option
-- nonblocking = sockopt.value.non_blocking;
-+ return PR_FAILURE;
-+}
-
-- sockopt.option = PR_SockOpt_Nonblocking;
-- sockopt.value.non_blocking = PR_FALSE;
-- status = PR_SetSocketOption(fd, &sockopt);
-+PRStatus
-+nsSOCKSSocketInfo::WriteToSocket(PRFileDesc *fd)
-+{
-+ PRInt32 rc;
-+ const PRUint8 *end;
-
-- if (PR_SUCCESS != status) {
-- LOGERROR(("PR_SetSocketOption() failed. status = %x.", status));
-- return status;
-+ if (!mDataLength) {
-+ LOGDEBUG(("socks: WriteToSocket(), nothing to do"));
-+ return PR_SUCCESS;
- }
-
-- // Now setup sockopts, so we can restore the value later.
-- sockopt.option = PR_SockOpt_Nonblocking;
-- sockopt.value.non_blocking = nonblocking;
-+ if (!mDataIoPtr)
-+ mDataIoPtr = mData;
-
-- // This connectWait should be long enough to connect to local proxy
-- // servers, but not much longer. Since this protocol negotiation
-- // uses blocking network calls, the app can appear to hang for a maximum
-- // of this time if the user presses the STOP button during the SOCKS
-- // connection negotiation. Note that this value only applies to the
-- // connecting to the SOCKS server: once the SOCKS connection has been
-- // established, the value is not used anywhere else.
-- PRIntervalTime connectWait = PR_SecondsToInterval(10);
-+ end = mData + mDataLength;
-
-- // Connect to the proxy server.
-- PRInt32 addresses = 0;
-- do {
-- rv = rec->GetNextAddr(info->ProxyPort(), &proxyAddr);
-- if (NS_FAILED(rv)) {
-- status = PR_FAILURE;
-+ while (mDataIoPtr < end) {
-+ rc = PR_Write(fd, mDataIoPtr, end - mDataIoPtr);
-+ if (rc < 0) {
-+ if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
-+ LOGDEBUG(("socks: WriteToSocket(), want write"));
-+ }
- break;
- }
-- ++addresses;
-- status = fd->lower->methods->connect(fd->lower, &proxyAddr, connectWait);
-- } while (PR_SUCCESS != status);
-+
-+ mDataIoPtr += rc;
-+ }
-
-- if (PR_SUCCESS != status) {
-- LOGERROR(("Failed to TCP connect to the proxy server (%s): timeout = %d, status = %x, tried %d addresses.", proxyHost.get(), connectWait, status, addresses));
-- PR_SetSocketOption(fd, &sockopt);
-- return status;
-+ if (mDataIoPtr == end) {
-+ mDataIoPtr = nsnull;
-+ mDataLength = 0;
-+ mReadOffset = 0;
-+ return PR_SUCCESS;
- }
-+
-+ return PR_FAILURE;
-+}
-
-+static PRStatus
-+nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime to)
-+{
-+ PRStatus status;
-+ PRNetAddr dst;
-
-- // We are now connected to the SOCKS proxy server.
-- // Now we will negotiate a connection to the desired server.
-+ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
-+ if (info == NULL) return PR_FAILURE;
-
-- // External IP address returned from ConnectSOCKS5(). Not supported in SOCKS4.
-- PRNetAddr extAddr;
-- PR_InitializeNetAddr(PR_IpAddrNull, 0, &extAddr);
-+ if (PR_NetAddrFamily(addr) == PR_AF_INET6 &&
-+ PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
-+ const PRUint8 *srcp;
-
-- NS_ASSERTION((socksVersion == 4) || (socksVersion == 5), "SOCKS Version must be selected");
-+ LOGDEBUG(("socks: converting ipv4-mapped ipv6 address to ipv4"));
-
-- // Try to connect via SOCKS 5.
-- if (socksVersion == 5) {
-- rv = ConnectSOCKS5(fd, addr, &extAddr, connectWait);
-+ // copied from _PR_ConvertToIpv4NetAddr()
-+ PR_InitializeNetAddr(PR_IpAddrAny, 0, &dst);
-+ srcp = addr->ipv6.ip.pr_s6_addr;
-+ memcpy(&dst.inet.ip, srcp + 12, 4);
-+ dst.inet.family = PR_AF_INET;
-+ dst.inet.port = addr->ipv6.port;
-+ } else {
-+ memcpy(&dst, addr, sizeof(dst));
-+ }
-
-- if (NS_FAILED(rv)) {
-- PR_SetSocketOption(fd, &sockopt);
-- return PR_FAILURE;
-- }
-+ info->SetDestinationAddr(&dst);
-+ info->SetConnectTimeout(to);
-
-- }
-+ do {
-+ status = info->DoHandshake(fd, -1);
-+ } while (status == PR_SUCCESS && !info->IsConnected());
-
-- // Try to connect via SOCKS 4.
-- else {
-- rv = ConnectSOCKS4(fd, addr, connectWait);
-+ return status;
-+}
-
-- if (NS_FAILED(rv)) {
-- PR_SetSocketOption(fd, &sockopt);
-- return PR_FAILURE;
-- }
-+static PRStatus
-+nsSOCKSIOLayerConnectContinue(PRFileDesc *fd, PRInt16 oflags)
-+{
-+ PRStatus status;
-
-- }
-+ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
-+ if (info == NULL) return PR_FAILURE;
-
-+ do {
-+ status = info->DoHandshake(fd, oflags);
-+ } while (status == PR_SUCCESS && !info->IsConnected());
-
-- info->SetDestinationAddr((PRNetAddr*)addr);
-- info->SetExternalProxyAddr(&extAddr);
-+ return status;
-+}
-
-- // restore non-blocking option
-- PR_SetSocketOption(fd, &sockopt);
-+static PRInt16
-+nsSOCKSIOLayerPoll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
-+{
-+ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
-+ if (info == NULL) return PR_FAILURE;
-
-- // we're set-up and connected.
-- // this socket can be used as normal now.
-+ if (!info->IsConnected()) {
-+ *out_flags = 0;
-+ return info->GetPollFlags();
-+ }
-
-- return PR_SUCCESS;
-+ return fd->lower->methods->poll(fd->lower, in_flags, out_flags);
- }
-
- static PRStatus
-@@ -885,6 +1120,8 @@ nsSOCKSIOLayerAddToSocket(PRInt32 family,
- nsSOCKSIOLayerMethods = *PR_GetDefaultIOMethods();
-
- nsSOCKSIOLayerMethods.connect = nsSOCKSIOLayerConnect;
-+ nsSOCKSIOLayerMethods.connectcontinue = nsSOCKSIOLayerConnectContinue;
-+ nsSOCKSIOLayerMethods.poll = nsSOCKSIOLayerPoll;
- nsSOCKSIOLayerMethods.bind = nsSOCKSIOLayerBind;
- nsSOCKSIOLayerMethods.acceptread = nsSOCKSIOLayerAcceptRead;
- nsSOCKSIOLayerMethods.getsockname = nsSOCKSIOLayerGetName;
---
-1.7.3.4
-
diff --git a/src/current-patches/0001-Firefox5-Block-Components.interfaces-lookupMethod-fr.patch b/src/current-patches/0001-Firefox5-Block-Components.interfaces-lookupMethod-fr.patch
deleted file mode 100644
index 816e2d2..0000000
--- a/src/current-patches/0001-Firefox5-Block-Components.interfaces-lookupMethod-fr.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From cb6df58b95028693007936e423d43223609e17cc Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git(a)fscked.org>
-Date: Mon, 20 Jun 2011 17:07:41 -0700
-Subject: [PATCH 1/3] Firefox5: Block Components.interfaces,lookupMethod from content
-
-This patch removes the ability of content script to access
-Components.interfaces.* as well as call or access Components.lookupMethod.
-
-These two interfaces seem to be exposed to content script only to make our
-lives difficult. Components.lookupMethod can undo our JS hooks, and
-Components.interfaces is useful for fingerprinting the platform, OS, and
-Firebox version.
-
-They appear to have no other legitimate use. See also:
-https://bugzilla.mozilla.org/show_bug.cgi?id=429070
-https://trac.torproject.org/projects/tor/ticket/2873
-https://trac.torproject.org/projects/tor/ticket/2874
----
- js/src/xpconnect/src/xpccomponents.cpp | 8 ++++++--
- 1 files changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp
-index 5e789e7..5c76981 100644
---- a/js/src/xpconnect/src/xpccomponents.cpp
-+++ b/js/src/xpconnect/src/xpccomponents.cpp
-@@ -4287,7 +4287,9 @@ nsXPCComponents::CanCreateWrapper(const nsIID * iid, char **_retval)
- NS_IMETHODIMP
- nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
- {
-- static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
-+ // XXX: Pref observer? Also, is this what we want? Seems like a plan
-+ //static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
-+ static const char* allowed[] = { "isSuccessCode", nsnull };
- *_retval = xpc_CheckAccessList(methodName, allowed);
- return NS_OK;
- }
-@@ -4296,7 +4298,9 @@ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, c
- NS_IMETHODIMP
- nsXPCComponents::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
- {
-- static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
-+ // XXX: Pref observer? Also, is this what we want? Seems like a plan
-+ // static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
-+ static const char* allowed[] = { "results", nsnull};
- *_retval = xpc_CheckAccessList(propertyName, allowed);
- return NS_OK;
- }
---
-1.7.3.4
-
diff --git a/src/current-patches/0001-Firefox6-Block-Components.interfaces-lookupMethod-fr.patch b/src/current-patches/0001-Firefox6-Block-Components.interfaces-lookupMethod-fr.patch
new file mode 100644
index 0000000..39a5c99
--- /dev/null
+++ b/src/current-patches/0001-Firefox6-Block-Components.interfaces-lookupMethod-fr.patch
@@ -0,0 +1,50 @@
+From c745f4022a8795e81a690c4a680d46aa407ba6c7 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Mon, 20 Jun 2011 17:07:41 -0700
+Subject: [PATCH 1/3] Firefox6: Block Components.interfaces,lookupMethod from content
+
+This patch removes the ability of content script to access
+Components.interfaces.* as well as call or access Components.lookupMethod.
+
+These two interfaces seem to be exposed to content script only to make our
+lives difficult. Components.lookupMethod can undo our JS hooks, and
+Components.interfaces is useful for fingerprinting the platform, OS, and
+Firebox version.
+
+They appear to have no other legitimate use. See also:
+https://bugzilla.mozilla.org/show_bug.cgi?id=429070
+https://trac.torproject.org/projects/tor/ticket/2873
+https://trac.torproject.org/projects/tor/ticket/2874
+---
+ js/src/xpconnect/src/xpccomponents.cpp | 8 ++++++--
+ 1 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp
+index c1d3e30..48c8b6a 100644
+--- a/js/src/xpconnect/src/xpccomponents.cpp
++++ b/js/src/xpconnect/src/xpccomponents.cpp
+@@ -4231,7 +4231,9 @@ nsXPCComponents::CanCreateWrapper(const nsIID * iid, char **_retval)
+ NS_IMETHODIMP
+ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
+ {
+- static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
++ // XXX: Pref observer? Also, is this what we want? Seems like a plan
++ //static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
++ static const char* allowed[] = { "isSuccessCode", nsnull };
+ *_retval = xpc_CheckAccessList(methodName, allowed);
+ return NS_OK;
+ }
+@@ -4240,7 +4242,9 @@ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, c
+ NS_IMETHODIMP
+ nsXPCComponents::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
+ {
+- static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
++ // XXX: Pref observer? Also, is this what we want? Seems like a plan
++ // static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
++ static const char* allowed[] = { "results", nsnull};
+ *_retval = xpc_CheckAccessList(propertyName, allowed);
+ return NS_OK;
+ }
+--
+1.7.3.4
+
diff --git a/src/current-patches/0002-Firefox4-Block-Components.interfaces-lookupMethod-fr.patch b/src/current-patches/0002-Firefox4-Block-Components.interfaces-lookupMethod-fr.patch
deleted file mode 100644
index 8e34500..0000000
--- a/src/current-patches/0002-Firefox4-Block-Components.interfaces-lookupMethod-fr.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From ebaf58a014f98942886ae829da83fadd662df948 Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git(a)fscked.org>
-Date: Mon, 20 Jun 2011 17:07:41 -0700
-Subject: [PATCH 2/4] Firefox4: Block Components.interfaces,lookupMethod from content
-
-This patch removes the ability of content script to access
-Components.interfaces.* as well as call or access Components.lookupMethod.
-
-These two interfaces seem to be exposed to content script only to make our
-lives difficult. Components.lookupMethod can undo our JS hooks, and
-Components.interfaces is useful for fingerprinting the platform, OS, and
-Firebox version.
-
-They appear to have no other legitimate use. See also:
-https://bugzilla.mozilla.org/show_bug.cgi?id=429070
-https://trac.torproject.org/projects/tor/ticket/2873
-https://trac.torproject.org/projects/tor/ticket/2874
----
- js/src/xpconnect/src/xpccomponents.cpp | 8 ++++++--
- 1 files changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp
-index 1c141f9..85a2b4e 100644
---- a/js/src/xpconnect/src/xpccomponents.cpp
-+++ b/js/src/xpconnect/src/xpccomponents.cpp
-@@ -4294,7 +4294,9 @@ nsXPCComponents::CanCreateWrapper(const nsIID * iid, char **_retval)
- NS_IMETHODIMP
- nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
- {
-- static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
-+ // XXX: Pref observer? Also, is this what we want? Seems like a plan
-+ //static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
-+ static const char* allowed[] = { "isSuccessCode", nsnull };
- *_retval = xpc_CheckAccessList(methodName, allowed);
- return NS_OK;
- }
-@@ -4303,7 +4305,9 @@ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, c
- NS_IMETHODIMP
- nsXPCComponents::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
- {
-- static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
-+ // XXX: Pref observer? Also, is this what we want? Seems like a plan
-+ // static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
-+ static const char* allowed[] = { "results", nsnull};
- *_retval = xpc_CheckAccessList(propertyName, allowed);
- return NS_OK;
- }
---
-1.7.3.4
-
diff --git a/src/current-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch b/src/current-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch
deleted file mode 100644
index 2bd11e8..0000000
--- a/src/current-patches/0002-Firefox5-Make-Intermediate-Cert-Store-memory-only.patch
+++ /dev/null
@@ -1,300 +0,0 @@
-From 16b89c54032d1ad0acf2d6fa005b292a6f434791 Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git(a)fscked.org>
-Date: Mon, 20 Jun 2011 17:07:49 -0700
-Subject: [PATCH 2/3] Firefox5: Make Intermediate Cert Store memory-only.
-
-This patch makes the intermediate SSL cert store exist in memory only. It
-exposes a pref ('security.nocertdb') to toggle to clear the store, but this
-seems buggy.
-
-The pref must be set before startup in prefs.js.
-https://trac.torproject.org/projects/tor/ticket/2949
----
- security/manager/ssl/src/nsNSSComponent.cpp | 180 ++++++++++++++++++---------
- 1 files changed, 120 insertions(+), 60 deletions(-)
-
-diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp
-index d3ae772..fa37ace 100644
---- a/security/manager/ssl/src/nsNSSComponent.cpp
-+++ b/security/manager/ssl/src/nsNSSComponent.cpp
-@@ -1658,8 +1658,21 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
- // Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
- // "/usr/lib/nss/libnssckbi.so".
- PRUint32 init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
-- SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
-+ PRBool nocertdb = false;
-+ mPrefBranch->GetBoolPref("security.nocertdb", &nocertdb);
-+
-+ // XXX: We can also do the the following to only disable the certdb.
-+ // Leaving this codepath in as a fallback in case InitNODB fails
-+ if (nocertdb)
-+ init_flags |= NSS_INIT_NOCERTDB;
-+
-+ SECStatus init_rv;
-+ if (nocertdb) {
-+ init_rv = ::NSS_NoDB_Init(NULL);
-+ } else {
-+ init_rv = ::NSS_Initialize(profileStr.get(), "", "",
- SECMOD_DB, init_flags);
-+ }
-
- if (init_rv != SECSuccess) {
- PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init NSS r/w in %s\n", profileStr.get()));
-@@ -2215,70 +2228,106 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
- }
- }
- }
-- else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
-- nsNSSShutDownPreventionLock locker;
-- PRBool clearSessionCache = PR_FALSE;
-- PRBool enabled;
-+ else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
- NS_ConvertUTF16toUTF8 prefName(someData);
-+ // XXX: This should be an observer notification, so we can properly cancel it
-+ if (prefName.Equals("security.nocertdb")) {
-+ // XXX: If these functions tell us to cancel, the browser seems to get left in an
-+ // indeterminate state that prevents SSL from being used.
-+ //
-+ // We apparently need to wait for all SSL sockets to shut down on their
-+ // own (this can take up to a minute!) and then attempt to alter the pref
-+ // again before doing anything.
-+ //
-+ // So any implementation of New Identity based on this code will need to keep
-+ // attempting to send the notification until it is not canceled. Ugh...
-+ if (!DoProfileApproveChange(aSubject)) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled\n"));
-+ return NS_OK;
-+ }
-
-- if (prefName.Equals("security.enable_ssl2")) {
-- mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
-- SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
-- clearSessionCache = PR_TRUE;
-- } else if (prefName.Equals("security.enable_ssl3")) {
-- mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
-- clearSessionCache = PR_TRUE;
-- } else if (prefName.Equals("security.enable_tls")) {
-- mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
-- clearSessionCache = PR_TRUE;
-- } else if (prefName.Equals("security.enable_tls_session_tickets")) {
-- mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
-- } else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
-- mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
-- SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
-- } else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
-- mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
-- enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
-- } else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
-- char *unrestricted_hosts=nsnull;
-- mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
-- if (unrestricted_hosts) {
-- nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
-- nsMemory::Free(unrestricted_hosts);
-+ DoProfileChangeNetTeardown();
-+ if (!DoProfileChangeTeardown(aSubject)) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled\n"));
-+ return NS_OK;
-+ }
-+
-+ if (!DoProfileBeforeChange(aSubject)) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled by NSS shutdown\n"));
-+ // Need to re-add observer because ShutdownNSS removed it.
-+ nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(mPrefBranch);
-+ pbi->AddObserver("security.", this, PR_FALSE);
-+ return NS_OK;
- }
-- } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
-- mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
-- nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
-- } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
-- PRInt32 warnLevel = 1;
-- mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
-- nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
-+
-+ DoProfileChangeNetRestore();
-+ InitializeNSS(PR_FALSE);
-+ InitializeCRLUpdateTimer();
-+ return NS_OK;
-+ } else {
-+ nsNSSShutDownPreventionLock locker;
-+ PRBool clearSessionCache = PR_FALSE;
-+ PRBool enabled;
-+
-+ if (prefName.Equals("security.enable_ssl2")) {
-+ mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
-+ SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
-+ clearSessionCache = PR_TRUE;
-+ } else if (prefName.Equals("security.enable_ssl3")) {
-+ mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
-+ clearSessionCache = PR_TRUE;
-+ } else if (prefName.Equals("security.enable_tls")) {
-+ mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
-+ clearSessionCache = PR_TRUE;
-+ } else if (prefName.Equals("security.enable_tls_session_tickets")) {
-+ mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
-+ } else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
-+ mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
-+ SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
-+ } else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
-+ mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
-+ enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
-+ } else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
-+ char *unrestricted_hosts=nsnull;
-+ mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
-+ if (unrestricted_hosts) {
-+ nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
-+ nsMemory::Free(unrestricted_hosts);
-+ }
-+ } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
-+ mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
-+ nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
-+ } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
-+ PRInt32 warnLevel = 1;
-+ mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
-+ nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
- #ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8
-- } else if (prefName.Equals("security.ssl.enable_false_start")) {
-- mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
-+ } else if (prefName.Equals("security.ssl.enable_false_start")) {
-+ mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
- #endif
-- } else if (prefName.Equals("security.OCSP.enabled")
-- || prefName.Equals("security.OCSP.require")) {
-- setOCSPOptions(mPrefBranch);
-- } else {
-- /* Look through the cipher table and set according to pref setting */
-- for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
-- if (prefName.Equals(cp->pref)) {
-- mPrefBranch->GetBoolPref(cp->pref, &enabled);
-- SSL_CipherPrefSetDefault(cp->id, enabled);
-- clearSessionCache = PR_TRUE;
-- break;
-+ } else if (prefName.Equals("security.OCSP.enabled")
-+ || prefName.Equals("security.OCSP.require")) {
-+ setOCSPOptions(mPrefBranch);
-+ } else {
-+ /* Look through the cipher table and set according to pref setting */
-+ for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
-+ if (prefName.Equals(cp->pref)) {
-+ mPrefBranch->GetBoolPref(cp->pref, &enabled);
-+ SSL_CipherPrefSetDefault(cp->id, enabled);
-+ clearSessionCache = PR_TRUE;
-+ break;
-+ }
- }
- }
-+ if (clearSessionCache)
-+ SSL_ClearSessionCache();
- }
-- if (clearSessionCache)
-- SSL_ClearSessionCache();
- }
- else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_TEARDOWN_TOPIC) == 0) {
- PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network teardown topic\n"));
-@@ -2447,16 +2496,19 @@ nsNSSComponent::RememberCert(CERTCertificate *cert)
- return NS_OK;
- }
-
--void
-+PRBool
- nsNSSComponent::DoProfileApproveChange(nsISupports* aSubject)
- {
- if (mShutdownObjectList->isUIActive()) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS UI active in profile change!\n"));
- ShowAlert(ai_crypto_ui_active);
- nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
- if (status) {
- status->VetoChange();
- }
-+ return false;
- }
-+ return true;
- }
-
- void
-@@ -2469,16 +2521,18 @@ nsNSSComponent::DoProfileChangeNetTeardown()
- mIsNetworkDown = PR_TRUE;
- }
-
--void
-+PRBool
- nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject)
- {
- PRBool callVeto = PR_FALSE;
-
- if (!mShutdownObjectList->ifPossibleDisallowUI()) {
- callVeto = PR_TRUE;
-+ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: Not possible to disallow UI!\n"));
- ShowAlert(ai_crypto_ui_active);
- }
- else if (mShutdownObjectList->areSSLSocketsActive()) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: SSL Sockets are active!\n"));
- callVeto = PR_TRUE;
- ShowAlert(ai_sockets_still_active);
- }
-@@ -2489,9 +2543,11 @@ nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject)
- status->VetoChange();
- }
- }
-+
-+ return !callVeto;
- }
-
--void
-+PRBool
- nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject)
- {
- NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
-@@ -2510,16 +2566,20 @@ nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject)
- }
-
- StopCRLUpdateTimer();
-+ PRBool allow_change = PR_TRUE;
-
- if (needsCleanup) {
- if (NS_FAILED(ShutdownNSS())) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: Shutdown failed\n"));
- nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
- if (status) {
- status->ChangeFailed();
- }
-+ allow_change = PR_FALSE;
- }
- }
- mShutdownObjectList->allowUI();
-+ return allow_change;
- }
-
- void
---- a/security/manager/ssl/src/nsNSSComponent.h
-+++ b/security/manager/ssl/src/nsNSSComponent.h
-@@ -321,10 +321,10 @@
-
- // Methods that we use to handle the profile change notifications (and to
- // synthesize a full profile change when we're just doing a profile startup):
-- void DoProfileApproveChange(nsISupports* aSubject);
-+ PRBool DoProfileApproveChange(nsISupports* aSubject);
- void DoProfileChangeNetTeardown();
-- void DoProfileChangeTeardown(nsISupports* aSubject);
-- void DoProfileBeforeChange(nsISupports* aSubject);
-+ PRBool DoProfileChangeTeardown(nsISupports* aSubject);
-+ PRBool DoProfileBeforeChange(nsISupports* aSubject);
- void DoProfileChangeNetRestore();
-
- Mutex mutex;
-
---
-1.7.3.4
-
diff --git a/src/current-patches/0002-Firefox6-Make-Permissions-Manager-memory-only.patch b/src/current-patches/0002-Firefox6-Make-Permissions-Manager-memory-only.patch
new file mode 100644
index 0000000..35262e6
--- /dev/null
+++ b/src/current-patches/0002-Firefox6-Make-Permissions-Manager-memory-only.patch
@@ -0,0 +1,94 @@
+From 1eb6ddb69b9fa4b82a555398d2c47b8ef1166ae2 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Mon, 20 Jun 2011 17:07:56 -0700
+Subject: [PATCH 2/3] Firefox6: Make Permissions Manager memory-only
+
+This patch exposes a pref 'permissions.memory_only' that properly isolates the
+permissions manager to memory, which is responsible for all user specified
+site permissions, as well as stored STS policy.
+
+The pref does successfully clear the permissions manager memory if toggled. It
+does not need to be set in prefs.js, and can be handled by Torbutton.
+
+https://trac.torproject.org/projects/tor/ticket/2950
+---
+ extensions/cookie/nsPermissionManager.cpp | 34 ++++++++++++++++++++++++++--
+ 1 files changed, 31 insertions(+), 3 deletions(-)
+
+diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp
+index 773a973..5387397 100644
+--- a/extensions/cookie/nsPermissionManager.cpp
++++ b/extensions/cookie/nsPermissionManager.cpp
+@@ -58,6 +58,10 @@
+ #include "mozStorageHelper.h"
+ #include "mozStorageCID.h"
+ #include "nsXULAppAPI.h"
++#include "nsCOMPtr.h"
++#include "nsIPrefService.h"
++#include "nsIPrefBranch.h"
++#include "nsIPrefBranch2.h"
+
+ static nsPermissionManager *gPermissionManager = nsnull;
+
+@@ -227,6 +231,11 @@ nsPermissionManager::Init()
+ mObserverService->AddObserver(this, "profile-do-change", PR_TRUE);
+ }
+
++ nsCOMPtr<nsIPrefBranch2> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
++ if (pbi) {
++ pbi->AddObserver("permissions.", this, PR_FALSE);
++ }
++
+ if (IsChildProcess()) {
+ // Get the permissions from the parent process
+ InfallibleTArray<IPC::Permission> perms;
+@@ -275,8 +284,18 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
+ if (!storage)
+ return NS_ERROR_UNEXPECTED;
+
++ PRBool memory_db = false;
++ nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
++ if (prefs) {
++ prefs->GetBoolPref("permissions.memory_only", &memory_db);
++ }
++
+ // cache a connection to the hosts database
+- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ if (memory_db) {
++ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
++ } else {
++ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ }
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRBool ready;
+@@ -286,7 +305,11 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
+ rv = permissionsFile->Remove(PR_FALSE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ if (memory_db) {
++ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
++ } else {
++ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++ }
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mDBConn->GetConnectionReady(&ready);
+@@ -805,7 +828,12 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
+ {
+ ENSURE_NOT_CHILD_PROCESS;
+
+- if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
++ if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
++ if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("permissions.memory_only").get())) {
++ // XXX: Should we remove the file? Probably not..
++ InitDB(PR_FALSE);
++ }
++ } else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
+ // The profile is about to change,
+ // or is going away because the application is shutting down.
+ if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
+--
+1.7.3.4
+
diff --git a/src/current-patches/0003-Firefox4-Make-Intermediate-Cert-Store-memory-only.patch b/src/current-patches/0003-Firefox4-Make-Intermediate-Cert-Store-memory-only.patch
deleted file mode 100644
index d4f7b73..0000000
--- a/src/current-patches/0003-Firefox4-Make-Intermediate-Cert-Store-memory-only.patch
+++ /dev/null
@@ -1,283 +0,0 @@
-From 4db14cbb5a0aff6102189d30b9202555dcc39ff4 Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git(a)fscked.org>
-Date: Mon, 20 Jun 2011 17:07:49 -0700
-Subject: [PATCH 3/4] Firefox4: Make Intermediate Cert Store memory-only.
-
-This patch makes the intermediate SSL cert store exist in memory only. It
-exposes a pref ('security.nocertdb') to toggle to clear the store, but this
-seems buggy.
-
-The pref must be set before startup in prefs.js.
-https://trac.torproject.org/projects/tor/ticket/2949
----
- security/manager/ssl/src/nsNSSComponent.cpp | 180 ++++++++++++++++++---------
- 1 files changed, 120 insertions(+), 60 deletions(-)
-
-diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp
-index 33377ac..716bcee 100644
---- a/security/manager/ssl/src/nsNSSComponent.cpp
-+++ b/security/manager/ssl/src/nsNSSComponent.cpp
-@@ -1674,8 +1674,21 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
- // Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
- // "/usr/lib/nss/libnssckbi.so".
- PRUint32 init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
-- SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
-+ PRBool nocertdb = false;
-+ mPrefBranch->GetBoolPref("security.nocertdb", &nocertdb);
-+
-+ // XXX: We can also do the the following to only disable the certdb.
-+ // Leaving this codepath in as a fallback in case InitNODB fails
-+ if (nocertdb)
-+ init_flags |= NSS_INIT_NOCERTDB;
-+
-+ SECStatus init_rv;
-+ if (nocertdb) {
-+ init_rv = ::NSS_NoDB_Init(NULL);
-+ } else {
-+ init_rv = ::NSS_Initialize(profileStr.get(), "", "",
- SECMOD_DB, init_flags);
-+ }
-
- if (init_rv != SECSuccess) {
- PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init NSS r/w in %s\n", profileStr.get()));
-@@ -2231,70 +2244,106 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
- }
- }
- }
-- else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
-- nsNSSShutDownPreventionLock locker;
-- PRBool clearSessionCache = PR_FALSE;
-- PRBool enabled;
-+ else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
- NS_ConvertUTF16toUTF8 prefName(someData);
-+ // XXX: This should be an observer notification, so we can properly cancel it
-+ if (prefName.Equals("security.nocertdb")) {
-+ // XXX: If these functions tell us to cancel, the browser seems to get left in an
-+ // indeterminate state that prevents SSL from being used.
-+ //
-+ // We apparently need to wait for all SSL sockets to shut down on their
-+ // own (this can take up to a minute!) and then attempt to alter the pref
-+ // again before doing anything.
-+ //
-+ // So any implementation of New Identity based on this code will need to keep
-+ // attempting to send the notification until it is not canceled. Ugh...
-+ if (!DoProfileApproveChange(aSubject)) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled\n"));
-+ return NS_OK;
-+ }
-
-- if (prefName.Equals("security.enable_ssl2")) {
-- mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
-- SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
-- clearSessionCache = PR_TRUE;
-- } else if (prefName.Equals("security.enable_ssl3")) {
-- mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
-- clearSessionCache = PR_TRUE;
-- } else if (prefName.Equals("security.enable_tls")) {
-- mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
-- clearSessionCache = PR_TRUE;
-- } else if (prefName.Equals("security.enable_tls_session_tickets")) {
-- mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
-- } else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
-- mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
-- SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
-- } else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
-- mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
-- enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
-- } else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
-- char *unrestricted_hosts=nsnull;
-- mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
-- if (unrestricted_hosts) {
-- nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
-- nsMemory::Free(unrestricted_hosts);
-+ DoProfileChangeNetTeardown();
-+ if (!DoProfileChangeTeardown(aSubject)) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled\n"));
-+ return NS_OK;
-+ }
-+
-+ if (!DoProfileBeforeChange(aSubject)) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDB change canceled by NSS shutdown\n"));
-+ // Need to re-add observer because ShutdownNSS removed it.
-+ nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(mPrefBranch);
-+ pbi->AddObserver("security.", this, PR_FALSE);
-+ return NS_OK;
- }
-- } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
-- mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
-- nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
-- } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
-- PRInt32 warnLevel = 1;
-- mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
-- nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
-+
-+ DoProfileChangeNetRestore();
-+ InitializeNSS(PR_FALSE);
-+ InitializeCRLUpdateTimer();
-+ return NS_OK;
-+ } else {
-+ nsNSSShutDownPreventionLock locker;
-+ PRBool clearSessionCache = PR_FALSE;
-+ PRBool enabled;
-+
-+ if (prefName.Equals("security.enable_ssl2")) {
-+ mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
-+ SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
-+ clearSessionCache = PR_TRUE;
-+ } else if (prefName.Equals("security.enable_ssl3")) {
-+ mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
-+ clearSessionCache = PR_TRUE;
-+ } else if (prefName.Equals("security.enable_tls")) {
-+ mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
-+ clearSessionCache = PR_TRUE;
-+ } else if (prefName.Equals("security.enable_tls_session_tickets")) {
-+ mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
-+ } else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
-+ mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
-+ SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
-+ } else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
-+ mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
-+ enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
-+ } else if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
-+ char *unrestricted_hosts=nsnull;
-+ mPrefBranch->GetCharPref("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
-+ if (unrestricted_hosts) {
-+ nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(nsDependentCString(unrestricted_hosts));
-+ nsMemory::Free(unrestricted_hosts);
-+ }
-+ } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
-+ mPrefBranch->GetBoolPref("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
-+ nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(enabled);
-+ } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
-+ PRInt32 warnLevel = 1;
-+ mPrefBranch->GetIntPref("security.ssl.warn_missing_rfc5746", &warnLevel);
-+ nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(warnLevel);
- #ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8
-- } else if (prefName.Equals("security.ssl.enable_false_start")) {
-- mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
-- SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
-+ } else if (prefName.Equals("security.ssl.enable_false_start")) {
-+ mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
-+ SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
- #endif
-- } else if (prefName.Equals("security.OCSP.enabled")
-- || prefName.Equals("security.OCSP.require")) {
-- setOCSPOptions(mPrefBranch);
-- } else {
-- /* Look through the cipher table and set according to pref setting */
-- for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
-- if (prefName.Equals(cp->pref)) {
-- mPrefBranch->GetBoolPref(cp->pref, &enabled);
-- SSL_CipherPrefSetDefault(cp->id, enabled);
-- clearSessionCache = PR_TRUE;
-- break;
-+ } else if (prefName.Equals("security.OCSP.enabled")
-+ || prefName.Equals("security.OCSP.require")) {
-+ setOCSPOptions(mPrefBranch);
-+ } else {
-+ /* Look through the cipher table and set according to pref setting */
-+ for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
-+ if (prefName.Equals(cp->pref)) {
-+ mPrefBranch->GetBoolPref(cp->pref, &enabled);
-+ SSL_CipherPrefSetDefault(cp->id, enabled);
-+ clearSessionCache = PR_TRUE;
-+ break;
-+ }
- }
- }
-+ if (clearSessionCache)
-+ SSL_ClearSessionCache();
- }
-- if (clearSessionCache)
-- SSL_ClearSessionCache();
- }
- else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_TEARDOWN_TOPIC) == 0) {
- PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network teardown topic\n"));
-@@ -2463,16 +2512,19 @@ nsNSSComponent::RememberCert(CERTCertificate *cert)
- return NS_OK;
- }
-
--void
-+PRBool
- nsNSSComponent::DoProfileApproveChange(nsISupports* aSubject)
- {
- if (mShutdownObjectList->isUIActive()) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS UI active in profile change!\n"));
- ShowAlert(ai_crypto_ui_active);
- nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
- if (status) {
- status->VetoChange();
- }
-+ return false;
- }
-+ return true;
- }
-
- void
-@@ -2485,16 +2537,18 @@ nsNSSComponent::DoProfileChangeNetTeardown()
- mIsNetworkDown = PR_TRUE;
- }
-
--void
-+PRBool
- nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject)
- {
- PRBool callVeto = PR_FALSE;
-
- if (!mShutdownObjectList->ifPossibleDisallowUI()) {
- callVeto = PR_TRUE;
-+ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: Not possible to disallow UI!\n"));
- ShowAlert(ai_crypto_ui_active);
- }
- else if (mShutdownObjectList->areSSLSocketsActive()) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: SSL Sockets are active!\n"));
- callVeto = PR_TRUE;
- ShowAlert(ai_sockets_still_active);
- }
-@@ -2505,9 +2559,11 @@ nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject)
- status->VetoChange();
- }
- }
-+
-+ return !callVeto;
- }
-
--void
-+PRBool
- nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject)
- {
- NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
-@@ -2526,16 +2582,20 @@ nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject)
- }
-
- StopCRLUpdateTimer();
-+ PRBool allow_change = PR_TRUE;
-
- if (needsCleanup) {
- if (NS_FAILED(ShutdownNSS())) {
-+ PR_LOG(gPIPNSSLog, PR_LOG_WARN, ("NSS: Shutdown failed\n"));
- nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
- if (status) {
- status->ChangeFailed();
- }
-+ allow_change = PR_FALSE;
- }
- }
- mShutdownObjectList->allowUI();
-+ return allow_change;
- }
-
- void
---
-1.7.3.4
-
diff --git a/src/current-patches/0003-Firefox5-Make-Permissions-Manager-memory-only.patch b/src/current-patches/0003-Firefox5-Make-Permissions-Manager-memory-only.patch
deleted file mode 100644
index 1384245..0000000
--- a/src/current-patches/0003-Firefox5-Make-Permissions-Manager-memory-only.patch
+++ /dev/null
@@ -1,94 +0,0 @@
-From 16bafbf39c89cce901af6500255822677bc4c36d Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git(a)fscked.org>
-Date: Mon, 20 Jun 2011 17:07:56 -0700
-Subject: [PATCH 3/3] Firefox5: Make Permissions Manager memory-only
-
-This patch exposes a pref 'permissions.memory_only' that properly isolates the
-permissions manager to memory, which is responsible for all user specified
-site permissions, as well as stored STS policy.
-
-The pref does successfully clear the permissions manager memory if toggled. It
-does not need to be set in prefs.js, and can be handled by Torbutton.
-
-https://trac.torproject.org/projects/tor/ticket/2950
----
- extensions/cookie/nsPermissionManager.cpp | 34 ++++++++++++++++++++++++++--
- 1 files changed, 31 insertions(+), 3 deletions(-)
-
-diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp
-index 773a973..5387397 100644
---- a/extensions/cookie/nsPermissionManager.cpp
-+++ b/extensions/cookie/nsPermissionManager.cpp
-@@ -58,6 +58,10 @@
- #include "mozStorageHelper.h"
- #include "mozStorageCID.h"
- #include "nsXULAppAPI.h"
-+#include "nsCOMPtr.h"
-+#include "nsIPrefService.h"
-+#include "nsIPrefBranch.h"
-+#include "nsIPrefBranch2.h"
-
- static nsPermissionManager *gPermissionManager = nsnull;
-
-@@ -227,6 +231,11 @@ nsPermissionManager::Init()
- mObserverService->AddObserver(this, "profile-do-change", PR_TRUE);
- }
-
-+ nsCOMPtr<nsIPrefBranch2> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
-+ if (pbi) {
-+ pbi->AddObserver("permissions.", this, PR_FALSE);
-+ }
-+
- if (IsChildProcess()) {
- // Get the permissions from the parent process
- InfallibleTArray<IPC::Permission> perms;
-@@ -275,8 +284,18 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
- if (!storage)
- return NS_ERROR_UNEXPECTED;
-
-+ PRBool memory_db = false;
-+ nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
-+ if (prefs) {
-+ prefs->GetBoolPref("permissions.memory_only", &memory_db);
-+ }
-+
- // cache a connection to the hosts database
-- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
-+ if (memory_db) {
-+ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
-+ } else {
-+ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
-+ }
- NS_ENSURE_SUCCESS(rv, rv);
-
- PRBool ready;
-@@ -286,7 +305,11 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
- rv = permissionsFile->Remove(PR_FALSE);
- NS_ENSURE_SUCCESS(rv, rv);
-
-- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
-+ if (memory_db) {
-+ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
-+ } else {
-+ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
-+ }
- NS_ENSURE_SUCCESS(rv, rv);
-
- mDBConn->GetConnectionReady(&ready);
-@@ -805,7 +828,12 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
- {
- ENSURE_NOT_CHILD_PROCESS;
-
-- if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
-+ if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
-+ if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("permissions.memory_only").get())) {
-+ // XXX: Should we remove the file? Probably not..
-+ InitDB(PR_FALSE);
-+ }
-+ } else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
- // The profile is about to change,
- // or is going away because the application is shutting down.
- if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
---
-1.7.3.4
-
diff --git a/src/current-patches/0003-Firefox6-Make-Intermediate-Cert-Store-memory-only.patch b/src/current-patches/0003-Firefox6-Make-Intermediate-Cert-Store-memory-only.patch
new file mode 100644
index 0000000..9c568a0
--- /dev/null
+++ b/src/current-patches/0003-Firefox6-Make-Intermediate-Cert-Store-memory-only.patch
@@ -0,0 +1,43 @@
+From 2bdee82990bbda960d23d6122bf89d422bb63211 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git(a)fscked.org>
+Date: Fri, 19 Aug 2011 17:58:23 -0700
+Subject: [PATCH 3/3] Firefox6: Make Intermediate Cert Store memory-only.
+
+This patch makes the intermediate SSL cert store exist in memory only.
+
+The pref must be set before startup in prefs.js.
+https://trac.torproject.org/projects/tor/ticket/2949
+---
+ security/manager/ssl/src/nsNSSComponent.cpp | 16 ++++++++++++++++
+ 1 files changed, 16 insertions(+), 0 deletions(-)
+
+diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp
+index 7a8569b..5261c5e 100644
+--- a/security/manager/ssl/src/nsNSSComponent.cpp
++++ b/security/manager/ssl/src/nsNSSComponent.cpp
+@@ -1729,6 +1729,22 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
+ // Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
+ // "/usr/lib/nss/libnssckbi.so".
+ PRUint32 init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
++ PRBool nocertdb = false;
++ mPrefBranch->GetBoolPref("security.nocertdb", &nocertdb);
++
++ // XXX: We can also do the the following to only disable the certdb.
++ // Leaving this codepath in as a fallback in case InitNODB fails
++ if (nocertdb)
++ init_flags |= NSS_INIT_NOCERTDB;
++
++ SECStatus init_rv;
++ if (nocertdb) {
++ init_rv = ::NSS_NoDB_Init(NULL);
++ } else {
++ init_rv = ::NSS_Initialize(profileStr.get(), "", "",
++ SECMOD_DB, init_flags);
++ }
++
+ SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
+ SECMOD_DB, init_flags);
+
+--
+1.7.3.4
+
diff --git a/src/current-patches/0004-Firefox4-Make-Permissions-Manager-memory-only.patch b/src/current-patches/0004-Firefox4-Make-Permissions-Manager-memory-only.patch
deleted file mode 100644
index 8f7ddd9..0000000
--- a/src/current-patches/0004-Firefox4-Make-Permissions-Manager-memory-only.patch
+++ /dev/null
@@ -1,94 +0,0 @@
-From 6f37edd80181906c37ace589fc26eabf6731b09d Mon Sep 17 00:00:00 2001
-From: Mike Perry <mikeperry-git(a)fscked.org>
-Date: Mon, 20 Jun 2011 17:07:56 -0700
-Subject: [PATCH 4/4] Firefox4: Make Permissions Manager memory-only
-
-This patch exposes a pref 'permissions.memory_only' that properly isolates the
-permissions manager to memory, which is responsible for all user specified
-site permissions, as well as stored STS policy.
-
-The pref does successfully clear the permissions manager memory if toggled. It
-does not need to be set in prefs.js, and can be handled by Torbutton.
-
-https://trac.torproject.org/projects/tor/ticket/2950
----
- extensions/cookie/nsPermissionManager.cpp | 34 ++++++++++++++++++++++++++--
- 1 files changed, 31 insertions(+), 3 deletions(-)
-
-diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp
-index d182013..0a1aea6 100644
---- a/extensions/cookie/nsPermissionManager.cpp
-+++ b/extensions/cookie/nsPermissionManager.cpp
-@@ -60,6 +60,10 @@
- #include "mozStorageHelper.h"
- #include "mozStorageCID.h"
- #include "nsXULAppAPI.h"
-+#include "nsCOMPtr.h"
-+#include "nsIPrefService.h"
-+#include "nsIPrefBranch.h"
-+#include "nsIPrefBranch2.h"
-
- static nsPermissionManager *gPermissionManager = nsnull;
-
-@@ -233,6 +237,11 @@ nsPermissionManager::Init()
- mObserverService->AddObserver(this, "profile-do-change", PR_TRUE);
- }
-
-+ nsCOMPtr<nsIPrefBranch2> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
-+ if (pbi) {
-+ pbi->AddObserver("permissions.", this, PR_FALSE);
-+ }
-+
- #ifdef MOZ_IPC
- if (IsChildProcess()) {
- // Get the permissions from the parent process
-@@ -283,8 +292,18 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
- if (!storage)
- return NS_ERROR_UNEXPECTED;
-
-+ PRBool memory_db = false;
-+ nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
-+ if (prefs) {
-+ prefs->GetBoolPref("permissions.memory_only", &memory_db);
-+ }
-+
- // cache a connection to the hosts database
-- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
-+ if (memory_db) {
-+ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
-+ } else {
-+ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
-+ }
- NS_ENSURE_SUCCESS(rv, rv);
-
- PRBool ready;
-@@ -294,7 +313,11 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
- rv = permissionsFile->Remove(PR_FALSE);
- NS_ENSURE_SUCCESS(rv, rv);
-
-- rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
-+ if (memory_db) {
-+ rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
-+ } else {
-+ rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
-+ }
- NS_ENSURE_SUCCESS(rv, rv);
-
- mDBConn->GetConnectionReady(&ready);
-@@ -825,7 +848,12 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
- ENSURE_NOT_CHILD_PROCESS;
- #endif
-
-- if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
-+ if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
-+ if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("permissions.memory_only").get())) {
-+ // XXX: Should we remove the file? Probably not..
-+ InitDB(PR_FALSE);
-+ }
-+ } else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
- // The profile is about to change,
- // or is going away because the application is shutting down.
- if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
---
-1.7.3.4
-
1
0

[torbrowser/master] update lots and lots of build targets for building firefox, fixing tabs, and making it easier to download & unpack all of the tarballs
by erinn@torproject.org 23 Oct '11
by erinn@torproject.org 23 Oct '11
23 Oct '11
commit a5f7328004ffef76cb954719f0f3749dc8e3b45f
Author: Erinn Clark <erinn(a)torproject.org>
Date: Sat Aug 20 21:35:01 2011 +0200
update lots and lots of build targets for building firefox, fixing tabs, and making it easier to download & unpack all of the tarballs
---
build-scripts/config/dot_mozconfig | 3 ---
build-scripts/linux.mk | 24 ++++++++++++++++++------
build-scripts/osx.mk | 4 ++++
build-scripts/versions.mk | 35 +++++++++++++++++++++++++++++++----
build-scripts/windows.mk | 2 +-
5 files changed, 54 insertions(+), 14 deletions(-)
diff --git a/build-scripts/config/dot_mozconfig b/build-scripts/config/dot_mozconfig
index 7ba5ca6..934e4f4 100755
--- a/build-scripts/config/dot_mozconfig
+++ b/build-scripts/config/dot_mozconfig
@@ -3,9 +3,6 @@
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-@CONFIG_GUESS@
mk_add_options MOZ_APP_DISPLAYNAME=TorBrowser
-ac_add_options --enable-static
-ac_add_options --disable-shared
-ac_add_options --disable-libxul
ac_add_options --enable-optimize
ac_add_options --disable-tests
ac_add_options --disable-debug
diff --git a/build-scripts/linux.mk b/build-scripts/linux.mk
index aaeb11d..1a70edb 100644
--- a/build-scripts/linux.mk
+++ b/build-scripts/linux.mk
@@ -108,8 +108,20 @@ build-polipo:
build-pidgin:
echo "We're not building pidgin yet!"
+FIREFOX_DIR=$(FETCH_DIR)/mozilla-release
build-firefox:
- # XXX: add directions ASAP
+ cp ../src/current-patches/*Firefox* $(FIREFOX_DIR)
+ cp patch-firefox-src.sh $(FIREFOX_DIR)
+ cp $(CONFIG_SRC)/mozconfig-osx-$(ARCH_TYPE) $(FIREFOX_DIR)/mozconfig
+ cd $(FIREFOX_DIR) && ./patch-firefox-src.sh
+ cd $(FIREFOX_DIR) && make -f client.mk build
+
+copy-firefox:
+ -rm -rf $(FETCH_DIR)/Firefox
+ ## This is so ugly. Update it to use cool tar --transform soon.
+ cd $(FIREFOX_DIR) && make -C obj-$(ARCH_TYPE)-pc-linux-gnu/ package
+ cp $(FIREFOX_DIR)/obj-$(ARCH_TYPE)-pc-linux-gnu/*bz2 $(FETCH_DIR)
+ cd $(FETCH_DIR) && tar -xvjf firefox-$(FIREFOX_VER).en-US.bz2 && mv firefox Firefox
# source-dance unpack-source
build-all-binaries: source-dance build-zlib build-openssl build-libpng build-qt build-vidalia build-libevent build-tor build-polipo
@@ -269,9 +281,9 @@ install-binaries:
cp -d $(ZLIB)/libz.so $(ZLIB)/libz.so.1 $(ZLIB)/libz.so.1.2.5 $(LIBSDIR)/libz
# Libevent
cp -d $(LIBEVENT)/libevent-2.0.so.5 $(LIBEVENT)/libevent-2.0.so.5.0.1 $(LIBEVENT)/libevent_core.so \
- $(LIBEVENT)/libevent_core-2.0.so.5 $(LIBEVENT)/libevent_core-2.0.so.5.0.1 \
- $(LIBEVENT)/libevent_extra-2.0.so.5 $(LIBEVENT)/libevent_extra-2.0.so.5.0.1 \
- $(LIBEVENT)/libevent_extra.so $(LIBEVENT)/libevent.so $(LIBSDIR)
+ $(LIBEVENT)/libevent_core-2.0.so.5 $(LIBEVENT)/libevent_core-2.0.so.5.0.1 \
+ $(LIBEVENT)/libevent_extra-2.0.so.5 $(LIBEVENT)/libevent_extra-2.0.so.5.0.1 \
+ $(LIBEVENT)/libevent_extra.so $(LIBEVENT)/libevent.so $(LIBSDIR)
# libpng
cp -d $(LIBPNG)/libpng14.so* $(LIBSDIR)
# OpenSSL
@@ -436,8 +448,8 @@ patch-pidgin-language:
## Patch Pidgin
ifeq ($(USE_PIDGIN),1)
./patch-pidgin-language.sh $(BUNDLE)/PidginPortable/Data/settings/PidginPortableSettings.ini $(LANGCODE) \
- $(BUNDLE)/PidginPortable/App/Pidgin/locale \
- $(BUNDLE)/PidginPortable/App/GTK/share/locale
+ $(BUNDLE)/PidginPortable/App/Pidgin/locale \
+ $(BUNDLE)/PidginPortable/App/GTK/share/locale
endif
patch-firefox-language:
diff --git a/build-scripts/osx.mk b/build-scripts/osx.mk
index 7151ddf..1ab3a77 100644
--- a/build-scripts/osx.mk
+++ b/build-scripts/osx.mk
@@ -109,6 +109,10 @@ build-firefox:
cd $(FIREFOX_DIR) && ./patch-firefox-src.sh
cd $(FIREFOX_DIR) && make -f client.mk build
+copy-firefox:
+ -rm -rf $(FETCH_DIR)/Firefox.app
+ cp -r $(FIREFOX_DIR)/obj*/dist/*.app $(FETCH_DIR)/Firefox.app
+
build-all-binaries: build-zlib build-openssl build-vidalia build-libevent build-tor
echo "If we're here, we've done something right."
diff --git a/build-scripts/versions.mk b/build-scripts/versions.mk
index e116326..e8991a2 100644
--- a/build-scripts/versions.mk
+++ b/build-scripts/versions.mk
@@ -35,28 +35,55 @@ ZLIB_URL=http://www.zlib.net/$(ZLIB_PACKAGE)
OPENSSL_URL=http://www.openssl.org/source/$(OPENSSL_PACKAGE)
QT_URL=ftp://ftp.qt.nokia.com/qt/source/$(QT_PACKAGE)
VIDALIA_URL=http://www.torproject.org/dist/vidalia/$(VIDALIA_PACKAGE)
-LIBEVENT_URL=http://www.monkey.org/~provos/$(LIBEVENT_PACKAGE)
+LIBEVENT_URL=http://archive.torproject.org/tor-package-archive/libevent/$(LIBEVENT_PACKAGE)
TOR_URL=http://www.torproject.org/dist/$(TOR_PACKAGE)
PIDGIN_URL=http://sourceforge.net/projects/pidgin/files/Pidgin/$(PIDGIN_PAC…
FIREFOX_URL=http://releases.mozilla.org/pub/mozilla.org/firefox/releases/$(…
-fetch-source:
+fetch-source: fetch-zlib fetch-openssl fetch-vidalia fetch-libevent fetch-tor fetch-firefox
-mkdir $(FETCH_DIR)
+
+fetch-zlib:
$(WGET) --no-check-certificate --directory-prefix=$(FETCH_DIR) $(ZLIB_URL)
+
+fetch-openssl:
$(WGET) --no-check-certificate --directory-prefix=$(FETCH_DIR) $(OPENSSL_URL)
+
+fetch-vidalia:
$(WGET) --no-check-certificate --directory-prefix=$(FETCH_DIR) $(VIDALIA_URL)
+
+fetch-libevent:
$(WGET) --no-check-certificate --directory-prefix=$(FETCH_DIR) $(LIBEVENT_URL)
+
+fetch-tor:
$(WGET) --no-check-certificate --directory-prefix=$(FETCH_DIR) $(TOR_URL)
fetch-firefox:
-rm -rf $(FETCH_DIR)/mozilla-release
$(WGET) --no-check-certificate --directory-prefix=$(FETCH_DIR) $(FIREFOX_URL)
-unpack-source:
+unpack-source: unpack-zlib unpack-openssl unpack-vidalia unpack-libevent unpack-tor unpack-firefox
+
+unpack-zlib:
+ -rm -rf $(FETCH_DIR)/zlib-$(ZLIB_VER)
cd $(FETCH_DIR) && tar -xvzf $(ZLIB_PACKAGE)
+
+unpack-openssl:
+ -rm -rf $(FETCH_DIR)/openssl-$(OPENSSL_VER)
cd $(FETCH_DIR) && tar -xvzf $(OPENSSL_PACKAGE)
+
+unpack-vidalia:
+ -rm -rf $(FETCH_DIR)/vidalia-$(VIDALIA_VER)
cd $(FETCH_DIR) && tar -xvzf $(VIDALIA_PACKAGE)
+
+unpack-libevent:
+ -rm -rf $(FETCH_DIR)/libevent-$(LIBEVENT_VER)
cd $(FETCH_DIR) && tar -xvzf $(LIBEVENT_PACKAGE)
- cd $(FETCH_DIR) && tar -xvzf $(TOR_PACKAGE)
+unpack-tor:
+ -rm -rf $(FETCH_DIR)/tor-$(TOR-VER)
+ cd $(FETCH_DIR) && tar -xvzf $(TOR_PACKAGE)
+unpack-firefox:
+ -rm -rf $(FETCH_DIR)/mozilla-release
+ cd $(FETCH_DIR) && tar -xvjf $(FIREFOX_PACKAGE)
diff --git a/build-scripts/windows.mk b/build-scripts/windows.mk
index 1836741..da5dda1 100644
--- a/build-scripts/windows.mk
+++ b/build-scripts/windows.mk
@@ -359,7 +359,7 @@ split-bundle_%:
LANGCODE=$* make -f windows.mk split-bundle-localized
bundle-localized_%.stamp:
- make -f windows.mk copy-files_$* install-extensions install-torbutton install-httpseverywhere install-betterprivacy install-noscript patch-vidalia-language patch-firefox-language patch-pidgin-language
+ make -f windows.mk copy-files_$* install-extensions install-torbutton install-httpseverywhere install-noscript patch-vidalia-language patch-firefox-language patch-pidgin-language
touch bundle-localized_$*.stamp
bundle-localized: bundle-localized_$(LANGCODE).stamp
1
0