Annotation of src/usr.bin/ssh/ssh.c, Revision 1.1
1.1 ! deraadt 1: /*
! 2:
! 3: ssh.c
! 4:
! 5: Author: Tatu Ylonen <ylo@cs.hut.fi>
! 6:
! 7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
! 8: All rights reserved
! 9:
! 10: Created: Sat Mar 18 16:36:11 1995 ylo
! 11:
! 12: Ssh client program. This program can be used to log into a remote machine.
! 13: The software supports strong authentication, encryption, and forwarding
! 14: of X11, TCP/IP, and authentication connections.
! 15:
! 16: */
! 17:
! 18: #include "includes.h"
! 19: RCSID("$Id: ssh.c,v 1.13 1999/05/11 19:27:16 bg Exp $");
! 20:
! 21: #include "xmalloc.h"
! 22: #include "randoms.h"
! 23: #include "ssh.h"
! 24: #include "packet.h"
! 25: #include "buffer.h"
! 26: #include "authfd.h"
! 27: #include "readconf.h"
! 28: #include "uidswap.h"
! 29:
! 30: /* Random number generator state. This is initialized in ssh_login, and
! 31: left initialized. This is used both by the packet module and by various
! 32: other functions. */
! 33: RandomState random_state;
! 34:
! 35: /* Flag indicating whether debug mode is on. This can be set on the
! 36: command line. */
! 37: int debug_flag = 0;
! 38:
! 39: /* Flag indicating whether quiet mode is on. */
! 40: int quiet_flag = 0;
! 41:
! 42: /* Flag indicating whether to allocate a pseudo tty. This can be set on the
! 43: command line, and is automatically set if no command is given on the command
! 44: line. */
! 45: int tty_flag = 0;
! 46:
! 47: /* Flag indicating that nothing should be read from stdin. This can be set
! 48: on the command line. */
! 49: int stdin_null_flag = 0;
! 50:
! 51: /* Flag indicating that ssh should fork after authentication. This is useful
! 52: so that the pasphrase can be entered manually, and then ssh goes to the
! 53: background. */
! 54: int fork_after_authentication_flag = 0;
! 55:
! 56: /* General data structure for command line options and options configurable
! 57: in configuration files. See readconf.h. */
! 58: Options options;
! 59:
! 60: /* Name of the host we are connecting to. This is the name given on the
! 61: command line, or the HostName specified for the user-supplied name
! 62: in a configuration file. */
! 63: char *host;
! 64:
! 65: #ifdef SIGWINCH
! 66: /* Flag to indicate that we have received a window change signal which has
! 67: not yet been processed. This will cause a message indicating the new
! 68: window size to be sent to the server a little later. This is volatile
! 69: because this is updated in a signal handler. */
! 70: volatile int received_window_change_signal = 0;
! 71: #endif /* SIGWINCH */
! 72:
! 73: /* Value of argv[0] (set in the main program). */
! 74: char *av0;
! 75:
! 76: /* Flag indicating whether we have a valid host private key loaded. */
! 77: int host_private_key_loaded = 0;
! 78:
! 79: /* Host private key. */
! 80: RSAPrivateKey host_private_key;
! 81:
! 82:
! 83: /* Prints a help message to the user. This function never returns. */
! 84:
! 85: void usage()
! 86: {
! 87: int i;
! 88:
! 89: fprintf(stderr, "Usage: %s [options] host [command]\n", av0);
! 90: fprintf(stderr, "Options:\n");
! 91: fprintf(stderr, " -l user Log in using this user name.\n");
! 92: fprintf(stderr, " -n Redirect input from /dev/null.\n");
! 93: fprintf(stderr, " -k Disable authentication agent forwarding.\n");
! 94: #if defined(KERBEROS_TGT_PASSING) || defined(AFS)
! 95: fprintf(stderr, " This also disables passing of AFS tokens/Kerberos tickets.\n");
! 96: #endif /* KERBEROS_TGT_PASSING || AFS */
! 97: fprintf(stderr, " -x Disable X11 connection forwarding.\n");
! 98: fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n");
! 99: fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
! 100: fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
! 101: fprintf(stderr, " -q Quiet; don't display any warning messages.\n");
! 102: fprintf(stderr, " -f Fork into background after authentication.\n");
! 103: fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n");
! 104:
! 105: fprintf(stderr, " -c cipher Select encryption algorithm: ");
! 106: for (i = 1; i <= 6; i++)
! 107: {
! 108: const char *t = cipher_name(i);
! 109: if (t[0] == 'n' && t[1] == 'o' && t[2] == ' ')
! 110: continue;
! 111: fprintf(stderr, "%s, ", t);
! 112: }
! 113: fprintf(stderr, "or none.\n");
! 114:
! 115: fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n");
! 116: fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n");
! 117: fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n");
! 118: fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0);
! 119: fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
! 120: #ifdef WITH_ZLIB
! 121: fprintf(stderr, " -C Enable compression.\n");
! 122: #endif /* WITH_ZLIB */
! 123: fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
! 124: exit(1);
! 125: }
! 126:
! 127: /* Connects to the given host using rsh (or prints an error message and exits
! 128: if rsh is not available). This function never returns. */
! 129:
! 130: void rsh_connect(char *host, char *user, Buffer *command)
! 131: {
! 132: #ifdef RSH_PATH
! 133: char *args[10];
! 134: int i;
! 135:
! 136: log("Using rsh. WARNING: Connection will not be encrypted.");
! 137: /* Build argument list for rsh. */
! 138: i = 0;
! 139: args[i++] = RSH_PATH;
! 140: args[i++] = host; /* may have to come after user on some systems */
! 141: if (user)
! 142: {
! 143: args[i++] = "-l";
! 144: args[i++] = user;
! 145: }
! 146: if (buffer_len(command) > 0)
! 147: {
! 148: buffer_append(command, "\0", 1);
! 149: args[i++] = buffer_ptr(command);
! 150: }
! 151: args[i++] = NULL;
! 152: if (debug_flag)
! 153: {
! 154: for (i = 0; args[i]; i++)
! 155: {
! 156: if (i != 0)
! 157: fprintf(stderr, " ");
! 158: fprintf(stderr, "%s", args[i]);
! 159: }
! 160: fprintf(stderr, "\n");
! 161: }
! 162: execv(RSH_PATH, args);
! 163: perror(RSH_PATH);
! 164: exit(1);
! 165: #else /* RSH_PATH */
! 166: fatal("Rsh not available.");
! 167: #endif /* RSH_PATH */
! 168: }
! 169:
! 170: /* Main program for the ssh client. */
! 171:
! 172: int main(int ac, char **av)
! 173: {
! 174: int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port, authfd;
! 175: char *optarg, *cp, buf[256];
! 176: Buffer command;
! 177: struct winsize ws;
! 178: struct stat st;
! 179: struct passwd *pw, pwcopy;
! 180: int interactive = 0, dummy;
! 181: uid_t original_real_uid;
! 182: uid_t original_effective_uid;
! 183: int plen;
! 184:
! 185: /* Save the original real uid. It will be needed later (uid-swapping may
! 186: clobber the real uid). */
! 187: original_real_uid = getuid();
! 188: original_effective_uid = geteuid();
! 189:
! 190: /* If we are installed setuid root be careful to not drop core. */
! 191: if (original_real_uid != original_effective_uid)
! 192: {
! 193: #ifdef HAVE_SETRLIMIT
! 194: struct rlimit rlim;
! 195: rlim.rlim_cur = rlim.rlim_max = 0;
! 196: if (setrlimit(RLIMIT_CORE, &rlim) < 0)
! 197: fatal("setrlimit failed: %.100s", strerror(errno));
! 198: #else
! 199: fatal("ssh is installed setuid root.\n");
! 200: #endif
! 201: }
! 202:
! 203: /* Use uid-swapping to give up root privileges for the duration of option
! 204: processing. We will re-instantiate the rights when we are ready to
! 205: create the privileged port, and will permanently drop them when the
! 206: port has been created (actually, when the connection has been made, as
! 207: we may need to create the port several times). */
! 208: temporarily_use_uid(original_real_uid);
! 209:
! 210: #ifdef HAVE_UMASK
! 211: /* Set our umask to something reasonable, as some files are created with
! 212: the default umask. This will make them world-readable but writable
! 213: only by the owner, which is ok for all files for which we don't set
! 214: the modes explicitly. */
! 215: umask(022);
! 216: #endif /* HAVE_UMASK */
! 217:
! 218: /* Save our own name. */
! 219: av0 = av[0];
! 220:
! 221: #ifdef SOCKS
! 222: /* Initialize SOCKS (the firewall traversal library). */
! 223: SOCKSinit(av0);
! 224: #endif /* SOCKS */
! 225:
! 226: /* Set RSA (actually gmp) memory allocation functions. */
! 227: rsa_set_mp_memory_allocation();
! 228:
! 229: /* Initialize option structure to indicate that no values have been set. */
! 230: initialize_options(&options);
! 231:
! 232: /* Parse command-line arguments. */
! 233: host = NULL;
! 234:
! 235: /* If program name is not one of the standard names, use it as host name. */
! 236: if (strchr(av0, '/'))
! 237: cp = strrchr(av0, '/') + 1;
! 238: else
! 239: cp = av0;
! 240: if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 &&
! 241: strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0)
! 242: host = cp;
! 243:
! 244: for (optind = 1; optind < ac; optind++)
! 245: {
! 246: if (av[optind][0] != '-')
! 247: {
! 248: if (host)
! 249: break;
! 250: host = av[optind];
! 251: continue;
! 252: }
! 253: opt = av[optind][1];
! 254: if (!opt)
! 255: usage();
! 256: if (strchr("eilcpLRo", opt)) /* options with arguments */
! 257: {
! 258: optarg = av[optind] + 2;
! 259: if (strcmp(optarg, "") == 0)
! 260: {
! 261: if (optind >= ac - 1)
! 262: usage();
! 263: optarg = av[++optind];
! 264: }
! 265: }
! 266: else
! 267: {
! 268: if (av[optind][2])
! 269: usage();
! 270: optarg = NULL;
! 271: }
! 272: switch (opt)
! 273: {
! 274: case 'n':
! 275: stdin_null_flag = 1;
! 276: break;
! 277:
! 278: case 'f':
! 279: fork_after_authentication_flag = 1;
! 280: stdin_null_flag = 1;
! 281: break;
! 282:
! 283: case 'x':
! 284: options.forward_x11 = 0;
! 285: break;
! 286:
! 287: case 'X':
! 288: options.forward_x11 = 1;
! 289: break;
! 290:
! 291: case 'a':
! 292: options.forward_agent = 0;
! 293: #ifdef KERBEROS_TGT_PASSING
! 294: options.kerberos_tgt_passing = 0;
! 295: #endif
! 296: #ifdef AFS
! 297: options.afs_token_passing = 0;
! 298: #endif
! 299: break;
! 300:
! 301: case 'i':
! 302: if (stat(optarg, &st) < 0)
! 303: {
! 304: fprintf(stderr, "Warning: Identity file %s does not exist.\n",
! 305: optarg);
! 306: break;
! 307: }
! 308: if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
! 309: fatal("Too many identity files specified (max %d)",
! 310: SSH_MAX_IDENTITY_FILES);
! 311: options.identity_files[options.num_identity_files++] =
! 312: xstrdup(optarg);
! 313: break;
! 314:
! 315: case 't':
! 316: tty_flag = 1;
! 317: break;
! 318:
! 319: case 'v':
! 320: debug_flag = 1;
! 321: fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
! 322: SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
! 323: #ifdef RSAREF
! 324: fprintf(stderr, "Compiled with RSAREF.\n");
! 325: #elif defined(DO_SSL)
! 326: fprintf(stderr, "Compiled with SSL.\n");
! 327: #else /* RSAREF */
! 328: fprintf(stderr, "Standard version. Does not use RSAREF.\n");
! 329: #endif /* RSAREF */
! 330: break;
! 331:
! 332: case 'q':
! 333: quiet_flag = 1;
! 334: break;
! 335:
! 336: case 'e':
! 337: if (optarg[0] == '^' && optarg[2] == 0 &&
! 338: (unsigned char)optarg[1] >= 64 && (unsigned char)optarg[1] < 128)
! 339: options.escape_char = (unsigned char)optarg[1] & 31;
! 340: else
! 341: if (strlen(optarg) == 1)
! 342: options.escape_char = (unsigned char)optarg[0];
! 343: else
! 344: if (strcmp(optarg, "none") == 0)
! 345: options.escape_char = -2;
! 346: else
! 347: {
! 348: fprintf(stderr, "Bad escape character '%s'.\n", optarg);
! 349: exit(1);
! 350: }
! 351: break;
! 352:
! 353: case 'c':
! 354: options.cipher = cipher_number(optarg);
! 355: if (options.cipher == -1)
! 356: {
! 357: fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
! 358: exit(1);
! 359: }
! 360: break;
! 361:
! 362: case 'p':
! 363: options.port = atoi(optarg);
! 364: if (options.port < 1 || options.port > 65535)
! 365: {
! 366: fprintf(stderr, "Bad port %s.\n", optarg);
! 367: exit(1);
! 368: }
! 369: break;
! 370:
! 371: case 'l':
! 372: options.user = optarg;
! 373: break;
! 374:
! 375: case 'R':
! 376: if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
! 377: &fwd_host_port) != 3)
! 378: {
! 379: fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
! 380: usage();
! 381: /*NOTREACHED*/
! 382: }
! 383: add_remote_forward(&options, fwd_port, buf, fwd_host_port);
! 384: break;
! 385:
! 386: case 'L':
! 387: if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
! 388: &fwd_host_port) != 3)
! 389: {
! 390: fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
! 391: usage();
! 392: /*NOTREACHED*/
! 393: }
! 394: if (fwd_port < 1024 && original_real_uid != 0)
! 395: {
! 396: fprintf(stderr,
! 397: "Privileged ports can only be forwarded by root.\n");
! 398: exit(1);
! 399: }
! 400: add_local_forward(&options, fwd_port, buf, fwd_host_port);
! 401: break;
! 402:
! 403: #ifdef WITH_ZLIB
! 404: case 'C':
! 405: options.compression = 1;
! 406: break;
! 407: #endif /* WITH_ZLIB */
! 408:
! 409: case 'o':
! 410: dummy = 1;
! 411: process_config_line(&options, host ? host : "", optarg,
! 412: "command-line", 0, &dummy);
! 413: break;
! 414:
! 415: default:
! 416: usage();
! 417: }
! 418: }
! 419:
! 420: /* Check that we got a host name. */
! 421: if (!host)
! 422: usage();
! 423:
! 424: /* Initialize the command to execute on remote host. */
! 425: buffer_init(&command);
! 426:
! 427: /* Save the command to execute on the remote host in a buffer. There is
! 428: no limit on the length of the command, except by the maximum packet
! 429: size. Also sets the tty flag if there is no command. */
! 430: if (optind == ac)
! 431: {
! 432: /* No command specified - execute shell on a tty. */
! 433: tty_flag = 1;
! 434: }
! 435: else
! 436: {
! 437: /* A command has been specified. Store it into the buffer. */
! 438: for (i = optind; i < ac; i++)
! 439: {
! 440: if (i > optind)
! 441: buffer_append(&command, " ", 1);
! 442: buffer_append(&command, av[i], strlen(av[i]));
! 443: }
! 444: }
! 445:
! 446: /* Cannot fork to background if no command. */
! 447: if (fork_after_authentication_flag && buffer_len(&command) == 0)
! 448: fatal("Cannot fork into background without a command to execute.");
! 449:
! 450: /* Allocate a tty by default if no command specified. */
! 451: if (buffer_len(&command) == 0)
! 452: tty_flag = 1;
! 453:
! 454: /* Do not allocate a tty if stdin is not a tty. */
! 455: if (!isatty(fileno(stdin)))
! 456: {
! 457: if (tty_flag)
! 458: fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
! 459: tty_flag = 0;
! 460: }
! 461:
! 462: /* Get user data. */
! 463: pw = getpwuid(original_real_uid);
! 464: if (!pw)
! 465: {
! 466: fprintf(stderr, "You don't exist, go away!\n");
! 467: exit(1);
! 468: }
! 469:
! 470: /* Take a copy of the returned structure. */
! 471: memset(&pwcopy, 0, sizeof(pwcopy));
! 472: pwcopy.pw_name = xstrdup(pw->pw_name);
! 473: pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
! 474: pwcopy.pw_uid = pw->pw_uid;
! 475: pwcopy.pw_gid = pw->pw_gid;
! 476: pwcopy.pw_dir = xstrdup(pw->pw_dir);
! 477: pwcopy.pw_shell = xstrdup(pw->pw_shell);
! 478: pw = &pwcopy;
! 479:
! 480: /* Initialize "log" output. Since we are the client all output actually
! 481: goes to the terminal. */
! 482: log_init(av[0], 1, debug_flag, quiet_flag, SYSLOG_FACILITY_USER);
! 483:
! 484: /* Read per-user configuration file. */
! 485: sprintf(buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE);
! 486: read_config_file(buf, host, &options);
! 487:
! 488: /* Read systemwide configuration file. */
! 489: read_config_file(HOST_CONFIG_FILE, host, &options);
! 490:
! 491: /* Fill configuration defaults. */
! 492: fill_default_options(&options);
! 493: if (options.user == NULL)
! 494: options.user = xstrdup(pw->pw_name);
! 495:
! 496: if (options.hostname != NULL)
! 497: host = options.hostname;
! 498:
! 499: /* Find canonic host name. */
! 500: if (strchr(host, '.') == 0)
! 501: {
! 502: struct hostent *hp = gethostbyname(host);
! 503: if (hp != 0)
! 504: {
! 505: if (strchr(hp->h_name, '.') != 0)
! 506: host = xstrdup(hp->h_name);
! 507: else if (hp->h_aliases != 0
! 508: && hp->h_aliases[0] != 0
! 509: && strchr(hp->h_aliases[0], '.') != 0)
! 510: host = xstrdup(hp->h_aliases[0]);
! 511: }
! 512: }
! 513:
! 514: /* Disable rhosts authentication if not running as root. */
! 515: if (original_effective_uid != 0)
! 516: {
! 517: options.rhosts_authentication = 0;
! 518: options.rhosts_rsa_authentication = 0;
! 519: }
! 520:
! 521: /* If using rsh has been selected, exec it now (without trying anything
! 522: else). Note that we must release privileges first. */
! 523: if (options.use_rsh)
! 524: {
! 525: /* Restore our superuser privileges. This must be done before
! 526: permanently setting the uid. */
! 527: restore_uid();
! 528:
! 529: /* Switch to the original uid permanently. */
! 530: permanently_set_uid(original_real_uid);
! 531:
! 532: /* Execute rsh. */
! 533: rsh_connect(host, options.user, &command);
! 534: fatal("rsh_connect returned");
! 535: }
! 536:
! 537: /* Restore our superuser privileges. */
! 538: restore_uid();
! 539:
! 540: /* Open a connection to the remote host. This needs root privileges if
! 541: rhosts_authentication is true. Note that the random_state is not
! 542: yet used by this call, although a pointer to it is stored, and thus it
! 543: need not be initialized. */
! 544: ok = ssh_connect(host, options.port, options.connection_attempts,
! 545: !options.rhosts_authentication &&
! 546: !options.rhosts_rsa_authentication,
! 547: original_real_uid, options.proxy_command, &random_state);
! 548:
! 549: /* If we successfully made the connection, load the host private key in
! 550: case we will need it later for combined rsa-rhosts authentication.
! 551: This must be done before releasing extra privileges, because the file
! 552: is only readable by root. */
! 553: if (ok)
! 554: {
! 555: if (load_private_key(HOST_KEY_FILE, "", &host_private_key, NULL))
! 556: host_private_key_loaded = 1;
! 557: }
! 558:
! 559: /* Get rid of any extra privileges that we may have. We will no longer need
! 560: them. Also, extra privileges could make it very hard to read identity
! 561: files and other non-world-readable files from the user's home directory
! 562: if it happens to be on a NFS volume where root is mapped to nobody. */
! 563: permanently_set_uid(original_real_uid);
! 564:
! 565: /* Now that we are back to our own permissions, create ~/.ssh directory
! 566: if it doesn\'t already exist. */
! 567: sprintf(buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
! 568: if (stat(buf, &st) < 0)
! 569: if (mkdir(buf, 0755) < 0)
! 570: error("Could not create directory '%.200s'.", buf);
! 571:
! 572: /* Check if the connection failed, and try "rsh" if appropriate. */
! 573: if (!ok)
! 574: {
! 575: if (options.port != 0)
! 576: log("Secure connection to %.100s on port %d refused%.100s.",
! 577: host, options.port,
! 578: options.fallback_to_rsh ? "; reverting to insecure method" : "");
! 579: else
! 580: log("Secure connection to %.100s refused%.100s.", host,
! 581: options.fallback_to_rsh ? "; reverting to insecure method" : "");
! 582:
! 583: if (options.fallback_to_rsh)
! 584: {
! 585: rsh_connect(host, options.user, &command);
! 586: fatal("rsh_connect returned");
! 587: }
! 588: exit(1);
! 589: }
! 590:
! 591: /* Expand ~ in options.identity_files. */
! 592: for (i = 0; i < options.num_identity_files; i++)
! 593: options.identity_files[i] =
! 594: tilde_expand_filename(options.identity_files[i], original_real_uid);
! 595:
! 596: /* Expand ~ in known host file names. */
! 597: options.system_hostfile = tilde_expand_filename(options.system_hostfile,
! 598: original_real_uid);
! 599: options.user_hostfile = tilde_expand_filename(options.user_hostfile,
! 600: original_real_uid);
! 601:
! 602: /* Log into the remote system. This never returns if the login fails.
! 603: Note: this initializes the random state, and leaves it initialized. */
! 604: ssh_login(&random_state, host_private_key_loaded, &host_private_key,
! 605: host, &options, original_real_uid);
! 606:
! 607: /* We no longer need the host private key. Clear it now. */
! 608: if (host_private_key_loaded)
! 609: rsa_clear_private_key(&host_private_key);
! 610:
! 611: /* Close connection cleanly after attack. */
! 612: cipher_attack_detected = packet_disconnect;
! 613:
! 614: /* If requested, fork and let ssh continue in the background. */
! 615: if (fork_after_authentication_flag)
! 616: {
! 617: int ret = fork();
! 618: if (ret == -1)
! 619: fatal("fork failed: %.100s", strerror(errno));
! 620: if (ret != 0)
! 621: exit(0);
! 622: #ifdef HAVE_SETSID
! 623: setsid();
! 624: #endif /* HAVE_SETSID */
! 625: }
! 626:
! 627: #ifdef WITH_ZLIB
! 628: /* Enable compression if requested. */
! 629: if (options.compression)
! 630: {
! 631: debug("Requesting compression at level %d.", options.compression_level);
! 632:
! 633: if (options.compression_level < 1 || options.compression_level > 9)
! 634: fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
! 635:
! 636: /* Send the request. */
! 637: packet_start(SSH_CMSG_REQUEST_COMPRESSION);
! 638: packet_put_int(options.compression_level);
! 639: packet_send();
! 640: packet_write_wait();
! 641: type = packet_read(&plen);
! 642: if (type == SSH_SMSG_SUCCESS)
! 643: packet_start_compression(options.compression_level);
! 644: else if (type == SSH_SMSG_FAILURE)
! 645: log("Warning: Remote host refused compression.");
! 646: else
! 647: packet_disconnect("Protocol error waiting for compression response.");
! 648: }
! 649: #endif /* WITH_ZLIB */
! 650:
! 651: /* Allocate a pseudo tty if appropriate. */
! 652: if (tty_flag)
! 653: {
! 654: debug("Requesting pty.");
! 655:
! 656: /* Start the packet. */
! 657: packet_start(SSH_CMSG_REQUEST_PTY);
! 658:
! 659: /* Store TERM in the packet. There is no limit on the length of the
! 660: string. */
! 661: cp = getenv("TERM");
! 662: if (!cp)
! 663: cp = "";
! 664: packet_put_string(cp, strlen(cp));
! 665:
! 666: /* Store window size in the packet. */
! 667: if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
! 668: memset(&ws, 0, sizeof(ws));
! 669: packet_put_int(ws.ws_row);
! 670: packet_put_int(ws.ws_col);
! 671: packet_put_int(ws.ws_xpixel);
! 672: packet_put_int(ws.ws_ypixel);
! 673:
! 674: /* Store tty modes in the packet. */
! 675: tty_make_modes(fileno(stdin));
! 676:
! 677: /* Send the packet, and wait for it to leave. */
! 678: packet_send();
! 679: packet_write_wait();
! 680:
! 681: /* Read response from the server. */
! 682: type = packet_read(&plen);
! 683: if (type == SSH_SMSG_SUCCESS)
! 684: interactive = 1;
! 685: else if (type == SSH_SMSG_FAILURE)
! 686: log("Warning: Remote host failed or refused to allocate a pseudo tty.");
! 687: else
! 688: packet_disconnect("Protocol error waiting for pty request response.");
! 689: }
! 690:
! 691: /* Request X11 forwarding if enabled and DISPLAY is set. */
! 692: if (options.forward_x11 && getenv("DISPLAY") != NULL)
! 693: {
! 694: char line[512], proto[512], data[512];
! 695: FILE *f;
! 696: int forwarded = 0, got_data = 0, i;
! 697:
! 698: #ifdef XAUTH_PATH
! 699: /* Try to get Xauthority information for the display. */
! 700: sprintf(line, "%.100s list %.200s 2>/dev/null",
! 701: XAUTH_PATH, getenv("DISPLAY"));
! 702: f = popen(line, "r");
! 703: if (f && fgets(line, sizeof(line), f) &&
! 704: sscanf(line, "%*s %s %s", proto, data) == 2)
! 705: got_data = 1;
! 706: if (f)
! 707: pclose(f);
! 708: #endif /* XAUTH_PATH */
! 709: /* If we didn't get authentication data, just make up some data. The
! 710: forwarding code will check the validity of the response anyway, and
! 711: substitute this data. The X11 server, however, will ignore this
! 712: fake data and use whatever authentication mechanisms it was using
! 713: otherwise for the local connection. */
! 714: if (!got_data)
! 715: {
! 716: strcpy(proto, "MIT-MAGIC-COOKIE-1");
! 717: for (i = 0; i < 16; i++)
! 718: sprintf(data + 2 * i, "%02x", random_get_byte(&random_state));
! 719: }
! 720:
! 721: /* Got local authentication reasonable information. Request forwarding
! 722: with authentication spoofing. */
! 723: debug("Requesting X11 forwarding with authentication spoofing.");
! 724: x11_request_forwarding_with_spoofing(&random_state, proto, data);
! 725:
! 726: /* Read response from the server. */
! 727: type = packet_read(&plen);
! 728: if (type == SSH_SMSG_SUCCESS)
! 729: {
! 730: forwarded = 1;
! 731: interactive = 1;
! 732: }
! 733: else if (type == SSH_SMSG_FAILURE)
! 734: log("Warning: Remote host denied X11 forwarding.");
! 735: else
! 736: packet_disconnect("Protocol error waiting for X11 forwarding");
! 737: }
! 738:
! 739: /* Tell the packet module whether this is an interactive session. */
! 740: packet_set_interactive(interactive, options.keepalives);
! 741:
! 742: /* Clear agent forwarding if we don\'t have an agent. */
! 743: authfd = ssh_get_authentication_fd();
! 744: if (authfd < 0)
! 745: options.forward_agent = 0;
! 746: else
! 747: ssh_close_authentication_socket(authfd);
! 748:
! 749: /* Request authentication agent forwarding if appropriate. */
! 750: if (options.forward_agent)
! 751: {
! 752: debug("Requesting authentication agent forwarding.");
! 753: auth_request_forwarding();
! 754:
! 755: /* Read response from the server. */
! 756: type = packet_read(&plen);
! 757: packet_integrity_check(plen, 0, type);
! 758: if (type != SSH_SMSG_SUCCESS)
! 759: log("Warning: Remote host denied authentication agent forwarding.");
! 760: }
! 761:
! 762: /* Initiate local TCP/IP port forwardings. */
! 763: for (i = 0; i < options.num_local_forwards; i++)
! 764: {
! 765: debug("Connections to local port %d forwarded to remote address %.200s:%d",
! 766: options.local_forwards[i].port, options.local_forwards[i].host,
! 767: options.local_forwards[i].host_port);
! 768: channel_request_local_forwarding(options.local_forwards[i].port,
! 769: options.local_forwards[i].host,
! 770: options.local_forwards[i].host_port);
! 771: }
! 772:
! 773: /* Initiate remote TCP/IP port forwardings. */
! 774: for (i = 0; i < options.num_remote_forwards; i++)
! 775: {
! 776: debug("Connections to remote port %d forwarded to local address %.200s:%d",
! 777: options.remote_forwards[i].port, options.remote_forwards[i].host,
! 778: options.remote_forwards[i].host_port);
! 779: channel_request_remote_forwarding(options.remote_forwards[i].port,
! 780: options.remote_forwards[i].host,
! 781: options.remote_forwards[i].host_port);
! 782: }
! 783:
! 784: /* If a command was specified on the command line, execute the command now.
! 785: Otherwise request the server to start a shell. */
! 786: if (buffer_len(&command) > 0)
! 787: {
! 788: int len = buffer_len(&command);
! 789: if (len > 900)
! 790: len = 900;
! 791: debug("Sending command: %.*s", len, buffer_ptr(&command));
! 792: packet_start(SSH_CMSG_EXEC_CMD);
! 793: packet_put_string(buffer_ptr(&command), buffer_len(&command));
! 794: packet_send();
! 795: packet_write_wait();
! 796: }
! 797: else
! 798: {
! 799: debug("Requesting shell.");
! 800: packet_start(SSH_CMSG_EXEC_SHELL);
! 801: packet_send();
! 802: packet_write_wait();
! 803: }
! 804:
! 805: /* Enter the interactive session. */
! 806: exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1);
! 807:
! 808: /* Close the connection to the remote host. */
! 809: packet_close();
! 810:
! 811: /* Exit with the status returned by the program on the remote side. */
! 812: exit(exit_status);
! 813: }