fraca7 avatar fraca7 committed dd67f72

Use ctypes on Mac OS X

Comments (0)

Files changed (6)

extensions.py

-"""
-build_ext.py
-
-Created by Kang Zhang on 2009-08-07
-"""
-
-import sys
-
-from distutils.core import Extension
-
-
-def get_extensions():
-    """Collect the extensions that can be installed.
-    """
-    exts = []
-    platform = sys.platform
-
-    if platform in ['darwin', 'mac']:
-        # Mac OS X, keychain enabled
-        osx_keychain_module = Extension('osx_keychain',
-                        library_dirs = ['/System/Library/Frameworks/'],
-                        sources = ['keyring/backends/osx_keychain.c'],
-                        extra_link_args = ['-framework', 'Security',
-                            '-framework', 'CoreFoundation', '-framework',
-                            'CoreServices'])
-        exts.append(osx_keychain_module)
-
-    return exts

keyring/backend.py

     def _init_backend(self):
         """Return the handler: osx_keychain
         """
-        import osx_keychain
+        from backends import osx_keychain
         return osx_keychain
 
     def _recommend(self):

keyring/backends/keyring_util.h

-/*
- * keyring_util.h
- *
- * Some useful functions for keyring lib
- */
-#ifndef KEYRING_UTIL_H
-#define KEYRING_UTIL_H
-char *
-string_dump(const char *s,int n)
-{
-    char *res;
-    if (s == NULL)
-        return NULL;
-    res = (char*) malloc(n+1);
-    memcpy(res,s,n);
-    res[n] = '\0';
-    return res;
-}
-#endif //KEYRING_UTIL_H

keyring/backends/osx_keychain.c

-#include <Security/Security.h>
-
-#include "Python.h"
-#include "keyring_util.h"
-
-static PyObject *
-keychain_password_set(PyObject *self, PyObject *args)
-{
-    const char *realmstring;
-    const char *username;
-    const char *password;
-    OSStatus status;
-    SecKeychainRef keychain;
-    SecKeychainItemRef item;
-
-    if (!PyArg_ParseTuple(args, "sss", &realmstring, &username, &password)){
-        PyErr_Clear();
-        PyErr_SetString(PyExc_TypeError,
-            "password_set() must be called as (servicename,username,password)");                                               
-        return NULL;                                                        
-    }
-    
-    if (SecKeychainOpen("login.keychain",&keychain) != 0 ){
-        PyErr_Clear();
-        PyErr_SetString(PyExc_OSError,
-                    "can't access the login.keychain, Authorization failed");                                             
-        return NULL;                                                        
-    }
-    
-    status = SecKeychainFindGenericPassword(keychain, strlen(realmstring),
-                                            realmstring, username == NULL
-                                              ? 0
-                                              : strlen(username),
-                                            username, 0, NULL, &item);
-    if (status){
-        if (status == errSecItemNotFound)
-            status = SecKeychainAddGenericPassword(keychain, strlen(realmstring),
-                                                 realmstring, username == NULL
-                                                   ? 0
-                                                   : strlen(username),
-                                                 username, strlen(password),
-                                                 password, NULL);
-    }
-    else{
-        status = SecKeychainItemModifyAttributesAndData(item, NULL,
-                                                        strlen(password),
-                                                        password);
-        CFRelease(item);
-    }
-
-    if (status != 0){ // error occurs 
-        PyErr_Clear();
-        PyErr_SetString(PyExc_OSError, "Can't store password in Keychain");
-        return NULL;
-    }
-
-    Py_RETURN_NONE;
-}
-
-
-static PyObject *
-keychain_password_get(PyObject *self, PyObject *args)
-{
-    const char *realmstring;
-    const char *username;
-    char *password;
-    OSStatus status;
-    UInt32 length;
-    SecKeychainRef keychain;
-    void *data;
-    
-    if (!PyArg_ParseTuple(args, "ss", &realmstring, &username)){
-        PyErr_Clear();
-        PyErr_SetString(PyExc_TypeError,
-            "password_get() must be called as (servicename,username)");                                                
-        return NULL;                                                        
-    }
-    
-    if (SecKeychainOpen("login.keychain", &keychain) != 0 ){
-        PyErr_Clear();
-        PyErr_SetString(PyExc_OSError,
-                "can't access the login.keychain, Authorization failed");                                             
-        return NULL;                                                        
-    }
-    
-    status = SecKeychainFindGenericPassword(keychain, strlen(realmstring),
-                                            realmstring, username == NULL
-                                              ? 0
-                                              : strlen(username),
-                                            username, &length, &data, NULL);
-
-    if (status == 0){
-        password = string_dump(data, length);
-        SecKeychainItemFreeContent(NULL, data);
-    }else if (status == errSecItemNotFound){
-        password = NULL;
-    }
-    else{ // error occurs
-        PyErr_Clear();
-        PyErr_SetString(PyExc_OSError, "Can't fetch password from system");
-        return NULL;
-    }
-    
-    return Py_BuildValue("s",password);
-}
-
-static struct PyMethodDef keychain_methods[] ={
-    {"password_set", keychain_password_set, METH_VARARGS},
-    {"password_get", keychain_password_get, METH_VARARGS},
-    {NULL,NULL} /* Sentinel */
-};
-
-PyMODINIT_FUNC
-initosx_keychain(void)
-{
-    Py_InitModule("osx_keychain", keychain_methods);
-}
-

keyring/backends/osx_keychain.py

+#!/usr/bin/python
+
+import sys
+if sys.platform != 'darwin':
+    raise ImportError('Mac OS X only module')
+
+from ctypes import CDLL, CFUNCTYPE, c_void_p, c_uint32, \
+    c_int32, c_char_p, byref, POINTER, memmove, create_string_buffer
+
+# Types
+
+SecKeychainRef     = c_void_p
+SecKeychainItemRef = c_void_p
+OSStatus           = c_int32
+
+# Constants
+
+errSecSuccess                = 0
+errSecUnimplemented          = -4
+errSecParam                  = -50
+errSecAllocate               = -108
+
+errSecNotAvailable           = -25291
+errSecReadOnly               = -25292
+errSecAuthFailed             = -25293
+errSecNoSuchKeychain         = -25294
+errSecInvalidKeychain        = -25295
+errSecDuplicateKeychain      = -25296
+errSecDuplicateCallback      = -25297
+errSecInvalidCallback        = -25298
+errSecDuplicateItem          = -25299
+errSecItemNotFound           = -25300
+errSecBufferTooSmall         = -25301
+errSecDataTooLarge           = -25302
+errSecNoSuchAttr             = -25303
+errSecInvalidItemRef         = -25304
+errSecInvalidSearchRef       = -25305
+errSecNoSuchClass            = -25306
+errSecNoDefaultKeychain      = -25307
+errSecInteractionNotAllowed  = -25308
+errSecReadOnlyAttr           = -25309
+errSecWrongSecVersion        = -25310
+errSecKeySizeNotAllowed      = -25311
+errSecNoStorageModule        = -25312
+errSecNoCertificateModule    = -25313
+errSecNoPolicyModule         = -25314
+errSecInteractionRequired    = -25315
+errSecDataNotAvailable       = -25316
+errSecDataNotModifiable      = -25317
+errSecCreateChainFailed      = -25318
+errSecInvalidPrefsDomain     = -25319
+
+errSecACLNotSimple           = -25240
+errSecPolicyNotFound         = -25241
+errSecInvalidTrustSetting    = -25242
+errSecNoAccessForItem        = -25243
+errSecInvalidOwnerEdit       = -25244
+errSecTrustNotAvailable      = -25245
+errSecUnsupportedFormat      = -25256
+errSecUnknownFormat          = -25257
+errSecKeyIsSensitive         = -25258
+errSecMultiplePrivKeys       = -25259
+errSecPassphraseRequired     = -25260
+errSecInvalidPasswordRef     = -25261
+errSecInvalidTrustSettings   = -25262
+errSecNoTrustSettings        = -25263
+errSecPkcs12VerifyFailure    = -25264
+
+errSecDecode                 = -26275
+
+# Functions
+
+_dll = CDLL('/System/Library/Frameworks/Security.framework/Versions/A/Security')
+_core = CDLL('/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices')
+
+SecKeychainOpen = CFUNCTYPE(OSStatus, c_char_p, POINTER(SecKeychainRef))(('SecKeychainOpen', _dll))
+SecKeychainFindGenericPassword = CFUNCTYPE(OSStatus, SecKeychainRef, c_uint32,
+                                           c_char_p, c_uint32, c_char_p,
+                                           POINTER(c_uint32), POINTER(c_void_p),
+                                           POINTER(SecKeychainItemRef))(('SecKeychainFindGenericPassword', _dll))
+SecKeychainAddGenericPassword = CFUNCTYPE(OSStatus, SecKeychainRef, c_uint32, c_char_p,
+                                          c_uint32, c_char_p, c_uint32,
+                                          c_char_p, POINTER(SecKeychainItemRef))(('SecKeychainAddGenericPassword', _dll))
+SecKeychainItemModifyAttributesAndData = CFUNCTYPE(OSStatus, SecKeychainItemRef, c_void_p, c_uint32, c_void_p)(('SecKeychainItemModifyAttributesAndData', _dll))
+SecKeychainItemFreeContent = CFUNCTYPE(OSStatus, c_void_p, c_void_p)(('SecKeychainItemFreeContent', _dll))
+
+def password_set(realmstring, username, password):
+    if username is None:
+        username = ''
+
+    keychain = SecKeychainRef()
+    if SecKeychainOpen('login.keychain', byref(keychain)):
+        raise OSError("Can't access the login keychain")
+
+    try:
+        item = SecKeychainItemRef()
+        status = SecKeychainFindGenericPassword(keychain, len(realmstring), realmstring, len(username), username, None, None, byref(item))
+        if status:
+            if status == errSecItemNotFound:
+                status = SecKeychainAddGenericPassword(keychain, len(realmstring), realmstring, len(username), username, len(password), password, None)
+        else:
+            status = SecKeychainItemModifyAttributesAndData(item, None, len(password), password)
+            _core.CFRelease(item)
+
+        if status:
+            raise OSError("Can't store password in keychain")
+    finally:
+        _core.CFRelease(keychain)
+
+def password_get(realmstring, username):
+    if username is None:
+        username = ''
+
+    keychain = SecKeychainRef()
+    if SecKeychainOpen('login.keychain', byref(keychain)):
+        raise OSError("Can't access the login keychain")
+
+    try:
+        length = c_uint32()
+        data = c_void_p()
+        status = SecKeychainFindGenericPassword(keychain, len(realmstring), realmstring,
+                                                len(username), username,
+                                                byref(length), byref(data), None)
+        if status == 0:
+            password = create_string_buffer(length.value)
+            memmove(password, data.value, length.value)
+            password = password.raw
+            SecKeychainItemFreeContent(None, data)
+        elif status == errSecItemNotFound:
+            password = None
+        else:
+            raise OSError("Can't fetch password from system")
+        return password
+    finally:
+        _core.CFRelease(keychain)
+
 from distutils.core import setup, Extension
 from distutils.version import StrictVersion
 
-from extensions import get_extensions
-
 def runcmd(cmd, env):
     p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE, env=env)
       platforms = ["Many"],
       packages = ['keyring', 'keyring.tests', 'keyring.util',
                   'keyring.backends'],
-      ext_modules = get_extensions()
     )
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.