github.com/versent/saml2aws@v2.17.0+incompatible/helper/osxkeychain/osxkeychain_darwin.c (about) 1 // Copyright (c) 2016 David Calavera 2 3 // Permission is hereby granted, free of charge, to any person obtaining 4 // a copy of this software and associated documentation files (the 5 // "Software"), to deal in the Software without restriction, including 6 // without limitation the rights to use, copy, modify, merge, publish, 7 // distribute, sublicense, and/or sell copies of the Software, and to 8 // permit persons to whom the Software is furnished to do so, subject to 9 // the following conditions: 10 11 // The above copyright notice and this permission notice shall be 12 // included in all copies or substantial portions of the Software. 13 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 // 22 // https://github.com/docker/docker-credential-helpers 23 #include "osxkeychain_darwin.h" 24 #include <CoreFoundation/CoreFoundation.h> 25 #include <Foundation/NSValue.h> 26 #include <stdio.h> 27 #include <string.h> 28 29 char *get_error(OSStatus status) { 30 char *buf = malloc(128); 31 CFStringRef str = SecCopyErrorMessageString(status, NULL); 32 int success = CFStringGetCString(str, buf, 128, kCFStringEncodingUTF8); 33 if (!success) { 34 strncpy(buf, "Unknown error", 128); 35 } 36 return buf; 37 } 38 39 char *keychain_add(struct Server *server, char *label, char *username, char *secret) { 40 SecKeychainItemRef item; 41 42 OSStatus status = SecKeychainAddInternetPassword( 43 NULL, 44 strlen(server->host), server->host, 45 0, NULL, 46 strlen(username), username, 47 strlen(server->path), server->path, 48 server->port, 49 server->proto, 50 kSecAuthenticationTypeDefault, 51 strlen(secret), secret, 52 &item 53 ); 54 55 if (status) { 56 return get_error(status); 57 } 58 59 SecKeychainAttribute attribute; 60 SecKeychainAttributeList attrs; 61 attribute.tag = kSecLabelItemAttr; 62 attribute.data = label; 63 attribute.length = strlen(label); 64 attrs.count = 1; 65 attrs.attr = &attribute; 66 67 status = SecKeychainItemModifyContent(item, &attrs, 0, NULL); 68 69 if (status) { 70 return get_error(status); 71 } 72 73 return NULL; 74 } 75 76 char *keychain_get(struct Server *server, unsigned int *username_l, char **username, unsigned int *secret_l, char **secret) { 77 char *tmp; 78 SecKeychainItemRef item; 79 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 secret_l, (void **)&tmp, 90 &item); 91 92 if (status) { 93 return get_error(status); 94 } 95 96 *secret = strdup(tmp); 97 SecKeychainItemFreeContent(NULL, tmp); 98 99 SecKeychainAttributeList list; 100 SecKeychainAttribute attr; 101 102 list.count = 1; 103 list.attr = &attr; 104 attr.tag = kSecAccountItemAttr; 105 106 status = SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL); 107 if (status) { 108 return get_error(status); 109 } 110 111 *username = strdup(attr.data); 112 *username_l = attr.length; 113 SecKeychainItemFreeContent(&list, NULL); 114 115 return NULL; 116 } 117 118 char *keychain_delete(struct Server *server) { 119 SecKeychainItemRef item; 120 121 OSStatus status = SecKeychainFindInternetPassword( 122 NULL, 123 strlen(server->host), server->host, 124 0, NULL, 125 0, NULL, 126 strlen(server->path), server->path, 127 server->port, 128 server->proto, 129 kSecAuthenticationTypeDefault, 130 0, NULL, 131 &item); 132 133 if (status) { 134 return get_error(status); 135 } 136 137 status = SecKeychainItemDelete(item); 138 if (status) { 139 return get_error(status); 140 } 141 return NULL; 142 } 143 144 char * CFStringToCharArr(CFStringRef aString) { 145 if (aString == NULL) { 146 return NULL; 147 } 148 CFIndex length = CFStringGetLength(aString); 149 CFIndex maxSize = 150 CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; 151 char *buffer = (char *)malloc(maxSize); 152 if (CFStringGetCString(aString, buffer, maxSize, 153 kCFStringEncodingUTF8)) { 154 return buffer; 155 } 156 return NULL; 157 } 158 159 char *keychain_list(char *credsLabel, char *** paths, char *** accts, unsigned int *list_l) { 160 CFStringRef credsLabelCF = CFStringCreateWithCString(NULL, credsLabel, kCFStringEncodingUTF8); 161 CFMutableDictionaryRef query = CFDictionaryCreateMutable (NULL, 1, NULL, NULL); 162 CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); 163 CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue); 164 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll); 165 CFDictionaryAddValue(query, kSecAttrLabel, credsLabelCF); 166 //Use this query dictionary 167 CFTypeRef result= NULL; 168 OSStatus status = SecItemCopyMatching( 169 query, 170 &result); 171 172 CFRelease(credsLabelCF); 173 174 //Ran a search and store the results in result 175 if (status) { 176 return get_error(status); 177 } 178 CFIndex numKeys = CFArrayGetCount(result); 179 *paths = (char **) malloc((int)sizeof(char *)*numKeys); 180 *accts = (char **) malloc((int)sizeof(char *)*numKeys); 181 //result is of type CFArray 182 for(CFIndex i=0; i<numKeys; i++) { 183 CFDictionaryRef currKey = CFArrayGetValueAtIndex(result,i); 184 185 CFStringRef protocolTmp = CFDictionaryGetValue(currKey, CFSTR("ptcl")); 186 if (protocolTmp != NULL) { 187 CFStringRef protocolStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), protocolTmp); 188 if (CFStringCompare(protocolStr, CFSTR("htps"), 0) == kCFCompareEqualTo) { 189 protocolTmp = CFSTR("https://"); 190 } 191 else { 192 protocolTmp = CFSTR("http://"); 193 } 194 CFRelease(protocolStr); 195 } 196 else { 197 char * path = "0"; 198 char * acct = "0"; 199 (*paths)[i] = (char *) malloc(sizeof(char)*(strlen(path))); 200 memcpy((*paths)[i], path, sizeof(char)*(strlen(path))); 201 (*accts)[i] = (char *) malloc(sizeof(char)*(strlen(acct))); 202 memcpy((*accts)[i], acct, sizeof(char)*(strlen(acct))); 203 continue; 204 } 205 206 CFMutableStringRef str = CFStringCreateMutableCopy(NULL, 0, protocolTmp); 207 CFStringRef serverTmp = CFDictionaryGetValue(currKey, CFSTR("srvr")); 208 if (serverTmp != NULL) { 209 CFStringAppend(str, serverTmp); 210 } 211 212 CFStringRef pathTmp = CFDictionaryGetValue(currKey, CFSTR("path")); 213 if (pathTmp != NULL) { 214 CFStringAppend(str, pathTmp); 215 } 216 217 const NSNumber * portTmp = CFDictionaryGetValue(currKey, CFSTR("port")); 218 if (portTmp != NULL && portTmp.integerValue != 0) { 219 CFStringRef portStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), portTmp); 220 CFStringAppend(str, CFSTR(":")); 221 CFStringAppend(str, portStr); 222 CFRelease(portStr); 223 } 224 225 CFStringRef acctTmp = CFDictionaryGetValue(currKey, CFSTR("acct")); 226 if (acctTmp == NULL) { 227 acctTmp = CFSTR("account not defined"); 228 } 229 230 char * path = CFStringToCharArr(str); 231 char * acct = CFStringToCharArr(acctTmp); 232 233 //We now have all we need, username and servername. Now export this to .go 234 (*paths)[i] = (char *) malloc(sizeof(char)*(strlen(path)+1)); 235 memcpy((*paths)[i], path, sizeof(char)*(strlen(path)+1)); 236 (*accts)[i] = (char *) malloc(sizeof(char)*(strlen(acct)+1)); 237 memcpy((*accts)[i], acct, sizeof(char)*(strlen(acct)+1)); 238 239 CFRelease(str); 240 } 241 *list_l = (int)numKeys; 242 return NULL; 243 } 244 245 void freeListData(char *** data, unsigned int length) { 246 for(int i=0; i<length; i++) { 247 free((*data)[i]); 248 } 249 free(*data); 250 }