+// StorageManager is responsible for silently switching to newer-style keychains.
+// If the keychain requested is in ~/Library/Keychains/, and there is a
+// newer keychain available (with extension ".keychain-db"), open that one
+// instead of the one requested.
+//
+// Because of backwards compatibility reasons, we can't update the plist
+// files on disk to point to the upgraded keychains. We will be asked to
+// load "/Users/account/Library/Keychains/login.keychain", hence this
+// modification to 'login.keychain-db'.
+DLDbIdentifier
+StorageManager::mungeDLDbIdentifier(const DLDbIdentifier& dLDbIdentifier, bool isReset) {
+ if(!dLDbIdentifier.dbName()) {
+ // If this DLDbIdentifier doesn't have a filename, don't munge it
+ return dLDbIdentifier;
+ }
+
+ string path = dLDbIdentifier.dbName();
+
+ bool shouldCreateProtected = globals().integrityProtection();
+
+ // If we don't have a DLDbIdentifier, we can't return one
+ if(dLDbIdentifier.mImpl == NULL) {
+ return DLDbIdentifier();
+ }
+
+ // Ensure we're in ~/Library/Keychains
+ if(pathInHomeLibraryKeychains(path)) {
+ string pathdb = makeKeychainDbFilename(path);
+
+ struct stat st;
+
+ int path_stat_err = 0;
+ bool path_exists = (::stat(path.c_str(), &st) == 0);
+ if(!path_exists) {
+ path_stat_err = errno;
+ }
+
+ int pathdb_stat_err = 0;
+ bool pathdb_exists = (::stat(pathdb.c_str(), &st) == 0);
+ if(!pathdb_exists) {
+ pathdb_stat_err = errno;
+ }
+
+ // If protections are off, don't change the requested filename.
+ // If protictions are on and the -db file exists, always use it.
+ //
+ // If we're resetting, and we're creating a new-style keychain, use the -db path.
+ // If we're resetting, and we're creating an old-style keychain, use the original path.
+ //
+ // Protection pathdb_exists path_exists resetting Result
+ // DISABLED X X X original
+ // ENABLED 1 X X -db
+ // ENABLED 0 0 X -db
+ // ENABLED 0 1 0 original
+ // ENABLED 0 1 1 -db
+ //
+ bool switchPaths = shouldCreateProtected && (pathdb_exists || (!pathdb_exists && !path_exists) || isReset);
+
+ if(switchPaths) {
+ secinfo("integrity", "switching to keychain-db: %s from %s (%d %d %d_%d %d_%d)", pathdb.c_str(), path.c_str(), isReset, shouldCreateProtected, path_exists, path_stat_err, pathdb_exists, pathdb_stat_err);
+ path = pathdb;
+ } else {
+ secinfo("integrity", "not switching: %s from %s (%d %d %d_%d %d_%d)", pathdb.c_str(), path.c_str(), isReset, shouldCreateProtected, path_exists, path_stat_err, pathdb_exists, pathdb_stat_err);
+ }
+ }
+
+ DLDbIdentifier id(dLDbIdentifier.ssuid(), path.c_str(), dLDbIdentifier.dbLocation());
+ return id;
+}
+
+DLDbIdentifier
+StorageManager::forceMungeDLDbIDentifier(const DLDbIdentifier& dLDbIdentifier) {
+ if(!dLDbIdentifier.dbName() || dLDbIdentifier.mImpl == NULL) {
+ return dLDbIdentifier;
+ }
+
+ string path = dLDbIdentifier.dbName();
+ string pathdb = makeKeychainDbFilename(path);
+
+ DLDbIdentifier id(dLDbIdentifier.ssuid(), pathdb.c_str(), dLDbIdentifier.dbLocation());
+ return id;
+}
+
+DLDbIdentifier
+StorageManager::demungeDLDbIdentifier(const DLDbIdentifier& dLDbIdentifier) {
+ if(dLDbIdentifier.dbName() == NULL) {
+ return dLDbIdentifier;
+ }
+
+ string path = dLDbIdentifier.dbName();
+ string dbSuffix = "-db";
+ bool endsWithKeychainDb = (path.size() > dbSuffix.size() && (0 == path.compare(path.size() - dbSuffix.size(), dbSuffix.size(), dbSuffix)));
+
+ // Ensure we're in ~/Library/Keychains, and that the path ends in "-db"
+ if(pathInHomeLibraryKeychains(path) && endsWithKeychainDb) {
+ // remove "-db" from the end.
+ path.erase(path.end() - 3, path.end());
+ }
+
+ DLDbIdentifier id(dLDbIdentifier.ssuid(), path.c_str(), dLDbIdentifier.dbLocation());
+ return id;
+}
+
+string
+StorageManager::makeKeychainDbFilename(const string& filename) {
+ string keychainDbSuffix = "-db";
+ bool endsWithKeychainDb = (filename.size() > keychainDbSuffix.size() && (0 == filename.compare(filename.size() - keychainDbSuffix.size(), keychainDbSuffix.size(), keychainDbSuffix)));
+
+ if(endsWithKeychainDb) {
+ return filename;
+ } else {
+ return filename + keychainDbSuffix;
+ }
+}
+
+bool
+StorageManager::pathInHomeLibraryKeychains(const string& path) {
+ return SecurityServer::CommonBlob::pathInHomeLibraryKeychains(path);
+}
+