diff --git a/client/tailscale/tailscale.go b/client/tailscale/tailscale.go index 9f2811250daca..74bf7e148645d 100644 --- a/client/tailscale/tailscale.go +++ b/client/tailscale/tailscale.go @@ -104,6 +104,10 @@ func doLocalRequestNiceError(req *http.Request) (*http.Response, error) { if server := res.Header.Get("Tailscale-Version"); server != "" && server != version.Long && onVersionMismatch != nil { onVersionMismatch(version.Long, server) } + if res.StatusCode == 403 { + all, _ := ioutil.ReadAll(res.Body) + return nil, &AccessDeniedError{errors.New(errorMessageFromBody(all))} + } return res, nil } if ue, ok := err.(*url.Error); ok { @@ -179,10 +183,6 @@ func send(ctx context.Context, method, path string, wantStatus int, body io.Read return nil, err } if res.StatusCode != wantStatus { - if res.StatusCode == 403 { - return nil, &AccessDeniedError{errors.New(errorMessageFromBody(slurp))} - } - err := fmt.Errorf("HTTP %s: %s (expected %v)", res.Status, slurp, wantStatus) return nil, bestError(err, slurp) } return slurp, nil @@ -294,7 +294,7 @@ func GetWaitingFile(ctx context.Context, baseName string) (rc io.ReadCloser, siz if err != nil { return nil, 0, err } - res, err := DoLocalRequest(req) + res, err := doLocalRequestNiceError(req) if err != nil { return nil, 0, err } @@ -343,7 +343,7 @@ func PushFile(ctx context.Context, target tailcfg.StableNodeID, size int64, name return nil } all, _ := io.ReadAll(res.Body) - return fmt.Errorf("%s: %s", res.Status, all) + return bestError(fmt.Errorf("%s: %s", res.Status, all), all) } func CheckIPForwarding(ctx context.Context) error { diff --git a/cmd/tailscale/cli/cert.go b/cmd/tailscale/cli/cert.go index 1cb7d3ba40ee7..38007c173f7c5 100644 --- a/cmd/tailscale/cli/cert.go +++ b/cmd/tailscale/cli/cert.go @@ -13,7 +13,6 @@ import ( "log" "net/http" "os" - "runtime" "strings" "github.com/peterbourgon/ff/v3/ffcli" @@ -92,9 +91,6 @@ func runCert(ctx context.Context, args []string) error { certArgs.keyFile = domain + ".key" } certPEM, keyPEM, err := tailscale.CertPair(ctx, domain) - if tailscale.IsAccessDeniedError(err) && os.Getuid() != 0 && runtime.GOOS != "windows" { - return fmt.Errorf("%v\n\nUse 'sudo tailscale cert' or 'tailscale up --operator=$USER' to not require root.", err) - } if err != nil { return err } diff --git a/cmd/tailscale/cli/cli.go b/cmd/tailscale/cli/cli.go index 2943047860397..a049b7291d481 100644 --- a/cmd/tailscale/cli/cli.go +++ b/cmd/tailscale/cli/cli.go @@ -171,6 +171,9 @@ change in the future. }) err := rootCmd.Run(context.Background()) + if tailscale.IsAccessDeniedError(err) && os.Getuid() != 0 && runtime.GOOS != "windows" { + return fmt.Errorf("%v\n\nUse 'sudo tailscale %s' or 'tailscale up --operator=$USER' to not require root.", err, strings.Join(args, " ")) + } if errors.Is(err, flag.ErrHelp) { return nil } diff --git a/cmd/tailscale/cli/file.go b/cmd/tailscale/cli/file.go index 64bde3134f733..84f7da8c220dd 100644 --- a/cmd/tailscale/cli/file.go +++ b/cmd/tailscale/cli/file.go @@ -324,7 +324,7 @@ func runFileGet(ctx context.Context, args []string) error { for { wfs, err = tailscale.WaitingFiles(ctx) if err != nil { - return fmt.Errorf("getting WaitingFiles: %v", err) + return fmt.Errorf("getting WaitingFiles: %w", err) } if len(wfs) != 0 || !getArgs.wait { break @@ -379,7 +379,7 @@ func wipeInbox(ctx context.Context) error { } wfs, err := tailscale.WaitingFiles(ctx) if err != nil { - return fmt.Errorf("getting WaitingFiles: %v", err) + return fmt.Errorf("getting WaitingFiles: %w", err) } deleted := 0 for _, wf := range wfs {