static void mm_record_login(Session *s, struct passwd *pw) { struct ssh *ssh = active_state; /* XXX */ 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)); cleanup_exit(255); } } /* 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, session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns), (struct sockaddr *)&from, fromlen); }
const char * get_canonical_hostname(int use_dns) { char *host; static char *canonical_host_name = NULL; static char *remote_ip = NULL; /* Check if we have previously retrieved name with same option. */ if (use_dns && canonical_host_name != NULL) return canonical_host_name; if (!use_dns && remote_ip != NULL) return remote_ip; /* Get the real hostname if socket; otherwise return UNKNOWN. */ if (packet_connection_is_on_socket()) host = get_remote_hostname(packet_get_connection_in(), use_dns); else host = "UNKNOWN"; if (use_dns) canonical_host_name = host; else remote_ip = host; return host; }
void blacklist_notify(int action) { if (blstate != NULL && packet_connection_is_on_socket()) (void)blacklist_r(blstate, action, packet_get_connection_in(), "ssh"); }
static int get_port(int local) { /* * If the connection is not a socket, return 65535. This is * intentionally chosen to be an unprivileged port number. */ if (!packet_connection_is_on_socket()) return 65535; /* Get socket and return the port number. */ return get_sock_port(packet_get_connection_in(), local); }
void blacklist_notify(int action) { int fd; if (blstate == NULL) blacklist_init(); if (blstate == NULL) return; fd = packet_get_connection_in(); if (!packet_connection_is_on_socket()) { fprintf(stderr, "packet_connection_is_on_socket: false " "(fd = %d)\n", fd); } (void)blacklist_r(blstate, action, fd, "ssh"); }
const char * get_remote_ipaddr(void) { /* 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) cleanup_exit(255); } 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)); if (packet_connection_is_on_socket()) { fromlen = sizeof(from); 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); }
const char * get_canonical_hostname(int use_dns) { static char *canonical_host_name = NULL; static int use_dns_done = 0; /* Check if we have previously retrieved name with same option. */ if (canonical_host_name != NULL) { if (use_dns_done != use_dns) xfree(canonical_host_name); else return canonical_host_name; } /* Get the real hostname if socket; otherwise return UNKNOWN. */ if (packet_connection_is_on_socket()) canonical_host_name = get_remote_hostname( packet_get_connection_in(), use_dns); else canonical_host_name = xstrdup("UNKNOWN"); use_dns_done = use_dns; return canonical_host_name; }
/* * Main program for the ssh client. */ int main(int ac, char **av) { int i, r, opt, exit_status, use_syslog; char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg; char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; struct stat st; struct passwd *pw; int dummy, timeout_ms; extern int optind, optreset; extern char *optarg; struct servent *sp; Forward fwd; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); __progname = ssh_get_progname(av[0]); #ifndef HAVE_SETPROCTITLE /* Prepare for later setproctitle emulation */ /* Save argv so it isn't clobbered by setproctitle() emulation */ saved_av = xcalloc(ac + 1, sizeof(*saved_av)); for (i = 0; i < ac; i++) saved_av[i] = xstrdup(av[i]); saved_av[i] = NULL; compat_init_setproctitle(ac, av); av = saved_av; #endif /* * Discard other fds that are hanging around. These can cause problem * with backgrounded ssh processes started by ControlPersist. */ closefrom(STDERR_FILENO + 1); /* * Save the original real uid. It will be needed later (uid-swapping * may clobber the real uid). */ original_real_uid = getuid(); original_effective_uid = geteuid(); /* * Use uid-swapping to give up root privileges for the duration of * option processing. We will re-instantiate the rights when we are * ready to create the privileged port, and will permanently drop * them when the port has been created (actually, when the connection * has been made, as we may need to create the port several times). */ PRIV_END; #ifdef HAVE_SETRLIMIT /* If we are installed setuid root be careful to not drop core. */ if (original_real_uid != original_effective_uid) { struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &rlim) < 0) fatal("setrlimit failed: %.100s", strerror(errno)); } #endif /* Get user data. */ pw = getpwuid(original_real_uid); if (!pw) { logit("You don't exist, go away!"); exit(255); } /* Take a copy of the returned structure. */ pw = pwcopy(pw); /* * Set our umask to something reasonable, as some files are created * with the default umask. This will make them world-readable but * writable only by the owner, which is ok for all files for which we * don't set the modes explicitly. */ umask(022); /* * Initialize option structure to indicate that no values have been * set. */ initialize_options(&options); /* Parse command-line arguments. */ host = NULL; use_syslog = 0; argv0 = av[0]; again: while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) { switch (opt) { case '1': options.protocol = SSH_PROTO_1; break; case '2': options.protocol = SSH_PROTO_2; break; case '4': options.address_family = AF_INET; break; case '6': options.address_family = AF_INET6; break; case 'n': stdin_null_flag = 1; break; case 'f': fork_after_authentication_flag = 1; stdin_null_flag = 1; break; case 'x': options.forward_x11 = 0; break; case 'X': options.forward_x11 = 1; break; case 'y': use_syslog = 1; break; case 'Y': options.forward_x11 = 1; options.forward_x11_trusted = 1; break; case 'g': options.gateway_ports = 1; break; case 'O': if (stdio_forward_host != NULL) fatal("Cannot specify multiplexing " "command with -W"); else if (muxclient_command != 0) fatal("Multiplexing command already specified"); if (strcmp(optarg, "check") == 0) muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; else if (strcmp(optarg, "forward") == 0) muxclient_command = SSHMUX_COMMAND_FORWARD; else if (strcmp(optarg, "exit") == 0) muxclient_command = SSHMUX_COMMAND_TERMINATE; else if (strcmp(optarg, "stop") == 0) muxclient_command = SSHMUX_COMMAND_STOP; else if (strcmp(optarg, "cancel") == 0) muxclient_command = SSHMUX_COMMAND_CANCEL_FWD; else fatal("Invalid multiplex command."); break; case 'P': /* deprecated */ options.use_privileged_port = 0; break; case 'a': options.forward_agent = 0; break; case 'A': options.forward_agent = 1; break; case 'k': options.gss_deleg_creds = 0; break; case 'K': options.gss_authentication = 1; options.gss_deleg_creds = 1; break; case 'i': if (stat(optarg, &st) < 0) { fprintf(stderr, "Warning: Identity file %s " "not accessible: %s.\n", optarg, strerror(errno)); break; } if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES) fatal("Too many identity files specified " "(max %d)", SSH_MAX_IDENTITY_FILES); options.identity_files[options.num_identity_files++] = xstrdup(optarg); break; case 'I': #ifdef ENABLE_PKCS11 options.pkcs11_provider = xstrdup(optarg); #else fprintf(stderr, "no support for PKCS#11.\n"); #endif break; case 't': if (options.request_tty == REQUEST_TTY_YES) options.request_tty = REQUEST_TTY_FORCE; else options.request_tty = REQUEST_TTY_YES; break; case 'v': if (debug_flag == 0) { debug_flag = 1; options.log_level = SYSLOG_LEVEL_DEBUG1; } else { if (options.log_level < SYSLOG_LEVEL_DEBUG3) options.log_level++; break; } /* FALLTHROUGH */ case 'V': fprintf(stderr, "%s, %s\n", SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); if (opt == 'V') exit(0); break; case 'w': if (options.tun_open == -1) options.tun_open = SSH_TUNMODE_DEFAULT; options.tun_local = a2tun(optarg, &options.tun_remote); if (options.tun_local == SSH_TUNID_ERR) { fprintf(stderr, "Bad tun device '%s'\n", optarg); exit(255); } break; case 'W': if (stdio_forward_host != NULL) fatal("stdio forward already specified"); if (muxclient_command != 0) fatal("Cannot specify stdio forward with -O"); if (parse_forward(&fwd, optarg, 1, 0)) { stdio_forward_host = fwd.listen_host; stdio_forward_port = fwd.listen_port; xfree(fwd.connect_host); } else { fprintf(stderr, "Bad stdio forwarding specification '%s'\n", optarg); exit(255); } options.request_tty = REQUEST_TTY_NO; no_shell_flag = 1; options.clear_forwardings = 1; options.exit_on_forward_failure = 1; break; case 'q': options.log_level = SYSLOG_LEVEL_QUIET; break; case 'e': if (optarg[0] == '^' && optarg[2] == 0 && (u_char) optarg[1] >= 64 && (u_char) optarg[1] < 128) options.escape_char = (u_char) optarg[1] & 31; else if (strlen(optarg) == 1) options.escape_char = (u_char) optarg[0]; else if (strcmp(optarg, "none") == 0) options.escape_char = SSH_ESCAPECHAR_NONE; else { fprintf(stderr, "Bad escape character '%s'.\n", optarg); exit(255); } break; case 'c': if (ciphers_valid(optarg)) { /* SSH2 only */ options.ciphers = xstrdup(optarg); options.cipher = SSH_CIPHER_INVALID; } else { /* SSH1 only */ options.cipher = cipher_number(optarg); if (options.cipher == -1) { fprintf(stderr, "Unknown cipher type '%s'\n", optarg); exit(255); } if (options.cipher == SSH_CIPHER_3DES) options.ciphers = "3des-cbc"; else if (options.cipher == SSH_CIPHER_BLOWFISH) options.ciphers = "blowfish-cbc"; else options.ciphers = (char *)-1; } break; case 'm': if (mac_valid(optarg)) options.macs = xstrdup(optarg); else { fprintf(stderr, "Unknown mac type '%s'\n", optarg); exit(255); } break; case 'M': if (options.control_master == SSHCTL_MASTER_YES) options.control_master = SSHCTL_MASTER_ASK; else options.control_master = SSHCTL_MASTER_YES; break; case 'p': options.port = a2port(optarg); if (options.port <= 0) { fprintf(stderr, "Bad port '%s'\n", optarg); exit(255); } break; case 'l': options.user = optarg; break; case 'L': if (parse_forward(&fwd, optarg, 0, 0)) add_local_forward(&options, &fwd); else { fprintf(stderr, "Bad local forwarding specification '%s'\n", optarg); exit(255); } break; case 'R': if (parse_forward(&fwd, optarg, 0, 1)) { add_remote_forward(&options, &fwd); } else { fprintf(stderr, "Bad remote forwarding specification " "'%s'\n", optarg); exit(255); } break; case 'D': if (parse_forward(&fwd, optarg, 1, 0)) { add_local_forward(&options, &fwd); } else { fprintf(stderr, "Bad dynamic forwarding specification " "'%s'\n", optarg); exit(255); } break; case 'C': options.compression = 1; break; case 'N': no_shell_flag = 1; options.request_tty = REQUEST_TTY_NO; break; case 'T': options.request_tty = REQUEST_TTY_NO; break; case 'o': dummy = 1; line = xstrdup(optarg); if (process_config_line(&options, host ? host : "", line, "command-line", 0, &dummy) != 0) exit(255); xfree(line); break; case 's': subsystem_flag = 1; break; case 'S': if (options.control_path != NULL) free(options.control_path); options.control_path = xstrdup(optarg); break; case 'b': options.bind_address = optarg; break; case 'F': config = optarg; break; default: usage(); } } ac -= optind; av += optind; if (ac > 0 && !host) { if (strrchr(*av, '@')) { p = xstrdup(*av); cp = strrchr(p, '@'); if (cp == NULL || cp == p) usage(); options.user = p; *cp = '\0'; host = ++cp; } else host = *av; if (ac > 1) { optind = optreset = 1; goto again; } ac--, av++; } /* Check that we got a host name. */ if (!host) usage(); OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); /* Initialize the command to execute on remote host. */ buffer_init(&command); if (options.request_tty == REQUEST_TTY_YES || options.request_tty == REQUEST_TTY_FORCE) tty_flag = 1; /* * Save the command to execute on the remote host in a buffer. There * is no limit on the length of the command, except by the maximum * packet size. Also sets the tty flag if there is no command. */ if (!ac) { /* No command specified - execute shell on a tty. */ tty_flag = options.request_tty != REQUEST_TTY_NO; if (subsystem_flag) { fprintf(stderr, "You must specify a subsystem to invoke.\n"); usage(); } } else { /* A command has been specified. Store it into the buffer. */ for (i = 0; i < ac; i++) { if (i) buffer_append(&command, " ", 1); buffer_append(&command, av[i], strlen(av[i])); } } /* Cannot fork to background if no command. */ if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag) fatal("Cannot fork into background without a command " "to execute."); /* Allocate a tty by default if no command specified. */ if (buffer_len(&command) == 0) tty_flag = options.request_tty != REQUEST_TTY_NO; /* Force no tty */ if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0) tty_flag = 0; /* Do not allocate a tty if stdin is not a tty. */ if ((!isatty(fileno(stdin)) || stdin_null_flag) && options.request_tty != REQUEST_TTY_FORCE) { if (tty_flag) logit("Pseudo-terminal will not be allocated because " "stdin is not a terminal."); tty_flag = 0; } /* * Initialize "log" output. Since we are the client all output * actually goes to stderr. */ log_init(argv0, options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, SYSLOG_FACILITY_USER, !use_syslog); /* * Read per-user configuration file. Ignore the system wide config * file if the user specifies a config file on the command line. */ if (config != NULL) { if (!read_config_file(config, host, &options, 0)) fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); } else { r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); if (r > 0 && (size_t)r < sizeof(buf)) (void)read_config_file(buf, host, &options, 1); /* Read systemwide configuration file after user config. */ (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options, 0); } /* Fill configuration defaults. */ fill_default_options(&options); channel_set_af(options.address_family); /* reinit */ log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); seed_rng(); if (options.user == NULL) options.user = xstrdup(pw->pw_name); /* Get default port if port has not been set. */ if (options.port == 0) { sp = getservbyname(SSH_SERVICE_NAME, "tcp"); options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; } /* preserve host name given on command line for %n expansion */ host_arg = host; if (options.hostname != NULL) { host = percent_expand(options.hostname, "h", host, (char *)NULL); } if (gethostname(thishost, sizeof(thishost)) == -1) fatal("gethostname: %s", strerror(errno)); strlcpy(shorthost, thishost, sizeof(shorthost)); shorthost[strcspn(thishost, ".")] = '\0'; snprintf(portstr, sizeof(portstr), "%d", options.port); if (options.local_command != NULL) { debug3("expanding LocalCommand: %s", options.local_command); cp = options.local_command; options.local_command = percent_expand(cp, "d", pw->pw_dir, "h", host, "l", thishost, "n", host_arg, "r", options.user, "p", portstr, "u", pw->pw_name, "L", shorthost, (char *)NULL); debug3("expanded LocalCommand: %s", options.local_command); xfree(cp); } /* force lowercase for hostkey matching */ if (options.host_key_alias != NULL) { for (p = options.host_key_alias; *p; p++) if (isupper(*p)) *p = (char)tolower(*p); } if (options.proxy_command != NULL && strcmp(options.proxy_command, "none") == 0) { xfree(options.proxy_command); options.proxy_command = NULL; } if (options.control_path != NULL && strcmp(options.control_path, "none") == 0) { xfree(options.control_path); options.control_path = NULL; } if (options.control_path != NULL) { cp = tilde_expand_filename(options.control_path, original_real_uid); xfree(options.control_path); options.control_path = percent_expand(cp, "h", host, "l", thishost, "n", host_arg, "r", options.user, "p", portstr, "u", pw->pw_name, "L", shorthost, (char *)NULL); xfree(cp); } if (muxclient_command != 0 && options.control_path == NULL) fatal("No ControlPath specified for \"-O\" command"); if (options.control_path != NULL) muxclient(options.control_path); timeout_ms = options.connection_timeout * 1000; /* Open a connection to the remote host. */ if (ssh_connect(host, &hostaddr, options.port, options.address_family, options.connection_attempts, &timeout_ms, options.tcp_keep_alive, #ifdef HAVE_CYGWIN options.use_privileged_port, #else original_effective_uid == 0 && options.use_privileged_port, #endif options.proxy_command) != 0) exit(255); if (timeout_ms > 0) debug3("timeout: %d ms remain after connect", timeout_ms); /* * If we successfully made the connection, load the host private key * in case we will need it later for combined rsa-rhosts * authentication. This must be done before releasing extra * privileges, because the file is only readable by root. * If we cannot access the private keys, load the public keys * instead and try to execute the ssh-keysign helper instead. */ sensitive_data.nkeys = 0; sensitive_data.keys = NULL; sensitive_data.external_keysign = 0; if (options.rhosts_rsa_authentication || options.hostbased_authentication) { sensitive_data.nkeys = 7; sensitive_data.keys = xcalloc(sensitive_data.nkeys, sizeof(Key)); for (i = 0; i < sensitive_data.nkeys; i++) sensitive_data.keys[i] = NULL; PRIV_START; sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, _PATH_HOST_KEY_FILE, "", NULL, NULL); sensitive_data.keys[1] = key_load_private_cert(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL); #ifdef OPENSSL_HAS_ECC sensitive_data.keys[2] = key_load_private_cert(KEY_ECDSA, _PATH_HOST_ECDSA_KEY_FILE, "", NULL); #endif sensitive_data.keys[3] = key_load_private_cert(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL); sensitive_data.keys[4] = key_load_private_type(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); #ifdef OPENSSL_HAS_ECC sensitive_data.keys[5] = key_load_private_type(KEY_ECDSA, _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL); #endif sensitive_data.keys[6] = key_load_private_type(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); PRIV_END; if (options.hostbased_authentication == 1 && sensitive_data.keys[0] == NULL && sensitive_data.keys[4] == NULL && sensitive_data.keys[5] == NULL && sensitive_data.keys[6] == NULL) { sensitive_data.keys[1] = key_load_cert( _PATH_HOST_DSA_KEY_FILE); #ifdef OPENSSL_HAS_ECC sensitive_data.keys[2] = key_load_cert( _PATH_HOST_ECDSA_KEY_FILE); #endif sensitive_data.keys[3] = key_load_cert( _PATH_HOST_RSA_KEY_FILE); sensitive_data.keys[4] = key_load_public( _PATH_HOST_DSA_KEY_FILE, NULL); #ifdef OPENSSL_HAS_ECC sensitive_data.keys[5] = key_load_public( _PATH_HOST_ECDSA_KEY_FILE, NULL); #endif sensitive_data.keys[6] = key_load_public( _PATH_HOST_RSA_KEY_FILE, NULL); sensitive_data.external_keysign = 1; } } /* * Get rid of any extra privileges that we may have. We will no * longer need them. Also, extra privileges could make it very hard * to read identity files and other non-world-readable files from the * user's home directory if it happens to be on a NFS volume where * root is mapped to nobody. */ if (original_effective_uid == 0) { PRIV_START; permanently_set_uid(pw); } /* * Now that we are back to our own permissions, create ~/.ssh * directory if it doesn't already exist. */ if (config == NULL) { r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) { #ifdef WITH_SELINUX ssh_selinux_setfscreatecon(buf); #endif if (mkdir(buf, 0700) < 0) error("Could not create directory '%.200s'.", buf); #ifdef WITH_SELINUX ssh_selinux_setfscreatecon(NULL); #endif } } /* load options.identity_files */ load_public_identity_files(); /* Expand ~ in known host file names. */ tilde_expand_paths(options.system_hostfiles, options.num_system_hostfiles); tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles); signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ signal(SIGCHLD, main_sigchld_handler); /* Log into the remote system. Never returns if the login fails. */ ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, options.port, pw, timeout_ms); if (packet_connection_is_on_socket()) { verbose("Authenticated to %s ([%s]:%d).", host, get_remote_ipaddr(), get_remote_port()); } else { verbose("Authenticated to %s (via proxy).", host); } /* We no longer need the private host keys. Clear them now. */ if (sensitive_data.nkeys != 0) { for (i = 0; i < sensitive_data.nkeys; i++) { if (sensitive_data.keys[i] != NULL) { /* Destroys contents safely */ debug3("clear hostkey %d", i); key_free(sensitive_data.keys[i]); sensitive_data.keys[i] = NULL; } } xfree(sensitive_data.keys); } for (i = 0; i < options.num_identity_files; i++) { if (options.identity_files[i]) { xfree(options.identity_files[i]); options.identity_files[i] = NULL; } if (options.identity_keys[i]) { key_free(options.identity_keys[i]); options.identity_keys[i] = NULL; } } exit_status = compat20 ? ssh_session2() : ssh_session(); packet_close(); if (options.control_path != NULL && muxserver_sock != -1) unlink(options.control_path); /* Kill ProxyCommand if it is running. */ ssh_kill_proxy_command(); return exit_status; }
void record_failed_login(const char *username, const char *hostname, const char *ttyn) { int fd; struct utmp ut; struct sockaddr_storage from; socklen_t fromlen = sizeof(from); struct sockaddr_in *a4; struct sockaddr_in6 *a6; time_t t; struct stat fst; if (geteuid() != 0) return; if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) { debug("Unable to open the btmp file %s: %s", _PATH_BTMP, strerror(errno)); return; } if (fstat(fd, &fst) < 0) { logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP, strerror(errno)); goto out; } if((fst.st_mode & (S_IXGRP | S_IRWXO)) || (fst.st_uid != 0)){ logit("Excess permission or bad ownership on file %s", _PATH_BTMP); goto out; } memset(&ut, 0, sizeof(ut)); /* strncpy because we don't necessarily want nul termination */ strncpy(ut.ut_user, username, sizeof(ut.ut_user)); strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line)); time(&t); ut.ut_time = t; /* ut_time is not always a time_t */ ut.ut_type = LOGIN_PROCESS; ut.ut_pid = getpid(); /* strncpy because we don't necessarily want nul termination */ strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); if (packet_connection_is_on_socket() && getpeername(packet_get_connection_in(), (struct sockaddr *)&from, &fromlen) == 0) { ipv64_normalise_mapped(&from, &fromlen); if (from.ss_family == AF_INET) { a4 = (struct sockaddr_in *)&from; memcpy(&ut.ut_addr, &(a4->sin_addr), MIN_SIZEOF(ut.ut_addr, a4->sin_addr)); } #ifdef HAVE_ADDR_V6_IN_UTMP if (from.ss_family == AF_INET6) { a6 = (struct sockaddr_in6 *)&from; memcpy(&ut.ut_addr_v6, &(a6->sin6_addr), MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr)); } #endif } if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut)) error("Failed to write to %s: %s", _PATH_BTMP, strerror(errno)); out: close(fd); }