summaryrefslogtreecommitdiff
path: root/other/ssharp/sshconnect.c
diff options
context:
space:
mode:
authorSkyperTHC2026-03-03 06:28:55 +0000
committerSkyperTHC2026-03-03 06:28:55 +0000
commit5d3573ef7a109ee70416fe94db098fe6a769a798 (patch)
treedc2d5b294c9db8ab2db7433511f94e1c4bb8b698 /other/ssharp/sshconnect.c
parentc6c59dc73cc4586357f93ab38ecf459e98675cc5 (diff)
packetstorm sync
Diffstat (limited to 'other/ssharp/sshconnect.c')
-rw-r--r--other/ssharp/sshconnect.c497
1 files changed, 497 insertions, 0 deletions
diff --git a/other/ssharp/sshconnect.c b/other/ssharp/sshconnect.c
new file mode 100644
index 0000000..d964c5f
--- /dev/null
+++ b/other/ssharp/sshconnect.c
@@ -0,0 +1,497 @@
1/*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
5 * Code to connect to a remote host, and to perform the client side of the
6 * login (authentication) dialog.
7 *
8 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose. Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
13 */
14
15#include "includes.h"
16RCSID("$OpenBSD: sshconnect.c,v 1.104 2001/04/12 19:15:25 markus Exp $");
17
18#include <openssl/bn.h>
19
20#include "ssh.h"
21#include "xmalloc.h"
22#include "rsa.h"
23#include "buffer.h"
24#include "packet.h"
25#include "uidswap.h"
26#include "compat.h"
27#include "key.h"
28#include "sshconnect.h"
29#include "hostfile.h"
30#include "log.h"
31#include "readconf.h"
32#include "atomicio.h"
33#include "misc.h"
34#include "ssharp.h"
35
36char *client_version_string = NULL;
37char *server_version_string = NULL;
38
39extern Options options;
40extern char *__progname;
41
42/* AF_UNSPEC or AF_INET or AF_INET6 */
43extern int IPv4or6;
44
45/*
46 * Connect to the given ssh server using a proxy command.
47 */
48int
49ssh_proxy_connect(const char *host, u_short port,
50 const char *proxy_command)
51{
52 Buffer command;
53 const char *cp;
54 char *command_string;
55 int pin[2], pout[2];
56 pid_t pid;
57 char strport[NI_MAXSERV];
58
59 /* Convert the port number into a string. */
60 snprintf(strport, sizeof strport, "%hu", port);
61
62 /* Build the final command string in the buffer by making the
63 appropriate substitutions to the given proxy command. */
64 buffer_init(&command);
65 for (cp = proxy_command; *cp; cp++) {
66 if (cp[0] == '%' && cp[1] == '%') {
67 buffer_append(&command, "%", 1);
68 cp++;
69 continue;
70 }
71 if (cp[0] == '%' && cp[1] == 'h') {
72 buffer_append(&command, host, strlen(host));
73 cp++;
74 continue;
75 }
76 if (cp[0] == '%' && cp[1] == 'p') {
77 buffer_append(&command, strport, strlen(strport));
78 cp++;
79 continue;
80 }
81 buffer_append(&command, cp, 1);
82 }
83 buffer_append(&command, "\0", 1);
84
85 /* Get the final command string. */
86 command_string = buffer_ptr(&command);
87
88 /* Create pipes for communicating with the proxy. */
89 if (pipe(pin) < 0 || pipe(pout) < 0)
90 fatal("Could not create pipes to communicate with the proxy: %.100s",
91 strerror(errno));
92
93 debug("Executing proxy command: %.500s", command_string);
94
95 /* Fork and execute the proxy command. */
96 if ((pid = fork()) == 0) {
97 char *argv[10];
98
99
100 /* Redirect stdin and stdout. */
101 close(pin[1]);
102 if (pin[0] != 0) {
103 if (dup2(pin[0], 0) < 0)
104 perror("dup2 stdin");
105 close(pin[0]);
106 }
107 close(pout[0]);
108 if (dup2(pout[1], 1) < 0)
109 perror("dup2 stdout");
110 /* Cannot be 1 because pin allocated two descriptors. */
111 close(pout[1]);
112
113 /* Stderr is left as it is so that error messages get
114 printed on the user's terminal. */
115 argv[0] = _PATH_BSHELL;
116 argv[1] = "-c";
117 argv[2] = command_string;
118 argv[3] = NULL;
119
120 /* Execute the proxy command. Note that we gave up any
121 extra privileges above. */
122 execv(argv[0], argv);
123 perror(argv[0]);
124 exit(1);
125 }
126 /* Parent. */
127 if (pid < 0)
128 fatal("fork failed: %.100s", strerror(errno));
129
130 /* Close child side of the descriptors. */
131 close(pin[0]);
132 close(pout[1]);
133
134 /* Free the command name. */
135 buffer_free(&command);
136
137 /* Set the connection file descriptors. */
138 packet_set_connection(pout[0], pin[1]);
139
140 return 1;
141}
142
143
144/*
145 * Creates a (possibly privileged) socket for use as the ssh connection.
146 */
147int
148ssh_create_socket(int family)
149{
150 int sock = socket(family, SOCK_STREAM, 0);
151 return sock;
152}
153
154/*
155 * Opens a TCP/IP connection to the remote server on the given host.
156 * The address of the remote host will be returned in hostaddr.
157 * If port is 0, the default port will be used. If anonymous is zero,
158 * a privileged port will be allocated to make the connection.
159 * This requires super-user privileges if anonymous is false.
160 * Connection_attempts specifies the maximum number of tries (one per
161 * second). If proxy_command is non-NULL, it specifies the command (with %h
162 * and %p substituted for host and port, respectively) to use to contact
163 * the daemon.
164 */
165int
166ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
167 u_short port, int connection_attempts,
168 int anonymous,
169 const char *proxy_command)
170{
171 int gaierr;
172 int on = 1;
173 int sock = -1, attempt;
174 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
175 struct addrinfo hints, *ai, *aitop;
176 struct linger linger;
177 struct servent *sp;
178
179 debug("ssh_connect: getuid %u geteuid %u anon %d",
180 (u_int) getuid(), (u_int) geteuid(), anonymous);
181
182 /* Get default port if port has not been set. */
183 if (port == 0) {
184 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
185 if (sp)
186 port = ntohs(sp->s_port);
187 else
188 port = SSH_DEFAULT_PORT;
189 }
190 /* If a proxy command is given, connect using it. */
191 if (proxy_command != NULL)
192 return ssh_proxy_connect(host, port, proxy_command);
193
194 /* No proxy command. */
195
196 memset(&hints, 0, sizeof(hints));
197 hints.ai_family = IPv4or6;
198 hints.ai_socktype = SOCK_STREAM;
199 snprintf(strport, sizeof strport, "%d", port);
200 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
201 fatal("%s: %.100s: %s", __progname, host,
202 gai_strerror(gaierr));
203
204 /*
205 * Try to connect several times. On some machines, the first time
206 * will sometimes fail. In general socket code appears to behave
207 * quite magically on many machines.
208 */
209 for (attempt = 0; attempt < connection_attempts; attempt++) {
210 if (attempt > 0)
211 debug("Trying again...");
212
213 /* Loop through addresses for this host, and try each one in
214 sequence until the connection succeeds. */
215 for (ai = aitop; ai; ai = ai->ai_next) {
216 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
217 continue;
218 if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
219 ntop, sizeof(ntop), strport, sizeof(strport),
220 NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
221 error("ssh_connect: getnameinfo failed");
222 continue;
223 }
224 debug("Connecting to %.200s [%.100s] port %s.",
225 host, ntop, strport);
226
227
228 if ((sock = socket_connect_b(ai->ai_addr, ai->ai_addrlen, SSHARP_MINPORT)) >= 0) {
229 /* Successful connection. */
230 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
231 break;
232 } else {
233 debug("connect: %.100s", strerror(errno));
234 /*
235 * Close the failed socket; there appear to
236 * be some problems when reusing a socket for
237 * which connect() has already returned an
238 * error.
239 */
240 shutdown(sock, SHUT_RDWR);
241 close(sock);
242 }
243 }
244 if (ai)
245 break; /* Successful connection. */
246
247 /* Sleep a moment before retrying. */
248 sleep(1);
249 }
250
251 freeaddrinfo(aitop);
252
253 /* Return failure if we didn't get a successful connection. */
254 if (attempt >= connection_attempts)
255 return 0;
256
257 debug("Connection established.");
258
259 /*
260 * Set socket options. We would like the socket to disappear as soon
261 * as it has been closed for whatever reason.
262 */
263 /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
264 linger.l_onoff = 1;
265 linger.l_linger = 5;
266 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
267
268 /* Set keepalives if requested. */
269 if (options.keepalives &&
270 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
271 sizeof(on)) < 0)
272 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
273
274 /* Set the connection. */
275 packet_set_connection(sock, sock);
276
277 return 1;
278}
279
280/*
281 * Waits for the server identification string, and sends our own
282 * identification string.
283 */
284void
285ssh_exchange_identification(void)
286{
287 char buf[256], remote_version[256]; /* must be same size! */
288 int remote_major, remote_minor, i, mismatch;
289 int connection_in = packet_get_connection_in();
290 int connection_out = packet_get_connection_out();
291 int minor1 = PROTOCOL_MINOR_1;
292
293 /* Read other side\'s version identification. */
294 for (;;) {
295 for (i = 0; i < sizeof(buf) - 1; i++) {
296 int len = atomicio(read, connection_in, &buf[i], 1);
297 if (len < 0)
298 fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
299 if (len != 1)
300 fatal("ssh_exchange_identification: Connection closed by remote host");
301 if (buf[i] == '\r') {
302 buf[i] = '\n';
303 buf[i + 1] = 0;
304 continue; /**XXX wait for \n */
305 }
306 if (buf[i] == '\n') {
307 buf[i + 1] = 0;
308 break;
309 }
310 }
311 buf[sizeof(buf) - 1] = 0;
312 if (strncmp(buf, "SSH-", 4) == 0)
313 break;
314 debug("ssh_exchange_identification: %s", buf);
315 }
316 server_version_string = xstrdup(buf);
317
318 /*
319 * Check that the versions match. In future this might accept
320 * several versions and set appropriate flags to handle them.
321 */
322 if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
323 &remote_major, &remote_minor, remote_version) != 3)
324 fatal("Bad remote protocol version identification: '%.100s'", buf);
325 debug("Remote protocol version %d.%d, remote software version %.100s",
326 remote_major, remote_minor, remote_version);
327
328 compat_datafellows(remote_version);
329 mismatch = 0;
330
331 switch(remote_major) {
332 case 1:
333 if (remote_minor == 99 &&
334 (options.protocol & SSH_PROTO_2) &&
335 !(options.protocol & SSH_PROTO_1_PREFERRED)) {
336 enable_compat20();
337 break;
338 }
339 if (!(options.protocol & SSH_PROTO_1)) {
340 mismatch = 1;
341 break;
342 }
343 if (remote_minor < 3) {
344 fatal("Remote machine has too old SSH software version.");
345 } else if (remote_minor == 3 || remote_minor == 4) {
346 /* We speak 1.3, too. */
347 enable_compat13();
348 minor1 = 3;
349 if (options.forward_agent) {
350 log("Agent forwarding disabled for protocol 1.3");
351 options.forward_agent = 0;
352 }
353 }
354 break;
355 case 2:
356 if (options.protocol & SSH_PROTO_2) {
357 enable_compat20();
358 break;
359 }
360 /* FALLTHROUGH */
361 default:
362 mismatch = 1;
363 break;
364 }
365 if (mismatch)
366 fatal("Protocol major versions differ: %d vs. %d",
367 (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
368 remote_major);
369 if (compat20)
370 packet_set_ssh2_format();
371 /* Send our own protocol version identification. */
372 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
373 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
374 compat20 ? PROTOCOL_MINOR_2 : minor1,
375 SSH_VERSION);
376 if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
377 fatal("write: %.100s", strerror(errno));
378 client_version_string = xstrdup(buf);
379 chop(client_version_string);
380 chop(server_version_string);
381 debug("Local version string %.100s", client_version_string);
382}
383
384/* defaults to 'no' */
385int
386read_yes_or_no(const char *prompt, int defval)
387{
388 char buf[1024];
389 FILE *f;
390 int retval = -1;
391
392 if (options.batch_mode)
393 return 0;
394
395 if (isatty(STDIN_FILENO))
396 f = stdin;
397 else
398 f = fopen(_PATH_TTY, "rw");
399
400 if (f == NULL)
401 return 0;
402
403 fflush(stdout);
404
405 while (1) {
406 fprintf(stderr, "%s", prompt);
407 if (fgets(buf, sizeof(buf), f) == NULL) {
408 /* Print a newline (the prompt probably didn\'t have one). */
409 fprintf(stderr, "\n");
410 strlcpy(buf, "no", sizeof buf);
411 }
412 /* Remove newline from response. */
413 if (strchr(buf, '\n'))
414 *strchr(buf, '\n') = 0;
415
416 if (buf[0] == 0)
417 retval = defval;
418 if (strcmp(buf, "yes") == 0)
419 retval = 1;
420 else if (strcmp(buf, "no") == 0)
421 retval = 0;
422 else
423 fprintf(stderr, "Please type 'yes' or 'no'.\n");
424
425 if (retval != -1) {
426 if (f != stdin)
427 fclose(f);
428 return retval;
429 }
430 }
431}
432
433/*
434 * check whether the supplied host key is valid, return only if ok.
435 */
436
437void
438check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
439 const char *user_hostfile, const char *system_hostfile)
440{
441 /* SSHARP: dummy */
442}
443
444/*
445 * Starts a dialog with the server, and authenticates the current user on the
446 * server. This does not need any extra privileges. The basic connection
447 * to the server must already have been established before this is called.
448 * If login fails, this function prints an error and never returns.
449 * This function does not require super-user privileges.
450 */
451void
452ssh_login(Key **keys, int nkeys, const char *orighost,
453 struct sockaddr *hostaddr, char *login, char *pass)
454{
455 char *host, *cp;
456
457 /* Convert the user-supplied hostname into all lowercase. */
458 host = xstrdup(orighost);
459 for (cp = host; *cp; cp++)
460 if (isupper(*cp))
461 *cp = tolower(*cp);
462
463 /* Exchange protocol version identification strings with the server. */
464 ssh_exchange_identification();
465
466 /* Put the connection into non-blocking mode. */
467 packet_set_nonblocking();
468
469 /* key exchange */
470 /* authenticate user */
471 if (compat20) {
472 ssh_kex2(host, hostaddr);
473 ssh_userauth2(login, pass, host, keys, nkeys);
474 } else {
475 ssh_kex(host, hostaddr);
476 ssh_userauth1(login, pass, host, keys, nkeys);
477 }
478}
479
480void
481ssh_put_password(char *password)
482{
483 int size;
484 char *padded;
485
486 if (datafellows & SSH_BUG_PASSWORDPAD) {
487 packet_put_string(password, strlen(password));
488 return;
489 }
490 size = roundup(strlen(password) + 1, 32);
491 padded = xmalloc(size);
492 memset(padded, 0, size);
493 strlcpy(padded, password, size);
494 packet_put_string(padded, size);
495 memset(padded, 0, size);
496 xfree(padded);
497}