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