mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	switch to use gliderlabs/ssh for builtin server (#7250)
resolves git conflicts from #3896 (credit to @belak, in case github doesn't keep original author during squash) Co-Authored-By: Matti Ranta <techknowlogick@gitea.io>
This commit is contained in:
		
							
								
								
									
										8
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.mod
									
									
									
									
									
								
							@@ -40,7 +40,7 @@ require (
 | 
				
			|||||||
	github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
 | 
						github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
 | 
				
			||||||
	github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4 // indirect
 | 
						github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4 // indirect
 | 
				
			||||||
	github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
 | 
						github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
 | 
				
			||||||
	github.com/gliderlabs/ssh v0.1.4 // indirect
 | 
						github.com/gliderlabs/ssh v0.2.2
 | 
				
			||||||
	github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd // indirect
 | 
						github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd // indirect
 | 
				
			||||||
	github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
 | 
						github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
 | 
				
			||||||
	github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
 | 
						github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
 | 
				
			||||||
@@ -110,11 +110,11 @@ require (
 | 
				
			|||||||
	github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53
 | 
						github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53
 | 
				
			||||||
	go.etcd.io/bbolt v1.3.2 // indirect
 | 
						go.etcd.io/bbolt v1.3.2 // indirect
 | 
				
			||||||
	golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443
 | 
						golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443
 | 
				
			||||||
	golang.org/x/net v0.0.0-20190613194153-d28f0bde5980
 | 
						golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b
 | 
				
			||||||
	golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759
 | 
						golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759
 | 
				
			||||||
	golang.org/x/sys v0.0.0-20190618155005-516e3c20635f
 | 
						golang.org/x/sys v0.0.0-20190620070143-6f217b454f45
 | 
				
			||||||
	golang.org/x/text v0.3.2
 | 
						golang.org/x/text v0.3.2
 | 
				
			||||||
	golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a // indirect
 | 
						golang.org/x/tools v0.0.0-20190620154339-431033348dd0 // indirect
 | 
				
			||||||
	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
 | 
						gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
 | 
				
			||||||
	gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect
 | 
						gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect
 | 
				
			||||||
	gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect
 | 
						gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								go.sum
									
									
									
									
									
								
							@@ -100,8 +100,8 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI
 | 
				
			|||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 | 
					github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 | 
				
			||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
					github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
				
			||||||
github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 | 
					github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 | 
				
			||||||
github.com/gliderlabs/ssh v0.1.4 h1:5N8AYXpaQAPy0L7linKa5aI+WRfyYagAhjksVzxh+mI=
 | 
					github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
 | 
				
			||||||
github.com/gliderlabs/ssh v0.1.4/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 | 
					github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 | 
				
			||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04MMPyLHj/QwZuMJ5+7tJcBr1AQjpiAK/rZWRrQT7o=
 | 
					github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04MMPyLHj/QwZuMJ5+7tJcBr1AQjpiAK/rZWRrQT7o=
 | 
				
			||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
 | 
					github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
 | 
				
			||||||
github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e h1:SiEs4J3BKVIeaWrH3tKaz3QLZhJ68iJ/A4xrzIoE5+Y=
 | 
					github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e h1:SiEs4J3BKVIeaWrH3tKaz3QLZhJ68iJ/A4xrzIoE5+Y=
 | 
				
			||||||
@@ -369,8 +369,8 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r
 | 
				
			|||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
					golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
				
			||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
					golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
				
			||||||
golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
					golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
				
			||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
 | 
					golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b h1:lkjdUzSyJ5P1+eal9fxXX9Xg2BTfswsonKUse48C0uE=
 | 
				
			||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
					golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
				
			||||||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
					golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
				
			||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
					golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
				
			||||||
golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 h1:TMrx+Qdx7uJAeUbv15N72h5Hmyb5+VDjEiMufAEAM04=
 | 
					golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 h1:TMrx+Qdx7uJAeUbv15N72h5Hmyb5+VDjEiMufAEAM04=
 | 
				
			||||||
@@ -395,15 +395,15 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqY
 | 
				
			|||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20190618155005-516e3c20635f h1:dHNZYIYdq2QuU6w73vZ/DzesPbVlZVYZTtTZmrnsbQ8=
 | 
					golang.org/x/sys v0.0.0-20190620070143-6f217b454f45 h1:Dl2hc890lrizvUppGbRWhnIh2f8jOTCQpY5IKWRS0oM=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20190618155005-516e3c20635f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 | 
					golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 | 
				
			||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
					golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
				
			||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 | 
					golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 | 
				
			||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 | 
					golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
					golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a h1:aQmaYPOmKItb96VioBrTlYay5tSNUdKAFEhPCWMeLSM=
 | 
					golang.org/x/tools v0.0.0-20190620154339-431033348dd0 h1:qUGDNmGEM+ZBtwF9vuzEv+9nQQPL+l/oNBZ+DCDTAyo=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20190618163018-fdf1049a943a/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 | 
					golang.org/x/tools v0.0.0-20190620154339-431033348dd0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 | 
				
			||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 | 
					google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 | 
				
			||||||
google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24=
 | 
					google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24=
 | 
				
			||||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 | 
					google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@ LFS_CONTENT_PATH = data/lfs-mssql
 | 
				
			|||||||
OFFLINE_MODE     = false
 | 
					OFFLINE_MODE     = false
 | 
				
			||||||
LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
					LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
				
			||||||
APP_DATA_PATH    = integrations/gitea-integration-mssql/data
 | 
					APP_DATA_PATH    = integrations/gitea-integration-mssql/data
 | 
				
			||||||
 | 
					BUILTIN_SSH_SERVER_USER = git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[mailer]
 | 
					[mailer]
 | 
				
			||||||
ENABLED = true
 | 
					ENABLED = true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@ LFS_CONTENT_PATH = data/lfs-mysql
 | 
				
			|||||||
OFFLINE_MODE     = false
 | 
					OFFLINE_MODE     = false
 | 
				
			||||||
LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
					LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
				
			||||||
APP_DATA_PATH    = integrations/gitea-integration-mysql/data
 | 
					APP_DATA_PATH    = integrations/gitea-integration-mysql/data
 | 
				
			||||||
 | 
					BUILTIN_SSH_SERVER_USER = git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[mailer]
 | 
					[mailer]
 | 
				
			||||||
ENABLED = true
 | 
					ENABLED = true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@ LFS_CONTENT_PATH = data/lfs-mysql8
 | 
				
			|||||||
OFFLINE_MODE     = false
 | 
					OFFLINE_MODE     = false
 | 
				
			||||||
LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
					LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
				
			||||||
APP_DATA_PATH    = integrations/gitea-integration-mysql8/data
 | 
					APP_DATA_PATH    = integrations/gitea-integration-mysql8/data
 | 
				
			||||||
 | 
					BUILTIN_SSH_SERVER_USER = git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[mailer]
 | 
					[mailer]
 | 
				
			||||||
ENABLED = false
 | 
					ENABLED = false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@ LFS_CONTENT_PATH = data/lfs-pgsql
 | 
				
			|||||||
OFFLINE_MODE     = false
 | 
					OFFLINE_MODE     = false
 | 
				
			||||||
LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
					LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
				
			||||||
APP_DATA_PATH    = integrations/gitea-integration-pgsql/data
 | 
					APP_DATA_PATH    = integrations/gitea-integration-pgsql/data
 | 
				
			||||||
 | 
					BUILTIN_SSH_SERVER_USER = git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[mailer]
 | 
					[mailer]
 | 
				
			||||||
ENABLED = true
 | 
					ENABLED = true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@ func TestViewRepo1CloneLinkAuthorized(t *testing.T) {
 | 
				
			|||||||
	assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
 | 
						assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
 | 
				
			||||||
	link, exists = htmlDoc.doc.Find("#repo-clone-ssh").Attr("data-link")
 | 
						link, exists = htmlDoc.doc.Find("#repo-clone-ssh").Attr("data-link")
 | 
				
			||||||
	assert.True(t, exists, "The template has changed")
 | 
						assert.True(t, exists, "The template has changed")
 | 
				
			||||||
	sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.RunUser, setting.SSH.Domain, setting.SSH.Port)
 | 
						sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.SSH.BuiltinServerUser, setting.SSH.Domain, setting.SSH.Port)
 | 
				
			||||||
	assert.Equal(t, sshURL, link)
 | 
						assert.Equal(t, sshURL, link)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,7 @@ OFFLINE_MODE     = false
 | 
				
			|||||||
LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
					LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
				
			||||||
APP_DATA_PATH    = integrations/gitea-integration-sqlite/data
 | 
					APP_DATA_PATH    = integrations/gitea-integration-sqlite/data
 | 
				
			||||||
ENABLE_GZIP      = true
 | 
					ENABLE_GZIP      = true
 | 
				
			||||||
 | 
					BUILTIN_SSH_SERVER_USER = git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[mailer]
 | 
					[mailer]
 | 
				
			||||||
ENABLED     = true
 | 
					ENABLED     = true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
					 | 
				
			||||||
// Copyright 2017 The Gitea Authors. All rights reserved.
 | 
					// Copyright 2017 The Gitea Authors. All rights reserved.
 | 
				
			||||||
// Use of this source code is governed by a MIT-style
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
// license that can be found in the LICENSE file.
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
@@ -10,178 +9,157 @@ import (
 | 
				
			|||||||
	"crypto/rsa"
 | 
						"crypto/rsa"
 | 
				
			||||||
	"crypto/x509"
 | 
						"crypto/x509"
 | 
				
			||||||
	"encoding/pem"
 | 
						"encoding/pem"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
					 | 
				
			||||||
	"net"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
	"github.com/Unknwon/com"
 | 
						"syscall"
 | 
				
			||||||
	"golang.org/x/crypto/ssh"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/Unknwon/com"
 | 
				
			||||||
 | 
						"github.com/gliderlabs/ssh"
 | 
				
			||||||
 | 
						gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func cleanCommand(cmd string) string {
 | 
					type contextKey string
 | 
				
			||||||
	i := strings.Index(cmd, "git")
 | 
					 | 
				
			||||||
	if i == -1 {
 | 
					 | 
				
			||||||
		return cmd
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return cmd[i:]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
 | 
					const giteaKeyID = contextKey("gitea-key-id")
 | 
				
			||||||
	for newChan := range chans {
 | 
					
 | 
				
			||||||
		if newChan.ChannelType() != "session" {
 | 
					func getExitStatusFromError(err error) int {
 | 
				
			||||||
			err := newChan.Reject(ssh.UnknownChannelType, "unknown channel type")
 | 
						if err == nil {
 | 
				
			||||||
			if err != nil {
 | 
							return 0
 | 
				
			||||||
				log.Error("Error rejecting channel: %v", err)
 | 
						}
 | 
				
			||||||
			}
 | 
					
 | 
				
			||||||
			continue
 | 
						exitErr, ok := err.(*exec.ExitError)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						waitStatus, ok := exitErr.Sys().(syscall.WaitStatus)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							// This is a fallback and should at least let us return something useful
 | 
				
			||||||
 | 
							// when running on Windows, even if it isn't completely accurate.
 | 
				
			||||||
 | 
							if exitErr.Success() {
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ch, reqs, err := newChan.Accept()
 | 
							return 1
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log.Error("Error accepting channel: %v", err)
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		go func(in <-chan *ssh.Request) {
 | 
					 | 
				
			||||||
			defer func() {
 | 
					 | 
				
			||||||
				if err = ch.Close(); err != nil {
 | 
					 | 
				
			||||||
					log.Error("Close: %v", err)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}()
 | 
					 | 
				
			||||||
			for req := range in {
 | 
					 | 
				
			||||||
				payload := cleanCommand(string(req.Payload))
 | 
					 | 
				
			||||||
				switch req.Type {
 | 
					 | 
				
			||||||
				case "exec":
 | 
					 | 
				
			||||||
					cmdName := strings.TrimLeft(payload, "'()")
 | 
					 | 
				
			||||||
					log.Trace("SSH: Payload: %v", cmdName)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					args := []string{"serv", "key-" + keyID, "--config=" + setting.CustomConf}
 | 
					 | 
				
			||||||
					log.Trace("SSH: Arguments: %v", args)
 | 
					 | 
				
			||||||
					cmd := exec.Command(setting.AppPath, args...)
 | 
					 | 
				
			||||||
					cmd.Env = append(
 | 
					 | 
				
			||||||
						os.Environ(),
 | 
					 | 
				
			||||||
						"SSH_ORIGINAL_COMMAND="+cmdName,
 | 
					 | 
				
			||||||
						"SKIP_MINWINSVC=1",
 | 
					 | 
				
			||||||
					)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					stdout, err := cmd.StdoutPipe()
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						log.Error("SSH: StdoutPipe: %v", err)
 | 
					 | 
				
			||||||
						return
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					stderr, err := cmd.StderrPipe()
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						log.Error("SSH: StderrPipe: %v", err)
 | 
					 | 
				
			||||||
						return
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					input, err := cmd.StdinPipe()
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						log.Error("SSH: StdinPipe: %v", err)
 | 
					 | 
				
			||||||
						return
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					// FIXME: check timeout
 | 
					 | 
				
			||||||
					if err = cmd.Start(); err != nil {
 | 
					 | 
				
			||||||
						log.Error("SSH: Start: %v", err)
 | 
					 | 
				
			||||||
						return
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					err = req.Reply(true, nil)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						log.Error("SSH: Reply: %v", err)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					go func() {
 | 
					 | 
				
			||||||
						_, err = io.Copy(input, ch)
 | 
					 | 
				
			||||||
						if err != nil {
 | 
					 | 
				
			||||||
							log.Error("SSH: Copy: %v", err)
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}()
 | 
					 | 
				
			||||||
					_, err = io.Copy(ch, stdout)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						log.Error("SSH: Copy: %v", err)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					_, err = io.Copy(ch.Stderr(), stderr)
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						log.Error("SSH: Copy: %v", err)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if err = cmd.Wait(); err != nil {
 | 
					 | 
				
			||||||
						log.Error("SSH: Wait: %v", err)
 | 
					 | 
				
			||||||
						return
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					_, err = ch.SendRequest("exit-status", false, []byte{0, 0, 0, 0})
 | 
					 | 
				
			||||||
					if err != nil {
 | 
					 | 
				
			||||||
						log.Error("SSH: SendRequest: %v", err)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return
 | 
					 | 
				
			||||||
				default:
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}(reqs)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return waitStatus.ExitStatus()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func listen(config *ssh.ServerConfig, host string, port int) {
 | 
					func sessionHandler(session ssh.Session) {
 | 
				
			||||||
	listener, err := net.Listen("tcp", host+":"+com.ToStr(port))
 | 
						keyID := session.Context().Value(giteaKeyID).(int64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						command := session.RawCommand()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Trace("SSH: Payload: %v", command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						args := []string{"serv", "key-" + com.ToStr(keyID), "--config=" + setting.CustomConf}
 | 
				
			||||||
 | 
						log.Trace("SSH: Arguments: %v", args)
 | 
				
			||||||
 | 
						cmd := exec.Command(setting.AppPath, args...)
 | 
				
			||||||
 | 
						cmd.Env = append(
 | 
				
			||||||
 | 
							os.Environ(),
 | 
				
			||||||
 | 
							"SSH_ORIGINAL_COMMAND="+command,
 | 
				
			||||||
 | 
							"SKIP_MINWINSVC=1",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stdout, err := cmd.StdoutPipe()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatal("Failed to start SSH server: %v", err)
 | 
							log.Error("SSH: StdoutPipe: %v", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for {
 | 
						stderr, err := cmd.StderrPipe()
 | 
				
			||||||
		// Once a ServerConfig has been configured, connections can be accepted.
 | 
						if err != nil {
 | 
				
			||||||
		conn, err := listener.Accept()
 | 
							log.Error("SSH: StderrPipe: %v", err)
 | 
				
			||||||
		if err != nil {
 | 
							return
 | 
				
			||||||
			log.Error("SSH: Error accepting incoming connection: %v", err)
 | 
						}
 | 
				
			||||||
			continue
 | 
						stdin, err := cmd.StdinPipe()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("SSH: StdinPipe: %v", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wg := &sync.WaitGroup{}
 | 
				
			||||||
 | 
						wg.Add(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err = cmd.Start(); err != nil {
 | 
				
			||||||
 | 
							log.Error("SSH: Start: %v", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							defer stdin.Close()
 | 
				
			||||||
 | 
							if _, err := io.Copy(stdin, session); err != nil {
 | 
				
			||||||
 | 
								log.Error("Failed to write session to stdin. %s", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Before use, a handshake must be performed on the incoming net.Conn.
 | 
						go func() {
 | 
				
			||||||
		// It must be handled in a separate goroutine,
 | 
							defer wg.Done()
 | 
				
			||||||
		// otherwise one user could easily block entire loop.
 | 
							if _, err := io.Copy(session, stdout); err != nil {
 | 
				
			||||||
		// For example, user could be asked to trust server key fingerprint and hangs.
 | 
								log.Error("Failed to write stdout to session. %s", err)
 | 
				
			||||||
		go func() {
 | 
							}
 | 
				
			||||||
			log.Trace("SSH: Handshaking for %s", conn.RemoteAddr())
 | 
						}()
 | 
				
			||||||
			sConn, chans, reqs, err := ssh.NewServerConn(conn, config)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				if err == io.EOF {
 | 
					 | 
				
			||||||
					log.Warn("SSH: Handshaking with %s was terminated: %v", conn.RemoteAddr(), err)
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					log.Error("SSH: Error on handshaking with %s: %v", conn.RemoteAddr(), err)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			log.Trace("SSH: Connection from %s (%s)", sConn.RemoteAddr(), sConn.ClientVersion())
 | 
						go func() {
 | 
				
			||||||
			// The incoming Request channel must be serviced.
 | 
							defer wg.Done()
 | 
				
			||||||
			go ssh.DiscardRequests(reqs)
 | 
							if _, err := io.Copy(session.Stderr(), stderr); err != nil {
 | 
				
			||||||
			go handleServerConn(sConn.Permissions.Extensions["key-id"], chans)
 | 
								log.Error("Failed to write stderr to session. %s", err)
 | 
				
			||||||
		}()
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Ensure all the output has been written before we wait on the command
 | 
				
			||||||
 | 
						// to exit.
 | 
				
			||||||
 | 
						wg.Wait()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Wait for the command to exit and log any errors we get
 | 
				
			||||||
 | 
						err = cmd.Wait()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("SSH: Wait: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := session.Exit(getExitStatusFromError(err)); err != nil {
 | 
				
			||||||
 | 
							log.Error("Session failed to exit. %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool {
 | 
				
			||||||
 | 
						if ctx.User() != setting.SSH.BuiltinServerUser {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key))))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("SearchPublicKeyByContent: %v", err)
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.SetValue(giteaKeyID, pkey.ID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Listen starts a SSH server listens on given port.
 | 
					// Listen starts a SSH server listens on given port.
 | 
				
			||||||
func Listen(host string, port int, ciphers []string, keyExchanges []string, macs []string) {
 | 
					func Listen(host string, port int, ciphers []string, keyExchanges []string, macs []string) {
 | 
				
			||||||
	config := &ssh.ServerConfig{
 | 
						// TODO: Handle ciphers, keyExchanges, and macs
 | 
				
			||||||
		Config: ssh.Config{
 | 
					
 | 
				
			||||||
			Ciphers:      ciphers,
 | 
						srv := ssh.Server{
 | 
				
			||||||
			KeyExchanges: keyExchanges,
 | 
							Addr:             fmt.Sprintf("%s:%d", host, port),
 | 
				
			||||||
			MACs:         macs,
 | 
							PublicKeyHandler: publicKeyHandler,
 | 
				
			||||||
		},
 | 
							Handler:          sessionHandler,
 | 
				
			||||||
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
 | 
					
 | 
				
			||||||
			pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))))
 | 
							// We need to explicitly disable the PtyCallback so text displays
 | 
				
			||||||
			if err != nil {
 | 
							// properly.
 | 
				
			||||||
				log.Error("SearchPublicKeyByContent: %v", err)
 | 
							PtyCallback: func(ctx ssh.Context, pty ssh.Pty) bool {
 | 
				
			||||||
				return nil, err
 | 
								return false
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return &ssh.Permissions{Extensions: map[string]string{"key-id": com.ToStr(pkey.ID)}}, nil
 | 
					 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -197,20 +175,21 @@ func Listen(host string, port int, ciphers []string, keyExchanges []string, macs
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatal("Failed to generate private key: %v", err)
 | 
								log.Fatal("Failed to generate private key: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		log.Trace("SSH: New private key is generateed: %s", keyPath)
 | 
							log.Trace("New private key is generated: %s", keyPath)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	privateBytes, err := ioutil.ReadFile(keyPath)
 | 
						err := srv.SetOption(ssh.HostKeyFile(keyPath))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatal("SSH: Failed to load private key")
 | 
							log.Error("Failed to set Host Key. %s", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	private, err := ssh.ParsePrivateKey(privateBytes)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal("SSH: Failed to parse private key")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	config.AddHostKey(private)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go listen(config, host, port)
 | 
						go func() {
 | 
				
			||||||
 | 
							err := srv.ListenAndServe()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Error("Failed to serve with builtin SSH server. %s", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GenKeyPair make a pair of public and private keys for SSH access.
 | 
					// GenKeyPair make a pair of public and private keys for SSH access.
 | 
				
			||||||
@@ -238,12 +217,12 @@ func GenKeyPair(keyPath string) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// generate public key
 | 
						// generate public key
 | 
				
			||||||
	pub, err := ssh.NewPublicKey(&privateKey.PublicKey)
 | 
						pub, err := gossh.NewPublicKey(&privateKey.PublicKey)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public := ssh.MarshalAuthorizedKey(pub)
 | 
						public := gossh.MarshalAuthorizedKey(pub)
 | 
				
			||||||
	p, err := os.OpenFile(keyPath+".pub", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
 | 
						p, err := os.OpenFile(keyPath+".pub", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/github.com/anmitsu/go-shlex/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/anmitsu/go-shlex/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					shlex.test
 | 
				
			||||||
							
								
								
									
										20
									
								
								vendor/github.com/anmitsu/go-shlex/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/anmitsu/go-shlex/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					Copyright (c) anmitsu <anmitsu.s@gmail.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining
 | 
				
			||||||
 | 
					a copy of this software and associated documentation files (the
 | 
				
			||||||
 | 
					"Software"), to deal in the Software without restriction, including
 | 
				
			||||||
 | 
					without limitation the rights to use, copy, modify, merge, publish,
 | 
				
			||||||
 | 
					distribute, sublicense, and/or sell copies of the Software, and to
 | 
				
			||||||
 | 
					permit persons to whom the Software is furnished to do so, subject to
 | 
				
			||||||
 | 
					the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be
 | 
				
			||||||
 | 
					included in all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
				
			||||||
 | 
					EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
				
			||||||
 | 
					MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
				
			||||||
 | 
					NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 | 
				
			||||||
 | 
					LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | 
				
			||||||
 | 
					OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | 
				
			||||||
 | 
					WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
							
								
								
									
										38
									
								
								vendor/github.com/anmitsu/go-shlex/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/anmitsu/go-shlex/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					# go-shlex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					go-shlex is a library to make a lexical analyzer like Unix shell for
 | 
				
			||||||
 | 
					Go.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    go get -u "github.com/anmitsu/go-shlex"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
					    "fmt"
 | 
				
			||||||
 | 
					    "log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    "github.com/anmitsu/go-shlex"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
					    cmd := `cp -Rdp "file name" 'file name2' dir\ name`
 | 
				
			||||||
 | 
					    words, err := shlex.Split(cmd, true)
 | 
				
			||||||
 | 
					    if err != nil {
 | 
				
			||||||
 | 
					        log.Fatal(err)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for _, w := range words {
 | 
				
			||||||
 | 
					        fmt.Println(w)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					http://godoc.org/github.com/anmitsu/go-shlex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										193
									
								
								vendor/github.com/anmitsu/go-shlex/shlex.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								vendor/github.com/anmitsu/go-shlex/shlex.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,193 @@
 | 
				
			|||||||
 | 
					// Package shlex provides a simple lexical analysis like Unix shell.
 | 
				
			||||||
 | 
					package shlex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"unicode"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						ErrNoClosing = errors.New("No closing quotation")
 | 
				
			||||||
 | 
						ErrNoEscaped = errors.New("No escaped character")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tokenizer is the interface that classifies a token according to
 | 
				
			||||||
 | 
					// words, whitespaces, quotations, escapes and escaped quotations.
 | 
				
			||||||
 | 
					type Tokenizer interface {
 | 
				
			||||||
 | 
						IsWord(rune) bool
 | 
				
			||||||
 | 
						IsWhitespace(rune) bool
 | 
				
			||||||
 | 
						IsQuote(rune) bool
 | 
				
			||||||
 | 
						IsEscape(rune) bool
 | 
				
			||||||
 | 
						IsEscapedQuote(rune) bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DefaultTokenizer implements a simple tokenizer like Unix shell.
 | 
				
			||||||
 | 
					type DefaultTokenizer struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t *DefaultTokenizer) IsWord(r rune) bool {
 | 
				
			||||||
 | 
						return r == '_' || unicode.IsLetter(r) || unicode.IsNumber(r)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (t *DefaultTokenizer) IsQuote(r rune) bool {
 | 
				
			||||||
 | 
						switch r {
 | 
				
			||||||
 | 
						case '\'', '"':
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (t *DefaultTokenizer) IsWhitespace(r rune) bool {
 | 
				
			||||||
 | 
						return unicode.IsSpace(r)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (t *DefaultTokenizer) IsEscape(r rune) bool {
 | 
				
			||||||
 | 
						return r == '\\'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (t *DefaultTokenizer) IsEscapedQuote(r rune) bool {
 | 
				
			||||||
 | 
						return r == '"'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Lexer represents a lexical analyzer.
 | 
				
			||||||
 | 
					type Lexer struct {
 | 
				
			||||||
 | 
						reader          *bufio.Reader
 | 
				
			||||||
 | 
						tokenizer       Tokenizer
 | 
				
			||||||
 | 
						posix           bool
 | 
				
			||||||
 | 
						whitespacesplit bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewLexer creates a new Lexer reading from io.Reader.  This Lexer
 | 
				
			||||||
 | 
					// has a DefaultTokenizer according to posix and whitespacesplit
 | 
				
			||||||
 | 
					// rules.
 | 
				
			||||||
 | 
					func NewLexer(r io.Reader, posix, whitespacesplit bool) *Lexer {
 | 
				
			||||||
 | 
						return &Lexer{
 | 
				
			||||||
 | 
							reader:          bufio.NewReader(r),
 | 
				
			||||||
 | 
							tokenizer:       &DefaultTokenizer{},
 | 
				
			||||||
 | 
							posix:           posix,
 | 
				
			||||||
 | 
							whitespacesplit: whitespacesplit,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewLexerString creates a new Lexer reading from a string.  This
 | 
				
			||||||
 | 
					// Lexer has a DefaultTokenizer according to posix and whitespacesplit
 | 
				
			||||||
 | 
					// rules.
 | 
				
			||||||
 | 
					func NewLexerString(s string, posix, whitespacesplit bool) *Lexer {
 | 
				
			||||||
 | 
						return NewLexer(strings.NewReader(s), posix, whitespacesplit)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Split splits a string according to posix or non-posix rules.
 | 
				
			||||||
 | 
					func Split(s string, posix bool) ([]string, error) {
 | 
				
			||||||
 | 
						return NewLexerString(s, posix, true).Split()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetTokenizer sets a Tokenizer.
 | 
				
			||||||
 | 
					func (l *Lexer) SetTokenizer(t Tokenizer) {
 | 
				
			||||||
 | 
						l.tokenizer = t
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l *Lexer) Split() ([]string, error) {
 | 
				
			||||||
 | 
						result := make([]string, 0)
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							token, err := l.readToken()
 | 
				
			||||||
 | 
							if token != "" {
 | 
				
			||||||
 | 
								result = append(result, token)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err == io.EOF {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							} else if err != nil {
 | 
				
			||||||
 | 
								return result, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l *Lexer) readToken() (string, error) {
 | 
				
			||||||
 | 
						t := l.tokenizer
 | 
				
			||||||
 | 
						token := ""
 | 
				
			||||||
 | 
						quoted := false
 | 
				
			||||||
 | 
						state := ' '
 | 
				
			||||||
 | 
						escapedstate := ' '
 | 
				
			||||||
 | 
					scanning:
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							next, _, err := l.reader.ReadRune()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if t.IsQuote(state) {
 | 
				
			||||||
 | 
									return token, ErrNoClosing
 | 
				
			||||||
 | 
								} else if t.IsEscape(state) {
 | 
				
			||||||
 | 
									return token, ErrNoEscaped
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return token, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch {
 | 
				
			||||||
 | 
							case t.IsWhitespace(state):
 | 
				
			||||||
 | 
								switch {
 | 
				
			||||||
 | 
								case t.IsWhitespace(next):
 | 
				
			||||||
 | 
									break scanning
 | 
				
			||||||
 | 
								case l.posix && t.IsEscape(next):
 | 
				
			||||||
 | 
									escapedstate = 'a'
 | 
				
			||||||
 | 
									state = next
 | 
				
			||||||
 | 
								case t.IsWord(next):
 | 
				
			||||||
 | 
									token += string(next)
 | 
				
			||||||
 | 
									state = 'a'
 | 
				
			||||||
 | 
								case t.IsQuote(next):
 | 
				
			||||||
 | 
									if !l.posix {
 | 
				
			||||||
 | 
										token += string(next)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									state = next
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									token = string(next)
 | 
				
			||||||
 | 
									if l.whitespacesplit {
 | 
				
			||||||
 | 
										state = 'a'
 | 
				
			||||||
 | 
									} else if token != "" || (l.posix && quoted) {
 | 
				
			||||||
 | 
										break scanning
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case t.IsQuote(state):
 | 
				
			||||||
 | 
								quoted = true
 | 
				
			||||||
 | 
								switch {
 | 
				
			||||||
 | 
								case next == state:
 | 
				
			||||||
 | 
									if !l.posix {
 | 
				
			||||||
 | 
										token += string(next)
 | 
				
			||||||
 | 
										break scanning
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										state = 'a'
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case l.posix && t.IsEscape(next) && t.IsEscapedQuote(state):
 | 
				
			||||||
 | 
									escapedstate = state
 | 
				
			||||||
 | 
									state = next
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									token += string(next)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case t.IsEscape(state):
 | 
				
			||||||
 | 
								if t.IsQuote(escapedstate) && next != state && next != escapedstate {
 | 
				
			||||||
 | 
									token += string(state)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								token += string(next)
 | 
				
			||||||
 | 
								state = escapedstate
 | 
				
			||||||
 | 
							case t.IsWord(state):
 | 
				
			||||||
 | 
								switch {
 | 
				
			||||||
 | 
								case t.IsWhitespace(next):
 | 
				
			||||||
 | 
									if token != "" || (l.posix && quoted) {
 | 
				
			||||||
 | 
										break scanning
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case l.posix && t.IsQuote(next):
 | 
				
			||||||
 | 
									state = next
 | 
				
			||||||
 | 
								case l.posix && t.IsEscape(next):
 | 
				
			||||||
 | 
									escapedstate = 'a'
 | 
				
			||||||
 | 
									state = next
 | 
				
			||||||
 | 
								case t.IsWord(next) || t.IsQuote(next):
 | 
				
			||||||
 | 
									token += string(next)
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									if l.whitespacesplit {
 | 
				
			||||||
 | 
										token += string(next)
 | 
				
			||||||
 | 
									} else if token != "" {
 | 
				
			||||||
 | 
										l.reader.UnreadRune()
 | 
				
			||||||
 | 
										break scanning
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return token, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								vendor/github.com/gliderlabs/ssh/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/gliderlabs/ssh/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					Copyright (c) 2016 Glider Labs. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					met:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					   * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					distribution.
 | 
				
			||||||
 | 
					   * Neither the name of Glider Labs nor the names of its
 | 
				
			||||||
 | 
					contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					this software without specific prior written permission.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
							
								
								
									
										96
									
								
								vendor/github.com/gliderlabs/ssh/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								vendor/github.com/gliderlabs/ssh/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					# gliderlabs/ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[](https://godoc.org/github.com/gliderlabs/ssh) 
 | 
				
			||||||
 | 
					[](https://circleci.com/gh/gliderlabs/ssh)
 | 
				
			||||||
 | 
					[](https://goreportcard.com/report/github.com/gliderlabs/ssh) 
 | 
				
			||||||
 | 
					[](#sponsors)
 | 
				
			||||||
 | 
					[](http://slack.gliderlabs.com) 
 | 
				
			||||||
 | 
					[](https://app.convertkit.com/landing_pages/243312)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> The Glider Labs SSH server package is dope.  —[@bradfitz](https://twitter.com/bradfitz), Go team member
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This Go package wraps the [crypto/ssh
 | 
				
			||||||
 | 
					package](https://godoc.org/golang.org/x/crypto/ssh) with a higher-level API for
 | 
				
			||||||
 | 
					building SSH servers. The goal of the API was to make it as simple as using
 | 
				
			||||||
 | 
					[net/http](https://golang.org/pkg/net/http/), so the API is very similar:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					 package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 import (
 | 
				
			||||||
 | 
					     "github.com/gliderlabs/ssh"
 | 
				
			||||||
 | 
					     "io"
 | 
				
			||||||
 | 
					     "log"
 | 
				
			||||||
 | 
					 )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 func main() {
 | 
				
			||||||
 | 
					     ssh.Handle(func(s ssh.Session) {
 | 
				
			||||||
 | 
					         io.WriteString(s, "Hello world\n")
 | 
				
			||||||
 | 
					     })  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     log.Fatal(ssh.ListenAndServe(":2222", nil))
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					This package was built by [@progrium](https://twitter.com/progrium) after working on nearly a dozen projects at Glider Labs using SSH and collaborating with [@shazow](https://twitter.com/shazow) (known for [ssh-chat](https://github.com/shazow/ssh-chat)).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A bunch of great examples are in the `_examples` directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[See GoDoc reference.](https://godoc.org/github.com/gliderlabs/ssh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Contributing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Pull requests are welcome! However, since this project is very much about API
 | 
				
			||||||
 | 
					design, please submit API changes as issues to discuss before submitting PRs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also, you can [join our Slack](http://slack.gliderlabs.com) to discuss as well.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Roadmap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Non-session channel handlers
 | 
				
			||||||
 | 
					* Cleanup callback API
 | 
				
			||||||
 | 
					* 1.0 release
 | 
				
			||||||
 | 
					* High-level client?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Sponsors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/ssh#sponsor)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/0/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/1/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/2/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/3/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/4/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/5/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/6/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/7/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/8/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/9/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/10/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/11/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/11/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/12/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/12/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/13/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/13/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/14/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/14/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/15/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/15/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/16/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/16/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/17/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/17/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/18/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/18/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/19/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/19/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/20/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/20/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/21/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/21/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/22/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/22/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/23/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/23/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/24/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/24/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/25/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/25/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/26/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/26/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/27/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/27/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/28/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/28/avatar.svg"></a>
 | 
				
			||||||
 | 
					<a href="https://opencollective.com/ssh/sponsor/29/website" target="_blank"><img src="https://opencollective.com/ssh/sponsor/29/avatar.svg"></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BSD
 | 
				
			||||||
							
								
								
									
										83
									
								
								vendor/github.com/gliderlabs/ssh/agent.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								vendor/github.com/gliderlabs/ssh/agent.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						agentRequestType = "auth-agent-req@openssh.com"
 | 
				
			||||||
 | 
						agentChannelType = "auth-agent@openssh.com"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						agentTempDir    = "auth-agent"
 | 
				
			||||||
 | 
						agentListenFile = "listener.sock"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// contextKeyAgentRequest is an internal context key for storing if the
 | 
				
			||||||
 | 
					// client requested agent forwarding
 | 
				
			||||||
 | 
					var contextKeyAgentRequest = &contextKey{"auth-agent-req"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetAgentRequested sets up the session context so that AgentRequested
 | 
				
			||||||
 | 
					// returns true.
 | 
				
			||||||
 | 
					func SetAgentRequested(ctx Context) {
 | 
				
			||||||
 | 
						ctx.SetValue(contextKeyAgentRequest, true)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AgentRequested returns true if the client requested agent forwarding.
 | 
				
			||||||
 | 
					func AgentRequested(sess Session) bool {
 | 
				
			||||||
 | 
						return sess.Context().Value(contextKeyAgentRequest) == true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewAgentListener sets up a temporary Unix socket that can be communicated
 | 
				
			||||||
 | 
					// to the session environment and used for forwarding connections.
 | 
				
			||||||
 | 
					func NewAgentListener() (net.Listener, error) {
 | 
				
			||||||
 | 
						dir, err := ioutil.TempDir("", agentTempDir)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						l, err := net.Listen("unix", path.Join(dir, agentListenFile))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return l, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ForwardAgentConnections takes connections from a listener to proxy into the
 | 
				
			||||||
 | 
					// session on the OpenSSH channel for agent connections. It blocks and services
 | 
				
			||||||
 | 
					// connections until the listener stop accepting.
 | 
				
			||||||
 | 
					func ForwardAgentConnections(l net.Listener, s Session) {
 | 
				
			||||||
 | 
						sshConn := s.Context().Value(ContextKeyConn).(gossh.Conn)
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							conn, err := l.Accept()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							go func(conn net.Conn) {
 | 
				
			||||||
 | 
								defer conn.Close()
 | 
				
			||||||
 | 
								channel, reqs, err := sshConn.OpenChannel(agentChannelType, nil)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								defer channel.Close()
 | 
				
			||||||
 | 
								go gossh.DiscardRequests(reqs)
 | 
				
			||||||
 | 
								var wg sync.WaitGroup
 | 
				
			||||||
 | 
								wg.Add(2)
 | 
				
			||||||
 | 
								go func() {
 | 
				
			||||||
 | 
									io.Copy(conn, channel)
 | 
				
			||||||
 | 
									conn.(*net.UnixConn).CloseWrite()
 | 
				
			||||||
 | 
									wg.Done()
 | 
				
			||||||
 | 
								}()
 | 
				
			||||||
 | 
								go func() {
 | 
				
			||||||
 | 
									io.Copy(channel, conn)
 | 
				
			||||||
 | 
									channel.CloseWrite()
 | 
				
			||||||
 | 
									wg.Done()
 | 
				
			||||||
 | 
								}()
 | 
				
			||||||
 | 
								wg.Wait()
 | 
				
			||||||
 | 
							}(conn)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								vendor/github.com/gliderlabs/ssh/circle.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/gliderlabs/ssh/circle.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					version: 2
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  build-go-latest:
 | 
				
			||||||
 | 
					    docker:
 | 
				
			||||||
 | 
					    - image: golang:latest
 | 
				
			||||||
 | 
					    working_directory: /go/src/github.com/gliderlabs/ssh
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					    - checkout
 | 
				
			||||||
 | 
					    - run: go get
 | 
				
			||||||
 | 
					    - run: go test -v -race
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  build-go-1.9:
 | 
				
			||||||
 | 
					    docker:
 | 
				
			||||||
 | 
					    - image: golang:1.9
 | 
				
			||||||
 | 
					    working_directory: /go/src/github.com/gliderlabs/ssh
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					    - checkout
 | 
				
			||||||
 | 
					    - run: go get
 | 
				
			||||||
 | 
					    - run: go test -v -race
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					workflows:
 | 
				
			||||||
 | 
					  version: 2
 | 
				
			||||||
 | 
					  build:
 | 
				
			||||||
 | 
					    jobs:
 | 
				
			||||||
 | 
					      - build-go-latest
 | 
				
			||||||
 | 
					      - build-go-1.9
 | 
				
			||||||
							
								
								
									
										55
									
								
								vendor/github.com/gliderlabs/ssh/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/gliderlabs/ssh/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type serverConn struct {
 | 
				
			||||||
 | 
						net.Conn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						idleTimeout   time.Duration
 | 
				
			||||||
 | 
						maxDeadline   time.Time
 | 
				
			||||||
 | 
						closeCanceler context.CancelFunc
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *serverConn) Write(p []byte) (n int, err error) {
 | 
				
			||||||
 | 
						c.updateDeadline()
 | 
				
			||||||
 | 
						n, err = c.Conn.Write(p)
 | 
				
			||||||
 | 
						if _, isNetErr := err.(net.Error); isNetErr && c.closeCanceler != nil {
 | 
				
			||||||
 | 
							c.closeCanceler()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *serverConn) Read(b []byte) (n int, err error) {
 | 
				
			||||||
 | 
						c.updateDeadline()
 | 
				
			||||||
 | 
						n, err = c.Conn.Read(b)
 | 
				
			||||||
 | 
						if _, isNetErr := err.(net.Error); isNetErr && c.closeCanceler != nil {
 | 
				
			||||||
 | 
							c.closeCanceler()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *serverConn) Close() (err error) {
 | 
				
			||||||
 | 
						err = c.Conn.Close()
 | 
				
			||||||
 | 
						if c.closeCanceler != nil {
 | 
				
			||||||
 | 
							c.closeCanceler()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *serverConn) updateDeadline() {
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case c.idleTimeout > 0:
 | 
				
			||||||
 | 
							idleDeadline := time.Now().Add(c.idleTimeout)
 | 
				
			||||||
 | 
							if idleDeadline.Unix() < c.maxDeadline.Unix() || c.maxDeadline.IsZero() {
 | 
				
			||||||
 | 
								c.Conn.SetDeadline(idleDeadline)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fallthrough
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							c.Conn.SetDeadline(c.maxDeadline)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										152
									
								
								vendor/github.com/gliderlabs/ssh/context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								vendor/github.com/gliderlabs/ssh/context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// contextKey is a value for use with context.WithValue. It's used as
 | 
				
			||||||
 | 
					// a pointer so it fits in an interface{} without allocation.
 | 
				
			||||||
 | 
					type contextKey struct {
 | 
				
			||||||
 | 
						name string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						// ContextKeyUser is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type string.
 | 
				
			||||||
 | 
						ContextKeyUser = &contextKey{"user"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ContextKeySessionID is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type string.
 | 
				
			||||||
 | 
						ContextKeySessionID = &contextKey{"session-id"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ContextKeyPermissions is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type *Permissions.
 | 
				
			||||||
 | 
						ContextKeyPermissions = &contextKey{"permissions"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ContextKeyClientVersion is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type string.
 | 
				
			||||||
 | 
						ContextKeyClientVersion = &contextKey{"client-version"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ContextKeyServerVersion is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type string.
 | 
				
			||||||
 | 
						ContextKeyServerVersion = &contextKey{"server-version"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ContextKeyLocalAddr is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type net.Addr.
 | 
				
			||||||
 | 
						ContextKeyLocalAddr = &contextKey{"local-addr"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ContextKeyRemoteAddr is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type net.Addr.
 | 
				
			||||||
 | 
						ContextKeyRemoteAddr = &contextKey{"remote-addr"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ContextKeyServer is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type *Server.
 | 
				
			||||||
 | 
						ContextKeyServer = &contextKey{"ssh-server"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ContextKeyConn is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type gossh.ServerConn.
 | 
				
			||||||
 | 
						ContextKeyConn = &contextKey{"ssh-conn"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ContextKeyPublicKey is a context key for use with Contexts in this package.
 | 
				
			||||||
 | 
						// The associated value will be of type PublicKey.
 | 
				
			||||||
 | 
						ContextKeyPublicKey = &contextKey{"public-key"}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Context is a package specific context interface. It exposes connection
 | 
				
			||||||
 | 
					// metadata and allows new values to be easily written to it. It's used in
 | 
				
			||||||
 | 
					// authentication handlers and callbacks, and its underlying context.Context is
 | 
				
			||||||
 | 
					// exposed on Session in the session Handler. A connection-scoped lock is also
 | 
				
			||||||
 | 
					// embedded in the context to make it easier to limit operations per-connection.
 | 
				
			||||||
 | 
					type Context interface {
 | 
				
			||||||
 | 
						context.Context
 | 
				
			||||||
 | 
						sync.Locker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// User returns the username used when establishing the SSH connection.
 | 
				
			||||||
 | 
						User() string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// SessionID returns the session hash.
 | 
				
			||||||
 | 
						SessionID() string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ClientVersion returns the version reported by the client.
 | 
				
			||||||
 | 
						ClientVersion() string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ServerVersion returns the version reported by the server.
 | 
				
			||||||
 | 
						ServerVersion() string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RemoteAddr returns the remote address for this connection.
 | 
				
			||||||
 | 
						RemoteAddr() net.Addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// LocalAddr returns the local address for this connection.
 | 
				
			||||||
 | 
						LocalAddr() net.Addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Permissions returns the Permissions object used for this connection.
 | 
				
			||||||
 | 
						Permissions() *Permissions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// SetValue allows you to easily write new values into the underlying context.
 | 
				
			||||||
 | 
						SetValue(key, value interface{})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type sshContext struct {
 | 
				
			||||||
 | 
						context.Context
 | 
				
			||||||
 | 
						*sync.Mutex
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newContext(srv *Server) (*sshContext, context.CancelFunc) {
 | 
				
			||||||
 | 
						innerCtx, cancel := context.WithCancel(context.Background())
 | 
				
			||||||
 | 
						ctx := &sshContext{innerCtx, &sync.Mutex{}}
 | 
				
			||||||
 | 
						ctx.SetValue(ContextKeyServer, srv)
 | 
				
			||||||
 | 
						perms := &Permissions{&gossh.Permissions{}}
 | 
				
			||||||
 | 
						ctx.SetValue(ContextKeyPermissions, perms)
 | 
				
			||||||
 | 
						return ctx, cancel
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// this is separate from newContext because we will get ConnMetadata
 | 
				
			||||||
 | 
					// at different points so it needs to be applied separately
 | 
				
			||||||
 | 
					func applyConnMetadata(ctx Context, conn gossh.ConnMetadata) {
 | 
				
			||||||
 | 
						if ctx.Value(ContextKeySessionID) != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.SetValue(ContextKeySessionID, hex.EncodeToString(conn.SessionID()))
 | 
				
			||||||
 | 
						ctx.SetValue(ContextKeyClientVersion, string(conn.ClientVersion()))
 | 
				
			||||||
 | 
						ctx.SetValue(ContextKeyServerVersion, string(conn.ServerVersion()))
 | 
				
			||||||
 | 
						ctx.SetValue(ContextKeyUser, conn.User())
 | 
				
			||||||
 | 
						ctx.SetValue(ContextKeyLocalAddr, conn.LocalAddr())
 | 
				
			||||||
 | 
						ctx.SetValue(ContextKeyRemoteAddr, conn.RemoteAddr())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ctx *sshContext) SetValue(key, value interface{}) {
 | 
				
			||||||
 | 
						ctx.Context = context.WithValue(ctx.Context, key, value)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ctx *sshContext) User() string {
 | 
				
			||||||
 | 
						return ctx.Value(ContextKeyUser).(string)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ctx *sshContext) SessionID() string {
 | 
				
			||||||
 | 
						return ctx.Value(ContextKeySessionID).(string)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ctx *sshContext) ClientVersion() string {
 | 
				
			||||||
 | 
						return ctx.Value(ContextKeyClientVersion).(string)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ctx *sshContext) ServerVersion() string {
 | 
				
			||||||
 | 
						return ctx.Value(ContextKeyServerVersion).(string)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ctx *sshContext) RemoteAddr() net.Addr {
 | 
				
			||||||
 | 
						return ctx.Value(ContextKeyRemoteAddr).(net.Addr)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ctx *sshContext) LocalAddr() net.Addr {
 | 
				
			||||||
 | 
						return ctx.Value(ContextKeyLocalAddr).(net.Addr)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ctx *sshContext) Permissions() *Permissions {
 | 
				
			||||||
 | 
						return ctx.Value(ContextKeyPermissions).(*Permissions)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										45
									
								
								vendor/github.com/gliderlabs/ssh/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/gliderlabs/ssh/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Package ssh wraps the crypto/ssh package with a higher-level API for building
 | 
				
			||||||
 | 
					SSH servers. The goal of the API was to make it as simple as using net/http, so
 | 
				
			||||||
 | 
					the API is very similar.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You should be able to build any SSH server using only this package, which wraps
 | 
				
			||||||
 | 
					relevant types and some functions from crypto/ssh. However, you still need to
 | 
				
			||||||
 | 
					use crypto/ssh for building SSH clients.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ListenAndServe starts an SSH server with a given address, handler, and options. The
 | 
				
			||||||
 | 
					handler is usually nil, which means to use DefaultHandler. Handle sets DefaultHandler:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ssh.Handle(func(s ssh.Session) {
 | 
				
			||||||
 | 
					      io.WriteString(s, "Hello world\n")
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  log.Fatal(ssh.ListenAndServe(":2222", nil))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you don't specify a host key, it will generate one every time. This is convenient
 | 
				
			||||||
 | 
					except you'll have to deal with clients being confused that the host key is different.
 | 
				
			||||||
 | 
					It's a better idea to generate or point to an existing key on your system:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  log.Fatal(ssh.ListenAndServe(":2222", nil, ssh.HostKeyFile("/Users/progrium/.ssh/id_rsa")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Although all options have functional option helpers, another way to control the
 | 
				
			||||||
 | 
					server's behavior is by creating a custom Server:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  s := &ssh.Server{
 | 
				
			||||||
 | 
					      Addr:             ":2222",
 | 
				
			||||||
 | 
					      Handler:          sessionHandler,
 | 
				
			||||||
 | 
					      PublicKeyHandler: authHandler,
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  s.AddHostKey(hostKeySigner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  log.Fatal(s.ListenAndServe())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This package automatically handles basic SSH requests like setting environment
 | 
				
			||||||
 | 
					variables, requesting PTY, and changing window size. These requests are
 | 
				
			||||||
 | 
					processed, responded to, and any relevant state is updated. This state is then
 | 
				
			||||||
 | 
					exposed to you via the Session interface.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The one big feature missing from the Session abstraction is signals. This was
 | 
				
			||||||
 | 
					started, but not completed. Pull Requests welcome!
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					package ssh
 | 
				
			||||||
							
								
								
									
										77
									
								
								vendor/github.com/gliderlabs/ssh/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								vendor/github.com/gliderlabs/ssh/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PasswordAuth returns a functional option that sets PasswordHandler on the server.
 | 
				
			||||||
 | 
					func PasswordAuth(fn PasswordHandler) Option {
 | 
				
			||||||
 | 
						return func(srv *Server) error {
 | 
				
			||||||
 | 
							srv.PasswordHandler = fn
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PublicKeyAuth returns a functional option that sets PublicKeyHandler on the server.
 | 
				
			||||||
 | 
					func PublicKeyAuth(fn PublicKeyHandler) Option {
 | 
				
			||||||
 | 
						return func(srv *Server) error {
 | 
				
			||||||
 | 
							srv.PublicKeyHandler = fn
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HostKeyFile returns a functional option that adds HostSigners to the server
 | 
				
			||||||
 | 
					// from a PEM file at filepath.
 | 
				
			||||||
 | 
					func HostKeyFile(filepath string) Option {
 | 
				
			||||||
 | 
						return func(srv *Server) error {
 | 
				
			||||||
 | 
							pemBytes, err := ioutil.ReadFile(filepath)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							signer, err := gossh.ParsePrivateKey(pemBytes)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							srv.AddHostKey(signer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HostKeyPEM returns a functional option that adds HostSigners to the server
 | 
				
			||||||
 | 
					// from a PEM file as bytes.
 | 
				
			||||||
 | 
					func HostKeyPEM(bytes []byte) Option {
 | 
				
			||||||
 | 
						return func(srv *Server) error {
 | 
				
			||||||
 | 
							signer, err := gossh.ParsePrivateKey(bytes)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							srv.AddHostKey(signer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NoPty returns a functional option that sets PtyCallback to return false,
 | 
				
			||||||
 | 
					// denying PTY requests.
 | 
				
			||||||
 | 
					func NoPty() Option {
 | 
				
			||||||
 | 
						return func(srv *Server) error {
 | 
				
			||||||
 | 
							srv.PtyCallback = func(ctx Context, pty Pty) bool {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WrapConn returns a functional option that sets ConnCallback on the server.
 | 
				
			||||||
 | 
					func WrapConn(fn ConnCallback) Option {
 | 
				
			||||||
 | 
						return func(srv *Server) error {
 | 
				
			||||||
 | 
							srv.ConnCallback = fn
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										394
									
								
								vendor/github.com/gliderlabs/ssh/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								vendor/github.com/gliderlabs/ssh/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,394 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ErrServerClosed is returned by the Server's Serve, ListenAndServe,
 | 
				
			||||||
 | 
					// and ListenAndServeTLS methods after a call to Shutdown or Close.
 | 
				
			||||||
 | 
					var ErrServerClosed = errors.New("ssh: Server closed")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type RequestHandler func(ctx Context, srv *Server, req *gossh.Request) (ok bool, payload []byte)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var DefaultRequestHandlers = map[string]RequestHandler{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ChannelHandler func(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var DefaultChannelHandlers = map[string]ChannelHandler{
 | 
				
			||||||
 | 
						"session": DefaultSessionHandler,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Server defines parameters for running an SSH server. The zero value for
 | 
				
			||||||
 | 
					// Server is a valid configuration. When both PasswordHandler and
 | 
				
			||||||
 | 
					// PublicKeyHandler are nil, no client authentication is performed.
 | 
				
			||||||
 | 
					type Server struct {
 | 
				
			||||||
 | 
						Addr        string   // TCP address to listen on, ":22" if empty
 | 
				
			||||||
 | 
						Handler     Handler  // handler to invoke, ssh.DefaultHandler if nil
 | 
				
			||||||
 | 
						HostSigners []Signer // private keys for the host key, must have at least one
 | 
				
			||||||
 | 
						Version     string   // server version to be sent before the initial handshake
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						KeyboardInteractiveHandler    KeyboardInteractiveHandler    // keyboard-interactive authentication handler
 | 
				
			||||||
 | 
						PasswordHandler               PasswordHandler               // password authentication handler
 | 
				
			||||||
 | 
						PublicKeyHandler              PublicKeyHandler              // public key authentication handler
 | 
				
			||||||
 | 
						PtyCallback                   PtyCallback                   // callback for allowing PTY sessions, allows all if nil
 | 
				
			||||||
 | 
						ConnCallback                  ConnCallback                  // optional callback for wrapping net.Conn before handling
 | 
				
			||||||
 | 
						LocalPortForwardingCallback   LocalPortForwardingCallback   // callback for allowing local port forwarding, denies all if nil
 | 
				
			||||||
 | 
						ReversePortForwardingCallback ReversePortForwardingCallback // callback for allowing reverse port forwarding, denies all if nil
 | 
				
			||||||
 | 
						ServerConfigCallback          ServerConfigCallback          // callback for configuring detailed SSH options
 | 
				
			||||||
 | 
						SessionRequestCallback        SessionRequestCallback        // callback for allowing or denying SSH sessions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						IdleTimeout time.Duration // connection timeout when no activity, none if empty
 | 
				
			||||||
 | 
						MaxTimeout  time.Duration // absolute connection timeout, none if empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ChannelHandlers allow overriding the built-in session handlers or provide
 | 
				
			||||||
 | 
						// extensions to the protocol, such as tcpip forwarding. By default only the
 | 
				
			||||||
 | 
						// "session" handler is enabled.
 | 
				
			||||||
 | 
						ChannelHandlers map[string]ChannelHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RequestHandlers allow overriding the server-level request handlers or
 | 
				
			||||||
 | 
						// provide extensions to the protocol, such as tcpip forwarding. By default
 | 
				
			||||||
 | 
						// no handlers are enabled.
 | 
				
			||||||
 | 
						RequestHandlers map[string]RequestHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						listenerWg sync.WaitGroup
 | 
				
			||||||
 | 
						mu         sync.Mutex
 | 
				
			||||||
 | 
						listeners  map[net.Listener]struct{}
 | 
				
			||||||
 | 
						conns      map[*gossh.ServerConn]struct{}
 | 
				
			||||||
 | 
						connWg     sync.WaitGroup
 | 
				
			||||||
 | 
						doneChan   chan struct{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) ensureHostSigner() error {
 | 
				
			||||||
 | 
						if len(srv.HostSigners) == 0 {
 | 
				
			||||||
 | 
							signer, err := generateSigner()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							srv.HostSigners = append(srv.HostSigners, signer)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) ensureHandlers() {
 | 
				
			||||||
 | 
						srv.mu.Lock()
 | 
				
			||||||
 | 
						defer srv.mu.Unlock()
 | 
				
			||||||
 | 
						if srv.RequestHandlers == nil {
 | 
				
			||||||
 | 
							srv.RequestHandlers = map[string]RequestHandler{}
 | 
				
			||||||
 | 
							for k, v := range DefaultRequestHandlers {
 | 
				
			||||||
 | 
								srv.RequestHandlers[k] = v
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srv.ChannelHandlers == nil {
 | 
				
			||||||
 | 
							srv.ChannelHandlers = map[string]ChannelHandler{}
 | 
				
			||||||
 | 
							for k, v := range DefaultChannelHandlers {
 | 
				
			||||||
 | 
								srv.ChannelHandlers[k] = v
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) config(ctx Context) *gossh.ServerConfig {
 | 
				
			||||||
 | 
						var config *gossh.ServerConfig
 | 
				
			||||||
 | 
						if srv.ServerConfigCallback == nil {
 | 
				
			||||||
 | 
							config = &gossh.ServerConfig{}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							config = srv.ServerConfigCallback(ctx)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, signer := range srv.HostSigners {
 | 
				
			||||||
 | 
							config.AddHostKey(signer)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srv.PasswordHandler == nil && srv.PublicKeyHandler == nil {
 | 
				
			||||||
 | 
							config.NoClientAuth = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srv.Version != "" {
 | 
				
			||||||
 | 
							config.ServerVersion = "SSH-2.0-" + srv.Version
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srv.PasswordHandler != nil {
 | 
				
			||||||
 | 
							config.PasswordCallback = func(conn gossh.ConnMetadata, password []byte) (*gossh.Permissions, error) {
 | 
				
			||||||
 | 
								applyConnMetadata(ctx, conn)
 | 
				
			||||||
 | 
								if ok := srv.PasswordHandler(ctx, string(password)); !ok {
 | 
				
			||||||
 | 
									return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return ctx.Permissions().Permissions, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srv.PublicKeyHandler != nil {
 | 
				
			||||||
 | 
							config.PublicKeyCallback = func(conn gossh.ConnMetadata, key gossh.PublicKey) (*gossh.Permissions, error) {
 | 
				
			||||||
 | 
								applyConnMetadata(ctx, conn)
 | 
				
			||||||
 | 
								if ok := srv.PublicKeyHandler(ctx, key); !ok {
 | 
				
			||||||
 | 
									return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.SetValue(ContextKeyPublicKey, key)
 | 
				
			||||||
 | 
								return ctx.Permissions().Permissions, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srv.KeyboardInteractiveHandler != nil {
 | 
				
			||||||
 | 
							config.KeyboardInteractiveCallback = func(conn gossh.ConnMetadata, challenger gossh.KeyboardInteractiveChallenge) (*gossh.Permissions, error) {
 | 
				
			||||||
 | 
								if ok := srv.KeyboardInteractiveHandler(ctx, challenger); !ok {
 | 
				
			||||||
 | 
									return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return ctx.Permissions().Permissions, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return config
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Handle sets the Handler for the server.
 | 
				
			||||||
 | 
					func (srv *Server) Handle(fn Handler) {
 | 
				
			||||||
 | 
						srv.Handler = fn
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Close immediately closes all active listeners and all active
 | 
				
			||||||
 | 
					// connections.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Close returns any error returned from closing the Server's
 | 
				
			||||||
 | 
					// underlying Listener(s).
 | 
				
			||||||
 | 
					func (srv *Server) Close() error {
 | 
				
			||||||
 | 
						srv.mu.Lock()
 | 
				
			||||||
 | 
						defer srv.mu.Unlock()
 | 
				
			||||||
 | 
						srv.closeDoneChanLocked()
 | 
				
			||||||
 | 
						err := srv.closeListenersLocked()
 | 
				
			||||||
 | 
						for c := range srv.conns {
 | 
				
			||||||
 | 
							c.Close()
 | 
				
			||||||
 | 
							delete(srv.conns, c)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Shutdown gracefully shuts down the server without interrupting any
 | 
				
			||||||
 | 
					// active connections. Shutdown works by first closing all open
 | 
				
			||||||
 | 
					// listeners, and then waiting indefinitely for connections to close.
 | 
				
			||||||
 | 
					// If the provided context expires before the shutdown is complete,
 | 
				
			||||||
 | 
					// then the context's error is returned.
 | 
				
			||||||
 | 
					func (srv *Server) Shutdown(ctx context.Context) error {
 | 
				
			||||||
 | 
						srv.mu.Lock()
 | 
				
			||||||
 | 
						lnerr := srv.closeListenersLocked()
 | 
				
			||||||
 | 
						srv.closeDoneChanLocked()
 | 
				
			||||||
 | 
						srv.mu.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						finished := make(chan struct{}, 1)
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							srv.listenerWg.Wait()
 | 
				
			||||||
 | 
							srv.connWg.Wait()
 | 
				
			||||||
 | 
							finished <- struct{}{}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						select {
 | 
				
			||||||
 | 
						case <-ctx.Done():
 | 
				
			||||||
 | 
							return ctx.Err()
 | 
				
			||||||
 | 
						case <-finished:
 | 
				
			||||||
 | 
							return lnerr
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Serve accepts incoming connections on the Listener l, creating a new
 | 
				
			||||||
 | 
					// connection goroutine for each. The connection goroutines read requests and then
 | 
				
			||||||
 | 
					// calls srv.Handler to handle sessions.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Serve always returns a non-nil error.
 | 
				
			||||||
 | 
					func (srv *Server) Serve(l net.Listener) error {
 | 
				
			||||||
 | 
						srv.ensureHandlers()
 | 
				
			||||||
 | 
						defer l.Close()
 | 
				
			||||||
 | 
						if err := srv.ensureHostSigner(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srv.Handler == nil {
 | 
				
			||||||
 | 
							srv.Handler = DefaultHandler
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var tempDelay time.Duration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srv.trackListener(l, true)
 | 
				
			||||||
 | 
						defer srv.trackListener(l, false)
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							conn, e := l.Accept()
 | 
				
			||||||
 | 
							if e != nil {
 | 
				
			||||||
 | 
								select {
 | 
				
			||||||
 | 
								case <-srv.getDoneChan():
 | 
				
			||||||
 | 
									return ErrServerClosed
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if ne, ok := e.(net.Error); ok && ne.Temporary() {
 | 
				
			||||||
 | 
									if tempDelay == 0 {
 | 
				
			||||||
 | 
										tempDelay = 5 * time.Millisecond
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										tempDelay *= 2
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if max := 1 * time.Second; tempDelay > max {
 | 
				
			||||||
 | 
										tempDelay = max
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									time.Sleep(tempDelay)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return e
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							go srv.handleConn(conn)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) handleConn(newConn net.Conn) {
 | 
				
			||||||
 | 
						if srv.ConnCallback != nil {
 | 
				
			||||||
 | 
							cbConn := srv.ConnCallback(newConn)
 | 
				
			||||||
 | 
							if cbConn == nil {
 | 
				
			||||||
 | 
								newConn.Close()
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							newConn = cbConn
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx, cancel := newContext(srv)
 | 
				
			||||||
 | 
						conn := &serverConn{
 | 
				
			||||||
 | 
							Conn:          newConn,
 | 
				
			||||||
 | 
							idleTimeout:   srv.IdleTimeout,
 | 
				
			||||||
 | 
							closeCanceler: cancel,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srv.MaxTimeout > 0 {
 | 
				
			||||||
 | 
							conn.maxDeadline = time.Now().Add(srv.MaxTimeout)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer conn.Close()
 | 
				
			||||||
 | 
						sshConn, chans, reqs, err := gossh.NewServerConn(conn, srv.config(ctx))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// TODO: trigger event callback
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srv.trackConn(sshConn, true)
 | 
				
			||||||
 | 
						defer srv.trackConn(sshConn, false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.SetValue(ContextKeyConn, sshConn)
 | 
				
			||||||
 | 
						applyConnMetadata(ctx, sshConn)
 | 
				
			||||||
 | 
						//go gossh.DiscardRequests(reqs)
 | 
				
			||||||
 | 
						go srv.handleRequests(ctx, reqs)
 | 
				
			||||||
 | 
						for ch := range chans {
 | 
				
			||||||
 | 
							handler := srv.ChannelHandlers[ch.ChannelType()]
 | 
				
			||||||
 | 
							if handler == nil {
 | 
				
			||||||
 | 
								handler = srv.ChannelHandlers["default"]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if handler == nil {
 | 
				
			||||||
 | 
								ch.Reject(gossh.UnknownChannelType, "unsupported channel type")
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							go handler(srv, sshConn, ch, ctx)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) handleRequests(ctx Context, in <-chan *gossh.Request) {
 | 
				
			||||||
 | 
						for req := range in {
 | 
				
			||||||
 | 
							handler := srv.RequestHandlers[req.Type]
 | 
				
			||||||
 | 
							if handler == nil {
 | 
				
			||||||
 | 
								handler = srv.RequestHandlers["default"]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if handler == nil {
 | 
				
			||||||
 | 
								req.Reply(false, nil)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/*reqCtx, cancel := context.WithCancel(ctx)
 | 
				
			||||||
 | 
							defer cancel() */
 | 
				
			||||||
 | 
							ret, payload := handler(ctx, srv, req)
 | 
				
			||||||
 | 
							req.Reply(ret, payload)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListenAndServe listens on the TCP network address srv.Addr and then calls
 | 
				
			||||||
 | 
					// Serve to handle incoming connections. If srv.Addr is blank, ":22" is used.
 | 
				
			||||||
 | 
					// ListenAndServe always returns a non-nil error.
 | 
				
			||||||
 | 
					func (srv *Server) ListenAndServe() error {
 | 
				
			||||||
 | 
						addr := srv.Addr
 | 
				
			||||||
 | 
						if addr == "" {
 | 
				
			||||||
 | 
							addr = ":22"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ln, err := net.Listen("tcp", addr)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return srv.Serve(ln)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddHostKey adds a private key as a host key. If an existing host key exists
 | 
				
			||||||
 | 
					// with the same algorithm, it is overwritten. Each server config must have at
 | 
				
			||||||
 | 
					// least one host key.
 | 
				
			||||||
 | 
					func (srv *Server) AddHostKey(key Signer) {
 | 
				
			||||||
 | 
						// these are later added via AddHostKey on ServerConfig, which performs the
 | 
				
			||||||
 | 
						// check for one of every algorithm.
 | 
				
			||||||
 | 
						srv.HostSigners = append(srv.HostSigners, key)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetOption runs a functional option against the server.
 | 
				
			||||||
 | 
					func (srv *Server) SetOption(option Option) error {
 | 
				
			||||||
 | 
						return option(srv)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) getDoneChan() <-chan struct{} {
 | 
				
			||||||
 | 
						srv.mu.Lock()
 | 
				
			||||||
 | 
						defer srv.mu.Unlock()
 | 
				
			||||||
 | 
						return srv.getDoneChanLocked()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) getDoneChanLocked() chan struct{} {
 | 
				
			||||||
 | 
						if srv.doneChan == nil {
 | 
				
			||||||
 | 
							srv.doneChan = make(chan struct{})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return srv.doneChan
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) closeDoneChanLocked() {
 | 
				
			||||||
 | 
						ch := srv.getDoneChanLocked()
 | 
				
			||||||
 | 
						select {
 | 
				
			||||||
 | 
						case <-ch:
 | 
				
			||||||
 | 
							// Already closed. Don't close again.
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							// Safe to close here. We're the only closer, guarded
 | 
				
			||||||
 | 
							// by srv.mu.
 | 
				
			||||||
 | 
							close(ch)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) closeListenersLocked() error {
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						for ln := range srv.listeners {
 | 
				
			||||||
 | 
							if cerr := ln.Close(); cerr != nil && err == nil {
 | 
				
			||||||
 | 
								err = cerr
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							delete(srv.listeners, ln)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) trackListener(ln net.Listener, add bool) {
 | 
				
			||||||
 | 
						srv.mu.Lock()
 | 
				
			||||||
 | 
						defer srv.mu.Unlock()
 | 
				
			||||||
 | 
						if srv.listeners == nil {
 | 
				
			||||||
 | 
							srv.listeners = make(map[net.Listener]struct{})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if add {
 | 
				
			||||||
 | 
							// If the *Server is being reused after a previous
 | 
				
			||||||
 | 
							// Close or Shutdown, reset its doneChan:
 | 
				
			||||||
 | 
							if len(srv.listeners) == 0 && len(srv.conns) == 0 {
 | 
				
			||||||
 | 
								srv.doneChan = nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							srv.listeners[ln] = struct{}{}
 | 
				
			||||||
 | 
							srv.listenerWg.Add(1)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							delete(srv.listeners, ln)
 | 
				
			||||||
 | 
							srv.listenerWg.Done()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (srv *Server) trackConn(c *gossh.ServerConn, add bool) {
 | 
				
			||||||
 | 
						srv.mu.Lock()
 | 
				
			||||||
 | 
						defer srv.mu.Unlock()
 | 
				
			||||||
 | 
						if srv.conns == nil {
 | 
				
			||||||
 | 
							srv.conns = make(map[*gossh.ServerConn]struct{})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if add {
 | 
				
			||||||
 | 
							srv.conns[c] = struct{}{}
 | 
				
			||||||
 | 
							srv.connWg.Add(1)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							delete(srv.conns, c)
 | 
				
			||||||
 | 
							srv.connWg.Done()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										308
									
								
								vendor/github.com/gliderlabs/ssh/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								vendor/github.com/gliderlabs/ssh/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,308 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/anmitsu/go-shlex"
 | 
				
			||||||
 | 
						gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Session provides access to information about an SSH session and methods
 | 
				
			||||||
 | 
					// to read and write to the SSH channel with an embedded Channel interface from
 | 
				
			||||||
 | 
					// cypto/ssh.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// When Command() returns an empty slice, the user requested a shell. Otherwise
 | 
				
			||||||
 | 
					// the user is performing an exec with those command arguments.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// TODO: Signals
 | 
				
			||||||
 | 
					type Session interface {
 | 
				
			||||||
 | 
						gossh.Channel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// User returns the username used when establishing the SSH connection.
 | 
				
			||||||
 | 
						User() string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RemoteAddr returns the net.Addr of the client side of the connection.
 | 
				
			||||||
 | 
						RemoteAddr() net.Addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// LocalAddr returns the net.Addr of the server side of the connection.
 | 
				
			||||||
 | 
						LocalAddr() net.Addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Environ returns a copy of strings representing the environment set by the
 | 
				
			||||||
 | 
						// user for this session, in the form "key=value".
 | 
				
			||||||
 | 
						Environ() []string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Exit sends an exit status and then closes the session.
 | 
				
			||||||
 | 
						Exit(code int) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Command returns a shell parsed slice of arguments that were provided by the
 | 
				
			||||||
 | 
						// user. Shell parsing splits the command string according to POSIX shell rules,
 | 
				
			||||||
 | 
						// which considers quoting not just whitespace.
 | 
				
			||||||
 | 
						Command() []string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RawCommand returns the exact command that was provided by the user.
 | 
				
			||||||
 | 
						RawCommand() string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// PublicKey returns the PublicKey used to authenticate. If a public key was not
 | 
				
			||||||
 | 
						// used it will return nil.
 | 
				
			||||||
 | 
						PublicKey() PublicKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Context returns the connection's context. The returned context is always
 | 
				
			||||||
 | 
						// non-nil and holds the same data as the Context passed into auth
 | 
				
			||||||
 | 
						// handlers and callbacks.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// The context is canceled when the client's connection closes or I/O
 | 
				
			||||||
 | 
						// operation fails.
 | 
				
			||||||
 | 
						Context() context.Context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Permissions returns a copy of the Permissions object that was available for
 | 
				
			||||||
 | 
						// setup in the auth handlers via the Context.
 | 
				
			||||||
 | 
						Permissions() Permissions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Pty returns PTY information, a channel of window size changes, and a boolean
 | 
				
			||||||
 | 
						// of whether or not a PTY was accepted for this session.
 | 
				
			||||||
 | 
						Pty() (Pty, <-chan Window, bool)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Signals registers a channel to receive signals sent from the client. The
 | 
				
			||||||
 | 
						// channel must handle signal sends or it will block the SSH request loop.
 | 
				
			||||||
 | 
						// Registering nil will unregister the channel from signal sends. During the
 | 
				
			||||||
 | 
						// time no channel is registered signals are buffered up to a reasonable amount.
 | 
				
			||||||
 | 
						// If there are buffered signals when a channel is registered, they will be
 | 
				
			||||||
 | 
						// sent in order on the channel immediately after registering.
 | 
				
			||||||
 | 
						Signals(c chan<- Signal)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// maxSigBufSize is how many signals will be buffered
 | 
				
			||||||
 | 
					// when there is no signal channel specified
 | 
				
			||||||
 | 
					const maxSigBufSize = 128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func DefaultSessionHandler(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context) {
 | 
				
			||||||
 | 
						ch, reqs, err := newChan.Accept()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// TODO: trigger event callback
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sess := &session{
 | 
				
			||||||
 | 
							Channel:   ch,
 | 
				
			||||||
 | 
							conn:      conn,
 | 
				
			||||||
 | 
							handler:   srv.Handler,
 | 
				
			||||||
 | 
							ptyCb:     srv.PtyCallback,
 | 
				
			||||||
 | 
							sessReqCb: srv.SessionRequestCallback,
 | 
				
			||||||
 | 
							ctx:       ctx,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sess.handleRequests(reqs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type session struct {
 | 
				
			||||||
 | 
						sync.Mutex
 | 
				
			||||||
 | 
						gossh.Channel
 | 
				
			||||||
 | 
						conn      *gossh.ServerConn
 | 
				
			||||||
 | 
						handler   Handler
 | 
				
			||||||
 | 
						handled   bool
 | 
				
			||||||
 | 
						exited    bool
 | 
				
			||||||
 | 
						pty       *Pty
 | 
				
			||||||
 | 
						winch     chan Window
 | 
				
			||||||
 | 
						env       []string
 | 
				
			||||||
 | 
						ptyCb     PtyCallback
 | 
				
			||||||
 | 
						sessReqCb SessionRequestCallback
 | 
				
			||||||
 | 
						rawCmd    string
 | 
				
			||||||
 | 
						ctx       Context
 | 
				
			||||||
 | 
						sigCh     chan<- Signal
 | 
				
			||||||
 | 
						sigBuf    []Signal
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) Write(p []byte) (n int, err error) {
 | 
				
			||||||
 | 
						if sess.pty != nil {
 | 
				
			||||||
 | 
							m := len(p)
 | 
				
			||||||
 | 
							// normalize \n to \r\n when pty is accepted.
 | 
				
			||||||
 | 
							// this is a hardcoded shortcut since we don't support terminal modes.
 | 
				
			||||||
 | 
							p = bytes.Replace(p, []byte{'\n'}, []byte{'\r', '\n'}, -1)
 | 
				
			||||||
 | 
							p = bytes.Replace(p, []byte{'\r', '\r', '\n'}, []byte{'\r', '\n'}, -1)
 | 
				
			||||||
 | 
							n, err = sess.Channel.Write(p)
 | 
				
			||||||
 | 
							if n > m {
 | 
				
			||||||
 | 
								n = m
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sess.Channel.Write(p)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) PublicKey() PublicKey {
 | 
				
			||||||
 | 
						sessionkey := sess.ctx.Value(ContextKeyPublicKey)
 | 
				
			||||||
 | 
						if sessionkey == nil {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sessionkey.(PublicKey)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) Permissions() Permissions {
 | 
				
			||||||
 | 
						// use context permissions because its properly
 | 
				
			||||||
 | 
						// wrapped and easier to dereference
 | 
				
			||||||
 | 
						perms := sess.ctx.Value(ContextKeyPermissions).(*Permissions)
 | 
				
			||||||
 | 
						return *perms
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) Context() context.Context {
 | 
				
			||||||
 | 
						return sess.ctx
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) Exit(code int) error {
 | 
				
			||||||
 | 
						sess.Lock()
 | 
				
			||||||
 | 
						defer sess.Unlock()
 | 
				
			||||||
 | 
						if sess.exited {
 | 
				
			||||||
 | 
							return errors.New("Session.Exit called multiple times")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sess.exited = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status := struct{ Status uint32 }{uint32(code)}
 | 
				
			||||||
 | 
						_, err := sess.SendRequest("exit-status", false, gossh.Marshal(&status))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sess.Close()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) User() string {
 | 
				
			||||||
 | 
						return sess.conn.User()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) RemoteAddr() net.Addr {
 | 
				
			||||||
 | 
						return sess.conn.RemoteAddr()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) LocalAddr() net.Addr {
 | 
				
			||||||
 | 
						return sess.conn.LocalAddr()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) Environ() []string {
 | 
				
			||||||
 | 
						return append([]string(nil), sess.env...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) RawCommand() string {
 | 
				
			||||||
 | 
						return sess.rawCmd
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) Command() []string {
 | 
				
			||||||
 | 
						cmd, _ := shlex.Split(sess.rawCmd, true)
 | 
				
			||||||
 | 
						return append([]string(nil), cmd...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) Pty() (Pty, <-chan Window, bool) {
 | 
				
			||||||
 | 
						if sess.pty != nil {
 | 
				
			||||||
 | 
							return *sess.pty, sess.winch, true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return Pty{}, sess.winch, false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) Signals(c chan<- Signal) {
 | 
				
			||||||
 | 
						sess.Lock()
 | 
				
			||||||
 | 
						defer sess.Unlock()
 | 
				
			||||||
 | 
						sess.sigCh = c
 | 
				
			||||||
 | 
						if len(sess.sigBuf) > 0 {
 | 
				
			||||||
 | 
							go func() {
 | 
				
			||||||
 | 
								for _, sig := range sess.sigBuf {
 | 
				
			||||||
 | 
									sess.sigCh <- sig
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sess *session) handleRequests(reqs <-chan *gossh.Request) {
 | 
				
			||||||
 | 
						for req := range reqs {
 | 
				
			||||||
 | 
							switch req.Type {
 | 
				
			||||||
 | 
							case "shell", "exec":
 | 
				
			||||||
 | 
								if sess.handled {
 | 
				
			||||||
 | 
									req.Reply(false, nil)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var payload = struct{ Value string }{}
 | 
				
			||||||
 | 
								gossh.Unmarshal(req.Payload, &payload)
 | 
				
			||||||
 | 
								sess.rawCmd = payload.Value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// If there's a session policy callback, we need to confirm before
 | 
				
			||||||
 | 
								// accepting the session.
 | 
				
			||||||
 | 
								if sess.sessReqCb != nil && !sess.sessReqCb(sess, req.Type) {
 | 
				
			||||||
 | 
									sess.rawCmd = ""
 | 
				
			||||||
 | 
									req.Reply(false, nil)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								sess.handled = true
 | 
				
			||||||
 | 
								req.Reply(true, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								go func() {
 | 
				
			||||||
 | 
									sess.handler(sess)
 | 
				
			||||||
 | 
									sess.Exit(0)
 | 
				
			||||||
 | 
								}()
 | 
				
			||||||
 | 
							case "env":
 | 
				
			||||||
 | 
								if sess.handled {
 | 
				
			||||||
 | 
									req.Reply(false, nil)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								var kv struct{ Key, Value string }
 | 
				
			||||||
 | 
								gossh.Unmarshal(req.Payload, &kv)
 | 
				
			||||||
 | 
								sess.env = append(sess.env, fmt.Sprintf("%s=%s", kv.Key, kv.Value))
 | 
				
			||||||
 | 
								req.Reply(true, nil)
 | 
				
			||||||
 | 
							case "signal":
 | 
				
			||||||
 | 
								var payload struct{ Signal string }
 | 
				
			||||||
 | 
								gossh.Unmarshal(req.Payload, &payload)
 | 
				
			||||||
 | 
								sess.Lock()
 | 
				
			||||||
 | 
								if sess.sigCh != nil {
 | 
				
			||||||
 | 
									sess.sigCh <- Signal(payload.Signal)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									if len(sess.sigBuf) < maxSigBufSize {
 | 
				
			||||||
 | 
										sess.sigBuf = append(sess.sigBuf, Signal(payload.Signal))
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								sess.Unlock()
 | 
				
			||||||
 | 
							case "pty-req":
 | 
				
			||||||
 | 
								if sess.handled || sess.pty != nil {
 | 
				
			||||||
 | 
									req.Reply(false, nil)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ptyReq, ok := parsePtyRequest(req.Payload)
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									req.Reply(false, nil)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if sess.ptyCb != nil {
 | 
				
			||||||
 | 
									ok := sess.ptyCb(sess.ctx, ptyReq)
 | 
				
			||||||
 | 
									if !ok {
 | 
				
			||||||
 | 
										req.Reply(false, nil)
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								sess.pty = &ptyReq
 | 
				
			||||||
 | 
								sess.winch = make(chan Window, 1)
 | 
				
			||||||
 | 
								sess.winch <- ptyReq.Window
 | 
				
			||||||
 | 
								defer func() {
 | 
				
			||||||
 | 
									// when reqs is closed
 | 
				
			||||||
 | 
									close(sess.winch)
 | 
				
			||||||
 | 
								}()
 | 
				
			||||||
 | 
								req.Reply(ok, nil)
 | 
				
			||||||
 | 
							case "window-change":
 | 
				
			||||||
 | 
								if sess.pty == nil {
 | 
				
			||||||
 | 
									req.Reply(false, nil)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								win, ok := parseWinchRequest(req.Payload)
 | 
				
			||||||
 | 
								if ok {
 | 
				
			||||||
 | 
									sess.pty.Window = win
 | 
				
			||||||
 | 
									sess.winch <- win
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								req.Reply(ok, nil)
 | 
				
			||||||
 | 
							case agentRequestType:
 | 
				
			||||||
 | 
								// TODO: option/callback to allow agent forwarding
 | 
				
			||||||
 | 
								SetAgentRequested(sess.ctx)
 | 
				
			||||||
 | 
								req.Reply(true, nil)
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								// TODO: debug log
 | 
				
			||||||
 | 
								req.Reply(false, nil)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										123
									
								
								vendor/github.com/gliderlabs/ssh/ssh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								vendor/github.com/gliderlabs/ssh/ssh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"crypto/subtle"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Signal string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// POSIX signals as listed in RFC 4254 Section 6.10.
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						SIGABRT Signal = "ABRT"
 | 
				
			||||||
 | 
						SIGALRM Signal = "ALRM"
 | 
				
			||||||
 | 
						SIGFPE  Signal = "FPE"
 | 
				
			||||||
 | 
						SIGHUP  Signal = "HUP"
 | 
				
			||||||
 | 
						SIGILL  Signal = "ILL"
 | 
				
			||||||
 | 
						SIGINT  Signal = "INT"
 | 
				
			||||||
 | 
						SIGKILL Signal = "KILL"
 | 
				
			||||||
 | 
						SIGPIPE Signal = "PIPE"
 | 
				
			||||||
 | 
						SIGQUIT Signal = "QUIT"
 | 
				
			||||||
 | 
						SIGSEGV Signal = "SEGV"
 | 
				
			||||||
 | 
						SIGTERM Signal = "TERM"
 | 
				
			||||||
 | 
						SIGUSR1 Signal = "USR1"
 | 
				
			||||||
 | 
						SIGUSR2 Signal = "USR2"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DefaultHandler is the default Handler used by Serve.
 | 
				
			||||||
 | 
					var DefaultHandler Handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Option is a functional option handler for Server.
 | 
				
			||||||
 | 
					type Option func(*Server) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Handler is a callback for handling established SSH sessions.
 | 
				
			||||||
 | 
					type Handler func(Session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PublicKeyHandler is a callback for performing public key authentication.
 | 
				
			||||||
 | 
					type PublicKeyHandler func(ctx Context, key PublicKey) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PasswordHandler is a callback for performing password authentication.
 | 
				
			||||||
 | 
					type PasswordHandler func(ctx Context, password string) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// KeyboardInteractiveHandler is a callback for performing keyboard-interactive authentication.
 | 
				
			||||||
 | 
					type KeyboardInteractiveHandler func(ctx Context, challenger gossh.KeyboardInteractiveChallenge) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PtyCallback is a hook for allowing PTY sessions.
 | 
				
			||||||
 | 
					type PtyCallback func(ctx Context, pty Pty) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SessionRequestCallback is a callback for allowing or denying SSH sessions.
 | 
				
			||||||
 | 
					type SessionRequestCallback func(sess Session, requestType string) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ConnCallback is a hook for new connections before handling.
 | 
				
			||||||
 | 
					// It allows wrapping for timeouts and limiting by returning
 | 
				
			||||||
 | 
					// the net.Conn that will be used as the underlying connection.
 | 
				
			||||||
 | 
					type ConnCallback func(conn net.Conn) net.Conn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LocalPortForwardingCallback is a hook for allowing port forwarding
 | 
				
			||||||
 | 
					type LocalPortForwardingCallback func(ctx Context, destinationHost string, destinationPort uint32) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReversePortForwardingCallback is a hook for allowing reverse port forwarding
 | 
				
			||||||
 | 
					type ReversePortForwardingCallback func(ctx Context, bindHost string, bindPort uint32) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ServerConfigCallback is a hook for creating custom default server configs
 | 
				
			||||||
 | 
					type ServerConfigCallback func(ctx Context) *gossh.ServerConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Window represents the size of a PTY window.
 | 
				
			||||||
 | 
					type Window struct {
 | 
				
			||||||
 | 
						Width  int
 | 
				
			||||||
 | 
						Height int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pty represents a PTY request and configuration.
 | 
				
			||||||
 | 
					type Pty struct {
 | 
				
			||||||
 | 
						Term   string
 | 
				
			||||||
 | 
						Window Window
 | 
				
			||||||
 | 
						// HELP WANTED: terminal modes!
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Serve accepts incoming SSH connections on the listener l, creating a new
 | 
				
			||||||
 | 
					// connection goroutine for each. The connection goroutines read requests and
 | 
				
			||||||
 | 
					// then calls handler to handle sessions. Handler is typically nil, in which
 | 
				
			||||||
 | 
					// case the DefaultHandler is used.
 | 
				
			||||||
 | 
					func Serve(l net.Listener, handler Handler, options ...Option) error {
 | 
				
			||||||
 | 
						srv := &Server{Handler: handler}
 | 
				
			||||||
 | 
						for _, option := range options {
 | 
				
			||||||
 | 
							if err := srv.SetOption(option); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return srv.Serve(l)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListenAndServe listens on the TCP network address addr and then calls Serve
 | 
				
			||||||
 | 
					// with handler to handle sessions on incoming connections. Handler is typically
 | 
				
			||||||
 | 
					// nil, in which case the DefaultHandler is used.
 | 
				
			||||||
 | 
					func ListenAndServe(addr string, handler Handler, options ...Option) error {
 | 
				
			||||||
 | 
						srv := &Server{Addr: addr, Handler: handler}
 | 
				
			||||||
 | 
						for _, option := range options {
 | 
				
			||||||
 | 
							if err := srv.SetOption(option); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return srv.ListenAndServe()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Handle registers the handler as the DefaultHandler.
 | 
				
			||||||
 | 
					func Handle(handler Handler) {
 | 
				
			||||||
 | 
						DefaultHandler = handler
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// KeysEqual is constant time compare of the keys to avoid timing attacks.
 | 
				
			||||||
 | 
					func KeysEqual(ak, bk PublicKey) bool {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//avoid panic if one of the keys is nil, return false instead
 | 
				
			||||||
 | 
						if ak == nil || bk == nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						a := ak.Marshal()
 | 
				
			||||||
 | 
						b := bk.Marshal()
 | 
				
			||||||
 | 
						return (len(a) == len(b) && subtle.ConstantTimeCompare(a, b) == 1)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										193
									
								
								vendor/github.com/gliderlabs/ssh/tcpip.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								vendor/github.com/gliderlabs/ssh/tcpip.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,193 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						forwardedTCPChannelType = "forwarded-tcpip"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// direct-tcpip data struct as specified in RFC4254, Section 7.2
 | 
				
			||||||
 | 
					type localForwardChannelData struct {
 | 
				
			||||||
 | 
						DestAddr string
 | 
				
			||||||
 | 
						DestPort uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OriginAddr string
 | 
				
			||||||
 | 
						OriginPort uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DirectTCPIPHandler can be enabled by adding it to the server's
 | 
				
			||||||
 | 
					// ChannelHandlers under direct-tcpip.
 | 
				
			||||||
 | 
					func DirectTCPIPHandler(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context) {
 | 
				
			||||||
 | 
						d := localForwardChannelData{}
 | 
				
			||||||
 | 
						if err := gossh.Unmarshal(newChan.ExtraData(), &d); err != nil {
 | 
				
			||||||
 | 
							newChan.Reject(gossh.ConnectionFailed, "error parsing forward data: "+err.Error())
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if srv.LocalPortForwardingCallback == nil || !srv.LocalPortForwardingCallback(ctx, d.DestAddr, d.DestPort) {
 | 
				
			||||||
 | 
							newChan.Reject(gossh.Prohibited, "port forwarding is disabled")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dest := net.JoinHostPort(d.DestAddr, strconv.FormatInt(int64(d.DestPort), 10))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var dialer net.Dialer
 | 
				
			||||||
 | 
						dconn, err := dialer.DialContext(ctx, "tcp", dest)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							newChan.Reject(gossh.ConnectionFailed, err.Error())
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ch, reqs, err := newChan.Accept()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							dconn.Close()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						go gossh.DiscardRequests(reqs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							defer ch.Close()
 | 
				
			||||||
 | 
							defer dconn.Close()
 | 
				
			||||||
 | 
							io.Copy(ch, dconn)
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							defer ch.Close()
 | 
				
			||||||
 | 
							defer dconn.Close()
 | 
				
			||||||
 | 
							io.Copy(dconn, ch)
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type remoteForwardRequest struct {
 | 
				
			||||||
 | 
						BindAddr string
 | 
				
			||||||
 | 
						BindPort uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type remoteForwardSuccess struct {
 | 
				
			||||||
 | 
						BindPort uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type remoteForwardCancelRequest struct {
 | 
				
			||||||
 | 
						BindAddr string
 | 
				
			||||||
 | 
						BindPort uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type remoteForwardChannelData struct {
 | 
				
			||||||
 | 
						DestAddr   string
 | 
				
			||||||
 | 
						DestPort   uint32
 | 
				
			||||||
 | 
						OriginAddr string
 | 
				
			||||||
 | 
						OriginPort uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ForwardedTCPHandler can be enabled by creating a ForwardedTCPHandler and
 | 
				
			||||||
 | 
					// adding the HandleSSHRequest callback to the server's RequestHandlers under
 | 
				
			||||||
 | 
					// tcpip-forward and cancel-tcpip-forward.
 | 
				
			||||||
 | 
					type ForwardedTCPHandler struct {
 | 
				
			||||||
 | 
						forwards map[string]net.Listener
 | 
				
			||||||
 | 
						sync.Mutex
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *ForwardedTCPHandler) HandleSSHRequest(ctx Context, srv *Server, req *gossh.Request) (bool, []byte) {
 | 
				
			||||||
 | 
						h.Lock()
 | 
				
			||||||
 | 
						if h.forwards == nil {
 | 
				
			||||||
 | 
							h.forwards = make(map[string]net.Listener)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h.Unlock()
 | 
				
			||||||
 | 
						conn := ctx.Value(ContextKeyConn).(*gossh.ServerConn)
 | 
				
			||||||
 | 
						switch req.Type {
 | 
				
			||||||
 | 
						case "tcpip-forward":
 | 
				
			||||||
 | 
							var reqPayload remoteForwardRequest
 | 
				
			||||||
 | 
							if err := gossh.Unmarshal(req.Payload, &reqPayload); err != nil {
 | 
				
			||||||
 | 
								// TODO: log parse failure
 | 
				
			||||||
 | 
								return false, []byte{}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if srv.ReversePortForwardingCallback == nil || !srv.ReversePortForwardingCallback(ctx, reqPayload.BindAddr, reqPayload.BindPort) {
 | 
				
			||||||
 | 
								return false, []byte("port forwarding is disabled")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							addr := net.JoinHostPort(reqPayload.BindAddr, strconv.Itoa(int(reqPayload.BindPort)))
 | 
				
			||||||
 | 
							ln, err := net.Listen("tcp", addr)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// TODO: log listen failure
 | 
				
			||||||
 | 
								return false, []byte{}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_, destPortStr, _ := net.SplitHostPort(ln.Addr().String())
 | 
				
			||||||
 | 
							destPort, _ := strconv.Atoi(destPortStr)
 | 
				
			||||||
 | 
							h.Lock()
 | 
				
			||||||
 | 
							h.forwards[addr] = ln
 | 
				
			||||||
 | 
							h.Unlock()
 | 
				
			||||||
 | 
							go func() {
 | 
				
			||||||
 | 
								<-ctx.Done()
 | 
				
			||||||
 | 
								h.Lock()
 | 
				
			||||||
 | 
								ln, ok := h.forwards[addr]
 | 
				
			||||||
 | 
								h.Unlock()
 | 
				
			||||||
 | 
								if ok {
 | 
				
			||||||
 | 
									ln.Close()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}()
 | 
				
			||||||
 | 
							go func() {
 | 
				
			||||||
 | 
								for {
 | 
				
			||||||
 | 
									c, err := ln.Accept()
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										// TODO: log accept failure
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									originAddr, orignPortStr, _ := net.SplitHostPort(c.RemoteAddr().String())
 | 
				
			||||||
 | 
									originPort, _ := strconv.Atoi(orignPortStr)
 | 
				
			||||||
 | 
									payload := gossh.Marshal(&remoteForwardChannelData{
 | 
				
			||||||
 | 
										DestAddr:   reqPayload.BindAddr,
 | 
				
			||||||
 | 
										DestPort:   uint32(destPort),
 | 
				
			||||||
 | 
										OriginAddr: originAddr,
 | 
				
			||||||
 | 
										OriginPort: uint32(originPort),
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
									go func() {
 | 
				
			||||||
 | 
										ch, reqs, err := conn.OpenChannel(forwardedTCPChannelType, payload)
 | 
				
			||||||
 | 
										if err != nil {
 | 
				
			||||||
 | 
											// TODO: log failure to open channel
 | 
				
			||||||
 | 
											log.Println(err)
 | 
				
			||||||
 | 
											c.Close()
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										go gossh.DiscardRequests(reqs)
 | 
				
			||||||
 | 
										go func() {
 | 
				
			||||||
 | 
											defer ch.Close()
 | 
				
			||||||
 | 
											defer c.Close()
 | 
				
			||||||
 | 
											io.Copy(ch, c)
 | 
				
			||||||
 | 
										}()
 | 
				
			||||||
 | 
										go func() {
 | 
				
			||||||
 | 
											defer ch.Close()
 | 
				
			||||||
 | 
											defer c.Close()
 | 
				
			||||||
 | 
											io.Copy(c, ch)
 | 
				
			||||||
 | 
										}()
 | 
				
			||||||
 | 
									}()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								h.Lock()
 | 
				
			||||||
 | 
								delete(h.forwards, addr)
 | 
				
			||||||
 | 
								h.Unlock()
 | 
				
			||||||
 | 
							}()
 | 
				
			||||||
 | 
							return true, gossh.Marshal(&remoteForwardSuccess{uint32(destPort)})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case "cancel-tcpip-forward":
 | 
				
			||||||
 | 
							var reqPayload remoteForwardCancelRequest
 | 
				
			||||||
 | 
							if err := gossh.Unmarshal(req.Payload, &reqPayload); err != nil {
 | 
				
			||||||
 | 
								// TODO: log parse failure
 | 
				
			||||||
 | 
								return false, []byte{}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							addr := net.JoinHostPort(reqPayload.BindAddr, strconv.Itoa(int(reqPayload.BindPort)))
 | 
				
			||||||
 | 
							h.Lock()
 | 
				
			||||||
 | 
							ln, ok := h.forwards[addr]
 | 
				
			||||||
 | 
							h.Unlock()
 | 
				
			||||||
 | 
							if ok {
 | 
				
			||||||
 | 
								ln.Close()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										83
									
								
								vendor/github.com/gliderlabs/ssh/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								vendor/github.com/gliderlabs/ssh/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"crypto/rand"
 | 
				
			||||||
 | 
						"crypto/rsa"
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func generateSigner() (ssh.Signer, error) {
 | 
				
			||||||
 | 
						key, err := rsa.GenerateKey(rand.Reader, 2048)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ssh.NewSignerFromKey(key)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parsePtyRequest(s []byte) (pty Pty, ok bool) {
 | 
				
			||||||
 | 
						term, s, ok := parseString(s)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						width32, s, ok := parseUint32(s)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						height32, _, ok := parseUint32(s)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pty = Pty{
 | 
				
			||||||
 | 
							Term: term,
 | 
				
			||||||
 | 
							Window: Window{
 | 
				
			||||||
 | 
								Width:  int(width32),
 | 
				
			||||||
 | 
								Height: int(height32),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseWinchRequest(s []byte) (win Window, ok bool) {
 | 
				
			||||||
 | 
						width32, s, ok := parseUint32(s)
 | 
				
			||||||
 | 
						if width32 < 1 {
 | 
				
			||||||
 | 
							ok = false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						height32, _, ok := parseUint32(s)
 | 
				
			||||||
 | 
						if height32 < 1 {
 | 
				
			||||||
 | 
							ok = false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						win = Window{
 | 
				
			||||||
 | 
							Width:  int(width32),
 | 
				
			||||||
 | 
							Height: int(height32),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseString(in []byte) (out string, rest []byte, ok bool) {
 | 
				
			||||||
 | 
						if len(in) < 4 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						length := binary.BigEndian.Uint32(in)
 | 
				
			||||||
 | 
						if uint32(len(in)) < 4+length {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						out = string(in[4 : 4+length])
 | 
				
			||||||
 | 
						rest = in[4+length:]
 | 
				
			||||||
 | 
						ok = true
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseUint32(in []byte) (uint32, []byte, bool) {
 | 
				
			||||||
 | 
						if len(in) < 4 {
 | 
				
			||||||
 | 
							return 0, nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return binary.BigEndian.Uint32(in), in[4:], true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								vendor/github.com/gliderlabs/ssh/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/gliderlabs/ssh/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					package ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PublicKey is an abstraction of different types of public keys.
 | 
				
			||||||
 | 
					type PublicKey interface {
 | 
				
			||||||
 | 
						gossh.PublicKey
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The Permissions type holds fine-grained permissions that are specific to a
 | 
				
			||||||
 | 
					// user or a specific authentication method for a user. Permissions, except for
 | 
				
			||||||
 | 
					// "source-address", must be enforced in the server application layer, after
 | 
				
			||||||
 | 
					// successful authentication.
 | 
				
			||||||
 | 
					type Permissions struct {
 | 
				
			||||||
 | 
						*gossh.Permissions
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A Signer can create signatures that verify against a public key.
 | 
				
			||||||
 | 
					type Signer interface {
 | 
				
			||||||
 | 
						gossh.Signer
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ParseAuthorizedKey parses a public key from an authorized_keys file used in
 | 
				
			||||||
 | 
					// OpenSSH according to the sshd(8) manual page.
 | 
				
			||||||
 | 
					func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) {
 | 
				
			||||||
 | 
						return gossh.ParseAuthorizedKey(in)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ParsePublicKey parses an SSH public key formatted for use in
 | 
				
			||||||
 | 
					// the SSH wire protocol according to RFC 4253, section 6.6.
 | 
				
			||||||
 | 
					func ParsePublicKey(in []byte) (out PublicKey, err error) {
 | 
				
			||||||
 | 
						return gossh.ParsePublicKey(in)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								vendor/golang.org/x/sys/unix/syscall_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/golang.org/x/sys/unix/syscall_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -13,7 +13,6 @@ package unix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/binary"
 | 
						"encoding/binary"
 | 
				
			||||||
	"net"
 | 
					 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
	"unsafe"
 | 
						"unsafe"
 | 
				
			||||||
@@ -765,7 +764,7 @@ const px_proto_oe = 0
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type SockaddrPPPoE struct {
 | 
					type SockaddrPPPoE struct {
 | 
				
			||||||
	SID    uint16
 | 
						SID    uint16
 | 
				
			||||||
	Remote net.HardwareAddr
 | 
						Remote []byte
 | 
				
			||||||
	Dev    string
 | 
						Dev    string
 | 
				
			||||||
	raw    RawSockaddrPPPoX
 | 
						raw    RawSockaddrPPPoX
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -916,7 +915,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		sa := &SockaddrPPPoE{
 | 
							sa := &SockaddrPPPoE{
 | 
				
			||||||
			SID:    binary.BigEndian.Uint16(pp[6:8]),
 | 
								SID:    binary.BigEndian.Uint16(pp[6:8]),
 | 
				
			||||||
			Remote: net.HardwareAddr(pp[8:14]),
 | 
								Remote: pp[8:14],
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for i := 14; i < 14+IFNAMSIZ; i++ {
 | 
							for i := 14; i < 14+IFNAMSIZ; i++ {
 | 
				
			||||||
			if pp[i] == 0 {
 | 
								if pp[i] == 0 {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/types_netbsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/types_netbsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -254,6 +254,7 @@ type Ptmget C.struct_ptmget
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = C.AT_FDCWD
 | 
						AT_FDCWD            = C.AT_FDCWD
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = C.AT_SYMLINK_FOLLOW
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW
 | 
						AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/types_openbsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/types_openbsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -241,6 +241,7 @@ type Winsize C.struct_winsize
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = C.AT_FDCWD
 | 
						AT_FDCWD            = C.AT_FDCWD
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = C.AT_SYMLINK_FOLLOW
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW
 | 
						AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -411,6 +411,7 @@ type Ptmget struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = -0x64
 | 
						AT_FDCWD            = -0x64
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = 0x400
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = 0x200
 | 
						AT_SYMLINK_NOFOLLOW = 0x200
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -418,6 +418,7 @@ type Ptmget struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = -0x64
 | 
						AT_FDCWD            = -0x64
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = 0x400
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = 0x200
 | 
						AT_SYMLINK_NOFOLLOW = 0x200
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -416,6 +416,7 @@ type Ptmget struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = -0x64
 | 
						AT_FDCWD            = -0x64
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = 0x400
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = 0x200
 | 
						AT_SYMLINK_NOFOLLOW = 0x200
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -418,6 +418,7 @@ type Ptmget struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = -0x64
 | 
						AT_FDCWD            = -0x64
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = 0x400
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = 0x200
 | 
						AT_SYMLINK_NOFOLLOW = 0x200
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -436,6 +436,7 @@ type Winsize struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = -0x64
 | 
						AT_FDCWD            = -0x64
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = 0x4
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = 0x2
 | 
						AT_SYMLINK_NOFOLLOW = 0x2
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -436,6 +436,7 @@ type Winsize struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = -0x64
 | 
						AT_FDCWD            = -0x64
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = 0x4
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = 0x2
 | 
						AT_SYMLINK_NOFOLLOW = 0x2
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -437,6 +437,7 @@ type Winsize struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = -0x64
 | 
						AT_FDCWD            = -0x64
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = 0x4
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = 0x2
 | 
						AT_SYMLINK_NOFOLLOW = 0x2
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -430,6 +430,7 @@ type Winsize struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AT_FDCWD            = -0x64
 | 
						AT_FDCWD            = -0x64
 | 
				
			||||||
 | 
						AT_SYMLINK_FOLLOW   = 0x4
 | 
				
			||||||
	AT_SYMLINK_NOFOLLOW = 0x2
 | 
						AT_SYMLINK_NOFOLLOW = 0x2
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/golang.org/x/sys/windows/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/golang.org/x/sys/windows/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -294,7 +294,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 | 
				
			|||||||
//sys	clsidFromString(lpsz *uint16, pclsid *GUID) (ret error) = ole32.CLSIDFromString
 | 
					//sys	clsidFromString(lpsz *uint16, pclsid *GUID) (ret error) = ole32.CLSIDFromString
 | 
				
			||||||
//sys	stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) = ole32.StringFromGUID2
 | 
					//sys	stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) = ole32.StringFromGUID2
 | 
				
			||||||
//sys	coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid
 | 
					//sys	coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid
 | 
				
			||||||
//sys	coTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree
 | 
					//sys	CoTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree
 | 
				
			||||||
//sys	rtlGetVersion(info *OsVersionInfoEx) (ret error) = ntdll.RtlGetVersion
 | 
					//sys	rtlGetVersion(info *OsVersionInfoEx) (ret error) = ntdll.RtlGetVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// syscall interface implementation for other packages
 | 
					// syscall interface implementation for other packages
 | 
				
			||||||
@@ -1302,7 +1302,7 @@ func (t Token) KnownFolderPath(folderID *KNOWNFOLDERID, flags uint32) (string, e
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer coTaskMemFree(unsafe.Pointer(p))
 | 
						defer CoTaskMemFree(unsafe.Pointer(p))
 | 
				
			||||||
	return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]), nil
 | 
						return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/golang.org/x/sys/windows/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/golang.org/x/sys/windows/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2517,7 +2517,7 @@ func coCreateGuid(pguid *GUID) (ret error) {
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func coTaskMemFree(address unsafe.Pointer) {
 | 
					func CoTaskMemFree(address unsafe.Pointer) {
 | 
				
			||||||
	syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(address), 0, 0)
 | 
						syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(address), 0, 0)
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -15,6 +15,8 @@ github.com/Unknwon/i18n
 | 
				
			|||||||
github.com/Unknwon/paginater
 | 
					github.com/Unknwon/paginater
 | 
				
			||||||
# github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470
 | 
					# github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470
 | 
				
			||||||
github.com/andybalholm/cascadia
 | 
					github.com/andybalholm/cascadia
 | 
				
			||||||
 | 
					# github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239
 | 
				
			||||||
 | 
					github.com/anmitsu/go-shlex
 | 
				
			||||||
# github.com/beorn7/perks v1.0.0
 | 
					# github.com/beorn7/perks v1.0.0
 | 
				
			||||||
github.com/beorn7/perks/quantile
 | 
					github.com/beorn7/perks/quantile
 | 
				
			||||||
# github.com/blevesearch/bleve v0.0.0-20190214220507-05d86ea8f6e3
 | 
					# github.com/blevesearch/bleve v0.0.0-20190214220507-05d86ea8f6e3
 | 
				
			||||||
@@ -112,6 +114,8 @@ github.com/facebookgo/grace/gracenet
 | 
				
			|||||||
github.com/facebookgo/httpdown
 | 
					github.com/facebookgo/httpdown
 | 
				
			||||||
# github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4
 | 
					# github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4
 | 
				
			||||||
github.com/facebookgo/stats
 | 
					github.com/facebookgo/stats
 | 
				
			||||||
 | 
					# github.com/gliderlabs/ssh v0.2.2
 | 
				
			||||||
 | 
					github.com/gliderlabs/ssh
 | 
				
			||||||
# github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd
 | 
					# github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd
 | 
				
			||||||
github.com/glycerine/go-unsnap-stream
 | 
					github.com/glycerine/go-unsnap-stream
 | 
				
			||||||
# github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
 | 
					# github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
 | 
				
			||||||
@@ -353,7 +357,7 @@ golang.org/x/crypto/cast5
 | 
				
			|||||||
golang.org/x/crypto/openpgp/elgamal
 | 
					golang.org/x/crypto/openpgp/elgamal
 | 
				
			||||||
golang.org/x/crypto/ssh/knownhosts
 | 
					golang.org/x/crypto/ssh/knownhosts
 | 
				
			||||||
golang.org/x/crypto/ssh/agent
 | 
					golang.org/x/crypto/ssh/agent
 | 
				
			||||||
# golang.org/x/net v0.0.0-20190613194153-d28f0bde5980
 | 
					# golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b
 | 
				
			||||||
golang.org/x/net/html/charset
 | 
					golang.org/x/net/html/charset
 | 
				
			||||||
golang.org/x/net/html
 | 
					golang.org/x/net/html
 | 
				
			||||||
golang.org/x/net/html/atom
 | 
					golang.org/x/net/html/atom
 | 
				
			||||||
@@ -365,7 +369,7 @@ golang.org/x/net/internal/socks
 | 
				
			|||||||
# golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759
 | 
					# golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759
 | 
				
			||||||
golang.org/x/oauth2
 | 
					golang.org/x/oauth2
 | 
				
			||||||
golang.org/x/oauth2/internal
 | 
					golang.org/x/oauth2/internal
 | 
				
			||||||
# golang.org/x/sys v0.0.0-20190618155005-516e3c20635f
 | 
					# golang.org/x/sys v0.0.0-20190620070143-6f217b454f45
 | 
				
			||||||
golang.org/x/sys/windows
 | 
					golang.org/x/sys/windows
 | 
				
			||||||
golang.org/x/sys/windows/svc
 | 
					golang.org/x/sys/windows/svc
 | 
				
			||||||
golang.org/x/sys/unix
 | 
					golang.org/x/sys/unix
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user