diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-11 23:26:13 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-11 23:26:13 +0000 |
commit | f8138d1f91c913166bffb0077a0fe06831a77ecf (patch) | |
tree | ad67c96ccbbce0620186dd2926451f69c0831f0f /networking/fakeidentd.c | |
parent | 4fa5e8b455c732db3176c7dbd58dec63d38f4273 (diff) | |
download | busybox-w32-f8138d1f91c913166bffb0077a0fe06831a77ecf.tar.gz busybox-w32-f8138d1f91c913166bffb0077a0fe06831a77ecf.tar.bz2 busybox-w32-f8138d1f91c913166bffb0077a0fe06831a77ecf.zip |
fakeinetd: attempted ipv6-ization (and it's done)
but entire applet can be orders of magnitude smaller
if written as an inetd service.
So did that (#ifdef'ed out entire old version).
inetd version is less than 10% of old one!
function old new delta
packed_usage 22083 22105 +22
nobodystr 4 - -4
bind_ip_address 4 - -4
ident_substr 20 - -20
chmatch 22 - -22
movefd 25 - -25
skipchars 49 - -49
handlexitsigs 51 - -51
replyError 70 - -70
.rodata 158120 158024 -96
deleteConn 102 - -102
G 524 388 -136
conns 560 - -560
fakeidentd_main 1457 143 -1314
------------------------------------------------------------------------------
(add/remove: 0/10 grow/shrink: 1/3 up/down: 22/-2453) Total: -2431 bytes
Diffstat (limited to 'networking/fakeidentd.c')
-rw-r--r-- | networking/fakeidentd.c | 346 |
1 files changed, 167 insertions, 179 deletions
diff --git a/networking/fakeidentd.c b/networking/fakeidentd.c index 7eac48065..8c07082fc 100644 --- a/networking/fakeidentd.c +++ b/networking/fakeidentd.c | |||
@@ -9,12 +9,62 @@ | |||
9 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 9 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* Ident crash course | ||
13 | * | ||
14 | * Incoming requests are of form "6191, 23\r\n" - peer asks us | ||
15 | * "which user connected from your port 6191 to my port 23?" | ||
16 | * We should answer: | ||
17 | * "6193, 23 : USERID : UNIX : username\r\n" | ||
18 | * and close the connection. | ||
19 | * We can also reply: | ||
20 | * "6195, 23 : USERID : OTHER[,US-ASCII] : username\r\n" | ||
21 | * "6195, 23 : ERROR : INVALID-PORT/NO-USER/HIDDEN-USER/UNKNOWN-ERROR\r\n" | ||
22 | * but we probably will never want that. | ||
23 | */ | ||
24 | |||
12 | #include "busybox.h" | 25 | #include "busybox.h" |
26 | |||
27 | #define SANE_INETD_ONLY_VERSION | ||
28 | |||
29 | #ifdef SANE_INETD_ONLY_VERSION | ||
30 | |||
31 | int fakeidentd_main(int argc, char **argv) | ||
32 | { | ||
33 | char buf[64]; | ||
34 | const char *bogouser = "nobody"; | ||
35 | char *cur = buf; | ||
36 | int rem = sizeof(buf)-1; | ||
37 | |||
38 | if (argv[1]) | ||
39 | bogouser = argv[1]; | ||
40 | |||
41 | alarm(30); | ||
42 | while (1) { | ||
43 | char *p; | ||
44 | int sz = safe_read(0, cur, rem); | ||
45 | if (sz < 0) return 1; | ||
46 | cur[sz] = '\0'; | ||
47 | p = strpbrk(cur, "\r\n"); | ||
48 | if (p) { | ||
49 | *p = '\0'; | ||
50 | break; | ||
51 | } | ||
52 | cur += sz; | ||
53 | rem -= sz; | ||
54 | if (!rem || !sz) | ||
55 | break; | ||
56 | } | ||
57 | printf("%s : USERID : UNIX : %s\r\n", buf, bogouser); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | #else | ||
62 | |||
63 | /* Welcome to the bloaty horrors */ | ||
64 | |||
13 | #include <sys/syslog.h> | 65 | #include <sys/syslog.h> |
14 | #include <sys/uio.h> | 66 | #include <sys/uio.h> |
15 | 67 | ||
16 | |||
17 | #define IDENT_PORT 113 | ||
18 | #define MAXCONNS 20 | 68 | #define MAXCONNS 20 |
19 | #define MAXIDLETIME 45 | 69 | #define MAXIDLETIME 45 |
20 | 70 | ||
@@ -43,9 +93,9 @@ enum { ident_substr_len = sizeof(ident_substr) - 1 }; | |||
43 | * in `conns' array + FCS | 93 | * in `conns' array + FCS |
44 | */ | 94 | */ |
45 | static struct { | 95 | static struct { |
46 | char buf[20]; | ||
47 | int len; | ||
48 | time_t lasttime; | 96 | time_t lasttime; |
97 | int len; | ||
98 | char buf[20]; | ||
49 | } conns[MAXCONNS]; | 99 | } conns[MAXCONNS]; |
50 | 100 | ||
51 | /* When using global variables, bind those at least to a structure. */ | 101 | /* When using global variables, bind those at least to a structure. */ |
@@ -55,111 +105,92 @@ static struct { | |||
55 | int conncnt; | 105 | int conncnt; |
56 | } G; | 106 | } G; |
57 | 107 | ||
58 | /* | 108 | static char *bind_ip_address; |
59 | * Prototypes | ||
60 | */ | ||
61 | static void reply(int s, char *buf); | ||
62 | static void replyError(int s, char *buf); | ||
63 | 109 | ||
64 | static const char *nobodystr = "nobody"; /* this needs to be declared like this */ | 110 | static int chmatch(char c, char *chars) |
65 | static char *bind_ip_address = "0.0.0.0"; | 111 | { |
112 | for (; *chars; chars++) | ||
113 | if (c == *chars) | ||
114 | return 1; | ||
115 | return 0; | ||
116 | } | ||
66 | 117 | ||
67 | static void movefd(int from, int to) | 118 | static int skipchars(char **p, char *chars) |
68 | { | 119 | { |
69 | if (from != to) { | 120 | while (chmatch(**p, chars)) |
70 | dup2(from, to); | 121 | (*p)++; |
71 | close(from); | 122 | if (**p == '\r' || **p == '\n') |
72 | } | 123 | return 0; |
124 | return 1; | ||
73 | } | 125 | } |
74 | 126 | ||
75 | static void inetbind(void) | 127 | static int parseAddrs(char *ptr, char **myaddr, char **heraddr) |
76 | { | 128 | { |
77 | int s, port; | 129 | /* parse <port-on-server> , <port-on-client> */ |
78 | struct sockaddr_in addr; | ||
79 | int len = sizeof(addr); | ||
80 | struct servent *se; | ||
81 | 130 | ||
82 | se = getservbyname("identd", "tcp"); | 131 | if (!skipchars(&ptr, " \t")) |
83 | port = IDENT_PORT; | 132 | return -1; |
84 | if (se) | ||
85 | port = se->s_port; | ||
86 | 133 | ||
87 | s = xsocket(AF_INET, SOCK_STREAM, 0); | 134 | *myaddr = ptr; |
88 | 135 | ||
89 | setsockopt_reuseaddr(s); | 136 | if (!skipchars(&ptr, "1234567890")) |
137 | return -1; | ||
90 | 138 | ||
91 | memset(&addr, 0, sizeof(addr)); | 139 | if (!chmatch(*ptr, " \t,")) |
92 | addr.sin_addr.s_addr = inet_addr(bind_ip_address); | 140 | return -1; |
93 | addr.sin_family = AF_INET; | ||
94 | addr.sin_port = htons(port); | ||
95 | 141 | ||
96 | xbind(s, (struct sockaddr *)&addr, len); | 142 | *ptr++ = '\0'; |
97 | xlisten(s, 5); | ||
98 | 143 | ||
99 | movefd(s, 0); | 144 | if (!skipchars(&ptr, " \t,") ) |
100 | } | 145 | return -1; |
101 | 146 | ||
102 | static void handlexitsigs(int signum) | 147 | *heraddr = ptr; |
103 | { | ||
104 | if (unlink(PIDFILE) < 0) | ||
105 | close(open(PIDFILE, O_WRONLY|O_CREAT|O_TRUNC, 0644)); | ||
106 | exit(0); | ||
107 | } | ||
108 | 148 | ||
109 | /* May succeed. If not, won't care. */ | 149 | skipchars(&ptr, "1234567890"); |
110 | static void writepid(uid_t nobody, uid_t nogrp) | ||
111 | { | ||
112 | char buf[sizeof(int)*3 + 2]; | ||
113 | int fd = open(PIDFILE, O_WRONLY|O_CREAT|O_TRUNC, 0664); | ||
114 | 150 | ||
115 | if (fd < 0) | 151 | if (!chmatch(*ptr, " \n\r")) |
116 | return; | 152 | return -1; |
117 | 153 | ||
118 | sprintf(buf, "%d\n", getpid()); | 154 | *ptr = '\0'; |
119 | write(fd, buf, strlen(buf)); | ||
120 | fchown(fd, nobody, nogrp); | ||
121 | close(fd); | ||
122 | 155 | ||
123 | /* should this handle ILL, ... (see signal(7)) */ | 156 | return 0; |
124 | signal(SIGTERM, handlexitsigs); | ||
125 | signal(SIGINT, handlexitsigs); | ||
126 | signal(SIGQUIT, handlexitsigs); | ||
127 | } | 157 | } |
128 | 158 | ||
129 | /* return 0 as parent, 1 as child */ | 159 | static void replyError(int s, char *buf) |
130 | static int godaemon(void) | ||
131 | { | 160 | { |
132 | uid_t nobody, nogrp; | 161 | struct iovec iv[3]; |
133 | struct passwd *pw; | 162 | iv[0].iov_base = "0, 0 : ERROR : "; iv[0].iov_len = 15; |
134 | 163 | iv[1].iov_base = buf; iv[1].iov_len = strlen(buf); | |
135 | switch (fork()) { | 164 | iv[2].iov_base = "\r\n"; iv[2].iov_len = 2; |
136 | case -1: | 165 | writev(s, iv, 3); |
137 | bb_perror_msg_and_die("fork"); | 166 | } |
138 | |||
139 | case 0: | ||
140 | pw = getpwnam(nobodystr); | ||
141 | if (pw == NULL) | ||
142 | bb_error_msg_and_die("cannot find uid/gid of user '%s'", nobodystr); | ||
143 | nobody = pw->pw_uid; | ||
144 | nogrp = pw->pw_gid; | ||
145 | writepid(nobody, nogrp); | ||
146 | |||
147 | close(0); | ||
148 | inetbind(); | ||
149 | xsetgid(nogrp); | ||
150 | xsetuid(nobody); | ||
151 | close(1); | ||
152 | close(2); | ||
153 | 167 | ||
154 | signal(SIGHUP, SIG_IGN); | 168 | static void reply(int s, char *buf) |
155 | signal(SIGPIPE, SIG_IGN); /* connection closed when writing (raises ???) */ | 169 | { |
170 | char *myaddr, *heraddr; | ||
156 | 171 | ||
157 | setsid(); | 172 | myaddr = heraddr = NULL; |
158 | 173 | ||
159 | return 1; | 174 | if (parseAddrs(buf, &myaddr, &heraddr)) |
175 | replyError(s, "X-INVALID-REQUEST"); | ||
176 | else { | ||
177 | struct iovec iv[6]; | ||
178 | iv[0].iov_base = myaddr; iv[0].iov_len = strlen(myaddr); | ||
179 | iv[1].iov_base = ", "; iv[1].iov_len = 2; | ||
180 | iv[2].iov_base = heraddr; iv[2].iov_len = strlen(heraddr); | ||
181 | iv[3].iov_base = (void *)ident_substr; iv[3].iov_len = ident_substr_len; | ||
182 | iv[4].iov_base = (void *)G.identuser; iv[4].iov_len = strlen(G.identuser); | ||
183 | iv[5].iov_base = "\r\n"; iv[5].iov_len = 2; | ||
184 | writev(s, iv, 6); | ||
160 | } | 185 | } |
186 | } | ||
161 | 187 | ||
162 | return 0; | 188 | static void movefd(int from, int to) |
189 | { | ||
190 | if (from != to) { | ||
191 | dup2(from, to); | ||
192 | close(from); | ||
193 | } | ||
163 | } | 194 | } |
164 | 195 | ||
165 | static void deleteConn(int s) | 196 | static void deleteConn(int s) |
@@ -215,15 +246,32 @@ static int checkInput(char *buf, int len, int l) | |||
215 | return 0; | 246 | return 0; |
216 | } | 247 | } |
217 | 248 | ||
249 | /* May succeed. If not, won't care. */ | ||
250 | static const char *to_unlink; | ||
251 | static void writepid(void) | ||
252 | { | ||
253 | int fd = open(PIDFILE, O_WRONLY|O_CREAT|O_TRUNC, 0664); | ||
254 | if (fd < 0) | ||
255 | return; | ||
256 | to_unlink = PIDFILE; | ||
257 | fdprintf(fd, "%d\n", getpid()); | ||
258 | close(fd); | ||
259 | } | ||
260 | |||
261 | static void handlexitsigs(int signum) | ||
262 | { | ||
263 | if (to_unlink) | ||
264 | if (unlink(to_unlink) < 0) | ||
265 | close(open(to_unlink, O_WRONLY|O_CREAT|O_TRUNC, 0644)); | ||
266 | exit(0); | ||
267 | } | ||
268 | |||
218 | int fakeidentd_main(int argc, char **argv) | 269 | int fakeidentd_main(int argc, char **argv) |
219 | { | 270 | { |
220 | /* This applet is an inetd-style daemon */ | 271 | int fd; |
221 | openlog(applet_name, 0, LOG_DAEMON); | 272 | pid_t pid; |
222 | logmode = LOGMODE_SYSLOG; | ||
223 | 273 | ||
224 | memset(conns, 0, sizeof(conns)); | 274 | /* FD_ZERO(&G.readfds); - in bss, already zeroed */ |
225 | memset(&G, 0, sizeof(G)); | ||
226 | FD_ZERO(&G.readfds); | ||
227 | FD_SET(0, &G.readfds); | 275 | FD_SET(0, &G.readfds); |
228 | 276 | ||
229 | /* handle -b <ip> parameter */ | 277 | /* handle -b <ip> parameter */ |
@@ -232,11 +280,30 @@ int fakeidentd_main(int argc, char **argv) | |||
232 | if (optind < argc) | 280 | if (optind < argc) |
233 | G.identuser = argv[optind]; | 281 | G.identuser = argv[optind]; |
234 | else | 282 | else |
235 | G.identuser = nobodystr; | 283 | G.identuser = "nobody"; |
236 | 284 | ||
237 | /* daemonize and have the parent return */ | 285 | writepid(); |
238 | if (godaemon() == 0) | 286 | signal(SIGTERM, handlexitsigs); |
239 | return 0; | 287 | signal(SIGINT, handlexitsigs); |
288 | signal(SIGQUIT, handlexitsigs); | ||
289 | signal(SIGHUP, SIG_IGN); | ||
290 | signal(SIGPIPE, SIG_IGN); /* ignore closed connections when writing */ | ||
291 | |||
292 | fd = create_and_bind_stream_or_die(bind_ip_address, bb_lookup_port("identd", "tcp", 113)); | ||
293 | xlisten(fd, 5); | ||
294 | |||
295 | pid = fork(); | ||
296 | if (pid < 0) | ||
297 | bb_perror_msg_and_die("fork"); | ||
298 | if (pid != 0) /* parent */ | ||
299 | exit(0); | ||
300 | /* child */ | ||
301 | setsid(); | ||
302 | movefd(fd, 0); | ||
303 | while (fd) | ||
304 | close(fd--); | ||
305 | openlog(applet_name, 0, LOG_DAEMON); | ||
306 | logmode = LOGMODE_SYSLOG; | ||
240 | 307 | ||
241 | /* main loop where we process all events and never exit */ | 308 | /* main loop where we process all events and never exit */ |
242 | while (1) { | 309 | while (1) { |
@@ -252,10 +319,11 @@ int fakeidentd_main(int argc, char **argv) | |||
252 | 319 | ||
253 | if (FD_ISSET(s, &rfds)) { | 320 | if (FD_ISSET(s, &rfds)) { |
254 | char *buf = conns[i].buf; | 321 | char *buf = conns[i].buf; |
255 | unsigned int len = conns[i].len; | 322 | unsigned len = conns[i].len; |
256 | unsigned int l; | 323 | unsigned l; |
257 | 324 | ||
258 | if ((l = read(s, buf + len, sizeof(conns[0].buf) - len)) > 0) { | 325 | l = read(s, buf + len, sizeof(conns[0].buf) - len); |
326 | if (l > 0) { | ||
259 | if (checkInput(buf, len, l)) { | 327 | if (checkInput(buf, len, l)) { |
260 | reply(s, buf); | 328 | reply(s, buf); |
261 | goto deleteconn; | 329 | goto deleteconn; |
@@ -268,10 +336,8 @@ int fakeidentd_main(int argc, char **argv) | |||
268 | } else { | 336 | } else { |
269 | goto deleteconn; | 337 | goto deleteconn; |
270 | } | 338 | } |
271 | |||
272 | conns[i].lasttime = tim; | 339 | conns[i].lasttime = tim; |
273 | continue; | 340 | continue; |
274 | |||
275 | deleteconn: | 341 | deleteconn: |
276 | deleteConn(s); | 342 | deleteConn(s); |
277 | } else { | 343 | } else { |
@@ -287,7 +353,7 @@ deleteconn: | |||
287 | int s = accept(0, NULL, 0); | 353 | int s = accept(0, NULL, 0); |
288 | 354 | ||
289 | if (s < 0) { | 355 | if (s < 0) { |
290 | if (errno != EINTR) /* EINTR */ | 356 | if (errno != EINTR) |
291 | bb_perror_msg("accept"); | 357 | bb_perror_msg("accept"); |
292 | } else { | 358 | } else { |
293 | if (G.conncnt == MAXCONNS) | 359 | if (G.conncnt == MAXCONNS) |
@@ -297,7 +363,6 @@ deleteconn: | |||
297 | 363 | ||
298 | movefd(s, i + FCS); /* move if not already there */ | 364 | movefd(s, i + FCS); /* move if not already there */ |
299 | FD_SET(i + FCS, &G.readfds); | 365 | FD_SET(i + FCS, &G.readfds); |
300 | |||
301 | conns[i].len = 0; | 366 | conns[i].len = 0; |
302 | conns[i].lasttime = time(NULL); | 367 | conns[i].lasttime = time(NULL); |
303 | } | 368 | } |
@@ -307,81 +372,4 @@ deleteconn: | |||
307 | return 0; | 372 | return 0; |
308 | } | 373 | } |
309 | 374 | ||
310 | static int parseAddrs(char *ptr, char **myaddr, char **heraddr); | 375 | #endif /* !SANE_INETD_ONLY_VERSION */ |
311 | static void reply(int s, char *buf) | ||
312 | { | ||
313 | char *myaddr, *heraddr; | ||
314 | |||
315 | myaddr = heraddr = NULL; | ||
316 | |||
317 | if (parseAddrs(buf, &myaddr, &heraddr)) | ||
318 | replyError(s, "X-INVALID-REQUEST"); | ||
319 | else { | ||
320 | struct iovec iv[6]; | ||
321 | iv[0].iov_base = myaddr; iv[0].iov_len = strlen(myaddr); | ||
322 | iv[1].iov_base = ", "; iv[1].iov_len = 2; | ||
323 | iv[2].iov_base = heraddr; iv[2].iov_len = strlen(heraddr); | ||
324 | iv[3].iov_base = (void *)ident_substr; iv[3].iov_len = ident_substr_len; | ||
325 | iv[4].iov_base = (void *)G.identuser; iv[4].iov_len = strlen(G.identuser); | ||
326 | iv[5].iov_base = "\r\n"; iv[5].iov_len = 2; | ||
327 | writev(s, iv, 6); | ||
328 | } | ||
329 | } | ||
330 | |||
331 | static void replyError(int s, char *buf) | ||
332 | { | ||
333 | struct iovec iv[3]; | ||
334 | iv[0].iov_base = "0, 0 : ERROR : "; iv[0].iov_len = 15; | ||
335 | iv[1].iov_base = buf; iv[1].iov_len = strlen(buf); | ||
336 | iv[2].iov_base = "\r\n"; iv[2].iov_len = 2; | ||
337 | writev(s, iv, 3); | ||
338 | } | ||
339 | |||
340 | static int chmatch(char c, char *chars) | ||
341 | { | ||
342 | for (; *chars; chars++) | ||
343 | if (c == *chars) | ||
344 | return 1; | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int skipchars(char **p, char *chars) | ||
349 | { | ||
350 | while (chmatch(**p, chars)) | ||
351 | (*p)++; | ||
352 | if (**p == '\r' || **p == '\n') | ||
353 | return 0; | ||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | static int parseAddrs(char *ptr, char **myaddr, char **heraddr) | ||
358 | { | ||
359 | /* parse <port-on-server> , <port-on-client> */ | ||
360 | |||
361 | if (!skipchars(&ptr, " \t")) | ||
362 | return -1; | ||
363 | |||
364 | *myaddr = ptr; | ||
365 | |||
366 | if (!skipchars(&ptr, "1234567890")) | ||
367 | return -1; | ||
368 | |||
369 | if (!chmatch(*ptr, " \t,")) | ||
370 | return -1; | ||
371 | |||
372 | *ptr++ = '\0'; | ||
373 | |||
374 | if (!skipchars(&ptr, " \t,") ) | ||
375 | return -1; | ||
376 | |||
377 | *heraddr = ptr; | ||
378 | |||
379 | skipchars(&ptr, "1234567890"); | ||
380 | |||
381 | if (!chmatch(*ptr, " \n\r")) | ||
382 | return -1; | ||
383 | |||
384 | *ptr = '\0'; | ||
385 | |||
386 | return 0; | ||
387 | } | ||