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