summaryrefslogtreecommitdiffhomepage
path: root/ipn/ipnserver
AgeCommit message (Collapse)AuthorFilesLines
2026-03-24ipn/ipnserver: use peercreds for actor.Username on freebsd (for Taildrive)rtgnx1-1/+1
Signed-off-by: Adrian Cybulski <adrian@cybulski.cc>
2026-03-23safesocket, ipn/ipnserver: use PeerCreds on solaris and illumosNahum Shalman1-1/+1
Updates tailscale/peercred#10 Signed-off-by: Nahum Shalman <nahamu@gmail.com>
2026-03-05types/ptr: deprecate ptr.To, use Go 1.26 newBrad Fitzpatrick1-4/+3
Updates #18682 Change-Id: I62f6aa0de2a15ef8c1435032c6aa74a181c25f8f Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-03-05all: fix typos in commentsBrad Fitzpatrick1-1/+1
Fix its/it's, who's/whose, wether/whether, missing apostrophes in contractions, and other misspellings across the codebase. Updates #cleanup Change-Id: I20453b81a7aceaa14ea2a551abba08a2e7f0a1d8 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2026-01-23all: remove AUTHORS file and references to itWill Norris7-7/+7
This file was never truly necessary and has never actually been used in the history of Tailscale's open source releases. A Brief History of AUTHORS files --- The AUTHORS file was a pattern developed at Google, originally for Chromium, then adopted by Go and a bunch of other projects. The problem was that Chromium originally had a copyright line only recognizing Google as the copyright holder. Because Google (and most open source projects) do not require copyright assignemnt for contributions, each contributor maintains their copyright. Some large corporate contributors then tried to add their own name to the copyright line in the LICENSE file or in file headers. This quickly becomes unwieldy, and puts a tremendous burden on anyone building on top of Chromium, since the license requires that they keep all copyright lines intact. The compromise was to create an AUTHORS file that would list all of the copyright holders. The LICENSE file and source file headers would then include that list by reference, listing the copyright holder as "The Chromium Authors". This also become cumbersome to simply keep the file up to date with a high rate of new contributors. Plus it's not always obvious who the copyright holder is. Sometimes it is the individual making the contribution, but many times it may be their employer. There is no way for the proejct maintainer to know. Eventually, Google changed their policy to no longer recommend trying to keep the AUTHORS file up to date proactively, and instead to only add to it when requested: https://opensource.google/docs/releasing/authors. They are also clear that: > Adding contributors to the AUTHORS file is entirely within the > project's discretion and has no implications for copyright ownership. It was primarily added to appease a small number of large contributors that insisted that they be recognized as copyright holders (which was entirely their right to do). But it's not truly necessary, and not even the most accurate way of identifying contributors and/or copyright holders. In practice, we've never added anyone to our AUTHORS file. It only lists Tailscale, so it's not really serving any purpose. It also causes confusion because Tailscalars put the "Tailscale Inc & AUTHORS" header in other open source repos which don't actually have an AUTHORS file, so it's ambiguous what that means. Instead, we just acknowledge that the contributors to Tailscale (whoever they are) are copyright holders for their individual contributions. We also have the benefit of using the DCO (developercertificate.org) which provides some additional certification of their right to make the contribution. The source file changes were purely mechanical with: git ls-files | xargs sed -i -e 's/\(Tailscale Inc &\) AUTHORS/\1 contributors/g' Updates #cleanup Change-Id: Ia101a4a3005adb9118051b3416f5a64a4a45987d Signed-off-by: Will Norris <will@tailscale.com>
2025-10-02feature/featuretags, all: add build features, use existing ones in more placesBrad Fitzpatrick3-0/+29
Saves 270 KB. Updates #12614 Change-Id: I4c3fe06d32c49edb3a4bb0758a8617d83f291cf5 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-09-29feature/sdnotify: move util/systemd to a modular featureBrad Fitzpatrick1-2/+4
Updates #12614 Change-Id: I08e714c83b455df7f538cc99cafe940db936b480 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-09-25various: allow tailscaled shutdown via LocalAPINick Khyl2-2/+71
A customer wants to allow their employees to restart tailscaled at will, when access rights and MDM policy allow it, as a way to fully reset client state and re-create the tunnel in case of connectivity issues. On Windows, the main tailscaled process runs as a child of a service process. The service restarts the child when it exits (or crashes) until the service itself is stopped. Regular (non-admin) users can't stop the service, and allowing them to do so isn't ideal, especially in managed or multi-user environments. In this PR, we add a LocalAPI endpoint that instructs ipnserver.Server, and by extension the tailscaled process, to shut down. The service then restarts the child tailscaled. Shutting down tailscaled requires LocalAPI write access and an enabled policy setting. Updates tailscale/corp#32674 Updates tailscale/corp#32675 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-09-21ipn/ipnauth: don't crash on OpenBSD trying to log username of unknown peerBrad Fitzpatrick1-1/+5
We never implemented the peercred package on OpenBSD (and I just tried again and failed), but we've always documented that the creds pointer can be nil for operating systems where we can't map the unix socket back to its UID. On those platforms, we set the default unix socket permissions such that only the admin can open it anyway and we don't have a read-only vs read-write distinction. OpenBSD was always in that camp, where any access to Tailscale's unix socket meant full access. But during some refactoring, we broke OpenBSD in that we started assuming during one logging path (during login) that Creds was non-nil when looking up an ipnauth.Actor's username, which wasn't relevant (it was called from a function "maybeUsernameOf" anyway, which threw away errors). Verified on an OpenBSD VM. We don't have any OpenBSD integration tests yet. Fixes #17209 Updates #17221 Change-Id: I473c5903dfaa645694bcc75e7f5d484f3dd6044d Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-08-18ipn/localapi: plumb an event bus through the localapi.Handler (#16892)M. J. Fromberger1-1/+7
Some of the operations of the local API need an event bus to correctly instantiate other components (notably including the portmapper). This commit adds that, and as the parameter list is starting to get a bit long and hard to read, I took the opportunity to move the arguments to a config type. Only a few call sites needed to be updated and this API is not intended for general use, so I did not bother to stage the change. Updates #15160 Updates #16842 Change-Id: I7b057d71161bd859f5acb96e2f878a34c85be0ef Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-06-17ipn: add missing entries for OpenBSDJuan Francisco Cantero Hurtado1-1/+1
Signed-off-by: Juan Francisco Cantero Hurtado <jfch@30041993.xyz>
2025-05-09ipn/ipn{server,test}: extract the LocalAPI test client and server into ipntestNick Khyl4-335/+138
In this PR, we extract the in-process LocalAPI client/server implementation from ipn/ipnserver/server_test.go into a new ipntest package to be used in high‑level black‑box tests, such as those for the tailscale CLI. Updates #15575 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-16net/netmon: publish events to event busDavid Anderson1-1/+1
Updates #15160 Signed-off-by: David Anderson <dave@tailscale.com>
2025-04-16all: update the tsd.System constructor name (#15372)M. J. Fromberger1-1/+1
Replace NewSystemWithEventBus with plain NewSystem, and update all usage. See https://github.com/tailscale/tailscale/pull/15355#discussion_r2003910766 Updates #15160 Change-Id: I64d337f09576b41d9ad78eba301a74b9a9d6ebf4 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-04-16all: construct new System values with an event bus pre-populatedM. J. Fromberger1-1/+1
Although, at the moment, we do not yet require an event bus to be present, as we start to add more pieces we will want to ensure it is always available. Add a new constructor and replace existing uses of new(tsd.System) throughout. Update generated files for import changes. Updates #15160 Change-Id: Ie5460985571ade87b8eac8b416948c7f49f0f64b Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
2025-04-02ipn/ipnserver: treat all plan9 safesocket connections as permittedBrad Fitzpatrick1-1/+1
Updates #5794 Change-Id: Ibf74d017e38e0713d19bef437f26685280d79f6f Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-02-14various: keep tailscale connected when Always On mode is enabled on WindowsNick Khyl1-0/+1
In this PR, we enable the registration of LocalBackend extensions to exclude code specific to certain platforms or environments. We then introduce desktopSessionsExt, which is included only in Windows builds and only if the ts_omit_desktop_sessions tag is disabled for the build. This extension tracks desktop sessions and switches to (or remains on) the appropriate profile when a user signs in or out, locks their screen, or disconnects a remote session. As desktopSessionsExt requires an ipn/desktop.SessionManager, we register it with tsd.System for the tailscaled subprocess on Windows. We also fix a bug in the sessionWatcher implementation where it attempts to close a nil channel on stop. Updates #14823 Updates tailscale/corp#26247 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-12ipn/ipn{local,server}: extract logic that determines the "best" Tailscale ↵Nick Khyl1-2/+10
profile to use In this PR, we further refactor LocalBackend and Unattended Mode to extract the logic that determines which profile should be used at the time of the check, such as when a LocalAPI client connects or disconnects. We then update (*LocalBackend).switchProfileLockedOnEntry to to switch to the profile returned by (*LocalBackend).resolveBestProfileLocked() rather than to the caller-specified specified profile, and rename it to switchToBestProfileLockedOnEntry. This is done in preparation for updating (*LocalBackend).getBackgroundProfileIDLocked to support Always-On mode by determining which profile to use based on which users, if any, are currently logged in and have an active foreground desktop session. Updates #14823 Updates tailscale/corp#26247 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-11ipn/ipn{local,server}: move "staying alive in server mode" from ipnserver to ↵Nick Khyl1-14/+2
LocalBackend Currently, we disconnect Tailscale and reset LocalBackend on Windows when the last LocalAPI client disconnects, unless Unattended Mode is enabled for the current profile. And the implementation is somewhat racy since the current profile could theoretically change after (*ipnserver.Server).addActiveHTTPRequest checks (*LocalBackend).InServerMode() and before it calls (*LocalBackend).SetCurrentUser(nil) (or, previously, (*LocalBackend).ResetForClientDisconnect). Additionally, we might want to keep Tailscale running and connected while a user is logged in rather than tying it to whether a LocalAPI client is connected (i.e., while the GUI is running), even when Unattended Mode is disabled for a profile. This includes scenarios where the new AlwaysOn mode is enabled, as well as when Tailscale is used on headless Windows editions, such as Windows Server Core, where the GUI is not supported. It may also be desirable to switch to the "background" profile when a user logs off from their device or implement other similar features. To facilitate these improvements, we move the logic from ipnserver.Server to ipnlocal.LocalBackend, where it determines whether to keep Tailscale running when the current user disconnects. We also update the logic that determines whether a connection should be allowed to better reflect the fact that, currently, LocalAPI connections are not allowed unless: - the current UID is "", meaning that either we are not on a multi-user system or Tailscale is idle; - the LocalAPI client belongs to the current user (their UIDs are the same); - the LocalAPI client is Local System (special case; Local System is always allowed). Whether Unattended Mode is enabled only affects the error message returned to the Local API client when the connection is denied. Updates #14823 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-11ipn/ipn{auth,server}: update ipnauth.Actor to carry a contextNick Khyl1-0/+3
The context carries additional information about the actor, such as the request reason, and is canceled when the actor is done. Additionally, we implement three new ipn.Actor types that wrap other actors to modify their behavior: - WithRequestReason, which adds a request reason to the actor; - WithoutClose, which narrows the actor's interface to prevent it from being closed; - WithPolicyChecks, which adds policy checks to the actor's CheckProfileAccess method. Updates #14823 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-10ipn/ipn{local,server}: remove ResetForClientDisconnect in favor of ↵Nick Khyl1-1/+1
SetCurrentUser(nil) There’s (*LocalBackend).ResetForClientDisconnect, and there’s also (*LocalBackend).resetForProfileChangeLockedOnEntry. Both methods essentially did the same thing but in slightly different ways. For example, resetForProfileChangeLockedOnEntry didn’t reset the control client until (*LocalBackend).Start() was called at the very end and didn’t reset the keyExpired flag, while ResetForClientDisconnect didn’t reinitialize TKA. Since SetCurrentUser can be called with a nil argument to reset the currently connected user and internally calls resetForProfileChangeLockedOnEntry, we can remove ResetForClientDisconnect and let SetCurrentUser and resetForProfileChangeLockedOnEntry handle it. Updates #14823 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-06safesocket: add ability for Darwin clients to set explicit credentials (#14702)Jonathan Nobels1-0/+7
updates tailscale/corp#25687 The darwin appstore and standalone clients now support XPC and the keychain for passing user credentials securely between the gui process and an NEVPNExtension hosted tailscaled. Clients that can communicate directly with the network extension, via XPC or the keychain, are now expected to call SetCredentials and supply credentials explicitly, fixing issues with the cli breaking if the current user cannot read the contents of /Library/Tailscale due to group membership restrictions. This matches how those clients source and supply credentials to the localAPI http client. Non-platform-specific code that has traditionally been in the client is moved to safesocket. /Libraray/Tailscaled/sameuserproof has its permissions changed to that it's readably only by users in the admin group. This restricts standalone CLI access for and direct use of localAPI to admins. Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
2025-02-05all: use new LocalAPI client package locationBrad Fitzpatrick1-9/+10
It was moved in f57fa3cbc30e. Updates tailscale/corp#22748 Change-Id: I19f965e6bded1d4c919310aa5b864f2de0cd6220 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-02-04ipn/{ipnserver,localapi},tsnet: use ipnauth.Self as the actor in tsnet ↵Nick Khyl1-7/+7
localapi handlers With #14843 merged, (*localapi.Handler).servePrefs() now requires a non-nil actor, and other places may soon require it as well. In this PR, we update localapi.NewHandler with a new required parameter for the actor. We then update tsnet to use ipnauth.Self. We also rearrange the code in (*ipnserver.Server).serveHTTP() to pass the actor via Handler's constructor instead of the field. Updates #14823 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-04ipn/{ipnauth,ipnlocal,ipnserver}: move the AlwaysOn policy check from ↵Nick Khyl1-14/+3
ipnserver to ipnauth In this PR, we move the code that checks the AlwaysOn policy from ipnserver.actor to ipnauth. It is intended to be used by ipnauth.Actor implementations, and we temporarily make it exported while these implementations reside in ipnserver and in corp. We'll unexport it later. We also update [ipnauth.Actor.CheckProfileAccess] to accept an auditLogger, which is called to write details about the action to the audit log when required by the policy, and update LocalBackend.EditPrefsAs to use an auditLogger that writes to the regular backend log. Updates tailscale/corp#26146 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-02-01client/tailscale,ipn/ipn{local,server},util/syspolicy: implement the ↵Nick Khyl2-7/+45
AlwaysOn.OverrideWithReason policy setting In this PR, we update client/tailscale.LocalClient to allow sending requests with an optional X-Tailscale-Reason header. We then update ipn/ipnserver.{actor,Server} to retrieve this reason, if specified, and use it to determine whether ipnauth.Disconnect is allowed when the AlwaysOn.OverrideWithReason policy setting is enabled. For now, we log the reason, along with the profile and OS username, to the backend log. Finally, we update LocalBackend to remember when a disconnect was permitted and do not reconnect automatically unless the policy changes. Updates tailscale/corp#26146 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-31ipn/ipn{auth,server,local}: initial support for the always-on modeNick Khyl1-1/+12
In this PR, we update LocalBackend to set WantRunning=true when applying policy settings to the current profile's prefs, if the "always-on" mode is enabled. We also implement a new (*LocalBackend).EditPrefsAs() method, which is like EditPrefs but accepts an actor (e.g., a LocalAPI client's identity) that initiated the change. If WantRunning is being set to false, the new EditPrefsAs method checks whether the actor has ipnauth.Disconnect access to the profile and propagates an error if they do not. Finally, we update (*ipnserver.actor).CheckProfileAccess to allow a disconnect only if the "always-on" mode is not enabled by the AlwaysOn policy setting. This is not a comprehensive solution to the "always-on" mode across platforms, as instead of disconnecting a user could achieve the same effect by creating a new empty profile, initiating a reauth, or by deleting the profile. These are the things we should address in future PRs. Updates #14823 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-31ipn/{ipnauth, ipnserver}: extend the ipnauth.Actor interface with a ↵Nick Khyl1-0/+8
CheckProfileAccess method The implementations define it to verify whether the actor has the requested access to a login profile. Updates #14823 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-15ipn/ipnserver: fix a deadlock in (*Server).blockWhileIdentityInUseNick Khyl2-1/+58
If the server was in use at the time of the initial check, but disconnected and was removed from the activeReqs map by the time we registered a waiter, the ready channel will never be closed, resulting in a deadlock. To avoid this, we check whether the server is still busy after registering the wait. Fixes #14655 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-15ipn/ipnserver: fix TestConcurrentOSUserSwitchingOnWindowsNick Khyl1-1/+14
I made a last-minute change in #14626 to split a single loop that created 1_000 concurrent connections into an inner and outer loop that create 100 concurrent connections 10 times. This introduced a race because the last user's connection may still be active (from the server's perspective) when a new outer iteration begins. Since every new client gets a unique ClientID, but we reuse usernames and UIDs, the server may let a user in (as the UID matches, which is fine), but the test might then fail due to a ClientID mismatch: server_test.go:232: CurrentUser(Initial): got &{S-1-5-21-1-0-0-1001 User-4 <nil> Client-2 false false}; want &{S-1-5-21-1-0-0-1001 User-4 <nil> Client-114 false false} In this PR, we update (*testIPNServer).blockWhileInUse to check whether the server is currently busy and wait until it frees up. We then call blockWhileInUse at the end of each outer iteration so that the server is always in a known idle state at the beginning of the inner loop. We also check that the current user is not set when the server is idle. Updates tailscale/corp#25804 Updates #14655 (found when working on it) Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-14ipn/ipnserver: fix race condition where LocalBackend is reset after a ↵Nick Khyl2-8/+74
different user connects In this commit, we add a failing test to verify that ipn/ipnserver.Server correctly sets and unsets the current user when two different clients send requests concurrently (A sends request, B sends request, A's request completes, B's request completes). The expectation is that the user who wins the race becomes the current user from the LocalBackend's perspective, remaining in this state until they disconnect, after which a different user should be able to connect and use the LocalBackend. We then fix the second of two bugs in (*Server).addActiveHTTPRequest, where a race condition causes the LocalBackend's state to be reset after a new client connects, instead of after the last active request of the previous client completes and the server becomes idle. Fixes tailscale/corp#25804 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-14ipn/{ipnlocal,ipnserver}: remove redundant ↵Nick Khyl2-22/+30
(*LocalBackend).ResetForClientDisconnect In this commit, we add a failing test to verify that ipn/ipnserver.Server correctly sets and unsets the current user when two different users connect sequentially (A connects, A disconnects, B connects, B disconnects). We then fix the test by updating (*ipn/ipnserver.Server).addActiveHTTPRequest to avoid calling (*LocalBackend).ResetForClientDisconnect again after a new user has connected and been set as the current user with (*LocalBackend).SetCurrentUser(). Since ipn/ipnserver.Server does not allow simultaneous connections from different Windows users and relies on the LocalBackend's current user, and since we already reset the LocalBackend's state by calling ResetForClientDisconnect when the last active request completes (indicating the server is idle and can accept connections from any Windows user), it is unnecessary to track the last connected user on the ipnserver.Server side or call ResetForClientDisconnect again when the user changes. Additionally, the second call to ResetForClientDisconnect occurs after the new user has been set as the current user, resetting the correct state for the new user instead of the old state of the now-disconnected user, causing issues. Updates tailscale/corp#25804 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-14ipn/{ipnauth,ipnlocal,ipnserver}, client/tailscale: make ipnserver.Server ↵Nick Khyl1-0/+358
testable We update client/tailscale.LocalClient to allow specifying an optional Transport (http.RoundTripper) for LocalAPI HTTP requests, and implement one that injects an ipnauth.TestActor via request headers. We also add several functions and types to make testing an ipn/ipnserver.Server possible (or at least easier). We then use these updates to write basic tests for ipnserver.Server, ensuring it works on non-Windows platforms and correctly sets and unsets the LocalBackend's current user when a Windows user connects and disconnects. We intentionally omit tests for switching between different OS users and will add them in follow-up commits. Updates tailscale/corp#25804 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-14ipn/ipnserver: use ipnauth.Actor instead of *ipnserver.actor whenever possibleNick Khyl2-12/+20
In preparation for adding test coverage for ipn/ipnserver.Server, we update it to use ipnauth.Actor instead of its concrete implementation where possible. Updates tailscale/corp#25804 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-01-09all: illumos/solaris userspace only supportNahum Shalman1-1/+1
Updates #14565 Change-Id: I743148144938794db0a224873ce76c10dbe6fa5f Signed-off-by: Nahum Shalman <nahamu@gmail.com>
2024-12-16Switch logging service from log.tailscale.io to log.tailscale.com (#14398)Joe Tsai1-1/+1
Updates tailscale/corp#23617 Signed-off-by: Joe Tsai <joetsai@digital-static.net>
2024-10-18ipn/{ipnauth,ipnlocal,ipnserver}: send the auth URL to the user who started ↵Nick Khyl1-1/+22
interactive login We add the ClientID() method to the ipnauth.Actor interface and updated ipnserver.actor to implement it. This method returns a unique ID of the connected client if the actor represents one. It helps link a series of interactions initiated by the client, such as when a notification needs to be sent back to a specific session, rather than all active sessions, in response to a certain request. We also add LocalBackend.WatchNotificationsAs and LocalBackend.StartLoginInteractiveAs methods, which are like WatchNotifications and StartLoginInteractive but accept an additional parameter specifying an ipnauth.Actor who initiates the operation. We store these actor identities in watchSession.owner and LocalBackend.authActor, respectively,and implement LocalBackend.sendTo and related helper methods to enable sending notifications to watchSessions associated with actors (or, more broadly, identifiable recipients). We then use the above to change who receives the BrowseToURL notifications: - For user-initiated, interactive logins, the notification is delivered only to the user who initiated the process. If the initiating actor represents a specific connected client, the URL notification is sent back to the same LocalAPI client that called StartLoginInteractive. Otherwise, the notification is sent to all clients connected as that user. Currently, we only differentiate between users on Windows, as it is inherently a multi-user OS. - In all other cases (e.g., node key expiration), we send the notification to all connected users. Updates tailscale/corp#18342 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2024-09-05ipn/ipnserver: remove IdleTimeoutNick Khyl1-10/+1
We no longer need this on Windows, and it was never required on other platforms. It just results in more short-lived connections unless we use HTTP/2. Updates tailscale/corp#18342 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2024-08-28ipn/{ipnauth,ipnlocal,ipnserver,localapi}: start baby step toward moving ↵Nick Khyl2-79/+241
access checks from the localapi.Handler to the LocalBackend Currently, we use PermitRead/PermitWrite/PermitCert permission flags to determine which operations are allowed for a LocalAPI client. These checks are performed when localapi.Handler handles a request. Additionally, certain operations (e.g., changing the serve config) requires the connected user to be a local admin. This approach is inherently racey and is subject to TOCTOU issues. We consider it to be more critical on Windows environments, which are inherently multi-user, and therefore we prevent more than one OS user from connecting and utilizing the LocalBackend at the same time. However, the same type of issues is also applicable to other platforms when switching between profiles that have different OperatorUser values in ipn.Prefs. We'd like to allow more than one Windows user to connect, but limit what they can see and do based on their access rights on the device (e.g., an local admin or not) and to the currently active LoginProfile (e.g., owner/operator or not), while preventing TOCTOU issues on Windows and other platforms. Therefore, we'd like to pass an actor from the LocalAPI to the LocalBackend to represent the user performing the operation. The LocalBackend, or the profileManager down the line, will then check the actor's access rights to perform a given operation on the device and against the current (and/or the target) profile. This PR does not change the current permission model in any way, but it introduces the concept of an actor and includes some preparatory work to pass it around. Temporarily, the ipnauth.Actor interface has methods like IsLocalSystem and IsLocalAdmin, which are only relevant to the current permission model. It also lacks methods that will actually be used in the new model. We'll be adding these gradually in the next PRs and removing the deprecated methods and the Permit* flags at the end of the transition. Updates tailscale/corp#18342 Signed-off-by: Nick Khyl <nickk@tailscale.com>
2024-07-10all: add test for package comments, fix, add comments as neededBrad Fitzpatrick1-0/+2
Updates #cleanup Change-Id: Ic4304e909d2131a95a38b26911f49e7b1729aaef Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-05-07ipn/ipnserver: close a small race in ipnserver, ~simplify codeBrad Fitzpatrick1-23/+2
There was a small window in ipnserver after we assigned a LocalBackend to the ipnserver's atomic but before we Start'ed it where our initalization Start could conflict with API calls from the LocalAPI. Simplify that a bit and lay out the rules in the docs. Updates #12028 Change-Id: Ic5f5e4861e26340599184e20e308e709edec68b1 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-04-26ipn/{ipnlocal,localapi},wgengine{,/magicsock}: plumb health.TrackerBrad Fitzpatrick1-1/+1
Down to 25 health.Global users. After this remains controlclient & net/dns & wgengine/router. Updates #11874 Updates #4136 Change-Id: I6dd1856e3d9bf523bdd44b60fb3b8f7501d5dc0d Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-04-16all: use Go 1.22 range-over-intBrad Fitzpatrick1-1/+1
Updates #11058 Change-Id: I35e7ef9b90e83cac04ca93fd964ad00ed5b48430 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-01-12ipn/ipnserver: always allow Windows SYSTEM user to connectWill Norris1-2/+10
When establishing connections to the ipnserver, we validate that the local user is allowed to connect. If Tailscale is currently being managed by a different user (primarily for multi-user Windows installs), we don't allow the connection. With the new device web UI, the inbound connection is coming from tailscaled itself, which is often running as "NT AUTHORITY\SYSTEM". In this case, we still want to allow the connection, even though it doesn't match the user running the Tailscale GUI. The SYSTEM user has full access to everything on the system anyway, so this doesn't escalate privileges. Eventually, we want the device web UI to run outside of the tailscaled process, at which point this exception would probably not be needed. Updates tailscale/corp#16393 Signed-off-by: Will Norris <will@tailscale.com>
2023-12-05all: fix nilness issuesMatt Layher1-1/+1
Signed-off-by: Matt Layher <mdlayher@gmail.com>
2023-11-09ipn/localapi: only perform local-admin check in serveServeConfig (#10163)Andrew Lytvynov1-59/+1
On unix systems, the check involves executing sudo, which is slow. Instead of doing it for every incoming request, move the logic into localapi serveServeConfig handler and do it as needed. Updates tailscale/corp#15405 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
2023-11-07ipn/localapi: require root or sudo+operator access for SetServeConfig (#10142)Andrew Lytvynov1-7/+46
For an operator user, require them to be able to `sudo tailscale` to use `tailscale serve`. This is similar to the Windows elevated token check. Updates tailscale/corp#15405 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
2023-11-03ipn/ipnauth: improve the Windows token administrator checkAaron Klotz1-8/+2
(*Token).IsAdministrator is supposed to return true even when the user is running with a UAC limited token. The idea is that, for the purposes of this check, we don't care whether the user is *currently* running with full Admin rights, we just want to know whether the user can *potentially* do so. We accomplish this by querying for the token's "linked token," which should be the fully-elevated variant, and checking its group memberships. We also switch ipn/ipnserver/(*Server).connIsLocalAdmin to use the elevation check to preserve those semantics for tailscale serve; I want the IsAdministrator check to be used for less sensitive things like toggling auto-update on and off. Fixes #10036 Signed-off-by: Aaron Klotz <aaron@tailscale.com>
2023-10-26ipn, safesocket: use Windows token in LocalAPIAaron Klotz1-9/+68
On Windows, the idiomatic way to check access on a named pipe is for the server to impersonate the client on its current OS thread, perform access checks using the client's access token, and then revert the OS thread's access token back to its true self. The access token is a better representation of the client's rights than just a username/userid check, as it represents the client's effective rights at connection time, which might differ from their normal rights. This patch updates safesocket to do the aforementioned impersonation, extract the token handle, and then revert the impersonation. We retain the token handle for the remaining duration of the connection (the token continues to be valid even after we have reverted back to self). Since the token is a property of the connection, I changed ipnauth to wrap the concrete net.Conn to include the token. I then plumbed that change through ipnlocal, ipnserver, and localapi as necessary. I also added a PermitLocalAdmin flag to the localapi Handler which I intend to use for controlling access to a few new localapi endpoints intended for configuring auto-update. Updates https://github.com/tailscale/tailscale/issues/755 Signed-off-by: Aaron Klotz <aaron@tailscale.com>
2023-07-10logpolicy, various: allow overriding log functionAndrew Dunham1-1/+1
This allows sending logs from the "logpolicy" package (and associated callees) to something other than the log package. The behaviour for tailscaled remains the same, passing in log.Printf Updates #8249 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: Ie1d43b75fa7281933d9225bffd388462c08a5f31