/* * ------------------------------------ * Bullet-Proof Extensible Vote Counter * ------------------------------------ * * In response to Daniel Horn's abominable, sick and twisted idea of running * a contest for programs that skew election results, I decided to counter * his efforts by providing this program that not only counts votes perfectly * well, but also goes great lengths to verify data integrity in case of * unforseen flaws or tampering attempts. * * I did not rely on his proposed vote counting framework, noting that * first and foremost, it could be already backdoored, and second, that * it does not scale well. * * -- Michal Zalewski * */ #include #include #include #include /* Error reporting macro */ #define fatal(x) do { fprintf(stderr,"ERROR: %s\n",x); exit(1); } while (0) #define CHECK_INTERVAL 10 /* How often to check database? */ #define VOTE_LIMIT 300000000 /* Maximum number of votes possible */ /* Candidates and vote count. Can be extended and modified at will. The last entry should be NULL, reserved for "other". */ struct candidate { char* name; unsigned int votes; } tally[] = { { "Bush" , 0 }, { "Kerry", 0 }, { "Nader", 0 }, { NULL , 0 } }; /* Total vote count - used to validate individual vote counts. */ unsigned int total = 0; /* Display all results, including the trailing NULL ("other"). */ void show_results(void) { struct candidate* t = tally; do printf("%-8s : %u\n", t->name ? t->name : "Other", t->votes); while ((t++)->name); } /* Safely count vote. Every CHECK_INTERVAL votes, run a database integrity check to detect corrupted vote counts or candidate names; otherwise, just count the vote. */ #define VOTE_AND_CHECK(v) do { \ if (!(total % CHECK_INTERVAL)) { \ struct candidate* t = tally; \ unsigned int cur_tot = 0; \ /* Verify that votes add up to the right count... */ \ do cur_tot += t->votes; while ((t++)->name); \ if (cur_tot != total) fatal("Vote count tampering!"); \ /* Go back through entries and verify every name... */ \ t--; \ while ((--t) != tally) \ if (!t->name || !isupper(*t->name)) fatal("Candidate tampering!"); \ /* Count vote, checking for erratic numbers */ \ if ((v)++ >= VOTE_LIMIT) fatal("Too many voters!"); \ } else (v)++; \ total++; \ } while (0) /* Add one vote for candidate whose initial is given by c. If no matching candidate found, account as "other". */ void process_vote(unsigned char c) { struct candidate* t = tally; while (t->name) { if (t->name[0] == c) { VOTE_AND_CHECK(t->votes); return; } t++; } VOTE_AND_CHECK(t->votes); } /* Run the elections! */ int main(int argc,char** argv) { int c; /* Read and process votes */ while ((c=getchar()) != EOF) if (!isspace(c)) process_vote(c); /* And the winner is... */ show_results(); return 0; }