blob: 7696915a75620733184fae1c30eb62ab30796116 [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() */
gdtf80a0162005-12-29 16:03:32 +0000231 for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
paul22085182005-03-08 16:00:12 +0000232 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;
vincentfbf5d032005-09-29 11:25:50 +0000391 const char *protocolname;
paul718e3742002-12-13 20:15:29 +0000392
393 /* Split readline string up into the vector */
394 vline = cmd_make_strvec (buf);
395
396 if (vline == NULL)
397 return CMD_SUCCESS;
398
ajs924b9222005-04-16 17:11:24 +0000399#ifdef CONSUMED_TIME_CHECK
400 {
401 RUSAGE_T before;
402 RUSAGE_T after;
ajs8b70d0b2005-04-28 01:31:13 +0000403 unsigned long realtime, cputime;
ajs924b9222005-04-16 17:11:24 +0000404
405 GETRUSAGE(&before);
406#endif /* CONSUMED_TIME_CHECK */
407
hasso87d683b2005-01-16 23:31:54 +0000408 ret = cmd_execute_command (vline, vty, NULL, 0);
paul718e3742002-12-13 20:15:29 +0000409
vincentfbf5d032005-09-29 11:25:50 +0000410 /* Get the name of the protocol if any */
411 if (zlog_default)
412 protocolname = zlog_proto_names[zlog_default->protocol];
413 else
414 protocolname = zlog_proto_names[ZLOG_NONE];
415
ajs924b9222005-04-16 17:11:24 +0000416#ifdef CONSUMED_TIME_CHECK
417 GETRUSAGE(&after);
ajs8b70d0b2005-04-28 01:31:13 +0000418 if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
419 CONSUMED_TIME_CHECK)
ajs924b9222005-04-16 17:11:24 +0000420 /* Warn about CPU hog that must be fixed. */
ajs8b70d0b2005-04-28 01:31:13 +0000421 zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
422 realtime/1000, cputime/1000, buf);
ajs924b9222005-04-16 17:11:24 +0000423 }
424#endif /* CONSUMED_TIME_CHECK */
425
paul718e3742002-12-13 20:15:29 +0000426 if (ret != CMD_SUCCESS)
427 switch (ret)
428 {
429 case CMD_WARNING:
430 if (vty->type == VTY_FILE)
431 vty_out (vty, "Warning...%s", VTY_NEWLINE);
432 break;
433 case CMD_ERR_AMBIGUOUS:
434 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
435 break;
436 case CMD_ERR_NO_MATCH:
vincentfbf5d032005-09-29 11:25:50 +0000437 vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000438 break;
439 case CMD_ERR_INCOMPLETE:
440 vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
441 break;
442 }
443 cmd_free_strvec (vline);
444
445 return ret;
446}
447
ajs9fc7ebf2005-02-23 15:12:34 +0000448static const char telnet_backward_char = 0x08;
449static const char telnet_space_char = ' ';
paul718e3742002-12-13 20:15:29 +0000450
451/* Basic function to write buffer to vty. */
452static void
ajs9fc7ebf2005-02-23 15:12:34 +0000453vty_write (struct vty *vty, const char *buf, size_t nbytes)
paul718e3742002-12-13 20:15:29 +0000454{
455 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
456 return;
457
458 /* Should we do buffering here ? And make vty_flush (vty) ? */
ajs9fc7ebf2005-02-23 15:12:34 +0000459 buffer_put (vty->obuf, buf, nbytes);
paul718e3742002-12-13 20:15:29 +0000460}
461
462/* Ensure length of input buffer. Is buffer is short, double it. */
463static void
464vty_ensure (struct vty *vty, int length)
465{
466 if (vty->max <= length)
467 {
468 vty->max *= 2;
469 vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
470 }
471}
472
473/* Basic function to insert character into vty. */
474static void
475vty_self_insert (struct vty *vty, char c)
476{
477 int i;
478 int length;
479
480 vty_ensure (vty, vty->length + 1);
481 length = vty->length - vty->cp;
482 memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
483 vty->buf[vty->cp] = c;
484
485 vty_write (vty, &vty->buf[vty->cp], length + 1);
486 for (i = 0; i < length; i++)
487 vty_write (vty, &telnet_backward_char, 1);
488
489 vty->cp++;
490 vty->length++;
491}
492
493/* Self insert character 'c' in overwrite mode. */
494static void
495vty_self_insert_overwrite (struct vty *vty, char c)
496{
497 vty_ensure (vty, vty->length + 1);
498 vty->buf[vty->cp++] = c;
499
500 if (vty->cp > vty->length)
501 vty->length++;
502
503 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
504 return;
505
506 vty_write (vty, &c, 1);
507}
508
509/* Insert a word into vty interface with overwrite mode. */
510static void
511vty_insert_word_overwrite (struct vty *vty, char *str)
512{
513 int len = strlen (str);
514 vty_write (vty, str, len);
515 strcpy (&vty->buf[vty->cp], str);
516 vty->cp += len;
517 vty->length = vty->cp;
518}
519
520/* Forward character. */
521static void
522vty_forward_char (struct vty *vty)
523{
524 if (vty->cp < vty->length)
525 {
526 vty_write (vty, &vty->buf[vty->cp], 1);
527 vty->cp++;
528 }
529}
530
531/* Backward character. */
532static void
533vty_backward_char (struct vty *vty)
534{
535 if (vty->cp > 0)
536 {
537 vty->cp--;
538 vty_write (vty, &telnet_backward_char, 1);
539 }
540}
541
542/* Move to the beginning of the line. */
543static void
544vty_beginning_of_line (struct vty *vty)
545{
546 while (vty->cp)
547 vty_backward_char (vty);
548}
549
550/* Move to the end of the line. */
551static void
552vty_end_of_line (struct vty *vty)
553{
554 while (vty->cp < vty->length)
555 vty_forward_char (vty);
556}
557
558static void vty_kill_line_from_beginning (struct vty *);
559static void vty_redraw_line (struct vty *);
560
561/* Print command line history. This function is called from
562 vty_next_line and vty_previous_line. */
563static void
564vty_history_print (struct vty *vty)
565{
566 int length;
567
568 vty_kill_line_from_beginning (vty);
569
570 /* Get previous line from history buffer */
571 length = strlen (vty->hist[vty->hp]);
572 memcpy (vty->buf, vty->hist[vty->hp], length);
573 vty->cp = vty->length = length;
574
575 /* Redraw current line */
576 vty_redraw_line (vty);
577}
578
579/* Show next command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000580static void
paul718e3742002-12-13 20:15:29 +0000581vty_next_line (struct vty *vty)
582{
583 int try_index;
584
585 if (vty->hp == vty->hindex)
586 return;
587
588 /* Try is there history exist or not. */
589 try_index = vty->hp;
590 if (try_index == (VTY_MAXHIST - 1))
591 try_index = 0;
592 else
593 try_index++;
594
595 /* If there is not history return. */
596 if (vty->hist[try_index] == NULL)
597 return;
598 else
599 vty->hp = try_index;
600
601 vty_history_print (vty);
602}
603
604/* Show previous command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000605static void
paul718e3742002-12-13 20:15:29 +0000606vty_previous_line (struct vty *vty)
607{
608 int try_index;
609
610 try_index = vty->hp;
611 if (try_index == 0)
612 try_index = VTY_MAXHIST - 1;
613 else
614 try_index--;
615
616 if (vty->hist[try_index] == NULL)
617 return;
618 else
619 vty->hp = try_index;
620
621 vty_history_print (vty);
622}
623
624/* This function redraw all of the command line character. */
625static void
626vty_redraw_line (struct vty *vty)
627{
628 vty_write (vty, vty->buf, vty->length);
629 vty->cp = vty->length;
630}
631
632/* Forward word. */
633static void
634vty_forward_word (struct vty *vty)
635{
636 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
637 vty_forward_char (vty);
638
639 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
640 vty_forward_char (vty);
641}
642
643/* Backward word without skipping training space. */
644static void
645vty_backward_pure_word (struct vty *vty)
646{
647 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
648 vty_backward_char (vty);
649}
650
651/* Backward word. */
652static void
653vty_backward_word (struct vty *vty)
654{
655 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
656 vty_backward_char (vty);
657
658 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
659 vty_backward_char (vty);
660}
661
662/* When '^D' is typed at the beginning of the line we move to the down
663 level. */
664static void
665vty_down_level (struct vty *vty)
666{
667 vty_out (vty, "%s", VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +0000668 (*config_exit_cmd.func)(NULL, vty, 0, NULL);
paul718e3742002-12-13 20:15:29 +0000669 vty_prompt (vty);
670 vty->cp = 0;
671}
672
673/* When '^Z' is received from vty, move down to the enable mode. */
ajs9fc7ebf2005-02-23 15:12:34 +0000674static void
paul718e3742002-12-13 20:15:29 +0000675vty_end_config (struct vty *vty)
676{
677 vty_out (vty, "%s", VTY_NEWLINE);
678
679 switch (vty->node)
680 {
681 case VIEW_NODE:
682 case ENABLE_NODE:
683 /* Nothing to do. */
684 break;
685 case CONFIG_NODE:
686 case INTERFACE_NODE:
687 case ZEBRA_NODE:
688 case RIP_NODE:
689 case RIPNG_NODE:
690 case BGP_NODE:
691 case BGP_VPNV4_NODE:
692 case BGP_IPV4_NODE:
693 case BGP_IPV4M_NODE:
694 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +0000695 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +0000696 case RMAP_NODE:
697 case OSPF_NODE:
698 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +0000699 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +0000700 case KEYCHAIN_NODE:
701 case KEYCHAIN_KEY_NODE:
702 case MASC_NODE:
703 case VTY_NODE:
704 vty_config_unlock (vty);
705 vty->node = ENABLE_NODE;
706 break;
707 default:
708 /* Unknown node, we have to ignore it. */
709 break;
710 }
711
712 vty_prompt (vty);
713 vty->cp = 0;
714}
715
716/* Delete a charcter at the current point. */
717static void
718vty_delete_char (struct vty *vty)
719{
720 int i;
721 int size;
722
723 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
724 return;
725
726 if (vty->length == 0)
727 {
728 vty_down_level (vty);
729 return;
730 }
731
732 if (vty->cp == vty->length)
733 return; /* completion need here? */
734
735 size = vty->length - vty->cp;
736
737 vty->length--;
738 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
739 vty->buf[vty->length] = '\0';
740
741 vty_write (vty, &vty->buf[vty->cp], size - 1);
742 vty_write (vty, &telnet_space_char, 1);
743
744 for (i = 0; i < size; i++)
745 vty_write (vty, &telnet_backward_char, 1);
746}
747
748/* Delete a character before the point. */
749static void
750vty_delete_backward_char (struct vty *vty)
751{
752 if (vty->cp == 0)
753 return;
754
755 vty_backward_char (vty);
756 vty_delete_char (vty);
757}
758
759/* Kill rest of line from current point. */
760static void
761vty_kill_line (struct vty *vty)
762{
763 int i;
764 int size;
765
766 size = vty->length - vty->cp;
767
768 if (size == 0)
769 return;
770
771 for (i = 0; i < size; i++)
772 vty_write (vty, &telnet_space_char, 1);
773 for (i = 0; i < size; i++)
774 vty_write (vty, &telnet_backward_char, 1);
775
776 memset (&vty->buf[vty->cp], 0, size);
777 vty->length = vty->cp;
778}
779
780/* Kill line from the beginning. */
781static void
782vty_kill_line_from_beginning (struct vty *vty)
783{
784 vty_beginning_of_line (vty);
785 vty_kill_line (vty);
786}
787
788/* Delete a word before the point. */
789static void
790vty_forward_kill_word (struct vty *vty)
791{
792 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
793 vty_delete_char (vty);
794 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
795 vty_delete_char (vty);
796}
797
798/* Delete a word before the point. */
799static void
800vty_backward_kill_word (struct vty *vty)
801{
802 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
803 vty_delete_backward_char (vty);
804 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
805 vty_delete_backward_char (vty);
806}
807
808/* Transpose chars before or at the point. */
809static void
810vty_transpose_chars (struct vty *vty)
811{
812 char c1, c2;
813
814 /* If length is short or point is near by the beginning of line then
815 return. */
816 if (vty->length < 2 || vty->cp < 1)
817 return;
818
819 /* In case of point is located at the end of the line. */
820 if (vty->cp == vty->length)
821 {
822 c1 = vty->buf[vty->cp - 1];
823 c2 = vty->buf[vty->cp - 2];
824
825 vty_backward_char (vty);
826 vty_backward_char (vty);
827 vty_self_insert_overwrite (vty, c1);
828 vty_self_insert_overwrite (vty, c2);
829 }
830 else
831 {
832 c1 = vty->buf[vty->cp];
833 c2 = vty->buf[vty->cp - 1];
834
835 vty_backward_char (vty);
836 vty_self_insert_overwrite (vty, c1);
837 vty_self_insert_overwrite (vty, c2);
838 }
839}
840
841/* Do completion at vty interface. */
842static void
843vty_complete_command (struct vty *vty)
844{
845 int i;
846 int ret;
847 char **matched = NULL;
848 vector vline;
849
850 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
851 return;
852
853 vline = cmd_make_strvec (vty->buf);
854 if (vline == NULL)
855 return;
856
857 /* In case of 'help \t'. */
858 if (isspace ((int) vty->buf[vty->length - 1]))
859 vector_set (vline, '\0');
860
861 matched = cmd_complete_command (vline, vty, &ret);
862
863 cmd_free_strvec (vline);
864
865 vty_out (vty, "%s", VTY_NEWLINE);
866 switch (ret)
867 {
868 case CMD_ERR_AMBIGUOUS:
869 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
870 vty_prompt (vty);
871 vty_redraw_line (vty);
872 break;
873 case CMD_ERR_NO_MATCH:
874 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
875 vty_prompt (vty);
876 vty_redraw_line (vty);
877 break;
878 case CMD_COMPLETE_FULL_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 vty_self_insert (vty, ' ');
884 XFREE (MTYPE_TMP, matched[0]);
885 break;
886 case CMD_COMPLETE_MATCH:
887 vty_prompt (vty);
888 vty_redraw_line (vty);
889 vty_backward_pure_word (vty);
890 vty_insert_word_overwrite (vty, matched[0]);
891 XFREE (MTYPE_TMP, matched[0]);
892 vector_only_index_free (matched);
893 return;
894 break;
895 case CMD_COMPLETE_LIST_MATCH:
896 for (i = 0; matched[i] != NULL; i++)
897 {
898 if (i != 0 && ((i % 6) == 0))
899 vty_out (vty, "%s", VTY_NEWLINE);
900 vty_out (vty, "%-10s ", matched[i]);
901 XFREE (MTYPE_TMP, matched[i]);
902 }
903 vty_out (vty, "%s", VTY_NEWLINE);
904
905 vty_prompt (vty);
906 vty_redraw_line (vty);
907 break;
908 case CMD_ERR_NOTHING_TODO:
909 vty_prompt (vty);
910 vty_redraw_line (vty);
911 break;
912 default:
913 break;
914 }
915 if (matched)
916 vector_only_index_free (matched);
917}
918
ajs9fc7ebf2005-02-23 15:12:34 +0000919static void
paul718e3742002-12-13 20:15:29 +0000920vty_describe_fold (struct vty *vty, int cmd_width,
hasso8c328f12004-10-05 21:01:23 +0000921 unsigned int desc_width, struct desc *desc)
paul718e3742002-12-13 20:15:29 +0000922{
hasso8c328f12004-10-05 21:01:23 +0000923 char *buf;
924 const char *cmd, *p;
paul718e3742002-12-13 20:15:29 +0000925 int pos;
926
927 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
928
929 if (desc_width <= 0)
930 {
931 vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
932 return;
933 }
934
935 buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
936
937 for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
938 {
939 for (pos = desc_width; pos > 0; pos--)
940 if (*(p + pos) == ' ')
941 break;
942
943 if (pos == 0)
944 break;
945
946 strncpy (buf, p, pos);
947 buf[pos] = '\0';
948 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
949
950 cmd = "";
951 }
952
953 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
954
955 XFREE (MTYPE_TMP, buf);
956}
957
958/* Describe matched command function. */
959static void
960vty_describe_command (struct vty *vty)
961{
962 int ret;
963 vector vline;
964 vector describe;
hasso8c328f12004-10-05 21:01:23 +0000965 unsigned int i, width, desc_width;
paul718e3742002-12-13 20:15:29 +0000966 struct desc *desc, *desc_cr = NULL;
967
968 vline = cmd_make_strvec (vty->buf);
969
970 /* In case of '> ?'. */
971 if (vline == NULL)
972 {
973 vline = vector_init (1);
974 vector_set (vline, '\0');
975 }
976 else
977 if (isspace ((int) vty->buf[vty->length - 1]))
978 vector_set (vline, '\0');
979
980 describe = cmd_describe_command (vline, vty, &ret);
981
982 vty_out (vty, "%s", VTY_NEWLINE);
983
984 /* Ambiguous error. */
985 switch (ret)
986 {
987 case CMD_ERR_AMBIGUOUS:
paul718e3742002-12-13 20:15:29 +0000988 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
Paul Jakma2fe8aba2006-05-12 23:22:01 +0000989 goto out;
paul718e3742002-12-13 20:15:29 +0000990 break;
991 case CMD_ERR_NO_MATCH:
paul718e3742002-12-13 20:15:29 +0000992 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
Paul Jakma2fe8aba2006-05-12 23:22:01 +0000993 goto out;
paul718e3742002-12-13 20:15:29 +0000994 break;
995 }
996
997 /* Get width of command string. */
998 width = 0;
paul55468c82005-03-14 20:19:01 +0000999 for (i = 0; i < vector_active (describe); i++)
paul718e3742002-12-13 20:15:29 +00001000 if ((desc = vector_slot (describe, i)) != NULL)
1001 {
hasso8c328f12004-10-05 21:01:23 +00001002 unsigned int len;
paul718e3742002-12-13 20:15:29 +00001003
1004 if (desc->cmd[0] == '\0')
1005 continue;
1006
1007 len = strlen (desc->cmd);
1008 if (desc->cmd[0] == '.')
1009 len--;
1010
1011 if (width < len)
1012 width = len;
1013 }
1014
1015 /* Get width of description string. */
1016 desc_width = vty->width - (width + 6);
1017
1018 /* Print out description. */
paul55468c82005-03-14 20:19:01 +00001019 for (i = 0; i < vector_active (describe); i++)
paul718e3742002-12-13 20:15:29 +00001020 if ((desc = vector_slot (describe, i)) != NULL)
1021 {
1022 if (desc->cmd[0] == '\0')
1023 continue;
1024
1025 if (strcmp (desc->cmd, "<cr>") == 0)
1026 {
1027 desc_cr = desc;
1028 continue;
1029 }
1030
1031 if (!desc->str)
1032 vty_out (vty, " %-s%s",
1033 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1034 VTY_NEWLINE);
1035 else if (desc_width >= strlen (desc->str))
1036 vty_out (vty, " %-*s %s%s", width,
1037 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1038 desc->str, VTY_NEWLINE);
1039 else
1040 vty_describe_fold (vty, width, desc_width, desc);
1041
1042#if 0
1043 vty_out (vty, " %-*s %s%s", width
1044 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1045 desc->str ? desc->str : "", VTY_NEWLINE);
1046#endif /* 0 */
1047 }
1048
1049 if ((desc = desc_cr))
1050 {
1051 if (!desc->str)
1052 vty_out (vty, " %-s%s",
1053 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1054 VTY_NEWLINE);
1055 else if (desc_width >= strlen (desc->str))
1056 vty_out (vty, " %-*s %s%s", width,
1057 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1058 desc->str, VTY_NEWLINE);
1059 else
1060 vty_describe_fold (vty, width, desc_width, desc);
1061 }
1062
Paul Jakma2fe8aba2006-05-12 23:22:01 +00001063out:
paul718e3742002-12-13 20:15:29 +00001064 cmd_free_strvec (vline);
Paul Jakmad16e0432006-05-15 10:56:46 +00001065 if (describe)
1066 vector_free (describe);
paul718e3742002-12-13 20:15:29 +00001067
1068 vty_prompt (vty);
1069 vty_redraw_line (vty);
1070}
1071
ajs9fc7ebf2005-02-23 15:12:34 +00001072static void
paul718e3742002-12-13 20:15:29 +00001073vty_clear_buf (struct vty *vty)
1074{
1075 memset (vty->buf, 0, vty->max);
1076}
1077
1078/* ^C stop current input and do not add command line to the history. */
1079static void
1080vty_stop_input (struct vty *vty)
1081{
1082 vty->cp = vty->length = 0;
1083 vty_clear_buf (vty);
1084 vty_out (vty, "%s", VTY_NEWLINE);
1085
1086 switch (vty->node)
1087 {
1088 case VIEW_NODE:
1089 case ENABLE_NODE:
1090 /* Nothing to do. */
1091 break;
1092 case CONFIG_NODE:
1093 case INTERFACE_NODE:
1094 case ZEBRA_NODE:
1095 case RIP_NODE:
1096 case RIPNG_NODE:
1097 case BGP_NODE:
1098 case RMAP_NODE:
1099 case OSPF_NODE:
1100 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00001101 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00001102 case KEYCHAIN_NODE:
1103 case KEYCHAIN_KEY_NODE:
1104 case MASC_NODE:
1105 case VTY_NODE:
1106 vty_config_unlock (vty);
1107 vty->node = ENABLE_NODE;
1108 break;
1109 default:
1110 /* Unknown node, we have to ignore it. */
1111 break;
1112 }
1113 vty_prompt (vty);
1114
1115 /* Set history pointer to the latest one. */
1116 vty->hp = vty->hindex;
1117}
1118
1119/* Add current command line to the history buffer. */
1120static void
1121vty_hist_add (struct vty *vty)
1122{
1123 int index;
1124
1125 if (vty->length == 0)
1126 return;
1127
1128 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1129
1130 /* Ignore the same string as previous one. */
1131 if (vty->hist[index])
1132 if (strcmp (vty->buf, vty->hist[index]) == 0)
1133 {
1134 vty->hp = vty->hindex;
1135 return;
1136 }
1137
1138 /* Insert history entry. */
1139 if (vty->hist[vty->hindex])
1140 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1141 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1142
1143 /* History index rotation. */
1144 vty->hindex++;
1145 if (vty->hindex == VTY_MAXHIST)
1146 vty->hindex = 0;
1147
1148 vty->hp = vty->hindex;
1149}
1150
1151/* #define TELNET_OPTION_DEBUG */
1152
1153/* Get telnet window size. */
1154static int
1155vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1156{
1157#ifdef TELNET_OPTION_DEBUG
1158 int i;
1159
1160 for (i = 0; i < nbytes; i++)
1161 {
1162 switch (buf[i])
1163 {
1164 case IAC:
1165 vty_out (vty, "IAC ");
1166 break;
1167 case WILL:
1168 vty_out (vty, "WILL ");
1169 break;
1170 case WONT:
1171 vty_out (vty, "WONT ");
1172 break;
1173 case DO:
1174 vty_out (vty, "DO ");
1175 break;
1176 case DONT:
1177 vty_out (vty, "DONT ");
1178 break;
1179 case SB:
1180 vty_out (vty, "SB ");
1181 break;
1182 case SE:
1183 vty_out (vty, "SE ");
1184 break;
1185 case TELOPT_ECHO:
1186 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1187 break;
1188 case TELOPT_SGA:
1189 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1190 break;
1191 case TELOPT_NAWS:
1192 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1193 break;
1194 default:
1195 vty_out (vty, "%x ", buf[i]);
1196 break;
1197 }
1198 }
1199 vty_out (vty, "%s", VTY_NEWLINE);
1200
1201#endif /* TELNET_OPTION_DEBUG */
1202
1203 switch (buf[0])
1204 {
1205 case SB:
ajs9fc7ebf2005-02-23 15:12:34 +00001206 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001207 vty->iac_sb_in_progress = 1;
1208 return 0;
1209 break;
1210 case SE:
1211 {
paul718e3742002-12-13 20:15:29 +00001212 if (!vty->iac_sb_in_progress)
1213 return 0;
1214
ajs9fc7ebf2005-02-23 15:12:34 +00001215 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
paul718e3742002-12-13 20:15:29 +00001216 {
1217 vty->iac_sb_in_progress = 0;
1218 return 0;
1219 }
ajs9fc7ebf2005-02-23 15:12:34 +00001220 switch (vty->sb_buf[0])
paul718e3742002-12-13 20:15:29 +00001221 {
1222 case TELOPT_NAWS:
ajs9fc7ebf2005-02-23 15:12:34 +00001223 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1224 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1225 "should send %d characters, but we received %lu",
1226 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1227 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1228 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1229 "too small to handle the telnet NAWS option",
1230 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1231 else
1232 {
1233 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1234 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1235#ifdef TELNET_OPTION_DEBUG
1236 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1237 "width %d, height %d%s",
1238 vty->width, vty->height, VTY_NEWLINE);
1239#endif
1240 }
paul718e3742002-12-13 20:15:29 +00001241 break;
1242 }
1243 vty->iac_sb_in_progress = 0;
1244 return 0;
1245 break;
1246 }
1247 default:
1248 break;
1249 }
1250 return 1;
1251}
1252
1253/* Execute current command line. */
1254static int
1255vty_execute (struct vty *vty)
1256{
1257 int ret;
1258
1259 ret = CMD_SUCCESS;
1260
1261 switch (vty->node)
1262 {
1263 case AUTH_NODE:
1264 case AUTH_ENABLE_NODE:
1265 vty_auth (vty, vty->buf);
1266 break;
1267 default:
1268 ret = vty_command (vty, vty->buf);
1269 if (vty->type == VTY_TERM)
1270 vty_hist_add (vty);
1271 break;
1272 }
1273
1274 /* Clear command line buffer. */
1275 vty->cp = vty->length = 0;
1276 vty_clear_buf (vty);
1277
ajs5a646652004-11-05 01:25:55 +00001278 if (vty->status != VTY_CLOSE )
paul718e3742002-12-13 20:15:29 +00001279 vty_prompt (vty);
1280
1281 return ret;
1282}
1283
1284#define CONTROL(X) ((X) - '@')
1285#define VTY_NORMAL 0
1286#define VTY_PRE_ESCAPE 1
1287#define VTY_ESCAPE 2
1288
1289/* Escape character command map. */
1290static void
1291vty_escape_map (unsigned char c, struct vty *vty)
1292{
1293 switch (c)
1294 {
1295 case ('A'):
1296 vty_previous_line (vty);
1297 break;
1298 case ('B'):
1299 vty_next_line (vty);
1300 break;
1301 case ('C'):
1302 vty_forward_char (vty);
1303 break;
1304 case ('D'):
1305 vty_backward_char (vty);
1306 break;
1307 default:
1308 break;
1309 }
1310
1311 /* Go back to normal mode. */
1312 vty->escape = VTY_NORMAL;
1313}
1314
1315/* Quit print out to the buffer. */
1316static void
1317vty_buffer_reset (struct vty *vty)
1318{
1319 buffer_reset (vty->obuf);
1320 vty_prompt (vty);
1321 vty_redraw_line (vty);
1322}
1323
1324/* Read data via vty socket. */
1325static int
1326vty_read (struct thread *thread)
1327{
1328 int i;
paul718e3742002-12-13 20:15:29 +00001329 int nbytes;
1330 unsigned char buf[VTY_READ_BUFSIZ];
1331
1332 int vty_sock = THREAD_FD (thread);
1333 struct vty *vty = THREAD_ARG (thread);
1334 vty->t_read = NULL;
1335
1336 /* Read raw data from socket */
ajs9fc7ebf2005-02-23 15:12:34 +00001337 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1338 {
1339 if (nbytes < 0)
1340 {
1341 if (ERRNO_IO_RETRY(errno))
1342 {
1343 vty_event (VTY_READ, vty_sock, vty);
1344 return 0;
1345 }
1346 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1347 __func__, vty->fd, safe_strerror(errno));
1348 }
1349 buffer_reset(vty->obuf);
1350 vty->status = VTY_CLOSE;
1351 }
paul718e3742002-12-13 20:15:29 +00001352
1353 for (i = 0; i < nbytes; i++)
1354 {
1355 if (buf[i] == IAC)
1356 {
1357 if (!vty->iac)
1358 {
1359 vty->iac = 1;
1360 continue;
1361 }
1362 else
1363 {
1364 vty->iac = 0;
1365 }
1366 }
1367
1368 if (vty->iac_sb_in_progress && !vty->iac)
1369 {
ajs9fc7ebf2005-02-23 15:12:34 +00001370 if (vty->sb_len < sizeof(vty->sb_buf))
1371 vty->sb_buf[vty->sb_len] = buf[i];
1372 vty->sb_len++;
paul718e3742002-12-13 20:15:29 +00001373 continue;
1374 }
1375
1376 if (vty->iac)
1377 {
1378 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001379 int ret = 0;
paule9372532003-10-26 21:36:07 +00001380 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001381 vty->iac = 0;
1382 i += ret;
1383 continue;
1384 }
paul5b8c1b02003-10-15 23:08:55 +00001385
paul718e3742002-12-13 20:15:29 +00001386
1387 if (vty->status == VTY_MORE)
1388 {
1389 switch (buf[i])
1390 {
1391 case CONTROL('C'):
1392 case 'q':
1393 case 'Q':
paul718e3742002-12-13 20:15:29 +00001394 vty_buffer_reset (vty);
1395 break;
1396#if 0 /* More line does not work for "show ip bgp". */
1397 case '\n':
1398 case '\r':
1399 vty->status = VTY_MORELINE;
1400 break;
1401#endif
1402 default:
paul718e3742002-12-13 20:15:29 +00001403 break;
1404 }
1405 continue;
1406 }
1407
1408 /* Escape character. */
1409 if (vty->escape == VTY_ESCAPE)
1410 {
1411 vty_escape_map (buf[i], vty);
1412 continue;
1413 }
1414
1415 /* Pre-escape status. */
1416 if (vty->escape == VTY_PRE_ESCAPE)
1417 {
1418 switch (buf[i])
1419 {
1420 case '[':
1421 vty->escape = VTY_ESCAPE;
1422 break;
1423 case 'b':
1424 vty_backward_word (vty);
1425 vty->escape = VTY_NORMAL;
1426 break;
1427 case 'f':
1428 vty_forward_word (vty);
1429 vty->escape = VTY_NORMAL;
1430 break;
1431 case 'd':
1432 vty_forward_kill_word (vty);
1433 vty->escape = VTY_NORMAL;
1434 break;
1435 case CONTROL('H'):
1436 case 0x7f:
1437 vty_backward_kill_word (vty);
1438 vty->escape = VTY_NORMAL;
1439 break;
1440 default:
1441 vty->escape = VTY_NORMAL;
1442 break;
1443 }
1444 continue;
1445 }
1446
1447 switch (buf[i])
1448 {
1449 case CONTROL('A'):
1450 vty_beginning_of_line (vty);
1451 break;
1452 case CONTROL('B'):
1453 vty_backward_char (vty);
1454 break;
1455 case CONTROL('C'):
1456 vty_stop_input (vty);
1457 break;
1458 case CONTROL('D'):
1459 vty_delete_char (vty);
1460 break;
1461 case CONTROL('E'):
1462 vty_end_of_line (vty);
1463 break;
1464 case CONTROL('F'):
1465 vty_forward_char (vty);
1466 break;
1467 case CONTROL('H'):
1468 case 0x7f:
1469 vty_delete_backward_char (vty);
1470 break;
1471 case CONTROL('K'):
1472 vty_kill_line (vty);
1473 break;
1474 case CONTROL('N'):
1475 vty_next_line (vty);
1476 break;
1477 case CONTROL('P'):
1478 vty_previous_line (vty);
1479 break;
1480 case CONTROL('T'):
1481 vty_transpose_chars (vty);
1482 break;
1483 case CONTROL('U'):
1484 vty_kill_line_from_beginning (vty);
1485 break;
1486 case CONTROL('W'):
1487 vty_backward_kill_word (vty);
1488 break;
1489 case CONTROL('Z'):
1490 vty_end_config (vty);
1491 break;
1492 case '\n':
1493 case '\r':
1494 vty_out (vty, "%s", VTY_NEWLINE);
1495 vty_execute (vty);
1496 break;
1497 case '\t':
1498 vty_complete_command (vty);
1499 break;
1500 case '?':
1501 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1502 vty_self_insert (vty, buf[i]);
1503 else
1504 vty_describe_command (vty);
1505 break;
1506 case '\033':
1507 if (i + 1 < nbytes && buf[i + 1] == '[')
1508 {
1509 vty->escape = VTY_ESCAPE;
1510 i++;
1511 }
1512 else
1513 vty->escape = VTY_PRE_ESCAPE;
1514 break;
1515 default:
1516 if (buf[i] > 31 && buf[i] < 127)
1517 vty_self_insert (vty, buf[i]);
1518 break;
1519 }
1520 }
1521
1522 /* Check status. */
1523 if (vty->status == VTY_CLOSE)
1524 vty_close (vty);
1525 else
1526 {
1527 vty_event (VTY_WRITE, vty_sock, vty);
1528 vty_event (VTY_READ, vty_sock, vty);
1529 }
1530 return 0;
1531}
1532
1533/* Flush buffer to the vty. */
1534static int
1535vty_flush (struct thread *thread)
1536{
1537 int erase;
ajs9fc7ebf2005-02-23 15:12:34 +00001538 buffer_status_t flushrc;
paul718e3742002-12-13 20:15:29 +00001539 int vty_sock = THREAD_FD (thread);
1540 struct vty *vty = THREAD_ARG (thread);
ajs9fc7ebf2005-02-23 15:12:34 +00001541
paul718e3742002-12-13 20:15:29 +00001542 vty->t_write = NULL;
1543
1544 /* Tempolary disable read thread. */
ajs9fc7ebf2005-02-23 15:12:34 +00001545 if ((vty->lines == 0) && vty->t_read)
1546 {
1547 thread_cancel (vty->t_read);
1548 vty->t_read = NULL;
1549 }
paul718e3742002-12-13 20:15:29 +00001550
1551 /* Function execution continue. */
ajs9fc7ebf2005-02-23 15:12:34 +00001552 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
paul718e3742002-12-13 20:15:29 +00001553
ajs9fc7ebf2005-02-23 15:12:34 +00001554 /* N.B. if width is 0, that means we don't know the window size. */
1555 if ((vty->lines == 0) || (vty->width == 0))
1556 flushrc = buffer_flush_available(vty->obuf, vty->fd);
1557 else if (vty->status == VTY_MORELINE)
1558 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1559 1, erase, 0);
1560 else
1561 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1562 vty->lines >= 0 ? vty->lines :
1563 vty->height,
1564 erase, 0);
1565 switch (flushrc)
1566 {
1567 case BUFFER_ERROR:
1568 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1569 vty->fd);
1570 buffer_reset(vty->obuf);
1571 vty_close(vty);
1572 return 0;
1573 case BUFFER_EMPTY:
1574 if (vty->status == VTY_CLOSE)
1575 vty_close (vty);
paul718e3742002-12-13 20:15:29 +00001576 else
1577 {
ajs9fc7ebf2005-02-23 15:12:34 +00001578 vty->status = VTY_NORMAL;
paul718e3742002-12-13 20:15:29 +00001579 if (vty->lines == 0)
ajs9fc7ebf2005-02-23 15:12:34 +00001580 vty_event (VTY_READ, vty_sock, vty);
paul718e3742002-12-13 20:15:29 +00001581 }
ajs9fc7ebf2005-02-23 15:12:34 +00001582 break;
1583 case BUFFER_PENDING:
1584 /* There is more data waiting to be written. */
1585 vty->status = VTY_MORE;
1586 if (vty->lines == 0)
1587 vty_event (VTY_WRITE, vty_sock, vty);
1588 break;
1589 }
paul718e3742002-12-13 20:15:29 +00001590
1591 return 0;
1592}
1593
1594/* Create new vty structure. */
ajs9fc7ebf2005-02-23 15:12:34 +00001595static struct vty *
paul718e3742002-12-13 20:15:29 +00001596vty_create (int vty_sock, union sockunion *su)
1597{
1598 struct vty *vty;
1599
1600 /* Allocate new vty structure and set up default values. */
1601 vty = vty_new ();
1602 vty->fd = vty_sock;
1603 vty->type = VTY_TERM;
1604 vty->address = sockunion_su2str (su);
1605 if (no_password_check)
1606 {
1607 if (host.advanced)
1608 vty->node = ENABLE_NODE;
1609 else
1610 vty->node = VIEW_NODE;
1611 }
1612 else
1613 vty->node = AUTH_NODE;
1614 vty->fail = 0;
1615 vty->cp = 0;
1616 vty_clear_buf (vty);
1617 vty->length = 0;
1618 memset (vty->hist, 0, sizeof (vty->hist));
1619 vty->hp = 0;
1620 vty->hindex = 0;
1621 vector_set_index (vtyvec, vty_sock, vty);
1622 vty->status = VTY_NORMAL;
1623 vty->v_timeout = vty_timeout_val;
1624 if (host.lines >= 0)
1625 vty->lines = host.lines;
1626 else
1627 vty->lines = -1;
1628 vty->iac = 0;
1629 vty->iac_sb_in_progress = 0;
ajs9fc7ebf2005-02-23 15:12:34 +00001630 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001631
1632 if (! no_password_check)
1633 {
1634 /* Vty is not available if password isn't set. */
1635 if (host.password == NULL && host.password_encrypt == NULL)
1636 {
1637 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1638 vty->status = VTY_CLOSE;
1639 vty_close (vty);
1640 return NULL;
1641 }
1642 }
1643
1644 /* Say hello to the world. */
1645 vty_hello (vty);
1646 if (! no_password_check)
1647 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1648
1649 /* Setting up terminal. */
1650 vty_will_echo (vty);
1651 vty_will_suppress_go_ahead (vty);
1652
1653 vty_dont_linemode (vty);
1654 vty_do_window_size (vty);
1655 /* vty_dont_lflow_ahead (vty); */
1656
1657 vty_prompt (vty);
1658
1659 /* Add read/write thread. */
1660 vty_event (VTY_WRITE, vty_sock, vty);
1661 vty_event (VTY_READ, vty_sock, vty);
1662
1663 return vty;
1664}
1665
1666/* Accept connection from the network. */
1667static int
1668vty_accept (struct thread *thread)
1669{
1670 int vty_sock;
1671 struct vty *vty;
1672 union sockunion su;
1673 int ret;
1674 unsigned int on;
1675 int accept_sock;
1676 struct prefix *p = NULL;
1677 struct access_list *acl = NULL;
1678
1679 accept_sock = THREAD_FD (thread);
1680
1681 /* We continue hearing vty socket. */
1682 vty_event (VTY_SERV, accept_sock, NULL);
1683
1684 memset (&su, 0, sizeof (union sockunion));
1685
1686 /* We can handle IPv4 or IPv6 socket. */
1687 vty_sock = sockunion_accept (accept_sock, &su);
1688 if (vty_sock < 0)
1689 {
ajs6099b3b2004-11-20 02:06:59 +00001690 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001691 return -1;
1692 }
ajs9fc7ebf2005-02-23 15:12:34 +00001693 set_nonblocking(vty_sock);
paul718e3742002-12-13 20:15:29 +00001694
1695 p = sockunion2hostprefix (&su);
1696
1697 /* VTY's accesslist apply. */
1698 if (p->family == AF_INET && vty_accesslist_name)
1699 {
1700 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1701 (access_list_apply (acl, p) == FILTER_DENY))
1702 {
1703 char *buf;
1704 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1705 (buf = sockunion_su2str (&su)));
1706 free (buf);
1707 close (vty_sock);
1708
1709 /* continue accepting connections */
1710 vty_event (VTY_SERV, accept_sock, NULL);
1711
1712 prefix_free (p);
1713
1714 return 0;
1715 }
1716 }
1717
1718#ifdef HAVE_IPV6
1719 /* VTY's ipv6 accesslist apply. */
1720 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1721 {
1722 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1723 (access_list_apply (acl, p) == FILTER_DENY))
1724 {
1725 char *buf;
1726 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1727 (buf = sockunion_su2str (&su)));
1728 free (buf);
1729 close (vty_sock);
1730
1731 /* continue accepting connections */
1732 vty_event (VTY_SERV, accept_sock, NULL);
1733
1734 prefix_free (p);
1735
1736 return 0;
1737 }
1738 }
1739#endif /* HAVE_IPV6 */
1740
1741 prefix_free (p);
1742
1743 on = 1;
1744 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1745 (char *) &on, sizeof (on));
1746 if (ret < 0)
1747 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
ajs6099b3b2004-11-20 02:06:59 +00001748 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001749
1750 vty = vty_create (vty_sock, &su);
1751
1752 return 0;
1753}
1754
1755#if defined(HAVE_IPV6) && !defined(NRL)
ajs9fc7ebf2005-02-23 15:12:34 +00001756static void
paul718e3742002-12-13 20:15:29 +00001757vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1758{
1759 int ret;
1760 struct addrinfo req;
1761 struct addrinfo *ainfo;
1762 struct addrinfo *ainfo_save;
1763 int sock;
1764 char port_str[BUFSIZ];
1765
1766 memset (&req, 0, sizeof (struct addrinfo));
1767 req.ai_flags = AI_PASSIVE;
1768 req.ai_family = AF_UNSPEC;
1769 req.ai_socktype = SOCK_STREAM;
1770 sprintf (port_str, "%d", port);
1771 port_str[sizeof (port_str) - 1] = '\0';
1772
1773 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1774
1775 if (ret != 0)
1776 {
1777 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1778 exit (1);
1779 }
1780
1781 ainfo_save = ainfo;
1782
1783 do
1784 {
1785 if (ainfo->ai_family != AF_INET
1786#ifdef HAVE_IPV6
1787 && ainfo->ai_family != AF_INET6
1788#endif /* HAVE_IPV6 */
1789 )
1790 continue;
1791
1792 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1793 if (sock < 0)
1794 continue;
1795
1796 sockopt_reuseaddr (sock);
1797 sockopt_reuseport (sock);
1798
1799 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1800 if (ret < 0)
1801 {
1802 close (sock); /* Avoid sd leak. */
1803 continue;
1804 }
1805
1806 ret = listen (sock, 3);
1807 if (ret < 0)
1808 {
1809 close (sock); /* Avoid sd leak. */
1810 continue;
1811 }
1812
1813 vty_event (VTY_SERV, sock, NULL);
1814 }
1815 while ((ainfo = ainfo->ai_next) != NULL);
1816
1817 freeaddrinfo (ainfo_save);
1818}
1819#endif /* HAVE_IPV6 && ! NRL */
1820
1821/* Make vty server socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001822static void
paul29db05b2003-05-08 20:10:22 +00001823vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001824{
1825 int ret;
1826 union sockunion su;
1827 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001828 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001829
1830 memset (&su, 0, sizeof (union sockunion));
1831 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001832 if(addr)
1833 switch(family)
1834 {
1835 case AF_INET:
1836 naddr=&su.sin.sin_addr;
1837#ifdef HAVE_IPV6
1838 case AF_INET6:
1839 naddr=&su.sin6.sin6_addr;
1840#endif
1841 }
1842
1843 if(naddr)
1844 switch(inet_pton(family,addr,naddr))
1845 {
1846 case -1:
1847 zlog_err("bad address %s",addr);
1848 naddr=NULL;
1849 break;
1850 case 0:
ajs6099b3b2004-11-20 02:06:59 +00001851 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
paul29db05b2003-05-08 20:10:22 +00001852 naddr=NULL;
1853 }
paul718e3742002-12-13 20:15:29 +00001854
1855 /* Make new socket. */
1856 accept_sock = sockunion_stream_socket (&su);
1857 if (accept_sock < 0)
1858 return;
1859
1860 /* This is server, so reuse address. */
1861 sockopt_reuseaddr (accept_sock);
1862 sockopt_reuseport (accept_sock);
1863
1864 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001865 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001866 if (ret < 0)
1867 {
paul29db05b2003-05-08 20:10:22 +00001868 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001869 close (accept_sock); /* Avoid sd leak. */
1870 return;
1871 }
1872
1873 /* Listen socket under queue 3. */
1874 ret = listen (accept_sock, 3);
1875 if (ret < 0)
1876 {
1877 zlog (NULL, LOG_WARNING, "can't listen socket");
1878 close (accept_sock); /* Avoid sd leak. */
1879 return;
1880 }
1881
1882 /* Add vty server event. */
1883 vty_event (VTY_SERV, accept_sock, NULL);
1884}
1885
1886#ifdef VTYSH
1887/* For sockaddr_un. */
1888#include <sys/un.h>
1889
1890/* VTY shell UNIX domain socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001891static void
hasso6ad96ea2004-10-07 19:33:46 +00001892vty_serv_un (const char *path)
paul718e3742002-12-13 20:15:29 +00001893{
1894 int ret;
paul75e15fe2004-10-31 02:13:09 +00001895 int sock, len;
paul718e3742002-12-13 20:15:29 +00001896 struct sockaddr_un serv;
1897 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00001898 struct zprivs_ids_t ids;
1899
paul718e3742002-12-13 20:15:29 +00001900 /* First of all, unlink existing socket */
1901 unlink (path);
1902
1903 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00001904 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00001905
1906 /* Make UNIX domain socket. */
1907 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1908 if (sock < 0)
1909 {
ajs6a52d0d2005-01-30 18:49:28 +00001910 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001911 return;
1912 }
1913
1914 /* Make server socket. */
1915 memset (&serv, 0, sizeof (struct sockaddr_un));
1916 serv.sun_family = AF_UNIX;
1917 strncpy (serv.sun_path, path, strlen (path));
1918#ifdef HAVE_SUN_LEN
1919 len = serv.sun_len = SUN_LEN(&serv);
1920#else
1921 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1922#endif /* HAVE_SUN_LEN */
1923
1924 ret = bind (sock, (struct sockaddr *) &serv, len);
1925 if (ret < 0)
1926 {
ajs6a52d0d2005-01-30 18:49:28 +00001927 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001928 close (sock); /* Avoid sd leak. */
1929 return;
1930 }
1931
1932 ret = listen (sock, 5);
1933 if (ret < 0)
1934 {
ajs6a52d0d2005-01-30 18:49:28 +00001935 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001936 close (sock); /* Avoid sd leak. */
1937 return;
1938 }
1939
1940 umask (old_mask);
1941
pauledd7c242003-06-04 13:59:38 +00001942 zprivs_get_ids(&ids);
1943
1944 if (ids.gid_vty > 0)
1945 {
1946 /* set group of socket */
1947 if ( chown (path, -1, ids.gid_vty) )
1948 {
1949 zlog_err ("vty_serv_un: could chown socket, %s",
ajs6099b3b2004-11-20 02:06:59 +00001950 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +00001951 }
1952 }
1953
paul718e3742002-12-13 20:15:29 +00001954 vty_event (VTYSH_SERV, sock, NULL);
1955}
1956
1957/* #define VTYSH_DEBUG 1 */
1958
1959static int
1960vtysh_accept (struct thread *thread)
1961{
1962 int accept_sock;
1963 int sock;
1964 int client_len;
1965 struct sockaddr_un client;
1966 struct vty *vty;
1967
1968 accept_sock = THREAD_FD (thread);
1969
1970 vty_event (VTYSH_SERV, accept_sock, NULL);
1971
1972 memset (&client, 0, sizeof (struct sockaddr_un));
1973 client_len = sizeof (struct sockaddr_un);
1974
hassoe473b032004-09-26 16:08:11 +00001975 sock = accept (accept_sock, (struct sockaddr *) &client,
1976 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00001977
1978 if (sock < 0)
1979 {
ajs6099b3b2004-11-20 02:06:59 +00001980 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001981 return -1;
1982 }
1983
ajs9fc7ebf2005-02-23 15:12:34 +00001984 if (set_nonblocking(sock) < 0)
paul75e15fe2004-10-31 02:13:09 +00001985 {
ajs9fc7ebf2005-02-23 15:12:34 +00001986 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
1987 " %s, closing", sock, safe_strerror (errno));
paul75e15fe2004-10-31 02:13:09 +00001988 close (sock);
1989 return -1;
1990 }
pauldccfb192004-10-29 08:29:36 +00001991
paul718e3742002-12-13 20:15:29 +00001992#ifdef VTYSH_DEBUG
1993 printf ("VTY shell accept\n");
1994#endif /* VTYSH_DEBUG */
1995
1996 vty = vty_new ();
1997 vty->fd = sock;
1998 vty->type = VTY_SHELL_SERV;
1999 vty->node = VIEW_NODE;
2000
2001 vty_event (VTYSH_READ, sock, vty);
2002
2003 return 0;
2004}
2005
2006static int
ajs9fc7ebf2005-02-23 15:12:34 +00002007vtysh_flush(struct vty *vty)
2008{
2009 switch (buffer_flush_available(vty->obuf, vty->fd))
2010 {
2011 case BUFFER_PENDING:
2012 vty_event(VTYSH_WRITE, vty->fd, vty);
2013 break;
2014 case BUFFER_ERROR:
2015 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
2016 buffer_reset(vty->obuf);
2017 vty_close(vty);
2018 return -1;
2019 break;
2020 case BUFFER_EMPTY:
2021 break;
2022 }
2023 return 0;
2024}
2025
2026static int
paul718e3742002-12-13 20:15:29 +00002027vtysh_read (struct thread *thread)
2028{
2029 int ret;
2030 int sock;
2031 int nbytes;
2032 struct vty *vty;
2033 unsigned char buf[VTY_READ_BUFSIZ];
ajs9fc7ebf2005-02-23 15:12:34 +00002034 unsigned char *p;
paul718e3742002-12-13 20:15:29 +00002035 u_char header[4] = {0, 0, 0, 0};
2036
2037 sock = THREAD_FD (thread);
2038 vty = THREAD_ARG (thread);
2039 vty->t_read = NULL;
2040
ajs9fc7ebf2005-02-23 15:12:34 +00002041 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
paul718e3742002-12-13 20:15:29 +00002042 {
ajs9fc7ebf2005-02-23 15:12:34 +00002043 if (nbytes < 0)
2044 {
2045 if (ERRNO_IO_RETRY(errno))
2046 {
2047 vty_event (VTYSH_READ, sock, vty);
2048 return 0;
2049 }
2050 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2051 __func__, sock, safe_strerror(errno));
2052 }
2053 buffer_reset(vty->obuf);
paul718e3742002-12-13 20:15:29 +00002054 vty_close (vty);
2055#ifdef VTYSH_DEBUG
2056 printf ("close vtysh\n");
2057#endif /* VTYSH_DEBUG */
2058 return 0;
2059 }
2060
2061#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002062 printf ("line: %.*s\n", nbytes, buf);
paul718e3742002-12-13 20:15:29 +00002063#endif /* VTYSH_DEBUG */
2064
ajs9fc7ebf2005-02-23 15:12:34 +00002065 for (p = buf; p < buf+nbytes; p++)
2066 {
2067 vty_ensure(vty, vty->length+1);
2068 vty->buf[vty->length++] = *p;
2069 if (*p == '\0')
2070 {
2071 /* Pass this line to parser. */
2072 ret = vty_execute (vty);
2073 /* Note that vty_execute clears the command buffer and resets
2074 vty->length to 0. */
paul718e3742002-12-13 20:15:29 +00002075
ajs9fc7ebf2005-02-23 15:12:34 +00002076 /* Return result. */
paul718e3742002-12-13 20:15:29 +00002077#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002078 printf ("result: %d\n", ret);
2079 printf ("vtysh node: %d\n", vty->node);
paul718e3742002-12-13 20:15:29 +00002080#endif /* VTYSH_DEBUG */
2081
ajs9fc7ebf2005-02-23 15:12:34 +00002082 header[3] = ret;
2083 buffer_put(vty->obuf, header, 4);
paul718e3742002-12-13 20:15:29 +00002084
ajs9fc7ebf2005-02-23 15:12:34 +00002085 if (!vty->t_write && (vtysh_flush(vty) < 0))
2086 /* Try to flush results; exit if a write error occurs. */
2087 return 0;
2088 }
2089 }
2090
paul718e3742002-12-13 20:15:29 +00002091 vty_event (VTYSH_READ, sock, vty);
2092
2093 return 0;
2094}
ajs49ff6d92004-11-04 19:26:16 +00002095
2096static int
2097vtysh_write (struct thread *thread)
2098{
2099 struct vty *vty = THREAD_ARG (thread);
2100
2101 vty->t_write = NULL;
ajs9fc7ebf2005-02-23 15:12:34 +00002102 vtysh_flush(vty);
ajs976d8c72004-11-10 15:40:09 +00002103 return 0;
ajs49ff6d92004-11-04 19:26:16 +00002104}
2105
paul718e3742002-12-13 20:15:29 +00002106#endif /* VTYSH */
2107
2108/* Determine address family to bind. */
2109void
hasso6ad96ea2004-10-07 19:33:46 +00002110vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002111{
2112 /* If port is set to 0, do not listen on TCP/IP at all! */
2113 if (port)
2114 {
2115
2116#ifdef HAVE_IPV6
2117#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002118 vty_serv_sock_family (addr, port, AF_INET);
2119 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002120#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002121 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002122#endif /* NRL*/
2123#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002124 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002125#endif /* HAVE_IPV6 */
2126 }
2127
2128#ifdef VTYSH
2129 vty_serv_un (path);
2130#endif /* VTYSH */
2131}
2132
2133/* Close vty interface. */
2134void
2135vty_close (struct vty *vty)
2136{
2137 int i;
2138
2139 /* Cancel threads.*/
2140 if (vty->t_read)
2141 thread_cancel (vty->t_read);
2142 if (vty->t_write)
2143 thread_cancel (vty->t_write);
2144 if (vty->t_timeout)
2145 thread_cancel (vty->t_timeout);
paul718e3742002-12-13 20:15:29 +00002146
2147 /* Flush buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +00002148 buffer_flush_all (vty->obuf, vty->fd);
paul718e3742002-12-13 20:15:29 +00002149
2150 /* Free input buffer. */
2151 buffer_free (vty->obuf);
2152
paul718e3742002-12-13 20:15:29 +00002153 /* Free command history. */
2154 for (i = 0; i < VTY_MAXHIST; i++)
2155 if (vty->hist[i])
2156 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2157
2158 /* Unset vector. */
2159 vector_unset (vtyvec, vty->fd);
2160
2161 /* Close socket. */
2162 if (vty->fd > 0)
2163 close (vty->fd);
2164
2165 if (vty->address)
paul05865c92005-10-26 05:49:54 +00002166 XFREE (MTYPE_TMP, vty->address);
paul718e3742002-12-13 20:15:29 +00002167 if (vty->buf)
2168 XFREE (MTYPE_VTY, vty->buf);
2169
2170 /* Check configure. */
2171 vty_config_unlock (vty);
2172
2173 /* OK free vty. */
2174 XFREE (MTYPE_VTY, vty);
2175}
2176
2177/* When time out occur output message then close connection. */
2178static int
2179vty_timeout (struct thread *thread)
2180{
2181 struct vty *vty;
2182
2183 vty = THREAD_ARG (thread);
2184 vty->t_timeout = NULL;
2185 vty->v_timeout = 0;
2186
2187 /* Clear buffer*/
2188 buffer_reset (vty->obuf);
2189 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2190
2191 /* Close connection. */
2192 vty->status = VTY_CLOSE;
2193 vty_close (vty);
2194
2195 return 0;
2196}
2197
2198/* Read up configuration file from file_name. */
2199static void
2200vty_read_file (FILE *confp)
2201{
2202 int ret;
2203 struct vty *vty;
2204
2205 vty = vty_new ();
2206 vty->fd = 0; /* stdout */
2207 vty->type = VTY_TERM;
2208 vty->node = CONFIG_NODE;
2209
2210 /* Execute configuration file */
2211 ret = config_from_file (vty, confp);
2212
paul7021c422003-07-15 12:52:22 +00002213 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002214 {
2215 switch (ret)
paul7021c422003-07-15 12:52:22 +00002216 {
2217 case CMD_ERR_AMBIGUOUS:
2218 fprintf (stderr, "Ambiguous command.\n");
2219 break;
2220 case CMD_ERR_NO_MATCH:
2221 fprintf (stderr, "There is no such command.\n");
2222 break;
2223 }
paul718e3742002-12-13 20:15:29 +00002224 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2225 vty->buf);
2226 vty_close (vty);
2227 exit (1);
2228 }
2229
2230 vty_close (vty);
2231}
2232
ajs9fc7ebf2005-02-23 15:12:34 +00002233static FILE *
paul718e3742002-12-13 20:15:29 +00002234vty_use_backup_config (char *fullpath)
2235{
2236 char *fullpath_sav, *fullpath_tmp;
2237 FILE *ret = NULL;
2238 struct stat buf;
2239 int tmp, sav;
2240 int c;
2241 char buffer[512];
2242
2243 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2244 strcpy (fullpath_sav, fullpath);
2245 strcat (fullpath_sav, CONF_BACKUP_EXT);
2246 if (stat (fullpath_sav, &buf) == -1)
2247 {
2248 free (fullpath_sav);
2249 return NULL;
2250 }
2251
2252 fullpath_tmp = malloc (strlen (fullpath) + 8);
2253 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2254
2255 /* Open file to configuration write. */
2256 tmp = mkstemp (fullpath_tmp);
2257 if (tmp < 0)
2258 {
2259 free (fullpath_sav);
2260 free (fullpath_tmp);
2261 return NULL;
2262 }
2263
2264 sav = open (fullpath_sav, O_RDONLY);
2265 if (sav < 0)
2266 {
gdt3dbf9962003-12-22 20:18:18 +00002267 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002268 free (fullpath_sav);
2269 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002270 return NULL;
2271 }
2272
2273 while((c = read (sav, buffer, 512)) > 0)
2274 write (tmp, buffer, c);
2275
2276 close (sav);
2277 close (tmp);
2278
gdtaa593d52003-12-22 20:15:53 +00002279 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2280 {
gdt3dbf9962003-12-22 20:18:18 +00002281 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002282 free (fullpath_sav);
2283 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002284 return NULL;
2285 }
2286
paul718e3742002-12-13 20:15:29 +00002287 if (link (fullpath_tmp, fullpath) == 0)
2288 ret = fopen (fullpath, "r");
2289
2290 unlink (fullpath_tmp);
2291
2292 free (fullpath_sav);
2293 free (fullpath_tmp);
hasso12f6ea22005-03-07 08:35:39 +00002294 return ret;
paul718e3742002-12-13 20:15:29 +00002295}
2296
2297/* Read up configuration file from file_name. */
2298void
2299vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002300 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002301{
paulccc92352003-10-22 02:49:38 +00002302 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002303 FILE *confp = NULL;
2304 char *fullpath;
paul05865c92005-10-26 05:49:54 +00002305 char *tmp = NULL;
paul718e3742002-12-13 20:15:29 +00002306
2307 /* If -f flag specified. */
2308 if (config_file != NULL)
2309 {
2310 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002311 {
2312 getcwd (cwd, MAXPATHLEN);
paul05865c92005-10-26 05:49:54 +00002313 tmp = XMALLOC (MTYPE_TMP,
hasso320ec102004-06-20 19:54:37 +00002314 strlen (cwd) + strlen (config_file) + 2);
paul05865c92005-10-26 05:49:54 +00002315 sprintf (tmp, "%s/%s", cwd, config_file);
2316 fullpath = tmp;
hasso320ec102004-06-20 19:54:37 +00002317 }
paul718e3742002-12-13 20:15:29 +00002318 else
hasso320ec102004-06-20 19:54:37 +00002319 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002320
2321 confp = fopen (fullpath, "r");
2322
2323 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002324 {
paul3d1dc852005-04-05 00:45:23 +00002325 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2326 __func__, fullpath, safe_strerror (errno));
2327
hasso320ec102004-06-20 19:54:37 +00002328 confp = vty_use_backup_config (fullpath);
2329 if (confp)
2330 fprintf (stderr, "WARNING: using backup configuration file!\n");
2331 else
2332 {
2333 fprintf (stderr, "can't open configuration file [%s]\n",
paul3d1dc852005-04-05 00:45:23 +00002334 config_file);
hasso320ec102004-06-20 19:54:37 +00002335 exit(1);
2336 }
2337 }
paul718e3742002-12-13 20:15:29 +00002338 }
2339 else
2340 {
paul718e3742002-12-13 20:15:29 +00002341#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002342 int ret;
2343 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002344
hasso320ec102004-06-20 19:54:37 +00002345 /* !!!!PLEASE LEAVE!!!!
2346 * This is NEEDED for use with vtysh -b, or else you can get
2347 * a real configuration food fight with a lot garbage in the
2348 * merged configuration file it creates coming from the per
2349 * daemon configuration files. This also allows the daemons
2350 * to start if there default configuration file is not
2351 * present or ignore them, as needed when using vtysh -b to
2352 * configure the daemons at boot - MAG
2353 */
paul718e3742002-12-13 20:15:29 +00002354
hasso320ec102004-06-20 19:54:37 +00002355 /* Stat for vtysh Zebra.conf, if found startup and wait for
2356 * boot configuration
2357 */
paul718e3742002-12-13 20:15:29 +00002358
hasso320ec102004-06-20 19:54:37 +00002359 if ( strstr(config_default_dir, "vtysh") == NULL)
2360 {
2361 ret = stat (integrate_default, &conf_stat);
2362 if (ret >= 0)
2363 return;
2364 }
paul718e3742002-12-13 20:15:29 +00002365#endif /* VTYSH */
2366
hasso320ec102004-06-20 19:54:37 +00002367 confp = fopen (config_default_dir, "r");
2368 if (confp == NULL)
2369 {
paul3d1dc852005-04-05 00:45:23 +00002370 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2371 __func__, config_default_dir, safe_strerror (errno));
2372
hasso320ec102004-06-20 19:54:37 +00002373 confp = vty_use_backup_config (config_default_dir);
2374 if (confp)
2375 {
2376 fprintf (stderr, "WARNING: using backup configuration file!\n");
2377 fullpath = config_default_dir;
2378 }
2379 else
2380 {
2381 fprintf (stderr, "can't open configuration file [%s]\n",
2382 config_default_dir);
2383 exit (1);
paul3d1dc852005-04-05 00:45:23 +00002384 }
hasso320ec102004-06-20 19:54:37 +00002385 }
paul718e3742002-12-13 20:15:29 +00002386 else
hasso320ec102004-06-20 19:54:37 +00002387 fullpath = config_default_dir;
2388 }
2389
paul718e3742002-12-13 20:15:29 +00002390 vty_read_file (confp);
2391
2392 fclose (confp);
2393
2394 host_config_set (fullpath);
paul05865c92005-10-26 05:49:54 +00002395
2396 if (tmp)
2397 XFREE (MTYPE_TMP, fullpath);
paul718e3742002-12-13 20:15:29 +00002398}
2399
2400/* Small utility function which output log to the VTY. */
2401void
ajs274a4a42004-12-07 15:39:31 +00002402vty_log (const char *level, const char *proto_str,
2403 const char *format, va_list va)
paul718e3742002-12-13 20:15:29 +00002404{
hasso8c328f12004-10-05 21:01:23 +00002405 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002406 struct vty *vty;
2407
paul55468c82005-03-14 20:19:01 +00002408 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002409 if ((vty = vector_slot (vtyvec, i)) != NULL)
2410 if (vty->monitor)
ajsd246bd92004-11-23 17:35:08 +00002411 {
2412 va_list ac;
2413 va_copy(ac, va);
ajs274a4a42004-12-07 15:39:31 +00002414 vty_log_out (vty, level, proto_str, format, ac);
ajsd246bd92004-11-23 17:35:08 +00002415 va_end(ac);
2416 }
paul718e3742002-12-13 20:15:29 +00002417}
2418
ajs274a4a42004-12-07 15:39:31 +00002419/* Async-signal-safe version of vty_log for fixed strings. */
2420void
2421vty_log_fixed (const char *buf, size_t len)
2422{
2423 unsigned int i;
ajs9fc7ebf2005-02-23 15:12:34 +00002424 struct iovec iov[2];
2425
ajs926fe8f2005-04-08 18:50:40 +00002426 iov[0].iov_base = (void *)buf;
ajs9fc7ebf2005-02-23 15:12:34 +00002427 iov[0].iov_len = len;
ajs926fe8f2005-04-08 18:50:40 +00002428 iov[1].iov_base = (void *)"\r\n";
ajs9fc7ebf2005-02-23 15:12:34 +00002429 iov[1].iov_len = 2;
ajs274a4a42004-12-07 15:39:31 +00002430
paul55468c82005-03-14 20:19:01 +00002431 for (i = 0; i < vector_active (vtyvec); i++)
ajs274a4a42004-12-07 15:39:31 +00002432 {
2433 struct vty *vty;
ajs9fc7ebf2005-02-23 15:12:34 +00002434 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2435 /* N.B. We don't care about the return code, since process is
2436 most likely just about to die anyway. */
2437 writev(vty->fd, iov, 2);
ajs274a4a42004-12-07 15:39:31 +00002438 }
2439}
2440
paul718e3742002-12-13 20:15:29 +00002441int
2442vty_config_lock (struct vty *vty)
2443{
2444 if (vty_config == 0)
2445 {
2446 vty->config = 1;
2447 vty_config = 1;
2448 }
2449 return vty->config;
2450}
2451
2452int
2453vty_config_unlock (struct vty *vty)
2454{
2455 if (vty_config == 1 && vty->config == 1)
2456 {
2457 vty->config = 0;
2458 vty_config = 0;
2459 }
2460 return vty->config;
2461}
2462
2463/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002464static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002465
2466static void
2467vty_event (enum event event, int sock, struct vty *vty)
2468{
2469 struct thread *vty_serv_thread;
2470
2471 switch (event)
2472 {
2473 case VTY_SERV:
2474 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2475 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2476 break;
2477#ifdef VTYSH
2478 case VTYSH_SERV:
2479 thread_add_read (master, vtysh_accept, vty, sock);
2480 break;
2481 case VTYSH_READ:
ajs49ff6d92004-11-04 19:26:16 +00002482 vty->t_read = thread_add_read (master, vtysh_read, vty, sock);
2483 break;
2484 case VTYSH_WRITE:
2485 vty->t_write = thread_add_write (master, vtysh_write, vty, sock);
paul718e3742002-12-13 20:15:29 +00002486 break;
2487#endif /* VTYSH */
2488 case VTY_READ:
2489 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2490
2491 /* Time out treatment. */
2492 if (vty->v_timeout)
2493 {
2494 if (vty->t_timeout)
2495 thread_cancel (vty->t_timeout);
2496 vty->t_timeout =
2497 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2498 }
2499 break;
2500 case VTY_WRITE:
2501 if (! vty->t_write)
2502 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2503 break;
2504 case VTY_TIMEOUT_RESET:
2505 if (vty->t_timeout)
2506 {
2507 thread_cancel (vty->t_timeout);
2508 vty->t_timeout = NULL;
2509 }
2510 if (vty->v_timeout)
2511 {
2512 vty->t_timeout =
2513 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2514 }
2515 break;
2516 }
2517}
2518
2519DEFUN (config_who,
2520 config_who_cmd,
2521 "who",
2522 "Display who is on vty\n")
2523{
hasso8c328f12004-10-05 21:01:23 +00002524 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002525 struct vty *v;
2526
paul55468c82005-03-14 20:19:01 +00002527 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002528 if ((v = vector_slot (vtyvec, i)) != NULL)
2529 vty_out (vty, "%svty[%d] connected from %s.%s",
2530 v->config ? "*" : " ",
2531 i, v->address, VTY_NEWLINE);
2532 return CMD_SUCCESS;
2533}
2534
2535/* Move to vty configuration mode. */
2536DEFUN (line_vty,
2537 line_vty_cmd,
2538 "line vty",
2539 "Configure a terminal line\n"
2540 "Virtual terminal\n")
2541{
2542 vty->node = VTY_NODE;
2543 return CMD_SUCCESS;
2544}
2545
2546/* Set time out value. */
ajs9fc7ebf2005-02-23 15:12:34 +00002547static int
paul9035efa2004-10-10 11:56:56 +00002548exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002549{
2550 unsigned long timeout = 0;
2551
2552 /* min_str and sec_str are already checked by parser. So it must be
2553 all digit string. */
2554 if (min_str)
2555 {
2556 timeout = strtol (min_str, NULL, 10);
2557 timeout *= 60;
2558 }
2559 if (sec_str)
2560 timeout += strtol (sec_str, NULL, 10);
2561
2562 vty_timeout_val = timeout;
2563 vty->v_timeout = timeout;
2564 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2565
2566
2567 return CMD_SUCCESS;
2568}
2569
2570DEFUN (exec_timeout_min,
2571 exec_timeout_min_cmd,
2572 "exec-timeout <0-35791>",
2573 "Set timeout value\n"
2574 "Timeout value in minutes\n")
2575{
2576 return exec_timeout (vty, argv[0], NULL);
2577}
2578
2579DEFUN (exec_timeout_sec,
2580 exec_timeout_sec_cmd,
2581 "exec-timeout <0-35791> <0-2147483>",
2582 "Set the EXEC timeout\n"
2583 "Timeout in minutes\n"
2584 "Timeout in seconds\n")
2585{
2586 return exec_timeout (vty, argv[0], argv[1]);
2587}
2588
2589DEFUN (no_exec_timeout,
2590 no_exec_timeout_cmd,
2591 "no exec-timeout",
2592 NO_STR
2593 "Set the EXEC timeout\n")
2594{
2595 return exec_timeout (vty, NULL, NULL);
2596}
2597
2598/* Set vty access class. */
2599DEFUN (vty_access_class,
2600 vty_access_class_cmd,
2601 "access-class WORD",
2602 "Filter connections based on an IP access list\n"
2603 "IP access list\n")
2604{
2605 if (vty_accesslist_name)
2606 XFREE(MTYPE_VTY, vty_accesslist_name);
2607
2608 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2609
2610 return CMD_SUCCESS;
2611}
2612
2613/* Clear vty access class. */
2614DEFUN (no_vty_access_class,
2615 no_vty_access_class_cmd,
2616 "no access-class [WORD]",
2617 NO_STR
2618 "Filter connections based on an IP access list\n"
2619 "IP access list\n")
2620{
2621 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2622 {
2623 vty_out (vty, "Access-class is not currently applied to vty%s",
2624 VTY_NEWLINE);
2625 return CMD_WARNING;
2626 }
2627
2628 XFREE(MTYPE_VTY, vty_accesslist_name);
2629
2630 vty_accesslist_name = NULL;
2631
2632 return CMD_SUCCESS;
2633}
2634
2635#ifdef HAVE_IPV6
2636/* Set vty access class. */
2637DEFUN (vty_ipv6_access_class,
2638 vty_ipv6_access_class_cmd,
2639 "ipv6 access-class WORD",
2640 IPV6_STR
2641 "Filter connections based on an IP access list\n"
2642 "IPv6 access list\n")
2643{
2644 if (vty_ipv6_accesslist_name)
2645 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2646
2647 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2648
2649 return CMD_SUCCESS;
2650}
2651
2652/* Clear vty access class. */
2653DEFUN (no_vty_ipv6_access_class,
2654 no_vty_ipv6_access_class_cmd,
2655 "no ipv6 access-class [WORD]",
2656 NO_STR
2657 IPV6_STR
2658 "Filter connections based on an IP access list\n"
2659 "IPv6 access list\n")
2660{
2661 if (! vty_ipv6_accesslist_name ||
2662 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2663 {
2664 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2665 VTY_NEWLINE);
2666 return CMD_WARNING;
2667 }
2668
2669 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2670
2671 vty_ipv6_accesslist_name = NULL;
2672
2673 return CMD_SUCCESS;
2674}
2675#endif /* HAVE_IPV6 */
2676
2677/* vty login. */
2678DEFUN (vty_login,
2679 vty_login_cmd,
2680 "login",
2681 "Enable password checking\n")
2682{
2683 no_password_check = 0;
2684 return CMD_SUCCESS;
2685}
2686
2687DEFUN (no_vty_login,
2688 no_vty_login_cmd,
2689 "no login",
2690 NO_STR
2691 "Enable password checking\n")
2692{
2693 no_password_check = 1;
2694 return CMD_SUCCESS;
2695}
2696
2697DEFUN (service_advanced_vty,
2698 service_advanced_vty_cmd,
2699 "service advanced-vty",
2700 "Set up miscellaneous service\n"
2701 "Enable advanced mode vty interface\n")
2702{
2703 host.advanced = 1;
2704 return CMD_SUCCESS;
2705}
2706
2707DEFUN (no_service_advanced_vty,
2708 no_service_advanced_vty_cmd,
2709 "no service advanced-vty",
2710 NO_STR
2711 "Set up miscellaneous service\n"
2712 "Enable advanced mode vty interface\n")
2713{
2714 host.advanced = 0;
2715 return CMD_SUCCESS;
2716}
2717
2718DEFUN (terminal_monitor,
2719 terminal_monitor_cmd,
2720 "terminal monitor",
2721 "Set terminal line parameters\n"
2722 "Copy debug output to the current terminal line\n")
2723{
2724 vty->monitor = 1;
2725 return CMD_SUCCESS;
2726}
2727
2728DEFUN (terminal_no_monitor,
2729 terminal_no_monitor_cmd,
2730 "terminal no monitor",
2731 "Set terminal line parameters\n"
2732 NO_STR
2733 "Copy debug output to the current terminal line\n")
2734{
2735 vty->monitor = 0;
2736 return CMD_SUCCESS;
2737}
2738
paul789f78a2006-01-17 17:42:03 +00002739ALIAS (terminal_no_monitor,
2740 no_terminal_monitor_cmd,
2741 "no terminal monitor",
2742 NO_STR
2743 "Set terminal line parameters\n"
2744 "Copy debug output to the current terminal line\n")
2745
paul718e3742002-12-13 20:15:29 +00002746DEFUN (show_history,
2747 show_history_cmd,
2748 "show history",
2749 SHOW_STR
2750 "Display the session command history\n")
2751{
2752 int index;
2753
2754 for (index = vty->hindex + 1; index != vty->hindex;)
2755 {
2756 if (index == VTY_MAXHIST)
2757 {
2758 index = 0;
2759 continue;
2760 }
2761
2762 if (vty->hist[index] != NULL)
2763 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2764
2765 index++;
2766 }
2767
2768 return CMD_SUCCESS;
2769}
2770
2771/* Display current configuration. */
ajs9fc7ebf2005-02-23 15:12:34 +00002772static int
paul718e3742002-12-13 20:15:29 +00002773vty_config_write (struct vty *vty)
2774{
2775 vty_out (vty, "line vty%s", VTY_NEWLINE);
2776
2777 if (vty_accesslist_name)
2778 vty_out (vty, " access-class %s%s",
2779 vty_accesslist_name, VTY_NEWLINE);
2780
2781 if (vty_ipv6_accesslist_name)
2782 vty_out (vty, " ipv6 access-class %s%s",
2783 vty_ipv6_accesslist_name, VTY_NEWLINE);
2784
2785 /* exec-timeout */
2786 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2787 vty_out (vty, " exec-timeout %ld %ld%s",
2788 vty_timeout_val / 60,
2789 vty_timeout_val % 60, VTY_NEWLINE);
2790
2791 /* login */
2792 if (no_password_check)
2793 vty_out (vty, " no login%s", VTY_NEWLINE);
2794
2795 vty_out (vty, "!%s", VTY_NEWLINE);
2796
2797 return CMD_SUCCESS;
2798}
2799
2800struct cmd_node vty_node =
2801{
2802 VTY_NODE,
2803 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00002804 1,
paul718e3742002-12-13 20:15:29 +00002805};
2806
2807/* Reset all VTY status. */
2808void
2809vty_reset ()
2810{
hasso8c328f12004-10-05 21:01:23 +00002811 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002812 struct vty *vty;
2813 struct thread *vty_serv_thread;
2814
paul55468c82005-03-14 20:19:01 +00002815 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002816 if ((vty = vector_slot (vtyvec, i)) != NULL)
2817 {
2818 buffer_reset (vty->obuf);
2819 vty->status = VTY_CLOSE;
2820 vty_close (vty);
2821 }
2822
paul55468c82005-03-14 20:19:01 +00002823 for (i = 0; i < vector_active (Vvty_serv_thread); i++)
paul718e3742002-12-13 20:15:29 +00002824 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2825 {
2826 thread_cancel (vty_serv_thread);
2827 vector_slot (Vvty_serv_thread, i) = NULL;
2828 close (i);
2829 }
2830
2831 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2832
2833 if (vty_accesslist_name)
2834 {
2835 XFREE(MTYPE_VTY, vty_accesslist_name);
2836 vty_accesslist_name = NULL;
2837 }
2838
2839 if (vty_ipv6_accesslist_name)
2840 {
2841 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2842 vty_ipv6_accesslist_name = NULL;
2843 }
2844}
2845
ajs9fc7ebf2005-02-23 15:12:34 +00002846static void
2847vty_save_cwd (void)
paul718e3742002-12-13 20:15:29 +00002848{
paul79ad2792003-10-15 22:09:28 +00002849 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00002850 char *c;
paul718e3742002-12-13 20:15:29 +00002851
paulccc92352003-10-22 02:49:38 +00002852 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002853
paulccc92352003-10-22 02:49:38 +00002854 if (!c)
paul79ad2792003-10-15 22:09:28 +00002855 {
2856 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00002857 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002858 }
paul718e3742002-12-13 20:15:29 +00002859
2860 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2861 strcpy (vty_cwd, cwd);
2862}
2863
2864char *
2865vty_get_cwd ()
2866{
2867 return vty_cwd;
2868}
2869
2870int
2871vty_shell (struct vty *vty)
2872{
2873 return vty->type == VTY_SHELL ? 1 : 0;
2874}
2875
2876int
2877vty_shell_serv (struct vty *vty)
2878{
2879 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2880}
2881
2882void
2883vty_init_vtysh ()
2884{
2885 vtyvec = vector_init (VECTOR_MIN_SIZE);
2886}
2887
2888/* Install vty's own commands like `who' command. */
2889void
paulb21b19c2003-06-15 01:28:29 +00002890vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00002891{
2892 /* For further configuration read, preserve current directory. */
2893 vty_save_cwd ();
2894
2895 vtyvec = vector_init (VECTOR_MIN_SIZE);
2896
paulb21b19c2003-06-15 01:28:29 +00002897 master = master_thread;
2898
paul718e3742002-12-13 20:15:29 +00002899 /* Initilize server thread vector. */
2900 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2901
2902 /* Install bgp top node. */
2903 install_node (&vty_node, vty_config_write);
2904
2905 install_element (VIEW_NODE, &config_who_cmd);
2906 install_element (VIEW_NODE, &show_history_cmd);
2907 install_element (ENABLE_NODE, &config_who_cmd);
2908 install_element (CONFIG_NODE, &line_vty_cmd);
2909 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2910 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2911 install_element (CONFIG_NODE, &show_history_cmd);
2912 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2913 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
paul789f78a2006-01-17 17:42:03 +00002914 install_element (ENABLE_NODE, &no_terminal_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00002915 install_element (ENABLE_NODE, &show_history_cmd);
2916
2917 install_default (VTY_NODE);
2918 install_element (VTY_NODE, &exec_timeout_min_cmd);
2919 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2920 install_element (VTY_NODE, &no_exec_timeout_cmd);
2921 install_element (VTY_NODE, &vty_access_class_cmd);
2922 install_element (VTY_NODE, &no_vty_access_class_cmd);
2923 install_element (VTY_NODE, &vty_login_cmd);
2924 install_element (VTY_NODE, &no_vty_login_cmd);
2925#ifdef HAVE_IPV6
2926 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2927 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2928#endif /* HAVE_IPV6 */
2929}