grim/hgkeeper
Clone
Summary
Browse
Changes
Graph
Remove the mercurial 6.1 pin from the container image
23 months ago, Gary Kramlich
653b933ba715
Remove the mercurial 6.1 pin from the container image
package
ssh
import
(
"fmt"
"github.com/gliderlabs/ssh"
log
"github.com/sirupsen/logrus"
gossh
"golang.org/x/crypto/ssh"
"keep.imfreedom.org/grim/hgkeeper/access"
"keep.imfreedom.org/grim/hgkeeper/ssh/commands"
)
type
Server
struct
{
reposPath
string
server
*
ssh
.
Server
}
func
NewServer
(
hostKeysPath
,
reposPath
,
adminRepo
string
)
(
*
Server
,
error
)
{
s
:=
&
Server
{
reposPath
:
reposPath
,
}
s
.
server
=
&
ssh
.
Server
{
PublicKeyHandler
:
s
.
publicKeyHandler
,
Handler
:
s
.
sessionHandler
,
PtyCallback
:
func
(
ctx
ssh
.
Context
,
pty
ssh
.
Pty
)
bool
{
return
false
},
}
if
err
:=
s
.
setHostKeysPath
(
hostKeysPath
);
err
!=
nil
{
return
nil
,
err
}
return
s
,
nil
}
func
(
s
*
Server
)
publicKeyHandler
(
ctx
ssh
.
Context
,
key
ssh
.
PublicKey
)
bool
{
username
,
err
:=
access
.
UsernameFromPubkey
(
key
)
if
err
!=
nil
{
log
.
Warnf
(
"authentication failure, unknown key %s"
,
gossh
.
FingerprintSHA256
(
key
))
return
false
}
ctx
.
SetValue
(
"username"
,
username
)
log
.
Infof
(
"%q authenticated with %s"
,
username
,
gossh
.
FingerprintSHA256
(
key
),
)
return
true
}
func
(
s
*
Server
)
sessionHandler
(
session
ssh
.
Session
)
{
username
:=
session
.
Context
().
Value
(
"username"
).(
string
)
// per the docs, session.Command is empty if the user is requesting a shell.
// we only support execs, which means command should be non-empty.
if
len
(
session
.
Command
())
==
0
{
fmt
.
Fprintf
(
session
,
"logged in as %s\n\nShell access is disabled\n"
,
username
)
return
}
log
.
Infof
(
"%s@%s requested command %q"
,
username
,
session
.
RemoteAddr
(),
session
.
RawCommand
(),
)
cmd
,
err
:=
commands
.
Find
(
session
.
RawCommand
(),
s
.
reposPath
)
if
err
!=
nil
{
log
.
Warnf
(
"failed to find command for %q, %v"
,
session
.
RawCommand
(),
err
)
return
}
if
err
:=
cmd
.
Run
(
session
,
username
);
err
!=
nil
{
log
.
Warnf
(
"%s@%s command %q failed: %v"
,
username
,
session
.
RemoteAddr
(),
session
.
RawCommand
(),
err
,
)
if
err
:=
session
.
Exit
(
255
);
err
!=
nil
{
log
.
Errorf
(
"session failed to exit: %v"
,
err
)
}
}
else
{
log
.
Infof
(
"%s@%s command %q succeed"
,
username
,
session
.
RemoteAddr
(),
session
.
RawCommand
(),
)
if
err
:=
session
.
Exit
(
0
);
err
!=
nil
{
log
.
Errorf
(
"session failed to exit: %v"
,
err
)
}
}
}
func
(
s
*
Server
)
Listen
(
addr
string
)
error
{
s
.
server
.
Addr
=
addr
log
.
Infof
(
"ssh listening on %s"
,
s
.
server
.
Addr
)
if
err
:=
s
.
server
.
ListenAndServe
();
err
!=
nil
{
if
err
!=
ssh
.
ErrServerClosed
{
return
err
}
}
return
nil
}
func
(
s
*
Server
)
Close
()
error
{
if
s
.
server
!=
nil
{
if
err
:=
s
.
server
.
Close
();
err
!=
nil
{
s
.
server
=
nil
}
}
return
nil
}