From 6a0544091e04dc972069d6ce031f886a873daf32 Mon Sep 17 00:00:00 2001 From: Albert Strasheim Date: Sun, 18 Mar 2012 10:03:00 -0700 Subject: [PATCH] syscall: Test SCM_CREDENTIALS, SO_PASSCRED on Linux. R=bradfitz, iant CC=golang-dev https://golang.org/cl/5846059 --- src/pkg/syscall/creds_linux_test.go | 107 ++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 src/pkg/syscall/creds_linux_test.go diff --git a/src/pkg/syscall/creds_linux_test.go b/src/pkg/syscall/creds_linux_test.go new file mode 100644 index 0000000000..c1ed98b707 --- /dev/null +++ b/src/pkg/syscall/creds_linux_test.go @@ -0,0 +1,107 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall_test + +import ( + "bytes" + "net" + "os" + "syscall" + "testing" +) + +// TestSCMCredentials tests the sending and receiving of credentials +// (PID, UID, GID) in an ancillary message between two UNIX +// sockets. The SO_PASSCRED socket option is enabled on the sending +// socket for this to work. +func TestSCMCredentials(t *testing.T) { + fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0) + if err != nil { + t.Fatalf("Socketpair: %v", err) + } + defer syscall.Close(fds[0]) + defer syscall.Close(fds[1]) + + err = syscall.SetsockoptInt(fds[0], syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1) + if err != nil { + t.Fatalf("SetsockoptInt: %v", err) + } + + srv, err := net.FileConn(os.NewFile(uintptr(fds[0]), "")) + if err != nil { + t.Errorf("FileConn: %v", err) + return + } + defer srv.Close() + + cli, err := net.FileConn(os.NewFile(uintptr(fds[1]), "")) + if err != nil { + t.Errorf("FileConn: %v", err) + return + } + defer cli.Close() + + var ucred syscall.Ucred + if os.Getuid() != 0 { + ucred.Pid = int32(os.Getpid()) + ucred.Uid = 0 + ucred.Gid = 0 + oob := syscall.UnixCredentials(&ucred) + _, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) + if err.(*net.OpError).Err != syscall.EPERM { + t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err) + } + } + + ucred.Pid = int32(os.Getpid()) + ucred.Uid = uint32(os.Getuid()) + ucred.Gid = uint32(os.Getgid()) + oob := syscall.UnixCredentials(&ucred) + + // this is going to send a dummy byte + n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) + if err != nil { + t.Fatalf("WriteMsgUnix: %v", err) + } + if n != 0 { + t.Fatalf("WriteMsgUnix n = %d, want 0", n) + } + if oobn != len(oob) { + t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob)) + } + + oob2 := make([]byte, 10*len(oob)) + n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2) + if err != nil { + t.Fatalf("ReadMsgUnix: %v", err) + } + if flags != 0 { + t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags) + } + if n != 1 { + t.Fatalf("ReadMsgUnix n = %d, want 1 (dummy byte)", n) + } + if oobn2 != oobn { + // without SO_PASSCRED set on the socket, the ReadMsgUnix will + // return zero oob bytes + t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn) + } + oob2 = oob2[:oobn2] + if !bytes.Equal(oob, oob2) { + t.Fatal("ReadMsgUnix oob bytes don't match") + } + + scm, err := syscall.ParseSocketControlMessage(oob2) + if err != nil { + t.Fatalf("ParseSocketControlMessage: %v", err) + } + newUcred, err := syscall.ParseUnixCredentials(&scm[0]) + if err != nil { + t.Fatalf("ParseUnixCredentials: %v", err) + } + if *newUcred != ucred { + t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred) + } +}