Vendor in latest containers/image
Adds support for credential helpers Signed-off-by: umohnani8 <umohnani@redhat.com>
This commit is contained in:
parent
8538c4067a
commit
e9467dc540
24 changed files with 1405 additions and 10 deletions
228
vendor/github.com/docker/docker-credential-helpers/osxkeychain/osxkeychain_darwin.c
generated
vendored
Normal file
228
vendor/github.com/docker/docker-credential-helpers/osxkeychain/osxkeychain_darwin.c
generated
vendored
Normal file
|
@ -0,0 +1,228 @@
|
|||
#include "osxkeychain_darwin.h"
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Foundation/NSValue.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
char *get_error(OSStatus status) {
|
||||
char *buf = malloc(128);
|
||||
CFStringRef str = SecCopyErrorMessageString(status, NULL);
|
||||
int success = CFStringGetCString(str, buf, 128, kCFStringEncodingUTF8);
|
||||
if (!success) {
|
||||
strncpy(buf, "Unknown error", 128);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *keychain_add(struct Server *server, char *label, char *username, char *secret) {
|
||||
SecKeychainItemRef item;
|
||||
|
||||
OSStatus status = SecKeychainAddInternetPassword(
|
||||
NULL,
|
||||
strlen(server->host), server->host,
|
||||
0, NULL,
|
||||
strlen(username), username,
|
||||
strlen(server->path), server->path,
|
||||
server->port,
|
||||
server->proto,
|
||||
kSecAuthenticationTypeDefault,
|
||||
strlen(secret), secret,
|
||||
&item
|
||||
);
|
||||
|
||||
if (status) {
|
||||
return get_error(status);
|
||||
}
|
||||
|
||||
SecKeychainAttribute attribute;
|
||||
SecKeychainAttributeList attrs;
|
||||
attribute.tag = kSecLabelItemAttr;
|
||||
attribute.data = label;
|
||||
attribute.length = strlen(label);
|
||||
attrs.count = 1;
|
||||
attrs.attr = &attribute;
|
||||
|
||||
status = SecKeychainItemModifyContent(item, &attrs, 0, NULL);
|
||||
|
||||
if (status) {
|
||||
return get_error(status);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *keychain_get(struct Server *server, unsigned int *username_l, char **username, unsigned int *secret_l, char **secret) {
|
||||
char *tmp;
|
||||
SecKeychainItemRef item;
|
||||
|
||||
OSStatus status = SecKeychainFindInternetPassword(
|
||||
NULL,
|
||||
strlen(server->host), server->host,
|
||||
0, NULL,
|
||||
0, NULL,
|
||||
strlen(server->path), server->path,
|
||||
server->port,
|
||||
server->proto,
|
||||
kSecAuthenticationTypeDefault,
|
||||
secret_l, (void **)&tmp,
|
||||
&item);
|
||||
|
||||
if (status) {
|
||||
return get_error(status);
|
||||
}
|
||||
|
||||
*secret = strdup(tmp);
|
||||
SecKeychainItemFreeContent(NULL, tmp);
|
||||
|
||||
SecKeychainAttributeList list;
|
||||
SecKeychainAttribute attr;
|
||||
|
||||
list.count = 1;
|
||||
list.attr = &attr;
|
||||
attr.tag = kSecAccountItemAttr;
|
||||
|
||||
status = SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL);
|
||||
if (status) {
|
||||
return get_error(status);
|
||||
}
|
||||
|
||||
*username = strdup(attr.data);
|
||||
*username_l = attr.length;
|
||||
SecKeychainItemFreeContent(&list, NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *keychain_delete(struct Server *server) {
|
||||
SecKeychainItemRef item;
|
||||
|
||||
OSStatus status = SecKeychainFindInternetPassword(
|
||||
NULL,
|
||||
strlen(server->host), server->host,
|
||||
0, NULL,
|
||||
0, NULL,
|
||||
strlen(server->path), server->path,
|
||||
server->port,
|
||||
server->proto,
|
||||
kSecAuthenticationTypeDefault,
|
||||
0, NULL,
|
||||
&item);
|
||||
|
||||
if (status) {
|
||||
return get_error(status);
|
||||
}
|
||||
|
||||
status = SecKeychainItemDelete(item);
|
||||
if (status) {
|
||||
return get_error(status);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char * CFStringToCharArr(CFStringRef aString) {
|
||||
if (aString == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
CFIndex length = CFStringGetLength(aString);
|
||||
CFIndex maxSize =
|
||||
CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
|
||||
char *buffer = (char *)malloc(maxSize);
|
||||
if (CFStringGetCString(aString, buffer, maxSize,
|
||||
kCFStringEncodingUTF8)) {
|
||||
return buffer;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *keychain_list(char *credsLabel, char *** paths, char *** accts, unsigned int *list_l) {
|
||||
CFStringRef credsLabelCF = CFStringCreateWithCString(NULL, credsLabel, kCFStringEncodingUTF8);
|
||||
CFMutableDictionaryRef query = CFDictionaryCreateMutable (NULL, 1, NULL, NULL);
|
||||
CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
|
||||
CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue);
|
||||
CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll);
|
||||
CFDictionaryAddValue(query, kSecAttrLabel, credsLabelCF);
|
||||
//Use this query dictionary
|
||||
CFTypeRef result= NULL;
|
||||
OSStatus status = SecItemCopyMatching(
|
||||
query,
|
||||
&result);
|
||||
|
||||
CFRelease(credsLabelCF);
|
||||
|
||||
//Ran a search and store the results in result
|
||||
if (status) {
|
||||
return get_error(status);
|
||||
}
|
||||
CFIndex numKeys = CFArrayGetCount(result);
|
||||
*paths = (char **) malloc((int)sizeof(char *)*numKeys);
|
||||
*accts = (char **) malloc((int)sizeof(char *)*numKeys);
|
||||
//result is of type CFArray
|
||||
for(CFIndex i=0; i<numKeys; i++) {
|
||||
CFDictionaryRef currKey = CFArrayGetValueAtIndex(result,i);
|
||||
|
||||
CFStringRef protocolTmp = CFDictionaryGetValue(currKey, CFSTR("ptcl"));
|
||||
if (protocolTmp != NULL) {
|
||||
CFStringRef protocolStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), protocolTmp);
|
||||
if (CFStringCompare(protocolStr, CFSTR("htps"), 0) == kCFCompareEqualTo) {
|
||||
protocolTmp = CFSTR("https://");
|
||||
}
|
||||
else {
|
||||
protocolTmp = CFSTR("http://");
|
||||
}
|
||||
CFRelease(protocolStr);
|
||||
}
|
||||
else {
|
||||
char * path = "0";
|
||||
char * acct = "0";
|
||||
(*paths)[i] = (char *) malloc(sizeof(char)*(strlen(path)));
|
||||
memcpy((*paths)[i], path, sizeof(char)*(strlen(path)));
|
||||
(*accts)[i] = (char *) malloc(sizeof(char)*(strlen(acct)));
|
||||
memcpy((*accts)[i], acct, sizeof(char)*(strlen(acct)));
|
||||
continue;
|
||||
}
|
||||
|
||||
CFMutableStringRef str = CFStringCreateMutableCopy(NULL, 0, protocolTmp);
|
||||
CFStringRef serverTmp = CFDictionaryGetValue(currKey, CFSTR("srvr"));
|
||||
if (serverTmp != NULL) {
|
||||
CFStringAppend(str, serverTmp);
|
||||
}
|
||||
|
||||
CFStringRef pathTmp = CFDictionaryGetValue(currKey, CFSTR("path"));
|
||||
if (pathTmp != NULL) {
|
||||
CFStringAppend(str, pathTmp);
|
||||
}
|
||||
|
||||
const NSNumber * portTmp = CFDictionaryGetValue(currKey, CFSTR("port"));
|
||||
if (portTmp != NULL && portTmp.integerValue != 0) {
|
||||
CFStringRef portStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), portTmp);
|
||||
CFStringAppend(str, CFSTR(":"));
|
||||
CFStringAppend(str, portStr);
|
||||
CFRelease(portStr);
|
||||
}
|
||||
|
||||
CFStringRef acctTmp = CFDictionaryGetValue(currKey, CFSTR("acct"));
|
||||
if (acctTmp == NULL) {
|
||||
acctTmp = CFSTR("account not defined");
|
||||
}
|
||||
|
||||
char * path = CFStringToCharArr(str);
|
||||
char * acct = CFStringToCharArr(acctTmp);
|
||||
|
||||
//We now have all we need, username and servername. Now export this to .go
|
||||
(*paths)[i] = (char *) malloc(sizeof(char)*(strlen(path)+1));
|
||||
memcpy((*paths)[i], path, sizeof(char)*(strlen(path)+1));
|
||||
(*accts)[i] = (char *) malloc(sizeof(char)*(strlen(acct)+1));
|
||||
memcpy((*accts)[i], acct, sizeof(char)*(strlen(acct)+1));
|
||||
|
||||
CFRelease(str);
|
||||
}
|
||||
*list_l = (int)numKeys;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void freeListData(char *** data, unsigned int length) {
|
||||
for(int i=0; i<length; i++) {
|
||||
free((*data)[i]);
|
||||
}
|
||||
free(*data);
|
||||
}
|
196
vendor/github.com/docker/docker-credential-helpers/osxkeychain/osxkeychain_darwin.go
generated
vendored
Normal file
196
vendor/github.com/docker/docker-credential-helpers/osxkeychain/osxkeychain_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,196 @@
|
|||
package osxkeychain
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c -mmacosx-version-min=10.10
|
||||
#cgo LDFLAGS: -framework Security -framework Foundation -mmacosx-version-min=10.10
|
||||
|
||||
#include "osxkeychain_darwin.h"
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/docker/docker-credential-helpers/credentials"
|
||||
)
|
||||
|
||||
// errCredentialsNotFound is the specific error message returned by OS X
|
||||
// when the credentials are not in the keychain.
|
||||
const errCredentialsNotFound = "The specified item could not be found in the keychain."
|
||||
|
||||
// Osxkeychain handles secrets using the OS X Keychain as store.
|
||||
type Osxkeychain struct{}
|
||||
|
||||
// Add adds new credentials to the keychain.
|
||||
func (h Osxkeychain) Add(creds *credentials.Credentials) error {
|
||||
h.Delete(creds.ServerURL)
|
||||
|
||||
s, err := splitServer(creds.ServerURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer freeServer(s)
|
||||
|
||||
label := C.CString(credentials.CredsLabel)
|
||||
defer C.free(unsafe.Pointer(label))
|
||||
username := C.CString(creds.Username)
|
||||
defer C.free(unsafe.Pointer(username))
|
||||
secret := C.CString(creds.Secret)
|
||||
defer C.free(unsafe.Pointer(secret))
|
||||
|
||||
errMsg := C.keychain_add(s, label, username, secret)
|
||||
if errMsg != nil {
|
||||
defer C.free(unsafe.Pointer(errMsg))
|
||||
return errors.New(C.GoString(errMsg))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes credentials from the keychain.
|
||||
func (h Osxkeychain) Delete(serverURL string) error {
|
||||
s, err := splitServer(serverURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer freeServer(s)
|
||||
|
||||
errMsg := C.keychain_delete(s)
|
||||
if errMsg != nil {
|
||||
defer C.free(unsafe.Pointer(errMsg))
|
||||
return errors.New(C.GoString(errMsg))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the username and secret to use for a given registry server URL.
|
||||
func (h Osxkeychain) Get(serverURL string) (string, string, error) {
|
||||
s, err := splitServer(serverURL)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer freeServer(s)
|
||||
|
||||
var usernameLen C.uint
|
||||
var username *C.char
|
||||
var secretLen C.uint
|
||||
var secret *C.char
|
||||
defer C.free(unsafe.Pointer(username))
|
||||
defer C.free(unsafe.Pointer(secret))
|
||||
|
||||
errMsg := C.keychain_get(s, &usernameLen, &username, &secretLen, &secret)
|
||||
if errMsg != nil {
|
||||
defer C.free(unsafe.Pointer(errMsg))
|
||||
goMsg := C.GoString(errMsg)
|
||||
if goMsg == errCredentialsNotFound {
|
||||
return "", "", credentials.NewErrCredentialsNotFound()
|
||||
}
|
||||
|
||||
return "", "", errors.New(goMsg)
|
||||
}
|
||||
|
||||
user := C.GoStringN(username, C.int(usernameLen))
|
||||
pass := C.GoStringN(secret, C.int(secretLen))
|
||||
return user, pass, nil
|
||||
}
|
||||
|
||||
// List returns the stored URLs and corresponding usernames.
|
||||
func (h Osxkeychain) List() (map[string]string, error) {
|
||||
credsLabelC := C.CString(credentials.CredsLabel)
|
||||
defer C.free(unsafe.Pointer(credsLabelC))
|
||||
|
||||
var pathsC **C.char
|
||||
defer C.free(unsafe.Pointer(pathsC))
|
||||
var acctsC **C.char
|
||||
defer C.free(unsafe.Pointer(acctsC))
|
||||
var listLenC C.uint
|
||||
errMsg := C.keychain_list(credsLabelC, &pathsC, &acctsC, &listLenC)
|
||||
if errMsg != nil {
|
||||
defer C.free(unsafe.Pointer(errMsg))
|
||||
goMsg := C.GoString(errMsg)
|
||||
return nil, errors.New(goMsg)
|
||||
}
|
||||
|
||||
defer C.freeListData(&pathsC, listLenC)
|
||||
defer C.freeListData(&acctsC, listLenC)
|
||||
|
||||
var listLen int
|
||||
listLen = int(listLenC)
|
||||
pathTmp := (*[1 << 30]*C.char)(unsafe.Pointer(pathsC))[:listLen:listLen]
|
||||
acctTmp := (*[1 << 30]*C.char)(unsafe.Pointer(acctsC))[:listLen:listLen]
|
||||
//taking the array of c strings into go while ignoring all the stuff irrelevant to credentials-helper
|
||||
resp := make(map[string]string)
|
||||
for i := 0; i < listLen; i++ {
|
||||
if C.GoString(pathTmp[i]) == "0" {
|
||||
continue
|
||||
}
|
||||
resp[C.GoString(pathTmp[i])] = C.GoString(acctTmp[i])
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func splitServer(serverURL string) (*C.struct_Server, error) {
|
||||
u, err := parseURL(serverURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proto := C.kSecProtocolTypeHTTPS
|
||||
if u.Scheme == "http" {
|
||||
proto = C.kSecProtocolTypeHTTP
|
||||
}
|
||||
var port int
|
||||
p := getPort(u)
|
||||
if p != "" {
|
||||
port, err = strconv.Atoi(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &C.struct_Server{
|
||||
proto: C.SecProtocolType(proto),
|
||||
host: C.CString(getHostname(u)),
|
||||
port: C.uint(port),
|
||||
path: C.CString(u.Path),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func freeServer(s *C.struct_Server) {
|
||||
C.free(unsafe.Pointer(s.host))
|
||||
C.free(unsafe.Pointer(s.path))
|
||||
}
|
||||
|
||||
// parseURL parses and validates a given serverURL to an url.URL, and
|
||||
// returns an error if validation failed. Querystring parameters are
|
||||
// omitted in the resulting URL, because they are not used in the helper.
|
||||
//
|
||||
// If serverURL does not have a valid scheme, `//` is used as scheme
|
||||
// before parsing. This prevents the hostname being used as path,
|
||||
// and the credentials being stored without host.
|
||||
func parseURL(serverURL string) (*url.URL, error) {
|
||||
// Check if serverURL has a scheme, otherwise add `//` as scheme.
|
||||
if !strings.Contains(serverURL, "://") && !strings.HasPrefix(serverURL, "//") {
|
||||
serverURL = "//" + serverURL
|
||||
}
|
||||
|
||||
u, err := url.Parse(serverURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if u.Scheme != "" && u.Scheme != "https" && u.Scheme != "http" {
|
||||
return nil, errors.New("unsupported scheme: " + u.Scheme)
|
||||
}
|
||||
if getHostname(u) == "" {
|
||||
return nil, errors.New("no hostname in URL")
|
||||
}
|
||||
|
||||
u.RawQuery = ""
|
||||
return u, nil
|
||||
}
|
14
vendor/github.com/docker/docker-credential-helpers/osxkeychain/osxkeychain_darwin.h
generated
vendored
Normal file
14
vendor/github.com/docker/docker-credential-helpers/osxkeychain/osxkeychain_darwin.h
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <Security/Security.h>
|
||||
|
||||
struct Server {
|
||||
SecProtocolType proto;
|
||||
char *host;
|
||||
char *path;
|
||||
unsigned int port;
|
||||
};
|
||||
|
||||
char *keychain_add(struct Server *server, char *label, char *username, char *secret);
|
||||
char *keychain_get(struct Server *server, unsigned int *username_l, char **username, unsigned int *secret_l, char **secret);
|
||||
char *keychain_delete(struct Server *server);
|
||||
char *keychain_list(char *credsLabel, char *** data, char *** accts, unsigned int *list_l);
|
||||
void freeListData(char *** data, unsigned int length);
|
13
vendor/github.com/docker/docker-credential-helpers/osxkeychain/url_go18.go
generated
vendored
Normal file
13
vendor/github.com/docker/docker-credential-helpers/osxkeychain/url_go18.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
//+build go1.8
|
||||
|
||||
package osxkeychain
|
||||
|
||||
import "net/url"
|
||||
|
||||
func getHostname(u *url.URL) string {
|
||||
return u.Hostname()
|
||||
}
|
||||
|
||||
func getPort(u *url.URL) string {
|
||||
return u.Port()
|
||||
}
|
41
vendor/github.com/docker/docker-credential-helpers/osxkeychain/url_non_go18.go
generated
vendored
Normal file
41
vendor/github.com/docker/docker-credential-helpers/osxkeychain/url_non_go18.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
//+build !go1.8
|
||||
|
||||
package osxkeychain
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getHostname(u *url.URL) string {
|
||||
return stripPort(u.Host)
|
||||
}
|
||||
|
||||
func getPort(u *url.URL) string {
|
||||
return portOnly(u.Host)
|
||||
}
|
||||
|
||||
func stripPort(hostport string) string {
|
||||
colon := strings.IndexByte(hostport, ':')
|
||||
if colon == -1 {
|
||||
return hostport
|
||||
}
|
||||
if i := strings.IndexByte(hostport, ']'); i != -1 {
|
||||
return strings.TrimPrefix(hostport[:i], "[")
|
||||
}
|
||||
return hostport[:colon]
|
||||
}
|
||||
|
||||
func portOnly(hostport string) string {
|
||||
colon := strings.IndexByte(hostport, ':')
|
||||
if colon == -1 {
|
||||
return ""
|
||||
}
|
||||
if i := strings.Index(hostport, "]:"); i != -1 {
|
||||
return hostport[i+len("]:"):]
|
||||
}
|
||||
if strings.Contains(hostport, "]") {
|
||||
return ""
|
||||
}
|
||||
return hostport[colon+len(":"):]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue