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