Я не устаю ссылаться на книгу “Mac OS X Internals. A Systems Approach“, которую мне посоветовал alexmak. Эта книга – очень достойный источник информации для желающих разобраться в работе Mac OS X.

Сегодня я хочу продемонстрировать пример из книги, показывающий работу с Disk Arbitration (я надеюсь, что приводя пример, я способствую увеличению количества читателей этой книги; также я написал Amit Singh, автору книги с просьбой дать разрешение на использование на сайте его кода).

Подсистема Disk Arbitration управляет дисками и образами дисков. Она содержит демон diskarbitrationd и фреймворк DiskArbitration.framework, используя который, можно взаимодействовать с демоном. diskarbitrationd выполняет такие задачи:

  • обрабатывает подключенные к системе диски на предмет возможности монтирования разделов
  • уведомляет клиентов, подписанных на нотификации, о появлении и исчезновении дисков и разделов
  • выступает арбитром, разрешающим или запрещающим доступ к дискам

Ранее я описал, как можно отключить возможность подключения внешних USB-носителей, удаляя соответствующий модуль kext. Но более правильный метод основан как раз на взаимодействии с diskarbitrationd. Привожу пример из книги:

// dissent_mount.c
#include 

#define OUT_ON_NULL(ptr, msg) \
   if (!ptr) { fprintf(stderr, "%s\n", msg); goto out; }

DADissenterRef
mountApprovalCallback(DADiskRef disk, void *context)
{
   // В ответ на любой запрос монтирования выдать запрет
   DADissenterRef dissenter = DADissenterCreate(kCFAllocatorDefault,
      kDAReturnNotPermitted,
      CFSTR("mount disallowed"));
   printf("%s: mount disallowed\n", DADiskGetBSDName(disk));
   return dissenter;
}

int main(void)
{
   DAApprovalSessionRef session = DAApprovalSessionCreate(kCFAllocatorDefault);
   OUT_ON_NULL(session, "failed to create Disk Arbitration session");
   // Зарегистрировать callback-функцию, вызываемую при монтировании
   DARegisterDiskMountApprovalCallback(session,
      NULL, // matches all disk objects
      mountApprovalCallback,
      NULL); // context
   DAApprovalSessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(),
      kCFRunLoopDefaultMode);
   // Программа работает 30 секунд, после чего производится выход
   CFRunLoopRunInMode(kCFRunLoopDefaultMode, 30 /* seconds */, false);
   DAApprovalSessionUnscheduleFromRunLoop(session, CFRunLoopGetCurrent(),
      kCFRunLoopDefaultMode);
   DAUnregisterApprovalCallback(session, mountApprovalCallback, NULL);

out:
   if (session)
      CFRelease(session);

   exit(0);
}

Компиляция:

$ gcc -Wall -o dissent_mount dissent_mount.c \
   -framework DiskArbitration -framework CoreFoundation

Запуск:

$ ./dissent_mount
disk3s2: mount disallowed
disk3s2: mount disallowed

Программа запускается на 30 секунд и не даёт ничего смонтировать, пока она работает. Например, те же USB-диски подключить будет невозможно. В качестве развития программы можно выборочно анализировать тип подключаемых дисков, и, допустим, разрешать монтировать образы, но запрещать монтировать диски. Также можно запустить программу при старте системы, в итоге пользователи без административных прав не смогут её отключить.

Более жёсткий метод борьбы с монтированием приводится на Mac OS X Forensics. Нет запущенного diskarbitrationd – нет проблемы:

$ sudo launchctl unload \
   /System/Library/LaunchDaemons/com.apple.diskarbitrationd.plist