Commits

Marcin Kasperski committed 1e4e182

devel notes

  • Participants

Comments (0)

Files changed (1)

devel_notes/how_to_use.txt

+
+Access to OS/X keychain can be tunelled via /usr/bin/security
+program. Two Pythonic examples how to do it are:
+
+Manpage
+==============
+
+http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/security.1.html
+
+mentions delete-generic-password in particular
+
+
+Random sources
+==========================
+
+$ security -q find-generic-password -g -s server.com
+
+keychain: "/Users/myUser/Library/Keychains/login.keychain"
+class: "genp"
+attributes:
+    0x00000007 <blob>="server.com"
+    0x00000008 <blob>=<NULL>
+    "acct"<blob>="userIDtoServer.com"
+    "cdat"<timedate>=0x33313024C53131693134253345315F00  "20041201142351A\123"
+    "crtr"<uint32>=<NULL>
+    "cusi"<sint32>=<NULL>
+    "desc"<blob>=<NULL>
+    "gena"<blob>=<NULL>
+    "icmt"<blob>=<NULL>
+    "invi"<sint32>=<NULL>
+    "mdat"<timedate>=0x33313024C53131693134253345315F00  "20041201142351A\123"
+    "nega"<sint32>=<NULL>
+    "prot"<blob>=<NULL>
+    "scrp"<sint32>=<NULL>
+    "svce"<blob>="server.com"
+    "type"<uint32>=<NULL>
+password: "myPassword"
+
+
+OS/X backend from keyring library
+=================================
+
+setting password
+----------------
+
+   security add-generic-password -a username -s realmstring -w password -U
+
+retcode <> 0 → failure
+
+getting password
+----------------
+
+   security find-generic-password -g -a username -s realmstring
+
+retcode <> 0 → failure
+
+password is read from stderr (!), line is either
+
+   password: \n      (empty)
+
+   password: "password"   (nonempty)
+
+or some ugly escaped form handled this way:
+
+        matches = re.search('password:(?P<hex>.*?)"(?P<pw>.*)"', output)
+        if matches:
+            hex = matches.group('hex').strip()
+            pw = matches.group('pw')
+            if hex:
+                # it's a weird hex password, decode it.
+                return binascii.unhexlify(hex[2:])
+            else:
+                # it's a normal password, send it back.
+                return pw
+
+keychain.py
+================================
+
+http://bazaar.launchpad.net/~muffinresearch/keychain.py/trunk/view/head:/keychain.py
+
+setting the password
+--------------------
+
+   security add-generic-password \
+            -a account \
+            -p password \
+            -s servicename \
+            blahblah.keychain
+
+   (again expects status 0)
+
+getting the password
+--------------------
+
+   security find-generic-password \
+            -g \
+            -a account \
+            -s servicename \
+            blahblah.keychain
+
+checks for exitcode 0 (otherwise fails) and greps standard output
+for regexps (account and password obligatorily, service optionally):
+
+RXACCOUNT = re.compile(r'"acct"<blob>="(.*?)"', re.S)
+RXPASS = re.compile(r'password: "(.*?)"', re.S)
+RXSERVICE = re.compile(r'"svce"<blob>="(.*?)"', re.S)
+
+removing the password
+---------------------
+
+To remove password, it loads all accounts from keychain, removes it,
+then creates new keychain minus given password.
+
+Seems overkill, some strange value as marker should do instead.
+
+listing keychain contents
+--------------------------
+
+   security dump-keychain -d blahlbah.keychain
+
+output is split by "keychain:" and each part is searched for the same
+regexps get_password uses in case of account and optional service,
+but with different regexp for password: 
+
+re.compile(r'data:.*?"(.*?)"', re.S)
+
+creating and deleting keychain
+------------------------------
+
+   security create-keychain -p password blahblah.keychain
+
+exit status of 12288 means that such keychain already exists,
+0 means success, other statuses failure
+
+   security delete-keychain blahblah.keychain
+
+(status 0 means OK)
+
+checking keychain existence and related commands
+------------------------------------------------
+
+to check existence it lists all keychains and checks
+whether name is on the list.
+
+   security show-keychain-info blahblah.keychain
+
+(non-zero output means no such keychain). Looks for fixed
+strings no-timeout and lock-on-sleep but maybe can be used
+for checking
+
+locking and lunlocking
+----------------------------------------------------------------------
+
+   security lock-keychain blah.keychain
+
+   security unlock-keychain blah.keychain
+
+(both status 0)
+
+
+listing keychains
+-----------------
+
+   security list-keychains
+
+        keychain_rx = re.compile(r'".*?/([0-9a-z_\-]*)\.keychain"', re.I | re.M)
+        keychains = {}
+        for match in keychain_rx.finditer(result):
+            keychains[match.group(1)]=match.group().strip('"')
+        return keychains
+
+
+