2023-03-29 16:27:12 +01:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
|
|
|
// Package permissions provides a doctor.Check that prints the process
|
|
|
|
// permissions for the running process.
|
|
|
|
package permissions
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"os/user"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"golang.org/x/exp/constraints"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Check implements the doctor.Check interface.
|
|
|
|
type Check struct{}
|
|
|
|
|
|
|
|
func (Check) Name() string {
|
|
|
|
return "permissions"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (Check) Run(_ context.Context, logf logger.Logf) error {
|
|
|
|
return permissionsImpl(logf)
|
|
|
|
}
|
|
|
|
|
2023-12-22 01:40:03 +00:00
|
|
|
//lint:ignore U1000 used in non-windows implementations.
|
2023-03-29 16:27:12 +01:00
|
|
|
func formatUserID[T constraints.Integer](id T) string {
|
|
|
|
idStr := fmt.Sprint(id)
|
|
|
|
if uu, err := user.LookupId(idStr); err != nil {
|
|
|
|
return idStr + "(<unknown>)"
|
|
|
|
} else {
|
|
|
|
return fmt.Sprintf("%s(%q)", idStr, uu.Username)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-22 01:40:03 +00:00
|
|
|
//lint:ignore U1000 used in non-windows implementations.
|
2023-03-29 16:27:12 +01:00
|
|
|
func formatGroupID[T constraints.Integer](id T) string {
|
|
|
|
idStr := fmt.Sprint(id)
|
|
|
|
if g, err := user.LookupGroupId(idStr); err != nil {
|
|
|
|
return idStr + "(<unknown>)"
|
|
|
|
} else {
|
|
|
|
return fmt.Sprintf("%s(%q)", idStr, g.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-22 01:40:03 +00:00
|
|
|
//lint:ignore U1000 used in non-windows implementations.
|
2023-03-29 16:27:12 +01:00
|
|
|
func formatGroups[T constraints.Integer](groups []T) string {
|
|
|
|
var buf strings.Builder
|
|
|
|
for i, group := range groups {
|
|
|
|
if i > 0 {
|
|
|
|
buf.WriteByte(',')
|
|
|
|
}
|
|
|
|
buf.WriteString(formatGroupID(group))
|
|
|
|
}
|
|
|
|
return buf.String()
|
|
|
|
}
|