Remove the -v option.
[shallot/rransom.git] / src / shallot.c
blobf68942c70a85058bf337f7b58a684d722ce22375
1 /* program: shallot (based on the popular onionhash program by Bebop)
2 * version: 0.0.2
3 * purpose: brute-force customized SHA1-hashes of RSA keys for Tor's
4 * .onion namespace
5 * license: OSI-approved MIT License
6 * credits: Bebop, for onionhash, which credits the following:
7 * - Plasmoid (The Hacker's Choice)
8 * - Roger Dingledine (Tor Project)
9 * - Nick Mathewson (Tor Project)
10 * - Eric Young (OpenSSL Project)
12 * I would also like to thank the following testers/benchmarkers:
13 * - seeess (Linux)
14 * - Cheeze- (Linux, OS X)
15 * - Tas (Linux, OS X, OpenBSD)
16 * - ^wAc^ (FreeBSD)
17 * - cybernetseraph (OpenBSD)
19 * Special thanks to nickm for some debugging assistance!
20 * Extra-special thanks to Tas for his patience and assistance
21 * in getting shallot to build on OpenBSD, OS X, and Linux
23 * contact: mention bugs to <`Orum@OFTC or `Orum@ORC>
26 /* TODO:
27 * - finish all TODOs
28 * - figure out a way to allow for -p w/o a pattern being supplied
29 * - allow -m to be used with -f (use file for status output) [v0.0.3]
32 #include "config.h"
34 #include "math.h"
35 #include "error.h"
36 #include "print.h"
37 #include "thread.h"
38 #include "defines.h"
39 #include "globals.h"
41 #ifdef LINUX_PORT
42 // Linux specific headers
43 #include "linux.h"
44 #include <fcntl.h>
45 #include <string.h> // included with something else on *BSD
46 #include <sys/uio.h>
47 #endif
49 #ifdef BSD
50 // BSD specific headers
51 #include <sys/param.h> // needed on OpenBSD
52 #include <sys/sysctl.h>
53 #endif
55 #include <signal.h>
56 #include <unistd.h>
57 #include <sys/stat.h>
59 void terminate(int signum) { // Ctrl-C/kill handler
60 error(X_SGNL_INT_TERM);
63 int main(int argc, char *argv[]) { // onions are fun, here we go
64 signal(SIGTERM, terminate); // always let people kill
66 if(argc < 2) // not enough arguments
67 usage();
69 // set up our initial values
70 uint8_t daemon = 0, optimum = 0;
71 uint32_t threads = 1, x = 1;
72 char *file = 0;
73 elim = DEFAULT_E_LIMIT;
74 loop = 0;
75 found = 0;
76 monitor = 0;
78 #ifdef BSD // my
79 int mib[2] = { CTL_HW, HW_NCPU }; // how
80 size_t size = sizeof(threads); // easy
81 if(sysctl(mib, 2, &threads, &size, NULL, 0)) // BSD
82 error(X_SYSCTL_FAILED); // is
84 #elif defined(LINUX_PORT) // Oh no! We're on linux... :(
85 // ...even *Windows 95* (gasp!) has a better way of doing this...
86 // TODO: move this to linux.c
87 char cpuinfo[CPUINFO_BUF_SIZE] = "";
88 int fd = open(CPUINFO_PATH, O_RDONLY);
90 if(fd < 0)
91 error(X_BAD_FILE_DESC);
93 threads--; // reset threads to 0
94 size_t r = 0;
95 ssize_t tmp = 1; // must not initially be 0!
96 uint16_t used = 0;
98 do {
99 if(tmp)
100 tmp = read(fd, &cpuinfo[r], CPUINFO_BUF_SIZE - r); // fill the buffer
102 if(tmp < 0) // something went wrong
103 error(X_ABNORMAL_READ);
105 r += tmp; // add how much we read
107 if(r < CPUINFO_BUF_SIZE)
108 cpuinfo[r] = 0;
110 threads += parse_cpuinfo(&cpuinfo[0], (uint16_t)r, &used);
111 r -= used; // subtract what we parsed
113 memmove(&cpuinfo[0], &cpuinfo[used], r);
114 } while(used > 0);
116 close(fd); // TODO: add error handling! (is there any point?)
118 if(!threads) { // This is needed for Liunx/ARM (do not remove!)
119 printf("WARNING: No CPUs detected. Defaulting to 1 thread... "
120 "(or manually specify thread count with -t)\n");
121 threads++;
124 #elif defined(GENERIC)
125 printf("WARNING: Threads will default to 1 unless specified with -t\n");
126 #endif
128 for(; x < argc - 1; x++) { // options parsing
129 if(argv[x][0] != '-') {
130 fprintf(stderr, "Error: Options must start with '-'\n");
131 usage();
133 uint32_t y = 1;
134 for(; argv[x][y] != '\0'; y++) {
135 uint8_t dbreak = 0;
136 switch(argv[x][y]) {
137 case 'd': { // daemonize
138 daemon = 1;
139 break;
141 case 'm': { // monitor
142 monitor = 1;
143 break;
145 case 'o': { // prime optimization
146 optimum = 1;
147 break;
149 case 'p': { // pattern help
150 pattern();
151 break;
153 case 'f': { // file <file>
154 if((argv[x][y + 1] != '\0') || (x + 1 > argc)) {
155 fprintf(stderr, "Error: -f format is '-f <file>'\n");
156 usage();
158 file = argv[x + 1];
159 dbreak = 1;
160 break;
162 case 't': { // threads
163 if((argv[x][y + 1] != '\0') || (x + 1 > argc)) {
164 fprintf(stderr, "Error: -t format is '-t threads'\n");
165 usage();
167 threads = strtoul(argv[x + 1], NULL, 0);
168 dbreak = 1;
169 break;
171 case 'e': { // e limit
172 if((argv[x][y + 1] != '\0') || (x + 1 > argc)) {
173 fprintf(stderr, "Error: -e format is '-e limit'\n");
174 usage();
176 elim = strtoull(argv[x + 1], NULL, 0);
177 dbreak = 1;
178 break;
180 default: { // unrecognized
181 fprintf(stderr, "Error: Unrecognized option - '%c'\n", argv[x][y]);
182 usage();
183 break; // redundant... but safe :)
186 if(dbreak) {
187 x++; //skip the next param
188 break;
193 // now for our sanity checks
194 if(threads < 1)
195 error(X_INVALID_THRDS);
197 if(monitor && file)
198 error(X_EXCLUSIVE_OPT);
200 if(!(elim & 1) || (elim < RSA_PK_EXPONENT) || (elim > MAXIMUM_E_LIMIT))
201 error(X_INVALID_E_LIM);
203 if(daemon && !file)
204 error(X_NEED_FILE_OUT);
206 // compile regular expression from argument
207 char *pattern = argv[argc - 1];
209 if(*pattern == '-')
210 error(X_REGEX_INVALID);
212 regex = malloc(REGEX_COMP_LMAX);
214 if(regcomp(regex, pattern, REG_EXTENDED | REG_NOSUB))
215 error(X_REGEX_COMPILE);
217 if(file) {
218 umask(077); // remove permissions to be safe
220 // redirect output
221 if (
222 (freopen(file, "w", stdout) == NULL) ||
223 (freopen(file, "w", stderr) == NULL)
224 ) error(X_FILE_OPEN_ERR);
227 if(daemon && (getppid() != 1)) { // daemonize if we should
228 pid_t pid = fork();
230 if(pid < 0) // fork failed
231 error(X_DAEMON_FAILED);
233 if(pid) // exit on the parent process
234 exit(0);
236 if(setsid() < 0) // get a new SID
237 error(X_DAEMON_FAILED);
239 if(chdir("/") < 0) // cd to root
240 error(X_DAEMON_FAILED);
242 // block input
243 if (freopen("/dev/null", "r", stdin) == NULL)
244 error(X_FILE_OPEN_ERR);
246 // ignore certain signals
247 signal(SIGCHLD, SIG_IGN);
248 signal(SIGTSTP, SIG_IGN);
249 signal(SIGTTOU, SIG_IGN);
250 signal(SIGTTIN, SIG_IGN);
251 signal(SIGHUP, SIG_IGN);
253 } else signal(SIGINT, terminate); // die on CTRL-C
255 pthread_t thrd;
257 // create our threads for 2+ cores
258 for(x = 1; x < threads; x++) {
260 if(pthread_create(&thrd, NULL, worker, &optimum))
261 error(X_THREAD_CREATE);
264 if(monitor) {
265 // TODO: when support is added for -mv, put a message here
266 if(pthread_create(&thrd, NULL, monitor_proc, NULL))
267 error(X_THREAD_CREATE);
270 worker(&optimum); // use main thread for brute forcing too
272 if(pthread_self() != lucky_thread) { // be safe and avoid EDEADLK
274 pthread_join(lucky_thread, NULL); // wait for the lucky thread to exit
277 regfree(regex);
278 return 0;