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