diff options
author | Hans Insulander <hin@cvs.openbsd.org> | 2000-12-10 19:34:12 +0000 |
---|---|---|
committer | Hans Insulander <hin@cvs.openbsd.org> | 2000-12-10 19:34:12 +0000 |
commit | 5a42588854b7b3f9e2dec7393772b293e0d33e4e (patch) | |
tree | d728ba0e5cb58353ea0b5b9c4c79b5f5d9875409 /kerberosIV | |
parent | efe9bf7d000060216c14825637f799acf5fc8784 (diff) |
Merge krb4 1.0.4.
Diffstat (limited to 'kerberosIV')
-rw-r--r-- | kerberosIV/src/appl/bsd/rshd.c | 12 | ||||
-rw-r--r-- | kerberosIV/src/appl/bsd/su.c | 45 | ||||
-rw-r--r-- | kerberosIV/src/appl/ftp/ftpd/ftpd.c | 2 | ||||
-rw-r--r-- | kerberosIV/src/appl/telnet/telnetd/telnetd.c | 7 | ||||
-rw-r--r-- | kerberosIV/src/kadmin/admin_server.c | 356 | ||||
-rw-r--r-- | kerberosIV/src/kuser/klist.c | 2 | ||||
-rw-r--r-- | kerberosIV/src/man/kinit.1 | 2 | ||||
-rw-r--r-- | kerberosIV/src/server/kerberos.c | 55 |
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; |