blob: 788c7fd6f5f71e13746802eed066f27c98014005 [file] [log] [blame]
Harald Welte955049f2009-03-10 12:16:51 +00001
2#include <stdio.h>
3#include <stdarg.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <string.h>
7#include <errno.h>
8#include <ctype.h>
9#include <termios.h>
10
11#include <sys/utsname.h>
12#include <sys/param.h>
13
14#include <arpa/telnet.h>
15
16#include "cardshell.h"
17#include <vty/vty.h>
18#include <vty/command.h>
19#include <vty/buffer.h>
Harald Welte2477d932009-08-07 00:32:41 +020020#include <openbsc/talloc.h>
Harald Welte955049f2009-03-10 12:16:51 +000021
Holger Hans Peter Freyther6d30a352009-08-10 08:10:26 +020022/* our callback, located in telnet_interface.c */
23void vty_event(enum event event, int sock, struct vty *vty);
24
Harald Welte955049f2009-03-10 12:16:51 +000025extern struct host host;
26
27/* Vector which store each vty structure. */
28static vector vtyvec;
29
30vector Vvty_serv_thread;
31
32char *vty_cwd = NULL;
33
34/* Configure lock. */
35static int vty_config;
36
37static int no_password_check = 1;
38
Harald Welte0224e4d2009-08-07 13:25:41 +020039void *tall_vty_ctx;
Harald Welte2477d932009-08-07 00:32:41 +020040
Harald Welte955049f2009-03-10 12:16:51 +000041static void vty_clear_buf(struct vty *vty)
42{
43 memset(vty->buf, 0, vty->max);
44}
45
46/* Allocate new vty struct. */
47struct vty *vty_new()
48{
Harald Welte2477d932009-08-07 00:32:41 +020049 struct vty *new = talloc_zero(tall_vty_ctx, struct vty);
Harald Welte955049f2009-03-10 12:16:51 +000050
51 if (!new)
52 goto out;
53
54 new->obuf = buffer_new(0); /* Use default buffer size. */
55 if (!new->obuf)
56 goto out_new;
Harald Welte2477d932009-08-07 00:32:41 +020057 new->buf = _talloc_zero(tall_vty_ctx, VTY_BUFSIZ, "vty_new->buf");
Harald Welte955049f2009-03-10 12:16:51 +000058 if (!new->buf)
59 goto out_obuf;
60
61 new->max = VTY_BUFSIZ;
62
63 return new;
64
65out_obuf:
Harald Welte2477d932009-08-07 00:32:41 +020066 buffer_free(new->obuf);
Harald Welte955049f2009-03-10 12:16:51 +000067out_new:
Harald Welte2477d932009-08-07 00:32:41 +020068 talloc_free(new);
Harald Welte955049f2009-03-10 12:16:51 +000069 new = NULL;
70out:
71 return new;
72}
73
74/* Authentication of vty */
75static void vty_auth(struct vty *vty, char *buf)
76{
77 char *passwd = NULL;
78 enum node_type next_node = 0;
79 int fail;
80 char *crypt(const char *, const char *);
81
82 switch (vty->node) {
83 case AUTH_NODE:
Harald Welted6cab812009-05-21 07:31:48 +000084#ifdef VTY_CRYPT_PW
Harald Welte955049f2009-03-10 12:16:51 +000085 if (host.encrypt)
86 passwd = host.password_encrypt;
87 else
Harald Welted6cab812009-05-21 07:31:48 +000088#endif
Harald Welte955049f2009-03-10 12:16:51 +000089 passwd = host.password;
90 if (host.advanced)
91 next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
92 else
93 next_node = VIEW_NODE;
94 break;
95 case AUTH_ENABLE_NODE:
Harald Welted6cab812009-05-21 07:31:48 +000096#ifdef VTY_CRYPT_PW
Harald Welte955049f2009-03-10 12:16:51 +000097 if (host.encrypt)
98 passwd = host.enable_encrypt;
99 else
Harald Welted6cab812009-05-21 07:31:48 +0000100#endif
Harald Welte955049f2009-03-10 12:16:51 +0000101 passwd = host.enable;
102 next_node = ENABLE_NODE;
103 break;
104 }
105
106 if (passwd) {
Harald Welted6cab812009-05-21 07:31:48 +0000107#ifdef VTY_CRYPT_PW
Harald Welte955049f2009-03-10 12:16:51 +0000108 if (host.encrypt)
109 fail = strcmp(crypt(buf, passwd), passwd);
110 else
Harald Welted6cab812009-05-21 07:31:48 +0000111#endif
Harald Welte955049f2009-03-10 12:16:51 +0000112 fail = strcmp(buf, passwd);
113 } else
114 fail = 1;
115
116 if (!fail) {
117 vty->fail = 0;
118 vty->node = next_node; /* Success ! */
119 } else {
120 vty->fail++;
121 if (vty->fail >= 3) {
122 if (vty->node == AUTH_NODE) {
123 vty_out(vty,
124 "%% Bad passwords, too many failures!%s",
125 VTY_NEWLINE);
126 vty->status = VTY_CLOSE;
127 } else {
128 /* AUTH_ENABLE_NODE */
129 vty->fail = 0;
130 vty_out(vty,
131 "%% Bad enable passwords, too many failures!%s",
132 VTY_NEWLINE);
133 vty->node = VIEW_NODE;
134 }
135 }
136 }
137}
138
139/* Close vty interface. */
140void vty_close(struct vty *vty)
141{
142 int i;
143
Harald Welte2477d932009-08-07 00:32:41 +0200144 if (vty->obuf) {
145 /* Flush buffer. */
146 buffer_flush_all(vty->obuf, vty->fd);
Harald Welte955049f2009-03-10 12:16:51 +0000147
Harald Welte2477d932009-08-07 00:32:41 +0200148 /* Free input buffer. */
149 buffer_free(vty->obuf);
150 vty->obuf = NULL;
151 }
Harald Welte955049f2009-03-10 12:16:51 +0000152
153 /* Free command history. */
154 for (i = 0; i < VTY_MAXHIST; i++)
155 if (vty->hist[i])
Harald Welte2477d932009-08-07 00:32:41 +0200156 talloc_free(vty->hist[i]);
Harald Welte955049f2009-03-10 12:16:51 +0000157
158 /* Unset vector. */
159 vector_unset(vtyvec, vty->fd);
160
161 /* Close socket. */
162 if (vty->fd > 0)
163 close(vty->fd);
164
Harald Welte2477d932009-08-07 00:32:41 +0200165 if (vty->buf) {
166 talloc_free(vty->buf);
167 vty->buf = NULL;
168 }
Harald Welte955049f2009-03-10 12:16:51 +0000169
170 /* Check configure. */
171 vty_config_unlock(vty);
172
Harald Welte678bdea2009-06-26 19:42:14 +0200173 /* FIXME: memory leak. We need to call telnet_close_client() but don't
174 * have bfd */
Harald Welte2477d932009-08-07 00:32:41 +0200175 vty_event(VTY_CLOSED, vty->fd, vty);
176
177 /* OK free vty. */
178 talloc_free(vty);
Harald Welte955049f2009-03-10 12:16:51 +0000179}
180
181int vty_shell(struct vty *vty)
182{
183 return vty->type == VTY_SHELL ? 1 : 0;
184}
185
186
187/* VTY standard output function. */
188int vty_out(struct vty *vty, const char *format, ...)
189{
190 va_list args;
191 int len = 0;
192 int size = 1024;
193 char buf[1024];
194 char *p = NULL;
195
196 if (vty_shell(vty)) {
197 va_start(args, format);
198 vprintf(format, args);
199 va_end(args);
200 } else {
201 /* Try to write to initial buffer. */
202 va_start(args, format);
203 len = vsnprintf(buf, sizeof buf, format, args);
204 va_end(args);
205
206 /* Initial buffer is not enough. */
207 if (len < 0 || len >= size) {
208 while (1) {
209 if (len > -1)
210 size = len + 1;
211 else
212 size = size * 2;
213
Harald Welte2477d932009-08-07 00:32:41 +0200214 p = talloc_realloc_size(tall_vty_ctx, p, size);
Harald Welte955049f2009-03-10 12:16:51 +0000215 if (!p)
216 return -1;
217
218 va_start(args, format);
219 len = vsnprintf(p, size, format, args);
220 va_end(args);
221
222 if (len > -1 && len < size)
223 break;
224 }
225 }
226
227 /* When initial buffer is enough to store all output. */
228 if (!p)
229 p = buf;
230
231 /* Pointer p must point out buffer. */
232 buffer_put(vty->obuf, (u_char *) p, len);
233
234 /* If p is not different with buf, it is allocated buffer. */
235 if (p != buf)
Harald Welte2477d932009-08-07 00:32:41 +0200236 talloc_free(p);
Harald Welte955049f2009-03-10 12:16:51 +0000237 }
238
Harald Welte7cb7a732009-12-17 21:32:19 +0100239 vty_event(VTY_WRITE, vty->fd, vty);
240
Harald Welte955049f2009-03-10 12:16:51 +0000241 return len;
242}
243
244int vty_out_newline(struct vty *vty)
245{
246 char *p = vty_newline(vty);
247 buffer_put(vty->obuf, p, strlen(p));
Harald Weltec63e51d2009-03-10 19:46:16 +0000248 return 0;
Harald Welte955049f2009-03-10 12:16:51 +0000249}
250
251int vty_config_lock(struct vty *vty)
252{
253 if (vty_config == 0) {
254 vty->config = 1;
255 vty_config = 1;
256 }
257 return vty->config;
258}
259
260int vty_config_unlock(struct vty *vty)
261{
262 if (vty_config == 1 && vty->config == 1) {
263 vty->config = 0;
264 vty_config = 0;
265 }
266 return vty->config;
267}
268
Harald Welte955049f2009-03-10 12:16:51 +0000269/* Say hello to vty interface. */
270void vty_hello(struct vty *vty)
271{
272 if (host.motdfile) {
273 FILE *f;
274 char buf[4096];
275
276 f = fopen(host.motdfile, "r");
277 if (f) {
278 while (fgets(buf, sizeof(buf), f)) {
279 char *s;
280 /* work backwards to ignore trailling isspace() */
281 for (s = buf + strlen(buf);
282 (s > buf) && isspace(*(s - 1)); s--) ;
283 *s = '\0';
284 vty_out(vty, "%s%s", buf, VTY_NEWLINE);
285 }
286 fclose(f);
287 } else
288 vty_out(vty, "MOTD file not found%s", VTY_NEWLINE);
289 } else if (host.motd)
Holger Hans Peter Freytherc423a122009-08-10 08:10:11 +0200290 vty_out(vty, "%s", host.motd);
Harald Welte955049f2009-03-10 12:16:51 +0000291}
292
293/* Put out prompt and wait input from user. */
294static void vty_prompt(struct vty *vty)
295{
296 struct utsname names;
297 const char *hostname;
298
299 if (vty->type == VTY_TERM) {
300 hostname = host.name;
301 if (!hostname) {
302 uname(&names);
303 hostname = names.nodename;
304 }
305 vty_out(vty, cmd_prompt(vty->node), hostname);
306 }
307}
308
309/* Command execution over the vty interface. */
310static int vty_command(struct vty *vty, char *buf)
311{
312 int ret;
313 vector vline;
314
315 /* Split readline string up into the vector */
316 vline = cmd_make_strvec(buf);
317
318 if (vline == NULL)
319 return CMD_SUCCESS;
320
321 ret = cmd_execute_command(vline, vty, NULL, 0);
322 if (ret != CMD_SUCCESS)
323 switch (ret) {
324 case CMD_WARNING:
325 if (vty->type == VTY_FILE)
326 vty_out(vty, "Warning...%s", VTY_NEWLINE);
327 break;
328 case CMD_ERR_AMBIGUOUS:
329 vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
330 break;
331 case CMD_ERR_NO_MATCH:
332 vty_out(vty, "%% Unknown command.%s", VTY_NEWLINE);
333 break;
334 case CMD_ERR_INCOMPLETE:
335 vty_out(vty, "%% Command incomplete.%s", VTY_NEWLINE);
336 break;
337 }
338 cmd_free_strvec(vline);
339
340 return ret;
341}
342
343static const char telnet_backward_char = 0x08;
344static const char telnet_space_char = ' ';
345
346/* Basic function to write buffer to vty. */
347static void vty_write(struct vty *vty, const char *buf, size_t nbytes)
348{
349 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
350 return;
351
352 /* Should we do buffering here ? And make vty_flush (vty) ? */
353 buffer_put(vty->obuf, buf, nbytes);
354}
355
356/* Ensure length of input buffer. Is buffer is short, double it. */
357static void vty_ensure(struct vty *vty, int length)
358{
359 if (vty->max <= length) {
360 vty->max *= 2;
Harald Welte2477d932009-08-07 00:32:41 +0200361 vty->buf = talloc_realloc_size(tall_vty_ctx, vty->buf, vty->max);
Harald Welte955049f2009-03-10 12:16:51 +0000362 // FIXME: check return
363 }
364}
365
366/* Basic function to insert character into vty. */
367static void vty_self_insert(struct vty *vty, char c)
368{
369 int i;
370 int length;
371
372 vty_ensure(vty, vty->length + 1);
373 length = vty->length - vty->cp;
374 memmove(&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
375 vty->buf[vty->cp] = c;
376
377 vty_write(vty, &vty->buf[vty->cp], length + 1);
378 for (i = 0; i < length; i++)
379 vty_write(vty, &telnet_backward_char, 1);
380
381 vty->cp++;
382 vty->length++;
383}
384
385/* Self insert character 'c' in overwrite mode. */
386static void vty_self_insert_overwrite(struct vty *vty, char c)
387{
388 vty_ensure(vty, vty->length + 1);
389 vty->buf[vty->cp++] = c;
390
391 if (vty->cp > vty->length)
392 vty->length++;
393
394 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
395 return;
396
397 vty_write(vty, &c, 1);
398}
399
400/* Insert a word into vty interface with overwrite mode. */
401static void vty_insert_word_overwrite(struct vty *vty, char *str)
402{
403 int len = strlen(str);
404 vty_write(vty, str, len);
405 strcpy(&vty->buf[vty->cp], str);
406 vty->cp += len;
407 vty->length = vty->cp;
408}
409
410/* Forward character. */
411static void vty_forward_char(struct vty *vty)
412{
413 if (vty->cp < vty->length) {
414 vty_write(vty, &vty->buf[vty->cp], 1);
415 vty->cp++;
416 }
417}
418
419/* Backward character. */
420static void vty_backward_char(struct vty *vty)
421{
422 if (vty->cp > 0) {
423 vty->cp--;
424 vty_write(vty, &telnet_backward_char, 1);
425 }
426}
427
428/* Move to the beginning of the line. */
429static void vty_beginning_of_line(struct vty *vty)
430{
431 while (vty->cp)
432 vty_backward_char(vty);
433}
434
435/* Move to the end of the line. */
436static void vty_end_of_line(struct vty *vty)
437{
438 while (vty->cp < vty->length)
439 vty_forward_char(vty);
440}
441
442/* Add current command line to the history buffer. */
443static void vty_hist_add(struct vty *vty)
444{
445 int index;
446
447 if (vty->length == 0)
448 return;
449
450 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
451
452 /* Ignore the same string as previous one. */
453 if (vty->hist[index])
454 if (strcmp(vty->buf, vty->hist[index]) == 0) {
455 vty->hp = vty->hindex;
456 return;
457 }
458
459 /* Insert history entry. */
460 if (vty->hist[vty->hindex])
Harald Welte2477d932009-08-07 00:32:41 +0200461 talloc_free(vty->hist[vty->hindex]);
462 vty->hist[vty->hindex] = talloc_strdup(tall_vty_ctx, vty->buf);
Harald Welte955049f2009-03-10 12:16:51 +0000463
464 /* History index rotation. */
465 vty->hindex++;
466 if (vty->hindex == VTY_MAXHIST)
467 vty->hindex = 0;
468
469 vty->hp = vty->hindex;
470}
471
472/* Get telnet window size. */
473static int
474vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
475{
476#ifdef TELNET_OPTION_DEBUG
477 int i;
478
479 for (i = 0; i < nbytes; i++)
480 {
481 switch (buf[i])
482 {
483 case IAC:
484 vty_out (vty, "IAC ");
485 break;
486 case WILL:
487 vty_out (vty, "WILL ");
488 break;
489 case WONT:
490 vty_out (vty, "WONT ");
491 break;
492 case DO:
493 vty_out (vty, "DO ");
494 break;
495 case DONT:
496 vty_out (vty, "DONT ");
497 break;
498 case SB:
499 vty_out (vty, "SB ");
500 break;
501 case SE:
502 vty_out (vty, "SE ");
503 break;
504 case TELOPT_ECHO:
505 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
506 break;
507 case TELOPT_SGA:
508 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
509 break;
510 case TELOPT_NAWS:
511 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
512 break;
513 default:
514 vty_out (vty, "%x ", buf[i]);
515 break;
516 }
517 }
518 vty_out (vty, "%s", VTY_NEWLINE);
519
520#endif /* TELNET_OPTION_DEBUG */
521
522 switch (buf[0])
523 {
524 case SB:
525 vty->sb_len = 0;
526 vty->iac_sb_in_progress = 1;
527 return 0;
528 break;
529 case SE:
530 {
531 if (!vty->iac_sb_in_progress)
532 return 0;
533
534 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
535 {
536 vty->iac_sb_in_progress = 0;
537 return 0;
538 }
539 switch (vty->sb_buf[0])
540 {
541 case TELOPT_NAWS:
542 if (vty->sb_len != TELNET_NAWS_SB_LEN)
543 vty_out(vty,"RFC 1073 violation detected: telnet NAWS option "
544 "should send %d characters, but we received %lu",
545 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
546 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
547 vty_out(vty, "Bug detected: sizeof(vty->sb_buf) %lu < %d, "
548 "too small to handle the telnet NAWS option",
549 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
550 else
551 {
552 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
553 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
554#ifdef TELNET_OPTION_DEBUG
555 vty_out(vty, "TELNET NAWS window size negotiation completed: "
556 "width %d, height %d%s",
557 vty->width, vty->height, VTY_NEWLINE);
558#endif
559 }
560 break;
561 }
562 vty->iac_sb_in_progress = 0;
563 return 0;
564 break;
565 }
566 default:
567 break;
568 }
569 return 1;
570}
571
572/* Execute current command line. */
573static int vty_execute(struct vty *vty)
574{
575 int ret;
576
577 ret = CMD_SUCCESS;
578
579 switch (vty->node) {
580 case AUTH_NODE:
581 case AUTH_ENABLE_NODE:
582 vty_auth(vty, vty->buf);
583 break;
584 default:
585 ret = vty_command(vty, vty->buf);
586 if (vty->type == VTY_TERM)
587 vty_hist_add(vty);
588 break;
589 }
590
591 /* Clear command line buffer. */
592 vty->cp = vty->length = 0;
593 vty_clear_buf(vty);
594
595 if (vty->status != VTY_CLOSE)
596 vty_prompt(vty);
597
598 return ret;
599}
600
601/* Send WILL TELOPT_ECHO to remote server. */
602static void
603vty_will_echo (struct vty *vty)
604{
605 unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
606 vty_out (vty, "%s", cmd);
607}
608
609/* Make suppress Go-Ahead telnet option. */
610static void
611vty_will_suppress_go_ahead (struct vty *vty)
612{
613 unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
614 vty_out (vty, "%s", cmd);
615}
616
617/* Make don't use linemode over telnet. */
618static void
619vty_dont_linemode (struct vty *vty)
620{
621 unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
622 vty_out (vty, "%s", cmd);
623}
624
625/* Use window size. */
626static void
627vty_do_window_size (struct vty *vty)
628{
629 unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
630 vty_out (vty, "%s", cmd);
631}
632
633static void vty_kill_line_from_beginning(struct vty *);
634static void vty_redraw_line(struct vty *);
635
636/* Print command line history. This function is called from
637 vty_next_line and vty_previous_line. */
638static void vty_history_print(struct vty *vty)
639{
640 int length;
641
642 vty_kill_line_from_beginning(vty);
643
644 /* Get previous line from history buffer */
645 length = strlen(vty->hist[vty->hp]);
646 memcpy(vty->buf, vty->hist[vty->hp], length);
647 vty->cp = vty->length = length;
648
649 /* Redraw current line */
650 vty_redraw_line(vty);
651}
652
653/* Show next command line history. */
654static void vty_next_line(struct vty *vty)
655{
656 int try_index;
657
658 if (vty->hp == vty->hindex)
659 return;
660
661 /* Try is there history exist or not. */
662 try_index = vty->hp;
663 if (try_index == (VTY_MAXHIST - 1))
664 try_index = 0;
665 else
666 try_index++;
667
668 /* If there is not history return. */
669 if (vty->hist[try_index] == NULL)
670 return;
671 else
672 vty->hp = try_index;
673
674 vty_history_print(vty);
675}
676
677/* Show previous command line history. */
678static void vty_previous_line(struct vty *vty)
679{
680 int try_index;
681
682 try_index = vty->hp;
683 if (try_index == 0)
684 try_index = VTY_MAXHIST - 1;
685 else
686 try_index--;
687
688 if (vty->hist[try_index] == NULL)
689 return;
690 else
691 vty->hp = try_index;
692
693 vty_history_print(vty);
694}
695
696/* This function redraw all of the command line character. */
697static void vty_redraw_line(struct vty *vty)
698{
699 vty_write(vty, vty->buf, vty->length);
700 vty->cp = vty->length;
701}
702
703/* Forward word. */
704static void vty_forward_word(struct vty *vty)
705{
706 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
707 vty_forward_char(vty);
708
709 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
710 vty_forward_char(vty);
711}
712
713/* Backward word without skipping training space. */
714static void vty_backward_pure_word(struct vty *vty)
715{
716 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
717 vty_backward_char(vty);
718}
719
720/* Backward word. */
721static void vty_backward_word(struct vty *vty)
722{
723 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
724 vty_backward_char(vty);
725
726 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
727 vty_backward_char(vty);
728}
729
730/* When '^D' is typed at the beginning of the line we move to the down
731 level. */
732static void vty_down_level(struct vty *vty)
733{
734 vty_out(vty, "%s", VTY_NEWLINE);
735 (*config_exit_cmd.func) (NULL, vty, 0, NULL);
736 vty_prompt(vty);
737 vty->cp = 0;
738}
739
740/* When '^Z' is received from vty, move down to the enable mode. */
741static void vty_end_config(struct vty *vty)
742{
743 vty_out(vty, "%s", VTY_NEWLINE);
744
745 switch (vty->node) {
746 case VIEW_NODE:
747 case ENABLE_NODE:
748 /* Nothing to do. */
749 break;
750 case CONFIG_NODE:
Harald Welte955049f2009-03-10 12:16:51 +0000751 case VTY_NODE:
752 vty_config_unlock(vty);
753 vty->node = ENABLE_NODE;
754 break;
755 default:
756 /* Unknown node, we have to ignore it. */
757 break;
758 }
759
760 vty_prompt(vty);
761 vty->cp = 0;
762}
763
764/* Delete a charcter at the current point. */
765static void vty_delete_char(struct vty *vty)
766{
767 int i;
768 int size;
769
770 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
771 return;
772
773 if (vty->length == 0) {
774 vty_down_level(vty);
775 return;
776 }
777
778 if (vty->cp == vty->length)
779 return; /* completion need here? */
780
781 size = vty->length - vty->cp;
782
783 vty->length--;
784 memmove(&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
785 vty->buf[vty->length] = '\0';
786
787 vty_write(vty, &vty->buf[vty->cp], size - 1);
788 vty_write(vty, &telnet_space_char, 1);
789
790 for (i = 0; i < size; i++)
791 vty_write(vty, &telnet_backward_char, 1);
792}
793
794/* Delete a character before the point. */
795static void vty_delete_backward_char(struct vty *vty)
796{
797 if (vty->cp == 0)
798 return;
799
800 vty_backward_char(vty);
801 vty_delete_char(vty);
802}
803
804/* Kill rest of line from current point. */
805static void vty_kill_line(struct vty *vty)
806{
807 int i;
808 int size;
809
810 size = vty->length - vty->cp;
811
812 if (size == 0)
813 return;
814
815 for (i = 0; i < size; i++)
816 vty_write(vty, &telnet_space_char, 1);
817 for (i = 0; i < size; i++)
818 vty_write(vty, &telnet_backward_char, 1);
819
820 memset(&vty->buf[vty->cp], 0, size);
821 vty->length = vty->cp;
822}
823
824/* Kill line from the beginning. */
825static void vty_kill_line_from_beginning(struct vty *vty)
826{
827 vty_beginning_of_line(vty);
828 vty_kill_line(vty);
829}
830
831/* Delete a word before the point. */
832static void vty_forward_kill_word(struct vty *vty)
833{
834 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
835 vty_delete_char(vty);
836 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
837 vty_delete_char(vty);
838}
839
840/* Delete a word before the point. */
841static void vty_backward_kill_word(struct vty *vty)
842{
843 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
844 vty_delete_backward_char(vty);
845 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
846 vty_delete_backward_char(vty);
847}
848
849/* Transpose chars before or at the point. */
850static void vty_transpose_chars(struct vty *vty)
851{
852 char c1, c2;
853
854 /* If length is short or point is near by the beginning of line then
855 return. */
856 if (vty->length < 2 || vty->cp < 1)
857 return;
858
859 /* In case of point is located at the end of the line. */
860 if (vty->cp == vty->length) {
861 c1 = vty->buf[vty->cp - 1];
862 c2 = vty->buf[vty->cp - 2];
863
864 vty_backward_char(vty);
865 vty_backward_char(vty);
866 vty_self_insert_overwrite(vty, c1);
867 vty_self_insert_overwrite(vty, c2);
868 } else {
869 c1 = vty->buf[vty->cp];
870 c2 = vty->buf[vty->cp - 1];
871
872 vty_backward_char(vty);
873 vty_self_insert_overwrite(vty, c1);
874 vty_self_insert_overwrite(vty, c2);
875 }
876}
877
878/* Do completion at vty interface. */
879static void vty_complete_command(struct vty *vty)
880{
881 int i;
882 int ret;
883 char **matched = NULL;
884 vector vline;
885
886 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
887 return;
888
889 vline = cmd_make_strvec(vty->buf);
890 if (vline == NULL)
891 return;
892
893 /* In case of 'help \t'. */
894 if (isspace((int)vty->buf[vty->length - 1]))
895 vector_set(vline, '\0');
896
897 matched = cmd_complete_command(vline, vty, &ret);
898
899 cmd_free_strvec(vline);
900
901 vty_out(vty, "%s", VTY_NEWLINE);
902 switch (ret) {
903 case CMD_ERR_AMBIGUOUS:
904 vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
905 vty_prompt(vty);
906 vty_redraw_line(vty);
907 break;
908 case CMD_ERR_NO_MATCH:
909 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
910 vty_prompt(vty);
911 vty_redraw_line(vty);
912 break;
913 case CMD_COMPLETE_FULL_MATCH:
914 vty_prompt(vty);
915 vty_redraw_line(vty);
916 vty_backward_pure_word(vty);
917 vty_insert_word_overwrite(vty, matched[0]);
918 vty_self_insert(vty, ' ');
Harald Welte2477d932009-08-07 00:32:41 +0200919 //talloc_free(matched[0]);
Harald Welte955049f2009-03-10 12:16:51 +0000920 break;
921 case CMD_COMPLETE_MATCH:
922 vty_prompt(vty);
923 vty_redraw_line(vty);
924 vty_backward_pure_word(vty);
925 vty_insert_word_overwrite(vty, matched[0]);
Harald Welte2477d932009-08-07 00:32:41 +0200926 talloc_free(matched[0]);
Harald Welte955049f2009-03-10 12:16:51 +0000927 vector_only_index_free(matched);
928 return;
929 break;
930 case CMD_COMPLETE_LIST_MATCH:
931 for (i = 0; matched[i] != NULL; i++) {
932 if (i != 0 && ((i % 6) == 0))
933 vty_out(vty, "%s", VTY_NEWLINE);
934 vty_out(vty, "%-10s ", matched[i]);
Harald Welte2477d932009-08-07 00:32:41 +0200935 talloc_free(matched[i]);
Harald Welte955049f2009-03-10 12:16:51 +0000936 }
937 vty_out(vty, "%s", VTY_NEWLINE);
938
939 vty_prompt(vty);
940 vty_redraw_line(vty);
941 break;
942 case CMD_ERR_NOTHING_TODO:
943 vty_prompt(vty);
944 vty_redraw_line(vty);
945 break;
946 default:
947 break;
948 }
949 if (matched)
950 vector_only_index_free(matched);
951}
952
953static void
954vty_describe_fold(struct vty *vty, int cmd_width,
955 unsigned int desc_width, struct desc *desc)
956{
957 char *buf;
958 const char *cmd, *p;
959 int pos;
960
961 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
962
963 if (desc_width <= 0) {
964 vty_out(vty, " %-*s %s%s", cmd_width, cmd, desc->str,
965 VTY_NEWLINE);
966 return;
967 }
968
Harald Welte2477d932009-08-07 00:32:41 +0200969 buf = _talloc_zero(tall_vty_ctx, strlen(desc->str) + 1, "describe_fold");
Harald Welte955049f2009-03-10 12:16:51 +0000970 if (!buf)
971 return;
972
973 for (p = desc->str; strlen(p) > desc_width; p += pos + 1) {
974 for (pos = desc_width; pos > 0; pos--)
975 if (*(p + pos) == ' ')
976 break;
977
978 if (pos == 0)
979 break;
980
981 strncpy(buf, p, pos);
982 buf[pos] = '\0';
983 vty_out(vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
984
985 cmd = "";
986 }
987
988 vty_out(vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
989
Harald Welte2477d932009-08-07 00:32:41 +0200990 talloc_free(buf);
Harald Welte955049f2009-03-10 12:16:51 +0000991}
992
993/* Describe matched command function. */
994static void vty_describe_command(struct vty *vty)
995{
996 int ret;
997 vector vline;
998 vector describe;
999 unsigned int i, width, desc_width;
1000 struct desc *desc, *desc_cr = NULL;
1001
1002 vline = cmd_make_strvec(vty->buf);
1003
1004 /* In case of '> ?'. */
1005 if (vline == NULL) {
1006 vline = vector_init(1);
1007 vector_set(vline, '\0');
1008 } else if (isspace((int)vty->buf[vty->length - 1]))
1009 vector_set(vline, '\0');
1010
1011 describe = cmd_describe_command(vline, vty, &ret);
1012
1013 vty_out(vty, "%s", VTY_NEWLINE);
1014
1015 /* Ambiguous error. */
1016 switch (ret) {
1017 case CMD_ERR_AMBIGUOUS:
1018 cmd_free_strvec(vline);
1019 vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
1020 vty_prompt(vty);
1021 vty_redraw_line(vty);
1022 return;
1023 break;
1024 case CMD_ERR_NO_MATCH:
1025 cmd_free_strvec(vline);
1026 vty_out(vty, "%% There is no matched command.%s", VTY_NEWLINE);
1027 vty_prompt(vty);
1028 vty_redraw_line(vty);
1029 return;
1030 break;
1031 }
1032
1033 /* Get width of command string. */
1034 width = 0;
1035 for (i = 0; i < vector_active(describe); i++)
1036 if ((desc = vector_slot(describe, i)) != NULL) {
1037 unsigned int len;
1038
1039 if (desc->cmd[0] == '\0')
1040 continue;
1041
1042 len = strlen(desc->cmd);
1043 if (desc->cmd[0] == '.')
1044 len--;
1045
1046 if (width < len)
1047 width = len;
1048 }
1049
1050 /* Get width of description string. */
1051 desc_width = vty->width - (width + 6);
1052
1053 /* Print out description. */
1054 for (i = 0; i < vector_active(describe); i++)
1055 if ((desc = vector_slot(describe, i)) != NULL) {
1056 if (desc->cmd[0] == '\0')
1057 continue;
1058
1059 if (strcmp(desc->cmd, "<cr>") == 0) {
1060 desc_cr = desc;
1061 continue;
1062 }
1063
1064 if (!desc->str)
1065 vty_out(vty, " %-s%s",
1066 desc->cmd[0] ==
1067 '.' ? desc->cmd + 1 : desc->cmd,
1068 VTY_NEWLINE);
1069 else if (desc_width >= strlen(desc->str))
1070 vty_out(vty, " %-*s %s%s", width,
1071 desc->cmd[0] ==
1072 '.' ? desc->cmd + 1 : desc->cmd,
1073 desc->str, VTY_NEWLINE);
1074 else
1075 vty_describe_fold(vty, width, desc_width, desc);
1076
1077#if 0
1078 vty_out(vty, " %-*s %s%s", width
1079 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1080 desc->str ? desc->str : "", VTY_NEWLINE);
1081#endif /* 0 */
1082 }
1083
1084 if ((desc = desc_cr)) {
1085 if (!desc->str)
1086 vty_out(vty, " %-s%s",
1087 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1088 VTY_NEWLINE);
1089 else if (desc_width >= strlen(desc->str))
1090 vty_out(vty, " %-*s %s%s", width,
1091 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1092 desc->str, VTY_NEWLINE);
1093 else
1094 vty_describe_fold(vty, width, desc_width, desc);
1095 }
1096
1097 cmd_free_strvec(vline);
1098 vector_free(describe);
1099
1100 vty_prompt(vty);
1101 vty_redraw_line(vty);
1102}
1103
1104/* ^C stop current input and do not add command line to the history. */
1105static void vty_stop_input(struct vty *vty)
1106{
1107 vty->cp = vty->length = 0;
1108 vty_clear_buf(vty);
1109 vty_out(vty, "%s", VTY_NEWLINE);
1110
1111 switch (vty->node) {
1112 case VIEW_NODE:
1113 case ENABLE_NODE:
1114 /* Nothing to do. */
1115 break;
1116 case CONFIG_NODE:
Harald Welte955049f2009-03-10 12:16:51 +00001117 case VTY_NODE:
1118 vty_config_unlock(vty);
1119 vty->node = ENABLE_NODE;
1120 break;
1121 default:
1122 /* Unknown node, we have to ignore it. */
1123 break;
1124 }
1125 vty_prompt(vty);
1126
1127 /* Set history pointer to the latest one. */
1128 vty->hp = vty->hindex;
1129}
1130
1131#define CONTROL(X) ((X) - '@')
1132#define VTY_NORMAL 0
1133#define VTY_PRE_ESCAPE 1
1134#define VTY_ESCAPE 2
1135
1136/* Escape character command map. */
1137static void vty_escape_map(unsigned char c, struct vty *vty)
1138{
1139 switch (c) {
1140 case ('A'):
1141 vty_previous_line(vty);
1142 break;
1143 case ('B'):
1144 vty_next_line(vty);
1145 break;
1146 case ('C'):
1147 vty_forward_char(vty);
1148 break;
1149 case ('D'):
1150 vty_backward_char(vty);
1151 break;
1152 default:
1153 break;
1154 }
1155
1156 /* Go back to normal mode. */
1157 vty->escape = VTY_NORMAL;
1158}
1159
1160/* Quit print out to the buffer. */
1161static void vty_buffer_reset(struct vty *vty)
1162{
1163 buffer_reset(vty->obuf);
1164 vty_prompt(vty);
1165 vty_redraw_line(vty);
1166}
1167
1168/* Read data via vty socket. */
1169int vty_read(struct vty *vty)
1170{
1171 int i;
1172 int nbytes;
1173 unsigned char buf[VTY_READ_BUFSIZ];
1174
1175 int vty_sock = vty->fd;
1176
1177 /* Read raw data from socket */
1178 if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) {
1179 if (nbytes < 0) {
1180 if (ERRNO_IO_RETRY(errno)) {
1181 vty_event(VTY_READ, vty_sock, vty);
1182 return 0;
1183 }
1184 }
1185 buffer_reset(vty->obuf);
1186 vty->status = VTY_CLOSE;
1187 }
1188
1189 for (i = 0; i < nbytes; i++) {
1190 if (buf[i] == IAC) {
1191 if (!vty->iac) {
1192 vty->iac = 1;
1193 continue;
1194 } else {
1195 vty->iac = 0;
1196 }
1197 }
1198
1199 if (vty->iac_sb_in_progress && !vty->iac) {
1200 if (vty->sb_len < sizeof(vty->sb_buf))
1201 vty->sb_buf[vty->sb_len] = buf[i];
1202 vty->sb_len++;
1203 continue;
1204 }
1205
1206 if (vty->iac) {
1207 /* In case of telnet command */
1208 int ret = 0;
1209 ret = vty_telnet_option(vty, buf + i, nbytes - i);
1210 vty->iac = 0;
1211 i += ret;
1212 continue;
1213 }
1214
1215 if (vty->status == VTY_MORE) {
1216 switch (buf[i]) {
1217 case CONTROL('C'):
1218 case 'q':
1219 case 'Q':
1220 vty_buffer_reset(vty);
1221 break;
1222#if 0 /* More line does not work for "show ip bgp". */
1223 case '\n':
1224 case '\r':
1225 vty->status = VTY_MORELINE;
1226 break;
1227#endif
1228 default:
1229 break;
1230 }
1231 continue;
1232 }
1233
1234 /* Escape character. */
1235 if (vty->escape == VTY_ESCAPE) {
1236 vty_escape_map(buf[i], vty);
1237 continue;
1238 }
1239
1240 /* Pre-escape status. */
1241 if (vty->escape == VTY_PRE_ESCAPE) {
1242 switch (buf[i]) {
1243 case '[':
1244 vty->escape = VTY_ESCAPE;
1245 break;
1246 case 'b':
1247 vty_backward_word(vty);
1248 vty->escape = VTY_NORMAL;
1249 break;
1250 case 'f':
1251 vty_forward_word(vty);
1252 vty->escape = VTY_NORMAL;
1253 break;
1254 case 'd':
1255 vty_forward_kill_word(vty);
1256 vty->escape = VTY_NORMAL;
1257 break;
1258 case CONTROL('H'):
1259 case 0x7f:
1260 vty_backward_kill_word(vty);
1261 vty->escape = VTY_NORMAL;
1262 break;
1263 default:
1264 vty->escape = VTY_NORMAL;
1265 break;
1266 }
1267 continue;
1268 }
1269
1270 switch (buf[i]) {
1271 case CONTROL('A'):
1272 vty_beginning_of_line(vty);
1273 break;
1274 case CONTROL('B'):
1275 vty_backward_char(vty);
1276 break;
1277 case CONTROL('C'):
1278 vty_stop_input(vty);
1279 break;
1280 case CONTROL('D'):
1281 vty_delete_char(vty);
1282 break;
1283 case CONTROL('E'):
1284 vty_end_of_line(vty);
1285 break;
1286 case CONTROL('F'):
1287 vty_forward_char(vty);
1288 break;
1289 case CONTROL('H'):
1290 case 0x7f:
1291 vty_delete_backward_char(vty);
1292 break;
1293 case CONTROL('K'):
1294 vty_kill_line(vty);
1295 break;
1296 case CONTROL('N'):
1297 vty_next_line(vty);
1298 break;
1299 case CONTROL('P'):
1300 vty_previous_line(vty);
1301 break;
1302 case CONTROL('T'):
1303 vty_transpose_chars(vty);
1304 break;
1305 case CONTROL('U'):
1306 vty_kill_line_from_beginning(vty);
1307 break;
1308 case CONTROL('W'):
1309 vty_backward_kill_word(vty);
1310 break;
1311 case CONTROL('Z'):
1312 vty_end_config(vty);
1313 break;
1314 case '\n':
1315 case '\r':
1316 vty_out(vty, "%s", VTY_NEWLINE);
1317 vty_execute(vty);
1318 break;
1319 case '\t':
1320 vty_complete_command(vty);
1321 break;
1322 case '?':
1323 if (vty->node == AUTH_NODE
1324 || vty->node == AUTH_ENABLE_NODE)
1325 vty_self_insert(vty, buf[i]);
1326 else
1327 vty_describe_command(vty);
1328 break;
1329 case '\033':
1330 if (i + 1 < nbytes && buf[i + 1] == '[') {
1331 vty->escape = VTY_ESCAPE;
1332 i++;
1333 } else
1334 vty->escape = VTY_PRE_ESCAPE;
1335 break;
1336 default:
1337 if (buf[i] > 31 && buf[i] < 127)
1338 vty_self_insert(vty, buf[i]);
1339 break;
1340 }
1341 }
1342
1343 /* Check status. */
1344 if (vty->status == VTY_CLOSE)
1345 vty_close(vty);
1346 else {
1347 vty_event(VTY_WRITE, vty_sock, vty);
1348 vty_event(VTY_READ, vty_sock, vty);
1349 }
1350 return 0;
1351}
1352
Harald Weltec7c19822009-08-07 13:28:08 +02001353/* Read up configuration file */
1354static int
1355vty_read_file(FILE *confp)
1356{
1357 int ret;
1358 struct vty *vty;
1359
1360 vty = vty_new();
1361 vty->fd = 0;
1362 vty->type = VTY_FILE;
1363 vty->node = CONFIG_NODE;
1364
1365 ret = config_from_file(vty, confp);
1366
1367 if (ret != CMD_SUCCESS) {
1368 switch (ret) {
1369 case CMD_ERR_AMBIGUOUS:
1370 fprintf(stderr, "Ambiguous command.\n");
1371 break;
1372 case CMD_ERR_NO_MATCH:
Harald Welte42581822009-08-08 16:12:58 +02001373 fprintf(stderr, "There is no such command.\n");
Harald Weltec7c19822009-08-07 13:28:08 +02001374 break;
1375 }
1376 fprintf(stderr, "Error occurred during reading below "
1377 "line:\n%s\n", vty->buf);
1378 vty_close(vty);
1379 return -EINVAL;
1380 }
1381
1382 vty_close(vty);
1383 return 0;
1384}
1385
Harald Welte955049f2009-03-10 12:16:51 +00001386/* Create new vty structure. */
1387struct vty *
Harald Weltec63e51d2009-03-10 19:46:16 +00001388vty_create (int vty_sock, void *priv)
Harald Welte955049f2009-03-10 12:16:51 +00001389{
1390 struct vty *vty;
1391
1392 struct termios t;
1393
1394 tcgetattr(vty_sock, &t);
1395 cfmakeraw(&t);
1396 tcsetattr(vty_sock, TCSANOW, &t);
1397
1398 /* Allocate new vty structure and set up default values. */
1399 vty = vty_new ();
1400 vty->fd = vty_sock;
Harald Weltec63e51d2009-03-10 19:46:16 +00001401 vty->priv = priv;
Harald Welte955049f2009-03-10 12:16:51 +00001402 vty->type = VTY_TERM;
1403 if (no_password_check)
1404 {
1405 if (host.advanced)
1406 vty->node = ENABLE_NODE;
1407 else
1408 vty->node = VIEW_NODE;
1409 }
1410 else
1411 vty->node = AUTH_NODE;
1412 vty->fail = 0;
1413 vty->cp = 0;
1414 vty_clear_buf (vty);
1415 vty->length = 0;
1416 memset (vty->hist, 0, sizeof (vty->hist));
1417 vty->hp = 0;
1418 vty->hindex = 0;
1419 vector_set_index (vtyvec, vty_sock, vty);
1420 vty->status = VTY_NORMAL;
1421 if (host.lines >= 0)
1422 vty->lines = host.lines;
1423 else
1424 vty->lines = -1;
1425
1426 if (! no_password_check)
1427 {
1428 /* Vty is not available if password isn't set. */
1429 if (host.password == NULL && host.password_encrypt == NULL)
1430 {
1431 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1432 vty->status = VTY_CLOSE;
1433 vty_close (vty);
1434 return NULL;
1435 }
1436 }
1437
1438 /* Say hello to the world. */
1439 vty_hello (vty);
1440 if (! no_password_check)
1441 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1442
1443 /* Setting up terminal. */
1444 vty_will_echo (vty);
1445 vty_will_suppress_go_ahead (vty);
1446
1447 vty_dont_linemode (vty);
1448 vty_do_window_size (vty);
1449 /* vty_dont_lflow_ahead (vty); */
1450
1451 vty_prompt (vty);
1452
1453 /* Add read/write thread. */
1454 vty_event (VTY_WRITE, vty_sock, vty);
1455 vty_event (VTY_READ, vty_sock, vty);
1456
1457 return vty;
1458}
1459
1460DEFUN(config_who, config_who_cmd, "who", "Display who is on vty\n")
1461{
1462 unsigned int i;
1463 struct vty *v;
1464
1465 for (i = 0; i < vector_active(vtyvec); i++)
1466 if ((v = vector_slot(vtyvec, i)) != NULL)
1467 vty_out(vty, "%svty[%d] %s",
1468 v->config ? "*" : " ", i, VTY_NEWLINE);
1469 return CMD_SUCCESS;
1470}
1471
1472/* Move to vty configuration mode. */
1473DEFUN(line_vty,
1474 line_vty_cmd,
1475 "line vty", "Configure a terminal line\n" "Virtual terminal\n")
1476{
1477 vty->node = VTY_NODE;
1478 return CMD_SUCCESS;
1479}
1480
1481/* vty login. */
1482DEFUN(vty_login, vty_login_cmd, "login", "Enable password checking\n")
1483{
1484 no_password_check = 0;
1485 return CMD_SUCCESS;
1486}
1487
1488DEFUN(no_vty_login,
1489 no_vty_login_cmd, "no login", NO_STR "Enable password checking\n")
1490{
1491 no_password_check = 1;
1492 return CMD_SUCCESS;
1493}
1494
1495DEFUN(service_advanced_vty,
1496 service_advanced_vty_cmd,
1497 "service advanced-vty",
1498 "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
1499{
1500 host.advanced = 1;
1501 return CMD_SUCCESS;
1502}
1503
1504DEFUN(no_service_advanced_vty,
1505 no_service_advanced_vty_cmd,
1506 "no service advanced-vty",
1507 NO_STR
1508 "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
1509{
1510 host.advanced = 0;
1511 return CMD_SUCCESS;
1512}
1513
1514DEFUN(terminal_monitor,
1515 terminal_monitor_cmd,
1516 "terminal monitor",
1517 "Set terminal line parameters\n"
1518 "Copy debug output to the current terminal line\n")
1519{
1520 vty->monitor = 1;
1521 return CMD_SUCCESS;
1522}
1523
1524DEFUN(terminal_no_monitor,
1525 terminal_no_monitor_cmd,
1526 "terminal no monitor",
1527 "Set terminal line parameters\n"
1528 NO_STR "Copy debug output to the current terminal line\n")
1529{
1530 vty->monitor = 0;
1531 return CMD_SUCCESS;
1532}
1533
1534DEFUN(show_history,
1535 show_history_cmd,
1536 "show history", SHOW_STR "Display the session command history\n")
1537{
1538 int index;
1539
1540 for (index = vty->hindex + 1; index != vty->hindex;) {
1541 if (index == VTY_MAXHIST) {
1542 index = 0;
1543 continue;
1544 }
1545
1546 if (vty->hist[index] != NULL)
1547 vty_out(vty, " %s%s", vty->hist[index], VTY_NEWLINE);
1548
1549 index++;
1550 }
1551
1552 return CMD_SUCCESS;
1553}
1554
1555/* Display current configuration. */
1556static int vty_config_write(struct vty *vty)
1557{
1558 vty_out(vty, "line vty%s", VTY_NEWLINE);
1559
1560 /* login */
1561 if (no_password_check)
1562 vty_out(vty, " no login%s", VTY_NEWLINE);
1563
1564 vty_out(vty, "!%s", VTY_NEWLINE);
1565
1566 return CMD_SUCCESS;
1567}
1568
1569struct cmd_node vty_node = {
1570 VTY_NODE,
1571 "%s(config-line)# ",
1572 1,
1573};
1574
1575/* Reset all VTY status. */
1576void vty_reset()
1577{
1578 unsigned int i;
1579 struct vty *vty;
1580 struct thread *vty_serv_thread;
1581
1582 for (i = 0; i < vector_active(vtyvec); i++)
1583 if ((vty = vector_slot(vtyvec, i)) != NULL) {
1584 buffer_reset(vty->obuf);
1585 vty->status = VTY_CLOSE;
1586 vty_close(vty);
1587 }
1588
1589 for (i = 0; i < vector_active(Vvty_serv_thread); i++)
1590 if ((vty_serv_thread =
1591 vector_slot(Vvty_serv_thread, i)) != NULL) {
1592 //thread_cancel (vty_serv_thread);
1593 vector_slot(Vvty_serv_thread, i) = NULL;
1594 close(i);
1595 }
1596}
1597
1598static void vty_save_cwd(void)
1599{
1600 char cwd[MAXPATHLEN];
Holger Hans Peter Freyther6d30a352009-08-10 08:10:26 +02001601 char *c ;
Harald Welte955049f2009-03-10 12:16:51 +00001602
1603 c = getcwd(cwd, MAXPATHLEN);
1604
1605 if (!c) {
Holger Hans Peter Freyther6d30a352009-08-10 08:10:26 +02001606 if (chdir(SYSCONFDIR) != 0)
1607 perror("chdir failed");
1608 if (getcwd(cwd, MAXPATHLEN) == NULL)
1609 perror("getcwd failed");
Harald Welte955049f2009-03-10 12:16:51 +00001610 }
1611
Harald Welte2477d932009-08-07 00:32:41 +02001612 vty_cwd = _talloc_zero(tall_vty_ctx, strlen(cwd) + 1, "save_cwd");
Harald Welte955049f2009-03-10 12:16:51 +00001613 strcpy(vty_cwd, cwd);
1614}
1615
1616char *vty_get_cwd()
1617{
1618 return vty_cwd;
1619}
1620
1621int vty_shell_serv(struct vty *vty)
1622{
1623 return vty->type == VTY_SHELL_SERV ? 1 : 0;
1624}
1625
1626void vty_init_vtysh()
1627{
1628 vtyvec = vector_init(VECTOR_MIN_SIZE);
1629}
1630
Harald Welte0224e4d2009-08-07 13:25:41 +02001631extern void *tall_bsc_ctx;
Harald Welte955049f2009-03-10 12:16:51 +00001632/* Install vty's own commands like `who' command. */
1633void vty_init()
1634{
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02001635 tall_vty_ctx = talloc_named_const(NULL, 0, "vty");
Harald Welte0224e4d2009-08-07 13:25:41 +02001636
Harald Welte955049f2009-03-10 12:16:51 +00001637 /* For further configuration read, preserve current directory. */
1638 vty_save_cwd();
1639
1640 vtyvec = vector_init(VECTOR_MIN_SIZE);
1641
1642 /* Install bgp top node. */
1643 install_node(&vty_node, vty_config_write);
1644
1645 install_element(VIEW_NODE, &config_who_cmd);
1646 install_element(VIEW_NODE, &show_history_cmd);
1647 install_element(ENABLE_NODE, &config_who_cmd);
1648 install_element(CONFIG_NODE, &line_vty_cmd);
1649 install_element(CONFIG_NODE, &service_advanced_vty_cmd);
1650 install_element(CONFIG_NODE, &no_service_advanced_vty_cmd);
1651 install_element(CONFIG_NODE, &show_history_cmd);
1652 install_element(ENABLE_NODE, &terminal_monitor_cmd);
1653 install_element(ENABLE_NODE, &terminal_no_monitor_cmd);
1654 install_element(ENABLE_NODE, &show_history_cmd);
1655
1656 install_default(VTY_NODE);
Harald Welte955049f2009-03-10 12:16:51 +00001657 install_element(VTY_NODE, &vty_login_cmd);
1658 install_element(VTY_NODE, &no_vty_login_cmd);
Harald Welte955049f2009-03-10 12:16:51 +00001659}
Harald Welte2477d932009-08-07 00:32:41 +02001660
Harald Weltec7c19822009-08-07 13:28:08 +02001661int vty_read_config_file(const char *file_name)
Harald Welte2477d932009-08-07 00:32:41 +02001662{
Harald Weltec7c19822009-08-07 13:28:08 +02001663 FILE *cfile;
1664 int rc;
1665
1666 cfile = fopen(file_name, "r");
1667 if (!cfile)
1668 return -ENOENT;
1669
1670 rc = vty_read_file(cfile);
1671 fclose(cfile);
1672
1673 host_config_set(file_name);
1674
1675 return rc;
Harald Welte2477d932009-08-07 00:32:41 +02001676}