func (zd *Dir) canRead(ai *auth.Info) bool { if ai==nil || ai.Uid=="elf" { return zd.mode&0444 != 0 } uid := zd.d["Uid"] if uid=="" || ai.Uid==uid { return zd.mode&0444 != 0 } if ai.InGroup(zd.d["Gid"]) { return zd.mode&0044 != 0 } return zd.mode&0004 != 0 }
func (zd *Dir) canExec(ai *auth.Info) bool { if ai==nil || ai.Uid=="elf" { return zd.mode&0111 != 0 } uid := zd.d["Uid"] if uid=="" || ai.Uid==uid || ai.Uid=="elf" { return zd.mode&0111 != 0 } if ai.InGroup(zd.d["Gid"]) { return zd.mode&0011 != 0 } return zd.mode&0001 != 0 }
// To check with 0111 | 0222 | 0444. func (d Dir) Can(ai *auth.Info, what int) bool { if d == nil { return true } mode := int(d.Mode()) if ai.InGroup(d["Uid"]) { return mode&what != 0 } if ai.InGroup(d["Gid"]) { return mode&what&077 != 0 } return mode&what&07 != 0 }
func (zd *Dir) canWstat(ai *auth.Info, nd zx.Dir) error { isowner := ai==nil || zd.d["Uid"]=="" || zd.d["Uid"]==ai.Uid canwrite := zd.canWrite(ai) for k, v := range nd { if v==zd.d[k] || ai!=nil && ai.Uid=="elf" { continue // no change really } switch k { case "mode": if !isowner { return fmt.Errorf("mode: %s", dbg.ErrPerm) } case "mtime", "size": if !canwrite { return fmt.Errorf("mtime: %s", dbg.ErrPerm) } case "type", "name", "Wuid": return fmt.Errorf("%s: %s", k, dbg.ErrPerm) case "Uid": if !ai.InGroup("sys") { return fmt.Errorf("%s: %s", k, dbg.ErrPerm) } case "Gid": if !ai.InGroup(v) && !ai.InGroup("sys") { return fmt.Errorf("%s: %s", k, dbg.ErrPerm) } default: if len(k)>0 && k[0]>='A' && k[0]<='Z' && !canwrite && !isowner { return fmt.Errorf("mtime: %s", dbg.ErrPerm) } } } return nil }
// can this auth info do this wstat to this file? // If ai is nil, owner's role is assumed. // path, addr, type, wuid, and name are never updated // so they are ignored. // Only the owner can udpate the mode // Updating the size is ok if CanPut(), and it's ignored for directories. // The owner can update the group or the owner if it's a // member of the target owner/group. // The owner and group members may update other attributes func (d Dir) CanWstat(ai *auth.Info, nd Dir) error { if ai == nil && nd["size"] != "" && d["type"] == "d" { return fmt.Errorf("size: %s", ErrIsDir) } if len(d) == 0 || len(nd) == 0 || ai == nil { return nil } isowner := ai.InGroup(d["uid"]) for k, v := range nd { if d[k] == v { continue } switch k { case "path", "addr", "type", "wuid", "name": // ignored case "mode": if !isowner { return fmt.Errorf("mode: %s", ErrPerm) } case "size": if !d.CanPut(ai) { return fmt.Errorf("size: %s", ErrPerm) } case "uid", "gid": if !isowner || (!ai.InGroup(v) && !ai.InGroup("elf")) { return fmt.Errorf("%s: %s", k, ErrPerm) } case "mtime": fallthrough default: if !isowner && !ai.InGroup(d["gid"]) { return fmt.Errorf("size: %s", ErrPerm) } } } return nil }
// can this wstat be performed? // If ai is nil, owner's role is assumed. // Use this to check that it look fine even under no permission checking. // The user can set only mode, mtime, size, and attrs starting with Upper runes but // for Wuid. // Attributes that the user can't set are ignored. // However if there are only attributes that the user can't set and they try to // change the value, an error is granted. // Mode can be changed only by the owner // mtime can be changed by the owner and anyone with write permissions. // size can be changed by anyone with write permissions. // uid/gid can be changed only by the owner if also a member of the target id or elf. // Other usr attrs can be changed only by the owner and anyone with write permissions. func (d Dir) CanWstat(ai *auth.Info, nd Dir) error { if d == nil || nd == nil { return nil } isowner := ai.InGroup(d["Uid"]) some := false somecant := "" for k, v := range nd { if !IsUsr(k) { if v == "" { return fmt.Errorf("%s: %s", k, errCantRemove) } somecant = k continue } if k == "size" && d["type"] == "d" && v != d[k] { somecant = k continue } some = true if v == d[k] { continue // no change really } switch k { case "mode": if v == "" { return fmt.Errorf("mode: %s", errCantRemove) } if !isowner { return fmt.Errorf("mode: %s", dbg.ErrPerm) } case "size": if v == "" { return fmt.Errorf("%s: %s", k, errCantRemove) } if !d.CanWrite(ai) { return fmt.Errorf("%s: %s", k, dbg.ErrPerm) } case "Uid", "Gid": if v == "" { return fmt.Errorf("%s: %s", k, errCantRemove) } if !isowner || (!ai.InGroup(v) && !ai.InGroup("elf")) { return fmt.Errorf("%s: %s", k, dbg.ErrPerm) } case "mtime": if v == "" { return fmt.Errorf("%s: %s", k, errCantRemove) } fallthrough default: if !isowner && !d.CanWrite(ai) { return fmt.Errorf("%s: %s", k, dbg.ErrPerm) } } } if !some && somecant != "" { return fmt.Errorf("%s: %s", somecant, dbg.ErrPerm) } return nil }