darwin: add authorization for device capture

To use USBDeviceReEnumerate with kUSBReEnumerateCaptureDeviceMask your app
either needs to be running as root OR have the 'com.apple.vm.device-access'
entitlement AND have the user authorization requested via
IOServiceAuthorize().

We can use the capture re-enumerate APIs if either 1) the process is running
as root or 2) the 'com.apple.vm.device-access' entitlement is used AND
IOServiceAuthorize() is called. We assume that if the entitlement is not
there then we are running as root--if this is not true, then
darwin_detach_kernel_driver will fail anyways.

The authorization status is cached in the device's start() so we have to
stop() and start() the device by destroying the plugin and recreating it
again.

Signed-off-by: Nathan Hjelm <hjelmn@google.com>
diff --git a/Xcode/libusb.xcodeproj/project.pbxproj b/Xcode/libusb.xcodeproj/project.pbxproj
index fcda7e2..958e256 100644
--- a/Xcode/libusb.xcodeproj/project.pbxproj
+++ b/Xcode/libusb.xcodeproj/project.pbxproj
@@ -66,6 +66,32 @@
 		20951C0625630F8F00ED6351 /* ezusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFDD1628BA0E00BC5BE2 /* ezusb.h */; };
 		20951C0F25630FD300ED6351 /* libusb_testlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 008A23CA236C849A004854AA /* libusb_testlib.h */; };
 		20951C152563125200ED6351 /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; };
+		CEA0F5EF26321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; };
+		CEA0F5F026321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; };
+		CEA0F5F126321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; };
+		CEA0F5F226321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
+		CEA0F5F326321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; };
+		CEA0F5F426321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; };
+		CEA0F5F526321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
+		CEA0F5F626321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; };
+		CEA0F5F726321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; };
+		CEA0F5F826321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
+		CEA0F5F926321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; };
+		CEA0F5FA26321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; };
+		CEA0F5FB26321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
+		CEA0F5FC26321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; };
+		CEA0F5FD26321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; };
+		CEA0F5FE26321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
+		CEA0F5FF26321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; };
+		CEA0F60026321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; };
+		CEA0F60126321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
+		CEA0F60226321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; };
+		CEA0F60326321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; };
+		CEA0F60426321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
+		CEA0F60526321FAA00ADF3EC /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBFA41628B84200BC5BE2 /* config.h */; };
+		CEA0F60626321FAA00ADF3EC /* libusb.h in Headers */ = {isa = PBXBuildFile; fileRef = 008FBF5A1628B7E800BC5BE2 /* libusb.h */; };
+		CEA0F60726321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 008FBF311628B79300BC5BE2 /* libusb-1.0.0.dylib */; };
+		CEA45DFB2634CDFA002FA97D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEDCEA6E2632200A00F7AA49 /* Security.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -254,6 +280,7 @@
 		20468D6E243298C100650534 /* sam3u_benchmark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sam3u_benchmark.c; sourceTree = "<group>"; usesTabs = 1; };
 		20468D75243298D300650534 /* testlibusb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testlibusb; sourceTree = BUILT_PRODUCTS_DIR; };
 		20468D7C2432990000650534 /* testlibusb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testlibusb.c; sourceTree = "<group>"; usesTabs = 1; };
+		CEDCEA6E2632200A00F7AA49 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -261,7 +288,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */,
+				CEA0F5F826321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -269,7 +296,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */,
+				CEA0F60126321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -279,6 +306,7 @@
 			files = (
 				008FBFAB1628B8CB00BC5BE2 /* libobjc.dylib in Frameworks */,
 				008FBFA91628B88000BC5BE2 /* IOKit.framework in Frameworks */,
+				CEA45DFB2634CDFA002FA97D /* Security.framework in Frameworks */,
 				008FBFA71628B87000BC5BE2 /* CoreFoundation.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -287,7 +315,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */,
+				CEA0F60726321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -303,7 +331,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */,
+				CEA0F5F226321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -311,7 +339,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */,
+				CEA0F5F526321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -319,7 +347,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */,
+				CEA0F5FB26321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -327,7 +355,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */,
+				CEA0F5FE26321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -335,7 +363,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				006AD4261C8C5AD9007F8C6A /* libusb-1.0.0.dylib in Frameworks */,
+				CEA0F60426321FAA00ADF3EC /* libusb-1.0.0.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -453,6 +481,7 @@
 				008FBFAA1628B8CB00BC5BE2 /* libobjc.dylib */,
 				008FBFA81628B88000BC5BE2 /* IOKit.framework */,
 				008FBFA61628B87000BC5BE2 /* CoreFoundation.framework */,
+				CEDCEA6E2632200A00F7AA49 /* Security.framework */,
 			);
 			name = Apple;
 			path = ../libusb;
@@ -481,7 +510,7 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				008FBFA51628B84200BC5BE2 /* config.h in Headers */,
+				CEA0F5EF26321FAA00ADF3EC /* config.h in Headers */,
 				20951C152563125200ED6351 /* libusb.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -490,8 +519,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				008FBFA51628B84200BC5BE2 /* config.h in Headers */,
-				20951C152563125200ED6351 /* libusb.h in Headers */,
+				CEA0F5F026321FAA00ADF3EC /* config.h in Headers */,
+				CEA0F5F126321FAA00ADF3EC /* libusb.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -499,9 +528,9 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				008FBFA51628B84200BC5BE2 /* config.h in Headers */,
+				CEA0F5F326321FAA00ADF3EC /* config.h in Headers */,
 				20951C0625630F8F00ED6351 /* ezusb.h in Headers */,
-				20951C152563125200ED6351 /* libusb.h in Headers */,
+				CEA0F5F426321FAA00ADF3EC /* libusb.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -509,8 +538,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				008FBFA51628B84200BC5BE2 /* config.h in Headers */,
-				20951C152563125200ED6351 /* libusb.h in Headers */,
+				CEA0F5F626321FAA00ADF3EC /* config.h in Headers */,
+				CEA0F5F726321FAA00ADF3EC /* libusb.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -518,8 +547,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				008FBFA51628B84200BC5BE2 /* config.h in Headers */,
-				20951C152563125200ED6351 /* libusb.h in Headers */,
+				CEA0F5F926321FAA00ADF3EC /* config.h in Headers */,
+				CEA0F5FA26321FAA00ADF3EC /* libusb.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -527,8 +556,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				008FBFA51628B84200BC5BE2 /* config.h in Headers */,
-				20951C152563125200ED6351 /* libusb.h in Headers */,
+				CEA0F5FC26321FAA00ADF3EC /* config.h in Headers */,
+				CEA0F5FD26321FAA00ADF3EC /* libusb.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -536,9 +565,9 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				008FBFA51628B84200BC5BE2 /* config.h in Headers */,
+				CEA0F5FF26321FAA00ADF3EC /* config.h in Headers */,
 				20951C0F25630FD300ED6351 /* libusb_testlib.h in Headers */,
-				20951C152563125200ED6351 /* libusb.h in Headers */,
+				CEA0F60026321FAA00ADF3EC /* libusb.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -546,8 +575,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				008FBFA51628B84200BC5BE2 /* config.h in Headers */,
-				20951C152563125200ED6351 /* libusb.h in Headers */,
+				CEA0F60226321FAA00ADF3EC /* config.h in Headers */,
+				CEA0F60326321FAA00ADF3EC /* libusb.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -555,8 +584,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				008FBFA51628B84200BC5BE2 /* config.h in Headers */,
-				20951C152563125200ED6351 /* libusb.h in Headers */,
+				CEA0F60526321FAA00ADF3EC /* config.h in Headers */,
+				CEA0F60626321FAA00ADF3EC /* libusb.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/configure.ac b/configure.ac
index 7c86598..5899fc2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -161,7 +161,7 @@
 case $backend in
 darwin)
 	AC_CHECK_FUNCS([pthread_threadid_np])
-	LIBS="${LIBS} -lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation"
+	LIBS="${LIBS} -lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation -Wl,-framework,Security"
 	;;
 haiku)
 	LIBS="${LIBS} -lbe"
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index 988ca9e..2e64038 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -172,6 +172,7 @@
       (*(cached_dev->device))->Release(cached_dev->device);
       cached_dev->device = NULL;
     }
+    IOObjectRelease (cached_dev->service);
     free (cached_dev);
   }
 }
@@ -1057,6 +1058,9 @@
       (*device)->GetLocationID (device, &new_device->location);
       new_device->port = port;
       new_device->parent_session = parent_sessionID;
+    } else {
+      /* release the ref to old device's service */
+      IOObjectRelease (new_device->service);
     }
 
     /* keep track of devices regardless of if we successfully enumerate them to
@@ -1065,6 +1069,10 @@
 
     new_device->session = sessionID;
     new_device->device = device;
+    new_device->service = service;
+
+    /* retain the service */
+    IOObjectRetain (service);
 
     /* cache the device descriptor */
     ret = darwin_cache_device_descriptor(new_device);
@@ -2294,6 +2302,34 @@
 
 #if InterfaceVersion >= 700
 
+/* macOS APIs for getting entitlement values */
+
+#if TARGET_OS_OSX
+#include <Security/Security.h>
+#else
+typedef struct __SecTask *SecTaskRef;
+extern SecTaskRef SecTaskCreateFromSelf(CFAllocatorRef allocator);
+extern CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error);
+#endif
+
+static bool darwin_has_capture_entitlements (void) {
+  SecTaskRef task;
+  CFTypeRef value;
+  bool entitled;
+
+  task = SecTaskCreateFromSelf (kCFAllocatorDefault);
+  if (task == NULL) {
+    return false;
+  }
+  value = SecTaskCopyValueForEntitlement(task, CFSTR("com.apple.vm.device-access"), NULL);
+  CFRelease (task);
+  entitled = value && (CFGetTypeID (value) == CFBooleanGetTypeID ()) && CFBooleanGetValue (value);
+  if (value) {
+    CFRelease (value);
+  }
+  return entitled;
+}
+
 static int darwin_reload_device (struct libusb_device_handle *dev_handle) {
   struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
   enum libusb_error err;
@@ -2325,6 +2361,19 @@
   }
 
   if (dpriv->capture_count == 0) {
+    /* request authorization */
+    if (darwin_has_capture_entitlements ()) {
+      kresult = IOServiceAuthorize (dpriv->service, kIOServiceInteractionAllowed);
+      if (kresult != kIOReturnSuccess) {
+        usbi_err (HANDLE_CTX (dev_handle), "IOServiceAuthorize: %s", darwin_error_str(kresult));
+        return darwin_to_libusb (kresult);
+      }
+      /* we need start() to be called again for authorization status to refresh */
+      err = darwin_reload_device (dev_handle);
+      if (err != LIBUSB_SUCCESS) {
+        return err;
+      }
+    }
     /* reset device to release existing drivers */
     err = darwin_reenumerate_device (dev_handle, true);
     if (err != LIBUSB_SUCCESS) {
diff --git a/libusb/os/darwin_usb.h b/libusb/os/darwin_usb.h
index 179341c..201dc36 100644
--- a/libusb/os/darwin_usb.h
+++ b/libusb/os/darwin_usb.h
@@ -171,6 +171,7 @@
   USBDeviceAddress      address;
   char                  sys_path[21];
   usb_device_t        **device;
+  io_service_t          service;
   int                   open_count;
   UInt8                 first_config, active_config, port;
   int                   can_enumerate;
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index fcbf3cd..7d8c211 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11612
+#define LIBUSB_NANO 11613