mirror of
https://github.com/rwinkhart/rcw.git
synced 2026-08-29 21:36:41 -04:00
Incomplete Windows daemon support
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
//go:build !windows
|
||||
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"net"
|
||||
"net/rpc"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
peercred "github.com/rwinkhart/peercred-mini"
|
||||
)
|
||||
|
||||
// Run should be called to start an RPC server.
|
||||
func Run() {
|
||||
// register RCWService with the RPC package
|
||||
if err := rpc.Register(&RCWService{}); err != nil {
|
||||
log.Fatalf("Error registering RPC service: %v", err)
|
||||
}
|
||||
|
||||
// store the hash of the daemon binary
|
||||
daemonHash = getFileHash(binPath)
|
||||
|
||||
// remove the socket file if it already exists
|
||||
if _, err := os.Stat(socketPath); err == nil {
|
||||
if err := os.Remove(socketPath); err != nil {
|
||||
log.Fatalf("Failed to remove existing socket: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// listen on the Unix domain socket
|
||||
listener, err := net.Listen("unix", socketPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to listen on UNIX socket %s: %v", socketPath, err)
|
||||
}
|
||||
defer listener.Close()
|
||||
log.Printf("RPC daemon listening on unix://%s", socketPath)
|
||||
|
||||
// accept connections (timeout after 3 minutes of inactivity)
|
||||
for {
|
||||
listener.(*net.UnixListener).SetDeadline(time.Now().Add(3 * time.Minute))
|
||||
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
if err.(net.Error).Timeout() {
|
||||
log.Println("Three minutes have passed without any connections. Exiting...")
|
||||
os.Exit(0)
|
||||
}
|
||||
log.Printf("Accept error: %v", err)
|
||||
continue
|
||||
}
|
||||
// use a goroutine to check the client's identity
|
||||
go handleConn(conn)
|
||||
}
|
||||
}
|
||||
|
||||
// handleConn verifies the identity of the client.
|
||||
// It uses the file descriptor of the connection to get the PID of the client,
|
||||
// which is then used to get the path of the client's executable and calculate its hash.
|
||||
// The passphrase is only returned if the client's executable hash matches the daemon's hash
|
||||
// and if the request is coming from the same user.
|
||||
// This ensures that only the binary the daemon is embedded in can retrieve the passphrase.
|
||||
func handleConn(conn net.Conn) {
|
||||
ucred := peercred.Get(conn)
|
||||
|
||||
// check if the RPC call is coming from an identical binary and from the same user
|
||||
callingBinPath := pidToPath(ucred.PID)
|
||||
if ucred.UID == strconv.Itoa(os.Getuid()) && bytes.Equal(getFileHash(callingBinPath), daemonHash) {
|
||||
// valid client; hand off the connection to the RPC server
|
||||
rpc.ServeConn(conn)
|
||||
} else {
|
||||
// invalid client; close the connection w/o a response,
|
||||
// log the client's path, and kill the daemon
|
||||
conn.Close()
|
||||
log.Printf("Request received from invalid client: PID(%d), UID(%s), Path(%s)", ucred.PID, ucred.UID, callingBinPath) // TODO log to file
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user