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