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