| | varnish-cache/bin/varnishd/mgt/mgt_cli.c |
| 0 |
|
/*- |
| 1 |
|
* Copyright (c) 2006 Verdens Gang AS |
| 2 |
|
* Copyright (c) 2006-2011 Varnish Software AS |
| 3 |
|
* All rights reserved. |
| 4 |
|
* |
| 5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
| 6 |
|
* |
| 7 |
|
* SPDX-License-Identifier: BSD-2-Clause |
| 8 |
|
* |
| 9 |
|
* Redistribution and use in source and binary forms, with or without |
| 10 |
|
* modification, are permitted provided that the following conditions |
| 11 |
|
* are met: |
| 12 |
|
* 1. Redistributions of source code must retain the above copyright |
| 13 |
|
* notice, this list of conditions and the following disclaimer. |
| 14 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
| 15 |
|
* notice, this list of conditions and the following disclaimer in the |
| 16 |
|
* documentation and/or other materials provided with the distribution. |
| 17 |
|
* |
| 18 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 19 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 20 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 21 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
| 22 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 23 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 24 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 25 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 26 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 27 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 28 |
|
* SUCH DAMAGE. |
| 29 |
|
* |
| 30 |
|
* The management process' CLI handling |
| 31 |
|
*/ |
| 32 |
|
|
| 33 |
|
#include "config.h" |
| 34 |
|
|
| 35 |
|
#include <sys/types.h> |
| 36 |
|
#include <sys/socket.h> |
| 37 |
|
|
| 38 |
|
#include <fcntl.h> |
| 39 |
|
#include <poll.h> |
| 40 |
|
#include <signal.h> |
| 41 |
|
#include <stdarg.h> |
| 42 |
|
#include <stdio.h> |
| 43 |
|
#include <stdlib.h> |
| 44 |
|
#include <string.h> |
| 45 |
|
#include <unistd.h> |
| 46 |
|
|
| 47 |
|
#include "mgt/mgt.h" |
| 48 |
|
#include "common/heritage.h" |
| 49 |
|
|
| 50 |
|
#include "vcli_serve.h" |
| 51 |
|
#include "vev.h" |
| 52 |
|
#include "vrnd.h" |
| 53 |
|
#include "vsa.h" |
| 54 |
|
#include "vss.h" |
| 55 |
|
#include "vtcp.h" |
| 56 |
|
|
| 57 |
|
#define CLI_CMD(U,l,s,h,d,m,M) \ |
| 58 |
|
const struct cli_cmd_desc CLICMD_##U[1] = {{ l, s, h, d, m, M }}; |
| 59 |
|
#include "tbl/cli_cmds.h" |
| 60 |
|
|
| 61 |
|
static const struct cli_cmd_desc *cmds[] = { |
| 62 |
|
#define CLI_CMD(U,l,s,h,d,m,M) CLICMD_##U, |
| 63 |
|
#include "tbl/cli_cmds.h" |
| 64 |
|
}; |
| 65 |
|
|
| 66 |
|
static const int ncmds = vcountof(cmds); |
| 67 |
|
|
| 68 |
|
static int cli_i = -1, cli_o = -1; |
| 69 |
|
struct VCLS *mgt_cls; |
| 70 |
|
static const char *secret_file; |
| 71 |
|
|
| 72 |
|
static struct vsb *cli_buf = NULL; |
| 73 |
|
|
| 74 |
|
/*--------------------------------------------------------------------*/ |
| 75 |
|
|
| 76 |
|
static void v_matchproto_(cli_func_t) |
| 77 |
78840 |
mcf_banner(struct cli *cli, const char *const *av, void *priv) |
| 78 |
|
{ |
| 79 |
|
|
| 80 |
78840 |
(void)av; |
| 81 |
78840 |
(void)priv; |
| 82 |
78840 |
VCLI_Out(cli, "-----------------------------\n"); |
| 83 |
78840 |
VCLI_Out(cli, "Varnish Cache CLI 1.0\n"); |
| 84 |
78840 |
VCLI_Out(cli, "-----------------------------\n"); |
| 85 |
78840 |
VCLI_Out(cli, "%s\n", VSB_data(vident) + 1); |
| 86 |
78840 |
VCLI_Out(cli, "%s\n", VCS_String("V")); |
| 87 |
78840 |
VCLI_Out(cli, "\n"); |
| 88 |
78840 |
VCLI_Out(cli, "Type 'help' for command list.\n"); |
| 89 |
78840 |
VCLI_Out(cli, "Type 'quit' to close CLI session.\n"); |
| 90 |
78840 |
if (!MCH_Running()) |
| 91 |
77560 |
VCLI_Out(cli, "Type 'start' to launch worker process.\n"); |
| 92 |
78840 |
VCLI_SetResult(cli, CLIS_OK); |
| 93 |
78840 |
} |
| 94 |
|
|
| 95 |
|
/*--------------------------------------------------------------------*/ |
| 96 |
|
|
| 97 |
|
static struct cli_proto cli_proto[] = { |
| 98 |
|
{ CLICMD_BANNER, "", mcf_banner }, |
| 99 |
|
{ NULL } |
| 100 |
|
}; |
| 101 |
|
|
| 102 |
|
/*--------------------------------------------------------------------*/ |
| 103 |
|
|
| 104 |
|
static void v_noreturn_ v_matchproto_(cli_func_t) |
| 105 |
0 |
mcf_panic(struct cli *cli, const char * const *av, void *priv) |
| 106 |
|
{ |
| 107 |
|
|
| 108 |
0 |
(void)cli; |
| 109 |
0 |
(void)av; |
| 110 |
0 |
(void)priv; |
| 111 |
0 |
v_gcov_flush(); |
| 112 |
0 |
AZ(strcmp("", "You asked for it")); |
| 113 |
|
/* NOTREACHED */ |
| 114 |
0 |
abort(); |
| 115 |
|
} |
| 116 |
|
|
| 117 |
|
static struct cli_proto cli_debug[] = { |
| 118 |
|
{ CLICMD_DEBUG_PANIC_MASTER, "d", mcf_panic }, |
| 119 |
|
{ NULL } |
| 120 |
|
}; |
| 121 |
|
|
| 122 |
|
/*--------------------------------------------------------------------*/ |
| 123 |
|
|
| 124 |
|
static void v_matchproto_(cli_func_t) |
| 125 |
166240 |
mcf_askchild(struct cli *cli, const char * const *av, void *priv) |
| 126 |
|
{ |
| 127 |
|
int i; |
| 128 |
|
char *q; |
| 129 |
|
unsigned u; |
| 130 |
|
|
| 131 |
166240 |
(void)priv; |
| 132 |
|
/* |
| 133 |
|
* Command not recognized in master, try cacher if it is |
| 134 |
|
* running. |
| 135 |
|
*/ |
| 136 |
166240 |
if (cli_o <= 0) { |
| 137 |
2720 |
VCLI_SetResult(cli, CLIS_UNKNOWN); |
| 138 |
2720 |
VCLI_Out(cli, |
| 139 |
|
"Unknown request in manager process " |
| 140 |
|
"(child not running).\n" |
| 141 |
|
"Type 'help' for more info."); |
| 142 |
2720 |
return; |
| 143 |
|
} |
| 144 |
163520 |
VSB_clear(cli_buf); |
| 145 |
384960 |
for (i = 1; av[i] != NULL; i++) { |
| 146 |
221440 |
VSB_quote(cli_buf, av[i], strlen(av[i]), 0); |
| 147 |
221440 |
VSB_putc(cli_buf, ' '); |
| 148 |
221440 |
} |
| 149 |
163520 |
VSB_putc(cli_buf, '\n'); |
| 150 |
163520 |
AZ(VSB_finish(cli_buf)); |
| 151 |
163520 |
if (VSB_tofile(cli_buf, cli_o)) { |
| 152 |
0 |
VCLI_SetResult(cli, CLIS_COMMS); |
| 153 |
0 |
VCLI_Out(cli, "CLI communication error"); |
| 154 |
0 |
MCH_Cli_Fail(); |
| 155 |
0 |
return; |
| 156 |
|
} |
| 157 |
163520 |
if (VCLI_ReadResult(cli_i, &u, &q, mgt_param.cli_timeout)) |
| 158 |
40 |
MCH_Cli_Fail(); |
| 159 |
163520 |
VCLI_SetResult(cli, u); |
| 160 |
163520 |
VCLI_Out(cli, "%s", q); |
| 161 |
163520 |
free(q); |
| 162 |
166240 |
} |
| 163 |
|
|
| 164 |
|
static const struct cli_cmd_desc CLICMD_WILDCARD[1] = |
| 165 |
|
{{ "*", "<wild-card-entry>", "<fall through to cacher>", "", 0, 999 }}; |
| 166 |
|
|
| 167 |
|
static struct cli_proto cli_askchild[] = { |
| 168 |
|
{ CLICMD_WILDCARD, "h*", mcf_askchild, mcf_askchild }, |
| 169 |
|
{ NULL } |
| 170 |
|
}; |
| 171 |
|
|
| 172 |
|
/*-------------------------------------------------------------------- |
| 173 |
|
* Ask the child something over CLI, return zero only if everything is |
| 174 |
|
* happy happy. |
| 175 |
|
*/ |
| 176 |
|
|
| 177 |
|
int |
| 178 |
151296 |
mgt_cli_askchild(unsigned *status, char **resp, const char *fmt, ...) |
| 179 |
|
{ |
| 180 |
|
int i; |
| 181 |
|
va_list ap; |
| 182 |
|
unsigned u; |
| 183 |
|
|
| 184 |
151296 |
AN(status); |
| 185 |
151296 |
VSB_clear(cli_buf); |
| 186 |
|
|
| 187 |
151296 |
if (resp != NULL) |
| 188 |
151296 |
*resp = NULL; |
| 189 |
151296 |
*status = 0; |
| 190 |
151296 |
if (cli_i < 0 || cli_o < 0) { |
| 191 |
0 |
*status = CLIS_CANT; |
| 192 |
0 |
return (CLIS_CANT); |
| 193 |
|
} |
| 194 |
151296 |
va_start(ap, fmt); |
| 195 |
151296 |
AZ(VSB_vprintf(cli_buf, fmt, ap)); |
| 196 |
151296 |
va_end(ap); |
| 197 |
151296 |
AZ(VSB_finish(cli_buf)); |
| 198 |
151296 |
i = VSB_len(cli_buf); |
| 199 |
151296 |
assert(i > 0 && VSB_data(cli_buf)[i - 1] == '\n'); |
| 200 |
151296 |
if (VSB_tofile(cli_buf, cli_o)) { |
| 201 |
0 |
*status = CLIS_COMMS; |
| 202 |
0 |
if (resp != NULL) |
| 203 |
0 |
*resp = strdup("CLI communication error"); |
| 204 |
0 |
MCH_Cli_Fail(); |
| 205 |
0 |
return (CLIS_COMMS); |
| 206 |
|
} |
| 207 |
|
|
| 208 |
151296 |
if (VCLI_ReadResult(cli_i, &u, resp, mgt_param.cli_timeout)) |
| 209 |
40 |
MCH_Cli_Fail(); |
| 210 |
151296 |
*status = u; |
| 211 |
151296 |
return (u == CLIS_OK || u == CLIS_TRUNCATED ? 0 : u); |
| 212 |
151296 |
} |
| 213 |
|
|
| 214 |
|
/*--------------------------------------------------------------------*/ |
| 215 |
|
|
| 216 |
|
unsigned |
| 217 |
39080 |
mgt_cli_start_child(int fd, double tmo) |
| 218 |
|
{ |
| 219 |
|
unsigned u; |
| 220 |
|
|
| 221 |
39080 |
cli_i = fd; |
| 222 |
39080 |
cli_o = fd; |
| 223 |
39080 |
if (VCLI_ReadResult(cli_i, &u, NULL, tmo)) { |
| 224 |
440 |
return (CLIS_COMMS); |
| 225 |
|
} |
| 226 |
38640 |
return (u); |
| 227 |
39080 |
} |
| 228 |
|
|
| 229 |
|
/*--------------------------------------------------------------------*/ |
| 230 |
|
|
| 231 |
|
void |
| 232 |
39080 |
mgt_cli_stop_child(void) |
| 233 |
|
{ |
| 234 |
|
|
| 235 |
39080 |
cli_i = -1; |
| 236 |
39080 |
cli_o = -1; |
| 237 |
|
/* XXX: kick any users */ |
| 238 |
39080 |
} |
| 239 |
|
|
| 240 |
|
/*-------------------------------------------------------------------- |
| 241 |
|
* Generate a random challenge |
| 242 |
|
*/ |
| 243 |
|
|
| 244 |
|
static void |
| 245 |
40080 |
mgt_cli_challenge(struct cli *cli) |
| 246 |
|
{ |
| 247 |
|
size_t z; |
| 248 |
|
uint8_t u; |
| 249 |
|
|
| 250 |
40080 |
AZ(VRND_RandomCrypto(cli->challenge, sizeof cli->challenge - 2)); |
| 251 |
1322640 |
for (z = 0; z < (sizeof cli->challenge) - 2; z++) { |
| 252 |
1282560 |
AZ(VRND_RandomCrypto(&u, sizeof u)); |
| 253 |
1282560 |
cli->challenge[z] = (u % 26) + 'a'; |
| 254 |
1282560 |
} |
| 255 |
40080 |
cli->challenge[z++] = '\n'; |
| 256 |
40080 |
cli->challenge[z] = '\0'; |
| 257 |
40080 |
VCLI_Out(cli, "%s", cli->challenge); |
| 258 |
40080 |
VCLI_Out(cli, "\nAuthentication required.\n"); |
| 259 |
40080 |
VCLI_SetResult(cli, CLIS_AUTH); |
| 260 |
40080 |
} |
| 261 |
|
|
| 262 |
|
/*-------------------------------------------------------------------- |
| 263 |
|
* Validate the authentication |
| 264 |
|
*/ |
| 265 |
|
|
| 266 |
|
static void |
| 267 |
40080 |
mcf_auth(struct cli *cli, const char *const *av, void *priv) |
| 268 |
|
{ |
| 269 |
|
int fd; |
| 270 |
|
char buf[CLI_AUTH_RESPONSE_LEN + 1]; |
| 271 |
|
|
| 272 |
40080 |
AN(av[2]); |
| 273 |
40080 |
(void)priv; |
| 274 |
40080 |
if (secret_file == NULL) { |
| 275 |
0 |
VCLI_Out(cli, "Secret file not configured\n"); |
| 276 |
0 |
VCLI_SetResult(cli, CLIS_CANT); |
| 277 |
0 |
return; |
| 278 |
|
} |
| 279 |
40080 |
VJ_master(JAIL_MASTER_FILE); |
| 280 |
40080 |
fd = open(secret_file, O_RDONLY); |
| 281 |
40080 |
if (fd < 0) { |
| 282 |
0 |
VCLI_Out(cli, "Cannot open secret file (%s)\n", |
| 283 |
0 |
VAS_errtxt(errno)); |
| 284 |
0 |
VCLI_SetResult(cli, CLIS_CANT); |
| 285 |
0 |
VJ_master(JAIL_MASTER_LOW); |
| 286 |
0 |
return; |
| 287 |
|
} |
| 288 |
40080 |
VJ_master(JAIL_MASTER_LOW); |
| 289 |
40080 |
MCH_TrackHighFd(fd); |
| 290 |
40080 |
VCLI_AuthResponse(fd, cli->challenge, buf); |
| 291 |
40080 |
closefd(&fd); |
| 292 |
40080 |
if (strcasecmp(buf, av[2])) { |
| 293 |
0 |
MGT_Complain(C_SECURITY, |
| 294 |
0 |
"CLI Authentication failure from %s", cli->ident); |
| 295 |
0 |
VCLI_SetResult(cli, CLIS_CLOSE); |
| 296 |
0 |
return; |
| 297 |
|
} |
| 298 |
40080 |
cli->auth = MCF_AUTH; |
| 299 |
40080 |
memset(cli->challenge, 0, sizeof cli->challenge); |
| 300 |
40080 |
VCLI_SetResult(cli, CLIS_OK); |
| 301 |
40080 |
mcf_banner(cli, av, priv); |
| 302 |
40080 |
} |
| 303 |
|
|
| 304 |
|
/*--------------------------------------------------------------------*/ |
| 305 |
|
|
| 306 |
|
static void v_matchproto_(cli_func_t) |
| 307 |
840 |
mcf_help(struct cli *cli, const char * const *av, void *priv) |
| 308 |
|
{ |
| 309 |
840 |
if (cli_o <= 0) |
| 310 |
560 |
VCLS_func_help(cli, av, priv); |
| 311 |
|
else |
| 312 |
280 |
mcf_askchild(cli, av, priv); |
| 313 |
840 |
} |
| 314 |
|
|
| 315 |
|
static void v_matchproto_(cli_func_t) |
| 316 |
280 |
mcf_help_json(struct cli *cli, const char * const *av, void *priv) |
| 317 |
|
{ |
| 318 |
280 |
if (cli_o <= 0) |
| 319 |
0 |
VCLS_func_help_json(cli, av, priv); |
| 320 |
|
else |
| 321 |
280 |
mcf_askchild(cli, av, priv); |
| 322 |
280 |
} |
| 323 |
|
|
| 324 |
|
static struct cli_proto cli_auth[] = { |
| 325 |
|
{ CLICMD_HELP, "", mcf_help, mcf_help_json }, |
| 326 |
|
{ CLICMD_PING, "", VCLS_func_ping, VCLS_func_ping_json }, |
| 327 |
|
{ CLICMD_AUTH, "", mcf_auth }, |
| 328 |
|
{ CLICMD_QUIT, "", VCLS_func_close }, |
| 329 |
|
{ NULL } |
| 330 |
|
}; |
| 331 |
|
|
| 332 |
|
/*--------------------------------------------------------------------*/ |
| 333 |
|
|
| 334 |
|
static void |
| 335 |
551200 |
mgt_cli_cb_before(const struct cli *cli) |
| 336 |
|
{ |
| 337 |
|
|
| 338 |
551200 |
if (cli->priv == stderr) |
| 339 |
160 |
fprintf(stderr, "> %s\n", VSB_data(cli->cmd)); |
| 340 |
551200 |
MGT_Complain(C_CLI, "CLI %s Rd %s", cli->ident, VSB_data(cli->cmd)); |
| 341 |
551200 |
} |
| 342 |
|
|
| 343 |
|
static void |
| 344 |
551280 |
mgt_cli_cb_after(const struct cli *cli) |
| 345 |
|
{ |
| 346 |
|
|
| 347 |
551280 |
MGT_Complain(C_CLI, "CLI %s Wr %03u %s", |
| 348 |
551280 |
cli->ident, cli->result, VSB_data(cli->sb)); |
| 349 |
551280 |
if (cli->priv != stderr) |
| 350 |
551040 |
return; |
| 351 |
240 |
if (cli->result == CLIS_TRUNCATED) |
| 352 |
80 |
ARGV_ERR("-I file had incomplete CLI command at the end\n"); |
| 353 |
160 |
if (cli->result != CLIS_OK && *VSB_data(cli->cmd) != '-') { |
| 354 |
40 |
ARGV_ERR("-I file CLI command failed (%d)\n%s\n", |
| 355 |
|
cli->result, VSB_data(cli->sb)); |
| 356 |
0 |
} |
| 357 |
551160 |
} |
| 358 |
|
|
| 359 |
|
/*--------------------------------------------------------------------*/ |
| 360 |
|
|
| 361 |
|
void |
| 362 |
42200 |
mgt_cli_init_cls(void) |
| 363 |
|
{ |
| 364 |
|
|
| 365 |
42200 |
mgt_cls = VCLS_New(NULL); |
| 366 |
42200 |
AN(mgt_cls); |
| 367 |
42200 |
VCLS_SetHooks(mgt_cls, mgt_cli_cb_before, mgt_cli_cb_after); |
| 368 |
42200 |
VCLS_AddFunc(mgt_cls, MCF_NOAUTH, cli_auth); |
| 369 |
42200 |
VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_proto); |
| 370 |
42200 |
VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_debug); |
| 371 |
42200 |
VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_askchild); |
| 372 |
42200 |
cli_buf = VSB_new_auto(); |
| 373 |
42200 |
AN(cli_buf); |
| 374 |
42200 |
} |
| 375 |
|
|
| 376 |
|
/*-------------------------------------------------------------------- |
| 377 |
|
* Get rid of all CLI sessions |
| 378 |
|
*/ |
| 379 |
|
|
| 380 |
|
void |
| 381 |
38600 |
mgt_cli_close_all(void) |
| 382 |
|
{ |
| 383 |
|
|
| 384 |
38600 |
VCLS_Destroy(&mgt_cls); |
| 385 |
38600 |
} |
| 386 |
|
|
| 387 |
|
/*-------------------------------------------------------------------- |
| 388 |
|
* Callback whenever something happens to the input fd of the session. |
| 389 |
|
*/ |
| 390 |
|
|
| 391 |
|
static int |
| 392 |
1132656 |
mgt_cli_callback2(const struct vev *e, int what) |
| 393 |
|
{ |
| 394 |
|
int i; |
| 395 |
|
|
| 396 |
1132656 |
(void)what; |
| 397 |
1132656 |
i = VCLS_Poll(mgt_cls, e->priv, 0); |
| 398 |
1132656 |
return (i); |
| 399 |
|
} |
| 400 |
|
|
| 401 |
|
/*--------------------------------------------------------------------*/ |
| 402 |
|
|
| 403 |
|
void |
| 404 |
78800 |
mgt_cli_setup(int fdi, int fdo, int auth, const char *ident, |
| 405 |
|
mgt_cli_close_f *closefunc, void *priv) |
| 406 |
|
{ |
| 407 |
|
struct cli *cli; |
| 408 |
|
struct vev *ev; |
| 409 |
|
|
| 410 |
78800 |
cli = VCLS_AddFd(mgt_cls, fdi, fdo, closefunc, priv); |
| 411 |
|
|
| 412 |
78800 |
REPLACE(cli->ident, ident); |
| 413 |
|
|
| 414 |
78800 |
if (!auth && secret_file != NULL) { |
| 415 |
40080 |
cli->auth = MCF_NOAUTH; |
| 416 |
40080 |
mgt_cli_challenge(cli); |
| 417 |
40080 |
} else { |
| 418 |
38720 |
cli->auth = MCF_AUTH; |
| 419 |
38720 |
mcf_banner(cli, NULL, NULL); |
| 420 |
|
} |
| 421 |
78800 |
AZ(VSB_finish(cli->sb)); |
| 422 |
78800 |
(void)VCLI_WriteResult(fdo, cli->result, VSB_data(cli->sb)); |
| 423 |
|
|
| 424 |
78800 |
ev = VEV_Alloc(); |
| 425 |
78800 |
AN(ev); |
| 426 |
78800 |
ev->name = cli->ident; |
| 427 |
78800 |
ev->fd = fdi; |
| 428 |
78800 |
ev->fd_flags = VEV__RD; |
| 429 |
78800 |
ev->callback = mgt_cli_callback2; |
| 430 |
78800 |
ev->priv = cli; |
| 431 |
78800 |
AZ(VEV_Start(mgt_evb, ev)); |
| 432 |
78800 |
} |
| 433 |
|
|
| 434 |
|
/*--------------------------------------------------------------------*/ |
| 435 |
|
|
| 436 |
|
static struct vsb * |
| 437 |
40080 |
sock_id(const char *pfx, int fd) |
| 438 |
|
{ |
| 439 |
|
struct vsb *vsb; |
| 440 |
|
|
| 441 |
|
char abuf1[VTCP_ADDRBUFSIZE], abuf2[VTCP_ADDRBUFSIZE]; |
| 442 |
|
char pbuf1[VTCP_PORTBUFSIZE], pbuf2[VTCP_PORTBUFSIZE]; |
| 443 |
|
|
| 444 |
40080 |
vsb = VSB_new_auto(); |
| 445 |
40080 |
AN(vsb); |
| 446 |
40080 |
VTCP_myname(fd, abuf1, sizeof abuf1, pbuf1, sizeof pbuf1); |
| 447 |
40080 |
VTCP_hisname(fd, abuf2, sizeof abuf2, pbuf2, sizeof pbuf2); |
| 448 |
40080 |
VSB_printf(vsb, "%s %s %s %s %s", pfx, abuf2, pbuf2, abuf1, pbuf1); |
| 449 |
40080 |
AZ(VSB_finish(vsb)); |
| 450 |
40080 |
return (vsb); |
| 451 |
|
} |
| 452 |
|
|
| 453 |
|
/*--------------------------------------------------------------------*/ |
| 454 |
|
|
| 455 |
|
static int |
| 456 |
1640 |
telnet_accept(const struct vev *ev, int what) |
| 457 |
|
{ |
| 458 |
|
struct vsb *vsb; |
| 459 |
|
int i; |
| 460 |
|
|
| 461 |
1640 |
(void)what; |
| 462 |
1640 |
i = accept(ev->fd, NULL, NULL); |
| 463 |
1640 |
if (i < 0 && errno == EBADF) |
| 464 |
0 |
return (1); |
| 465 |
1640 |
if (i < 0) |
| 466 |
0 |
return (0); |
| 467 |
|
|
| 468 |
1640 |
MCH_TrackHighFd(i); |
| 469 |
1640 |
vsb = sock_id("telnet", i); |
| 470 |
1640 |
mgt_cli_setup(i, i, 0, VSB_data(vsb), NULL, NULL); |
| 471 |
1640 |
VSB_destroy(&vsb); |
| 472 |
1640 |
return (0); |
| 473 |
1640 |
} |
| 474 |
|
|
| 475 |
|
void |
| 476 |
39040 |
mgt_cli_secret(const char *S_arg) |
| 477 |
|
{ |
| 478 |
|
int i, fd; |
| 479 |
|
char buf[BUFSIZ]; |
| 480 |
|
|
| 481 |
|
/* Save in shmem */ |
| 482 |
39040 |
mgt_SHM_static_alloc(S_arg, strlen(S_arg) + 1L, "Arg", "-S"); |
| 483 |
|
|
| 484 |
39040 |
VJ_master(JAIL_MASTER_FILE); |
| 485 |
39040 |
fd = open(S_arg, O_RDONLY); |
| 486 |
39040 |
if (fd < 0) { |
| 487 |
0 |
fprintf(stderr, "Cannot open secret-file \"%s\"\n", S_arg); |
| 488 |
0 |
exit(2); |
| 489 |
|
} |
| 490 |
39040 |
VJ_master(JAIL_MASTER_LOW); |
| 491 |
39040 |
MCH_TrackHighFd(fd); |
| 492 |
39040 |
i = read(fd, buf, sizeof buf); |
| 493 |
39040 |
if (i == 0) { |
| 494 |
0 |
fprintf(stderr, "Empty secret-file \"%s\"\n", S_arg); |
| 495 |
0 |
exit(2); |
| 496 |
|
} |
| 497 |
39040 |
if (i < 0) { |
| 498 |
0 |
fprintf(stderr, "Cannot read secret-file \"%s\"\n", S_arg); |
| 499 |
0 |
exit(2); |
| 500 |
|
} |
| 501 |
39040 |
closefd(&fd); |
| 502 |
39040 |
secret_file = S_arg; |
| 503 |
39040 |
} |
| 504 |
|
|
| 505 |
|
static int v_matchproto_(vss_resolved_f) |
| 506 |
78160 |
mct_callback(void *priv, const struct suckaddr *sa) |
| 507 |
|
{ |
| 508 |
|
int sock; |
| 509 |
78160 |
struct vsb *vsb = priv; |
| 510 |
|
const char *err; |
| 511 |
|
char abuf[VTCP_ADDRBUFSIZE]; |
| 512 |
|
char pbuf[VTCP_PORTBUFSIZE]; |
| 513 |
|
struct vev *ev; |
| 514 |
|
|
| 515 |
78160 |
VJ_master(JAIL_MASTER_PRIVPORT); |
| 516 |
78160 |
sock = VTCP_listen(sa, 10, &err); |
| 517 |
78160 |
VJ_master(JAIL_MASTER_LOW); |
| 518 |
78160 |
assert(sock != 0); // We know where stdin is |
| 519 |
78160 |
if (sock > 0) { |
| 520 |
78160 |
VTCP_myname(sock, abuf, sizeof abuf, pbuf, sizeof pbuf); |
| 521 |
78160 |
VSB_printf(vsb, "%s %s\n", abuf, pbuf); |
| 522 |
78160 |
ev = VEV_Alloc(); |
| 523 |
78160 |
AN(ev); |
| 524 |
78160 |
ev->fd = sock; |
| 525 |
78160 |
ev->fd_flags = POLLIN; |
| 526 |
78160 |
ev->callback = telnet_accept; |
| 527 |
78160 |
AZ(VEV_Start(mgt_evb, ev)); |
| 528 |
78160 |
} |
| 529 |
78160 |
return (0); |
| 530 |
|
} |
| 531 |
|
|
| 532 |
|
void |
| 533 |
39080 |
mgt_cli_telnet(const char *T_arg) |
| 534 |
|
{ |
| 535 |
|
int error; |
| 536 |
|
const char *err; |
| 537 |
|
struct vsb *vsb; |
| 538 |
|
|
| 539 |
39080 |
AN(T_arg); |
| 540 |
39080 |
vsb = VSB_new_auto(); |
| 541 |
39080 |
AN(vsb); |
| 542 |
39080 |
error = VSS_resolver(T_arg, NULL, mct_callback, vsb, &err); |
| 543 |
39080 |
if (err != NULL) |
| 544 |
0 |
ARGV_ERR("Could not resolve -T argument to address\n\t%s\n", |
| 545 |
|
err); |
| 546 |
39080 |
AZ(error); |
| 547 |
39080 |
AZ(VSB_finish(vsb)); |
| 548 |
39080 |
if (VSB_len(vsb) == 0) |
| 549 |
0 |
ARGV_ERR("-T %s could not be listened on.\n", T_arg); |
| 550 |
|
/* Save in shmem */ |
| 551 |
39080 |
mgt_SHM_static_alloc(VSB_data(vsb), VSB_len(vsb) + 1, "Arg", "-T"); |
| 552 |
39080 |
VSB_destroy(&vsb); |
| 553 |
39080 |
} |
| 554 |
|
|
| 555 |
|
/* Reverse CLI ("Master") connections --------------------------------*/ |
| 556 |
|
|
| 557 |
|
struct m_addr { |
| 558 |
|
unsigned magic; |
| 559 |
|
#define M_ADDR_MAGIC 0xbc6217ed |
| 560 |
|
const struct suckaddr *sa; |
| 561 |
|
VTAILQ_ENTRY(m_addr) list; |
| 562 |
|
}; |
| 563 |
|
|
| 564 |
|
static int M_fd = -1; |
| 565 |
|
static struct vev *M_poker, *M_conn; |
| 566 |
|
static double M_poll = 0.1; |
| 567 |
|
|
| 568 |
|
static VTAILQ_HEAD(,m_addr) m_addr_list = |
| 569 |
|
VTAILQ_HEAD_INITIALIZER(m_addr_list); |
| 570 |
|
|
| 571 |
|
static int v_matchproto_(mgt_cli_close_f) |
| 572 |
38440 |
Marg_closer(void *priv) |
| 573 |
|
{ |
| 574 |
|
|
| 575 |
38440 |
(void)priv; |
| 576 |
38440 |
M_fd = -1; |
| 577 |
38440 |
return (0); |
| 578 |
|
} |
| 579 |
|
|
| 580 |
|
static int v_matchproto_(vev_cb_f) |
| 581 |
38440 |
Marg_connect(const struct vev *e, int what) |
| 582 |
|
{ |
| 583 |
|
struct vsb *vsb; |
| 584 |
|
struct m_addr *ma; |
| 585 |
|
|
| 586 |
38440 |
assert(e == M_conn); |
| 587 |
38440 |
(void)what; |
| 588 |
|
|
| 589 |
38440 |
M_fd = VTCP_connected(M_fd); |
| 590 |
38440 |
if (M_fd < 0) { |
| 591 |
0 |
MGT_Complain(C_INFO, "Could not connect to CLI-master: %s", |
| 592 |
0 |
VAS_errtxt(errno)); |
| 593 |
0 |
ma = VTAILQ_FIRST(&m_addr_list); |
| 594 |
0 |
AN(ma); |
| 595 |
0 |
VTAILQ_REMOVE(&m_addr_list, ma, list); |
| 596 |
0 |
VTAILQ_INSERT_TAIL(&m_addr_list, ma, list); |
| 597 |
0 |
if (M_poll < 10) |
| 598 |
0 |
M_poll++; |
| 599 |
0 |
return (1); |
| 600 |
|
} |
| 601 |
38440 |
vsb = sock_id("master", M_fd); |
| 602 |
38440 |
mgt_cli_setup(M_fd, M_fd, 0, VSB_data(vsb), Marg_closer, NULL); |
| 603 |
38440 |
VSB_destroy(&vsb); |
| 604 |
38440 |
M_poll = 1; |
| 605 |
38440 |
return (1); |
| 606 |
38440 |
} |
| 607 |
|
|
| 608 |
|
static int v_matchproto_(vev_cb_f) |
| 609 |
152256 |
Marg_poker(const struct vev *e, int what) |
| 610 |
|
{ |
| 611 |
|
int s; |
| 612 |
|
struct m_addr *ma; |
| 613 |
|
|
| 614 |
152256 |
assert(e == M_poker); |
| 615 |
152256 |
(void)what; |
| 616 |
|
|
| 617 |
152256 |
M_poker->timeout = M_poll; /* XXX nasty ? */ |
| 618 |
152256 |
if (M_fd > 0) |
| 619 |
113816 |
return (0); |
| 620 |
|
|
| 621 |
38440 |
ma = VTAILQ_FIRST(&m_addr_list); |
| 622 |
38440 |
AN(ma); |
| 623 |
|
|
| 624 |
|
/* Try to connect asynchronously */ |
| 625 |
38440 |
s = VTCP_connect(ma->sa, -1); |
| 626 |
38440 |
if (s < 0) |
| 627 |
0 |
return (0); |
| 628 |
|
|
| 629 |
38440 |
MCH_TrackHighFd(s); |
| 630 |
|
|
| 631 |
38440 |
M_conn = VEV_Alloc(); |
| 632 |
38440 |
AN(M_conn); |
| 633 |
38440 |
M_conn->callback = Marg_connect; |
| 634 |
38440 |
M_conn->name = "-M connector"; |
| 635 |
38440 |
M_conn->fd_flags = VEV__WR; |
| 636 |
38440 |
M_conn->fd = s; |
| 637 |
38440 |
M_fd = s; |
| 638 |
38440 |
AZ(VEV_Start(mgt_evb, M_conn)); |
| 639 |
38440 |
return (0); |
| 640 |
152256 |
} |
| 641 |
|
|
| 642 |
|
static int v_matchproto_(vss_resolved_f) |
| 643 |
38440 |
marg_cb(void *priv, const struct suckaddr *sa) |
| 644 |
|
{ |
| 645 |
|
struct m_addr *ma; |
| 646 |
|
|
| 647 |
38440 |
(void)priv; |
| 648 |
38440 |
ALLOC_OBJ(ma, M_ADDR_MAGIC); |
| 649 |
38440 |
AN(ma); |
| 650 |
38440 |
ma->sa = VSA_Clone(sa); |
| 651 |
38440 |
VTAILQ_INSERT_TAIL(&m_addr_list, ma, list); |
| 652 |
38440 |
return (0); |
| 653 |
|
} |
| 654 |
|
|
| 655 |
|
void |
| 656 |
38440 |
mgt_cli_master(const char *M_arg) |
| 657 |
|
{ |
| 658 |
|
const char *err; |
| 659 |
|
int error; |
| 660 |
|
|
| 661 |
38440 |
AN(M_arg); |
| 662 |
|
|
| 663 |
38440 |
error = VSS_resolver(M_arg, NULL, marg_cb, NULL, &err); |
| 664 |
38440 |
if (err != NULL) |
| 665 |
0 |
ARGV_ERR("Could not resolve -M argument to address\n\t%s\n", |
| 666 |
|
err); |
| 667 |
38440 |
AZ(error); |
| 668 |
38440 |
if (VTAILQ_EMPTY(&m_addr_list)) |
| 669 |
0 |
ARGV_ERR("Could not resolve -M argument to address\n"); |
| 670 |
38440 |
AZ(M_poker); |
| 671 |
38440 |
M_poker = VEV_Alloc(); |
| 672 |
38440 |
AN(M_poker); |
| 673 |
38440 |
M_poker->timeout = M_poll; |
| 674 |
38440 |
M_poker->callback = Marg_poker; |
| 675 |
38440 |
M_poker->name = "-M poker"; |
| 676 |
38440 |
AZ(VEV_Start(mgt_evb, M_poker)); |
| 677 |
38440 |
} |
| 678 |
|
|
| 679 |
|
static int |
| 680 |
14160 |
cli_cmp(const void *a, const void *b) |
| 681 |
|
{ |
| 682 |
14160 |
struct cli_cmd_desc * const * const aa = a; |
| 683 |
14160 |
struct cli_cmd_desc * const * const bb = b; |
| 684 |
|
|
| 685 |
14160 |
return (strcmp((*aa)->request, (*bb)->request)); |
| 686 |
|
} |
| 687 |
|
|
| 688 |
|
void |
| 689 |
80 |
mgt_DumpRstCli(void) |
| 690 |
|
{ |
| 691 |
|
const struct cli_cmd_desc *cp; |
| 692 |
|
const char *p; |
| 693 |
|
int z; |
| 694 |
|
size_t j; |
| 695 |
|
|
| 696 |
80 |
qsort(cmds, ncmds, sizeof cmds[0], cli_cmp); |
| 697 |
3200 |
for (z = 0; z < ncmds; z++, cp++) { |
| 698 |
3120 |
cp = cmds[z]; |
| 699 |
3120 |
if (!strncmp(cp->request, "debug.", 6)) |
| 700 |
800 |
continue; |
| 701 |
2320 |
printf(".. _ref_cli_"); |
| 702 |
20880 |
for (p = cp->request; *p; p++) |
| 703 |
18560 |
fputc(*p == '.' ? '_' : *p, stdout); |
| 704 |
2320 |
printf(":\n\n"); |
| 705 |
2320 |
printf("%s\n", cp->syntax); |
| 706 |
58000 |
for (j = 0; j < strlen(cp->syntax); j++) |
| 707 |
55680 |
printf("~"); |
| 708 |
2320 |
printf("\n"); |
| 709 |
2320 |
printf(" %s\n", cp->help); |
| 710 |
2320 |
if (*cp->doc != '\0') |
| 711 |
1440 |
printf("\n%s\n", cp->doc); |
| 712 |
|
|
| 713 |
2320 |
printf("\n"); |
| 714 |
2320 |
} |
| 715 |
80 |
} |