+ if (!err) {
+ len = s->getLength();
+ *propertiesCnt = len;
+ err = copyoutkdata( s->text(), len, properties );
+ }
+
+ s->release();
+ return( err );
+}
+
+#if CONFIG_MACF
+
+struct GetPropertiesEditorRef
+{
+ kauth_cred_t cred;
+ IORegistryEntry * entry;
+ OSCollection * root;
+};
+
+static const OSMetaClassBase *
+GetPropertiesEditor(void * reference,
+ OSSerialize * s,
+ OSCollection * container,
+ const OSSymbol * name,
+ const OSMetaClassBase * value)
+{
+ GetPropertiesEditorRef * ref = (typeof(ref)) reference;
+
+ if (!ref->root) ref->root = container;
+ if (ref->root == container)
+ {
+ if (0 != mac_iokit_check_get_property(ref->cred, ref->entry, name->getCStringNoCopy()))
+ {
+ value = 0;
+ }
+ }
+ if (value) value->retain();
+ return (value);
+}
+
+#endif /* CONFIG_MACF */
+
+/* Routine io_registry_entry_get_properties */
+kern_return_t is_io_registry_entry_get_properties_bin(
+ io_object_t registry_entry,
+ io_buf_ptr_t *properties,
+ mach_msg_type_number_t *propertiesCnt)
+{
+ kern_return_t err = kIOReturnSuccess;
+ vm_size_t len;
+ OSSerialize * s;
+ OSSerialize::Editor editor = 0;
+ void * editRef = 0;
+
+ CHECK(IORegistryEntry, registry_entry, entry);
+
+#if CONFIG_MACF
+ GetPropertiesEditorRef ref;
+ if (mac_iokit_check_filter_properties(kauth_cred_get(), entry))
+ {
+ editor = &GetPropertiesEditor;
+ editRef = &ref;
+ ref.cred = kauth_cred_get();
+ ref.entry = entry;
+ ref.root = 0;
+ }
+#endif
+
+ s = OSSerialize::binaryWithCapacity(4096, editor, editRef);
+ if (!s) return (kIOReturnNoMemory);
+
+ if (!entry->serializeProperties(s)) err = kIOReturnUnsupported;
+
+ if (kIOReturnSuccess == err)
+ {
+ len = s->getLength();
+ *propertiesCnt = len;
+ err = copyoutkdata(s->text(), len, properties);
+ }
+ s->release();
+
+ return (err);
+}
+
+/* Routine io_registry_entry_get_property_bin */
+kern_return_t is_io_registry_entry_get_property_bin(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_name_t property_name,
+ uint32_t options,
+ io_buf_ptr_t *properties,
+ mach_msg_type_number_t *propertiesCnt )
+{
+ kern_return_t err;
+ vm_size_t len;
+ OSObject * obj;
+ const OSSymbol * sym;
+
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+#if CONFIG_MACF
+ if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name))
+ return kIOReturnNotPermitted;
+#endif
+
+ if ((kIORegistryIterateRecursively & options) && plane[0])
+ {
+ obj = entry->copyProperty(property_name,
+ IORegistryEntry::getPlane(plane), options);
+ }
+ else
+ {
+ obj = entry->copyProperty(property_name);
+ }
+
+ if( !obj)
+ return( kIOReturnNotFound );
+
+ sym = OSSymbol::withCString(property_name);
+ if (sym)
+ {
+ if (gIORemoveOnReadProperties->containsObject(sym)) entry->removeProperty(sym);
+ sym->release();
+ }
+
+ OSSerialize * s = OSSerialize::binaryWithCapacity(4096);
+ if( !s) {
+ obj->release();
+ return( kIOReturnNoMemory );
+ }
+
+ if( obj->serialize( s )) {
+ len = s->getLength();
+ *propertiesCnt = len;
+ err = copyoutkdata( s->text(), len, properties );
+
+ } else err = kIOReturnUnsupported;
+
+ s->release();
+ obj->release();
+
+ return( err );
+}
+
+/* Routine io_registry_entry_set_properties */
+kern_return_t is_io_registry_entry_set_properties
+(
+ io_object_t registry_entry,
+ io_buf_ptr_t properties,
+ mach_msg_type_number_t propertiesCnt,
+ kern_return_t * result)
+{
+ OSObject * obj;
+ kern_return_t err;
+ IOReturn res;
+ vm_offset_t data;
+ vm_map_offset_t map_data;
+
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ if( propertiesCnt > sizeof(io_struct_inband_t) * 1024)
+ return( kIOReturnMessageTooLarge);
+
+ err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
+ data = CAST_DOWN(vm_offset_t, map_data);
+
+ if( KERN_SUCCESS == err) {
+
+ // must return success after vm_map_copyout() succeeds
+ obj = OSUnserializeXML( (const char *) data, propertiesCnt );
+ vm_deallocate( kernel_map, data, propertiesCnt );
+
+ if (!obj)
+ res = kIOReturnBadArgument;
+#if CONFIG_MACF
+ else if (0 != mac_iokit_check_set_properties(kauth_cred_get(),
+ registry_entry, obj))
+ {
+ res = kIOReturnNotPermitted;
+ }
+#endif
+ else
+ {
+ res = entry->setProperties( obj );
+ }
+
+ if (obj)
+ obj->release();
+ } else
+ res = err;
+
+ *result = res;
+ return( err );
+}
+
+/* Routine io_registry_entry_get_child_iterator */
+kern_return_t is_io_registry_entry_get_child_iterator(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_object_t *iterator )
+{
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ *iterator = entry->getChildIterator(
+ IORegistryEntry::getPlane( plane ));
+
+ return( kIOReturnSuccess );
+}
+
+/* Routine io_registry_entry_get_parent_iterator */
+kern_return_t is_io_registry_entry_get_parent_iterator(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_object_t *iterator)
+{
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ *iterator = entry->getParentIterator(
+ IORegistryEntry::getPlane( plane ));
+
+ return( kIOReturnSuccess );
+}
+
+/* Routine io_service_get_busy_state */
+kern_return_t is_io_service_get_busy_state(
+ io_object_t _service,
+ uint32_t *busyState )
+{
+ CHECK( IOService, _service, service );
+
+ *busyState = service->getBusyState();
+
+ return( kIOReturnSuccess );
+}
+
+/* Routine io_service_get_state */
+kern_return_t is_io_service_get_state(
+ io_object_t _service,
+ uint64_t *state,
+ uint32_t *busy_state,
+ uint64_t *accumulated_busy_time )
+{
+ CHECK( IOService, _service, service );
+
+ *state = service->getState();
+ *busy_state = service->getBusyState();
+ *accumulated_busy_time = service->getAccumulatedBusyTime();
+
+ return( kIOReturnSuccess );
+}
+
+/* Routine io_service_wait_quiet */
+kern_return_t is_io_service_wait_quiet(
+ io_object_t _service,
+ mach_timespec_t wait_time )
+{
+ uint64_t timeoutNS;
+
+ CHECK( IOService, _service, service );
+
+ timeoutNS = wait_time.tv_sec;
+ timeoutNS *= kSecondScale;
+ timeoutNS += wait_time.tv_nsec;
+
+ return( service->waitQuiet(timeoutNS) );
+}
+
+/* Routine io_service_request_probe */
+kern_return_t is_io_service_request_probe(
+ io_object_t _service,
+ uint32_t options )
+{
+ CHECK( IOService, _service, service );
+
+ return( service->requestProbe( options ));
+}
+
+/* Routine io_service_get_authorization_id */
+kern_return_t is_io_service_get_authorization_id(
+ io_object_t _service,
+ uint64_t *authorization_id )
+{
+ kern_return_t kr;
+
+ CHECK( IOService, _service, service );
+
+ kr = IOUserClient::clientHasPrivilege( (void *) current_task(),
+ kIOClientPrivilegeAdministrator );
+ if( kIOReturnSuccess != kr)
+ return( kr );
+
+ *authorization_id = service->getAuthorizationID();
+
+ return( kr );
+}
+
+/* Routine io_service_set_authorization_id */
+kern_return_t is_io_service_set_authorization_id(
+ io_object_t _service,
+ uint64_t authorization_id )
+{
+ CHECK( IOService, _service, service );
+
+ return( service->setAuthorizationID( authorization_id ) );
+}
+
+/* Routine io_service_open_ndr */
+kern_return_t is_io_service_open_extended(
+ io_object_t _service,
+ task_t owningTask,
+ uint32_t connect_type,
+ NDR_record_t ndr,
+ io_buf_ptr_t properties,
+ mach_msg_type_number_t propertiesCnt,
+ kern_return_t * result,
+ io_object_t *connection )
+{
+ IOUserClient * client = 0;
+ kern_return_t err = KERN_SUCCESS;
+ IOReturn res = kIOReturnSuccess;
+ OSDictionary * propertiesDict = 0;
+ bool crossEndian;
+ bool disallowAccess;
+
+ CHECK( IOService, _service, service );
+
+ do
+ {
+ if (properties)
+ {
+ OSObject * obj;
+ vm_offset_t data;
+ vm_map_offset_t map_data;
+
+ if( propertiesCnt > sizeof(io_struct_inband_t))
+ return( kIOReturnMessageTooLarge);
+
+ err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
+ res = err;
+ data = CAST_DOWN(vm_offset_t, map_data);
+ if (KERN_SUCCESS == err)
+ {
+ // must return success after vm_map_copyout() succeeds
+ obj = OSUnserializeXML( (const char *) data, propertiesCnt );
+ vm_deallocate( kernel_map, data, propertiesCnt );
+ propertiesDict = OSDynamicCast(OSDictionary, obj);
+ if (!propertiesDict)
+ {
+ res = kIOReturnBadArgument;
+ if (obj)
+ obj->release();
+ }
+ }
+ if (kIOReturnSuccess != res)
+ break;
+ }
+
+ crossEndian = (ndr.int_rep != NDR_record.int_rep);
+ if (crossEndian)
+ {
+ if (!propertiesDict)
+ propertiesDict = OSDictionary::withCapacity(4);
+ OSData * data = OSData::withBytes(&ndr, sizeof(ndr));
+ if (data)
+ {
+ if (propertiesDict)
+ propertiesDict->setObject(kIOUserClientCrossEndianKey, data);
+ data->release();
+ }
+ }
+
+ res = service->newUserClient( owningTask, (void *) owningTask,
+ connect_type, propertiesDict, &client );
+
+ if (propertiesDict)
+ propertiesDict->release();
+
+ if (res == kIOReturnSuccess)
+ {
+ assert( OSDynamicCast(IOUserClient, client) );
+
+ disallowAccess = (crossEndian
+ && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
+ && (kOSBooleanTrue != client->getProperty(kIOUserClientCrossEndianCompatibleKey)));
+ if (disallowAccess) res = kIOReturnUnsupported;
+#if CONFIG_MACF
+ else if (0 != mac_iokit_check_open(kauth_cred_get(), client, connect_type))
+ res = kIOReturnNotPermitted;
+#endif
+ if (kIOReturnSuccess != res)
+ {
+ IOStatisticsClientCall();
+ client->clientClose();
+ client->release();
+ client = 0;
+ break;
+ }
+ client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey));
+ OSString * creatorName = IOCopyLogNameForPID(proc_selfpid());
+ if (creatorName)
+ {
+ client->setProperty(kIOUserClientCreatorKey, creatorName);
+ creatorName->release();
+ }
+ client->setTerminateDefer(service, false);
+ }
+ }
+ while (false);
+
+ *connection = client;
+ *result = res;
+
+ return (err);
+}