1 /**
2  * Author......: See docs/credits.txt
3  * License.....: MIT
4  */
5 
6 #include "common.h"
7 #include "types.h"
8 #include "memory.h"
9 #include "event.h"
10 #include "shared.h"
11 #include "folder.h"
12 #include <libgen.h>
13 
14 #if defined (__APPLE__)
15 #include "event.h"
16 #endif
17 
get_exec_path(char * exec_path,const size_t exec_path_sz)18 static int get_exec_path (char *exec_path, const size_t exec_path_sz)
19 {
20   #if defined (__linux__) || defined (__CYGWIN__)
21 
22   char *tmp;
23 
24   hc_asprintf (&tmp, "/proc/%d/exe", getpid ());
25 
26   const ssize_t len = readlink (tmp, exec_path, exec_path_sz - 1);
27 
28   hcfree (tmp);
29 
30   if (len == -1) return -1;
31 
32   #elif defined (_WIN)
33 
34   memset (exec_path, 0, exec_path_sz);
35 
36   const int len = 0;
37 
38   #elif defined (__APPLE__)
39 
40   u32 size = (u32) exec_path_sz;
41 
42   if (_NSGetExecutablePath (exec_path, &size) != 0) return -1;
43 
44   const size_t len = strlen (exec_path);
45 
46   #elif defined (__FreeBSD__) || defined(__DragonFly__)
47 
48   #include <sys/sysctl.h>
49 
50   int mib[4];
51 
52   mib[0] = CTL_KERN;
53   mib[1] = KERN_PROC;
54   mib[2] = KERN_PROC_PATHNAME;
55   mib[3] = -1;
56 
57   size_t size = exec_path_sz;
58 
59   sysctl (mib, 4, exec_path, &size, NULL, 0);
60 
61   const size_t len = strlen (exec_path);
62 
63   #else
64   #error Your Operating System is not supported or detected
65   #endif
66 
67   exec_path[len] = 0;
68 
69   return 0;
70 }
71 
get_install_dir(char * install_dir,const char * exec_path)72 static void get_install_dir (char *install_dir, const char *exec_path)
73 {
74   strncpy (install_dir, exec_path, HCBUFSIZ_TINY - 1);
75 
76   char *last_slash = NULL;
77 
78   if ((last_slash = strrchr (install_dir, '/')) != NULL)
79   {
80     *last_slash = 0;
81   }
82   else if ((last_slash = strrchr (install_dir, '\\')) != NULL)
83   {
84     *last_slash = 0;
85   }
86   else
87   {
88     install_dir[0] = '.';
89     install_dir[1] = 0;
90   }
91 }
92 
93 #if defined (_POSIX)
get_profile_dir(char * profile_dir,const char * home_dir)94 static void get_profile_dir (char *profile_dir, const char *home_dir)
95 {
96   snprintf (profile_dir, HCBUFSIZ_TINY, "%s/%s", home_dir, DOT_HASHCAT);
97 
98   if (hc_path_is_directory (profile_dir)) return;
99 
100   char *xdg_data_home = getenv ("XDG_DATA_HOME");
101 
102   if (xdg_data_home)
103   {
104     snprintf (profile_dir, HCBUFSIZ_TINY, "%s/hashcat", xdg_data_home);
105   }
106   else
107   {
108     snprintf (profile_dir, HCBUFSIZ_TINY, "%s/.local/share/hashcat", home_dir);
109   }
110 }
111 
get_cache_dir(char * cache_dir,const char * home_dir)112 static void get_cache_dir (char *cache_dir, const char *home_dir)
113 {
114   snprintf (cache_dir, HCBUFSIZ_TINY, "%s/%s", home_dir, DOT_HASHCAT);
115 
116   if (hc_path_is_directory (cache_dir)) return;
117 
118   char *xdg_cache_home = getenv ("XDG_CACHE_HOME");
119 
120   if (xdg_cache_home)
121   {
122     snprintf (cache_dir, HCBUFSIZ_TINY, "%s/hashcat", xdg_cache_home);
123   }
124   else
125   {
126     snprintf (cache_dir, HCBUFSIZ_TINY, "%s/.cache/hashcat", home_dir);
127   }
128 }
129 
get_session_dir(char * session_dir,const char * profile_dir)130 static void get_session_dir (char *session_dir, const char *profile_dir)
131 {
132   snprintf (session_dir, HCBUFSIZ_TINY, "%s/%s", profile_dir, SESSIONS_FOLDER);
133 }
134 #endif
135 
count_dictionaries(char ** dictionary_files)136 int count_dictionaries (char **dictionary_files)
137 {
138   if (dictionary_files == NULL) return 0;
139 
140   int cnt = 0;
141 
142   for (int d = 0; dictionary_files[d] != NULL; d++)
143   {
144     cnt++;
145   }
146 
147   return (cnt);
148 }
149 
first_file_in_directory(const char * path)150 char *first_file_in_directory (const char *path)
151 {
152   DIR *d;
153 
154   if ((d = opendir (path)) != NULL)
155   {
156     char *first_file = NULL;
157 
158     #if 0
159 
160     struct dirent e;
161 
162     for (;;)
163     {
164       memset (&e, 0, sizeof (e));
165 
166       struct dirent *de = NULL;
167 
168       if (readdir_r (d, &e, &de) != 0) break;
169 
170       if (de == NULL) break;
171 
172     #else
173 
174     struct dirent *de;
175 
176     while ((de = readdir (d)) != NULL)
177     {
178 
179     #endif
180 
181       if (de->d_name[0] == '.') continue;
182 
183       first_file = strdup (de->d_name);
184 
185       break;
186     }
187 
188     closedir (d);
189 
190     return first_file;
191   }
192 
193   return NULL;
194 }
195 
196 char **scan_directory (const char *path)
197 {
198   char *tmp_path = hcstrdup (path);
199 
200   size_t tmp_path_len = strlen (tmp_path);
201 
202   while (tmp_path[tmp_path_len - 1] == '/' || tmp_path[tmp_path_len - 1] == '\\')
203   {
204     tmp_path[tmp_path_len - 1] = 0;
205 
206     tmp_path_len = strlen (tmp_path);
207   }
208 
209   char **files = NULL;
210 
211   size_t num_files = 0;
212 
213   DIR *d = NULL;
214 
215   if ((d = opendir (tmp_path)) != NULL)
216   {
217     #if 0
218 
219     struct dirent e;
220 
221     for (;;)
222     {
223       memset (&e, 0, sizeof (e));
224 
225       struct dirent *de = NULL;
226 
227       if (readdir_r (d, &e, &de) != 0) break;
228 
229       if (de == NULL) break;
230 
231     #else
232 
233     struct dirent *de;
234 
235     while ((de = readdir (d)) != NULL)
236     {
237 
238     #endif
239 
240       if (de->d_name[0] == '.') continue;
241 
242       char *path_file;
243 
244       hc_asprintf (&path_file, "%s/%s", tmp_path, de->d_name);
245 
246       DIR *d_test;
247 
248       if ((d_test = opendir (path_file)) != NULL)
249       {
250         closedir (d_test);
251 
252         hcfree (path_file);
253       }
254       else
255       {
256         files = (char **) hcrealloc (files, (num_files + 1) * sizeof (char *), sizeof (char *));
257 
258         files[num_files] = path_file;
259 
260         num_files++;
261       }
262     }
263 
264     closedir (d);
265   }
266   else if (errno == ENOTDIR)
267   {
268     files = (char **) hcrealloc (files, (num_files + 1) * sizeof (char *), sizeof (char *));
269 
270     files[num_files] = hcstrdup (path);
271 
272     num_files++;
273   }
274 
275   files = (char **) hcrealloc (files, (num_files + 1) * sizeof (char *), sizeof (char *));
276 
277   files[num_files] = NULL;
278 
279   hcfree (tmp_path);
280 
281   return (files);
282 }
283 
284 int folder_config_init (hashcat_ctx_t *hashcat_ctx, MAYBE_UNUSED const char *install_folder, MAYBE_UNUSED const char *shared_folder)
285 {
286   folder_config_t *folder_config = hashcat_ctx->folder_config;
287 
288   /**
289    * There's some buggy OpenCL runtime that do not support -I.
290    * A workaround is to chdir() to the OpenCL folder,
291    * then compile the kernels,
292    * then chdir() back to where we came from so we need to save it first
293    * - temporary disabled due to https://github.com/hashcat/hashcat/issues/2379
294    */
295 
296   char *cwd = (char *) hcmalloc (HCBUFSIZ_TINY);
297 
298   if (getcwd (cwd, HCBUFSIZ_TINY - 1) == NULL)
299   {
300     event_log_error (hashcat_ctx, "getcwd(): %s", strerror (errno));
301 
302     hcfree (cwd);
303 
304     return -1;
305   }
306 
307   /**
308    * folders, as discussed on https://github.com/hashcat/hashcat/issues/20
309    */
310 
311   const size_t exec_path_sz = 1024;
312 
313   char *exec_path = (char *) hcmalloc (exec_path_sz);
314 
315   const int rc = get_exec_path (exec_path, exec_path_sz);
316 
317   if (rc == -1)
318   {
319     event_log_error (hashcat_ctx, "get_exec_path() failed.");
320 
321     hcfree (cwd);
322 
323     hcfree (exec_path);
324 
325     return -1;
326   }
327 
328   #if defined (_POSIX)
329 
330   static const char SLASH[] = "/";
331 
332   if (install_folder == NULL) install_folder = SLASH; // makes library use easier
333 
334   char *resolved_install_folder = realpath (install_folder, NULL);
335   char *resolved_exec_path      = realpath (exec_path, NULL);
336 
337   if (resolved_install_folder == NULL) resolved_install_folder = hcstrdup (SLASH);
338 
339   /*
340   This causes invalid error out if install_folder (/usr/local/bin) does not exist
341   if (resolved_install_folder == NULL)
342   {
343     event_log_error (hashcat_ctx, "%s: %s", resolved_install_folder, strerror (errno));
344 
345     hcfree (cwd);
346 
347     hcfree (exec_path);
348 
349     hcfree (resolved_install_folder);
350 
351     return -1;
352   }
353   */
354 
355   if (resolved_exec_path == NULL)
356   {
357     event_log_error (hashcat_ctx, "%s: %s", exec_path, strerror (errno));
358 
359     hcfree (cwd);
360 
361     hcfree (exec_path);
362 
363     hcfree (resolved_install_folder);
364 
365     return -1;
366   }
367 
368   char *install_dir = (char *) hcmalloc (HCBUFSIZ_TINY);
369 
370   get_install_dir (install_dir, resolved_exec_path);
371 
372   char *profile_dir = NULL;
373   char *cache_dir   = NULL;
374   char *session_dir = NULL;
375   char *shared_dir  = NULL;
376 
377   if (strcmp (install_dir, resolved_install_folder) == 0)
378   {
379     struct passwd pw;
380     struct passwd *pwp;
381 
382     char buf[HCBUFSIZ_TINY];
383 
384     getpwuid_r (getuid (), &pw, buf, HCBUFSIZ_TINY, &pwp);
385 
386     const char *home_dir = pwp->pw_dir;
387 
388     profile_dir = (char *) hcmalloc (HCBUFSIZ_TINY);
389     cache_dir   = (char *) hcmalloc (HCBUFSIZ_TINY);
390     session_dir = (char *) hcmalloc (HCBUFSIZ_TINY);
391 
392     get_profile_dir (profile_dir, home_dir);
393     get_cache_dir   (cache_dir,   home_dir);
394     get_session_dir (session_dir, profile_dir);
395 
396     shared_dir = hcstrdup (shared_folder);
397 
398     hc_mkdir_rec (profile_dir, 0700);
399     hc_mkdir_rec (cache_dir,   0700);
400     hc_mkdir     (session_dir, 0700);
401   }
402   else
403   {
404     profile_dir = install_dir;
405     cache_dir   = install_dir;
406     session_dir = install_dir;
407     shared_dir  = install_dir;
408   }
409 
410   hcfree (resolved_install_folder);
411   hcfree (resolved_exec_path);
412 
413   #else
414 
415   char *install_dir = hcmalloc (HCBUFSIZ_TINY);
416 
417   get_install_dir (install_dir, exec_path);
418 
419   char *profile_dir = install_dir;
420   char *cache_dir   = install_dir;
421   char *session_dir = install_dir;
422   char *shared_dir  = install_dir;
423 
424   #endif
425 
426   hcfree (exec_path);
427 
428   /**
429    * There are a lot of problems related to bad support of -I parameters when building the kernel.
430    * Each OpenCL runtime handles it slightly differently.
431    * The most problematic is with new AMD drivers on Windows, which cannot handle quote characters!
432    * The best workaround found so far is to modify the TMP variable (only inside hashcat process) before the runtime is loaded.
433    */
434 
435   char *cpath;
436 
437   #if defined (_WIN)
438 
439   hc_asprintf (&cpath, "%s\\OpenCL\\", shared_dir);
440 
441   char *cpath_real;
442 
443   hc_asprintf (&cpath_real, "%s\\OpenCL\\", shared_dir);
444 
445   #else
446 
447   hc_asprintf (&cpath, "%s/OpenCL/", shared_dir);
448 
449   char *cpath_real = (char *) hcmalloc (PATH_MAX);
450 
451   if (realpath (cpath, cpath_real) == NULL)
452   {
453     event_log_error (hashcat_ctx, "%s: %s", cpath, strerror (errno));
454 
455     hcfree (cwd);
456 
457     hcfree (shared_dir);
458 
459     // Attention: since hcfree () doesn't set the pointer to NULL, we need to do it externally such that
460     // we prevent double-freeing the same memory address (this happens if e.g. profile_dir == session_dir)
461 
462     if (profile_dir == shared_dir) profile_dir = NULL;
463     if (cache_dir   == shared_dir) cache_dir   = NULL;
464     if (session_dir == shared_dir) session_dir = NULL;
465 
466     shared_dir = NULL;
467 
468 
469     hcfree (profile_dir);
470 
471     if (session_dir == profile_dir) session_dir = NULL;
472     if (cache_dir   == profile_dir) cache_dir   = NULL;
473 
474     profile_dir = NULL;
475 
476 
477     hcfree (cache_dir);
478 
479     if (session_dir == cache_dir) session_dir = NULL;
480 
481     cache_dir = NULL;
482 
483     hcfree (session_dir);
484 
485     session_dir = NULL;
486 
487     hcfree (cpath_real);
488 
489     cpath_real = NULL;
490 
491     return -1;
492   }
493 
494   #endif
495 
496   hcfree (cpath);
497 
498   //if (getenv ("TMP") == NULL)
499   /* temporary disabled due to https://github.com/hashcat/hashcat/issues/2379
500   if (true)
501   {
502     char *tmp;
503 
504     hc_asprintf (&tmp, "TMP=%s", cpath_real);
505 
506     putenv (tmp);
507   }
508   */
509 
510   // not escaping here, using quotes later
511   // naive_escape (cpath_real, PATH_MAX,  ' ', '\\');
512 
513   #if defined (_WIN)
514 
515   naive_replace (cpath_real, '\\', '/');
516 
517   #endif
518 
519   /**
520    * kernel cache, we need to make sure folder exist
521    */
522 
523   char *kernels_folder;
524 
525   hc_asprintf (&kernels_folder, "%s/kernels", cache_dir);
526 
527   hc_mkdir (kernels_folder, 0700);
528 
529   hcfree (kernels_folder);
530 
531   /**
532    * store for later use
533    */
534 
535   folder_config->cwd          = cwd;
536   folder_config->install_dir  = install_dir;
537   folder_config->profile_dir  = profile_dir;
538   folder_config->cache_dir    = cache_dir;
539   folder_config->session_dir  = session_dir;
540   folder_config->shared_dir   = shared_dir;
541   folder_config->cpath_real   = cpath_real;
542 
543   return 0;
544 }
545 
546 void folder_config_destroy (hashcat_ctx_t *hashcat_ctx)
547 {
548   folder_config_t *folder_config = hashcat_ctx->folder_config;
549 
550   hcfree (folder_config->cpath_real);
551   hcfree (folder_config->cwd);
552   hcfree (folder_config->install_dir);
553 
554   memset (folder_config, 0, sizeof (folder_config_t));
555 }
556 
557 int hc_mkdir (const char *name, MAYBE_UNUSED const int mode)
558 {
559   #if defined (_WIN)
560   return _mkdir (name);
561   #else
562   return mkdir (name, mode);
563   #endif
564 }
565 
566 int hc_mkdir_rec (const char *path, MAYBE_UNUSED const int mode)
567 {
568   char *fullpath = hcstrdup (path);
569 
570   char *subpath = dirname (fullpath);
571 
572   if (strlen (subpath) > 1)
573   {
574     if (hc_mkdir_rec (subpath, mode) == -1) return -1;
575   }
576 
577   if (hc_mkdir (path, mode) == -1)
578   {
579     if (errno != EEXIST) return -1;
580   }
581 
582   hcfree (fullpath);
583 
584   return 0;
585 }
586