1#include "osxkeychain.h"
2#include <CoreFoundation/CoreFoundation.h>
3#include <Foundation/NSValue.h>
4#include <stdio.h>
5#include <string.h>
6
7char *get_error(OSStatus status) {
8 char *buf = malloc(128);
9 CFStringRef str = SecCopyErrorMessageString(status, NULL);
10 int success = CFStringGetCString(str, buf, 128, kCFStringEncodingUTF8);
11 if (!success) {
12 strncpy(buf, "Unknown error", 128);
13 }
14 return buf;
15}
16
17char *keychain_add(struct Server *server, char *label, char *username, char *secret) {
18 SecKeychainItemRef item;
19
20 OSStatus status = SecKeychainAddInternetPassword(
21 NULL,
22 strlen(server->host), server->host,
23 0, NULL,
24 strlen(username), username,
25 strlen(server->path), server->path,
26 server->port,
27 server->proto,
28 kSecAuthenticationTypeDefault,
29 strlen(secret), secret,
30 &item
31 );
32
33 if (status) {
34 return get_error(status);
35 }
36
37 SecKeychainAttribute attribute;
38 SecKeychainAttributeList attrs;
39 attribute.tag = kSecLabelItemAttr;
40 attribute.data = label;
41 attribute.length = strlen(label);
42 attrs.count = 1;
43 attrs.attr = &attribute;
44
45 status = SecKeychainItemModifyContent(item, &attrs, 0, NULL);
46
47 if (status) {
48 return get_error(status);
49 }
50
51 return NULL;
52}
53
54char *keychain_get(struct Server *server, unsigned int *username_l, char **username, unsigned int *secret_l, char **secret) {
55 char *tmp;
56 SecKeychainItemRef item;
57
58 OSStatus status = SecKeychainFindInternetPassword(
59 NULL,
60 strlen(server->host), server->host,
61 0, NULL,
62 0, NULL,
63 strlen(server->path), server->path,
64 server->port,
65 server->proto,
66 kSecAuthenticationTypeDefault,
67 secret_l, (void **)&tmp,
68 &item);
69
70 if (status) {
71 return get_error(status);
72 }
73
74 *secret = strdup(tmp);
75 SecKeychainItemFreeContent(NULL, tmp);
76
77 SecKeychainAttributeList list;
78 SecKeychainAttribute attr;
79
80 list.count = 1;
81 list.attr = &attr;
82 attr.tag = kSecAccountItemAttr;
83
84 status = SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL);
85 if (status) {
86 return get_error(status);
87 }
88
89 *username = strdup(attr.data);
90 *username_l = attr.length;
91 SecKeychainItemFreeContent(&list, NULL);
92
93 return NULL;
94}
95
96char *keychain_delete(struct Server *server) {
97 SecKeychainItemRef item;
98
99 OSStatus status = SecKeychainFindInternetPassword(
100 NULL,
101 strlen(server->host), server->host,
102 0, NULL,
103 0, NULL,
104 strlen(server->path), server->path,
105 server->port,
106 server->proto,
107 kSecAuthenticationTypeDefault,
108 0, NULL,
109 &item);
110
111 if (status) {
112 return get_error(status);
113 }
114
115 status = SecKeychainItemDelete(item);
116 if (status) {
117 return get_error(status);
118 }
119 return NULL;
120}
121
122char * CFStringToCharArr(CFStringRef aString) {
123 if (aString == NULL) {
124 return NULL;
125 }
126 CFIndex length = CFStringGetLength(aString);
127 CFIndex maxSize =
128 CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
129 char *buffer = (char *)malloc(maxSize);
130 if (CFStringGetCString(aString, buffer, maxSize,
131 kCFStringEncodingUTF8)) {
132 return buffer;
133 }
134 return NULL;
135}
136
137char *keychain_list(char *credsLabel, char *** paths, char *** accts, unsigned int *list_l) {
138 CFStringRef credsLabelCF = CFStringCreateWithCString(NULL, credsLabel, kCFStringEncodingUTF8);
139 CFMutableDictionaryRef query = CFDictionaryCreateMutable (NULL, 1, NULL, NULL);
140 CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
141 CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue);
142 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll);
143 CFDictionaryAddValue(query, kSecAttrLabel, credsLabelCF);
144 //Use this query dictionary
145 CFTypeRef result= NULL;
146 OSStatus status = SecItemCopyMatching(
147 query,
148 &result);
149
150 CFRelease(credsLabelCF);
151
152 //Ran a search and store the results in result
153 if (status) {
154 return get_error(status);
155 }
156 CFIndex numKeys = CFArrayGetCount(result);
157 *paths = (char **) malloc((int)sizeof(char *)*numKeys);
158 *accts = (char **) malloc((int)sizeof(char *)*numKeys);
159 //result is of type CFArray
160 for(CFIndex i=0; i<numKeys; i++) {
161 CFDictionaryRef currKey = CFArrayGetValueAtIndex(result,i);
162
163 CFStringRef protocolTmp = CFDictionaryGetValue(currKey, CFSTR("ptcl"));
164 if (protocolTmp != NULL) {
165 CFStringRef protocolStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), protocolTmp);
166 if (CFStringCompare(protocolStr, CFSTR("htps"), 0) == kCFCompareEqualTo) {
167 protocolTmp = CFSTR("https://");
168 }
169 else {
170 protocolTmp = CFSTR("http://");
171 }
172 CFRelease(protocolStr);
173 }
174 else {
175 char * path = "0";
176 char * acct = "0";
177 (*paths)[i] = (char *) malloc(sizeof(char)*(strlen(path)));
178 memcpy((*paths)[i], path, sizeof(char)*(strlen(path)));
179 (*accts)[i] = (char *) malloc(sizeof(char)*(strlen(acct)));
180 memcpy((*accts)[i], acct, sizeof(char)*(strlen(acct)));
181 continue;
182 }
183
184 CFMutableStringRef str = CFStringCreateMutableCopy(NULL, 0, protocolTmp);
185 CFStringRef serverTmp = CFDictionaryGetValue(currKey, CFSTR("srvr"));
186 if (serverTmp != NULL) {
187 CFStringAppend(str, serverTmp);
188 }
189
190 CFStringRef pathTmp = CFDictionaryGetValue(currKey, CFSTR("path"));
191 if (pathTmp != NULL) {
192 CFStringAppend(str, pathTmp);
193 }
194
195 const NSNumber * portTmp = CFDictionaryGetValue(currKey, CFSTR("port"));
196 if (portTmp != NULL && portTmp.integerValue != 0) {
197 CFStringRef portStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), portTmp);
198 CFStringAppend(str, CFSTR(":"));
199 CFStringAppend(str, portStr);
200 CFRelease(portStr);
201 }
202
203 CFStringRef acctTmp = CFDictionaryGetValue(currKey, CFSTR("acct"));
204 if (acctTmp == NULL) {
205 acctTmp = CFSTR("account not defined");
206 }
207
208 char * path = CFStringToCharArr(str);
209 char * acct = CFStringToCharArr(acctTmp);
210
211 //We now have all we need, username and servername. Now export this to .go
212 (*paths)[i] = (char *) malloc(sizeof(char)*(strlen(path)+1));
213 memcpy((*paths)[i], path, sizeof(char)*(strlen(path)+1));
214 (*accts)[i] = (char *) malloc(sizeof(char)*(strlen(acct)+1));
215 memcpy((*accts)[i], acct, sizeof(char)*(strlen(acct)+1));
216
217 CFRelease(str);
218 }
219 *list_l = (int)numKeys;
220 return NULL;
221}
222
223void freeListData(char *** data, unsigned int length) {
224 for(int i=0; i<length; i++) {
225 free((*data)[i]);
226 }
227}
View as plain text