freebsd-ports/security/ssh/files/patch-af
2002-06-29 21:31:50 +00:00

565 lines
20 KiB
Plaintext

--- sshd.c.orig Mon Jul 3 19:07:35 2000
+++ sshd.c Sat Jun 29 22:25:41 2002
@@ -567,6 +567,19 @@
/* Name of the server configuration file. */
char *config_file_name = SERVER_CONFIG_FILE;
+/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
+ Default value is AF_UNSPEC means both IPv4 and IPv6. */
+#ifdef ENABLE_IPV6
+int IPv4or6 = AF_UNSPEC;
+#else
+int IPv4or6 = AF_INET;
+#endif
+
+#ifdef ENABLE_LOG_AUTH
+char *unauthenticated_user = NULL;
+int log_auth_flag = 0;
+#endif /* ENABLE_LOG_AUTH */
+
/* Debug mode flag. This can be set on the command line. If debug
mode is enabled, extra debugging output will be sent to the system
log, the daemon will not go to background, and will exit after processing
@@ -590,7 +603,17 @@
/* This is set to the socket that the server is listening; this is used in
the SIGHUP signal handler. */
-int listen_sock;
+#define MAX_LISTEN_SOCKS 16
+int listen_socks[MAX_LISTEN_SOCKS];
+int num_listen_socks = 0;
+void close_listen_socks()
+{
+ int i;
+
+ for (i = 0; i < num_listen_socks; i++)
+ close(listen_socks[i]);
+ num_listen_socks = -1;
+}
/* This is not really needed, and could be eliminated if server-specific
and client-specific code were removed from newchannels.c */
@@ -680,7 +703,7 @@
void sighup_restart(void)
{
log_msg("Received SIGHUP; restarting.");
- close(listen_sock);
+ close_listen_socks();
execvp(saved_argv[0], saved_argv);
log_msg("RESTART FAILED: av[0]='%.100s', error: %.100s.",
saved_argv[0], strerror(errno));
@@ -694,7 +717,7 @@
RETSIGTYPE sigterm_handler(int sig)
{
log_msg("Received signal %d; terminating.", sig);
- close(listen_sock);
+ close_listen_socks();
exit(255);
}
@@ -773,7 +796,7 @@
int perm_denied = 0;
int ret;
fd_set fdset;
- struct sockaddr_in sin;
+ struct sockaddr_storage from;
char buf[100]; /* Must not be larger than remote_version. */
char remote_version[100]; /* Must be at least as big as buf. */
char *comment;
@@ -783,6 +806,9 @@
struct linger linger;
#endif /* SO_LINGER */
int done;
+ struct addrinfo *ai;
+ char ntop[ADDRSTRLEN], strport[PORTSTRLEN];
+ int listen_sock, maxfd;
/* Save argv[0]. */
saved_argv = av;
@@ -801,10 +827,26 @@
initialize_server_options(&options);
/* Parse command-line arguments. */
- while ((opt = getopt(ac, av, "f:p:b:k:h:g:diqV:")) != EOF)
+ while ((opt = getopt(ac, av, "f:p:b:k:h:g:diqV:4"
+#ifdef ENABLE_IPV6
+ "6"
+#endif
+ )) != EOF)
{
switch (opt)
{
+ case '4':
+#ifdef ENABLE_IPV6
+ IPv4or6 = (IPv4or6 == AF_INET6) ? AF_UNSPEC : AF_INET;
+#else
+ IPv4or6 = AF_INET;
+#endif
+ break;
+#ifdef ENABLE_IPV6
+ case '6':
+ IPv4or6 = (IPv4or6 == AF_INET) ? AF_UNSPEC : AF_INET6;
+ break;
+#endif
case 'f':
config_file_name = optarg;
break;
@@ -821,7 +863,7 @@
options.server_key_bits = atoi(optarg);
break;
case 'p':
- options.port = atoi(optarg);
+ options.ports[options.num_ports++] = atoi(optarg);
break;
case 'g':
options.login_grace_time = atoi(optarg);
@@ -843,6 +885,10 @@
fprintf(stderr, "sshd version %s [%s]\n", SSH_VERSION, HOSTTYPE);
fprintf(stderr, "Usage: %s [options]\n", av0);
fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -4 Use IPv4 only\n");
+#ifdef ENABLE_IPV6
+ fprintf(stderr, " -6 Use IPv6 only\n");
+#endif
fprintf(stderr, " -f file Configuration file (default %s/sshd_config)\n", ETCDIR);
fprintf(stderr, " -d Debugging mode\n");
fprintf(stderr, " -i Started from inetd\n");
@@ -871,16 +917,15 @@
fprintf(stderr, "fatal: Bad server key size.\n");
exit(1);
}
- if (options.port < 1 || options.port > 65535)
- {
- fprintf(stderr, "fatal: Bad port number.\n");
- exit(1);
- }
if (options.umask != -1)
{
umask(options.umask);
}
+#ifdef ENABLE_LOG_AUTH
+ log_auth_flag = options.log_auth;
+#endif /* ENABLE_LOG_AUTH */
+
/* Check that there are no remaining arguments. */
if (optind < ac)
{
@@ -1048,10 +1093,13 @@
}
else
{
+ for (ai = options.listen_addrs; ai; ai = ai->ai_next)
+ {
/* Create socket for listening. */
- listen_sock = socket(AF_INET, SOCK_STREAM, 0);
+ listen_sock = socket(ai->ai_family, SOCK_STREAM, 0);
if (listen_sock < 0)
fatal("socket: %.100s", strerror(errno));
+ listen_socks[num_listen_socks] = listen_sock;
/* Set socket options. We try to make the port reusable and have it
close as fast as possible without waiting in unnecessary wait states
@@ -1065,21 +1113,30 @@
sizeof(linger));
#endif /* SO_LINGER */
- /* Initialize the socket address. */
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr = options.listen_addr;
- sin.sin_port = htons(options.port);
+ getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ ntop, sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV);
/* Bind the socket to the desired port. */
- if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+ if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0)
{
- error("bind: %.100s", strerror(errno));
- shutdown(listen_sock, 2);
+ error("Bind to port %s on %s failed: %.200s.",
+ strport, ntop, strerror(errno));
close(listen_sock);
- fatal("Bind to port %d failed: %.200s.", options.port,
- strerror(errno));
+ continue;
}
+ num_listen_socks++;
+
+ /* Start listening on the port. */
+ log_msg("Server listening on %s port %s.", ntop, strport);
+ if (listen(listen_sock, 5) < 0)
+ fatal("listen: %.100s", strerror(errno));
+
+ } /* for (ai = options.listen_addrs; ai; ai = ai->ai_next) */
+ freeaddrinfo(options.listen_addrs);
+
+ if (!num_listen_socks)
+ fatal("Cannot bind all addresses.");
if (!debug_flag)
{
@@ -1095,11 +1152,6 @@
}
}
- /* Start listening on the port. */
- log_msg("Server listening on port %d.", options.port);
- if (listen(listen_sock, 5) < 0)
- fatal("listen: %.100s", strerror(errno));
-
/* Generate an rsa key. */
log_msg("Generating %d bit RSA key.", options.server_key_bits);
rsa_generate_key(&sensitive_data.private_key, &public_key,
@@ -1153,18 +1205,28 @@
/* Wait in select until there is a connection. */
FD_ZERO(&fdset);
- FD_SET(listen_sock, &fdset);
- ret = select(listen_sock + 1, &fdset, NULL, NULL, NULL);
- if (ret < 0 || !FD_ISSET(listen_sock, &fdset))
+ maxfd = 0;
+ for (i = 0; i < num_listen_socks; i++)
+ {
+ FD_SET(listen_socks[i], &fdset);
+ if (listen_socks[i] > maxfd)
+ maxfd = listen_socks[i];
+ }
+ ret = select(maxfd + 1, &fdset, NULL, NULL, NULL);
+ if (ret < 0)
{
if (errno == EINTR)
continue;
error("select: %.100s", strerror(errno));
continue;
}
-
- aux = sizeof(sin);
- newsock = accept(listen_sock, (struct sockaddr *)&sin, &aux);
+
+ for (i = 0; i < num_listen_socks; i++)
+ {
+ if (!FD_ISSET(listen_socks[i], &fdset))
+ continue;
+ aux = sizeof(from);
+ newsock = accept(listen_socks[i], (struct sockaddr *)&from, &aux);
if (newsock < 0)
{
if (errno == EINTR)
@@ -1180,7 +1242,7 @@
/* In debugging mode. Close the listening socket, and start
processing the connection without forking. */
debug("Server will not fork when running in debugging mode.");
- close(listen_sock);
+ close_listen_socks();
sock_in = newsock;
sock_out = newsock;
pid = getpid();
@@ -1209,7 +1271,7 @@
the accepted socket. Reinitialize logging (since our
pid has changed). We break out of the loop to handle
the connection. */
- close(listen_sock);
+ close_listen_socks();
sock_in = newsock;
sock_out = newsock;
#ifdef LIBWRAP
@@ -1247,6 +1309,10 @@
/* Close the new socket (the child is now taking care of it). */
close(newsock);
+ } /* for (i = 0; i < num_host_socks; i++) */
+ /* child process check (or debug mode) */
+ if (num_listen_socks < 0)
+ break;
}
}
@@ -2219,6 +2285,9 @@
krb5_parse_name(ssh_context, user, &client);
#endif /* defined(KERBEROS) && defined(KRB5) */
+#ifdef ENABLE_LOG_AUTH
+ unauthenticated_user = user;
+#endif /* ENABLE_LOG_AUTH */
/* Verify that the user is a valid user. We disallow usernames starting
with any characters that are commonly used to start NIS entries. */
pw = getpwnam(user);
@@ -2236,7 +2305,7 @@
pwcopy.pw_class = xstrdup(pw->pw_class);
pwcopy.pw_change = pw->pw_change;
pwcopy.pw_expire = pw->pw_expire;
-#endif /* __bsdi__ && _BSDI_VERSION >= 199510 */
+#endif /* (__bsdi__ && _BSDI_VERSION >= 199510) || (__FreeBSD__ && HAVE_LOGIN_CAP_H) */
pwcopy.pw_dir = xstrdup(pw->pw_dir);
pwcopy.pw_shell = xstrdup(pw->pw_shell);
pw = &pwcopy;
@@ -2274,6 +2343,11 @@
{
/* Authentication with empty password succeeded. */
debug("Login for user %.100s accepted without authentication.", user);
+#ifdef ENABLE_LOG_AUTH
+ log_auth("%.100s from %.700s (%s)",
+ user, get_canonical_hostname(),
+ "empty password accepted");
+#endif /* ENABLE_LOG_AUTH */
authentication_type = SSH_AUTH_PASSWORD;
authenticated = 1;
/* Success packet will be sent after loop below. */
@@ -2348,6 +2422,11 @@
/* Client has successfully authenticated to us. */
log_msg("Kerberos authentication accepted %.100s for login to account %.100s from %.200s",
tkt_user, user, get_canonical_hostname());
+#ifdef ENABLE_LOG_AUTH
+ log_auth("%.100s from %.700s (%s)",
+ user, get_canonical_hostname(),
+ "kerberos authentication accepted");
+#endif /* ENABLE_LOG_AUTH */
authentication_type = SSH_AUTH_KERBEROS;
authenticated = 1;
break;
@@ -2396,6 +2475,11 @@
/* Authentication accepted. */
log_msg("Rhosts authentication accepted for %.100s, remote %.100s on %.700s.",
user, client_user, get_canonical_hostname());
+#ifdef ENABLE_LOG_AUTH
+ log_auth("%.100s from %.100s@%.700s (%s)",
+ user, client_user, get_canonical_hostname(),
+ "rhosts authentication accepted");
+#endif /* ENABLE_LOG_AUTH */
authentication_type = SSH_AUTH_RHOSTS;
authenticated = 1;
remote_user_name = client_user;
@@ -2455,6 +2539,11 @@
options.strict_modes))
{
/* Authentication accepted. */
+#ifdef ENABLE_LOG_AUTH
+ log_auth("%.100s from %.100s@%.700s (%s)",
+ user, client_user, get_canonical_hostname(),
+ "rhosts with RSA host authentication accepted");
+#endif /* ENABLE_LOG_AUTH */
authentication_type = SSH_AUTH_RHOSTS_RSA;
authenticated = 1;
remote_user_name = client_user;
@@ -2488,6 +2577,11 @@
/* Successful authentication. */
mpz_clear(&n);
log_msg("RSA authentication for %.100s accepted.", user);
+#ifdef ENABLE_LOG_AUTH
+ log_auth("%.100s from %.700s (%s)",
+ user, get_canonical_hostname(),
+ "RSA user authentication accepted");
+#endif /* ENABLE_LOG_AUTH */
authentication_type = SSH_AUTH_RSA;
authenticated = 1;
break;
@@ -2622,6 +2716,11 @@
auth_close();
memset(password, 0, strlen(password));
xfree(password);
+#ifdef ENABLE_LOG_AUTH
+ log_auth("%.100s from @%.700s (%s)",
+ user, get_canonical_hostname(),
+ "TIS authentication accepted");
+#endif /* ENABLE_LOG_AUTH */
authentication_type = SSH_AUTH_TIS;
authenticated = 1;
break;
@@ -2682,6 +2781,11 @@
memset(password, 0, strlen(password));
xfree(password);
log_msg("Password authentication for %.100s accepted.", user);
+#ifdef ENABLE_LOG_AUTH
+ log_auth("%.100s from %.700s (%s)",
+ user, get_canonical_hostname(),
+ "password authentication accepted");
+#endif /* ENABLE_LOG_AUTH */
authentication_type = SSH_AUTH_PASSWORD;
authenticated = 1;
break;
@@ -2722,6 +2826,11 @@
}
/* Check if the user is logging in as root and root logins are disallowed. */
+#ifdef ENABLE_LOG_AUTH
+ if ((pw->pw_uid == UID_ROOT && options.permit_root_login == 1) ||
+ (pw->pw_uid == UID_ROOT && options.permit_root_login == 0 && !forced_command))
+ log_auth("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
+#endif /* ENABLE_LOG_AUTH */
if (pw->pw_uid == UID_ROOT && options.permit_root_login == 1)
{
if (authentication_type == SSH_AUTH_PASSWORD)
@@ -2789,6 +2898,9 @@
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
+#ifdef ENABLE_LOG_AUTH
+ unauthenticated_user = NULL;
+#endif /* ENABLE_LOG_AUTH */
/* Perform session preparation. */
do_authenticated(pw);
@@ -3383,15 +3495,16 @@
char line[256];
struct stat st;
int quiet_login;
- struct sockaddr_in from;
+ struct sockaddr_storage from;
int fromlen;
struct pty_cleanup_context cleanup_context;
#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
login_cap_t *lc;
+ time_t warnpassword, warnexpire;
#endif
-#if defined (__bsdi__) && _BSDI_VERSION >= 199510
+#if defined(__FreeBSD__) || (defined (__bsdi__) && _BSDI_VERSION >= 199510)
struct timeval tp;
-#endif /* __bsdi__ && _BSDI_VERSION >= 199510 */
+#endif /* __FreeBSD__ || (__bsdi__ && _BSDI_VERSION >= 199510) */
/* We no longer need the child running on user's privileges. */
userfile_uninit();
@@ -3490,7 +3603,7 @@
/* Record that there was a login on that terminal. */
record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname,
- &from);
+ (struct sockaddr *)&from);
#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
lc = login_getclass(pw->pw_class);
@@ -3549,6 +3662,14 @@
"The Regents of the University of California. ",
"All rights reserved.");
}
+#ifdef HAVE_LOGIN_CAP_H
+#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
+
+ warnpassword = login_getcaptime(lc, "warnpassword",
+ DEFAULT_WARN, DEFAULT_WARN);
+ warnexpire = login_getcaptime(lc, "warnexpire",
+ DEFAULT_WARN, DEFAULT_WARN);
+#endif
#endif
/* Print /etc/motd unless a command was specified or printing it was
@@ -3572,7 +3693,7 @@
fputs(line, stdout);
fclose(f);
}
-#if defined (__bsdi__) && _BSDI_VERSION >= 199510
+#if defined(__FreeBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199510)
if (pw->pw_change || pw->pw_expire)
(void)gettimeofday(&tp, (struct timezone *)NULL);
if (pw->pw_change)
@@ -3979,6 +4100,7 @@
char *user_shell;
char *remote_ip;
int remote_port;
+ int local_port;
#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
login_cap_t *lc;
char *real_shell;
@@ -4025,7 +4147,7 @@
while (fgets(buf, sizeof(buf), f))
fputs(buf, stderr);
fclose(f);
-#if defined (__bsdi__) && _BSDI_VERSION >= 199510
+#if (defined(__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)) || (defined (__bsdi__) && _BSDI_VERSION >= 199510)
if (pw->pw_uid != UID_ROOT &&
!login_getcapbool(lc, "ignorenologin", 0))
exit(254);
@@ -4084,6 +4206,7 @@
user_shell = xstrdup(pw->pw_shell);
remote_ip = xstrdup(get_remote_ipaddr());
remote_port = get_remote_port();
+ local_port = get_local_port();
/* Close the connection descriptors; note that this is the child, and the
server will still have the socket open, and it is important that we
@@ -4103,7 +4226,6 @@
/* Close any extra file descriptors. Note that there may still be
descriptors left by system functions. They will be closed later. */
endpwent();
- endhostent();
/* Set dummy encryption key to clear information about the key from
memory. This key will never be used. */
@@ -4360,7 +4482,7 @@
/* Set SSH_CLIENT. */
snprintf(buf, sizeof(buf),
- "%.50s %d %d", remote_ip, remote_port, options.port);
+ "%.50s %d %d", remote_ip, remote_port, local_port);
child_set_env(&env, &envsize, "SSH_CLIENT", buf);
/* Set SSH_TTY if we have a pty. */
@@ -4533,7 +4655,8 @@
int i;
char name[255], *p;
char line[256];
- struct hostent *hp;
+ struct addrinfo hints, *ai, *aitop;
+ char ntop[ADDRSTRLEN];
strncpy(name, display, sizeof(name));
name[sizeof(name) - 1] = '\0';
@@ -4550,7 +4673,10 @@
/* Moved this call here to avoid a nasty buf in SunOS
4.1.4 libc where gethostbyname closes an unrelated
file descriptor. */
- hp = gethostbyname(name);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = IPv4or6;
+ if (getaddrinfo(name, NULL, &hints, &aitop) != 0)
+ aitop = 0;
snprintf(line, sizeof(line),
"%.200s -q -", options.xauth_path);
@@ -4568,21 +4694,24 @@
cp - display, display, cp, auth_proto,
auth_data);
#endif
- if (hp)
+ if (aitop)
{
- for(i = 0; hp->h_addr_list[i]; i++)
+ for (ai = aitop; ai; ai = ai->ai_next)
{
+ getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ ntop, sizeof(ntop), NULL, 0,
+ NI_NUMERICHOST);
+ if (strchr(ntop, ':'))
+ continue; /* XXX - xauth doesn't accept it */
if (debug_flag)
{
fprintf(stderr, "Running %s add %s%s %s %s\n",
options.xauth_path,
- inet_ntoa(*((struct in_addr *)
- hp->h_addr_list[i])),
+ ntop,
cp, auth_proto, auth_data);
}
fprintf(f, "add %s%s %s %s\n",
- inet_ntoa(*((struct in_addr *)
- hp->h_addr_list[i])),
+ ntop,
cp, auth_proto, auth_data);
}
}
@@ -4632,7 +4761,11 @@
struct stat mailbuf;
if (stat(mailbox, &mailbuf) == -1 || mailbuf.st_size == 0)
+#ifdef __FreeBSD__
+ ;
+#else
printf("No mail.\n");
+#endif
else if (mailbuf.st_atime > mailbuf.st_mtime)
printf("You have mail.\n");
else