blob: 2a1f4665f37aebd1e13ccf86aeda5f8886bfe34d [file] [log] [blame]
jardineb5d44e2003-12-23 08:09:43 +00001/*
2 * Virtual terminal [aka TeletYpe] interface routine.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "linklist.h"
26#include "buffer.h"
27#include "version.h"
28#include "command.h"
29#include "sockunion.h"
30#include "thread.h"
31#include "memory.h"
32#include "str.h"
33#include "log.h"
34#include "prefix.h"
35#include "filter.h"
36
37/* Vty events */
38enum event
39{
40 VTY_SERV,
41 VTY_READ,
42 VTY_WRITE,
43 VTY_TIMEOUT_RESET,
44#ifdef VTYSH
45 VTYSH_SERV,
46 VTYSH_READ
47#endif /* VTYSH */
48};
49
50static void vty_event (enum event, int, struct vty *);
51
52/* Extern host structure from command.c */
53extern struct host host;
54
55/* Vector which store each vty structure. */
56static vector vtyvec;
57
58/* Vty timeout value. */
59static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
60
61/* Vty access-class command */
62static char *vty_accesslist_name = NULL;
63
64/* Vty access-calss for IPv6. */
65static char *vty_ipv6_accesslist_name = NULL;
66
67/* VTY server thread. */
68vector Vvty_serv_thread;
69
70/* Current directory. */
71char *vty_cwd = NULL;
72
73/* Configure lock. */
74static int vty_config;
75
76/* Login password check. */
77static int no_password_check = 0;
78
79/* Integrated configuration file path */
80char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
81
82
83/* VTY standard output function. */
84int
85vty_out (struct vty *vty, const char *format, ...)
86{
87 va_list args;
88 int len = 0;
89 int size = 1024;
90 char buf[1024];
91 char *p = NULL;
92
93 va_start (args, format);
94
95 if (vty_shell (vty))
96 vprintf (format, args);
97 else
98 {
99 /* Try to write to initial buffer. */
100 len = vsnprintf (buf, sizeof buf, format, args);
101
102 /* Initial buffer is not enough. */
103 if (len < 0 || len >= size)
104 {
105 while (1)
106 {
107 if (len > -1)
108 size = len + 1;
109 else
110 size = size * 2;
111
112 p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
113 if (! p)
114 return -1;
115
116 len = vsnprintf (p, size, format, args);
117
118 if (len > -1 && len < size)
119 break;
120 }
121 }
122
123 /* When initial buffer is enough to store all output. */
124 if (! p)
125 p = buf;
126
127 /* Pointer p must point out buffer. */
128 if (vty_shell_serv (vty))
129 write (vty->fd, (u_char *) p, len);
130 else
131 buffer_write (vty->obuf, (u_char *) p, len);
132
133 /* If p is not different with buf, it is allocated buffer. */
134 if (p != buf)
135 XFREE (MTYPE_VTY_OUT_BUF, p);
136 }
137
138 va_end (args);
139
140 return len;
141}
142
143int
144vty_log_out (struct vty *vty, const char *proto_str, const char *format,
145 va_list va)
146{
147 int len;
148 char buf[1024];
149
150 snprintf (buf, sizeof buf, "%s: ", proto_str);
151 write (vty->fd, buf, strlen (proto_str) + 2);
152
153 len = vsnprintf (buf, sizeof buf, format, va);
154 if (len < 0)
155 return -1;
156 write (vty->fd, (u_char *)buf, len);
157
158 snprintf (buf, sizeof buf, "\r\n");
159 write (vty->fd, buf, 2);
160
161 return len;
162}
163
164/* Output current time to the vty. */
165void
166vty_time_print (struct vty *vty, int cr)
167{
168 time_t clock;
169 struct tm *tm;
170#define TIME_BUF 25
171 char buf [TIME_BUF];
172 int ret;
173
174 time (&clock);
175 tm = localtime (&clock);
176
177 ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
178 if (ret == 0)
179 {
180 zlog (NULL, LOG_INFO, "strftime error");
181 return;
182 }
183 if (cr)
184 vty_out (vty, "%s\n", buf);
185 else
186 vty_out (vty, "%s ", buf);
187
188 return;
189}
190
191/* Say hello to vty interface. */
192void
193vty_hello (struct vty *vty)
194{
195 if (host.motd)
196 vty_out (vty, host.motd);
197}
198
199/* Put out prompt and wait input from user. */
200static void
201vty_prompt (struct vty *vty)
202{
203 struct utsname names;
204 const char*hostname;
205
206 if (vty->type == VTY_TERM)
207 {
208 hostname = host.name;
209 if (!hostname)
210 {
211 uname (&names);
212 hostname = names.nodename;
213 }
214 vty_out (vty, cmd_prompt (vty->node), hostname);
215 }
216}
217
218/* Send WILL TELOPT_ECHO to remote server. */
219void
220vty_will_echo (struct vty *vty)
221{
222 char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
223 vty_out (vty, "%s", cmd);
224}
225
226/* Make suppress Go-Ahead telnet option. */
227static void
228vty_will_suppress_go_ahead (struct vty *vty)
229{
230 char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
231 vty_out (vty, "%s", cmd);
232}
233
234/* Make don't use linemode over telnet. */
235static void
236vty_dont_linemode (struct vty *vty)
237{
238 char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
239 vty_out (vty, "%s", cmd);
240}
241
242/* Use window size. */
243static void
244vty_do_window_size (struct vty *vty)
245{
246 char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
247 vty_out (vty, "%s", cmd);
248}
249
250#if 0 /* Currently not used. */
251/* Make don't use lflow vty interface. */
252static void
253vty_dont_lflow_ahead (struct vty *vty)
254{
255 char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
256 vty_out (vty, "%s", cmd);
257}
258#endif /* 0 */
259
260/* Allocate new vty struct. */
261struct vty *
262vty_new ()
263{
264 struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
265
266 new->obuf = (struct buffer *) buffer_new (100);
267 new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
268 new->max = VTY_BUFSIZ;
269 new->sb_buffer = NULL;
270
271 return new;
272}
273
274/* Authentication of vty */
275static void
276vty_auth (struct vty *vty, char *buf)
277{
278 char *passwd = NULL;
279 enum node_type next_node = 0;
280 int fail;
281 char *crypt (const char *, const char *);
282
283 switch (vty->node)
284 {
285 case AUTH_NODE:
286 if (host.encrypt)
287 passwd = host.password_encrypt;
288 else
289 passwd = host.password;
290 if (host.advanced)
291 next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
292 else
293 next_node = VIEW_NODE;
294 break;
295 case AUTH_ENABLE_NODE:
296 if (host.encrypt)
297 passwd = host.enable_encrypt;
298 else
299 passwd = host.enable;
300 next_node = ENABLE_NODE;
301 break;
302 }
303
304 if (passwd)
305 {
306 if (host.encrypt)
307 fail = strcmp (crypt(buf, passwd), passwd);
308 else
309 fail = strcmp (buf, passwd);
310 }
311 else
312 fail = 1;
313
314 if (! fail)
315 {
316 vty->fail = 0;
317 vty->node = next_node; /* Success ! */
318 }
319 else
320 {
321 vty->fail++;
322 if (vty->fail >= 3)
323 {
324 if (vty->node == AUTH_NODE)
325 {
326 vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
327 vty->status = VTY_CLOSE;
328 }
329 else
330 {
331 /* AUTH_ENABLE_NODE */
332 vty->fail = 0;
333 vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
334 vty->node = VIEW_NODE;
335 }
336 }
337 }
338}
339
340/* Command execution over the vty interface. */
341int
342vty_command (struct vty *vty, char *buf)
343{
344 int ret;
345 vector vline;
346
347 /* Split readline string up into the vector */
348 vline = cmd_make_strvec (buf);
349
350 if (vline == NULL)
351 return CMD_SUCCESS;
352
353 ret = cmd_execute_command (vline, vty, NULL);
354
355 if (ret != CMD_SUCCESS)
356 switch (ret)
357 {
358 case CMD_WARNING:
359 if (vty->type == VTY_FILE)
360 vty_out (vty, "Warning...%s", VTY_NEWLINE);
361 break;
362 case CMD_ERR_AMBIGUOUS:
363 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
364 break;
365 case CMD_ERR_NO_MATCH:
366 vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
367 break;
368 case CMD_ERR_INCOMPLETE:
369 vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
370 break;
371 }
372 cmd_free_strvec (vline);
373
374 return ret;
375}
376
377char telnet_backward_char = 0x08;
378char telnet_space_char = ' ';
379
380/* Basic function to write buffer to vty. */
381static void
382vty_write (struct vty *vty, char *buf, size_t nbytes)
383{
384 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
385 return;
386
387 /* Should we do buffering here ? And make vty_flush (vty) ? */
388 buffer_write (vty->obuf, (u_char *)buf, nbytes);
389}
390
391/* Ensure length of input buffer. Is buffer is short, double it. */
392static void
393vty_ensure (struct vty *vty, int length)
394{
395 if (vty->max <= length)
396 {
397 vty->max *= 2;
398 vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
399 }
400}
401
402/* Basic function to insert character into vty. */
403static void
404vty_self_insert (struct vty *vty, char c)
405{
406 int i;
407 int length;
408
409 vty_ensure (vty, vty->length + 1);
410 length = vty->length - vty->cp;
411 memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
412 vty->buf[vty->cp] = c;
413
414 vty_write (vty, &vty->buf[vty->cp], length + 1);
415 for (i = 0; i < length; i++)
416 vty_write (vty, &telnet_backward_char, 1);
417
418 vty->cp++;
419 vty->length++;
420}
421
422/* Self insert character 'c' in overwrite mode. */
423static void
424vty_self_insert_overwrite (struct vty *vty, char c)
425{
426 vty_ensure (vty, vty->length + 1);
427 vty->buf[vty->cp++] = c;
428
429 if (vty->cp > vty->length)
430 vty->length++;
431
432 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
433 return;
434
435 vty_write (vty, &c, 1);
436}
437
438/* Insert a word into vty interface with overwrite mode. */
439static void
440vty_insert_word_overwrite (struct vty *vty, char *str)
441{
442 int len = strlen (str);
443 vty_write (vty, str, len);
444 strcpy (&vty->buf[vty->cp], str);
445 vty->cp += len;
446 vty->length = vty->cp;
447}
448
449/* Forward character. */
450static void
451vty_forward_char (struct vty *vty)
452{
453 if (vty->cp < vty->length)
454 {
455 vty_write (vty, &vty->buf[vty->cp], 1);
456 vty->cp++;
457 }
458}
459
460/* Backward character. */
461static void
462vty_backward_char (struct vty *vty)
463{
464 if (vty->cp > 0)
465 {
466 vty->cp--;
467 vty_write (vty, &telnet_backward_char, 1);
468 }
469}
470
471/* Move to the beginning of the line. */
472static void
473vty_beginning_of_line (struct vty *vty)
474{
475 while (vty->cp)
476 vty_backward_char (vty);
477}
478
479/* Move to the end of the line. */
480static void
481vty_end_of_line (struct vty *vty)
482{
483 while (vty->cp < vty->length)
484 vty_forward_char (vty);
485}
486
487static void vty_kill_line_from_beginning (struct vty *);
488static void vty_redraw_line (struct vty *);
489
490/* Print command line history. This function is called from
491 vty_next_line and vty_previous_line. */
492static void
493vty_history_print (struct vty *vty)
494{
495 int length;
496
497 vty_kill_line_from_beginning (vty);
498
499 /* Get previous line from history buffer */
500 length = strlen (vty->hist[vty->hp]);
501 memcpy (vty->buf, vty->hist[vty->hp], length);
502 vty->cp = vty->length = length;
503
504 /* Redraw current line */
505 vty_redraw_line (vty);
506}
507
508/* Show next command line history. */
509void
510vty_next_line (struct vty *vty)
511{
512 int try_index;
513
514 if (vty->hp == vty->hindex)
515 return;
516
517 /* Try is there history exist or not. */
518 try_index = vty->hp;
519 if (try_index == (VTY_MAXHIST - 1))
520 try_index = 0;
521 else
522 try_index++;
523
524 /* If there is not history return. */
525 if (vty->hist[try_index] == NULL)
526 return;
527 else
528 vty->hp = try_index;
529
530 vty_history_print (vty);
531}
532
533/* Show previous command line history. */
534void
535vty_previous_line (struct vty *vty)
536{
537 int try_index;
538
539 try_index = vty->hp;
540 if (try_index == 0)
541 try_index = VTY_MAXHIST - 1;
542 else
543 try_index--;
544
545 if (vty->hist[try_index] == NULL)
546 return;
547 else
548 vty->hp = try_index;
549
550 vty_history_print (vty);
551}
552
553/* This function redraw all of the command line character. */
554static void
555vty_redraw_line (struct vty *vty)
556{
557 vty_write (vty, vty->buf, vty->length);
558 vty->cp = vty->length;
559}
560
561/* Forward word. */
562static void
563vty_forward_word (struct vty *vty)
564{
565 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
566 vty_forward_char (vty);
567
568 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
569 vty_forward_char (vty);
570}
571
572/* Backward word without skipping training space. */
573static void
574vty_backward_pure_word (struct vty *vty)
575{
576 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
577 vty_backward_char (vty);
578}
579
580/* Backward word. */
581static void
582vty_backward_word (struct vty *vty)
583{
584 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
585 vty_backward_char (vty);
586
587 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
588 vty_backward_char (vty);
589}
590
591/* When '^D' is typed at the beginning of the line we move to the down
592 level. */
593static void
594vty_down_level (struct vty *vty)
595{
596 vty_out (vty, "%s", VTY_NEWLINE);
597 config_exit (NULL, vty, 0, NULL);
598 vty_prompt (vty);
599 vty->cp = 0;
600}
601
602/* When '^Z' is received from vty, move down to the enable mode. */
603void
604vty_end_config (struct vty *vty)
605{
606 vty_out (vty, "%s", VTY_NEWLINE);
607
608 switch (vty->node)
609 {
610 case VIEW_NODE:
611 case ENABLE_NODE:
612 /* Nothing to do. */
613 break;
614 case CONFIG_NODE:
615 case INTERFACE_NODE:
616 case ZEBRA_NODE:
617 case RIP_NODE:
618 case RIPNG_NODE:
619 case BGP_NODE:
620 case BGP_VPNV4_NODE:
621 case BGP_IPV4_NODE:
622 case BGP_IPV4M_NODE:
623 case BGP_IPV6_NODE:
624 case RMAP_NODE:
625 case OSPF_NODE:
626 case OSPF6_NODE:
627 case ISIS_NODE:
628 case KEYCHAIN_NODE:
629 case KEYCHAIN_KEY_NODE:
630 case MASC_NODE:
631 case VTY_NODE:
632 vty_config_unlock (vty);
633 vty->node = ENABLE_NODE;
634 break;
635 default:
636 /* Unknown node, we have to ignore it. */
637 break;
638 }
639
640 vty_prompt (vty);
641 vty->cp = 0;
642}
643
644/* Delete a charcter at the current point. */
645static void
646vty_delete_char (struct vty *vty)
647{
648 int i;
649 int size;
650
651 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
652 return;
653
654 if (vty->length == 0)
655 {
656 vty_down_level (vty);
657 return;
658 }
659
660 if (vty->cp == vty->length)
661 return; /* completion need here? */
662
663 size = vty->length - vty->cp;
664
665 vty->length--;
666 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
667 vty->buf[vty->length] = '\0';
668
669 vty_write (vty, &vty->buf[vty->cp], size - 1);
670 vty_write (vty, &telnet_space_char, 1);
671
672 for (i = 0; i < size; i++)
673 vty_write (vty, &telnet_backward_char, 1);
674}
675
676/* Delete a character before the point. */
677static void
678vty_delete_backward_char (struct vty *vty)
679{
680 if (vty->cp == 0)
681 return;
682
683 vty_backward_char (vty);
684 vty_delete_char (vty);
685}
686
687/* Kill rest of line from current point. */
688static void
689vty_kill_line (struct vty *vty)
690{
691 int i;
692 int size;
693
694 size = vty->length - vty->cp;
695
696 if (size == 0)
697 return;
698
699 for (i = 0; i < size; i++)
700 vty_write (vty, &telnet_space_char, 1);
701 for (i = 0; i < size; i++)
702 vty_write (vty, &telnet_backward_char, 1);
703
704 memset (&vty->buf[vty->cp], 0, size);
705 vty->length = vty->cp;
706}
707
708/* Kill line from the beginning. */
709static void
710vty_kill_line_from_beginning (struct vty *vty)
711{
712 vty_beginning_of_line (vty);
713 vty_kill_line (vty);
714}
715
716/* Delete a word before the point. */
717static void
718vty_forward_kill_word (struct vty *vty)
719{
720 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
721 vty_delete_char (vty);
722 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
723 vty_delete_char (vty);
724}
725
726/* Delete a word before the point. */
727static void
728vty_backward_kill_word (struct vty *vty)
729{
730 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
731 vty_delete_backward_char (vty);
732 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
733 vty_delete_backward_char (vty);
734}
735
736/* Transpose chars before or at the point. */
737static void
738vty_transpose_chars (struct vty *vty)
739{
740 char c1, c2;
741
742 /* If length is short or point is near by the beginning of line then
743 return. */
744 if (vty->length < 2 || vty->cp < 1)
745 return;
746
747 /* In case of point is located at the end of the line. */
748 if (vty->cp == vty->length)
749 {
750 c1 = vty->buf[vty->cp - 1];
751 c2 = vty->buf[vty->cp - 2];
752
753 vty_backward_char (vty);
754 vty_backward_char (vty);
755 vty_self_insert_overwrite (vty, c1);
756 vty_self_insert_overwrite (vty, c2);
757 }
758 else
759 {
760 c1 = vty->buf[vty->cp];
761 c2 = vty->buf[vty->cp - 1];
762
763 vty_backward_char (vty);
764 vty_self_insert_overwrite (vty, c1);
765 vty_self_insert_overwrite (vty, c2);
766 }
767}
768
769/* Do completion at vty interface. */
770static void
771vty_complete_command (struct vty *vty)
772{
773 int i;
774 int ret;
775 char **matched = NULL;
776 vector vline;
777
778 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
779 return;
780
781 vline = cmd_make_strvec (vty->buf);
782 if (vline == NULL)
783 return;
784
785 /* In case of 'help \t'. */
786 if (isspace ((int) vty->buf[vty->length - 1]))
787 vector_set (vline, '\0');
788
789 matched = cmd_complete_command (vline, vty, &ret);
790
791 cmd_free_strvec (vline);
792
793 vty_out (vty, "%s", VTY_NEWLINE);
794 switch (ret)
795 {
796 case CMD_ERR_AMBIGUOUS:
797 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
798 vty_prompt (vty);
799 vty_redraw_line (vty);
800 break;
801 case CMD_ERR_NO_MATCH:
802 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
803 vty_prompt (vty);
804 vty_redraw_line (vty);
805 break;
806 case CMD_COMPLETE_FULL_MATCH:
807 vty_prompt (vty);
808 vty_redraw_line (vty);
809 vty_backward_pure_word (vty);
810 vty_insert_word_overwrite (vty, matched[0]);
811 vty_self_insert (vty, ' ');
812 XFREE (MTYPE_TMP, matched[0]);
813 break;
814 case CMD_COMPLETE_MATCH:
815 vty_prompt (vty);
816 vty_redraw_line (vty);
817 vty_backward_pure_word (vty);
818 vty_insert_word_overwrite (vty, matched[0]);
819 XFREE (MTYPE_TMP, matched[0]);
820 vector_only_index_free (matched);
821 return;
822 break;
823 case CMD_COMPLETE_LIST_MATCH:
824 for (i = 0; matched[i] != NULL; i++)
825 {
826 if (i != 0 && ((i % 6) == 0))
827 vty_out (vty, "%s", VTY_NEWLINE);
828 vty_out (vty, "%-10s ", matched[i]);
829 XFREE (MTYPE_TMP, matched[i]);
830 }
831 vty_out (vty, "%s", VTY_NEWLINE);
832
833 vty_prompt (vty);
834 vty_redraw_line (vty);
835 break;
836 case CMD_ERR_NOTHING_TODO:
837 vty_prompt (vty);
838 vty_redraw_line (vty);
839 break;
840 default:
841 break;
842 }
843 if (matched)
844 vector_only_index_free (matched);
845}
846
847void
848vty_describe_fold (struct vty *vty, int cmd_width,
849 int desc_width, struct desc *desc)
850{
851 char *buf, *cmd, *p;
852 int pos;
853
854 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
855
856 if (desc_width <= 0)
857 {
858 vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
859 return;
860 }
861
862 buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
863
864 for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
865 {
866 for (pos = desc_width; pos > 0; pos--)
867 if (*(p + pos) == ' ')
868 break;
869
870 if (pos == 0)
871 break;
872
873 strncpy (buf, p, pos);
874 buf[pos] = '\0';
875 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
876
877 cmd = "";
878 }
879
880 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
881
882 XFREE (MTYPE_TMP, buf);
883}
884
885/* Describe matched command function. */
886static void
887vty_describe_command (struct vty *vty)
888{
889 int ret;
890 vector vline;
891 vector describe;
892 int i, width, desc_width;
893 struct desc *desc, *desc_cr = NULL;
894
895 vline = cmd_make_strvec (vty->buf);
896
897 /* In case of '> ?'. */
898 if (vline == NULL)
899 {
900 vline = vector_init (1);
901 vector_set (vline, '\0');
902 }
903 else
904 if (isspace ((int) vty->buf[vty->length - 1]))
905 vector_set (vline, '\0');
906
907 describe = cmd_describe_command (vline, vty, &ret);
908
909 vty_out (vty, "%s", VTY_NEWLINE);
910
911 /* Ambiguous error. */
912 switch (ret)
913 {
914 case CMD_ERR_AMBIGUOUS:
915 cmd_free_strvec (vline);
916 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
917 vty_prompt (vty);
918 vty_redraw_line (vty);
919 return;
920 break;
921 case CMD_ERR_NO_MATCH:
922 cmd_free_strvec (vline);
923 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
924 vty_prompt (vty);
925 vty_redraw_line (vty);
926 return;
927 break;
928 }
929
930 /* Get width of command string. */
931 width = 0;
932 for (i = 0; i < vector_max (describe); i++)
933 if ((desc = vector_slot (describe, i)) != NULL)
934 {
935 int len;
936
937 if (desc->cmd[0] == '\0')
938 continue;
939
940 len = strlen (desc->cmd);
941 if (desc->cmd[0] == '.')
942 len--;
943
944 if (width < len)
945 width = len;
946 }
947
948 /* Get width of description string. */
949 desc_width = vty->width - (width + 6);
950
951 /* Print out description. */
952 for (i = 0; i < vector_max (describe); i++)
953 if ((desc = vector_slot (describe, i)) != NULL)
954 {
955 if (desc->cmd[0] == '\0')
956 continue;
957
958 if (strcmp (desc->cmd, "<cr>") == 0)
959 {
960 desc_cr = desc;
961 continue;
962 }
963
964 if (!desc->str)
965 vty_out (vty, " %-s%s",
966 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
967 VTY_NEWLINE);
968 else if (desc_width >= strlen (desc->str))
969 vty_out (vty, " %-*s %s%s", width,
970 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
971 desc->str, VTY_NEWLINE);
972 else
973 vty_describe_fold (vty, width, desc_width, desc);
974
975#if 0
976 vty_out (vty, " %-*s %s%s", width
977 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
978 desc->str ? desc->str : "", VTY_NEWLINE);
979#endif /* 0 */
980 }
981
982 if ((desc = desc_cr))
983 {
984 if (!desc->str)
985 vty_out (vty, " %-s%s",
986 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
987 VTY_NEWLINE);
988 else if (desc_width >= strlen (desc->str))
989 vty_out (vty, " %-*s %s%s", width,
990 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
991 desc->str, VTY_NEWLINE);
992 else
993 vty_describe_fold (vty, width, desc_width, desc);
994 }
995
996 cmd_free_strvec (vline);
997 vector_free (describe);
998
999 vty_prompt (vty);
1000 vty_redraw_line (vty);
1001}
1002
1003void
1004vty_clear_buf (struct vty *vty)
1005{
1006 memset (vty->buf, 0, vty->max);
1007}
1008
1009/* ^C stop current input and do not add command line to the history. */
1010static void
1011vty_stop_input (struct vty *vty)
1012{
1013 vty->cp = vty->length = 0;
1014 vty_clear_buf (vty);
1015 vty_out (vty, "%s", VTY_NEWLINE);
1016
1017 switch (vty->node)
1018 {
1019 case VIEW_NODE:
1020 case ENABLE_NODE:
1021 /* Nothing to do. */
1022 break;
1023 case CONFIG_NODE:
1024 case INTERFACE_NODE:
1025 case ZEBRA_NODE:
1026 case RIP_NODE:
1027 case RIPNG_NODE:
1028 case BGP_NODE:
1029 case RMAP_NODE:
1030 case OSPF_NODE:
1031 case OSPF6_NODE:
1032 case ISIS_NODE:
1033 case KEYCHAIN_NODE:
1034 case KEYCHAIN_KEY_NODE:
1035 case MASC_NODE:
1036 case VTY_NODE:
1037 vty_config_unlock (vty);
1038 vty->node = ENABLE_NODE;
1039 break;
1040 default:
1041 /* Unknown node, we have to ignore it. */
1042 break;
1043 }
1044 vty_prompt (vty);
1045
1046 /* Set history pointer to the latest one. */
1047 vty->hp = vty->hindex;
1048}
1049
1050/* Add current command line to the history buffer. */
1051static void
1052vty_hist_add (struct vty *vty)
1053{
1054 int index;
1055
1056 if (vty->length == 0)
1057 return;
1058
1059 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1060
1061 /* Ignore the same string as previous one. */
1062 if (vty->hist[index])
1063 if (strcmp (vty->buf, vty->hist[index]) == 0)
1064 {
1065 vty->hp = vty->hindex;
1066 return;
1067 }
1068
1069 /* Insert history entry. */
1070 if (vty->hist[vty->hindex])
1071 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1072 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1073
1074 /* History index rotation. */
1075 vty->hindex++;
1076 if (vty->hindex == VTY_MAXHIST)
1077 vty->hindex = 0;
1078
1079 vty->hp = vty->hindex;
1080}
1081
1082/* #define TELNET_OPTION_DEBUG */
1083
1084/* Get telnet window size. */
1085static int
1086vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1087{
1088#ifdef TELNET_OPTION_DEBUG
1089 int i;
1090
1091 for (i = 0; i < nbytes; i++)
1092 {
1093 switch (buf[i])
1094 {
1095 case IAC:
1096 vty_out (vty, "IAC ");
1097 break;
1098 case WILL:
1099 vty_out (vty, "WILL ");
1100 break;
1101 case WONT:
1102 vty_out (vty, "WONT ");
1103 break;
1104 case DO:
1105 vty_out (vty, "DO ");
1106 break;
1107 case DONT:
1108 vty_out (vty, "DONT ");
1109 break;
1110 case SB:
1111 vty_out (vty, "SB ");
1112 break;
1113 case SE:
1114 vty_out (vty, "SE ");
1115 break;
1116 case TELOPT_ECHO:
1117 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1118 break;
1119 case TELOPT_SGA:
1120 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1121 break;
1122 case TELOPT_NAWS:
1123 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1124 break;
1125 default:
1126 vty_out (vty, "%x ", buf[i]);
1127 break;
1128 }
1129 }
1130 vty_out (vty, "%s", VTY_NEWLINE);
1131
1132#endif /* TELNET_OPTION_DEBUG */
1133
1134 switch (buf[0])
1135 {
1136 case SB:
1137 buffer_reset(vty->sb_buffer);
1138 vty->iac_sb_in_progress = 1;
1139 return 0;
1140 break;
1141 case SE:
1142 {
1143 char *buffer = (char *)vty->sb_buffer->head->data;
1144 int length = vty->sb_buffer->length;
1145
1146 if (buffer == NULL)
1147 return 0;
1148
1149 if (!vty->iac_sb_in_progress)
1150 return 0;
1151
1152 if (buffer[0] == '\0')
1153 {
1154 vty->iac_sb_in_progress = 0;
1155 return 0;
1156 }
1157 switch (buffer[0])
1158 {
1159 case TELOPT_NAWS:
1160 if (length < 5)
1161 break;
1162 vty->width = buffer[2];
1163 vty->height = vty->lines >= 0 ? vty->lines : buffer[4];
1164 break;
1165 }
1166 vty->iac_sb_in_progress = 0;
1167 return 0;
1168 break;
1169 }
1170 default:
1171 break;
1172 }
1173 return 1;
1174}
1175
1176/* Execute current command line. */
1177static int
1178vty_execute (struct vty *vty)
1179{
1180 int ret;
1181
1182 ret = CMD_SUCCESS;
1183
1184 switch (vty->node)
1185 {
1186 case AUTH_NODE:
1187 case AUTH_ENABLE_NODE:
1188 vty_auth (vty, vty->buf);
1189 break;
1190 default:
1191 ret = vty_command (vty, vty->buf);
1192 if (vty->type == VTY_TERM)
1193 vty_hist_add (vty);
1194 break;
1195 }
1196
1197 /* Clear command line buffer. */
1198 vty->cp = vty->length = 0;
1199 vty_clear_buf (vty);
1200
1201 if (vty->status != VTY_CLOSE
1202 && vty->status != VTY_START
1203 && vty->status != VTY_CONTINUE)
1204 vty_prompt (vty);
1205
1206 return ret;
1207}
1208
1209#define CONTROL(X) ((X) - '@')
1210#define VTY_NORMAL 0
1211#define VTY_PRE_ESCAPE 1
1212#define VTY_ESCAPE 2
1213
1214/* Escape character command map. */
1215static void
1216vty_escape_map (unsigned char c, struct vty *vty)
1217{
1218 switch (c)
1219 {
1220 case ('A'):
1221 vty_previous_line (vty);
1222 break;
1223 case ('B'):
1224 vty_next_line (vty);
1225 break;
1226 case ('C'):
1227 vty_forward_char (vty);
1228 break;
1229 case ('D'):
1230 vty_backward_char (vty);
1231 break;
1232 default:
1233 break;
1234 }
1235
1236 /* Go back to normal mode. */
1237 vty->escape = VTY_NORMAL;
1238}
1239
1240/* Quit print out to the buffer. */
1241static void
1242vty_buffer_reset (struct vty *vty)
1243{
1244 buffer_reset (vty->obuf);
1245 vty_prompt (vty);
1246 vty_redraw_line (vty);
1247}
1248
1249/* Read data via vty socket. */
1250static int
1251vty_read (struct thread *thread)
1252{
1253 int i;
1254 int ret;
1255 int nbytes;
1256 unsigned char buf[VTY_READ_BUFSIZ];
1257
1258 int vty_sock = THREAD_FD (thread);
1259 struct vty *vty = THREAD_ARG (thread);
1260 vty->t_read = NULL;
1261
1262 /* Read raw data from socket */
1263 nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ);
1264 if (nbytes <= 0)
1265 vty->status = VTY_CLOSE;
1266
1267 for (i = 0; i < nbytes; i++)
1268 {
1269 if (buf[i] == IAC)
1270 {
1271 if (!vty->iac)
1272 {
1273 vty->iac = 1;
1274 continue;
1275 }
1276 else
1277 {
1278 vty->iac = 0;
1279 }
1280 }
1281
1282 if (vty->iac_sb_in_progress && !vty->iac)
1283 {
1284 buffer_putc(vty->sb_buffer, buf[i]);
1285 continue;
1286 }
1287
1288 if (vty->iac)
1289 {
1290 /* In case of telnet command */
1291 ret = vty_telnet_option (vty, buf + i, nbytes - i);
1292 vty->iac = 0;
1293 i += ret;
1294 continue;
1295 }
1296
1297 if (vty->status == VTY_MORE)
1298 {
1299 switch (buf[i])
1300 {
1301 case CONTROL('C'):
1302 case 'q':
1303 case 'Q':
1304 if (vty->output_func)
1305 (*vty->output_func) (vty, 1);
1306 vty_buffer_reset (vty);
1307 break;
1308 default:
1309 if (vty->output_func)
1310 (*vty->output_func) (vty, 0);
1311 break;
1312 }
1313 continue;
1314 }
1315
1316 /* Escape character. */
1317 if (vty->escape == VTY_ESCAPE)
1318 {
1319 vty_escape_map (buf[i], vty);
1320 continue;
1321 }
1322
1323 /* Pre-escape status. */
1324 if (vty->escape == VTY_PRE_ESCAPE)
1325 {
1326 switch (buf[i])
1327 {
1328 case '[':
1329 vty->escape = VTY_ESCAPE;
1330 break;
1331 case 'b':
1332 vty_backward_word (vty);
1333 vty->escape = VTY_NORMAL;
1334 break;
1335 case 'f':
1336 vty_forward_word (vty);
1337 vty->escape = VTY_NORMAL;
1338 break;
1339 case 'd':
1340 vty_forward_kill_word (vty);
1341 vty->escape = VTY_NORMAL;
1342 break;
1343 case CONTROL('H'):
1344 case 0x7f:
1345 vty_backward_kill_word (vty);
1346 vty->escape = VTY_NORMAL;
1347 break;
1348 default:
1349 vty->escape = VTY_NORMAL;
1350 break;
1351 }
1352 continue;
1353 }
1354
1355 switch (buf[i])
1356 {
1357 case CONTROL('A'):
1358 vty_beginning_of_line (vty);
1359 break;
1360 case CONTROL('B'):
1361 vty_backward_char (vty);
1362 break;
1363 case CONTROL('C'):
1364 vty_stop_input (vty);
1365 break;
1366 case CONTROL('D'):
1367 vty_delete_char (vty);
1368 break;
1369 case CONTROL('E'):
1370 vty_end_of_line (vty);
1371 break;
1372 case CONTROL('F'):
1373 vty_forward_char (vty);
1374 break;
1375 case CONTROL('H'):
1376 case 0x7f:
1377 vty_delete_backward_char (vty);
1378 break;
1379 case CONTROL('K'):
1380 vty_kill_line (vty);
1381 break;
1382 case CONTROL('N'):
1383 vty_next_line (vty);
1384 break;
1385 case CONTROL('P'):
1386 vty_previous_line (vty);
1387 break;
1388 case CONTROL('T'):
1389 vty_transpose_chars (vty);
1390 break;
1391 case CONTROL('U'):
1392 vty_kill_line_from_beginning (vty);
1393 break;
1394 case CONTROL('W'):
1395 vty_backward_kill_word (vty);
1396 break;
1397 case CONTROL('Z'):
1398 vty_end_config (vty);
1399 break;
1400 case '\n':
1401 case '\r':
1402 vty_out (vty, "%s", VTY_NEWLINE);
1403 vty_execute (vty);
1404 break;
1405 case '\t':
1406 vty_complete_command (vty);
1407 break;
1408 case '?':
1409 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1410 vty_self_insert (vty, buf[i]);
1411 else
1412 vty_describe_command (vty);
1413 break;
1414 case '\033':
1415 if (i + 1 < nbytes && buf[i + 1] == '[')
1416 {
1417 vty->escape = VTY_ESCAPE;
1418 i++;
1419 }
1420 else
1421 vty->escape = VTY_PRE_ESCAPE;
1422 break;
1423 default:
1424 if (buf[i] > 31 && buf[i] < 127)
1425 vty_self_insert (vty, buf[i]);
1426 break;
1427 }
1428 }
1429
1430 /* Check status. */
1431 if (vty->status == VTY_CLOSE)
1432 vty_close (vty);
1433 else
1434 {
1435 vty_event (VTY_WRITE, vty_sock, vty);
1436 vty_event (VTY_READ, vty_sock, vty);
1437 }
1438 return 0;
1439}
1440
1441/* Flush buffer to the vty. */
1442static int
1443vty_flush (struct thread *thread)
1444{
1445 int erase;
1446 int dont_more;
1447 int vty_sock = THREAD_FD (thread);
1448 struct vty *vty = THREAD_ARG (thread);
1449 vty->t_write = NULL;
1450
1451 /* Tempolary disable read thread. */
1452 if (vty->lines == 0)
1453 if (vty->t_read)
1454 {
1455 thread_cancel (vty->t_read);
1456 vty->t_read = NULL;
1457 }
1458
1459 /* Function execution continue. */
1460 if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
1461 {
1462 if (vty->status == VTY_CONTINUE)
1463 erase = 1;
1464 else
1465 erase = 0;
1466
1467 if (vty->output_func == NULL)
1468 dont_more = 1;
1469 else
1470 dont_more = 0;
1471
1472 if (vty->lines == 0)
1473 {
1474 erase = 0;
1475 dont_more = 1;
1476 }
1477
1478 buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
1479
1480 if (vty->status == VTY_CLOSE)
1481 {
1482 vty_close (vty);
1483 return 0;
1484 }
1485
1486 if (vty->output_func == NULL)
1487 {
1488 vty->status = VTY_NORMAL;
1489 vty_prompt (vty);
1490 vty_event (VTY_WRITE, vty_sock, vty);
1491 }
1492 else
1493 vty->status = VTY_MORE;
1494
1495 if (vty->lines == 0)
1496 {
1497 if (vty->output_func == NULL)
1498 vty_event (VTY_READ, vty_sock, vty);
1499 else
1500 {
1501 if (vty->output_func)
1502 (*vty->output_func) (vty, 0);
1503 vty_event (VTY_WRITE, vty_sock, vty);
1504 }
1505 }
1506 }
1507 else
1508 {
1509 if (vty->status == VTY_MORE)
1510 erase = 1;
1511 else
1512 erase = 0;
1513
1514 if (vty->lines == 0)
1515 buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
1516 else
1517 buffer_flush_window (vty->obuf, vty->fd, vty->width,
1518 vty->lines >= 0 ? vty->lines : vty->height,
1519 erase, 0);
1520
1521 if (buffer_empty (vty->obuf))
1522 {
1523 if (vty->status == VTY_CLOSE)
1524 vty_close (vty);
1525 else
1526 {
1527 vty->status = VTY_NORMAL;
1528
1529 if (vty->lines == 0)
1530 vty_event (VTY_READ, vty_sock, vty);
1531 }
1532 }
1533 else
1534 {
1535 vty->status = VTY_MORE;
1536
1537 if (vty->lines == 0)
1538 vty_event (VTY_WRITE, vty_sock, vty);
1539 }
1540 }
1541
1542 return 0;
1543}
1544
1545/* Create new vty structure. */
1546struct vty *
1547vty_create (int vty_sock, union sockunion *su)
1548{
1549 struct vty *vty;
1550
1551 /* Allocate new vty structure and set up default values. */
1552 vty = vty_new ();
1553 vty->fd = vty_sock;
1554 vty->type = VTY_TERM;
1555 vty->address = sockunion_su2str (su);
1556 if (no_password_check)
1557 {
1558 if (host.advanced)
1559 vty->node = ENABLE_NODE;
1560 else
1561 vty->node = VIEW_NODE;
1562 }
1563 else
1564 vty->node = AUTH_NODE;
1565 vty->fail = 0;
1566 vty->cp = 0;
1567 vty_clear_buf (vty);
1568 vty->length = 0;
1569 memset (vty->hist, 0, sizeof (vty->hist));
1570 vty->hp = 0;
1571 vty->hindex = 0;
1572 vector_set_index (vtyvec, vty_sock, vty);
1573 vty->status = VTY_NORMAL;
1574 vty->v_timeout = vty_timeout_val;
1575 if (host.lines >= 0)
1576 vty->lines = host.lines;
1577 else
1578 vty->lines = -1;
1579 vty->iac = 0;
1580 vty->iac_sb_in_progress = 0;
1581 vty->sb_buffer = buffer_new (1024);
1582
1583 if (! no_password_check)
1584 {
1585 /* Vty is not available if password isn't set. */
1586 if (host.password == NULL && host.password_encrypt == NULL)
1587 {
1588 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1589 vty->status = VTY_CLOSE;
1590 vty_close (vty);
1591 return NULL;
1592 }
1593 }
1594
1595 /* Say hello to the world. */
1596 vty_hello (vty);
1597 if (! no_password_check)
1598 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1599
1600 /* Setting up terminal. */
1601 vty_will_echo (vty);
1602 vty_will_suppress_go_ahead (vty);
1603
1604 vty_dont_linemode (vty);
1605 vty_do_window_size (vty);
1606 /* vty_dont_lflow_ahead (vty); */
1607
1608 vty_prompt (vty);
1609
1610 /* Add read/write thread. */
1611 vty_event (VTY_WRITE, vty_sock, vty);
1612 vty_event (VTY_READ, vty_sock, vty);
1613
1614 return vty;
1615}
1616
1617/* Accept connection from the network. */
1618static int
1619vty_accept (struct thread *thread)
1620{
1621 int vty_sock;
1622 struct vty *vty;
1623 union sockunion su;
1624 int ret;
1625 unsigned int on;
1626 int accept_sock;
1627 struct prefix *p = NULL;
1628 struct access_list *acl = NULL;
1629
1630 accept_sock = THREAD_FD (thread);
1631
1632 /* We continue hearing vty socket. */
1633 vty_event (VTY_SERV, accept_sock, NULL);
1634
1635 memset (&su, 0, sizeof (union sockunion));
1636
1637 /* We can handle IPv4 or IPv6 socket. */
1638 vty_sock = sockunion_accept (accept_sock, &su);
1639 if (vty_sock < 0)
1640 {
ajs6099b3b2004-11-20 02:06:59 +00001641 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
jardineb5d44e2003-12-23 08:09:43 +00001642 return -1;
1643 }
1644
1645 p = sockunion2hostprefix (&su);
1646
1647 /* VTY's accesslist apply. */
1648 if (p->family == AF_INET && vty_accesslist_name)
1649 {
1650 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1651 (access_list_apply (acl, p) == FILTER_DENY))
1652 {
1653 char *buf;
1654 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1655 (buf = sockunion_su2str (&su)));
1656 free (buf);
1657 close (vty_sock);
1658
1659 /* continue accepting connections */
1660 vty_event (VTY_SERV, accept_sock, NULL);
1661
1662 prefix_free (p);
1663
1664 return 0;
1665 }
1666 }
1667
1668#ifdef HAVE_IPV6
1669 /* VTY's ipv6 accesslist apply. */
1670 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1671 {
1672 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1673 (access_list_apply (acl, p) == FILTER_DENY))
1674 {
1675 char *buf;
1676 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1677 (buf = sockunion_su2str (&su)));
1678 free (buf);
1679 close (vty_sock);
1680
1681 /* continue accepting connections */
1682 vty_event (VTY_SERV, accept_sock, NULL);
1683
1684 prefix_free (p);
1685
1686 return 0;
1687 }
1688 }
1689#endif /* HAVE_IPV6 */
1690
1691 prefix_free (p);
1692
1693 on = 1;
1694 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1695 (char *) &on, sizeof (on));
1696 if (ret < 0)
1697 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
ajs6099b3b2004-11-20 02:06:59 +00001698 safe_strerror (errno));
jardineb5d44e2003-12-23 08:09:43 +00001699
1700 vty = vty_create (vty_sock, &su);
1701
1702 return 0;
1703}
1704
1705#if defined(HAVE_IPV6) && !defined(NRL)
1706void
1707vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1708{
1709 int ret;
1710 struct addrinfo req;
1711 struct addrinfo *ainfo;
1712 struct addrinfo *ainfo_save;
1713 int sock;
1714 char port_str[BUFSIZ];
1715
1716 memset (&req, 0, sizeof (struct addrinfo));
1717 req.ai_flags = AI_PASSIVE;
1718 req.ai_family = AF_UNSPEC;
1719 req.ai_socktype = SOCK_STREAM;
1720 sprintf (port_str, "%d", port);
1721 port_str[sizeof (port_str) - 1] = '\0';
1722
1723 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1724
1725 if (ret != 0)
1726 {
1727 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1728 exit (1);
1729 }
1730
1731 ainfo_save = ainfo;
1732
1733 do
1734 {
1735 if (ainfo->ai_family != AF_INET
1736#ifdef HAVE_IPV6
1737 && ainfo->ai_family != AF_INET6
1738#endif /* HAVE_IPV6 */
1739 )
1740 continue;
1741
1742 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1743 if (sock < 0)
1744 continue;
1745
1746 sockopt_reuseaddr (sock);
1747 sockopt_reuseport (sock);
1748
1749 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1750 if (ret < 0)
1751 {
1752 close (sock); /* Avoid sd leak. */
1753 continue;
1754 }
1755
1756 ret = listen (sock, 3);
1757 if (ret < 0)
1758 {
1759 close (sock); /* Avoid sd leak. */
1760 continue;
1761 }
1762
1763 vty_event (VTY_SERV, sock, NULL);
1764 }
1765 while ((ainfo = ainfo->ai_next) != NULL);
1766
1767 freeaddrinfo (ainfo_save);
1768}
1769#endif /* HAVE_IPV6 && ! NRL */
1770
1771/* Make vty server socket. */
1772void
1773vty_serv_sock_family (unsigned short port, int family)
1774{
1775 int ret;
1776 union sockunion su;
1777 int accept_sock;
1778
1779 memset (&su, 0, sizeof (union sockunion));
1780 su.sa.sa_family = family;
1781
1782 /* Make new socket. */
1783 accept_sock = sockunion_stream_socket (&su);
1784 if (accept_sock < 0)
1785 return;
1786
1787 /* This is server, so reuse address. */
1788 sockopt_reuseaddr (accept_sock);
1789 sockopt_reuseport (accept_sock);
1790
1791 /* Bind socket to universal address and given port. */
1792 ret = sockunion_bind (accept_sock, &su, port, NULL);
1793 if (ret < 0)
1794 {
1795 close (accept_sock); /* Avoid sd leak. */
1796 return;
1797 }
1798
1799 /* Listen socket under queue 3. */
1800 ret = listen (accept_sock, 3);
1801 if (ret < 0)
1802 {
1803 zlog (NULL, LOG_WARNING, "can't listen socket");
1804 close (accept_sock); /* Avoid sd leak. */
1805 return;
1806 }
1807
1808 /* Add vty server event. */
1809 vty_event (VTY_SERV, accept_sock, NULL);
1810}
1811
1812#ifdef VTYSH
1813/* For sockaddr_un. */
1814#include <sys/un.h>
1815
1816/* VTY shell UNIX domain socket. */
1817void
1818vty_serv_un (char *path)
1819{
1820 int ret;
1821 int sock, len;
1822 struct sockaddr_un serv;
1823 mode_t old_mask;
1824
1825 /* First of all, unlink existing socket */
1826 unlink (path);
1827
1828 /* Set umask */
1829 old_mask = umask (0077);
1830
1831 /* Make UNIX domain socket. */
1832 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1833 if (sock < 0)
1834 {
1835 perror ("sock");
1836 return;
1837 }
1838
1839 /* Make server socket. */
1840 memset (&serv, 0, sizeof (struct sockaddr_un));
1841 serv.sun_family = AF_UNIX;
1842 strncpy (serv.sun_path, path, strlen (path));
1843#ifdef HAVE_SUN_LEN
1844 len = serv.sun_len = SUN_LEN(&serv);
1845#else
1846 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1847#endif /* HAVE_SUN_LEN */
1848
1849 ret = bind (sock, (struct sockaddr *) &serv, len);
1850 if (ret < 0)
1851 {
1852 perror ("bind");
1853 close (sock); /* Avoid sd leak. */
1854 return;
1855 }
1856
1857 ret = listen (sock, 5);
1858 if (ret < 0)
1859 {
1860 perror ("listen");
1861 close (sock); /* Avoid sd leak. */
1862 return;
1863 }
1864
1865 umask (old_mask);
1866
1867 vty_event (VTYSH_SERV, sock, NULL);
1868}
1869
1870/* #define VTYSH_DEBUG 1 */
1871
1872static int
1873vtysh_accept (struct thread *thread)
1874{
1875 int accept_sock;
1876 int sock;
1877 int client_len;
1878 struct sockaddr_un client;
1879 struct vty *vty;
1880
1881 accept_sock = THREAD_FD (thread);
1882
1883 vty_event (VTYSH_SERV, accept_sock, NULL);
1884
1885 memset (&client, 0, sizeof (struct sockaddr_un));
1886 client_len = sizeof (struct sockaddr_un);
1887
1888 sock = accept (accept_sock, (struct sockaddr *) &client, &client_len);
1889
1890 if (sock < 0)
1891 {
ajs6099b3b2004-11-20 02:06:59 +00001892 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
jardineb5d44e2003-12-23 08:09:43 +00001893 return -1;
1894 }
1895
1896#ifdef VTYSH_DEBUG
1897 printf ("VTY shell accept\n");
1898#endif /* VTYSH_DEBUG */
1899
1900 vty = vty_new ();
1901 vty->fd = sock;
1902 vty->type = VTY_SHELL_SERV;
1903 vty->node = VIEW_NODE;
1904
1905 vty_event (VTYSH_READ, sock, vty);
1906
1907 return 0;
1908}
1909
1910static int
1911vtysh_read (struct thread *thread)
1912{
1913 int ret;
1914 int sock;
1915 int nbytes;
1916 struct vty *vty;
1917 unsigned char buf[VTY_READ_BUFSIZ];
1918 u_char header[4] = {0, 0, 0, 0};
1919
1920 sock = THREAD_FD (thread);
1921 vty = THREAD_ARG (thread);
1922 vty->t_read = NULL;
1923
1924 nbytes = read (sock, buf, VTY_READ_BUFSIZ);
1925 if (nbytes <= 0)
1926 {
1927 vty_close (vty);
1928#ifdef VTYSH_DEBUG
1929 printf ("close vtysh\n");
1930#endif /* VTYSH_DEBUG */
1931 return 0;
1932 }
1933
1934#ifdef VTYSH_DEBUG
1935 printf ("line: %s\n", buf);
1936#endif /* VTYSH_DEBUG */
1937
1938 vty_ensure (vty, nbytes);
1939 memcpy (vty->buf, buf, nbytes);
1940
1941 /* Pass this line to parser. */
1942 ret = vty_execute (vty);
1943
1944 vty_clear_buf (vty);
1945
1946 /* Return result. */
1947#ifdef VTYSH_DEBUG
1948 printf ("result: %d\n", ret);
1949 printf ("vtysh node: %d\n", vty->node);
1950#endif /* VTYSH_DEBUG */
1951
1952 header[3] = ret;
1953 write (vty->fd, header, 4);
1954
1955 vty_event (VTYSH_READ, sock, vty);
1956
1957 return 0;
1958}
1959#endif /* VTYSH */
1960
1961/* Determine address family to bind. */
1962void
1963vty_serv_sock (const char *hostname, unsigned short port, char *path)
1964{
1965 /* If port is set to 0, do not listen on TCP/IP at all! */
1966 if (port)
1967 {
1968
1969#ifdef HAVE_IPV6
1970#ifdef NRL
1971 vty_serv_sock_family (port, AF_INET);
1972 vty_serv_sock_family (port, AF_INET6);
1973#else /* ! NRL */
1974 vty_serv_sock_addrinfo (hostname, port);
1975#endif /* NRL*/
1976#else /* ! HAVE_IPV6 */
1977 vty_serv_sock_family (port, AF_INET);
1978#endif /* HAVE_IPV6 */
1979 }
1980
1981#ifdef VTYSH
1982 vty_serv_un (path);
1983#endif /* VTYSH */
1984}
1985
1986/* Close vty interface. */
1987void
1988vty_close (struct vty *vty)
1989{
1990 int i;
1991
1992 /* Cancel threads.*/
1993 if (vty->t_read)
1994 thread_cancel (vty->t_read);
1995 if (vty->t_write)
1996 thread_cancel (vty->t_write);
1997 if (vty->t_timeout)
1998 thread_cancel (vty->t_timeout);
1999 if (vty->t_output)
2000 thread_cancel (vty->t_output);
2001
2002 /* Flush buffer. */
2003 if (! buffer_empty (vty->obuf))
2004 buffer_flush_all (vty->obuf, vty->fd);
2005
2006 /* Free input buffer. */
2007 buffer_free (vty->obuf);
2008
2009 /* Free SB buffer. */
2010 if (vty->sb_buffer)
2011 buffer_free (vty->sb_buffer);
2012
2013 /* Free command history. */
2014 for (i = 0; i < VTY_MAXHIST; i++)
2015 if (vty->hist[i])
2016 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2017
2018 /* Unset vector. */
2019 vector_unset (vtyvec, vty->fd);
2020
2021 /* Close socket. */
2022 if (vty->fd > 0)
2023 close (vty->fd);
2024
2025 if (vty->address)
2026 XFREE (0, vty->address);
2027 if (vty->buf)
2028 XFREE (MTYPE_VTY, vty->buf);
2029
2030 /* Check configure. */
2031 vty_config_unlock (vty);
2032
2033 /* OK free vty. */
2034 XFREE (MTYPE_VTY, vty);
2035}
2036
2037/* When time out occur output message then close connection. */
2038static int
2039vty_timeout (struct thread *thread)
2040{
2041 struct vty *vty;
2042
2043 vty = THREAD_ARG (thread);
2044 vty->t_timeout = NULL;
2045 vty->v_timeout = 0;
2046
2047 /* Clear buffer*/
2048 buffer_reset (vty->obuf);
2049 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2050
2051 /* Close connection. */
2052 vty->status = VTY_CLOSE;
2053 vty_close (vty);
2054
2055 return 0;
2056}
2057
2058/* Read up configuration file from file_name. */
2059static void
2060vty_read_file (FILE *confp)
2061{
2062 int ret;
2063 struct vty *vty;
2064
2065 vty = vty_new ();
2066 vty->fd = 0; /* stdout */
2067 vty->type = VTY_TERM;
2068 vty->node = CONFIG_NODE;
2069
2070 /* Execute configuration file */
2071 ret = config_from_file (vty, confp);
2072
2073 if (ret != CMD_SUCCESS)
2074 {
2075 switch (ret)
2076 {
2077 case CMD_ERR_AMBIGUOUS:
2078 fprintf (stderr, "Ambiguous command.\n");
2079 break;
2080 case CMD_ERR_NO_MATCH:
2081 fprintf (stderr, "There is no such command.\n");
2082 break;
2083 }
2084 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2085 vty->buf);
2086 vty_close (vty);
2087 exit (1);
2088 }
2089
2090 vty_close (vty);
2091}
2092
2093FILE *
2094vty_use_backup_config (char *fullpath)
2095{
2096 char *fullpath_sav, *fullpath_tmp;
2097 FILE *ret = NULL;
2098 struct stat buf;
2099 int tmp, sav;
2100 int c;
2101 char buffer[512];
2102
2103 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2104 strcpy (fullpath_sav, fullpath);
2105 strcat (fullpath_sav, CONF_BACKUP_EXT);
2106 if (stat (fullpath_sav, &buf) == -1)
2107 {
2108 free (fullpath_sav);
2109 return NULL;
2110 }
2111
2112 fullpath_tmp = malloc (strlen (fullpath) + 8);
2113 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2114
2115 /* Open file to configuration write. */
2116 tmp = mkstemp (fullpath_tmp);
2117 if (tmp < 0)
2118 {
2119 free (fullpath_sav);
2120 free (fullpath_tmp);
2121 return NULL;
2122 }
2123
2124 sav = open (fullpath_sav, O_RDONLY);
2125 if (sav < 0)
2126 {
2127 free (fullpath_sav);
2128 free (fullpath_tmp);
2129 unlink (fullpath_tmp);
2130 return NULL;
2131 }
2132
2133 while((c = read (sav, buffer, 512)) > 0)
2134 write (tmp, buffer, c);
2135
2136 close (sav);
2137 close (tmp);
2138
2139 if (link (fullpath_tmp, fullpath) == 0)
2140 ret = fopen (fullpath, "r");
2141
2142 unlink (fullpath_tmp);
2143
2144 free (fullpath_sav);
2145 free (fullpath_tmp);
2146 return fopen (fullpath, "r");
2147}
2148
2149/* Read up configuration file from file_name. */
2150void
2151vty_read_config (char *config_file,
2152 char *config_current_dir,
2153 char *config_default_dir)
2154{
2155 char *cwd;
2156 FILE *confp = NULL;
2157 char *fullpath;
2158
2159 /* If -f flag specified. */
2160 if (config_file != NULL)
2161 {
2162 if (! IS_DIRECTORY_SEP (config_file[0]))
2163 {
2164 cwd = getcwd (NULL, MAXPATHLEN);
2165 fullpath = XMALLOC (MTYPE_TMP,
2166 strlen (cwd) + strlen (config_file) + 2);
2167 sprintf (fullpath, "%s/%s", cwd, config_file);
2168 }
2169 else
2170 fullpath = config_file;
2171
2172 confp = fopen (fullpath, "r");
2173
2174 if (confp == NULL)
2175 {
2176 confp = vty_use_backup_config (fullpath);
2177 if (confp)
2178 fprintf (stderr, "WARNING: using backup configuration file!\n");
2179 else
2180 {
2181 fprintf (stderr, "can't open configuration file [%s]\n",
2182 config_file);
2183 exit(1);
2184 }
2185 }
2186 }
2187 else
2188 {
2189 /* Relative path configuration file open. */
2190 if (config_current_dir)
2191 {
2192 confp = fopen (config_current_dir, "r");
2193 if (confp == NULL)
2194 {
2195 confp = vty_use_backup_config (config_current_dir);
2196 if (confp)
2197 fprintf (stderr, "WARNING: using backup configuration file!\n");
2198 }
2199 }
2200
2201 /* If there is no relative path exists, open system default file. */
2202 if (confp == NULL)
2203 {
2204#ifdef VTYSH
2205 int ret;
2206 struct stat conf_stat;
2207
2208 /* !!!!PLEASE LEAVE!!!!
2209 This is NEEDED for use with vtysh -b, or else you can get
2210 a real configuration food fight with a lot garbage in the
2211 merged configuration file it creates coming from the per
2212 daemon configuration files. This also allows the daemons
2213 to start if there default configuration file is not
2214 present or ignore them, as needed when using vtysh -b to
2215 configure the daemons at boot - MAG */
2216
2217 /* Stat for vtysh Zebra.conf, if found startup and wait for
2218 boot configuration */
2219
2220 if ( strstr(config_default_dir, "vtysh") == NULL)
2221 {
2222 ret = stat (integrate_default, &conf_stat);
2223 if (ret >= 0)
2224 {
2225 return;
2226 }
2227 }
2228#endif /* VTYSH */
2229
2230 confp = fopen (config_default_dir, "r");
2231 if (confp == NULL)
2232 {
2233 confp = vty_use_backup_config (config_default_dir);
2234 if (confp)
2235 {
2236 fprintf (stderr, "WARNING: using backup configuration file!\n");
2237 fullpath = config_default_dir;
2238 }
2239 else
2240 {
2241 fprintf (stderr, "can't open configuration file [%s]\n",
2242 config_default_dir);
2243 exit (1);
2244 }
2245 }
2246 else
2247 fullpath = config_default_dir;
2248 }
2249 else
2250 {
2251 /* Rleative path configuration file. */
2252 cwd = getcwd (NULL, MAXPATHLEN);
2253 fullpath = XMALLOC (MTYPE_TMP,
2254 strlen (cwd) + strlen (config_current_dir) + 2);
2255 sprintf (fullpath, "%s/%s", cwd, config_current_dir);
2256 }
2257 }
2258 vty_read_file (confp);
2259
2260 fclose (confp);
2261
2262 host_config_set (fullpath);
2263}
2264
2265/* Small utility function which output log to the VTY. */
2266void
2267vty_log (const char *proto_str, const char *format, va_list va)
2268{
2269 int i;
2270 struct vty *vty;
2271
2272 for (i = 0; i < vector_max (vtyvec); i++)
2273 if ((vty = vector_slot (vtyvec, i)) != NULL)
2274 if (vty->monitor)
2275 vty_log_out (vty, proto_str, format, va);
2276}
2277
2278int
2279vty_config_lock (struct vty *vty)
2280{
2281 if (vty_config == 0)
2282 {
2283 vty->config = 1;
2284 vty_config = 1;
2285 }
2286 return vty->config;
2287}
2288
2289int
2290vty_config_unlock (struct vty *vty)
2291{
2292 if (vty_config == 1 && vty->config == 1)
2293 {
2294 vty->config = 0;
2295 vty_config = 0;
2296 }
2297 return vty->config;
2298}
2299
2300/* Master of the threads. */
2301extern struct thread_master *master;
2302/* struct thread_master *master; */
2303
2304static void
2305vty_event (enum event event, int sock, struct vty *vty)
2306{
2307 struct thread *vty_serv_thread;
2308
2309 switch (event)
2310 {
2311 case VTY_SERV:
2312 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2313 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2314 break;
2315#ifdef VTYSH
2316 case VTYSH_SERV:
2317 thread_add_read (master, vtysh_accept, vty, sock);
2318 break;
2319 case VTYSH_READ:
2320 thread_add_read (master, vtysh_read, vty, sock);
2321 break;
2322#endif /* VTYSH */
2323 case VTY_READ:
2324 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2325
2326 /* Time out treatment. */
2327 if (vty->v_timeout)
2328 {
2329 if (vty->t_timeout)
2330 thread_cancel (vty->t_timeout);
2331 vty->t_timeout =
2332 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2333 }
2334 break;
2335 case VTY_WRITE:
2336 if (! vty->t_write)
2337 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2338 break;
2339 case VTY_TIMEOUT_RESET:
2340 if (vty->t_timeout)
2341 {
2342 thread_cancel (vty->t_timeout);
2343 vty->t_timeout = NULL;
2344 }
2345 if (vty->v_timeout)
2346 {
2347 vty->t_timeout =
2348 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2349 }
2350 break;
2351 }
2352}
2353
2354DEFUN (config_who,
2355 config_who_cmd,
2356 "who",
2357 "Display who is on vty\n")
2358{
2359 int i;
2360 struct vty *v;
2361
2362 for (i = 0; i < vector_max (vtyvec); i++)
2363 if ((v = vector_slot (vtyvec, i)) != NULL)
2364 vty_out (vty, "%svty[%d] connected from %s.%s",
2365 v->config ? "*" : " ",
2366 i, v->address, VTY_NEWLINE);
2367 return CMD_SUCCESS;
2368}
2369
2370/* Move to vty configuration mode. */
2371DEFUN (line_vty,
2372 line_vty_cmd,
2373 "line vty",
2374 "Configure a terminal line\n"
2375 "Virtual terminal\n")
2376{
2377 vty->node = VTY_NODE;
2378 return CMD_SUCCESS;
2379}
2380
2381/* Set time out value. */
2382int
2383exec_timeout (struct vty *vty, char *min_str, char *sec_str)
2384{
2385 unsigned long timeout = 0;
2386
2387 /* min_str and sec_str are already checked by parser. So it must be
2388 all digit string. */
2389 if (min_str)
2390 {
2391 timeout = strtol (min_str, NULL, 10);
2392 timeout *= 60;
2393 }
2394 if (sec_str)
2395 timeout += strtol (sec_str, NULL, 10);
2396
2397 vty_timeout_val = timeout;
2398 vty->v_timeout = timeout;
2399 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2400
2401
2402 return CMD_SUCCESS;
2403}
2404
2405DEFUN (exec_timeout_min,
2406 exec_timeout_min_cmd,
2407 "exec-timeout <0-35791>",
2408 "Set timeout value\n"
2409 "Timeout value in minutes\n")
2410{
2411 return exec_timeout (vty, argv[0], NULL);
2412}
2413
2414DEFUN (exec_timeout_sec,
2415 exec_timeout_sec_cmd,
2416 "exec-timeout <0-35791> <0-2147483>",
2417 "Set the EXEC timeout\n"
2418 "Timeout in minutes\n"
2419 "Timeout in seconds\n")
2420{
2421 return exec_timeout (vty, argv[0], argv[1]);
2422}
2423
2424DEFUN (no_exec_timeout,
2425 no_exec_timeout_cmd,
2426 "no exec-timeout",
2427 NO_STR
2428 "Set the EXEC timeout\n")
2429{
2430 return exec_timeout (vty, NULL, NULL);
2431}
2432
2433/* Set vty access class. */
2434DEFUN (vty_access_class,
2435 vty_access_class_cmd,
2436 "access-class WORD",
2437 "Filter connections based on an IP access list\n"
2438 "IP access list\n")
2439{
2440 if (vty_accesslist_name)
2441 XFREE(MTYPE_VTY, vty_accesslist_name);
2442
2443 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2444
2445 return CMD_SUCCESS;
2446}
2447
2448/* Clear vty access class. */
2449DEFUN (no_vty_access_class,
2450 no_vty_access_class_cmd,
2451 "no access-class [WORD]",
2452 NO_STR
2453 "Filter connections based on an IP access list\n"
2454 "IP access list\n")
2455{
2456 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2457 {
2458 vty_out (vty, "Access-class is not currently applied to vty%s",
2459 VTY_NEWLINE);
2460 return CMD_WARNING;
2461 }
2462
2463 XFREE(MTYPE_VTY, vty_accesslist_name);
2464
2465 vty_accesslist_name = NULL;
2466
2467 return CMD_SUCCESS;
2468}
2469
2470#ifdef HAVE_IPV6
2471/* Set vty access class. */
2472DEFUN (vty_ipv6_access_class,
2473 vty_ipv6_access_class_cmd,
2474 "ipv6 access-class WORD",
2475 IPV6_STR
2476 "Filter connections based on an IP access list\n"
2477 "IPv6 access list\n")
2478{
2479 if (vty_ipv6_accesslist_name)
2480 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2481
2482 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2483
2484 return CMD_SUCCESS;
2485}
2486
2487/* Clear vty access class. */
2488DEFUN (no_vty_ipv6_access_class,
2489 no_vty_ipv6_access_class_cmd,
2490 "no ipv6 access-class [WORD]",
2491 NO_STR
2492 IPV6_STR
2493 "Filter connections based on an IP access list\n"
2494 "IPv6 access list\n")
2495{
2496 if (! vty_ipv6_accesslist_name ||
2497 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2498 {
2499 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2500 VTY_NEWLINE);
2501 return CMD_WARNING;
2502 }
2503
2504 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2505
2506 vty_ipv6_accesslist_name = NULL;
2507
2508 return CMD_SUCCESS;
2509}
2510#endif /* HAVE_IPV6 */
2511
2512/* vty login. */
2513DEFUN (vty_login,
2514 vty_login_cmd,
2515 "login",
2516 "Enable password checking\n")
2517{
2518 no_password_check = 0;
2519 return CMD_SUCCESS;
2520}
2521
2522DEFUN (no_vty_login,
2523 no_vty_login_cmd,
2524 "no login",
2525 NO_STR
2526 "Enable password checking\n")
2527{
2528 no_password_check = 1;
2529 return CMD_SUCCESS;
2530}
2531
2532DEFUN (service_advanced_vty,
2533 service_advanced_vty_cmd,
2534 "service advanced-vty",
2535 "Set up miscellaneous service\n"
2536 "Enable advanced mode vty interface\n")
2537{
2538 host.advanced = 1;
2539 return CMD_SUCCESS;
2540}
2541
2542DEFUN (no_service_advanced_vty,
2543 no_service_advanced_vty_cmd,
2544 "no service advanced-vty",
2545 NO_STR
2546 "Set up miscellaneous service\n"
2547 "Enable advanced mode vty interface\n")
2548{
2549 host.advanced = 0;
2550 return CMD_SUCCESS;
2551}
2552
2553DEFUN (terminal_monitor,
2554 terminal_monitor_cmd,
2555 "terminal monitor",
2556 "Set terminal line parameters\n"
2557 "Copy debug output to the current terminal line\n")
2558{
2559 vty->monitor = 1;
2560 return CMD_SUCCESS;
2561}
2562
2563DEFUN (terminal_no_monitor,
2564 terminal_no_monitor_cmd,
2565 "terminal no monitor",
2566 "Set terminal line parameters\n"
2567 NO_STR
2568 "Copy debug output to the current terminal line\n")
2569{
2570 vty->monitor = 0;
2571 return CMD_SUCCESS;
2572}
2573
2574DEFUN (show_history,
2575 show_history_cmd,
2576 "show history",
2577 SHOW_STR
2578 "Display the session command history\n")
2579{
2580 int index;
2581
2582 for (index = vty->hindex + 1; index != vty->hindex;)
2583 {
2584 if (index == VTY_MAXHIST)
2585 {
2586 index = 0;
2587 continue;
2588 }
2589
2590 if (vty->hist[index] != NULL)
2591 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2592
2593 index++;
2594 }
2595
2596 return CMD_SUCCESS;
2597}
2598
2599/* Display current configuration. */
2600int
2601vty_config_write (struct vty *vty)
2602{
2603 vty_out (vty, "line vty%s", VTY_NEWLINE);
2604
2605 if (vty_accesslist_name)
2606 vty_out (vty, " access-class %s%s",
2607 vty_accesslist_name, VTY_NEWLINE);
2608
2609 if (vty_ipv6_accesslist_name)
2610 vty_out (vty, " ipv6 access-class %s%s",
2611 vty_ipv6_accesslist_name, VTY_NEWLINE);
2612
2613 /* exec-timeout */
2614 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2615 vty_out (vty, " exec-timeout %ld %ld%s",
2616 vty_timeout_val / 60,
2617 vty_timeout_val % 60, VTY_NEWLINE);
2618
2619 /* login */
2620 if (no_password_check)
2621 vty_out (vty, " no login%s", VTY_NEWLINE);
2622
2623 vty_out (vty, "!%s", VTY_NEWLINE);
2624
2625 return CMD_SUCCESS;
2626}
2627
2628struct cmd_node vty_node =
2629{
2630 VTY_NODE,
2631 "%s(config-line)# ",
2632};
2633
2634/* Reset all VTY status. */
2635void
2636vty_reset ()
2637{
2638 int i;
2639 struct vty *vty;
2640 struct thread *vty_serv_thread;
2641
2642 for (i = 0; i < vector_max (vtyvec); i++)
2643 if ((vty = vector_slot (vtyvec, i)) != NULL)
2644 {
2645 buffer_reset (vty->obuf);
2646 vty->status = VTY_CLOSE;
2647 vty_close (vty);
2648 }
2649
2650 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2651 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2652 {
2653 thread_cancel (vty_serv_thread);
2654 vector_slot (Vvty_serv_thread, i) = NULL;
2655 close (i);
2656 }
2657
2658 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2659
2660 if (vty_accesslist_name)
2661 {
2662 XFREE(MTYPE_VTY, vty_accesslist_name);
2663 vty_accesslist_name = NULL;
2664 }
2665
2666 if (vty_ipv6_accesslist_name)
2667 {
2668 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2669 vty_ipv6_accesslist_name = NULL;
2670 }
2671}
2672
2673/* for ospf6d easy temprary reload function */
2674/* vty_reset + close accept socket */
2675void
2676vty_finish ()
2677{
2678 int i;
2679 struct vty *vty;
2680 struct thread *vty_serv_thread;
2681
2682 for (i = 0; i < vector_max (vtyvec); i++)
2683 if ((vty = vector_slot (vtyvec, i)) != NULL)
2684 {
2685 buffer_reset (vty->obuf);
2686 vty->status = VTY_CLOSE;
2687 vty_close (vty);
2688 }
2689
2690 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2691 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2692 {
2693 thread_cancel (vty_serv_thread);
2694 vector_slot (Vvty_serv_thread, i) = NULL;
2695 close (i);
2696 }
2697
2698 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2699
2700 if (vty_accesslist_name)
2701 {
2702 XFREE(MTYPE_VTY, vty_accesslist_name);
2703 vty_accesslist_name = NULL;
2704 }
2705
2706 if (vty_ipv6_accesslist_name)
2707 {
2708 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2709 vty_ipv6_accesslist_name = NULL;
2710 }
2711}
2712
2713void
2714vty_save_cwd ()
2715{
2716 char *cwd;
2717
2718 cwd = getcwd (NULL, MAXPATHLEN);
2719
2720 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2721 strcpy (vty_cwd, cwd);
2722}
2723
2724char *
2725vty_get_cwd ()
2726{
2727 return vty_cwd;
2728}
2729
2730int
2731vty_shell (struct vty *vty)
2732{
2733 return vty->type == VTY_SHELL ? 1 : 0;
2734}
2735
2736int
2737vty_shell_serv (struct vty *vty)
2738{
2739 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2740}
2741
2742void
2743vty_init_vtysh ()
2744{
2745 vtyvec = vector_init (VECTOR_MIN_SIZE);
2746}
2747
2748/* Install vty's own commands like `who' command. */
2749void
2750vty_init ()
2751{
2752 /* For further configuration read, preserve current directory. */
2753 vty_save_cwd ();
2754
2755 vtyvec = vector_init (VECTOR_MIN_SIZE);
2756
2757 /* Initilize server thread vector. */
2758 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2759
2760 /* Install bgp top node. */
2761 install_node (&vty_node, vty_config_write);
2762
2763 install_element (VIEW_NODE, &config_who_cmd);
2764 install_element (VIEW_NODE, &show_history_cmd);
2765 install_element (ENABLE_NODE, &config_who_cmd);
2766 install_element (CONFIG_NODE, &line_vty_cmd);
2767 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2768 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2769 install_element (CONFIG_NODE, &show_history_cmd);
2770 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2771 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
2772 install_element (ENABLE_NODE, &show_history_cmd);
2773
2774 install_default (VTY_NODE);
2775 install_element (VTY_NODE, &exec_timeout_min_cmd);
2776 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2777 install_element (VTY_NODE, &no_exec_timeout_cmd);
2778 install_element (VTY_NODE, &vty_access_class_cmd);
2779 install_element (VTY_NODE, &no_vty_access_class_cmd);
2780 install_element (VTY_NODE, &vty_login_cmd);
2781 install_element (VTY_NODE, &no_vty_login_cmd);
2782#ifdef HAVE_IPV6
2783 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2784 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2785#endif /* HAVE_IPV6 */
2786}