blob: d21f38c93e75dd0288cd57f3eea12372c8376bea [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"
paul718e3742002-12-13 20:15:29 +000038
39/* Vty events */
40enum event
41{
42 VTY_SERV,
43 VTY_READ,
44 VTY_WRITE,
45 VTY_TIMEOUT_RESET,
46#ifdef VTYSH
47 VTYSH_SERV,
48 VTYSH_READ
49#endif /* VTYSH */
50};
51
52static void vty_event (enum event, int, struct vty *);
53
54/* Extern host structure from command.c */
55extern struct host host;
56
57/* Vector which store each vty structure. */
58static vector vtyvec;
59
60/* Vty timeout value. */
61static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
62
63/* Vty access-class command */
64static char *vty_accesslist_name = NULL;
65
66/* Vty access-calss for IPv6. */
67static char *vty_ipv6_accesslist_name = NULL;
68
69/* VTY server thread. */
70vector Vvty_serv_thread;
71
72/* Current directory. */
73char *vty_cwd = NULL;
74
75/* Configure lock. */
76static int vty_config;
77
78/* Login password check. */
79static int no_password_check = 0;
80
81/* Integrated configuration file path */
82char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
83
84
85/* VTY standard output function. */
86int
87vty_out (struct vty *vty, const char *format, ...)
88{
89 va_list args;
90 int len = 0;
91 int size = 1024;
92 char buf[1024];
93 char *p = NULL;
94
95 va_start (args, format);
96
97 if (vty_shell (vty))
98 vprintf (format, args);
99 else
100 {
101 /* Try to write to initial buffer. */
102 len = vsnprintf (buf, sizeof buf, format, args);
103
104 /* Initial buffer is not enough. */
105 if (len < 0 || len >= size)
106 {
107 while (1)
108 {
109 if (len > -1)
110 size = len + 1;
111 else
112 size = size * 2;
113
114 p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
115 if (! p)
116 return -1;
117
118 len = vsnprintf (p, size, format, args);
119
120 if (len > -1 && len < size)
121 break;
122 }
123 }
124
125 /* When initial buffer is enough to store all output. */
126 if (! p)
127 p = buf;
128
129 /* Pointer p must point out buffer. */
130 if (vty_shell_serv (vty))
131 write (vty->fd, (u_char *) p, len);
132 else
133 buffer_write (vty->obuf, (u_char *) p, len);
134
135 /* If p is not different with buf, it is allocated buffer. */
136 if (p != buf)
137 XFREE (MTYPE_VTY_OUT_BUF, p);
138 }
139
140 va_end (args);
141
142 return len;
143}
144
145int
146vty_log_out (struct vty *vty, const char *proto_str, const char *format,
147 va_list va)
148{
149 int len;
150 char buf[1024];
151
152 snprintf (buf, sizeof buf, "%s: ", proto_str);
153 write (vty->fd, buf, strlen (proto_str) + 2);
154
155 len = vsnprintf (buf, sizeof buf, format, va);
156 if (len < 0)
157 return -1;
158 write (vty->fd, (u_char *)buf, len);
159
160 snprintf (buf, sizeof buf, "\r\n");
161 write (vty->fd, buf, 2);
162
163 return len;
164}
165
166/* Output current time to the vty. */
167void
168vty_time_print (struct vty *vty, int cr)
169{
170 time_t clock;
171 struct tm *tm;
172#define TIME_BUF 25
173 char buf [TIME_BUF];
174 int ret;
175
176 time (&clock);
177 tm = localtime (&clock);
178
179 ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
180 if (ret == 0)
181 {
182 zlog (NULL, LOG_INFO, "strftime error");
183 return;
184 }
185 if (cr)
186 vty_out (vty, "%s\n", buf);
187 else
188 vty_out (vty, "%s ", buf);
189
190 return;
191}
192
193/* Say hello to vty interface. */
194void
195vty_hello (struct vty *vty)
196{
197 if (host.motd)
198 vty_out (vty, host.motd);
199}
200
201/* Put out prompt and wait input from user. */
202static void
203vty_prompt (struct vty *vty)
204{
205 struct utsname names;
206 const char*hostname;
207
208 if (vty->type == VTY_TERM)
209 {
210 hostname = host.name;
211 if (!hostname)
212 {
213 uname (&names);
214 hostname = names.nodename;
215 }
216 vty_out (vty, cmd_prompt (vty->node), hostname);
217 }
218}
219
220/* Send WILL TELOPT_ECHO to remote server. */
221void
222vty_will_echo (struct vty *vty)
223{
paul02ff83c2004-06-11 11:27:03 +0000224 unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
paul718e3742002-12-13 20:15:29 +0000225 vty_out (vty, "%s", cmd);
226}
227
228/* Make suppress Go-Ahead telnet option. */
229static void
230vty_will_suppress_go_ahead (struct vty *vty)
231{
paul02ff83c2004-06-11 11:27:03 +0000232 unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
paul718e3742002-12-13 20:15:29 +0000233 vty_out (vty, "%s", cmd);
234}
235
236/* Make don't use linemode over telnet. */
237static void
238vty_dont_linemode (struct vty *vty)
239{
paul02ff83c2004-06-11 11:27:03 +0000240 unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
paul718e3742002-12-13 20:15:29 +0000241 vty_out (vty, "%s", cmd);
242}
243
244/* Use window size. */
245static void
246vty_do_window_size (struct vty *vty)
247{
paul02ff83c2004-06-11 11:27:03 +0000248 unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
paul718e3742002-12-13 20:15:29 +0000249 vty_out (vty, "%s", cmd);
250}
251
252#if 0 /* Currently not used. */
253/* Make don't use lflow vty interface. */
254static void
255vty_dont_lflow_ahead (struct vty *vty)
256{
paul02ff83c2004-06-11 11:27:03 +0000257 unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
paul718e3742002-12-13 20:15:29 +0000258 vty_out (vty, "%s", cmd);
259}
260#endif /* 0 */
261
262/* Allocate new vty struct. */
263struct vty *
264vty_new ()
265{
266 struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
267
268 new->obuf = (struct buffer *) buffer_new (100);
269 new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
270 new->max = VTY_BUFSIZ;
271 new->sb_buffer = NULL;
272
273 return new;
274}
275
276/* Authentication of vty */
277static void
278vty_auth (struct vty *vty, char *buf)
279{
280 char *passwd = NULL;
281 enum node_type next_node = 0;
282 int fail;
283 char *crypt (const char *, const char *);
284
285 switch (vty->node)
286 {
287 case AUTH_NODE:
288 if (host.encrypt)
289 passwd = host.password_encrypt;
290 else
291 passwd = host.password;
292 if (host.advanced)
293 next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
294 else
295 next_node = VIEW_NODE;
296 break;
297 case AUTH_ENABLE_NODE:
298 if (host.encrypt)
299 passwd = host.enable_encrypt;
300 else
301 passwd = host.enable;
302 next_node = ENABLE_NODE;
303 break;
304 }
305
306 if (passwd)
307 {
308 if (host.encrypt)
309 fail = strcmp (crypt(buf, passwd), passwd);
310 else
311 fail = strcmp (buf, passwd);
312 }
313 else
314 fail = 1;
315
316 if (! fail)
317 {
318 vty->fail = 0;
319 vty->node = next_node; /* Success ! */
320 }
321 else
322 {
323 vty->fail++;
324 if (vty->fail >= 3)
325 {
326 if (vty->node == AUTH_NODE)
327 {
328 vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
329 vty->status = VTY_CLOSE;
330 }
331 else
332 {
333 /* AUTH_ENABLE_NODE */
334 vty->fail = 0;
335 vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
336 vty->node = VIEW_NODE;
337 }
338 }
339 }
340}
341
342/* Command execution over the vty interface. */
343int
344vty_command (struct vty *vty, char *buf)
345{
346 int ret;
347 vector vline;
348
349 /* Split readline string up into the vector */
350 vline = cmd_make_strvec (buf);
351
352 if (vline == NULL)
353 return CMD_SUCCESS;
354
355 ret = cmd_execute_command (vline, vty, NULL);
356
357 if (ret != CMD_SUCCESS)
358 switch (ret)
359 {
360 case CMD_WARNING:
361 if (vty->type == VTY_FILE)
362 vty_out (vty, "Warning...%s", VTY_NEWLINE);
363 break;
364 case CMD_ERR_AMBIGUOUS:
365 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
366 break;
367 case CMD_ERR_NO_MATCH:
368 vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
369 break;
370 case CMD_ERR_INCOMPLETE:
371 vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
372 break;
373 }
374 cmd_free_strvec (vline);
375
376 return ret;
377}
378
379char telnet_backward_char = 0x08;
380char telnet_space_char = ' ';
381
382/* Basic function to write buffer to vty. */
383static void
384vty_write (struct vty *vty, char *buf, size_t nbytes)
385{
386 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
387 return;
388
389 /* Should we do buffering here ? And make vty_flush (vty) ? */
390 buffer_write (vty->obuf, (u_char *)buf, nbytes);
391}
392
393/* Ensure length of input buffer. Is buffer is short, double it. */
394static void
395vty_ensure (struct vty *vty, int length)
396{
397 if (vty->max <= length)
398 {
399 vty->max *= 2;
400 vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
401 }
402}
403
404/* Basic function to insert character into vty. */
405static void
406vty_self_insert (struct vty *vty, char c)
407{
408 int i;
409 int length;
410
411 vty_ensure (vty, vty->length + 1);
412 length = vty->length - vty->cp;
413 memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
414 vty->buf[vty->cp] = c;
415
416 vty_write (vty, &vty->buf[vty->cp], length + 1);
417 for (i = 0; i < length; i++)
418 vty_write (vty, &telnet_backward_char, 1);
419
420 vty->cp++;
421 vty->length++;
422}
423
424/* Self insert character 'c' in overwrite mode. */
425static void
426vty_self_insert_overwrite (struct vty *vty, char c)
427{
428 vty_ensure (vty, vty->length + 1);
429 vty->buf[vty->cp++] = c;
430
431 if (vty->cp > vty->length)
432 vty->length++;
433
434 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
435 return;
436
437 vty_write (vty, &c, 1);
438}
439
440/* Insert a word into vty interface with overwrite mode. */
441static void
442vty_insert_word_overwrite (struct vty *vty, char *str)
443{
444 int len = strlen (str);
445 vty_write (vty, str, len);
446 strcpy (&vty->buf[vty->cp], str);
447 vty->cp += len;
448 vty->length = vty->cp;
449}
450
451/* Forward character. */
452static void
453vty_forward_char (struct vty *vty)
454{
455 if (vty->cp < vty->length)
456 {
457 vty_write (vty, &vty->buf[vty->cp], 1);
458 vty->cp++;
459 }
460}
461
462/* Backward character. */
463static void
464vty_backward_char (struct vty *vty)
465{
466 if (vty->cp > 0)
467 {
468 vty->cp--;
469 vty_write (vty, &telnet_backward_char, 1);
470 }
471}
472
473/* Move to the beginning of the line. */
474static void
475vty_beginning_of_line (struct vty *vty)
476{
477 while (vty->cp)
478 vty_backward_char (vty);
479}
480
481/* Move to the end of the line. */
482static void
483vty_end_of_line (struct vty *vty)
484{
485 while (vty->cp < vty->length)
486 vty_forward_char (vty);
487}
488
489static void vty_kill_line_from_beginning (struct vty *);
490static void vty_redraw_line (struct vty *);
491
492/* Print command line history. This function is called from
493 vty_next_line and vty_previous_line. */
494static void
495vty_history_print (struct vty *vty)
496{
497 int length;
498
499 vty_kill_line_from_beginning (vty);
500
501 /* Get previous line from history buffer */
502 length = strlen (vty->hist[vty->hp]);
503 memcpy (vty->buf, vty->hist[vty->hp], length);
504 vty->cp = vty->length = length;
505
506 /* Redraw current line */
507 vty_redraw_line (vty);
508}
509
510/* Show next command line history. */
511void
512vty_next_line (struct vty *vty)
513{
514 int try_index;
515
516 if (vty->hp == vty->hindex)
517 return;
518
519 /* Try is there history exist or not. */
520 try_index = vty->hp;
521 if (try_index == (VTY_MAXHIST - 1))
522 try_index = 0;
523 else
524 try_index++;
525
526 /* If there is not history return. */
527 if (vty->hist[try_index] == NULL)
528 return;
529 else
530 vty->hp = try_index;
531
532 vty_history_print (vty);
533}
534
535/* Show previous command line history. */
536void
537vty_previous_line (struct vty *vty)
538{
539 int try_index;
540
541 try_index = vty->hp;
542 if (try_index == 0)
543 try_index = VTY_MAXHIST - 1;
544 else
545 try_index--;
546
547 if (vty->hist[try_index] == NULL)
548 return;
549 else
550 vty->hp = try_index;
551
552 vty_history_print (vty);
553}
554
555/* This function redraw all of the command line character. */
556static void
557vty_redraw_line (struct vty *vty)
558{
559 vty_write (vty, vty->buf, vty->length);
560 vty->cp = vty->length;
561}
562
563/* Forward word. */
564static void
565vty_forward_word (struct vty *vty)
566{
567 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
568 vty_forward_char (vty);
569
570 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
571 vty_forward_char (vty);
572}
573
574/* Backward word without skipping training space. */
575static void
576vty_backward_pure_word (struct vty *vty)
577{
578 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
579 vty_backward_char (vty);
580}
581
582/* Backward word. */
583static void
584vty_backward_word (struct vty *vty)
585{
586 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
587 vty_backward_char (vty);
588
589 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
590 vty_backward_char (vty);
591}
592
593/* When '^D' is typed at the beginning of the line we move to the down
594 level. */
595static void
596vty_down_level (struct vty *vty)
597{
598 vty_out (vty, "%s", VTY_NEWLINE);
599 config_exit (NULL, vty, 0, NULL);
600 vty_prompt (vty);
601 vty->cp = 0;
602}
603
604/* When '^Z' is received from vty, move down to the enable mode. */
605void
606vty_end_config (struct vty *vty)
607{
608 vty_out (vty, "%s", VTY_NEWLINE);
609
610 switch (vty->node)
611 {
612 case VIEW_NODE:
613 case ENABLE_NODE:
614 /* Nothing to do. */
615 break;
616 case CONFIG_NODE:
617 case INTERFACE_NODE:
618 case ZEBRA_NODE:
619 case RIP_NODE:
620 case RIPNG_NODE:
621 case BGP_NODE:
622 case BGP_VPNV4_NODE:
623 case BGP_IPV4_NODE:
624 case BGP_IPV4M_NODE:
625 case BGP_IPV6_NODE:
626 case RMAP_NODE:
627 case OSPF_NODE:
628 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +0000629 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +0000630 case KEYCHAIN_NODE:
631 case KEYCHAIN_KEY_NODE:
632 case MASC_NODE:
633 case VTY_NODE:
634 vty_config_unlock (vty);
635 vty->node = ENABLE_NODE;
636 break;
637 default:
638 /* Unknown node, we have to ignore it. */
639 break;
640 }
641
642 vty_prompt (vty);
643 vty->cp = 0;
644}
645
646/* Delete a charcter at the current point. */
647static void
648vty_delete_char (struct vty *vty)
649{
650 int i;
651 int size;
652
653 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
654 return;
655
656 if (vty->length == 0)
657 {
658 vty_down_level (vty);
659 return;
660 }
661
662 if (vty->cp == vty->length)
663 return; /* completion need here? */
664
665 size = vty->length - vty->cp;
666
667 vty->length--;
668 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
669 vty->buf[vty->length] = '\0';
670
671 vty_write (vty, &vty->buf[vty->cp], size - 1);
672 vty_write (vty, &telnet_space_char, 1);
673
674 for (i = 0; i < size; i++)
675 vty_write (vty, &telnet_backward_char, 1);
676}
677
678/* Delete a character before the point. */
679static void
680vty_delete_backward_char (struct vty *vty)
681{
682 if (vty->cp == 0)
683 return;
684
685 vty_backward_char (vty);
686 vty_delete_char (vty);
687}
688
689/* Kill rest of line from current point. */
690static void
691vty_kill_line (struct vty *vty)
692{
693 int i;
694 int size;
695
696 size = vty->length - vty->cp;
697
698 if (size == 0)
699 return;
700
701 for (i = 0; i < size; i++)
702 vty_write (vty, &telnet_space_char, 1);
703 for (i = 0; i < size; i++)
704 vty_write (vty, &telnet_backward_char, 1);
705
706 memset (&vty->buf[vty->cp], 0, size);
707 vty->length = vty->cp;
708}
709
710/* Kill line from the beginning. */
711static void
712vty_kill_line_from_beginning (struct vty *vty)
713{
714 vty_beginning_of_line (vty);
715 vty_kill_line (vty);
716}
717
718/* Delete a word before the point. */
719static void
720vty_forward_kill_word (struct vty *vty)
721{
722 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
723 vty_delete_char (vty);
724 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
725 vty_delete_char (vty);
726}
727
728/* Delete a word before the point. */
729static void
730vty_backward_kill_word (struct vty *vty)
731{
732 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
733 vty_delete_backward_char (vty);
734 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
735 vty_delete_backward_char (vty);
736}
737
738/* Transpose chars before or at the point. */
739static void
740vty_transpose_chars (struct vty *vty)
741{
742 char c1, c2;
743
744 /* If length is short or point is near by the beginning of line then
745 return. */
746 if (vty->length < 2 || vty->cp < 1)
747 return;
748
749 /* In case of point is located at the end of the line. */
750 if (vty->cp == vty->length)
751 {
752 c1 = vty->buf[vty->cp - 1];
753 c2 = vty->buf[vty->cp - 2];
754
755 vty_backward_char (vty);
756 vty_backward_char (vty);
757 vty_self_insert_overwrite (vty, c1);
758 vty_self_insert_overwrite (vty, c2);
759 }
760 else
761 {
762 c1 = vty->buf[vty->cp];
763 c2 = vty->buf[vty->cp - 1];
764
765 vty_backward_char (vty);
766 vty_self_insert_overwrite (vty, c1);
767 vty_self_insert_overwrite (vty, c2);
768 }
769}
770
771/* Do completion at vty interface. */
772static void
773vty_complete_command (struct vty *vty)
774{
775 int i;
776 int ret;
777 char **matched = NULL;
778 vector vline;
779
780 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
781 return;
782
783 vline = cmd_make_strvec (vty->buf);
784 if (vline == NULL)
785 return;
786
787 /* In case of 'help \t'. */
788 if (isspace ((int) vty->buf[vty->length - 1]))
789 vector_set (vline, '\0');
790
791 matched = cmd_complete_command (vline, vty, &ret);
792
793 cmd_free_strvec (vline);
794
795 vty_out (vty, "%s", VTY_NEWLINE);
796 switch (ret)
797 {
798 case CMD_ERR_AMBIGUOUS:
799 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
800 vty_prompt (vty);
801 vty_redraw_line (vty);
802 break;
803 case CMD_ERR_NO_MATCH:
804 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
805 vty_prompt (vty);
806 vty_redraw_line (vty);
807 break;
808 case CMD_COMPLETE_FULL_MATCH:
809 vty_prompt (vty);
810 vty_redraw_line (vty);
811 vty_backward_pure_word (vty);
812 vty_insert_word_overwrite (vty, matched[0]);
813 vty_self_insert (vty, ' ');
814 XFREE (MTYPE_TMP, matched[0]);
815 break;
816 case CMD_COMPLETE_MATCH:
817 vty_prompt (vty);
818 vty_redraw_line (vty);
819 vty_backward_pure_word (vty);
820 vty_insert_word_overwrite (vty, matched[0]);
821 XFREE (MTYPE_TMP, matched[0]);
822 vector_only_index_free (matched);
823 return;
824 break;
825 case CMD_COMPLETE_LIST_MATCH:
826 for (i = 0; matched[i] != NULL; i++)
827 {
828 if (i != 0 && ((i % 6) == 0))
829 vty_out (vty, "%s", VTY_NEWLINE);
830 vty_out (vty, "%-10s ", matched[i]);
831 XFREE (MTYPE_TMP, matched[i]);
832 }
833 vty_out (vty, "%s", VTY_NEWLINE);
834
835 vty_prompt (vty);
836 vty_redraw_line (vty);
837 break;
838 case CMD_ERR_NOTHING_TODO:
839 vty_prompt (vty);
840 vty_redraw_line (vty);
841 break;
842 default:
843 break;
844 }
845 if (matched)
846 vector_only_index_free (matched);
847}
848
849void
850vty_describe_fold (struct vty *vty, int cmd_width,
hasso8c328f12004-10-05 21:01:23 +0000851 unsigned int desc_width, struct desc *desc)
paul718e3742002-12-13 20:15:29 +0000852{
hasso8c328f12004-10-05 21:01:23 +0000853 char *buf;
854 const char *cmd, *p;
paul718e3742002-12-13 20:15:29 +0000855 int pos;
856
857 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
858
859 if (desc_width <= 0)
860 {
861 vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
862 return;
863 }
864
865 buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
866
867 for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
868 {
869 for (pos = desc_width; pos > 0; pos--)
870 if (*(p + pos) == ' ')
871 break;
872
873 if (pos == 0)
874 break;
875
876 strncpy (buf, p, pos);
877 buf[pos] = '\0';
878 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
879
880 cmd = "";
881 }
882
883 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
884
885 XFREE (MTYPE_TMP, buf);
886}
887
888/* Describe matched command function. */
889static void
890vty_describe_command (struct vty *vty)
891{
892 int ret;
893 vector vline;
894 vector describe;
hasso8c328f12004-10-05 21:01:23 +0000895 unsigned int i, width, desc_width;
paul718e3742002-12-13 20:15:29 +0000896 struct desc *desc, *desc_cr = NULL;
897
898 vline = cmd_make_strvec (vty->buf);
899
900 /* In case of '> ?'. */
901 if (vline == NULL)
902 {
903 vline = vector_init (1);
904 vector_set (vline, '\0');
905 }
906 else
907 if (isspace ((int) vty->buf[vty->length - 1]))
908 vector_set (vline, '\0');
909
910 describe = cmd_describe_command (vline, vty, &ret);
911
912 vty_out (vty, "%s", VTY_NEWLINE);
913
914 /* Ambiguous error. */
915 switch (ret)
916 {
917 case CMD_ERR_AMBIGUOUS:
918 cmd_free_strvec (vline);
919 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
920 vty_prompt (vty);
921 vty_redraw_line (vty);
922 return;
923 break;
924 case CMD_ERR_NO_MATCH:
925 cmd_free_strvec (vline);
926 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
927 vty_prompt (vty);
928 vty_redraw_line (vty);
929 return;
930 break;
931 }
932
933 /* Get width of command string. */
934 width = 0;
935 for (i = 0; i < vector_max (describe); i++)
936 if ((desc = vector_slot (describe, i)) != NULL)
937 {
hasso8c328f12004-10-05 21:01:23 +0000938 unsigned int len;
paul718e3742002-12-13 20:15:29 +0000939
940 if (desc->cmd[0] == '\0')
941 continue;
942
943 len = strlen (desc->cmd);
944 if (desc->cmd[0] == '.')
945 len--;
946
947 if (width < len)
948 width = len;
949 }
950
951 /* Get width of description string. */
952 desc_width = vty->width - (width + 6);
953
954 /* Print out description. */
955 for (i = 0; i < vector_max (describe); i++)
956 if ((desc = vector_slot (describe, i)) != NULL)
957 {
958 if (desc->cmd[0] == '\0')
959 continue;
960
961 if (strcmp (desc->cmd, "<cr>") == 0)
962 {
963 desc_cr = desc;
964 continue;
965 }
966
967 if (!desc->str)
968 vty_out (vty, " %-s%s",
969 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
970 VTY_NEWLINE);
971 else if (desc_width >= strlen (desc->str))
972 vty_out (vty, " %-*s %s%s", width,
973 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
974 desc->str, VTY_NEWLINE);
975 else
976 vty_describe_fold (vty, width, desc_width, desc);
977
978#if 0
979 vty_out (vty, " %-*s %s%s", width
980 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
981 desc->str ? desc->str : "", VTY_NEWLINE);
982#endif /* 0 */
983 }
984
985 if ((desc = desc_cr))
986 {
987 if (!desc->str)
988 vty_out (vty, " %-s%s",
989 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
990 VTY_NEWLINE);
991 else if (desc_width >= strlen (desc->str))
992 vty_out (vty, " %-*s %s%s", width,
993 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
994 desc->str, VTY_NEWLINE);
995 else
996 vty_describe_fold (vty, width, desc_width, desc);
997 }
998
999 cmd_free_strvec (vline);
1000 vector_free (describe);
1001
1002 vty_prompt (vty);
1003 vty_redraw_line (vty);
1004}
1005
1006void
1007vty_clear_buf (struct vty *vty)
1008{
1009 memset (vty->buf, 0, vty->max);
1010}
1011
1012/* ^C stop current input and do not add command line to the history. */
1013static void
1014vty_stop_input (struct vty *vty)
1015{
1016 vty->cp = vty->length = 0;
1017 vty_clear_buf (vty);
1018 vty_out (vty, "%s", VTY_NEWLINE);
1019
1020 switch (vty->node)
1021 {
1022 case VIEW_NODE:
1023 case ENABLE_NODE:
1024 /* Nothing to do. */
1025 break;
1026 case CONFIG_NODE:
1027 case INTERFACE_NODE:
1028 case ZEBRA_NODE:
1029 case RIP_NODE:
1030 case RIPNG_NODE:
1031 case BGP_NODE:
1032 case RMAP_NODE:
1033 case OSPF_NODE:
1034 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00001035 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00001036 case KEYCHAIN_NODE:
1037 case KEYCHAIN_KEY_NODE:
1038 case MASC_NODE:
1039 case VTY_NODE:
1040 vty_config_unlock (vty);
1041 vty->node = ENABLE_NODE;
1042 break;
1043 default:
1044 /* Unknown node, we have to ignore it. */
1045 break;
1046 }
1047 vty_prompt (vty);
1048
1049 /* Set history pointer to the latest one. */
1050 vty->hp = vty->hindex;
1051}
1052
1053/* Add current command line to the history buffer. */
1054static void
1055vty_hist_add (struct vty *vty)
1056{
1057 int index;
1058
1059 if (vty->length == 0)
1060 return;
1061
1062 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1063
1064 /* Ignore the same string as previous one. */
1065 if (vty->hist[index])
1066 if (strcmp (vty->buf, vty->hist[index]) == 0)
1067 {
1068 vty->hp = vty->hindex;
1069 return;
1070 }
1071
1072 /* Insert history entry. */
1073 if (vty->hist[vty->hindex])
1074 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1075 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1076
1077 /* History index rotation. */
1078 vty->hindex++;
1079 if (vty->hindex == VTY_MAXHIST)
1080 vty->hindex = 0;
1081
1082 vty->hp = vty->hindex;
1083}
1084
1085/* #define TELNET_OPTION_DEBUG */
1086
1087/* Get telnet window size. */
1088static int
1089vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1090{
1091#ifdef TELNET_OPTION_DEBUG
1092 int i;
1093
1094 for (i = 0; i < nbytes; i++)
1095 {
1096 switch (buf[i])
1097 {
1098 case IAC:
1099 vty_out (vty, "IAC ");
1100 break;
1101 case WILL:
1102 vty_out (vty, "WILL ");
1103 break;
1104 case WONT:
1105 vty_out (vty, "WONT ");
1106 break;
1107 case DO:
1108 vty_out (vty, "DO ");
1109 break;
1110 case DONT:
1111 vty_out (vty, "DONT ");
1112 break;
1113 case SB:
1114 vty_out (vty, "SB ");
1115 break;
1116 case SE:
1117 vty_out (vty, "SE ");
1118 break;
1119 case TELOPT_ECHO:
1120 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1121 break;
1122 case TELOPT_SGA:
1123 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1124 break;
1125 case TELOPT_NAWS:
1126 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1127 break;
1128 default:
1129 vty_out (vty, "%x ", buf[i]);
1130 break;
1131 }
1132 }
1133 vty_out (vty, "%s", VTY_NEWLINE);
1134
1135#endif /* TELNET_OPTION_DEBUG */
1136
1137 switch (buf[0])
1138 {
1139 case SB:
1140 buffer_reset(vty->sb_buffer);
1141 vty->iac_sb_in_progress = 1;
1142 return 0;
1143 break;
1144 case SE:
1145 {
paul5b8c1b02003-10-15 23:08:55 +00001146 char *buffer;
1147 int length;
paul718e3742002-12-13 20:15:29 +00001148
1149 if (!vty->iac_sb_in_progress)
1150 return 0;
1151
paul5b8c1b02003-10-15 23:08:55 +00001152 buffer = (char *)vty->sb_buffer->head->data;
1153 length = vty->sb_buffer->length;
1154
1155 if (buffer == NULL)
1156 return 0;
1157
paul718e3742002-12-13 20:15:29 +00001158 if (buffer[0] == '\0')
1159 {
1160 vty->iac_sb_in_progress = 0;
1161 return 0;
1162 }
1163 switch (buffer[0])
1164 {
1165 case TELOPT_NAWS:
1166 if (length < 5)
1167 break;
1168 vty->width = buffer[2];
1169 vty->height = vty->lines >= 0 ? vty->lines : buffer[4];
1170 break;
1171 }
1172 vty->iac_sb_in_progress = 0;
1173 return 0;
1174 break;
1175 }
1176 default:
1177 break;
1178 }
1179 return 1;
1180}
1181
1182/* Execute current command line. */
1183static int
1184vty_execute (struct vty *vty)
1185{
1186 int ret;
1187
1188 ret = CMD_SUCCESS;
1189
1190 switch (vty->node)
1191 {
1192 case AUTH_NODE:
1193 case AUTH_ENABLE_NODE:
1194 vty_auth (vty, vty->buf);
1195 break;
1196 default:
1197 ret = vty_command (vty, vty->buf);
1198 if (vty->type == VTY_TERM)
1199 vty_hist_add (vty);
1200 break;
1201 }
1202
1203 /* Clear command line buffer. */
1204 vty->cp = vty->length = 0;
1205 vty_clear_buf (vty);
1206
1207 if (vty->status != VTY_CLOSE
1208 && vty->status != VTY_START
1209 && vty->status != VTY_CONTINUE)
1210 vty_prompt (vty);
1211
1212 return ret;
1213}
1214
1215#define CONTROL(X) ((X) - '@')
1216#define VTY_NORMAL 0
1217#define VTY_PRE_ESCAPE 1
1218#define VTY_ESCAPE 2
1219
1220/* Escape character command map. */
1221static void
1222vty_escape_map (unsigned char c, struct vty *vty)
1223{
1224 switch (c)
1225 {
1226 case ('A'):
1227 vty_previous_line (vty);
1228 break;
1229 case ('B'):
1230 vty_next_line (vty);
1231 break;
1232 case ('C'):
1233 vty_forward_char (vty);
1234 break;
1235 case ('D'):
1236 vty_backward_char (vty);
1237 break;
1238 default:
1239 break;
1240 }
1241
1242 /* Go back to normal mode. */
1243 vty->escape = VTY_NORMAL;
1244}
1245
1246/* Quit print out to the buffer. */
1247static void
1248vty_buffer_reset (struct vty *vty)
1249{
1250 buffer_reset (vty->obuf);
1251 vty_prompt (vty);
1252 vty_redraw_line (vty);
1253}
1254
1255/* Read data via vty socket. */
1256static int
1257vty_read (struct thread *thread)
1258{
1259 int i;
paul718e3742002-12-13 20:15:29 +00001260 int nbytes;
1261 unsigned char buf[VTY_READ_BUFSIZ];
1262
1263 int vty_sock = THREAD_FD (thread);
1264 struct vty *vty = THREAD_ARG (thread);
1265 vty->t_read = NULL;
1266
1267 /* Read raw data from socket */
1268 nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ);
1269 if (nbytes <= 0)
1270 vty->status = VTY_CLOSE;
1271
1272 for (i = 0; i < nbytes; i++)
1273 {
1274 if (buf[i] == IAC)
1275 {
1276 if (!vty->iac)
1277 {
1278 vty->iac = 1;
1279 continue;
1280 }
1281 else
1282 {
1283 vty->iac = 0;
1284 }
1285 }
1286
1287 if (vty->iac_sb_in_progress && !vty->iac)
1288 {
1289 buffer_putc(vty->sb_buffer, buf[i]);
1290 continue;
1291 }
1292
1293 if (vty->iac)
1294 {
1295 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001296 int ret = 0;
paule9372532003-10-26 21:36:07 +00001297 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001298 vty->iac = 0;
1299 i += ret;
1300 continue;
1301 }
paul5b8c1b02003-10-15 23:08:55 +00001302
paul718e3742002-12-13 20:15:29 +00001303
1304 if (vty->status == VTY_MORE)
1305 {
1306 switch (buf[i])
1307 {
1308 case CONTROL('C'):
1309 case 'q':
1310 case 'Q':
1311 if (vty->output_func)
1312 (*vty->output_func) (vty, 1);
1313 vty_buffer_reset (vty);
1314 break;
1315#if 0 /* More line does not work for "show ip bgp". */
1316 case '\n':
1317 case '\r':
1318 vty->status = VTY_MORELINE;
1319 break;
1320#endif
1321 default:
1322 if (vty->output_func)
1323 (*vty->output_func) (vty, 0);
1324 break;
1325 }
1326 continue;
1327 }
1328
1329 /* Escape character. */
1330 if (vty->escape == VTY_ESCAPE)
1331 {
1332 vty_escape_map (buf[i], vty);
1333 continue;
1334 }
1335
1336 /* Pre-escape status. */
1337 if (vty->escape == VTY_PRE_ESCAPE)
1338 {
1339 switch (buf[i])
1340 {
1341 case '[':
1342 vty->escape = VTY_ESCAPE;
1343 break;
1344 case 'b':
1345 vty_backward_word (vty);
1346 vty->escape = VTY_NORMAL;
1347 break;
1348 case 'f':
1349 vty_forward_word (vty);
1350 vty->escape = VTY_NORMAL;
1351 break;
1352 case 'd':
1353 vty_forward_kill_word (vty);
1354 vty->escape = VTY_NORMAL;
1355 break;
1356 case CONTROL('H'):
1357 case 0x7f:
1358 vty_backward_kill_word (vty);
1359 vty->escape = VTY_NORMAL;
1360 break;
1361 default:
1362 vty->escape = VTY_NORMAL;
1363 break;
1364 }
1365 continue;
1366 }
1367
1368 switch (buf[i])
1369 {
1370 case CONTROL('A'):
1371 vty_beginning_of_line (vty);
1372 break;
1373 case CONTROL('B'):
1374 vty_backward_char (vty);
1375 break;
1376 case CONTROL('C'):
1377 vty_stop_input (vty);
1378 break;
1379 case CONTROL('D'):
1380 vty_delete_char (vty);
1381 break;
1382 case CONTROL('E'):
1383 vty_end_of_line (vty);
1384 break;
1385 case CONTROL('F'):
1386 vty_forward_char (vty);
1387 break;
1388 case CONTROL('H'):
1389 case 0x7f:
1390 vty_delete_backward_char (vty);
1391 break;
1392 case CONTROL('K'):
1393 vty_kill_line (vty);
1394 break;
1395 case CONTROL('N'):
1396 vty_next_line (vty);
1397 break;
1398 case CONTROL('P'):
1399 vty_previous_line (vty);
1400 break;
1401 case CONTROL('T'):
1402 vty_transpose_chars (vty);
1403 break;
1404 case CONTROL('U'):
1405 vty_kill_line_from_beginning (vty);
1406 break;
1407 case CONTROL('W'):
1408 vty_backward_kill_word (vty);
1409 break;
1410 case CONTROL('Z'):
1411 vty_end_config (vty);
1412 break;
1413 case '\n':
1414 case '\r':
1415 vty_out (vty, "%s", VTY_NEWLINE);
1416 vty_execute (vty);
1417 break;
1418 case '\t':
1419 vty_complete_command (vty);
1420 break;
1421 case '?':
1422 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1423 vty_self_insert (vty, buf[i]);
1424 else
1425 vty_describe_command (vty);
1426 break;
1427 case '\033':
1428 if (i + 1 < nbytes && buf[i + 1] == '[')
1429 {
1430 vty->escape = VTY_ESCAPE;
1431 i++;
1432 }
1433 else
1434 vty->escape = VTY_PRE_ESCAPE;
1435 break;
1436 default:
1437 if (buf[i] > 31 && buf[i] < 127)
1438 vty_self_insert (vty, buf[i]);
1439 break;
1440 }
1441 }
1442
1443 /* Check status. */
1444 if (vty->status == VTY_CLOSE)
1445 vty_close (vty);
1446 else
1447 {
1448 vty_event (VTY_WRITE, vty_sock, vty);
1449 vty_event (VTY_READ, vty_sock, vty);
1450 }
1451 return 0;
1452}
1453
1454/* Flush buffer to the vty. */
1455static int
1456vty_flush (struct thread *thread)
1457{
1458 int erase;
1459 int dont_more;
1460 int vty_sock = THREAD_FD (thread);
1461 struct vty *vty = THREAD_ARG (thread);
1462 vty->t_write = NULL;
1463
1464 /* Tempolary disable read thread. */
1465 if (vty->lines == 0)
1466 if (vty->t_read)
1467 {
1468 thread_cancel (vty->t_read);
1469 vty->t_read = NULL;
1470 }
1471
1472 /* Function execution continue. */
1473 if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
1474 {
1475 if (vty->status == VTY_CONTINUE)
1476 erase = 1;
1477 else
1478 erase = 0;
1479
1480 if (vty->output_func == NULL)
1481 dont_more = 1;
1482 else
1483 dont_more = 0;
1484
1485 if (vty->lines == 0)
1486 {
1487 erase = 0;
1488 dont_more = 1;
1489 }
1490
1491 buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
1492
1493 if (vty->status == VTY_CLOSE)
1494 {
1495 vty_close (vty);
1496 return 0;
1497 }
1498
1499 if (vty->output_func == NULL)
1500 {
1501 vty->status = VTY_NORMAL;
1502 vty_prompt (vty);
1503 vty_event (VTY_WRITE, vty_sock, vty);
1504 }
1505 else
1506 vty->status = VTY_MORE;
1507
1508 if (vty->lines == 0)
1509 {
1510 if (vty->output_func == NULL)
1511 vty_event (VTY_READ, vty_sock, vty);
1512 else
1513 {
1514 if (vty->output_func)
1515 (*vty->output_func) (vty, 0);
1516 vty_event (VTY_WRITE, vty_sock, vty);
1517 }
1518 }
1519 }
1520 else
1521 {
1522 if (vty->status == VTY_MORE || vty->status == VTY_MORELINE)
1523 erase = 1;
1524 else
1525 erase = 0;
1526
1527 if (vty->lines == 0)
1528 buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
1529 else if (vty->status == VTY_MORELINE)
1530 buffer_flush_window (vty->obuf, vty->fd, vty->width, 1, erase, 0);
1531 else
1532 buffer_flush_window (vty->obuf, vty->fd, vty->width,
1533 vty->lines >= 0 ? vty->lines : vty->height,
1534 erase, 0);
1535
1536 if (buffer_empty (vty->obuf))
1537 {
1538 if (vty->status == VTY_CLOSE)
1539 vty_close (vty);
1540 else
1541 {
1542 vty->status = VTY_NORMAL;
1543
1544 if (vty->lines == 0)
1545 vty_event (VTY_READ, vty_sock, vty);
1546 }
1547 }
1548 else
1549 {
1550 vty->status = VTY_MORE;
1551
1552 if (vty->lines == 0)
1553 vty_event (VTY_WRITE, vty_sock, vty);
1554 }
1555 }
1556
1557 return 0;
1558}
1559
1560/* Create new vty structure. */
1561struct vty *
1562vty_create (int vty_sock, union sockunion *su)
1563{
1564 struct vty *vty;
1565
1566 /* Allocate new vty structure and set up default values. */
1567 vty = vty_new ();
1568 vty->fd = vty_sock;
1569 vty->type = VTY_TERM;
1570 vty->address = sockunion_su2str (su);
1571 if (no_password_check)
1572 {
1573 if (host.advanced)
1574 vty->node = ENABLE_NODE;
1575 else
1576 vty->node = VIEW_NODE;
1577 }
1578 else
1579 vty->node = AUTH_NODE;
1580 vty->fail = 0;
1581 vty->cp = 0;
1582 vty_clear_buf (vty);
1583 vty->length = 0;
1584 memset (vty->hist, 0, sizeof (vty->hist));
1585 vty->hp = 0;
1586 vty->hindex = 0;
1587 vector_set_index (vtyvec, vty_sock, vty);
1588 vty->status = VTY_NORMAL;
1589 vty->v_timeout = vty_timeout_val;
1590 if (host.lines >= 0)
1591 vty->lines = host.lines;
1592 else
1593 vty->lines = -1;
1594 vty->iac = 0;
1595 vty->iac_sb_in_progress = 0;
1596 vty->sb_buffer = buffer_new (1024);
1597
1598 if (! no_password_check)
1599 {
1600 /* Vty is not available if password isn't set. */
1601 if (host.password == NULL && host.password_encrypt == NULL)
1602 {
1603 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1604 vty->status = VTY_CLOSE;
1605 vty_close (vty);
1606 return NULL;
1607 }
1608 }
1609
1610 /* Say hello to the world. */
1611 vty_hello (vty);
1612 if (! no_password_check)
1613 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1614
1615 /* Setting up terminal. */
1616 vty_will_echo (vty);
1617 vty_will_suppress_go_ahead (vty);
1618
1619 vty_dont_linemode (vty);
1620 vty_do_window_size (vty);
1621 /* vty_dont_lflow_ahead (vty); */
1622
1623 vty_prompt (vty);
1624
1625 /* Add read/write thread. */
1626 vty_event (VTY_WRITE, vty_sock, vty);
1627 vty_event (VTY_READ, vty_sock, vty);
1628
1629 return vty;
1630}
1631
1632/* Accept connection from the network. */
1633static int
1634vty_accept (struct thread *thread)
1635{
1636 int vty_sock;
1637 struct vty *vty;
1638 union sockunion su;
1639 int ret;
1640 unsigned int on;
1641 int accept_sock;
1642 struct prefix *p = NULL;
1643 struct access_list *acl = NULL;
1644
1645 accept_sock = THREAD_FD (thread);
1646
1647 /* We continue hearing vty socket. */
1648 vty_event (VTY_SERV, accept_sock, NULL);
1649
1650 memset (&su, 0, sizeof (union sockunion));
1651
1652 /* We can handle IPv4 or IPv6 socket. */
1653 vty_sock = sockunion_accept (accept_sock, &su);
1654 if (vty_sock < 0)
1655 {
1656 zlog_warn ("can't accept vty socket : %s", strerror (errno));
1657 return -1;
1658 }
1659
1660 p = sockunion2hostprefix (&su);
1661
1662 /* VTY's accesslist apply. */
1663 if (p->family == AF_INET && vty_accesslist_name)
1664 {
1665 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1666 (access_list_apply (acl, p) == FILTER_DENY))
1667 {
1668 char *buf;
1669 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1670 (buf = sockunion_su2str (&su)));
1671 free (buf);
1672 close (vty_sock);
1673
1674 /* continue accepting connections */
1675 vty_event (VTY_SERV, accept_sock, NULL);
1676
1677 prefix_free (p);
1678
1679 return 0;
1680 }
1681 }
1682
1683#ifdef HAVE_IPV6
1684 /* VTY's ipv6 accesslist apply. */
1685 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1686 {
1687 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1688 (access_list_apply (acl, p) == FILTER_DENY))
1689 {
1690 char *buf;
1691 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1692 (buf = sockunion_su2str (&su)));
1693 free (buf);
1694 close (vty_sock);
1695
1696 /* continue accepting connections */
1697 vty_event (VTY_SERV, accept_sock, NULL);
1698
1699 prefix_free (p);
1700
1701 return 0;
1702 }
1703 }
1704#endif /* HAVE_IPV6 */
1705
1706 prefix_free (p);
1707
1708 on = 1;
1709 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1710 (char *) &on, sizeof (on));
1711 if (ret < 0)
1712 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
1713 strerror (errno));
1714
1715 vty = vty_create (vty_sock, &su);
1716
1717 return 0;
1718}
1719
1720#if defined(HAVE_IPV6) && !defined(NRL)
1721void
1722vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1723{
1724 int ret;
1725 struct addrinfo req;
1726 struct addrinfo *ainfo;
1727 struct addrinfo *ainfo_save;
1728 int sock;
1729 char port_str[BUFSIZ];
1730
1731 memset (&req, 0, sizeof (struct addrinfo));
1732 req.ai_flags = AI_PASSIVE;
1733 req.ai_family = AF_UNSPEC;
1734 req.ai_socktype = SOCK_STREAM;
1735 sprintf (port_str, "%d", port);
1736 port_str[sizeof (port_str) - 1] = '\0';
1737
1738 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1739
1740 if (ret != 0)
1741 {
1742 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1743 exit (1);
1744 }
1745
1746 ainfo_save = ainfo;
1747
1748 do
1749 {
1750 if (ainfo->ai_family != AF_INET
1751#ifdef HAVE_IPV6
1752 && ainfo->ai_family != AF_INET6
1753#endif /* HAVE_IPV6 */
1754 )
1755 continue;
1756
1757 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1758 if (sock < 0)
1759 continue;
1760
1761 sockopt_reuseaddr (sock);
1762 sockopt_reuseport (sock);
1763
1764 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1765 if (ret < 0)
1766 {
1767 close (sock); /* Avoid sd leak. */
1768 continue;
1769 }
1770
1771 ret = listen (sock, 3);
1772 if (ret < 0)
1773 {
1774 close (sock); /* Avoid sd leak. */
1775 continue;
1776 }
1777
1778 vty_event (VTY_SERV, sock, NULL);
1779 }
1780 while ((ainfo = ainfo->ai_next) != NULL);
1781
1782 freeaddrinfo (ainfo_save);
1783}
1784#endif /* HAVE_IPV6 && ! NRL */
1785
1786/* Make vty server socket. */
1787void
paul29db05b2003-05-08 20:10:22 +00001788vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001789{
1790 int ret;
1791 union sockunion su;
1792 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001793 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001794
1795 memset (&su, 0, sizeof (union sockunion));
1796 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001797 if(addr)
1798 switch(family)
1799 {
1800 case AF_INET:
1801 naddr=&su.sin.sin_addr;
1802#ifdef HAVE_IPV6
1803 case AF_INET6:
1804 naddr=&su.sin6.sin6_addr;
1805#endif
1806 }
1807
1808 if(naddr)
1809 switch(inet_pton(family,addr,naddr))
1810 {
1811 case -1:
1812 zlog_err("bad address %s",addr);
1813 naddr=NULL;
1814 break;
1815 case 0:
1816 zlog_err("error translating address %s: %s",addr,strerror(errno));
1817 naddr=NULL;
1818 }
paul718e3742002-12-13 20:15:29 +00001819
1820 /* Make new socket. */
1821 accept_sock = sockunion_stream_socket (&su);
1822 if (accept_sock < 0)
1823 return;
1824
1825 /* This is server, so reuse address. */
1826 sockopt_reuseaddr (accept_sock);
1827 sockopt_reuseport (accept_sock);
1828
1829 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001830 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001831 if (ret < 0)
1832 {
paul29db05b2003-05-08 20:10:22 +00001833 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001834 close (accept_sock); /* Avoid sd leak. */
1835 return;
1836 }
1837
1838 /* Listen socket under queue 3. */
1839 ret = listen (accept_sock, 3);
1840 if (ret < 0)
1841 {
1842 zlog (NULL, LOG_WARNING, "can't listen socket");
1843 close (accept_sock); /* Avoid sd leak. */
1844 return;
1845 }
1846
1847 /* Add vty server event. */
1848 vty_event (VTY_SERV, accept_sock, NULL);
1849}
1850
1851#ifdef VTYSH
1852/* For sockaddr_un. */
1853#include <sys/un.h>
1854
1855/* VTY shell UNIX domain socket. */
1856void
hasso6ad96ea2004-10-07 19:33:46 +00001857vty_serv_un (const char *path)
paul718e3742002-12-13 20:15:29 +00001858{
1859 int ret;
paulc0618de2004-08-18 21:52:58 +00001860 int sock, len, flags;
paul718e3742002-12-13 20:15:29 +00001861 struct sockaddr_un serv;
1862 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00001863 struct zprivs_ids_t ids;
1864
paul718e3742002-12-13 20:15:29 +00001865 /* First of all, unlink existing socket */
1866 unlink (path);
1867
1868 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00001869 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00001870
1871 /* Make UNIX domain socket. */
1872 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1873 if (sock < 0)
1874 {
1875 perror ("sock");
1876 return;
1877 }
1878
1879 /* Make server socket. */
1880 memset (&serv, 0, sizeof (struct sockaddr_un));
1881 serv.sun_family = AF_UNIX;
1882 strncpy (serv.sun_path, path, strlen (path));
1883#ifdef HAVE_SUN_LEN
1884 len = serv.sun_len = SUN_LEN(&serv);
1885#else
1886 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1887#endif /* HAVE_SUN_LEN */
1888
1889 ret = bind (sock, (struct sockaddr *) &serv, len);
1890 if (ret < 0)
1891 {
1892 perror ("bind");
1893 close (sock); /* Avoid sd leak. */
1894 return;
1895 }
1896
1897 ret = listen (sock, 5);
1898 if (ret < 0)
1899 {
1900 perror ("listen");
1901 close (sock); /* Avoid sd leak. */
1902 return;
1903 }
1904
paulc0618de2004-08-18 21:52:58 +00001905 /* set to non-blocking*/
1906 if ( ((flags = fcntl (sock, F_GETFL)) == -1)
1907 || (fcntl (sock, F_SETFL, flags|O_NONBLOCK) == -1) )
1908 zlog_warn ("vty_serv_un: could not set vty socket to non-blocking,"
1909 " %s", strerror (errno));
1910
paul718e3742002-12-13 20:15:29 +00001911 umask (old_mask);
1912
pauledd7c242003-06-04 13:59:38 +00001913 zprivs_get_ids(&ids);
1914
1915 if (ids.gid_vty > 0)
1916 {
1917 /* set group of socket */
1918 if ( chown (path, -1, ids.gid_vty) )
1919 {
1920 zlog_err ("vty_serv_un: could chown socket, %s",
1921 strerror (errno) );
1922 }
1923 }
1924
paul718e3742002-12-13 20:15:29 +00001925 vty_event (VTYSH_SERV, sock, NULL);
1926}
1927
1928/* #define VTYSH_DEBUG 1 */
1929
1930static int
1931vtysh_accept (struct thread *thread)
1932{
1933 int accept_sock;
1934 int sock;
1935 int client_len;
1936 struct sockaddr_un client;
1937 struct vty *vty;
1938
1939 accept_sock = THREAD_FD (thread);
1940
1941 vty_event (VTYSH_SERV, accept_sock, NULL);
1942
1943 memset (&client, 0, sizeof (struct sockaddr_un));
1944 client_len = sizeof (struct sockaddr_un);
1945
hassoe473b032004-09-26 16:08:11 +00001946 sock = accept (accept_sock, (struct sockaddr *) &client,
1947 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00001948
1949 if (sock < 0)
1950 {
1951 zlog_warn ("can't accept vty socket : %s", strerror (errno));
1952 return -1;
1953 }
1954
1955#ifdef VTYSH_DEBUG
1956 printf ("VTY shell accept\n");
1957#endif /* VTYSH_DEBUG */
1958
1959 vty = vty_new ();
1960 vty->fd = sock;
1961 vty->type = VTY_SHELL_SERV;
1962 vty->node = VIEW_NODE;
1963
1964 vty_event (VTYSH_READ, sock, vty);
1965
1966 return 0;
1967}
1968
1969static int
1970vtysh_read (struct thread *thread)
1971{
1972 int ret;
1973 int sock;
1974 int nbytes;
1975 struct vty *vty;
1976 unsigned char buf[VTY_READ_BUFSIZ];
1977 u_char header[4] = {0, 0, 0, 0};
1978
1979 sock = THREAD_FD (thread);
1980 vty = THREAD_ARG (thread);
1981 vty->t_read = NULL;
1982
1983 nbytes = read (sock, buf, VTY_READ_BUFSIZ);
1984 if (nbytes <= 0)
1985 {
1986 vty_close (vty);
1987#ifdef VTYSH_DEBUG
1988 printf ("close vtysh\n");
1989#endif /* VTYSH_DEBUG */
1990 return 0;
1991 }
1992
1993#ifdef VTYSH_DEBUG
1994 printf ("line: %s\n", buf);
1995#endif /* VTYSH_DEBUG */
1996
1997 vty_ensure (vty, nbytes);
1998 memcpy (vty->buf, buf, nbytes);
1999
2000 /* Pass this line to parser. */
2001 ret = vty_execute (vty);
2002
2003 vty_clear_buf (vty);
2004
2005 /* Return result. */
2006#ifdef VTYSH_DEBUG
2007 printf ("result: %d\n", ret);
2008 printf ("vtysh node: %d\n", vty->node);
2009#endif /* VTYSH_DEBUG */
2010
2011 header[3] = ret;
2012 write (vty->fd, header, 4);
2013
2014 vty_event (VTYSH_READ, sock, vty);
2015
2016 return 0;
2017}
2018#endif /* VTYSH */
2019
2020/* Determine address family to bind. */
2021void
hasso6ad96ea2004-10-07 19:33:46 +00002022vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002023{
2024 /* If port is set to 0, do not listen on TCP/IP at all! */
2025 if (port)
2026 {
2027
2028#ifdef HAVE_IPV6
2029#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002030 vty_serv_sock_family (addr, port, AF_INET);
2031 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002032#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002033 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002034#endif /* NRL*/
2035#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002036 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002037#endif /* HAVE_IPV6 */
2038 }
2039
2040#ifdef VTYSH
2041 vty_serv_un (path);
2042#endif /* VTYSH */
2043}
2044
2045/* Close vty interface. */
2046void
2047vty_close (struct vty *vty)
2048{
2049 int i;
2050
2051 /* Cancel threads.*/
2052 if (vty->t_read)
2053 thread_cancel (vty->t_read);
2054 if (vty->t_write)
2055 thread_cancel (vty->t_write);
2056 if (vty->t_timeout)
2057 thread_cancel (vty->t_timeout);
2058 if (vty->t_output)
2059 thread_cancel (vty->t_output);
2060
2061 /* Flush buffer. */
2062 if (! buffer_empty (vty->obuf))
2063 buffer_flush_all (vty->obuf, vty->fd);
2064
2065 /* Free input buffer. */
2066 buffer_free (vty->obuf);
2067
2068 /* Free SB buffer. */
2069 if (vty->sb_buffer)
2070 buffer_free (vty->sb_buffer);
2071
2072 /* Free command history. */
2073 for (i = 0; i < VTY_MAXHIST; i++)
2074 if (vty->hist[i])
2075 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2076
2077 /* Unset vector. */
2078 vector_unset (vtyvec, vty->fd);
2079
2080 /* Close socket. */
2081 if (vty->fd > 0)
2082 close (vty->fd);
2083
2084 if (vty->address)
2085 XFREE (0, vty->address);
2086 if (vty->buf)
2087 XFREE (MTYPE_VTY, vty->buf);
2088
2089 /* Check configure. */
2090 vty_config_unlock (vty);
2091
2092 /* OK free vty. */
2093 XFREE (MTYPE_VTY, vty);
2094}
2095
2096/* When time out occur output message then close connection. */
2097static int
2098vty_timeout (struct thread *thread)
2099{
2100 struct vty *vty;
2101
2102 vty = THREAD_ARG (thread);
2103 vty->t_timeout = NULL;
2104 vty->v_timeout = 0;
2105
2106 /* Clear buffer*/
2107 buffer_reset (vty->obuf);
2108 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2109
2110 /* Close connection. */
2111 vty->status = VTY_CLOSE;
2112 vty_close (vty);
2113
2114 return 0;
2115}
2116
2117/* Read up configuration file from file_name. */
2118static void
2119vty_read_file (FILE *confp)
2120{
2121 int ret;
2122 struct vty *vty;
2123
2124 vty = vty_new ();
2125 vty->fd = 0; /* stdout */
2126 vty->type = VTY_TERM;
2127 vty->node = CONFIG_NODE;
2128
2129 /* Execute configuration file */
2130 ret = config_from_file (vty, confp);
2131
paul7021c422003-07-15 12:52:22 +00002132 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002133 {
2134 switch (ret)
paul7021c422003-07-15 12:52:22 +00002135 {
2136 case CMD_ERR_AMBIGUOUS:
2137 fprintf (stderr, "Ambiguous command.\n");
2138 break;
2139 case CMD_ERR_NO_MATCH:
2140 fprintf (stderr, "There is no such command.\n");
2141 break;
2142 }
paul718e3742002-12-13 20:15:29 +00002143 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2144 vty->buf);
2145 vty_close (vty);
2146 exit (1);
2147 }
2148
2149 vty_close (vty);
2150}
2151
2152FILE *
2153vty_use_backup_config (char *fullpath)
2154{
2155 char *fullpath_sav, *fullpath_tmp;
2156 FILE *ret = NULL;
2157 struct stat buf;
2158 int tmp, sav;
2159 int c;
2160 char buffer[512];
2161
2162 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2163 strcpy (fullpath_sav, fullpath);
2164 strcat (fullpath_sav, CONF_BACKUP_EXT);
2165 if (stat (fullpath_sav, &buf) == -1)
2166 {
2167 free (fullpath_sav);
2168 return NULL;
2169 }
2170
2171 fullpath_tmp = malloc (strlen (fullpath) + 8);
2172 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2173
2174 /* Open file to configuration write. */
2175 tmp = mkstemp (fullpath_tmp);
2176 if (tmp < 0)
2177 {
2178 free (fullpath_sav);
2179 free (fullpath_tmp);
2180 return NULL;
2181 }
2182
2183 sav = open (fullpath_sav, O_RDONLY);
2184 if (sav < 0)
2185 {
gdt3dbf9962003-12-22 20:18:18 +00002186 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002187 free (fullpath_sav);
2188 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002189 return NULL;
2190 }
2191
2192 while((c = read (sav, buffer, 512)) > 0)
2193 write (tmp, buffer, c);
2194
2195 close (sav);
2196 close (tmp);
2197
gdtaa593d52003-12-22 20:15:53 +00002198 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2199 {
gdt3dbf9962003-12-22 20:18:18 +00002200 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002201 free (fullpath_sav);
2202 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002203 return NULL;
2204 }
2205
paul718e3742002-12-13 20:15:29 +00002206 if (link (fullpath_tmp, fullpath) == 0)
2207 ret = fopen (fullpath, "r");
2208
2209 unlink (fullpath_tmp);
2210
2211 free (fullpath_sav);
2212 free (fullpath_tmp);
2213 return fopen (fullpath, "r");
2214}
2215
2216/* Read up configuration file from file_name. */
2217void
2218vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002219 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002220{
paulccc92352003-10-22 02:49:38 +00002221 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002222 FILE *confp = NULL;
2223 char *fullpath;
2224
2225 /* If -f flag specified. */
2226 if (config_file != NULL)
2227 {
2228 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002229 {
2230 getcwd (cwd, MAXPATHLEN);
2231 fullpath = XMALLOC (MTYPE_TMP,
2232 strlen (cwd) + strlen (config_file) + 2);
2233 sprintf (fullpath, "%s/%s", cwd, config_file);
2234 }
paul718e3742002-12-13 20:15:29 +00002235 else
hasso320ec102004-06-20 19:54:37 +00002236 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002237
2238 confp = fopen (fullpath, "r");
2239
2240 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002241 {
2242 confp = vty_use_backup_config (fullpath);
2243 if (confp)
2244 fprintf (stderr, "WARNING: using backup configuration file!\n");
2245 else
2246 {
2247 fprintf (stderr, "can't open configuration file [%s]\n",
2248 config_file);
2249 exit(1);
2250 }
2251 }
paul718e3742002-12-13 20:15:29 +00002252 }
2253 else
2254 {
paul718e3742002-12-13 20:15:29 +00002255#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002256 int ret;
2257 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002258
hasso320ec102004-06-20 19:54:37 +00002259 /* !!!!PLEASE LEAVE!!!!
2260 * This is NEEDED for use with vtysh -b, or else you can get
2261 * a real configuration food fight with a lot garbage in the
2262 * merged configuration file it creates coming from the per
2263 * daemon configuration files. This also allows the daemons
2264 * to start if there default configuration file is not
2265 * present or ignore them, as needed when using vtysh -b to
2266 * configure the daemons at boot - MAG
2267 */
paul718e3742002-12-13 20:15:29 +00002268
hasso320ec102004-06-20 19:54:37 +00002269 /* Stat for vtysh Zebra.conf, if found startup and wait for
2270 * boot configuration
2271 */
paul718e3742002-12-13 20:15:29 +00002272
hasso320ec102004-06-20 19:54:37 +00002273 if ( strstr(config_default_dir, "vtysh") == NULL)
2274 {
2275 ret = stat (integrate_default, &conf_stat);
2276 if (ret >= 0)
2277 return;
2278 }
paul718e3742002-12-13 20:15:29 +00002279#endif /* VTYSH */
2280
hasso320ec102004-06-20 19:54:37 +00002281 confp = fopen (config_default_dir, "r");
2282 if (confp == NULL)
2283 {
2284 confp = vty_use_backup_config (config_default_dir);
2285 if (confp)
2286 {
2287 fprintf (stderr, "WARNING: using backup configuration file!\n");
2288 fullpath = config_default_dir;
2289 }
2290 else
2291 {
2292 fprintf (stderr, "can't open configuration file [%s]\n",
2293 config_default_dir);
2294 exit (1);
2295 }
2296 }
paul718e3742002-12-13 20:15:29 +00002297 else
hasso320ec102004-06-20 19:54:37 +00002298 fullpath = config_default_dir;
2299 }
2300
paul718e3742002-12-13 20:15:29 +00002301 vty_read_file (confp);
2302
2303 fclose (confp);
2304
2305 host_config_set (fullpath);
2306}
2307
2308/* Small utility function which output log to the VTY. */
2309void
2310vty_log (const char *proto_str, const char *format, va_list va)
2311{
hasso8c328f12004-10-05 21:01:23 +00002312 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002313 struct vty *vty;
2314
2315 for (i = 0; i < vector_max (vtyvec); i++)
2316 if ((vty = vector_slot (vtyvec, i)) != NULL)
2317 if (vty->monitor)
2318 vty_log_out (vty, proto_str, format, va);
2319}
2320
2321int
2322vty_config_lock (struct vty *vty)
2323{
2324 if (vty_config == 0)
2325 {
2326 vty->config = 1;
2327 vty_config = 1;
2328 }
2329 return vty->config;
2330}
2331
2332int
2333vty_config_unlock (struct vty *vty)
2334{
2335 if (vty_config == 1 && vty->config == 1)
2336 {
2337 vty->config = 0;
2338 vty_config = 0;
2339 }
2340 return vty->config;
2341}
2342
2343/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002344static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002345
2346static void
2347vty_event (enum event event, int sock, struct vty *vty)
2348{
2349 struct thread *vty_serv_thread;
2350
2351 switch (event)
2352 {
2353 case VTY_SERV:
2354 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2355 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2356 break;
2357#ifdef VTYSH
2358 case VTYSH_SERV:
2359 thread_add_read (master, vtysh_accept, vty, sock);
2360 break;
2361 case VTYSH_READ:
2362 thread_add_read (master, vtysh_read, vty, sock);
2363 break;
2364#endif /* VTYSH */
2365 case VTY_READ:
2366 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2367
2368 /* Time out treatment. */
2369 if (vty->v_timeout)
2370 {
2371 if (vty->t_timeout)
2372 thread_cancel (vty->t_timeout);
2373 vty->t_timeout =
2374 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2375 }
2376 break;
2377 case VTY_WRITE:
2378 if (! vty->t_write)
2379 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2380 break;
2381 case VTY_TIMEOUT_RESET:
2382 if (vty->t_timeout)
2383 {
2384 thread_cancel (vty->t_timeout);
2385 vty->t_timeout = NULL;
2386 }
2387 if (vty->v_timeout)
2388 {
2389 vty->t_timeout =
2390 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2391 }
2392 break;
2393 }
2394}
2395
2396DEFUN (config_who,
2397 config_who_cmd,
2398 "who",
2399 "Display who is on vty\n")
2400{
hasso8c328f12004-10-05 21:01:23 +00002401 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002402 struct vty *v;
2403
2404 for (i = 0; i < vector_max (vtyvec); i++)
2405 if ((v = vector_slot (vtyvec, i)) != NULL)
2406 vty_out (vty, "%svty[%d] connected from %s.%s",
2407 v->config ? "*" : " ",
2408 i, v->address, VTY_NEWLINE);
2409 return CMD_SUCCESS;
2410}
2411
2412/* Move to vty configuration mode. */
2413DEFUN (line_vty,
2414 line_vty_cmd,
2415 "line vty",
2416 "Configure a terminal line\n"
2417 "Virtual terminal\n")
2418{
2419 vty->node = VTY_NODE;
2420 return CMD_SUCCESS;
2421}
2422
2423/* Set time out value. */
2424int
paul9035efa2004-10-10 11:56:56 +00002425exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002426{
2427 unsigned long timeout = 0;
2428
2429 /* min_str and sec_str are already checked by parser. So it must be
2430 all digit string. */
2431 if (min_str)
2432 {
2433 timeout = strtol (min_str, NULL, 10);
2434 timeout *= 60;
2435 }
2436 if (sec_str)
2437 timeout += strtol (sec_str, NULL, 10);
2438
2439 vty_timeout_val = timeout;
2440 vty->v_timeout = timeout;
2441 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2442
2443
2444 return CMD_SUCCESS;
2445}
2446
2447DEFUN (exec_timeout_min,
2448 exec_timeout_min_cmd,
2449 "exec-timeout <0-35791>",
2450 "Set timeout value\n"
2451 "Timeout value in minutes\n")
2452{
2453 return exec_timeout (vty, argv[0], NULL);
2454}
2455
2456DEFUN (exec_timeout_sec,
2457 exec_timeout_sec_cmd,
2458 "exec-timeout <0-35791> <0-2147483>",
2459 "Set the EXEC timeout\n"
2460 "Timeout in minutes\n"
2461 "Timeout in seconds\n")
2462{
2463 return exec_timeout (vty, argv[0], argv[1]);
2464}
2465
2466DEFUN (no_exec_timeout,
2467 no_exec_timeout_cmd,
2468 "no exec-timeout",
2469 NO_STR
2470 "Set the EXEC timeout\n")
2471{
2472 return exec_timeout (vty, NULL, NULL);
2473}
2474
2475/* Set vty access class. */
2476DEFUN (vty_access_class,
2477 vty_access_class_cmd,
2478 "access-class WORD",
2479 "Filter connections based on an IP access list\n"
2480 "IP access list\n")
2481{
2482 if (vty_accesslist_name)
2483 XFREE(MTYPE_VTY, vty_accesslist_name);
2484
2485 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2486
2487 return CMD_SUCCESS;
2488}
2489
2490/* Clear vty access class. */
2491DEFUN (no_vty_access_class,
2492 no_vty_access_class_cmd,
2493 "no access-class [WORD]",
2494 NO_STR
2495 "Filter connections based on an IP access list\n"
2496 "IP access list\n")
2497{
2498 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2499 {
2500 vty_out (vty, "Access-class is not currently applied to vty%s",
2501 VTY_NEWLINE);
2502 return CMD_WARNING;
2503 }
2504
2505 XFREE(MTYPE_VTY, vty_accesslist_name);
2506
2507 vty_accesslist_name = NULL;
2508
2509 return CMD_SUCCESS;
2510}
2511
2512#ifdef HAVE_IPV6
2513/* Set vty access class. */
2514DEFUN (vty_ipv6_access_class,
2515 vty_ipv6_access_class_cmd,
2516 "ipv6 access-class WORD",
2517 IPV6_STR
2518 "Filter connections based on an IP access list\n"
2519 "IPv6 access list\n")
2520{
2521 if (vty_ipv6_accesslist_name)
2522 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2523
2524 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2525
2526 return CMD_SUCCESS;
2527}
2528
2529/* Clear vty access class. */
2530DEFUN (no_vty_ipv6_access_class,
2531 no_vty_ipv6_access_class_cmd,
2532 "no ipv6 access-class [WORD]",
2533 NO_STR
2534 IPV6_STR
2535 "Filter connections based on an IP access list\n"
2536 "IPv6 access list\n")
2537{
2538 if (! vty_ipv6_accesslist_name ||
2539 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2540 {
2541 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2542 VTY_NEWLINE);
2543 return CMD_WARNING;
2544 }
2545
2546 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2547
2548 vty_ipv6_accesslist_name = NULL;
2549
2550 return CMD_SUCCESS;
2551}
2552#endif /* HAVE_IPV6 */
2553
2554/* vty login. */
2555DEFUN (vty_login,
2556 vty_login_cmd,
2557 "login",
2558 "Enable password checking\n")
2559{
2560 no_password_check = 0;
2561 return CMD_SUCCESS;
2562}
2563
2564DEFUN (no_vty_login,
2565 no_vty_login_cmd,
2566 "no login",
2567 NO_STR
2568 "Enable password checking\n")
2569{
2570 no_password_check = 1;
2571 return CMD_SUCCESS;
2572}
2573
2574DEFUN (service_advanced_vty,
2575 service_advanced_vty_cmd,
2576 "service advanced-vty",
2577 "Set up miscellaneous service\n"
2578 "Enable advanced mode vty interface\n")
2579{
2580 host.advanced = 1;
2581 return CMD_SUCCESS;
2582}
2583
2584DEFUN (no_service_advanced_vty,
2585 no_service_advanced_vty_cmd,
2586 "no service advanced-vty",
2587 NO_STR
2588 "Set up miscellaneous service\n"
2589 "Enable advanced mode vty interface\n")
2590{
2591 host.advanced = 0;
2592 return CMD_SUCCESS;
2593}
2594
2595DEFUN (terminal_monitor,
2596 terminal_monitor_cmd,
2597 "terminal monitor",
2598 "Set terminal line parameters\n"
2599 "Copy debug output to the current terminal line\n")
2600{
2601 vty->monitor = 1;
2602 return CMD_SUCCESS;
2603}
2604
2605DEFUN (terminal_no_monitor,
2606 terminal_no_monitor_cmd,
2607 "terminal no monitor",
2608 "Set terminal line parameters\n"
2609 NO_STR
2610 "Copy debug output to the current terminal line\n")
2611{
2612 vty->monitor = 0;
2613 return CMD_SUCCESS;
2614}
2615
2616DEFUN (show_history,
2617 show_history_cmd,
2618 "show history",
2619 SHOW_STR
2620 "Display the session command history\n")
2621{
2622 int index;
2623
2624 for (index = vty->hindex + 1; index != vty->hindex;)
2625 {
2626 if (index == VTY_MAXHIST)
2627 {
2628 index = 0;
2629 continue;
2630 }
2631
2632 if (vty->hist[index] != NULL)
2633 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2634
2635 index++;
2636 }
2637
2638 return CMD_SUCCESS;
2639}
2640
2641/* Display current configuration. */
2642int
2643vty_config_write (struct vty *vty)
2644{
2645 vty_out (vty, "line vty%s", VTY_NEWLINE);
2646
2647 if (vty_accesslist_name)
2648 vty_out (vty, " access-class %s%s",
2649 vty_accesslist_name, VTY_NEWLINE);
2650
2651 if (vty_ipv6_accesslist_name)
2652 vty_out (vty, " ipv6 access-class %s%s",
2653 vty_ipv6_accesslist_name, VTY_NEWLINE);
2654
2655 /* exec-timeout */
2656 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2657 vty_out (vty, " exec-timeout %ld %ld%s",
2658 vty_timeout_val / 60,
2659 vty_timeout_val % 60, VTY_NEWLINE);
2660
2661 /* login */
2662 if (no_password_check)
2663 vty_out (vty, " no login%s", VTY_NEWLINE);
2664
2665 vty_out (vty, "!%s", VTY_NEWLINE);
2666
2667 return CMD_SUCCESS;
2668}
2669
2670struct cmd_node vty_node =
2671{
2672 VTY_NODE,
2673 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00002674 1,
paul718e3742002-12-13 20:15:29 +00002675};
2676
2677/* Reset all VTY status. */
2678void
2679vty_reset ()
2680{
hasso8c328f12004-10-05 21:01:23 +00002681 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002682 struct vty *vty;
2683 struct thread *vty_serv_thread;
2684
2685 for (i = 0; i < vector_max (vtyvec); i++)
2686 if ((vty = vector_slot (vtyvec, i)) != NULL)
2687 {
2688 buffer_reset (vty->obuf);
2689 vty->status = VTY_CLOSE;
2690 vty_close (vty);
2691 }
2692
2693 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2694 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2695 {
2696 thread_cancel (vty_serv_thread);
2697 vector_slot (Vvty_serv_thread, i) = NULL;
2698 close (i);
2699 }
2700
2701 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2702
2703 if (vty_accesslist_name)
2704 {
2705 XFREE(MTYPE_VTY, vty_accesslist_name);
2706 vty_accesslist_name = NULL;
2707 }
2708
2709 if (vty_ipv6_accesslist_name)
2710 {
2711 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2712 vty_ipv6_accesslist_name = NULL;
2713 }
2714}
2715
2716/* for ospf6d easy temprary reload function */
2717/* vty_reset + close accept socket */
2718void
2719vty_finish ()
2720{
hasso8c328f12004-10-05 21:01:23 +00002721 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002722 struct vty *vty;
2723 struct thread *vty_serv_thread;
2724
2725 for (i = 0; i < vector_max (vtyvec); i++)
2726 if ((vty = vector_slot (vtyvec, i)) != NULL)
2727 {
2728 buffer_reset (vty->obuf);
2729 vty->status = VTY_CLOSE;
2730 vty_close (vty);
2731 }
2732
2733 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2734 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2735 {
2736 thread_cancel (vty_serv_thread);
2737 vector_slot (Vvty_serv_thread, i) = NULL;
2738 close (i);
2739 }
2740
2741 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2742
2743 if (vty_accesslist_name)
2744 {
2745 XFREE(MTYPE_VTY, vty_accesslist_name);
2746 vty_accesslist_name = NULL;
2747 }
2748
2749 if (vty_ipv6_accesslist_name)
2750 {
2751 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2752 vty_ipv6_accesslist_name = NULL;
2753 }
2754}
2755
2756void
2757vty_save_cwd ()
2758{
paul79ad2792003-10-15 22:09:28 +00002759 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00002760 char *c;
paul718e3742002-12-13 20:15:29 +00002761
paulccc92352003-10-22 02:49:38 +00002762 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002763
paulccc92352003-10-22 02:49:38 +00002764 if (!c)
paul79ad2792003-10-15 22:09:28 +00002765 {
2766 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00002767 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002768 }
paul718e3742002-12-13 20:15:29 +00002769
2770 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2771 strcpy (vty_cwd, cwd);
2772}
2773
2774char *
2775vty_get_cwd ()
2776{
2777 return vty_cwd;
2778}
2779
2780int
2781vty_shell (struct vty *vty)
2782{
2783 return vty->type == VTY_SHELL ? 1 : 0;
2784}
2785
2786int
2787vty_shell_serv (struct vty *vty)
2788{
2789 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2790}
2791
2792void
2793vty_init_vtysh ()
2794{
2795 vtyvec = vector_init (VECTOR_MIN_SIZE);
2796}
2797
2798/* Install vty's own commands like `who' command. */
2799void
paulb21b19c2003-06-15 01:28:29 +00002800vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00002801{
2802 /* For further configuration read, preserve current directory. */
2803 vty_save_cwd ();
2804
2805 vtyvec = vector_init (VECTOR_MIN_SIZE);
2806
paulb21b19c2003-06-15 01:28:29 +00002807 master = master_thread;
2808
paul718e3742002-12-13 20:15:29 +00002809 /* Initilize server thread vector. */
2810 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2811
2812 /* Install bgp top node. */
2813 install_node (&vty_node, vty_config_write);
2814
2815 install_element (VIEW_NODE, &config_who_cmd);
2816 install_element (VIEW_NODE, &show_history_cmd);
2817 install_element (ENABLE_NODE, &config_who_cmd);
2818 install_element (CONFIG_NODE, &line_vty_cmd);
2819 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2820 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2821 install_element (CONFIG_NODE, &show_history_cmd);
2822 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2823 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
2824 install_element (ENABLE_NODE, &show_history_cmd);
2825
2826 install_default (VTY_NODE);
2827 install_element (VTY_NODE, &exec_timeout_min_cmd);
2828 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2829 install_element (VTY_NODE, &no_exec_timeout_cmd);
2830 install_element (VTY_NODE, &vty_access_class_cmd);
2831 install_element (VTY_NODE, &no_vty_access_class_cmd);
2832 install_element (VTY_NODE, &vty_login_cmd);
2833 install_element (VTY_NODE, &no_vty_login_cmd);
2834#ifdef HAVE_IPV6
2835 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2836 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2837#endif /* HAVE_IPV6 */
2838}