diff --git a/cmd/olliesrv/server.go b/cmd/olliesrv/server.go index 72c14ba..27f0cd1 100644 --- a/cmd/olliesrv/server.go +++ b/cmd/olliesrv/server.go @@ -144,35 +144,11 @@ func fileOwnerGroup(root *fs.Tree, path string) (uid, gid string) { return "ollie", "agent" } -func checkPerm(uname string, mode uint8, uid string, perm uint32, inGroup bool) error { - var bits uint32 - if uname == uid { - bits = (perm >> 6) & 7 - } else if inGroup { - bits = (perm >> 3) & 7 - } else { - bits = perm & 7 - } - omode := mode & 3 - switch omode { - case plan9.OREAD: - if bits&4 == 0 { - return fmt.Errorf("permission denied") - } - case plan9.OWRITE: - if bits&2 == 0 { - return fmt.Errorf("permission denied") - } - case plan9.ORDWR: - if bits&6 != 6 { - return fmt.Errorf("permission denied") - } - case plan9.OEXEC: - if bits&1 == 0 { - return fmt.Errorf("permission denied") - } - } - return nil +var permMask = [4]uint32{4, 2, 6, 1} // OREAD, OWRITE, ORDWR, OEXEC + +func hasPermBits(mode uint8, bits uint32) bool { + m := permMask[mode&3] + return bits&m == m } const readTimeout = 10 * time.Second @@ -413,8 +389,20 @@ func (s *Server) open(cs *connState, fc *plan9.Fcall) *plan9.Fcall { return errFcall(fc, "bad fid") } uid, gid := fileOwnerGroup(s.rootTree, f.path) - if err := checkPerm(cs.uname, fc.Mode, uid, uint32(makeStat(s.rootTree, f.path).Mode)&0777, s.InGroup(gid, cs.uname)); err != nil { - return errFcall(fc, err.Error()) + perm := uint32(makeStat(s.rootTree, f.path).Mode) & 0777 + + allowed := false + if cs.uname == uid { + allowed = hasPermBits(fc.Mode, perm>>6) + } + if !allowed && s.InGroup(gid, cs.uname) { + allowed = hasPermBits(fc.Mode, perm>>3) + } + if !allowed { + allowed = hasPermBits(fc.Mode, perm) + } + if !allowed { + return errFcall(fc, "permission denied") } f.mode = fc.Mode return &plan9.Fcall{Type: plan9.Ropen, Tag: fc.Tag, Qid: f.qid}