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 $ */
13 RCSID("$Id: kerberos.c,v 1.87.2.3 2000/10/18 20:24:13 assar Exp $");
16 * If support for really large numbers of network interfaces is
17 * desired, define FD_SETSIZE to some suitable value.
19 #define FD_SETSIZE (4*1024)
26 #ifdef HAVE_SYS_TYPES_H
27 #include <sys/types.h>
30 #ifdef TIME_WITH_SYS_TIME
33 #elif defined(HAVE_SYS_TIME_H)
39 #ifdef HAVE_SYS_SELECT_H
40 #include <sys/select.h>
48 #ifdef HAVE_SYS_SOCKET_H
49 #include <sys/socket.h>
51 #ifdef HAVE_NETINET_IN_H
52 #include <netinet/in.h>
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
58 #ifdef HAVE_SYS_STAT_H
64 #if defined(HAVE_SYS_IOCTL_H) && SunOS != 40
65 #include <sys/ioctl.h>
67 #ifdef HAVE_SYS_FILIO_H
68 #include <sys/filio.h>
69 #endif /* HAVE_SYS_FILIO_H */
83 #define OPENSSL_DES_LIBDES_COMPATIBILITY
84 #include <openssl/des.h>
94 static des_key_schedule master_key_schedule;
95 static des_cblock master_key;
97 static struct timeval kerb_time;
98 static u_char master_key_version;
102 static int mflag; /* Are we invoked manually? */
103 static char *log_file = KRBLOG; /* name of alt. log file */
104 static int nflag; /* don't check max age */
105 static int rflag; /* alternate realm specified */
107 /* fields within the received request packet */
108 static char *req_name_ptr;
109 static char *req_inst_ptr;
110 static char *req_realm_ptr;
111 static u_int32_t req_time_ws;
113 static char local_realm[REALM_SZ];
116 static int max_age = -1;
117 static int pause_int = -1;
120 * Print usage message and exit.
125 fprintf(stderr, "Usage: %s [-s] [-m] [-n] [-p pause_seconds]"
126 " [-a max_age] [-l log_file] [-i address_to_listen_on]"
127 " [-r realm] [database_pathname]\n",
133 * kerb_err_reply creates an error reply packet and sends it to the
138 kerb_err_reply(int f, struct sockaddr_in *client, int err, char *string)
140 static KTEXT_ST e_pkt_st;
141 KTEXT e_pkt = &e_pkt_st;
142 static char e_msg[128];
144 snprintf (e_msg, sizeof(e_msg),
145 "\nKerberos error -- %s", string);
146 cr_err_reply(e_pkt, req_name_ptr, req_inst_ptr, req_realm_ptr,
147 req_time_ws, err, e_msg);
148 sendto(f, (char*)e_pkt->dat, e_pkt->length, 0, (struct sockaddr *)client,
155 if (pause_int == -1) {
156 klog(L_KRB_PERR, "Kerberos will pause so as not to loop init");
161 snprintf(buf, sizeof(buf),
162 "Kerberos will wait %d seconds before dying so as not to loop init",
164 klog(L_KRB_PERR, buf);
166 klog(L_KRB_PERR, "Do svedania....\n");
172 check_princ(char *p_name, char *instance, unsigned int lifetime, Principal *p)
177 n = kerb_get_principal(p_name, instance, p, 1, &more);
180 lt = klog(L_KRB_PERR, "Database unavailable!");
185 * if more than one p_name, pick one, randomly create a session key,
186 * compute maximum lifetime, lookup authorizations if applicable,
187 * and stuff into cipher.
190 /* service unknown, log error, skip to next request */
191 lt = klog(L_ERR_UNK, "UNKNOWN %s.%s", p_name, instance);
192 return KERB_ERR_PRINCIPAL_UNKNOWN;
195 /* not unique, log error */
196 lt = klog(L_ERR_NUN, "Principal not unique %s.%s", p_name, instance);
197 return KERB_ERR_PRINCIPAL_NOT_UNIQUE;
199 /* If the user's key is null, we want to return an error */
200 if ((p->key_low == 0) && (p->key_high == 0)) {
201 /* User has a null key */
202 lt = klog(L_ERR_NKY, "Null key %s.%s", p_name, instance);
203 return KERB_ERR_NULL_KEY;
205 if (master_key_version != p->kdc_key_ver) {
206 /* log error reply */
208 "Incorrect master key version for %s.%s: %d (should be %d)",
209 p->name, p->instance, p->kdc_key_ver, master_key_version);
210 return KERB_ERR_NAME_MAST_KEY_VER;
212 /* make sure the service hasn't expired */
213 if ((u_int32_t) p->exp_date < (u_int32_t) kerb_time.tv_sec) {
214 /* service did expire, log it */
215 time_t t = p->exp_date;
216 lt = klog(L_ERR_SEXP,
217 "Principal %s.%s expired at %s", p->name, p->instance,
219 return KERB_ERR_NAME_EXP;
226 unseal(des_cblock *key)
228 kdb_encrypt_key(key, key, &master_key, master_key_schedule, DES_DECRYPT);
232 /* Set the key for krb_rd_req so we can check tgt */
235 /* Realm for desired key */
238 static char lastrealm[REALM_SZ];
240 Principal *p = &p_st;
243 if (!strcmp(lastrealm, r))
246 klog(L_ALL_REQ, "Getting key for %s", r);
248 n = kerb_get_principal(KRB_TICKET_GRANTING_TICKET, r, p, 1, &more);
252 /* unseal tgt key from master key */
253 copy_to_key(&p->key_low, &p->key_high, key);
256 strlcpy (lastrealm, r, REALM_SZ);
262 kerberos(unsigned char *buf, int len,
263 char *proto, struct sockaddr_in *client,
264 struct sockaddr_in *server,
272 char name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
273 char service[SNAME_SZ], sinst[INST_SZ];
275 static KTEXT_ST ticket, cipher, adat;
276 KTEXT tk = &ticket, ciph = &cipher, auth = &adat;
278 des_cblock session, key;
280 Principal a_name, s_name;
285 unsigned char *p = buf;
287 strlcpy((char*)rpkt->dat,
293 gettimeofday(&kerb_time, NULL);
296 if(pvno != KRB_PROT_VERSION){
297 msg = klog(L_KRB_PERR, "KRB protocol version mismatch (%d)", pvno);
298 strlcpy((char*)rpkt->dat,
301 return KERB_ERR_PKT_VER;
307 case AUTH_MSG_KDC_REQUEST:
308 /* XXX range check */
309 p += krb_get_nir(p, name, sizeof(name),
311 realm, sizeof(realm));
312 p += krb_get_int(p, &req_time, 4, lsb);
314 p += krb_get_nir(p, service, sizeof(service),
315 sinst, sizeof(sinst), NULL, 0);
317 "AS REQ %s.%s@%s for %s.%s from %s (%s/%u)",
318 name, inst, realm, service, sinst,
319 inet_ntoa(client->sin_addr),
320 proto, ntohs(server->sin_port));
321 if((err = check_princ(name, inst, 0, &a_name))){
322 strlcpy((char*)rpkt->dat,
323 krb_get_err_text(err),
328 if((err = check_princ(service, sinst, 0, &s_name))){
329 strlcpy((char*)rpkt->dat,
330 krb_get_err_text(err),
334 life = min(life, s_name.max_life);
335 life = min(life, a_name.max_life);
337 des_random_key(session);
338 copy_to_key(&s_name.key_low, &s_name.key_high, key);
340 krb_create_ticket(tk, flags, a_name.name, a_name.instance,
341 local_realm, client->sin_addr.s_addr,
343 life, kerb_time.tv_sec,
344 s_name.name, s_name.instance, &key);
345 copy_to_key(&a_name.key_low, &a_name.key_high, key);
347 create_ciph(ciph, session, s_name.name, s_name.instance,
348 local_realm, life, s_name.key_version, tk,
349 kerb_time.tv_sec, &key);
350 memset(&session, 0, sizeof(session));
351 memset(&key, 0, sizeof(key));
354 r = create_auth_reply(name, inst, realm, req_time, 0,
355 a_name.exp_date, a_name.key_version, ciph);
356 memcpy(rpkt, r, sizeof(*rpkt));
359 case AUTH_MSG_APPL_REQUEST:
360 strlcpy(realm, (char*)buf + 3, REALM_SZ);
361 if((err = set_tgtkey(realm))){
362 msg = klog(L_ERR_UNK,
363 "Unknown realm %s from %s (%s/%u)",
364 realm, inet_ntoa(client->sin_addr),
365 proto, ntohs(server->sin_port));
366 strlcpy((char*)rpkt->dat,
371 p = buf + strlen(realm) + 4;
372 p = p + p[0] + p[1] + 2;
373 auth->length = p - buf;
374 memcpy(auth->dat, buf, auth->length);
375 err = krb_rd_req(auth, KRB_TICKET_GRANTING_TICKET,
376 realm, client->sin_addr.s_addr, &ad, 0);
378 msg = klog(L_ERR_UNK,
379 "krb_rd_req from %s (%s/%u): %s",
380 inet_ntoa(client->sin_addr),
382 ntohs(server->sin_port),
383 krb_get_err_text(err));
384 strlcpy((char*)rpkt->dat,
389 p += krb_get_int(p, &req_time, 4, lsb);
391 p += krb_get_nir(p, service, sizeof(service),
392 sinst, sizeof(sinst), NULL, 0);
394 "APPL REQ %s.%s@%s for %s.%s from %s (%s/%u)",
395 ad.pname, ad.pinst, ad.prealm,
397 inet_ntoa(client->sin_addr),
399 ntohs(server->sin_port));
401 if(strcmp(ad.prealm, realm)){
402 msg = klog(L_ERR_UNK, "Can't hop realms: %s -> %s",
404 strlcpy((char*)rpkt->dat,
407 return KERB_ERR_PRINCIPAL_UNKNOWN;
410 if(!strcmp(service, "changepw")){
411 strlcpy((char*)rpkt->dat,
412 "Can't authorize password changed based on TGT",
414 return KERB_ERR_PRINCIPAL_UNKNOWN;
417 err = check_princ(service, sinst, life, &s_name);
419 strlcpy((char*)rpkt->dat,
420 krb_get_err_text(err),
425 krb_time_to_life(kerb_time.tv_sec,
426 krb_life_to_time(ad.time_sec,
428 life = min(life, s_name.max_life);
429 copy_to_key(&s_name.key_low, &s_name.key_high, key);
431 des_random_key(session);
432 krb_create_ticket(tk, flags, ad.pname, ad.pinst, ad.prealm,
433 client->sin_addr.s_addr, &session,
434 life, kerb_time.tv_sec,
435 s_name.name, s_name.instance,
438 memset(&key, 0, sizeof(key));
440 create_ciph(ciph, session, service, sinst, local_realm,
441 life, s_name.key_version, tk,
442 kerb_time.tv_sec, &ad.session);
444 memset(&session, 0, sizeof(session));
445 memset(ad.session, 0, sizeof(ad.session));
448 r =create_auth_reply(ad.pname, ad.pinst, ad.prealm,
449 req_time, 0, 0, 0, ciph);
450 memcpy(rpkt, r, sizeof(*rpkt));
452 memset(&s_name, 0, sizeof(s_name));
455 case AUTH_MSG_ERR_REPLY:
458 msg = klog(L_KRB_PERR,
459 "Unknown message type: %d from %s (%s/%u)",
461 inet_ntoa(client->sin_addr),
463 ntohs(server->sin_port));
464 strlcpy((char*)rpkt->dat,
473 kerberos_wrap(int s, KTEXT data, char *proto, struct sockaddr_in *client,
474 struct sockaddr_in *server)
477 int http_flag = strcmp(proto, "http") == 0;
478 int err = kerberos(data->dat, data->length, proto, client, server, &pkt);
483 "HTTP/1.1 200 OK\r\n"
484 "Server: KTH-KRB/1\r\n"
485 "Content-type: application/octet-stream\r\n"
486 "Content-transfer-encoding: binary\r\n\r\n";
487 sendto(s, msg, strlen(msg), 0, (struct sockaddr *)client,
491 kerb_err_reply(s, client, err, (char*)pkt.dat);
494 sendto(s, pkt.dat, pkt.length, 0, (struct sockaddr *)client,
502 * disconnect all descriptors, remove ourself from the process
503 * group that spawned us.
511 for (s = 0; s < 3; s++) {
515 open("/dev/null", 0);
526 * Make sure that database isn't stale.
528 * Exit if it is; we don't want to tell lies.
537 /* Requires existance of kerb_get_db_age() */
538 gettimeofday(&kerb_time, 0);
539 age = kerb_get_db_age();
541 klog(L_KRB_PERR, "Database currently being updated!");
544 if ((age + max_age) < kerb_time.tv_sec) {
545 klog(L_KRB_PERR, "Database out of date!");
557 struct sockaddr_in addr;
561 mksocket(struct descr *d, struct in_addr addr, int type,
562 const char *service, int port)
567 memset(d, 0, sizeof(struct descr));
568 if ((sock = socket(AF_INET, type, 0)) < 0)
570 if (sock >= FD_SETSIZE) {
572 errx(1, "Aborting: too many descriptors");
574 #if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
575 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
577 warn ("setsockopt (SO_REUSEADDR)");
579 memset(&d->addr, 0, sizeof(d->addr));
580 d->addr.sin_family = AF_INET;
581 d->addr.sin_port = port;
582 d->addr.sin_addr = addr;
583 if (bind(sock, (struct sockaddr *)&d->addr, sizeof(d->addr)) < 0)
584 err (1, "bind '%s/%s' (%d)",
585 service, (type == SOCK_DGRAM) ? "udp" : "tcp",
586 ntohs(d->addr.sin_port));
588 if(type == SOCK_STREAM)
589 listen(sock, SOMAXCONN);
595 static void loop(struct descr *fds, int maxfd);
603 add_port(struct port_spec **ports, int *num_ports, int port, int type)
605 struct port_spec *tmp;
606 tmp = realloc(*ports, (*num_ports + 1) * sizeof(*tmp));
610 tmp[*num_ports].port = port;
611 tmp[*num_ports].type = type;
617 make_sockets(const char *port_spec, struct in_addr *i_addr,
618 struct descr **fds, int *nfds)
622 char *p, *q, *pos = NULL;
624 struct port_spec *ports = NULL;
627 char *port_spec_copy = strdup (port_spec);
629 if (port_spec_copy == NULL)
632 for(p = strtok_r(port_spec_copy, ", \t", &pos);
634 p = strtok_r(NULL, ", \t", &pos)){
635 if(strcmp(p, "+") == 0){
636 add_port(&ports, &num_ports, 88, SOCK_DGRAM);
637 add_port(&ports, &num_ports, 88, SOCK_STREAM);
638 add_port(&ports, &num_ports, 750, SOCK_DGRAM);
639 add_port(&ports, &num_ports, 750, SOCK_STREAM);
646 sp = getservbyname(p, q);
648 tp = ntohs(sp->s_port);
649 else if(sscanf(p, "%d", &tp) != 1) {
650 warnx("Unknown port: %s%s%s", p, q ? "/" : "", q ? q : "");
654 if(strcasecmp(q, "tcp") == 0)
655 add_port(&ports, &num_ports, tp, SOCK_STREAM);
656 else if(strcasecmp(q, "udp") == 0)
657 add_port(&ports, &num_ports, tp, SOCK_DGRAM);
659 warnx("Unknown protocol type: %s", q);
661 add_port(&ports, &num_ports, tp, SOCK_DGRAM);
662 add_port(&ports, &num_ports, tp, SOCK_STREAM);
666 free (port_spec_copy);
669 errx(1, "No valid ports specified!");
673 a = malloc(sizeof(*a) * *nfds);
675 errx (1, "Failed to allocate %lu bytes",
676 (unsigned long)(sizeof(*a) * *nfds));
677 memcpy(a, i_addr, sizeof(struct in_addr));
679 *nfds = k_get_all_addrs (&a);
683 any.s_addr = INADDR_ANY;
685 warnx ("Could not get local addresses, binding to INADDR_ANY");
687 a = malloc(sizeof(*a) * *nfds);
689 errx (1, "Failed to allocate %lu bytes",
690 (unsigned long)(sizeof(*a) * *nfds));
691 memcpy(a, &any, sizeof(struct in_addr));
693 *fds = malloc(*nfds * num_ports * sizeof(**fds));
695 errx (1, "Failed to allocate %lu bytes",
696 (unsigned long)(*nfds * num_ports * sizeof(**fds)));
697 for (i = 0; i < *nfds; i++) {
698 for(j = 0; j < num_ports; j++) {
699 mksocket(*fds + num_ports * i + j, a[i],
700 ports[j].type, "", htons(ports[j].port));
710 main(int argc, char **argv)
719 struct in_addr i_addr;
720 char *port_spec = "+";
722 umask(077); /* Create protected files */
724 set_progname (argv[0]);
726 while ((c = getopt(argc, argv, "snmp:P:a:l:r:i:")) != -1) {
730 * Set parameters to slave server defaults.
732 if (max_age == -1 && !nflag)
733 max_age = THREE_DAYS; /* Survive weekend */
735 pause_int = FIVE_MINUTES; /* 5 minutes */
738 max_age = -1; /* don't check max age. */
742 mflag++; /* running manually; prompt for master key */
745 /* Set pause interval. */
748 pause_int = strtol (optarg, &tmp, 0);
749 if (pause_int == 0 && tmp == optarg) {
750 fprintf(stderr, "pause_int `%s' not a number\n", optarg);
754 if ((pause_int < 5) || (pause_int > ONE_HOUR)) {
755 fprintf(stderr, "pause_int must be between 5 and 3600 seconds.\n");
767 max_age = strtol (optarg, &tmp, 0);
768 if (max_age == 0 && tmp == optarg) {
769 fprintf (stderr, "max_age `%s' not a number\n", optarg);
772 if ((max_age < ONE_HOUR) || (max_age > THREE_DAYS)) {
773 fprintf(stderr, "max_age must be between one hour and "
774 "three days, in seconds\n");
780 /* Set alternate log file */
786 strlcpy(local_realm, optarg, sizeof(local_realm));
789 /* Only listen on this address */
790 if(inet_aton (optarg, &i_addr) == 0) {
791 fprintf (stderr, "Bad address: %s\n", optarg);
802 if (optind == (argc-1)) {
803 if (kerb_db_set_name(argv[optind]) != 0) {
804 fprintf(stderr, "Could not set alternate database name\n");
813 printf("Kerberos server starting\n");
815 if ((!nflag) && (max_age != -1))
816 printf("\tMaximum database age: %d seconds\n", max_age);
818 printf("\tSleep for %d seconds on error\n", pause_int);
820 printf("\tSleep forever on error\n");
822 printf("\tMaster key will be entered manually\n");
824 printf("\tLog file is %s\n", log_file);
826 kset_logfile(log_file);
828 make_sockets(port_spec, i_flag ? &i_addr : NULL, &fds, &nfds);
830 /* do all the database and cache inits */
831 if ((n = kerb_init())) {
833 printf("Kerberos db and cache init ");
834 printf("failed = %d ...exiting\n", n);
838 "Kerberos db and cache init failed = %d ...exiting", n);
843 /* Make sure database isn't stale */
846 /* setup master key */
847 if (kdb_get_master_key (mflag, &master_key, master_key_schedule) != 0) {
848 klog (L_KRB_PERR, "kerberos: couldn't get master key.");
851 kerror = kdb_verify_master_key (&master_key, master_key_schedule, stdout);
853 klog (L_KRB_PERR, "Can't verify master key.");
854 memset(master_key, 0, sizeof (master_key));
855 memset (master_key_schedule, 0, sizeof (master_key_schedule));
859 master_key_version = (u_char) kerror;
861 fprintf(stdout, "\nCurrent Kerberos master key version is %d\n",
865 /* Look up our local realm */
866 krb_get_lrealm(local_realm, 1);
868 fprintf(stdout, "Local realm: %s\n", local_realm);
871 if (set_tgtkey(local_realm)) {
872 /* Ticket granting service unknown */
873 klog(L_KRB_PERR, "Ticket granting ticket service unknown");
874 fprintf(stderr, "Ticket granting ticket service unknown\n");
878 if ((child = fork()) != 0) {
879 printf("Kerberos started, PID=%d\n", child);
885 klog(L_ALL_REQ, "Starting Kerberos for %s (kvno %d)",
886 local_realm, master_key_version);
895 read_socket(struct descr *n)
898 struct sockaddr_in from;
899 int fromlen = sizeof(from);
900 b = recvfrom(n->s, n->buf.dat + n->buf.length,
901 MAX_PKT_LEN - n->buf.length, 0,
902 (struct sockaddr *)&from, &fromlen);
904 if(n->type == SOCK_STREAM){
912 if(n->type == SOCK_STREAM){
914 if(n->buf.length > 4 &&
915 strncmp((char *)n->buf.dat, "GET ", 4) == 0 &&
916 strncmp((char *)n->buf.dat + n->buf.length - 4,
917 "\r\n\r\n", 4) == 0){
921 n->buf.dat[n->buf.length - 1] = 0;
922 strtok_r((char *)n->buf.dat, " \t\r\n", &save);
923 p = strtok_r(NULL, " \t\r\n", &save);
927 n->buf.length = base64_decode(p, n->buf.dat);
928 if(n->buf.length <= 0){
930 "HTTP/1.1 404 Not found\r\n"
931 "Server: KTH-KRB/1\r\n"
932 "Content-type: text/html\r\n"
933 "Content-transfer-encoding: 8bit\r\n\r\n"
934 "<TITLE>404 Not found</TITLE>\r\n"
935 "<H1>404 Not found</H1>\r\n"
936 "That page does not exist. Information about "
937 "<A HREF=\"http://www.pdc.kth.se/kth-krb\">KTH-KRB</A> "
938 "is available elsewhere.\r\n";
939 fromlen = sizeof(from);
940 if(getpeername(n->s,(struct sockaddr*)&from, &fromlen) == 0)
941 klog(L_KRB_PERR, "Unknown HTTP request from %s",
942 inet_ntoa(from.sin_addr));
944 klog(L_KRB_PERR, "Unknown HTTP request from <unknown>");
945 write(n->s, msg, strlen(msg));
954 else if(n->buf.length >= 4 && n->buf.dat[0] == 0){
955 /* if this is a new type of packet (with
956 the length attached to the head of the
957 packet), and there is no more data to
958 be read, fake an old packet, so the
959 code below will work */
961 krb_get_int(n->buf.dat, &len, 4, 0);
962 if(n->buf.length == len + 4){
963 memmove(n->buf.dat, n->buf.dat + 4, len);
968 /* handle request if there are
969 no more bytes to read */
970 fromlen = sizeof(from);
971 getpeername(n->s,(struct sockaddr*)&from, &fromlen);
972 kerberos_wrap(n->s, &n->buf, proto, &from,
979 /* udp packets are atomic */
980 kerberos_wrap(n->s, &n->buf, "udp", &from,
986 static fd_set readfds;
989 loop(struct descr *fds, int base_nfds)
991 int nfds = base_nfds;
992 int max_tcp = min(FD_SETSIZE, getdtablesize()) - fds[base_nfds - 1].s;
995 errx(1, "Aborting: too many descriptors");
997 max_tcp -= 10; /* We need a few extra for DB, logs, etc. */
998 if (max_tcp > 100) max_tcp = 100; /* Keep to some sane limit. */
1003 int next_timeout = 10; /* In seconds */
1005 struct descr *n, *minfree;
1006 int accepted; /* accept at most one socket per `round' */
1009 gettimeofday(&tv, NULL);
1012 /* Remove expired TCP sockets, and add all other
1013 to the set we are selecting on */
1014 for(n = fds; n < fds + nfds; n++){
1015 if(n->s >= 0 && n->timeout && tv.tv_sec > n->timeout){
1016 kerb_err_reply(n->s, NULL, KERB_ERR_TIMEOUT, "Timeout");
1021 if(minfree == NULL) minfree = n;
1024 FD_SET(n->s, &readfds);
1025 maxfd = max(maxfd, n->s);
1026 next_timeout = min(next_timeout, tv.tv_sec - n->timeout);
1028 /* add more space for sockets */
1029 if (minfree == NULL && nfds < base_nfds + max_tcp) {
1033 if (nfds > base_nfds + max_tcp)
1034 nfds = base_nfds + max_tcp;
1035 new = realloc(fds, sizeof(struct descr) * nfds);
1039 for(; i < nfds; i++) fds[i].s = -1;
1042 if (minfree == NULL) {
1044 * We are possibly the subject of a DOS attack, pick a TCP
1045 * connection at random and drop it.
1047 int r = rand() % (nfds - base_nfds);
1049 FD_CLR(fds[r].s, &readfds);
1054 if (next_timeout < 0) next_timeout = 0;
1055 tv.tv_sec = next_timeout;
1057 ret = select(maxfd + 1, &readfds, 0, 0, &tv);
1060 klog(L_KRB_PERR, "select: %s", strerror(errno));
1064 for (n = fds; n < fds + nfds; n++){
1065 if(n->s < 0) continue;
1066 if (FD_ISSET(n->s, &readfds)){
1067 if(n->type == SOCK_STREAM && n->timeout == 0){
1068 /* add accepted socket to list of sockets we are
1071 if(accepted) continue;
1073 s = accept(n->s, NULL, 0);
1074 if (minfree == NULL || s >= FD_SETSIZE) {
1078 minfree->type = SOCK_STREAM;
1079 gettimeofday(&tv, NULL);
1080 minfree->timeout = tv.tv_sec + 4; /* XXX */
1081 minfree->buf.length = 0;
1082 memcpy(&minfree->addr, &n->addr, sizeof(minfree->addr));