Я не устаю ссылаться на книгу “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