From 377f2f0496e88713fe576d9b47378150d4005655 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 11 Jun 2019 02:03:11 +0200 Subject: TunnelsManager: store UID on macOS for keychain availability Signed-off-by: Jason A. Donenfeld --- .../Model/NETunnelProviderProtocol+Extension.swift | 29 +++++++++++--- WireGuard/WireGuard/Tunnel/TunnelsManager.swift | 46 ++++++++++------------ WireGuard/WireGuard/UI/macOS/StatusMenu.swift | 2 +- .../ManageTunnelsRootViewController.swift | 2 +- 4 files changed, 45 insertions(+), 34 deletions(-) (limited to 'WireGuard') diff --git a/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift b/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift index 856df1f..7828d81 100644 --- a/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift +++ b/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift @@ -22,6 +22,9 @@ extension NETunnelProviderProtocol { if passwordReference == nil { return nil } + #if os(macOS) + providerConfiguration = ["UID": getuid()] + #endif let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint } if endpoints.count == 1 { @@ -60,11 +63,25 @@ extension NETunnelProviderProtocol { * in the keychain. But it's still useful to keep the migration * around so that .mobileconfig files are easier. */ - guard let oldConfig = providerConfiguration?["WgQuickConfig"] as? String else { return false } - providerConfiguration = nil - guard passwordReference == nil else { return true } - wg_log(.debug, message: "Migrating tunnel configuration '\(name)'") - passwordReference = Keychain.makeReference(containing: oldConfig, called: name) - return true + if let oldConfig = providerConfiguration?["WgQuickConfig"] as? String { + #if os(macOS) + providerConfiguration = ["UID": getuid()] + #elseif os(iOS) + providerConfiguration = nil + #else + #error("Unimplemented") + #endif + guard passwordReference == nil else { return true } + wg_log(.debug, message: "Migrating tunnel configuration '\(name)'") + passwordReference = Keychain.makeReference(containing: oldConfig, called: name) + return true + } + #if os(macOS) + if passwordReference != nil && providerConfiguration?["UID"] == nil && verifyConfigurationReference() { + providerConfiguration = ["UID": getuid()] + return true + } + #endif + return false } } diff --git a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift index c43fa50..ec1ea74 100644 --- a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift +++ b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift @@ -58,7 +58,12 @@ class TunnelsManager { #if os(iOS) let passwordRef = proto.verifyConfigurationReference() ? proto.passwordReference : nil #elseif os(macOS) - let passwordRef = proto.passwordReference // To handle multiple users in macOS, we skip verifying + let passwordRef: Data? + if proto.providerConfiguration?["UID"] as? uid_t == getuid() { + passwordRef = proto.verifyConfigurationReference() ? proto.passwordReference : nil + } else { + passwordRef = proto.passwordReference // To handle multiple users in macOS, we skip verifying + } #else #error("Unimplemented") #endif @@ -262,10 +267,15 @@ class TunnelsManager { func remove(tunnel: TunnelContainer, completionHandler: @escaping (TunnelsManagerError?) -> Void) { let tunnelProviderManager = tunnel.tunnelProvider - if tunnel.isTunnelConfigurationAvailableInKeychain { + #if os(macOS) + if tunnel.isTunnelAvailableToUser { (tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference() } - + #elseif os(iOS) + (tunnelProviderManager.protocolConfiguration as? NETunnelProviderProtocol)?.destroyConfigurationReference() + #else + #error("Unimplemented") + #endif tunnelProviderManager.removeFromPreferences { [weak self] error in guard error == nil else { wg_log(.error, message: "Remove: Saving configuration failed: \(error!)") @@ -493,14 +503,16 @@ class TunnelContainer: NSObject { return tunnelProvider.tunnelConfiguration } - var isTunnelConfigurationAvailableInKeychain: Bool { - return tunnelProvider.isTunnelConfigurationAvailableInKeychain - } - var onDemandOption: ActivateOnDemandOption { return ActivateOnDemandOption(from: tunnelProvider) } + #if os(macOS) + var isTunnelAvailableToUser: Bool { + return (tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol)?.providerConfiguration?["UID"] as? uid_t == getuid() + } + #endif + init(tunnel: NETunnelProviderManager) { name = tunnel.localizedDescription ?? "Unnamed" let status = TunnelStatus(from: tunnel.connection.status) @@ -609,18 +621,8 @@ class TunnelContainer: NSObject { } extension NETunnelProviderManager { - private static var cachedIsConfigAvailableInKeychainKey: UInt8 = 0 private static var cachedConfigKey: UInt8 = 0 - var isTunnelConfigurationAvailableInKeychain: Bool { - if let cachedNumber = objc_getAssociatedObject(self, &NETunnelProviderManager.cachedIsConfigAvailableInKeychainKey) as? NSNumber { - return cachedNumber.boolValue - } - let isAvailable = (protocolConfiguration as? NETunnelProviderProtocol)?.verifyConfigurationReference() ?? false - objc_setAssociatedObject(self, &NETunnelProviderManager.cachedIsConfigAvailableInKeychainKey, NSNumber(value: isAvailable), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) - return isAvailable - } - var tunnelConfiguration: TunnelConfiguration? { if let cached = objc_getAssociatedObject(self, &NETunnelProviderManager.cachedConfigKey) as? TunnelConfiguration { return cached @@ -636,17 +638,9 @@ extension NETunnelProviderManager { protocolConfiguration = NETunnelProviderProtocol(tunnelConfiguration: tunnelConfiguration, previouslyFrom: protocolConfiguration) localizedDescription = tunnelConfiguration.name objc_setAssociatedObject(self, &NETunnelProviderManager.cachedConfigKey, tunnelConfiguration, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) - objc_setAssociatedObject(self, &NETunnelProviderManager.cachedIsConfigAvailableInKeychainKey, NSNumber(value: true), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } func isEquivalentTo(_ tunnel: TunnelContainer) -> Bool { - switch (isTunnelConfigurationAvailableInKeychain, tunnel.isTunnelConfigurationAvailableInKeychain) { - case (true, true): - return tunnelConfiguration == tunnel.tunnelConfiguration - case (false, false): - return localizedDescription == tunnel.name - default: - return false - } + return localizedDescription == tunnel.name && tunnelConfiguration == tunnel.tunnelConfiguration } } diff --git a/WireGuard/WireGuard/UI/macOS/StatusMenu.swift b/WireGuard/WireGuard/UI/macOS/StatusMenu.swift index f4f999d..ec9ffe8 100644 --- a/WireGuard/WireGuard/UI/macOS/StatusMenu.swift +++ b/WireGuard/WireGuard/UI/macOS/StatusMenu.swift @@ -168,7 +168,7 @@ extension StatusMenu { func insertTunnelMenuItem(for tunnel: TunnelContainer, at tunnelIndex: Int) { let menuItem = TunnelMenuItem(tunnel: tunnel, action: #selector(tunnelClicked(sender:))) menuItem.target = self - menuItem.isHidden = !tunnel.isTunnelConfigurationAvailableInKeychain + menuItem.isHidden = !tunnel.isTunnelAvailableToUser insertItem(menuItem, at: firstTunnelMenuItemIndex + tunnelIndex) if numberOfTunnelMenuItems == 0 { insertItem(NSMenuItem.separator(), at: firstTunnelMenuItemIndex + tunnelIndex + 1) diff --git a/WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift b/WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift index 179387f..0ad0805 100644 --- a/WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift +++ b/WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift @@ -81,7 +81,7 @@ extension ManageTunnelsRootViewController: TunnelsListTableViewControllerDelegat assert(!tunnelIndices.isEmpty) if tunnelIndices.count == 1 { let tunnel = tunnelsManager.tunnel(at: tunnelIndices.first!) - if tunnel.isTunnelConfigurationAvailableInKeychain { + if tunnel.isTunnelAvailableToUser { let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel) setTunnelDetailContentVC(tunnelDetailVC) self.tunnelDetailVC = tunnelDetailVC -- cgit v1.2.3-59-g8ed1b