secretservice_linux.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package secretservice
  2. /*
  3. #cgo pkg-config: libsecret-1
  4. #include "secretservice_linux.h"
  5. #include <stdlib.h>
  6. */
  7. import "C"
  8. import (
  9. "errors"
  10. "unsafe"
  11. "github.com/docker/docker-credential-helpers/credentials"
  12. )
  13. // Secretservice handles secrets using Linux secret-service as a store.
  14. type Secretservice struct{}
  15. // Add adds new credentials to the keychain.
  16. func (h Secretservice) Add(creds *credentials.Credentials) error {
  17. if creds == nil {
  18. return errors.New("missing credentials")
  19. }
  20. credsLabel := C.CString(credentials.CredsLabel)
  21. defer C.free(unsafe.Pointer(credsLabel))
  22. server := C.CString(creds.ServerURL)
  23. defer C.free(unsafe.Pointer(server))
  24. username := C.CString(creds.Username)
  25. defer C.free(unsafe.Pointer(username))
  26. secret := C.CString(creds.Secret)
  27. defer C.free(unsafe.Pointer(secret))
  28. if err := C.add(credsLabel, server, username, secret); err != nil {
  29. defer C.g_error_free(err)
  30. errMsg := (*C.char)(unsafe.Pointer(err.message))
  31. return errors.New(C.GoString(errMsg))
  32. }
  33. return nil
  34. }
  35. // Delete removes credentials from the store.
  36. func (h Secretservice) Delete(serverURL string) error {
  37. if serverURL == "" {
  38. return errors.New("missing server url")
  39. }
  40. server := C.CString(serverURL)
  41. defer C.free(unsafe.Pointer(server))
  42. if err := C.delete(server); err != nil {
  43. defer C.g_error_free(err)
  44. errMsg := (*C.char)(unsafe.Pointer(err.message))
  45. return errors.New(C.GoString(errMsg))
  46. }
  47. return nil
  48. }
  49. // Get returns the username and secret to use for a given registry server URL.
  50. func (h Secretservice) Get(serverURL string) (string, string, error) {
  51. if serverURL == "" {
  52. return "", "", errors.New("missing server url")
  53. }
  54. var username *C.char
  55. defer C.free(unsafe.Pointer(username))
  56. var secret *C.char
  57. defer C.free(unsafe.Pointer(secret))
  58. server := C.CString(serverURL)
  59. defer C.free(unsafe.Pointer(server))
  60. err := C.get(server, &username, &secret)
  61. if err != nil {
  62. defer C.g_error_free(err)
  63. errMsg := (*C.char)(unsafe.Pointer(err.message))
  64. return "", "", errors.New(C.GoString(errMsg))
  65. }
  66. user := C.GoString(username)
  67. pass := C.GoString(secret)
  68. if pass == "" {
  69. return "", "", credentials.NewErrCredentialsNotFound()
  70. }
  71. return user, pass, nil
  72. }
  73. // List returns the stored URLs and corresponding usernames for a given credentials label
  74. func (h Secretservice) List() (map[string]string, error) {
  75. credsLabelC := C.CString(credentials.CredsLabel)
  76. defer C.free(unsafe.Pointer(credsLabelC))
  77. var pathsC **C.char
  78. defer C.free(unsafe.Pointer(pathsC))
  79. var acctsC **C.char
  80. defer C.free(unsafe.Pointer(acctsC))
  81. var listLenC C.uint
  82. err := C.list(credsLabelC, &pathsC, &acctsC, &listLenC)
  83. if err != nil {
  84. defer C.free(unsafe.Pointer(err))
  85. return nil, errors.New("Error from list function in secretservice_linux.c likely due to error in secretservice library")
  86. }
  87. defer C.freeListData(&pathsC, listLenC)
  88. defer C.freeListData(&acctsC, listLenC)
  89. resp := make(map[string]string)
  90. listLen := int(listLenC)
  91. if listLen == 0 {
  92. return resp, nil
  93. }
  94. pathTmp := (*[1 << 30]*C.char)(unsafe.Pointer(pathsC))[:listLen:listLen]
  95. acctTmp := (*[1 << 30]*C.char)(unsafe.Pointer(acctsC))[:listLen:listLen]
  96. for i := 0; i < listLen; i++ {
  97. resp[C.GoString(pathTmp[i])] = C.GoString(acctTmp[i])
  98. }
  99. return resp, nil
  100. }