tailscale/paths/paths_unix.go
Aaron Klotz 9ebb5d4205 ipn, paths: ensure that the state directory for Windows has the correct perms
ProgramData has a permissive ACL. For us to safely store machine-wide
state information, we must set a more restrictive ACL on our state directory.
We set the ACL so that only talescaled's user (ie, LocalSystem) and the
Administrators group may access our directory.

We must include Administrators to ensure that logs continue to be easily
accessible; omitting that group would force users to use special tools to
log in interactively as LocalSystem, which is not ideal.

(Note that the ACL we apply matches the ACL that was used for LocalSystem's
AppData\Local).

There are two cases where we need to reset perms: One is during migration
from the old location to the new. The second case is for clean installations
where we are creating the file store for the first time.

Updates #2856

Signed-off-by: Aaron Klotz <aaron@tailscale.com>
2021-09-22 14:50:00 -06:00

72 lines
1.5 KiB
Go

// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !windows
// +build !windows
package paths
import (
"os"
"path/filepath"
"runtime"
"golang.org/x/sys/unix"
)
func init() {
stateFileFunc = stateFileUnix
}
func statePath() string {
switch runtime.GOOS {
case "linux":
return "/var/lib/tailscale/tailscaled.state"
case "freebsd", "openbsd":
return "/var/db/tailscale/tailscaled.state"
case "darwin":
return "/Library/Tailscale/tailscaled.state"
default:
return ""
}
}
func stateFileUnix() string {
path := statePath()
if path == "" {
return ""
}
try := path
for i := 0; i < 3; i++ { // check writability of the file, /var/lib/tailscale, and /var/lib
err := unix.Access(try, unix.O_RDWR)
if err == nil {
return path
}
try = filepath.Dir(try)
}
if os.Getuid() == 0 {
return ""
}
// For non-root users, fall back to $XDG_DATA_HOME/tailscale/*.
return filepath.Join(xdgDataHome(), "tailscale", "tailscaled.state")
}
func xdgDataHome() string {
if e := os.Getenv("XDG_DATA_HOME"); e != "" {
return e
}
return filepath.Join(os.Getenv("HOME"), ".local/share")
}
func ensureStateDirPerms(dirPath string) error {
// Unfortunately there are currently numerous tests that set up state files
// right off of /tmp, on which Chmod will of course fail. We should fix our
// test harnesses to not do that, at which point we can return an error.
os.Chmod(dirPath, 0700)
return nil
}