示例#1
0
static void
mcf_auth(struct cli *cli, const char *const *av, void *priv)
{
	int fd;
	char buf[CLI_AUTH_RESPONSE_LEN + 1];

	AN(av[2]);
	(void)priv;
	if (secret_file == NULL) {
		VCLI_Out(cli, "Secret file not configured\n");
		VCLI_SetResult(cli, CLIS_CANT);
		return;
	}
	fd = open(secret_file, O_RDONLY);
	if (fd < 0) {
		VCLI_Out(cli, "Cannot open secret file (%s)\n",
		    strerror(errno));
		VCLI_SetResult(cli, CLIS_CANT);
		return;
	}
	mgt_got_fd(fd);
	VCLI_AuthResponse(fd, cli->challenge, buf);
	AZ(close(fd));
	if (strcasecmp(buf, av[2])) {
		mgt_cli_challenge(cli);
		return;
	}
	cli->auth = MCF_AUTH;
	memset(cli->challenge, 0, sizeof cli->challenge);
	VCLI_SetResult(cli, CLIS_OK);
	mcf_banner(cli, av, priv);
}
示例#2
0
static void
tweak_generic_double(struct cli *cli, const struct parspec *par,
    const char *arg)
{
	volatile double *dest;
	double u;

	dest = par->priv;
	if (arg != NULL) {
		u = strtod(arg, NULL);
		if (u < par->min) {
			VCLI_Out(cli,
			    "Must be greater or equal to %.g\n",
				 par->min);
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		if (u > par->max) {
			VCLI_Out(cli,
			    "Must be less than or equal to %.g\n",
				 par->max);
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		*dest = u;
	} else
		VCLI_Out(cli, "%f", *dest);
}
示例#3
0
static int
tweak_generic_timeout_double(struct cli *cli, volatile double *dest,
    const char *arg, double min, double max)
{
	double u;
	char *p;

	if (arg != NULL) {
		p = NULL;
		u = strtod(arg, &p);
		if (*arg == '\0' || *p != '\0') {
			VCLI_Out(cli, "Not a number(%s)\n", arg);
			VCLI_SetResult(cli, CLIS_PARAM);
			return (-1);
		}
		if (u < min) {
			VCLI_Out(cli,
			    "Timeout must be greater or equal to %.g\n", min);
			VCLI_SetResult(cli, CLIS_PARAM);
			return (-1);
		}
		if (u > max) {
			VCLI_Out(cli,
			    "Timeout must be less than or equal to %.g\n", max);
			VCLI_SetResult(cli, CLIS_PARAM);
			return (-1);
		}
		*dest = u;
	} else
		VCLI_Out(cli, "%.6f", *dest);
	return (0);
}
示例#4
0
void
tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg,
    unsigned min, unsigned max)
{
	unsigned u;

	if (arg != NULL) {
		if (!strcasecmp(arg, "unlimited"))
			u = UINT_MAX;
		else
			u = strtoul(arg, NULL, 0);
		if (u < min) {
			VCLI_Out(cli, "Must be at least %u\n", min);
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		if (u > max) {
			VCLI_Out(cli, "Must be no more than %u\n", max);
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		*dest = u;
	} else if (*dest == UINT_MAX) {
		VCLI_Out(cli, "unlimited", *dest);
	} else {
		VCLI_Out(cli, "%u", *dest);
	}
}
示例#5
0
static void
mcf_askchild(struct cli *cli, const char * const *av, void *priv)
{
	int i;
	char *q;
	unsigned u;
	struct vsb *vsb;

	(void)priv;
	/*
	 * Command not recognized in master, try cacher if it is
	 * running.
	 */
	if (cli_o <= 0) {
		if (!strcmp(av[1], "help")) {
			if (av[2] == NULL || strcmp(av[2], "-j"))
				VCLI_Out(cli,
				   "No help from child, (not running).\n");
			return;
		}
		VCLI_SetResult(cli, CLIS_UNKNOWN);
		VCLI_Out(cli,
		    "Unknown request in manager process "
		    "(child not running).\n"
		    "Type 'help' for more info.");
		return;
	}
	vsb = VSB_new_auto();
	for (i = 1; av[i] != NULL; i++) {
		VSB_quote(vsb, av[i], strlen(av[i]), 0);
		VSB_putc(vsb, ' ');
	}
	VSB_putc(vsb, '\n');
	AZ(VSB_finish(vsb));
	i = write(cli_o, VSB_data(vsb), VSB_len(vsb));
	if (i != VSB_len(vsb)) {
		VSB_destroy(&vsb);
		VCLI_SetResult(cli, CLIS_COMMS);
		VCLI_Out(cli, "CLI communication error");
		MGT_Child_Cli_Fail();
		return;
	}
	VSB_destroy(&vsb);
	if (VCLI_ReadResult(cli_i, &u, &q, mgt_param.cli_timeout))
		MGT_Child_Cli_Fail();
	VCLI_SetResult(cli, u);
	VCLI_Out(cli, "%s", q);
	free(q);
}
示例#6
0
void
tweak_group(struct cli *cli, const struct parspec *par, const char *arg)
{
	struct group *gr;

	(void)par;
	if (arg != NULL) {
		if (*arg != '\0') {
			gr = getgrnam(arg);
			if (gr == NULL) {
				VCLI_Out(cli, "Unknown group");
				VCLI_SetResult(cli, CLIS_PARAM);
				return;
			}
			REPLACE(mgt_param.group, gr->gr_name);
			mgt_param.gid = gr->gr_gid;
		} else {
			mgt_param.gid = getgid();
		}
	} else if (mgt_param.group) {
		VCLI_Out(cli, "%s (%d)", mgt_param.group, (int)mgt_param.gid);
	} else {
		VCLI_Out(cli, "GID %d", (int)mgt_param.gid);
	}
}
示例#7
0
static void
tweak_generic_bool(struct cli *cli, volatile unsigned *dest, const char *arg)
{
	if (arg != NULL) {
		if (!strcasecmp(arg, "off"))
			*dest = 0;
		else if (!strcasecmp(arg, "disable"))
			*dest = 0;
		else if (!strcasecmp(arg, "no"))
			*dest = 0;
		else if (!strcasecmp(arg, "false"))
			*dest = 0;
		else if (!strcasecmp(arg, "on"))
			*dest = 1;
		else if (!strcasecmp(arg, "enable"))
			*dest = 1;
		else if (!strcasecmp(arg, "yes"))
			*dest = 1;
		else if (!strcasecmp(arg, "true"))
			*dest = 1;
		else {
			VCLI_Out(cli, "use \"on\" or \"off\"\n");
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
	} else
		VCLI_Out(cli, *dest ? "on" : "off");
}
示例#8
0
static void
tweak_group(struct cli *cli, const struct parspec *par, const char *arg)
{
	struct group *gr;

	(void)par;
	if (arg != NULL) {
		if (!strcmp(arg, MAGIC_INIT_STRING)) {
			gr = getgrnam("nogroup");
			if (gr == NULL) {
				/* Only replace if tweak_user didn't */
				if (master.gid == 0)
					master.gid = getgid();
				return;
			}
		} else
			gr = getgrnam(arg);
		if (gr == NULL) {
			VCLI_Out(cli, "Unknown group");
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		REPLACE(master.group, gr->gr_name);
		master.gid = gr->gr_gid;
	} else if (master.group) {
		VCLI_Out(cli, "%s (%d)", master.group, (int)master.gid);
	} else {
		VCLI_Out(cli, "%d", (int)master.gid);
	}
}
示例#9
0
void
tweak_user(struct cli *cli, const struct parspec *par, const char *arg)
{
	struct passwd *pw;

	(void)par;
	if (arg != NULL) {
		if (*arg != '\0') {
			pw = getpwnam(arg);
			if (pw == NULL) {
				VCLI_Out(cli, "Unknown user");
				VCLI_SetResult(cli, CLIS_PARAM);
				return;
			}
			REPLACE(mgt_param.user, pw->pw_name);
			mgt_param.uid = pw->pw_uid;
		} else {
			mgt_param.uid = getuid();
		}
	} else if (mgt_param.user) {
		VCLI_Out(cli, "%s (%d)", mgt_param.user, (int)mgt_param.uid);
	} else {
		VCLI_Out(cli, "UID %d", (int)mgt_param.uid);
	}
}
示例#10
0
void
WAIT_tweak_waiter(struct cli *cli, const char *arg)
{
	int i;

	ASSERT_MGT();

	if (arg == NULL) {
		if (waiter == NULL)
			VCLI_Out(cli, "default");
		else
			VCLI_Out(cli, "%s", waiter->name);

		VCLI_Out(cli, " (");
		for (i = 0; vca_waiters[i] != NULL; i++)
			VCLI_Out(cli, "%s%s", i == 0 ? "" : ", ",
			    vca_waiters[i]->name);
		VCLI_Out(cli, ")");
		return;
	}
	if (!strcmp(arg, "default")) {
		waiter = NULL;
		return;
	}
	for (i = 0; vca_waiters[i]; i++) {
		if (!strcmp(arg, vca_waiters[i]->name)) {
			waiter = vca_waiters[i];
			return;
		}
	}
	VCLI_Out(cli, "Unknown waiter");
	VCLI_SetResult(cli, CLIS_PARAM);
}
示例#11
0
mcf_server_start(struct cli *cli, const char * const *av, void *priv)
{

	(void)av;
	(void)priv;
	if (child_state == CH_STOPPED) {
		if (mgt_has_vcl()) {
			mgt_launch_child(cli);
		} else {
			VCLI_SetResult(cli, CLIS_CANT);
			VCLI_Out(cli, "No VCL available");
		}
	} else {
		VCLI_SetResult(cli, CLIS_CANT);
		VCLI_Out(cli, "Child in state %s", ch_state[child_state]);
	}
}
mcf_server_startstop(struct cli *cli, const char * const *av, void *priv)
{

	(void)av;
	if (priv != NULL && child_state == CH_RUNNING)
		mgt_stop_child();
	else if (priv == NULL && child_state == CH_STOPPED) {
		if (mgt_has_vcl()) {
			mgt_launch_child(cli);
		} else {
			VCLI_SetResult(cli, CLIS_CANT);
			VCLI_Out(cli, "No VCL available");
		}
	} else {
		VCLI_SetResult(cli, CLIS_CANT);
		VCLI_Out(cli, "Child in state %s", ch_state[child_state]);
	}
}
示例#13
0
static void
tweak_generic_bytes(struct cli *cli, volatile ssize_t *dest, const char *arg,
    double min, double max)
{
	uintmax_t r;
	const char *p;

	if (arg != NULL) {
		p = VNUM_2bytes(arg, &r, 0);
		if (p != NULL) {
			VCLI_Out(cli, "Could not convert to bytes.\n");
			VCLI_Out(cli, "%s\n", p);
			VCLI_Out(cli,
			    "  Try something like '80k' or '120M'\n");
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		if ((uintmax_t)((ssize_t)r) != r) {
			fmt_bytes(cli, r);
			VCLI_Out(cli, " is too large for this architecture.\n");
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		if (max != 0. && r > max) {
			VCLI_Out(cli, "Must be no more than ");
			fmt_bytes(cli, (uintmax_t)max);
			VCLI_Out(cli, "\n");
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		if (r < min) {
			VCLI_Out(cli, "Must be at least ");
			fmt_bytes(cli, (uintmax_t)min);
			VCLI_Out(cli, "\n");
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		*dest = r;
	} else {
		fmt_bytes(cli, *dest);
	}
}
mcf_panic_clear(struct cli *cli, const char * const *av, void *priv)
{
	(void)priv;

	if (av[2] != NULL && strcmp(av[2], "-z")) {
		VCLI_SetResult(cli, CLIS_PARAM);
		VCLI_Out(cli, "Unknown parameter \"%s\".", av[2]);
		return;
	} else if (av[2] != NULL) {
		VSC_C_mgt->child_panic = static_VSC_C_mgt.child_panic = 0;
		if (child_panic == NULL)
			return;
	}
	if (child_panic == NULL) {
		VCLI_SetResult(cli, CLIS_CANT);
		VCLI_Out(cli, "No panic to clear");
		return;
	}
	mgt_panic_clear();
}
示例#15
0
mcf_server_stop(struct cli *cli, const char * const *av, void *priv)
{

	(void)av;
	(void)priv;
	if (child_state == CH_RUNNING) {
		mgt_stop_child();
	} else {
		VCLI_SetResult(cli, CLIS_CANT);
		VCLI_Out(cli, "Child in state %s", ch_state[child_state]);
	}
}
示例#16
0
char *
mgt_VccCompile(struct cli *cli, const char *vclname, const char *vclsrc,
    int C_flag)
{
	struct vcc_priv vp;
	struct vsb *sb;
	unsigned status;

	AN(cli);

	sb = VSB_new_auto();
	XXXAN(sb);

	INIT_OBJ(&vp, VCC_PRIV_MAGIC);
	vp.src = vclsrc;

	VSB_printf(sb, "./vcl_%s.c", vclname);
	AZ(VSB_finish(sb));
	vp.srcfile = strdup(VSB_data(sb));
	AN(vp.srcfile);
	VSB_clear(sb);

	VSB_printf(sb, "./vcl_%s.so", vclname);
	AZ(VSB_finish(sb));
	vp.libfile = strdup(VSB_data(sb));
	AN(vp.srcfile);
	VSB_clear(sb);

	status = mgt_vcc_compile(&vp, sb, C_flag);

	AZ(VSB_finish(sb));
	if (VSB_len(sb) > 0)
		VCLI_Out(cli, "%s", VSB_data(sb));
	VSB_delete(sb);

	(void)unlink(vp.srcfile);
	free(vp.srcfile);

	if (status || C_flag) {
		(void)unlink(vp.libfile);
		free(vp.libfile);
		if (!C_flag) {
			VCLI_Out(cli, "VCL compilation failed");
			VCLI_SetResult(cli, CLIS_PARAM);
		}
		return(NULL);
	}

	VCLI_Out(cli, "VCL compiled.\n");

	return (vp.libfile);
}
示例#17
0
static void
mgt_cli_challenge(struct cli *cli)
{
	int i;

	for (i = 0; i + 2L < sizeof cli->challenge; i++)
		cli->challenge[i] = (random() % 26) + 'a';
	cli->challenge[i++] = '\n';
	cli->challenge[i] = '\0';
	VCLI_Out(cli, "%s", cli->challenge);
	VCLI_Out(cli, "\nAuthentication required.\n");
	VCLI_SetResult(cli, CLIS_AUTH);
}
mcf_panic_show(struct cli *cli, const char * const *av, void *priv)
{
	(void)av;
	(void)priv;

	if (!child_panic) {
		VCLI_SetResult(cli, CLIS_CANT);
		VCLI_Out(cli,
		    "Child has not panicked or panic has been cleared");
		return;
	}

	VCLI_Out(cli, "%s\n", VSB_data(child_panic));
}
示例#19
0
int
tweak_generic_uint(struct cli *cli, volatile unsigned *dest, const char *arg,
    unsigned min, unsigned max)
{
	unsigned u;
	char *p;

	if (arg != NULL) {
		p = NULL;
		if (!strcasecmp(arg, "unlimited"))
			u = UINT_MAX;
		else {
			u = strtoul(arg, &p, 0);
			if (*arg == '\0' || *p != '\0') {
				VCLI_Out(cli, "Not a number (%s)\n", arg);
				VCLI_SetResult(cli, CLIS_PARAM);
				return (-1);
			}
		}
		if (u < min) {
			VCLI_Out(cli, "Must be at least %u\n", min);
			VCLI_SetResult(cli, CLIS_PARAM);
			return (-1);
		}
		if (u > max) {
			VCLI_Out(cli, "Must be no more than %u\n", max);
			VCLI_SetResult(cli, CLIS_PARAM);
			return (-1);
		}
		*dest = u;
	} else if (*dest == UINT_MAX) {
		VCLI_Out(cli, "unlimited");
	} else {
		VCLI_Out(cli, "%u", *dest);
	}
	return (0);
}
示例#20
0
static void
mcf_auth(struct cli *cli, const char *const *av, void *priv)
{
	int fd;
	char buf[CLI_AUTH_RESPONSE_LEN + 1];

	AN(av[2]);
	(void)priv;
	if (secret_file == NULL) {
		VCLI_Out(cli, "Secret file not configured\n");
		VCLI_SetResult(cli, CLIS_CANT);
		return;
	}
	VJ_master(JAIL_MASTER_FILE);
	fd = open(secret_file, O_RDONLY);
	if (fd < 0) {
		VCLI_Out(cli, "Cannot open secret file (%s)\n",
		    strerror(errno));
		VCLI_SetResult(cli, CLIS_CANT);
		VJ_master(JAIL_MASTER_LOW);
		return;
	}
	VJ_master(JAIL_MASTER_LOW);
	mgt_got_fd(fd);
	VCLI_AuthResponse(fd, cli->challenge, buf);
	AZ(close(fd));
	if (strcasecmp(buf, av[2])) {
		MGT_complain(C_SECURITY,
		    "CLI Authentication failure from %s", cli->ident);
		VCLI_SetResult(cli, CLIS_CLOSE);
		return;
	}
	cli->auth = MCF_AUTH;
	memset(cli->challenge, 0, sizeof cli->challenge);
	VCLI_SetResult(cli, CLIS_OK);
	mcf_banner(cli, av, priv);
}
示例#21
0
static void
tweak_generic_timeout(struct cli *cli, volatile unsigned *dst, const char *arg)
{
	unsigned u;

	if (arg != NULL) {
		u = strtoul(arg, NULL, 0);
		if (u == 0) {
			VCLI_Out(cli, "Timeout must be greater than zero\n");
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		*dst = u;
	} else
		VCLI_Out(cli, "%u", *dst);
}
示例#22
0
static void
mcf_banner(struct cli *cli, const char *const *av, void *priv)
{

	(void)av;
	(void)priv;
	VCLI_Out(cli, "-----------------------------\n");
	VCLI_Out(cli, "Varnish Cache CLI 1.0\n");
	VCLI_Out(cli, "-----------------------------\n");
	VCLI_Out(cli, "%s\n", VSB_data(vident) + 1);
	VCLI_Out(cli, "\n");
	VCLI_Out(cli, "Type 'help' for command list.\n");
	VCLI_Out(cli, "Type 'quit' to close CLI session.\n");
	if (child_pid < 0)
		VCLI_Out(cli, "Type 'start' to launch worker process.\n");
	VCLI_SetResult(cli, CLIS_OK);
}
示例#23
0
static void
mgt_cli_challenge(struct cli *cli)
{
	int i;
	uint8_t u;

	AZ(VRND_RandomCrypto(cli->challenge, sizeof cli->challenge - 2));
	for (i = 0; i < (sizeof cli->challenge) - 2; i++) {
		AZ(VRND_RandomCrypto(&u, sizeof u));
		cli->challenge[i] = (u % 26) + 'a';
	}
	cli->challenge[i++] = '\n';
	cli->challenge[i] = '\0';
	VCLI_Out(cli, "%s", cli->challenge);
	VCLI_Out(cli, "\nAuthentication required.\n");
	VCLI_SetResult(cli, CLIS_AUTH);
}
示例#24
0
void
tweak_bool(struct cli *cli, const struct parspec *par, const char *arg)
{
	volatile unsigned *dest;
	int mode = 0;

	if (!strcmp(par->def, "off") || !strcmp(par->def, "on"))
		mode = 1;

	dest = par->priv;
	if (arg != NULL) {
		if (!strcasecmp(arg, "off"))
			*dest = 0;
		else if (!strcasecmp(arg, "disable"))
			*dest = 0;
		else if (!strcasecmp(arg, "no"))
			*dest = 0;
		else if (!strcasecmp(arg, "false"))
			*dest = 0;
		else if (!strcasecmp(arg, "on"))
			*dest = 1;
		else if (!strcasecmp(arg, "enable"))
			*dest = 1;
		else if (!strcasecmp(arg, "yes"))
			*dest = 1;
		else if (!strcasecmp(arg, "true"))
			*dest = 1;
		else {
			VCLI_Out(cli,
			    mode ?
				"use \"on\" or \"off\"\n" :
				"use \"true\" or \"false\"\n");
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
	} else if (mode) {
		VCLI_Out(cli, *dest ? "on" : "off");
	} else {
		VCLI_Out(cli, *dest ? "true" : "false");
	}
}
示例#25
0
static void
tweak_user(struct cli *cli, const struct parspec *par, const char *arg)
{
	struct passwd *pw;
	struct group *gr;

	(void)par;
	if (arg != NULL) {
		if (!strcmp(arg, MAGIC_INIT_STRING)) {
			pw = getpwnam("nobody");
			if (pw == NULL) {
				master.uid = getuid();
				return;
			}
		} else
			pw = getpwnam(arg);
		if (pw == NULL) {
			VCLI_Out(cli, "Unknown user");
			VCLI_SetResult(cli, CLIS_PARAM);
			return;
		}
		REPLACE(master.user, pw->pw_name);
		master.uid = pw->pw_uid;
		master.gid = pw->pw_gid;

		/* set group to user's primary group */
		if ((gr = getgrgid(pw->pw_gid)) != NULL &&
		    (gr = getgrnam(gr->gr_name)) != NULL &&
		    gr->gr_gid == pw->pw_gid)
			REPLACE(master.group, gr->gr_name);
	} else if (master.user) {
		VCLI_Out(cli, "%s (%d)", master.user, (int)master.uid);
	} else {
		VCLI_Out(cli, "%d", (int)master.uid);
	}
}
static void
mgt_launch_child(struct cli *cli)
{
	pid_t pid;
	unsigned u;
	char *p;
	struct vev *e;
	int i, j, k, cp[2];
	struct sigaction sa;

	if (child_state != CH_STOPPED && child_state != CH_DIED)
		return;

	if (!MAC_sockets_ready(cli)) {
		child_state = CH_STOPPED;
		if (cli != NULL) {
			VCLI_SetResult(cli, CLIS_CANT);
			return;
		}
		MGT_complain(C_ERR,
		    "Child start failed: could not open sockets");
		return;
	}

	child_state = CH_STARTING;

	/* Open pipe for mgr->child CLI */
	AZ(pipe(cp));
	heritage.cli_in = cp[0];
	mgt_child_inherit(heritage.cli_in, "cli_in");
	child_cli_out = cp[1];

	/* Open pipe for child->mgr CLI */
	AZ(pipe(cp));
	heritage.cli_out = cp[1];
	mgt_child_inherit(heritage.cli_out, "cli_out");
	child_cli_in = cp[0];

	/*
	 * Open pipe for child stdout/err
	 * NB: not inherited, because we dup2() it to stdout/stderr in child
	 */
	AZ(pipe(cp));
	heritage.std_fd = cp[1];
	child_output = cp[0];

	AN(heritage.vsm);
	mgt_SHM_Size_Adjust();
	AN(heritage.vsm);
	AN(heritage.param);
	if ((pid = fork()) < 0) {
		/* XXX */
		perror("Could not fork child");
		exit(1);
	}
	if (pid == 0) {

		/* Redirect stdin/out/err */
		AZ(close(STDIN_FILENO));
		assert(open("/dev/null", O_RDONLY) == STDIN_FILENO);
		assert(dup2(heritage.std_fd, STDOUT_FILENO) == STDOUT_FILENO);
		assert(dup2(heritage.std_fd, STDERR_FILENO) == STDERR_FILENO);

		/*
		 * Close all FDs the child shouldn't know about
		 *
		 * We cannot just close these filedescriptors, some random
		 * library routine might miss it later on and wantonly close
		 * a FD we use at that point in time. (See bug #1841).
		 * We close the FD and replace it with /dev/null instead,
		 * That prevents security leakage, and gives the library
		 * code a valid FD to close when it discovers the changed
		 * circumstances.
		 */
		closelog();

		for (i = STDERR_FILENO + 1; i < CLOSE_FD_UP_TO; i++) {
			if (vbit_test(fd_map, i))
				continue;
			if (close(i) == 0) {
				k = open("/dev/null", O_RDONLY);
				assert(k >= 0);
				j = dup2(k, i);
				assert(j == i);
				AZ(close(k));
			}
		}
#ifdef HAVE_SETPROCTITLE
		setproctitle("Varnish-Chld %s", heritage.name);
#endif

		if (mgt_param.sigsegv_handler) {
			memset(&sa, 0, sizeof sa);
			sa.sa_sigaction = child_sigsegv_handler;
			sa.sa_flags = SA_SIGINFO;
			(void)sigaction(SIGSEGV, &sa, NULL);
			(void)sigaction(SIGBUS, &sa, NULL);
			(void)sigaction(SIGABRT, &sa, NULL);
		}
		(void)signal(SIGINT, SIG_DFL);
		(void)signal(SIGTERM, SIG_DFL);

		VJ_subproc(JAIL_SUBPROC_WORKER);

		child_main();

		exit(0);
	}
	assert(pid > 1);
	MGT_complain(C_DEBUG, "Child (%jd) Started", (intmax_t)pid);
	VSC_C_mgt->child_start = ++static_VSC_C_mgt.child_start;

	/* Close stuff the child got */
	closex(&heritage.std_fd);

	mgt_child_inherit(heritage.cli_in, NULL);
	closex(&heritage.cli_in);

	mgt_child_inherit(heritage.cli_out, NULL);
	closex(&heritage.cli_out);

	child_std_vlu = VLU_New(NULL, child_line, 0);
	AN(child_std_vlu);

	AZ(ev_listen);
	e = vev_new();
	XXXAN(e);
	e->fd = child_output;
	e->fd_flags = EV_RD;
	e->name = "Child listener";
	e->callback = child_listener;
	AZ(vev_add(mgt_evb, e));
	ev_listen = e;
	AZ(ev_poker);
	if (mgt_param.ping_interval > 0) {
		e = vev_new();
		XXXAN(e);
		e->timeout = mgt_param.ping_interval;
		e->callback = child_poker;
		e->name = "child poker";
		AZ(vev_add(mgt_evb, e));
		ev_poker = e;
	}

	mgt_cli_start_child(child_cli_in, child_cli_out);
	child_pid = pid;
	if (mgt_push_vcls_and_start(cli, &u, &p)) {
		VCLI_SetResult(cli, u);
		MGT_complain(C_ERR, "Child (%jd) Pushing vcls failed:\n%s",
		    (intmax_t)child_pid, p);
		free(p);
		child_state = CH_RUNNING;
		mgt_stop_child();
	} else
		child_state = CH_RUNNING;
}
示例#27
0
char *
mgt_VccCompile(struct cli *cli, struct vclprog *vcl, const char *vclname,
    const char *vclsrc, const char *vclsrcfile, int C_flag)
{
	struct vcc_priv vp;
	struct vsb *sb;
	unsigned status;
	char buf[1024];
	FILE *fcs;
	char **av;
	int ac;

	AN(cli);

	sb = VSB_new_auto();
	XXXAN(sb);

	INIT_OBJ(&vp, VCC_PRIV_MAGIC);
	vp.vclsrc = vclsrc;
	vp.vclsrcfile = vclsrcfile;

	/*
	 * The subdirectory must have a unique name to 100% certain evade
	 * the refcounting semantics of dlopen(3).
	 *
	 * Bad implementations of dlopen(3) think the shlib you are opening
	 * is the same, if the filename is the same as one already opened.
	 *
	 * Sensible implementations do a stat(2) and requires st_ino and
	 * st_dev to also match.
	 *
	 * A correct implementation would run on filesystems which tickle
	 * st_gen, and also insist that be the identical, before declaring
	 * a match.
	 *
	 * Since no correct implementations are known to exist, we are subject
	 * to really interesting races if you do something like:
	 *
	 *	(running on 'boot' vcl)
	 *	vcl.load foo /foo.vcl
	 *	vcl.use foo
	 *	few/slow requests
	 *	vcl.use boot
	 *	vcl.discard foo
	 *	vcl.load foo /foo.vcl	// dlopen(3) says "same-same"
	 *	vcl.use foo
	 *
	 * Because discard of the first 'foo' lingers on non-zero reference
	 * count, and when it finally runs, it trashes the second 'foo' because
	 * dlopen(3) decided they were really the same thing.
	 *
	 * The Best way to reproduce this is to have regexps in the VCL.
	 */
	VSB_printf(sb, "vcl_%s.%.9f", vclname, VTIM_real());
	AZ(VSB_finish(sb));
	vp.dir = strdup(VSB_data(sb));
	AN(vp.dir);

	if (VJ_make_subdir(vp.dir, "VCL", cli->sb)) {
		free(vp.dir);
		VSB_destroy(&sb);
		VCLI_Out(cli, "VCL compilation failed");
		VCLI_SetResult(cli, CLIS_PARAM);
		return (NULL);
	}

	VSB_clear(sb);
	VSB_printf(sb, "%s/%s", vp.dir, VGC_SRC);
	AZ(VSB_finish(sb));
	vp.csrcfile = strdup(VSB_data(sb));
	AN(vp.csrcfile);
	VSB_clear(sb);

	VSB_printf(sb, "%s/%s", vp.dir, VGC_LIB);
	AZ(VSB_finish(sb));
	vp.libfile = strdup(VSB_data(sb));
	AN(vp.csrcfile);
	VSB_clear(sb);

	status = mgt_vcc_compile(&vp, sb, C_flag);

	AZ(VSB_finish(sb));
	if (VSB_len(sb) > 0)
		VCLI_Out(cli, "%s", VSB_data(sb));
	VSB_destroy(&sb);

	if (status || C_flag) {
		(void)unlink(vp.csrcfile);
		free(vp.csrcfile);
		(void)unlink(vp.libfile);
		free(vp.libfile);
		(void)rmdir(vp.dir);
		free(vp.dir);
		if (status) {
			VCLI_Out(cli, "VCL compilation failed");
			VCLI_SetResult(cli, CLIS_PARAM);
		}
		return (NULL);
	}

	fcs = fopen(vp.csrcfile, "r");
	AN(fcs);
	while (1) {
		AN(fgets(buf, sizeof buf, fcs));
		if (memcmp(buf, VCC_INFO_PREFIX, strlen(VCC_INFO_PREFIX)))
			break;
		av = VAV_Parse(buf, &ac, 0);
		AN(av);
		AZ(av[0]);
		AZ(strcmp(av[1], "/*"));
		AZ(strcmp(av[ac-1], "*/"));
		if (!strcmp(av[3], "VCL"))
			mgt_vcl_depends(vcl, av[4]);
		else if (!strcmp(av[3], "VMOD"))
			mgt_vcl_vmod(vcl, av[4], av[5]);
		else
			WRONG("Wrong VCCINFO");
		VAV_Free(av);
	}
	AZ(fclose(fcs));

	(void)unlink(vp.csrcfile);
	free(vp.csrcfile);

	free(vp.dir);

	VCLI_Out(cli, "VCL compiled.\n");

	return (vp.libfile);
}