📄 inetd.c
字号:
* much a mess of the internal state. */ for (i=getdtablesize()-1; i>=64; i--) close(i); return; } /* * At this point we're committed to restarting. * Note that we have to close everything before execing the new * inetd, or it won't be able to listen on the ports we've got * bound. */ for (i=getdtablesize()-1; i>2; i--) { shutdown(i,2); close(i); } /* should we try argv[0] first? probably not */ tmpargv1 = argv; /* grr */ /*tmpargv2 = (char **)tmpargv1;*/ memcpy(&tmpargv2, &tmpargv1, sizeof(tmpargv1)); mysleep(10); execv(_PATH_INETD, tmpargv2); /* Should this be EMERG? */ closelog(); openlog("inetd", LOG_PID, LOG_DAEMON); syslog(LOG_ALERT, "Restart attempt failed."); syslog(LOG_ALERT, "Recommend manually restarting inetd ASAP."); /* this may help restore us to a semi-operable state */ { const char *tmp = configfile; configfile = "/dev/null"; config(0); configfile = tmp; config(0); }}intmain(int argc, char *argv[], char *envp[]){ int ch; int nodaemon=0; gid_t gid; char *progname; gid = getgid(); setgroups(1, &gid); /* * Note that Linux, unlike 4.4BSD, needs to clobber the * environment space for setproctitle. If the total size * of the argv and envp strings isn't enough, you won't * see anything. In fact, it may not even show "inetd", only * "ine" or "in". There's nothing that can be done about this, * except run inetd with the full pathname and some long * environment variables, or hack 4.4BSD-style setproctitle * support into Linux. * * Note that the setproctitle implementation copies the environment, * so child processes won't be sent trash. * * Also note that we only setproctitle() in child processes, so * our progname pointer and the like remain valid. */ initsetproctitle(argc, argv, envp); /* * This must come _after_ initsetproctitle. */ discard_stupid_environment(); progname = strrchr(argv[0], '/'); if (progname == NULL) { progname = argv[0]; } else { progname++; } while ((ch = getopt(argc, argv, "diq:")) != EOF) switch(ch) { case 'd': debug = nodaemon = 1; options |= SO_DEBUG; got_dflag = 1; break; case 'i': nodaemon = 1; got_iflag = 1; break; case 'q': global_queuelen = atoi(optarg); if (global_queuelen < 8) global_queuelen=8; got_qflag = 1; break; case '?': default: fprintf(stderr, "usage: %s [-di] [-q len] [conf]", progname); exit(1); } argc -= optind; argv += optind; if (argc > 0) { configfile = argv[0]; got_conf = 1; } if (nodaemon == 0) { daemon(0, 0); } else if (debug == 0) { /* * If nodaemon mode, but not debug mode, run in our own * session. Init might have done this for us if we're being * spawned from init... but it might not have. */ setsid(); } openlog(progname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); logpid();#ifdef RLIMIT_NOFILE rlim_ofile_cur = DEFAULT_FILE_LIMIT; if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) { syslog(LOG_ERR, "getrlimit: %m"); } else if (rlim_ofile.rlim_cur != RLIM_INFINITY) { rlim_ofile_cur = rlim_ofile.rlim_cur; }#endif config(0); sig_init(); mainloop(); /* Not reachable */ return 0;}voidreapchild(int signum){ int status; pid_t pid; register struct servtab *sep; const char *name; char tmp[64]; (void)signum; while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { if (debug) { fprintf(stderr, "pid %d, exit status %x\n", pid, status); } sep = find_service_by_pid(pid); if (sep==NULL) { snprintf(tmp, sizeof(tmp), "pid %d", (int)pid); name = tmp; } else { snprintf(tmp, sizeof(tmp), "%s (pid %d)", sep->se_server, (int)pid); name = tmp; } if (WIFEXITED(status) && WEXITSTATUS(status)) { syslog(LOG_WARNING, "%s: exit status %d", name, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { syslog(LOG_WARNING, "%s: exit signal %d", name, WTERMSIG(status)); } if (sep!=NULL) { sep->se_wait = 1; FD_SET(sep->se_fd, &allsock); nsock++; if (debug) { fprintf(stderr, "restored %s, fd %d\n", sep->se_service, sep->se_fd); } } }}voidretry(int signum){ (void)signum; timingout = 0; restart_services();}voidgoaway(int signum){ register struct servtab *sep; (void)signum; for (sep = servtab; sep; sep = sep->se_next) { if (sep->se_fd == -1) continue; switch (sep->se_family) { case AF_UNIX: (void)unlink(sep->se_service); break; case AF_INET: if (sep->se_wait == 1 && isrpcservice(sep)) unregister_rpc(sep); break; } (void)close(sep->se_fd); } (void)unlink(_PATH_INETDPID); exit(0);}voidcloseit(struct servtab *sep){ FD_CLR(sep->se_fd, &allsock); nsock--; (void) close(sep->se_fd); sep->se_fd = -1;}voidsetup(struct servtab *sep){ int on = 1; if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { syslog(LOG_ERR, "%s: socket: %m", service_name(sep), sep->se_service, sep->se_proto); if (errno == EMFILE) { syslog(LOG_ALERT, "Out of files! Attempting restart..."); attempt_to_restart(); } return; }#define turnon(fd, opt) \setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && turnon(sep->se_fd, SO_DEBUG) < 0) syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); if (turnon(sep->se_fd, SO_REUSEADDR) < 0) syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");#undef turnon if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) { syslog(LOG_ERR, "%s: bind: %m", service_name(sep), sep->se_service, sep->se_proto); (void) close(sep->se_fd); sep->se_fd = -1; if (!timingout) { timingout = 1; alarm(RETRYTIME); } return; } if (sep->se_socktype == SOCK_STREAM) listen(sep->se_fd, global_queuelen); if (sep->se_family == AF_UNIX) { /* * Ignore any error, on the grounds that chmod on a socket * might not be possible on some systems. * * XXX in the long run there should be a config option for * the mode. And owner/group, too. */ chmod(sep->se_ctrladdr_un.sun_path, 0666); } FD_SET(sep->se_fd, &allsock); nsock++; if (sep->se_fd > maxsock) { maxsock = sep->se_fd; if (maxsock > rlim_ofile_cur - FD_MARGIN) bump_nofile(); }}voidregister_rpc(struct servtab *sep){#ifdef RPC/* size_t m; */ socklen_t m; int i; struct sockaddr_in sn; struct protoent *pp; if ((pp = getprotobyname(sep->se_proto+4)) == NULL) { syslog(LOG_ERR, "%s: getproto: %m", sep->se_proto); return; } m = sizeof(sn); if (getsockname(sep->se_fd, (struct sockaddr *)&sn, &m) < 0) { syslog(LOG_ERR, "%s: getsockname: %m", service_name(sep), sep->se_service, sep->se_proto); return; } for (i = sep->se_rpcversl; i <= sep->se_rpcversh; i++) { if (debug) fprintf(stderr, "pmap_set: %u %u %u %u\n", sep->se_rpcprog, i, pp->p_proto, ntohs(sn.sin_port)); (void)pmap_unset(sep->se_rpcprog, i); if (!pmap_set(sep->se_rpcprog, i, pp->p_proto, ntohs(sn.sin_port))) syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m", sep->se_rpcprog, i, pp->p_proto, ntohs(sn.sin_port)); }#endif /* RPC */}voidunregister_rpc(struct servtab *sep){#ifdef RPC int n; for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { if (debug) fprintf(stderr, "pmap_unset(%u, %u)\n", sep->se_rpcprog, n); if (!pmap_unset(sep->se_rpcprog, n)) syslog(LOG_ERR, "pmap_unset(%u, %u)\n", sep->se_rpcprog, n); }#endif /* RPC */}struct servtab *enter(struct servtab *cp){ register struct servtab *sep; sep = domalloc(sizeof(*sep)); *sep = *cp; sep->se_fd = -1; sep->se_rpcprog = -1; sep->se_next = servtab; servtab = sep; return (sep);}//static char *skip(char **);//static char *nextline(FILE *);static voidlogpid(void){ FILE *fp; if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) { fprintf(fp, "%u\n", getpid()); (void)fclose(fp); }}static intbump_nofile(void){#ifdef RLIMIT_NOFILE#define FD_CHUNK 32 struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) < 0) { syslog(LOG_ERR, "getrlimit: %m"); return -1; } rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK); if (rl.rlim_cur <= rlim_ofile_cur) { syslog(LOG_ERR, "bump_nofile: cannot extend file limit, max = %d", rl.rlim_cur); return -1; } if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { syslog(LOG_ERR, "setrlimit: %m"); return -1; } rlim_ofile_cur = rl.rlim_cur; return 0;#else syslog(LOG_ERR, "bump_nofile: cannot extend file limit"); return -1;#endif}#ifdef MULOGdolog(sep, ctrl) struct servtab *sep; int ctrl;{ struct sockaddr sa; struct sockaddr_in *sin = (struct sockaddr_in *)&sa; int len = sizeof(sa); struct hostent *hp; char *host, *dp, buf[BUFSIZ], *rfc931_name(); int connected = 1; if (sep->se_family != AF_INET) return; if (getpeername(ctrl, &sa, &len) < 0) { if (errno != ENOTCONN) { syslog(LOG_ERR, "getpeername: %m"); return; } if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) { syslog(LOG_ERR, "recvfrom: %m"); return; } connected = 0; } if (sa.sa_family != AF_INET) { syslog(LOG_ERR, "unexpected address family %u", sa.sa_family); return; } hp = gethostbyaddr((char *) &sin->sin_addr.s_addr, sizeof (sin->sin_addr.s_addr), AF_INET); host = hp?hp->h_name:inet_ntoa(sin->sin_addr); switch (sep->se_log & ~MULOG_RFC931) { case 0: return; case 1: if (curdom == NULL || *curdom == '\0') break; dp = host + strlen(host) - strlen(curdom); if (dp < host) break; if (debug) fprintf(stderr, "check \"%s\" against curdom \"%s\"\n", host, curdom); if (strcasecmp(dp, curdom) == 0) return; break; case 2: default: break; } openlog("", LOG_NOWAIT, MULOG); if (connected && (sep->se_log & MULOG_RFC931)) syslog(LOG_INFO, "%s@%s wants %s", rfc931_name(sin, ctrl), host, sep->se_service); else syslog(LOG_INFO, "%s wants %s", host, sep->se_service);}/* * From tcp_log by * Wietse Venema, Eindhoven University of Technology, The Netherlands. */#if 0static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";#endif#include <setjmp.h>#define RFC931_PORT 113 /* Semi-well-known port */#define TIMEOUT 4#define TIMEOUT2 10static sigjmp_buf timebuf;/* timeout - handle timeouts */static void timeout(sig)int sig;{ siglongjmp(timebuf, sig);}/* rfc931_name - return remote user name */char *rfc931_name(struct sockaddr_in *there, int ctrl){ /* "there" is remote link information */ struct sockaddr_in here; /* local link information */ struct sockaddr_in sin; /* for talking to RFC931 daemon */ int length; int s; unsigned remote; unsigned local; static char user[256]; /* XXX */ char buf[256]; char *cp; char *result = "USER_UNKNOWN"; int len; /* Find out local port number of our stdin. */ length = sizeof(here); if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) { syslog(LOG_ERR, "getsockname: %m"); return (result); } /* Set up timer so we won't get stuck. */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { syslog(LOG_ERR, "socket: %m"); return (result); } sin = here; sin.sin_port = htons(0); if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) { syslog(LOG_ERR, "bind: %m"); close(s); return (result); } signal(SIGALRM, timeout); if (sigsetjmp(timebuf)) { close(s); /* not: fclose(fp) */ return (result); } alarm(TIMEOUT); /* Connect to the RFC931 daemon. */ sin = *there; sin.sin_port = htons(RFC931_PORT); if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) { close(s); alarm(0); return (result); } /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */ snprintf(buf, sizeof(buf), "%u,%u\r\n", ntohs(there->sin_port), ntohs(here.sin_port)); for (len = 0, cp = buf; len < strlen(buf); ) { int n; if ((n = write(s, cp, strlen(buf) - len)) == -1) { close(s); alarm(0); return (result); } cp += n; len += n; } /* Read response */ for (cp = buf; cp < buf + sizeof(buf) - 1; ) { char c; if (read(s, &c, 1) != 1) { close(s); alarm(0); return (result); } if (c == '\n') break; *cp++ = c; } *cp = '\0'; if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3 && ntohs(there->sin_port) == remote && ntohs(here.sin_port) == local) { /* Strip trailing carriage return. */ if (cp = strchr(user, '\r')) *cp = 0; result = user; } alarm(0); close(s); return (result);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -