From 390f6acbcd720f8e3b3224f4582817e071742bde Mon Sep 17 00:00:00 2001
From: Bolke de Bruin <bolke@xs4all.nl>
Date: Tue, 23 Aug 2022 22:31:41 +0200
Subject: [PATCH] Add support for PAM authentication

---
 .github/workflows/go.yml  |  2 +-
 Makefile                  |  4 ++-
 cmd/auth/auth.go          | 72 +++++++++++++++++++++++++++++++++++++++
 cmd/auth/proto/auth.proto | 14 ++++++++
 go.mod                    |  5 ++-
 5 files changed, 94 insertions(+), 3 deletions(-)
 create mode 100644 cmd/auth/auth.go
 create mode 100644 cmd/auth/proto/auth.proto

diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index ecb0797..8a08082 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -16,7 +16,7 @@ jobs:
     - name: Set up Go 1.x
       uses: actions/setup-go@v2
       with:
-        go-version: ^1.16
+        go-version: ^1.19
       id: go
 
     - name: Check out code into the Go module directory
diff --git a/Makefile b/Makefile
index 03148c0..d3f6539 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
 BINDIR      := $(CURDIR)/bin
 INSTALL_PATH ?= /usr/local/bin
 BINNAME     ?= rdpgw
+BINNAME2    ?= auth
 
 # Rebuild the binary if any of these files change
 SRC := $(shell find . -type f -name '*.go' -print) go.mod go.sum
@@ -35,6 +36,7 @@ build: $(BINDIR)/$(BINNAME)
 
 $(BINDIR)/$(BINNAME): $(SRC)
 	go build $(GOFLAGS) -trimpath -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o '$(BINDIR)'/$(BINNAME) ./cmd/rdpgw
+	go build $(GOFLAGS) -trimpath -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o '$(BINDIR)'/$(BINNAME2) ./cmd/auth
 
 # ------------------------------------------------------------------------------
 #  install
@@ -48,7 +50,7 @@ install: build
 
 .PHONY: mod
 mod:
-	go mod tidy -compat=1.17
+	go mod tidy -compat=1.19
 
 # ------------------------------------------------------------------------------
 #  test
diff --git a/cmd/auth/auth.go b/cmd/auth/auth.go
new file mode 100644
index 0000000..611762d
--- /dev/null
+++ b/cmd/auth/auth.go
@@ -0,0 +1,72 @@
+package main
+
+import (
+	"errors"
+	"github.com/golang/protobuf/proto"
+	ipc "github.com/james-barrow/golang-ipc"
+	"github.com/msteinert/pam"
+	"github.com/thought-machine/go-flags"
+	"log"
+)
+
+var opts struct {
+	serviceName string `short:"s" long:"service" default:"rdpgw" description:"the PAM service name to use"`
+}
+
+func auth(service, user, passwd string) error {
+	t, err := pam.StartFunc(service, user, func(s pam.Style, msg string) (string, error) {
+		switch s {
+		case pam.PromptEchoOff:
+			return passwd, nil
+		case pam.PromptEchoOn, pam.ErrorMsg, pam.TextInfo:
+			return "", nil
+		}
+		return "", errors.New("unrecognized PAM message style")
+	})
+
+	if err != nil {
+		return err
+	}
+
+	if err = t.Authenticate(0); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func main() {
+	_, err := flags.Parse(&opts)
+	if err != nil {
+		panic(err)
+	}
+
+	config := &ipc.ServerConfig{UnmaskPermissions: true}
+	sc, err := ipc.StartServer("rdpgw-auth", config)
+	for {
+		msg, err := sc.Read()
+		if err != nil {
+			log.Printf("server error, %s", err)
+			continue
+		}
+		if msg.MsgType > 0 {
+			req := &UserPass{}
+			if err = proto.Unmarshal(msg.Data, req); err != nil {
+				log.Printf("cannot unmarshal request %s", string(msg.Data))
+				continue
+			}
+			err := auth(opts.serviceName, req.Username, req.Password)
+			if err != nil {
+				res := &Response{Status: "cannot authenticate"}
+				out, err := proto.Marshal(res)
+				if err != nil {
+					log.Fatalf("cannot marshal response due to %s", err)
+				}
+				sc.Write(1, out)
+			}
+		}
+	}
+	if err != nil {
+		log.Printf("cannot authenticate due to %s", err)
+	}
+}
diff --git a/cmd/auth/proto/auth.proto b/cmd/auth/proto/auth.proto
new file mode 100644
index 0000000..acc33a2
--- /dev/null
+++ b/cmd/auth/proto/auth.proto
@@ -0,0 +1,14 @@
+syntax = "proto3";
+
+package main;
+
+option go_package = "./auth;main";
+
+message UserPass {
+  string username = 1;
+  string password = 2;
+}
+
+message Response {
+  string status = 1;
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 5536858..1922f09 100644
--- a/go.mod
+++ b/go.mod
@@ -1,13 +1,15 @@
 module github.com/bolkedebruin/rdpgw
 
-go 1.17
+go 1.19
 
 require (
 	github.com/coreos/go-oidc/v3 v3.2.0
 	github.com/go-jose/go-jose/v3 v3.0.0
 	github.com/gorilla/sessions v1.2.1
 	github.com/gorilla/websocket v1.5.0
+	github.com/james-barrow/golang-ipc v1.0.0
 	github.com/knadh/koanf v1.4.2
+	github.com/msteinert/pam v1.0.0
 	github.com/patrickmn/go-cache v2.1.0+incompatible
 	github.com/prometheus/client_golang v1.12.1
 	github.com/thought-machine/go-flags v1.6.1
@@ -15,6 +17,7 @@ require (
 )
 
 require (
+	github.com/Microsoft/go-winio v0.4.16 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
 	github.com/fsnotify/fsnotify v1.5.4 // indirect
-- 
GitLab