]> git.proxmox.com Git - mirror_frr.git/blob - lib/vty.c
3f135004494ff73806435b6abf0a33dce9135720
[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_IPV4_NODE:
751 case BGP_IPV4M_NODE:
752 case BGP_IPV6_NODE:
753 case BGP_IPV6M_NODE:
754 case RMAP_NODE:
755 case OSPF_NODE:
756 case OSPF6_NODE:
757 case LDP_NODE:
758 case LDP_IPV4_NODE:
759 case LDP_IPV6_NODE:
760 case LDP_IPV4_IFACE_NODE:
761 case LDP_IPV6_IFACE_NODE:
762 case LDP_L2VPN_NODE:
763 case LDP_PSEUDOWIRE_NODE:
764 case ISIS_NODE:
765 case KEYCHAIN_NODE:
766 case KEYCHAIN_KEY_NODE:
767 case MASC_NODE:
768 case PIM_NODE:
769 case VTY_NODE:
770 vty_config_unlock (vty);
771 vty->node = ENABLE_NODE;
772 break;
773 default:
774 /* Unknown node, we have to ignore it. */
775 break;
776 }
777
778 vty_prompt (vty);
779 vty->cp = 0;
780 }
781
782 /* Delete a charcter at the current point. */
783 static void
784 vty_delete_char (struct vty *vty)
785 {
786 int i;
787 int size;
788
789 if (vty->length == 0)
790 {
791 vty_down_level (vty);
792 return;
793 }
794
795 if (vty->cp == vty->length)
796 return; /* completion need here? */
797
798 size = vty->length - vty->cp;
799
800 vty->length--;
801 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
802 vty->buf[vty->length] = '\0';
803
804 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
805 return;
806
807 vty_write (vty, &vty->buf[vty->cp], size - 1);
808 vty_write (vty, &telnet_space_char, 1);
809
810 for (i = 0; i < size; i++)
811 vty_write (vty, &telnet_backward_char, 1);
812 }
813
814 /* Delete a character before the point. */
815 static void
816 vty_delete_backward_char (struct vty *vty)
817 {
818 if (vty->cp == 0)
819 return;
820
821 vty_backward_char (vty);
822 vty_delete_char (vty);
823 }
824
825 /* Kill rest of line from current point. */
826 static void
827 vty_kill_line (struct vty *vty)
828 {
829 int i;
830 int size;
831
832 size = vty->length - vty->cp;
833
834 if (size == 0)
835 return;
836
837 for (i = 0; i < size; i++)
838 vty_write (vty, &telnet_space_char, 1);
839 for (i = 0; i < size; i++)
840 vty_write (vty, &telnet_backward_char, 1);
841
842 memset (&vty->buf[vty->cp], 0, size);
843 vty->length = vty->cp;
844 }
845
846 /* Kill line from the beginning. */
847 static void
848 vty_kill_line_from_beginning (struct vty *vty)
849 {
850 vty_beginning_of_line (vty);
851 vty_kill_line (vty);
852 }
853
854 /* Delete a word before the point. */
855 static void
856 vty_forward_kill_word (struct vty *vty)
857 {
858 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
859 vty_delete_char (vty);
860 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
861 vty_delete_char (vty);
862 }
863
864 /* Delete a word before the point. */
865 static void
866 vty_backward_kill_word (struct vty *vty)
867 {
868 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
869 vty_delete_backward_char (vty);
870 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
871 vty_delete_backward_char (vty);
872 }
873
874 /* Transpose chars before or at the point. */
875 static void
876 vty_transpose_chars (struct vty *vty)
877 {
878 char c1, c2;
879
880 /* If length is short or point is near by the beginning of line then
881 return. */
882 if (vty->length < 2 || vty->cp < 1)
883 return;
884
885 /* In case of point is located at the end of the line. */
886 if (vty->cp == vty->length)
887 {
888 c1 = vty->buf[vty->cp - 1];
889 c2 = vty->buf[vty->cp - 2];
890
891 vty_backward_char (vty);
892 vty_backward_char (vty);
893 vty_self_insert_overwrite (vty, c1);
894 vty_self_insert_overwrite (vty, c2);
895 }
896 else
897 {
898 c1 = vty->buf[vty->cp];
899 c2 = vty->buf[vty->cp - 1];
900
901 vty_backward_char (vty);
902 vty_self_insert_overwrite (vty, c1);
903 vty_self_insert_overwrite (vty, c2);
904 }
905 }
906
907 /* Do completion at vty interface. */
908 static void
909 vty_complete_command (struct vty *vty)
910 {
911 int i;
912 int ret;
913 char **matched = NULL;
914 vector vline;
915
916 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
917 return;
918
919 vline = cmd_make_strvec (vty->buf);
920 if (vline == NULL)
921 return;
922
923 /* In case of 'help \t'. */
924 if (isspace ((int) vty->buf[vty->length - 1]))
925 vector_set (vline, NULL);
926
927 matched = cmd_complete_command_lib (vline, vty, &ret, 1);
928
929 cmd_free_strvec (vline);
930
931 vty_out (vty, "%s", VTY_NEWLINE);
932 switch (ret)
933 {
934 case CMD_ERR_AMBIGUOUS:
935 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
936 vty_prompt (vty);
937 vty_redraw_line (vty);
938 break;
939 case CMD_ERR_NO_MATCH:
940 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
941 vty_prompt (vty);
942 vty_redraw_line (vty);
943 break;
944 case CMD_COMPLETE_FULL_MATCH:
945 vty_prompt (vty);
946 vty_redraw_line (vty);
947 vty_backward_pure_word (vty);
948 vty_insert_word_overwrite (vty, matched[0]);
949 vty_self_insert (vty, ' ');
950 XFREE (MTYPE_TMP, matched[0]);
951 break;
952 case CMD_COMPLETE_MATCH:
953 vty_prompt (vty);
954 vty_redraw_line (vty);
955 vty_backward_pure_word (vty);
956 vty_insert_word_overwrite (vty, matched[0]);
957 XFREE (MTYPE_TMP, matched[0]);
958 vector_only_index_free (matched);
959 return;
960 break;
961 case CMD_COMPLETE_LIST_MATCH:
962 for (i = 0; matched[i] != NULL; i++)
963 {
964 if (i != 0 && ((i % 6) == 0))
965 vty_out (vty, "%s", VTY_NEWLINE);
966 vty_out (vty, "%-10s ", matched[i]);
967 XFREE (MTYPE_TMP, matched[i]);
968 }
969 vty_out (vty, "%s", VTY_NEWLINE);
970
971 vty_prompt (vty);
972 vty_redraw_line (vty);
973 break;
974 case CMD_ERR_NOTHING_TODO:
975 vty_prompt (vty);
976 vty_redraw_line (vty);
977 break;
978 default:
979 break;
980 }
981 if (matched)
982 vector_only_index_free (matched);
983 }
984
985 static void
986 vty_describe_fold (struct vty *vty, int cmd_width,
987 unsigned int desc_width, struct cmd_token *token)
988 {
989 char *buf;
990 const char *cmd, *p;
991 int pos;
992
993 cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd;
994
995 if (desc_width <= 0)
996 {
997 vty_out (vty, " %-*s %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE);
998 return;
999 }
1000
1001 buf = XCALLOC (MTYPE_TMP, strlen (token->desc) + 1);
1002
1003 for (p = token->desc; strlen (p) > desc_width; p += pos + 1)
1004 {
1005 for (pos = desc_width; pos > 0; pos--)
1006 if (*(p + pos) == ' ')
1007 break;
1008
1009 if (pos == 0)
1010 break;
1011
1012 strncpy (buf, p, pos);
1013 buf[pos] = '\0';
1014 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
1015
1016 cmd = "";
1017 }
1018
1019 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
1020
1021 XFREE (MTYPE_TMP, buf);
1022 }
1023
1024 /* Describe matched command function. */
1025 static void
1026 vty_describe_command (struct vty *vty)
1027 {
1028 int ret;
1029 vector vline;
1030 vector describe;
1031 unsigned int i, width, desc_width;
1032 struct cmd_token *token, *token_cr = NULL;
1033
1034 vline = cmd_make_strvec (vty->buf);
1035
1036 /* In case of '> ?'. */
1037 if (vline == NULL)
1038 {
1039 vline = vector_init (1);
1040 vector_set (vline, NULL);
1041 }
1042 else
1043 if (isspace ((int) vty->buf[vty->length - 1]))
1044 vector_set (vline, NULL);
1045
1046 describe = cmd_describe_command (vline, vty, &ret);
1047
1048 vty_out (vty, "%s", VTY_NEWLINE);
1049
1050 /* Ambiguous error. */
1051 switch (ret)
1052 {
1053 case CMD_ERR_AMBIGUOUS:
1054 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
1055 goto out;
1056 break;
1057 case CMD_ERR_NO_MATCH:
1058 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
1059 goto out;
1060 break;
1061 }
1062
1063 /* Get width of command string. */
1064 width = 0;
1065 for (i = 0; i < vector_active (describe); i++)
1066 if ((token = vector_slot (describe, i)) != NULL)
1067 {
1068 unsigned int len;
1069
1070 if (token->cmd[0] == '\0')
1071 continue;
1072
1073 len = strlen (token->cmd);
1074 if (token->cmd[0] == '.')
1075 len--;
1076
1077 if (width < len)
1078 width = len;
1079 }
1080
1081 /* Get width of description string. */
1082 desc_width = vty->width - (width + 6);
1083
1084 /* Print out description. */
1085 for (i = 0; i < vector_active (describe); i++)
1086 if ((token = vector_slot (describe, i)) != NULL)
1087 {
1088 if (token->cmd[0] == '\0')
1089 continue;
1090
1091 if (strcmp (token->cmd, command_cr) == 0)
1092 {
1093 token_cr = token;
1094 continue;
1095 }
1096
1097 if (!token->desc)
1098 vty_out (vty, " %-s%s",
1099 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1100 VTY_NEWLINE);
1101 else if (desc_width >= strlen (token->desc))
1102 vty_out (vty, " %-*s %s%s", width,
1103 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1104 token->desc, VTY_NEWLINE);
1105 else
1106 vty_describe_fold (vty, width, desc_width, token);
1107
1108 #if 0
1109 vty_out (vty, " %-*s %s%s", width
1110 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1111 desc->str ? desc->str : "", VTY_NEWLINE);
1112 #endif /* 0 */
1113 }
1114
1115 if ((token = token_cr))
1116 {
1117 if (!token->desc)
1118 vty_out (vty, " %-s%s",
1119 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1120 VTY_NEWLINE);
1121 else if (desc_width >= strlen (token->desc))
1122 vty_out (vty, " %-*s %s%s", width,
1123 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1124 token->desc, VTY_NEWLINE);
1125 else
1126 vty_describe_fold (vty, width, desc_width, token);
1127 }
1128
1129 out:
1130 cmd_free_strvec (vline);
1131 if (describe)
1132 vector_free (describe);
1133
1134 vty_prompt (vty);
1135 vty_redraw_line (vty);
1136 }
1137
1138 static void
1139 vty_clear_buf (struct vty *vty)
1140 {
1141 memset (vty->buf, 0, vty->max);
1142 }
1143
1144 /* ^C stop current input and do not add command line to the history. */
1145 static void
1146 vty_stop_input (struct vty *vty)
1147 {
1148 vty->cp = vty->length = 0;
1149 vty_clear_buf (vty);
1150 vty_out (vty, "%s", VTY_NEWLINE);
1151
1152 switch (vty->node)
1153 {
1154 case VIEW_NODE:
1155 case ENABLE_NODE:
1156 case RESTRICTED_NODE:
1157 /* Nothing to do. */
1158 break;
1159 case CONFIG_NODE:
1160 case INTERFACE_NODE:
1161 case ZEBRA_NODE:
1162 case RIP_NODE:
1163 case RIPNG_NODE:
1164 case BGP_NODE:
1165 case RMAP_NODE:
1166 case OSPF_NODE:
1167 case OSPF6_NODE:
1168 case LDP_NODE:
1169 case LDP_IPV4_NODE:
1170 case LDP_IPV6_NODE:
1171 case LDP_IPV4_IFACE_NODE:
1172 case LDP_IPV6_IFACE_NODE:
1173 case LDP_L2VPN_NODE:
1174 case LDP_PSEUDOWIRE_NODE:
1175 case ISIS_NODE:
1176 case KEYCHAIN_NODE:
1177 case KEYCHAIN_KEY_NODE:
1178 case MASC_NODE:
1179 case PIM_NODE:
1180 case VTY_NODE:
1181 vty_config_unlock (vty);
1182 vty->node = ENABLE_NODE;
1183 break;
1184 default:
1185 /* Unknown node, we have to ignore it. */
1186 break;
1187 }
1188 vty_prompt (vty);
1189
1190 /* Set history pointer to the latest one. */
1191 vty->hp = vty->hindex;
1192 }
1193
1194 /* Add current command line to the history buffer. */
1195 static void
1196 vty_hist_add (struct vty *vty)
1197 {
1198 int index;
1199
1200 if (vty->length == 0)
1201 return;
1202
1203 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1204
1205 /* Ignore the same string as previous one. */
1206 if (vty->hist[index])
1207 if (strcmp (vty->buf, vty->hist[index]) == 0)
1208 {
1209 vty->hp = vty->hindex;
1210 return;
1211 }
1212
1213 /* Insert history entry. */
1214 if (vty->hist[vty->hindex])
1215 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1216 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1217
1218 /* History index rotation. */
1219 vty->hindex++;
1220 if (vty->hindex == VTY_MAXHIST)
1221 vty->hindex = 0;
1222
1223 vty->hp = vty->hindex;
1224 }
1225
1226 /* #define TELNET_OPTION_DEBUG */
1227
1228 /* Get telnet window size. */
1229 static int
1230 vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1231 {
1232 #ifdef TELNET_OPTION_DEBUG
1233 int i;
1234
1235 for (i = 0; i < nbytes; i++)
1236 {
1237 switch (buf[i])
1238 {
1239 case IAC:
1240 vty_out (vty, "IAC ");
1241 break;
1242 case WILL:
1243 vty_out (vty, "WILL ");
1244 break;
1245 case WONT:
1246 vty_out (vty, "WONT ");
1247 break;
1248 case DO:
1249 vty_out (vty, "DO ");
1250 break;
1251 case DONT:
1252 vty_out (vty, "DONT ");
1253 break;
1254 case SB:
1255 vty_out (vty, "SB ");
1256 break;
1257 case SE:
1258 vty_out (vty, "SE ");
1259 break;
1260 case TELOPT_ECHO:
1261 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1262 break;
1263 case TELOPT_SGA:
1264 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1265 break;
1266 case TELOPT_NAWS:
1267 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1268 break;
1269 default:
1270 vty_out (vty, "%x ", buf[i]);
1271 break;
1272 }
1273 }
1274 vty_out (vty, "%s", VTY_NEWLINE);
1275
1276 #endif /* TELNET_OPTION_DEBUG */
1277
1278 switch (buf[0])
1279 {
1280 case SB:
1281 vty->sb_len = 0;
1282 vty->iac_sb_in_progress = 1;
1283 return 0;
1284 break;
1285 case SE:
1286 {
1287 if (!vty->iac_sb_in_progress)
1288 return 0;
1289
1290 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
1291 {
1292 vty->iac_sb_in_progress = 0;
1293 return 0;
1294 }
1295 switch (vty->sb_buf[0])
1296 {
1297 case TELOPT_NAWS:
1298 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1299 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1300 "should send %d characters, but we received %lu",
1301 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1302 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1303 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1304 "too small to handle the telnet NAWS option",
1305 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1306 else
1307 {
1308 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1309 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1310 #ifdef TELNET_OPTION_DEBUG
1311 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1312 "width %d, height %d%s",
1313 vty->width, vty->height, VTY_NEWLINE);
1314 #endif
1315 }
1316 break;
1317 }
1318 vty->iac_sb_in_progress = 0;
1319 return 0;
1320 break;
1321 }
1322 default:
1323 break;
1324 }
1325 return 1;
1326 }
1327
1328 /* Execute current command line. */
1329 static int
1330 vty_execute (struct vty *vty)
1331 {
1332 int ret;
1333
1334 ret = CMD_SUCCESS;
1335
1336 switch (vty->node)
1337 {
1338 case AUTH_NODE:
1339 case AUTH_ENABLE_NODE:
1340 vty_auth (vty, vty->buf);
1341 break;
1342 default:
1343 ret = vty_command (vty, vty->buf);
1344 if (vty->type == VTY_TERM)
1345 vty_hist_add (vty);
1346 break;
1347 }
1348
1349 /* Clear command line buffer. */
1350 vty->cp = vty->length = 0;
1351 vty_clear_buf (vty);
1352
1353 if (vty->status != VTY_CLOSE )
1354 vty_prompt (vty);
1355
1356 return ret;
1357 }
1358
1359 #define CONTROL(X) ((X) - '@')
1360 #define VTY_NORMAL 0
1361 #define VTY_PRE_ESCAPE 1
1362 #define VTY_ESCAPE 2
1363
1364 /* Escape character command map. */
1365 static void
1366 vty_escape_map (unsigned char c, struct vty *vty)
1367 {
1368 switch (c)
1369 {
1370 case ('A'):
1371 vty_previous_line (vty);
1372 break;
1373 case ('B'):
1374 vty_next_line (vty);
1375 break;
1376 case ('C'):
1377 vty_forward_char (vty);
1378 break;
1379 case ('D'):
1380 vty_backward_char (vty);
1381 break;
1382 default:
1383 break;
1384 }
1385
1386 /* Go back to normal mode. */
1387 vty->escape = VTY_NORMAL;
1388 }
1389
1390 /* Quit print out to the buffer. */
1391 static void
1392 vty_buffer_reset (struct vty *vty)
1393 {
1394 buffer_reset (vty->obuf);
1395 vty_prompt (vty);
1396 vty_redraw_line (vty);
1397 }
1398
1399 /* Read data via vty socket. */
1400 static int
1401 vty_read (struct thread *thread)
1402 {
1403 int i;
1404 int nbytes;
1405 unsigned char buf[VTY_READ_BUFSIZ];
1406
1407 int vty_sock = THREAD_FD (thread);
1408 struct vty *vty = THREAD_ARG (thread);
1409 vty->t_read = NULL;
1410
1411 /* Read raw data from socket */
1412 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1413 {
1414 if (nbytes < 0)
1415 {
1416 if (ERRNO_IO_RETRY(errno))
1417 {
1418 vty_event (VTY_READ, vty_sock, vty);
1419 return 0;
1420 }
1421 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
1422 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1423 __func__, vty->fd, safe_strerror(errno));
1424 buffer_reset(vty->obuf);
1425 }
1426 vty->status = VTY_CLOSE;
1427 }
1428
1429 for (i = 0; i < nbytes; i++)
1430 {
1431 if (buf[i] == IAC)
1432 {
1433 if (!vty->iac)
1434 {
1435 vty->iac = 1;
1436 continue;
1437 }
1438 else
1439 {
1440 vty->iac = 0;
1441 }
1442 }
1443
1444 if (vty->iac_sb_in_progress && !vty->iac)
1445 {
1446 if (vty->sb_len < sizeof(vty->sb_buf))
1447 vty->sb_buf[vty->sb_len] = buf[i];
1448 vty->sb_len++;
1449 continue;
1450 }
1451
1452 if (vty->iac)
1453 {
1454 /* In case of telnet command */
1455 int ret = 0;
1456 ret = vty_telnet_option (vty, buf + i, nbytes - i);
1457 vty->iac = 0;
1458 i += ret;
1459 continue;
1460 }
1461
1462
1463 if (vty->status == VTY_MORE)
1464 {
1465 switch (buf[i])
1466 {
1467 case CONTROL('C'):
1468 case 'q':
1469 case 'Q':
1470 vty_buffer_reset (vty);
1471 break;
1472 #if 0 /* More line does not work for "show ip bgp". */
1473 case '\n':
1474 case '\r':
1475 vty->status = VTY_MORELINE;
1476 break;
1477 #endif
1478 default:
1479 break;
1480 }
1481 continue;
1482 }
1483
1484 /* Escape character. */
1485 if (vty->escape == VTY_ESCAPE)
1486 {
1487 vty_escape_map (buf[i], vty);
1488 continue;
1489 }
1490
1491 /* Pre-escape status. */
1492 if (vty->escape == VTY_PRE_ESCAPE)
1493 {
1494 switch (buf[i])
1495 {
1496 case '[':
1497 vty->escape = VTY_ESCAPE;
1498 break;
1499 case 'b':
1500 vty_backward_word (vty);
1501 vty->escape = VTY_NORMAL;
1502 break;
1503 case 'f':
1504 vty_forward_word (vty);
1505 vty->escape = VTY_NORMAL;
1506 break;
1507 case 'd':
1508 vty_forward_kill_word (vty);
1509 vty->escape = VTY_NORMAL;
1510 break;
1511 case CONTROL('H'):
1512 case 0x7f:
1513 vty_backward_kill_word (vty);
1514 vty->escape = VTY_NORMAL;
1515 break;
1516 default:
1517 vty->escape = VTY_NORMAL;
1518 break;
1519 }
1520 continue;
1521 }
1522
1523 switch (buf[i])
1524 {
1525 case CONTROL('A'):
1526 vty_beginning_of_line (vty);
1527 break;
1528 case CONTROL('B'):
1529 vty_backward_char (vty);
1530 break;
1531 case CONTROL('C'):
1532 vty_stop_input (vty);
1533 break;
1534 case CONTROL('D'):
1535 vty_delete_char (vty);
1536 break;
1537 case CONTROL('E'):
1538 vty_end_of_line (vty);
1539 break;
1540 case CONTROL('F'):
1541 vty_forward_char (vty);
1542 break;
1543 case CONTROL('H'):
1544 case 0x7f:
1545 vty_delete_backward_char (vty);
1546 break;
1547 case CONTROL('K'):
1548 vty_kill_line (vty);
1549 break;
1550 case CONTROL('N'):
1551 vty_next_line (vty);
1552 break;
1553 case CONTROL('P'):
1554 vty_previous_line (vty);
1555 break;
1556 case CONTROL('T'):
1557 vty_transpose_chars (vty);
1558 break;
1559 case CONTROL('U'):
1560 vty_kill_line_from_beginning (vty);
1561 break;
1562 case CONTROL('W'):
1563 vty_backward_kill_word (vty);
1564 break;
1565 case CONTROL('Z'):
1566 vty_end_config (vty);
1567 break;
1568 case '\n':
1569 case '\r':
1570 vty_out (vty, "%s", VTY_NEWLINE);
1571 vty_execute (vty);
1572 break;
1573 case '\t':
1574 vty_complete_command (vty);
1575 break;
1576 case '?':
1577 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1578 vty_self_insert (vty, buf[i]);
1579 else
1580 vty_describe_command (vty);
1581 break;
1582 case '\033':
1583 if (i + 1 < nbytes && buf[i + 1] == '[')
1584 {
1585 vty->escape = VTY_ESCAPE;
1586 i++;
1587 }
1588 else
1589 vty->escape = VTY_PRE_ESCAPE;
1590 break;
1591 default:
1592 if (buf[i] > 31 && buf[i] < 127)
1593 vty_self_insert (vty, buf[i]);
1594 break;
1595 }
1596 }
1597
1598 /* Check status. */
1599 if (vty->status == VTY_CLOSE)
1600 vty_close (vty);
1601 else
1602 {
1603 vty_event (VTY_WRITE, vty->wfd, vty);
1604 vty_event (VTY_READ, vty_sock, vty);
1605 }
1606 return 0;
1607 }
1608
1609 /* Flush buffer to the vty. */
1610 static int
1611 vty_flush (struct thread *thread)
1612 {
1613 int erase;
1614 buffer_status_t flushrc;
1615 int vty_sock = THREAD_FD (thread);
1616 struct vty *vty = THREAD_ARG (thread);
1617
1618 vty->t_write = NULL;
1619
1620 /* Tempolary disable read thread. */
1621 if ((vty->lines == 0) && vty->t_read)
1622 {
1623 thread_cancel (vty->t_read);
1624 vty->t_read = NULL;
1625 }
1626
1627 /* Function execution continue. */
1628 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
1629
1630 /* N.B. if width is 0, that means we don't know the window size. */
1631 if ((vty->lines == 0) || (vty->width == 0) || (vty->height == 0))
1632 flushrc = buffer_flush_available(vty->obuf, vty_sock);
1633 else if (vty->status == VTY_MORELINE)
1634 flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
1635 1, erase, 0);
1636 else
1637 flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
1638 vty->lines >= 0 ? vty->lines :
1639 vty->height,
1640 erase, 0);
1641 switch (flushrc)
1642 {
1643 case BUFFER_ERROR:
1644 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
1645 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1646 vty->fd);
1647 buffer_reset(vty->obuf);
1648 vty_close(vty);
1649 return 0;
1650 case BUFFER_EMPTY:
1651 if (vty->status == VTY_CLOSE)
1652 vty_close (vty);
1653 else
1654 {
1655 vty->status = VTY_NORMAL;
1656 if (vty->lines == 0)
1657 vty_event (VTY_READ, vty_sock, vty);
1658 }
1659 break;
1660 case BUFFER_PENDING:
1661 /* There is more data waiting to be written. */
1662 vty->status = VTY_MORE;
1663 if (vty->lines == 0)
1664 vty_event (VTY_WRITE, vty_sock, vty);
1665 break;
1666 }
1667
1668 return 0;
1669 }
1670
1671 /* allocate and initialise vty */
1672 static struct vty *
1673 vty_new_init (int vty_sock)
1674 {
1675 struct vty *vty;
1676
1677 vty = vty_new ();
1678 vty->fd = vty_sock;
1679 vty->wfd = vty_sock;
1680 vty->type = VTY_TERM;
1681 vty->node = AUTH_NODE;
1682 vty->fail = 0;
1683 vty->cp = 0;
1684 vty_clear_buf (vty);
1685 vty->length = 0;
1686 memset (vty->hist, 0, sizeof (vty->hist));
1687 vty->hp = 0;
1688 vty->hindex = 0;
1689 vector_set_index (vtyvec, vty_sock, vty);
1690 vty->status = VTY_NORMAL;
1691 vty->lines = -1;
1692 vty->iac = 0;
1693 vty->iac_sb_in_progress = 0;
1694 vty->sb_len = 0;
1695
1696 return vty;
1697 }
1698
1699 /* Create new vty structure. */
1700 static struct vty *
1701 vty_create (int vty_sock, union sockunion *su)
1702 {
1703 char buf[SU_ADDRSTRLEN];
1704 struct vty *vty;
1705
1706 sockunion2str(su, buf, SU_ADDRSTRLEN);
1707
1708 /* Allocate new vty structure and set up default values. */
1709 vty = vty_new_init (vty_sock);
1710
1711 /* configurable parameters not part of basic init */
1712 vty->v_timeout = vty_timeout_val;
1713 strcpy (vty->address, buf);
1714 if (no_password_check)
1715 {
1716 if (restricted_mode)
1717 vty->node = RESTRICTED_NODE;
1718 else if (host.advanced)
1719 vty->node = ENABLE_NODE;
1720 else
1721 vty->node = VIEW_NODE;
1722 }
1723 if (host.lines >= 0)
1724 vty->lines = host.lines;
1725
1726 if (! no_password_check)
1727 {
1728 /* Vty is not available if password isn't set. */
1729 if (host.password == NULL && host.password_encrypt == NULL)
1730 {
1731 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1732 vty->status = VTY_CLOSE;
1733 vty_close (vty);
1734 return NULL;
1735 }
1736 }
1737
1738 /* Say hello to the world. */
1739 vty_hello (vty);
1740 if (! no_password_check)
1741 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1742
1743 /* Setting up terminal. */
1744 vty_will_echo (vty);
1745 vty_will_suppress_go_ahead (vty);
1746
1747 vty_dont_linemode (vty);
1748 vty_do_window_size (vty);
1749 /* vty_dont_lflow_ahead (vty); */
1750
1751 vty_prompt (vty);
1752
1753 /* Add read/write thread. */
1754 vty_event (VTY_WRITE, vty_sock, vty);
1755 vty_event (VTY_READ, vty_sock, vty);
1756
1757 return vty;
1758 }
1759
1760 /* create vty for stdio */
1761 static struct termios stdio_orig_termios;
1762 static struct vty *stdio_vty = NULL;
1763 static void (*stdio_vty_atclose)(void);
1764
1765 static void
1766 vty_stdio_reset (void)
1767 {
1768 if (stdio_vty)
1769 {
1770 tcsetattr (0, TCSANOW, &stdio_orig_termios);
1771 stdio_vty = NULL;
1772
1773 if (stdio_vty_atclose)
1774 stdio_vty_atclose ();
1775 stdio_vty_atclose = NULL;
1776 }
1777 }
1778
1779 struct vty *
1780 vty_stdio (void (*atclose)())
1781 {
1782 struct vty *vty;
1783 struct termios termios;
1784
1785 /* refuse creating two vtys on stdio */
1786 if (stdio_vty)
1787 return NULL;
1788
1789 vty = stdio_vty = vty_new_init (0);
1790 stdio_vty_atclose = atclose;
1791 vty->wfd = 1;
1792
1793 /* always have stdio vty in a known _unchangeable_ state, don't want config
1794 * to have any effect here to make sure scripting this works as intended */
1795 vty->node = ENABLE_NODE;
1796 vty->v_timeout = 0;
1797 strcpy (vty->address, "console");
1798
1799 if (!tcgetattr (0, &stdio_orig_termios))
1800 {
1801 termios = stdio_orig_termios;
1802 termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
1803 | INLCR | IGNCR | ICRNL | IXON);
1804 termios.c_oflag &= ~OPOST;
1805 termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
1806 termios.c_cflag &= ~(CSIZE | PARENB);
1807 termios.c_cflag |= CS8;
1808 tcsetattr (0, TCSANOW, &termios);
1809 }
1810
1811 vty_prompt (vty);
1812
1813 /* Add read/write thread. */
1814 vty_event (VTY_WRITE, 1, vty);
1815 vty_event (VTY_READ, 0, vty);
1816
1817 return vty;
1818 }
1819
1820 /* Accept connection from the network. */
1821 static int
1822 vty_accept (struct thread *thread)
1823 {
1824 int vty_sock;
1825 union sockunion su;
1826 int ret;
1827 unsigned int on;
1828 int accept_sock;
1829 struct prefix p;
1830 struct access_list *acl = NULL;
1831 char buf[SU_ADDRSTRLEN];
1832
1833 accept_sock = THREAD_FD (thread);
1834
1835 /* We continue hearing vty socket. */
1836 vty_event (VTY_SERV, accept_sock, NULL);
1837
1838 memset (&su, 0, sizeof (union sockunion));
1839
1840 /* We can handle IPv4 or IPv6 socket. */
1841 vty_sock = sockunion_accept (accept_sock, &su);
1842 if (vty_sock < 0)
1843 {
1844 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
1845 return -1;
1846 }
1847 set_nonblocking(vty_sock);
1848
1849 sockunion2hostprefix (&su, &p);
1850
1851 /* VTY's accesslist apply. */
1852 if (p.family == AF_INET && vty_accesslist_name)
1853 {
1854 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1855 (access_list_apply (acl, &p) == FILTER_DENY))
1856 {
1857 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1858 sockunion2str (&su, buf, SU_ADDRSTRLEN));
1859 close (vty_sock);
1860
1861 /* continue accepting connections */
1862 vty_event (VTY_SERV, accept_sock, NULL);
1863
1864 return 0;
1865 }
1866 }
1867
1868 #ifdef HAVE_IPV6
1869 /* VTY's ipv6 accesslist apply. */
1870 if (p.family == AF_INET6 && vty_ipv6_accesslist_name)
1871 {
1872 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1873 (access_list_apply (acl, &p) == FILTER_DENY))
1874 {
1875 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1876 sockunion2str (&su, buf, SU_ADDRSTRLEN));
1877 close (vty_sock);
1878
1879 /* continue accepting connections */
1880 vty_event (VTY_SERV, accept_sock, NULL);
1881
1882 return 0;
1883 }
1884 }
1885 #endif /* HAVE_IPV6 */
1886
1887 on = 1;
1888 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1889 (char *) &on, sizeof (on));
1890 if (ret < 0)
1891 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
1892 safe_strerror (errno));
1893
1894 zlog (NULL, LOG_INFO, "Vty connection from %s",
1895 sockunion2str (&su, buf, SU_ADDRSTRLEN));
1896
1897 vty_create (vty_sock, &su);
1898
1899 return 0;
1900 }
1901
1902 #ifdef HAVE_IPV6
1903 static void
1904 vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1905 {
1906 int ret;
1907 struct addrinfo req;
1908 struct addrinfo *ainfo;
1909 struct addrinfo *ainfo_save;
1910 int sock;
1911 char port_str[BUFSIZ];
1912
1913 memset (&req, 0, sizeof (struct addrinfo));
1914 req.ai_flags = AI_PASSIVE;
1915 req.ai_family = AF_UNSPEC;
1916 req.ai_socktype = SOCK_STREAM;
1917 sprintf (port_str, "%d", port);
1918 port_str[sizeof (port_str) - 1] = '\0';
1919
1920 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1921
1922 if (ret != 0)
1923 {
1924 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1925 exit (1);
1926 }
1927
1928 ainfo_save = ainfo;
1929
1930 do
1931 {
1932 if (ainfo->ai_family != AF_INET
1933 #ifdef HAVE_IPV6
1934 && ainfo->ai_family != AF_INET6
1935 #endif /* HAVE_IPV6 */
1936 )
1937 continue;
1938
1939 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1940 if (sock < 0)
1941 continue;
1942
1943 sockopt_v6only (ainfo->ai_family, sock);
1944 sockopt_reuseaddr (sock);
1945 sockopt_reuseport (sock);
1946
1947 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1948 if (ret < 0)
1949 {
1950 close (sock); /* Avoid sd leak. */
1951 continue;
1952 }
1953
1954 ret = listen (sock, 3);
1955 if (ret < 0)
1956 {
1957 close (sock); /* Avoid sd leak. */
1958 continue;
1959 }
1960
1961 vty_event (VTY_SERV, sock, NULL);
1962 }
1963 while ((ainfo = ainfo->ai_next) != NULL);
1964
1965 freeaddrinfo (ainfo_save);
1966 }
1967 #else /* HAVE_IPV6 */
1968
1969 /* Make vty server socket. */
1970 static void
1971 vty_serv_sock_family (const char* addr, unsigned short port, int family)
1972 {
1973 int ret;
1974 union sockunion su;
1975 int accept_sock;
1976 void* naddr=NULL;
1977
1978 memset (&su, 0, sizeof (union sockunion));
1979 su.sa.sa_family = family;
1980 if(addr)
1981 switch(family)
1982 {
1983 case AF_INET:
1984 naddr=&su.sin.sin_addr;
1985 break;
1986 #ifdef HAVE_IPV6
1987 case AF_INET6:
1988 naddr=&su.sin6.sin6_addr;
1989 break;
1990 #endif
1991 }
1992
1993 if(naddr)
1994 switch(inet_pton(family,addr,naddr))
1995 {
1996 case -1:
1997 zlog_err("bad address %s",addr);
1998 naddr=NULL;
1999 break;
2000 case 0:
2001 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
2002 naddr=NULL;
2003 }
2004
2005 /* Make new socket. */
2006 accept_sock = sockunion_stream_socket (&su);
2007 if (accept_sock < 0)
2008 return;
2009
2010 /* This is server, so reuse address. */
2011 sockopt_reuseaddr (accept_sock);
2012 sockopt_reuseport (accept_sock);
2013
2014 /* Bind socket to universal address and given port. */
2015 ret = sockunion_bind (accept_sock, &su, port, naddr);
2016 if (ret < 0)
2017 {
2018 zlog_warn("can't bind socket");
2019 close (accept_sock); /* Avoid sd leak. */
2020 return;
2021 }
2022
2023 /* Listen socket under queue 3. */
2024 ret = listen (accept_sock, 3);
2025 if (ret < 0)
2026 {
2027 zlog (NULL, LOG_WARNING, "can't listen socket");
2028 close (accept_sock); /* Avoid sd leak. */
2029 return;
2030 }
2031
2032 /* Add vty server event. */
2033 vty_event (VTY_SERV, accept_sock, NULL);
2034 }
2035 #endif /* HAVE_IPV6 */
2036
2037 #ifdef VTYSH
2038 /* For sockaddr_un. */
2039 #include <sys/un.h>
2040
2041 /* VTY shell UNIX domain socket. */
2042 static void
2043 vty_serv_un (const char *path)
2044 {
2045 int ret;
2046 int sock, len;
2047 struct sockaddr_un serv;
2048 mode_t old_mask;
2049 struct zprivs_ids_t ids;
2050
2051 /* First of all, unlink existing socket */
2052 unlink (path);
2053
2054 /* Set umask */
2055 old_mask = umask (0007);
2056
2057 /* Make UNIX domain socket. */
2058 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2059 if (sock < 0)
2060 {
2061 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
2062 return;
2063 }
2064
2065 /* Make server socket. */
2066 memset (&serv, 0, sizeof (struct sockaddr_un));
2067 serv.sun_family = AF_UNIX;
2068 strncpy (serv.sun_path, path, strlen (path));
2069 #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
2070 len = serv.sun_len = SUN_LEN(&serv);
2071 #else
2072 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
2073 #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
2074
2075 ret = bind (sock, (struct sockaddr *) &serv, len);
2076 if (ret < 0)
2077 {
2078 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
2079 close (sock); /* Avoid sd leak. */
2080 return;
2081 }
2082
2083 ret = listen (sock, 5);
2084 if (ret < 0)
2085 {
2086 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
2087 close (sock); /* Avoid sd leak. */
2088 return;
2089 }
2090
2091 umask (old_mask);
2092
2093 zprivs_get_ids(&ids);
2094
2095 if (ids.gid_vty > 0)
2096 {
2097 /* set group of socket */
2098 if ( chown (path, -1, ids.gid_vty) )
2099 {
2100 zlog_err ("vty_serv_un: could chown socket, %s",
2101 safe_strerror (errno) );
2102 }
2103 }
2104
2105 vty_event (VTYSH_SERV, sock, NULL);
2106 }
2107
2108 /* #define VTYSH_DEBUG 1 */
2109
2110 static int
2111 vtysh_accept (struct thread *thread)
2112 {
2113 int accept_sock;
2114 int sock;
2115 int client_len;
2116 struct sockaddr_un client;
2117 struct vty *vty;
2118
2119 accept_sock = THREAD_FD (thread);
2120
2121 vty_event (VTYSH_SERV, accept_sock, NULL);
2122
2123 memset (&client, 0, sizeof (struct sockaddr_un));
2124 client_len = sizeof (struct sockaddr_un);
2125
2126 sock = accept (accept_sock, (struct sockaddr *) &client,
2127 (socklen_t *) &client_len);
2128
2129 if (sock < 0)
2130 {
2131 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
2132 return -1;
2133 }
2134
2135 if (set_nonblocking(sock) < 0)
2136 {
2137 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
2138 " %s, closing", sock, safe_strerror (errno));
2139 close (sock);
2140 return -1;
2141 }
2142
2143 #ifdef VTYSH_DEBUG
2144 printf ("VTY shell accept\n");
2145 #endif /* VTYSH_DEBUG */
2146
2147 vty = vty_new ();
2148 vty->fd = sock;
2149 vty->wfd = sock;
2150 vty->type = VTY_SHELL_SERV;
2151 vty->node = VIEW_NODE;
2152
2153 vty_event (VTYSH_READ, sock, vty);
2154
2155 return 0;
2156 }
2157
2158 static int
2159 vtysh_flush(struct vty *vty)
2160 {
2161 switch (buffer_flush_available(vty->obuf, vty->wfd))
2162 {
2163 case BUFFER_PENDING:
2164 vty_event(VTYSH_WRITE, vty->wfd, vty);
2165 break;
2166 case BUFFER_ERROR:
2167 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
2168 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
2169 buffer_reset(vty->obuf);
2170 vty_close(vty);
2171 return -1;
2172 break;
2173 case BUFFER_EMPTY:
2174 break;
2175 }
2176 return 0;
2177 }
2178
2179 static int
2180 vtysh_read (struct thread *thread)
2181 {
2182 int ret;
2183 int sock;
2184 int nbytes;
2185 struct vty *vty;
2186 unsigned char buf[VTY_READ_BUFSIZ];
2187 unsigned char *p;
2188 u_char header[4] = {0, 0, 0, 0};
2189
2190 sock = THREAD_FD (thread);
2191 vty = THREAD_ARG (thread);
2192 vty->t_read = NULL;
2193
2194 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
2195 {
2196 if (nbytes < 0)
2197 {
2198 if (ERRNO_IO_RETRY(errno))
2199 {
2200 vty_event (VTYSH_READ, sock, vty);
2201 return 0;
2202 }
2203 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
2204 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2205 __func__, sock, safe_strerror(errno));
2206 }
2207 buffer_reset(vty->obuf);
2208 vty_close (vty);
2209 #ifdef VTYSH_DEBUG
2210 printf ("close vtysh\n");
2211 #endif /* VTYSH_DEBUG */
2212 return 0;
2213 }
2214
2215 #ifdef VTYSH_DEBUG
2216 printf ("line: %.*s\n", nbytes, buf);
2217 #endif /* VTYSH_DEBUG */
2218
2219 for (p = buf; p < buf+nbytes; p++)
2220 {
2221 vty_ensure(vty, vty->length+1);
2222 vty->buf[vty->length++] = *p;
2223 if (*p == '\0')
2224 {
2225 /* Pass this line to parser. */
2226 ret = vty_execute (vty);
2227 /* Note that vty_execute clears the command buffer and resets
2228 vty->length to 0. */
2229
2230 /* Return result. */
2231 #ifdef VTYSH_DEBUG
2232 printf ("result: %d\n", ret);
2233 printf ("vtysh node: %d\n", vty->node);
2234 #endif /* VTYSH_DEBUG */
2235
2236 header[3] = ret;
2237 buffer_put(vty->obuf, header, 4);
2238
2239 if (!vty->t_write && (vtysh_flush(vty) < 0))
2240 /* Try to flush results; exit if a write error occurs. */
2241 return 0;
2242 }
2243 }
2244
2245 vty_event (VTYSH_READ, sock, vty);
2246
2247 return 0;
2248 }
2249
2250 static int
2251 vtysh_write (struct thread *thread)
2252 {
2253 struct vty *vty = THREAD_ARG (thread);
2254
2255 vty->t_write = NULL;
2256 vtysh_flush(vty);
2257 return 0;
2258 }
2259
2260 #endif /* VTYSH */
2261
2262 /* Determine address family to bind. */
2263 void
2264 vty_serv_sock (const char *addr, unsigned short port, const char *path)
2265 {
2266 /* If port is set to 0, do not listen on TCP/IP at all! */
2267 if (port)
2268 {
2269
2270 #ifdef HAVE_IPV6
2271 vty_serv_sock_addrinfo (addr, port);
2272 #else /* ! HAVE_IPV6 */
2273 vty_serv_sock_family (addr,port, AF_INET);
2274 #endif /* HAVE_IPV6 */
2275 }
2276
2277 #ifdef VTYSH
2278 vty_serv_un (path);
2279 #endif /* VTYSH */
2280 }
2281
2282 /* Close vty interface. Warning: call this only from functions that
2283 will be careful not to access the vty afterwards (since it has
2284 now been freed). This is safest from top-level functions (called
2285 directly by the thread dispatcher). */
2286 void
2287 vty_close (struct vty *vty)
2288 {
2289 int i;
2290
2291 /* Cancel threads.*/
2292 if (vty->t_read)
2293 thread_cancel (vty->t_read);
2294 if (vty->t_write)
2295 thread_cancel (vty->t_write);
2296 if (vty->t_timeout)
2297 thread_cancel (vty->t_timeout);
2298
2299 /* Flush buffer. */
2300 buffer_flush_all (vty->obuf, vty->wfd);
2301
2302 /* Free input buffer. */
2303 buffer_free (vty->obuf);
2304
2305 /* Free command history. */
2306 for (i = 0; i < VTY_MAXHIST; i++)
2307 if (vty->hist[i])
2308 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2309
2310 /* Unset vector. */
2311 vector_unset (vtyvec, vty->fd);
2312
2313 /* Close socket. */
2314 if (vty->fd > 0)
2315 close (vty->fd);
2316 else
2317 vty_stdio_reset ();
2318
2319 if (vty->buf)
2320 XFREE (MTYPE_VTY, vty->buf);
2321
2322 if (vty->error_buf)
2323 XFREE (MTYPE_VTY, vty->error_buf);
2324
2325 /* Check configure. */
2326 vty_config_unlock (vty);
2327
2328 /* OK free vty. */
2329 XFREE (MTYPE_VTY, vty);
2330 }
2331
2332 /* When time out occur output message then close connection. */
2333 static int
2334 vty_timeout (struct thread *thread)
2335 {
2336 struct vty *vty;
2337
2338 vty = THREAD_ARG (thread);
2339 vty->t_timeout = NULL;
2340 vty->v_timeout = 0;
2341
2342 /* Clear buffer*/
2343 buffer_reset (vty->obuf);
2344 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2345
2346 /* Close connection. */
2347 vty->status = VTY_CLOSE;
2348 vty_close (vty);
2349
2350 return 0;
2351 }
2352
2353 /* Read up configuration file from file_name. */
2354 static void
2355 vty_read_file (FILE *confp)
2356 {
2357 int ret;
2358 struct vty *vty;
2359 unsigned int line_num = 0;
2360
2361 vty = vty_new ();
2362 vty->wfd = dup(STDERR_FILENO); /* vty_close() will close this */
2363 if (vty->wfd < 0)
2364 {
2365 /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */
2366 vty->wfd = STDOUT_FILENO;
2367 }
2368 vty->fd = STDIN_FILENO;
2369 vty->type = VTY_FILE;
2370 vty->node = CONFIG_NODE;
2371
2372 /* Execute configuration file */
2373 ret = config_from_file (vty, confp, &line_num);
2374
2375 /* Flush any previous errors before printing messages below */
2376 buffer_flush_all (vty->obuf, vty->fd);
2377
2378 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
2379 {
2380 switch (ret)
2381 {
2382 case CMD_ERR_AMBIGUOUS:
2383 fprintf (stderr, "*** Error reading config: Ambiguous command.\n");
2384 break;
2385 case CMD_ERR_NO_MATCH:
2386 fprintf (stderr, "*** Error reading config: There is no such command.\n");
2387 break;
2388 }
2389 fprintf (stderr, "*** Error occured processing line %u, below:\n%s\n",
2390 line_num, vty->error_buf);
2391 }
2392
2393 vty_close (vty);
2394 }
2395
2396 static FILE *
2397 vty_use_backup_config (char *fullpath)
2398 {
2399 char *fullpath_sav, *fullpath_tmp;
2400 FILE *ret = NULL;
2401 struct stat buf;
2402 int tmp, sav;
2403 int c;
2404 char buffer[512];
2405
2406 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2407 strcpy (fullpath_sav, fullpath);
2408 strcat (fullpath_sav, CONF_BACKUP_EXT);
2409 if (stat (fullpath_sav, &buf) == -1)
2410 {
2411 free (fullpath_sav);
2412 return NULL;
2413 }
2414
2415 fullpath_tmp = malloc (strlen (fullpath) + 8);
2416 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2417
2418 /* Open file to configuration write. */
2419 tmp = mkstemp (fullpath_tmp);
2420 if (tmp < 0)
2421 {
2422 free (fullpath_sav);
2423 free (fullpath_tmp);
2424 return NULL;
2425 }
2426
2427 sav = open (fullpath_sav, O_RDONLY);
2428 if (sav < 0)
2429 {
2430 unlink (fullpath_tmp);
2431 free (fullpath_sav);
2432 free (fullpath_tmp);
2433 return NULL;
2434 }
2435
2436 while((c = read (sav, buffer, 512)) > 0)
2437 {
2438 if (write (tmp, buffer, c) <= 0)
2439 {
2440 free (fullpath_sav);
2441 free (fullpath_tmp);
2442 close (sav);
2443 close (tmp);
2444 return NULL;
2445 }
2446 }
2447 close (sav);
2448 close (tmp);
2449
2450 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2451 {
2452 unlink (fullpath_tmp);
2453 free (fullpath_sav);
2454 free (fullpath_tmp);
2455 return NULL;
2456 }
2457
2458 if (link (fullpath_tmp, fullpath) == 0)
2459 ret = fopen (fullpath, "r");
2460
2461 unlink (fullpath_tmp);
2462
2463 free (fullpath_sav);
2464 free (fullpath_tmp);
2465 return ret;
2466 }
2467
2468 /* Read up configuration file from file_name. */
2469 void
2470 vty_read_config (char *config_file,
2471 char *config_default_dir)
2472 {
2473 char cwd[MAXPATHLEN];
2474 FILE *confp = NULL;
2475 char *fullpath;
2476 char *tmp = NULL;
2477
2478 /* If -f flag specified. */
2479 if (config_file != NULL)
2480 {
2481 if (! IS_DIRECTORY_SEP (config_file[0]))
2482 {
2483 if (getcwd (cwd, MAXPATHLEN) == NULL)
2484 {
2485 fprintf (stderr, "Failure to determine Current Working Directory %d!\n", errno);
2486 exit (1);
2487 }
2488 tmp = XMALLOC (MTYPE_TMP,
2489 strlen (cwd) + strlen (config_file) + 2);
2490 sprintf (tmp, "%s/%s", cwd, config_file);
2491 fullpath = tmp;
2492 }
2493 else
2494 fullpath = config_file;
2495
2496 confp = fopen (fullpath, "r");
2497
2498 if (confp == NULL)
2499 {
2500 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2501 __func__, fullpath, safe_strerror (errno));
2502
2503 confp = vty_use_backup_config (fullpath);
2504 if (confp)
2505 fprintf (stderr, "WARNING: using backup configuration file!\n");
2506 else
2507 {
2508 fprintf (stderr, "can't open configuration file [%s]\n",
2509 config_file);
2510 exit(1);
2511 }
2512 }
2513 }
2514 else
2515 {
2516
2517 host_config_set (config_default_dir);
2518
2519 #ifdef VTYSH
2520 int ret;
2521 struct stat conf_stat;
2522
2523 /* !!!!PLEASE LEAVE!!!!
2524 * This is NEEDED for use with vtysh -b, or else you can get
2525 * a real configuration food fight with a lot garbage in the
2526 * merged configuration file it creates coming from the per
2527 * daemon configuration files. This also allows the daemons
2528 * to start if there default configuration file is not
2529 * present or ignore them, as needed when using vtysh -b to
2530 * configure the daemons at boot - MAG
2531 */
2532
2533 /* Stat for vtysh Zebra.conf, if found startup and wait for
2534 * boot configuration
2535 */
2536
2537 if ( strstr(config_default_dir, "vtysh") == NULL)
2538 {
2539 ret = stat (integrate_default, &conf_stat);
2540 if (ret >= 0)
2541 goto tmp_free_and_out;
2542 }
2543 #endif /* VTYSH */
2544 confp = fopen (config_default_dir, "r");
2545 if (confp == NULL)
2546 {
2547 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2548 __func__, config_default_dir, safe_strerror (errno));
2549
2550 confp = vty_use_backup_config (config_default_dir);
2551 if (confp)
2552 {
2553 fprintf (stderr, "WARNING: using backup configuration file!\n");
2554 fullpath = config_default_dir;
2555 }
2556 else
2557 {
2558 fprintf (stderr, "can't open configuration file [%s]\n",
2559 config_default_dir);
2560 goto tmp_free_and_out;
2561 }
2562 }
2563 else
2564 fullpath = config_default_dir;
2565 }
2566
2567 vty_read_file (confp);
2568
2569 fclose (confp);
2570
2571 host_config_set (fullpath);
2572
2573 tmp_free_and_out:
2574 if (tmp)
2575 XFREE (MTYPE_TMP, fullpath);
2576 }
2577
2578 /* Small utility function which output log to the VTY. */
2579 void
2580 vty_log (const char *level, const char *proto_str,
2581 const char *format, struct timestamp_control *ctl, va_list va)
2582 {
2583 unsigned int i;
2584 struct vty *vty;
2585
2586 if (!vtyvec)
2587 return;
2588
2589 for (i = 0; i < vector_active (vtyvec); i++)
2590 if ((vty = vector_slot (vtyvec, i)) != NULL)
2591 if (vty->monitor)
2592 {
2593 va_list ac;
2594 va_copy(ac, va);
2595 vty_log_out (vty, level, proto_str, format, ctl, ac);
2596 va_end(ac);
2597 }
2598 }
2599
2600 /* Async-signal-safe version of vty_log for fixed strings. */
2601 void
2602 vty_log_fixed (char *buf, size_t len)
2603 {
2604 unsigned int i;
2605 struct iovec iov[2];
2606 char crlf[4] = "\r\n";
2607
2608 /* vty may not have been initialised */
2609 if (!vtyvec)
2610 return;
2611
2612 iov[0].iov_base = buf;
2613 iov[0].iov_len = len;
2614 iov[1].iov_base = crlf;
2615 iov[1].iov_len = 2;
2616
2617 for (i = 0; i < vector_active (vtyvec); i++)
2618 {
2619 struct vty *vty;
2620 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2621 /* N.B. We don't care about the return code, since process is
2622 most likely just about to die anyway. */
2623 if (writev(vty->wfd, iov, 2) == -1)
2624 {
2625 fprintf(stderr, "Failure to writev: %d\n", errno);
2626 exit(-1);
2627 }
2628 }
2629 }
2630
2631 int
2632 vty_config_lock (struct vty *vty)
2633 {
2634 if (vty_config == 0)
2635 {
2636 vty->config = 1;
2637 vty_config = 1;
2638 }
2639 return vty->config;
2640 }
2641
2642 int
2643 vty_config_unlock (struct vty *vty)
2644 {
2645 if (vty_config == 1 && vty->config == 1)
2646 {
2647 vty->config = 0;
2648 vty_config = 0;
2649 }
2650 return vty->config;
2651 }
2652
2653 /* Master of the threads. */
2654 static struct thread_master *vty_master;
2655
2656 static void
2657 vty_event (enum event event, int sock, struct vty *vty)
2658 {
2659 struct thread *vty_serv_thread;
2660
2661 switch (event)
2662 {
2663 case VTY_SERV:
2664 vty_serv_thread = thread_add_read (vty_master, vty_accept, vty, sock);
2665 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2666 break;
2667 #ifdef VTYSH
2668 case VTYSH_SERV:
2669 vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock);
2670 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2671 break;
2672 case VTYSH_READ:
2673 vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock);
2674 break;
2675 case VTYSH_WRITE:
2676 vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock);
2677 break;
2678 #endif /* VTYSH */
2679 case VTY_READ:
2680 vty->t_read = thread_add_read (vty_master, vty_read, vty, sock);
2681
2682 /* Time out treatment. */
2683 if (vty->v_timeout)
2684 {
2685 if (vty->t_timeout)
2686 thread_cancel (vty->t_timeout);
2687 vty->t_timeout =
2688 thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
2689 }
2690 break;
2691 case VTY_WRITE:
2692 if (! vty->t_write)
2693 vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock);
2694 break;
2695 case VTY_TIMEOUT_RESET:
2696 if (vty->t_timeout)
2697 {
2698 thread_cancel (vty->t_timeout);
2699 vty->t_timeout = NULL;
2700 }
2701 if (vty->v_timeout)
2702 {
2703 vty->t_timeout =
2704 thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
2705 }
2706 break;
2707 }
2708 }
2709
2710 DEFUN (config_who,
2711 config_who_cmd,
2712 "who",
2713 "Display who is on vty\n")
2714 {
2715 unsigned int i;
2716 struct vty *v;
2717
2718 for (i = 0; i < vector_active (vtyvec); i++)
2719 if ((v = vector_slot (vtyvec, i)) != NULL)
2720 vty_out (vty, "%svty[%d] connected from %s.%s",
2721 v->config ? "*" : " ",
2722 i, v->address, VTY_NEWLINE);
2723 return CMD_SUCCESS;
2724 }
2725
2726 /* Move to vty configuration mode. */
2727 DEFUN (line_vty,
2728 line_vty_cmd,
2729 "line vty",
2730 "Configure a terminal line\n"
2731 "Virtual terminal\n")
2732 {
2733 vty->node = VTY_NODE;
2734 return CMD_SUCCESS;
2735 }
2736
2737 /* Set time out value. */
2738 static int
2739 exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
2740 {
2741 unsigned long timeout = 0;
2742
2743 /* min_str and sec_str are already checked by parser. So it must be
2744 all digit string. */
2745 if (min_str)
2746 {
2747 timeout = strtol (min_str, NULL, 10);
2748 timeout *= 60;
2749 }
2750 if (sec_str)
2751 timeout += strtol (sec_str, NULL, 10);
2752
2753 vty_timeout_val = timeout;
2754 vty->v_timeout = timeout;
2755 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2756
2757
2758 return CMD_SUCCESS;
2759 }
2760
2761 DEFUN (exec_timeout_min,
2762 exec_timeout_min_cmd,
2763 "exec-timeout <0-35791>",
2764 "Set timeout value\n"
2765 "Timeout value in minutes\n")
2766 {
2767 return exec_timeout (vty, argv[0], NULL);
2768 }
2769
2770 DEFUN (exec_timeout_sec,
2771 exec_timeout_sec_cmd,
2772 "exec-timeout <0-35791> <0-2147483>",
2773 "Set the EXEC timeout\n"
2774 "Timeout in minutes\n"
2775 "Timeout in seconds\n")
2776 {
2777 return exec_timeout (vty, argv[0], argv[1]);
2778 }
2779
2780 DEFUN (no_exec_timeout,
2781 no_exec_timeout_cmd,
2782 "no exec-timeout",
2783 NO_STR
2784 "Set the EXEC timeout\n")
2785 {
2786 return exec_timeout (vty, NULL, NULL);
2787 }
2788
2789 /* Set vty access class. */
2790 DEFUN (vty_access_class,
2791 vty_access_class_cmd,
2792 "access-class WORD",
2793 "Filter connections based on an IP access list\n"
2794 "IP access list\n")
2795 {
2796 if (vty_accesslist_name)
2797 XFREE(MTYPE_VTY, vty_accesslist_name);
2798
2799 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2800
2801 return CMD_SUCCESS;
2802 }
2803
2804 /* Clear vty access class. */
2805 DEFUN (no_vty_access_class,
2806 no_vty_access_class_cmd,
2807 "no access-class [WORD]",
2808 NO_STR
2809 "Filter connections based on an IP access list\n"
2810 "IP access list\n")
2811 {
2812 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2813 {
2814 vty_out (vty, "Access-class is not currently applied to vty%s",
2815 VTY_NEWLINE);
2816 return CMD_WARNING;
2817 }
2818
2819 XFREE(MTYPE_VTY, vty_accesslist_name);
2820
2821 vty_accesslist_name = NULL;
2822
2823 return CMD_SUCCESS;
2824 }
2825
2826 #ifdef HAVE_IPV6
2827 /* Set vty access class. */
2828 DEFUN (vty_ipv6_access_class,
2829 vty_ipv6_access_class_cmd,
2830 "ipv6 access-class WORD",
2831 IPV6_STR
2832 "Filter connections based on an IP access list\n"
2833 "IPv6 access list\n")
2834 {
2835 if (vty_ipv6_accesslist_name)
2836 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2837
2838 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2839
2840 return CMD_SUCCESS;
2841 }
2842
2843 /* Clear vty access class. */
2844 DEFUN (no_vty_ipv6_access_class,
2845 no_vty_ipv6_access_class_cmd,
2846 "no ipv6 access-class [WORD]",
2847 NO_STR
2848 IPV6_STR
2849 "Filter connections based on an IP access list\n"
2850 "IPv6 access list\n")
2851 {
2852 if (! vty_ipv6_accesslist_name ||
2853 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2854 {
2855 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2856 VTY_NEWLINE);
2857 return CMD_WARNING;
2858 }
2859
2860 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2861
2862 vty_ipv6_accesslist_name = NULL;
2863
2864 return CMD_SUCCESS;
2865 }
2866 #endif /* HAVE_IPV6 */
2867
2868 /* vty login. */
2869 DEFUN (vty_login,
2870 vty_login_cmd,
2871 "login",
2872 "Enable password checking\n")
2873 {
2874 no_password_check = 0;
2875 return CMD_SUCCESS;
2876 }
2877
2878 DEFUN (no_vty_login,
2879 no_vty_login_cmd,
2880 "no login",
2881 NO_STR
2882 "Enable password checking\n")
2883 {
2884 no_password_check = 1;
2885 return CMD_SUCCESS;
2886 }
2887
2888 /* initial mode. */
2889 DEFUN (vty_restricted_mode,
2890 vty_restricted_mode_cmd,
2891 "anonymous restricted",
2892 "Restrict view commands available in anonymous, unauthenticated vty\n")
2893 {
2894 restricted_mode = 1;
2895 return CMD_SUCCESS;
2896 }
2897
2898 DEFUN (vty_no_restricted_mode,
2899 vty_no_restricted_mode_cmd,
2900 "no anonymous restricted",
2901 NO_STR
2902 "Enable password checking\n")
2903 {
2904 restricted_mode = 0;
2905 return CMD_SUCCESS;
2906 }
2907
2908 DEFUN (service_advanced_vty,
2909 service_advanced_vty_cmd,
2910 "service advanced-vty",
2911 "Set up miscellaneous service\n"
2912 "Enable advanced mode vty interface\n")
2913 {
2914 host.advanced = 1;
2915 return CMD_SUCCESS;
2916 }
2917
2918 DEFUN (no_service_advanced_vty,
2919 no_service_advanced_vty_cmd,
2920 "no service advanced-vty",
2921 NO_STR
2922 "Set up miscellaneous service\n"
2923 "Enable advanced mode vty interface\n")
2924 {
2925 host.advanced = 0;
2926 return CMD_SUCCESS;
2927 }
2928
2929 DEFUN (terminal_monitor,
2930 terminal_monitor_cmd,
2931 "terminal monitor",
2932 "Set terminal line parameters\n"
2933 "Copy debug output to the current terminal line\n")
2934 {
2935 vty->monitor = 1;
2936 return CMD_SUCCESS;
2937 }
2938
2939 DEFUN (terminal_no_monitor,
2940 terminal_no_monitor_cmd,
2941 "terminal no monitor",
2942 "Set terminal line parameters\n"
2943 NO_STR
2944 "Copy debug output to the current terminal line\n")
2945 {
2946 vty->monitor = 0;
2947 return CMD_SUCCESS;
2948 }
2949
2950 ALIAS (terminal_no_monitor,
2951 no_terminal_monitor_cmd,
2952 "no terminal monitor",
2953 NO_STR
2954 "Set terminal line parameters\n"
2955 "Copy debug output to the current terminal line\n")
2956
2957 DEFUN (show_history,
2958 show_history_cmd,
2959 "show history",
2960 SHOW_STR
2961 "Display the session command history\n")
2962 {
2963 int index;
2964
2965 for (index = vty->hindex + 1; index != vty->hindex;)
2966 {
2967 if (index == VTY_MAXHIST)
2968 {
2969 index = 0;
2970 continue;
2971 }
2972
2973 if (vty->hist[index] != NULL)
2974 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2975
2976 index++;
2977 }
2978
2979 return CMD_SUCCESS;
2980 }
2981
2982 /* vty login. */
2983 DEFUN (log_commands,
2984 log_commands_cmd,
2985 "log commands",
2986 "Logging control\n"
2987 "Log all commands (can't be unset without restart)\n")
2988 {
2989 do_log_commands = 1;
2990 return CMD_SUCCESS;
2991 }
2992
2993 /* Display current configuration. */
2994 static int
2995 vty_config_write (struct vty *vty)
2996 {
2997 vty_out (vty, "line vty%s", VTY_NEWLINE);
2998
2999 if (vty_accesslist_name)
3000 vty_out (vty, " access-class %s%s",
3001 vty_accesslist_name, VTY_NEWLINE);
3002
3003 if (vty_ipv6_accesslist_name)
3004 vty_out (vty, " ipv6 access-class %s%s",
3005 vty_ipv6_accesslist_name, VTY_NEWLINE);
3006
3007 /* exec-timeout */
3008 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
3009 vty_out (vty, " exec-timeout %ld %ld%s",
3010 vty_timeout_val / 60,
3011 vty_timeout_val % 60, VTY_NEWLINE);
3012
3013 /* login */
3014 if (no_password_check)
3015 vty_out (vty, " no login%s", VTY_NEWLINE);
3016
3017 if (restricted_mode != restricted_mode_default)
3018 {
3019 if (restricted_mode_default)
3020 vty_out (vty, " no anonymous restricted%s", VTY_NEWLINE);
3021 else
3022 vty_out (vty, " anonymous restricted%s", VTY_NEWLINE);
3023 }
3024
3025 if (do_log_commands)
3026 vty_out (vty, "log commands%s", VTY_NEWLINE);
3027
3028 vty_out (vty, "!%s", VTY_NEWLINE);
3029
3030 return CMD_SUCCESS;
3031 }
3032
3033 struct cmd_node vty_node =
3034 {
3035 VTY_NODE,
3036 "%s(config-line)# ",
3037 1,
3038 };
3039
3040 /* Reset all VTY status. */
3041 void
3042 vty_reset ()
3043 {
3044 unsigned int i;
3045 struct vty *vty;
3046 struct thread *vty_serv_thread;
3047
3048 for (i = 0; i < vector_active (vtyvec); i++)
3049 if ((vty = vector_slot (vtyvec, i)) != NULL)
3050 {
3051 buffer_reset (vty->obuf);
3052 vty->status = VTY_CLOSE;
3053 vty_close (vty);
3054 }
3055
3056 for (i = 0; i < vector_active (Vvty_serv_thread); i++)
3057 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
3058 {
3059 thread_cancel (vty_serv_thread);
3060 vector_slot (Vvty_serv_thread, i) = NULL;
3061 close (i);
3062 }
3063
3064 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
3065
3066 if (vty_accesslist_name)
3067 {
3068 XFREE(MTYPE_VTY, vty_accesslist_name);
3069 vty_accesslist_name = NULL;
3070 }
3071
3072 if (vty_ipv6_accesslist_name)
3073 {
3074 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
3075 vty_ipv6_accesslist_name = NULL;
3076 }
3077 }
3078
3079 static void
3080 vty_save_cwd (void)
3081 {
3082 char cwd[MAXPATHLEN];
3083 char *c;
3084
3085 c = getcwd (cwd, MAXPATHLEN);
3086
3087 if (!c)
3088 {
3089 /*
3090 * At this point if these go wrong, more than likely
3091 * the whole world is coming down around us
3092 * Hence not worrying about it too much.
3093 */
3094 if (!chdir (SYSCONFDIR))
3095 {
3096 fprintf(stderr, "Failure to chdir to %s, errno: %d\n", SYSCONFDIR, errno);
3097 exit(-1);
3098 }
3099 if (getcwd (cwd, MAXPATHLEN) == NULL)
3100 {
3101 fprintf(stderr, "Failure to getcwd, errno: %d\n", errno);
3102 exit(-1);
3103 }
3104 }
3105
3106 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
3107 strcpy (vty_cwd, cwd);
3108 }
3109
3110 char *
3111 vty_get_cwd ()
3112 {
3113 return vty_cwd;
3114 }
3115
3116 int
3117 vty_shell (struct vty *vty)
3118 {
3119 return vty->type == VTY_SHELL ? 1 : 0;
3120 }
3121
3122 int
3123 vty_shell_serv (struct vty *vty)
3124 {
3125 return vty->type == VTY_SHELL_SERV ? 1 : 0;
3126 }
3127
3128 void
3129 vty_init_vtysh ()
3130 {
3131 vtyvec = vector_init (VECTOR_MIN_SIZE);
3132 }
3133
3134 /* Install vty's own commands like `who' command. */
3135 void
3136 vty_init (struct thread_master *master_thread)
3137 {
3138 /* For further configuration read, preserve current directory. */
3139 vty_save_cwd ();
3140
3141 vtyvec = vector_init (VECTOR_MIN_SIZE);
3142
3143 vty_master = master_thread;
3144
3145 atexit (vty_stdio_reset);
3146
3147 /* Initilize server thread vector. */
3148 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
3149
3150 /* Install bgp top node. */
3151 install_node (&vty_node, vty_config_write);
3152
3153 install_element (RESTRICTED_NODE, &config_who_cmd);
3154 install_element (RESTRICTED_NODE, &show_history_cmd);
3155 install_element (VIEW_NODE, &config_who_cmd);
3156 install_element (VIEW_NODE, &show_history_cmd);
3157 install_element (ENABLE_NODE, &config_who_cmd);
3158 install_element (CONFIG_NODE, &line_vty_cmd);
3159 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
3160 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
3161 install_element (CONFIG_NODE, &show_history_cmd);
3162 install_element (CONFIG_NODE, &log_commands_cmd);
3163 install_element (ENABLE_NODE, &terminal_monitor_cmd);
3164 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
3165 install_element (ENABLE_NODE, &no_terminal_monitor_cmd);
3166 install_element (ENABLE_NODE, &show_history_cmd);
3167
3168 install_default (VTY_NODE);
3169 install_element (VTY_NODE, &exec_timeout_min_cmd);
3170 install_element (VTY_NODE, &exec_timeout_sec_cmd);
3171 install_element (VTY_NODE, &no_exec_timeout_cmd);
3172 install_element (VTY_NODE, &vty_access_class_cmd);
3173 install_element (VTY_NODE, &no_vty_access_class_cmd);
3174 install_element (VTY_NODE, &vty_login_cmd);
3175 install_element (VTY_NODE, &no_vty_login_cmd);
3176 install_element (VTY_NODE, &vty_restricted_mode_cmd);
3177 install_element (VTY_NODE, &vty_no_restricted_mode_cmd);
3178 #ifdef HAVE_IPV6
3179 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
3180 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
3181 #endif /* HAVE_IPV6 */
3182 }
3183
3184 void
3185 vty_terminate (void)
3186 {
3187 if (vty_cwd)
3188 XFREE (MTYPE_TMP, vty_cwd);
3189
3190 if (vtyvec && Vvty_serv_thread)
3191 {
3192 vty_reset ();
3193 vector_free (vtyvec);
3194 vector_free (Vvty_serv_thread);
3195 }
3196 }
3197
3198 /* Utility functions to get arguments from commands generated
3199 by the xml2cli.pl script. */
3200 const char *
3201 vty_get_arg_value (struct vty_arg *args[], const char *arg)
3202 {
3203 while (*args)
3204 {
3205 if (strcmp ((*args)->name, arg) == 0)
3206 return (*args)->value;
3207 args++;
3208 }
3209 return NULL;
3210 }
3211
3212 struct vty_arg *
3213 vty_get_arg (struct vty_arg *args[], const char *arg)
3214 {
3215 while (*args)
3216 {
3217 if (strcmp ((*args)->name, arg) == 0)
3218 return *args;
3219 args++;
3220 }
3221 return NULL;
3222 }