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