1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef nsPermissionManager_h__ 8 #define nsPermissionManager_h__ 9 10 #include "nsIPermissionManager.h" 11 #include "nsIObserver.h" 12 #include "nsWeakReference.h" 13 #include "nsCOMPtr.h" 14 #include "nsIInputStream.h" 15 #include "nsTHashtable.h" 16 #include "nsTArray.h" 17 #include "nsString.h" 18 #include "nsPermission.h" 19 #include "nsIPrefBranch.h" 20 #include "nsHashKeys.h" 21 #include "nsCOMArray.h" 22 #include "nsDataHashtable.h" 23 #include "nsIRunnable.h" 24 #include "nsRefPtrHashtable.h" 25 #include "mozilla/MozPromise.h" 26 27 namespace mozilla { 28 class OriginAttributesPattern; 29 } 30 31 class nsIPermission; 32 class mozIStorageConnection; 33 class mozIStorageAsyncStatement; 34 35 //////////////////////////////////////////////////////////////////////////////// 36 37 class nsPermissionManager final : public nsIPermissionManager, 38 public nsIObserver, 39 public nsSupportsWeakReference { 40 public: 41 class PermissionEntry { 42 public: PermissionEntry(int64_t aID,uint32_t aType,uint32_t aPermission,uint32_t aExpireType,int64_t aExpireTime,int64_t aModificationTime)43 PermissionEntry(int64_t aID, uint32_t aType, uint32_t aPermission, 44 uint32_t aExpireType, int64_t aExpireTime, 45 int64_t aModificationTime) 46 : mID(aID), 47 mType(aType), 48 mPermission(aPermission), 49 mExpireType(aExpireType), 50 mExpireTime(aExpireTime), 51 mModificationTime(aModificationTime), 52 mNonSessionPermission(aPermission), 53 mNonSessionExpireType(aExpireType), 54 mNonSessionExpireTime(aExpireTime) {} 55 56 int64_t mID; 57 uint32_t mType; 58 uint32_t mPermission; 59 uint32_t mExpireType; 60 int64_t mExpireTime; 61 int64_t mModificationTime; 62 uint32_t mNonSessionPermission; 63 uint32_t mNonSessionExpireType; 64 uint32_t mNonSessionExpireTime; 65 }; 66 67 /** 68 * PermissionKey is the key used by PermissionHashKey hash table. 69 * 70 * NOTE: It could be implementing nsIHashable but there is no reason to worry 71 * with XPCOM interfaces while we don't need to. 72 */ 73 class PermissionKey { 74 public: 75 static PermissionKey* CreateFromPrincipal(nsIPrincipal* aPrincipal, 76 nsresult& aResult); 77 static PermissionKey* CreateFromURI(nsIURI* aURI, nsresult& aResult); 78 PermissionKey(const nsACString & aOrigin)79 explicit PermissionKey(const nsACString& aOrigin) : mOrigin(aOrigin) {} 80 81 bool operator==(const PermissionKey& aKey) const { 82 return mOrigin.Equals(aKey.mOrigin); 83 } 84 GetHashCode()85 PLDHashNumber GetHashCode() const { return mozilla::HashString(mOrigin); } 86 87 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PermissionKey) 88 89 nsCString mOrigin; 90 91 private: 92 // Default ctor shouldn't be used. 93 PermissionKey() = delete; 94 95 // Dtor shouldn't be used outside of the class. ~PermissionKey()96 ~PermissionKey(){}; 97 }; 98 99 class PermissionHashKey : public nsRefPtrHashKey<PermissionKey> { 100 public: PermissionHashKey(const PermissionKey * aPermissionKey)101 explicit PermissionHashKey(const PermissionKey* aPermissionKey) 102 : nsRefPtrHashKey<PermissionKey>(aPermissionKey) {} 103 PermissionHashKey(PermissionHashKey && toCopy)104 PermissionHashKey(PermissionHashKey&& toCopy) 105 : nsRefPtrHashKey<PermissionKey>(mozilla::Move(toCopy)), 106 mPermissions(mozilla::Move(toCopy.mPermissions)) {} 107 KeyEquals(const PermissionKey * aKey)108 bool KeyEquals(const PermissionKey* aKey) const { 109 return *aKey == *GetKey(); 110 } 111 HashKey(const PermissionKey * aKey)112 static PLDHashNumber HashKey(const PermissionKey* aKey) { 113 return aKey->GetHashCode(); 114 } 115 116 // Force the hashtable to use the copy constructor when shuffling entries 117 // around, otherwise the Auto part of our AutoTArray won't be happy! 118 enum { ALLOW_MEMMOVE = false }; 119 GetPermissions()120 inline nsTArray<PermissionEntry>& GetPermissions() { return mPermissions; } 121 GetPermissionIndex(uint32_t aType)122 inline int32_t GetPermissionIndex(uint32_t aType) const { 123 for (uint32_t i = 0; i < mPermissions.Length(); ++i) 124 if (mPermissions[i].mType == aType) return i; 125 126 return -1; 127 } 128 GetPermission(uint32_t aType)129 inline PermissionEntry GetPermission(uint32_t aType) const { 130 for (uint32_t i = 0; i < mPermissions.Length(); ++i) 131 if (mPermissions[i].mType == aType) return mPermissions[i]; 132 133 // unknown permission... return relevant data 134 return PermissionEntry(-1, aType, nsIPermissionManager::UNKNOWN_ACTION, 135 nsIPermissionManager::EXPIRE_NEVER, 0, 0); 136 } 137 138 private: 139 AutoTArray<PermissionEntry, 1> mPermissions; 140 }; 141 142 // nsISupports 143 NS_DECL_ISUPPORTS 144 NS_DECL_NSIPERMISSIONMANAGER 145 NS_DECL_NSIOBSERVER 146 147 nsPermissionManager(); 148 static already_AddRefed<nsIPermissionManager> GetXPCOMSingleton(); 149 nsresult Init(); 150 151 // enums for AddInternal() 152 enum OperationType { 153 eOperationNone, 154 eOperationAdding, 155 eOperationRemoving, 156 eOperationChanging, 157 eOperationReplacingDefault 158 }; 159 160 enum DBOperationType { eNoDBOperation, eWriteToDB }; 161 162 enum NotifyOperationType { eDontNotify, eNotify }; 163 164 // A special value for a permission ID that indicates the ID was loaded as 165 // a default value. These will never be written to the database, but may 166 // be overridden with an explicit permission (including UNKNOWN_ACTION) 167 static const int64_t cIDPermissionIsDefault = -1; 168 169 nsresult AddInternal(nsIPrincipal* aPrincipal, const nsCString& aType, 170 uint32_t aPermission, int64_t aID, uint32_t aExpireType, 171 int64_t aExpireTime, int64_t aModificationTime, 172 NotifyOperationType aNotifyOperation, 173 DBOperationType aDBOperation, 174 const bool aIgnoreSessionPermissions = false); 175 176 /** 177 * Initialize the "clear-origin-attributes-data" observing. 178 * Will create a nsPermissionManager instance if needed. 179 * That way, we can prevent have nsPermissionManager created at startup just 180 * to be able to clear data when an application is uninstalled. 181 */ 182 static void ClearOriginDataObserverInit(); 183 184 nsresult RemovePermissionsWithAttributes( 185 mozilla::OriginAttributesPattern& aAttrs); 186 187 /** 188 * See `nsIPermissionManager::GetPermissionsWithKey` for more info on 189 * permission keys. 190 * 191 * Get the permission key corresponding to the given Principal. This method is 192 * intentionally infallible, as we want to provide an permission key to every 193 * principal. Principals which don't have meaningful URIs with http://, 194 * https://, or ftp:// schemes are given the default "" Permission Key. 195 * 196 * @param aPrincipal The Principal which the key is to be extracted from. 197 * @param aPermissionKey A string which will be filled with the permission 198 * key. 199 */ 200 static void GetKeyForPrincipal(nsIPrincipal* aPrincipal, 201 nsACString& aPermissionKey); 202 203 /** 204 * See `nsIPermissionManager::GetPermissionsWithKey` for more info on 205 * permission keys. 206 * 207 * Get the permission key corresponding to the given Origin. This method is 208 * like GetKeyForPrincipal, except that it avoids creating a nsIPrincipal 209 * object when you already have access to an origin string. 210 * 211 * If this method is passed a nonsensical origin string it may produce a 212 * nonsensical permission key result. 213 * 214 * @param aOrigin The origin which the key is to be extracted from. 215 * @param aPermissionKey A string which will be filled with the permission 216 * key. 217 */ 218 static void GetKeyForOrigin(const nsACString& aOrigin, 219 nsACString& aPermissionKey); 220 221 /** 222 * See `nsIPermissionManager::GetPermissionsWithKey` for more info on 223 * permission keys. 224 * 225 * Get the permission key corresponding to the given Principal and type. This 226 * method is intentionally infallible, as we want to provide an permission key 227 * to every principal. Principals which don't have meaningful URIs with 228 * http://, https://, or ftp:// schemes are given the default "" Permission 229 * Key. 230 * 231 * This method is different from GetKeyForPrincipal in that it also takes 232 * permissions which must be sent down before loading a document into account. 233 * 234 * @param aPrincipal The Principal which the key is to be extracted from. 235 * @param aType The type of the permission to get the key for. 236 * @param aPermissionKey A string which will be filled with the permission 237 * key. 238 */ 239 static void GetKeyForPermission(nsIPrincipal* aPrincipal, const char* aType, 240 nsACString& aPermissionKey); 241 242 /** 243 * See `nsIPermissionManager::GetPermissionsWithKey` for more info on 244 * permission keys. 245 * 246 * Get all permissions keys which could correspond to the given principal. 247 * This method, like GetKeyForPrincipal, is infallible and should always 248 * produce at least one key. 249 * 250 * Unlike GetKeyForPrincipal, this method also gets the keys for base domains 251 * of the given principal. All keys returned by this method must be available 252 * in the content process for a given URL to successfully have its permissions 253 * checked in the `aExactHostMatch = false` situation. 254 * 255 * @param aPrincipal The Principal which the key is to be extracted from. 256 */ 257 static nsTArray<nsCString> GetAllKeysForPrincipal(nsIPrincipal* aPrincipal); 258 259 private: 260 virtual ~nsPermissionManager(); 261 262 int32_t GetTypeIndex(const char* aTypeString, bool aAdd); 263 264 PermissionHashKey* GetPermissionHashKey(nsIPrincipal* aPrincipal, 265 uint32_t aType, bool aExactHostMatch); 266 PermissionHashKey* GetPermissionHashKey(nsIURI* aURI, uint32_t aType, 267 bool aExactHostMatch); 268 CommonTestPermission(nsIPrincipal * aPrincipal,const char * aType,uint32_t * aPermission,bool aExactHostMatch,bool aIncludingSession)269 nsresult CommonTestPermission(nsIPrincipal* aPrincipal, const char* aType, 270 uint32_t* aPermission, bool aExactHostMatch, 271 bool aIncludingSession) { 272 return CommonTestPermissionInternal(aPrincipal, nullptr, aType, aPermission, 273 aExactHostMatch, aIncludingSession); 274 } CommonTestPermission(nsIURI * aURI,const char * aType,uint32_t * aPermission,bool aExactHostMatch,bool aIncludingSession)275 nsresult CommonTestPermission(nsIURI* aURI, const char* aType, 276 uint32_t* aPermission, bool aExactHostMatch, 277 bool aIncludingSession) { 278 return CommonTestPermissionInternal(nullptr, aURI, aType, aPermission, 279 aExactHostMatch, aIncludingSession); 280 } 281 // Only one of aPrincipal or aURI is allowed to be passed in. 282 nsresult CommonTestPermissionInternal(nsIPrincipal* aPrincipal, nsIURI* aURI, 283 const char* aType, 284 uint32_t* aPermission, 285 bool aExactHostMatch, 286 bool aIncludingSession); 287 288 nsresult OpenDatabase(nsIFile* permissionsFile); 289 nsresult InitDB(bool aRemoveFile); 290 nsresult CreateTable(); 291 nsresult Import(); 292 nsresult ImportDefaults(); 293 nsresult _DoImport(nsIInputStream* inputStream, mozIStorageConnection* aConn); 294 nsresult Read(); 295 void NotifyObserversWithPermission(nsIPrincipal* aPrincipal, 296 const nsCString& aType, 297 uint32_t aPermission, uint32_t aExpireType, 298 int64_t aExpireTime, 299 const char16_t* aData); 300 void NotifyObservers(nsIPermission* aPermission, const char16_t* aData); 301 302 // Finalize all statements, close the DB and null it. 303 // if aRebuildOnSuccess, reinitialize database 304 void CloseDB(bool aRebuildOnSuccess = false); 305 306 nsresult RemoveAllInternal(bool aNotifyObservers); 307 nsresult RemoveAllFromMemory(); 308 static void UpdateDB(OperationType aOp, mozIStorageAsyncStatement* aStmt, 309 int64_t aID, const nsACString& aOrigin, 310 const nsACString& aType, uint32_t aPermission, 311 uint32_t aExpireType, int64_t aExpireTime, 312 int64_t aModificationTime); 313 314 /** 315 * This method removes all permissions modified after the specified time. 316 */ 317 nsresult RemoveAllModifiedSince(int64_t aModificationTime); 318 319 /** 320 * Returns false if this permission manager wouldn't have the permission 321 * requested available. 322 * 323 * If aType is nullptr, checks that the permission manager would have all 324 * permissions available for the given principal. 325 */ 326 bool PermissionAvailable(nsIPrincipal* aPrincipal, const char* aType); 327 328 nsRefPtrHashtable<nsCStringHashKey, mozilla::GenericPromise::Private> 329 mPermissionKeyPromiseMap; 330 331 nsCOMPtr<mozIStorageConnection> mDBConn; 332 nsCOMPtr<mozIStorageAsyncStatement> mStmtInsert; 333 nsCOMPtr<mozIStorageAsyncStatement> mStmtDelete; 334 nsCOMPtr<mozIStorageAsyncStatement> mStmtUpdate; 335 336 bool mMemoryOnlyDB; 337 338 nsTHashtable<PermissionHashKey> mPermissionTable; 339 // a unique, monotonically increasing id used to identify each database entry 340 int64_t mLargestID; 341 342 // An array to store the strings identifying the different types. 343 nsTArray<nsCString> mTypeArray; 344 345 // Initially, |false|. Set to |true| once shutdown has started, to avoid 346 // reopening the database. 347 bool mIsShuttingDown; 348 349 nsCOMPtr<nsIPrefBranch> mDefaultPrefBranch; 350 351 friend class DeleteFromMozHostListener; 352 friend class CloseDatabaseListener; 353 }; 354 355 // {4F6B5E00-0C36-11d5-A535-0010A401EB10} 356 #define NS_PERMISSIONMANAGER_CID \ 357 { \ 358 0x4f6b5e00, 0xc36, 0x11d5, { \ 359 0xa5, 0x35, 0x0, 0x10, 0xa4, 0x1, 0xeb, 0x10 \ 360 } \ 361 } 362 363 #endif /* nsPermissionManager_h__ */ 364