From 595b7f25314f3e6c73085ff31abd753cfe65224a Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Wed, 8 Mar 2017 17:07:40 +0100 Subject: [PATCH 01/14] Add a Docker Credentials label to store and list creds Signed-off-by: Nassim 'Nass' Eddequiouaq --- credentials/credentials.go | 9 ++++++++- credentials/credentials_test.go | 2 +- credentials/helper.go | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/credentials/credentials.go b/credentials/credentials.go index 3c4eec7..e25103e 100644 --- a/credentials/credentials.go +++ b/credentials/credentials.go @@ -12,11 +12,16 @@ import ( // Credentials holds the information shared between docker and the credentials store. type Credentials struct { + Label string ServerURL string Username string Secret string } +// Docker credentials should be labeled as such in credential stores, this label +// allow us to filter out non-Docker credentials at lookup +const CredsLabel = "Docker Credentials" + // Serve initializes the credentials helper and parses the action argument. // This function is designed to be called from a command line interface. // It uses os.Args[1] as the key for the action. @@ -72,6 +77,8 @@ func Store(helper Helper, reader io.Reader) error { return err } + creds.Label = CredsLabel + return helper.Add(&creds) } @@ -133,7 +140,7 @@ func Erase(helper Helper, reader io.Reader) error { //List returns all the serverURLs of keys in //the OS store as a list of strings func List(helper Helper, writer io.Writer) error { - accts, err := helper.List() + accts, err := helper.List(CredsLabel) if err != nil { return err } diff --git a/credentials/credentials_test.go b/credentials/credentials_test.go index 6b8bbe1..3c2ca52 100644 --- a/credentials/credentials_test.go +++ b/credentials/credentials_test.go @@ -36,7 +36,7 @@ func (m *memoryStore) Get(serverURL string) (string, string, error) { return c.Username, c.Secret, nil } -func (m *memoryStore) List() (map[string]string, error) { +func (m *memoryStore) List(credsLabel string) (map[string]string, error) { //Simply a placeholder to let memoryStore be a valid implementation of Helper interface return nil, nil } diff --git a/credentials/helper.go b/credentials/helper.go index 135acd2..fad53ee 100644 --- a/credentials/helper.go +++ b/credentials/helper.go @@ -9,6 +9,7 @@ type Helper interface { // Get retrieves credentials from the store. // It returns username and secret as strings. Get(serverURL string) (string, string, error) - // List returns the stored serverURLs and their associated usernames. - List() (map[string]string, error) + // List returns the stored serverURLs and their associated usernames + // for a given credentials label. + List(credsLabel string) (map[string]string, error) } From 406812bf8e8e96495414e2ddd4e6d79b54e16c08 Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Wed, 8 Mar 2017 17:08:22 +0100 Subject: [PATCH 02/14] Add a Docker Credentials label support for macOS Signed-off-by: Nassim 'Nass' Eddequiouaq --- osxkeychain/osxkeychain_darwin.c | 25 ++++++++++++++++++++++--- osxkeychain/osxkeychain_darwin.go | 11 ++++++++--- osxkeychain/osxkeychain_darwin.h | 2 +- osxkeychain/osxkeychain_darwin_test.go | 4 ++-- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/osxkeychain/osxkeychain_darwin.c b/osxkeychain/osxkeychain_darwin.c index 371222e..5b420d0 100644 --- a/osxkeychain/osxkeychain_darwin.c +++ b/osxkeychain/osxkeychain_darwin.c @@ -14,7 +14,9 @@ char *get_error(OSStatus status) { return buf; } -char *keychain_add(struct Server *server, char *username, char *secret) { +char *keychain_add(struct Server *server, char *label, char *username, char *secret) { + SecKeychainItemRef item; + OSStatus status = SecKeychainAddInternetPassword( NULL, strlen(server->host), server->host, @@ -25,11 +27,27 @@ char *keychain_add(struct Server *server, char *username, char *secret) { server->proto, kSecAuthenticationTypeDefault, strlen(secret), secret, - NULL + &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; } @@ -116,11 +134,12 @@ char * CFStringToCharArr(CFStringRef aString) { return NULL; } -char *keychain_list(char *** paths, char *** accts, unsigned int *list_l) { +char *keychain_list(char *credsLabel, char *** paths, char *** accts, unsigned int *list_l) { CFMutableDictionaryRef query = CFDictionaryCreateMutable (NULL, 1, NULL, NULL); CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue); CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll); + CFDictionaryAddValue(query, kSecAttrLabel, CFSTR(credsLabel)); //Use this query dictionary CFTypeRef result= NULL; OSStatus status = SecItemCopyMatching( diff --git a/osxkeychain/osxkeychain_darwin.go b/osxkeychain/osxkeychain_darwin.go index 21761aa..137b894 100644 --- a/osxkeychain/osxkeychain_darwin.go +++ b/osxkeychain/osxkeychain_darwin.go @@ -35,12 +35,14 @@ func (h Osxkeychain) Add(creds *credentials.Credentials) error { } defer freeServer(s) + label := C.CString(creds.Label) + 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, username, secret) + errMsg := C.keychain_add(s, label, username, secret) if errMsg != nil { defer C.free(unsafe.Pointer(errMsg)) return errors.New(C.GoString(errMsg)) @@ -98,13 +100,16 @@ func (h Osxkeychain) Get(serverURL string) (string, string, error) { } // List returns the stored URLs and corresponding usernames. -func (h Osxkeychain) List() (map[string]string, error) { +func (h Osxkeychain) List(credsLabel string) (map[string]string, error) { + credsLabelC := C.CString(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(&pathsC, &acctsC, &listLenC) + errMsg := C.keychain_list(credsLabelC, &pathsC, &acctsC, &listLenC) if errMsg != nil { defer C.free(unsafe.Pointer(errMsg)) goMsg := C.GoString(errMsg) diff --git a/osxkeychain/osxkeychain_darwin.h b/osxkeychain/osxkeychain_darwin.h index 6b01e97..a368046 100644 --- a/osxkeychain/osxkeychain_darwin.h +++ b/osxkeychain/osxkeychain_darwin.h @@ -7,7 +7,7 @@ struct Server { unsigned int port; }; -char *keychain_add(struct Server *server, char *username, char *secret); +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 *** data, char *** accts, unsigned int *list_l); diff --git a/osxkeychain/osxkeychain_darwin_test.go b/osxkeychain/osxkeychain_darwin_test.go index 406fe9b..700f153 100644 --- a/osxkeychain/osxkeychain_darwin_test.go +++ b/osxkeychain/osxkeychain_darwin_test.go @@ -34,14 +34,14 @@ func TestOSXKeychainHelper(t *testing.T) { t.Fatalf("expected %s, got %s\n", "foobarbaz", secret) } - auths, err := helper.List() + auths, err := helper.List(credentials.CredsLabel) if err != nil || len(auths) == 0 { t.Fatal(err) } helper.Add(creds1) defer helper.Delete(creds1.ServerURL) - newauths, err := helper.List() + newauths, err := helper.List(credentials.CredsLabel) if len(newauths)-len(auths) != 1 { if err == nil { t.Fatalf("Error: len(newauths): %d, len(auths): %d", len(newauths), len(auths)) From f7f2744e6d110d8598dd72a7d06475e74cd59b1d Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Wed, 8 Mar 2017 17:08:43 +0100 Subject: [PATCH 03/14] Add a Docker Credentials label support for linux Signed-off-by: Nassim 'Nass' Eddequiouaq --- secretservice/secretservice_linux.c | 13 ++++++++----- secretservice/secretservice_linux.go | 13 +++++++++---- secretservice/secretservice_linux.h | 4 ++-- secretservice/secretservice_linux_test.go | 5 +++-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/secretservice/secretservice_linux.c b/secretservice/secretservice_linux.c index ab23a5e..17e67bc 100644 --- a/secretservice/secretservice_linux.c +++ b/secretservice/secretservice_linux.c @@ -7,6 +7,7 @@ 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 }, @@ -16,11 +17,12 @@ const SecretSchema *docker_get_schema(void) return &docker_schema; } -GError *add(char *server, char *username, char *secret) { +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", @@ -98,14 +100,15 @@ GError *get(char *server, char **username, char **secret) { return NULL; } -GError *list(char *** paths, char *** accts, unsigned int *list_l) { +GError *list(char *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); - attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + GHashTable *attributes = secret_attributes_build(NULL, + "label", label, + NULL); + service = secret_service_get_sync(SECRET_SERVICE_NONE, NULL, &err); items = secret_service_search_sync(service, NULL, attributes, flags, NULL, &err); int numKeys = g_list_length(items); diff --git a/secretservice/secretservice_linux.go b/secretservice/secretservice_linux.go index f3264ce..26760bf 100644 --- a/secretservice/secretservice_linux.go +++ b/secretservice/secretservice_linux.go @@ -22,6 +22,8 @@ func (h Secretservice) Add(creds *credentials.Credentials) error { if creds == nil { return errors.New("missing credentials") } + credsLabel := C.CString(creds.Label) + defer C.free(unsafe.Pointer(credsLabel)) server := C.CString(creds.ServerURL) defer C.free(unsafe.Pointer(server)) username := C.CString(creds.Username) @@ -29,7 +31,7 @@ func (h Secretservice) Add(creds *credentials.Credentials) error { secret := C.CString(creds.Secret) defer C.free(unsafe.Pointer(secret)) - if err := C.add(server, username, secret); err != nil { + 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)) @@ -79,14 +81,17 @@ func (h Secretservice) Get(serverURL string) (string, string, error) { return user, pass, nil } -// List returns the stored URLs and corresponding usernames. -func (h Secretservice) List() (map[string]string, error) { +// List returns the stored URLs and corresponding usernames for a given credentials label +func (h Secretservice) List(credsLabel string) (map[string]string, error) { + credsLabelC := C.CString(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(&pathsC, &acctsC, &listLenC) + 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") diff --git a/secretservice/secretservice_linux.h b/secretservice/secretservice_linux.h index 319cdc0..a28179d 100644 --- a/secretservice/secretservice_linux.h +++ b/secretservice/secretservice_linux.h @@ -6,8 +6,8 @@ const SecretSchema *docker_get_schema(void) G_GNUC_CONST; #define DOCKER_SCHEMA docker_get_schema() -GError *add(char *server, char *username, char *secret); +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 *** paths, char *** accts, unsigned int *list_l); +GError *list(char *label, char *** paths, char *** accts, unsigned int *list_l); void freeListData(char *** data, unsigned int length); diff --git a/secretservice/secretservice_linux_test.go b/secretservice/secretservice_linux_test.go index bd0caf3..daa11b1 100644 --- a/secretservice/secretservice_linux_test.go +++ b/secretservice/secretservice_linux_test.go @@ -13,6 +13,7 @@ func TestSecretServiceHelper(t *testing.T) { ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", + Label: credentials.CredsLabel, } helper := Secretservice{} @@ -36,12 +37,12 @@ func TestSecretServiceHelper(t *testing.T) { if err := helper.Delete(creds.ServerURL); err != nil { t.Fatal(err) } - auths, err := helper.List() + auths, err := helper.List(credentials.CredsLabel) if err != nil || len(auths) == 0 { t.Fatal(err) } helper.Add(creds) - if newauths, err := helper.List(); (len(newauths) - len(auths)) != 1 { + if newauths, err := helper.List(credentials.CredsLabel); (len(newauths) - len(auths)) != 1 { t.Fatal(err) } } From 23a1f310a55128aa5be81fb59057040f158198a7 Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Wed, 8 Mar 2017 18:07:14 +0100 Subject: [PATCH 04/14] Add a Docker Credentials label support for windows Signed-off-by: Nassim 'Nass' Eddequiouaq --- wincred/wincred_windows.go | 19 ++++++++++++++++--- wincred/wincred_windows_test.go | 6 ++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/wincred/wincred_windows.go b/wincred/wincred_windows.go index 294c939..584440b 100644 --- a/wincred/wincred_windows.go +++ b/wincred/wincred_windows.go @@ -3,6 +3,8 @@ package wincred import ( winc "github.com/danieljoos/wincred" "github.com/docker/docker-credential-helpers/credentials" + "bytes" + "strings" ) // Wincred handles secrets using the Windows credential service. @@ -14,6 +16,8 @@ func (h Wincred) Add(creds *credentials.Credentials) error { g.UserName = creds.Username g.CredentialBlob = []byte(creds.Secret) g.Persist = winc.PersistLocalMachine + g.Attributes = []winc.CredentialAttribute{winc.CredentialAttribute{"label", []byte(creds.Label)}} + return g.Write() } @@ -38,8 +42,8 @@ func (h Wincred) Get(serverURL string) (string, string, error) { return g.UserName, string(g.CredentialBlob), nil } -// List returns the stored URLs and corresponding usernames. -func (h Wincred) List() (map[string]string, error) { +// List returns the stored URLs and corresponding usernames for a given credentials label. +func (h Wincred) List(credsLabel string) (map[string]string, error) { creds, err := winc.List() if err != nil { return nil, err @@ -47,7 +51,16 @@ func (h Wincred) List() (map[string]string, error) { resp := make(map[string]string) for i := range creds { - resp[creds[i].TargetName] = creds[i].UserName + attrs = creds[i].Attributes + for _, attr := range attrs { + if !strings.Compare(attr.Keyword, "label") && + !bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) { + + resp[creds[i].TargetName] = creds[i].UserName + } + } + } + return resp, nil } diff --git a/wincred/wincred_windows_test.go b/wincred/wincred_windows_test.go index 01f6e59..17eb243 100644 --- a/wincred/wincred_windows_test.go +++ b/wincred/wincred_windows_test.go @@ -8,11 +8,13 @@ import ( func TestWinCredHelper(t *testing.T) { creds := &credentials.Credentials{ + Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", } creds1 := &credentials.Credentials{ + Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v2", Username: "foobarbaz", Secret: "foobar", @@ -36,14 +38,14 @@ func TestWinCredHelper(t *testing.T) { t.Fatalf("expected %s, got %s\n", "foobarbaz", secret) } - auths, err := helper.List() + auths, err := helper.List(credentials.CredsLabel) if err != nil || len(auths) == 0 { t.Fatal(err) } helper.Add(creds1) defer helper.Delete(creds1.ServerURL) - newauths, err := helper.List() + newauths, err := helper.List(credentials.CredsLabel) if err != nil { t.Fatal(err) } From cfe7556d6d28ed0b1b3e4a92176fb081882cd0d4 Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Wed, 8 Mar 2017 18:08:33 +0100 Subject: [PATCH 05/14] [SYNTAX] Run gofmt on changed files Signed-off-by: Nassim 'Nass' Eddequiouaq --- credentials/credentials.go | 4 ++-- secretservice/secretservice_linux_test.go | 2 +- wincred/wincred_windows.go | 4 ++-- wincred/wincred_windows_test.go | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/credentials/credentials.go b/credentials/credentials.go index e25103e..539a5a4 100644 --- a/credentials/credentials.go +++ b/credentials/credentials.go @@ -12,7 +12,7 @@ import ( // Credentials holds the information shared between docker and the credentials store. type Credentials struct { - Label string + Label string ServerURL string Username string Secret string @@ -20,7 +20,7 @@ type Credentials struct { // Docker credentials should be labeled as such in credential stores, this label // allow us to filter out non-Docker credentials at lookup -const CredsLabel = "Docker Credentials" +const CredsLabel = "Docker Credentials" // Serve initializes the credentials helper and parses the action argument. // This function is designed to be called from a command line interface. diff --git a/secretservice/secretservice_linux_test.go b/secretservice/secretservice_linux_test.go index daa11b1..f5ba9df 100644 --- a/secretservice/secretservice_linux_test.go +++ b/secretservice/secretservice_linux_test.go @@ -13,7 +13,7 @@ func TestSecretServiceHelper(t *testing.T) { ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", - Label: credentials.CredsLabel, + Label: credentials.CredsLabel, } helper := Secretservice{} diff --git a/wincred/wincred_windows.go b/wincred/wincred_windows.go index 584440b..ce42d91 100644 --- a/wincred/wincred_windows.go +++ b/wincred/wincred_windows.go @@ -1,9 +1,9 @@ package wincred import ( + "bytes" winc "github.com/danieljoos/wincred" "github.com/docker/docker-credential-helpers/credentials" - "bytes" "strings" ) @@ -16,7 +16,7 @@ func (h Wincred) Add(creds *credentials.Credentials) error { g.UserName = creds.Username g.CredentialBlob = []byte(creds.Secret) g.Persist = winc.PersistLocalMachine - g.Attributes = []winc.CredentialAttribute{winc.CredentialAttribute{"label", []byte(creds.Label)}} + g.Attributes = []winc.CredentialAttribute{{"label", []byte(creds.Label)}} return g.Write() } diff --git a/wincred/wincred_windows_test.go b/wincred/wincred_windows_test.go index 17eb243..0c115e9 100644 --- a/wincred/wincred_windows_test.go +++ b/wincred/wincred_windows_test.go @@ -8,13 +8,13 @@ import ( func TestWinCredHelper(t *testing.T) { creds := &credentials.Credentials{ - Label: credentials.CredsLabel, + Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", } creds1 := &credentials.Credentials{ - Label: credentials.CredsLabel, + Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v2", Username: "foobarbaz", Secret: "foobar", From c6cf8aa13b96ad1e4f28c33e5d5e6678a58778a6 Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Wed, 8 Mar 2017 18:48:54 +0100 Subject: [PATCH 06/14] Add Label to Credentials in test files Signed-off-by: Nassim 'Nass' Eddequiouaq --- client/client_test.go | 10 +++++----- osxkeychain/osxkeychain_darwin.h | 2 +- osxkeychain/osxkeychain_darwin_test.go | 2 ++ secretservice/secretservice_linux_test.go | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/client/client_test.go b/client/client_test.go index e5f1bf2..c1665c4 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -106,8 +106,8 @@ func ExampleStore() { func TestStore(t *testing.T) { valid := []credentials.Credentials{ - {validServerAddress, "foo", "bar"}, - {validServerAddress2, "", "abcd1234"}, + {credentials.CredsLabel, validServerAddress, "foo", "bar"}, + {credentials.CredsLabel, validServerAddress2, "", "abcd1234"}, } for _, v := range valid { @@ -117,7 +117,7 @@ func TestStore(t *testing.T) { } invalid := []credentials.Credentials{ - {invalidServerAddress, "foo", "bar"}, + {credentials.CredsLabel, invalidServerAddress, "foo", "bar"}, } for _, v := range invalid { @@ -140,8 +140,8 @@ func ExampleGet() { func TestGet(t *testing.T) { valid := []credentials.Credentials{ - {validServerAddress, "foo", "bar"}, - {validServerAddress2, "", "abcd1234"}, + {credentials.CredsLabel, validServerAddress, "foo", "bar"}, + {credentials.CredsLabel, validServerAddress2, "", "abcd1234"}, } for _, v := range valid { diff --git a/osxkeychain/osxkeychain_darwin.h b/osxkeychain/osxkeychain_darwin.h index a368046..c54e7d7 100644 --- a/osxkeychain/osxkeychain_darwin.h +++ b/osxkeychain/osxkeychain_darwin.h @@ -10,5 +10,5 @@ struct Server { 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 *** data, char *** accts, unsigned int *list_l); +char *keychain_list(char *credsLabel, char *** data, char *** accts, unsigned int *list_l); void freeListData(char *** data, unsigned int length); \ No newline at end of file diff --git a/osxkeychain/osxkeychain_darwin_test.go b/osxkeychain/osxkeychain_darwin_test.go index 700f153..bbfe1ff 100644 --- a/osxkeychain/osxkeychain_darwin_test.go +++ b/osxkeychain/osxkeychain_darwin_test.go @@ -7,11 +7,13 @@ import ( func TestOSXKeychainHelper(t *testing.T) { creds := &credentials.Credentials{ + Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", } creds1 := &credentials.Credentials{ + Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v2", Username: "foobarbaz", Secret: "foobar", diff --git a/secretservice/secretservice_linux_test.go b/secretservice/secretservice_linux_test.go index f5ba9df..057efca 100644 --- a/secretservice/secretservice_linux_test.go +++ b/secretservice/secretservice_linux_test.go @@ -10,10 +10,10 @@ func TestSecretServiceHelper(t *testing.T) { t.Skip("test requires gnome-keyring but travis CI doesn't have it") creds := &credentials.Credentials{ + Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", - Label: credentials.CredsLabel, } helper := Secretservice{} From c5fbd3a5ad14f14a9726942750e0cb95c1e08066 Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Wed, 8 Mar 2017 18:54:09 +0100 Subject: [PATCH 07/14] Fix type conversion for labels added to search queries on macOS Signed-off-by: Nassim 'Nass' Eddequiouaq --- osxkeychain/osxkeychain_darwin.c | 6 +++++- osxkeychain/osxkeychain_darwin_test.go | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osxkeychain/osxkeychain_darwin.c b/osxkeychain/osxkeychain_darwin.c index 5b420d0..f84d61e 100644 --- a/osxkeychain/osxkeychain_darwin.c +++ b/osxkeychain/osxkeychain_darwin.c @@ -135,16 +135,20 @@ char * CFStringToCharArr(CFStringRef aString) { } 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, CFSTR(credsLabel)); + 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); diff --git a/osxkeychain/osxkeychain_darwin_test.go b/osxkeychain/osxkeychain_darwin_test.go index bbfe1ff..9cfb108 100644 --- a/osxkeychain/osxkeychain_darwin_test.go +++ b/osxkeychain/osxkeychain_darwin_test.go @@ -7,13 +7,13 @@ import ( func TestOSXKeychainHelper(t *testing.T) { creds := &credentials.Credentials{ - Label: credentials.CredsLabel, + Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", } creds1 := &credentials.Credentials{ - Label: credentials.CredsLabel, + Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v2", Username: "foobarbaz", Secret: "foobar", From 2a8670e0da11b26e54bcccf815afbf7d851073c6 Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Thu, 9 Mar 2017 01:33:48 +0100 Subject: [PATCH 08/14] Cleanup original modifications to the exposed APIs Signed-off-by: Nassim 'Nass' Eddequiouaq --- client/client_test.go | 10 +++++----- credentials/credentials.go | 10 ++++------ credentials/credentials_test.go | 2 +- credentials/helper.go | 5 ++--- osxkeychain/osxkeychain_darwin.go | 6 +++--- osxkeychain/osxkeychain_darwin_test.go | 6 ++---- secretservice/secretservice_linux.go | 6 +++--- secretservice/secretservice_linux_test.go | 5 ++--- wincred/wincred_windows.go | 4 ++-- wincred/wincred_windows_test.go | 6 ++---- 10 files changed, 26 insertions(+), 34 deletions(-) diff --git a/client/client_test.go b/client/client_test.go index c1665c4..e5f1bf2 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -106,8 +106,8 @@ func ExampleStore() { func TestStore(t *testing.T) { valid := []credentials.Credentials{ - {credentials.CredsLabel, validServerAddress, "foo", "bar"}, - {credentials.CredsLabel, validServerAddress2, "", "abcd1234"}, + {validServerAddress, "foo", "bar"}, + {validServerAddress2, "", "abcd1234"}, } for _, v := range valid { @@ -117,7 +117,7 @@ func TestStore(t *testing.T) { } invalid := []credentials.Credentials{ - {credentials.CredsLabel, invalidServerAddress, "foo", "bar"}, + {invalidServerAddress, "foo", "bar"}, } for _, v := range invalid { @@ -140,8 +140,8 @@ func ExampleGet() { func TestGet(t *testing.T) { valid := []credentials.Credentials{ - {credentials.CredsLabel, validServerAddress, "foo", "bar"}, - {credentials.CredsLabel, validServerAddress2, "", "abcd1234"}, + {validServerAddress, "foo", "bar"}, + {validServerAddress2, "", "abcd1234"}, } for _, v := range valid { diff --git a/credentials/credentials.go b/credentials/credentials.go index 539a5a4..ec1aff8 100644 --- a/credentials/credentials.go +++ b/credentials/credentials.go @@ -12,14 +12,14 @@ import ( // Credentials holds the information shared between docker and the credentials store. type Credentials struct { - Label string ServerURL string Username string Secret string } -// Docker credentials should be labeled as such in credential stores, this label -// allow us to filter out non-Docker credentials at lookup +// Docker credentials should be labeled as such in credentials stores that allow labelling. +// That label allows to filter out non-Docker credentials too at lookup/search in macOS keychain, +// Windows credentials manager and Linux libsecret. const CredsLabel = "Docker Credentials" // Serve initializes the credentials helper and parses the action argument. @@ -77,8 +77,6 @@ func Store(helper Helper, reader io.Reader) error { return err } - creds.Label = CredsLabel - return helper.Add(&creds) } @@ -140,7 +138,7 @@ func Erase(helper Helper, reader io.Reader) error { //List returns all the serverURLs of keys in //the OS store as a list of strings func List(helper Helper, writer io.Writer) error { - accts, err := helper.List(CredsLabel) + accts, err := helper.List() if err != nil { return err } diff --git a/credentials/credentials_test.go b/credentials/credentials_test.go index 3c2ca52..6b8bbe1 100644 --- a/credentials/credentials_test.go +++ b/credentials/credentials_test.go @@ -36,7 +36,7 @@ func (m *memoryStore) Get(serverURL string) (string, string, error) { return c.Username, c.Secret, nil } -func (m *memoryStore) List(credsLabel string) (map[string]string, error) { +func (m *memoryStore) List() (map[string]string, error) { //Simply a placeholder to let memoryStore be a valid implementation of Helper interface return nil, nil } diff --git a/credentials/helper.go b/credentials/helper.go index fad53ee..135acd2 100644 --- a/credentials/helper.go +++ b/credentials/helper.go @@ -9,7 +9,6 @@ type Helper interface { // Get retrieves credentials from the store. // It returns username and secret as strings. Get(serverURL string) (string, string, error) - // List returns the stored serverURLs and their associated usernames - // for a given credentials label. - List(credsLabel string) (map[string]string, error) + // List returns the stored serverURLs and their associated usernames. + List() (map[string]string, error) } diff --git a/osxkeychain/osxkeychain_darwin.go b/osxkeychain/osxkeychain_darwin.go index 137b894..a3f5da8 100644 --- a/osxkeychain/osxkeychain_darwin.go +++ b/osxkeychain/osxkeychain_darwin.go @@ -35,7 +35,7 @@ func (h Osxkeychain) Add(creds *credentials.Credentials) error { } defer freeServer(s) - label := C.CString(creds.Label) + label := C.CString(credentials.CredsLabel) defer C.free(unsafe.Pointer(label)) username := C.CString(creds.Username) defer C.free(unsafe.Pointer(username)) @@ -100,8 +100,8 @@ func (h Osxkeychain) Get(serverURL string) (string, string, error) { } // List returns the stored URLs and corresponding usernames. -func (h Osxkeychain) List(credsLabel string) (map[string]string, error) { - credsLabelC := C.CString(credsLabel) +func (h Osxkeychain) List() (map[string]string, error) { + credsLabelC := C.CString(credentials.CredsLabel) defer C.free(unsafe.Pointer(credsLabelC)) var pathsC **C.char diff --git a/osxkeychain/osxkeychain_darwin_test.go b/osxkeychain/osxkeychain_darwin_test.go index 9cfb108..406fe9b 100644 --- a/osxkeychain/osxkeychain_darwin_test.go +++ b/osxkeychain/osxkeychain_darwin_test.go @@ -7,13 +7,11 @@ import ( func TestOSXKeychainHelper(t *testing.T) { creds := &credentials.Credentials{ - Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", } creds1 := &credentials.Credentials{ - Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v2", Username: "foobarbaz", Secret: "foobar", @@ -36,14 +34,14 @@ func TestOSXKeychainHelper(t *testing.T) { t.Fatalf("expected %s, got %s\n", "foobarbaz", secret) } - auths, err := helper.List(credentials.CredsLabel) + auths, err := helper.List() if err != nil || len(auths) == 0 { t.Fatal(err) } helper.Add(creds1) defer helper.Delete(creds1.ServerURL) - newauths, err := helper.List(credentials.CredsLabel) + newauths, err := helper.List() if len(newauths)-len(auths) != 1 { if err == nil { t.Fatalf("Error: len(newauths): %d, len(auths): %d", len(newauths), len(auths)) diff --git a/secretservice/secretservice_linux.go b/secretservice/secretservice_linux.go index 26760bf..6b82a07 100644 --- a/secretservice/secretservice_linux.go +++ b/secretservice/secretservice_linux.go @@ -22,7 +22,7 @@ func (h Secretservice) Add(creds *credentials.Credentials) error { if creds == nil { return errors.New("missing credentials") } - credsLabel := C.CString(creds.Label) + credsLabel := C.CString(credentials.CredsLabel) defer C.free(unsafe.Pointer(credsLabel)) server := C.CString(creds.ServerURL) defer C.free(unsafe.Pointer(server)) @@ -82,8 +82,8 @@ func (h Secretservice) Get(serverURL string) (string, string, error) { } // List returns the stored URLs and corresponding usernames for a given credentials label -func (h Secretservice) List(credsLabel string) (map[string]string, error) { - credsLabelC := C.CString(credsLabel) +func (h Secretservice) List() (map[string]string, error) { + credsLabelC := C.CString(credentials.CredsLabel) defer C.free(unsafe.Pointer(credsLabelC)) var pathsC **C.char diff --git a/secretservice/secretservice_linux_test.go b/secretservice/secretservice_linux_test.go index 057efca..bd0caf3 100644 --- a/secretservice/secretservice_linux_test.go +++ b/secretservice/secretservice_linux_test.go @@ -10,7 +10,6 @@ func TestSecretServiceHelper(t *testing.T) { t.Skip("test requires gnome-keyring but travis CI doesn't have it") creds := &credentials.Credentials{ - Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", @@ -37,12 +36,12 @@ func TestSecretServiceHelper(t *testing.T) { if err := helper.Delete(creds.ServerURL); err != nil { t.Fatal(err) } - auths, err := helper.List(credentials.CredsLabel) + auths, err := helper.List() if err != nil || len(auths) == 0 { t.Fatal(err) } helper.Add(creds) - if newauths, err := helper.List(credentials.CredsLabel); (len(newauths) - len(auths)) != 1 { + if newauths, err := helper.List(); (len(newauths) - len(auths)) != 1 { t.Fatal(err) } } diff --git a/wincred/wincred_windows.go b/wincred/wincred_windows.go index ce42d91..18e442e 100644 --- a/wincred/wincred_windows.go +++ b/wincred/wincred_windows.go @@ -16,7 +16,7 @@ func (h Wincred) Add(creds *credentials.Credentials) error { g.UserName = creds.Username g.CredentialBlob = []byte(creds.Secret) g.Persist = winc.PersistLocalMachine - g.Attributes = []winc.CredentialAttribute{{"label", []byte(creds.Label)}} + g.Attributes = []winc.CredentialAttribute{{"label", []byte(credentials.CredsLabel)}} return g.Write() } @@ -43,7 +43,7 @@ func (h Wincred) Get(serverURL string) (string, string, error) { } // List returns the stored URLs and corresponding usernames for a given credentials label. -func (h Wincred) List(credsLabel string) (map[string]string, error) { +func (h Wincred) List() (map[string]string, error) { creds, err := winc.List() if err != nil { return nil, err diff --git a/wincred/wincred_windows_test.go b/wincred/wincred_windows_test.go index 0c115e9..01f6e59 100644 --- a/wincred/wincred_windows_test.go +++ b/wincred/wincred_windows_test.go @@ -8,13 +8,11 @@ import ( func TestWinCredHelper(t *testing.T) { creds := &credentials.Credentials{ - Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", } creds1 := &credentials.Credentials{ - Label: credentials.CredsLabel, ServerURL: "https://foobar.docker.io:2376/v2", Username: "foobarbaz", Secret: "foobar", @@ -38,14 +36,14 @@ func TestWinCredHelper(t *testing.T) { t.Fatalf("expected %s, got %s\n", "foobarbaz", secret) } - auths, err := helper.List(credentials.CredsLabel) + auths, err := helper.List() if err != nil || len(auths) == 0 { t.Fatal(err) } helper.Add(creds1) defer helper.Delete(creds1.ServerURL) - newauths, err := helper.List(credentials.CredsLabel) + newauths, err := helper.List() if err != nil { t.Fatal(err) } From 021d7d6a1955b6b132e717a953f8f50a2780ac3f Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Thu, 9 Mar 2017 18:10:48 +0100 Subject: [PATCH 09/14] Add label filter on the list of secrets Signed-off-by: Nassim 'Nass' Eddequiouaq --- secretservice/secretservice_linux.c | 36 +++++++++++++++++------------ 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/secretservice/secretservice_linux.c b/secretservice/secretservice_linux.c index 17e67bc..8b48231 100644 --- a/secretservice/secretservice_linux.c +++ b/secretservice/secretservice_linux.c @@ -42,7 +42,7 @@ GError *delete(char *server) { return NULL; } -char *get_username(SecretItem *item) { +char *get_attribute(const char *attribute, SecretItem *item) { GHashTable *attributes; GHashTableIter iter; gchar *value, *key; @@ -50,7 +50,7 @@ char *get_username(SecretItem *item) { 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, "username", strlen(key)) == 0) + if (strncmp(key, attribute, strlen(key)) == 0) return (char *)value; } g_hash_table_unref(attributes); @@ -87,7 +87,7 @@ GError *get(char *server, char **username, char **secret) { *secret = strdup(secret_value_get(secretValue, &length)); secret_value_unref(secretValue); } - *username = get_username(l->data); + *username = get_attribute("username", l->data); } g_list_free_full(items, g_object_unref); } @@ -100,14 +100,12 @@ GError *get(char *server, char **username, char **secret) { return NULL; } -GError *list(char *label, char *** paths, char *** accts, unsigned int *list_l) { +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 = secret_attributes_build(NULL, - "label", label, - NULL); + GHashTable *attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); service = secret_service_get_sync(SECRET_SERVICE_NONE, NULL, &err); items = secret_service_search_sync(service, NULL, attributes, flags, NULL, &err); @@ -115,8 +113,8 @@ GError *list(char *label, char *** paths, char *** accts, unsigned int *list_l) if (err != NULL) { return err; } - *paths = (char **) malloc((int)sizeof(char *)*numKeys); - *accts = (char **) malloc((int)sizeof(char *)*numKeys); + char **tmp_paths = (char **) malloc((int)sizeof(char *)*numKeys); + char **tmp_accts = (char **) malloc((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; @@ -124,21 +122,29 @@ GError *list(char *label, char *** paths, char *** accts, unsigned int *list_l) 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_username(current->data); + char *acctTmp = get_attribute("username",current->data); if (acctTmp==NULL) { acctTmp = "account not defined"; } + char *labelTmp = get_attribute("label", current->data); + if (strcmp(labelTmp, ref_label)) { + continue; + } char *path = (char *) malloc(strlen(pathTmp)); char *acct = (char *) malloc(strlen(acctTmp)); path = pathTmp; acct = acctTmp; - (*paths)[listNumber] = (char *) malloc(sizeof(char)*(strlen(path))); - memcpy((*paths)[listNumber], path, sizeof(char)*(strlen(path))); - (*accts)[listNumber] = (char *) malloc(sizeof(char)*(strlen(acct))); - memcpy((*accts)[listNumber], acct, sizeof(char)*(strlen(acct))); + tmp_paths[listNumber] = (char *) malloc(sizeof(char)*(strlen(path))); + memcpy(tmp_paths[listNumber], path, sizeof(char)*(strlen(path))); + tmp_accts[listNumber] = (char *) malloc(sizeof(char)*(strlen(acct))); + memcpy(tmp_accts[listNumber], acct, sizeof(char)*(strlen(acct))); listNumber = listNumber + 1; } - *list_l = numKeys; + + *paths = (char **) realloc(tmp_paths, listNumber); + *accts = (char **) realloc(tmp_accts, listNumber); + *list_l = listNumber; + return NULL; } From cd76e4253f7caa30069f69fac5ec3bfac645fb40 Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Fri, 10 Mar 2017 05:29:24 -0800 Subject: [PATCH 10/14] Use the proper docker secret schema for items to search for Signed-off-by: Nassim 'Nass' Eddequiouaq --- secretservice/secretservice_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secretservice/secretservice_linux.c b/secretservice/secretservice_linux.c index 8b48231..4af5731 100644 --- a/secretservice/secretservice_linux.c +++ b/secretservice/secretservice_linux.c @@ -73,7 +73,7 @@ GError *get(char *server, char **username, char **secret) { service = secret_service_get_sync(SECRET_SERVICE_NONE, NULL, &err); if (err == NULL) { - items = secret_service_search_sync(service, NULL, attributes, flags, NULL, &err); + 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); From 8cb3338668e828acc5c174ab7bace6590e01e683 Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Fri, 10 Mar 2017 05:30:48 -0800 Subject: [PATCH 11/14] Filter docker credentials with label directly through libsecret Signed-off-by: Nassim 'Nass' Eddequiouaq --- secretservice/secretservice_linux.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/secretservice/secretservice_linux.c b/secretservice/secretservice_linux.c index 4af5731..56e1a75 100644 --- a/secretservice/secretservice_linux.c +++ b/secretservice/secretservice_linux.c @@ -107,7 +107,14 @@ GError *list(char *ref_label, char *** paths, char *** accts, unsigned int *list 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) { From e522e566994909b4eb604d471be15ea56fca1440 Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Fri, 10 Mar 2017 05:32:12 -0800 Subject: [PATCH 12/14] Fix memory leaks and non-null terminated strings usage Signed-off-by: Nassim 'Nass' Eddequiouaq --- secretservice/secretservice_linux.c | 30 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/secretservice/secretservice_linux.c b/secretservice/secretservice_linux.c index 56e1a75..35dea92 100644 --- a/secretservice/secretservice_linux.c +++ b/secretservice/secretservice_linux.c @@ -120,8 +120,10 @@ GError *list(char *ref_label, char *** paths, char *** accts, unsigned int *list if (err != NULL) { return err; } - char **tmp_paths = (char **) malloc((int)sizeof(char *)*numKeys); - char **tmp_accts = (char **) malloc((int)sizeof(char *)*numKeys); + + 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; @@ -133,23 +135,19 @@ GError *list(char *ref_label, char *** paths, char *** accts, unsigned int *list if (acctTmp==NULL) { acctTmp = "account not defined"; } - char *labelTmp = get_attribute("label", current->data); - if (strcmp(labelTmp, ref_label)) { - continue; - } - char *path = (char *) malloc(strlen(pathTmp)); - char *acct = (char *) malloc(strlen(acctTmp)); - path = pathTmp; - acct = acctTmp; - tmp_paths[listNumber] = (char *) malloc(sizeof(char)*(strlen(path))); - memcpy(tmp_paths[listNumber], path, sizeof(char)*(strlen(path))); - tmp_accts[listNumber] = (char *) malloc(sizeof(char)*(strlen(acct))); - memcpy(tmp_accts[listNumber], acct, sizeof(char)*(strlen(acct))); + + 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, listNumber); - *accts = (char **) realloc(tmp_accts, listNumber); + *paths = (char **) realloc(tmp_paths, (int)sizeof(char *)*listNumber); + *accts = (char **) realloc(tmp_accts, (int)sizeof(char *)*listNumber); + *list_l = listNumber; return NULL; From b9d19b479aa256c9301e978d3f1dfe4b663988dc Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Fri, 10 Mar 2017 05:33:24 -0800 Subject: [PATCH 13/14] Return empty server-url to usernames map if no search results Signed-off-by: Nassim 'Nass' Eddequiouaq --- secretservice/secretservice_linux.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/secretservice/secretservice_linux.go b/secretservice/secretservice_linux.go index 6b82a07..ec1c5d3 100644 --- a/secretservice/secretservice_linux.go +++ b/secretservice/secretservice_linux.go @@ -99,10 +99,14 @@ func (h Secretservice) List() (map[string]string, error) { defer C.freeListData(&pathsC, listLenC) defer C.freeListData(&acctsC, listLenC) + resp := make(map[string]string) + listLen := int(listLenC) + if listLen == 0 { + return resp, nil + } pathTmp := (*[1 << 30]*C.char)(unsafe.Pointer(pathsC))[:listLen:listLen] acctTmp := (*[1 << 30]*C.char)(unsafe.Pointer(acctsC))[:listLen:listLen] - resp := make(map[string]string) for i := 0; i < listLen; i++ { resp[C.GoString(pathTmp[i])] = C.GoString(acctTmp[i]) } From 7133af577e1dfce3040f52d0af5d6528d7e3da5e Mon Sep 17 00:00:00 2001 From: Nassim 'Nass' Eddequiouaq Date: Sat, 11 Mar 2017 12:34:22 +0100 Subject: [PATCH 14/14] Creds label can be configured from helpers Signed-off-by: Nassim 'Nass' Eddequiouaq --- credentials/credentials.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/credentials/credentials.go b/credentials/credentials.go index ec1aff8..cfe0cb1 100644 --- a/credentials/credentials.go +++ b/credentials/credentials.go @@ -19,8 +19,12 @@ type Credentials struct { // Docker credentials should be labeled as such in credentials stores that allow labelling. // That label allows to filter out non-Docker credentials too at lookup/search in macOS keychain, -// Windows credentials manager and Linux libsecret. -const CredsLabel = "Docker Credentials" +// Windows credentials manager and Linux libsecret. Default value is "Docker Credentials" +var CredsLabel = "Docker Credentials" + +func SetCredsLabel(label string) { + CredsLabel = label +} // Serve initializes the credentials helper and parses the action argument. // This function is designed to be called from a command line interface.