grim/hgkeeper
Clone
Summary
Browse
Changes
Graph
Update the Dockerfile to build with golang 1.17
2022-03-07, Gary Kramlich
61b4f876b057
Update the Dockerfile to build with golang 1.17
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
}