565 lines
20 KiB
Plaintext
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
|