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