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