diff --git a/browsergateway/rdp.go b/browsergateway/rdp.go index 1df5a13..120de59 100644 --- a/browsergateway/rdp.go +++ b/browsergateway/rdp.go @@ -7,13 +7,13 @@ import ( "errors" "fmt" "io" - "log" "net" "net/http" "strconv" "time" "github.com/coder/websocket" + "github.com/fosrl/newt/logger" ) // HandleRDP is an http.HandlerFunc for RDP-over-WebSocket connections. @@ -24,7 +24,7 @@ func (g *Gateway) HandleRDP(w http.ResponseWriter, r *http.Request) { Subprotocols: []string{"binary"}, }) if err != nil { - log.Printf("websocket upgrade failed: %v", err) + logger.Debug("websocket upgrade failed: %v", err) return } // Disable per-message read size cap (default is 32 KiB which would break @@ -33,7 +33,7 @@ func (g *Gateway) HandleRDP(w http.ResponseWriter, r *http.Request) { defer ws.CloseNow() //nolint:errcheck if err := g.serveSession(ctx, ws); err != nil { - log.Printf("session error: %v", err) + logger.Debug("session error: %v", err) } } @@ -71,7 +71,7 @@ func (g *Gateway) serveSession(ctx context.Context, ws *websocket.Conn) error { return fmt.Errorf("RDP destination %s is not in the allowed target list or auth token mismatch", target) } - log.Printf("Connecting to RDP server %s", target) + logger.Debug("Connecting to RDP server %s", target) // -- Open TCP connection to the destination RDP server -- serverTCP, err := net.DialTimeout("tcp", target, 15*time.Second) @@ -128,7 +128,7 @@ func (g *Gateway) serveSession(ctx context.Context, ws *websocket.Conn) error { if err := tlsConn.Handshake(); err != nil { return fmt.Errorf("TLS handshake with server: %w", err) } - log.Printf("Server TLS handshake OK (version=0x%04x cipher=0x%04x)", + logger.Debug("Server TLS handshake OK (version=0x%04x cipher=0x%04x)", tlsConn.ConnectionState().Version, tlsConn.ConnectionState().CipherSuite) // Collect the raw DER server certificate chain to return to the client. @@ -150,7 +150,7 @@ func (g *Gateway) serveSession(ctx context.Context, ws *websocket.Conn) error { return fmt.Errorf("write RDCleanPath response: %w", err) } - log.Printf("RDCleanPath handshake complete, forwarding traffic to %s", serverAddr) + logger.Debug("RDCleanPath handshake complete, forwarding traffic to %s", serverAddr) // -- Two-way blind forwarding of the (now TLS-encrypted) RDP stream -- return forward(stream, tlsConn) @@ -219,7 +219,7 @@ func readX224(r io.Reader) ([]byte, error) { // bytes 15..18 selected protocol / failure code (u32 little-endian) func logX224Negotiation(pdu []byte) { if len(pdu) < 19 { - log.Printf("X.224 response too short (%d bytes) to contain RDP negotiation", len(pdu)) + logger.Debug("X.224 response too short (%d bytes) to contain RDP negotiation", len(pdu)) return } switch pdu[11] { @@ -236,12 +236,12 @@ func logX224Negotiation(pdu []byte) { case 8: name = "HYBRID_EX" } - log.Printf("Server selected RDP protocol 0x%x (%s)", proto, name) + logger.Debug("Server selected RDP protocol 0x%x (%s)", proto, name) case 0x03: code := uint32(pdu[15]) | uint32(pdu[16])<<8 | uint32(pdu[17])<<16 | uint32(pdu[18])<<24 - log.Printf("Server returned RDP negotiation failure code 0x%x", code) + logger.Debug("Server returned RDP negotiation failure code 0x%x", code) default: - log.Printf("X.224 response has no RDP negotiation block (type=0x%02x)", pdu[11]) + logger.Debug("X.224 response has no RDP negotiation block (type=0x%02x)", pdu[11]) } } diff --git a/browsergateway/ssh.go b/browsergateway/ssh.go index 06ca9a0..6ea74c0 100644 --- a/browsergateway/ssh.go +++ b/browsergateway/ssh.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "log" "net" "net/http" "strconv" @@ -18,13 +17,13 @@ import ( // sshClientMsg is a JSON message sent from the browser to the proxy. type sshClientMsg struct { // type: "auth" | "data" | "resize" - Type string `json:"type"` - Password string `json:"password,omitempty"` // used when type="auth" - PrivateKey string `json:"privateKey,omitempty"` // used when type="auth" + Type string `json:"type"` + Password string `json:"password,omitempty"` // used when type="auth" + PrivateKey string `json:"privateKey,omitempty"` // used when type="auth" Certificate string `json:"certificate,omitempty"` // used when type="auth" - Data string `json:"data,omitempty"` // used when type="data" - Cols uint32 `json:"cols,omitempty"` // used when type="resize" - Rows uint32 `json:"rows,omitempty"` // used when type="resize" + Data string `json:"data,omitempty"` // used when type="data" + Cols uint32 `json:"cols,omitempty"` // used when type="resize" + Rows uint32 `json:"rows,omitempty"` // used when type="resize" } // sshServerMsg is a JSON message sent from the proxy back to the browser. @@ -83,7 +82,7 @@ func (g *Gateway) HandleSSH(w http.ResponseWriter, r *http.Request) { Subprotocols: []string{"ssh"}, }) if err != nil { - log.Printf("SSH websocket upgrade failed: %v", err) + logger.Debug("SSH websocket upgrade failed: %v", err) return } ws.SetReadLimit(-1) @@ -91,11 +90,11 @@ func (g *Gateway) HandleSSH(w http.ResponseWriter, r *http.Request) { if nativeSSH { if err := serveNativeSSHSession(ctx, ws, username, g.sshCreds); err != nil { - log.Printf("SSH native session error: %v", err) + logger.Debug("SSH native session error: %v", err) } } else { if err := serveSSHSession(ctx, ws, target, username, g.authToken); err != nil { - log.Printf("SSH session error: %v", err) + logger.Debug("SSH session error: %v", err) } } } @@ -130,7 +129,7 @@ func serveSSHSession(ctx context.Context, ws *websocket.Conn, target, username, sendSSHError(ctx, ws, "No authentication credentials provided") return fmt.Errorf("no auth credentials") } - log.Printf("SSH: connecting to %s as %s", target, username) + logger.Debug("SSH: connecting to %s as %s", target, username) sshCfg := &ssh.ClientConfig{ User: username, Auth: authMethods, @@ -183,7 +182,7 @@ func serveSSHSession(ctx context.Context, ws *websocket.Conn, target, username, return fmt.Errorf("ssh shell: %w", err) } - log.Printf("SSH: session established with %s", target) + logger.Debug("SSH: session established with %s", target) // -- Pump SSH stdout/stderr → WebSocket -- sessCtx, cancelSess := context.WithCancel(ctx) @@ -253,7 +252,7 @@ func serveSSHSession(ctx context.Context, ws *websocket.Conn, target, username, // sendSSHError sends an error message to the browser and logs it. func sendSSHError(ctx context.Context, ws *websocket.Conn, msg string) { - log.Printf("SSH error: %s", msg) + logger.Debug("SSH error: %s", msg) b, _ := json.Marshal(sshServerMsg{Type: "error", Error: msg}) _ = ws.Write(ctx, websocket.MessageText, b) } diff --git a/browsergateway/ssh_native.go b/browsergateway/ssh_native.go index 87adf92..6b923ed 100644 --- a/browsergateway/ssh_native.go +++ b/browsergateway/ssh_native.go @@ -6,9 +6,9 @@ import ( "context" "encoding/json" "fmt" - "log" "github.com/coder/websocket" + "github.com/fosrl/newt/logger" "github.com/fosrl/newt/nativessh" ) @@ -36,7 +36,7 @@ func serveNativeSSHSession(ctx context.Context, ws *websocket.Conn, username str return fmt.Errorf("auth for user %q: %w", username, err) } - log.Printf("SSH native: spawning shell as user %q", username) + logger.Debug("SSH native: spawning shell as user %q", username) sess, err := nativessh.NewPTYSessionAs(username) if err != nil { diff --git a/browsergateway/vnc.go b/browsergateway/vnc.go index 5d917a4..62f4065 100644 --- a/browsergateway/vnc.go +++ b/browsergateway/vnc.go @@ -3,13 +3,13 @@ package browsergateway import ( "context" "io" - "log" "net" "net/http" "strconv" "time" "github.com/coder/websocket" + "github.com/fosrl/newt/logger" ) const ( @@ -51,7 +51,7 @@ func (g *Gateway) handleVNC(w http.ResponseWriter, r *http.Request) { Subprotocols: []string{"binary", "base64"}, }) if err != nil { - log.Printf("vnc: websocket upgrade failed: %v", err) + logger.Debug("vnc: websocket upgrade failed: %v", err) return } ws.SetReadLimit(-1) @@ -59,7 +59,7 @@ func (g *Gateway) handleVNC(w http.ResponseWriter, r *http.Request) { ctx := r.Context() if err := serveVNC(ctx, ws, target); err != nil { - log.Printf("vnc: session error (%s): %v", target, err) + logger.Debug("vnc: session error (%s): %v", target, err) } } diff --git a/main.go b/main.go index 15209d1..ecdc3a6 100644 --- a/main.go +++ b/main.go @@ -1053,7 +1053,7 @@ persistent_keepalive_interval=5`, util.FixKey(privateKey.String()), util.FixKey( } else { browserGatewayStop = func() { _ = ln.Close() } go func() { - logger.Info("Browser gateway started on port %d", browsergateway.ListenPort) + logger.Debug("Browser gateway started on port %d", browsergateway.ListenPort) if startErr := browserGateway.Start(ln); startErr != nil { logger.Error("Browser gateway stopped with error: %v", startErr) } @@ -2028,7 +2028,7 @@ persistent_keepalive_interval=5`, util.FixKey(privateKey.String()), util.FixKey( } else { browserGatewayStop = func() { _ = ln.Close() } go func() { - logger.Info("Browser gateway started on port %d", browsergateway.ListenPort) + logger.Debug("Browser gateway started on port %d", browsergateway.ListenPort) if startErr := browserGateway.Start(ln); startErr != nil { logger.Error("Browser gateway stopped with error: %v", startErr) } diff --git a/nativessh/auth.go b/nativessh/auth.go index 9f9289b..6ecf4c9 100644 --- a/nativessh/auth.go +++ b/nativessh/auth.go @@ -3,13 +3,13 @@ package nativessh import ( "bufio" "fmt" - "log" "net" "os" "os/user" "path/filepath" "strings" + "github.com/fosrl/newt/logger" "golang.org/x/crypto/ssh" ) @@ -17,12 +17,12 @@ type staticConnMeta struct { user string } -func (m staticConnMeta) User() string { return m.user } -func (m staticConnMeta) SessionID() []byte { return nil } -func (m staticConnMeta) ClientVersion() []byte { return nil } -func (m staticConnMeta) ServerVersion() []byte { return nil } -func (m staticConnMeta) RemoteAddr() net.Addr { return nil } -func (m staticConnMeta) LocalAddr() net.Addr { return nil } +func (m staticConnMeta) User() string { return m.user } +func (m staticConnMeta) SessionID() []byte { return nil } +func (m staticConnMeta) ClientVersion() []byte { return nil } +func (m staticConnMeta) ServerVersion() []byte { return nil } +func (m staticConnMeta) RemoteAddr() net.Addr { return nil } +func (m staticConnMeta) LocalAddr() net.Addr { return nil } // CheckAuthorizedKeys reports whether key matches any entry in the system // user's ~/.ssh/authorized_keys file. Returns false (not an error) when the @@ -80,9 +80,9 @@ func Authenticate(username, password, privateKeyPEM string) error { // 2. SSH certificate signed by the configured CA (when provided). // 3. Password via host PAM stack. func AuthenticateWithCertificate(store *CredentialStore, username, password, privateKeyPEM, certificate string) error { - log.Printf("nativessh: authenticating user %q (hasPassword=%v, hasPrivateKey=%v)", username, password != "", privateKeyPEM != "") + logger.Debug("nativessh: authenticating user %q (hasPassword=%v, hasPrivateKey=%v)", username, password != "", privateKeyPEM != "") if !SystemUserExists(username) { - log.Printf("nativessh: user %q not found on system", username) + logger.Debug("nativessh: user %q not found on system", username) return fmt.Errorf("user %q does not exist", username) } @@ -90,35 +90,35 @@ func AuthenticateWithCertificate(store *CredentialStore, username, password, pri if privateKeyPEM != "" { parsedSigner, err := ssh.ParsePrivateKey([]byte(privateKeyPEM)) if err != nil { - log.Printf("nativessh: failed to parse private key for %q: %v", username, err) + logger.Debug("nativessh: failed to parse private key for %q: %v", username, err) } else if CheckAuthorizedKeys(username, parsedSigner.PublicKey()) { - log.Printf("nativessh: private key auth succeeded for %q", username) + logger.Debug("nativessh: private key auth succeeded for %q", username) return nil } else { signer = parsedSigner - log.Printf("nativessh: private key not in authorized_keys for %q", username) + logger.Debug("nativessh: private key not in authorized_keys for %q", username) } } if store != nil && certificate != "" { if signer == nil { - log.Printf("nativessh: certificate provided for %q but no matching private key was provided", username) + logger.Debug("nativessh: certificate provided for %q but no matching private key was provided", username) } else { pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(certificate)) if err != nil { - log.Printf("nativessh: failed to parse certificate for %q: %v", username, err) + logger.Debug("nativessh: failed to parse certificate for %q: %v", username, err) } else { cert, ok := pub.(*ssh.Certificate) if !ok { - log.Printf("nativessh: provided cert data for %q is not an SSH certificate", username) + logger.Debug("nativessh: provided cert data for %q is not an SSH certificate", username) } else if ssh.FingerprintSHA256(cert.Key) != ssh.FingerprintSHA256(signer.PublicKey()) { - log.Printf("nativessh: certificate key mismatch for %q", username) + logger.Debug("nativessh: certificate key mismatch for %q", username) } else { caKey, userPrincipals := store.get(username) if caKey == nil { - log.Printf("nativessh: CA key is not set for certificate auth user %q", username) + logger.Debug("nativessh: CA key is not set for certificate auth user %q", username) } else if len(userPrincipals) == 0 { - log.Printf("nativessh: no allowed principals found for certificate auth user %q", username) + logger.Debug("nativessh: no allowed principals found for certificate auth user %q", username) } else { checker := &ssh.CertChecker{ IsUserAuthority: func(auth ssh.PublicKey) bool { @@ -130,13 +130,13 @@ func AuthenticateWithCertificate(store *CredentialStore, username, password, pri for principal := range userPrincipals { _, authErr := checker.Authenticate(staticConnMeta{user: principal}, cert) if authErr == nil { - log.Printf("nativessh: certificate auth succeeded for %q (principal=%q)", username, principal) + logger.Debug("nativessh: certificate auth succeeded for %q (principal=%q)", username, principal) return nil } lastErr = authErr } if lastErr != nil { - log.Printf("nativessh: certificate auth failed for %q: %v", username, lastErr) + logger.Debug("nativessh: certificate auth failed for %q: %v", username, lastErr) } } } @@ -146,13 +146,13 @@ func AuthenticateWithCertificate(store *CredentialStore, username, password, pri if password != "" { if err := VerifySystemPassword(username, password); err != nil { - log.Printf("nativessh: password auth failed for %q: %v", username, err) + logger.Debug("nativessh: password auth failed for %q: %v", username, err) } else { - log.Printf("nativessh: password auth succeeded for %q", username) + logger.Debug("nativessh: password auth succeeded for %q", username) return nil } } else { - log.Printf("nativessh: no password provided for %q", username) + logger.Debug("nativessh: no password provided for %q", username) } return fmt.Errorf("authentication failed for user %q", username) } diff --git a/nativessh/pam_linux.go b/nativessh/pam_linux.go index f33828b..da02c7c 100644 --- a/nativessh/pam_linux.go +++ b/nativessh/pam_linux.go @@ -7,10 +7,10 @@ import ( "bytes" "errors" "fmt" - "log" "os" "strings" + "github.com/fosrl/newt/logger" "github.com/go-crypt/crypt" "github.com/go-crypt/x/yescrypt" ) @@ -21,7 +21,7 @@ import ( func VerifySystemPassword(username, password string) error { hash, err := readShadowHash(username) if err != nil { - log.Printf("nativessh/pam: readShadowHash for %q failed: %v", username, err) + logger.Debug("nativessh/pam: readShadowHash for %q failed: %v", username, err) return fmt.Errorf("shadow: %w", err) } @@ -33,17 +33,17 @@ func VerifySystemPassword(username, password string) error { break } } - log.Printf("nativessh/pam: verifying password for %q using scheme %s", username, scheme) + logger.Debug("nativessh/pam: verifying password for %q using scheme %s", username, scheme) // Yescrypt ($y$) is not in go-crypt/crypt's default decoder; handle it directly. if strings.HasPrefix(hash, "$y$") { computed, err := yescrypt.Hash([]byte(password), []byte(hash)) if err != nil { - log.Printf("nativessh/pam: yescrypt.Hash for %q failed: %v", username, err) + logger.Debug("nativessh/pam: yescrypt.Hash for %q failed: %v", username, err) return fmt.Errorf("yescrypt: %w", err) } if !bytes.Equal(computed, []byte(hash)) { - log.Printf("nativessh/pam: yescrypt mismatch for %q", username) + logger.Debug("nativessh/pam: yescrypt mismatch for %q", username) return errors.New("authentication failed") } return nil @@ -56,17 +56,17 @@ func VerifySystemPassword(username, password string) error { digest, err := decoder.Decode(hash) if err != nil { - log.Printf("nativessh/pam: failed to decode hash for %q: %v", username, err) + logger.Debug("nativessh/pam: failed to decode hash for %q: %v", username, err) return fmt.Errorf("unsupported password hash scheme %q: %w", scheme, err) } match, err := digest.MatchAdvanced(password) if err != nil { - log.Printf("nativessh/pam: MatchAdvanced for %q failed: %v", username, err) + logger.Debug("nativessh/pam: MatchAdvanced for %q failed: %v", username, err) return err } if !match { - log.Printf("nativessh/pam: password mismatch for %q", username) + logger.Debug("nativessh/pam: password mismatch for %q", username) return errors.New("authentication failed") } return nil diff --git a/nativessh/server.go b/nativessh/server.go index 20a13d9..0dc820f 100644 --- a/nativessh/server.go +++ b/nativessh/server.go @@ -7,11 +7,11 @@ import ( "crypto/rand" "fmt" "io" - "log" "net" "strings" "sync" + "github.com/fosrl/newt/logger" "golang.org/x/crypto/ssh" ) @@ -126,7 +126,7 @@ func (s *Server) Serve(ln net.Listener) error { if err != nil { return err } - log.Printf("nativessh: server listening on %s", ln.Addr()) + logger.Debug("nativessh: server listening on %s", ln.Addr()) for { conn, err := ln.Accept() if err != nil { @@ -151,11 +151,11 @@ func (s *Server) handleConn(conn net.Conn, cfg *ssh.ServerConfig) { defer conn.Close() sshConn, chans, reqs, err := ssh.NewServerConn(conn, cfg) if err != nil { - log.Printf("nativessh: handshake failed from %s: %v", conn.RemoteAddr(), err) + logger.Debug("nativessh: handshake failed from %s: %v", conn.RemoteAddr(), err) return } defer sshConn.Close() - log.Printf("nativessh: connection from %s user=%s", conn.RemoteAddr(), sshConn.User()) + logger.Debug("nativessh: connection from %s user=%s", conn.RemoteAddr(), sshConn.User()) go ssh.DiscardRequests(reqs) @@ -166,7 +166,7 @@ func (s *Server) handleConn(conn net.Conn, cfg *ssh.ServerConfig) { } ch, requests, err := newChan.Accept() if err != nil { - log.Printf("nativessh: channel accept error: %v", err) + logger.Debug("nativessh: channel accept error: %v", err) return } go s.handleSession(ch, requests, sshConn.User()) @@ -190,7 +190,7 @@ func (s *Server) handleSession(ch ssh.Channel, requests <-chan *ssh.Request, use if sess == nil { sess, err = NewPTYSessionAs(username) if err != nil { - log.Printf("nativessh: PTY start error: %v", err) + logger.Debug("nativessh: PTY start error: %v", err) if req.WantReply { _ = req.Reply(false, nil) } @@ -264,7 +264,7 @@ func makePublicKeyCallback(store *CredentialStore) func(ssh.ConnMetadata, ssh.Pu return func(meta ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { // 1. Host authorized_keys. if CheckAuthorizedKeys(meta.User(), key) { - log.Printf("nativessh: authorized_keys auth for user %q", meta.User()) + logger.Debug("nativessh: authorized_keys auth for user %q", meta.User()) return &ssh.Permissions{}, nil } @@ -286,14 +286,14 @@ func makePublicKeyCallback(store *CredentialStore) func(ssh.ConnMetadata, ssh.Pu for principal := range userPrincipals { perms, err := checker.Authenticate(connMetaWithUser{ConnMetadata: meta, user: principal}, key) if err == nil { - log.Printf("nativessh: CA cert auth for user %q principal=%q", meta.User(), principal) + logger.Debug("nativessh: CA cert auth for user %q principal=%q", meta.User(), principal) return perms, nil } lastErr = err } if lastErr != nil { - log.Printf("nativessh: CA cert rejected for user %q: %v", meta.User(), lastErr) + logger.Debug("nativessh: CA cert rejected for user %q: %v", meta.User(), lastErr) } } } @@ -309,10 +309,10 @@ func makePasswordCallback() func(ssh.ConnMetadata, []byte) (*ssh.Permissions, er return func(meta ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { if err := VerifySystemPassword(meta.User(), string(password)); err != nil { // Return a generic message to the client; log the real reason. - log.Printf("nativessh: password auth failed for user %q: %v", meta.User(), err) + logger.Debug("nativessh: password auth failed for user %q: %v", meta.User(), err) return nil, fmt.Errorf("permission denied") } - log.Printf("nativessh: password auth for user %q", meta.User()) + logger.Debug("nativessh: password auth for user %q", meta.User()) return &ssh.Permissions{}, nil } } @@ -324,7 +324,7 @@ func generateHostKey() (ssh.Signer, error) { if err != nil { return nil, fmt.Errorf("generate host key: %w", err) } - log.Printf("nativessh: generated ephemeral Ed25519 host key") + logger.Debug("nativessh: generated ephemeral Ed25519 host key") return ssh.NewSignerFromKey(priv) } diff --git a/newt b/newt index 34062da..1f46b58 100755 Binary files a/newt and b/newt differ diff --git a/service_windows.go b/service_windows.go index 7102cc2..3206d80 100644 --- a/service_windows.go +++ b/service_windows.go @@ -7,7 +7,6 @@ import ( "encoding/json" "fmt" "io" - "log" "os" "os/signal" "path/filepath" @@ -649,7 +648,7 @@ func setupWindowsEventLog() { // Set the custom logger output logger.GetLogger().SetOutput(file) - log.Printf("Newt service logging initialized - log file: %s", logFile) + logger.Debug("Newt service logging initialized - log file: %s", logFile) } // handleServiceCommand checks for service management commands and returns true if handled diff --git a/websocket/config.go b/websocket/config.go index f24f65a..b503449 100644 --- a/websocket/config.go +++ b/websocket/config.go @@ -7,7 +7,6 @@ import ( "encoding/json" "fmt" "io" - "log" "net/http" "net/url" "os" @@ -38,7 +37,7 @@ func getConfigPath(clientType string, overridePath string) string { } if err := os.MkdirAll(configDir, 0755); err != nil { - log.Printf("Failed to create config directory: %v", err) + logger.Debug("Failed to create config directory: %v", err) } return filepath.Join(configDir, "config.json") @@ -279,4 +278,4 @@ func (c *Client) provisionIfNeeded() error { } return nil -} \ No newline at end of file +}