| | 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 = sizeof cmds / sizeof cmds[0]; |
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 |
76360 |
mcf_banner(struct cli *cli, const char *const *av, void *priv) |
78 |
|
{ |
79 |
|
|
80 |
76360 |
(void)av; |
81 |
76360 |
(void)priv; |
82 |
76360 |
VCLI_Out(cli, "-----------------------------\n"); |
83 |
76360 |
VCLI_Out(cli, "Varnish Cache CLI 1.0\n"); |
84 |
76360 |
VCLI_Out(cli, "-----------------------------\n"); |
85 |
76360 |
VCLI_Out(cli, "%s\n", VSB_data(vident) + 1); |
86 |
76360 |
VCLI_Out(cli, "%s\n", VCS_String("V")); |
87 |
76360 |
VCLI_Out(cli, "\n"); |
88 |
76360 |
VCLI_Out(cli, "Type 'help' for command list.\n"); |
89 |
76360 |
VCLI_Out(cli, "Type 'quit' to close CLI session.\n"); |
90 |
76360 |
if (!MCH_Running()) |
91 |
75080 |
VCLI_Out(cli, "Type 'start' to launch worker process.\n"); |
92 |
76360 |
VCLI_SetResult(cli, CLIS_OK); |
93 |
76360 |
} |
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 |
160600 |
mcf_askchild(struct cli *cli, const char * const *av, void *priv) |
126 |
|
{ |
127 |
|
int i; |
128 |
|
char *q; |
129 |
|
unsigned u; |
130 |
|
|
131 |
160600 |
(void)priv; |
132 |
|
/* |
133 |
|
* Command not recognized in master, try cacher if it is |
134 |
|
* running. |
135 |
|
*/ |
136 |
160600 |
if (cli_o <= 0) { |
137 |
2640 |
VCLI_SetResult(cli, CLIS_UNKNOWN); |
138 |
2640 |
VCLI_Out(cli, |
139 |
|
"Unknown request in manager process " |
140 |
|
"(child not running).\n" |
141 |
|
"Type 'help' for more info."); |
142 |
2640 |
return; |
143 |
|
} |
144 |
157960 |
VSB_clear(cli_buf); |
145 |
371160 |
for (i = 1; av[i] != NULL; i++) { |
146 |
213200 |
VSB_quote(cli_buf, av[i], strlen(av[i]), 0); |
147 |
213200 |
VSB_putc(cli_buf, ' '); |
148 |
213200 |
} |
149 |
157960 |
VSB_putc(cli_buf, '\n'); |
150 |
157960 |
AZ(VSB_finish(cli_buf)); |
151 |
157960 |
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 |
157960 |
if (VCLI_ReadResult(cli_i, &u, &q, mgt_param.cli_timeout)) |
158 |
40 |
MCH_Cli_Fail(); |
159 |
157960 |
VCLI_SetResult(cli, u); |
160 |
157960 |
VCLI_Out(cli, "%s", q); |
161 |
157960 |
free(q); |
162 |
160600 |
} |
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 |
146083 |
mgt_cli_askchild(unsigned *status, char **resp, const char *fmt, ...) |
179 |
|
{ |
180 |
|
int i; |
181 |
|
va_list ap; |
182 |
|
unsigned u; |
183 |
|
|
184 |
146083 |
AN(status); |
185 |
146083 |
VSB_clear(cli_buf); |
186 |
|
|
187 |
146083 |
if (resp != NULL) |
188 |
146083 |
*resp = NULL; |
189 |
146083 |
*status = 0; |
190 |
146083 |
if (cli_i < 0 || cli_o < 0) { |
191 |
0 |
*status = CLIS_CANT; |
192 |
0 |
return (CLIS_CANT); |
193 |
|
} |
194 |
146083 |
va_start(ap, fmt); |
195 |
146083 |
AZ(VSB_vprintf(cli_buf, fmt, ap)); |
196 |
146083 |
va_end(ap); |
197 |
146083 |
AZ(VSB_finish(cli_buf)); |
198 |
146083 |
i = VSB_len(cli_buf); |
199 |
146083 |
assert(i > 0 && VSB_data(cli_buf)[i - 1] == '\n'); |
200 |
146083 |
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 |
146083 |
if (VCLI_ReadResult(cli_i, &u, resp, mgt_param.cli_timeout)) |
209 |
40 |
MCH_Cli_Fail(); |
210 |
146083 |
*status = u; |
211 |
146083 |
return (u == CLIS_OK || u == CLIS_TRUNCATED ? 0 : u); |
212 |
146083 |
} |
213 |
|
|
214 |
|
/*--------------------------------------------------------------------*/ |
215 |
|
|
216 |
|
unsigned |
217 |
37600 |
mgt_cli_start_child(int fd, double tmo) |
218 |
|
{ |
219 |
|
unsigned u; |
220 |
|
|
221 |
37600 |
cli_i = fd; |
222 |
37600 |
cli_o = fd; |
223 |
37600 |
if (VCLI_ReadResult(cli_i, &u, NULL, tmo)) { |
224 |
320 |
return (CLIS_COMMS); |
225 |
|
} |
226 |
37280 |
return (u); |
227 |
37600 |
} |
228 |
|
|
229 |
|
/*--------------------------------------------------------------------*/ |
230 |
|
|
231 |
|
void |
232 |
37600 |
mgt_cli_stop_child(void) |
233 |
|
{ |
234 |
|
|
235 |
37600 |
cli_i = -1; |
236 |
37600 |
cli_o = -1; |
237 |
|
/* XXX: kick any users */ |
238 |
37600 |
} |
239 |
|
|
240 |
|
/*-------------------------------------------------------------------- |
241 |
|
* Generate a random challenge |
242 |
|
*/ |
243 |
|
|
244 |
|
static void |
245 |
38840 |
mgt_cli_challenge(struct cli *cli) |
246 |
|
{ |
247 |
|
size_t z; |
248 |
|
uint8_t u; |
249 |
|
|
250 |
38840 |
AZ(VRND_RandomCrypto(cli->challenge, sizeof cli->challenge - 2)); |
251 |
1281720 |
for (z = 0; z < (sizeof cli->challenge) - 2; z++) { |
252 |
1242880 |
AZ(VRND_RandomCrypto(&u, sizeof u)); |
253 |
1242880 |
cli->challenge[z] = (u % 26) + 'a'; |
254 |
1242880 |
} |
255 |
38840 |
cli->challenge[z++] = '\n'; |
256 |
38840 |
cli->challenge[z] = '\0'; |
257 |
38840 |
VCLI_Out(cli, "%s", cli->challenge); |
258 |
38840 |
VCLI_Out(cli, "\nAuthentication required.\n"); |
259 |
38840 |
VCLI_SetResult(cli, CLIS_AUTH); |
260 |
38840 |
} |
261 |
|
|
262 |
|
/*-------------------------------------------------------------------- |
263 |
|
* Validate the authentication |
264 |
|
*/ |
265 |
|
|
266 |
|
static void |
267 |
38840 |
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 |
38840 |
AN(av[2]); |
273 |
38840 |
(void)priv; |
274 |
38840 |
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 |
38840 |
VJ_master(JAIL_MASTER_FILE); |
280 |
38840 |
fd = open(secret_file, O_RDONLY); |
281 |
38840 |
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 |
38840 |
VJ_master(JAIL_MASTER_LOW); |
289 |
38840 |
MCH_TrackHighFd(fd); |
290 |
38840 |
VCLI_AuthResponse(fd, cli->challenge, buf); |
291 |
38840 |
closefd(&fd); |
292 |
38840 |
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 |
38840 |
cli->auth = MCF_AUTH; |
299 |
38840 |
memset(cli->challenge, 0, sizeof cli->challenge); |
300 |
38840 |
VCLI_SetResult(cli, CLIS_OK); |
301 |
38840 |
mcf_banner(cli, av, priv); |
302 |
38840 |
} |
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 |
532600 |
mgt_cli_cb_before(const struct cli *cli) |
336 |
|
{ |
337 |
|
|
338 |
532600 |
if (cli->priv == stderr) |
339 |
160 |
fprintf(stderr, "> %s\n", VSB_data(cli->cmd)); |
340 |
532600 |
MGT_Complain(C_CLI, "CLI %s Rd %s", cli->ident, VSB_data(cli->cmd)); |
341 |
532600 |
} |
342 |
|
|
343 |
|
static void |
344 |
532680 |
mgt_cli_cb_after(const struct cli *cli) |
345 |
|
{ |
346 |
|
|
347 |
532680 |
MGT_Complain(C_CLI, "CLI %s Wr %03u %s", |
348 |
532680 |
cli->ident, cli->result, VSB_data(cli->sb)); |
349 |
532680 |
if (cli->priv != stderr) |
350 |
532440 |
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 |
532560 |
} |
358 |
|
|
359 |
|
/*--------------------------------------------------------------------*/ |
360 |
|
|
361 |
|
void |
362 |
40800 |
mgt_cli_init_cls(void) |
363 |
|
{ |
364 |
|
|
365 |
40800 |
mgt_cls = VCLS_New(NULL); |
366 |
40800 |
AN(mgt_cls); |
367 |
40800 |
VCLS_SetHooks(mgt_cls, mgt_cli_cb_before, mgt_cli_cb_after); |
368 |
40800 |
VCLS_AddFunc(mgt_cls, MCF_NOAUTH, cli_auth); |
369 |
40800 |
VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_proto); |
370 |
40800 |
VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_debug); |
371 |
40800 |
VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_askchild); |
372 |
40800 |
cli_buf = VSB_new_auto(); |
373 |
40800 |
AN(cli_buf); |
374 |
40800 |
} |
375 |
|
|
376 |
|
/*-------------------------------------------------------------------- |
377 |
|
* Get rid of all CLI sessions |
378 |
|
*/ |
379 |
|
|
380 |
|
void |
381 |
37360 |
mgt_cli_close_all(void) |
382 |
|
{ |
383 |
|
|
384 |
37360 |
VCLS_Destroy(&mgt_cls); |
385 |
37360 |
} |
386 |
|
|
387 |
|
/*-------------------------------------------------------------------- |
388 |
|
* Callback whenever something happens to the input fd of the session. |
389 |
|
*/ |
390 |
|
|
391 |
|
static int |
392 |
1094551 |
mgt_cli_callback2(const struct vev *e, int what) |
393 |
|
{ |
394 |
|
int i; |
395 |
|
|
396 |
1094551 |
(void)what; |
397 |
1094551 |
i = VCLS_Poll(mgt_cls, e->priv, 0); |
398 |
1094551 |
return (i); |
399 |
|
} |
400 |
|
|
401 |
|
/*--------------------------------------------------------------------*/ |
402 |
|
|
403 |
|
void |
404 |
76320 |
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 |
76320 |
cli = VCLS_AddFd(mgt_cls, fdi, fdo, closefunc, priv); |
411 |
|
|
412 |
76320 |
REPLACE(cli->ident, ident); |
413 |
|
|
414 |
76320 |
if (!auth && secret_file != NULL) { |
415 |
38840 |
cli->auth = MCF_NOAUTH; |
416 |
38840 |
mgt_cli_challenge(cli); |
417 |
38840 |
} else { |
418 |
37480 |
cli->auth = MCF_AUTH; |
419 |
37480 |
mcf_banner(cli, NULL, NULL); |
420 |
|
} |
421 |
76320 |
AZ(VSB_finish(cli->sb)); |
422 |
76320 |
(void)VCLI_WriteResult(fdo, cli->result, VSB_data(cli->sb)); |
423 |
|
|
424 |
76320 |
ev = VEV_Alloc(); |
425 |
76320 |
AN(ev); |
426 |
76320 |
ev->name = cli->ident; |
427 |
76320 |
ev->fd = fdi; |
428 |
76320 |
ev->fd_flags = VEV__RD; |
429 |
76320 |
ev->callback = mgt_cli_callback2; |
430 |
76320 |
ev->priv = cli; |
431 |
76320 |
AZ(VEV_Start(mgt_evb, ev)); |
432 |
76320 |
} |
433 |
|
|
434 |
|
/*--------------------------------------------------------------------*/ |
435 |
|
|
436 |
|
static struct vsb * |
437 |
38840 |
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 |
38840 |
vsb = VSB_new_auto(); |
445 |
38840 |
AN(vsb); |
446 |
38840 |
VTCP_myname(fd, abuf1, sizeof abuf1, pbuf1, sizeof pbuf1); |
447 |
38840 |
VTCP_hisname(fd, abuf2, sizeof abuf2, pbuf2, sizeof pbuf2); |
448 |
38840 |
VSB_printf(vsb, "%s %s %s %s %s", pfx, abuf2, pbuf2, abuf1, pbuf1); |
449 |
38840 |
AZ(VSB_finish(vsb)); |
450 |
38840 |
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 |
37680 |
mgt_cli_secret(const char *S_arg) |
477 |
|
{ |
478 |
|
int i, fd; |
479 |
|
char buf[BUFSIZ]; |
480 |
|
|
481 |
|
/* Save in shmem */ |
482 |
37680 |
mgt_SHM_static_alloc(S_arg, strlen(S_arg) + 1L, "Arg", "-S"); |
483 |
|
|
484 |
37680 |
VJ_master(JAIL_MASTER_FILE); |
485 |
37680 |
fd = open(S_arg, O_RDONLY); |
486 |
37680 |
if (fd < 0) { |
487 |
0 |
fprintf(stderr, "Cannot open secret-file \"%s\"\n", S_arg); |
488 |
0 |
exit(2); |
489 |
|
} |
490 |
37680 |
VJ_master(JAIL_MASTER_LOW); |
491 |
37680 |
MCH_TrackHighFd(fd); |
492 |
37680 |
i = read(fd, buf, sizeof buf); |
493 |
37680 |
if (i == 0) { |
494 |
0 |
fprintf(stderr, "Empty secret-file \"%s\"\n", S_arg); |
495 |
0 |
exit(2); |
496 |
|
} |
497 |
37680 |
if (i < 0) { |
498 |
0 |
fprintf(stderr, "Cannot read secret-file \"%s\"\n", S_arg); |
499 |
0 |
exit(2); |
500 |
|
} |
501 |
37680 |
closefd(&fd); |
502 |
37680 |
secret_file = S_arg; |
503 |
37680 |
} |
504 |
|
|
505 |
|
static int v_matchproto_(vss_resolved_f) |
506 |
75440 |
mct_callback(void *priv, const struct suckaddr *sa) |
507 |
|
{ |
508 |
|
int sock; |
509 |
75440 |
struct vsb *vsb = priv; |
510 |
|
const char *err; |
511 |
|
char abuf[VTCP_ADDRBUFSIZE]; |
512 |
|
char pbuf[VTCP_PORTBUFSIZE]; |
513 |
|
struct vev *ev; |
514 |
|
|
515 |
75440 |
VJ_master(JAIL_MASTER_PRIVPORT); |
516 |
75440 |
sock = VTCP_listen(sa, 10, &err); |
517 |
75440 |
VJ_master(JAIL_MASTER_LOW); |
518 |
75440 |
assert(sock != 0); // We know where stdin is |
519 |
75440 |
if (sock > 0) { |
520 |
75440 |
VTCP_myname(sock, abuf, sizeof abuf, pbuf, sizeof pbuf); |
521 |
75440 |
VSB_printf(vsb, "%s %s\n", abuf, pbuf); |
522 |
75440 |
ev = VEV_Alloc(); |
523 |
75440 |
AN(ev); |
524 |
75440 |
ev->fd = sock; |
525 |
75440 |
ev->fd_flags = POLLIN; |
526 |
75440 |
ev->callback = telnet_accept; |
527 |
75440 |
AZ(VEV_Start(mgt_evb, ev)); |
528 |
75440 |
} |
529 |
75440 |
return (0); |
530 |
|
} |
531 |
|
|
532 |
|
void |
533 |
37720 |
mgt_cli_telnet(const char *T_arg) |
534 |
|
{ |
535 |
|
int error; |
536 |
|
const char *err; |
537 |
|
struct vsb *vsb; |
538 |
|
|
539 |
37720 |
AN(T_arg); |
540 |
37720 |
vsb = VSB_new_auto(); |
541 |
37720 |
AN(vsb); |
542 |
37720 |
error = VSS_resolver(T_arg, NULL, mct_callback, vsb, &err); |
543 |
37720 |
if (err != NULL) |
544 |
0 |
ARGV_ERR("Could not resolve -T argument to address\n\t%s\n", |
545 |
|
err); |
546 |
37720 |
AZ(error); |
547 |
37720 |
AZ(VSB_finish(vsb)); |
548 |
37720 |
if (VSB_len(vsb) == 0) |
549 |
0 |
ARGV_ERR("-T %s could not be listened on.\n", T_arg); |
550 |
|
/* Save in shmem */ |
551 |
37720 |
mgt_SHM_static_alloc(VSB_data(vsb), VSB_len(vsb) + 1, "Arg", "-T"); |
552 |
37720 |
VSB_destroy(&vsb); |
553 |
37720 |
} |
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 |
37200 |
Marg_closer(void *priv) |
573 |
|
{ |
574 |
|
|
575 |
37200 |
(void)priv; |
576 |
37200 |
M_fd = -1; |
577 |
37200 |
return (0); |
578 |
|
} |
579 |
|
|
580 |
|
static int v_matchproto_(vev_cb_f) |
581 |
37200 |
Marg_connect(const struct vev *e, int what) |
582 |
|
{ |
583 |
|
struct vsb *vsb; |
584 |
|
struct m_addr *ma; |
585 |
|
|
586 |
37200 |
assert(e == M_conn); |
587 |
37200 |
(void)what; |
588 |
|
|
589 |
37200 |
M_fd = VTCP_connected(M_fd); |
590 |
37200 |
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 |
37200 |
vsb = sock_id("master", M_fd); |
602 |
37200 |
mgt_cli_setup(M_fd, M_fd, 0, VSB_data(vsb), Marg_closer, NULL); |
603 |
37200 |
VSB_destroy(&vsb); |
604 |
37200 |
M_poll = 1; |
605 |
37200 |
return (1); |
606 |
37200 |
} |
607 |
|
|
608 |
|
static int v_matchproto_(vev_cb_f) |
609 |
125649 |
Marg_poker(const struct vev *e, int what) |
610 |
|
{ |
611 |
|
int s; |
612 |
|
struct m_addr *ma; |
613 |
|
|
614 |
125649 |
assert(e == M_poker); |
615 |
125649 |
(void)what; |
616 |
|
|
617 |
125649 |
M_poker->timeout = M_poll; /* XXX nasty ? */ |
618 |
125649 |
if (M_fd > 0) |
619 |
88449 |
return (0); |
620 |
|
|
621 |
37200 |
ma = VTAILQ_FIRST(&m_addr_list); |
622 |
37200 |
AN(ma); |
623 |
|
|
624 |
|
/* Try to connect asynchronously */ |
625 |
37200 |
s = VTCP_connect(ma->sa, -1); |
626 |
37200 |
if (s < 0) |
627 |
0 |
return (0); |
628 |
|
|
629 |
37200 |
MCH_TrackHighFd(s); |
630 |
|
|
631 |
37200 |
M_conn = VEV_Alloc(); |
632 |
37200 |
AN(M_conn); |
633 |
37200 |
M_conn->callback = Marg_connect; |
634 |
37200 |
M_conn->name = "-M connector"; |
635 |
37200 |
M_conn->fd_flags = VEV__WR; |
636 |
37200 |
M_conn->fd = s; |
637 |
37200 |
M_fd = s; |
638 |
37200 |
AZ(VEV_Start(mgt_evb, M_conn)); |
639 |
37200 |
return (0); |
640 |
125649 |
} |
641 |
|
|
642 |
|
static int v_matchproto_(vss_resolved_f) |
643 |
37200 |
marg_cb(void *priv, const struct suckaddr *sa) |
644 |
|
{ |
645 |
|
struct m_addr *ma; |
646 |
|
|
647 |
37200 |
(void)priv; |
648 |
37200 |
ALLOC_OBJ(ma, M_ADDR_MAGIC); |
649 |
37200 |
AN(ma); |
650 |
37200 |
ma->sa = VSA_Clone(sa); |
651 |
37200 |
VTAILQ_INSERT_TAIL(&m_addr_list, ma, list); |
652 |
37200 |
return (0); |
653 |
|
} |
654 |
|
|
655 |
|
void |
656 |
37200 |
mgt_cli_master(const char *M_arg) |
657 |
|
{ |
658 |
|
const char *err; |
659 |
|
int error; |
660 |
|
|
661 |
37200 |
AN(M_arg); |
662 |
|
|
663 |
37200 |
error = VSS_resolver(M_arg, NULL, marg_cb, NULL, &err); |
664 |
37200 |
if (err != NULL) |
665 |
0 |
ARGV_ERR("Could not resolve -M argument to address\n\t%s\n", |
666 |
|
err); |
667 |
37200 |
AZ(error); |
668 |
37200 |
if (VTAILQ_EMPTY(&m_addr_list)) |
669 |
0 |
ARGV_ERR("Could not resolve -M argument to address\n"); |
670 |
37200 |
AZ(M_poker); |
671 |
37200 |
M_poker = VEV_Alloc(); |
672 |
37200 |
AN(M_poker); |
673 |
37200 |
M_poker->timeout = M_poll; |
674 |
37200 |
M_poker->callback = Marg_poker; |
675 |
37200 |
M_poker->name = "-M poker"; |
676 |
37200 |
AZ(VEV_Start(mgt_evb, M_poker)); |
677 |
37200 |
} |
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 |
} |