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