r3865 - in trunk/varnish-cache: bin/varnishd include

phk at projects.linpro.no phk at projects.linpro.no
Tue Mar 3 12:25:46 CET 2009


Author: phk
Date: 2009-03-03 12:25:46 +0100 (Tue, 03 Mar 2009)
New Revision: 3865

Modified:
   trunk/varnish-cache/bin/varnishd/mgt.h
   trunk/varnish-cache/bin/varnishd/mgt_cli.c
   trunk/varnish-cache/bin/varnishd/varnishd.c
   trunk/varnish-cache/include/cli.h
   trunk/varnish-cache/include/cli_common.h
Log:
Add support for authenticating CLI telnet connections



Modified: trunk/varnish-cache/bin/varnishd/mgt.h
===================================================================
--- trunk/varnish-cache/bin/varnishd/mgt.h	2009-03-03 11:18:41 UTC (rev 3864)
+++ trunk/varnish-cache/bin/varnishd/mgt.h	2009-03-03 11:25:46 UTC (rev 3865)
@@ -52,6 +52,7 @@
 void mgt_cli_start_child(int fdi, int fdo);
 void mgt_cli_stop_child(void);
 void mgt_cli_telnet(const char *T_arg);
+void mgt_cli_secret(const char *S_arg);
 
 /* mgt_param.c */
 void MCF_ParamSync(void);

Modified: trunk/varnish-cache/bin/varnishd/mgt_cli.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/mgt_cli.c	2009-03-03 11:18:41 UTC (rev 3864)
+++ trunk/varnish-cache/bin/varnishd/mgt_cli.c	2009-03-03 11:25:46 UTC (rev 3865)
@@ -57,12 +57,14 @@
 #include "mgt.h"
 #include "mgt_cli.h"
 #include "vev.h"
+#include "vsha256.h"
 #include "shmlog.h"
 
 #include "vlu.h"
 #include "vss.h"
 
 static int		cli_i = -1, cli_o = -1;
+static const char	*secret_file;
 
 struct telnet {
 	int			fd;
@@ -70,6 +72,19 @@
 	VTAILQ_ENTRY(telnet)	list;
 };
 
+struct cli_port {
+	unsigned		magic;
+#define CLI_PORT_MAGIC		0x5791079f
+	struct vev		*ev;
+	int			fdi;
+	int			fdo;
+	int			verbose;
+	struct vlu		*vlu;
+	struct cli		cli[1];
+	char			*name;
+	char			challenge[34];
+};
+
 static VTAILQ_HEAD(,telnet)	telnets = VTAILQ_HEAD_INITIALIZER(telnets);
 static void telnet_close_all(void);
 static void telnet_close_one(int fd);
@@ -166,7 +181,6 @@
 
 /*--------------------------------------------------------------------*/
 
-
 static void
 mcf_panic(struct cli *cli, const char * const *av, void *priv)
 {
@@ -248,20 +262,94 @@
 	/* XXX: kick any users */
 }
 
-/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------
+ * Validate the authentication
+ */
 
-struct cli_port {
-	unsigned		magic;
-#define CLI_PORT_MAGIC		0x5791079f
-	struct vev		*ev;
-	int			fdi;
-	int			fdo;
-	int			verbose;
-	struct vlu		*vlu;
-	struct cli		cli[1];
-	char			*name;
+static void
+mcf_auth(struct cli *cli, const char *const *av, void *priv)
+{
+	char buf[1025];
+	int i, fd;
+	struct SHA256Context sha256ctx;
+	unsigned char digest[SHA256_LEN];
+	struct cli_port *cp;
+
+	AN(av[2]);
+	CAST_OBJ_NOTNULL(cp, cli->priv, CLI_PORT_MAGIC);
+	(void)priv;
+	AN(secret_file);
+	fd = open(secret_file, O_RDONLY);
+	if (fd < 0) {
+		cli_out(cli, "Cannot open secret file (%s)\n",
+		    strerror(errno));
+		cli_result(cli, CLIS_CANT);
+		return;
+	}
+	i = read(fd, buf, sizeof buf);
+	if (i == 0) {
+		cli_out(cli, "Empty secret file");
+		cli_result(cli, CLIS_CANT);
+		return;
+	}
+	if (i < 0) {
+		cli_out(cli, "Read error on secret file (%s)\n",
+		    strerror(errno));
+		cli_result(cli, CLIS_CANT);
+		return;
+	}
+	if (i == sizeof buf) {
+		cli_out(cli, "Secret file too long (> %d)\n",
+		    sizeof buf - 1);
+		cli_result(cli, CLIS_CANT);
+		return;
+	}
+	buf[i] = '\0';
+	AZ(close(fd));
+	SHA256_Init(&sha256ctx);
+	SHA256_Update(&sha256ctx, cp->challenge, strlen(cp->challenge));
+	SHA256_Update(&sha256ctx, buf, i);
+	SHA256_Update(&sha256ctx, cp->challenge, strlen(cp->challenge));
+	SHA256_Final(digest, &sha256ctx);
+	for (i = 0; i < SHA256_LEN; i++)
+		sprintf(buf + i + i, "%02x", digest[i]);
+	if (strcasecmp(buf, av[2])) {
+		cli_result(cli, CLIS_UNKNOWN);
+		return;
+	}
+	cp->challenge[0] = '\0';
+	cli_result(cli, CLIS_OK);
+	if (params->cli_banner) 
+		mcf_banner(cli, av, priv);
+}
+
+static struct cli_proto cli_auth[] = {
+	{ CLI_HELP,		mcf_help, cli_auth },
+	{ CLI_AUTH,		mcf_auth, NULL },
+	{ CLI_QUIT,		mcf_close, NULL},
+	{ NULL }
 };
 
+/*--------------------------------------------------------------------
+ * Generate a random challenge
+ */
+
+static void
+mgt_cli_challenge(struct cli_port *cp)
+{
+	int i;
+
+	for (i = 0; i + 2 < sizeof cp->challenge; i++)
+		cp->challenge[i] = (random() % 26) + 'a';
+	cp->challenge[i++] = '\n';
+	cp->challenge[i] = '\0';
+	cli_out(cp->cli, "%s", cp->challenge);
+	cli_out(cp->cli, "\nAuthentication required.\n");
+	cli_result(cp->cli, CLIS_AUTH);
+}
+
+/*--------------------------------------------------------------------*/
+
 static int
 mgt_cli_vlu(void *priv, const char *p)
 {
@@ -281,31 +369,39 @@
 	if (*p == '\0')
 		return (0);
 
-	cli_dispatch(cp->cli, cli_proto, p);
-	if (cp->cli->result == CLIS_UNKNOWN) 
-		cli_dispatch(cp->cli, cli_debug, p);
-	if (cp->cli->result == CLIS_UNKNOWN) {
-		/*
-		 * Command not recognized in master, try cacher if it is
-		 * running.
-		 */
-		vsb_clear(cp->cli->sb);
-		cp->cli->result = CLIS_OK;
-		if (cli_o <= 0) {
-			cli_result(cp->cli, CLIS_UNKNOWN);
-			cli_out(cp->cli,
-			    "Unknown request in manager process "
-			    "(child not running).\n"
-			    "Type 'help' for more info.");
-		} else {
-			i = write(cli_o, p, strlen(p));
-			xxxassert(i == strlen(p));
-			i = write(cli_o, "\n", 1);
-			xxxassert(i == 1);
-			(void)cli_readres(cli_i, &u, &q, params->cli_timeout);
-			cli_result(cp->cli, u);
-			cli_out(cp->cli, "%s", q);
-			free(q);
+	if (secret_file != NULL && cp->challenge[0] != '\0') {
+		/* Authentication not yet passed */
+		cli_dispatch(cp->cli, cli_auth, p);
+		if (cp->cli->result == CLIS_UNKNOWN) 
+			mgt_cli_challenge(cp);
+	} else {
+		cli_dispatch(cp->cli, cli_proto, p);
+		if (cp->cli->result == CLIS_UNKNOWN) 
+			cli_dispatch(cp->cli, cli_debug, p);
+		if (cp->cli->result == CLIS_UNKNOWN) {
+			/*
+			 * Command not recognized in master, try cacher if it is
+			 * running.
+			 */
+			vsb_clear(cp->cli->sb);
+			cp->cli->result = CLIS_OK;
+			if (cli_o <= 0) {
+				cli_result(cp->cli, CLIS_UNKNOWN);
+				cli_out(cp->cli,
+				    "Unknown request in manager process "
+				    "(child not running).\n"
+				    "Type 'help' for more info.");
+			} else {
+				i = write(cli_o, p, strlen(p));
+				xxxassert(i == strlen(p));
+				i = write(cli_o, "\n", 1);
+				xxxassert(i == 1);
+				(void)cli_readres(cli_i,
+				    &u, &q, params->cli_timeout);
+				cli_result(cp->cli, u);
+				cli_out(cp->cli, "%s", q);
+				free(q);
+			}
 		}
 	}
 	vsb_finish(cp->cli->sb);
@@ -403,8 +499,16 @@
 
 	cp->cli->sb = vsb_newauto();
 	XXXAN(cp->cli->sb);
+	cp->cli->priv = cp;
 
-	if (params->cli_banner)
+	/*
+	 * If we have a secret file authenticate all CLI connections
+	 * except the stdin/stdout debug port.
+	 */
+	if (cp->fdi != 0 && secret_file != NULL) {
+		mgt_cli_challenge(cp);
+		(void)VLU_Data("auth -\n", -1, cp->vlu);
+	} else if (params->cli_banner)
 		(void)VLU_Data("banner\n", -1, cp->vlu);
 
 	cp->ev = calloc(sizeof *cp->ev, 1);
@@ -433,7 +537,6 @@
 	}
 }
 
-
 static void
 telnet_close_all()
 {
@@ -490,6 +593,31 @@
 }
 
 void
+mgt_cli_secret(const char *S_arg)
+{
+	int i, fd;
+	char buf[BUFSIZ];
+
+
+	srandomdev();
+	fd = open(S_arg, O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Can not open secret-file \"%s\"\n", S_arg);
+		exit (2);
+	}
+	i = read(fd, buf, sizeof buf);
+	if (i == 0) {
+		fprintf(stderr, "Empty secret-file \"%s\"\n", S_arg);
+		exit (2);
+	}
+	if (i < 0) {
+		fprintf(stderr, "Can not read secret-file \"%s\"\n", S_arg);
+		exit (2);
+	}
+	secret_file = S_arg;
+}
+
+void
 mgt_cli_telnet(const char *T_arg)
 {
 	struct vss_addr **ta;

Modified: trunk/varnish-cache/bin/varnishd/varnishd.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/varnishd.c	2009-03-03 11:18:41 UTC (rev 3864)
+++ trunk/varnish-cache/bin/varnishd/varnishd.c	2009-03-03 11:25:46 UTC (rev 3865)
@@ -207,6 +207,8 @@
 	fprintf(stderr, FMT, "",
 	    "  -s file,<dir_or_file>,<size>,<granularity>");
 	fprintf(stderr, FMT, "-t", "Default TTL");
+	fprintf(stderr, FMT, "-S secret-file",
+	    "Secret file for CLI authentication");
 	fprintf(stderr, FMT, "-T address:port",
 	    "Telnet listen address and port");
 	fprintf(stderr, FMT, "-V", "version");
@@ -404,6 +406,7 @@
 	const char *h_arg = "classic";
 	const char *n_arg = NULL;
 	const char *P_arg = NULL;
+	const char *S_arg = NULL;
 	const char *s_arg = "file";
 	int s_arg_given = 0;
 	const char *T_arg = NULL;
@@ -445,7 +448,7 @@
 	cli_check(cli);
 
 	while ((o = getopt(argc, argv,
-	    "a:b:Cdf:Fg:h:l:n:P:p:s:T:t:u:Vw:")) != -1)
+	    "a:b:Cdf:Fg:h:l:n:P:p:S:s:T:t:u:Vw:")) != -1)
 		switch (o) {
 		case 'a':
 			MCF_ParamSet(cli, "listen_address", optarg);
@@ -497,6 +500,9 @@
 		case 't':
 			MCF_ParamSet(cli, "default_ttl", optarg);
 			break;
+		case 'S':
+			S_arg = optarg;
+			break;
 		case 'T':
 			T_arg = optarg;
 			break;
@@ -617,7 +623,9 @@
 
 	if (d_flag)
 		mgt_cli_setup(0, 1, 1, "debug");
-	if (T_arg)
+	if (S_arg != NULL)
+		mgt_cli_secret(S_arg);
+	if (T_arg != NULL)
 		mgt_cli_telnet(T_arg);
 
 	MGT_Run();

Modified: trunk/varnish-cache/include/cli.h
===================================================================
--- trunk/varnish-cache/include/cli.h	2009-03-03 11:18:41 UTC (rev 3864)
+++ trunk/varnish-cache/include/cli.h	2009-03-03 11:25:46 UTC (rev 3865)
@@ -231,6 +231,12 @@
 	"\tPrint welcome banner.",					\
 	0, 0
 
+#define CLI_AUTH	 						\
+	"auth",								\
+	"auth response",						\
+	"\tAuthenticate.",						\
+	1, 1
+
 #define CLI_HIDDEN(foo, min_arg, max_arg)				\
 	foo, NULL, NULL, min_arg, max_arg,
 
@@ -245,6 +251,7 @@
 	CLIS_TOOFEW	= 104,
 	CLIS_TOOMANY	= 105,
 	CLIS_PARAM	= 106,
+	CLIS_AUTH	= 107,
 	CLIS_OK		= 200,
 	CLIS_CANT	= 300,
 	CLIS_COMMS	= 400,

Modified: trunk/varnish-cache/include/cli_common.h
===================================================================
--- trunk/varnish-cache/include/cli_common.h	2009-03-03 11:18:41 UTC (rev 3864)
+++ trunk/varnish-cache/include/cli_common.h	2009-03-03 11:25:46 UTC (rev 3865)
@@ -33,6 +33,7 @@
 	/* XXX: should be MINI_OBJ */
 	struct vsb		*sb;
 	enum cli_status_e	result;
+	void			*priv;
 };
 
 int cli_writeres(int fd, const struct cli *cli);



More information about the varnish-commit mailing list