Skip to content

Commit a49296b

Browse files
authored
add options to forget command (#27)
1 parent dfd3541 commit a49296b

File tree

6 files changed

+389
-152
lines changed

6 files changed

+389
-152
lines changed

README.asciidoc

+74
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,80 @@ Modify the SSH daemon configuration +/etc/ssh/sshd_config+ by adding:
8484
8585
ForceCommand /usr/sbin/sshproxy
8686
87+
Migrating to sshproxy 2
88+
-----------------------
89+
90+
Version 2 brings a lot of changes to sshproxy:
91+
92+
1. configuration file:
93+
- **all** configuration options can now be set outside of overrides (those are
94+
the default values) or inside an override
95+
- `users`, `groups` and `routes` options have been replaced by the overrides
96+
system:
97+
* old style:
98+
99+
routes:
100+
default:
101+
some_default_options…
102+
service1:
103+
source: [an.ip.sshd.listens.to]
104+
some_sources_options…
105+
users:
106+
- alice,bob:
107+
some_users_options…
108+
groups:
109+
- foo,bar:
110+
some_groups_options…
111+
112+
* new style:
113+
114+
some_default_options…
115+
overrides:
116+
- match:
117+
- sources: [an.ip.sshd.listens.to]
118+
some_sources_options…
119+
- match:
120+
- users: [alice,bob]
121+
some_users_options…
122+
overrides:
123+
- match:
124+
- groups: [foo,bar]
125+
some_groups_options…
126+
127+
- the `match` conditions of the overrides system can be combined. Here is an
128+
example meaning "match if (the user is in the group foo **and** in the
129+
group bar) **or** ((the user is alice **or** bob) **and** the user is
130+
connected to an.ip.sshd.listens.to)":
131+
132+
overrides:
133+
- match:
134+
- groups: [foo]
135+
groups: [bar]
136+
- users: [alice,bob]
137+
sources: [an.ip.sshd.listens.to]
138+
139+
- nodesets can now be used for the `dest` key
140+
- if `libnodeset.so` (from https://github.com/fdiakh/nodeset-rs) is found, it
141+
allows the use of clustershell groups where nodesets are allowed
142+
- new option: `blocking_command` runs a command before starting the ssh
143+
connection to the destination. If the command does not return 0, the
144+
connection is aborted
145+
2. command line interface:
146+
- in all the tables, `Host` and `Port` columns are now merged into a single
147+
`Host:Port`
148+
- `sshproxyctl get_config` has been removed and replaced by
149+
`sshproxyctl show config`
150+
- `sshproxyctl show hosts` and `sshproxyctl show users -all` now display
151+
persist info
152+
- `sshproxyctl enable HOST [PORT]` has been removed and replaced by
153+
`sshproxyctl enable -all|-host HOST [-port PORT]`
154+
- `sshproxyctl disable HOST [PORT]` has been removed and replaced by
155+
`sshproxyctl disable -all|-host HOST [-port PORT]`
156+
- `sshproxyctl forget HOST [PORT]` has been removed and replaced by
157+
`sshproxyctl forget host -all|-host HOST [-port PORT]`
158+
- `sshproxyctl error_banner` (without any parameter) has been removed and
159+
replaced by `sshproxyctl forget error_banner`
160+
87161
Copying
88162
-------
89163

cmd/sshproxyctl/sshproxyctl.go

+130-61
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ var (
3535
// SshproxyVersion is set by Makefile
3636
SshproxyVersion = "0.0.0+noproperlybuilt"
3737
defaultConfig = "/etc/sshproxy/sshproxy.yaml"
38-
defaultHostPort = "22"
3938
)
4039

4140
func mustInitEtcdClient(configFile string) *utils.Client {
@@ -536,6 +535,13 @@ func setErrorBanner(errorBanner string, expire time.Time, configFile string) err
536535
return cli.SetErrorBanner(errorBanner, expire)
537536
}
538537

538+
func delErrorBanner(configFile string) error {
539+
cli := mustInitEtcdClient(configFile)
540+
defer cli.Close()
541+
542+
return cli.DelErrorBanner()
543+
}
544+
539545
func showErrorBanner(configFile string) {
540546
cli := mustInitEtcdClient(configFile)
541547
defer cli.Close()
@@ -592,7 +598,7 @@ The commands are:
592598
version show version number and exit
593599
show show states present in etcd
594600
enable enable a host in etcd
595-
forget forget a host in etcd
601+
forget forget a host/error_banner in etcd
596602
disable disable a host in etcd
597603
error_banner set the error banner in etcd
598604
@@ -654,39 +660,53 @@ The options are:
654660
return fs
655661
}
656662

657-
func newEnableParser() *flag.FlagSet {
663+
func newEnableParser(allFlag *bool, hostString *string, portString *string) *flag.FlagSet {
658664
fs := flag.NewFlagSet("enable", flag.ExitOnError)
665+
fs.BoolVar(allFlag, "all", false, "enable all hosts present in config")
666+
fs.StringVar(hostString, "host", "", "hostname to enable (can be a nodeset)")
667+
fs.StringVar(portString, "port", "", "port to enable (can be a nodeset)")
659668
fs.Usage = func() {
660-
fmt.Fprintf(flag.CommandLine.Output(), `Usage: %s enable HOST [PORT]
669+
fmt.Fprintf(flag.CommandLine.Output(), `Usage: %s enable -all|-host HOST [-port PORT]
661670
662-
Enable a previously disabled host in etcd. The default port is %s. Host and port
663-
can be nodesets.
664-
`, os.Args[0], defaultHostPort)
671+
Enable a previously disabled host in etcd.
672+
`, os.Args[0])
673+
fs.PrintDefaults()
665674
os.Exit(2)
666675
}
667676
return fs
668677
}
669678

670-
func newForgetParser() *flag.FlagSet {
679+
func newForgetParser(allFlag *bool, hostString *string, portString *string) *flag.FlagSet {
671680
fs := flag.NewFlagSet("forget", flag.ExitOnError)
681+
fs.BoolVar(allFlag, "all", false, "forget all hosts present in config")
682+
fs.StringVar(hostString, "host", "", "hostname to forget (can be a nodeset)")
683+
fs.StringVar(portString, "port", "", "port to forget (can be a nodeset)")
672684
fs.Usage = func() {
673-
fmt.Fprintf(flag.CommandLine.Output(), `Usage: %s forget HOST [PORT]
685+
fmt.Fprintf(flag.CommandLine.Output(), `Usage: %s forget COMMAND [OPTIONS]
674686
675-
Forget a host in etcd. The default port is %s. Remember that if this host is
676-
used, it will appear back in the list. Host and port can be nodesets.
677-
`, os.Args[0], defaultHostPort)
687+
The commands are:
688+
host -all|-host HOST [-port PORT] forget a host in etcd
689+
error_banner forget the error_banner in etcd
690+
691+
The options are:
692+
`, os.Args[0])
693+
fs.PrintDefaults()
678694
os.Exit(2)
679695
}
680696
return fs
681697
}
682698

683-
func newDisableParser() *flag.FlagSet {
699+
func newDisableParser(allFlag *bool, hostString *string, portString *string) *flag.FlagSet {
684700
fs := flag.NewFlagSet("disable", flag.ExitOnError)
701+
fs.BoolVar(allFlag, "all", false, "disable all hosts present in config")
702+
fs.StringVar(hostString, "host", "", "hostname to disable (can be a nodeset)")
703+
fs.StringVar(portString, "port", "", "port to disable (can be a nodeset)")
685704
fs.Usage = func() {
686-
fmt.Fprintf(flag.CommandLine.Output(), `Usage: %s disable HOST [PORT]
705+
fmt.Fprintf(flag.CommandLine.Output(), `Usage: %s disable -all|-host HOST [-port PORT]
687706
688-
Disable a host in etcd. The default port is %s. Host and port can be nodesets.
689-
`, os.Args[0], defaultHostPort)
707+
Disable a host in etcd.
708+
`, os.Args[0])
709+
fs.PrintDefaults()
690710
os.Exit(2)
691711
}
692712
return fs
@@ -708,53 +728,66 @@ The options are:
708728
return fs
709729
}
710730

711-
func getHostPortFromCommandLine(args []string) ([]string, []string, error) {
731+
func getHostPortFromCommandLine(allFlag bool, hostsNodeset string, portsNodeset string, configFile string) ([]string, error) {
712732
_, nodesetDlclose, nodesetExpand := nodesets.InitExpander()
713733
defer nodesetDlclose()
714-
hostsNodeset, portsNodeset := "", defaultHostPort
715-
switch len(args) {
716-
case 2:
717-
hostsNodeset, portsNodeset = args[0], args[1]
718-
case 1:
719-
hostsNodeset = args[0]
720-
default:
721-
return []string{}, []string{}, fmt.Errorf("wrong number of arguments")
722-
}
723734

724-
hosts, err := nodesetExpand(hostsNodeset)
735+
configDests, err := utils.LoadAllDestsFromConfig(configFile)
725736
if err != nil {
726-
return []string{}, []string{}, fmt.Errorf("%s", err)
737+
return []string{}, fmt.Errorf("%s", err)
727738
}
728-
ports, err := nodesetExpand(portsNodeset)
729-
if err != nil {
730-
return []string{}, []string{}, fmt.Errorf("%s", err)
739+
740+
if allFlag && portsNodeset == "" {
741+
return configDests, nil
742+
}
743+
744+
var hosts []string
745+
var ports []string
746+
for _, configDest := range configDests {
747+
host, port, err := utils.SplitHostPort(configDest)
748+
if err != nil {
749+
return []string{}, fmt.Errorf("%s", err)
750+
}
751+
hosts = append(hosts, host)
752+
ports = append(ports, port)
753+
}
754+
755+
if !allFlag {
756+
hosts, err = nodesetExpand(hostsNodeset)
757+
if err != nil {
758+
return []string{}, fmt.Errorf("%s", err)
759+
}
731760
}
761+
762+
if portsNodeset != "" {
763+
ports, err = nodesetExpand(portsNodeset)
764+
if err != nil {
765+
return []string{}, fmt.Errorf("%s", err)
766+
}
767+
}
768+
769+
var hostPorts []string
732770
for _, port := range ports {
733771
if iport, err := strconv.Atoi(port); err != nil {
734-
return []string{}, []string{}, fmt.Errorf("port \"%s\" must be an integer", port)
772+
return []string{}, fmt.Errorf("port \"%s\" must be an integer", port)
735773
} else if iport < 0 || iport > 65535 {
736-
return []string{}, []string{}, fmt.Errorf("port \"%s\" must be in the 0-65535 range", port)
774+
return []string{}, fmt.Errorf("port \"%s\" must be in the 0-65535 range", port)
737775
}
738776
for _, host := range hosts {
739777
if _, _, err := net.SplitHostPort(host + ":" + port); err != nil {
740-
return []string{}, []string{}, fmt.Errorf("%s", err)
778+
return []string{}, fmt.Errorf("%s", err)
741779
}
780+
hostPorts = append(hostPorts, host+":"+port)
742781
}
743782
}
744-
return hosts, ports, nil
783+
return hostPorts, nil
745784
}
746785

747786
func getErrorBannerFromCommandLine(args []string) (string, error) {
748-
errorBanner := ""
749-
switch len(args) {
750-
case 0:
751-
errorBanner = ""
752-
case 1:
753-
errorBanner = args[0]
754-
default:
755-
return "", fmt.Errorf("wrong number of arguments")
787+
if len(args) == 1 {
788+
return args[0], nil
756789
}
757-
return errorBanner, nil
790+
return "", fmt.Errorf("wrong number of arguments")
758791
}
759792

760793
func byteToHuman(b int, passthrough bool) string {
@@ -831,14 +864,16 @@ func main() {
831864
var userString string
832865
var groupsString string
833866
var sourceString string
867+
var hostString string
868+
var portString string
834869

835870
parsers := map[string]*flag.FlagSet{
836871
"help": newHelpParser(),
837872
"version": newVersionParser(),
838873
"show": newShowParser(&csvFlag, &jsonFlag, &allFlag, &userString, &groupsString, &sourceString),
839-
"enable": newEnableParser(),
840-
"forget": newForgetParser(),
841-
"disable": newDisableParser(),
874+
"enable": newEnableParser(&allFlag, &hostString, &portString),
875+
"forget": newForgetParser(&allFlag, &hostString, &portString),
876+
"disable": newDisableParser(&allFlag, &hostString, &portString),
842877
"error_banner": newErrorBannerParser(&expire),
843878
}
844879

@@ -866,7 +901,7 @@ func main() {
866901
p := parsers[cmd]
867902
p.Parse(args)
868903
if p.NArg() == 0 {
869-
fmt.Fprintf(os.Stderr, "ERROR: missing 'hosts' or 'connections'\n\n")
904+
fmt.Fprintf(os.Stderr, "ERROR: missing 'hosts', 'connections', 'users', 'groups', 'error_banner' or 'config'\n\n")
870905
p.Usage()
871906
}
872907
subcmd := p.Arg(0)
@@ -893,41 +928,75 @@ func main() {
893928
case "enable":
894929
p := parsers[cmd]
895930
p.Parse(args)
896-
hosts, ports, err := getHostPortFromCommandLine(p.Args())
931+
if !allFlag && hostString == "" {
932+
fmt.Fprintf(os.Stderr, "ERROR: missing '-all' or '-host'\n\n")
933+
p.Usage()
934+
}
935+
hostPorts, err := getHostPortFromCommandLine(allFlag, hostString, portString, *configFile)
897936
if err != nil {
898937
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err)
899938
p.Usage()
900939
}
901-
for _, host := range hosts {
902-
for _, port := range ports {
903-
enableHost(host, port, *configFile)
940+
for _, hostPort := range hostPorts {
941+
host, port, err := utils.SplitHostPort(hostPort)
942+
if err != nil {
943+
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err)
944+
p.Usage()
904945
}
946+
enableHost(host, port, *configFile)
905947
}
906948
case "forget":
907949
p := parsers[cmd]
908950
p.Parse(args)
909-
hosts, ports, err := getHostPortFromCommandLine(p.Args())
910-
if err != nil {
911-
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err)
951+
if p.NArg() == 0 {
952+
fmt.Fprintf(os.Stderr, "ERROR: missing 'host' or 'error_banner'\n\n")
912953
p.Usage()
913954
}
914-
for _, host := range hosts {
915-
for _, port := range ports {
955+
subcmd := p.Arg(0)
956+
// parse flags after subcommand
957+
args = p.Args()[1:]
958+
p.Parse(args)
959+
switch subcmd {
960+
case "host":
961+
if !allFlag && hostString == "" {
962+
fmt.Fprintf(os.Stderr, "ERROR: missing '-all' or '-host'\n\n")
963+
p.Usage()
964+
}
965+
hostPorts, err := getHostPortFromCommandLine(allFlag, hostString, portString, *configFile)
966+
if err != nil {
967+
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err)
968+
p.Usage()
969+
}
970+
for _, hostPort := range hostPorts {
971+
host, port, err := utils.SplitHostPort(hostPort)
972+
if err != nil {
973+
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err)
974+
p.Usage()
975+
}
916976
forgetHost(host, port, *configFile)
917977
}
978+
case "error_banner":
979+
delErrorBanner(*configFile)
918980
}
919981
case "disable":
920982
p := parsers[cmd]
921983
p.Parse(args)
922-
hosts, ports, err := getHostPortFromCommandLine(p.Args())
984+
if !allFlag && hostString == "" {
985+
fmt.Fprintf(os.Stderr, "ERROR: missing '-all' or '-host'\n\n")
986+
p.Usage()
987+
}
988+
hostPorts, err := getHostPortFromCommandLine(allFlag, hostString, portString, *configFile)
923989
if err != nil {
924990
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err)
925991
p.Usage()
926992
}
927-
for _, host := range hosts {
928-
for _, port := range ports {
929-
disableHost(host, port, *configFile)
993+
for _, hostPort := range hostPorts {
994+
host, port, err := utils.SplitHostPort(hostPort)
995+
if err != nil {
996+
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err)
997+
p.Usage()
930998
}
999+
disableHost(host, port, *configFile)
9311000
}
9321001
case "error_banner":
9331002
p := parsers[cmd]

0 commit comments

Comments
 (0)