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