⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inetd.c

📁 netkit-base-0.17.tar.gz linux嵌入式开发使用!
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1983, 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */char copyright[] =  "@(#) Copyright (c) 1983 Regents of the University of California.\n"  "All rights reserved.\n";/* * From: @(#)inetd.c	5.30 (Berkeley) 6/3/91 */char rcsid[] =   "$Id: inetd.c,v 1.38 2000/07/24 23:48:34 dholland Exp $";#include "../version.h"/* * Inetd - Internet super-server * * This program invokes all internet services as needed. * connection-oriented services are invoked each time a * connection is made, by creating a process.  This process * is passed the connection as file descriptor 0 and is * expected to do a getpeername to find out the source host * and port. * * Datagram oriented services are invoked when a datagram * arrives; a process is created and passed a pending message * on file descriptor 0.  Datagram servers may either connect * to their peer, freeing up the original socket for inetd * to receive further messages on, or ``take over the socket'', * processing all arriving datagrams and, eventually, timing * out.	 The first type of server is said to be ``multi-threaded''; * the second type of server ``single-threaded''.  * * Inetd uses a configuration file which is read at startup * and, possibly, at some later time in response to a hangup signal. * The configuration file is ``free format'' with fields given in the * order shown below.  Continuation lines for an entry must being with * a space or tab.  All fields must be present in each entry. * *	service name			must be in /etc/services *	socket type			stream/dgram/raw/rdm/seqpacket *	protocol			must be in /etc/protocols *	wait/nowait[.max]		single-threaded/multi-threaded, max # *	user[.group]			user/group to run daemon as *	server program			full path name *	server program arguments	maximum of MAXARGS (20) * * For RPC services *      service name/version            must be in /etc/rpc *	socket type			stream/dgram/raw/rdm/seqpacket *	protocol			must be in /etc/protocols *	wait/nowait[.max]		single-threaded/multi-threaded *	user[.group]			user to run daemon as *	server program			full path name *	server program arguments	maximum of MAXARGS (20) * * Comment lines are indicated by a `#' in column 1. *//* * Here's the scoop concerning the user.group feature: * * 1) No group listed. *  * 	a) for root:	NO setuid() or setgid() is done *  * 	b) nonroot:	setuid() * 			setgid(primary group as found in passwd) * 			initgroups(name, primary group) *  * 2) set-group-option on. *  * 	a) for root:	NO setuid() * 			setgid(specified group) * 			setgroups(1, specified group) *  * 	b) nonroot:	setuid() * 			setgid(specified group) * 			initgroups(name, specified group) *  * All supplementary groups are discarded at startup in case inetd was * run manually. */#include <sys/types.h>#include <sys/param.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/file.h>#include <sys/wait.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/un.h>#include <netinet/in.h>#include <arpa/inet.h>  /* for inet_ntoa */#include <errno.h>#include <netdb.h>#include <syslog.h>#include <pwd.h>#include <grp.h>#include <stdio.h>#include <string.h>#include <getopt.h>#include <stdlib.h>#include <unistd.h>#ifndef __linux__#ifndef RLIMIT_NOFILE#define RLIMIT_NOFILE	RLIMIT_OFILE#endif#endif#include "pathnames.h"#include "inetd.h"#include "servtab.h"#include "sig.h"#include "daemon.h"#include "setproctitle.h"#include "mysleep.h"#ifdef RPC   /* must come after inetd.h, which defines RPC *//* work around a compiler warning in rpc.h in libc5 */#define __wait __wait_foo#include <rpc/rpc.h>#include <rpc/pmap_clnt.h>#undef __wait#endif#include <rpc/pmap_clnt.h>#ifndef MIN#define MIN(a, b)	((a) < (b) ? (a) : (b))#endif#define DEFAULT_FILE_LIMIT	1024/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */#define FD_MARGIN	(8)static void logpid(void);static int bump_nofile(void);static void attempt_to_restart(void);struct servtab *servtab;                     /* service table */const char *configfile = _PATH_INETDCONF;    /* config file path */int debug = 0;                               /* debug flag *//* Length of socket listen queue. Should be per-service probably. */static int 	global_queuelen = 128;static volatile int	nsock;static int		maxsock;static fd_set		allsock;static int		options;static int		timingout;static long rlim_ofile_cur = DEFAULT_FILE_LIMIT;#ifdef RLIMIT_NOFILEstruct rlimit	rlim_ofile;#endif#ifdef sun/* * Sun's RPC library caches the result of `dtablesize()' * This is incompatible with our "bumping" of file descriptors "on demand" */int_rpc_dtablesize(){	return rlim_ofile_cur;}#endif/* * Remove things from environ[] that might have been inherited from the * parent process if we were started by root from a shell without "env -". * But, only remove the things that we can be reasonably sure are not  * intended to be inherited by inetd's children, because such things might * have been deliberately set in /etc/rc. * * In the long run we need to be able to explicitly specify environment in * inetd.conf. Then we can just clear the environment, which is much  * simpler. */staticvoiddiscard_stupid_environment(void){	static const char *const junk[] = {		/* these are prefixes */		"CVS",		"DISPLAY=",		"EDITOR=",		"GROUP=",		"HOME=",		"IFS=",		"LD_",		"LOGNAME=",		"MAIL=",		"PATH=",		"PRINTER=",		"PWD=",		"SHELL=",		"SHLVL=",		"SSH",		"TERM",		"TMP",		"USER=",		"VISUAL=",		NULL	};	int i,k=0;	for (i=0; __environ[i]; i++) {		int found=0, j;		for (j=0; junk[j]; j++) {			if (!strncmp(__environ[i], junk[j], strlen(junk[j]))) {				found=1;			}		}		if (!found) {			__environ[k++] = __environ[i];		}	}	__environ[k] = NULL;}/* * Exec a child, or run a builtin that's meant to be a subprocess. * (Not reached in the parent inetd process.) */staticvoidexec_child(struct servtab *sep){	struct passwd *pwd;	struct group *grp = NULL;	int tmpint;	uid_t uid;	gid_t gid;	/* 	 * If debugging, we're in someone else's session; make a new one.	 */	if (debug) {		setsid();	}	/*	 * Prepare to exec.	 */	pwd = getpwnam(sep->se_user);	if (pwd == NULL) {		syslog(LOG_ERR, "getpwnam: %s: No such user", sep->se_user);		return;	}	/*	 * Use the uid and gid of the user.	 */	uid = pwd->pw_uid;	gid = pwd->pw_gid;	/*	 * If a group was specified, use its gid instead of the user's gid.	 */	if (sep->se_group) {		grp = getgrnam(sep->se_group);		if (grp == NULL) {			syslog(LOG_ERR, "getgrnam: %s: No such group",			       sep->se_group);			return;		}		gid = grp->gr_gid;	}	/*	 * If a nonroot user, do initgroups to run with that user's group	 * list. 	 *	 * But if root, do not use root's group list - just use the one gid.	 *	 * If no group was specified, keep the group inetd was run under.	 * This is the traditional behavior, but seems dumb - shouldn't	 * we use the group from the password file? XXX.	 */	if (uid) {		if (setgid(gid)) {			syslog(LOG_AUTH|LOG_ERR, "setgid: %m");			return;		}		if (initgroups(pwd->pw_name, gid)) {			syslog(LOG_AUTH|LOG_ERR, "initgroups: %m");			return;		}		if (setuid(uid)) {			syslog(LOG_AUTH|LOG_ERR, "setuid: %m");			return;		}		/*		 * Just a bit of extra paranoia.		 */		seteuid(0);		if (getuid()==0 || geteuid()==0) {			syslog(LOG_AUTH|LOG_ERR, "Failed to drop root");			return;		}	} 	else if (grp) {		if (setgid(gid)) {			syslog(LOG_AUTH|LOG_ERR, "setgid: %m");			return;		}		if (setgroups(1, &gid)) {			syslog(LOG_AUTH|LOG_ERR, "setgroups: %m");			return;		}	}	if (debug) {		gid_t tmp[NGROUPS_MAX];		int n, i;		fprintf(stderr, "pid %d: exec %s\n", getpid(), sep->se_server);		fprintf(stderr, "uid: %d  gid: %d\n", getuid(), getgid());		fprintf(stderr, "groups: ");		n = getgroups(NGROUPS_MAX, tmp);		for (i=0; i<n; i++) fprintf(stderr, "%d ", tmp[i]);		fprintf(stderr, "\n");	}#ifdef MULOG	if (sep->se_log) {		dolog(sep, 0);	}#endif#ifdef RLIMIT_NOFILE	if (rlim_ofile.rlim_cur != rlim_ofile_cur) {		if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {			syslog(LOG_ERR,"setrlimit: %m");		}	}#endif	/* 	 * Transfer stdout to stderr. This is not with the other dup2's	 * so debug logging works.	 */	dup2(1, 2);	for (tmpint = rlim_ofile_cur-1; tmpint > 2; tmpint--) {		close(tmpint);	}		sig_preexec();	/*	 * If a builtin, now run it instead of execing.	 */	if (sep->se_bi) {		(*sep->se_bi->bi_fn)(0, sep);		exit(0);	}		execv(sep->se_server, sep->se_argv);	syslog(LOG_ERR, "execv %s: %m", sep->se_server);}staticpid_tfork_child(struct servtab *sep){	pid_t pid;	if (sep->se_count++ == 0) {		gettimeofday(&sep->se_time, NULL);	}	else if (sep->se_count >= sep->se_max) {		struct timeval now;		gettimeofday(&now, (struct timezone *)0);		if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {			sep->se_time = now;			sep->se_count = 1;		} 		else {			syslog(LOG_ERR, "%s server failing (looping or "			       "being flooded), service terminated for "			       "%d min\n",			       service_name(sep),			       RETRYTIME/60);			FD_CLR(sep->se_fd, &allsock);			close(sep->se_fd);			sep->se_fd = -1;			sep->se_count = 0;			nsock--;			if (!timingout) {				timingout = 1;				alarm(RETRYTIME);			}			return -1;		}	}	pid = fork();	if (pid<0) {		syslog(LOG_ERR, "fork: %m");	}	return pid;}staticvoidlaunch(struct servtab *sep){	char buf[50];	int ctrl, dofork;	if (debug) {		fprintf(stderr, "launching: %s\n", sep->se_service);	}	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {		/* Do nonblocking accept, just in case */		fcntl(sep->se_fd, F_SETFL, O_NDELAY);		ctrl = accept(sep->se_fd, NULL, NULL);		fcntl(sep->se_fd, F_SETFL, 0);		if (debug) {			fprintf(stderr, "accept: new socket %d\n", ctrl);		}		if (ctrl < 0) {			if (errno != EINTR && errno != EWOULDBLOCK) {				syslog(LOG_WARNING, "accept (for %s): %m",				       sep->se_service);			}			if (errno == EMFILE) {				syslog(LOG_ALERT, 				       "Out of files! Attempting restart...");				attempt_to_restart();			}			return;		}	} 	else {		ctrl = sep->se_fd;	}	dofork = (sep->se_bi == NULL || sep->se_bi->bi_fork);	if (dofork) {		pid_t pid = fork_child(sep);		if (pid < 0) {			if (ctrl != sep->se_fd)				close(ctrl);			mysleep(1);			return;		}		if (pid==0) {			/* child */			dup2(ctrl, 0);			close(ctrl);			dup2(0, 1);			/* don't do stderr yet */			exec_child(sep);			if (sep->se_socktype != SOCK_STREAM)				recv(0, buf, sizeof (buf), 0);			_exit(1);		}		if (sep->se_wait) {			sep->se_wait = pid;			FD_CLR(sep->se_fd, &allsock);			nsock--;		}		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)			close(ctrl);	}	else {		sep->se_bi->bi_fn(ctrl, sep);		if (ctrl != sep->se_fd)			close(ctrl);	}}staticvoidmainloop(void){	struct servtab *sep;	int n, i;	fd_set readable;	sig_block();	syslog(LOG_INFO, "Online and ready (%d sockets)", nsock);	for (;;) {		/*		 * If there are no live sockets, hold until we have some.		 * (Is this necessary? Wouldn't the select just wait until		 * it got signaled?)		 */		if (nsock == 0) {			while (nsock == 0) {				sig_wait();			}		}		readable = allsock;		sig_unblock();		n = select(maxsock + 1, &readable, NULL, NULL, NULL);		sig_block();		if (n <= 0) {			if (n < 0 && errno != EINTR) {				syslog(LOG_WARNING, "select: %m");				mysleep(1);			}			continue;		}		/*		 * Was:		 * for (sep = servtab; n && sep; sep = sep->se_next)		 *   if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {		 *      n--;                 *      launch(sep);		 */		for (i=3; i<=maxsock; i++) {			if (FD_ISSET(i, &readable)) {				sep = find_service_by_fd(i);				if (sep==NULL || sep->se_fd<0) {					/* ? */					syslog(LOG_ERR, 					       "selected closed socket!?");					continue;				}				launch(sep);			}		}	}}/* * Saved state so we can try to restart. */static int got_dflag=0, got_iflag=0, got_qflag=0, got_conf=0;staticvoidattempt_to_restart(void){	struct stat statbuf;	const char *argv[6];	const char **tmpargv1;	char **tmpargv2;	char qbuf[16];	int i=0;	snprintf(qbuf, sizeof(qbuf), "-q%d", global_queuelen);	argv[i++] = "inetd";	if (got_dflag) argv[i++] = "-d";	if (got_iflag) argv[i++] = "-i";	if (got_qflag) argv[i++] = qbuf;	if (got_conf) argv[i++] = configfile;	argv[i] = NULL;	if (stat(_PATH_INETD, &statbuf)!=0 || (statbuf.st_mode & 0111)==0) {		/*		 * Cannot restart - inetd is not there or not executable		 */		syslog(LOG_ALERT, "Cannot restart.");		syslog(LOG_ALERT, "Recommend manually restarting inetd ASAP.");				/*		 * Hopefully this will help the situation and not make too

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -