...

Text file src/github.com/docker/docker-credential-helpers/osxkeychain/osxkeychain.c

Documentation: github.com/docker/docker-credential-helpers/osxkeychain

     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