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