PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/aircrack-ng-1.1/src/airolib-ng.c

#
C | 1030 lines | 795 code | 134 blank | 101 comment | 246 complexity | be5ef387ace3af673e18260d64e1db14 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * A tool to compute and manage PBKDF2 values as used in WPA-PSK and WPA2-PSK
  3. *
  4. * Copyright (C) 2007; 2008, 2009 ebfe
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. * If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. * If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. * If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <unistd.h>
  37. #include <stdint.h>
  38. #include <string.h>
  39. #include <sqlite3.h>
  40. #include <sys/time.h>
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #include <unistd.h>
  44. #include <getopt.h>
  45. #include "aircrack-ng.h"
  46. #include "crypto.h"
  47. #ifdef HAVE_REGEXP
  48. #include <regex.h>
  49. #endif
  50. #include "version.h"
  51. #define IMPORT_ESSID "essid"
  52. #define IMPORT_PASSWD "passwd"
  53. #define IMPORT_COWPATTY "cowpatty"
  54. extern char * getVersion(char * progname, int maj, int min, int submin, int svnrev, int beta, int rc);
  55. void print_help(const char * msg) {
  56. printf("\n"
  57. " %s - (C) 2007, 2008, 2009 ebfe\n"
  58. " http://www.aircrack-ng.org\n"
  59. "\n"
  60. " Usage: airolib-ng <database> <operation> [options]\n"
  61. "\n"
  62. " Operations:\n"
  63. "\n"
  64. " --stats : Output information about the database.\n"
  65. " --sql <sql> : Execute specified SQL statement.\n"
  66. " --clean [all] : Clean the database from old junk. 'all' will also \n"
  67. " reduce filesize if possible and run an integrity check.\n"
  68. " --batch : Start batch-processing all combinations of ESSIDs\n"
  69. " and passwords.\n"
  70. " --verify [all] : Verify a set of randomly chosen PMKs.\n"
  71. " If 'all' is given, all invalid PMK will be deleted.\n"
  72. "\n"
  73. " --import [essid|passwd] <file> :\n"
  74. " Import a text file as a list of ESSIDs or passwords.\n"
  75. " --import cowpatty <file> :\n"
  76. " Import a cowpatty file.\n"
  77. "\n"
  78. " --export cowpatty <essid> <file> :\n"
  79. " Export to a cowpatty file.\n"
  80. "\n",
  81. getVersion("Airolib-ng", _MAJ, _MIN, _SUB_MIN, _REVISION, _BETA, _RC));
  82. if (msg && strlen(msg) > 0) {
  83. printf("%s", msg);
  84. puts("");
  85. }
  86. }
  87. void sql_error(sqlite3* db) {
  88. fprintf(stderr, "Database error: %s\n", sqlite3_errmsg(db));
  89. }
  90. int sql_exec_cb(sqlite3* db, const char *sql, void* callback, void* cb_arg) {
  91. #ifdef SQL_DEBUG
  92. printf(sql);
  93. printf("\n");
  94. fflush(stdout);
  95. #endif
  96. int rc;
  97. char *zErrMsg = 0;
  98. char looper[4] = {'|','/','-','\\'};
  99. int looperc = 0;
  100. int waited = 0;
  101. while (1) {
  102. rc = sqlite3_exec(db,sql,callback,cb_arg,&zErrMsg);
  103. if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) {
  104. fprintf(stdout,"Database is locked or busy. Waiting %is ... %1c \r",++waited, looper[looperc++ % sizeof(looper)]);
  105. fflush(stdout);
  106. sleep(1);
  107. } else {
  108. if (rc != SQLITE_OK) {
  109. fprintf(stderr, "SQL error. %s\n", zErrMsg);
  110. sqlite3_free(zErrMsg);
  111. }
  112. if (waited != 0) printf("\n\n");
  113. return rc;
  114. }
  115. }
  116. }
  117. // execute sql fast and hard.
  118. int sql_exec(sqlite3* db, const char *sql) {
  119. return sql_exec_cb(db,sql,0,0);
  120. }
  121. // wrapper for sqlite3_step which retries executing statements if the db returns SQLITE_BUSY or SQLITE_LOCKED
  122. int sql_step(sqlite3_stmt* stmt, int wait) {
  123. int rc;
  124. char looper[4] = {'|','/','-','\\'};
  125. int looperc = 0;
  126. int waited = 0;
  127. while (1) {
  128. rc = sqlite3_step(stmt);
  129. if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) {
  130. if (wait != 0) {
  131. fprintf(stdout,"Database is locked or busy. Waiting %is ... %1c \r",++waited, looper[looperc]);
  132. fflush(stdout);
  133. wait--;
  134. looperc = looperc+1 % sizeof(looper);
  135. sleep(1);
  136. } else {
  137. fprintf(stderr,"Database was locked or busy while getting results. I've given up.\n");
  138. return rc;
  139. }
  140. } else {
  141. if (waited != 0) printf("\n\n");
  142. return rc;
  143. }
  144. }
  145. }
  146. // wrapper for sqlite3_prepare_v2 which retries creating statements if the db returns SQLITE_BUSY or SQLITE_LOCKED
  147. int sql_prepare(sqlite3 *db, const char *sql, sqlite3_stmt **ppStmt, int wait) {
  148. #ifdef SQL_DEBUG
  149. printf(sql);
  150. printf("\n");
  151. fflush(stdout);
  152. #endif
  153. int rc;
  154. char looper[4] = {'|','/','-','\\'};
  155. int looperc = 0;
  156. int waited = 0;
  157. while (1) {
  158. rc = sqlite3_prepare_v2(db,sql,-1,ppStmt,NULL);
  159. if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) {
  160. if (wait != 0) {
  161. fprintf(stdout,"Database is locked or busy. Waiting %is ... %1c \r", ++waited, looper[looperc]);
  162. fflush(stdout);
  163. wait--;
  164. looperc = looperc+1 % sizeof(looper);
  165. sleep(1);
  166. } else {
  167. fprintf(stderr,"Database was locked or busy while creating statement. I've given up.\n");
  168. return rc;
  169. }
  170. } else {
  171. if (waited != 0) printf("\n\n");
  172. return rc;
  173. }
  174. }
  175. }
  176. // generic function to dump a resultset including column names to stdout
  177. int stmt_stdout(sqlite3_stmt* stmt, int* rowcount) {
  178. int ccount;
  179. int rcount = 0;
  180. int rc;
  181. if (stmt == 0 || (ccount = sqlite3_column_count(stmt)) == 0) {
  182. return sql_step(stmt,0);
  183. }
  184. int i = 0;
  185. do {
  186. printf("%s", sqlite3_column_name(stmt,i++));
  187. if (i < ccount) printf("\t");
  188. } while (i < ccount);
  189. printf("\n");
  190. while ((rc = sql_step(stmt,0)) == SQLITE_ROW) {
  191. i = 0;
  192. rcount++;
  193. do {
  194. printf("%s", (char *)sqlite3_column_text(stmt,i++));
  195. if (i < ccount) printf("\t");
  196. } while (i < ccount);
  197. printf("\n");
  198. }
  199. if (rowcount != NULL) *rowcount=rcount;
  200. return rc;
  201. }
  202. // generic function to dump the output of a sql statement to stdout.
  203. // will return sqlite error codes but also handle (read: ignore) them itself
  204. int sql_stdout(sqlite3* db, const char* sql, int* rowcount) {
  205. int rc;
  206. sqlite3_stmt *stmt;
  207. rc = sql_prepare(db,sql,&stmt,-1);
  208. if (rc != SQLITE_OK) {
  209. sql_error(db);
  210. return rc;
  211. }
  212. rc = stmt_stdout(stmt,rowcount);
  213. sqlite3_finalize(stmt);
  214. if (rc == SQLITE_DONE) {
  215. if (sqlite3_changes(db) > 0) fprintf(stdout,"Query done. %i rows affected.",sqlite3_changes(db));
  216. } else {
  217. sql_error(db);
  218. }
  219. printf("\n");
  220. return rc;
  221. }
  222. // retrieve a single int value using a sql query.
  223. // returns 0 if something goes wrong. beware! create your own statement if you need error handling.
  224. int query_int(sqlite3* db, const char* sql) {
  225. sqlite3_stmt *stmt;
  226. int rc;
  227. int ret;
  228. rc = sql_prepare(db,sql,&stmt,-1);
  229. if (rc != SQLITE_OK || stmt == 0 || sqlite3_column_count(stmt) == 0) {
  230. sql_error(db);
  231. ret = 0;
  232. } else {
  233. rc = sql_step(stmt,-1);
  234. if (rc == SQLITE_ROW) {
  235. ret = sqlite3_column_int(stmt,0);
  236. } else {
  237. #ifdef SQL_DEBUG
  238. printf("DEBUG: query_int() returns with sql_step() != SQLITE_ROW\n");
  239. #endif
  240. ret = 0;
  241. }
  242. }
  243. sqlite3_finalize(stmt);
  244. return ret;
  245. }
  246. // throw some statistics about the db to stdout.
  247. // if precise!=0 the stats will be queried nail by nail which can be slow
  248. void show_stats(sqlite3* db, int precise) {
  249. sql_exec(db,"BEGIN;");
  250. int essids = query_int(db, "SELECT COUNT(*) FROM essid;");
  251. int passwds = query_int(db,"SELECT COUNT(*) FROM passwd;");
  252. int done;
  253. if (precise != 0) {
  254. printf("Determining precise statistics may be slow...\n");
  255. done = query_int(db, "SELECT COUNT(*) FROM essid,passwd INNER JOIN pmk ON pmk.essid_id = essid.essid_id AND pmk.passwd_id = passwd.passwd_id");
  256. } else {
  257. done = query_int(db, "SELECT COUNT(*) FROM pmk;");
  258. }
  259. fprintf(stdout,"There are %i ESSIDs and %i passwords in the database. %i out of %i possible combinations have been computed (%g%%).\n\n", essids, passwds, done, essids*passwds, essids*passwds > 0 ? ((double)done*100)/(essids*passwds) : 0);
  260. if (precise != 0) {
  261. sql_stdout(db, "select essid.essid AS ESSID, essid.prio AS Priority, round(count(pmk.essid_id) * 100.0 / count(*),2) AS Done from essid,passwd left join pmk on pmk.essid_id = essid.essid_id and pmk.passwd_id = passwd.passwd_id group by essid.essid_id;",0);
  262. } else {
  263. sql_stdout(db, "SELECT essid.essid AS ESSID, essid.prio AS Priority, ROUND(COUNT(pmk.essid_id) * 100.0 / (SELECT COUNT(*) FROM passwd),2) AS Done FROM essid LEFT JOIN pmk ON pmk.essid_id = essid.essid_id GROUP BY essid.essid_id;",0);
  264. }
  265. sql_exec(db,"COMMIT;");
  266. }
  267. /*
  268. batch-process all combinations of ESSIDs and PASSWDs. this function may be called
  269. only once per db at the same time, yet multiple processes can batch-process a single db.
  270. don't modify this function's layout or it's queries without carefully considering speed, efficiency and concurrency.
  271. */
  272. void batch_process(sqlite3* db) {
  273. int rc;
  274. int cur_essid = 0;
  275. struct timeval starttime;
  276. struct timeval curtime;
  277. gettimeofday(&starttime,NULL);
  278. int rowcount = 0;
  279. char *sql;
  280. if (sql_exec(db, "CREATE TEMPORARY TABLE temp.buffer (wb_id integer, essid_id integer, passwd_id integer, essid text, passwd text, pmk blob);") != SQLITE_OK) {
  281. fprintf(stderr,"Failed to create buffer for batch processing.\n");
  282. return;
  283. }
  284. // may fail - thats ok
  285. cur_essid = query_int(db,"SELECT essid_id FROM workbench LIMIT 1;");
  286. while(1) {
  287. //loop over everything
  288. do {
  289. //loop over ESSID
  290. do {
  291. //loop over workbench
  292. sql_exec(db,"DELETE FROM temp.buffer;");
  293. // select some work from the workbench into our own buffer
  294. // move lockid ahead so other clients won't get those rows any time soon
  295. sql_exec(db,"BEGIN EXCLUSIVE;");
  296. sql_exec(db,"INSERT INTO temp.buffer (wb_id,essid_id,passwd_id,essid,passwd) SELECT wb_id, essid.essid_id,passwd.passwd_id,essid,passwd FROM workbench CROSS JOIN essid ON essid.essid_id = workbench.essid_id CROSS JOIN passwd ON passwd.passwd_id = workbench.passwd_id ORDER BY lockid LIMIT 25000;");
  297. sql_exec(db,"UPDATE workbench SET lockid=lockid+1 WHERE wb_id IN (SELECT wb_id FROM buffer);");
  298. sql_exec(db,"COMMIT;");
  299. rc = query_int(db,"SELECT COUNT(*) FROM buffer;");
  300. if (rc > 0) {
  301. // now calculate all the PMKs with a single statement.
  302. // remember the update won't lock the db
  303. sql_exec(db,"UPDATE temp.buffer SET pmk = PMK(essid,passwd);");
  304. // commit work and delete package from workbench
  305. sql_exec(db,"BEGIN EXCLUSIVE;");
  306. sql_exec(db,"INSERT OR IGNORE INTO pmk (essid_id,passwd_id,pmk) SELECT essid_id,passwd_id,pmk FROM temp.buffer");
  307. sql_exec(db,"DELETE FROM workbench WHERE wb_id IN (SELECT wb_id FROM buffer);");
  308. sql_exec(db,"COMMIT;");
  309. rowcount += rc;
  310. gettimeofday(&curtime,NULL);
  311. int timediff = curtime.tv_sec - starttime.tv_sec;
  312. fprintf(stdout,"\rComputed %i PMK in %i seconds (%i PMK/s, %i in buffer). ",rowcount,timediff, timediff > 0 ? rowcount / timediff : rowcount, query_int(db,"SELECT COUNT(*) FROM workbench;"));
  313. fflush(stdout);
  314. }
  315. } while (rc > 0);
  316. sql = sqlite3_mprintf("INSERT OR IGNORE INTO workbench (essid_id,passwd_id) SELECT essid.essid_id,passwd.passwd_id FROM passwd CROSS JOIN essid LEFT JOIN pmk ON pmk.essid_id = essid.essid_id AND pmk.passwd_id = passwd.passwd_id WHERE essid.essid_id = %i AND pmk.essid_id IS NULL LIMIT 250000;",cur_essid);
  317. sql_exec(db,sql);
  318. sqlite3_free(sql);
  319. } while (query_int(db,"SELECT COUNT(*) FROM workbench INNER JOIN essid ON essid.essid_id = workbench.essid_id INNER JOIN passwd ON passwd.passwd_id = workbench.passwd_id;") > 0);
  320. cur_essid = query_int(db,"SELECT essid.essid_id FROM essid LEFT JOIN pmk USING (essid_id) WHERE VERIFY_ESSID(essid.essid) == 0 GROUP BY essid.essid_id HAVING COUNT(pmk.essid_id) < (SELECT COUNT(*) FROM passwd) ORDER BY essid.prio,COUNT(pmk.essid_id),RANDOM() LIMIT 1;");
  321. if (cur_essid == 0) {
  322. printf("All ESSID processed.\n\n");
  323. sqlite3_close(db);
  324. exit(0);
  325. /*
  326. printf("No free ESSID found. Will try determining new ESSID in 5 minutes...\n");
  327. sleep(60*5);
  328. // slower, yet certain. should never be any better than the above, unless users fumble with the db.
  329. cur_essid = query_int(db,"SELECT essid.essid_id FROM essid,passwd LEFT JOIN pmk ON pmk.essid_id = essid.essid_id AND pmk.passwd_id = passwd.passwd_id WHERE pmk.essid_id IS NULL LIMIT 1;");
  330. if (cur_essid == 0) {
  331. printf("No free ESSID found. Sleeping 25 additional minutes...\n");
  332. sleep(60*25);
  333. }
  334. */
  335. }
  336. }
  337. //never reached
  338. sql_exec(db,"DROP TABLE temp.buffer;");
  339. }
  340. // Verify an ESSID. Returns 1 if ESSID is invalid.
  341. //TODO More things to verify? Invalid chars?
  342. int verify_essid(char* essid) {
  343. return essid == NULL || strlen(essid) < 1 || strlen(essid) > 32;
  344. }
  345. // sql function which checks a given ESSID
  346. void sql_verify_essid(sqlite3_context* context, int argc, sqlite3_value** values) {
  347. char* essid = (char*)sqlite3_value_text(values[0]);
  348. if (argc != 1 || essid == 0) {
  349. fprintf(stderr,"SQL function VERIFY_ESSID called with invalid arguments");
  350. return;
  351. }
  352. sqlite3_result_int(context,verify_essid(essid));
  353. }
  354. int verify_passwd(char* passwd) {
  355. return passwd == NULL || strlen(passwd) < 8 || strlen(passwd) > 63;
  356. }
  357. void sql_verify_passwd(sqlite3_context* context, int argc, sqlite3_value** values) {
  358. char* passwd = (char*)sqlite3_value_text(values[0]);
  359. if (argc != 1 || passwd == 0) {
  360. fprintf(stderr,"SQL function VERIFY_PASSWD called with invalid arguments");
  361. return;
  362. }
  363. sqlite3_result_int(context,verify_passwd(passwd));
  364. }
  365. // clean the db, analyze, maybe vacuum and check
  366. void vacuum(sqlite3* db, int deep) {
  367. printf("Deleting invalid ESSIDs and passwords...\n");
  368. sql_exec(db, "DELETE FROM essid WHERE VERIFY_ESSID(essid) != 0;");
  369. sql_exec(db, "DELETE FROM passwd WHERE VERIFY_PASSWD(passwd) != 0");
  370. printf("Deleting unreferenced PMKs...\n");
  371. sql_exec(db, "DELETE FROM pmk WHERE essid_id NOT IN (SELECT essid_id FROM essid)");
  372. sql_exec(db, "DELETE FROM pmk WHERE passwd_id NOT IN (SELECT passwd_id FROM passwd)");
  373. printf("Analysing index structure...\n");
  374. sql_exec(db, "ANALYZE;");
  375. if (deep != 0) {
  376. printf("Vacuum-cleaning the database. This could take a while...\n");
  377. sql_exec(db, "VACUUM;");
  378. printf("Checking database integrity...\n");
  379. sql_stdout(db, "PRAGMA integrity_check;",0);
  380. }
  381. printf("Done.\n");
  382. }
  383. // verify PMKs. If complete==1 we check all PMKs
  384. // returns 0 if ok, !=0 otherwise
  385. void verify(sqlite3* db, int complete) {
  386. if (complete != 1) {
  387. printf("Checking ~10.000 randomly chosen PMKs...\n");
  388. // this is faster than 'order by random()'. we need the subquery to trick the optimizer...
  389. sql_stdout(db,"select s.essid AS ESSID, COUNT(*) AS CHECKED, CASE WHEN MIN(s.pmk == PMK(essid,passwd)) == 0 THEN 'FAILED' ELSE 'OK' END AS STATUS FROM (select distinct essid,passwd,pmk FROM pmk INNER JOIN passwd ON passwd.passwd_id = pmk.passwd_id INNER JOIN essid ON essid.essid_id = pmk.essid_id WHERE abs(random() % (select count(*) from pmk)) < 10000) AS s GROUP BY s.essid;",0);
  390. } else {
  391. printf("Checking all PMKs. This could take a while...\n");
  392. sql_stdout(db,"select essid AS ESSID,passwd AS PASSWORD,HEX(pmk) AS PMK_DB, HEX(PMK(essid,passwd)) AS CORRECT FROM pmk INNER JOIN passwd ON passwd.passwd_id = pmk.passwd_id INNER JOIN essid ON essid.essid_id = pmk.essid_id WHERE pmk.pmk != PMK(essid,passwd);",0);
  393. }
  394. }
  395. // callback for export_cowpatty. takes the passwd and pmk from the query and writes another fileentry.
  396. int sql_exportcow(void* arg, int ccount, char** values, char** columnnames) {
  397. FILE *f = (FILE*)arg;
  398. struct hashdb_rec rec;
  399. if (ccount != 2 || values[0] == NULL || values[1] == NULL || fileno(f) == -1) {
  400. printf("Illegal call to sql_exportcow.\n");
  401. return -1;
  402. }
  403. if (columnnames) {} //XXX
  404. char* passwd = (char*)values[0];
  405. memcpy(rec.pmk,values[1],sizeof(rec.pmk));
  406. rec.rec_size = strlen(passwd) + sizeof(rec.pmk)+ sizeof(rec.rec_size);
  407. int rc = fwrite(&rec.rec_size,sizeof(rec.rec_size),1,f);
  408. rc += fwrite(passwd, strlen(passwd),1,f);
  409. rc += fwrite(rec.pmk, sizeof(rec.pmk), 1, f);
  410. if (rc != 3) {
  411. printf("Error while writing to export file. Query aborted...\n");
  412. return 1;
  413. }
  414. fflush(f);
  415. return 0;
  416. }
  417. // export to a cowpatty file
  418. void export_cowpatty(sqlite3* db, char* essid, char* filename) {
  419. struct hashdb_head filehead;
  420. memset(&filehead, 0, sizeof(filehead));
  421. FILE *f = NULL;
  422. if (access(filename, F_OK)==0) {
  423. printf("The file already exists and I won't overwrite it.\n");
  424. return;
  425. }
  426. // ensure that the essid is found in the db and has at least one entry in the pmk table.
  427. char *sql = sqlite3_mprintf("SELECT COUNT(*) FROM (SELECT passwd, pmk FROM essid,passwd INNER JOIN pmk ON pmk.passwd_id = passwd.passwd_id AND pmk.essid_id = essid.essid_id WHERE essid.essid = '%q' LIMIT 1);",essid);
  428. int rc = query_int(db,sql);
  429. sqlite3_free(sql);
  430. if (rc == 0) {
  431. printf("There is no such ESSID in the database or there are no PMKs for it.\n");
  432. return;
  433. }
  434. memcpy(filehead.ssid, essid,strlen(essid));
  435. filehead.ssidlen = strlen(essid);
  436. filehead.magic = GENPMKMAGIC;
  437. f = fopen(filename, "w");
  438. if (f == NULL || fwrite(&filehead, sizeof(filehead), 1, f) != 1) {
  439. printf("Couldn't open the export file for writing.\n");
  440. return;
  441. }
  442. // as we have an open filehandle, we now query the db to return passwds and associated PMKs for that essid. we pass the filehandle to a callback function which will write the rows to the file.
  443. sql = sqlite3_mprintf("SELECT passwd, pmk FROM essid,passwd INNER JOIN pmk ON pmk.passwd_id = passwd.passwd_id AND pmk.essid_id = essid.essid_id WHERE essid.essid = '%q'",essid);
  444. printf("Exporting...\n");
  445. rc = sql_exec_cb(db,sql,&sql_exportcow,f);
  446. sqlite3_free(sql);
  447. if (rc != SQLITE_OK) {
  448. printf("There was an error while exporting.\n");
  449. }
  450. fclose(f);
  451. printf("Done.\n");
  452. }
  453. // import a cowpatty file
  454. int import_cowpatty(sqlite3* db, char* filename) {
  455. struct hashdb_head filehead;
  456. struct hashdb_rec rec;
  457. FILE *f = NULL;
  458. int rc;
  459. sqlite3_stmt *stmt;
  460. char* sql;
  461. int essid_id;
  462. int wordlength;
  463. char passwd[63+1];
  464. if (strcmp(filename,"-") == 0) {
  465. f = stdin;
  466. } else {
  467. f = fopen(filename, "r");
  468. }
  469. if (f == NULL || fread(&filehead, sizeof(filehead),1,f) != 1) {
  470. printf("Couldn't open the import file for reading.\n");
  471. return 0;
  472. } else if (filehead.magic != GENPMKMAGIC) {
  473. printf("File doesn't seem to be a cowpatty file.\n");
  474. fclose(f);
  475. return 0;
  476. } else if (verify_essid((char *)filehead.ssid) != 0) {
  477. printf("The file's ESSID is invalid.\n");
  478. fclose(f);
  479. return 0;
  480. }
  481. printf("Reading header...\n");
  482. //We need protection so concurrent transactions can't smash the ID-references
  483. sql_exec(db,"BEGIN;");
  484. sql = sqlite3_mprintf("INSERT OR IGNORE INTO essid (essid) VALUES ('%q');",filehead.ssid);
  485. sql_exec(db,sql);
  486. sqlite3_free(sql);
  487. //since there is only one essid per file, we can determine it's ID now
  488. sql = sqlite3_mprintf("SELECT essid_id FROM essid WHERE essid = '%q'", filehead.ssid);
  489. essid_id = query_int(db,sql);
  490. sqlite3_free(sql);
  491. if (essid_id == 0) {
  492. fclose(f);
  493. sql_exec(db,"ROLLBACK;");
  494. printf("ESSID couldn't be inserted. I've given up.\n");
  495. return 0;
  496. }
  497. sql = sqlite3_mprintf("CREATE TEMPORARY TABLE import (passwd text, pmk blob);", essid_id);
  498. sql_exec(db,sql);
  499. sqlite3_free(sql);
  500. sql_prepare(db,"INSERT INTO import (passwd,pmk) VALUES (@pw,@pmk)",&stmt,-1);
  501. printf("Reading...\n");
  502. while ((rc = fread(&rec.rec_size, sizeof(rec.rec_size), 1, f)) == 1) {
  503. wordlength = abs(rec.rec_size) - (sizeof(rec.pmk) + sizeof(rec.rec_size));
  504. //prevent out of bounds writing (sigsegv guaranteed) but don't skip the whole file if wordlength < 8
  505. if (wordlength > 0 && wordlength < (int) sizeof(passwd)) {
  506. passwd[wordlength] = 0;
  507. rc += fread(passwd, wordlength, 1, f);
  508. if (rc == 2) rc += fread(&rec.pmk, sizeof(rec.pmk), 1, f);
  509. }
  510. if (rc != 3) {
  511. fprintf(stdout,"Error while reading record (%i).\n",rc);
  512. sqlite3_finalize(stmt);
  513. if (db == NULL) {
  514. printf("omg");
  515. fflush(stdout);
  516. }
  517. sql_exec(db, "ROLLBACK;");
  518. fclose(f);
  519. return 1;
  520. }
  521. if (verify_passwd(passwd) == 0) {
  522. sqlite3_bind_text(stmt,1,passwd, strlen(passwd),SQLITE_TRANSIENT);
  523. sqlite3_bind_blob(stmt,2,&rec.pmk, sizeof(rec.pmk),SQLITE_TRANSIENT);
  524. if (sql_step(stmt,-1) == SQLITE_DONE) {
  525. sqlite3_reset(stmt);
  526. } else {
  527. printf("Error while inserting record into database.\n");
  528. sqlite3_finalize(stmt);
  529. sql_exec(db, "ROLLBACK;");
  530. fclose(f);
  531. return 1;
  532. }
  533. } else {
  534. fprintf(stdout,"Invalid password %s will not be imported.\n",passwd);
  535. }
  536. }
  537. sqlite3_finalize(stmt);
  538. if (!feof(f)) {
  539. printf("Error while reading file.\n");
  540. sql_exec(db,"ROLLBACK;");
  541. fclose(f);
  542. return 1;
  543. }
  544. printf("Updating references...\n");
  545. sql_exec(db, "INSERT OR IGNORE INTO passwd (passwd) SELECT passwd FROM import;");
  546. //TODO Give the user a choice to either INSERT OR UPDATE or INSERT OR IGNORE
  547. printf("Writing...\n");
  548. sql = sqlite3_mprintf("INSERT OR IGNORE INTO pmk (essid_id,passwd_id,pmk) SELECT %i,passwd.passwd_id,import.pmk FROM import INNER JOIN passwd ON passwd.passwd = import.passwd;",essid_id);
  549. sql_exec(db,sql);
  550. sqlite3_free(sql);
  551. sql_exec(db,"COMMIT;");
  552. fclose(f);
  553. return 1;
  554. }
  555. int import_ascii(sqlite3* db, const char* mode, const char* filename) {
  556. FILE *f = NULL;
  557. sqlite3_stmt *stmt;
  558. char buffer[63+1];
  559. int imported=0;
  560. int ignored=0;
  561. int imode=0;
  562. if (strcasecmp(mode,IMPORT_ESSID) == 0) {
  563. imode = 0;
  564. } else if (strcasecmp(mode,IMPORT_PASSWD) == 0) {
  565. imode = 1;
  566. } else {
  567. printf("Specify either 'essid' or 'passwd' as import mode.\n");
  568. return 0;
  569. }
  570. if (strcmp(filename,"-") == 0) {
  571. f = stdin;
  572. } else {
  573. f = fopen(filename, "r");
  574. }
  575. if (f == NULL) {
  576. printf("Could not open file/stream for reading.\n");
  577. return 0;
  578. }
  579. char* sql = sqlite3_mprintf("INSERT OR IGNORE INTO %q (%q) VALUES (@v);",mode,mode);
  580. sql_prepare(db,sql,&stmt,-1);
  581. sqlite3_free(sql);
  582. sql_exec(db, "BEGIN;");
  583. printf("Reading file...\n");
  584. while (fgets(buffer, sizeof(buffer), f) != 0) {
  585. int i = strlen(buffer);
  586. if (buffer[i-1] == '\n') buffer[--i] = '\0';
  587. if (buffer[i-1] == '\r') buffer[--i] = '\0';
  588. imported++;
  589. if ((imode == 0 && verify_essid(buffer)==0) || (imode == 1 && verify_passwd(buffer)==0)) {
  590. sqlite3_bind_text(stmt,1,buffer, strlen(buffer),SQLITE_TRANSIENT);
  591. if (sql_step(stmt,-1) == SQLITE_DONE) {
  592. sqlite3_reset(stmt);
  593. } else {
  594. printf("Error while inserting record into database.\n");
  595. sql_exec(db, "ROLLBACK;");
  596. sqlite3_finalize(stmt);
  597. fclose(f);
  598. return 1;
  599. }
  600. } else {
  601. ignored++;
  602. }
  603. if (imported % 1000 == 0) {
  604. fprintf(stdout,"%i lines read, %i invalid lines ignored.\r",imported,ignored);
  605. fflush(stdout);
  606. }
  607. }
  608. sqlite3_finalize(stmt);
  609. if (!feof(f)) {
  610. printf("Error while reading file.\n");
  611. sql_exec(db,"ROLLBACK;");
  612. fclose(f);
  613. return 1;
  614. }
  615. fclose(f);
  616. printf("Writing...\n");
  617. sql_exec(db,"COMMIT;");
  618. printf("Done.\n");
  619. return 1;
  620. }
  621. // sql function. takes ESSID and PASSWD, gives PMK
  622. void sql_calcpmk(sqlite3_context* context, int argc, sqlite3_value** values) {
  623. unsigned char pmk[40];
  624. char* passwd = (char*)sqlite3_value_blob(values[1]);
  625. char* essid = (char*)sqlite3_value_blob(values[0]);
  626. if (argc < 2 || passwd == 0 || essid == 0) {
  627. sqlite3_result_error(context, "SQL function PMK() called with invalid arguments.\n", -1);
  628. return;
  629. }
  630. calc_pmk(passwd,essid,pmk);
  631. sqlite3_result_blob(context,pmk,32,SQLITE_TRANSIENT);
  632. }
  633. #ifdef HAVE_REGEXP
  634. void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
  635. int ret;
  636. regex_t regex;
  637. char* reg = (char*)sqlite3_value_text(values[0]);
  638. char* text = (char*)sqlite3_value_text(values[1]);
  639. if ( argc != 2 || reg == 0 || text == 0) {
  640. sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
  641. return;
  642. }
  643. ret = regcomp(&regex, reg, REG_EXTENDED | REG_NOSUB);
  644. if ( ret != 0 ) {
  645. sqlite3_result_error(context, "error compiling regular expression", -1);
  646. return;
  647. }
  648. ret = regexec(&regex, text , 0, NULL, 0);
  649. regfree(&regex);
  650. sqlite3_result_int(context, (ret != REG_NOMATCH));
  651. }
  652. #endif
  653. int initDataBase(const char * filename, sqlite3 ** db)
  654. {
  655. //int rc = sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
  656. int rc = sqlite3_open(filename, &(*db));
  657. if (rc != SQLITE_OK) {
  658. sql_error(*db);
  659. sqlite3_close(*db);
  660. // May be usefull later
  661. return rc;
  662. }
  663. sql_exec(*db, "create table essid (essid_id integer primary key autoincrement, essid text, prio integer default 64);");
  664. sql_exec(*db, "create table passwd (passwd_id integer primary key autoincrement, passwd text);");
  665. sql_exec(*db, "create table pmk (pmk_id integer primary key autoincrement, passwd_id int, essid_id int, pmk blob);");
  666. sql_exec(*db, "create table workbench (wb_id integer primary key autoincrement, essid_id integer, passwd_id integer, lockid integer default 0);");
  667. sql_exec(*db, "create index lock_lockid on workbench (lockid);");
  668. sql_exec(*db, "create index pmk_pw on pmk (passwd_id);");
  669. sql_exec(*db, "create unique index essid_u on essid (essid);");
  670. sql_exec(*db, "create unique index passwd_u on passwd (passwd);");
  671. sql_exec(*db, "create unique index ep_u on pmk (essid_id,passwd_id);");
  672. sql_exec(*db, "create unique index wb_u on workbench (essid_id,passwd_id);");
  673. sql_exec(*db, "CREATE TRIGGER delete_essid DELETE ON essid BEGIN DELETE FROM pmk WHERE pmk.essid_id = OLD.essid_id; DELETE FROM workbench WHERE workbench.essid_id = OLD.essid_id; END;");
  674. sql_exec(*db, "CREATE TRIGGER delete_passwd DELETE ON passwd BEGIN DELETE FROM pmk WHERE pmk.passwd_id = OLD.passwd_id; DELETE FROM workbench WHERE workbench.passwd_id = OLD.passwd_id; END;");
  675. #ifdef SQL_DEBUG
  676. sql_exec(*db, "begin;");
  677. sql_exec(*db, "insert into essid (essid,prio) values ('e',random())");
  678. sql_exec(*db, "insert into passwd (passwd) values ('p')");
  679. sql_exec(*db, "insert into essid (essid,prio) select essid||'a',random() from essid;");
  680. sql_exec(*db, "insert into essid (essid,prio) select essid||'b',random() from essid;");
  681. sql_exec(*db, "insert into essid (essid,prio) select essid||'c',random() from essid;");
  682. sql_exec(*db, "insert into essid (essid,prio) select essid||'d',random() from essid;");
  683. sql_exec(*db, "insert into passwd (passwd) select passwd||'a' from passwd;");
  684. sql_exec(*db, "insert into passwd (passwd) select passwd||'b' from passwd;");
  685. sql_exec(*db, "insert into passwd (passwd) select passwd||'c' from passwd;");
  686. sql_exec(*db, "insert into passwd (passwd) select passwd||'d' from passwd;");
  687. sql_exec(*db, "insert into passwd (passwd) select passwd||'e' from passwd;");
  688. sql_exec(*db, "insert into pmk (essid_id,passwd_id) select essid_id,passwd_id from essid,passwd limit 1000000;");
  689. sql_exec(*db,"commit;");
  690. #endif
  691. sqlite3_close(*db);
  692. printf("Database <%s> successfully created\n", filename);
  693. return 0;
  694. }
  695. int check_for_db(sqlite3 ** db, const char * filename, int can_create, int readonly)
  696. {
  697. struct stat dbfile;
  698. int rc;
  699. int accessflags = R_OK | W_OK;
  700. if (readonly)
  701. accessflags = R_OK;
  702. // Check if DB exist. If it does not, initialize it
  703. if (access(filename, accessflags)) {
  704. printf("Database <%s> does not already exist, ", filename);
  705. if (can_create)
  706. {
  707. printf("creating it...\n");
  708. rc = initDataBase(filename, db);
  709. if (rc)
  710. {
  711. printf("Error initializing database (return code: %d), exiting...\n", rc);
  712. return 1;
  713. }
  714. }
  715. else
  716. {
  717. printf("exiting ...\n");
  718. return 1;
  719. }
  720. }
  721. else
  722. {
  723. if (stat(filename, &dbfile))
  724. {
  725. perror("stat()");
  726. return 1;
  727. }
  728. if ((S_ISREG(dbfile.st_mode) && !S_ISDIR(dbfile.st_mode)) == 0)
  729. {
  730. printf("\"%s\" does not appear to be a file.\n", filename);
  731. return 1;
  732. }
  733. }
  734. rc = sqlite3_open(filename, &(*db));
  735. if(rc) {
  736. sql_error(*db);
  737. sqlite3_close(*db);
  738. return 1;
  739. }
  740. // TODO: Sanity check: Table definitions, index
  741. // register new functions to be used in SQL statements
  742. if (sqlite3_create_function(*db, "PMK", 2, SQLITE_ANY, 0, &sql_calcpmk,0,0) != SQLITE_OK) {
  743. printf("Failed creating PMK function.\n");
  744. sql_error(*db);
  745. sqlite3_close(*db);
  746. return 1;
  747. }
  748. if (sqlite3_create_function(*db, "VERIFY_ESSID", 1, SQLITE_ANY, 0, &sql_verify_essid,0,0) != SQLITE_OK) {
  749. printf("Failed creating VERIFY_ESSID function.\n");
  750. sql_error(*db);
  751. sqlite3_close(*db);
  752. return 1;
  753. }
  754. if (sqlite3_create_function(*db, "VERIFY_PASSWD", 1, SQLITE_ANY, 0, &sql_verify_passwd,0,0) != SQLITE_OK) {
  755. printf("Failed creating VERIFY_PASSWD function.\n");
  756. sql_error(*db);
  757. sqlite3_close(*db);
  758. return 1;
  759. }
  760. #ifdef HAVE_REGEXP
  761. if (sqlite3_create_function(*db, "regexp", 2, SQLITE_ANY,0, &sqlite_regexp,0,0) != SQLITE_OK) {
  762. printf("Failed creating regexp() handler.\n");
  763. sql_error(*db);
  764. sqlite3_close(*db);
  765. return 1;
  766. }
  767. #endif
  768. return 0;
  769. }
  770. int main(int argc, char **argv) {
  771. sqlite3 *db;
  772. int option_index, option;
  773. if( argc < 3 ){
  774. print_help(NULL);
  775. return 1;
  776. }
  777. db = NULL;
  778. option_index = 0;
  779. static struct option long_options[] = {
  780. {"batch", 0, 0, 'b'},
  781. {"clean", 2, 0, 'c'},
  782. {"export", 2, 0, 'e'},
  783. {"h", 0, 0, 'h'},
  784. {"help", 0, 0, 'h'},
  785. {"import", 2, 0, 'i'},
  786. {"sql", 1, 0, 's'},
  787. {"stats", 2, 0, 't'},
  788. {"statistics", 2, 0, 't'},
  789. {"verify", 2, 0, 'v'},
  790. {"vacuum", 2, 0, 'c'},
  791. // TODO: implement options like '-e essid' to limit
  792. // operations to a certain essid where possible
  793. {"essid", 1, 0, 'd'},
  794. {0, 0, 0, 0 }
  795. };
  796. option = getopt_long( argc, argv, "bc:d:e:hi:s:t:v:", long_options, &option_index );
  797. if( option > 0 )
  798. {
  799. switch (option)
  800. {
  801. case 'b':
  802. // Batch
  803. if ( check_for_db(&db, argv[1], 0, 1) ) {
  804. return 1;
  805. }
  806. batch_process(db);
  807. break;
  808. case 'c':
  809. // Clean
  810. if ( check_for_db(&db, argv[1], 0, 0) ) {
  811. return 1;
  812. }
  813. vacuum(db, (argc > 3 && strcasecmp(argv[3],"all") == 0) ? 1 : 0);
  814. break;
  815. case 'e':
  816. if (argc < 4) {
  817. print_help("You must specify an export format.");
  818. } else if (strcmp(argv[3],"cowpatty")==0) {
  819. if (argc < 6) {
  820. print_help("You must specify essid and output file.");
  821. } else {
  822. // Export
  823. if ( check_for_db(&db, argv[1], 0, 0) ) {
  824. return 1;
  825. }
  826. export_cowpatty(db,argv[4],argv[5]);
  827. }
  828. } else {
  829. print_help("Invalid export format specified.");
  830. }
  831. break;
  832. case ':' :
  833. case '?' :
  834. case 'h':
  835. // Show help
  836. print_help(NULL);
  837. break;
  838. case 'i':
  839. // Import
  840. if (argc < 5) {
  841. print_help("You must specifiy an import format and a file.");
  842. } else if (strcasecmp(argv[3], IMPORT_COWPATTY) == 0) {
  843. if ( check_for_db(&db, argv[1], 1, 0) ) {
  844. return 1;
  845. }
  846. import_cowpatty(db,argv[4]);
  847. } else if (strcasecmp(argv[3], IMPORT_ESSID) == 0) {
  848. if ( check_for_db(&db, argv[1], 1, 0) ) {
  849. return 1;
  850. }
  851. import_ascii(db, IMPORT_ESSID,argv[4]);
  852. } else if (strcasecmp(argv[3], IMPORT_PASSWD) == 0 || strcasecmp(argv[3],"password") == 0) {
  853. if ( check_for_db(&db, argv[1], 1, 0) ) {
  854. return 1;
  855. }
  856. import_ascii(db,IMPORT_PASSWD, argv[4]);
  857. } else {
  858. print_help("Invalid import format specified.");
  859. return 1;
  860. }
  861. break;
  862. case 's':
  863. // SQL
  864. // We don't know if the SQL order is changing the file or not
  865. if ( check_for_db(&db, argv[1], 0, 0) ) {
  866. return 1;
  867. }
  868. sql_stdout(db, argv[3], 0);
  869. break;
  870. case 't':
  871. // Stats
  872. if ( check_for_db(&db, argv[1], 0, 1) ) {
  873. return 1;
  874. }
  875. show_stats(db, (argv[3] == NULL) ? 0 : 1);
  876. break;
  877. case 'v':
  878. // Verify
  879. if ( check_for_db(&db, argv[1], 0, (argc > 3 && strcasecmp(argv[3],"all")==0) ? 0 : 1) ) {
  880. return 1;
  881. }
  882. verify(db, (argc > 3 && strcasecmp(argv[3],"all")==0) ? 1 : 0);
  883. break;
  884. default:
  885. print_help("Invalid option");
  886. break;
  887. }
  888. }
  889. else
  890. {
  891. print_help(NULL);
  892. }
  893. if (db)
  894. sqlite3_close(db);
  895. return 0;
  896. }