mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09: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