4 #include <Security/Security.h>
6 static SecProtocolType protocol;
10 static char *password;
13 static void die(const char *err, ...)
17 va_start(params, err);
18 vsnprintf(msg, sizeof(msg), err, params);
19 fprintf(stderr, "%s\n", msg);
24 static void *xstrdup(const char *s1)
26 void *ret = strdup(s1);
32 #define KEYCHAIN_ITEM(x) (x ? strlen(x) : 0), x
33 #define KEYCHAIN_ARGS \
34 NULL, /* default keychain */ \
35 KEYCHAIN_ITEM(host), \
36 0, NULL, /* account domain */ \
37 KEYCHAIN_ITEM(username), \
38 KEYCHAIN_ITEM(path), \
41 kSecAuthenticationTypeDefault
43 static void write_item(const char *what, const char *buf, int len)
46 fwrite(buf, 1, len, stdout);
50 static void find_username_in_item(SecKeychainItemRef item)
52 SecKeychainAttributeList list;
53 SecKeychainAttribute attr;
57 attr.tag = kSecAccountItemAttr;
59 if (SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL))
62 write_item("username", attr.data, attr.length);
63 SecKeychainItemFreeContent(&list, NULL);
66 static void find_internet_password(void)
70 SecKeychainItemRef item;
72 if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, &len, &buf, &item))
75 write_item("password", buf, len);
77 find_username_in_item(item);
79 SecKeychainItemFreeContent(NULL, buf);
82 static void delete_internet_password(void)
84 SecKeychainItemRef item;
87 * Require at least a protocol and host for removal, which is what git
88 * will give us; if you want to do something more fancy, use the
91 if (!protocol || !host)
94 if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, 0, NULL, &item))
97 SecKeychainItemDelete(item);
100 static void add_internet_password(void)
102 /* Only store complete credentials */
103 if (!protocol || !host || !username || !password)
106 if (SecKeychainAddInternetPassword(
108 KEYCHAIN_ITEM(password),
113 static void read_credential(void)
117 while (fgets(buf, sizeof(buf), stdin)) {
120 if (!strcmp(buf, "\n"))
122 buf[strlen(buf)-1] = '\0';
124 v = strchr(buf, '=');
126 die("bad input: %s", buf);
129 if (!strcmp(buf, "protocol")) {
130 if (!strcmp(v, "https"))
131 protocol = kSecProtocolTypeHTTPS;
132 else if (!strcmp(v, "http"))
133 protocol = kSecProtocolTypeHTTP;
134 else /* we don't yet handle other protocols */
137 else if (!strcmp(buf, "host")) {
138 char *colon = strchr(v, ':');
145 else if (!strcmp(buf, "path"))
147 else if (!strcmp(buf, "username"))
148 username = xstrdup(v);
149 else if (!strcmp(buf, "password"))
150 password = xstrdup(v);
154 int main(int argc, const char **argv)
157 "Usage: git credential-osxkeychain <get|store|erase>";
164 if (!strcmp(argv[1], "get"))
165 find_internet_password();
166 else if (!strcmp(argv[1], "store"))
167 add_internet_password();
168 else if (!strcmp(argv[1], "erase"))
169 delete_internet_password();
170 /* otherwise, ignore unknown action */