osxkeychain_darwin.c 6.7 KB

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