Remove a warning about ignoring the return value of freopen().
[shallot/rransom.git] / src / shallot.c
blob8622b5fda38004b352a079a522a84d350a229753
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 verbose = 0;
77 monitor = 0;
79 #ifdef BSD // my
80 int mib[2] = { CTL_HW, HW_NCPU }; // how
81 size_t size = sizeof(threads); // easy
82 if(sysctl(mib, 2, &threads, &size, NULL, 0)) // BSD
83 error(X_SYSCTL_FAILED); // is
85 #elif defined(LINUX_PORT) // Oh no! We're on linux... :(
86 // ...even *Windows 95* (gasp!) has a better way of doing this...
87 // TODO: move this to linux.c
88 char cpuinfo[CPUINFO_BUF_SIZE] = "";
89 int fd = open(CPUINFO_PATH, O_RDONLY);
91 if(fd < 0)
92 error(X_BAD_FILE_DESC);
94 threads--; // reset threads to 0
95 size_t r = 0;
96 ssize_t tmp = 1; // must not initially be 0!
97 uint16_t used = 0;
99 do {
100 if(tmp)
101 tmp = read(fd, &cpuinfo[r], CPUINFO_BUF_SIZE - r); // fill the buffer
103 if(tmp < 0) // something went wrong
104 error(X_ABNORMAL_READ);
106 r += tmp; // add how much we read
108 if(r < CPUINFO_BUF_SIZE)
109 cpuinfo[r] = 0;
111 threads += parse_cpuinfo(&cpuinfo[0], (uint16_t)r, &used);
112 r -= used; // subtract what we parsed
114 memmove(&cpuinfo[0], &cpuinfo[used], r);
115 } while(used > 0);
117 close(fd); // TODO: add error handling! (is there any point?)
119 if(!threads) { // This is needed for Liunx/ARM (do not remove!)
120 printf("WARNING: No CPUs detected. Defaulting to 1 thread... "
121 "(or manually specify thread count with -t)\n");
122 threads++;
125 #elif defined(GENERIC)
126 printf("WARNING: Threads will default to 1 unless specified with -t\n");
127 #endif
129 for(; x < argc - 1; x++) { // options parsing
130 if(argv[x][0] != '-') {
131 fprintf(stderr, "Error: Options must start with '-'\n");
132 usage();
134 uint32_t y = 1;
135 for(; argv[x][y] != '\0'; y++) {
136 uint8_t dbreak = 0;
137 switch(argv[x][y]) {
138 case 'd': { // daemonize
139 daemon = 1;
140 break;
142 case 'm': { // monitor
143 monitor = 1;
144 break;
146 case 'o': { // prime optimization
147 optimum = 1;
148 break;
150 case 'p': { // pattern help
151 pattern();
152 break;
154 case 'v': { // verbose
155 verbose = 1;
156 break;
158 case 'f': { // file <file>
159 if((argv[x][y + 1] != '\0') || (x + 1 > argc)) {
160 fprintf(stderr, "Error: -f format is '-f <file>'\n");
161 usage();
163 file = argv[x + 1];
164 dbreak = 1;
165 break;
167 case 't': { // threads
168 if((argv[x][y + 1] != '\0') || (x + 1 > argc)) {
169 fprintf(stderr, "Error: -t format is '-t threads'\n");
170 usage();
172 threads = strtoul(argv[x + 1], NULL, 0);
173 dbreak = 1;
174 break;
176 case 'e': { // e limit
177 if((argv[x][y + 1] != '\0') || (x + 1 > argc)) {
178 fprintf(stderr, "Error: -e format is '-e limit'\n");
179 usage();
181 elim = strtoull(argv[x + 1], NULL, 0);
182 dbreak = 1;
183 break;
185 default: { // unrecognized
186 fprintf(stderr, "Error: Unrecognized option - '%c'\n", argv[x][y]);
187 usage();
188 break; // redundant... but safe :)
191 if(dbreak) {
192 x++; //skip the next param
193 break;
198 // now for our sanity checks
199 if(threads < 1)
200 error(X_INVALID_THRDS);
202 if((monitor && file) || (monitor && verbose))
203 error(X_EXCLUSIVE_OPT);
205 if(!(elim & 1) || (elim < RSA_PK_EXPONENT) || (elim > MAXIMUM_E_LIMIT))
206 error(X_INVALID_E_LIM);
208 if(daemon && !file)
209 error(X_NEED_FILE_OUT);
211 if(verbose)
212 printf("Options parsed successfully.\nCompiling regex...\n");
214 // compile regular expression from argument
215 char *pattern = argv[argc - 1];
217 if(*pattern == '-')
218 error(X_REGEX_INVALID);
220 regex = malloc(REGEX_COMP_LMAX);
222 if(regcomp(regex, pattern, REG_EXTENDED | REG_NOSUB))
223 error(X_REGEX_COMPILE);
225 if(verbose)
226 printf("Regex compiled successfully.\n");
228 if(file) {
229 if(verbose)
230 printf("Redirecting output to file...\n");
232 umask(077); // remove permissions to be safe
234 // redirect output
235 if (
236 (freopen(file, "w", stdout) == NULL) ||
237 (freopen(file, "w", stderr) == NULL)
238 ) error(X_FILE_OPEN_ERR);
241 if(daemon && (getppid() != 1)) { // daemonize if we should
242 if(verbose)
243 printf("Daemonizing...\n");
245 pid_t pid = fork();
247 if(pid < 0) // fork failed
248 error(X_DAEMON_FAILED);
250 if(pid) // exit on the parent process
251 exit(0);
253 if(setsid() < 0) // get a new SID
254 error(X_DAEMON_FAILED);
256 if(chdir("/") < 0) // cd to root
257 error(X_DAEMON_FAILED);
259 // block input
260 if (freopen("/dev/null", "r", stdin) == NULL)
261 error(X_FILE_OPEN_ERR);
263 // ignore certain signals
264 signal(SIGCHLD, SIG_IGN);
265 signal(SIGTSTP, SIG_IGN);
266 signal(SIGTTOU, SIG_IGN);
267 signal(SIGTTIN, SIG_IGN);
268 signal(SIGHUP, SIG_IGN);
270 if(verbose)
271 printf("Daemonization completed successfully!\n");
272 } else signal(SIGINT, terminate); // die on CTRL-C
274 pthread_t thrd;
276 if(verbose)
277 printf("Spawning threads... (Total: %u)\n", threads);
279 // create our threads for 2+ cores
280 for(x = 1; x < threads; x++) {
281 if(verbose)
282 printf("Additional thread spawning (%u)...\n", x);
284 if(pthread_create(&thrd, NULL, worker, &optimum))
285 error(X_THREAD_CREATE);
288 if(monitor) {
289 // TODO: when support is added for -mv, put a message here
290 if(pthread_create(&thrd, NULL, monitor_proc, NULL))
291 error(X_THREAD_CREATE);
294 if(verbose)
295 printf("All additional threads (if any) spawned.\n"
296 "Main thread (ID: 0x%X) entering loop...\n",
297 (uint32_t)pthread_self());
299 worker(&optimum); // use main thread for brute forcing too
301 if(pthread_self() != lucky_thread) { // be safe and avoid EDEADLK
302 if(verbose)
303 printf("Main thread waiting on lucky thread (ID: 0x%X) to exit...\n",
304 (uint32_t)lucky_thread);
306 pthread_join(lucky_thread, NULL); // wait for the lucky thread to exit
309 if(verbose)
310 printf("Lucky thread exited loop.\nCleaning up and exiting...\n");
312 regfree(regex);
313 return 0;