// throw some statistics about the db to stdout. // if precise!=0 the stats will be queried nail by nail which can be slow void show_stats(sqlite3* db, int precise) { sql_exec(db,"BEGIN;"); int essids = query_int(db, "SELECT COUNT(*) FROM essid;"); int passwds = query_int(db,"SELECT COUNT(*) FROM passwd;"); int done; if (precise != 0) { printf("Determining precise statistics may be slow...\n"); 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"); } else { done = query_int(db, "SELECT COUNT(*) FROM pmk;"); } 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); if (precise != 0) { 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); } else { 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); } sql_exec(db,"COMMIT;"); }
// export to a cowpatty file void export_cowpatty(sqlite3* db, char* essid, char* filename) { struct hashdb_head filehead; memset(&filehead, 0, sizeof(filehead)); FILE *f = NULL; if (access(filename, F_OK)==0) { printf("The file already exists and I won't overwrite it.\n"); return; } // ensure that the essid is found in the db and has at least one entry in the pmk table. 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); int rc = query_int(db,sql); sqlite3_free(sql); if (rc == 0) { printf("There is no such ESSID in the database or there are no PMKs for it.\n"); return; } memcpy(filehead.ssid, essid,strlen(essid)); filehead.ssidlen = strlen(essid); filehead.magic = GENPMKMAGIC; f = fopen(filename, "w"); if (f == NULL || fwrite(&filehead, sizeof(filehead), 1, f) != 1) { printf("Couldn't open the export file for writing.\n"); return; } // 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. 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); printf("Exporting...\n"); rc = sql_exec_cb(db,sql,&sql_exportcow,f); sqlite3_free(sql); if (rc != SQLITE_OK) { printf("There was an error while exporting.\n"); } fclose(f); printf("Done.\n"); }
// import a cowpatty file int import_cowpatty(sqlite3* db, char* filename) { struct hashdb_head filehead; struct hashdb_rec rec; FILE *f = NULL; int rc; sqlite3_stmt *stmt; char* sql; int essid_id; int wordlength; char passwd[63+1]; if (strcmp(filename,"-") == 0) { f = stdin; } else { f = fopen(filename, "r"); } if (f == NULL || fread(&filehead, sizeof(filehead),1,f) != 1) { printf("Couldn't open the import file for reading.\n"); return 0; } else if (filehead.magic != GENPMKMAGIC) { printf("File doesn't seem to be a cowpatty file.\n"); fclose(f); return 0; } else if (verify_essid((char *)filehead.ssid) != 0) { printf("The file's ESSID is invalid.\n"); fclose(f); return 0; } printf("Reading header...\n"); //We need protection so concurrent transactions can't smash the ID-references sql_exec(db,"BEGIN;"); sql = sqlite3_mprintf("INSERT OR IGNORE INTO essid (essid) VALUES ('%q');",filehead.ssid); sql_exec(db,sql); sqlite3_free(sql); //since there is only one essid per file, we can determine it's ID now sql = sqlite3_mprintf("SELECT essid_id FROM essid WHERE essid = '%q'", filehead.ssid); essid_id = query_int(db,sql); sqlite3_free(sql); if (essid_id == 0) { fclose(f); sql_exec(db,"ROLLBACK;"); printf("ESSID couldn't be inserted. I've given up.\n"); return 0; } sql = sqlite3_mprintf("CREATE TEMPORARY TABLE import (passwd text, pmk blob);", essid_id); sql_exec(db,sql); sqlite3_free(sql); sql_prepare(db,"INSERT INTO import (passwd,pmk) VALUES (@pw,@pmk)",&stmt,-1); printf("Reading...\n"); while ((rc = fread(&rec.rec_size, sizeof(rec.rec_size), 1, f)) == 1) { wordlength = abs(rec.rec_size) - (sizeof(rec.pmk) + sizeof(rec.rec_size)); //prevent out of bounds writing (sigsegv guaranteed) but don't skip the whole file if wordlength < 8 if (wordlength > 0 && wordlength < (int) sizeof(passwd)) { passwd[wordlength] = 0; rc += fread(passwd, wordlength, 1, f); if (rc == 2) rc += fread(&rec.pmk, sizeof(rec.pmk), 1, f); } if (rc != 3) { fprintf(stdout,"Error while reading record (%i).\n",rc); sqlite3_finalize(stmt); if (db == NULL) { printf("omg"); fflush(stdout); } sql_exec(db, "ROLLBACK;"); fclose(f); return 1; } if (verify_passwd(passwd) == 0) { sqlite3_bind_text(stmt,1,passwd, strlen(passwd),SQLITE_TRANSIENT); sqlite3_bind_blob(stmt,2,&rec.pmk, sizeof(rec.pmk),SQLITE_TRANSIENT); if (sql_step(stmt,-1) == SQLITE_DONE) { sqlite3_reset(stmt); } else { printf("Error while inserting record into database.\n"); sqlite3_finalize(stmt); sql_exec(db, "ROLLBACK;"); fclose(f); return 1; } } else { fprintf(stdout,"Invalid password %s will not be imported.\n",passwd); } } sqlite3_finalize(stmt); if (!feof(f)) { printf("Error while reading file.\n"); sql_exec(db,"ROLLBACK;"); fclose(f); return 1; } printf("Updating references...\n"); sql_exec(db, "INSERT OR IGNORE INTO passwd (passwd) SELECT passwd FROM import;"); //TODO Give the user a choice to either INSERT OR UPDATE or INSERT OR IGNORE printf("Writing...\n"); 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); sql_exec(db,sql); sqlite3_free(sql); sql_exec(db,"COMMIT;"); fclose(f); return 1; }
/* batch-process all combinations of ESSIDs and PASSWDs. this function may be called only once per db at the same time, yet multiple processes can batch-process a single db. don't modify this function's layout or it's queries without carefully considering speed, efficiency and concurrency. */ void batch_process(sqlite3* db) { int rc; int cur_essid = 0; struct timeval starttime; struct timeval curtime; gettimeofday(&starttime,NULL); int rowcount = 0; char *sql; 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) { fprintf(stderr,"Failed to create buffer for batch processing.\n"); return; } // may fail - thats ok cur_essid = query_int(db,"SELECT essid_id FROM workbench LIMIT 1;"); while(1) { //loop over everything do { //loop over ESSID do { //loop over workbench sql_exec(db,"DELETE FROM temp.buffer;"); // select some work from the workbench into our own buffer // move lockid ahead so other clients won't get those rows any time soon sql_exec(db,"BEGIN EXCLUSIVE;"); 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;"); sql_exec(db,"UPDATE workbench SET lockid=lockid+1 WHERE wb_id IN (SELECT wb_id FROM buffer);"); sql_exec(db,"COMMIT;"); rc = query_int(db,"SELECT COUNT(*) FROM buffer;"); if (rc > 0) { // now calculate all the PMKs with a single statement. // remember the update won't lock the db sql_exec(db,"UPDATE temp.buffer SET pmk = PMK(essid,passwd);"); // commit work and delete package from workbench sql_exec(db,"BEGIN EXCLUSIVE;"); sql_exec(db,"INSERT OR IGNORE INTO pmk (essid_id,passwd_id,pmk) SELECT essid_id,passwd_id,pmk FROM temp.buffer"); sql_exec(db,"DELETE FROM workbench WHERE wb_id IN (SELECT wb_id FROM buffer);"); sql_exec(db,"COMMIT;"); rowcount += rc; gettimeofday(&curtime,NULL); int timediff = curtime.tv_sec - starttime.tv_sec; 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;")); fflush(stdout); } } while (rc > 0); 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); sql_exec(db,sql); sqlite3_free(sql); } 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); 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;"); if (cur_essid == 0) { printf("All ESSID processed.\n\n"); sqlite3_close(db); exit(0); /* printf("No free ESSID found. Will try determining new ESSID in 5 minutes...\n"); sleep(60*5); // slower, yet certain. should never be any better than the above, unless users fumble with the db. 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;"); if (cur_essid == 0) { printf("No free ESSID found. Sleeping 25 additional minutes...\n"); sleep(60*25); } */ } } //never reached sql_exec(db,"DROP TABLE temp.buffer;"); }
static int procfs_read_encr(char *page, char **start, off_t off, int count, int *eof, void *data) { char *p = page; struct ndis_handle *handle = (struct ndis_handle *) data; int i, encr_status, auth_mode, op_mode; unsigned int res, written, needed; struct ndis_essid essid; mac_address ap_address; if (off != 0) { *eof = 1; return 0; } res = doquery(handle, NDIS_OID_BSSID, (char*)&ap_address, sizeof(ap_address), &written, &needed); if (res) memset(ap_address, 0, ETH_ALEN); p += sprintf(p, "ap_address=%2.2X", ap_address[0]); for (i = 1 ; i < ETH_ALEN ; i++) p += sprintf(p, ":%2.2X", ap_address[i]); p += sprintf(p, "\n"); res = doquery(handle, NDIS_OID_ESSID, (char*)&essid, sizeof(essid), &written, &needed); if (!res) { essid.essid[essid.length] = '\0'; p += sprintf(p, "essid=%s\n", essid.essid); } res = query_int(handle, NDIS_OID_ENCR_STATUS, &encr_status); res |= query_int(handle, NDIS_OID_AUTH_MODE, &auth_mode); if (!res) { int active = handle->encr_info.active; p += sprintf(p, "tx_key=%u\n", handle->encr_info.active); p += sprintf(p, "key="); if (handle->encr_info.keys[active].length > 0) for (i = 0; i < NDIS_ENCODING_TOKEN_MAX && i < handle->encr_info.keys[active].length; i++) p += sprintf(p, "%2.2X", handle->encr_info.keys[active].key[i]); else p += sprintf(p, "off"); p += sprintf(p, "\n"); p += sprintf(p, "status=%sabled\n", (encr_status == ENCR_DISABLED) ? "dis" : "en"); p += sprintf(p, "auth_mode=%s\n", (auth_mode == AUTHMODE_RESTRICTED) ? "restricted" : "open"); } res = query_int(handle, NDIS_OID_MODE, &op_mode); p += sprintf(p, "mode=%s\n", (op_mode == NDIS_MODE_ADHOC) ? "adhoc" : (op_mode == NDIS_MODE_INFRA) ? "managed" : "auto"); if (p - page > count) { WARNING("wrote %u bytes (limit is %u)", p - page, count); *eof = 1; } return (p - page); }
static int procfs_read_hw(char *page, char **start, off_t off, int count, int *eof, void *data) { char *p = page; struct ndis_handle *handle = (struct ndis_handle *)data; struct ndis_configuration config; unsigned int res, written, needed, power_mode; unsigned long tx_power, bit_rate, rts_threshold, frag_threshold; unsigned long antenna; if (off != 0) { *eof = 1; return 0; } res = doquery(handle, NDIS_OID_CONFIGURATION, (char*)&config, sizeof(config), &written, &needed); if (!res) { p += sprintf(p, "beacon_period=%u msec\n", config.beacon_period); p += sprintf(p, "atim_window=%u msec\n", config.atim_window); p += sprintf(p, "frequency=%u kHZ\n", config.ds_config); p += sprintf(p, "hop_pattern=%u\n", config.fh_config.hop_pattern); p += sprintf(p, "hop_set=%u\n", config.fh_config.hop_set); p += sprintf(p, "dwell_time=%u msec\n", config.fh_config.dwell_time); } res = doquery(handle, NDIS_OID_TX_POWER_LEVEL, (char*)&tx_power, sizeof(tx_power), &written, &needed); if (!res) p += sprintf(p, "tx_power=%lu mW\n", tx_power); res = doquery(handle, NDIS_OID_GEN_SPEED, (char*)&bit_rate, sizeof(bit_rate), &written, &needed); if (!res) p += sprintf(p, "bit_rate=%lu kBps\n", bit_rate / 10); res = doquery(handle, NDIS_OID_RTS_THRESH, (char*)&rts_threshold, sizeof(rts_threshold), &written, &needed); if (!res) p += sprintf(p, "rts_threshold=%lu bytes\n", rts_threshold); res = doquery(handle, NDIS_OID_FRAG_THRESH, (char*)&frag_threshold, sizeof(frag_threshold), &written, &needed); if (!res) p += sprintf(p, "frag_threshold=%lu bytes\n", frag_threshold); res = query_int(handle, NDIS_OID_POWER_MODE, &power_mode); if (!res) p += sprintf(p, "power_mode=%s\n", (power_mode == NDIS_POWER_OFF) ? "always_on" : (power_mode == NDIS_POWER_MAX) ? "max_savings" : "min_savings"); res = doquery(handle, NDIS_OID_NUM_ANTENNA, (char *)&antenna, sizeof(antenna), &written, &needed); if (!res) p += sprintf(p, "num_antennas=%lu\n", antenna); res = doquery(handle, NDIS_OID_TX_ANTENNA, (char *)&antenna, sizeof(antenna), &written, &needed); if (!res) p += sprintf(p, "tx_antenna=%lu\n", antenna); res = doquery(handle, NDIS_OID_RX_ANTENNA, (char *)&antenna, sizeof(antenna), &written, &needed); if (!res) p += sprintf(p, "rx_antenna=%lu\n", antenna); if (p - page > count) { WARNING("wrote %u bytes (limit is %u)", p - page, count); *eof = 1; } return (p - page); }