LCOV - code coverage report
Current view: directory - security/manager/boot/src - nsStrictTransportSecurityService.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 228 157 68.9 %
Date: 2012-06-02 Functions: 24 19 79.2 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is Strict-Transport-Security.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *  Sid Stamm <sid@mozilla.com>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "plstr.h"
      39                 : #include "prlog.h"
      40                 : #include "prprf.h"
      41                 : #include "nsCRTGlue.h"
      42                 : #include "nsIPermissionManager.h"
      43                 : #include "nsIPrivateBrowsingService.h"
      44                 : #include "nsISSLStatus.h"
      45                 : #include "nsISSLStatusProvider.h"
      46                 : #include "nsStrictTransportSecurityService.h"
      47                 : #include "nsIURI.h"
      48                 : #include "nsNetUtil.h"
      49                 : #include "nsThreadUtils.h"
      50                 : #include "nsStringGlue.h"
      51                 : 
      52                 : #if defined(PR_LOGGING)
      53            1464 : PRLogModuleInfo *gSTSLog = PR_NewLogModule("nsSTSService");
      54                 : #endif
      55                 : 
      56                 : #define STSLOG(args) PR_LOG(gSTSLog, 4, args)
      57                 : 
      58                 : #define STS_PARSER_FAIL_IF(test,args) \
      59                 :   if (test) { \
      60                 :     STSLOG(args); \
      61                 :     return NS_ERROR_FAILURE; \
      62                 :   }
      63                 : 
      64                 : 
      65                 : ////////////////////////////////////////////////////////////////////////////////
      66                 : 
      67               0 : nsSTSHostEntry::nsSTSHostEntry(const char* aHost)
      68                 :   : mHost(aHost)
      69                 :   , mExpireTime(0)
      70                 :   , mDeleted(false)
      71               0 :   , mIncludeSubdomains(false)
      72                 : {
      73               0 : }
      74                 : 
      75               0 : nsSTSHostEntry::nsSTSHostEntry(const nsSTSHostEntry& toCopy)
      76                 :   : mHost(toCopy.mHost)
      77                 :   , mExpireTime(toCopy.mExpireTime)
      78                 :   , mDeleted(toCopy.mDeleted)
      79               0 :   , mIncludeSubdomains(toCopy.mIncludeSubdomains)
      80                 : {
      81               0 : }
      82                 : 
      83                 : ////////////////////////////////////////////////////////////////////////////////
      84                 : 
      85                 : 
      86             266 : nsStrictTransportSecurityService::nsStrictTransportSecurityService()
      87             266 :   : mInPrivateMode(false)
      88                 : {
      89             266 : }
      90                 : 
      91             528 : nsStrictTransportSecurityService::~nsStrictTransportSecurityService()
      92                 : {
      93            1056 : }
      94                 : 
      95            2940 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsStrictTransportSecurityService,
      96                 :                               nsIObserver,
      97                 :                               nsIStrictTransportSecurityService)
      98                 : 
      99                 : nsresult
     100             266 : nsStrictTransportSecurityService::Init()
     101                 : {
     102                 :    nsresult rv;
     103                 : 
     104             266 :    mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
     105             266 :    NS_ENSURE_SUCCESS(rv, rv);
     106                 : 
     107                 :    // figure out if we're starting in private browsing mode
     108                 :    nsCOMPtr<nsIPrivateBrowsingService> pbs =
     109             532 :      do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
     110             266 :    if (pbs)
     111             266 :      pbs->GetPrivateBrowsingEnabled(&mInPrivateMode);
     112                 : 
     113             266 :    mObserverService = mozilla::services::GetObserverService();
     114             266 :    if (mObserverService)
     115             266 :      mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false);
     116                 : 
     117             266 :    if (mInPrivateMode && !mPrivateModeHostTable.Init())
     118               0 :      return NS_ERROR_OUT_OF_MEMORY;
     119                 : 
     120             266 :    return NS_OK;
     121                 : }
     122                 : 
     123                 : nsresult
     124              24 : nsStrictTransportSecurityService::GetHost(nsIURI *aURI, nsACString &aResult)
     125                 : {
     126              48 :   nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
     127              24 :   if (!innerURI) return NS_ERROR_FAILURE;
     128                 : 
     129              24 :   nsresult rv = innerURI->GetAsciiHost(aResult);
     130                 : 
     131              24 :   if (NS_FAILED(rv) || aResult.IsEmpty())
     132               0 :     return NS_ERROR_UNEXPECTED;
     133                 : 
     134              24 :   return NS_OK;
     135                 : }
     136                 : 
     137                 : nsresult
     138              28 : nsStrictTransportSecurityService::SetStsState(nsIURI* aSourceURI,
     139                 :                                               PRInt64 maxage,
     140                 :                                               bool includeSubdomains)
     141                 : {
     142                 :   // If max-age is zero, that's an indication to immediately remove the
     143                 :   // permissions, so here's a shortcut.
     144              28 :   if (!maxage)
     145               0 :     return RemoveStsState(aSourceURI);
     146                 : 
     147                 :   // Expire time is millis from now.  Since STS max-age is in seconds, and
     148                 :   // PR_Now() is in micros, must equalize the units at milliseconds.
     149              28 :   PRInt64 expiretime = (PR_Now() / 1000) + (maxage * 1000);
     150                 : 
     151                 :   // record entry for this host with max-age in the permissions manager
     152              28 :   STSLOG(("STS: maxage permission SET, adding permission\n"));
     153                 :   nsresult rv = AddPermission(aSourceURI,
     154                 :                               STS_PERMISSION,
     155                 :                               (PRUint32) nsIPermissionManager::ALLOW_ACTION,
     156                 :                               (PRUint32) nsIPermissionManager::EXPIRE_TIME,
     157              28 :                               expiretime);
     158              28 :   NS_ENSURE_SUCCESS(rv, rv);
     159                 : 
     160              28 :   if (includeSubdomains) {
     161                 :     // record entry for this host with include subdomains in the permissions manager
     162              10 :     STSLOG(("STS: subdomains permission SET, adding permission\n"));
     163                 :     rv = AddPermission(aSourceURI,
     164                 :                        STS_SUBDOMAIN_PERMISSION,
     165                 :                        (PRUint32) nsIPermissionManager::ALLOW_ACTION,
     166                 :                        (PRUint32) nsIPermissionManager::EXPIRE_TIME,
     167              10 :                        expiretime);
     168              10 :     NS_ENSURE_SUCCESS(rv, rv);
     169                 :   } else { // !includeSubdomains
     170              36 :     nsCAutoString hostname;
     171              18 :     rv = GetHost(aSourceURI, hostname);
     172              18 :     NS_ENSURE_SUCCESS(rv, rv);
     173                 : 
     174              18 :     STSLOG(("STS: subdomains permission UNSET, removing any existing ones\n"));
     175              18 :     rv = RemovePermission(hostname, STS_SUBDOMAIN_PERMISSION);
     176              18 :     NS_ENSURE_SUCCESS(rv, rv);
     177                 :   }
     178              28 :   return NS_OK;
     179                 : }
     180                 : 
     181                 : NS_IMETHODIMP
     182               0 : nsStrictTransportSecurityService::RemoveStsState(nsIURI* aURI)
     183                 : {
     184                 :   // Should be called on the main thread (or via proxy) since the permission
     185                 :   // manager is used and it's not threadsafe.
     186               0 :   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
     187                 : 
     188               0 :   nsCAutoString hostname;
     189               0 :   nsresult rv = GetHost(aURI, hostname);
     190               0 :   NS_ENSURE_SUCCESS(rv, rv);
     191                 : 
     192               0 :   rv = RemovePermission(hostname, STS_PERMISSION);
     193               0 :   NS_ENSURE_SUCCESS(rv, rv);
     194               0 :   STSLOG(("STS: deleted maxage permission\n"));
     195                 : 
     196               0 :   rv = RemovePermission(hostname, STS_SUBDOMAIN_PERMISSION);
     197               0 :   NS_ENSURE_SUCCESS(rv, rv);
     198               0 :   STSLOG(("STS: deleted subdomains permission\n"));
     199                 : 
     200               0 :   return NS_OK;
     201                 : }
     202                 : 
     203                 : NS_IMETHODIMP
     204              40 : nsStrictTransportSecurityService::ProcessStsHeader(nsIURI* aSourceURI,
     205                 :                                                    const char* aHeader)
     206                 : {
     207                 :   // Should be called on the main thread (or via proxy) since the permission
     208                 :   // manager is used and it's not threadsafe.
     209              40 :   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
     210                 : 
     211              40 :   char * header = NS_strdup(aHeader);
     212              40 :   if (!header) return NS_ERROR_OUT_OF_MEMORY;
     213              40 :   nsresult rv = ProcessStsHeaderMutating(aSourceURI, header);
     214              40 :   NS_Free(header);
     215              40 :   return rv;
     216                 : }
     217                 : 
     218                 : nsresult
     219              40 : nsStrictTransportSecurityService::ProcessStsHeaderMutating(nsIURI* aSourceURI,
     220                 :                                                            char* aHeader)
     221                 : {
     222              40 :   STSLOG(("STS: ProcessStrictTransportHeader(%s)\n", aHeader));
     223                 : 
     224                 :   // "Strict-Transport-Security" ":" OWS
     225                 :   //      STS-d  *( OWS ";" OWS STS-d  OWS)
     226                 :   //
     227                 :   //  ; STS directive
     228                 :   //  STS-d      = maxAge / includeSubDomains
     229                 :   //
     230                 :   //  maxAge     = "max-age" "=" delta-seconds v-ext
     231                 :   //
     232                 :   //  includeSubDomains = [ "includeSubDomains" ]
     233                 : 
     234                 :   const char* directive;
     235                 : 
     236              40 :   bool foundMaxAge = false;
     237              40 :   bool foundUnrecognizedTokens = false;
     238              40 :   bool includeSubdomains = false;
     239              40 :   PRInt64 maxAge = 0;
     240                 : 
     241              80 :   NS_NAMED_LITERAL_CSTRING(max_age_var, "max-age");
     242              80 :   NS_NAMED_LITERAL_CSTRING(include_subd_var, "includesubdomains");
     243                 : 
     244             124 :   while ((directive = NS_strtok(";", &aHeader))) {
     245                 :     //skip leading whitespace
     246              50 :     directive = NS_strspnp(" \t", directive);
     247              50 :     STS_PARSER_FAIL_IF(!(*directive), ("error removing initial whitespace\n."));
     248                 : 
     249              50 :     if (!PL_strncasecmp(directive, max_age_var.get(), max_age_var.Length())) {
     250                 :       // skip directive name
     251              34 :       directive += max_age_var.Length();
     252                 :       // skip leading whitespace
     253              34 :       directive = NS_strspnp(" \t", directive);
     254              34 :       STS_PARSER_FAIL_IF(*directive != '=',
     255                 :                   ("No equal sign found in max-age directive\n"));
     256                 : 
     257                 :       // skip over the equal sign
     258              33 :       STS_PARSER_FAIL_IF(*(++directive) == '\0',
     259                 :                   ("No delta-seconds present\n"));
     260                 : 
     261                 :       // obtain the delta-seconds value
     262              33 :       STS_PARSER_FAIL_IF(PR_sscanf(directive, "%lld", &maxAge) != 1,
     263                 :                   ("Could not convert delta-seconds\n"));
     264              28 :       STSLOG(("STS: ProcessStrictTransportHeader() STS found maxage %lld\n", maxAge));
     265              28 :       foundMaxAge = true;
     266                 : 
     267                 :       // skip max-age value and trailing whitespace
     268              28 :       directive = NS_strspnp("0123456789 \t", directive);
     269                 : 
     270                 :       // log unknown tokens, but don't fail (for forwards compatibility)
     271              28 :       if (*directive != '\0') {
     272               3 :         foundUnrecognizedTokens = true;
     273               3 :         STSLOG(("Extra stuff in max-age after delta-seconds: %s \n", directive));
     274                 :       }
     275                 :     }
     276              16 :     else if (!PL_strncasecmp(directive, include_subd_var.get(), include_subd_var.Length())) {
     277              12 :       directive += include_subd_var.Length();
     278                 : 
     279                 :       // only record "includesubdomains" if it is a token by itself... for
     280                 :       // example, don't set includeSubdomains = true if the directive is
     281                 :       // "includesubdomainsFooBar".
     282              12 :       if (*directive == '\0' || *directive =='\t' || *directive == ' ') {
     283              11 :         includeSubdomains = true;
     284              11 :         STSLOG(("STS: ProcessStrictTransportHeader: obtained subdomains status\n"));
     285                 : 
     286                 :         // skip trailing whitespace
     287              11 :         directive = NS_strspnp(" \t", directive);
     288                 : 
     289              22 :         if (*directive != '\0') {
     290               0 :           foundUnrecognizedTokens = true;
     291               0 :           STSLOG(("Extra stuff after includesubdomains: %s\n", directive));
     292                 :         }
     293                 :       } else {
     294               1 :         foundUnrecognizedTokens = true;
     295               1 :         STSLOG(("Unrecognized directive in header: %s\n", directive));
     296                 :       }
     297                 :     }
     298                 :     else {
     299                 :       // log unknown directives, but don't fail (for backwards compatibility)
     300               4 :       foundUnrecognizedTokens = true;
     301               4 :       STSLOG(("Unrecognized directive in header: %s\n", directive));
     302                 :     }
     303                 :   }
     304                 : 
     305                 :   // after processing all the directives, make sure we came across max-age
     306                 :   // somewhere.
     307              34 :   STS_PARSER_FAIL_IF(!foundMaxAge,
     308                 :               ("Parse ERROR: couldn't locate max-age token\n"));
     309                 : 
     310                 :   // record the successfully parsed header data.
     311              28 :   SetStsState(aSourceURI, maxAge, includeSubdomains);
     312                 : 
     313                 :   return foundUnrecognizedTokens ?
     314                 :          NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA :
     315              28 :          NS_OK;
     316                 : }
     317                 : 
     318                 : NS_IMETHODIMP
     319               0 : nsStrictTransportSecurityService::IsStsHost(const char* aHost, bool* aResult)
     320                 : {
     321                 :   // Should be called on the main thread (or via proxy) since the permission
     322                 :   // manager is used and it's not threadsafe.
     323               0 :   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
     324                 : 
     325               0 :   nsCOMPtr<nsIURI> uri;
     326               0 :   nsDependentCString hostString(aHost);
     327               0 :   nsresult rv = NS_NewURI(getter_AddRefs(uri),
     328               0 :                           NS_LITERAL_CSTRING("https://") + hostString);
     329               0 :   NS_ENSURE_SUCCESS(rv, rv);
     330               0 :   return IsStsURI(uri, aResult);
     331                 : }
     332                 : 
     333                 : NS_IMETHODIMP
     334            5051 : nsStrictTransportSecurityService::IsStsURI(nsIURI* aURI, bool* aResult)
     335                 : {
     336                 :   // Should be called on the main thread (or via proxy) since the permission
     337                 :   // manager is used and it's not threadsafe.
     338            5051 :   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
     339                 : 
     340                 :   nsresult rv;
     341                 :   PRUint32 permExact, permGeneral;
     342                 :   // If this domain has the forcehttps permission, this is an STS host.
     343            5051 :   rv = TestPermission(aURI, STS_PERMISSION, &permExact, true);
     344            5051 :   NS_ENSURE_SUCCESS(rv, rv);
     345                 : 
     346                 :   // If any super-domain has the includeSubdomains permission, this is an
     347                 :   // STS host.
     348            5051 :   rv = TestPermission(aURI, STS_SUBDOMAIN_PERMISSION, &permGeneral, false);
     349            5051 :   NS_ENSURE_SUCCESS(rv, rv);
     350                 : 
     351                 :   *aResult = ((permExact   == nsIPermissionManager::ALLOW_ACTION) ||
     352            5051 :               (permGeneral == nsIPermissionManager::ALLOW_ACTION));
     353            5051 :   return NS_OK;
     354                 : }
     355                 : 
     356                 : 
     357                 : // Verify the trustworthiness of the security info (are there any cert errors?)
     358                 : NS_IMETHODIMP
     359               4 : nsStrictTransportSecurityService::ShouldIgnoreStsHeader(nsISupports* aSecurityInfo,
     360                 :                                                         bool* aResult)
     361                 : {
     362                 :   nsresult rv;
     363               4 :   bool tlsIsBroken = false;
     364               8 :   nsCOMPtr<nsISSLStatusProvider> sslprov = do_QueryInterface(aSecurityInfo);
     365               4 :   NS_ENSURE_TRUE(sslprov, NS_ERROR_FAILURE);
     366                 : 
     367               8 :   nsCOMPtr<nsISSLStatus> sslstat;
     368               4 :   rv = sslprov->GetSSLStatus(getter_AddRefs(sslstat));
     369               4 :   NS_ENSURE_SUCCESS(rv, rv);
     370               4 :   NS_ENSURE_TRUE(sslstat, NS_ERROR_FAILURE);
     371                 : 
     372                 :   bool trustcheck;
     373               4 :   rv = sslstat->GetIsDomainMismatch(&trustcheck);
     374               4 :   NS_ENSURE_SUCCESS(rv, rv);
     375               4 :   tlsIsBroken = tlsIsBroken || trustcheck;
     376                 : 
     377               4 :   rv = sslstat->GetIsNotValidAtThisTime(&trustcheck);
     378               4 :   NS_ENSURE_SUCCESS(rv, rv);
     379               4 :   tlsIsBroken = tlsIsBroken || trustcheck;
     380                 : 
     381               4 :   rv = sslstat->GetIsUntrusted(&trustcheck);
     382               4 :   NS_ENSURE_SUCCESS(rv, rv);
     383               4 :   tlsIsBroken = tlsIsBroken || trustcheck;
     384                 : 
     385               4 :   *aResult = tlsIsBroken;
     386               4 :   return NS_OK;
     387                 : }
     388                 : 
     389                 : //------------------------------------------------------------
     390                 : // nsStrictTransportSecurityService::nsIObserver
     391                 : //------------------------------------------------------------
     392                 : 
     393                 : NS_IMETHODIMP
     394               4 : nsStrictTransportSecurityService::Observe(nsISupports *subject,
     395                 :                                           const char *topic,
     396                 :                                           const PRUnichar *data)
     397                 : {
     398               4 :   if (strcmp(topic, NS_PRIVATE_BROWSING_SWITCH_TOPIC) == 0) {
     399               4 :     if(NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(data)) {
     400                 :       // Indication to start recording stuff locally and not writing changes
     401                 :       // out to the permission manager.
     402                 : 
     403               3 :       if (!mPrivateModeHostTable.IsInitialized()
     404               1 :           && !mPrivateModeHostTable.Init()) {
     405               0 :         return NS_ERROR_OUT_OF_MEMORY;
     406                 :       }
     407               2 :       mInPrivateMode = true;
     408                 :     }
     409               2 :     else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(data)) {
     410               2 :       mPrivateModeHostTable.Clear();
     411               2 :       mInPrivateMode = false;
     412                 :     }
     413                 :   }
     414                 : 
     415               4 :   return NS_OK;
     416                 : }
     417                 : 
     418                 : //------------------------------------------------------------
     419                 : // Functions to overlay the permission manager calls in case
     420                 : // we're in private browsing mode.
     421                 : //------------------------------------------------------------
     422                 : nsresult
     423              38 : nsStrictTransportSecurityService::AddPermission(nsIURI     *aURI,
     424                 :                                                 const char *aType,
     425                 :                                                 PRUint32   aPermission,
     426                 :                                                 PRUint32   aExpireType,
     427                 :                                                 PRInt64    aExpireTime)
     428                 : {
     429                 :     // Private mode doesn't address user-set (EXPIRE_NEVER) permissions: let
     430                 :     // those be stored persistently.
     431              38 :     if (!mInPrivateMode || aExpireType == nsIPermissionManager::EXPIRE_NEVER) {
     432                 :       // Not in private mode, or manually-set permission
     433              38 :       return mPermMgr->Add(aURI, aType, aPermission, aExpireType, aExpireTime);
     434                 :     }
     435                 : 
     436               0 :     nsCAutoString host;
     437               0 :     nsresult rv = GetHost(aURI, host);
     438               0 :     NS_ENSURE_SUCCESS(rv, rv);
     439               0 :     STSLOG(("AddPermission for entry for for %s", host.get()));
     440                 : 
     441                 :     // Update in mPrivateModeHostTable only, so any changes will be rolled
     442                 :     // back when exiting private mode.
     443                 : 
     444                 :     // Note: EXPIRE_NEVER permissions should trump anything that shows up in
     445                 :     // the HTTP header, so if there's an EXPIRE_NEVER permission already
     446                 :     // don't store anything new.
     447                 :     // Currently there's no way to get the type of expiry out of the
     448                 :     // permission manager, but that's okay since there's nothing that stores
     449                 :     // EXPIRE_NEVER permissions.
     450                 : 
     451                 :     // PutEntry returns an existing entry if there already is one, or it
     452                 :     // creates a new one if there isn't.
     453               0 :     nsSTSHostEntry* entry = mPrivateModeHostTable.PutEntry(host.get());
     454               0 :     STSLOG(("Created private mode entry for for %s", host.get()));
     455                 : 
     456                 :     // AddPermission() will be called twice if the STS header encountered has
     457                 :     // includeSubdomains (first for the main permission and second for the
     458                 :     // subdomains permission). If AddPermission() gets called a second time
     459                 :     // with the STS_SUBDOMAIN_PERMISSION, we just have to flip that bit in
     460                 :     // the nsSTSHostEntry.
     461               0 :     if (strcmp(aType, STS_SUBDOMAIN_PERMISSION) == 0) {
     462               0 :       entry->mIncludeSubdomains = true;
     463                 :     }
     464                 :     // for the case where PutEntry() returned an existing host entry, make
     465                 :     // sure it's not set as deleted (which might have happened in the past).
     466               0 :     entry->mDeleted = false;
     467                 : 
     468                 :     // Also refresh the expiration time.
     469               0 :     entry->mExpireTime = aExpireTime;
     470               0 :     return NS_OK;
     471                 : 
     472                 : }
     473                 : 
     474                 : nsresult
     475              18 : nsStrictTransportSecurityService::RemovePermission(const nsCString  &aHost,
     476                 :                                                    const char       *aType)
     477                 : {
     478              18 :     if (!mInPrivateMode) {
     479                 :       // Not in private mode: remove permissions persistently.
     480              18 :       return mPermMgr->Remove(aHost, aType);
     481                 :     }
     482                 : 
     483                 :     // Make changes in mPrivateModeHostTable only, so any changes will be
     484                 :     // rolled back when exiting private mode.
     485               0 :     nsSTSHostEntry* entry = mPrivateModeHostTable.GetEntry(aHost.get());
     486                 : 
     487                 :     // Build up an nsIURI for use with the permission manager.
     488               0 :     nsCOMPtr<nsIURI> uri;
     489               0 :     nsresult rv = NS_NewURI(getter_AddRefs(uri),
     490               0 :                             NS_LITERAL_CSTRING("http://") + aHost);
     491               0 :     NS_ENSURE_SUCCESS(rv, rv);
     492                 : 
     493                 :     // Check to see if there's STS data stored for this host in the
     494                 :     // permission manager (probably set outside private mode).
     495                 :     PRUint32 permmgrValue;
     496               0 :     rv = mPermMgr->TestExactPermission(uri, aType, &permmgrValue);
     497               0 :     NS_ENSURE_SUCCESS(rv, rv);
     498                 : 
     499                 :     // If there is STS data in the permission manager, store a "deleted" mask
     500                 :     // for the permission in mPrivateModeHostTable (either update
     501                 :     // mPrivateModeHostTable to have the deleted mask, or add one).
     502                 :     // This is because we don't want removals that happen in private mode to
     503                 :     // be reflected when private mode is exited -- but while in private mode
     504                 :     // we still want the effect of the removal.
     505               0 :     if (permmgrValue != nsIPermissionManager::UNKNOWN_ACTION) {
     506                 :       // if there's no entry in mPrivateModeHostTable, we have to make one.
     507               0 :       if (!entry) {
     508               0 :         entry = mPrivateModeHostTable.PutEntry(aHost.get());
     509               0 :         STSLOG(("Created private mode deleted mask for for %s", aHost.get()));
     510                 :       }
     511               0 :       entry->mDeleted = true;
     512               0 :       entry->mIncludeSubdomains = false;
     513               0 :       return NS_OK;
     514                 :     }
     515                 : 
     516                 :     // Otherwise, permission doesn't exist in the real permission manager, so
     517                 :     // there's nothing to "pretend" to delete.  I'ts ok to delete any copy in
     518                 :     // mPrivateModeHostTable.
     519               0 :     if (entry) mPrivateModeHostTable.RawRemoveEntry(entry);
     520               0 :     return NS_OK;
     521                 : }
     522                 : 
     523                 : nsresult
     524           10102 : nsStrictTransportSecurityService::TestPermission(nsIURI     *aURI,
     525                 :                                                  const char *aType,
     526                 :                                                  PRUint32   *aPermission,
     527                 :                                                  bool       testExact)
     528                 : {
     529                 :     // set default for if we can't find any STS information
     530           10102 :     *aPermission = nsIPermissionManager::UNKNOWN_ACTION;
     531                 : 
     532           10102 :     if (!mInPrivateMode) {
     533                 :       // if not in private mode, just delegate to the permission manager.
     534           10096 :       if (testExact)
     535            5048 :         return mPermMgr->TestExactPermission(aURI, aType, aPermission);
     536                 :       else
     537            5048 :         return mPermMgr->TestPermission(aURI, aType, aPermission);
     538                 :     }
     539                 : 
     540              12 :     nsCAutoString host;
     541               6 :     nsresult rv = GetHost(aURI, host);
     542               6 :     if (NS_FAILED(rv)) return NS_OK;
     543                 : 
     544                 :     nsSTSHostEntry *entry;
     545                 :     PRUint32 actualExactPermission;
     546               6 :     PRUint32 offset = 0;
     547               6 :     PRInt64 now = PR_Now() / 1000;
     548                 : 
     549                 :     // Used for testing permissions as we walk up the domain tree.
     550              12 :     nsCOMPtr<nsIURI> domainWalkURI;
     551                 : 
     552                 :     // In parallel, loop over private mode cache and also the real permission
     553                 :     // manager--ignoring any masked as "deleted" in the local cache. We have
     554                 :     // to do this here since the most specific permission in *either* the
     555                 :     // permission manager or mPrivateModeHostTable should be used.
     556               3 :     do {
     557               6 :       entry = mPrivateModeHostTable.GetEntry(host.get() + offset);
     558               6 :       STSLOG(("Checking PM Table entry and permmgr for %s", host.get()+offset));
     559                 : 
     560                 :       // flag as deleted any entries encountered that have expired.  We only
     561                 :       // flag the nsSTSHostEntry because there could be some data in the
     562                 :       // permission manager that -- if not in private mode -- would have been
     563                 :       // overwritten by newly encountered STS data.
     564               6 :       if (entry && (now > entry->mExpireTime)) {
     565               0 :         STSLOG(("Deleting expired PM Table entry for %s", host.get()+offset));
     566               0 :         entry->mDeleted = true;
     567               0 :         entry->mIncludeSubdomains = false;
     568                 :       }
     569                 : 
     570               6 :       rv = NS_NewURI(getter_AddRefs(domainWalkURI),
     571              12 :                       NS_LITERAL_CSTRING("http://") + Substring(host, offset));
     572               6 :       NS_ENSURE_SUCCESS(rv, rv);
     573                 : 
     574               6 :       rv = mPermMgr->TestExactPermission(domainWalkURI,
     575                 :                                           aType,
     576               6 :                                           &actualExactPermission);
     577               6 :       NS_ENSURE_SUCCESS(rv, rv);
     578                 : 
     579                 :       // There are three cases as we walk up the hostname testing
     580                 :       // permissions:
     581                 :       // 1. There's no entry in mPrivateModeHostTable for this host; rely
     582                 :       // on data in the permission manager
     583               6 :       if (!entry) {
     584               6 :         if (actualExactPermission != nsIPermissionManager::UNKNOWN_ACTION) {
     585                 :           // no cached data but a permission in the permission manager so use
     586                 :           // it and stop looking.
     587               0 :           *aPermission = actualExactPermission;
     588               0 :           STSLOG(("no PM Table entry for %s, using permmgr", host.get()+offset));
     589               0 :           break;
     590                 :         }
     591                 :       }
     592                 :       // 2. There's a "deleted" mask in mPrivateModeHostTable for this host
     593                 :       // or we're looking for includeSubdomain information and it's not set:
     594                 :       // any data in the permission manager must be ignored, since the
     595                 :       // permission would have been deleted if not in private mode.
     596               0 :       else if (entry->mDeleted || (strcmp(aType, STS_SUBDOMAIN_PERMISSION) == 0
     597               0 :                                   && !entry->mIncludeSubdomains)) {
     598               0 :         STSLOG(("no entry at all for %s, walking up", host.get()+offset));
     599                 :         // keep looking
     600                 :       }
     601                 :       // 3. There's a non-deleted entry in mPrivateModeHostTable for this
     602                 :       // host, so it should be used.
     603                 :       else {
     604                 :         // All STS permissions' values are ALLOW_ACTION or they are not
     605                 :         // known (as in, not set or turned off).
     606               0 :         *aPermission = nsIPermissionManager::ALLOW_ACTION;
     607               0 :         STSLOG(("PM Table entry for %s: forcing", host.get()+offset));
     608               0 :         break;
     609                 :       }
     610                 : 
     611                 :       // Don't continue walking up the host segments if the test was for an
     612                 :       // exact match only.
     613               6 :       if (testExact) break;
     614                 : 
     615               3 :       STSLOG(("no PM Table entry or permmgr data for %s, walking up domain",
     616                 :               host.get()+offset));
     617                 :       // walk up the host segments
     618               3 :       offset = host.FindChar('.', offset) + 1;
     619                 :     } while (offset > 0);
     620                 : 
     621                 :     // Use whatever we ended up with, which defaults to UNKNOWN_ACTION.
     622               6 :     return NS_OK;
     623            4392 : }

Generated by: LCOV version 1.7