Check-in [3b303ae685]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added a "jobs" command and some basic work towards supporting passwords
Timelines: family | ancestors | trunk
Files: files | file ages | folders
SHA1:3b303ae685e73bd021df12c447367de759945f67
User & Date: rkeene 2014-07-03 06:21:59
Context
2014-07-03
06:21
Added a "jobs" command and some basic work towards supporting passwords Leaf check-in: 3b303ae685 user: rkeene tags: trunk
2014-07-02
06:36
Updated to use "eval" in the shell for safer execution check-in: 6cdd98d6d0 user: rkeene tags: trunk
Changes

Changes to bin/netexec.

1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
24







25
26
27
28
29
30
31
..
32
33
34
35
36
37
38





39
40
41
42
43
44
45
46
47
48
49





50
51
52
53
54
55
56
..
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
74
75
76
77


78
79
80
81
82
83
84
..
92
93
94
95
96
97
98

99
100








101
102
103
104
105
106
107
108
109
...
118
119
120
121
122
123
124
125




126
127
128
129
130
131
132
...
142
143
144
145
146
147
148













149


150
151
152
153
154
155
156
...
161
162
163
164
165
166
167


















168
169
170
171
172
173
174
175
176
177





178
179
180
181
182
183
184
#! /usr/bin/env tclsh

set sshopts [list]
lappend sshopts -o ForwardAgent=no -o StrictHostKeyChecking=no -o CheckHostIP=yes -o UserKnownHostsFile=$env(HOME)/.ssh/netexec_known_hosts
lappend sshopts -o PasswordAuthentication=no -o BatchMode=yes -o PreferredAuthentications=publickey
lappend sshopts -o RequestTTY=no

lappend auto_path ../lib

package require getopt


getopt flag arg $argv {
	-h - --help {
		help
	}
	-D: {
		set opts(delay) $arg
	}
	-f: {
		set opts(file) $arg
	}
	-g: {
		lappend opts(groups) $arg
	}







	unknown {
		puts stderr "Unknown option: \"$arg\""

		exit 1
	}
	missing {
		puts stderr "Option (\"$arg\") requires a value"
................................................................................

		exit 1
	}
	arglist {
		set argv $arg
	}
}






set hosts $opts(file)

proc shell_quote {arg} {
	set retval [string map [list "'" "'\\''"] $arg]

	return $retval
}

proc issue_command_to_host {host cmdid} {
	set sock $::socks($host)






	catch {
		puts -nonewline $sock "echo START_$cmdid;"
		puts -nonewline $sock "eval '[shell_quote $::commands($cmdid)]';"
		puts -nonewline $sock "echo;"
		puts $sock "echo END_$cmdid;"

................................................................................
		flush $sock
	}
}

proc issue_command {cmd hosts} {
	set cmdid [expr rand()][expr rand()][expr rand()][expr rand()][expr rand()]
	set ::commands($cmdid) $cmd


	foreach host $hosts {
		set ::host_data([list $host $cmdid]) [list]
		set ::commands_completed($cmdid) [list]

		issue_command_to_host $host $cmdid
	}

	while 1 {
		vwait ::commands_completed($cmdid)

		if {[llength $::commands_completed($cmdid)] == [llength $hosts]} {
			break
		}


	}

	unset ::commands($cmdid)
	unset ::commands_completed($cmdid)

	set retval [list]
	foreach host $hosts {
................................................................................
	}

	return $retval
}

proc get_data_from_host {host sock} {


	gets $sock line









	if {[info exists ::debug]} {
		puts stderr "$host\($sock) -> $line"
		flush stderr
	}

	foreach cmdid [array names ::commands] {
		if {$line == "START_$cmdid"} {
			set ::host_command($host) $cmdid

................................................................................
		}
	}

	if {[info exists ::host_command($host)]} {
		set cmdid $::host_command($host)
	}

	if {[eof $sock]} {




		catch {
			close $sock
		}

		if {[info exists cmdid]} {
			if {[lsearch -exact $::commands_completed($cmdid) $host] == -1} {
				lappend ::commands_completed($cmdid) $host
................................................................................
	}

	lappend ::host_data([list $host $cmdid]) $line
	
}

proc connect_host {host} {













	set ::socks($host) [open |[list ssh {*}$::sshopts $host 2>@1] "w+"]


	fileevent $::socks($host) readable [list get_data_from_host $host $::socks($host)]
}

proc prompt {} {
	puts -nonewline "netexec$ "
	flush stdout
}
................................................................................
			foreach host [array names ::socks] {
				catch {
					close $::socks($host)
				}
			}
			exit
		}


















		"" {
			return [list]
		}
	}

	set hosts [array names ::socks]

	# Direct input
	if {[array names ::commands] != ""} {
		foreach host $hosts {





			puts $::socks($host) $cmd
			flush $::socks($host)
		}

		return [list]
	}





<






>













>
>
>
>
>
>
>







 







>
>
>
>
>











>
>
>
>
>







 







>



<





<
<



>
>







 







>
|
|
>
>
>
>
>
>
>
>

|







 







|
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










>
>
>
>
>







1
2
3
4

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
..
74
75
76
77
78
79
80
81
82
83
84

85
86
87
88
89


90
91
92
93
94
95
96
97
98
99
100
101
...
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#! /usr/bin/env tclsh

set sshopts [list]
lappend sshopts -o ForwardAgent=no -o StrictHostKeyChecking=no -o CheckHostIP=yes -o UserKnownHostsFile=$env(HOME)/.ssh/netexec_known_hosts

lappend sshopts -o RequestTTY=no

lappend auto_path ../lib

package require getopt

set ::debug 1
getopt flag arg $argv {
	-h - --help {
		help
	}
	-D: {
		set opts(delay) $arg
	}
	-f: {
		set opts(file) $arg
	}
	-g: {
		lappend opts(groups) $arg
	}
	-p {
		puts -nonewline "Password: "
		flush stdout

		gets stdin password
		set opts(password) $password
	}
	unknown {
		puts stderr "Unknown option: \"$arg\""

		exit 1
	}
	missing {
		puts stderr "Option (\"$arg\") requires a value"
................................................................................

		exit 1
	}
	arglist {
		set argv $arg
	}
}
if {![info exists opts(password)]} {
	lappend sshopts -o PasswordAuthentication=no -o BatchMode=yes -o PreferredAuthentications=publickey
} else {
	lappend sshopts -o PubkeyAuthentication=no
}

set hosts $opts(file)

proc shell_quote {arg} {
	set retval [string map [list "'" "'\\''"] $arg]

	return $retval
}

proc issue_command_to_host {host cmdid} {
	set sock $::socks($host)

	if {[info exists ::debug]} {
		puts stderr "\[OUT-CMD\] ${host}: $::commands($cmdid)"
		flush stderr
	}

	catch {
		puts -nonewline $sock "echo START_$cmdid;"
		puts -nonewline $sock "eval '[shell_quote $::commands($cmdid)]';"
		puts -nonewline $sock "echo;"
		puts $sock "echo END_$cmdid;"

................................................................................
		flush $sock
	}
}

proc issue_command {cmd hosts} {
	set cmdid [expr rand()][expr rand()][expr rand()][expr rand()][expr rand()]
	set ::commands($cmdid) $cmd
	set ::commands_completed($cmdid) [list]

	foreach host $hosts {
		set ::host_data([list $host $cmdid]) [list]


		issue_command_to_host $host $cmdid
	}

	while 1 {


		if {[llength $::commands_completed($cmdid)] == [llength $hosts]} {
			break
		}

		vwait ::commands_completed($cmdid)
	}

	unset ::commands($cmdid)
	unset ::commands_completed($cmdid)

	set retval [list]
	foreach host $hosts {
................................................................................
	}

	return $retval
}

proc get_data_from_host {host sock} {

	catch {
		gets $sock line
	}

	if {![info exists line]} {
		set eof 1
		set line ""
	} else {
		set eof [eof $sock]
	}

	if {[info exists ::debug]} {
		puts stderr "\[IN\] $host\($sock) -> $line"
		flush stderr
	}

	foreach cmdid [array names ::commands] {
		if {$line == "START_$cmdid"} {
			set ::host_command($host) $cmdid

................................................................................
		}
	}

	if {[info exists ::host_command($host)]} {
		set cmdid $::host_command($host)
	}

	if {$eof} {
		if {[info exists ::debug]} {
			puts stderr "\[IN\] $host\($sock) EOF"
		}

		catch {
			close $sock
		}

		if {[info exists cmdid]} {
			if {[lsearch -exact $::commands_completed($cmdid) $host] == -1} {
				lappend ::commands_completed($cmdid) $host
................................................................................
	}

	lappend ::host_data([list $host $cmdid]) $line
	
}

proc connect_host {host} {
	if {[info exists ::opts(password)]} {
		package require Expect
		log_user 0

		spawn ssh {*}$::sshopts $host
		set ::socks($host) [exp_open]

		puts $::socks($host) ""
		puts $::socks($host) $::opts(password)
		flush $::socks($host)

		fconfigure $::socks($host) -blocking 0
	} else {
		set ::socks($host) [open |[list ssh {*}$::sshopts $host 2>@1] "w+"]
	}

	fileevent $::socks($host) readable [list get_data_from_host $host $::socks($host)]
}

proc prompt {} {
	puts -nonewline "netexec$ "
	flush stdout
}
................................................................................
			foreach host [array names ::socks] {
				catch {
					close $::socks($host)
				}
			}
			exit
		}
		"jobs" {
			foreach cmdid [array names ::commands] {
				puts "Job: $cmdid"
				foreach host_cmdid [array names ::host_data [list * $cmdid]] {
					set host [lindex $host_cmdid 0]

					if {[lsearch -exact $::commands_completed($cmdid) $host] == -1} {
						set status RUNNING
					} else {
						set status DONE
					}

					puts "  $host: $status"
				}
			}

			return [list]
		}
		"" {
			return [list]
		}
	}

	set hosts [array names ::socks]

	# Direct input
	if {[array names ::commands] != ""} {
		foreach host $hosts {
			if {[info exists ::debug]} {
				puts stderr "\[OUT-IMM\] ${host}: $cmd"
				flush stderr
			}

			puts $::socks($host) $cmd
			flush $::socks($host)
		}

		return [list]
	}