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