1 /* radare - LGPL - Copyright 2009-2021 - pancake */
2 
3 #include <string.h>
4 #include "r_config.h"
5 #include "r_cons.h"
6 #include "r_core.h"
7 
8 // TODO #7967 help refactor: move to another place
9 static const char *help_msg_L[] = {
10 	"Usage:", "L[acio]", "[-name][ file]",
11 	"L",  "", "show this help",
12 	"L", " blah."R_LIB_EXT, "load plugin file",
13 	"L-", "duk", "unload core plugin by name",
14 	"Ll", "", "list lang plugins (same as #!)",
15 	"LL", "", "lock screen",
16 	"La", "", "list asm/anal plugins (aL, e asm.arch=" "??" ")",
17 	"Le", "", "list esil plugins",
18 	"Lc", "", "list core plugins",
19 	"Ld", "", "list debug plugins (same as dL)",
20 	"LD", "", "list supported decompilers (e cmd.pdc=?)",
21 	"Lm", "", "list fs plugins (same as mL)",
22 	"Lh", "", "list hash plugins (same as ph)",
23 	"Li", "", "list bin plugins (same as iL)",
24 	"Lo", "", "list io plugins (same as oL)",
25 	"Lp", "", "list parser plugins (e asm.parser=?)",
26 	NULL
27 };
28 
29 static const char *help_msg_T[] = {
30 	"Usage:", "T", "[-][ num|msg]",
31 	"T", "", "list all Text log messages",
32 	"T", " message", "add new log message",
33 	"T", " 123", "list log from 123",
34 	"T", " 10 3", "list 3 log messages starting from 10",
35 	"T*", "", "list in radare commands",
36 	"T-", "", "delete all logs",
37 	"T-", " 123", "delete logs before 123",
38 	"Tl", "", "get last log message id",
39 	"Tj", "", "list in json format",
40 	"Tm", " [idx]", "display log messages without index",
41 	"Ts", "", "list files in current directory (see pwd, cd)",
42 	"TT", "", "enter into the text log chat console",
43 	"T=", "[.]", "Pull logs from remote r2 instance specified by http.sync",
44 	"T=&", "", "Start background thread syncing with the remote server",
45 	NULL
46 };
47 
48 // TODO #7967 help refactor: move L to another place
cmd_log_init(RCore * core,RCmdDesc * parent)49 static void cmd_log_init(RCore *core, RCmdDesc *parent) {
50 	DEFINE_CMD_DESCRIPTOR (core, L);
51 	DEFINE_CMD_DESCRIPTOR (core, T);
52 }
53 
screenlock(RCore * core)54 static void screenlock(RCore *core) {
55 	//  char *pass = r_cons_input ("Enter new password: ");
56 	char *pass = r_cons_password (Color_INVERT "Enter new password:"Color_INVERT_RESET);
57 	if (!pass || !*pass) {
58 		return;
59 	}
60 	char *again = r_cons_password (Color_INVERT "Type it again:"Color_INVERT_RESET);
61 	if (!again || !*again) {
62 		free (pass);
63 		return;
64 	}
65 	if (strcmp (pass, again)) {
66 		eprintf ("Password mismatch!\n");
67 		free (pass);
68 		free (again);
69 		return;
70 	}
71 	bool running = true;
72 	r_cons_clear_buffer ();
73 	ut64 begin = r_time_now ();
74 	ut64 last = UT64_MAX;
75 	int tries = 0;
76 	do {
77 		r_cons_clear00 ();
78 		r_cons_printf ("Retries: %d\n", tries);
79 		r_cons_printf ("Locked ts: %s\n", r_time_to_string (begin));
80 		if (last != UT64_MAX) {
81 			r_cons_printf ("Last try: %s\n", r_time_to_string (last));
82 		}
83 		r_cons_newline ();
84 		r_cons_flush ();
85 		char *msg = r_cons_password ("radare2 password: ");
86 		if (msg && !strcmp (msg, pass)) {
87 			running = false;
88 		} else {
89 			eprintf ("\nInvalid password.\n");
90 			last = r_time_now ();
91 			tries++;
92 		}
93 		free (msg);
94 		int n = r_num_rand (10) + 1;
95 		r_sys_usleep (n * 100000);
96 	} while (running);
97 	r_cons_set_cup (true);
98 	free (pass);
99 	eprintf ("Unlocked!\n");
100 }
101 
textlog_chat(RCore * core)102 static int textlog_chat(RCore *core) {
103 	char prompt[64];
104 	char buf[1024];
105 	int lastmsg = 0;
106 	const char *me = r_config_get (core->config, "cfg.user");
107 	char msg[2048];
108 
109 	eprintf ("Type '/help' for commands:\n");
110 	snprintf (prompt, sizeof (prompt) - 1, "[%s]> ", me);
111 	r_line_set_prompt (prompt);
112 	for (;;) {
113 		r_core_log_list (core, lastmsg, 0, 0);
114 		lastmsg = core->log->last;
115 		if (r_cons_fgets (buf, sizeof (buf), 0, NULL) < 0) {
116 			return 1;
117 		}
118 		if (!*buf) {
119 			continue;
120 		}
121 		if (!strcmp (buf, "/help")) {
122 			eprintf ("/quit           quit the chat (same as ^D)\n");
123 			eprintf ("/name <nick>    set cfg.user name\n");
124 			eprintf ("/log            show full log\n");
125 			eprintf ("/clear          clear text log messages\n");
126 		} else if (!strncmp (buf, "/name ", 6)) {
127 			snprintf (msg, sizeof (msg) - 1, "* '%s' is now known as '%s'", me, buf + 6);
128 			r_core_log_add (core, msg);
129 			r_config_set (core->config, "cfg.user", buf + 6);
130 			me = r_config_get (core->config, "cfg.user");
131 			snprintf (prompt, sizeof (prompt) - 1, "[%s]> ", me);
132 			r_line_set_prompt (prompt);
133 			return 0;
134 		} else if (!strcmp (buf, "/log")) {
135 			r_core_log_list (core, 0, 0, 0);
136 			return 0;
137 		} else if (!strcmp (buf, "/clear")) {
138 			// r_core_log_del (core, 0);
139 			r_core_cmd0 (core, "T-");
140 			return 0;
141 		} else if (!strcmp (buf, "/quit")) {
142 			return 0;
143 		} else if (*buf == '/') {
144 			eprintf ("Unknown command: %s\n", buf);
145 		} else {
146 			snprintf (msg, sizeof (msg), "[%s] %s", me, buf);
147 			r_core_log_add (core, msg);
148 		}
149 	}
150 	return 1;
151 }
152 
getIndexFromLogString(const char * s)153 static int getIndexFromLogString(const char *s) {
154 	int len = strlen (s);
155 	const char *m = s + len;
156 	int nlctr = 2;
157 	const char *nl = NULL;
158 	while (m > s) {
159 		if (*m == '\n') {
160 			nl = m;
161 			if (--nlctr < 1) {
162 				return atoi (m + 1);
163 			}
164 		}
165 		m--;
166 	}
167 		return atoi (nl?nl + 1: s);
168 	return -1;
169 }
170 
expr2cmd(RCoreLog * log,const char * line)171 static char *expr2cmd (RCoreLog *log, const char *line) {
172 	if (!line || !*line) {
173 		return NULL;
174 	}
175 	line++;
176 	if (!strncmp (line, "add-comment", 11)) {
177 		line += 11;
178 		if (*line == ' ') {
179 			char *sp = strchr (line + 1, ' ');
180 			if (sp) {
181 				char *msg = sp + 1;
182 				ut64 addr = r_num_get (NULL, line);
183 				return r_str_newf ("CCu base64:%s @ 0x%"PFMT64x"\n", msg, addr);
184 			}
185 		}
186 		eprintf ("add-comment parsing error\n");
187 	}
188 	if (!strncmp (line, "del-comment", 11)) {
189 		if (line[11] == ' ') {
190 			return r_str_newf ("CC-%s\n", line + 12);
191 		}
192 		eprintf ("add-comment parsing error\n");
193 	}
194 	return NULL;
195 }
196 
log_callback_r2(RCore * core,int count,const char * line)197 static int log_callback_r2 (RCore *core, int count, const char *line) {
198 	if (*line == ':') {
199 		char *cmd = expr2cmd (core->log, line);
200 		if (cmd) {
201 			r_cons_printf ("%s\n", cmd);
202 			r_core_cmd (core, cmd, 0);
203 			free (cmd);
204 		}
205 	}
206 	return 0;
207 }
208 
log_callback_all(RCore * log,int count,const char * line)209 static int log_callback_all (RCore *log, int count, const char *line) {
210 	r_cons_printf ("%d %s\n", count, line);
211 	return 0;
212 }
213 
cmd_log(void * data,const char * input)214 static int cmd_log(void *data, const char *input) {
215 	RCore *core = (RCore *) data;
216 	const char *arg, *input2;
217 	int n, n2;
218 
219 	if (!input) {
220 		return 1;
221 	}
222 
223 	input2 = (input && *input)? input + 1: "";
224 	arg = strchr (input2, ' ');
225 	n = atoi (input2);
226 	n2 = arg? atoi (arg + 1): 0;
227 
228 	switch (*input) {
229 	case 'e': // "Te" shell: less
230 		{
231 			char *p = strchr (input, ' ');
232 			if (p) {
233 				char *b = r_file_slurp (p + 1, NULL);
234 				if (b) {
235 					r_cons_less_str (b, NULL);
236 					free (b);
237 				} else {
238 					eprintf ("File not found\n");
239 				}
240 			} else {
241 				eprintf ("Usage: less [filename]\n");
242 			}
243 		}
244 		break;
245 	case 'l': // "Tl"
246 		r_cons_printf ("%d\n", core->log->last - 1);
247 		break;
248 	case '-': //  "T-"
249 		r_core_log_del (core, n);
250 		break;
251 	case '?': // "T?"
252 		r_core_cmd_help (core, help_msg_T);
253 		break;
254 	case 'T': // "TT" Ts ? as ms?
255 		if (r_cons_is_interactive ()) {
256 			textlog_chat (core);
257 		} else {
258 			eprintf ("Only available when the screen is interactive\n");
259 		}
260 		break;
261 	case '=': // "T="
262 		if (input[1] == '&') { //  "T=&"
263 			if (input[2] == '&') { // "T=&&"
264 				r_cons_break_push (NULL, NULL);
265 				while (!r_cons_is_breaked ()) {
266 					r_core_cmd0 (core, "T=");
267 					void *bed = r_cons_sleep_begin();
268 					r_sys_sleep (1);
269 					r_cons_sleep_end (bed);
270 				}
271 				r_cons_break_pop ();
272 			} else {
273 				// TODO: Sucks that we can't enqueue functions, only commands
274 				eprintf ("Background thread syncing with http.sync started.\n");
275 				RCoreTask *task = r_core_task_new (core, true, "T=&&", NULL, core);
276 				r_core_task_enqueue (&core->tasks, task);
277 			}
278 		} else {
279 			if (atoi (input + 1) > 0 || (input[1] == '0')) {
280 				core->sync_index = 0;
281 			} else {
282 				RCoreLogCallback log_callback = (input[1] == '*')
283 					? log_callback_all: log_callback_r2;
284 				char *res = r_core_log_get (core, core->sync_index);
285 				if (res) {
286 					int idx = getIndexFromLogString (res);
287 					if (idx != -1) {
288 						core->sync_index = idx + 1;
289 					}
290 					r_core_log_run (core, res, log_callback);
291 					free (res);
292 				} else {
293 					r_cons_printf ("Please check e http.sync\n");
294 				}
295 			}
296 		}
297 		break;
298 	case ' ': // "T "
299 		if (n > 0 || *input == '0') {
300 			r_core_log_list (core, n, n2, *input);
301 		} else {
302 			r_core_log_add (core, input + 1);
303 		}
304 		break;
305 	case 'm': // "Tm"
306 		if (n > 0) {
307 			r_core_log_list (core, n, 1, 't');
308 		} else {
309 			r_core_log_list (core, n, 0, 't');
310 		}
311 		break;
312 	case 'j': // "Tj"
313 	case '*':
314 	case '\0':
315 		r_core_log_list (core, n, n2, *input);
316 		break;
317 	}
318 	return 0;
319 }
320 
cmd_plugins(void * data,const char * input)321 static int cmd_plugins(void *data, const char *input) {
322 	RCore *core = (RCore *) data;
323 	switch (input[0]) {
324 	case 0:
325 		r_core_cmd_help (core, help_msg_L);
326 		// return r_core_cmd0 (core, "Lc");
327 		break;
328 	case '-':
329 		r_lib_close (core->lib, r_str_trim_head_ro (input + 1));
330 		break;
331 	case ' ':
332 		r_lib_open (core->lib, r_str_trim_head_ro (input + 1));
333 		break;
334 	case '?':
335 		r_core_cmd_help (core, help_msg_L);
336 		break;
337 	case 'm': // "Lm"
338 		r_core_cmdf (core, "mL%s", input + 1);
339 		break;
340 	case 'e': // "Le"
341 		r_core_cmdf (core, "aeL%s", input + 1);
342 		break;
343 	case 'd': // "Ld"
344 		r_core_cmdf (core, "dL%s", input + 1);
345 		break;
346 	case 'h': // "Lh"
347 		r_core_cmd0 (core, "ph"); // rahash2 -L is more verbose
348 		break;
349 	case 'a': // "La"
350 		r_core_cmd0 (core, "e asm.arch=??");
351 		break;
352 	case 'p': // "Lp"
353 		r_core_cmd0 (core, "e asm.parser=?");
354 		break;
355 	case 'D': // "LD"
356 		if (input[1] == ' ') {
357 			r_core_cmdf (core, "e cmd.pdc=%s", r_str_trim_head_ro (input + 2));
358 		} else {
359 			r_core_cmd0 (core, "e cmd.pdc=?");
360 		}
361 		break;
362 	case 'l': // "Ll"
363 		r_core_cmd0 (core, "#!");
364 		break;
365 	case 'L': // "LL"
366 		screenlock (core);
367 		break;
368 	case 'o': // "Lo"
369 	case 'i': // "Li"
370 		r_core_cmdf (core, "%cL", input[0]);
371 		break;
372 	case 'c': { // "Lc"
373 		RListIter *iter;
374 		RCorePlugin *cp;
375 		switch (input[1]) {
376 		case 'j': {
377 			PJ *pj = r_core_pj_new (core);
378 			if (!pj) {
379 				return 1;
380 			}
381 			pj_a (pj);
382 			r_list_foreach (core->rcmd->plist, iter, cp) {
383 				pj_o (pj);
384 				pj_ks (pj, "Name", cp->name);
385 				pj_ks (pj, "Description", cp->desc);
386 				pj_end (pj);
387 			}
388 			pj_end (pj);
389 			r_cons_println (pj_string (pj));
390 			pj_free (pj);
391 			break;
392 			}
393 		case 0:
394 			r_lib_list (core->lib);
395 			r_list_foreach (core->rcmd->plist, iter, cp) {
396 				r_cons_printf ("%s: %s\n", cp->name, cp->desc);
397 			}
398 			break;
399 		default:
400 			eprintf ("oops\n");
401 			break;
402 		}
403 		}
404 		break;
405 	}
406 	return 0;
407 }
408