Vendor in latest containers/image

Adds support for credential helpers

Signed-off-by: umohnani8 <umohnani@redhat.com>
This commit is contained in:
umohnani8 2017-09-05 12:19:42 -04:00
parent 8538c4067a
commit e9467dc540
24 changed files with 1405 additions and 10 deletions

View file

@ -0,0 +1,162 @@
#include <string.h>
#include <stdlib.h>
#include "secretservice_linux.h"
const SecretSchema *docker_get_schema(void)
{
static const SecretSchema docker_schema = {
"io.docker.Credentials", SECRET_SCHEMA_NONE,
{
{ "label", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ "server", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ "username", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ "docker_cli", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ "NULL", 0 },
}
};
return &docker_schema;
}
GError *add(char *label, char *server, char *username, char *secret) {
GError *err = NULL;
secret_password_store_sync (DOCKER_SCHEMA, SECRET_COLLECTION_DEFAULT,
server, secret, NULL, &err,
"label", label,
"server", server,
"username", username,
"docker_cli", "1",
NULL);
return err;
}
GError *delete(char *server) {
GError *err = NULL;
secret_password_clear_sync(DOCKER_SCHEMA, NULL, &err,
"server", server,
"docker_cli", "1",
NULL);
if (err != NULL)
return err;
return NULL;
}
char *get_attribute(const char *attribute, SecretItem *item) {
GHashTable *attributes;
GHashTableIter iter;
gchar *value, *key;
attributes = secret_item_get_attributes(item);
g_hash_table_iter_init(&iter, attributes);
while (g_hash_table_iter_next(&iter, (void **)&key, (void **)&value)) {
if (strncmp(key, attribute, strlen(key)) == 0)
return (char *)value;
}
g_hash_table_unref(attributes);
return NULL;
}
GError *get(char *server, char **username, char **secret) {
GError *err = NULL;
GHashTable *attributes;
SecretService *service;
GList *items, *l;
SecretSearchFlags flags = SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK;
SecretValue *secretValue;
gsize length;
gchar *value;
attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
g_hash_table_insert(attributes, g_strdup("server"), g_strdup(server));
g_hash_table_insert(attributes, g_strdup("docker_cli"), g_strdup("1"));
service = secret_service_get_sync(SECRET_SERVICE_NONE, NULL, &err);
if (err == NULL) {
items = secret_service_search_sync(service, DOCKER_SCHEMA, attributes, flags, NULL, &err);
if (err == NULL) {
for (l = items; l != NULL; l = g_list_next(l)) {
value = secret_item_get_schema_name(l->data);
if (strncmp(value, "io.docker.Credentials", strlen(value)) != 0) {
g_free(value);
continue;
}
g_free(value);
secretValue = secret_item_get_secret(l->data);
if (secret != NULL) {
*secret = strdup(secret_value_get(secretValue, &length));
secret_value_unref(secretValue);
}
*username = get_attribute("username", l->data);
}
g_list_free_full(items, g_object_unref);
}
g_object_unref(service);
}
g_hash_table_unref(attributes);
if (err != NULL) {
return err;
}
return NULL;
}
GError *list(char *ref_label, char *** paths, char *** accts, unsigned int *list_l) {
GList *items;
GError *err = NULL;
SecretService *service;
SecretSearchFlags flags = SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK;
GHashTable *attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
// List credentials with the right label only
g_hash_table_insert(attributes, g_strdup("label"), g_strdup(ref_label));
service = secret_service_get_sync(SECRET_SERVICE_NONE, NULL, &err);
if (err != NULL) {
return err;
}
items = secret_service_search_sync(service, NULL, attributes, flags, NULL, &err);
int numKeys = g_list_length(items);
if (err != NULL) {
return err;
}
char **tmp_paths = (char **) calloc(1,(int)sizeof(char *)*numKeys);
char **tmp_accts = (char **) calloc(1,(int)sizeof(char *)*numKeys);
// items now contains our keys from the gnome keyring
// we will now put it in our two lists to return it to go
GList *current;
int listNumber = 0;
for(current = items; current!=NULL; current = current->next) {
char *pathTmp = secret_item_get_label(current->data);
// you cannot have a key without a label in the gnome keyring
char *acctTmp = get_attribute("username",current->data);
if (acctTmp==NULL) {
acctTmp = "account not defined";
}
tmp_paths[listNumber] = (char *) calloc(1, sizeof(char)*(strlen(pathTmp)+1));
tmp_accts[listNumber] = (char *) calloc(1, sizeof(char)*(strlen(acctTmp)+1));
memcpy(tmp_paths[listNumber], pathTmp, sizeof(char)*(strlen(pathTmp)+1));
memcpy(tmp_accts[listNumber], acctTmp, sizeof(char)*(strlen(acctTmp)+1));
listNumber = listNumber + 1;
}
*paths = (char **) realloc(tmp_paths, (int)sizeof(char *)*listNumber);
*accts = (char **) realloc(tmp_accts, (int)sizeof(char *)*listNumber);
*list_l = listNumber;
return NULL;
}
void freeListData(char *** data, unsigned int length) {
int i;
for(i=0; i<length; i++) {
free((*data)[i]);
}
free(*data);
}

View file

@ -0,0 +1,118 @@
package secretservice
/*
#cgo pkg-config: libsecret-1
#include "secretservice_linux.h"
#include <stdlib.h>
*/
import "C"
import (
"errors"
"unsafe"
"github.com/docker/docker-credential-helpers/credentials"
)
// Secretservice handles secrets using Linux secret-service as a store.
type Secretservice struct{}
// Add adds new credentials to the keychain.
func (h Secretservice) Add(creds *credentials.Credentials) error {
if creds == nil {
return errors.New("missing credentials")
}
credsLabel := C.CString(credentials.CredsLabel)
defer C.free(unsafe.Pointer(credsLabel))
server := C.CString(creds.ServerURL)
defer C.free(unsafe.Pointer(server))
username := C.CString(creds.Username)
defer C.free(unsafe.Pointer(username))
secret := C.CString(creds.Secret)
defer C.free(unsafe.Pointer(secret))
if err := C.add(credsLabel, server, username, secret); err != nil {
defer C.g_error_free(err)
errMsg := (*C.char)(unsafe.Pointer(err.message))
return errors.New(C.GoString(errMsg))
}
return nil
}
// Delete removes credentials from the store.
func (h Secretservice) Delete(serverURL string) error {
if serverURL == "" {
return errors.New("missing server url")
}
server := C.CString(serverURL)
defer C.free(unsafe.Pointer(server))
if err := C.delete(server); err != nil {
defer C.g_error_free(err)
errMsg := (*C.char)(unsafe.Pointer(err.message))
return errors.New(C.GoString(errMsg))
}
return nil
}
// Get returns the username and secret to use for a given registry server URL.
func (h Secretservice) Get(serverURL string) (string, string, error) {
if serverURL == "" {
return "", "", errors.New("missing server url")
}
var username *C.char
defer C.free(unsafe.Pointer(username))
var secret *C.char
defer C.free(unsafe.Pointer(secret))
server := C.CString(serverURL)
defer C.free(unsafe.Pointer(server))
err := C.get(server, &username, &secret)
if err != nil {
defer C.g_error_free(err)
errMsg := (*C.char)(unsafe.Pointer(err.message))
return "", "", errors.New(C.GoString(errMsg))
}
user := C.GoString(username)
pass := C.GoString(secret)
if pass == "" {
return "", "", credentials.NewErrCredentialsNotFound()
}
return user, pass, nil
}
// List returns the stored URLs and corresponding usernames for a given credentials label
func (h Secretservice) 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
err := C.list(credsLabelC, &pathsC, &acctsC, &listLenC)
if err != nil {
defer C.free(unsafe.Pointer(err))
return nil, errors.New("Error from list function in secretservice_linux.c likely due to error in secretservice library")
}
defer C.freeListData(&pathsC, listLenC)
defer C.freeListData(&acctsC, listLenC)
resp := make(map[string]string)
listLen := int(listLenC)
if listLen == 0 {
return resp, nil
}
// The maximum capacity of the following two slices is limited to (2^29)-1 to remain compatible
// with 32-bit platforms. The size of a `*C.char` (a pointer) is 4 Byte on a 32-bit system
// and (2^29)*4 == math.MaxInt32 + 1. -- See issue golang/go#13656
pathTmp := (*[(1 << 29) - 1]*C.char)(unsafe.Pointer(pathsC))[:listLen:listLen]
acctTmp := (*[(1 << 29) - 1]*C.char)(unsafe.Pointer(acctsC))[:listLen:listLen]
for i := 0; i < listLen; i++ {
resp[C.GoString(pathTmp[i])] = C.GoString(acctTmp[i])
}
return resp, nil
}

View file

@ -0,0 +1,13 @@
#define SECRET_WITH_UNSTABLE 1
#define SECRET_API_SUBJECT_TO_CHANGE 1
#include <libsecret/secret.h>
const SecretSchema *docker_get_schema(void) G_GNUC_CONST;
#define DOCKER_SCHEMA docker_get_schema()
GError *add(char *label, char *server, char *username, char *secret);
GError *delete(char *server);
GError *get(char *server, char **username, char **secret);
GError *list(char *label, char *** paths, char *** accts, unsigned int *list_l);
void freeListData(char *** data, unsigned int length);