Line 0
Link Here
|
|
|
1 |
#if 0 /* |
2 |
# This program is easy to compile. For example the following ways: |
3 |
# $ sh identd.c |
4 |
# $ sh identd.c -g -DDEBUG |
5 |
# $ sh identd.c -s -DXXXMULTI |
6 |
# $ CC=cc sh identd.c |
7 |
# $ CC=egcs sh identd.c -s -fomit-frame-pointer |
8 |
|
9 |
NAME=`basename $0 .c` |
10 |
[ x`uname` = xSunOS ] && L="-lsocket -lnsl" || L= |
11 |
[ x$1 = x ] && set -- -s -O2 |
12 |
CMDLINE="${CC:-gcc} -Wall $@ -o $NAME $NAME.c $L" |
13 |
echo $CMDLINE; exec $CMDLINE; exit -1 |
14 |
|
15 |
# */ |
16 |
#endif |
17 |
/* |
18 |
* $Id: identd.c,v 1.7 2002/09/29 07:50:20 too Stab $ |
19 |
* |
20 |
* Author: Tomi Ollila <too@iki.fi> |
21 |
* |
22 |
* Created: Sat Nov 25 15:34:07 1995 too |
23 |
* Last modified: Sun Sep 29 10:48:42 2002 too |
24 |
* |
25 |
* This program is standalone 'fake' ident daemon. This program does |
26 |
* not fork() but is configured to handle up to 20 concurrent connections. |
27 |
* Since one connection should not last long, if all 20 connections are |
28 |
* in use, the next connection will close the oldest connection data |
29 |
* has been read. This way this program is not very vulnerable to so |
30 |
* called `denial of service' attack, thus making this ideal "identd" |
31 |
* to be used in a firewall. |
32 |
* |
33 |
* Program takes one (or many) arguments, which if exist, determines the |
34 |
* `user' name(s) that is returned for successful ident query. |
35 |
* |
36 |
* This program is free software; you can redistribute it and/or modify |
37 |
* it under the terms of the GNU General Public License as published by |
38 |
* the Free Software Foundation; either version 2, or (at your option) |
39 |
* any later version. |
40 |
* |
41 |
* This program is distributed in the hope that it will be useful, |
42 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
43 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
44 |
* GNU General Public License for more details. |
45 |
* |
46 |
* HISTORY |
47 |
* $Log: identd.c,v $ |
48 |
* |
49 |
* Revision 1.7 2002/09/29 07:50:20 too |
50 |
* No longer chops up to IDSTR_MAX chars, but uses "%.*s" to limit length; |
51 |
* now works also when XXXMULTI defined. |
52 |
* Back-hacked self-compilable trick, with more tricks to avoid compiler |
53 |
* warnings. |
54 |
* Removed own define of FD_SETSIZE altogether; |
55 |
* systems has it small to begin with. |
56 |
* Line '415' (or whatever that is now) fixed. () -> (void) in func def. |
57 |
* Some fine tuning. |
58 |
* Thanks to Cristian for his patches. |
59 |
* |
60 |
* Revision 1.6.1 2002-09-28 12:30:29 +0200 cii |
61 |
* + added defines for IDSTR_MAX, IDENT_SUBSTR, IDSTR_BUFLEN and IDSTR_MAX |
62 |
* (length limit on the id-string) |
63 |
* + program arg 1 chopped after IDSTR_MAX characters (when applicable); |
64 |
* reason is: |
65 |
* - if the program is called with a relativelly long string as arg 1 |
66 |
* (tested with about 400 chars), a segfault occurs due to an internal |
67 |
* buffer overflow (buffer space reserved for id-string is 128 chars, |
68 |
* but never verified) |
69 |
* - it may trigger buffer overflows in clients |
70 |
* + put a proper comment at the top of the file |
71 |
* + sorted out FD_SETSIZE (on Linux it's already defined) |
72 |
* - moved it down below all the includes |
73 |
* + added time.h include |
74 |
* + added some short comments |
75 |
* + conditionals '{', '}' enclosed |
76 |
* + variable index -> idx in function closeOldest (killed a warning) |
77 |
* + splitted multiple statements on a singel line |
78 |
* + splitted long lines |
79 |
* + prototypes ending in '()' -> '(void)'; changed by protoize |
80 |
* + corrected most warnings, but "function declaration isn't a prototype" |
81 |
* which still occurs on line: 415 |
82 |
* + added IDENT_PORT |
83 |
* + added IDENT_SUBSTR |
84 |
* |
85 |
* Revision 1.6 2002/07/31 16:25:20 too |
86 |
* Now works when started as root (in Linux). Stupid me, tested |
87 |
* only starting as an ordinary loser. |
88 |
* |
89 |
* Revision 1.5 2002/07/29 14:02:42 too |
90 |
* Added possibility to have multible reply users, one (pseudo)randomly |
91 |
* chosen at each time. |
92 |
* |
93 |
* Revision 1.4 2001/02/09 08:45:42 too |
94 |
* Now GID is also changed to nobody/nogroup. |
95 |
* |
96 |
* Revision 1.3 2000/06/07 05:55:44 too |
97 |
* Fixed some Solaris compilation "bugs". |
98 |
* Changed LOG_PERROR to LOG_CONS |
99 |
* |
100 |
* Revision 1.2 1999/07/30 04:08:42 too |
101 |
* Added printing version string (and exit) with `-V' command line option. |
102 |
* |
103 |
* Revision 1.1 1999/04/21 17:23:20 too |
104 |
* - Writes process id to /var/run/identd.pid. |
105 |
* - Changes (effective) user id to `nobody' after initialization |
106 |
* (binding socket etc.). |
107 |
* - Ignores some signals (HUP and PIPE). |
108 |
* - Handles some signals that aborts by default. The handler function |
109 |
* tries to get rid of the pidfile. |
110 |
* |
111 |
* Revision 0.9b 1999/04/15 20:45:12 too |
112 |
* Not so much spaghetti anymore. Added documentation and more replies. |
113 |
* |
114 |
* Revision 0.9 1999/04/12 18:30:00 too |
115 |
* Version for unix systems. Standalone, supports 20 concurrent connections. |
116 |
* The code is quite a spaghetti. But that does not matter. |
117 |
* |
118 |
*/ |
119 |
|
120 |
#include <unistd.h> |
121 |
#include <stdio.h> |
122 |
#include <stdlib.h> |
123 |
#include <stdarg.h> |
124 |
#include <string.h> |
125 |
#include <fcntl.h> |
126 |
#include <signal.h> |
127 |
#include <syslog.h> |
128 |
|
129 |
#include <pwd.h> |
130 |
#include <netdb.h> |
131 |
|
132 |
#include <sys/syslog.h> |
133 |
#include <sys/types.h> |
134 |
#include <sys/time.h> |
135 |
#include <time.h> |
136 |
#include <sys/socket.h> |
137 |
#include <netinet/in.h> |
138 |
#include <errno.h> |
139 |
|
140 |
|
141 |
#define IDENT_PORT 113 |
142 |
#define IDENT_SUBSTR ": USERID : UNIX :" |
143 |
#define MAXCONNS 20 |
144 |
#define MAXIDLETIME 45 |
145 |
#define IDSTR_BUFLEN 128 /*could be dropped down to 64 if tight in memory */ |
146 |
|
147 |
/* |
148 |
* format string is: "%d, %d " IDENT_SUBSTR " %.*s\r\n" |
149 |
* %d is max 999999999 (allowed by this identd, |
150 |
*/ |
151 |
#define IDSTR_MAX (IDSTR_BUFLEN - 1) - \ |
152 |
9 - 2 - 9 - 1 - (sizeof IDENT_SUBSTR - 1) - 1 - 2 |
153 |
|
154 |
#ifndef DEBUG |
155 |
#define FCS 2 /* First Connection Socket */ |
156 |
#define TRACE(x); |
157 |
#else |
158 |
#define FCS 4 |
159 |
#define TRACE(x) printf x |
160 |
#endif |
161 |
|
162 |
/* descriptors when debugging: |
163 |
* 0 = server socket |
164 |
* 1 = standard output (debugging output) |
165 |
* 2 = standard error |
166 |
* 3 = syslog fd (hopefully -- otherwise this won't work) |
167 |
* 4 - 4 + MAXCONNS = connection sockets |
168 |
* |
169 |
* descriptors when not debugging |
170 |
* 0 = server socket |
171 |
* 1 = syslog fd (hopefully -- otherwise this won't work) |
172 |
* 2 = connection socket after detached from tty. standard error before that |
173 |
* 3 - 2 + MAXCONNS = rest connection sockets |
174 |
*/ |
175 |
|
176 |
/* |
177 |
* FD of the connection is always the index of the connection structure |
178 |
* in `conns' array + FCS |
179 |
*/ |
180 |
struct { |
181 |
char buf[20]; |
182 |
int len; |
183 |
time_t lasttime; |
184 |
} conns[MAXCONNS]; |
185 |
|
186 |
|
187 |
/* |
188 |
* To support multible usernames that can be replied by this fake identd |
189 |
* define `XXXMULTI' in compilation command line. This doesn't look guite |
190 |
* pretty, but alternatives looks even uglier. |
191 |
* XXX NOTE: multi currently only slightly tested XXXX. |
192 |
*/ |
193 |
#ifdef XXXMULTI |
194 |
#define IU_IN_STRUCT char ** identuserlist; int identusers |
195 |
#define SET_IU(s, c) do { G.identuserlist = &(s); G.identusers = c; } while (0) |
196 |
#define IU_IN_USAGESTR "[identuser [identuser2...]]" |
197 |
#else |
198 |
#define IU_IN_STRUCT char * identuser |
199 |
#define SET_IU(s, c) G.identuser = (s) |
200 |
#define IU_IN_USAGESTR "[identuser]" |
201 |
#endif |
202 |
|
203 |
/* When using global variables, bind those at least to a structure. */ |
204 |
struct { |
205 |
IU_IN_STRUCT; |
206 |
fd_set readfds; |
207 |
int conncnt; |
208 |
} G; |
209 |
|
210 |
static const char rcs_id[] = |
211 |
/* */ "$Id: identd.c,v 1.7 2002/09/29 07:50:20 too Stab $"; |
212 |
|
213 |
|
214 |
/* |
215 |
* Prototypes |
216 |
*/ |
217 |
static void reply(int s, char * buf); |
218 |
static void replyError(int s, char * buf); |
219 |
static const char * strerrno(void); |
220 |
|
221 |
const int one = 1; |
222 |
char * nobodystr = "nobody"; |
223 |
|
224 |
/* a more general name would be `movefd',but we are only moving sockets here */ |
225 |
static inline void movesocket(int from, int to) |
226 |
{ |
227 |
TRACE(("movesocket(from = %d, to = %d)\n", from, to)); |
228 |
dup2(from, to); |
229 |
close(from); |
230 |
} |
231 |
|
232 |
/* |
233 |
* inetbind() must always return 0 or value < 0. |
234 |
*/ |
235 |
static int inetbind(int port) |
236 |
{ |
237 |
int s; |
238 |
struct sockaddr_in addr = { 0 }; |
239 |
int len = sizeof addr; |
240 |
|
241 |
close(0); |
242 |
|
243 |
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) |
244 |
{ |
245 |
syslog(LOG_CRIT, "cannot create server socket: %s.", strerrno()); |
246 |
return -1; |
247 |
} |
248 |
|
249 |
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one); |
250 |
|
251 |
addr.sin_family = AF_INET; |
252 |
addr.sin_port = htons(port); |
253 |
|
254 |
if (bind(s, (struct sockaddr *)&addr, len) < 0) |
255 |
{ |
256 |
syslog(LOG_CRIT, "cannot bind() server socket: %s.", strerrno()); |
257 |
return -1; |
258 |
} |
259 |
|
260 |
if (listen(s, 5) < 0) |
261 |
{ |
262 |
syslog(LOG_CRIT, "cannot listen() server socket: %s.", strerrno()); |
263 |
return -1; |
264 |
} |
265 |
|
266 |
if (s != 0) |
267 |
{ |
268 |
movesocket(s, 0); |
269 |
} |
270 |
|
271 |
return 0; |
272 |
} |
273 |
|
274 |
static void deleteConn(int s) |
275 |
{ |
276 |
int i = s - FCS; |
277 |
|
278 |
TRACE(("deleteConn(): socket %d, conncnt %d\n", s, G.conncnt)); |
279 |
|
280 |
close(s); |
281 |
|
282 |
G.conncnt--; |
283 |
|
284 |
/* |
285 |
* Most of the time there is 0 connections. Most often that there |
286 |
* is connections, there is just one connection. When this one connection |
287 |
* closes, i == G.conncnt = 0 -> no copying. |
288 |
* When there is more than one connection, the oldest connections closes |
289 |
* earlier on average. When this happens, the code below starts copying |
290 |
* the connection structure w/ highest index to the place which which is |
291 |
* just deleted. This means that the connection structures are no longer |
292 |
* in chronological order. I'd quess this means that when there is more |
293 |
* than 1 connection, on average every other connection structure needs |
294 |
* to be copied over the time all these connections are deleted. |
295 |
*/ |
296 |
if (i != G.conncnt) |
297 |
{ |
298 |
memcpy(&conns[i], &conns[G.conncnt], sizeof conns[0]); |
299 |
movesocket(G.conncnt + FCS, s); |
300 |
} |
301 |
|
302 |
TRACE(("Clearing fd %d, readfds now 0x%x\n\n", |
303 |
G.conncnt + FCS, *(int *)&G.readfds)); |
304 |
|
305 |
FD_CLR(G.conncnt + FCS, &G.readfds); |
306 |
} |
307 |
|
308 |
static int closeOldest(void) |
309 |
{ |
310 |
time_t min = conns[0].lasttime; |
311 |
int idx = 0; |
312 |
int i; |
313 |
|
314 |
for (i = 1; i < MAXCONNS; i++) |
315 |
{ |
316 |
if (conns[i].lasttime < min) |
317 |
{ |
318 |
idx = i; |
319 |
} |
320 |
} |
321 |
TRACE(("closeOldest(): index %d, socket %d\n", idx, idx + FCS)); |
322 |
|
323 |
replyError(idx + FCS, "X-SERVER-TOO-BUSY"); |
324 |
close(idx + FCS); |
325 |
|
326 |
return idx; |
327 |
} |
328 |
|
329 |
|
330 |
static inline int checkInput(char * buf, int len, int l) |
331 |
{ |
332 |
int i; |
333 |
|
334 |
for (i = len; i < len + l; i++) |
335 |
{ |
336 |
if (buf[i] == '\n') |
337 |
{ |
338 |
return 1; |
339 |
} |
340 |
} |
341 |
|
342 |
return 0; |
343 |
} |
344 |
|
345 |
|
346 |
static int getport(void) |
347 |
{ |
348 |
struct servent * se; |
349 |
|
350 |
if ((se = getservbyname("identd", "tcp")) == NULL) |
351 |
{ |
352 |
return IDENT_PORT; |
353 |
} |
354 |
else |
355 |
{ |
356 |
return se->s_port; |
357 |
} |
358 |
} |
359 |
|
360 |
static const char * strerrno() |
361 |
{ |
362 |
return sys_errlist[errno]; |
363 |
} |
364 |
|
365 |
/* here we trust no-one in this program overflows our data buffer. */ |
366 |
static void fdprintf(int fd, char * format, ...) |
367 |
{ |
368 |
va_list ap; |
369 |
char buf[IDSTR_BUFLEN]; |
370 |
|
371 |
va_start(ap, format); |
372 |
vsprintf(buf, format, ap); |
373 |
va_end(ap); |
374 |
|
375 |
write(fd, buf, strlen(buf)); |
376 |
} |
377 |
|
378 |
|
379 |
#ifndef DEBUG |
380 |
static void godaemon(void) |
381 |
{ |
382 |
switch(fork()) |
383 |
{ |
384 |
case -1: |
385 |
exit(-1); |
386 |
|
387 |
case 0: |
388 |
close(1); |
389 |
close(2); |
390 |
setsid(); |
391 |
break; |
392 |
|
393 |
default: |
394 |
exit(0); |
395 |
} |
396 |
} |
397 |
#endif |
398 |
|
399 |
#define PIDFILE "/var/run/identd.pid" |
400 |
|
401 |
static void delpidfile(void) |
402 |
{ |
403 |
/* |
404 |
* Usually nobody has no write/delete access to directory /var/run/ |
405 |
* therefore if file cannot be deleted, it is truncated |
406 |
*/ |
407 |
if (unlink(PIDFILE) < 0) |
408 |
{ |
409 |
close(open(PIDFILE, O_WRONLY|O_CREAT|O_TRUNC, 0644)); |
410 |
} |
411 |
} |
412 |
|
413 |
static void handlexitsigs(void) |
414 |
{ |
415 |
delpidfile(); |
416 |
exit(0); |
417 |
} |
418 |
|
419 |
static void writepid(uid_t nobody, uid_t nogrp) |
420 |
/* May succeed. If not, won't care. */ |
421 |
{ |
422 |
int fd = open(PIDFILE, O_WRONLY|O_CREAT|O_TRUNC, 0664); |
423 |
|
424 |
if (fd < 0) |
425 |
{ |
426 |
return; |
427 |
} |
428 |
|
429 |
fdprintf(fd, "%d\n", getpid()); |
430 |
fchown(fd, nobody, nogrp); |
431 |
close(fd); |
432 |
|
433 |
signal(SIGTERM, (void(*)(int))handlexitsigs); |
434 |
signal(SIGINT, (void(*)(int))handlexitsigs); |
435 |
signal(SIGQUIT, (void(*)(int))handlexitsigs); |
436 |
/* should this handle ILL, ... (see signal(7)) */ |
437 |
} |
438 |
|
439 |
/* parses the `rcs_id' string for version information and prints the info. */ |
440 |
static void printversion(char nameterm) |
441 |
{ |
442 |
struct { |
443 |
const char * p; |
444 |
int l; |
445 |
|
446 |
} s[4] = { { 0 } }; |
447 |
|
448 |
int i; |
449 |
const char * p; |
450 |
|
451 |
for (i = 0, p = rcs_id; *p && i < 4 ; i++) |
452 |
{ |
453 |
while (*p != ' ' && *p != '\0') |
454 |
{ |
455 |
p++; |
456 |
} |
457 |
if (*p++ == ' ' && *p != '\0') |
458 |
{ |
459 |
s[i].p = p; |
460 |
} |
461 |
} |
462 |
|
463 |
if (s[0].p) |
464 |
{ |
465 |
p = s[0].p; |
466 |
while (*p != nameterm && *p != ' ') |
467 |
{ |
468 |
p++; |
469 |
} |
470 |
s[0].l = p - s[0].p; |
471 |
} |
472 |
else |
473 |
{ |
474 |
s[0].p = "unknown"; |
475 |
s[0].l = 7; |
476 |
} |
477 |
|
478 |
for (i = 1; i < 3; i++) |
479 |
{ |
480 |
if (s[i+1].p) |
481 |
{ |
482 |
s[i].l = s[i+1].p - s[i].p - 1; |
483 |
} |
484 |
else |
485 |
{ |
486 |
s[i].p = "unknown"; s[i].l = 7; |
487 |
} |
488 |
} |
489 |
|
490 |
fdprintf(1, "%.*s %.*s (%.*s)\n", |
491 |
s[0].l, s[0].p, /**/ s[1].l, s[1].p, /**/ s[2].l, s[2].p); |
492 |
} |
493 |
|
494 |
int main(int argc, char * argv[]) |
495 |
{ |
496 |
uid_t nobody, nogrp; |
497 |
|
498 |
memset(conns, 0, sizeof conns); |
499 |
memset(&G, 0, sizeof G); |
500 |
FD_ZERO(&G.readfds); |
501 |
FD_SET(0, &G.readfds); |
502 |
|
503 |
if (argv[1]) |
504 |
{ |
505 |
if (argv[1][0] == '-') |
506 |
{ |
507 |
if (argv[1][1] == 'V') |
508 |
{ |
509 |
printversion('.'); |
510 |
return 0; |
511 |
} |
512 |
else |
513 |
{ |
514 |
fdprintf(2, "%s: invalid option -- %c\n", argv[0], argv[1][1]); |
515 |
fdprintf(2, "Usage: %s [-V] " IU_IN_USAGESTR "\n", argv[0]); |
516 |
return 1; |
517 |
} |
518 |
} |
519 |
else |
520 |
{ |
521 |
SET_IU(argv[1], argc - 1); |
522 |
} |
523 |
} |
524 |
else |
525 |
{ |
526 |
SET_IU(nobodystr, 1); |
527 |
} |
528 |
|
529 |
|
530 |
#ifndef DEBUG |
531 |
close(1); /* not debugging, openlog() hopefully uses fd 1. */ |
532 |
#else |
533 |
close(3); /* debugging, TRACE uses fd 1, openlog() hopefully fd 3 */ |
534 |
#endif |
535 |
|
536 |
openlog("identd", LOG_CONS, LOG_DAEMON); |
537 |
|
538 |
{ |
539 |
struct passwd * pw = getpwnam(nobodystr); |
540 |
|
541 |
if (pw) |
542 |
{ |
543 |
nobody = pw->pw_uid; |
544 |
nogrp = pw->pw_gid; |
545 |
} |
546 |
else |
547 |
{ |
548 |
syslog(LOG_CRIT, "Cannot find user `nobody': %s", strerrno()); |
549 |
return -1; |
550 |
} |
551 |
} |
552 |
|
553 |
if (inetbind(getport()) < 0) |
554 |
{ |
555 |
return -1; |
556 |
} |
557 |
|
558 |
/* */ |
559 |
{ |
560 |
int i; |
561 |
|
562 |
for (i = FCS; i < MAXCONNS + FCS; i++) |
563 |
{ |
564 |
close(i); |
565 |
} |
566 |
} |
567 |
|
568 |
#ifdef DEBUG |
569 |
#ifndef LOG_PERROR |
570 |
#define LOG_PERROR 0 |
571 |
#endif |
572 |
openlog("identd", LOG_PERROR, LOG_DAEMON); |
573 |
#else /* not DEBUG */ |
574 |
godaemon(); |
575 |
openlog("identd", 0, LOG_DAEMON); |
576 |
close(2); |
577 |
signal(SIGHUP, SIG_IGN); |
578 |
#endif /* DEBUG */ |
579 |
|
580 |
signal(SIGPIPE, SIG_IGN); /* connection closed when writing (raises ???) */ |
581 |
|
582 |
writepid(nobody, nogrp); |
583 |
|
584 |
setegid(nogrp); setgid(nogrp); setuid(nobody); seteuid(nobody); |
585 |
|
586 |
{ |
587 |
int i; |
588 |
|
589 |
for (i = 0; i < 4; i++) |
590 |
{ |
591 |
char * id = (char)NULL; |
592 |
unsigned int rv = 0; |
593 |
|
594 |
switch (i) |
595 |
{ |
596 |
case 0: |
597 |
rv = (unsigned int)getegid(); |
598 |
id = "egid"; |
599 |
break; |
600 |
case 1: |
601 |
rv = (unsigned int)getgid(); |
602 |
id = "gid"; |
603 |
break; |
604 |
case 2: |
605 |
rv = (unsigned int)geteuid(); |
606 |
id = "euid"; |
607 |
break; |
608 |
case 3: |
609 |
rv = (unsigned int)getuid(); |
610 |
id = "uid"; |
611 |
break; |
612 |
} |
613 |
|
614 |
if (rv == 0) |
615 |
{ |
616 |
syslog(LOG_ERR, |
617 |
"Can not drop all root privileges (%s) !!! %s !!!", |
618 |
id, strerrno()); |
619 |
delpidfile(); |
620 |
return -1; |
621 |
} |
622 |
} |
623 |
} |
624 |
|
625 |
while (2) |
626 |
{ |
627 |
fd_set rfds = G.readfds; |
628 |
struct timeval tv = { 15, 0 }; |
629 |
int i; |
630 |
int tim = time(NULL); |
631 |
|
632 |
TRACE(("calling select(): n = %d, rfds = 0x%x\n\n", |
633 |
G.conncnt + FCS, *(int *)&rfds)); |
634 |
|
635 |
select(G.conncnt + FCS, &rfds, NULL, NULL, G.conncnt? &tv: NULL); |
636 |
|
637 |
for (i = G.conncnt - 1; i >= 0; i--) |
638 |
{ |
639 |
int s = i + FCS; |
640 |
|
641 |
if (FD_ISSET(s, &rfds)) |
642 |
{ |
643 |
char * buf = conns[i].buf; |
644 |
unsigned int len = conns[i].len; |
645 |
unsigned int l; |
646 |
|
647 |
TRACE(("data socket fd_isset %d\n", s)); |
648 |
|
649 |
if ((int)(l = read(s, buf + len, sizeof conns[0].buf - len)) > 0) |
650 |
{ |
651 |
if (checkInput(buf, len, l)) |
652 |
{ |
653 |
reply(s, buf); |
654 |
goto deleteconn; |
655 |
} |
656 |
else if (len + l >= sizeof conns[0].buf) |
657 |
{ |
658 |
replyError(s, "X-INVALID-REQUEST"); |
659 |
goto deleteconn; |
660 |
} |
661 |
else |
662 |
{ |
663 |
conns[i].len += l; |
664 |
} |
665 |
} |
666 |
else |
667 |
{ |
668 |
goto deleteconn; |
669 |
} |
670 |
|
671 |
conns[i].lasttime = tim; |
672 |
continue; |
673 |
|
674 |
deleteconn: |
675 |
deleteConn(s); |
676 |
} |
677 |
else |
678 |
{ |
679 |
/* implement as time_after() in linux kernel sources ... */ |
680 |
if (conns[i].lasttime + MAXIDLETIME <= tim) |
681 |
{ |
682 |
replyError(s, "X-TIMEOUT"); |
683 |
deleteConn(s); |
684 |
} |
685 |
} |
686 |
} |
687 |
|
688 |
if (FD_ISSET(0, &rfds)) |
689 |
{ |
690 |
int s = accept(0, NULL, 0); |
691 |
|
692 |
TRACE(("server socket fd_isset, %d accepted\n", s)); |
693 |
|
694 |
if (s < 0) |
695 |
{ |
696 |
if (errno != EINTR) /* EINTR */ |
697 |
{ |
698 |
syslog(LOG_ERR, "accept: %s", strerrno()); |
699 |
} |
700 |
} |
701 |
else |
702 |
{ |
703 |
if (G.conncnt == MAXCONNS) |
704 |
{ |
705 |
i = closeOldest(); |
706 |
} |
707 |
else |
708 |
{ |
709 |
i = G.conncnt++; |
710 |
} |
711 |
|
712 |
if (s != i + FCS) |
713 |
{ |
714 |
movesocket(s, i + FCS); |
715 |
} |
716 |
|
717 |
FD_SET(i + FCS, &G.readfds); |
718 |
|
719 |
conns[i].len = 0; |
720 |
conns[i].lasttime = time(NULL); |
721 |
} |
722 |
} |
723 |
} |
724 |
} |
725 |
|
726 |
static int parseAddrs(char * ptr, int * myaddr, int * heraddr); |
727 |
|
728 |
static void replyError(int s, char * buf) |
729 |
{ |
730 |
fdprintf(s, "0, 0 : ERROR : %s\r\n", buf); |
731 |
} |
732 |
|
733 |
static void reply(int s, char * buf) |
734 |
{ |
735 |
int myaddr, heraddr; |
736 |
|
737 |
myaddr = heraddr = 0; |
738 |
|
739 |
if (parseAddrs(buf, &myaddr, &heraddr)) |
740 |
{ |
741 |
replyError(s, "X-INVALID-REQUEST"); |
742 |
} |
743 |
else |
744 |
{ |
745 |
fdprintf(s, "%d, %d " IDENT_SUBSTR " %.*s\r\n", |
746 |
myaddr, heraddr, IDSTR_MAX, |
747 |
#ifdef XXXMULTI |
748 |
G.identuserlist[random() % G.identusers] |
749 |
#else |
750 |
G.identuser |
751 |
#endif |
752 |
); |
753 |
} |
754 |
} |
755 |
|
756 |
|
757 |
static int chmatch(char c, char * chars) |
758 |
{ |
759 |
while (*chars) |
760 |
{ |
761 |
if (c == *chars) |
762 |
{ |
763 |
return 1; |
764 |
} |
765 |
else |
766 |
{ |
767 |
chars++; |
768 |
} |
769 |
} |
770 |
|
771 |
return 0; |
772 |
} |
773 |
|
774 |
static int skipchars(char ** p, char * chars) |
775 |
{ |
776 |
while (chmatch(**p, chars)) |
777 |
{ |
778 |
(*p)++; |
779 |
} |
780 |
|
781 |
if (**p == '\r' || **p == '\n') |
782 |
{ |
783 |
return -1; |
784 |
} |
785 |
|
786 |
return 0; |
787 |
} |
788 |
|
789 |
static int parseAddrs(char * ptr, int * myaddr, int * heraddr) |
790 |
{ |
791 |
/* parse <port-on-server> , <port-on-client> */ |
792 |
|
793 |
if (skipchars(&ptr, " \t") || |
794 |
(*myaddr = atoi(ptr)) <= 0 || |
795 |
skipchars(&ptr, "1234567890") || |
796 |
skipchars(&ptr, " \t,") || |
797 |
(*heraddr = atoi(ptr)) <= 0) |
798 |
{ |
799 |
return -1; |
800 |
} |
801 |
|
802 |
return 0; |
803 |
} |
804 |
|
805 |
|
806 |
/* |
807 |
* Variables for Emacs |
808 |
* |
809 |
* Local variables: |
810 |
* mode: c |
811 |
* c-file-style: "gnu" |
812 |
* c-file-offsets: ( (substatement-open . 0) (statement-block-intro . ++) ) |
813 |
* tab-width: 8 |
814 |
* compile-command: "sh identd.c" |
815 |
* End: |
816 |
*/ |
817 |
|
818 |
/* EOF */ |