From 0e0eb5f41fe5f80385e83132972f9c00cb0b61cb Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 19 Oct 2020 12:08:13 +0200 Subject: [PATCH] Added permission checks for mac audio backend. --- channels/audin/client/mac/CMakeLists.txt | 5 +- .../client/mac/{audin_mac.c => audin_mac.m} | 103 +++++++++++++----- client/Mac/Info.plist | 4 + client/Mac/cli/Info.plist | 4 + 4 files changed, 85 insertions(+), 31 deletions(-) rename channels/audin/client/mac/{audin_mac.c => audin_mac.m} (78%) diff --git a/channels/audin/client/mac/CMakeLists.txt b/channels/audin/client/mac/CMakeLists.txt index b4c695fcf..f07e9f000 100644 --- a/channels/audin/client/mac/CMakeLists.txt +++ b/channels/audin/client/mac/CMakeLists.txt @@ -18,17 +18,18 @@ define_channel_client_subsystem("audin" "mac" "") FIND_LIBRARY(CORE_AUDIO CoreAudio) +FIND_LIBRARY(AVFOUNDATION AVFoundation) FIND_LIBRARY(AUDIO_TOOL AudioToolbox) FIND_LIBRARY(APP_SERVICES ApplicationServices) set(${MODULE_PREFIX}_SRCS - audin_mac.c) + audin_mac.m) include_directories(..) include_directories(${MAC_INCLUDE_DIRS}) add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") -set(${MODULE_PREFIX}_LIBS freerdp ${CORE_AUDIO} ${AUDIO_TOOL} ${APP_SERVICES} winpr) +set(${MODULE_PREFIX}_LIBS freerdp ${AVFOUNDATION} ${CORE_AUDIO} ${AUDIO_TOOL} ${APP_SERVICES} winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/audin/client/mac/audin_mac.c b/channels/audin/client/mac/audin_mac.m similarity index 78% rename from channels/audin/client/mac/audin_mac.c rename to channels/audin/client/mac/audin_mac.m index e34b83528..8d3bf1995 100644 --- a/channels/audin/client/mac/audin_mac.c +++ b/channels/audin/client/mac/audin_mac.m @@ -33,12 +33,14 @@ #include #include +#import + #define __COREFOUNDATION_CFPLUGINCOM__ 1 #define IUNKNOWN_C_GUTS \ - void* _reserved; \ - void* QueryInterface; \ - void* AddRef; \ - void* Release + void *_reserved; \ + void *QueryInterface; \ + void *AddRef; \ + void *Release #include #include @@ -72,17 +74,18 @@ typedef struct _AudinMacDevice int dev_unit; AudinReceive receive; - void* user_data; + void *user_data; - rdpContext* rdpcontext; + rdpContext *rdpcontext; + bool isAuthorized; bool isOpen; AudioQueueRef audioQueue; AudioStreamBasicDescription audioFormat; AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; } AudinMacDevice; -static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT* format) +static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT *format) { switch (format->wFormatTag) { @@ -94,7 +97,7 @@ static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT* format) } } -static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT* format) +static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT *format) { switch (format->wFormatTag) { @@ -106,10 +109,14 @@ static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT* forma } } -static BOOL audin_mac_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) +static BOOL audin_mac_format_supported(IAudinDevice *device, const AUDIO_FORMAT *format) { + AudinMacDevice *mac = (AudinMacDevice *)device; AudioFormatID req_fmt = 0; + if (!mac->isAuthorized) + return FALSE; + if (device == NULL || format == NULL) return FALSE; @@ -126,10 +133,13 @@ static BOOL audin_mac_format_supported(IAudinDevice* device, const AUDIO_FORMAT* * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, +static UINT audin_mac_set_format(IAudinDevice *device, const AUDIO_FORMAT *format, UINT32 FramesPerPacket) { - AudinMacDevice* mac = (AudinMacDevice*)device; + AudinMacDevice *mac = (AudinMacDevice *)device; + + if (!mac->isAuthorized) + return ERROR_INTERNAL_ERROR; if (device == NULL || format == NULL) return ERROR_INVALID_PARAMETER; @@ -155,13 +165,13 @@ static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* forma return CHANNEL_RC_OK; } -static void mac_audio_queue_input_cb(void* aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, - const AudioTimeStamp* inStartTime, UInt32 inNumPackets, - const AudioStreamPacketDescription* inPacketDesc) +static void mac_audio_queue_input_cb(void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, + const AudioTimeStamp *inStartTime, UInt32 inNumPackets, + const AudioStreamPacketDescription *inPacketDesc) { - AudinMacDevice* mac = (AudinMacDevice*)aqData; + AudinMacDevice *mac = (AudinMacDevice *)aqData; UINT error = CHANNEL_RC_OK; - const BYTE* buffer = inBuffer->mAudioData; + const BYTE *buffer = inBuffer->mAudioData; int buffer_size = inBuffer->mAudioDataByteSize; (void)inAQ; (void)inStartTime; @@ -180,12 +190,15 @@ static void mac_audio_queue_input_cb(void* aqData, AudioQueueRef inAQ, AudioQueu } } -static UINT audin_mac_close(IAudinDevice* device) +static UINT audin_mac_close(IAudinDevice *device) { UINT errCode = CHANNEL_RC_OK; char errString[1024]; OSStatus devStat; - AudinMacDevice* mac = (AudinMacDevice*)device; + AudinMacDevice *mac = (AudinMacDevice *)device; + + if (!mac->isAuthorized) + return ERROR_INTERNAL_ERROR; if (device == NULL) return ERROR_INVALID_PARAMETER; @@ -223,13 +236,17 @@ static UINT audin_mac_close(IAudinDevice* device) return errCode; } -static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* user_data) +static UINT audin_mac_open(IAudinDevice *device, AudinReceive receive, void *user_data) { - AudinMacDevice* mac = (AudinMacDevice*)device; + AudinMacDevice *mac = (AudinMacDevice *)device; DWORD errCode; char errString[1024]; OSStatus devStat; size_t index; + + if (!mac->isAuthorized) + return ERROR_INTERNAL_ERROR; + mac->receive = receive; mac->user_data = user_data; devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, mac, NULL, @@ -285,9 +302,9 @@ err_out: return CHANNEL_RC_INITIALIZATION_ERROR; } -static UINT audin_mac_free(IAudinDevice* device) +static UINT audin_mac_free(IAudinDevice *device) { - AudinMacDevice* mac = (AudinMacDevice*)device; + AudinMacDevice *mac = (AudinMacDevice *)device; int error; if (device == NULL) @@ -302,19 +319,19 @@ static UINT audin_mac_free(IAudinDevice* device) return CHANNEL_RC_OK; } -static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args) +static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args) { DWORD errCode; char errString[1024]; int status; char *str_num, *eptr; DWORD flags; - COMMAND_LINE_ARGUMENT_A* arg; + COMMAND_LINE_ARGUMENT_A *arg; COMMAND_LINE_ARGUMENT_A audin_mac_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; - AudinMacDevice* mac = (AudinMacDevice*)device; + AudinMacDevice *mac = (AudinMacDevice *)device; if (args->argc == 1) return CHANNEL_RC_OK; @@ -369,10 +386,10 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn { DWORD errCode; char errString[1024]; - ADDIN_ARGV* args; - AudinMacDevice* mac; + ADDIN_ARGV *args; + AudinMacDevice *mac; UINT error; - mac = (AudinMacDevice*)calloc(1, sizeof(AudinMacDevice)); + mac = (AudinMacDevice *)calloc(1, sizeof(AudinMacDevice)); if (!mac) { @@ -397,12 +414,40 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn goto error_out; } - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)mac))) + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice *)mac))) { WLog_ERR(TAG, "RegisterAudinDevice failed with error %" PRIu32 "!", error); goto error_out; } + AVAuthorizationStatus status = + [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + switch (status) + { + case AVAuthorizationStatusAuthorized: + mac->isAuthorized = TRUE; + break; + case AVAuthorizationStatusNotDetermined: + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo + completionHandler:^(BOOL granted) { + if (granted == YES) + { + mac->isAuthorized = TRUE; + } + else + WLog_WARN(TAG, "Microphone access denied by user"); + }]; + break; + case AVAuthorizationStatusRestricted: + WLog_WARN(TAG, "Microphone access restricted by policy"); + break; + case AVAuthorizationStatusDenied: + WLog_WARN(TAG, "Microphone access denied by policy"); + break; + default: + break; + } + return CHANNEL_RC_OK; error_out: free(mac); diff --git a/client/Mac/Info.plist b/client/Mac/Info.plist index 2b552b421..fd111db68 100644 --- a/client/Mac/Info.plist +++ b/client/Mac/Info.plist @@ -2,6 +2,10 @@ + NSCameraUsageDescription + This application requires camera access to redirect it to the remote host + NSMicrophoneUsageDescription + This application requires microphone access to redirect it to the remote host CFBundleDevelopmentRegion English CFBundleIconFile diff --git a/client/Mac/cli/Info.plist b/client/Mac/cli/Info.plist index cb6976502..198a14461 100644 --- a/client/Mac/cli/Info.plist +++ b/client/Mac/cli/Info.plist @@ -2,6 +2,10 @@ + NSCameraUsageDescription + This application requires camera access to redirect it to the remote host + NSMicrophoneUsageDescription + This application requires microphone access to redirect it to the remote host CFBundleDevelopmentRegion en CFBundleExecutable