<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -87,26 +87,21 @@ class Keychain(object):
         # SecKeychainItemFreeAttributesAndData when you no longer need the
         # attributes and data.
 
-        d_len   = ctypes.c_int(0)
         info    = SecKeychainAttributeInfo()
         attrs_p = SecKeychainAttributeList_p()
 
         # Thank you Wil Shipley:
         # http://www.wilshipley.com/blog/2006/10/pimp-my-code-part-12-frozen-in.html
-        # SecKeychainAttributeInfo should allow .append(tag, [data])
         info.count = 1
-        info.tag.contents = ctypes.c_ulong(7) # TODO: add kSecLabelItemAttr define
+        info.tag.contents = Security.kSecLabelItemAttr
 
-        Security.lib.SecKeychainItemCopyAttributesAndData(item_p, ctypes.pointer(info), None, ctypes.byref(attrs_p), ctypes.byref(d_len), None)
+        Security.lib.SecKeychainItemCopyAttributesAndData(item_p, ctypes.pointer(info), None, ctypes.byref(attrs_p), None, None)
         attrs = attrs_p.contents
         assert(attrs.count == 1)
-        # TODO: This should move into standard iterator support for SecKeychainAttributeList:
-        # for offset in range(0, attrs.count):
-        #     print &quot;[%d]: %s(%d): %s&quot; % (offset, attrs.attr[offset].tag, attrs.attr[offset].length, attrs.attr[offset].data)
 
         label = attrs.attr[0].data[:attrs.attr[0].length]
 
-        Security.lib.SecKeychainItemFreeContent(None, item_p)
+        Security.lib.SecKeychainFreeAttributeInfo(attrs_p)
 
         return GenericPassword(service_name=service_name, account_name=account_name, password=password, keychain_item=item_p, label=label)
 
@@ -300,6 +295,20 @@ class SecKeychainAttributeList(ctypes.Structure):
     count:  An unsigned 32-bit integer that represents the number of keychain attributes in the array.
     attr:   A pointer to the first keychain attribute in the array.
     &quot;&quot;&quot;
+
+    # TODO: Standard iterator support for SecKeychainAttributeList:
+    #
+    #   for offset in range(0, attrs.count):
+    #     print &quot;[%d]: %s: %s&quot; % (offset, attrs.attr[offset].tag, attrs.attr[offset].data[:attrs.attr[offset].length])
+    #
+    # becomes:
+    #
+    #   for tag, data in attrs:
+    #       &#8230;
+    #
+    #   attrs[tag] should also work
+    #
+
     _fields_ = [
         ('count',   ctypes.c_uint),
         ('attr',    ctypes.POINTER(SecKeychainAttribute))
@@ -312,18 +321,13 @@ class SecKeychainAttributeInfo(ctypes.Structure):
     tag:    A pointer to the first attribute tag in the array
     format: A pointer to the first CSSM_DB_ATTRIBUTE_FORMAT in the array
     &quot;&quot;&quot;
+    # TODO: SecKeychainAttributeInfo should allow .append(tag, [data])
     _fields_ = [
         ('count',   ctypes.c_uint),
         ('tag',     ctypes.POINTER(ctypes.c_uint)),
         ('format',  ctypes.POINTER(ctypes.c_uint))
     ]
 
-# The APIs expect pointers to SecKeychainAttributeInfo objects and we'd
-# like to avoid having to manage memory manually:
+# The APIs expect pointers to SecKeychainAttributeInfo objects:
 SecKeychainAttributeInfo_p = ctypes.POINTER(SecKeychainAttributeInfo)
-# BUG: This causes a crash if the Python object is never initialized correctly. We should define a checked free function instead:
-# SecKeychainAttributeInfo_p.__del__ = lambda self: Security.lib.SecKeychainFreeAttributeInfo(self)
-
 SecKeychainAttributeList_p = ctypes.POINTER(SecKeychainAttributeList)
-# BUG: This causes a crash if the Python object is never initialized correctly. We should define a checked free function instead:
-# SecKeychainAttributeList_p.__del__ = lambda self: Security.lib.SecKeychainFreeAttributeInfo(self)
\ No newline at end of file</diff>
      <filename>lib/PyMacAdmin/Security/Keychain.py</filename>
    </modified>
    <modified>
      <diff>@@ -1,21 +1,60 @@
 # encoding: utf-8
-import ctypes
 import PyMacAdmin
+import ctypes
 import struct
+import sys
 
 # This is not particularly elegant but to avoid everything having to load the
 # Security framework we use a single copy hanging of this module so everything
 # else can simply use Security.lib.SecKeychainFoo(&#8230;)
 lib = PyMacAdmin.load_carbon_framework('/System/Library/Frameworks/Security.framework/Versions/Current/Security')
 
-# TODO: Expand this considerably or find a better way to deal with pre-defined constants
 CSSM_DB_RECORDTYPE_APP_DEFINED_START = 0x80000000
 CSSM_DL_DB_RECORD_X509_CERTIFICATE   = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 0x1000
 
-# typedef FourCharCode SecItemClass;
-# SecKeychainItem.h
-# TODO: Expand these constants to avoid calling struct.unpack()
-kSecInternetPasswordItemClass   = struct.unpack('BBBB', 'inet')
-kSecGenericPasswordItemClass    = struct.unpack('BBBB', 'genp')
-kSecAppleSharePasswordItemClass = struct.unpack('BBBB', 'ashp')
-kSecCertificateItemClass        = CSSM_DL_DB_RECORD_X509_CERTIFICATE
+# This is somewhat gross: we define a bunch of module-level constants based on
+# the SecKeychainItem.h defines (FourCharCodes) by passing them through
+# struct.unpack and converting them to ctypes.c_long() since we'll never use
+# them for non-native APIs
+
+CARBON_DEFINES = {
+    'kSecCreationDateItemAttr':         'cdat',
+    'kSecModDateItemAttr':              'mdat',
+    'kSecDescriptionItemAttr':          'desc',
+    'kSecCommentItemAttr':              'icmt',
+    'kSecCreatorItemAttr':              'crtr',
+    'kSecTypeItemAttr':                 'type',
+    'kSecScriptCodeItemAttr':           'scrp',
+    'kSecLabelItemAttr':                'labl',
+    'kSecInvisibleItemAttr':            'invi',
+    'kSecNegativeItemAttr':             'nega',
+    'kSecCustomIconItemAttr':           'cusi',
+    'kSecAccountItemAttr':              'acct',
+    'kSecServiceItemAttr':              'svce',
+    'kSecGenericItemAttr':              'gena',
+    'kSecSecurityDomainItemAttr':       'sdmn',
+    'kSecServerItemAttr':               'srvr',
+    'kSecAuthenticationTypeItemAttr':   'atyp',
+    'kSecPortItemAttr':                 'port',
+    'kSecPathItemAttr':                 'path',
+    'kSecVolumeItemAttr':               'vlme',
+    'kSecAddressItemAttr':              'addr',
+    'kSecSignatureItemAttr':            'ssig',
+    'kSecProtocolItemAttr':             'ptcl',
+    'kSecCertificateType':              'ctyp',
+    'kSecCertificateEncoding':          'cenc',
+    'kSecCrlType':                      'crtp',
+    'kSecCrlEncoding':                  'crnc',
+    'kSecAlias':                        'alis',
+    'kSecInternetPasswordItemClass':    'inet',
+    'kSecGenericPasswordItemClass':     'genp',
+    'kSecAppleSharePasswordItemClass':  'ashp',
+    'kSecCertificateItemClass':         CSSM_DL_DB_RECORD_X509_CERTIFICATE
+}
+
+for k in CARBON_DEFINES:
+    v = CARBON_DEFINES[k]
+    if isinstance(v, str):
+        assert(len(v) == 4)
+        v = ctypes.c_ulong(struct.unpack(&quot;&gt;L&quot;, v)[0])
+    setattr(sys.modules[__name__], k, v)
\ No newline at end of file</diff>
      <filename>lib/PyMacAdmin/Security/__init__.py</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>60630dbdb99c37193673c100c7239c80a8b90527</id>
    </parent>
  </parents>
  <author>
    <name>Chris Adams</name>
    <email>chris@improbable.org</email>
  </author>
  <url>http://github.com/acdha/pymacadmin/commit/649dae5c16e380d8ac36c8430e4dcca81ab57fe7</url>
  <id>649dae5c16e380d8ac36c8430e4dcca81ab57fe7</id>
  <committed-date>2009-03-21T13:55:16-07:00</committed-date>
  <authored-date>2009-03-21T13:55:16-07:00</authored-date>
  <message>Keychain cleanup

Added module attributes for all of the kSec* defines
Fixed a bug caused by prematurely releasing the opaque item handle in find_generic_password
Removed some stale code, comments and unused variables</message>
  <tree>e1ac9330caa88f2bbefe5ff4d4cf1d70fc40a20a</tree>
  <committer>
    <name>Chris Adams</name>
    <email>chris@improbable.org</email>
  </committer>
</commit>
