1 /*
2 This file is part of Kismet
3
4 Kismet is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 Kismet is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Kismet; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include "config.h"
20
21 // Panel has to be here to pass configure, so just test these
22 #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES))
23
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <dlfcn.h>
27 #include <dirent.h>
28
29 #include "util.h"
30 #include "messagebus.h"
31 #include "kis_panel_widgets.h"
32 #include "kis_panel_windows.h"
33 #include "kis_panel_frontend.h"
34 #include "version.h"
35
36 #define KPI_SOURCE_FIELDS "uuid,interface,type,username,channel,packets,hop," \
37 "velocity,dwell,hop_time_sec,hop_time_usec,channellist,error,warning"
38
39 #define KPI_ALERT_FIELDS "sec,usec,header,bssid,source,dest,other,channel,text"
40
41 // STATUS protocol parser that injects right into the messagebus
KisPanelClient_STATUS(CLIPROTO_CB_PARMS)42 void KisPanelClient_STATUS(CLIPROTO_CB_PARMS) {
43 if (proto_parsed->size() < 2) {
44 return;
45 }
46
47 int flags;
48 string text;
49
50 text = (*proto_parsed)[0].word;
51
52 if (sscanf((*proto_parsed)[1].word.c_str(), "%d", &flags) != 1) {
53 return;
54 }
55
56 _MSG(text, flags);
57 }
58
KisPanelClient_SOURCE(CLIPROTO_CB_PARMS)59 void KisPanelClient_SOURCE(CLIPROTO_CB_PARMS) {
60 // Pass it off to the clinet frame
61 ((KisPanelInterface *) auxptr)->proto_SOURCE(globalreg, proto_string,
62 proto_parsed, srccli, auxptr);
63 }
64
KisPanelClient_ALERT(CLIPROTO_CB_PARMS)65 void KisPanelClient_ALERT(CLIPROTO_CB_PARMS) {
66 ((KisPanelInterface *) auxptr)->proto_ALERT(globalreg, proto_string,
67 proto_parsed, srccli, auxptr);
68 }
69
KisPanelClient_INFO(CLIPROTO_CB_PARMS)70 void KisPanelClient_INFO(CLIPROTO_CB_PARMS) {
71 ((KisPanelInterface *) auxptr)->proto_INFO(globalreg, proto_string,
72 proto_parsed, srccli, auxptr);
73 }
74
kpi_prompt_sourcewarnings(KIS_PROMPT_CB_PARMS)75 void kpi_prompt_sourcewarnings(KIS_PROMPT_CB_PARMS) {
76 if (check)
77 globalreg->panel_interface->prefs->SetOpt("WARN_SOURCEWARN", "false", 1);
78 }
79
proto_SOURCE(CLIPROTO_CB_PARMS)80 void KisPanelInterface::proto_SOURCE(CLIPROTO_CB_PARMS) {
81 // "uuid,interface,type,username,channel,packets,hop,"
82 // "velocity,dwell,hop_time_sec,hop_time_usec,channellist,
83 // error,warning"
84
85 if (proto_parsed->size() < 14) {
86 return;
87 }
88
89 int fnum = 0;
90 int tint;
91
92 knc_card *source = NULL;
93
94 uuid inuuid = uuid((*proto_parsed)[fnum++].word);
95
96 if (inuuid.error)
97 return;
98
99 if (netcard_map.find(inuuid) == netcard_map.end()) {
100 source = new knc_card;
101 source->carduuid = inuuid;
102 source->uuid_hash = Adler32Checksum(inuuid.UUID2String().c_str(),
103 inuuid.UUID2String().length());
104 netcard_map[inuuid] = source;
105 } else {
106 source = netcard_map.find(inuuid)->second;
107 }
108
109 source->last_update = time(0);
110
111 source->interface = ((*proto_parsed)[fnum++].word);
112 source->type = ((*proto_parsed)[fnum++].word);
113 source->name = ((*proto_parsed)[fnum++].word);
114
115 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1)
116 return;
117 source->channel = tint;
118
119 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1)
120 return;
121 source->packets = tint;
122
123 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1)
124 return;
125 source->hopping = tint;
126
127 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1)
128 return;
129 source->hopvelocity = tint;
130
131 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1)
132 return;
133 source->dwell = tint;
134
135 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1)
136 return;
137 source->hop_tm.tv_sec = tint;
138
139 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1)
140 return;
141 source->hop_tm.tv_usec = tint;
142
143 source->channellist = (*proto_parsed)[fnum++].word;
144
145 source->error = (*proto_parsed)[fnum++].word == "1";
146
147 string warning = (*proto_parsed)[fnum++].word;
148
149 if (warning != "" && warning != source->warning &&
150 prefs->FetchOpt("WARN_SOURCEWARN") != "false") {
151
152 vector<string> t;
153
154 t = StrTokenize(InLineWrap(warning, 0, 50), "\n");
155 Kis_Prompt_Panel *kpp =
156 new Kis_Prompt_Panel(globalreg, this);
157
158 kpp->SetTitle("Sources Warning");
159 kpp->SetDisplayText(t);
160 kpp->SetCheckText("Do not show source warnings in the future");
161 kpp->SetChecked(0);
162 kpp->SetDefaultButton(1);
163 kpp->SetButtonText("OK", "");
164 kpp->SetCallback(kpi_prompt_sourcewarnings, this);
165 QueueModalPanel(kpp);
166 }
167
168 source->warning = warning;
169
170 }
171
proto_ALERT(CLIPROTO_CB_PARMS)172 void KisPanelInterface::proto_ALERT(CLIPROTO_CB_PARMS) {
173 // sec, usec, header, bssid, source, dest, other, channel, text
174
175 if (proto_parsed->size() < 9) {
176 return;
177 }
178
179 int fnum = 0;
180 int tint;
181 unsigned int tuint;
182 mac_addr tmac;
183
184 knc_alert *alert = new knc_alert;
185
186 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tuint) != 1) {
187 delete alert;
188 return;
189 }
190 alert->tv.tv_sec = tuint;
191
192 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%u", &tuint) != 1) {
193 delete alert;
194 return;
195 }
196 alert->tv.tv_usec = tuint;
197
198 alert->alertname = MungeToPrintable((*proto_parsed)[fnum++].word);
199
200 tmac = mac_addr((*proto_parsed)[fnum++].word.c_str());
201 if (tmac.error) {
202 delete alert;
203 return;
204 }
205 alert->bssid = tmac;
206
207 tmac = mac_addr((*proto_parsed)[fnum++].word.c_str());
208 if (tmac.error) {
209 delete alert;
210 return;
211 }
212 alert->source = tmac;
213
214 tmac = mac_addr((*proto_parsed)[fnum++].word.c_str());
215 if (tmac.error) {
216 delete alert;
217 return;
218 }
219 alert->dest = tmac;
220
221 tmac = mac_addr((*proto_parsed)[fnum++].word.c_str());
222 if (tmac.error) {
223 delete alert;
224 return;
225 }
226 alert->other = tmac;
227
228 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &tint) != 1) {
229 delete alert;
230 return;
231 }
232 alert->channel = tint;
233
234 alert->text = (*proto_parsed)[fnum++].word;
235
236 alert_vec.push_back(alert);
237 }
238
kpi_prompt_addsource(KIS_PROMPT_CB_PARMS)239 void kpi_prompt_addsource(KIS_PROMPT_CB_PARMS) {
240 if (ok && globalreg->panel_interface->FetchNetClient() != NULL) {
241 Kis_AddCard_Panel *acp =
242 new Kis_AddCard_Panel(globalreg, globalreg->panel_interface);
243 globalreg->panel_interface->AddPanel(acp);
244 }
245 }
246
kpi_prompt_warnallerr(KIS_PROMPT_CB_PARMS)247 void kpi_prompt_warnallerr(KIS_PROMPT_CB_PARMS) {
248 if (check)
249 globalreg->panel_interface->prefs->SetOpt("WARN_ALLERRSOURCE", "false", 1);
250
251 ((KisPanelInterface *) auxptr)->ResetWarnAllClear();
252 }
253
proto_INFO(CLIPROTO_CB_PARMS)254 void KisPanelInterface::proto_INFO(CLIPROTO_CB_PARMS) {
255 // Numsources,numerrorsources
256
257 if (proto_parsed->size() < 1) {
258 return;
259 }
260
261 int fnum = 0;
262 int ns = 0, ne = 0;
263
264 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &ns) != 1)
265 return;
266
267 if (sscanf((*proto_parsed)[fnum++].word.c_str(), "%d", &ne) != 1)
268 return;
269
270 if (ns != 0 && ne >= ns)
271 warned_all_errors_consec++;
272 else
273 warned_all_errors_consec = 0;
274
275 // If we've found all our defined sources, make sure they're not all in
276 // an error state
277 if (ns != 0 && time(0) - warned_all_errors > 60 &&
278 warned_cleared && ne >= ns && warned_all_errors_consec > 20 &&
279 prefs->FetchOpt("WARN_ALLERRSOURCE") != "false") {
280
281 warned_all_errors = time(0);
282 warned_all_errors_consec = 0;
283
284 vector<string> t;
285
286 t.push_back("All packet sources are in error state.");
287 t.push_back("Kismet will not be able to capture any data");
288 t.push_back("until a packet source is out of error mode.");
289 t.push_back("In most cases Kismet will continue to try to");
290 t.push_back("re-enable errored packet sources.");
291
292 Kis_Prompt_Panel *kpp =
293 new Kis_Prompt_Panel(globalreg, this);
294 kpp->SetTitle("Sources Failed");
295 kpp->SetDisplayText(t);
296 kpp->SetCheckText("Do not show this warning in the future");
297 kpp->SetChecked(0);
298 kpp->SetDefaultButton(1);
299 kpp->SetButtonText("OK", "");
300 QueueModalPanel(kpp);
301 }
302
303 // If we have no sources and we haven't warned the user about that, do so
304 if (ns == 0 && warned_no_sources == 0) {
305 warned_no_sources = 1;
306
307 vector<string> t;
308
309 t.push_back("Kismet started with no packet sources defined.");
310 t.push_back("No sources were defined or all defined sources");
311 t.push_back("encountered unrecoverable errors.");
312 t.push_back("Kismet will not be able to capture any data until");
313 t.push_back("a capture interface is added. Add a source now?");
314
315 Kis_Prompt_Panel *kpp =
316 new Kis_Prompt_Panel(globalreg, this);
317 kpp->SetTitle("No sources");
318 kpp->SetDisplayText(t);
319 kpp->SetCallback(kpi_prompt_addsource, this);
320 kpp->SetButtonText("Yes", "No");
321 kpp->SetDefaultButton(1);
322 QueueModalPanel(kpp);
323 }
324
325 }
326
KisPanelClient_Configured(CLICONF_CB_PARMS)327 void KisPanelClient_Configured(CLICONF_CB_PARMS) {
328 ((KisPanelInterface *) auxptr)->NetClientConfigure(kcli, recon);
329 }
330
KisPanelInterface()331 KisPanelInterface::KisPanelInterface() {
332 fprintf(stderr, "FATAL OOPS: KisPanelInterface not called with globalreg\n");
333 exit(-1);
334 }
335
KisPanelInterface(GlobalRegistry * in_globalreg)336 KisPanelInterface::KisPanelInterface(GlobalRegistry *in_globalreg) :
337 PanelInterface(in_globalreg) {
338 globalreg = in_globalreg;
339
340 network_client = NULL;
341
342 prefs = new ConfigFile(globalreg);
343
344 shutdown_mode = 0;
345
346 // Load the preferences file
347 LoadPreferences();
348
349 // Update the plugin dirs if we didn't get them
350 if (prefs->FetchOptVec("PLUGINDIR").size() == 0) {
351 vector<string> pdv;
352 pdv.push_back("%h/.kismet/client_plugins/");
353 pdv.push_back(string(LIB_LOC) + "/kismet_client/");
354 prefs->SetOptVec("PLUGINDIR", pdv, 1);
355 }
356
357 // Initialize the plugin data record. The first panel to get added
358 // to us is the main panel.
359 plugdata.kpinterface = this;
360 plugdata.mainpanel = NULL;
361 plugdata.globalreg = globalreg;
362
363 // Fill the plugin paths if they haven't been found
364 ScanPlugins();
365
366 addcb_ref = 0;
367
368 mainp = NULL;
369
370 server_framework = NULL;
371 server_popen = NULL;
372 server_text_cb = -1;
373
374 warned_no_sources = 0;
375 warned_all_errors = warned_all_errors_consec = 0;
376 warned_cleared = 1;
377
378 endwin();
379 }
380
~KisPanelInterface()381 KisPanelInterface::~KisPanelInterface() {
382 Shutdown();
383
384 delete network_client;
385 }
386
Shutdown()387 void KisPanelInterface::Shutdown() {
388 SavePreferences();
389
390 Remove_All_Netcli_Conf_CB(KisPanelClient_Configured);
391
392 Remove_All_Netcli_ProtoHandler("STATUS", KisPanelClient_STATUS, this);
393 Remove_All_Netcli_ProtoHandler("SOURCE", KisPanelClient_SOURCE, this);
394 Remove_All_Netcli_ProtoHandler("INFO", KisPanelClient_INFO, this);
395 Remove_All_Netcli_ProtoHandler("ALERT", KisPanelClient_ALERT, this);
396
397 // Destroy panels in this destructor, if they get destroyed in the
398 // parent destructor sadness happens
399 for (unsigned int x = 0; x < live_panels.size(); x++)
400 KillPanel(live_panels[x]);
401
402 // we don't kill the clients since we might still be issuing shutdown
403 // commands
404
405 // we don't kill the server if it exists, but we do kill the callback
406 // referencing ourselves
407 if (server_framework != NULL)
408 server_framework->RemoveCallback(server_text_cb);
409
410 shutdown_mode = 1;
411 }
412
MergeSet(int in_max_fd,fd_set * out_rset,fd_set * out_wset)413 int KisPanelInterface::MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) {
414 if (shutdown_mode)
415 return in_max_fd;
416
417 return PanelInterface::MergeSet(in_max_fd, out_rset, out_wset);
418 }
419
Poll(fd_set & in_rset,fd_set & in_wset)420 int KisPanelInterface::Poll(fd_set& in_rset, fd_set& in_wset) {
421 if (shutdown_mode)
422 return 0;
423
424 return PanelInterface::Poll(in_rset, in_wset);
425 }
426
AddPanel(Kis_Panel * in_panel)427 void KisPanelInterface::AddPanel(Kis_Panel *in_panel) {
428 in_panel->ShowPanel();
429
430 PanelInterface::AddPanel(in_panel);
431
432 if (plugdata.mainpanel == NULL)
433 plugdata.mainpanel = (Kis_Main_Panel *) in_panel;
434
435 if (mainp == NULL)
436 mainp = (Kis_Main_Panel *) in_panel;
437 }
438
KillPanel(Kis_Panel * in_panel)439 void KisPanelInterface::KillPanel(Kis_Panel *in_panel) {
440 // Kill the panel (this will delete it so be careful)
441 PanelInterface::KillPanel(in_panel);
442
443 // If it's a modal panel, remove it from the modal vec list. We only ever display
444 // the head of the modal vec list, so this check is sane. We're also only doing
445 // a pointer compare, so it being destroyed above is also sane
446 if (modal_vec.size() > 0 && modal_vec[0] == in_panel) {
447 modal_vec.erase(modal_vec.begin());
448
449 // If we have another modal alert queued, put it up
450 if (modal_vec.size() > 0)
451 AddPanel(modal_vec[0]);
452 }
453
454 }
455
LoadPreferences()456 int KisPanelInterface::LoadPreferences() {
457 if (prefs->ParseConfig(prefs->ExpandLogPath("%h/.kismet/kismet_ui.conf",
458 "", "", 0, 1).c_str()) >= 0) {
459 prefs->SetOpt("LOADEDFROMFILE", "1", 0);
460 }
461
462 SavePreferences();
463
464 return 1;
465 }
466
SavePreferences()467 int KisPanelInterface::SavePreferences() {
468 // Try to make the dir
469 int ret;
470
471 string dir = prefs->ExpandLogPath("%h/.kismet", "", "", 0, 1);
472
473 ret = mkdir(dir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
474
475 if (ret < 0 && errno != EEXIST) {
476 string err = string(strerror(errno));
477 _MSG("Failed to create dir " + dir + ": " + err,
478 MSGFLAG_ERROR);
479
480 RaiseAlert("Could not save prefs",
481 "Could not save preferences file, failed to create\n"
482 "directory " + dir + ":\n"
483 " " + err + "\n"
484 "Kismet will continue to run, however changes to\n"
485 "preferences will not be saved.\n");
486
487 return -1;
488 }
489
490 ret = prefs->SaveConfig(prefs->ExpandLogPath("%h/.kismet/kismet_ui.conf",
491 "", "", 0, 1).c_str());
492
493 if (ret < 0)
494 RaiseAlert("Could not save prefs",
495 "Could not save the preferences file, check error\n"
496 "messages. Kismet will continue to run, however\n"
497 "preference changes will not be preserved.\n");
498
499 return ret;
500 }
501
AddNetClient(string in_host,int in_reconnect)502 int KisPanelInterface::AddNetClient(string in_host, int in_reconnect) {
503 if (network_client != NULL)
504 delete network_client;
505
506 KisNetClient *netcl = new KisNetClient(globalreg);
507
508 network_client = netcl;
509
510 netcl->AddConfCallback(KisPanelClient_Configured, 1, this);
511
512 for (unsigned int x = 0; x < addclicb_vec.size(); x++)
513 (*(addclicb_vec[x]->cb))(globalreg, netcl, 1,
514 addclicb_vec[x]->auxptr);
515
516 return netcl->Connect(in_host, in_reconnect);
517 }
518
RemoveNetClient()519 void KisPanelInterface::RemoveNetClient() {
520 if (network_client != NULL) {
521 for (unsigned int c = 0; c < addclicb_vec.size(); c++)
522 (*(addclicb_vec[c]->cb))(globalreg, network_client, 0,
523 addclicb_vec[c]->auxptr);
524 delete network_client;
525 network_client = NULL;
526 }
527
528 return;
529 }
530
NetClientConfigure(KisNetClient * in_cli,int in_recon)531 void KisPanelInterface::NetClientConfigure(KisNetClient *in_cli, int in_recon) {
532 // Reset the card list. This assumes we only ever have one client, which
533 // is the case despite the stubs for multi-client. Sorry. We do this here
534 // so we don't get deltas before the reconnect event in configure.
535 for (map<uuid, KisPanelInterface::knc_card *>::iterator x = netcard_map.begin();
536 x != netcard_map.end(); ++x) {
537 delete x->second;
538 }
539 netcard_map.clear();
540
541 warned_no_sources = 0;
542 warned_all_errors = warned_all_errors_consec = 0;
543 warned_cleared = 1;
544
545 _MSG("Got configure event for client", MSGFLAG_INFO);
546
547 if (in_cli->RegisterProtoHandler("STATUS", "text,flags",
548 KisPanelClient_STATUS, this) < 0) {
549 _MSG("Could not register STATUS protocol with remote server, connection "
550 "will be terminated.", MSGFLAG_ERROR);
551 in_cli->KillConnection();
552 }
553
554 if (in_cli->RegisterProtoHandler("SOURCE", KPI_SOURCE_FIELDS,
555 KisPanelClient_SOURCE, this) < 0) {
556 _MSG("Could not register SOURCE protocol with remote server, connection "
557 "will be terminated.", MSGFLAG_ERROR);
558 in_cli->KillConnection();
559 }
560
561 if (in_cli->RegisterProtoHandler("INFO", "numsources,numerrorsources",
562 KisPanelClient_INFO, this) < 0) {
563 _MSG("Could not register INFO protocol with remote server, connection "
564 "will be terminated.", MSGFLAG_ERROR);
565 in_cli->KillConnection();
566 }
567
568 if (in_cli->RegisterProtoHandler("ALERT", KPI_ALERT_FIELDS,
569 KisPanelClient_ALERT, this) < 0) {
570 _MSG("Could not register ALERT protocol with remote server, connection "
571 "will be terminated.", MSGFLAG_ERROR);
572 in_cli->KillConnection();
573 }
574 }
575
Remove_All_Netcli_ProtoHandler(string in_proto,CliProto_Callback in_cb,void * in_aux)576 int KisPanelInterface::Remove_All_Netcli_ProtoHandler(string in_proto,
577 CliProto_Callback in_cb,
578 void *in_aux) {
579 if (network_client != NULL)
580 network_client->RemoveProtoHandler(in_proto, in_cb, in_aux);
581
582 return 0;
583 }
584
Remove_All_Netcli_Cmd_CB(CliCmd_Callback in_cb,void * in_aux)585 void KisPanelInterface::Remove_All_Netcli_Cmd_CB(CliCmd_Callback in_cb, void *in_aux) {
586 if (network_client != NULL)
587 network_client->RemoveAllCmdCallbacks(in_cb, in_aux);
588
589 return;
590 }
591
RaiseAlert(string in_title,string in_text)592 void KisPanelInterface::RaiseAlert(string in_title, string in_text) {
593 vector<string> t = StrTokenize(in_text, "\n");
594
595 Kis_Prompt_Panel *kpp =
596 new Kis_Prompt_Panel(globalreg, this);
597 kpp->SetTitle(in_title);
598 kpp->SetDisplayText(t);
599 kpp->SetButtonText("OK", "");
600
601 if (modal_vec.size() != 0)
602 modal_vec.push_back(kpp);
603 else
604 AddPanel(kpp);
605 }
606
QueueModalPanel(Kis_Panel * in_panel)607 void KisPanelInterface::QueueModalPanel(Kis_Panel *in_panel) {
608 if (modal_vec.size() > 0) {
609 modal_vec.push_back(in_panel);
610 } else {
611 modal_vec.push_back(in_panel);
612 AddPanel(in_panel);
613 }
614 }
615
FetchNetCardMap()616 map<uuid, KisPanelInterface::knc_card *> *KisPanelInterface::FetchNetCardMap() {
617 return &netcard_map;
618 }
619
Add_NetCli_AddCli_CB(KPI_AddCli_Callback in_cb,void * in_auxptr)620 int KisPanelInterface::Add_NetCli_AddCli_CB(KPI_AddCli_Callback in_cb,
621 void *in_auxptr) {
622 addcli_cb_rec *cbr = new addcli_cb_rec;
623
624 cbr->refnum = addcb_ref;
625 cbr->cb = in_cb;
626 cbr->auxptr = in_auxptr;
627
628 addcb_ref++;
629
630 addclicb_vec.push_back(cbr);
631
632 // Call it immediately if we're already connected
633 if (network_client != NULL) {
634 (*(in_cb))(globalreg, network_client, 1, in_auxptr);
635 }
636
637 return cbr->refnum;
638 }
639
Remove_Netcli_AddCli_CB(int in_cbref)640 void KisPanelInterface::Remove_Netcli_AddCli_CB(int in_cbref) {
641 for (unsigned int x = 0; x < addclicb_vec.size(); x++) {
642 if (addclicb_vec[x]->refnum == in_cbref) {
643 delete addclicb_vec[x];
644 addclicb_vec.erase(addclicb_vec.begin() + x);
645 return;
646 }
647 }
648 }
649
Remove_All_Netcli_Conf_CB(CliConf_Callback in_cb)650 void KisPanelInterface::Remove_All_Netcli_Conf_CB(CliConf_Callback in_cb) {
651 if (network_client != NULL) {
652 network_client->RemoveConfCallback(in_cb);
653 }
654 }
655
656 string global_plugin_load;
PluginClientSignalHandler(int sig)657 void PluginClientSignalHandler(int sig) {
658 fprintf(stderr, "\n\n"
659 "FATAL: Kismet (UI) crashed while loading a plugin...\n"
660 "Plugin loading: %s\n\n"
661 "This is either a bug in the plugin, or the plugin needs to be recompiled\n"
662 "to match the version of Kismet you are using (especially if you are using\n"
663 "development versions of Kismet or have recently upgraded.)\n\n"
664 "Remove the plugin from the plugins directory to keep it from loading,\n"
665 "or manually edit ~/.kismet/kismet_ui.conf and remove the plugin_autoload\n"
666 "line to stop Kismet from trying to start it.\n\n",
667 global_plugin_load.c_str());
668 exit(1);
669 }
670
LoadPlugin(string in_fname,string in_objname)671 void KisPanelInterface::LoadPlugin(string in_fname, string in_objname) {
672 void *dlfile;
673 panel_plugin_hook plughook;
674 #ifdef SYS_CYGWIN
675 _sig_func_ptr old_segv = SIG_DFL;
676 #else
677 sig_t old_segv = SIG_DFL;
678 #endif
679
680 old_segv = signal(SIGSEGV, PluginClientSignalHandler);
681
682 global_plugin_load = in_fname;
683
684 if ((dlfile = dlopen(in_fname.c_str(), RTLD_LAZY)) == NULL) {
685 _MSG("Failed to open plugin '" + in_fname + "': " +
686 dlerror(), MSGFLAG_ERROR);
687 signal(SIGSEGV, old_segv);
688 return;
689 }
690
691 // Resolve the version function
692 panel_plugin_revisioncall vsym = NULL;
693 if ((vsym = (panel_plugin_revisioncall) dlsym(dlfile,
694 "kis_revision_info")) == NULL) {
695 string msg = "Failed to find a Kismet version record in plugin '" + in_fname +
696 "'. This plugin has not been "
697 "updated to use the new version API. Please download the "
698 "latest version, or contact the plugin authors. Kismet will "
699 "still load this plugin, but BE WARNED, there is no way "
700 "to know if it was compiled for this version of Kismet, and "
701 "crashes may occur.";
702 RaiseAlert("Plugin Loading Error", InLineWrap(msg, 0, 50));
703 } else {
704 // Make a struct of whatever PREV we use, it will tell us what
705 // it supports in response.
706 panel_plugin_revision *prev = new panel_plugin_revision;
707 prev->version_api_revision = KIS_PANEL_PLUGIN_VREVISION;
708
709 (*vsym)(prev);
710
711 if (prev->version_api_revision >= 1) {
712 if (prev->major != string(VERSION_MAJOR) ||
713 prev->minor != string(VERSION_MINOR) ||
714 prev->tiny != string(VERSION_TINY)) {
715 string msg =
716 "Failed to load plugin '" + in_fname +
717 "': This plugin was compiled for a different version of "
718 "Kismet; Please recompile and reinstall it, or remove "
719 "it entirely.";
720 _MSG(msg, MSGFLAG_ERROR);
721
722 RaiseAlert("Loading Plugin Failed", InLineWrap(msg, 0, 50));
723
724 signal(SIGSEGV, old_segv);
725 return;
726 }
727 }
728
729 delete(prev);
730 }
731
732 if ((plughook = (panel_plugin_hook) dlsym(dlfile, "panel_plugin_init")) == NULL) {
733 _MSG("Failed to find 'panel_plugin_init' function in plugin '" + in_fname +
734 "': " + strerror(errno), MSGFLAG_ERROR);
735 dlclose(dlfile);
736 signal(SIGSEGV, old_segv);
737 return;
738 }
739
740 int ret;
741 ret = (*(plughook))(globalreg, &plugdata);
742
743 if (ret < 0) {
744 _MSG("Failed to initialize plugin '" + in_fname + "'", MSGFLAG_ERROR);
745 dlclose(dlfile);
746 signal(SIGSEGV, old_segv);
747 return;
748 }
749
750 for (unsigned int x = 0; x < plugin_vec.size(); x++) {
751 if (plugin_vec[x]->filename == in_fname &&
752 plugin_vec[x]->objectname == in_objname) {
753 plugin_vec[x]->dlfileptr = dlfile;
754 break;
755 }
756 }
757
758 signal(SIGSEGV, old_segv);
759 }
760
ScanPlugins()761 void KisPanelInterface::ScanPlugins() {
762 vector<string> plugdirs = prefs->FetchOptVec("PLUGINDIR");
763
764 for (unsigned int x = 0; x < plugdirs.size(); x++) {
765 DIR *plugdir;
766 struct dirent *plugfile;
767 string expanddir = prefs->ExpandLogPath(plugdirs[x], "", "", 0, 1);
768
769 if ((plugdir = opendir(expanddir.c_str())) == NULL) {
770 continue;
771 }
772
773 while ((plugfile = readdir(plugdir)) != NULL) {
774 int loaded = 0;
775
776 if (plugfile->d_name[0] == '.')
777 continue;
778
779 string fname = plugfile->d_name;
780
781 if (fname.find(".so") == fname.length() - 3) {
782 for (unsigned int y = 0; y < plugin_vec.size(); y++) {
783 if (plugin_vec[y]->filename == expanddir + fname) {
784 loaded = 1;
785 break;
786 }
787 }
788
789 if (loaded)
790 continue;
791
792 panel_plugin_meta *pm = new panel_plugin_meta;
793 pm->filename = expanddir + fname;
794 pm->objectname = fname;
795 pm->dlfileptr = (void *) 0x0;
796 plugin_vec.push_back(pm);
797 }
798 }
799
800 closedir(plugdir);
801 }
802 }
803
LoadPlugins()804 void KisPanelInterface::LoadPlugins() {
805 // Scan for plugins to auto load
806 vector<string> plugprefs = prefs->FetchOptVec("plugin_autoload");
807 for (unsigned int x = 0; x < plugin_vec.size(); x++) {
808 for (unsigned int y = 0; y < plugprefs.size(); y++) {
809 if (plugin_vec[x]->objectname == plugprefs[y] &&
810 plugin_vec[x]->dlfileptr == 0x0) {
811 _MSG("Auto-loading plugin '" + plugprefs[y] + "'", MSGFLAG_INFO);
812 LoadPlugin(plugin_vec[x]->filename, plugin_vec[x]->objectname);
813 break;
814 }
815 }
816 }
817 }
818
819 // keep the last 50 lines of server console for when the window is first opened
kpi_textcli_consolevec(TEXTCLI_PARMS)820 void kpi_textcli_consolevec(TEXTCLI_PARMS) {
821 vector<string> *console =
822 ((KisPanelInterface *) auxptr)->FetchServerConsole();
823 console->push_back(text);
824 if (console->size() > 100)
825 console->erase(console->begin(), console->begin() + console->size() - 100);
826 }
827
SpawnServer(string in_parm)828 void KisPanelInterface::SpawnServer(string in_parm) {
829 server_parm = in_parm;
830 SpawnServer();
831 }
832
kpi_serverpopen_fail(CLIFRAME_FAIL_CB_PARMS)833 void kpi_serverpopen_fail(CLIFRAME_FAIL_CB_PARMS) {
834 ((KisPanelInterface *) auxptr)->RaiseAlert("Kismet Server Failed",
835 InLineWrap("Locally started Kismet server exited unexpectedly "
836 "with error " + IntToString(in_errno) + ". Something "
837 "has gone wrong. Check the Kismet server console for "
838 "more information and errors.", 0, 50));
839 }
840
SpawnServer()841 void KisPanelInterface::SpawnServer() {
842 string servercmd = string(BIN_LOC) + "/kismet_server " + server_parm;
843
844 if (server_framework == NULL) {
845 server_framework = new TextCliFrame(globalreg);
846 server_popen = new PopenClient(globalreg);
847
848 server_framework->RegisterNetworkClient(server_popen);
849 server_framework->RegisterFailCB(kpi_serverpopen_fail, this);
850 server_popen->RegisterClientFramework(server_framework);
851
852 server_text_cb =
853 server_framework->RegisterCallback(kpi_textcli_consolevec, this);
854
855 if (server_popen->Connect(servercmd.c_str(), 'r', NULL, NULL) < 0) {
856 _MSG("Failed to launch kismet_server", MSGFLAG_ERROR);
857 delete server_popen;
858 delete server_framework;
859 server_popen = NULL;
860 server_framework = NULL;
861 }
862 }
863 }
864
KillServer()865 void KisPanelInterface::KillServer() {
866 if (server_framework != NULL) {
867 server_popen->SoftKillConnection();
868 server_framework->RemoveCallback(server_text_cb);
869 }
870 }
871
872 #endif
873
874