示例#1
0
pid_t
proc_run(struct privsep *ps, struct privsep_proc *p,
    struct privsep_proc *procs, u_int nproc,
    void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg)
{
	pid_t			 pid;
	struct passwd		*pw;
	const char		*root;
	struct control_sock	*rcs;
	u_int			 n;

	if (ps->ps_noaction)
		return (0);

	proc_open(ps, p, procs, nproc);

	/* Fork child handlers */
	switch (pid = fork()) {
	case -1:
		fatal("proc_run: cannot fork");
	case 0:
		/* Set the process group of the current process */
		setpgrp(0, getpid());
		break;
	default:
		return (pid);
	}

	pw = ps->ps_pw;

	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
		if (control_init(ps, &ps->ps_csock) == -1)
			fatalx(p->p_title);
		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
			if (control_init(ps, rcs) == -1)
				fatalx(p->p_title);
	}

	/* Change root directory */
	if (p->p_chroot != NULL)
		root = p->p_chroot;
	else
		root = pw->pw_dir;

	if (chroot(root) == -1)
		fatal("proc_run: chroot");
	if (chdir("/") == -1)
		fatal("proc_run: chdir(\"/\")");

	privsep_process = p->p_id;

	setproctitle("%s", p->p_title);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("proc_run: cannot drop privileges");

	/* Fork child handlers */
	for (n = 1; n < ps->ps_instances[p->p_id]; n++) {
		if (fork() == 0) {
			ps->ps_instance = p->p_instance = n;
			break;
		}
	}

#ifdef DEBUG
	log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title,
	    ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid());
#endif

	event_init();

	signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p);
	signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p);
	signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p);
	signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p);
	signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p);
	signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p);

	signal_add(&ps->ps_evsigint, NULL);
	signal_add(&ps->ps_evsigterm, NULL);
	signal_add(&ps->ps_evsigchld, NULL);
	signal_add(&ps->ps_evsighup, NULL);
	signal_add(&ps->ps_evsigpipe, NULL);
	signal_add(&ps->ps_evsigusr1, NULL);

	proc_listen(ps, procs, nproc);

	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
		TAILQ_INIT(&ctl_conns);
		if (control_listen(&ps->ps_csock) == -1)
			fatalx(p->p_title);
		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
			if (control_listen(rcs) == -1)
				fatalx(p->p_title);
	}
示例#2
0
int
main(int argc, char *argv[])
{
	struct sockaddr_in from;
	struct stat st;
	char path[64];
	int on = 1;
	char *cp;
	struct sockaddr_in soin;
	uid_t unpriv_uid;
	gid_t unpriv_gid;

	if (getuid())
		errx(1, "not super user");

	run_as(&unpriv_uid, &unpriv_gid);

	argv++; argc--;
	while (argc > 0 && *argv[0] == '-') {
		if (strcmp(*argv, "-m") == 0) {
			if (argc > 1 && isdigit(*(argv + 1)[0])) {
				argv++, argc--;
				multicast_mode  = SCOPED_MULTICAST;
				multicast_scope = atoi(*argv);
				if (multicast_scope > MAX_MULTICAST_SCOPE)
					errx(1, "ttl must not exceed %u",
					MAX_MULTICAST_SCOPE);
			}
			else multicast_mode = PER_INTERFACE_MULTICAST;
		}
		else if (strcmp(*argv, "-i") == 0)
			insecure_mode = 1;
		else if (strcmp(*argv, "-l") == 0)
			quiet_mode = 1;
		else if (strcmp(*argv, "-p") == 0)
			iff_flag = 0;
		else
			usage();
		argv++, argc--;
	}
	if (argc > 0)
		usage();
#ifndef DEBUG
	daemon(1, 0);
#endif
	(void) signal(SIGHUP, getboottime);
	openlog("rwhod", LOG_PID, LOG_DAEMON);
	sp = getservbyname("who", "udp");
	if (sp == NULL) {
		syslog(LOG_ERR, "who/udp: unknown service");
		exit(1);
	}
	if (chdir(_PATH_RWHODIR) < 0) {
		syslog(LOG_ERR, "%s: %m", _PATH_RWHODIR);
		exit(1);
	}
	/*
	 * Establish host name as returned by system.
	 */
	if (gethostname(myname, sizeof(myname) - 1) < 0) {
		syslog(LOG_ERR, "gethostname: %m");
		exit(1);
	}
	if ((cp = index(myname, '.')) != NULL)
		*cp = '\0';
	strncpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname) - 1);
	mywd.wd_hostname[sizeof(mywd.wd_hostname) - 1] = '\0';
#ifdef __APPLE__
	utmpf = open(_PATH_UTMPX, O_RDONLY|O_CREAT, 0644);
#else
	utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644);
#endif
	if (utmpf < 0) {
#ifdef __APPLE__
		syslog(LOG_ERR, "%s: %m", _PATH_UTMPX);
#else
		syslog(LOG_ERR, "%s: %m", _PATH_UTMP);
#endif
		exit(1);
	}
	getboottime(0);
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		syslog(LOG_ERR, "socket: %m");
		exit(1);
	}
	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
		syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
		exit(1);
	}
	memset(&soin, 0, sizeof(soin));
	soin.sin_len = sizeof(soin);
	soin.sin_family = AF_INET;
	soin.sin_port = sp->s_port;
	if (bind(s, (struct sockaddr *)&soin, sizeof(soin)) < 0) {
		syslog(LOG_ERR, "bind: %m");
		exit(1);
	}
	setgid(unpriv_gid);
	setgroups(1, &unpriv_gid);	/* XXX BOGUS groups[0] = egid */
	setuid(unpriv_uid);
	if (!configure(s))
		exit(1);
	if (!quiet_mode) {
		signal(SIGALRM, onalrm);
		onalrm(0);
	}
	for (;;) {
		struct whod wd;
		socklen_t len = sizeof(from);
		int cc, whod;
		time_t t;

		cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0,
			(struct sockaddr *)&from, &len);
		if (cc <= 0) {
			if (cc < 0 && errno != EINTR)
				syslog(LOG_WARNING, "recv: %m");
			continue;
		}
		if (from.sin_port != sp->s_port && !insecure_mode) {
			syslog(LOG_WARNING, "%d: bad source port from %s",
			    ntohs(from.sin_port), inet_ntoa(from.sin_addr));
			continue;
		}
		if (cc < WHDRSIZE) {
			syslog(LOG_WARNING, "short packet from %s",
			    inet_ntoa(from.sin_addr));
			continue;
		}
		if (wd.wd_vers != WHODVERSION)
			continue;
		if (wd.wd_type != WHODTYPE_STATUS)
			continue;
		if (!verify(wd.wd_hostname, sizeof wd.wd_hostname)) {
			syslog(LOG_WARNING, "malformed host name from %s",
			    inet_ntoa(from.sin_addr));
			continue;
		}
		(void) snprintf(path, sizeof path, "whod.%s", wd.wd_hostname);
		/*
		 * Rather than truncating and growing the file each time,
		 * use ftruncate if size is less than previous size.
		 */
		whod = open(path, O_WRONLY | O_CREAT, 0644);
		if (whod < 0) {
			syslog(LOG_WARNING, "%s: %m", path);
			continue;
		}
#if ENDIAN != BIG_ENDIAN
		{
			int i, n = (cc - WHDRSIZE)/sizeof(struct whoent);
			struct whoent *we;

			/* undo header byte swapping before writing to file */
			wd.wd_sendtime = ntohl(wd.wd_sendtime);
			for (i = 0; i < 3; i++)
				wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
			wd.wd_boottime = ntohl(wd.wd_boottime);
			we = wd.wd_we;
			for (i = 0; i < n; i++) {
				we->we_idle = ntohl(we->we_idle);
				we->we_utmp.out_time =
				    ntohl(we->we_utmp.out_time);
				we++;
			}
		}
#endif
		(void) time(&t);
		wd.wd_recvtime = _time_to_int(t);
		(void) write(whod, (char *)&wd, cc);
		if (fstat(whod, &st) < 0 || st.st_size > cc)
			ftruncate(whod, cc);
		(void) close(whod);
	}
}
示例#3
0
int daemonize_trqauthd(char *server_ip, int server_port, void *(*process_meth)(void *))
  {
  int gid;
  pid_t pid;
  int   rc;
  char  error_buf[1024];

  umask(022);

  gid = getgid();
  /* secure supplemental groups */
  if(setgroups(1, (gid_t *)&gid) != 0)
    {
    fprintf(stderr, "Unable to drop secondary groups. Some MAC framework is active?\n");
    snprintf(error_buf, sizeof(error_buf),
                     "setgroups(group = %lu) failed: %s\n",
                     (unsigned long)gid, strerror(errno));
    fprintf(stderr, "%s\n", error_buf);
    return(1);
    }

  if (getenv("PBSDEBUG") != NULL)
    debug_mode = TRUE;
  if (debug_mode == FALSE)
    {
    pid = fork();
    if(pid > 0)
      {
      /* parent. We are done */
      return(0);
      }
    else if (pid < 0)
      {
      /* something went wrong */
      fprintf(stderr, "fork failed. errno = %d\n", errno);
      return(PBSE_RMSYSTEM);
      }
    else
      {
      fprintf(stderr, "trqauthd daemonized - port %d\n", server_port);
      /* If I made it here I am the child */
      fclose(stdin);
      fclose(stdout);
      fclose(stderr);
      /* We closed 0 (stdin), 1 (stdout), and 2 (stderr). fopen should give us
         0, 1 and 2 in that order. this is a UNIX practice */
      (void)fopen("/dev/null", "r");
      (void)fopen("/dev/null", "r");
      (void)fopen("/dev/null", "r");
      }
    }
  else
    {
    fprintf(stderr, "trqauthd port: %d\n", server_port);
    }

    /* start the listener */
    rc = start_listener(server_ip, server_port, process_meth);
    if(rc != PBSE_NONE)
      {
      openlog("daemonize_trqauthd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
      syslog(LOG_ALERT, "trqauthd could not start: %d\n", rc);
      exit(-1);
      }

    exit(0);
  }
示例#4
0
int main (int argc, char **argv) {
	server *srv = NULL;
	int print_config = 0;
	int test_config = 0;
	int i_am_root;
	int o;
	int num_childs = 0;
	int pid_fd = -1, fd;
	size_t i;
#ifdef HAVE_SIGACTION
	struct sigaction act;
#endif
#ifdef HAVE_GETRLIMIT
	struct rlimit rlim;
#endif

#ifdef USE_ALARM
	struct itimerval interval;

	interval.it_interval.tv_sec = 1;
	interval.it_interval.tv_usec = 0;
	interval.it_value.tv_sec = 1;
	interval.it_value.tv_usec = 0;
#endif


	/* for nice %b handling in strfime() */
	setlocale(LC_TIME, "C");

	if (NULL == (srv = server_init())) {
		fprintf(stderr, "did this really happen?\n");
		return -1;
	}

	/* init structs done */

	srv->srvconf.port = 0;
#ifdef HAVE_GETUID
	i_am_root = (getuid() == 0);
#else
	i_am_root = 0;
#endif
	srv->srvconf.dont_daemonize = 0;

	while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
		switch(o) {
		case 'f':
			if (config_read(srv, optarg)) {
				server_free(srv);
				return -1;
			}
			break;
		case 'm':
			buffer_copy_string(srv->srvconf.modules_dir, optarg);
			break;
		case 'p': print_config = 1; break;
		case 't': test_config = 1; break;
		case 'D': srv->srvconf.dont_daemonize = 1; break;
		case 'v': show_version(); return 0;
		case 'V': show_features(); return 0;
		case 'h': show_help(); return 0;
		default:
			show_help();
			server_free(srv);
			return -1;
		}
	}

	if (!srv->config_storage) {
		log_error_write(srv, __FILE__, __LINE__, "s",
				"No configuration available. Try using -f option.");

		server_free(srv);
		return -1;
	}

	if (print_config) {
		data_unset *dc = srv->config_context->data[0];
		if (dc) {
			dc->print(dc, 0);
			fprintf(stdout, "\n");
		} else {
			/* shouldn't happend */
			fprintf(stderr, "global config not found\n");
		}
	}

	if (test_config) {
		printf("Syntax OK\n");
	}

	if (test_config || print_config) {
		server_free(srv);
		return 0;
	}

	/* close stdin and stdout, as they are not needed */
	openDevNull(STDIN_FILENO);
	openDevNull(STDOUT_FILENO);

	if (0 != config_set_defaults(srv)) {
		log_error_write(srv, __FILE__, __LINE__, "s",
				"setting default values failed");
		server_free(srv);
		return -1;
	}

	/* UID handling */
#ifdef HAVE_GETUID
	if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
		/* we are setuid-root */

		log_error_write(srv, __FILE__, __LINE__, "s",
				"Are you nuts ? Don't apply a SUID bit to this binary");

		server_free(srv);
		return -1;
	}
#endif

	/* check document-root */
	if (srv->config_storage[0]->document_root->used <= 1) {
		log_error_write(srv, __FILE__, __LINE__, "s",
				"document-root is not set\n");

		server_free(srv);

		return -1;
	}

	if (plugins_load(srv)) {
		log_error_write(srv, __FILE__, __LINE__, "s",
				"loading plugins finally failed");

		plugins_free(srv);
		server_free(srv);

		return -1;
	}

	/* open pid file BEFORE chroot */
	if (srv->srvconf.pid_file->used) {
		if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
			struct stat st;
			if (errno != EEXIST) {
				log_error_write(srv, __FILE__, __LINE__, "sbs",
					"opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
				return -1;
			}

			if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
				log_error_write(srv, __FILE__, __LINE__, "sbs",
						"stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
			}

			if (!S_ISREG(st.st_mode)) {
				log_error_write(srv, __FILE__, __LINE__, "sb",
						"pid-file exists and isn't regular file:", srv->srvconf.pid_file);
				return -1;
			}

			if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
				log_error_write(srv, __FILE__, __LINE__, "sbs",
						"opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
				return -1;
			}
		}
	}

	if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
		/* select limits itself
		 *
		 * as it is a hard limit and will lead to a segfault we add some safety
		 * */
		srv->max_fds = FD_SETSIZE - 200;
	} else {
		srv->max_fds = 4096;
	}

	if (i_am_root) {
		struct group *grp = NULL;
		struct passwd *pwd = NULL;
		int use_rlimit = 1;

#ifdef HAVE_VALGRIND_VALGRIND_H
		if (RUNNING_ON_VALGRIND) use_rlimit = 0;
#endif

#ifdef HAVE_GETRLIMIT
		if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
			log_error_write(srv, __FILE__, __LINE__,
					"ss", "couldn't get 'max filedescriptors'",
					strerror(errno));
			return -1;
		}

		if (use_rlimit && srv->srvconf.max_fds) {
			/* set rlimits */

			rlim.rlim_cur = srv->srvconf.max_fds;
			rlim.rlim_max = srv->srvconf.max_fds;

			if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
				log_error_write(srv, __FILE__, __LINE__,
						"ss", "couldn't set 'max filedescriptors'",
						strerror(errno));
				return -1;
			}
		}

		if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
			srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
		} else {
			srv->max_fds = rlim.rlim_cur;
		}

		/* set core file rlimit, if enable_cores is set */
		if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
			rlim.rlim_cur = rlim.rlim_max;
			setrlimit(RLIMIT_CORE, &rlim);
		}
#endif
		if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
			/* don't raise the limit above FD_SET_SIZE */
			if (srv->max_fds > FD_SETSIZE - 200) {
				log_error_write(srv, __FILE__, __LINE__, "sd",
						"can't raise max filedescriptors above",  FD_SETSIZE - 200,
						"if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
				return -1;
			}
		}


#ifdef HAVE_PWD_H
		/* set user and group */
		if (srv->srvconf.username->used) {
			if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
				log_error_write(srv, __FILE__, __LINE__, "sb",
						"can't find username", srv->srvconf.username);
				return -1;
			}

			if (pwd->pw_uid == 0) {
				log_error_write(srv, __FILE__, __LINE__, "s",
						"I will not set uid to 0\n");
				return -1;
			}
		}

		if (srv->srvconf.groupname->used) {
			if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
				log_error_write(srv, __FILE__, __LINE__, "sb",
					"can't find groupname", srv->srvconf.groupname);
				return -1;
			}
			if (grp->gr_gid == 0) {
				log_error_write(srv, __FILE__, __LINE__, "s",
						"I will not set gid to 0\n");
				return -1;
			}
		}
#endif
		/* we need root-perms for port < 1024 */
		if (0 != network_init(srv)) {
			plugins_free(srv);
			server_free(srv);

			return -1;
		}
#ifdef HAVE_PWD_H
		/* 
		 * Change group before chroot, when we have access
		 * to /etc/group
		 * */
		if (srv->srvconf.groupname->used) {
			setgid(grp->gr_gid);
			setgroups(0, NULL);
			if (srv->srvconf.username->used) {
				initgroups(srv->srvconf.username->ptr, grp->gr_gid);
			}
		}
#endif
#ifdef HAVE_CHROOT
		if (srv->srvconf.changeroot->used) {
			tzset();

			if (-1 == chroot(srv->srvconf.changeroot->ptr)) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "chroot failed: ", strerror(errno));
				return -1;
			}
			if (-1 == chdir("/")) {
				log_error_write(srv, __FILE__, __LINE__, "ss", "chdir failed: ", strerror(errno));
				return -1;
			}
		}
#endif
#ifdef HAVE_PWD_H
		/* drop root privs */
		if (srv->srvconf.username->used) {
			setuid(pwd->pw_uid);
		}
#endif
#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
		/**
		 * on IRIX 6.5.30 they have prctl() but no DUMPABLE
		 */
		if (srv->srvconf.enable_cores) {
			prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
		}
#endif
	} else {

#ifdef HAVE_GETRLIMIT
		if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
			log_error_write(srv, __FILE__, __LINE__,
					"ss", "couldn't get 'max filedescriptors'",
					strerror(errno));
			return -1;
		}

		/**
		 * we are not root can can't increase the fd-limit, but we can reduce it
		 */
		if (srv->srvconf.max_fds && srv->srvconf.max_fds < rlim.rlim_cur) {
			/* set rlimits */

			rlim.rlim_cur = srv->srvconf.max_fds;

			if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
				log_error_write(srv, __FILE__, __LINE__,
						"ss", "couldn't set 'max filedescriptors'",
						strerror(errno));
				return -1;
			}
		}

		if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
			srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
		} else {
			srv->max_fds = rlim.rlim_cur;
		}

		/* set core file rlimit, if enable_cores is set */
		if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
			rlim.rlim_cur = rlim.rlim_max;
			setrlimit(RLIMIT_CORE, &rlim);
		}

#endif
		if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
			/* don't raise the limit above FD_SET_SIZE */
			if (srv->max_fds > FD_SETSIZE - 200) {
				log_error_write(srv, __FILE__, __LINE__, "sd",
						"can't raise max filedescriptors above",  FD_SETSIZE - 200,
						"if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
				return -1;
			}
		}

		if (0 != network_init(srv)) {
			plugins_free(srv);
			server_free(srv);

			return -1;
		}
	}

	/* set max-conns */
	if (srv->srvconf.max_conns > srv->max_fds) {
		/* we can't have more connections than max-fds */
		srv->max_conns = srv->max_fds;
	} else if (srv->srvconf.max_conns) {
		/* otherwise respect the wishes of the user */
		srv->max_conns = srv->srvconf.max_conns;
	} else {
		/* or use the default */
		srv->max_conns = srv->max_fds;
	}

	if (HANDLER_GO_ON != plugins_call_init(srv)) {
		log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");

		plugins_free(srv);
		network_close(srv);
		server_free(srv);

		return -1;
	}

#ifdef HAVE_FORK
	/* network is up, let's deamonize ourself */
	if (srv->srvconf.dont_daemonize == 0) daemonize();
#endif

	srv->gid = getgid();
	srv->uid = getuid();

	/* write pid file */
	if (pid_fd != -1) {
		buffer_copy_long(srv->tmp_buf, getpid());
		buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n"));
		write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1);
		close(pid_fd);
		pid_fd = -1;
	}

	/* Close stderr ASAP in the child process to make sure that nothing
	 * is being written to that fd which may not be valid anymore. */
	if (-1 == log_error_open(srv)) {
		log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down.");

		plugins_free(srv);
		network_close(srv);
		server_free(srv);
		return -1;
	}

	if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
		log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");

		plugins_free(srv);
		network_close(srv);
		server_free(srv);

		return -1;
	}

	/* dump unused config-keys */
	for (i = 0; i < srv->config_context->used; i++) {
		array *config = ((data_config *)srv->config_context->data[i])->value;
		size_t j;

		for (j = 0; config && j < config->used; j++) {
			data_unset *du = config->data[j];

			/* all var.* is known as user defined variable */
			if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
				continue;
			}

			if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
				log_error_write(srv, __FILE__, __LINE__, "sbs",
						"WARNING: unknown config-key:",
						du->key,
						"(ignored)");
			}
		}
	}

	if (srv->config_unsupported) {
		log_error_write(srv, __FILE__, __LINE__, "s",
				"Configuration contains unsupported keys. Going down.");
	}

	if (srv->config_deprecated) {
		log_error_write(srv, __FILE__, __LINE__, "s",
				"Configuration contains deprecated keys. Going down.");
	}

	if (srv->config_unsupported || srv->config_deprecated) {
		plugins_free(srv);
		network_close(srv);
		server_free(srv);

		return -1;
	}




#ifdef HAVE_SIGACTION
	memset(&act, 0, sizeof(act));
	act.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &act, NULL);
	sigaction(SIGUSR1, &act, NULL);
# if defined(SA_SIGINFO)
	act.sa_sigaction = sigaction_handler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = SA_SIGINFO;
# else
	act.sa_handler = signal_handler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
# endif
	sigaction(SIGINT,  &act, NULL);
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGHUP,  &act, NULL);
	sigaction(SIGALRM, &act, NULL);
	sigaction(SIGCHLD, &act, NULL);

#elif defined(HAVE_SIGNAL)
	/* ignore the SIGPIPE from sendfile() */
	signal(SIGPIPE, SIG_IGN);
	signal(SIGUSR1, SIG_IGN);
	signal(SIGALRM, signal_handler);
	signal(SIGTERM, signal_handler);
	signal(SIGHUP,  signal_handler);
	signal(SIGCHLD,  signal_handler);
	signal(SIGINT,  signal_handler);
#endif

#ifdef USE_ALARM
	signal(SIGALRM, signal_handler);

	/* setup periodic timer (1 second) */
	if (setitimer(ITIMER_REAL, &interval, NULL)) {
		log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
		return -1;
	}

	getitimer(ITIMER_REAL, &interval);
#endif

#ifdef HAVE_FORK
	/* start watcher and workers */
	num_childs = srv->srvconf.max_worker;
	if (num_childs > 0) {
		int child = 0;
		while (!child && !srv_shutdown && !graceful_shutdown) {
			if (num_childs > 0) {
				switch (fork()) {
				case -1:
					return -1;
				case 0:
					child = 1;
					break;
				default:
					num_childs--;
					break;
				}
			} else {
				int status;

				if (-1 != wait(&status)) {
					/** 
					 * one of our workers went away 
					 */
					num_childs++;
				} else {
					switch (errno) {
					case EINTR:
						/**
						 * if we receive a SIGHUP we have to close our logs ourself as we don't 
						 * have the mainloop who can help us here
						 */
						if (handle_sig_hup) {
							handle_sig_hup = 0;

							log_error_cycle(srv);

							/**
							 * forward to all procs in the process-group
							 * 
							 * we also send it ourself
							 */
							if (!forwarded_sig_hup) {
								forwarded_sig_hup = 1;
								kill(0, SIGHUP);
							}
						}
						break;
					default:
						break;
					}
				}
			}
		}

		/**
		 * for the parent this is the exit-point 
		 */
		if (!child) {
			/** 
			 * kill all children too 
			 */
			if (graceful_shutdown) {
				kill(0, SIGINT);
			} else if (srv_shutdown) {
				kill(0, SIGTERM);
			}

			log_error_close(srv);
			network_close(srv);
			connections_free(srv);
			plugins_free(srv);
			server_free(srv);
			return 0;
		}
	}
#endif

	if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
		log_error_write(srv, __FILE__, __LINE__,
				"s", "fdevent_init failed");
		return -1;
	}
	/*
	 * kqueue() is called here, select resets its internals,
	 * all server sockets get their handlers
	 *
	 * */
	if (0 != network_register_fdevents(srv)) {
		plugins_free(srv);
		network_close(srv);
		server_free(srv);

		return -1;
	}

	/* might fail if user is using fam (not gamin) and famd isn't running */
	if (NULL == (srv->stat_cache = stat_cache_init())) {
		log_error_write(srv, __FILE__, __LINE__, "s",
			"stat-cache could not be setup, dieing.");
		return -1;
	}

#ifdef HAVE_FAM_H
	/* setup FAM */
	if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
		if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
			log_error_write(srv, __FILE__, __LINE__, "s",
					 "could not open a fam connection, dieing.");
			return -1;
		}
#ifdef HAVE_FAMNOEXISTS
		FAMNoExists(srv->stat_cache->fam);
#endif

		srv->stat_cache->fam_fcce_ndx = -1;
		fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
		fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
	}
#endif


	/* get the current number of FDs */
	srv->cur_fds = open("/dev/null", O_RDONLY);
	close(srv->cur_fds);

	for (i = 0; i < srv->srv_sockets.used; i++) {
		server_socket *srv_socket = srv->srv_sockets.ptr[i];
		if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
			return -1;
		}
	}

	/* main-loop */
	while (!srv_shutdown) {
		int n;
		size_t ndx;
		time_t min_ts;

		if (handle_sig_hup) {
			handler_t r;

			/* reset notification */
			handle_sig_hup = 0;


			/* cycle logfiles */

			switch(r = plugins_call_handle_sighup(srv)) {
			case HANDLER_GO_ON:
				break;
			default:
				log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
				break;
			}

			if (-1 == log_error_cycle(srv)) {
				log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");

				return -1;
			} else {
#ifdef HAVE_SIGACTION
				log_error_write(srv, __FILE__, __LINE__, "sdsd", 
					"logfiles cycled UID =",
					last_sighup_info.si_uid,
					"PID =",
					last_sighup_info.si_pid);
#else
				log_error_write(srv, __FILE__, __LINE__, "s", 
					"logfiles cycled");
#endif
			}
		}

		if (handle_sig_alarm) {
			/* a new second */

#ifdef USE_ALARM
			/* reset notification */
			handle_sig_alarm = 0;
#endif

			/* get current time */
			min_ts = time(NULL);

			if (min_ts != srv->cur_ts) {
				int cs = 0;
				connections *conns = srv->conns;
				handler_t r;

				switch(r = plugins_call_handle_trigger(srv)) {
				case HANDLER_GO_ON:
					break;
				case HANDLER_ERROR:
					log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
					break;
				default:
					log_error_write(srv, __FILE__, __LINE__, "d", r);
					break;
				}

				/* trigger waitpid */
				srv->cur_ts = min_ts;

				/* cleanup stat-cache */
				stat_cache_trigger_cleanup(srv);
				/**
				 * check all connections for timeouts
				 *
				 */
				for (ndx = 0; ndx < conns->used; ndx++) {
					int changed = 0;
					connection *con;
					int t_diff;

					con = conns->ptr[ndx];

					if (con->state == CON_STATE_READ ||
					    con->state == CON_STATE_READ_POST) {
						if (con->request_count == 1) {
							if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
								/* time - out */
#if 0
								log_error_write(srv, __FILE__, __LINE__, "sd",
										"connection closed - read-timeout:", con->fd);
#endif
								connection_set_state(srv, con, CON_STATE_ERROR);
								changed = 1;
							}
						} else {
							if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
								/* time - out */
#if 0
								log_error_write(srv, __FILE__, __LINE__, "sd",
										"connection closed - read-timeout:", con->fd);
#endif
								connection_set_state(srv, con, CON_STATE_ERROR);
								changed = 1;
							}
						}
					}

					if ((con->state == CON_STATE_WRITE) &&
					    (con->write_request_ts != 0)) {
#if 0
						if (srv->cur_ts - con->write_request_ts > 60) {
							log_error_write(srv, __FILE__, __LINE__, "sdd",
									"connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
						}
#endif

						if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
							/* time - out */
#if 1
							log_error_write(srv, __FILE__, __LINE__, "sbsosds",
									"NOTE: a request for",
									con->request.uri,
									"timed out after writing",
									con->bytes_written,
									"bytes. We waited",
									(int)con->conf.max_write_idle,
									"seconds. If this a problem increase server.max-write-idle");
#endif
							connection_set_state(srv, con, CON_STATE_ERROR);
							changed = 1;
						}
					}
					/* we don't like div by zero */
					if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;

					if (con->traffic_limit_reached &&
					    (con->conf.kbytes_per_second == 0 ||
					     ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
						/* enable connection again */
						con->traffic_limit_reached = 0;

						changed = 1;
					}

					if (changed) {
						connection_state_machine(srv, con);
					}
					con->bytes_written_cur_second = 0;
					*(con->conf.global_bytes_per_second_cnt_ptr) = 0;

#if 0
					if (cs == 0) {
						fprintf(stderr, "connection-state: ");
						cs = 1;
					}

					fprintf(stderr, "c[%d,%d]: %s ",
						con->fd,
						con->fcgi.fd,
						connection_get_state(con->state));
#endif
				}

				if (cs == 1) fprintf(stderr, "\n");
			}
		}

		if (srv->sockets_disabled) {
			/* our server sockets are disabled, why ? */

			if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
			    (srv->conns->used < srv->max_conns * 0.9) &&
			    (0 == graceful_shutdown)) {
				for (i = 0; i < srv->srv_sockets.used; i++) {
					server_socket *srv_socket = srv->srv_sockets.ptr[i];
					fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
				}

				log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");

				srv->sockets_disabled = 0;
			}
		} else {
			if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
			    (srv->conns->used > srv->max_conns) || /* out of connections */
			    (graceful_shutdown)) { /* graceful_shutdown */

				/* disable server-fds */

				for (i = 0; i < srv->srv_sockets.used; i++) {
					server_socket *srv_socket = srv->srv_sockets.ptr[i];
					fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);

					if (graceful_shutdown) {
						/* we don't want this socket anymore,
						 *
						 * closing it right away will make it possible for
						 * the next lighttpd to take over (graceful restart)
						 *  */

						fdevent_unregister(srv->ev, srv_socket->fd);
						close(srv_socket->fd);
						srv_socket->fd = -1;

						/* network_close() will cleanup after us */

						if (srv->srvconf.pid_file->used &&
						    srv->srvconf.changeroot->used == 0) {
							if (0 != unlink(srv->srvconf.pid_file->ptr)) {
								if (errno != EACCES && errno != EPERM) {
									log_error_write(srv, __FILE__, __LINE__, "sbds",
											"unlink failed for:",
											srv->srvconf.pid_file,
											errno,
											strerror(errno));
								}
							}
						}
					}
				}

				if (graceful_shutdown) {
					log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
				} else if (srv->conns->used > srv->max_conns) {
					log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
				} else {
					log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
				}

				srv->sockets_disabled = 1;
			}
		}

		if (graceful_shutdown && srv->conns->used == 0) {
			/* we are in graceful shutdown phase and all connections are closed
			 * we are ready to terminate without harming anyone */
			srv_shutdown = 1;
		}

		/* we still have some fds to share */
		if (srv->want_fds) {
			/* check the fdwaitqueue for waiting fds */
			int free_fds = srv->max_fds - srv->cur_fds - 16;
			connection *con;

			for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
				connection_state_machine(srv, con);

				srv->want_fds--;
			}
		}

		if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
			/* n is the number of events */
			int revents;
			int fd_ndx;
#if 0
			if (n > 0) {
				log_error_write(srv, __FILE__, __LINE__, "sd",
						"polls:", n);
			}
#endif
			fd_ndx = -1;
			do {
				fdevent_handler handler;
				void *context;
				handler_t r;

				fd_ndx  = fdevent_event_next_fdndx (srv->ev, fd_ndx);
				revents = fdevent_event_get_revent (srv->ev, fd_ndx);
				fd      = fdevent_event_get_fd     (srv->ev, fd_ndx);
				handler = fdevent_get_handler(srv->ev, fd);
				context = fdevent_get_context(srv->ev, fd);

				/* connection_handle_fdevent needs a joblist_append */
#if 0
				log_error_write(srv, __FILE__, __LINE__, "sdd",
						"event for", fd, revents);
#endif
				switch (r = (*handler)(srv, context, revents)) {
				case HANDLER_FINISHED:
				case HANDLER_GO_ON:
				case HANDLER_WAIT_FOR_EVENT:
				case HANDLER_WAIT_FOR_FD:
					break;
				case HANDLER_ERROR:
					/* should never happen */
					SEGFAULT();
					break;
				default:
					log_error_write(srv, __FILE__, __LINE__, "d", r);
					break;
				}
			} while (--n > 0);
		} else if (n < 0 && errno != EINTR) {
			log_error_write(srv, __FILE__, __LINE__, "ss",
					"fdevent_poll failed:",
					strerror(errno));
		}

		for (ndx = 0; ndx < srv->joblist->used; ndx++) {
			connection *con = srv->joblist->ptr[ndx];
			handler_t r;

			connection_state_machine(srv, con);

			switch(r = plugins_call_handle_joblist(srv, con)) {
			case HANDLER_FINISHED:
			case HANDLER_GO_ON:
				break;
			default:
				log_error_write(srv, __FILE__, __LINE__, "d", r);
				break;
			}

			con->in_joblist = 0;
		}

		srv->joblist->used = 0;
	}

	if (srv->srvconf.pid_file->used &&
	    srv->srvconf.changeroot->used == 0 &&
	    0 == graceful_shutdown) {
		if (0 != unlink(srv->srvconf.pid_file->ptr)) {
			if (errno != EACCES && errno != EPERM) {
				log_error_write(srv, __FILE__, __LINE__, "sbds",
						"unlink failed for:",
						srv->srvconf.pid_file,
						errno,
						strerror(errno));
			}
		}
	}

#ifdef HAVE_SIGACTION
	log_error_write(srv, __FILE__, __LINE__, "sdsd", 
			"server stopped by UID =",
			last_sigterm_info.si_uid,
			"PID =",
			last_sigterm_info.si_pid);
#else
	log_error_write(srv, __FILE__, __LINE__, "s", 
			"server stopped");
#endif

	/* clean-up */
	log_error_close(srv);
	network_close(srv);
	connections_free(srv);
	plugins_free(srv);
	server_free(srv);

	return 0;
}
示例#5
0
文件: iodine.c 项目: nbraud/iodine
int
main(int argc, char **argv)
{
	char *nameserv_host;
	char *topdomain;
	char *errormsg;
#ifndef WINDOWS32
	struct passwd *pw;
#endif
	char *username;
	char password[33];
	int foreground;
	char *newroot;
	char *context;
	char *device;
	char *pidfile;
	int choice;
	int tun_fd;
	int dns_fd;
	int max_downstream_frag_size;
	int autodetect_frag_size;
	int retval;
	int raw_mode;
	int lazymode;
	int selecttimeout;
	int hostname_maxlen;
#ifdef OPENBSD
	int rtable = 0;
#endif
	struct sockaddr_storage nameservaddr;
	int nameservaddr_len;
	int nameserv_family;

	nameserv_host = NULL;
	topdomain = NULL;
	errormsg = NULL;
#ifndef WINDOWS32
	pw = NULL;
#endif
	username = NULL;
	memset(password, 0, 33);
	srand(time(NULL));
	foreground = 0;
	newroot = NULL;
	context = NULL;
	device = NULL;
	pidfile = NULL;

	autodetect_frag_size = 1;
	max_downstream_frag_size = 3072;
	retval = 0;
	raw_mode = 1;
	lazymode = 1;
	selecttimeout = 4;
	hostname_maxlen = 0xFF;
	nameserv_family = AF_UNSPEC;

#ifdef WINDOWS32
	WSAStartup(req_version, &wsa_data);
#endif

	srand((unsigned) time(NULL));
	client_init();

#if !defined(BSD) && !defined(__GLIBC__)
	__progname = strrchr(argv[0], '/');
	if (__progname == NULL)
		__progname = argv[0];
	else
		__progname++;
#endif

	while ((choice = getopt(argc, argv, "46vfhru:t:d:R:P:m:M:F:T:O:L:I:")) != -1) {
		switch(choice) {
		case '4':
			nameserv_family = AF_INET;
			break;
		case '6':
			nameserv_family = AF_INET6;
			break;
		case 'v':
			version();
			/* NOTREACHED */
			break;
		case 'f':
			foreground = 1;
			break;
		case 'h':
			help();
			/* NOTREACHED */
			break;
		case 'r':
			raw_mode = 0;
			break;
		case 'u':
			username = optarg;
			break;
		case 't':
			newroot = optarg;
			break;
		case 'd':
			device = optarg;
			break;
#ifdef OPENBSD
		case 'R':
			rtable = atoi(optarg);
			break;
#endif
		case 'P':
			strncpy(password, optarg, sizeof(password));
			password[sizeof(password)-1] = 0;

			/* XXX: find better way of cleaning up ps(1) */
			memset(optarg, 0, strlen(optarg));
			break;
		case 'm':
			autodetect_frag_size = 0;
			max_downstream_frag_size = atoi(optarg);
			break;
		case 'M':
			hostname_maxlen = atoi(optarg);
			if (hostname_maxlen > 255)
				hostname_maxlen = 255;
			if (hostname_maxlen < 10)
				hostname_maxlen = 10;
			break;
		case 'z':
			context = optarg;
			break;
		case 'F':
			pidfile = optarg;
			break;
		case 'T':
			if (client_set_qtype(optarg))
				errx(5, "Invalid query type '%s'", optarg);
			break;
		case 'O':       /* not -D, is Debug in server */
			client_set_downenc(optarg);
			break;
		case 'L':
			lazymode = atoi(optarg);
			if (lazymode > 1)
				lazymode = 1;
			if (lazymode < 0)
				lazymode = 0;
			if (!lazymode)
				selecttimeout = 1;
			break;
		case 'I':
			selecttimeout = atoi(optarg);
			if (selecttimeout < 1)
				selecttimeout = 1;
			break;
		default:
			usage();
			/* NOTREACHED */
		}
	}

	check_superuser(usage);

	argc -= optind;
	argv += optind;

	switch (argc) {
	case 1:
		nameserv_host = get_resolvconf_addr();
		topdomain = strdup(argv[0]);
		break;
	case 2:
		nameserv_host = argv[0];
		topdomain = strdup(argv[1]);
		break;
	default:
		usage();
		/* NOTREACHED */
	}

	if (max_downstream_frag_size < 1 || max_downstream_frag_size > 0xffff) {
		warnx("Use a max frag size between 1 and 65535 bytes.\n");
		usage();
		/* NOTREACHED */
	}

	if (nameserv_host) {
		nameservaddr_len = get_addr(nameserv_host, DNS_PORT, nameserv_family, 0, &nameservaddr);
		if (nameservaddr_len < 0) {
			errx(1, "Cannot lookup nameserver '%s': %s ",
				nameserv_host, gai_strerror(nameservaddr_len));
		}
		client_set_nameserver(&nameservaddr, nameservaddr_len);
	} else {
		warnx("No nameserver found - not connected to any network?\n");
		usage();
		/* NOTREACHED */
	}

	if(check_topdomain(topdomain, &errormsg)) {
		warnx("Invalid topdomain: %s", errormsg);
		usage();
		/* NOTREACHED */
	}

	client_set_selecttimeout(selecttimeout);
	client_set_lazymode(lazymode);
	client_set_topdomain(topdomain);
	client_set_hostname_maxlen(hostname_maxlen);

	if (username != NULL) {
#ifndef WINDOWS32
		if ((pw = getpwnam(username)) == NULL) {
			warnx("User %s does not exist!\n", username);
			usage();
			/* NOTREACHED */
		}
#endif
	}

	if (strlen(password) == 0) {
		if (NULL != getenv(PASSWORD_ENV_VAR))
			snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR));
		else
			read_password(password, sizeof(password));
	}

	client_set_password(password);

	if ((tun_fd = open_tun(device)) == -1) {
		retval = 1;
		goto cleanup1;
	}
	if ((dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE)) < 0) {
		retval = 1;
		goto cleanup2;
	}
#ifdef OPENBSD
	if (rtable > 0)
		socket_setrtable(dns_fd, rtable);
#endif

	signal(SIGINT, sighandler);
	signal(SIGTERM, sighandler);

	fprintf(stderr, "Sending DNS queries for %s to %s\n",
		topdomain, format_addr(&nameservaddr, nameservaddr_len));

	if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) {
		retval = 1;
		goto cleanup2;
	}

	if (client_get_conn() == CONN_RAW_UDP) {
		fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr());
	}

	fprintf(stderr, "Connection setup complete, transmitting data.\n");

	if (foreground == 0)
		do_detach();

	if (pidfile != NULL)
		do_pidfile(pidfile);

	if (newroot != NULL)
		do_chroot(newroot);

	if (username != NULL) {
#ifndef WINDOWS32
		gid_t gids[1];
		gids[0] = pw->pw_gid;
		if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
			warnx("Could not switch to user %s!\n", username);
			usage();
			/* NOTREACHED */
		}
#endif
	}

	if (context != NULL)
		do_setcon(context);

	client_tunnel(tun_fd, dns_fd);

cleanup2:
	close_dns(dns_fd);
	close_tun(tun_fd);
cleanup1:

	return retval;
}
示例#6
0
/*
 * User shell for authenticating gateways. Sole purpose is to allow
 * a user to ssh to a gateway, and have the gateway modify packet
 * filters to allow access, then remove access when the user finishes
 * up. Meant to be used only from ssh(1) connections.
 */
int
main(int argc, char *argv[])
{
	int		 lockcnt = 0, n, pidfd;
	FILE		*config;
	struct in6_addr	 ina;
	struct passwd	*pw;
	char		*cp;
	gid_t		 gid;
	uid_t		 uid;
	char		*shell;
	login_cap_t	*lc;

	config = fopen(PATH_CONFFILE, "r");
	if (config == NULL) {
		syslog(LOG_ERR, "can not open %s (%m)", PATH_CONFFILE);
		exit(1);
	}

	if ((cp = getenv("SSH_TTY")) == NULL) {
		syslog(LOG_ERR, "non-interactive session connection for authpf");
		exit(1);
	}

	if ((cp = getenv("SSH_CLIENT")) == NULL) {
		syslog(LOG_ERR, "cannot determine connection source");
		exit(1);
	}

	if (strlcpy(ipsrc, cp, sizeof(ipsrc)) >= sizeof(ipsrc)) {
		syslog(LOG_ERR, "SSH_CLIENT variable too long");
		exit(1);
	}
	cp = strchr(ipsrc, ' ');
	if (!cp) {
		syslog(LOG_ERR, "corrupt SSH_CLIENT variable %s", ipsrc);
		exit(1);
	}
	*cp = '\0';
	if (inet_pton(AF_INET, ipsrc, &ina) != 1 &&
	    inet_pton(AF_INET6, ipsrc, &ina) != 1) {
		syslog(LOG_ERR,
		    "cannot determine IP from SSH_CLIENT %s", ipsrc);
		exit(1);
	}
	/* open the pf device */
	dev = open(PATH_DEVFILE, O_RDWR);
	if (dev == -1) {
		syslog(LOG_ERR, "cannot open packet filter device (%m)");
		goto die;
	}

	uid = getuid();
	pw = getpwuid(uid);
	if (pw == NULL) {
		syslog(LOG_ERR, "cannot find user for uid %u", uid);
		goto die;
	}

	if ((lc = login_getclass(pw->pw_class)) != NULL)
		shell = login_getcapstr(lc, "shell", pw->pw_shell,
		    pw->pw_shell);
	else
		shell = pw->pw_shell;

	login_close(lc);

	if (strcmp(shell, PATH_AUTHPF_SHELL)) {
		syslog(LOG_ERR, "wrong shell for user %s, uid %u",
		    pw->pw_name, pw->pw_uid);
		if (shell != pw->pw_shell)
			free(shell);
		goto die;
	}

	if (shell != pw->pw_shell)
		free(shell);

	/*
	 * Paranoia, but this data _does_ come from outside authpf, and
	 * truncation would be bad.
	 */
	if (strlcpy(luser, pw->pw_name, sizeof(luser)) >= sizeof(luser)) {
		syslog(LOG_ERR, "username too long: %s", pw->pw_name);
		goto die;
	}

	if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)",
	    luser, (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
		syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld",
		    luser, (long)getpid(), (long)getpid());
		if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
		    (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
			syslog(LOG_ERR, "pid too large for ruleset name");
			goto die;
		}
	}


	/* Make our entry in /var/authpf as /var/authpf/ipaddr */
	n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc);
	if (n < 0 || (u_int)n >= sizeof(pidfile)) {
		syslog(LOG_ERR, "path to pidfile too long");
		goto die;
	}

	/*
	 * If someone else is already using this ip, then this person
	 * wants to switch users - so kill the old process and exit
	 * as well.
	 *
	 * Note, we could print a message and tell them to log out, but the
	 * usual case of this is that someone has left themselves logged in,
	 * with the authenticated connection iconized and someone else walks
	 * up to use and automatically logs in before using. If this just
	 * gets rid of the old one silently, the new user never knows they
	 * could have used someone else's old authentication. If we
	 * tell them to log out before switching users it is an invitation
	 * for abuse.
	 */

	do {
		int	save_errno, otherpid = -1;
		char	otherluser[MAXLOGNAME];

		if ((pidfd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1 ||
		    (pidfp = fdopen(pidfd, "r+")) == NULL) {
			if (pidfd != -1)
				close(pidfd);
			syslog(LOG_ERR, "cannot open or create %s: %s", pidfile,
			    strerror(errno));
			goto die;
		}

		if (flock(fileno(pidfp), LOCK_EX|LOCK_NB) == 0)
			break;
		save_errno = errno;

		/* Mark our pid, and username to our file. */

		rewind(pidfp);
		/* 31 == MAXLOGNAME - 1 */
		if (fscanf(pidfp, "%d\n%31s\n", &otherpid, otherluser) != 2)
			otherpid = -1;
		syslog(LOG_DEBUG, "tried to lock %s, in use by pid %d: %s",
		    pidfile, otherpid, strerror(save_errno));

		if (otherpid > 0) {
			syslog(LOG_INFO,
			    "killing prior auth (pid %d) of %s by user %s",
			    otherpid, ipsrc, otherluser);
			if (kill((pid_t) otherpid, SIGTERM) == -1) {
				syslog(LOG_INFO,
				    "could not kill process %d: (%m)",
				    otherpid);
			}
		}

		/*
		 * we try to kill the previous process and acquire the lock
		 * for 10 seconds, trying once a second. if we can't after
		 * 10 attempts we log an error and give up
		 */
		if (++lockcnt > 10) {
			syslog(LOG_ERR, "cannot kill previous authpf (pid %d)",
			    otherpid);
			fclose(pidfp);
			pidfp = NULL;
			goto dogdeath;
		}
		sleep(1);

		/* re-open, and try again. The previous authpf process
		 * we killed above should unlink the file and release
		 * it's lock, giving us a chance to get it now
		 */
		fclose(pidfp);
		pidfp = NULL;
	} while (1);
	
	/* whack the group list */
	gid = getegid();
	if (setgroups(1, &gid) == -1) {
		syslog(LOG_INFO, "setgroups: %s", strerror(errno));
		do_death(0);
	}

	/* revoke privs */
	uid = getuid();
#if defined(__OpenBSD__)
	if (setresuid(uid, uid, uid) == -1) {
		syslog(LOG_INFO, "setresuid: %s", strerror(errno));
		do_death(0);
	}
#else /* defined(__OpenBSD__) */
	/* NetBSD */
	if (setuid(uid) == -1) {
		syslog(LOG_INFO, "setresuid: %s", strerror(errno));
		do_death(0);
	}
#endif /* defined(__OpenBSD__) */
	openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);

	if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) {
		syslog(LOG_INFO, "user %s prohibited", luser);
		do_death(0);
	}

	if (read_config(config)) {
		syslog(LOG_ERR, "invalid config file %s", PATH_CONFFILE);
		do_death(0);
	}

	if (remove_stale_rulesets()) {
		syslog(LOG_INFO, "error removing stale rulesets");
		do_death(0);
	}

	/* We appear to be making headway, so actually mark our pid */
	rewind(pidfp);
	fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser);
	fflush(pidfp);
	(void) ftruncate(fileno(pidfp), ftello(pidfp));

	if (change_filter(1, luser, ipsrc) == -1) {
		printf("Unable to modify filters\r\n");
		do_death(0);
	}
	if (change_table(1, ipsrc) == -1) {
		printf("Unable to modify table\r\n");
		change_filter(0, luser, ipsrc);
		do_death(0);
	}

	signal(SIGTERM, need_death);
	signal(SIGINT, need_death);
	signal(SIGALRM, need_death);
	signal(SIGPIPE, need_death);
	signal(SIGHUP, need_death);
	signal(SIGQUIT, need_death);
	signal(SIGTSTP, need_death);
	while (1) {
		printf("\r\nHello %s. ", luser);
		printf("You are authenticated from host \"%s\"\r\n", ipsrc);
		setproctitle("%s@%s", luser, ipsrc);
		print_message(PATH_MESSAGE);
		while (1) {
			sleep(10);
			if (want_death)
				do_death(1);
		}
	}

	/* NOTREACHED */
dogdeath:
	printf("\r\n\r\nSorry, this service is currently unavailable due to ");
	printf("technical difficulties\r\n\r\n");
	print_message(PATH_PROBLEM);
	printf("\r\nYour authentication process (pid %ld) was unable to run\n",
	    (long)getpid());
	sleep(180); /* them lusers read reaaaaal slow */
die:
	do_death(0);
	return (0);
}
示例#7
0
文件: slurmd.c 项目: mrhaoji/slurm
int
main (int argc, char *argv[])
{
	int i, pidfd;
	int blocked_signals[] = {SIGPIPE, 0};
	int cc;
	char *oom_value;
	uint32_t slurmd_uid = 0;
	uint32_t curr_uid = 0;
	char time_stamp[256];
	log_options_t lopts = LOG_OPTS_INITIALIZER;

	/* NOTE: logfile is NULL at this point */
	log_init(argv[0], lopts, LOG_DAEMON, NULL);

	/*
	 * Make sure we have no extra open files which
	 * would be propagated to spawned tasks.
	 */
	cc = sysconf(_SC_OPEN_MAX);
	for (i = 3; i < cc; i++)
		close(i);

	/*
	 * Drop supplementary groups.
	 */
	if (geteuid() == 0) {
		if (setgroups(0, NULL) != 0) {
			fatal("Failed to drop supplementary groups, "
			      "setgroups: %m");
		}
	} else {
		debug("Not running as root. Can't drop supplementary groups");
	}

	/*
	 * Create and set default values for the slurmd global
	 * config variable "conf"
	 */
	conf = xmalloc(sizeof(slurmd_conf_t));
	_init_conf();
	conf->argv = &argv;
	conf->argc = &argc;

	if (_slurmd_init() < 0) {
		error( "slurmd initialization failed" );
		fflush( NULL );
		exit(1);
	}

	slurmd_uid = slurm_get_slurmd_user_id();
	curr_uid = getuid();
	if (curr_uid != slurmd_uid) {
		struct passwd *pw = NULL;
		char *slurmd_user = NULL;
		char *curr_user = NULL;

		/* since when you do a getpwuid you get a pointer to a
		 * structure you have to do a xstrdup on the first
		 * call or your information will just get over
		 * written.  This is a memory leak, but a fatal is
		 * called right after so it isn't that big of a deal.
		 */
		if ((pw=getpwuid(slurmd_uid)))
			slurmd_user = xstrdup(pw->pw_name);
		if ((pw=getpwuid(curr_uid)))
			curr_user = pw->pw_name;

		fatal("You are running slurmd as something "
		      "other than user %s(%d).  If you want to "
		      "run as this user add SlurmdUser=%s "
		      "to the slurm.conf file.",
		      slurmd_user, slurmd_uid, curr_user);
	}
	init_setproctitle(argc, argv);

	xsignal(SIGTERM, &_term_handler);
	xsignal(SIGINT,  &_term_handler);
	xsignal(SIGHUP,  &_hup_handler );
	xsignal_block(blocked_signals);

	debug3("slurmd initialization successful");

	/*
	 * Become a daemon if desired.
	 * Do not chdir("/") or close all fd's
	 */
	if (conf->daemonize) {
		if (daemon(1,1) == -1)
			error("Couldn't daemonize slurmd: %m");
	}
	test_core_limit();
	info("slurmd version %s started", SLURM_VERSION_STRING);
	debug3("finished daemonize");

	if ((oom_value = getenv("SLURMD_OOM_ADJ"))) {
		i = atoi(oom_value);
		debug("Setting slurmd oom_adj to %d", i);
		set_oom_adj(i);
	}

	_kill_old_slurmd();

	if (conf->mlock_pages) {
		/*
		 * Call mlockall() if available to ensure slurmd
		 *  doesn't get swapped out
		 */
#ifdef _POSIX_MEMLOCK
		if (mlockall (MCL_FUTURE | MCL_CURRENT) < 0)
			error ("failed to mlock() slurmd pages: %m");
#else
		error ("mlockall() system call does not appear to be available");
#endif /* _POSIX_MEMLOCK */
	}


	/*
	 * Restore any saved revoked credential information
	 */
	if (!conf->cleanstart && (_restore_cred_state(conf->vctx) < 0))
		return SLURM_FAILURE;

	if (jobacct_gather_init() != SLURM_SUCCESS)
		fatal("Unable to initialize jobacct_gather");
	if (job_container_init() < 0)
		fatal("Unable to initialize job_container plugin.");
	if (container_g_restore(conf->spooldir, !conf->cleanstart))
		error("Unable to restore job_container state.");
	if (switch_g_node_init() < 0)
		fatal("Unable to initialize interconnect.");
	if (conf->cleanstart && switch_g_clear_node_state())
		fatal("Unable to clear interconnect state.");
	switch_g_slurmd_init();

	_create_msg_socket();

	conf->pid = getpid();
	/* This has to happen after daemon(), which closes all fd's,
	   so we keep the write lock of the pidfile.
	*/
	pidfd = create_pidfile(conf->pidfile, 0);

	rfc2822_timestamp(time_stamp, sizeof(time_stamp));
	info("%s started on %s", slurm_prog_name, time_stamp);

	_install_fork_handlers();
	list_install_fork_handlers();
	slurm_conf_install_fork_handlers();

	/*
	 * Initialize any plugins
	 */
	if (slurmd_plugstack_init())
		fatal("failed to initialize slurmd_plugstack");

	_spawn_registration_engine();
	_msg_engine();

	/*
	 * Close fd here, otherwise we'll deadlock since create_pidfile()
	 * flocks the pidfile.
	 */
	if (pidfd >= 0)			/* valid pidfd, non-error */
		(void) close(pidfd);	/* Ignore errors */
	if (unlink(conf->pidfile) < 0)
		error("Unable to remove pidfile `%s': %m", conf->pidfile);

	_wait_for_all_threads(120);
	_slurmd_fini();
	_destroy_conf();
	slurm_crypto_fini();	/* must be after _destroy_conf() */

	info("Slurmd shutdown completing");
	log_fini();
       	return 0;
}
示例#8
0
/*-------------------------------------------------------------------------*/
int Daemonize(const char* pidfile)
/* Turn the calling process into a daemon (detach from tty setuid(), etc   */
/*                                                                         */      
/* Returns: zero on success non-zero if slpd could not daemonize (or if    */
/*          slpd is already running                             .          */
/*-------------------------------------------------------------------------*/
{
    pid_t   pid;
    FILE*   fd;
    struct  passwd* pwent;
    char    pidstr[13];
    
    if(G_SlpdCommandLine.detach)
    {
    
        /*-------------------------------------------*/
        /* Release the controlling tty and std files */
        /*-------------------------------------------*/
        switch(fork())
        {
        case -1:
            return -1;
        case 0:
            /* child lives */
            break;
    
        default:
            /* parent dies */
            exit(0);
        }
    
        close(0); 
        close(1); 
        close(2); 
        setsid(); /* will only fail if we are already the process group leader */
    }
     
    /*------------------------------------------*/
    /* make sure that we're not running already */
    /*------------------------------------------*/
    /* read the pid from the file */
    fd = fopen(pidfile,"r");
    if(fd)
    {
        fread(pidstr,13,1,fd);
        fclose(fd);
        pid = atoi(pidstr);
        if(pid)
        {
            if(kill(pid,0) == 0)
            {
                /* we are already running */
                SLPFatal("slpd daemon is already running\n");
                return -1;
            }
        }    
    }
    /* write my pid to the pidfile */
    fd = fopen(pidfile,"w");
    if(fd)
    {
        sprintf(pidstr,"%i",getpid());
        fwrite(pidstr,strlen(pidstr),1,fd);
        fclose(fd);
    }
    
    /*----------------*/
    /* suid to daemon */
    /*----------------*/
    /* TODO: why do the following lines mess up my signal handlers? */
    pwent = getpwnam("daemon"); 
    if(pwent)
    {
        if( setgroups(1, &pwent->pw_gid) < 0 ||
            setgid(pwent->pw_gid) < 0 ||
            setuid(pwent->pw_uid) < 0 )
        {
            /* TODO: should we log here and return fail */
        }
    }
    
    return 0;
}
示例#9
0
main(int argc, char *argv[])
#endif
{
    char            options[128] = "aAc:CdD::fhHI:l:L:m:M:n:p:P:qrsS:UvV-:Y:";
    int             arg, i, ret;
    int             dont_fork = 0, do_help = 0;
    int             log_set = 0;
    int             uid = 0, gid = 0;
    int             agent_mode = -1;
    char           *pid_file = NULL;
    char            option_compatability[] = "-Le";
#if HAVE_GETPID
    int fd;
    FILE           *PID;
#endif
#if HAVE_GETPWNAM && HAVE_PWD_H
    struct passwd  *info;
#endif
#if HAVE_UNISTD_H
    const char     *persistent_dir;
#endif

#ifndef WIN32
    /*
     * close all non-standard file descriptors we may have
     * inherited from the shell.
     */
    for (i = getdtablesize() - 1; i > 2; --i) {
        (void) close(i);
    }
#endif /* #WIN32 */
    
    /*
     * register signals ASAP to prevent default action (usually core)
     * for signals during startup...
     */
#ifdef SIGTERM
    DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n"));
    signal(SIGTERM, SnmpdShutDown);
#endif
#ifdef SIGINT
    DEBUGMSGTL(("signal", "registering SIGINT signal handler\n"));
    signal(SIGINT, SnmpdShutDown);
#endif
#ifdef SIGHUP
    signal(SIGHUP, SIG_IGN);   /* do not terminate on early SIGHUP */
#endif
#ifdef SIGUSR1
    DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n"));
    signal(SIGUSR1, SnmpdDump);
#endif
#ifdef SIGPIPE
    DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n"));
    signal(SIGPIPE, SIG_IGN);   /* 'Inline' failure of wayward readers */
#endif
#ifdef SIGXFSZ
    signal(SIGXFSZ, SnmpdCatchRandomSignal);
#endif

#ifdef NETSNMP_NO_ROOT_ACCESS
    /*
     * Default to no.  
     */
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
			   NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
#endif
    /*
     * Default to NOT running an AgentX master.  
     */
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
			   NETSNMP_DS_AGENT_AGENTX_MASTER, 0);
    netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
                       NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1);
    netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
                       NETSNMP_DS_AGENT_AGENTX_RETRIES, -1);

    netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
                       NETSNMP_DS_AGENT_CACHE_TIMEOUT, 5);
    /*
     * Add some options if they are available.  
     */
#if HAVE_UNISTD_H
    strcat(options, "g:u:");
#endif
#if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
    strcat(options, "x:");
#endif
#ifdef USING_AGENTX_SUBAGENT_MODULE
    strcat(options, "X");
#endif

    /*
     * This is incredibly ugly, but it's probably the simplest way
     *  to handle the old '-L' option as well as the new '-Lx' style
     */
    for (i=0; i<argc; i++) {
        if (!strcmp(argv[i], "-L"))
            argv[i] = option_compatability;            
    }

#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
#ifdef WIN32
    snmp_log_syslogname(app_name_long);
#else
    snmp_log_syslogname(app_name);
#endif
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
    netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
                          NETSNMP_DS_LIB_APPTYPE, app_name);

    /*
     * Now process options normally.  
     */
    while ((arg = getopt(argc, argv, options)) != EOF) {
        switch (arg) {
        case '-':
            if (strcasecmp(optarg, "help") == 0) {
                usage(argv[0]);
            }
            if (strcasecmp(optarg, "version") == 0) {
                version();
            }

            handle_long_opt(optarg);
            break;

        case 'a':
            log_addresses++;
            break;

        case 'A':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
                                   NETSNMP_DS_LIB_APPEND_LOGFILES, 1);
            break;

        case 'c':
            if (optarg != NULL) {
                netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
				      NETSNMP_DS_LIB_OPTIONALCONFIG, optarg);
            } else {
                usage(argv[0]);
            }
            break;

        case 'C':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
				   NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
            break;

        case 'd':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
                                   NETSNMP_DS_LIB_QUICK_PRINT,
                                   ++snmp_dump_packet);
            break;

        case 'D':
            debug_register_tokens(optarg);
            snmp_set_do_debugging(1);
            break;

        case 'f':
            dont_fork = 1;
            break;

#if HAVE_UNISTD_H
        case 'g':
            if (optarg != NULL) {
                char           *ecp;
                int             gid;

                gid = strtoul(optarg, &ecp, 10);
                if (*ecp) {
#if HAVE_GETPWNAM && HAVE_PWD_H
                    struct group  *info;
                    info = getgrnam(optarg);
                    if (info) {
                        gid = info->gr_gid;
                    } else {
#endif
                        fprintf(stderr, "Bad group id: %s\n", optarg);
                        exit(1);
#if HAVE_GETPWNAM && HAVE_PWD_H
                    }
#endif
                }
                netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_GROUPID, gid);
            } else {
                usage(argv[0]);
            }
            break;
#endif

        case 'h':
            usage(argv[0]);
            break;

        case 'H':
            do_help = 1;
            break;

        case 'I':
            if (optarg != NULL) {
                add_to_init_list(optarg);
            } else {
                usage(argv[0]);
            }
            break;

#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
        case 'l':
            printf("Warning: -l option is deprecated, use -Lf <file> instead\n");
            if (optarg != NULL) {
                if (strlen(optarg) > PATH_MAX) {
                    fprintf(stderr,
                            "%s: logfile path too long (limit %d chars)\n",
                            argv[0], PATH_MAX);
                    exit(1);
                }
                snmp_enable_filelog(optarg,
                                    netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
                                                           NETSNMP_DS_LIB_APPEND_LOGFILES));
                log_set = 1;
            } else {
                usage(argv[0]);
            }
            break;
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */

        case 'L':
	    if  (snmp_log_options( optarg, argc, argv ) < 0 ) {
                usage(argv[0]);
            }
            log_set = 1;
            break;

        case 'm':
            if (optarg != NULL) {
                setenv("MIBS", optarg, 1);
            } else {
                usage(argv[0]);
            }
            break;

        case 'M':
            if (optarg != NULL) {
                setenv("MIBDIRS", optarg, 1);
            } else {
                usage(argv[0]);
            }
            break;

        case 'n':
            if (optarg != NULL) {
                app_name = optarg;
                netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
                                      NETSNMP_DS_LIB_APPTYPE, app_name);
            } else {
                usage(argv[0]);
            }
            break;

        case 'P':
            printf("Warning: -P option is deprecated, use -p instead\n");
        case 'p':
            if (optarg != NULL) {
                pid_file = optarg;
            } else {
                usage(argv[0]);
            }
            break;

        case 'q':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
                                   NETSNMP_DS_LIB_QUICK_PRINT, 1);
            break;

        case 'r':
            netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_NO_ROOT_ACCESS);
            break;

#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
        case 's':
            printf("Warning: -s option is deprecated, use -Lsd instead\n");
            snmp_enable_syslog();
            log_set = 1;
            break;

        case 'S':
            printf("Warning: -S option is deprecated, use -Ls <facility> instead\n");
            if (optarg != NULL) {
                switch (*optarg) {
                case 'd':
                case 'D':
                    Facility = LOG_DAEMON;
                    break;
                case 'i':
                case 'I':
                    Facility = LOG_INFO;
                    break;
                case '0':
                    Facility = LOG_LOCAL0;
                    break;
                case '1':
                    Facility = LOG_LOCAL1;
                    break;
                case '2':
                    Facility = LOG_LOCAL2;
                    break;
                case '3':
                    Facility = LOG_LOCAL3;
                    break;
                case '4':
                    Facility = LOG_LOCAL4;
                    break;
                case '5':
                    Facility = LOG_LOCAL5;
                    break;
                case '6':
                    Facility = LOG_LOCAL6;
                    break;
                case '7':
                    Facility = LOG_LOCAL7;
                    break;
                default:
                    fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg);
                    usage(argv[0]);
                }
                snmp_enable_syslog_ident(snmp_log_syslogname(NULL), Facility);
                log_set = 1;
            } else {
                fprintf(stderr, "no syslog facility specified\n");
                usage(argv[0]);
            }
            break;
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */

        case 'U':
            netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_LEAVE_PIDFILE);
            break;

#if HAVE_UNISTD_H
        case 'u':
            if (optarg != NULL) {
                char           *ecp;
                int             uid;

                uid = strtoul(optarg, &ecp, 10);
                if (*ecp) {
#if HAVE_GETPWNAM && HAVE_PWD_H
                    info = getpwnam(optarg);
                    if (info) {
                        uid = info->pw_uid;
                    } else {
#endif
                        fprintf(stderr, "Bad user id: %s\n", optarg);
                        exit(1);
#if HAVE_GETPWNAM && HAVE_PWD_H
                    }
#endif
                }
                netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_USERID, uid);
            } else {
                usage(argv[0]);
            }
            break;
#endif

        case 'v':
            version();

        case 'V':
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_VERBOSE, 1);
            break;

#if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
        case 'x':
            if (optarg != NULL) {
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_X_SOCKET, optarg);
            } else {
                usage(argv[0]);
            }
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_AGENTX_MASTER, 1);
            break;
#endif

        case 'X':
#if defined(USING_AGENTX_SUBAGENT_MODULE)
            agent_mode = SUB_AGENT;
#else
            fprintf(stderr, "%s: Illegal argument -X:"
		            "AgentX support not compiled in.\n", argv[0]);
            usage(argv[0]);
            exit(1);
#endif
            break;

        case 'Y':
            netsnmp_config_remember(optarg);
            break;

        default:
            usage(argv[0]);
            break;
        }
    }

    if (do_help) {
        netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
                               NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
        init_agent(app_name);        /* register our .conf handlers */
        init_mib_modules();
        init_snmp(app_name);
        fprintf(stderr, "Configuration directives understood:\n");
        read_config_print_usage("  ");
        exit(0);
    }

    if (optind < argc) {
#ifndef NETSNMP_NO_LISTEN_SUPPORT
        /*
         * There are optional transport addresses on the command line.  
         */
        DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc));
        for (i = optind; i < argc; i++) {
            char *c, *astring;
            if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
					   NETSNMP_DS_AGENT_PORTS))) {
                astring = (char*)malloc(strlen(c) + 2 + strlen(argv[i]));
                if (astring == NULL) {
                    fprintf(stderr, "malloc failure processing argv[%d]\n", i);
                    exit(1);
                }
                sprintf(astring, "%s,%s", c, argv[i]);
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_PORTS, astring);
                SNMP_FREE(astring);
            } else {
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_PORTS, argv[i]);
            }
        }
        DEBUGMSGTL(("snmpd/main", "port spec: %s\n",
                    netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
					  NETSNMP_DS_AGENT_PORTS)));
#else /* NETSNMP_NO_LISTEN_SUPPORT */
        fprintf(stderr, "You specified ports to open; this agent was built to only send notifications\n");
        exit(1);
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
    }

#ifdef NETSNMP_LOGFILE
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
    if (0 == log_set)
        snmp_enable_filelog(NETSNMP_LOGFILE,
                            netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
                                                   NETSNMP_DS_LIB_APPEND_LOGFILES));
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
#endif

#ifdef USING_UTIL_FUNCS_RESTART_MODULE
    {
        /*
         * Initialize a argv set to the current for restarting the agent.
         */
        char *cptr, **argvptr;

        argvrestartp = (char **)malloc((argc + 2) * sizeof(char *));
        argvptr = argvrestartp;
        for (i = 0, ret = 1; i < argc; i++) {
            ret += strlen(argv[i]) + 1;
        }
        argvrestart = (char *) malloc(ret);
        argvrestartname = (char *) malloc(strlen(argv[0]) + 1);
        if (!argvrestartp || !argvrestart || !argvrestartname) {
            fprintf(stderr, "malloc failure processing argvrestart\n");
            exit(1);
        }
        strcpy(argvrestartname, argv[0]);

        for (cptr = argvrestart, i = 0; i < argc; i++) {
            strcpy(cptr, argv[i]);
            *(argvptr++) = cptr;
            cptr += strlen(argv[i]) + 1;
        }
    }
#endif /* USING_UTIL_FUNCS_RESTART_MODULE */

    if (agent_mode == -1) {
        if (strstr(argv[0], "agentxd") != NULL) {
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
				   NETSNMP_DS_AGENT_ROLE, SUB_AGENT);
        } else {
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
				   NETSNMP_DS_AGENT_ROLE, MASTER_AGENT);
        }
    } else {
        netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
			       NETSNMP_DS_AGENT_ROLE, agent_mode);
    }

    SOCK_STARTUP;
    init_agent(app_name);        /* do what we need to do first. */
    init_mib_modules();

    /*
     * start library 
     */
    init_snmp(app_name);

    if ((ret = init_master_agent()) != 0) {
        /*
         * Some error opening one of the specified agent transports.  
         */
        snmp_log(LOG_ERR, "Server Exiting with code 1\n");
        exit(1);
    }

    /*
     * Initialize the world.  Detach from the shell.  Create initial user.  
     */
    if(!dont_fork) {
        int quit = ! netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
                                            NETSNMP_DS_AGENT_QUIT_IMMEDIATELY);
        ret = netsnmp_daemonize(quit,
#ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
                                snmp_stderrlog_status()
#else /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
                                0
#endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
            );
        /*
         * xxx-rks: do we care if fork fails? I think we should...
         */
        if(ret != 0) {
            snmp_log(LOG_ERR, "Server Exiting with code 1\n");
            exit(1);
        }
    }

#if HAVE_GETPID
    if (pid_file != NULL) {
        /*
         * unlink the pid_file, if it exists, prior to open.  Without
         * doing this the open will fail if the user specified pid_file
         * already exists.
         */
        unlink(pid_file);
        fd = open(pid_file, O_CREAT | O_EXCL | O_WRONLY, 0600);
        if (fd == -1) {
            snmp_log_perror(pid_file);
            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
                                        NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                exit(1);
            }
        } else {
            if ((PID = fdopen(fd, "w")) == NULL) {
                snmp_log_perror(pid_file);
                exit(1);
            } else {
                fprintf(PID, "%d\n", (int) getpid());
                fclose(PID);
            }
#ifndef _MSC_VER
            /* The sequence open()/fdopen()/fclose()/close() makes MSVC crash,
               hence skip the close() call when using the MSVC runtime. */
            close(fd);
#endif
        }
    }
#endif

#if HAVE_UNISTD_H
    persistent_dir = get_persistent_directory();
    mkdirhier( persistent_dir, NETSNMP_AGENT_DIRECTORY_MODE, 0 );
   
    uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
			     NETSNMP_DS_AGENT_USERID);
    gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
			     NETSNMP_DS_AGENT_GROUPID);
    
#ifdef HAVE_CHOWN
    if ( uid != 0 || gid != 0 )
        chown( persistent_dir, uid, gid );
#endif

#ifdef HAVE_SETGID
    if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
				  NETSNMP_DS_AGENT_GROUPID)) != 0) {
        DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid));
        if (setgid(gid) == -1
#ifdef HAVE_SETGROUPS
            || setgroups(1, (gid_t *)&gid) == -1
#endif
            ) {
            snmp_log_perror("setgid failed");
            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
					NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                exit(1);
            }
        }
    }
#endif
#ifdef HAVE_SETUID
    if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
				  NETSNMP_DS_AGENT_USERID)) != 0) {
#if HAVE_GETPWNAM && HAVE_PWD_H && HAVE_INITGROUPS
        /*
         * Set supplementary groups before changing UID
         *   (which probably involves giving up privileges)
         */
        info = getpwuid(uid);
        if (info) {
            DEBUGMSGTL(("snmpd/main", "Supplementary groups for %s.\n", info->pw_name));
            if (initgroups(info->pw_name, (gid != 0 ? (gid_t)gid : info->pw_gid)) == -1) {
                snmp_log_perror("initgroups failed");
                if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
                                            NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                    exit(1);
                }
            }
        }
#endif
        DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid));
        if (setuid(uid) == -1) {
            snmp_log_perror("setuid failed");
            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
					NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                exit(1);
            }
        }
    }
#endif
#endif

    /*
     * Store persistent data immediately in case we crash later.  
     */
    snmp_store(app_name);

#ifdef SIGHUP
    DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n"));
    signal(SIGHUP, SnmpdReconfig);
#endif

    /*
     * Send coldstart trap if possible.  
     */
    send_easy_trap(0, 0);

    /*
     * We're up, log our version number.  
     */
    snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version());
#ifdef WIN32SERVICE
    agent_status = AGENT_RUNNING;
#endif
    netsnmp_addrcache_initialise();

    /*
     * Forever monitor the dest_port for incoming PDUs.  
     */
    DEBUGMSGTL(("snmpd/main", "We're up.  Starting to process data.\n"));
    if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
				NETSNMP_DS_AGENT_QUIT_IMMEDIATELY))
        receive();
    DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n"));
    SnmpTrapNodeDown();
    DEBUGMSGTL(("snmpd/main", "Bye...\n"));
    snmp_shutdown(app_name);
    shutdown_master_agent();
    shutdown_agent();

    if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
				NETSNMP_DS_AGENT_LEAVE_PIDFILE) &&
	(pid_file != NULL)) {
        unlink(pid_file);
    }
#ifdef WIN32SERVICE
    agent_status = AGENT_STOPPED;
#endif

#ifdef USING_UTIL_FUNCS_RESTART_MODULE
    SNMP_FREE(argvrestartname);
    SNMP_FREE(argvrestart);
    SNMP_FREE(argvrestartp);
#endif /* USING_UTIL_FUNCS_RESTART_MODULE */

    SOCK_CLEANUP;
    return 0;
}                               /* End main() -- snmpd */
示例#10
0
/*++
 * Function:    BecomeNonRoot
 *
 * Purpose:     If we are running as root, attempt to change that.
 *
 * Parameters:  nada
 *
 * Returns:     0 on success
 *              -1 on failure
 *
 * Authors:     Dave McMurtrie <*****@*****.**>
 *
 * Notes:       Relies on global copy of ProxyConfig_Struct "PC_Struct".
 *              Also worth mentioning that instead of just becoming non-root
 *              this function is now also responsible for chown()ing
 *              the global statistics file.  I had to choose
 *              between doing a passwd and group lookup twice (and further
 *              cluttering main) or doing the chown here where it
 *              doesn't logically belong.  I chose to put it here, but at
 *              least I documented it...
 *
 *              In addition to becoming non-root, this function now also
 *              does a chroot() if so configured.  Soon I'll rename this
 *              function to something more fitting...
 *--
 */
extern int BecomeNonRoot( void )
{
    char *fn = "BecomeNonRoot()";
    struct passwd *pwent;                    /* ptr to a passwd file entry */
    struct group *gp;                        /* ptr to a group file entry */
    uid_t newuid;                            /* uid we want to run as */
    gid_t newgid;                            /* gid we want to run as */
    
    if ((pwent = getpwnam( PC_Struct.proc_username )) == NULL)
    {
	syslog(LOG_WARNING, "%s: getpwnam(%s) failed.", 
	       fn, PC_Struct.proc_username);
	return(-1);
    }
    else
    {
	newuid = pwent->pw_uid;
    }
    
    /*
     * Since the whole purpose here is to not run as root, make sure that
     * we don't get UID 0 back for username.
     */
    if ( newuid == 0 )
    {
	syslog( LOG_ERR, "%s: getpwnam returned UID 0 for '%s'.", 
		fn, PC_Struct.proc_username );
	return(-1);
    }
    
    if ((gp = getgrnam( PC_Struct.proc_groupname )) == NULL)
    {
	syslog(LOG_WARNING, "%s: getgrnam(%s) failed.", 
	       fn, PC_Struct.proc_groupname);
	return(-1);
    }
    else
    {
	newgid = gp->gr_gid;
    }
    
    /*
     * The chown() call gets stuck here.  I hate it, but 
     * once in a while there are going to be things in life that I hate.
     */
    if ( chown( PC_Struct.stat_filename, newuid, newgid ) < 0 )
    {
	syslog( LOG_WARNING, "%s: chown() failed to set ownership of file '%s' to '%s:%s': %s", fn, PC_Struct.stat_filename, PC_Struct.proc_username, PC_Struct.proc_groupname, strerror( errno ) );
	return( -1 );
    }
    

    /*
     * Now the whole reason this function exists...  setgid and setuid.
     *
     * Patch by Jarno Huuskonen -- also drop any supplementary groups.
     */

    syslog( LOG_INFO, "%s: Process will run as uid %d (%s) and gid %d (%s).",
	    fn, newuid, PC_Struct.proc_username, 
	    newgid, PC_Struct.proc_groupname );
    
    if ( setgroups( 0, NULL ) < 0 )
    {
	syslog( LOG_WARNING, "%s: setgroups() failed: %s", fn, strerror( errno ) );
	return( -1 );
    }
    
    if ((setgid(newgid)) < 0 )
    {
	syslog(LOG_WARNING, "%s: setgid(%d) failed: %s", fn, 
	       newgid, strerror(errno));
	return(-1);
    }

    /*
     * Patch originally by Dave Steinberg, and later modified by
     * Jarno Huuskonen -- chroot() if so configured.
     */
    if ( PC_Struct.chroot_directory ) 
    {
	if ( chroot( PC_Struct.chroot_directory ) < 0 || chdir( "/" ) < 0 ) 
	{
	    syslog( LOG_WARNING, "%s: chroot(%s) failed: %s", fn, PC_Struct.chroot_directory, strerror( errno ) );
	    return( -1 );
	}
	
	syslog( LOG_INFO, "%s: Process chrooted in %s", fn, PC_Struct.chroot_directory );
    }
    
    if ((setuid(newuid)) < 0 )
    {
	syslog(LOG_WARNING,"%s: setuid(%d) failed: %s", fn, 
	       newuid, strerror(errno));
	return(-1);
    }
    
    return(0);
}
示例#11
0
int
main(int argc, char **argv)
{
  int i;
  sigset_t set;
#if ENABLE_LINUXDVB
  uint32_t adapter_mask;
#endif
  int  log_level   = LOG_INFO;
  int  log_options = TVHLOG_OPT_MILLIS | TVHLOG_OPT_STDERR | TVHLOG_OPT_SYSLOG;
  const char *log_debug = NULL, *log_trace = NULL;
  char buf[512];

  main_tid = pthread_self();

  /* Setup global mutexes */
  pthread_mutex_init(&ffmpeg_lock, NULL);
  pthread_mutex_init(&fork_lock, NULL);
  pthread_mutex_init(&global_lock, NULL);
  pthread_mutex_init(&atomic_lock, NULL);
  pthread_cond_init(&gtimer_cond, NULL);

  /* Defaults */
  tvheadend_webui_port      = 9981;
  tvheadend_webroot         = NULL;
  tvheadend_htsp_port       = 9982;
  tvheadend_htsp_port_extra = 0;

  /* Command line options */
  int         opt_help         = 0,
              opt_version      = 0,
              opt_fork         = 0,
              opt_firstrun     = 0,
              opt_stderr       = 0,
              opt_syslog       = 0,
              opt_uidebug      = 0,
              opt_abort        = 0,
              opt_noacl        = 0,
              opt_fileline     = 0,
              opt_threadid     = 0,
              opt_ipv6         = 0,
              opt_tsfile_tuner = 0,
              opt_dump         = 0;
  const char *opt_config       = NULL,
             *opt_user         = NULL,
             *opt_group        = NULL,
             *opt_logpath      = NULL,
             *opt_log_debug    = NULL,
             *opt_log_trace    = NULL,
             *opt_pidpath      = "/var/run/tvheadend.pid",
#if ENABLE_LINUXDVB
             *opt_dvb_adapters = NULL,
#endif
             *opt_bindaddr     = NULL,
             *opt_subscribe    = NULL;
  str_list_t  opt_tsfile       = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) };
  cmdline_opt_t cmdline_opts[] = {
    {   0, NULL,        "Generic Options",         OPT_BOOL, NULL         },
    { 'h', "help",      "Show this page",          OPT_BOOL, &opt_help    },
    { 'v', "version",   "Show version infomation", OPT_BOOL, &opt_version },

    {   0, NULL,        "Service Configuration",   OPT_BOOL, NULL         },
    { 'c', "config",    "Alternate config path",   OPT_STR,  &opt_config  },
    { 'f', "fork",      "Fork and run as daemon",  OPT_BOOL, &opt_fork    },
    { 'u', "user",      "Run as user",             OPT_STR,  &opt_user    },
    { 'g', "group",     "Run as group",            OPT_STR,  &opt_group   },
    { 'p', "pid",       "Alternate pid path",      OPT_STR,  &opt_pidpath },
    { 'C', "firstrun",  "If no user account exists then create one with\n"
	                      "no username and no password. Use with care as\n"
	                      "it will allow world-wide administrative access\n"
	                      "to your Tvheadend installation until you edit\n"
	                      "the access-control from within the Tvheadend UI",
      OPT_BOOL, &opt_firstrun },
#if ENABLE_LINUXDVB
    { 'a', "adapters",  "Only use specified DVB adapters (comma separated)",
      OPT_STR, &opt_dvb_adapters },
#endif
    {   0, NULL,         "Server Connectivity",    OPT_BOOL, NULL         },
    { '6', "ipv6",       "Listen on IPv6",         OPT_BOOL, &opt_ipv6    },
    { 'b', "bindaddr",   "Specify bind address",   OPT_STR,  &opt_bindaddr},
    {   0, "http_port",  "Specify alternative http port",
      OPT_INT, &tvheadend_webui_port },
    {   0, "http_root",  "Specify alternative http webroot",
      OPT_STR, &tvheadend_webroot },
    {   0, "htsp_port",  "Specify alternative htsp port",
      OPT_INT, &tvheadend_htsp_port },
    {   0, "htsp_port2", "Specify extra htsp port",
      OPT_INT, &tvheadend_htsp_port_extra },

    {   0, NULL,        "Debug Options",           OPT_BOOL, NULL         },
    { 'd', "stderr",    "Enable debug on stderr",  OPT_BOOL, &opt_stderr  },
    { 's', "syslog",    "Enable debug to syslog",  OPT_BOOL, &opt_syslog  },
    { 'l', "logfile",   "Enable debug to file",    OPT_STR,  &opt_logpath },
    {   0, "debug",     "Enable debug subsystems", OPT_STR,  &opt_log_debug },
#if ENABLE_TRACE
    {   0, "trace",     "Enable trace subsystems", OPT_STR,  &opt_log_trace },
#endif
    {   0, "fileline",  "Add file and line numbers to debug", OPT_BOOL, &opt_fileline },
    {   0, "threadid",  "Add the thread ID to debug", OPT_BOOL, &opt_threadid },
    {   0, "uidebug",   "Enable webUI debug (non-minified JS)", OPT_BOOL, &opt_uidebug },
    { 'A', "abort",     "Immediately abort",       OPT_BOOL, &opt_abort   },
    { 'D', "dump",      "Enable coredumps for daemon", OPT_BOOL, &opt_dump },
    {   0, "noacl",     "Disable all access control checks",
      OPT_BOOL, &opt_noacl },
    { 'j', "join",      "Subscribe to a service permanently",
      OPT_STR, &opt_subscribe },


    { 0, NULL, "TODO: testing", OPT_BOOL, NULL },
    { 0, "tsfile_tuners", "Number of tsfile tuners", OPT_INT, &opt_tsfile_tuner },
    { 0, "tsfile", "tsfile input (mux file)", OPT_STR_LIST, &opt_tsfile },

  };

  /* Get current directory */
  tvheadend_cwd = dirname(dirname(tvh_strdupa(argv[0])));

  /* Set locale */
  setlocale(LC_ALL, "");
  setlocale(LC_NUMERIC, "C");

  /* make sure the timezone is set */
  tzset();

  /* Process command line */
  for (i = 1; i < argc; i++) {

    /* Find option */
    cmdline_opt_t *opt
      = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]);
    if (!opt)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 "invalid option specified [%s]", argv[i]);

    /* Process */
    if (opt->type == OPT_BOOL)
      *((int*)opt->param) = 1;
    else if (++i == argc)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 "option %s requires a value", opt->lopt);
    else if (opt->type == OPT_INT)
      *((int*)opt->param) = atoi(argv[i]);
    else if (opt->type == OPT_STR_LIST) {
      str_list_t *strl = opt->param;
      if (strl->num < strl->max)
        strl->str[strl->num++] = argv[i];
    }
    else
      *((char**)opt->param) = argv[i];

    /* Stop processing */
    if (opt_help)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL);
    if (opt_version)
      show_version(argv[0]);
  }

  /* Additional cmdline processing */
#if ENABLE_LINUXDVB
  if (!opt_dvb_adapters) {
    adapter_mask = ~0;
  } else {
    char *p, *e;
    char *r = NULL;
    char *dvb_adapters = strdup(opt_dvb_adapters);
    adapter_mask = 0x0;
    p = strtok_r(dvb_adapters, ",", &r);
    while (p) {
      int a = strtol(p, &e, 10);
      if (*e != 0 || a < 0 || a > 31) {
        tvhlog(LOG_ERR, "START", "Invalid adapter number '%s'", p);
        free(dvb_adapters);
        return 1;
      }
      adapter_mask |= (1 << a);
      p = strtok_r(NULL, ",", &r);
    }
    free(dvb_adapters);
    if (!adapter_mask) {
      tvhlog(LOG_ERR, "START", "No adapters specified!");
      return 1;
    }
  }
#endif
  if (tvheadend_webroot) {
    char *tmp;
    if (*tvheadend_webroot == '/')
      tmp = strdup(tvheadend_webroot);
    else {
      tmp = malloc(strlen(tvheadend_webroot)+2);
      *tmp = '/';
      strcpy(tmp+1, tvheadend_webroot);
    }
    if (tmp[strlen(tmp)-1] == '/')
      tmp[strlen(tmp)-1] = '\0';
    tvheadend_webroot = tmp;
  }
  tvheadend_webui_debug = opt_uidebug;

  /* Setup logging */
  if (isatty(2))
    log_options |= TVHLOG_OPT_DECORATE;
  if (opt_stderr || opt_syslog || opt_logpath) {
    if (!opt_log_trace && !opt_log_debug)
      log_debug      = "all";
    log_level      = LOG_DEBUG;
    if (opt_stderr)
      log_options   |= TVHLOG_OPT_DBG_STDERR;
    if (opt_syslog)
      log_options   |= TVHLOG_OPT_DBG_SYSLOG;
    if (opt_logpath)
      log_options   |= TVHLOG_OPT_DBG_FILE;
  }
  if (opt_fileline)
    log_options |= TVHLOG_OPT_FILELINE;
  if (opt_threadid)
    log_options |= TVHLOG_OPT_THREAD;
  if (opt_log_trace) {
    log_level  = LOG_TRACE;
    log_trace  = opt_log_trace;
  }
  if (opt_log_debug)
    log_debug  = opt_log_debug;
    
  tvhlog_init(log_level, log_options, opt_logpath);
  tvhlog_set_debug(log_debug);
  tvhlog_set_trace(log_trace);
 
  signal(SIGPIPE, handle_sigpipe); // will be redundant later

  /* Daemonise */
  if(opt_fork) {
    const char *homedir;
    gid_t gid;
    uid_t uid;
    struct group  *grp = getgrnam(opt_group ?: "video");
    struct passwd *pw  = opt_user ? getpwnam(opt_user) : NULL;
    FILE   *pidfile    = fopen(opt_pidpath, "w+");

    if(grp != NULL) {
      gid = grp->gr_gid;
    } else {
      gid = 1;
    }

    if (pw != NULL) {
      if (getuid() != pw->pw_uid) {
        gid_t glist[10];
        int gnum;
        gnum = get_user_groups(pw, glist, 10);
        if (setgroups(gnum, glist)) {
          tvhlog(LOG_ALERT, "START",
                 "setgroups() failed, do you have permission?");
          return 1;
        }
      }
      uid     = pw->pw_uid;
      homedir = pw->pw_dir;
      setenv("HOME", homedir, 1);
    } else {
      uid = 1;
    }
    if ((getgid() != gid) && setgid(gid)) {
      tvhlog(LOG_ALERT, "START",
             "setgid() failed, do you have permission?");
      return 1;
    }
    if ((getuid() != uid) && setuid(uid)) {
      tvhlog(LOG_ALERT, "START",
             "setuid() failed, do you have permission?");
      return 1;
    }

    if(daemon(0, 0)) {
      exit(2);
    }
    if(pidfile != NULL) {
      fprintf(pidfile, "%d\n", getpid());
      fclose(pidfile);
    }

    /* Make dumpable */
    if (opt_dump) {
#ifdef PLATFORM_LINUX
      if (chdir("/tmp"))
        tvhwarn("START", "failed to change cwd to /tmp");
      prctl(PR_SET_DUMPABLE, 1);
#else
      tvhwarn("START", "Coredumps not implemented on your platform");
#endif
    }

    umask(0);
  }

  tvheadend_running = 1;

  /* Start log thread (must be done post fork) */
  tvhlog_start();

  /* Alter logging */
  if (opt_fork)
    tvhlog_options &= ~TVHLOG_OPT_STDERR;
  if (!isatty(2))
    tvhlog_options &= ~TVHLOG_OPT_DECORATE;
  
  /* Initialise clock */
  pthread_mutex_lock(&global_lock);
  time(&dispatch_clock);

  /* Signal handling */
  sigfillset(&set);
  sigprocmask(SIG_BLOCK, &set, NULL);
  trap_init(argv[0]);
  
  /* Initialise configuration */
  uuid_init();
  idnode_init();
  config_init(opt_config);

  /**
   * Initialize subsystems
   */
  
  api_init();

  fsmonitor_init();

#if ENABLE_LIBAV
  libav_init();
  transcoding_init();
#endif

  imagecache_init();

  service_init();

#if ENABLE_TSFILE
  if(opt_tsfile.num) {
    tsfile_init(opt_tsfile_tuner ?: opt_tsfile.num);
    for (i = 0; i < opt_tsfile.num; i++)
      tsfile_add_file(opt_tsfile.str[i]);
  }
#endif
#if ENABLE_MPEGTS_DVB
  dvb_network_init();
#endif
#if ENABLE_IPTV
  iptv_init();
#endif
#if ENABLE_LINUXDVB
  linuxdvb_init(adapter_mask);
#endif

  channel_init();

  subscription_init();

  access_init(opt_firstrun, opt_noacl);

#if ENABLE_TIMESHIFT
  timeshift_init();
#endif

  http_client_init();
  tcp_server_init(opt_ipv6);
  http_server_init(opt_bindaddr);
  webui_init();

  service_mapper_init();

  descrambler_init();

  epggrab_init();
  epg_init();

  dvr_init();

  htsp_init(opt_bindaddr);


  if(opt_subscribe != NULL)
    subscription_dummy_join(opt_subscribe, 1);

  avahi_init();

  epg_updated(); // cleanup now all prev ref's should have been created

  pthread_mutex_unlock(&global_lock);

  /**
   * Wait for SIGTERM / SIGINT, but only in this thread
   */

  sigemptyset(&set);
  sigaddset(&set, SIGTERM);
  sigaddset(&set, SIGINT);

  signal(SIGTERM, doexit);
  signal(SIGINT, doexit);

  pthread_sigmask(SIG_UNBLOCK, &set, NULL);

  tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, "
         "running as PID:%d UID:%d GID:%d, CWD:%s CNF:%s",
         tvheadend_version,
         getpid(), getuid(), getgid(), getcwd(buf, sizeof(buf)),
         hts_settings_get_root());

  if(opt_abort)
    abort();

  mainloop();

  tvhftrace("main", htsp_done);
  tvhftrace("main", http_server_done);
  tvhftrace("main", webui_done);
  tvhftrace("main", http_client_done);
  tvhftrace("main", fsmonitor_done);
#if ENABLE_MPEGTS_DVB
  tvhftrace("main", dvb_network_done);
#endif
#if ENABLE_IPTV
  tvhftrace("main", iptv_done);
#endif
#if ENABLE_LINUXDVB
  tvhftrace("main", linuxdvb_done);
#endif
#if ENABLE_TSFILE
  tvhftrace("main", tsfile_done);
#endif

  // Note: the locking is obviously a bit redundant, but without
  //       we need to disable the gtimer_arm call in epg_save()
  pthread_mutex_lock(&global_lock);
  tvhftrace("main", epg_save);

#if ENABLE_TIMESHIFT
  tvhftrace("main", timeshift_term);
#endif
  pthread_mutex_unlock(&global_lock);

  tvhftrace("main", epggrab_done);
  tvhftrace("main", tcp_server_done);
  tvhftrace("main", descrambler_done);
  tvhftrace("main", service_mapper_done);
  tvhftrace("main", service_done);
  tvhftrace("main", channel_done);
  tvhftrace("main", dvr_done);
  tvhftrace("main", subscription_done);
  tvhftrace("main", access_done);
  tvhftrace("main", epg_done);
  tvhftrace("main", avahi_done);
  tvhftrace("main", imagecache_done);
  tvhftrace("main", idnode_done);
  tvhftrace("main", lang_code_done);
  tvhftrace("main", api_done);
  tvhftrace("main", config_done);
  tvhftrace("main", hts_settings_done);
  tvhftrace("main", dvb_done);
  tvhftrace("main", lang_str_done);

  tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");
  tvhlog_end();

  if(opt_fork)
    unlink(opt_pidpath);
    
  free(opt_tsfile.str);

  return 0;
}
示例#12
0
int
table_api_dispatch(void)
{
#if 0
	struct passwd	*pw;
#endif
	ssize_t		 n;

#if 0
	pw = getpwnam(user);
	if (pw == NULL) {
		log_warn("table-api: getpwnam");
		fatalx("table-api: exiting");
	}

	if (rootpath) {
		if (chroot(rootpath) == -1) {
			log_warn("table-api: chroot");
			fatalx("table-api: exiting");
		}
		if (chdir("/") == -1) {
			log_warn("table-api: chdir");
			fatalx("table-api: exiting");
		}
	}

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) {
		log_warn("table-api: cannot drop privileges");
		fatalx("table-api: exiting");
	}
#endif

	imsg_init(&ibuf, 0);

	while (1) {
		n = imsg_get(&ibuf, &imsg);
		if (n == -1) {
			log_warn("warn: table-api: imsg_get");
			break;
		}

		if (n) {
			rdata = imsg.data;
			rlen = imsg.hdr.len - IMSG_HEADER_SIZE;
			table_msg_dispatch();
			if (quit)
				break;
			imsg_flush(&ibuf);
			continue;
		}

		n = imsg_read(&ibuf);
		if (n == -1 && errno != EAGAIN) {
			log_warn("warn: table-api: imsg_read");
			break;
		}
		if (n == 0) {
			log_warnx("warn: table-api: pipe closed");
			break;
		}
	}

	return (1);
}
示例#13
0
文件: pony.c 项目: evadot/OpenSMTPD
pid_t
pony(void)
{
	pid_t		 pid;
	struct passwd	*pw;
	struct event	 ev_sigint;
	struct event	 ev_sigterm;

	switch (pid = fork()) {
	case -1:
		fatal("pony: cannot fork");
	case 0:
		post_fork(PROC_PONY);
		break;
	default:
		return (pid);
	}

	mda_postfork();
	mta_postfork();
	smtp_postfork();
	filter_postfork();

	/* do not purge listeners and pki, they are purged
	 * in smtp_configure()
	 */
	purge_config(PURGE_TABLES|PURGE_RULES);

	if ((pw = getpwnam(SMTPD_USER)) == NULL)
		fatalx("unknown user " SMTPD_USER);

	if (chroot(PATH_CHROOT) == -1)
		fatal("pony: chroot");
	if (chdir("/") == -1)
		fatal("pony: chdir(\"/\")");

	config_process(PROC_PONY);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("pony: cannot drop privileges");


	imsg_callback = pony_imsg;
	event_init();

	mda_postprivdrop();
	mta_postprivdrop();
	smtp_postprivdrop();

	signal_set(&ev_sigint, SIGINT, pony_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, pony_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	config_peer(PROC_PARENT);
	config_peer(PROC_QUEUE);
	config_peer(PROC_LKA);
	config_peer(PROC_CONTROL);
	config_peer(PROC_CA);
	config_done();

	ca_engine_init();

	if (event_dispatch() < 0)
		fatal("event_dispatch");
	pony_shutdown();

	return (0);
}
示例#14
0
int main(int argc, char **argv)
{
    enum {
        NNP = CHAR_MAX + 1,
        RUID,
        EUID,
        RGID,
        EGID,
        REUID,
        REGID,
        CLEAR_GROUPS,
        KEEP_GROUPS,
        GROUPS,
        INHCAPS,
        LISTCAPS,
        CAPBSET,
        SECUREBITS,
        SELINUX_LABEL,
        APPARMOR_PROFILE
    };

    static const struct option longopts[] = {
        {"dump", no_argument, 0, 'd'},
        {"nnp", no_argument, 0, NNP},
        {"no-new-privs", no_argument, 0, NNP},
        {"inh-caps", required_argument, 0, INHCAPS},
        {"list-caps", no_argument, 0, LISTCAPS},
        {"ruid", required_argument, 0, RUID},
        {"euid", required_argument, 0, EUID},
        {"rgid", required_argument, 0, RGID},
        {"egid", required_argument, 0, EGID},
        {"reuid", required_argument, 0, REUID},
        {"regid", required_argument, 0, REGID},
        {"clear-groups", no_argument, 0, CLEAR_GROUPS},
        {"keep-groups", no_argument, 0, KEEP_GROUPS},
        {"groups", required_argument, 0, GROUPS},
        {"bounding-set", required_argument, 0, CAPBSET},
        {"securebits", required_argument, 0, SECUREBITS},
        {"selinux-label", required_argument, 0, SELINUX_LABEL},
        {"apparmor-profile", required_argument, 0, APPARMOR_PROFILE},
        {"help", no_argument, 0, 'h'},
        {"version", no_argument, 0, 'V'},
        {NULL, 0, 0, 0}
    };

    static const ul_excl_t excl[] = {
        /* keep in same order with enum definitions */
        {CLEAR_GROUPS, KEEP_GROUPS, GROUPS},
        {0}
    };
    int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;

    int c;
    struct privctx opts;
    int dumplevel = 0;
    int total_opts = 0;
    int list_caps = 0;

    setlocale(LC_ALL, "");
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
    atexit(close_stdout);

    memset(&opts, 0, sizeof(opts));

    while ((c = getopt_long(argc, argv, "+dhV", longopts, NULL)) != -1) {
        err_exclusive_options(c, longopts, excl, excl_st);
        total_opts++;
        switch (c) {
        case 'd':
            dumplevel++;
            break;
        case NNP:
            if (opts.nnp)
                errx(EXIT_FAILURE,
                     _("duplicate --no-new-privs option"));
            opts.nnp = 1;
            break;
        case RUID:
            if (opts.have_ruid)
                errx(EXIT_FAILURE, _("duplicate ruid"));
            opts.have_ruid = 1;
            opts.ruid = get_user(optarg, _("failed to parse ruid"));
            break;
        case EUID:
            if (opts.have_euid)
                errx(EXIT_FAILURE, _("duplicate euid"));
            opts.have_euid = 1;
            opts.euid = get_user(optarg, _("failed to parse euid"));
            break;
        case REUID:
            if (opts.have_ruid || opts.have_euid)
                errx(EXIT_FAILURE, _("duplicate ruid or euid"));
            opts.have_ruid = opts.have_euid = 1;
            opts.ruid = opts.euid = get_user(optarg, _("failed to parse reuid"));
            break;
        case RGID:
            if (opts.have_rgid)
                errx(EXIT_FAILURE, _("duplicate rgid"));
            opts.have_rgid = 1;
            opts.rgid = get_group(optarg, _("failed to parse rgid"));
            break;
        case EGID:
            if (opts.have_egid)
                errx(EXIT_FAILURE, _("duplicate egid"));
            opts.have_egid = 1;
            opts.egid = get_group(optarg, _("failed to parse egid"));
            break;
        case REGID:
            if (opts.have_rgid || opts.have_egid)
                errx(EXIT_FAILURE, _("duplicate rgid or egid"));
            opts.have_rgid = opts.have_egid = 1;
            opts.rgid = opts.egid = get_group(optarg, _("failed to parse regid"));
            break;
        case CLEAR_GROUPS:
            if (opts.clear_groups)
                errx(EXIT_FAILURE,
                     _("duplicate --clear-groups option"));
            opts.clear_groups = 1;
            break;
        case KEEP_GROUPS:
            if (opts.keep_groups)
                errx(EXIT_FAILURE,
                     _("duplicate --keep-groups option"));
            opts.keep_groups = 1;
            break;
        case GROUPS:
            if (opts.have_groups)
                errx(EXIT_FAILURE,
                     _("duplicate --groups option"));
            parse_groups(&opts, optarg);
            break;
        case LISTCAPS:
            list_caps = 1;
            break;
        case INHCAPS:
            if (opts.caps_to_inherit)
                errx(EXIT_FAILURE,
                     _("duplicate --inh-caps option"));
            opts.caps_to_inherit = optarg;
            break;
        case CAPBSET:
            if (opts.bounding_set)
                errx(EXIT_FAILURE,
                     _("duplicate --bounding-set option"));
            opts.bounding_set = optarg;
            break;
        case SECUREBITS:
            if (opts.have_securebits)
                errx(EXIT_FAILURE,
                     _("duplicate --securebits option"));
            parse_securebits(&opts, optarg);
            break;
        case SELINUX_LABEL:
            if (opts.selinux_label)
                errx(EXIT_FAILURE,
                     _("duplicate --selinux-label option"));
            opts.selinux_label = optarg;
            break;
        case APPARMOR_PROFILE:
            if (opts.apparmor_profile)
                errx(EXIT_FAILURE,
                     _("duplicate --apparmor-profile option"));
            opts.apparmor_profile = optarg;
            break;
        case 'h':
            usage(stdout);
        case 'V':
            printf(UTIL_LINUX_VERSION);
            return EXIT_SUCCESS;
        case '?':
            usage(stderr);
        default:
            errx(EXIT_FAILURE, _("unrecognized option '%c'"), c);
        }
    }

    if (dumplevel) {
        if (total_opts != dumplevel || optind < argc)
            errx(EXIT_FAILURE,
                 _("--dump is incompatible with all other options"));
        dump(dumplevel);
        return EXIT_SUCCESS;
    }

    if (list_caps) {
        if (total_opts != 1 || optind < argc)
            errx(EXIT_FAILURE,
                 _("--list-caps must be specified alone"));
        list_known_caps();
        return EXIT_SUCCESS;
    }

    if (argc <= optind)
        errx(EXIT_FAILURE, _("No program specified"));

    if ((opts.have_rgid || opts.have_egid)
            && !opts.keep_groups && !opts.clear_groups && !opts.have_groups)
        errx(EXIT_FAILURE,
             _("--[re]gid requires --keep-groups, --clear-groups, or --groups"));

    if (opts.nnp)
        if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
            err(EXIT_FAILURE, _("disallow granting new privileges failed"));

    if (opts.selinux_label)
        do_selinux_label(opts.selinux_label);
    if (opts.apparmor_profile)
        do_apparmor_profile(opts.apparmor_profile);

    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
        err(EXIT_FAILURE, _("keep process capabilities failed"));

    /* We're going to want CAP_SETPCAP, CAP_SETUID, and CAP_SETGID if
     * possible.  */
    bump_cap(CAP_SETPCAP);
    bump_cap(CAP_SETUID);
    bump_cap(CAP_SETGID);
    if (capng_apply(CAPNG_SELECT_CAPS) != 0)
        err(SETPRIV_EXIT_PRIVERR, _("activate capabilities"));

    if (opts.have_ruid || opts.have_euid) {
        do_setresuid(&opts);
        /* KEEPCAPS doesn't work for the effective mask. */
        if (capng_apply(CAPNG_SELECT_CAPS) != 0)
            err(SETPRIV_EXIT_PRIVERR, _("reactivate capabilities"));
    }

    if (opts.have_rgid || opts.have_egid)
        do_setresgid(&opts);

    if (opts.have_groups) {
        if (setgroups(opts.num_groups, opts.groups) != 0)
            err(SETPRIV_EXIT_PRIVERR, _("setgroups failed"));
    } else if (opts.clear_groups) {
        gid_t x = 0;
        if (setgroups(0, &x) != 0)
            err(SETPRIV_EXIT_PRIVERR, _("setgroups failed"));
    }

    if (opts.have_securebits)
        if (prctl(PR_SET_SECUREBITS, opts.securebits, 0, 0, 0) != 0)
            err(SETPRIV_EXIT_PRIVERR, _("set process securebits failed"));

    if (opts.bounding_set) {
        do_caps(CAPNG_BOUNDING_SET, opts.bounding_set);
        errno = EPERM;	/* capng doesn't set errno if we're missing CAP_SETPCAP */
        if (capng_apply(CAPNG_SELECT_BOUNDS) != 0)
            err(SETPRIV_EXIT_PRIVERR, _("apply bounding set"));
    }

    if (opts.caps_to_inherit) {
        do_caps(CAPNG_INHERITABLE, opts.caps_to_inherit);
        if (capng_apply(CAPNG_SELECT_CAPS) != 0)
            err(SETPRIV_EXIT_PRIVERR, _("apply capabilities"));
    }

    execvp(argv[optind], argv + optind);

    err(EXIT_FAILURE, _("cannot execute: %s"), argv[optind]);
}
示例#15
0
static void f_create_process( INT32 args ) {
  struct perishables storage;
  struct array *cmd = 0;
  struct mapping *optional = 0;
  struct svalue *tmp;
  int e;
  int stds[3];
  int *fds;
  int num_fds = 3;
  int wanted_gid=0, wanted_uid=0;
  int gid_request=0, uid_request=0;
  char *tmp_cwd = NULL;
  pid_t pid=-2;

  extern char **environ;

  fds = stds;
  storage.env = NULL;
  storage.argv = NULL;
  storage.disabled = 0;
  storage.fds = NULL;
  storage.limits = NULL;

  check_all_args("create_process",args, BIT_ARRAY, BIT_MAPPING | BIT_VOID, 0);

  switch(args)
  {
    default:
      optional=Pike_sp[1-args].u.mapping;
      mapping_fix_type_field(optional);

      if(m_ind_types(optional) & ~BIT_STRING)
        Pike_error("Bad index type in argument 2 to Caudium.create_process()\n");

    case 1: cmd=Pike_sp[-args].u.array;
      if(cmd->size < 1)
        Pike_error("Too few elements in argument array.\n");

      for(e=0; e<cmd->size; e++)
        if(ITEM(cmd)[e].type!=T_STRING)
          Pike_error("Argument is not a string.\n");

      array_fix_type_field(cmd);

      if(cmd->type_field & ~BIT_STRING)
        Pike_error("Bad argument 1 to Caudium.create_process().\n");
  }

  if (optional) {

     if ((tmp = simple_mapping_string_lookup(optional, "gid"))) {
        switch(tmp->type)
	{
	  case T_INT:
	    wanted_gid = tmp->u.integer;
	    gid_request = 1;
	    break;

	  default:
	    Pike_error("Invalid argument for gid.");
	    break;
	}
     } 

     if ((tmp = simple_mapping_string_lookup(optional, "uid"))) {
        switch(tmp->type)
	{
	  case T_INT:
	    wanted_uid = tmp->u.integer;
	    uid_request = 1;
	    break;

	  default:
	    Pike_error("Invalid argument for uid.");
	    break;
	}
     } 

     if((tmp = simple_mapping_string_lookup( optional, "cwd" )) &&
	 tmp->type == T_STRING && !tmp->u.string->size_shift)
       tmp_cwd = tmp->u.string->str;

     if((tmp = simple_mapping_string_lookup( optional, "stdin" )) &&
         tmp->type == T_OBJECT)
     {
        fds[0] = fd_from_object( tmp->u.object );
        if(fds[0] == -1)
          Pike_error("Invalid stdin file\n");
     }

     if((tmp = simple_mapping_string_lookup( optional, "stdout" )) &&
         tmp->type == T_OBJECT)
     {
        fds[1] = fd_from_object( tmp->u.object );
        if(fds[1] == -1)
          Pike_error("Invalid stdout file\n");
     }

     if((tmp = simple_mapping_string_lookup( optional, "stderr" )) &&
         tmp->type == T_OBJECT)
     {
        fds[2] = fd_from_object( tmp->u.object );
        if(fds[2] == -1)
          Pike_error("Invalid stderr file\n");
     }

     if((tmp=simple_mapping_string_lookup(optional, "rlimit"))) {
        struct svalue *tmp2;
        if(tmp->type != T_MAPPING)
          Pike_error("Wrong type of argument for the 'rusage' option. "
		     "Should be mapping.\n");
#define ADD_LIMIT(X,Y,Z) internal_add_limit(&storage,X,Y,Z);
#ifdef RLIMIT_NPROC
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "nproc")))
        ADD_LIMIT( "nproc", RLIMIT_NPROC, tmp2 );
#endif        
#ifdef RLIMIT_MEMLOCK
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "memlock")))
        ADD_LIMIT( "memlock", RLIMIT_MEMLOCK, tmp2 );
#endif        
#ifdef RLIMIT_RSS
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "rss")))
        ADD_LIMIT( "rss", RLIMIT_RSS, tmp2 );
#endif        
#ifdef RLIMIT_CORE
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "core")))
        ADD_LIMIT( "core", RLIMIT_CORE, tmp2 );
#endif        
#ifdef RLIMIT_CPU
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "cpu")))
        ADD_LIMIT( "cpu", RLIMIT_CPU, tmp2 );
#endif        
#ifdef RLIMIT_DATA
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "data")))
        ADD_LIMIT( "data", RLIMIT_DATA, tmp2 );
#endif        
#ifdef RLIMIT_FSIZE
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "fsize")))
        ADD_LIMIT( "fsize", RLIMIT_FSIZE, tmp2 );
#endif        
#ifdef RLIMIT_NOFILE
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "nofile")))
        ADD_LIMIT( "nofile", RLIMIT_NOFILE, tmp2 );
#endif        
#ifdef RLIMIT_STACK
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "stack")))
        ADD_LIMIT( "stack", RLIMIT_STACK, tmp2 );
#endif        
#ifdef RLIMIT_VMEM
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "map_mem"))
         ||(tmp2=simple_mapping_string_lookup(tmp->u.mapping, "vmem")))
        ADD_LIMIT( "map_mem", RLIMIT_VMEM, tmp2 );
#endif        
#ifdef RLIMIT_AS
      if((tmp2=simple_mapping_string_lookup(tmp->u.mapping, "as"))
         ||(tmp2=simple_mapping_string_lookup(tmp->u.mapping, "mem")))
        ADD_LIMIT( "mem", RLIMIT_AS, tmp2 );
#endif
#undef ADD_LIMIT
     }
  }

  if((tmp=simple_mapping_string_lookup(optional, "env"))) {
    if(tmp->type == T_MAPPING) {
      struct mapping *m=tmp->u.mapping;
      struct array *i,*v;
      int ptr=0;
      i=mapping_indices(m);
      v=mapping_values(m);

      storage.env=(char **)xalloc((1+m_sizeof(m)) * sizeof(char *));
      for(e=0;e<i->size;e++)
      {
        if(ITEM(i)[e].type == T_STRING &&
           ITEM(v)[e].type == T_STRING)
        {
          check_stack(3);
          ref_push_string(ITEM(i)[e].u.string);
          push_string(make_shared_string("="));
          ref_push_string(ITEM(v)[e].u.string);
          f_add(3);
          storage.env[ptr++]=Pike_sp[-1].u.string->str;
        }
      }
      storage.env[ptr++]=0;
      free_array(i);
      free_array(v);
    }
  }

  storage.argv = (char **)xalloc((1 + cmd->size) * sizeof(char *));
  for (e = 0; e < cmd->size; e++) storage.argv[e] = ITEM(cmd)[e].u.string->str;
  storage.argv[e] = 0;
  
  th_atfork_prepare();
  
  pid = fork();

  if (pid) {
     th_atfork_parent();
  } else {
     th_atfork_child();
  }

  if (pid == -1) {
     Pike_error("Caudium.create_process() failed.");
  } else if (pid) {
    
    pop_n_elems(args);
    push_int(pid);
    return;

  } else {

    if(storage.limits) {
      struct plimit *l = storage.limits;
      while(l) {
        int tmpres = setrlimit( l->resource, &l->rlp );
        l = l->next;
      }
    }

    if(storage.env) environ = storage.env;

    chdir(tmp_cwd);

    seteuid(0);
    setegid(0);

    setgroups(0, NULL);

    if (gid_request) setgid(wanted_gid);
    if (uid_request) setuid(wanted_uid);
    
    dup2(fds[0], 0);
    dup2(fds[1], 1);
    dup2(fds[2], 2);
	  
    set_close_on_exec(0,0);
    set_close_on_exec(1,0);
    set_close_on_exec(2,0);

    execvp(storage.argv[0],storage.argv);

    exit(99);
  }

  pop_n_elems(args);
  push_int(0);
}
示例#16
0
文件: process.c 项目: kjthegod/node
static void uv__process_child_init(const uv_process_options_t* options,
                                   int stdio_count,
                                   int (*pipes)[2],
                                   int error_fd) {
  int close_fd;
  int use_fd;
  int fd;

  if (options->flags & UV_PROCESS_DETACHED)
    setsid();

  for (fd = 0; fd < stdio_count; fd++) {
    close_fd = pipes[fd][0];
    use_fd = pipes[fd][1];

    if (use_fd < 0) {
      if (fd >= 3)
        continue;
      else {
        /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
         * set
         */
        use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
        close_fd = use_fd;

        if (use_fd == -1) {
          uv__write_int(error_fd, -errno);
          _exit(127);
        }
      }
    }

    if (fd == use_fd)
      uv__cloexec(use_fd, 0);
    else
      dup2(use_fd, fd);

    if (fd <= 2)
      uv__nonblock(fd, 0);

    if (close_fd >= stdio_count)
      uv__close(close_fd);
  }

  for (fd = 0; fd < stdio_count; fd++) {
    use_fd = pipes[fd][1];

    if (use_fd >= 0 && fd != use_fd)
      close(use_fd);
  }

  if (options->cwd != NULL && chdir(options->cwd)) {
    uv__write_int(error_fd, -errno);
    _exit(127);
  }

  if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
    /* When dropping privileges from root, the `setgroups` call will
     * remove any extraneous groups. If we don't call this, then
     * even though our uid has dropped, we may still have groups
     * that enable us to do super-user things. This will fail if we
     * aren't root, so don't bother checking the return value, this
     * is just done as an optimistic privilege dropping function.
     */
    SAVE_ERRNO(setgroups(0, NULL));
  }

  if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
    uv__write_int(error_fd, -errno);
    _exit(127);
  }

  if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
    uv__write_int(error_fd, -errno);
    _exit(127);
  }

  if (options->env != NULL) {
    environ = options->env;
  }

  execvp(options->file, options->args);
  uv__write_int(error_fd, -errno);
  _exit(127);
}
示例#17
0
文件: attach.c 项目: LynxChaus/lxc
static int attach_child_main(void* data)
{
	struct attach_clone_payload* payload = (struct attach_clone_payload*)data;
	int ipc_socket = payload->ipc_socket;
	lxc_attach_options_t* options = payload->options;
	struct lxc_proc_context_info* init_ctx = payload->init_ctx;
#if HAVE_SYS_PERSONALITY_H
	long new_personality;
#endif
	int ret;
	int status;
	int expected;
	long flags;
	int fd;
	int lsm_labelfd;
	uid_t new_uid;
	gid_t new_gid;

	/* Wait for the initial thread to signal us that it's ready for us to
	 * start initializing.
	 */
	expected = 0;
	status = -1;
	ret = lxc_read_nointr_expect(ipc_socket, &status, sizeof(status), &expected);
	if (ret <= 0) {
		ERROR("Expected to receive sequence number 0: %s.", strerror(errno));
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	/* A description of the purpose of this functionality is provided in the
	 * lxc-attach(1) manual page. We have to remount here and not in the
	 * parent process, otherwise /proc may not properly reflect the new pid
	 * namespace.
	 */
	if (!(options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_REMOUNT_PROC_SYS)) {
		ret = lxc_attach_remount_sys_proc();
		if (ret < 0) {
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
	}

	/* Now perform additional attachments. */
#if HAVE_SYS_PERSONALITY_H
	if (options->personality < 0)
		new_personality = init_ctx->personality;
	else
		new_personality = options->personality;

	if (options->attach_flags & LXC_ATTACH_SET_PERSONALITY) {
		ret = personality(new_personality);
		if (ret < 0) {
			SYSERROR("Could not ensure correct architecture.");
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
	}
#endif

	if (options->attach_flags & LXC_ATTACH_DROP_CAPABILITIES) {
		ret = lxc_attach_drop_privs(init_ctx);
		if (ret < 0) {
			ERROR("Could not drop privileges.");
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
	}

	/* Always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL)
	 * if you want this to be a no-op).
	 */
	ret = lxc_attach_set_environment(options->env_policy, options->extra_env_vars, options->extra_keep_env);
	if (ret < 0) {
		ERROR("Could not set initial environment for attached process.");
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	/* Set {u,g}id. */
	new_uid = 0;
	new_gid = 0;
	/* Ignore errors, we will fall back to root in that case (/proc was not
	 * mounted etc.).
	 */
	if (options->namespaces & CLONE_NEWUSER)
		lxc_attach_get_init_uidgid(&new_uid, &new_gid);

	if (options->uid != (uid_t)-1)
		new_uid = options->uid;
	if (options->gid != (gid_t)-1)
		new_gid = options->gid;

	/* Setup the controlling tty. */
	if (options->stdin_fd && isatty(options->stdin_fd)) {
		if (setsid() < 0) {
			SYSERROR("Unable to setsid.");
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}

		if (ioctl(options->stdin_fd, TIOCSCTTY, (char *)NULL) < 0) {
			SYSERROR("Unable to set TIOCSTTY.");
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
	}

	/* Try to set the {u,g}id combination. */
	if ((new_gid != 0 || options->namespaces & CLONE_NEWUSER)) {
		if (setgid(new_gid) || setgroups(0, NULL)) {
			SYSERROR("Switching to container gid.");
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
	}
	if ((new_uid != 0 || options->namespaces & CLONE_NEWUSER) && setuid(new_uid)) {
		SYSERROR("Switching to container uid.");
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	/* Tell initial process it may now put us into cgroups. */
	status = 1;
	ret = lxc_write_nointr(ipc_socket, &status, sizeof(status));
	if (ret != sizeof(status)) {
		ERROR("Intended to send sequence number 1: %s.", strerror(errno));
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	/* Wait for the initial thread to signal us that it has done everything
	 * for us when it comes to cgroups etc.
	 */
	expected = 2;
	status = -1;
	ret = lxc_read_nointr_expect(ipc_socket, &status, sizeof(status), &expected);
	if (ret <= 0) {
		ERROR("Expected to receive sequence number 2: %s", strerror(errno));
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	if ((init_ctx->container && init_ctx->container->lxc_conf &&
	     init_ctx->container->lxc_conf->no_new_privs) ||
	    (options->attach_flags & LXC_ATTACH_NO_NEW_PRIVS)) {
		if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
			SYSERROR("PR_SET_NO_NEW_PRIVS could not be set. "
				 "Process can use execve() gainable "
				 "privileges.");
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
		INFO("PR_SET_NO_NEW_PRIVS is set. Process cannot use execve() "
		     "gainable privileges.");
	}

	/* Tell the (grand)parent to send us LSM label fd. */
	status = 3;
	ret = lxc_write_nointr(ipc_socket, &status, sizeof(status));
	if (ret <= 0) {
		ERROR("Intended to send sequence number 3: %s.", strerror(errno));
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
		int on_exec;
		/* Receive fd for LSM security module. */
		ret = lxc_abstract_unix_recv_fds(ipc_socket, &lsm_labelfd, 1, NULL, 0);
		if (ret <= 0) {
			ERROR("Expected to receive file descriptor: %s.", strerror(errno));
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}

		/* Change into our new LSM profile. */
		on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
		if (lsm_set_label_at(lsm_labelfd, on_exec, init_ctx->lsm_label) < 0) {
			SYSERROR("Failed to set LSM label.");
			shutdown(ipc_socket, SHUT_RDWR);
			close(lsm_labelfd);
			rexit(-1);
		}
		close(lsm_labelfd);
	}

	if (init_ctx->container && init_ctx->container->lxc_conf &&
	    init_ctx->container->lxc_conf->seccomp &&
	    (lxc_seccomp_load(init_ctx->container->lxc_conf) != 0)) {
		ERROR("Failed to load seccomp policy.");
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	shutdown(ipc_socket, SHUT_RDWR);
	close(ipc_socket);
	lxc_proc_put_context_info(init_ctx);

	/* The following is done after the communication socket is shut down.
	 * That way, all errors that might (though unlikely) occur up until this
	 * point will have their messages printed to the original stderr (if
	 * logging is so configured) and not the fd the user supplied, if any.
	 */

	/* Fd handling for stdin, stdout and stderr; ignore errors here, user
	 * may want to make sure the fds are closed, for example.
	 */
	if (options->stdin_fd >= 0 && options->stdin_fd != 0)
		dup2(options->stdin_fd, 0);
	if (options->stdout_fd >= 0 && options->stdout_fd != 1)
		dup2(options->stdout_fd, 1);
	if (options->stderr_fd >= 0 && options->stderr_fd != 2)
		dup2(options->stderr_fd, 2);

	/* close the old fds */
	if (options->stdin_fd > 2)
		close(options->stdin_fd);
	if (options->stdout_fd > 2)
		close(options->stdout_fd);
	if (options->stderr_fd > 2)
		close(options->stderr_fd);

	/* Try to remove FD_CLOEXEC flag from stdin/stdout/stderr, but also
	 * here, ignore errors.
	 */
	for (fd = 0; fd <= 2; fd++) {
		flags = fcntl(fd, F_GETFL);
		if (flags < 0)
			continue;
		if (flags & FD_CLOEXEC)
			if (fcntl(fd, F_SETFL, flags & ~FD_CLOEXEC) < 0)
				SYSERROR("Unable to clear FD_CLOEXEC from file descriptor.");
	}

	/* We're done, so we can now do whatever the user intended us to do. */
	rexit(payload->exec_function(payload->exec_payload));
}
static int process_security_set_cap(request_rec *r)
{

    int ncap;
    cap_t cap;
    cap_value_t capval[3];
    gid_t gid;
    uid_t uid;

    ncap = 2;

    process_security_dir_config_t *dconf = ap_get_module_config(r->per_dir_config, &process_security_module);
    process_security_config_t *conf = ap_get_module_config(r->server->module_config, &process_security_module);

    if (dconf->process_security_mode==PS_MODE_STAT || dconf->process_security_mode==PS_MODE_UNDEFINED) {
        gid = r->finfo.group;
        uid = r->finfo.user;
    } else {
        gid = conf->default_gid;
        uid = conf->default_uid;
    }

    cap       = cap_init();
    capval[0] = CAP_SETUID;
    capval[1] = CAP_SETGID;
    cap_set_flag(cap, CAP_PERMITTED, ncap, capval, CAP_SET);

    if (cap_set_proc(cap) != 0)
        ap_log_error(APLOG_MARK
            , APLOG_ERR
            , 0
            , NULL
            , "%s ERROR %s:cap_set_proc failed"
            , MODULE_NAME
            , __func__
        );

    cap_free(cap);
    coredump = prctl(PR_GET_DUMPABLE);

    cap = cap_get_proc();
    cap_set_flag(cap, CAP_EFFECTIVE, ncap, capval, CAP_SET);

    if (cap_set_proc(cap) != 0)
        ap_log_error (APLOG_MARK
            , APLOG_ERR
            , 0
            , NULL
            , "%s ERROR %s:cap_set_proc failed before setuid"
            , MODULE_NAME
            , __func__
        );

    cap_free(cap);

    setgroups(0, NULL);
    setgid(gid);
    setuid(uid);

    cap = cap_get_proc();
    cap_set_flag(cap, CAP_EFFECTIVE, ncap, capval, CAP_CLEAR);
    cap_set_flag(cap, CAP_PERMITTED, ncap, capval, CAP_CLEAR);
    if (cap_set_proc(cap) != 0) {
        ap_log_error (APLOG_MARK
            , APLOG_ERR
            , 0
            , NULL
            , "%s ERROR %s:cap_set_proc failed after setuid"
            , MODULE_NAME
            , __func__
        );
    }
    cap_free(cap);

    if (coredump)
        prctl(PR_SET_DUMPABLE, 1);

    return OK;

}
示例#19
0
int main(int argc, char **argv) {
    char *my_socket, *pt;
    const struct optstruct *opt;
    struct optstruct *opts;
    time_t currtime;
    int ret;

    memset(&descr, 0, sizeof(struct smfiDesc));
    descr.xxfi_name = "ClamAV";			/* filter name */
    descr.xxfi_version = SMFI_VERSION;		/* milter version */
    descr.xxfi_flags = SMFIF_QUARANTINE;	/* flags */
    descr.xxfi_connect = clamfi_connect;	/* connection info filter */
    descr.xxfi_envfrom = clamfi_envfrom;	/* envelope sender filter */
    descr.xxfi_envrcpt = clamfi_envrcpt;	/* envelope recipient filter */
    descr.xxfi_header = clamfi_header;		/* header filter */
    descr.xxfi_body = clamfi_body;		/* body block */
    descr.xxfi_eom = clamfi_eom;		/* end of message */
    descr.xxfi_abort = clamfi_abort;		/* message aborted */

    opts = optparse(NULL, argc, argv, 1, OPT_MILTER, 0, NULL);
    if (!opts) {
	mprintf("!Can't parse command line options\n");
	return 1;
    }

    if(optget(opts, "help")->enabled) {
	printf("Usage: %s [-c <config-file>]\n\n", argv[0]);
	printf("    --help                   -h       Show this help\n");
	printf("    --version                -V       Show version and exit\n");
	printf("    --config-file <file>     -c       Read configuration from file\n\n");
	optfree(opts);
	return 0;
    }

    if(opts->filename) {
	int x;
	for(x = 0; opts->filename[x]; x++)
	    mprintf("^Ignoring option %s\n", opts->filename[x]);
    }

    if(optget(opts, "version")->enabled) {
	printf("clamav-milter %s\n", get_version());
	optfree(opts);
	return 0;
    }

    pt = strdup(optget(opts, "config-file")->strarg);
    if((opts = optparse(pt, 0, NULL, 1, OPT_MILTER, 0, opts)) == NULL) {
	printf("%s: cannot parse config file %s\n", argv[0], pt);
	free(pt);
	return 1;
    }
    free(pt);

    if((opt = optget(opts, "Chroot"))->enabled) {
	if(chdir(opt->strarg) != 0) {
	    logg("!Cannot change directory to %s\n", opt->strarg);
	    return 1;
	}
	if(chroot(opt->strarg) != 0) {
	    logg("!chroot to %s failed. Are you root?\n", opt->strarg);
	    return 1;
	}
    }

    if(geteuid() == 0 && (opt = optget(opts, "User"))->enabled) {
        struct passwd *user = NULL;
	if((user = getpwnam(opt->strarg)) == NULL) {
	    fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg);
	    optfree(opts);
	    return 1;
	}

	if(optget(opts, "AllowSupplementaryGroups")->enabled) {
#ifdef HAVE_INITGROUPS
	    if(initgroups(opt->strarg, user->pw_gid)) {
		fprintf(stderr, "ERROR: initgroups() failed.\n");
		optfree(opts);
		return 1;
	    }
#else
	    mprintf("!AllowSupplementaryGroups: initgroups() is not available, please disable AllowSupplementaryGroups\n");
	    optfree(opts);
	    return 1;
#endif
	} else {
#ifdef HAVE_SETGROUPS
	    if(setgroups(1, &user->pw_gid)) {
		fprintf(stderr, "ERROR: setgroups() failed.\n");
		optfree(opts);
		return 1;
	    }
#endif
	}

	if(setgid(user->pw_gid)) {
	    fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid);
	    optfree(opts);
	    return 1;
	}

	if(setuid(user->pw_uid)) {
	    fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid);
	    optfree(opts);
	    return 1;
	}
    }

    logg_lock = !optget(opts, "LogFileUnlock")->enabled;
    logg_time = optget(opts, "LogTime")->enabled;
    logg_size = optget(opts, "LogFileMaxSize")->numarg;
    logg_verbose = mprintf_verbose = optget(opts, "LogVerbose")->enabled;

    if((opt = optget(opts, "LogFile"))->enabled) {
	logg_file = opt->strarg;
	if(strlen(logg_file) < 2 || logg_file[0] != '/') {
	    fprintf(stderr, "ERROR: LogFile requires full path.\n");
	    logg_close();
	    optfree(opts);
	    return 1;
	}
    } else
	logg_file = NULL;

#if defined(USE_SYSLOG) && !defined(C_AIX)
    if(optget(opts, "LogSyslog")->enabled) {
	int fac;

	opt = optget(opts, "LogFacility");
	if((fac = logg_facility(opt->strarg)) == -1) {
	    logg("!LogFacility: %s: No such facility.\n", opt->strarg);
	    logg_close();
	    optfree(opts);
	    return 1;
	}

	openlog("clamav-milter", LOG_PID, fac);
	logg_syslog = 1;
    }
#endif

    time(&currtime);
    if(logg("#+++ Started at %s", ctime(&currtime))) {
	fprintf(stderr, "ERROR: Can't initialize the internal logger\n");
	logg_close();
	optfree(opts);
	return 1;
    }
    if((opt = optget(opts, "TemporaryDirectory"))->enabled)
	tempdir = opt->strarg;

    if(localnets_init(opts) || init_actions(opts)) {
	logg_close();
	optfree(opts);
	return 1;
    }

    if((opt = optget(opts, "Whitelist"))->enabled && whitelist_init(opt->strarg)) {
	localnets_free();
	logg_close();
	optfree(opts);
	return 1;
    }

    if((opt = optget(opts, "SkipAuthenticated"))->enabled && smtpauth_init(opt->strarg)) {
	localnets_free();
	whitelist_free();
	logg_close();
	optfree(opts);
	return 1;
    }

    pt = optget(opts, "AddHeader")->strarg;
    if(strcasecmp(pt, "No")) {
	char myname[255];

	if(!gethostname(myname, sizeof(myname))) {
	    myname[sizeof(myname)-1] = '\0';
	    snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s at %s", get_version(), myname);
	    xvirushdr[sizeof(xvirushdr)-1] = '\0';
	} else {
	    snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s", get_version());
	    xvirushdr[sizeof(xvirushdr)-1] = '\0';
	}

	descr.xxfi_flags |= SMFIF_ADDHDRS;

	if(strcasecmp(pt, "Add")) { /* Replace or Yes */
	    descr.xxfi_flags |= SMFIF_CHGHDRS;
	    addxvirus = 1;
	} else { /* Add */
	    addxvirus = 2;
	}
    }
    
    if(!(my_socket = optget(opts, "MilterSocket")->strarg)) {
	logg("!Please configure the MilterSocket directive\n");
	localnets_free();
	whitelist_free();
	logg_close();
	optfree(opts);
	return 1;
    }

    if(!optget(opts, "Foreground")->enabled) {
	if(daemonize() == -1) {
	    logg("!daemonize() failed\n");
	    localnets_free();
	    whitelist_free();
	    cpool_free();
	    logg_close();
	    optfree(opts);
	    return 1;
	}
	if(chdir("/") == -1)
	    logg("^Can't change current working directory to root\n");
    }

    if(smfi_setconn(my_socket) == MI_FAILURE) {
	logg("!smfi_setconn failed\n");
	localnets_free();
	whitelist_free();
	logg_close();
	optfree(opts);
	return 1;
    }
    if(smfi_register(descr) == MI_FAILURE) {
	logg("!smfi_register failed\n");
	localnets_free();
	whitelist_free();
	logg_close();
	optfree(opts);
	return 1;
    }
    opt = optget(opts, "FixStaleSocket");
    if(smfi_opensocket(opt->enabled) == MI_FAILURE) {
	logg("!Failed to create socket %s\n", my_socket);
	localnets_free();
	whitelist_free();
	logg_close();
	optfree(opts);
	return 1;
    }

    maxfilesize = optget(opts, "MaxFileSize")->numarg;
    readtimeout = optget(opts, "ReadTimeout")->numarg;

    cpool_init(opts);
    if (!cp) {
	logg("!Failed to init the socket pool\n");
	localnets_free();
	whitelist_free();
	logg_close();
	optfree(opts);
	return 1;
    }	

    if((opt = optget(opts, "PidFile"))->enabled) {
	FILE *fd;
	mode_t old_umask = umask(0006);

	if((fd = fopen(opt->strarg, "w")) == NULL) {
	    logg("!Can't save PID in file %s\n", opt->strarg);
	} else {
	    if (fprintf(fd, "%u", (unsigned int)getpid())<0) {
	    	logg("!Can't save PID in file %s\n", opt->strarg);
	    }
	    fclose(fd);
	}
	umask(old_umask);
    }

    ret = smfi_main();

    optfree(opts);

    logg_close();
    cpool_free();
    localnets_free();
    whitelist_free();

    return ret;
}
示例#20
0
文件: suexec.c 项目: vnaybhat/emulab
int main(int argc, char *argv[])
{
    int userdir = 0;		/* ~userdir flag             */
    uid_t uid;			/* user information          */
    gid_t gid, primary_gid;	/* target group placeholder  */
    char *target_uname;		/* target user name          */
    char *target_gname;		/* target group name         */
    char *target_homedir;	/* target home directory     */
    char *actual_uname;		/* actual user name          */
    char *actual_gname;		/* actual group name         */
    char *prog;			/* name of this program      */
    char *cmd;			/* command to be executed    */
    char cwd[AP_MAXPATH];	/* current working directory */
    char dwd[AP_MAXPATH];	/* docroot working directory */
#ifdef TESTBED
    char cmdpath[AP_MAXPATH];	/* full path to command      */
    int  grouplist[NGROUPS], ngroups = 0;
#endif
    struct passwd *pw;		/* password entry holder     */
    struct group *gr;		/* group entry holder        */
    struct stat dir_info;	/* directory info holder     */
    struct stat prg_info;	/* program info holder       */

#ifdef TESTBED
    /*
     * For the Testbed, we run this from php3, and it loses all
     * outout sent to stderr, so make sure it all goes to stdout.
     */
    dup2(1, 2);
    {
	    int i, max;

	    /*
	     * Close all other descriptors. I think this is the wrong
	     * place for this since a program can be run from the web
	     * server without going through suexec!
	     */
	    max = getdtablesize();
	    for (i = 3; i < max; i++)
		    (void) close(i); 
    }
#endif

    /*
     * If there are a proper number of arguments, set
     * all of them to variables.  Otherwise, error out.
     */
    prog = argv[0];
    if (argc < 4) {
	log_err("alert: too few arguments\n");
	exit(101);
    }
    target_uname = argv[1];
    target_gname = argv[2];
    cmd = argv[3];

    /*
     * Check existence/validity of the UID of the user
     * running this program.  Error out if invalid.
     */
    uid = getuid();
    if ((pw = getpwuid(uid)) == NULL) {
	log_err("crit: invalid uid: (%ld)\n", uid);
	exit(102);
    }

    /*
     * Check to see if the user running this program
     * is the user allowed to do so as defined in
     * suexec.h.  If not the allowed user, error out.
     */
#ifdef _OSD_POSIX
    /* User name comparisons are case insensitive on BS2000/OSD */
    if (strcasecmp(HTTPD_USER, pw->pw_name)) {
        log_err("crit: calling user mismatch (%s instead of %s)\n",
		pw->pw_name, HTTPD_USER);
	exit(103);
    }
#else  /* _OSD_POSIX */
    if (strcmp(HTTPD_USER, pw->pw_name)) {
        log_err("crit: calling user mismatch (%s instead of %s)\n",
		pw->pw_name, HTTPD_USER);
	exit(103);
    }
#endif /* _OSD_POSIX */

    /*
     * Check for a leading '/' (absolute path) in the command to be executed,
     * or attempts to back up out of the current directory,
     * to protect against attacks.  If any are
     * found, error out.  Naughty naughty crackers.
     */
    if ((cmd[0] == '/') || (!strncmp(cmd, "../", 3))
	|| (strstr(cmd, "/../") != NULL)) {
        log_err("error: invalid command (%s)\n", cmd);
	exit(104);
    }

#ifndef TESTBED
    /*
     * Check to see if this is a ~userdir request.  If
     * so, set the flag, and remove the '~' from the
     * target username.
     */
    if (!strncmp("~", target_uname, 1)) {
	target_uname++;
	userdir = 1;
    }
#endif

    /*
     * Error out if the target username is invalid.
     */
    if ((pw = getpwnam(target_uname)) == NULL) {
	log_err("crit: invalid target user name: (%s)\n", target_uname);
	exit(105);
    }

#ifdef TESTBED
    {
	char *cp, *bp, *rname, *temp_gname = strdup(target_gname);
	gid_t rgid;
	int i;

	actual_gname = NULL;
	bp = temp_gname;
	while ((bp = strsep(&temp_gname, ",")) != NULL) {
	    if (!*bp)
		continue;
	    
	    /*
	     * Error out if the target group name is invalid.
	     */
	    if (strspn(bp, "1234567890") != strlen(bp)) {
		if ((gr = getgrnam(bp)) == NULL) {
		    log_err("crit: invalid target group name: (%s)\n", bp);
		    exit(106);
		}
		rgid  = gr->gr_gid;
		rname = gr->gr_name;
	    }
	    else {
		rgid  = atoi(bp);
		rname = bp;
	    }
	    /* Watch for duplicates */
	    for (i = 0; i < ngroups; i++) {
		if (grouplist[i] == rgid)
		    goto skip;
	    }
	    
	    grouplist[ngroups++] = rgid;

	    /*
	     * Error out if attempt is made to execute as root group
	     * or as a GID less than GID_MIN.  Tsk tsk.
	     */
	    if ((rgid == 0) || (rgid < GID_MIN)) {
	         log_err("crit: cannot run as forbidden gid (%d/%s)\n",
			 gid, cmd);
		 exit(108);
	    }

	    /* see below; need room for primary group in first two slots */
	    if (ngroups >= (NGROUPS - 2)) {
		log_err("crit: Too many groups: (%s)\n", bp);
		exit(106);
	    }

	    if (actual_gname) {
		cp = (char *) malloc(strlen(actual_gname) + strlen(rname) + 2);
		strcpy(cp, actual_gname);
		strcat(cp, ",");
		strcat(cp, rname);
		free(actual_gname);
		actual_gname = cp;
	    }
	    else {
		actual_gname = strdup(rname);
	    }
	skip:
	    ;
	}
    }
#else
    /*
     * Error out if the target group name is invalid.
     */
    if (strspn(target_gname, "1234567890") != strlen(target_gname)) {
	if ((gr = getgrnam(target_gname)) == NULL) {
	    log_err("crit: invalid target group name: (%s)\n", target_gname);
	    exit(106);
	}
	gid = gr->gr_gid;
	actual_gname = strdup(gr->gr_name);
    }
    else {
	gid = atoi(target_gname);
	actual_gname = strdup(target_gname);
    }
#endif

#ifdef _OSD_POSIX
    /*
     * Initialize BS2000 user environment
     */
    {
	pid_t pid;
	int status;

	switch (pid = ufork(target_uname))
	{
	case -1:	/* Error */
	    log_err("emerg: failed to setup bs2000 environment for user "
		    "%s: %s\n",
		    target_uname, strerror(errno));
	    exit(150);
	case 0:	/* Child */
	    break;
	default:	/* Father */
	    while (pid != waitpid(pid, &status, 0))
		;
	    /* @@@ FIXME: should we deal with STOP signals as well? */
	    if (WIFSIGNALED(status)) {
		kill (getpid(), WTERMSIG(status));
	    }
	    exit(WEXITSTATUS(status));
	}
    }
#endif /* _OSD_POSIX */

    /*
     * Save these for later since initgroups will hose the struct
     */
    uid = pw->pw_uid;
    primary_gid  = pw->pw_gid;
    actual_uname = strdup(pw->pw_name);
    target_homedir = strdup(pw->pw_dir);

    /*
     * Log the transaction here to be sure we have an open log 
     * before we setuid().
     */
    {
        char argbuf[2*BUFSIZ], *bp = argbuf;
	int i, size = sizeof(argbuf) - 1;

	*bp = '\0';

	for (i = 4; i < argc; i++) {
	    int count = snprintf(bp, size, "%s ", argv[i]);

	    if (count >= size)
	        break;
	    
	    size -= count;
	    bp   += count;
	}
    
	log_err("info: (target/actual) uid: (%s/%s) gid: (%s/%s) cmd: %s %s\n",
		target_uname, actual_uname,
		target_gname, actual_gname,
		cmd, argbuf);
    }

    /*
     * Error out if attempt is made to execute as root or as
     * a UID less than UID_MIN.  Tsk tsk.
     */
    if ((uid == 0) || (uid < UID_MIN)) {
	log_err("crit: cannot run as forbidden uid (%d/%s)\n", uid, cmd);
	exit(107);
    }

#ifdef TESTBED
    {
	gid_t groups[NGROUPS];
	int i, idx = 0;

	groups[idx++] = primary_gid;
	/* duplicate has something to do with effective gid */
	groups[idx++] = primary_gid;

	/* Move over the grouplist from above. */
	for (i = 0; i < ngroups; i++) {
 	    if (grouplist[i] != primary_gid)
	        groups[idx++] = grouplist[i];
	}
	
	if (setgid(primary_gid) != 0) {
	    log_err("emerg: failed to setgid (%ld: %s)\n", primary_gid, cmd);
	    exit(109);
	}
	if (setgroups(idx, groups) != 0) {
	    log_err("emerg: failed to setgroups (%s: %s)\n", actual_gname,cmd);
	    exit(109);
	}
    }
#else
    /*
     * Error out if attempt is made to execute as root group
     * or as a GID less than GID_MIN.  Tsk tsk.
     */
    if ((gid == 0) || (gid < GID_MIN)) {
	log_err("crit: cannot run as forbidden gid (%d/%s)\n", gid, cmd);
	exit(108);
    }

    /*
     * Change UID/GID here so that the following tests work over NFS.
     *
     * Initialize the group access list for the target user,
     * and setgid() to the target group. If unsuccessful, error out.
     */
    if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 0)) {
	log_err("emerg: failed to setgid (%ld: %s)\n", gid, cmd);
	exit(109);
    }
#endif

    /*
     * setuid() to the target user.  Error out on fail.
     */
    if ((setuid(uid)) != 0) {
	log_err("emerg: failed to setuid (%ld: %s)\n", uid, cmd);
	exit(110);
    }

#ifdef TESTBED
    /*
     * All programs exist in the testbed bin directory, and we won't be
     * running those programs from that directory (cwd will not be the
     * bin directory, but rather someplace else). So, fake things
     * up so the rest of this code works okay.
     */
    strcpy(cwd, DOC_ROOT);
    strcpy(cmdpath, DOC_ROOT);
    strcat(cmdpath, cmd);
    cmd = cmdpath;
#else
    /*
     * Get the current working directory, as well as the proper
     * document root (dependant upon whether or not it is a
     * ~userdir request).  Error out if we cannot get either one,
     * or if the current working directory is not in the docroot.
     * Use chdir()s and getcwd()s to avoid problems with symlinked
     * directories.  Yuck.
     */
    if (getcwd(cwd, AP_MAXPATH) == NULL) {
	log_err("emerg: cannot get current working directory\n");
	exit(111);
    }

    if (userdir) {
	if (((chdir(target_homedir)) != 0) ||
	    ((chdir(USERDIR_SUFFIX)) != 0) ||
	    ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
	    ((chdir(cwd)) != 0)) {
	    log_err("emerg: cannot get docroot information (%s)\n",
		    target_homedir);
	    exit(112);
	}
    }
    else {
	if (((chdir(DOC_ROOT)) != 0) ||
	    ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
	    ((chdir(cwd)) != 0)) {
	    log_err("emerg: cannot get docroot information (%s)\n", DOC_ROOT);
	    exit(113);
	}
    }

    if ((strncmp(cwd, dwd, strlen(dwd))) != 0) {
	log_err("error: command not in docroot (%s/%s)\n", cwd, cmd);
	exit(114);
    }
#endif

    /*
     * Stat the cwd and verify it is a directory, or error out.
     */
    if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) {
	log_err("error: cannot stat directory: (%s)\n", cwd);
	exit(115);
    }

    /*
     * Error out if cwd is writable by others.
     */
#ifdef TESTBED
    if (dir_info.st_mode & S_IWOTH) {
#else
    if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
#endif
	log_err("error: directory is writable by group or other: (%s)\n", cwd);
	exit(116);
    }

    /*
     * Error out if we cannot stat the program.
     */
    if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
	log_err("error: cannot stat program: (%s)\n", cmd);
	exit(117);
    }

    /*
     * Error out if the program is writable by others.
     */
    if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
	log_err("error: file is writable by group or other: (%s/%s)\n", cwd, cmd);
	exit(118);
    }

#ifndef TESTBED
    /*
     * Error out if the file is setuid or setgid.
     */
    if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & S_ISGID)) {
	log_err("error: file is either setuid or setgid: (%s/%s)\n", cwd, cmd);
	exit(119);
    }

    /*
     * Error out if the target name/group is different from
     * the name/group of the cwd or the program.
     */
    if ((uid != dir_info.st_uid) ||
	(gid != dir_info.st_gid) ||
	(uid != prg_info.st_uid) ||
	(gid != prg_info.st_gid)) {
	log_err("error: target uid/gid (%ld/%ld) mismatch "
		"with directory (%ld/%ld) or program (%ld/%ld)\n",
		uid, gid,
		dir_info.st_uid, dir_info.st_gid,
		prg_info.st_uid, prg_info.st_gid);
	exit(120);
    }
#endif
    /*
     * Error out if the program is not executable for the user.
     * Otherwise, she won't find any error in the logs except for
     * "[error] Premature end of script headers: ..."
     */
    if (!(prg_info.st_mode & S_IXUSR)) {
	log_err("error: file has no execute permission: (%s/%s)\n", cwd, cmd);
	exit(121);
    }

#ifdef SUEXEC_UMASK
    /*
     * umask() uses inverse logic; bits are CLEAR for allowed access.
     */
    if ((~SUEXEC_UMASK) & 0022) {
	log_err("notice: SUEXEC_UMASK of %03o allows "
		"write permission to group and/or other\n", SUEXEC_UMASK);
    }
    umask(SUEXEC_UMASK);
#endif /* SUEXEC_UMASK */
    clean_env();

    /* 
     * Be sure to close the log file so the CGI can't
     * mess with it.  If the exec fails, it will be reopened 
     * automatically when log_err is called.  Note that the log
     * might not actually be open if LOG_EXEC isn't defined.
     * However, the "log" cell isn't ifdef'd so let's be defensive
     * and assume someone might have done something with it
     * outside an ifdef'd LOG_EXEC block.
     */
    if (log != NULL) {
	fclose(log);
	log = NULL;
    }

    /*
     * Execute the command, replacing our image with its own.
     */
#ifdef NEED_HASHBANG_EMUL
    /* We need the #! emulation when we want to execute scripts */
    {
	extern char **environ;

	ap_execve(cmd, &argv[3], environ);
    }
#else /*NEED_HASHBANG_EMUL*/
    execv(cmd, &argv[3]);
#endif /*NEED_HASHBANG_EMUL*/

    /*
     * (I can't help myself...sorry.)
     *
     * Uh oh.  Still here.  Where's the kaboom?  There was supposed to be an
     * EARTH-shattering kaboom!
     *
     * Oh well, log the failure and error out.
     */
    log_err("emerg: (%d)%s: exec failed (%s)\n", errno, strerror(errno), cmd);
    exit(255);
}
示例#21
0
文件: spawn-fcgi.c 项目: UIKit0/ylem
int main(int argc, char **argv) {
	char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
               *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
                *addr = NULL;
	char **fcgi_app_argv = { NULL };
	unsigned short port = 0;
	int child_count = 5;
	int i_am_root, o;
	int pid_fd = -1;
	int nofork = 0;
	struct sockaddr_un un;
	const size_t sun_path_len = sizeof(un.sun_path);

	i_am_root = (getuid() == 0);

	while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
		switch(o) {
		case 'f': fcgi_app = optarg; break;
		case 'a': addr = optarg;/* ip addr */ break;
		case 'p': port = strtol(optarg, NULL, 10);/* port */ break;
		case 'C': child_count = strtol(optarg, NULL, 10);/*  */ break;
		case 's': unixsocket = optarg; /* unix-domain socket */ break;
		case 'c': if (i_am_root) { changeroot = optarg; }/* chroot() */ break;
		case 'u': if (i_am_root) { username = optarg; } /* set user */ break;
		case 'g': if (i_am_root) { groupname = optarg; } /* set group */ break;
		case 'n': nofork = 1; break;
		case 'P': pid_file = optarg; /* PID file */ break;
		case 'v': show_version(); return 0;
		case 'h': show_help(); return 0;
		default:
			show_help();
			return -1;
		}
	}

	if (optind < argc) {
		fcgi_app_argv = &argv[optind];
	}

	if ((fcgi_app == NULL && fcgi_app_argv == NULL) || (port == 0 && unixsocket == NULL)) {
		show_help();
		return -1;
	}

	if (unixsocket && port) {
		fprintf(stderr, "%s.%d: %s\n",
			__FILE__, __LINE__,
			"either a unix domain socket or a tcp-port, but not both\n");

		return -1;
	}

	if (unixsocket && strlen(unixsocket) > sun_path_len - 1) {
		fprintf(stderr, "%s.%d: %s\n",
			__FILE__, __LINE__,
			"path of the unix socket is too long\n");

		return -1;
	}

	/* UID handling */
	if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
		/* we are setuid-root */

		fprintf(stderr, "%s.%d: %s\n",
			__FILE__, __LINE__,
			"Are you nuts ? Don't apply a SUID bit to this binary\n");

		return -1;
	}

	if (pid_file &&
	    (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
		struct stat st;
		if (errno != EEXIST) {
			fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
				__FILE__, __LINE__,
				pid_file, strerror(errno));

			return -1;
		}

		/* ok, file exists */

		if (0 != stat(pid_file, &st)) {
			fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
				__FILE__, __LINE__,
				pid_file, strerror(errno));

			return -1;
		}

		/* is it a regular file ? */

		if (!S_ISREG(st.st_mode)) {
			fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
				__FILE__, __LINE__,
				pid_file);

			return -1;
		}

		if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
			fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
				__FILE__, __LINE__,
				pid_file, strerror(errno));

			return -1;
		}
	}

	if (i_am_root) {
		struct group *grp = NULL;
		struct passwd *pwd = NULL;

		/* set user and group */

		if (username) {
			if (NULL == (pwd = getpwnam(username))) {
				fprintf(stderr, "%s.%d: %s, %s\n",
					__FILE__, __LINE__,
					"can't find username", username);
				return -1;
			}

			if (pwd->pw_uid == 0) {
				fprintf(stderr, "%s.%d: %s\n",
					__FILE__, __LINE__,
					"I will not set uid to 0\n");
				return -1;
			}
		}

		if (groupname) {
			if (NULL == (grp = getgrnam(groupname))) {
				fprintf(stderr, "%s.%d: %s %s\n",
					__FILE__, __LINE__,
					"can't find groupname",
					groupname);
				return -1;
			}
			if (grp->gr_gid == 0) {
				fprintf(stderr, "%s.%d: %s\n",
					__FILE__, __LINE__,
					"I will not set gid to 0\n");
				return -1;
			}
		}

		/*
		 * Change group before chroot, when we have access
		 * to /etc/group
		 */
		if (groupname) {
			setgid(grp->gr_gid);
			setgroups(0, NULL);
			if (username) {
				initgroups(username, grp->gr_gid);
			}
		}

		if (changeroot) {
			if (-1 == chroot(changeroot)) {
				fprintf(stderr, "%s.%d: %s %s\n",
					__FILE__, __LINE__,
					"chroot failed: ", strerror(errno));
				return -1;
			}
			if (-1 == chdir("/")) {
				fprintf(stderr, "%s.%d: %s %s\n",
					__FILE__, __LINE__,
					"chdir failed: ", strerror(errno));
				return -1;
			}
		}

		/* drop root privs */
		if (username) {
			setuid(pwd->pw_uid);
		}
	}

       return fcgi_spawn_connection(fcgi_app, fcgi_app_argv, addr, port, unixsocket, child_count, pid_fd, nofork);
}
示例#22
0
文件: misc.c 项目: rovaughn/distro
/* change a Flag(*) value; takes care of special actions */
void
change_flag(enum sh_flag f, int what, bool newset)
{
	unsigned char oldval;
	unsigned char newval = (newset ? 1 : 0);

	if (f == FXTRACE) {
		change_xtrace(newval, true);
		return;
	}
	oldval = Flag(f);
	Flag(f) = newval = (newset ? 1 : 0);
#ifndef MKSH_UNEMPLOYED
	if (f == FMONITOR) {
		if (what != OF_CMDLINE && newval != oldval)
			j_change();
	} else
#endif
#ifndef MKSH_NO_CMDLINE_EDITING
	  if ((
#if !MKSH_S_NOVI
	    f == FVI ||
#endif
	    f == FEMACS || f == FGMACS) && newval) {
#if !MKSH_S_NOVI
		Flag(FVI) =
#endif
		    Flag(FEMACS) = Flag(FGMACS) = 0;
		Flag(f) = newval;
	} else
#endif
	  if (f == FPRIVILEGED && oldval && !newval) {
		/* Turning off -p? */

		/*XXX this can probably be optimised */
		kshegid = kshgid = getgid();
		ksheuid = kshuid = getuid();
#if HAVE_SETRESUGID
		DO_SETUID(setresgid, (kshegid, kshegid, kshegid));
#if HAVE_SETGROUPS
		/* setgroups doesn't EAGAIN on Linux */
		setgroups(1, &kshegid);
#endif
		DO_SETUID(setresuid, (ksheuid, ksheuid, ksheuid));
#else /* !HAVE_SETRESUGID */
		/* setgid, setegid, seteuid don't EAGAIN on Linux */
		setgid(kshegid);
#ifndef MKSH__NO_SETEUGID
		setegid(kshegid);
#endif
		DO_SETUID(setuid, (ksheuid));
#ifndef MKSH__NO_SETEUGID
		seteuid(ksheuid);
#endif
#endif /* !HAVE_SETRESUGID */
	} else if ((f == FPOSIX || f == FSH) && newval) {
		/* Turning on -o posix or -o sh? */
		Flag(FBRACEEXPAND) = 0;
	} else if (f == FTALKING) {
		/* Changing interactive flag? */
		if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid)
			Flag(FTALKING_I) = newval;
	}
}
示例#23
0
int
main(int argc, char **argv)
{
    int ch;
    mode_t omask;
    const char *oconn = OCONN;
    const char *user = USER;
    const char *group = "";
    sfsistat r = MI_FAILURE;
    const char *ofile = NULL;

    tzset();
    openlog("sa2scl-milter", LOG_PID | LOG_NDELAY, LOG_DAEMON);

    while ((ch = getopt(argc, argv, "dg:p:u:")) != -1) {
        switch (ch) {
        case 'd':
            debug = 1;
            break;
        case 'g':
            group = optarg;
            break;
        case 'p':
            oconn = optarg;
            break;
        case 'u':
            user = optarg;
            break;
        default:
            usage(argv[0]);
        }
    }
    if (argc != optind) {
        fprintf(stderr, "unknown command line argument: %s ...",
                argv[optind]);
        usage(argv[0]);
    }

    if (!strncmp(oconn, "unix:", 5))
        ofile = oconn + 5;
    else if (!strncmp(oconn, "local:", 6))
        ofile = oconn + 6;
    if (ofile != NULL)
        unlink(ofile);

    /* drop privileges */
    if (!getuid()) {
        struct passwd *pw;
        struct group *gr;

        if ((pw = getpwnam(user)) == NULL) {
            fprintf(stderr, "getpwnam: %s: %s\n", user,
                    strerror(errno));
            return (1);
        }
        if (strlen(group) == 0 || (gr = getgrnam(group)) == NULL) {
            /* use primary group of user */
            setgroups(1, &pw->pw_gid);
            if (setegid(pw->pw_gid) || setgid(pw->pw_gid)) {
                fprintf(stderr, "setgid: %s\n", strerror(errno));
                return (1);
            }
            omask = 0177;
        } else {
            /* custom group */
            setgroups(1, &gr->gr_gid);
            if (setegid(gr->gr_gid) || setgid(gr->gr_gid)) {
                fprintf(stderr, "setgid: %s\n", strerror(errno));
                return (1);
            }
            omask = 0117;
        }
        if (
#if ! ( __linux__ )
            seteuid(pw->pw_uid) ||
#endif
            setuid(pw->pw_uid)) {
            fprintf(stderr, "setuid: %s\n", strerror(errno));
            return (1);
        }
    }

    if (smfi_setconn((char *)oconn) != MI_SUCCESS) {
        fprintf(stderr, "smfi_setconn: %s: failed\n", oconn);
        goto done;
    }

    if (smfi_register(smfilter) != MI_SUCCESS) {
        fprintf(stderr, "smfi_register: failed\n");
        goto done;
    }

    /* daemonize (detach from controlling terminal) */
    if (!debug && daemon(0, 0)) {
        fprintf(stderr, "daemon: %s\n", strerror(errno));
        goto done;
    }
    umask(omask);

    msg(LOG_INFO, NULL, "smfi_main: started");
    r = smfi_main();
    if (r != MI_SUCCESS)
        msg(LOG_ERR, NULL, "smfi_main: terminating due to error");
    else
        msg(LOG_INFO, NULL, "smfi_main: terminating without error");

done:
    return (r);
}
示例#24
0
int
main(void)
{
	struct passwd *credentials;
	pid_t pid;
	int result;

	char *const argv[] = {
		"/usr/local/share/rivoluz/run.sh",
		NULL
	};
	char *const envp[] = {
		"USER="******"LOGNAME=" UNPRIV_USER,
		"HOME=/",
		"PATH=/usr/bin:/bin",
	};

	/*
	 * Drop privileges
	 */

	credentials = getpwnam(UNPRIV_USER);
	if (credentials == NULL)
		err(1, "getpwnam");

	result = setresgid(credentials->pw_gid, credentials->pw_gid,
	    credentials->pw_gid);
	if (result != 0)
		err(1, "setresgid");

	result = setgroups(0, NULL);
	if (result != 0)
		err(1, "setgroups");

	result = setresuid(credentials->pw_uid, credentials->pw_uid,
	    credentials->pw_uid);
	if (result != 0)
		err(1, "setresuid");

	/*
	 * Become a daemon
	 */

	pid = fork();
	if (pid == -1)
		err(1, "fork");
	if (pid != 0)
		exit(0);

	pid = setsid();
	if (pid == -1)
		err(1, "setsid");

	pid = fork();
	if (pid == -1)
		err(1, "fork");
	if (pid != 0)
		exit(0);

	/*
	 * Redirect stdio
	 */

	(void)close(0);
	result = open("/dev/null", O_RDONLY);
	if (result == -1)
		err(1, "open");

	(void)close(1);
	result = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT,
	    S_IRUSR|S_IWUSR|S_IRGRP);
	if (result == -1)
		err(1, "open");

	(void)close(2);
	result = dup(1);
	if (result == -1)
		exit(1);

	/*
	 * Execve
	 */

	result = execve(argv[0], argv, envp);
	if (result != 0)
		err(1, "execve");

	/* NOTREACHED */
	exit(1);
}
int
main(int argc, char **argv)
{
#ifdef __FreeBSD__
	FILE		*fpid = NULL;
#endif	
	int		 ch;
	struct passwd	*pw;
	pcap_handler	 phandler = logpkt_handler;
	int syncfd = 0;
	struct servent *ent;
	char *sync_iface = NULL;
	char *sync_baddr = NULL;

	if ((ent = getservbyname("spamd-sync", "udp")) == NULL)
		errx(1, "Can't find service \"spamd-sync\" in /etc/services");
	sync_port = ntohs(ent->s_port);
#ifndef __FreeBSD__
	while ((ch = getopt(argc, argv, "DIi:l:Y:")) != -1) {
#else
	while ((ch = getopt(argc, argv, "DIi:l:Y:m:")) != -1) {
#endif
		switch (ch) {
		case 'D':
			flag_debug = 1;
			break;
		case 'I':
			flag_inbound = 1;
			break;
		case 'i':
			networkif = optarg;
			break;
		case 'l':
			pflogif = optarg;
			break;
		case 'Y':
			if (sync_addhost(optarg, sync_port) != 0)
				sync_iface = optarg;
			syncsend++;
			break;
#ifdef __FreeBSD__
		case 'm':
			if (strcmp(optarg, "ipfw") == 0)
				use_pf=0;
			break;
#endif
			
		default:
			usage();
			/* NOTREACHED */
		}
	}

	signal(SIGINT , sighandler_close);
	signal(SIGQUIT, sighandler_close);
	signal(SIGTERM, sighandler_close);

	logmsg(LOG_DEBUG, "Listening on %s for %s %s", pflogif,
	    (networkif == NULL) ? "all interfaces." : networkif,
	    (flag_inbound) ? "Inbound direction only." : "");

	if (init_pcap() == -1)
		err(1, "couldn't initialize pcap");

	if (syncsend) {
		syncfd = sync_init(sync_iface, sync_baddr, sync_port);
		if (syncfd == -1)
			err(1, "sync init");
	}
	
#ifdef __FreeBSD__
	/* open the pid file just before switch the user */
	fpid = fopen(pid_file, "w");
	if (fpid == NULL) {
		syslog(LOG_ERR, "exiting (couldn't create pid file %s)", 
				pid_file);
		 err(1, "couldn't create pid file \"%s\"", pid_file);
	}
#endif	

	/* privdrop */
	pw = getpwnam("_spamd");
	if (pw == NULL)
		errx(1, "User '_spamd' not found! ");

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		err(1, "failed to drop privs");

	if (!flag_debug) {
		if (daemon(0, 0) == -1)
			err(1, "daemon");
		tzset();
		openlog_r("spamlogd", LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata);
	}

#ifdef __FreeBSD__
	/* after switch user and daemon write and close the pid file */
	if (fpid) {
		fprintf(fpid, "%ld\n", (long) getpid());
		if (fclose(fpid) == EOF) {
			syslog(LOG_ERR, "exiting (couldn't close pid file %s)", 
				pid_file);
			exit (1);
		}
	}
#endif	

	pcap_loop(hpcap, -1, phandler, NULL);

	logmsg(LOG_NOTICE, "exiting");
	if (!flag_debug)
		closelog_r(&sdata);

	exit(0);
}
示例#26
0
pid_t
control(void)
{
	pid_t			 pid;
	struct passwd		*pw;
	struct event		 ev_sigint;
	struct event		 ev_sigterm;

	switch (pid = fork()) {
	case -1:
		fatal("control: cannot fork");
	case 0:
		post_fork(PROC_CONTROL);
		break;
	default:
		return (pid);
	}

	purge_config(PURGE_EVERYTHING);

	if ((pw = getpwnam(SMTPD_USER)) == NULL)
		fatalx("unknown user " SMTPD_USER);

	stat_backend = env->sc_stat;
	stat_backend->init();

	if (chroot(PATH_CHROOT) == -1)
		fatal("control: chroot");
	if (chdir("/") == -1)
		fatal("control: chdir(\"/\")");

	config_process(PROC_CONTROL);

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("control: cannot drop privileges");

	imsg_callback = control_imsg;
	event_init();

	signal_set(&ev_sigint, SIGINT, control_sig_handler, NULL);
	signal_set(&ev_sigterm, SIGTERM, control_sig_handler, NULL);
	signal_add(&ev_sigint, NULL);
	signal_add(&ev_sigterm, NULL);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	tree_init(&ctl_conns);

	memset(&digest, 0, sizeof digest);
	digest.startup = time(NULL);

	config_peer(PROC_SCHEDULER);
	config_peer(PROC_QUEUE);
	config_peer(PROC_SMTP);
	config_peer(PROC_MFA);
	config_peer(PROC_PARENT);
	config_peer(PROC_LKA);
	config_peer(PROC_MDA);
	config_peer(PROC_MTA);
	config_done();

	control_listen();

	if (event_dispatch() < 0)
		fatal("event_dispatch");
	control_shutdown();

	return (0);
}
示例#27
0
int daemonize_trqauthd(const char *server_ip, int server_port, void *(*process_meth)(void *))
  {
  int gid;
  pid_t pid;
  int   rc;
  char  error_buf[MAX_BUF];
  char msg_trqauthddown[MAX_BUF];
  char path_log[MAXPATHLEN + 1];
  char unix_socket_name[MAXPATHLEN + 1];
  char *log_file=NULL;
  int eventclass = PBS_EVENTCLASS_TRQAUTHD;
  const char *path_home = PBS_SERVER_HOME;

  umask(022);

  gid = getgid();
  /* secure supplemental groups */
  if(setgroups(1, (gid_t *)&gid) != 0)
    {
    fprintf(stderr, "Unable to drop secondary groups. Some MAC framework is active?\n");
    snprintf(error_buf, sizeof(error_buf),
                     "setgroups(group = %lu) failed: %s\n",
                     (unsigned long)gid, strerror(errno));
    fprintf(stderr, "%s\n", error_buf);
    return(1);
    }

  if (getenv("PBSDEBUG") != NULL)
    debug_mode = TRUE;
  if (debug_mode == FALSE)
    {
    pid = fork();
    if(pid > 0)
      {
      /* parent. We are done */
      return(0);
      }
    else if (pid < 0)
      {
      /* something went wrong */
      fprintf(stderr, "fork failed. errno = %d\n", errno);
      return(PBSE_RMSYSTEM);
      }
    else
      {
      fprintf(stderr, "trqauthd daemonized - port %d\n", server_port);
      /* If I made it here I am the child */
      fclose(stdin);
      fclose(stdout);
      fclose(stderr);
      /* We closed 0 (stdin), 1 (stdout), and 2 (stderr). fopen should give us
         0, 1 and 2 in that order. this is a UNIX practice */
      if (fopen("/dev/null", "r") == NULL)
        perror(__func__);

      if (fopen("/dev/null", "r") == NULL)
        perror(__func__);

      if (fopen("/dev/null", "r") == NULL)
        perror(__func__);
      }
    }
  else
    {
    fprintf(stderr, "trqauthd port: %d\n", server_port);
    }

    log_init(NULL, NULL);
    log_get_set_eventclass(&eventclass, SETV);
    initialize_globals_for_log(server_port);
    sprintf(path_log, "%s/%s", path_home, TRQ_LOGFILES);
    if ((mkdir(path_log, 0755) == -1) && (errno != EEXIST))
      {
         openlog("daemonize_trqauthd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
         syslog(LOG_ALERT, "Failed to create client_logs directory: errno: %d", errno);
         log_err(errno,"daemonize_trqauthd", "Failed to create client_logs directory");
         closelog();
      }
    pthread_mutex_lock(log_mutex);
    log_open(log_file, path_log);
    pthread_mutex_unlock(log_mutex);

    /* start the listener */
    snprintf(unix_socket_name, sizeof(unix_socket_name), "%s/%s", TRQAUTHD_SOCK_DIR, TRQAUTHD_SOCK_NAME);
    rc = start_domainsocket_listener(unix_socket_name, process_meth);
    if(rc != PBSE_NONE)
      {
      openlog("daemonize_trqauthd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
      syslog(LOG_ALERT, "trqauthd could not start: %d\n", rc);
      log_err(rc, "daemonize_trqauthd", (char *)"trqauthd could not start");
      pthread_mutex_lock(log_mutex);
      log_close(1);
      pthread_mutex_unlock(log_mutex);
      if (changed_msg_daem && msg_daemonname) {
          free(msg_daemonname);
      }
      clean_log_init_mutex();
      exit(-1);
      }
    snprintf(msg_trqauthddown, sizeof(msg_trqauthddown),
      "TORQUE authd daemon shut down and no longer listening on IP:port %s:%d",
      server_ip, server_port);
    log_event(PBSEVENT_SYSTEM | PBSEVENT_FORCE, PBS_EVENTCLASS_TRQAUTHD,
      msg_daemonname, msg_trqauthddown);
    pthread_mutex_lock(log_mutex);
    log_close(1);
    pthread_mutex_unlock(log_mutex);
    if (changed_msg_daem && msg_daemonname)
      {
      free(msg_daemonname);
      }
    clean_log_init_mutex();
    exit(0);
  }
示例#28
0
static int ruid_set_perm (request_rec *r, const char *from_func)
{
	ruid_config_t *conf = ap_get_module_config(r->server->module_config, &ruid2_module);
	ruid_dir_config_t *dconf = ap_get_module_config(r->per_dir_config, &ruid2_module);

	int retval = DECLINED;
	gid_t gid;
	uid_t uid;
	gid_t groups[RUID_MAXGROUPS];
	int groupsnr;

	cap_t cap;
	cap_value_t capval[3];

	cap=cap_get_proc();
	capval[0]=CAP_SETUID;
	capval[1]=CAP_SETGID;
	cap_set_flag(cap,CAP_EFFECTIVE,2,capval,CAP_SET);
	if (cap_set_proc(cap)!=0) {
		ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "%s CRITICAL ERROR %s>%s:cap_set_proc failed before setuid", MODULE_NAME, from_func, __func__);
	}
	cap_free(cap);

	if (dconf->ruid_mode==RUID_MODE_STAT) {
		/* set uid,gid to uid,gid of file
		 * if file does not exist, finfo.user and finfo.group is set to uid,gid of parent directory
		 */
		gid=r->finfo.group;
		uid=r->finfo.user;

		/* if uid of filename is less than conf->min_uid then set to conf->default_uid */
		if (uid < conf->min_uid) {
			uid=conf->default_uid;
		}
		if (gid < conf->min_gid) {
			gid=conf->default_gid;
		}
	} else {
		gid=(dconf->ruid_gid == UNSET) ? ap_unixd_config.group_id : dconf->ruid_gid;
		uid=(dconf->ruid_uid == UNSET) ? ap_unixd_config.user_id : dconf->ruid_uid;
	}

	/* set supplementary groups */
	if ((dconf->groupsnr == UNSET) && (startup_groupsnr > 0)) {
		memcpy(groups, startup_groups, sizeof(groups));
		groupsnr = startup_groupsnr;
	} else if (dconf->groupsnr > 0) {
		for (groupsnr = 0; groupsnr < dconf->groupsnr; groupsnr++) {
			groups[groupsnr] = dconf->groups[groupsnr];
		}
	} else {
		groupsnr = 0;
	}
	setgroups(groupsnr, groups);

	/* final set[ug]id */
	if (setgid(gid) != 0)
	{
		ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "%s %s %s %s>%s:setgid(%d) failed. getgid=%d getuid=%d", MODULE_NAME, ap_get_server_name(r), r->the_request, from_func, __func__, dconf->ruid_gid, getgid(), getuid());
		retval = HTTP_FORBIDDEN;
	} else {
		if (setuid(uid) != 0)
		{
			ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "%s %s %s %s>%s:setuid(%d) failed. getuid=%d", MODULE_NAME, ap_get_server_name(r), r->the_request, from_func, __func__, dconf->ruid_uid, getuid());
			retval = HTTP_FORBIDDEN;
		}
	}

	/* set httpd process dumpable after setuid */
	if (coredump) {
		prctl(PR_SET_DUMPABLE,1);
	}

	/* clear capabilties from effective set */
	cap=cap_get_proc();
	capval[0]=CAP_SETUID;
	capval[1]=CAP_SETGID;
	capval[2]=CAP_DAC_READ_SEARCH;
	cap_set_flag(cap,CAP_EFFECTIVE,3,capval,CAP_CLEAR);

	if (cap_set_proc(cap)!=0) {
		ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "%s CRITICAL ERROR %s>%s:cap_set_proc failed after setuid", MODULE_NAME, from_func, __func__);
		retval = HTTP_FORBIDDEN;
	}
	cap_free(cap);

	return retval;
}
示例#29
0
void service_start(struct service *svc, const char *dynamic_args)
{
    struct stat s;
    pid_t pid;
    int needs_console;
    int n;
    char *scon = NULL;
    int rc;

        /* starting a service removes it from the disabled or reset
         * state and immediately takes it out of the restarting
         * state if it was in there
         */
    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
    svc->time_started = 0;

        /* running processes require no additional work -- if
         * they're in the process of exiting, we've ensured
         * that they will immediately restart on exit, unless
         * they are ONESHOT
         */
    if (svc->flags & SVC_RUNNING) {
#ifdef MTK_INIT
		ERROR("service '%s' still running, return directly\n", svc->name);
#endif
        return;
    }

    needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
    if (needs_console && (!have_console)) {
        ERROR("service '%s' requires console\n", svc->name);
        svc->flags |= SVC_DISABLED;
        return;
    }

    if (stat(svc->args[0], &s) != 0) {
        ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
        svc->flags |= SVC_DISABLED;
        return;
    }

    if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
               svc->args[0]);
        svc->flags |= SVC_DISABLED;
        return;
    }

    if (is_selinux_enabled() > 0) {
        if (svc->seclabel) {
            scon = strdup(svc->seclabel);
            if (!scon) {
                ERROR("Out of memory while starting '%s'\n", svc->name);
                return;
            }
        } else {
            char *mycon = NULL, *fcon = NULL;

            INFO("computing context for service '%s'\n", svc->args[0]);
            rc = getcon(&mycon);
            if (rc < 0) {
                ERROR("could not get context while starting '%s'\n", svc->name);
                return;
            }

            rc = getfilecon(svc->args[0], &fcon);
            if (rc < 0) {
                ERROR("could not get context while starting '%s'\n", svc->name);
                freecon(mycon);
                return;
            }

            rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
            if (rc == 0 && !strcmp(scon, mycon)) {
                ERROR("Warning!  Service %s needs a SELinux domain defined; please fix!\n", svc->name);
            }
            freecon(mycon);
            freecon(fcon);
            if (rc < 0) {
                ERROR("could not get context while starting '%s'\n", svc->name);
                return;
            }
        }
    }

    NOTICE("starting '%s'\n", svc->name);

    pid = fork();

    if (pid == 0) {
        struct socketinfo *si;
        struct svcenvinfo *ei;
        char tmp[32];
        int fd, sz;

        umask(077);
        if (properties_inited()) {
            get_property_workspace(&fd, &sz);
            sprintf(tmp, "%d,%d", dup(fd), sz);
            add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
        }

        for (ei = svc->envvars; ei; ei = ei->next)
            add_environment(ei->name, ei->value);

        for (si = svc->sockets; si; si = si->next) {
            int socket_type = (
                    !strcmp(si->type, "stream") ? SOCK_STREAM :
                        (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
            int s = create_socket(si->name, socket_type,
                                  si->perm, si->uid, si->gid, si->socketcon ?: scon);
            if (s >= 0) {
                publish_socket(si->name, s);
            }
        }

        freecon(scon);
        scon = NULL;

        if (svc->ioprio_class != IoSchedClass_NONE) {
            if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
                ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
                      getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
            }
        }

        if (needs_console) {
            setsid();
            open_console();
        } else {
            zap_stdio();
        }

#if 0
        for (n = 0; svc->args[n]; n++) {
            INFO("args[%d] = '%s'\n", n, svc->args[n]);
        }
        for (n = 0; ENV[n]; n++) {
            INFO("env[%d] = '%s'\n", n, ENV[n]);
        }
#endif

        setpgid(0, getpid());

    /* as requested, set our gid, supplemental gids, and uid */
        if (svc->gid) {
            if (setgid(svc->gid) != 0) {
                ERROR("setgid failed: %s service name %s\n", strerror(errno),svc->name);
                _exit(127);
            }
        }
        if (svc->nr_supp_gids) {
            if (setgroups(svc->nr_supp_gids, svc->supp_gids) != 0) {
                ERROR("setgroups failed: %s service name %s\n", strerror(errno),svc->name);
                _exit(127);
            }
        }
        if (svc->uid) {
            if (setuid(svc->uid) != 0) {
                ERROR("setuid failed: %s service name %s\n", strerror(errno),svc->name);
                _exit(127);
            }
        }
        if (svc->seclabel) {
            if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) {
                ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno));
                _exit(127);
            }
        }

        if (!dynamic_args) {
            if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
                ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
            }
        } else {
            char *arg_ptrs[INIT_PARSER_MAXARGS+1];
            int arg_idx = svc->nargs;
            char *tmp = strdup(dynamic_args);
            char *next = tmp;
            char *bword;

            /* Copy the static arguments */
            memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));

            while((bword = strsep(&next, " "))) {
                arg_ptrs[arg_idx++] = bword;
                if (arg_idx == INIT_PARSER_MAXARGS)
                    break;
            }
            arg_ptrs[arg_idx] = '\0';
            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
        }
        _exit(127);
    }

    freecon(scon);

    if (pid < 0) {
        ERROR("failed to start '%s'\n", svc->name);
        svc->pid = 0;
        return;
    }

    svc->time_started = gettime();
    svc->pid = pid;
    svc->flags |= SVC_RUNNING;

#ifdef MTK_INIT
    //record the usage of serivce
    svc->flags |= SVC_MT_GOTLIFE;
#endif
    if (properties_inited())
        notify_service_state(svc->name, "running");
}
示例#30
0
void service_start(struct service *svc, const char *dynamic_args)
{
    struct stat s;
    pid_t pid;
    int needs_console;
    int n;

        /* starting a service removes it from the disabled
         * state and immediately takes it out of the restarting
         * state if it was in there
         */
    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING));
    svc->time_started = 0;
    
        /* running processes require no additional work -- if
         * they're in the process of exiting, we've ensured
         * that they will immediately restart on exit, unless
         * they are ONESHOT
         */
    if (svc->flags & SVC_RUNNING) {
        return;
    }

    needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
    if (needs_console && (!have_console)) {
        ERROR("service '%s' requires console\n", svc->name);
        svc->flags |= SVC_DISABLED;
        return;
    }

    if (stat(svc->args[0], &s) != 0) {
        ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
        svc->flags |= SVC_DISABLED;
        return;
    }

    if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
               svc->args[0]);
        svc->flags |= SVC_DISABLED;
        return;
    }

    NOTICE("starting '%s'\n", svc->name);

    pid = fork();

    if (pid == 0) {
        struct socketinfo *si;
        struct svcenvinfo *ei;
        char tmp[32];
        int fd, sz;

        if (properties_inited()) {
            get_property_workspace(&fd, &sz);
            sprintf(tmp, "%d,%d", dup(fd), sz);
            add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
        }

        for (ei = svc->envvars; ei; ei = ei->next)
            add_environment(ei->name, ei->value);

        for (si = svc->sockets; si; si = si->next) {
            int socket_type = (
                    !strcmp(si->type, "stream") ? SOCK_STREAM :
                        (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
            int s = create_socket(si->name, socket_type,
                                  si->perm, si->uid, si->gid);
            if (s >= 0) {
                publish_socket(si->name, s);
            }
        }

        if (svc->ioprio_class != IoSchedClass_NONE) {
            if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
                ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
                      getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
            }
        }

        if (needs_console) {
            setsid();
            open_console();
        } else {
            zap_stdio();
        }

#if 0
        for (n = 0; svc->args[n]; n++) {
            INFO("args[%d] = '%s'\n", n, svc->args[n]);
        }
        for (n = 0; ENV[n]; n++) {
            INFO("env[%d] = '%s'\n", n, ENV[n]);
        }
#endif

        setpgid(0, getpid());

    /* as requested, set our gid, supplemental gids, and uid */
        if (svc->gid) {
            setgid(svc->gid);
        }
        if (svc->nr_supp_gids) {
            setgroups(svc->nr_supp_gids, svc->supp_gids);
        }
        if (svc->uid) {
            setuid(svc->uid);
        }

        if (!dynamic_args) {
            if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
                ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
            }
        } else {
            char *arg_ptrs[INIT_PARSER_MAXARGS+1];
            int arg_idx = svc->nargs;
            char *tmp = strdup(dynamic_args);
            char *next = tmp;
            char *bword;

            /* Copy the static arguments */
            memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));

            while((bword = strsep(&next, " "))) {
                arg_ptrs[arg_idx++] = bword;
                if (arg_idx == INIT_PARSER_MAXARGS)
                    break;
            }
            arg_ptrs[arg_idx] = '\0';
            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
        }
        _exit(127);
    }

    if (pid < 0) {
        ERROR("failed to start '%s'\n", svc->name);
        svc->pid = 0;
        return;
    }

    svc->time_started = gettime();
    svc->pid = pid;
    svc->flags |= SVC_RUNNING;

    if (properties_inited())
        notify_service_state(svc->name, "running");
}