--- a/access/access.go Sat Apr 27 18:19:37 2019 -0300
+++ b/access/access.go Sun Apr 28 02:00:26 2019 -0300
@@ -1,10 +1,11 @@
@@ -21,11 +22,6 @@
- keysCacheMu sync.RWMutex
- keysCache = make(map[string]string)
// Public is a reserved hgkeeper name and is not valid in the patterns
// or keys of an access file.
@@ -41,38 +37,6 @@
-// A Perm represents one or more access permissions: reading, writing, etc.
-// All permisions constants
-// String returns a textual representation of the perm.
-func (p Perm) String() string {
-func (p *Perm) can(i Perm) bool { return *p&i != 0 }
-func (p *Perm) clear(i Perm) { *p &^= i }
-func (p *Perm) set(i Perm) { *p |= i }
@@ -90,23 +54,14 @@
-// parse parses access yml into a
-func (a *Access) parse(b []byte) error {
- dec := yaml.NewDecoder(bytes.NewReader(b))
+// parse calls inderectly UnmarshalYAML, it's caller's duty to control the access to a. +func (a *Access) parse(r io.Reader) error { + return yaml.NewDecoder(r).Decode(a) // UnmarshalYAML unmarshals access yaml into an internal access
+// It's caller's duty to control the access to a. func (a *Access) UnmarshalYAML(f func(interface{}) error) error {
Init []string `yaml:"init"`
@@ -129,13 +84,12 @@
log.Errorf("access: %q group is reserved, ignored", i)
+ if _, exists := groups[i]; exists { log.Errorf("access: group %q registered twice", i)
- for _, key := range v {
+ for _, keyFile := range v { + k, err := loadKey(keyFile) if _, ok := groups[i]; !ok {
@@ -145,7 +99,11 @@
- groups[i] = append(groups[i], _key{fprint: k})
+ keys := make([]_key, 0, len(k)) + keys = append(keys, _key{fprint: v}) + groups[i] = append(groups[i], keys...) @@ -162,23 +120,20 @@
a.setPathWrite(path, v.Write, groups)
- // what to do with dummy.Global?
- fmt.Printf("%+v\n", a.paths)
-func (a *Access) addToPath(path string, k _key, p Perm) {
- defer a.pathsMu.Unlock()
- if keys, found := a.paths[path]; found {
- if n := k.find(keys); n >= 0 {
- a.paths[path][n].p.set(p)
+func (a *Access) addToPath(path string, p Perm, ks ..._key) { + if keys, found := a.paths[path]; found { + if n := k.find(keys); n >= 0 { + a.paths[path][n].p.set(p) + a.paths[path] = append(a.paths[path], k)
- a.paths[path] = append(a.paths[path], k)
func (a *Access) setPathInit(path string, init []string, groups map[string][]_key) {
@@ -188,17 +143,20 @@
for i := range groups[key] {
- a.addToPath(path, k, Init)
+ a.addToPath(path, Init, k) - fp, err := loadKey(key)
+ ks, err := loadKey(key)
- a.addToPath(path, k, Init)
+ keys := make([]_key, 0, len(ks)) + keys = append(keys, _key{fprint: v}) + a.addToPath(path, Init, keys...) @@ -209,17 +167,20 @@
for i := range groups[key] {
- a.addToPath(path, k, Read)
+ a.addToPath(path, Read, k) - fp, err := loadKey(key)
+ ks, err := loadKey(key)
- a.addToPath(path, k, Read)
+ keys := make([]_key, 0, len(ks)) + keys = append(keys, _key{fprint: v}) + a.addToPath(path, Read, keys...) @@ -230,17 +191,20 @@
for i := range groups[key] {
- a.addToPath(path, k, Write)
+ a.addToPath(path, Write, k) - fp, err := loadKey(key)
+ ks, err := loadKey(key)
- a.addToPath(path, k, Write)
+ keys := make([]_key, 0, len(ks)) + keys = append(keys, _key{fprint: v}) + a.addToPath(path, Write, keys...) @@ -264,18 +228,16 @@
func (a *Access) Reset() error {
+ defer a.pathsMu.Unlock()
- b, err := ioutil.ReadFile(accessFile)
+ f, err := os.Open(accessFile) - if err = a.parse(b); err != nil {
// New initializes access strucuture, if any error is
@@ -285,34 +247,37 @@
accessFile = filepath.Join(reposPath, "hgkeeper", AccessFile)
keysDir = filepath.Join(reposPath, "hgkeeper", KeysDir)
- b, err := ioutil.ReadFile(accessFile)
a.paths = make(map[string][]_key)
- if err = a.parse(b); err != nil {
// loadKey reads repoPath/hgkeeper/keys/name and tries to
// parse as an authorized keys format, and returns its fingerprint
-func loadKey(name string) (string, error) {
- k, err := ioutil.ReadFile(filepath.Join(keysDir, name))
+func loadKey(name string) ([]string, error) { + f, err := os.Open(filepath.Join(keysDir, name)) - return "", fmt.Errorf("loadKey %q: %v", name, err)
+ return nil, fmt.Errorf("loadKey %q: %v", name, err)
- pub, _, _, _, err := ssh.ParseAuthorizedKey(k)
- return "", fmt.Errorf("loadKey %q: %v", name, err)
+ keys := make([]string, 0, 20) + // according to sshd(8) each line of the file contains one key, + // ignoring empty and lines starting with # + bio := bufio.NewScanner(f) + for line := 1; bio.Scan(); line++ { + if key == "" || key[0] == '#' { + pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key)) + log.Errorf("loadKey %q:%d: %v", name, line, err) + keys = append(keys, ssh.FingerprintSHA256(pub)) - return ssh.FingerprintSHA256(pub), nil
// isPublic checks whenever u is or not the reserved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/access/permissions.go Sun Apr 28 02:00:26 2019 -0300
@@ -0,0 +1,33 @@
+// A Perm represents one or more access permissions: reading, writing, etc. +// All permisions constants +// String returns a textual representation of the perm. +func (p Perm) String() string { +func (p *Perm) can(i Perm) bool { return *p&i != 0 } +func (p *Perm) clear(i Perm) { *p &^= i } +func (p *Perm) set(i Perm) { *p |= i } --- a/ssh/server.go Sat Apr 27 18:19:37 2019 -0300
+++ b/ssh/server.go Sun Apr 28 02:00:26 2019 -0300
@@ -63,9 +63,7 @@
func (s *Server) publicKeyCallback(meta ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
- if !s.a.Can("", "", access.Read) {
- return nil, fmt.Errorf("permission denied")
+ log.Debugf("key: %s\n", key.Marshal())