blob: 540f7b9820c1a5b15736fafee58af16ecf2111b5 [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:
paul1e836592005-08-22 22:39:56 +0000688 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +0000689 case RMAP_NODE:
690 case OSPF_NODE:
691 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +0000692 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +0000693 case KEYCHAIN_NODE:
694 case KEYCHAIN_KEY_NODE:
695 case MASC_NODE:
696 case VTY_NODE:
697 vty_config_unlock (vty);
698 vty->node = ENABLE_NODE;
699 break;
700 default:
701 /* Unknown node, we have to ignore it. */
702 break;
703 }
704
705 vty_prompt (vty);
706 vty->cp = 0;
707}
708
709/* Delete a charcter at the current point. */
710static void
711vty_delete_char (struct vty *vty)
712{
713 int i;
714 int size;
715
716 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
717 return;
718
719 if (vty->length == 0)
720 {
721 vty_down_level (vty);
722 return;
723 }
724
725 if (vty->cp == vty->length)
726 return; /* completion need here? */
727
728 size = vty->length - vty->cp;
729
730 vty->length--;
731 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
732 vty->buf[vty->length] = '\0';
733
734 vty_write (vty, &vty->buf[vty->cp], size - 1);
735 vty_write (vty, &telnet_space_char, 1);
736
737 for (i = 0; i < size; i++)
738 vty_write (vty, &telnet_backward_char, 1);
739}
740
741/* Delete a character before the point. */
742static void
743vty_delete_backward_char (struct vty *vty)
744{
745 if (vty->cp == 0)
746 return;
747
748 vty_backward_char (vty);
749 vty_delete_char (vty);
750}
751
752/* Kill rest of line from current point. */
753static void
754vty_kill_line (struct vty *vty)
755{
756 int i;
757 int size;
758
759 size = vty->length - vty->cp;
760
761 if (size == 0)
762 return;
763
764 for (i = 0; i < size; i++)
765 vty_write (vty, &telnet_space_char, 1);
766 for (i = 0; i < size; i++)
767 vty_write (vty, &telnet_backward_char, 1);
768
769 memset (&vty->buf[vty->cp], 0, size);
770 vty->length = vty->cp;
771}
772
773/* Kill line from the beginning. */
774static void
775vty_kill_line_from_beginning (struct vty *vty)
776{
777 vty_beginning_of_line (vty);
778 vty_kill_line (vty);
779}
780
781/* Delete a word before the point. */
782static void
783vty_forward_kill_word (struct vty *vty)
784{
785 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
786 vty_delete_char (vty);
787 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
788 vty_delete_char (vty);
789}
790
791/* Delete a word before the point. */
792static void
793vty_backward_kill_word (struct vty *vty)
794{
795 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
796 vty_delete_backward_char (vty);
797 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
798 vty_delete_backward_char (vty);
799}
800
801/* Transpose chars before or at the point. */
802static void
803vty_transpose_chars (struct vty *vty)
804{
805 char c1, c2;
806
807 /* If length is short or point is near by the beginning of line then
808 return. */
809 if (vty->length < 2 || vty->cp < 1)
810 return;
811
812 /* In case of point is located at the end of the line. */
813 if (vty->cp == vty->length)
814 {
815 c1 = vty->buf[vty->cp - 1];
816 c2 = vty->buf[vty->cp - 2];
817
818 vty_backward_char (vty);
819 vty_backward_char (vty);
820 vty_self_insert_overwrite (vty, c1);
821 vty_self_insert_overwrite (vty, c2);
822 }
823 else
824 {
825 c1 = vty->buf[vty->cp];
826 c2 = vty->buf[vty->cp - 1];
827
828 vty_backward_char (vty);
829 vty_self_insert_overwrite (vty, c1);
830 vty_self_insert_overwrite (vty, c2);
831 }
832}
833
834/* Do completion at vty interface. */
835static void
836vty_complete_command (struct vty *vty)
837{
838 int i;
839 int ret;
840 char **matched = NULL;
841 vector vline;
842
843 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
844 return;
845
846 vline = cmd_make_strvec (vty->buf);
847 if (vline == NULL)
848 return;
849
850 /* In case of 'help \t'. */
851 if (isspace ((int) vty->buf[vty->length - 1]))
852 vector_set (vline, '\0');
853
854 matched = cmd_complete_command (vline, vty, &ret);
855
856 cmd_free_strvec (vline);
857
858 vty_out (vty, "%s", VTY_NEWLINE);
859 switch (ret)
860 {
861 case CMD_ERR_AMBIGUOUS:
862 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
863 vty_prompt (vty);
864 vty_redraw_line (vty);
865 break;
866 case CMD_ERR_NO_MATCH:
867 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
868 vty_prompt (vty);
869 vty_redraw_line (vty);
870 break;
871 case CMD_COMPLETE_FULL_MATCH:
872 vty_prompt (vty);
873 vty_redraw_line (vty);
874 vty_backward_pure_word (vty);
875 vty_insert_word_overwrite (vty, matched[0]);
876 vty_self_insert (vty, ' ');
877 XFREE (MTYPE_TMP, matched[0]);
878 break;
879 case CMD_COMPLETE_MATCH:
880 vty_prompt (vty);
881 vty_redraw_line (vty);
882 vty_backward_pure_word (vty);
883 vty_insert_word_overwrite (vty, matched[0]);
884 XFREE (MTYPE_TMP, matched[0]);
885 vector_only_index_free (matched);
886 return;
887 break;
888 case CMD_COMPLETE_LIST_MATCH:
889 for (i = 0; matched[i] != NULL; i++)
890 {
891 if (i != 0 && ((i % 6) == 0))
892 vty_out (vty, "%s", VTY_NEWLINE);
893 vty_out (vty, "%-10s ", matched[i]);
894 XFREE (MTYPE_TMP, matched[i]);
895 }
896 vty_out (vty, "%s", VTY_NEWLINE);
897
898 vty_prompt (vty);
899 vty_redraw_line (vty);
900 break;
901 case CMD_ERR_NOTHING_TODO:
902 vty_prompt (vty);
903 vty_redraw_line (vty);
904 break;
905 default:
906 break;
907 }
908 if (matched)
909 vector_only_index_free (matched);
910}
911
ajs9fc7ebf2005-02-23 15:12:34 +0000912static void
paul718e3742002-12-13 20:15:29 +0000913vty_describe_fold (struct vty *vty, int cmd_width,
hasso8c328f12004-10-05 21:01:23 +0000914 unsigned int desc_width, struct desc *desc)
paul718e3742002-12-13 20:15:29 +0000915{
hasso8c328f12004-10-05 21:01:23 +0000916 char *buf;
917 const char *cmd, *p;
paul718e3742002-12-13 20:15:29 +0000918 int pos;
919
920 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
921
922 if (desc_width <= 0)
923 {
924 vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
925 return;
926 }
927
928 buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
929
930 for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
931 {
932 for (pos = desc_width; pos > 0; pos--)
933 if (*(p + pos) == ' ')
934 break;
935
936 if (pos == 0)
937 break;
938
939 strncpy (buf, p, pos);
940 buf[pos] = '\0';
941 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
942
943 cmd = "";
944 }
945
946 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
947
948 XFREE (MTYPE_TMP, buf);
949}
950
951/* Describe matched command function. */
952static void
953vty_describe_command (struct vty *vty)
954{
955 int ret;
956 vector vline;
957 vector describe;
hasso8c328f12004-10-05 21:01:23 +0000958 unsigned int i, width, desc_width;
paul718e3742002-12-13 20:15:29 +0000959 struct desc *desc, *desc_cr = NULL;
960
961 vline = cmd_make_strvec (vty->buf);
962
963 /* In case of '> ?'. */
964 if (vline == NULL)
965 {
966 vline = vector_init (1);
967 vector_set (vline, '\0');
968 }
969 else
970 if (isspace ((int) vty->buf[vty->length - 1]))
971 vector_set (vline, '\0');
972
973 describe = cmd_describe_command (vline, vty, &ret);
974
975 vty_out (vty, "%s", VTY_NEWLINE);
976
977 /* Ambiguous error. */
978 switch (ret)
979 {
980 case CMD_ERR_AMBIGUOUS:
981 cmd_free_strvec (vline);
982 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
983 vty_prompt (vty);
984 vty_redraw_line (vty);
985 return;
986 break;
987 case CMD_ERR_NO_MATCH:
988 cmd_free_strvec (vline);
989 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
990 vty_prompt (vty);
991 vty_redraw_line (vty);
992 return;
993 break;
994 }
995
996 /* Get width of command string. */
997 width = 0;
paul55468c82005-03-14 20:19:01 +0000998 for (i = 0; i < vector_active (describe); i++)
paul718e3742002-12-13 20:15:29 +0000999 if ((desc = vector_slot (describe, i)) != NULL)
1000 {
hasso8c328f12004-10-05 21:01:23 +00001001 unsigned int len;
paul718e3742002-12-13 20:15:29 +00001002
1003 if (desc->cmd[0] == '\0')
1004 continue;
1005
1006 len = strlen (desc->cmd);
1007 if (desc->cmd[0] == '.')
1008 len--;
1009
1010 if (width < len)
1011 width = len;
1012 }
1013
1014 /* Get width of description string. */
1015 desc_width = vty->width - (width + 6);
1016
1017 /* Print out description. */
paul55468c82005-03-14 20:19:01 +00001018 for (i = 0; i < vector_active (describe); i++)
paul718e3742002-12-13 20:15:29 +00001019 if ((desc = vector_slot (describe, i)) != NULL)
1020 {
1021 if (desc->cmd[0] == '\0')
1022 continue;
1023
1024 if (strcmp (desc->cmd, "<cr>") == 0)
1025 {
1026 desc_cr = desc;
1027 continue;
1028 }
1029
1030 if (!desc->str)
1031 vty_out (vty, " %-s%s",
1032 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1033 VTY_NEWLINE);
1034 else if (desc_width >= strlen (desc->str))
1035 vty_out (vty, " %-*s %s%s", width,
1036 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1037 desc->str, VTY_NEWLINE);
1038 else
1039 vty_describe_fold (vty, width, desc_width, desc);
1040
1041#if 0
1042 vty_out (vty, " %-*s %s%s", width
1043 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1044 desc->str ? desc->str : "", VTY_NEWLINE);
1045#endif /* 0 */
1046 }
1047
1048 if ((desc = desc_cr))
1049 {
1050 if (!desc->str)
1051 vty_out (vty, " %-s%s",
1052 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1053 VTY_NEWLINE);
1054 else if (desc_width >= strlen (desc->str))
1055 vty_out (vty, " %-*s %s%s", width,
1056 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1057 desc->str, VTY_NEWLINE);
1058 else
1059 vty_describe_fold (vty, width, desc_width, desc);
1060 }
1061
1062 cmd_free_strvec (vline);
1063 vector_free (describe);
1064
1065 vty_prompt (vty);
1066 vty_redraw_line (vty);
1067}
1068
ajs9fc7ebf2005-02-23 15:12:34 +00001069static void
paul718e3742002-12-13 20:15:29 +00001070vty_clear_buf (struct vty *vty)
1071{
1072 memset (vty->buf, 0, vty->max);
1073}
1074
1075/* ^C stop current input and do not add command line to the history. */
1076static void
1077vty_stop_input (struct vty *vty)
1078{
1079 vty->cp = vty->length = 0;
1080 vty_clear_buf (vty);
1081 vty_out (vty, "%s", VTY_NEWLINE);
1082
1083 switch (vty->node)
1084 {
1085 case VIEW_NODE:
1086 case ENABLE_NODE:
1087 /* Nothing to do. */
1088 break;
1089 case CONFIG_NODE:
1090 case INTERFACE_NODE:
1091 case ZEBRA_NODE:
1092 case RIP_NODE:
1093 case RIPNG_NODE:
1094 case BGP_NODE:
1095 case RMAP_NODE:
1096 case OSPF_NODE:
1097 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00001098 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00001099 case KEYCHAIN_NODE:
1100 case KEYCHAIN_KEY_NODE:
1101 case MASC_NODE:
1102 case VTY_NODE:
1103 vty_config_unlock (vty);
1104 vty->node = ENABLE_NODE;
1105 break;
1106 default:
1107 /* Unknown node, we have to ignore it. */
1108 break;
1109 }
1110 vty_prompt (vty);
1111
1112 /* Set history pointer to the latest one. */
1113 vty->hp = vty->hindex;
1114}
1115
1116/* Add current command line to the history buffer. */
1117static void
1118vty_hist_add (struct vty *vty)
1119{
1120 int index;
1121
1122 if (vty->length == 0)
1123 return;
1124
1125 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1126
1127 /* Ignore the same string as previous one. */
1128 if (vty->hist[index])
1129 if (strcmp (vty->buf, vty->hist[index]) == 0)
1130 {
1131 vty->hp = vty->hindex;
1132 return;
1133 }
1134
1135 /* Insert history entry. */
1136 if (vty->hist[vty->hindex])
1137 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1138 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1139
1140 /* History index rotation. */
1141 vty->hindex++;
1142 if (vty->hindex == VTY_MAXHIST)
1143 vty->hindex = 0;
1144
1145 vty->hp = vty->hindex;
1146}
1147
1148/* #define TELNET_OPTION_DEBUG */
1149
1150/* Get telnet window size. */
1151static int
1152vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1153{
1154#ifdef TELNET_OPTION_DEBUG
1155 int i;
1156
1157 for (i = 0; i < nbytes; i++)
1158 {
1159 switch (buf[i])
1160 {
1161 case IAC:
1162 vty_out (vty, "IAC ");
1163 break;
1164 case WILL:
1165 vty_out (vty, "WILL ");
1166 break;
1167 case WONT:
1168 vty_out (vty, "WONT ");
1169 break;
1170 case DO:
1171 vty_out (vty, "DO ");
1172 break;
1173 case DONT:
1174 vty_out (vty, "DONT ");
1175 break;
1176 case SB:
1177 vty_out (vty, "SB ");
1178 break;
1179 case SE:
1180 vty_out (vty, "SE ");
1181 break;
1182 case TELOPT_ECHO:
1183 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1184 break;
1185 case TELOPT_SGA:
1186 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1187 break;
1188 case TELOPT_NAWS:
1189 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1190 break;
1191 default:
1192 vty_out (vty, "%x ", buf[i]);
1193 break;
1194 }
1195 }
1196 vty_out (vty, "%s", VTY_NEWLINE);
1197
1198#endif /* TELNET_OPTION_DEBUG */
1199
1200 switch (buf[0])
1201 {
1202 case SB:
ajs9fc7ebf2005-02-23 15:12:34 +00001203 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001204 vty->iac_sb_in_progress = 1;
1205 return 0;
1206 break;
1207 case SE:
1208 {
paul718e3742002-12-13 20:15:29 +00001209 if (!vty->iac_sb_in_progress)
1210 return 0;
1211
ajs9fc7ebf2005-02-23 15:12:34 +00001212 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
paul718e3742002-12-13 20:15:29 +00001213 {
1214 vty->iac_sb_in_progress = 0;
1215 return 0;
1216 }
ajs9fc7ebf2005-02-23 15:12:34 +00001217 switch (vty->sb_buf[0])
paul718e3742002-12-13 20:15:29 +00001218 {
1219 case TELOPT_NAWS:
ajs9fc7ebf2005-02-23 15:12:34 +00001220 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1221 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1222 "should send %d characters, but we received %lu",
1223 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1224 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1225 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1226 "too small to handle the telnet NAWS option",
1227 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1228 else
1229 {
1230 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1231 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1232#ifdef TELNET_OPTION_DEBUG
1233 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1234 "width %d, height %d%s",
1235 vty->width, vty->height, VTY_NEWLINE);
1236#endif
1237 }
paul718e3742002-12-13 20:15:29 +00001238 break;
1239 }
1240 vty->iac_sb_in_progress = 0;
1241 return 0;
1242 break;
1243 }
1244 default:
1245 break;
1246 }
1247 return 1;
1248}
1249
1250/* Execute current command line. */
1251static int
1252vty_execute (struct vty *vty)
1253{
1254 int ret;
1255
1256 ret = CMD_SUCCESS;
1257
1258 switch (vty->node)
1259 {
1260 case AUTH_NODE:
1261 case AUTH_ENABLE_NODE:
1262 vty_auth (vty, vty->buf);
1263 break;
1264 default:
1265 ret = vty_command (vty, vty->buf);
1266 if (vty->type == VTY_TERM)
1267 vty_hist_add (vty);
1268 break;
1269 }
1270
1271 /* Clear command line buffer. */
1272 vty->cp = vty->length = 0;
1273 vty_clear_buf (vty);
1274
ajs5a646652004-11-05 01:25:55 +00001275 if (vty->status != VTY_CLOSE )
paul718e3742002-12-13 20:15:29 +00001276 vty_prompt (vty);
1277
1278 return ret;
1279}
1280
1281#define CONTROL(X) ((X) - '@')
1282#define VTY_NORMAL 0
1283#define VTY_PRE_ESCAPE 1
1284#define VTY_ESCAPE 2
1285
1286/* Escape character command map. */
1287static void
1288vty_escape_map (unsigned char c, struct vty *vty)
1289{
1290 switch (c)
1291 {
1292 case ('A'):
1293 vty_previous_line (vty);
1294 break;
1295 case ('B'):
1296 vty_next_line (vty);
1297 break;
1298 case ('C'):
1299 vty_forward_char (vty);
1300 break;
1301 case ('D'):
1302 vty_backward_char (vty);
1303 break;
1304 default:
1305 break;
1306 }
1307
1308 /* Go back to normal mode. */
1309 vty->escape = VTY_NORMAL;
1310}
1311
1312/* Quit print out to the buffer. */
1313static void
1314vty_buffer_reset (struct vty *vty)
1315{
1316 buffer_reset (vty->obuf);
1317 vty_prompt (vty);
1318 vty_redraw_line (vty);
1319}
1320
1321/* Read data via vty socket. */
1322static int
1323vty_read (struct thread *thread)
1324{
1325 int i;
paul718e3742002-12-13 20:15:29 +00001326 int nbytes;
1327 unsigned char buf[VTY_READ_BUFSIZ];
1328
1329 int vty_sock = THREAD_FD (thread);
1330 struct vty *vty = THREAD_ARG (thread);
1331 vty->t_read = NULL;
1332
1333 /* Read raw data from socket */
ajs9fc7ebf2005-02-23 15:12:34 +00001334 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1335 {
1336 if (nbytes < 0)
1337 {
1338 if (ERRNO_IO_RETRY(errno))
1339 {
1340 vty_event (VTY_READ, vty_sock, vty);
1341 return 0;
1342 }
1343 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1344 __func__, vty->fd, safe_strerror(errno));
1345 }
1346 buffer_reset(vty->obuf);
1347 vty->status = VTY_CLOSE;
1348 }
paul718e3742002-12-13 20:15:29 +00001349
1350 for (i = 0; i < nbytes; i++)
1351 {
1352 if (buf[i] == IAC)
1353 {
1354 if (!vty->iac)
1355 {
1356 vty->iac = 1;
1357 continue;
1358 }
1359 else
1360 {
1361 vty->iac = 0;
1362 }
1363 }
1364
1365 if (vty->iac_sb_in_progress && !vty->iac)
1366 {
ajs9fc7ebf2005-02-23 15:12:34 +00001367 if (vty->sb_len < sizeof(vty->sb_buf))
1368 vty->sb_buf[vty->sb_len] = buf[i];
1369 vty->sb_len++;
paul718e3742002-12-13 20:15:29 +00001370 continue;
1371 }
1372
1373 if (vty->iac)
1374 {
1375 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001376 int ret = 0;
paule9372532003-10-26 21:36:07 +00001377 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001378 vty->iac = 0;
1379 i += ret;
1380 continue;
1381 }
paul5b8c1b02003-10-15 23:08:55 +00001382
paul718e3742002-12-13 20:15:29 +00001383
1384 if (vty->status == VTY_MORE)
1385 {
1386 switch (buf[i])
1387 {
1388 case CONTROL('C'):
1389 case 'q':
1390 case 'Q':
paul718e3742002-12-13 20:15:29 +00001391 vty_buffer_reset (vty);
1392 break;
1393#if 0 /* More line does not work for "show ip bgp". */
1394 case '\n':
1395 case '\r':
1396 vty->status = VTY_MORELINE;
1397 break;
1398#endif
1399 default:
paul718e3742002-12-13 20:15:29 +00001400 break;
1401 }
1402 continue;
1403 }
1404
1405 /* Escape character. */
1406 if (vty->escape == VTY_ESCAPE)
1407 {
1408 vty_escape_map (buf[i], vty);
1409 continue;
1410 }
1411
1412 /* Pre-escape status. */
1413 if (vty->escape == VTY_PRE_ESCAPE)
1414 {
1415 switch (buf[i])
1416 {
1417 case '[':
1418 vty->escape = VTY_ESCAPE;
1419 break;
1420 case 'b':
1421 vty_backward_word (vty);
1422 vty->escape = VTY_NORMAL;
1423 break;
1424 case 'f':
1425 vty_forward_word (vty);
1426 vty->escape = VTY_NORMAL;
1427 break;
1428 case 'd':
1429 vty_forward_kill_word (vty);
1430 vty->escape = VTY_NORMAL;
1431 break;
1432 case CONTROL('H'):
1433 case 0x7f:
1434 vty_backward_kill_word (vty);
1435 vty->escape = VTY_NORMAL;
1436 break;
1437 default:
1438 vty->escape = VTY_NORMAL;
1439 break;
1440 }
1441 continue;
1442 }
1443
1444 switch (buf[i])
1445 {
1446 case CONTROL('A'):
1447 vty_beginning_of_line (vty);
1448 break;
1449 case CONTROL('B'):
1450 vty_backward_char (vty);
1451 break;
1452 case CONTROL('C'):
1453 vty_stop_input (vty);
1454 break;
1455 case CONTROL('D'):
1456 vty_delete_char (vty);
1457 break;
1458 case CONTROL('E'):
1459 vty_end_of_line (vty);
1460 break;
1461 case CONTROL('F'):
1462 vty_forward_char (vty);
1463 break;
1464 case CONTROL('H'):
1465 case 0x7f:
1466 vty_delete_backward_char (vty);
1467 break;
1468 case CONTROL('K'):
1469 vty_kill_line (vty);
1470 break;
1471 case CONTROL('N'):
1472 vty_next_line (vty);
1473 break;
1474 case CONTROL('P'):
1475 vty_previous_line (vty);
1476 break;
1477 case CONTROL('T'):
1478 vty_transpose_chars (vty);
1479 break;
1480 case CONTROL('U'):
1481 vty_kill_line_from_beginning (vty);
1482 break;
1483 case CONTROL('W'):
1484 vty_backward_kill_word (vty);
1485 break;
1486 case CONTROL('Z'):
1487 vty_end_config (vty);
1488 break;
1489 case '\n':
1490 case '\r':
1491 vty_out (vty, "%s", VTY_NEWLINE);
1492 vty_execute (vty);
1493 break;
1494 case '\t':
1495 vty_complete_command (vty);
1496 break;
1497 case '?':
1498 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1499 vty_self_insert (vty, buf[i]);
1500 else
1501 vty_describe_command (vty);
1502 break;
1503 case '\033':
1504 if (i + 1 < nbytes && buf[i + 1] == '[')
1505 {
1506 vty->escape = VTY_ESCAPE;
1507 i++;
1508 }
1509 else
1510 vty->escape = VTY_PRE_ESCAPE;
1511 break;
1512 default:
1513 if (buf[i] > 31 && buf[i] < 127)
1514 vty_self_insert (vty, buf[i]);
1515 break;
1516 }
1517 }
1518
1519 /* Check status. */
1520 if (vty->status == VTY_CLOSE)
1521 vty_close (vty);
1522 else
1523 {
1524 vty_event (VTY_WRITE, vty_sock, vty);
1525 vty_event (VTY_READ, vty_sock, vty);
1526 }
1527 return 0;
1528}
1529
1530/* Flush buffer to the vty. */
1531static int
1532vty_flush (struct thread *thread)
1533{
1534 int erase;
ajs9fc7ebf2005-02-23 15:12:34 +00001535 buffer_status_t flushrc;
paul718e3742002-12-13 20:15:29 +00001536 int vty_sock = THREAD_FD (thread);
1537 struct vty *vty = THREAD_ARG (thread);
ajs9fc7ebf2005-02-23 15:12:34 +00001538
paul718e3742002-12-13 20:15:29 +00001539 vty->t_write = NULL;
1540
1541 /* Tempolary disable read thread. */
ajs9fc7ebf2005-02-23 15:12:34 +00001542 if ((vty->lines == 0) && vty->t_read)
1543 {
1544 thread_cancel (vty->t_read);
1545 vty->t_read = NULL;
1546 }
paul718e3742002-12-13 20:15:29 +00001547
1548 /* Function execution continue. */
ajs9fc7ebf2005-02-23 15:12:34 +00001549 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
paul718e3742002-12-13 20:15:29 +00001550
ajs9fc7ebf2005-02-23 15:12:34 +00001551 /* N.B. if width is 0, that means we don't know the window size. */
1552 if ((vty->lines == 0) || (vty->width == 0))
1553 flushrc = buffer_flush_available(vty->obuf, vty->fd);
1554 else if (vty->status == VTY_MORELINE)
1555 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1556 1, erase, 0);
1557 else
1558 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1559 vty->lines >= 0 ? vty->lines :
1560 vty->height,
1561 erase, 0);
1562 switch (flushrc)
1563 {
1564 case BUFFER_ERROR:
1565 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1566 vty->fd);
1567 buffer_reset(vty->obuf);
1568 vty_close(vty);
1569 return 0;
1570 case BUFFER_EMPTY:
1571 if (vty->status == VTY_CLOSE)
1572 vty_close (vty);
paul718e3742002-12-13 20:15:29 +00001573 else
1574 {
ajs9fc7ebf2005-02-23 15:12:34 +00001575 vty->status = VTY_NORMAL;
paul718e3742002-12-13 20:15:29 +00001576 if (vty->lines == 0)
ajs9fc7ebf2005-02-23 15:12:34 +00001577 vty_event (VTY_READ, vty_sock, vty);
paul718e3742002-12-13 20:15:29 +00001578 }
ajs9fc7ebf2005-02-23 15:12:34 +00001579 break;
1580 case BUFFER_PENDING:
1581 /* There is more data waiting to be written. */
1582 vty->status = VTY_MORE;
1583 if (vty->lines == 0)
1584 vty_event (VTY_WRITE, vty_sock, vty);
1585 break;
1586 }
paul718e3742002-12-13 20:15:29 +00001587
1588 return 0;
1589}
1590
1591/* Create new vty structure. */
ajs9fc7ebf2005-02-23 15:12:34 +00001592static struct vty *
paul718e3742002-12-13 20:15:29 +00001593vty_create (int vty_sock, union sockunion *su)
1594{
1595 struct vty *vty;
1596
1597 /* Allocate new vty structure and set up default values. */
1598 vty = vty_new ();
1599 vty->fd = vty_sock;
1600 vty->type = VTY_TERM;
1601 vty->address = sockunion_su2str (su);
1602 if (no_password_check)
1603 {
1604 if (host.advanced)
1605 vty->node = ENABLE_NODE;
1606 else
1607 vty->node = VIEW_NODE;
1608 }
1609 else
1610 vty->node = AUTH_NODE;
1611 vty->fail = 0;
1612 vty->cp = 0;
1613 vty_clear_buf (vty);
1614 vty->length = 0;
1615 memset (vty->hist, 0, sizeof (vty->hist));
1616 vty->hp = 0;
1617 vty->hindex = 0;
1618 vector_set_index (vtyvec, vty_sock, vty);
1619 vty->status = VTY_NORMAL;
1620 vty->v_timeout = vty_timeout_val;
1621 if (host.lines >= 0)
1622 vty->lines = host.lines;
1623 else
1624 vty->lines = -1;
1625 vty->iac = 0;
1626 vty->iac_sb_in_progress = 0;
ajs9fc7ebf2005-02-23 15:12:34 +00001627 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001628
1629 if (! no_password_check)
1630 {
1631 /* Vty is not available if password isn't set. */
1632 if (host.password == NULL && host.password_encrypt == NULL)
1633 {
1634 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1635 vty->status = VTY_CLOSE;
1636 vty_close (vty);
1637 return NULL;
1638 }
1639 }
1640
1641 /* Say hello to the world. */
1642 vty_hello (vty);
1643 if (! no_password_check)
1644 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1645
1646 /* Setting up terminal. */
1647 vty_will_echo (vty);
1648 vty_will_suppress_go_ahead (vty);
1649
1650 vty_dont_linemode (vty);
1651 vty_do_window_size (vty);
1652 /* vty_dont_lflow_ahead (vty); */
1653
1654 vty_prompt (vty);
1655
1656 /* Add read/write thread. */
1657 vty_event (VTY_WRITE, vty_sock, vty);
1658 vty_event (VTY_READ, vty_sock, vty);
1659
1660 return vty;
1661}
1662
1663/* Accept connection from the network. */
1664static int
1665vty_accept (struct thread *thread)
1666{
1667 int vty_sock;
1668 struct vty *vty;
1669 union sockunion su;
1670 int ret;
1671 unsigned int on;
1672 int accept_sock;
1673 struct prefix *p = NULL;
1674 struct access_list *acl = NULL;
1675
1676 accept_sock = THREAD_FD (thread);
1677
1678 /* We continue hearing vty socket. */
1679 vty_event (VTY_SERV, accept_sock, NULL);
1680
1681 memset (&su, 0, sizeof (union sockunion));
1682
1683 /* We can handle IPv4 or IPv6 socket. */
1684 vty_sock = sockunion_accept (accept_sock, &su);
1685 if (vty_sock < 0)
1686 {
ajs6099b3b2004-11-20 02:06:59 +00001687 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001688 return -1;
1689 }
ajs9fc7ebf2005-02-23 15:12:34 +00001690 set_nonblocking(vty_sock);
paul718e3742002-12-13 20:15:29 +00001691
1692 p = sockunion2hostprefix (&su);
1693
1694 /* VTY's accesslist apply. */
1695 if (p->family == AF_INET && vty_accesslist_name)
1696 {
1697 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1698 (access_list_apply (acl, p) == FILTER_DENY))
1699 {
1700 char *buf;
1701 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1702 (buf = sockunion_su2str (&su)));
1703 free (buf);
1704 close (vty_sock);
1705
1706 /* continue accepting connections */
1707 vty_event (VTY_SERV, accept_sock, NULL);
1708
1709 prefix_free (p);
1710
1711 return 0;
1712 }
1713 }
1714
1715#ifdef HAVE_IPV6
1716 /* VTY's ipv6 accesslist apply. */
1717 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1718 {
1719 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1720 (access_list_apply (acl, p) == FILTER_DENY))
1721 {
1722 char *buf;
1723 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1724 (buf = sockunion_su2str (&su)));
1725 free (buf);
1726 close (vty_sock);
1727
1728 /* continue accepting connections */
1729 vty_event (VTY_SERV, accept_sock, NULL);
1730
1731 prefix_free (p);
1732
1733 return 0;
1734 }
1735 }
1736#endif /* HAVE_IPV6 */
1737
1738 prefix_free (p);
1739
1740 on = 1;
1741 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1742 (char *) &on, sizeof (on));
1743 if (ret < 0)
1744 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
ajs6099b3b2004-11-20 02:06:59 +00001745 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001746
1747 vty = vty_create (vty_sock, &su);
1748
1749 return 0;
1750}
1751
1752#if defined(HAVE_IPV6) && !defined(NRL)
ajs9fc7ebf2005-02-23 15:12:34 +00001753static void
paul718e3742002-12-13 20:15:29 +00001754vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1755{
1756 int ret;
1757 struct addrinfo req;
1758 struct addrinfo *ainfo;
1759 struct addrinfo *ainfo_save;
1760 int sock;
1761 char port_str[BUFSIZ];
1762
1763 memset (&req, 0, sizeof (struct addrinfo));
1764 req.ai_flags = AI_PASSIVE;
1765 req.ai_family = AF_UNSPEC;
1766 req.ai_socktype = SOCK_STREAM;
1767 sprintf (port_str, "%d", port);
1768 port_str[sizeof (port_str) - 1] = '\0';
1769
1770 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1771
1772 if (ret != 0)
1773 {
1774 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1775 exit (1);
1776 }
1777
1778 ainfo_save = ainfo;
1779
1780 do
1781 {
1782 if (ainfo->ai_family != AF_INET
1783#ifdef HAVE_IPV6
1784 && ainfo->ai_family != AF_INET6
1785#endif /* HAVE_IPV6 */
1786 )
1787 continue;
1788
1789 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1790 if (sock < 0)
1791 continue;
1792
1793 sockopt_reuseaddr (sock);
1794 sockopt_reuseport (sock);
1795
1796 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1797 if (ret < 0)
1798 {
1799 close (sock); /* Avoid sd leak. */
1800 continue;
1801 }
1802
1803 ret = listen (sock, 3);
1804 if (ret < 0)
1805 {
1806 close (sock); /* Avoid sd leak. */
1807 continue;
1808 }
1809
1810 vty_event (VTY_SERV, sock, NULL);
1811 }
1812 while ((ainfo = ainfo->ai_next) != NULL);
1813
1814 freeaddrinfo (ainfo_save);
1815}
1816#endif /* HAVE_IPV6 && ! NRL */
1817
1818/* Make vty server socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001819static void
paul29db05b2003-05-08 20:10:22 +00001820vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001821{
1822 int ret;
1823 union sockunion su;
1824 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001825 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001826
1827 memset (&su, 0, sizeof (union sockunion));
1828 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001829 if(addr)
1830 switch(family)
1831 {
1832 case AF_INET:
1833 naddr=&su.sin.sin_addr;
1834#ifdef HAVE_IPV6
1835 case AF_INET6:
1836 naddr=&su.sin6.sin6_addr;
1837#endif
1838 }
1839
1840 if(naddr)
1841 switch(inet_pton(family,addr,naddr))
1842 {
1843 case -1:
1844 zlog_err("bad address %s",addr);
1845 naddr=NULL;
1846 break;
1847 case 0:
ajs6099b3b2004-11-20 02:06:59 +00001848 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
paul29db05b2003-05-08 20:10:22 +00001849 naddr=NULL;
1850 }
paul718e3742002-12-13 20:15:29 +00001851
1852 /* Make new socket. */
1853 accept_sock = sockunion_stream_socket (&su);
1854 if (accept_sock < 0)
1855 return;
1856
1857 /* This is server, so reuse address. */
1858 sockopt_reuseaddr (accept_sock);
1859 sockopt_reuseport (accept_sock);
1860
1861 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001862 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001863 if (ret < 0)
1864 {
paul29db05b2003-05-08 20:10:22 +00001865 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001866 close (accept_sock); /* Avoid sd leak. */
1867 return;
1868 }
1869
1870 /* Listen socket under queue 3. */
1871 ret = listen (accept_sock, 3);
1872 if (ret < 0)
1873 {
1874 zlog (NULL, LOG_WARNING, "can't listen socket");
1875 close (accept_sock); /* Avoid sd leak. */
1876 return;
1877 }
1878
1879 /* Add vty server event. */
1880 vty_event (VTY_SERV, accept_sock, NULL);
1881}
1882
1883#ifdef VTYSH
1884/* For sockaddr_un. */
1885#include <sys/un.h>
1886
1887/* VTY shell UNIX domain socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001888static void
hasso6ad96ea2004-10-07 19:33:46 +00001889vty_serv_un (const char *path)
paul718e3742002-12-13 20:15:29 +00001890{
1891 int ret;
paul75e15fe2004-10-31 02:13:09 +00001892 int sock, len;
paul718e3742002-12-13 20:15:29 +00001893 struct sockaddr_un serv;
1894 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00001895 struct zprivs_ids_t ids;
1896
paul718e3742002-12-13 20:15:29 +00001897 /* First of all, unlink existing socket */
1898 unlink (path);
1899
1900 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00001901 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00001902
1903 /* Make UNIX domain socket. */
1904 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1905 if (sock < 0)
1906 {
ajs6a52d0d2005-01-30 18:49:28 +00001907 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001908 return;
1909 }
1910
1911 /* Make server socket. */
1912 memset (&serv, 0, sizeof (struct sockaddr_un));
1913 serv.sun_family = AF_UNIX;
1914 strncpy (serv.sun_path, path, strlen (path));
1915#ifdef HAVE_SUN_LEN
1916 len = serv.sun_len = SUN_LEN(&serv);
1917#else
1918 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1919#endif /* HAVE_SUN_LEN */
1920
1921 ret = bind (sock, (struct sockaddr *) &serv, len);
1922 if (ret < 0)
1923 {
ajs6a52d0d2005-01-30 18:49:28 +00001924 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001925 close (sock); /* Avoid sd leak. */
1926 return;
1927 }
1928
1929 ret = listen (sock, 5);
1930 if (ret < 0)
1931 {
ajs6a52d0d2005-01-30 18:49:28 +00001932 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001933 close (sock); /* Avoid sd leak. */
1934 return;
1935 }
1936
1937 umask (old_mask);
1938
pauledd7c242003-06-04 13:59:38 +00001939 zprivs_get_ids(&ids);
1940
1941 if (ids.gid_vty > 0)
1942 {
1943 /* set group of socket */
1944 if ( chown (path, -1, ids.gid_vty) )
1945 {
1946 zlog_err ("vty_serv_un: could chown socket, %s",
ajs6099b3b2004-11-20 02:06:59 +00001947 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +00001948 }
1949 }
1950
paul718e3742002-12-13 20:15:29 +00001951 vty_event (VTYSH_SERV, sock, NULL);
1952}
1953
1954/* #define VTYSH_DEBUG 1 */
1955
1956static int
1957vtysh_accept (struct thread *thread)
1958{
1959 int accept_sock;
1960 int sock;
1961 int client_len;
1962 struct sockaddr_un client;
1963 struct vty *vty;
1964
1965 accept_sock = THREAD_FD (thread);
1966
1967 vty_event (VTYSH_SERV, accept_sock, NULL);
1968
1969 memset (&client, 0, sizeof (struct sockaddr_un));
1970 client_len = sizeof (struct sockaddr_un);
1971
hassoe473b032004-09-26 16:08:11 +00001972 sock = accept (accept_sock, (struct sockaddr *) &client,
1973 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00001974
1975 if (sock < 0)
1976 {
ajs6099b3b2004-11-20 02:06:59 +00001977 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001978 return -1;
1979 }
1980
ajs9fc7ebf2005-02-23 15:12:34 +00001981 if (set_nonblocking(sock) < 0)
paul75e15fe2004-10-31 02:13:09 +00001982 {
ajs9fc7ebf2005-02-23 15:12:34 +00001983 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
1984 " %s, closing", sock, safe_strerror (errno));
paul75e15fe2004-10-31 02:13:09 +00001985 close (sock);
1986 return -1;
1987 }
pauldccfb192004-10-29 08:29:36 +00001988
paul718e3742002-12-13 20:15:29 +00001989#ifdef VTYSH_DEBUG
1990 printf ("VTY shell accept\n");
1991#endif /* VTYSH_DEBUG */
1992
1993 vty = vty_new ();
1994 vty->fd = sock;
1995 vty->type = VTY_SHELL_SERV;
1996 vty->node = VIEW_NODE;
1997
1998 vty_event (VTYSH_READ, sock, vty);
1999
2000 return 0;
2001}
2002
2003static int
ajs9fc7ebf2005-02-23 15:12:34 +00002004vtysh_flush(struct vty *vty)
2005{
2006 switch (buffer_flush_available(vty->obuf, vty->fd))
2007 {
2008 case BUFFER_PENDING:
2009 vty_event(VTYSH_WRITE, vty->fd, vty);
2010 break;
2011 case BUFFER_ERROR:
2012 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
2013 buffer_reset(vty->obuf);
2014 vty_close(vty);
2015 return -1;
2016 break;
2017 case BUFFER_EMPTY:
2018 break;
2019 }
2020 return 0;
2021}
2022
2023static int
paul718e3742002-12-13 20:15:29 +00002024vtysh_read (struct thread *thread)
2025{
2026 int ret;
2027 int sock;
2028 int nbytes;
2029 struct vty *vty;
2030 unsigned char buf[VTY_READ_BUFSIZ];
ajs9fc7ebf2005-02-23 15:12:34 +00002031 unsigned char *p;
paul718e3742002-12-13 20:15:29 +00002032 u_char header[4] = {0, 0, 0, 0};
2033
2034 sock = THREAD_FD (thread);
2035 vty = THREAD_ARG (thread);
2036 vty->t_read = NULL;
2037
ajs9fc7ebf2005-02-23 15:12:34 +00002038 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
paul718e3742002-12-13 20:15:29 +00002039 {
ajs9fc7ebf2005-02-23 15:12:34 +00002040 if (nbytes < 0)
2041 {
2042 if (ERRNO_IO_RETRY(errno))
2043 {
2044 vty_event (VTYSH_READ, sock, vty);
2045 return 0;
2046 }
2047 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2048 __func__, sock, safe_strerror(errno));
2049 }
2050 buffer_reset(vty->obuf);
paul718e3742002-12-13 20:15:29 +00002051 vty_close (vty);
2052#ifdef VTYSH_DEBUG
2053 printf ("close vtysh\n");
2054#endif /* VTYSH_DEBUG */
2055 return 0;
2056 }
2057
2058#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002059 printf ("line: %.*s\n", nbytes, buf);
paul718e3742002-12-13 20:15:29 +00002060#endif /* VTYSH_DEBUG */
2061
ajs9fc7ebf2005-02-23 15:12:34 +00002062 for (p = buf; p < buf+nbytes; p++)
2063 {
2064 vty_ensure(vty, vty->length+1);
2065 vty->buf[vty->length++] = *p;
2066 if (*p == '\0')
2067 {
2068 /* Pass this line to parser. */
2069 ret = vty_execute (vty);
2070 /* Note that vty_execute clears the command buffer and resets
2071 vty->length to 0. */
paul718e3742002-12-13 20:15:29 +00002072
ajs9fc7ebf2005-02-23 15:12:34 +00002073 /* Return result. */
paul718e3742002-12-13 20:15:29 +00002074#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002075 printf ("result: %d\n", ret);
2076 printf ("vtysh node: %d\n", vty->node);
paul718e3742002-12-13 20:15:29 +00002077#endif /* VTYSH_DEBUG */
2078
ajs9fc7ebf2005-02-23 15:12:34 +00002079 header[3] = ret;
2080 buffer_put(vty->obuf, header, 4);
paul718e3742002-12-13 20:15:29 +00002081
ajs9fc7ebf2005-02-23 15:12:34 +00002082 if (!vty->t_write && (vtysh_flush(vty) < 0))
2083 /* Try to flush results; exit if a write error occurs. */
2084 return 0;
2085 }
2086 }
2087
paul718e3742002-12-13 20:15:29 +00002088 vty_event (VTYSH_READ, sock, vty);
2089
2090 return 0;
2091}
ajs49ff6d92004-11-04 19:26:16 +00002092
2093static int
2094vtysh_write (struct thread *thread)
2095{
2096 struct vty *vty = THREAD_ARG (thread);
2097
2098 vty->t_write = NULL;
ajs9fc7ebf2005-02-23 15:12:34 +00002099 vtysh_flush(vty);
ajs976d8c72004-11-10 15:40:09 +00002100 return 0;
ajs49ff6d92004-11-04 19:26:16 +00002101}
2102
paul718e3742002-12-13 20:15:29 +00002103#endif /* VTYSH */
2104
2105/* Determine address family to bind. */
2106void
hasso6ad96ea2004-10-07 19:33:46 +00002107vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002108{
2109 /* If port is set to 0, do not listen on TCP/IP at all! */
2110 if (port)
2111 {
2112
2113#ifdef HAVE_IPV6
2114#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002115 vty_serv_sock_family (addr, port, AF_INET);
2116 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002117#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002118 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002119#endif /* NRL*/
2120#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002121 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002122#endif /* HAVE_IPV6 */
2123 }
2124
2125#ifdef VTYSH
2126 vty_serv_un (path);
2127#endif /* VTYSH */
2128}
2129
2130/* Close vty interface. */
2131void
2132vty_close (struct vty *vty)
2133{
2134 int i;
2135
2136 /* Cancel threads.*/
2137 if (vty->t_read)
2138 thread_cancel (vty->t_read);
2139 if (vty->t_write)
2140 thread_cancel (vty->t_write);
2141 if (vty->t_timeout)
2142 thread_cancel (vty->t_timeout);
paul718e3742002-12-13 20:15:29 +00002143
2144 /* Flush buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +00002145 buffer_flush_all (vty->obuf, vty->fd);
paul718e3742002-12-13 20:15:29 +00002146
2147 /* Free input buffer. */
2148 buffer_free (vty->obuf);
2149
paul718e3742002-12-13 20:15:29 +00002150 /* Free command history. */
2151 for (i = 0; i < VTY_MAXHIST; i++)
2152 if (vty->hist[i])
2153 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2154
2155 /* Unset vector. */
2156 vector_unset (vtyvec, vty->fd);
2157
2158 /* Close socket. */
2159 if (vty->fd > 0)
2160 close (vty->fd);
2161
2162 if (vty->address)
2163 XFREE (0, vty->address);
2164 if (vty->buf)
2165 XFREE (MTYPE_VTY, vty->buf);
2166
2167 /* Check configure. */
2168 vty_config_unlock (vty);
2169
2170 /* OK free vty. */
2171 XFREE (MTYPE_VTY, vty);
2172}
2173
2174/* When time out occur output message then close connection. */
2175static int
2176vty_timeout (struct thread *thread)
2177{
2178 struct vty *vty;
2179
2180 vty = THREAD_ARG (thread);
2181 vty->t_timeout = NULL;
2182 vty->v_timeout = 0;
2183
2184 /* Clear buffer*/
2185 buffer_reset (vty->obuf);
2186 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2187
2188 /* Close connection. */
2189 vty->status = VTY_CLOSE;
2190 vty_close (vty);
2191
2192 return 0;
2193}
2194
2195/* Read up configuration file from file_name. */
2196static void
2197vty_read_file (FILE *confp)
2198{
2199 int ret;
2200 struct vty *vty;
2201
2202 vty = vty_new ();
2203 vty->fd = 0; /* stdout */
2204 vty->type = VTY_TERM;
2205 vty->node = CONFIG_NODE;
2206
2207 /* Execute configuration file */
2208 ret = config_from_file (vty, confp);
2209
paul7021c422003-07-15 12:52:22 +00002210 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002211 {
2212 switch (ret)
paul7021c422003-07-15 12:52:22 +00002213 {
2214 case CMD_ERR_AMBIGUOUS:
2215 fprintf (stderr, "Ambiguous command.\n");
2216 break;
2217 case CMD_ERR_NO_MATCH:
2218 fprintf (stderr, "There is no such command.\n");
2219 break;
2220 }
paul718e3742002-12-13 20:15:29 +00002221 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2222 vty->buf);
2223 vty_close (vty);
2224 exit (1);
2225 }
2226
2227 vty_close (vty);
2228}
2229
ajs9fc7ebf2005-02-23 15:12:34 +00002230static FILE *
paul718e3742002-12-13 20:15:29 +00002231vty_use_backup_config (char *fullpath)
2232{
2233 char *fullpath_sav, *fullpath_tmp;
2234 FILE *ret = NULL;
2235 struct stat buf;
2236 int tmp, sav;
2237 int c;
2238 char buffer[512];
2239
2240 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2241 strcpy (fullpath_sav, fullpath);
2242 strcat (fullpath_sav, CONF_BACKUP_EXT);
2243 if (stat (fullpath_sav, &buf) == -1)
2244 {
2245 free (fullpath_sav);
2246 return NULL;
2247 }
2248
2249 fullpath_tmp = malloc (strlen (fullpath) + 8);
2250 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2251
2252 /* Open file to configuration write. */
2253 tmp = mkstemp (fullpath_tmp);
2254 if (tmp < 0)
2255 {
2256 free (fullpath_sav);
2257 free (fullpath_tmp);
2258 return NULL;
2259 }
2260
2261 sav = open (fullpath_sav, O_RDONLY);
2262 if (sav < 0)
2263 {
gdt3dbf9962003-12-22 20:18:18 +00002264 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002265 free (fullpath_sav);
2266 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002267 return NULL;
2268 }
2269
2270 while((c = read (sav, buffer, 512)) > 0)
2271 write (tmp, buffer, c);
2272
2273 close (sav);
2274 close (tmp);
2275
gdtaa593d52003-12-22 20:15:53 +00002276 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2277 {
gdt3dbf9962003-12-22 20:18:18 +00002278 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002279 free (fullpath_sav);
2280 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002281 return NULL;
2282 }
2283
paul718e3742002-12-13 20:15:29 +00002284 if (link (fullpath_tmp, fullpath) == 0)
2285 ret = fopen (fullpath, "r");
2286
2287 unlink (fullpath_tmp);
2288
2289 free (fullpath_sav);
2290 free (fullpath_tmp);
hasso12f6ea22005-03-07 08:35:39 +00002291 return ret;
paul718e3742002-12-13 20:15:29 +00002292}
2293
2294/* Read up configuration file from file_name. */
2295void
2296vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002297 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002298{
paulccc92352003-10-22 02:49:38 +00002299 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002300 FILE *confp = NULL;
2301 char *fullpath;
2302
2303 /* If -f flag specified. */
2304 if (config_file != NULL)
2305 {
2306 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002307 {
2308 getcwd (cwd, MAXPATHLEN);
2309 fullpath = XMALLOC (MTYPE_TMP,
2310 strlen (cwd) + strlen (config_file) + 2);
2311 sprintf (fullpath, "%s/%s", cwd, config_file);
2312 }
paul718e3742002-12-13 20:15:29 +00002313 else
hasso320ec102004-06-20 19:54:37 +00002314 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002315
2316 confp = fopen (fullpath, "r");
2317
2318 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002319 {
paul3d1dc852005-04-05 00:45:23 +00002320 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2321 __func__, fullpath, safe_strerror (errno));
2322
hasso320ec102004-06-20 19:54:37 +00002323 confp = vty_use_backup_config (fullpath);
2324 if (confp)
2325 fprintf (stderr, "WARNING: using backup configuration file!\n");
2326 else
2327 {
2328 fprintf (stderr, "can't open configuration file [%s]\n",
paul3d1dc852005-04-05 00:45:23 +00002329 config_file);
hasso320ec102004-06-20 19:54:37 +00002330 exit(1);
2331 }
2332 }
paul718e3742002-12-13 20:15:29 +00002333 }
2334 else
2335 {
paul718e3742002-12-13 20:15:29 +00002336#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002337 int ret;
2338 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002339
hasso320ec102004-06-20 19:54:37 +00002340 /* !!!!PLEASE LEAVE!!!!
2341 * This is NEEDED for use with vtysh -b, or else you can get
2342 * a real configuration food fight with a lot garbage in the
2343 * merged configuration file it creates coming from the per
2344 * daemon configuration files. This also allows the daemons
2345 * to start if there default configuration file is not
2346 * present or ignore them, as needed when using vtysh -b to
2347 * configure the daemons at boot - MAG
2348 */
paul718e3742002-12-13 20:15:29 +00002349
hasso320ec102004-06-20 19:54:37 +00002350 /* Stat for vtysh Zebra.conf, if found startup and wait for
2351 * boot configuration
2352 */
paul718e3742002-12-13 20:15:29 +00002353
hasso320ec102004-06-20 19:54:37 +00002354 if ( strstr(config_default_dir, "vtysh") == NULL)
2355 {
2356 ret = stat (integrate_default, &conf_stat);
2357 if (ret >= 0)
2358 return;
2359 }
paul718e3742002-12-13 20:15:29 +00002360#endif /* VTYSH */
2361
hasso320ec102004-06-20 19:54:37 +00002362 confp = fopen (config_default_dir, "r");
2363 if (confp == NULL)
2364 {
paul3d1dc852005-04-05 00:45:23 +00002365 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2366 __func__, config_default_dir, safe_strerror (errno));
2367
hasso320ec102004-06-20 19:54:37 +00002368 confp = vty_use_backup_config (config_default_dir);
2369 if (confp)
2370 {
2371 fprintf (stderr, "WARNING: using backup configuration file!\n");
2372 fullpath = config_default_dir;
2373 }
2374 else
2375 {
2376 fprintf (stderr, "can't open configuration file [%s]\n",
2377 config_default_dir);
2378 exit (1);
paul3d1dc852005-04-05 00:45:23 +00002379 }
hasso320ec102004-06-20 19:54:37 +00002380 }
paul718e3742002-12-13 20:15:29 +00002381 else
hasso320ec102004-06-20 19:54:37 +00002382 fullpath = config_default_dir;
2383 }
2384
paul718e3742002-12-13 20:15:29 +00002385 vty_read_file (confp);
2386
2387 fclose (confp);
2388
2389 host_config_set (fullpath);
2390}
2391
2392/* Small utility function which output log to the VTY. */
2393void
ajs274a4a42004-12-07 15:39:31 +00002394vty_log (const char *level, const char *proto_str,
2395 const char *format, va_list va)
paul718e3742002-12-13 20:15:29 +00002396{
hasso8c328f12004-10-05 21:01:23 +00002397 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002398 struct vty *vty;
2399
paul55468c82005-03-14 20:19:01 +00002400 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002401 if ((vty = vector_slot (vtyvec, i)) != NULL)
2402 if (vty->monitor)
ajsd246bd92004-11-23 17:35:08 +00002403 {
2404 va_list ac;
2405 va_copy(ac, va);
ajs274a4a42004-12-07 15:39:31 +00002406 vty_log_out (vty, level, proto_str, format, ac);
ajsd246bd92004-11-23 17:35:08 +00002407 va_end(ac);
2408 }
paul718e3742002-12-13 20:15:29 +00002409}
2410
ajs274a4a42004-12-07 15:39:31 +00002411/* Async-signal-safe version of vty_log for fixed strings. */
2412void
2413vty_log_fixed (const char *buf, size_t len)
2414{
2415 unsigned int i;
ajs9fc7ebf2005-02-23 15:12:34 +00002416 struct iovec iov[2];
2417
ajs926fe8f2005-04-08 18:50:40 +00002418 iov[0].iov_base = (void *)buf;
ajs9fc7ebf2005-02-23 15:12:34 +00002419 iov[0].iov_len = len;
ajs926fe8f2005-04-08 18:50:40 +00002420 iov[1].iov_base = (void *)"\r\n";
ajs9fc7ebf2005-02-23 15:12:34 +00002421 iov[1].iov_len = 2;
ajs274a4a42004-12-07 15:39:31 +00002422
paul55468c82005-03-14 20:19:01 +00002423 for (i = 0; i < vector_active (vtyvec); i++)
ajs274a4a42004-12-07 15:39:31 +00002424 {
2425 struct vty *vty;
ajs9fc7ebf2005-02-23 15:12:34 +00002426 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2427 /* N.B. We don't care about the return code, since process is
2428 most likely just about to die anyway. */
2429 writev(vty->fd, iov, 2);
ajs274a4a42004-12-07 15:39:31 +00002430 }
2431}
2432
paul718e3742002-12-13 20:15:29 +00002433int
2434vty_config_lock (struct vty *vty)
2435{
2436 if (vty_config == 0)
2437 {
2438 vty->config = 1;
2439 vty_config = 1;
2440 }
2441 return vty->config;
2442}
2443
2444int
2445vty_config_unlock (struct vty *vty)
2446{
2447 if (vty_config == 1 && vty->config == 1)
2448 {
2449 vty->config = 0;
2450 vty_config = 0;
2451 }
2452 return vty->config;
2453}
2454
2455/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002456static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002457
2458static void
2459vty_event (enum event event, int sock, struct vty *vty)
2460{
2461 struct thread *vty_serv_thread;
2462
2463 switch (event)
2464 {
2465 case VTY_SERV:
2466 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2467 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2468 break;
2469#ifdef VTYSH
2470 case VTYSH_SERV:
2471 thread_add_read (master, vtysh_accept, vty, sock);
2472 break;
2473 case VTYSH_READ:
ajs49ff6d92004-11-04 19:26:16 +00002474 vty->t_read = thread_add_read (master, vtysh_read, vty, sock);
2475 break;
2476 case VTYSH_WRITE:
2477 vty->t_write = thread_add_write (master, vtysh_write, vty, sock);
paul718e3742002-12-13 20:15:29 +00002478 break;
2479#endif /* VTYSH */
2480 case VTY_READ:
2481 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2482
2483 /* Time out treatment. */
2484 if (vty->v_timeout)
2485 {
2486 if (vty->t_timeout)
2487 thread_cancel (vty->t_timeout);
2488 vty->t_timeout =
2489 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2490 }
2491 break;
2492 case VTY_WRITE:
2493 if (! vty->t_write)
2494 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2495 break;
2496 case VTY_TIMEOUT_RESET:
2497 if (vty->t_timeout)
2498 {
2499 thread_cancel (vty->t_timeout);
2500 vty->t_timeout = NULL;
2501 }
2502 if (vty->v_timeout)
2503 {
2504 vty->t_timeout =
2505 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2506 }
2507 break;
2508 }
2509}
2510
2511DEFUN (config_who,
2512 config_who_cmd,
2513 "who",
2514 "Display who is on vty\n")
2515{
hasso8c328f12004-10-05 21:01:23 +00002516 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002517 struct vty *v;
2518
paul55468c82005-03-14 20:19:01 +00002519 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002520 if ((v = vector_slot (vtyvec, i)) != NULL)
2521 vty_out (vty, "%svty[%d] connected from %s.%s",
2522 v->config ? "*" : " ",
2523 i, v->address, VTY_NEWLINE);
2524 return CMD_SUCCESS;
2525}
2526
2527/* Move to vty configuration mode. */
2528DEFUN (line_vty,
2529 line_vty_cmd,
2530 "line vty",
2531 "Configure a terminal line\n"
2532 "Virtual terminal\n")
2533{
2534 vty->node = VTY_NODE;
2535 return CMD_SUCCESS;
2536}
2537
2538/* Set time out value. */
ajs9fc7ebf2005-02-23 15:12:34 +00002539static int
paul9035efa2004-10-10 11:56:56 +00002540exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002541{
2542 unsigned long timeout = 0;
2543
2544 /* min_str and sec_str are already checked by parser. So it must be
2545 all digit string. */
2546 if (min_str)
2547 {
2548 timeout = strtol (min_str, NULL, 10);
2549 timeout *= 60;
2550 }
2551 if (sec_str)
2552 timeout += strtol (sec_str, NULL, 10);
2553
2554 vty_timeout_val = timeout;
2555 vty->v_timeout = timeout;
2556 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2557
2558
2559 return CMD_SUCCESS;
2560}
2561
2562DEFUN (exec_timeout_min,
2563 exec_timeout_min_cmd,
2564 "exec-timeout <0-35791>",
2565 "Set timeout value\n"
2566 "Timeout value in minutes\n")
2567{
2568 return exec_timeout (vty, argv[0], NULL);
2569}
2570
2571DEFUN (exec_timeout_sec,
2572 exec_timeout_sec_cmd,
2573 "exec-timeout <0-35791> <0-2147483>",
2574 "Set the EXEC timeout\n"
2575 "Timeout in minutes\n"
2576 "Timeout in seconds\n")
2577{
2578 return exec_timeout (vty, argv[0], argv[1]);
2579}
2580
2581DEFUN (no_exec_timeout,
2582 no_exec_timeout_cmd,
2583 "no exec-timeout",
2584 NO_STR
2585 "Set the EXEC timeout\n")
2586{
2587 return exec_timeout (vty, NULL, NULL);
2588}
2589
2590/* Set vty access class. */
2591DEFUN (vty_access_class,
2592 vty_access_class_cmd,
2593 "access-class WORD",
2594 "Filter connections based on an IP access list\n"
2595 "IP access list\n")
2596{
2597 if (vty_accesslist_name)
2598 XFREE(MTYPE_VTY, vty_accesslist_name);
2599
2600 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2601
2602 return CMD_SUCCESS;
2603}
2604
2605/* Clear vty access class. */
2606DEFUN (no_vty_access_class,
2607 no_vty_access_class_cmd,
2608 "no access-class [WORD]",
2609 NO_STR
2610 "Filter connections based on an IP access list\n"
2611 "IP access list\n")
2612{
2613 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2614 {
2615 vty_out (vty, "Access-class is not currently applied to vty%s",
2616 VTY_NEWLINE);
2617 return CMD_WARNING;
2618 }
2619
2620 XFREE(MTYPE_VTY, vty_accesslist_name);
2621
2622 vty_accesslist_name = NULL;
2623
2624 return CMD_SUCCESS;
2625}
2626
2627#ifdef HAVE_IPV6
2628/* Set vty access class. */
2629DEFUN (vty_ipv6_access_class,
2630 vty_ipv6_access_class_cmd,
2631 "ipv6 access-class WORD",
2632 IPV6_STR
2633 "Filter connections based on an IP access list\n"
2634 "IPv6 access list\n")
2635{
2636 if (vty_ipv6_accesslist_name)
2637 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2638
2639 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2640
2641 return CMD_SUCCESS;
2642}
2643
2644/* Clear vty access class. */
2645DEFUN (no_vty_ipv6_access_class,
2646 no_vty_ipv6_access_class_cmd,
2647 "no ipv6 access-class [WORD]",
2648 NO_STR
2649 IPV6_STR
2650 "Filter connections based on an IP access list\n"
2651 "IPv6 access list\n")
2652{
2653 if (! vty_ipv6_accesslist_name ||
2654 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2655 {
2656 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2657 VTY_NEWLINE);
2658 return CMD_WARNING;
2659 }
2660
2661 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2662
2663 vty_ipv6_accesslist_name = NULL;
2664
2665 return CMD_SUCCESS;
2666}
2667#endif /* HAVE_IPV6 */
2668
2669/* vty login. */
2670DEFUN (vty_login,
2671 vty_login_cmd,
2672 "login",
2673 "Enable password checking\n")
2674{
2675 no_password_check = 0;
2676 return CMD_SUCCESS;
2677}
2678
2679DEFUN (no_vty_login,
2680 no_vty_login_cmd,
2681 "no login",
2682 NO_STR
2683 "Enable password checking\n")
2684{
2685 no_password_check = 1;
2686 return CMD_SUCCESS;
2687}
2688
2689DEFUN (service_advanced_vty,
2690 service_advanced_vty_cmd,
2691 "service advanced-vty",
2692 "Set up miscellaneous service\n"
2693 "Enable advanced mode vty interface\n")
2694{
2695 host.advanced = 1;
2696 return CMD_SUCCESS;
2697}
2698
2699DEFUN (no_service_advanced_vty,
2700 no_service_advanced_vty_cmd,
2701 "no service advanced-vty",
2702 NO_STR
2703 "Set up miscellaneous service\n"
2704 "Enable advanced mode vty interface\n")
2705{
2706 host.advanced = 0;
2707 return CMD_SUCCESS;
2708}
2709
2710DEFUN (terminal_monitor,
2711 terminal_monitor_cmd,
2712 "terminal monitor",
2713 "Set terminal line parameters\n"
2714 "Copy debug output to the current terminal line\n")
2715{
2716 vty->monitor = 1;
2717 return CMD_SUCCESS;
2718}
2719
2720DEFUN (terminal_no_monitor,
2721 terminal_no_monitor_cmd,
2722 "terminal no monitor",
2723 "Set terminal line parameters\n"
2724 NO_STR
2725 "Copy debug output to the current terminal line\n")
2726{
2727 vty->monitor = 0;
2728 return CMD_SUCCESS;
2729}
2730
2731DEFUN (show_history,
2732 show_history_cmd,
2733 "show history",
2734 SHOW_STR
2735 "Display the session command history\n")
2736{
2737 int index;
2738
2739 for (index = vty->hindex + 1; index != vty->hindex;)
2740 {
2741 if (index == VTY_MAXHIST)
2742 {
2743 index = 0;
2744 continue;
2745 }
2746
2747 if (vty->hist[index] != NULL)
2748 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2749
2750 index++;
2751 }
2752
2753 return CMD_SUCCESS;
2754}
2755
2756/* Display current configuration. */
ajs9fc7ebf2005-02-23 15:12:34 +00002757static int
paul718e3742002-12-13 20:15:29 +00002758vty_config_write (struct vty *vty)
2759{
2760 vty_out (vty, "line vty%s", VTY_NEWLINE);
2761
2762 if (vty_accesslist_name)
2763 vty_out (vty, " access-class %s%s",
2764 vty_accesslist_name, VTY_NEWLINE);
2765
2766 if (vty_ipv6_accesslist_name)
2767 vty_out (vty, " ipv6 access-class %s%s",
2768 vty_ipv6_accesslist_name, VTY_NEWLINE);
2769
2770 /* exec-timeout */
2771 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2772 vty_out (vty, " exec-timeout %ld %ld%s",
2773 vty_timeout_val / 60,
2774 vty_timeout_val % 60, VTY_NEWLINE);
2775
2776 /* login */
2777 if (no_password_check)
2778 vty_out (vty, " no login%s", VTY_NEWLINE);
2779
2780 vty_out (vty, "!%s", VTY_NEWLINE);
2781
2782 return CMD_SUCCESS;
2783}
2784
2785struct cmd_node vty_node =
2786{
2787 VTY_NODE,
2788 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00002789 1,
paul718e3742002-12-13 20:15:29 +00002790};
2791
2792/* Reset all VTY status. */
2793void
2794vty_reset ()
2795{
hasso8c328f12004-10-05 21:01:23 +00002796 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002797 struct vty *vty;
2798 struct thread *vty_serv_thread;
2799
paul55468c82005-03-14 20:19:01 +00002800 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002801 if ((vty = vector_slot (vtyvec, i)) != NULL)
2802 {
2803 buffer_reset (vty->obuf);
2804 vty->status = VTY_CLOSE;
2805 vty_close (vty);
2806 }
2807
paul55468c82005-03-14 20:19:01 +00002808 for (i = 0; i < vector_active (Vvty_serv_thread); i++)
paul718e3742002-12-13 20:15:29 +00002809 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2810 {
2811 thread_cancel (vty_serv_thread);
2812 vector_slot (Vvty_serv_thread, i) = NULL;
2813 close (i);
2814 }
2815
2816 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2817
2818 if (vty_accesslist_name)
2819 {
2820 XFREE(MTYPE_VTY, vty_accesslist_name);
2821 vty_accesslist_name = NULL;
2822 }
2823
2824 if (vty_ipv6_accesslist_name)
2825 {
2826 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2827 vty_ipv6_accesslist_name = NULL;
2828 }
2829}
2830
ajs9fc7ebf2005-02-23 15:12:34 +00002831static void
2832vty_save_cwd (void)
paul718e3742002-12-13 20:15:29 +00002833{
paul79ad2792003-10-15 22:09:28 +00002834 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00002835 char *c;
paul718e3742002-12-13 20:15:29 +00002836
paulccc92352003-10-22 02:49:38 +00002837 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002838
paulccc92352003-10-22 02:49:38 +00002839 if (!c)
paul79ad2792003-10-15 22:09:28 +00002840 {
2841 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00002842 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002843 }
paul718e3742002-12-13 20:15:29 +00002844
2845 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2846 strcpy (vty_cwd, cwd);
2847}
2848
2849char *
2850vty_get_cwd ()
2851{
2852 return vty_cwd;
2853}
2854
2855int
2856vty_shell (struct vty *vty)
2857{
2858 return vty->type == VTY_SHELL ? 1 : 0;
2859}
2860
2861int
2862vty_shell_serv (struct vty *vty)
2863{
2864 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2865}
2866
2867void
2868vty_init_vtysh ()
2869{
2870 vtyvec = vector_init (VECTOR_MIN_SIZE);
2871}
2872
2873/* Install vty's own commands like `who' command. */
2874void
paulb21b19c2003-06-15 01:28:29 +00002875vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00002876{
2877 /* For further configuration read, preserve current directory. */
2878 vty_save_cwd ();
2879
2880 vtyvec = vector_init (VECTOR_MIN_SIZE);
2881
paulb21b19c2003-06-15 01:28:29 +00002882 master = master_thread;
2883
paul718e3742002-12-13 20:15:29 +00002884 /* Initilize server thread vector. */
2885 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2886
2887 /* Install bgp top node. */
2888 install_node (&vty_node, vty_config_write);
2889
2890 install_element (VIEW_NODE, &config_who_cmd);
2891 install_element (VIEW_NODE, &show_history_cmd);
2892 install_element (ENABLE_NODE, &config_who_cmd);
2893 install_element (CONFIG_NODE, &line_vty_cmd);
2894 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2895 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2896 install_element (CONFIG_NODE, &show_history_cmd);
2897 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2898 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
2899 install_element (ENABLE_NODE, &show_history_cmd);
2900
2901 install_default (VTY_NODE);
2902 install_element (VTY_NODE, &exec_timeout_min_cmd);
2903 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2904 install_element (VTY_NODE, &no_exec_timeout_cmd);
2905 install_element (VTY_NODE, &vty_access_class_cmd);
2906 install_element (VTY_NODE, &no_vty_access_class_cmd);
2907 install_element (VTY_NODE, &vty_login_cmd);
2908 install_element (VTY_NODE, &no_vty_login_cmd);
2909#ifdef HAVE_IPV6
2910 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2911 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2912#endif /* HAVE_IPV6 */
2913}