6
#define ENCODING kCFStringEncodingUTF8
7
static CFStringRef protocol; /* Stores constant strings - not memory managed */
8
static CFStringRef host;
9
+static CFNumberRef port;
10
static CFStringRef path;
11
static CFStringRef username;
12
static CFDataRef password;
12
-static CFNumberRef port;
13
+static CFDataRef password_expiry_utc;
14
+static CFDataRef oauth_refresh_token;
15
16
static void clear_credential(void)
17
{
19
CFRelease(host);
20
host = NULL;
21
}
22
+ if (port) {
23
+ CFRelease(port);
24
+ port = NULL;
25
+ }
26
if (path) {
27
CFRelease(path);
28
path = NULL;
35
CFRelease(password);
36
password = NULL;
37
}
32
- if (port) {
33
- CFRelease(port);
34
- port = NULL;
38
+ if (password_expiry_utc) {
39
+ CFRelease(password_expiry_utc);
40
+ password_expiry_utc = NULL;
41
+ }
42
+ if (oauth_refresh_token) {
43
+ CFRelease(oauth_refresh_token);
44
+ oauth_refresh_token = NULL;
45
}
46
}
47
48
+#define STRING_WITH_LENGTH(s) s, sizeof(s) - 1
49
+
50
__attribute__((format (printf, 1, 2), __noreturn__))
51
static void die(const char *err, ...)
52
{
209
CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
210
result = SecItemCopyMatching(query, (CFTypeRef *)&data);
211
if (!result) {
200
- if (CFEqual(data, password))
212
+ CFDataRef kc_password;
213
+ const UInt8 *raw_data;
214
+ const UInt8 *line;
215
+
216
+ /* Don't match appended metadata */
217
+ raw_data = CFDataGetBytePtr(data);
218
+ line = memchr(raw_data, '\n', CFDataGetLength(data));
219
+ if (line)
220
+ kc_password = CFDataCreateWithBytesNoCopy(
221
+ kCFAllocatorDefault,
222
+ raw_data,
223
+ line - raw_data,
224
+ kCFAllocatorNull);
225
+ else
226
+ kc_password = data;
227
+
228
+ if (CFEqual(kc_password, password))
229
result = SecItemDelete(delete_query);
230
231
+ if (line)
232
+ CFRelease(kc_password);
233
CFRelease(data);
234
}
235
280
281
static OSStatus add_internet_password(void)
282
{
283
+ CFMutableDataRef data;
284
CFDictionaryRef attrs;
285
OSStatus result;
286
288
if (!protocol || !host || !username || !password)
289
return -1;
290
260
- attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, password,
291
+ data = CFDataCreateMutableCopy(kCFAllocatorDefault, 0, password);
292
+ if (password_expiry_utc) {
293
+ CFDataAppendBytes(data,
294
+ (const UInt8 *)STRING_WITH_LENGTH("\npassword_expiry_utc="));
295
+ CFDataAppendBytes(data,
296
+ CFDataGetBytePtr(password_expiry_utc),
297
+ CFDataGetLength(password_expiry_utc));
298
+ }
299
+ if (oauth_refresh_token) {
300
+ CFDataAppendBytes(data,
301
+ (const UInt8 *)STRING_WITH_LENGTH("\noauth_refresh_token="));
302
+ CFDataAppendBytes(data,
303
+ CFDataGetBytePtr(oauth_refresh_token),
304
+ CFDataGetLength(oauth_refresh_token));
305
+ }
306
+
307
+ attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, data,
308
NULL);
309
310
result = SecItemAdd(attrs, NULL);
315
CFRelease(query);
316
}
317
318
+ CFRelease(data);
319
CFRelease(attrs);
320
321
return result;
387
password = CFDataCreate(kCFAllocatorDefault,
388
(UInt8 *)v,
389
strlen(v));
390
+ else if (!strcmp(buf, "password_expiry_utc"))
391
+ password_expiry_utc = CFDataCreate(kCFAllocatorDefault,
392
+ (UInt8 *)v,
393
+ strlen(v));
394
+ else if (!strcmp(buf, "oauth_refresh_token"))
395
+ oauth_refresh_token = CFDataCreate(kCFAllocatorDefault,
396
+ (UInt8 *)v,
397
+ strlen(v));
398
/*
399
* Ignore other lines; we don't know what they mean, but
400
* this future-proofs us when later versions of git do