@@ -6,9 +6,12 @@ import (
6
6
"fmt"
7
7
"net"
8
8
"net/url"
9
+ "path"
9
10
"strconv"
11
+ "time"
10
12
11
13
"github.com/wzshiming/sshd"
14
+ "github.com/wzshiming/sshproxy/permissions"
12
15
"golang.org/x/crypto/ssh"
13
16
)
14
17
@@ -24,14 +27,15 @@ type SimpleServer struct {
24
27
25
28
// NewSimpleServer creates a new NewSimpleServer
26
29
func NewSimpleServer (addr string ) (* SimpleServer , error ) {
27
- user , pwd , host , config , err := serverConfig (addr )
30
+ user , pwd , host , config , userPermissions , err := serverConfig (addr )
28
31
if err != nil {
29
32
return nil , err
30
33
}
31
34
32
35
s := & SimpleServer {
33
36
Server : Server {
34
- ServerConfig : * config ,
37
+ ServerConfig : * config ,
38
+ UserPermissions : userPermissions ,
35
39
},
36
40
Network : "tcp" ,
37
41
Address : host ,
@@ -41,10 +45,10 @@ func NewSimpleServer(addr string) (*SimpleServer, error) {
41
45
return s , nil
42
46
}
43
47
44
- func serverConfig (addr string ) (host , user , pwd string , config * ssh.ServerConfig , err error ) {
48
+ func serverConfig (addr string ) (host , user , pwd string , config * ssh.ServerConfig , userPermissions func ( user string ) sshd. Permissions , err error ) {
45
49
ur , err := url .Parse (addr )
46
50
if err != nil {
47
- return "" , "" , "" , nil , err
51
+ return "" , "" , "" , nil , nil , err
48
52
}
49
53
50
54
isPwd := false
@@ -71,45 +75,104 @@ func serverConfig(addr string) (host, user, pwd string, config *ssh.ServerConfig
71
75
72
76
hostkeyDatas , err := getQuery (ur .Query ()["hostkey_data" ], ur .Query ()["hostkey_file" ])
73
77
if err != nil {
74
- return "" , "" , "" , nil , err
78
+ return "" , "" , "" , nil , nil , err
75
79
}
76
80
if len (hostkeyDatas ) == 0 {
77
81
key , err := sshd .RandomHostkey ()
78
82
if err != nil {
79
- return "" , "" , "" , nil , err
83
+ return "" , "" , "" , nil , nil , err
80
84
}
81
85
config .AddHostKey (key )
82
86
} else {
83
87
for _ , data := range hostkeyDatas {
84
88
key , err := sshd .ParseHostkey (data )
85
89
if err != nil {
86
- return "" , "" , "" , nil , err
90
+ return "" , "" , "" , nil , nil , err
87
91
}
88
92
config .AddHostKey (key )
89
93
}
90
94
}
91
95
96
+ pks := []func (conn ssh.ConnMetadata , key ssh.PublicKey ) (* ssh.Permissions , error ){}
92
97
authorizedDatas , err := getQuery (ur .Query ()["authorized_data" ], ur .Query ()["authorized_file" ])
93
98
if err != nil {
94
- return "" , "" , "" , nil , err
99
+ return "" , "" , "" , nil , nil , err
95
100
}
96
- allKeys := map [string ]string {}
97
- for _ , data := range authorizedDatas {
98
- keys , err := sshd .ParseAuthorized (bytes .NewBuffer (data ))
101
+ if len (authorizedDatas ) != 0 {
102
+ keys , err := sshd .ParseAuthorized (bytes .NewBuffer (bytes .Join (authorizedDatas , []byte {'\n' })))
99
103
if err != nil {
100
- return "" , "" , "" , nil , err
104
+ return "" , "" , "" , nil , nil , err
101
105
}
102
- for k , v := range keys {
103
- allKeys [k ] = v
106
+ if len (keys .Data ) != 0 {
107
+ pks = append (pks , func (conn ssh.ConnMetadata , key ssh.PublicKey ) (* ssh.Permissions , error ) {
108
+ ok , _ := keys .Allow (key )
109
+ if ok {
110
+ return nil , nil
111
+ }
112
+ return nil , fmt .Errorf ("denied" )
113
+ })
104
114
}
105
115
}
106
- if len (allKeys ) != 0 {
107
- config .PublicKeyCallback = func (conn ssh.ConnMetadata , key ssh.PublicKey ) (* ssh.Permissions , error ) {
108
- k := string (key .Marshal ())
109
- if _ , ok := allKeys [k ]; ok {
116
+
117
+ homeDirs := ur .Query ()["home_dir" ]
118
+ if len (homeDirs ) != 0 && homeDirs [0 ] != "" {
119
+ homeDir := homeDirs [0 ]
120
+ sshDirName := ".ssh"
121
+ sshDirNames := ur .Query ()["ssh_dir_name" ]
122
+ if len (sshDirNames ) != 0 {
123
+ sshDirName = sshDirNames [0 ]
124
+ }
125
+ authorizedFileName := "authorized_keys"
126
+ authorizedFileNames := ur .Query ()["authorized_file_name" ]
127
+ if len (authorizedFileNames ) != 0 {
128
+ authorizedFileName = authorizedFileNames [0 ]
129
+ }
130
+ pks = append (pks , func (conn ssh.ConnMetadata , key ssh.PublicKey ) (* ssh.Permissions , error ) {
131
+ file := path .Join (homeDir , conn .User (), sshDirName , authorizedFileName )
132
+ keys , err := sshd .GetAuthorizedFile (file )
133
+ if err != nil {
134
+ return nil , fmt .Errorf ("denied" )
135
+ }
136
+ ok , _ := keys .Allow (key )
137
+ if ok {
110
138
return nil , nil
111
139
}
112
140
return nil , fmt .Errorf ("denied" )
141
+ })
142
+
143
+ // Other sshd implementations do not have such fine-grained permissions control,
144
+ // and this is a fine-grained set of permissions control files defined by the project itself
145
+ permissionsFileName := ""
146
+ permissionsFileNames := ur .Query ()["permissions_file_name" ]
147
+ if len (permissionsFileNames ) != 0 {
148
+ permissionsFileName = permissionsFileNames [0 ]
149
+ }
150
+ if permissionsFileName != "" {
151
+ permissionsFileUpdatePeriod := time .Duration (0 )
152
+ permissionsFileUpdatePeriods := ur .Query ()["permissions_file_update_period" ]
153
+ if len (permissionsFileUpdatePeriods ) != 0 {
154
+ permissionsFileUpdatePeriod , _ = time .ParseDuration (permissionsFileUpdatePeriods [0 ])
155
+ }
156
+ userPermissions = func (user string ) sshd.Permissions {
157
+ file := path .Join (homeDir , user , sshDirName , permissionsFileName )
158
+ return permissions .NewPermissionsFromFile (file , permissionsFileUpdatePeriod )
159
+ }
160
+ }
161
+ }
162
+
163
+ if len (pks ) != 0 {
164
+ if len (pks ) == 1 {
165
+ config .PublicKeyCallback = pks [0 ]
166
+ } else {
167
+ config .PublicKeyCallback = func (conn ssh.ConnMetadata , key ssh.PublicKey ) (p * ssh.Permissions , err error ) {
168
+ for _ , pk := range pks {
169
+ p , err = pk (conn , key )
170
+ if err == nil {
171
+ break
172
+ }
173
+ }
174
+ return
175
+ }
113
176
}
114
177
}
115
178
@@ -125,7 +188,7 @@ func serverConfig(addr string) (host, user, pwd string, config *ssh.ServerConfig
125
188
port = "22"
126
189
}
127
190
host = net .JoinHostPort (host , port )
128
- return user , pwd , host , config , nil
191
+ return user , pwd , host , config , userPermissions , nil
129
192
}
130
193
131
194
// Run the server
0 commit comments