diff options
-rw-r--r-- | ChangeLog | 32 | ||||
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | auth.c | 606 | ||||
-rw-r--r-- | auth.h | 6 | ||||
-rw-r--r-- | bufaux.c | 53 | ||||
-rw-r--r-- | bufaux.h | 5 | ||||
-rw-r--r-- | channels.c | 1194 | ||||
-rw-r--r-- | channels.h | 194 | ||||
-rw-r--r-- | cipher.c | 123 | ||||
-rw-r--r-- | cipher.h | 22 | ||||
-rw-r--r-- | clientloop.c | 205 | ||||
-rw-r--r-- | compress.c | 40 | ||||
-rw-r--r-- | dispatch.c | 78 | ||||
-rw-r--r-- | dispatch.h | 11 | ||||
-rw-r--r-- | log-server.c | 12 | ||||
-rw-r--r-- | mpaux.c | 8 | ||||
-rw-r--r-- | nchan.c | 9 | ||||
-rw-r--r-- | nchan.h | 4 | ||||
-rw-r--r-- | packet.c | 3 | ||||
-rw-r--r-- | pty.h | 4 | ||||
-rw-r--r-- | readconf.c | 3 | ||||
-rw-r--r-- | serverloop.c | 195 | ||||
-rw-r--r-- | session.c | 1153 | ||||
-rw-r--r-- | session.h | 7 | ||||
-rw-r--r-- | ssh.c | 3 | ||||
-rw-r--r-- | ssh.h | 171 | ||||
-rw-r--r-- | ssh2.h | 106 | ||||
-rw-r--r-- | sshd.8 | 10 | ||||
-rw-r--r-- | sshd.c | 1855 |
29 files changed, 3410 insertions, 2706 deletions
@@ -1,3 +1,35 @@ | |||
1 | 20000401 | ||
2 | - Big OpenBSD CVS update (mainly beginnings of SSH2 infrastructure) | ||
3 | - [auth.c session.c sshd.c auth.h] | ||
4 | split sshd.c -> auth.c session.c sshd.c plus cleanup and goto-removal | ||
5 | - [bufaux.c bufaux.h] | ||
6 | support ssh2 bignums | ||
7 | - [channels.c channels.h clientloop.c sshd.c nchan.c nchan.h packet.c] | ||
8 | [readconf.c ssh.c ssh.h serverloop.c] | ||
9 | replace big switch() with function tables (prepare for ssh2) | ||
10 | - [ssh2.h] | ||
11 | ssh2 message type codes | ||
12 | - [sshd.8] | ||
13 | reorder Xr to avoid cutting | ||
14 | - [serverloop.c] | ||
15 | close(fdin) if fdin != fdout, shutdown otherwise, ok theo@ | ||
16 | - [channels.c] | ||
17 | missing close | ||
18 | allow bigger packets | ||
19 | - [cipher.c cipher.h] | ||
20 | support ssh2 ciphers | ||
21 | - [compress.c] | ||
22 | cleanup, less code | ||
23 | - [dispatch.c dispatch.h] | ||
24 | function tables for different message types | ||
25 | - [log-server.c] | ||
26 | do not log() if debuggin to stderr | ||
27 | rename a cpp symbol, to avoid param.h collision | ||
28 | - [mpaux.c] | ||
29 | KNF | ||
30 | - [nchan.c] | ||
31 | sync w/ channels.c | ||
32 | |||
1 | 20000326 | 33 | 20000326 |
2 | - Better tests for OpenSSL w/ RSAref | 34 | - Better tests for OpenSSL w/ RSAref |
3 | - Added replacement setenv() function from OpenBSD libc. Suggested by | 35 | - Added replacement setenv() function from OpenBSD libc. Suggested by |
diff --git a/Makefile.in b/Makefile.in index 6fee608df..43870d5f9 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -31,11 +31,11 @@ LDFLAGS=-L. @LDFLAGS@ | |||
31 | 31 | ||
32 | TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) | 32 | TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) |
33 | 33 | ||
34 | LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hostfile.o key.o log.o match.o mpaux.o nchan.o packet.o radix.o random.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o | 34 | LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hostfile.o key.o log.o match.o mpaux.o nchan.o packet.o radix.o random.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o |
35 | 35 | ||
36 | SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o | 36 | SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o |
37 | 37 | ||
38 | SSHDOBJS= sshd.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o | 38 | SSHDOBJS= sshd.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o session.o auth.o |
39 | 39 | ||
40 | TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 | 40 | TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 |
41 | CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 | 41 | CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 |
@@ -0,0 +1,606 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
3 | * All rights reserved | ||
4 | */ | ||
5 | |||
6 | #include "includes.h" | ||
7 | RCSID("$OpenBSD: auth.c,v 1.1 2000/03/28 21:15:45 markus Exp $"); | ||
8 | |||
9 | #include "xmalloc.h" | ||
10 | #include "rsa.h" | ||
11 | #include "ssh.h" | ||
12 | #include "pty.h" | ||
13 | #include "packet.h" | ||
14 | #include "buffer.h" | ||
15 | #include "cipher.h" | ||
16 | #include "mpaux.h" | ||
17 | #include "servconf.h" | ||
18 | #include "channels.h" | ||
19 | #include "match.h" | ||
20 | |||
21 | #include "session.h" | ||
22 | #include "dispatch.h" | ||
23 | |||
24 | /* import */ | ||
25 | extern ServerOptions options; | ||
26 | extern char *forced_command; | ||
27 | |||
28 | /* | ||
29 | * Check if the user is allowed to log in via ssh. If user is listed in | ||
30 | * DenyUsers or user's primary group is listed in DenyGroups, false will | ||
31 | * be returned. If AllowUsers isn't empty and user isn't listed there, or | ||
32 | * if AllowGroups isn't empty and user isn't listed there, false will be | ||
33 | * returned. | ||
34 | * If the user's shell is not executable, false will be returned. | ||
35 | * Otherwise true is returned. | ||
36 | */ | ||
37 | static int | ||
38 | allowed_user(struct passwd * pw) | ||
39 | { | ||
40 | struct stat st; | ||
41 | struct group *grp; | ||
42 | int i; | ||
43 | #ifdef WITH_AIXAUTHENTICATE | ||
44 | char *loginmsg; | ||
45 | #endif /* WITH_AIXAUTHENTICATE */ | ||
46 | |||
47 | /* Shouldn't be called if pw is NULL, but better safe than sorry... */ | ||
48 | if (!pw) | ||
49 | return 0; | ||
50 | |||
51 | /* deny if shell does not exists or is not executable */ | ||
52 | if (stat(pw->pw_shell, &st) != 0) | ||
53 | return 0; | ||
54 | if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) | ||
55 | return 0; | ||
56 | |||
57 | /* Return false if user is listed in DenyUsers */ | ||
58 | if (options.num_deny_users > 0) { | ||
59 | if (!pw->pw_name) | ||
60 | return 0; | ||
61 | for (i = 0; i < options.num_deny_users; i++) | ||
62 | if (match_pattern(pw->pw_name, options.deny_users[i])) | ||
63 | return 0; | ||
64 | } | ||
65 | /* Return false if AllowUsers isn't empty and user isn't listed there */ | ||
66 | if (options.num_allow_users > 0) { | ||
67 | if (!pw->pw_name) | ||
68 | return 0; | ||
69 | for (i = 0; i < options.num_allow_users; i++) | ||
70 | if (match_pattern(pw->pw_name, options.allow_users[i])) | ||
71 | break; | ||
72 | /* i < options.num_allow_users iff we break for loop */ | ||
73 | if (i >= options.num_allow_users) | ||
74 | return 0; | ||
75 | } | ||
76 | /* Get the primary group name if we need it. Return false if it fails */ | ||
77 | if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { | ||
78 | grp = getgrgid(pw->pw_gid); | ||
79 | if (!grp) | ||
80 | return 0; | ||
81 | |||
82 | /* Return false if user's group is listed in DenyGroups */ | ||
83 | if (options.num_deny_groups > 0) { | ||
84 | if (!grp->gr_name) | ||
85 | return 0; | ||
86 | for (i = 0; i < options.num_deny_groups; i++) | ||
87 | if (match_pattern(grp->gr_name, options.deny_groups[i])) | ||
88 | return 0; | ||
89 | } | ||
90 | /* | ||
91 | * Return false if AllowGroups isn't empty and user's group | ||
92 | * isn't listed there | ||
93 | */ | ||
94 | if (options.num_allow_groups > 0) { | ||
95 | if (!grp->gr_name) | ||
96 | return 0; | ||
97 | for (i = 0; i < options.num_allow_groups; i++) | ||
98 | if (match_pattern(grp->gr_name, options.allow_groups[i])) | ||
99 | break; | ||
100 | /* i < options.num_allow_groups iff we break for | ||
101 | loop */ | ||
102 | if (i >= options.num_allow_groups) | ||
103 | return 0; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | #ifdef WITH_AIXAUTHENTICATE | ||
108 | if (loginrestrictions(pw->pw_name,S_LOGIN,NULL,&loginmsg) != 0) | ||
109 | return 0; | ||
110 | #endif /* WITH_AIXAUTHENTICATE */ | ||
111 | |||
112 | /* We found no reason not to let this user try to log on... */ | ||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * convert ssh auth msg type into description | ||
118 | */ | ||
119 | char * | ||
120 | get_authname(int type) | ||
121 | { | ||
122 | static char buf[1024]; | ||
123 | switch (type) { | ||
124 | case SSH_CMSG_AUTH_PASSWORD: | ||
125 | return "password"; | ||
126 | case SSH_CMSG_AUTH_RSA: | ||
127 | return "rsa"; | ||
128 | case SSH_CMSG_AUTH_RHOSTS_RSA: | ||
129 | return "rhosts-rsa"; | ||
130 | case SSH_CMSG_AUTH_RHOSTS: | ||
131 | return "rhosts"; | ||
132 | #ifdef KRB4 | ||
133 | case SSH_CMSG_AUTH_KERBEROS: | ||
134 | return "kerberos"; | ||
135 | #endif | ||
136 | #ifdef SKEY | ||
137 | case SSH_CMSG_AUTH_TIS_RESPONSE: | ||
138 | return "s/key"; | ||
139 | #endif | ||
140 | } | ||
141 | snprintf(buf, sizeof buf, "bad-auth-msg-%d", type); | ||
142 | return buf; | ||
143 | } | ||
144 | |||
145 | #define AUTH_FAIL_MAX 6 | ||
146 | #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) | ||
147 | #define AUTH_FAIL_MSG "Too many authentication failures for %.100s" | ||
148 | |||
149 | /* | ||
150 | * The user does not exist or access is denied, | ||
151 | * but fake indication that authentication is needed. | ||
152 | */ | ||
153 | void | ||
154 | do_fake_authloop1(char *user) | ||
155 | { | ||
156 | int attempt = 0; | ||
157 | |||
158 | log("Faking authloop for illegal user %.200s from %.200s port %d", | ||
159 | user, | ||
160 | get_remote_ipaddr(), | ||
161 | get_remote_port()); | ||
162 | |||
163 | #ifdef WITH_AIXAUTHENTICATE | ||
164 | if (strncmp(get_authname(type),"password", | ||
165 | strlen(get_authname(type))) == 0) | ||
166 | loginfailed(pw->pw_name,get_canonical_hostname(),"ssh"); | ||
167 | #endif /* WITH_AIXAUTHENTICATE */ | ||
168 | |||
169 | /* Indicate that authentication is needed. */ | ||
170 | packet_start(SSH_SMSG_FAILURE); | ||
171 | packet_send(); | ||
172 | packet_write_wait(); | ||
173 | |||
174 | /* | ||
175 | * Keep reading packets, and always respond with a failure. This is | ||
176 | * to avoid disclosing whether such a user really exists. | ||
177 | */ | ||
178 | for (attempt = 1;; attempt++) { | ||
179 | /* Read a packet. This will not return if the client disconnects. */ | ||
180 | int plen; | ||
181 | #ifndef SKEY | ||
182 | (void)packet_read(&plen); | ||
183 | #else /* SKEY */ | ||
184 | int type = packet_read(&plen); | ||
185 | unsigned int dlen; | ||
186 | char *password, *skeyinfo; | ||
187 | /* Try to send a fake s/key challenge. */ | ||
188 | if (options.skey_authentication == 1 && | ||
189 | (skeyinfo = skey_fake_keyinfo(user)) != NULL) { | ||
190 | password = NULL; | ||
191 | if (type == SSH_CMSG_AUTH_TIS) { | ||
192 | packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); | ||
193 | packet_put_string(skeyinfo, strlen(skeyinfo)); | ||
194 | packet_send(); | ||
195 | packet_write_wait(); | ||
196 | continue; | ||
197 | } else if (type == SSH_CMSG_AUTH_PASSWORD && | ||
198 | options.password_authentication && | ||
199 | (password = packet_get_string(&dlen)) != NULL && | ||
200 | dlen == 5 && | ||
201 | strncasecmp(password, "s/key", 5) == 0 ) { | ||
202 | packet_send_debug(skeyinfo); | ||
203 | } | ||
204 | if (password != NULL) | ||
205 | xfree(password); | ||
206 | } | ||
207 | #endif | ||
208 | if (attempt > AUTH_FAIL_MAX) | ||
209 | packet_disconnect(AUTH_FAIL_MSG, user); | ||
210 | |||
211 | /* | ||
212 | * Send failure. This should be indistinguishable from a | ||
213 | * failed authentication. | ||
214 | */ | ||
215 | packet_start(SSH_SMSG_FAILURE); | ||
216 | packet_send(); | ||
217 | packet_write_wait(); | ||
218 | } | ||
219 | /* NOTREACHED */ | ||
220 | abort(); | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * read packets and try to authenticate local user *pw. | ||
225 | * return if authentication is successfull | ||
226 | */ | ||
227 | void | ||
228 | do_authloop(struct passwd * pw) | ||
229 | { | ||
230 | int attempt = 0; | ||
231 | unsigned int bits; | ||
232 | RSA *client_host_key; | ||
233 | BIGNUM *n; | ||
234 | char *client_user = NULL, *password = NULL; | ||
235 | char user[1024]; | ||
236 | unsigned int dlen; | ||
237 | int plen, nlen, elen; | ||
238 | unsigned int ulen; | ||
239 | int type = 0; | ||
240 | void (*authlog) (const char *fmt,...) = verbose; | ||
241 | |||
242 | /* Indicate that authentication is needed. */ | ||
243 | packet_start(SSH_SMSG_FAILURE); | ||
244 | packet_send(); | ||
245 | packet_write_wait(); | ||
246 | |||
247 | for (attempt = 1;; attempt++) { | ||
248 | int authenticated = 0; | ||
249 | strlcpy(user, "", sizeof user); | ||
250 | |||
251 | /* Get a packet from the client. */ | ||
252 | type = packet_read(&plen); | ||
253 | |||
254 | /* Process the packet. */ | ||
255 | switch (type) { | ||
256 | #ifdef AFS | ||
257 | case SSH_CMSG_HAVE_KERBEROS_TGT: | ||
258 | if (!options.kerberos_tgt_passing) { | ||
259 | /* packet_get_all(); */ | ||
260 | verbose("Kerberos tgt passing disabled."); | ||
261 | break; | ||
262 | } else { | ||
263 | /* Accept Kerberos tgt. */ | ||
264 | char *tgt = packet_get_string(&dlen); | ||
265 | packet_integrity_check(plen, 4 + dlen, type); | ||
266 | if (!auth_kerberos_tgt(pw, tgt)) | ||
267 | verbose("Kerberos tgt REFUSED for %s", pw->pw_name); | ||
268 | xfree(tgt); | ||
269 | } | ||
270 | continue; | ||
271 | |||
272 | case SSH_CMSG_HAVE_AFS_TOKEN: | ||
273 | if (!options.afs_token_passing || !k_hasafs()) { | ||
274 | /* packet_get_all(); */ | ||
275 | verbose("AFS token passing disabled."); | ||
276 | break; | ||
277 | } else { | ||
278 | /* Accept AFS token. */ | ||
279 | char *token_string = packet_get_string(&dlen); | ||
280 | packet_integrity_check(plen, 4 + dlen, type); | ||
281 | if (!auth_afs_token(pw, token_string)) | ||
282 | verbose("AFS token REFUSED for %s", pw->pw_name); | ||
283 | xfree(token_string); | ||
284 | } | ||
285 | continue; | ||
286 | #endif /* AFS */ | ||
287 | #ifdef KRB4 | ||
288 | case SSH_CMSG_AUTH_KERBEROS: | ||
289 | if (!options.kerberos_authentication) { | ||
290 | /* packet_get_all(); */ | ||
291 | verbose("Kerberos authentication disabled."); | ||
292 | break; | ||
293 | } else { | ||
294 | /* Try Kerberos v4 authentication. */ | ||
295 | KTEXT_ST auth; | ||
296 | char *tkt_user = NULL; | ||
297 | char *kdata = packet_get_string((unsigned int *) &auth.length); | ||
298 | packet_integrity_check(plen, 4 + auth.length, type); | ||
299 | |||
300 | if (auth.length < MAX_KTXT_LEN) | ||
301 | memcpy(auth.dat, kdata, auth.length); | ||
302 | xfree(kdata); | ||
303 | |||
304 | authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user); | ||
305 | |||
306 | if (authenticated) { | ||
307 | snprintf(user, sizeof user, " tktuser %s", tkt_user); | ||
308 | xfree(tkt_user); | ||
309 | } | ||
310 | } | ||
311 | break; | ||
312 | #endif /* KRB4 */ | ||
313 | |||
314 | case SSH_CMSG_AUTH_RHOSTS: | ||
315 | if (!options.rhosts_authentication) { | ||
316 | verbose("Rhosts authentication disabled."); | ||
317 | break; | ||
318 | } | ||
319 | /* | ||
320 | * Get client user name. Note that we just have to | ||
321 | * trust the client; this is one reason why rhosts | ||
322 | * authentication is insecure. (Another is | ||
323 | * IP-spoofing on a local network.) | ||
324 | */ | ||
325 | client_user = packet_get_string(&ulen); | ||
326 | packet_integrity_check(plen, 4 + ulen, type); | ||
327 | |||
328 | /* Try to authenticate using /etc/hosts.equiv and | ||
329 | .rhosts. */ | ||
330 | authenticated = auth_rhosts(pw, client_user); | ||
331 | |||
332 | snprintf(user, sizeof user, " ruser %s", client_user); | ||
333 | break; | ||
334 | |||
335 | case SSH_CMSG_AUTH_RHOSTS_RSA: | ||
336 | if (!options.rhosts_rsa_authentication) { | ||
337 | verbose("Rhosts with RSA authentication disabled."); | ||
338 | break; | ||
339 | } | ||
340 | /* | ||
341 | * Get client user name. Note that we just have to | ||
342 | * trust the client; root on the client machine can | ||
343 | * claim to be any user. | ||
344 | */ | ||
345 | client_user = packet_get_string(&ulen); | ||
346 | |||
347 | /* Get the client host key. */ | ||
348 | client_host_key = RSA_new(); | ||
349 | if (client_host_key == NULL) | ||
350 | fatal("RSA_new failed"); | ||
351 | client_host_key->e = BN_new(); | ||
352 | client_host_key->n = BN_new(); | ||
353 | if (client_host_key->e == NULL || client_host_key->n == NULL) | ||
354 | fatal("BN_new failed"); | ||
355 | bits = packet_get_int(); | ||
356 | packet_get_bignum(client_host_key->e, &elen); | ||
357 | packet_get_bignum(client_host_key->n, &nlen); | ||
358 | |||
359 | if (bits != BN_num_bits(client_host_key->n)) | ||
360 | error("Warning: keysize mismatch for client_host_key: " | ||
361 | "actual %d, announced %d", BN_num_bits(client_host_key->n), bits); | ||
362 | packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type); | ||
363 | |||
364 | authenticated = auth_rhosts_rsa(pw, client_user, client_host_key); | ||
365 | RSA_free(client_host_key); | ||
366 | |||
367 | snprintf(user, sizeof user, " ruser %s", client_user); | ||
368 | break; | ||
369 | |||
370 | case SSH_CMSG_AUTH_RSA: | ||
371 | if (!options.rsa_authentication) { | ||
372 | verbose("RSA authentication disabled."); | ||
373 | break; | ||
374 | } | ||
375 | /* RSA authentication requested. */ | ||
376 | n = BN_new(); | ||
377 | packet_get_bignum(n, &nlen); | ||
378 | packet_integrity_check(plen, nlen, type); | ||
379 | authenticated = auth_rsa(pw, n); | ||
380 | BN_clear_free(n); | ||
381 | break; | ||
382 | |||
383 | case SSH_CMSG_AUTH_PASSWORD: | ||
384 | if (!options.password_authentication) { | ||
385 | verbose("Password authentication disabled."); | ||
386 | break; | ||
387 | } | ||
388 | /* | ||
389 | * Read user password. It is in plain text, but was | ||
390 | * transmitted over the encrypted channel so it is | ||
391 | * not visible to an outside observer. | ||
392 | */ | ||
393 | password = packet_get_string(&dlen); | ||
394 | packet_integrity_check(plen, 4 + dlen, type); | ||
395 | |||
396 | #ifdef USE_PAM | ||
397 | /* Do PAM auth with password */ | ||
398 | authenticated = auth_pam_password(pw, password); | ||
399 | #else /* USE_PAM */ | ||
400 | /* Try authentication with the password. */ | ||
401 | authenticated = auth_password(pw, password); | ||
402 | #endif /* USE_PAM */ | ||
403 | memset(password, 0, strlen(password)); | ||
404 | xfree(password); | ||
405 | break; | ||
406 | |||
407 | #ifdef SKEY | ||
408 | case SSH_CMSG_AUTH_TIS: | ||
409 | debug("rcvd SSH_CMSG_AUTH_TIS"); | ||
410 | if (options.skey_authentication == 1) { | ||
411 | char *skeyinfo = skey_keyinfo(pw->pw_name); | ||
412 | if (skeyinfo == NULL) { | ||
413 | debug("generating fake skeyinfo for %.100s.", pw->pw_name); | ||
414 | skeyinfo = skey_fake_keyinfo(pw->pw_name); | ||
415 | } | ||
416 | if (skeyinfo != NULL) { | ||
417 | /* we send our s/key- in tis-challenge messages */ | ||
418 | debug("sending challenge '%s'", skeyinfo); | ||
419 | packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); | ||
420 | packet_put_string(skeyinfo, strlen(skeyinfo)); | ||
421 | packet_send(); | ||
422 | packet_write_wait(); | ||
423 | continue; | ||
424 | } | ||
425 | } | ||
426 | break; | ||
427 | case SSH_CMSG_AUTH_TIS_RESPONSE: | ||
428 | debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE"); | ||
429 | if (options.skey_authentication == 1) { | ||
430 | char *response = packet_get_string(&dlen); | ||
431 | debug("skey response == '%s'", response); | ||
432 | packet_integrity_check(plen, 4 + dlen, type); | ||
433 | authenticated = (skey_haskey(pw->pw_name) == 0 && | ||
434 | skey_passcheck(pw->pw_name, response) != -1); | ||
435 | xfree(response); | ||
436 | } | ||
437 | break; | ||
438 | #else | ||
439 | case SSH_CMSG_AUTH_TIS: | ||
440 | /* TIS Authentication is unsupported */ | ||
441 | log("TIS authentication unsupported."); | ||
442 | break; | ||
443 | #endif | ||
444 | |||
445 | default: | ||
446 | /* | ||
447 | * Any unknown messages will be ignored (and failure | ||
448 | * returned) during authentication. | ||
449 | */ | ||
450 | log("Unknown message during authentication: type %d", type); | ||
451 | break; | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * Check if the user is logging in as root and root logins | ||
456 | * are disallowed. | ||
457 | * Note that root login is allowed for forced commands. | ||
458 | */ | ||
459 | if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) { | ||
460 | if (forced_command) { | ||
461 | log("Root login accepted for forced command."); | ||
462 | } else { | ||
463 | authenticated = 0; | ||
464 | log("ROOT LOGIN REFUSED FROM %.200s", | ||
465 | get_canonical_hostname()); | ||
466 | } | ||
467 | } | ||
468 | |||
469 | /* Raise logging level */ | ||
470 | if (authenticated || | ||
471 | attempt == AUTH_FAIL_LOG || | ||
472 | type == SSH_CMSG_AUTH_PASSWORD) | ||
473 | authlog = log; | ||
474 | |||
475 | authlog("%s %s for %.200s from %.200s port %d%s", | ||
476 | authenticated ? "Accepted" : "Failed", | ||
477 | get_authname(type), | ||
478 | pw->pw_uid == 0 ? "ROOT" : pw->pw_name, | ||
479 | get_remote_ipaddr(), | ||
480 | get_remote_port(), | ||
481 | user); | ||
482 | |||
483 | #ifdef USE_PAM | ||
484 | if (authenticated) { | ||
485 | if (!do_pam_account(pw->pw_name, client_user)) { | ||
486 | if (client_user != NULL) { | ||
487 | xfree(client_user); | ||
488 | client_user = NULL; | ||
489 | } | ||
490 | do_fake_authloop1(pw->pw_name); | ||
491 | } | ||
492 | return; | ||
493 | } | ||
494 | #else /* USE_PAM */ | ||
495 | if (authenticated) { | ||
496 | return; | ||
497 | } | ||
498 | #endif /* USE_PAM */ | ||
499 | |||
500 | if (client_user != NULL) { | ||
501 | xfree(client_user); | ||
502 | client_user = NULL; | ||
503 | } | ||
504 | |||
505 | if (attempt > AUTH_FAIL_MAX) | ||
506 | packet_disconnect(AUTH_FAIL_MSG, pw->pw_name); | ||
507 | |||
508 | /* Send a message indicating that the authentication attempt failed. */ | ||
509 | packet_start(SSH_SMSG_FAILURE); | ||
510 | packet_send(); | ||
511 | packet_write_wait(); | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * Performs authentication of an incoming connection. Session key has already | ||
517 | * been exchanged and encryption is enabled. | ||
518 | */ | ||
519 | void | ||
520 | do_authentication() | ||
521 | { | ||
522 | struct passwd *pw, pwcopy; | ||
523 | int plen; | ||
524 | unsigned int ulen; | ||
525 | char *user; | ||
526 | #ifdef WITH_AIXAUTHENTICATE | ||
527 | char *loginmsg; | ||
528 | #endif /* WITH_AIXAUTHENTICATE */ | ||
529 | |||
530 | /* Get the name of the user that we wish to log in as. */ | ||
531 | packet_read_expect(&plen, SSH_CMSG_USER); | ||
532 | |||
533 | /* Get the user name. */ | ||
534 | user = packet_get_string(&ulen); | ||
535 | packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER); | ||
536 | |||
537 | setproctitle("%s", user); | ||
538 | |||
539 | #ifdef AFS | ||
540 | /* If machine has AFS, set process authentication group. */ | ||
541 | if (k_hasafs()) { | ||
542 | k_setpag(); | ||
543 | k_unlog(); | ||
544 | } | ||
545 | #endif /* AFS */ | ||
546 | |||
547 | /* Verify that the user is a valid user. */ | ||
548 | pw = getpwnam(user); | ||
549 | if (!pw || !allowed_user(pw)) | ||
550 | do_fake_authloop1(user); | ||
551 | xfree(user); | ||
552 | |||
553 | /* Take a copy of the returned structure. */ | ||
554 | memset(&pwcopy, 0, sizeof(pwcopy)); | ||
555 | pwcopy.pw_name = xstrdup(pw->pw_name); | ||
556 | pwcopy.pw_passwd = xstrdup(pw->pw_passwd); | ||
557 | pwcopy.pw_uid = pw->pw_uid; | ||
558 | pwcopy.pw_gid = pw->pw_gid; | ||
559 | pwcopy.pw_dir = xstrdup(pw->pw_dir); | ||
560 | pwcopy.pw_shell = xstrdup(pw->pw_shell); | ||
561 | pw = &pwcopy; | ||
562 | |||
563 | #ifdef USE_PAM | ||
564 | start_pam(pw); | ||
565 | #endif | ||
566 | |||
567 | /* | ||
568 | * If we are not running as root, the user must have the same uid as | ||
569 | * the server. | ||
570 | */ | ||
571 | if (getuid() != 0 && pw->pw_uid != getuid()) | ||
572 | packet_disconnect("Cannot change user when server not running as root."); | ||
573 | |||
574 | debug("Attempting authentication for %.100s.", pw->pw_name); | ||
575 | |||
576 | /* If the user has no password, accept authentication immediately. */ | ||
577 | if (options.password_authentication && | ||
578 | #ifdef KRB4 | ||
579 | (!options.kerberos_authentication || options.kerberos_or_local_passwd) && | ||
580 | #endif /* KRB4 */ | ||
581 | #ifdef USE_PAM | ||
582 | auth_pam_password(pw, "")) { | ||
583 | #else /* USE_PAM */ | ||
584 | auth_password(pw, "")) { | ||
585 | #endif /* USE_PAM */ | ||
586 | /* Authentication with empty password succeeded. */ | ||
587 | log("Login for user %s from %.100s, accepted without authentication.", | ||
588 | pw->pw_name, get_remote_ipaddr()); | ||
589 | } else { | ||
590 | /* Loop until the user has been authenticated or the | ||
591 | connection is closed, do_authloop() returns only if | ||
592 | authentication is successfull */ | ||
593 | do_authloop(pw); | ||
594 | } | ||
595 | |||
596 | /* The user has been authenticated and accepted. */ | ||
597 | #ifdef WITH_AIXAUTHENTICATE | ||
598 | loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg); | ||
599 | #endif /* WITH_AIXAUTHENTICATE */ | ||
600 | packet_start(SSH_SMSG_SUCCESS); | ||
601 | packet_send(); | ||
602 | packet_write_wait(); | ||
603 | |||
604 | /* Perform session preparation. */ | ||
605 | do_authenticated(pw); | ||
606 | } | ||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef AUTH_H | ||
2 | #define AUTH_H | ||
3 | |||
4 | void do_authentication(void); | ||
5 | |||
6 | #endif | ||
@@ -12,10 +12,12 @@ | |||
12 | * Auxiliary functions for storing and retrieving various data types to/from | 12 | * Auxiliary functions for storing and retrieving various data types to/from |
13 | * Buffers. | 13 | * Buffers. |
14 | * | 14 | * |
15 | * SSH2 packet format added by Markus Friedl | ||
16 | * | ||
15 | */ | 17 | */ |
16 | 18 | ||
17 | #include "includes.h" | 19 | #include "includes.h" |
18 | RCSID("$Id: bufaux.c,v 1.8 2000/03/17 12:40:15 damien Exp $"); | 20 | RCSID("$Id: bufaux.c,v 1.9 2000/04/01 01:09:23 damien Exp $"); |
19 | 21 | ||
20 | #include "ssh.h" | 22 | #include "ssh.h" |
21 | 23 | ||
@@ -83,6 +85,50 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value) | |||
83 | } | 85 | } |
84 | 86 | ||
85 | /* | 87 | /* |
88 | * Stores an BIGNUM in the buffer in SSH2 format. | ||
89 | */ | ||
90 | void | ||
91 | buffer_put_bignum2(Buffer *buffer, BIGNUM *value) | ||
92 | { | ||
93 | int bytes = BN_num_bytes(value) + 1; | ||
94 | unsigned char *buf = xmalloc(bytes); | ||
95 | int oi; | ||
96 | int hasnohigh = 0; | ||
97 | buf[0] = '\0'; | ||
98 | /* Get the value of in binary */ | ||
99 | oi = BN_bn2bin(value, buf+1); | ||
100 | if (oi != bytes-1) | ||
101 | fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d", | ||
102 | oi, bytes); | ||
103 | hasnohigh = (buf[1] & 0x80) ? 0 : 1; | ||
104 | if (value->neg) { | ||
105 | /**XXX should be two's-complement */ | ||
106 | int i, carry; | ||
107 | unsigned char *uc = buf; | ||
108 | log("negativ!"); | ||
109 | for(i = bytes-1, carry = 1; i>=0; i--) { | ||
110 | uc[i] ^= 0xff; | ||
111 | if(carry) | ||
112 | carry = !++uc[i]; | ||
113 | } | ||
114 | } | ||
115 | buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh); | ||
116 | memset(buf, 0, bytes); | ||
117 | xfree(buf); | ||
118 | } | ||
119 | |||
120 | int | ||
121 | buffer_get_bignum2(Buffer *buffer, BIGNUM *value) | ||
122 | { | ||
123 | /**XXX should be two's-complement */ | ||
124 | int len; | ||
125 | unsigned char *bin = (unsigned char *)buffer_get_string(buffer, (unsigned int *)&len); | ||
126 | BN_bin2bn(bin, len, value); | ||
127 | xfree(bin); | ||
128 | return len; | ||
129 | } | ||
130 | |||
131 | /* | ||
86 | * Returns an integer from the buffer (4 bytes, msb first). | 132 | * Returns an integer from the buffer (4 bytes, msb first). |
87 | */ | 133 | */ |
88 | unsigned int | 134 | unsigned int |
@@ -142,6 +188,11 @@ buffer_put_string(Buffer *buffer, const void *buf, unsigned int len) | |||
142 | buffer_put_int(buffer, len); | 188 | buffer_put_int(buffer, len); |
143 | buffer_append(buffer, buf, len); | 189 | buffer_append(buffer, buf, len); |
144 | } | 190 | } |
191 | void | ||
192 | buffer_put_cstring(Buffer *buffer, const char *s) | ||
193 | { | ||
194 | buffer_put_string(buffer, s, strlen(s)); | ||
195 | } | ||
145 | 196 | ||
146 | /* | 197 | /* |
147 | * Returns a character from the buffer (0 - 255). | 198 | * Returns a character from the buffer (0 - 255). |
@@ -11,7 +11,7 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* RCSID("$Id: bufaux.h,v 1.3 1999/11/25 00:54:58 damien Exp $"); */ | 14 | /* RCSID("$Id: bufaux.h,v 1.4 2000/04/01 01:09:23 damien Exp $"); */ |
15 | 15 | ||
16 | #ifndef BUFAUX_H | 16 | #ifndef BUFAUX_H |
17 | #define BUFAUX_H | 17 | #define BUFAUX_H |
@@ -23,9 +23,11 @@ | |||
23 | * by (bits+7)/8 bytes of binary data, msb first. | 23 | * by (bits+7)/8 bytes of binary data, msb first. |
24 | */ | 24 | */ |
25 | void buffer_put_bignum(Buffer * buffer, BIGNUM * value); | 25 | void buffer_put_bignum(Buffer * buffer, BIGNUM * value); |
26 | void buffer_put_bignum2(Buffer * buffer, BIGNUM * value); | ||
26 | 27 | ||
27 | /* Retrieves an BIGNUM from the buffer. */ | 28 | /* Retrieves an BIGNUM from the buffer. */ |
28 | int buffer_get_bignum(Buffer * buffer, BIGNUM * value); | 29 | int buffer_get_bignum(Buffer * buffer, BIGNUM * value); |
30 | int buffer_get_bignum2(Buffer *buffer, BIGNUM * value); | ||
29 | 31 | ||
30 | /* Returns an integer from the buffer (4 bytes, msb first). */ | 32 | /* Returns an integer from the buffer (4 bytes, msb first). */ |
31 | unsigned int buffer_get_int(Buffer * buffer); | 33 | unsigned int buffer_get_int(Buffer * buffer); |
@@ -51,5 +53,6 @@ char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr); | |||
51 | 53 | ||
52 | /* Stores and arbitrary binary string in the buffer. */ | 54 | /* Stores and arbitrary binary string in the buffer. */ |
53 | void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len); | 55 | void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len); |
56 | void buffer_put_cstring(Buffer *buffer, const char *s); | ||
54 | 57 | ||
55 | #endif /* BUFAUX_H */ | 58 | #endif /* BUFAUX_H */ |
diff --git a/channels.c b/channels.c index e60ecc614..b87ff9f4f 100644 --- a/channels.c +++ b/channels.c | |||
@@ -16,7 +16,7 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include "includes.h" | 18 | #include "includes.h" |
19 | RCSID("$Id: channels.c,v 1.19 2000/03/17 12:40:15 damien Exp $"); | 19 | RCSID("$Id: channels.c,v 1.20 2000/04/01 01:09:23 damien Exp $"); |
20 | 20 | ||
21 | #include "ssh.h" | 21 | #include "ssh.h" |
22 | #include "packet.h" | 22 | #include "packet.h" |
@@ -37,6 +37,10 @@ RCSID("$Id: channels.c,v 1.19 2000/03/17 12:40:15 damien Exp $"); | |||
37 | /* Max len of agent socket */ | 37 | /* Max len of agent socket */ |
38 | #define MAX_SOCKET_NAME 100 | 38 | #define MAX_SOCKET_NAME 100 |
39 | 39 | ||
40 | /* default buffer for tcp-fwd-channel */ | ||
41 | #define CHAN_WINDOW_DEFAULT (8*1024) | ||
42 | #define CHAN_PACKET_DEFAULT (CHAN_WINDOW_DEFAULT/2) | ||
43 | |||
40 | /* | 44 | /* |
41 | * Pointer to an array containing all allocated channels. The array is | 45 | * Pointer to an array containing all allocated channels. The array is |
42 | * dynamically extended as needed. | 46 | * dynamically extended as needed. |
@@ -81,8 +85,9 @@ unsigned int x11_fake_data_len; | |||
81 | * network (which might be behind a firewall). | 85 | * network (which might be behind a firewall). |
82 | */ | 86 | */ |
83 | typedef struct { | 87 | typedef struct { |
84 | char *host; /* Host name. */ | 88 | char *host_to_connect; /* Connect to 'host'. */ |
85 | u_short port; /* Port number. */ | 89 | u_short port_to_connect; /* Connect to 'port'. */ |
90 | u_short listen_port; /* Remote side should listen port number. */ | ||
86 | } ForwardPermission; | 91 | } ForwardPermission; |
87 | 92 | ||
88 | /* List of all permitted host/port pairs to connect. */ | 93 | /* List of all permitted host/port pairs to connect. */ |
@@ -119,20 +124,43 @@ channel_permit_all_opens() | |||
119 | all_opens_permitted = 1; | 124 | all_opens_permitted = 1; |
120 | } | 125 | } |
121 | 126 | ||
127 | /* lookup channel by id */ | ||
128 | |||
129 | Channel * | ||
130 | channel_lookup(int id) | ||
131 | { | ||
132 | Channel *c; | ||
133 | if (id < 0 && id > channels_alloc) { | ||
134 | log("channel_lookup: %d: bad id", id); | ||
135 | return NULL; | ||
136 | } | ||
137 | c = &channels[id]; | ||
138 | if (c->type == SSH_CHANNEL_FREE) { | ||
139 | log("channel_lookup: %d: bad id: channel free", id); | ||
140 | return NULL; | ||
141 | } | ||
142 | return c; | ||
143 | } | ||
144 | |||
122 | /* | 145 | /* |
123 | * Allocate a new channel object and set its type and socket. This will cause | 146 | * Allocate a new channel object and set its type and socket. This will cause |
124 | * remote_name to be freed. | 147 | * remote_name to be freed. |
125 | */ | 148 | */ |
126 | 149 | ||
127 | int | 150 | int |
128 | channel_allocate(int type, int sock, char *remote_name) | 151 | channel_new(char *ctype, int type, int rfd, int wfd, int efd, |
152 | int window, int maxpack, int extended_usage, char *remote_name) | ||
129 | { | 153 | { |
130 | int i, found; | 154 | int i, found; |
131 | Channel *c; | 155 | Channel *c; |
132 | 156 | ||
133 | /* Update the maximum file descriptor value. */ | 157 | /* Update the maximum file descriptor value. */ |
134 | if (sock > channel_max_fd_value) | 158 | if (rfd > channel_max_fd_value) |
135 | channel_max_fd_value = sock; | 159 | channel_max_fd_value = rfd; |
160 | if (wfd > channel_max_fd_value) | ||
161 | channel_max_fd_value = wfd; | ||
162 | if (efd > channel_max_fd_value) | ||
163 | channel_max_fd_value = efd; | ||
136 | /* XXX set close-on-exec -markus */ | 164 | /* XXX set close-on-exec -markus */ |
137 | 165 | ||
138 | /* Do initial allocation if this is the first call. */ | 166 | /* Do initial allocation if this is the first call. */ |
@@ -167,388 +195,514 @@ channel_allocate(int type, int sock, char *remote_name) | |||
167 | c = &channels[found]; | 195 | c = &channels[found]; |
168 | buffer_init(&c->input); | 196 | buffer_init(&c->input); |
169 | buffer_init(&c->output); | 197 | buffer_init(&c->output); |
198 | buffer_init(&c->extended); | ||
170 | chan_init_iostates(c); | 199 | chan_init_iostates(c); |
171 | c->self = found; | 200 | c->self = found; |
172 | c->type = type; | 201 | c->type = type; |
173 | c->sock = sock; | 202 | c->ctype = ctype; |
203 | c->local_window = window; | ||
204 | c->local_window_max = window; | ||
205 | c->local_consumed = 0; | ||
206 | c->local_maxpacket = maxpack; | ||
207 | c->remote_window = 0; | ||
208 | c->remote_maxpacket = 0; | ||
209 | c->rfd = rfd; | ||
210 | c->wfd = wfd; | ||
211 | c->sock = (rfd == wfd) ? rfd : -1; | ||
212 | c->efd = efd; | ||
213 | c->extended_usage = extended_usage; | ||
174 | c->remote_id = -1; | 214 | c->remote_id = -1; |
175 | c->remote_name = remote_name; | 215 | c->remote_name = remote_name; |
216 | c->remote_window = 0; | ||
217 | c->remote_maxpacket = 0; | ||
218 | c->cb_fn = NULL; | ||
219 | c->cb_arg = NULL; | ||
220 | c->cb_event = 0; | ||
221 | c->dettach_user = NULL; | ||
176 | debug("channel %d: new [%s]", found, remote_name); | 222 | debug("channel %d: new [%s]", found, remote_name); |
177 | return found; | 223 | return found; |
178 | } | 224 | } |
225 | int | ||
226 | channel_allocate(int type, int sock, char *remote_name) | ||
227 | { | ||
228 | return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name); | ||
229 | } | ||
179 | 230 | ||
180 | /* Free the channel and close its socket. */ | 231 | /* Free the channel and close its socket. */ |
181 | 232 | ||
182 | void | 233 | void |
183 | channel_free(int channel) | 234 | channel_free(int id) |
184 | { | 235 | { |
185 | if (channel < 0 || channel >= channels_alloc || | 236 | Channel *c = channel_lookup(id); |
186 | channels[channel].type == SSH_CHANNEL_FREE) | 237 | if (c == NULL) |
187 | packet_disconnect("channel free: bad local channel %d", channel); | 238 | packet_disconnect("channel free: bad local channel %d", id); |
188 | 239 | debug("channel_free: channel %d: status: %s", id, channel_open_message()); | |
189 | if (compat13) | 240 | if (c->sock != -1) { |
190 | shutdown(channels[channel].sock, SHUT_RDWR); | 241 | shutdown(c->sock, SHUT_RDWR); |
191 | close(channels[channel].sock); | 242 | close(c->sock); |
192 | buffer_free(&channels[channel].input); | 243 | } |
193 | buffer_free(&channels[channel].output); | 244 | buffer_free(&c->input); |
194 | channels[channel].type = SSH_CHANNEL_FREE; | 245 | buffer_free(&c->output); |
195 | if (channels[channel].remote_name) { | 246 | buffer_free(&c->extended); |
196 | xfree(channels[channel].remote_name); | 247 | c->type = SSH_CHANNEL_FREE; |
197 | channels[channel].remote_name = NULL; | 248 | if (c->remote_name) { |
249 | xfree(c->remote_name); | ||
250 | c->remote_name = NULL; | ||
198 | } | 251 | } |
199 | } | 252 | } |
200 | 253 | ||
201 | /* | 254 | /* |
202 | * This is called just before select() to add any bits relevant to channels | 255 | * 'channel_pre*' are called just before select() to add any bits relevant to |
203 | * in the select bitmasks. | 256 | * channels in the select bitmasks. |
257 | */ | ||
258 | /* | ||
259 | * 'channel_post*': perform any appropriate operations for channels which | ||
260 | * have events pending. | ||
204 | */ | 261 | */ |
262 | typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset); | ||
263 | chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE]; | ||
264 | chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE]; | ||
205 | 265 | ||
206 | void | 266 | void |
207 | channel_prepare_select(fd_set * readset, fd_set * writeset) | 267 | channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset) |
208 | { | 268 | { |
209 | int i; | 269 | FD_SET(c->sock, readset); |
210 | Channel *ch; | 270 | } |
211 | unsigned char *ucp; | ||
212 | unsigned int proto_len, data_len; | ||
213 | 271 | ||
214 | for (i = 0; i < channels_alloc; i++) { | 272 | void |
215 | ch = &channels[i]; | 273 | channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) |
216 | redo: | 274 | { |
217 | switch (ch->type) { | 275 | if (buffer_len(&c->input) < packet_get_maxsize()) |
218 | case SSH_CHANNEL_X11_LISTENER: | 276 | FD_SET(c->sock, readset); |
219 | case SSH_CHANNEL_PORT_LISTENER: | 277 | if (buffer_len(&c->output) > 0) |
220 | case SSH_CHANNEL_AUTH_SOCKET: | 278 | FD_SET(c->sock, writeset); |
221 | FD_SET(ch->sock, readset); | 279 | } |
222 | break; | ||
223 | 280 | ||
224 | case SSH_CHANNEL_OPEN: | 281 | void |
225 | if (compat13) { | 282 | channel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset) |
226 | if (buffer_len(&ch->input) < packet_get_maxsize()) | 283 | { |
227 | FD_SET(ch->sock, readset); | 284 | /* test whether sockets are 'alive' for read/write */ |
228 | if (buffer_len(&ch->output) > 0) | 285 | if (c->istate == CHAN_INPUT_OPEN) |
229 | FD_SET(ch->sock, writeset); | 286 | if (buffer_len(&c->input) < packet_get_maxsize()) |
230 | break; | 287 | FD_SET(c->sock, readset); |
231 | } | 288 | if (c->ostate == CHAN_OUTPUT_OPEN || |
232 | /* test whether sockets are 'alive' for read/write */ | 289 | c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { |
233 | if (ch->istate == CHAN_INPUT_OPEN) | 290 | if (buffer_len(&c->output) > 0) { |
234 | if (buffer_len(&ch->input) < packet_get_maxsize()) | 291 | FD_SET(c->sock, writeset); |
235 | FD_SET(ch->sock, readset); | 292 | } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { |
236 | if (ch->ostate == CHAN_OUTPUT_OPEN || | 293 | chan_obuf_empty(c); |
237 | ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) { | 294 | } |
238 | if (buffer_len(&ch->output) > 0) { | 295 | } |
239 | FD_SET(ch->sock, writeset); | 296 | } |
240 | } else if (ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) { | ||
241 | chan_obuf_empty(ch); | ||
242 | } | ||
243 | } | ||
244 | break; | ||
245 | 297 | ||
246 | case SSH_CHANNEL_INPUT_DRAINING: | 298 | void |
247 | if (!compat13) | 299 | channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) |
248 | fatal("cannot happen: IN_DRAIN"); | 300 | { |
249 | if (buffer_len(&ch->input) == 0) { | 301 | if (buffer_len(&c->input) == 0) { |
250 | packet_start(SSH_MSG_CHANNEL_CLOSE); | 302 | packet_start(SSH_MSG_CHANNEL_CLOSE); |
251 | packet_put_int(ch->remote_id); | 303 | packet_put_int(c->remote_id); |
252 | packet_send(); | 304 | packet_send(); |
253 | ch->type = SSH_CHANNEL_CLOSED; | 305 | c->type = SSH_CHANNEL_CLOSED; |
254 | debug("Closing channel %d after input drain.", ch->self); | 306 | debug("Closing channel %d after input drain.", c->self); |
255 | break; | 307 | } |
256 | } | 308 | } |
257 | break; | ||
258 | 309 | ||
259 | case SSH_CHANNEL_OUTPUT_DRAINING: | 310 | void |
260 | if (!compat13) | 311 | channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) |
261 | fatal("cannot happen: OUT_DRAIN"); | 312 | { |
262 | if (buffer_len(&ch->output) == 0) { | 313 | if (buffer_len(&c->output) == 0) |
263 | channel_free(i); | 314 | channel_free(c->self); |
264 | break; | 315 | else |
265 | } | 316 | FD_SET(c->sock, writeset); |
266 | FD_SET(ch->sock, writeset); | 317 | } |
267 | break; | ||
268 | 318 | ||
269 | case SSH_CHANNEL_X11_OPEN: | 319 | /* |
270 | /* | 320 | * This is a special state for X11 authentication spoofing. An opened X11 |
271 | * This is a special state for X11 authentication | 321 | * connection (when authentication spoofing is being done) remains in this |
272 | * spoofing. An opened X11 connection (when | 322 | * state until the first packet has been completely read. The authentication |
273 | * authentication spoofing is being done) remains in | 323 | * data in that packet is then substituted by the real data if it matches the |
274 | * this state until the first packet has been | 324 | * fake data, and the channel is put into normal mode. |
275 | * completely read. The authentication data in that | 325 | */ |
276 | * packet is then substituted by the real data if it | 326 | int |
277 | * matches the fake data, and the channel is put into | 327 | x11_open_helper(Channel *c) |
278 | * normal mode. | 328 | { |
279 | */ | 329 | unsigned char *ucp; |
280 | /* Check if the fixed size part of the packet is in buffer. */ | 330 | unsigned int proto_len, data_len; |
281 | if (buffer_len(&ch->output) < 12) | ||
282 | break; | ||
283 | 331 | ||
284 | /* Parse the lengths of variable-length fields. */ | 332 | /* Check if the fixed size part of the packet is in buffer. */ |
285 | ucp = (unsigned char *) buffer_ptr(&ch->output); | 333 | if (buffer_len(&c->output) < 12) |
286 | if (ucp[0] == 0x42) { /* Byte order MSB first. */ | 334 | return 0; |
287 | proto_len = 256 * ucp[6] + ucp[7]; | 335 | |
288 | data_len = 256 * ucp[8] + ucp[9]; | 336 | /* Parse the lengths of variable-length fields. */ |
289 | } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */ | 337 | ucp = (unsigned char *) buffer_ptr(&c->output); |
290 | proto_len = ucp[6] + 256 * ucp[7]; | 338 | if (ucp[0] == 0x42) { /* Byte order MSB first. */ |
291 | data_len = ucp[8] + 256 * ucp[9]; | 339 | proto_len = 256 * ucp[6] + ucp[7]; |
292 | } else { | 340 | data_len = 256 * ucp[8] + ucp[9]; |
293 | debug("Initial X11 packet contains bad byte order byte: 0x%x", | 341 | } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */ |
294 | ucp[0]); | 342 | proto_len = ucp[6] + 256 * ucp[7]; |
295 | ch->type = SSH_CHANNEL_OPEN; | 343 | data_len = ucp[8] + 256 * ucp[9]; |
296 | goto reject; | 344 | } else { |
297 | } | 345 | debug("Initial X11 packet contains bad byte order byte: 0x%x", |
346 | ucp[0]); | ||
347 | return -1; | ||
348 | } | ||
298 | 349 | ||
299 | /* Check if the whole packet is in buffer. */ | 350 | /* Check if the whole packet is in buffer. */ |
300 | if (buffer_len(&ch->output) < | 351 | if (buffer_len(&c->output) < |
301 | 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) | 352 | 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) |
302 | break; | 353 | return 0; |
303 | 354 | ||
304 | /* Check if authentication protocol matches. */ | 355 | /* Check if authentication protocol matches. */ |
305 | if (proto_len != strlen(x11_saved_proto) || | 356 | if (proto_len != strlen(x11_saved_proto) || |
306 | memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { | 357 | memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { |
307 | debug("X11 connection uses different authentication protocol."); | 358 | debug("X11 connection uses different authentication protocol."); |
308 | ch->type = SSH_CHANNEL_OPEN; | 359 | return -1; |
309 | goto reject; | 360 | } |
310 | } | 361 | /* Check if authentication data matches our fake data. */ |
311 | /* Check if authentication data matches our fake data. */ | 362 | if (data_len != x11_fake_data_len || |
312 | if (data_len != x11_fake_data_len || | 363 | memcmp(ucp + 12 + ((proto_len + 3) & ~3), |
313 | memcmp(ucp + 12 + ((proto_len + 3) & ~3), | 364 | x11_fake_data, x11_fake_data_len) != 0) { |
314 | x11_fake_data, x11_fake_data_len) != 0) { | 365 | debug("X11 auth data does not match fake data."); |
315 | debug("X11 auth data does not match fake data."); | 366 | return -1; |
316 | ch->type = SSH_CHANNEL_OPEN; | 367 | } |
317 | goto reject; | 368 | /* Check fake data length */ |
318 | } | 369 | if (x11_fake_data_len != x11_saved_data_len) { |
319 | /* Check fake data length */ | 370 | error("X11 fake_data_len %d != saved_data_len %d", |
320 | if (x11_fake_data_len != x11_saved_data_len) { | 371 | x11_fake_data_len, x11_saved_data_len); |
321 | error("X11 fake_data_len %d != saved_data_len %d", | 372 | return -1; |
322 | x11_fake_data_len, x11_saved_data_len); | 373 | } |
323 | ch->type = SSH_CHANNEL_OPEN; | 374 | /* |
324 | goto reject; | 375 | * Received authentication protocol and data match |
325 | } | 376 | * our fake data. Substitute the fake data with real |
326 | /* | 377 | * data. |
327 | * Received authentication protocol and data match | 378 | */ |
328 | * our fake data. Substitute the fake data with real | 379 | memcpy(ucp + 12 + ((proto_len + 3) & ~3), |
329 | * data. | 380 | x11_saved_data, x11_saved_data_len); |
330 | */ | 381 | return 1; |
331 | memcpy(ucp + 12 + ((proto_len + 3) & ~3), | 382 | } |
332 | x11_saved_data, x11_saved_data_len); | ||
333 | 383 | ||
334 | /* Start normal processing for the channel. */ | 384 | void |
335 | ch->type = SSH_CHANNEL_OPEN; | 385 | channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) |
336 | goto redo; | 386 | { |
387 | int ret = x11_open_helper(c); | ||
388 | if (ret == 1) { | ||
389 | /* Start normal processing for the channel. */ | ||
390 | c->type = SSH_CHANNEL_OPEN; | ||
391 | } else if (ret == -1) { | ||
392 | /* | ||
393 | * We have received an X11 connection that has bad | ||
394 | * authentication information. | ||
395 | */ | ||
396 | log("X11 connection rejected because of wrong authentication.\r\n"); | ||
397 | buffer_clear(&c->input); | ||
398 | buffer_clear(&c->output); | ||
399 | close(c->sock); | ||
400 | c->sock = -1; | ||
401 | c->type = SSH_CHANNEL_CLOSED; | ||
402 | packet_start(SSH_MSG_CHANNEL_CLOSE); | ||
403 | packet_put_int(c->remote_id); | ||
404 | packet_send(); | ||
405 | } | ||
406 | } | ||
337 | 407 | ||
338 | reject: | 408 | void |
339 | /* | 409 | channel_pre_x11_open_15(Channel *c, fd_set * readset, fd_set * writeset) |
340 | * We have received an X11 connection that has bad | 410 | { |
341 | * authentication information. | 411 | int ret = x11_open_helper(c); |
342 | */ | 412 | if (ret == 1) { |
343 | log("X11 connection rejected because of wrong authentication.\r\n"); | 413 | c->type = SSH_CHANNEL_OPEN; |
344 | buffer_clear(&ch->input); | 414 | } else if (ret == -1) { |
345 | buffer_clear(&ch->output); | 415 | debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); |
346 | if (compat13) { | 416 | chan_read_failed(c); |
347 | close(ch->sock); | 417 | chan_write_failed(c); |
348 | ch->sock = -1; | 418 | debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); |
349 | ch->type = SSH_CHANNEL_CLOSED; | 419 | } |
350 | packet_start(SSH_MSG_CHANNEL_CLOSE); | 420 | } |
351 | packet_put_int(ch->remote_id); | ||
352 | packet_send(); | ||
353 | } else { | ||
354 | debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); | ||
355 | chan_read_failed(ch); | ||
356 | chan_write_failed(ch); | ||
357 | debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); | ||
358 | } | ||
359 | break; | ||
360 | 421 | ||
361 | case SSH_CHANNEL_FREE: | 422 | /* This is our fake X11 server socket. */ |
362 | default: | 423 | void |
363 | continue; | 424 | channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) |
425 | { | ||
426 | struct sockaddr addr; | ||
427 | int newsock, newch; | ||
428 | socklen_t addrlen; | ||
429 | char buf[16384], *remote_hostname; | ||
430 | |||
431 | if (FD_ISSET(c->sock, readset)) { | ||
432 | debug("X11 connection requested."); | ||
433 | addrlen = sizeof(addr); | ||
434 | newsock = accept(c->sock, &addr, &addrlen); | ||
435 | if (newsock < 0) { | ||
436 | error("accept: %.100s", strerror(errno)); | ||
437 | return; | ||
364 | } | 438 | } |
439 | remote_hostname = get_remote_hostname(newsock); | ||
440 | snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", | ||
441 | remote_hostname, get_peer_port(newsock)); | ||
442 | xfree(remote_hostname); | ||
443 | newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, | ||
444 | xstrdup(buf)); | ||
445 | packet_start(SSH_SMSG_X11_OPEN); | ||
446 | packet_put_int(newch); | ||
447 | if (have_hostname_in_open) | ||
448 | packet_put_string(buf, strlen(buf)); | ||
449 | packet_send(); | ||
365 | } | 450 | } |
366 | } | 451 | } |
367 | 452 | ||
368 | /* | 453 | /* |
369 | * After select, perform any appropriate operations for channels which have | 454 | * This socket is listening for connections to a forwarded TCP/IP port. |
370 | * events pending. | ||
371 | */ | 455 | */ |
456 | void | ||
457 | channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) | ||
458 | { | ||
459 | struct sockaddr addr; | ||
460 | int newsock, newch; | ||
461 | socklen_t addrlen; | ||
462 | char buf[1024], *remote_hostname; | ||
463 | int remote_port; | ||
464 | |||
465 | if (FD_ISSET(c->sock, readset)) { | ||
466 | debug("Connection to port %d forwarding " | ||
467 | "to %.100s port %d requested.", | ||
468 | c->listening_port, c->path, c->host_port); | ||
469 | addrlen = sizeof(addr); | ||
470 | newsock = accept(c->sock, &addr, &addrlen); | ||
471 | if (newsock < 0) { | ||
472 | error("accept: %.100s", strerror(errno)); | ||
473 | return; | ||
474 | } | ||
475 | remote_hostname = get_remote_hostname(newsock); | ||
476 | remote_port = get_peer_port(newsock); | ||
477 | snprintf(buf, sizeof buf, | ||
478 | "listen port %d for %.100s port %d, " | ||
479 | "connect from %.200s port %d", | ||
480 | c->listening_port, c->path, c->host_port, | ||
481 | remote_hostname, remote_port); | ||
482 | newch = channel_new("direct-tcpip", | ||
483 | SSH_CHANNEL_OPENING, newsock, newsock, -1, | ||
484 | c->local_window_max, c->local_maxpacket, | ||
485 | 0, xstrdup(buf)); | ||
486 | |||
487 | packet_start(SSH_MSG_PORT_OPEN); | ||
488 | packet_put_int(newch); | ||
489 | packet_put_string(c->path, strlen(c->path)); | ||
490 | packet_put_int(c->host_port); | ||
491 | if (have_hostname_in_open) { | ||
492 | packet_put_string(buf, strlen(buf)); | ||
493 | } | ||
494 | packet_send(); | ||
495 | xfree(remote_hostname); | ||
496 | } | ||
497 | } | ||
372 | 498 | ||
373 | void | 499 | /* |
374 | channel_after_select(fd_set * readset, fd_set * writeset) | 500 | * This is the authentication agent socket listening for connections from |
501 | * clients. | ||
502 | */ | ||
503 | void | ||
504 | channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) | ||
375 | { | 505 | { |
376 | struct sockaddr addr; | 506 | struct sockaddr addr; |
377 | int newsock, i, newch, len; | 507 | int newsock, newch; |
378 | socklen_t addrlen; | 508 | socklen_t addrlen; |
379 | Channel *ch; | ||
380 | char buf[16384], *remote_hostname; | ||
381 | 509 | ||
382 | /* Loop over all channels... */ | 510 | if (FD_ISSET(c->sock, readset)) { |
383 | for (i = 0; i < channels_alloc; i++) { | 511 | addrlen = sizeof(addr); |
384 | ch = &channels[i]; | 512 | newsock = accept(c->sock, &addr, &addrlen); |
385 | switch (ch->type) { | 513 | if (newsock < 0) { |
386 | case SSH_CHANNEL_X11_LISTENER: | 514 | error("accept from auth socket: %.100s", strerror(errno)); |
387 | /* This is our fake X11 server socket. */ | 515 | return; |
388 | if (FD_ISSET(ch->sock, readset)) { | 516 | } |
389 | debug("X11 connection requested."); | 517 | newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, |
390 | addrlen = sizeof(addr); | 518 | xstrdup("accepted auth socket")); |
391 | newsock = accept(ch->sock, &addr, &addrlen); | 519 | packet_start(SSH_SMSG_AGENT_OPEN); |
392 | if (newsock < 0) { | 520 | packet_put_int(newch); |
393 | error("accept: %.100s", strerror(errno)); | 521 | packet_send(); |
394 | break; | 522 | } |
395 | } | 523 | } |
396 | remote_hostname = get_remote_hostname(newsock); | ||
397 | snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", | ||
398 | remote_hostname, get_peer_port(newsock)); | ||
399 | xfree(remote_hostname); | ||
400 | newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, | ||
401 | xstrdup(buf)); | ||
402 | packet_start(SSH_SMSG_X11_OPEN); | ||
403 | packet_put_int(newch); | ||
404 | if (have_hostname_in_open) | ||
405 | packet_put_string(buf, strlen(buf)); | ||
406 | packet_send(); | ||
407 | } | ||
408 | break; | ||
409 | 524 | ||
410 | case SSH_CHANNEL_PORT_LISTENER: | 525 | int |
411 | /* | 526 | channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) |
412 | * This socket is listening for connections to a | 527 | { |
413 | * forwarded TCP/IP port. | 528 | char buf[16*1024]; |
414 | */ | 529 | int len; |
415 | if (FD_ISSET(ch->sock, readset)) { | 530 | |
416 | debug("Connection to port %d forwarding to %.100s port %d requested.", | 531 | if (c->rfd != -1 && |
417 | ch->listening_port, ch->path, ch->host_port); | 532 | FD_ISSET(c->rfd, readset)) { |
418 | addrlen = sizeof(addr); | 533 | len = read(c->rfd, buf, sizeof(buf)); |
419 | newsock = accept(ch->sock, &addr, &addrlen); | 534 | if (len <= 0) { |
420 | if (newsock < 0) { | 535 | debug("channel %d: read<0 rfd %d len %d", |
421 | error("accept: %.100s", strerror(errno)); | 536 | c->self, c->rfd, len); |
422 | break; | 537 | if (compat13) { |
423 | } | 538 | buffer_consume(&c->output, buffer_len(&c->output)); |
424 | remote_hostname = get_remote_hostname(newsock); | 539 | c->type = SSH_CHANNEL_INPUT_DRAINING; |
425 | snprintf(buf, sizeof buf, "listen port %d for %.100s port %d, connect from %.200s port %d", | 540 | debug("Channel %d status set to input draining.", c->self); |
426 | ch->listening_port, ch->path, ch->host_port, | 541 | } else { |
427 | remote_hostname, get_peer_port(newsock)); | 542 | chan_read_failed(c); |
428 | xfree(remote_hostname); | ||
429 | newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, | ||
430 | xstrdup(buf)); | ||
431 | packet_start(SSH_MSG_PORT_OPEN); | ||
432 | packet_put_int(newch); | ||
433 | packet_put_string(ch->path, strlen(ch->path)); | ||
434 | packet_put_int(ch->host_port); | ||
435 | if (have_hostname_in_open) | ||
436 | packet_put_string(buf, strlen(buf)); | ||
437 | packet_send(); | ||
438 | } | 543 | } |
439 | break; | 544 | return -1; |
440 | 545 | } | |
441 | case SSH_CHANNEL_AUTH_SOCKET: | 546 | buffer_append(&c->input, buf, len); |
442 | /* | 547 | } |
443 | * This is the authentication agent socket listening | 548 | return 1; |
444 | * for connections from clients. | 549 | } |
445 | */ | 550 | int |
446 | if (FD_ISSET(ch->sock, readset)) { | 551 | channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) |
447 | addrlen = sizeof(addr); | 552 | { |
448 | newsock = accept(ch->sock, &addr, &addrlen); | 553 | int len; |
449 | if (newsock < 0) { | 554 | |
450 | error("accept from auth socket: %.100s", strerror(errno)); | 555 | /* Send buffered output data to the socket. */ |
451 | break; | 556 | if (c->wfd != -1 && |
452 | } | 557 | FD_ISSET(c->wfd, writeset) && |
453 | newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, | 558 | buffer_len(&c->output) > 0) { |
454 | xstrdup("accepted auth socket")); | 559 | len = write(c->wfd, buffer_ptr(&c->output), |
455 | packet_start(SSH_SMSG_AGENT_OPEN); | 560 | buffer_len(&c->output)); |
456 | packet_put_int(newch); | 561 | if (len <= 0) { |
457 | packet_send(); | 562 | if (compat13) { |
563 | buffer_consume(&c->output, buffer_len(&c->output)); | ||
564 | debug("Channel %d status set to input draining.", c->self); | ||
565 | c->type = SSH_CHANNEL_INPUT_DRAINING; | ||
566 | } else { | ||
567 | chan_write_failed(c); | ||
458 | } | 568 | } |
459 | break; | 569 | return -1; |
570 | } | ||
571 | buffer_consume(&c->output, len); | ||
572 | } | ||
573 | return 1; | ||
574 | } | ||
460 | 575 | ||
461 | case SSH_CHANNEL_OPEN: | 576 | void |
462 | /* | 577 | channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset) |
463 | * This is an open two-way communication channel. It | 578 | { |
464 | * is not of interest to us at this point what kind | 579 | channel_handle_rfd(c, readset, writeset); |
465 | * of data is being transmitted. | 580 | channel_handle_wfd(c, readset, writeset); |
466 | */ | 581 | } |
467 | 582 | ||
468 | /* | 583 | void |
469 | * Read available incoming data and append it to | 584 | channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) |
470 | * buffer; shutdown socket, if read or write failes | 585 | { |
471 | */ | 586 | int len; |
472 | if (FD_ISSET(ch->sock, readset)) { | 587 | /* Send buffered output data to the socket. */ |
473 | len = read(ch->sock, buf, sizeof(buf)); | 588 | if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) { |
474 | if (len <= 0) { | 589 | len = write(c->sock, buffer_ptr(&c->output), |
475 | if (compat13) { | 590 | buffer_len(&c->output)); |
476 | buffer_consume(&ch->output, buffer_len(&ch->output)); | 591 | if (len <= 0) |
477 | ch->type = SSH_CHANNEL_INPUT_DRAINING; | 592 | buffer_consume(&c->output, buffer_len(&c->output)); |
478 | debug("Channel %d status set to input draining.", i); | 593 | else |
479 | } else { | 594 | buffer_consume(&c->output, len); |
480 | chan_read_failed(ch); | 595 | } |
481 | } | 596 | } |
482 | break; | ||
483 | } | ||
484 | buffer_append(&ch->input, buf, len); | ||
485 | } | ||
486 | /* Send buffered output data to the socket. */ | ||
487 | if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) { | ||
488 | len = write(ch->sock, buffer_ptr(&ch->output), | ||
489 | buffer_len(&ch->output)); | ||
490 | if (len <= 0) { | ||
491 | if (compat13) { | ||
492 | buffer_consume(&ch->output, buffer_len(&ch->output)); | ||
493 | debug("Channel %d status set to input draining.", i); | ||
494 | ch->type = SSH_CHANNEL_INPUT_DRAINING; | ||
495 | } else { | ||
496 | chan_write_failed(ch); | ||
497 | } | ||
498 | break; | ||
499 | } | ||
500 | buffer_consume(&ch->output, len); | ||
501 | } | ||
502 | break; | ||
503 | 597 | ||
504 | case SSH_CHANNEL_OUTPUT_DRAINING: | 598 | void |
505 | if (!compat13) | 599 | channel_handler_init_13(void) |
506 | fatal("cannot happen: OUT_DRAIN"); | 600 | { |
507 | /* Send buffered output data to the socket. */ | 601 | channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13; |
508 | if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) { | 602 | channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_13; |
509 | len = write(ch->sock, buffer_ptr(&ch->output), | 603 | channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; |
510 | buffer_len(&ch->output)); | 604 | channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
511 | if (len <= 0) | 605 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
512 | buffer_consume(&ch->output, buffer_len(&ch->output)); | 606 | channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining; |
513 | else | 607 | channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; |
514 | buffer_consume(&ch->output, len); | 608 | |
515 | } | 609 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; |
516 | break; | 610 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
611 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; | ||
612 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | ||
613 | channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; | ||
614 | } | ||
517 | 615 | ||
518 | case SSH_CHANNEL_X11_OPEN: | 616 | void |
519 | case SSH_CHANNEL_FREE: | 617 | channel_handler_init_15(void) |
520 | default: | 618 | { |
619 | channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_15; | ||
620 | channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_15; | ||
621 | channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; | ||
622 | channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; | ||
623 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; | ||
624 | |||
625 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; | ||
626 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; | ||
627 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | ||
628 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; | ||
629 | } | ||
630 | |||
631 | void | ||
632 | channel_handler_init(void) | ||
633 | { | ||
634 | int i; | ||
635 | for(i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) { | ||
636 | channel_pre[i] = NULL; | ||
637 | channel_post[i] = NULL; | ||
638 | } | ||
639 | if (compat13) | ||
640 | channel_handler_init_13(); | ||
641 | else | ||
642 | channel_handler_init_15(); | ||
643 | } | ||
644 | |||
645 | void | ||
646 | channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) | ||
647 | { | ||
648 | static int did_init = 0; | ||
649 | int i; | ||
650 | Channel *c; | ||
651 | |||
652 | if (!did_init) { | ||
653 | channel_handler_init(); | ||
654 | did_init = 1; | ||
655 | } | ||
656 | for (i = 0; i < channels_alloc; i++) { | ||
657 | c = &channels[i]; | ||
658 | if (c->type == SSH_CHANNEL_FREE) | ||
521 | continue; | 659 | continue; |
522 | } | 660 | if (ftab[c->type] == NULL) |
661 | continue; | ||
662 | (*ftab[c->type])(c, readset, writeset); | ||
663 | if (!compat13) | ||
664 | chan_delete_if_full_closed(c); | ||
523 | } | 665 | } |
524 | } | 666 | } |
525 | 667 | ||
668 | void | ||
669 | channel_prepare_select(fd_set * readset, fd_set * writeset) | ||
670 | { | ||
671 | channel_handler(channel_pre, readset, writeset); | ||
672 | } | ||
673 | |||
674 | void | ||
675 | channel_after_select(fd_set * readset, fd_set * writeset) | ||
676 | { | ||
677 | channel_handler(channel_post, readset, writeset); | ||
678 | } | ||
679 | |||
526 | /* If there is data to send to the connection, send some of it now. */ | 680 | /* If there is data to send to the connection, send some of it now. */ |
527 | 681 | ||
528 | void | 682 | void |
529 | channel_output_poll() | 683 | channel_output_poll() |
530 | { | 684 | { |
531 | int len, i; | 685 | int len, i; |
532 | Channel *ch; | 686 | Channel *c; |
533 | 687 | ||
534 | for (i = 0; i < channels_alloc; i++) { | 688 | for (i = 0; i < channels_alloc; i++) { |
535 | ch = &channels[i]; | 689 | c = &channels[i]; |
536 | 690 | ||
537 | /* We are only interested in channels that can have buffered incoming data. */ | 691 | /* We are only interested in channels that can have buffered incoming data. */ |
538 | if (compat13) { | 692 | if (compat13) { |
539 | if (ch->type != SSH_CHANNEL_OPEN && | 693 | if (c->type != SSH_CHANNEL_OPEN && |
540 | ch->type != SSH_CHANNEL_INPUT_DRAINING) | 694 | c->type != SSH_CHANNEL_INPUT_DRAINING) |
541 | continue; | 695 | continue; |
542 | } else { | 696 | } else { |
543 | if (ch->type != SSH_CHANNEL_OPEN) | 697 | if (c->type != SSH_CHANNEL_OPEN) |
544 | continue; | 698 | continue; |
545 | if (ch->istate != CHAN_INPUT_OPEN && | 699 | if (c->istate != CHAN_INPUT_OPEN && |
546 | ch->istate != CHAN_INPUT_WAIT_DRAIN) | 700 | c->istate != CHAN_INPUT_WAIT_DRAIN) |
547 | continue; | 701 | continue; |
548 | } | 702 | } |
549 | 703 | ||
550 | /* Get the amount of buffered data for this channel. */ | 704 | /* Get the amount of buffered data for this channel. */ |
551 | len = buffer_len(&ch->input); | 705 | len = buffer_len(&c->input); |
552 | if (len > 0) { | 706 | if (len > 0) { |
553 | /* Send some data for the other side over the secure connection. */ | 707 | /* Send some data for the other side over the secure connection. */ |
554 | if (packet_is_interactive()) { | 708 | if (packet_is_interactive()) { |
@@ -556,22 +710,26 @@ channel_output_poll() | |||
556 | len = 512; | 710 | len = 512; |
557 | } else { | 711 | } else { |
558 | /* Keep the packets at reasonable size. */ | 712 | /* Keep the packets at reasonable size. */ |
559 | if (len > packet_get_maxsize()/2) | 713 | if (len > packet_get_maxsize()) |
560 | len = packet_get_maxsize()/2; | 714 | len = packet_get_maxsize()/2; |
561 | } | 715 | } |
562 | packet_start(SSH_MSG_CHANNEL_DATA); | 716 | if (len > 0) { |
563 | packet_put_int(ch->remote_id); | 717 | packet_start(SSH_MSG_CHANNEL_DATA); |
564 | packet_put_string(buffer_ptr(&ch->input), len); | 718 | packet_put_int(c->remote_id); |
565 | packet_send(); | 719 | packet_put_string(buffer_ptr(&c->input), len); |
566 | buffer_consume(&ch->input, len); | 720 | packet_send(); |
567 | } else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) { | 721 | buffer_consume(&c->input, len); |
722 | c->remote_window -= len; | ||
723 | debug("channel %d: send data len %d", c->self, len); | ||
724 | } | ||
725 | } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { | ||
568 | if (compat13) | 726 | if (compat13) |
569 | fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); | 727 | fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); |
570 | /* | 728 | /* |
571 | * input-buffer is empty and read-socket shutdown: | 729 | * input-buffer is empty and read-socket shutdown: |
572 | * tell peer, that we will not send more data: send IEOF | 730 | * tell peer, that we will not send more data: send IEOF |
573 | */ | 731 | */ |
574 | chan_ibuf_empty(ch); | 732 | chan_ibuf_empty(c); |
575 | } | 733 | } |
576 | } | 734 | } |
577 | } | 735 | } |
@@ -583,35 +741,33 @@ channel_output_poll() | |||
583 | */ | 741 | */ |
584 | 742 | ||
585 | void | 743 | void |
586 | channel_input_data(int payload_len) | 744 | channel_input_data(int type, int plen) |
587 | { | 745 | { |
588 | int id; | 746 | int id; |
589 | char *data; | 747 | char *data; |
590 | unsigned int data_len; | 748 | unsigned int data_len; |
591 | Channel *ch; | 749 | Channel *c; |
592 | 750 | ||
593 | /* Get the channel number and verify it. */ | 751 | /* Get the channel number and verify it. */ |
594 | id = packet_get_int(); | 752 | id = packet_get_int(); |
595 | if (id < 0 || id >= channels_alloc) | 753 | c = channel_lookup(id); |
754 | if (c == NULL) | ||
596 | packet_disconnect("Received data for nonexistent channel %d.", id); | 755 | packet_disconnect("Received data for nonexistent channel %d.", id); |
597 | ch = &channels[id]; | ||
598 | |||
599 | if (ch->type == SSH_CHANNEL_FREE) | ||
600 | packet_disconnect("Received data for free channel %d.", ch->self); | ||
601 | 756 | ||
602 | /* Ignore any data for non-open channels (might happen on close) */ | 757 | /* Ignore any data for non-open channels (might happen on close) */ |
603 | if (ch->type != SSH_CHANNEL_OPEN && | 758 | if (c->type != SSH_CHANNEL_OPEN && |
604 | ch->type != SSH_CHANNEL_X11_OPEN) | 759 | c->type != SSH_CHANNEL_X11_OPEN) |
605 | return; | 760 | return; |
606 | 761 | ||
607 | /* same for protocol 1.5 if output end is no longer open */ | 762 | /* same for protocol 1.5 if output end is no longer open */ |
608 | if (!compat13 && ch->ostate != CHAN_OUTPUT_OPEN) | 763 | if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) |
609 | return; | 764 | return; |
610 | 765 | ||
611 | /* Get the data. */ | 766 | /* Get the data. */ |
612 | data = packet_get_string(&data_len); | 767 | data = packet_get_string(&data_len); |
613 | packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA); | 768 | |
614 | buffer_append(&ch->output, data, data_len); | 769 | packet_integrity_check(plen, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA); |
770 | buffer_append(&c->output, data, data_len); | ||
615 | xfree(data); | 771 | xfree(data); |
616 | } | 772 | } |
617 | 773 | ||
@@ -624,45 +780,60 @@ int | |||
624 | channel_not_very_much_buffered_data() | 780 | channel_not_very_much_buffered_data() |
625 | { | 781 | { |
626 | unsigned int i; | 782 | unsigned int i; |
627 | Channel *ch; | 783 | Channel *c; |
628 | 784 | ||
629 | for (i = 0; i < channels_alloc; i++) { | 785 | for (i = 0; i < channels_alloc; i++) { |
630 | ch = &channels[i]; | 786 | c = &channels[i]; |
631 | if (ch->type == SSH_CHANNEL_OPEN) { | 787 | if (c->type == SSH_CHANNEL_OPEN) { |
632 | if (buffer_len(&ch->input) > packet_get_maxsize()) | 788 | if (buffer_len(&c->input) > packet_get_maxsize()) { |
789 | debug("channel %d: big input buffer %d", | ||
790 | c->self, buffer_len(&c->input)); | ||
633 | return 0; | 791 | return 0; |
634 | if (buffer_len(&ch->output) > packet_get_maxsize()) | 792 | } |
793 | if (buffer_len(&c->output) > packet_get_maxsize()) { | ||
794 | debug("channel %d: big output buffer %d", | ||
795 | c->self, buffer_len(&c->output)); | ||
635 | return 0; | 796 | return 0; |
797 | } | ||
636 | } | 798 | } |
637 | } | 799 | } |
638 | return 1; | 800 | return 1; |
639 | } | 801 | } |
640 | 802 | ||
641 | /* This is called after receiving CHANNEL_CLOSE/IEOF. */ | 803 | void |
804 | channel_input_ieof(int type, int plen) | ||
805 | { | ||
806 | int id; | ||
807 | Channel *c; | ||
808 | |||
809 | packet_integrity_check(plen, 4, type); | ||
810 | |||
811 | id = packet_get_int(); | ||
812 | c = channel_lookup(id); | ||
813 | if (c == NULL) | ||
814 | packet_disconnect("Received ieof for nonexistent channel %d.", id); | ||
815 | chan_rcvd_ieof(c); | ||
816 | } | ||
642 | 817 | ||
643 | void | 818 | void |
644 | channel_input_close() | 819 | channel_input_close(int type, int plen) |
645 | { | 820 | { |
646 | int channel; | 821 | int id; |
822 | Channel *c; | ||
647 | 823 | ||
648 | /* Get the channel number and verify it. */ | 824 | packet_integrity_check(plen, 4, type); |
649 | channel = packet_get_int(); | 825 | |
650 | if (channel < 0 || channel >= channels_alloc || | 826 | id = packet_get_int(); |
651 | channels[channel].type == SSH_CHANNEL_FREE) | 827 | c = channel_lookup(id); |
652 | packet_disconnect("Received data for nonexistent channel %d.", channel); | 828 | if (c == NULL) |
653 | 829 | packet_disconnect("Received close for nonexistent channel %d.", id); | |
654 | if (!compat13) { | ||
655 | /* proto version 1.5 overloads CLOSE with IEOF */ | ||
656 | chan_rcvd_ieof(&channels[channel]); | ||
657 | return; | ||
658 | } | ||
659 | 830 | ||
660 | /* | 831 | /* |
661 | * Send a confirmation that we have closed the channel and no more | 832 | * Send a confirmation that we have closed the channel and no more |
662 | * data is coming for it. | 833 | * data is coming for it. |
663 | */ | 834 | */ |
664 | packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); | 835 | packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); |
665 | packet_put_int(channels[channel].remote_id); | 836 | packet_put_int(c->remote_id); |
666 | packet_send(); | 837 | packet_send(); |
667 | 838 | ||
668 | /* | 839 | /* |
@@ -672,81 +843,80 @@ channel_input_close() | |||
672 | * no-one to receive the confirmation. The channel gets freed when | 843 | * no-one to receive the confirmation. The channel gets freed when |
673 | * the confirmation arrives. | 844 | * the confirmation arrives. |
674 | */ | 845 | */ |
675 | if (channels[channel].type != SSH_CHANNEL_CLOSED) { | 846 | if (c->type != SSH_CHANNEL_CLOSED) { |
676 | /* | 847 | /* |
677 | * Not a closed channel - mark it as draining, which will | 848 | * Not a closed channel - mark it as draining, which will |
678 | * cause it to be freed later. | 849 | * cause it to be freed later. |
679 | */ | 850 | */ |
680 | buffer_consume(&channels[channel].input, | 851 | buffer_consume(&c->input, buffer_len(&c->input)); |
681 | buffer_len(&channels[channel].input)); | 852 | c->type = SSH_CHANNEL_OUTPUT_DRAINING; |
682 | channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING; | ||
683 | } | 853 | } |
684 | } | 854 | } |
685 | 855 | ||
686 | /* This is called after receiving CHANNEL_CLOSE_CONFIRMATION/OCLOSE. */ | 856 | /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ |
687 | |||
688 | void | 857 | void |
689 | channel_input_close_confirmation() | 858 | channel_input_oclose(int type, int plen) |
690 | { | 859 | { |
691 | int channel; | 860 | int id = packet_get_int(); |
692 | 861 | Channel *c = channel_lookup(id); | |
693 | /* Get the channel number and verify it. */ | 862 | packet_integrity_check(plen, 4, type); |
694 | channel = packet_get_int(); | 863 | if (c == NULL) |
695 | if (channel < 0 || channel >= channels_alloc) | 864 | packet_disconnect("Received oclose for nonexistent channel %d.", id); |
696 | packet_disconnect("Received close confirmation for out-of-range channel %d.", | 865 | chan_rcvd_oclose(c); |
697 | channel); | ||
698 | |||
699 | if (!compat13) { | ||
700 | /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ | ||
701 | chan_rcvd_oclose(&channels[channel]); | ||
702 | return; | ||
703 | } | ||
704 | if (channels[channel].type != SSH_CHANNEL_CLOSED) | ||
705 | packet_disconnect("Received close confirmation for non-closed channel %d (type %d).", | ||
706 | channel, channels[channel].type); | ||
707 | |||
708 | /* Free the channel. */ | ||
709 | channel_free(channel); | ||
710 | } | 866 | } |
711 | 867 | ||
712 | /* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */ | 868 | void |
869 | channel_input_close_confirmation(int type, int plen) | ||
870 | { | ||
871 | int id = packet_get_int(); | ||
872 | Channel *c = channel_lookup(id); | ||
873 | |||
874 | if (c == NULL) | ||
875 | packet_disconnect("Received close confirmation for " | ||
876 | "out-of-range channel %d.", id); | ||
877 | if (c->type != SSH_CHANNEL_CLOSED) | ||
878 | packet_disconnect("Received close confirmation for " | ||
879 | "non-closed channel %d (type %d).", id, c->type); | ||
880 | channel_free(c->self); | ||
881 | } | ||
713 | 882 | ||
714 | void | 883 | void |
715 | channel_input_open_confirmation() | 884 | channel_input_open_confirmation(int type, int plen) |
716 | { | 885 | { |
717 | int channel, remote_channel; | 886 | int id, remote_id; |
887 | Channel *c; | ||
718 | 888 | ||
719 | /* Get the channel number and verify it. */ | 889 | packet_integrity_check(plen, 4 + 4, type); |
720 | channel = packet_get_int(); | ||
721 | if (channel < 0 || channel >= channels_alloc || | ||
722 | channels[channel].type != SSH_CHANNEL_OPENING) | ||
723 | packet_disconnect("Received open confirmation for non-opening channel %d.", | ||
724 | channel); | ||
725 | 890 | ||
726 | /* Get remote side's id for this channel. */ | 891 | id = packet_get_int(); |
727 | remote_channel = packet_get_int(); | 892 | c = channel_lookup(id); |
728 | 893 | ||
894 | if (c==NULL || c->type != SSH_CHANNEL_OPENING) | ||
895 | packet_disconnect("Received open confirmation for " | ||
896 | "non-opening channel %d.", id); | ||
897 | remote_id = packet_get_int(); | ||
729 | /* Record the remote channel number and mark that the channel is now open. */ | 898 | /* Record the remote channel number and mark that the channel is now open. */ |
730 | channels[channel].remote_id = remote_channel; | 899 | c->remote_id = remote_id; |
731 | channels[channel].type = SSH_CHANNEL_OPEN; | 900 | c->type = SSH_CHANNEL_OPEN; |
732 | } | 901 | } |
733 | 902 | ||
734 | /* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */ | ||
735 | |||
736 | void | 903 | void |
737 | channel_input_open_failure() | 904 | channel_input_open_failure(int type, int plen) |
738 | { | 905 | { |
739 | int channel; | 906 | int id; |
907 | Channel *c; | ||
740 | 908 | ||
741 | /* Get the channel number and verify it. */ | 909 | packet_integrity_check(plen, 4, type); |
742 | channel = packet_get_int(); | 910 | |
743 | if (channel < 0 || channel >= channels_alloc || | 911 | id = packet_get_int(); |
744 | channels[channel].type != SSH_CHANNEL_OPENING) | 912 | c = channel_lookup(id); |
745 | packet_disconnect("Received open failure for non-opening channel %d.", | 913 | |
746 | channel); | 914 | if (c==NULL || c->type != SSH_CHANNEL_OPENING) |
915 | packet_disconnect("Received open failure for " | ||
916 | "non-opening channel %d.", id); | ||
747 | 917 | ||
748 | /* Free the channel. This will also close the socket. */ | 918 | /* Free the channel. This will also close the socket. */ |
749 | channel_free(channel); | 919 | channel_free(id); |
750 | } | 920 | } |
751 | 921 | ||
752 | /* | 922 | /* |
@@ -859,15 +1029,16 @@ channel_open_message() | |||
859 | case SSH_CHANNEL_X11_OPEN: | 1029 | case SSH_CHANNEL_X11_OPEN: |
860 | case SSH_CHANNEL_INPUT_DRAINING: | 1030 | case SSH_CHANNEL_INPUT_DRAINING: |
861 | case SSH_CHANNEL_OUTPUT_DRAINING: | 1031 | case SSH_CHANNEL_OUTPUT_DRAINING: |
862 | snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d)\r\n", | 1032 | snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n", |
863 | c->self, c->remote_name, | 1033 | c->self, c->remote_name, |
864 | c->type, c->remote_id, | 1034 | c->type, c->remote_id, |
865 | c->istate, buffer_len(&c->input), | 1035 | c->istate, buffer_len(&c->input), |
866 | c->ostate, buffer_len(&c->output)); | 1036 | c->ostate, buffer_len(&c->output), |
1037 | c->rfd, c->wfd); | ||
867 | buffer_append(&buffer, buf, strlen(buf)); | 1038 | buffer_append(&buffer, buf, strlen(buf)); |
868 | continue; | 1039 | continue; |
869 | default: | 1040 | default: |
870 | fatal("channel_still_open: bad channel type %d", c->type); | 1041 | fatal("channel_open_message: bad channel type %d", c->type); |
871 | /* NOTREACHED */ | 1042 | /* NOTREACHED */ |
872 | } | 1043 | } |
873 | } | 1044 | } |
@@ -950,8 +1121,11 @@ channel_request_local_forwarding(u_short port, const char *host, | |||
950 | continue; | 1121 | continue; |
951 | } | 1122 | } |
952 | /* Allocate a channel number for the socket. */ | 1123 | /* Allocate a channel number for the socket. */ |
953 | ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock, | 1124 | ch = channel_new( |
954 | xstrdup("port listener")); | 1125 | "port listener", SSH_CHANNEL_PORT_LISTENER, |
1126 | sock, sock, -1, | ||
1127 | CHAN_WINDOW_DEFAULT, CHAN_PACKET_DEFAULT, | ||
1128 | 0, xstrdup("port listener")); | ||
955 | strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); | 1129 | strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); |
956 | channels[ch].host_port = host_port; | 1130 | channels[ch].host_port = host_port; |
957 | channels[ch].listening_port = port; | 1131 | channels[ch].listening_port = port; |
@@ -968,26 +1142,26 @@ channel_request_local_forwarding(u_short port, const char *host, | |||
968 | */ | 1142 | */ |
969 | 1143 | ||
970 | void | 1144 | void |
971 | channel_request_remote_forwarding(u_short port, const char *host, | 1145 | channel_request_remote_forwarding(u_short listen_port, const char *host_to_connect, |
972 | u_short remote_port) | 1146 | u_short port_to_connect) |
973 | { | 1147 | { |
974 | int payload_len; | 1148 | int payload_len; |
975 | /* Record locally that connection to this host/port is permitted. */ | 1149 | /* Record locally that connection to this host/port is permitted. */ |
976 | if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) | 1150 | if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) |
977 | fatal("channel_request_remote_forwarding: too many forwards"); | 1151 | fatal("channel_request_remote_forwarding: too many forwards"); |
978 | 1152 | ||
979 | permitted_opens[num_permitted_opens].host = xstrdup(host); | 1153 | permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); |
980 | permitted_opens[num_permitted_opens].port = remote_port; | 1154 | permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; |
1155 | permitted_opens[num_permitted_opens].listen_port = listen_port; | ||
981 | num_permitted_opens++; | 1156 | num_permitted_opens++; |
982 | 1157 | ||
983 | /* Send the forward request to the remote side. */ | 1158 | /* Send the forward request to the remote side. */ |
984 | packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); | 1159 | packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); |
985 | packet_put_int(port); | 1160 | packet_put_int(port_to_connect); |
986 | packet_put_string(host, strlen(host)); | 1161 | packet_put_string(host_to_connect, strlen(host_to_connect)); |
987 | packet_put_int(remote_port); | 1162 | packet_put_int(listen_port); |
988 | packet_send(); | 1163 | packet_send(); |
989 | packet_write_wait(); | 1164 | packet_write_wait(); |
990 | |||
991 | /* | 1165 | /* |
992 | * Wait for response from the remote side. It will send a disconnect | 1166 | * Wait for response from the remote side. It will send a disconnect |
993 | * message on failure, and we will never see it here. | 1167 | * message on failure, and we will never see it here. |
@@ -1029,63 +1203,14 @@ channel_input_port_forward_request(int is_root) | |||
1029 | xfree(hostname); | 1203 | xfree(hostname); |
1030 | } | 1204 | } |
1031 | 1205 | ||
1032 | /* | 1206 | /* XXX move to aux.c */ |
1033 | * This is called after receiving PORT_OPEN message. This attempts to | 1207 | int |
1034 | * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION | 1208 | channel_connect_to(const char *host, u_short host_port) |
1035 | * or CHANNEL_OPEN_FAILURE. | ||
1036 | */ | ||
1037 | |||
1038 | void | ||
1039 | channel_input_port_open(int payload_len) | ||
1040 | { | 1209 | { |
1041 | int remote_channel, sock = 0, newch, i; | ||
1042 | u_short host_port; | ||
1043 | char *host, *originator_string; | ||
1044 | unsigned int host_len, originator_len; | ||
1045 | struct addrinfo hints, *ai, *aitop; | 1210 | struct addrinfo hints, *ai, *aitop; |
1046 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | 1211 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
1047 | int gaierr; | 1212 | int gaierr; |
1048 | 1213 | int sock = -1; | |
1049 | /* Get remote channel number. */ | ||
1050 | remote_channel = packet_get_int(); | ||
1051 | |||
1052 | /* Get host name to connect to. */ | ||
1053 | host = packet_get_string(&host_len); | ||
1054 | |||
1055 | /* Get port to connect to. */ | ||
1056 | host_port = packet_get_int(); | ||
1057 | |||
1058 | /* Get remote originator name. */ | ||
1059 | if (have_hostname_in_open) { | ||
1060 | originator_string = packet_get_string(&originator_len); | ||
1061 | originator_len += 4; /* size of packet_int */ | ||
1062 | } else { | ||
1063 | originator_string = xstrdup("unknown (remote did not supply name)"); | ||
1064 | originator_len = 0; /* no originator supplied */ | ||
1065 | } | ||
1066 | |||
1067 | packet_integrity_check(payload_len, | ||
1068 | 4 + 4 + host_len + 4 + originator_len, | ||
1069 | SSH_MSG_PORT_OPEN); | ||
1070 | |||
1071 | /* Check if opening that port is permitted. */ | ||
1072 | if (!all_opens_permitted) { | ||
1073 | /* Go trough all permitted ports. */ | ||
1074 | for (i = 0; i < num_permitted_opens; i++) | ||
1075 | if (permitted_opens[i].port == host_port && | ||
1076 | strcmp(permitted_opens[i].host, host) == 0) | ||
1077 | break; | ||
1078 | |||
1079 | /* Check if we found the requested port among those permitted. */ | ||
1080 | if (i >= num_permitted_opens) { | ||
1081 | /* The port is not permitted. */ | ||
1082 | log("Received request to connect to %.100s:%d, but the request was denied.", | ||
1083 | host, host_port); | ||
1084 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
1085 | packet_put_int(remote_channel); | ||
1086 | packet_send(); | ||
1087 | } | ||
1088 | } | ||
1089 | 1214 | ||
1090 | memset(&hints, 0, sizeof(hints)); | 1215 | memset(&hints, 0, sizeof(hints)); |
1091 | hints.ai_family = IPv4or6; | 1216 | hints.ai_family = IPv4or6; |
@@ -1093,15 +1218,14 @@ channel_input_port_open(int payload_len) | |||
1093 | snprintf(strport, sizeof strport, "%d", host_port); | 1218 | snprintf(strport, sizeof strport, "%d", host_port); |
1094 | if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { | 1219 | if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { |
1095 | error("%.100s: unknown host (%s)", host, gai_strerror(gaierr)); | 1220 | error("%.100s: unknown host (%s)", host, gai_strerror(gaierr)); |
1096 | goto fail; | 1221 | return -1; |
1097 | } | 1222 | } |
1098 | |||
1099 | for (ai = aitop; ai; ai = ai->ai_next) { | 1223 | for (ai = aitop; ai; ai = ai->ai_next) { |
1100 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) | 1224 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
1101 | continue; | 1225 | continue; |
1102 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), | 1226 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
1103 | strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { | 1227 | strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
1104 | error("channel_input_port_open: getnameinfo failed"); | 1228 | error("channel_connect_to: getnameinfo failed"); |
1105 | continue; | 1229 | continue; |
1106 | } | 1230 | } |
1107 | /* Create the socket. */ | 1231 | /* Create the socket. */ |
@@ -1121,37 +1245,82 @@ channel_input_port_open(int payload_len) | |||
1121 | 1245 | ||
1122 | } | 1246 | } |
1123 | freeaddrinfo(aitop); | 1247 | freeaddrinfo(aitop); |
1124 | |||
1125 | if (!ai) { | 1248 | if (!ai) { |
1126 | error("connect %.100s port %d: failed.", host, host_port); | 1249 | error("connect %.100s port %d: failed.", host, host_port); |
1127 | goto fail; | 1250 | return -1; |
1128 | } | 1251 | } |
1252 | /* success */ | ||
1253 | return sock; | ||
1254 | } | ||
1129 | 1255 | ||
1130 | /* Successful connection. */ | 1256 | /* |
1257 | * This is called after receiving PORT_OPEN message. This attempts to | ||
1258 | * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION | ||
1259 | * or CHANNEL_OPEN_FAILURE. | ||
1260 | */ | ||
1131 | 1261 | ||
1132 | /* Allocate a channel for this connection. */ | 1262 | void |
1133 | newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string); | 1263 | channel_input_port_open(int type, int plen) |
1134 | channels[newch].remote_id = remote_channel; | 1264 | { |
1265 | u_short host_port; | ||
1266 | char *host, *originator_string; | ||
1267 | int remote_channel, sock = -1, newch, i, denied; | ||
1268 | unsigned int host_len, originator_len; | ||
1135 | 1269 | ||
1136 | /* Send a confirmation to the remote host. */ | 1270 | /* Get remote channel number. */ |
1137 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | 1271 | remote_channel = packet_get_int(); |
1138 | packet_put_int(remote_channel); | ||
1139 | packet_put_int(newch); | ||
1140 | packet_send(); | ||
1141 | 1272 | ||
1142 | /* Free the argument string. */ | 1273 | /* Get host name to connect to. */ |
1143 | xfree(host); | 1274 | host = packet_get_string(&host_len); |
1144 | 1275 | ||
1145 | return; | 1276 | /* Get port to connect to. */ |
1277 | host_port = packet_get_int(); | ||
1146 | 1278 | ||
1147 | fail: | 1279 | /* Get remote originator name. */ |
1148 | /* Free the argument string. */ | 1280 | if (have_hostname_in_open) { |
1149 | xfree(host); | 1281 | originator_string = packet_get_string(&originator_len); |
1282 | originator_len += 4; /* size of packet_int */ | ||
1283 | } else { | ||
1284 | originator_string = xstrdup("unknown (remote did not supply name)"); | ||
1285 | originator_len = 0; /* no originator supplied */ | ||
1286 | } | ||
1150 | 1287 | ||
1151 | /* Send refusal to the remote host. */ | 1288 | packet_integrity_check(plen, |
1152 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | 1289 | 4 + 4 + host_len + 4 + originator_len, SSH_MSG_PORT_OPEN); |
1153 | packet_put_int(remote_channel); | 1290 | |
1154 | packet_send(); | 1291 | /* Check if opening that port is permitted. */ |
1292 | denied = 0; | ||
1293 | if (!all_opens_permitted) { | ||
1294 | /* Go trough all permitted ports. */ | ||
1295 | for (i = 0; i < num_permitted_opens; i++) | ||
1296 | if (permitted_opens[i].port_to_connect == host_port && | ||
1297 | strcmp(permitted_opens[i].host_to_connect, host) == 0) | ||
1298 | break; | ||
1299 | |||
1300 | /* Check if we found the requested port among those permitted. */ | ||
1301 | if (i >= num_permitted_opens) { | ||
1302 | /* The port is not permitted. */ | ||
1303 | log("Received request to connect to %.100s:%d, but the request was denied.", | ||
1304 | host, host_port); | ||
1305 | denied = 1; | ||
1306 | } | ||
1307 | } | ||
1308 | sock = denied ? -1 : channel_connect_to(host, host_port); | ||
1309 | if (sock > 0) { | ||
1310 | /* Allocate a channel for this connection. */ | ||
1311 | newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string); | ||
1312 | channels[newch].remote_id = remote_channel; | ||
1313 | |||
1314 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | ||
1315 | packet_put_int(remote_channel); | ||
1316 | packet_put_int(newch); | ||
1317 | packet_send(); | ||
1318 | } else { | ||
1319 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
1320 | packet_put_int(remote_channel); | ||
1321 | packet_send(); | ||
1322 | } | ||
1323 | xfree(host); | ||
1155 | } | 1324 | } |
1156 | 1325 | ||
1157 | /* | 1326 | /* |
@@ -1336,7 +1505,7 @@ connect_local_xsocket(unsigned int dnr) | |||
1336 | */ | 1505 | */ |
1337 | 1506 | ||
1338 | void | 1507 | void |
1339 | x11_input_open(int payload_len) | 1508 | x11_input_open(int type, int plen) |
1340 | { | 1509 | { |
1341 | int remote_channel, display_number, sock = 0, newch; | 1510 | int remote_channel, display_number, sock = 0, newch; |
1342 | const char *display; | 1511 | const char *display; |
@@ -1359,7 +1528,7 @@ x11_input_open(int payload_len) | |||
1359 | } | 1528 | } |
1360 | 1529 | ||
1361 | debug("Received X11 open request."); | 1530 | debug("Received X11 open request."); |
1362 | packet_integrity_check(payload_len, 4 + remote_len, SSH_SMSG_X11_OPEN); | 1531 | packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN); |
1363 | 1532 | ||
1364 | /* Try to open a socket for the local X server. */ | 1533 | /* Try to open a socket for the local X server. */ |
1365 | display = getenv("DISPLAY"); | 1534 | display = getenv("DISPLAY"); |
@@ -1425,19 +1594,18 @@ x11_input_open(int payload_len) | |||
1425 | sock = socket(ai->ai_family, SOCK_STREAM, 0); | 1594 | sock = socket(ai->ai_family, SOCK_STREAM, 0); |
1426 | if (sock < 0) { | 1595 | if (sock < 0) { |
1427 | debug("socket: %.100s", strerror(errno)); | 1596 | debug("socket: %.100s", strerror(errno)); |
1428 | continue; | 1597 | continue; |
1429 | } | 1598 | } |
1430 | /* Connect it to the display. */ | 1599 | /* Connect it to the display. */ |
1431 | if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { | 1600 | if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
1432 | debug("connect %.100s port %d: %.100s", buf, 6000 + display_number, | 1601 | debug("connect %.100s port %d: %.100s", buf, |
1433 | strerror(errno)); | 1602 | 6000 + display_number, strerror(errno)); |
1434 | close(sock); | 1603 | close(sock); |
1435 | continue; | 1604 | continue; |
1605 | } | ||
1606 | /* Success */ | ||
1607 | break; | ||
1436 | } | 1608 | } |
1437 | /* Success */ | ||
1438 | break; | ||
1439 | |||
1440 | } /* (ai = aitop, ai; ai = ai->ai_next) */ | ||
1441 | freeaddrinfo(aitop); | 1609 | freeaddrinfo(aitop); |
1442 | if (!ai) { | 1610 | if (!ai) { |
1443 | error("connect %.100s port %d: %.100s", buf, 6000 + display_number, | 1611 | error("connect %.100s port %d: %.100s", buf, 6000 + display_number, |
@@ -1625,11 +1793,13 @@ auth_input_request_forwarding(struct passwd * pw) | |||
1625 | /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ | 1793 | /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ |
1626 | 1794 | ||
1627 | void | 1795 | void |
1628 | auth_input_open_request() | 1796 | auth_input_open_request(int type, int plen) |
1629 | { | 1797 | { |
1630 | int remch, sock, newch; | 1798 | int remch, sock, newch; |
1631 | char *dummyname; | 1799 | char *dummyname; |
1632 | 1800 | ||
1801 | packet_integrity_check(plen, 4, type); | ||
1802 | |||
1633 | /* Read the remote channel number from the message. */ | 1803 | /* Read the remote channel number from the message. */ |
1634 | remch = packet_get_int(); | 1804 | remch = packet_get_int(); |
1635 | 1805 | ||
diff --git a/channels.h b/channels.h index f8bca5c9a..73ff5a595 100644 --- a/channels.h +++ b/channels.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* RCSID("$Id: channels.h,v 1.4 1999/11/25 00:54:58 damien Exp $"); */ | 1 | /* RCSID("$Id: channels.h,v 1.5 2000/04/01 01:09:23 damien Exp $"); */ |
2 | 2 | ||
3 | #ifndef CHANNELS_H | 3 | #ifndef CHANNELS_H |
4 | #define CHANNELS_H | 4 | #define CHANNELS_H |
@@ -10,17 +10,18 @@ | |||
10 | #define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */ | 10 | #define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */ |
11 | #define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */ | 11 | #define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */ |
12 | #define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */ | 12 | #define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */ |
13 | /* SSH_CHANNEL_AUTH_FD 6 authentication fd */ | 13 | #define SSH_CHANNEL_AUTH_SOCKET 6 /* authentication socket */ |
14 | #define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */ | 14 | #define SSH_CHANNEL_X11_OPEN 7 /* reading first X11 packet */ |
15 | /* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */ | 15 | #define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */ |
16 | #define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */ | 16 | #define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */ |
17 | #define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */ | 17 | #define SSH_CHANNEL_LARVAL 10 /* larval session */ |
18 | #define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */ | 18 | #define SSH_CHANNEL_MAX_TYPE 11 |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * Data structure for channel data. This is iniailized in channel_allocate | 21 | * Data structure for channel data. This is iniailized in channel_allocate |
22 | * and cleared in channel_free. | 22 | * and cleared in channel_free. |
23 | */ | 23 | */ |
24 | typedef void channel_callback_fn(int id, void *arg); | ||
24 | 25 | ||
25 | typedef struct Channel { | 26 | typedef struct Channel { |
26 | int type; /* channel type/state */ | 27 | int type; /* channel type/state */ |
@@ -29,15 +30,192 @@ typedef struct Channel { | |||
29 | /* peer can be reached over encrypted connection, via packet-sent */ | 30 | /* peer can be reached over encrypted connection, via packet-sent */ |
30 | int istate; /* input from channel (state of receive half) */ | 31 | int istate; /* input from channel (state of receive half) */ |
31 | int ostate; /* output to channel (state of transmit half) */ | 32 | int ostate; /* output to channel (state of transmit half) */ |
32 | int sock; /* data socket, linked to this channel */ | 33 | int rfd; /* read fd */ |
34 | int wfd; /* write fd */ | ||
35 | int efd; /* extended fd */ | ||
36 | int sock; /* sock fd */ | ||
33 | Buffer input; /* data read from socket, to be sent over | 37 | Buffer input; /* data read from socket, to be sent over |
34 | * encrypted connection */ | 38 | * encrypted connection */ |
35 | Buffer output; /* data received over encrypted connection for | 39 | Buffer output; /* data received over encrypted connection for |
36 | * send on socket */ | 40 | * send on socket */ |
41 | Buffer extended; | ||
37 | char path[200]; /* path for unix domain sockets, or host name | 42 | char path[200]; /* path for unix domain sockets, or host name |
38 | * for forwards */ | 43 | * for forwards */ |
39 | int listening_port; /* port being listened for forwards */ | 44 | int listening_port; /* port being listened for forwards */ |
40 | int host_port; /* remote port to connect for forwards */ | 45 | int host_port; /* remote port to connect for forwards */ |
41 | char *remote_name; /* remote hostname */ | 46 | char *remote_name; /* remote hostname */ |
47 | |||
48 | int remote_window; | ||
49 | int remote_maxpacket; | ||
50 | int local_window; | ||
51 | int local_window_max; | ||
52 | int local_consumed; | ||
53 | int local_maxpacket; | ||
54 | int extended_usage; | ||
55 | |||
56 | char *ctype; /* type */ | ||
57 | |||
58 | // callback | ||
59 | channel_callback_fn *cb_fn; | ||
60 | void *cb_arg; | ||
61 | int cb_event; | ||
62 | channel_callback_fn *dettach_user; | ||
42 | } Channel; | 63 | } Channel; |
64 | |||
65 | #define CHAN_EXTENDED_IGNORE 0 | ||
66 | #define CHAN_EXTENDED_READ 1 | ||
67 | #define CHAN_EXTENDED_WRITE 2 | ||
68 | |||
69 | void channel_open(int id); | ||
70 | Channel *channel_lookup(int id); | ||
71 | |||
72 | int | ||
73 | channel_new(char *ctype, int type, int rfd, int wfd, int efd, | ||
74 | int window, int maxpack, int extended_usage, char *remote_name); | ||
75 | |||
76 | void channel_input_close(int type, int plen); | ||
77 | void channel_input_close_confirmation(int type, int plen); | ||
78 | void channel_input_data(int type, int plen); | ||
79 | void channel_input_ieof(int type, int plen); | ||
80 | void channel_input_oclose(int type, int plen); | ||
81 | void channel_input_open_confirmation(int type, int plen); | ||
82 | void channel_input_open_failure(int type, int plen); | ||
83 | void channel_input_port_open(int type, int plen); | ||
84 | void channel_input_open(int type, int plen); | ||
85 | |||
86 | /* Sets specific protocol options. */ | ||
87 | void channel_set_options(int hostname_in_open); | ||
88 | |||
89 | /* | ||
90 | * Allocate a new channel object and set its type and socket. Remote_name | ||
91 | * must have been allocated with xmalloc; this will free it when the channel | ||
92 | * is freed. | ||
93 | */ | ||
94 | int channel_allocate(int type, int sock, char *remote_name); | ||
95 | |||
96 | /* Free the channel and close its socket. */ | ||
97 | void channel_free(int channel); | ||
98 | |||
99 | /* Add any bits relevant to channels in select bitmasks. */ | ||
100 | void channel_prepare_select(fd_set * readset, fd_set * writeset); | ||
101 | |||
102 | /* | ||
103 | * After select, perform any appropriate operations for channels which have | ||
104 | * events pending. | ||
105 | */ | ||
106 | void channel_after_select(fd_set * readset, fd_set * writeset); | ||
107 | |||
108 | /* If there is data to send to the connection, send some of it now. */ | ||
109 | void channel_output_poll(void); | ||
110 | |||
111 | /* Returns true if no channel has too much buffered data. */ | ||
112 | int channel_not_very_much_buffered_data(void); | ||
113 | |||
114 | /* This closes any sockets that are listening for connections; this removes | ||
115 | any unix domain sockets. */ | ||
116 | void channel_stop_listening(void); | ||
117 | |||
118 | /* | ||
119 | * Closes the sockets of all channels. This is used to close extra file | ||
120 | * descriptors after a fork. | ||
121 | */ | ||
122 | void channel_close_all(void); | ||
123 | |||
124 | /* Returns the maximum file descriptor number used by the channels. */ | ||
125 | int channel_max_fd(void); | ||
126 | |||
127 | /* Returns true if there is still an open channel over the connection. */ | ||
128 | int channel_still_open(void); | ||
129 | |||
130 | /* | ||
131 | * Returns a string containing a list of all open channels. The list is | ||
132 | * suitable for displaying to the user. It uses crlf instead of newlines. | ||
133 | * The caller should free the string with xfree. | ||
134 | */ | ||
135 | char *channel_open_message(void); | ||
136 | |||
137 | /* | ||
138 | * Initiate forwarding of connections to local port "port" through the secure | ||
139 | * channel to host:port from remote side. This never returns if there was an | ||
140 | * error. | ||
141 | */ | ||
142 | void | ||
143 | channel_request_local_forwarding(u_short port, const char *host, | ||
144 | u_short remote_port, int gateway_ports); | ||
145 | |||
146 | /* | ||
147 | * Initiate forwarding of connections to port "port" on remote host through | ||
148 | * the secure channel to host:port from local side. This never returns if | ||
149 | * there was an error. This registers that open requests for that port are | ||
150 | * permitted. | ||
151 | */ | ||
152 | void | ||
153 | channel_request_remote_forwarding(u_short port, const char *host, | ||
154 | u_short remote_port); | ||
155 | |||
156 | /* | ||
157 | * Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually | ||
158 | * called by the server, because the user could connect to any port anyway, | ||
159 | * and the server has no way to know but to trust the client anyway. | ||
160 | */ | ||
161 | void channel_permit_all_opens(void); | ||
162 | |||
163 | /* | ||
164 | * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates | ||
165 | * listening for the port, and sends back a success reply (or disconnect | ||
166 | * message if there was an error). This never returns if there was an error. | ||
167 | */ | ||
168 | void channel_input_port_forward_request(int is_root); | ||
169 | |||
170 | /* | ||
171 | * Creates a port for X11 connections, and starts listening for it. Returns | ||
172 | * the display name, or NULL if an error was encountered. | ||
173 | */ | ||
174 | char *x11_create_display(int screen); | ||
175 | |||
176 | /* | ||
177 | * Creates an internet domain socket for listening for X11 connections. | ||
178 | * Returns a suitable value for the DISPLAY variable, or NULL if an error | ||
179 | * occurs. | ||
180 | */ | ||
181 | char *x11_create_display_inet(int screen, int x11_display_offset); | ||
182 | |||
183 | /* | ||
184 | * This is called when SSH_SMSG_X11_OPEN is received. The packet contains | ||
185 | * the remote channel number. We should do whatever we want, and respond | ||
186 | * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. | ||
187 | */ | ||
188 | void x11_input_open(int type, int plen); | ||
189 | |||
190 | /* | ||
191 | * Requests forwarding of X11 connections. This should be called on the | ||
192 | * client only. | ||
193 | */ | ||
194 | void x11_request_forwarding(void); | ||
195 | |||
196 | /* | ||
197 | * Requests forwarding for X11 connections, with authentication spoofing. | ||
198 | * This should be called in the client only. | ||
199 | */ | ||
200 | void x11_request_forwarding_with_spoofing(const char *proto, const char *data); | ||
201 | |||
202 | /* Sends a message to the server to request authentication fd forwarding. */ | ||
203 | void auth_request_forwarding(void); | ||
204 | |||
205 | /* | ||
206 | * Returns the name of the forwarded authentication socket. Returns NULL if | ||
207 | * there is no forwarded authentication socket. The returned value points to | ||
208 | * a static buffer. | ||
209 | */ | ||
210 | char *auth_get_socket_name(void); | ||
211 | |||
212 | /* | ||
213 | * This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. | ||
214 | * This starts forwarding authentication requests. | ||
215 | */ | ||
216 | void auth_input_request_forwarding(struct passwd * pw); | ||
217 | |||
218 | /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ | ||
219 | void auth_input_open_request(int type, int plen); | ||
220 | |||
43 | #endif | 221 | #endif |
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include "includes.h" | 14 | #include "includes.h" |
15 | RCSID("$Id: cipher.c,v 1.14 2000/03/26 03:04:52 damien Exp $"); | 15 | RCSID("$Id: cipher.c,v 1.15 2000/04/01 01:09:23 damien Exp $"); |
16 | 16 | ||
17 | #include "ssh.h" | 17 | #include "ssh.h" |
18 | #include "cipher.h" | 18 | #include "cipher.h" |
@@ -122,7 +122,12 @@ static char *cipher_names[] = | |||
122 | "3des", | 122 | "3des", |
123 | "tss", | 123 | "tss", |
124 | "rc4", | 124 | "rc4", |
125 | "blowfish" | 125 | "blowfish", |
126 | "reserved", | ||
127 | "blowfish-cbc", | ||
128 | "3des-cbc", | ||
129 | "arcfour", | ||
130 | "cast128-cbc" | ||
126 | }; | 131 | }; |
127 | 132 | ||
128 | /* | 133 | /* |
@@ -137,6 +142,10 @@ cipher_mask() | |||
137 | unsigned int mask = 0; | 142 | unsigned int mask = 0; |
138 | mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ | 143 | mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ |
139 | mask |= 1 << SSH_CIPHER_BLOWFISH; | 144 | mask |= 1 << SSH_CIPHER_BLOWFISH; |
145 | mask |= 1 << SSH_CIPHER_BLOWFISH_CBC; | ||
146 | mask |= 1 << SSH_CIPHER_3DES_CBC; | ||
147 | mask |= 1 << SSH_CIPHER_ARCFOUR; | ||
148 | mask |= 1 << SSH_CIPHER_CAST128_CBC; | ||
140 | return mask; | 149 | return mask; |
141 | } | 150 | } |
142 | 151 | ||
@@ -233,16 +242,84 @@ cipher_set_key(CipherContext *context, int cipher, | |||
233 | break; | 242 | break; |
234 | 243 | ||
235 | case SSH_CIPHER_BLOWFISH: | 244 | case SSH_CIPHER_BLOWFISH: |
245 | if (keylen < 16) | ||
246 | error("Key length %d is insufficient for blowfish.", keylen); | ||
236 | BF_set_key(&context->u.bf.key, keylen, padded); | 247 | BF_set_key(&context->u.bf.key, keylen, padded); |
237 | memset(context->u.bf.iv, 0, 8); | 248 | memset(context->u.bf.iv, 0, 8); |
238 | break; | 249 | break; |
239 | 250 | ||
251 | case SSH_CIPHER_3DES_CBC: | ||
252 | case SSH_CIPHER_BLOWFISH_CBC: | ||
253 | case SSH_CIPHER_ARCFOUR: | ||
254 | case SSH_CIPHER_CAST128_CBC: | ||
255 | fatal("cipher_set_key: illegal cipher: %s", cipher_name(cipher)); | ||
256 | break; | ||
257 | |||
240 | default: | 258 | default: |
241 | fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher)); | 259 | fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher)); |
242 | } | 260 | } |
243 | memset(padded, 0, sizeof(padded)); | 261 | memset(padded, 0, sizeof(padded)); |
244 | } | 262 | } |
245 | 263 | ||
264 | |||
265 | void | ||
266 | cipher_set_key_iv(CipherContext * context, int cipher, | ||
267 | const unsigned char *key, int keylen, | ||
268 | const unsigned char *iv, int ivlen) | ||
269 | { | ||
270 | /* Set cipher type. */ | ||
271 | context->type = cipher; | ||
272 | |||
273 | /* Initialize the initialization vector. */ | ||
274 | switch (cipher) { | ||
275 | case SSH_CIPHER_NONE: | ||
276 | break; | ||
277 | |||
278 | case SSH_CIPHER_3DES: | ||
279 | case SSH_CIPHER_BLOWFISH: | ||
280 | fatal("cipher_set_key_iv: illegal cipher: %s", cipher_name(cipher)); | ||
281 | break; | ||
282 | |||
283 | case SSH_CIPHER_3DES_CBC: | ||
284 | if (keylen < 24) | ||
285 | error("Key length %d is insufficient for 3des-cbc.", keylen); | ||
286 | des_set_key((void *) key, context->u.des3.key1); | ||
287 | des_set_key((void *) (key+8), context->u.des3.key2); | ||
288 | des_set_key((void *) (key+16), context->u.des3.key3); | ||
289 | if (ivlen < 8) | ||
290 | error("IV length %d is insufficient for 3des-cbc.", ivlen); | ||
291 | memcpy(context->u.des3.iv3, (char *)iv, 8); | ||
292 | break; | ||
293 | |||
294 | case SSH_CIPHER_BLOWFISH_CBC: | ||
295 | if (keylen < 16) | ||
296 | error("Key length %d is insufficient for blowfish.", keylen); | ||
297 | if (ivlen < 8) | ||
298 | error("IV length %d is insufficient for blowfish.", ivlen); | ||
299 | BF_set_key(&context->u.bf.key, keylen, (unsigned char *)key); | ||
300 | memcpy(context->u.bf.iv, (char *)iv, 8); | ||
301 | break; | ||
302 | |||
303 | case SSH_CIPHER_ARCFOUR: | ||
304 | if (keylen < 16) | ||
305 | error("Key length %d is insufficient for arcfour.", keylen); | ||
306 | RC4_set_key(&context->u.rc4, keylen, (unsigned char *)key); | ||
307 | break; | ||
308 | |||
309 | case SSH_CIPHER_CAST128_CBC: | ||
310 | if (keylen < 16) | ||
311 | error("Key length %d is insufficient for cast128.", keylen); | ||
312 | if (ivlen < 8) | ||
313 | error("IV length %d is insufficient for cast128.", ivlen); | ||
314 | CAST_set_key(&context->u.cast.key, keylen, (unsigned char *) key); | ||
315 | memcpy(context->u.cast.iv, (char *)iv, 8); | ||
316 | break; | ||
317 | |||
318 | default: | ||
319 | fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher)); | ||
320 | } | ||
321 | } | ||
322 | |||
246 | /* Encrypts data using the cipher. */ | 323 | /* Encrypts data using the cipher. */ |
247 | 324 | ||
248 | void | 325 | void |
@@ -272,6 +349,27 @@ cipher_encrypt(CipherContext *context, unsigned char *dest, | |||
272 | swap_bytes(dest, dest, len); | 349 | swap_bytes(dest, dest, len); |
273 | break; | 350 | break; |
274 | 351 | ||
352 | case SSH_CIPHER_BLOWFISH_CBC: | ||
353 | BF_cbc_encrypt((void *)src, dest, len, | ||
354 | &context->u.bf.key, context->u.bf.iv, | ||
355 | BF_ENCRYPT); | ||
356 | break; | ||
357 | |||
358 | case SSH_CIPHER_3DES_CBC: | ||
359 | des_ede3_cbc_encrypt(src, dest, len, | ||
360 | context->u.des3.key1, context->u.des3.key2, | ||
361 | context->u.des3.key3, &context->u.des3.iv3, DES_ENCRYPT); | ||
362 | break; | ||
363 | |||
364 | case SSH_CIPHER_ARCFOUR: | ||
365 | RC4(&context->u.rc4, len, (unsigned char *)src, dest); | ||
366 | break; | ||
367 | |||
368 | case SSH_CIPHER_CAST128_CBC: | ||
369 | CAST_cbc_encrypt(src, dest, len, | ||
370 | &context->u.cast.key, context->u.cast.iv, CAST_ENCRYPT); | ||
371 | break; | ||
372 | |||
275 | default: | 373 | default: |
276 | fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type)); | 374 | fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type)); |
277 | } | 375 | } |
@@ -306,6 +404,27 @@ cipher_decrypt(CipherContext *context, unsigned char *dest, | |||
306 | swap_bytes(dest, dest, len); | 404 | swap_bytes(dest, dest, len); |
307 | break; | 405 | break; |
308 | 406 | ||
407 | case SSH_CIPHER_BLOWFISH_CBC: | ||
408 | BF_cbc_encrypt((void *) src, dest, len, | ||
409 | &context->u.bf.key, context->u.bf.iv, | ||
410 | BF_DECRYPT); | ||
411 | break; | ||
412 | |||
413 | case SSH_CIPHER_3DES_CBC: | ||
414 | des_ede3_cbc_encrypt(src, dest, len, | ||
415 | context->u.des3.key1, context->u.des3.key2, | ||
416 | context->u.des3.key3, &context->u.des3.iv3, DES_DECRYPT); | ||
417 | break; | ||
418 | |||
419 | case SSH_CIPHER_ARCFOUR: | ||
420 | RC4(&context->u.rc4, len, (unsigned char *)src, dest); | ||
421 | break; | ||
422 | |||
423 | case SSH_CIPHER_CAST128_CBC: | ||
424 | CAST_cbc_encrypt(src, dest, len, | ||
425 | &context->u.cast.key, context->u.cast.iv, CAST_DECRYPT); | ||
426 | break; | ||
427 | |||
309 | default: | 428 | default: |
310 | fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type)); | 429 | fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type)); |
311 | } | 430 | } |
@@ -11,7 +11,7 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* RCSID("$Id: cipher.h,v 1.6 2000/03/26 03:04:52 damien Exp $"); */ | 14 | /* RCSID("$Id: cipher.h,v 1.7 2000/04/01 01:09:23 damien Exp $"); */ |
15 | 15 | ||
16 | #ifndef CIPHER_H | 16 | #ifndef CIPHER_H |
17 | #define CIPHER_H | 17 | #define CIPHER_H |
@@ -21,10 +21,14 @@ | |||
21 | #ifdef HAVE_OPENSSL | 21 | #ifdef HAVE_OPENSSL |
22 | #include <openssl/des.h> | 22 | #include <openssl/des.h> |
23 | #include <openssl/blowfish.h> | 23 | #include <openssl/blowfish.h> |
24 | #include <openssl/rc4.h> | ||
25 | #include <openssl/cast.h> | ||
24 | #endif | 26 | #endif |
25 | #ifdef HAVE_SSL | 27 | #ifdef HAVE_SSL |
26 | #include <ssl/des.h> | 28 | #include <ssl/des.h> |
27 | #include <ssl/blowfish.h> | 29 | #include <ssl/blowfish.h> |
30 | #include <ssl/rc4.h> | ||
31 | #include <ssl/cast.h> | ||
28 | #endif | 32 | #endif |
29 | 33 | ||
30 | /* Cipher types. New types can be added, but old types should not be removed | 34 | /* Cipher types. New types can be added, but old types should not be removed |
@@ -37,6 +41,13 @@ | |||
37 | #define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */ | 41 | #define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */ |
38 | #define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */ | 42 | #define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */ |
39 | #define SSH_CIPHER_BLOWFISH 6 | 43 | #define SSH_CIPHER_BLOWFISH 6 |
44 | #define SSH_CIPHER_RESERVED 7 | ||
45 | |||
46 | /* these ciphers are used in SSH2: */ | ||
47 | #define SSH_CIPHER_BLOWFISH_CBC 8 | ||
48 | #define SSH_CIPHER_3DES_CBC 9 | ||
49 | #define SSH_CIPHER_ARCFOUR 10 /* Alleged RC4 */ | ||
50 | #define SSH_CIPHER_CAST128_CBC 11 | ||
40 | 51 | ||
41 | typedef struct { | 52 | typedef struct { |
42 | unsigned int type; | 53 | unsigned int type; |
@@ -52,6 +63,11 @@ typedef struct { | |||
52 | struct bf_key_st key; | 63 | struct bf_key_st key; |
53 | unsigned char iv[8]; | 64 | unsigned char iv[8]; |
54 | } bf; | 65 | } bf; |
66 | struct { | ||
67 | CAST_KEY key; | ||
68 | unsigned char iv[8]; | ||
69 | } cast; | ||
70 | RC4_KEY rc4; | ||
55 | } u; | 71 | } u; |
56 | } CipherContext; | 72 | } CipherContext; |
57 | /* | 73 | /* |
@@ -77,6 +93,10 @@ int cipher_number(const char *name); | |||
77 | void | 93 | void |
78 | cipher_set_key(CipherContext * context, int cipher, | 94 | cipher_set_key(CipherContext * context, int cipher, |
79 | const unsigned char *key, int keylen, int for_encryption); | 95 | const unsigned char *key, int keylen, int for_encryption); |
96 | void | ||
97 | cipher_set_key_iv(CipherContext * context, int cipher, | ||
98 | const unsigned char *key, int keylen, | ||
99 | const unsigned char *iv, int ivlen); | ||
80 | 100 | ||
81 | /* | 101 | /* |
82 | * Sets key for the cipher by computing the MD5 checksum of the passphrase, | 102 | * Sets key for the cipher by computing the MD5 checksum of the passphrase, |
diff --git a/clientloop.c b/clientloop.c index bfa3019b6..1bc6d7e67 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -15,7 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "includes.h" | 17 | #include "includes.h" |
18 | RCSID("$Id: clientloop.c,v 1.7 1999/12/07 04:38:32 damien Exp $"); | 18 | RCSID("$Id: clientloop.c,v 1.8 2000/04/01 01:09:23 damien Exp $"); |
19 | 19 | ||
20 | #include "xmalloc.h" | 20 | #include "xmalloc.h" |
21 | #include "ssh.h" | 21 | #include "ssh.h" |
@@ -24,6 +24,11 @@ RCSID("$Id: clientloop.c,v 1.7 1999/12/07 04:38:32 damien Exp $"); | |||
24 | #include "authfd.h" | 24 | #include "authfd.h" |
25 | #include "readconf.h" | 25 | #include "readconf.h" |
26 | 26 | ||
27 | #include "compat.h" | ||
28 | #include "channels.h" | ||
29 | #include "dispatch.h" | ||
30 | |||
31 | |||
27 | /* Flag indicating that stdin should be redirected from /dev/null. */ | 32 | /* Flag indicating that stdin should be redirected from /dev/null. */ |
28 | extern int stdin_null_flag; | 33 | extern int stdin_null_flag; |
29 | 34 | ||
@@ -228,108 +233,6 @@ client_check_initial_eof_on_stdin() | |||
228 | } | 233 | } |
229 | } | 234 | } |
230 | 235 | ||
231 | /* | ||
232 | * Get packets from the connection input buffer, and process them as long as | ||
233 | * there are packets available. | ||
234 | */ | ||
235 | |||
236 | void | ||
237 | client_process_buffered_input_packets() | ||
238 | { | ||
239 | int type; | ||
240 | char *data; | ||
241 | unsigned int data_len; | ||
242 | int payload_len; | ||
243 | |||
244 | /* Process any buffered packets from the server. */ | ||
245 | while (!quit_pending && | ||
246 | (type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) { | ||
247 | switch (type) { | ||
248 | |||
249 | case SSH_SMSG_STDOUT_DATA: | ||
250 | data = packet_get_string(&data_len); | ||
251 | packet_integrity_check(payload_len, 4 + data_len, type); | ||
252 | buffer_append(&stdout_buffer, data, data_len); | ||
253 | stdout_bytes += data_len; | ||
254 | memset(data, 0, data_len); | ||
255 | xfree(data); | ||
256 | break; | ||
257 | |||
258 | case SSH_SMSG_STDERR_DATA: | ||
259 | data = packet_get_string(&data_len); | ||
260 | packet_integrity_check(payload_len, 4 + data_len, type); | ||
261 | buffer_append(&stderr_buffer, data, data_len); | ||
262 | stdout_bytes += data_len; | ||
263 | memset(data, 0, data_len); | ||
264 | xfree(data); | ||
265 | break; | ||
266 | |||
267 | case SSH_SMSG_EXITSTATUS: | ||
268 | packet_integrity_check(payload_len, 4, type); | ||
269 | exit_status = packet_get_int(); | ||
270 | /* Acknowledge the exit. */ | ||
271 | packet_start(SSH_CMSG_EXIT_CONFIRMATION); | ||
272 | packet_send(); | ||
273 | /* | ||
274 | * Must wait for packet to be sent since we are | ||
275 | * exiting the loop. | ||
276 | */ | ||
277 | packet_write_wait(); | ||
278 | /* Flag that we want to exit. */ | ||
279 | quit_pending = 1; | ||
280 | break; | ||
281 | |||
282 | case SSH_SMSG_X11_OPEN: | ||
283 | x11_input_open(payload_len); | ||
284 | break; | ||
285 | |||
286 | case SSH_MSG_PORT_OPEN: | ||
287 | channel_input_port_open(payload_len); | ||
288 | break; | ||
289 | |||
290 | case SSH_SMSG_AGENT_OPEN: | ||
291 | packet_integrity_check(payload_len, 4, type); | ||
292 | auth_input_open_request(); | ||
293 | break; | ||
294 | |||
295 | case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: | ||
296 | packet_integrity_check(payload_len, 4 + 4, type); | ||
297 | channel_input_open_confirmation(); | ||
298 | break; | ||
299 | |||
300 | case SSH_MSG_CHANNEL_OPEN_FAILURE: | ||
301 | packet_integrity_check(payload_len, 4, type); | ||
302 | channel_input_open_failure(); | ||
303 | break; | ||
304 | |||
305 | case SSH_MSG_CHANNEL_DATA: | ||
306 | channel_input_data(payload_len); | ||
307 | break; | ||
308 | |||
309 | case SSH_MSG_CHANNEL_CLOSE: | ||
310 | packet_integrity_check(payload_len, 4, type); | ||
311 | channel_input_close(); | ||
312 | break; | ||
313 | |||
314 | case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION: | ||
315 | packet_integrity_check(payload_len, 4, type); | ||
316 | channel_input_close_confirmation(); | ||
317 | break; | ||
318 | |||
319 | default: | ||
320 | /* | ||
321 | * Any unknown packets received during the actual | ||
322 | * session cause the session to terminate. This is | ||
323 | * intended to make debugging easier since no | ||
324 | * confirmations are sent. Any compatible protocol | ||
325 | * extensions must be negotiated during the | ||
326 | * preparatory phase. | ||
327 | */ | ||
328 | packet_disconnect("Protocol error during session: type %d", | ||
329 | type); | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | 236 | ||
334 | /* | 237 | /* |
335 | * Make packets from buffered stdin data, and buffer them for sending to the | 238 | * Make packets from buffered stdin data, and buffer them for sending to the |
@@ -776,12 +679,32 @@ client_process_output(fd_set * writeset) | |||
776 | } | 679 | } |
777 | 680 | ||
778 | /* | 681 | /* |
682 | * Get packets from the connection input buffer, and process them as long as | ||
683 | * there are packets available. | ||
684 | * | ||
685 | * Any unknown packets received during the actual | ||
686 | * session cause the session to terminate. This is | ||
687 | * intended to make debugging easier since no | ||
688 | * confirmations are sent. Any compatible protocol | ||
689 | * extensions must be negotiated during the | ||
690 | * preparatory phase. | ||
691 | */ | ||
692 | |||
693 | void | ||
694 | client_process_buffered_input_packets() | ||
695 | { | ||
696 | dispatch_run(DISPATCH_NONBLOCK, &quit_pending); | ||
697 | } | ||
698 | |||
699 | /* | ||
779 | * Implements the interactive session with the server. This is called after | 700 | * Implements the interactive session with the server. This is called after |
780 | * the user has been authenticated, and a command has been started on the | 701 | * the user has been authenticated, and a command has been started on the |
781 | * remote host. If escape_char != -1, it is the character used as an escape | 702 | * remote host. If escape_char != -1, it is the character used as an escape |
782 | * character for terminating or suspending the session. | 703 | * character for terminating or suspending the session. |
783 | */ | 704 | */ |
784 | 705 | ||
706 | void client_init_dispatch(void); | ||
707 | |||
785 | int | 708 | int |
786 | client_loop(int have_pty, int escape_char_arg) | 709 | client_loop(int have_pty, int escape_char_arg) |
787 | { | 710 | { |
@@ -816,6 +739,8 @@ client_loop(int have_pty, int escape_char_arg) | |||
816 | buffer_init(&stdout_buffer); | 739 | buffer_init(&stdout_buffer); |
817 | buffer_init(&stderr_buffer); | 740 | buffer_init(&stderr_buffer); |
818 | 741 | ||
742 | client_init_dispatch(); | ||
743 | |||
819 | /* Set signal handlers to restore non-blocking mode. */ | 744 | /* Set signal handlers to restore non-blocking mode. */ |
820 | signal(SIGINT, signal_handler); | 745 | signal(SIGINT, signal_handler); |
821 | signal(SIGQUIT, signal_handler); | 746 | signal(SIGQUIT, signal_handler); |
@@ -950,3 +875,77 @@ client_loop(int have_pty, int escape_char_arg) | |||
950 | debug("Exit status %d", exit_status); | 875 | debug("Exit status %d", exit_status); |
951 | return exit_status; | 876 | return exit_status; |
952 | } | 877 | } |
878 | |||
879 | /*********/ | ||
880 | |||
881 | void | ||
882 | client_input_stdout_data(int type, int plen) | ||
883 | { | ||
884 | unsigned int data_len; | ||
885 | char *data = packet_get_string(&data_len); | ||
886 | packet_integrity_check(plen, 4 + data_len, type); | ||
887 | buffer_append(&stdout_buffer, data, data_len); | ||
888 | stdout_bytes += data_len; | ||
889 | memset(data, 0, data_len); | ||
890 | xfree(data); | ||
891 | } | ||
892 | void | ||
893 | client_input_stderr_data(int type, int plen) | ||
894 | { | ||
895 | unsigned int data_len; | ||
896 | char *data = packet_get_string(&data_len); | ||
897 | packet_integrity_check(plen, 4 + data_len, type); | ||
898 | buffer_append(&stderr_buffer, data, data_len); | ||
899 | stdout_bytes += data_len; | ||
900 | memset(data, 0, data_len); | ||
901 | xfree(data); | ||
902 | } | ||
903 | void | ||
904 | client_input_exit_status(int type, int plen) | ||
905 | { | ||
906 | packet_integrity_check(plen, 4, type); | ||
907 | exit_status = packet_get_int(); | ||
908 | /* Acknowledge the exit. */ | ||
909 | packet_start(SSH_CMSG_EXIT_CONFIRMATION); | ||
910 | packet_send(); | ||
911 | /* | ||
912 | * Must wait for packet to be sent since we are | ||
913 | * exiting the loop. | ||
914 | */ | ||
915 | packet_write_wait(); | ||
916 | /* Flag that we want to exit. */ | ||
917 | quit_pending = 1; | ||
918 | } | ||
919 | |||
920 | void | ||
921 | client_init_dispatch_13() | ||
922 | { | ||
923 | dispatch_init(NULL); | ||
924 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); | ||
925 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); | ||
926 | dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); | ||
927 | dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); | ||
928 | dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); | ||
929 | dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); | ||
930 | dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); | ||
931 | dispatch_set(SSH_SMSG_AGENT_OPEN, &auth_input_open_request); | ||
932 | dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status); | ||
933 | dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data); | ||
934 | dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data); | ||
935 | dispatch_set(SSH_SMSG_X11_OPEN, &x11_input_open); | ||
936 | } | ||
937 | void | ||
938 | client_init_dispatch_15() | ||
939 | { | ||
940 | client_init_dispatch_13(); | ||
941 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); | ||
942 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); | ||
943 | } | ||
944 | void | ||
945 | client_init_dispatch() | ||
946 | { | ||
947 | if (compat13) | ||
948 | client_init_dispatch_13(); | ||
949 | else | ||
950 | client_init_dispatch_15(); | ||
951 | } | ||
diff --git a/compress.c b/compress.c index cf15c6670..ee5cdccb5 100644 --- a/compress.c +++ b/compress.c | |||
@@ -14,7 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include "includes.h" | 16 | #include "includes.h" |
17 | RCSID("$Id: compress.c,v 1.4 2000/03/17 12:40:16 damien Exp $"); | 17 | RCSID("$Id: compress.c,v 1.5 2000/04/01 01:09:24 damien Exp $"); |
18 | 18 | ||
19 | #include "ssh.h" | 19 | #include "ssh.h" |
20 | #include "buffer.h" | 20 | #include "buffer.h" |
@@ -90,23 +90,13 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer) | |||
90 | case Z_OK: | 90 | case Z_OK: |
91 | /* Append compressed data to output_buffer. */ | 91 | /* Append compressed data to output_buffer. */ |
92 | buffer_append(output_buffer, buf, | 92 | buffer_append(output_buffer, buf, |
93 | sizeof(buf) - outgoing_stream.avail_out); | 93 | sizeof(buf) - outgoing_stream.avail_out); |
94 | break; | 94 | break; |
95 | case Z_STREAM_END: | ||
96 | fatal("buffer_compress: deflate returned Z_STREAM_END"); | ||
97 | /* NOTREACHED */ | ||
98 | case Z_STREAM_ERROR: | ||
99 | fatal("buffer_compress: deflate returned Z_STREAM_ERROR"); | ||
100 | /* NOTREACHED */ | ||
101 | case Z_BUF_ERROR: | ||
102 | fatal("buffer_compress: deflate returned Z_BUF_ERROR"); | ||
103 | /* NOTREACHED */ | ||
104 | default: | 95 | default: |
105 | fatal("buffer_compress: deflate returned %d", status); | 96 | fatal("buffer_compress: deflate returned %d", status); |
106 | /* NOTREACHED */ | 97 | /* NOTREACHED */ |
107 | } | 98 | } |
108 | } | 99 | } while (outgoing_stream.avail_out == 0); |
109 | while (outgoing_stream.avail_out == 0); | ||
110 | } | 100 | } |
111 | 101 | ||
112 | /* | 102 | /* |
@@ -127,27 +117,17 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer) | |||
127 | incoming_stream.next_in = (unsigned char *) buffer_ptr(input_buffer); | 117 | incoming_stream.next_in = (unsigned char *) buffer_ptr(input_buffer); |
128 | incoming_stream.avail_in = buffer_len(input_buffer); | 118 | incoming_stream.avail_in = buffer_len(input_buffer); |
129 | 119 | ||
130 | incoming_stream.next_out = (unsigned char *) buf; | ||
131 | incoming_stream.avail_out = sizeof(buf); | ||
132 | |||
133 | for (;;) { | 120 | for (;;) { |
121 | /* Set up fixed-size output buffer. */ | ||
122 | incoming_stream.next_out = (unsigned char *) buf; | ||
123 | incoming_stream.avail_out = sizeof(buf); | ||
124 | |||
134 | status = inflate(&incoming_stream, Z_PARTIAL_FLUSH); | 125 | status = inflate(&incoming_stream, Z_PARTIAL_FLUSH); |
135 | switch (status) { | 126 | switch (status) { |
136 | case Z_OK: | 127 | case Z_OK: |
137 | buffer_append(output_buffer, buf, | 128 | buffer_append(output_buffer, buf, |
138 | sizeof(buf) - incoming_stream.avail_out); | 129 | sizeof(buf) - incoming_stream.avail_out); |
139 | incoming_stream.next_out = (unsigned char *) buf; | ||
140 | incoming_stream.avail_out = sizeof(buf); | ||
141 | break; | 130 | break; |
142 | case Z_STREAM_END: | ||
143 | fatal("buffer_uncompress: inflate returned Z_STREAM_END"); | ||
144 | /* NOTREACHED */ | ||
145 | case Z_DATA_ERROR: | ||
146 | fatal("buffer_uncompress: inflate returned Z_DATA_ERROR"); | ||
147 | /* NOTREACHED */ | ||
148 | case Z_STREAM_ERROR: | ||
149 | fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR"); | ||
150 | /* NOTREACHED */ | ||
151 | case Z_BUF_ERROR: | 131 | case Z_BUF_ERROR: |
152 | /* | 132 | /* |
153 | * Comments in zlib.h say that we should keep calling | 133 | * Comments in zlib.h say that we should keep calling |
@@ -155,11 +135,9 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer) | |||
155 | * be the error that we get. | 135 | * be the error that we get. |
156 | */ | 136 | */ |
157 | return; | 137 | return; |
158 | case Z_MEM_ERROR: | ||
159 | fatal("buffer_uncompress: inflate returned Z_MEM_ERROR"); | ||
160 | /* NOTREACHED */ | ||
161 | default: | 138 | default: |
162 | fatal("buffer_uncompress: inflate returned %d", status); | 139 | fatal("buffer_uncompress: inflate returned %d", status); |
140 | /* NOTREACHED */ | ||
163 | } | 141 | } |
164 | } | 142 | } |
165 | } | 143 | } |
diff --git a/dispatch.c b/dispatch.c new file mode 100644 index 000000000..8594f986e --- /dev/null +++ b/dispatch.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | ||
3 | * | ||
4 | * Redistribution and use in source and binary forms, with or without | ||
5 | * modification, are permitted provided that the following conditions | ||
6 | * are met: | ||
7 | * 1. Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * 2. Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * 3. All advertising materials mentioning features or use of this software | ||
13 | * must display the following acknowledgement: | ||
14 | * This product includes software developed by Markus Friedl. | ||
15 | * 4. The name of the author may not be used to endorse or promote products | ||
16 | * derived from this software without specific prior written permission. | ||
17 | * | ||
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
28 | */ | ||
29 | #include "includes.h" | ||
30 | RCSID("$Id: dispatch.c,v 1.1 2000/04/01 01:09:24 damien Exp $"); | ||
31 | #include "ssh.h" | ||
32 | #include "dispatch.h" | ||
33 | #include "packet.h" | ||
34 | |||
35 | #define DISPATCH_MIN 0 | ||
36 | #define DISPATCH_MAX 255 | ||
37 | |||
38 | dispatch_fn *dispatch[DISPATCH_MAX]; | ||
39 | |||
40 | void | ||
41 | dispatch_protocol_error(int type, int plen) | ||
42 | { | ||
43 | error("Hm, dispatch protocol error: type %d plen %d", type, plen); | ||
44 | } | ||
45 | void | ||
46 | dispatch_init(dispatch_fn *dflt) | ||
47 | { | ||
48 | int i; | ||
49 | for (i = 0; i < DISPATCH_MAX; i++) | ||
50 | dispatch[i] = dflt; | ||
51 | } | ||
52 | void | ||
53 | dispatch_set(int type, dispatch_fn *fn) | ||
54 | { | ||
55 | dispatch[type] = fn; | ||
56 | } | ||
57 | void | ||
58 | dispatch_run(int mode, int *done) | ||
59 | { | ||
60 | for (;;) { | ||
61 | int plen; | ||
62 | int type; | ||
63 | |||
64 | if (mode == DISPATCH_BLOCK) { | ||
65 | type = packet_read(&plen); | ||
66 | } else { | ||
67 | type = packet_read_poll(&plen); | ||
68 | if (type == SSH_MSG_NONE) | ||
69 | return; | ||
70 | } | ||
71 | if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL) | ||
72 | (*dispatch[type])(type, plen); | ||
73 | else | ||
74 | packet_disconnect("protocol error: rcvd type %d", type); | ||
75 | if (done != NULL && *done) | ||
76 | return; | ||
77 | } | ||
78 | } | ||
diff --git a/dispatch.h b/dispatch.h new file mode 100644 index 000000000..12084aafe --- /dev/null +++ b/dispatch.h | |||
@@ -0,0 +1,11 @@ | |||
1 | enum { | ||
2 | DISPATCH_BLOCK, | ||
3 | DISPATCH_NONBLOCK | ||
4 | }; | ||
5 | |||
6 | typedef void dispatch_fn(int type, int plen); | ||
7 | |||
8 | void dispatch_init(dispatch_fn *dflt); | ||
9 | void dispatch_set(int type, dispatch_fn *fn); | ||
10 | void dispatch_run(int mode, int *done); | ||
11 | void dispatch_protocol_error(int type, int plen); | ||
diff --git a/log-server.c b/log-server.c index 7f732ed3b..476e49f80 100644 --- a/log-server.c +++ b/log-server.c | |||
@@ -15,7 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "includes.h" | 17 | #include "includes.h" |
18 | RCSID("$Id: log-server.c,v 1.7 2000/03/09 10:27:50 damien Exp $"); | 18 | RCSID("$Id: log-server.c,v 1.8 2000/04/01 01:09:24 damien Exp $"); |
19 | 19 | ||
20 | #include <syslog.h> | 20 | #include <syslog.h> |
21 | #include "packet.h" | 21 | #include "packet.h" |
@@ -137,9 +137,11 @@ do_log(LogLevel level, const char *fmt, va_list args) | |||
137 | } else { | 137 | } else { |
138 | vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); | 138 | vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); |
139 | } | 139 | } |
140 | if (log_on_stderr) | 140 | if (log_on_stderr) { |
141 | fprintf(stderr, "%s\n", msgbuf); | 141 | fprintf(stderr, "%s\n", msgbuf); |
142 | openlog(__progname, LOG_PID, log_facility); | 142 | } else { |
143 | syslog(pri, "%.500s", msgbuf); | 143 | openlog(__progname, LOG_PID, log_facility); |
144 | closelog(); | 144 | syslog(pri, "%.500s", msgbuf); |
145 | closelog(); | ||
146 | } | ||
145 | } | 147 | } |
@@ -15,7 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "includes.h" | 17 | #include "includes.h" |
18 | RCSID("$Id: mpaux.c,v 1.8 1999/12/13 23:47:16 damien Exp $"); | 18 | RCSID("$Id: mpaux.c,v 1.9 2000/04/01 01:09:24 damien Exp $"); |
19 | 19 | ||
20 | #include "getput.h" | 20 | #include "getput.h" |
21 | #include "xmalloc.h" | 21 | #include "xmalloc.h" |
@@ -31,9 +31,9 @@ RCSID("$Id: mpaux.c,v 1.8 1999/12/13 23:47:16 damien Exp $"); | |||
31 | 31 | ||
32 | void | 32 | void |
33 | compute_session_id(unsigned char session_id[16], | 33 | compute_session_id(unsigned char session_id[16], |
34 | unsigned char cookie[8], | 34 | unsigned char cookie[8], |
35 | BIGNUM* host_key_n, | 35 | BIGNUM* host_key_n, |
36 | BIGNUM* session_key_n) | 36 | BIGNUM* session_key_n) |
37 | { | 37 | { |
38 | unsigned int host_key_bytes = BN_num_bytes(host_key_n); | 38 | unsigned int host_key_bytes = BN_num_bytes(host_key_n); |
39 | unsigned int session_key_bytes = BN_num_bytes(session_key_n); | 39 | unsigned int session_key_bytes = BN_num_bytes(session_key_n); |
@@ -28,7 +28,7 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include "includes.h" | 30 | #include "includes.h" |
31 | RCSID("$Id: nchan.c,v 1.5 2000/01/14 04:45:50 damien Exp $"); | 31 | RCSID("$Id: nchan.c,v 1.6 2000/04/01 01:09:24 damien Exp $"); |
32 | 32 | ||
33 | #include "ssh.h" | 33 | #include "ssh.h" |
34 | 34 | ||
@@ -41,7 +41,6 @@ static void chan_send_ieof(Channel *c); | |||
41 | static void chan_send_oclose(Channel *c); | 41 | static void chan_send_oclose(Channel *c); |
42 | static void chan_shutdown_write(Channel *c); | 42 | static void chan_shutdown_write(Channel *c); |
43 | static void chan_shutdown_read(Channel *c); | 43 | static void chan_shutdown_read(Channel *c); |
44 | static void chan_delete_if_full_closed(Channel *c); | ||
45 | 44 | ||
46 | /* | 45 | /* |
47 | * EVENTS update channel input/output states execute ACTIONS | 46 | * EVENTS update channel input/output states execute ACTIONS |
@@ -73,7 +72,6 @@ chan_rcvd_oclose(Channel *c) | |||
73 | error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate); | 72 | error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate); |
74 | return; | 73 | return; |
75 | } | 74 | } |
76 | chan_delete_if_full_closed(c); | ||
77 | } | 75 | } |
78 | void | 76 | void |
79 | chan_read_failed(Channel *c) | 77 | chan_read_failed(Channel *c) |
@@ -121,7 +119,6 @@ chan_rcvd_ieof(Channel *c) | |||
121 | case CHAN_OUTPUT_WAIT_IEOF: | 119 | case CHAN_OUTPUT_WAIT_IEOF: |
122 | debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self); | 120 | debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self); |
123 | c->ostate = CHAN_OUTPUT_CLOSED; | 121 | c->ostate = CHAN_OUTPUT_CLOSED; |
124 | chan_delete_if_full_closed(c); | ||
125 | break; | 122 | break; |
126 | default: | 123 | default: |
127 | error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate); | 124 | error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate); |
@@ -141,7 +138,6 @@ chan_write_failed(Channel *c) | |||
141 | debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self); | 138 | debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self); |
142 | chan_send_oclose(c); | 139 | chan_send_oclose(c); |
143 | c->ostate = CHAN_OUTPUT_CLOSED; | 140 | c->ostate = CHAN_OUTPUT_CLOSED; |
144 | chan_delete_if_full_closed(c); | ||
145 | break; | 141 | break; |
146 | default: | 142 | default: |
147 | error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate); | 143 | error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate); |
@@ -160,7 +156,6 @@ chan_obuf_empty(Channel *c) | |||
160 | debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self); | 156 | debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self); |
161 | chan_send_oclose(c); | 157 | chan_send_oclose(c); |
162 | c->ostate = CHAN_OUTPUT_CLOSED; | 158 | c->ostate = CHAN_OUTPUT_CLOSED; |
163 | chan_delete_if_full_closed(c); | ||
164 | break; | 159 | break; |
165 | default: | 160 | default: |
166 | error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate); | 161 | error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate); |
@@ -222,7 +217,7 @@ chan_shutdown_read(Channel *c) | |||
222 | error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s", | 217 | error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s", |
223 | c->self, c->sock, c->istate, c->ostate, strerror(errno)); | 218 | c->self, c->sock, c->istate, c->ostate, strerror(errno)); |
224 | } | 219 | } |
225 | static void | 220 | void |
226 | chan_delete_if_full_closed(Channel *c) | 221 | chan_delete_if_full_closed(Channel *c) |
227 | { | 222 | { |
228 | if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { | 223 | if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { |
@@ -27,7 +27,7 @@ | |||
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | /* RCSID("$Id: nchan.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */ | 30 | /* RCSID("$Id: nchan.h,v 1.4 2000/04/01 01:09:24 damien Exp $"); */ |
31 | 31 | ||
32 | #ifndef NCHAN_H | 32 | #ifndef NCHAN_H |
33 | #define NCHAN_H | 33 | #define NCHAN_H |
@@ -83,4 +83,6 @@ void chan_write_failed(Channel * c); | |||
83 | void chan_obuf_empty(Channel * c); | 83 | void chan_obuf_empty(Channel * c); |
84 | 84 | ||
85 | void chan_init_iostates(Channel * c); | 85 | void chan_init_iostates(Channel * c); |
86 | |||
87 | void chan_delete_if_full_closed(Channel *c); | ||
86 | #endif | 88 | #endif |
@@ -15,7 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "includes.h" | 17 | #include "includes.h" |
18 | RCSID("$Id: packet.c,v 1.12 2000/03/09 10:27:50 damien Exp $"); | 18 | RCSID("$Id: packet.c,v 1.13 2000/04/01 01:09:25 damien Exp $"); |
19 | 19 | ||
20 | #include "xmalloc.h" | 20 | #include "xmalloc.h" |
21 | #include "buffer.h" | 21 | #include "buffer.h" |
@@ -28,6 +28,7 @@ RCSID("$Id: packet.c,v 1.12 2000/03/09 10:27:50 damien Exp $"); | |||
28 | 28 | ||
29 | #include "compress.h" | 29 | #include "compress.h" |
30 | #include "deattack.h" | 30 | #include "deattack.h" |
31 | #include "channels.h" | ||
31 | 32 | ||
32 | /* | 33 | /* |
33 | * This variable contains the file descriptors used for communicating with | 34 | * This variable contains the file descriptors used for communicating with |
@@ -13,7 +13,7 @@ | |||
13 | * tty. | 13 | * tty. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | /* RCSID("$Id: pty.h,v 1.6 2000/03/09 10:27:51 damien Exp $"); */ | 16 | /* RCSID("$Id: pty.h,v 1.7 2000/04/01 01:09:25 damien Exp $"); */ |
17 | 17 | ||
18 | #ifndef PTY_H | 18 | #ifndef PTY_H |
19 | #define PTY_H | 19 | #define PTY_H |
@@ -45,6 +45,4 @@ pty_change_window_size(int ptyfd, int row, int col, | |||
45 | 45 | ||
46 | void pty_setowner(struct passwd *pw, const char *ttyname); | 46 | void pty_setowner(struct passwd *pw, const char *ttyname); |
47 | 47 | ||
48 | void pty_setowner(struct passwd *pw, const char *ttyname); | ||
49 | |||
50 | #endif /* PTY_H */ | 48 | #endif /* PTY_H */ |
diff --git a/readconf.c b/readconf.c index 99023d136..bb420ac05 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -14,11 +14,12 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include "includes.h" | 16 | #include "includes.h" |
17 | RCSID("$Id: readconf.c,v 1.8 2000/03/09 10:27:51 damien Exp $"); | 17 | RCSID("$Id: readconf.c,v 1.9 2000/04/01 01:09:25 damien Exp $"); |
18 | 18 | ||
19 | #include "ssh.h" | 19 | #include "ssh.h" |
20 | #include "cipher.h" | 20 | #include "cipher.h" |
21 | #include "readconf.h" | 21 | #include "readconf.h" |
22 | #include "match.h" | ||
22 | #include "xmalloc.h" | 23 | #include "xmalloc.h" |
23 | 24 | ||
24 | /* Format of the configuration file: | 25 | /* Format of the configuration file: |
diff --git a/serverloop.c b/serverloop.c index 2afca7637..8bf448ceb 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -13,6 +13,10 @@ | |||
13 | #include "buffer.h" | 13 | #include "buffer.h" |
14 | #include "servconf.h" | 14 | #include "servconf.h" |
15 | #include "pty.h" | 15 | #include "pty.h" |
16 | #include "channels.h" | ||
17 | |||
18 | #include "compat.h" | ||
19 | #include "dispatch.h" | ||
16 | 20 | ||
17 | static Buffer stdin_buffer; /* Buffer for stdin data. */ | 21 | static Buffer stdin_buffer; /* Buffer for stdin data. */ |
18 | static Buffer stdout_buffer; /* Buffer for stdout data. */ | 22 | static Buffer stdout_buffer; /* Buffer for stdout data. */ |
@@ -47,6 +51,8 @@ static volatile int child_terminated; /* The child has terminated. */ | |||
47 | static volatile int child_has_selected; /* Child has had chance to drain. */ | 51 | static volatile int child_has_selected; /* Child has had chance to drain. */ |
48 | static volatile int child_wait_status; /* Status from wait(). */ | 52 | static volatile int child_wait_status; /* Status from wait(). */ |
49 | 53 | ||
54 | void server_init_dispatch(void); | ||
55 | |||
50 | void | 56 | void |
51 | sigchld_handler(int sig) | 57 | sigchld_handler(int sig) |
52 | { | 58 | { |
@@ -68,104 +74,6 @@ sigchld_handler(int sig) | |||
68 | } | 74 | } |
69 | 75 | ||
70 | /* | 76 | /* |
71 | * Process any buffered packets that have been received from the client. | ||
72 | */ | ||
73 | void | ||
74 | process_buffered_input_packets() | ||
75 | { | ||
76 | int type; | ||
77 | char *data; | ||
78 | unsigned int data_len; | ||
79 | int row, col, xpixel, ypixel; | ||
80 | int payload_len; | ||
81 | |||
82 | /* Process buffered packets from the client. */ | ||
83 | while ((type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) { | ||
84 | switch (type) { | ||
85 | case SSH_CMSG_STDIN_DATA: | ||
86 | /* Stdin data from the client. Append it to the buffer. */ | ||
87 | /* Ignore any data if the client has closed stdin. */ | ||
88 | if (fdin == -1) | ||
89 | break; | ||
90 | data = packet_get_string(&data_len); | ||
91 | packet_integrity_check(payload_len, (4 + data_len), type); | ||
92 | buffer_append(&stdin_buffer, data, data_len); | ||
93 | memset(data, 0, data_len); | ||
94 | xfree(data); | ||
95 | break; | ||
96 | |||
97 | case SSH_CMSG_EOF: | ||
98 | /* | ||
99 | * Eof from the client. The stdin descriptor to the | ||
100 | * program will be closed when all buffered data has | ||
101 | * drained. | ||
102 | */ | ||
103 | debug("EOF received for stdin."); | ||
104 | packet_integrity_check(payload_len, 0, type); | ||
105 | stdin_eof = 1; | ||
106 | break; | ||
107 | |||
108 | case SSH_CMSG_WINDOW_SIZE: | ||
109 | debug("Window change received."); | ||
110 | packet_integrity_check(payload_len, 4 * 4, type); | ||
111 | row = packet_get_int(); | ||
112 | col = packet_get_int(); | ||
113 | xpixel = packet_get_int(); | ||
114 | ypixel = packet_get_int(); | ||
115 | if (fdin != -1) | ||
116 | pty_change_window_size(fdin, row, col, xpixel, ypixel); | ||
117 | break; | ||
118 | |||
119 | case SSH_MSG_PORT_OPEN: | ||
120 | debug("Received port open request."); | ||
121 | channel_input_port_open(payload_len); | ||
122 | break; | ||
123 | |||
124 | case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: | ||
125 | debug("Received channel open confirmation."); | ||
126 | packet_integrity_check(payload_len, 4 + 4, type); | ||
127 | channel_input_open_confirmation(); | ||
128 | break; | ||
129 | |||
130 | case SSH_MSG_CHANNEL_OPEN_FAILURE: | ||
131 | debug("Received channel open failure."); | ||
132 | packet_integrity_check(payload_len, 4, type); | ||
133 | channel_input_open_failure(); | ||
134 | break; | ||
135 | |||
136 | case SSH_MSG_CHANNEL_DATA: | ||
137 | channel_input_data(payload_len); | ||
138 | break; | ||
139 | |||
140 | case SSH_MSG_CHANNEL_CLOSE: | ||
141 | debug("Received channel close."); | ||
142 | packet_integrity_check(payload_len, 4, type); | ||
143 | channel_input_close(); | ||
144 | break; | ||
145 | |||
146 | case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION: | ||
147 | debug("Received channel close confirmation."); | ||
148 | packet_integrity_check(payload_len, 4, type); | ||
149 | channel_input_close_confirmation(); | ||
150 | break; | ||
151 | |||
152 | default: | ||
153 | /* | ||
154 | * In this phase, any unexpected messages cause a | ||
155 | * protocol error. This is to ease debugging; also, | ||
156 | * since no confirmations are sent messages, | ||
157 | * unprocessed unknown messages could cause strange | ||
158 | * problems. Any compatible protocol extensions must | ||
159 | * be negotiated before entering the interactive | ||
160 | * session. | ||
161 | */ | ||
162 | packet_disconnect("Protocol error during session: type %d", | ||
163 | type); | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * Make packets from buffered stderr data, and buffer it for sending | 77 | * Make packets from buffered stderr data, and buffer it for sending |
170 | * to the client. | 78 | * to the client. |
171 | */ | 79 | */ |
@@ -378,7 +286,7 @@ process_output(fd_set * writeset) | |||
378 | #ifdef USE_PIPES | 286 | #ifdef USE_PIPES |
379 | close(fdin); | 287 | close(fdin); |
380 | #else | 288 | #else |
381 | if (fdout == -1) | 289 | if (fdin != fdout) |
382 | close(fdin); | 290 | close(fdin); |
383 | else | 291 | else |
384 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ | 292 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ |
@@ -425,6 +333,12 @@ drain_output() | |||
425 | packet_write_wait(); | 333 | packet_write_wait(); |
426 | } | 334 | } |
427 | 335 | ||
336 | void | ||
337 | process_buffered_input_packets() | ||
338 | { | ||
339 | dispatch_run(DISPATCH_NONBLOCK, NULL); | ||
340 | } | ||
341 | |||
428 | /* | 342 | /* |
429 | * Performs the interactive session. This handles data transmission between | 343 | * Performs the interactive session. This handles data transmission between |
430 | * the client and the program. Note that the notion of stdin, stdout, and | 344 | * the client and the program. Note that the notion of stdin, stdout, and |
@@ -490,6 +404,8 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
490 | if (fderr == -1) | 404 | if (fderr == -1) |
491 | fderr_eof = 1; | 405 | fderr_eof = 1; |
492 | 406 | ||
407 | server_init_dispatch(); | ||
408 | |||
493 | /* Main loop of the server for the interactive session mode. */ | 409 | /* Main loop of the server for the interactive session mode. */ |
494 | for (;;) { | 410 | for (;;) { |
495 | fd_set readset, writeset; | 411 | fd_set readset, writeset; |
@@ -505,7 +421,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
505 | #ifdef USE_PIPES | 421 | #ifdef USE_PIPES |
506 | close(fdin); | 422 | close(fdin); |
507 | #else | 423 | #else |
508 | if (fdout == -1) | 424 | if (fdin != fdout) |
509 | close(fdin); | 425 | close(fdin); |
510 | else | 426 | else |
511 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ | 427 | shutdown(fdin, SHUT_WR); /* We will no longer send. */ |
@@ -549,7 +465,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
549 | (buffer_len(&stdout_buffer) == 0) && | 465 | (buffer_len(&stdout_buffer) == 0) && |
550 | (buffer_len(&stderr_buffer) == 0)) { | 466 | (buffer_len(&stderr_buffer) == 0)) { |
551 | if (!channel_still_open()) | 467 | if (!channel_still_open()) |
552 | goto quit; | 468 | break; |
553 | if (!waiting_termination) { | 469 | if (!waiting_termination) { |
554 | const char *s = "Waiting for forwarded connections to terminate...\r\n"; | 470 | const char *s = "Waiting for forwarded connections to terminate...\r\n"; |
555 | char *cp; | 471 | char *cp; |
@@ -576,7 +492,6 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
576 | process_output(&writeset); | 492 | process_output(&writeset); |
577 | } | 493 | } |
578 | 494 | ||
579 | quit: | ||
580 | /* Cleanup and termination code. */ | 495 | /* Cleanup and termination code. */ |
581 | 496 | ||
582 | /* Wait until all output has been sent to the client. */ | 497 | /* Wait until all output has been sent to the client. */ |
@@ -662,3 +577,79 @@ quit: | |||
662 | packet_disconnect("wait returned status %04x.", wait_status); | 577 | packet_disconnect("wait returned status %04x.", wait_status); |
663 | /* NOTREACHED */ | 578 | /* NOTREACHED */ |
664 | } | 579 | } |
580 | |||
581 | void | ||
582 | server_input_stdin_data(int type, int plen) | ||
583 | { | ||
584 | char *data; | ||
585 | unsigned int data_len; | ||
586 | |||
587 | /* Stdin data from the client. Append it to the buffer. */ | ||
588 | /* Ignore any data if the client has closed stdin. */ | ||
589 | if (fdin == -1) | ||
590 | return; | ||
591 | data = packet_get_string(&data_len); | ||
592 | packet_integrity_check(plen, (4 + data_len), type); | ||
593 | buffer_append(&stdin_buffer, data, data_len); | ||
594 | memset(data, 0, data_len); | ||
595 | xfree(data); | ||
596 | } | ||
597 | |||
598 | void | ||
599 | server_input_eof(int type, int plen) | ||
600 | { | ||
601 | /* | ||
602 | * Eof from the client. The stdin descriptor to the | ||
603 | * program will be closed when all buffered data has | ||
604 | * drained. | ||
605 | */ | ||
606 | debug("EOF received for stdin."); | ||
607 | packet_integrity_check(plen, 0, type); | ||
608 | stdin_eof = 1; | ||
609 | } | ||
610 | |||
611 | void | ||
612 | server_input_window_size(int type, int plen) | ||
613 | { | ||
614 | int row = packet_get_int(); | ||
615 | int col = packet_get_int(); | ||
616 | int xpixel = packet_get_int(); | ||
617 | int ypixel = packet_get_int(); | ||
618 | |||
619 | debug("Window change received."); | ||
620 | packet_integrity_check(plen, 4 * 4, type); | ||
621 | if (fdin != -1) | ||
622 | pty_change_window_size(fdin, row, col, xpixel, ypixel); | ||
623 | } | ||
624 | |||
625 | void | ||
626 | server_init_dispatch_13() | ||
627 | { | ||
628 | debug("server_init_dispatch_13"); | ||
629 | dispatch_init(NULL); | ||
630 | dispatch_set(SSH_CMSG_EOF, &server_input_eof); | ||
631 | dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data); | ||
632 | dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size); | ||
633 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); | ||
634 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); | ||
635 | dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); | ||
636 | dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); | ||
637 | dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); | ||
638 | dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); | ||
639 | } | ||
640 | void | ||
641 | server_init_dispatch_15() | ||
642 | { | ||
643 | server_init_dispatch_13(); | ||
644 | debug("server_init_dispatch_15"); | ||
645 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); | ||
646 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose); | ||
647 | } | ||
648 | void | ||
649 | server_init_dispatch() | ||
650 | { | ||
651 | if (compat13) | ||
652 | server_init_dispatch_13(); | ||
653 | else | ||
654 | server_init_dispatch_15(); | ||
655 | } | ||
diff --git a/session.c b/session.c new file mode 100644 index 000000000..2128fe394 --- /dev/null +++ b/session.c | |||
@@ -0,0 +1,1153 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
3 | * All rights reserved | ||
4 | */ | ||
5 | |||
6 | #include "includes.h" | ||
7 | RCSID("$OpenBSD: session.c,v 1.1 2000/03/28 21:15:45 markus Exp $"); | ||
8 | |||
9 | #include "xmalloc.h" | ||
10 | #include "ssh.h" | ||
11 | #include "pty.h" | ||
12 | #include "packet.h" | ||
13 | #include "buffer.h" | ||
14 | #include "cipher.h" | ||
15 | #include "mpaux.h" | ||
16 | #include "servconf.h" | ||
17 | #include "uidswap.h" | ||
18 | #include "compat.h" | ||
19 | #include "channels.h" | ||
20 | #include "nchan.h" | ||
21 | |||
22 | /* types */ | ||
23 | |||
24 | #define TTYSZ 64 | ||
25 | typedef struct Session Session; | ||
26 | struct Session { | ||
27 | int used; | ||
28 | int self; | ||
29 | struct passwd *pw; | ||
30 | pid_t pid; | ||
31 | /* tty */ | ||
32 | char *term; | ||
33 | int ptyfd, ttyfd, ptymaster; | ||
34 | int row, col, xpixel, ypixel; | ||
35 | char tty[TTYSZ]; | ||
36 | /* X11 */ | ||
37 | char *display; | ||
38 | int screen; | ||
39 | char *auth_proto; | ||
40 | char *auth_data; | ||
41 | /* proto 2 */ | ||
42 | int chanid; | ||
43 | }; | ||
44 | |||
45 | /* func */ | ||
46 | |||
47 | Session *session_new(void); | ||
48 | void session_set_fds(Session *s, int fdin, int fdout, int fderr); | ||
49 | void session_pty_cleanup(Session *s); | ||
50 | void do_exec_pty(Session *s, const char *command, struct passwd * pw); | ||
51 | void do_exec_no_pty(Session *s, const char *command, struct passwd * pw); | ||
52 | |||
53 | void | ||
54 | do_child(const char *command, struct passwd * pw, const char *term, | ||
55 | const char *display, const char *auth_proto, | ||
56 | const char *auth_data, const char *ttyname); | ||
57 | |||
58 | /* import */ | ||
59 | extern ServerOptions options; | ||
60 | extern char *__progname; | ||
61 | extern int log_stderr; | ||
62 | extern int debug_flag; | ||
63 | |||
64 | /* Local Xauthority file. */ | ||
65 | static char *xauthfile; | ||
66 | |||
67 | /* data */ | ||
68 | #define MAX_SESSIONS 10 | ||
69 | Session sessions[MAX_SESSIONS]; | ||
70 | |||
71 | /* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */ | ||
72 | int no_port_forwarding_flag = 0; | ||
73 | int no_agent_forwarding_flag = 0; | ||
74 | int no_x11_forwarding_flag = 0; | ||
75 | int no_pty_flag = 0; | ||
76 | |||
77 | /* RSA authentication "command=" option. */ | ||
78 | char *forced_command = NULL; | ||
79 | |||
80 | /* RSA authentication "environment=" options. */ | ||
81 | struct envstring *custom_environment = NULL; | ||
82 | |||
83 | /* | ||
84 | * Remove local Xauthority file. | ||
85 | */ | ||
86 | void | ||
87 | xauthfile_cleanup_proc(void *ignore) | ||
88 | { | ||
89 | debug("xauthfile_cleanup_proc called"); | ||
90 | |||
91 | if (xauthfile != NULL) { | ||
92 | char *p; | ||
93 | unlink(xauthfile); | ||
94 | p = strrchr(xauthfile, '/'); | ||
95 | if (p != NULL) { | ||
96 | *p = '\0'; | ||
97 | rmdir(xauthfile); | ||
98 | } | ||
99 | xfree(xauthfile); | ||
100 | xauthfile = NULL; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Function to perform cleanup if we get aborted abnormally (e.g., due to a | ||
106 | * dropped connection). | ||
107 | */ | ||
108 | void | ||
109 | pty_cleanup_proc(void *session) | ||
110 | { | ||
111 | Session *s=session; | ||
112 | if (s == NULL) | ||
113 | fatal("pty_cleanup_proc: no session"); | ||
114 | debug("pty_cleanup_proc: %s", s->tty); | ||
115 | |||
116 | if (s->pid != 0) { | ||
117 | /* Record that the user has logged out. */ | ||
118 | record_logout(s->pid, s->tty); | ||
119 | } | ||
120 | |||
121 | /* Release the pseudo-tty. */ | ||
122 | pty_release(s->tty); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Prepares for an interactive session. This is called after the user has | ||
127 | * been successfully authenticated. During this message exchange, pseudo | ||
128 | * terminals are allocated, X11, TCP/IP, and authentication agent forwardings | ||
129 | * are requested, etc. | ||
130 | */ | ||
131 | void | ||
132 | do_authenticated(struct passwd * pw) | ||
133 | { | ||
134 | Session *s; | ||
135 | int type; | ||
136 | int compression_level = 0, enable_compression_after_reply = 0; | ||
137 | int have_pty = 0; | ||
138 | char *command; | ||
139 | int n_bytes; | ||
140 | int plen; | ||
141 | unsigned int proto_len, data_len, dlen; | ||
142 | |||
143 | /* | ||
144 | * Cancel the alarm we set to limit the time taken for | ||
145 | * authentication. | ||
146 | */ | ||
147 | alarm(0); | ||
148 | |||
149 | /* | ||
150 | * Inform the channel mechanism that we are the server side and that | ||
151 | * the client may request to connect to any port at all. (The user | ||
152 | * could do it anyway, and we wouldn\'t know what is permitted except | ||
153 | * by the client telling us, so we can equally well trust the client | ||
154 | * not to request anything bogus.) | ||
155 | */ | ||
156 | if (!no_port_forwarding_flag) | ||
157 | channel_permit_all_opens(); | ||
158 | |||
159 | s = session_new(); | ||
160 | |||
161 | /* | ||
162 | * We stay in this loop until the client requests to execute a shell | ||
163 | * or a command. | ||
164 | */ | ||
165 | for (;;) { | ||
166 | int success = 0; | ||
167 | |||
168 | /* Get a packet from the client. */ | ||
169 | type = packet_read(&plen); | ||
170 | |||
171 | /* Process the packet. */ | ||
172 | switch (type) { | ||
173 | case SSH_CMSG_REQUEST_COMPRESSION: | ||
174 | packet_integrity_check(plen, 4, type); | ||
175 | compression_level = packet_get_int(); | ||
176 | if (compression_level < 1 || compression_level > 9) { | ||
177 | packet_send_debug("Received illegal compression level %d.", | ||
178 | compression_level); | ||
179 | break; | ||
180 | } | ||
181 | /* Enable compression after we have responded with SUCCESS. */ | ||
182 | enable_compression_after_reply = 1; | ||
183 | success = 1; | ||
184 | break; | ||
185 | |||
186 | case SSH_CMSG_REQUEST_PTY: | ||
187 | if (no_pty_flag) { | ||
188 | debug("Allocating a pty not permitted for this authentication."); | ||
189 | break; | ||
190 | } | ||
191 | if (have_pty) | ||
192 | packet_disconnect("Protocol error: you already have a pty."); | ||
193 | |||
194 | debug("Allocating pty."); | ||
195 | |||
196 | /* Allocate a pty and open it. */ | ||
197 | if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, | ||
198 | sizeof(s->tty))) { | ||
199 | error("Failed to allocate pty."); | ||
200 | break; | ||
201 | } | ||
202 | fatal_add_cleanup(pty_cleanup_proc, (void *)s); | ||
203 | pty_setowner(pw, s->tty); | ||
204 | |||
205 | /* Get TERM from the packet. Note that the value may be of arbitrary length. */ | ||
206 | s->term = packet_get_string(&dlen); | ||
207 | packet_integrity_check(dlen, strlen(s->term), type); | ||
208 | /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */ | ||
209 | /* Remaining bytes */ | ||
210 | n_bytes = plen - (4 + dlen + 4 * 4); | ||
211 | |||
212 | if (strcmp(s->term, "") == 0) { | ||
213 | xfree(s->term); | ||
214 | s->term = NULL; | ||
215 | } | ||
216 | /* Get window size from the packet. */ | ||
217 | s->row = packet_get_int(); | ||
218 | s->col = packet_get_int(); | ||
219 | s->xpixel = packet_get_int(); | ||
220 | s->ypixel = packet_get_int(); | ||
221 | pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); | ||
222 | |||
223 | /* Get tty modes from the packet. */ | ||
224 | tty_parse_modes(s->ttyfd, &n_bytes); | ||
225 | packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type); | ||
226 | |||
227 | /* Indicate that we now have a pty. */ | ||
228 | success = 1; | ||
229 | have_pty = 1; | ||
230 | break; | ||
231 | |||
232 | case SSH_CMSG_X11_REQUEST_FORWARDING: | ||
233 | if (!options.x11_forwarding) { | ||
234 | packet_send_debug("X11 forwarding disabled in server configuration file."); | ||
235 | break; | ||
236 | } | ||
237 | #ifdef XAUTH_PATH | ||
238 | if (no_x11_forwarding_flag) { | ||
239 | packet_send_debug("X11 forwarding not permitted for this authentication."); | ||
240 | break; | ||
241 | } | ||
242 | debug("Received request for X11 forwarding with auth spoofing."); | ||
243 | if (s->display != NULL) | ||
244 | packet_disconnect("Protocol error: X11 display already set."); | ||
245 | |||
246 | s->auth_proto = packet_get_string(&proto_len); | ||
247 | s->auth_data = packet_get_string(&data_len); | ||
248 | packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type); | ||
249 | |||
250 | if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER) | ||
251 | s->screen = packet_get_int(); | ||
252 | else | ||
253 | s->screen = 0; | ||
254 | s->display = x11_create_display_inet(s->screen, options.x11_display_offset); | ||
255 | |||
256 | if (s->display == NULL) | ||
257 | break; | ||
258 | |||
259 | /* Setup to always have a local .Xauthority. */ | ||
260 | xauthfile = xmalloc(MAXPATHLEN); | ||
261 | strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); | ||
262 | temporarily_use_uid(pw->pw_uid); | ||
263 | if (mkdtemp(xauthfile) == NULL) { | ||
264 | restore_uid(); | ||
265 | error("private X11 dir: mkdtemp %s failed: %s", | ||
266 | xauthfile, strerror(errno)); | ||
267 | xfree(xauthfile); | ||
268 | xauthfile = NULL; | ||
269 | break; | ||
270 | } | ||
271 | strlcat(xauthfile, "/cookies", MAXPATHLEN); | ||
272 | open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); | ||
273 | restore_uid(); | ||
274 | fatal_add_cleanup(xauthfile_cleanup_proc, NULL); | ||
275 | success = 1; | ||
276 | break; | ||
277 | #else /* XAUTH_PATH */ | ||
278 | packet_send_debug("No xauth program; cannot forward with spoofing."); | ||
279 | break; | ||
280 | #endif /* XAUTH_PATH */ | ||
281 | |||
282 | case SSH_CMSG_AGENT_REQUEST_FORWARDING: | ||
283 | if (no_agent_forwarding_flag || compat13) { | ||
284 | debug("Authentication agent forwarding not permitted for this authentication."); | ||
285 | break; | ||
286 | } | ||
287 | debug("Received authentication agent forwarding request."); | ||
288 | auth_input_request_forwarding(pw); | ||
289 | success = 1; | ||
290 | break; | ||
291 | |||
292 | case SSH_CMSG_PORT_FORWARD_REQUEST: | ||
293 | if (no_port_forwarding_flag) { | ||
294 | debug("Port forwarding not permitted for this authentication."); | ||
295 | break; | ||
296 | } | ||
297 | debug("Received TCP/IP port forwarding request."); | ||
298 | channel_input_port_forward_request(pw->pw_uid == 0); | ||
299 | success = 1; | ||
300 | break; | ||
301 | |||
302 | case SSH_CMSG_MAX_PACKET_SIZE: | ||
303 | if (packet_set_maxsize(packet_get_int()) > 0) | ||
304 | success = 1; | ||
305 | break; | ||
306 | |||
307 | case SSH_CMSG_EXEC_SHELL: | ||
308 | case SSH_CMSG_EXEC_CMD: | ||
309 | /* Set interactive/non-interactive mode. */ | ||
310 | packet_set_interactive(have_pty || s->display != NULL, | ||
311 | options.keepalives); | ||
312 | |||
313 | if (type == SSH_CMSG_EXEC_CMD) { | ||
314 | command = packet_get_string(&dlen); | ||
315 | debug("Exec command '%.500s'", command); | ||
316 | packet_integrity_check(plen, 4 + dlen, type); | ||
317 | } else { | ||
318 | command = NULL; | ||
319 | packet_integrity_check(plen, 0, type); | ||
320 | } | ||
321 | if (forced_command != NULL) { | ||
322 | command = forced_command; | ||
323 | debug("Forced command '%.500s'", forced_command); | ||
324 | } | ||
325 | if (have_pty) | ||
326 | do_exec_pty(s, command, pw); | ||
327 | else | ||
328 | do_exec_no_pty(s, command, pw); | ||
329 | |||
330 | if (command != NULL) | ||
331 | xfree(command); | ||
332 | /* Cleanup user's local Xauthority file. */ | ||
333 | if (xauthfile) | ||
334 | xauthfile_cleanup_proc(NULL); | ||
335 | return; | ||
336 | |||
337 | default: | ||
338 | /* | ||
339 | * Any unknown messages in this phase are ignored, | ||
340 | * and a failure message is returned. | ||
341 | */ | ||
342 | log("Unknown packet type received after authentication: %d", type); | ||
343 | } | ||
344 | packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE); | ||
345 | packet_send(); | ||
346 | packet_write_wait(); | ||
347 | |||
348 | /* Enable compression now that we have replied if appropriate. */ | ||
349 | if (enable_compression_after_reply) { | ||
350 | enable_compression_after_reply = 0; | ||
351 | packet_start_compression(compression_level); | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | |||
356 | /* | ||
357 | * This is called to fork and execute a command when we have no tty. This | ||
358 | * will call do_child from the child, and server_loop from the parent after | ||
359 | * setting up file descriptors and such. | ||
360 | */ | ||
361 | void | ||
362 | do_exec_no_pty(Session *s, const char *command, struct passwd * pw) | ||
363 | { | ||
364 | int pid; | ||
365 | |||
366 | #ifdef USE_PIPES | ||
367 | int pin[2], pout[2], perr[2]; | ||
368 | /* Allocate pipes for communicating with the program. */ | ||
369 | if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) | ||
370 | packet_disconnect("Could not create pipes: %.100s", | ||
371 | strerror(errno)); | ||
372 | #else /* USE_PIPES */ | ||
373 | int inout[2], err[2]; | ||
374 | /* Uses socket pairs to communicate with the program. */ | ||
375 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || | ||
376 | socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) | ||
377 | packet_disconnect("Could not create socket pairs: %.100s", | ||
378 | strerror(errno)); | ||
379 | #endif /* USE_PIPES */ | ||
380 | if (s == NULL) | ||
381 | fatal("do_exec_no_pty: no session"); | ||
382 | |||
383 | setproctitle("%s@notty", pw->pw_name); | ||
384 | |||
385 | #ifdef USE_PAM | ||
386 | do_pam_setcred(); | ||
387 | #endif /* USE_PAM */ | ||
388 | |||
389 | /* Fork the child. */ | ||
390 | if ((pid = fork()) == 0) { | ||
391 | /* Child. Reinitialize the log since the pid has changed. */ | ||
392 | log_init(__progname, options.log_level, options.log_facility, log_stderr); | ||
393 | |||
394 | /* | ||
395 | * Create a new session and process group since the 4.4BSD | ||
396 | * setlogin() affects the entire process group. | ||
397 | */ | ||
398 | if (setsid() < 0) | ||
399 | error("setsid failed: %.100s", strerror(errno)); | ||
400 | |||
401 | #ifdef USE_PIPES | ||
402 | /* | ||
403 | * Redirect stdin. We close the parent side of the socket | ||
404 | * pair, and make the child side the standard input. | ||
405 | */ | ||
406 | close(pin[1]); | ||
407 | if (dup2(pin[0], 0) < 0) | ||
408 | perror("dup2 stdin"); | ||
409 | close(pin[0]); | ||
410 | |||
411 | /* Redirect stdout. */ | ||
412 | close(pout[0]); | ||
413 | if (dup2(pout[1], 1) < 0) | ||
414 | perror("dup2 stdout"); | ||
415 | close(pout[1]); | ||
416 | |||
417 | /* Redirect stderr. */ | ||
418 | close(perr[0]); | ||
419 | if (dup2(perr[1], 2) < 0) | ||
420 | perror("dup2 stderr"); | ||
421 | close(perr[1]); | ||
422 | #else /* USE_PIPES */ | ||
423 | /* | ||
424 | * Redirect stdin, stdout, and stderr. Stdin and stdout will | ||
425 | * use the same socket, as some programs (particularly rdist) | ||
426 | * seem to depend on it. | ||
427 | */ | ||
428 | close(inout[1]); | ||
429 | close(err[1]); | ||
430 | if (dup2(inout[0], 0) < 0) /* stdin */ | ||
431 | perror("dup2 stdin"); | ||
432 | if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ | ||
433 | perror("dup2 stdout"); | ||
434 | if (dup2(err[0], 2) < 0) /* stderr */ | ||
435 | perror("dup2 stderr"); | ||
436 | #endif /* USE_PIPES */ | ||
437 | |||
438 | /* Do processing for the child (exec command etc). */ | ||
439 | do_child(command, pw, NULL, s->display, s->auth_proto, s->auth_data, NULL); | ||
440 | /* NOTREACHED */ | ||
441 | } | ||
442 | if (pid < 0) | ||
443 | packet_disconnect("fork failed: %.100s", strerror(errno)); | ||
444 | s->pid = pid; | ||
445 | #ifdef USE_PIPES | ||
446 | /* We are the parent. Close the child sides of the pipes. */ | ||
447 | close(pin[0]); | ||
448 | close(pout[1]); | ||
449 | close(perr[1]); | ||
450 | |||
451 | /* Enter the interactive session. */ | ||
452 | server_loop(pid, pin[1], pout[0], perr[0]); | ||
453 | /* server_loop has closed pin[1], pout[1], and perr[1]. */ | ||
454 | #else /* USE_PIPES */ | ||
455 | /* We are the parent. Close the child sides of the socket pairs. */ | ||
456 | close(inout[0]); | ||
457 | close(err[0]); | ||
458 | |||
459 | /* | ||
460 | * Enter the interactive session. Note: server_loop must be able to | ||
461 | * handle the case that fdin and fdout are the same. | ||
462 | */ | ||
463 | server_loop(pid, inout[1], inout[1], err[1]); | ||
464 | /* server_loop has closed inout[1] and err[1]. */ | ||
465 | #endif /* USE_PIPES */ | ||
466 | } | ||
467 | |||
468 | /* | ||
469 | * This is called to fork and execute a command when we have a tty. This | ||
470 | * will call do_child from the child, and server_loop from the parent after | ||
471 | * setting up file descriptors, controlling tty, updating wtmp, utmp, | ||
472 | * lastlog, and other such operations. | ||
473 | */ | ||
474 | void | ||
475 | do_exec_pty(Session *s, const char *command, struct passwd * pw) | ||
476 | { | ||
477 | FILE *f; | ||
478 | char buf[100], *time_string; | ||
479 | char line[256]; | ||
480 | const char *hostname; | ||
481 | int fdout, ptyfd, ttyfd, ptymaster; | ||
482 | int quiet_login; | ||
483 | pid_t pid; | ||
484 | socklen_t fromlen; | ||
485 | struct sockaddr_storage from; | ||
486 | struct stat st; | ||
487 | time_t last_login_time; | ||
488 | |||
489 | if (s == NULL) | ||
490 | fatal("do_exec_pty: no session"); | ||
491 | ptyfd = s->ptyfd; | ||
492 | ttyfd = s->ttyfd; | ||
493 | |||
494 | /* Get remote host name. */ | ||
495 | hostname = get_canonical_hostname(); | ||
496 | |||
497 | /* | ||
498 | * Get the time when the user last logged in. Buf will be set to | ||
499 | * contain the hostname the last login was from. | ||
500 | */ | ||
501 | if (!options.use_login) { | ||
502 | last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, | ||
503 | buf, sizeof(buf)); | ||
504 | } | ||
505 | setproctitle("%s@%s", pw->pw_name, strrchr(s->tty, '/') + 1); | ||
506 | |||
507 | #ifdef USE_PAM | ||
508 | do_pam_session(pw->pw_name, s->tty); | ||
509 | do_pam_setcred(); | ||
510 | #endif /* USE_PAM */ | ||
511 | |||
512 | /* Fork the child. */ | ||
513 | if ((pid = fork()) == 0) { | ||
514 | pid = getpid(); | ||
515 | |||
516 | /* Child. Reinitialize the log because the pid has | ||
517 | changed. */ | ||
518 | log_init(__progname, options.log_level, options.log_facility, log_stderr); | ||
519 | |||
520 | /* Close the master side of the pseudo tty. */ | ||
521 | close(ptyfd); | ||
522 | |||
523 | /* Make the pseudo tty our controlling tty. */ | ||
524 | pty_make_controlling_tty(&ttyfd, s->tty); | ||
525 | |||
526 | /* Redirect stdin from the pseudo tty. */ | ||
527 | if (dup2(ttyfd, fileno(stdin)) < 0) | ||
528 | error("dup2 stdin failed: %.100s", strerror(errno)); | ||
529 | |||
530 | /* Redirect stdout to the pseudo tty. */ | ||
531 | if (dup2(ttyfd, fileno(stdout)) < 0) | ||
532 | error("dup2 stdin failed: %.100s", strerror(errno)); | ||
533 | |||
534 | /* Redirect stderr to the pseudo tty. */ | ||
535 | if (dup2(ttyfd, fileno(stderr)) < 0) | ||
536 | error("dup2 stdin failed: %.100s", strerror(errno)); | ||
537 | |||
538 | /* Close the extra descriptor for the pseudo tty. */ | ||
539 | close(ttyfd); | ||
540 | |||
541 | ///XXXX ? move to do_child() ?? | ||
542 | /* | ||
543 | * Get IP address of client. This is needed because we want | ||
544 | * to record where the user logged in from. If the | ||
545 | * connection is not a socket, let the ip address be 0.0.0.0. | ||
546 | */ | ||
547 | memset(&from, 0, sizeof(from)); | ||
548 | if (packet_connection_is_on_socket()) { | ||
549 | fromlen = sizeof(from); | ||
550 | if (getpeername(packet_get_connection_in(), | ||
551 | (struct sockaddr *) & from, &fromlen) < 0) { | ||
552 | debug("getpeername: %.100s", strerror(errno)); | ||
553 | fatal_cleanup(); | ||
554 | } | ||
555 | } | ||
556 | /* Record that there was a login on that terminal. */ | ||
557 | record_login(pid, s->tty, pw->pw_name, pw->pw_uid, hostname, | ||
558 | (struct sockaddr *)&from); | ||
559 | |||
560 | /* Check if .hushlogin exists. */ | ||
561 | snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir); | ||
562 | quiet_login = stat(line, &st) >= 0; | ||
563 | |||
564 | #ifdef USE_PAM | ||
565 | if (!quiet_login) | ||
566 | print_pam_messages(); | ||
567 | #endif /* USE_PAM */ | ||
568 | |||
569 | /* | ||
570 | * If the user has logged in before, display the time of last | ||
571 | * login. However, don't display anything extra if a command | ||
572 | * has been specified (so that ssh can be used to execute | ||
573 | * commands on a remote machine without users knowing they | ||
574 | * are going to another machine). Login(1) will do this for | ||
575 | * us as well, so check if login(1) is used | ||
576 | */ | ||
577 | if (command == NULL && last_login_time != 0 && !quiet_login && | ||
578 | !options.use_login) { | ||
579 | /* Convert the date to a string. */ | ||
580 | time_string = ctime(&last_login_time); | ||
581 | /* Remove the trailing newline. */ | ||
582 | if (strchr(time_string, '\n')) | ||
583 | *strchr(time_string, '\n') = 0; | ||
584 | /* Display the last login time. Host if displayed | ||
585 | if known. */ | ||
586 | if (strcmp(buf, "") == 0) | ||
587 | printf("Last login: %s\r\n", time_string); | ||
588 | else | ||
589 | printf("Last login: %s from %s\r\n", time_string, buf); | ||
590 | } | ||
591 | /* | ||
592 | * Print /etc/motd unless a command was specified or printing | ||
593 | * it was disabled in server options or login(1) will be | ||
594 | * used. Note that some machines appear to print it in | ||
595 | * /etc/profile or similar. | ||
596 | */ | ||
597 | if (command == NULL && options.print_motd && !quiet_login && | ||
598 | !options.use_login) { | ||
599 | /* Print /etc/motd if it exists. */ | ||
600 | f = fopen("/etc/motd", "r"); | ||
601 | if (f) { | ||
602 | while (fgets(line, sizeof(line), f)) | ||
603 | fputs(line, stdout); | ||
604 | fclose(f); | ||
605 | } | ||
606 | } | ||
607 | /* Do common processing for the child, such as execing the command. */ | ||
608 | do_child(command, pw, s->term, s->display, s->auth_proto, s->auth_data, s->tty); | ||
609 | /* NOTREACHED */ | ||
610 | } | ||
611 | if (pid < 0) | ||
612 | packet_disconnect("fork failed: %.100s", strerror(errno)); | ||
613 | s->pid = pid; | ||
614 | |||
615 | /* Parent. Close the slave side of the pseudo tty. */ | ||
616 | close(ttyfd); | ||
617 | |||
618 | /* | ||
619 | * Create another descriptor of the pty master side for use as the | ||
620 | * standard input. We could use the original descriptor, but this | ||
621 | * simplifies code in server_loop. The descriptor is bidirectional. | ||
622 | */ | ||
623 | fdout = dup(ptyfd); | ||
624 | if (fdout < 0) | ||
625 | packet_disconnect("dup #1 failed: %.100s", strerror(errno)); | ||
626 | |||
627 | /* we keep a reference to the pty master */ | ||
628 | ptymaster = dup(ptyfd); | ||
629 | if (ptymaster < 0) | ||
630 | packet_disconnect("dup #2 failed: %.100s", strerror(errno)); | ||
631 | s->ptymaster = ptymaster; | ||
632 | |||
633 | /* Enter interactive session. */ | ||
634 | server_loop(pid, ptyfd, fdout, -1); | ||
635 | /* server_loop _has_ closed ptyfd and fdout. */ | ||
636 | session_pty_cleanup(s); | ||
637 | } | ||
638 | |||
639 | /* | ||
640 | * Sets the value of the given variable in the environment. If the variable | ||
641 | * already exists, its value is overriden. | ||
642 | */ | ||
643 | void | ||
644 | child_set_env(char ***envp, unsigned int *envsizep, const char *name, | ||
645 | const char *value) | ||
646 | { | ||
647 | unsigned int i, namelen; | ||
648 | char **env; | ||
649 | |||
650 | /* | ||
651 | * Find the slot where the value should be stored. If the variable | ||
652 | * already exists, we reuse the slot; otherwise we append a new slot | ||
653 | * at the end of the array, expanding if necessary. | ||
654 | */ | ||
655 | env = *envp; | ||
656 | namelen = strlen(name); | ||
657 | for (i = 0; env[i]; i++) | ||
658 | if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') | ||
659 | break; | ||
660 | if (env[i]) { | ||
661 | /* Reuse the slot. */ | ||
662 | xfree(env[i]); | ||
663 | } else { | ||
664 | /* New variable. Expand if necessary. */ | ||
665 | if (i >= (*envsizep) - 1) { | ||
666 | (*envsizep) += 50; | ||
667 | env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *)); | ||
668 | } | ||
669 | /* Need to set the NULL pointer at end of array beyond the new slot. */ | ||
670 | env[i + 1] = NULL; | ||
671 | } | ||
672 | |||
673 | /* Allocate space and format the variable in the appropriate slot. */ | ||
674 | env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); | ||
675 | snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); | ||
676 | } | ||
677 | |||
678 | /* | ||
679 | * Reads environment variables from the given file and adds/overrides them | ||
680 | * into the environment. If the file does not exist, this does nothing. | ||
681 | * Otherwise, it must consist of empty lines, comments (line starts with '#') | ||
682 | * and assignments of the form name=value. No other forms are allowed. | ||
683 | */ | ||
684 | void | ||
685 | read_environment_file(char ***env, unsigned int *envsize, | ||
686 | const char *filename) | ||
687 | { | ||
688 | FILE *f; | ||
689 | char buf[4096]; | ||
690 | char *cp, *value; | ||
691 | |||
692 | f = fopen(filename, "r"); | ||
693 | if (!f) | ||
694 | return; | ||
695 | |||
696 | while (fgets(buf, sizeof(buf), f)) { | ||
697 | for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) | ||
698 | ; | ||
699 | if (!*cp || *cp == '#' || *cp == '\n') | ||
700 | continue; | ||
701 | if (strchr(cp, '\n')) | ||
702 | *strchr(cp, '\n') = '\0'; | ||
703 | value = strchr(cp, '='); | ||
704 | if (value == NULL) { | ||
705 | fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf); | ||
706 | continue; | ||
707 | } | ||
708 | /* Replace the equals sign by nul, and advance value to the value string. */ | ||
709 | *value = '\0'; | ||
710 | value++; | ||
711 | child_set_env(env, envsize, cp, value); | ||
712 | } | ||
713 | fclose(f); | ||
714 | } | ||
715 | |||
716 | #ifdef USE_PAM | ||
717 | /* | ||
718 | * Sets any environment variables which have been specified by PAM | ||
719 | */ | ||
720 | void do_pam_environment(char ***env, int *envsize) | ||
721 | { | ||
722 | char *equals, var_name[512], var_val[512]; | ||
723 | char **pam_env; | ||
724 | int i; | ||
725 | |||
726 | if ((pam_env = fetch_pam_environment()) == NULL) | ||
727 | return; | ||
728 | |||
729 | for(i = 0; pam_env[i] != NULL; i++) { | ||
730 | if ((equals = strstr(pam_env[i], "=")) == NULL) | ||
731 | continue; | ||
732 | |||
733 | if (strlen(pam_env[i]) < (sizeof(var_name) - 1)) { | ||
734 | memset(var_name, '\0', sizeof(var_name)); | ||
735 | memset(var_val, '\0', sizeof(var_val)); | ||
736 | |||
737 | strncpy(var_name, pam_env[i], equals - pam_env[i]); | ||
738 | strcpy(var_val, equals + 1); | ||
739 | |||
740 | debug("PAM environment: %s=%s", var_name, var_val); | ||
741 | |||
742 | child_set_env(env, envsize, var_name, var_val); | ||
743 | } | ||
744 | } | ||
745 | } | ||
746 | #endif /* USE_PAM */ | ||
747 | |||
748 | /* | ||
749 | * Performs common processing for the child, such as setting up the | ||
750 | * environment, closing extra file descriptors, setting the user and group | ||
751 | * ids, and executing the command or shell. | ||
752 | */ | ||
753 | void | ||
754 | do_child(const char *command, struct passwd * pw, const char *term, | ||
755 | const char *display, const char *auth_proto, | ||
756 | const char *auth_data, const char *ttyname) | ||
757 | { | ||
758 | const char *shell, *cp = NULL; | ||
759 | char buf[256]; | ||
760 | FILE *f; | ||
761 | unsigned int envsize, i; | ||
762 | char **env; | ||
763 | extern char **environ; | ||
764 | struct stat st; | ||
765 | char *argv[10]; | ||
766 | |||
767 | #ifndef USE_PAM /* pam_nologin handles this */ | ||
768 | f = fopen("/etc/nologin", "r"); | ||
769 | if (f) { | ||
770 | /* /etc/nologin exists. Print its contents and exit. */ | ||
771 | while (fgets(buf, sizeof(buf), f)) | ||
772 | fputs(buf, stderr); | ||
773 | fclose(f); | ||
774 | if (pw->pw_uid != 0) | ||
775 | exit(254); | ||
776 | } | ||
777 | #endif /* USE_PAM */ | ||
778 | |||
779 | /* Set login name in the kernel. */ | ||
780 | if (setlogin(pw->pw_name) < 0) | ||
781 | error("setlogin failed: %s", strerror(errno)); | ||
782 | |||
783 | /* Set uid, gid, and groups. */ | ||
784 | /* Login(1) does this as well, and it needs uid 0 for the "-h" | ||
785 | switch, so we let login(1) to this for us. */ | ||
786 | if (!options.use_login) { | ||
787 | if (getuid() == 0 || geteuid() == 0) { | ||
788 | if (setgid(pw->pw_gid) < 0) { | ||
789 | perror("setgid"); | ||
790 | exit(1); | ||
791 | } | ||
792 | /* Initialize the group list. */ | ||
793 | if (initgroups(pw->pw_name, pw->pw_gid) < 0) { | ||
794 | perror("initgroups"); | ||
795 | exit(1); | ||
796 | } | ||
797 | endgrent(); | ||
798 | |||
799 | /* Permanently switch to the desired uid. */ | ||
800 | permanently_set_uid(pw->pw_uid); | ||
801 | } | ||
802 | if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) | ||
803 | fatal("Failed to set uids to %d.", (int) pw->pw_uid); | ||
804 | } | ||
805 | /* | ||
806 | * Get the shell from the password data. An empty shell field is | ||
807 | * legal, and means /bin/sh. | ||
808 | */ | ||
809 | shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; | ||
810 | |||
811 | #ifdef AFS | ||
812 | /* Try to get AFS tokens for the local cell. */ | ||
813 | if (k_hasafs()) { | ||
814 | char cell[64]; | ||
815 | |||
816 | if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) | ||
817 | krb_afslog(cell, 0); | ||
818 | |||
819 | krb_afslog(0, 0); | ||
820 | } | ||
821 | #endif /* AFS */ | ||
822 | |||
823 | /* Initialize the environment. */ | ||
824 | envsize = 100; | ||
825 | env = xmalloc(envsize * sizeof(char *)); | ||
826 | env[0] = NULL; | ||
827 | |||
828 | if (!options.use_login) { | ||
829 | /* Set basic environment. */ | ||
830 | child_set_env(&env, &envsize, "USER", pw->pw_name); | ||
831 | child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); | ||
832 | child_set_env(&env, &envsize, "HOME", pw->pw_dir); | ||
833 | child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); | ||
834 | |||
835 | snprintf(buf, sizeof buf, "%.200s/%.50s", | ||
836 | _PATH_MAILDIR, pw->pw_name); | ||
837 | child_set_env(&env, &envsize, "MAIL", buf); | ||
838 | |||
839 | /* Normal systems set SHELL by default. */ | ||
840 | child_set_env(&env, &envsize, "SHELL", shell); | ||
841 | } | ||
842 | if (getenv("TZ")) | ||
843 | child_set_env(&env, &envsize, "TZ", getenv("TZ")); | ||
844 | |||
845 | /* Set custom environment options from RSA authentication. */ | ||
846 | while (custom_environment) { | ||
847 | struct envstring *ce = custom_environment; | ||
848 | char *s = ce->s; | ||
849 | int i; | ||
850 | for (i = 0; s[i] != '=' && s[i]; i++); | ||
851 | if (s[i] == '=') { | ||
852 | s[i] = 0; | ||
853 | child_set_env(&env, &envsize, s, s + i + 1); | ||
854 | } | ||
855 | custom_environment = ce->next; | ||
856 | xfree(ce->s); | ||
857 | xfree(ce); | ||
858 | } | ||
859 | |||
860 | snprintf(buf, sizeof buf, "%.50s %d %d", | ||
861 | get_remote_ipaddr(), get_remote_port(), get_local_port()); | ||
862 | child_set_env(&env, &envsize, "SSH_CLIENT", buf); | ||
863 | |||
864 | if (ttyname) | ||
865 | child_set_env(&env, &envsize, "SSH_TTY", ttyname); | ||
866 | if (term) | ||
867 | child_set_env(&env, &envsize, "TERM", term); | ||
868 | if (display) | ||
869 | child_set_env(&env, &envsize, "DISPLAY", display); | ||
870 | |||
871 | #ifdef _AIX | ||
872 | { | ||
873 | char *authstate,*krb5cc; | ||
874 | |||
875 | if ((authstate = getenv("AUTHSTATE")) != NULL) | ||
876 | child_set_env(&env,&envsize,"AUTHSTATE",authstate); | ||
877 | |||
878 | if ((krb5cc = getenv("KRB5CCNAME")) != NULL) | ||
879 | child_set_env(&env,&envsize,"KRB5CCNAME",krb5cc); | ||
880 | } | ||
881 | #endif | ||
882 | |||
883 | #ifdef KRB4 | ||
884 | { | ||
885 | extern char *ticket; | ||
886 | |||
887 | if (ticket) | ||
888 | child_set_env(&env, &envsize, "KRBTKFILE", ticket); | ||
889 | } | ||
890 | #endif /* KRB4 */ | ||
891 | |||
892 | #ifdef USE_PAM | ||
893 | /* Pull in any environment variables that may have been set by PAM. */ | ||
894 | do_pam_environment(&env, &envsize); | ||
895 | #endif /* USE_PAM */ | ||
896 | |||
897 | read_environment_file(&env,&envsize,"/etc/environment"); | ||
898 | |||
899 | if (xauthfile) | ||
900 | child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); | ||
901 | if (auth_get_socket_name() != NULL) | ||
902 | child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, | ||
903 | auth_get_socket_name()); | ||
904 | |||
905 | /* read $HOME/.ssh/environment. */ | ||
906 | if (!options.use_login) { | ||
907 | snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir); | ||
908 | read_environment_file(&env, &envsize, buf); | ||
909 | } | ||
910 | if (debug_flag) { | ||
911 | /* dump the environment */ | ||
912 | fprintf(stderr, "Environment:\n"); | ||
913 | for (i = 0; env[i]; i++) | ||
914 | fprintf(stderr, " %.200s\n", env[i]); | ||
915 | } | ||
916 | /* | ||
917 | * Close the connection descriptors; note that this is the child, and | ||
918 | * the server will still have the socket open, and it is important | ||
919 | * that we do not shutdown it. Note that the descriptors cannot be | ||
920 | * closed before building the environment, as we call | ||
921 | * get_remote_ipaddr there. | ||
922 | */ | ||
923 | if (packet_get_connection_in() == packet_get_connection_out()) | ||
924 | close(packet_get_connection_in()); | ||
925 | else { | ||
926 | close(packet_get_connection_in()); | ||
927 | close(packet_get_connection_out()); | ||
928 | } | ||
929 | /* | ||
930 | * Close all descriptors related to channels. They will still remain | ||
931 | * open in the parent. | ||
932 | */ | ||
933 | /* XXX better use close-on-exec? -markus */ | ||
934 | channel_close_all(); | ||
935 | |||
936 | /* | ||
937 | * Close any extra file descriptors. Note that there may still be | ||
938 | * descriptors left by system functions. They will be closed later. | ||
939 | */ | ||
940 | endpwent(); | ||
941 | |||
942 | /* | ||
943 | * Close any extra open file descriptors so that we don\'t have them | ||
944 | * hanging around in clients. Note that we want to do this after | ||
945 | * initgroups, because at least on Solaris 2.3 it leaves file | ||
946 | * descriptors open. | ||
947 | */ | ||
948 | for (i = 3; i < 64; i++) | ||
949 | close(i); | ||
950 | |||
951 | /* Change current directory to the user\'s home directory. */ | ||
952 | if (chdir(pw->pw_dir) < 0) | ||
953 | fprintf(stderr, "Could not chdir to home directory %s: %s\n", | ||
954 | pw->pw_dir, strerror(errno)); | ||
955 | |||
956 | /* | ||
957 | * Must take new environment into use so that .ssh/rc, /etc/sshrc and | ||
958 | * xauth are run in the proper environment. | ||
959 | */ | ||
960 | environ = env; | ||
961 | |||
962 | /* | ||
963 | * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first | ||
964 | * in this order). | ||
965 | */ | ||
966 | if (!options.use_login) { | ||
967 | if (stat(SSH_USER_RC, &st) >= 0) { | ||
968 | if (debug_flag) | ||
969 | fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC); | ||
970 | |||
971 | f = popen("/bin/sh " SSH_USER_RC, "w"); | ||
972 | if (f) { | ||
973 | if (auth_proto != NULL && auth_data != NULL) | ||
974 | fprintf(f, "%s %s\n", auth_proto, auth_data); | ||
975 | pclose(f); | ||
976 | } else | ||
977 | fprintf(stderr, "Could not run %s\n", SSH_USER_RC); | ||
978 | } else if (stat(SSH_SYSTEM_RC, &st) >= 0) { | ||
979 | if (debug_flag) | ||
980 | fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC); | ||
981 | |||
982 | f = popen("/bin/sh " SSH_SYSTEM_RC, "w"); | ||
983 | if (f) { | ||
984 | if (auth_proto != NULL && auth_data != NULL) | ||
985 | fprintf(f, "%s %s\n", auth_proto, auth_data); | ||
986 | pclose(f); | ||
987 | } else | ||
988 | fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC); | ||
989 | } | ||
990 | #ifdef XAUTH_PATH | ||
991 | else { | ||
992 | /* Add authority data to .Xauthority if appropriate. */ | ||
993 | if (auth_proto != NULL && auth_data != NULL) { | ||
994 | if (debug_flag) | ||
995 | fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n", | ||
996 | XAUTH_PATH, display, auth_proto, auth_data); | ||
997 | |||
998 | f = popen(XAUTH_PATH " -q -", "w"); | ||
999 | if (f) { | ||
1000 | fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data); | ||
1001 | pclose(f); | ||
1002 | } else | ||
1003 | fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH); | ||
1004 | } | ||
1005 | } | ||
1006 | #endif /* XAUTH_PATH */ | ||
1007 | |||
1008 | /* Get the last component of the shell name. */ | ||
1009 | cp = strrchr(shell, '/'); | ||
1010 | if (cp) | ||
1011 | cp++; | ||
1012 | else | ||
1013 | cp = shell; | ||
1014 | } | ||
1015 | /* | ||
1016 | * If we have no command, execute the shell. In this case, the shell | ||
1017 | * name to be passed in argv[0] is preceded by '-' to indicate that | ||
1018 | * this is a login shell. | ||
1019 | */ | ||
1020 | if (!command) { | ||
1021 | if (!options.use_login) { | ||
1022 | char buf[256]; | ||
1023 | |||
1024 | /* | ||
1025 | * Check for mail if we have a tty and it was enabled | ||
1026 | * in server options. | ||
1027 | */ | ||
1028 | if (ttyname && options.check_mail) { | ||
1029 | char *mailbox; | ||
1030 | struct stat mailstat; | ||
1031 | mailbox = getenv("MAIL"); | ||
1032 | if (mailbox != NULL) { | ||
1033 | if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0) | ||
1034 | printf("No mail.\n"); | ||
1035 | else if (mailstat.st_mtime < mailstat.st_atime) | ||
1036 | printf("You have mail.\n"); | ||
1037 | else | ||
1038 | printf("You have new mail.\n"); | ||
1039 | } | ||
1040 | } | ||
1041 | /* Start the shell. Set initial character to '-'. */ | ||
1042 | buf[0] = '-'; | ||
1043 | strncpy(buf + 1, cp, sizeof(buf) - 1); | ||
1044 | buf[sizeof(buf) - 1] = 0; | ||
1045 | |||
1046 | /* Execute the shell. */ | ||
1047 | argv[0] = buf; | ||
1048 | argv[1] = NULL; | ||
1049 | execve(shell, argv, env); | ||
1050 | |||
1051 | /* Executing the shell failed. */ | ||
1052 | perror(shell); | ||
1053 | exit(1); | ||
1054 | |||
1055 | } else { | ||
1056 | /* Launch login(1). */ | ||
1057 | |||
1058 | execl("/usr/bin/login", "login", "-h", get_remote_ipaddr(), | ||
1059 | "-p", "-f", "--", pw->pw_name, NULL); | ||
1060 | |||
1061 | /* Login couldn't be executed, die. */ | ||
1062 | |||
1063 | perror("login"); | ||
1064 | exit(1); | ||
1065 | } | ||
1066 | } | ||
1067 | /* | ||
1068 | * Execute the command using the user's shell. This uses the -c | ||
1069 | * option to execute the command. | ||
1070 | */ | ||
1071 | argv[0] = (char *) cp; | ||
1072 | argv[1] = "-c"; | ||
1073 | argv[2] = (char *) command; | ||
1074 | argv[3] = NULL; | ||
1075 | execve(shell, argv, env); | ||
1076 | perror(shell); | ||
1077 | exit(1); | ||
1078 | } | ||
1079 | |||
1080 | Session * | ||
1081 | session_new(void) | ||
1082 | { | ||
1083 | int i; | ||
1084 | static int did_init = 0; | ||
1085 | if (!did_init) { | ||
1086 | debug("session_new: init"); | ||
1087 | for(i = 0; i < MAX_SESSIONS; i++) { | ||
1088 | sessions[i].used = 0; | ||
1089 | sessions[i].self = i; | ||
1090 | } | ||
1091 | did_init = 1; | ||
1092 | } | ||
1093 | for(i = 0; i < MAX_SESSIONS; i++) { | ||
1094 | Session *s = &sessions[i]; | ||
1095 | if (! s->used) { | ||
1096 | s->pid = 0; | ||
1097 | s->chanid = -1; | ||
1098 | s->ptyfd = -1; | ||
1099 | s->ttyfd = -1; | ||
1100 | s->term = NULL; | ||
1101 | s->pw = NULL; | ||
1102 | s->display = NULL; | ||
1103 | s->screen = 0; | ||
1104 | s->auth_data = NULL; | ||
1105 | s->auth_proto = NULL; | ||
1106 | s->used = 1; | ||
1107 | debug("session_new: session %d", i); | ||
1108 | return s; | ||
1109 | } | ||
1110 | } | ||
1111 | return NULL; | ||
1112 | } | ||
1113 | |||
1114 | void | ||
1115 | session_dump(void) | ||
1116 | { | ||
1117 | int i; | ||
1118 | for(i = 0; i < MAX_SESSIONS; i++) { | ||
1119 | Session *s = &sessions[i]; | ||
1120 | debug("dump: used %d session %d %p channel %d pid %d", | ||
1121 | s->used, | ||
1122 | s->self, | ||
1123 | s, | ||
1124 | s->chanid, | ||
1125 | s->pid); | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | void | ||
1130 | session_pty_cleanup(Session *s) | ||
1131 | { | ||
1132 | if (s == NULL || s->ttyfd == -1) | ||
1133 | return; | ||
1134 | |||
1135 | debug("session_pty_cleanup: session %i release %s", s->self, s->tty); | ||
1136 | |||
1137 | /* Cancel the cleanup function. */ | ||
1138 | fatal_remove_cleanup(pty_cleanup_proc, (void *)s); | ||
1139 | |||
1140 | /* Record that the user has logged out. */ | ||
1141 | record_logout(s->pid, s->tty); | ||
1142 | |||
1143 | /* Release the pseudo-tty. */ | ||
1144 | pty_release(s->tty); | ||
1145 | |||
1146 | /* | ||
1147 | * Close the server side of the socket pairs. We must do this after | ||
1148 | * the pty cleanup, so that another process doesn't get this pty | ||
1149 | * while we're still cleaning up. | ||
1150 | */ | ||
1151 | if (close(s->ptymaster) < 0) | ||
1152 | error("close(s->ptymaster): %s", strerror(errno)); | ||
1153 | } | ||
diff --git a/session.h b/session.h new file mode 100644 index 000000000..2051b737d --- /dev/null +++ b/session.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef SESSION_H | ||
2 | #define SESSION_H | ||
3 | |||
4 | /* SSH1 */ | ||
5 | void do_authenticated(struct passwd * pw); | ||
6 | |||
7 | #endif | ||
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include "includes.h" | 13 | #include "includes.h" |
14 | RCSID("$Id: ssh.c,v 1.22 2000/03/26 03:04:54 damien Exp $"); | 14 | RCSID("$Id: ssh.c,v 1.23 2000/04/01 01:09:26 damien Exp $"); |
15 | 15 | ||
16 | #include "xmalloc.h" | 16 | #include "xmalloc.h" |
17 | #include "ssh.h" | 17 | #include "ssh.h" |
@@ -20,6 +20,7 @@ RCSID("$Id: ssh.c,v 1.22 2000/03/26 03:04:54 damien Exp $"); | |||
20 | #include "authfd.h" | 20 | #include "authfd.h" |
21 | #include "readconf.h" | 21 | #include "readconf.h" |
22 | #include "uidswap.h" | 22 | #include "uidswap.h" |
23 | #include "channels.h" | ||
23 | 24 | ||
24 | #ifdef HAVE___PROGNAME | 25 | #ifdef HAVE___PROGNAME |
25 | extern char *__progname; | 26 | extern char *__progname; |
@@ -13,7 +13,7 @@ | |||
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | /* RCSID("$Id: ssh.h,v 1.28 2000/03/26 03:04:54 damien Exp $"); */ | 16 | /* RCSID("$Id: ssh.h,v 1.29 2000/04/01 01:09:26 damien Exp $"); */ |
17 | 17 | ||
18 | #ifndef SSH_H | 18 | #ifndef SSH_H |
19 | #define SSH_H | 19 | #define SSH_H |
@@ -486,175 +486,6 @@ void fatal_add_cleanup(void (*proc) (void *context), void *context); | |||
486 | /* Removes a cleanup function to be called at fatal(). */ | 486 | /* Removes a cleanup function to be called at fatal(). */ |
487 | void fatal_remove_cleanup(void (*proc) (void *context), void *context); | 487 | void fatal_remove_cleanup(void (*proc) (void *context), void *context); |
488 | 488 | ||
489 | /*---------------- definitions for channels ------------------*/ | ||
490 | |||
491 | /* Sets specific protocol options. */ | ||
492 | void channel_set_options(int hostname_in_open); | ||
493 | |||
494 | /* | ||
495 | * Allocate a new channel object and set its type and socket. Remote_name | ||
496 | * must have been allocated with xmalloc; this will free it when the channel | ||
497 | * is freed. | ||
498 | */ | ||
499 | int channel_allocate(int type, int sock, char *remote_name); | ||
500 | |||
501 | /* Free the channel and close its socket. */ | ||
502 | void channel_free(int channel); | ||
503 | |||
504 | /* Add any bits relevant to channels in select bitmasks. */ | ||
505 | void channel_prepare_select(fd_set * readset, fd_set * writeset); | ||
506 | |||
507 | /* | ||
508 | * After select, perform any appropriate operations for channels which have | ||
509 | * events pending. | ||
510 | */ | ||
511 | void channel_after_select(fd_set * readset, fd_set * writeset); | ||
512 | |||
513 | /* If there is data to send to the connection, send some of it now. */ | ||
514 | void channel_output_poll(void); | ||
515 | |||
516 | /* | ||
517 | * This is called when a packet of type CHANNEL_DATA has just been received. | ||
518 | * The message type has already been consumed, but channel number and data is | ||
519 | * still there. | ||
520 | */ | ||
521 | void channel_input_data(int payload_len); | ||
522 | |||
523 | /* Returns true if no channel has too much buffered data. */ | ||
524 | int channel_not_very_much_buffered_data(void); | ||
525 | |||
526 | /* This is called after receiving CHANNEL_CLOSE. */ | ||
527 | void channel_input_close(void); | ||
528 | |||
529 | /* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */ | ||
530 | void channel_input_close_confirmation(void); | ||
531 | |||
532 | /* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */ | ||
533 | void channel_input_open_confirmation(void); | ||
534 | |||
535 | /* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */ | ||
536 | void channel_input_open_failure(void); | ||
537 | |||
538 | /* This closes any sockets that are listening for connections; this removes | ||
539 | any unix domain sockets. */ | ||
540 | void channel_stop_listening(void); | ||
541 | |||
542 | /* | ||
543 | * Closes the sockets of all channels. This is used to close extra file | ||
544 | * descriptors after a fork. | ||
545 | */ | ||
546 | void channel_close_all(void); | ||
547 | |||
548 | /* Returns the maximum file descriptor number used by the channels. */ | ||
549 | int channel_max_fd(void); | ||
550 | |||
551 | /* Returns true if there is still an open channel over the connection. */ | ||
552 | int channel_still_open(void); | ||
553 | |||
554 | /* | ||
555 | * Returns a string containing a list of all open channels. The list is | ||
556 | * suitable for displaying to the user. It uses crlf instead of newlines. | ||
557 | * The caller should free the string with xfree. | ||
558 | */ | ||
559 | char *channel_open_message(void); | ||
560 | |||
561 | /* | ||
562 | * Initiate forwarding of connections to local port "port" through the secure | ||
563 | * channel to host:port from remote side. This never returns if there was an | ||
564 | * error. | ||
565 | */ | ||
566 | void | ||
567 | channel_request_local_forwarding(u_short port, const char *host, | ||
568 | u_short remote_port, int gateway_ports); | ||
569 | |||
570 | /* | ||
571 | * Initiate forwarding of connections to port "port" on remote host through | ||
572 | * the secure channel to host:port from local side. This never returns if | ||
573 | * there was an error. This registers that open requests for that port are | ||
574 | * permitted. | ||
575 | */ | ||
576 | void | ||
577 | channel_request_remote_forwarding(u_short port, const char *host, | ||
578 | u_short remote_port); | ||
579 | |||
580 | /* | ||
581 | * Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually | ||
582 | * called by the server, because the user could connect to any port anyway, | ||
583 | * and the server has no way to know but to trust the client anyway. | ||
584 | */ | ||
585 | void channel_permit_all_opens(void); | ||
586 | |||
587 | /* | ||
588 | * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates | ||
589 | * listening for the port, and sends back a success reply (or disconnect | ||
590 | * message if there was an error). This never returns if there was an error. | ||
591 | */ | ||
592 | void channel_input_port_forward_request(int is_root); | ||
593 | |||
594 | /* | ||
595 | * This is called after receiving PORT_OPEN message. This attempts to | ||
596 | * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION | ||
597 | * or CHANNEL_OPEN_FAILURE. | ||
598 | */ | ||
599 | void channel_input_port_open(int payload_len); | ||
600 | |||
601 | /* | ||
602 | * Creates a port for X11 connections, and starts listening for it. Returns | ||
603 | * the display name, or NULL if an error was encountered. | ||
604 | */ | ||
605 | char *x11_create_display(int screen); | ||
606 | |||
607 | /* | ||
608 | * Creates an internet domain socket for listening for X11 connections. | ||
609 | * Returns a suitable value for the DISPLAY variable, or NULL if an error | ||
610 | * occurs. | ||
611 | */ | ||
612 | char *x11_create_display_inet(int screen, int x11_display_offset); | ||
613 | |||
614 | /* | ||
615 | * This is called when SSH_SMSG_X11_OPEN is received. The packet contains | ||
616 | * the remote channel number. We should do whatever we want, and respond | ||
617 | * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. | ||
618 | */ | ||
619 | void x11_input_open(int payload_len); | ||
620 | |||
621 | /* | ||
622 | * Requests forwarding of X11 connections. This should be called on the | ||
623 | * client only. | ||
624 | */ | ||
625 | void x11_request_forwarding(void); | ||
626 | |||
627 | /* | ||
628 | * Requests forwarding for X11 connections, with authentication spoofing. | ||
629 | * This should be called in the client only. | ||
630 | */ | ||
631 | void x11_request_forwarding_with_spoofing(const char *proto, const char *data); | ||
632 | |||
633 | /* Sends a message to the server to request authentication fd forwarding. */ | ||
634 | void auth_request_forwarding(void); | ||
635 | |||
636 | /* | ||
637 | * Returns the name of the forwarded authentication socket. Returns NULL if | ||
638 | * there is no forwarded authentication socket. The returned value points to | ||
639 | * a static buffer. | ||
640 | */ | ||
641 | char *auth_get_socket_name(void); | ||
642 | |||
643 | /* | ||
644 | * This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. | ||
645 | * This starts forwarding authentication requests. | ||
646 | */ | ||
647 | void auth_input_request_forwarding(struct passwd * pw); | ||
648 | |||
649 | /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ | ||
650 | void auth_input_open_request(void); | ||
651 | |||
652 | /* | ||
653 | * Returns true if the given string matches the pattern (which may contain ? | ||
654 | * and * as wildcards), and zero if it does not match. | ||
655 | */ | ||
656 | int match_pattern(const char *s, const char *pattern); | ||
657 | |||
658 | /* | 489 | /* |
659 | * Expands tildes in the file name. Returns data allocated by xmalloc. | 490 | * Expands tildes in the file name. Returns data allocated by xmalloc. |
660 | * Warning: this calls getpw*. | 491 | * Warning: this calls getpw*. |
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * draft-ietf-secsh-architecture-04.txt | ||
3 | * | ||
4 | * Transport layer protocol: | ||
5 | * | ||
6 | * 1-19 Transport layer generic (e.g. disconnect, ignore, debug, | ||
7 | * etc) | ||
8 | * 20-29 Algorithm negotiation | ||
9 | * 30-49 Key exchange method specific (numbers can be reused for | ||
10 | * different authentication methods) | ||
11 | * | ||
12 | * User authentication protocol: | ||
13 | * | ||
14 | * 50-59 User authentication generic | ||
15 | * 60-79 User authentication method specific (numbers can be reused | ||
16 | * for different authentication methods) | ||
17 | * | ||
18 | * Connection protocol: | ||
19 | * | ||
20 | * 80-89 Connection protocol generic | ||
21 | * 90-127 Channel related messages | ||
22 | * | ||
23 | * Reserved for client protocols: | ||
24 | * | ||
25 | * 128-191 Reserved | ||
26 | * | ||
27 | * Local extensions: | ||
28 | * | ||
29 | * 192-255 Local extensions | ||
30 | */ | ||
31 | |||
32 | /* transport layer: generic */ | ||
33 | |||
34 | #define SSH2_MSG_DISCONNECT 1 | ||
35 | #define SSH2_MSG_IGNORE 2 | ||
36 | #define SSH2_MSG_UNIMPLEMENTED 3 | ||
37 | #define SSH2_MSG_DEBUG 4 | ||
38 | #define SSH2_MSG_SERVICE_REQUEST 5 | ||
39 | #define SSH2_MSG_SERVICE_ACCEPT 6 | ||
40 | |||
41 | /* transport layer: alg negotiation */ | ||
42 | |||
43 | #define SSH2_MSG_KEXINIT 20 | ||
44 | #define SSH2_MSG_NEWKEYS 21 | ||
45 | |||
46 | /* transport layer: kex specific messages, can be reused */ | ||
47 | |||
48 | #define SSH2_MSG_KEXDH_INIT 30 | ||
49 | #define SSH2_MSG_KEXDH_REPLY 31 | ||
50 | |||
51 | /* user authentication: generic */ | ||
52 | |||
53 | #define SSH2_MSG_USERAUTH_REQUEST 50 | ||
54 | #define SSH2_MSG_USERAUTH_FAILURE 51 | ||
55 | #define SSH2_MSG_USERAUTH_SUCCESS 52 | ||
56 | #define SSH2_MSG_USERAUTH_BANNER 53 | ||
57 | |||
58 | /* user authentication: method specific, can be reused */ | ||
59 | |||
60 | #define SSH2_MSG_USERAUTH_PK_OK 60 | ||
61 | #define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 | ||
62 | #define SSH2_MSG_USERAUTH_INFO_REQUEST 60 | ||
63 | #define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 | ||
64 | |||
65 | /* connection protocol: generic */ | ||
66 | |||
67 | #define SSH2_MSG_GLOBAL_REQUEST 80 | ||
68 | #define SSH2_MSG_REQUEST_SUCCESS 81 | ||
69 | #define SSH2_MSG_REQUEST_FAILURE 82 | ||
70 | |||
71 | /* channel related messages */ | ||
72 | |||
73 | #define SSH2_MSG_CHANNEL_OPEN 90 | ||
74 | #define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 | ||
75 | #define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 | ||
76 | #define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 | ||
77 | #define SSH2_MSG_CHANNEL_DATA 94 | ||
78 | #define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 | ||
79 | #define SSH2_MSG_CHANNEL_EOF 96 | ||
80 | #define SSH2_MSG_CHANNEL_CLOSE 97 | ||
81 | #define SSH2_MSG_CHANNEL_REQUEST 98 | ||
82 | #define SSH2_MSG_CHANNEL_SUCCESS 99 | ||
83 | #define SSH2_MSG_CHANNEL_FAILURE 100 | ||
84 | |||
85 | /* disconnect reason code */ | ||
86 | |||
87 | #define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 | ||
88 | #define SSH2_DISCONNECT_PROTOCOL_ERROR 2 | ||
89 | #define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3 | ||
90 | #define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4 | ||
91 | #define SSH2_DISCONNECT_MAC_ERROR 5 | ||
92 | #define SSH2_DISCONNECT_COMPRESSION_ERROR 6 | ||
93 | #define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7 | ||
94 | #define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 | ||
95 | #define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 | ||
96 | #define SSH2_DISCONNECT_CONNECTION_LOST 10 | ||
97 | #define SSH2_DISCONNECT_BY_APPLICATION 11 | ||
98 | |||
99 | /* misc */ | ||
100 | |||
101 | #define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1 | ||
102 | #define SSH2_OPEN_CONNECT_FAILED 2 | ||
103 | #define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3 | ||
104 | #define SSH2_OPEN_RESOURCE_SHORTAGE 4 | ||
105 | |||
106 | #define SSH2_EXTENDED_DATA_STDERR 1 | ||
@@ -9,7 +9,7 @@ | |||
9 | .\" | 9 | .\" |
10 | .\" Created: Sat Apr 22 21:55:14 1995 ylo | 10 | .\" Created: Sat Apr 22 21:55:14 1995 ylo |
11 | .\" | 11 | .\" |
12 | .\" $Id: sshd.8,v 1.15 2000/03/26 03:04:55 damien Exp $ | 12 | .\" $Id: sshd.8,v 1.16 2000/04/01 01:09:27 damien Exp $ |
13 | .\" | 13 | .\" |
14 | .Dd September 25, 1999 | 14 | .Dd September 25, 1999 |
15 | .Dt SSHD 8 | 15 | .Dt SSHD 8 |
@@ -69,7 +69,7 @@ random number as a session key which is used to encrypt all further | |||
69 | communications in the session. | 69 | communications in the session. |
70 | The rest of the session is encrypted | 70 | The rest of the session is encrypted |
71 | using a conventional cipher, currently Blowfish and 3DES, with 3DES | 71 | using a conventional cipher, currently Blowfish and 3DES, with 3DES |
72 | being is used by default. | 72 | being used by default. |
73 | The client selects the encryption algorithm | 73 | The client selects the encryption algorithm |
74 | to use from those offered by the server. | 74 | to use from those offered by the server. |
75 | .Pp | 75 | .Pp |
@@ -877,11 +877,11 @@ The libraries described in | |||
877 | .Xr ssl 8 | 877 | .Xr ssl 8 |
878 | are required for proper operation. | 878 | are required for proper operation. |
879 | .Sh SEE ALSO | 879 | .Sh SEE ALSO |
880 | .Xr rlogin 1 , | ||
881 | .Xr rsh 1 , | ||
882 | .Xr scp 1 , | 880 | .Xr scp 1 , |
883 | .Xr ssh 1 , | 881 | .Xr ssh 1 , |
884 | .Xr ssh-add 1 , | 882 | .Xr ssh-add 1 , |
885 | .Xr ssh-agent 1 , | 883 | .Xr ssh-agent 1 , |
886 | .Xr ssh-keygen 1 , | 884 | .Xr ssh-keygen 1 , |
887 | .Xr ssl 8 | 885 | .Xr ssl 8 , |
886 | .Xr rlogin 1 , | ||
887 | .Xr rsh 1 | ||
@@ -11,19 +11,37 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include "includes.h" | 13 | #include "includes.h" |
14 | RCSID("$OpenBSD: sshd.c,v 1.94 2000/03/23 22:15:34 markus Exp $"); | 14 | RCSID("$OpenBSD: sshd.c,v 1.96 2000/03/28 21:15:45 markus Exp $"); |
15 | 15 | ||
16 | #include "xmalloc.h" | 16 | #include "xmalloc.h" |
17 | #include "rsa.h" | 17 | #include "rsa.h" |
18 | #include "ssh.h" | 18 | #include "ssh.h" |
19 | #include "pty.h" | 19 | #include "pty.h" |
20 | #include "packet.h" | 20 | #include "packet.h" |
21 | #include "buffer.h" | ||
22 | #include "cipher.h" | 21 | #include "cipher.h" |
23 | #include "mpaux.h" | 22 | #include "mpaux.h" |
24 | #include "servconf.h" | 23 | #include "servconf.h" |
25 | #include "uidswap.h" | 24 | #include "uidswap.h" |
26 | #include "compat.h" | 25 | #include "compat.h" |
26 | #include "buffer.h" | ||
27 | |||
28 | #ifdef HAVE_OPENSSL | ||
29 | # include <openssl/dh.h> | ||
30 | # include <openssl/bn.h> | ||
31 | # include <openssl/hmac.h> | ||
32 | # include <openssl/dsa.h> | ||
33 | # include <openssl/rsa.h> | ||
34 | #endif | ||
35 | #ifdef HAVE_SSL | ||
36 | # include <ssl/dh.h> | ||
37 | # include <ssl/bn.h> | ||
38 | # include <ssl/hmac.h> | ||
39 | # include <ssl/dsa.h> | ||
40 | # include <ssl/rsa.h> | ||
41 | #endif | ||
42 | #include "key.h" | ||
43 | |||
44 | #include "auth.h" | ||
27 | 45 | ||
28 | #ifdef LIBWRAP | 46 | #ifdef LIBWRAP |
29 | #include <tcpd.h> | 47 | #include <tcpd.h> |
@@ -36,9 +54,6 @@ int deny_severity = LOG_WARNING; | |||
36 | #define O_NOCTTY 0 | 54 | #define O_NOCTTY 0 |
37 | #endif | 55 | #endif |
38 | 56 | ||
39 | /* Local Xauthority file. */ | ||
40 | static char *xauthfile = NULL; | ||
41 | |||
42 | /* Server configuration options. */ | 57 | /* Server configuration options. */ |
43 | ServerOptions options; | 58 | ServerOptions options; |
44 | 59 | ||
@@ -88,21 +103,7 @@ int num_listen_socks = 0; | |||
88 | * sshd will skip the version-number exchange | 103 | * sshd will skip the version-number exchange |
89 | */ | 104 | */ |
90 | char *client_version_string = NULL; | 105 | char *client_version_string = NULL; |
91 | 106 | char *server_version_string = NULL; | |
92 | /* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */ | ||
93 | int no_port_forwarding_flag = 0; | ||
94 | int no_agent_forwarding_flag = 0; | ||
95 | int no_x11_forwarding_flag = 0; | ||
96 | int no_pty_flag = 0; | ||
97 | |||
98 | /* RSA authentication "command=" option. */ | ||
99 | char *forced_command = NULL; | ||
100 | |||
101 | /* RSA authentication "environment=" options. */ | ||
102 | struct envstring *custom_environment = NULL; | ||
103 | |||
104 | /* Session id for the current session. */ | ||
105 | unsigned char session_id[16]; | ||
106 | 107 | ||
107 | /* | 108 | /* |
108 | * Any really sensitive data in the application is contained in this | 109 | * Any really sensitive data in the application is contained in this |
@@ -130,43 +131,11 @@ int received_sighup = 0; | |||
130 | the private key. */ | 131 | the private key. */ |
131 | RSA *public_key; | 132 | RSA *public_key; |
132 | 133 | ||
133 | /* Prototypes for various functions defined later in this file. */ | 134 | /* session identifier, used by RSA-auth */ |
134 | void do_ssh_kex(); | 135 | unsigned char session_id[16]; |
135 | void do_authentication(); | ||
136 | void do_authloop(struct passwd * pw); | ||
137 | void do_fake_authloop(char *user); | ||
138 | void do_authenticated(struct passwd * pw); | ||
139 | void do_exec_pty(const char *command, int ptyfd, int ttyfd, | ||
140 | const char *ttyname, struct passwd * pw, const char *term, | ||
141 | const char *display, const char *auth_proto, | ||
142 | const char *auth_data); | ||
143 | void do_exec_no_pty(const char *command, struct passwd * pw, | ||
144 | const char *display, const char *auth_proto, | ||
145 | const char *auth_data); | ||
146 | void do_child(const char *command, struct passwd * pw, const char *term, | ||
147 | const char *display, const char *auth_proto, | ||
148 | const char *auth_data, const char *ttyname); | ||
149 | 136 | ||
150 | /* | 137 | /* Prototypes for various functions defined later in this file. */ |
151 | * Remove local Xauthority file. | 138 | void do_ssh1_kex(); |
152 | */ | ||
153 | void | ||
154 | xauthfile_cleanup_proc(void *ignore) | ||
155 | { | ||
156 | debug("xauthfile_cleanup_proc called"); | ||
157 | |||
158 | if (xauthfile != NULL) { | ||
159 | char *p; | ||
160 | unlink(xauthfile); | ||
161 | p = strrchr(xauthfile, '/'); | ||
162 | if (p != NULL) { | ||
163 | *p = '\0'; | ||
164 | rmdir(xauthfile); | ||
165 | } | ||
166 | xfree(xauthfile); | ||
167 | xauthfile = NULL; | ||
168 | } | ||
169 | } | ||
170 | 139 | ||
171 | /* | 140 | /* |
172 | * Close all listening sockets | 141 | * Close all listening sockets |
@@ -250,35 +219,6 @@ grace_alarm_handler(int sig) | |||
250 | } | 219 | } |
251 | 220 | ||
252 | /* | 221 | /* |
253 | * convert ssh auth msg type into description | ||
254 | */ | ||
255 | char * | ||
256 | get_authname(int type) | ||
257 | { | ||
258 | static char buf[1024]; | ||
259 | switch (type) { | ||
260 | case SSH_CMSG_AUTH_PASSWORD: | ||
261 | return "password"; | ||
262 | case SSH_CMSG_AUTH_RSA: | ||
263 | return "rsa"; | ||
264 | case SSH_CMSG_AUTH_RHOSTS_RSA: | ||
265 | return "rhosts-rsa"; | ||
266 | case SSH_CMSG_AUTH_RHOSTS: | ||
267 | return "rhosts"; | ||
268 | #ifdef KRB4 | ||
269 | case SSH_CMSG_AUTH_KERBEROS: | ||
270 | return "kerberos"; | ||
271 | #endif | ||
272 | #ifdef SKEY | ||
273 | case SSH_CMSG_AUTH_TIS_RESPONSE: | ||
274 | return "s/key"; | ||
275 | #endif | ||
276 | } | ||
277 | snprintf(buf, sizeof buf, "bad-auth-msg-%d", type); | ||
278 | return buf; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Signal handler for the key regeneration alarm. Note that this | 222 | * Signal handler for the key regeneration alarm. Note that this |
283 | * alarm only occurs in the daemon waiting for connections, and it does not | 223 | * alarm only occurs in the daemon waiting for connections, and it does not |
284 | * do anything with the private key or random state before forking. | 224 | * do anything with the private key or random state before forking. |
@@ -315,6 +255,88 @@ key_regeneration_alarm(int sig) | |||
315 | errno = save_errno; | 255 | errno = save_errno; |
316 | } | 256 | } |
317 | 257 | ||
258 | void | ||
259 | sshd_exchange_identification(int sock_in, int sock_out) | ||
260 | { | ||
261 | int i; | ||
262 | int remote_major, remote_minor; | ||
263 | char *s; | ||
264 | char buf[256]; /* Must not be larger than remote_version. */ | ||
265 | char remote_version[256]; /* Must be at least as big as buf. */ | ||
266 | |||
267 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", | ||
268 | PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); | ||
269 | server_version_string = xstrdup(buf); | ||
270 | |||
271 | if (client_version_string == NULL) { | ||
272 | /* Send our protocol version identification. */ | ||
273 | if (atomicio(write, sock_out, server_version_string, strlen(server_version_string)) | ||
274 | != strlen(server_version_string)) { | ||
275 | log("Could not write ident string to %s.", get_remote_ipaddr()); | ||
276 | fatal_cleanup(); | ||
277 | } | ||
278 | |||
279 | /* Read other side\'s version identification. */ | ||
280 | for (i = 0; i < sizeof(buf) - 1; i++) { | ||
281 | if (read(sock_in, &buf[i], 1) != 1) { | ||
282 | log("Did not receive ident string from %s.", get_remote_ipaddr()); | ||
283 | fatal_cleanup(); | ||
284 | } | ||
285 | if (buf[i] == '\r') { | ||
286 | buf[i] = '\n'; | ||
287 | buf[i + 1] = 0; | ||
288 | continue; | ||
289 | /*break; XXX eat \r */ | ||
290 | } | ||
291 | if (buf[i] == '\n') { | ||
292 | /* buf[i] == '\n' */ | ||
293 | buf[i + 1] = 0; | ||
294 | break; | ||
295 | } | ||
296 | } | ||
297 | buf[sizeof(buf) - 1] = 0; | ||
298 | client_version_string = xstrdup(buf); | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * Check that the versions match. In future this might accept | ||
303 | * several versions and set appropriate flags to handle them. | ||
304 | */ | ||
305 | if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n", | ||
306 | &remote_major, &remote_minor, remote_version) != 3) { | ||
307 | s = "Protocol mismatch.\n"; | ||
308 | (void) atomicio(write, sock_out, s, strlen(s)); | ||
309 | close(sock_in); | ||
310 | close(sock_out); | ||
311 | log("Bad protocol version identification '%.100s' from %s", | ||
312 | client_version_string, get_remote_ipaddr()); | ||
313 | fatal_cleanup(); | ||
314 | } | ||
315 | debug("Client protocol version %d.%d; client software version %.100s", | ||
316 | remote_major, remote_minor, remote_version); | ||
317 | |||
318 | switch(remote_major) { | ||
319 | case 1: | ||
320 | if (remote_minor < 3) { | ||
321 | packet_disconnect("Your ssh version is too old and" | ||
322 | "is no longer supported. Please install a newer version."); | ||
323 | } else if (remote_minor == 3) { | ||
324 | /* note that this disables agent-forwarding */ | ||
325 | enable_compat13(); | ||
326 | } | ||
327 | break; | ||
328 | default: | ||
329 | s = "Protocol major versions differ.\n"; | ||
330 | (void) atomicio(write, sock_out, s, strlen(s)); | ||
331 | close(sock_in); | ||
332 | close(sock_out); | ||
333 | log("Protocol major versions differ for %s: %d vs. %d", | ||
334 | get_remote_ipaddr(), PROTOCOL_MAJOR, remote_major); | ||
335 | fatal_cleanup(); | ||
336 | break; | ||
337 | } | ||
338 | } | ||
339 | |||
318 | /* | 340 | /* |
319 | * Main program for the daemon. | 341 | * Main program for the daemon. |
320 | */ | 342 | */ |
@@ -325,12 +347,9 @@ main(int ac, char **av) | |||
325 | extern int optind; | 347 | extern int optind; |
326 | int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, pid, on = 1; | 348 | int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, pid, on = 1; |
327 | socklen_t fromlen; | 349 | socklen_t fromlen; |
328 | int remote_major, remote_minor; | ||
329 | int silentrsa = 0; | 350 | int silentrsa = 0; |
330 | fd_set *fdset; | 351 | fd_set *fdset; |
331 | struct sockaddr_storage from; | 352 | struct sockaddr_storage from; |
332 | char buf[100]; /* Must not be larger than remote_version. */ | ||
333 | char remote_version[100]; /* Must be at least as big as buf. */ | ||
334 | const char *remote_ip; | 353 | const char *remote_ip; |
335 | int remote_port; | 354 | int remote_port; |
336 | char *comment; | 355 | char *comment; |
@@ -794,73 +813,7 @@ main(int ac, char **av) | |||
794 | if (!debug_flag) | 813 | if (!debug_flag) |
795 | alarm(options.login_grace_time); | 814 | alarm(options.login_grace_time); |
796 | 815 | ||
797 | if (client_version_string != NULL) { | 816 | sshd_exchange_identification(sock_in, sock_out); |
798 | /* we are exec'ed by sshd2, so skip exchange of protocol version */ | ||
799 | strlcpy(buf, client_version_string, sizeof(buf)); | ||
800 | } else { | ||
801 | /* Send our protocol version identification. */ | ||
802 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", | ||
803 | PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); | ||
804 | if (atomicio(write, sock_out, buf, strlen(buf)) != strlen(buf)) { | ||
805 | log("Could not write ident string to %s.", remote_ip); | ||
806 | fatal_cleanup(); | ||
807 | } | ||
808 | |||
809 | /* Read other side\'s version identification. */ | ||
810 | for (i = 0; i < sizeof(buf) - 1; i++) { | ||
811 | if (read(sock_in, &buf[i], 1) != 1) { | ||
812 | log("Did not receive ident string from %s.", remote_ip); | ||
813 | fatal_cleanup(); | ||
814 | } | ||
815 | if (buf[i] == '\r') { | ||
816 | buf[i] = '\n'; | ||
817 | buf[i + 1] = 0; | ||
818 | break; | ||
819 | } | ||
820 | if (buf[i] == '\n') { | ||
821 | /* buf[i] == '\n' */ | ||
822 | buf[i + 1] = 0; | ||
823 | break; | ||
824 | } | ||
825 | } | ||
826 | buf[sizeof(buf) - 1] = 0; | ||
827 | } | ||
828 | |||
829 | /* | ||
830 | * Check that the versions match. In future this might accept | ||
831 | * several versions and set appropriate flags to handle them. | ||
832 | */ | ||
833 | if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, | ||
834 | remote_version) != 3) { | ||
835 | char *s = "Protocol mismatch.\n"; | ||
836 | |||
837 | (void) atomicio(write, sock_out, s, strlen(s)); | ||
838 | close(sock_in); | ||
839 | close(sock_out); | ||
840 | log("Bad protocol version identification '%.100s' from %s", | ||
841 | buf, remote_ip); | ||
842 | fatal_cleanup(); | ||
843 | } | ||
844 | debug("Client protocol version %d.%d; client software version %.100s", | ||
845 | remote_major, remote_minor, remote_version); | ||
846 | if (remote_major != PROTOCOL_MAJOR) { | ||
847 | char *s = "Protocol major versions differ.\n"; | ||
848 | |||
849 | (void) atomicio(write, sock_out, s, strlen(s)); | ||
850 | close(sock_in); | ||
851 | close(sock_out); | ||
852 | log("Protocol major versions differ for %s: %d vs. %d", | ||
853 | remote_ip, PROTOCOL_MAJOR, remote_major); | ||
854 | fatal_cleanup(); | ||
855 | } | ||
856 | /* Check that the client has sufficiently high software version. */ | ||
857 | if (remote_major == 1 && remote_minor < 3) | ||
858 | packet_disconnect("Your ssh version is too old and is no longer supported. Please install a newer version."); | ||
859 | |||
860 | if (remote_major == 1 && remote_minor == 3) { | ||
861 | /* note that this disables agent-forwarding */ | ||
862 | enable_compat13(); | ||
863 | } | ||
864 | /* | 817 | /* |
865 | * Check that the connection comes from a privileged port. Rhosts- | 818 | * Check that the connection comes from a privileged port. Rhosts- |
866 | * and Rhosts-RSA-Authentication only make sense from priviledged | 819 | * and Rhosts-RSA-Authentication only make sense from priviledged |
@@ -884,8 +837,7 @@ main(int ac, char **av) | |||
884 | packet_set_nonblocking(); | 837 | packet_set_nonblocking(); |
885 | 838 | ||
886 | /* perform the key exchange */ | 839 | /* perform the key exchange */ |
887 | do_ssh_kex(); | 840 | do_ssh1_kex(); |
888 | |||
889 | /* authenticate user and start session */ | 841 | /* authenticate user and start session */ |
890 | do_authentication(); | 842 | do_authentication(); |
891 | 843 | ||
@@ -895,10 +847,6 @@ main(int ac, char **av) | |||
895 | (void) dest_tkt(); | 847 | (void) dest_tkt(); |
896 | #endif /* KRB4 */ | 848 | #endif /* KRB4 */ |
897 | 849 | ||
898 | /* Cleanup user's local Xauthority file. */ | ||
899 | if (xauthfile) | ||
900 | xauthfile_cleanup_proc(NULL); | ||
901 | |||
902 | /* The connection has been terminated. */ | 850 | /* The connection has been terminated. */ |
903 | verbose("Closing connection to %.100s", remote_ip); | 851 | verbose("Closing connection to %.100s", remote_ip); |
904 | 852 | ||
@@ -914,7 +862,7 @@ main(int ac, char **av) | |||
914 | * SSH1 key exchange | 862 | * SSH1 key exchange |
915 | */ | 863 | */ |
916 | void | 864 | void |
917 | do_ssh_kex() | 865 | do_ssh1_kex() |
918 | { | 866 | { |
919 | int i, len; | 867 | int i, len; |
920 | int plen, slen; | 868 | int plen, slen; |
@@ -1101,1586 +1049,3 @@ do_ssh_kex() | |||
1101 | packet_send(); | 1049 | packet_send(); |
1102 | packet_write_wait(); | 1050 | packet_write_wait(); |
1103 | } | 1051 | } |
1104 | |||
1105 | |||
1106 | /* | ||
1107 | * Check if the user is allowed to log in via ssh. If user is listed in | ||
1108 | * DenyUsers or user's primary group is listed in DenyGroups, false will | ||
1109 | * be returned. If AllowUsers isn't empty and user isn't listed there, or | ||
1110 | * if AllowGroups isn't empty and user isn't listed there, false will be | ||
1111 | * returned. | ||
1112 | * If the user's shell is not executable, false will be returned. | ||
1113 | * Otherwise true is returned. | ||
1114 | */ | ||
1115 | static int | ||
1116 | allowed_user(struct passwd * pw) | ||
1117 | { | ||
1118 | struct stat st; | ||
1119 | struct group *grp; | ||
1120 | int i; | ||
1121 | #ifdef WITH_AIXAUTHENTICATE | ||
1122 | char *loginmsg; | ||
1123 | #endif /* WITH_AIXAUTHENTICATE */ | ||
1124 | |||
1125 | /* Shouldn't be called if pw is NULL, but better safe than sorry... */ | ||
1126 | if (!pw) | ||
1127 | return 0; | ||
1128 | |||
1129 | /* deny if shell does not exists or is not executable */ | ||
1130 | if (stat(pw->pw_shell, &st) != 0) | ||
1131 | return 0; | ||
1132 | if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) | ||
1133 | return 0; | ||
1134 | |||
1135 | /* Return false if user is listed in DenyUsers */ | ||
1136 | if (options.num_deny_users > 0) { | ||
1137 | if (!pw->pw_name) | ||
1138 | return 0; | ||
1139 | for (i = 0; i < options.num_deny_users; i++) | ||
1140 | if (match_pattern(pw->pw_name, options.deny_users[i])) | ||
1141 | return 0; | ||
1142 | } | ||
1143 | /* Return false if AllowUsers isn't empty and user isn't listed there */ | ||
1144 | if (options.num_allow_users > 0) { | ||
1145 | if (!pw->pw_name) | ||
1146 | return 0; | ||
1147 | for (i = 0; i < options.num_allow_users; i++) | ||
1148 | if (match_pattern(pw->pw_name, options.allow_users[i])) | ||
1149 | break; | ||
1150 | /* i < options.num_allow_users iff we break for loop */ | ||
1151 | if (i >= options.num_allow_users) | ||
1152 | return 0; | ||
1153 | } | ||
1154 | /* Get the primary group name if we need it. Return false if it fails */ | ||
1155 | if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { | ||
1156 | grp = getgrgid(pw->pw_gid); | ||
1157 | if (!grp) | ||
1158 | return 0; | ||
1159 | |||
1160 | /* Return false if user's group is listed in DenyGroups */ | ||
1161 | if (options.num_deny_groups > 0) { | ||
1162 | if (!grp->gr_name) | ||
1163 | return 0; | ||
1164 | for (i = 0; i < options.num_deny_groups; i++) | ||
1165 | if (match_pattern(grp->gr_name, options.deny_groups[i])) | ||
1166 | return 0; | ||
1167 | } | ||
1168 | /* | ||
1169 | * Return false if AllowGroups isn't empty and user's group | ||
1170 | * isn't listed there | ||
1171 | */ | ||
1172 | if (options.num_allow_groups > 0) { | ||
1173 | if (!grp->gr_name) | ||
1174 | return 0; | ||
1175 | for (i = 0; i < options.num_allow_groups; i++) | ||
1176 | if (match_pattern(grp->gr_name, options.allow_groups[i])) | ||
1177 | break; | ||
1178 | /* i < options.num_allow_groups iff we break for | ||
1179 | loop */ | ||
1180 | if (i >= options.num_allow_groups) | ||
1181 | return 0; | ||
1182 | } | ||
1183 | } | ||
1184 | |||
1185 | #ifdef WITH_AIXAUTHENTICATE | ||
1186 | if (loginrestrictions(pw->pw_name,S_LOGIN,NULL,&loginmsg) != 0) | ||
1187 | return 0; | ||
1188 | #endif /* WITH_AIXAUTHENTICATE */ | ||
1189 | |||
1190 | /* We found no reason not to let this user try to log on... */ | ||
1191 | return 1; | ||
1192 | } | ||
1193 | |||
1194 | /* | ||
1195 | * Performs authentication of an incoming connection. Session key has already | ||
1196 | * been exchanged and encryption is enabled. | ||
1197 | */ | ||
1198 | void | ||
1199 | do_authentication() | ||
1200 | { | ||
1201 | struct passwd *pw, pwcopy; | ||
1202 | int plen; | ||
1203 | unsigned int ulen; | ||
1204 | char *user; | ||
1205 | |||
1206 | /* Get the name of the user that we wish to log in as. */ | ||
1207 | packet_read_expect(&plen, SSH_CMSG_USER); | ||
1208 | |||
1209 | /* Get the user name. */ | ||
1210 | user = packet_get_string(&ulen); | ||
1211 | packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER); | ||
1212 | |||
1213 | setproctitle("%s", user); | ||
1214 | |||
1215 | #ifdef WITH_AIXAUTHENTICATE | ||
1216 | char *loginmsg; | ||
1217 | #endif /* WITH_AIXAUTHENTICATE */ | ||
1218 | |||
1219 | #ifdef AFS | ||
1220 | /* If machine has AFS, set process authentication group. */ | ||
1221 | if (k_hasafs()) { | ||
1222 | k_setpag(); | ||
1223 | k_unlog(); | ||
1224 | } | ||
1225 | #endif /* AFS */ | ||
1226 | |||
1227 | /* Verify that the user is a valid user. */ | ||
1228 | pw = getpwnam(user); | ||
1229 | if (!pw || !allowed_user(pw)) | ||
1230 | do_fake_authloop(user); | ||
1231 | xfree(user); | ||
1232 | |||
1233 | /* Take a copy of the returned structure. */ | ||
1234 | memset(&pwcopy, 0, sizeof(pwcopy)); | ||
1235 | pwcopy.pw_name = xstrdup(pw->pw_name); | ||
1236 | pwcopy.pw_passwd = xstrdup(pw->pw_passwd); | ||
1237 | pwcopy.pw_uid = pw->pw_uid; | ||
1238 | pwcopy.pw_gid = pw->pw_gid; | ||
1239 | pwcopy.pw_dir = xstrdup(pw->pw_dir); | ||
1240 | pwcopy.pw_shell = xstrdup(pw->pw_shell); | ||
1241 | pw = &pwcopy; | ||
1242 | |||
1243 | #ifdef USE_PAM | ||
1244 | start_pam(pw); | ||
1245 | #endif | ||
1246 | |||
1247 | /* | ||
1248 | * If we are not running as root, the user must have the same uid as | ||
1249 | * the server. | ||
1250 | */ | ||
1251 | if (getuid() != 0 && pw->pw_uid != getuid()) | ||
1252 | packet_disconnect("Cannot change user when server not running as root."); | ||
1253 | |||
1254 | debug("Attempting authentication for %.100s.", pw->pw_name); | ||
1255 | |||
1256 | /* If the user has no password, accept authentication immediately. */ | ||
1257 | if (options.password_authentication && | ||
1258 | #ifdef KRB4 | ||
1259 | (!options.kerberos_authentication || options.kerberos_or_local_passwd) && | ||
1260 | #endif /* KRB4 */ | ||
1261 | #ifdef USE_PAM | ||
1262 | auth_pam_password(pw, "")) { | ||
1263 | #else /* USE_PAM */ | ||
1264 | auth_password(pw, "")) { | ||
1265 | #endif /* USE_PAM */ | ||
1266 | /* Authentication with empty password succeeded. */ | ||
1267 | log("Login for user %s from %.100s, accepted without authentication.", | ||
1268 | pw->pw_name, get_remote_ipaddr()); | ||
1269 | } else { | ||
1270 | /* Loop until the user has been authenticated or the | ||
1271 | connection is closed, do_authloop() returns only if | ||
1272 | authentication is successfull */ | ||
1273 | do_authloop(pw); | ||
1274 | } | ||
1275 | |||
1276 | /* The user has been authenticated and accepted. */ | ||
1277 | #ifdef WITH_AIXAUTHENTICATE | ||
1278 | loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg); | ||
1279 | #endif /* WITH_AIXAUTHENTICATE */ | ||
1280 | packet_start(SSH_SMSG_SUCCESS); | ||
1281 | packet_send(); | ||
1282 | packet_write_wait(); | ||
1283 | |||
1284 | /* Perform session preparation. */ | ||
1285 | do_authenticated(pw); | ||
1286 | } | ||
1287 | |||
1288 | #define AUTH_FAIL_MAX 6 | ||
1289 | #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) | ||
1290 | #define AUTH_FAIL_MSG "Too many authentication failures for %.100s" | ||
1291 | |||
1292 | /* | ||
1293 | * read packets and try to authenticate local user *pw. | ||
1294 | * return if authentication is successfull | ||
1295 | */ | ||
1296 | void | ||
1297 | do_authloop(struct passwd * pw) | ||
1298 | { | ||
1299 | int attempt = 0; | ||
1300 | unsigned int bits; | ||
1301 | RSA *client_host_key; | ||
1302 | BIGNUM *n; | ||
1303 | char *client_user = NULL, *password = NULL; | ||
1304 | char user[1024]; | ||
1305 | unsigned int dlen; | ||
1306 | int plen, nlen, elen; | ||
1307 | unsigned int ulen; | ||
1308 | int type = 0; | ||
1309 | void (*authlog) (const char *fmt,...) = verbose; | ||
1310 | |||
1311 | /* Indicate that authentication is needed. */ | ||
1312 | packet_start(SSH_SMSG_FAILURE); | ||
1313 | packet_send(); | ||
1314 | packet_write_wait(); | ||
1315 | |||
1316 | for (attempt = 1;; attempt++) { | ||
1317 | int authenticated = 0; | ||
1318 | strlcpy(user, "", sizeof user); | ||
1319 | |||
1320 | /* Get a packet from the client. */ | ||
1321 | type = packet_read(&plen); | ||
1322 | |||
1323 | /* Process the packet. */ | ||
1324 | switch (type) { | ||
1325 | #ifdef AFS | ||
1326 | case SSH_CMSG_HAVE_KERBEROS_TGT: | ||
1327 | if (!options.kerberos_tgt_passing) { | ||
1328 | /* packet_get_all(); */ | ||
1329 | verbose("Kerberos tgt passing disabled."); | ||
1330 | break; | ||
1331 | } else { | ||
1332 | /* Accept Kerberos tgt. */ | ||
1333 | char *tgt = packet_get_string(&dlen); | ||
1334 | packet_integrity_check(plen, 4 + dlen, type); | ||
1335 | if (!auth_kerberos_tgt(pw, tgt)) | ||
1336 | verbose("Kerberos tgt REFUSED for %s", pw->pw_name); | ||
1337 | xfree(tgt); | ||
1338 | } | ||
1339 | continue; | ||
1340 | |||
1341 | case SSH_CMSG_HAVE_AFS_TOKEN: | ||
1342 | if (!options.afs_token_passing || !k_hasafs()) { | ||
1343 | /* packet_get_all(); */ | ||
1344 | verbose("AFS token passing disabled."); | ||
1345 | break; | ||
1346 | } else { | ||
1347 | /* Accept AFS token. */ | ||
1348 | char *token_string = packet_get_string(&dlen); | ||
1349 | packet_integrity_check(plen, 4 + dlen, type); | ||
1350 | if (!auth_afs_token(pw, token_string)) | ||
1351 | verbose("AFS token REFUSED for %s", pw->pw_name); | ||
1352 | xfree(token_string); | ||
1353 | } | ||
1354 | continue; | ||
1355 | #endif /* AFS */ | ||
1356 | #ifdef KRB4 | ||
1357 | case SSH_CMSG_AUTH_KERBEROS: | ||
1358 | if (!options.kerberos_authentication) { | ||
1359 | /* packet_get_all(); */ | ||
1360 | verbose("Kerberos authentication disabled."); | ||
1361 | break; | ||
1362 | } else { | ||
1363 | /* Try Kerberos v4 authentication. */ | ||
1364 | KTEXT_ST auth; | ||
1365 | char *tkt_user = NULL; | ||
1366 | char *kdata = packet_get_string((unsigned int *) &auth.length); | ||
1367 | packet_integrity_check(plen, 4 + auth.length, type); | ||
1368 | |||
1369 | if (auth.length < MAX_KTXT_LEN) | ||
1370 | memcpy(auth.dat, kdata, auth.length); | ||
1371 | xfree(kdata); | ||
1372 | |||
1373 | authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user); | ||
1374 | |||
1375 | if (authenticated) { | ||
1376 | snprintf(user, sizeof user, " tktuser %s", tkt_user); | ||
1377 | xfree(tkt_user); | ||
1378 | } | ||
1379 | } | ||
1380 | break; | ||
1381 | #endif /* KRB4 */ | ||
1382 | |||
1383 | case SSH_CMSG_AUTH_RHOSTS: | ||
1384 | if (!options.rhosts_authentication) { | ||
1385 | verbose("Rhosts authentication disabled."); | ||
1386 | break; | ||
1387 | } | ||
1388 | /* | ||
1389 | * Get client user name. Note that we just have to | ||
1390 | * trust the client; this is one reason why rhosts | ||
1391 | * authentication is insecure. (Another is | ||
1392 | * IP-spoofing on a local network.) | ||
1393 | */ | ||
1394 | client_user = packet_get_string(&ulen); | ||
1395 | packet_integrity_check(plen, 4 + ulen, type); | ||
1396 | |||
1397 | /* Try to authenticate using /etc/hosts.equiv and | ||
1398 | .rhosts. */ | ||
1399 | authenticated = auth_rhosts(pw, client_user); | ||
1400 | |||
1401 | snprintf(user, sizeof user, " ruser %s", client_user); | ||
1402 | break; | ||
1403 | |||
1404 | case SSH_CMSG_AUTH_RHOSTS_RSA: | ||
1405 | if (!options.rhosts_rsa_authentication) { | ||
1406 | verbose("Rhosts with RSA authentication disabled."); | ||
1407 | break; | ||
1408 | } | ||
1409 | /* | ||
1410 | * Get client user name. Note that we just have to | ||
1411 | * trust the client; root on the client machine can | ||
1412 | * claim to be any user. | ||
1413 | */ | ||
1414 | client_user = packet_get_string(&ulen); | ||
1415 | |||
1416 | /* Get the client host key. */ | ||
1417 | client_host_key = RSA_new(); | ||
1418 | if (client_host_key == NULL) | ||
1419 | fatal("RSA_new failed"); | ||
1420 | client_host_key->e = BN_new(); | ||
1421 | client_host_key->n = BN_new(); | ||
1422 | if (client_host_key->e == NULL || client_host_key->n == NULL) | ||
1423 | fatal("BN_new failed"); | ||
1424 | bits = packet_get_int(); | ||
1425 | packet_get_bignum(client_host_key->e, &elen); | ||
1426 | packet_get_bignum(client_host_key->n, &nlen); | ||
1427 | |||
1428 | if (bits != BN_num_bits(client_host_key->n)) | ||
1429 | error("Warning: keysize mismatch for client_host_key: " | ||
1430 | "actual %d, announced %d", BN_num_bits(client_host_key->n), bits); | ||
1431 | packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type); | ||
1432 | |||
1433 | authenticated = auth_rhosts_rsa(pw, client_user, client_host_key); | ||
1434 | RSA_free(client_host_key); | ||
1435 | |||
1436 | snprintf(user, sizeof user, " ruser %s", client_user); | ||
1437 | break; | ||
1438 | |||
1439 | case SSH_CMSG_AUTH_RSA: | ||
1440 | if (!options.rsa_authentication) { | ||
1441 | verbose("RSA authentication disabled."); | ||
1442 | break; | ||
1443 | } | ||
1444 | /* RSA authentication requested. */ | ||
1445 | n = BN_new(); | ||
1446 | packet_get_bignum(n, &nlen); | ||
1447 | packet_integrity_check(plen, nlen, type); | ||
1448 | authenticated = auth_rsa(pw, n); | ||
1449 | BN_clear_free(n); | ||
1450 | break; | ||
1451 | |||
1452 | case SSH_CMSG_AUTH_PASSWORD: | ||
1453 | if (!options.password_authentication) { | ||
1454 | verbose("Password authentication disabled."); | ||
1455 | break; | ||
1456 | } | ||
1457 | /* | ||
1458 | * Read user password. It is in plain text, but was | ||
1459 | * transmitted over the encrypted channel so it is | ||
1460 | * not visible to an outside observer. | ||
1461 | */ | ||
1462 | password = packet_get_string(&dlen); | ||
1463 | packet_integrity_check(plen, 4 + dlen, type); | ||
1464 | |||
1465 | #ifdef USE_PAM | ||
1466 | /* Do PAM auth with password */ | ||
1467 | authenticated = auth_pam_password(pw, password); | ||
1468 | #else /* USE_PAM */ | ||
1469 | /* Try authentication with the password. */ | ||
1470 | authenticated = auth_password(pw, password); | ||
1471 | #endif /* USE_PAM */ | ||
1472 | memset(password, 0, strlen(password)); | ||
1473 | xfree(password); | ||
1474 | break; | ||
1475 | |||
1476 | #ifdef SKEY | ||
1477 | case SSH_CMSG_AUTH_TIS: | ||
1478 | debug("rcvd SSH_CMSG_AUTH_TIS"); | ||
1479 | if (options.skey_authentication == 1) { | ||
1480 | char *skeyinfo = skey_keyinfo(pw->pw_name); | ||
1481 | if (skeyinfo == NULL) { | ||
1482 | debug("generating fake skeyinfo for %.100s.", pw->pw_name); | ||
1483 | skeyinfo = skey_fake_keyinfo(pw->pw_name); | ||
1484 | } | ||
1485 | if (skeyinfo != NULL) { | ||
1486 | /* we send our s/key- in tis-challenge messages */ | ||
1487 | debug("sending challenge '%s'", skeyinfo); | ||
1488 | packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); | ||
1489 | packet_put_string(skeyinfo, strlen(skeyinfo)); | ||
1490 | packet_send(); | ||
1491 | packet_write_wait(); | ||
1492 | continue; | ||
1493 | } | ||
1494 | } | ||
1495 | break; | ||
1496 | case SSH_CMSG_AUTH_TIS_RESPONSE: | ||
1497 | debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE"); | ||
1498 | if (options.skey_authentication == 1) { | ||
1499 | char *response = packet_get_string(&dlen); | ||
1500 | debug("skey response == '%s'", response); | ||
1501 | packet_integrity_check(plen, 4 + dlen, type); | ||
1502 | authenticated = (skey_haskey(pw->pw_name) == 0 && | ||
1503 | skey_passcheck(pw->pw_name, response) != -1); | ||
1504 | xfree(response); | ||
1505 | } | ||
1506 | break; | ||
1507 | #else | ||
1508 | case SSH_CMSG_AUTH_TIS: | ||
1509 | /* TIS Authentication is unsupported */ | ||
1510 | log("TIS authentication unsupported."); | ||
1511 | break; | ||
1512 | #endif | ||
1513 | |||
1514 | default: | ||
1515 | /* | ||
1516 | * Any unknown messages will be ignored (and failure | ||
1517 | * returned) during authentication. | ||
1518 | */ | ||
1519 | log("Unknown message during authentication: type %d", type); | ||
1520 | break; | ||
1521 | } | ||
1522 | |||
1523 | /* | ||
1524 | * Check if the user is logging in as root and root logins | ||
1525 | * are disallowed. | ||
1526 | * Note that root login is allowed for forced commands. | ||
1527 | */ | ||
1528 | if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) { | ||
1529 | if (forced_command) { | ||
1530 | log("Root login accepted for forced command."); | ||
1531 | } else { | ||
1532 | authenticated = 0; | ||
1533 | log("ROOT LOGIN REFUSED FROM %.200s", | ||
1534 | get_canonical_hostname()); | ||
1535 | } | ||
1536 | } | ||
1537 | |||
1538 | /* Raise logging level */ | ||
1539 | if (authenticated || | ||
1540 | attempt == AUTH_FAIL_LOG || | ||
1541 | type == SSH_CMSG_AUTH_PASSWORD) | ||
1542 | authlog = log; | ||
1543 | |||
1544 | authlog("%s %s for %.200s from %.200s port %d%s", | ||
1545 | authenticated ? "Accepted" : "Failed", | ||
1546 | get_authname(type), | ||
1547 | pw->pw_uid == 0 ? "ROOT" : pw->pw_name, | ||
1548 | get_remote_ipaddr(), | ||
1549 | get_remote_port(), | ||
1550 | user); | ||
1551 | |||
1552 | #ifdef USE_PAM | ||
1553 | if (authenticated) { | ||
1554 | if (!do_pam_account(pw->pw_name, client_user)) { | ||
1555 | if (client_user != NULL) { | ||
1556 | xfree(client_user); | ||
1557 | client_user = NULL; | ||
1558 | } | ||
1559 | do_fake_authloop(pw->pw_name); | ||
1560 | } | ||
1561 | return; | ||
1562 | } | ||
1563 | #else /* USE_PAM */ | ||
1564 | if (authenticated) { | ||
1565 | return; | ||
1566 | } | ||
1567 | #endif /* USE_PAM */ | ||
1568 | |||
1569 | if (client_user != NULL) { | ||
1570 | xfree(client_user); | ||
1571 | client_user = NULL; | ||
1572 | } | ||
1573 | |||
1574 | if (attempt > AUTH_FAIL_MAX) | ||
1575 | packet_disconnect(AUTH_FAIL_MSG, pw->pw_name); | ||
1576 | |||
1577 | /* Send a message indicating that the authentication attempt failed. */ | ||
1578 | packet_start(SSH_SMSG_FAILURE); | ||
1579 | packet_send(); | ||
1580 | packet_write_wait(); | ||
1581 | } | ||
1582 | } | ||
1583 | |||
1584 | /* | ||
1585 | * The user does not exist or access is denied, | ||
1586 | * but fake indication that authentication is needed. | ||
1587 | */ | ||
1588 | void | ||
1589 | do_fake_authloop(char *user) | ||
1590 | { | ||
1591 | int attempt = 0; | ||
1592 | |||
1593 | log("Faking authloop for illegal user %.200s from %.200s port %d", | ||
1594 | user, | ||
1595 | get_remote_ipaddr(), | ||
1596 | get_remote_port()); | ||
1597 | |||
1598 | /* Indicate that authentication is needed. */ | ||
1599 | packet_start(SSH_SMSG_FAILURE); | ||
1600 | packet_send(); | ||
1601 | packet_write_wait(); | ||
1602 | |||
1603 | /* | ||
1604 | * Keep reading packets, and always respond with a failure. This is | ||
1605 | * to avoid disclosing whether such a user really exists. | ||
1606 | */ | ||
1607 | for (attempt = 1;; attempt++) { | ||
1608 | /* Read a packet. This will not return if the client disconnects. */ | ||
1609 | int plen; | ||
1610 | #ifndef SKEY | ||
1611 | (void)packet_read(&plen); | ||
1612 | #else /* SKEY */ | ||
1613 | int type = packet_read(&plen); | ||
1614 | unsigned int dlen; | ||
1615 | char *password, *skeyinfo; | ||
1616 | /* Try to send a fake s/key challenge. */ | ||
1617 | if (options.skey_authentication == 1 && | ||
1618 | (skeyinfo = skey_fake_keyinfo(user)) != NULL) { | ||
1619 | password = NULL; | ||
1620 | if (type == SSH_CMSG_AUTH_TIS) { | ||
1621 | packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); | ||
1622 | packet_put_string(skeyinfo, strlen(skeyinfo)); | ||
1623 | packet_send(); | ||
1624 | packet_write_wait(); | ||
1625 | continue; | ||
1626 | } else if (type == SSH_CMSG_AUTH_PASSWORD && | ||
1627 | options.password_authentication && | ||
1628 | (password = packet_get_string(&dlen)) != NULL && | ||
1629 | dlen == 5 && | ||
1630 | strncasecmp(password, "s/key", 5) == 0 ) { | ||
1631 | packet_send_debug(skeyinfo); | ||
1632 | } | ||
1633 | if (password != NULL) | ||
1634 | xfree(password); | ||
1635 | } | ||
1636 | #endif | ||
1637 | if (attempt > AUTH_FAIL_MAX) | ||
1638 | packet_disconnect(AUTH_FAIL_MSG, user); | ||
1639 | |||
1640 | /* | ||
1641 | * Send failure. This should be indistinguishable from a | ||
1642 | * failed authentication. | ||
1643 | */ | ||
1644 | packet_start(SSH_SMSG_FAILURE); | ||
1645 | packet_send(); | ||
1646 | packet_write_wait(); | ||
1647 | #ifdef WITH_AIXAUTHENTICATE | ||
1648 | if (strncmp(get_authname(type),"password", | ||
1649 | strlen(get_authname(type))) == 0) | ||
1650 | loginfailed(pw->pw_name,get_canonical_hostname(),"ssh"); | ||
1651 | #endif /* WITH_AIXAUTHENTICATE */ | ||
1652 | } | ||
1653 | /* NOTREACHED */ | ||
1654 | abort(); | ||
1655 | } | ||
1656 | |||
1657 | struct pty_cleanup_context { | ||
1658 | const char *ttyname; | ||
1659 | int pid; | ||
1660 | }; | ||
1661 | |||
1662 | /* | ||
1663 | * Function to perform cleanup if we get aborted abnormally (e.g., due to a | ||
1664 | * dropped connection). | ||
1665 | */ | ||
1666 | void | ||
1667 | pty_cleanup_proc(void *context) | ||
1668 | { | ||
1669 | struct pty_cleanup_context *cu = context; | ||
1670 | |||
1671 | debug("pty_cleanup_proc called"); | ||
1672 | |||
1673 | /* Record that the user has logged out. */ | ||
1674 | record_logout(cu->pid, cu->ttyname); | ||
1675 | |||
1676 | /* Release the pseudo-tty. */ | ||
1677 | pty_release(cu->ttyname); | ||
1678 | } | ||
1679 | |||
1680 | /* simple cleanup: chown tty slave back to root */ | ||
1681 | static void | ||
1682 | pty_release_proc(void *tty) | ||
1683 | { | ||
1684 | char *ttyname = tty; | ||
1685 | pty_release(ttyname); | ||
1686 | } | ||
1687 | |||
1688 | /* | ||
1689 | * Prepares for an interactive session. This is called after the user has | ||
1690 | * been successfully authenticated. During this message exchange, pseudo | ||
1691 | * terminals are allocated, X11, TCP/IP, and authentication agent forwardings | ||
1692 | * are requested, etc. | ||
1693 | */ | ||
1694 | void | ||
1695 | do_authenticated(struct passwd * pw) | ||
1696 | { | ||
1697 | int type; | ||
1698 | int compression_level = 0, enable_compression_after_reply = 0; | ||
1699 | int have_pty = 0, ptyfd = -1, ttyfd = -1; | ||
1700 | int row, col, xpixel, ypixel, screen; | ||
1701 | char ttyname[64]; | ||
1702 | char *command, *term = NULL, *display = NULL, *proto = NULL, *data = NULL; | ||
1703 | int plen; | ||
1704 | unsigned int dlen; | ||
1705 | int n_bytes; | ||
1706 | |||
1707 | /* | ||
1708 | * Cancel the alarm we set to limit the time taken for | ||
1709 | * authentication. | ||
1710 | */ | ||
1711 | alarm(0); | ||
1712 | |||
1713 | /* | ||
1714 | * Inform the channel mechanism that we are the server side and that | ||
1715 | * the client may request to connect to any port at all. (The user | ||
1716 | * could do it anyway, and we wouldn\'t know what is permitted except | ||
1717 | * by the client telling us, so we can equally well trust the client | ||
1718 | * not to request anything bogus.) | ||
1719 | */ | ||
1720 | if (!no_port_forwarding_flag) | ||
1721 | channel_permit_all_opens(); | ||
1722 | |||
1723 | /* | ||
1724 | * We stay in this loop until the client requests to execute a shell | ||
1725 | * or a command. | ||
1726 | */ | ||
1727 | while (1) { | ||
1728 | |||
1729 | /* Get a packet from the client. */ | ||
1730 | type = packet_read(&plen); | ||
1731 | |||
1732 | /* Process the packet. */ | ||
1733 | switch (type) { | ||
1734 | case SSH_CMSG_REQUEST_COMPRESSION: | ||
1735 | packet_integrity_check(plen, 4, type); | ||
1736 | compression_level = packet_get_int(); | ||
1737 | if (compression_level < 1 || compression_level > 9) { | ||
1738 | packet_send_debug("Received illegal compression level %d.", | ||
1739 | compression_level); | ||
1740 | goto fail; | ||
1741 | } | ||
1742 | /* Enable compression after we have responded with SUCCESS. */ | ||
1743 | enable_compression_after_reply = 1; | ||
1744 | break; | ||
1745 | |||
1746 | case SSH_CMSG_REQUEST_PTY: | ||
1747 | if (no_pty_flag) { | ||
1748 | debug("Allocating a pty not permitted for this authentication."); | ||
1749 | goto fail; | ||
1750 | } | ||
1751 | if (have_pty) | ||
1752 | packet_disconnect("Protocol error: you already have a pty."); | ||
1753 | |||
1754 | debug("Allocating pty."); | ||
1755 | |||
1756 | /* Allocate a pty and open it. */ | ||
1757 | if (!pty_allocate(&ptyfd, &ttyfd, ttyname, | ||
1758 | sizeof(ttyname))) { | ||
1759 | error("Failed to allocate pty."); | ||
1760 | goto fail; | ||
1761 | } | ||
1762 | fatal_add_cleanup(pty_release_proc, (void *)ttyname); | ||
1763 | pty_setowner(pw, ttyname); | ||
1764 | |||
1765 | /* Get TERM from the packet. Note that the value may be of arbitrary length. */ | ||
1766 | term = packet_get_string(&dlen); | ||
1767 | packet_integrity_check(dlen, strlen(term), type); | ||
1768 | |||
1769 | /* Remaining bytes */ | ||
1770 | n_bytes = plen - (4 + dlen + 4 * 4); | ||
1771 | |||
1772 | if (strcmp(term, "") == 0) { | ||
1773 | xfree(term); | ||
1774 | term = NULL; | ||
1775 | } | ||
1776 | |||
1777 | /* Get window size from the packet. */ | ||
1778 | row = packet_get_int(); | ||
1779 | col = packet_get_int(); | ||
1780 | xpixel = packet_get_int(); | ||
1781 | ypixel = packet_get_int(); | ||
1782 | pty_change_window_size(ptyfd, row, col, xpixel, ypixel); | ||
1783 | |||
1784 | /* Get tty modes from the packet. */ | ||
1785 | tty_parse_modes(ttyfd, &n_bytes); | ||
1786 | packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type); | ||
1787 | |||
1788 | /* Indicate that we now have a pty. */ | ||
1789 | have_pty = 1; | ||
1790 | break; | ||
1791 | |||
1792 | case SSH_CMSG_X11_REQUEST_FORWARDING: | ||
1793 | if (!options.x11_forwarding) { | ||
1794 | packet_send_debug("X11 forwarding disabled in server configuration file."); | ||
1795 | goto fail; | ||
1796 | } | ||
1797 | #ifdef XAUTH_PATH | ||
1798 | if (no_x11_forwarding_flag) { | ||
1799 | packet_send_debug("X11 forwarding not permitted for this authentication."); | ||
1800 | goto fail; | ||
1801 | } | ||
1802 | debug("Received request for X11 forwarding with auth spoofing."); | ||
1803 | if (display) | ||
1804 | packet_disconnect("Protocol error: X11 display already set."); | ||
1805 | { | ||
1806 | unsigned int proto_len, data_len; | ||
1807 | proto = packet_get_string(&proto_len); | ||
1808 | data = packet_get_string(&data_len); | ||
1809 | packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type); | ||
1810 | } | ||
1811 | if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER) | ||
1812 | screen = packet_get_int(); | ||
1813 | else | ||
1814 | screen = 0; | ||
1815 | display = x11_create_display_inet(screen, options.x11_display_offset); | ||
1816 | if (!display) | ||
1817 | goto fail; | ||
1818 | |||
1819 | /* Setup to always have a local .Xauthority. */ | ||
1820 | xauthfile = xmalloc(MAXPATHLEN); | ||
1821 | strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); | ||
1822 | temporarily_use_uid(pw->pw_uid); | ||
1823 | if (mkdtemp(xauthfile) == NULL) { | ||
1824 | restore_uid(); | ||
1825 | error("private X11 dir: mkdtemp %s failed: %s", | ||
1826 | xauthfile, strerror(errno)); | ||
1827 | xfree(xauthfile); | ||
1828 | xauthfile = NULL; | ||
1829 | goto fail; | ||
1830 | } | ||
1831 | strlcat(xauthfile, "/cookies", MAXPATHLEN); | ||
1832 | open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); | ||
1833 | restore_uid(); | ||
1834 | fatal_add_cleanup(xauthfile_cleanup_proc, NULL); | ||
1835 | break; | ||
1836 | #else /* XAUTH_PATH */ | ||
1837 | packet_send_debug("No xauth program; cannot forward with spoofing."); | ||
1838 | goto fail; | ||
1839 | #endif /* XAUTH_PATH */ | ||
1840 | |||
1841 | case SSH_CMSG_AGENT_REQUEST_FORWARDING: | ||
1842 | if (no_agent_forwarding_flag || compat13) { | ||
1843 | debug("Authentication agent forwarding not permitted for this authentication."); | ||
1844 | goto fail; | ||
1845 | } | ||
1846 | debug("Received authentication agent forwarding request."); | ||
1847 | auth_input_request_forwarding(pw); | ||
1848 | break; | ||
1849 | |||
1850 | case SSH_CMSG_PORT_FORWARD_REQUEST: | ||
1851 | if (no_port_forwarding_flag) { | ||
1852 | debug("Port forwarding not permitted for this authentication."); | ||
1853 | goto fail; | ||
1854 | } | ||
1855 | debug("Received TCP/IP port forwarding request."); | ||
1856 | channel_input_port_forward_request(pw->pw_uid == 0); | ||
1857 | break; | ||
1858 | |||
1859 | case SSH_CMSG_MAX_PACKET_SIZE: | ||
1860 | if (packet_set_maxsize(packet_get_int()) < 0) | ||
1861 | goto fail; | ||
1862 | break; | ||
1863 | |||
1864 | case SSH_CMSG_EXEC_SHELL: | ||
1865 | /* Set interactive/non-interactive mode. */ | ||
1866 | packet_set_interactive(have_pty || display != NULL, | ||
1867 | options.keepalives); | ||
1868 | |||
1869 | if (forced_command != NULL) | ||
1870 | goto do_forced_command; | ||
1871 | debug("Forking shell."); | ||
1872 | packet_integrity_check(plen, 0, type); | ||
1873 | if (have_pty) | ||
1874 | do_exec_pty(NULL, ptyfd, ttyfd, ttyname, pw, term, display, proto, data); | ||
1875 | else | ||
1876 | do_exec_no_pty(NULL, pw, display, proto, data); | ||
1877 | return; | ||
1878 | |||
1879 | case SSH_CMSG_EXEC_CMD: | ||
1880 | /* Set interactive/non-interactive mode. */ | ||
1881 | packet_set_interactive(have_pty || display != NULL, | ||
1882 | options.keepalives); | ||
1883 | |||
1884 | if (forced_command != NULL) | ||
1885 | goto do_forced_command; | ||
1886 | /* Get command from the packet. */ | ||
1887 | { | ||
1888 | unsigned int dlen; | ||
1889 | command = packet_get_string(&dlen); | ||
1890 | debug("Executing command '%.500s'", command); | ||
1891 | packet_integrity_check(plen, 4 + dlen, type); | ||
1892 | } | ||
1893 | if (have_pty) | ||
1894 | do_exec_pty(command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data); | ||
1895 | else | ||
1896 | do_exec_no_pty(command, pw, display, proto, data); | ||
1897 | xfree(command); | ||
1898 | return; | ||
1899 | |||
1900 | default: | ||
1901 | /* | ||
1902 | * Any unknown messages in this phase are ignored, | ||
1903 | * and a failure message is returned. | ||
1904 | */ | ||
1905 | log("Unknown packet type received after authentication: %d", type); | ||
1906 | goto fail; | ||
1907 | } | ||
1908 | |||
1909 | /* The request was successfully processed. */ | ||
1910 | packet_start(SSH_SMSG_SUCCESS); | ||
1911 | packet_send(); | ||
1912 | packet_write_wait(); | ||
1913 | |||
1914 | /* Enable compression now that we have replied if appropriate. */ | ||
1915 | if (enable_compression_after_reply) { | ||
1916 | enable_compression_after_reply = 0; | ||
1917 | packet_start_compression(compression_level); | ||
1918 | } | ||
1919 | continue; | ||
1920 | |||
1921 | fail: | ||
1922 | /* The request failed. */ | ||
1923 | packet_start(SSH_SMSG_FAILURE); | ||
1924 | packet_send(); | ||
1925 | packet_write_wait(); | ||
1926 | continue; | ||
1927 | |||
1928 | do_forced_command: | ||
1929 | /* | ||
1930 | * There is a forced command specified for this login. | ||
1931 | * Execute it. | ||
1932 | */ | ||
1933 | debug("Executing forced command: %.900s", forced_command); | ||
1934 | if (have_pty) | ||
1935 | do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data); | ||
1936 | else | ||
1937 | do_exec_no_pty(forced_command, pw, display, proto, data); | ||
1938 | return; | ||
1939 | } | ||
1940 | } | ||
1941 | |||
1942 | /* | ||
1943 | * This is called to fork and execute a command when we have no tty. This | ||
1944 | * will call do_child from the child, and server_loop from the parent after | ||
1945 | * setting up file descriptors and such. | ||
1946 | */ | ||
1947 | void | ||
1948 | do_exec_no_pty(const char *command, struct passwd * pw, | ||
1949 | const char *display, const char *auth_proto, | ||
1950 | const char *auth_data) | ||
1951 | { | ||
1952 | int pid; | ||
1953 | |||
1954 | #ifdef USE_PIPES | ||
1955 | int pin[2], pout[2], perr[2]; | ||
1956 | /* Allocate pipes for communicating with the program. */ | ||
1957 | if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) | ||
1958 | packet_disconnect("Could not create pipes: %.100s", | ||
1959 | strerror(errno)); | ||
1960 | #else /* USE_PIPES */ | ||
1961 | int inout[2], err[2]; | ||
1962 | /* Uses socket pairs to communicate with the program. */ | ||
1963 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || | ||
1964 | socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) | ||
1965 | packet_disconnect("Could not create socket pairs: %.100s", | ||
1966 | strerror(errno)); | ||
1967 | #endif /* USE_PIPES */ | ||
1968 | |||
1969 | setproctitle("%s@notty", pw->pw_name); | ||
1970 | |||
1971 | #ifdef USE_PAM | ||
1972 | do_pam_setcred(); | ||
1973 | #endif /* USE_PAM */ | ||
1974 | |||
1975 | /* Fork the child. */ | ||
1976 | if ((pid = fork()) == 0) { | ||
1977 | /* Child. Reinitialize the log since the pid has changed. */ | ||
1978 | log_init(av0, options.log_level, options.log_facility, log_stderr); | ||
1979 | |||
1980 | /* | ||
1981 | * Create a new session and process group since the 4.4BSD | ||
1982 | * setlogin() affects the entire process group. | ||
1983 | */ | ||
1984 | if (setsid() < 0) | ||
1985 | error("setsid failed: %.100s", strerror(errno)); | ||
1986 | |||
1987 | #ifdef USE_PIPES | ||
1988 | /* | ||
1989 | * Redirect stdin. We close the parent side of the socket | ||
1990 | * pair, and make the child side the standard input. | ||
1991 | */ | ||
1992 | close(pin[1]); | ||
1993 | if (dup2(pin[0], 0) < 0) | ||
1994 | perror("dup2 stdin"); | ||
1995 | close(pin[0]); | ||
1996 | |||
1997 | /* Redirect stdout. */ | ||
1998 | close(pout[0]); | ||
1999 | if (dup2(pout[1], 1) < 0) | ||
2000 | perror("dup2 stdout"); | ||
2001 | close(pout[1]); | ||
2002 | |||
2003 | /* Redirect stderr. */ | ||
2004 | close(perr[0]); | ||
2005 | if (dup2(perr[1], 2) < 0) | ||
2006 | perror("dup2 stderr"); | ||
2007 | close(perr[1]); | ||
2008 | #else /* USE_PIPES */ | ||
2009 | /* | ||
2010 | * Redirect stdin, stdout, and stderr. Stdin and stdout will | ||
2011 | * use the same socket, as some programs (particularly rdist) | ||
2012 | * seem to depend on it. | ||
2013 | */ | ||
2014 | close(inout[1]); | ||
2015 | close(err[1]); | ||
2016 | if (dup2(inout[0], 0) < 0) /* stdin */ | ||
2017 | perror("dup2 stdin"); | ||
2018 | if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ | ||
2019 | perror("dup2 stdout"); | ||
2020 | if (dup2(err[0], 2) < 0) /* stderr */ | ||
2021 | perror("dup2 stderr"); | ||
2022 | #endif /* USE_PIPES */ | ||
2023 | |||
2024 | /* Do processing for the child (exec command etc). */ | ||
2025 | do_child(command, pw, NULL, display, auth_proto, auth_data, NULL); | ||
2026 | /* NOTREACHED */ | ||
2027 | } | ||
2028 | if (pid < 0) | ||
2029 | packet_disconnect("fork failed: %.100s", strerror(errno)); | ||
2030 | #ifdef USE_PIPES | ||
2031 | /* We are the parent. Close the child sides of the pipes. */ | ||
2032 | close(pin[0]); | ||
2033 | close(pout[1]); | ||
2034 | close(perr[1]); | ||
2035 | |||
2036 | /* Enter the interactive session. */ | ||
2037 | server_loop(pid, pin[1], pout[0], perr[0]); | ||
2038 | /* server_loop has closed pin[1], pout[1], and perr[1]. */ | ||
2039 | #else /* USE_PIPES */ | ||
2040 | /* We are the parent. Close the child sides of the socket pairs. */ | ||
2041 | close(inout[0]); | ||
2042 | close(err[0]); | ||
2043 | |||
2044 | /* | ||
2045 | * Enter the interactive session. Note: server_loop must be able to | ||
2046 | * handle the case that fdin and fdout are the same. | ||
2047 | */ | ||
2048 | server_loop(pid, inout[1], inout[1], err[1]); | ||
2049 | /* server_loop has closed inout[1] and err[1]. */ | ||
2050 | #endif /* USE_PIPES */ | ||
2051 | } | ||
2052 | |||
2053 | /* | ||
2054 | * This is called to fork and execute a command when we have a tty. This | ||
2055 | * will call do_child from the child, and server_loop from the parent after | ||
2056 | * setting up file descriptors, controlling tty, updating wtmp, utmp, | ||
2057 | * lastlog, and other such operations. | ||
2058 | */ | ||
2059 | void | ||
2060 | do_exec_pty(const char *command, int ptyfd, int ttyfd, | ||
2061 | const char *ttyname, struct passwd * pw, const char *term, | ||
2062 | const char *display, const char *auth_proto, | ||
2063 | const char *auth_data) | ||
2064 | { | ||
2065 | int pid, fdout; | ||
2066 | int ptymaster; | ||
2067 | const char *hostname; | ||
2068 | time_t last_login_time; | ||
2069 | char buf[100], *time_string; | ||
2070 | FILE *f; | ||
2071 | char line[256]; | ||
2072 | struct stat st; | ||
2073 | int quiet_login; | ||
2074 | struct sockaddr_storage from; | ||
2075 | socklen_t fromlen; | ||
2076 | struct pty_cleanup_context cleanup_context; | ||
2077 | |||
2078 | /* Get remote host name. */ | ||
2079 | hostname = get_canonical_hostname(); | ||
2080 | |||
2081 | /* | ||
2082 | * Get the time when the user last logged in. Buf will be set to | ||
2083 | * contain the hostname the last login was from. | ||
2084 | */ | ||
2085 | if (!options.use_login) { | ||
2086 | last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, | ||
2087 | buf, sizeof(buf)); | ||
2088 | } | ||
2089 | setproctitle("%s@%s", pw->pw_name, strrchr(ttyname, '/') + 1); | ||
2090 | |||
2091 | #ifdef USE_PAM | ||
2092 | do_pam_session(pw->pw_name, ttyname); | ||
2093 | do_pam_setcred(); | ||
2094 | #endif /* USE_PAM */ | ||
2095 | |||
2096 | /* Fork the child. */ | ||
2097 | if ((pid = fork()) == 0) { | ||
2098 | pid = getpid(); | ||
2099 | |||
2100 | /* Child. Reinitialize the log because the pid has | ||
2101 | changed. */ | ||
2102 | log_init(av0, options.log_level, options.log_facility, log_stderr); | ||
2103 | |||
2104 | /* Close the master side of the pseudo tty. */ | ||
2105 | close(ptyfd); | ||
2106 | |||
2107 | /* Make the pseudo tty our controlling tty. */ | ||
2108 | pty_make_controlling_tty(&ttyfd, ttyname); | ||
2109 | |||
2110 | /* Redirect stdin from the pseudo tty. */ | ||
2111 | if (dup2(ttyfd, fileno(stdin)) < 0) | ||
2112 | error("dup2 stdin failed: %.100s", strerror(errno)); | ||
2113 | |||
2114 | /* Redirect stdout to the pseudo tty. */ | ||
2115 | if (dup2(ttyfd, fileno(stdout)) < 0) | ||
2116 | error("dup2 stdin failed: %.100s", strerror(errno)); | ||
2117 | |||
2118 | /* Redirect stderr to the pseudo tty. */ | ||
2119 | if (dup2(ttyfd, fileno(stderr)) < 0) | ||
2120 | error("dup2 stdin failed: %.100s", strerror(errno)); | ||
2121 | |||
2122 | /* Close the extra descriptor for the pseudo tty. */ | ||
2123 | close(ttyfd); | ||
2124 | |||
2125 | /* | ||
2126 | * Get IP address of client. This is needed because we want | ||
2127 | * to record where the user logged in from. If the | ||
2128 | * connection is not a socket, let the ip address be 0.0.0.0. | ||
2129 | */ | ||
2130 | memset(&from, 0, sizeof(from)); | ||
2131 | if (packet_get_connection_in() == packet_get_connection_out()) { | ||
2132 | fromlen = sizeof(from); | ||
2133 | if (getpeername(packet_get_connection_in(), | ||
2134 | (struct sockaddr *) & from, &fromlen) < 0) { | ||
2135 | debug("getpeername: %.100s", strerror(errno)); | ||
2136 | fatal_cleanup(); | ||
2137 | } | ||
2138 | } | ||
2139 | /* Record that there was a login on that terminal. */ | ||
2140 | record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname, | ||
2141 | (struct sockaddr *)&from); | ||
2142 | |||
2143 | /* Check if .hushlogin exists. */ | ||
2144 | snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir); | ||
2145 | quiet_login = stat(line, &st) >= 0; | ||
2146 | |||
2147 | #ifdef USE_PAM | ||
2148 | if (!quiet_login) | ||
2149 | print_pam_messages(); | ||
2150 | #endif /* USE_PAM */ | ||
2151 | |||
2152 | /* | ||
2153 | * If the user has logged in before, display the time of last | ||
2154 | * login. However, don't display anything extra if a command | ||
2155 | * has been specified (so that ssh can be used to execute | ||
2156 | * commands on a remote machine without users knowing they | ||
2157 | * are going to another machine). Login(1) will do this for | ||
2158 | * us as well, so check if login(1) is used | ||
2159 | */ | ||
2160 | if (command == NULL && last_login_time != 0 && !quiet_login && | ||
2161 | !options.use_login) { | ||
2162 | /* Convert the date to a string. */ | ||
2163 | time_string = ctime(&last_login_time); | ||
2164 | /* Remove the trailing newline. */ | ||
2165 | if (strchr(time_string, '\n')) | ||
2166 | *strchr(time_string, '\n') = 0; | ||
2167 | /* Display the last login time. Host if displayed | ||
2168 | if known. */ | ||
2169 | if (strcmp(buf, "") == 0) | ||
2170 | printf("Last login: %s\r\n", time_string); | ||
2171 | else | ||
2172 | printf("Last login: %s from %s\r\n", time_string, buf); | ||
2173 | } | ||
2174 | /* | ||
2175 | * Print /etc/motd unless a command was specified or printing | ||
2176 | * it was disabled in server options or login(1) will be | ||
2177 | * used. Note that some machines appear to print it in | ||
2178 | * /etc/profile or similar. | ||
2179 | */ | ||
2180 | if (command == NULL && options.print_motd && !quiet_login && | ||
2181 | !options.use_login) { | ||
2182 | /* Print /etc/motd if it exists. */ | ||
2183 | f = fopen("/etc/motd", "r"); | ||
2184 | if (f) { | ||
2185 | while (fgets(line, sizeof(line), f)) | ||
2186 | fputs(line, stdout); | ||
2187 | fclose(f); | ||
2188 | } | ||
2189 | } | ||
2190 | /* Do common processing for the child, such as execing the command. */ | ||
2191 | do_child(command, pw, term, display, auth_proto, auth_data, ttyname); | ||
2192 | /* NOTREACHED */ | ||
2193 | } | ||
2194 | if (pid < 0) | ||
2195 | packet_disconnect("fork failed: %.100s", strerror(errno)); | ||
2196 | /* Parent. Close the slave side of the pseudo tty. */ | ||
2197 | close(ttyfd); | ||
2198 | |||
2199 | /* | ||
2200 | * Add a cleanup function to clear the utmp entry and record logout | ||
2201 | * time in case we call fatal() (e.g., the connection gets closed). | ||
2202 | */ | ||
2203 | cleanup_context.pid = pid; | ||
2204 | cleanup_context.ttyname = ttyname; | ||
2205 | fatal_add_cleanup(pty_cleanup_proc, (void *) &cleanup_context); | ||
2206 | fatal_remove_cleanup(pty_release_proc, (void *) ttyname); | ||
2207 | |||
2208 | /* | ||
2209 | * Create another descriptor of the pty master side for use as the | ||
2210 | * standard input. We could use the original descriptor, but this | ||
2211 | * simplifies code in server_loop. The descriptor is bidirectional. | ||
2212 | */ | ||
2213 | fdout = dup(ptyfd); | ||
2214 | if (fdout < 0) | ||
2215 | packet_disconnect("dup #1 failed: %.100s", strerror(errno)); | ||
2216 | |||
2217 | /* we keep a reference to the pty master */ | ||
2218 | ptymaster = dup(ptyfd); | ||
2219 | if (ptymaster < 0) | ||
2220 | packet_disconnect("dup #2 failed: %.100s", strerror(errno)); | ||
2221 | |||
2222 | /* Enter interactive session. */ | ||
2223 | server_loop(pid, ptyfd, fdout, -1); | ||
2224 | /* server_loop _has_ closed ptyfd and fdout. */ | ||
2225 | |||
2226 | /* Cancel the cleanup function. */ | ||
2227 | fatal_remove_cleanup(pty_cleanup_proc, (void *) &cleanup_context); | ||
2228 | |||
2229 | /* Record that the user has logged out. */ | ||
2230 | record_logout(pid, ttyname); | ||
2231 | |||
2232 | /* Release the pseudo-tty. */ | ||
2233 | pty_release(ttyname); | ||
2234 | |||
2235 | /* | ||
2236 | * Close the server side of the socket pairs. We must do this after | ||
2237 | * the pty cleanup, so that another process doesn't get this pty | ||
2238 | * while we're still cleaning up. | ||
2239 | */ | ||
2240 | if (close(ptymaster) < 0) | ||
2241 | error("close(ptymaster): %s", strerror(errno)); | ||
2242 | } | ||
2243 | |||
2244 | /* | ||
2245 | * Sets the value of the given variable in the environment. If the variable | ||
2246 | * already exists, its value is overriden. | ||
2247 | */ | ||
2248 | void | ||
2249 | child_set_env(char ***envp, unsigned int *envsizep, const char *name, | ||
2250 | const char *value) | ||
2251 | { | ||
2252 | unsigned int i, namelen; | ||
2253 | char **env; | ||
2254 | |||
2255 | /* | ||
2256 | * Find the slot where the value should be stored. If the variable | ||
2257 | * already exists, we reuse the slot; otherwise we append a new slot | ||
2258 | * at the end of the array, expanding if necessary. | ||
2259 | */ | ||
2260 | env = *envp; | ||
2261 | namelen = strlen(name); | ||
2262 | for (i = 0; env[i]; i++) | ||
2263 | if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') | ||
2264 | break; | ||
2265 | if (env[i]) { | ||
2266 | /* Reuse the slot. */ | ||
2267 | xfree(env[i]); | ||
2268 | } else { | ||
2269 | /* New variable. Expand if necessary. */ | ||
2270 | if (i >= (*envsizep) - 1) { | ||
2271 | (*envsizep) += 50; | ||
2272 | env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *)); | ||
2273 | } | ||
2274 | /* Need to set the NULL pointer at end of array beyond the new slot. */ | ||
2275 | env[i + 1] = NULL; | ||
2276 | } | ||
2277 | |||
2278 | /* Allocate space and format the variable in the appropriate slot. */ | ||
2279 | env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); | ||
2280 | snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); | ||
2281 | } | ||
2282 | |||
2283 | /* | ||
2284 | * Reads environment variables from the given file and adds/overrides them | ||
2285 | * into the environment. If the file does not exist, this does nothing. | ||
2286 | * Otherwise, it must consist of empty lines, comments (line starts with '#') | ||
2287 | * and assignments of the form name=value. No other forms are allowed. | ||
2288 | */ | ||
2289 | void | ||
2290 | read_environment_file(char ***env, unsigned int *envsize, | ||
2291 | const char *filename) | ||
2292 | { | ||
2293 | FILE *f; | ||
2294 | char buf[4096]; | ||
2295 | char *cp, *value; | ||
2296 | |||
2297 | f = fopen(filename, "r"); | ||
2298 | if (!f) | ||
2299 | return; | ||
2300 | |||
2301 | while (fgets(buf, sizeof(buf), f)) { | ||
2302 | for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) | ||
2303 | ; | ||
2304 | if (!*cp || *cp == '#' || *cp == '\n') | ||
2305 | continue; | ||
2306 | if (strchr(cp, '\n')) | ||
2307 | *strchr(cp, '\n') = '\0'; | ||
2308 | value = strchr(cp, '='); | ||
2309 | if (value == NULL) { | ||
2310 | fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf); | ||
2311 | continue; | ||
2312 | } | ||
2313 | /* Replace the equals sign by nul, and advance value to the value string. */ | ||
2314 | *value = '\0'; | ||
2315 | value++; | ||
2316 | child_set_env(env, envsize, cp, value); | ||
2317 | } | ||
2318 | fclose(f); | ||
2319 | } | ||
2320 | |||
2321 | #ifdef USE_PAM | ||
2322 | /* | ||
2323 | * Sets any environment variables which have been specified by PAM | ||
2324 | */ | ||
2325 | void do_pam_environment(char ***env, int *envsize) | ||
2326 | { | ||
2327 | char *equals, var_name[512], var_val[512]; | ||
2328 | char **pam_env; | ||
2329 | int i; | ||
2330 | |||
2331 | if ((pam_env = fetch_pam_environment()) == NULL) | ||
2332 | return; | ||
2333 | |||
2334 | for(i = 0; pam_env[i] != NULL; i++) { | ||
2335 | if ((equals = strstr(pam_env[i], "=")) == NULL) | ||
2336 | continue; | ||
2337 | |||
2338 | if (strlen(pam_env[i]) < (sizeof(var_name) - 1)) | ||
2339 | { | ||
2340 | memset(var_name, '\0', sizeof(var_name)); | ||
2341 | memset(var_val, '\0', sizeof(var_val)); | ||
2342 | |||
2343 | strncpy(var_name, pam_env[i], equals - pam_env[i]); | ||
2344 | strcpy(var_val, equals + 1); | ||
2345 | |||
2346 | debug("PAM environment: %s=%s", var_name, var_val); | ||
2347 | |||
2348 | child_set_env(env, envsize, var_name, var_val); | ||
2349 | } | ||
2350 | } | ||
2351 | } | ||
2352 | #endif /* USE_PAM */ | ||
2353 | |||
2354 | /* | ||
2355 | * Performs common processing for the child, such as setting up the | ||
2356 | * environment, closing extra file descriptors, setting the user and group | ||
2357 | * ids, and executing the command or shell. | ||
2358 | */ | ||
2359 | void | ||
2360 | do_child(const char *command, struct passwd * pw, const char *term, | ||
2361 | const char *display, const char *auth_proto, | ||
2362 | const char *auth_data, const char *ttyname) | ||
2363 | { | ||
2364 | const char *shell, *cp = NULL; | ||
2365 | char buf[256]; | ||
2366 | FILE *f; | ||
2367 | unsigned int envsize, i; | ||
2368 | char **env; | ||
2369 | extern char **environ; | ||
2370 | struct stat st; | ||
2371 | char *argv[10]; | ||
2372 | |||
2373 | #ifndef USE_PAM /* pam_nologin handles this */ | ||
2374 | /* Check /etc/nologin. */ | ||
2375 | f = fopen("/etc/nologin", "r"); | ||
2376 | if (f) { | ||
2377 | /* /etc/nologin exists. Print its contents and exit. */ | ||
2378 | while (fgets(buf, sizeof(buf), f)) | ||
2379 | fputs(buf, stderr); | ||
2380 | fclose(f); | ||
2381 | if (pw->pw_uid != 0) | ||
2382 | exit(254); | ||
2383 | } | ||
2384 | #endif /* USE_PAM */ | ||
2385 | |||
2386 | /* Set login name in the kernel. */ | ||
2387 | if (setlogin(pw->pw_name) < 0) | ||
2388 | error("setlogin failed: %s", strerror(errno)); | ||
2389 | |||
2390 | /* Set uid, gid, and groups. */ | ||
2391 | /* Login(1) does this as well, and it needs uid 0 for the "-h" | ||
2392 | switch, so we let login(1) to this for us. */ | ||
2393 | if (!options.use_login) { | ||
2394 | if (getuid() == 0 || geteuid() == 0) { | ||
2395 | if (setgid(pw->pw_gid) < 0) { | ||
2396 | perror("setgid"); | ||
2397 | exit(1); | ||
2398 | } | ||
2399 | /* Initialize the group list. */ | ||
2400 | if (initgroups(pw->pw_name, pw->pw_gid) < 0) { | ||
2401 | perror("initgroups"); | ||
2402 | exit(1); | ||
2403 | } | ||
2404 | endgrent(); | ||
2405 | |||
2406 | /* Permanently switch to the desired uid. */ | ||
2407 | permanently_set_uid(pw->pw_uid); | ||
2408 | } | ||
2409 | if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) | ||
2410 | fatal("Failed to set uids to %d.", (int) pw->pw_uid); | ||
2411 | } | ||
2412 | /* | ||
2413 | * Get the shell from the password data. An empty shell field is | ||
2414 | * legal, and means /bin/sh. | ||
2415 | */ | ||
2416 | shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; | ||
2417 | |||
2418 | #ifdef AFS | ||
2419 | /* Try to get AFS tokens for the local cell. */ | ||
2420 | if (k_hasafs()) { | ||
2421 | char cell[64]; | ||
2422 | |||
2423 | if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) | ||
2424 | krb_afslog(cell, 0); | ||
2425 | |||
2426 | krb_afslog(0, 0); | ||
2427 | } | ||
2428 | #endif /* AFS */ | ||
2429 | |||
2430 | /* Initialize the environment. */ | ||
2431 | envsize = 100; | ||
2432 | env = xmalloc(envsize * sizeof(char *)); | ||
2433 | env[0] = NULL; | ||
2434 | |||
2435 | if (!options.use_login) { | ||
2436 | /* Set basic environment. */ | ||
2437 | child_set_env(&env, &envsize, "USER", pw->pw_name); | ||
2438 | child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); | ||
2439 | child_set_env(&env, &envsize, "HOME", pw->pw_dir); | ||
2440 | child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); | ||
2441 | |||
2442 | snprintf(buf, sizeof buf, "%.200s/%.50s", | ||
2443 | _PATH_MAILDIR, pw->pw_name); | ||
2444 | child_set_env(&env, &envsize, "MAIL", buf); | ||
2445 | |||
2446 | /* Normal systems set SHELL by default. */ | ||
2447 | child_set_env(&env, &envsize, "SHELL", shell); | ||
2448 | } | ||
2449 | if (getenv("TZ")) | ||
2450 | child_set_env(&env, &envsize, "TZ", getenv("TZ")); | ||
2451 | |||
2452 | /* Set custom environment options from RSA authentication. */ | ||
2453 | while (custom_environment) { | ||
2454 | struct envstring *ce = custom_environment; | ||
2455 | char *s = ce->s; | ||
2456 | int i; | ||
2457 | for (i = 0; s[i] != '=' && s[i]; i++); | ||
2458 | if (s[i] == '=') { | ||
2459 | s[i] = 0; | ||
2460 | child_set_env(&env, &envsize, s, s + i + 1); | ||
2461 | } | ||
2462 | custom_environment = ce->next; | ||
2463 | xfree(ce->s); | ||
2464 | xfree(ce); | ||
2465 | } | ||
2466 | |||
2467 | snprintf(buf, sizeof buf, "%.50s %d %d", | ||
2468 | get_remote_ipaddr(), get_remote_port(), get_local_port()); | ||
2469 | child_set_env(&env, &envsize, "SSH_CLIENT", buf); | ||
2470 | |||
2471 | if (ttyname) | ||
2472 | child_set_env(&env, &envsize, "SSH_TTY", ttyname); | ||
2473 | if (term) | ||
2474 | child_set_env(&env, &envsize, "TERM", term); | ||
2475 | if (display) | ||
2476 | child_set_env(&env, &envsize, "DISPLAY", display); | ||
2477 | |||
2478 | #ifdef _AIX | ||
2479 | { | ||
2480 | char *authstate,*krb5cc; | ||
2481 | |||
2482 | if ((authstate = getenv("AUTHSTATE")) != NULL) | ||
2483 | child_set_env(&env,&envsize,"AUTHSTATE",authstate); | ||
2484 | |||
2485 | if ((krb5cc = getenv("KRB5CCNAME")) != NULL) | ||
2486 | child_set_env(&env,&envsize,"KRB5CCNAME",krb5cc); | ||
2487 | } | ||
2488 | #endif | ||
2489 | |||
2490 | #ifdef KRB4 | ||
2491 | { | ||
2492 | extern char *ticket; | ||
2493 | |||
2494 | if (ticket) | ||
2495 | child_set_env(&env, &envsize, "KRBTKFILE", ticket); | ||
2496 | } | ||
2497 | #endif /* KRB4 */ | ||
2498 | |||
2499 | #ifdef USE_PAM | ||
2500 | /* Pull in any environment variables that may have been set by PAM. */ | ||
2501 | do_pam_environment(&env, &envsize); | ||
2502 | #endif /* USE_PAM */ | ||
2503 | |||
2504 | if (xauthfile) | ||
2505 | child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); | ||
2506 | |||
2507 | if (auth_get_socket_name() != NULL) | ||
2508 | child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, | ||
2509 | auth_get_socket_name()); | ||
2510 | |||
2511 | read_environment_file(&env,&envsize,"/etc/environment"); | ||
2512 | |||
2513 | /* read $HOME/.ssh/environment. */ | ||
2514 | if (!options.use_login) { | ||
2515 | snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir); | ||
2516 | read_environment_file(&env, &envsize, buf); | ||
2517 | } | ||
2518 | if (debug_flag) { | ||
2519 | /* dump the environment */ | ||
2520 | fprintf(stderr, "Environment:\n"); | ||
2521 | for (i = 0; env[i]; i++) | ||
2522 | fprintf(stderr, " %.200s\n", env[i]); | ||
2523 | } | ||
2524 | /* | ||
2525 | * Close the connection descriptors; note that this is the child, and | ||
2526 | * the server will still have the socket open, and it is important | ||
2527 | * that we do not shutdown it. Note that the descriptors cannot be | ||
2528 | * closed before building the environment, as we call | ||
2529 | * get_remote_ipaddr there. | ||
2530 | */ | ||
2531 | if (packet_get_connection_in() == packet_get_connection_out()) | ||
2532 | close(packet_get_connection_in()); | ||
2533 | else { | ||
2534 | close(packet_get_connection_in()); | ||
2535 | close(packet_get_connection_out()); | ||
2536 | } | ||
2537 | /* | ||
2538 | * Close all descriptors related to channels. They will still remain | ||
2539 | * open in the parent. | ||
2540 | */ | ||
2541 | /* XXX better use close-on-exec? -markus */ | ||
2542 | channel_close_all(); | ||
2543 | |||
2544 | /* | ||
2545 | * Close any extra file descriptors. Note that there may still be | ||
2546 | * descriptors left by system functions. They will be closed later. | ||
2547 | */ | ||
2548 | endpwent(); | ||
2549 | |||
2550 | /* | ||
2551 | * Close any extra open file descriptors so that we don\'t have them | ||
2552 | * hanging around in clients. Note that we want to do this after | ||
2553 | * initgroups, because at least on Solaris 2.3 it leaves file | ||
2554 | * descriptors open. | ||
2555 | */ | ||
2556 | for (i = 3; i < 64; i++) | ||
2557 | close(i); | ||
2558 | |||
2559 | /* Change current directory to the user\'s home directory. */ | ||
2560 | if (chdir(pw->pw_dir) < 0) | ||
2561 | fprintf(stderr, "Could not chdir to home directory %s: %s\n", | ||
2562 | pw->pw_dir, strerror(errno)); | ||
2563 | |||
2564 | /* | ||
2565 | * Must take new environment into use so that .ssh/rc, /etc/sshrc and | ||
2566 | * xauth are run in the proper environment. | ||
2567 | */ | ||
2568 | environ = env; | ||
2569 | |||
2570 | /* | ||
2571 | * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first | ||
2572 | * in this order). | ||
2573 | */ | ||
2574 | if (!options.use_login) { | ||
2575 | if (stat(SSH_USER_RC, &st) >= 0) { | ||
2576 | if (debug_flag) | ||
2577 | fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC); | ||
2578 | |||
2579 | f = popen("/bin/sh " SSH_USER_RC, "w"); | ||
2580 | if (f) { | ||
2581 | if (auth_proto != NULL && auth_data != NULL) | ||
2582 | fprintf(f, "%s %s\n", auth_proto, auth_data); | ||
2583 | pclose(f); | ||
2584 | } else | ||
2585 | fprintf(stderr, "Could not run %s\n", SSH_USER_RC); | ||
2586 | } else if (stat(SSH_SYSTEM_RC, &st) >= 0) { | ||
2587 | if (debug_flag) | ||
2588 | fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC); | ||
2589 | |||
2590 | f = popen("/bin/sh " SSH_SYSTEM_RC, "w"); | ||
2591 | if (f) { | ||
2592 | if (auth_proto != NULL && auth_data != NULL) | ||
2593 | fprintf(f, "%s %s\n", auth_proto, auth_data); | ||
2594 | pclose(f); | ||
2595 | } else | ||
2596 | fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC); | ||
2597 | } | ||
2598 | #ifdef XAUTH_PATH | ||
2599 | else { | ||
2600 | /* Add authority data to .Xauthority if appropriate. */ | ||
2601 | if (auth_proto != NULL && auth_data != NULL) { | ||
2602 | if (debug_flag) | ||
2603 | fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n", | ||
2604 | XAUTH_PATH, display, auth_proto, auth_data); | ||
2605 | |||
2606 | f = popen(XAUTH_PATH " -q -", "w"); | ||
2607 | if (f) { | ||
2608 | fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data); | ||
2609 | pclose(f); | ||
2610 | } else | ||
2611 | fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH); | ||
2612 | } | ||
2613 | } | ||
2614 | #endif /* XAUTH_PATH */ | ||
2615 | |||
2616 | /* Get the last component of the shell name. */ | ||
2617 | cp = strrchr(shell, '/'); | ||
2618 | if (cp) | ||
2619 | cp++; | ||
2620 | else | ||
2621 | cp = shell; | ||
2622 | } | ||
2623 | /* | ||
2624 | * If we have no command, execute the shell. In this case, the shell | ||
2625 | * name to be passed in argv[0] is preceded by '-' to indicate that | ||
2626 | * this is a login shell. | ||
2627 | */ | ||
2628 | if (!command) { | ||
2629 | if (!options.use_login) { | ||
2630 | char buf[256]; | ||
2631 | |||
2632 | /* | ||
2633 | * Check for mail if we have a tty and it was enabled | ||
2634 | * in server options. | ||
2635 | */ | ||
2636 | if (ttyname && options.check_mail) { | ||
2637 | char *mailbox; | ||
2638 | struct stat mailstat; | ||
2639 | mailbox = getenv("MAIL"); | ||
2640 | if (mailbox != NULL) { | ||
2641 | if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0) | ||
2642 | printf("No mail.\n"); | ||
2643 | else if (mailstat.st_mtime < mailstat.st_atime) | ||
2644 | printf("You have mail.\n"); | ||
2645 | else | ||
2646 | printf("You have new mail.\n"); | ||
2647 | } | ||
2648 | } | ||
2649 | /* Start the shell. Set initial character to '-'. */ | ||
2650 | buf[0] = '-'; | ||
2651 | strncpy(buf + 1, cp, sizeof(buf) - 1); | ||
2652 | buf[sizeof(buf) - 1] = 0; | ||
2653 | |||
2654 | /* Execute the shell. */ | ||
2655 | argv[0] = buf; | ||
2656 | argv[1] = NULL; | ||
2657 | execve(shell, argv, env); | ||
2658 | |||
2659 | /* Executing the shell failed. */ | ||
2660 | perror(shell); | ||
2661 | exit(1); | ||
2662 | |||
2663 | } else { | ||
2664 | /* Launch login(1). */ | ||
2665 | |||
2666 | execl(LOGIN_PROGRAM, "login", "-h", get_remote_ipaddr(), | ||
2667 | "-p", "-f", "--", pw->pw_name, NULL); | ||
2668 | |||
2669 | /* Login couldn't be executed, die. */ | ||
2670 | |||
2671 | perror("login"); | ||
2672 | exit(1); | ||
2673 | } | ||
2674 | } | ||
2675 | /* | ||
2676 | * Execute the command using the user's shell. This uses the -c | ||
2677 | * option to execute the command. | ||
2678 | */ | ||
2679 | argv[0] = (char *) cp; | ||
2680 | argv[1] = "-c"; | ||
2681 | argv[2] = (char *) command; | ||
2682 | argv[3] = NULL; | ||
2683 | execve(shell, argv, env); | ||
2684 | perror(shell); | ||
2685 | exit(1); | ||
2686 | } | ||