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