Use dlopen() / dysym() instead of dynmically linking to the Security framework. A followup commit will refactor things such that git-credential-osxkeychain can be hardlinked to git. Signed-off-by: Jay Soffian <jaysoffian@xxxxxxxxx> --- > Hmm, maybe it can be if I dlopen the security framework instead of linking > against it. Something like this. I'm going to pause here for feedback. Is the (not yet existant) followup commit referenced above allowing git-credential-osxkeychain to be a hard link to git a worthwhile endeavor? Or would a better approach be to make git-credential-osxkeychain.c not use any git code? contrib/credential-osxkeychain/Makefile | 12 +++- .../credential-osxkeychain/generate_security.py | 73 ++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100755 contrib/credential-osxkeychain/generate_security.py diff --git a/contrib/credential-osxkeychain/Makefile b/contrib/credential-osxkeychain/Makefile index dc6bbbc3f9..001d695cb8 100644 --- a/contrib/credential-osxkeychain/Makefile +++ b/contrib/credential-osxkeychain/Makefile @@ -25,11 +25,17 @@ ifndef V endif endif -git-credential-osxkeychain: git-credential-osxkeychain.o $(GIT_LIBS) - $(QUIET_LINK)$(CC) -o $@ $< $(LIBS) -Wl,-framework -Wl,Security +git-credential-osxkeychain: git-credential-osxkeychain.o security.o $(GIT_LIBS) + $(QUIET_LINK)$(CC) -o $@ $< security.o $(LIBS) git-credential-osxkeychain.o: git-credential-osxkeychain.c $(QUIET_CC)$(CC) -c $(CFLAGS) $< +security.o: security.c + $(QUIET_CC)$(CC) -c $(CFLAGS) $< + +security.c: generate_security.py + python generate_security.py + clean: - $(RM) git-credential-osxkeychain git-credential-osxkeychain.o + $(RM) git-credential-osxkeychain git-credential-osxkeychain.o security.? diff --git a/contrib/credential-osxkeychain/generate_security.py b/contrib/credential-osxkeychain/generate_security.py new file mode 100755 index 0000000000..db94672e95 --- /dev/null +++ b/contrib/credential-osxkeychain/generate_security.py @@ -0,0 +1,73 @@ +#!/usr/bin/python + +import re + +func_decls = """ +OSStatus SecKeychainAddInternetPassword(SecKeychainRef keychain, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef); +OSStatus SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef); +OSStatus SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass *itemClass, SecKeychainAttributeList *attrList, UInt32 *length, void **outData); +OSStatus SecKeychainItemDelete(SecKeychainItemRef itemRef); +OSStatus SecKeychainItemFreeContent(SecKeychainAttributeList *attrList, void *data); +OSStatus SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data); +""" + +header = r""" +#include <dlfcn.h> +#include <Security/Security.h> +#include "cache.h" + +const char *security_framework = + "/System/Library/Frameworks/Security.framework/Security"; + +void *load_security() +{ + static void *security; + if (!security) { + if (!(security = dlopen(security_framework, RTLD_LAZY))) + die(_("dlopen(\"%s\") failed: %s"), + security_framework, dlerror()); + } + return security; +} +""" + +func_tmpl = """ +%(func_decl)s +{ + %(func_rv)s (*func)(%(arg_types)s) = + dlsym(load_security(), "%(func_name)s"); + if (!func) + die(_("dlsym(%(func_name)s) failed: %%s"), dlerror()); + return func(%(arg_names)s); +} +""" + +def generate_func(decl): + func_rv, func_name, func_args = re.search( + r'^(.*?)\s+([^(]+)\((.*)\);$', decl).groups() + func_args = [s.strip() for s in func_args.split(',')] + arg_types = [] + arg_names = [] + for arg in func_args: + arg_type, arg_name = re.search(r'^(.*?)([a-zA-Z]+)$', arg).groups() + arg_types.append(arg_type.strip()) + arg_names.append(arg_name.strip()) + return func_tmpl % dict( + func_decl=decl.rstrip(';'), + func_name=func_name, + func_rv=func_rv, + arg_types=', '.join(arg_types), + arg_names=', '.join(arg_names), + ) + +def main(): + f = open('security.c', 'w') + f.write(header) + for decl in func_decls.splitlines(): + decl = decl.strip() + if decl: + f.write(generate_func(decl)) + f.close() + +if __name__ == '__main__': + main() -- 1.7.7.rc1.1.g011e1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html