blob: bb3f14a50c7cabbffe776f8082b5cb2ae052c1e6 [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];
223 int r;
224 f = fopen (host.motdfile, "r");
225 if (f)
226 {
227 while (!feof (f))
228 {
229 memset (buf, '\0', sizeof (buf));
230 r = fread (&buf, sizeof (buf) - 1, 1, f);
231 if (r < 0)
232 break;
233 vty_out (vty, buf);
234 }
235 fclose (f);
236 }
237 else
238 vty_out (vty, "MOTD file not found\n");
239 }
240 else if (host.motd)
paul718e3742002-12-13 20:15:29 +0000241 vty_out (vty, host.motd);
242}
243
244/* Put out prompt and wait input from user. */
245static void
246vty_prompt (struct vty *vty)
247{
248 struct utsname names;
249 const char*hostname;
250
251 if (vty->type == VTY_TERM)
252 {
253 hostname = host.name;
254 if (!hostname)
255 {
256 uname (&names);
257 hostname = names.nodename;
258 }
259 vty_out (vty, cmd_prompt (vty->node), hostname);
260 }
261}
262
263/* Send WILL TELOPT_ECHO to remote server. */
ajs9fc7ebf2005-02-23 15:12:34 +0000264static void
paul718e3742002-12-13 20:15:29 +0000265vty_will_echo (struct vty *vty)
266{
paul02ff83c2004-06-11 11:27:03 +0000267 unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
paul718e3742002-12-13 20:15:29 +0000268 vty_out (vty, "%s", cmd);
269}
270
271/* Make suppress Go-Ahead telnet option. */
272static void
273vty_will_suppress_go_ahead (struct vty *vty)
274{
paul02ff83c2004-06-11 11:27:03 +0000275 unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
paul718e3742002-12-13 20:15:29 +0000276 vty_out (vty, "%s", cmd);
277}
278
279/* Make don't use linemode over telnet. */
280static void
281vty_dont_linemode (struct vty *vty)
282{
paul02ff83c2004-06-11 11:27:03 +0000283 unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
paul718e3742002-12-13 20:15:29 +0000284 vty_out (vty, "%s", cmd);
285}
286
287/* Use window size. */
288static void
289vty_do_window_size (struct vty *vty)
290{
paul02ff83c2004-06-11 11:27:03 +0000291 unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
paul718e3742002-12-13 20:15:29 +0000292 vty_out (vty, "%s", cmd);
293}
294
295#if 0 /* Currently not used. */
296/* Make don't use lflow vty interface. */
297static void
298vty_dont_lflow_ahead (struct vty *vty)
299{
paul02ff83c2004-06-11 11:27:03 +0000300 unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
paul718e3742002-12-13 20:15:29 +0000301 vty_out (vty, "%s", cmd);
302}
303#endif /* 0 */
304
305/* Allocate new vty struct. */
306struct vty *
307vty_new ()
308{
309 struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
310
ajs9fc7ebf2005-02-23 15:12:34 +0000311 new->obuf = buffer_new(0); /* Use default buffer size. */
paul718e3742002-12-13 20:15:29 +0000312 new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
313 new->max = VTY_BUFSIZ;
paul718e3742002-12-13 20:15:29 +0000314
315 return new;
316}
317
318/* Authentication of vty */
319static void
320vty_auth (struct vty *vty, char *buf)
321{
322 char *passwd = NULL;
323 enum node_type next_node = 0;
324 int fail;
325 char *crypt (const char *, const char *);
326
327 switch (vty->node)
328 {
329 case AUTH_NODE:
330 if (host.encrypt)
331 passwd = host.password_encrypt;
332 else
333 passwd = host.password;
334 if (host.advanced)
335 next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
336 else
337 next_node = VIEW_NODE;
338 break;
339 case AUTH_ENABLE_NODE:
340 if (host.encrypt)
341 passwd = host.enable_encrypt;
342 else
343 passwd = host.enable;
344 next_node = ENABLE_NODE;
345 break;
346 }
347
348 if (passwd)
349 {
350 if (host.encrypt)
351 fail = strcmp (crypt(buf, passwd), passwd);
352 else
353 fail = strcmp (buf, passwd);
354 }
355 else
356 fail = 1;
357
358 if (! fail)
359 {
360 vty->fail = 0;
361 vty->node = next_node; /* Success ! */
362 }
363 else
364 {
365 vty->fail++;
366 if (vty->fail >= 3)
367 {
368 if (vty->node == AUTH_NODE)
369 {
370 vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
371 vty->status = VTY_CLOSE;
372 }
373 else
374 {
375 /* AUTH_ENABLE_NODE */
376 vty->fail = 0;
377 vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
378 vty->node = VIEW_NODE;
379 }
380 }
381 }
382}
383
384/* Command execution over the vty interface. */
ajs9fc7ebf2005-02-23 15:12:34 +0000385static int
paul718e3742002-12-13 20:15:29 +0000386vty_command (struct vty *vty, char *buf)
387{
388 int ret;
389 vector vline;
390
391 /* Split readline string up into the vector */
392 vline = cmd_make_strvec (buf);
393
394 if (vline == NULL)
395 return CMD_SUCCESS;
396
hasso87d683b2005-01-16 23:31:54 +0000397 ret = cmd_execute_command (vline, vty, NULL, 0);
paul718e3742002-12-13 20:15:29 +0000398
399 if (ret != CMD_SUCCESS)
400 switch (ret)
401 {
402 case CMD_WARNING:
403 if (vty->type == VTY_FILE)
404 vty_out (vty, "Warning...%s", VTY_NEWLINE);
405 break;
406 case CMD_ERR_AMBIGUOUS:
407 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
408 break;
409 case CMD_ERR_NO_MATCH:
410 vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
411 break;
412 case CMD_ERR_INCOMPLETE:
413 vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
414 break;
415 }
416 cmd_free_strvec (vline);
417
418 return ret;
419}
420
ajs9fc7ebf2005-02-23 15:12:34 +0000421static const char telnet_backward_char = 0x08;
422static const char telnet_space_char = ' ';
paul718e3742002-12-13 20:15:29 +0000423
424/* Basic function to write buffer to vty. */
425static void
ajs9fc7ebf2005-02-23 15:12:34 +0000426vty_write (struct vty *vty, const char *buf, size_t nbytes)
paul718e3742002-12-13 20:15:29 +0000427{
428 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
429 return;
430
431 /* Should we do buffering here ? And make vty_flush (vty) ? */
ajs9fc7ebf2005-02-23 15:12:34 +0000432 buffer_put (vty->obuf, buf, nbytes);
paul718e3742002-12-13 20:15:29 +0000433}
434
435/* Ensure length of input buffer. Is buffer is short, double it. */
436static void
437vty_ensure (struct vty *vty, int length)
438{
439 if (vty->max <= length)
440 {
441 vty->max *= 2;
442 vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
443 }
444}
445
446/* Basic function to insert character into vty. */
447static void
448vty_self_insert (struct vty *vty, char c)
449{
450 int i;
451 int length;
452
453 vty_ensure (vty, vty->length + 1);
454 length = vty->length - vty->cp;
455 memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
456 vty->buf[vty->cp] = c;
457
458 vty_write (vty, &vty->buf[vty->cp], length + 1);
459 for (i = 0; i < length; i++)
460 vty_write (vty, &telnet_backward_char, 1);
461
462 vty->cp++;
463 vty->length++;
464}
465
466/* Self insert character 'c' in overwrite mode. */
467static void
468vty_self_insert_overwrite (struct vty *vty, char c)
469{
470 vty_ensure (vty, vty->length + 1);
471 vty->buf[vty->cp++] = c;
472
473 if (vty->cp > vty->length)
474 vty->length++;
475
476 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
477 return;
478
479 vty_write (vty, &c, 1);
480}
481
482/* Insert a word into vty interface with overwrite mode. */
483static void
484vty_insert_word_overwrite (struct vty *vty, char *str)
485{
486 int len = strlen (str);
487 vty_write (vty, str, len);
488 strcpy (&vty->buf[vty->cp], str);
489 vty->cp += len;
490 vty->length = vty->cp;
491}
492
493/* Forward character. */
494static void
495vty_forward_char (struct vty *vty)
496{
497 if (vty->cp < vty->length)
498 {
499 vty_write (vty, &vty->buf[vty->cp], 1);
500 vty->cp++;
501 }
502}
503
504/* Backward character. */
505static void
506vty_backward_char (struct vty *vty)
507{
508 if (vty->cp > 0)
509 {
510 vty->cp--;
511 vty_write (vty, &telnet_backward_char, 1);
512 }
513}
514
515/* Move to the beginning of the line. */
516static void
517vty_beginning_of_line (struct vty *vty)
518{
519 while (vty->cp)
520 vty_backward_char (vty);
521}
522
523/* Move to the end of the line. */
524static void
525vty_end_of_line (struct vty *vty)
526{
527 while (vty->cp < vty->length)
528 vty_forward_char (vty);
529}
530
531static void vty_kill_line_from_beginning (struct vty *);
532static void vty_redraw_line (struct vty *);
533
534/* Print command line history. This function is called from
535 vty_next_line and vty_previous_line. */
536static void
537vty_history_print (struct vty *vty)
538{
539 int length;
540
541 vty_kill_line_from_beginning (vty);
542
543 /* Get previous line from history buffer */
544 length = strlen (vty->hist[vty->hp]);
545 memcpy (vty->buf, vty->hist[vty->hp], length);
546 vty->cp = vty->length = length;
547
548 /* Redraw current line */
549 vty_redraw_line (vty);
550}
551
552/* Show next command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000553static void
paul718e3742002-12-13 20:15:29 +0000554vty_next_line (struct vty *vty)
555{
556 int try_index;
557
558 if (vty->hp == vty->hindex)
559 return;
560
561 /* Try is there history exist or not. */
562 try_index = vty->hp;
563 if (try_index == (VTY_MAXHIST - 1))
564 try_index = 0;
565 else
566 try_index++;
567
568 /* If there is not history return. */
569 if (vty->hist[try_index] == NULL)
570 return;
571 else
572 vty->hp = try_index;
573
574 vty_history_print (vty);
575}
576
577/* Show previous command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000578static void
paul718e3742002-12-13 20:15:29 +0000579vty_previous_line (struct vty *vty)
580{
581 int try_index;
582
583 try_index = vty->hp;
584 if (try_index == 0)
585 try_index = VTY_MAXHIST - 1;
586 else
587 try_index--;
588
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/* This function redraw all of the command line character. */
598static void
599vty_redraw_line (struct vty *vty)
600{
601 vty_write (vty, vty->buf, vty->length);
602 vty->cp = vty->length;
603}
604
605/* Forward word. */
606static void
607vty_forward_word (struct vty *vty)
608{
609 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
610 vty_forward_char (vty);
611
612 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
613 vty_forward_char (vty);
614}
615
616/* Backward word without skipping training space. */
617static void
618vty_backward_pure_word (struct vty *vty)
619{
620 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
621 vty_backward_char (vty);
622}
623
624/* Backward word. */
625static void
626vty_backward_word (struct vty *vty)
627{
628 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
629 vty_backward_char (vty);
630
631 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
632 vty_backward_char (vty);
633}
634
635/* When '^D' is typed at the beginning of the line we move to the down
636 level. */
637static void
638vty_down_level (struct vty *vty)
639{
640 vty_out (vty, "%s", VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +0000641 (*config_exit_cmd.func)(NULL, vty, 0, NULL);
paul718e3742002-12-13 20:15:29 +0000642 vty_prompt (vty);
643 vty->cp = 0;
644}
645
646/* When '^Z' is received from vty, move down to the enable mode. */
ajs9fc7ebf2005-02-23 15:12:34 +0000647static void
paul718e3742002-12-13 20:15:29 +0000648vty_end_config (struct vty *vty)
649{
650 vty_out (vty, "%s", VTY_NEWLINE);
651
652 switch (vty->node)
653 {
654 case VIEW_NODE:
655 case ENABLE_NODE:
656 /* Nothing to do. */
657 break;
658 case CONFIG_NODE:
659 case INTERFACE_NODE:
660 case ZEBRA_NODE:
661 case RIP_NODE:
662 case RIPNG_NODE:
663 case BGP_NODE:
664 case BGP_VPNV4_NODE:
665 case BGP_IPV4_NODE:
666 case BGP_IPV4M_NODE:
667 case BGP_IPV6_NODE:
668 case RMAP_NODE:
669 case OSPF_NODE:
670 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +0000671 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +0000672 case KEYCHAIN_NODE:
673 case KEYCHAIN_KEY_NODE:
674 case MASC_NODE:
675 case VTY_NODE:
676 vty_config_unlock (vty);
677 vty->node = ENABLE_NODE;
678 break;
679 default:
680 /* Unknown node, we have to ignore it. */
681 break;
682 }
683
684 vty_prompt (vty);
685 vty->cp = 0;
686}
687
688/* Delete a charcter at the current point. */
689static void
690vty_delete_char (struct vty *vty)
691{
692 int i;
693 int size;
694
695 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
696 return;
697
698 if (vty->length == 0)
699 {
700 vty_down_level (vty);
701 return;
702 }
703
704 if (vty->cp == vty->length)
705 return; /* completion need here? */
706
707 size = vty->length - vty->cp;
708
709 vty->length--;
710 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
711 vty->buf[vty->length] = '\0';
712
713 vty_write (vty, &vty->buf[vty->cp], size - 1);
714 vty_write (vty, &telnet_space_char, 1);
715
716 for (i = 0; i < size; i++)
717 vty_write (vty, &telnet_backward_char, 1);
718}
719
720/* Delete a character before the point. */
721static void
722vty_delete_backward_char (struct vty *vty)
723{
724 if (vty->cp == 0)
725 return;
726
727 vty_backward_char (vty);
728 vty_delete_char (vty);
729}
730
731/* Kill rest of line from current point. */
732static void
733vty_kill_line (struct vty *vty)
734{
735 int i;
736 int size;
737
738 size = vty->length - vty->cp;
739
740 if (size == 0)
741 return;
742
743 for (i = 0; i < size; i++)
744 vty_write (vty, &telnet_space_char, 1);
745 for (i = 0; i < size; i++)
746 vty_write (vty, &telnet_backward_char, 1);
747
748 memset (&vty->buf[vty->cp], 0, size);
749 vty->length = vty->cp;
750}
751
752/* Kill line from the beginning. */
753static void
754vty_kill_line_from_beginning (struct vty *vty)
755{
756 vty_beginning_of_line (vty);
757 vty_kill_line (vty);
758}
759
760/* Delete a word before the point. */
761static void
762vty_forward_kill_word (struct vty *vty)
763{
764 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
765 vty_delete_char (vty);
766 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
767 vty_delete_char (vty);
768}
769
770/* Delete a word before the point. */
771static void
772vty_backward_kill_word (struct vty *vty)
773{
774 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
775 vty_delete_backward_char (vty);
776 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
777 vty_delete_backward_char (vty);
778}
779
780/* Transpose chars before or at the point. */
781static void
782vty_transpose_chars (struct vty *vty)
783{
784 char c1, c2;
785
786 /* If length is short or point is near by the beginning of line then
787 return. */
788 if (vty->length < 2 || vty->cp < 1)
789 return;
790
791 /* In case of point is located at the end of the line. */
792 if (vty->cp == vty->length)
793 {
794 c1 = vty->buf[vty->cp - 1];
795 c2 = vty->buf[vty->cp - 2];
796
797 vty_backward_char (vty);
798 vty_backward_char (vty);
799 vty_self_insert_overwrite (vty, c1);
800 vty_self_insert_overwrite (vty, c2);
801 }
802 else
803 {
804 c1 = vty->buf[vty->cp];
805 c2 = vty->buf[vty->cp - 1];
806
807 vty_backward_char (vty);
808 vty_self_insert_overwrite (vty, c1);
809 vty_self_insert_overwrite (vty, c2);
810 }
811}
812
813/* Do completion at vty interface. */
814static void
815vty_complete_command (struct vty *vty)
816{
817 int i;
818 int ret;
819 char **matched = NULL;
820 vector vline;
821
822 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
823 return;
824
825 vline = cmd_make_strvec (vty->buf);
826 if (vline == NULL)
827 return;
828
829 /* In case of 'help \t'. */
830 if (isspace ((int) vty->buf[vty->length - 1]))
831 vector_set (vline, '\0');
832
833 matched = cmd_complete_command (vline, vty, &ret);
834
835 cmd_free_strvec (vline);
836
837 vty_out (vty, "%s", VTY_NEWLINE);
838 switch (ret)
839 {
840 case CMD_ERR_AMBIGUOUS:
841 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
842 vty_prompt (vty);
843 vty_redraw_line (vty);
844 break;
845 case CMD_ERR_NO_MATCH:
846 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
847 vty_prompt (vty);
848 vty_redraw_line (vty);
849 break;
850 case CMD_COMPLETE_FULL_MATCH:
851 vty_prompt (vty);
852 vty_redraw_line (vty);
853 vty_backward_pure_word (vty);
854 vty_insert_word_overwrite (vty, matched[0]);
855 vty_self_insert (vty, ' ');
856 XFREE (MTYPE_TMP, matched[0]);
857 break;
858 case CMD_COMPLETE_MATCH:
859 vty_prompt (vty);
860 vty_redraw_line (vty);
861 vty_backward_pure_word (vty);
862 vty_insert_word_overwrite (vty, matched[0]);
863 XFREE (MTYPE_TMP, matched[0]);
864 vector_only_index_free (matched);
865 return;
866 break;
867 case CMD_COMPLETE_LIST_MATCH:
868 for (i = 0; matched[i] != NULL; i++)
869 {
870 if (i != 0 && ((i % 6) == 0))
871 vty_out (vty, "%s", VTY_NEWLINE);
872 vty_out (vty, "%-10s ", matched[i]);
873 XFREE (MTYPE_TMP, matched[i]);
874 }
875 vty_out (vty, "%s", VTY_NEWLINE);
876
877 vty_prompt (vty);
878 vty_redraw_line (vty);
879 break;
880 case CMD_ERR_NOTHING_TODO:
881 vty_prompt (vty);
882 vty_redraw_line (vty);
883 break;
884 default:
885 break;
886 }
887 if (matched)
888 vector_only_index_free (matched);
889}
890
ajs9fc7ebf2005-02-23 15:12:34 +0000891static void
paul718e3742002-12-13 20:15:29 +0000892vty_describe_fold (struct vty *vty, int cmd_width,
hasso8c328f12004-10-05 21:01:23 +0000893 unsigned int desc_width, struct desc *desc)
paul718e3742002-12-13 20:15:29 +0000894{
hasso8c328f12004-10-05 21:01:23 +0000895 char *buf;
896 const char *cmd, *p;
paul718e3742002-12-13 20:15:29 +0000897 int pos;
898
899 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
900
901 if (desc_width <= 0)
902 {
903 vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
904 return;
905 }
906
907 buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
908
909 for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
910 {
911 for (pos = desc_width; pos > 0; pos--)
912 if (*(p + pos) == ' ')
913 break;
914
915 if (pos == 0)
916 break;
917
918 strncpy (buf, p, pos);
919 buf[pos] = '\0';
920 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
921
922 cmd = "";
923 }
924
925 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
926
927 XFREE (MTYPE_TMP, buf);
928}
929
930/* Describe matched command function. */
931static void
932vty_describe_command (struct vty *vty)
933{
934 int ret;
935 vector vline;
936 vector describe;
hasso8c328f12004-10-05 21:01:23 +0000937 unsigned int i, width, desc_width;
paul718e3742002-12-13 20:15:29 +0000938 struct desc *desc, *desc_cr = NULL;
939
940 vline = cmd_make_strvec (vty->buf);
941
942 /* In case of '> ?'. */
943 if (vline == NULL)
944 {
945 vline = vector_init (1);
946 vector_set (vline, '\0');
947 }
948 else
949 if (isspace ((int) vty->buf[vty->length - 1]))
950 vector_set (vline, '\0');
951
952 describe = cmd_describe_command (vline, vty, &ret);
953
954 vty_out (vty, "%s", VTY_NEWLINE);
955
956 /* Ambiguous error. */
957 switch (ret)
958 {
959 case CMD_ERR_AMBIGUOUS:
960 cmd_free_strvec (vline);
961 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
962 vty_prompt (vty);
963 vty_redraw_line (vty);
964 return;
965 break;
966 case CMD_ERR_NO_MATCH:
967 cmd_free_strvec (vline);
968 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
969 vty_prompt (vty);
970 vty_redraw_line (vty);
971 return;
972 break;
973 }
974
975 /* Get width of command string. */
976 width = 0;
977 for (i = 0; i < vector_max (describe); i++)
978 if ((desc = vector_slot (describe, i)) != NULL)
979 {
hasso8c328f12004-10-05 21:01:23 +0000980 unsigned int len;
paul718e3742002-12-13 20:15:29 +0000981
982 if (desc->cmd[0] == '\0')
983 continue;
984
985 len = strlen (desc->cmd);
986 if (desc->cmd[0] == '.')
987 len--;
988
989 if (width < len)
990 width = len;
991 }
992
993 /* Get width of description string. */
994 desc_width = vty->width - (width + 6);
995
996 /* Print out description. */
997 for (i = 0; i < vector_max (describe); i++)
998 if ((desc = vector_slot (describe, i)) != NULL)
999 {
1000 if (desc->cmd[0] == '\0')
1001 continue;
1002
1003 if (strcmp (desc->cmd, "<cr>") == 0)
1004 {
1005 desc_cr = desc;
1006 continue;
1007 }
1008
1009 if (!desc->str)
1010 vty_out (vty, " %-s%s",
1011 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1012 VTY_NEWLINE);
1013 else if (desc_width >= strlen (desc->str))
1014 vty_out (vty, " %-*s %s%s", width,
1015 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1016 desc->str, VTY_NEWLINE);
1017 else
1018 vty_describe_fold (vty, width, desc_width, desc);
1019
1020#if 0
1021 vty_out (vty, " %-*s %s%s", width
1022 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1023 desc->str ? desc->str : "", VTY_NEWLINE);
1024#endif /* 0 */
1025 }
1026
1027 if ((desc = desc_cr))
1028 {
1029 if (!desc->str)
1030 vty_out (vty, " %-s%s",
1031 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1032 VTY_NEWLINE);
1033 else if (desc_width >= strlen (desc->str))
1034 vty_out (vty, " %-*s %s%s", width,
1035 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1036 desc->str, VTY_NEWLINE);
1037 else
1038 vty_describe_fold (vty, width, desc_width, desc);
1039 }
1040
1041 cmd_free_strvec (vline);
1042 vector_free (describe);
1043
1044 vty_prompt (vty);
1045 vty_redraw_line (vty);
1046}
1047
ajs9fc7ebf2005-02-23 15:12:34 +00001048static void
paul718e3742002-12-13 20:15:29 +00001049vty_clear_buf (struct vty *vty)
1050{
1051 memset (vty->buf, 0, vty->max);
1052}
1053
1054/* ^C stop current input and do not add command line to the history. */
1055static void
1056vty_stop_input (struct vty *vty)
1057{
1058 vty->cp = vty->length = 0;
1059 vty_clear_buf (vty);
1060 vty_out (vty, "%s", VTY_NEWLINE);
1061
1062 switch (vty->node)
1063 {
1064 case VIEW_NODE:
1065 case ENABLE_NODE:
1066 /* Nothing to do. */
1067 break;
1068 case CONFIG_NODE:
1069 case INTERFACE_NODE:
1070 case ZEBRA_NODE:
1071 case RIP_NODE:
1072 case RIPNG_NODE:
1073 case BGP_NODE:
1074 case RMAP_NODE:
1075 case OSPF_NODE:
1076 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00001077 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00001078 case KEYCHAIN_NODE:
1079 case KEYCHAIN_KEY_NODE:
1080 case MASC_NODE:
1081 case VTY_NODE:
1082 vty_config_unlock (vty);
1083 vty->node = ENABLE_NODE;
1084 break;
1085 default:
1086 /* Unknown node, we have to ignore it. */
1087 break;
1088 }
1089 vty_prompt (vty);
1090
1091 /* Set history pointer to the latest one. */
1092 vty->hp = vty->hindex;
1093}
1094
1095/* Add current command line to the history buffer. */
1096static void
1097vty_hist_add (struct vty *vty)
1098{
1099 int index;
1100
1101 if (vty->length == 0)
1102 return;
1103
1104 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1105
1106 /* Ignore the same string as previous one. */
1107 if (vty->hist[index])
1108 if (strcmp (vty->buf, vty->hist[index]) == 0)
1109 {
1110 vty->hp = vty->hindex;
1111 return;
1112 }
1113
1114 /* Insert history entry. */
1115 if (vty->hist[vty->hindex])
1116 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1117 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1118
1119 /* History index rotation. */
1120 vty->hindex++;
1121 if (vty->hindex == VTY_MAXHIST)
1122 vty->hindex = 0;
1123
1124 vty->hp = vty->hindex;
1125}
1126
1127/* #define TELNET_OPTION_DEBUG */
1128
1129/* Get telnet window size. */
1130static int
1131vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1132{
1133#ifdef TELNET_OPTION_DEBUG
1134 int i;
1135
1136 for (i = 0; i < nbytes; i++)
1137 {
1138 switch (buf[i])
1139 {
1140 case IAC:
1141 vty_out (vty, "IAC ");
1142 break;
1143 case WILL:
1144 vty_out (vty, "WILL ");
1145 break;
1146 case WONT:
1147 vty_out (vty, "WONT ");
1148 break;
1149 case DO:
1150 vty_out (vty, "DO ");
1151 break;
1152 case DONT:
1153 vty_out (vty, "DONT ");
1154 break;
1155 case SB:
1156 vty_out (vty, "SB ");
1157 break;
1158 case SE:
1159 vty_out (vty, "SE ");
1160 break;
1161 case TELOPT_ECHO:
1162 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1163 break;
1164 case TELOPT_SGA:
1165 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1166 break;
1167 case TELOPT_NAWS:
1168 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1169 break;
1170 default:
1171 vty_out (vty, "%x ", buf[i]);
1172 break;
1173 }
1174 }
1175 vty_out (vty, "%s", VTY_NEWLINE);
1176
1177#endif /* TELNET_OPTION_DEBUG */
1178
1179 switch (buf[0])
1180 {
1181 case SB:
ajs9fc7ebf2005-02-23 15:12:34 +00001182 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001183 vty->iac_sb_in_progress = 1;
1184 return 0;
1185 break;
1186 case SE:
1187 {
paul718e3742002-12-13 20:15:29 +00001188 if (!vty->iac_sb_in_progress)
1189 return 0;
1190
ajs9fc7ebf2005-02-23 15:12:34 +00001191 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
paul718e3742002-12-13 20:15:29 +00001192 {
1193 vty->iac_sb_in_progress = 0;
1194 return 0;
1195 }
ajs9fc7ebf2005-02-23 15:12:34 +00001196 switch (vty->sb_buf[0])
paul718e3742002-12-13 20:15:29 +00001197 {
1198 case TELOPT_NAWS:
ajs9fc7ebf2005-02-23 15:12:34 +00001199 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1200 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1201 "should send %d characters, but we received %lu",
1202 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1203 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1204 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1205 "too small to handle the telnet NAWS option",
1206 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1207 else
1208 {
1209 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1210 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1211#ifdef TELNET_OPTION_DEBUG
1212 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1213 "width %d, height %d%s",
1214 vty->width, vty->height, VTY_NEWLINE);
1215#endif
1216 }
paul718e3742002-12-13 20:15:29 +00001217 break;
1218 }
1219 vty->iac_sb_in_progress = 0;
1220 return 0;
1221 break;
1222 }
1223 default:
1224 break;
1225 }
1226 return 1;
1227}
1228
1229/* Execute current command line. */
1230static int
1231vty_execute (struct vty *vty)
1232{
1233 int ret;
1234
1235 ret = CMD_SUCCESS;
1236
1237 switch (vty->node)
1238 {
1239 case AUTH_NODE:
1240 case AUTH_ENABLE_NODE:
1241 vty_auth (vty, vty->buf);
1242 break;
1243 default:
1244 ret = vty_command (vty, vty->buf);
1245 if (vty->type == VTY_TERM)
1246 vty_hist_add (vty);
1247 break;
1248 }
1249
1250 /* Clear command line buffer. */
1251 vty->cp = vty->length = 0;
1252 vty_clear_buf (vty);
1253
ajs5a646652004-11-05 01:25:55 +00001254 if (vty->status != VTY_CLOSE )
paul718e3742002-12-13 20:15:29 +00001255 vty_prompt (vty);
1256
1257 return ret;
1258}
1259
1260#define CONTROL(X) ((X) - '@')
1261#define VTY_NORMAL 0
1262#define VTY_PRE_ESCAPE 1
1263#define VTY_ESCAPE 2
1264
1265/* Escape character command map. */
1266static void
1267vty_escape_map (unsigned char c, struct vty *vty)
1268{
1269 switch (c)
1270 {
1271 case ('A'):
1272 vty_previous_line (vty);
1273 break;
1274 case ('B'):
1275 vty_next_line (vty);
1276 break;
1277 case ('C'):
1278 vty_forward_char (vty);
1279 break;
1280 case ('D'):
1281 vty_backward_char (vty);
1282 break;
1283 default:
1284 break;
1285 }
1286
1287 /* Go back to normal mode. */
1288 vty->escape = VTY_NORMAL;
1289}
1290
1291/* Quit print out to the buffer. */
1292static void
1293vty_buffer_reset (struct vty *vty)
1294{
1295 buffer_reset (vty->obuf);
1296 vty_prompt (vty);
1297 vty_redraw_line (vty);
1298}
1299
1300/* Read data via vty socket. */
1301static int
1302vty_read (struct thread *thread)
1303{
1304 int i;
paul718e3742002-12-13 20:15:29 +00001305 int nbytes;
1306 unsigned char buf[VTY_READ_BUFSIZ];
1307
1308 int vty_sock = THREAD_FD (thread);
1309 struct vty *vty = THREAD_ARG (thread);
1310 vty->t_read = NULL;
1311
1312 /* Read raw data from socket */
ajs9fc7ebf2005-02-23 15:12:34 +00001313 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1314 {
1315 if (nbytes < 0)
1316 {
1317 if (ERRNO_IO_RETRY(errno))
1318 {
1319 vty_event (VTY_READ, vty_sock, vty);
1320 return 0;
1321 }
1322 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1323 __func__, vty->fd, safe_strerror(errno));
1324 }
1325 buffer_reset(vty->obuf);
1326 vty->status = VTY_CLOSE;
1327 }
paul718e3742002-12-13 20:15:29 +00001328
1329 for (i = 0; i < nbytes; i++)
1330 {
1331 if (buf[i] == IAC)
1332 {
1333 if (!vty->iac)
1334 {
1335 vty->iac = 1;
1336 continue;
1337 }
1338 else
1339 {
1340 vty->iac = 0;
1341 }
1342 }
1343
1344 if (vty->iac_sb_in_progress && !vty->iac)
1345 {
ajs9fc7ebf2005-02-23 15:12:34 +00001346 if (vty->sb_len < sizeof(vty->sb_buf))
1347 vty->sb_buf[vty->sb_len] = buf[i];
1348 vty->sb_len++;
paul718e3742002-12-13 20:15:29 +00001349 continue;
1350 }
1351
1352 if (vty->iac)
1353 {
1354 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001355 int ret = 0;
paule9372532003-10-26 21:36:07 +00001356 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001357 vty->iac = 0;
1358 i += ret;
1359 continue;
1360 }
paul5b8c1b02003-10-15 23:08:55 +00001361
paul718e3742002-12-13 20:15:29 +00001362
1363 if (vty->status == VTY_MORE)
1364 {
1365 switch (buf[i])
1366 {
1367 case CONTROL('C'):
1368 case 'q':
1369 case 'Q':
paul718e3742002-12-13 20:15:29 +00001370 vty_buffer_reset (vty);
1371 break;
1372#if 0 /* More line does not work for "show ip bgp". */
1373 case '\n':
1374 case '\r':
1375 vty->status = VTY_MORELINE;
1376 break;
1377#endif
1378 default:
paul718e3742002-12-13 20:15:29 +00001379 break;
1380 }
1381 continue;
1382 }
1383
1384 /* Escape character. */
1385 if (vty->escape == VTY_ESCAPE)
1386 {
1387 vty_escape_map (buf[i], vty);
1388 continue;
1389 }
1390
1391 /* Pre-escape status. */
1392 if (vty->escape == VTY_PRE_ESCAPE)
1393 {
1394 switch (buf[i])
1395 {
1396 case '[':
1397 vty->escape = VTY_ESCAPE;
1398 break;
1399 case 'b':
1400 vty_backward_word (vty);
1401 vty->escape = VTY_NORMAL;
1402 break;
1403 case 'f':
1404 vty_forward_word (vty);
1405 vty->escape = VTY_NORMAL;
1406 break;
1407 case 'd':
1408 vty_forward_kill_word (vty);
1409 vty->escape = VTY_NORMAL;
1410 break;
1411 case CONTROL('H'):
1412 case 0x7f:
1413 vty_backward_kill_word (vty);
1414 vty->escape = VTY_NORMAL;
1415 break;
1416 default:
1417 vty->escape = VTY_NORMAL;
1418 break;
1419 }
1420 continue;
1421 }
1422
1423 switch (buf[i])
1424 {
1425 case CONTROL('A'):
1426 vty_beginning_of_line (vty);
1427 break;
1428 case CONTROL('B'):
1429 vty_backward_char (vty);
1430 break;
1431 case CONTROL('C'):
1432 vty_stop_input (vty);
1433 break;
1434 case CONTROL('D'):
1435 vty_delete_char (vty);
1436 break;
1437 case CONTROL('E'):
1438 vty_end_of_line (vty);
1439 break;
1440 case CONTROL('F'):
1441 vty_forward_char (vty);
1442 break;
1443 case CONTROL('H'):
1444 case 0x7f:
1445 vty_delete_backward_char (vty);
1446 break;
1447 case CONTROL('K'):
1448 vty_kill_line (vty);
1449 break;
1450 case CONTROL('N'):
1451 vty_next_line (vty);
1452 break;
1453 case CONTROL('P'):
1454 vty_previous_line (vty);
1455 break;
1456 case CONTROL('T'):
1457 vty_transpose_chars (vty);
1458 break;
1459 case CONTROL('U'):
1460 vty_kill_line_from_beginning (vty);
1461 break;
1462 case CONTROL('W'):
1463 vty_backward_kill_word (vty);
1464 break;
1465 case CONTROL('Z'):
1466 vty_end_config (vty);
1467 break;
1468 case '\n':
1469 case '\r':
1470 vty_out (vty, "%s", VTY_NEWLINE);
1471 vty_execute (vty);
1472 break;
1473 case '\t':
1474 vty_complete_command (vty);
1475 break;
1476 case '?':
1477 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1478 vty_self_insert (vty, buf[i]);
1479 else
1480 vty_describe_command (vty);
1481 break;
1482 case '\033':
1483 if (i + 1 < nbytes && buf[i + 1] == '[')
1484 {
1485 vty->escape = VTY_ESCAPE;
1486 i++;
1487 }
1488 else
1489 vty->escape = VTY_PRE_ESCAPE;
1490 break;
1491 default:
1492 if (buf[i] > 31 && buf[i] < 127)
1493 vty_self_insert (vty, buf[i]);
1494 break;
1495 }
1496 }
1497
1498 /* Check status. */
1499 if (vty->status == VTY_CLOSE)
1500 vty_close (vty);
1501 else
1502 {
1503 vty_event (VTY_WRITE, vty_sock, vty);
1504 vty_event (VTY_READ, vty_sock, vty);
1505 }
1506 return 0;
1507}
1508
1509/* Flush buffer to the vty. */
1510static int
1511vty_flush (struct thread *thread)
1512{
1513 int erase;
ajs9fc7ebf2005-02-23 15:12:34 +00001514 buffer_status_t flushrc;
paul718e3742002-12-13 20:15:29 +00001515 int vty_sock = THREAD_FD (thread);
1516 struct vty *vty = THREAD_ARG (thread);
ajs9fc7ebf2005-02-23 15:12:34 +00001517
paul718e3742002-12-13 20:15:29 +00001518 vty->t_write = NULL;
1519
1520 /* Tempolary disable read thread. */
ajs9fc7ebf2005-02-23 15:12:34 +00001521 if ((vty->lines == 0) && vty->t_read)
1522 {
1523 thread_cancel (vty->t_read);
1524 vty->t_read = NULL;
1525 }
paul718e3742002-12-13 20:15:29 +00001526
1527 /* Function execution continue. */
ajs9fc7ebf2005-02-23 15:12:34 +00001528 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
paul718e3742002-12-13 20:15:29 +00001529
ajs9fc7ebf2005-02-23 15:12:34 +00001530 /* N.B. if width is 0, that means we don't know the window size. */
1531 if ((vty->lines == 0) || (vty->width == 0))
1532 flushrc = buffer_flush_available(vty->obuf, vty->fd);
1533 else if (vty->status == VTY_MORELINE)
1534 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1535 1, erase, 0);
1536 else
1537 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1538 vty->lines >= 0 ? vty->lines :
1539 vty->height,
1540 erase, 0);
1541 switch (flushrc)
1542 {
1543 case BUFFER_ERROR:
1544 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1545 vty->fd);
1546 buffer_reset(vty->obuf);
1547 vty_close(vty);
1548 return 0;
1549 case BUFFER_EMPTY:
1550 if (vty->status == VTY_CLOSE)
1551 vty_close (vty);
paul718e3742002-12-13 20:15:29 +00001552 else
1553 {
ajs9fc7ebf2005-02-23 15:12:34 +00001554 vty->status = VTY_NORMAL;
paul718e3742002-12-13 20:15:29 +00001555 if (vty->lines == 0)
ajs9fc7ebf2005-02-23 15:12:34 +00001556 vty_event (VTY_READ, vty_sock, vty);
paul718e3742002-12-13 20:15:29 +00001557 }
ajs9fc7ebf2005-02-23 15:12:34 +00001558 break;
1559 case BUFFER_PENDING:
1560 /* There is more data waiting to be written. */
1561 vty->status = VTY_MORE;
1562 if (vty->lines == 0)
1563 vty_event (VTY_WRITE, vty_sock, vty);
1564 break;
1565 }
paul718e3742002-12-13 20:15:29 +00001566
1567 return 0;
1568}
1569
1570/* Create new vty structure. */
ajs9fc7ebf2005-02-23 15:12:34 +00001571static struct vty *
paul718e3742002-12-13 20:15:29 +00001572vty_create (int vty_sock, union sockunion *su)
1573{
1574 struct vty *vty;
1575
1576 /* Allocate new vty structure and set up default values. */
1577 vty = vty_new ();
1578 vty->fd = vty_sock;
1579 vty->type = VTY_TERM;
1580 vty->address = sockunion_su2str (su);
1581 if (no_password_check)
1582 {
1583 if (host.advanced)
1584 vty->node = ENABLE_NODE;
1585 else
1586 vty->node = VIEW_NODE;
1587 }
1588 else
1589 vty->node = AUTH_NODE;
1590 vty->fail = 0;
1591 vty->cp = 0;
1592 vty_clear_buf (vty);
1593 vty->length = 0;
1594 memset (vty->hist, 0, sizeof (vty->hist));
1595 vty->hp = 0;
1596 vty->hindex = 0;
1597 vector_set_index (vtyvec, vty_sock, vty);
1598 vty->status = VTY_NORMAL;
1599 vty->v_timeout = vty_timeout_val;
1600 if (host.lines >= 0)
1601 vty->lines = host.lines;
1602 else
1603 vty->lines = -1;
1604 vty->iac = 0;
1605 vty->iac_sb_in_progress = 0;
ajs9fc7ebf2005-02-23 15:12:34 +00001606 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001607
1608 if (! no_password_check)
1609 {
1610 /* Vty is not available if password isn't set. */
1611 if (host.password == NULL && host.password_encrypt == NULL)
1612 {
1613 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1614 vty->status = VTY_CLOSE;
1615 vty_close (vty);
1616 return NULL;
1617 }
1618 }
1619
1620 /* Say hello to the world. */
1621 vty_hello (vty);
1622 if (! no_password_check)
1623 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1624
1625 /* Setting up terminal. */
1626 vty_will_echo (vty);
1627 vty_will_suppress_go_ahead (vty);
1628
1629 vty_dont_linemode (vty);
1630 vty_do_window_size (vty);
1631 /* vty_dont_lflow_ahead (vty); */
1632
1633 vty_prompt (vty);
1634
1635 /* Add read/write thread. */
1636 vty_event (VTY_WRITE, vty_sock, vty);
1637 vty_event (VTY_READ, vty_sock, vty);
1638
1639 return vty;
1640}
1641
1642/* Accept connection from the network. */
1643static int
1644vty_accept (struct thread *thread)
1645{
1646 int vty_sock;
1647 struct vty *vty;
1648 union sockunion su;
1649 int ret;
1650 unsigned int on;
1651 int accept_sock;
1652 struct prefix *p = NULL;
1653 struct access_list *acl = NULL;
1654
1655 accept_sock = THREAD_FD (thread);
1656
1657 /* We continue hearing vty socket. */
1658 vty_event (VTY_SERV, accept_sock, NULL);
1659
1660 memset (&su, 0, sizeof (union sockunion));
1661
1662 /* We can handle IPv4 or IPv6 socket. */
1663 vty_sock = sockunion_accept (accept_sock, &su);
1664 if (vty_sock < 0)
1665 {
ajs6099b3b2004-11-20 02:06:59 +00001666 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001667 return -1;
1668 }
ajs9fc7ebf2005-02-23 15:12:34 +00001669 set_nonblocking(vty_sock);
paul718e3742002-12-13 20:15:29 +00001670
1671 p = sockunion2hostprefix (&su);
1672
1673 /* VTY's accesslist apply. */
1674 if (p->family == AF_INET && vty_accesslist_name)
1675 {
1676 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1677 (access_list_apply (acl, p) == FILTER_DENY))
1678 {
1679 char *buf;
1680 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1681 (buf = sockunion_su2str (&su)));
1682 free (buf);
1683 close (vty_sock);
1684
1685 /* continue accepting connections */
1686 vty_event (VTY_SERV, accept_sock, NULL);
1687
1688 prefix_free (p);
1689
1690 return 0;
1691 }
1692 }
1693
1694#ifdef HAVE_IPV6
1695 /* VTY's ipv6 accesslist apply. */
1696 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1697 {
1698 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1699 (access_list_apply (acl, p) == FILTER_DENY))
1700 {
1701 char *buf;
1702 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1703 (buf = sockunion_su2str (&su)));
1704 free (buf);
1705 close (vty_sock);
1706
1707 /* continue accepting connections */
1708 vty_event (VTY_SERV, accept_sock, NULL);
1709
1710 prefix_free (p);
1711
1712 return 0;
1713 }
1714 }
1715#endif /* HAVE_IPV6 */
1716
1717 prefix_free (p);
1718
1719 on = 1;
1720 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1721 (char *) &on, sizeof (on));
1722 if (ret < 0)
1723 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
ajs6099b3b2004-11-20 02:06:59 +00001724 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001725
1726 vty = vty_create (vty_sock, &su);
1727
1728 return 0;
1729}
1730
1731#if defined(HAVE_IPV6) && !defined(NRL)
ajs9fc7ebf2005-02-23 15:12:34 +00001732static void
paul718e3742002-12-13 20:15:29 +00001733vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1734{
1735 int ret;
1736 struct addrinfo req;
1737 struct addrinfo *ainfo;
1738 struct addrinfo *ainfo_save;
1739 int sock;
1740 char port_str[BUFSIZ];
1741
1742 memset (&req, 0, sizeof (struct addrinfo));
1743 req.ai_flags = AI_PASSIVE;
1744 req.ai_family = AF_UNSPEC;
1745 req.ai_socktype = SOCK_STREAM;
1746 sprintf (port_str, "%d", port);
1747 port_str[sizeof (port_str) - 1] = '\0';
1748
1749 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1750
1751 if (ret != 0)
1752 {
1753 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1754 exit (1);
1755 }
1756
1757 ainfo_save = ainfo;
1758
1759 do
1760 {
1761 if (ainfo->ai_family != AF_INET
1762#ifdef HAVE_IPV6
1763 && ainfo->ai_family != AF_INET6
1764#endif /* HAVE_IPV6 */
1765 )
1766 continue;
1767
1768 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1769 if (sock < 0)
1770 continue;
1771
1772 sockopt_reuseaddr (sock);
1773 sockopt_reuseport (sock);
1774
1775 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1776 if (ret < 0)
1777 {
1778 close (sock); /* Avoid sd leak. */
1779 continue;
1780 }
1781
1782 ret = listen (sock, 3);
1783 if (ret < 0)
1784 {
1785 close (sock); /* Avoid sd leak. */
1786 continue;
1787 }
1788
1789 vty_event (VTY_SERV, sock, NULL);
1790 }
1791 while ((ainfo = ainfo->ai_next) != NULL);
1792
1793 freeaddrinfo (ainfo_save);
1794}
1795#endif /* HAVE_IPV6 && ! NRL */
1796
1797/* Make vty server socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001798static void
paul29db05b2003-05-08 20:10:22 +00001799vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001800{
1801 int ret;
1802 union sockunion su;
1803 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001804 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001805
1806 memset (&su, 0, sizeof (union sockunion));
1807 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001808 if(addr)
1809 switch(family)
1810 {
1811 case AF_INET:
1812 naddr=&su.sin.sin_addr;
1813#ifdef HAVE_IPV6
1814 case AF_INET6:
1815 naddr=&su.sin6.sin6_addr;
1816#endif
1817 }
1818
1819 if(naddr)
1820 switch(inet_pton(family,addr,naddr))
1821 {
1822 case -1:
1823 zlog_err("bad address %s",addr);
1824 naddr=NULL;
1825 break;
1826 case 0:
ajs6099b3b2004-11-20 02:06:59 +00001827 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
paul29db05b2003-05-08 20:10:22 +00001828 naddr=NULL;
1829 }
paul718e3742002-12-13 20:15:29 +00001830
1831 /* Make new socket. */
1832 accept_sock = sockunion_stream_socket (&su);
1833 if (accept_sock < 0)
1834 return;
1835
1836 /* This is server, so reuse address. */
1837 sockopt_reuseaddr (accept_sock);
1838 sockopt_reuseport (accept_sock);
1839
1840 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001841 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001842 if (ret < 0)
1843 {
paul29db05b2003-05-08 20:10:22 +00001844 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001845 close (accept_sock); /* Avoid sd leak. */
1846 return;
1847 }
1848
1849 /* Listen socket under queue 3. */
1850 ret = listen (accept_sock, 3);
1851 if (ret < 0)
1852 {
1853 zlog (NULL, LOG_WARNING, "can't listen socket");
1854 close (accept_sock); /* Avoid sd leak. */
1855 return;
1856 }
1857
1858 /* Add vty server event. */
1859 vty_event (VTY_SERV, accept_sock, NULL);
1860}
1861
1862#ifdef VTYSH
1863/* For sockaddr_un. */
1864#include <sys/un.h>
1865
1866/* VTY shell UNIX domain socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001867static void
hasso6ad96ea2004-10-07 19:33:46 +00001868vty_serv_un (const char *path)
paul718e3742002-12-13 20:15:29 +00001869{
1870 int ret;
paul75e15fe2004-10-31 02:13:09 +00001871 int sock, len;
paul718e3742002-12-13 20:15:29 +00001872 struct sockaddr_un serv;
1873 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00001874 struct zprivs_ids_t ids;
1875
paul718e3742002-12-13 20:15:29 +00001876 /* First of all, unlink existing socket */
1877 unlink (path);
1878
1879 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00001880 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00001881
1882 /* Make UNIX domain socket. */
1883 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1884 if (sock < 0)
1885 {
ajs6a52d0d2005-01-30 18:49:28 +00001886 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001887 return;
1888 }
1889
1890 /* Make server socket. */
1891 memset (&serv, 0, sizeof (struct sockaddr_un));
1892 serv.sun_family = AF_UNIX;
1893 strncpy (serv.sun_path, path, strlen (path));
1894#ifdef HAVE_SUN_LEN
1895 len = serv.sun_len = SUN_LEN(&serv);
1896#else
1897 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1898#endif /* HAVE_SUN_LEN */
1899
1900 ret = bind (sock, (struct sockaddr *) &serv, len);
1901 if (ret < 0)
1902 {
ajs6a52d0d2005-01-30 18:49:28 +00001903 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001904 close (sock); /* Avoid sd leak. */
1905 return;
1906 }
1907
1908 ret = listen (sock, 5);
1909 if (ret < 0)
1910 {
ajs6a52d0d2005-01-30 18:49:28 +00001911 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001912 close (sock); /* Avoid sd leak. */
1913 return;
1914 }
1915
1916 umask (old_mask);
1917
pauledd7c242003-06-04 13:59:38 +00001918 zprivs_get_ids(&ids);
1919
1920 if (ids.gid_vty > 0)
1921 {
1922 /* set group of socket */
1923 if ( chown (path, -1, ids.gid_vty) )
1924 {
1925 zlog_err ("vty_serv_un: could chown socket, %s",
ajs6099b3b2004-11-20 02:06:59 +00001926 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +00001927 }
1928 }
1929
paul718e3742002-12-13 20:15:29 +00001930 vty_event (VTYSH_SERV, sock, NULL);
1931}
1932
1933/* #define VTYSH_DEBUG 1 */
1934
1935static int
1936vtysh_accept (struct thread *thread)
1937{
1938 int accept_sock;
1939 int sock;
1940 int client_len;
1941 struct sockaddr_un client;
1942 struct vty *vty;
1943
1944 accept_sock = THREAD_FD (thread);
1945
1946 vty_event (VTYSH_SERV, accept_sock, NULL);
1947
1948 memset (&client, 0, sizeof (struct sockaddr_un));
1949 client_len = sizeof (struct sockaddr_un);
1950
hassoe473b032004-09-26 16:08:11 +00001951 sock = accept (accept_sock, (struct sockaddr *) &client,
1952 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00001953
1954 if (sock < 0)
1955 {
ajs6099b3b2004-11-20 02:06:59 +00001956 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001957 return -1;
1958 }
1959
ajs9fc7ebf2005-02-23 15:12:34 +00001960 if (set_nonblocking(sock) < 0)
paul75e15fe2004-10-31 02:13:09 +00001961 {
ajs9fc7ebf2005-02-23 15:12:34 +00001962 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
1963 " %s, closing", sock, safe_strerror (errno));
paul75e15fe2004-10-31 02:13:09 +00001964 close (sock);
1965 return -1;
1966 }
pauldccfb192004-10-29 08:29:36 +00001967
paul718e3742002-12-13 20:15:29 +00001968#ifdef VTYSH_DEBUG
1969 printf ("VTY shell accept\n");
1970#endif /* VTYSH_DEBUG */
1971
1972 vty = vty_new ();
1973 vty->fd = sock;
1974 vty->type = VTY_SHELL_SERV;
1975 vty->node = VIEW_NODE;
1976
1977 vty_event (VTYSH_READ, sock, vty);
1978
1979 return 0;
1980}
1981
1982static int
ajs9fc7ebf2005-02-23 15:12:34 +00001983vtysh_flush(struct vty *vty)
1984{
1985 switch (buffer_flush_available(vty->obuf, vty->fd))
1986 {
1987 case BUFFER_PENDING:
1988 vty_event(VTYSH_WRITE, vty->fd, vty);
1989 break;
1990 case BUFFER_ERROR:
1991 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
1992 buffer_reset(vty->obuf);
1993 vty_close(vty);
1994 return -1;
1995 break;
1996 case BUFFER_EMPTY:
1997 break;
1998 }
1999 return 0;
2000}
2001
2002static int
paul718e3742002-12-13 20:15:29 +00002003vtysh_read (struct thread *thread)
2004{
2005 int ret;
2006 int sock;
2007 int nbytes;
2008 struct vty *vty;
2009 unsigned char buf[VTY_READ_BUFSIZ];
ajs9fc7ebf2005-02-23 15:12:34 +00002010 unsigned char *p;
paul718e3742002-12-13 20:15:29 +00002011 u_char header[4] = {0, 0, 0, 0};
2012
2013 sock = THREAD_FD (thread);
2014 vty = THREAD_ARG (thread);
2015 vty->t_read = NULL;
2016
ajs9fc7ebf2005-02-23 15:12:34 +00002017 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
paul718e3742002-12-13 20:15:29 +00002018 {
ajs9fc7ebf2005-02-23 15:12:34 +00002019 if (nbytes < 0)
2020 {
2021 if (ERRNO_IO_RETRY(errno))
2022 {
2023 vty_event (VTYSH_READ, sock, vty);
2024 return 0;
2025 }
2026 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2027 __func__, sock, safe_strerror(errno));
2028 }
2029 buffer_reset(vty->obuf);
paul718e3742002-12-13 20:15:29 +00002030 vty_close (vty);
2031#ifdef VTYSH_DEBUG
2032 printf ("close vtysh\n");
2033#endif /* VTYSH_DEBUG */
2034 return 0;
2035 }
2036
2037#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002038 printf ("line: %.*s\n", nbytes, buf);
paul718e3742002-12-13 20:15:29 +00002039#endif /* VTYSH_DEBUG */
2040
ajs9fc7ebf2005-02-23 15:12:34 +00002041 for (p = buf; p < buf+nbytes; p++)
2042 {
2043 vty_ensure(vty, vty->length+1);
2044 vty->buf[vty->length++] = *p;
2045 if (*p == '\0')
2046 {
2047 /* Pass this line to parser. */
2048 ret = vty_execute (vty);
2049 /* Note that vty_execute clears the command buffer and resets
2050 vty->length to 0. */
paul718e3742002-12-13 20:15:29 +00002051
ajs9fc7ebf2005-02-23 15:12:34 +00002052 /* Return result. */
paul718e3742002-12-13 20:15:29 +00002053#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002054 printf ("result: %d\n", ret);
2055 printf ("vtysh node: %d\n", vty->node);
paul718e3742002-12-13 20:15:29 +00002056#endif /* VTYSH_DEBUG */
2057
ajs9fc7ebf2005-02-23 15:12:34 +00002058 header[3] = ret;
2059 buffer_put(vty->obuf, header, 4);
paul718e3742002-12-13 20:15:29 +00002060
ajs9fc7ebf2005-02-23 15:12:34 +00002061 if (!vty->t_write && (vtysh_flush(vty) < 0))
2062 /* Try to flush results; exit if a write error occurs. */
2063 return 0;
2064 }
2065 }
2066
paul718e3742002-12-13 20:15:29 +00002067 vty_event (VTYSH_READ, sock, vty);
2068
2069 return 0;
2070}
ajs49ff6d92004-11-04 19:26:16 +00002071
2072static int
2073vtysh_write (struct thread *thread)
2074{
2075 struct vty *vty = THREAD_ARG (thread);
2076
2077 vty->t_write = NULL;
ajs9fc7ebf2005-02-23 15:12:34 +00002078 vtysh_flush(vty);
ajs976d8c72004-11-10 15:40:09 +00002079 return 0;
ajs49ff6d92004-11-04 19:26:16 +00002080}
2081
paul718e3742002-12-13 20:15:29 +00002082#endif /* VTYSH */
2083
2084/* Determine address family to bind. */
2085void
hasso6ad96ea2004-10-07 19:33:46 +00002086vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002087{
2088 /* If port is set to 0, do not listen on TCP/IP at all! */
2089 if (port)
2090 {
2091
2092#ifdef HAVE_IPV6
2093#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002094 vty_serv_sock_family (addr, port, AF_INET);
2095 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002096#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002097 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002098#endif /* NRL*/
2099#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002100 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002101#endif /* HAVE_IPV6 */
2102 }
2103
2104#ifdef VTYSH
2105 vty_serv_un (path);
2106#endif /* VTYSH */
2107}
2108
2109/* Close vty interface. */
2110void
2111vty_close (struct vty *vty)
2112{
2113 int i;
2114
2115 /* Cancel threads.*/
2116 if (vty->t_read)
2117 thread_cancel (vty->t_read);
2118 if (vty->t_write)
2119 thread_cancel (vty->t_write);
2120 if (vty->t_timeout)
2121 thread_cancel (vty->t_timeout);
paul718e3742002-12-13 20:15:29 +00002122
2123 /* Flush buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +00002124 buffer_flush_all (vty->obuf, vty->fd);
paul718e3742002-12-13 20:15:29 +00002125
2126 /* Free input buffer. */
2127 buffer_free (vty->obuf);
2128
paul718e3742002-12-13 20:15:29 +00002129 /* Free command history. */
2130 for (i = 0; i < VTY_MAXHIST; i++)
2131 if (vty->hist[i])
2132 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2133
2134 /* Unset vector. */
2135 vector_unset (vtyvec, vty->fd);
2136
2137 /* Close socket. */
2138 if (vty->fd > 0)
2139 close (vty->fd);
2140
2141 if (vty->address)
2142 XFREE (0, vty->address);
2143 if (vty->buf)
2144 XFREE (MTYPE_VTY, vty->buf);
2145
2146 /* Check configure. */
2147 vty_config_unlock (vty);
2148
2149 /* OK free vty. */
2150 XFREE (MTYPE_VTY, vty);
2151}
2152
2153/* When time out occur output message then close connection. */
2154static int
2155vty_timeout (struct thread *thread)
2156{
2157 struct vty *vty;
2158
2159 vty = THREAD_ARG (thread);
2160 vty->t_timeout = NULL;
2161 vty->v_timeout = 0;
2162
2163 /* Clear buffer*/
2164 buffer_reset (vty->obuf);
2165 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2166
2167 /* Close connection. */
2168 vty->status = VTY_CLOSE;
2169 vty_close (vty);
2170
2171 return 0;
2172}
2173
2174/* Read up configuration file from file_name. */
2175static void
2176vty_read_file (FILE *confp)
2177{
2178 int ret;
2179 struct vty *vty;
2180
2181 vty = vty_new ();
2182 vty->fd = 0; /* stdout */
2183 vty->type = VTY_TERM;
2184 vty->node = CONFIG_NODE;
2185
2186 /* Execute configuration file */
2187 ret = config_from_file (vty, confp);
2188
paul7021c422003-07-15 12:52:22 +00002189 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002190 {
2191 switch (ret)
paul7021c422003-07-15 12:52:22 +00002192 {
2193 case CMD_ERR_AMBIGUOUS:
2194 fprintf (stderr, "Ambiguous command.\n");
2195 break;
2196 case CMD_ERR_NO_MATCH:
2197 fprintf (stderr, "There is no such command.\n");
2198 break;
2199 }
paul718e3742002-12-13 20:15:29 +00002200 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2201 vty->buf);
2202 vty_close (vty);
2203 exit (1);
2204 }
2205
2206 vty_close (vty);
2207}
2208
ajs9fc7ebf2005-02-23 15:12:34 +00002209static FILE *
paul718e3742002-12-13 20:15:29 +00002210vty_use_backup_config (char *fullpath)
2211{
2212 char *fullpath_sav, *fullpath_tmp;
2213 FILE *ret = NULL;
2214 struct stat buf;
2215 int tmp, sav;
2216 int c;
2217 char buffer[512];
2218
2219 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2220 strcpy (fullpath_sav, fullpath);
2221 strcat (fullpath_sav, CONF_BACKUP_EXT);
2222 if (stat (fullpath_sav, &buf) == -1)
2223 {
2224 free (fullpath_sav);
2225 return NULL;
2226 }
2227
2228 fullpath_tmp = malloc (strlen (fullpath) + 8);
2229 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2230
2231 /* Open file to configuration write. */
2232 tmp = mkstemp (fullpath_tmp);
2233 if (tmp < 0)
2234 {
2235 free (fullpath_sav);
2236 free (fullpath_tmp);
2237 return NULL;
2238 }
2239
2240 sav = open (fullpath_sav, O_RDONLY);
2241 if (sav < 0)
2242 {
gdt3dbf9962003-12-22 20:18:18 +00002243 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002244 free (fullpath_sav);
2245 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002246 return NULL;
2247 }
2248
2249 while((c = read (sav, buffer, 512)) > 0)
2250 write (tmp, buffer, c);
2251
2252 close (sav);
2253 close (tmp);
2254
gdtaa593d52003-12-22 20:15:53 +00002255 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2256 {
gdt3dbf9962003-12-22 20:18:18 +00002257 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002258 free (fullpath_sav);
2259 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002260 return NULL;
2261 }
2262
paul718e3742002-12-13 20:15:29 +00002263 if (link (fullpath_tmp, fullpath) == 0)
2264 ret = fopen (fullpath, "r");
2265
2266 unlink (fullpath_tmp);
2267
2268 free (fullpath_sav);
2269 free (fullpath_tmp);
hasso12f6ea22005-03-07 08:35:39 +00002270 return ret;
paul718e3742002-12-13 20:15:29 +00002271}
2272
2273/* Read up configuration file from file_name. */
2274void
2275vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002276 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002277{
paulccc92352003-10-22 02:49:38 +00002278 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002279 FILE *confp = NULL;
2280 char *fullpath;
2281
2282 /* If -f flag specified. */
2283 if (config_file != NULL)
2284 {
2285 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002286 {
2287 getcwd (cwd, MAXPATHLEN);
2288 fullpath = XMALLOC (MTYPE_TMP,
2289 strlen (cwd) + strlen (config_file) + 2);
2290 sprintf (fullpath, "%s/%s", cwd, config_file);
2291 }
paul718e3742002-12-13 20:15:29 +00002292 else
hasso320ec102004-06-20 19:54:37 +00002293 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002294
2295 confp = fopen (fullpath, "r");
2296
2297 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002298 {
2299 confp = vty_use_backup_config (fullpath);
2300 if (confp)
2301 fprintf (stderr, "WARNING: using backup configuration file!\n");
2302 else
2303 {
2304 fprintf (stderr, "can't open configuration file [%s]\n",
2305 config_file);
2306 exit(1);
2307 }
2308 }
paul718e3742002-12-13 20:15:29 +00002309 }
2310 else
2311 {
paul718e3742002-12-13 20:15:29 +00002312#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002313 int ret;
2314 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002315
hasso320ec102004-06-20 19:54:37 +00002316 /* !!!!PLEASE LEAVE!!!!
2317 * This is NEEDED for use with vtysh -b, or else you can get
2318 * a real configuration food fight with a lot garbage in the
2319 * merged configuration file it creates coming from the per
2320 * daemon configuration files. This also allows the daemons
2321 * to start if there default configuration file is not
2322 * present or ignore them, as needed when using vtysh -b to
2323 * configure the daemons at boot - MAG
2324 */
paul718e3742002-12-13 20:15:29 +00002325
hasso320ec102004-06-20 19:54:37 +00002326 /* Stat for vtysh Zebra.conf, if found startup and wait for
2327 * boot configuration
2328 */
paul718e3742002-12-13 20:15:29 +00002329
hasso320ec102004-06-20 19:54:37 +00002330 if ( strstr(config_default_dir, "vtysh") == NULL)
2331 {
2332 ret = stat (integrate_default, &conf_stat);
2333 if (ret >= 0)
2334 return;
2335 }
paul718e3742002-12-13 20:15:29 +00002336#endif /* VTYSH */
2337
hasso320ec102004-06-20 19:54:37 +00002338 confp = fopen (config_default_dir, "r");
2339 if (confp == NULL)
2340 {
2341 confp = vty_use_backup_config (config_default_dir);
2342 if (confp)
2343 {
2344 fprintf (stderr, "WARNING: using backup configuration file!\n");
2345 fullpath = config_default_dir;
2346 }
2347 else
2348 {
2349 fprintf (stderr, "can't open configuration file [%s]\n",
2350 config_default_dir);
2351 exit (1);
2352 }
2353 }
paul718e3742002-12-13 20:15:29 +00002354 else
hasso320ec102004-06-20 19:54:37 +00002355 fullpath = config_default_dir;
2356 }
2357
paul718e3742002-12-13 20:15:29 +00002358 vty_read_file (confp);
2359
2360 fclose (confp);
2361
2362 host_config_set (fullpath);
2363}
2364
2365/* Small utility function which output log to the VTY. */
2366void
ajs274a4a42004-12-07 15:39:31 +00002367vty_log (const char *level, const char *proto_str,
2368 const char *format, va_list va)
paul718e3742002-12-13 20:15:29 +00002369{
hasso8c328f12004-10-05 21:01:23 +00002370 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002371 struct vty *vty;
2372
2373 for (i = 0; i < vector_max (vtyvec); i++)
2374 if ((vty = vector_slot (vtyvec, i)) != NULL)
2375 if (vty->monitor)
ajsd246bd92004-11-23 17:35:08 +00002376 {
2377 va_list ac;
2378 va_copy(ac, va);
ajs274a4a42004-12-07 15:39:31 +00002379 vty_log_out (vty, level, proto_str, format, ac);
ajsd246bd92004-11-23 17:35:08 +00002380 va_end(ac);
2381 }
paul718e3742002-12-13 20:15:29 +00002382}
2383
ajs274a4a42004-12-07 15:39:31 +00002384/* Async-signal-safe version of vty_log for fixed strings. */
2385void
2386vty_log_fixed (const char *buf, size_t len)
2387{
2388 unsigned int i;
ajs9fc7ebf2005-02-23 15:12:34 +00002389 struct iovec iov[2];
2390
2391 iov[0].iov_base = buf;
2392 iov[0].iov_len = len;
2393 iov[1].iov_base = "\r\n";
2394 iov[1].iov_len = 2;
ajs274a4a42004-12-07 15:39:31 +00002395
2396 for (i = 0; i < vector_max (vtyvec); i++)
2397 {
2398 struct vty *vty;
ajs9fc7ebf2005-02-23 15:12:34 +00002399 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2400 /* N.B. We don't care about the return code, since process is
2401 most likely just about to die anyway. */
2402 writev(vty->fd, iov, 2);
ajs274a4a42004-12-07 15:39:31 +00002403 }
2404}
2405
paul718e3742002-12-13 20:15:29 +00002406int
2407vty_config_lock (struct vty *vty)
2408{
2409 if (vty_config == 0)
2410 {
2411 vty->config = 1;
2412 vty_config = 1;
2413 }
2414 return vty->config;
2415}
2416
2417int
2418vty_config_unlock (struct vty *vty)
2419{
2420 if (vty_config == 1 && vty->config == 1)
2421 {
2422 vty->config = 0;
2423 vty_config = 0;
2424 }
2425 return vty->config;
2426}
2427
2428/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002429static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002430
2431static void
2432vty_event (enum event event, int sock, struct vty *vty)
2433{
2434 struct thread *vty_serv_thread;
2435
2436 switch (event)
2437 {
2438 case VTY_SERV:
2439 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2440 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2441 break;
2442#ifdef VTYSH
2443 case VTYSH_SERV:
2444 thread_add_read (master, vtysh_accept, vty, sock);
2445 break;
2446 case VTYSH_READ:
ajs49ff6d92004-11-04 19:26:16 +00002447 vty->t_read = thread_add_read (master, vtysh_read, vty, sock);
2448 break;
2449 case VTYSH_WRITE:
2450 vty->t_write = thread_add_write (master, vtysh_write, vty, sock);
paul718e3742002-12-13 20:15:29 +00002451 break;
2452#endif /* VTYSH */
2453 case VTY_READ:
2454 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2455
2456 /* Time out treatment. */
2457 if (vty->v_timeout)
2458 {
2459 if (vty->t_timeout)
2460 thread_cancel (vty->t_timeout);
2461 vty->t_timeout =
2462 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2463 }
2464 break;
2465 case VTY_WRITE:
2466 if (! vty->t_write)
2467 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2468 break;
2469 case VTY_TIMEOUT_RESET:
2470 if (vty->t_timeout)
2471 {
2472 thread_cancel (vty->t_timeout);
2473 vty->t_timeout = NULL;
2474 }
2475 if (vty->v_timeout)
2476 {
2477 vty->t_timeout =
2478 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2479 }
2480 break;
2481 }
2482}
2483
2484DEFUN (config_who,
2485 config_who_cmd,
2486 "who",
2487 "Display who is on vty\n")
2488{
hasso8c328f12004-10-05 21:01:23 +00002489 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002490 struct vty *v;
2491
2492 for (i = 0; i < vector_max (vtyvec); i++)
2493 if ((v = vector_slot (vtyvec, i)) != NULL)
2494 vty_out (vty, "%svty[%d] connected from %s.%s",
2495 v->config ? "*" : " ",
2496 i, v->address, VTY_NEWLINE);
2497 return CMD_SUCCESS;
2498}
2499
2500/* Move to vty configuration mode. */
2501DEFUN (line_vty,
2502 line_vty_cmd,
2503 "line vty",
2504 "Configure a terminal line\n"
2505 "Virtual terminal\n")
2506{
2507 vty->node = VTY_NODE;
2508 return CMD_SUCCESS;
2509}
2510
2511/* Set time out value. */
ajs9fc7ebf2005-02-23 15:12:34 +00002512static int
paul9035efa2004-10-10 11:56:56 +00002513exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002514{
2515 unsigned long timeout = 0;
2516
2517 /* min_str and sec_str are already checked by parser. So it must be
2518 all digit string. */
2519 if (min_str)
2520 {
2521 timeout = strtol (min_str, NULL, 10);
2522 timeout *= 60;
2523 }
2524 if (sec_str)
2525 timeout += strtol (sec_str, NULL, 10);
2526
2527 vty_timeout_val = timeout;
2528 vty->v_timeout = timeout;
2529 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2530
2531
2532 return CMD_SUCCESS;
2533}
2534
2535DEFUN (exec_timeout_min,
2536 exec_timeout_min_cmd,
2537 "exec-timeout <0-35791>",
2538 "Set timeout value\n"
2539 "Timeout value in minutes\n")
2540{
2541 return exec_timeout (vty, argv[0], NULL);
2542}
2543
2544DEFUN (exec_timeout_sec,
2545 exec_timeout_sec_cmd,
2546 "exec-timeout <0-35791> <0-2147483>",
2547 "Set the EXEC timeout\n"
2548 "Timeout in minutes\n"
2549 "Timeout in seconds\n")
2550{
2551 return exec_timeout (vty, argv[0], argv[1]);
2552}
2553
2554DEFUN (no_exec_timeout,
2555 no_exec_timeout_cmd,
2556 "no exec-timeout",
2557 NO_STR
2558 "Set the EXEC timeout\n")
2559{
2560 return exec_timeout (vty, NULL, NULL);
2561}
2562
2563/* Set vty access class. */
2564DEFUN (vty_access_class,
2565 vty_access_class_cmd,
2566 "access-class WORD",
2567 "Filter connections based on an IP access list\n"
2568 "IP access list\n")
2569{
2570 if (vty_accesslist_name)
2571 XFREE(MTYPE_VTY, vty_accesslist_name);
2572
2573 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2574
2575 return CMD_SUCCESS;
2576}
2577
2578/* Clear vty access class. */
2579DEFUN (no_vty_access_class,
2580 no_vty_access_class_cmd,
2581 "no access-class [WORD]",
2582 NO_STR
2583 "Filter connections based on an IP access list\n"
2584 "IP access list\n")
2585{
2586 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2587 {
2588 vty_out (vty, "Access-class is not currently applied to vty%s",
2589 VTY_NEWLINE);
2590 return CMD_WARNING;
2591 }
2592
2593 XFREE(MTYPE_VTY, vty_accesslist_name);
2594
2595 vty_accesslist_name = NULL;
2596
2597 return CMD_SUCCESS;
2598}
2599
2600#ifdef HAVE_IPV6
2601/* Set vty access class. */
2602DEFUN (vty_ipv6_access_class,
2603 vty_ipv6_access_class_cmd,
2604 "ipv6 access-class WORD",
2605 IPV6_STR
2606 "Filter connections based on an IP access list\n"
2607 "IPv6 access list\n")
2608{
2609 if (vty_ipv6_accesslist_name)
2610 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2611
2612 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2613
2614 return CMD_SUCCESS;
2615}
2616
2617/* Clear vty access class. */
2618DEFUN (no_vty_ipv6_access_class,
2619 no_vty_ipv6_access_class_cmd,
2620 "no ipv6 access-class [WORD]",
2621 NO_STR
2622 IPV6_STR
2623 "Filter connections based on an IP access list\n"
2624 "IPv6 access list\n")
2625{
2626 if (! vty_ipv6_accesslist_name ||
2627 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2628 {
2629 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2630 VTY_NEWLINE);
2631 return CMD_WARNING;
2632 }
2633
2634 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2635
2636 vty_ipv6_accesslist_name = NULL;
2637
2638 return CMD_SUCCESS;
2639}
2640#endif /* HAVE_IPV6 */
2641
2642/* vty login. */
2643DEFUN (vty_login,
2644 vty_login_cmd,
2645 "login",
2646 "Enable password checking\n")
2647{
2648 no_password_check = 0;
2649 return CMD_SUCCESS;
2650}
2651
2652DEFUN (no_vty_login,
2653 no_vty_login_cmd,
2654 "no login",
2655 NO_STR
2656 "Enable password checking\n")
2657{
2658 no_password_check = 1;
2659 return CMD_SUCCESS;
2660}
2661
2662DEFUN (service_advanced_vty,
2663 service_advanced_vty_cmd,
2664 "service advanced-vty",
2665 "Set up miscellaneous service\n"
2666 "Enable advanced mode vty interface\n")
2667{
2668 host.advanced = 1;
2669 return CMD_SUCCESS;
2670}
2671
2672DEFUN (no_service_advanced_vty,
2673 no_service_advanced_vty_cmd,
2674 "no service advanced-vty",
2675 NO_STR
2676 "Set up miscellaneous service\n"
2677 "Enable advanced mode vty interface\n")
2678{
2679 host.advanced = 0;
2680 return CMD_SUCCESS;
2681}
2682
2683DEFUN (terminal_monitor,
2684 terminal_monitor_cmd,
2685 "terminal monitor",
2686 "Set terminal line parameters\n"
2687 "Copy debug output to the current terminal line\n")
2688{
2689 vty->monitor = 1;
2690 return CMD_SUCCESS;
2691}
2692
2693DEFUN (terminal_no_monitor,
2694 terminal_no_monitor_cmd,
2695 "terminal no monitor",
2696 "Set terminal line parameters\n"
2697 NO_STR
2698 "Copy debug output to the current terminal line\n")
2699{
2700 vty->monitor = 0;
2701 return CMD_SUCCESS;
2702}
2703
2704DEFUN (show_history,
2705 show_history_cmd,
2706 "show history",
2707 SHOW_STR
2708 "Display the session command history\n")
2709{
2710 int index;
2711
2712 for (index = vty->hindex + 1; index != vty->hindex;)
2713 {
2714 if (index == VTY_MAXHIST)
2715 {
2716 index = 0;
2717 continue;
2718 }
2719
2720 if (vty->hist[index] != NULL)
2721 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2722
2723 index++;
2724 }
2725
2726 return CMD_SUCCESS;
2727}
2728
2729/* Display current configuration. */
ajs9fc7ebf2005-02-23 15:12:34 +00002730static int
paul718e3742002-12-13 20:15:29 +00002731vty_config_write (struct vty *vty)
2732{
2733 vty_out (vty, "line vty%s", VTY_NEWLINE);
2734
2735 if (vty_accesslist_name)
2736 vty_out (vty, " access-class %s%s",
2737 vty_accesslist_name, VTY_NEWLINE);
2738
2739 if (vty_ipv6_accesslist_name)
2740 vty_out (vty, " ipv6 access-class %s%s",
2741 vty_ipv6_accesslist_name, VTY_NEWLINE);
2742
2743 /* exec-timeout */
2744 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2745 vty_out (vty, " exec-timeout %ld %ld%s",
2746 vty_timeout_val / 60,
2747 vty_timeout_val % 60, VTY_NEWLINE);
2748
2749 /* login */
2750 if (no_password_check)
2751 vty_out (vty, " no login%s", VTY_NEWLINE);
2752
2753 vty_out (vty, "!%s", VTY_NEWLINE);
2754
2755 return CMD_SUCCESS;
2756}
2757
2758struct cmd_node vty_node =
2759{
2760 VTY_NODE,
2761 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00002762 1,
paul718e3742002-12-13 20:15:29 +00002763};
2764
2765/* Reset all VTY status. */
2766void
2767vty_reset ()
2768{
hasso8c328f12004-10-05 21:01:23 +00002769 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002770 struct vty *vty;
2771 struct thread *vty_serv_thread;
2772
2773 for (i = 0; i < vector_max (vtyvec); i++)
2774 if ((vty = vector_slot (vtyvec, i)) != NULL)
2775 {
2776 buffer_reset (vty->obuf);
2777 vty->status = VTY_CLOSE;
2778 vty_close (vty);
2779 }
2780
2781 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2782 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2783 {
2784 thread_cancel (vty_serv_thread);
2785 vector_slot (Vvty_serv_thread, i) = NULL;
2786 close (i);
2787 }
2788
2789 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2790
2791 if (vty_accesslist_name)
2792 {
2793 XFREE(MTYPE_VTY, vty_accesslist_name);
2794 vty_accesslist_name = NULL;
2795 }
2796
2797 if (vty_ipv6_accesslist_name)
2798 {
2799 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2800 vty_ipv6_accesslist_name = NULL;
2801 }
2802}
2803
ajs9fc7ebf2005-02-23 15:12:34 +00002804static void
2805vty_save_cwd (void)
paul718e3742002-12-13 20:15:29 +00002806{
paul79ad2792003-10-15 22:09:28 +00002807 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00002808 char *c;
paul718e3742002-12-13 20:15:29 +00002809
paulccc92352003-10-22 02:49:38 +00002810 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002811
paulccc92352003-10-22 02:49:38 +00002812 if (!c)
paul79ad2792003-10-15 22:09:28 +00002813 {
2814 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00002815 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002816 }
paul718e3742002-12-13 20:15:29 +00002817
2818 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2819 strcpy (vty_cwd, cwd);
2820}
2821
2822char *
2823vty_get_cwd ()
2824{
2825 return vty_cwd;
2826}
2827
2828int
2829vty_shell (struct vty *vty)
2830{
2831 return vty->type == VTY_SHELL ? 1 : 0;
2832}
2833
2834int
2835vty_shell_serv (struct vty *vty)
2836{
2837 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2838}
2839
2840void
2841vty_init_vtysh ()
2842{
2843 vtyvec = vector_init (VECTOR_MIN_SIZE);
2844}
2845
2846/* Install vty's own commands like `who' command. */
2847void
paulb21b19c2003-06-15 01:28:29 +00002848vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00002849{
2850 /* For further configuration read, preserve current directory. */
2851 vty_save_cwd ();
2852
2853 vtyvec = vector_init (VECTOR_MIN_SIZE);
2854
paulb21b19c2003-06-15 01:28:29 +00002855 master = master_thread;
2856
paul718e3742002-12-13 20:15:29 +00002857 /* Initilize server thread vector. */
2858 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2859
2860 /* Install bgp top node. */
2861 install_node (&vty_node, vty_config_write);
2862
2863 install_element (VIEW_NODE, &config_who_cmd);
2864 install_element (VIEW_NODE, &show_history_cmd);
2865 install_element (ENABLE_NODE, &config_who_cmd);
2866 install_element (CONFIG_NODE, &line_vty_cmd);
2867 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2868 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2869 install_element (CONFIG_NODE, &show_history_cmd);
2870 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2871 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
2872 install_element (ENABLE_NODE, &show_history_cmd);
2873
2874 install_default (VTY_NODE);
2875 install_element (VTY_NODE, &exec_timeout_min_cmd);
2876 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2877 install_element (VTY_NODE, &no_exec_timeout_cmd);
2878 install_element (VTY_NODE, &vty_access_class_cmd);
2879 install_element (VTY_NODE, &no_vty_access_class_cmd);
2880 install_element (VTY_NODE, &vty_login_cmd);
2881 install_element (VTY_NODE, &no_vty_login_cmd);
2882#ifdef HAVE_IPV6
2883 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2884 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2885#endif /* HAVE_IPV6 */
2886}