extensions/cookie/nsPermissionManager.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/Attributes.h"
     7 #include "mozilla/DebugOnly.h"
     9 #include "mozilla/dom/ContentParent.h"
    10 #include "mozilla/dom/ContentChild.h"
    11 #include "mozilla/unused.h"
    12 #include "nsPermissionManager.h"
    13 #include "nsPermission.h"
    14 #include "nsCRT.h"
    15 #include "nsNetUtil.h"
    16 #include "nsCOMArray.h"
    17 #include "nsArrayEnumerator.h"
    18 #include "nsTArray.h"
    19 #include "nsReadableUtils.h"
    20 #include "nsILineInputStream.h"
    21 #include "nsIIDNService.h"
    22 #include "nsAppDirectoryServiceDefs.h"
    23 #include "prprf.h"
    24 #include "mozilla/storage.h"
    25 #include "mozilla/Attributes.h"
    26 #include "nsXULAppAPI.h"
    27 #include "nsIPrincipal.h"
    28 #include "nsContentUtils.h"
    29 #include "nsIScriptSecurityManager.h"
    30 #include "nsIAppsService.h"
    31 #include "mozIApplication.h"
    32 #include "nsIEffectiveTLDService.h"
    33 #include "nsPIDOMWindow.h"
    34 #include "nsIDocument.h"
    35 #include "nsCOMPtr.h"
    36 #include "nsIPrefService.h"
    37 #include "nsIPrefBranch.h"
    38 #include "nsIPrefBranch2.h"
    39 #include "mozilla/net/NeckoMessageUtils.h"
    41 static nsPermissionManager *gPermissionManager = nullptr;
    43 using mozilla::dom::ContentParent;
    44 using mozilla::dom::ContentChild;
    45 using mozilla::unused; // ha!
    47 static bool
    48 IsChildProcess()
    49 {
    50   return XRE_GetProcessType() == GeckoProcessType_Content;
    51 }
    53 /**
    54  * @returns The child process object, or if we are not in the child
    55  *          process, nullptr.
    56  */
    57 static ContentChild*
    58 ChildProcess()
    59 {
    60   if (IsChildProcess()) {
    61     ContentChild* cpc = ContentChild::GetSingleton();
    62     if (!cpc)
    63       NS_RUNTIMEABORT("Content Process is nullptr!");
    64     return cpc;
    65   }
    67   return nullptr;
    68 }
    71 #define ENSURE_NOT_CHILD_PROCESS_(onError) \
    72   PR_BEGIN_MACRO \
    73   if (IsChildProcess()) { \
    74     NS_ERROR("Cannot perform action in content process!"); \
    75     onError \
    76   } \
    77   PR_END_MACRO
    79 #define ENSURE_NOT_CHILD_PROCESS \
    80   ENSURE_NOT_CHILD_PROCESS_({ return NS_ERROR_NOT_AVAILABLE; })
    82 #define ENSURE_NOT_CHILD_PROCESS_NORET \
    83   ENSURE_NOT_CHILD_PROCESS_(;)
    85 ////////////////////////////////////////////////////////////////////////////////
    87 namespace {
    89 nsresult
    90 GetPrincipal(const nsACString& aHost, uint32_t aAppId, bool aIsInBrowserElement,
    91              nsIPrincipal** aPrincipal)
    92 {
    93   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
    94   NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
    96   nsCOMPtr<nsIURI> uri;
    97   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHost);
    98   if (NS_FAILED(rv)) {
    99     // NOTE: most callers will end up here because we don't append "http://" for
   100     // hosts. It's fine to arbitrary use "http://" because, for those entries,
   101     // we will actually just use the host. If we end up here, but the host looks
   102     // like an email address, we use mailto: instead.
   103     nsCString scheme;
   104     if (aHost.FindChar('@') == -1)
   105       scheme = NS_LITERAL_CSTRING("http://");
   106     else
   107       scheme = NS_LITERAL_CSTRING("mailto:");
   108     rv = NS_NewURI(getter_AddRefs(uri), scheme + aHost);
   109     NS_ENSURE_SUCCESS(rv, rv);
   110   }
   112   return secMan->GetAppCodebasePrincipal(uri, aAppId, aIsInBrowserElement, aPrincipal);
   113 }
   115 nsresult
   116 GetPrincipal(nsIURI* aURI, nsIPrincipal** aPrincipal)
   117 {
   118   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   119   NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
   121   return secMan->GetNoAppCodebasePrincipal(aURI, aPrincipal);
   122 }
   124 nsresult
   125 GetPrincipal(const nsACString& aHost, nsIPrincipal** aPrincipal)
   126 {
   127   return GetPrincipal(aHost, nsIScriptSecurityManager::NO_APP_ID, false, aPrincipal);
   128 }
   130 nsresult
   131 GetHostForPrincipal(nsIPrincipal* aPrincipal, nsACString& aHost)
   132 {
   133   nsCOMPtr<nsIURI> uri;
   134   nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
   135   NS_ENSURE_SUCCESS(rv, rv);
   137   uri = NS_GetInnermostURI(uri);
   138   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
   140   rv = uri->GetAsciiHost(aHost);
   141   if (NS_SUCCEEDED(rv) && !aHost.IsEmpty()) {
   142     return NS_OK;
   143   }
   145   // For the mailto scheme, we use the path of the URI. We have to chop off the
   146   // query part if one exists, so we eliminate everything after a ?.
   147   bool isMailTo = false;
   148   if (NS_SUCCEEDED(uri->SchemeIs("mailto", &isMailTo)) && isMailTo) {
   149     rv = uri->GetPath(aHost);
   150     NS_ENSURE_SUCCESS(rv, rv);
   152     int32_t spart = aHost.FindChar('?', 0);
   153     if (spart >= 0) {
   154       aHost.Cut(spart, aHost.Length() - spart);
   155     }
   156     return NS_OK;
   157   }
   159   // Some entries like "file://" uses the origin.
   160   rv = aPrincipal->GetOrigin(getter_Copies(aHost));
   161   if (NS_SUCCEEDED(rv) && !aHost.IsEmpty()) {
   162     return NS_OK;
   163   }
   165   return NS_ERROR_UNEXPECTED;
   166 }
   168 nsCString
   169 GetNextSubDomainForHost(const nsACString& aHost)
   170 {
   171   nsCOMPtr<nsIEffectiveTLDService> tldService =
   172     do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
   173   if (!tldService) {
   174     NS_ERROR("Should have a tld service!");
   175     return EmptyCString();
   176   }
   178   nsCString subDomain;
   179   nsresult rv = tldService->GetNextSubDomain(aHost, subDomain);
   180   // We can fail if there is no more subdomain or if the host can't have a
   181   // subdomain.
   182   if (NS_FAILED(rv)) {
   183     return EmptyCString();
   184   }
   186   return subDomain;
   187 }
   189 class AppClearDataObserver MOZ_FINAL : public nsIObserver {
   190 public:
   191   NS_DECL_ISUPPORTS
   193   // nsIObserver implementation.
   194   NS_IMETHODIMP
   195   Observe(nsISupports *aSubject, const char *aTopic, const char16_t *data)
   196   {
   197     MOZ_ASSERT(!nsCRT::strcmp(aTopic, "webapps-clear-data"));
   199     nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
   200       do_QueryInterface(aSubject);
   201     if (!params) {
   202       NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
   203       return NS_ERROR_UNEXPECTED;
   204     }
   206     uint32_t appId;
   207     nsresult rv = params->GetAppId(&appId);
   208     NS_ENSURE_SUCCESS(rv, rv);
   210     bool browserOnly;
   211     rv = params->GetBrowserOnly(&browserOnly);
   212     NS_ENSURE_SUCCESS(rv, rv);
   214     nsCOMPtr<nsIPermissionManager> permManager = do_GetService("@mozilla.org/permissionmanager;1");
   215     return permManager->RemovePermissionsForApp(appId, browserOnly);
   216   }
   217 };
   219 NS_IMPL_ISUPPORTS(AppClearDataObserver, nsIObserver)
   221 static bool
   222 IsExpandedPrincipal(nsIPrincipal* aPrincipal)
   223 {
   224   nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal);
   225   return !!ep;
   226 }
   228 } // anonymous namespace
   230 ////////////////////////////////////////////////////////////////////////////////
   232 nsPermissionManager::PermissionKey::PermissionKey(nsIPrincipal* aPrincipal)
   233 {
   234   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(GetHostForPrincipal(aPrincipal, mHost)));
   235   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aPrincipal->GetAppId(&mAppId)));
   236   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aPrincipal->GetIsInBrowserElement(&mIsInBrowserElement)));
   237 }
   239 /**
   240  * Simple callback used by |AsyncClose| to trigger a treatment once
   241  * the database is closed.
   242  *
   243  * Note: Beware that, if you hold onto a |CloseDatabaseListener| from a
   244  * |nsPermissionManager|, this will create a cycle.
   245  *
   246  * Note: Once the callback has been called this DeleteFromMozHostListener cannot
   247  * be reused.
   248  */
   249 class CloseDatabaseListener MOZ_FINAL : public mozIStorageCompletionCallback
   250 {
   251 public:
   252   NS_DECL_ISUPPORTS
   253   NS_DECL_MOZISTORAGECOMPLETIONCALLBACK
   254   /**
   255    * @param aManager The owning manager.
   256    * @param aRebuildOnSuccess If |true|, reinitialize the database once
   257    * it has been closed. Otherwise, do nothing such.
   258    */
   259   CloseDatabaseListener(nsPermissionManager* aManager,
   260                         bool aRebuildOnSuccess);
   262 protected:
   263   nsRefPtr<nsPermissionManager> mManager;
   264   bool mRebuildOnSuccess;
   265 };
   267 NS_IMPL_ISUPPORTS(CloseDatabaseListener, mozIStorageCompletionCallback)
   269 CloseDatabaseListener::CloseDatabaseListener(nsPermissionManager* aManager,
   270                                              bool aRebuildOnSuccess)
   271   : mManager(aManager)
   272   , mRebuildOnSuccess(aRebuildOnSuccess)
   273 {
   274 }
   276 NS_IMETHODIMP
   277 CloseDatabaseListener::Complete(nsresult, nsISupports*)
   278 {
   279   // Help breaking cycles
   280   nsRefPtr<nsPermissionManager> manager = mManager.forget();
   281   if (mRebuildOnSuccess && !manager->mIsShuttingDown) {
   282     return manager->InitDB(true);
   283   }
   284   return NS_OK;
   285 }
   288 /**
   289  * Simple callback used by |RemoveAllInternal| to trigger closing
   290  * the database and reinitializing it.
   291  *
   292  * Note: Beware that, if you hold onto a |DeleteFromMozHostListener| from a
   293  * |nsPermissionManager|, this will create a cycle.
   294  *
   295  * Note: Once the callback has been called this DeleteFromMozHostListener cannot
   296  * be reused.
   297  */
   298 class DeleteFromMozHostListener MOZ_FINAL : public mozIStorageStatementCallback
   299 {
   300 public:
   301   NS_DECL_ISUPPORTS
   302   NS_DECL_MOZISTORAGESTATEMENTCALLBACK
   304   /**
   305    * @param aManager The owning manager.
   306    */
   307   DeleteFromMozHostListener(nsPermissionManager* aManager);
   309 protected:
   310   nsRefPtr<nsPermissionManager> mManager;
   311 };
   313 NS_IMPL_ISUPPORTS(DeleteFromMozHostListener, mozIStorageStatementCallback)
   315 DeleteFromMozHostListener::
   316 DeleteFromMozHostListener(nsPermissionManager* aManager)
   317   : mManager(aManager)
   318 {
   319 }
   321 NS_IMETHODIMP DeleteFromMozHostListener::HandleResult(mozIStorageResultSet *)
   322 {
   323   MOZ_CRASH("Should not get any results");
   324 }
   326 NS_IMETHODIMP DeleteFromMozHostListener::HandleError(mozIStorageError *)
   327 {
   328   // Errors are handled in |HandleCompletion|
   329   return NS_OK;
   330 }
   332 NS_IMETHODIMP DeleteFromMozHostListener::HandleCompletion(uint16_t aReason)
   333 {
   334   // Help breaking cycles
   335   nsRefPtr<nsPermissionManager> manager = mManager.forget();
   337   if (aReason == REASON_ERROR) {
   338     manager->CloseDB(true);
   339   }
   341   return NS_OK;
   342 }
   344 /* static */ void
   345 nsPermissionManager::AppClearDataObserverInit()
   346 {
   347   nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
   348   observerService->AddObserver(new AppClearDataObserver(), "webapps-clear-data", /* holdsWeak= */ false);
   349 }
   351 ////////////////////////////////////////////////////////////////////////////////
   352 // nsPermissionManager Implementation
   354 static const char kPermissionsFileName[] = "permissions.sqlite";
   355 #define HOSTS_SCHEMA_VERSION 3
   357 static const char kHostpermFileName[] = "hostperm.1";
   359 static const char kPermissionChangeNotification[] = PERM_CHANGE_NOTIFICATION;
   361 NS_IMPL_ISUPPORTS(nsPermissionManager, nsIPermissionManager, nsIObserver, nsISupportsWeakReference)
   363 nsPermissionManager::nsPermissionManager()
   364  : mLargestID(0)
   365  , mIsShuttingDown(false)
   366 {
   367 }
   369 nsPermissionManager::~nsPermissionManager()
   370 {
   371   RemoveAllFromMemory();
   372   gPermissionManager = nullptr;
   373 }
   375 // static
   376 nsIPermissionManager*
   377 nsPermissionManager::GetXPCOMSingleton()
   378 {
   379   if (gPermissionManager) {
   380     NS_ADDREF(gPermissionManager);
   381     return gPermissionManager;
   382   }
   384   // Create a new singleton nsPermissionManager.
   385   // We AddRef only once since XPCOM has rules about the ordering of module
   386   // teardowns - by the time our module destructor is called, it's too late to
   387   // Release our members, since GC cycles have already been completed and
   388   // would result in serious leaks.
   389   // See bug 209571.
   390   gPermissionManager = new nsPermissionManager();
   391   if (gPermissionManager) {
   392     NS_ADDREF(gPermissionManager);
   393     if (NS_FAILED(gPermissionManager->Init())) {
   394       NS_RELEASE(gPermissionManager);
   395     }
   396   }
   398   return gPermissionManager;
   399 }
   401 nsresult
   402 nsPermissionManager::Init()
   403 {
   404   nsresult rv;
   406   mObserverService = do_GetService("@mozilla.org/observer-service;1", &rv);
   407   if (NS_SUCCEEDED(rv)) {
   408     mObserverService->AddObserver(this, "profile-before-change", true);
   409     mObserverService->AddObserver(this, "profile-do-change", true);
   410   }
   413   nsCOMPtr<nsIPrefBranch2> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
   414   if (pbi) {
   415     pbi->AddObserver("permissions.", this, PR_FALSE);
   416   }
   418   if (IsChildProcess()) {
   419     // Get the permissions from the parent process
   420     InfallibleTArray<IPC::Permission> perms;
   421     ChildProcess()->SendReadPermissions(&perms);
   423     for (uint32_t i = 0; i < perms.Length(); i++) {
   424       const IPC::Permission &perm = perms[i];
   426       nsCOMPtr<nsIPrincipal> principal;
   427       rv = GetPrincipal(perm.host, perm.appId, perm.isInBrowserElement, getter_AddRefs(principal));
   428       NS_ENSURE_SUCCESS(rv, rv);
   430       AddInternal(principal, perm.type, perm.capability, 0, perm.expireType,
   431                   perm.expireTime, eNotify, eNoDBOperation);
   432     }
   434     // Stop here; we don't need the DB in the child process
   435     return NS_OK;
   436   }
   438   // ignore failure here, since it's non-fatal (we can run fine without
   439   // persistent storage - e.g. if there's no profile).
   440   // XXX should we tell the user about this?
   441   InitDB(false);
   443   return NS_OK;
   444 }
   446 nsresult
   447 nsPermissionManager::InitDB(bool aRemoveFile)
   448 {
   449   nsCOMPtr<nsIFile> permissionsFile;
   450   nsresult rv = NS_GetSpecialDirectory(NS_APP_PERMISSION_PARENT_DIR, getter_AddRefs(permissionsFile));
   451   if (NS_FAILED(rv)) {
   452     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(permissionsFile));
   453   }
   454   NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
   456   rv = permissionsFile->AppendNative(NS_LITERAL_CSTRING(kPermissionsFileName));
   457   NS_ENSURE_SUCCESS(rv, rv);
   459   if (aRemoveFile) {
   460     bool exists = false;
   461     rv = permissionsFile->Exists(&exists);
   462     NS_ENSURE_SUCCESS(rv, rv);
   463     if (exists) {
   464       rv = permissionsFile->Remove(false);
   465       NS_ENSURE_SUCCESS(rv, rv);
   466     }
   467   }
   469   nsCOMPtr<mozIStorageService> storage = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
   470   if (!storage)
   471     return NS_ERROR_UNEXPECTED;
   473   bool memory_db = false;
   474   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   475   if (prefs) {
   476     prefs->GetBoolPref("permissions.memory_only", &memory_db); 
   477   }
   479   // cache a connection to the hosts database
   480   if (memory_db) {
   481     rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
   482   } else {
   483     rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
   484   }
   485   NS_ENSURE_SUCCESS(rv, rv);
   487   bool ready;
   488   mDBConn->GetConnectionReady(&ready);
   489   if (!ready) {
   490     // delete and try again
   491     rv = permissionsFile->Remove(false);
   492     NS_ENSURE_SUCCESS(rv, rv);
   494     if (memory_db) {
   495       rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
   496     } else {
   497       rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
   498     }
   499     NS_ENSURE_SUCCESS(rv, rv);
   501     mDBConn->GetConnectionReady(&ready);
   502     if (!ready)
   503       return NS_ERROR_UNEXPECTED;
   504   }
   506   bool tableExists = false;
   507   mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), &tableExists);
   508   if (!tableExists) {
   509     rv = CreateTable();
   510     NS_ENSURE_SUCCESS(rv, rv);
   512   } else {
   513     // table already exists; check the schema version before reading
   514     int32_t dbSchemaVersion;
   515     rv = mDBConn->GetSchemaVersion(&dbSchemaVersion);
   516     NS_ENSURE_SUCCESS(rv, rv);
   518     switch (dbSchemaVersion) {
   519     // upgrading.
   520     // every time you increment the database schema, you need to implement
   521     // the upgrading code from the previous version to the new one.
   522     // fall through to current version
   524     case 1:
   525       {
   526         // previous non-expiry version of database.  Upgrade it by adding the
   527         // expiration columns
   528         rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   529               "ALTER TABLE moz_hosts ADD expireType INTEGER"));
   530         NS_ENSURE_SUCCESS(rv, rv);
   532         rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   533               "ALTER TABLE moz_hosts ADD expireTime INTEGER"));
   534         NS_ENSURE_SUCCESS(rv, rv);
   535       }
   537       // fall through to the next upgrade
   539     // TODO: we want to make default version as version 2 in order to fix bug 784875.
   540     case 0:
   541     case 2:
   542       {
   543         // Add appId/isInBrowserElement fields.
   544         rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   545               "ALTER TABLE moz_hosts ADD appId INTEGER"));
   546         NS_ENSURE_SUCCESS(rv, rv);
   548         rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   549               "ALTER TABLE moz_hosts ADD isInBrowserElement INTEGER"));
   550         NS_ENSURE_SUCCESS(rv, rv);
   552         rv = mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION);
   553         NS_ENSURE_SUCCESS(rv, rv);
   554       }
   556       // fall through to the next upgrade
   558     // current version.
   559     case HOSTS_SCHEMA_VERSION:
   560       break;
   562     // downgrading.
   563     // if columns have been added to the table, we can still use the ones we
   564     // understand safely. if columns have been deleted or altered, just
   565     // blow away the table and start from scratch! if you change the way
   566     // a column is interpreted, make sure you also change its name so this
   567     // check will catch it.
   568     default:
   569       {
   570         // check if all the expected columns exist
   571         nsCOMPtr<mozIStorageStatement> stmt;
   572         rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
   573           "SELECT host, type, permission, expireType, expireTime, appId, isInBrowserElement FROM moz_hosts"),
   574           getter_AddRefs(stmt));
   575         if (NS_SUCCEEDED(rv))
   576           break;
   578         // our columns aren't there - drop the table!
   579         rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE moz_hosts"));
   580         NS_ENSURE_SUCCESS(rv, rv);
   582         rv = CreateTable();
   583         NS_ENSURE_SUCCESS(rv, rv);
   584       }
   585       break;
   586     }
   587   }
   589   // make operations on the table asynchronous, for performance
   590   mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA synchronous = OFF"));
   592   // cache frequently used statements (for insertion, deletion, and updating)
   593   rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
   594     "INSERT INTO moz_hosts "
   595     "(id, host, type, permission, expireType, expireTime, appId, isInBrowserElement) "
   596     "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)"), getter_AddRefs(mStmtInsert));
   597   NS_ENSURE_SUCCESS(rv, rv);
   599   rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
   600     "DELETE FROM moz_hosts "
   601     "WHERE id = ?1"), getter_AddRefs(mStmtDelete));
   602   NS_ENSURE_SUCCESS(rv, rv);
   604   rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
   605     "UPDATE moz_hosts "
   606     "SET permission = ?2, expireType= ?3, expireTime = ?4 WHERE id = ?1"),
   607     getter_AddRefs(mStmtUpdate));
   608   NS_ENSURE_SUCCESS(rv, rv);
   610   // check whether to import or just read in the db
   611   if (tableExists)
   612     return Read();
   614   return Import();
   615 }
   617 // sets the schema version and creates the moz_hosts table.
   618 nsresult
   619 nsPermissionManager::CreateTable()
   620 {
   621   // set the schema version, before creating the table
   622   nsresult rv = mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION);
   623   if (NS_FAILED(rv)) return rv;
   625   // create the table
   626   // SQL also lives in automation.py.in. If you change this SQL change that
   627   // one too.
   628   return mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   629     "CREATE TABLE moz_hosts ("
   630       " id INTEGER PRIMARY KEY"
   631       ",host TEXT"
   632       ",type TEXT"
   633       ",permission INTEGER"
   634       ",expireType INTEGER"
   635       ",expireTime INTEGER"
   636       ",appId INTEGER"
   637       ",isInBrowserElement INTEGER"
   638     ")"));
   639 }
   641 NS_IMETHODIMP
   642 nsPermissionManager::Add(nsIURI     *aURI,
   643                          const char *aType,
   644                          uint32_t    aPermission,
   645                          uint32_t    aExpireType,
   646                          int64_t     aExpireTime)
   647 {
   648   NS_ENSURE_ARG_POINTER(aURI);
   650   nsCOMPtr<nsIPrincipal> principal;
   651   nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal));
   652   NS_ENSURE_SUCCESS(rv, rv);
   654   return AddFromPrincipal(principal, aType, aPermission, aExpireType, aExpireTime);
   655 }
   657 NS_IMETHODIMP
   658 nsPermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal,
   659                                       const char* aType, uint32_t aPermission,
   660                                       uint32_t aExpireType, int64_t aExpireTime)
   661 {
   662   ENSURE_NOT_CHILD_PROCESS;
   663   NS_ENSURE_ARG_POINTER(aPrincipal);
   664   NS_ENSURE_ARG_POINTER(aType);
   665   NS_ENSURE_TRUE(aExpireType == nsIPermissionManager::EXPIRE_NEVER ||
   666                  aExpireType == nsIPermissionManager::EXPIRE_TIME ||
   667                  aExpireType == nsIPermissionManager::EXPIRE_SESSION,
   668                  NS_ERROR_INVALID_ARG);
   670   // Skip addition if the permission is already expired. Note that EXPIRE_SESSION only
   671   // honors expireTime if it is nonzero.
   672   if ((aExpireType == nsIPermissionManager::EXPIRE_TIME ||
   673        (aExpireType == nsIPermissionManager::EXPIRE_SESSION && aExpireTime != 0)) &&
   674       aExpireTime <= (PR_Now() / 1000)) {
   675     return NS_OK;
   676   }
   678   // We don't add the system principal because it actually has no URI and we
   679   // always allow action for them.
   680   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
   681     return NS_OK;
   682   }
   684   // Permissions may not be added to expanded principals.
   685   if (IsExpandedPrincipal(aPrincipal)) {
   686     return NS_ERROR_INVALID_ARG;
   687   }
   689   return AddInternal(aPrincipal, nsDependentCString(aType), aPermission, 0,
   690                      aExpireType, aExpireTime, eNotify, eWriteToDB);
   691 }
   693 nsresult
   694 nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
   695                                  const nsAFlatCString &aType,
   696                                  uint32_t              aPermission,
   697                                  int64_t               aID,
   698                                  uint32_t              aExpireType,
   699                                  int64_t               aExpireTime,
   700                                  NotifyOperationType   aNotifyOperation,
   701                                  DBOperationType       aDBOperation)
   702 {
   703   nsAutoCString host;
   704   nsresult rv = GetHostForPrincipal(aPrincipal, host);
   705   NS_ENSURE_SUCCESS(rv, rv);
   707   if (!IsChildProcess()) {
   708     uint32_t appId;
   709     rv = aPrincipal->GetAppId(&appId);
   710     NS_ENSURE_SUCCESS(rv, rv);
   712     bool isInBrowserElement;
   713     rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
   714     NS_ENSURE_SUCCESS(rv, rv);
   716     IPC::Permission permission(host, appId, isInBrowserElement, aType,
   717                                aPermission, aExpireType, aExpireTime);
   719     nsTArray<ContentParent*> cplist;
   720     ContentParent::GetAll(cplist);
   721     for (uint32_t i = 0; i < cplist.Length(); ++i) {
   722       ContentParent* cp = cplist[i];
   723       if (cp->NeedsPermissionsUpdate())
   724         unused << cp->SendAddPermission(permission);
   725     }
   726   }
   728   // look up the type index
   729   int32_t typeIndex = GetTypeIndex(aType.get(), true);
   730   NS_ENSURE_TRUE(typeIndex != -1, NS_ERROR_OUT_OF_MEMORY);
   732   // When an entry already exists, PutEntry will return that, instead
   733   // of adding a new one
   734   nsRefPtr<PermissionKey> key = new PermissionKey(aPrincipal);
   735   PermissionHashKey* entry = mPermissionTable.PutEntry(key);
   736   if (!entry) return NS_ERROR_FAILURE;
   737   if (!entry->GetKey()) {
   738     mPermissionTable.RawRemoveEntry(entry);
   739     return NS_ERROR_OUT_OF_MEMORY;
   740   }
   742   // figure out the transaction type, and get any existing permission value
   743   OperationType op;
   744   int32_t index = entry->GetPermissionIndex(typeIndex);
   745   if (index == -1) {
   746     if (aPermission == nsIPermissionManager::UNKNOWN_ACTION)
   747       op = eOperationNone;
   748     else
   749       op = eOperationAdding;
   751   } else {
   752     PermissionEntry oldPermissionEntry = entry->GetPermissions()[index];
   754     // remove the permission if the permission is UNKNOWN, update the
   755     // permission if its value or expire type have changed OR if the time has
   756     // changed and the expire type is time, otherwise, don't modify.  There's
   757     // no need to modify a permission that doesn't expire with time when the
   758     // only thing changed is the expire time.
   759     if (aPermission == oldPermissionEntry.mPermission &&
   760         aExpireType == oldPermissionEntry.mExpireType &&
   761         (aExpireType == nsIPermissionManager::EXPIRE_NEVER ||
   762          aExpireTime == oldPermissionEntry.mExpireTime))
   763       op = eOperationNone;
   764     else if (aPermission == nsIPermissionManager::UNKNOWN_ACTION)
   765       op = eOperationRemoving;
   766     else
   767       op = eOperationChanging;
   768   }
   770   // do the work for adding, deleting, or changing a permission:
   771   // update the in-memory list, write to the db, and notify consumers.
   772   int64_t id;
   773   switch (op) {
   774   case eOperationNone:
   775     {
   776       // nothing to do
   777       return NS_OK;
   778     }
   780   case eOperationAdding:
   781     {
   782       if (aDBOperation == eWriteToDB) {
   783         // we'll be writing to the database - generate a known unique id
   784         id = ++mLargestID;
   785       } else {
   786         // we're reading from the database - use the id already assigned
   787         id = aID;
   788       }
   790       entry->GetPermissions().AppendElement(PermissionEntry(id, typeIndex, aPermission, aExpireType, aExpireTime));
   792       if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION) {
   793         uint32_t appId;
   794         rv = aPrincipal->GetAppId(&appId);
   795         NS_ENSURE_SUCCESS(rv, rv);
   797         bool isInBrowserElement;
   798         rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
   799         NS_ENSURE_SUCCESS(rv, rv);
   801         UpdateDB(op, mStmtInsert, id, host, aType, aPermission, aExpireType, aExpireTime, appId, isInBrowserElement);
   802       }
   804       if (aNotifyOperation == eNotify) {
   805         NotifyObserversWithPermission(host,
   806                                       entry->GetKey()->mAppId,
   807                                       entry->GetKey()->mIsInBrowserElement,
   808                                       mTypeArray[typeIndex],
   809                                       aPermission,
   810                                       aExpireType,
   811                                       aExpireTime,
   812                                       MOZ_UTF16("added"));
   813       }
   815       break;
   816     }
   818   case eOperationRemoving:
   819     {
   820       PermissionEntry oldPermissionEntry = entry->GetPermissions()[index];
   821       id = oldPermissionEntry.mID;
   822       entry->GetPermissions().RemoveElementAt(index);
   824       if (aDBOperation == eWriteToDB)
   825         // We care only about the id here so we pass dummy values for all other
   826         // parameters.
   827         UpdateDB(op, mStmtDelete, id, EmptyCString(), EmptyCString(), 0,
   828                  nsIPermissionManager::EXPIRE_NEVER, 0, 0, false);
   830       if (aNotifyOperation == eNotify) {
   831         NotifyObserversWithPermission(host,
   832                                       entry->GetKey()->mAppId,
   833                                       entry->GetKey()->mIsInBrowserElement,
   834                                       mTypeArray[typeIndex],
   835                                       oldPermissionEntry.mPermission,
   836                                       oldPermissionEntry.mExpireType,
   837                                       oldPermissionEntry.mExpireTime,
   838                                       MOZ_UTF16("deleted"));
   839       }
   841       // If there are no more permissions stored for that entry, clear it.
   842       if (entry->GetPermissions().IsEmpty()) {
   843         mPermissionTable.RawRemoveEntry(entry);
   844       }
   846       break;
   847     }
   849   case eOperationChanging:
   850     {
   851       id = entry->GetPermissions()[index].mID;
   853       // If the new expireType is EXPIRE_SESSION, then we have to keep a
   854       // copy of the previous permission/expireType values. This cached value will be
   855       // used when restoring the permissions of an app.
   856       if (entry->GetPermissions()[index].mExpireType != nsIPermissionManager::EXPIRE_SESSION &&
   857           aExpireType == nsIPermissionManager::EXPIRE_SESSION) {
   858         entry->GetPermissions()[index].mNonSessionPermission = entry->GetPermissions()[index].mPermission;
   859         entry->GetPermissions()[index].mNonSessionExpireType = entry->GetPermissions()[index].mExpireType;
   860         entry->GetPermissions()[index].mNonSessionExpireTime = entry->GetPermissions()[index].mExpireTime;
   861       } else if (aExpireType != nsIPermissionManager::EXPIRE_SESSION) {
   862         entry->GetPermissions()[index].mNonSessionPermission = aPermission;
   863         entry->GetPermissions()[index].mNonSessionExpireType = aExpireType;
   864         entry->GetPermissions()[index].mNonSessionExpireTime = aExpireTime;
   865       }
   867       entry->GetPermissions()[index].mPermission = aPermission;
   868       entry->GetPermissions()[index].mExpireType = aExpireType;
   869       entry->GetPermissions()[index].mExpireTime = aExpireTime;
   871       if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION)
   872         // We care only about the id, the permission and expireType/expireTime here.
   873         // We pass dummy values for all other parameters.
   874         UpdateDB(op, mStmtUpdate, id, EmptyCString(), EmptyCString(),
   875                  aPermission, aExpireType, aExpireTime, 0, false);
   877       if (aNotifyOperation == eNotify) {
   878         NotifyObserversWithPermission(host,
   879                                       entry->GetKey()->mAppId,
   880                                       entry->GetKey()->mIsInBrowserElement,
   881                                       mTypeArray[typeIndex],
   882                                       aPermission,
   883                                       aExpireType,
   884                                       aExpireTime,
   885                                       MOZ_UTF16("changed"));
   886       }
   888       break;
   889     }
   890   }
   892   return NS_OK;
   893 }
   895 NS_IMETHODIMP
   896 nsPermissionManager::Remove(const nsACString &aHost,
   897                             const char       *aType)
   898 {
   899   nsCOMPtr<nsIPrincipal> principal;
   900   nsresult rv = GetPrincipal(aHost, getter_AddRefs(principal));
   901   NS_ENSURE_SUCCESS(rv, rv);
   903   return RemoveFromPrincipal(principal, aType);
   904 }
   906 NS_IMETHODIMP
   907 nsPermissionManager::RemoveFromPrincipal(nsIPrincipal* aPrincipal,
   908                                          const char* aType)
   909 {
   910   ENSURE_NOT_CHILD_PROCESS;
   911   NS_ENSURE_ARG_POINTER(aPrincipal);
   912   NS_ENSURE_ARG_POINTER(aType);
   914   // System principals are never added to the database, no need to remove them.
   915   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
   916     return NS_OK;
   917   }
   919   // Permissions may not be added to expanded principals.
   920   if (IsExpandedPrincipal(aPrincipal)) {
   921     return NS_ERROR_INVALID_ARG;
   922   }
   924   // AddInternal() handles removal, just let it do the work
   925   return AddInternal(aPrincipal,
   926                      nsDependentCString(aType),
   927                      nsIPermissionManager::UNKNOWN_ACTION,
   928                      0,
   929                      nsIPermissionManager::EXPIRE_NEVER,
   930                      0,
   931                      eNotify,
   932                      eWriteToDB);
   933 }
   935 NS_IMETHODIMP
   936 nsPermissionManager::RemoveAll()
   937 {
   938   ENSURE_NOT_CHILD_PROCESS;
   939   return RemoveAllInternal(true);
   940 }
   942 void
   943 nsPermissionManager::CloseDB(bool aRebuildOnSuccess)
   944 {
   945   // Null the statements, this will finalize them.
   946   mStmtInsert = nullptr;
   947   mStmtDelete = nullptr;
   948   mStmtUpdate = nullptr;
   949   if (mDBConn) {
   950     mozIStorageCompletionCallback* cb = new CloseDatabaseListener(this,
   951            aRebuildOnSuccess);
   952     mozilla::DebugOnly<nsresult> rv = mDBConn->AsyncClose(cb);
   953     MOZ_ASSERT(NS_SUCCEEDED(rv));
   954     mDBConn = nullptr; // Avoid race conditions
   955   }
   956 }
   958 nsresult
   959 nsPermissionManager::RemoveAllInternal(bool aNotifyObservers)
   960 {
   961   // Remove from memory and notify immediately. Since the in-memory
   962   // database is authoritative, we do not need confirmation from the
   963   // on-disk database to notify observers.
   964   RemoveAllFromMemory();
   965   if (aNotifyObservers) {
   966     NotifyObservers(nullptr, MOZ_UTF16("cleared"));
   967   }
   969   // clear the db
   970   if (mDBConn) {
   971     nsCOMPtr<mozIStorageAsyncStatement> removeStmt;
   972     nsresult rv = mDBConn->
   973       CreateAsyncStatement(NS_LITERAL_CSTRING(
   974          "DELETE FROM moz_hosts"
   975       ), getter_AddRefs(removeStmt));
   976     MOZ_ASSERT(NS_SUCCEEDED(rv));
   977     if (!removeStmt) {
   978       return NS_ERROR_UNEXPECTED;
   979     }
   980     nsCOMPtr<mozIStoragePendingStatement> pending;
   981     mozIStorageStatementCallback* cb = new DeleteFromMozHostListener(this);
   982     rv = removeStmt->ExecuteAsync(cb, getter_AddRefs(pending));
   983     MOZ_ASSERT(NS_SUCCEEDED(rv));
   985     return rv;
   986   }
   988   return NS_OK;
   989 }
   991 NS_IMETHODIMP
   992 nsPermissionManager::TestExactPermission(nsIURI     *aURI,
   993                                          const char *aType,
   994                                          uint32_t   *aPermission)
   995 {
   996   nsCOMPtr<nsIPrincipal> principal;
   997   nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal));
   998   NS_ENSURE_SUCCESS(rv, rv);
  1000   return TestExactPermissionFromPrincipal(principal, aType, aPermission);
  1003 NS_IMETHODIMP
  1004 nsPermissionManager::TestExactPermissionFromPrincipal(nsIPrincipal* aPrincipal,
  1005                                                       const char* aType,
  1006                                                       uint32_t* aPermission)
  1008   return CommonTestPermission(aPrincipal, aType, aPermission, true, true);
  1011 NS_IMETHODIMP
  1012 nsPermissionManager::TestExactPermanentPermission(nsIPrincipal* aPrincipal,
  1013                                                   const char* aType,
  1014                                                   uint32_t* aPermission)
  1016   return CommonTestPermission(aPrincipal, aType, aPermission, true, false);
  1019 NS_IMETHODIMP
  1020 nsPermissionManager::TestPermission(nsIURI     *aURI,
  1021                                     const char *aType,
  1022                                     uint32_t   *aPermission)
  1024   nsCOMPtr<nsIPrincipal> principal;
  1025   nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal));
  1026   NS_ENSURE_SUCCESS(rv, rv);
  1028   return TestPermissionFromPrincipal(principal, aType, aPermission);
  1031 NS_IMETHODIMP
  1032 nsPermissionManager::TestPermissionFromWindow(nsIDOMWindow* aWindow,
  1033                                               const char* aType,
  1034                                               uint32_t* aPermission)
  1036   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
  1037   NS_ENSURE_TRUE(window, NS_NOINTERFACE);
  1039   nsPIDOMWindow* innerWindow = window->IsInnerWindow() ?
  1040     window.get() :
  1041     window->GetCurrentInnerWindow();
  1043   // Get the document for security check
  1044   nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
  1045   NS_ENSURE_TRUE(document, NS_NOINTERFACE);
  1047   nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
  1048   return TestPermissionFromPrincipal(principal, aType, aPermission);
  1051 NS_IMETHODIMP
  1052 nsPermissionManager::TestPermissionFromPrincipal(nsIPrincipal* aPrincipal,
  1053                                                  const char* aType,
  1054                                                  uint32_t* aPermission)
  1056   return CommonTestPermission(aPrincipal, aType, aPermission, false, true);
  1059 NS_IMETHODIMP
  1060 nsPermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal,
  1061                                          const char* aType,
  1062                                          bool aExactHostMatch,
  1063                                          nsIPermission** aResult)
  1065   NS_ENSURE_ARG_POINTER(aPrincipal);
  1066   NS_ENSURE_ARG_POINTER(aType);
  1068   *aResult = nullptr;
  1070   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
  1071     return NS_OK;
  1074   // Querying the permission object of an nsEP is non-sensical.
  1075   if (IsExpandedPrincipal(aPrincipal)) {
  1076     return NS_ERROR_INVALID_ARG;
  1079   nsAutoCString host;
  1080   nsresult rv = GetHostForPrincipal(aPrincipal, host);
  1081   NS_ENSURE_SUCCESS(rv, rv);
  1083   int32_t typeIndex = GetTypeIndex(aType, false);
  1084   // If type == -1, the type isn't known,
  1085   // so just return NS_OK
  1086   if (typeIndex == -1) return NS_OK;
  1088   uint32_t appId;
  1089   rv = aPrincipal->GetAppId(&appId);
  1090   NS_ENSURE_SUCCESS(rv, rv);
  1092   bool isInBrowserElement;
  1093   rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
  1094   NS_ENSURE_SUCCESS(rv, rv);
  1096   PermissionHashKey* entry = GetPermissionHashKey(host, appId, isInBrowserElement,
  1097                                                   typeIndex, aExactHostMatch);
  1098   if (!entry) {
  1099     return NS_OK;
  1102   // We don't call GetPermission(typeIndex) because that returns a fake
  1103   // UNKNOWN_ACTION entry if there is no match.
  1104   int32_t idx = entry->GetPermissionIndex(typeIndex);
  1105   if (-1 == idx) {
  1106     return NS_OK;
  1109   PermissionEntry& perm = entry->GetPermissions()[idx];
  1110   nsCOMPtr<nsIPermission> r = new nsPermission(entry->GetKey()->mHost,
  1111                                                entry->GetKey()->mAppId,
  1112                                                entry->GetKey()->mIsInBrowserElement,
  1113                                                mTypeArray.ElementAt(perm.mType),
  1114                                                perm.mPermission,
  1115                                                perm.mExpireType,
  1116                                                perm.mExpireTime);
  1117   r.forget(aResult);
  1118   return NS_OK;
  1121 nsresult
  1122 nsPermissionManager::CommonTestPermission(nsIPrincipal* aPrincipal,
  1123                                           const char *aType,
  1124                                           uint32_t   *aPermission,
  1125                                           bool        aExactHostMatch,
  1126                                           bool        aIncludingSession)
  1128   NS_ENSURE_ARG_POINTER(aPrincipal);
  1129   NS_ENSURE_ARG_POINTER(aType);
  1131   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
  1132     *aPermission = nsIPermissionManager::ALLOW_ACTION;
  1133     return NS_OK;
  1136   // Set the default.
  1137   *aPermission = nsIPermissionManager::UNKNOWN_ACTION;
  1139   // For expanded principals, we want to iterate over the whitelist and see
  1140   // if the permission is granted for any of them.
  1141   nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal);
  1142   if (ep) {
  1143     nsTArray<nsCOMPtr<nsIPrincipal>>* whitelist;
  1144     nsresult rv = ep->GetWhiteList(&whitelist);
  1145     NS_ENSURE_SUCCESS(rv, rv);
  1147     for (size_t i = 0; i < whitelist->Length(); ++i) {
  1148       uint32_t perm;
  1149       rv = CommonTestPermission(whitelist->ElementAt(i), aType, &perm, aExactHostMatch,
  1150                                 aIncludingSession);
  1151       NS_ENSURE_SUCCESS(rv, rv);
  1152       if (perm == nsIPermissionManager::ALLOW_ACTION) {
  1153         *aPermission = perm;
  1154         return NS_OK;
  1155       } else if (perm == nsIPermissionManager::PROMPT_ACTION) {
  1156         // Store it, but keep going to see if we can do better.
  1157         *aPermission = perm;
  1161     return NS_OK;
  1164   nsAutoCString host;
  1165   nsresult rv = GetHostForPrincipal(aPrincipal, host);
  1166   NS_ENSURE_SUCCESS(rv, rv);
  1168   int32_t typeIndex = GetTypeIndex(aType, false);
  1169   // If type == -1, the type isn't known,
  1170   // so just return NS_OK
  1171   if (typeIndex == -1) return NS_OK;
  1173   uint32_t appId;
  1174   rv = aPrincipal->GetAppId(&appId);
  1175   NS_ENSURE_SUCCESS(rv, rv);
  1177   bool isInBrowserElement;
  1178   rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
  1179   NS_ENSURE_SUCCESS(rv, rv);
  1181   PermissionHashKey* entry = GetPermissionHashKey(host, appId, isInBrowserElement,
  1182                                                   typeIndex, aExactHostMatch);
  1183   if (!entry ||
  1184       (!aIncludingSession &&
  1185        entry->GetPermission(typeIndex).mNonSessionExpireType ==
  1186          nsIPermissionManager::EXPIRE_SESSION)) {
  1187     return NS_OK;
  1190   *aPermission = aIncludingSession
  1191                    ? entry->GetPermission(typeIndex).mPermission
  1192                    : entry->GetPermission(typeIndex).mNonSessionPermission;
  1194   return NS_OK;
  1197 // Returns PermissionHashKey for a given { host, appId, isInBrowserElement } tuple.
  1198 // This is not simply using PermissionKey because we will walk-up domains in
  1199 // case of |host| contains sub-domains.
  1200 // Returns null if nothing found.
  1201 // Also accepts host on the format "<foo>". This will perform an exact match
  1202 // lookup as the string doesn't contain any dots.
  1203 nsPermissionManager::PermissionHashKey*
  1204 nsPermissionManager::GetPermissionHashKey(const nsACString& aHost,
  1205                                           uint32_t aAppId,
  1206                                           bool aIsInBrowserElement,
  1207                                           uint32_t aType,
  1208                                           bool aExactHostMatch)
  1210   PermissionHashKey* entry = nullptr;
  1212   nsRefPtr<PermissionKey> key = new PermissionKey(aHost, aAppId, aIsInBrowserElement);
  1213   entry = mPermissionTable.GetEntry(key);
  1215   if (entry) {
  1216     PermissionEntry permEntry = entry->GetPermission(aType);
  1218     // if the entry is expired, remove and keep looking for others.
  1219     // Note that EXPIRE_SESSION only honors expireTime if it is nonzero.
  1220     if ((permEntry.mExpireType == nsIPermissionManager::EXPIRE_TIME ||
  1221          (permEntry.mExpireType == nsIPermissionManager::EXPIRE_SESSION &&
  1222           permEntry.mExpireTime != 0)) &&
  1223         permEntry.mExpireTime <= (PR_Now() / 1000)) {
  1224       nsCOMPtr<nsIPrincipal> principal;
  1225       if (NS_FAILED(GetPrincipal(aHost, aAppId, aIsInBrowserElement, getter_AddRefs(principal)))) {
  1226         return nullptr;
  1229       entry = nullptr;
  1230       RemoveFromPrincipal(principal, mTypeArray[aType].get());
  1231     } else if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) {
  1232       entry = nullptr;
  1236   if (entry) {
  1237     return entry;
  1240   // If we haven't found an entry, depending on the host, we could try a bit
  1241   // harder.
  1242   // If this is a file:// URI, we can check for the presence of the magic entry
  1243   // <file> which gives permission to all file://. This hack might disappear,
  1244   // see bug 817007. Note that we don't require aExactHostMatch to be true for
  1245   // that to keep retro-compatibility.
  1246   // If this is not a file:// URI, and that aExactHostMatch wasn't true, we can
  1247   // check if the base domain has a permission entry.
  1249   if (StringBeginsWith(aHost, NS_LITERAL_CSTRING("file://"))) {
  1250     return GetPermissionHashKey(NS_LITERAL_CSTRING("<file>"), aAppId, aIsInBrowserElement, aType, true);
  1253   if (!aExactHostMatch) {
  1254     nsCString domain = GetNextSubDomainForHost(aHost);
  1255     if (!domain.IsEmpty()) {
  1256       return GetPermissionHashKey(domain, aAppId, aIsInBrowserElement, aType, aExactHostMatch);
  1260   // No entry, really...
  1261   return nullptr;
  1264 // helper struct for passing arguments into hash enumeration callback.
  1265 struct nsGetEnumeratorData
  1267   nsGetEnumeratorData(nsCOMArray<nsIPermission> *aArray, const nsTArray<nsCString> *aTypes)
  1268    : array(aArray)
  1269    , types(aTypes) {}
  1271   nsCOMArray<nsIPermission> *array;
  1272   const nsTArray<nsCString> *types;
  1273 };
  1275 static PLDHashOperator
  1276 AddPermissionsToList(nsPermissionManager::PermissionHashKey* entry, void *arg)
  1278   nsGetEnumeratorData *data = static_cast<nsGetEnumeratorData *>(arg);
  1280   for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
  1281     nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
  1283     nsPermission *perm = new nsPermission(entry->GetKey()->mHost,
  1284                                           entry->GetKey()->mAppId,
  1285                                           entry->GetKey()->mIsInBrowserElement,
  1286                                           data->types->ElementAt(permEntry.mType),
  1287                                           permEntry.mPermission,
  1288                                           permEntry.mExpireType,
  1289                                           permEntry.mExpireTime);
  1291     data->array->AppendObject(perm);
  1294   return PL_DHASH_NEXT;
  1297 NS_IMETHODIMP nsPermissionManager::GetEnumerator(nsISimpleEnumerator **aEnum)
  1299   // roll an nsCOMArray of all our permissions, then hand out an enumerator
  1300   nsCOMArray<nsIPermission> array;
  1301   nsGetEnumeratorData data(&array, &mTypeArray);
  1303   mPermissionTable.EnumerateEntries(AddPermissionsToList, &data);
  1305   return NS_NewArrayEnumerator(aEnum, array);
  1308 NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
  1310   ENSURE_NOT_CHILD_PROCESS;
  1312   if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
  1313     if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("permissions.memory_only").get())) {
  1314       // XXX: Should we remove the file? Probably not..
  1315       InitDB(PR_FALSE);
  1317   } else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
  1318     // The profile is about to change,
  1319     // or is going away because the application is shutting down.
  1320     mIsShuttingDown = true;
  1321     if (!nsCRT::strcmp(someData, MOZ_UTF16("shutdown-cleanse"))) {
  1322       // Clear the permissions file and close the db asynchronously
  1323       RemoveAllInternal(false);
  1324     } else {
  1325       RemoveAllFromMemory();
  1326       CloseDB(false);
  1329   else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
  1330     // the profile has already changed; init the db from the new location
  1331     InitDB(false);
  1334   return NS_OK;
  1337 PLDHashOperator
  1338 nsPermissionManager::GetPermissionsForApp(nsPermissionManager::PermissionHashKey* entry, void* arg)
  1340   GetPermissionsForAppStruct* data = static_cast<GetPermissionsForAppStruct*>(arg);
  1342   for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
  1343     nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
  1345     if (entry->GetKey()->mAppId != data->appId ||
  1346         (data->browserOnly && !entry->GetKey()->mIsInBrowserElement)) {
  1347       continue;
  1350     data->permissions.AppendObject(new nsPermission(entry->GetKey()->mHost,
  1351                                                     entry->GetKey()->mAppId,
  1352                                                     entry->GetKey()->mIsInBrowserElement,
  1353                                                     gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
  1354                                                     permEntry.mPermission,
  1355                                                     permEntry.mExpireType,
  1356                                                     permEntry.mExpireTime));
  1359   return PL_DHASH_NEXT;
  1362 NS_IMETHODIMP
  1363 nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
  1365   ENSURE_NOT_CHILD_PROCESS;
  1366   NS_ENSURE_ARG(aAppId != nsIScriptSecurityManager::NO_APP_ID);
  1368   // We begin by removing all the permissions from the DB.
  1369   // After clearing the DB, we call AddInternal() to make sure that all
  1370   // processes are aware of this change and the representation of the DB in
  1371   // memory is updated.
  1372   // We have to get all permissions associated with an application and then
  1373   // remove those because doing so in EnumerateEntries() would fail because
  1374   // we might happen to actually delete entries from the list.
  1376   nsAutoCString sql;
  1377   sql.AppendLiteral("DELETE FROM moz_hosts WHERE appId=");
  1378   sql.AppendInt(aAppId);
  1380   if (aBrowserOnly) {
  1381     sql.AppendLiteral(" AND isInBrowserElement=1");
  1384   nsCOMPtr<mozIStorageAsyncStatement> removeStmt;
  1385   nsresult rv = mDBConn->CreateAsyncStatement(sql, getter_AddRefs(removeStmt));
  1386   NS_ENSURE_SUCCESS(rv, rv);
  1388   nsCOMPtr<mozIStoragePendingStatement> pending;
  1389   rv = removeStmt->ExecuteAsync(nullptr, getter_AddRefs(pending));
  1390   NS_ENSURE_SUCCESS(rv, rv);
  1392   GetPermissionsForAppStruct data(aAppId, aBrowserOnly);
  1393   mPermissionTable.EnumerateEntries(GetPermissionsForApp, &data);
  1395   for (int32_t i=0; i<data.permissions.Count(); ++i) {
  1396     nsAutoCString host;
  1397     bool isInBrowserElement;
  1398     nsAutoCString type;
  1400     data.permissions[i]->GetHost(host);
  1401     data.permissions[i]->GetIsInBrowserElement(&isInBrowserElement);
  1402     data.permissions[i]->GetType(type);
  1404     nsCOMPtr<nsIPrincipal> principal;
  1405     if (NS_FAILED(GetPrincipal(host, aAppId, isInBrowserElement,
  1406                                getter_AddRefs(principal)))) {
  1407       NS_ERROR("GetPrincipal() failed!");
  1408       continue;
  1411     AddInternal(principal,
  1412                 type,
  1413                 nsIPermissionManager::UNKNOWN_ACTION,
  1414                 0,
  1415                 nsIPermissionManager::EXPIRE_NEVER,
  1416                 0,
  1417                 nsPermissionManager::eNotify,
  1418                 nsPermissionManager::eNoDBOperation);
  1421   return NS_OK;
  1424 PLDHashOperator
  1425 nsPermissionManager::RemoveExpiredPermissionsForAppEnumerator(
  1426   nsPermissionManager::PermissionHashKey* entry, void* arg)
  1428   uint32_t* appId = static_cast<uint32_t*>(arg);
  1430   for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
  1431     if (entry->GetKey()->mAppId != *appId) {
  1432       continue;
  1435     nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
  1436     if (permEntry.mExpireType != nsIPermissionManager::EXPIRE_SESSION) {
  1437       continue;
  1440     if (permEntry.mNonSessionExpireType == nsIPermissionManager::EXPIRE_SESSION) {
  1441       PermissionEntry oldPermissionEntry = entry->GetPermissions()[i];
  1443       entry->GetPermissions().RemoveElementAt(i);
  1445       gPermissionManager->NotifyObserversWithPermission(entry->GetKey()->mHost,
  1446                                                         entry->GetKey()->mAppId,
  1447                                                         entry->GetKey()->mIsInBrowserElement,
  1448                                                         gPermissionManager->mTypeArray.ElementAt(oldPermissionEntry.mType),
  1449                                                         oldPermissionEntry.mPermission,
  1450                                                         oldPermissionEntry.mExpireType,
  1451                                                         oldPermissionEntry.mExpireTime,
  1452                                                         MOZ_UTF16("deleted"));
  1453       --i;
  1454       continue;
  1457     permEntry.mPermission = permEntry.mNonSessionPermission;
  1458     permEntry.mExpireType = permEntry.mNonSessionExpireType;
  1459     permEntry.mExpireTime = permEntry.mNonSessionExpireTime;
  1461     gPermissionManager->NotifyObserversWithPermission(entry->GetKey()->mHost,
  1462                                                       entry->GetKey()->mAppId,
  1463                                                       entry->GetKey()->mIsInBrowserElement,
  1464                                                       gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
  1465                                                       permEntry.mPermission,
  1466                                                       permEntry.mExpireType,
  1467                                                       permEntry.mExpireTime,
  1468                                                       MOZ_UTF16("changed"));
  1471   return PL_DHASH_NEXT;
  1474 nsresult
  1475 nsPermissionManager::RemoveExpiredPermissionsForApp(uint32_t aAppId)
  1477   ENSURE_NOT_CHILD_PROCESS;
  1479   if (aAppId != nsIScriptSecurityManager::NO_APP_ID) {
  1480     mPermissionTable.EnumerateEntries(RemoveExpiredPermissionsForAppEnumerator, &aAppId);
  1483   return NS_OK;
  1486 //*****************************************************************************
  1487 //*** nsPermissionManager private methods
  1488 //*****************************************************************************
  1490 nsresult
  1491 nsPermissionManager::RemoveAllFromMemory()
  1493   mLargestID = 0;
  1494   mTypeArray.Clear();
  1495   mPermissionTable.Clear();
  1497   return NS_OK;
  1500 // Returns -1 on failure
  1501 int32_t
  1502 nsPermissionManager::GetTypeIndex(const char *aType,
  1503                                   bool        aAdd)
  1505   for (uint32_t i = 0; i < mTypeArray.Length(); ++i)
  1506     if (mTypeArray[i].Equals(aType))
  1507       return i;
  1509   if (!aAdd) {
  1510     // Not found, but that is ok - we were just looking.
  1511     return -1;
  1514   // This type was not registered before.
  1515   // append it to the array, without copy-constructing the string
  1516   nsCString *elem = mTypeArray.AppendElement();
  1517   if (!elem)
  1518     return -1;
  1520   elem->Assign(aType);
  1521   return mTypeArray.Length() - 1;
  1524 // wrapper function for mangling (host,type,perm,expireType,expireTime)
  1525 // set into an nsIPermission.
  1526 void
  1527 nsPermissionManager::NotifyObserversWithPermission(const nsACString &aHost,
  1528                                                    uint32_t          aAppId,
  1529                                                    bool              aIsInBrowserElement,
  1530                                                    const nsCString  &aType,
  1531                                                    uint32_t          aPermission,
  1532                                                    uint32_t          aExpireType,
  1533                                                    int64_t           aExpireTime,
  1534                                                    const char16_t  *aData)
  1536   nsCOMPtr<nsIPermission> permission =
  1537     new nsPermission(aHost, aAppId, aIsInBrowserElement, aType, aPermission,
  1538                      aExpireType, aExpireTime);
  1539   if (permission)
  1540     NotifyObservers(permission, aData);
  1543 // notify observers that the permission list changed. there are four possible
  1544 // values for aData:
  1545 // "deleted" means a permission was deleted. aPermission is the deleted permission.
  1546 // "added"   means a permission was added. aPermission is the added permission.
  1547 // "changed" means a permission was altered. aPermission is the new permission.
  1548 // "cleared" means the entire permission list was cleared. aPermission is null.
  1549 void
  1550 nsPermissionManager::NotifyObservers(nsIPermission   *aPermission,
  1551                                      const char16_t *aData)
  1553   if (mObserverService)
  1554     mObserverService->NotifyObservers(aPermission,
  1555                                       kPermissionChangeNotification,
  1556                                       aData);
  1559 nsresult
  1560 nsPermissionManager::Read()
  1562   ENSURE_NOT_CHILD_PROCESS;
  1564   nsresult rv;
  1566   // delete expired permissions before we read in the db
  1568     // this deletion has its own scope so the write lock is released when done.
  1569     nsCOMPtr<mozIStorageStatement> stmtDeleteExpired;
  1570     rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
  1571           "DELETE FROM moz_hosts WHERE expireType = ?1 AND expireTime <= ?2"),
  1572           getter_AddRefs(stmtDeleteExpired));
  1573     NS_ENSURE_SUCCESS(rv, rv);
  1575     rv = stmtDeleteExpired->BindInt32ByIndex(0, nsIPermissionManager::EXPIRE_TIME);
  1576     NS_ENSURE_SUCCESS(rv, rv);
  1578     rv = stmtDeleteExpired->BindInt64ByIndex(1, PR_Now() / 1000);
  1579     NS_ENSURE_SUCCESS(rv, rv);
  1581     bool hasResult;
  1582     rv = stmtDeleteExpired->ExecuteStep(&hasResult);
  1583     NS_ENSURE_SUCCESS(rv, rv);
  1586   nsCOMPtr<mozIStorageStatement> stmt;
  1587   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
  1588     "SELECT id, host, type, permission, expireType, expireTime, appId, isInBrowserElement "
  1589     "FROM moz_hosts"), getter_AddRefs(stmt));
  1590   NS_ENSURE_SUCCESS(rv, rv);
  1592   int64_t id;
  1593   nsAutoCString host, type;
  1594   uint32_t permission;
  1595   uint32_t expireType;
  1596   int64_t expireTime;
  1597   uint32_t appId;
  1598   bool isInBrowserElement;
  1599   bool hasResult;
  1600   bool readError = false;
  1602   while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
  1603     // explicitly set our entry id counter for use in AddInternal(),
  1604     // and keep track of the largest id so we know where to pick up.
  1605     id = stmt->AsInt64(0);
  1606     if (id > mLargestID)
  1607       mLargestID = id;
  1609     rv = stmt->GetUTF8String(1, host);
  1610     if (NS_FAILED(rv)) {
  1611       readError = true;
  1612       continue;
  1615     rv = stmt->GetUTF8String(2, type);
  1616     if (NS_FAILED(rv)) {
  1617       readError = true;
  1618       continue;
  1621     permission = stmt->AsInt32(3);
  1622     expireType = stmt->AsInt32(4);
  1624     // convert into int64_t value (milliseconds)
  1625     expireTime = stmt->AsInt64(5);
  1627     if (stmt->AsInt64(6) < 0) {
  1628       readError = true;
  1629       continue;
  1631     appId = static_cast<uint32_t>(stmt->AsInt64(6));
  1632     isInBrowserElement = static_cast<bool>(stmt->AsInt32(7));
  1634     nsCOMPtr<nsIPrincipal> principal;
  1635     nsresult rv = GetPrincipal(host, appId, isInBrowserElement, getter_AddRefs(principal));
  1636     if (NS_FAILED(rv)) {
  1637       readError = true;
  1638       continue;
  1641     rv = AddInternal(principal, type, permission, id, expireType, expireTime,
  1642                      eDontNotify, eNoDBOperation);
  1643     if (NS_FAILED(rv)) {
  1644       readError = true;
  1645       continue;
  1649   if (readError) {
  1650     NS_ERROR("Error occured while reading the permissions database!");
  1651     return NS_ERROR_FAILURE;
  1654   return NS_OK;
  1657 static const char kMatchTypeHost[] = "host";
  1659 nsresult
  1660 nsPermissionManager::Import()
  1662   ENSURE_NOT_CHILD_PROCESS;
  1664   nsresult rv;
  1666   nsCOMPtr<nsIFile> permissionsFile;
  1667   rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(permissionsFile));
  1668   if (NS_FAILED(rv)) return rv;
  1670   rv = permissionsFile->AppendNative(NS_LITERAL_CSTRING(kHostpermFileName));
  1671   NS_ENSURE_SUCCESS(rv, rv);
  1673   nsCOMPtr<nsIInputStream> fileInputStream;
  1674   rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream),
  1675                                   permissionsFile);
  1676   if (NS_FAILED(rv)) return rv;
  1678   nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
  1679   NS_ENSURE_SUCCESS(rv, rv);
  1681   // start a transaction on the storage db, to optimize insertions.
  1682   // transaction will automically commit on completion
  1683   mozStorageTransaction transaction(mDBConn, true);
  1685   /* format is:
  1686    * matchtype \t type \t permission \t host
  1687    * Only "host" is supported for matchtype
  1688    * type is a string that identifies the type of permission (e.g. "cookie")
  1689    * permission is an integer between 1 and 15
  1690    */
  1692   nsAutoCString buffer;
  1693   bool isMore = true;
  1694   while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
  1695     if (buffer.IsEmpty() || buffer.First() == '#') {
  1696       continue;
  1699     nsTArray<nsCString> lineArray;
  1701     // Split the line at tabs
  1702     ParseString(buffer, '\t', lineArray);
  1704     if (lineArray[0].EqualsLiteral(kMatchTypeHost) &&
  1705         lineArray.Length() == 4) {
  1707       nsresult error;
  1708       uint32_t permission = lineArray[2].ToInteger(&error);
  1709       if (NS_FAILED(error))
  1710         continue;
  1712       // hosts might be encoded in UTF8; switch them to ACE to be consistent
  1713       if (!IsASCII(lineArray[3])) {
  1714         rv = NormalizeToACE(lineArray[3]);
  1715         if (NS_FAILED(rv))
  1716           continue;
  1719       nsCOMPtr<nsIPrincipal> principal;
  1720       nsresult rv = GetPrincipal(lineArray[3], getter_AddRefs(principal));
  1721       NS_ENSURE_SUCCESS(rv, rv);
  1723       rv = AddInternal(principal, lineArray[1], permission, 0,
  1724                        nsIPermissionManager::EXPIRE_NEVER, 0, eDontNotify, eWriteToDB);
  1725       NS_ENSURE_SUCCESS(rv, rv);
  1729   // we're done importing - delete the old file
  1730   permissionsFile->Remove(false);
  1732   return NS_OK;
  1735 nsresult
  1736 nsPermissionManager::NormalizeToACE(nsCString &aHost)
  1738   // lazily init the IDN service
  1739   if (!mIDNService) {
  1740     nsresult rv;
  1741     mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv);
  1742     NS_ENSURE_SUCCESS(rv, rv);
  1745   return mIDNService->ConvertUTF8toACE(aHost, aHost);
  1748 void
  1749 nsPermissionManager::UpdateDB(OperationType aOp,
  1750                               mozIStorageAsyncStatement* aStmt,
  1751                               int64_t aID,
  1752                               const nsACString &aHost,
  1753                               const nsACString &aType,
  1754                               uint32_t aPermission,
  1755                               uint32_t aExpireType,
  1756                               int64_t aExpireTime,
  1757                               uint32_t aAppId,
  1758                               bool aIsInBrowserElement)
  1760   ENSURE_NOT_CHILD_PROCESS_NORET;
  1762   nsresult rv;
  1764   // no statement is ok - just means we don't have a profile
  1765   if (!aStmt)
  1766     return;
  1768   switch (aOp) {
  1769   case eOperationAdding:
  1771       rv = aStmt->BindInt64ByIndex(0, aID);
  1772       if (NS_FAILED(rv)) break;
  1774       rv = aStmt->BindUTF8StringByIndex(1, aHost);
  1775       if (NS_FAILED(rv)) break;
  1777       rv = aStmt->BindUTF8StringByIndex(2, aType);
  1778       if (NS_FAILED(rv)) break;
  1780       rv = aStmt->BindInt32ByIndex(3, aPermission);
  1781       if (NS_FAILED(rv)) break;
  1783       rv = aStmt->BindInt32ByIndex(4, aExpireType);
  1784       if (NS_FAILED(rv)) break;
  1786       rv = aStmt->BindInt64ByIndex(5, aExpireTime);
  1787       if (NS_FAILED(rv)) break;
  1789       rv = aStmt->BindInt64ByIndex(6, aAppId);
  1790       if (NS_FAILED(rv)) break;
  1792       rv = aStmt->BindInt64ByIndex(7, aIsInBrowserElement);
  1793       break;
  1796   case eOperationRemoving:
  1798       rv = aStmt->BindInt64ByIndex(0, aID);
  1799       break;
  1802   case eOperationChanging:
  1804       rv = aStmt->BindInt64ByIndex(0, aID);
  1805       if (NS_FAILED(rv)) break;
  1807       rv = aStmt->BindInt32ByIndex(1, aPermission);
  1808       if (NS_FAILED(rv)) break;
  1810       rv = aStmt->BindInt32ByIndex(2, aExpireType);
  1811       if (NS_FAILED(rv)) break;
  1813       rv = aStmt->BindInt64ByIndex(3, aExpireTime);
  1814       break;
  1817   default:
  1819       NS_NOTREACHED("need a valid operation in UpdateDB()!");
  1820       rv = NS_ERROR_UNEXPECTED;
  1821       break;
  1825   if (NS_FAILED(rv)) {
  1826     NS_WARNING("db change failed!");
  1827     return;
  1830   nsCOMPtr<mozIStoragePendingStatement> pending;
  1831   rv = aStmt->ExecuteAsync(nullptr, getter_AddRefs(pending));
  1832   MOZ_ASSERT(NS_SUCCEEDED(rv));
  1835 NS_IMETHODIMP
  1836 nsPermissionManager::AddrefAppId(uint32_t aAppId)
  1838   if (aAppId == nsIScriptSecurityManager::NO_APP_ID) {
  1839     return NS_OK;
  1842   bool found = false;
  1843   for (uint32_t i = 0; i < mAppIdRefcounts.Length(); ++i) {
  1844     if (mAppIdRefcounts[i].mAppId == aAppId) {
  1845       ++mAppIdRefcounts[i].mCounter;
  1846       found = true;
  1847       break;
  1851   if (!found) {
  1852     ApplicationCounter app = { aAppId, 1 };
  1853     mAppIdRefcounts.AppendElement(app);
  1856   return NS_OK;
  1859 NS_IMETHODIMP
  1860 nsPermissionManager::ReleaseAppId(uint32_t aAppId)
  1862   // An app has been released, maybe we have to reset its session.
  1864   if (aAppId == nsIScriptSecurityManager::NO_APP_ID) {
  1865     return NS_OK;
  1868   for (uint32_t i = 0; i < mAppIdRefcounts.Length(); ++i) {
  1869     if (mAppIdRefcounts[i].mAppId == aAppId) {
  1870       --mAppIdRefcounts[i].mCounter;
  1872       if (!mAppIdRefcounts[i].mCounter) {
  1873         mAppIdRefcounts.RemoveElementAt(i);
  1874         return RemoveExpiredPermissionsForApp(aAppId);
  1877       break;
  1881   return NS_OK;
  1884 NS_IMETHODIMP
  1885 nsPermissionManager::UpdateExpireTime(nsIPrincipal* aPrincipal,
  1886                                      const char* aType,
  1887                                      bool aExactHostMatch,
  1888                                      uint64_t aSessionExpireTime,
  1889                                      uint64_t aPersistentExpireTime)
  1891   NS_ENSURE_ARG_POINTER(aPrincipal);
  1892   NS_ENSURE_ARG_POINTER(aType);
  1894   uint64_t nowms = PR_Now() / 1000;
  1895   if (aSessionExpireTime < nowms || aPersistentExpireTime < nowms) {
  1896     return NS_ERROR_INVALID_ARG;
  1899   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
  1900     return NS_OK;
  1903   // Setting the expire time of an nsEP is non-sensical.
  1904   if (IsExpandedPrincipal(aPrincipal)) {
  1905     return NS_ERROR_INVALID_ARG;
  1908   nsAutoCString host;
  1909   nsresult rv = GetHostForPrincipal(aPrincipal, host);
  1910   NS_ENSURE_SUCCESS(rv, rv);
  1912   int32_t typeIndex = GetTypeIndex(aType, false);
  1913   // If type == -1, the type isn't known,
  1914   // so just return NS_OK
  1915   if (typeIndex == -1) return NS_OK;
  1917   uint32_t appId;
  1918   rv = aPrincipal->GetAppId(&appId);
  1919   NS_ENSURE_SUCCESS(rv, rv);
  1921   bool isInBrowserElement;
  1922   rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
  1923   NS_ENSURE_SUCCESS(rv, rv);
  1925   PermissionHashKey* entry = GetPermissionHashKey(host, appId, isInBrowserElement,
  1926                                                   typeIndex, aExactHostMatch);
  1927   if (!entry) {
  1928     return NS_OK;
  1931   int32_t idx = entry->GetPermissionIndex(typeIndex);
  1932   if (-1 == idx) {
  1933     return NS_OK;
  1936   PermissionEntry& perm = entry->GetPermissions()[idx];
  1937   if (perm.mExpireType == EXPIRE_TIME) {
  1938     perm.mExpireTime = aPersistentExpireTime;
  1939   } else if (perm.mExpireType == EXPIRE_SESSION && perm.mExpireTime != 0) {
  1940     perm.mExpireTime = aSessionExpireTime;
  1942   return NS_OK;

mercurial