commit 39912e51561efeca6d0fd179d365ef3ab99eb081
parent c8017f6c77407151e2d758d5f828fe74fed62e2b
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Tue, 27 Aug 2024 17:46:27 +0900
try to negosiate with factotum
Diffstat:
5 files changed, 90 insertions(+), 14 deletions(-)
diff --git a/auth_test.go b/auth_test.go
@@ -18,7 +18,7 @@ func TestAuth(t *testing.T) {
 	go sOpen(ctx, c, otc)
 	acr, asw := io.Pipe()
 	asr, acw := io.Pipe()
-	c.s.Auth = func(ctx context.Context, r *request) {
+	c.s.Auth = func(ctx context.Context, r *request) error {
 		ifcall := r.ifcall.(*TAuth)
 		aqid := Qid{Type: QTAUTH, Vers: 0, Path: ^uint64(0)}
 		r.afid.file = &AuthFile{
@@ -28,8 +28,9 @@ func TestAuth(t *testing.T) {
 			W:     acw,
 			R:     acr,
 		}
-		runAuth(ctx, t, r.afid.file.(*AuthFile), asr, asw)
+		runTestAuth(ctx, t, r.afid.file.(*AuthFile), asr, asw)
 		r.ofcall = &RAuth{Tag: ifcall.Tag, Aqid: aqid}
+		return nil
 	}
 	atc <- &request{ifcall: &TAuth{Afid: 0, Uname: "kenji"}}
 	ofcall := (<-rc).ofcall
@@ -56,7 +57,7 @@ func TestAuth(t *testing.T) {
 
 // Dumb state machine...
 // TODO: return when ctx is canceled
-func runAuth(ctx context.Context, t *testing.T, afile *AuthFile, r io.Reader, w io.Writer) {
+func runTestAuth(ctx context.Context, t *testing.T, afile *AuthFile, r io.Reader, w io.Writer) {
 	go func() {
 		buf := make([]byte, 10)
 		uname := "kenji"
diff --git a/cmd/diskfs/main.go b/cmd/diskfs/main.go
@@ -31,6 +31,7 @@ import (
 
 var dFlag = flag.Bool("D", false, "Prints chatty message to the stderr.")
 var aFlag = flag.String("a", "127.0.0.1", "Address the server listens to.")
+var fFlag = flag.String("f", "", "Rpc file of factotum to be used for authentication")
 var pFlag = flag.Int("p", 5640, "Port number the server listens to.")
 var PFlag = flag.Int("P", 0, "Enables pprof over http on this port.")
 var gFlag = flag.Bool("g", false, "Prints goroutin count once per second.")
@@ -38,7 +39,7 @@ var gFlag = flag.Bool("g", false, "Prints goroutin count once per second.")
 func main() {
 	flag.Parse()
 	if flag.NArg() != 1 {
-		fmt.Fprintf(os.Stderr, "usage: %s [-D] [-P profport] [-a addr] [-p port] root\n", os.Args[0])
+		fmt.Fprintf(os.Stderr, "usage: %s [-D] [-P profport] [-f rpcfile] [-a addr] [-p port] root\n", os.Args[0])
 		os.Exit(1)
 	}
 	if *gFlag {
@@ -72,6 +73,11 @@ func main() {
 	if *dFlag {
 		s.Chatty()
 	}
+	if *fFlag != "" {
+		if err := lib9p.SetFactotum(s, *fFlag); err != nil {
+			log.Fatalf("setfactotum: %v", err)
+		}
+	}
 L:
 	for {
 		conn, err := listener.Accept()
diff --git a/factotum.go b/factotum.go
@@ -0,0 +1,63 @@
+package lib9p
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"log"
+	"os"
+)
+
+func SetFactotum(s *Server, rpcpath string) error {
+	s.Auth = func(ctx context.Context, r *request) error {
+		ifcall := r.ifcall.(*TAuth) // TODO: need assertion?
+		rpcfile, err := os.OpenFile(rpcpath, os.O_RDWR, 0)
+		if err != nil {
+			return fmt.Errorf("openfile: %v", err)
+		}
+		cr, sw := io.Pipe()
+		sr, cw := io.Pipe()
+		// TODO: close rpcfile.
+		// TODO: check race condition. Can I ignore?
+		afile := &AuthFile{
+			// TODO: BUG: allocate Qid
+			Qid:    Qid{Type: QTAUTH, Vers: 0, Path: ^uint64(0)},
+			Uname:  ifcall.Uname, // TODO: need to check.
+			Aname:  ifcall.Aname,
+			AuthOK: false,
+			W:      cw,
+			R:      cr,
+		}
+		r.afid.file = afile
+		runAuth(ctx, rpcfile, afile, sr, sw)
+		r.ofcall = &RAuth{Tag: ifcall.Tag, Aqid: afile.Qid}
+		return nil
+	}
+	return nil
+}
+
+func runAuth(ctx context.Context, rpcfile *os.File, afile *AuthFile, r io.Reader, w io.Writer) {
+	buf := make([]byte, 1024)
+	for {
+		n, err := r.Read(buf)
+		if err != nil {
+			log.Printf("read from auth channel: %v", err)
+		}
+		n, err = rpcfile.Write(buf[:n])
+		if err != nil {
+			log.Printf("write to auth file: %v", err)
+		}
+		n, err = rpcfile.Read(buf)
+		if err != nil {
+			log.Printf("read from auth file: %v", err)
+		}
+		if n >= 4 && string(buf[:4]) == "done" {
+			afile.AuthOK = true
+			break
+		}
+		n, err = w.Write(buf[:n])
+		if err != nil {
+			log.Printf("write to auth channel: %v", err)
+		}
+	}
+}
+\ No newline at end of file
diff --git a/server.go b/server.go
@@ -43,7 +43,7 @@ type Server struct {
 	// authenticate via the Read()/Write() calls to request.Afid.file.
 	// Auth should clean up everything it creates when ctx is canceled.
 	// If this is nil, no authentication is performed.
-	Auth func(ctx context.Context, r *request)
+	Auth func(ctx context.Context, r *request) error
 }
 
 // NewServer creates a Server.
@@ -278,10 +278,13 @@ func sAuth(ctx context.Context, c *conn, rc <-chan *request) {
 			if r.err != nil {
 				setError(r, r.err)
 			} else {
-				c.s.Auth(ctx, r)
-				// TODO: should move this code to c.s.Auth?
-				if rauth, ok := r.ofcall.(*RAuth); ok {
-					r.afid.qidpath = rauth.Aqid.Path
+				if err := c.s.Auth(ctx, r); err != nil {
+					setError(r, fmt.Errorf("auth: %v", err))
+				} else {
+					// TODO: should move this code to c.s.Auth?
+					if rauth, ok := r.ofcall.(*RAuth); ok {
+						r.afid.qidpath = rauth.Aqid.Path
+					}
 				}
 			}
 			select {
diff --git a/server_test.go b/server_test.go
@@ -177,22 +177,24 @@ func TestSAuth(t *testing.T) {
 	tests := []struct {
 		input    *TAuth
 		want     Msg
-		authFunc func(context.Context, *request)
+		authFunc func(context.Context, *request) error
 	}{
 		{&TAuth{Afid: NOFID, Uname: "kenji", Aname: ""},
 			&RError{Ename: errors.New("authentication not required")}, nil},
 		{&TAuth{Afid: NOFID, Uname: "kenji", Aname: ""},
 			&RError{Ename: errors.New("NOFID can't be used for afid")},
-			func(ctx context.Context, r *request) {}},
+			func(ctx context.Context, r *request) error { return nil }},
 		{&TAuth{Afid: 0, Uname: "kenji", Aname: ""},
 			&RAuth{Tag: 0, Aqid: Qid{0, 1, 2}},
-			func(ctx context.Context, r *request) {
+			func(ctx context.Context, r *request) error {
 				r.ofcall = &RAuth{Tag: 0, Aqid: Qid{0, 1, 2}}
+				return nil
 			}},
 		{&TAuth{Afid: 0, Uname: "kenji", Aname: "fs"},
 			&RError{Ename: errors.New("no such file system")},
-			func(ctx context.Context, r *request) {
+			func(ctx context.Context, r *request) error {
 				r.ofcall = &RAuth{Tag: 0, Aqid: Qid{0, 1, 2}}
+				return nil
 			}},
 	}
 	for i, test := range tests {
@@ -267,7 +269,7 @@ func TestSAttach(t *testing.T) {
 	c, rc := setupConn(testfs)
 	c.s.fsmap["fs"] = testfs
 	tc := make(chan *request)
-	dammyAuth := func(context.Context, *request) {}
+	dammyAuth := func(context.Context, *request) error { return nil }
 	af := &AuthFile{
 		Qid:   Qid{Type: QTAUTH},
 		Uname: "kenji",