mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-29 12:32:24 +00:00

We have a lot of access checks spread around the ipnserver, ipnlocal, localapi, and ipnauth packages, with a significant number of platform-specific checks that are used exclusively on either Windows or Unix-like platforms. Additionally, with the exception of a few Windows-specific checks, most of these checks are per-device rather than per-profile, which is not always correct even on single-user/single-session environments, but even more problematic on multi-user/multi-session environments such as Windows. We initially attempted to map all possible operations onto the permitRead/permitWrite access flags. However, these flags are not utilized on Windows and prove insufficient on Unix machines. Specifically, on Windows, the first user to connect is granted full access, while subsequent logged-in users have no access to the LocalAPI at all. This restriction applies regardless of the environment, local user roles (e.g., whether a Windows user is a local admin), or whether they are the active user on a shared Windows client device. Conversely, on Unix, we introduced the permitCert flag to enable granting non-root web servers (such as www-data, caddy, nginx, etc.) access to certificates. We also added additional access check to distinguish local admins (root on Unix-like platforms, elevated admins on Windows) from users with permitWrite access, and used it as a fix for the serve path LPE. A more fine-grained access control system could better suit our current and future needs, especially in improving the UX across various scenarios on corporate and personal Windows devices. This adds an API surface in ipnauth that will be used in LocalBackend to check access to individual Tailscale profiles as well as any device-wide information and operations. Updates tailscale/corp#18342 Signed-off-by: Nick Khyl <nickk@tailscale.com>
108 lines
3.4 KiB
Go
108 lines
3.4 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package ipn
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
)
|
|
|
|
// AccessDeniedError is an error due to permissions.
|
|
type AccessDeniedError struct {
|
|
// Err is the underlying error.
|
|
Err error
|
|
}
|
|
|
|
// Error returns error message.
|
|
func (e *AccessDeniedError) Error() string { return e.Err.Error() }
|
|
|
|
// Unwrap returns an underlying error.
|
|
func (e *AccessDeniedError) Unwrap() error { return e.Err }
|
|
|
|
// ToHTTPStatus returns http.StatusForbidden.
|
|
func (e *AccessDeniedError) ToHTTPStatus() int { return http.StatusForbidden }
|
|
|
|
// NotFoundError is an error due to a missing resource.
|
|
type NotFoundError struct {
|
|
// Err is the underlying error.
|
|
Err error
|
|
}
|
|
|
|
// Error returns error message.
|
|
func (e *NotFoundError) Error() string { return e.Err.Error() }
|
|
|
|
// Unwrap returns an underlying error.
|
|
func (e *NotFoundError) Unwrap() error { return e.Err }
|
|
|
|
// ToHTTPStatus returns http.StatusNotFound.
|
|
func (e *NotFoundError) ToHTTPStatus() int { return http.StatusNotFound }
|
|
|
|
// BadArgsError is an error due to bad arguments.
|
|
type BadArgsError struct {
|
|
// Err is the underlying error.
|
|
Err error
|
|
}
|
|
|
|
// Error returns error message.
|
|
func (e *BadArgsError) Error() string { return e.Err.Error() }
|
|
|
|
// Unwrap returns an underlying error.
|
|
func (e *BadArgsError) Unwrap() error { return e.Err }
|
|
|
|
// ToHTTPStatus returns http.StatusBadRequest.
|
|
func (e *BadArgsError) ToHTTPStatus() int { return http.StatusBadRequest }
|
|
|
|
// ServiceUnavailableError is an error that can be represented by http.StatusServiceUnavailable.
|
|
type ServiceUnavailableError struct {
|
|
Err error // Err is the underlying error.
|
|
}
|
|
|
|
// Error returns error message.
|
|
func (e *ServiceUnavailableError) Error() string { return e.Err.Error() }
|
|
|
|
// Unwrap returns an underlying error.
|
|
func (e *ServiceUnavailableError) Unwrap() error { return e.Err }
|
|
|
|
// ToHTTPStatus returns http.StatusServiceUnavailable.
|
|
func (e *ServiceUnavailableError) ToHTTPStatus() int { return http.StatusServiceUnavailable }
|
|
|
|
// InternalServerError is an error that can be represented by http.StatusInternalServerError.
|
|
type InternalServerError struct {
|
|
Err error // Err is the underlying error.
|
|
}
|
|
|
|
// Error returns error message.
|
|
func (e *InternalServerError) Error() string { return e.Err.Error() }
|
|
|
|
// Unwrap returns an underlying error.
|
|
func (e *InternalServerError) Unwrap() error { return e.Err }
|
|
|
|
// ToHTTPStatus returns http.StatusInternalServerError.
|
|
func (e *InternalServerError) ToHTTPStatus() int { return http.StatusInternalServerError }
|
|
|
|
// NewAccessDeniedError returns a new AccessDeniedError with the specified text.
|
|
func NewAccessDeniedError(text string) *AccessDeniedError {
|
|
return &AccessDeniedError{errors.New(text)}
|
|
}
|
|
|
|
// NewNotFoundError returns a new NotFoundError with the specified text.
|
|
func NewNotFoundError(text string) *NotFoundError {
|
|
return &NotFoundError{errors.New(text)}
|
|
}
|
|
|
|
// NewBadArgsError returns a new BadArgsError with the specified text.
|
|
func NewBadArgsError(text string) *BadArgsError {
|
|
return &BadArgsError{errors.New(text)}
|
|
}
|
|
|
|
// NewServiceUnavailableError returns a new ServiceUnavailableError with the specified text.
|
|
func NewServiceUnavailableError(text string) *ServiceUnavailableError {
|
|
return &ServiceUnavailableError{errors.New(text)}
|
|
}
|
|
|
|
// NewInternalServerError returns a new InternalServerError with the specified text.
|
|
func NewInternalServerError(text string) *InternalServerError {
|
|
return &InternalServerError{errors.New(text)}
|
|
}
|