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