blob: e429ef17ce96ce593a15975ff3bd8cba6ba85cad [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>
paul718e3742002-12-13 20:15:29 +000041
42/* Vty events */
43enum event
44{
45 VTY_SERV,
46 VTY_READ,
47 VTY_WRITE,
48 VTY_TIMEOUT_RESET,
49#ifdef VTYSH
50 VTYSH_SERV,
ajs49ff6d92004-11-04 19:26:16 +000051 VTYSH_READ,
52 VTYSH_WRITE
paul718e3742002-12-13 20:15:29 +000053#endif /* VTYSH */
54};
55
56static void vty_event (enum event, int, struct vty *);
57
58/* Extern host structure from command.c */
59extern struct host host;
60
61/* Vector which store each vty structure. */
62static vector vtyvec;
63
64/* Vty timeout value. */
65static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
66
67/* Vty access-class command */
68static char *vty_accesslist_name = NULL;
69
70/* Vty access-calss for IPv6. */
71static char *vty_ipv6_accesslist_name = NULL;
72
73/* VTY server thread. */
74vector Vvty_serv_thread;
75
76/* Current directory. */
77char *vty_cwd = NULL;
78
79/* Configure lock. */
80static int vty_config;
81
82/* Login password check. */
83static int no_password_check = 0;
84
85/* Integrated configuration file path */
86char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
87
88
89/* VTY standard output function. */
90int
91vty_out (struct vty *vty, const char *format, ...)
92{
93 va_list args;
94 int len = 0;
95 int size = 1024;
96 char buf[1024];
97 char *p = NULL;
paul718e3742002-12-13 20:15:29 +000098
99 if (vty_shell (vty))
ajsd246bd92004-11-23 17:35:08 +0000100 {
101 va_start (args, format);
102 vprintf (format, args);
103 va_end (args);
104 }
paul718e3742002-12-13 20:15:29 +0000105 else
106 {
107 /* Try to write to initial buffer. */
ajsd246bd92004-11-23 17:35:08 +0000108 va_start (args, format);
paul718e3742002-12-13 20:15:29 +0000109 len = vsnprintf (buf, sizeof buf, format, args);
ajsd246bd92004-11-23 17:35:08 +0000110 va_end (args);
paul718e3742002-12-13 20:15:29 +0000111
112 /* Initial buffer is not enough. */
113 if (len < 0 || len >= size)
114 {
115 while (1)
116 {
117 if (len > -1)
118 size = len + 1;
119 else
120 size = size * 2;
121
122 p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
123 if (! p)
124 return -1;
125
ajsd246bd92004-11-23 17:35:08 +0000126 va_start (args, format);
paul718e3742002-12-13 20:15:29 +0000127 len = vsnprintf (p, size, format, args);
ajsd246bd92004-11-23 17:35:08 +0000128 va_end (args);
paul718e3742002-12-13 20:15:29 +0000129
130 if (len > -1 && len < size)
131 break;
132 }
133 }
134
135 /* When initial buffer is enough to store all output. */
136 if (! p)
137 p = buf;
138
139 /* Pointer p must point out buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +0000140 buffer_put (vty->obuf, (u_char *) p, len);
paul718e3742002-12-13 20:15:29 +0000141
142 /* If p is not different with buf, it is allocated buffer. */
143 if (p != buf)
144 XFREE (MTYPE_VTY_OUT_BUF, p);
145 }
146
paul718e3742002-12-13 20:15:29 +0000147 return len;
148}
149
ajsd246bd92004-11-23 17:35:08 +0000150static int
ajs274a4a42004-12-07 15:39:31 +0000151vty_log_out (struct vty *vty, const char *level, const char *proto_str,
152 const char *format, va_list va)
paul718e3742002-12-13 20:15:29 +0000153{
ajs9fc7ebf2005-02-23 15:12:34 +0000154 int ret;
paul718e3742002-12-13 20:15:29 +0000155 int len;
156 char buf[1024];
157
ajs274a4a42004-12-07 15:39:31 +0000158 if (level)
ajs9fc7ebf2005-02-23 15:12:34 +0000159 len = snprintf(buf, sizeof(buf), "%s: %s: ", level, proto_str);
ajs274a4a42004-12-07 15:39:31 +0000160 else
ajs9fc7ebf2005-02-23 15:12:34 +0000161 len = snprintf(buf, sizeof(buf), "%s: ", proto_str);
162 if ((len < 0) || ((size_t)len >= sizeof(buf)))
paul718e3742002-12-13 20:15:29 +0000163 return -1;
paul718e3742002-12-13 20:15:29 +0000164
ajs9fc7ebf2005-02-23 15:12:34 +0000165 if (((ret = vsnprintf(buf+len, sizeof(buf)-len, format, va)) < 0) ||
166 ((size_t)((len += ret)+2) > sizeof(buf)))
167 return -1;
paul718e3742002-12-13 20:15:29 +0000168
ajs9fc7ebf2005-02-23 15:12:34 +0000169 buf[len++] = '\r';
170 buf[len++] = '\n';
171
172 if (write(vty->fd, buf, len) < 0)
173 {
174 if (ERRNO_IO_RETRY(errno))
175 /* Kernel buffer is full, probably too much debugging output, so just
176 drop the data and ignore. */
177 return -1;
178 /* Fatal I/O error. */
179 zlog_warn("%s: write failed to vty client fd %d, closing: %s",
180 __func__, vty->fd, safe_strerror(errno));
181 buffer_reset(vty->obuf);
182 vty_close(vty);
183 return -1;
184 }
185 return 0;
paul718e3742002-12-13 20:15:29 +0000186}
187
188/* Output current time to the vty. */
189void
190vty_time_print (struct vty *vty, int cr)
191{
192 time_t clock;
193 struct tm *tm;
194#define TIME_BUF 25
195 char buf [TIME_BUF];
196 int ret;
197
198 time (&clock);
199 tm = localtime (&clock);
200
201 ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
202 if (ret == 0)
203 {
204 zlog (NULL, LOG_INFO, "strftime error");
205 return;
206 }
207 if (cr)
208 vty_out (vty, "%s\n", buf);
209 else
210 vty_out (vty, "%s ", buf);
211
212 return;
213}
214
215/* Say hello to vty interface. */
216void
217vty_hello (struct vty *vty)
218{
paul3b0c5d92005-03-08 10:43:43 +0000219 if (host.motdfile)
220 {
221 FILE *f;
222 char buf[4096];
paul22085182005-03-08 16:00:12 +0000223
paul3b0c5d92005-03-08 10:43:43 +0000224 f = fopen (host.motdfile, "r");
225 if (f)
226 {
paulb45da6f2005-03-08 15:16:57 +0000227 while (fgets (buf, sizeof (buf), f))
paul3b0c5d92005-03-08 10:43:43 +0000228 {
paulb45da6f2005-03-08 15:16:57 +0000229 char *s;
paul22085182005-03-08 16:00:12 +0000230 /* work backwards to ignore trailling isspace() */
231 for (s = buf + strlen (buf); (s > buf) && isspace (*(s - 1));
232 s--);
233 *s = '\0';
234 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
235 }
paul3b0c5d92005-03-08 10:43:43 +0000236 fclose (f);
237 }
238 else
paulb45da6f2005-03-08 15:16:57 +0000239 vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
paul3b0c5d92005-03-08 10:43:43 +0000240 }
241 else if (host.motd)
paul718e3742002-12-13 20:15:29 +0000242 vty_out (vty, host.motd);
243}
244
245/* Put out prompt and wait input from user. */
246static void
247vty_prompt (struct vty *vty)
248{
249 struct utsname names;
250 const char*hostname;
251
252 if (vty->type == VTY_TERM)
253 {
254 hostname = host.name;
255 if (!hostname)
256 {
257 uname (&names);
258 hostname = names.nodename;
259 }
260 vty_out (vty, cmd_prompt (vty->node), hostname);
261 }
262}
263
264/* Send WILL TELOPT_ECHO to remote server. */
ajs9fc7ebf2005-02-23 15:12:34 +0000265static void
paul718e3742002-12-13 20:15:29 +0000266vty_will_echo (struct vty *vty)
267{
paul02ff83c2004-06-11 11:27:03 +0000268 unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
paul718e3742002-12-13 20:15:29 +0000269 vty_out (vty, "%s", cmd);
270}
271
272/* Make suppress Go-Ahead telnet option. */
273static void
274vty_will_suppress_go_ahead (struct vty *vty)
275{
paul02ff83c2004-06-11 11:27:03 +0000276 unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
paul718e3742002-12-13 20:15:29 +0000277 vty_out (vty, "%s", cmd);
278}
279
280/* Make don't use linemode over telnet. */
281static void
282vty_dont_linemode (struct vty *vty)
283{
paul02ff83c2004-06-11 11:27:03 +0000284 unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
paul718e3742002-12-13 20:15:29 +0000285 vty_out (vty, "%s", cmd);
286}
287
288/* Use window size. */
289static void
290vty_do_window_size (struct vty *vty)
291{
paul02ff83c2004-06-11 11:27:03 +0000292 unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
paul718e3742002-12-13 20:15:29 +0000293 vty_out (vty, "%s", cmd);
294}
295
296#if 0 /* Currently not used. */
297/* Make don't use lflow vty interface. */
298static void
299vty_dont_lflow_ahead (struct vty *vty)
300{
paul02ff83c2004-06-11 11:27:03 +0000301 unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
paul718e3742002-12-13 20:15:29 +0000302 vty_out (vty, "%s", cmd);
303}
304#endif /* 0 */
305
306/* Allocate new vty struct. */
307struct vty *
308vty_new ()
309{
310 struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
311
ajs9fc7ebf2005-02-23 15:12:34 +0000312 new->obuf = buffer_new(0); /* Use default buffer size. */
paul718e3742002-12-13 20:15:29 +0000313 new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
314 new->max = VTY_BUFSIZ;
paul718e3742002-12-13 20:15:29 +0000315
316 return new;
317}
318
319/* Authentication of vty */
320static void
321vty_auth (struct vty *vty, char *buf)
322{
323 char *passwd = NULL;
324 enum node_type next_node = 0;
325 int fail;
326 char *crypt (const char *, const char *);
327
328 switch (vty->node)
329 {
330 case AUTH_NODE:
331 if (host.encrypt)
332 passwd = host.password_encrypt;
333 else
334 passwd = host.password;
335 if (host.advanced)
336 next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
337 else
338 next_node = VIEW_NODE;
339 break;
340 case AUTH_ENABLE_NODE:
341 if (host.encrypt)
342 passwd = host.enable_encrypt;
343 else
344 passwd = host.enable;
345 next_node = ENABLE_NODE;
346 break;
347 }
348
349 if (passwd)
350 {
351 if (host.encrypt)
352 fail = strcmp (crypt(buf, passwd), passwd);
353 else
354 fail = strcmp (buf, passwd);
355 }
356 else
357 fail = 1;
358
359 if (! fail)
360 {
361 vty->fail = 0;
362 vty->node = next_node; /* Success ! */
363 }
364 else
365 {
366 vty->fail++;
367 if (vty->fail >= 3)
368 {
369 if (vty->node == AUTH_NODE)
370 {
371 vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
372 vty->status = VTY_CLOSE;
373 }
374 else
375 {
376 /* AUTH_ENABLE_NODE */
377 vty->fail = 0;
378 vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
379 vty->node = VIEW_NODE;
380 }
381 }
382 }
383}
384
385/* Command execution over the vty interface. */
ajs9fc7ebf2005-02-23 15:12:34 +0000386static int
paul718e3742002-12-13 20:15:29 +0000387vty_command (struct vty *vty, char *buf)
388{
389 int ret;
390 vector vline;
391
392 /* Split readline string up into the vector */
393 vline = cmd_make_strvec (buf);
394
395 if (vline == NULL)
396 return CMD_SUCCESS;
397
ajs924b9222005-04-16 17:11:24 +0000398#ifdef CONSUMED_TIME_CHECK
399 {
400 RUSAGE_T before;
401 RUSAGE_T after;
ajs8b70d0b2005-04-28 01:31:13 +0000402 unsigned long realtime, cputime;
ajs924b9222005-04-16 17:11:24 +0000403
404 GETRUSAGE(&before);
405#endif /* CONSUMED_TIME_CHECK */
406
hasso87d683b2005-01-16 23:31:54 +0000407 ret = cmd_execute_command (vline, vty, NULL, 0);
paul718e3742002-12-13 20:15:29 +0000408
ajs924b9222005-04-16 17:11:24 +0000409#ifdef CONSUMED_TIME_CHECK
410 GETRUSAGE(&after);
ajs8b70d0b2005-04-28 01:31:13 +0000411 if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
412 CONSUMED_TIME_CHECK)
ajs924b9222005-04-16 17:11:24 +0000413 /* Warn about CPU hog that must be fixed. */
ajs8b70d0b2005-04-28 01:31:13 +0000414 zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
415 realtime/1000, cputime/1000, buf);
ajs924b9222005-04-16 17:11:24 +0000416 }
417#endif /* CONSUMED_TIME_CHECK */
418
paul718e3742002-12-13 20:15:29 +0000419 if (ret != CMD_SUCCESS)
420 switch (ret)
421 {
422 case CMD_WARNING:
423 if (vty->type == VTY_FILE)
424 vty_out (vty, "Warning...%s", VTY_NEWLINE);
425 break;
426 case CMD_ERR_AMBIGUOUS:
427 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
428 break;
429 case CMD_ERR_NO_MATCH:
430 vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
431 break;
432 case CMD_ERR_INCOMPLETE:
433 vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
434 break;
435 }
436 cmd_free_strvec (vline);
437
438 return ret;
439}
440
ajs9fc7ebf2005-02-23 15:12:34 +0000441static const char telnet_backward_char = 0x08;
442static const char telnet_space_char = ' ';
paul718e3742002-12-13 20:15:29 +0000443
444/* Basic function to write buffer to vty. */
445static void
ajs9fc7ebf2005-02-23 15:12:34 +0000446vty_write (struct vty *vty, const char *buf, size_t nbytes)
paul718e3742002-12-13 20:15:29 +0000447{
448 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
449 return;
450
451 /* Should we do buffering here ? And make vty_flush (vty) ? */
ajs9fc7ebf2005-02-23 15:12:34 +0000452 buffer_put (vty->obuf, buf, nbytes);
paul718e3742002-12-13 20:15:29 +0000453}
454
455/* Ensure length of input buffer. Is buffer is short, double it. */
456static void
457vty_ensure (struct vty *vty, int length)
458{
459 if (vty->max <= length)
460 {
461 vty->max *= 2;
462 vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
463 }
464}
465
466/* Basic function to insert character into vty. */
467static void
468vty_self_insert (struct vty *vty, char c)
469{
470 int i;
471 int length;
472
473 vty_ensure (vty, vty->length + 1);
474 length = vty->length - vty->cp;
475 memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
476 vty->buf[vty->cp] = c;
477
478 vty_write (vty, &vty->buf[vty->cp], length + 1);
479 for (i = 0; i < length; i++)
480 vty_write (vty, &telnet_backward_char, 1);
481
482 vty->cp++;
483 vty->length++;
484}
485
486/* Self insert character 'c' in overwrite mode. */
487static void
488vty_self_insert_overwrite (struct vty *vty, char c)
489{
490 vty_ensure (vty, vty->length + 1);
491 vty->buf[vty->cp++] = c;
492
493 if (vty->cp > vty->length)
494 vty->length++;
495
496 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
497 return;
498
499 vty_write (vty, &c, 1);
500}
501
502/* Insert a word into vty interface with overwrite mode. */
503static void
504vty_insert_word_overwrite (struct vty *vty, char *str)
505{
506 int len = strlen (str);
507 vty_write (vty, str, len);
508 strcpy (&vty->buf[vty->cp], str);
509 vty->cp += len;
510 vty->length = vty->cp;
511}
512
513/* Forward character. */
514static void
515vty_forward_char (struct vty *vty)
516{
517 if (vty->cp < vty->length)
518 {
519 vty_write (vty, &vty->buf[vty->cp], 1);
520 vty->cp++;
521 }
522}
523
524/* Backward character. */
525static void
526vty_backward_char (struct vty *vty)
527{
528 if (vty->cp > 0)
529 {
530 vty->cp--;
531 vty_write (vty, &telnet_backward_char, 1);
532 }
533}
534
535/* Move to the beginning of the line. */
536static void
537vty_beginning_of_line (struct vty *vty)
538{
539 while (vty->cp)
540 vty_backward_char (vty);
541}
542
543/* Move to the end of the line. */
544static void
545vty_end_of_line (struct vty *vty)
546{
547 while (vty->cp < vty->length)
548 vty_forward_char (vty);
549}
550
551static void vty_kill_line_from_beginning (struct vty *);
552static void vty_redraw_line (struct vty *);
553
554/* Print command line history. This function is called from
555 vty_next_line and vty_previous_line. */
556static void
557vty_history_print (struct vty *vty)
558{
559 int length;
560
561 vty_kill_line_from_beginning (vty);
562
563 /* Get previous line from history buffer */
564 length = strlen (vty->hist[vty->hp]);
565 memcpy (vty->buf, vty->hist[vty->hp], length);
566 vty->cp = vty->length = length;
567
568 /* Redraw current line */
569 vty_redraw_line (vty);
570}
571
572/* Show next command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000573static void
paul718e3742002-12-13 20:15:29 +0000574vty_next_line (struct vty *vty)
575{
576 int try_index;
577
578 if (vty->hp == vty->hindex)
579 return;
580
581 /* Try is there history exist or not. */
582 try_index = vty->hp;
583 if (try_index == (VTY_MAXHIST - 1))
584 try_index = 0;
585 else
586 try_index++;
587
588 /* If there is not history return. */
589 if (vty->hist[try_index] == NULL)
590 return;
591 else
592 vty->hp = try_index;
593
594 vty_history_print (vty);
595}
596
597/* Show previous command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000598static void
paul718e3742002-12-13 20:15:29 +0000599vty_previous_line (struct vty *vty)
600{
601 int try_index;
602
603 try_index = vty->hp;
604 if (try_index == 0)
605 try_index = VTY_MAXHIST - 1;
606 else
607 try_index--;
608
609 if (vty->hist[try_index] == NULL)
610 return;
611 else
612 vty->hp = try_index;
613
614 vty_history_print (vty);
615}
616
617/* This function redraw all of the command line character. */
618static void
619vty_redraw_line (struct vty *vty)
620{
621 vty_write (vty, vty->buf, vty->length);
622 vty->cp = vty->length;
623}
624
625/* Forward word. */
626static void
627vty_forward_word (struct vty *vty)
628{
629 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
630 vty_forward_char (vty);
631
632 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
633 vty_forward_char (vty);
634}
635
636/* Backward word without skipping training space. */
637static void
638vty_backward_pure_word (struct vty *vty)
639{
640 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
641 vty_backward_char (vty);
642}
643
644/* Backward word. */
645static void
646vty_backward_word (struct vty *vty)
647{
648 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
649 vty_backward_char (vty);
650
651 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
652 vty_backward_char (vty);
653}
654
655/* When '^D' is typed at the beginning of the line we move to the down
656 level. */
657static void
658vty_down_level (struct vty *vty)
659{
660 vty_out (vty, "%s", VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +0000661 (*config_exit_cmd.func)(NULL, vty, 0, NULL);
paul718e3742002-12-13 20:15:29 +0000662 vty_prompt (vty);
663 vty->cp = 0;
664}
665
666/* When '^Z' is received from vty, move down to the enable mode. */
ajs9fc7ebf2005-02-23 15:12:34 +0000667static void
paul718e3742002-12-13 20:15:29 +0000668vty_end_config (struct vty *vty)
669{
670 vty_out (vty, "%s", VTY_NEWLINE);
671
672 switch (vty->node)
673 {
674 case VIEW_NODE:
675 case ENABLE_NODE:
676 /* Nothing to do. */
677 break;
678 case CONFIG_NODE:
679 case INTERFACE_NODE:
680 case ZEBRA_NODE:
681 case RIP_NODE:
682 case RIPNG_NODE:
683 case BGP_NODE:
684 case BGP_VPNV4_NODE:
685 case BGP_IPV4_NODE:
686 case BGP_IPV4M_NODE:
687 case BGP_IPV6_NODE:
688 case RMAP_NODE:
689 case OSPF_NODE:
690 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +0000691 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +0000692 case KEYCHAIN_NODE:
693 case KEYCHAIN_KEY_NODE:
694 case MASC_NODE:
695 case VTY_NODE:
696 vty_config_unlock (vty);
697 vty->node = ENABLE_NODE;
698 break;
699 default:
700 /* Unknown node, we have to ignore it. */
701 break;
702 }
703
704 vty_prompt (vty);
705 vty->cp = 0;
706}
707
708/* Delete a charcter at the current point. */
709static void
710vty_delete_char (struct vty *vty)
711{
712 int i;
713 int size;
714
715 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
716 return;
717
718 if (vty->length == 0)
719 {
720 vty_down_level (vty);
721 return;
722 }
723
724 if (vty->cp == vty->length)
725 return; /* completion need here? */
726
727 size = vty->length - vty->cp;
728
729 vty->length--;
730 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
731 vty->buf[vty->length] = '\0';
732
733 vty_write (vty, &vty->buf[vty->cp], size - 1);
734 vty_write (vty, &telnet_space_char, 1);
735
736 for (i = 0; i < size; i++)
737 vty_write (vty, &telnet_backward_char, 1);
738}
739
740/* Delete a character before the point. */
741static void
742vty_delete_backward_char (struct vty *vty)
743{
744 if (vty->cp == 0)
745 return;
746
747 vty_backward_char (vty);
748 vty_delete_char (vty);
749}
750
751/* Kill rest of line from current point. */
752static void
753vty_kill_line (struct vty *vty)
754{
755 int i;
756 int size;
757
758 size = vty->length - vty->cp;
759
760 if (size == 0)
761 return;
762
763 for (i = 0; i < size; i++)
764 vty_write (vty, &telnet_space_char, 1);
765 for (i = 0; i < size; i++)
766 vty_write (vty, &telnet_backward_char, 1);
767
768 memset (&vty->buf[vty->cp], 0, size);
769 vty->length = vty->cp;
770}
771
772/* Kill line from the beginning. */
773static void
774vty_kill_line_from_beginning (struct vty *vty)
775{
776 vty_beginning_of_line (vty);
777 vty_kill_line (vty);
778}
779
780/* Delete a word before the point. */
781static void
782vty_forward_kill_word (struct vty *vty)
783{
784 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
785 vty_delete_char (vty);
786 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
787 vty_delete_char (vty);
788}
789
790/* Delete a word before the point. */
791static void
792vty_backward_kill_word (struct vty *vty)
793{
794 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
795 vty_delete_backward_char (vty);
796 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
797 vty_delete_backward_char (vty);
798}
799
800/* Transpose chars before or at the point. */
801static void
802vty_transpose_chars (struct vty *vty)
803{
804 char c1, c2;
805
806 /* If length is short or point is near by the beginning of line then
807 return. */
808 if (vty->length < 2 || vty->cp < 1)
809 return;
810
811 /* In case of point is located at the end of the line. */
812 if (vty->cp == vty->length)
813 {
814 c1 = vty->buf[vty->cp - 1];
815 c2 = vty->buf[vty->cp - 2];
816
817 vty_backward_char (vty);
818 vty_backward_char (vty);
819 vty_self_insert_overwrite (vty, c1);
820 vty_self_insert_overwrite (vty, c2);
821 }
822 else
823 {
824 c1 = vty->buf[vty->cp];
825 c2 = vty->buf[vty->cp - 1];
826
827 vty_backward_char (vty);
828 vty_self_insert_overwrite (vty, c1);
829 vty_self_insert_overwrite (vty, c2);
830 }
831}
832
833/* Do completion at vty interface. */
834static void
835vty_complete_command (struct vty *vty)
836{
837 int i;
838 int ret;
839 char **matched = NULL;
840 vector vline;
841
842 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
843 return;
844
845 vline = cmd_make_strvec (vty->buf);
846 if (vline == NULL)
847 return;
848
849 /* In case of 'help \t'. */
850 if (isspace ((int) vty->buf[vty->length - 1]))
851 vector_set (vline, '\0');
852
853 matched = cmd_complete_command (vline, vty, &ret);
854
855 cmd_free_strvec (vline);
856
857 vty_out (vty, "%s", VTY_NEWLINE);
858 switch (ret)
859 {
860 case CMD_ERR_AMBIGUOUS:
861 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
862 vty_prompt (vty);
863 vty_redraw_line (vty);
864 break;
865 case CMD_ERR_NO_MATCH:
866 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
867 vty_prompt (vty);
868 vty_redraw_line (vty);
869 break;
870 case CMD_COMPLETE_FULL_MATCH:
871 vty_prompt (vty);
872 vty_redraw_line (vty);
873 vty_backward_pure_word (vty);
874 vty_insert_word_overwrite (vty, matched[0]);
875 vty_self_insert (vty, ' ');
876 XFREE (MTYPE_TMP, matched[0]);
877 break;
878 case CMD_COMPLETE_MATCH:
879 vty_prompt (vty);
880 vty_redraw_line (vty);
881 vty_backward_pure_word (vty);
882 vty_insert_word_overwrite (vty, matched[0]);
883 XFREE (MTYPE_TMP, matched[0]);
884 vector_only_index_free (matched);
885 return;
886 break;
887 case CMD_COMPLETE_LIST_MATCH:
888 for (i = 0; matched[i] != NULL; i++)
889 {
890 if (i != 0 && ((i % 6) == 0))
891 vty_out (vty, "%s", VTY_NEWLINE);
892 vty_out (vty, "%-10s ", matched[i]);
893 XFREE (MTYPE_TMP, matched[i]);
894 }
895 vty_out (vty, "%s", VTY_NEWLINE);
896
897 vty_prompt (vty);
898 vty_redraw_line (vty);
899 break;
900 case CMD_ERR_NOTHING_TODO:
901 vty_prompt (vty);
902 vty_redraw_line (vty);
903 break;
904 default:
905 break;
906 }
907 if (matched)
908 vector_only_index_free (matched);
909}
910
ajs9fc7ebf2005-02-23 15:12:34 +0000911static void
paul718e3742002-12-13 20:15:29 +0000912vty_describe_fold (struct vty *vty, int cmd_width,
hasso8c328f12004-10-05 21:01:23 +0000913 unsigned int desc_width, struct desc *desc)
paul718e3742002-12-13 20:15:29 +0000914{
hasso8c328f12004-10-05 21:01:23 +0000915 char *buf;
916 const char *cmd, *p;
paul718e3742002-12-13 20:15:29 +0000917 int pos;
918
919 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
920
921 if (desc_width <= 0)
922 {
923 vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
924 return;
925 }
926
927 buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
928
929 for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
930 {
931 for (pos = desc_width; pos > 0; pos--)
932 if (*(p + pos) == ' ')
933 break;
934
935 if (pos == 0)
936 break;
937
938 strncpy (buf, p, pos);
939 buf[pos] = '\0';
940 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
941
942 cmd = "";
943 }
944
945 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
946
947 XFREE (MTYPE_TMP, buf);
948}
949
950/* Describe matched command function. */
951static void
952vty_describe_command (struct vty *vty)
953{
954 int ret;
955 vector vline;
956 vector describe;
hasso8c328f12004-10-05 21:01:23 +0000957 unsigned int i, width, desc_width;
paul718e3742002-12-13 20:15:29 +0000958 struct desc *desc, *desc_cr = NULL;
959
960 vline = cmd_make_strvec (vty->buf);
961
962 /* In case of '> ?'. */
963 if (vline == NULL)
964 {
965 vline = vector_init (1);
966 vector_set (vline, '\0');
967 }
968 else
969 if (isspace ((int) vty->buf[vty->length - 1]))
970 vector_set (vline, '\0');
971
972 describe = cmd_describe_command (vline, vty, &ret);
973
974 vty_out (vty, "%s", VTY_NEWLINE);
975
976 /* Ambiguous error. */
977 switch (ret)
978 {
979 case CMD_ERR_AMBIGUOUS:
980 cmd_free_strvec (vline);
981 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
982 vty_prompt (vty);
983 vty_redraw_line (vty);
984 return;
985 break;
986 case CMD_ERR_NO_MATCH:
987 cmd_free_strvec (vline);
988 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
989 vty_prompt (vty);
990 vty_redraw_line (vty);
991 return;
992 break;
993 }
994
995 /* Get width of command string. */
996 width = 0;
paul55468c82005-03-14 20:19:01 +0000997 for (i = 0; i < vector_active (describe); i++)
paul718e3742002-12-13 20:15:29 +0000998 if ((desc = vector_slot (describe, i)) != NULL)
999 {
hasso8c328f12004-10-05 21:01:23 +00001000 unsigned int len;
paul718e3742002-12-13 20:15:29 +00001001
1002 if (desc->cmd[0] == '\0')
1003 continue;
1004
1005 len = strlen (desc->cmd);
1006 if (desc->cmd[0] == '.')
1007 len--;
1008
1009 if (width < len)
1010 width = len;
1011 }
1012
1013 /* Get width of description string. */
1014 desc_width = vty->width - (width + 6);
1015
1016 /* Print out description. */
paul55468c82005-03-14 20:19:01 +00001017 for (i = 0; i < vector_active (describe); i++)
paul718e3742002-12-13 20:15:29 +00001018 if ((desc = vector_slot (describe, i)) != NULL)
1019 {
1020 if (desc->cmd[0] == '\0')
1021 continue;
1022
1023 if (strcmp (desc->cmd, "<cr>") == 0)
1024 {
1025 desc_cr = desc;
1026 continue;
1027 }
1028
1029 if (!desc->str)
1030 vty_out (vty, " %-s%s",
1031 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1032 VTY_NEWLINE);
1033 else if (desc_width >= strlen (desc->str))
1034 vty_out (vty, " %-*s %s%s", width,
1035 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1036 desc->str, VTY_NEWLINE);
1037 else
1038 vty_describe_fold (vty, width, desc_width, desc);
1039
1040#if 0
1041 vty_out (vty, " %-*s %s%s", width
1042 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1043 desc->str ? desc->str : "", VTY_NEWLINE);
1044#endif /* 0 */
1045 }
1046
1047 if ((desc = desc_cr))
1048 {
1049 if (!desc->str)
1050 vty_out (vty, " %-s%s",
1051 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1052 VTY_NEWLINE);
1053 else if (desc_width >= strlen (desc->str))
1054 vty_out (vty, " %-*s %s%s", width,
1055 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1056 desc->str, VTY_NEWLINE);
1057 else
1058 vty_describe_fold (vty, width, desc_width, desc);
1059 }
1060
1061 cmd_free_strvec (vline);
1062 vector_free (describe);
1063
1064 vty_prompt (vty);
1065 vty_redraw_line (vty);
1066}
1067
ajs9fc7ebf2005-02-23 15:12:34 +00001068static void
paul718e3742002-12-13 20:15:29 +00001069vty_clear_buf (struct vty *vty)
1070{
1071 memset (vty->buf, 0, vty->max);
1072}
1073
1074/* ^C stop current input and do not add command line to the history. */
1075static void
1076vty_stop_input (struct vty *vty)
1077{
1078 vty->cp = vty->length = 0;
1079 vty_clear_buf (vty);
1080 vty_out (vty, "%s", VTY_NEWLINE);
1081
1082 switch (vty->node)
1083 {
1084 case VIEW_NODE:
1085 case ENABLE_NODE:
1086 /* Nothing to do. */
1087 break;
1088 case CONFIG_NODE:
1089 case INTERFACE_NODE:
1090 case ZEBRA_NODE:
1091 case RIP_NODE:
1092 case RIPNG_NODE:
1093 case BGP_NODE:
1094 case RMAP_NODE:
1095 case OSPF_NODE:
1096 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00001097 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00001098 case KEYCHAIN_NODE:
1099 case KEYCHAIN_KEY_NODE:
1100 case MASC_NODE:
1101 case VTY_NODE:
1102 vty_config_unlock (vty);
1103 vty->node = ENABLE_NODE;
1104 break;
1105 default:
1106 /* Unknown node, we have to ignore it. */
1107 break;
1108 }
1109 vty_prompt (vty);
1110
1111 /* Set history pointer to the latest one. */
1112 vty->hp = vty->hindex;
1113}
1114
1115/* Add current command line to the history buffer. */
1116static void
1117vty_hist_add (struct vty *vty)
1118{
1119 int index;
1120
1121 if (vty->length == 0)
1122 return;
1123
1124 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1125
1126 /* Ignore the same string as previous one. */
1127 if (vty->hist[index])
1128 if (strcmp (vty->buf, vty->hist[index]) == 0)
1129 {
1130 vty->hp = vty->hindex;
1131 return;
1132 }
1133
1134 /* Insert history entry. */
1135 if (vty->hist[vty->hindex])
1136 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1137 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1138
1139 /* History index rotation. */
1140 vty->hindex++;
1141 if (vty->hindex == VTY_MAXHIST)
1142 vty->hindex = 0;
1143
1144 vty->hp = vty->hindex;
1145}
1146
1147/* #define TELNET_OPTION_DEBUG */
1148
1149/* Get telnet window size. */
1150static int
1151vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1152{
1153#ifdef TELNET_OPTION_DEBUG
1154 int i;
1155
1156 for (i = 0; i < nbytes; i++)
1157 {
1158 switch (buf[i])
1159 {
1160 case IAC:
1161 vty_out (vty, "IAC ");
1162 break;
1163 case WILL:
1164 vty_out (vty, "WILL ");
1165 break;
1166 case WONT:
1167 vty_out (vty, "WONT ");
1168 break;
1169 case DO:
1170 vty_out (vty, "DO ");
1171 break;
1172 case DONT:
1173 vty_out (vty, "DONT ");
1174 break;
1175 case SB:
1176 vty_out (vty, "SB ");
1177 break;
1178 case SE:
1179 vty_out (vty, "SE ");
1180 break;
1181 case TELOPT_ECHO:
1182 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1183 break;
1184 case TELOPT_SGA:
1185 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1186 break;
1187 case TELOPT_NAWS:
1188 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1189 break;
1190 default:
1191 vty_out (vty, "%x ", buf[i]);
1192 break;
1193 }
1194 }
1195 vty_out (vty, "%s", VTY_NEWLINE);
1196
1197#endif /* TELNET_OPTION_DEBUG */
1198
1199 switch (buf[0])
1200 {
1201 case SB:
ajs9fc7ebf2005-02-23 15:12:34 +00001202 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001203 vty->iac_sb_in_progress = 1;
1204 return 0;
1205 break;
1206 case SE:
1207 {
paul718e3742002-12-13 20:15:29 +00001208 if (!vty->iac_sb_in_progress)
1209 return 0;
1210
ajs9fc7ebf2005-02-23 15:12:34 +00001211 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
paul718e3742002-12-13 20:15:29 +00001212 {
1213 vty->iac_sb_in_progress = 0;
1214 return 0;
1215 }
ajs9fc7ebf2005-02-23 15:12:34 +00001216 switch (vty->sb_buf[0])
paul718e3742002-12-13 20:15:29 +00001217 {
1218 case TELOPT_NAWS:
ajs9fc7ebf2005-02-23 15:12:34 +00001219 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1220 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1221 "should send %d characters, but we received %lu",
1222 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1223 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1224 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1225 "too small to handle the telnet NAWS option",
1226 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1227 else
1228 {
1229 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1230 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1231#ifdef TELNET_OPTION_DEBUG
1232 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1233 "width %d, height %d%s",
1234 vty->width, vty->height, VTY_NEWLINE);
1235#endif
1236 }
paul718e3742002-12-13 20:15:29 +00001237 break;
1238 }
1239 vty->iac_sb_in_progress = 0;
1240 return 0;
1241 break;
1242 }
1243 default:
1244 break;
1245 }
1246 return 1;
1247}
1248
1249/* Execute current command line. */
1250static int
1251vty_execute (struct vty *vty)
1252{
1253 int ret;
1254
1255 ret = CMD_SUCCESS;
1256
1257 switch (vty->node)
1258 {
1259 case AUTH_NODE:
1260 case AUTH_ENABLE_NODE:
1261 vty_auth (vty, vty->buf);
1262 break;
1263 default:
1264 ret = vty_command (vty, vty->buf);
1265 if (vty->type == VTY_TERM)
1266 vty_hist_add (vty);
1267 break;
1268 }
1269
1270 /* Clear command line buffer. */
1271 vty->cp = vty->length = 0;
1272 vty_clear_buf (vty);
1273
ajs5a646652004-11-05 01:25:55 +00001274 if (vty->status != VTY_CLOSE )
paul718e3742002-12-13 20:15:29 +00001275 vty_prompt (vty);
1276
1277 return ret;
1278}
1279
1280#define CONTROL(X) ((X) - '@')
1281#define VTY_NORMAL 0
1282#define VTY_PRE_ESCAPE 1
1283#define VTY_ESCAPE 2
1284
1285/* Escape character command map. */
1286static void
1287vty_escape_map (unsigned char c, struct vty *vty)
1288{
1289 switch (c)
1290 {
1291 case ('A'):
1292 vty_previous_line (vty);
1293 break;
1294 case ('B'):
1295 vty_next_line (vty);
1296 break;
1297 case ('C'):
1298 vty_forward_char (vty);
1299 break;
1300 case ('D'):
1301 vty_backward_char (vty);
1302 break;
1303 default:
1304 break;
1305 }
1306
1307 /* Go back to normal mode. */
1308 vty->escape = VTY_NORMAL;
1309}
1310
1311/* Quit print out to the buffer. */
1312static void
1313vty_buffer_reset (struct vty *vty)
1314{
1315 buffer_reset (vty->obuf);
1316 vty_prompt (vty);
1317 vty_redraw_line (vty);
1318}
1319
1320/* Read data via vty socket. */
1321static int
1322vty_read (struct thread *thread)
1323{
1324 int i;
paul718e3742002-12-13 20:15:29 +00001325 int nbytes;
1326 unsigned char buf[VTY_READ_BUFSIZ];
1327
1328 int vty_sock = THREAD_FD (thread);
1329 struct vty *vty = THREAD_ARG (thread);
1330 vty->t_read = NULL;
1331
1332 /* Read raw data from socket */
ajs9fc7ebf2005-02-23 15:12:34 +00001333 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1334 {
1335 if (nbytes < 0)
1336 {
1337 if (ERRNO_IO_RETRY(errno))
1338 {
1339 vty_event (VTY_READ, vty_sock, vty);
1340 return 0;
1341 }
1342 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1343 __func__, vty->fd, safe_strerror(errno));
1344 }
1345 buffer_reset(vty->obuf);
1346 vty->status = VTY_CLOSE;
1347 }
paul718e3742002-12-13 20:15:29 +00001348
1349 for (i = 0; i < nbytes; i++)
1350 {
1351 if (buf[i] == IAC)
1352 {
1353 if (!vty->iac)
1354 {
1355 vty->iac = 1;
1356 continue;
1357 }
1358 else
1359 {
1360 vty->iac = 0;
1361 }
1362 }
1363
1364 if (vty->iac_sb_in_progress && !vty->iac)
1365 {
ajs9fc7ebf2005-02-23 15:12:34 +00001366 if (vty->sb_len < sizeof(vty->sb_buf))
1367 vty->sb_buf[vty->sb_len] = buf[i];
1368 vty->sb_len++;
paul718e3742002-12-13 20:15:29 +00001369 continue;
1370 }
1371
1372 if (vty->iac)
1373 {
1374 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001375 int ret = 0;
paule9372532003-10-26 21:36:07 +00001376 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001377 vty->iac = 0;
1378 i += ret;
1379 continue;
1380 }
paul5b8c1b02003-10-15 23:08:55 +00001381
paul718e3742002-12-13 20:15:29 +00001382
1383 if (vty->status == VTY_MORE)
1384 {
1385 switch (buf[i])
1386 {
1387 case CONTROL('C'):
1388 case 'q':
1389 case 'Q':
paul718e3742002-12-13 20:15:29 +00001390 vty_buffer_reset (vty);
1391 break;
1392#if 0 /* More line does not work for "show ip bgp". */
1393 case '\n':
1394 case '\r':
1395 vty->status = VTY_MORELINE;
1396 break;
1397#endif
1398 default:
paul718e3742002-12-13 20:15:29 +00001399 break;
1400 }
1401 continue;
1402 }
1403
1404 /* Escape character. */
1405 if (vty->escape == VTY_ESCAPE)
1406 {
1407 vty_escape_map (buf[i], vty);
1408 continue;
1409 }
1410
1411 /* Pre-escape status. */
1412 if (vty->escape == VTY_PRE_ESCAPE)
1413 {
1414 switch (buf[i])
1415 {
1416 case '[':
1417 vty->escape = VTY_ESCAPE;
1418 break;
1419 case 'b':
1420 vty_backward_word (vty);
1421 vty->escape = VTY_NORMAL;
1422 break;
1423 case 'f':
1424 vty_forward_word (vty);
1425 vty->escape = VTY_NORMAL;
1426 break;
1427 case 'd':
1428 vty_forward_kill_word (vty);
1429 vty->escape = VTY_NORMAL;
1430 break;
1431 case CONTROL('H'):
1432 case 0x7f:
1433 vty_backward_kill_word (vty);
1434 vty->escape = VTY_NORMAL;
1435 break;
1436 default:
1437 vty->escape = VTY_NORMAL;
1438 break;
1439 }
1440 continue;
1441 }
1442
1443 switch (buf[i])
1444 {
1445 case CONTROL('A'):
1446 vty_beginning_of_line (vty);
1447 break;
1448 case CONTROL('B'):
1449 vty_backward_char (vty);
1450 break;
1451 case CONTROL('C'):
1452 vty_stop_input (vty);
1453 break;
1454 case CONTROL('D'):
1455 vty_delete_char (vty);
1456 break;
1457 case CONTROL('E'):
1458 vty_end_of_line (vty);
1459 break;
1460 case CONTROL('F'):
1461 vty_forward_char (vty);
1462 break;
1463 case CONTROL('H'):
1464 case 0x7f:
1465 vty_delete_backward_char (vty);
1466 break;
1467 case CONTROL('K'):
1468 vty_kill_line (vty);
1469 break;
1470 case CONTROL('N'):
1471 vty_next_line (vty);
1472 break;
1473 case CONTROL('P'):
1474 vty_previous_line (vty);
1475 break;
1476 case CONTROL('T'):
1477 vty_transpose_chars (vty);
1478 break;
1479 case CONTROL('U'):
1480 vty_kill_line_from_beginning (vty);
1481 break;
1482 case CONTROL('W'):
1483 vty_backward_kill_word (vty);
1484 break;
1485 case CONTROL('Z'):
1486 vty_end_config (vty);
1487 break;
1488 case '\n':
1489 case '\r':
1490 vty_out (vty, "%s", VTY_NEWLINE);
1491 vty_execute (vty);
1492 break;
1493 case '\t':
1494 vty_complete_command (vty);
1495 break;
1496 case '?':
1497 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1498 vty_self_insert (vty, buf[i]);
1499 else
1500 vty_describe_command (vty);
1501 break;
1502 case '\033':
1503 if (i + 1 < nbytes && buf[i + 1] == '[')
1504 {
1505 vty->escape = VTY_ESCAPE;
1506 i++;
1507 }
1508 else
1509 vty->escape = VTY_PRE_ESCAPE;
1510 break;
1511 default:
1512 if (buf[i] > 31 && buf[i] < 127)
1513 vty_self_insert (vty, buf[i]);
1514 break;
1515 }
1516 }
1517
1518 /* Check status. */
1519 if (vty->status == VTY_CLOSE)
1520 vty_close (vty);
1521 else
1522 {
1523 vty_event (VTY_WRITE, vty_sock, vty);
1524 vty_event (VTY_READ, vty_sock, vty);
1525 }
1526 return 0;
1527}
1528
1529/* Flush buffer to the vty. */
1530static int
1531vty_flush (struct thread *thread)
1532{
1533 int erase;
ajs9fc7ebf2005-02-23 15:12:34 +00001534 buffer_status_t flushrc;
paul718e3742002-12-13 20:15:29 +00001535 int vty_sock = THREAD_FD (thread);
1536 struct vty *vty = THREAD_ARG (thread);
ajs9fc7ebf2005-02-23 15:12:34 +00001537
paul718e3742002-12-13 20:15:29 +00001538 vty->t_write = NULL;
1539
1540 /* Tempolary disable read thread. */
ajs9fc7ebf2005-02-23 15:12:34 +00001541 if ((vty->lines == 0) && vty->t_read)
1542 {
1543 thread_cancel (vty->t_read);
1544 vty->t_read = NULL;
1545 }
paul718e3742002-12-13 20:15:29 +00001546
1547 /* Function execution continue. */
ajs9fc7ebf2005-02-23 15:12:34 +00001548 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
paul718e3742002-12-13 20:15:29 +00001549
ajs9fc7ebf2005-02-23 15:12:34 +00001550 /* N.B. if width is 0, that means we don't know the window size. */
1551 if ((vty->lines == 0) || (vty->width == 0))
1552 flushrc = buffer_flush_available(vty->obuf, vty->fd);
1553 else if (vty->status == VTY_MORELINE)
1554 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1555 1, erase, 0);
1556 else
1557 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1558 vty->lines >= 0 ? vty->lines :
1559 vty->height,
1560 erase, 0);
1561 switch (flushrc)
1562 {
1563 case BUFFER_ERROR:
1564 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1565 vty->fd);
1566 buffer_reset(vty->obuf);
1567 vty_close(vty);
1568 return 0;
1569 case BUFFER_EMPTY:
1570 if (vty->status == VTY_CLOSE)
1571 vty_close (vty);
paul718e3742002-12-13 20:15:29 +00001572 else
1573 {
ajs9fc7ebf2005-02-23 15:12:34 +00001574 vty->status = VTY_NORMAL;
paul718e3742002-12-13 20:15:29 +00001575 if (vty->lines == 0)
ajs9fc7ebf2005-02-23 15:12:34 +00001576 vty_event (VTY_READ, vty_sock, vty);
paul718e3742002-12-13 20:15:29 +00001577 }
ajs9fc7ebf2005-02-23 15:12:34 +00001578 break;
1579 case BUFFER_PENDING:
1580 /* There is more data waiting to be written. */
1581 vty->status = VTY_MORE;
1582 if (vty->lines == 0)
1583 vty_event (VTY_WRITE, vty_sock, vty);
1584 break;
1585 }
paul718e3742002-12-13 20:15:29 +00001586
1587 return 0;
1588}
1589
1590/* Create new vty structure. */
ajs9fc7ebf2005-02-23 15:12:34 +00001591static struct vty *
paul718e3742002-12-13 20:15:29 +00001592vty_create (int vty_sock, union sockunion *su)
1593{
1594 struct vty *vty;
1595
1596 /* Allocate new vty structure and set up default values. */
1597 vty = vty_new ();
1598 vty->fd = vty_sock;
1599 vty->type = VTY_TERM;
1600 vty->address = sockunion_su2str (su);
1601 if (no_password_check)
1602 {
1603 if (host.advanced)
1604 vty->node = ENABLE_NODE;
1605 else
1606 vty->node = VIEW_NODE;
1607 }
1608 else
1609 vty->node = AUTH_NODE;
1610 vty->fail = 0;
1611 vty->cp = 0;
1612 vty_clear_buf (vty);
1613 vty->length = 0;
1614 memset (vty->hist, 0, sizeof (vty->hist));
1615 vty->hp = 0;
1616 vty->hindex = 0;
1617 vector_set_index (vtyvec, vty_sock, vty);
1618 vty->status = VTY_NORMAL;
1619 vty->v_timeout = vty_timeout_val;
1620 if (host.lines >= 0)
1621 vty->lines = host.lines;
1622 else
1623 vty->lines = -1;
1624 vty->iac = 0;
1625 vty->iac_sb_in_progress = 0;
ajs9fc7ebf2005-02-23 15:12:34 +00001626 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001627
1628 if (! no_password_check)
1629 {
1630 /* Vty is not available if password isn't set. */
1631 if (host.password == NULL && host.password_encrypt == NULL)
1632 {
1633 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1634 vty->status = VTY_CLOSE;
1635 vty_close (vty);
1636 return NULL;
1637 }
1638 }
1639
1640 /* Say hello to the world. */
1641 vty_hello (vty);
1642 if (! no_password_check)
1643 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1644
1645 /* Setting up terminal. */
1646 vty_will_echo (vty);
1647 vty_will_suppress_go_ahead (vty);
1648
1649 vty_dont_linemode (vty);
1650 vty_do_window_size (vty);
1651 /* vty_dont_lflow_ahead (vty); */
1652
1653 vty_prompt (vty);
1654
1655 /* Add read/write thread. */
1656 vty_event (VTY_WRITE, vty_sock, vty);
1657 vty_event (VTY_READ, vty_sock, vty);
1658
1659 return vty;
1660}
1661
1662/* Accept connection from the network. */
1663static int
1664vty_accept (struct thread *thread)
1665{
1666 int vty_sock;
1667 struct vty *vty;
1668 union sockunion su;
1669 int ret;
1670 unsigned int on;
1671 int accept_sock;
1672 struct prefix *p = NULL;
1673 struct access_list *acl = NULL;
1674
1675 accept_sock = THREAD_FD (thread);
1676
1677 /* We continue hearing vty socket. */
1678 vty_event (VTY_SERV, accept_sock, NULL);
1679
1680 memset (&su, 0, sizeof (union sockunion));
1681
1682 /* We can handle IPv4 or IPv6 socket. */
1683 vty_sock = sockunion_accept (accept_sock, &su);
1684 if (vty_sock < 0)
1685 {
ajs6099b3b2004-11-20 02:06:59 +00001686 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001687 return -1;
1688 }
ajs9fc7ebf2005-02-23 15:12:34 +00001689 set_nonblocking(vty_sock);
paul718e3742002-12-13 20:15:29 +00001690
1691 p = sockunion2hostprefix (&su);
1692
1693 /* VTY's accesslist apply. */
1694 if (p->family == AF_INET && vty_accesslist_name)
1695 {
1696 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1697 (access_list_apply (acl, p) == FILTER_DENY))
1698 {
1699 char *buf;
1700 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1701 (buf = sockunion_su2str (&su)));
1702 free (buf);
1703 close (vty_sock);
1704
1705 /* continue accepting connections */
1706 vty_event (VTY_SERV, accept_sock, NULL);
1707
1708 prefix_free (p);
1709
1710 return 0;
1711 }
1712 }
1713
1714#ifdef HAVE_IPV6
1715 /* VTY's ipv6 accesslist apply. */
1716 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1717 {
1718 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1719 (access_list_apply (acl, p) == FILTER_DENY))
1720 {
1721 char *buf;
1722 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1723 (buf = sockunion_su2str (&su)));
1724 free (buf);
1725 close (vty_sock);
1726
1727 /* continue accepting connections */
1728 vty_event (VTY_SERV, accept_sock, NULL);
1729
1730 prefix_free (p);
1731
1732 return 0;
1733 }
1734 }
1735#endif /* HAVE_IPV6 */
1736
1737 prefix_free (p);
1738
1739 on = 1;
1740 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1741 (char *) &on, sizeof (on));
1742 if (ret < 0)
1743 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
ajs6099b3b2004-11-20 02:06:59 +00001744 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001745
1746 vty = vty_create (vty_sock, &su);
1747
1748 return 0;
1749}
1750
1751#if defined(HAVE_IPV6) && !defined(NRL)
ajs9fc7ebf2005-02-23 15:12:34 +00001752static void
paul718e3742002-12-13 20:15:29 +00001753vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1754{
1755 int ret;
1756 struct addrinfo req;
1757 struct addrinfo *ainfo;
1758 struct addrinfo *ainfo_save;
1759 int sock;
1760 char port_str[BUFSIZ];
1761
1762 memset (&req, 0, sizeof (struct addrinfo));
1763 req.ai_flags = AI_PASSIVE;
1764 req.ai_family = AF_UNSPEC;
1765 req.ai_socktype = SOCK_STREAM;
1766 sprintf (port_str, "%d", port);
1767 port_str[sizeof (port_str) - 1] = '\0';
1768
1769 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1770
1771 if (ret != 0)
1772 {
1773 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1774 exit (1);
1775 }
1776
1777 ainfo_save = ainfo;
1778
1779 do
1780 {
1781 if (ainfo->ai_family != AF_INET
1782#ifdef HAVE_IPV6
1783 && ainfo->ai_family != AF_INET6
1784#endif /* HAVE_IPV6 */
1785 )
1786 continue;
1787
1788 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1789 if (sock < 0)
1790 continue;
1791
1792 sockopt_reuseaddr (sock);
1793 sockopt_reuseport (sock);
1794
1795 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1796 if (ret < 0)
1797 {
1798 close (sock); /* Avoid sd leak. */
1799 continue;
1800 }
1801
1802 ret = listen (sock, 3);
1803 if (ret < 0)
1804 {
1805 close (sock); /* Avoid sd leak. */
1806 continue;
1807 }
1808
1809 vty_event (VTY_SERV, sock, NULL);
1810 }
1811 while ((ainfo = ainfo->ai_next) != NULL);
1812
1813 freeaddrinfo (ainfo_save);
1814}
1815#endif /* HAVE_IPV6 && ! NRL */
1816
1817/* Make vty server socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001818static void
paul29db05b2003-05-08 20:10:22 +00001819vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001820{
1821 int ret;
1822 union sockunion su;
1823 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001824 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001825
1826 memset (&su, 0, sizeof (union sockunion));
1827 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001828 if(addr)
1829 switch(family)
1830 {
1831 case AF_INET:
1832 naddr=&su.sin.sin_addr;
1833#ifdef HAVE_IPV6
1834 case AF_INET6:
1835 naddr=&su.sin6.sin6_addr;
1836#endif
1837 }
1838
1839 if(naddr)
1840 switch(inet_pton(family,addr,naddr))
1841 {
1842 case -1:
1843 zlog_err("bad address %s",addr);
1844 naddr=NULL;
1845 break;
1846 case 0:
ajs6099b3b2004-11-20 02:06:59 +00001847 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
paul29db05b2003-05-08 20:10:22 +00001848 naddr=NULL;
1849 }
paul718e3742002-12-13 20:15:29 +00001850
1851 /* Make new socket. */
1852 accept_sock = sockunion_stream_socket (&su);
1853 if (accept_sock < 0)
1854 return;
1855
1856 /* This is server, so reuse address. */
1857 sockopt_reuseaddr (accept_sock);
1858 sockopt_reuseport (accept_sock);
1859
1860 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001861 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001862 if (ret < 0)
1863 {
paul29db05b2003-05-08 20:10:22 +00001864 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001865 close (accept_sock); /* Avoid sd leak. */
1866 return;
1867 }
1868
1869 /* Listen socket under queue 3. */
1870 ret = listen (accept_sock, 3);
1871 if (ret < 0)
1872 {
1873 zlog (NULL, LOG_WARNING, "can't listen socket");
1874 close (accept_sock); /* Avoid sd leak. */
1875 return;
1876 }
1877
1878 /* Add vty server event. */
1879 vty_event (VTY_SERV, accept_sock, NULL);
1880}
1881
1882#ifdef VTYSH
1883/* For sockaddr_un. */
1884#include <sys/un.h>
1885
1886/* VTY shell UNIX domain socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001887static void
hasso6ad96ea2004-10-07 19:33:46 +00001888vty_serv_un (const char *path)
paul718e3742002-12-13 20:15:29 +00001889{
1890 int ret;
paul75e15fe2004-10-31 02:13:09 +00001891 int sock, len;
paul718e3742002-12-13 20:15:29 +00001892 struct sockaddr_un serv;
1893 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00001894 struct zprivs_ids_t ids;
1895
paul718e3742002-12-13 20:15:29 +00001896 /* First of all, unlink existing socket */
1897 unlink (path);
1898
1899 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00001900 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00001901
1902 /* Make UNIX domain socket. */
1903 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1904 if (sock < 0)
1905 {
ajs6a52d0d2005-01-30 18:49:28 +00001906 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001907 return;
1908 }
1909
1910 /* Make server socket. */
1911 memset (&serv, 0, sizeof (struct sockaddr_un));
1912 serv.sun_family = AF_UNIX;
1913 strncpy (serv.sun_path, path, strlen (path));
1914#ifdef HAVE_SUN_LEN
1915 len = serv.sun_len = SUN_LEN(&serv);
1916#else
1917 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1918#endif /* HAVE_SUN_LEN */
1919
1920 ret = bind (sock, (struct sockaddr *) &serv, len);
1921 if (ret < 0)
1922 {
ajs6a52d0d2005-01-30 18:49:28 +00001923 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001924 close (sock); /* Avoid sd leak. */
1925 return;
1926 }
1927
1928 ret = listen (sock, 5);
1929 if (ret < 0)
1930 {
ajs6a52d0d2005-01-30 18:49:28 +00001931 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001932 close (sock); /* Avoid sd leak. */
1933 return;
1934 }
1935
1936 umask (old_mask);
1937
pauledd7c242003-06-04 13:59:38 +00001938 zprivs_get_ids(&ids);
1939
1940 if (ids.gid_vty > 0)
1941 {
1942 /* set group of socket */
1943 if ( chown (path, -1, ids.gid_vty) )
1944 {
1945 zlog_err ("vty_serv_un: could chown socket, %s",
ajs6099b3b2004-11-20 02:06:59 +00001946 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +00001947 }
1948 }
1949
paul718e3742002-12-13 20:15:29 +00001950 vty_event (VTYSH_SERV, sock, NULL);
1951}
1952
1953/* #define VTYSH_DEBUG 1 */
1954
1955static int
1956vtysh_accept (struct thread *thread)
1957{
1958 int accept_sock;
1959 int sock;
1960 int client_len;
1961 struct sockaddr_un client;
1962 struct vty *vty;
1963
1964 accept_sock = THREAD_FD (thread);
1965
1966 vty_event (VTYSH_SERV, accept_sock, NULL);
1967
1968 memset (&client, 0, sizeof (struct sockaddr_un));
1969 client_len = sizeof (struct sockaddr_un);
1970
hassoe473b032004-09-26 16:08:11 +00001971 sock = accept (accept_sock, (struct sockaddr *) &client,
1972 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00001973
1974 if (sock < 0)
1975 {
ajs6099b3b2004-11-20 02:06:59 +00001976 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001977 return -1;
1978 }
1979
ajs9fc7ebf2005-02-23 15:12:34 +00001980 if (set_nonblocking(sock) < 0)
paul75e15fe2004-10-31 02:13:09 +00001981 {
ajs9fc7ebf2005-02-23 15:12:34 +00001982 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
1983 " %s, closing", sock, safe_strerror (errno));
paul75e15fe2004-10-31 02:13:09 +00001984 close (sock);
1985 return -1;
1986 }
pauldccfb192004-10-29 08:29:36 +00001987
paul718e3742002-12-13 20:15:29 +00001988#ifdef VTYSH_DEBUG
1989 printf ("VTY shell accept\n");
1990#endif /* VTYSH_DEBUG */
1991
1992 vty = vty_new ();
1993 vty->fd = sock;
1994 vty->type = VTY_SHELL_SERV;
1995 vty->node = VIEW_NODE;
1996
1997 vty_event (VTYSH_READ, sock, vty);
1998
1999 return 0;
2000}
2001
2002static int
ajs9fc7ebf2005-02-23 15:12:34 +00002003vtysh_flush(struct vty *vty)
2004{
2005 switch (buffer_flush_available(vty->obuf, vty->fd))
2006 {
2007 case BUFFER_PENDING:
2008 vty_event(VTYSH_WRITE, vty->fd, vty);
2009 break;
2010 case BUFFER_ERROR:
2011 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
2012 buffer_reset(vty->obuf);
2013 vty_close(vty);
2014 return -1;
2015 break;
2016 case BUFFER_EMPTY:
2017 break;
2018 }
2019 return 0;
2020}
2021
2022static int
paul718e3742002-12-13 20:15:29 +00002023vtysh_read (struct thread *thread)
2024{
2025 int ret;
2026 int sock;
2027 int nbytes;
2028 struct vty *vty;
2029 unsigned char buf[VTY_READ_BUFSIZ];
ajs9fc7ebf2005-02-23 15:12:34 +00002030 unsigned char *p;
paul718e3742002-12-13 20:15:29 +00002031 u_char header[4] = {0, 0, 0, 0};
2032
2033 sock = THREAD_FD (thread);
2034 vty = THREAD_ARG (thread);
2035 vty->t_read = NULL;
2036
ajs9fc7ebf2005-02-23 15:12:34 +00002037 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
paul718e3742002-12-13 20:15:29 +00002038 {
ajs9fc7ebf2005-02-23 15:12:34 +00002039 if (nbytes < 0)
2040 {
2041 if (ERRNO_IO_RETRY(errno))
2042 {
2043 vty_event (VTYSH_READ, sock, vty);
2044 return 0;
2045 }
2046 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2047 __func__, sock, safe_strerror(errno));
2048 }
2049 buffer_reset(vty->obuf);
paul718e3742002-12-13 20:15:29 +00002050 vty_close (vty);
2051#ifdef VTYSH_DEBUG
2052 printf ("close vtysh\n");
2053#endif /* VTYSH_DEBUG */
2054 return 0;
2055 }
2056
2057#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002058 printf ("line: %.*s\n", nbytes, buf);
paul718e3742002-12-13 20:15:29 +00002059#endif /* VTYSH_DEBUG */
2060
ajs9fc7ebf2005-02-23 15:12:34 +00002061 for (p = buf; p < buf+nbytes; p++)
2062 {
2063 vty_ensure(vty, vty->length+1);
2064 vty->buf[vty->length++] = *p;
2065 if (*p == '\0')
2066 {
2067 /* Pass this line to parser. */
2068 ret = vty_execute (vty);
2069 /* Note that vty_execute clears the command buffer and resets
2070 vty->length to 0. */
paul718e3742002-12-13 20:15:29 +00002071
ajs9fc7ebf2005-02-23 15:12:34 +00002072 /* Return result. */
paul718e3742002-12-13 20:15:29 +00002073#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002074 printf ("result: %d\n", ret);
2075 printf ("vtysh node: %d\n", vty->node);
paul718e3742002-12-13 20:15:29 +00002076#endif /* VTYSH_DEBUG */
2077
ajs9fc7ebf2005-02-23 15:12:34 +00002078 header[3] = ret;
2079 buffer_put(vty->obuf, header, 4);
paul718e3742002-12-13 20:15:29 +00002080
ajs9fc7ebf2005-02-23 15:12:34 +00002081 if (!vty->t_write && (vtysh_flush(vty) < 0))
2082 /* Try to flush results; exit if a write error occurs. */
2083 return 0;
2084 }
2085 }
2086
paul718e3742002-12-13 20:15:29 +00002087 vty_event (VTYSH_READ, sock, vty);
2088
2089 return 0;
2090}
ajs49ff6d92004-11-04 19:26:16 +00002091
2092static int
2093vtysh_write (struct thread *thread)
2094{
2095 struct vty *vty = THREAD_ARG (thread);
2096
2097 vty->t_write = NULL;
ajs9fc7ebf2005-02-23 15:12:34 +00002098 vtysh_flush(vty);
ajs976d8c72004-11-10 15:40:09 +00002099 return 0;
ajs49ff6d92004-11-04 19:26:16 +00002100}
2101
paul718e3742002-12-13 20:15:29 +00002102#endif /* VTYSH */
2103
2104/* Determine address family to bind. */
2105void
hasso6ad96ea2004-10-07 19:33:46 +00002106vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002107{
2108 /* If port is set to 0, do not listen on TCP/IP at all! */
2109 if (port)
2110 {
2111
2112#ifdef HAVE_IPV6
2113#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002114 vty_serv_sock_family (addr, port, AF_INET);
2115 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002116#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002117 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002118#endif /* NRL*/
2119#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002120 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002121#endif /* HAVE_IPV6 */
2122 }
2123
2124#ifdef VTYSH
2125 vty_serv_un (path);
2126#endif /* VTYSH */
2127}
2128
2129/* Close vty interface. */
2130void
2131vty_close (struct vty *vty)
2132{
2133 int i;
2134
2135 /* Cancel threads.*/
2136 if (vty->t_read)
2137 thread_cancel (vty->t_read);
2138 if (vty->t_write)
2139 thread_cancel (vty->t_write);
2140 if (vty->t_timeout)
2141 thread_cancel (vty->t_timeout);
paul718e3742002-12-13 20:15:29 +00002142
2143 /* Flush buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +00002144 buffer_flush_all (vty->obuf, vty->fd);
paul718e3742002-12-13 20:15:29 +00002145
2146 /* Free input buffer. */
2147 buffer_free (vty->obuf);
2148
paul718e3742002-12-13 20:15:29 +00002149 /* Free command history. */
2150 for (i = 0; i < VTY_MAXHIST; i++)
2151 if (vty->hist[i])
2152 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2153
2154 /* Unset vector. */
2155 vector_unset (vtyvec, vty->fd);
2156
2157 /* Close socket. */
2158 if (vty->fd > 0)
2159 close (vty->fd);
2160
2161 if (vty->address)
2162 XFREE (0, vty->address);
2163 if (vty->buf)
2164 XFREE (MTYPE_VTY, vty->buf);
2165
2166 /* Check configure. */
2167 vty_config_unlock (vty);
2168
2169 /* OK free vty. */
2170 XFREE (MTYPE_VTY, vty);
2171}
2172
2173/* When time out occur output message then close connection. */
2174static int
2175vty_timeout (struct thread *thread)
2176{
2177 struct vty *vty;
2178
2179 vty = THREAD_ARG (thread);
2180 vty->t_timeout = NULL;
2181 vty->v_timeout = 0;
2182
2183 /* Clear buffer*/
2184 buffer_reset (vty->obuf);
2185 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2186
2187 /* Close connection. */
2188 vty->status = VTY_CLOSE;
2189 vty_close (vty);
2190
2191 return 0;
2192}
2193
2194/* Read up configuration file from file_name. */
2195static void
2196vty_read_file (FILE *confp)
2197{
2198 int ret;
2199 struct vty *vty;
2200
2201 vty = vty_new ();
2202 vty->fd = 0; /* stdout */
2203 vty->type = VTY_TERM;
2204 vty->node = CONFIG_NODE;
2205
2206 /* Execute configuration file */
2207 ret = config_from_file (vty, confp);
2208
paul7021c422003-07-15 12:52:22 +00002209 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002210 {
2211 switch (ret)
paul7021c422003-07-15 12:52:22 +00002212 {
2213 case CMD_ERR_AMBIGUOUS:
2214 fprintf (stderr, "Ambiguous command.\n");
2215 break;
2216 case CMD_ERR_NO_MATCH:
2217 fprintf (stderr, "There is no such command.\n");
2218 break;
2219 }
paul718e3742002-12-13 20:15:29 +00002220 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2221 vty->buf);
2222 vty_close (vty);
2223 exit (1);
2224 }
2225
2226 vty_close (vty);
2227}
2228
ajs9fc7ebf2005-02-23 15:12:34 +00002229static FILE *
paul718e3742002-12-13 20:15:29 +00002230vty_use_backup_config (char *fullpath)
2231{
2232 char *fullpath_sav, *fullpath_tmp;
2233 FILE *ret = NULL;
2234 struct stat buf;
2235 int tmp, sav;
2236 int c;
2237 char buffer[512];
2238
2239 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2240 strcpy (fullpath_sav, fullpath);
2241 strcat (fullpath_sav, CONF_BACKUP_EXT);
2242 if (stat (fullpath_sav, &buf) == -1)
2243 {
2244 free (fullpath_sav);
2245 return NULL;
2246 }
2247
2248 fullpath_tmp = malloc (strlen (fullpath) + 8);
2249 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2250
2251 /* Open file to configuration write. */
2252 tmp = mkstemp (fullpath_tmp);
2253 if (tmp < 0)
2254 {
2255 free (fullpath_sav);
2256 free (fullpath_tmp);
2257 return NULL;
2258 }
2259
2260 sav = open (fullpath_sav, O_RDONLY);
2261 if (sav < 0)
2262 {
gdt3dbf9962003-12-22 20:18:18 +00002263 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002264 free (fullpath_sav);
2265 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002266 return NULL;
2267 }
2268
2269 while((c = read (sav, buffer, 512)) > 0)
2270 write (tmp, buffer, c);
2271
2272 close (sav);
2273 close (tmp);
2274
gdtaa593d52003-12-22 20:15:53 +00002275 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2276 {
gdt3dbf9962003-12-22 20:18:18 +00002277 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002278 free (fullpath_sav);
2279 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002280 return NULL;
2281 }
2282
paul718e3742002-12-13 20:15:29 +00002283 if (link (fullpath_tmp, fullpath) == 0)
2284 ret = fopen (fullpath, "r");
2285
2286 unlink (fullpath_tmp);
2287
2288 free (fullpath_sav);
2289 free (fullpath_tmp);
hasso12f6ea22005-03-07 08:35:39 +00002290 return ret;
paul718e3742002-12-13 20:15:29 +00002291}
2292
2293/* Read up configuration file from file_name. */
2294void
2295vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002296 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002297{
paulccc92352003-10-22 02:49:38 +00002298 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002299 FILE *confp = NULL;
2300 char *fullpath;
2301
2302 /* If -f flag specified. */
2303 if (config_file != NULL)
2304 {
2305 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002306 {
2307 getcwd (cwd, MAXPATHLEN);
2308 fullpath = XMALLOC (MTYPE_TMP,
2309 strlen (cwd) + strlen (config_file) + 2);
2310 sprintf (fullpath, "%s/%s", cwd, config_file);
2311 }
paul718e3742002-12-13 20:15:29 +00002312 else
hasso320ec102004-06-20 19:54:37 +00002313 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002314
2315 confp = fopen (fullpath, "r");
2316
2317 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002318 {
paul3d1dc852005-04-05 00:45:23 +00002319 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2320 __func__, fullpath, safe_strerror (errno));
2321
hasso320ec102004-06-20 19:54:37 +00002322 confp = vty_use_backup_config (fullpath);
2323 if (confp)
2324 fprintf (stderr, "WARNING: using backup configuration file!\n");
2325 else
2326 {
2327 fprintf (stderr, "can't open configuration file [%s]\n",
paul3d1dc852005-04-05 00:45:23 +00002328 config_file);
hasso320ec102004-06-20 19:54:37 +00002329 exit(1);
2330 }
2331 }
paul718e3742002-12-13 20:15:29 +00002332 }
2333 else
2334 {
paul718e3742002-12-13 20:15:29 +00002335#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002336 int ret;
2337 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002338
hasso320ec102004-06-20 19:54:37 +00002339 /* !!!!PLEASE LEAVE!!!!
2340 * This is NEEDED for use with vtysh -b, or else you can get
2341 * a real configuration food fight with a lot garbage in the
2342 * merged configuration file it creates coming from the per
2343 * daemon configuration files. This also allows the daemons
2344 * to start if there default configuration file is not
2345 * present or ignore them, as needed when using vtysh -b to
2346 * configure the daemons at boot - MAG
2347 */
paul718e3742002-12-13 20:15:29 +00002348
hasso320ec102004-06-20 19:54:37 +00002349 /* Stat for vtysh Zebra.conf, if found startup and wait for
2350 * boot configuration
2351 */
paul718e3742002-12-13 20:15:29 +00002352
hasso320ec102004-06-20 19:54:37 +00002353 if ( strstr(config_default_dir, "vtysh") == NULL)
2354 {
2355 ret = stat (integrate_default, &conf_stat);
2356 if (ret >= 0)
2357 return;
2358 }
paul718e3742002-12-13 20:15:29 +00002359#endif /* VTYSH */
2360
hasso320ec102004-06-20 19:54:37 +00002361 confp = fopen (config_default_dir, "r");
2362 if (confp == NULL)
2363 {
paul3d1dc852005-04-05 00:45:23 +00002364 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2365 __func__, config_default_dir, safe_strerror (errno));
2366
hasso320ec102004-06-20 19:54:37 +00002367 confp = vty_use_backup_config (config_default_dir);
2368 if (confp)
2369 {
2370 fprintf (stderr, "WARNING: using backup configuration file!\n");
2371 fullpath = config_default_dir;
2372 }
2373 else
2374 {
2375 fprintf (stderr, "can't open configuration file [%s]\n",
2376 config_default_dir);
2377 exit (1);
paul3d1dc852005-04-05 00:45:23 +00002378 }
hasso320ec102004-06-20 19:54:37 +00002379 }
paul718e3742002-12-13 20:15:29 +00002380 else
hasso320ec102004-06-20 19:54:37 +00002381 fullpath = config_default_dir;
2382 }
2383
paul718e3742002-12-13 20:15:29 +00002384 vty_read_file (confp);
2385
2386 fclose (confp);
2387
2388 host_config_set (fullpath);
2389}
2390
2391/* Small utility function which output log to the VTY. */
2392void
ajs274a4a42004-12-07 15:39:31 +00002393vty_log (const char *level, const char *proto_str,
2394 const char *format, va_list va)
paul718e3742002-12-13 20:15:29 +00002395{
hasso8c328f12004-10-05 21:01:23 +00002396 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002397 struct vty *vty;
2398
paul55468c82005-03-14 20:19:01 +00002399 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002400 if ((vty = vector_slot (vtyvec, i)) != NULL)
2401 if (vty->monitor)
ajsd246bd92004-11-23 17:35:08 +00002402 {
2403 va_list ac;
2404 va_copy(ac, va);
ajs274a4a42004-12-07 15:39:31 +00002405 vty_log_out (vty, level, proto_str, format, ac);
ajsd246bd92004-11-23 17:35:08 +00002406 va_end(ac);
2407 }
paul718e3742002-12-13 20:15:29 +00002408}
2409
ajs274a4a42004-12-07 15:39:31 +00002410/* Async-signal-safe version of vty_log for fixed strings. */
2411void
2412vty_log_fixed (const char *buf, size_t len)
2413{
2414 unsigned int i;
ajs9fc7ebf2005-02-23 15:12:34 +00002415 struct iovec iov[2];
2416
ajs926fe8f2005-04-08 18:50:40 +00002417 iov[0].iov_base = (void *)buf;
ajs9fc7ebf2005-02-23 15:12:34 +00002418 iov[0].iov_len = len;
ajs926fe8f2005-04-08 18:50:40 +00002419 iov[1].iov_base = (void *)"\r\n";
ajs9fc7ebf2005-02-23 15:12:34 +00002420 iov[1].iov_len = 2;
ajs274a4a42004-12-07 15:39:31 +00002421
paul55468c82005-03-14 20:19:01 +00002422 for (i = 0; i < vector_active (vtyvec); i++)
ajs274a4a42004-12-07 15:39:31 +00002423 {
2424 struct vty *vty;
ajs9fc7ebf2005-02-23 15:12:34 +00002425 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2426 /* N.B. We don't care about the return code, since process is
2427 most likely just about to die anyway. */
2428 writev(vty->fd, iov, 2);
ajs274a4a42004-12-07 15:39:31 +00002429 }
2430}
2431
paul718e3742002-12-13 20:15:29 +00002432int
2433vty_config_lock (struct vty *vty)
2434{
2435 if (vty_config == 0)
2436 {
2437 vty->config = 1;
2438 vty_config = 1;
2439 }
2440 return vty->config;
2441}
2442
2443int
2444vty_config_unlock (struct vty *vty)
2445{
2446 if (vty_config == 1 && vty->config == 1)
2447 {
2448 vty->config = 0;
2449 vty_config = 0;
2450 }
2451 return vty->config;
2452}
2453
2454/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002455static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002456
2457static void
2458vty_event (enum event event, int sock, struct vty *vty)
2459{
2460 struct thread *vty_serv_thread;
2461
2462 switch (event)
2463 {
2464 case VTY_SERV:
2465 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2466 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2467 break;
2468#ifdef VTYSH
2469 case VTYSH_SERV:
2470 thread_add_read (master, vtysh_accept, vty, sock);
2471 break;
2472 case VTYSH_READ:
ajs49ff6d92004-11-04 19:26:16 +00002473 vty->t_read = thread_add_read (master, vtysh_read, vty, sock);
2474 break;
2475 case VTYSH_WRITE:
2476 vty->t_write = thread_add_write (master, vtysh_write, vty, sock);
paul718e3742002-12-13 20:15:29 +00002477 break;
2478#endif /* VTYSH */
2479 case VTY_READ:
2480 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2481
2482 /* Time out treatment. */
2483 if (vty->v_timeout)
2484 {
2485 if (vty->t_timeout)
2486 thread_cancel (vty->t_timeout);
2487 vty->t_timeout =
2488 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2489 }
2490 break;
2491 case VTY_WRITE:
2492 if (! vty->t_write)
2493 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2494 break;
2495 case VTY_TIMEOUT_RESET:
2496 if (vty->t_timeout)
2497 {
2498 thread_cancel (vty->t_timeout);
2499 vty->t_timeout = NULL;
2500 }
2501 if (vty->v_timeout)
2502 {
2503 vty->t_timeout =
2504 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2505 }
2506 break;
2507 }
2508}
2509
2510DEFUN (config_who,
2511 config_who_cmd,
2512 "who",
2513 "Display who is on vty\n")
2514{
hasso8c328f12004-10-05 21:01:23 +00002515 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002516 struct vty *v;
2517
paul55468c82005-03-14 20:19:01 +00002518 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002519 if ((v = vector_slot (vtyvec, i)) != NULL)
2520 vty_out (vty, "%svty[%d] connected from %s.%s",
2521 v->config ? "*" : " ",
2522 i, v->address, VTY_NEWLINE);
2523 return CMD_SUCCESS;
2524}
2525
2526/* Move to vty configuration mode. */
2527DEFUN (line_vty,
2528 line_vty_cmd,
2529 "line vty",
2530 "Configure a terminal line\n"
2531 "Virtual terminal\n")
2532{
2533 vty->node = VTY_NODE;
2534 return CMD_SUCCESS;
2535}
2536
2537/* Set time out value. */
ajs9fc7ebf2005-02-23 15:12:34 +00002538static int
paul9035efa2004-10-10 11:56:56 +00002539exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002540{
2541 unsigned long timeout = 0;
2542
2543 /* min_str and sec_str are already checked by parser. So it must be
2544 all digit string. */
2545 if (min_str)
2546 {
2547 timeout = strtol (min_str, NULL, 10);
2548 timeout *= 60;
2549 }
2550 if (sec_str)
2551 timeout += strtol (sec_str, NULL, 10);
2552
2553 vty_timeout_val = timeout;
2554 vty->v_timeout = timeout;
2555 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2556
2557
2558 return CMD_SUCCESS;
2559}
2560
2561DEFUN (exec_timeout_min,
2562 exec_timeout_min_cmd,
2563 "exec-timeout <0-35791>",
2564 "Set timeout value\n"
2565 "Timeout value in minutes\n")
2566{
2567 return exec_timeout (vty, argv[0], NULL);
2568}
2569
2570DEFUN (exec_timeout_sec,
2571 exec_timeout_sec_cmd,
2572 "exec-timeout <0-35791> <0-2147483>",
2573 "Set the EXEC timeout\n"
2574 "Timeout in minutes\n"
2575 "Timeout in seconds\n")
2576{
2577 return exec_timeout (vty, argv[0], argv[1]);
2578}
2579
2580DEFUN (no_exec_timeout,
2581 no_exec_timeout_cmd,
2582 "no exec-timeout",
2583 NO_STR
2584 "Set the EXEC timeout\n")
2585{
2586 return exec_timeout (vty, NULL, NULL);
2587}
2588
2589/* Set vty access class. */
2590DEFUN (vty_access_class,
2591 vty_access_class_cmd,
2592 "access-class WORD",
2593 "Filter connections based on an IP access list\n"
2594 "IP access list\n")
2595{
2596 if (vty_accesslist_name)
2597 XFREE(MTYPE_VTY, vty_accesslist_name);
2598
2599 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2600
2601 return CMD_SUCCESS;
2602}
2603
2604/* Clear vty access class. */
2605DEFUN (no_vty_access_class,
2606 no_vty_access_class_cmd,
2607 "no access-class [WORD]",
2608 NO_STR
2609 "Filter connections based on an IP access list\n"
2610 "IP access list\n")
2611{
2612 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2613 {
2614 vty_out (vty, "Access-class is not currently applied to vty%s",
2615 VTY_NEWLINE);
2616 return CMD_WARNING;
2617 }
2618
2619 XFREE(MTYPE_VTY, vty_accesslist_name);
2620
2621 vty_accesslist_name = NULL;
2622
2623 return CMD_SUCCESS;
2624}
2625
2626#ifdef HAVE_IPV6
2627/* Set vty access class. */
2628DEFUN (vty_ipv6_access_class,
2629 vty_ipv6_access_class_cmd,
2630 "ipv6 access-class WORD",
2631 IPV6_STR
2632 "Filter connections based on an IP access list\n"
2633 "IPv6 access list\n")
2634{
2635 if (vty_ipv6_accesslist_name)
2636 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2637
2638 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2639
2640 return CMD_SUCCESS;
2641}
2642
2643/* Clear vty access class. */
2644DEFUN (no_vty_ipv6_access_class,
2645 no_vty_ipv6_access_class_cmd,
2646 "no ipv6 access-class [WORD]",
2647 NO_STR
2648 IPV6_STR
2649 "Filter connections based on an IP access list\n"
2650 "IPv6 access list\n")
2651{
2652 if (! vty_ipv6_accesslist_name ||
2653 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2654 {
2655 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2656 VTY_NEWLINE);
2657 return CMD_WARNING;
2658 }
2659
2660 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2661
2662 vty_ipv6_accesslist_name = NULL;
2663
2664 return CMD_SUCCESS;
2665}
2666#endif /* HAVE_IPV6 */
2667
2668/* vty login. */
2669DEFUN (vty_login,
2670 vty_login_cmd,
2671 "login",
2672 "Enable password checking\n")
2673{
2674 no_password_check = 0;
2675 return CMD_SUCCESS;
2676}
2677
2678DEFUN (no_vty_login,
2679 no_vty_login_cmd,
2680 "no login",
2681 NO_STR
2682 "Enable password checking\n")
2683{
2684 no_password_check = 1;
2685 return CMD_SUCCESS;
2686}
2687
2688DEFUN (service_advanced_vty,
2689 service_advanced_vty_cmd,
2690 "service advanced-vty",
2691 "Set up miscellaneous service\n"
2692 "Enable advanced mode vty interface\n")
2693{
2694 host.advanced = 1;
2695 return CMD_SUCCESS;
2696}
2697
2698DEFUN (no_service_advanced_vty,
2699 no_service_advanced_vty_cmd,
2700 "no service advanced-vty",
2701 NO_STR
2702 "Set up miscellaneous service\n"
2703 "Enable advanced mode vty interface\n")
2704{
2705 host.advanced = 0;
2706 return CMD_SUCCESS;
2707}
2708
2709DEFUN (terminal_monitor,
2710 terminal_monitor_cmd,
2711 "terminal monitor",
2712 "Set terminal line parameters\n"
2713 "Copy debug output to the current terminal line\n")
2714{
2715 vty->monitor = 1;
2716 return CMD_SUCCESS;
2717}
2718
2719DEFUN (terminal_no_monitor,
2720 terminal_no_monitor_cmd,
2721 "terminal no monitor",
2722 "Set terminal line parameters\n"
2723 NO_STR
2724 "Copy debug output to the current terminal line\n")
2725{
2726 vty->monitor = 0;
2727 return CMD_SUCCESS;
2728}
2729
2730DEFUN (show_history,
2731 show_history_cmd,
2732 "show history",
2733 SHOW_STR
2734 "Display the session command history\n")
2735{
2736 int index;
2737
2738 for (index = vty->hindex + 1; index != vty->hindex;)
2739 {
2740 if (index == VTY_MAXHIST)
2741 {
2742 index = 0;
2743 continue;
2744 }
2745
2746 if (vty->hist[index] != NULL)
2747 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2748
2749 index++;
2750 }
2751
2752 return CMD_SUCCESS;
2753}
2754
2755/* Display current configuration. */
ajs9fc7ebf2005-02-23 15:12:34 +00002756static int
paul718e3742002-12-13 20:15:29 +00002757vty_config_write (struct vty *vty)
2758{
2759 vty_out (vty, "line vty%s", VTY_NEWLINE);
2760
2761 if (vty_accesslist_name)
2762 vty_out (vty, " access-class %s%s",
2763 vty_accesslist_name, VTY_NEWLINE);
2764
2765 if (vty_ipv6_accesslist_name)
2766 vty_out (vty, " ipv6 access-class %s%s",
2767 vty_ipv6_accesslist_name, VTY_NEWLINE);
2768
2769 /* exec-timeout */
2770 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2771 vty_out (vty, " exec-timeout %ld %ld%s",
2772 vty_timeout_val / 60,
2773 vty_timeout_val % 60, VTY_NEWLINE);
2774
2775 /* login */
2776 if (no_password_check)
2777 vty_out (vty, " no login%s", VTY_NEWLINE);
2778
2779 vty_out (vty, "!%s", VTY_NEWLINE);
2780
2781 return CMD_SUCCESS;
2782}
2783
2784struct cmd_node vty_node =
2785{
2786 VTY_NODE,
2787 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00002788 1,
paul718e3742002-12-13 20:15:29 +00002789};
2790
2791/* Reset all VTY status. */
2792void
2793vty_reset ()
2794{
hasso8c328f12004-10-05 21:01:23 +00002795 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002796 struct vty *vty;
2797 struct thread *vty_serv_thread;
2798
paul55468c82005-03-14 20:19:01 +00002799 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002800 if ((vty = vector_slot (vtyvec, i)) != NULL)
2801 {
2802 buffer_reset (vty->obuf);
2803 vty->status = VTY_CLOSE;
2804 vty_close (vty);
2805 }
2806
paul55468c82005-03-14 20:19:01 +00002807 for (i = 0; i < vector_active (Vvty_serv_thread); i++)
paul718e3742002-12-13 20:15:29 +00002808 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2809 {
2810 thread_cancel (vty_serv_thread);
2811 vector_slot (Vvty_serv_thread, i) = NULL;
2812 close (i);
2813 }
2814
2815 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2816
2817 if (vty_accesslist_name)
2818 {
2819 XFREE(MTYPE_VTY, vty_accesslist_name);
2820 vty_accesslist_name = NULL;
2821 }
2822
2823 if (vty_ipv6_accesslist_name)
2824 {
2825 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2826 vty_ipv6_accesslist_name = NULL;
2827 }
2828}
2829
ajs9fc7ebf2005-02-23 15:12:34 +00002830static void
2831vty_save_cwd (void)
paul718e3742002-12-13 20:15:29 +00002832{
paul79ad2792003-10-15 22:09:28 +00002833 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00002834 char *c;
paul718e3742002-12-13 20:15:29 +00002835
paulccc92352003-10-22 02:49:38 +00002836 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002837
paulccc92352003-10-22 02:49:38 +00002838 if (!c)
paul79ad2792003-10-15 22:09:28 +00002839 {
2840 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00002841 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002842 }
paul718e3742002-12-13 20:15:29 +00002843
2844 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2845 strcpy (vty_cwd, cwd);
2846}
2847
2848char *
2849vty_get_cwd ()
2850{
2851 return vty_cwd;
2852}
2853
2854int
2855vty_shell (struct vty *vty)
2856{
2857 return vty->type == VTY_SHELL ? 1 : 0;
2858}
2859
2860int
2861vty_shell_serv (struct vty *vty)
2862{
2863 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2864}
2865
2866void
2867vty_init_vtysh ()
2868{
2869 vtyvec = vector_init (VECTOR_MIN_SIZE);
2870}
2871
2872/* Install vty's own commands like `who' command. */
2873void
paulb21b19c2003-06-15 01:28:29 +00002874vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00002875{
2876 /* For further configuration read, preserve current directory. */
2877 vty_save_cwd ();
2878
2879 vtyvec = vector_init (VECTOR_MIN_SIZE);
2880
paulb21b19c2003-06-15 01:28:29 +00002881 master = master_thread;
2882
paul718e3742002-12-13 20:15:29 +00002883 /* Initilize server thread vector. */
2884 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2885
2886 /* Install bgp top node. */
2887 install_node (&vty_node, vty_config_write);
2888
2889 install_element (VIEW_NODE, &config_who_cmd);
2890 install_element (VIEW_NODE, &show_history_cmd);
2891 install_element (ENABLE_NODE, &config_who_cmd);
2892 install_element (CONFIG_NODE, &line_vty_cmd);
2893 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2894 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2895 install_element (CONFIG_NODE, &show_history_cmd);
2896 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2897 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
2898 install_element (ENABLE_NODE, &show_history_cmd);
2899
2900 install_default (VTY_NODE);
2901 install_element (VTY_NODE, &exec_timeout_min_cmd);
2902 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2903 install_element (VTY_NODE, &no_exec_timeout_cmd);
2904 install_element (VTY_NODE, &vty_access_class_cmd);
2905 install_element (VTY_NODE, &no_vty_access_class_cmd);
2906 install_element (VTY_NODE, &vty_login_cmd);
2907 install_element (VTY_NODE, &no_vty_login_cmd);
2908#ifdef HAVE_IPV6
2909 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2910 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2911#endif /* HAVE_IPV6 */
2912}