aboutsummaryrefslogtreecommitdiff
path: root/networking/isrv_identd.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-01-14 01:29:06 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-01-14 01:29:06 +0000
commit7a431b3715299854fb423ec00d5fafc0e2c7f07b (patch)
tree4e90c9d364485ef13c2e429ab22b9b925d50ea04 /networking/isrv_identd.c
parent150f402b36197d822f8a7dd835231cd67b77e959 (diff)
downloadbusybox-w32-7a431b3715299854fb423ec00d5fafc0e2c7f07b.tar.gz
busybox-w32-7a431b3715299854fb423ec00d5fafc0e2c7f07b.tar.bz2
busybox-w32-7a431b3715299854fb423ec00d5fafc0e2c7f07b.zip
By popular request reinstate fakeidentd's standalone mode.
Since this is also needed for other applets like telnetd, introduce generic driver for such things. It even supports inetd-wait ('linger') mode, when inetd hands out listen socket to child and waits to it to die, instead of handing out accepted socket and continuing listening itself (nowait mode). Code growth ~200 bytes. NB: our inetd doesn't support wait mode yet (or mabe it is buggy).
Diffstat (limited to 'networking/isrv_identd.c')
-rw-r--r--networking/isrv_identd.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/networking/isrv_identd.c b/networking/isrv_identd.c
new file mode 100644
index 000000000..b9481f8d3
--- /dev/null
+++ b/networking/isrv_identd.c
@@ -0,0 +1,144 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Fake identd server.
4 *
5 * Copyright (C) 2007 Denis Vlasenko
6 *
7 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
8 */
9
10#include <syslog.h>
11#include "busybox.h"
12#include "isrv.h"
13
14enum { TIMEOUT = 20 };
15
16/* Why use alarm(TIMEOUT-1)?
17 * isrv's internal select() will run with timeout=TIMEOUT.
18 * If nothing happens during TIMEOUT-1 seconds (no accept/read),
19 * then ALL sessions timed out by now. Instead of closing them one-by-one
20 * (isrv calls do_timeout for each 'stale' session),
21 * SIGALRM triggered by alarm(TIMEOUT-1) will kill us, terminating them all.
22 */
23
24typedef struct identd_buf_t {
25 int pos;
26 int fd_flag;
27 char buf[64 - 2*sizeof(int)];
28} identd_buf_t;
29
30static const char *bogouser = "nobody";
31
32static int new_peer(isrv_state_t *state, int fd)
33{
34 int peer;
35 identd_buf_t *buf = xzalloc(sizeof(*buf));
36
37 alarm(TIMEOUT - 1);
38
39 peer = isrv_register_peer(state, buf);
40 if (peer < 0)
41 return 0; /* failure */
42 if (isrv_register_fd(state, peer, fd) < 0)
43 return peer; /* failure, unregister peer */
44
45 buf->fd_flag = fcntl(fd, F_GETFL, 0) | O_NONBLOCK;
46 isrv_want_rd(state, fd);
47 return 0;
48}
49
50static int do_rd(int fd, void **paramp)
51{
52 identd_buf_t *buf = *paramp;
53 char *cur, *p;
54 int sz;
55
56 alarm(TIMEOUT - 1);
57
58 cur = buf->buf + buf->pos;
59
60 fcntl(fd, F_SETFL, buf->fd_flag | O_NONBLOCK);
61 sz = safe_read(fd, cur, sizeof(buf->buf) - buf->pos);
62
63 if (sz < 0) {
64 if (errno != EAGAIN)
65 goto term; /* terminate this session if !EAGAIN */
66 goto ok;
67 }
68
69 buf->pos += sz;
70 buf->buf[buf->pos] = '\0';
71 p = strpbrk(cur, "\r\n");
72 if (p)
73 *p = '\0';
74 if (p || !sz || buf->pos == sizeof(buf->buf)) {
75 /* fd is still in nonblocking mode - we never block here */
76 fdprintf(fd, "%s : USERID : UNIX : %s\r\n", buf->buf, bogouser);
77 goto term;
78 }
79 ok:
80 fcntl(fd, F_SETFL, buf->fd_flag & ~O_NONBLOCK);
81 return 0;
82 term:
83 fcntl(fd, F_SETFL, buf->fd_flag & ~O_NONBLOCK);
84 free(buf);
85 return 1;
86}
87
88static int do_timeout(void **paramp)
89{
90 return 1; /* terminate session */
91}
92
93static void inetd_mode(void)
94{
95 identd_buf_t *buf = xzalloc(sizeof(*buf));
96 /* We do NOT want nonblocking I/O here! */
97 buf->fd_flag = fcntl(0, F_GETFL, 0);
98 while (do_rd(0, (void*)&buf) == 0) /* repeat */;
99}
100
101int fakeidentd_main(int argc, char **argv)
102{
103 enum {
104 OPT_foreground = 0x1,
105 OPT_inetd = 0x2,
106 OPT_inetdwait = 0x4,
107 OPT_nodeamon = 0x7,
108 OPT_bindaddr = 0x8,
109 };
110
111 const char *bind_address = NULL;
112 unsigned opt;
113 int fd;
114
115 opt = getopt32(argc, argv, "fiwb:", &bind_address);
116 if (optind < argc)
117 bogouser = argv[optind];
118
119 /* Daemonize if no -f or -i or -w */
120 bb_sanitize_stdio(!(opt & OPT_nodeamon));
121 if (!(opt & OPT_nodeamon)) {
122 openlog(applet_name, 0, LOG_DAEMON);
123 logmode = LOGMODE_SYSLOG;
124 }
125
126 if (opt & OPT_inetd) {
127 inetd_mode();
128 return 0;
129 }
130
131 /* Ignore closed connections when writing */
132 signal(SIGPIPE, SIG_IGN);
133
134 if (opt & OPT_inetdwait) {
135 fd = 0;
136 } else {
137 fd = create_and_bind_stream_or_die(bind_address,
138 bb_lookup_port("identd", "tcp", 113));
139 xlisten(fd, 5);
140 }
141
142 isrv_run(fd, new_peer, do_rd, NULL, do_timeout, TIMEOUT, 1);
143 return 0;
144}