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