diff options
Diffstat (limited to 'networking')
-rw-r--r-- | networking/inetd.c | 296 |
1 files changed, 151 insertions, 145 deletions
diff --git a/networking/inetd.c b/networking/inetd.c index d6265d875..8c8843b9b 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -183,8 +183,7 @@ static struct rlimit rlim_ofile; # define INETD_SETPROCTITLE #endif -typedef struct servtab -{ +typedef struct servtab { char *se_hostaddr; /* host address to listen on */ char *se_service; /* name of service */ int se_socktype; /* type of socket to use */ @@ -209,8 +208,7 @@ typedef struct servtab #define MAXARGV 20 char *se_argv[MAXARGV + 1]; /* program arguments */ int se_fd; /* open descriptor */ - union - { + union { struct sockaddr se_un_ctrladdr; struct sockaddr_in se_un_ctrladdr_in; #ifdef CONFIG_FEATURE_IPV6 @@ -232,8 +230,7 @@ typedef struct servtab static servtab_t *servtab; #ifdef INETD_FEATURE_ENABLED -struct builtin -{ +struct builtin { const char *bi_service; /* internally provided service name */ int bi_socktype; /* type of socket supported */ short bi_fork; /* 1 if should fork before call */ @@ -427,7 +424,8 @@ static void setup(servtab_t *sep) int on = 1; int r; - if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { + sep->se_fd = socket(sep->se_family, sep->se_socktype, 0); + if (sep->se_fd < 0) { bb_perror_msg("%s/%s: socket", sep->se_service, sep->se_proto); return; } @@ -1355,7 +1353,7 @@ inetd_main(int argc, char *argv[]) } readable = allsock; - n = select(maxsock + 1, &readable, NULL, NULL, NULL) + n = select(maxsock + 1, &readable, NULL, NULL, NULL); if (n <= 0) { if (n < 0 && errno != EINTR) { bb_perror_msg("select"); @@ -1363,154 +1361,154 @@ inetd_main(int argc, char *argv[]) } continue; } + for (sep = servtab; n && sep; sep = sep->se_next) { - // TODO: undo this unholy mess - if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { - n--; - if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { - ctrl = accept(sep->se_fd, NULL, NULL); - if (ctrl < 0) { - if (errno == EINTR) - continue; - bb_perror_msg("accept (for %s)", sep->se_service); + if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) + continue; + + n--; + if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { + ctrl = accept(sep->se_fd, NULL, NULL); + if (ctrl < 0) { + if (errno == EINTR) + continue; + bb_perror_msg("accept (for %s)", sep->se_service); + continue; + } + if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) { + struct sockaddr_in peer; + socklen_t plen = sizeof(peer); + + if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) { + bb_error_msg("could not getpeername"); + close(ctrl); continue; } - if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) { - struct sockaddr_in peer; - socklen_t plen = sizeof(peer); + if (ntohs(peer.sin_port) == 20) { + /* XXX ftp bounce */ + close(ctrl); + continue; + } + } + } else + ctrl = sep->se_fd; - if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) { - bb_error_msg("could not getpeername"); + Block_Using_Signals(omask); + pid = 0; +#ifdef INETD_FEATURE_ENABLED + if (sep->se_bi == 0 || sep->se_bi->bi_fork) +#endif + { + if (sep->se_count++ == 0) + (void) gettimeofday(&sep->se_time, NULL); + else if (toomany > 0 && sep->se_count >= sep->se_max) { + struct timeval now; + + (void) gettimeofday(&now, NULL); + if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) { + sep->se_time = now; + sep->se_count = 1; + } else { + if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) close(ctrl); + if (sep->se_family == AF_INET && + ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) { + /* + * Cannot close it -- there are + * thieves on the system. + * Simply ignore the connection. + */ + --sep->se_count; continue; } - if (ntohs(peer.sin_port) == 20) { - /* XXX ftp bounce */ + bb_error_msg("%s/%s server failing (looping), service terminated", + sep->se_service, sep->se_proto); + if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) close(ctrl); - continue; - } - } - } else - ctrl = sep->se_fd; - Block_Using_Signals(omask); - pid = 0; -#ifdef INETD_FEATURE_ENABLED - if (sep->se_bi == 0 || sep->se_bi->bi_fork) -#endif - { - if (sep->se_count++ == 0) - (void) gettimeofday(&sep->se_time, NULL); - else if (toomany > 0 && sep->se_count >= sep->se_max) { - struct timeval now; - - (void) gettimeofday(&now, NULL); - if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) { - sep->se_time = now; - sep->se_count = 1; - } else { - if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) - close(ctrl); - if (sep->se_family == AF_INET && - ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) { - /* - * Cannot close it -- there are - * thieves on the system. - * Simply ignore the connection. - */ - --sep->se_count; - continue; - } - bb_error_msg("%s/%s server failing (looping), service terminated", - sep->se_service, sep->se_proto); - if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) - close(ctrl); - FD_CLR(sep->se_fd, &allsock); - (void) close(sep->se_fd); - sep->se_fd = -1; - sep->se_count = 0; - nsock--; - sigprocmask(SIG_UNBLOCK, &omask, NULL); - if (!timingout) { - timingout = 1; - alarm(RETRYTIME); - } - continue; + FD_CLR(sep->se_fd, &allsock); + (void) close(sep->se_fd); + sep->se_fd = -1; + sep->se_count = 0; + nsock--; + sigprocmask(SIG_UNBLOCK, &omask, NULL); + if (!timingout) { + timingout = 1; + alarm(RETRYTIME); } + continue; } - pid = fork(); - } - if (pid < 0) { - bb_perror_msg("fork"); - if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) - close(ctrl); - sigprocmask(SIG_UNBLOCK, &omask, NULL); - sleep(1); - continue; - } - if (pid && sep->se_wait) { - sep->se_wait = pid; - FD_CLR(sep->se_fd, &allsock); - nsock--; } + pid = fork(); + } + if (pid < 0) { + bb_perror_msg("fork"); + if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) + close(ctrl); sigprocmask(SIG_UNBLOCK, &omask, NULL); - if (pid == 0) { + sleep(1); + continue; + } + if (pid && sep->se_wait) { + sep->se_wait = pid; + FD_CLR(sep->se_fd, &allsock); + nsock--; + } + sigprocmask(SIG_UNBLOCK, &omask, NULL); + if (pid == 0) { #ifdef INETD_FEATURE_ENABLED - if (sep->se_bi) { - (*sep->se_bi->bi_fn)(ctrl, sep); - } else + if (sep->se_bi) { + (*sep->se_bi->bi_fn)(ctrl, sep); + } else #endif - { - if ((pwd = getpwnam(sep->se_user)) == NULL) { - bb_error_msg("getpwnam: %s: no such user", sep->se_user); - if (sep->se_socktype != SOCK_STREAM) - recv(0, buf, sizeof(buf), 0); - _exit(1); - } - if (setsid() < 0) - bb_perror_msg("%s: setsid", sep->se_service); - if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) { - bb_error_msg("getgrnam: %s: no such group", sep->se_group); - if (sep->se_socktype != SOCK_STREAM) - recv(0, buf, sizeof(buf), 0); + { + pwd = getpwnam(sep->se_user); + if (pwd == NULL) { + bb_error_msg("getpwnam: %s: no such user", sep->se_user); + goto do_exit1; + } + if (setsid() < 0) + bb_perror_msg("%s: setsid", sep->se_service); + if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) { + bb_error_msg("getgrnam: %s: no such group", sep->se_group); + goto do_exit1; + } + if (uid != 0) { + /* a user running private inetd */ + if (uid != pwd->pw_uid) _exit(1); - } - if (uid != 0) { - /* a user running private inetd */ - if (uid != pwd->pw_uid) - _exit(1); - } else if (pwd->pw_uid) { - if (sep->se_group) - pwd->pw_gid = grp->gr_gid; - xsetgid((gid_t) pwd->pw_gid); - initgroups(pwd->pw_name, pwd->pw_gid); - xsetuid((uid_t) pwd->pw_uid); - } else if (sep->se_group) { - xsetgid(grp->gr_gid); - setgroups(1, &grp->gr_gid); - } - dup2(ctrl, 0); - close(ctrl); - dup2(0, 1); - dup2(0, 2); - if (rlim_ofile.rlim_cur != rlim_ofile_cur) - if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) - bb_perror_msg("setrlimit"); - closelog(); - for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;) - (void) close(tmpint); - sigaction(SIGPIPE, &sapipe, NULL); - execv(sep->se_server, sep->se_argv); - if (sep->se_socktype != SOCK_STREAM) - recv(0, buf, sizeof(buf), 0); - bb_perror_msg("execv %s", sep->se_server); - _exit(1); + } else if (pwd->pw_uid) { + if (sep->se_group) + pwd->pw_gid = grp->gr_gid; + xsetgid((gid_t) pwd->pw_gid); + initgroups(pwd->pw_name, pwd->pw_gid); + xsetuid((uid_t) pwd->pw_uid); + } else if (sep->se_group) { + xsetgid(grp->gr_gid); + setgroups(1, &grp->gr_gid); } + dup2(ctrl, 0); + if (ctrl) close(ctrl); + dup2(0, 1); + dup2(0, 2); + if (rlim_ofile.rlim_cur != rlim_ofile_cur) + if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) + bb_perror_msg("setrlimit"); + closelog(); + for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;) + (void) close(tmpint); + sigaction(SIGPIPE, &sapipe, NULL); + execv(sep->se_server, sep->se_argv); + bb_perror_msg("execv %s", sep->se_server); +do_exit1: + if (sep->se_socktype != SOCK_STREAM) + recv(0, buf, sizeof(buf), 0); + _exit(1); } - if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) - close(ctrl); } - } - } + if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) + close(ctrl); + } /* for (sep = servtab...) */ + } /* for(;;) */ } /* @@ -1542,8 +1540,12 @@ echo_stream(int s, servtab_t *sep) int i; inetd_setproctitle(sep->se_service, s); - while ((i = read(s, buffer, sizeof(buffer))) > 0 && - write(s, buffer, i) > 0); + while (1) { + i = read(s, buffer, sizeof(buffer)); + if (i <= 0) break; + /* FIXME: this isnt correct - safe_write()? */ + if (write(s, buffer, i) <= 0) break; + } exit(0); } @@ -1577,9 +1579,11 @@ discard_stream(int s, servtab_t *sep) char buffer[BUFSIZE]; inetd_setproctitle(sep->se_service, s); - while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) || - errno == EINTR); - exit(0); + while (1) { + errno = 0; + if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR) + exit(0); + } } /* Discard service -- ignore data */ @@ -1629,8 +1633,10 @@ chargen_stream(int s, servtab_t *sep) text[LINESIZ] = '\r'; text[LINESIZ + 1] = '\n'; - for (rs = ring;;) { - if ((len = endring - rs) >= LINESIZ) + rs = ring; + for (;;) { + len = endring - rs; + if (len >= LINESIZ) memmove(text, rs, LINESIZ); else { memmove(text, rs, len); |