2
#include <string.h>
3
#include <stdlib.h>
4
#include <Security/Security.h>
5
+#include "git-compat-util.h"
6
+#include "strbuf.h"
7
+#include "wrapper.h"
8
9
#define ENCODING kCFStringEncodingUTF8
10
static CFStringRef protocol; /* Stores constant strings - not memory managed */
15
static CFDataRef password;
16
static CFDataRef password_expiry_utc;
17
static CFDataRef oauth_refresh_token;
15
-static int state_seen;
18
+static char *state_seen;
19
20
static void clear_credential(void)
21
{
51
52
#define STRING_WITH_LENGTH(s) s, sizeof(s) - 1
53
51
-__attribute__((format (printf, 1, 2), __noreturn__))
52
-static void die(const char *err, ...)
53
-{
54
- char msg[4096];
55
- va_list params;
56
- va_start(params, err);
57
- vsnprintf(msg, sizeof(msg), err, params);
58
- fprintf(stderr, "%s\n", msg);
59
- va_end(params);
60
- clear_credential();
61
- exit(1);
62
-}
63
-
64
-static void *xmalloc(size_t len)
65
-{
66
- void *ret = malloc(len);
67
- if (!ret)
68
- die("Out of memory");
69
- return ret;
70
-}
71
-
54
static CFDictionaryRef create_dictionary(CFAllocatorRef allocator, ...)
55
{
56
va_list args;
94
putchar('\n');
95
}
96
97
+static void write_item_strbuf(struct strbuf *sb, const char *what, const char *buf, int n)
98
+{
99
+ char s[32];
100
+
101
+ xsnprintf(s, sizeof(s), "__%s=", what);
102
+ strbuf_add(sb, s, strlen(s));
103
+ strbuf_add(sb, buf, n);
104
+}
105
+
106
+static void write_item_strbuf_cfstring(struct strbuf *sb, const char *what, CFStringRef ref)
107
+{
108
+ char *buf;
109
+ int len;
110
+
111
+ if (!ref)
112
+ return;
113
+ len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), ENCODING) + 1;
114
+ buf = xmalloc(len);
115
+ if (CFStringGetCString(ref, buf, len, ENCODING))
116
+ write_item_strbuf(sb, what, buf, strlen(buf));
117
+ free(buf);
118
+}
119
+
120
+static void write_item_strbuf_cfnumber(struct strbuf *sb, const char *what, CFNumberRef ref)
121
+{
122
+ short n;
123
+ char buf[32];
124
+
125
+ if (!ref)
126
+ return;
127
+ if (!CFNumberGetValue(ref, kCFNumberShortType, &n))
128
+ return;
129
+ xsnprintf(buf, sizeof(buf), "%d", n);
130
+ write_item_strbuf(sb, what, buf, strlen(buf));
131
+}
132
+
133
+static void write_item_strbuf_cfdata(struct strbuf *sb, const char *what, CFDataRef ref)
134
+{
135
+ char *buf;
136
+ int len;
137
+
138
+ if (!ref)
139
+ return;
140
+ buf = (char *)CFDataGetBytePtr(ref);
141
+ if (!buf || strlen(buf) == 0)
142
+ return;
143
+ len = CFDataGetLength(ref);
144
+ write_item_strbuf(sb, what, buf, len);
145
+}
146
+
147
+static void encode_state_seen(struct strbuf *sb)
148
+{
149
+ strbuf_add(sb, "osxkeychain:seen=", strlen("osxkeychain:seen="));
150
+ write_item_strbuf_cfstring(sb, "host", host);
151
+ write_item_strbuf_cfnumber(sb, "port", port);
152
+ write_item_strbuf_cfstring(sb, "path", path);
153
+ write_item_strbuf_cfstring(sb, "username", username);
154
+ write_item_strbuf_cfdata(sb, "password", password);
155
+}
156
+
157
static void find_username_in_item(CFDictionaryRef item)
158
{
159
CFStringRef account_ref;
166
write_item("username", "", 0);
167
return;
168
}
169
+ username = CFStringCreateCopy(kCFAllocatorDefault, account_ref);
170
171
username_buf = (char *)CFStringGetCStringPtr(account_ref, ENCODING);
172
if (username_buf)
206
}
207
208
data = CFDictionaryGetValue(item, kSecValueData);
209
+ password = CFDataCreateCopy(kCFAllocatorDefault, data);
210
211
write_item("password",
212
(const char *)CFDataGetBytePtr(data),
217
CFRelease(item);
218
219
write_item("capability[]", "state", strlen("state"));
176
- write_item("state[]", "osxkeychain:seen=1", strlen("osxkeychain:seen=1"));
220
+ {
221
+ struct strbuf sb;
222
+
223
+ strbuf_init(&sb, 1024);
224
+ encode_state_seen(&sb);
225
+ write_item("state[]", sb.buf, strlen(sb.buf));
226
+ strbuf_release(&sb);
227
+ }
228
229
out:
230
CFRelease(attrs);
339
CFDictionaryRef attrs;
340
OSStatus result;
341
291
- if (state_seen)
292
- return errSecSuccess;
293
-
342
/* Only store complete credentials */
343
if (!protocol || !host || !username || !password)
344
return -1;
345
346
+ if (state_seen) {
347
+ struct strbuf sb;
348
+
349
+ strbuf_init(&sb, 1024);
350
+ encode_state_seen(&sb);
351
+ if (!strcmp(state_seen, sb.buf)) {
352
+ strbuf_release(&sb);
353
+ return errSecSuccess;
354
+ }
355
+ strbuf_release(&sb);
356
+ }
357
+
358
data = CFDataCreateMutableCopy(kCFAllocatorDefault, 0, password);
359
if (password_expiry_utc) {
360
CFDataAppendBytes(data,
463
(UInt8 *)v,
464
strlen(v));
465
else if (!strcmp(buf, "state[]")) {
406
- if (!strcmp(v, "osxkeychain:seen=1"))
407
- state_seen = 1;
466
+ int len = strlen("osxkeychain:seen=");
467
+ if (!strncmp(v, "osxkeychain:seen=", len))
468
+ state_seen = xstrdup(v);
469
}
470
/*
471
* Ignore other lines; we don't know what they mean, but
504
505
clear_credential();
506
507
+ if (state_seen)
508
+ free(state_seen);
509
+
510
return 0;
511
}