2 * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
5 * For copying and distribution information, please see the file
8 /* $FreeBSD: src/crypto/kerberosIV/server/kerberos.c,v 1.2.2.3 2003/02/14 22:37:37 nectar Exp $ */
9 /* $DragonFly: src/crypto/kerberosIV/server/Attic/kerberos.c,v 1.2 2003/06/17 04:24:36 dillon Exp $ */
14 RCSID("$Id: kerberos.c,v 1.87.2.3 2000/10/18 20:24:13 assar Exp $");
17 * If support for really large numbers of network interfaces is
18 * desired, define FD_SETSIZE to some suitable value.
20 #define FD_SETSIZE (4*1024)
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
31 #ifdef TIME_WITH_SYS_TIME
34 #elif defined(HAVE_SYS_TIME_H)
40 #ifdef HAVE_SYS_SELECT_H
41 #include <sys/select.h>
49 #ifdef HAVE_SYS_SOCKET_H
50 #include <sys/socket.h>
52 #ifdef HAVE_NETINET_IN_H
53 #include <netinet/in.h>
55 #ifdef HAVE_ARPA_INET_H
56 #include <arpa/inet.h>
59 #ifdef HAVE_SYS_STAT_H
65 #if defined(HAVE_SYS_IOCTL_H) && SunOS != 40
66 #include <sys/ioctl.h>
68 #ifdef HAVE_SYS_FILIO_H
69 #include <sys/filio.h>
70 #endif /* HAVE_SYS_FILIO_H */
84 #define OPENSSL_DES_LIBDES_COMPATIBILITY
85 #include <openssl/des.h>
95 static des_key_schedule master_key_schedule;
96 static des_cblock master_key;
98 static struct timeval kerb_time;
99 static u_char master_key_version;
103 static int mflag; /* Are we invoked manually? */
104 static char *log_file = KRBLOG; /* name of alt. log file */
105 static int nflag; /* don't check max age */
106 static int rflag; /* alternate realm specified */
108 /* fields within the received request packet */
109 static char *req_name_ptr;
110 static char *req_inst_ptr;
111 static char *req_realm_ptr;
112 static u_int32_t req_time_ws;
114 static char local_realm[REALM_SZ];
117 static int max_age = -1;
118 static int pause_int = -1;
121 * Print usage message and exit.
126 fprintf(stderr, "Usage: %s [-s] [-m] [-n] [-p pause_seconds]"
127 " [-a max_age] [-l log_file] [-i address_to_listen_on]"
128 " [-r realm] [database_pathname]\n",
134 * kerb_err_reply creates an error reply packet and sends it to the
139 kerb_err_reply(int f, struct sockaddr_in *client, int err, char *string)
141 static KTEXT_ST e_pkt_st;
142 KTEXT e_pkt = &e_pkt_st;
143 static char e_msg[128];
145 snprintf (e_msg, sizeof(e_msg),
146 "\nKerberos error -- %s", string);
147 cr_err_reply(e_pkt, req_name_ptr, req_inst_ptr, req_realm_ptr,
148 req_time_ws, err, e_msg);
149 sendto(f, (char*)e_pkt->dat, e_pkt->length, 0, (struct sockaddr *)client,
156 if (pause_int == -1) {
157 klog(L_KRB_PERR, "Kerberos will pause so as not to loop init");
162 snprintf(buf, sizeof(buf),
163 "Kerberos will wait %d seconds before dying so as not to loop init",
165 klog(L_KRB_PERR, buf);
167 klog(L_KRB_PERR, "Do svedania....\n");
173 check_princ(char *p_name, char *instance, unsigned int lifetime, Principal *p)
178 n = kerb_get_principal(p_name, instance, p, 1, &more);
181 lt = klog(L_KRB_PERR, "Database unavailable!");
186 * if more than one p_name, pick one, randomly create a session key,
187 * compute maximum lifetime, lookup authorizations if applicable,
188 * and stuff into cipher.
191 /* service unknown, log error, skip to next request */
192 lt = klog(L_ERR_UNK, "UNKNOWN %s.%s", p_name, instance);
193 return KERB_ERR_PRINCIPAL_UNKNOWN;
196 /* not unique, log error */
197 lt = klog(L_ERR_NUN, "Principal not unique %s.%s", p_name, instance);
198 return KERB_ERR_PRINCIPAL_NOT_UNIQUE;
200 /* If the user's key is null, we want to return an error */
201 if ((p->key_low == 0) && (p->key_high == 0)) {
202 /* User has a null key */
203 lt = klog(L_ERR_NKY, "Null key %s.%s", p_name, instance);
204 return KERB_ERR_NULL_KEY;
206 if (master_key_version != p->kdc_key_ver) {
207 /* log error reply */
209 "Incorrect master key version for %s.%s: %d (should be %d)",
210 p->name, p->instance, p->kdc_key_ver, master_key_version);
211 return KERB_ERR_NAME_MAST_KEY_VER;
213 /* make sure the service hasn't expired */
214 if ((u_int32_t) p->exp_date < (u_int32_t) kerb_time.tv_sec) {
215 /* service did expire, log it */
216 time_t t = p->exp_date;
217 lt = klog(L_ERR_SEXP,
218 "Principal %s.%s expired at %s", p->name, p->instance,
220 return KERB_ERR_NAME_EXP;
227 unseal(des_cblock *key)
229 kdb_encrypt_key(key, key, &master_key, master_key_schedule, DES_DECRYPT);
233 /* Set the key for krb_rd_req so we can check tgt */
236 /* Realm for desired key */
239 static char lastrealm[REALM_SZ];
241 Principal *p = &p_st;
244 if (!strcmp(lastrealm, r))
247 klog(L_ALL_REQ, "Getting key for %s", r);
249 n = kerb_get_principal(KRB_TICKET_GRANTING_TICKET, r, p, 1, &more);
253 /* unseal tgt key from master key */
254 copy_to_key(&p->key_low, &p->key_high, key);
257 strlcpy (lastrealm, r, REALM_SZ);
263 kerberos(unsigned char *buf, int len,
264 char *proto, struct sockaddr_in *client,
265 struct sockaddr_in *server,
273 char name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
274 char service[SNAME_SZ], sinst[INST_SZ];
276 static KTEXT_ST ticket, cipher, adat;
277 KTEXT tk = &ticket, ciph = &cipher, auth = &adat;
279 des_cblock session, key;
281 Principal a_name, s_name;
286 unsigned char *p = buf;
288 strlcpy((char*)rpkt->dat,
294 gettimeofday(&kerb_time, NULL);
297 if(pvno != KRB_PROT_VERSION){
298 msg = klog(L_KRB_PERR, "KRB protocol version mismatch (%d)", pvno);
299 strlcpy((char*)rpkt->dat,
302 return KERB_ERR_PKT_VER;
308 case AUTH_MSG_KDC_REQUEST:
309 /* XXX range check */
310 p += krb_get_nir(p, name, sizeof(name),
312 realm, sizeof(realm));
313 p += krb_get_int(p, &req_time, 4, lsb);
315 p += krb_get_nir(p, service, sizeof(service),
316 sinst, sizeof(sinst), NULL, 0);
318 "AS REQ %s.%s@%s for %s.%s from %s (%s/%u)",
319 name, inst, realm, service, sinst,
320 inet_ntoa(client->sin_addr),
321 proto, ntohs(server->sin_port));
322 if((err = check_princ(name, inst, 0, &a_name))){
323 strlcpy((char*)rpkt->dat,
324 krb_get_err_text(err),
329 if((err = check_princ(service, sinst, 0, &s_name))){
330 strlcpy((char*)rpkt->dat,
331 krb_get_err_text(err),
335 life = min(life, s_name.max_life);
336 life = min(life, a_name.max_life);
338 des_random_key(session);
339 copy_to_key(&s_name.key_low, &s_name.key_high, key);
341 krb_create_ticket(tk, flags, a_name.name, a_name.instance,
342 local_realm, client->sin_addr.s_addr,
344 life, kerb_time.tv_sec,
345 s_name.name, s_name.instance, &key);
346 copy_to_key(&a_name.key_low, &a_name.key_high, key);
348 create_ciph(ciph, session, s_name.name, s_name.instance,
349 local_realm, life, s_name.key_version, tk,
350 kerb_time.tv_sec, &key);
351 memset(&session, 0, sizeof(session));
352 memset(&key, 0, sizeof(key));
355 r = create_auth_reply(name, inst, realm, req_time, 0,
356 a_name.exp_date, a_name.key_version, ciph);
357 memcpy(rpkt, r, sizeof(*rpkt));
360 case AUTH_MSG_APPL_REQUEST:
361 strlcpy(realm, (char*)buf + 3, REALM_SZ);
362 if((err = set_tgtkey(realm))){
363 msg = klog(L_ERR_UNK,
364 "Unknown realm %s from %s (%s/%u)",
365 realm, inet_ntoa(client->sin_addr),
366 proto, ntohs(server->sin_port));
367 strlcpy((char*)rpkt->dat,
372 p = buf + strlen(realm) + 4;
373 p = p + p[0] + p[1] + 2;
374 auth->length = p - buf;
375 memcpy(auth->dat, buf, auth->length);
376 err = krb_rd_req(auth, KRB_TICKET_GRANTING_TICKET,
377 realm, client->sin_addr.s_addr, &ad, 0);
379 msg = klog(L_ERR_UNK,
380 "krb_rd_req from %s (%s/%u): %s",
381 inet_ntoa(client->sin_addr),
383 ntohs(server->sin_port),
384 krb_get_err_text(err));
385 strlcpy((char*)rpkt->dat,
390 p += krb_get_int(p, &req_time, 4, lsb);
392 p += krb_get_nir(p, service, sizeof(service),
393 sinst, sizeof(sinst), NULL, 0);
395 "APPL REQ %s.%s@%s for %s.%s from %s (%s/%u)",
396 ad.pname, ad.pinst, ad.prealm,
398 inet_ntoa(client->sin_addr),
400 ntohs(server->sin_port));
402 if(strcmp(ad.prealm, realm)){
403 msg = klog(L_ERR_UNK, "Can't hop realms: %s -> %s",
405 strlcpy((char*)rpkt->dat,
408 return KERB_ERR_PRINCIPAL_UNKNOWN;
411 if(!strcmp(service, "changepw")){
412 strlcpy((char*)rpkt->dat,
413 "Can't authorize password changed based on TGT",
415 return KERB_ERR_PRINCIPAL_UNKNOWN;
418 err = check_princ(service, sinst, life, &s_name);
420 strlcpy((char*)rpkt->dat,
421 krb_get_err_text(err),
426 krb_time_to_life(kerb_time.tv_sec,
427 krb_life_to_time(ad.time_sec,
429 life = min(life, s_name.max_life);
430 copy_to_key(&s_name.key_low, &s_name.key_high, key);
432 des_random_key(session);
433 krb_create_ticket(tk, flags, ad.pname, ad.pinst, ad.prealm,
434 client->sin_addr.s_addr, &session,
435 life, kerb_time.tv_sec,
436 s_name.name, s_name.instance,
439 memset(&key, 0, sizeof(key));
441 create_ciph(ciph, session, service, sinst, local_realm,
442 life, s_name.key_version, tk,
443 kerb_time.tv_sec, &ad.session);
445 memset(&session, 0, sizeof(session));
446 memset(ad.session, 0, sizeof(ad.session));
449 r =create_auth_reply(ad.pname, ad.pinst, ad.prealm,
450 req_time, 0, 0, 0, ciph);
451 memcpy(rpkt, r, sizeof(*rpkt));
453 memset(&s_name, 0, sizeof(s_name));
456 case AUTH_MSG_ERR_REPLY:
459 msg = klog(L_KRB_PERR,
460 "Unknown message type: %d from %s (%s/%u)",
462 inet_ntoa(client->sin_addr),
464 ntohs(server->sin_port));
465 strlcpy((char*)rpkt->dat,
474 kerberos_wrap(int s, KTEXT data, char *proto, struct sockaddr_in *client,
475 struct sockaddr_in *server)
478 int http_flag = strcmp(proto, "http") == 0;
479 int err = kerberos(data->dat, data->length, proto, client, server, &pkt);
484 "HTTP/1.1 200 OK\r\n"
485 "Server: KTH-KRB/1\r\n"
486 "Content-type: application/octet-stream\r\n"
487 "Content-transfer-encoding: binary\r\n\r\n";
488 sendto(s, msg, strlen(msg), 0, (struct sockaddr *)client,
492 kerb_err_reply(s, client, err, (char*)pkt.dat);
495 sendto(s, pkt.dat, pkt.length, 0, (struct sockaddr *)client,
503 * disconnect all descriptors, remove ourself from the process
504 * group that spawned us.
512 for (s = 0; s < 3; s++) {
516 open("/dev/null", 0);
527 * Make sure that database isn't stale.
529 * Exit if it is; we don't want to tell lies.
538 /* Requires existance of kerb_get_db_age() */
539 gettimeofday(&kerb_time, 0);
540 age = kerb_get_db_age();
542 klog(L_KRB_PERR, "Database currently being updated!");
545 if ((age + max_age) < kerb_time.tv_sec) {
546 klog(L_KRB_PERR, "Database out of date!");
558 struct sockaddr_in addr;
562 mksocket(struct descr *d, struct in_addr addr, int type,
563 const char *service, int port)
568 memset(d, 0, sizeof(struct descr));
569 if ((sock = socket(AF_INET, type, 0)) < 0)
571 if (sock >= FD_SETSIZE) {
573 errx(1, "Aborting: too many descriptors");
575 #if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
576 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
578 warn ("setsockopt (SO_REUSEADDR)");
580 memset(&d->addr, 0, sizeof(d->addr));
581 d->addr.sin_family = AF_INET;
582 d->addr.sin_port = port;
583 d->addr.sin_addr = addr;
584 if (bind(sock, (struct sockaddr *)&d->addr, sizeof(d->addr)) < 0)
585 err (1, "bind '%s/%s' (%d)",
586 service, (type == SOCK_DGRAM) ? "udp" : "tcp",
587 ntohs(d->addr.sin_port));
589 if(type == SOCK_STREAM)
590 listen(sock, SOMAXCONN);
596 static void loop(struct descr *fds, int maxfd);
604 add_port(struct port_spec **ports, int *num_ports, int port, int type)
606 struct port_spec *tmp;
607 tmp = realloc(*ports, (*num_ports + 1) * sizeof(*tmp));
611 tmp[*num_ports].port = port;
612 tmp[*num_ports].type = type;
618 make_sockets(const char *port_spec, struct in_addr *i_addr,
619 struct descr **fds, int *nfds)
623 char *p, *q, *pos = NULL;
625 struct port_spec *ports = NULL;
628 char *port_spec_copy = strdup (port_spec);
630 if (port_spec_copy == NULL)
633 for(p = strtok_r(port_spec_copy, ", \t", &pos);
635 p = strtok_r(NULL, ", \t", &pos)){
636 if(strcmp(p, "+") == 0){
637 add_port(&ports, &num_ports, 88, SOCK_DGRAM);
638 add_port(&ports, &num_ports, 88, SOCK_STREAM);
639 add_port(&ports, &num_ports, 750, SOCK_DGRAM);
640 add_port(&ports, &num_ports, 750, SOCK_STREAM);
647 sp = getservbyname(p, q);
649 tp = ntohs(sp->s_port);
650 else if(sscanf(p, "%d", &tp) != 1) {
651 warnx("Unknown port: %s%s%s", p, q ? "/" : "", q ? q : "");
655 if(strcasecmp(q, "tcp") == 0)
656 add_port(&ports, &num_ports, tp, SOCK_STREAM);
657 else if(strcasecmp(q, "udp") == 0)
658 add_port(&ports, &num_ports, tp, SOCK_DGRAM);
660 warnx("Unknown protocol type: %s", q);
662 add_port(&ports, &num_ports, tp, SOCK_DGRAM);
663 add_port(&ports, &num_ports, tp, SOCK_STREAM);
667 free (port_spec_copy);
670 errx(1, "No valid ports specified!");
674 a = malloc(sizeof(*a) * *nfds);
676 errx (1, "Failed to allocate %lu bytes",
677 (unsigned long)(sizeof(*a) * *nfds));
678 memcpy(a, i_addr, sizeof(struct in_addr));
680 *nfds = k_get_all_addrs (&a);
684 any.s_addr = INADDR_ANY;
686 warnx ("Could not get local addresses, binding to INADDR_ANY");
688 a = malloc(sizeof(*a) * *nfds);
690 errx (1, "Failed to allocate %lu bytes",
691 (unsigned long)(sizeof(*a) * *nfds));
692 memcpy(a, &any, sizeof(struct in_addr));
694 *fds = malloc(*nfds * num_ports * sizeof(**fds));
696 errx (1, "Failed to allocate %lu bytes",
697 (unsigned long)(*nfds * num_ports * sizeof(**fds)));
698 for (i = 0; i < *nfds; i++) {
699 for(j = 0; j < num_ports; j++) {
700 mksocket(*fds + num_ports * i + j, a[i],
701 ports[j].type, "", htons(ports[j].port));
711 main(int argc, char **argv)
720 struct in_addr i_addr;
721 char *port_spec = "+";
723 umask(077); /* Create protected files */
725 set_progname (argv[0]);
727 while ((c = getopt(argc, argv, "snmp:P:a:l:r:i:")) != -1) {
731 * Set parameters to slave server defaults.
733 if (max_age == -1 && !nflag)
734 max_age = THREE_DAYS; /* Survive weekend */
736 pause_int = FIVE_MINUTES; /* 5 minutes */
739 max_age = -1; /* don't check max age. */
743 mflag++; /* running manually; prompt for master key */
746 /* Set pause interval. */
749 pause_int = strtol (optarg, &tmp, 0);
750 if (pause_int == 0 && tmp == optarg) {
751 fprintf(stderr, "pause_int `%s' not a number\n", optarg);
755 if ((pause_int < 5) || (pause_int > ONE_HOUR)) {
756 fprintf(stderr, "pause_int must be between 5 and 3600 seconds.\n");
768 max_age = strtol (optarg, &tmp, 0);
769 if (max_age == 0 && tmp == optarg) {
770 fprintf (stderr, "max_age `%s' not a number\n", optarg);
773 if ((max_age < ONE_HOUR) || (max_age > THREE_DAYS)) {
774 fprintf(stderr, "max_age must be between one hour and "
775 "three days, in seconds\n");
781 /* Set alternate log file */
787 strlcpy(local_realm, optarg, sizeof(local_realm));
790 /* Only listen on this address */
791 if(inet_aton (optarg, &i_addr) == 0) {
792 fprintf (stderr, "Bad address: %s\n", optarg);
803 if (optind == (argc-1)) {
804 if (kerb_db_set_name(argv[optind]) != 0) {
805 fprintf(stderr, "Could not set alternate database name\n");
814 printf("Kerberos server starting\n");
816 if ((!nflag) && (max_age != -1))
817 printf("\tMaximum database age: %d seconds\n", max_age);
819 printf("\tSleep for %d seconds on error\n", pause_int);
821 printf("\tSleep forever on error\n");
823 printf("\tMaster key will be entered manually\n");
825 printf("\tLog file is %s\n", log_file);
827 kset_logfile(log_file);
829 make_sockets(port_spec, i_flag ? &i_addr : NULL, &fds, &nfds);
831 /* do all the database and cache inits */
832 if ((n = kerb_init())) {
834 printf("Kerberos db and cache init ");
835 printf("failed = %d ...exiting\n", n);
839 "Kerberos db and cache init failed = %d ...exiting", n);
844 /* Make sure database isn't stale */
847 /* setup master key */
848 if (kdb_get_master_key (mflag, &master_key, master_key_schedule) != 0) {
849 klog (L_KRB_PERR, "kerberos: couldn't get master key.");
852 kerror = kdb_verify_master_key (&master_key, master_key_schedule, stdout);
854 klog (L_KRB_PERR, "Can't verify master key.");
855 memset(master_key, 0, sizeof (master_key));
856 memset (master_key_schedule, 0, sizeof (master_key_schedule));
860 master_key_version = (u_char) kerror;
862 fprintf(stdout, "\nCurrent Kerberos master key version is %d\n",
866 /* Look up our local realm */
867 krb_get_lrealm(local_realm, 1);
869 fprintf(stdout, "Local realm: %s\n", local_realm);
872 if (set_tgtkey(local_realm)) {
873 /* Ticket granting service unknown */
874 klog(L_KRB_PERR, "Ticket granting ticket service unknown");
875 fprintf(stderr, "Ticket granting ticket service unknown\n");
879 if ((child = fork()) != 0) {
880 printf("Kerberos started, PID=%d\n", child);
886 klog(L_ALL_REQ, "Starting Kerberos for %s (kvno %d)",
887 local_realm, master_key_version);
896 read_socket(struct descr *n)
899 struct sockaddr_in from;
900 int fromlen = sizeof(from);
901 b = recvfrom(n->s, n->buf.dat + n->buf.length,
902 MAX_PKT_LEN - n->buf.length, 0,
903 (struct sockaddr *)&from, &fromlen);
905 if(n->type == SOCK_STREAM){
913 if(n->type == SOCK_STREAM){
915 if(n->buf.length > 4 &&
916 strncmp((char *)n->buf.dat, "GET ", 4) == 0 &&
917 strncmp((char *)n->buf.dat + n->buf.length - 4,
918 "\r\n\r\n", 4) == 0){
922 n->buf.dat[n->buf.length - 1] = 0;
923 strtok_r((char *)n->buf.dat, " \t\r\n", &save);
924 p = strtok_r(NULL, " \t\r\n", &save);
928 n->buf.length = base64_decode(p, n->buf.dat);
929 if(n->buf.length <= 0){
931 "HTTP/1.1 404 Not found\r\n"
932 "Server: KTH-KRB/1\r\n"
933 "Content-type: text/html\r\n"
934 "Content-transfer-encoding: 8bit\r\n\r\n"
935 "<TITLE>404 Not found</TITLE>\r\n"
936 "<H1>404 Not found</H1>\r\n"
937 "That page does not exist. Information about "
938 "<A HREF=\"http://www.pdc.kth.se/kth-krb\">KTH-KRB</A> "
939 "is available elsewhere.\r\n";
940 fromlen = sizeof(from);
941 if(getpeername(n->s,(struct sockaddr*)&from, &fromlen) == 0)
942 klog(L_KRB_PERR, "Unknown HTTP request from %s",
943 inet_ntoa(from.sin_addr));
945 klog(L_KRB_PERR, "Unknown HTTP request from <unknown>");
946 write(n->s, msg, strlen(msg));
955 else if(n->buf.length >= 4 && n->buf.dat[0] == 0){
956 /* if this is a new type of packet (with
957 the length attached to the head of the
958 packet), and there is no more data to
959 be read, fake an old packet, so the
960 code below will work */
962 krb_get_int(n->buf.dat, &len, 4, 0);
963 if(n->buf.length == len + 4){
964 memmove(n->buf.dat, n->buf.dat + 4, len);
969 /* handle request if there are
970 no more bytes to read */
971 fromlen = sizeof(from);
972 getpeername(n->s,(struct sockaddr*)&from, &fromlen);
973 kerberos_wrap(n->s, &n->buf, proto, &from,
980 /* udp packets are atomic */
981 kerberos_wrap(n->s, &n->buf, "udp", &from,
987 static fd_set readfds;
990 loop(struct descr *fds, int base_nfds)
992 int nfds = base_nfds;
993 int max_tcp = min(FD_SETSIZE, getdtablesize()) - fds[base_nfds - 1].s;
996 errx(1, "Aborting: too many descriptors");
998 max_tcp -= 10; /* We need a few extra for DB, logs, etc. */
999 if (max_tcp > 100) max_tcp = 100; /* Keep to some sane limit. */
1004 int next_timeout = 10; /* In seconds */
1006 struct descr *n, *minfree;
1007 int accepted; /* accept at most one socket per `round' */
1010 gettimeofday(&tv, NULL);
1013 /* Remove expired TCP sockets, and add all other
1014 to the set we are selecting on */
1015 for(n = fds; n < fds + nfds; n++){
1016 if(n->s >= 0 && n->timeout && tv.tv_sec > n->timeout){
1017 kerb_err_reply(n->s, NULL, KERB_ERR_TIMEOUT, "Timeout");
1022 if(minfree == NULL) minfree = n;
1025 FD_SET(n->s, &readfds);
1026 maxfd = max(maxfd, n->s);
1027 next_timeout = min(next_timeout, tv.tv_sec - n->timeout);
1029 /* add more space for sockets */
1030 if (minfree == NULL && nfds < base_nfds + max_tcp) {
1034 if (nfds > base_nfds + max_tcp)
1035 nfds = base_nfds + max_tcp;
1036 new = realloc(fds, sizeof(struct descr) * nfds);
1040 for(; i < nfds; i++) fds[i].s = -1;
1043 if (minfree == NULL) {
1045 * We are possibly the subject of a DOS attack, pick a TCP
1046 * connection at random and drop it.
1048 int r = rand() % (nfds - base_nfds);
1050 FD_CLR(fds[r].s, &readfds);
1055 if (next_timeout < 0) next_timeout = 0;
1056 tv.tv_sec = next_timeout;
1058 ret = select(maxfd + 1, &readfds, 0, 0, &tv);
1061 klog(L_KRB_PERR, "select: %s", strerror(errno));
1065 for (n = fds; n < fds + nfds; n++){
1066 if(n->s < 0) continue;
1067 if (FD_ISSET(n->s, &readfds)){
1068 if(n->type == SOCK_STREAM && n->timeout == 0){
1069 /* add accepted socket to list of sockets we are
1072 if(accepted) continue;
1074 s = accept(n->s, NULL, 0);
1075 if (minfree == NULL || s >= FD_SETSIZE) {
1079 minfree->type = SOCK_STREAM;
1080 gettimeofday(&tv, NULL);
1081 minfree->timeout = tv.tv_sec + 4; /* XXX */
1082 minfree->buf.length = 0;
1083 memcpy(&minfree->addr, &n->addr, sizeof(minfree->addr));