summaryrefslogtreecommitdiff
path: root/kerberosIV
diff options
context:
space:
mode:
authorHans Insulander <hin@cvs.openbsd.org>2000-12-10 19:34:12 +0000
committerHans Insulander <hin@cvs.openbsd.org>2000-12-10 19:34:12 +0000
commit5a42588854b7b3f9e2dec7393772b293e0d33e4e (patch)
treed728ba0e5cb58353ea0b5b9c4c79b5f5d9875409 /kerberosIV
parentefe9bf7d000060216c14825637f799acf5fc8784 (diff)
Merge krb4 1.0.4.
Diffstat (limited to 'kerberosIV')
-rw-r--r--kerberosIV/src/appl/bsd/rshd.c12
-rw-r--r--kerberosIV/src/appl/bsd/su.c45
-rw-r--r--kerberosIV/src/appl/ftp/ftpd/ftpd.c2
-rw-r--r--kerberosIV/src/appl/telnet/telnetd/telnetd.c7
-rw-r--r--kerberosIV/src/kadmin/admin_server.c356
-rw-r--r--kerberosIV/src/kuser/klist.c2
-rw-r--r--kerberosIV/src/man/kinit.12
-rw-r--r--kerberosIV/src/server/kerberos.c55
8 files changed, 355 insertions, 126 deletions
diff --git a/kerberosIV/src/appl/bsd/rshd.c b/kerberosIV/src/appl/bsd/rshd.c
index 973c20a0e29..7493a6de665 100644
--- a/kerberosIV/src/appl/bsd/rshd.c
+++ b/kerberosIV/src/appl/bsd/rshd.c
@@ -42,7 +42,7 @@
#include "bsd_locl.h"
-RCSID("$KTH: rshd.c,v 1.60.2.1 2000/06/23 02:40:54 assar Exp $");
+RCSID("$KTH: rshd.c,v 1.60.2.3 2000/10/18 20:39:12 assar Exp $");
extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */
extern int __check_rhosts_file;
@@ -435,6 +435,11 @@ doit(struct sockaddr_in *fromp)
close(2);
close(pv[1]);
+ if (s >= FD_SETSIZE || pv[0] >= FD_SETSIZE) {
+ error ("fd too large\n");
+ exit (1);
+ }
+
FD_ZERO(&readfrom);
FD_SET(s, &readfrom);
FD_SET(pv[0], &readfrom);
@@ -443,6 +448,11 @@ doit(struct sockaddr_in *fromp)
else
nfd = s;
if (doencrypt) {
+ if (pv2[1] >= FD_SETSIZE || pv1[0] >= FD_SETSIZE) {
+ error ("fd too large\n");
+ exit (1);
+ }
+
FD_ZERO(&writeto);
FD_SET(pv2[1], &writeto);
FD_SET(pv1[0], &readfrom);
diff --git a/kerberosIV/src/appl/bsd/su.c b/kerberosIV/src/appl/bsd/su.c
index e93a2b43ba3..f1d28d58831 100644
--- a/kerberosIV/src/appl/bsd/su.c
+++ b/kerberosIV/src/appl/bsd/su.c
@@ -33,20 +33,20 @@
#include "bsd_locl.h"
-RCSID ("$KTH: su.c,v 1.70.2.1 2000/06/23 02:42:28 assar Exp $");
+RCSID ("$KTH: su.c,v 1.70.2.2 2000/12/07 14:04:19 assar Exp $");
#ifdef SYSV_SHADOW
#include "sysv_shadow.h"
#endif
-static int kerberos (char *username, char *user, int uid);
+static int kerberos (char *username, char *user, char *realm, int uid);
static int chshell (char *sh);
static char *ontty (void);
static int koktologin (char *name, char *realm, char *toname);
static int chshell (char *sh);
/* Handle '-' option after all the getopt options */
-#define ARGSTR "Kflmti:"
+#define ARGSTR "Kkflmti:r:"
int destroy_tickets = 0;
static int use_kerberos = 1;
@@ -63,15 +63,22 @@ main (int argc, char **argv)
enum { UNSET, YES, NO } iscsh = UNSET;
char *user, *shell, *avshell, *username, **np;
char shellbuf[MaxPathLen], avshellbuf[MaxPathLen];
+ char *realm = NULL;
set_progname (argv[0]);
+ if (getuid() == 0)
+ use_kerberos = 0;
+
asme = asthem = fastlogin = 0;
while ((ch = getopt (argc, argv, ARGSTR)) != -1)
switch ((char) ch) {
case 'K':
use_kerberos = 0;
break;
+ case 'k':
+ use_kerberos = 1;
+ break;
case 'f':
fastlogin = 1;
break;
@@ -89,10 +96,13 @@ main (int argc, char **argv)
case 'i':
root_inst = optarg;
break;
+ case 'r':
+ realm = optarg;
+ break;
case '?':
default:
fprintf (stderr,
- "usage: su [-Kflmt] [-i root-instance] [-] [login]\n");
+ "usage: su [-Kkflmt] [-i root-instance] [-r realm] [-] [login]\n");
exit (1);
}
/* Don't handle '-' option with getopt */
@@ -150,7 +160,7 @@ main (int argc, char **argv)
syslog (LOG_ALERT, "NIS attack, user %s has uid 0", user);
errx (1, "unknown login %s", user);
}
- if (!use_kerberos || kerberos (username, user, pwd->pw_uid)) {
+ if (!use_kerberos || kerberos (username, user, realm, pwd->pw_uid)) {
#ifndef PASSWD_FALLBACK
errx (1, "won't use /etc/passwd authentication");
#endif
@@ -226,7 +236,7 @@ main (int argc, char **argv)
if (setgid (pwd->pw_gid) < 0)
err (1, "setgid");
if (initgroups (user, pwd->pw_gid)) {
- if (errno == E2BIG) /* Member of to many groups! */
+ if (errno == E2BIG) /* Member of too many groups! */
warn("initgroups failed.");
else
errx(1, "initgroups failed.");
@@ -337,19 +347,26 @@ ontty (void)
}
static int
-kerberos (char *username, char *user, int uid)
+kerberos (char *username, char *user, char *lrealm, int uid)
{
KTEXT_ST ticket;
AUTH_DAT authdata;
struct hostent *hp;
int kerno;
u_long faddr;
- char lrealm[REALM_SZ], krbtkfile[MaxPathLen];
+ char tmp_realm[REALM_SZ], krbtkfile[MaxPathLen];
char hostname[MaxHostNameLen], savehost[MaxHostNameLen];
+ int n;
+ int allowed = 0;
- if (krb_get_lrealm (lrealm, 1) != KSUCCESS)
- return (1);
- if (koktologin (username, lrealm, user) && !uid) {
+ if (lrealm != NULL) {
+ allowed = koktologin (username, lrealm, user) == 0;
+ } else {
+ for (n = 1; !allowed && krb_get_lrealm (tmp_realm, n) == KSUCCESS; ++n)
+ allowed = koktologin (username, tmp_realm, user) == 0;
+ lrealm = tmp_realm;
+ }
+ if (!allowed && !uid) {
#ifndef PASSWD_FALLBACK
warnx ("not in %s's ACL.", user);
#endif
@@ -433,7 +450,11 @@ kerberos (char *username, char *user, int uid)
}
strlcpy (savehost, krb_get_phost (hostname), sizeof (savehost));
- kerno = krb_mk_req (&ticket, "rcmd", savehost, lrealm, 33);
+ for (n = 1; krb_get_lrealm (tmp_realm, n) == KSUCCESS; ++n) {
+ kerno = krb_mk_req (&ticket, "rcmd", savehost, tmp_realm, 33);
+ if (kerno == 0)
+ break;
+ }
if (kerno == KDC_PR_UNKNOWN) {
warnx ("Warning: TGT not verified.");
diff --git a/kerberosIV/src/appl/ftp/ftpd/ftpd.c b/kerberosIV/src/appl/ftp/ftpd/ftpd.c
index 44bbd5f94c3..6f0ad14dfc9 100644
--- a/kerberosIV/src/appl/ftp/ftpd/ftpd.c
+++ b/kerberosIV/src/appl/ftp/ftpd/ftpd.c
@@ -38,7 +38,7 @@
#endif
#include "getarg.h"
-RCSID("$KTH: ftpd.c,v 1.131.2.3 2000/06/23 02:49:48 assar Exp $");
+RCSID("$KTH: ftpd.c,v 1.131.2.4 2000/09/26 09:30:26 assar Exp $");
static char version[] = "Version 6.00";
diff --git a/kerberosIV/src/appl/telnet/telnetd/telnetd.c b/kerberosIV/src/appl/telnet/telnetd/telnetd.c
index 3e627bc2d4c..73825df7db3 100644
--- a/kerberosIV/src/appl/telnet/telnetd/telnetd.c
+++ b/kerberosIV/src/appl/telnet/telnetd/telnetd.c
@@ -33,7 +33,7 @@
#include "telnetd.h"
-RCSID("$KTH: telnetd.c,v 1.58 1999/11/13 06:31:04 assar Exp $");
+RCSID("$KTH: telnetd.c,v 1.58.2.1 2000/10/10 13:12:08 assar Exp $");
#ifdef _SC_CRAY_SECURE_SYS
#include <sys/sysv.h>
@@ -1008,6 +1008,11 @@ my_telnet(int f, int p, char *host, int level, char *autoname)
FD_ZERO(&ibits);
FD_ZERO(&obits);
FD_ZERO(&xbits);
+
+ if (f >= FD_SETSIZE
+ || p >= FD_SETSIZE)
+ fatal(net, "fd too large");
+
/*
* Never look for input if there's still
* stuff in the corresponding output buffer
diff --git a/kerberosIV/src/kadmin/admin_server.c b/kerberosIV/src/kadmin/admin_server.c
index d7bb477c265..bf0626c914c 100644
--- a/kerberosIV/src/kadmin/admin_server.c
+++ b/kerberosIV/src/kadmin/admin_server.c
@@ -30,7 +30,7 @@ or implied warranty.
#include "kadm_locl.h"
-RCSID("$KTH: admin_server.c,v 1.49 1999/11/13 06:32:19 assar Exp $");
+RCSID("$KTH: admin_server.c,v 1.49.2.2 2000/10/18 20:24:57 assar Exp $");
/* Almost all procs and such need this, so it is global */
admin_params prm; /* The command line parameters struct */
@@ -39,8 +39,16 @@ admin_params prm; /* The command line parameters struct */
char *acldir = DEFAULT_ACL_DIR;
static char krbrlm[REALM_SZ];
-static unsigned pidarraysize = 0;
-static int *pidarray = NULL;
+#define MAXCHILDREN 100
+
+struct child {
+ pid_t pid;
+ int pipe_fd;
+ int authenticated;
+};
+
+static unsigned nchildren = 0;
+static struct child children[MAXCHILDREN];
static int exit_now = 0;
@@ -52,46 +60,26 @@ doexit(int sig)
SIGRETURN(0);
}
+static sig_atomic_t do_wait;
+
static
RETSIGTYPE
do_child(int sig)
{
- int pid;
- int i, j;
-
- int status;
-
- pid = wait(&status);
-
- /* Reinstall signal handlers for SysV. Must be done *after* wait */
- signal(SIGCHLD, do_child);
-
- for (i = 0; i < pidarraysize; i++)
- if (pidarray[i] == pid) {
- /* found it */
- for (j = i; j < pidarraysize-1; j++)
- /* copy others down */
- pidarray[j] = pidarray[j+1];
- pidarraysize--;
- if ((WIFEXITED(status) && WEXITSTATUS(status) != 0)
- || WIFSIGNALED(status))
- krb_log("child %d: termsig %d, retcode %d", pid,
- WTERMSIG(status), WEXITSTATUS(status));
- SIGRETURN(0);
- }
- krb_log("child %d not in list: termsig %d, retcode %d", pid,
- WTERMSIG(status), WEXITSTATUS(status));
+ do_wait = 1;
SIGRETURN(0);
}
+
static void
kill_children(void)
{
int i;
- for (i = 0; i < pidarraysize; i++) {
- kill(pidarray[i], SIGINT);
- krb_log("killing child %d", pidarray[i]);
+ for (i = 0; i < nchildren; i++) {
+ kill(children[i].pid, SIGINT);
+ close (children[i].pipe_fd);
+ krb_log("killing child %d", children[i].pid);
}
}
@@ -117,11 +105,6 @@ clear_secrets(void)
server_parm.master_key_version = 0L;
}
-#ifdef DEBUG
-#define cleanexit(code) {kerb_fini(); return;}
-#endif
-
-#ifndef DEBUG
static void
cleanexit(int val)
{
@@ -129,10 +112,21 @@ cleanexit(int val)
clear_secrets();
exit(val);
}
-#endif
+
+static RETSIGTYPE
+sigalrm(int sig)
+{
+ cleanexit(1);
+}
+
+/*
+ * handle the client on the socket `fd' from `who'
+ * `signal_fd' is a pipe on which to signal when the user has been
+ * authenticated
+ */
static void
-process_client(int fd, struct sockaddr_in *who)
+process_client(int fd, struct sockaddr_in *who, int signal_fd)
{
u_char *dat;
int dat_len;
@@ -142,6 +136,13 @@ process_client(int fd, struct sockaddr_in *who)
des_cblock skey;
int more;
int status;
+ int authenticated = 0;
+
+ /* make this connection time-out after 1 second if the user has
+ not managed one transaction succesfully in kadm_ser_in */
+
+ signal(SIGALRM, sigalrm);
+ alarm(2);
#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
{
@@ -230,8 +231,19 @@ process_client(int fd, struct sockaddr_in *who)
if (exit_now) {
cleanexit(0);
}
- if ((retval = kadm_ser_in(&dat, &dat_len, errpkt)) != KADM_SUCCESS)
+ retval = kadm_ser_in(&dat, &dat_len, errpkt);
+
+ if (retval == KADM_SUCCESS) {
+ if (!authenticated) {
+ unsigned char one = 1;
+
+ authenticated = 1;
+ alarm (0);
+ write (signal_fd, &one, 1);
+ }
+ } else {
krb_log("processing request: %s", error_message(retval));
+ }
/* kadm_ser_in did the processing and returned stuff in
dat & dat_len , return the appropriate data */
@@ -255,6 +267,175 @@ process_client(int fd, struct sockaddr_in *who)
/*NOTREACHED*/
}
+static void
+accept_client (int admin_fd)
+{
+ int pipe_fd[2];
+ int addrlen;
+ struct sockaddr_in peer;
+ pid_t pid;
+ int peer_fd;
+
+ /* using up the maximum number of children, try to get rid
+ of one unauthenticated one */
+
+ if (nchildren >= MAXCHILDREN) {
+ int i, nunauth = 0;
+ int victim;
+
+ for (;;) {
+ for (i = 0; i < nchildren; ++i)
+ if (children[i].authenticated == 0)
+ ++nunauth;
+ if (nunauth == 0)
+ return;
+
+ victim = rand() % nchildren;
+ if (children[victim].authenticated == 0) {
+ kill(children[victim].pid, SIGINT);
+ close(children[victim].pipe_fd);
+ for (i = victim; i < nchildren; ++i)
+ children[i] = children[i + 1];
+ --nchildren;
+ break;
+ }
+ }
+ }
+
+ /* accept the conn */
+ addrlen = sizeof(peer);
+ peer_fd = accept(admin_fd, (struct sockaddr *)&peer, &addrlen);
+ if (peer_fd < 0) {
+ krb_log("accept: %s",error_message(errno));
+ return;
+ }
+ if (pipe (pipe_fd) < 0) {
+ krb_log ("pipe: %s", error_message(errno));
+ return;
+ }
+
+ if (pipe_fd[0] >= FD_SETSIZE
+ || pipe_fd[1] >= FD_SETSIZE) {
+ krb_log ("pipe fds too large");
+ close (pipe_fd[0]);
+ close (pipe_fd[1]);
+ return;
+ }
+
+ pid = fork ();
+
+ if (pid < 0) {
+ krb_log ("fork: %s", error_message(errno));
+ close (pipe_fd[0]);
+ close (pipe_fd[1]);
+ return;
+ }
+
+ if (pid != 0) {
+ /* parent */
+ /* fork succeded: keep tabs on child */
+ close(peer_fd);
+ children[nchildren].pid = pid;
+ children[nchildren].pipe_fd = pipe_fd[0];
+ children[nchildren].authenticated = 0;
+ ++nchildren;
+ close (pipe_fd[1]);
+
+ } else {
+ int i;
+
+ /* child */
+ close(admin_fd);
+ close(pipe_fd[0]);
+
+ for (i = 0; i < nchildren; ++i)
+ close (children[i].pipe_fd);
+
+ /*
+ * If we are multihomed we need to figure out which
+ * local address that is used this time since it is
+ * used in "direction" comparison.
+ */
+ getsockname(peer_fd,
+ (struct sockaddr *)&server_parm.admin_addr,
+ &addrlen);
+ /* do stuff */
+ process_client (peer_fd, &peer, pipe_fd[1]);
+ }
+}
+
+/*
+ * handle data signaled from child `child' kadmind
+ */
+
+static void
+handle_child_signal (int child)
+{
+ int ret;
+ unsigned char data[1];
+
+ ret = read (children[child].pipe_fd, data, 1);
+ if (ret < 0) {
+ if (errno != EINTR)
+ krb_log ("read from child %d: %s", child,
+ error_message(errno));
+ return;
+ }
+ if (ret == 0) {
+ close (children[child].pipe_fd);
+ children[child].pipe_fd = -1;
+ return;
+ }
+ if (data)
+ children[child].authenticated = 1;
+}
+
+/*
+ * handle dead children
+ */
+
+static void
+handle_sigchld (void)
+{
+ pid_t pid;
+ int status;
+ int i, j;
+
+ for (;;) {
+ int found = 0;
+
+ pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
+ if (pid == 0 || (pid < 0 && errno == ECHILD))
+ break;
+ if (pid < 0) {
+ krb_log("waitpid: %s", error_message(errno));
+ break;
+ }
+ for (i = 0; i < nchildren; i++)
+ if (children[i].pid == pid) {
+ /* found it */
+ close(children[i].pipe_fd);
+ for (j = i; j < nchildren; j++)
+ /* copy others down */
+ children[j] = children[j+1];
+ --nchildren;
+#if 0
+ if ((WIFEXITED(status) && WEXITSTATUS(status) != 0)
+ || WIFSIGNALED(status))
+ krb_log("child %d: termsig %d, retcode %d", pid,
+ WTERMSIG(status), WEXITSTATUS(status));
+#endif
+ found = 1;
+ }
+#if 0
+ if (!found)
+ krb_log("child %d not in list: termsig %d, retcode %d", pid,
+ WTERMSIG(status), WEXITSTATUS(status));
+#endif
+ }
+ do_wait = 0;
+}
+
/*
kadm_listen
listen on the admin servers port for a request
@@ -262,12 +443,9 @@ listen on the admin servers port for a request
static int
kadm_listen(void)
{
+ int found;
int admin_fd;
- int peer_fd;
- struct pollfd pfd[1];
- struct sockaddr_in peer;
- int addrlen;
- int pid;
+ fd_set readfds;
signal(SIGINT, doexit);
signal(SIGTERM, doexit);
@@ -281,9 +459,15 @@ kadm_listen(void)
if ((admin_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return KADM_NO_SOCK;
+
+ if (admin_fd >= FD_SETSIZE) {
+ krb_log("admin_fd too big");
+ return KADM_NO_BIND;
+ }
+
#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
{
- int one=1;
+ int one = 1;
setsockopt(admin_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one,
sizeof(one));
}
@@ -291,73 +475,43 @@ kadm_listen(void)
if (bind(admin_fd, (struct sockaddr *)&server_parm.admin_addr,
sizeof(struct sockaddr_in)) < 0)
return KADM_NO_BIND;
- listen(admin_fd, 1);
-
- pfd[0].fd = admin_fd;
- pfd[0].events = POLLIN;
+ if (listen(admin_fd, SOMAXCONN) < 0)
+ return KADM_NO_BIND;
for (;;) { /* loop nearly forever */
+ int i;
+ int maxfd = -1;
+
if (exit_now) {
clear_secrets();
kill_children();
return(0);
}
- if (poll(pfd, 1, -1) < 0) {
+ if (do_wait)
+ handle_sigchld ();
+
+ FD_ZERO(&readfds);
+ FD_SET(admin_fd, &readfds);
+ maxfd = max(maxfd, admin_fd);
+ for (i = 0; i < nchildren; ++i)
+ if (children[i].pipe_fd >= 0) {
+ FD_SET(children[i].pipe_fd, &readfds);
+ maxfd = max(maxfd, children[i].pipe_fd);
+ }
+
+ found = select(maxfd + 1, &readfds, NULL, NULL, NULL);
+ if (found < 0) {
if (errno != EINTR)
- krb_log("poll: %s",error_message(errno));
+ krb_log("select: %s",error_message(errno));
continue;
}
- if (pfd[0].revents & POLLIN) {
- /* accept the conn */
- addrlen = sizeof(peer);
- if ((peer_fd = accept(admin_fd, (struct sockaddr *)&peer,
- &addrlen)) < 0) {
- krb_log("accept: %s",error_message(errno));
- continue;
+ if (FD_ISSET(admin_fd, &readfds))
+ accept_client (admin_fd);
+ for (i = 0; i < nchildren; ++i)
+ if (children[i].pipe_fd >= 0
+ && FD_ISSET(children[i].pipe_fd, &readfds)) {
+ handle_child_signal (i);
}
-#ifndef DEBUG
- /* if you want a sep daemon for each server */
- if ((pid = fork())) {
- void *tmp;
-
- /* parent */
- if (pid < 0) {
- krb_log("fork: %s",error_message(errno));
- close(peer_fd);
- continue;
- }
- /* fork succeded: keep tabs on child */
- close(peer_fd);
- tmp = realloc(pidarray,
- (pidarraysize + 1) * sizeof(*pidarray));
- if(tmp == NULL) {
- krb_log ("malloc: no memory. pid %u on its own",
- (unsigned)pid);
- } else {
- pidarray = tmp;
- pidarray[pidarraysize++] = pid;
- }
- } else {
- /* child */
- close(admin_fd);
-#endif /* DEBUG */
- /*
- * If we are multihomed we need to figure out which
- * local address that is used this time since it is
- * used in "direction" comparison.
- */
- getsockname(peer_fd,
- (struct sockaddr *)&server_parm.admin_addr,
- &addrlen);
- /* do stuff */
- process_client (peer_fd, &peer);
-#ifndef DEBUG
- }
-#endif
- } else {
- krb_log("something else woke me up!");
- return(0);
- }
}
/*NOTREACHED*/
}
diff --git a/kerberosIV/src/kuser/klist.c b/kerberosIV/src/kuser/klist.c
index 2ee1c525990..33b5cf1adaa 100644
--- a/kerberosIV/src/kuser/klist.c
+++ b/kerberosIV/src/kuser/klist.c
@@ -22,7 +22,7 @@
#include <parse_time.h>
-RCSID("$KTH: klist.c,v 1.44.2.2 1999/12/07 00:20:43 assar Exp $");
+RCSID("$KTH: klist.c,v 1.44.2.3 2000/10/18 20:38:29 assar Exp $");
static int option_verbose = 0;
diff --git a/kerberosIV/src/man/kinit.1 b/kerberosIV/src/man/kinit.1
index babb22e057f..62eb984359b 100644
--- a/kerberosIV/src/man/kinit.1
+++ b/kerberosIV/src/man/kinit.1
@@ -1,4 +1,4 @@
-.\" $Id: kinit.1,v 1.3 2000/03/30 09:26:50 hin Exp $
+.\" $KTH: kinit.1,v 1.4.4.1 2000/10/10 13:26:51 assar Exp $
.\" Copyright 1989 by the Massachusetts Institute of Technology.
.\"
.\" For copying and distribution information,
diff --git a/kerberosIV/src/server/kerberos.c b/kerberosIV/src/server/kerberos.c
index 8598e46ee9f..f68c9f66b34 100644
--- a/kerberosIV/src/server/kerberos.c
+++ b/kerberosIV/src/server/kerberos.c
@@ -9,7 +9,13 @@
#include "config.h"
#include "protos.h"
-RCSID("$KTH: kerberos.c,v 1.87.2.1 2000/06/23 03:14:04 assar Exp $");
+RCSID("$KTH: kerberos.c,v 1.87.2.3 2000/10/18 20:24:13 assar Exp $");
+
+/*
+ * If support for really large numbers of network interfaces is
+ * desired, define FD_SETSIZE to some suitable value.
+ */
+#define FD_SETSIZE (4*1024)
#include <stdio.h>
#include <stdlib.h>
@@ -560,8 +566,8 @@ mksocket(struct descr *d, struct in_addr addr, int type,
if ((sock = socket(AF_INET, type, 0)) < 0)
err (1, "socket");
if (sock >= FD_SETSIZE) {
- errno = EMFILE;
- errx(1, "aborting: too many descriptors");
+ errno = EMFILE;
+ errx(1, "Aborting: too many descriptors");
}
#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
@@ -976,13 +982,24 @@ read_socket(struct descr *n)
}
}
+static fd_set readfds;
+
static void
-loop(struct descr *fds, int nfds)
+loop(struct descr *fds, int base_nfds)
{
+ int nfds = base_nfds;
+ int max_tcp = min(FD_SETSIZE, getdtablesize()) - fds[base_nfds - 1].s;
+ if (max_tcp <= 10) {
+ errno = EMFILE;
+ errx(1, "Aborting: too many descriptors");
+ }
+ max_tcp -= 10; /* We need a few extra for DB, logs, etc. */
+ if (max_tcp > 100) max_tcp = 100; /* Keep to some sane limit. */
+
for (;;) {
int ret;
- fd_set readfds;
struct timeval tv;
+ int next_timeout = 10; /* In seconds */
int maxfd = 0;
struct descr *n, *minfree;
int accepted; /* accept at most one socket per `round' */
@@ -1005,12 +1022,15 @@ loop(struct descr *fds, int nfds)
}
FD_SET(n->s, &readfds);
maxfd = max(maxfd, n->s);
+ next_timeout = min(next_timeout, tv.tv_sec - n->timeout);
}
/* add more space for sockets */
- if(minfree == NULL){
+ if (minfree == NULL && nfds < base_nfds + max_tcp) {
int i = nfds;
struct descr *new;
nfds *=2;
+ if (nfds > base_nfds + max_tcp)
+ nfds = base_nfds + max_tcp;
new = realloc(fds, sizeof(struct descr) * nfds);
if(new){
fds = new;
@@ -1018,7 +1038,27 @@ loop(struct descr *fds, int nfds)
for(; i < nfds; i++) fds[i].s = -1;
}
}
- ret = select(maxfd + 1, &readfds, 0, 0, 0);
+ if (minfree == NULL) {
+ /*
+ * We are possibly the subject of a DOS attack, pick a TCP
+ * connection at random and drop it.
+ */
+ int r = rand() % (nfds - base_nfds);
+ r = r + base_nfds;
+ FD_CLR(fds[r].s, &readfds);
+ close(fds[r].s);
+ fds[r].s = -1;
+ minfree = &fds[r];
+ }
+ if (next_timeout < 0) next_timeout = 0;
+ tv.tv_sec = next_timeout;
+ tv.tv_usec = 0;
+ ret = select(maxfd + 1, &readfds, 0, 0, &tv);
+ if (ret < 0) {
+ if (errno != EINTR)
+ klog(L_KRB_PERR, "select: %s", strerror(errno));
+ continue;
+ }
accepted = 0;
for (n = fds; n < fds + nfds; n++){
if(n->s < 0) continue;
@@ -1031,7 +1071,6 @@ loop(struct descr *fds, int nfds)
accepted = 1;
s = accept(n->s, NULL, 0);
if (minfree == NULL || s >= FD_SETSIZE) {
- kerb_err_reply(s, NULL, KFAILURE, "Out of memory");
close(s);
}else{
minfree->s = s;