LCOV - code coverage report
Current view: top level - lib - vty.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 315 1289 24.4 %
Date: 2015-11-19 Functions: 27 98 27.6 %

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

Generated by: LCOV version 1.10