]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
TunnelsManager: store UID on macOS for keychain availability
authorJason A. Donenfeld <Jason@zx2c4.com>
Tue, 11 Jun 2019 00:03:11 +0000 (02:03 +0200)
committerJason A. Donenfeld <Jason@zx2c4.com>
Tue, 11 Jun 2019 00:18:42 +0000 (02:18 +0200)
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift
WireGuard/WireGuard/Tunnel/TunnelsManager.swift
WireGuard/WireGuard/UI/macOS/StatusMenu.swift
WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift

index 856df1f3ae611e3657fedc591ba18c925856c341..7828d81a822b0ee56b708fba0ccb8bf34877d3e6 100644 (file)
@@ -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
     }
 }
index c43fa50aef09a5001224f41169ea9d15b5fed147..ec1ea7489b79922bcf14f3fa12df3b3195accf6b 100644 (file)
@@ -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
     }
 }
index f4f999df6b7d8495286273bf18589b4f9c6163fa..ec9ffe88c5327bfdcbbfc9e046a7bf674e9e9861 100644 (file)
@@ -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)
index 179387f1ac268a1955827310b4984ab6d6f95ed9..0ad080532421fef0e4c9eb161c5ba2ab4459d0ab 100644 (file)
@@ -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