grim/hgkeeper

Deny invalid path

13 months ago, aklitzing
5a19892df841
Deny invalid path

If an authenticated user calls `hg init hg.host.com/dummy/../../../etc`
it will create the repository in another root directory if the process of
hgkeeper has permissions for this.
This could be an attack to the server.

Also hgkeeper admin repository can be overriden like this.
`hg init ssh://hg.host.com/dummy/../hgkeeper/keys`

Reviewed at https://reviews.imfreedom.org/r/2422/
package serve
import (
"fmt"
"os"
"os/signal"
"syscall"
"go.uber.org/zap"
"keep.imfreedom.org/grim/hgkeeper/access"
"keep.imfreedom.org/grim/hgkeeper/globals"
"keep.imfreedom.org/grim/hgkeeper/http"
"keep.imfreedom.org/grim/hgkeeper/ssh"
)
type Command struct {
SSHAddr string `kong:"flag,name='ssh-listen-addr',env='HGK_SSH_LISTEN_ADDR',short='l',help='what address to listen on',default=':22222'"`
SSHHostKeysPath string `kong:"flag,name='ssh-host-keys-path',env='HGK_SSH_HOST_KEYS_PATH',short='H',help='the path where host keys are kept',default='host-keys'"`
HTTPAddr string `kong:"flag,name='http-listen-addr',env='HGK_HTTP_LISTEN_ADDR',help='what address the http server listens on',default=':8080'"`
DisableSSH bool `kong:"flag,name='disable-ssh',env='HGK_DISABLE_SSH',help='disable the SSH server',default='false'"`
DisableHGWeb bool `kong:"flag,name='disable-hgweb',env='HGK_DISABLE_HGWEB',help='disable the HGWEB cgi server',default='false'"`
ExternalHostname string `kong:"flag,name='external-hostname',env='HGK_EXTERNAL_HOSTNAME',help='The external hostname of the hgkeeper instance. This is used to integrate with other ssh servers.'"`
ExternalPort string `kong:"flag,name='external-port',env='HGK_EXTERNAL_PORT',help='The external port of the hgkeeper instance. This is used to itegrate with other ssh servers.',default='22222'"`
}
func (c *Command) Run(g *globals.Globals) error {
if c.DisableHGWeb && c.DisableSSH {
return fmt.Errorf("both HGWeb and SSH servers have been disabled")
}
if err := access.Setup(g.ReposPath, g.AdminRepo); err != nil {
return err
}
defer access.Teardown()
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
errChan := make(chan error, 10)
var sshServer *ssh.Server
if c.DisableSSH {
zap.S().Info("SSH server has been disabled")
} else {
var err error
sshServer, err = ssh.NewServer(c.SSHHostKeysPath, g.ReposPath, access.AdminRepoPath())
if err != nil {
return err
}
defer sshServer.Close()
}
httpServer, err := http.NewServer(c.HTTPAddr, c.DisableHGWeb, c.ExternalHostname, c.ExternalPort)
if err != nil {
return err
}
defer httpServer.Close()
if !c.DisableSSH {
go func() {
if err := sshServer.Listen(c.SSHAddr); err != nil {
errChan <- err
}
}()
}
go func() {
if err := httpServer.Listen(); err != nil {
errChan <- err
}
}()
for {
select {
case err := <-errChan:
if err != nil {
return err
}
case s := <-signalChan:
zap.S().Infof("Captured %v signal. Exiting...", s)
return nil
}
}
}