Line data Source code
1 : #include "../../burp.h"
2 : #include "../../alloc.h"
3 : #include "../../asfd.h"
4 : #include "../../async.h"
5 : #include "../../bu.h"
6 : #include "../../cstat.h"
7 : #include "../../conffile.h"
8 : #include "../../handy.h"
9 : #include "../../iobuf.h"
10 : #include "../../log.h"
11 : #include "cstat.h"
12 : #include "json_output.h"
13 : #include "status_server.h"
14 :
15 6 : static int parse_cntr_data(const char *buf, struct cstat *clist)
16 : {
17 6 : int bno=0;
18 6 : int ret=-1;
19 6 : char *cname=NULL;
20 6 : struct cstat *c=NULL;
21 6 : char *path=NULL;
22 6 : char *dp=NULL;
23 6 : pid_t pid=-1;
24 :
25 : // Skip the type.
26 6 : if(!(dp=strchr(buf, '\t')))
27 : return 0;
28 5 : dp++;
29 :
30 5 : if(extract_client_pid_bno(dp, &cname, &pid, &bno))
31 : return -1;
32 5 : if(!cname)
33 : return 0;
34 :
35 : // Find the array entry for this client,
36 : // and add the detail from the parent to it.
37 3 : for(c=clist; c; c=c->next)
38 : {
39 3 : struct cntr *cntr=NULL;
40 3 : if(strcmp(c->name, cname))
41 2 : continue;
42 1 : cstat_set_run_status(c, RUN_STATUS_RUNNING);
43 :
44 : // Find the cntr entry for this client/pid.
45 1 : for(cntr=c->cntrs; cntr; cntr=cntr->next)
46 0 : if(cntr->pid==pid)
47 : break;
48 1 : if(!cntr)
49 : {
50 : // Need to allocate a new cntr.
51 1 : if(!(cntr=cntr_alloc())
52 1 : || cntr_init(cntr, cname, pid))
53 : goto end;
54 1 : cstat_add_cntr_to_list(c, cntr);
55 : }
56 1 : if(str_to_cntr(buf, cntr, &path))
57 : goto end;
58 : }
59 :
60 : // FIX THIS: Do something with path.
61 :
62 : ret=0;
63 : end:
64 5 : free_w(&cname);
65 5 : free_w(&path);
66 5 : return ret;
67 : }
68 :
69 4 : static void clean_up_cntrs(struct cstat *clist)
70 : {
71 : struct cstat *c;
72 16 : for(c=clist; c; c=c->next)
73 : {
74 : struct cntr *cntr=NULL;
75 24 : for(cntr=c->cntrs; cntr; )
76 : {
77 0 : if(cntr->found)
78 : {
79 0 : cntr=cntr->next;
80 0 : continue;
81 : }
82 0 : cstat_remove_cntr_from_list(c, cntr);
83 0 : cntr_free(&cntr);
84 0 : if(c->cntrs)
85 0 : cntr=c->cntrs;
86 : }
87 : }
88 4 : }
89 :
90 9 : static int parse_clients_list(char *buf, struct cstat *clist)
91 : {
92 9 : char *tok=NULL;
93 : struct cstat *c;
94 :
95 9 : if(!clist)
96 : return 0;
97 :
98 : // Do not need the first token.
99 4 : if(!(tok=strtok(buf, "\t\n")))
100 : return 0;
101 12 : for(c=clist; c; c=c->next)
102 : {
103 : struct cntr *cntr;
104 12 : for(cntr=c->cntrs; cntr; cntr=cntr->next)
105 0 : cntr->found=0;
106 12 : cstat_set_run_status(c, RUN_STATUS_IDLE);
107 : }
108 :
109 7 : while((tok=strtok(NULL, "\t\n")))
110 : {
111 3 : int bno=0;
112 3 : pid_t pid=-1;
113 3 : char *cname=NULL;
114 3 : if(extract_client_pid_bno(tok, &cname, &pid, &bno))
115 0 : return -1;
116 11 : for(c=clist; c; c=c->next)
117 : {
118 : struct cntr *cntr;
119 7 : if(strcmp(c->name, cname))
120 4 : continue;
121 3 : cstat_set_run_status(c, RUN_STATUS_RUNNING);
122 3 : for(cntr=c->cntrs; cntr; cntr=cntr->next)
123 0 : if(cntr->pid==pid)
124 : break;
125 3 : if(cntr)
126 : {
127 0 : cntr->found=1;
128 0 : cntr->bno=bno;
129 : }
130 : break;
131 : }
132 3 : free_w(&cname);
133 : }
134 :
135 4 : clean_up_cntrs(clist);
136 :
137 4 : return 0;
138 : }
139 :
140 : #ifndef UTEST
141 : static
142 : #endif
143 18 : int parse_parent_data(char *buf, struct cstat *clist)
144 : {
145 18 : if(!buf || !*buf)
146 : return 0;
147 :
148 17 : if(!strncmp(buf, "cntr", strlen("cntr")))
149 : {
150 6 : if(parse_cntr_data(buf, clist))
151 : return -1;
152 : }
153 11 : else if(!strncmp(buf, "clients", strlen("clients")))
154 : {
155 9 : if(parse_clients_list(buf, clist))
156 : return -1;
157 : }
158 :
159 : return 0;
160 : }
161 :
162 : #ifndef UTEST
163 : static
164 : #endif
165 6 : int status_server_parse_cmd(
166 : const char *buf,
167 : char **command,
168 : char **client,
169 : char **backup,
170 : char **logfile,
171 : char **browse
172 : ) {
173 6 : int ret=-1;
174 6 : char *tok=NULL;
175 6 : char **current=NULL;
176 6 : char *copy=NULL;
177 :
178 6 : if(!buf)
179 : return 0;
180 :
181 6 : if(!(copy=strdup_w(buf, __func__)))
182 : goto end;
183 6 : if(!(tok=strtok(copy, ":")))
184 : {
185 : ret=0;
186 : goto end;
187 : }
188 : do {
189 33 : if(current)
190 : {
191 15 : if(!(*current=strdup_w(tok, __func__)))
192 : goto end;
193 : current=NULL;
194 : }
195 : else
196 : {
197 18 : if(!strcmp(tok, "j"))
198 : current=command;
199 17 : else if(!strcmp(tok, "c"))
200 : current=client;
201 12 : else if(!strcmp(tok, "b"))
202 : current=backup;
203 7 : else if(!strcmp(tok, "l"))
204 : current=logfile;
205 3 : else if(!strcmp(tok, "p"))
206 : {
207 : // The path may have colons in it. So, make
208 : // this the last one.
209 3 : if(copy+strlen(buf) > tok+1)
210 : {
211 2 : if(!(*browse=strdup_w(tok+2, __func__)))
212 : goto end;
213 : }
214 : break;
215 : }
216 : else
217 : current=NULL;
218 : }
219 30 : } while((tok=strtok(NULL, ":")));
220 :
221 : ret=0;
222 : end:
223 6 : free_w(©);
224 6 : return ret;
225 : }
226 :
227 : /*
228 : void dump_cbno(struct cstat *clist, const char *msg)
229 : {
230 : if(!clist) return;
231 : printf("dump %s: %s\n", msg, clist->name);
232 : struct bu *b;
233 : for(b=clist->bu; b; b=b->prev)
234 : printf(" %d\n", b->bno);
235 : }
236 : */
237 :
238 : static int response_marker_start(struct asfd *srfd, const char *buf)
239 : {
240 0 : return json_send_msg(srfd, "response-start", buf);
241 : }
242 :
243 : static int response_marker_end(struct asfd *srfd, const char *buf)
244 : {
245 0 : return json_send_msg(srfd, "response-end", buf);
246 : }
247 :
248 0 : static int parse_client_data(struct asfd *srfd,
249 : struct cstat *clist, int monitor_browse_cache, long *peer_version)
250 : {
251 0 : int ret=0;
252 0 : char *command=NULL;
253 0 : char *client=NULL;
254 0 : char *backup=NULL;
255 0 : char *logfile=NULL;
256 0 : char *browse=NULL;
257 0 : struct cstat *cstat=NULL;
258 0 : struct bu *bu=NULL;
259 : static int response_markers=0;
260 0 : const char *cmd_result=NULL;
261 : //logp("got client data: '%s'\n", srfd->rbuf->buf);
262 :
263 0 : if(status_server_parse_cmd(
264 0 : srfd->rbuf->buf,
265 : &command,
266 : &client,
267 : &backup,
268 : &logfile,
269 : &browse))
270 : goto error;
271 :
272 0 : if(command)
273 : {
274 : size_t l;
275 0 : char peer_version_str[32]="peer_version=";
276 0 : l=strlen(peer_version_str);
277 0 : if(!strcmp(command, "pretty-print-on"))
278 : {
279 0 : json_set_pretty_print(1);
280 0 : cmd_result="Pretty print on";
281 : }
282 0 : else if(!strcmp(command, "pretty-print-off"))
283 : {
284 0 : json_set_pretty_print(0);
285 0 : cmd_result="Pretty print off";
286 : }
287 0 : else if(!strcmp(command, "response-markers-on"))
288 : {
289 0 : response_markers=1;
290 0 : cmd_result="Response markers on";
291 : }
292 0 : else if(!strcmp(command, "response-markers-off"))
293 : {
294 0 : response_markers=0;
295 0 : cmd_result="Response markers off";
296 : }
297 0 : else if(!strncmp(command, peer_version_str, l))
298 : {
299 0 : if(!(*peer_version=version_to_long(command+l)))
300 : goto error;
301 : cmd_result="Peer version updated";
302 : }
303 : else
304 : {
305 : cmd_result="Unknown command";
306 : }
307 : }
308 :
309 0 : if(response_markers
310 0 : && response_marker_start(srfd, srfd->rbuf->buf))
311 : goto error;
312 :
313 0 : if(cmd_result)
314 : {
315 0 : if(json_send_warn(srfd, cmd_result))
316 : goto error;
317 : goto end;
318 : }
319 :
320 0 : if(browse)
321 : {
322 0 : free_w(&logfile);
323 0 : if(!(logfile=strdup_w("manifest", __func__)))
324 : goto error;
325 0 : strip_trailing_slashes(&browse);
326 : }
327 :
328 : //dump_cbno(clist, "pcd");
329 :
330 0 : if(client && *client)
331 : {
332 0 : if(!(cstat=cstat_get_by_name(clist, client)))
333 : {
334 0 : char msg[256]="";
335 0 : snprintf(msg, sizeof(msg),
336 : "Could not find client: %s", client);
337 0 : if(json_send_warn(srfd, msg))
338 : goto error;
339 0 : goto end;
340 : }
341 :
342 0 : if(cstat_set_backup_list(cstat))
343 : {
344 0 : if(json_send_warn(srfd, "Could not get backup list"))
345 : goto error;
346 : goto end;
347 :
348 : }
349 : }
350 0 : if(cstat && backup)
351 : {
352 0 : unsigned long bno=0;
353 0 : if(!(bno=strtoul(backup, NULL, 10)))
354 : {
355 0 : if(json_send_warn(srfd, "Could not get backup number"))
356 : goto error;
357 : goto end;
358 : }
359 0 : for(bu=cstat->bu; bu; bu=bu->prev)
360 0 : if(bu->bno==bno) break;
361 :
362 0 : if(!bu)
363 : {
364 0 : if(json_send_warn(srfd, "Backup not found"))
365 : goto error;
366 : goto end;
367 : }
368 : }
369 0 : if(logfile)
370 : {
371 0 : if(strcmp(logfile, "manifest")
372 0 : && strcmp(logfile, "backup")
373 0 : && strcmp(logfile, "restore")
374 0 : && strcmp(logfile, "verify")
375 0 : && strcmp(logfile, "backup_stats")
376 0 : && strcmp(logfile, "restore_stats")
377 0 : && strcmp(logfile, "verify_stats"))
378 : {
379 0 : if(json_send_warn(srfd, "File not supported"))
380 : goto error;
381 : goto end;
382 : }
383 : }
384 : /*
385 : printf("client: %s\n", client?:"");
386 : printf("backup: %s\n", backup?:"");
387 : printf("logfile: %s\n", logfile?:"");
388 : */
389 0 : if(json_send(srfd, clist, cstat, bu, logfile, browse,
390 : monitor_browse_cache, *peer_version))
391 : goto error;
392 :
393 : goto end;
394 : error:
395 : ret=-1;
396 : end:
397 0 : if(response_markers
398 0 : && response_marker_end(srfd, srfd->rbuf->buf))
399 0 : ret=-1;
400 :
401 0 : free_w(&client);
402 0 : free_w(&backup);
403 0 : free_w(&logfile);
404 0 : free_w(&browse);
405 0 : return ret;
406 : }
407 :
408 0 : static int parse_data(struct asfd *asfd, struct cstat *clist,
409 : struct asfd *cfd, int monitor_browse_cache, long *peer_version)
410 : {
411 0 : if(asfd==cfd)
412 0 : return parse_client_data(asfd,
413 : clist, monitor_browse_cache, peer_version);
414 0 : return parse_parent_data(asfd->rbuf->buf, clist);
415 : }
416 :
417 : static int have_data_for_running_clients(struct cstat *clist)
418 : {
419 : struct cstat *c;
420 0 : for(c=clist; c; c=c->next)
421 : {
422 0 : if(c->run_status==RUN_STATUS_RUNNING)
423 : {
424 0 : if(!c->cntrs
425 0 : || c->cntrs->cntr_status==CNTR_STATUS_UNSET)
426 : return 0;
427 : }
428 : }
429 : return 1;
430 : }
431 :
432 : static int have_run_statuses(struct cstat *clist)
433 : {
434 : struct cstat *c;
435 0 : for(c=clist; c; c=c->next)
436 0 : if(c->permitted && c->run_status==RUN_STATUS_UNSET)
437 : return 0;
438 : return 1;
439 : }
440 :
441 0 : static int get_initial_data(struct async *as,
442 : struct cstat **clist,
443 : struct conf **monitor_cconfs,
444 : struct conf **globalcs, struct conf **cconfs,
445 : int monitor_browse_cache, long *peer_version)
446 : {
447 0 : int x=10;
448 0 : struct asfd *asfd=NULL;
449 :
450 0 : if(cstat_load_data_from_disk(clist, monitor_cconfs, globalcs, cconfs))
451 : return -1;
452 :
453 : // Try to get the initial data.
454 0 : while(x)
455 : {
456 : // Do not wait forever for running clients.
457 0 : if(!have_data_for_running_clients(*clist))
458 0 : x--;
459 0 : else if(have_run_statuses(*clist))
460 : return 0;
461 :
462 0 : if(as->read_write(as))
463 : {
464 0 : logp("Exiting main status server loop\n");
465 0 : return -1;
466 : }
467 0 : asfd=as->asfd->next;
468 0 : if(asfd->rbuf->buf)
469 : {
470 0 : if(parse_data(asfd, *clist,
471 : NULL, monitor_browse_cache, peer_version))
472 : {
473 0 : iobuf_free_content(asfd->rbuf);
474 0 : return -1;
475 : }
476 0 : iobuf_free_content(asfd->rbuf);
477 : }
478 : }
479 : return 0;
480 : }
481 :
482 0 : int status_server(struct async *as, struct conf **monitor_cconfs)
483 : {
484 0 : int ret=-1;
485 0 : int gotdata=0;
486 : struct asfd *asfd;
487 0 : struct cstat *clist=NULL;
488 0 : struct asfd *cfd=as->asfd; // Client.
489 0 : struct conf **cconfs=NULL;
490 0 : struct conf **globalcs=NULL;
491 0 : const char *conffile=get_string(monitor_cconfs[OPT_CONFFILE]);
492 0 : long peer_version=version_to_long(get_string(monitor_cconfs[OPT_PEER_VERSION]));
493 0 : int monitor_browse_cache=get_int(monitor_cconfs[OPT_MONITOR_BROWSE_CACHE]);
494 :
495 : // We need to load a fresh global conf so that the clients do not all
496 : // get settings from the monitor client. In particular, if protocol=0
497 : // in both burp-server.conf and the monitor burp.conf, the monitor
498 : // client gets protocol=1 from extra comms, and all the clients here
499 : // would end up getting protocol=1.
500 0 : if(!(globalcs=confs_alloc()))
501 : goto end;
502 0 : if(confs_init(globalcs)) return -1;
503 0 : if(conf_load_global_only(conffile, globalcs))
504 : return -1;
505 :
506 0 : if(!(cconfs=confs_alloc()))
507 : goto end;
508 :
509 0 : if(get_initial_data(as, &clist, monitor_cconfs,
510 : globalcs, cconfs, monitor_browse_cache, &peer_version))
511 : goto end;
512 :
513 : while(1)
514 : {
515 : // Take the opportunity to get data from the disk if nothing
516 : // was read from the fds.
517 0 : if(gotdata) gotdata=0;
518 0 : else if(cstat_load_data_from_disk(&clist, monitor_cconfs,
519 : globalcs, cconfs))
520 : goto end;
521 0 : if(as->read_write(as))
522 : {
523 0 : logp("Exiting main status server loop\n");
524 : break;
525 : }
526 0 : for(asfd=as->asfd; asfd; asfd=asfd->next)
527 0 : while(asfd->rbuf->buf)
528 : {
529 0 : gotdata=1;
530 0 : if(parse_data(asfd, clist,
531 : cfd, monitor_browse_cache, &peer_version)
532 0 : || asfd->parse_readbuf(asfd))
533 : goto end;
534 0 : iobuf_free_content(asfd->rbuf);
535 : }
536 : }
537 0 : ret=0;
538 : end:
539 : // FIX THIS: should free clist;
540 0 : confs_free(&globalcs);
541 0 : return ret;
542 : }
|