1 /* radare - LGPL - Copyright 2008-2021 - pancake */
2 
3 #include <r_util.h>
4 #include <r_lib.h>
5 
6 R_LIB_VERSION(r_lib);
7 
8 /* TODO: avoid globals */
9 #define IFDBG if(__has_debug)
10 static bool __has_debug = false;
11 
12 /* XXX : this must be registered in runtime */
13 static const char *r_lib_types[] = {
14 	"io", "dbg", "lang", "asm", "anal", "parse", "bin", "bin_xtr", "bin_ldr",
15 	"bp", "syscall", "fastcall", "crypto", "core", "egg", "fs", NULL
16 };
17 
__lib_types_get(int idx)18 static const char *__lib_types_get(int idx) {
19 	if (idx < 0 || idx > R_LIB_TYPE_LAST - 1) {
20 		return "unk";
21 	}
22 	return r_lib_types[idx];
23 }
24 
r_lib_types_get_i(const char * str)25 R_API int r_lib_types_get_i(const char *str) {
26 	int i;
27 	for (i = 0; r_lib_types[i]; i++) {
28 		if (!strcmp (str, r_lib_types[i])) {
29 			return i;
30 		}
31 	}
32 	return -1;
33 }
34 
r_lib_dl_open(const char * libname)35 R_API void *r_lib_dl_open(const char *libname) {
36 	void *ret = NULL;
37 #if WANT_DYLINK
38 #if __UNIX__
39 	if (libname) {
40 		ret = dlopen (libname, RTLD_GLOBAL | RTLD_LAZY);
41 	} else {
42 		ret = dlopen (NULL, RTLD_NOW);
43 	}
44 	if (!ret && __has_debug) {
45 		eprintf ("r_lib_dl_open: error: %s (%s)\n", libname, dlerror ());
46 	}
47 #elif __WINDOWS__
48 	LPTSTR libname_;
49 	if (libname && *libname) {
50 		libname_ = r_sys_conv_utf8_to_win (libname);
51 	} else {
52 		libname_ = calloc (MAX_PATH, sizeof (TCHAR));
53 		if (!libname_) {
54 			R_LOG_ERROR ("lib/r_lib_dl_open: Failed to allocate memory.\n");
55 			return NULL;
56 		}
57 		if (!GetModuleFileName (NULL, libname_, MAX_PATH)) {
58 			libname_[0] = '\0';
59 		}
60 	}
61 	ret = LoadLibrary (libname_);
62 	free (libname_);
63 	if (!ret && __has_debug) {
64 		eprintf ("r_lib_dl_open: error: %s\n", libname);
65 	}
66 #endif
67 #endif
68 	return ret;
69 }
70 
r_lib_dl_sym(void * handler,const char * name)71 R_API void *r_lib_dl_sym(void *handler, const char *name) {
72 #if WANT_DYLINK
73 #if __UNIX__
74 	return dlsym (handler, name);
75 #elif __WINDOWS__
76 	return GetProcAddress (handler, name);
77 #else
78 	return NULL;
79 #endif
80 #else
81 	return NULL;
82 #endif
83 }
84 
r_lib_dl_close(void * handler)85 R_API int r_lib_dl_close(void *handler) {
86 #if __UNIX__
87 	return dlclose (handler);
88 #else
89 	return handler? 0: -1;
90 #endif
91 }
92 
r_lib_path(const char * libname)93 R_API char *r_lib_path(const char *libname) {
94 #if __WINDOWS__
95 	char *tmp = r_str_newf ("%s." R_LIB_EXT, libname);
96 	if (!tmp) {
97 		return NULL;
98 	}
99 	WCHAR *name = r_utf8_to_utf16 (tmp);
100 	free (tmp);
101 	WCHAR *path = NULL;
102 	if (!name) {
103 		goto err;
104 	}
105 
106 	int count;
107 	if (!(count = SearchPathW (NULL, name, NULL, 0, NULL, NULL))) {
108 		r_sys_perror ("SearchPath");
109 		goto err;
110 	}
111 	path = malloc (count * sizeof (WCHAR));
112 	if (!path) {
113 		goto err;
114 	}
115 	if (!(count = SearchPathW (NULL, name, NULL, count, path, NULL))) {
116 		R_FREE (path);
117 		r_sys_perror ("SearchPath");
118 		goto err;
119 	}
120 	tmp = r_utf16_to_utf8 (path);
121 	free (name);
122 	free (path);
123 	return tmp;
124 err:
125 	free (name);
126 	return NULL;
127 #else
128 #if __APPLE__
129 	char *env = r_sys_getenv ("DYLD_LIBRARY_PATH");
130 	env = r_str_append (env, ":/lib:/usr/lib:/usr/local/lib");
131 #elif __UNIX__
132 	char *env = r_sys_getenv ("LD_LIBRARY_PATH");
133 	env = r_str_append (env, ":/lib:/usr/lib:/usr/local/lib");
134 #endif
135 	if (!env) {
136 		env = strdup (".");
137 	}
138 	char *next, *path0 = env;
139 	do {
140 		next = strchr (path0, ':');
141 		if (next) {
142 			*next = 0;
143 		}
144 		char *libpath = r_str_newf ("%s/%s." R_LIB_EXT, path0, libname);
145 		if (r_file_exists (libpath)) {
146 			free (env);
147 			return libpath;
148 		}
149 		free (libpath);
150 		path0 = next + 1;
151 	} while (next);
152 	free (env);
153 	return NULL;
154 #endif
155 }
156 
r_lib_new(const char * symname,const char * symnamefunc)157 R_API RLib *r_lib_new(const char *symname, const char *symnamefunc) {
158 	RLib *lib = R_NEW (RLib);
159 	if (lib) {
160 		__has_debug = r_sys_getenv_asbool ("R2_DEBUG");
161 		lib->handlers = r_list_newf (free);
162 		lib->plugins = r_list_newf (free);
163 		lib->symname = strdup (symname? symname: R_LIB_SYMNAME);
164 		lib->symnamefunc = strdup (symnamefunc? symnamefunc: R_LIB_SYMFUNC);
165 	}
166 	return lib;
167 }
168 
r_lib_free(RLib * lib)169 R_API void r_lib_free(RLib *lib) {
170 	if (lib) {
171 		r_lib_close (lib, NULL);
172 		r_list_free (lib->handlers);
173 		r_list_free (lib->plugins);
174 		free (lib->symname);
175 		free (lib->symnamefunc);
176 		free (lib);
177 	}
178 }
179 
__lib_dl_check_filename(const char * file)180 static bool __lib_dl_check_filename(const char *file) {
181 	return r_str_endswith (file, "." R_LIB_EXT);
182 }
183 
r_lib_run_handler(RLib * lib,RLibPlugin * plugin,RLibStruct * symbol)184 R_API int r_lib_run_handler(RLib *lib, RLibPlugin *plugin, RLibStruct *symbol) {
185 	RLibHandler *h = plugin->handler;
186 	if (h && h->constructor) {
187 		IFDBG eprintf ("PLUGIN LOADED %p fcn %p\n", h, h->constructor);
188 		return h->constructor (plugin, h->user, symbol->data);
189 	}
190 	IFDBG eprintf ("Cannot find plugin constructor\n");
191 	return -1;
192 }
193 
r_lib_get_handler(RLib * lib,int type)194 R_API RLibHandler *r_lib_get_handler(RLib *lib, int type) {
195 	RLibHandler *h;
196 	RListIter *iter;
197 	r_list_foreach (lib->handlers, iter, h) {
198 		if (h->type == type) {
199 			return h;
200 		}
201 	}
202 	return NULL;
203 }
204 
r_lib_close(RLib * lib,const char * file)205 R_API int r_lib_close(RLib *lib, const char *file) {
206 	RLibPlugin *p;
207 	RListIter *iter, *iter2;
208 	r_list_foreach_safe (lib->plugins, iter, iter2, p) {
209 		if ((!file || !strcmp (file, p->file))) {
210 			int ret = 0;
211 			if (p->handler && p->handler->destructor) {
212 				ret = p->handler->destructor (p, p->handler->user, p->data);
213 			}
214 			if (p->free) {
215 				p->free (p->data);
216 			}
217 			free (p->file);
218 			r_list_delete (lib->plugins, iter);
219 			if (file != NULL) {
220 				return ret;
221 			}
222 		}
223 	}
224 	if (!file) {
225 		return 0;
226 	}
227 	// delete similar plugin name
228 	r_list_foreach (lib->plugins, iter, p) {
229 		if (strstr (p->file, file)) {
230 			int ret = 0;
231 			if (p->handler && p->handler->destructor) {
232 				ret = p->handler->destructor (p,
233 					p->handler->user, p->data);
234 			}
235 			eprintf ("Unloaded %s\n", p->file);
236 			free (p->file);
237 			r_list_delete (lib->plugins, iter);
238 			return ret;
239 		}
240 	}
241 	return -1;
242 }
243 
__already_loaded(RLib * lib,const char * file)244 static bool __already_loaded(RLib *lib, const char *file) {
245 	const char *fileName = r_str_rstr (file, R_SYS_DIR);
246 	RLibPlugin *p;
247 	RListIter *iter;
248 	if (fileName) {
249 		r_list_foreach (lib->plugins, iter, p) {
250 			const char *pFileName = r_str_rstr (p->file, R_SYS_DIR);
251 			if (pFileName && !strcmp (fileName, pFileName)) {
252 				return true;
253 			}
254 		}
255 	}
256 	return false;
257 }
258 
r_lib_open(RLib * lib,const char * file)259 R_API int r_lib_open(RLib *lib, const char *file) {
260 	/* ignored by filename */
261 	if (!__lib_dl_check_filename (file)) {
262 		eprintf ("Invalid library extension: %s\n", file);
263 		return -1;
264 	}
265 
266 	if (__already_loaded (lib, file)) {
267 		eprintf("Not loading library because it has already been loaded from somewhere else: '%s'\n", file);
268 		return -1;
269 	}
270 
271 	void *handler = r_lib_dl_open (file);
272 	if (!handler) {
273 		IFDBG eprintf ("Cannot open library: '%s'\n", file);
274 		return -1;
275 	}
276 
277 	RLibStructFunc strf = (RLibStructFunc) r_lib_dl_sym (handler, lib->symnamefunc);
278 	RLibStruct *stru = NULL;
279 	if (strf) {
280 		stru = strf ();
281 	}
282 	if (!stru) {
283 		stru = (RLibStruct *) r_lib_dl_sym (handler, lib->symname);
284 	}
285 	if (!stru) {
286 		IFDBG eprintf ("Cannot find symbol '%s' in library '%s'\n",
287 			lib->symname, file);
288 		r_lib_dl_close (handler);
289 		return -1;
290 	}
291 
292 	int res = r_lib_open_ptr (lib, file, handler, stru);
293 	if (strf) {
294 		free (stru);
295 	}
296 	return res;
297 }
298 
major_minor(const char * s)299 static char *major_minor(const char *s) {
300 	char *a = strdup (s);
301 	char *p = strchr (a, '.');
302 	if (p) {
303 		p = strchr (p + 1, '.');
304 		if (p) {
305 			*p = 0;
306 		}
307 	}
308 	return a;
309 }
310 
r_lib_open_ptr(RLib * lib,const char * file,void * handler,RLibStruct * stru)311 R_API int r_lib_open_ptr(RLib *lib, const char *file, void *handler, RLibStruct *stru) {
312 	r_return_val_if_fail (lib && file && stru, -1);
313 	if (stru->version) {
314 		char *mm0 = major_minor (stru->version);
315 		char *mm1 = major_minor (R2_VERSION);
316 		bool mismatch = strcmp (mm0, mm1);
317 		free (mm0);
318 		free (mm1);
319 		if (mismatch) {
320 			eprintf ("Module version mismatch %s (%s) vs (%s)\n",
321 				file, stru->version, R2_VERSION);
322 			if (stru->pkgname) {
323 				const char *dot = strchr (stru->version, '.');
324 				int major = atoi (stru->version);
325 				int minor = dot ? atoi (dot + 1) : 0;
326 				// The pkgname member was introduced in 4.2.0
327 				if (major > 4 || (major == 4 && minor >= 2)) {
328 					printf ("r2pm -ci %s\n", stru->pkgname);
329 				}
330 			}
331 			return -1;
332 		}
333 	}
334 	RLibPlugin *p = R_NEW0 (RLibPlugin);
335 	p->type = stru->type;
336 	p->data = stru->data;
337 	p->file = strdup (file);
338 	p->dl_handler = handler;
339 	p->handler = r_lib_get_handler (lib, p->type);
340 	p->free = stru->free;
341 
342 	int ret = r_lib_run_handler (lib, p, stru);
343 	if (ret == -1) {
344 		IFDBG eprintf ("Library handler has failed for '%s'\n", file);
345 		free (p->file);
346 		free (p);
347 		r_lib_dl_close (handler);
348 	} else {
349 		r_list_append (lib->plugins, p);
350 	}
351 
352 	return ret;
353 }
354 
r_lib_opendir(RLib * lib,const char * path)355 R_API bool r_lib_opendir(RLib *lib, const char *path) {
356 #if WANT_DYLINK
357 	r_return_val_if_fail (lib && path, false);
358 #if __WINDOWS__
359 	wchar_t file[1024];
360 	WIN32_FIND_DATAW dir;
361 	HANDLE fh;
362 	wchar_t directory[MAX_PATH];
363 	wchar_t *wcpath;
364 	char *wctocbuff;
365 #else
366 	char file[1024];
367 	struct dirent *de;
368 	DIR *dh;
369 #endif
370 #ifdef R2_LIBR_PLUGINS
371 	if (!path) {
372 		path = R2_LIBR_PLUGINS;
373 	}
374 #endif
375 	if (!path) {
376 		return false;
377 	}
378 #if __WINDOWS__
379 	wcpath = r_utf8_to_utf16 (path);
380 	if (!wcpath) {
381 		return false;
382 
383 	}
384 	swprintf (directory, _countof (directory), L"%ls\\*.*", wcpath);
385 	fh = FindFirstFileW (directory, &dir);
386 	if (fh == INVALID_HANDLE_VALUE) {
387 		IFDBG eprintf ("Cannot open directory %ls\n", wcpath);
388 		free (wcpath);
389 		return false;
390 	}
391 	do {
392 		swprintf (file, _countof (file), L"%ls/%ls", wcpath, dir.cFileName);
393 		wctocbuff = r_utf16_to_utf8 (file);
394 		if (wctocbuff) {
395 			if (__lib_dl_check_filename (wctocbuff)) {
396 				r_lib_open (lib, wctocbuff);
397 			} else {
398 				IFDBG eprintf ("Cannot open %ls\n", dir.cFileName);
399 			}
400 			free (wctocbuff);
401 		}
402 	} while (FindNextFileW (fh, &dir));
403 	FindClose (fh);
404 	free (wcpath);
405 #else
406 	dh = opendir (path);
407 	if (!dh) {
408 		IFDBG eprintf ("Cannot open directory '%s'\n", path);
409 		return false;
410 	}
411 	while ((de = (struct dirent *)readdir (dh))) {
412 		if (de->d_name[0] == '.' || strstr (de->d_name, ".dSYM")) {
413 			continue;
414 		}
415 		snprintf (file, sizeof (file), "%s/%s", path, de->d_name);
416 		if (__lib_dl_check_filename (file)) {
417 			IFDBG eprintf ("Loading %s\n", file);
418 			r_lib_open (lib, file);
419 		} else {
420 			IFDBG eprintf ("Cannot open %s\n", file);
421 		}
422 	}
423 	closedir (dh);
424 #endif
425 #endif
426 	return true;
427 }
428 
r_lib_add_handler(RLib * lib,int type,const char * desc,int (* cb)(RLibPlugin *,void *,void *),int (* dt)(RLibPlugin *,void *,void *),void * user)429 R_API bool r_lib_add_handler(RLib *lib,
430 	int type, const char *desc,
431 	int (*cb)(RLibPlugin *, void *, void *),  /* constructor */
432 	int (*dt)(RLibPlugin *, void *, void *),  /* destructor */
433 	void *user)
434 {
435 	RLibHandler *h;
436 	RListIter *iter;
437 	RLibHandler *handler = NULL;
438 
439 	r_list_foreach (lib->handlers, iter, h) {
440 		if (type == h->type) {
441 			IFDBG eprintf ("Redefining library handler constructor for %d\n", type);
442 			handler = h;
443 			break;
444 		}
445 	}
446 	if (!handler) {
447 		handler = R_NEW (RLibHandler);
448 		if (!handler) {
449 			return false;
450 		}
451 		handler->type = type;
452 		r_list_append (lib->handlers, handler);
453 	}
454 	strncpy (handler->desc, desc, sizeof (handler->desc)-1);
455 	handler->user = user;
456 	handler->constructor = cb;
457 	handler->destructor = dt;
458 
459 	return true;
460 }
461 
r_lib_del_handler(RLib * lib,int type)462 R_API bool r_lib_del_handler(RLib *lib, int type) {
463 	RLibHandler *h;
464 	RListIter *iter;
465 	// TODO: remove all handlers for that type? or only one?
466 	/* No _safe loop necessary because we return immediately after the delete. */
467 	r_list_foreach (lib->handlers, iter, h) {
468 		if (type == h->type) {
469 			r_list_delete (lib->handlers, iter);
470 			return true;
471 		}
472 	}
473 	return false;
474 }
475 
476 // TODO _list methods should not exist.. only used in ../core/cmd_log.c: r_lib_list (core->lib);
r_lib_list(RLib * lib)477 R_API void r_lib_list(RLib *lib) {
478 	RListIter *iter;
479 	RLibPlugin *p;
480 	r_list_foreach (lib->plugins, iter, p) {
481 		printf (" %5s %p %s \n", __lib_types_get (p->type),
482 			p->dl_handler, p->file);
483 	}
484 }
485