1 /*
2  *
3  *   Ophcrack is a Lanmanager/NTLM hash cracker based on the faster time-memory
4  *   trade-off using rainbow tables.
5  *
6  *   Created with the help of: Maxime Mueller, Luca Wullschleger, Claude
7  *   Hochreutiner, Andreas Huber and Etienne Dysli.
8  *
9  *   Copyright (c) 2008 Philippe Oechslin, Cedric Tissieres, Bertrand Mesot
10  *
11  *   Ophcrack is free software; you can redistribute it and/or modify
12  *   it under the terms of the GNU General Public License as published by
13  *   the Free Software Foundation; either version 2 of the License, or
14  *   (at your option) any later version.
15  *
16  *   Ophcrack is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with Ophcrack; if not, write to the Free Software
23  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  *
25  *   This program is released under the GPL with the additional exemption
26  *   that compiling, linking, and/or using OpenSSL is allowed.
27  *
28  *
29  *
30  *
31 */
32 #include <QHeaderView>
33 #include <QMessageBox>
34 #include <QTimer>
35 #include <QMenu>
36 #include <assert.h>
37 #include <math.h>
38 #include <config.h>
39 
40 #include "ophcrackgui.h"
41 #include "hash.h"
42 #include "ophtask.h"
43 #include "list.h"
44 #include "message.h"
45 #include "original.h"
46 #include "singlehashdialog.h"
47 #include "aboutdialog.h"
48 //---------------------------------------------------------------------------
OphcrackGUI(ophcrack_t * crack)49 OphcrackGUI::OphcrackGUI(ophcrack_t *crack) : QMainWindow() {
50   setupUi(this);
51 
52   this->crack = crack;
53   this->arg = crack->arg;
54   this->fsm = fsm_alloc(crack);
55 
56   tableDialog = 0;
57   helpDialog = 0;
58   exportDialog = 0;
59   graphDialog = 0;
60 
61   fsm_reset_preload(fsm);
62   fsm_reset_bforce(fsm);
63   resetTime();
64 
65   // Setup the model which will display the hashes.
66 
67   hashModel = new HashModel(hashView, arg->auditmode);
68   hashView->setModel(hashModel);
69   hashSelModel = hashView->selectionModel();
70 
71   connect(hashView, SIGNAL(delSelection()), this, SLOT(delSelection()));
72   connect(hashModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
73 	  this, SLOT(addDelHash(const QModelIndex &, int, int)));
74 
75   connect(hashModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
76 	  this, SLOT(addDelHash(const QModelIndex &, int, int)));
77 
78   deleteButton->setEnabled(false);
79   saveButton->setEnabled(false);
80 
81   // Insert into the model all the hashes which have been loaded
82   // before we start the GUI.
83 
84   list_nd_t *nd;
85 
86   for (nd = crack->hashes->head; nd != 0; nd = nd->next) {
87     hash_t *hsh = (hash_t*)nd->data;
88     hashModel->insertHash(hsh);
89   }
90 
91   // Setup the model which we will use to display the tables.
92 
93   tableModel = new TableModel(tableView);
94   tableView->setModel(tableModel);
95   tableView->hideColumn(TableModel::DIR_COL_IDX);
96 
97   progDelegate = new ProgDelegate(tableView);
98   tableView->setItemDelegateForColumn(TableModel::PROGRESS_COL_IDX, progDelegate);
99 
100   connect(tableModel, SIGNAL(itemChanged(QStandardItem*)),
101 	  this, SLOT(tableItemChanged(QStandardItem*)));
102 
103   // Install the tables which have been specified on the command line.
104 
105   list_t *table_str = crack->arg->table_str_cmd;
106 
107   for (nd = table_str->head; nd != 0; nd = nd->next) {
108     char *tblstr = (char*)nd->data;
109     installTables(tblstr, true, false);
110   }
111 
112   bool replace = table_str->size > 0 ? false : true;
113 
114   // Install the tables given in the config file. Do not replace the
115   // table if some have already been installed from the command line.
116 
117   table_str = crack->arg->table_str_conf;
118 
119   for (nd = table_str->head; nd != 0; nd = nd->next) {
120     char *tblstr = (char*)nd->data;
121     installTables(tblstr, replace, false);
122   }
123 
124   // Mark as not installed the tables which have not been loaded.
125 
126   tableModel->insertRoot(lmalphanum5k);
127   tableModel->insertRoot(lmalphanum10k);
128   tableModel->insertRoot(lmextended);
129   tableModel->insertRoot(lmgermanv1);
130   tableModel->insertRoot(lmgermanv2);
131   tableModel->insertRoot(ntextended);
132   tableModel->insertRoot(ntdict);
133   tableModel->insertRoot(ntnine);
134   tableModel->insertRoot(nteight);
135   tableModel->insertRoot(ntnum);
136   tableModel->insertRoot(ntseven);
137   tableModel->insertRoot(lmflash);
138   tableModel->insertRoot(nteightxl);
139   tableModel->insertRoot(ntspecialxl);
140   tableModel->insertRoot(ntprobafree);
141   tableModel->insertRoot(ntproba10g);
142   tableModel->insertRoot(ntproba60g);
143 
144   // Associate a menu to the load button.
145 
146   loadMenu   = new QMenu();
147   singleHash = loadMenu->addAction("Single hash");
148   hashFile   = loadMenu->addAction("PWDUMP file");
149   sessFile   = loadMenu->addAction("Session file");
150   samFile    = loadMenu->addAction("Encrypted SAM");
151 #ifdef WIN32
152   localSam2  = loadMenu->addAction("Local SAM with samdump2");
153 #endif
154 
155   connect(singleHash, SIGNAL(triggered()), this, SLOT(loadSingleHash()));
156   connect(hashFile, SIGNAL(triggered()), this, SLOT(loadHashFile()));
157   connect(samFile, SIGNAL(triggered()), this, SLOT(loadSamFile()));
158   connect(sessFile, SIGNAL(triggered()), this, SLOT(loadHashFile()));
159 #ifdef WIN32
160   connect(localSam2, SIGNAL(triggered()), this, SLOT(loadLocalSamSamdump()));
161 #endif
162 
163   loadButton->setMenu(loadMenu);
164 
165   // Associate a menu to the save button.
166 
167   saveMenu   = new QMenu();
168   saveFile   = saveMenu->addAction("Save to file");
169   exportFile = saveMenu->addAction("Export to CSV");
170 
171   connect(saveFile, SIGNAL(triggered()), this, SLOT(save()));
172   connect(exportFile, SIGNAL(triggered()), this, SLOT(exportCSV()));
173 
174   saveButton->setMenu(saveMenu);
175 
176   // Connect the other buttons.
177 
178   connect(deleteButton, SIGNAL(clicked()), this, SLOT(delSelection()));
179   connect(crackButton, SIGNAL(clicked()), this, SLOT(startStopCrack()));
180   connect(tableButton, SIGNAL(clicked()), this, SLOT(selectTables()));
181   connect(resetButton, SIGNAL(clicked()), this, SLOT(resetStat()));
182   connect(graphButton, SIGNAL(clicked()), this, SLOT(displayGraph()));
183   connect(threadSpinBox, SIGNAL(valueChanged(int)), this, SLOT(threadChanged(int)));
184   connect(hreduxSlider, SIGNAL(valueChanged(int)), this, SLOT(hreduxChanged(int)));
185   connect(queueSlider, SIGNAL(valueChanged(int)), this, SLOT(queueChanged(int)));
186   connect(defaultButton, SIGNAL(clicked()), this, SLOT(defaultConfig()));
187   connect(bforceBox, SIGNAL(currentIndexChanged(int)), this, SLOT(bforceChanged(int)));
188   connect(hideUnameBox, SIGNAL(currentIndexChanged(int)), this, SLOT(hideUnameChanged(int)));
189   connect(auditModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(auditModeChanged(int)));
190   connect(aboutButton, SIGNAL(clicked()), this, SLOT(displayAbout()));
191   connect(helpButton, SIGNAL(clicked()), this, SLOT(displayHelp()));
192   connect(sessBox, SIGNAL(stateChanged(int)), this, SLOT(sessOnOff(int)));
193   connect(sessButton, SIGNAL(clicked()), this, SLOT(chooseSessFile()));
194 
195   // Setup a timer which will be used to pool the message queue at
196   // regular intervals.
197 
198   QTimer *timer = new QTimer(this);
199   connect(timer, SIGNAL(timeout()), this, SLOT(handleMessages()));
200   timer->start(500);
201 
202   // Associtate the tables to the hashes and update the statistics,
203   // status bar and the preferences.
204 
205   tablesChanged();
206 
207   updateStat();
208   updateStatus();
209   updateConfig();
210 
211   // Start cracking if the user asked it.
212 
213   if (arg->run)
214     emit startStopCrack();
215 }
216 //---------------------------------------------------------------------------
tableItemChanged(QStandardItem * item)217 void OphcrackGUI::tableItemChanged(QStandardItem *item) {
218   QStandardItem *parent = item->parent();
219   QModelIndex index = tableModel->indexFromItem(item);
220 
221   int row = index.row();
222   int col = index.column();
223 
224   if (col > 0) return;
225 
226   // If it is a top level item, then we refresh all the root items.
227 
228   if (parent == 0) {
229     int nrows = tableModel->rowCount();
230 
231     for (int i=0; i<nrows; ++i) {
232       QStandardItem *root = tableModel->item(i, 0);
233       int nenabled = root->data(Qt::UserRole).toInt();
234 
235       if (nenabled > 0)
236 	tableView->setRowHidden(i, QModelIndex(), false);
237       else
238 	tableView->setRowHidden(i, QModelIndex(), true);
239     }
240   }
241 
242   // If is is a child item, then we refresh only the concerned item.
243 
244   else {
245     QModelIndex index = tableModel->indexFromItem(parent);
246     table_t *tbl = tableModel->tableFromItem(item);
247 
248     if (tbl && tbl->enabled)
249       tableView->setRowHidden(row, index, false);
250     else
251       tableView->setRowHidden(row, index, true);
252   }
253 }
254 //---------------------------------------------------------------------------
selectTables(void)255 void OphcrackGUI::selectTables(void) {
256   if (tableDialog == 0) {
257     tableDialog = new TableDialog(tableModel, this);
258 
259     connect(tableDialog, SIGNAL(install(QString, bool, bool)),
260 	    this, SLOT(installTables(QString, bool, bool)));
261   }
262 
263   if (tableDialog->exec() == QDialog::Accepted) {
264     fsm_reset_preload(fsm);
265     tablesChanged();
266   }
267 }
268 //---------------------------------------------------------------------------
tablesChanged(void)269 void OphcrackGUI::tablesChanged(void) {
270   // Return to the 'start' state and ignore any pending message.
271 
272   fsm->oldstate = st_start;
273   list_clear(fsm->pending_msg);
274 
275   // Save the table configuration and update the status bar.
276 
277   saveConfig();
278   updateStatus();
279 
280   // Build a list of the enabled tables following the order specified
281   // by the user.
282 
283   list_t *enabled = crack->enabled;
284   list_clear(enabled);
285 
286   int nrows = tableModel->rowCount();
287   int i, j;
288 
289   for (i=0; i<nrows; ++i) {
290     QStandardItem *item = tableModel->item(i, 0);
291     int ntables = item->rowCount();
292 
293     for (j=0; j<ntables; ++j) {
294       QStandardItem *child = item->child(j, 0);
295       table_t *tbl = (table_t*)child->data(Qt::UserRole).value<void*>();
296 
297       if (tbl->enabled)
298 	list_add_tail(enabled, tbl);
299     }
300   }
301 
302   // Associate the enabled tables to the hashes. The tables are
303   // added in the order specified by the user. Since, for a given
304   // hash, some tables might have been searched in already, we have to
305   // be careful to retain the last visited column so that we do not
306   // need to go through the whole table again.
307 
308   list_t *hashes = crack->hashes;
309   int maxtid = crack->maxtid;
310 
311   list_nd_t *hnd;
312   list_nd_t *tnd;
313 
314   htbl_t **id_to_htbl = (htbl_t**)malloc(maxtid*sizeof(htbl_t*));
315 
316   for (hnd = hashes->head; hnd != 0; hnd = hnd->next) {
317     hash_t *hsh = (hash_t*)hnd->data;
318 
319     // We store the tables associated with the current hash into the
320     // id_to_htbl array so that we can retrieve them easily later. The
321     // column index is reset to its 'covered' (minus one) value so
322     // that we are sure we do not miss a column.
323 
324     memset(id_to_htbl, 0, maxtid*sizeof(htbl_t*));
325 
326     while (hsh->tables->size > 0) {
327       htbl_t *htbl = (htbl_t*)list_rem_head(hsh->tables);
328       table_t *tbl = htbl->tbl;
329 
330       assert(id_to_htbl[tbl->id] == 0);
331 
332       id_to_htbl[tbl->id] = htbl;
333       htbl->col = htbl->covered-1;
334     }
335 
336     // We associate the tables to the current hash following the order
337     // specified by the user.
338 
339     list_t *enabled = crack->enabled;
340 
341     for (tnd = enabled->head; tnd != 0; tnd = tnd->next) {
342       table_t *tbl = (table_t*)tnd->data;
343       htbl_t *htbl = id_to_htbl[tbl->id];
344 
345       if (htbl != 0) {
346 	list_add_tail(hsh->tables, htbl);
347 	id_to_htbl[tbl->id] = 0;
348       } else
349 	ophcrack_associate(crack, hsh, tbl);
350     }
351 
352     // Some tables which were previously associated to the hash might
353     // not have been enabled this time. We store them anyway because
354     // we want to keep track of the last column we have been searching
355     // from.
356 
357     int i;
358 
359     for (i=0; i<maxtid; ++i) {
360       htbl_t *htbl = id_to_htbl[i];
361 
362       if (htbl != 0)
363 	list_add_tail(hsh->tables, htbl);
364     }
365 
366     // Since we changed the list of tables, we should reset the table
367     // list node pointer.
368 
369     hsh->tnd = 0;
370   }
371 
372   free(id_to_htbl);
373 
374   // Update the status of the search in the tables.
375 
376   ophcrack_update(crack);
377   updateProgress();
378 }
379 //---------------------------------------------------------------------------
hashesAdded(list_t * hashes)380 void OphcrackGUI::hashesAdded(list_t *hashes) {
381   list_t *enabled = crack->enabled;
382   list_nd_t *hnd, *tnd;
383 
384   for (hnd = hashes->head; hnd != 0; hnd = hnd->next) {
385     hash_t *hsh = (hash_t*)hnd->data;
386 
387     assert(hsh->tables->size == 0);
388 
389     for (tnd = enabled->head; tnd != 0; tnd = tnd->next) {
390       table_t *tbl = (table_t*)tnd->data;
391       ophcrack_associate(crack, hsh, tbl);
392     }
393   }
394 
395   fsm_reset_preload(fsm);
396   fsm_reset_bforce(fsm);
397 
398   ophcrack_update(crack);
399   updateProgress();
400 }
401 //---------------------------------------------------------------------------
startStopCrack(void)402 void OphcrackGUI::startStopCrack(void) {
403   int npwds_total = crack->npwds_total;
404   int npwds_found = crack->npwds_found;
405 
406   if (fsm->state == st_wait && npwds_found < npwds_total) {
407     startCrack();
408     fsm_reset(fsm);
409 
410     fsm->state = st_start;
411     fsm_handle_start(fsm);
412   }
413 
414   else if (fsm->state == st_pause1) {
415     if (npwds_found < npwds_total) {
416       startCrack();
417 
418       fsm->state = st_pause2;
419       fsm_handle_pause2(fsm, 0);
420     }
421   }
422 
423   else if (fsm->state == st_pause2) {
424     stopCrack();
425     fsm->state = st_pause1;
426   }
427 
428   else if (fsm->state != st_wait) {
429     stopCrack();
430     fsm_pause(fsm);
431   }
432 }
433 //---------------------------------------------------------------------------
loadSingleHash(void)434 void OphcrackGUI::loadSingleHash(void) {
435   SingleHashDialog singleHashDialog;
436 
437   if (singleHashDialog.exec() == QDialog::Accepted) {
438     char *str = strdup(singleHashDialog.getHash());
439 
440     list_t *hashes = list_alloc();
441     list_nd_t *nd;
442 
443     int maxhid = crack->maxhid;
444     int ret = hash_extract_lmnt(str, hashes, maxhid);
445 
446     // If not hashes could be loaded, then we inform the user.
447 
448     if (ret == 0) {
449       QMessageBox msgBox(QMessageBox::Warning,
450 			 "Warning",
451 			 QString("No hashes could be extracted." ) +
452 			 QString("Check that you provided valid hashes ") +
453 			 QString("in one of the three formats allowed."),
454 			 QMessageBox::Ok);
455       msgBox.exec();
456     }
457 
458     // Otherwise, we add the hashes to the list of hashes we must
459     // potentially crack.
460 
461     else {
462       for (nd = hashes->head; nd != 0; nd = nd->next) {
463 	hash_t *hsh = (hash_t*)nd->data;
464 
465 	ophcrack_add_hash(crack, hsh);
466 	hashModel->insertHash(hsh);
467       }
468 
469       hashesAdded(hashes);
470     }
471 
472     free(str);
473     list_free(hashes);
474   }
475 }
476 //---------------------------------------------------------------------------
loadHashFile(void)477 void OphcrackGUI::loadHashFile(void) {
478 
479   QString fileName = QFileDialog::getOpenFileName(this,
480 						  tr("Open PWDUMP file"),
481 						  QString(),
482 						  QString());
483 
484   if (!fileName.isNull()) {
485     const char *fname = fileName.toLatin1().constData();
486 
487     // If the file cannot be read, then we warn the user.
488 
489     FILE *file = fopen(fname, "r");
490 
491     if (file == 0) {
492       QMessageBox msgBox(QMessageBox::Warning,
493 			 "Warning",
494 			 QString("Cannot open file %1 for reading.").arg(fname),
495 			 QMessageBox::Ok);
496       msgBox.exec();
497     }
498 
499     // Otherwise, we load all the hashes we find.
500 
501     else {
502       list_t *hashes = list_alloc();
503       list_nd_t *nd;
504 
505       int maxhid = crack->maxhid;
506       hash_load_pwdump(hashes, file, maxhid);
507 
508       for (nd = hashes->head; nd != 0; nd = nd->next) {
509 	hash_t *hsh = (hash_t*)nd->data;
510 
511 	ophcrack_add_hash(crack, hsh);
512 	hashModel->insertHash(hsh);
513       }
514 
515       hashesAdded(hashes);
516 
517       list_free(hashes);
518       fclose(file);
519     }
520   }
521 }
522 //---------------------------------------------------------------------------
loadSamFile(void)523 void OphcrackGUI::loadSamFile(void) {
524 
525   QString dir = QFileDialog::getExistingDirectory(this,
526 						  tr("Select the directory containing the encrypted SAM and SYSTEM files.\n(Usually under C:\\WINDOWS\\system32\\config\\)"),
527 						  QString(),
528 						  QFileDialog::ShowDirsOnly);
529 
530   if (!dir.isNull()) {
531     list_t *hashes = list_alloc();
532     list_nd_t *nd;
533 
534     // Retrieve the hashes from the encrypted SAM.
535 
536     int maxhid = crack->maxhid;
537     int npwds = hash_load_sam(hashes, dir.toLatin1().constData(), maxhid);
538     QString buff = 0;
539 
540     // Check that something has actually been loaded.
541 
542     if (npwds == 0)
543       buff = QString("No proper hashes have been found in the encrypted SAM file in %1.").arg(arg->samdir);
544 
545     // Check if the SYSTEM or SAM file could not be found.
546 
547     else if (npwds == -1)
548       buff = QString("No SYSTEM file has been found in %1.").arg(arg->samdir);
549 
550     else if (npwds == -2)
551       buff = QString("No SAM file has been found in %1.").arg(arg->samdir);
552 
553     // Check if there was a problem while reading the SYSTEM or SAM file.
554 
555     else if (npwds == -3)
556       buff = QString("A problem occurred while reading the SYSTEM file found in %1.").arg(arg->samdir);
557 
558     else if (npwds == -4)
559       buff = QString("A problem occurred while reading the SAM file found in %1.").arg(arg->samdir);
560 
561     if (npwds <= 0) {
562       QMessageBox msgBox(QMessageBox::Warning,
563 			 "Warning",
564 			 buff,
565 			 QMessageBox::Ok);
566       msgBox.exec();
567     }
568 
569 
570     // Add the hashes.
571 
572     for (nd = hashes->head; nd != 0; nd = nd->next) {
573       hash_t *hsh = (hash_t*)nd->data;
574 
575       ophcrack_add_hash(crack, hsh);
576       hashModel->insertHash(hsh);
577     }
578 
579     hashesAdded(hashes);
580     list_free(hashes);
581   }
582 }
583 //---------------------------------------------------------------------------
loadLocalSamSamdump(void)584 void OphcrackGUI::loadLocalSamSamdump(void) {
585   // Retrieve the hashes from the local SAM with samdump2.
586 
587   list_t *hashes = list_alloc();
588   list_nd_t *nd;
589 
590   // Retrieve the hashes from the encrypted SAM.
591 
592   int maxhid = crack->maxhid;
593   int npwds = hash_dump_sam(hashes, maxhid);
594   QString buff = 0;
595 
596   // Check that something has actually been loaded.
597 
598   if (npwds == 0)
599     buff = QString("No proper hashes have been dumped with samdump2");
600 
601   else if (npwds == -1)
602     buff = QString("Error in samdump2: get_live_syskey function");
603 
604   else if (npwds == -2)
605     buff = QString("Error in samdump2: get_sam function\n\nMake sure ophcrack is running with administrator rights to perform this action. On Windows Vista and later, right-click on ophcrack icon and select run as administrator.\n\nThis function is not supported on Windows 10 Anniversary update. Use mimikatz (https://github.com/gentilkiwi/mimikatz/releases/) to dump local hashes: mimikatz privilege::debug  token::elevate lsadump::sam");
606 
607   else if (npwds == -3)
608     buff = QString("Error in samdump2: samdump2 function");
609 
610   if (npwds <= 0) {
611     QMessageBox msgBox(QMessageBox::Warning,
612 		       "Warning",
613 		       buff,
614 		       QMessageBox::Ok);
615     msgBox.exec();
616   }
617 
618 
619   // Add the hashes.
620 
621   for (nd = hashes->head; nd != 0; nd = nd->next) {
622     hash_t *hsh = (hash_t*)nd->data;
623 
624     ophcrack_add_hash(crack, hsh);
625     hashModel->insertHash(hsh);
626   }
627 
628   hashesAdded(hashes);
629   list_free(hashes);
630 }
631 //---------------------------------------------------------------------------
save(void)632 void OphcrackGUI::save(void) {
633   QString fileName;
634 
635   // If an output file has already been specified, then we preselect it.
636 
637   if (arg->ofname != 0)
638     fileName = QFileDialog::getSaveFileName(this,
639 					    tr("Save File"),
640 					    arg->ofname,
641 					    QString());
642 
643   // Otherwise, we preselect the current directory.
644 
645   else
646     fileName = QFileDialog::getSaveFileName(this,
647 					    tr("Save File"),
648 					    QDir::currentPath(),
649 					    QString());
650 
651   // If the user chose a file, then we use it to store all the hashes
652   // which are currently loaded.
653 
654   if (!fileName.isNull()) {
655     const char *fname = fileName.toLatin1().constData();
656 
657     // Store the selected file so that we can preselect it later.
658 
659     if (arg->ofname != 0) free(arg->ofname);
660     arg->ofname = strdup(fname);
661 
662     FILE *file = fopen(fname, "w");
663 
664     if (file == 0) {
665       QMessageBox msgBox(QMessageBox::Warning,
666 			 "Warning",
667 			 QString("Cannot open file %1 for writing.").arg(fname),
668 			 QMessageBox::Ok);
669       msgBox.exec();
670     }
671 
672     else {
673       scheduler_t *sched = crack->sched;
674       pthread_mutex_t *mutex = sched->mutex;
675 
676       pthread_mutex_lock(mutex);
677       ophcrack_save(crack, file, 0, 0);
678       pthread_mutex_unlock(mutex);
679 
680       fclose(file);
681     }
682   }
683 }
684 //---------------------------------------------------------------------------
exportCSV(void)685 void OphcrackGUI::exportCSV(void) {
686   QString fileName;
687   int *fields;
688 
689   fields = (int*)malloc(13*sizeof(int));
690   if (exportDialog == 0)
691     exportDialog = new ExportDialog(this);
692 
693   if (exportDialog->exec() == QDialog::Accepted) {
694     exportDialog->getFields(fields);
695     fileName = QFileDialog::getSaveFileName(this,
696 					    tr("Export to CSV"),
697 					    QDir::currentPath(),
698 					    QString());
699 
700     if (!fileName.isNull()) {
701       const char *fname = fileName.toLatin1().constData();
702 
703       FILE *file = fopen(fname, "w");
704 
705       if (file == 0) {
706 	QMessageBox msgBox(QMessageBox::Warning,
707 			   "Warning",
708 			 QString("Cannot open file %1 for writing.").arg(fname),
709 			   QMessageBox::Ok);
710 	msgBox.exec();
711       }
712 
713       else {
714 	scheduler_t *sched = crack->sched;
715 	pthread_mutex_t *mutex = sched->mutex;
716 
717 	pthread_mutex_lock(mutex);
718 	ophcrack_export_csv(crack, file, fields,
719 			    exportDialog->getSeparator(),
720 			    exportDialog->getQuotes());
721 	pthread_mutex_unlock(mutex);
722 
723 	fclose(file);
724       }
725     }
726 
727   }
728   free(fields);
729 }
730 //---------------------------------------------------------------------------
resetStat(void)731 void OphcrackGUI::resetStat(void) {
732   scheduler_t *sched = crack->sched;
733   pthread_mutex_t *mutex = sched->mutex;
734 
735   pthread_mutex_lock(mutex);
736   ophstat_reset(crack->stat);
737   pthread_mutex_unlock(mutex);
738 
739   resetTime();
740   updateStat();
741   updateStatus();
742 }
743 //---------------------------------------------------------------------------
displayGraph(void)744 void OphcrackGUI::displayGraph(void) {
745   if (graphDialog == 0) {
746     graphDialog = new GraphDialog(this);
747   }
748 
749   int tv_sec = (int) tm_total.tv_sec;
750 
751   graphDialog->plot(crack->stat, tv_sec);
752   graphDialog->show();
753 }
754 //---------------------------------------------------------------------------
handleMessages(void)755 void OphcrackGUI::handleMessages(void) {
756   message_t *msg = 0;
757 
758   int count = 1000;
759   bool flag = false;
760 
761   // Handle at most 'count' messages.
762 
763   state_t fsm_state = fsm->state;
764 
765   while (count-- && (msg = message_tryget())) {
766     // A password has been found.
767 
768     if (msg->kind == msg_found) {
769       msg_found_t *found = (msg_found_t*)msg->data;
770       hash_t *hsh = found->hsh;
771 
772       int tv_sec = (int) tm_total.tv_sec;
773 
774       if (graphDialog != 0 && graphDialog->isVisible())
775 	graphDialog->plot(crack->stat, tv_sec);
776       hashModel->updateHash(hsh);
777     }
778 
779     // The preloading of a single file is done.
780 
781     else if (msg->kind == msg_preload) {
782       msg_load_t *load = (msg_load_t*)msg->data;
783       table_t *tbl = load->tbl;
784 
785       if (tbl && load->done)
786         tableModel->updateTable(tbl);
787 
788       else if (tbl == 0 && load->size == 0) {
789         for (list_nd_t *nd = crack->enabled->head; nd != 0; nd = nd->next)
790           tableModel->updateTable((table_t*)nd->data);
791       }
792     }
793 
794     // A table has been unloaded.
795 
796     else if (msg->kind == msg_unload) {
797       msg_load_t *load = (msg_load_t*)msg->data;
798       table_t *tbl = load->tbl;
799 
800       if (tbl)
801 	tableModel->updateTable(tbl);
802     }
803 
804     // Ask the finite state machine to take the appropriate steps
805     // given the received message.
806 
807     msg = fsm_next(fsm, msg);
808 
809     // Delete the message.
810 
811     if (msg)
812       message_free(msg);
813 
814     flag = true;
815   }
816 
817   if (fsm->state & (~st_wait & ~st_pause1 & ~st_pause2)) {
818     updateStat();
819     updateProgress();
820     updateStatus();
821   }
822 
823   else if (flag)
824     updateStatus();
825 
826   // Check if it is time to save the session.
827 
828   if (arg->ssave && fsm->state & (st_work1 + st_work2)) {
829     struct timeval tm_curr;
830     gettimeofday(&tm_curr, 0);
831 
832     time_t tv_sec = tm_curr.tv_sec - tm_sess.tv_sec;
833 
834     if (tv_sec >= 30) {
835       tm_sess = tm_curr;
836       fsm_ssave(fsm);
837     }
838   }
839 
840   // Check if the job is finished.
841 
842   if (fsm->state == st_wait && fsm_state != st_wait) stopCrack();
843 }
844 //---------------------------------------------------------------------------
startCrack(void)845 void OphcrackGUI::startCrack(void) {
846   crackButton->setIcon(QIcon(":/icons/pixmaps/stop.png"));
847   crackButton->setText("Stop");
848 
849   loadButton->setEnabled(false);
850   deleteButton->setEnabled(false);
851   tableButton->setEnabled(false);
852   tabWidget->setTabEnabled(2, false);
853 
854   gettimeofday(&tm_start, 0);
855   tm_sess = tm_start;
856   extern struct timeval tm_main_start;
857   tm_main_start = tm_start;
858 
859   showNotFound(false);
860 }
861 //---------------------------------------------------------------------------
stopCrack(void)862 void OphcrackGUI::stopCrack(void) {
863   crackButton->setIcon(QIcon(":/icons/pixmaps/crack.png"));
864   crackButton->setText("Crack");
865 
866   loadButton->setEnabled(true);
867   deleteButton->setEnabled(crack->hashes->size > 0 ? true : false);
868   tableButton->setEnabled(true);
869   tabWidget->setTabEnabled(2, true);
870 
871   updateStat();
872   updateStatus();
873   updateProgress();
874 
875   if (fsm->state == st_wait) showNotFound(true);
876 }
877 //---------------------------------------------------------------------------
delSelection(void)878 void OphcrackGUI::delSelection(void) {
879   // Check that we are in a state which allow deleting hashes.
880 
881   if (fsm->state & (~st_wait & ~st_pause1)) return;
882 
883   // Check that some hashes have actually been selected.
884 
885   QList<QModelIndex> indexes = hashSelModel->selectedRows();
886 
887   if (indexes.isEmpty()) return;
888 
889   // Create a map which gives, for a given hash id, the list of hashes
890   // with that id in the order they are stored in the list of hashes
891   // in the ophrack_t data structure.
892 
893   QMultiMap<int, hash_t*>hashFromId;
894   list_t *hashes = crack->hashes;
895 
896   while (hashes->size > 0) {
897     hash_t *hsh = (hash_t*)list_rem_tail(hashes);
898     hashFromId.insert(hsh->id, hsh);
899   }
900 
901   // Delete the selected hashes. If we are in the 1st pause state, it
902   // might not be appropriate to free the memory occupied by a hash
903   // because it might still be used by a running task. In that case,
904   // we store the hashes and they will be removed later, when it will
905   // be safer.
906 
907   int maxhid = crack->maxhid;
908 
909   while (!indexes.isEmpty()) {
910     QModelIndex index = indexes.takeFirst();
911     int id = index.data(Qt::UserRole).toInt();
912 
913     assert(id >= 0 && id < maxhid);
914     QList<hash_t*> hashes = hashFromId.values(id);
915     assert(hashes.size() > 0);
916 
917     while (!hashes.isEmpty()) {
918       hash_t *hsh = hashes.takeFirst();
919       hsh->id = -1;
920 
921       if (fsm->state == st_pause1)
922 	list_add_tail(fsm->htoremove, hsh);
923       else
924 	hash_free(hsh);
925     }
926 
927     hashFromId.remove(id);
928   }
929 
930   // Manually reset the hash related stuff in ophcrack.
931 
932   crack->hnd = 0;
933   crack->maxhid = 0;
934   crack->npwds_total = 0;
935   crack->npwds_found = 0;
936   for (int i=0; i<16; i++) {
937     crack->stat->length[i]=0;
938     crack->stat->category[i]=0;
939   }
940   list_clear(crack->stat->time);
941 
942   // Remove all the lines in the hash view. Since the number of rows
943   // changes, we always remove the first one.
944 
945   int nrows = hashModel->rowCount();
946 
947   for (int i=0; i<nrows; ++i)
948     hashModel->removeRow(0);
949 
950   // Adjust the id of the remaining hashes and insert them into the
951   // ophcrack_t data structure.
952 
953   for (int i=0; i<maxhid; ++i) {
954     QList<hash_t*> hashes = hashFromId.values(i);
955     int j = i;
956 
957     while (hashes.isEmpty() && ++j < maxhid)
958       hashes = hashFromId.values(j);
959 
960     if (j == maxhid) break;
961     hashFromId.remove(j);
962 
963     while (!hashes.isEmpty()) {
964       hash_t *hsh = hashes.takeFirst();
965 
966       hsh->id = i;
967       ophcrack_add_hash(crack, hsh);
968       hashModel->insertHash(hsh);
969     }
970   }
971 
972   assert(crack->maxhid == crack->npwds_total);
973 
974   updateStatus();
975   updateProgress();
976 }
977 //---------------------------------------------------------------------------
updateStat(void)978 void OphcrackGUI::updateStat(void) {
979   scheduler_t *sched = crack->sched;
980   pthread_mutex_t *mutex = sched->mutex;
981   ophstat_t *stat = crack->stat;
982 
983   pthread_mutex_lock(mutex);
984   uint64_t hredux = stat->hredux;
985   uint64_t prefix = stat->prefix;
986   uint64_t postfix = stat->postfix;
987   uint64_t start = stat->start;
988   uint64_t fseek_idx = stat->fseek_idx;
989   uint64_t fseek_end = stat->fseek_end;
990   uint64_t fseek_srt = stat->fseek_srt;
991   uint64_t falarm = stat->falarm;
992   uint64_t falarm_hredux = stat->falarm_hredux;
993   uint64_t match_table = stat->match_table;
994   uint64_t match_bforce = stat->match_bforce;
995   pthread_mutex_unlock(mutex);
996 
997   // Hash/Redux and false alarms.
998 
999   hreduxField->clear();
1000   hreduxField->insert(QString("%1").arg(hredux));
1001 
1002   falarmField->clear();
1003   falarmField->insert(QString("%1").arg(falarm));
1004 
1005   falarm2Field->clear();
1006 
1007   if (falarm > 0)
1008     falarm2Field->insert(QString("%1").arg(falarm_hredux / falarm));
1009   else
1010     falarm2Field->insert(QString("0"));
1011 
1012   // Passwords.
1013 
1014   pwdField->clear();
1015   pwdField->insert(QString("%1").arg(match_table));
1016 
1017   bforceField->clear();
1018   bforceField->insert(QString("%1").arg(match_bforce));
1019 
1020   // Fseek.
1021 
1022   uint64_t fseek = fseek_idx + fseek_end + fseek_srt;
1023 
1024   fseekField->clear();
1025   fseekField->insert(QString("%1").arg(fseek));
1026 
1027   idxField->clear();
1028   idxField->insert(QString("%1").arg(fseek_idx));
1029 
1030   endField->clear();
1031   endField->insert(QString("%1").arg(fseek_end));
1032 
1033   srtField->clear();
1034   srtField->insert(QString("%1").arg(fseek_srt));
1035 
1036   // Prefix, postfix and start.
1037 
1038   prefixField->clear();
1039   prefixField->insert(QString("%1").arg(prefix));
1040 
1041   postfixField->clear();
1042   postfixField->insert(QString("%1").arg(postfix));
1043 
1044   startField->clear();
1045   startField->insert(QString("%1").arg(start));
1046 
1047 }
1048 //---------------------------------------------------------------------------
updateProgress(void)1049 void OphcrackGUI::updateProgress(void) {
1050   scheduler_t *sched = crack->sched;
1051   pthread_mutex_t *mutex = sched->mutex;
1052 
1053   ophcrack_update(crack);
1054 
1055   pthread_mutex_lock(mutex);
1056   tableModel->updateProgress();
1057   pthread_mutex_unlock(mutex);
1058 }
1059 //---------------------------------------------------------------------------
updateStatus(void)1060 void OphcrackGUI::updateStatus(void) {
1061   int npwds_total = crack->npwds_total;
1062   int npwds_found = crack->npwds_found;
1063 
1064   // Preload progress.
1065 
1066   uint64_t psize_curr  = fsm->psize_curr;
1067   uint64_t psize_total = fsm->psize_total;
1068   int psize_ratio = 0;
1069 
1070   if (psize_total > 0)
1071     psize_ratio = (100*psize_curr) / psize_total;
1072 
1073   QString preloadStr = "waiting";
1074 
1075   if (psize_ratio == 100)
1076     preloadStr = "done";
1077 
1078   else if (psize_total > 0)
1079     preloadStr = QString("%1%").arg(psize_ratio);
1080 
1081   preloadEdit->setText(preloadStr);
1082 
1083   // Brute force.
1084 
1085   if (!arg->bforce)
1086     bforceEdit->setText("disabled");
1087 
1088   else {
1089     uint64_t bforce_curr  = fsm->bforce_curr;
1090     uint64_t bforce_total = fsm->bforce_total;
1091     int bforce_ratio = 0;
1092 
1093     if (bforce_total > 0)
1094       bforce_ratio = (100*bforce_curr) / bforce_total;
1095 
1096     QString bforceStr = "waiting";
1097 
1098     if (bforce_ratio == 100)
1099       bforceStr = "done";
1100 
1101     else if (bforce_total > 0)
1102       bforceStr = QString("%1%").arg(bforce_ratio);
1103 
1104     bforceEdit->setText(bforceStr);
1105   }
1106 
1107   // Number of passwords found.
1108 
1109   QString pwdStr = QString("%1/%2").arg(npwds_found)
1110     .arg(npwds_total);
1111 
1112   pwdEdit->setText(pwdStr);
1113 
1114   // Elapsed time.
1115 
1116   if (fsm->state & (~st_wait & ~st_pause1 & ~st_pause2)) {
1117     struct timeval tm_stop;
1118     extern struct timeval tm_main_total;
1119     gettimeofday(&tm_stop, 0);
1120 
1121     tm_total.tv_sec += tm_stop.tv_sec - tm_start.tv_sec;
1122     tm_main_total.tv_sec = tm_total.tv_sec;
1123     tm_start = tm_stop;
1124   }
1125 
1126   long tv_sec = tm_total.tv_sec;
1127   long hour   = tv_sec / 3600;
1128   long sec    = tv_sec - 3600 * hour;
1129   long min    = sec / 60;
1130 
1131   sec %= 60;
1132 
1133   QString tmStr = QString("%1h %2m %3s").arg(hour).arg(min)
1134     .arg(sec);
1135 
1136   timeEdit->setText(tmStr);
1137 }
1138 //---------------------------------------------------------------------------
resetTime(void)1139 void OphcrackGUI::resetTime(void) {
1140   tm_start.tv_sec  = 0;
1141   tm_start.tv_usec = 0;
1142   tm_total.tv_sec  = 0;
1143   tm_total.tv_usec = 0;
1144 
1145   if (fsm->state & (~st_wait & ~st_pause1 & ~st_pause2))
1146     gettimeofday(&tm_start, 0);
1147 }
1148 //---------------------------------------------------------------------------
defaultConfig(void)1149 void OphcrackGUI::defaultConfig(void) {
1150   arg_default(arg);
1151   updateConfig();
1152 }
1153 //---------------------------------------------------------------------------
updateConfig(void)1154 void OphcrackGUI::updateConfig(void) {
1155   int nthreads  = arg->nthreads;
1156   int nhredux   = arg->nhredux;
1157   int mdqueue   = arg->mdqueue;
1158   int bforce    = arg->bforce;
1159   int hideuname = arg->hideuname;
1160   int auditmode = arg->auditmode;
1161 
1162   threadSpinBox->setValue(nthreads);
1163   threadChanged(nthreads);
1164 
1165   hreduxSlider->setSliderPosition(nhredux / 5000);
1166   hreduxChanged(nhredux / 5000);
1167 
1168   queueSlider->setSliderPosition(mdqueue / 50);
1169   queueChanged(mdqueue / 50);
1170 
1171   bforceBox->setCurrentIndex(bforce > 0 ? 1 : 0);
1172 
1173   hideUnameBox->setCurrentIndex(hideuname > 0 ? 1 : 0);
1174 
1175   auditModeBox->setCurrentIndex(auditmode > 0 ? 1 : 0);
1176 
1177   if (arg->sfname != 0) {
1178     sessEdit->setText(arg->sfname);
1179     sessBox->setCheckState(arg->ssave ? Qt::Checked : Qt::Unchecked);
1180     sessBox->setEnabled(true);
1181   }
1182 }
1183 //---------------------------------------------------------------------------
threadChanged(int x)1184 void OphcrackGUI::threadChanged(int x) {
1185   if (x != crack->arg->nthreads) {
1186     arg->nthreads = x;
1187     threadLabel->setText(QString("restart required"));
1188   }
1189   else
1190     threadLabel->setText(QString(""));
1191 }
1192 //---------------------------------------------------------------------------
hreduxChanged(int x)1193 void OphcrackGUI::hreduxChanged(int x) {
1194   arg->nhredux = 5000*x;
1195   hreduxLabel->setText(QString("%1").arg(arg->nhredux));
1196 }
1197 //---------------------------------------------------------------------------
queueChanged(int x)1198 void OphcrackGUI::queueChanged(int x) {
1199   arg->mdqueue = 50*x;
1200   queueLabel->setText(QString("%1").arg(arg->mdqueue));
1201 }
1202 //---------------------------------------------------------------------------
bforceChanged(int x)1203 void OphcrackGUI::bforceChanged(int x) {
1204   arg->bforce = x;
1205 
1206   fsm_reset_bforce(fsm);
1207   updateStatus();
1208 }
1209 //---------------------------------------------------------------------------
hideUnameChanged(int x)1210 void OphcrackGUI::hideUnameChanged(int x) {
1211   arg->hideuname = x;
1212 
1213   hashModel->setUnameVisible(x);
1214 
1215   list_nd_t *nd;
1216   for (nd = crack->hashes->head; nd != 0; nd = nd->next) {
1217     hash_t *hsh = (hash_t*)nd->data;
1218     hashModel->updateHash(hsh);
1219   }
1220 
1221 }
1222 //---------------------------------------------------------------------------
auditModeChanged(int x)1223 void OphcrackGUI::auditModeChanged(int x) {
1224   arg->auditmode = x;
1225 
1226   hashModel->setAuditMode(x);
1227 
1228   list_nd_t *nd;
1229   for (nd = crack->hashes->head; nd != 0; nd = nd->next) {
1230     hash_t *hsh = (hash_t*)nd->data;
1231     hashModel->updateHash(hsh);
1232   }
1233 
1234   if (x)
1235     hideUnameBox->setEnabled(false);
1236   else
1237     hideUnameBox->setEnabled(true);
1238 }
1239 //---------------------------------------------------------------------------
saveConfig(void)1240 void OphcrackGUI::saveConfig(void) {
1241   FILE *file = fopen(arg->cfname, "w");
1242 
1243   if (file == 0) return;
1244 
1245   // Save the order and state (enabled or not) of the tables.
1246 
1247   int nrows = tableModel->rowCount();
1248 
1249   for (int i=0; i<nrows; ++i) {
1250     QStandardItem *root = tableModel->item(i, 0);
1251     int nenabled  = root->data(Qt::UserRole).toInt();
1252     int nchildren = root->rowCount();
1253 
1254     if (nenabled == -1) continue;
1255 
1256     QStandardItem *child = root->child(0, 0);
1257     table_t *tbl = tableModel->tableFromItem(child);
1258     const char *path = tbl->path;
1259 
1260     fprintf(file, "table %s", path);
1261 
1262     if (nenabled == 0) {
1263       fprintf(file, ",-\n");
1264       continue;
1265     }
1266 
1267     for (int j=0; j<nchildren; ++j) {
1268       child = root->child(j, 0);
1269       tbl = tableModel->tableFromItem(child);
1270 
1271       if (tbl->enabled)
1272 	fprintf(file, ",%d", tbl->idx);
1273     }
1274 
1275     fprintf(file, "\n");
1276   }
1277 
1278   // Save the preferences.
1279 
1280   fprintf(file, "nthreads %d\n", arg->nthreads);
1281   fprintf(file, "nhredux %d\n", arg->nhredux);
1282   fprintf(file, "maxdqueue %d\n", arg->mdqueue);
1283   fprintf(file, "bforce %d\n", arg->bforce);
1284   fprintf(file, "hideuname %d\n", arg->hideuname);
1285   fprintf(file, "auditmode %d\n", arg->auditmode);
1286 
1287   if (arg->sfname != 0) {
1288     fprintf(file, "session_file %s\n", arg->sfname);
1289     fprintf(file, "session_save %d\n", arg->ssave);
1290   }
1291 
1292   fclose(file);
1293 }
1294 //---------------------------------------------------------------------------
close(void)1295 void OphcrackGUI::close(void) {
1296   saveConfig();
1297   QMainWindow::close();
1298 }
1299 //---------------------------------------------------------------------------
closeEvent(QCloseEvent * event)1300 void OphcrackGUI::closeEvent(QCloseEvent *event) {
1301   saveConfig();
1302   QMainWindow::closeEvent(event);
1303 }
1304 //---------------------------------------------------------------------------
addDelHash(const QModelIndex &,int,int)1305 void OphcrackGUI::addDelHash(const QModelIndex &, int, int) {
1306   // Disable/enable the save and delete button.
1307 
1308   saveButton->setEnabled(crack->hashes->size ? true : false);
1309   deleteButton->setEnabled(crack->hashes->size > 0 ? true : false);
1310 }
1311 //---------------------------------------------------------------------------
displayAbout(void)1312 void OphcrackGUI::displayAbout(void) {
1313   AboutDialog about;
1314   about.exec();
1315 }
1316 //---------------------------------------------------------------------------
displayHelp(void)1317 void OphcrackGUI::displayHelp(void) {
1318   if (helpDialog == 0)
1319     helpDialog = new HelpDialog(this);
1320 
1321   helpDialog->show();
1322 }
1323 //---------------------------------------------------------------------------
installTables(QString str,bool replace,bool warn)1324 void OphcrackGUI::installTables(QString str, bool replace, bool warn) {
1325   const char *tblstr = str.toLatin1().constData();
1326 
1327   // Search for the tables in the various directories specified.
1328 
1329   list_t *table_path = crack->arg->table_path;
1330   list_t *tables = list_alloc();
1331   list_nd_t *dnd;
1332 
1333   for (dnd = table_path->head; dnd != 0; dnd = dnd->next) {
1334     char *dir = (char*)dnd->data;
1335     int ret = table_open(tables, dir, tblstr);
1336 
1337     if (ret >= 0) break;
1338   }
1339 
1340   // If the requested tables were not found, then we notify the user.
1341 
1342   if (warn && dnd == 0) {
1343     QMessageBox msgBox(QMessageBox::Warning,
1344 		       "Warning",
1345 		       QString("You requested the table(s) %1, ").arg(str) +
1346 		       QString("but some or all tables could not ") +
1347 		       QString("be found or loaded."),
1348 		       QMessageBox::Ok);
1349     msgBox.exec();
1350   }
1351 
1352   // If some tables have been loaded, then we install them.
1353 
1354   else if (dnd != 0) {
1355     assert(tables->size > 0);
1356 
1357     table_t *tbl = (table_t*)tables->head->data;
1358     table_kind_t kind = tbl->kind;
1359 
1360     // Check the size of the tables.
1361 
1362     int size_invalid = 0;
1363     list_nd_t *nd;
1364 
1365     for (nd = tables->head; nd != 0; nd = nd->next) {
1366       table_t *tbl = (table_t*)nd->data;
1367       ophcrack_setup_table(tbl);
1368       if (table_verify(tbl) < 0) {
1369 	size_invalid = 1;
1370 	QMessageBox msgBox(QMessageBox::Warning,
1371 			   "Warning",
1372 			   QString("Size of table %1 is invalid.").arg(str) +
1373 			   QString("Please download it again."),
1374 			   QMessageBox::Ok);
1375 	msgBox.exec();
1376       }
1377     }
1378 
1379     // Check if we must replace existing tables by the newly loaded
1380     // ones.
1381 
1382     bool installed = tableModel->isInstalled(kind);
1383 
1384     if (replace && installed) {
1385       int ntables = crack->tables->size;
1386       int i;
1387 
1388       for (i=0; i<ntables; ++i) {
1389 	table_t *tbl = (table_t*)list_rem_head(crack->tables);
1390 
1391 	if (tbl->kind != kind)
1392 	  list_add_tail(crack->tables, tbl);
1393       }
1394 
1395       tableModel->uninstall(kind);
1396 
1397       // Install the newly loaded tables.
1398       if (!size_invalid) {
1399 	for (nd = tables->head; nd != 0; nd = nd->next) {
1400 	  table_t *tbl = (table_t*)nd->data;
1401 	  ophcrack_add_table(crack, tbl);
1402 	}
1403 
1404 	tableModel->install(tables);
1405       }
1406     }
1407 
1408     // If the tables are not installed yet, then we install them. If
1409     // 'replace' is false then we disable all tables.
1410 
1411     else if (!installed && !size_invalid) {
1412       for (nd = tables->head; nd != 0; nd = nd->next) {
1413 	table_t *tbl = (table_t*)nd->data;
1414 
1415 	if (!replace) tbl->enabled = 0;
1416 	ophcrack_add_table(crack, tbl);
1417       }
1418 
1419       tableModel->install(tables);
1420     }
1421   }
1422 }
1423 //---------------------------------------------------------------------------
sessOnOff(int state)1424 void OphcrackGUI::sessOnOff(int state) {
1425   if (state == Qt::Unchecked) {
1426     arg->ssave = 0;
1427     sessEdit->setEnabled(false);
1428   }
1429 
1430   else if (state == Qt::Checked) {
1431     arg->ssave = 1;
1432     fsm->ssave = 1;
1433 
1434     sessBox->setEnabled(true);
1435     sessEdit->setEnabled(true);
1436   }
1437 }
1438 //---------------------------------------------------------------------------
chooseSessFile(void)1439 void OphcrackGUI::chooseSessFile(void) {
1440   QString fileName;
1441 
1442   // If a session file has already been specified, then we preselect it.
1443 
1444   if (arg->sfname != 0)
1445     fileName = QFileDialog::getSaveFileName(this,
1446 					    tr("Choose Session File"),
1447 					    arg->sfname);
1448 
1449   // Otherwise, we preselect the current directory.
1450 
1451   else
1452     fileName = QFileDialog::getSaveFileName(this,
1453 					    tr("Choose Session File"),
1454 					    QDir::currentPath());
1455 
1456   // If the user chose a file, then we use it to store all the hashes
1457   // which are currently loaded.
1458 
1459   if (!fileName.isNull()) {
1460     const char *fname = fileName.toLatin1().constData();
1461 
1462     if (arg->sfname != 0) free(arg->sfname);
1463     arg->sfname = strdup(fname);
1464 
1465     sessEdit->setText(fileName);
1466 
1467     // Uncheck and recheck the checkbox in order to trigger a
1468     // stateChanged signal.
1469 
1470     sessBox->setCheckState(Qt::Unchecked);
1471     sessBox->setCheckState(Qt::Checked);
1472   }
1473 }
1474 //---------------------------------------------------------------------------
showNotFound(bool flag)1475 void OphcrackGUI::showNotFound(bool flag) {
1476   list_t *hashes = crack->hashes;
1477   list_nd_t *nd;
1478 
1479   for (nd = hashes->head; nd != 0; nd = nd->next) {
1480     hash_t *hsh = (hash_t*)nd->data;
1481 
1482     if (hsh->done <= 0 && hsh->id >= 0)
1483       hashModel->updateHash(hsh, flag);
1484   }
1485 }
1486