...

Source file src/github.com/docker/docker-credential-helpers/secretservice/secretservice.go

Documentation: github.com/docker/docker-credential-helpers/secretservice

     1  //go:build linux && cgo
     2  
     3  package secretservice
     4  
     5  /*
     6  #cgo pkg-config: libsecret-1
     7  
     8  #include "secretservice.h"
     9  #include <stdlib.h>
    10  */
    11  import "C"
    12  
    13  import (
    14  	"errors"
    15  	"unsafe"
    16  
    17  	"github.com/docker/docker-credential-helpers/credentials"
    18  )
    19  
    20  // Secretservice handles secrets using Linux secret-service as a store.
    21  type Secretservice struct{}
    22  
    23  // Add adds new credentials to the keychain.
    24  func (h Secretservice) Add(creds *credentials.Credentials) error {
    25  	if creds == nil {
    26  		return errors.New("missing credentials")
    27  	}
    28  	credsLabel := C.CString(credentials.CredsLabel)
    29  	defer C.free(unsafe.Pointer(credsLabel))
    30  	server := C.CString(creds.ServerURL)
    31  	defer C.free(unsafe.Pointer(server))
    32  	username := C.CString(creds.Username)
    33  	defer C.free(unsafe.Pointer(username))
    34  	secret := C.CString(creds.Secret)
    35  	defer C.free(unsafe.Pointer(secret))
    36  
    37  	if err := C.add(credsLabel, server, username, secret); err != nil {
    38  		defer C.g_error_free(err)
    39  		errMsg := (*C.char)(unsafe.Pointer(err.message))
    40  		return errors.New(C.GoString(errMsg))
    41  	}
    42  	return nil
    43  }
    44  
    45  // Delete removes credentials from the store.
    46  func (h Secretservice) Delete(serverURL string) error {
    47  	if serverURL == "" {
    48  		return errors.New("missing server url")
    49  	}
    50  	server := C.CString(serverURL)
    51  	defer C.free(unsafe.Pointer(server))
    52  
    53  	if err := C.delete(server); err != nil {
    54  		defer C.g_error_free(err)
    55  		errMsg := (*C.char)(unsafe.Pointer(err.message))
    56  		return errors.New(C.GoString(errMsg))
    57  	}
    58  	return nil
    59  }
    60  
    61  // Get returns the username and secret to use for a given registry server URL.
    62  func (h Secretservice) Get(serverURL string) (string, string, error) {
    63  	if serverURL == "" {
    64  		return "", "", errors.New("missing server url")
    65  	}
    66  	var username *C.char
    67  	defer C.free(unsafe.Pointer(username))
    68  	var secret *C.char
    69  	defer C.free(unsafe.Pointer(secret))
    70  	server := C.CString(serverURL)
    71  	defer C.free(unsafe.Pointer(server))
    72  
    73  	err := C.get(server, &username, &secret)
    74  	if err != nil {
    75  		defer C.g_error_free(err)
    76  		errMsg := (*C.char)(unsafe.Pointer(err.message))
    77  		return "", "", errors.New(C.GoString(errMsg))
    78  	}
    79  	user := C.GoString(username)
    80  	pass := C.GoString(secret)
    81  	if pass == "" {
    82  		return "", "", credentials.NewErrCredentialsNotFound()
    83  	}
    84  	return user, pass, nil
    85  }
    86  
    87  // List returns the stored URLs and corresponding usernames for a given credentials label
    88  func (h Secretservice) List() (map[string]string, error) {
    89  	credsLabelC := C.CString(credentials.CredsLabel)
    90  	defer C.free(unsafe.Pointer(credsLabelC))
    91  
    92  	var pathsC **C.char
    93  	defer C.free(unsafe.Pointer(pathsC))
    94  	var acctsC **C.char
    95  	defer C.free(unsafe.Pointer(acctsC))
    96  	var listLenC C.uint
    97  	err := C.list(credsLabelC, &pathsC, &acctsC, &listLenC)
    98  	defer C.freeListData(&pathsC, listLenC)
    99  	defer C.freeListData(&acctsC, listLenC)
   100  	if err != nil {
   101  		defer C.g_error_free(err)
   102  		errMsg := (*C.char)(unsafe.Pointer(err.message))
   103  		return nil, errors.New(C.GoString(errMsg))
   104  	}
   105  
   106  	resp := make(map[string]string)
   107  
   108  	listLen := int(listLenC)
   109  	if listLen == 0 {
   110  		return resp, nil
   111  	}
   112  	// The maximum capacity of the following two slices is limited to (2^29)-1 to remain compatible
   113  	// with 32-bit platforms. The size of a `*C.char` (a pointer) is 4 Byte on a 32-bit system
   114  	// and (2^29)*4 == math.MaxInt32 + 1. -- See issue golang/go#13656
   115  	pathTmp := (*[(1 << 29) - 1]*C.char)(unsafe.Pointer(pathsC))[:listLen:listLen]
   116  	acctTmp := (*[(1 << 29) - 1]*C.char)(unsafe.Pointer(acctsC))[:listLen:listLen]
   117  	for i := 0; i < listLen; i++ {
   118  		resp[C.GoString(pathTmp[i])] = C.GoString(acctTmp[i])
   119  	}
   120  
   121  	return resp, nil
   122  }
   123  

View as plain text