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