/* * Processes input from the client and the program. Input data is stored * in buffers and processed later. */ static void process_input(fd_set * readset) { int len; char buf[16384]; /* Read and buffer any input data from the client. */ if (FD_ISSET(connection_in, readset)) { len = read(connection_in, buf, sizeof(buf)); if (len == 0) { verbose("Connection closed by %.100s", get_remote_ipaddr()); connection_closed = 1; if (compat20) return; fatal_cleanup(); } else if (len < 0) { if (errno != EINTR && errno != EAGAIN) { verbose("Read error from remote host " "%.100s: %.100s", get_remote_ipaddr(), strerror(errno)); fatal_cleanup(); } } else { /* Buffer any received data. */ packet_process_incoming(buf, len); } } if (compat20) return; /* Read and buffer any available stdout data from the program. */ if (!fdout_eof && FD_ISSET(fdout, readset)) { len = read(fdout, buf, sizeof(buf)); if (len < 0 && (errno == EINTR || errno == EAGAIN)) { /* do nothing */ } else if (len <= 0) { fdout_eof = 1; } else { buffer_append(&stdout_buffer, buf, len); fdout_bytes += len; } } /* Read and buffer any available stderr data from the program. */ if (!fderr_eof && FD_ISSET(fderr, readset)) { len = read(fderr, buf, sizeof(buf)); if (len < 0 && (errno == EINTR || errno == EAGAIN)) { /* do nothing */ } else if (len <= 0) { fderr_eof = 1; } else { buffer_append(&stderr_buffer, buf, len); } } }
static int get_sock_port(int sock, int local) { struct sockaddr_storage from; socklen_t fromlen; char strport[NI_MAXSERV]; /* Get IP address of client. */ fromlen = sizeof(from); memset(&from, 0, sizeof(from)); if (local) { if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) { error("getsockname failed: %.100s", strerror(errno)); return 0; } } else { if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) { debug("getpeername failed: %.100s", strerror(errno)); fatal_cleanup(); } } /* Return port number. */ if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, strport, sizeof(strport), NI_NUMERICSERV) != 0) fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed"); return atoi(strport); }
void fatal(const char *fmt,...) { va_list args; va_start(args, fmt); do_log(SYSLOG_LEVEL_FATAL, fmt, args); va_end(args); fatal_cleanup(); }
ok_t _log_fatal(char *file, int line, char *msg) { extern void fatal_cleanup(); _log(file, line, "FATAL", msg ); fatal_cleanup(); return NG; }
static void ATTR_NORETURN cleanup(int signum) { FATAL(SYSTEM, "receive signal %d\n", signum); switch (signum) { case SIGPIPE: sigpipe_arised = TRUE; break; default: break; } fatal_cleanup(); }
const char * get_remote_ipaddr(void) { static char *canonical_host_ip = NULL; /* Check whether we have cached the ipaddr. */ if (canonical_host_ip == NULL) { if (packet_connection_is_on_socket()) { canonical_host_ip = get_peer_ipaddr(packet_get_connection_in()); if (canonical_host_ip == NULL) fatal_cleanup(); } else { /* If not on socket, return UNKNOWN. */ canonical_host_ip = xstrdup("UNKNOWN"); } } return canonical_host_ip; }
static void mm_record_login(Session *s, struct passwd *pw) { socklen_t fromlen; struct sockaddr_storage from; /* * Get IP address of client. If the connection is not a socket, let * the address be 0.0.0.0. */ memset(&from, 0, sizeof(from)); fromlen = sizeof(from); if (packet_connection_is_on_socket()) { if (getpeername(packet_get_connection_in(), (struct sockaddr *) & from, &fromlen) < 0) { debug("getpeername: %.100s", strerror(errno)); fatal_cleanup(); } } /* Record that there was a login on that tty from the remote host. */ record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid, get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping), (struct sockaddr *)&from, fromlen); }
void mm_request_receive(int socket, Buffer *m) { u_char buf[4]; u_int msg_len; ssize_t res; debug3("%s entering", __func__); res = atomicio(read, socket, buf, sizeof(buf)); if (res != sizeof(buf)) { if (res == 0) fatal_cleanup(); fatal("%s: read: %ld", __func__, (long)res); } msg_len = GET_32BIT(buf); if (msg_len > 256 * 1024) fatal("%s: read: bad msg_len %d", __func__, msg_len); buffer_clear(m); buffer_append_space(m, msg_len); res = atomicio(read, socket, buffer_ptr(m), msg_len); if (res != msg_len) fatal("%s: read: %ld != msg_len", __func__, (long)res); }
int auth_krb4(Authctxt *authctxt, KTEXT auth, char **client, KTEXT reply) { AUTH_DAT adat = {0}; Key_schedule schedule; struct sockaddr_in local, foreign; char instance[INST_SZ]; socklen_t slen; u_int cksum; int r, s; s = packet_get_connection_in(); slen = sizeof(local); memset(&local, 0, sizeof(local)); if (getsockname(s, (struct sockaddr *) & local, &slen) < 0) debug("getsockname failed: %.100s", strerror(errno)); slen = sizeof(foreign); memset(&foreign, 0, sizeof(foreign)); if (getpeername(s, (struct sockaddr *) & foreign, &slen) < 0) { debug("getpeername failed: %.100s", strerror(errno)); fatal_cleanup(); } instance[0] = '*'; instance[1] = 0; /* Get the encrypted request, challenge, and session key. */ if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) { debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]); return (0); } des_key_sched((des_cblock *) adat.session, schedule); *client = xmalloc(MAX_K_NAME_SZ); (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname, *adat.pinst ? "." : "", adat.pinst, adat.prealm); /* Check ~/.klogin authorization now. */ if (kuserok(&adat, authctxt->user) != KSUCCESS) { log("Kerberos v4 .klogin authorization failed for %s to " "account %s", *client, authctxt->user); xfree(*client); *client = NULL; return (0); } /* Increment the checksum, and return it encrypted with the session key. */ cksum = adat.checksum + 1; cksum = htonl(cksum); /* If we can't successfully encrypt the checksum, we send back an empty message, admitting our failure. */ if ((r = krb_mk_priv((u_char *) & cksum, reply->dat, sizeof(cksum) + 1, schedule, &adat.session, &local, &foreign)) < 0) { debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]); reply->dat[0] = 0; reply->length = 0; } else reply->length = r; /* Clear session key. */ memset(&adat.session, 0, sizeof(&adat.session)); return (1); }
static char * get_remote_hostname(int socket, int verify_reverse_mapping) { struct sockaddr_storage from; int i, res; socklen_t fromlen; struct addrinfo hints, *ai, *aitop; char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST]; /* Get IP address of client. */ fromlen = sizeof(from); memset(&from, 0, sizeof(from)); if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) { debug("getpeername failed: %.100s", strerror(errno)); fatal_cleanup(); } if ((res = getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST)) != 0) fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed: %d", res); #ifdef IPV4_IN_IPV6 if (from.ss_family == AF_INET6) { struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from; (void) inet_ntop_native(from.ss_family, from6->sin6_addr.s6_addr, ntop, sizeof(ntop)); } #endif /* IPV4_IN_IPV6 */ if (!verify_reverse_mapping) return xstrdup(ntop); debug3("Trying to reverse map address %.100s.", ntop); /* Map the IP address to a host name. */ if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), NULL, 0, NI_NAMEREQD) != 0) { /* Host name not found. Use ip address. */ return xstrdup(ntop); } /* Got host name. */ name[sizeof(name) - 1] = '\0'; /* * Convert it to all lowercase (which is expected by the rest * of this software). */ for (i = 0; name[i]; i++) if (isupper(name[i])) name[i] = tolower(name[i]); /* * Map it back to an IP address and check that the given * address actually is an address of this host. This is * necessary because anyone with access to a name server can * define arbitrary names for an IP address. Mapping from * name to IP address can be trusted better (but can still be * fooled if the intruder has access to the name server of * the domain). */ memset(&hints, 0, sizeof(hints)); hints.ai_family = from.ss_family; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { log("reverse mapping checking getaddrinfo for %.700s " "failed - POSSIBLE BREAKIN ATTEMPT!", name); return xstrdup(ntop); } /* Look for the address from the list of addresses. */ for (ai = aitop; ai; ai = ai->ai_next) { if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && (strcmp(ntop, ntop2) == 0)) break; } freeaddrinfo(aitop); /* If we reached the end of the list, the address was not there. */ if (!ai) { /* Address not found for the host name. */ log("Address %.100s maps to %.600s, but this does not " "map back to the address - POSSIBLE BREAKIN ATTEMPT!", ntop, name); return xstrdup(ntop); } return xstrdup(name); }
static void sshd_exchange_identification(int sock_in, int sock_out) { int i, mismatch; int remote_major, remote_minor; int major, minor; char *s; char buf[256]; /* Must not be larger than remote_version. */ char remote_version[256]; /* Must be at least as big as buf. */ if ((options.protocol & SSH_PROTO_1) && (options.protocol & SSH_PROTO_2)) { major = PROTOCOL_MAJOR_1; minor = 99; } else if (options.protocol & SSH_PROTO_2) { major = PROTOCOL_MAJOR_2; minor = PROTOCOL_MINOR_2; } else { major = PROTOCOL_MAJOR_1; minor = PROTOCOL_MINOR_1; } snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION); server_version_string = xstrdup(buf); if (client_version_string == NULL) { /* Send our protocol version identification. */ if (atomicio(write, sock_out, server_version_string, strlen(server_version_string)) != strlen(server_version_string)) { log("Could not write ident string to %s", get_remote_ipaddr()); fatal_cleanup(); } /* Read other sides version identification. */ memset(buf, 0, sizeof(buf)); for (i = 0; i < sizeof(buf) - 1; i++) { if (atomicio(read, sock_in, &buf[i], 1) != 1) { log("Did not receive identification string from %s", get_remote_ipaddr()); fatal_cleanup(); } if (buf[i] == '\r') { buf[i] = 0; /* Kludge for F-Secure Macintosh < 1.0.2 */ if (i == 12 && strncmp(buf, "SSH-1.5-W1.0", 12) == 0) break; continue; } if (buf[i] == '\n') { buf[i] = 0; break; } } buf[sizeof(buf) - 1] = 0; client_version_string = xstrdup(buf); } /* * Check that the versions match. In future this might accept * several versions and set appropriate flags to handle them. */ if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, remote_version) != 3) { s = "Protocol mismatch.\n"; (void) atomicio(write, sock_out, s, strlen(s)); close(sock_in); close(sock_out); log("Bad protocol version identification '%.100s' from %s", client_version_string, get_remote_ipaddr()); fatal_cleanup(); } debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); compat_datafellows(remote_version); if (datafellows & SSH_BUG_SCANNER) { log("scanned from %s with %s. Don't panic.", get_remote_ipaddr(), client_version_string); fatal_cleanup(); } mismatch = 0; switch (remote_major) { case 1: if (remote_minor == 99) { if (options.protocol & SSH_PROTO_2) enable_compat20(); else mismatch = 1; break; } if (!(options.protocol & SSH_PROTO_1)) { mismatch = 1; break; } if (remote_minor < 3) { packet_disconnect("Your ssh version is too old and " "is no longer supported. Please install a newer version."); } else if (remote_minor == 3) { /* note that this disables agent-forwarding */ enable_compat13(); } break; case 2: if (options.protocol & SSH_PROTO_2) { enable_compat20(); break; } /* FALLTHROUGH */ default: mismatch = 1; break; } chop(server_version_string); debug("Local version string %.200s", server_version_string); if (mismatch) { s = "Protocol major versions differ.\n"; (void) atomicio(write, sock_out, s, strlen(s)); close(sock_in); close(sock_out); log("Protocol major versions differ for %s: %.200s vs. %.200s", get_remote_ipaddr(), server_version_string, client_version_string); fatal_cleanup(); } }