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  }