1 /* vi: set sw=4 ts=4: */
5 * Copyright (C) 2007 Denys Vlasenko
7 * Licensed under GPLv2, see file LICENSE in this source tree.
10 //usage:#define fakeidentd_trivial_usage
11 //usage: "[-fiw] [-b ADDR] [STRING]"
12 //usage:#define fakeidentd_full_usage "\n\n"
13 //usage: "Provide fake ident (auth) service\n"
14 //usage: "\n -f Run in foreground"
15 //usage: "\n -i Inetd mode"
16 //usage: "\n -w Inetd 'wait' mode"
17 //usage: "\n -b ADDR Bind to specified address"
18 //usage: "\n STRING Ident answer string (default: nobody)"
24 enum { TIMEOUT
= 20 };
26 typedef struct identd_buf_t
{
29 char buf
[64 - 2*sizeof(int)];
32 #define bogouser bb_common_bufsiz1
34 static int new_peer(isrv_state_t
*state
, int fd
)
37 identd_buf_t
*buf
= xzalloc(sizeof(*buf
));
39 peer
= isrv_register_peer(state
, buf
);
41 return 0; /* failure */
42 if (isrv_register_fd(state
, peer
, fd
) < 0)
43 return peer
; /* failure, unregister peer */
45 buf
->fd_flag
= fcntl(fd
, F_GETFL
) | O_NONBLOCK
;
46 isrv_want_rd(state
, fd
);
50 static int do_rd(int fd
, void **paramp
)
52 identd_buf_t
*buf
= *paramp
;
54 int retval
= 0; /* session is ok (so far) */
57 cur
= buf
->buf
+ buf
->pos
;
59 if (buf
->fd_flag
& O_NONBLOCK
)
60 fcntl(fd
, F_SETFL
, buf
->fd_flag
);
61 sz
= safe_read(fd
, cur
, sizeof(buf
->buf
) - buf
->pos
);
65 goto term
; /* terminate this session if !EAGAIN */
70 buf
->buf
[buf
->pos
] = '\0';
71 p
= strpbrk(cur
, "\r\n");
74 if (!p
&& sz
&& buf
->pos
<= (int)sizeof(buf
->buf
))
76 /* Terminate session. If we are in server mode, then
77 * fd is still in nonblocking mode - we never block here */
78 if (fd
== 0) fd
++; /* inetd mode? then write to fd 1 */
79 fdprintf(fd
, "%s : USERID : UNIX : %s\r\n", buf
->buf
, bogouser
);
82 retval
= 1; /* terminate */
84 if (buf
->fd_flag
& O_NONBLOCK
)
85 fcntl(fd
, F_SETFL
, buf
->fd_flag
& ~O_NONBLOCK
);
89 static int do_timeout(void **paramp UNUSED_PARAM
)
91 return 1; /* terminate session */
94 static void inetd_mode(void)
96 identd_buf_t
*buf
= xzalloc(sizeof(*buf
));
97 /* buf->pos = 0; - xzalloc did it */
98 /* We do NOT want nonblocking I/O here! */
99 /* buf->fd_flag = 0; - xzalloc did it */
102 while (do_rd(0, (void*)&buf
) == 0);
105 int fakeidentd_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
106 int fakeidentd_main(int argc UNUSED_PARAM
, char **argv
)
109 OPT_foreground
= 0x1,
116 const char *bind_address
= NULL
;
120 opt
= getopt32(argv
, "fiwb:", &bind_address
);
121 strcpy(bogouser
, "nobody");
123 strncpy(bogouser
, argv
[optind
], sizeof(bogouser
));
125 /* Daemonize if no -f and no -i and no -w */
126 if (!(opt
& OPT_fiw
))
127 bb_daemonize_or_rexec(0, argv
);
129 /* Where to log in inetd modes? "Classic" inetd
130 * probably has its stderr /dev/null'ed (we need log to syslog?),
131 * but daemontools-like utilities usually expect that children
132 * log to stderr. I like daemontools more. Go their way.
133 * (Or maybe we need yet another option "log to syslog") */
134 if (!(opt
& OPT_fiw
) /* || (opt & OPT_syslog) */) {
135 openlog(applet_name
, LOG_PID
, LOG_DAEMON
);
136 logmode
= LOGMODE_SYSLOG
;
139 if (opt
& OPT_inetd
) {
144 /* Ignore closed connections when writing */
145 signal(SIGPIPE
, SIG_IGN
);
148 if (!(opt
& OPT_inetdwait
)) {
149 fd
= create_and_bind_stream_or_die(bind_address
,
150 bb_lookup_port("identd", "tcp", 113));
154 isrv_run(fd
, new_peer
, do_rd
, /*do_wr:*/ NULL
, do_timeout
,
155 TIMEOUT
, (opt
& OPT_inetdwait
) ? TIMEOUT
: 0);