Commit 8679b351 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Add support for authenticating CLI telnet connections



git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@3865 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent ccf0939d
......@@ -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);
......
......@@ -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 @@ 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)
{
......
......@@ -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();
......
......@@ -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 @@ 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,
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment