1 /*
2    Command interpreter routine for virtual terminal [aka TeletYpe]
3    Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
4    Copyright (C) 2013 by Open Source Routing.
5    Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
6 
7 This file is part of GNU Zebra.
8 
9 GNU Zebra is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published
11 by the Free Software Foundation; either version 2, or (at your
12 option) any later version.
13 
14 GNU Zebra is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with GNU Zebra; see the file COPYING.  If not, write to the
21 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23 
24 #include <zebra.h>
25 
26 
27 #include "memory.h"
28 #include "log.h"
29 #include <lib/version.h>
30 #include "thread.h"
31 #include "vector.h"
32 #include "vty.h"
33 #include "command.h"
34 #include "workqueue.h"
35 
36 /* Command vector which includes some level of command lists. Normally
37    each daemon maintains each own cmdvec. */
38 vector cmdvec = NULL;
39 
40 struct cmd_token token_cr;
41 char *command_cr = NULL;
42 
43 enum filter_type
44 {
45   FILTER_RELAXED,
46   FILTER_STRICT
47 };
48 
49 enum matcher_rv
50 {
51   MATCHER_OK,
52   MATCHER_COMPLETE,
53   MATCHER_INCOMPLETE,
54   MATCHER_NO_MATCH,
55   MATCHER_AMBIGUOUS,
56   MATCHER_EXCEED_ARGC_MAX
57 };
58 
59 #define MATCHER_ERROR(matcher_rv) \
60   (   (matcher_rv) == MATCHER_INCOMPLETE \
61    || (matcher_rv) == MATCHER_NO_MATCH \
62    || (matcher_rv) == MATCHER_AMBIGUOUS \
63    || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
64   )
65 
66 /* Host information structure. */
67 struct host host;
68 
69 /* Standard command node structures. */
70 static struct cmd_node auth_node =
71 {
72   AUTH_NODE,
73   "Password: ",
74 };
75 
76 static struct cmd_node view_node =
77 {
78   VIEW_NODE,
79   "%s> ",
80 };
81 
82 static struct cmd_node restricted_node =
83 {
84   RESTRICTED_NODE,
85   "%s$ ",
86 };
87 
88 static struct cmd_node auth_enable_node =
89 {
90   AUTH_ENABLE_NODE,
91   "Password: ",
92 };
93 
94 static struct cmd_node enable_node =
95 {
96   ENABLE_NODE,
97   "%s# ",
98 };
99 
100 static struct cmd_node config_node =
101 {
102   CONFIG_NODE,
103   "%s(config)# ",
104   1
105 };
106 
107 /* Default motd string. */
108 static const char *default_motd =
109 "\r\n\
110 Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
111 " QUAGGA_COPYRIGHT "\r\n\
112 " GIT_INFO "\r\n";
113 
114 
115 static const struct facility_map {
116   int facility;
117   const char *name;
118   size_t match;
119 } syslog_facilities[] =
120   {
121     { LOG_KERN, "kern", 1 },
122     { LOG_USER, "user", 2 },
123     { LOG_MAIL, "mail", 1 },
124     { LOG_DAEMON, "daemon", 1 },
125     { LOG_AUTH, "auth", 1 },
126     { LOG_SYSLOG, "syslog", 1 },
127     { LOG_LPR, "lpr", 2 },
128     { LOG_NEWS, "news", 1 },
129     { LOG_UUCP, "uucp", 2 },
130     { LOG_CRON, "cron", 1 },
131 #ifdef LOG_FTP
132     { LOG_FTP, "ftp", 1 },
133 #endif
134     { LOG_LOCAL0, "local0", 6 },
135     { LOG_LOCAL1, "local1", 6 },
136     { LOG_LOCAL2, "local2", 6 },
137     { LOG_LOCAL3, "local3", 6 },
138     { LOG_LOCAL4, "local4", 6 },
139     { LOG_LOCAL5, "local5", 6 },
140     { LOG_LOCAL6, "local6", 6 },
141     { LOG_LOCAL7, "local7", 6 },
142     { 0, NULL, 0 },
143   };
144 
145 static const char *
facility_name(int facility)146 facility_name(int facility)
147 {
148   const struct facility_map *fm;
149 
150   for (fm = syslog_facilities; fm->name; fm++)
151     if (fm->facility == facility)
152       return fm->name;
153   return "";
154 }
155 
156 static int
facility_match(const char * str)157 facility_match(const char *str)
158 {
159   const struct facility_map *fm;
160 
161   for (fm = syslog_facilities; fm->name; fm++)
162     if (!strncmp(str,fm->name,fm->match))
163       return fm->facility;
164   return -1;
165 }
166 
167 static int
level_match(const char * s)168 level_match(const char *s)
169 {
170   int level ;
171 
172   for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
173     if (!strncmp (s, zlog_priority[level], 2))
174       return level;
175   return ZLOG_DISABLED;
176 }
177 
178 /* This is called from main when a daemon is invoked with -v or --version. */
179 void
print_version(const char * progname)180 print_version (const char *progname)
181 {
182   printf ("%s version %s\n", progname, QUAGGA_VERSION);
183   printf ("%s\n", QUAGGA_COPYRIGHT);
184   printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS);
185 }
186 
187 
188 /* Utility function to concatenate argv argument into a single string
189    with inserting ' ' character between each argument.  */
190 char *
argv_concat(const char ** argv,int argc,int shift)191 argv_concat (const char **argv, int argc, int shift)
192 {
193   int i;
194   size_t len;
195   char *str;
196   char *p;
197 
198   len = 0;
199   for (i = shift; i < argc; i++)
200     len += strlen(argv[i])+1;
201   if (!len)
202     return NULL;
203   p = str = XMALLOC(MTYPE_TMP, len);
204   for (i = shift; i < argc; i++)
205     {
206       size_t arglen;
207       memcpy(p, argv[i], (arglen = strlen(argv[i])));
208       p += arglen;
209       *p++ = ' ';
210     }
211   *(p-1) = '\0';
212   return str;
213 }
214 
215 static unsigned int
cmd_hash_key(void * p)216 cmd_hash_key (void *p)
217 {
218   return (uintptr_t) p;
219 }
220 
221 static int
cmd_hash_cmp(const void * a,const void * b)222 cmd_hash_cmp (const void *a, const void *b)
223 {
224   return a == b;
225 }
226 
227 /* Install top node of command vector. */
228 void
install_node(struct cmd_node * node,int (* func)(struct vty *))229 install_node (struct cmd_node *node,
230 	      int (*func) (struct vty *))
231 {
232   vector_set_index (cmdvec, node->node, node);
233   node->func = func;
234   node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
235   node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
236 }
237 
238 /* Breaking up string into each command piece. I assume given
239    character is separated by a space character. Return value is a
240    vector which includes char ** data element. */
241 vector
cmd_make_strvec(const char * string)242 cmd_make_strvec (const char *string)
243 {
244   const char *cp, *start;
245   char *token;
246   int strlen;
247   vector strvec;
248 
249   if (string == NULL)
250     return NULL;
251 
252   cp = string;
253 
254   /* Skip white spaces. */
255   while (isspace ((int) *cp) && *cp != '\0')
256     cp++;
257 
258   /* Return if there is only white spaces */
259   if (*cp == '\0')
260     return NULL;
261 
262   if (*cp == '!' || *cp == '#')
263     return NULL;
264 
265   /* Prepare return vector. */
266   strvec = vector_init (VECTOR_MIN_SIZE);
267 
268   /* Copy each command piece and set into vector. */
269   while (1)
270     {
271       start = cp;
272       while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
273 	     *cp != '\0')
274 	cp++;
275       strlen = cp - start;
276       token = XMALLOC (MTYPE_STRVEC, strlen + 1);
277       memcpy (token, start, strlen);
278       *(token + strlen) = '\0';
279       vector_set (strvec, token);
280 
281       while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
282 	     *cp != '\0')
283 	cp++;
284 
285       if (*cp == '\0')
286 	return strvec;
287     }
288 }
289 
290 /* Free allocated string vector. */
291 void
cmd_free_strvec(vector v)292 cmd_free_strvec (vector v)
293 {
294   unsigned int i;
295   char *cp;
296 
297   if (!v)
298     return;
299 
300   for (i = 0; i < vector_active (v); i++)
301     if ((cp = vector_slot (v, i)) != NULL)
302       XFREE (MTYPE_STRVEC, cp);
303 
304   vector_free (v);
305 }
306 
307 struct format_parser_state
308 {
309   vector topvect; /* Top level vector */
310   vector intvect; /* Intermediate level vector, used when there's
311                    * a multiple in a keyword. */
312   vector curvect; /* current vector where read tokens should be
313                      appended. */
314 
315   const char *string; /* pointer to command string, not modified */
316   const char *cp; /* pointer in command string, moved along while
317                      parsing */
318   const char *dp;  /* pointer in description string, moved along while
319                      parsing */
320 
321   int in_keyword; /* flag to remember if we are in a keyword group */
322   int in_multiple; /* flag to remember if we are in a multiple group */
323   int just_read_word; /* flag to remember if the last thing we red was a
324                        * real word and not some abstract token */
325 };
326 
327 static void
format_parser_error(struct format_parser_state * state,const char * message)328 format_parser_error(struct format_parser_state *state, const char *message)
329 {
330   int offset = state->cp - state->string + 1;
331 
332   fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string);
333   fprintf(stderr, "                        %*c\n", offset, '^');
334   fprintf(stderr, "%s at offset %d.\n", message, offset);
335   fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n");
336   exit(1);
337 }
338 
339 static char *
format_parser_desc_str(struct format_parser_state * state)340 format_parser_desc_str(struct format_parser_state *state)
341 {
342   const char *cp, *start;
343   char *token;
344   int strlen;
345 
346   cp = state->dp;
347 
348   if (cp == NULL)
349     return NULL;
350 
351   /* Skip white spaces. */
352   while (isspace ((int) *cp) && *cp != '\0')
353     cp++;
354 
355   /* Return if there is only white spaces */
356   if (*cp == '\0')
357     return NULL;
358 
359   start = cp;
360 
361   while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
362     cp++;
363 
364   strlen = cp - start;
365   token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
366   memcpy (token, start, strlen);
367   *(token + strlen) = '\0';
368 
369   state->dp = cp;
370 
371   return token;
372 }
373 
374 static void
format_parser_begin_keyword(struct format_parser_state * state)375 format_parser_begin_keyword(struct format_parser_state *state)
376 {
377   struct cmd_token *token;
378   vector keyword_vect;
379 
380   if (state->in_keyword
381       || state->in_multiple)
382     format_parser_error(state, "Unexpected '{'");
383 
384   state->cp++;
385   state->in_keyword = 1;
386 
387   token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
388   token->type = TOKEN_KEYWORD;
389   token->keyword = vector_init(VECTOR_MIN_SIZE);
390 
391   keyword_vect = vector_init(VECTOR_MIN_SIZE);
392   vector_set(token->keyword, keyword_vect);
393 
394   vector_set(state->curvect, token);
395   state->curvect = keyword_vect;
396 }
397 
398 static void
format_parser_begin_multiple(struct format_parser_state * state)399 format_parser_begin_multiple(struct format_parser_state *state)
400 {
401   struct cmd_token *token;
402 
403   if (state->in_keyword == 1)
404     format_parser_error(state, "Keyword starting with '('");
405 
406   if (state->in_multiple)
407     format_parser_error(state, "Nested group");
408 
409   state->cp++;
410   state->in_multiple = 1;
411   state->just_read_word = 0;
412 
413   token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
414   token->type = TOKEN_MULTIPLE;
415   token->multiple = vector_init(VECTOR_MIN_SIZE);
416 
417   vector_set(state->curvect, token);
418   if (state->curvect != state->topvect)
419     state->intvect = state->curvect;
420   state->curvect = token->multiple;
421 }
422 
423 static void
format_parser_end_keyword(struct format_parser_state * state)424 format_parser_end_keyword(struct format_parser_state *state)
425 {
426   if (state->in_multiple
427       || !state->in_keyword)
428     format_parser_error(state, "Unexpected '}'");
429 
430   if (state->in_keyword == 1)
431     format_parser_error(state, "Empty keyword group");
432 
433   state->cp++;
434   state->in_keyword = 0;
435   state->curvect = state->topvect;
436 }
437 
438 static void
format_parser_end_multiple(struct format_parser_state * state)439 format_parser_end_multiple(struct format_parser_state *state)
440 {
441   char *dummy;
442 
443   if (!state->in_multiple)
444     format_parser_error(state, "Unexpected ')'");
445 
446   if (vector_active(state->curvect) == 0)
447     format_parser_error(state, "Empty multiple section");
448 
449   if (!state->just_read_word)
450     {
451       /* There are constructions like
452        * 'show ip ospf database ... (self-originate|)'
453        * in use.
454        * The old parser reads a description string for the
455        * word '' between |) which will never match.
456        * Simulate this behvaior by dropping the next desc
457        * string in such a case. */
458 
459       dummy = format_parser_desc_str(state);
460       XFREE(MTYPE_CMD_TOKENS, dummy);
461     }
462 
463   state->cp++;
464   state->in_multiple = 0;
465 
466   if (state->intvect)
467     state->curvect = state->intvect;
468   else
469     state->curvect = state->topvect;
470 }
471 
472 static void
format_parser_handle_pipe(struct format_parser_state * state)473 format_parser_handle_pipe(struct format_parser_state *state)
474 {
475   struct cmd_token *keyword_token;
476   vector keyword_vect;
477 
478   if (state->in_multiple)
479     {
480       state->just_read_word = 0;
481       state->cp++;
482     }
483   else if (state->in_keyword)
484     {
485       state->in_keyword = 1;
486       state->cp++;
487 
488       keyword_token = vector_slot(state->topvect,
489                                   vector_active(state->topvect) - 1);
490       keyword_vect = vector_init(VECTOR_MIN_SIZE);
491       vector_set(keyword_token->keyword, keyword_vect);
492       state->curvect = keyword_vect;
493     }
494   else
495     {
496       format_parser_error(state, "Unexpected '|'");
497     }
498 }
499 
500 static void
format_parser_read_word(struct format_parser_state * state)501 format_parser_read_word(struct format_parser_state *state)
502 {
503   const char *start;
504   int len;
505   char *cmd;
506   struct cmd_token *token;
507 
508   start = state->cp;
509 
510   while (state->cp[0] != '\0'
511          && !strchr("\r\n(){}|", state->cp[0])
512          && !isspace((int)state->cp[0]))
513     state->cp++;
514 
515   len = state->cp - start;
516   cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1);
517   memcpy(cmd, start, len);
518   cmd[len] = '\0';
519 
520   token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
521   token->type = TOKEN_TERMINAL;
522   if (strcmp (cmd, "A.B.C.D") == 0)
523     token->terminal = TERMINAL_IPV4;
524   else if (strcmp (cmd, "A.B.C.D/M") == 0)
525     token->terminal = TERMINAL_IPV4_PREFIX;
526   else if (strcmp (cmd, "X:X::X:X") == 0)
527     token->terminal = TERMINAL_IPV6;
528   else if (strcmp (cmd, "X:X::X:X/M") == 0)
529     token->terminal = TERMINAL_IPV6_PREFIX;
530   else if (cmd[0] == '[')
531     token->terminal = TERMINAL_OPTION;
532   else if (cmd[0] == '.')
533     token->terminal = TERMINAL_VARARG;
534   else if (cmd[0] == '<')
535     token->terminal = TERMINAL_RANGE;
536   else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
537     token->terminal = TERMINAL_VARIABLE;
538   else
539     token->terminal = TERMINAL_LITERAL;
540 
541   token->cmd = cmd;
542   token->desc = format_parser_desc_str(state);
543   vector_set(state->curvect, token);
544 
545   if (state->in_keyword == 1)
546     state->in_keyword = 2;
547 
548   state->just_read_word = 1;
549 }
550 
551 /**
552  * Parse a given command format string and build a tree of tokens from
553  * it that is suitable to be used by the command subsystem.
554  *
555  * @param string Command format string.
556  * @param descstr Description string.
557  * @return A vector of struct cmd_token representing the given command,
558  *         or NULL on error.
559  */
560 static vector
cmd_parse_format(const char * string,const char * descstr)561 cmd_parse_format(const char *string, const char *descstr)
562 {
563   struct format_parser_state state;
564 
565   if (string == NULL)
566     return NULL;
567 
568   memset(&state, 0, sizeof(state));
569   state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE);
570   state.cp = state.string = string;
571   state.dp = descstr;
572 
573   while (1)
574     {
575       while (isspace((int)state.cp[0]) && state.cp[0] != '\0')
576         state.cp++;
577 
578       switch (state.cp[0])
579         {
580         case '\0':
581           if (state.in_keyword
582               || state.in_multiple)
583             format_parser_error(&state, "Unclosed group/keyword");
584           return state.topvect;
585         case '{':
586           format_parser_begin_keyword(&state);
587           break;
588         case '(':
589           format_parser_begin_multiple(&state);
590           break;
591         case '}':
592           format_parser_end_keyword(&state);
593           break;
594         case ')':
595           format_parser_end_multiple(&state);
596           break;
597         case '|':
598           format_parser_handle_pipe(&state);
599           break;
600         default:
601           format_parser_read_word(&state);
602         }
603     }
604 }
605 
606 /* Return prompt character of specified node. */
607 const char *
cmd_prompt(enum node_type node)608 cmd_prompt (enum node_type node)
609 {
610   struct cmd_node *cnode;
611 
612   cnode = vector_slot (cmdvec, node);
613   return cnode->prompt;
614 }
615 
616 /* Install a command into a node. */
617 void
install_element(enum node_type ntype,struct cmd_element * cmd)618 install_element (enum node_type ntype, struct cmd_element *cmd)
619 {
620   struct cmd_node *cnode;
621 
622   /* cmd_init hasn't been called */
623   if (!cmdvec)
624     {
625       fprintf (stderr, "%s called before cmd_init, breakage likely\n",
626                __func__);
627       return;
628     }
629 
630   cnode = vector_slot (cmdvec, ntype);
631 
632   if (cnode == NULL)
633     {
634       fprintf (stderr, "Command node %d doesn't exist, please check it\n",
635 	       ntype);
636       exit (1);
637     }
638 
639   if (hash_lookup (cnode->cmd_hash, cmd) != NULL)
640     {
641 #ifdef DEV_BUILD
642       fprintf (stderr,
643                "Multiple command installs to node %d of command:\n%s\n",
644                ntype, cmd->string);
645 #endif
646       return;
647     }
648 
649   assert (hash_get (cnode->cmd_hash, cmd, hash_alloc_intern));
650 
651   vector_set (cnode->cmd_vector, cmd);
652   if (cmd->tokens == NULL)
653     cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
654 
655   if (ntype == VIEW_NODE)
656     install_element (ENABLE_NODE, cmd);
657 }
658 
659 static const unsigned char itoa64[] =
660 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
661 
662 static void
to64(char * s,long v,int n)663 to64(char *s, long v, int n)
664 {
665   while (--n >= 0)
666     {
667       *s++ = itoa64[v&0x3f];
668       v >>= 6;
669     }
670 }
671 
672 static char *
zencrypt(const char * passwd)673 zencrypt (const char *passwd)
674 {
675   char salt[6];
676   struct timeval tv;
677   char *crypt (const char *, const char *);
678 
679   gettimeofday(&tv,0);
680 
681   to64(&salt[0], random(), 3);
682   to64(&salt[3], tv.tv_usec, 3);
683   salt[5] = '\0';
684 
685   return crypt (passwd, salt);
686 }
687 
688 /* This function write configuration of this host. */
689 static int
config_write_host(struct vty * vty)690 config_write_host (struct vty *vty)
691 {
692   if (host.name)
693     vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
694 
695   if (host.encrypt)
696     {
697       if (host.password_encrypt)
698         vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
699       if (host.enable_encrypt)
700         vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
701     }
702   else
703     {
704       if (host.password)
705         vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
706       if (host.enable)
707         vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
708     }
709 
710   if (zlog_default->default_lvl != LOG_DEBUG)
711     {
712       vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
713 	       VTY_NEWLINE);
714       vty_out (vty, "log trap %s%s",
715 	       zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
716     }
717 
718   if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
719     {
720       vty_out (vty, "log file %s", host.logfile);
721       if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
722 	vty_out (vty, " %s",
723 		 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
724       vty_out (vty, "%s", VTY_NEWLINE);
725     }
726 
727   if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
728     {
729       vty_out (vty, "log stdout");
730       if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
731 	vty_out (vty, " %s",
732 		 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
733       vty_out (vty, "%s", VTY_NEWLINE);
734     }
735 
736   if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
737     vty_out(vty,"no log monitor%s",VTY_NEWLINE);
738   else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
739     vty_out(vty,"log monitor %s%s",
740 	    zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
741 
742   if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
743     {
744       vty_out (vty, "log syslog");
745       if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
746 	vty_out (vty, " %s",
747 		 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
748       vty_out (vty, "%s", VTY_NEWLINE);
749     }
750 
751   if (zlog_default->facility != LOG_DAEMON)
752     vty_out (vty, "log facility %s%s",
753 	     facility_name(zlog_default->facility), VTY_NEWLINE);
754 
755   if (zlog_default->record_priority == 1)
756     vty_out (vty, "log record-priority%s", VTY_NEWLINE);
757 
758   if (zlog_default->timestamp_precision > 0)
759     vty_out (vty, "log timestamp precision %d%s",
760 	     zlog_default->timestamp_precision, VTY_NEWLINE);
761 
762   if (host.advanced)
763     vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
764 
765   if (host.encrypt)
766     vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
767 
768   if (host.lines >= 0)
769     vty_out (vty, "service terminal-length %d%s", host.lines,
770 	     VTY_NEWLINE);
771 
772   if (host.motdfile)
773     vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
774   else if (! host.motd)
775     vty_out (vty, "no banner motd%s", VTY_NEWLINE);
776 
777   return 1;
778 }
779 
780 /* Utility function for getting command vector. */
781 static vector
cmd_node_vector(vector v,enum node_type ntype)782 cmd_node_vector (vector v, enum node_type ntype)
783 {
784   struct cmd_node *cnode = vector_slot (v, ntype);
785   return cnode->cmd_vector;
786 }
787 
788 /* Completion match types. */
789 enum match_type
790 {
791   no_match,
792   extend_match,
793   ipv4_prefix_match,
794   ipv4_match,
795   ipv6_prefix_match,
796   ipv6_match,
797   range_match,
798   vararg_match,
799   partly_match,
800   exact_match
801 };
802 
803 static enum match_type
cmd_ipv4_match(const char * str)804 cmd_ipv4_match (const char *str)
805 {
806   const char *sp;
807   int dots = 0, nums = 0;
808   char buf[4];
809 
810   if (str == NULL)
811     return partly_match;
812 
813   for (;;)
814     {
815       memset (buf, 0, sizeof (buf));
816       sp = str;
817       while (*str != '\0')
818 	{
819 	  if (*str == '.')
820 	    {
821 	      if (dots >= 3)
822 		return no_match;
823 
824 	      if (*(str + 1) == '.')
825 		return no_match;
826 
827 	      if (*(str + 1) == '\0')
828 		return partly_match;
829 
830 	      dots++;
831 	      break;
832 	    }
833 	  if (!isdigit ((int) *str))
834 	    return no_match;
835 
836 	  str++;
837 	}
838 
839       if (str - sp > 3)
840 	return no_match;
841 
842       strncpy (buf, sp, str - sp);
843       if (atoi (buf) > 255)
844 	return no_match;
845 
846       nums++;
847 
848       if (*str == '\0')
849 	break;
850 
851       str++;
852     }
853 
854   if (nums < 4)
855     return partly_match;
856 
857   return exact_match;
858 }
859 
860 static enum match_type
cmd_ipv4_prefix_match(const char * str)861 cmd_ipv4_prefix_match (const char *str)
862 {
863   const char *sp;
864   int dots = 0;
865   char buf[4];
866 
867   if (str == NULL)
868     return partly_match;
869 
870   for (;;)
871     {
872       memset (buf, 0, sizeof (buf));
873       sp = str;
874       while (*str != '\0' && *str != '/')
875 	{
876 	  if (*str == '.')
877 	    {
878 	      if (dots == 3)
879 		return no_match;
880 
881 	      if (*(str + 1) == '.' || *(str + 1) == '/')
882 		return no_match;
883 
884 	      if (*(str + 1) == '\0')
885 		return partly_match;
886 
887 	      dots++;
888 	      break;
889 	    }
890 
891 	  if (!isdigit ((int) *str))
892 	    return no_match;
893 
894 	  str++;
895 	}
896 
897       if (str - sp > 3)
898 	return no_match;
899 
900       strncpy (buf, sp, str - sp);
901       if (atoi (buf) > 255)
902 	return no_match;
903 
904       if (dots == 3)
905 	{
906 	  if (*str == '/')
907 	    {
908 	      if (*(str + 1) == '\0')
909 		return partly_match;
910 
911 	      str++;
912 	      break;
913 	    }
914 	  else if (*str == '\0')
915 	    return partly_match;
916 	}
917 
918       if (*str == '\0')
919 	return partly_match;
920 
921       str++;
922     }
923 
924   sp = str;
925   while (*str != '\0')
926     {
927       if (!isdigit ((int) *str))
928 	return no_match;
929 
930       str++;
931     }
932 
933   if (atoi (sp) > 32)
934     return no_match;
935 
936   return exact_match;
937 }
938 
939 #define IPV6_ADDR_STR		"0123456789abcdefABCDEF:.%"
940 #define IPV6_PREFIX_STR		"0123456789abcdefABCDEF:.%/"
941 #define STATE_START		1
942 #define STATE_COLON		2
943 #define STATE_DOUBLE		3
944 #define STATE_ADDR		4
945 #define STATE_DOT               5
946 #define STATE_SLASH		6
947 #define STATE_MASK		7
948 
949 #ifdef HAVE_IPV6
950 
951 static enum match_type
cmd_ipv6_match(const char * str)952 cmd_ipv6_match (const char *str)
953 {
954   struct sockaddr_in6 sin6_dummy;
955   int ret;
956 
957   if (str == NULL)
958     return partly_match;
959 
960   if (strspn (str, IPV6_ADDR_STR) != strlen (str))
961     return no_match;
962 
963   /* use inet_pton that has a better support,
964    * for example inet_pton can support the automatic addresses:
965    *  ::1.2.3.4
966    */
967   ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
968 
969   if (ret == 1)
970     return exact_match;
971 
972   return no_match;
973 }
974 
975 static enum match_type
cmd_ipv6_prefix_match(const char * str)976 cmd_ipv6_prefix_match (const char *str)
977 {
978   int state = STATE_START;
979   int colons = 0, nums = 0, double_colon = 0;
980   int mask;
981   const char *sp = NULL;
982   char *endptr = NULL;
983 
984   if (str == NULL)
985     return partly_match;
986 
987   if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
988     return no_match;
989 
990   while (*str != '\0' && state != STATE_MASK)
991     {
992       switch (state)
993 	{
994 	case STATE_START:
995 	  if (*str == ':')
996 	    {
997 	      if (*(str + 1) != ':' && *(str + 1) != '\0')
998 		return no_match;
999 	      colons--;
1000 	      state = STATE_COLON;
1001 	    }
1002 	  else
1003 	    {
1004 	      sp = str;
1005 	      state = STATE_ADDR;
1006 	    }
1007 
1008 	  continue;
1009 	case STATE_COLON:
1010 	  colons++;
1011 	  if (*(str + 1) == '/')
1012 	    return no_match;
1013 	  else if (*(str + 1) == ':')
1014 	    state = STATE_DOUBLE;
1015 	  else
1016 	    {
1017 	      sp = str + 1;
1018 	      state = STATE_ADDR;
1019 	    }
1020 	  break;
1021 	case STATE_DOUBLE:
1022 	  if (double_colon)
1023 	    return no_match;
1024 
1025 	  if (*(str + 1) == ':')
1026 	    return no_match;
1027 	  else
1028 	    {
1029 	      if (*(str + 1) != '\0' && *(str + 1) != '/')
1030 		colons++;
1031 	      sp = str + 1;
1032 
1033 	      if (*(str + 1) == '/')
1034 		state = STATE_SLASH;
1035 	      else
1036 		state = STATE_ADDR;
1037 	    }
1038 
1039 	  double_colon++;
1040 	  nums += 1;
1041 	  break;
1042 	case STATE_ADDR:
1043 	  if (*(str + 1) == ':' || *(str + 1) == '.'
1044 	      || *(str + 1) == '\0' || *(str + 1) == '/')
1045 	    {
1046 	      if (str - sp > 3)
1047 		return no_match;
1048 
1049 	      for (; sp <= str; sp++)
1050 		if (*sp == '/')
1051 		  return no_match;
1052 
1053 	      nums++;
1054 
1055 	      if (*(str + 1) == ':')
1056 		state = STATE_COLON;
1057 	      else if (*(str + 1) == '.')
1058 		{
1059 		  if (colons || double_colon)
1060 		    state = STATE_DOT;
1061 		  else
1062 		    return no_match;
1063 		}
1064 	      else if (*(str + 1) == '/')
1065 		state = STATE_SLASH;
1066 	    }
1067 	  break;
1068 	case STATE_DOT:
1069 	  state = STATE_ADDR;
1070 	  break;
1071 	case STATE_SLASH:
1072 	  if (*(str + 1) == '\0')
1073 	    return partly_match;
1074 
1075 	  state = STATE_MASK;
1076 	  break;
1077 	default:
1078 	  break;
1079 	}
1080 
1081       if (nums > 11)
1082 	return no_match;
1083 
1084       if (colons > 7)
1085 	return no_match;
1086 
1087       str++;
1088     }
1089 
1090   if (state < STATE_MASK)
1091     return partly_match;
1092 
1093   mask = strtol (str, &endptr, 10);
1094   if (*endptr != '\0')
1095     return no_match;
1096 
1097   if (mask < 0 || mask > 128)
1098     return no_match;
1099 
1100   return exact_match;
1101 }
1102 
1103 #endif /* HAVE_IPV6  */
1104 
1105 #define DECIMAL_STRLEN_MAX 10
1106 
1107 static int
cmd_range_match(const char * range,const char * str)1108 cmd_range_match (const char *range, const char *str)
1109 {
1110   char *p;
1111   char buf[DECIMAL_STRLEN_MAX + 1];
1112   char *endptr = NULL;
1113   unsigned long min, max, val;
1114 
1115   if (str == NULL)
1116     return 1;
1117 
1118   val = strtoul (str, &endptr, 10);
1119   if (*endptr != '\0')
1120     return 0;
1121 
1122   range++;
1123   p = strchr (range, '-');
1124   if (p == NULL)
1125     return 0;
1126   if (p - range > DECIMAL_STRLEN_MAX)
1127     return 0;
1128   strncpy (buf, range, p - range);
1129   buf[p - range] = '\0';
1130   min = strtoul (buf, &endptr, 10);
1131   if (*endptr != '\0')
1132     return 0;
1133 
1134   range = p + 1;
1135   p = strchr (range, '>');
1136   if (p == NULL)
1137     return 0;
1138   if (p - range > DECIMAL_STRLEN_MAX)
1139     return 0;
1140   strncpy (buf, range, p - range);
1141   buf[p - range] = '\0';
1142   max = strtoul (buf, &endptr, 10);
1143   if (*endptr != '\0')
1144     return 0;
1145 
1146   if (val < min || val > max)
1147     return 0;
1148 
1149   return 1;
1150 }
1151 
1152 static enum match_type
cmd_word_match(struct cmd_token * token,enum filter_type filter,const char * word)1153 cmd_word_match(struct cmd_token *token,
1154                enum filter_type filter,
1155                const char *word)
1156 {
1157   const char *str;
1158   enum match_type match_type;
1159 
1160   str = token->cmd;
1161 
1162   if (filter == FILTER_RELAXED)
1163     if (!word || !strlen(word))
1164       return partly_match;
1165 
1166   if (!word)
1167     return no_match;
1168 
1169   switch (token->terminal)
1170     {
1171       case TERMINAL_VARARG:
1172         return vararg_match;
1173 
1174       case TERMINAL_RANGE:
1175         if (cmd_range_match(str, word))
1176           return range_match;
1177         break;
1178 
1179       case TERMINAL_IPV6:
1180         match_type = cmd_ipv6_match(word);
1181         if ((filter == FILTER_RELAXED && match_type != no_match)
1182           || (filter == FILTER_STRICT && match_type == exact_match))
1183           return ipv6_match;
1184         break;
1185 
1186       case TERMINAL_IPV6_PREFIX:
1187         match_type = cmd_ipv6_prefix_match(word);
1188         if ((filter == FILTER_RELAXED && match_type != no_match)
1189             || (filter == FILTER_STRICT && match_type == exact_match))
1190           return ipv6_prefix_match;
1191         break;
1192 
1193       case TERMINAL_IPV4:
1194         match_type = cmd_ipv4_match(word);
1195         if ((filter == FILTER_RELAXED && match_type != no_match)
1196             || (filter == FILTER_STRICT && match_type == exact_match))
1197           return ipv4_match;
1198         break;
1199 
1200       case TERMINAL_IPV4_PREFIX:
1201         match_type = cmd_ipv4_prefix_match(word);
1202         if ((filter == FILTER_RELAXED && match_type != no_match)
1203             || (filter == FILTER_STRICT && match_type == exact_match))
1204           return ipv4_prefix_match;
1205         break;
1206 
1207       case TERMINAL_OPTION:
1208       case TERMINAL_VARIABLE:
1209         return extend_match;
1210 
1211       case TERMINAL_LITERAL:
1212         if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
1213           {
1214             if (!strcmp(str, word))
1215               return exact_match;
1216             return partly_match;
1217           }
1218         if (filter == FILTER_STRICT && !strcmp(str, word))
1219           return exact_match;
1220         break;
1221 
1222       default:
1223         assert (0);
1224     }
1225 
1226   return no_match;
1227 }
1228 
1229 struct cmd_matcher
1230 {
1231   struct cmd_element *cmd; /* The command element the matcher is using */
1232   enum filter_type filter; /* Whether to use strict or relaxed matching */
1233   vector vline; /* The tokenized commandline which is to be matched */
1234   unsigned int index; /* The index up to which matching should be done */
1235 
1236   /* If set, construct a list of matches at the position given by index */
1237   enum match_type *match_type;
1238   vector *match;
1239 
1240   unsigned int word_index; /* iterating over vline */
1241 };
1242 
1243 static int
push_argument(int * argc,const char ** argv,const char * arg)1244 push_argument(int *argc, const char **argv, const char *arg)
1245 {
1246   if (!arg || !strlen(arg))
1247     arg = NULL;
1248 
1249   if (!argc || !argv)
1250     return 0;
1251 
1252   if (*argc >= CMD_ARGC_MAX)
1253     return -1;
1254 
1255   argv[(*argc)++] = arg;
1256   return 0;
1257 }
1258 
1259 static void
cmd_matcher_record_match(struct cmd_matcher * matcher,enum match_type match_type,struct cmd_token * token)1260 cmd_matcher_record_match(struct cmd_matcher *matcher,
1261                          enum match_type match_type,
1262                          struct cmd_token *token)
1263 {
1264   if (matcher->word_index != matcher->index)
1265     return;
1266 
1267   if (matcher->match)
1268     {
1269       if (!*matcher->match)
1270         *matcher->match = vector_init(VECTOR_MIN_SIZE);
1271       vector_set(*matcher->match, token);
1272     }
1273 
1274   if (matcher->match_type)
1275     {
1276       if (match_type > *matcher->match_type)
1277         *matcher->match_type = match_type;
1278     }
1279 }
1280 
1281 static int
cmd_matcher_words_left(struct cmd_matcher * matcher)1282 cmd_matcher_words_left(struct cmd_matcher *matcher)
1283 {
1284   return matcher->word_index < vector_active(matcher->vline);
1285 }
1286 
1287 static const char*
cmd_matcher_get_word(struct cmd_matcher * matcher)1288 cmd_matcher_get_word(struct cmd_matcher *matcher)
1289 {
1290   assert(cmd_matcher_words_left(matcher));
1291 
1292   return vector_slot(matcher->vline, matcher->word_index);
1293 }
1294 
1295 static enum matcher_rv
cmd_matcher_match_terminal(struct cmd_matcher * matcher,struct cmd_token * token,int * argc,const char ** argv)1296 cmd_matcher_match_terminal(struct cmd_matcher *matcher,
1297                            struct cmd_token *token,
1298                            int *argc, const char **argv)
1299 {
1300   const char *word;
1301   enum match_type word_match;
1302 
1303   assert(token->type == TOKEN_TERMINAL);
1304 
1305   if (!cmd_matcher_words_left(matcher))
1306     {
1307       if (token->terminal == TERMINAL_OPTION)
1308         return MATCHER_OK; /* missing optional args are NOT pushed as NULL */
1309       else
1310         return MATCHER_INCOMPLETE;
1311     }
1312 
1313   word = cmd_matcher_get_word(matcher);
1314   word_match = cmd_word_match(token, matcher->filter, word);
1315   if (word_match == no_match)
1316     return MATCHER_NO_MATCH;
1317 
1318   /* We have to record the input word as argument if it matched
1319    * against a variable. */
1320   if (TERMINAL_RECORD (token->terminal))
1321     {
1322       if (push_argument(argc, argv, word))
1323         return MATCHER_EXCEED_ARGC_MAX;
1324     }
1325 
1326   cmd_matcher_record_match(matcher, word_match, token);
1327 
1328   matcher->word_index++;
1329 
1330   /* A vararg token should consume all left over words as arguments */
1331   if (token->terminal == TERMINAL_VARARG)
1332     while (cmd_matcher_words_left(matcher))
1333       {
1334         word = cmd_matcher_get_word(matcher);
1335         if (word && strlen(word))
1336           push_argument(argc, argv, word);
1337         matcher->word_index++;
1338       }
1339 
1340   return MATCHER_OK;
1341 }
1342 
1343 static enum matcher_rv
cmd_matcher_match_multiple(struct cmd_matcher * matcher,struct cmd_token * token,int * argc,const char ** argv)1344 cmd_matcher_match_multiple(struct cmd_matcher *matcher,
1345                            struct cmd_token *token,
1346                            int *argc, const char **argv)
1347 {
1348   enum match_type multiple_match;
1349   unsigned int multiple_index;
1350   const char *word;
1351   const char *arg = NULL;
1352   struct cmd_token *word_token;
1353   enum match_type word_match;
1354 
1355   assert(token->type == TOKEN_MULTIPLE);
1356 
1357   multiple_match = no_match;
1358 
1359   if (!cmd_matcher_words_left(matcher))
1360     return MATCHER_INCOMPLETE;
1361 
1362   word = cmd_matcher_get_word(matcher);
1363   for (multiple_index = 0;
1364        multiple_index < vector_active(token->multiple);
1365        multiple_index++)
1366     {
1367       word_token = vector_slot(token->multiple, multiple_index);
1368 
1369       word_match = cmd_word_match(word_token, matcher->filter, word);
1370       if (word_match == no_match)
1371         continue;
1372 
1373       cmd_matcher_record_match(matcher, word_match, word_token);
1374 
1375       if (word_match > multiple_match)
1376         {
1377           multiple_match = word_match;
1378           arg = word;
1379         }
1380       /* To mimic the behavior of the old command implementation, we
1381        * tolerate any ambiguities here :/ */
1382     }
1383 
1384   matcher->word_index++;
1385 
1386   if (multiple_match == no_match)
1387     return MATCHER_NO_MATCH;
1388 
1389   if (push_argument(argc, argv, arg))
1390     return MATCHER_EXCEED_ARGC_MAX;
1391 
1392   return MATCHER_OK;
1393 }
1394 
1395 static enum matcher_rv
cmd_matcher_read_keywords(struct cmd_matcher * matcher,struct cmd_token * token,vector args_vector)1396 cmd_matcher_read_keywords(struct cmd_matcher *matcher,
1397                           struct cmd_token *token,
1398                           vector args_vector)
1399 {
1400   unsigned int i;
1401   unsigned long keyword_mask;
1402   unsigned int keyword_found;
1403   enum match_type keyword_match;
1404   enum match_type word_match;
1405   vector keyword_vector;
1406   struct cmd_token *word_token;
1407   const char *word;
1408   int keyword_argc;
1409   const char **keyword_argv;
1410   enum matcher_rv rv = MATCHER_NO_MATCH;
1411 
1412   keyword_mask = 0;
1413   while (1)
1414     {
1415       if (!cmd_matcher_words_left(matcher))
1416         return MATCHER_OK;
1417 
1418       word = cmd_matcher_get_word(matcher);
1419 
1420       keyword_found = -1;
1421       keyword_match = no_match;
1422       for (i = 0; i < vector_active(token->keyword); i++)
1423         {
1424           if (keyword_mask & (1 << i))
1425             continue;
1426 
1427           keyword_vector = vector_slot(token->keyword, i);
1428           word_token = vector_slot(keyword_vector, 0);
1429 
1430           word_match = cmd_word_match(word_token, matcher->filter, word);
1431           if (word_match == no_match)
1432             continue;
1433 
1434           cmd_matcher_record_match(matcher, word_match, word_token);
1435 
1436           if (word_match > keyword_match)
1437             {
1438               keyword_match = word_match;
1439               keyword_found = i;
1440             }
1441           else if (word_match == keyword_match)
1442             {
1443               if (matcher->word_index != matcher->index || args_vector)
1444                 return MATCHER_AMBIGUOUS;
1445             }
1446         }
1447 
1448       if (keyword_found == (unsigned int)-1)
1449         return MATCHER_NO_MATCH;
1450 
1451       matcher->word_index++;
1452 
1453       if (matcher->word_index > matcher->index)
1454         return MATCHER_OK;
1455 
1456       keyword_mask |= (1 << keyword_found);
1457 
1458       if (args_vector)
1459         {
1460           keyword_argc = 0;
1461           keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*));
1462           /* We use -1 as a marker for unused fields as NULL might be a valid value */
1463           for (i = 0; i < CMD_ARGC_MAX + 1; i++)
1464             keyword_argv[i] = (void*)-1;
1465           vector_set_index(args_vector, keyword_found, keyword_argv);
1466         }
1467       else
1468         {
1469           keyword_argv = NULL;
1470         }
1471 
1472       keyword_vector = vector_slot(token->keyword, keyword_found);
1473       /* the keyword itself is at 0. We are only interested in the arguments,
1474        * so start counting at 1. */
1475       for (i = 1; i < vector_active(keyword_vector); i++)
1476         {
1477           word_token = vector_slot(keyword_vector, i);
1478 
1479           switch (word_token->type)
1480             {
1481             case TOKEN_TERMINAL:
1482               rv = cmd_matcher_match_terminal(matcher, word_token,
1483                                               &keyword_argc, keyword_argv);
1484               break;
1485             case TOKEN_MULTIPLE:
1486               rv = cmd_matcher_match_multiple(matcher, word_token,
1487                                               &keyword_argc, keyword_argv);
1488               break;
1489             case TOKEN_KEYWORD:
1490               assert(!"Keywords should never be nested.");
1491               break;
1492             }
1493 
1494           if (MATCHER_ERROR(rv))
1495             return rv;
1496 
1497           if (matcher->word_index > matcher->index)
1498             return MATCHER_OK;
1499         }
1500     }
1501   /* not reached */
1502 }
1503 
1504 static enum matcher_rv
cmd_matcher_build_keyword_args(struct cmd_matcher * matcher,struct cmd_token * token,int * argc,const char ** argv,vector keyword_args_vector)1505 cmd_matcher_build_keyword_args(struct cmd_matcher *matcher,
1506                                struct cmd_token *token,
1507                                int *argc, const char **argv,
1508                                vector keyword_args_vector)
1509 {
1510   unsigned int i, j;
1511   const char **keyword_args;
1512   vector keyword_vector;
1513   struct cmd_token *word_token;
1514   const char *arg;
1515   enum matcher_rv rv;
1516 
1517   rv = MATCHER_OK;
1518 
1519   if (keyword_args_vector == NULL)
1520     return rv;
1521 
1522   for (i = 0; i < vector_active(token->keyword); i++)
1523     {
1524       keyword_vector = vector_slot(token->keyword, i);
1525       keyword_args = vector_lookup(keyword_args_vector, i);
1526 
1527       if (vector_active(keyword_vector) == 1)
1528         {
1529           /* this is a keyword without arguments */
1530           if (keyword_args)
1531             {
1532               word_token = vector_slot(keyword_vector, 0);
1533               arg = word_token->cmd;
1534             }
1535           else
1536             {
1537               arg = NULL;
1538             }
1539 
1540           if (push_argument(argc, argv, arg))
1541             rv = MATCHER_EXCEED_ARGC_MAX;
1542         }
1543       else
1544         {
1545           /* this is a keyword with arguments */
1546           if (keyword_args)
1547             {
1548               /* the keyword was present, so just fill in the arguments */
1549               for (j = 0; keyword_args[j] != (void*)-1; j++)
1550                 if (push_argument(argc, argv, keyword_args[j]))
1551                   rv = MATCHER_EXCEED_ARGC_MAX;
1552               XFREE(MTYPE_TMP, keyword_args);
1553             }
1554           else
1555             {
1556               /* the keyword was not present, insert NULL for the arguments
1557                * the keyword would have taken. */
1558               for (j = 1; j < vector_active(keyword_vector); j++)
1559                 {
1560                   word_token = vector_slot(keyword_vector, j);
1561                   if ((word_token->type == TOKEN_TERMINAL
1562                        && TERMINAL_RECORD (word_token->terminal))
1563                       || word_token->type == TOKEN_MULTIPLE)
1564                     {
1565                       if (push_argument(argc, argv, NULL))
1566                         rv = MATCHER_EXCEED_ARGC_MAX;
1567                     }
1568                 }
1569             }
1570         }
1571     }
1572   vector_free(keyword_args_vector);
1573   return rv;
1574 }
1575 
1576 static enum matcher_rv
cmd_matcher_match_keyword(struct cmd_matcher * matcher,struct cmd_token * token,int * argc,const char ** argv)1577 cmd_matcher_match_keyword(struct cmd_matcher *matcher,
1578                           struct cmd_token *token,
1579                           int *argc, const char **argv)
1580 {
1581   vector keyword_args_vector;
1582   enum matcher_rv reader_rv;
1583   enum matcher_rv builder_rv;
1584 
1585   assert(token->type == TOKEN_KEYWORD);
1586 
1587   if (argc && argv)
1588     keyword_args_vector = vector_init(VECTOR_MIN_SIZE);
1589   else
1590     keyword_args_vector = NULL;
1591 
1592   reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector);
1593   builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc,
1594                                               argv, keyword_args_vector);
1595   /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
1596 
1597   if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv))
1598     return builder_rv;
1599 
1600   return reader_rv;
1601 }
1602 
1603 static void
cmd_matcher_init(struct cmd_matcher * matcher,struct cmd_element * cmd,enum filter_type filter,vector vline,unsigned int index,enum match_type * match_type,vector * match)1604 cmd_matcher_init(struct cmd_matcher *matcher,
1605                  struct cmd_element *cmd,
1606                  enum filter_type filter,
1607                  vector vline,
1608                  unsigned int index,
1609                  enum match_type *match_type,
1610                  vector *match)
1611 {
1612   memset(matcher, 0, sizeof(*matcher));
1613 
1614   matcher->cmd = cmd;
1615   matcher->filter = filter;
1616   matcher->vline = vline;
1617   matcher->index = index;
1618 
1619   matcher->match_type = match_type;
1620   if (matcher->match_type)
1621     *matcher->match_type = no_match;
1622   matcher->match = match;
1623 
1624   matcher->word_index = 0;
1625 }
1626 
1627 static enum matcher_rv
cmd_element_match(struct cmd_element * cmd_element,enum filter_type filter,vector vline,unsigned int index,enum match_type * match_type,vector * match,int * argc,const char ** argv)1628 cmd_element_match(struct cmd_element *cmd_element,
1629                   enum filter_type filter,
1630                   vector vline,
1631                   unsigned int index,
1632                   enum match_type *match_type,
1633                   vector *match,
1634                   int *argc,
1635                   const char **argv)
1636 {
1637   struct cmd_matcher matcher;
1638   unsigned int token_index;
1639   enum matcher_rv rv = MATCHER_NO_MATCH;
1640 
1641   cmd_matcher_init(&matcher, cmd_element, filter,
1642                    vline, index, match_type, match);
1643 
1644   if (argc != NULL)
1645     *argc = 0;
1646 
1647   for (token_index = 0;
1648        token_index < vector_active(cmd_element->tokens);
1649        token_index++)
1650     {
1651       struct cmd_token *token = vector_slot(cmd_element->tokens, token_index);
1652 
1653       switch (token->type)
1654         {
1655         case TOKEN_TERMINAL:
1656           rv = cmd_matcher_match_terminal(&matcher, token, argc, argv);
1657           break;
1658         case TOKEN_MULTIPLE:
1659           rv = cmd_matcher_match_multiple(&matcher, token, argc, argv);
1660           break;
1661         case TOKEN_KEYWORD:
1662           rv = cmd_matcher_match_keyword(&matcher, token, argc, argv);
1663         }
1664 
1665       if (MATCHER_ERROR(rv))
1666         return rv;
1667 
1668       if (matcher.word_index > index)
1669         return MATCHER_OK;
1670     }
1671 
1672   /* return MATCHER_COMPLETE if all words were consumed */
1673   if (matcher.word_index >= vector_active(vline))
1674     return MATCHER_COMPLETE;
1675 
1676   /* return MATCHER_COMPLETE also if only an empty word is left. */
1677   if (matcher.word_index == vector_active(vline) - 1
1678       && (!vector_slot(vline, matcher.word_index)
1679           || !strlen((char*)vector_slot(vline, matcher.word_index))))
1680     return MATCHER_COMPLETE;
1681 
1682   return MATCHER_NO_MATCH; /* command is too long to match */
1683 }
1684 
1685 /**
1686  * Filter a given vector of commands against a given commandline and
1687  * calculate possible completions.
1688  *
1689  * @param commands A vector of struct cmd_element*. Commands that don't
1690  *                 match against the given command line will be overwritten
1691  *                 with NULL in that vector.
1692  * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
1693  *               determines how incomplete commands are handled, compare with
1694  *               cmd_word_match for details.
1695  * @param vline A vector of char* containing the tokenized commandline.
1696  * @param index Only match up to the given token of the commandline.
1697  * @param match_type Record the type of the best match here.
1698  * @param matches Record the matches here. For each cmd_element in the commands
1699  *                vector, a match vector will be created in the matches vector.
1700  *                That vector will contain all struct command_token* of the
1701  *                cmd_element which matched against the given vline at the given
1702  *                index.
1703  * @return A code specifying if an error occurred. If all went right, it's
1704  *         CMD_SUCCESS.
1705  */
1706 static int
cmd_vector_filter(vector commands,enum filter_type filter,vector vline,unsigned int index,enum match_type * match_type,vector * matches)1707 cmd_vector_filter(vector commands,
1708                   enum filter_type filter,
1709                   vector vline,
1710                   unsigned int index,
1711                   enum match_type *match_type,
1712                   vector *matches)
1713 {
1714   unsigned int i;
1715   struct cmd_element *cmd_element;
1716   enum match_type best_match;
1717   enum match_type element_match;
1718   enum matcher_rv matcher_rv;
1719 
1720   best_match = no_match;
1721   *matches = vector_init(VECTOR_MIN_SIZE);
1722 
1723   for (i = 0; i < vector_active (commands); i++)
1724     if ((cmd_element = vector_slot (commands, i)) != NULL)
1725       {
1726         vector_set_index(*matches, i, NULL);
1727         matcher_rv = cmd_element_match(cmd_element, filter,
1728                                        vline, index,
1729                                        &element_match,
1730                                        (vector*)&vector_slot(*matches, i),
1731                                        NULL, NULL);
1732         if (MATCHER_ERROR(matcher_rv))
1733           {
1734             vector_slot(commands, i) = NULL;
1735             if (matcher_rv == MATCHER_AMBIGUOUS)
1736               return CMD_ERR_AMBIGUOUS;
1737             if (matcher_rv == MATCHER_EXCEED_ARGC_MAX)
1738               return CMD_ERR_EXEED_ARGC_MAX;
1739           }
1740         else if (element_match > best_match)
1741           {
1742             best_match = element_match;
1743           }
1744       }
1745   *match_type = best_match;
1746   return CMD_SUCCESS;
1747 }
1748 
1749 /**
1750  * Check whether a given commandline is complete if used for a specific
1751  * cmd_element.
1752  *
1753  * @param cmd_element A cmd_element against which the commandline should be
1754  *                    checked.
1755  * @param vline The tokenized commandline.
1756  * @return 1 if the given commandline is complete, 0 otherwise.
1757  */
1758 static int
cmd_is_complete(struct cmd_element * cmd_element,vector vline)1759 cmd_is_complete(struct cmd_element *cmd_element,
1760                 vector vline)
1761 {
1762   enum matcher_rv rv;
1763 
1764   rv = cmd_element_match(cmd_element,
1765                          FILTER_RELAXED,
1766                          vline, -1,
1767                          NULL, NULL,
1768                          NULL, NULL);
1769   return (rv == MATCHER_COMPLETE);
1770 }
1771 
1772 /**
1773  * Parse a given commandline and construct a list of arguments for the
1774  * given command_element.
1775  *
1776  * @param cmd_element The cmd_element for which we want to construct arguments.
1777  * @param vline The tokenized commandline.
1778  * @param argc Where to store the argument count.
1779  * @param argv Where to store the argument list. Should be at least
1780  *             CMD_ARGC_MAX elements long.
1781  * @return CMD_SUCCESS if everything went alright, an error otherwise.
1782  */
1783 static int
cmd_parse(struct cmd_element * cmd_element,vector vline,int * argc,const char ** argv)1784 cmd_parse(struct cmd_element *cmd_element,
1785           vector vline,
1786           int *argc, const char **argv)
1787 {
1788   enum matcher_rv rv = cmd_element_match(cmd_element,
1789                                          FILTER_RELAXED,
1790                                          vline, -1,
1791                                          NULL, NULL,
1792                                          argc, argv);
1793   switch (rv)
1794     {
1795     case MATCHER_COMPLETE:
1796       return CMD_SUCCESS;
1797 
1798     case MATCHER_NO_MATCH:
1799       return CMD_ERR_NO_MATCH;
1800 
1801     case MATCHER_AMBIGUOUS:
1802       return CMD_ERR_AMBIGUOUS;
1803 
1804     case MATCHER_EXCEED_ARGC_MAX:
1805       return CMD_ERR_EXEED_ARGC_MAX;
1806 
1807     default:
1808       return CMD_ERR_INCOMPLETE;
1809     }
1810 }
1811 
1812 /* Check ambiguous match */
1813 static int
is_cmd_ambiguous(vector cmd_vector,const char * command,vector matches,enum match_type type)1814 is_cmd_ambiguous (vector cmd_vector,
1815                   const char *command,
1816                   vector matches,
1817                   enum match_type type)
1818 {
1819   unsigned int i;
1820   unsigned int j;
1821   const char *str = NULL;
1822   const char *matched = NULL;
1823   vector match_vector;
1824   struct cmd_token *cmd_token;
1825 
1826   if (command == NULL)
1827     command = "";
1828 
1829   for (i = 0; i < vector_active (matches); i++)
1830     if ((match_vector = vector_slot (matches, i)) != NULL)
1831       {
1832 	int match = 0;
1833 
1834 	for (j = 0; j < vector_active (match_vector); j++)
1835 	  if ((cmd_token = vector_slot (match_vector, j)) != NULL)
1836 	    {
1837 	      enum match_type ret;
1838 
1839 	      assert(cmd_token->type == TOKEN_TERMINAL);
1840 	      if (cmd_token->type != TOKEN_TERMINAL)
1841 		continue;
1842 
1843 	      str = cmd_token->cmd;
1844 
1845 	      switch (type)
1846 		{
1847 		case exact_match:
1848 		  if (!TERMINAL_RECORD (cmd_token->terminal)
1849 		      && strcmp (command, str) == 0)
1850 		    match++;
1851 		  break;
1852 		case partly_match:
1853 		  if (!TERMINAL_RECORD (cmd_token->terminal)
1854 		      && strncmp (command, str, strlen (command)) == 0)
1855 		    {
1856 		      if (matched && strcmp (matched, str) != 0)
1857 			return 1;	/* There is ambiguous match. */
1858 		      else
1859 			matched = str;
1860 		      match++;
1861 		    }
1862 		  break;
1863 		case range_match:
1864 		  if (cmd_range_match (str, command))
1865 		    {
1866 		      if (matched && strcmp (matched, str) != 0)
1867 			return 1;
1868 		      else
1869 			matched = str;
1870 		      match++;
1871 		    }
1872 		  break;
1873 #ifdef HAVE_IPV6
1874 		case ipv6_match:
1875 		  if (cmd_token->terminal == TERMINAL_IPV6)
1876 		    match++;
1877 		  break;
1878 		case ipv6_prefix_match:
1879 		  if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1880 		    {
1881 		      if (ret == partly_match)
1882 			return 2;	/* There is incomplete match. */
1883 
1884 		      match++;
1885 		    }
1886 		  break;
1887 #endif /* HAVE_IPV6 */
1888 		case ipv4_match:
1889 		  if (cmd_token->terminal == TERMINAL_IPV4)
1890 		    match++;
1891 		  break;
1892 		case ipv4_prefix_match:
1893 		  if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1894 		    {
1895 		      if (ret == partly_match)
1896 			return 2;	/* There is incomplete match. */
1897 
1898 		      match++;
1899 		    }
1900 		  break;
1901 		case extend_match:
1902 		  if (TERMINAL_RECORD (cmd_token->terminal))
1903 		    match++;
1904 		  break;
1905 		case no_match:
1906 		default:
1907 		  break;
1908 		}
1909 	    }
1910 	if (!match)
1911 	  vector_slot (cmd_vector, i) = NULL;
1912       }
1913   return 0;
1914 }
1915 
1916 /* If src matches dst return dst string, otherwise return NULL */
1917 static const char *
cmd_entry_function(const char * src,struct cmd_token * token)1918 cmd_entry_function (const char *src, struct cmd_token *token)
1919 {
1920   const char *dst = token->cmd;
1921 
1922   /* Skip variable arguments. */
1923   if (TERMINAL_RECORD (token->terminal))
1924     return NULL;
1925 
1926   /* In case of 'command \t', given src is NULL string. */
1927   if (src == NULL)
1928     return dst;
1929 
1930   /* Matched with input string. */
1931   if (strncmp (src, dst, strlen (src)) == 0)
1932     return dst;
1933 
1934   return NULL;
1935 }
1936 
1937 /* If src matches dst return dst string, otherwise return NULL */
1938 /* This version will return the dst string always if it is
1939    CMD_VARIABLE for '?' key processing */
1940 static const char *
cmd_entry_function_desc(const char * src,struct cmd_token * token)1941 cmd_entry_function_desc (const char *src, struct cmd_token *token)
1942 {
1943   const char *dst = token->cmd;
1944 
1945   switch (token->terminal)
1946     {
1947       case TERMINAL_VARARG:
1948         return dst;
1949 
1950       case TERMINAL_RANGE:
1951         if (cmd_range_match (dst, src))
1952           return dst;
1953         else
1954           return NULL;
1955 
1956       case TERMINAL_IPV6:
1957         if (cmd_ipv6_match (src))
1958           return dst;
1959         else
1960           return NULL;
1961 
1962       case TERMINAL_IPV6_PREFIX:
1963         if (cmd_ipv6_prefix_match (src))
1964           return dst;
1965         else
1966           return NULL;
1967 
1968       case TERMINAL_IPV4:
1969         if (cmd_ipv4_match (src))
1970           return dst;
1971         else
1972           return NULL;
1973 
1974       case TERMINAL_IPV4_PREFIX:
1975         if (cmd_ipv4_prefix_match (src))
1976           return dst;
1977         else
1978           return NULL;
1979 
1980       /* Optional or variable commands always match on '?' */
1981       case TERMINAL_OPTION:
1982       case TERMINAL_VARIABLE:
1983         return dst;
1984 
1985       case TERMINAL_LITERAL:
1986         /* In case of 'command \t', given src is NULL string. */
1987         if (src == NULL)
1988           return dst;
1989 
1990         if (strncmp (src, dst, strlen (src)) == 0)
1991           return dst;
1992         else
1993           return NULL;
1994 
1995       default:
1996         assert(0);
1997         return NULL;
1998     }
1999 }
2000 
2001 /**
2002  * Check whether a string is already present in a vector of strings.
2003  * @param v A vector of char*.
2004  * @param str A char*.
2005  * @return 0 if str is already present in the vector, 1 otherwise.
2006  */
2007 static int
cmd_unique_string(vector v,const char * str)2008 cmd_unique_string (vector v, const char *str)
2009 {
2010   unsigned int i;
2011   char *match;
2012 
2013   for (i = 0; i < vector_active (v); i++)
2014     if ((match = vector_slot (v, i)) != NULL)
2015       if (strcmp (match, str) == 0)
2016 	return 0;
2017   return 1;
2018 }
2019 
2020 /**
2021  * Check whether a struct cmd_token matching a given string is already
2022  * present in a vector of struct cmd_token.
2023  * @param v A vector of struct cmd_token*.
2024  * @param str A char* which should be searched for.
2025  * @return 0 if there is a struct cmd_token* with its cmd matching str,
2026  *         1 otherwise.
2027  */
2028 static int
desc_unique_string(vector v,const char * str)2029 desc_unique_string (vector v, const char *str)
2030 {
2031   unsigned int i;
2032   struct cmd_token *token;
2033 
2034   for (i = 0; i < vector_active (v); i++)
2035     if ((token = vector_slot (v, i)) != NULL)
2036       if (strcmp (token->cmd, str) == 0)
2037 	return 0;
2038   return 1;
2039 }
2040 
2041 static int
cmd_try_do_shortcut(enum node_type node,char * first_word)2042 cmd_try_do_shortcut (enum node_type node, char* first_word) {
2043   if ( first_word != NULL &&
2044        node != AUTH_NODE &&
2045        node != VIEW_NODE &&
2046        node != AUTH_ENABLE_NODE &&
2047        node != ENABLE_NODE &&
2048        node != RESTRICTED_NODE &&
2049        0 == strcmp( "do", first_word ) )
2050     return 1;
2051   return 0;
2052 }
2053 
2054 static void
cmd_matches_free(vector * matches)2055 cmd_matches_free(vector *matches)
2056 {
2057   unsigned int i;
2058   vector cmd_matches;
2059 
2060   for (i = 0; i < vector_active(*matches); i++)
2061     if ((cmd_matches = vector_slot(*matches, i)) != NULL)
2062       vector_free(cmd_matches);
2063   vector_free(*matches);
2064   *matches = NULL;
2065 }
2066 
2067 static int
cmd_describe_cmp(const void * a,const void * b)2068 cmd_describe_cmp(const void *a, const void *b)
2069 {
2070   const struct cmd_token *first = *(struct cmd_token * const *)a;
2071   const struct cmd_token *second = *(struct cmd_token * const *)b;
2072 
2073   return strcmp(first->cmd, second->cmd);
2074 }
2075 
2076 static void
cmd_describe_sort(vector matchvec)2077 cmd_describe_sort(vector matchvec)
2078 {
2079   qsort(matchvec->index, vector_active(matchvec),
2080         sizeof(void*), cmd_describe_cmp);
2081 }
2082 
2083 /* '?' describe command support. */
2084 static vector
cmd_describe_command_real(vector vline,struct vty * vty,int * status)2085 cmd_describe_command_real (vector vline, struct vty *vty, int *status)
2086 {
2087   unsigned int i;
2088   vector cmd_vector;
2089 #define INIT_MATCHVEC_SIZE 10
2090   vector matchvec;
2091   struct cmd_element *cmd_element;
2092   unsigned int index;
2093   int ret;
2094   enum match_type match;
2095   char *command;
2096   vector matches = NULL;
2097   vector match_vector;
2098   uint32_t command_found = 0;
2099   const char *last_word;
2100 
2101   /* Set index. */
2102   if (vector_active (vline) == 0)
2103     {
2104       *status = CMD_ERR_NO_MATCH;
2105       return NULL;
2106     }
2107 
2108   index = vector_active (vline) - 1;
2109 
2110   /* Make copy vector of current node's command vector. */
2111   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2112 
2113   /* Prepare match vector */
2114   matchvec = vector_init (INIT_MATCHVEC_SIZE);
2115 
2116   /* Filter commands and build a list how they could possibly continue. */
2117   for (i = 0; i <= index; i++)
2118     {
2119       command = vector_slot (vline, i);
2120 
2121       if (matches)
2122 	cmd_matches_free(&matches);
2123 
2124       ret = cmd_vector_filter(cmd_vector,
2125 	                      FILTER_RELAXED,
2126 	                      vline, i,
2127 	                      &match,
2128 	                      &matches);
2129 
2130       if (ret != CMD_SUCCESS)
2131 	{
2132 	  vector_free (cmd_vector);
2133 	  vector_free (matchvec);
2134 	  cmd_matches_free(&matches);
2135 	  *status = ret;
2136 	  return NULL;
2137 	}
2138 
2139       /* The last match may well be ambigious, so break here */
2140       if (i == index)
2141 	break;
2142 
2143       if (match == vararg_match)
2144 	{
2145 	  /* We found a vararg match - so we can throw out the current matches here
2146 	   * and don't need to continue checking the command input */
2147 	  unsigned int j, k;
2148 
2149 	  for (j = 0; j < vector_active (matches); j++)
2150 	    if ((match_vector = vector_slot (matches, j)) != NULL)
2151 	      for (k = 0; k < vector_active (match_vector); k++)
2152 	        {
2153 	          struct cmd_token *token = vector_slot (match_vector, k);
2154 	          vector_set (matchvec, token);
2155 	        }
2156 
2157 	  *status = CMD_SUCCESS;
2158 	  vector_set(matchvec, &token_cr);
2159 	  vector_free (cmd_vector);
2160 	  cmd_matches_free(&matches);
2161 	  cmd_describe_sort(matchvec);
2162 	  return matchvec;
2163 	}
2164 
2165       ret = is_cmd_ambiguous(cmd_vector, command, matches, match);
2166       if (ret == 1)
2167 	{
2168 	  vector_free (cmd_vector);
2169 	  vector_free (matchvec);
2170 	  cmd_matches_free(&matches);
2171 	  *status = CMD_ERR_AMBIGUOUS;
2172 	  return NULL;
2173 	}
2174       else if (ret == 2)
2175 	{
2176 	  vector_free (cmd_vector);
2177 	  vector_free (matchvec);
2178 	  cmd_matches_free(&matches);
2179 	  *status = CMD_ERR_NO_MATCH;
2180 	  return NULL;
2181 	}
2182     }
2183 
2184   /* Make description vector. */
2185   for (i = 0; i < vector_active (matches); i++)
2186     {
2187       if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
2188 	{
2189 	  unsigned int j;
2190 	  vector vline_trimmed;
2191 
2192 	  command_found++;
2193 	  last_word = vector_slot(vline, vector_active(vline) - 1);
2194 	  if (last_word == NULL || !strlen(last_word))
2195 	    {
2196 	      vline_trimmed = vector_copy(vline);
2197 	      vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1);
2198 
2199 	      if (cmd_is_complete(cmd_element, vline_trimmed)
2200 		  && desc_unique_string(matchvec, command_cr))
2201 		{
2202 		  if (match != vararg_match)
2203 		    vector_set(matchvec, &token_cr);
2204 		}
2205 
2206 	      vector_free(vline_trimmed);
2207 	    }
2208 
2209 	  match_vector = vector_slot (matches, i);
2210 	  if (match_vector)
2211 	    {
2212 	      for (j = 0; j < vector_active(match_vector); j++)
2213 		{
2214 		  struct cmd_token *token = vector_slot(match_vector, j);
2215 		  const char *string;
2216 
2217 		  string = cmd_entry_function_desc(command, token);
2218 		  if (string && desc_unique_string(matchvec, string))
2219 		    vector_set(matchvec, token);
2220 		}
2221 	    }
2222 	}
2223     }
2224 
2225   /*
2226    * We can get into this situation when the command is complete
2227    * but the last part of the command is an optional piece of
2228    * the cli.
2229    */
2230   last_word = vector_slot(vline, vector_active(vline) - 1);
2231   if (command_found == 0 && (last_word == NULL || !strlen(last_word)))
2232     vector_set(matchvec, &token_cr);
2233 
2234   vector_free (cmd_vector);
2235   cmd_matches_free(&matches);
2236 
2237   if (vector_slot (matchvec, 0) == NULL)
2238     {
2239       vector_free (matchvec);
2240       *status = CMD_ERR_NO_MATCH;
2241       return NULL;
2242     }
2243 
2244   *status = CMD_SUCCESS;
2245   cmd_describe_sort(matchvec);
2246   return matchvec;
2247 }
2248 
2249 vector
cmd_describe_command(vector vline,struct vty * vty,int * status)2250 cmd_describe_command (vector vline, struct vty *vty, int *status)
2251 {
2252   vector ret;
2253 
2254   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2255     {
2256       enum node_type onode;
2257       vector shifted_vline;
2258       unsigned int index;
2259 
2260       onode = vty->node;
2261       vty->node = ENABLE_NODE;
2262       /* We can try it on enable node, cos' the vty is authenticated */
2263 
2264       shifted_vline = vector_init (vector_count(vline));
2265       /* use memcpy? */
2266       for (index = 1; index < vector_active (vline); index++)
2267 	{
2268 	  vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2269 	}
2270 
2271       ret = cmd_describe_command_real (shifted_vline, vty, status);
2272 
2273       vector_free(shifted_vline);
2274       vty->node = onode;
2275       return ret;
2276   }
2277 
2278 
2279   return cmd_describe_command_real (vline, vty, status);
2280 }
2281 
2282 
2283 /* Check LCD of matched command. */
2284 static int
cmd_lcd(char ** matched)2285 cmd_lcd (char **matched)
2286 {
2287   int i;
2288   int j;
2289   int lcd = -1;
2290   char *s1, *s2;
2291   char c1, c2;
2292 
2293   if (matched[0] == NULL || matched[1] == NULL)
2294     return 0;
2295 
2296   for (i = 1; matched[i] != NULL; i++)
2297     {
2298       s1 = matched[i - 1];
2299       s2 = matched[i];
2300 
2301       for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
2302 	if (c1 != c2)
2303 	  break;
2304 
2305       if (lcd < 0)
2306 	lcd = j;
2307       else
2308 	{
2309 	  if (lcd > j)
2310 	    lcd = j;
2311 	}
2312     }
2313   return lcd;
2314 }
2315 
2316 static int
cmd_complete_cmp(const void * a,const void * b)2317 cmd_complete_cmp(const void *a, const void *b)
2318 {
2319   const char *first = *(char * const *)a;
2320   const char *second = *(char * const *)b;
2321 
2322   if (!first)
2323     {
2324       if (!second)
2325         return 0;
2326       return 1;
2327     }
2328   if (!second)
2329     return -1;
2330 
2331   return strcmp(first, second);
2332 }
2333 
2334 static void
cmd_complete_sort(vector matchvec)2335 cmd_complete_sort(vector matchvec)
2336 {
2337   qsort(matchvec->index, vector_active(matchvec),
2338         sizeof(void*), cmd_complete_cmp);
2339 }
2340 
2341 /* Command line completion support. */
2342 static char **
cmd_complete_command_real(vector vline,struct vty * vty,int * status,int islib)2343 cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib)
2344 {
2345   unsigned int i;
2346   vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2347 #define INIT_MATCHVEC_SIZE 10
2348   vector matchvec;
2349   unsigned int index;
2350   char **match_str;
2351   struct cmd_token *token;
2352   char *command;
2353   int lcd;
2354   vector matches = NULL;
2355   vector match_vector;
2356 
2357   if (vector_active (vline) == 0)
2358     {
2359       vector_free (cmd_vector);
2360       *status = CMD_ERR_NO_MATCH;
2361       return NULL;
2362     }
2363   else
2364     index = vector_active (vline) - 1;
2365 
2366   /* First, filter by command string */
2367   for (i = 0; i <= index; i++)
2368     {
2369       command = vector_slot (vline, i);
2370       enum match_type match;
2371       int ret;
2372 
2373       if (matches)
2374         cmd_matches_free(&matches);
2375 
2376       /* First try completion match, if there is exactly match return 1 */
2377       ret = cmd_vector_filter(cmd_vector,
2378 	                      FILTER_RELAXED,
2379 	                      vline, i,
2380 	                      &match,
2381 	                      &matches);
2382 
2383       if (ret != CMD_SUCCESS)
2384 	{
2385 	  vector_free(cmd_vector);
2386 	  cmd_matches_free(&matches);
2387 	  *status = ret;
2388 	  return NULL;
2389 	}
2390 
2391       /* Break here - the completion mustn't be checked to be non-ambiguous */
2392       if (i == index)
2393 	break;
2394 
2395       /* If there is exact match then filter ambiguous match else check
2396 	 ambiguousness. */
2397       ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
2398       if (ret == 1)
2399 	{
2400 	  vector_free (cmd_vector);
2401 	  cmd_matches_free(&matches);
2402 	  *status = CMD_ERR_AMBIGUOUS;
2403 	  return NULL;
2404 	}
2405     }
2406 
2407   /* Prepare match vector. */
2408   matchvec = vector_init (INIT_MATCHVEC_SIZE);
2409 
2410   /* Build the possible list of continuations into a list of completions */
2411   for (i = 0; i < vector_active (matches); i++)
2412     if ((match_vector = vector_slot (matches, i)))
2413       {
2414 	const char *string;
2415 	unsigned int j;
2416 
2417 	for (j = 0; j < vector_active (match_vector); j++)
2418 	  if ((token = vector_slot (match_vector, j)))
2419             {
2420               string = cmd_entry_function (vector_slot (vline, index), token);
2421               if (string && cmd_unique_string (matchvec, string))
2422                 vector_set (matchvec, (islib != 0 ?
2423                                       XSTRDUP (MTYPE_TMP, string) :
2424                                       strdup (string) /* rl freed */));
2425             }
2426       }
2427 
2428   /* We don't need cmd_vector any more. */
2429   vector_free (cmd_vector);
2430   cmd_matches_free(&matches);
2431 
2432   /* No matched command */
2433   if (vector_slot (matchvec, 0) == NULL)
2434     {
2435       vector_free (matchvec);
2436 
2437       /* In case of 'command \t' pattern.  Do you need '?' command at
2438          the end of the line. */
2439       if (vector_slot (vline, index) == '\0')
2440 	*status = CMD_ERR_NOTHING_TODO;
2441       else
2442 	*status = CMD_ERR_NO_MATCH;
2443       return NULL;
2444     }
2445 
2446   /* Only one matched */
2447   if (vector_slot (matchvec, 1) == NULL)
2448     {
2449       match_str = (char **) matchvec->index;
2450       vector_only_wrapper_free (matchvec);
2451       *status = CMD_COMPLETE_FULL_MATCH;
2452       return match_str;
2453     }
2454   /* Make it sure last element is NULL. */
2455   vector_set (matchvec, NULL);
2456 
2457   /* Check LCD of matched strings. */
2458   if (vector_slot (vline, index) != NULL)
2459     {
2460       lcd = cmd_lcd ((char **) matchvec->index);
2461 
2462       if (lcd)
2463 	{
2464 	  int len = strlen (vector_slot (vline, index));
2465 
2466 	  if (len < lcd)
2467 	    {
2468 	      char *lcdstr;
2469 
2470 	      lcdstr = (islib != 0 ?
2471                         XMALLOC (MTYPE_TMP, lcd + 1) :
2472                         malloc(lcd + 1));
2473 	      memcpy (lcdstr, matchvec->index[0], lcd);
2474 	      lcdstr[lcd] = '\0';
2475 
2476 	      /* Free matchvec. */
2477 	      for (i = 0; i < vector_active (matchvec); i++)
2478                 {
2479                   if (vector_slot (matchvec, i))
2480                     {
2481                       if (islib != 0)
2482                         XFREE (MTYPE_TMP, vector_slot (matchvec, i));
2483                       else
2484                         free (vector_slot (matchvec, i));
2485                     }
2486                 }
2487 	      vector_free (matchvec);
2488 
2489 	      /* Make new matchvec. */
2490 	      matchvec = vector_init (INIT_MATCHVEC_SIZE);
2491 	      vector_set (matchvec, lcdstr);
2492 	      match_str = (char **) matchvec->index;
2493 	      vector_only_wrapper_free (matchvec);
2494 
2495 	      *status = CMD_COMPLETE_MATCH;
2496 	      return match_str;
2497 	    }
2498 	}
2499     }
2500 
2501   match_str = (char **) matchvec->index;
2502   cmd_complete_sort(matchvec);
2503   vector_only_wrapper_free (matchvec);
2504   *status = CMD_COMPLETE_LIST_MATCH;
2505   return match_str;
2506 }
2507 
2508 char **
cmd_complete_command_lib(vector vline,struct vty * vty,int * status,int islib)2509 cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
2510 {
2511   char **ret;
2512 
2513   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2514     {
2515       enum node_type onode;
2516       vector shifted_vline;
2517       unsigned int index;
2518 
2519       onode = vty->node;
2520       vty->node = ENABLE_NODE;
2521       /* We can try it on enable node, cos' the vty is authenticated */
2522 
2523       shifted_vline = vector_init (vector_count(vline));
2524       /* use memcpy? */
2525       for (index = 1; index < vector_active (vline); index++)
2526 	{
2527 	  vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2528 	}
2529 
2530       ret = cmd_complete_command_real (shifted_vline, vty, status, islib);
2531 
2532       vector_free(shifted_vline);
2533       vty->node = onode;
2534       return ret;
2535   }
2536 
2537   return cmd_complete_command_real (vline, vty, status, islib);
2538 }
2539 
2540 char **
cmd_complete_command(vector vline,struct vty * vty,int * status)2541 cmd_complete_command (vector vline, struct vty *vty, int *status)
2542 {
2543   return cmd_complete_command_lib (vline, vty, status, 0);
2544 }
2545 
2546 /* return parent node */
2547 /* MUST eventually converge on CONFIG_NODE */
2548 enum node_type
node_parent(enum node_type node)2549 node_parent ( enum node_type node )
2550 {
2551   enum node_type ret;
2552 
2553   assert (node > CONFIG_NODE);
2554 
2555   switch (node)
2556     {
2557     case BGP_VPNV4_NODE:
2558     case BGP_VPNV6_NODE:
2559     case BGP_ENCAP_NODE:
2560     case BGP_ENCAPV6_NODE:
2561     case BGP_IPV4_NODE:
2562     case BGP_IPV4M_NODE:
2563     case BGP_IPV6_NODE:
2564     case BGP_IPV6M_NODE:
2565       ret = BGP_NODE;
2566       break;
2567     case KEYCHAIN_KEY_NODE:
2568       ret = KEYCHAIN_NODE;
2569       break;
2570     case LINK_PARAMS_NODE:
2571       ret = INTERFACE_NODE;
2572       break;
2573     default:
2574       ret = CONFIG_NODE;
2575       break;
2576     }
2577 
2578   return ret;
2579 }
2580 
2581 /* Execute command by argument vline vector. */
2582 static int
cmd_execute_command_real(vector vline,enum filter_type filter,struct vty * vty,struct cmd_element ** cmd)2583 cmd_execute_command_real (vector vline,
2584 			  enum filter_type filter,
2585 			  struct vty *vty,
2586 			  struct cmd_element **cmd)
2587 {
2588   unsigned int i;
2589   unsigned int index;
2590   vector cmd_vector;
2591   struct cmd_element *cmd_element;
2592   struct cmd_element *matched_element;
2593   unsigned int matched_count, incomplete_count;
2594   int argc;
2595   const char *argv[CMD_ARGC_MAX];
2596   enum match_type match = 0;
2597   char *command;
2598   int ret;
2599   vector matches;
2600 
2601   /* Make copy of command elements. */
2602   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2603 
2604   for (index = 0; index < vector_active (vline); index++)
2605     {
2606       command = vector_slot (vline, index);
2607       ret = cmd_vector_filter(cmd_vector,
2608 			      filter,
2609 			      vline, index,
2610 			      &match,
2611 			      &matches);
2612 
2613       if (ret != CMD_SUCCESS)
2614 	{
2615 	  cmd_matches_free(&matches);
2616 	  return ret;
2617 	}
2618 
2619       if (match == vararg_match)
2620 	{
2621 	  cmd_matches_free(&matches);
2622 	  break;
2623 	}
2624 
2625       ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
2626       cmd_matches_free(&matches);
2627 
2628       if (ret == 1)
2629 	{
2630 	  vector_free(cmd_vector);
2631 	  return CMD_ERR_AMBIGUOUS;
2632 	}
2633       else if (ret == 2)
2634 	{
2635 	  vector_free(cmd_vector);
2636 	  return CMD_ERR_NO_MATCH;
2637 	}
2638     }
2639 
2640   /* Check matched count. */
2641   matched_element = NULL;
2642   matched_count = 0;
2643   incomplete_count = 0;
2644 
2645   for (i = 0; i < vector_active (cmd_vector); i++)
2646     if ((cmd_element = vector_slot (cmd_vector, i)))
2647       {
2648 	if (cmd_is_complete(cmd_element, vline))
2649 	  {
2650 	    matched_element = cmd_element;
2651 	    matched_count++;
2652 	  }
2653 	else
2654 	  {
2655 	    incomplete_count++;
2656 	  }
2657       }
2658 
2659   /* Finish of using cmd_vector. */
2660   vector_free (cmd_vector);
2661 
2662   /* To execute command, matched_count must be 1. */
2663   if (matched_count == 0)
2664     {
2665       if (incomplete_count)
2666 	return CMD_ERR_INCOMPLETE;
2667       else
2668 	return CMD_ERR_NO_MATCH;
2669     }
2670 
2671   if (matched_count > 1)
2672     return CMD_ERR_AMBIGUOUS;
2673 
2674   ret = cmd_parse(matched_element, vline, &argc, argv);
2675   if (ret != CMD_SUCCESS)
2676     return ret;
2677 
2678   /* For vtysh execution. */
2679   if (cmd)
2680     *cmd = matched_element;
2681 
2682   if (matched_element->daemon)
2683     return CMD_SUCCESS_DAEMON;
2684 
2685   /* Execute matched command. */
2686   return (*matched_element->func) (matched_element, vty, argc, argv);
2687 }
2688 
2689 /**
2690  * Execute a given command, handling things like "do ..." and checking
2691  * whether the given command might apply at a parent node if doesn't
2692  * apply for the current node.
2693  *
2694  * @param vline Command line input, vector of char* where each element is
2695  *              one input token.
2696  * @param vty The vty context in which the command should be executed.
2697  * @param cmd Pointer where the struct cmd_element of the matched command
2698  *            will be stored, if any. May be set to NULL if this info is
2699  *            not needed.
2700  * @param vtysh If set != 0, don't lookup the command at parent nodes.
2701  * @return The status of the command that has been executed or an error code
2702  *         as to why no command could be executed.
2703  */
2704 int
cmd_execute_command(vector vline,struct vty * vty,struct cmd_element ** cmd,int vtysh)2705 cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2706 		     int vtysh) {
2707   int ret, saved_ret, tried = 0;
2708   enum node_type onode, try_node;
2709 
2710   onode = try_node = vty->node;
2711 
2712   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2713     {
2714       vector shifted_vline;
2715       unsigned int index;
2716 
2717       vty->node = ENABLE_NODE;
2718       /* We can try it on enable node, cos' the vty is authenticated */
2719 
2720       shifted_vline = vector_init (vector_count(vline));
2721       /* use memcpy? */
2722       for (index = 1; index < vector_active (vline); index++)
2723 	{
2724 	  vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2725 	}
2726 
2727       ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
2728 
2729       vector_free(shifted_vline);
2730       vty->node = onode;
2731       return ret;
2732   }
2733 
2734 
2735   saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
2736 
2737   if (vtysh)
2738     return saved_ret;
2739 
2740   /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2741   while ( ret != CMD_SUCCESS && ret != CMD_WARNING
2742 	  && vty->node > CONFIG_NODE )
2743     {
2744       try_node = node_parent(try_node);
2745       vty->node = try_node;
2746       ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
2747       tried = 1;
2748       if (ret == CMD_SUCCESS || ret == CMD_WARNING)
2749 	{
2750 	  /* succesfull command, leave the node as is */
2751 	  return ret;
2752 	}
2753     }
2754   /* no command succeeded, reset the vty to the original node and
2755      return the error for this node */
2756   if ( tried )
2757     vty->node = onode;
2758   return saved_ret;
2759 }
2760 
2761 /**
2762  * Execute a given command, matching it strictly against the current node.
2763  * This mode is used when reading config files.
2764  *
2765  * @param vline Command line input, vector of char* where each element is
2766  *              one input token.
2767  * @param vty The vty context in which the command should be executed.
2768  * @param cmd Pointer where the struct cmd_element* of the matched command
2769  *            will be stored, if any. May be set to NULL if this info is
2770  *            not needed.
2771  * @return The status of the command that has been executed or an error code
2772  *         as to why no command could be executed.
2773  */
2774 int
cmd_execute_command_strict(vector vline,struct vty * vty,struct cmd_element ** cmd)2775 cmd_execute_command_strict (vector vline, struct vty *vty,
2776 			    struct cmd_element **cmd)
2777 {
2778   return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
2779 }
2780 
2781 /**
2782  * Parse one line of config, walking up the parse tree attempting to find a match
2783  *
2784  * @param vty The vty context in which the command should be executed.
2785  * @param cmd Pointer where the struct cmd_element* of the match command
2786  *            will be stored, if any.  May be set to NULL if this info is
2787  *            not needed.
2788  * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
2789  *                   or not.
2790  * @return The status of the command that has been executed or an error code
2791  *         as to why no command could be executed.
2792  */
2793 int
command_config_read_one_line(struct vty * vty,struct cmd_element ** cmd,int use_daemon)2794 command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use_daemon)
2795 {
2796   vector vline;
2797   int saved_node;
2798   int ret;
2799 
2800   vline = cmd_make_strvec (vty->buf);
2801 
2802   /* In case of comment line */
2803   if (vline == NULL)
2804     return CMD_SUCCESS;
2805 
2806   /* Execute configuration command : this is strict match */
2807   ret = cmd_execute_command_strict (vline, vty, cmd);
2808 
2809   saved_node = vty->node;
2810 
2811   while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
2812 	 ret != CMD_SUCCESS && ret != CMD_WARNING &&
2813 	 ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE) {
2814     vty->node = node_parent(vty->node);
2815     ret = cmd_execute_command_strict (vline, vty, cmd);
2816   }
2817 
2818   // If climbing the tree did not work then ignore the command and
2819   // stay at the same node
2820   if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
2821       ret != CMD_SUCCESS && ret != CMD_WARNING &&
2822       ret != CMD_ERR_NOTHING_TODO)
2823     {
2824       vty->node = saved_node;
2825     }
2826 
2827   cmd_free_strvec (vline);
2828 
2829   return ret;
2830 }
2831 
2832 /* Configration make from file. */
2833 int
config_from_file(struct vty * vty,FILE * fp,unsigned int * line_num)2834 config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
2835 {
2836   int ret;
2837   *line_num = 0;
2838 
2839   while (fgets (vty->buf, vty->max, fp))
2840     {
2841       ++(*line_num);
2842 
2843       ret = command_config_read_one_line (vty, NULL, 0);
2844 
2845       if (ret != CMD_SUCCESS && ret != CMD_WARNING
2846 	  && ret != CMD_ERR_NOTHING_TODO)
2847 	return ret;
2848     }
2849   return CMD_SUCCESS;
2850 }
2851 
2852 /* Configration from terminal */
2853 DEFUN (config_terminal,
2854        config_terminal_cmd,
2855        "configure terminal",
2856        "Configuration from vty interface\n"
2857        "Configuration terminal\n")
2858 {
2859   if (vty_config_lock (vty))
2860     vty->node = CONFIG_NODE;
2861   else
2862     {
2863       vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2864       return CMD_WARNING;
2865     }
2866   return CMD_SUCCESS;
2867 }
2868 
2869 /* Enable command */
2870 DEFUN (enable,
2871        config_enable_cmd,
2872        "enable",
2873        "Turn on privileged mode command\n")
2874 {
2875   /* If enable password is NULL, change to ENABLE_NODE */
2876   if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2877       vty->type == VTY_SHELL_SERV)
2878     vty->node = ENABLE_NODE;
2879   else
2880     vty->node = AUTH_ENABLE_NODE;
2881 
2882   return CMD_SUCCESS;
2883 }
2884 
2885 /* Disable command */
2886 DEFUN (disable,
2887        config_disable_cmd,
2888        "disable",
2889        "Turn off privileged mode command\n")
2890 {
2891   if (vty->node == ENABLE_NODE)
2892     vty->node = VIEW_NODE;
2893   return CMD_SUCCESS;
2894 }
2895 
2896 /* Down vty node level. */
2897 DEFUN (config_exit,
2898        config_exit_cmd,
2899        "exit",
2900        "Exit current mode and down to previous mode\n")
2901 {
2902   switch (vty->node)
2903     {
2904     case VIEW_NODE:
2905     case ENABLE_NODE:
2906     case RESTRICTED_NODE:
2907       if (vty_shell (vty))
2908 	exit (0);
2909       else
2910 	vty->status = VTY_CLOSE;
2911       break;
2912     case CONFIG_NODE:
2913       vty->node = ENABLE_NODE;
2914       vty_config_unlock (vty);
2915       break;
2916     case INTERFACE_NODE:
2917     case ZEBRA_NODE:
2918     case BGP_NODE:
2919     case RIP_NODE:
2920     case RIPNG_NODE:
2921     case BABEL_NODE:
2922     case OSPF_NODE:
2923     case OSPF6_NODE:
2924     case ISIS_NODE:
2925     case KEYCHAIN_NODE:
2926     case MASC_NODE:
2927     case RMAP_NODE:
2928     case PIM_NODE:
2929     case VTY_NODE:
2930       vty->node = CONFIG_NODE;
2931       break;
2932     case BGP_IPV4_NODE:
2933     case BGP_IPV4M_NODE:
2934     case BGP_VPNV4_NODE:
2935     case BGP_VPNV6_NODE:
2936     case BGP_ENCAP_NODE:
2937     case BGP_ENCAPV6_NODE:
2938     case BGP_IPV6_NODE:
2939     case BGP_IPV6M_NODE:
2940       vty->node = BGP_NODE;
2941       break;
2942     case KEYCHAIN_KEY_NODE:
2943       vty->node = KEYCHAIN_NODE;
2944       break;
2945     case LINK_PARAMS_NODE:
2946       vty->node = INTERFACE_NODE;
2947       break;
2948     default:
2949       break;
2950     }
2951   return CMD_SUCCESS;
2952 }
2953 
2954 /* quit is alias of exit. */
2955 ALIAS (config_exit,
2956        config_quit_cmd,
2957        "quit",
2958        "Exit current mode and down to previous mode\n")
2959 
2960 /* End of configuration. */
2961 DEFUN (config_end,
2962        config_end_cmd,
2963        "end",
2964        "End current mode and change to enable mode.")
2965 {
2966   switch (vty->node)
2967     {
2968     case VIEW_NODE:
2969     case ENABLE_NODE:
2970     case RESTRICTED_NODE:
2971       /* Nothing to do. */
2972       break;
2973     case CONFIG_NODE:
2974     case INTERFACE_NODE:
2975     case ZEBRA_NODE:
2976     case RIP_NODE:
2977     case RIPNG_NODE:
2978     case BABEL_NODE:
2979     case BGP_NODE:
2980     case BGP_ENCAP_NODE:
2981     case BGP_ENCAPV6_NODE:
2982     case BGP_VPNV4_NODE:
2983     case BGP_VPNV6_NODE:
2984     case BGP_IPV4_NODE:
2985     case BGP_IPV4M_NODE:
2986     case BGP_IPV6_NODE:
2987     case BGP_IPV6M_NODE:
2988     case RMAP_NODE:
2989     case OSPF_NODE:
2990     case OSPF6_NODE:
2991     case ISIS_NODE:
2992     case KEYCHAIN_NODE:
2993     case KEYCHAIN_KEY_NODE:
2994     case MASC_NODE:
2995     case PIM_NODE:
2996     case VTY_NODE:
2997     case LINK_PARAMS_NODE:
2998       vty_config_unlock (vty);
2999       vty->node = ENABLE_NODE;
3000       break;
3001     default:
3002       break;
3003     }
3004   return CMD_SUCCESS;
3005 }
3006 
3007 /* Show version. */
3008 DEFUN (show_version,
3009        show_version_cmd,
3010        "show version",
3011        SHOW_STR
3012        "Displays zebra version\n")
3013 {
3014   vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
3015 	   VTY_NEWLINE);
3016   vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
3017   vty_out (vty, "configured with:%s    %s%s", VTY_NEWLINE,
3018            QUAGGA_CONFIG_ARGS, VTY_NEWLINE);
3019 
3020   return CMD_SUCCESS;
3021 }
3022 
3023 /* Help display function for all node. */
3024 DEFUN (config_help,
3025        config_help_cmd,
3026        "help",
3027        "Description of the interactive help system\n")
3028 {
3029   vty_out (vty,
3030 	   "Quagga VTY provides advanced help feature.  When you need help,%s\
3031 anytime at the command line please press '?'.%s\
3032 %s\
3033 If nothing matches, the help list will be empty and you must backup%s\
3034  until entering a '?' shows the available options.%s\
3035 Two styles of help are provided:%s\
3036 1. Full help is available when you are ready to enter a%s\
3037 command argument (e.g. 'show ?') and describes each possible%s\
3038 argument.%s\
3039 2. Partial help is provided when an abbreviated argument is entered%s\
3040    and you want to know what arguments match the input%s\
3041    (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
3042 	   VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
3043 	   VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
3044   return CMD_SUCCESS;
3045 }
3046 
3047 /* Help display function for all node. */
3048 DEFUN (config_list,
3049        config_list_cmd,
3050        "list",
3051        "Print command list\n")
3052 {
3053   unsigned int i;
3054   struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
3055   struct cmd_element *cmd;
3056 
3057   for (i = 0; i < vector_active (cnode->cmd_vector); i++)
3058     if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
3059         && !(cmd->attr == CMD_ATTR_DEPRECATED
3060              || cmd->attr == CMD_ATTR_HIDDEN))
3061       vty_out (vty, "  %s%s", cmd->string,
3062 	       VTY_NEWLINE);
3063   return CMD_SUCCESS;
3064 }
3065 
3066 /* Write current configuration into file. */
3067 DEFUN (config_write_file,
3068        config_write_file_cmd,
3069        "write file",
3070        "Write running configuration to memory, network, or terminal\n"
3071        "Write to configuration file\n")
3072 {
3073   unsigned int i;
3074   int fd, dupfd = -1;
3075   struct cmd_node *node;
3076   char *config_file;
3077   char *config_file_tmp = NULL;
3078   char *config_file_sav = NULL;
3079   int ret = CMD_WARNING;
3080   struct vty *file_vty;
3081 
3082   /* Check and see if we are operating under vtysh configuration */
3083   if (host.config == NULL)
3084     {
3085       vty_out (vty, "Can't save to configuration file, using vtysh.%s",
3086 	       VTY_NEWLINE);
3087       return CMD_WARNING;
3088     }
3089 
3090   /* Get filename. */
3091   config_file = host.config;
3092 
3093   config_file_sav =
3094     XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
3095   strcpy (config_file_sav, config_file);
3096   strcat (config_file_sav, CONF_BACKUP_EXT);
3097 
3098 
3099   config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
3100   sprintf (config_file_tmp, "%s.XXXXXX", config_file);
3101 
3102   /* Open file to configuration write. */
3103   fd = mkstemp (config_file_tmp);
3104   if (fd < 0)
3105     {
3106       vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
3107 	       VTY_NEWLINE);
3108       goto finished;
3109     }
3110 
3111   /* Make vty for configuration file. */
3112   file_vty = vty_new ();
3113   file_vty->wfd = fd;
3114   file_vty->type = VTY_FILE;
3115 
3116   /* Config file header print. */
3117   vty_out (file_vty, "!\n! Zebra configuration saved from vty\n!   ");
3118   vty_time_print (file_vty, 1);
3119   vty_out (file_vty, "!\n");
3120 
3121   for (i = 0; i < vector_active (cmdvec); i++)
3122     if ((node = vector_slot (cmdvec, i)) && node->func)
3123       {
3124 	if ((*node->func) (file_vty))
3125 	  vty_out (file_vty, "!\n");
3126       }
3127 
3128   if ((dupfd = dup (file_vty->wfd)) < 0)
3129     {
3130       vty_out (vty, "Couldn't dup fd (for fsync) for %s, %s (%d).%s",
3131                config_file, safe_strerror(errno), errno, VTY_NEWLINE);
3132     }
3133 
3134   vty_close (file_vty);
3135 
3136   if (fsync (dupfd) < 0)
3137     {
3138       vty_out (vty, "Couldn't fsync %s, %s (%d)!%s",
3139                config_file, safe_strerror(errno), errno, VTY_NEWLINE);
3140     }
3141 
3142   if (unlink (config_file_sav) != 0)
3143     if (errno != ENOENT)
3144       {
3145 	vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
3146 		 VTY_NEWLINE);
3147         goto finished;
3148       }
3149   if (link (config_file, config_file_sav) != 0)
3150     {
3151       vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
3152 	        VTY_NEWLINE);
3153       goto finished;
3154     }
3155   if (rename (config_file_tmp, config_file) != 0)
3156     {
3157       vty_out (vty, "Can't move configuration file %s into place.%s",
3158                config_file, VTY_NEWLINE);
3159       goto finished;
3160     }
3161   if (chmod (config_file, CONFIGFILE_MASK) != 0)
3162     {
3163       vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
3164 	config_file, safe_strerror(errno), errno, VTY_NEWLINE);
3165       goto finished;
3166     }
3167 
3168   vty_out (vty, "Configuration saved to %s%s", config_file,
3169 	   VTY_NEWLINE);
3170   ret = CMD_SUCCESS;
3171 
3172 finished:
3173   if (dupfd >= 0)
3174     close (dupfd);
3175   unlink (config_file_tmp);
3176   XFREE (MTYPE_TMP, config_file_tmp);
3177   XFREE (MTYPE_TMP, config_file_sav);
3178   return ret;
3179 }
3180 
3181 ALIAS (config_write_file,
3182        config_write_cmd,
3183        "write",
3184        "Write running configuration to memory, network, or terminal\n")
3185 
3186 ALIAS (config_write_file,
3187        config_write_memory_cmd,
3188        "write memory",
3189        "Write running configuration to memory, network, or terminal\n"
3190        "Write configuration to the file (same as write file)\n")
3191 
3192 ALIAS (config_write_file,
3193        copy_runningconfig_startupconfig_cmd,
3194        "copy running-config startup-config",
3195        "Copy configuration\n"
3196        "Copy running config to... \n"
3197        "Copy running config to startup config (same as write file)\n")
3198 
3199 /* Write current configuration into the terminal. */
3200 DEFUN (config_write_terminal,
3201        config_write_terminal_cmd,
3202        "write terminal",
3203        "Write running configuration to memory, network, or terminal\n"
3204        "Write to terminal\n")
3205 {
3206   unsigned int i;
3207   struct cmd_node *node;
3208 
3209   if (vty->type == VTY_SHELL_SERV)
3210     {
3211       for (i = 0; i < vector_active (cmdvec); i++)
3212 	if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
3213 	  {
3214 	    if ((*node->func) (vty))
3215 	      vty_out (vty, "!%s", VTY_NEWLINE);
3216 	  }
3217     }
3218   else
3219     {
3220       vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
3221 	       VTY_NEWLINE);
3222       vty_out (vty, "!%s", VTY_NEWLINE);
3223 
3224       for (i = 0; i < vector_active (cmdvec); i++)
3225 	if ((node = vector_slot (cmdvec, i)) && node->func)
3226 	  {
3227 	    if ((*node->func) (vty))
3228 	      vty_out (vty, "!%s", VTY_NEWLINE);
3229 	  }
3230       vty_out (vty, "end%s",VTY_NEWLINE);
3231     }
3232   return CMD_SUCCESS;
3233 }
3234 
3235 /* Write current configuration into the terminal. */
3236 ALIAS (config_write_terminal,
3237        show_running_config_cmd,
3238        "show running-config",
3239        SHOW_STR
3240        "running configuration\n")
3241 
3242 /* Write startup configuration into the terminal. */
3243 DEFUN (show_startup_config,
3244        show_startup_config_cmd,
3245        "show startup-config",
3246        SHOW_STR
3247        "Contentes of startup configuration\n")
3248 {
3249   char buf[BUFSIZ];
3250   FILE *confp;
3251 
3252   confp = fopen (host.config, "r");
3253   if (confp == NULL)
3254     {
3255       vty_out (vty, "Can't open configuration file [%s]%s",
3256 	       host.config, VTY_NEWLINE);
3257       return CMD_WARNING;
3258     }
3259 
3260   while (fgets (buf, BUFSIZ, confp))
3261     {
3262       char *cp = buf;
3263 
3264       while (*cp != '\r' && *cp != '\n' && *cp != '\0')
3265 	cp++;
3266       *cp = '\0';
3267 
3268       vty_out (vty, "%s%s", buf, VTY_NEWLINE);
3269     }
3270 
3271   fclose (confp);
3272 
3273   return CMD_SUCCESS;
3274 }
3275 
3276 /* Hostname configuration */
3277 DEFUN (config_hostname,
3278        hostname_cmd,
3279        "hostname WORD",
3280        "Set system's network name\n"
3281        "This system's network name\n")
3282 {
3283   if (!isalpha((int) *argv[0]))
3284     {
3285       vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
3286       return CMD_WARNING;
3287     }
3288 
3289   if (host.name)
3290     XFREE (MTYPE_HOST, host.name);
3291 
3292   host.name = XSTRDUP (MTYPE_HOST, argv[0]);
3293   return CMD_SUCCESS;
3294 }
3295 
3296 DEFUN (config_no_hostname,
3297        no_hostname_cmd,
3298        "no hostname [HOSTNAME]",
3299        NO_STR
3300        "Reset system's network name\n"
3301        "Host name of this router\n")
3302 {
3303   if (host.name)
3304     XFREE (MTYPE_HOST, host.name);
3305   host.name = NULL;
3306   return CMD_SUCCESS;
3307 }
3308 
3309 /* VTY interface password set. */
3310 DEFUN (config_password, password_cmd,
3311        "password (8|) WORD",
3312        "Assign the terminal connection password\n"
3313        "Specifies a HIDDEN password will follow\n"
3314        "dummy string \n"
3315        "The HIDDEN line password string\n")
3316 {
3317   /* Argument check. */
3318   if (argc == 0)
3319     {
3320       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3321       return CMD_WARNING;
3322     }
3323 
3324   if (argc == 2)
3325     {
3326       if (*argv[0] == '8')
3327 	{
3328 	  if (host.password)
3329 	    XFREE (MTYPE_HOST, host.password);
3330 	  host.password = NULL;
3331 	  if (host.password_encrypt)
3332 	    XFREE (MTYPE_HOST, host.password_encrypt);
3333 	  host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
3334 	  return CMD_SUCCESS;
3335 	}
3336       else
3337 	{
3338 	  vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3339 	  return CMD_WARNING;
3340 	}
3341     }
3342 
3343   if (!isalnum ((int) *argv[0]))
3344     {
3345       vty_out (vty,
3346 	       "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3347       return CMD_WARNING;
3348     }
3349 
3350   if (host.password)
3351     XFREE (MTYPE_HOST, host.password);
3352   host.password = NULL;
3353 
3354   if (host.encrypt)
3355     {
3356       if (host.password_encrypt)
3357 	XFREE (MTYPE_HOST, host.password_encrypt);
3358       host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
3359     }
3360   else
3361     host.password = XSTRDUP (MTYPE_HOST, argv[0]);
3362 
3363   return CMD_SUCCESS;
3364 }
3365 
3366 ALIAS (config_password, password_text_cmd,
3367        "password LINE",
3368        "Assign the terminal connection password\n"
3369        "The UNENCRYPTED (cleartext) line password\n")
3370 
3371 /* VTY enable password set. */
3372 DEFUN (config_enable_password, enable_password_cmd,
3373        "enable password (8|) WORD",
3374        "Modify enable password parameters\n"
3375        "Assign the privileged level password\n"
3376        "Specifies a HIDDEN password will follow\n"
3377        "dummy string \n"
3378        "The HIDDEN 'enable' password string\n")
3379 {
3380   /* Argument check. */
3381   if (argc == 0)
3382     {
3383       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3384       return CMD_WARNING;
3385     }
3386 
3387   /* Crypt type is specified. */
3388   if (argc == 2)
3389     {
3390       if (*argv[0] == '8')
3391 	{
3392 	  if (host.enable)
3393 	    XFREE (MTYPE_HOST, host.enable);
3394 	  host.enable = NULL;
3395 
3396 	  if (host.enable_encrypt)
3397 	    XFREE (MTYPE_HOST, host.enable_encrypt);
3398 	  host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
3399 
3400 	  return CMD_SUCCESS;
3401 	}
3402       else
3403 	{
3404 	  vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3405 	  return CMD_WARNING;
3406 	}
3407     }
3408 
3409   if (!isalnum ((int) *argv[0]))
3410     {
3411       vty_out (vty,
3412 	       "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3413       return CMD_WARNING;
3414     }
3415 
3416   if (host.enable)
3417     XFREE (MTYPE_HOST, host.enable);
3418   host.enable = NULL;
3419 
3420   /* Plain password input. */
3421   if (host.encrypt)
3422     {
3423       if (host.enable_encrypt)
3424 	XFREE (MTYPE_HOST, host.enable_encrypt);
3425       host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
3426     }
3427   else
3428     host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
3429 
3430   return CMD_SUCCESS;
3431 }
3432 
3433 ALIAS (config_enable_password,
3434        enable_password_text_cmd,
3435        "enable password LINE",
3436        "Modify enable password parameters\n"
3437        "Assign the privileged level password\n"
3438        "The UNENCRYPTED (cleartext) 'enable' password\n")
3439 
3440 /* VTY enable password delete. */
3441 DEFUN (no_config_enable_password, no_enable_password_cmd,
3442        "no enable password",
3443        NO_STR
3444        "Modify enable password parameters\n"
3445        "Assign the privileged level password\n")
3446 {
3447   if (host.enable)
3448     XFREE (MTYPE_HOST, host.enable);
3449   host.enable = NULL;
3450 
3451   if (host.enable_encrypt)
3452     XFREE (MTYPE_HOST, host.enable_encrypt);
3453   host.enable_encrypt = NULL;
3454 
3455   return CMD_SUCCESS;
3456 }
3457 
3458 DEFUN (service_password_encrypt,
3459        service_password_encrypt_cmd,
3460        "service password-encryption",
3461        "Set up miscellaneous service\n"
3462        "Enable encrypted passwords\n")
3463 {
3464   if (host.encrypt)
3465     return CMD_SUCCESS;
3466 
3467   host.encrypt = 1;
3468 
3469   if (host.password)
3470     {
3471       if (host.password_encrypt)
3472 	XFREE (MTYPE_HOST, host.password_encrypt);
3473       host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
3474     }
3475   if (host.enable)
3476     {
3477       if (host.enable_encrypt)
3478 	XFREE (MTYPE_HOST, host.enable_encrypt);
3479       host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
3480     }
3481 
3482   return CMD_SUCCESS;
3483 }
3484 
3485 DEFUN (no_service_password_encrypt,
3486        no_service_password_encrypt_cmd,
3487        "no service password-encryption",
3488        NO_STR
3489        "Set up miscellaneous service\n"
3490        "Enable encrypted passwords\n")
3491 {
3492   if (! host.encrypt)
3493     return CMD_SUCCESS;
3494 
3495   host.encrypt = 0;
3496 
3497   if (host.password_encrypt)
3498     XFREE (MTYPE_HOST, host.password_encrypt);
3499   host.password_encrypt = NULL;
3500 
3501   if (host.enable_encrypt)
3502     XFREE (MTYPE_HOST, host.enable_encrypt);
3503   host.enable_encrypt = NULL;
3504 
3505   return CMD_SUCCESS;
3506 }
3507 
3508 DEFUN (config_terminal_length, config_terminal_length_cmd,
3509        "terminal length <0-512>",
3510        "Set terminal line parameters\n"
3511        "Set number of lines on a screen\n"
3512        "Number of lines on screen (0 for no pausing)\n")
3513 {
3514   int lines;
3515   char *endptr = NULL;
3516 
3517   lines = strtol (argv[0], &endptr, 10);
3518   if (lines < 0 || lines > 512 || *endptr != '\0')
3519     {
3520       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3521       return CMD_WARNING;
3522     }
3523   vty->lines = lines;
3524 
3525   return CMD_SUCCESS;
3526 }
3527 
3528 DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
3529        "terminal no length",
3530        "Set terminal line parameters\n"
3531        NO_STR
3532        "Set number of lines on a screen\n")
3533 {
3534   vty->lines = -1;
3535   return CMD_SUCCESS;
3536 }
3537 
3538 DEFUN (service_terminal_length, service_terminal_length_cmd,
3539        "service terminal-length <0-512>",
3540        "Set up miscellaneous service\n"
3541        "System wide terminal length configuration\n"
3542        "Number of lines of VTY (0 means no line control)\n")
3543 {
3544   int lines;
3545   char *endptr = NULL;
3546 
3547   lines = strtol (argv[0], &endptr, 10);
3548   if (lines < 0 || lines > 512 || *endptr != '\0')
3549     {
3550       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3551       return CMD_WARNING;
3552     }
3553   host.lines = lines;
3554 
3555   return CMD_SUCCESS;
3556 }
3557 
3558 DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3559        "no service terminal-length [<0-512>]",
3560        NO_STR
3561        "Set up miscellaneous service\n"
3562        "System wide terminal length configuration\n"
3563        "Number of lines of VTY (0 means no line control)\n")
3564 {
3565   host.lines = -1;
3566   return CMD_SUCCESS;
3567 }
3568 
3569 DEFUN_HIDDEN (do_echo,
3570 	      echo_cmd,
3571 	      "echo .MESSAGE",
3572 	      "Echo a message back to the vty\n"
3573 	      "The message to echo\n")
3574 {
3575   char *message;
3576 
3577   vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3578 	   VTY_NEWLINE);
3579   if (message)
3580     XFREE(MTYPE_TMP, message);
3581   return CMD_SUCCESS;
3582 }
3583 
3584 DEFUN (config_logmsg,
3585        config_logmsg_cmd,
3586        "logmsg "LOG_LEVELS" .MESSAGE",
3587        "Send a message to enabled logging destinations\n"
3588        LOG_LEVEL_DESC
3589        "The message to send\n")
3590 {
3591   int level;
3592   char *message;
3593 
3594   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3595     return CMD_ERR_NO_MATCH;
3596 
3597   zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
3598   if (message)
3599     XFREE(MTYPE_TMP, message);
3600   return CMD_SUCCESS;
3601 }
3602 
3603 DEFUN (show_logging,
3604        show_logging_cmd,
3605        "show logging",
3606        SHOW_STR
3607        "Show current logging configuration\n")
3608 {
3609   struct zlog *zl = zlog_default;
3610 
3611   vty_out (vty, "Syslog logging: ");
3612   if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3613     vty_out (vty, "disabled");
3614   else
3615     vty_out (vty, "level %s, facility %s, ident %s",
3616 	     zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3617 	     facility_name(zl->facility), zl->ident);
3618   vty_out (vty, "%s", VTY_NEWLINE);
3619 
3620   vty_out (vty, "Stdout logging: ");
3621   if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3622     vty_out (vty, "disabled");
3623   else
3624     vty_out (vty, "level %s",
3625 	     zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3626   vty_out (vty, "%s", VTY_NEWLINE);
3627 
3628   vty_out (vty, "Monitor logging: ");
3629   if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3630     vty_out (vty, "disabled");
3631   else
3632     vty_out (vty, "level %s",
3633 	     zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3634   vty_out (vty, "%s", VTY_NEWLINE);
3635 
3636   vty_out (vty, "File logging: ");
3637   if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3638       !zl->fp)
3639     vty_out (vty, "disabled");
3640   else
3641     vty_out (vty, "level %s, filename %s",
3642 	     zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3643 	     zl->filename);
3644   vty_out (vty, "%s", VTY_NEWLINE);
3645 
3646   vty_out (vty, "Protocol name: %s%s",
3647   	   zlog_proto_names[zl->protocol], VTY_NEWLINE);
3648   vty_out (vty, "Record priority: %s%s",
3649   	   (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3650   vty_out (vty, "Timestamp precision: %d%s",
3651 	   zl->timestamp_precision, VTY_NEWLINE);
3652 
3653   return CMD_SUCCESS;
3654 }
3655 
3656 DEFUN (config_log_stdout,
3657        config_log_stdout_cmd,
3658        "log stdout",
3659        "Logging control\n"
3660        "Set stdout logging level\n")
3661 {
3662   zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3663   return CMD_SUCCESS;
3664 }
3665 
3666 DEFUN (config_log_stdout_level,
3667        config_log_stdout_level_cmd,
3668        "log stdout "LOG_LEVELS,
3669        "Logging control\n"
3670        "Set stdout logging level\n"
3671        LOG_LEVEL_DESC)
3672 {
3673   int level;
3674 
3675   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3676     return CMD_ERR_NO_MATCH;
3677   zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
3678   return CMD_SUCCESS;
3679 }
3680 
3681 DEFUN (no_config_log_stdout,
3682        no_config_log_stdout_cmd,
3683        "no log stdout [LEVEL]",
3684        NO_STR
3685        "Logging control\n"
3686        "Cancel logging to stdout\n"
3687        "Logging level\n")
3688 {
3689   zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
3690   return CMD_SUCCESS;
3691 }
3692 
3693 DEFUN (config_log_monitor,
3694        config_log_monitor_cmd,
3695        "log monitor",
3696        "Logging control\n"
3697        "Set terminal line (monitor) logging level\n")
3698 {
3699   zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3700   return CMD_SUCCESS;
3701 }
3702 
3703 DEFUN (config_log_monitor_level,
3704        config_log_monitor_level_cmd,
3705        "log monitor "LOG_LEVELS,
3706        "Logging control\n"
3707        "Set terminal line (monitor) logging level\n"
3708        LOG_LEVEL_DESC)
3709 {
3710   int level;
3711 
3712   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3713     return CMD_ERR_NO_MATCH;
3714   zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3715   return CMD_SUCCESS;
3716 }
3717 
3718 DEFUN (no_config_log_monitor,
3719        no_config_log_monitor_cmd,
3720        "no log monitor [LEVEL]",
3721        NO_STR
3722        "Logging control\n"
3723        "Disable terminal line (monitor) logging\n"
3724        "Logging level\n")
3725 {
3726   zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3727   return CMD_SUCCESS;
3728 }
3729 
3730 static int
set_log_file(struct vty * vty,const char * fname,int loglevel)3731 set_log_file(struct vty *vty, const char *fname, int loglevel)
3732 {
3733   int ret;
3734   char *p = NULL;
3735   const char *fullpath;
3736 
3737   /* Path detection. */
3738   if (! IS_DIRECTORY_SEP (*fname))
3739     {
3740       char cwd[MAXPATHLEN+1];
3741       cwd[MAXPATHLEN] = '\0';
3742 
3743       if (getcwd (cwd, MAXPATHLEN) == NULL)
3744         {
3745           zlog_err ("config_log_file: Unable to alloc mem!");
3746           return CMD_WARNING;
3747         }
3748 
3749       if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
3750           == NULL)
3751         {
3752           zlog_err ("config_log_file: Unable to alloc mem!");
3753           return CMD_WARNING;
3754         }
3755       sprintf (p, "%s/%s", cwd, fname);
3756       fullpath = p;
3757     }
3758   else
3759     fullpath = fname;
3760 
3761   ret = zlog_set_file (NULL, fullpath, loglevel);
3762 
3763   if (p)
3764     XFREE (MTYPE_TMP, p);
3765 
3766   if (!ret)
3767     {
3768       vty_out (vty, "can't open logfile %s\n", fname);
3769       return CMD_WARNING;
3770     }
3771 
3772   if (host.logfile)
3773     XFREE (MTYPE_HOST, host.logfile);
3774 
3775   host.logfile = XSTRDUP (MTYPE_HOST, fname);
3776 
3777   return CMD_SUCCESS;
3778 }
3779 
3780 DEFUN (config_log_file,
3781        config_log_file_cmd,
3782        "log file FILENAME",
3783        "Logging control\n"
3784        "Logging to file\n"
3785        "Logging filename\n")
3786 {
3787   return set_log_file(vty, argv[0], zlog_default->default_lvl);
3788 }
3789 
3790 DEFUN (config_log_file_level,
3791        config_log_file_level_cmd,
3792        "log file FILENAME "LOG_LEVELS,
3793        "Logging control\n"
3794        "Logging to file\n"
3795        "Logging filename\n"
3796        LOG_LEVEL_DESC)
3797 {
3798   int level;
3799 
3800   if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3801     return CMD_ERR_NO_MATCH;
3802   return set_log_file(vty, argv[0], level);
3803 }
3804 
3805 DEFUN (no_config_log_file,
3806        no_config_log_file_cmd,
3807        "no log file [FILENAME]",
3808        NO_STR
3809        "Logging control\n"
3810        "Cancel logging to file\n"
3811        "Logging file name\n")
3812 {
3813   zlog_reset_file (NULL);
3814 
3815   if (host.logfile)
3816     XFREE (MTYPE_HOST, host.logfile);
3817 
3818   host.logfile = NULL;
3819 
3820   return CMD_SUCCESS;
3821 }
3822 
3823 ALIAS (no_config_log_file,
3824        no_config_log_file_level_cmd,
3825        "no log file FILENAME LEVEL",
3826        NO_STR
3827        "Logging control\n"
3828        "Cancel logging to file\n"
3829        "Logging file name\n"
3830        "Logging level\n")
3831 
3832 DEFUN (config_log_syslog,
3833        config_log_syslog_cmd,
3834        "log syslog",
3835        "Logging control\n"
3836        "Set syslog logging level\n")
3837 {
3838   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3839   return CMD_SUCCESS;
3840 }
3841 
3842 DEFUN (config_log_syslog_level,
3843        config_log_syslog_level_cmd,
3844        "log syslog "LOG_LEVELS,
3845        "Logging control\n"
3846        "Set syslog logging level\n"
3847        LOG_LEVEL_DESC)
3848 {
3849   int level;
3850 
3851   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3852     return CMD_ERR_NO_MATCH;
3853   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3854   return CMD_SUCCESS;
3855 }
3856 
3857 DEFUN_DEPRECATED (config_log_syslog_facility,
3858 		  config_log_syslog_facility_cmd,
3859 		  "log syslog facility "LOG_FACILITIES,
3860 		  "Logging control\n"
3861 		  "Logging goes to syslog\n"
3862 		  "(Deprecated) Facility parameter for syslog messages\n"
3863 		  LOG_FACILITY_DESC)
3864 {
3865   int facility;
3866 
3867   if ((facility = facility_match(argv[0])) < 0)
3868     return CMD_ERR_NO_MATCH;
3869 
3870   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3871   zlog_default->facility = facility;
3872   return CMD_SUCCESS;
3873 }
3874 
3875 DEFUN (no_config_log_syslog,
3876        no_config_log_syslog_cmd,
3877        "no log syslog [LEVEL]",
3878        NO_STR
3879        "Logging control\n"
3880        "Cancel logging to syslog\n"
3881        "Logging level\n")
3882 {
3883   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
3884   return CMD_SUCCESS;
3885 }
3886 
3887 ALIAS (no_config_log_syslog,
3888        no_config_log_syslog_facility_cmd,
3889        "no log syslog facility "LOG_FACILITIES,
3890        NO_STR
3891        "Logging control\n"
3892        "Logging goes to syslog\n"
3893        "Facility parameter for syslog messages\n"
3894        LOG_FACILITY_DESC)
3895 
3896 DEFUN (config_log_facility,
3897        config_log_facility_cmd,
3898        "log facility "LOG_FACILITIES,
3899        "Logging control\n"
3900        "Facility parameter for syslog messages\n"
3901        LOG_FACILITY_DESC)
3902 {
3903   int facility;
3904 
3905   if ((facility = facility_match(argv[0])) < 0)
3906     return CMD_ERR_NO_MATCH;
3907   zlog_default->facility = facility;
3908   return CMD_SUCCESS;
3909 }
3910 
3911 DEFUN (no_config_log_facility,
3912        no_config_log_facility_cmd,
3913        "no log facility [FACILITY]",
3914        NO_STR
3915        "Logging control\n"
3916        "Reset syslog facility to default (daemon)\n"
3917        "Syslog facility\n")
3918 {
3919   zlog_default->facility = LOG_DAEMON;
3920   return CMD_SUCCESS;
3921 }
3922 
3923 DEFUN_DEPRECATED (config_log_trap,
3924 		  config_log_trap_cmd,
3925 		  "log trap "LOG_LEVELS,
3926 		  "Logging control\n"
3927 		  "(Deprecated) Set logging level and default for all destinations\n"
3928 		  LOG_LEVEL_DESC)
3929 {
3930   int new_level ;
3931   int i;
3932 
3933   if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3934     return CMD_ERR_NO_MATCH;
3935 
3936   zlog_default->default_lvl = new_level;
3937   for (i = 0; i < ZLOG_NUM_DESTS; i++)
3938     if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3939       zlog_default->maxlvl[i] = new_level;
3940   return CMD_SUCCESS;
3941 }
3942 
3943 DEFUN_DEPRECATED (no_config_log_trap,
3944 		  no_config_log_trap_cmd,
3945 		  "no log trap [LEVEL]",
3946 		  NO_STR
3947 		  "Logging control\n"
3948 		  "Permit all logging information\n"
3949 		  "Logging level\n")
3950 {
3951   zlog_default->default_lvl = LOG_DEBUG;
3952   return CMD_SUCCESS;
3953 }
3954 
3955 DEFUN (config_log_record_priority,
3956        config_log_record_priority_cmd,
3957        "log record-priority",
3958        "Logging control\n"
3959        "Log the priority of the message within the message\n")
3960 {
3961   zlog_default->record_priority = 1 ;
3962   return CMD_SUCCESS;
3963 }
3964 
3965 DEFUN (no_config_log_record_priority,
3966        no_config_log_record_priority_cmd,
3967        "no log record-priority",
3968        NO_STR
3969        "Logging control\n"
3970        "Do not log the priority of the message within the message\n")
3971 {
3972   zlog_default->record_priority = 0 ;
3973   return CMD_SUCCESS;
3974 }
3975 
3976 DEFUN (config_log_timestamp_precision,
3977        config_log_timestamp_precision_cmd,
3978        "log timestamp precision <0-6>",
3979        "Logging control\n"
3980        "Timestamp configuration\n"
3981        "Set the timestamp precision\n"
3982        "Number of subsecond digits\n")
3983 {
3984   if (argc != 1)
3985     {
3986       vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3987       return CMD_WARNING;
3988     }
3989 
3990   VTY_GET_INTEGER_RANGE("Timestamp Precision",
3991   			zlog_default->timestamp_precision, argv[0], 0, 6);
3992   return CMD_SUCCESS;
3993 }
3994 
3995 DEFUN (no_config_log_timestamp_precision,
3996        no_config_log_timestamp_precision_cmd,
3997        "no log timestamp precision",
3998        NO_STR
3999        "Logging control\n"
4000        "Timestamp configuration\n"
4001        "Reset the timestamp precision to the default value of 0\n")
4002 {
4003   zlog_default->timestamp_precision = 0 ;
4004   return CMD_SUCCESS;
4005 }
4006 
4007 DEFUN (banner_motd_file,
4008        banner_motd_file_cmd,
4009        "banner motd file [FILE]",
4010        "Set banner\n"
4011        "Banner for motd\n"
4012        "Banner from a file\n"
4013        "Filename\n")
4014 {
4015   if (host.motdfile)
4016     XFREE (MTYPE_HOST, host.motdfile);
4017   host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
4018 
4019   return CMD_SUCCESS;
4020 }
4021 
4022 DEFUN (banner_motd_default,
4023        banner_motd_default_cmd,
4024        "banner motd default",
4025        "Set banner string\n"
4026        "Strings for motd\n"
4027        "Default string\n")
4028 {
4029   host.motd = default_motd;
4030   return CMD_SUCCESS;
4031 }
4032 
4033 DEFUN (no_banner_motd,
4034        no_banner_motd_cmd,
4035        "no banner motd",
4036        NO_STR
4037        "Set banner string\n"
4038        "Strings for motd\n")
4039 {
4040   host.motd = NULL;
4041   if (host.motdfile)
4042     XFREE (MTYPE_HOST, host.motdfile);
4043   host.motdfile = NULL;
4044   return CMD_SUCCESS;
4045 }
4046 
4047 DEFUN (show_commandtree,
4048        show_commandtree_cmd,
4049        "show commandtree",
4050        NO_STR
4051        "Show command tree\n")
4052 {
4053   /* TBD */
4054   vector cmd_vector;
4055   unsigned int i;
4056 
4057   vty_out (vty, "Current node id: %d%s", vty->node, VTY_NEWLINE);
4058 
4059   /* vector of all commands installed at this node */
4060   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
4061 
4062   /* loop over all commands at this node */
4063   for (i = 0; i < vector_active(cmd_vector); ++i)
4064     {
4065       struct cmd_element *cmd_element;
4066 
4067       /* A cmd_element (seems to be) is an individual command */
4068       if ((cmd_element = vector_slot (cmd_vector, i)) == NULL)
4069         continue;
4070 
4071       vty_out (vty, "    %s%s", cmd_element->string, VTY_NEWLINE);
4072     }
4073 
4074   vector_free (cmd_vector);
4075   return CMD_SUCCESS;
4076 }
4077 
4078 /* Set config filename.  Called from vty.c */
4079 void
host_config_set(char * filename)4080 host_config_set (char *filename)
4081 {
4082   if (host.config)
4083     XFREE (MTYPE_HOST, host.config);
4084   host.config = XSTRDUP (MTYPE_HOST, filename);
4085 }
4086 
4087 const char *
host_config_get(void)4088 host_config_get (void)
4089 {
4090   return host.config;
4091 }
4092 
4093 static void
install_default_basic(enum node_type node)4094 install_default_basic (enum node_type node)
4095 {
4096   install_element (node, &config_exit_cmd);
4097   install_element (node, &config_quit_cmd);
4098   install_element (node, &config_help_cmd);
4099   install_element (node, &config_list_cmd);
4100 }
4101 
4102 /* Install common/default commands for a privileged node */
4103 void
install_default(enum node_type node)4104 install_default (enum node_type node)
4105 {
4106   /* VIEW_NODE is inited below, via install_default_basic, and
4107      install_element's of commands to VIEW_NODE automatically are
4108      also installed to ENABLE_NODE.
4109 
4110      For all other nodes, we must ensure install_default_basic is
4111      also called/
4112    */
4113   if (node != VIEW_NODE && node != ENABLE_NODE)
4114     install_default_basic (node);
4115 
4116   install_element (node, &config_end_cmd);
4117   install_element (node, &config_write_terminal_cmd);
4118   install_element (node, &config_write_file_cmd);
4119   install_element (node, &config_write_memory_cmd);
4120   install_element (node, &config_write_cmd);
4121   install_element (node, &show_running_config_cmd);
4122 }
4123 
4124 /* Initialize command interface. Install basic nodes and commands. */
4125 void
cmd_init(int terminal)4126 cmd_init (int terminal)
4127 {
4128   command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
4129   token_cr.type = TOKEN_TERMINAL;
4130   token_cr.terminal = TERMINAL_LITERAL;
4131   token_cr.cmd = command_cr;
4132   token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
4133 
4134   /* Allocate initial top vector of commands. */
4135   cmdvec = vector_init (VECTOR_MIN_SIZE);
4136 
4137   /* Default host value settings. */
4138   host.name = NULL;
4139   host.password = NULL;
4140   host.enable = NULL;
4141   host.logfile = NULL;
4142   host.config = NULL;
4143   host.lines = -1;
4144   host.motd = default_motd;
4145   host.motdfile = NULL;
4146 
4147   /* Install top nodes. */
4148   install_node (&view_node, NULL);
4149   install_node (&enable_node, NULL);
4150   install_node (&auth_node, NULL);
4151   install_node (&auth_enable_node, NULL);
4152   install_node (&restricted_node, NULL);
4153   install_node (&config_node, config_write_host);
4154 
4155   /* Each node's basic commands. */
4156   install_element (VIEW_NODE, &show_version_cmd);
4157   if (terminal)
4158     {
4159       install_default_basic (VIEW_NODE);
4160 
4161       install_element (VIEW_NODE, &config_enable_cmd);
4162       install_element (VIEW_NODE, &config_terminal_length_cmd);
4163       install_element (VIEW_NODE, &config_terminal_no_length_cmd);
4164       install_element (VIEW_NODE, &show_logging_cmd);
4165       install_element (VIEW_NODE, &show_commandtree_cmd);
4166       install_element (VIEW_NODE, &echo_cmd);
4167 
4168       install_element (RESTRICTED_NODE, &config_enable_cmd);
4169       install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
4170       install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
4171       install_element (RESTRICTED_NODE, &show_commandtree_cmd);
4172       install_element (RESTRICTED_NODE, &echo_cmd);
4173     }
4174 
4175   if (terminal)
4176     {
4177       install_default (ENABLE_NODE);
4178       install_element (ENABLE_NODE, &config_disable_cmd);
4179       install_element (ENABLE_NODE, &config_terminal_cmd);
4180       install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
4181     }
4182   install_element (ENABLE_NODE, &show_startup_config_cmd);
4183 
4184   if (terminal)
4185     {
4186       install_element (ENABLE_NODE, &config_logmsg_cmd);
4187 
4188       install_default (CONFIG_NODE);
4189     }
4190 
4191   install_element (CONFIG_NODE, &hostname_cmd);
4192   install_element (CONFIG_NODE, &no_hostname_cmd);
4193 
4194   if (terminal)
4195     {
4196       install_element (CONFIG_NODE, &password_cmd);
4197       install_element (CONFIG_NODE, &password_text_cmd);
4198       install_element (CONFIG_NODE, &enable_password_cmd);
4199       install_element (CONFIG_NODE, &enable_password_text_cmd);
4200       install_element (CONFIG_NODE, &no_enable_password_cmd);
4201 
4202       install_element (CONFIG_NODE, &config_log_stdout_cmd);
4203       install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
4204       install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
4205       install_element (CONFIG_NODE, &config_log_monitor_cmd);
4206       install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
4207       install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
4208       install_element (CONFIG_NODE, &config_log_file_cmd);
4209       install_element (CONFIG_NODE, &config_log_file_level_cmd);
4210       install_element (CONFIG_NODE, &no_config_log_file_cmd);
4211       install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
4212       install_element (CONFIG_NODE, &config_log_syslog_cmd);
4213       install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
4214       install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
4215       install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
4216       install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
4217       install_element (CONFIG_NODE, &config_log_facility_cmd);
4218       install_element (CONFIG_NODE, &no_config_log_facility_cmd);
4219       install_element (CONFIG_NODE, &config_log_trap_cmd);
4220       install_element (CONFIG_NODE, &no_config_log_trap_cmd);
4221       install_element (CONFIG_NODE, &config_log_record_priority_cmd);
4222       install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
4223       install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
4224       install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
4225       install_element (CONFIG_NODE, &service_password_encrypt_cmd);
4226       install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
4227       install_element (CONFIG_NODE, &banner_motd_default_cmd);
4228       install_element (CONFIG_NODE, &banner_motd_file_cmd);
4229       install_element (CONFIG_NODE, &no_banner_motd_cmd);
4230       install_element (CONFIG_NODE, &service_terminal_length_cmd);
4231       install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
4232 
4233       install_element (VIEW_NODE, &show_thread_cpu_cmd);
4234       install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
4235 
4236       install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
4237       install_element (VIEW_NODE, &show_work_queues_cmd);
4238     }
4239   install_element (CONFIG_NODE, &show_commandtree_cmd);
4240   srandom(time(NULL));
4241 }
4242 
4243 static void
cmd_terminate_token(struct cmd_token * token)4244 cmd_terminate_token(struct cmd_token *token)
4245 {
4246   unsigned int i, j;
4247   vector keyword_vect;
4248 
4249   if (token->multiple)
4250     {
4251       for (i = 0; i < vector_active(token->multiple); i++)
4252         cmd_terminate_token(vector_slot(token->multiple, i));
4253       vector_free(token->multiple);
4254       token->multiple = NULL;
4255     }
4256 
4257   if (token->keyword)
4258     {
4259       for (i = 0; i < vector_active(token->keyword); i++)
4260         {
4261           keyword_vect = vector_slot(token->keyword, i);
4262           for (j = 0; j < vector_active(keyword_vect); j++)
4263             cmd_terminate_token(vector_slot(keyword_vect, j));
4264           vector_free(keyword_vect);
4265         }
4266       vector_free(token->keyword);
4267       token->keyword = NULL;
4268     }
4269 
4270   XFREE(MTYPE_CMD_TOKENS, token->cmd);
4271   XFREE(MTYPE_CMD_TOKENS, token->desc);
4272 
4273   XFREE(MTYPE_CMD_TOKENS, token);
4274 }
4275 
4276 static void
cmd_terminate_element(struct cmd_element * cmd)4277 cmd_terminate_element(struct cmd_element *cmd)
4278 {
4279   unsigned int i;
4280 
4281   if (cmd->tokens == NULL)
4282     return;
4283 
4284   for (i = 0; i < vector_active(cmd->tokens); i++)
4285     cmd_terminate_token(vector_slot(cmd->tokens, i));
4286 
4287   vector_free(cmd->tokens);
4288   cmd->tokens = NULL;
4289 }
4290 
4291 void
cmd_terminate()4292 cmd_terminate ()
4293 {
4294   unsigned int i, j;
4295   struct cmd_node *cmd_node;
4296   struct cmd_element *cmd_element;
4297   vector cmd_node_v;
4298 
4299   if (cmdvec)
4300     {
4301       for (i = 0; i < vector_active (cmdvec); i++)
4302         if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
4303           {
4304             cmd_node_v = cmd_node->cmd_vector;
4305 
4306             for (j = 0; j < vector_active (cmd_node_v); j++)
4307               if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
4308                 cmd_terminate_element(cmd_element);
4309 
4310             vector_free (cmd_node_v);
4311             hash_clean (cmd_node->cmd_hash, NULL);
4312             hash_free (cmd_node->cmd_hash);
4313             cmd_node->cmd_hash = NULL;
4314           }
4315 
4316       vector_free (cmdvec);
4317       cmdvec = NULL;
4318     }
4319 
4320   if (command_cr)
4321     XFREE(MTYPE_CMD_TOKENS, command_cr);
4322   if (token_cr.desc)
4323     XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
4324   if (host.name)
4325     XFREE (MTYPE_HOST, host.name);
4326   if (host.password)
4327     XFREE (MTYPE_HOST, host.password);
4328   if (host.password_encrypt)
4329     XFREE (MTYPE_HOST, host.password_encrypt);
4330   if (host.enable)
4331     XFREE (MTYPE_HOST, host.enable);
4332   if (host.enable_encrypt)
4333     XFREE (MTYPE_HOST, host.enable_encrypt);
4334   if (host.logfile)
4335     XFREE (MTYPE_HOST, host.logfile);
4336   if (host.motdfile)
4337     XFREE (MTYPE_HOST, host.motdfile);
4338   if (host.config)
4339     XFREE (MTYPE_HOST, host.config);
4340 }
4341