blob: 9f4d8faf04c09057d74df0d33d7ad7471a203e88 [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
43/* Vty events */
44enum event
45{
46 VTY_SERV,
47 VTY_READ,
48 VTY_WRITE,
49 VTY_TIMEOUT_RESET,
50#ifdef VTYSH
51 VTYSH_SERV,
ajs49ff6d92004-11-04 19:26:16 +000052 VTYSH_READ,
53 VTYSH_WRITE
paul718e3742002-12-13 20:15:29 +000054#endif /* VTYSH */
55};
56
57static void vty_event (enum event, int, struct vty *);
58
59/* Extern host structure from command.c */
60extern struct host host;
David Lamparter6b0655a2014-06-04 06:53:35 +020061
paul718e3742002-12-13 20:15:29 +000062/* Vector which store each vty structure. */
63static vector vtyvec;
64
65/* Vty timeout value. */
66static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
67
68/* Vty access-class command */
69static char *vty_accesslist_name = NULL;
70
71/* Vty access-calss for IPv6. */
72static char *vty_ipv6_accesslist_name = NULL;
73
74/* VTY server thread. */
Christian Franke677bcbb2013-02-27 13:47:23 +000075static vector Vvty_serv_thread;
paul718e3742002-12-13 20:15:29 +000076
77/* Current directory. */
78char *vty_cwd = NULL;
79
80/* Configure lock. */
81static int vty_config;
82
83/* Login password check. */
84static int no_password_check = 0;
85
Paul Jakma62687ff2008-08-23 14:27:06 +010086/* Restrict unauthenticated logins? */
87static const u_char restricted_mode_default = 0;
88static u_char restricted_mode = 0;
89
paul718e3742002-12-13 20:15:29 +000090/* Integrated configuration file path */
91char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
92
David Lamparter6b0655a2014-06-04 06:53:35 +020093
paul718e3742002-12-13 20:15:29 +000094/* VTY standard output function. */
95int
96vty_out (struct vty *vty, const char *format, ...)
97{
98 va_list args;
99 int len = 0;
100 int size = 1024;
101 char buf[1024];
102 char *p = NULL;
paul718e3742002-12-13 20:15:29 +0000103
104 if (vty_shell (vty))
ajsd246bd92004-11-23 17:35:08 +0000105 {
106 va_start (args, format);
107 vprintf (format, args);
108 va_end (args);
109 }
paul718e3742002-12-13 20:15:29 +0000110 else
111 {
112 /* Try to write to initial buffer. */
ajsd246bd92004-11-23 17:35:08 +0000113 va_start (args, format);
Lou Bergerc7f7e492016-01-12 13:41:49 -0500114 len = vsnprintf (buf, sizeof(buf), format, args);
ajsd246bd92004-11-23 17:35:08 +0000115 va_end (args);
paul718e3742002-12-13 20:15:29 +0000116
117 /* Initial buffer is not enough. */
118 if (len < 0 || len >= size)
119 {
120 while (1)
121 {
122 if (len > -1)
123 size = len + 1;
124 else
125 size = size * 2;
126
127 p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
128 if (! p)
129 return -1;
130
ajsd246bd92004-11-23 17:35:08 +0000131 va_start (args, format);
paul718e3742002-12-13 20:15:29 +0000132 len = vsnprintf (p, size, format, args);
ajsd246bd92004-11-23 17:35:08 +0000133 va_end (args);
paul718e3742002-12-13 20:15:29 +0000134
135 if (len > -1 && len < size)
136 break;
137 }
138 }
139
140 /* When initial buffer is enough to store all output. */
141 if (! p)
142 p = buf;
143
144 /* Pointer p must point out buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +0000145 buffer_put (vty->obuf, (u_char *) p, len);
paul718e3742002-12-13 20:15:29 +0000146
147 /* If p is not different with buf, it is allocated buffer. */
148 if (p != buf)
149 XFREE (MTYPE_VTY_OUT_BUF, p);
150 }
151
paul718e3742002-12-13 20:15:29 +0000152 return len;
153}
154
ajsd246bd92004-11-23 17:35:08 +0000155static int
ajs274a4a42004-12-07 15:39:31 +0000156vty_log_out (struct vty *vty, const char *level, const char *proto_str,
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000157 const char *format, struct timestamp_control *ctl, va_list va)
paul718e3742002-12-13 20:15:29 +0000158{
ajs9fc7ebf2005-02-23 15:12:34 +0000159 int ret;
paul718e3742002-12-13 20:15:29 +0000160 int len;
161 char buf[1024];
Andrew J. Schorr08942da2006-07-03 20:58:29 +0000162
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000163 if (!ctl->already_rendered)
164 {
165 ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
166 ctl->already_rendered = 1;
167 }
168 if (ctl->len+1 >= sizeof(buf))
169 return -1;
170 memcpy(buf, ctl->buf, len = ctl->len);
171 buf[len++] = ' ';
172 buf[len] = '\0';
paul718e3742002-12-13 20:15:29 +0000173
ajs274a4a42004-12-07 15:39:31 +0000174 if (level)
Andrew J. Schorr08942da2006-07-03 20:58:29 +0000175 ret = snprintf(buf+len, sizeof(buf)-len, "%s: %s: ", level, proto_str);
ajs274a4a42004-12-07 15:39:31 +0000176 else
Andrew J. Schorr08942da2006-07-03 20:58:29 +0000177 ret = snprintf(buf+len, sizeof(buf)-len, "%s: ", proto_str);
178 if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf)))
paul718e3742002-12-13 20:15:29 +0000179 return -1;
paul718e3742002-12-13 20:15:29 +0000180
ajs9fc7ebf2005-02-23 15:12:34 +0000181 if (((ret = vsnprintf(buf+len, sizeof(buf)-len, format, va)) < 0) ||
182 ((size_t)((len += ret)+2) > sizeof(buf)))
183 return -1;
paul718e3742002-12-13 20:15:29 +0000184
ajs9fc7ebf2005-02-23 15:12:34 +0000185 buf[len++] = '\r';
186 buf[len++] = '\n';
187
David Lamparter4715a532013-05-30 16:31:49 +0200188 if (write(vty->wfd, buf, len) < 0)
ajs9fc7ebf2005-02-23 15:12:34 +0000189 {
190 if (ERRNO_IO_RETRY(errno))
191 /* Kernel buffer is full, probably too much debugging output, so just
192 drop the data and ignore. */
193 return -1;
194 /* Fatal I/O error. */
Andrew J. Schorr74542d72006-07-10 18:09:42 +0000195 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +0000196 zlog_warn("%s: write failed to vty client fd %d, closing: %s",
197 __func__, vty->fd, safe_strerror(errno));
198 buffer_reset(vty->obuf);
Andrew J. Schorr9d0a3262006-07-11 00:06:49 +0000199 /* cannot call vty_close, because a parent routine may still try
200 to access the vty struct */
201 vty->status = VTY_CLOSE;
202 shutdown(vty->fd, SHUT_RDWR);
ajs9fc7ebf2005-02-23 15:12:34 +0000203 return -1;
204 }
205 return 0;
paul718e3742002-12-13 20:15:29 +0000206}
207
208/* Output current time to the vty. */
209void
210vty_time_print (struct vty *vty, int cr)
211{
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000212 char buf [25];
paul718e3742002-12-13 20:15:29 +0000213
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000214 if (quagga_timestamp(0, buf, sizeof(buf)) == 0)
paul718e3742002-12-13 20:15:29 +0000215 {
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000216 zlog (NULL, LOG_INFO, "quagga_timestamp error");
paul718e3742002-12-13 20:15:29 +0000217 return;
218 }
219 if (cr)
220 vty_out (vty, "%s\n", buf);
221 else
222 vty_out (vty, "%s ", buf);
223
224 return;
225}
226
227/* Say hello to vty interface. */
228void
229vty_hello (struct vty *vty)
230{
paul3b0c5d92005-03-08 10:43:43 +0000231 if (host.motdfile)
232 {
233 FILE *f;
234 char buf[4096];
paul22085182005-03-08 16:00:12 +0000235
paul3b0c5d92005-03-08 10:43:43 +0000236 f = fopen (host.motdfile, "r");
237 if (f)
238 {
paulb45da6f2005-03-08 15:16:57 +0000239 while (fgets (buf, sizeof (buf), f))
paul3b0c5d92005-03-08 10:43:43 +0000240 {
paulb45da6f2005-03-08 15:16:57 +0000241 char *s;
paul22085182005-03-08 16:00:12 +0000242 /* work backwards to ignore trailling isspace() */
gdtf80a0162005-12-29 16:03:32 +0000243 for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
paul22085182005-03-08 16:00:12 +0000244 s--);
245 *s = '\0';
246 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
247 }
paul3b0c5d92005-03-08 10:43:43 +0000248 fclose (f);
249 }
250 else
paulb45da6f2005-03-08 15:16:57 +0000251 vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
paul3b0c5d92005-03-08 10:43:43 +0000252 }
253 else if (host.motd)
Nico Goldeb830c892010-08-01 15:24:35 +0200254 vty_out (vty, "%s", host.motd);
paul718e3742002-12-13 20:15:29 +0000255}
256
257/* Put out prompt and wait input from user. */
258static void
259vty_prompt (struct vty *vty)
260{
261 struct utsname names;
262 const char*hostname;
263
264 if (vty->type == VTY_TERM)
265 {
266 hostname = host.name;
267 if (!hostname)
268 {
269 uname (&names);
270 hostname = names.nodename;
271 }
272 vty_out (vty, cmd_prompt (vty->node), hostname);
273 }
274}
275
276/* Send WILL TELOPT_ECHO to remote server. */
ajs9fc7ebf2005-02-23 15:12:34 +0000277static void
paul718e3742002-12-13 20:15:29 +0000278vty_will_echo (struct vty *vty)
279{
paul02ff83c2004-06-11 11:27:03 +0000280 unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
paul718e3742002-12-13 20:15:29 +0000281 vty_out (vty, "%s", cmd);
282}
283
284/* Make suppress Go-Ahead telnet option. */
285static void
286vty_will_suppress_go_ahead (struct vty *vty)
287{
paul02ff83c2004-06-11 11:27:03 +0000288 unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
paul718e3742002-12-13 20:15:29 +0000289 vty_out (vty, "%s", cmd);
290}
291
292/* Make don't use linemode over telnet. */
293static void
294vty_dont_linemode (struct vty *vty)
295{
paul02ff83c2004-06-11 11:27:03 +0000296 unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
paul718e3742002-12-13 20:15:29 +0000297 vty_out (vty, "%s", cmd);
298}
299
300/* Use window size. */
301static void
302vty_do_window_size (struct vty *vty)
303{
paul02ff83c2004-06-11 11:27:03 +0000304 unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
paul718e3742002-12-13 20:15:29 +0000305 vty_out (vty, "%s", cmd);
306}
307
308#if 0 /* Currently not used. */
309/* Make don't use lflow vty interface. */
310static void
311vty_dont_lflow_ahead (struct vty *vty)
312{
paul02ff83c2004-06-11 11:27:03 +0000313 unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
paul718e3742002-12-13 20:15:29 +0000314 vty_out (vty, "%s", cmd);
315}
316#endif /* 0 */
317
318/* Allocate new vty struct. */
319struct vty *
320vty_new ()
321{
322 struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
323
ajs9fc7ebf2005-02-23 15:12:34 +0000324 new->obuf = buffer_new(0); /* Use default buffer size. */
paul718e3742002-12-13 20:15:29 +0000325 new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
326 new->max = VTY_BUFSIZ;
paul718e3742002-12-13 20:15:29 +0000327
328 return new;
329}
330
331/* Authentication of vty */
332static void
333vty_auth (struct vty *vty, char *buf)
334{
335 char *passwd = NULL;
336 enum node_type next_node = 0;
337 int fail;
338 char *crypt (const char *, const char *);
339
340 switch (vty->node)
341 {
342 case AUTH_NODE:
343 if (host.encrypt)
344 passwd = host.password_encrypt;
345 else
346 passwd = host.password;
347 if (host.advanced)
348 next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
349 else
350 next_node = VIEW_NODE;
351 break;
352 case AUTH_ENABLE_NODE:
353 if (host.encrypt)
354 passwd = host.enable_encrypt;
355 else
356 passwd = host.enable;
357 next_node = ENABLE_NODE;
358 break;
359 }
360
361 if (passwd)
362 {
363 if (host.encrypt)
364 fail = strcmp (crypt(buf, passwd), passwd);
365 else
366 fail = strcmp (buf, passwd);
367 }
368 else
369 fail = 1;
370
371 if (! fail)
372 {
373 vty->fail = 0;
374 vty->node = next_node; /* Success ! */
375 }
376 else
377 {
378 vty->fail++;
379 if (vty->fail >= 3)
380 {
381 if (vty->node == AUTH_NODE)
382 {
383 vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
384 vty->status = VTY_CLOSE;
385 }
386 else
387 {
388 /* AUTH_ENABLE_NODE */
389 vty->fail = 0;
390 vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
Paul Jakma62687ff2008-08-23 14:27:06 +0100391 vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE;
paul718e3742002-12-13 20:15:29 +0000392 }
393 }
394 }
395}
396
397/* Command execution over the vty interface. */
ajs9fc7ebf2005-02-23 15:12:34 +0000398static int
paul718e3742002-12-13 20:15:29 +0000399vty_command (struct vty *vty, char *buf)
400{
401 int ret;
402 vector vline;
vincentfbf5d032005-09-29 11:25:50 +0000403 const char *protocolname;
Lou Bergerc7f7e492016-01-12 13:41:49 -0500404 char *cp;
paul718e3742002-12-13 20:15:29 +0000405
Lou Bergerc7f7e492016-01-12 13:41:49 -0500406 /*
407 * Log non empty command lines
408 */
409 cp = buf;
410 if (cp != NULL)
411 {
412 /* Skip white spaces. */
413 while (isspace ((int) *cp) && *cp != '\0')
414 cp++;
415 }
416 if (cp != NULL && *cp != '\0')
417 {
418 unsigned i;
419 char vty_str[VTY_BUFSIZ];
420 char prompt_str[VTY_BUFSIZ];
421
422 /* format the base vty info */
423 snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address);
424 if (vty)
425 for (i = 0; i < vector_active (vtyvec); i++)
426 if ((vty == vector_slot (vtyvec, i)))
427 {
428 snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s",
429 i, vty->address);
430 break;
431 }
432
433 /* format the prompt */
434 snprintf(prompt_str, sizeof(prompt_str), cmd_prompt (vty->node), vty_str);
435
436 /* now log the command */
437 zlog(NULL, LOG_NOTICE, "%s%s", prompt_str, buf);
438 }
paul718e3742002-12-13 20:15:29 +0000439 /* Split readline string up into the vector */
440 vline = cmd_make_strvec (buf);
441
442 if (vline == NULL)
443 return CMD_SUCCESS;
444
ajs924b9222005-04-16 17:11:24 +0000445#ifdef CONSUMED_TIME_CHECK
446 {
447 RUSAGE_T before;
448 RUSAGE_T after;
ajs8b70d0b2005-04-28 01:31:13 +0000449 unsigned long realtime, cputime;
ajs924b9222005-04-16 17:11:24 +0000450
451 GETRUSAGE(&before);
452#endif /* CONSUMED_TIME_CHECK */
453
hasso87d683b2005-01-16 23:31:54 +0000454 ret = cmd_execute_command (vline, vty, NULL, 0);
paul718e3742002-12-13 20:15:29 +0000455
vincentfbf5d032005-09-29 11:25:50 +0000456 /* Get the name of the protocol if any */
457 if (zlog_default)
458 protocolname = zlog_proto_names[zlog_default->protocol];
459 else
460 protocolname = zlog_proto_names[ZLOG_NONE];
461
ajs924b9222005-04-16 17:11:24 +0000462#ifdef CONSUMED_TIME_CHECK
463 GETRUSAGE(&after);
ajs8b70d0b2005-04-28 01:31:13 +0000464 if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
465 CONSUMED_TIME_CHECK)
ajs924b9222005-04-16 17:11:24 +0000466 /* Warn about CPU hog that must be fixed. */
ajs8b70d0b2005-04-28 01:31:13 +0000467 zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
468 realtime/1000, cputime/1000, buf);
ajs924b9222005-04-16 17:11:24 +0000469 }
470#endif /* CONSUMED_TIME_CHECK */
471
paul718e3742002-12-13 20:15:29 +0000472 if (ret != CMD_SUCCESS)
473 switch (ret)
474 {
475 case CMD_WARNING:
476 if (vty->type == VTY_FILE)
477 vty_out (vty, "Warning...%s", VTY_NEWLINE);
478 break;
479 case CMD_ERR_AMBIGUOUS:
480 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
481 break;
482 case CMD_ERR_NO_MATCH:
vincentfbf5d032005-09-29 11:25:50 +0000483 vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000484 break;
485 case CMD_ERR_INCOMPLETE:
486 vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
487 break;
488 }
489 cmd_free_strvec (vline);
490
491 return ret;
492}
David Lamparter6b0655a2014-06-04 06:53:35 +0200493
ajs9fc7ebf2005-02-23 15:12:34 +0000494static const char telnet_backward_char = 0x08;
495static const char telnet_space_char = ' ';
paul718e3742002-12-13 20:15:29 +0000496
497/* Basic function to write buffer to vty. */
498static void
ajs9fc7ebf2005-02-23 15:12:34 +0000499vty_write (struct vty *vty, const char *buf, size_t nbytes)
paul718e3742002-12-13 20:15:29 +0000500{
501 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
502 return;
503
504 /* Should we do buffering here ? And make vty_flush (vty) ? */
ajs9fc7ebf2005-02-23 15:12:34 +0000505 buffer_put (vty->obuf, buf, nbytes);
paul718e3742002-12-13 20:15:29 +0000506}
507
508/* Ensure length of input buffer. Is buffer is short, double it. */
509static void
510vty_ensure (struct vty *vty, int length)
511{
512 if (vty->max <= length)
513 {
514 vty->max *= 2;
515 vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
516 }
517}
518
519/* Basic function to insert character into vty. */
520static void
521vty_self_insert (struct vty *vty, char c)
522{
523 int i;
524 int length;
525
526 vty_ensure (vty, vty->length + 1);
527 length = vty->length - vty->cp;
528 memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
529 vty->buf[vty->cp] = c;
530
531 vty_write (vty, &vty->buf[vty->cp], length + 1);
532 for (i = 0; i < length; i++)
533 vty_write (vty, &telnet_backward_char, 1);
534
535 vty->cp++;
536 vty->length++;
537}
538
539/* Self insert character 'c' in overwrite mode. */
540static void
541vty_self_insert_overwrite (struct vty *vty, char c)
542{
543 vty_ensure (vty, vty->length + 1);
544 vty->buf[vty->cp++] = c;
545
546 if (vty->cp > vty->length)
547 vty->length++;
548
549 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
550 return;
551
552 vty_write (vty, &c, 1);
553}
554
555/* Insert a word into vty interface with overwrite mode. */
556static void
557vty_insert_word_overwrite (struct vty *vty, char *str)
558{
559 int len = strlen (str);
560 vty_write (vty, str, len);
561 strcpy (&vty->buf[vty->cp], str);
562 vty->cp += len;
563 vty->length = vty->cp;
564}
565
566/* Forward character. */
567static void
568vty_forward_char (struct vty *vty)
569{
570 if (vty->cp < vty->length)
571 {
572 vty_write (vty, &vty->buf[vty->cp], 1);
573 vty->cp++;
574 }
575}
576
577/* Backward character. */
578static void
579vty_backward_char (struct vty *vty)
580{
581 if (vty->cp > 0)
582 {
583 vty->cp--;
584 vty_write (vty, &telnet_backward_char, 1);
585 }
586}
587
588/* Move to the beginning of the line. */
589static void
590vty_beginning_of_line (struct vty *vty)
591{
592 while (vty->cp)
593 vty_backward_char (vty);
594}
595
596/* Move to the end of the line. */
597static void
598vty_end_of_line (struct vty *vty)
599{
600 while (vty->cp < vty->length)
601 vty_forward_char (vty);
602}
603
604static void vty_kill_line_from_beginning (struct vty *);
605static void vty_redraw_line (struct vty *);
606
607/* Print command line history. This function is called from
608 vty_next_line and vty_previous_line. */
609static void
610vty_history_print (struct vty *vty)
611{
612 int length;
613
614 vty_kill_line_from_beginning (vty);
615
616 /* Get previous line from history buffer */
617 length = strlen (vty->hist[vty->hp]);
618 memcpy (vty->buf, vty->hist[vty->hp], length);
619 vty->cp = vty->length = length;
620
621 /* Redraw current line */
622 vty_redraw_line (vty);
623}
624
625/* Show next command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000626static void
paul718e3742002-12-13 20:15:29 +0000627vty_next_line (struct vty *vty)
628{
629 int try_index;
630
631 if (vty->hp == vty->hindex)
632 return;
633
634 /* Try is there history exist or not. */
635 try_index = vty->hp;
636 if (try_index == (VTY_MAXHIST - 1))
637 try_index = 0;
638 else
639 try_index++;
640
641 /* If there is not history return. */
642 if (vty->hist[try_index] == NULL)
643 return;
644 else
645 vty->hp = try_index;
646
647 vty_history_print (vty);
648}
649
650/* Show previous command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000651static void
paul718e3742002-12-13 20:15:29 +0000652vty_previous_line (struct vty *vty)
653{
654 int try_index;
655
656 try_index = vty->hp;
657 if (try_index == 0)
658 try_index = VTY_MAXHIST - 1;
659 else
660 try_index--;
661
662 if (vty->hist[try_index] == NULL)
663 return;
664 else
665 vty->hp = try_index;
666
667 vty_history_print (vty);
668}
669
670/* This function redraw all of the command line character. */
671static void
672vty_redraw_line (struct vty *vty)
673{
674 vty_write (vty, vty->buf, vty->length);
675 vty->cp = vty->length;
676}
677
678/* Forward word. */
679static void
680vty_forward_word (struct vty *vty)
681{
682 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
683 vty_forward_char (vty);
684
685 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
686 vty_forward_char (vty);
687}
688
689/* Backward word without skipping training space. */
690static void
691vty_backward_pure_word (struct vty *vty)
692{
693 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
694 vty_backward_char (vty);
695}
696
697/* Backward word. */
698static void
699vty_backward_word (struct vty *vty)
700{
701 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
702 vty_backward_char (vty);
703
704 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
705 vty_backward_char (vty);
706}
707
708/* When '^D' is typed at the beginning of the line we move to the down
709 level. */
710static void
711vty_down_level (struct vty *vty)
712{
713 vty_out (vty, "%s", VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +0000714 (*config_exit_cmd.func)(NULL, vty, 0, NULL);
paul718e3742002-12-13 20:15:29 +0000715 vty_prompt (vty);
716 vty->cp = 0;
717}
718
719/* When '^Z' is received from vty, move down to the enable mode. */
ajs9fc7ebf2005-02-23 15:12:34 +0000720static void
paul718e3742002-12-13 20:15:29 +0000721vty_end_config (struct vty *vty)
722{
723 vty_out (vty, "%s", VTY_NEWLINE);
724
725 switch (vty->node)
726 {
727 case VIEW_NODE:
728 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +0100729 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +0000730 /* Nothing to do. */
731 break;
732 case CONFIG_NODE:
733 case INTERFACE_NODE:
734 case ZEBRA_NODE:
735 case RIP_NODE:
736 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +0100737 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +0000738 case BGP_NODE:
739 case BGP_VPNV4_NODE:
740 case BGP_IPV4_NODE:
741 case BGP_IPV4M_NODE:
742 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +0000743 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +0000744 case RMAP_NODE:
745 case OSPF_NODE:
746 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +0000747 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +0000748 case KEYCHAIN_NODE:
749 case KEYCHAIN_KEY_NODE:
750 case MASC_NODE:
Everton Marques42e30782009-11-18 17:19:43 -0200751 case PIM_NODE:
paul718e3742002-12-13 20:15:29 +0000752 case VTY_NODE:
753 vty_config_unlock (vty);
754 vty->node = ENABLE_NODE;
755 break;
756 default:
757 /* Unknown node, we have to ignore it. */
758 break;
759 }
760
761 vty_prompt (vty);
762 vty->cp = 0;
763}
764
765/* Delete a charcter at the current point. */
766static void
767vty_delete_char (struct vty *vty)
768{
769 int i;
770 int size;
771
paul718e3742002-12-13 20:15:29 +0000772 if (vty->length == 0)
773 {
774 vty_down_level (vty);
775 return;
776 }
777
778 if (vty->cp == vty->length)
779 return; /* completion need here? */
780
781 size = vty->length - vty->cp;
782
783 vty->length--;
784 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
785 vty->buf[vty->length] = '\0';
Roy7f794f22008-08-13 17:27:38 +0100786
787 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
788 return;
paul718e3742002-12-13 20:15:29 +0000789
790 vty_write (vty, &vty->buf[vty->cp], size - 1);
791 vty_write (vty, &telnet_space_char, 1);
792
793 for (i = 0; i < size; i++)
794 vty_write (vty, &telnet_backward_char, 1);
795}
796
797/* Delete a character before the point. */
798static void
799vty_delete_backward_char (struct vty *vty)
800{
801 if (vty->cp == 0)
802 return;
803
804 vty_backward_char (vty);
805 vty_delete_char (vty);
806}
807
808/* Kill rest of line from current point. */
809static void
810vty_kill_line (struct vty *vty)
811{
812 int i;
813 int size;
814
815 size = vty->length - vty->cp;
816
817 if (size == 0)
818 return;
819
820 for (i = 0; i < size; i++)
821 vty_write (vty, &telnet_space_char, 1);
822 for (i = 0; i < size; i++)
823 vty_write (vty, &telnet_backward_char, 1);
824
825 memset (&vty->buf[vty->cp], 0, size);
826 vty->length = vty->cp;
827}
828
829/* Kill line from the beginning. */
830static void
831vty_kill_line_from_beginning (struct vty *vty)
832{
833 vty_beginning_of_line (vty);
834 vty_kill_line (vty);
835}
836
837/* Delete a word before the point. */
838static void
839vty_forward_kill_word (struct vty *vty)
840{
841 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
842 vty_delete_char (vty);
843 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
844 vty_delete_char (vty);
845}
846
847/* Delete a word before the point. */
848static void
849vty_backward_kill_word (struct vty *vty)
850{
851 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
852 vty_delete_backward_char (vty);
853 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
854 vty_delete_backward_char (vty);
855}
856
857/* Transpose chars before or at the point. */
858static void
859vty_transpose_chars (struct vty *vty)
860{
861 char c1, c2;
862
863 /* If length is short or point is near by the beginning of line then
864 return. */
865 if (vty->length < 2 || vty->cp < 1)
866 return;
867
868 /* In case of point is located at the end of the line. */
869 if (vty->cp == vty->length)
870 {
871 c1 = vty->buf[vty->cp - 1];
872 c2 = vty->buf[vty->cp - 2];
873
874 vty_backward_char (vty);
875 vty_backward_char (vty);
876 vty_self_insert_overwrite (vty, c1);
877 vty_self_insert_overwrite (vty, c2);
878 }
879 else
880 {
881 c1 = vty->buf[vty->cp];
882 c2 = vty->buf[vty->cp - 1];
883
884 vty_backward_char (vty);
885 vty_self_insert_overwrite (vty, c1);
886 vty_self_insert_overwrite (vty, c2);
887 }
888}
889
890/* Do completion at vty interface. */
891static void
892vty_complete_command (struct vty *vty)
893{
894 int i;
895 int ret;
896 char **matched = NULL;
897 vector vline;
898
899 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
900 return;
901
902 vline = cmd_make_strvec (vty->buf);
903 if (vline == NULL)
904 return;
905
906 /* In case of 'help \t'. */
907 if (isspace ((int) vty->buf[vty->length - 1]))
David Lampartera91a3ba2015-03-03 09:06:51 +0100908 vector_set (vline, NULL);
paul718e3742002-12-13 20:15:29 +0000909
Lou Berger67290032016-01-12 13:41:46 -0500910 matched = cmd_complete_command_lib (vline, vty, &ret, 1);
paul718e3742002-12-13 20:15:29 +0000911
912 cmd_free_strvec (vline);
913
914 vty_out (vty, "%s", VTY_NEWLINE);
915 switch (ret)
916 {
917 case CMD_ERR_AMBIGUOUS:
918 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
919 vty_prompt (vty);
920 vty_redraw_line (vty);
921 break;
922 case CMD_ERR_NO_MATCH:
923 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
924 vty_prompt (vty);
925 vty_redraw_line (vty);
926 break;
927 case CMD_COMPLETE_FULL_MATCH:
928 vty_prompt (vty);
929 vty_redraw_line (vty);
930 vty_backward_pure_word (vty);
931 vty_insert_word_overwrite (vty, matched[0]);
932 vty_self_insert (vty, ' ');
933 XFREE (MTYPE_TMP, matched[0]);
934 break;
935 case CMD_COMPLETE_MATCH:
936 vty_prompt (vty);
937 vty_redraw_line (vty);
938 vty_backward_pure_word (vty);
939 vty_insert_word_overwrite (vty, matched[0]);
940 XFREE (MTYPE_TMP, matched[0]);
941 vector_only_index_free (matched);
942 return;
943 break;
944 case CMD_COMPLETE_LIST_MATCH:
945 for (i = 0; matched[i] != NULL; i++)
946 {
947 if (i != 0 && ((i % 6) == 0))
948 vty_out (vty, "%s", VTY_NEWLINE);
949 vty_out (vty, "%-10s ", matched[i]);
950 XFREE (MTYPE_TMP, matched[i]);
951 }
952 vty_out (vty, "%s", VTY_NEWLINE);
953
954 vty_prompt (vty);
955 vty_redraw_line (vty);
956 break;
957 case CMD_ERR_NOTHING_TODO:
958 vty_prompt (vty);
959 vty_redraw_line (vty);
960 break;
961 default:
962 break;
963 }
964 if (matched)
965 vector_only_index_free (matched);
966}
967
ajs9fc7ebf2005-02-23 15:12:34 +0000968static void
paul718e3742002-12-13 20:15:29 +0000969vty_describe_fold (struct vty *vty, int cmd_width,
Christian Frankecd40b322013-09-30 12:27:51 +0000970 unsigned int desc_width, struct cmd_token *token)
paul718e3742002-12-13 20:15:29 +0000971{
hasso8c328f12004-10-05 21:01:23 +0000972 char *buf;
973 const char *cmd, *p;
paul718e3742002-12-13 20:15:29 +0000974 int pos;
975
Christian Frankecd40b322013-09-30 12:27:51 +0000976 cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd;
paul718e3742002-12-13 20:15:29 +0000977
978 if (desc_width <= 0)
979 {
Christian Frankecd40b322013-09-30 12:27:51 +0000980 vty_out (vty, " %-*s %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000981 return;
982 }
983
Christian Frankecd40b322013-09-30 12:27:51 +0000984 buf = XCALLOC (MTYPE_TMP, strlen (token->desc) + 1);
paul718e3742002-12-13 20:15:29 +0000985
Christian Frankecd40b322013-09-30 12:27:51 +0000986 for (p = token->desc; strlen (p) > desc_width; p += pos + 1)
paul718e3742002-12-13 20:15:29 +0000987 {
988 for (pos = desc_width; pos > 0; pos--)
989 if (*(p + pos) == ' ')
990 break;
991
992 if (pos == 0)
993 break;
994
995 strncpy (buf, p, pos);
996 buf[pos] = '\0';
997 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
998
999 cmd = "";
1000 }
1001
1002 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
1003
1004 XFREE (MTYPE_TMP, buf);
1005}
1006
1007/* Describe matched command function. */
1008static void
1009vty_describe_command (struct vty *vty)
1010{
1011 int ret;
1012 vector vline;
1013 vector describe;
hasso8c328f12004-10-05 21:01:23 +00001014 unsigned int i, width, desc_width;
Christian Frankecd40b322013-09-30 12:27:51 +00001015 struct cmd_token *token, *token_cr = NULL;
paul718e3742002-12-13 20:15:29 +00001016
1017 vline = cmd_make_strvec (vty->buf);
1018
1019 /* In case of '> ?'. */
1020 if (vline == NULL)
1021 {
1022 vline = vector_init (1);
David Lampartera91a3ba2015-03-03 09:06:51 +01001023 vector_set (vline, NULL);
paul718e3742002-12-13 20:15:29 +00001024 }
1025 else
1026 if (isspace ((int) vty->buf[vty->length - 1]))
David Lampartera91a3ba2015-03-03 09:06:51 +01001027 vector_set (vline, NULL);
paul718e3742002-12-13 20:15:29 +00001028
1029 describe = cmd_describe_command (vline, vty, &ret);
1030
1031 vty_out (vty, "%s", VTY_NEWLINE);
1032
1033 /* Ambiguous error. */
1034 switch (ret)
1035 {
1036 case CMD_ERR_AMBIGUOUS:
paul718e3742002-12-13 20:15:29 +00001037 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
Paul Jakma2fe8aba2006-05-12 23:22:01 +00001038 goto out;
paul718e3742002-12-13 20:15:29 +00001039 break;
1040 case CMD_ERR_NO_MATCH:
paul718e3742002-12-13 20:15:29 +00001041 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
Paul Jakma2fe8aba2006-05-12 23:22:01 +00001042 goto out;
paul718e3742002-12-13 20:15:29 +00001043 break;
1044 }
1045
1046 /* Get width of command string. */
1047 width = 0;
paul55468c82005-03-14 20:19:01 +00001048 for (i = 0; i < vector_active (describe); i++)
Christian Frankecd40b322013-09-30 12:27:51 +00001049 if ((token = vector_slot (describe, i)) != NULL)
paul718e3742002-12-13 20:15:29 +00001050 {
hasso8c328f12004-10-05 21:01:23 +00001051 unsigned int len;
paul718e3742002-12-13 20:15:29 +00001052
Christian Frankecd40b322013-09-30 12:27:51 +00001053 if (token->cmd[0] == '\0')
paul718e3742002-12-13 20:15:29 +00001054 continue;
1055
Christian Frankecd40b322013-09-30 12:27:51 +00001056 len = strlen (token->cmd);
1057 if (token->cmd[0] == '.')
paul718e3742002-12-13 20:15:29 +00001058 len--;
1059
1060 if (width < len)
1061 width = len;
1062 }
1063
1064 /* Get width of description string. */
1065 desc_width = vty->width - (width + 6);
1066
1067 /* Print out description. */
paul55468c82005-03-14 20:19:01 +00001068 for (i = 0; i < vector_active (describe); i++)
Christian Frankecd40b322013-09-30 12:27:51 +00001069 if ((token = vector_slot (describe, i)) != NULL)
paul718e3742002-12-13 20:15:29 +00001070 {
Christian Frankecd40b322013-09-30 12:27:51 +00001071 if (token->cmd[0] == '\0')
paul718e3742002-12-13 20:15:29 +00001072 continue;
1073
Christian Frankecd40b322013-09-30 12:27:51 +00001074 if (strcmp (token->cmd, command_cr) == 0)
paul718e3742002-12-13 20:15:29 +00001075 {
Christian Frankecd40b322013-09-30 12:27:51 +00001076 token_cr = token;
paul718e3742002-12-13 20:15:29 +00001077 continue;
1078 }
1079
Christian Frankecd40b322013-09-30 12:27:51 +00001080 if (!token->desc)
paul718e3742002-12-13 20:15:29 +00001081 vty_out (vty, " %-s%s",
Christian Frankecd40b322013-09-30 12:27:51 +00001082 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
paul718e3742002-12-13 20:15:29 +00001083 VTY_NEWLINE);
Christian Frankecd40b322013-09-30 12:27:51 +00001084 else if (desc_width >= strlen (token->desc))
paul718e3742002-12-13 20:15:29 +00001085 vty_out (vty, " %-*s %s%s", width,
Christian Frankecd40b322013-09-30 12:27:51 +00001086 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1087 token->desc, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00001088 else
Christian Frankecd40b322013-09-30 12:27:51 +00001089 vty_describe_fold (vty, width, desc_width, token);
paul718e3742002-12-13 20:15:29 +00001090
1091#if 0
1092 vty_out (vty, " %-*s %s%s", width
1093 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1094 desc->str ? desc->str : "", VTY_NEWLINE);
1095#endif /* 0 */
1096 }
1097
Christian Frankecd40b322013-09-30 12:27:51 +00001098 if ((token = token_cr))
paul718e3742002-12-13 20:15:29 +00001099 {
Christian Frankecd40b322013-09-30 12:27:51 +00001100 if (!token->desc)
paul718e3742002-12-13 20:15:29 +00001101 vty_out (vty, " %-s%s",
Christian Frankecd40b322013-09-30 12:27:51 +00001102 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
paul718e3742002-12-13 20:15:29 +00001103 VTY_NEWLINE);
Christian Frankecd40b322013-09-30 12:27:51 +00001104 else if (desc_width >= strlen (token->desc))
paul718e3742002-12-13 20:15:29 +00001105 vty_out (vty, " %-*s %s%s", width,
Christian Frankecd40b322013-09-30 12:27:51 +00001106 token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
1107 token->desc, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00001108 else
Christian Frankecd40b322013-09-30 12:27:51 +00001109 vty_describe_fold (vty, width, desc_width, token);
paul718e3742002-12-13 20:15:29 +00001110 }
1111
Paul Jakma2fe8aba2006-05-12 23:22:01 +00001112out:
paul718e3742002-12-13 20:15:29 +00001113 cmd_free_strvec (vline);
Paul Jakmad16e0432006-05-15 10:56:46 +00001114 if (describe)
1115 vector_free (describe);
paul718e3742002-12-13 20:15:29 +00001116
1117 vty_prompt (vty);
1118 vty_redraw_line (vty);
1119}
1120
ajs9fc7ebf2005-02-23 15:12:34 +00001121static void
paul718e3742002-12-13 20:15:29 +00001122vty_clear_buf (struct vty *vty)
1123{
1124 memset (vty->buf, 0, vty->max);
1125}
1126
1127/* ^C stop current input and do not add command line to the history. */
1128static void
1129vty_stop_input (struct vty *vty)
1130{
1131 vty->cp = vty->length = 0;
1132 vty_clear_buf (vty);
1133 vty_out (vty, "%s", VTY_NEWLINE);
1134
1135 switch (vty->node)
1136 {
1137 case VIEW_NODE:
1138 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01001139 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00001140 /* Nothing to do. */
1141 break;
1142 case CONFIG_NODE:
1143 case INTERFACE_NODE:
1144 case ZEBRA_NODE:
1145 case RIP_NODE:
1146 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01001147 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00001148 case BGP_NODE:
1149 case RMAP_NODE:
1150 case OSPF_NODE:
1151 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00001152 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00001153 case KEYCHAIN_NODE:
1154 case KEYCHAIN_KEY_NODE:
1155 case MASC_NODE:
Everton Marques42e30782009-11-18 17:19:43 -02001156 case PIM_NODE:
paul718e3742002-12-13 20:15:29 +00001157 case VTY_NODE:
1158 vty_config_unlock (vty);
1159 vty->node = ENABLE_NODE;
1160 break;
1161 default:
1162 /* Unknown node, we have to ignore it. */
1163 break;
1164 }
1165 vty_prompt (vty);
1166
1167 /* Set history pointer to the latest one. */
1168 vty->hp = vty->hindex;
1169}
1170
1171/* Add current command line to the history buffer. */
1172static void
1173vty_hist_add (struct vty *vty)
1174{
1175 int index;
1176
1177 if (vty->length == 0)
1178 return;
1179
1180 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1181
1182 /* Ignore the same string as previous one. */
1183 if (vty->hist[index])
1184 if (strcmp (vty->buf, vty->hist[index]) == 0)
1185 {
1186 vty->hp = vty->hindex;
1187 return;
1188 }
1189
1190 /* Insert history entry. */
1191 if (vty->hist[vty->hindex])
1192 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1193 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1194
1195 /* History index rotation. */
1196 vty->hindex++;
1197 if (vty->hindex == VTY_MAXHIST)
1198 vty->hindex = 0;
1199
1200 vty->hp = vty->hindex;
1201}
1202
1203/* #define TELNET_OPTION_DEBUG */
1204
1205/* Get telnet window size. */
1206static int
1207vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1208{
1209#ifdef TELNET_OPTION_DEBUG
1210 int i;
1211
1212 for (i = 0; i < nbytes; i++)
1213 {
1214 switch (buf[i])
1215 {
1216 case IAC:
1217 vty_out (vty, "IAC ");
1218 break;
1219 case WILL:
1220 vty_out (vty, "WILL ");
1221 break;
1222 case WONT:
1223 vty_out (vty, "WONT ");
1224 break;
1225 case DO:
1226 vty_out (vty, "DO ");
1227 break;
1228 case DONT:
1229 vty_out (vty, "DONT ");
1230 break;
1231 case SB:
1232 vty_out (vty, "SB ");
1233 break;
1234 case SE:
1235 vty_out (vty, "SE ");
1236 break;
1237 case TELOPT_ECHO:
1238 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1239 break;
1240 case TELOPT_SGA:
1241 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1242 break;
1243 case TELOPT_NAWS:
1244 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1245 break;
1246 default:
1247 vty_out (vty, "%x ", buf[i]);
1248 break;
1249 }
1250 }
1251 vty_out (vty, "%s", VTY_NEWLINE);
1252
1253#endif /* TELNET_OPTION_DEBUG */
1254
1255 switch (buf[0])
1256 {
1257 case SB:
ajs9fc7ebf2005-02-23 15:12:34 +00001258 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001259 vty->iac_sb_in_progress = 1;
1260 return 0;
1261 break;
1262 case SE:
1263 {
paul718e3742002-12-13 20:15:29 +00001264 if (!vty->iac_sb_in_progress)
1265 return 0;
1266
ajs9fc7ebf2005-02-23 15:12:34 +00001267 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
paul718e3742002-12-13 20:15:29 +00001268 {
1269 vty->iac_sb_in_progress = 0;
1270 return 0;
1271 }
ajs9fc7ebf2005-02-23 15:12:34 +00001272 switch (vty->sb_buf[0])
paul718e3742002-12-13 20:15:29 +00001273 {
1274 case TELOPT_NAWS:
ajs9fc7ebf2005-02-23 15:12:34 +00001275 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1276 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1277 "should send %d characters, but we received %lu",
1278 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1279 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1280 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1281 "too small to handle the telnet NAWS option",
1282 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1283 else
1284 {
1285 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1286 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1287#ifdef TELNET_OPTION_DEBUG
1288 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1289 "width %d, height %d%s",
1290 vty->width, vty->height, VTY_NEWLINE);
1291#endif
1292 }
paul718e3742002-12-13 20:15:29 +00001293 break;
1294 }
1295 vty->iac_sb_in_progress = 0;
1296 return 0;
1297 break;
1298 }
1299 default:
1300 break;
1301 }
1302 return 1;
1303}
1304
1305/* Execute current command line. */
1306static int
1307vty_execute (struct vty *vty)
1308{
1309 int ret;
1310
1311 ret = CMD_SUCCESS;
1312
1313 switch (vty->node)
1314 {
1315 case AUTH_NODE:
1316 case AUTH_ENABLE_NODE:
1317 vty_auth (vty, vty->buf);
1318 break;
1319 default:
1320 ret = vty_command (vty, vty->buf);
1321 if (vty->type == VTY_TERM)
1322 vty_hist_add (vty);
1323 break;
1324 }
1325
1326 /* Clear command line buffer. */
1327 vty->cp = vty->length = 0;
1328 vty_clear_buf (vty);
1329
ajs5a646652004-11-05 01:25:55 +00001330 if (vty->status != VTY_CLOSE )
paul718e3742002-12-13 20:15:29 +00001331 vty_prompt (vty);
1332
1333 return ret;
1334}
1335
1336#define CONTROL(X) ((X) - '@')
1337#define VTY_NORMAL 0
1338#define VTY_PRE_ESCAPE 1
1339#define VTY_ESCAPE 2
1340
1341/* Escape character command map. */
1342static void
1343vty_escape_map (unsigned char c, struct vty *vty)
1344{
1345 switch (c)
1346 {
1347 case ('A'):
1348 vty_previous_line (vty);
1349 break;
1350 case ('B'):
1351 vty_next_line (vty);
1352 break;
1353 case ('C'):
1354 vty_forward_char (vty);
1355 break;
1356 case ('D'):
1357 vty_backward_char (vty);
1358 break;
1359 default:
1360 break;
1361 }
1362
1363 /* Go back to normal mode. */
1364 vty->escape = VTY_NORMAL;
1365}
1366
1367/* Quit print out to the buffer. */
1368static void
1369vty_buffer_reset (struct vty *vty)
1370{
1371 buffer_reset (vty->obuf);
1372 vty_prompt (vty);
1373 vty_redraw_line (vty);
1374}
1375
1376/* Read data via vty socket. */
1377static int
1378vty_read (struct thread *thread)
1379{
1380 int i;
paul718e3742002-12-13 20:15:29 +00001381 int nbytes;
1382 unsigned char buf[VTY_READ_BUFSIZ];
1383
1384 int vty_sock = THREAD_FD (thread);
1385 struct vty *vty = THREAD_ARG (thread);
1386 vty->t_read = NULL;
1387
1388 /* Read raw data from socket */
ajs9fc7ebf2005-02-23 15:12:34 +00001389 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1390 {
1391 if (nbytes < 0)
1392 {
1393 if (ERRNO_IO_RETRY(errno))
1394 {
1395 vty_event (VTY_READ, vty_sock, vty);
1396 return 0;
1397 }
Andrew J. Schorr74542d72006-07-10 18:09:42 +00001398 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +00001399 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1400 __func__, vty->fd, safe_strerror(errno));
David Lamparter90d31352015-05-14 14:24:06 +02001401 buffer_reset(vty->obuf);
ajs9fc7ebf2005-02-23 15:12:34 +00001402 }
ajs9fc7ebf2005-02-23 15:12:34 +00001403 vty->status = VTY_CLOSE;
1404 }
paul718e3742002-12-13 20:15:29 +00001405
1406 for (i = 0; i < nbytes; i++)
1407 {
1408 if (buf[i] == IAC)
1409 {
1410 if (!vty->iac)
1411 {
1412 vty->iac = 1;
1413 continue;
1414 }
1415 else
1416 {
1417 vty->iac = 0;
1418 }
1419 }
1420
1421 if (vty->iac_sb_in_progress && !vty->iac)
1422 {
ajs9fc7ebf2005-02-23 15:12:34 +00001423 if (vty->sb_len < sizeof(vty->sb_buf))
1424 vty->sb_buf[vty->sb_len] = buf[i];
1425 vty->sb_len++;
paul718e3742002-12-13 20:15:29 +00001426 continue;
1427 }
1428
1429 if (vty->iac)
1430 {
1431 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001432 int ret = 0;
paule9372532003-10-26 21:36:07 +00001433 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001434 vty->iac = 0;
1435 i += ret;
1436 continue;
1437 }
paul5b8c1b02003-10-15 23:08:55 +00001438
paul718e3742002-12-13 20:15:29 +00001439
1440 if (vty->status == VTY_MORE)
1441 {
1442 switch (buf[i])
1443 {
1444 case CONTROL('C'):
1445 case 'q':
1446 case 'Q':
paul718e3742002-12-13 20:15:29 +00001447 vty_buffer_reset (vty);
1448 break;
1449#if 0 /* More line does not work for "show ip bgp". */
1450 case '\n':
1451 case '\r':
1452 vty->status = VTY_MORELINE;
1453 break;
1454#endif
1455 default:
paul718e3742002-12-13 20:15:29 +00001456 break;
1457 }
1458 continue;
1459 }
1460
1461 /* Escape character. */
1462 if (vty->escape == VTY_ESCAPE)
1463 {
1464 vty_escape_map (buf[i], vty);
1465 continue;
1466 }
1467
1468 /* Pre-escape status. */
1469 if (vty->escape == VTY_PRE_ESCAPE)
1470 {
1471 switch (buf[i])
1472 {
1473 case '[':
1474 vty->escape = VTY_ESCAPE;
1475 break;
1476 case 'b':
1477 vty_backward_word (vty);
1478 vty->escape = VTY_NORMAL;
1479 break;
1480 case 'f':
1481 vty_forward_word (vty);
1482 vty->escape = VTY_NORMAL;
1483 break;
1484 case 'd':
1485 vty_forward_kill_word (vty);
1486 vty->escape = VTY_NORMAL;
1487 break;
1488 case CONTROL('H'):
1489 case 0x7f:
1490 vty_backward_kill_word (vty);
1491 vty->escape = VTY_NORMAL;
1492 break;
1493 default:
1494 vty->escape = VTY_NORMAL;
1495 break;
1496 }
1497 continue;
1498 }
1499
1500 switch (buf[i])
1501 {
1502 case CONTROL('A'):
1503 vty_beginning_of_line (vty);
1504 break;
1505 case CONTROL('B'):
1506 vty_backward_char (vty);
1507 break;
1508 case CONTROL('C'):
1509 vty_stop_input (vty);
1510 break;
1511 case CONTROL('D'):
1512 vty_delete_char (vty);
1513 break;
1514 case CONTROL('E'):
1515 vty_end_of_line (vty);
1516 break;
1517 case CONTROL('F'):
1518 vty_forward_char (vty);
1519 break;
1520 case CONTROL('H'):
1521 case 0x7f:
1522 vty_delete_backward_char (vty);
1523 break;
1524 case CONTROL('K'):
1525 vty_kill_line (vty);
1526 break;
1527 case CONTROL('N'):
1528 vty_next_line (vty);
1529 break;
1530 case CONTROL('P'):
1531 vty_previous_line (vty);
1532 break;
1533 case CONTROL('T'):
1534 vty_transpose_chars (vty);
1535 break;
1536 case CONTROL('U'):
1537 vty_kill_line_from_beginning (vty);
1538 break;
1539 case CONTROL('W'):
1540 vty_backward_kill_word (vty);
1541 break;
1542 case CONTROL('Z'):
1543 vty_end_config (vty);
1544 break;
1545 case '\n':
1546 case '\r':
1547 vty_out (vty, "%s", VTY_NEWLINE);
1548 vty_execute (vty);
1549 break;
1550 case '\t':
1551 vty_complete_command (vty);
1552 break;
1553 case '?':
1554 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1555 vty_self_insert (vty, buf[i]);
1556 else
1557 vty_describe_command (vty);
1558 break;
1559 case '\033':
1560 if (i + 1 < nbytes && buf[i + 1] == '[')
1561 {
1562 vty->escape = VTY_ESCAPE;
1563 i++;
1564 }
1565 else
1566 vty->escape = VTY_PRE_ESCAPE;
1567 break;
1568 default:
1569 if (buf[i] > 31 && buf[i] < 127)
1570 vty_self_insert (vty, buf[i]);
1571 break;
1572 }
1573 }
1574
1575 /* Check status. */
1576 if (vty->status == VTY_CLOSE)
1577 vty_close (vty);
1578 else
1579 {
David Lamparter4715a532013-05-30 16:31:49 +02001580 vty_event (VTY_WRITE, vty->wfd, vty);
paul718e3742002-12-13 20:15:29 +00001581 vty_event (VTY_READ, vty_sock, vty);
1582 }
1583 return 0;
1584}
1585
1586/* Flush buffer to the vty. */
1587static int
1588vty_flush (struct thread *thread)
1589{
1590 int erase;
ajs9fc7ebf2005-02-23 15:12:34 +00001591 buffer_status_t flushrc;
paul718e3742002-12-13 20:15:29 +00001592 int vty_sock = THREAD_FD (thread);
1593 struct vty *vty = THREAD_ARG (thread);
ajs9fc7ebf2005-02-23 15:12:34 +00001594
paul718e3742002-12-13 20:15:29 +00001595 vty->t_write = NULL;
1596
1597 /* Tempolary disable read thread. */
ajs9fc7ebf2005-02-23 15:12:34 +00001598 if ((vty->lines == 0) && vty->t_read)
1599 {
1600 thread_cancel (vty->t_read);
1601 vty->t_read = NULL;
1602 }
paul718e3742002-12-13 20:15:29 +00001603
1604 /* Function execution continue. */
ajs9fc7ebf2005-02-23 15:12:34 +00001605 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
paul718e3742002-12-13 20:15:29 +00001606
ajs9fc7ebf2005-02-23 15:12:34 +00001607 /* N.B. if width is 0, that means we don't know the window size. */
Lou Bergerc7f7e492016-01-12 13:41:49 -05001608 if ((vty->lines == 0) || (vty->width == 0) || (vty->height == 0))
David Lamparter4715a532013-05-30 16:31:49 +02001609 flushrc = buffer_flush_available(vty->obuf, vty_sock);
ajs9fc7ebf2005-02-23 15:12:34 +00001610 else if (vty->status == VTY_MORELINE)
David Lamparter4715a532013-05-30 16:31:49 +02001611 flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
ajs9fc7ebf2005-02-23 15:12:34 +00001612 1, erase, 0);
1613 else
David Lamparter4715a532013-05-30 16:31:49 +02001614 flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width,
ajs9fc7ebf2005-02-23 15:12:34 +00001615 vty->lines >= 0 ? vty->lines :
1616 vty->height,
1617 erase, 0);
1618 switch (flushrc)
1619 {
1620 case BUFFER_ERROR:
Andrew J. Schorr74542d72006-07-10 18:09:42 +00001621 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +00001622 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1623 vty->fd);
1624 buffer_reset(vty->obuf);
1625 vty_close(vty);
1626 return 0;
1627 case BUFFER_EMPTY:
1628 if (vty->status == VTY_CLOSE)
1629 vty_close (vty);
paul718e3742002-12-13 20:15:29 +00001630 else
1631 {
ajs9fc7ebf2005-02-23 15:12:34 +00001632 vty->status = VTY_NORMAL;
paul718e3742002-12-13 20:15:29 +00001633 if (vty->lines == 0)
ajs9fc7ebf2005-02-23 15:12:34 +00001634 vty_event (VTY_READ, vty_sock, vty);
paul718e3742002-12-13 20:15:29 +00001635 }
ajs9fc7ebf2005-02-23 15:12:34 +00001636 break;
1637 case BUFFER_PENDING:
1638 /* There is more data waiting to be written. */
1639 vty->status = VTY_MORE;
1640 if (vty->lines == 0)
1641 vty_event (VTY_WRITE, vty_sock, vty);
1642 break;
1643 }
paul718e3742002-12-13 20:15:29 +00001644
1645 return 0;
1646}
1647
David Lamparterba5dc5e2013-05-30 16:33:45 +02001648/* allocate and initialise vty */
1649static struct vty *
1650vty_new_init (int vty_sock)
1651{
1652 struct vty *vty;
1653
1654 vty = vty_new ();
1655 vty->fd = vty_sock;
1656 vty->wfd = vty_sock;
1657 vty->type = VTY_TERM;
1658 vty->node = AUTH_NODE;
1659 vty->fail = 0;
1660 vty->cp = 0;
1661 vty_clear_buf (vty);
1662 vty->length = 0;
1663 memset (vty->hist, 0, sizeof (vty->hist));
1664 vty->hp = 0;
1665 vty->hindex = 0;
1666 vector_set_index (vtyvec, vty_sock, vty);
1667 vty->status = VTY_NORMAL;
1668 vty->lines = -1;
1669 vty->iac = 0;
1670 vty->iac_sb_in_progress = 0;
1671 vty->sb_len = 0;
1672
1673 return vty;
1674}
1675
paul718e3742002-12-13 20:15:29 +00001676/* Create new vty structure. */
ajs9fc7ebf2005-02-23 15:12:34 +00001677static struct vty *
paul718e3742002-12-13 20:15:29 +00001678vty_create (int vty_sock, union sockunion *su)
1679{
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001680 char buf[SU_ADDRSTRLEN];
paul718e3742002-12-13 20:15:29 +00001681 struct vty *vty;
1682
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001683 sockunion2str(su, buf, SU_ADDRSTRLEN);
1684
paul718e3742002-12-13 20:15:29 +00001685 /* Allocate new vty structure and set up default values. */
David Lamparterba5dc5e2013-05-30 16:33:45 +02001686 vty = vty_new_init (vty_sock);
1687
1688 /* configurable parameters not part of basic init */
1689 vty->v_timeout = vty_timeout_val;
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001690 strcpy (vty->address, buf);
paul718e3742002-12-13 20:15:29 +00001691 if (no_password_check)
1692 {
Paul Jakma62687ff2008-08-23 14:27:06 +01001693 if (restricted_mode)
1694 vty->node = RESTRICTED_NODE;
1695 else if (host.advanced)
paul718e3742002-12-13 20:15:29 +00001696 vty->node = ENABLE_NODE;
1697 else
1698 vty->node = VIEW_NODE;
1699 }
paul718e3742002-12-13 20:15:29 +00001700 if (host.lines >= 0)
1701 vty->lines = host.lines;
paul718e3742002-12-13 20:15:29 +00001702
1703 if (! no_password_check)
1704 {
1705 /* Vty is not available if password isn't set. */
1706 if (host.password == NULL && host.password_encrypt == NULL)
1707 {
1708 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1709 vty->status = VTY_CLOSE;
1710 vty_close (vty);
1711 return NULL;
1712 }
1713 }
1714
1715 /* Say hello to the world. */
1716 vty_hello (vty);
1717 if (! no_password_check)
1718 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1719
1720 /* Setting up terminal. */
1721 vty_will_echo (vty);
1722 vty_will_suppress_go_ahead (vty);
1723
1724 vty_dont_linemode (vty);
1725 vty_do_window_size (vty);
1726 /* vty_dont_lflow_ahead (vty); */
1727
1728 vty_prompt (vty);
1729
1730 /* Add read/write thread. */
1731 vty_event (VTY_WRITE, vty_sock, vty);
1732 vty_event (VTY_READ, vty_sock, vty);
1733
1734 return vty;
1735}
1736
David Lamparterba5dc5e2013-05-30 16:33:45 +02001737/* create vty for stdio */
David Lamparterba53a8f2015-05-05 11:04:46 +02001738static struct termios stdio_orig_termios;
1739static struct vty *stdio_vty = NULL;
David Lamparter464ccf32015-05-12 21:56:18 +02001740static void (*stdio_vty_atclose)(void);
David Lamparterba53a8f2015-05-05 11:04:46 +02001741
1742static void
1743vty_stdio_reset (void)
1744{
1745 if (stdio_vty)
1746 {
1747 tcsetattr (0, TCSANOW, &stdio_orig_termios);
1748 stdio_vty = NULL;
David Lamparter464ccf32015-05-12 21:56:18 +02001749
1750 if (stdio_vty_atclose)
1751 stdio_vty_atclose ();
1752 stdio_vty_atclose = NULL;
David Lamparterba53a8f2015-05-05 11:04:46 +02001753 }
1754}
1755
David Lamparterba5dc5e2013-05-30 16:33:45 +02001756struct vty *
David Lamparter464ccf32015-05-12 21:56:18 +02001757vty_stdio (void (*atclose)())
David Lamparterba5dc5e2013-05-30 16:33:45 +02001758{
1759 struct vty *vty;
David Lamparterba53a8f2015-05-05 11:04:46 +02001760 struct termios termios;
David Lamparterba5dc5e2013-05-30 16:33:45 +02001761
David Lamparterba53a8f2015-05-05 11:04:46 +02001762 /* refuse creating two vtys on stdio */
1763 if (stdio_vty)
1764 return NULL;
1765
1766 vty = stdio_vty = vty_new_init (0);
David Lamparter464ccf32015-05-12 21:56:18 +02001767 stdio_vty_atclose = atclose;
David Lamparterba5dc5e2013-05-30 16:33:45 +02001768 vty->wfd = 1;
1769
1770 /* always have stdio vty in a known _unchangeable_ state, don't want config
1771 * to have any effect here to make sure scripting this works as intended */
1772 vty->node = ENABLE_NODE;
1773 vty->v_timeout = 0;
1774 strcpy (vty->address, "console");
1775
David Lamparterba53a8f2015-05-05 11:04:46 +02001776 if (!tcgetattr (0, &stdio_orig_termios))
1777 {
1778 termios = stdio_orig_termios;
1779 termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
1780 | INLCR | IGNCR | ICRNL | IXON);
1781 termios.c_oflag &= ~OPOST;
1782 termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
1783 termios.c_cflag &= ~(CSIZE | PARENB);
1784 termios.c_cflag |= CS8;
1785 tcsetattr (0, TCSANOW, &termios);
1786 }
1787
David Lamparterba5dc5e2013-05-30 16:33:45 +02001788 vty_prompt (vty);
1789
1790 /* Add read/write thread. */
1791 vty_event (VTY_WRITE, 1, vty);
1792 vty_event (VTY_READ, 0, vty);
1793
1794 return vty;
1795}
1796
paul718e3742002-12-13 20:15:29 +00001797/* Accept connection from the network. */
1798static int
1799vty_accept (struct thread *thread)
1800{
1801 int vty_sock;
paul718e3742002-12-13 20:15:29 +00001802 union sockunion su;
1803 int ret;
1804 unsigned int on;
1805 int accept_sock;
Timo Teräsc1c69e42015-05-22 13:40:57 +03001806 struct prefix p;
paul718e3742002-12-13 20:15:29 +00001807 struct access_list *acl = NULL;
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001808 char buf[SU_ADDRSTRLEN];
paul718e3742002-12-13 20:15:29 +00001809
1810 accept_sock = THREAD_FD (thread);
1811
1812 /* We continue hearing vty socket. */
1813 vty_event (VTY_SERV, accept_sock, NULL);
1814
1815 memset (&su, 0, sizeof (union sockunion));
1816
1817 /* We can handle IPv4 or IPv6 socket. */
1818 vty_sock = sockunion_accept (accept_sock, &su);
1819 if (vty_sock < 0)
1820 {
ajs6099b3b2004-11-20 02:06:59 +00001821 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001822 return -1;
1823 }
ajs9fc7ebf2005-02-23 15:12:34 +00001824 set_nonblocking(vty_sock);
paul718e3742002-12-13 20:15:29 +00001825
Timo Teräsc1c69e42015-05-22 13:40:57 +03001826 sockunion2hostprefix (&su, &p);
paul718e3742002-12-13 20:15:29 +00001827
1828 /* VTY's accesslist apply. */
Timo Teräsc1c69e42015-05-22 13:40:57 +03001829 if (p.family == AF_INET && vty_accesslist_name)
paul718e3742002-12-13 20:15:29 +00001830 {
1831 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
Timo Teräsc1c69e42015-05-22 13:40:57 +03001832 (access_list_apply (acl, &p) == FILTER_DENY))
paul718e3742002-12-13 20:15:29 +00001833 {
paul718e3742002-12-13 20:15:29 +00001834 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001835 sockunion2str (&su, buf, SU_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +00001836 close (vty_sock);
1837
1838 /* continue accepting connections */
1839 vty_event (VTY_SERV, accept_sock, NULL);
1840
paul718e3742002-12-13 20:15:29 +00001841 return 0;
1842 }
1843 }
1844
1845#ifdef HAVE_IPV6
1846 /* VTY's ipv6 accesslist apply. */
Timo Teräsc1c69e42015-05-22 13:40:57 +03001847 if (p.family == AF_INET6 && vty_ipv6_accesslist_name)
paul718e3742002-12-13 20:15:29 +00001848 {
1849 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
Timo Teräsc1c69e42015-05-22 13:40:57 +03001850 (access_list_apply (acl, &p) == FILTER_DENY))
paul718e3742002-12-13 20:15:29 +00001851 {
paul718e3742002-12-13 20:15:29 +00001852 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001853 sockunion2str (&su, buf, SU_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +00001854 close (vty_sock);
1855
1856 /* continue accepting connections */
1857 vty_event (VTY_SERV, accept_sock, NULL);
1858
paul718e3742002-12-13 20:15:29 +00001859 return 0;
1860 }
1861 }
1862#endif /* HAVE_IPV6 */
1863
paul718e3742002-12-13 20:15:29 +00001864 on = 1;
1865 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1866 (char *) &on, sizeof (on));
1867 if (ret < 0)
1868 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
ajs6099b3b2004-11-20 02:06:59 +00001869 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001870
heasley78e6cd92009-12-07 16:41:14 +03001871 zlog (NULL, LOG_INFO, "Vty connection from %s",
Jorge Boncompte [DTI2]d2276172012-04-10 16:57:23 +02001872 sockunion2str (&su, buf, SU_ADDRSTRLEN));
heasley78e6cd92009-12-07 16:41:14 +03001873
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001874 vty_create (vty_sock, &su);
paul718e3742002-12-13 20:15:29 +00001875
1876 return 0;
1877}
1878
David Lamparter6d6df302014-06-28 21:12:37 +02001879#ifdef HAVE_IPV6
ajs9fc7ebf2005-02-23 15:12:34 +00001880static void
paul718e3742002-12-13 20:15:29 +00001881vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1882{
1883 int ret;
1884 struct addrinfo req;
1885 struct addrinfo *ainfo;
1886 struct addrinfo *ainfo_save;
1887 int sock;
1888 char port_str[BUFSIZ];
1889
1890 memset (&req, 0, sizeof (struct addrinfo));
1891 req.ai_flags = AI_PASSIVE;
1892 req.ai_family = AF_UNSPEC;
1893 req.ai_socktype = SOCK_STREAM;
1894 sprintf (port_str, "%d", port);
1895 port_str[sizeof (port_str) - 1] = '\0';
1896
1897 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1898
1899 if (ret != 0)
1900 {
1901 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1902 exit (1);
1903 }
1904
1905 ainfo_save = ainfo;
1906
1907 do
1908 {
1909 if (ainfo->ai_family != AF_INET
1910#ifdef HAVE_IPV6
1911 && ainfo->ai_family != AF_INET6
1912#endif /* HAVE_IPV6 */
1913 )
1914 continue;
1915
1916 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1917 if (sock < 0)
1918 continue;
1919
David Lamparterca051262009-10-04 16:21:49 +02001920 sockopt_v6only (ainfo->ai_family, sock);
paul718e3742002-12-13 20:15:29 +00001921 sockopt_reuseaddr (sock);
1922 sockopt_reuseport (sock);
1923
1924 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1925 if (ret < 0)
1926 {
1927 close (sock); /* Avoid sd leak. */
1928 continue;
1929 }
1930
1931 ret = listen (sock, 3);
1932 if (ret < 0)
1933 {
1934 close (sock); /* Avoid sd leak. */
1935 continue;
1936 }
1937
1938 vty_event (VTY_SERV, sock, NULL);
1939 }
1940 while ((ainfo = ainfo->ai_next) != NULL);
1941
1942 freeaddrinfo (ainfo_save);
1943}
David Lamparter6d6df302014-06-28 21:12:37 +02001944#else /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001945
1946/* Make vty server socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001947static void
paul29db05b2003-05-08 20:10:22 +00001948vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001949{
1950 int ret;
1951 union sockunion su;
1952 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001953 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001954
1955 memset (&su, 0, sizeof (union sockunion));
1956 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001957 if(addr)
1958 switch(family)
1959 {
1960 case AF_INET:
1961 naddr=&su.sin.sin_addr;
Remi Gacognea11e0122013-09-08 13:48:34 +00001962 break;
paul29db05b2003-05-08 20:10:22 +00001963#ifdef HAVE_IPV6
1964 case AF_INET6:
1965 naddr=&su.sin6.sin6_addr;
Remi Gacognea11e0122013-09-08 13:48:34 +00001966 break;
paul29db05b2003-05-08 20:10:22 +00001967#endif
1968 }
1969
1970 if(naddr)
1971 switch(inet_pton(family,addr,naddr))
1972 {
1973 case -1:
1974 zlog_err("bad address %s",addr);
1975 naddr=NULL;
1976 break;
1977 case 0:
ajs6099b3b2004-11-20 02:06:59 +00001978 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
paul29db05b2003-05-08 20:10:22 +00001979 naddr=NULL;
1980 }
paul718e3742002-12-13 20:15:29 +00001981
1982 /* Make new socket. */
1983 accept_sock = sockunion_stream_socket (&su);
1984 if (accept_sock < 0)
1985 return;
1986
1987 /* This is server, so reuse address. */
1988 sockopt_reuseaddr (accept_sock);
1989 sockopt_reuseport (accept_sock);
1990
1991 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001992 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001993 if (ret < 0)
1994 {
paul29db05b2003-05-08 20:10:22 +00001995 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001996 close (accept_sock); /* Avoid sd leak. */
1997 return;
1998 }
1999
2000 /* Listen socket under queue 3. */
2001 ret = listen (accept_sock, 3);
2002 if (ret < 0)
2003 {
2004 zlog (NULL, LOG_WARNING, "can't listen socket");
2005 close (accept_sock); /* Avoid sd leak. */
2006 return;
2007 }
2008
2009 /* Add vty server event. */
2010 vty_event (VTY_SERV, accept_sock, NULL);
2011}
David Lamparter6d6df302014-06-28 21:12:37 +02002012#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00002013
2014#ifdef VTYSH
2015/* For sockaddr_un. */
2016#include <sys/un.h>
2017
2018/* VTY shell UNIX domain socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00002019static void
hasso6ad96ea2004-10-07 19:33:46 +00002020vty_serv_un (const char *path)
paul718e3742002-12-13 20:15:29 +00002021{
2022 int ret;
paul75e15fe2004-10-31 02:13:09 +00002023 int sock, len;
paul718e3742002-12-13 20:15:29 +00002024 struct sockaddr_un serv;
2025 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00002026 struct zprivs_ids_t ids;
2027
paul718e3742002-12-13 20:15:29 +00002028 /* First of all, unlink existing socket */
2029 unlink (path);
2030
2031 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00002032 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00002033
2034 /* Make UNIX domain socket. */
2035 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2036 if (sock < 0)
2037 {
ajs6a52d0d2005-01-30 18:49:28 +00002038 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00002039 return;
2040 }
2041
2042 /* Make server socket. */
2043 memset (&serv, 0, sizeof (struct sockaddr_un));
2044 serv.sun_family = AF_UNIX;
2045 strncpy (serv.sun_path, path, strlen (path));
Paul Jakma6f0e3f62007-05-10 02:38:51 +00002046#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
paul718e3742002-12-13 20:15:29 +00002047 len = serv.sun_len = SUN_LEN(&serv);
2048#else
2049 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
Paul Jakma6f0e3f62007-05-10 02:38:51 +00002050#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
paul718e3742002-12-13 20:15:29 +00002051
2052 ret = bind (sock, (struct sockaddr *) &serv, len);
2053 if (ret < 0)
2054 {
ajs6a52d0d2005-01-30 18:49:28 +00002055 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00002056 close (sock); /* Avoid sd leak. */
2057 return;
2058 }
2059
2060 ret = listen (sock, 5);
2061 if (ret < 0)
2062 {
ajs6a52d0d2005-01-30 18:49:28 +00002063 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00002064 close (sock); /* Avoid sd leak. */
2065 return;
2066 }
2067
2068 umask (old_mask);
2069
pauledd7c242003-06-04 13:59:38 +00002070 zprivs_get_ids(&ids);
2071
2072 if (ids.gid_vty > 0)
2073 {
2074 /* set group of socket */
2075 if ( chown (path, -1, ids.gid_vty) )
2076 {
2077 zlog_err ("vty_serv_un: could chown socket, %s",
ajs6099b3b2004-11-20 02:06:59 +00002078 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +00002079 }
2080 }
2081
paul718e3742002-12-13 20:15:29 +00002082 vty_event (VTYSH_SERV, sock, NULL);
2083}
2084
2085/* #define VTYSH_DEBUG 1 */
2086
2087static int
2088vtysh_accept (struct thread *thread)
2089{
2090 int accept_sock;
2091 int sock;
2092 int client_len;
2093 struct sockaddr_un client;
2094 struct vty *vty;
2095
2096 accept_sock = THREAD_FD (thread);
2097
2098 vty_event (VTYSH_SERV, accept_sock, NULL);
2099
2100 memset (&client, 0, sizeof (struct sockaddr_un));
2101 client_len = sizeof (struct sockaddr_un);
2102
hassoe473b032004-09-26 16:08:11 +00002103 sock = accept (accept_sock, (struct sockaddr *) &client,
2104 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00002105
2106 if (sock < 0)
2107 {
ajs6099b3b2004-11-20 02:06:59 +00002108 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00002109 return -1;
2110 }
2111
ajs9fc7ebf2005-02-23 15:12:34 +00002112 if (set_nonblocking(sock) < 0)
paul75e15fe2004-10-31 02:13:09 +00002113 {
ajs9fc7ebf2005-02-23 15:12:34 +00002114 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
2115 " %s, closing", sock, safe_strerror (errno));
paul75e15fe2004-10-31 02:13:09 +00002116 close (sock);
2117 return -1;
2118 }
pauldccfb192004-10-29 08:29:36 +00002119
paul718e3742002-12-13 20:15:29 +00002120#ifdef VTYSH_DEBUG
2121 printf ("VTY shell accept\n");
2122#endif /* VTYSH_DEBUG */
2123
2124 vty = vty_new ();
2125 vty->fd = sock;
David Lamparter4715a532013-05-30 16:31:49 +02002126 vty->wfd = sock;
paul718e3742002-12-13 20:15:29 +00002127 vty->type = VTY_SHELL_SERV;
2128 vty->node = VIEW_NODE;
2129
2130 vty_event (VTYSH_READ, sock, vty);
2131
2132 return 0;
2133}
2134
2135static int
ajs9fc7ebf2005-02-23 15:12:34 +00002136vtysh_flush(struct vty *vty)
2137{
David Lamparter4715a532013-05-30 16:31:49 +02002138 switch (buffer_flush_available(vty->obuf, vty->wfd))
ajs9fc7ebf2005-02-23 15:12:34 +00002139 {
2140 case BUFFER_PENDING:
David Lamparter4715a532013-05-30 16:31:49 +02002141 vty_event(VTYSH_WRITE, vty->wfd, vty);
ajs9fc7ebf2005-02-23 15:12:34 +00002142 break;
2143 case BUFFER_ERROR:
Andrew J. Schorr74542d72006-07-10 18:09:42 +00002144 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +00002145 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
2146 buffer_reset(vty->obuf);
2147 vty_close(vty);
2148 return -1;
2149 break;
2150 case BUFFER_EMPTY:
2151 break;
2152 }
2153 return 0;
2154}
2155
2156static int
paul718e3742002-12-13 20:15:29 +00002157vtysh_read (struct thread *thread)
2158{
2159 int ret;
2160 int sock;
2161 int nbytes;
2162 struct vty *vty;
2163 unsigned char buf[VTY_READ_BUFSIZ];
ajs9fc7ebf2005-02-23 15:12:34 +00002164 unsigned char *p;
paul718e3742002-12-13 20:15:29 +00002165 u_char header[4] = {0, 0, 0, 0};
2166
2167 sock = THREAD_FD (thread);
2168 vty = THREAD_ARG (thread);
2169 vty->t_read = NULL;
2170
ajs9fc7ebf2005-02-23 15:12:34 +00002171 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
paul718e3742002-12-13 20:15:29 +00002172 {
ajs9fc7ebf2005-02-23 15:12:34 +00002173 if (nbytes < 0)
2174 {
2175 if (ERRNO_IO_RETRY(errno))
2176 {
2177 vty_event (VTYSH_READ, sock, vty);
2178 return 0;
2179 }
Andrew J. Schorr74542d72006-07-10 18:09:42 +00002180 vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
ajs9fc7ebf2005-02-23 15:12:34 +00002181 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2182 __func__, sock, safe_strerror(errno));
2183 }
2184 buffer_reset(vty->obuf);
paul718e3742002-12-13 20:15:29 +00002185 vty_close (vty);
2186#ifdef VTYSH_DEBUG
2187 printf ("close vtysh\n");
2188#endif /* VTYSH_DEBUG */
2189 return 0;
2190 }
2191
2192#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002193 printf ("line: %.*s\n", nbytes, buf);
paul718e3742002-12-13 20:15:29 +00002194#endif /* VTYSH_DEBUG */
2195
ajs9fc7ebf2005-02-23 15:12:34 +00002196 for (p = buf; p < buf+nbytes; p++)
2197 {
2198 vty_ensure(vty, vty->length+1);
2199 vty->buf[vty->length++] = *p;
2200 if (*p == '\0')
2201 {
2202 /* Pass this line to parser. */
2203 ret = vty_execute (vty);
2204 /* Note that vty_execute clears the command buffer and resets
2205 vty->length to 0. */
paul718e3742002-12-13 20:15:29 +00002206
ajs9fc7ebf2005-02-23 15:12:34 +00002207 /* Return result. */
paul718e3742002-12-13 20:15:29 +00002208#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002209 printf ("result: %d\n", ret);
2210 printf ("vtysh node: %d\n", vty->node);
paul718e3742002-12-13 20:15:29 +00002211#endif /* VTYSH_DEBUG */
2212
ajs9fc7ebf2005-02-23 15:12:34 +00002213 header[3] = ret;
2214 buffer_put(vty->obuf, header, 4);
paul718e3742002-12-13 20:15:29 +00002215
ajs9fc7ebf2005-02-23 15:12:34 +00002216 if (!vty->t_write && (vtysh_flush(vty) < 0))
2217 /* Try to flush results; exit if a write error occurs. */
2218 return 0;
2219 }
2220 }
2221
paul718e3742002-12-13 20:15:29 +00002222 vty_event (VTYSH_READ, sock, vty);
2223
2224 return 0;
2225}
ajs49ff6d92004-11-04 19:26:16 +00002226
2227static int
2228vtysh_write (struct thread *thread)
2229{
2230 struct vty *vty = THREAD_ARG (thread);
2231
2232 vty->t_write = NULL;
ajs9fc7ebf2005-02-23 15:12:34 +00002233 vtysh_flush(vty);
ajs976d8c72004-11-10 15:40:09 +00002234 return 0;
ajs49ff6d92004-11-04 19:26:16 +00002235}
2236
paul718e3742002-12-13 20:15:29 +00002237#endif /* VTYSH */
2238
2239/* Determine address family to bind. */
2240void
hasso6ad96ea2004-10-07 19:33:46 +00002241vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002242{
2243 /* If port is set to 0, do not listen on TCP/IP at all! */
2244 if (port)
2245 {
2246
2247#ifdef HAVE_IPV6
paul29db05b2003-05-08 20:10:22 +00002248 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002249#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002250 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002251#endif /* HAVE_IPV6 */
2252 }
2253
2254#ifdef VTYSH
2255 vty_serv_un (path);
2256#endif /* VTYSH */
2257}
2258
Andrew J. Schorr9d0a3262006-07-11 00:06:49 +00002259/* Close vty interface. Warning: call this only from functions that
2260 will be careful not to access the vty afterwards (since it has
2261 now been freed). This is safest from top-level functions (called
2262 directly by the thread dispatcher). */
paul718e3742002-12-13 20:15:29 +00002263void
2264vty_close (struct vty *vty)
2265{
2266 int i;
2267
2268 /* Cancel threads.*/
2269 if (vty->t_read)
2270 thread_cancel (vty->t_read);
2271 if (vty->t_write)
2272 thread_cancel (vty->t_write);
2273 if (vty->t_timeout)
2274 thread_cancel (vty->t_timeout);
paul718e3742002-12-13 20:15:29 +00002275
2276 /* Flush buffer. */
David Lamparter4715a532013-05-30 16:31:49 +02002277 buffer_flush_all (vty->obuf, vty->wfd);
paul718e3742002-12-13 20:15:29 +00002278
2279 /* Free input buffer. */
2280 buffer_free (vty->obuf);
2281
paul718e3742002-12-13 20:15:29 +00002282 /* Free command history. */
2283 for (i = 0; i < VTY_MAXHIST; i++)
2284 if (vty->hist[i])
2285 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2286
2287 /* Unset vector. */
2288 vector_unset (vtyvec, vty->fd);
2289
2290 /* Close socket. */
2291 if (vty->fd > 0)
2292 close (vty->fd);
David Lamparterba53a8f2015-05-05 11:04:46 +02002293 else
2294 vty_stdio_reset ();
paul718e3742002-12-13 20:15:29 +00002295
paul718e3742002-12-13 20:15:29 +00002296 if (vty->buf)
2297 XFREE (MTYPE_VTY, vty->buf);
2298
2299 /* Check configure. */
2300 vty_config_unlock (vty);
2301
2302 /* OK free vty. */
2303 XFREE (MTYPE_VTY, vty);
2304}
2305
2306/* When time out occur output message then close connection. */
2307static int
2308vty_timeout (struct thread *thread)
2309{
2310 struct vty *vty;
2311
2312 vty = THREAD_ARG (thread);
2313 vty->t_timeout = NULL;
2314 vty->v_timeout = 0;
2315
2316 /* Clear buffer*/
2317 buffer_reset (vty->obuf);
2318 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2319
2320 /* Close connection. */
2321 vty->status = VTY_CLOSE;
2322 vty_close (vty);
2323
2324 return 0;
2325}
2326
2327/* Read up configuration file from file_name. */
2328static void
2329vty_read_file (FILE *confp)
2330{
2331 int ret;
2332 struct vty *vty;
Steve Hillea555002009-07-28 16:36:14 -04002333 unsigned int line_num = 0;
paul718e3742002-12-13 20:15:29 +00002334
2335 vty = vty_new ();
David Lamparter4715a532013-05-30 16:31:49 +02002336 vty->wfd = dup(STDERR_FILENO); /* vty_close() will close this */
2337 if (vty->wfd < 0)
Steve Hillea555002009-07-28 16:36:14 -04002338 {
2339 /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */
David Lamparter4715a532013-05-30 16:31:49 +02002340 vty->wfd = STDOUT_FILENO;
Steve Hillea555002009-07-28 16:36:14 -04002341 }
David Lamparter4715a532013-05-30 16:31:49 +02002342 vty->fd = STDIN_FILENO;
Steve Hillea555002009-07-28 16:36:14 -04002343 vty->type = VTY_FILE;
paul718e3742002-12-13 20:15:29 +00002344 vty->node = CONFIG_NODE;
2345
2346 /* Execute configuration file */
Steve Hillea555002009-07-28 16:36:14 -04002347 ret = config_from_file (vty, confp, &line_num);
2348
2349 /* Flush any previous errors before printing messages below */
2350 buffer_flush_all (vty->obuf, vty->fd);
paul718e3742002-12-13 20:15:29 +00002351
paul7021c422003-07-15 12:52:22 +00002352 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002353 {
2354 switch (ret)
paul7021c422003-07-15 12:52:22 +00002355 {
2356 case CMD_ERR_AMBIGUOUS:
Steve Hillea555002009-07-28 16:36:14 -04002357 fprintf (stderr, "*** Error reading config: Ambiguous command.\n");
paul7021c422003-07-15 12:52:22 +00002358 break;
2359 case CMD_ERR_NO_MATCH:
Steve Hillea555002009-07-28 16:36:14 -04002360 fprintf (stderr, "*** Error reading config: There is no such command.\n");
paul7021c422003-07-15 12:52:22 +00002361 break;
2362 }
Steve Hillea555002009-07-28 16:36:14 -04002363 fprintf (stderr, "*** Error occured processing line %u, below:\n%s\n",
2364 line_num, vty->buf);
paul718e3742002-12-13 20:15:29 +00002365 vty_close (vty);
2366 exit (1);
2367 }
2368
2369 vty_close (vty);
2370}
2371
ajs9fc7ebf2005-02-23 15:12:34 +00002372static FILE *
paul718e3742002-12-13 20:15:29 +00002373vty_use_backup_config (char *fullpath)
2374{
2375 char *fullpath_sav, *fullpath_tmp;
2376 FILE *ret = NULL;
2377 struct stat buf;
2378 int tmp, sav;
2379 int c;
2380 char buffer[512];
2381
2382 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2383 strcpy (fullpath_sav, fullpath);
2384 strcat (fullpath_sav, CONF_BACKUP_EXT);
2385 if (stat (fullpath_sav, &buf) == -1)
2386 {
2387 free (fullpath_sav);
2388 return NULL;
2389 }
2390
2391 fullpath_tmp = malloc (strlen (fullpath) + 8);
2392 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2393
2394 /* Open file to configuration write. */
2395 tmp = mkstemp (fullpath_tmp);
2396 if (tmp < 0)
2397 {
2398 free (fullpath_sav);
2399 free (fullpath_tmp);
2400 return NULL;
2401 }
2402
2403 sav = open (fullpath_sav, O_RDONLY);
2404 if (sav < 0)
2405 {
gdt3dbf9962003-12-22 20:18:18 +00002406 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002407 free (fullpath_sav);
2408 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002409 return NULL;
2410 }
2411
2412 while((c = read (sav, buffer, 512)) > 0)
2413 write (tmp, buffer, c);
2414
2415 close (sav);
2416 close (tmp);
2417
gdtaa593d52003-12-22 20:15:53 +00002418 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2419 {
gdt3dbf9962003-12-22 20:18:18 +00002420 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002421 free (fullpath_sav);
2422 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002423 return NULL;
2424 }
2425
paul718e3742002-12-13 20:15:29 +00002426 if (link (fullpath_tmp, fullpath) == 0)
2427 ret = fopen (fullpath, "r");
2428
2429 unlink (fullpath_tmp);
2430
2431 free (fullpath_sav);
2432 free (fullpath_tmp);
hasso12f6ea22005-03-07 08:35:39 +00002433 return ret;
paul718e3742002-12-13 20:15:29 +00002434}
2435
2436/* Read up configuration file from file_name. */
2437void
2438vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002439 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002440{
paulccc92352003-10-22 02:49:38 +00002441 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002442 FILE *confp = NULL;
2443 char *fullpath;
paul05865c92005-10-26 05:49:54 +00002444 char *tmp = NULL;
paul718e3742002-12-13 20:15:29 +00002445
2446 /* If -f flag specified. */
2447 if (config_file != NULL)
2448 {
2449 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002450 {
2451 getcwd (cwd, MAXPATHLEN);
paul05865c92005-10-26 05:49:54 +00002452 tmp = XMALLOC (MTYPE_TMP,
hasso320ec102004-06-20 19:54:37 +00002453 strlen (cwd) + strlen (config_file) + 2);
paul05865c92005-10-26 05:49:54 +00002454 sprintf (tmp, "%s/%s", cwd, config_file);
2455 fullpath = tmp;
hasso320ec102004-06-20 19:54:37 +00002456 }
paul718e3742002-12-13 20:15:29 +00002457 else
hasso320ec102004-06-20 19:54:37 +00002458 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002459
2460 confp = fopen (fullpath, "r");
2461
2462 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002463 {
paul3d1dc852005-04-05 00:45:23 +00002464 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2465 __func__, fullpath, safe_strerror (errno));
2466
hasso320ec102004-06-20 19:54:37 +00002467 confp = vty_use_backup_config (fullpath);
2468 if (confp)
2469 fprintf (stderr, "WARNING: using backup configuration file!\n");
2470 else
2471 {
2472 fprintf (stderr, "can't open configuration file [%s]\n",
paul3d1dc852005-04-05 00:45:23 +00002473 config_file);
hasso320ec102004-06-20 19:54:37 +00002474 exit(1);
2475 }
2476 }
paul718e3742002-12-13 20:15:29 +00002477 }
2478 else
2479 {
paul718e3742002-12-13 20:15:29 +00002480#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002481 int ret;
2482 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002483
hasso320ec102004-06-20 19:54:37 +00002484 /* !!!!PLEASE LEAVE!!!!
2485 * This is NEEDED for use with vtysh -b, or else you can get
2486 * a real configuration food fight with a lot garbage in the
2487 * merged configuration file it creates coming from the per
2488 * daemon configuration files. This also allows the daemons
2489 * to start if there default configuration file is not
2490 * present or ignore them, as needed when using vtysh -b to
2491 * configure the daemons at boot - MAG
2492 */
paul718e3742002-12-13 20:15:29 +00002493
hasso320ec102004-06-20 19:54:37 +00002494 /* Stat for vtysh Zebra.conf, if found startup and wait for
2495 * boot configuration
2496 */
paul718e3742002-12-13 20:15:29 +00002497
hasso320ec102004-06-20 19:54:37 +00002498 if ( strstr(config_default_dir, "vtysh") == NULL)
2499 {
2500 ret = stat (integrate_default, &conf_stat);
2501 if (ret >= 0)
2502 return;
2503 }
paul718e3742002-12-13 20:15:29 +00002504#endif /* VTYSH */
2505
hasso320ec102004-06-20 19:54:37 +00002506 confp = fopen (config_default_dir, "r");
2507 if (confp == NULL)
2508 {
paul3d1dc852005-04-05 00:45:23 +00002509 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2510 __func__, config_default_dir, safe_strerror (errno));
2511
hasso320ec102004-06-20 19:54:37 +00002512 confp = vty_use_backup_config (config_default_dir);
2513 if (confp)
2514 {
2515 fprintf (stderr, "WARNING: using backup configuration file!\n");
2516 fullpath = config_default_dir;
2517 }
2518 else
2519 {
2520 fprintf (stderr, "can't open configuration file [%s]\n",
2521 config_default_dir);
2522 exit (1);
paul3d1dc852005-04-05 00:45:23 +00002523 }
hasso320ec102004-06-20 19:54:37 +00002524 }
paul718e3742002-12-13 20:15:29 +00002525 else
hasso320ec102004-06-20 19:54:37 +00002526 fullpath = config_default_dir;
2527 }
2528
paul718e3742002-12-13 20:15:29 +00002529 vty_read_file (confp);
2530
2531 fclose (confp);
2532
2533 host_config_set (fullpath);
paul05865c92005-10-26 05:49:54 +00002534
2535 if (tmp)
2536 XFREE (MTYPE_TMP, fullpath);
paul718e3742002-12-13 20:15:29 +00002537}
2538
2539/* Small utility function which output log to the VTY. */
2540void
ajs274a4a42004-12-07 15:39:31 +00002541vty_log (const char *level, const char *proto_str,
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00002542 const char *format, struct timestamp_control *ctl, va_list va)
paul718e3742002-12-13 20:15:29 +00002543{
hasso8c328f12004-10-05 21:01:23 +00002544 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002545 struct vty *vty;
Paul Jakmaa4b30302006-05-28 08:18:38 +00002546
2547 if (!vtyvec)
2548 return;
paul718e3742002-12-13 20:15:29 +00002549
paul55468c82005-03-14 20:19:01 +00002550 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002551 if ((vty = vector_slot (vtyvec, i)) != NULL)
2552 if (vty->monitor)
ajsd246bd92004-11-23 17:35:08 +00002553 {
2554 va_list ac;
2555 va_copy(ac, va);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00002556 vty_log_out (vty, level, proto_str, format, ctl, ac);
ajsd246bd92004-11-23 17:35:08 +00002557 va_end(ac);
2558 }
paul718e3742002-12-13 20:15:29 +00002559}
2560
ajs274a4a42004-12-07 15:39:31 +00002561/* Async-signal-safe version of vty_log for fixed strings. */
2562void
Paul Jakma7aa9dce2014-09-19 14:42:23 +01002563vty_log_fixed (char *buf, size_t len)
ajs274a4a42004-12-07 15:39:31 +00002564{
2565 unsigned int i;
ajs9fc7ebf2005-02-23 15:12:34 +00002566 struct iovec iov[2];
2567
Paul Jakmaa4b30302006-05-28 08:18:38 +00002568 /* vty may not have been initialised */
2569 if (!vtyvec)
2570 return;
2571
Paul Jakma7aa9dce2014-09-19 14:42:23 +01002572 iov[0].iov_base = buf;
ajs9fc7ebf2005-02-23 15:12:34 +00002573 iov[0].iov_len = len;
ajs926fe8f2005-04-08 18:50:40 +00002574 iov[1].iov_base = (void *)"\r\n";
ajs9fc7ebf2005-02-23 15:12:34 +00002575 iov[1].iov_len = 2;
ajs274a4a42004-12-07 15:39:31 +00002576
paul55468c82005-03-14 20:19:01 +00002577 for (i = 0; i < vector_active (vtyvec); i++)
ajs274a4a42004-12-07 15:39:31 +00002578 {
2579 struct vty *vty;
ajs9fc7ebf2005-02-23 15:12:34 +00002580 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2581 /* N.B. We don't care about the return code, since process is
2582 most likely just about to die anyway. */
David Lamparter4715a532013-05-30 16:31:49 +02002583 writev(vty->wfd, iov, 2);
ajs274a4a42004-12-07 15:39:31 +00002584 }
2585}
2586
paul718e3742002-12-13 20:15:29 +00002587int
2588vty_config_lock (struct vty *vty)
2589{
2590 if (vty_config == 0)
2591 {
2592 vty->config = 1;
2593 vty_config = 1;
2594 }
2595 return vty->config;
2596}
2597
2598int
2599vty_config_unlock (struct vty *vty)
2600{
2601 if (vty_config == 1 && vty->config == 1)
2602 {
2603 vty->config = 0;
2604 vty_config = 0;
2605 }
2606 return vty->config;
2607}
David Lamparter6b0655a2014-06-04 06:53:35 +02002608
paul718e3742002-12-13 20:15:29 +00002609/* Master of the threads. */
Donald Sharpeeef0db2015-10-14 08:50:38 -04002610static struct thread_master *vty_master;
paul718e3742002-12-13 20:15:29 +00002611
2612static void
2613vty_event (enum event event, int sock, struct vty *vty)
2614{
2615 struct thread *vty_serv_thread;
2616
2617 switch (event)
2618 {
2619 case VTY_SERV:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002620 vty_serv_thread = thread_add_read (vty_master, vty_accept, vty, sock);
paul718e3742002-12-13 20:15:29 +00002621 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2622 break;
2623#ifdef VTYSH
2624 case VTYSH_SERV:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002625 vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock);
Christian Franke677bcbb2013-02-27 13:47:23 +00002626 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
paul718e3742002-12-13 20:15:29 +00002627 break;
2628 case VTYSH_READ:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002629 vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock);
ajs49ff6d92004-11-04 19:26:16 +00002630 break;
2631 case VTYSH_WRITE:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002632 vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock);
paul718e3742002-12-13 20:15:29 +00002633 break;
2634#endif /* VTYSH */
2635 case VTY_READ:
Donald Sharpeeef0db2015-10-14 08:50:38 -04002636 vty->t_read = thread_add_read (vty_master, vty_read, vty, sock);
paul718e3742002-12-13 20:15:29 +00002637
2638 /* Time out treatment. */
2639 if (vty->v_timeout)
2640 {
2641 if (vty->t_timeout)
2642 thread_cancel (vty->t_timeout);
2643 vty->t_timeout =
Donald Sharpeeef0db2015-10-14 08:50:38 -04002644 thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
paul718e3742002-12-13 20:15:29 +00002645 }
2646 break;
2647 case VTY_WRITE:
2648 if (! vty->t_write)
Donald Sharpeeef0db2015-10-14 08:50:38 -04002649 vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock);
paul718e3742002-12-13 20:15:29 +00002650 break;
2651 case VTY_TIMEOUT_RESET:
2652 if (vty->t_timeout)
2653 {
2654 thread_cancel (vty->t_timeout);
2655 vty->t_timeout = NULL;
2656 }
2657 if (vty->v_timeout)
2658 {
2659 vty->t_timeout =
Donald Sharpeeef0db2015-10-14 08:50:38 -04002660 thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
paul718e3742002-12-13 20:15:29 +00002661 }
2662 break;
2663 }
2664}
David Lamparter6b0655a2014-06-04 06:53:35 +02002665
paul718e3742002-12-13 20:15:29 +00002666DEFUN (config_who,
2667 config_who_cmd,
2668 "who",
2669 "Display who is on vty\n")
2670{
hasso8c328f12004-10-05 21:01:23 +00002671 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002672 struct vty *v;
2673
paul55468c82005-03-14 20:19:01 +00002674 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002675 if ((v = vector_slot (vtyvec, i)) != NULL)
2676 vty_out (vty, "%svty[%d] connected from %s.%s",
2677 v->config ? "*" : " ",
2678 i, v->address, VTY_NEWLINE);
2679 return CMD_SUCCESS;
2680}
2681
2682/* Move to vty configuration mode. */
2683DEFUN (line_vty,
2684 line_vty_cmd,
2685 "line vty",
2686 "Configure a terminal line\n"
2687 "Virtual terminal\n")
2688{
2689 vty->node = VTY_NODE;
2690 return CMD_SUCCESS;
2691}
2692
2693/* Set time out value. */
ajs9fc7ebf2005-02-23 15:12:34 +00002694static int
paul9035efa2004-10-10 11:56:56 +00002695exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002696{
2697 unsigned long timeout = 0;
2698
2699 /* min_str and sec_str are already checked by parser. So it must be
2700 all digit string. */
2701 if (min_str)
2702 {
2703 timeout = strtol (min_str, NULL, 10);
2704 timeout *= 60;
2705 }
2706 if (sec_str)
2707 timeout += strtol (sec_str, NULL, 10);
2708
2709 vty_timeout_val = timeout;
2710 vty->v_timeout = timeout;
2711 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2712
2713
2714 return CMD_SUCCESS;
2715}
2716
2717DEFUN (exec_timeout_min,
2718 exec_timeout_min_cmd,
2719 "exec-timeout <0-35791>",
2720 "Set timeout value\n"
2721 "Timeout value in minutes\n")
2722{
2723 return exec_timeout (vty, argv[0], NULL);
2724}
2725
2726DEFUN (exec_timeout_sec,
2727 exec_timeout_sec_cmd,
2728 "exec-timeout <0-35791> <0-2147483>",
2729 "Set the EXEC timeout\n"
2730 "Timeout in minutes\n"
2731 "Timeout in seconds\n")
2732{
2733 return exec_timeout (vty, argv[0], argv[1]);
2734}
2735
2736DEFUN (no_exec_timeout,
2737 no_exec_timeout_cmd,
2738 "no exec-timeout",
2739 NO_STR
2740 "Set the EXEC timeout\n")
2741{
2742 return exec_timeout (vty, NULL, NULL);
2743}
2744
2745/* Set vty access class. */
2746DEFUN (vty_access_class,
2747 vty_access_class_cmd,
2748 "access-class WORD",
2749 "Filter connections based on an IP access list\n"
2750 "IP access list\n")
2751{
2752 if (vty_accesslist_name)
2753 XFREE(MTYPE_VTY, vty_accesslist_name);
2754
2755 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2756
2757 return CMD_SUCCESS;
2758}
2759
2760/* Clear vty access class. */
2761DEFUN (no_vty_access_class,
2762 no_vty_access_class_cmd,
2763 "no access-class [WORD]",
2764 NO_STR
2765 "Filter connections based on an IP access list\n"
2766 "IP access list\n")
2767{
2768 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2769 {
2770 vty_out (vty, "Access-class is not currently applied to vty%s",
2771 VTY_NEWLINE);
2772 return CMD_WARNING;
2773 }
2774
2775 XFREE(MTYPE_VTY, vty_accesslist_name);
2776
2777 vty_accesslist_name = NULL;
2778
2779 return CMD_SUCCESS;
2780}
2781
2782#ifdef HAVE_IPV6
2783/* Set vty access class. */
2784DEFUN (vty_ipv6_access_class,
2785 vty_ipv6_access_class_cmd,
2786 "ipv6 access-class WORD",
2787 IPV6_STR
2788 "Filter connections based on an IP access list\n"
2789 "IPv6 access list\n")
2790{
2791 if (vty_ipv6_accesslist_name)
2792 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2793
2794 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2795
2796 return CMD_SUCCESS;
2797}
2798
2799/* Clear vty access class. */
2800DEFUN (no_vty_ipv6_access_class,
2801 no_vty_ipv6_access_class_cmd,
2802 "no ipv6 access-class [WORD]",
2803 NO_STR
2804 IPV6_STR
2805 "Filter connections based on an IP access list\n"
2806 "IPv6 access list\n")
2807{
2808 if (! vty_ipv6_accesslist_name ||
2809 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2810 {
2811 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2812 VTY_NEWLINE);
2813 return CMD_WARNING;
2814 }
2815
2816 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2817
2818 vty_ipv6_accesslist_name = NULL;
2819
2820 return CMD_SUCCESS;
2821}
2822#endif /* HAVE_IPV6 */
2823
2824/* vty login. */
2825DEFUN (vty_login,
2826 vty_login_cmd,
2827 "login",
2828 "Enable password checking\n")
2829{
2830 no_password_check = 0;
2831 return CMD_SUCCESS;
2832}
2833
2834DEFUN (no_vty_login,
2835 no_vty_login_cmd,
2836 "no login",
2837 NO_STR
2838 "Enable password checking\n")
2839{
2840 no_password_check = 1;
2841 return CMD_SUCCESS;
2842}
2843
Paul Jakma62687ff2008-08-23 14:27:06 +01002844/* initial mode. */
2845DEFUN (vty_restricted_mode,
2846 vty_restricted_mode_cmd,
2847 "anonymous restricted",
2848 "Restrict view commands available in anonymous, unauthenticated vty\n")
2849{
2850 restricted_mode = 1;
2851 return CMD_SUCCESS;
2852}
2853
2854DEFUN (vty_no_restricted_mode,
2855 vty_no_restricted_mode_cmd,
2856 "no anonymous restricted",
2857 NO_STR
2858 "Enable password checking\n")
2859{
2860 restricted_mode = 0;
2861 return CMD_SUCCESS;
2862}
2863
paul718e3742002-12-13 20:15:29 +00002864DEFUN (service_advanced_vty,
2865 service_advanced_vty_cmd,
2866 "service advanced-vty",
2867 "Set up miscellaneous service\n"
2868 "Enable advanced mode vty interface\n")
2869{
2870 host.advanced = 1;
2871 return CMD_SUCCESS;
2872}
2873
2874DEFUN (no_service_advanced_vty,
2875 no_service_advanced_vty_cmd,
2876 "no service advanced-vty",
2877 NO_STR
2878 "Set up miscellaneous service\n"
2879 "Enable advanced mode vty interface\n")
2880{
2881 host.advanced = 0;
2882 return CMD_SUCCESS;
2883}
2884
2885DEFUN (terminal_monitor,
2886 terminal_monitor_cmd,
2887 "terminal monitor",
2888 "Set terminal line parameters\n"
2889 "Copy debug output to the current terminal line\n")
2890{
2891 vty->monitor = 1;
2892 return CMD_SUCCESS;
2893}
2894
2895DEFUN (terminal_no_monitor,
2896 terminal_no_monitor_cmd,
2897 "terminal no monitor",
2898 "Set terminal line parameters\n"
2899 NO_STR
2900 "Copy debug output to the current terminal line\n")
2901{
2902 vty->monitor = 0;
2903 return CMD_SUCCESS;
2904}
2905
paul789f78a2006-01-17 17:42:03 +00002906ALIAS (terminal_no_monitor,
2907 no_terminal_monitor_cmd,
2908 "no terminal monitor",
2909 NO_STR
2910 "Set terminal line parameters\n"
2911 "Copy debug output to the current terminal line\n")
2912
paul718e3742002-12-13 20:15:29 +00002913DEFUN (show_history,
2914 show_history_cmd,
2915 "show history",
2916 SHOW_STR
2917 "Display the session command history\n")
2918{
2919 int index;
2920
2921 for (index = vty->hindex + 1; index != vty->hindex;)
2922 {
2923 if (index == VTY_MAXHIST)
2924 {
2925 index = 0;
2926 continue;
2927 }
2928
2929 if (vty->hist[index] != NULL)
2930 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2931
2932 index++;
2933 }
2934
2935 return CMD_SUCCESS;
2936}
2937
2938/* Display current configuration. */
ajs9fc7ebf2005-02-23 15:12:34 +00002939static int
paul718e3742002-12-13 20:15:29 +00002940vty_config_write (struct vty *vty)
2941{
2942 vty_out (vty, "line vty%s", VTY_NEWLINE);
2943
2944 if (vty_accesslist_name)
2945 vty_out (vty, " access-class %s%s",
2946 vty_accesslist_name, VTY_NEWLINE);
2947
2948 if (vty_ipv6_accesslist_name)
2949 vty_out (vty, " ipv6 access-class %s%s",
2950 vty_ipv6_accesslist_name, VTY_NEWLINE);
2951
2952 /* exec-timeout */
2953 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2954 vty_out (vty, " exec-timeout %ld %ld%s",
2955 vty_timeout_val / 60,
2956 vty_timeout_val % 60, VTY_NEWLINE);
2957
2958 /* login */
2959 if (no_password_check)
2960 vty_out (vty, " no login%s", VTY_NEWLINE);
Paul Jakma62687ff2008-08-23 14:27:06 +01002961
2962 if (restricted_mode != restricted_mode_default)
2963 {
2964 if (restricted_mode_default)
2965 vty_out (vty, " no anonymous restricted%s", VTY_NEWLINE);
2966 else
2967 vty_out (vty, " anonymous restricted%s", VTY_NEWLINE);
2968 }
2969
paul718e3742002-12-13 20:15:29 +00002970 vty_out (vty, "!%s", VTY_NEWLINE);
2971
2972 return CMD_SUCCESS;
2973}
2974
2975struct cmd_node vty_node =
2976{
2977 VTY_NODE,
2978 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00002979 1,
paul718e3742002-12-13 20:15:29 +00002980};
2981
2982/* Reset all VTY status. */
2983void
2984vty_reset ()
2985{
hasso8c328f12004-10-05 21:01:23 +00002986 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002987 struct vty *vty;
2988 struct thread *vty_serv_thread;
2989
paul55468c82005-03-14 20:19:01 +00002990 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002991 if ((vty = vector_slot (vtyvec, i)) != NULL)
2992 {
2993 buffer_reset (vty->obuf);
2994 vty->status = VTY_CLOSE;
2995 vty_close (vty);
2996 }
2997
paul55468c82005-03-14 20:19:01 +00002998 for (i = 0; i < vector_active (Vvty_serv_thread); i++)
paul718e3742002-12-13 20:15:29 +00002999 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
3000 {
3001 thread_cancel (vty_serv_thread);
3002 vector_slot (Vvty_serv_thread, i) = NULL;
3003 close (i);
3004 }
3005
3006 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
3007
3008 if (vty_accesslist_name)
3009 {
3010 XFREE(MTYPE_VTY, vty_accesslist_name);
3011 vty_accesslist_name = NULL;
3012 }
3013
3014 if (vty_ipv6_accesslist_name)
3015 {
3016 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
3017 vty_ipv6_accesslist_name = NULL;
3018 }
3019}
3020
ajs9fc7ebf2005-02-23 15:12:34 +00003021static void
3022vty_save_cwd (void)
paul718e3742002-12-13 20:15:29 +00003023{
paul79ad2792003-10-15 22:09:28 +00003024 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00003025 char *c;
paul718e3742002-12-13 20:15:29 +00003026
paulccc92352003-10-22 02:49:38 +00003027 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00003028
paulccc92352003-10-22 02:49:38 +00003029 if (!c)
paul79ad2792003-10-15 22:09:28 +00003030 {
3031 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00003032 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00003033 }
paul718e3742002-12-13 20:15:29 +00003034
3035 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
3036 strcpy (vty_cwd, cwd);
3037}
3038
3039char *
3040vty_get_cwd ()
3041{
3042 return vty_cwd;
3043}
3044
3045int
3046vty_shell (struct vty *vty)
3047{
3048 return vty->type == VTY_SHELL ? 1 : 0;
3049}
3050
3051int
3052vty_shell_serv (struct vty *vty)
3053{
3054 return vty->type == VTY_SHELL_SERV ? 1 : 0;
3055}
3056
3057void
3058vty_init_vtysh ()
3059{
3060 vtyvec = vector_init (VECTOR_MIN_SIZE);
3061}
3062
3063/* Install vty's own commands like `who' command. */
3064void
paulb21b19c2003-06-15 01:28:29 +00003065vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00003066{
3067 /* For further configuration read, preserve current directory. */
3068 vty_save_cwd ();
3069
3070 vtyvec = vector_init (VECTOR_MIN_SIZE);
3071
Donald Sharpeeef0db2015-10-14 08:50:38 -04003072 vty_master = master_thread;
paulb21b19c2003-06-15 01:28:29 +00003073
David Lamparterba53a8f2015-05-05 11:04:46 +02003074 atexit (vty_stdio_reset);
3075
paul718e3742002-12-13 20:15:29 +00003076 /* Initilize server thread vector. */
3077 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
3078
3079 /* Install bgp top node. */
3080 install_node (&vty_node, vty_config_write);
3081
Paul Jakma62687ff2008-08-23 14:27:06 +01003082 install_element (RESTRICTED_NODE, &config_who_cmd);
3083 install_element (RESTRICTED_NODE, &show_history_cmd);
paul718e3742002-12-13 20:15:29 +00003084 install_element (VIEW_NODE, &config_who_cmd);
3085 install_element (VIEW_NODE, &show_history_cmd);
3086 install_element (ENABLE_NODE, &config_who_cmd);
3087 install_element (CONFIG_NODE, &line_vty_cmd);
3088 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
3089 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
3090 install_element (CONFIG_NODE, &show_history_cmd);
3091 install_element (ENABLE_NODE, &terminal_monitor_cmd);
3092 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
paul789f78a2006-01-17 17:42:03 +00003093 install_element (ENABLE_NODE, &no_terminal_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003094 install_element (ENABLE_NODE, &show_history_cmd);
3095
3096 install_default (VTY_NODE);
3097 install_element (VTY_NODE, &exec_timeout_min_cmd);
3098 install_element (VTY_NODE, &exec_timeout_sec_cmd);
3099 install_element (VTY_NODE, &no_exec_timeout_cmd);
3100 install_element (VTY_NODE, &vty_access_class_cmd);
3101 install_element (VTY_NODE, &no_vty_access_class_cmd);
3102 install_element (VTY_NODE, &vty_login_cmd);
3103 install_element (VTY_NODE, &no_vty_login_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003104 install_element (VTY_NODE, &vty_restricted_mode_cmd);
3105 install_element (VTY_NODE, &vty_no_restricted_mode_cmd);
paul718e3742002-12-13 20:15:29 +00003106#ifdef HAVE_IPV6
3107 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
3108 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
3109#endif /* HAVE_IPV6 */
3110}
Chris Caputo228da422009-07-18 05:44:03 +00003111
3112void
3113vty_terminate (void)
3114{
3115 if (vty_cwd)
3116 XFREE (MTYPE_TMP, vty_cwd);
3117
3118 if (vtyvec && Vvty_serv_thread)
3119 {
3120 vty_reset ();
3121 vector_free (vtyvec);
3122 vector_free (Vvty_serv_thread);
3123 }
3124}