📄 clientloop.c
字号:
/* * Read input from the server, and add any such data to the buffer of * the packet subsystem. */ if (FD_ISSET(connection_in, readset)) { /* Read as much as possible. */ len = read(connection_in, buf, sizeof(buf)); if (len == 0) { /* Received EOF. The remote host has closed the connection. */ snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", host); buffer_append(&stderr_buffer, buf, strlen(buf)); quit_pending = 1; return; } /* * There is a kernel bug on Solaris that causes select to * sometimes wake up even though there is no data available. */ if (len < 0 && (errno == EAGAIN || errno == EINTR)) len = 0; if (len < 0) { /* An error has encountered. Perhaps there is a network problem. */ snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", host, strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); quit_pending = 1; return; } packet_process_incoming(buf, len); }}static voidclient_subsystem_reply(int type, u_int32_t seq, void *ctxt){ int id; Channel *c; id = packet_get_int(); packet_check_eom(); if ((c = channel_lookup(id)) == NULL) { error("%s: no channel for id %d", __func__, id); return; } if (type == SSH2_MSG_CHANNEL_SUCCESS) debug2("Request suceeded on channel %d", id); else if (type == SSH2_MSG_CHANNEL_FAILURE) { error("Request failed on channel %d", id); channel_free(c); }}static voidclient_extra_session2_setup(int id, void *arg){ struct confirm_ctx *cctx = arg; Channel *c; int i; if (cctx == NULL) fatal("%s: cctx == NULL", __func__); if ((c = channel_lookup(id)) == NULL) fatal("%s: no channel for id %d", __func__, id); client_session2_setup(id, cctx->want_tty, cctx->want_subsys, cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, client_subsystem_reply); c->confirm_ctx = NULL; buffer_free(&cctx->cmd); xfree(cctx->term); if (cctx->env != NULL) { for (i = 0; cctx->env[i] != NULL; i++) xfree(cctx->env[i]); xfree(cctx->env); } xfree(cctx);}static voidclient_process_control(fd_set * readset){ Buffer m; Channel *c; int client_fd, new_fd[3], ver, i, allowed; socklen_t addrlen; struct sockaddr_storage addr; struct confirm_ctx *cctx; char *cmd; u_int len, env_len, command, flags; uid_t euid; gid_t egid; /* * Accept connection on control socket */ if (control_fd == -1 || !FD_ISSET(control_fd, readset)) return; memset(&addr, 0, sizeof(addr)); addrlen = sizeof(addr); if ((client_fd = accept(control_fd, (struct sockaddr*)&addr, &addrlen)) == -1) { error("%s accept: %s", __func__, strerror(errno)); return; } if (getpeereid(client_fd, &euid, &egid) < 0) { error("%s getpeereid failed: %s", __func__, strerror(errno)); close(client_fd); return; } if ((euid != 0) && (getuid() != euid)) { error("control mode uid mismatch: peer euid %u != uid %u", (u_int) euid, (u_int) getuid()); close(client_fd); return; } unset_nonblock(client_fd); /* Read command */ buffer_init(&m); if (ssh_msg_recv(client_fd, &m) == -1) { error("%s: client msg_recv failed", __func__); close(client_fd); buffer_free(&m); return; } if ((ver = buffer_get_char(&m)) != 1) { error("%s: wrong client version %d", __func__, ver); buffer_free(&m); close(client_fd); return; } allowed = 1; command = buffer_get_int(&m); flags = buffer_get_int(&m); buffer_clear(&m); switch (command) { case SSHMUX_COMMAND_OPEN: if (options.control_master == 2) allowed = ask_permission("Allow shared connection " "to %s? ", host); /* continue below */ break; case SSHMUX_COMMAND_TERMINATE: if (options.control_master == 2) allowed = ask_permission("Terminate shared connection " "to %s? ", host); if (allowed) quit_pending = 1; /* FALLTHROUGH */ case SSHMUX_COMMAND_ALIVE_CHECK: /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ buffer_clear(&m); buffer_put_int(&m, allowed); buffer_put_int(&m, getpid()); if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { error("%s: client msg_send failed", __func__); close(client_fd); buffer_free(&m); return; } buffer_free(&m); close(client_fd); return; default: error("Unsupported command %d", command); buffer_free(&m); close(client_fd); return; } /* Reply for SSHMUX_COMMAND_OPEN */ buffer_clear(&m); buffer_put_int(&m, allowed); buffer_put_int(&m, getpid()); if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { error("%s: client msg_send failed", __func__); close(client_fd); buffer_free(&m); return; } if (!allowed) { error("Refused control connection"); close(client_fd); buffer_free(&m); return; } buffer_clear(&m); if (ssh_msg_recv(client_fd, &m) == -1) { error("%s: client msg_recv failed", __func__); close(client_fd); buffer_free(&m); return; } if ((ver = buffer_get_char(&m)) != 1) { error("%s: wrong client version %d", __func__, ver); buffer_free(&m); close(client_fd); return; } cctx = xmalloc(sizeof(*cctx)); memset(cctx, 0, sizeof(*cctx)); cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; cctx->term = buffer_get_string(&m, &len); cmd = buffer_get_string(&m, &len); buffer_init(&cctx->cmd); buffer_append(&cctx->cmd, cmd, strlen(cmd)); env_len = buffer_get_int(&m); env_len = MIN(env_len, 4096); debug3("%s: receiving %d env vars", __func__, env_len); if (env_len != 0) { cctx->env = xmalloc(sizeof(*cctx->env) * (env_len + 1)); for (i = 0; i < env_len; i++) cctx->env[i] = buffer_get_string(&m, &len); cctx->env[i] = NULL; } debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__, cctx->want_tty, cctx->want_subsys, cmd); /* Gather fds from client */ new_fd[0] = mm_receive_fd(client_fd); new_fd[1] = mm_receive_fd(client_fd); new_fd[2] = mm_receive_fd(client_fd); debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__, new_fd[0], new_fd[1], new_fd[2]); /* Try to pick up ttymodes from client before it goes raw */ if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) error("%s: tcgetattr: %s", __func__, strerror(errno)); /* This roundtrip is just for synchronisation of ttymodes */ buffer_clear(&m); if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { error("%s: client msg_send failed", __func__); close(client_fd); close(new_fd[0]); close(new_fd[1]); close(new_fd[2]); buffer_free(&m); xfree(cctx->term); if (env_len != 0) { for (i = 0; i < env_len; i++) xfree(cctx->env[i]); xfree(cctx->env); } return; } buffer_free(&m); /* enable nonblocking unless tty */ if (!isatty(new_fd[0])) set_nonblock(new_fd[0]); if (!isatty(new_fd[1])) set_nonblock(new_fd[1]); if (!isatty(new_fd[2])) set_nonblock(new_fd[2]); set_nonblock(client_fd); c = channel_new("session", SSH_CHANNEL_OPENING, new_fd[0], new_fd[1], new_fd[2], CHAN_SES_WINDOW_DEFAULT, CHAN_SES_PACKET_DEFAULT, CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); /* XXX */ c->ctl_fd = client_fd; debug3("%s: channel_new: %d", __func__, c->self); channel_send_open(c->self); channel_register_confirm(c->self, client_extra_session2_setup, cctx);}static voidprocess_cmdline(void){ void (*handler)(int); char *s, *cmd, *cancel_host; int delete = 0; int local = 0; u_short cancel_port; Forward fwd; leave_raw_mode(); handler = signal(SIGINT, SIG_IGN); cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); if (s == NULL) goto out; while (*s && isspace(*s)) s++; if (*s == '-') s++; /* Skip cmdline '-', if any */ if (*s == '\0') goto out; if (*s == 'h' || *s == 'H' || *s == '?') { logit("Commands:"); logit(" -Lport:host:hostport Request local forward"); logit(" -Rport:host:hostport Request remote forward"); logit(" -KRhostport Cancel remote forward"); goto out; } if (*s == 'K') { delete = 1; s++; } if (*s != 'L' && *s != 'R') { logit("Invalid command."); goto out; } if (*s == 'L') local = 1; if (local && delete) { logit("Not supported."); goto out; } if ((!local || delete) && !compat20) { logit("Not supported for SSH protocol version 1."); goto out; } s++; while (*s && isspace(*s)) s++; if (delete) { cancel_port = 0; cancel_host = hpdelim(&s); /* may be NULL */ if (s != NULL) { cancel_port = a2port(s); cancel_host = cleanhostname(cancel_host); } else { cancel_port = a2port(cancel_host); cancel_host = NULL; } if (cancel_port == 0) { logit("Bad forwarding close port"); goto out; } channel_request_rforward_cancel(cancel_host, cancel_port); } else { if (!parse_forward(&fwd, s)) { logit("Bad forwarding specification."); goto out; } if (local) { if (channel_setup_local_fwd_listener(fwd.listen_host, fwd.listen_port, fwd.connect_host, fwd.connect_port, options.gateway_ports) < 0) { logit("Port forwarding failed."); goto out; } } else { channel_request_remote_forwarding(fwd.listen_host, fwd.listen_port, fwd.connect_host, fwd.connect_port); } logit("Forwarding port."); }out: signal(SIGINT, handler); enter_raw_mode(); if (cmd) xfree(cmd);}/* process the characters one by one */static intprocess_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len){ char string[1024]; pid_t pid; int bytes = 0; u_int i; u_char ch; char *s; for (i = 0; i < len; i++) { /* Get one character at a time. */ ch = buf[i]; if (escape_pending) { /* We have previously seen an escape character. */ /* Clear the flag now. */ escape_pending = 0; /* Process the escaped character. */ switch (ch) { case '.': /* Terminate the connection. */ snprintf(string, sizeof string, "%c.\r\n", escape_char); buffer_append(berr, string, strlen(string)); quit_pending = 1; return -1; case 'Z' - 64: /* Suspend the program. */ /* Print a message to that effect to the user. */ snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); buffer_append(berr, string, strlen(string)); /* Restore terminal modes and suspend. */ client_suspend_self(bin, bout, berr); /* We have been continued. */ continue; case 'B': if (compat20) { snprintf(string, sizeof string, "%cB\r\n", escape_char); buffer_append(berr, string, strlen(string)); channel_request_start(session_ident, "break", 0); packet_put_int(1000); packet_send(); } continue; case 'R': if (compat20) { if (datafellows & SSH_BUG_NOREKEY) logit("Server does not support re-keying"); else need_rekeying = 1; } continue; case '&': /* * Detach the program (continue to serve connections, * but put in background and no more new connections). */ /* Restore tty modes. */ leave_raw_mode(); /* Stop listening for new connections. */ channel_stop_listening(); snprintf(string, sizeof string, "%c& [backgrounded]\n", escape_char); buffer_append(berr, string, strlen(string)); /* Fork into background. */ pid = fork();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -