blob: 6d647977438b73c19fdd4161b3b41ffac1e07c02 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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"
paulb21b19c2003-06-15 01:28:29 +000026#include "thread.h"
paul718e3742002-12-13 20:15:29 +000027#include "buffer.h"
gdt5e4fa162004-03-16 14:38:36 +000028#include <lib/version.h>
paul718e3742002-12-13 20:15:29 +000029#include "command.h"
30#include "sockunion.h"
paul718e3742002-12-13 20:15:29 +000031#include "memory.h"
32#include "str.h"
33#include "log.h"
34#include "prefix.h"
35#include "filter.h"
paulb21b19c2003-06-15 01:28:29 +000036#include "vty.h"
pauledd7c242003-06-04 13:59:38 +000037#include "privs.h"
ajs9fc7ebf2005-02-23 15:12:34 +000038#include "network.h"
39
40#include <arpa/telnet.h>
David Lamparterba53a8f2015-05-05 11:04:46 +020041#include <termios.h>
paul718e3742002-12-13 20:15:29 +000042
Quentin Youngb7ceefe2017-01-10 23:33:50 +000043#define VTY_BUFSIZ 4096
44
paul718e3742002-12-13 20:15:29 +000045/* Vty events */
46enum event
47{
48 VTY_SERV,
49 VTY_READ,
50 VTY_WRITE,
51 VTY_TIMEOUT_RESET,
52#ifdef VTYSH
53 VTYSH_SERV,
ajs49ff6d92004-11-04 19:26:16 +000054 VTYSH_READ,
55 VTYSH_WRITE
paul718e3742002-12-13 20:15:29 +000056#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;
David Lamparter6b0655a2014-06-04 06:53:35 +020063
paul718e3742002-12-13 20:15:29 +000064/* 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. */
Christian Franke677bcbb2013-02-27 13:47:23 +000077static vector Vvty_serv_thread;
paul718e3742002-12-13 20:15:29 +000078
79/* Current directory. */
80char *vty_cwd = NULL;
81
82/* Configure lock. */
83static int vty_config;
84
85/* Login password check. */
86static int no_password_check = 0;
87
Paul Jakma62687ff2008-08-23 14:27:06 +010088/* Restrict unauthenticated logins? */
89static const u_char restricted_mode_default = 0;
90static u_char restricted_mode = 0;
91
paul718e3742002-12-13 20:15:29 +000092/* Integrated configuration file path */
93char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
94
Lou Berger86b2a0a2016-05-17 12:19:51 -040095static int do_log_commands = 0;
David Lamparter6b0655a2014-06-04 06:53:35 +020096
paul718e3742002-12-13 20:15:29 +000097/* VTY standard output function. */
98int
99vty_out (struct vty *vty, const char *format, ...)
100{
101 va_list args;
102 int len = 0;
103 int size = 1024;
104 char buf[1024];
105 char *p = NULL;
paul718e3742002-12-13 20:15:29 +0000106
107 if (vty_shell (vty))
ajsd246bd92004-11-23 17:35:08 +0000108 {
109 va_start (args, format);
110 vprintf (format, args);
111 va_end (args);
112 }
paul718e3742002-12-13 20:15:29 +0000113 else
114 {
115 /* Try to write to initial buffer. */
ajsd246bd92004-11-23 17:35:08 +0000116 va_start (args, format);
Lou Bergerc7f7e492016-01-12 13:41:49 -0500117 len = vsnprintf (buf, sizeof(buf), format, args);
ajsd246bd92004-11-23 17:35:08 +0000118 va_end (args);
paul718e3742002-12-13 20:15:29 +0000119
120 /* Initial buffer is not enough. */
121 if (len < 0 || len >= size)
122 {
123 while (1)
124 {
125 if (len > -1)
126 size = len + 1;
127 else
128 size = size * 2;
129
130 p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
131 if (! p)
132 return -1;
133
ajsd246bd92004-11-23 17:35:08 +0000134 va_start (args, format);
paul718e3742002-12-13 20:15:29 +0000135 len = vsnprintf (p, size, format, args);
ajsd246bd92004-11-23 17:35:08 +0000136 va_end (args);
paul718e3742002-12-13 20:15:29 +0000137
138 if (len > -1 && len < size)
139 break;
140 }
141 }
142
143 /* When initial buffer is enough to store all output. */
144 if (! p)
145 p = buf;
146
147 /* Pointer p must point out buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +0000148 buffer_put (vty->obuf, (u_char *) p, len);
paul718e3742002-12-13 20:15:29 +0000149
150 /* If p is not different with buf, it is allocated buffer. */
151 if (p != buf)
152 XFREE (MTYPE_VTY_OUT_BUF, p);
153 }
154
paul718e3742002-12-13 20:15:29 +0000155 return len;
156}
157
ajsd246bd92004-11-23 17:35:08 +0000158static int
ajs274a4a42004-12-07 15:39:31 +0000159vty_log_out (struct vty *vty, const char *level, const char *proto_str,
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000160 const char *format, struct timestamp_control *ctl, va_list va)
paul718e3742002-12-13 20:15:29 +0000161{
ajs9fc7ebf2005-02-23 15:12:34 +0000162 int ret;
paul718e3742002-12-13 20:15:29 +0000163 int len;
164 char buf[1024];
Andrew J. Schorr08942da2006-07-03 20:58:29 +0000165
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000166 if (!ctl->already_rendered)
167 {
168 ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
169 ctl->already_rendered = 1;
170 }
171 if (ctl->len+1 >= sizeof(buf))
172 return -1;
173 memcpy(buf, ctl->buf, len = ctl->len);
174 buf[len++] = ' ';
175 buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000176
ajs274a4a42004-12-07 15:39:31 +0000177 if (level)
Andrew J. Schorr08942da2006-07-03 20:58:29 +0000178 ret = snprintf(buf+len, sizeof(buf)-len, "%s: %s: ", level, proto_str);
ajs274a4a42004-12-07 15:39:31 +0000179 else
Andrew J. Schorr08942da2006-07-03 20:58:29 +0000180 ret = snprintf(buf+len, sizeof(buf)-len, "%s: ", proto_str);
181 if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf)))
paul718e3742002-12-13 20:15:29 +0000182 return -1;
paul718e3742002-12-13 20:15:29 +0000183
ajs9fc7ebf2005-02-23 15:12:34 +0000184 if (((ret = vsnprintf(buf+len, sizeof(buf)-len, format, va)) < 0) ||
185 ((size_t)((len += ret)+2) > sizeof(buf)))
186 return -1;
paul718e3742002-12-13 20:15:29 +0000187
ajs9fc7ebf2005-02-23 15:12:34 +0000188 buf[len++] = '\r';
189 buf[len++] = '\n';
190
David Lamparter4715a532013-05-30 16:31:49 +0200191 if (write(vty->wfd, buf, len) < 0)
ajs9fc7ebf2005-02-23 15:12:34 +0000192 {
193 if (ERRNO_IO_RETRY(errno))
194 /* Kernel buffer is full, probably too much debugging output, so just
195 drop the data and ignore. */
196 return -1;
197 /* Fatal I/O error. */
Andrew J. Schorr74542d72006-07-10 18:09:42 +0000198 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +0000199 zlog_warn("%s: write failed to vty client fd %d, closing: %s",
200 __func__, vty->fd, safe_strerror(errno));
201 buffer_reset(vty->obuf);
Andrew J. Schorr9d0a3262006-07-11 00:06:49 +0000202 /* cannot call vty_close, because a parent routine may still try
203 to access the vty struct */
204 vty->status = VTY_CLOSE;
205 shutdown(vty->fd, SHUT_RDWR);
ajs9fc7ebf2005-02-23 15:12:34 +0000206 return -1;
207 }
208 return 0;
paul718e3742002-12-13 20:15:29 +0000209}
210
211/* Output current time to the vty. */
212void
213vty_time_print (struct vty *vty, int cr)
214{
Christian Franke880e31c2016-05-03 19:59:40 +0200215 char buf[QUAGGA_TIMESTAMP_LEN];
paul718e3742002-12-13 20:15:29 +0000216
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000217 if (quagga_timestamp(0, buf, sizeof(buf)) == 0)
paul718e3742002-12-13 20:15:29 +0000218 {
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000219 zlog (NULL, LOG_INFO, "quagga_timestamp error");
paul718e3742002-12-13 20:15:29 +0000220 return;
221 }
222 if (cr)
223 vty_out (vty, "%s\n", buf);
224 else
225 vty_out (vty, "%s ", buf);
226
227 return;
228}
229
230/* Say hello to vty interface. */
231void
232vty_hello (struct vty *vty)
233{
paul3b0c5d92005-03-08 10:43:43 +0000234 if (host.motdfile)
235 {
236 FILE *f;
237 char buf[4096];
paul22085182005-03-08 16:00:12 +0000238
paul3b0c5d92005-03-08 10:43:43 +0000239 f = fopen (host.motdfile, "r");
240 if (f)
241 {
paulb45da6f2005-03-08 15:16:57 +0000242 while (fgets (buf, sizeof (buf), f))
paul3b0c5d92005-03-08 10:43:43 +0000243 {
paulb45da6f2005-03-08 15:16:57 +0000244 char *s;
paul22085182005-03-08 16:00:12 +0000245 /* work backwards to ignore trailling isspace() */
gdtf80a0162005-12-29 16:03:32 +0000246 for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
paul22085182005-03-08 16:00:12 +0000247 s--);
248 *s = '\0';
249 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
250 }
paul3b0c5d92005-03-08 10:43:43 +0000251 fclose (f);
252 }
253 else
paulb45da6f2005-03-08 15:16:57 +0000254 vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
paul3b0c5d92005-03-08 10:43:43 +0000255 }
256 else if (host.motd)
Nico Goldeb830c892010-08-01 15:24:35 +0200257 vty_out (vty, "%s", host.motd);
paul718e3742002-12-13 20:15:29 +0000258}
259
260/* Put out prompt and wait input from user. */
261static void
262vty_prompt (struct vty *vty)
263{
264 struct utsname names;
265 const char*hostname;
266
267 if (vty->type == VTY_TERM)
268 {
269 hostname = host.name;
270 if (!hostname)
271 {
272 uname (&names);
273 hostname = names.nodename;
274 }
275 vty_out (vty, cmd_prompt (vty->node), hostname);
276 }
277}
278
279/* Send WILL TELOPT_ECHO to remote server. */
ajs9fc7ebf2005-02-23 15:12:34 +0000280static void
paul718e3742002-12-13 20:15:29 +0000281vty_will_echo (struct vty *vty)
282{
paul02ff83c2004-06-11 11:27:03 +0000283 unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
paul718e3742002-12-13 20:15:29 +0000284 vty_out (vty, "%s", cmd);
285}
286
287/* Make suppress Go-Ahead telnet option. */
288static void
289vty_will_suppress_go_ahead (struct vty *vty)
290{
paul02ff83c2004-06-11 11:27:03 +0000291 unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
paul718e3742002-12-13 20:15:29 +0000292 vty_out (vty, "%s", cmd);
293}
294
295/* Make don't use linemode over telnet. */
296static void
297vty_dont_linemode (struct vty *vty)
298{
paul02ff83c2004-06-11 11:27:03 +0000299 unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
paul718e3742002-12-13 20:15:29 +0000300 vty_out (vty, "%s", cmd);
301}
302
303/* Use window size. */
304static void
305vty_do_window_size (struct vty *vty)
306{
paul02ff83c2004-06-11 11:27:03 +0000307 unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
paul718e3742002-12-13 20:15:29 +0000308 vty_out (vty, "%s", cmd);
309}
310
311#if 0 /* Currently not used. */
312/* Make don't use lflow vty interface. */
313static void
314vty_dont_lflow_ahead (struct vty *vty)
315{
paul02ff83c2004-06-11 11:27:03 +0000316 unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
paul718e3742002-12-13 20:15:29 +0000317 vty_out (vty, "%s", cmd);
318}
319#endif /* 0 */
320
321/* Allocate new vty struct. */
322struct vty *
323vty_new ()
324{
325 struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
326
ajs9fc7ebf2005-02-23 15:12:34 +0000327 new->obuf = buffer_new(0); /* Use default buffer size. */
paul718e3742002-12-13 20:15:29 +0000328 new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
329 new->max = VTY_BUFSIZ;
paul718e3742002-12-13 20:15:29 +0000330
331 return new;
332}
333
334/* Authentication of vty */
335static void
336vty_auth (struct vty *vty, char *buf)
337{
338 char *passwd = NULL;
339 enum node_type next_node = 0;
340 int fail;
341 char *crypt (const char *, const char *);
342
343 switch (vty->node)
344 {
345 case AUTH_NODE:
346 if (host.encrypt)
347 passwd = host.password_encrypt;
348 else
349 passwd = host.password;
350 if (host.advanced)
351 next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
352 else
353 next_node = VIEW_NODE;
354 break;
355 case AUTH_ENABLE_NODE:
356 if (host.encrypt)
357 passwd = host.enable_encrypt;
358 else
359 passwd = host.enable;
360 next_node = ENABLE_NODE;
361 break;
362 }
363
364 if (passwd)
365 {
366 if (host.encrypt)
367 fail = strcmp (crypt(buf, passwd), passwd);
368 else
369 fail = strcmp (buf, passwd);
370 }
371 else
372 fail = 1;
373
374 if (! fail)
375 {
376 vty->fail = 0;
377 vty->node = next_node; /* Success ! */
378 }
379 else
380 {
381 vty->fail++;
382 if (vty->fail >= 3)
383 {
384 if (vty->node == AUTH_NODE)
385 {
386 vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
387 vty->status = VTY_CLOSE;
388 }
389 else
390 {
391 /* AUTH_ENABLE_NODE */
392 vty->fail = 0;
393 vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
Paul Jakma62687ff2008-08-23 14:27:06 +0100394 vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE;
paul718e3742002-12-13 20:15:29 +0000395 }
396 }
397 }
398}
399
400/* Command execution over the vty interface. */
ajs9fc7ebf2005-02-23 15:12:34 +0000401static int
paul718e3742002-12-13 20:15:29 +0000402vty_command (struct vty *vty, char *buf)
403{
404 int ret;
405 vector vline;
vincentfbf5d032005-09-29 11:25:50 +0000406 const char *protocolname;
Lou Berger86b2a0a2016-05-17 12:19:51 -0400407 char *cp = NULL;
paul718e3742002-12-13 20:15:29 +0000408
Lou Bergerc7f7e492016-01-12 13:41:49 -0500409 /*
410 * Log non empty command lines
411 */
Lou Berger86b2a0a2016-05-17 12:19:51 -0400412 if (do_log_commands)
413 cp = buf;
Lou Bergerc7f7e492016-01-12 13:41:49 -0500414 if (cp != NULL)
415 {
416 /* Skip white spaces. */
417 while (isspace ((int) *cp) && *cp != '\0')
418 cp++;
419 }
420 if (cp != NULL && *cp != '\0')
421 {
422 unsigned i;
423 char vty_str[VTY_BUFSIZ];
424 char prompt_str[VTY_BUFSIZ];
425
426 /* format the base vty info */
427 snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address);
428 if (vty)
429 for (i = 0; i < vector_active (vtyvec); i++)
Donald Sharp811577e2016-03-10 20:16:48 -0500430 if (vty == vector_slot (vtyvec, i))
Lou Bergerc7f7e492016-01-12 13:41:49 -0500431 {
432 snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s",
433 i, vty->address);
434 break;
435 }
436
437 /* format the prompt */
438 snprintf(prompt_str, sizeof(prompt_str), cmd_prompt (vty->node), vty_str);
439
440 /* now log the command */
Lou Berger86b2a0a2016-05-17 12:19:51 -0400441 zlog(NULL, LOG_ERR, "%s%s", prompt_str, buf);
Lou Bergerc7f7e492016-01-12 13:41:49 -0500442 }
paul718e3742002-12-13 20:15:29 +0000443 /* Split readline string up into the vector */
444 vline = cmd_make_strvec (buf);
445
446 if (vline == NULL)
447 return CMD_SUCCESS;
448
ajs924b9222005-04-16 17:11:24 +0000449#ifdef CONSUMED_TIME_CHECK
450 {
451 RUSAGE_T before;
452 RUSAGE_T after;
ajs8b70d0b2005-04-28 01:31:13 +0000453 unsigned long realtime, cputime;
ajs924b9222005-04-16 17:11:24 +0000454
455 GETRUSAGE(&before);
456#endif /* CONSUMED_TIME_CHECK */
457
hasso87d683b2005-01-16 23:31:54 +0000458 ret = cmd_execute_command (vline, vty, NULL, 0);
paul718e3742002-12-13 20:15:29 +0000459
vincentfbf5d032005-09-29 11:25:50 +0000460 /* Get the name of the protocol if any */
461 if (zlog_default)
462 protocolname = zlog_proto_names[zlog_default->protocol];
463 else
464 protocolname = zlog_proto_names[ZLOG_NONE];
465
ajs924b9222005-04-16 17:11:24 +0000466#ifdef CONSUMED_TIME_CHECK
467 GETRUSAGE(&after);
ajs8b70d0b2005-04-28 01:31:13 +0000468 if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
469 CONSUMED_TIME_CHECK)
ajs924b9222005-04-16 17:11:24 +0000470 /* Warn about CPU hog that must be fixed. */
ajs8b70d0b2005-04-28 01:31:13 +0000471 zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
472 realtime/1000, cputime/1000, buf);
ajs924b9222005-04-16 17:11:24 +0000473 }
474#endif /* CONSUMED_TIME_CHECK */
475
paul718e3742002-12-13 20:15:29 +0000476 if (ret != CMD_SUCCESS)
477 switch (ret)
478 {
479 case CMD_WARNING:
480 if (vty->type == VTY_FILE)
481 vty_out (vty, "Warning...%s", VTY_NEWLINE);
482 break;
483 case CMD_ERR_AMBIGUOUS:
484 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
485 break;
486 case CMD_ERR_NO_MATCH:
vincentfbf5d032005-09-29 11:25:50 +0000487 vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000488 break;
489 case CMD_ERR_INCOMPLETE:
490 vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
491 break;
492 }
493 cmd_free_strvec (vline);
494
495 return ret;
496}
David Lamparter6b0655a2014-06-04 06:53:35 +0200497
ajs9fc7ebf2005-02-23 15:12:34 +0000498static const char telnet_backward_char = 0x08;
499static const char telnet_space_char = ' ';
paul718e3742002-12-13 20:15:29 +0000500
501/* Basic function to write buffer to vty. */
502static void
ajs9fc7ebf2005-02-23 15:12:34 +0000503vty_write (struct vty *vty, const char *buf, size_t nbytes)
paul718e3742002-12-13 20:15:29 +0000504{
505 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
506 return;
507
508 /* Should we do buffering here ? And make vty_flush (vty) ? */
ajs9fc7ebf2005-02-23 15:12:34 +0000509 buffer_put (vty->obuf, buf, nbytes);
paul718e3742002-12-13 20:15:29 +0000510}
511
paul718e3742002-12-13 20:15:29 +0000512/* Basic function to insert character into vty. */
513static void
514vty_self_insert (struct vty *vty, char c)
515{
516 int i;
517 int length;
518
Quentin Youngb7ceefe2017-01-10 23:33:50 +0000519 if (vty->length + 1 > VTY_BUFSIZ)
520 return;
521
paul718e3742002-12-13 20:15:29 +0000522 length = vty->length - vty->cp;
523 memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
524 vty->buf[vty->cp] = c;
525
526 vty_write (vty, &vty->buf[vty->cp], length + 1);
527 for (i = 0; i < length; i++)
528 vty_write (vty, &telnet_backward_char, 1);
529
530 vty->cp++;
531 vty->length++;
532}
533
534/* Self insert character 'c' in overwrite mode. */
535static void
536vty_self_insert_overwrite (struct vty *vty, char c)
537{
Quentin Youngb7ceefe2017-01-10 23:33:50 +0000538 if (vty->cp == vty->length)
539 {
540 vty_self_insert (vty, c);
541 return;
542 }
543
paul718e3742002-12-13 20:15:29 +0000544 vty->buf[vty->cp++] = c;
paul718e3742002-12-13 20:15:29 +0000545 vty_write (vty, &c, 1);
546}
547
Quentin Youngb7ceefe2017-01-10 23:33:50 +0000548/**
549 * Insert a string into vty->buf at the current cursor position.
550 *
551 * If the resultant string would be larger than VTY_BUFSIZ it is
552 * truncated to fit.
553 */
paul718e3742002-12-13 20:15:29 +0000554static void
555vty_insert_word_overwrite (struct vty *vty, char *str)
556{
Quentin Youngb7ceefe2017-01-10 23:33:50 +0000557 size_t nwrite = MIN ((int) strlen (str), VTY_BUFSIZ - vty->cp);
558 vty_write (vty, str, nwrite);
559 strncpy (&vty->buf[vty->cp], str, nwrite);
560 vty->cp += nwrite;
paul718e3742002-12-13 20:15:29 +0000561 vty->length = vty->cp;
562}
563
564/* Forward character. */
565static void
566vty_forward_char (struct vty *vty)
567{
568 if (vty->cp < vty->length)
569 {
570 vty_write (vty, &vty->buf[vty->cp], 1);
571 vty->cp++;
572 }
573}
574
575/* Backward character. */
576static void
577vty_backward_char (struct vty *vty)
578{
579 if (vty->cp > 0)
580 {
581 vty->cp--;
582 vty_write (vty, &telnet_backward_char, 1);
583 }
584}
585
586/* Move to the beginning of the line. */
587static void
588vty_beginning_of_line (struct vty *vty)
589{
590 while (vty->cp)
591 vty_backward_char (vty);
592}
593
594/* Move to the end of the line. */
595static void
596vty_end_of_line (struct vty *vty)
597{
598 while (vty->cp < vty->length)
599 vty_forward_char (vty);
600}
601
602static void vty_kill_line_from_beginning (struct vty *);
603static void vty_redraw_line (struct vty *);
604
605/* Print command line history. This function is called from
606 vty_next_line and vty_previous_line. */
607static void
608vty_history_print (struct vty *vty)
609{
610 int length;
611
612 vty_kill_line_from_beginning (vty);
613
614 /* Get previous line from history buffer */
615 length = strlen (vty->hist[vty->hp]);
616 memcpy (vty->buf, vty->hist[vty->hp], length);
617 vty->cp = vty->length = length;
618
619 /* Redraw current line */
620 vty_redraw_line (vty);
621}
622
623/* Show next command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000624static void
paul718e3742002-12-13 20:15:29 +0000625vty_next_line (struct vty *vty)
626{
627 int try_index;
628
629 if (vty->hp == vty->hindex)
630 return;
631
632 /* Try is there history exist or not. */
633 try_index = vty->hp;
634 if (try_index == (VTY_MAXHIST - 1))
635 try_index = 0;
636 else
637 try_index++;
638
639 /* If there is not history return. */
640 if (vty->hist[try_index] == NULL)
641 return;
642 else
643 vty->hp = try_index;
644
645 vty_history_print (vty);
646}
647
648/* Show previous command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000649static void
paul718e3742002-12-13 20:15:29 +0000650vty_previous_line (struct vty *vty)
651{
652 int try_index;
653
654 try_index = vty->hp;
655 if (try_index == 0)
656 try_index = VTY_MAXHIST - 1;
657 else
658 try_index--;
659
660 if (vty->hist[try_index] == NULL)
661 return;
662 else
663 vty->hp = try_index;
664
665 vty_history_print (vty);
666}
667
668/* This function redraw all of the command line character. */
669static void
670vty_redraw_line (struct vty *vty)
671{
672 vty_write (vty, vty->buf, vty->length);
673 vty->cp = vty->length;
674}
675
676/* Forward word. */
677static void
678vty_forward_word (struct vty *vty)
679{
680 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
681 vty_forward_char (vty);
682
683 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
684 vty_forward_char (vty);
685}
686
687/* Backward word without skipping training space. */
688static void
689vty_backward_pure_word (struct vty *vty)
690{
691 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
692 vty_backward_char (vty);
693}
694
695/* Backward word. */
696static void
697vty_backward_word (struct vty *vty)
698{
699 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
700 vty_backward_char (vty);
701
702 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
703 vty_backward_char (vty);
704}
705
706/* When '^D' is typed at the beginning of the line we move to the down
707 level. */
708static void
709vty_down_level (struct vty *vty)
710{
711 vty_out (vty, "%s", VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +0000712 (*config_exit_cmd.func)(NULL, vty, 0, NULL);
paul718e3742002-12-13 20:15:29 +0000713 vty_prompt (vty);
714 vty->cp = 0;
715}
716
717/* When '^Z' is received from vty, move down to the enable mode. */
ajs9fc7ebf2005-02-23 15:12:34 +0000718static void
paul718e3742002-12-13 20:15:29 +0000719vty_end_config (struct vty *vty)
720{
721 vty_out (vty, "%s", VTY_NEWLINE);
722
723 switch (vty->node)
724 {
725 case VIEW_NODE:
726 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +0100727 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +0000728 /* Nothing to do. */
729 break;
730 case CONFIG_NODE:
731 case INTERFACE_NODE:
732 case ZEBRA_NODE:
733 case RIP_NODE:
734 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +0100735 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +0000736 case BGP_NODE:
737 case BGP_VPNV4_NODE:
Lou Berger13c378d2016-01-12 13:41:56 -0500738 case BGP_VPNV6_NODE:
Lou Bergera3fda882016-01-12 13:42:04 -0500739 case BGP_ENCAP_NODE:
740 case BGP_ENCAPV6_NODE:
paul718e3742002-12-13 20:15:29 +0000741 case BGP_IPV4_NODE:
742 case BGP_IPV4M_NODE:
743 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +0000744 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +0000745 case RMAP_NODE:
746 case OSPF_NODE:
747 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +0000748 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +0000749 case KEYCHAIN_NODE:
750 case KEYCHAIN_KEY_NODE:
751 case MASC_NODE:
Everton Marques42e30782009-11-18 17:19:43 -0200752 case PIM_NODE:
paul718e3742002-12-13 20:15:29 +0000753 case VTY_NODE:
754 vty_config_unlock (vty);
755 vty->node = ENABLE_NODE;
756 break;
757 default:
758 /* Unknown node, we have to ignore it. */
759 break;
760 }
761
762 vty_prompt (vty);
763 vty->cp = 0;
764}
765
766/* Delete a charcter at the current point. */
767static void
768vty_delete_char (struct vty *vty)
769{
770 int i;
771 int size;
772
paul718e3742002-12-13 20:15:29 +0000773 if (vty->length == 0)
774 {
775 vty_down_level (vty);
776 return;
777 }
778
779 if (vty->cp == vty->length)
780 return; /* completion need here? */
781
782 size = vty->length - vty->cp;
783
784 vty->length--;
785 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
786 vty->buf[vty->length] = '\0';
Roy7f794f22008-08-13 17:27:38 +0100787
788 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
789 return;
paul718e3742002-12-13 20:15:29 +0000790
791 vty_write (vty, &vty->buf[vty->cp], size - 1);
792 vty_write (vty, &telnet_space_char, 1);
793
794 for (i = 0; i < size; i++)
795 vty_write (vty, &telnet_backward_char, 1);
796}
797
798/* Delete a character before the point. */
799static void
800vty_delete_backward_char (struct vty *vty)
801{
802 if (vty->cp == 0)
803 return;
804
805 vty_backward_char (vty);
806 vty_delete_char (vty);
807}
808
809/* Kill rest of line from current point. */
810static void
811vty_kill_line (struct vty *vty)
812{
813 int i;
814 int size;
815
816 size = vty->length - vty->cp;
817
818 if (size == 0)
819 return;
820
821 for (i = 0; i < size; i++)
822 vty_write (vty, &telnet_space_char, 1);
823 for (i = 0; i < size; i++)
824 vty_write (vty, &telnet_backward_char, 1);
825
826 memset (&vty->buf[vty->cp], 0, size);
827 vty->length = vty->cp;
828}
829
830/* Kill line from the beginning. */
831static void
832vty_kill_line_from_beginning (struct vty *vty)
833{
834 vty_beginning_of_line (vty);
835 vty_kill_line (vty);
836}
837
838/* Delete a word before the point. */
839static void
840vty_forward_kill_word (struct vty *vty)
841{
842 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
843 vty_delete_char (vty);
844 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
845 vty_delete_char (vty);
846}
847
848/* Delete a word before the point. */
849static void
850vty_backward_kill_word (struct vty *vty)
851{
852 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
853 vty_delete_backward_char (vty);
854 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
855 vty_delete_backward_char (vty);
856}
857
858/* Transpose chars before or at the point. */
859static void
860vty_transpose_chars (struct vty *vty)
861{
862 char c1, c2;
863
864 /* If length is short or point is near by the beginning of line then
865 return. */
866 if (vty->length < 2 || vty->cp < 1)
867 return;
868
869 /* In case of point is located at the end of the line. */
870 if (vty->cp == vty->length)
871 {
872 c1 = vty->buf[vty->cp - 1];
873 c2 = vty->buf[vty->cp - 2];
874
875 vty_backward_char (vty);
876 vty_backward_char (vty);
877 vty_self_insert_overwrite (vty, c1);
878 vty_self_insert_overwrite (vty, c2);
879 }
880 else
881 {
882 c1 = vty->buf[vty->cp];
883 c2 = vty->buf[vty->cp - 1];
884
885 vty_backward_char (vty);
886 vty_self_insert_overwrite (vty, c1);
887 vty_self_insert_overwrite (vty, c2);
888 }
889}
890
891/* Do completion at vty interface. */
892static void
893vty_complete_command (struct vty *vty)
894{
895 int i;
896 int ret;
897 char **matched = NULL;
898 vector vline;
899
900 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
901 return;
902
903 vline = cmd_make_strvec (vty->buf);
904 if (vline == NULL)
905 return;
906
907 /* In case of 'help \t'. */
908 if (isspace ((int) vty->buf[vty->length - 1]))
David Lampartera91a3ba2015-03-03 09:06:51 +0100909 vector_set (vline, NULL);
paul718e3742002-12-13 20:15:29 +0000910
Lou Berger67290032016-01-12 13:41:46 -0500911 matched = cmd_complete_command_lib (vline, vty, &ret, 1);
paul718e3742002-12-13 20:15:29 +0000912
913 cmd_free_strvec (vline);
914
915 vty_out (vty, "%s", VTY_NEWLINE);
916 switch (ret)
917 {
918 case CMD_ERR_AMBIGUOUS:
919 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
920 vty_prompt (vty);
921 vty_redraw_line (vty);
922 break;
923 case CMD_ERR_NO_MATCH:
924 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
925 vty_prompt (vty);
926 vty_redraw_line (vty);
927 break;
928 case CMD_COMPLETE_FULL_MATCH:
929 vty_prompt (vty);
930 vty_redraw_line (vty);
931 vty_backward_pure_word (vty);
932 vty_insert_word_overwrite (vty, matched[0]);
933 vty_self_insert (vty, ' ');
934 XFREE (MTYPE_TMP, matched[0]);
935 break;
936 case CMD_COMPLETE_MATCH:
937 vty_prompt (vty);
938 vty_redraw_line (vty);
939 vty_backward_pure_word (vty);
940 vty_insert_word_overwrite (vty, matched[0]);
941 XFREE (MTYPE_TMP, matched[0]);
942 vector_only_index_free (matched);
943 return;
944 break;
945 case CMD_COMPLETE_LIST_MATCH:
946 for (i = 0; matched[i] != NULL; i++)
947 {
948 if (i != 0 && ((i % 6) == 0))
949 vty_out (vty, "%s", VTY_NEWLINE);
950 vty_out (vty, "%-10s ", matched[i]);
951 XFREE (MTYPE_TMP, matched[i]);
952 }
953 vty_out (vty, "%s", VTY_NEWLINE);
954
955 vty_prompt (vty);
956 vty_redraw_line (vty);
957 break;
958 case CMD_ERR_NOTHING_TODO:
959 vty_prompt (vty);
960 vty_redraw_line (vty);
961 break;
962 default:
963 break;
964 }
965 if (matched)
966 vector_only_index_free (matched);
967}
968
ajs9fc7ebf2005-02-23 15:12:34 +0000969static void
paul718e3742002-12-13 20:15:29 +0000970vty_describe_fold (struct vty *vty, int cmd_width,
Christian Frankecd40b322013-09-30 12:27:51 +0000971 unsigned int desc_width, struct cmd_token *token)
paul718e3742002-12-13 20:15:29 +0000972{
hasso8c328f12004-10-05 21:01:23 +0000973 char *buf;
974 const char *cmd, *p;
paul718e3742002-12-13 20:15:29 +0000975 int pos;
976
Christian Frankecd40b322013-09-30 12:27:51 +0000977 cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd;
paul718e3742002-12-13 20:15:29 +0000978
979 if (desc_width <= 0)
980 {
Christian Frankecd40b322013-09-30 12:27:51 +0000981 vty_out (vty, " %-*s %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000982 return;
983 }
984
Christian Frankecd40b322013-09-30 12:27:51 +0000985 buf = XCALLOC (MTYPE_TMP, strlen (token->desc) + 1);
paul718e3742002-12-13 20:15:29 +0000986
Christian Frankecd40b322013-09-30 12:27:51 +0000987 for (p = token->desc; strlen (p) > desc_width; p += pos + 1)
paul718e3742002-12-13 20:15:29 +0000988 {
989 for (pos = desc_width; pos > 0; pos--)
990 if (*(p + pos) == ' ')
991 break;
992
993 if (pos == 0)
994 break;
995
996 strncpy (buf, p, pos);
997 buf[pos] = '\0';
998 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
999
1000 cmd = "";
1001 }
1002
1003 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
1004
1005 XFREE (MTYPE_TMP, buf);
1006}
1007
1008/* Describe matched command function. */
1009static void
1010vty_describe_command (struct vty *vty)
1011{
1012 int ret;
1013 vector vline;
1014 vector describe;
hasso8c328f12004-10-05 21:01:23 +00001015 unsigned int i, width, desc_width;
Christian Frankecd40b322013-09-30 12:27:51 +00001016 struct cmd_token *token, *token_cr = NULL;
paul718e3742002-12-13 20:15:29 +00001017
1018 vline = cmd_make_strvec (vty->buf);
1019
1020 /* In case of '> ?'. */
1021 if (vline == NULL)
1022 {
1023 vline = vector_init (1);
David Lampartera91a3ba2015-03-03 09:06:51 +01001024 vector_set (vline, NULL);
paul718e3742002-12-13 20:15:29 +00001025 }
1026 else
1027 if (isspace ((int) vty->buf[vty->length - 1]))
David Lampartera91a3ba2015-03-03 09:06:51 +01001028 vector_set (vline, NULL);
paul718e3742002-12-13 20:15:29 +00001029
1030 describe = cmd_describe_command (vline, vty, &ret);
1031
1032 vty_out (vty, "%s", VTY_NEWLINE);
1033
1034 /* Ambiguous error. */
1035 switch (ret)
1036 {
1037 case CMD_ERR_AMBIGUOUS:
paul718e3742002-12-13 20:15:29 +00001038 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
Paul Jakma2fe8aba2006-05-12 23:22:01 +00001039 goto out;
paul718e3742002-12-13 20:15:29 +00001040 break;
1041 case CMD_ERR_NO_MATCH:
paul718e3742002-12-13 20:15:29 +00001042 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
Paul Jakma2fe8aba2006-05-12 23:22:01 +00001043 goto out;
paul718e3742002-12-13 20:15:29 +00001044 break;
1045 }
1046
1047 /* Get width of command string. */
1048 width = 0;
paul55468c82005-03-14 20:19:01 +00001049 for (i = 0; i < vector_active (describe); i++)
Christian Frankecd40b322013-09-30 12:27:51 +00001050 if ((token = vector_slot (describe, i)) != NULL)
paul718e3742002-12-13 20:15:29 +00001051 {
hasso8c328f12004-10-05 21:01:23 +00001052 unsigned int len;
paul718e3742002-12-13 20:15:29 +00001053
Christian Frankecd40b322013-09-30 12:27:51 +00001054 if (token->cmd[0] == '\0')
paul718e3742002-12-13 20:15:29 +00001055 continue;
1056
Christian Frankecd40b322013-09-30 12:27:51 +00001057 len = strlen (token->cmd);
1058 if (token->cmd[0] == '.')
paul718e3742002-12-13 20:15:29 +00001059 len--;
1060
1061 if (width < len)
1062 width = len;
1063 }
1064
1065 /* Get width of description string. */
1066 desc_width = vty->width - (width + 6);
1067
1068 /* Print out description. */
paul55468c82005-03-14 20:19:01 +00001069 for (i = 0; i < vector_active (describe); i++)
Christian Frankecd40b322013-09-30 12:27:51 +00001070 if ((token = vector_slot (describe, i)) != NULL)
paul718e3742002-12-13 20:15:29 +00001071 {
Christian Frankecd40b322013-09-30 12:27:51 +00001072 if (token->cmd[0] == '\0')
paul718e3742002-12-13 20:15:29 +00001073 continue;
1074
Christian Frankecd40b322013-09-30 12:27:51 +00001075 if (strcmp (token->cmd, command_cr) == 0)
paul718e3742002-12-13 20:15:29 +00001076 {
Christian Frankecd40b322013-09-30 12:27:51 +00001077 token_cr = token;
paul718e3742002-12-13 20:15:29 +00001078 continue;
1079 }
1080
Christian Frankecd40b322013-09-30 12:27:51 +00001081 if (!token->desc)
paul718e3742002-12-13 20:15:29 +00001082 vty_out (vty, " %-s%s",
Christian Frankecd40b322013-09-30 12:27:51 +00001083 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
paul718e3742002-12-13 20:15:29 +00001084 VTY_NEWLINE);
Christian Frankecd40b322013-09-30 12:27:51 +00001085 else if (desc_width >= strlen (token->desc))
paul718e3742002-12-13 20:15:29 +00001086 vty_out (vty, " %-*s %s%s", width,
Christian Frankecd40b322013-09-30 12:27:51 +00001087 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1088 token->desc, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00001089 else
Christian Frankecd40b322013-09-30 12:27:51 +00001090 vty_describe_fold (vty, width, desc_width, token);
paul718e3742002-12-13 20:15:29 +00001091
1092#if 0
1093 vty_out (vty, " %-*s %s%s", width
1094 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1095 desc->str ? desc->str : "", VTY_NEWLINE);
1096#endif /* 0 */
1097 }
1098
Christian Frankecd40b322013-09-30 12:27:51 +00001099 if ((token = token_cr))
paul718e3742002-12-13 20:15:29 +00001100 {
Christian Frankecd40b322013-09-30 12:27:51 +00001101 if (!token->desc)
paul718e3742002-12-13 20:15:29 +00001102 vty_out (vty, " %-s%s",
Christian Frankecd40b322013-09-30 12:27:51 +00001103 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
paul718e3742002-12-13 20:15:29 +00001104 VTY_NEWLINE);
Christian Frankecd40b322013-09-30 12:27:51 +00001105 else if (desc_width >= strlen (token->desc))
paul718e3742002-12-13 20:15:29 +00001106 vty_out (vty, " %-*s %s%s", width,
Christian Frankecd40b322013-09-30 12:27:51 +00001107 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1108 token->desc, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00001109 else
Christian Frankecd40b322013-09-30 12:27:51 +00001110 vty_describe_fold (vty, width, desc_width, token);
paul718e3742002-12-13 20:15:29 +00001111 }
1112
Paul Jakma2fe8aba2006-05-12 23:22:01 +00001113out:
paul718e3742002-12-13 20:15:29 +00001114 cmd_free_strvec (vline);
Paul Jakmad16e0432006-05-15 10:56:46 +00001115 if (describe)
1116 vector_free (describe);
paul718e3742002-12-13 20:15:29 +00001117
1118 vty_prompt (vty);
1119 vty_redraw_line (vty);
1120}
1121
ajs9fc7ebf2005-02-23 15:12:34 +00001122static void
paul718e3742002-12-13 20:15:29 +00001123vty_clear_buf (struct vty *vty)
1124{
1125 memset (vty->buf, 0, vty->max);
1126}
1127
1128/* ^C stop current input and do not add command line to the history. */
1129static void
1130vty_stop_input (struct vty *vty)
1131{
1132 vty->cp = vty->length = 0;
1133 vty_clear_buf (vty);
1134 vty_out (vty, "%s", VTY_NEWLINE);
1135
1136 switch (vty->node)
1137 {
1138 case VIEW_NODE:
1139 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01001140 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00001141 /* Nothing to do. */
1142 break;
1143 case CONFIG_NODE:
1144 case INTERFACE_NODE:
1145 case ZEBRA_NODE:
1146 case RIP_NODE:
1147 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01001148 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00001149 case BGP_NODE:
1150 case RMAP_NODE:
1151 case OSPF_NODE:
1152 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00001153 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00001154 case KEYCHAIN_NODE:
1155 case KEYCHAIN_KEY_NODE:
1156 case MASC_NODE:
Everton Marques42e30782009-11-18 17:19:43 -02001157 case PIM_NODE:
paul718e3742002-12-13 20:15:29 +00001158 case VTY_NODE:
1159 vty_config_unlock (vty);
1160 vty->node = ENABLE_NODE;
1161 break;
1162 default:
1163 /* Unknown node, we have to ignore it. */
1164 break;
1165 }
1166 vty_prompt (vty);
1167
1168 /* Set history pointer to the latest one. */
1169 vty->hp = vty->hindex;
1170}
1171
1172/* Add current command line to the history buffer. */
1173static void
1174vty_hist_add (struct vty *vty)
1175{
1176 int index;
1177
1178 if (vty->length == 0)
1179 return;
1180
1181 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1182
1183 /* Ignore the same string as previous one. */
1184 if (vty->hist[index])
1185 if (strcmp (vty->buf, vty->hist[index]) == 0)
1186 {
1187 vty->hp = vty->hindex;
1188 return;
1189 }
1190
1191 /* Insert history entry. */
1192 if (vty->hist[vty->hindex])
1193 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1194 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1195
1196 /* History index rotation. */
1197 vty->hindex++;
1198 if (vty->hindex == VTY_MAXHIST)
1199 vty->hindex = 0;
1200
1201 vty->hp = vty->hindex;
1202}
1203
1204/* #define TELNET_OPTION_DEBUG */
1205
1206/* Get telnet window size. */
1207static int
1208vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1209{
1210#ifdef TELNET_OPTION_DEBUG
1211 int i;
1212
1213 for (i = 0; i < nbytes; i++)
1214 {
1215 switch (buf[i])
1216 {
1217 case IAC:
1218 vty_out (vty, "IAC ");
1219 break;
1220 case WILL:
1221 vty_out (vty, "WILL ");
1222 break;
1223 case WONT:
1224 vty_out (vty, "WONT ");
1225 break;
1226 case DO:
1227 vty_out (vty, "DO ");
1228 break;
1229 case DONT:
1230 vty_out (vty, "DONT ");
1231 break;
1232 case SB:
1233 vty_out (vty, "SB ");
1234 break;
1235 case SE:
1236 vty_out (vty, "SE ");
1237 break;
1238 case TELOPT_ECHO:
1239 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1240 break;
1241 case TELOPT_SGA:
1242 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1243 break;
1244 case TELOPT_NAWS:
1245 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1246 break;
1247 default:
1248 vty_out (vty, "%x ", buf[i]);
1249 break;
1250 }
1251 }
1252 vty_out (vty, "%s", VTY_NEWLINE);
1253
1254#endif /* TELNET_OPTION_DEBUG */
1255
1256 switch (buf[0])
1257 {
1258 case SB:
ajs9fc7ebf2005-02-23 15:12:34 +00001259 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001260 vty->iac_sb_in_progress = 1;
1261 return 0;
1262 break;
1263 case SE:
1264 {
paul718e3742002-12-13 20:15:29 +00001265 if (!vty->iac_sb_in_progress)
1266 return 0;
1267
ajs9fc7ebf2005-02-23 15:12:34 +00001268 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
paul718e3742002-12-13 20:15:29 +00001269 {
1270 vty->iac_sb_in_progress = 0;
1271 return 0;
1272 }
ajs9fc7ebf2005-02-23 15:12:34 +00001273 switch (vty->sb_buf[0])
paul718e3742002-12-13 20:15:29 +00001274 {
1275 case TELOPT_NAWS:
ajs9fc7ebf2005-02-23 15:12:34 +00001276 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1277 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1278 "should send %d characters, but we received %lu",
1279 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1280 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1281 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1282 "too small to handle the telnet NAWS option",
1283 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1284 else
1285 {
1286 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1287 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1288#ifdef TELNET_OPTION_DEBUG
1289 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1290 "width %d, height %d%s",
1291 vty->width, vty->height, VTY_NEWLINE);
1292#endif
1293 }
paul718e3742002-12-13 20:15:29 +00001294 break;
1295 }
1296 vty->iac_sb_in_progress = 0;
1297 return 0;
1298 break;
1299 }
1300 default:
1301 break;
1302 }
1303 return 1;
1304}
1305
1306/* Execute current command line. */
1307static int
1308vty_execute (struct vty *vty)
1309{
1310 int ret;
1311
1312 ret = CMD_SUCCESS;
1313
1314 switch (vty->node)
1315 {
1316 case AUTH_NODE:
1317 case AUTH_ENABLE_NODE:
1318 vty_auth (vty, vty->buf);
1319 break;
1320 default:
1321 ret = vty_command (vty, vty->buf);
1322 if (vty->type == VTY_TERM)
1323 vty_hist_add (vty);
1324 break;
1325 }
1326
1327 /* Clear command line buffer. */
1328 vty->cp = vty->length = 0;
1329 vty_clear_buf (vty);
1330
ajs5a646652004-11-05 01:25:55 +00001331 if (vty->status != VTY_CLOSE )
paul718e3742002-12-13 20:15:29 +00001332 vty_prompt (vty);
1333
1334 return ret;
1335}
1336
1337#define CONTROL(X) ((X) - '@')
1338#define VTY_NORMAL 0
1339#define VTY_PRE_ESCAPE 1
1340#define VTY_ESCAPE 2
1341
1342/* Escape character command map. */
1343static void
1344vty_escape_map (unsigned char c, struct vty *vty)
1345{
1346 switch (c)
1347 {
1348 case ('A'):
1349 vty_previous_line (vty);
1350 break;
1351 case ('B'):
1352 vty_next_line (vty);
1353 break;
1354 case ('C'):
1355 vty_forward_char (vty);
1356 break;
1357 case ('D'):
1358 vty_backward_char (vty);
1359 break;
1360 default:
1361 break;
1362 }
1363
1364 /* Go back to normal mode. */
1365 vty->escape = VTY_NORMAL;
1366}
1367
1368/* Quit print out to the buffer. */
1369static void
1370vty_buffer_reset (struct vty *vty)
1371{
1372 buffer_reset (vty->obuf);
1373 vty_prompt (vty);
1374 vty_redraw_line (vty);
1375}
1376
1377/* Read data via vty socket. */
1378static int
1379vty_read (struct thread *thread)
1380{
1381 int i;
paul718e3742002-12-13 20:15:29 +00001382 int nbytes;
1383 unsigned char buf[VTY_READ_BUFSIZ];
1384
1385 int vty_sock = THREAD_FD (thread);
1386 struct vty *vty = THREAD_ARG (thread);
1387 vty->t_read = NULL;
1388
1389 /* Read raw data from socket */
ajs9fc7ebf2005-02-23 15:12:34 +00001390 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1391 {
1392 if (nbytes < 0)
1393 {
1394 if (ERRNO_IO_RETRY(errno))
1395 {
1396 vty_event (VTY_READ, vty_sock, vty);
1397 return 0;
1398 }
Andrew J. Schorr74542d72006-07-10 18:09:42 +00001399 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +00001400 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1401 __func__, vty->fd, safe_strerror(errno));
David Lamparter90d31352015-05-14 14:24:06 +02001402 buffer_reset(vty->obuf);
ajs9fc7ebf2005-02-23 15:12:34 +00001403 }
ajs9fc7ebf2005-02-23 15:12:34 +00001404 vty->status = VTY_CLOSE;
1405 }
paul718e3742002-12-13 20:15:29 +00001406
1407 for (i = 0; i < nbytes; i++)
1408 {
1409 if (buf[i] == IAC)
1410 {
1411 if (!vty->iac)
1412 {
1413 vty->iac = 1;
1414 continue;
1415 }
1416 else
1417 {
1418 vty->iac = 0;
1419 }
1420 }
1421
1422 if (vty->iac_sb_in_progress && !vty->iac)
1423 {
ajs9fc7ebf2005-02-23 15:12:34 +00001424 if (vty->sb_len < sizeof(vty->sb_buf))
1425 vty->sb_buf[vty->sb_len] = buf[i];
1426 vty->sb_len++;
paul718e3742002-12-13 20:15:29 +00001427 continue;
1428 }
1429
1430 if (vty->iac)
1431 {
1432 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001433 int ret = 0;
paule9372532003-10-26 21:36:07 +00001434 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001435 vty->iac = 0;
1436 i += ret;
1437 continue;
1438 }
paul5b8c1b02003-10-15 23:08:55 +00001439
paul718e3742002-12-13 20:15:29 +00001440
1441 if (vty->status == VTY_MORE)
1442 {
1443 switch (buf[i])
1444 {
1445 case CONTROL('C'):
1446 case 'q':
1447 case 'Q':
paul718e3742002-12-13 20:15:29 +00001448 vty_buffer_reset (vty);
1449 break;
1450#if 0 /* More line does not work for "show ip bgp". */
1451 case '\n':
1452 case '\r':
1453 vty->status = VTY_MORELINE;
1454 break;
1455#endif
1456 default:
paul718e3742002-12-13 20:15:29 +00001457 break;
1458 }
1459 continue;
1460 }
1461
1462 /* Escape character. */
1463 if (vty->escape == VTY_ESCAPE)
1464 {
1465 vty_escape_map (buf[i], vty);
1466 continue;
1467 }
1468
1469 /* Pre-escape status. */
1470 if (vty->escape == VTY_PRE_ESCAPE)
1471 {
1472 switch (buf[i])
1473 {
1474 case '[':
1475 vty->escape = VTY_ESCAPE;
1476 break;
1477 case 'b':
1478 vty_backward_word (vty);
1479 vty->escape = VTY_NORMAL;
1480 break;
1481 case 'f':
1482 vty_forward_word (vty);
1483 vty->escape = VTY_NORMAL;
1484 break;
1485 case 'd':
1486 vty_forward_kill_word (vty);
1487 vty->escape = VTY_NORMAL;
1488 break;
1489 case CONTROL('H'):
1490 case 0x7f:
1491 vty_backward_kill_word (vty);
1492 vty->escape = VTY_NORMAL;
1493 break;
1494 default:
1495 vty->escape = VTY_NORMAL;
1496 break;
1497 }
1498 continue;
1499 }
1500
1501 switch (buf[i])
1502 {
1503 case CONTROL('A'):
1504 vty_beginning_of_line (vty);
1505 break;
1506 case CONTROL('B'):
1507 vty_backward_char (vty);
1508 break;
1509 case CONTROL('C'):
1510 vty_stop_input (vty);
1511 break;
1512 case CONTROL('D'):
1513 vty_delete_char (vty);
1514 break;
1515 case CONTROL('E'):
1516 vty_end_of_line (vty);
1517 break;
1518 case CONTROL('F'):
1519 vty_forward_char (vty);
1520 break;
1521 case CONTROL('H'):
1522 case 0x7f:
1523 vty_delete_backward_char (vty);
1524 break;
1525 case CONTROL('K'):
1526 vty_kill_line (vty);
1527 break;
1528 case CONTROL('N'):
1529 vty_next_line (vty);
1530 break;
1531 case CONTROL('P'):
1532 vty_previous_line (vty);
1533 break;
1534 case CONTROL('T'):
1535 vty_transpose_chars (vty);
1536 break;
1537 case CONTROL('U'):
1538 vty_kill_line_from_beginning (vty);
1539 break;
1540 case CONTROL('W'):
1541 vty_backward_kill_word (vty);
1542 break;
1543 case CONTROL('Z'):
1544 vty_end_config (vty);
1545 break;
1546 case '\n':
1547 case '\r':
1548 vty_out (vty, "%s", VTY_NEWLINE);
1549 vty_execute (vty);
1550 break;
1551 case '\t':
1552 vty_complete_command (vty);
1553 break;
1554 case '?':
1555 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1556 vty_self_insert (vty, buf[i]);
1557 else
1558 vty_describe_command (vty);
1559 break;
1560 case '\033':
1561 if (i + 1 < nbytes && buf[i + 1] == '[')
1562 {
1563 vty->escape = VTY_ESCAPE;
1564 i++;
1565 }
1566 else
1567 vty->escape = VTY_PRE_ESCAPE;
1568 break;
1569 default:
1570 if (buf[i] > 31 && buf[i] < 127)
1571 vty_self_insert (vty, buf[i]);
1572 break;
1573 }
1574 }
1575
1576 /* Check status. */
1577 if (vty->status == VTY_CLOSE)
1578 vty_close (vty);
1579 else
1580 {
David Lamparter4715a532013-05-30 16:31:49 +02001581 vty_event (VTY_WRITE, vty->wfd, vty);
paul718e3742002-12-13 20:15:29 +00001582 vty_event (VTY_READ, vty_sock, vty);
1583 }
1584 return 0;
1585}
1586
1587/* Flush buffer to the vty. */
1588static int
1589vty_flush (struct thread *thread)
1590{
1591 int erase;
ajs9fc7ebf2005-02-23 15:12:34 +00001592 buffer_status_t flushrc;
paul718e3742002-12-13 20:15:29 +00001593 int vty_sock = THREAD_FD (thread);
1594 struct vty *vty = THREAD_ARG (thread);
ajs9fc7ebf2005-02-23 15:12:34 +00001595
paul718e3742002-12-13 20:15:29 +00001596 vty->t_write = NULL;
1597
1598 /* Tempolary disable read thread. */
ajs9fc7ebf2005-02-23 15:12:34 +00001599 if ((vty->lines == 0) && vty->t_read)
1600 {
1601 thread_cancel (vty->t_read);
1602 vty->t_read = NULL;
1603 }
paul718e3742002-12-13 20:15:29 +00001604
1605 /* Function execution continue. */
ajs9fc7ebf2005-02-23 15:12:34 +00001606 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
paul718e3742002-12-13 20:15:29 +00001607
ajs9fc7ebf2005-02-23 15:12:34 +00001608 /* N.B. if width is 0, that means we don't know the window size. */
Lou Bergerc7f7e492016-01-12 13:41:49 -05001609 if ((vty->lines == 0) || (vty->width == 0) || (vty->height == 0))
David Lamparter4715a532013-05-30 16:31:49 +02001610 flushrc = buffer_flush_available(vty->obuf, vty_sock);
ajs9fc7ebf2005-02-23 15:12:34 +00001611 else if (vty->status == VTY_MORELINE)
David Lamparter4715a532013-05-30 16:31:49 +02001612 flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
ajs9fc7ebf2005-02-23 15:12:34 +00001613 1, erase, 0);
1614 else
David Lamparter4715a532013-05-30 16:31:49 +02001615 flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
ajs9fc7ebf2005-02-23 15:12:34 +00001616 vty->lines >= 0 ? vty->lines :
1617 vty->height,
1618 erase, 0);
1619 switch (flushrc)
1620 {
1621 case BUFFER_ERROR:
Andrew J. Schorr74542d72006-07-10 18:09:42 +00001622 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +00001623 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1624 vty->fd);
1625 buffer_reset(vty->obuf);
1626 vty_close(vty);
1627 return 0;
1628 case BUFFER_EMPTY:
1629 if (vty->status == VTY_CLOSE)
1630 vty_close (vty);
paul718e3742002-12-13 20:15:29 +00001631 else
1632 {
ajs9fc7ebf2005-02-23 15:12:34 +00001633 vty->status = VTY_NORMAL;
paul718e3742002-12-13 20:15:29 +00001634 if (vty->lines == 0)
ajs9fc7ebf2005-02-23 15:12:34 +00001635 vty_event (VTY_READ, vty_sock, vty);
paul718e3742002-12-13 20:15:29 +00001636 }
ajs9fc7ebf2005-02-23 15:12:34 +00001637 break;
1638 case BUFFER_PENDING:
1639 /* There is more data waiting to be written. */
1640 vty->status = VTY_MORE;
1641 if (vty->lines == 0)
1642 vty_event (VTY_WRITE, vty_sock, vty);
1643 break;
1644 }
paul718e3742002-12-13 20:15:29 +00001645
1646 return 0;
1647}
1648
David Lamparterba5dc5e2013-05-30 16:33:45 +02001649/* allocate and initialise vty */
1650static struct vty *
1651vty_new_init (int vty_sock)
1652{
1653 struct vty *vty;
1654
1655 vty = vty_new ();
1656 vty->fd = vty_sock;
1657 vty->wfd = vty_sock;
1658 vty->type = VTY_TERM;
1659 vty->node = AUTH_NODE;
1660 vty->fail = 0;
1661 vty->cp = 0;
1662 vty_clear_buf (vty);
1663 vty->length = 0;
1664 memset (vty->hist, 0, sizeof (vty->hist));
1665 vty->hp = 0;
1666 vty->hindex = 0;
1667 vector_set_index (vtyvec, vty_sock, vty);
1668 vty->status = VTY_NORMAL;
1669 vty->lines = -1;
1670 vty->iac = 0;
1671 vty->iac_sb_in_progress = 0;
1672 vty->sb_len = 0;
1673
1674 return vty;
1675}
1676
paul718e3742002-12-13 20:15:29 +00001677/* Create new vty structure. */
ajs9fc7ebf2005-02-23 15:12:34 +00001678static struct vty *
paul718e3742002-12-13 20:15:29 +00001679vty_create (int vty_sock, union sockunion *su)
1680{
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001681 char buf[SU_ADDRSTRLEN];
paul718e3742002-12-13 20:15:29 +00001682 struct vty *vty;
1683
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001684 sockunion2str(su, buf, SU_ADDRSTRLEN);
1685
paul718e3742002-12-13 20:15:29 +00001686 /* Allocate new vty structure and set up default values. */
David Lamparterba5dc5e2013-05-30 16:33:45 +02001687 vty = vty_new_init (vty_sock);
1688
1689 /* configurable parameters not part of basic init */
1690 vty->v_timeout = vty_timeout_val;
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001691 strcpy (vty->address, buf);
paul718e3742002-12-13 20:15:29 +00001692 if (no_password_check)
1693 {
Paul Jakma62687ff2008-08-23 14:27:06 +01001694 if (restricted_mode)
1695 vty->node = RESTRICTED_NODE;
1696 else if (host.advanced)
paul718e3742002-12-13 20:15:29 +00001697 vty->node = ENABLE_NODE;
1698 else
1699 vty->node = VIEW_NODE;
1700 }
paul718e3742002-12-13 20:15:29 +00001701 if (host.lines >= 0)
1702 vty->lines = host.lines;
paul718e3742002-12-13 20:15:29 +00001703
1704 if (! no_password_check)
1705 {
1706 /* Vty is not available if password isn't set. */
1707 if (host.password == NULL && host.password_encrypt == NULL)
1708 {
1709 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1710 vty->status = VTY_CLOSE;
1711 vty_close (vty);
1712 return NULL;
1713 }
1714 }
1715
1716 /* Say hello to the world. */
1717 vty_hello (vty);
1718 if (! no_password_check)
1719 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1720
1721 /* Setting up terminal. */
1722 vty_will_echo (vty);
1723 vty_will_suppress_go_ahead (vty);
1724
1725 vty_dont_linemode (vty);
1726 vty_do_window_size (vty);
1727 /* vty_dont_lflow_ahead (vty); */
1728
1729 vty_prompt (vty);
1730
1731 /* Add read/write thread. */
1732 vty_event (VTY_WRITE, vty_sock, vty);
1733 vty_event (VTY_READ, vty_sock, vty);
1734
1735 return vty;
1736}
1737
David Lamparterba5dc5e2013-05-30 16:33:45 +02001738/* create vty for stdio */
David Lamparterba53a8f2015-05-05 11:04:46 +02001739static struct termios stdio_orig_termios;
1740static struct vty *stdio_vty = NULL;
David Lamparter464ccf32015-05-12 21:56:18 +02001741static void (*stdio_vty_atclose)(void);
David Lamparterba53a8f2015-05-05 11:04:46 +02001742
1743static void
1744vty_stdio_reset (void)
1745{
1746 if (stdio_vty)
1747 {
1748 tcsetattr (0, TCSANOW, &stdio_orig_termios);
1749 stdio_vty = NULL;
David Lamparter464ccf32015-05-12 21:56:18 +02001750
1751 if (stdio_vty_atclose)
1752 stdio_vty_atclose ();
1753 stdio_vty_atclose = NULL;
David Lamparterba53a8f2015-05-05 11:04:46 +02001754 }
1755}
1756
David Lamparterba5dc5e2013-05-30 16:33:45 +02001757struct vty *
David Lamparter464ccf32015-05-12 21:56:18 +02001758vty_stdio (void (*atclose)())
David Lamparterba5dc5e2013-05-30 16:33:45 +02001759{
1760 struct vty *vty;
David Lamparterba53a8f2015-05-05 11:04:46 +02001761 struct termios termios;
David Lamparterba5dc5e2013-05-30 16:33:45 +02001762
David Lamparterba53a8f2015-05-05 11:04:46 +02001763 /* refuse creating two vtys on stdio */
1764 if (stdio_vty)
1765 return NULL;
1766
1767 vty = stdio_vty = vty_new_init (0);
David Lamparter464ccf32015-05-12 21:56:18 +02001768 stdio_vty_atclose = atclose;
David Lamparterba5dc5e2013-05-30 16:33:45 +02001769 vty->wfd = 1;
1770
1771 /* always have stdio vty in a known _unchangeable_ state, don't want config
1772 * to have any effect here to make sure scripting this works as intended */
1773 vty->node = ENABLE_NODE;
1774 vty->v_timeout = 0;
1775 strcpy (vty->address, "console");
1776
David Lamparterba53a8f2015-05-05 11:04:46 +02001777 if (!tcgetattr (0, &stdio_orig_termios))
1778 {
1779 termios = stdio_orig_termios;
1780 termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
1781 | INLCR | IGNCR | ICRNL | IXON);
1782 termios.c_oflag &= ~OPOST;
1783 termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
1784 termios.c_cflag &= ~(CSIZE | PARENB);
1785 termios.c_cflag |= CS8;
1786 tcsetattr (0, TCSANOW, &termios);
1787 }
1788
David Lamparterba5dc5e2013-05-30 16:33:45 +02001789 vty_prompt (vty);
1790
1791 /* Add read/write thread. */
1792 vty_event (VTY_WRITE, 1, vty);
1793 vty_event (VTY_READ, 0, vty);
1794
1795 return vty;
1796}
1797
paul718e3742002-12-13 20:15:29 +00001798/* Accept connection from the network. */
1799static int
1800vty_accept (struct thread *thread)
1801{
1802 int vty_sock;
paul718e3742002-12-13 20:15:29 +00001803 union sockunion su;
1804 int ret;
1805 unsigned int on;
1806 int accept_sock;
Timo Teräsc1c69e42015-05-22 13:40:57 +03001807 struct prefix p;
paul718e3742002-12-13 20:15:29 +00001808 struct access_list *acl = NULL;
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001809 char buf[SU_ADDRSTRLEN];
paul718e3742002-12-13 20:15:29 +00001810
1811 accept_sock = THREAD_FD (thread);
1812
1813 /* We continue hearing vty socket. */
1814 vty_event (VTY_SERV, accept_sock, NULL);
1815
1816 memset (&su, 0, sizeof (union sockunion));
1817
1818 /* We can handle IPv4 or IPv6 socket. */
1819 vty_sock = sockunion_accept (accept_sock, &su);
1820 if (vty_sock < 0)
1821 {
ajs6099b3b2004-11-20 02:06:59 +00001822 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001823 return -1;
1824 }
ajs9fc7ebf2005-02-23 15:12:34 +00001825 set_nonblocking(vty_sock);
paul718e3742002-12-13 20:15:29 +00001826
Timo Teräsc1c69e42015-05-22 13:40:57 +03001827 sockunion2hostprefix (&su, &p);
paul718e3742002-12-13 20:15:29 +00001828
1829 /* VTY's accesslist apply. */
Timo Teräsc1c69e42015-05-22 13:40:57 +03001830 if (p.family == AF_INET && vty_accesslist_name)
paul718e3742002-12-13 20:15:29 +00001831 {
1832 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
Timo Teräsc1c69e42015-05-22 13:40:57 +03001833 (access_list_apply (acl, &p) == FILTER_DENY))
paul718e3742002-12-13 20:15:29 +00001834 {
paul718e3742002-12-13 20:15:29 +00001835 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001836 sockunion2str (&su, buf, SU_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +00001837 close (vty_sock);
1838
1839 /* continue accepting connections */
1840 vty_event (VTY_SERV, accept_sock, NULL);
1841
paul718e3742002-12-13 20:15:29 +00001842 return 0;
1843 }
1844 }
1845
1846#ifdef HAVE_IPV6
1847 /* VTY's ipv6 accesslist apply. */
Timo Teräsc1c69e42015-05-22 13:40:57 +03001848 if (p.family == AF_INET6 && vty_ipv6_accesslist_name)
paul718e3742002-12-13 20:15:29 +00001849 {
1850 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
Timo Teräsc1c69e42015-05-22 13:40:57 +03001851 (access_list_apply (acl, &p) == FILTER_DENY))
paul718e3742002-12-13 20:15:29 +00001852 {
paul718e3742002-12-13 20:15:29 +00001853 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001854 sockunion2str (&su, buf, SU_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +00001855 close (vty_sock);
1856
1857 /* continue accepting connections */
1858 vty_event (VTY_SERV, accept_sock, NULL);
1859
paul718e3742002-12-13 20:15:29 +00001860 return 0;
1861 }
1862 }
1863#endif /* HAVE_IPV6 */
1864
paul718e3742002-12-13 20:15:29 +00001865 on = 1;
1866 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1867 (char *) &on, sizeof (on));
1868 if (ret < 0)
1869 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
ajs6099b3b2004-11-20 02:06:59 +00001870 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001871
heasley78e6cd92009-12-07 16:41:14 +03001872 zlog (NULL, LOG_INFO, "Vty connection from %s",
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001873 sockunion2str (&su, buf, SU_ADDRSTRLEN));
heasley78e6cd92009-12-07 16:41:14 +03001874
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001875 vty_create (vty_sock, &su);
paul718e3742002-12-13 20:15:29 +00001876
1877 return 0;
1878}
1879
David Lamparter6d6df302014-06-28 21:12:37 +02001880#ifdef HAVE_IPV6
ajs9fc7ebf2005-02-23 15:12:34 +00001881static void
paul718e3742002-12-13 20:15:29 +00001882vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1883{
1884 int ret;
1885 struct addrinfo req;
1886 struct addrinfo *ainfo;
1887 struct addrinfo *ainfo_save;
1888 int sock;
1889 char port_str[BUFSIZ];
1890
1891 memset (&req, 0, sizeof (struct addrinfo));
1892 req.ai_flags = AI_PASSIVE;
1893 req.ai_family = AF_UNSPEC;
1894 req.ai_socktype = SOCK_STREAM;
1895 sprintf (port_str, "%d", port);
1896 port_str[sizeof (port_str) - 1] = '\0';
1897
1898 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1899
1900 if (ret != 0)
1901 {
1902 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1903 exit (1);
1904 }
1905
1906 ainfo_save = ainfo;
1907
1908 do
1909 {
1910 if (ainfo->ai_family != AF_INET
1911#ifdef HAVE_IPV6
1912 && ainfo->ai_family != AF_INET6
1913#endif /* HAVE_IPV6 */
1914 )
1915 continue;
1916
1917 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1918 if (sock < 0)
1919 continue;
1920
David Lamparterca051262009-10-04 16:21:49 +02001921 sockopt_v6only (ainfo->ai_family, sock);
paul718e3742002-12-13 20:15:29 +00001922 sockopt_reuseaddr (sock);
1923 sockopt_reuseport (sock);
1924
1925 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1926 if (ret < 0)
1927 {
1928 close (sock); /* Avoid sd leak. */
1929 continue;
1930 }
1931
1932 ret = listen (sock, 3);
1933 if (ret < 0)
1934 {
1935 close (sock); /* Avoid sd leak. */
1936 continue;
1937 }
1938
1939 vty_event (VTY_SERV, sock, NULL);
1940 }
1941 while ((ainfo = ainfo->ai_next) != NULL);
1942
1943 freeaddrinfo (ainfo_save);
1944}
David Lamparter6d6df302014-06-28 21:12:37 +02001945#else /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001946
1947/* Make vty server socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001948static void
paul29db05b2003-05-08 20:10:22 +00001949vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001950{
1951 int ret;
1952 union sockunion su;
1953 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001954 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001955
1956 memset (&su, 0, sizeof (union sockunion));
1957 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001958 if(addr)
1959 switch(family)
1960 {
1961 case AF_INET:
1962 naddr=&su.sin.sin_addr;
Remi Gacognea11e0122013-09-08 13:48:34 +00001963 break;
paul29db05b2003-05-08 20:10:22 +00001964#ifdef HAVE_IPV6
1965 case AF_INET6:
1966 naddr=&su.sin6.sin6_addr;
Remi Gacognea11e0122013-09-08 13:48:34 +00001967 break;
paul29db05b2003-05-08 20:10:22 +00001968#endif
1969 }
1970
1971 if(naddr)
1972 switch(inet_pton(family,addr,naddr))
1973 {
1974 case -1:
1975 zlog_err("bad address %s",addr);
1976 naddr=NULL;
1977 break;
1978 case 0:
ajs6099b3b2004-11-20 02:06:59 +00001979 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
paul29db05b2003-05-08 20:10:22 +00001980 naddr=NULL;
1981 }
paul718e3742002-12-13 20:15:29 +00001982
1983 /* Make new socket. */
1984 accept_sock = sockunion_stream_socket (&su);
1985 if (accept_sock < 0)
1986 return;
1987
1988 /* This is server, so reuse address. */
1989 sockopt_reuseaddr (accept_sock);
1990 sockopt_reuseport (accept_sock);
1991
1992 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001993 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001994 if (ret < 0)
1995 {
paul29db05b2003-05-08 20:10:22 +00001996 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001997 close (accept_sock); /* Avoid sd leak. */
1998 return;
1999 }
2000
2001 /* Listen socket under queue 3. */
2002 ret = listen (accept_sock, 3);
2003 if (ret < 0)
2004 {
2005 zlog (NULL, LOG_WARNING, "can't listen socket");
2006 close (accept_sock); /* Avoid sd leak. */
2007 return;
2008 }
2009
2010 /* Add vty server event. */
2011 vty_event (VTY_SERV, accept_sock, NULL);
2012}
David Lamparter6d6df302014-06-28 21:12:37 +02002013#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00002014
2015#ifdef VTYSH
2016/* For sockaddr_un. */
2017#include <sys/un.h>
2018
2019/* VTY shell UNIX domain socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00002020static void
hasso6ad96ea2004-10-07 19:33:46 +00002021vty_serv_un (const char *path)
paul718e3742002-12-13 20:15:29 +00002022{
2023 int ret;
paul75e15fe2004-10-31 02:13:09 +00002024 int sock, len;
paul718e3742002-12-13 20:15:29 +00002025 struct sockaddr_un serv;
2026 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00002027 struct zprivs_ids_t ids;
2028
paul718e3742002-12-13 20:15:29 +00002029 /* First of all, unlink existing socket */
2030 unlink (path);
2031
2032 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00002033 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00002034
2035 /* Make UNIX domain socket. */
2036 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2037 if (sock < 0)
2038 {
ajs6a52d0d2005-01-30 18:49:28 +00002039 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00002040 return;
2041 }
2042
2043 /* Make server socket. */
2044 memset (&serv, 0, sizeof (struct sockaddr_un));
2045 serv.sun_family = AF_UNIX;
2046 strncpy (serv.sun_path, path, strlen (path));
Paul Jakma6f0e3f62007-05-10 02:38:51 +00002047#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
paul718e3742002-12-13 20:15:29 +00002048 len = serv.sun_len = SUN_LEN(&serv);
2049#else
2050 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00002051#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
paul718e3742002-12-13 20:15:29 +00002052
2053 ret = bind (sock, (struct sockaddr *) &serv, len);
2054 if (ret < 0)
2055 {
ajs6a52d0d2005-01-30 18:49:28 +00002056 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00002057 close (sock); /* Avoid sd leak. */
2058 return;
2059 }
2060
2061 ret = listen (sock, 5);
2062 if (ret < 0)
2063 {
ajs6a52d0d2005-01-30 18:49:28 +00002064 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00002065 close (sock); /* Avoid sd leak. */
2066 return;
2067 }
2068
2069 umask (old_mask);
2070
pauledd7c242003-06-04 13:59:38 +00002071 zprivs_get_ids(&ids);
2072
2073 if (ids.gid_vty > 0)
2074 {
2075 /* set group of socket */
2076 if ( chown (path, -1, ids.gid_vty) )
2077 {
2078 zlog_err ("vty_serv_un: could chown socket, %s",
ajs6099b3b2004-11-20 02:06:59 +00002079 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +00002080 }
2081 }
2082
paul718e3742002-12-13 20:15:29 +00002083 vty_event (VTYSH_SERV, sock, NULL);
2084}
2085
2086/* #define VTYSH_DEBUG 1 */
2087
2088static int
2089vtysh_accept (struct thread *thread)
2090{
2091 int accept_sock;
2092 int sock;
2093 int client_len;
2094 struct sockaddr_un client;
2095 struct vty *vty;
2096
2097 accept_sock = THREAD_FD (thread);
2098
2099 vty_event (VTYSH_SERV, accept_sock, NULL);
2100
2101 memset (&client, 0, sizeof (struct sockaddr_un));
2102 client_len = sizeof (struct sockaddr_un);
2103
hassoe473b032004-09-26 16:08:11 +00002104 sock = accept (accept_sock, (struct sockaddr *) &client,
2105 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00002106
2107 if (sock < 0)
2108 {
ajs6099b3b2004-11-20 02:06:59 +00002109 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00002110 return -1;
2111 }
2112
ajs9fc7ebf2005-02-23 15:12:34 +00002113 if (set_nonblocking(sock) < 0)
paul75e15fe2004-10-31 02:13:09 +00002114 {
ajs9fc7ebf2005-02-23 15:12:34 +00002115 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
2116 " %s, closing", sock, safe_strerror (errno));
paul75e15fe2004-10-31 02:13:09 +00002117 close (sock);
2118 return -1;
2119 }
pauldccfb192004-10-29 08:29:36 +00002120
paul718e3742002-12-13 20:15:29 +00002121#ifdef VTYSH_DEBUG
2122 printf ("VTY shell accept\n");
2123#endif /* VTYSH_DEBUG */
2124
2125 vty = vty_new ();
2126 vty->fd = sock;
David Lamparter4715a532013-05-30 16:31:49 +02002127 vty->wfd = sock;
paul718e3742002-12-13 20:15:29 +00002128 vty->type = VTY_SHELL_SERV;
2129 vty->node = VIEW_NODE;
2130
2131 vty_event (VTYSH_READ, sock, vty);
2132
2133 return 0;
2134}
2135
2136static int
ajs9fc7ebf2005-02-23 15:12:34 +00002137vtysh_flush(struct vty *vty)
2138{
David Lamparter4715a532013-05-30 16:31:49 +02002139 switch (buffer_flush_available(vty->obuf, vty->wfd))
ajs9fc7ebf2005-02-23 15:12:34 +00002140 {
2141 case BUFFER_PENDING:
David Lamparter4715a532013-05-30 16:31:49 +02002142 vty_event(VTYSH_WRITE, vty->wfd, vty);
ajs9fc7ebf2005-02-23 15:12:34 +00002143 break;
2144 case BUFFER_ERROR:
Andrew J. Schorr74542d72006-07-10 18:09:42 +00002145 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +00002146 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
2147 buffer_reset(vty->obuf);
2148 vty_close(vty);
2149 return -1;
2150 break;
2151 case BUFFER_EMPTY:
2152 break;
2153 }
2154 return 0;
2155}
2156
2157static int
paul718e3742002-12-13 20:15:29 +00002158vtysh_read (struct thread *thread)
2159{
2160 int ret;
2161 int sock;
2162 int nbytes;
2163 struct vty *vty;
2164 unsigned char buf[VTY_READ_BUFSIZ];
ajs9fc7ebf2005-02-23 15:12:34 +00002165 unsigned char *p;
paul718e3742002-12-13 20:15:29 +00002166 u_char header[4] = {0, 0, 0, 0};
2167
2168 sock = THREAD_FD (thread);
2169 vty = THREAD_ARG (thread);
2170 vty->t_read = NULL;
2171
ajs9fc7ebf2005-02-23 15:12:34 +00002172 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
paul718e3742002-12-13 20:15:29 +00002173 {
ajs9fc7ebf2005-02-23 15:12:34 +00002174 if (nbytes < 0)
2175 {
2176 if (ERRNO_IO_RETRY(errno))
2177 {
2178 vty_event (VTYSH_READ, sock, vty);
2179 return 0;
2180 }
Andrew J. Schorr74542d72006-07-10 18:09:42 +00002181 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +00002182 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2183 __func__, sock, safe_strerror(errno));
2184 }
2185 buffer_reset(vty->obuf);
paul718e3742002-12-13 20:15:29 +00002186 vty_close (vty);
2187#ifdef VTYSH_DEBUG
2188 printf ("close vtysh\n");
2189#endif /* VTYSH_DEBUG */
2190 return 0;
2191 }
2192
2193#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002194 printf ("line: %.*s\n", nbytes, buf);
paul718e3742002-12-13 20:15:29 +00002195#endif /* VTYSH_DEBUG */
2196
Quentin Youngb7ceefe2017-01-10 23:33:50 +00002197 if (vty->length + nbytes > VTY_BUFSIZ)
2198 {
2199 /* Clear command line buffer. */
2200 vty->cp = vty->length = 0;
2201 vty_clear_buf (vty);
2202 vty_out (vty, "%% Command is too long.%s", VTY_NEWLINE);
2203 goto out;
2204 }
2205
ajs9fc7ebf2005-02-23 15:12:34 +00002206 for (p = buf; p < buf+nbytes; p++)
2207 {
ajs9fc7ebf2005-02-23 15:12:34 +00002208 vty->buf[vty->length++] = *p;
2209 if (*p == '\0')
2210 {
Quentin Youngb7ceefe2017-01-10 23:33:50 +00002211
ajs9fc7ebf2005-02-23 15:12:34 +00002212 /* Pass this line to parser. */
2213 ret = vty_execute (vty);
2214 /* Note that vty_execute clears the command buffer and resets
2215 vty->length to 0. */
paul718e3742002-12-13 20:15:29 +00002216
ajs9fc7ebf2005-02-23 15:12:34 +00002217 /* Return result. */
paul718e3742002-12-13 20:15:29 +00002218#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002219 printf ("result: %d\n", ret);
2220 printf ("vtysh node: %d\n", vty->node);
paul718e3742002-12-13 20:15:29 +00002221#endif /* VTYSH_DEBUG */
2222
ajs9fc7ebf2005-02-23 15:12:34 +00002223 header[3] = ret;
2224 buffer_put(vty->obuf, header, 4);
paul718e3742002-12-13 20:15:29 +00002225
ajs9fc7ebf2005-02-23 15:12:34 +00002226 if (!vty->t_write && (vtysh_flush(vty) < 0))
2227 /* Try to flush results; exit if a write error occurs. */
2228 return 0;
2229 }
2230 }
2231
Quentin Youngb7ceefe2017-01-10 23:33:50 +00002232out:
paul718e3742002-12-13 20:15:29 +00002233 vty_event (VTYSH_READ, sock, vty);
2234
2235 return 0;
2236}
ajs49ff6d92004-11-04 19:26:16 +00002237
2238static int
2239vtysh_write (struct thread *thread)
2240{
2241 struct vty *vty = THREAD_ARG (thread);
2242
2243 vty->t_write = NULL;
ajs9fc7ebf2005-02-23 15:12:34 +00002244 vtysh_flush(vty);
ajs976d8c72004-11-10 15:40:09 +00002245 return 0;
ajs49ff6d92004-11-04 19:26:16 +00002246}
2247
paul718e3742002-12-13 20:15:29 +00002248#endif /* VTYSH */
2249
2250/* Determine address family to bind. */
2251void
hasso6ad96ea2004-10-07 19:33:46 +00002252vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002253{
2254 /* If port is set to 0, do not listen on TCP/IP at all! */
2255 if (port)
2256 {
2257
2258#ifdef HAVE_IPV6
paul29db05b2003-05-08 20:10:22 +00002259 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002260#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002261 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002262#endif /* HAVE_IPV6 */
2263 }
2264
2265#ifdef VTYSH
2266 vty_serv_un (path);
2267#endif /* VTYSH */
2268}
2269
Andrew J. Schorr9d0a3262006-07-11 00:06:49 +00002270/* Close vty interface. Warning: call this only from functions that
2271 will be careful not to access the vty afterwards (since it has
2272 now been freed). This is safest from top-level functions (called
2273 directly by the thread dispatcher). */
paul718e3742002-12-13 20:15:29 +00002274void
2275vty_close (struct vty *vty)
2276{
2277 int i;
2278
2279 /* Cancel threads.*/
2280 if (vty->t_read)
2281 thread_cancel (vty->t_read);
2282 if (vty->t_write)
2283 thread_cancel (vty->t_write);
2284 if (vty->t_timeout)
2285 thread_cancel (vty->t_timeout);
paul718e3742002-12-13 20:15:29 +00002286
2287 /* Flush buffer. */
David Lamparter4715a532013-05-30 16:31:49 +02002288 buffer_flush_all (vty->obuf, vty->wfd);
paul718e3742002-12-13 20:15:29 +00002289
2290 /* Free input buffer. */
2291 buffer_free (vty->obuf);
2292
paul718e3742002-12-13 20:15:29 +00002293 /* Free command history. */
2294 for (i = 0; i < VTY_MAXHIST; i++)
2295 if (vty->hist[i])
2296 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2297
2298 /* Unset vector. */
2299 vector_unset (vtyvec, vty->fd);
2300
2301 /* Close socket. */
2302 if (vty->fd > 0)
2303 close (vty->fd);
David Lamparterba53a8f2015-05-05 11:04:46 +02002304 else
2305 vty_stdio_reset ();
paul718e3742002-12-13 20:15:29 +00002306
paul718e3742002-12-13 20:15:29 +00002307 if (vty->buf)
2308 XFREE (MTYPE_VTY, vty->buf);
2309
2310 /* Check configure. */
2311 vty_config_unlock (vty);
2312
2313 /* OK free vty. */
2314 XFREE (MTYPE_VTY, vty);
2315}
2316
2317/* When time out occur output message then close connection. */
2318static int
2319vty_timeout (struct thread *thread)
2320{
2321 struct vty *vty;
2322
2323 vty = THREAD_ARG (thread);
2324 vty->t_timeout = NULL;
2325 vty->v_timeout = 0;
2326
2327 /* Clear buffer*/
2328 buffer_reset (vty->obuf);
2329 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2330
2331 /* Close connection. */
2332 vty->status = VTY_CLOSE;
2333 vty_close (vty);
2334
2335 return 0;
2336}
2337
2338/* Read up configuration file from file_name. */
2339static void
2340vty_read_file (FILE *confp)
2341{
2342 int ret;
2343 struct vty *vty;
Steve Hillea555002009-07-28 16:36:14 -04002344 unsigned int line_num = 0;
paul718e3742002-12-13 20:15:29 +00002345
2346 vty = vty_new ();
David Lamparter4715a532013-05-30 16:31:49 +02002347 vty->wfd = dup(STDERR_FILENO); /* vty_close() will close this */
2348 if (vty->wfd < 0)
Steve Hillea555002009-07-28 16:36:14 -04002349 {
2350 /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */
David Lamparter4715a532013-05-30 16:31:49 +02002351 vty->wfd = STDOUT_FILENO;
Steve Hillea555002009-07-28 16:36:14 -04002352 }
David Lamparter4715a532013-05-30 16:31:49 +02002353 vty->fd = STDIN_FILENO;
Steve Hillea555002009-07-28 16:36:14 -04002354 vty->type = VTY_FILE;
paul718e3742002-12-13 20:15:29 +00002355 vty->node = CONFIG_NODE;
2356
2357 /* Execute configuration file */
Steve Hillea555002009-07-28 16:36:14 -04002358 ret = config_from_file (vty, confp, &line_num);
2359
2360 /* Flush any previous errors before printing messages below */
2361 buffer_flush_all (vty->obuf, vty->fd);
paul718e3742002-12-13 20:15:29 +00002362
paul7021c422003-07-15 12:52:22 +00002363 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002364 {
2365 switch (ret)
paul7021c422003-07-15 12:52:22 +00002366 {
2367 case CMD_ERR_AMBIGUOUS:
Steve Hillea555002009-07-28 16:36:14 -04002368 fprintf (stderr, "*** Error reading config: Ambiguous command.\n");
paul7021c422003-07-15 12:52:22 +00002369 break;
2370 case CMD_ERR_NO_MATCH:
Steve Hillea555002009-07-28 16:36:14 -04002371 fprintf (stderr, "*** Error reading config: There is no such command.\n");
paul7021c422003-07-15 12:52:22 +00002372 break;
2373 }
Steve Hillea555002009-07-28 16:36:14 -04002374 fprintf (stderr, "*** Error occured processing line %u, below:\n%s\n",
2375 line_num, vty->buf);
paul718e3742002-12-13 20:15:29 +00002376 vty_close (vty);
2377 exit (1);
2378 }
2379
2380 vty_close (vty);
2381}
2382
ajs9fc7ebf2005-02-23 15:12:34 +00002383static FILE *
paul718e3742002-12-13 20:15:29 +00002384vty_use_backup_config (char *fullpath)
2385{
2386 char *fullpath_sav, *fullpath_tmp;
2387 FILE *ret = NULL;
2388 struct stat buf;
2389 int tmp, sav;
2390 int c;
2391 char buffer[512];
2392
2393 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2394 strcpy (fullpath_sav, fullpath);
2395 strcat (fullpath_sav, CONF_BACKUP_EXT);
2396 if (stat (fullpath_sav, &buf) == -1)
2397 {
2398 free (fullpath_sav);
2399 return NULL;
2400 }
2401
2402 fullpath_tmp = malloc (strlen (fullpath) + 8);
2403 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2404
2405 /* Open file to configuration write. */
2406 tmp = mkstemp (fullpath_tmp);
2407 if (tmp < 0)
2408 {
2409 free (fullpath_sav);
2410 free (fullpath_tmp);
2411 return NULL;
2412 }
2413
2414 sav = open (fullpath_sav, O_RDONLY);
2415 if (sav < 0)
2416 {
gdt3dbf9962003-12-22 20:18:18 +00002417 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002418 free (fullpath_sav);
2419 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002420 return NULL;
2421 }
2422
2423 while((c = read (sav, buffer, 512)) > 0)
2424 write (tmp, buffer, c);
2425
2426 close (sav);
2427 close (tmp);
2428
gdtaa593d52003-12-22 20:15:53 +00002429 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2430 {
gdt3dbf9962003-12-22 20:18:18 +00002431 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002432 free (fullpath_sav);
2433 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002434 return NULL;
2435 }
2436
paul718e3742002-12-13 20:15:29 +00002437 if (link (fullpath_tmp, fullpath) == 0)
2438 ret = fopen (fullpath, "r");
2439
2440 unlink (fullpath_tmp);
2441
2442 free (fullpath_sav);
2443 free (fullpath_tmp);
hasso12f6ea22005-03-07 08:35:39 +00002444 return ret;
paul718e3742002-12-13 20:15:29 +00002445}
2446
2447/* Read up configuration file from file_name. */
2448void
2449vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002450 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002451{
paulccc92352003-10-22 02:49:38 +00002452 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002453 FILE *confp = NULL;
2454 char *fullpath;
paul05865c92005-10-26 05:49:54 +00002455 char *tmp = NULL;
paul718e3742002-12-13 20:15:29 +00002456
2457 /* If -f flag specified. */
2458 if (config_file != NULL)
2459 {
2460 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002461 {
2462 getcwd (cwd, MAXPATHLEN);
paul05865c92005-10-26 05:49:54 +00002463 tmp = XMALLOC (MTYPE_TMP,
hasso320ec102004-06-20 19:54:37 +00002464 strlen (cwd) + strlen (config_file) + 2);
paul05865c92005-10-26 05:49:54 +00002465 sprintf (tmp, "%s/%s", cwd, config_file);
2466 fullpath = tmp;
hasso320ec102004-06-20 19:54:37 +00002467 }
paul718e3742002-12-13 20:15:29 +00002468 else
hasso320ec102004-06-20 19:54:37 +00002469 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002470
2471 confp = fopen (fullpath, "r");
2472
2473 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002474 {
paul3d1dc852005-04-05 00:45:23 +00002475 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2476 __func__, fullpath, safe_strerror (errno));
2477
hasso320ec102004-06-20 19:54:37 +00002478 confp = vty_use_backup_config (fullpath);
2479 if (confp)
2480 fprintf (stderr, "WARNING: using backup configuration file!\n");
2481 else
2482 {
2483 fprintf (stderr, "can't open configuration file [%s]\n",
paul3d1dc852005-04-05 00:45:23 +00002484 config_file);
hasso320ec102004-06-20 19:54:37 +00002485 exit(1);
2486 }
2487 }
paul718e3742002-12-13 20:15:29 +00002488 }
2489 else
2490 {
paul718e3742002-12-13 20:15:29 +00002491#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002492 int ret;
2493 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002494
hasso320ec102004-06-20 19:54:37 +00002495 /* !!!!PLEASE LEAVE!!!!
2496 * This is NEEDED for use with vtysh -b, or else you can get
2497 * a real configuration food fight with a lot garbage in the
2498 * merged configuration file it creates coming from the per
2499 * daemon configuration files. This also allows the daemons
2500 * to start if there default configuration file is not
2501 * present or ignore them, as needed when using vtysh -b to
2502 * configure the daemons at boot - MAG
2503 */
paul718e3742002-12-13 20:15:29 +00002504
hasso320ec102004-06-20 19:54:37 +00002505 /* Stat for vtysh Zebra.conf, if found startup and wait for
2506 * boot configuration
2507 */
paul718e3742002-12-13 20:15:29 +00002508
hasso320ec102004-06-20 19:54:37 +00002509 if ( strstr(config_default_dir, "vtysh") == NULL)
2510 {
2511 ret = stat (integrate_default, &conf_stat);
2512 if (ret >= 0)
2513 return;
2514 }
paul718e3742002-12-13 20:15:29 +00002515#endif /* VTYSH */
2516
hasso320ec102004-06-20 19:54:37 +00002517 confp = fopen (config_default_dir, "r");
2518 if (confp == NULL)
2519 {
paul3d1dc852005-04-05 00:45:23 +00002520 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2521 __func__, config_default_dir, safe_strerror (errno));
2522
hasso320ec102004-06-20 19:54:37 +00002523 confp = vty_use_backup_config (config_default_dir);
2524 if (confp)
2525 {
2526 fprintf (stderr, "WARNING: using backup configuration file!\n");
2527 fullpath = config_default_dir;
2528 }
2529 else
2530 {
2531 fprintf (stderr, "can't open configuration file [%s]\n",
2532 config_default_dir);
2533 exit (1);
paul3d1dc852005-04-05 00:45:23 +00002534 }
hasso320ec102004-06-20 19:54:37 +00002535 }
paul718e3742002-12-13 20:15:29 +00002536 else
hasso320ec102004-06-20 19:54:37 +00002537 fullpath = config_default_dir;
2538 }
2539
paul718e3742002-12-13 20:15:29 +00002540 vty_read_file (confp);
2541
2542 fclose (confp);
2543
2544 host_config_set (fullpath);
paul05865c92005-10-26 05:49:54 +00002545
2546 if (tmp)
2547 XFREE (MTYPE_TMP, fullpath);
paul718e3742002-12-13 20:15:29 +00002548}
2549
2550/* Small utility function which output log to the VTY. */
2551void
ajs274a4a42004-12-07 15:39:31 +00002552vty_log (const char *level, const char *proto_str,
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00002553 const char *format, struct timestamp_control *ctl, va_list va)
paul718e3742002-12-13 20:15:29 +00002554{
hasso8c328f12004-10-05 21:01:23 +00002555 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002556 struct vty *vty;
Paul Jakmaa4b30302006-05-28 08:18:38 +00002557
2558 if (!vtyvec)
2559 return;
paul718e3742002-12-13 20:15:29 +00002560
paul55468c82005-03-14 20:19:01 +00002561 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002562 if ((vty = vector_slot (vtyvec, i)) != NULL)
2563 if (vty->monitor)
ajsd246bd92004-11-23 17:35:08 +00002564 {
2565 va_list ac;
2566 va_copy(ac, va);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00002567 vty_log_out (vty, level, proto_str, format, ctl, ac);
ajsd246bd92004-11-23 17:35:08 +00002568 va_end(ac);
2569 }
paul718e3742002-12-13 20:15:29 +00002570}
2571
ajs274a4a42004-12-07 15:39:31 +00002572/* Async-signal-safe version of vty_log for fixed strings. */
2573void
Paul Jakma7aa9dce2014-09-19 14:42:23 +01002574vty_log_fixed (char *buf, size_t len)
ajs274a4a42004-12-07 15:39:31 +00002575{
2576 unsigned int i;
ajs9fc7ebf2005-02-23 15:12:34 +00002577 struct iovec iov[2];
2578
Paul Jakmaa4b30302006-05-28 08:18:38 +00002579 /* vty may not have been initialised */
2580 if (!vtyvec)
2581 return;
2582
Paul Jakma7aa9dce2014-09-19 14:42:23 +01002583 iov[0].iov_base = buf;
ajs9fc7ebf2005-02-23 15:12:34 +00002584 iov[0].iov_len = len;
ajs926fe8f2005-04-08 18:50:40 +00002585 iov[1].iov_base = (void *)"\r\n";
ajs9fc7ebf2005-02-23 15:12:34 +00002586 iov[1].iov_len = 2;
ajs274a4a42004-12-07 15:39:31 +00002587
paul55468c82005-03-14 20:19:01 +00002588 for (i = 0; i < vector_active (vtyvec); i++)
ajs274a4a42004-12-07 15:39:31 +00002589 {
2590 struct vty *vty;
ajs9fc7ebf2005-02-23 15:12:34 +00002591 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2592 /* N.B. We don't care about the return code, since process is
2593 most likely just about to die anyway. */
David Lamparter4715a532013-05-30 16:31:49 +02002594 writev(vty->wfd, iov, 2);
ajs274a4a42004-12-07 15:39:31 +00002595 }
2596}
2597
paul718e3742002-12-13 20:15:29 +00002598int
2599vty_config_lock (struct vty *vty)
2600{
2601 if (vty_config == 0)
2602 {
2603 vty->config = 1;
2604 vty_config = 1;
2605 }
2606 return vty->config;
2607}
2608
2609int
2610vty_config_unlock (struct vty *vty)
2611{
2612 if (vty_config == 1 && vty->config == 1)
2613 {
2614 vty->config = 0;
2615 vty_config = 0;
2616 }
2617 return vty->config;
2618}
David Lamparter6b0655a2014-06-04 06:53:35 +02002619
paul718e3742002-12-13 20:15:29 +00002620/* Master of the threads. */
Donald Sharpeeef0db2015-10-14 08:50:38 -04002621static struct thread_master *vty_master;
paul718e3742002-12-13 20:15:29 +00002622
2623static void
2624vty_event (enum event event, int sock, struct vty *vty)
2625{
2626 struct thread *vty_serv_thread;
2627
2628 switch (event)
2629 {
2630 case VTY_SERV:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002631 vty_serv_thread = thread_add_read (vty_master, vty_accept, vty, sock);
paul718e3742002-12-13 20:15:29 +00002632 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2633 break;
2634#ifdef VTYSH
2635 case VTYSH_SERV:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002636 vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock);
Christian Franke677bcbb2013-02-27 13:47:23 +00002637 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
paul718e3742002-12-13 20:15:29 +00002638 break;
2639 case VTYSH_READ:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002640 vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock);
ajs49ff6d92004-11-04 19:26:16 +00002641 break;
2642 case VTYSH_WRITE:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002643 vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock);
paul718e3742002-12-13 20:15:29 +00002644 break;
2645#endif /* VTYSH */
2646 case VTY_READ:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002647 vty->t_read = thread_add_read (vty_master, vty_read, vty, sock);
paul718e3742002-12-13 20:15:29 +00002648
2649 /* Time out treatment. */
2650 if (vty->v_timeout)
2651 {
2652 if (vty->t_timeout)
2653 thread_cancel (vty->t_timeout);
2654 vty->t_timeout =
Donald Sharpeeef0db2015-10-14 08:50:38 -04002655 thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
paul718e3742002-12-13 20:15:29 +00002656 }
2657 break;
2658 case VTY_WRITE:
2659 if (! vty->t_write)
Donald Sharpeeef0db2015-10-14 08:50:38 -04002660 vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock);
paul718e3742002-12-13 20:15:29 +00002661 break;
2662 case VTY_TIMEOUT_RESET:
2663 if (vty->t_timeout)
2664 {
2665 thread_cancel (vty->t_timeout);
2666 vty->t_timeout = NULL;
2667 }
2668 if (vty->v_timeout)
2669 {
2670 vty->t_timeout =
Donald Sharpeeef0db2015-10-14 08:50:38 -04002671 thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
paul718e3742002-12-13 20:15:29 +00002672 }
2673 break;
2674 }
2675}
David Lamparter6b0655a2014-06-04 06:53:35 +02002676
Paul Jakma0f2f7a32016-06-16 15:40:02 +01002677DEFUN (who,
2678 who_cmd,
paul718e3742002-12-13 20:15:29 +00002679 "who",
2680 "Display who is on vty\n")
2681{
hasso8c328f12004-10-05 21:01:23 +00002682 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002683 struct vty *v;
2684
paul55468c82005-03-14 20:19:01 +00002685 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002686 if ((v = vector_slot (vtyvec, i)) != NULL)
2687 vty_out (vty, "%svty[%d] connected from %s.%s",
2688 v->config ? "*" : " ",
2689 i, v->address, VTY_NEWLINE);
2690 return CMD_SUCCESS;
2691}
2692
2693/* Move to vty configuration mode. */
2694DEFUN (line_vty,
2695 line_vty_cmd,
2696 "line vty",
2697 "Configure a terminal line\n"
2698 "Virtual terminal\n")
2699{
2700 vty->node = VTY_NODE;
2701 return CMD_SUCCESS;
2702}
2703
2704/* Set time out value. */
ajs9fc7ebf2005-02-23 15:12:34 +00002705static int
paul9035efa2004-10-10 11:56:56 +00002706exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002707{
2708 unsigned long timeout = 0;
2709
2710 /* min_str and sec_str are already checked by parser. So it must be
2711 all digit string. */
2712 if (min_str)
2713 {
2714 timeout = strtol (min_str, NULL, 10);
2715 timeout *= 60;
2716 }
2717 if (sec_str)
2718 timeout += strtol (sec_str, NULL, 10);
2719
2720 vty_timeout_val = timeout;
2721 vty->v_timeout = timeout;
2722 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2723
2724
2725 return CMD_SUCCESS;
2726}
2727
2728DEFUN (exec_timeout_min,
2729 exec_timeout_min_cmd,
2730 "exec-timeout <0-35791>",
2731 "Set timeout value\n"
2732 "Timeout value in minutes\n")
2733{
2734 return exec_timeout (vty, argv[0], NULL);
2735}
2736
2737DEFUN (exec_timeout_sec,
2738 exec_timeout_sec_cmd,
2739 "exec-timeout <0-35791> <0-2147483>",
2740 "Set the EXEC timeout\n"
2741 "Timeout in minutes\n"
2742 "Timeout in seconds\n")
2743{
2744 return exec_timeout (vty, argv[0], argv[1]);
2745}
2746
2747DEFUN (no_exec_timeout,
2748 no_exec_timeout_cmd,
2749 "no exec-timeout",
2750 NO_STR
2751 "Set the EXEC timeout\n")
2752{
2753 return exec_timeout (vty, NULL, NULL);
2754}
2755
2756/* Set vty access class. */
2757DEFUN (vty_access_class,
2758 vty_access_class_cmd,
2759 "access-class WORD",
2760 "Filter connections based on an IP access list\n"
2761 "IP access list\n")
2762{
2763 if (vty_accesslist_name)
2764 XFREE(MTYPE_VTY, vty_accesslist_name);
2765
2766 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2767
2768 return CMD_SUCCESS;
2769}
2770
2771/* Clear vty access class. */
2772DEFUN (no_vty_access_class,
2773 no_vty_access_class_cmd,
2774 "no access-class [WORD]",
2775 NO_STR
2776 "Filter connections based on an IP access list\n"
2777 "IP access list\n")
2778{
2779 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2780 {
2781 vty_out (vty, "Access-class is not currently applied to vty%s",
2782 VTY_NEWLINE);
2783 return CMD_WARNING;
2784 }
2785
2786 XFREE(MTYPE_VTY, vty_accesslist_name);
2787
2788 vty_accesslist_name = NULL;
2789
2790 return CMD_SUCCESS;
2791}
2792
2793#ifdef HAVE_IPV6
2794/* Set vty access class. */
2795DEFUN (vty_ipv6_access_class,
2796 vty_ipv6_access_class_cmd,
2797 "ipv6 access-class WORD",
2798 IPV6_STR
2799 "Filter connections based on an IP access list\n"
2800 "IPv6 access list\n")
2801{
2802 if (vty_ipv6_accesslist_name)
2803 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2804
2805 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2806
2807 return CMD_SUCCESS;
2808}
2809
2810/* Clear vty access class. */
2811DEFUN (no_vty_ipv6_access_class,
2812 no_vty_ipv6_access_class_cmd,
2813 "no ipv6 access-class [WORD]",
2814 NO_STR
2815 IPV6_STR
2816 "Filter connections based on an IP access list\n"
2817 "IPv6 access list\n")
2818{
2819 if (! vty_ipv6_accesslist_name ||
2820 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2821 {
2822 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2823 VTY_NEWLINE);
2824 return CMD_WARNING;
2825 }
2826
2827 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2828
2829 vty_ipv6_accesslist_name = NULL;
2830
2831 return CMD_SUCCESS;
2832}
2833#endif /* HAVE_IPV6 */
2834
2835/* vty login. */
2836DEFUN (vty_login,
2837 vty_login_cmd,
2838 "login",
2839 "Enable password checking\n")
2840{
2841 no_password_check = 0;
2842 return CMD_SUCCESS;
2843}
2844
2845DEFUN (no_vty_login,
2846 no_vty_login_cmd,
2847 "no login",
2848 NO_STR
2849 "Enable password checking\n")
2850{
2851 no_password_check = 1;
2852 return CMD_SUCCESS;
2853}
2854
Paul Jakma62687ff2008-08-23 14:27:06 +01002855/* initial mode. */
2856DEFUN (vty_restricted_mode,
2857 vty_restricted_mode_cmd,
2858 "anonymous restricted",
2859 "Restrict view commands available in anonymous, unauthenticated vty\n")
2860{
2861 restricted_mode = 1;
2862 return CMD_SUCCESS;
2863}
2864
2865DEFUN (vty_no_restricted_mode,
2866 vty_no_restricted_mode_cmd,
2867 "no anonymous restricted",
2868 NO_STR
2869 "Enable password checking\n")
2870{
2871 restricted_mode = 0;
2872 return CMD_SUCCESS;
2873}
2874
paul718e3742002-12-13 20:15:29 +00002875DEFUN (service_advanced_vty,
2876 service_advanced_vty_cmd,
2877 "service advanced-vty",
2878 "Set up miscellaneous service\n"
2879 "Enable advanced mode vty interface\n")
2880{
2881 host.advanced = 1;
2882 return CMD_SUCCESS;
2883}
2884
2885DEFUN (no_service_advanced_vty,
2886 no_service_advanced_vty_cmd,
2887 "no service advanced-vty",
2888 NO_STR
2889 "Set up miscellaneous service\n"
2890 "Enable advanced mode vty interface\n")
2891{
2892 host.advanced = 0;
2893 return CMD_SUCCESS;
2894}
2895
2896DEFUN (terminal_monitor,
2897 terminal_monitor_cmd,
2898 "terminal monitor",
2899 "Set terminal line parameters\n"
2900 "Copy debug output to the current terminal line\n")
2901{
2902 vty->monitor = 1;
2903 return CMD_SUCCESS;
2904}
2905
2906DEFUN (terminal_no_monitor,
2907 terminal_no_monitor_cmd,
2908 "terminal no monitor",
2909 "Set terminal line parameters\n"
2910 NO_STR
2911 "Copy debug output to the current terminal line\n")
2912{
2913 vty->monitor = 0;
2914 return CMD_SUCCESS;
2915}
2916
paul789f78a2006-01-17 17:42:03 +00002917ALIAS (terminal_no_monitor,
2918 no_terminal_monitor_cmd,
2919 "no terminal monitor",
2920 NO_STR
2921 "Set terminal line parameters\n"
2922 "Copy debug output to the current terminal line\n")
2923
paul718e3742002-12-13 20:15:29 +00002924DEFUN (show_history,
2925 show_history_cmd,
2926 "show history",
2927 SHOW_STR
2928 "Display the session command history\n")
2929{
2930 int index;
2931
2932 for (index = vty->hindex + 1; index != vty->hindex;)
2933 {
2934 if (index == VTY_MAXHIST)
2935 {
2936 index = 0;
2937 continue;
2938 }
2939
2940 if (vty->hist[index] != NULL)
2941 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2942
2943 index++;
2944 }
2945
2946 return CMD_SUCCESS;
2947}
2948
Lou Berger86b2a0a2016-05-17 12:19:51 -04002949/* vty login. */
2950DEFUN (log_commands,
2951 log_commands_cmd,
2952 "log commands",
2953 "Logging control\n"
2954 "Log all commands (can't be unset without restart)\n")
2955{
2956 do_log_commands = 1;
2957 return CMD_SUCCESS;
2958}
2959
paul718e3742002-12-13 20:15:29 +00002960/* Display current configuration. */
ajs9fc7ebf2005-02-23 15:12:34 +00002961static int
paul718e3742002-12-13 20:15:29 +00002962vty_config_write (struct vty *vty)
2963{
2964 vty_out (vty, "line vty%s", VTY_NEWLINE);
2965
2966 if (vty_accesslist_name)
2967 vty_out (vty, " access-class %s%s",
2968 vty_accesslist_name, VTY_NEWLINE);
2969
2970 if (vty_ipv6_accesslist_name)
2971 vty_out (vty, " ipv6 access-class %s%s",
2972 vty_ipv6_accesslist_name, VTY_NEWLINE);
2973
2974 /* exec-timeout */
2975 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2976 vty_out (vty, " exec-timeout %ld %ld%s",
2977 vty_timeout_val / 60,
2978 vty_timeout_val % 60, VTY_NEWLINE);
2979
2980 /* login */
2981 if (no_password_check)
2982 vty_out (vty, " no login%s", VTY_NEWLINE);
Paul Jakma62687ff2008-08-23 14:27:06 +01002983
2984 if (restricted_mode != restricted_mode_default)
2985 {
2986 if (restricted_mode_default)
2987 vty_out (vty, " no anonymous restricted%s", VTY_NEWLINE);
2988 else
2989 vty_out (vty, " anonymous restricted%s", VTY_NEWLINE);
2990 }
2991
Lou Berger86b2a0a2016-05-17 12:19:51 -04002992 if (do_log_commands)
2993 vty_out (vty, "log commands%s", VTY_NEWLINE);
2994
paul718e3742002-12-13 20:15:29 +00002995 vty_out (vty, "!%s", VTY_NEWLINE);
2996
2997 return CMD_SUCCESS;
2998}
2999
3000struct cmd_node vty_node =
3001{
3002 VTY_NODE,
3003 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00003004 1,
paul718e3742002-12-13 20:15:29 +00003005};
3006
3007/* Reset all VTY status. */
3008void
3009vty_reset ()
3010{
hasso8c328f12004-10-05 21:01:23 +00003011 unsigned int i;
paul718e3742002-12-13 20:15:29 +00003012 struct vty *vty;
3013 struct thread *vty_serv_thread;
3014
paul55468c82005-03-14 20:19:01 +00003015 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00003016 if ((vty = vector_slot (vtyvec, i)) != NULL)
3017 {
3018 buffer_reset (vty->obuf);
3019 vty->status = VTY_CLOSE;
3020 vty_close (vty);
3021 }
3022
paul55468c82005-03-14 20:19:01 +00003023 for (i = 0; i < vector_active (Vvty_serv_thread); i++)
paul718e3742002-12-13 20:15:29 +00003024 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
3025 {
3026 thread_cancel (vty_serv_thread);
3027 vector_slot (Vvty_serv_thread, i) = NULL;
3028 close (i);
3029 }
3030
3031 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
3032
3033 if (vty_accesslist_name)
3034 {
3035 XFREE(MTYPE_VTY, vty_accesslist_name);
3036 vty_accesslist_name = NULL;
3037 }
3038
3039 if (vty_ipv6_accesslist_name)
3040 {
3041 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
3042 vty_ipv6_accesslist_name = NULL;
3043 }
3044}
3045
ajs9fc7ebf2005-02-23 15:12:34 +00003046static void
3047vty_save_cwd (void)
paul718e3742002-12-13 20:15:29 +00003048{
paul79ad2792003-10-15 22:09:28 +00003049 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00003050 char *c;
paul718e3742002-12-13 20:15:29 +00003051
paulccc92352003-10-22 02:49:38 +00003052 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00003053
paulccc92352003-10-22 02:49:38 +00003054 if (!c)
paul79ad2792003-10-15 22:09:28 +00003055 {
3056 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00003057 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00003058 }
paul718e3742002-12-13 20:15:29 +00003059
3060 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
3061 strcpy (vty_cwd, cwd);
3062}
3063
3064char *
3065vty_get_cwd ()
3066{
3067 return vty_cwd;
3068}
3069
3070int
3071vty_shell (struct vty *vty)
3072{
3073 return vty->type == VTY_SHELL ? 1 : 0;
3074}
3075
3076int
3077vty_shell_serv (struct vty *vty)
3078{
3079 return vty->type == VTY_SHELL_SERV ? 1 : 0;
3080}
3081
3082void
3083vty_init_vtysh ()
3084{
3085 vtyvec = vector_init (VECTOR_MIN_SIZE);
3086}
3087
3088/* Install vty's own commands like `who' command. */
3089void
paulb21b19c2003-06-15 01:28:29 +00003090vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00003091{
3092 /* For further configuration read, preserve current directory. */
3093 vty_save_cwd ();
3094
3095 vtyvec = vector_init (VECTOR_MIN_SIZE);
3096
Donald Sharpeeef0db2015-10-14 08:50:38 -04003097 vty_master = master_thread;
paulb21b19c2003-06-15 01:28:29 +00003098
David Lamparterba53a8f2015-05-05 11:04:46 +02003099 atexit (vty_stdio_reset);
3100
paul718e3742002-12-13 20:15:29 +00003101 /* Initilize server thread vector. */
3102 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
3103
3104 /* Install bgp top node. */
3105 install_node (&vty_node, vty_config_write);
3106
Paul Jakma0f2f7a32016-06-16 15:40:02 +01003107 install_element (RESTRICTED_NODE, &who_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003108 install_element (RESTRICTED_NODE, &show_history_cmd);
Paul Jakma0f2f7a32016-06-16 15:40:02 +01003109 install_element (VIEW_NODE, &who_cmd);
paul718e3742002-12-13 20:15:29 +00003110 install_element (VIEW_NODE, &show_history_cmd);
paul718e3742002-12-13 20:15:29 +00003111 install_element (CONFIG_NODE, &line_vty_cmd);
3112 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
3113 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
3114 install_element (CONFIG_NODE, &show_history_cmd);
Lou Berger86b2a0a2016-05-17 12:19:51 -04003115 install_element (CONFIG_NODE, &log_commands_cmd);
paul718e3742002-12-13 20:15:29 +00003116 install_element (ENABLE_NODE, &terminal_monitor_cmd);
3117 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
paul789f78a2006-01-17 17:42:03 +00003118 install_element (ENABLE_NODE, &no_terminal_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003119
3120 install_default (VTY_NODE);
3121 install_element (VTY_NODE, &exec_timeout_min_cmd);
3122 install_element (VTY_NODE, &exec_timeout_sec_cmd);
3123 install_element (VTY_NODE, &no_exec_timeout_cmd);
3124 install_element (VTY_NODE, &vty_access_class_cmd);
3125 install_element (VTY_NODE, &no_vty_access_class_cmd);
3126 install_element (VTY_NODE, &vty_login_cmd);
3127 install_element (VTY_NODE, &no_vty_login_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003128 install_element (VTY_NODE, &vty_restricted_mode_cmd);
3129 install_element (VTY_NODE, &vty_no_restricted_mode_cmd);
paul718e3742002-12-13 20:15:29 +00003130#ifdef HAVE_IPV6
3131 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
3132 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
3133#endif /* HAVE_IPV6 */
3134}
Chris Caputo228da422009-07-18 05:44:03 +00003135
3136void
3137vty_terminate (void)
3138{
3139 if (vty_cwd)
3140 XFREE (MTYPE_TMP, vty_cwd);
3141
3142 if (vtyvec && Vvty_serv_thread)
3143 {
3144 vty_reset ();
3145 vector_free (vtyvec);
3146 vector_free (Vvty_serv_thread);
3147 }
3148}