Squashed 'third_party/git/' content from commit cb71568594
git-subtree-dir: third_party/git git-subtree-split: cb715685942260375e1eb8153b0768a376e4ece7
This commit is contained in:
commit
1b593e1ea4
3629 changed files with 1139935 additions and 0 deletions
183
contrib/credential/osxkeychain/git-credential-osxkeychain.c
Normal file
183
contrib/credential/osxkeychain/git-credential-osxkeychain.c
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
static SecProtocolType protocol;
|
||||
static char *host;
|
||||
static char *path;
|
||||
static char *username;
|
||||
static char *password;
|
||||
static UInt16 port;
|
||||
|
||||
static void die(const char *err, ...)
|
||||
{
|
||||
char msg[4096];
|
||||
va_list params;
|
||||
va_start(params, err);
|
||||
vsnprintf(msg, sizeof(msg), err, params);
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
va_end(params);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void *xstrdup(const char *s1)
|
||||
{
|
||||
void *ret = strdup(s1);
|
||||
if (!ret)
|
||||
die("Out of memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define KEYCHAIN_ITEM(x) (x ? strlen(x) : 0), x
|
||||
#define KEYCHAIN_ARGS \
|
||||
NULL, /* default keychain */ \
|
||||
KEYCHAIN_ITEM(host), \
|
||||
0, NULL, /* account domain */ \
|
||||
KEYCHAIN_ITEM(username), \
|
||||
KEYCHAIN_ITEM(path), \
|
||||
port, \
|
||||
protocol, \
|
||||
kSecAuthenticationTypeDefault
|
||||
|
||||
static void write_item(const char *what, const char *buf, int len)
|
||||
{
|
||||
printf("%s=", what);
|
||||
fwrite(buf, 1, len, stdout);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void find_username_in_item(SecKeychainItemRef item)
|
||||
{
|
||||
SecKeychainAttributeList list;
|
||||
SecKeychainAttribute attr;
|
||||
|
||||
list.count = 1;
|
||||
list.attr = &attr;
|
||||
attr.tag = kSecAccountItemAttr;
|
||||
|
||||
if (SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL))
|
||||
return;
|
||||
|
||||
write_item("username", attr.data, attr.length);
|
||||
SecKeychainItemFreeContent(&list, NULL);
|
||||
}
|
||||
|
||||
static void find_internet_password(void)
|
||||
{
|
||||
void *buf;
|
||||
UInt32 len;
|
||||
SecKeychainItemRef item;
|
||||
|
||||
if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, &len, &buf, &item))
|
||||
return;
|
||||
|
||||
write_item("password", buf, len);
|
||||
if (!username)
|
||||
find_username_in_item(item);
|
||||
|
||||
SecKeychainItemFreeContent(NULL, buf);
|
||||
}
|
||||
|
||||
static void delete_internet_password(void)
|
||||
{
|
||||
SecKeychainItemRef item;
|
||||
|
||||
/*
|
||||
* Require at least a protocol and host for removal, which is what git
|
||||
* will give us; if you want to do something more fancy, use the
|
||||
* Keychain manager.
|
||||
*/
|
||||
if (!protocol || !host)
|
||||
return;
|
||||
|
||||
if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, 0, NULL, &item))
|
||||
return;
|
||||
|
||||
SecKeychainItemDelete(item);
|
||||
}
|
||||
|
||||
static void add_internet_password(void)
|
||||
{
|
||||
/* Only store complete credentials */
|
||||
if (!protocol || !host || !username || !password)
|
||||
return;
|
||||
|
||||
if (SecKeychainAddInternetPassword(
|
||||
KEYCHAIN_ARGS,
|
||||
KEYCHAIN_ITEM(password),
|
||||
NULL))
|
||||
return;
|
||||
}
|
||||
|
||||
static void read_credential(void)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
while (fgets(buf, sizeof(buf), stdin)) {
|
||||
char *v;
|
||||
|
||||
if (!strcmp(buf, "\n"))
|
||||
break;
|
||||
buf[strlen(buf)-1] = '\0';
|
||||
|
||||
v = strchr(buf, '=');
|
||||
if (!v)
|
||||
die("bad input: %s", buf);
|
||||
*v++ = '\0';
|
||||
|
||||
if (!strcmp(buf, "protocol")) {
|
||||
if (!strcmp(v, "imap"))
|
||||
protocol = kSecProtocolTypeIMAP;
|
||||
else if (!strcmp(v, "imaps"))
|
||||
protocol = kSecProtocolTypeIMAPS;
|
||||
else if (!strcmp(v, "ftp"))
|
||||
protocol = kSecProtocolTypeFTP;
|
||||
else if (!strcmp(v, "ftps"))
|
||||
protocol = kSecProtocolTypeFTPS;
|
||||
else if (!strcmp(v, "https"))
|
||||
protocol = kSecProtocolTypeHTTPS;
|
||||
else if (!strcmp(v, "http"))
|
||||
protocol = kSecProtocolTypeHTTP;
|
||||
else if (!strcmp(v, "smtp"))
|
||||
protocol = kSecProtocolTypeSMTP;
|
||||
else /* we don't yet handle other protocols */
|
||||
exit(0);
|
||||
}
|
||||
else if (!strcmp(buf, "host")) {
|
||||
char *colon = strchr(v, ':');
|
||||
if (colon) {
|
||||
*colon++ = '\0';
|
||||
port = atoi(colon);
|
||||
}
|
||||
host = xstrdup(v);
|
||||
}
|
||||
else if (!strcmp(buf, "path"))
|
||||
path = xstrdup(v);
|
||||
else if (!strcmp(buf, "username"))
|
||||
username = xstrdup(v);
|
||||
else if (!strcmp(buf, "password"))
|
||||
password = xstrdup(v);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
const char *usage =
|
||||
"usage: git credential-osxkeychain <get|store|erase>";
|
||||
|
||||
if (!argv[1])
|
||||
die(usage);
|
||||
|
||||
read_credential();
|
||||
|
||||
if (!strcmp(argv[1], "get"))
|
||||
find_internet_password();
|
||||
else if (!strcmp(argv[1], "store"))
|
||||
add_internet_password();
|
||||
else if (!strcmp(argv[1], "erase"))
|
||||
delete_internet_password();
|
||||
/* otherwise, ignore unknown action */
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue