// 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
}
Exemple #2
0
// CFTypeDescription returns type string for CFTypeRef.
func CFTypeDescription(ref C.CFTypeRef) string {
	typeID := C.CFGetTypeID(ref)
	typeDesc := C.CFCopyTypeIDDescription(typeID)
	defer Release(C.CFTypeRef(typeDesc))
	return CFStringToString(typeDesc)
}