You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

687 lines
20 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2005 by Dominic Rath *
  3. * Dominic.Rath@gmx.de *
  4. * *
  5. * Copyright (C) 2007-2010 Øyvind Harboe *
  6. * oyvind.harboe@zylin.com *
  7. * *
  8. * Copyright (C) 2008 by Spencer Oliver *
  9. * spen@spen-soft.co.uk *
  10. * *
  11. * This program is free software; you can redistribute it and/or modify *
  12. * it under the terms of the GNU General Public License as published by *
  13. * the Free Software Foundation; either version 2 of the License, or *
  14. * (at your option) any later version. *
  15. * *
  16. * This program is distributed in the hope that it will be useful, *
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  19. * GNU General Public License for more details. *
  20. * *
  21. * You should have received a copy of the GNU General Public License *
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  23. ***************************************************************************/
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27. #include "telnet_server.h"
  28. #include <target/target_request.h>
  29. #include <helper/configuration.h>
  30. static char *telnet_port;
  31. static char *negotiate =
  32. "\xFF\xFB\x03" /* IAC WILL Suppress Go Ahead */
  33. "\xFF\xFB\x01" /* IAC WILL Echo */
  34. "\xFF\xFD\x03" /* IAC DO Suppress Go Ahead */
  35. "\xFF\xFE\x01"; /* IAC DON'T Echo */
  36. #define CTRL(c) (c - '@')
  37. #define TELNET_HISTORY ".openocd_history"
  38. /* The only way we can detect that the socket is closed is the first time
  39. * we write to it, we will fail. Subsequent write operations will
  40. * succeed. Shudder!
  41. */
  42. static int telnet_write(struct connection *connection, const void *data,
  43. int len)
  44. {
  45. struct telnet_connection *t_con = connection->priv;
  46. if (t_con->closed)
  47. return ERROR_SERVER_REMOTE_CLOSED;
  48. if (connection_write(connection, data, len) == len)
  49. return ERROR_OK;
  50. t_con->closed = 1;
  51. return ERROR_SERVER_REMOTE_CLOSED;
  52. }
  53. static int telnet_prompt(struct connection *connection)
  54. {
  55. struct telnet_connection *t_con = connection->priv;
  56. return telnet_write(connection, t_con->prompt, strlen(t_con->prompt));
  57. }
  58. static int telnet_outputline(struct connection *connection, const char *line)
  59. {
  60. int len;
  61. /* process lines in buffer */
  62. while (*line) {
  63. char *line_end = strchr(line, '\n');
  64. if (line_end)
  65. len = line_end-line;
  66. else
  67. len = strlen(line);
  68. telnet_write(connection, line, len);
  69. if (line_end) {
  70. telnet_write(connection, "\r\n", 2);
  71. line += len + 1;
  72. } else
  73. line += len;
  74. }
  75. return ERROR_OK;
  76. }
  77. static int telnet_output(struct command_context *cmd_ctx, const char *line)
  78. {
  79. struct connection *connection = cmd_ctx->output_handler_priv;
  80. return telnet_outputline(connection, line);
  81. }
  82. static void telnet_log_callback(void *priv, const char *file, unsigned line,
  83. const char *function, const char *string)
  84. {
  85. struct connection *connection = priv;
  86. struct telnet_connection *t_con = connection->priv;
  87. int i;
  88. /* if there is no prompt, simply output the message */
  89. if (t_con->line_cursor < 0) {
  90. telnet_outputline(connection, string);
  91. return;
  92. }
  93. /* clear the command line */
  94. for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16)
  95. telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i);
  96. for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16)
  97. telnet_write(connection, " ", i > 16 ? 16 : i);
  98. for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16)
  99. telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i);
  100. /* output the message */
  101. telnet_outputline(connection, string);
  102. /* put the command line to its previous state */
  103. telnet_prompt(connection);
  104. telnet_write(connection, t_con->line, t_con->line_size);
  105. for (i = t_con->line_size; i > t_con->line_cursor; i--)
  106. telnet_write(connection, "\b", 1);
  107. }
  108. static void telnet_load_history(struct telnet_connection *t_con)
  109. {
  110. FILE *histfp;
  111. char buffer[TELNET_BUFFER_SIZE];
  112. int i = 0;
  113. char *history = get_home_dir(TELNET_HISTORY);
  114. if (history == NULL) {
  115. LOG_INFO("unable to get user home directory, telnet history will be disabled");
  116. return;
  117. }
  118. histfp = fopen(history, "rb");
  119. if (histfp) {
  120. while (fgets(buffer, sizeof(buffer), histfp) != NULL) {
  121. char *p = strchr(buffer, '\n');
  122. if (p)
  123. *p = '\0';
  124. if (buffer[0] && i < TELNET_LINE_HISTORY_SIZE)
  125. t_con->history[i++] = strdup(buffer);
  126. }
  127. t_con->next_history = i;
  128. t_con->next_history %= TELNET_LINE_HISTORY_SIZE;
  129. /* try to set to last entry - 1, that way we skip over any exit/shutdown cmds */
  130. t_con->current_history = t_con->next_history > 0 ? i - 1 : 0;
  131. fclose(histfp);
  132. }
  133. free(history);
  134. }
  135. static void telnet_save_history(struct telnet_connection *t_con)
  136. {
  137. FILE *histfp;
  138. int i;
  139. int num;
  140. char *history = get_home_dir(TELNET_HISTORY);
  141. if (history == NULL) {
  142. LOG_INFO("unable to get user home directory, telnet history will be disabled");
  143. return;
  144. }
  145. histfp = fopen(history, "wb");
  146. if (histfp) {
  147. num = TELNET_LINE_HISTORY_SIZE;
  148. i = t_con->current_history + 1;
  149. i %= TELNET_LINE_HISTORY_SIZE;
  150. while (t_con->history[i] == NULL && num > 0) {
  151. i++;
  152. i %= TELNET_LINE_HISTORY_SIZE;
  153. num--;
  154. }
  155. if (num > 0) {
  156. for (; num > 0; num--) {
  157. fprintf(histfp, "%s\n", t_con->history[i]);
  158. i++;
  159. i %= TELNET_LINE_HISTORY_SIZE;
  160. }
  161. }
  162. fclose(histfp);
  163. }
  164. free(history);
  165. }
  166. static int telnet_new_connection(struct connection *connection)
  167. {
  168. struct telnet_connection *telnet_connection;
  169. struct telnet_service *telnet_service = connection->service->priv;
  170. int i;
  171. telnet_connection = malloc(sizeof(struct telnet_connection));
  172. if (!telnet_connection) {
  173. LOG_ERROR("Failed to allocate telnet connection.");
  174. return ERROR_FAIL;
  175. }
  176. connection->priv = telnet_connection;
  177. /* initialize telnet connection information */
  178. telnet_connection->closed = 0;
  179. telnet_connection->line_size = 0;
  180. telnet_connection->line_cursor = 0;
  181. telnet_connection->option_size = 0;
  182. telnet_connection->prompt = strdup("> ");
  183. telnet_connection->state = TELNET_STATE_DATA;
  184. /* output goes through telnet connection */
  185. command_set_output_handler(connection->cmd_ctx, telnet_output, connection);
  186. /* negotiate telnet options */
  187. telnet_write(connection, negotiate, strlen(negotiate));
  188. /* print connection banner */
  189. if (telnet_service->banner) {
  190. telnet_write(connection, telnet_service->banner, strlen(telnet_service->banner));
  191. telnet_write(connection, "\r\n", 2);
  192. }
  193. /* the prompt is always placed at the line beginning */
  194. telnet_write(connection, "\r", 1);
  195. telnet_prompt(connection);
  196. /* initialize history */
  197. for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
  198. telnet_connection->history[i] = NULL;
  199. telnet_connection->next_history = 0;
  200. telnet_connection->current_history = 0;
  201. telnet_load_history(telnet_connection);
  202. log_add_callback(telnet_log_callback, connection);
  203. return ERROR_OK;
  204. }
  205. static void telnet_clear_line(struct connection *connection,
  206. struct telnet_connection *t_con)
  207. {
  208. /* move to end of line */
  209. if (t_con->line_cursor < t_con->line_size)
  210. telnet_write(connection,
  211. t_con->line + t_con->line_cursor,
  212. t_con->line_size - t_con->line_cursor);
  213. /* backspace, overwrite with space, backspace */
  214. while (t_con->line_size > 0) {
  215. telnet_write(connection, "\b \b", 3);
  216. t_con->line_size--;
  217. }
  218. t_con->line_cursor = 0;
  219. }
  220. static void telnet_history_go(struct connection *connection, int idx)
  221. {
  222. struct telnet_connection *t_con = connection->priv;
  223. if (t_con->history[idx]) {
  224. telnet_clear_line(connection, t_con);
  225. t_con->line_size = strlen(t_con->history[idx]);
  226. t_con->line_cursor = t_con->line_size;
  227. memcpy(t_con->line, t_con->history[idx], t_con->line_size);
  228. telnet_write(connection, t_con->line, t_con->line_size);
  229. t_con->current_history = idx;
  230. }
  231. t_con->state = TELNET_STATE_DATA;
  232. }
  233. static void telnet_history_up(struct connection *connection)
  234. {
  235. struct telnet_connection *t_con = connection->priv;
  236. int last_history = (t_con->current_history > 0) ?
  237. t_con->current_history - 1 :
  238. TELNET_LINE_HISTORY_SIZE-1;
  239. telnet_history_go(connection, last_history);
  240. }
  241. static void telnet_history_down(struct connection *connection)
  242. {
  243. struct telnet_connection *t_con = connection->priv;
  244. int next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE;
  245. telnet_history_go(connection, next_history);
  246. }
  247. static int telnet_input(struct connection *connection)
  248. {
  249. int bytes_read;
  250. unsigned char buffer[TELNET_BUFFER_SIZE];
  251. unsigned char *buf_p;
  252. struct telnet_connection *t_con = connection->priv;
  253. struct command_context *command_context = connection->cmd_ctx;
  254. bytes_read = connection_read(connection, buffer, TELNET_BUFFER_SIZE);
  255. if (bytes_read == 0)
  256. return ERROR_SERVER_REMOTE_CLOSED;
  257. else if (bytes_read == -1) {
  258. LOG_ERROR("error during read: %s", strerror(errno));
  259. return ERROR_SERVER_REMOTE_CLOSED;
  260. }
  261. buf_p = buffer;
  262. while (bytes_read) {
  263. switch (t_con->state) {
  264. case TELNET_STATE_DATA:
  265. if (*buf_p == 0xff)
  266. t_con->state = TELNET_STATE_IAC;
  267. else {
  268. if (isprint(*buf_p)) { /* printable character */
  269. /* watch buffer size leaving one spare character for
  270. * string null termination */
  271. if (t_con->line_size == TELNET_LINE_MAX_SIZE-1) {
  272. /* output audible bell if buffer is full
  273. * "\a" does not work, at least on windows */
  274. telnet_write(connection, "\x07", 1);
  275. } else if (t_con->line_cursor == t_con->line_size) {
  276. telnet_write(connection, buf_p, 1);
  277. t_con->line[t_con->line_size++] = *buf_p;
  278. t_con->line_cursor++;
  279. } else {
  280. int i;
  281. memmove(t_con->line + t_con->line_cursor + 1,
  282. t_con->line + t_con->line_cursor,
  283. t_con->line_size - t_con->line_cursor);
  284. t_con->line[t_con->line_cursor] = *buf_p;
  285. t_con->line_size++;
  286. telnet_write(connection,
  287. t_con->line + t_con->line_cursor,
  288. t_con->line_size - t_con->line_cursor);
  289. t_con->line_cursor++;
  290. for (i = t_con->line_cursor; i < t_con->line_size; i++)
  291. telnet_write(connection, "\b", 1);
  292. }
  293. } else { /* non-printable */
  294. if (*buf_p == 0x1b) { /* escape */
  295. t_con->state = TELNET_STATE_ESCAPE;
  296. t_con->last_escape = '\x00';
  297. } else if ((*buf_p == 0xd) || (*buf_p == 0xa)) { /* CR/LF */
  298. int retval;
  299. /* skip over combinations with CR/LF and NUL characters */
  300. if ((bytes_read > 1) && ((*(buf_p + 1) == 0xa) ||
  301. (*(buf_p + 1) == 0xd))) {
  302. buf_p++;
  303. bytes_read--;
  304. }
  305. if ((bytes_read > 1) && (*(buf_p + 1) == 0)) {
  306. buf_p++;
  307. bytes_read--;
  308. }
  309. t_con->line[t_con->line_size] = 0;
  310. telnet_write(connection, "\r\n\x00", 3);
  311. if (strcmp(t_con->line, "history") == 0) {
  312. int i;
  313. for (i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) {
  314. /* the t_con->next_history line contains empty string
  315. * (unless NULL), thus it is not printed */
  316. char *history_line = t_con->history[(t_con->
  317. next_history + i) %
  318. TELNET_LINE_HISTORY_SIZE];
  319. if (history_line) {
  320. telnet_write(connection, history_line,
  321. strlen(history_line));
  322. telnet_write(connection, "\r\n\x00", 3);
  323. }
  324. }
  325. t_con->line_size = 0;
  326. t_con->line_cursor = 0;
  327. continue;
  328. }
  329. /* save only non-blank not repeating lines in the history */
  330. char *prev_line = t_con->history[(t_con->current_history > 0) ?
  331. t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1];
  332. if (*t_con->line && (prev_line == NULL ||
  333. strcmp(t_con->line, prev_line))) {
  334. /* if the history slot is already taken, free it */
  335. if (t_con->history[t_con->next_history])
  336. free(t_con->history[t_con->next_history]);
  337. /* add line to history */
  338. t_con->history[t_con->next_history] = strdup(t_con->line);
  339. /* wrap history at TELNET_LINE_HISTORY_SIZE */
  340. t_con->next_history = (t_con->next_history + 1) %
  341. TELNET_LINE_HISTORY_SIZE;
  342. /* current history line starts at the new entry */
  343. t_con->current_history =
  344. t_con->next_history;
  345. if (t_con->history[t_con->current_history])
  346. free(t_con->history[t_con->current_history]);
  347. t_con->history[t_con->current_history] = strdup("");
  348. }
  349. t_con->line_size = 0;
  350. /* to suppress prompt in log callback during command execution */
  351. t_con->line_cursor = -1;
  352. if (strcmp(t_con->line, "shutdown") == 0)
  353. telnet_save_history(t_con);
  354. retval = command_run_line(command_context, t_con->line);
  355. t_con->line_cursor = 0;
  356. if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
  357. return ERROR_SERVER_REMOTE_CLOSED;
  358. /* the prompt is always * placed at the line beginning */
  359. telnet_write(connection, "\r", 1);
  360. retval = telnet_prompt(connection);
  361. if (retval == ERROR_SERVER_REMOTE_CLOSED)
  362. return ERROR_SERVER_REMOTE_CLOSED;
  363. } else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) { /* delete character */
  364. if (t_con->line_cursor > 0) {
  365. if (t_con->line_cursor != t_con->line_size) {
  366. int i;
  367. telnet_write(connection, "\b", 1);
  368. t_con->line_cursor--;
  369. t_con->line_size--;
  370. memmove(t_con->line + t_con->line_cursor,
  371. t_con->line + t_con->line_cursor + 1,
  372. t_con->line_size -
  373. t_con->line_cursor);
  374. telnet_write(connection,
  375. t_con->line + t_con->line_cursor,
  376. t_con->line_size -
  377. t_con->line_cursor);
  378. telnet_write(connection, " \b", 2);
  379. for (i = t_con->line_cursor; i < t_con->line_size; i++)
  380. telnet_write(connection, "\b", 1);
  381. } else {
  382. t_con->line_size--;
  383. t_con->line_cursor--;
  384. /* back space: move the 'printer' head one char
  385. * back, overwrite with space, move back again */
  386. telnet_write(connection, "\b \b", 3);
  387. }
  388. }
  389. } else if (*buf_p == 0x15) /* clear line */
  390. telnet_clear_line(connection, t_con);
  391. else if (*buf_p == CTRL('B')) { /* cursor left */
  392. if (t_con->line_cursor > 0) {
  393. telnet_write(connection, "\b", 1);
  394. t_con->line_cursor--;
  395. }
  396. t_con->state = TELNET_STATE_DATA;
  397. } else if (*buf_p == CTRL('F')) { /* cursor right */
  398. if (t_con->line_cursor < t_con->line_size)
  399. telnet_write(connection, t_con->line + t_con->line_cursor++, 1);
  400. t_con->state = TELNET_STATE_DATA;
  401. } else if (*buf_p == CTRL('P')) /* cursor up */
  402. telnet_history_up(connection);
  403. else if (*buf_p == CTRL('N')) /* cursor down */
  404. telnet_history_down(connection);
  405. else
  406. LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p);
  407. }
  408. }
  409. break;
  410. case TELNET_STATE_IAC:
  411. switch (*buf_p) {
  412. case 0xfe:
  413. t_con->state = TELNET_STATE_DONT;
  414. break;
  415. case 0xfd:
  416. t_con->state = TELNET_STATE_DO;
  417. break;
  418. case 0xfc:
  419. t_con->state = TELNET_STATE_WONT;
  420. break;
  421. case 0xfb:
  422. t_con->state = TELNET_STATE_WILL;
  423. break;
  424. }
  425. break;
  426. case TELNET_STATE_SB:
  427. break;
  428. case TELNET_STATE_SE:
  429. break;
  430. case TELNET_STATE_WILL:
  431. case TELNET_STATE_WONT:
  432. case TELNET_STATE_DO:
  433. case TELNET_STATE_DONT:
  434. t_con->state = TELNET_STATE_DATA;
  435. break;
  436. case TELNET_STATE_ESCAPE:
  437. if (t_con->last_escape == '[') {
  438. if (*buf_p == 'D') { /* cursor left */
  439. if (t_con->line_cursor > 0) {
  440. telnet_write(connection, "\b", 1);
  441. t_con->line_cursor--;
  442. }
  443. t_con->state = TELNET_STATE_DATA;
  444. } else if (*buf_p == 'C') { /* cursor right */
  445. if (t_con->line_cursor < t_con->line_size)
  446. telnet_write(connection,
  447. t_con->line + t_con->line_cursor++, 1);
  448. t_con->state = TELNET_STATE_DATA;
  449. } else if (*buf_p == 'A') { /* cursor up */
  450. telnet_history_up(connection);
  451. } else if (*buf_p == 'B') { /* cursor down */
  452. telnet_history_down(connection);
  453. } else if (*buf_p == '3')
  454. t_con->last_escape = *buf_p;
  455. else
  456. t_con->state = TELNET_STATE_DATA;
  457. } else if (t_con->last_escape == '3') {
  458. /* Remove character */
  459. if (*buf_p == '~') {
  460. if (t_con->line_cursor < t_con->line_size) {
  461. int i;
  462. t_con->line_size--;
  463. /* remove char from line buffer */
  464. memmove(t_con->line + t_con->line_cursor,
  465. t_con->line + t_con->line_cursor + 1,
  466. t_con->line_size - t_con->line_cursor);
  467. /* print remainder of buffer */
  468. telnet_write(connection, t_con->line + t_con->line_cursor,
  469. t_con->line_size - t_con->line_cursor);
  470. /* overwrite last char with whitespace */
  471. telnet_write(connection, " \b", 2);
  472. /* move back to cursor position*/
  473. for (i = t_con->line_cursor; i < t_con->line_size; i++)
  474. telnet_write(connection, "\b", 1);
  475. }
  476. t_con->state = TELNET_STATE_DATA;
  477. } else
  478. t_con->state = TELNET_STATE_DATA;
  479. } else if (t_con->last_escape == '\x00') {
  480. if (*buf_p == '[')
  481. t_con->last_escape = *buf_p;
  482. else
  483. t_con->state = TELNET_STATE_DATA;
  484. } else {
  485. LOG_ERROR("BUG: unexpected value in t_con->last_escape");
  486. t_con->state = TELNET_STATE_DATA;
  487. }
  488. break;
  489. default:
  490. LOG_ERROR("unknown telnet state");
  491. exit(-1);
  492. }
  493. bytes_read--;
  494. buf_p++;
  495. }
  496. return ERROR_OK;
  497. }
  498. static int telnet_connection_closed(struct connection *connection)
  499. {
  500. struct telnet_connection *t_con = connection->priv;
  501. int i;
  502. log_remove_callback(telnet_log_callback, connection);
  503. if (t_con->prompt) {
  504. free(t_con->prompt);
  505. t_con->prompt = NULL;
  506. }
  507. /* save telnet history */
  508. telnet_save_history(t_con);
  509. for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++) {
  510. if (t_con->history[i]) {
  511. free(t_con->history[i]);
  512. t_con->history[i] = NULL;
  513. }
  514. }
  515. /* if this connection registered a debug-message receiver delete it */
  516. delete_debug_msg_receiver(connection->cmd_ctx, NULL);
  517. if (connection->priv) {
  518. free(connection->priv);
  519. connection->priv = NULL;
  520. } else
  521. LOG_ERROR("BUG: connection->priv == NULL");
  522. return ERROR_OK;
  523. }
  524. int telnet_init(char *banner)
  525. {
  526. int ret;
  527. struct telnet_service *telnet_service;
  528. if (strcmp(telnet_port, "disabled") == 0) {
  529. LOG_INFO("telnet server disabled");
  530. return ERROR_OK;
  531. }
  532. telnet_service = malloc(sizeof(struct telnet_service));
  533. if (!telnet_service) {
  534. LOG_ERROR("Failed to allocate telnet service.");
  535. return ERROR_FAIL;
  536. }
  537. telnet_service->banner = banner;
  538. ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED,
  539. telnet_new_connection, telnet_input, telnet_connection_closed,
  540. telnet_service);
  541. if (ret != ERROR_OK) {
  542. free(telnet_service);
  543. return ret;
  544. }
  545. return ERROR_OK;
  546. }
  547. /* daemon configuration command telnet_port */
  548. COMMAND_HANDLER(handle_telnet_port_command)
  549. {
  550. return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port);
  551. }
  552. COMMAND_HANDLER(handle_exit_command)
  553. {
  554. return ERROR_COMMAND_CLOSE_CONNECTION;
  555. }
  556. static const struct command_registration telnet_command_handlers[] = {
  557. {
  558. .name = "exit",
  559. .handler = handle_exit_command,
  560. .mode = COMMAND_EXEC,
  561. .usage = "",
  562. .help = "exit telnet session",
  563. },
  564. {
  565. .name = "telnet_port",
  566. .handler = handle_telnet_port_command,
  567. .mode = COMMAND_ANY,
  568. .help = "Specify port on which to listen "
  569. "for incoming telnet connections. "
  570. "Read help on 'gdb_port'.",
  571. .usage = "[port_num]",
  572. },
  573. COMMAND_REGISTRATION_DONE
  574. };
  575. int telnet_register_commands(struct command_context *cmd_ctx)
  576. {
  577. telnet_port = strdup("4444");
  578. return register_commands(cmd_ctx, NULL, telnet_command_handlers);
  579. }