func LoadInfoRaw(kextID string) (map[interface{}]interface{}, error) { cfKextID, err := StringToCFString(kextID) if cfKextID != nil { defer Release(C.CFTypeRef(cfKextID)) } if err != nil { return nil, err } cfKextIDs := ArrayToCFArray([]C.CFTypeRef{C.CFTypeRef(cfKextID)}) if cfKextIDs != nil { defer Release(C.CFTypeRef(cfKextIDs)) } cfDict := C.KextManagerCopyLoadedKextInfo(cfKextIDs, nil) m, err := ConvertCFDictionary(cfDict) if err != nil { return nil, err } info, hasKey := m[kextID] if !hasKey { return nil, nil } var ret, cast = info.(map[interface{}]interface{}) if !cast { return nil, fmt.Errorf("Unexpected value for kext info") } return ret, nil }
// Given a PostScript font name the function will attempt to load a matching // font and return a font object back to the caller. // // If no font with the given name is found a font that most closely resembles // what was requested will be returned instead based on the platform's fallback // mechanism. // More details on the mechanism can be found at: // https://developer.apple.com/library/mac/documentation/Carbon/Reference/CTFontRef/#//apple_ref/c/func/CTFontCreateWithName // // The function returns an error if loading the font failed for any reason. func NewFontWithName(fontName string) (font *Font, err error) { cfname := GoStringToCFString(fontName) defer C.CFRelease(C.CFTypeRef(cfname)) font = &Font{ ref: C.CTFontCreateWithName(cfname, 0.0, nil), } if font.ref == nil { err = fmt.Errorf("CoreText failed to craete a CTFontRef object with name '%s'", fontName) return } runtime.SetFinalizer(font, (*Font).release) name := C.CTFontCopyPostScriptName(font.ref) defer C.CFRelease(C.CFTypeRef(name)) family := C.CTFontCopyFamilyName(font.ref) defer C.CFRelease(C.CFTypeRef(family)) display := C.CTFontCopyDisplayName(font.ref) defer C.CFRelease(C.CFTypeRef(display)) font.name = CFStringToGoString(name) font.family = CFStringToGoString(family) font.display = CFStringToGoString(display) return }
func loadSystemRoots() (*CertPool, error) { roots := NewCertPool() var data C.CFDataRef = nil var untrustedData C.CFDataRef = nil err := C.FetchPEMRoots(&data, &untrustedData) if err == -1 { // TODO: better error message return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo") } defer C.CFRelease(C.CFTypeRef(data)) buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) roots.AppendCertsFromPEM(buf) if untrustedData == nil { return roots, nil } defer C.CFRelease(C.CFTypeRef(untrustedData)) buf = C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(untrustedData)), C.int(C.CFDataGetLength(untrustedData))) untrustedRoots := NewCertPool() untrustedRoots.AppendCertsFromPEM(buf) trustedRoots := NewCertPool() for _, c := range roots.certs { if !untrustedRoots.contains(c) { trustedRoots.AddCert(c) } } return trustedRoots, nil }
// ExportFromKeychain ... func ExportFromKeychain(itemRefsToExport []C.CFTypeRef, outputFilePath string, isAskForPassword bool) error { passphraseCString := C.CString("") defer C.free(unsafe.Pointer(passphraseCString)) var exportedData C.CFDataRef var exportParams C.SecItemImportExportKeyParameters exportParams.keyUsage = nil exportParams.keyAttributes = nil exportParams.version = C.SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION if isAskForPassword { exportParams.flags = C.kSecKeySecurePassphrase exportParams.passphrase = nil exportParams.alertTitle = nil promptText := C.CString("Enter a password which will be used to protect the exported items") defer C.free(unsafe.Pointer(promptText)) exportParams.alertPrompt = convertCStringToCFString(promptText) } else { exportParams.flags = 0 exportParams.passphrase = (C.CFTypeRef)(convertCStringToCFString(passphraseCString)) exportParams.alertTitle = nil exportParams.alertPrompt = nil } // create a C array from the input ptr := (*unsafe.Pointer)(&itemRefsToExport[0]) cfArrayForExport := C.CFArrayCreate( C.kCFAllocatorDefault, ptr, C.CFIndex(len(itemRefsToExport)), &C.kCFTypeArrayCallBacks) // do the export! status := C.SecItemExport(C.CFTypeRef(cfArrayForExport), C.kSecFormatPKCS12, 0, //C.kSecItemPemArmour, // Use kSecItemPemArmour to add PEM armour - the .p12 generated by Keychain Access.app does NOT have PEM armour &exportParams, &exportedData) if status != C.errSecSuccess { return fmt.Errorf("SecItemExport: error (OSStatus): %d", status) } // exportedData now contains your PKCS12 data // make sure it'll be released properly! defer C.CFRelease(C.CFTypeRef(exportedData)) dataBytes := convertCFDataRefToGoBytes(exportedData) if dataBytes == nil || len(dataBytes) < 1 { return errors.New("ExportFromKeychain: failed to convert export data - nil or empty") } if err := fileutil.WriteBytesToFile(outputFilePath, dataBytes); err != nil { return fmt.Errorf("ExportFromKeychain: failed to write into file: %s", err) } log.Debug("Export - success") return nil }
// ===== CFBoolean ===== func convertBoolToCFBoolean(b bool) C.CFBooleanRef { // I don't think the CFBoolean constants have retain counts, // but just in case lets call CFRetain on them if b { return C.CFBooleanRef(C.CFRetain(C.CFTypeRef(C.kCFBooleanTrue))) } return C.CFBooleanRef(C.CFRetain(C.CFTypeRef(C.kCFBooleanFalse))) }
// GetAllAccountNames returns a list of all account names for the // given service name in the default keychain. func GetAllAccountNames(serviceName string) (accountNames []string, err error) { var serviceNameString C.CFStringRef if serviceNameString, err = _UTF8StringToCFString(serviceName); err != nil { return } defer C.CFRelease(C.CFTypeRef(serviceNameString)) query := map[C.CFTypeRef]C.CFTypeRef{ secClass: secClassGenericPassword, secAttrService: C.CFTypeRef(serviceNameString), secMatchLimit: secMatchLimitAll, secReturnAttributes: C.CFTypeRef(C.kCFBooleanTrue), } queryDict := mapToCFDictionary(query) defer C.CFRelease(C.CFTypeRef(queryDict)) var resultsRef C.CFTypeRef errCode := C.SecItemCopyMatching(queryDict, &resultsRef) err = newKeychainError(errCode) if err == ErrItemNotFound { return []string{}, nil } else if err != nil { return nil, err } defer C.CFRelease(resultsRef) // The resultsRef should always be an array (because kSecReturnAttributes is true) // but it's a good sanity check and useful if want to support kSecReturnRef in the future. typeID := C.CFGetTypeID(resultsRef) if typeID != C.CFArrayGetTypeID() { typeDesc := C.CFCopyTypeIDDescription(typeID) defer C.CFRelease(C.CFTypeRef(typeDesc)) err = fmt.Errorf("Invalid result type: %s", _CFStringToUTF8String(typeDesc)) return } results := _CFArrayToArray(C.CFArrayRef(resultsRef)) for _, result := range results { m := _CFDictionaryToMap(C.CFDictionaryRef(result)) resultServiceName := _CFStringToUTF8String(C.CFStringRef(m[secAttrService])) if resultServiceName != serviceName { err = fmt.Errorf("Expected service name %s, got %s", serviceName, resultServiceName) return } accountName := _CFStringToUTF8String(C.CFStringRef(m[secAttrAccount])) accountNames = append(accountNames, accountName) } return }
// UpdateItem updates the queryItem with the parameters from updateItem func UpdateItem(queryItem Item, updateItem Item) error { cfDict, err := ConvertMapToCFDictionary(queryItem.attr) if err != nil { return err } defer Release(C.CFTypeRef(cfDict)) cfDictUpdate, err := ConvertMapToCFDictionary(updateItem.attr) if err != nil { return err } defer Release(C.CFTypeRef(cfDictUpdate)) errCode := C.SecItemUpdate(cfDict, cfDictUpdate) err = checkError(errCode) return err }
func NewCFError(c C.CFErrorRef) *CFError { e := &CFError{ Domain: convertCFStringToString(C.CFErrorGetDomain(c)), Code: int(C.CFErrorGetCode(c)), } cfDict := C.CFErrorCopyUserInfo(c) defer C.CFRelease(C.CFTypeRef(cfDict)) if userInfo, err := convertCFDictionaryToMap(cfDict); err == nil { // on error, skip user info e.UserInfo = userInfo } cfStr := C.CFErrorCopyDescription(c) defer C.CFRelease(C.CFTypeRef(cfStr)) e.Description = convertCFStringToString(cfStr) return e }
func (w *Watcher) watchPath(path string, options *Options) error { path, _ = filepath.Abs(path) w.wmut.Lock() _, found := w.watches[path] w.wmut.Unlock() if !found { cPaths := C.ArrayCreateMutable(C.int(1)) defer C.CFRelease(C.CFTypeRef(cPaths)) cpath := C.CString(path) defer C.free(unsafe.Pointer(cpath)) str := C.CFStringCreateWithCString(nil, cpath, C.kCFStringEncodingUTF8) C.CFArrayAppendValue(cPaths, unsafe.Pointer(str)) context := C.FSEventStreamContext{info: unsafe.Pointer(&w.internalEvent)} latency := C.CFTimeInterval(0) if options != nil && options.Throttle { latency = C.CFTimeInterval(options.ThrottleDuration / time.Second) } stream := C.EventStreamCreate(&context, cPaths, C.kFSEventStreamEventIdSinceNow+(1<<64), latency) w.wmut.Lock() w.watches[path] = stream w.wmut.Unlock() C.FSEventStreamScheduleWithRunLoop(stream, w.rlref, C.kCFRunLoopDefaultMode) C.FSEventStreamStart(stream) } return nil }
// The returned SecAccessRef, if non-nil, must be released via CFRelease. func createEmptyAccess(label string) (C.SecAccessRef, error) { var err error var labelRef C.CFStringRef if labelRef, err = _UTF8StringToCFString(label); err != nil { return nil, err } defer C.CFRelease(C.CFTypeRef(labelRef)) var access C.SecAccessRef trustedApplicationsArray := arrayToCFArray([]C.CFTypeRef{}) defer C.CFRelease(C.CFTypeRef(trustedApplicationsArray)) if err = newKeychainError(C.SecAccessCreate(labelRef, trustedApplicationsArray, &access)); err != nil { return nil, err } return access, nil }
// DeleteItem removes a Item func DeleteItem(item Item) error { cfDict, err := convertAttr(item.attr) if err != nil { return err } defer C.CFRelease(C.CFTypeRef(cfDict)) errCode := C.SecItemDelete(cfDict) return checkError(errCode) }
// DeleteItem removes a Item func DeleteItem(item Item) error { cfDict, err := ConvertMapToCFDictionary(item.attr) if err != nil { return err } defer Release(C.CFTypeRef(cfDict)) errCode := C.SecItemDelete(cfDict) return checkError(errCode) }
func (self *Clipboard) addImage(img image.Image) (err error) { var i C.CGImageRef if i, err = CGImageCreateWithImage(img); err == nil { C.Clipboard_AddImage(self.ref, i) C.CFRelease(C.CFTypeRef(i)) } return }
// AddItem adds a Item func AddItem(item Item) error { cfDict, err := convertAttr(item.attr) if err != nil { return err } defer C.CFRelease(C.CFTypeRef(cfDict)) errCode := C.SecItemAdd(cfDict, nil) err = checkError(errCode) return err }
// FindAndRemoveGenericPassword finds a generic password with the // given attributes in the default keychain and removes it if // found. If not found, an error is returned. func FindAndRemoveGenericPassword(attributes *GenericPasswordAttributes) error { itemRef, err := findGenericPasswordItem(attributes) if err != nil { return err } defer C.CFRelease(C.CFTypeRef(itemRef)) errCode := C.SecKeychainItemDelete(itemRef) return newKeychainError(errCode) }
// Attributes provides metadata about the voice. // The attributes for a voice are described in the documentation for [NSSpeechSynthesizer attributesForVoice]. // This functionality is undocumented in the Carbon Speech Synthesis Manager. func (vs VoiceSpec) Attributes() (VoiceAttributes, error) { var va VoiceAttributes oserr := C.GetVoiceInfo((*C.VoiceSpec)(&vs), C.soVoiceAttributes, unsafe.Pointer(&va.cfd)) if oserr != 0 { return va, osError(oserr) } runtime.SetFinalizer(&va, func(va *VoiceAttributes) { C.CFRelease(C.CFTypeRef(va.cfd)) }) return va, nil }
func (ke keychainError) Error() string { errorMessageCFString := C.SecCopyErrorMessageString(C.OSStatus(ke), nil) defer C.CFRelease(C.CFTypeRef(errorMessageCFString)) errorMessageCString := C.CFStringGetCStringPtr(errorMessageCFString, C.kCFStringEncodingASCII) if errorMessageCString != nil { return C.GoString(errorMessageCString) } return fmt.Sprintf("keychainError with unknown error code %d", C.OSStatus(ke)) }
func iterateDevices(action func(device C.IOHIDDeviceRef) bool) cleanupDeviceManagerFn { mgr := C.IOHIDManagerCreate(C.kCFAllocatorDefault, C.kIOHIDOptionsTypeNone) C.IOHIDManagerSetDeviceMatching(mgr, nil) C.IOHIDManagerOpen(mgr, C.kIOHIDOptionsTypeNone) allDevicesSet := C.IOHIDManagerCopyDevices(mgr) defer C.CFRelease(C.CFTypeRef(allDevicesSet)) devCnt := C.CFSetGetCount(allDevicesSet) allDevices := make([]unsafe.Pointer, uint64(devCnt)) C.CFSetGetValues(allDevicesSet, &allDevices[0]) for _, pDev := range allDevices { if !action(C.IOHIDDeviceRef(pDev)) { break } } return func() { C.IOHIDManagerClose(mgr, C.kIOHIDOptionsTypeNone) C.CFRelease(C.CFTypeRef(mgr)) } }
// https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/Reference/reference.html#jumpTo_8 func (s Stream) Paths() []string { cpaths := C.FSEventStreamCopyPathsBeingWatched(s.cstream) defer C.CFRelease(C.CFTypeRef(cpaths)) count := C.CFArrayGetCount(cpaths) paths := make([]string, count) var i C.CFIndex for ; i < count; i++ { cpath := C.CFStringRef(C.CFArrayGetValueAtIndex(cpaths, i)) paths[i] = fromCFString(cpath) } return paths }
// AddGenericPassword adds a generic password with the given // attributes to the default keychain. func AddGenericPassword(attributes *GenericPasswordAttributes) (err error) { if err = attributes.CheckValidity(); err != nil { return } var serviceNameString C.CFStringRef if serviceNameString, err = _UTF8StringToCFString(attributes.ServiceName); err != nil { return } defer C.CFRelease(C.CFTypeRef(serviceNameString)) var accountNameString C.CFStringRef if accountNameString, err = _UTF8StringToCFString(attributes.AccountName); err != nil { return } defer C.CFRelease(C.CFTypeRef(accountNameString)) dataBytes := bytesToCFData(attributes.Password) defer C.CFRelease(C.CFTypeRef(dataBytes)) query := map[C.CFTypeRef]C.CFTypeRef{ secClass: secClassGenericPassword, secAttrService: C.CFTypeRef(serviceNameString), secAttrAccount: C.CFTypeRef(accountNameString), secValueData: C.CFTypeRef(dataBytes), } access, err := createAccess(attributes.ServiceName, attributes.TrustedApplications) if err != nil { return } if access != nil { defer C.CFRelease(C.CFTypeRef(access)) query[secAttrAccess] = C.CFTypeRef(access) } queryDict := mapToCFDictionary(query) defer C.CFRelease(C.CFTypeRef(queryDict)) errCode := C.SecItemAdd(queryDict, nil) err = newKeychainError(errCode) return }
func buildFont(f C.CTFontRef) []byte { ctags := C.CTFontCopyAvailableTables(f, C.kCTFontTableOptionExcludeSynthetic) tagsCount := C.CFArrayGetCount(ctags) var tags []uint32 var dataRefs []C.CFDataRef var dataLens []uint32 for i := C.CFIndex(0); i < tagsCount; i++ { tag := (C.CTFontTableTag)((uintptr)(C.CFArrayGetValueAtIndex(ctags, i))) dataRef := C.CTFontCopyTable(f, tag, 0) // retained tags = append(tags, uint32(tag)) dataRefs = append(dataRefs, dataRef) dataLens = append(dataLens, uint32(C.CFDataGetLength(dataRef))) } totalLen := 0 for _, l := range dataLens { totalLen += int(l) } // Big-endian output. buf := make([]byte, 0, 12+16*len(tags)+totalLen) write16 := func(x uint16) { buf = append(buf, byte(x>>8), byte(x)) } write32 := func(x uint32) { buf = append(buf, byte(x>>24), byte(x>>16), byte(x>>8), byte(x)) } // File format description: http://www.microsoft.com/typography/otspec/otff.htm write32(0x00010000) // version 1.0 write16(uint16(len(tags))) // numTables write16(0) // searchRange write16(0) // entrySelector write16(0) // rangeShift // Table tags, includes offsets into following data segments. offset := uint32(12 + 16*len(tags)) // offset starts after table tags for i, tag := range tags { write32(tag) write32(0) write32(offset) write32(dataLens[i]) offset += dataLens[i] } // Data segments. for i, dataRef := range dataRefs { data := (*[1<<31 - 2]byte)((unsafe.Pointer)(C.CFDataGetBytePtr(dataRef)))[:dataLens[i]] buf = append(buf, data...) C.CFRelease(C.CFTypeRef(dataRef)) } return buf }
func initDefaultRoots() { roots := x509.NewCertPool() var data C.CFDataRef = nil err := C.FetchPEMRoots(&data) if err != -1 { defer C.CFRelease(C.CFTypeRef(data)) buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) roots.AppendCertsFromPEM(buf) } varDefaultRoots = roots }
func Unload(kextID string) error { cfKextID, err := StringToCFString(kextID) if cfKextID != nil { defer Release(C.CFTypeRef(cfKextID)) } if err != nil { return err } ret := C.KextManagerUnloadKextWithIdentifier(cfKextID) if ret != 0 { return fmt.Errorf("Error unloading kext (%d)", ret) } return nil }
// Start listening to an event stream. func (es *EventStream) Start() { cPaths := C.ArrayCreateMutable(C.int(len(es.Paths))) defer C.CFRelease(C.CFTypeRef(cPaths)) for _, p := range es.Paths { p, _ = filepath.Abs(p) cpath := C.CString(p) defer C.free(unsafe.Pointer(cpath)) str := C.CFStringCreateWithCString(nil, cpath, C.kCFStringEncodingUTF8) C.CFArrayAppendValue(cPaths, unsafe.Pointer(str)) } since := C.FSEventStreamEventId(EventIDSinceNow) if es.Resume { since = C.FSEventStreamEventId(es.EventID) } if es.Events == nil { es.Events = make(chan []Event) } es.registryID = registry.Add(es) context := C.FSEventStreamContext{} info := C.uintptr_t(es.registryID) latency := C.CFTimeInterval(float64(es.Latency) / float64(time.Second)) if es.Device != 0 { es.stream = C.EventStreamCreateRelativeToDevice(&context, info, C.dev_t(es.Device), cPaths, since, latency, C.FSEventStreamCreateFlags(es.Flags)) } else { es.stream = C.EventStreamCreate(&context, info, cPaths, since, latency, C.FSEventStreamCreateFlags(es.Flags)) } started := make(chan struct{}) go func() { runtime.LockOSThread() es.rlref = C.CFRunLoopGetCurrent() C.FSEventStreamScheduleWithRunLoop(es.stream, es.rlref, C.kCFRunLoopDefaultMode) C.FSEventStreamStart(es.stream) close(started) C.CFRunLoopRun() }() if !es.hasFinalizer { runtime.SetFinalizer(es, finalizer) es.hasFinalizer = true } <-started }
func (dev *osxDevice) Close() { if !dev.disconnected { C.IOHIDDeviceClose(dev.osDevice, C.kIOHIDOptionsTypeSeizeDevice) dev.disconnected = true } if dev.osDevice != nil { C.CFRelease(C.CFTypeRef(dev.osDevice)) dev.osDevice = nil } if dev.closeDM != nil { dev.closeDM() dev.closeDM = nil } }
func initSystemRoots() { roots := NewCertPool() var data C.CFDataRef = nil err := C.ZToolsFetchPEMRoots(&data) if err == -1 { return } defer C.CFRelease(C.CFTypeRef(data)) buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) roots.AppendCertsFromPEM(buf) systemRoots = roots }
// The returned SecAccessRef, if non-nil, must be released via CFRelease. func createAccess(label string, trustedApplications []string) (C.CFTypeRef, error) { if len(trustedApplications) == 0 { return nil, nil } // Always prepend with empty string which signifies that we // include a NULL application, which means ourselves. trustedApplications = append([]string{""}, trustedApplications...) var err error var labelRef C.CFStringRef if labelRef, err = StringToCFString(label); err != nil { return nil, err } defer C.CFRelease(C.CFTypeRef(labelRef)) var trustedApplicationsRefs []C.CFTypeRef for _, trustedApplication := range trustedApplications { trustedApplicationRef, err := createTrustedApplication(trustedApplication) if err != nil { return nil, err } defer C.CFRelease(C.CFTypeRef(trustedApplicationRef)) trustedApplicationsRefs = append(trustedApplicationsRefs, trustedApplicationRef) } var access C.SecAccessRef trustedApplicationsArray := ArrayToCFArray(trustedApplicationsRefs) defer C.CFRelease(C.CFTypeRef(trustedApplicationsArray)) errCode := C.SecAccessCreate(labelRef, trustedApplicationsArray, &access) err = checkError(errCode) if err != nil { return nil, err } return C.CFTypeRef(access), nil }
func Load(kextID string, paths []string) error { cfKextID, err := StringToCFString(kextID) if cfKextID != nil { defer Release(C.CFTypeRef(cfKextID)) } if err != nil { return err } var urls []C.CFTypeRef for _, p := range paths { cfPath, err := StringToCFString(p) if cfPath != nil { defer Release(C.CFTypeRef(cfPath)) } if err != nil { return err } cfURL := C.CFURLCreateWithFileSystemPath(nil, cfPath, 0, 1) if cfURL != nil { defer Release(C.CFTypeRef(cfURL)) } urls = append(urls, C.CFTypeRef(cfURL)) } cfURLs := ArrayToCFArray(urls) if cfURLs != nil { defer Release(C.CFTypeRef(cfURLs)) } ret := C.KextManagerLoadKextWithIdentifier(cfKextID, cfURLs) if ret != 0 { return fmt.Errorf("Error loading kext(%d)", ret) } return nil }
// QueryItem returns a list of query results. func QueryItem(item Item) ([]QueryResult, error) { cfDict, err := ConvertMapToCFDictionary(item.attr) if err != nil { return nil, err } defer Release(C.CFTypeRef(cfDict)) var resultsRef C.CFTypeRef errCode := C.SecItemCopyMatching(cfDict, &resultsRef) if Error(errCode) == ErrorItemNotFound { return nil, nil } err = checkError(errCode) if err != nil { return nil, err } defer Release(resultsRef) results := make([]QueryResult, 0, 1) typeID := C.CFGetTypeID(resultsRef) if typeID == C.CFArrayGetTypeID() { arr := CFArrayToArray(C.CFArrayRef(resultsRef)) for _, dictRef := range arr { item, err := convertResult(C.CFDictionaryRef(dictRef)) if err != nil { return nil, err } results = append(results, *item) } } else if typeID == C.CFDictionaryGetTypeID() { item, err := convertResult(C.CFDictionaryRef(resultsRef)) if err != nil { return nil, err } results = append(results, *item) } else if typeID == C.CFDataGetTypeID() { b, err := CFDataToBytes(C.CFDataRef(resultsRef)) if err != nil { return nil, err } item := QueryResult{Data: b} results = append(results, item) } else { return nil, fmt.Errorf("Invalid result type: %s", CFTypeDescription(resultsRef)) } return results, nil }
// ConvertMapToCFDictionary converts a map to a CFDictionary and if non-nil, // must be released with Release(ref). func ConvertMapToCFDictionary(attr map[string]interface{}) (C.CFDictionaryRef, error) { m := make(map[C.CFTypeRef]C.CFTypeRef) for key, i := range attr { var valueRef C.CFTypeRef switch val := i.(type) { default: return nil, fmt.Errorf("Unsupported value type: %v", reflect.TypeOf(i)) case C.CFTypeRef: valueRef = val case bool: if val { valueRef = C.CFTypeRef(C.kCFBooleanTrue) } else { valueRef = C.CFTypeRef(C.kCFBooleanFalse) } case []byte: bytesRef, err := BytesToCFData(val) if err != nil { return nil, err } valueRef = C.CFTypeRef(bytesRef) defer Release(valueRef) case string: stringRef, err := StringToCFString(val) if err != nil { return nil, err } valueRef = C.CFTypeRef(stringRef) defer Release(valueRef) case Convertable: convertedRef, err := val.Convert() if err != nil { return nil, err } valueRef = C.CFTypeRef(convertedRef) defer Release(valueRef) } keyRef, err := StringToCFString(key) if err != nil { return nil, err } m[C.CFTypeRef(keyRef)] = valueRef defer Release(C.CFTypeRef(keyRef)) } cfDict, err := MapToCFDictionary(m) if err != nil { return nil, err } return cfDict, nil }