func convertResult(d C.CFDictionaryRef) (*QueryResult, error) { m := CFDictionaryToMap(C.CFDictionaryRef(d)) result := QueryResult{} for k, v := range m { switch attrKey(k) { case ServiceKey: result.Service = CFStringToString(C.CFStringRef(v)) case AccountKey: result.Account = CFStringToString(C.CFStringRef(v)) case AccessGroupKey: result.AccessGroup = CFStringToString(C.CFStringRef(v)) case LabelKey: result.Label = CFStringToString(C.CFStringRef(v)) case DataKey: b, err := CFDataToBytes(C.CFDataRef(v)) if err != nil { return nil, err } result.Data = b // default: // fmt.Printf("Unhandled key in conversion: %v = %v\n", cfTypeValue(k), cfTypeValue(v)) } } return &result, nil }
// 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 }
// Convert converts a CFTypeRef to a go instance. func Convert(ref C.CFTypeRef) (interface{}, error) { typeID := C.CFGetTypeID(ref) if typeID == C.CFStringGetTypeID() { return CFStringToString(C.CFStringRef(ref)), nil } else if typeID == C.CFDictionaryGetTypeID() { return ConvertCFDictionary(C.CFDictionaryRef(ref)) } else if typeID == C.CFArrayGetTypeID() { arr := CFArrayToArray(C.CFArrayRef(ref)) results := make([]interface{}, 0, len(arr)) for _, ref := range arr { v, err := Convert(ref) if err != nil { return nil, err } results = append(results, v) return results, nil } } else if typeID == C.CFDataGetTypeID() { b, err := CFDataToBytes(C.CFDataRef(ref)) if err != nil { return nil, err } return b, nil } else if typeID == C.CFNumberGetTypeID() { return CFNumberToInterface(C.CFNumberRef(ref)), nil } else if typeID == C.CFBooleanGetTypeID() { if C.CFBooleanGetValue(C.CFBooleanRef(ref)) != 0 { return true, nil } return false, nil } return nil, fmt.Errorf("Invalid type: %s", CFTypeDescription(ref)) }
func (d VoiceAttributes) get(k C.CFStringRef) (s string) { cs := C.CFDictionaryGetValue(d.cfd, unsafe.Pointer(k)) if cs != nil { s = cfstringGo(C.CFStringRef(cs)) } return }
// 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 }
func getCFDictValueCFStringRef(dict C.CFDictionaryRef, key C.CFTypeRef) (C.CFStringRef, error) { val, err := getCFDictValueRef(dict, key) if err != nil { return nil, err } if val == nil { return nil, errors.New("getCFDictValueCFStringRef: Nil value returned") } if C.CFGetTypeID(val) != C.CFStringGetTypeID() { return nil, errors.New("getCFDictValueCFStringRef: value is not a string") } return C.CFStringRef(val), nil }
func (k *keychain) Keys() ([]string, error) { serviceRef, err := _UTF8StringToCFString(k.Service) if err != nil { return nil, err } defer C.CFRelease(C.CFTypeRef(serviceRef)) query := map[C.CFTypeRef]C.CFTypeRef{ C.CFTypeRef(C.kSecClass): C.CFTypeRef(C.kSecClassGenericPassword), C.CFTypeRef(C.kSecAttrService): C.CFTypeRef(serviceRef), C.CFTypeRef(C.kSecMatchLimit): C.CFTypeRef(C.kSecMatchLimitAll), C.CFTypeRef(C.kSecReturnAttributes): C.CFTypeRef(C.kCFBooleanTrue), } kref, err := openKeychain(k.Path) if err != nil { return nil, err } searchArray := arrayToCFArray([]C.CFTypeRef{C.CFTypeRef(kref)}) defer C.CFRelease(C.CFTypeRef(searchArray)) query[C.CFTypeRef(C.kSecMatchSearchList)] = C.CFTypeRef(searchArray) queryDict := mapToCFDictionary(query) defer C.CFRelease(C.CFTypeRef(queryDict)) var resultsRef C.CFTypeRef if err = newKeychainError(C.SecItemCopyMatching(queryDict, &resultsRef)); err == errItemNotFound { return nil, nil } else if err != nil { return nil, err } defer C.CFRelease(resultsRef) var accountNames = []string{} for _, result := range _CFArrayToArray(C.CFArrayRef(resultsRef)) { m := _CFDictionaryToMap(C.CFDictionaryRef(result)) accountName := _CFStringToUTF8String(C.CFStringRef(m[C.CFTypeRef(C.kSecAttrAccount)])) accountNames = append(accountNames, accountName) } return accountNames, nil }
func NSStringToString(inString Object) string { cr := C.CFStringRef(unsafe.Pointer(inString)) var usedBufLen C.CFIndex rng := C.CFRange{C.CFIndex(0), C.CFStringGetLength(cr)} n := int(C.CFStringGetBytes(cr, rng, C.kCFStringEncodingUTF8, 0, 0, nil, 0, &usedBufLen)) if n <= 0 { return "" } buf := make([]byte, int(usedBufLen)) C.CFStringGetBytes(cr, rng, C.kCFStringEncodingUTF8, 0, 0, (*C.UInt8)(unsafe.Pointer(&buf[0])), C.CFIndex(len(buf)), &usedBufLen) sh := &reflect.StringHeader{ Data: uintptr(unsafe.Pointer(&buf[0])), Len: int(usedBufLen), } return *(*string)(unsafe.Pointer(sh)) }
func convertCFDictionaryToMapHelper(cfDict C.CFDictionaryRef, helper func(key string, value cfTypeRef, count int) error) error { count := int(C.CFDictionaryGetCount(cfDict)) if count == 0 { return nil } cfKeys := make([]cfTypeRef, count) cfVals := make([]cfTypeRef, count) C.CFDictionaryGetKeysAndValues(cfDict, (*unsafe.Pointer)(&cfKeys[0]), (*unsafe.Pointer)(&cfVals[0])) for i := 0; i < count; i++ { cfKey := cfKeys[i] typeId := C.CFGetTypeID(C.CFTypeRef(cfKey)) if typeId != C.CFStringGetTypeID() { return &UnsupportedKeyTypeError{int(typeId)} } key := convertCFStringToString(C.CFStringRef(cfKey)) if err := helper(key, cfVals[i], count); err != nil { return err } } return nil }
// we shouldn't ever get an error from this, but I'd rather not panic func convertCFTypeToInterface(cfType cfTypeRef) (interface{}, error) { typeId := C.CFGetTypeID(C.CFTypeRef(cfType)) switch typeId { case C.CFStringGetTypeID(): return convertCFStringToString(C.CFStringRef(cfType)), nil case C.CFNumberGetTypeID(): return convertCFNumberToInterface(C.CFNumberRef(cfType)), nil case C.CFBooleanGetTypeID(): return convertCFBooleanToBool(C.CFBooleanRef(cfType)), nil case C.CFDataGetTypeID(): return convertCFDataToBytes(C.CFDataRef(cfType)), nil case C.CFDateGetTypeID(): return convertCFDateToTime(C.CFDateRef(cfType)), nil case C.CFArrayGetTypeID(): ary, err := convertCFArrayToSlice(C.CFArrayRef(cfType)) return ary, err case C.CFDictionaryGetTypeID(): dict, err := convertCFDictionaryToMap(C.CFDictionaryRef(cfType)) return dict, err } return nil, &UnknownCFTypeError{typeId} }
func (state *unmarshalState) unmarshalValue(cfObj cfTypeRef, v reflect.Value) error { vType := v.Type() var unmarshaler Unmarshaler if u, ok := v.Interface().(Unmarshaler); ok { unmarshaler = u } else if vType.Kind() != reflect.Ptr && vType.Name() != "" && v.CanAddr() { // matching the encoding/json behavior here // If v is a named type and is addressable, check its address for Unmarshaler. vA := v.Addr() if u, ok := vA.Interface().(Unmarshaler); ok { unmarshaler = u } } if unmarshaler != nil { // flip over to the dumb conversion routine so we have something to give UnmarshalPlist() plist, err := convertCFTypeToInterface(cfObj) if err != nil { return err } if vType.Kind() == reflect.Ptr && v.IsNil() { v.Set(reflect.New(vType.Elem())) unmarshaler = v.Interface().(Unmarshaler) } return unmarshaler.UnmarshalPlist(plist) } if vType.Kind() == reflect.Ptr { if v.IsNil() { v.Set(reflect.New(vType.Elem())) } return state.unmarshalValue(cfObj, v.Elem()) } typeID := C.CFGetTypeID(C.CFTypeRef(cfObj)) vSetter := v // receiver of any Set* calls vAddr := v.Addr() // used for re-setting v for maps/slices if vType.Kind() == reflect.Interface { if v.IsNil() { // pick an appropriate type based on the cfobj var typ reflect.Type if typeID == cfNumberTypeID { typ = cfNumberTypeToType(C.CFNumberGetType(C.CFNumberRef(cfObj))) } else { var ok bool typ, ok = cfTypeMap[typeID] if !ok { return &UnknownCFTypeError{typeID} } } if !typ.AssignableTo(vType) { // v must be some interface that our object doesn't conform to state.recordError(&UnmarshalTypeError{cfTypeNames[typeID], vType}) return nil } vSetter.Set(reflect.Zero(typ)) } vAddr = v v = v.Elem() vType = v.Type() } switch typeID { case cfArrayTypeID: if vType.Kind() != reflect.Slice && vType.Kind() != reflect.Array { state.recordError(&UnmarshalTypeError{cfTypeNames[typeID], vType}) return nil } return convertCFArrayToSliceHelper(C.CFArrayRef(cfObj), func(elem cfTypeRef, idx, count int) (bool, error) { if idx == 0 && vType.Kind() == reflect.Slice { vSetter.Set(reflect.MakeSlice(vType, count, count)) v = vAddr.Elem() } else if vType.Kind() == reflect.Array && idx >= v.Len() { return false, nil } if err := state.unmarshalValue(elem, v.Index(idx)); err != nil { return false, err } return true, nil }) case cfBooleanTypeID: if vType.Kind() != reflect.Bool { state.recordError(&UnmarshalTypeError{cfTypeNames[typeID], vType}) return nil } vSetter.Set(reflect.ValueOf(C.CFBooleanGetValue(C.CFBooleanRef(cfObj)) != C.false)) return nil case cfDataTypeID: if !byteSliceType.AssignableTo(vType) { state.recordError(&UnmarshalTypeError{cfTypeNames[typeID], vType}) return nil } vSetter.Set(reflect.ValueOf(convertCFDataToBytes(C.CFDataRef(cfObj)))) return nil case cfDateTypeID: if !timeType.AssignableTo(vType) { state.recordError(&UnmarshalTypeError{cfTypeNames[typeID], vType}) return nil } vSetter.Set(reflect.ValueOf(convertCFDateToTime(C.CFDateRef(cfObj)))) return nil case cfDictionaryTypeID: if vType.Kind() == reflect.Map { // it's a map. Check its key type first if !stringType.AssignableTo(vType.Key()) { state.recordError(&UnmarshalTypeError{cfTypeNames[cfStringTypeID], vType.Key()}) return nil } if v.IsNil() { vSetter.Set(reflect.MakeMap(vType)) v = vAddr.Elem() } return convertCFDictionaryToMapHelper(C.CFDictionaryRef(cfObj), func(key string, value cfTypeRef, count int) error { keyVal := reflect.ValueOf(key) val := reflect.New(vType.Elem()) if err := state.unmarshalValue(value, val); err != nil { return err } v.SetMapIndex(keyVal, val.Elem()) return nil }) } else if vType.Kind() == reflect.Struct { return convertCFDictionaryToMapHelper(C.CFDictionaryRef(cfObj), func(key string, value cfTypeRef, count int) error { // we need to iterate the fields because the tag might rename the key var f reflect.StructField var ok bool for i := 0; i < vType.NumField(); i++ { sf := vType.Field(i) tag := sf.Tag.Get("plist") if tag == "-" { // Pretend this field doesn't exist continue } if sf.Anonymous { // Match encoding/json's behavior here and pretend it doesn't exist continue } name, _ := parseTag(tag) if name == key { f = sf ok = true // This is unambiguously the right match break } if sf.Name == key { f = sf ok = true } // encoding/json does a case-insensitive match. Lets do that too if !ok && strings.EqualFold(sf.Name, key) { f = sf ok = true } } if ok { if f.PkgPath != "" { // this is an unexported field return &UnmarshalFieldError{key, vType, f} } vElem := v.FieldByIndex(f.Index) if err := state.unmarshalValue(value, vElem); err != nil { return err } } return nil }) } state.recordError(&UnmarshalTypeError{cfTypeNames[typeID], vType}) return nil case cfNumberTypeID: switch vType.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: i := convertCFNumberToInt64(C.CFNumberRef(cfObj)) if v.OverflowInt(i) { state.recordError(&UnmarshalTypeError{cfTypeNames[typeID] + " " + strconv.FormatInt(i, 10), vType}) return nil } if vSetter.Kind() == reflect.Interface { vSetter.Set(reflect.ValueOf(i)) } else { vSetter.SetInt(i) } return nil case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: u := uint64(convertCFNumberToUInt32(C.CFNumberRef(cfObj))) if v.OverflowUint(u) { state.recordError(&UnmarshalTypeError{cfTypeNames[typeID] + " " + strconv.FormatUint(u, 10), vType}) return nil } if vSetter.Kind() == reflect.Interface { vSetter.Set(reflect.ValueOf(u)) } else { vSetter.SetUint(u) } return nil case reflect.Float32, reflect.Float64: f := convertCFNumberToFloat64(C.CFNumberRef(cfObj)) if v.OverflowFloat(f) { state.recordError(&UnmarshalTypeError{cfTypeNames[typeID] + " " + strconv.FormatFloat(f, 'f', -1, 64), vType}) return nil } if vSetter.Kind() == reflect.Interface { vSetter.Set(reflect.ValueOf(f)) } else { vSetter.SetFloat(f) } return nil } state.recordError(&UnmarshalTypeError{cfTypeNames[typeID], vType}) return nil case cfStringTypeID: if vType.Kind() != reflect.String { state.recordError(&UnmarshalTypeError{cfTypeNames[typeID], vType}) return nil } vSetter.Set(reflect.ValueOf(convertCFStringToString(C.CFStringRef(cfObj)))) return nil } return &UnknownCFTypeError{typeID} }
func attrKey(ref C.CFTypeRef) string { return CFStringToString(C.CFStringRef(ref)) }
func getStringProp(device C.IOHIDDeviceRef, key C.CFStringRef) string { s := C.IOHIDDeviceGetProperty(device, key) return gostring(C.CFStringRef(s)) }
func (k *keychain) Get(key string) (Item, error) { if _, err := os.Stat(k.Path); os.IsNotExist(err) { return Item{}, ErrKeyNotFound } serviceRef, err := _UTF8StringToCFString(k.Service) if err != nil { return Item{}, err } defer C.CFRelease(C.CFTypeRef(serviceRef)) accountRef, err := _UTF8StringToCFString(key) if err != nil { return Item{}, err } defer C.CFRelease(C.CFTypeRef(serviceRef)) query := map[C.CFTypeRef]C.CFTypeRef{ C.CFTypeRef(C.kSecClass): C.CFTypeRef(C.kSecClassGenericPassword), C.CFTypeRef(C.kSecAttrService): C.CFTypeRef(serviceRef), C.CFTypeRef(C.kSecAttrAccount): C.CFTypeRef(accountRef), C.CFTypeRef(C.kSecMatchLimit): C.CFTypeRef(C.kSecMatchLimitOne), C.CFTypeRef(C.kSecReturnAttributes): C.CFTypeRef(C.kCFBooleanTrue), C.CFTypeRef(C.kSecReturnData): C.CFTypeRef(C.kCFBooleanTrue), } kref, err := openKeychain(k.Path) if err != nil { return Item{}, err } searchArray := arrayToCFArray([]C.CFTypeRef{C.CFTypeRef(kref)}) defer C.CFRelease(C.CFTypeRef(searchArray)) query[C.CFTypeRef(C.kSecMatchSearchList)] = C.CFTypeRef(searchArray) queryDict := mapToCFDictionary(query) defer C.CFRelease(C.CFTypeRef(queryDict)) var resultsRef C.CFTypeRef if err = newKeychainError(C.SecItemCopyMatching(queryDict, &resultsRef)); err == errItemNotFound { return Item{}, ErrKeyNotFound } else if err != nil { return Item{}, err } defer C.CFRelease(resultsRef) m := _CFDictionaryToMap(C.CFDictionaryRef(resultsRef)) data := C.CFDataRef(m[C.CFTypeRef(C.kSecValueData)]) dataLen := C.int(C.CFDataGetLength(data)) cdata := C.CFDataGetBytePtr(data) item := Item{ Key: key, Data: C.GoBytes(unsafe.Pointer(cdata), dataLen), } if label, exists := m[C.CFTypeRef(C.kSecAttrLabel)]; exists { item.Label = _CFStringToUTF8String(C.CFStringRef(label)) } if descr, exists := m[C.CFTypeRef(C.kSecAttrDescription)]; exists { item.Description = _CFStringToUTF8String(C.CFStringRef(descr)) } return item, nil }