add support for protocol specific CGI environments

Signed-off-by: kim (grufwub) <grufwub@gmail.com>

Former-commit-id: 3a465a080010d59e4679f7cbbc128c71d4f7b993
development
kim (grufwub) 4 years ago
parent 30bf8d5b80
commit 4066ff11f9

@ -31,6 +31,7 @@ func generateCGIEnv(client *Client, request *Request) []string {
env = append(env, "SCRIPT_NAME="+request.Path().Relative())
env = append(env, "SCRIPT_FILENAME="+request.Path().Absolute())
env = append(env, "REQUEST_URI="+request.Path().Selector())
env = appendCgiEnv(client, request, env)
return env
}

@ -24,7 +24,7 @@ func usage(code int) {
}
// ParseConfigAndSetup parses necessary core server config from file (and any others defined), and sets up the core ready for Start() to be called
func ParseConfigAndSetup(tree config.Tree, proto string, defaultPort uint, newListener func() (*Listener, *errors.Error), fileContent func(*Path) FileContent, dirHandler func(*Client, *os.File, *Path) *errors.Error, largeHandler func(*Client, *os.File, *Path) *errors.Error) {
func ParseConfigAndSetup(tree config.Tree, proto string, defaultPort uint, newListener func() (*Listener, *errors.Error), fileContent func(*Path) FileContent, dirHandler func(*Client, *os.File, *Path) *errors.Error, largeHandler func(*Client, *os.File, *Path) *errors.Error, appendCgi func(*Client, *Request, []string) []string) {
// Default configuration file location
configFile := "/etc/gophi." + proto + ".conf"
@ -259,10 +259,11 @@ func ParseConfigAndSetup(tree config.Tree, proto string, defaultPort uint, newLi
BuildPath = buildPathUserSpacesDisabled
}
// Set provided client filesystem handler functions
// Set provided protocol specific functions
newFileContent = fileContent
handleDirectory = dirHandler
handleLargeFile = largeHandler
appendCgiEnv = appendCgi
// Setup signal channel
sigChannel = make(chan os.Signal)

@ -36,7 +36,7 @@ type conn struct {
b []byte
br *bufio.Reader
bw *bufio.Writer
cl io.Closer
c net.Conn
}
// wrapConn wraps a net.Conn in deadlineConn, then within conn and returns the result
@ -46,10 +46,15 @@ func wrapConn(c net.Conn) *conn {
b: connRequestBufferPool.Get(),
br: connBufferedReaderPool.Get(deadlineConn),
bw: connBufferedWriterPool.Get(deadlineConn),
cl: deadlineConn,
c: c,
}
}
// Conn returns the underlying net.Conn
func (c *conn) Conn() net.Conn {
return c.c
}
// ReadLine reads a single line and returns the result, or nil and error
func (c *conn) ReadLine() ([]byte, *errors.Error) {
// Perform single read into buffer slice
@ -103,7 +108,7 @@ func (c *conn) Writer() io.Writer {
func (c *conn) Close() *errors.Error {
// Flush + close
c.bw.Flush()
err := c.cl.Close()
err := c.c.Close()
// Put buffers back
connBufferedReaderPool.Put(c.br)

@ -75,6 +75,9 @@ var (
// WithinCGIDir returns whether a path is within the server's specified CGI scripts directory
WithinCGIDir func(*Path) bool
// appendCgiEnv is the global function set by implementor to append protocol specific CGI information
appendCgiEnv func(*Client, *Request, []string) []string
// IsRestrictedPath is the global function to check against restricted paths
IsRestrictedPath func(*Path) bool

@ -0,0 +1,65 @@
package gemini
import (
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"gophi/core"
)
// Mapped to tls.Version__ where:
// value - 0x300 = index
var tlsVersionStrings = []string{
"",
"TLSv1.0",
"TLSv1.1",
"TLSv1.2",
"TLSv1.3",
}
func certSha256Hash(cert *x509.Certificate) string {
checksum := sha256.Sum256(cert.Raw)
return hex.EncodeToString(checksum[:])
}
func appendCgiEnv(client *core.Client, request *core.Request, env []string) []string {
// Build and append the full gemini url
env = append(env, "GEMINI_URL=gemini://"+core.Hostname+":"+core.Port+request.Path().Selector())
// Cast client underlying net.Conn as tls.Conn
tlsConn := client.Conn().Conn().(*tls.Conn)
state := tlsConn.ConnectionState()
// Append TLS env vars
env = append(env, "TLS_CIPHER="+tls.CipherSuiteName(state.CipherSuite))
env = append(env, "TLS_VERSION="+tlsVersionStrings[state.Version-0x300])
// Append TLS client cert vars (if present!)
clientCerts := state.PeerCertificates
if len(clientCerts) > 0 {
// Only use first if multiple client
// certs available
cert := clientCerts[0]
// Verify client cert
var isAuthorized string
_, err := cert.Verify(x509.VerifyOptions{})
if err != nil {
isAuthorized = "0"
} else {
isAuthorized = "1"
}
// Set user cert environment vars
env = append(env, "AUTH_TYPE=CERTIFICATE")
env = append(env, "REMOTE_USER="+cert.Subject.CommonName)
env = append(env, "TLS_CLIENT_HASH="+certSha256Hash(cert))
env = append(env, "TLS_CLIENT_NOT_BEFORE="+cert.NotBefore.String())
env = append(env, "TLS_CLIENT_NOT_AFTER="+cert.NotAfter.String())
env = append(env, "TLS_CLIENT_SERIAL_NUMBER="+cert.SerialNumber.String())
env = append(env, "TLS_CLIENT_AUTHORISED="+isAuthorized)
}
return env
}

@ -57,6 +57,7 @@ func Run() {
newFileContent,
handleDirectory,
handleLargeFile,
appendCgiEnv,
)
// Start!

@ -0,0 +1,11 @@
package gopher
import (
"gophi/core"
"strconv"
)
func appendCgiEnv(client *core.Client, request *core.Request, env []string) []string {
env = append(env, "COLUMNS="+strconv.Itoa(pageWidth))
return env
}

@ -35,6 +35,7 @@ func Run() {
newFileContent,
handleDirectory,
handleLargeFile,
appendCgiEnv,
)
// Setup gopher specific global variables

Loading…
Cancel
Save