]> err.no Git - varnish/commitdiff
Add support for authenticating CLI telnet connections
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 3 Mar 2009 11:25:46 +0000 (11:25 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 3 Mar 2009 11:25:46 +0000 (11:25 +0000)
git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3865 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/mgt.h
varnish-cache/bin/varnishd/mgt_cli.c
varnish-cache/bin/varnishd/varnishd.c
varnish-cache/include/cli.h
varnish-cache/include/cli_common.h

index a01a5d6a77f2ea1277739c7b9d5263f92423a1e8..c71a19d0f0a7ca0cbea4ec5f1a82696c5cf36903 100644 (file)
@@ -52,6 +52,7 @@ int mgt_cli_askchild(unsigned *status, char **resp, const char *fmt, ...);
 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);
index a1e64eeed0b8f88139136cec057d3fc9e6f2f271..3068395ebb5d55a13feadd228a4b3cc734c12592 100644 (file)
 #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 @@ struct telnet {
        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 struct cli_proto cli_proto[] = {
 
 /*--------------------------------------------------------------------*/
 
-
 static void
 mcf_panic(struct cli *cli, const char * const *av, void *priv)
 {
@@ -248,20 +262,94 @@ mgt_cli_stop_child(void)
        /* 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 @@ mgt_cli_vlu(void *priv, const char *p)
        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 @@ mgt_cli_setup(int fdi, int fdo, int verbose, const char *ident)
 
        cp->cli->sb = vsb_newauto();
        XXXAN(cp->cli->sb);
-
-       if (params->cli_banner)
+       cp->cli->priv = cp;
+
+       /*
+        * 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 @@ telnet_close_one(int fd)
        }
 }
 
-
 static void
 telnet_close_all()
 {
@@ -489,6 +592,31 @@ telnet_accept(const struct vev *ev, int what)
        return (0);
 }
 
+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)
 {
index 52b3a57007e59f2c9921e892569c51f71352c52f..07cfd7e184d82cd7a4e308abb902871674dc2944 100644 (file)
@@ -207,6 +207,8 @@ usage(void)
        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 @@ main(int argc, char * const *argv)
        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 @@ main(int argc, char * const *argv)
        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 @@ main(int argc, char * const *argv)
                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 @@ main(int argc, char * const *argv)
 
        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();
index 8ff924183cdc40204e485f295cfd1eed38868a1b..f793c979ad14a6f6fae387c81d7c4ad286659ce7 100644 (file)
        "\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 @@ enum cli_status_e {
        CLIS_TOOFEW     = 104,
        CLIS_TOOMANY    = 105,
        CLIS_PARAM      = 106,
+       CLIS_AUTH       = 107,
        CLIS_OK         = 200,
        CLIS_CANT       = 300,
        CLIS_COMMS      = 400,
index 18bed279f9d3a8a00c6713a632e833b3fb98ed2e..1a3a587cd05c01de1efbfca0ec25fe3e0a518ae4 100644 (file)
@@ -33,6 +33,7 @@ struct cli {
        /* XXX: should be MINI_OBJ */
        struct vsb              *sb;
        enum cli_status_e       result;
+       void                    *priv;
 };
 
 int cli_writeres(int fd, const struct cli *cli);