Skip to content

Commit adef8d6

Browse files
authored
Merge pull request #342 from shazow/unsafe-password
main: Add --unsafe-passphrase
2 parents 3b8e644 + 99d303e commit adef8d6

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

cmd/ssh-chat/cmd.go

+62-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ package main
22

33
import (
44
"bufio"
5+
"errors"
56
"fmt"
67
"io/ioutil"
78
"net/http"
89
"os"
910
"os/signal"
1011
"os/user"
1112
"strings"
13+
"time"
1214

1315
"github.com/alexcesaro/log"
1416
"github.com/alexcesaro/log/golog"
@@ -19,8 +21,9 @@ import (
1921
"github.com/shazow/ssh-chat/chat"
2022
"github.com/shazow/ssh-chat/chat/message"
2123
"github.com/shazow/ssh-chat/sshd"
24+
25+
_ "net/http/pprof"
2226
)
23-
import _ "net/http/pprof"
2427

2528
// Version of the binary, assigned during build.
2629
var Version string = "dev"
@@ -36,8 +39,22 @@ type Options struct {
3639
Motd string `long:"motd" description:"Optional Message of the Day file."`
3740
Log string `long:"log" description:"Write chat log to this file."`
3841
Pprof int `long:"pprof" description:"Enable pprof http server for profiling."`
42+
43+
// Hidden flags, because they're discouraged from being used casually.
44+
Passphrase string `long:"unsafe-passphrase" description:"Require an interactive passphrase to connect. Whitelist feature is more secure." hidden:"true"`
3945
}
4046

47+
const extraHelp = `There are hidden options and easter eggs in ssh-chat. The source code is a good
48+
place to start looking. Some useful links:
49+
50+
* Project Repository:
51+
https://github.com/shazow/ssh-chat
52+
* Project Wiki FAQ:
53+
https://github.com/shazow/ssh-chat/wiki/FAQ
54+
* Command Flags Declaration:
55+
https://github.com/shazow/ssh-chat/blob/master/cmd/ssh-chat/cmd.go#L29
56+
`
57+
4158
var logLevels = []log.Level{
4259
log.Warning,
4360
log.Info,
@@ -57,6 +74,9 @@ func main() {
5774
if p == nil {
5875
fmt.Print(err)
5976
}
77+
if flagErr, ok := err.(*flags.Error); ok && flagErr.Type == flags.ErrHelp {
78+
fmt.Print(extraHelp)
79+
}
6080
return
6181
}
6282

@@ -78,7 +98,8 @@ func main() {
7898
}
7999

80100
logLevel := logLevels[numVerbose]
81-
sshchat.SetLogger(golog.New(os.Stderr, logLevel))
101+
logger := golog.New(os.Stderr, logLevel)
102+
sshchat.SetLogger(logger)
82103

83104
if logLevel == log.Debug {
84105
// Enable logging from submodules
@@ -109,6 +130,45 @@ func main() {
109130
config := sshd.MakeAuth(auth)
110131
config.AddHostKey(signer)
111132
config.ServerVersion = "SSH-2.0-Go ssh-chat"
133+
// FIXME: Should we be using config.NoClientAuth = true by default?
134+
135+
if options.Passphrase != "" {
136+
if options.Whitelist != "" {
137+
logger.Warning("Passphrase is disabled while whitelist is enabled.")
138+
}
139+
if config.KeyboardInteractiveCallback != nil {
140+
fail(1, "Passphrase authentication conflicts with existing KeyboardInteractive setup.") // This should not happen
141+
}
142+
143+
// We use KeyboardInteractiveCallback instead of PasswordCallback to
144+
// avoid preventing the client from including a pubkey in the user
145+
// identification.
146+
config.KeyboardInteractiveCallback = func(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
147+
answers, err := challenge("", "", []string{"Passphrase required to connect: "}, []bool{true})
148+
if err != nil {
149+
return nil, err
150+
}
151+
if len(answers) == 1 && answers[0] == options.Passphrase {
152+
// Success
153+
return nil, nil
154+
}
155+
// It's not gonna do much but may as well throttle brute force attempts a little
156+
time.Sleep(2 * time.Second)
157+
158+
return nil, errors.New("incorrect passphrase")
159+
}
160+
161+
// We also need to override the PublicKeyCallback to prevent rando pubkeys from bypassing
162+
cb := config.PublicKeyCallback
163+
config.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
164+
perms, err := cb(conn, key)
165+
if err == nil {
166+
err = errors.New("passphrase authentication required")
167+
}
168+
return perms, err
169+
}
170+
171+
}
112172

113173
s, err := sshd.ListenSSH(options.Bind, config)
114174
if err != nil {

sshd/auth.go

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type Auth interface {
1919
}
2020

2121
// MakeAuth makes an ssh.ServerConfig which performs authentication against an Auth implementation.
22+
// TODO: Switch to using ssh.AuthMethod instead?
2223
func MakeAuth(auth Auth) *ssh.ServerConfig {
2324
config := ssh.ServerConfig{
2425
NoClientAuth: false,

0 commit comments

Comments
 (0)