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