Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/networking/fakeidentd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 8436 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 niro 532 /* NB: this file is to be removed soon. See isrv_identd.c */
2    
3     /* vi: set sw=4 ts=4: */
4     /*
5     * A fake identd server
6     *
7     * Adapted to busybox by Thomas Lundquist <thomasez@zelow.no>
8     * Original Author: Tomi Ollila <too@iki.fi>
9     * http://www.guru-group.fi/~too/sw/
10     *
11     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
12     */
13    
14     /* Ident crash course
15     *
16     * Incoming requests are of form "6191, 23\r\n" - peer asks us
17     * "which user connected from your port 6191 to my port 23?"
18     * We should answer:
19     * "6193, 23 : USERID : UNIX : username\r\n"
20     * and close the connection.
21     * We can also reply:
22     * "6195, 23 : USERID : OTHER[,US-ASCII] : username\r\n"
23     * "6195, 23 : ERROR : INVALID-PORT/NO-USER/HIDDEN-USER/UNKNOWN-ERROR\r\n"
24     * but we probably will never want that.
25     */
26    
27     #include "busybox.h"
28    
29     #define SANE_INETD_ONLY_VERSION
30    
31     #ifdef SANE_INETD_ONLY_VERSION
32    
33     int fakeidentd_main(int argc, char **argv)
34     {
35     char buf[64];
36     const char *bogouser = "nobody";
37     char *cur = buf;
38     int rem = sizeof(buf)-1;
39    
40     if (argv[1])
41     bogouser = argv[1];
42    
43     alarm(30);
44     while (1) {
45     char *p;
46     int sz = safe_read(0, cur, rem);
47     if (sz < 0) return 1;
48     cur[sz] = '\0';
49     p = strpbrk(cur, "\r\n");
50     if (p) {
51     *p = '\0';
52     break;
53     }
54     cur += sz;
55     rem -= sz;
56     if (!rem || !sz)
57     break;
58     }
59     printf("%s : USERID : UNIX : %s\r\n", buf, bogouser);
60     return 0;
61     }
62    
63     #else
64    
65     /* Welcome to the bloaty horrors */
66    
67     #include <sys/syslog.h>
68     #include <sys/uio.h>
69    
70     #define MAXCONNS 20
71     #define MAXIDLETIME 45
72    
73     static const char ident_substr[] = " : USERID : UNIX : ";
74     enum { ident_substr_len = sizeof(ident_substr) - 1 };
75     #define PIDFILE "/var/run/identd.pid"
76    
77     /*
78     * We have to track the 'first connection socket' so that we
79     * don't go around closing file descriptors for non-clients.
80     *
81     * descriptor setup normally
82     * 0 = server socket
83     * 1 = syslog fd (hopefully -- otherwise this won't work)
84     * 2 = connection socket after detached from tty. standard error before that
85     * 3 - 2 + MAXCONNS = rest connection sockets
86     *
87     * To try to make sure that syslog fd is what is "requested", the that fd
88     * is closed before openlog() call. It can only severely fail if fd 0
89     * is initially closed.
90     */
91     #define FCS 2
92    
93     /*
94     * FD of the connection is always the index of the connection structure
95     * in `conns' array + FCS
96     */
97     static struct {
98     time_t lasttime;
99     int len;
100     char buf[20];
101     } conns[MAXCONNS];
102    
103     /* When using global variables, bind those at least to a structure. */
104     static struct {
105     const char *identuser;
106     fd_set readfds;
107     int conncnt;
108     } G;
109    
110     static char *bind_ip_address;
111    
112     static int chmatch(char c, char *chars)
113     {
114     for (; *chars; chars++)
115     if (c == *chars)
116     return 1;
117     return 0;
118     }
119    
120     static int skipchars(char **p, char *chars)
121     {
122     while (chmatch(**p, chars))
123     (*p)++;
124     if (**p == '\r' || **p == '\n')
125     return 0;
126     return 1;
127     }
128    
129     static int parseAddrs(char *ptr, char **myaddr, char **heraddr)
130     {
131     /* parse <port-on-server> , <port-on-client> */
132    
133     if (!skipchars(&ptr, " \t"))
134     return -1;
135    
136     *myaddr = ptr;
137    
138     if (!skipchars(&ptr, "1234567890"))
139     return -1;
140    
141     if (!chmatch(*ptr, " \t,"))
142     return -1;
143    
144     *ptr++ = '\0';
145    
146     if (!skipchars(&ptr, " \t,") )
147     return -1;
148    
149     *heraddr = ptr;
150    
151     skipchars(&ptr, "1234567890");
152    
153     if (!chmatch(*ptr, " \n\r"))
154     return -1;
155    
156     *ptr = '\0';
157    
158     return 0;
159     }
160    
161     static void replyError(int s, char *buf)
162     {
163     struct iovec iv[3];
164     iv[0].iov_base = "0, 0 : ERROR : "; iv[0].iov_len = 15;
165     iv[1].iov_base = buf; iv[1].iov_len = strlen(buf);
166     iv[2].iov_base = "\r\n"; iv[2].iov_len = 2;
167     writev(s, iv, 3);
168     }
169    
170     static void reply(int s, char *buf)
171     {
172     char *myaddr, *heraddr;
173    
174     myaddr = heraddr = NULL;
175    
176     if (parseAddrs(buf, &myaddr, &heraddr))
177     replyError(s, "X-INVALID-REQUEST");
178     else {
179     struct iovec iv[6];
180     iv[0].iov_base = myaddr; iv[0].iov_len = strlen(myaddr);
181     iv[1].iov_base = ", "; iv[1].iov_len = 2;
182     iv[2].iov_base = heraddr; iv[2].iov_len = strlen(heraddr);
183     iv[3].iov_base = (void *)ident_substr; iv[3].iov_len = ident_substr_len;
184     iv[4].iov_base = (void *)G.identuser; iv[4].iov_len = strlen(G.identuser);
185     iv[5].iov_base = "\r\n"; iv[5].iov_len = 2;
186     writev(s, iv, 6);
187     }
188     }
189    
190     static void movefd(int from, int to)
191     {
192     if (from != to) {
193     dup2(from, to);
194     close(from);
195     }
196     }
197    
198     static void deleteConn(int s)
199     {
200     int i = s - FCS;
201    
202     close(s);
203    
204     G.conncnt--;
205    
206     /*
207     * Most of the time there is 0 connections. Most often that there
208     * is connections, there is just one connection. When this one connection
209     * closes, i == G.conncnt = 0 -> no copying.
210     * When there is more than one connection, the oldest connections closes
211     * earlier on average. When this happens, the code below starts copying
212     * the connection structure w/ highest index to the place which which is
213     * just deleted. This means that the connection structures are no longer
214     * in chronological order. I'd quess this means that when there is more
215     * than 1 connection, on average every other connection structure needs
216     * to be copied over the time all these connections are deleted.
217     */
218     if (i != G.conncnt) {
219     memcpy(&conns[i], &conns[G.conncnt], sizeof(conns[0]));
220     movefd(G.conncnt + FCS, s);
221     }
222    
223     FD_CLR(G.conncnt + FCS, &G.readfds);
224     }
225    
226     static int closeOldest(void)
227     {
228     time_t min = conns[0].lasttime;
229     int idx = 0;
230     int i;
231    
232     for (i = 1; i < MAXCONNS; i++)
233     if (conns[i].lasttime < min)
234     idx = i;
235    
236     replyError(idx + FCS, "X-SERVER-TOO-BUSY");
237     close(idx + FCS);
238    
239     return idx;
240     }
241    
242     static int checkInput(char *buf, int len, int l)
243     {
244     int i;
245     for (i = len; i < len + l; ++i)
246     if (buf[i] == '\n')
247     return 1;
248     return 0;
249     }
250    
251     /* May succeed. If not, won't care. */
252     static const char *to_unlink;
253     static void writepid(void)
254     {
255     int fd = open(PIDFILE, O_WRONLY|O_CREAT|O_TRUNC, 0664);
256     if (fd < 0)
257     return;
258     to_unlink = PIDFILE;
259     fdprintf(fd, "%d\n", getpid());
260     close(fd);
261     }
262    
263     static void handlexitsigs(int signum)
264     {
265     if (to_unlink)
266     if (unlink(to_unlink) < 0)
267     close(open(to_unlink, O_WRONLY|O_CREAT|O_TRUNC, 0644));
268     exit(0);
269     }
270    
271     int fakeidentd_main(int argc, char **argv)
272     {
273     int fd;
274     pid_t pid;
275    
276     /* FD_ZERO(&G.readfds); - in bss, already zeroed */
277     FD_SET(0, &G.readfds);
278    
279     /* handle -b <ip> parameter */
280     getopt32(argc, argv, "b:", &bind_ip_address);
281     /* handle optional REPLY STRING */
282     if (optind < argc)
283     G.identuser = argv[optind];
284     else
285     G.identuser = "nobody";
286    
287     writepid();
288     signal(SIGTERM, handlexitsigs);
289     signal(SIGINT, handlexitsigs);
290     signal(SIGQUIT, handlexitsigs);
291     signal(SIGHUP, SIG_IGN);
292     signal(SIGPIPE, SIG_IGN); /* ignore closed connections when writing */
293    
294     fd = create_and_bind_stream_or_die(bind_ip_address, bb_lookup_port("identd", "tcp", 113));
295     xlisten(fd, 5);
296    
297     pid = fork();
298     if (pid < 0)
299     bb_perror_msg_and_die("fork");
300     if (pid != 0) /* parent */
301     exit(0);
302     /* child */
303     setsid();
304     movefd(fd, 0);
305     while (fd)
306     close(fd--);
307     openlog(applet_name, 0, LOG_DAEMON);
308     logmode = LOGMODE_SYSLOG;
309    
310     /* main loop where we process all events and never exit */
311     while (1) {
312     fd_set rfds = G.readfds;
313     struct timeval tv = { 15, 0 };
314     int i;
315     int tim = time(NULL);
316    
317     select(G.conncnt + FCS, &rfds, NULL, NULL, G.conncnt? &tv: NULL);
318    
319     for (i = G.conncnt - 1; i >= 0; i--) {
320     int s = i + FCS;
321    
322     if (FD_ISSET(s, &rfds)) {
323     char *buf = conns[i].buf;
324     unsigned len = conns[i].len;
325     unsigned l;
326    
327     l = read(s, buf + len, sizeof(conns[0].buf) - len);
328     if (l > 0) {
329     if (checkInput(buf, len, l)) {
330     reply(s, buf);
331     goto deleteconn;
332     } else if (len + l >= sizeof(conns[0].buf)) {
333     replyError(s, "X-INVALID-REQUEST");
334     goto deleteconn;
335     } else {
336     conns[i].len += l;
337     }
338     } else {
339     goto deleteconn;
340     }
341     conns[i].lasttime = tim;
342     continue;
343     deleteconn:
344     deleteConn(s);
345     } else {
346     /* implement as time_after() in linux kernel sources ... */
347     if (conns[i].lasttime + MAXIDLETIME <= tim) {
348     replyError(s, "X-TIMEOUT");
349     deleteConn(s);
350     }
351     }
352     }
353    
354     if (FD_ISSET(0, &rfds)) {
355     int s = accept(0, NULL, 0);
356    
357     if (s < 0) {
358     if (errno != EINTR)
359     bb_perror_msg("accept");
360     } else {
361     if (G.conncnt == MAXCONNS)
362     i = closeOldest();
363     else
364     i = G.conncnt++;
365    
366     movefd(s, i + FCS); /* move if not already there */
367     FD_SET(i + FCS, &G.readfds);
368     conns[i].len = 0;
369     conns[i].lasttime = time(NULL);
370     }
371     }
372     } /* end of while (1) */
373    
374     return 0;
375     }
376    
377     #endif /* !SANE_INETD_ONLY_VERSION */