blob: e37c99f56abafe498773650890b606440a044bb2 [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;
paul75e15fe2004-10-31 02:13:09 +00001860 int sock, len;
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
1905 umask (old_mask);
1906
pauledd7c242003-06-04 13:59:38 +00001907 zprivs_get_ids(&ids);
1908
1909 if (ids.gid_vty > 0)
1910 {
1911 /* set group of socket */
1912 if ( chown (path, -1, ids.gid_vty) )
1913 {
1914 zlog_err ("vty_serv_un: could chown socket, %s",
1915 strerror (errno) );
1916 }
1917 }
1918
paul718e3742002-12-13 20:15:29 +00001919 vty_event (VTYSH_SERV, sock, NULL);
1920}
1921
1922/* #define VTYSH_DEBUG 1 */
1923
1924static int
1925vtysh_accept (struct thread *thread)
1926{
1927 int accept_sock;
1928 int sock;
1929 int client_len;
paul75e15fe2004-10-31 02:13:09 +00001930 int flags;
paul718e3742002-12-13 20:15:29 +00001931 struct sockaddr_un client;
1932 struct vty *vty;
1933
1934 accept_sock = THREAD_FD (thread);
1935
1936 vty_event (VTYSH_SERV, accept_sock, NULL);
1937
1938 memset (&client, 0, sizeof (struct sockaddr_un));
1939 client_len = sizeof (struct sockaddr_un);
1940
hassoe473b032004-09-26 16:08:11 +00001941 sock = accept (accept_sock, (struct sockaddr *) &client,
1942 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00001943
1944 if (sock < 0)
1945 {
1946 zlog_warn ("can't accept vty socket : %s", strerror (errno));
1947 return -1;
1948 }
1949
pauldccfb192004-10-29 08:29:36 +00001950 /* set to non-blocking*/
1951 if ( ((flags = fcntl (sock, F_GETFL)) == -1)
1952 || (fcntl (sock, F_SETFL, flags|O_NONBLOCK) == -1) )
paul75e15fe2004-10-31 02:13:09 +00001953 {
1954 zlog_warn ("vtysh_accept: could not set vty socket to non-blocking,"
1955 " %s, closing", strerror (errno));
1956 close (sock);
1957 return -1;
1958 }
pauldccfb192004-10-29 08:29:36 +00001959
paul718e3742002-12-13 20:15:29 +00001960#ifdef VTYSH_DEBUG
1961 printf ("VTY shell accept\n");
1962#endif /* VTYSH_DEBUG */
1963
1964 vty = vty_new ();
1965 vty->fd = sock;
1966 vty->type = VTY_SHELL_SERV;
1967 vty->node = VIEW_NODE;
1968
1969 vty_event (VTYSH_READ, sock, vty);
1970
1971 return 0;
1972}
1973
1974static int
1975vtysh_read (struct thread *thread)
1976{
1977 int ret;
1978 int sock;
1979 int nbytes;
1980 struct vty *vty;
1981 unsigned char buf[VTY_READ_BUFSIZ];
1982 u_char header[4] = {0, 0, 0, 0};
1983
1984 sock = THREAD_FD (thread);
1985 vty = THREAD_ARG (thread);
1986 vty->t_read = NULL;
1987
1988 nbytes = read (sock, buf, VTY_READ_BUFSIZ);
1989 if (nbytes <= 0)
1990 {
1991 vty_close (vty);
1992#ifdef VTYSH_DEBUG
1993 printf ("close vtysh\n");
1994#endif /* VTYSH_DEBUG */
1995 return 0;
1996 }
1997
1998#ifdef VTYSH_DEBUG
1999 printf ("line: %s\n", buf);
2000#endif /* VTYSH_DEBUG */
2001
2002 vty_ensure (vty, nbytes);
2003 memcpy (vty->buf, buf, nbytes);
2004
2005 /* Pass this line to parser. */
2006 ret = vty_execute (vty);
2007
2008 vty_clear_buf (vty);
2009
2010 /* Return result. */
2011#ifdef VTYSH_DEBUG
2012 printf ("result: %d\n", ret);
2013 printf ("vtysh node: %d\n", vty->node);
2014#endif /* VTYSH_DEBUG */
2015
2016 header[3] = ret;
2017 write (vty->fd, header, 4);
2018
2019 vty_event (VTYSH_READ, sock, vty);
2020
2021 return 0;
2022}
2023#endif /* VTYSH */
2024
2025/* Determine address family to bind. */
2026void
hasso6ad96ea2004-10-07 19:33:46 +00002027vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002028{
2029 /* If port is set to 0, do not listen on TCP/IP at all! */
2030 if (port)
2031 {
2032
2033#ifdef HAVE_IPV6
2034#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002035 vty_serv_sock_family (addr, port, AF_INET);
2036 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002037#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002038 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002039#endif /* NRL*/
2040#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002041 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002042#endif /* HAVE_IPV6 */
2043 }
2044
2045#ifdef VTYSH
2046 vty_serv_un (path);
2047#endif /* VTYSH */
2048}
2049
2050/* Close vty interface. */
2051void
2052vty_close (struct vty *vty)
2053{
2054 int i;
2055
2056 /* Cancel threads.*/
2057 if (vty->t_read)
2058 thread_cancel (vty->t_read);
2059 if (vty->t_write)
2060 thread_cancel (vty->t_write);
2061 if (vty->t_timeout)
2062 thread_cancel (vty->t_timeout);
2063 if (vty->t_output)
2064 thread_cancel (vty->t_output);
2065
2066 /* Flush buffer. */
2067 if (! buffer_empty (vty->obuf))
2068 buffer_flush_all (vty->obuf, vty->fd);
2069
2070 /* Free input buffer. */
2071 buffer_free (vty->obuf);
2072
2073 /* Free SB buffer. */
2074 if (vty->sb_buffer)
2075 buffer_free (vty->sb_buffer);
2076
2077 /* Free command history. */
2078 for (i = 0; i < VTY_MAXHIST; i++)
2079 if (vty->hist[i])
2080 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2081
2082 /* Unset vector. */
2083 vector_unset (vtyvec, vty->fd);
2084
2085 /* Close socket. */
2086 if (vty->fd > 0)
2087 close (vty->fd);
2088
2089 if (vty->address)
2090 XFREE (0, vty->address);
2091 if (vty->buf)
2092 XFREE (MTYPE_VTY, vty->buf);
2093
2094 /* Check configure. */
2095 vty_config_unlock (vty);
2096
2097 /* OK free vty. */
2098 XFREE (MTYPE_VTY, vty);
2099}
2100
2101/* When time out occur output message then close connection. */
2102static int
2103vty_timeout (struct thread *thread)
2104{
2105 struct vty *vty;
2106
2107 vty = THREAD_ARG (thread);
2108 vty->t_timeout = NULL;
2109 vty->v_timeout = 0;
2110
2111 /* Clear buffer*/
2112 buffer_reset (vty->obuf);
2113 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2114
2115 /* Close connection. */
2116 vty->status = VTY_CLOSE;
2117 vty_close (vty);
2118
2119 return 0;
2120}
2121
2122/* Read up configuration file from file_name. */
2123static void
2124vty_read_file (FILE *confp)
2125{
2126 int ret;
2127 struct vty *vty;
2128
2129 vty = vty_new ();
2130 vty->fd = 0; /* stdout */
2131 vty->type = VTY_TERM;
2132 vty->node = CONFIG_NODE;
2133
2134 /* Execute configuration file */
2135 ret = config_from_file (vty, confp);
2136
paul7021c422003-07-15 12:52:22 +00002137 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002138 {
2139 switch (ret)
paul7021c422003-07-15 12:52:22 +00002140 {
2141 case CMD_ERR_AMBIGUOUS:
2142 fprintf (stderr, "Ambiguous command.\n");
2143 break;
2144 case CMD_ERR_NO_MATCH:
2145 fprintf (stderr, "There is no such command.\n");
2146 break;
2147 }
paul718e3742002-12-13 20:15:29 +00002148 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2149 vty->buf);
2150 vty_close (vty);
2151 exit (1);
2152 }
2153
2154 vty_close (vty);
2155}
2156
2157FILE *
2158vty_use_backup_config (char *fullpath)
2159{
2160 char *fullpath_sav, *fullpath_tmp;
2161 FILE *ret = NULL;
2162 struct stat buf;
2163 int tmp, sav;
2164 int c;
2165 char buffer[512];
2166
2167 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2168 strcpy (fullpath_sav, fullpath);
2169 strcat (fullpath_sav, CONF_BACKUP_EXT);
2170 if (stat (fullpath_sav, &buf) == -1)
2171 {
2172 free (fullpath_sav);
2173 return NULL;
2174 }
2175
2176 fullpath_tmp = malloc (strlen (fullpath) + 8);
2177 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2178
2179 /* Open file to configuration write. */
2180 tmp = mkstemp (fullpath_tmp);
2181 if (tmp < 0)
2182 {
2183 free (fullpath_sav);
2184 free (fullpath_tmp);
2185 return NULL;
2186 }
2187
2188 sav = open (fullpath_sav, O_RDONLY);
2189 if (sav < 0)
2190 {
gdt3dbf9962003-12-22 20:18:18 +00002191 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002192 free (fullpath_sav);
2193 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002194 return NULL;
2195 }
2196
2197 while((c = read (sav, buffer, 512)) > 0)
2198 write (tmp, buffer, c);
2199
2200 close (sav);
2201 close (tmp);
2202
gdtaa593d52003-12-22 20:15:53 +00002203 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2204 {
gdt3dbf9962003-12-22 20:18:18 +00002205 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002206 free (fullpath_sav);
2207 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002208 return NULL;
2209 }
2210
paul718e3742002-12-13 20:15:29 +00002211 if (link (fullpath_tmp, fullpath) == 0)
2212 ret = fopen (fullpath, "r");
2213
2214 unlink (fullpath_tmp);
2215
2216 free (fullpath_sav);
2217 free (fullpath_tmp);
2218 return fopen (fullpath, "r");
2219}
2220
2221/* Read up configuration file from file_name. */
2222void
2223vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002224 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002225{
paulccc92352003-10-22 02:49:38 +00002226 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002227 FILE *confp = NULL;
2228 char *fullpath;
2229
2230 /* If -f flag specified. */
2231 if (config_file != NULL)
2232 {
2233 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002234 {
2235 getcwd (cwd, MAXPATHLEN);
2236 fullpath = XMALLOC (MTYPE_TMP,
2237 strlen (cwd) + strlen (config_file) + 2);
2238 sprintf (fullpath, "%s/%s", cwd, config_file);
2239 }
paul718e3742002-12-13 20:15:29 +00002240 else
hasso320ec102004-06-20 19:54:37 +00002241 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002242
2243 confp = fopen (fullpath, "r");
2244
2245 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002246 {
2247 confp = vty_use_backup_config (fullpath);
2248 if (confp)
2249 fprintf (stderr, "WARNING: using backup configuration file!\n");
2250 else
2251 {
2252 fprintf (stderr, "can't open configuration file [%s]\n",
2253 config_file);
2254 exit(1);
2255 }
2256 }
paul718e3742002-12-13 20:15:29 +00002257 }
2258 else
2259 {
paul718e3742002-12-13 20:15:29 +00002260#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002261 int ret;
2262 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002263
hasso320ec102004-06-20 19:54:37 +00002264 /* !!!!PLEASE LEAVE!!!!
2265 * This is NEEDED for use with vtysh -b, or else you can get
2266 * a real configuration food fight with a lot garbage in the
2267 * merged configuration file it creates coming from the per
2268 * daemon configuration files. This also allows the daemons
2269 * to start if there default configuration file is not
2270 * present or ignore them, as needed when using vtysh -b to
2271 * configure the daemons at boot - MAG
2272 */
paul718e3742002-12-13 20:15:29 +00002273
hasso320ec102004-06-20 19:54:37 +00002274 /* Stat for vtysh Zebra.conf, if found startup and wait for
2275 * boot configuration
2276 */
paul718e3742002-12-13 20:15:29 +00002277
hasso320ec102004-06-20 19:54:37 +00002278 if ( strstr(config_default_dir, "vtysh") == NULL)
2279 {
2280 ret = stat (integrate_default, &conf_stat);
2281 if (ret >= 0)
2282 return;
2283 }
paul718e3742002-12-13 20:15:29 +00002284#endif /* VTYSH */
2285
hasso320ec102004-06-20 19:54:37 +00002286 confp = fopen (config_default_dir, "r");
2287 if (confp == NULL)
2288 {
2289 confp = vty_use_backup_config (config_default_dir);
2290 if (confp)
2291 {
2292 fprintf (stderr, "WARNING: using backup configuration file!\n");
2293 fullpath = config_default_dir;
2294 }
2295 else
2296 {
2297 fprintf (stderr, "can't open configuration file [%s]\n",
2298 config_default_dir);
2299 exit (1);
2300 }
2301 }
paul718e3742002-12-13 20:15:29 +00002302 else
hasso320ec102004-06-20 19:54:37 +00002303 fullpath = config_default_dir;
2304 }
2305
paul718e3742002-12-13 20:15:29 +00002306 vty_read_file (confp);
2307
2308 fclose (confp);
2309
2310 host_config_set (fullpath);
2311}
2312
2313/* Small utility function which output log to the VTY. */
2314void
2315vty_log (const char *proto_str, const char *format, va_list va)
2316{
hasso8c328f12004-10-05 21:01:23 +00002317 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002318 struct vty *vty;
2319
2320 for (i = 0; i < vector_max (vtyvec); i++)
2321 if ((vty = vector_slot (vtyvec, i)) != NULL)
2322 if (vty->monitor)
2323 vty_log_out (vty, proto_str, format, va);
2324}
2325
2326int
2327vty_config_lock (struct vty *vty)
2328{
2329 if (vty_config == 0)
2330 {
2331 vty->config = 1;
2332 vty_config = 1;
2333 }
2334 return vty->config;
2335}
2336
2337int
2338vty_config_unlock (struct vty *vty)
2339{
2340 if (vty_config == 1 && vty->config == 1)
2341 {
2342 vty->config = 0;
2343 vty_config = 0;
2344 }
2345 return vty->config;
2346}
2347
2348/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002349static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002350
2351static void
2352vty_event (enum event event, int sock, struct vty *vty)
2353{
2354 struct thread *vty_serv_thread;
2355
2356 switch (event)
2357 {
2358 case VTY_SERV:
2359 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2360 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2361 break;
2362#ifdef VTYSH
2363 case VTYSH_SERV:
2364 thread_add_read (master, vtysh_accept, vty, sock);
2365 break;
2366 case VTYSH_READ:
2367 thread_add_read (master, vtysh_read, vty, sock);
2368 break;
2369#endif /* VTYSH */
2370 case VTY_READ:
2371 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2372
2373 /* Time out treatment. */
2374 if (vty->v_timeout)
2375 {
2376 if (vty->t_timeout)
2377 thread_cancel (vty->t_timeout);
2378 vty->t_timeout =
2379 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2380 }
2381 break;
2382 case VTY_WRITE:
2383 if (! vty->t_write)
2384 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2385 break;
2386 case VTY_TIMEOUT_RESET:
2387 if (vty->t_timeout)
2388 {
2389 thread_cancel (vty->t_timeout);
2390 vty->t_timeout = NULL;
2391 }
2392 if (vty->v_timeout)
2393 {
2394 vty->t_timeout =
2395 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2396 }
2397 break;
2398 }
2399}
2400
2401DEFUN (config_who,
2402 config_who_cmd,
2403 "who",
2404 "Display who is on vty\n")
2405{
hasso8c328f12004-10-05 21:01:23 +00002406 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002407 struct vty *v;
2408
2409 for (i = 0; i < vector_max (vtyvec); i++)
2410 if ((v = vector_slot (vtyvec, i)) != NULL)
2411 vty_out (vty, "%svty[%d] connected from %s.%s",
2412 v->config ? "*" : " ",
2413 i, v->address, VTY_NEWLINE);
2414 return CMD_SUCCESS;
2415}
2416
2417/* Move to vty configuration mode. */
2418DEFUN (line_vty,
2419 line_vty_cmd,
2420 "line vty",
2421 "Configure a terminal line\n"
2422 "Virtual terminal\n")
2423{
2424 vty->node = VTY_NODE;
2425 return CMD_SUCCESS;
2426}
2427
2428/* Set time out value. */
2429int
paul9035efa2004-10-10 11:56:56 +00002430exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002431{
2432 unsigned long timeout = 0;
2433
2434 /* min_str and sec_str are already checked by parser. So it must be
2435 all digit string. */
2436 if (min_str)
2437 {
2438 timeout = strtol (min_str, NULL, 10);
2439 timeout *= 60;
2440 }
2441 if (sec_str)
2442 timeout += strtol (sec_str, NULL, 10);
2443
2444 vty_timeout_val = timeout;
2445 vty->v_timeout = timeout;
2446 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2447
2448
2449 return CMD_SUCCESS;
2450}
2451
2452DEFUN (exec_timeout_min,
2453 exec_timeout_min_cmd,
2454 "exec-timeout <0-35791>",
2455 "Set timeout value\n"
2456 "Timeout value in minutes\n")
2457{
2458 return exec_timeout (vty, argv[0], NULL);
2459}
2460
2461DEFUN (exec_timeout_sec,
2462 exec_timeout_sec_cmd,
2463 "exec-timeout <0-35791> <0-2147483>",
2464 "Set the EXEC timeout\n"
2465 "Timeout in minutes\n"
2466 "Timeout in seconds\n")
2467{
2468 return exec_timeout (vty, argv[0], argv[1]);
2469}
2470
2471DEFUN (no_exec_timeout,
2472 no_exec_timeout_cmd,
2473 "no exec-timeout",
2474 NO_STR
2475 "Set the EXEC timeout\n")
2476{
2477 return exec_timeout (vty, NULL, NULL);
2478}
2479
2480/* Set vty access class. */
2481DEFUN (vty_access_class,
2482 vty_access_class_cmd,
2483 "access-class WORD",
2484 "Filter connections based on an IP access list\n"
2485 "IP access list\n")
2486{
2487 if (vty_accesslist_name)
2488 XFREE(MTYPE_VTY, vty_accesslist_name);
2489
2490 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2491
2492 return CMD_SUCCESS;
2493}
2494
2495/* Clear vty access class. */
2496DEFUN (no_vty_access_class,
2497 no_vty_access_class_cmd,
2498 "no access-class [WORD]",
2499 NO_STR
2500 "Filter connections based on an IP access list\n"
2501 "IP access list\n")
2502{
2503 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2504 {
2505 vty_out (vty, "Access-class is not currently applied to vty%s",
2506 VTY_NEWLINE);
2507 return CMD_WARNING;
2508 }
2509
2510 XFREE(MTYPE_VTY, vty_accesslist_name);
2511
2512 vty_accesslist_name = NULL;
2513
2514 return CMD_SUCCESS;
2515}
2516
2517#ifdef HAVE_IPV6
2518/* Set vty access class. */
2519DEFUN (vty_ipv6_access_class,
2520 vty_ipv6_access_class_cmd,
2521 "ipv6 access-class WORD",
2522 IPV6_STR
2523 "Filter connections based on an IP access list\n"
2524 "IPv6 access list\n")
2525{
2526 if (vty_ipv6_accesslist_name)
2527 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2528
2529 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2530
2531 return CMD_SUCCESS;
2532}
2533
2534/* Clear vty access class. */
2535DEFUN (no_vty_ipv6_access_class,
2536 no_vty_ipv6_access_class_cmd,
2537 "no ipv6 access-class [WORD]",
2538 NO_STR
2539 IPV6_STR
2540 "Filter connections based on an IP access list\n"
2541 "IPv6 access list\n")
2542{
2543 if (! vty_ipv6_accesslist_name ||
2544 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2545 {
2546 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2547 VTY_NEWLINE);
2548 return CMD_WARNING;
2549 }
2550
2551 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2552
2553 vty_ipv6_accesslist_name = NULL;
2554
2555 return CMD_SUCCESS;
2556}
2557#endif /* HAVE_IPV6 */
2558
2559/* vty login. */
2560DEFUN (vty_login,
2561 vty_login_cmd,
2562 "login",
2563 "Enable password checking\n")
2564{
2565 no_password_check = 0;
2566 return CMD_SUCCESS;
2567}
2568
2569DEFUN (no_vty_login,
2570 no_vty_login_cmd,
2571 "no login",
2572 NO_STR
2573 "Enable password checking\n")
2574{
2575 no_password_check = 1;
2576 return CMD_SUCCESS;
2577}
2578
2579DEFUN (service_advanced_vty,
2580 service_advanced_vty_cmd,
2581 "service advanced-vty",
2582 "Set up miscellaneous service\n"
2583 "Enable advanced mode vty interface\n")
2584{
2585 host.advanced = 1;
2586 return CMD_SUCCESS;
2587}
2588
2589DEFUN (no_service_advanced_vty,
2590 no_service_advanced_vty_cmd,
2591 "no service advanced-vty",
2592 NO_STR
2593 "Set up miscellaneous service\n"
2594 "Enable advanced mode vty interface\n")
2595{
2596 host.advanced = 0;
2597 return CMD_SUCCESS;
2598}
2599
2600DEFUN (terminal_monitor,
2601 terminal_monitor_cmd,
2602 "terminal monitor",
2603 "Set terminal line parameters\n"
2604 "Copy debug output to the current terminal line\n")
2605{
2606 vty->monitor = 1;
2607 return CMD_SUCCESS;
2608}
2609
2610DEFUN (terminal_no_monitor,
2611 terminal_no_monitor_cmd,
2612 "terminal no monitor",
2613 "Set terminal line parameters\n"
2614 NO_STR
2615 "Copy debug output to the current terminal line\n")
2616{
2617 vty->monitor = 0;
2618 return CMD_SUCCESS;
2619}
2620
2621DEFUN (show_history,
2622 show_history_cmd,
2623 "show history",
2624 SHOW_STR
2625 "Display the session command history\n")
2626{
2627 int index;
2628
2629 for (index = vty->hindex + 1; index != vty->hindex;)
2630 {
2631 if (index == VTY_MAXHIST)
2632 {
2633 index = 0;
2634 continue;
2635 }
2636
2637 if (vty->hist[index] != NULL)
2638 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2639
2640 index++;
2641 }
2642
2643 return CMD_SUCCESS;
2644}
2645
2646/* Display current configuration. */
2647int
2648vty_config_write (struct vty *vty)
2649{
2650 vty_out (vty, "line vty%s", VTY_NEWLINE);
2651
2652 if (vty_accesslist_name)
2653 vty_out (vty, " access-class %s%s",
2654 vty_accesslist_name, VTY_NEWLINE);
2655
2656 if (vty_ipv6_accesslist_name)
2657 vty_out (vty, " ipv6 access-class %s%s",
2658 vty_ipv6_accesslist_name, VTY_NEWLINE);
2659
2660 /* exec-timeout */
2661 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2662 vty_out (vty, " exec-timeout %ld %ld%s",
2663 vty_timeout_val / 60,
2664 vty_timeout_val % 60, VTY_NEWLINE);
2665
2666 /* login */
2667 if (no_password_check)
2668 vty_out (vty, " no login%s", VTY_NEWLINE);
2669
2670 vty_out (vty, "!%s", VTY_NEWLINE);
2671
2672 return CMD_SUCCESS;
2673}
2674
2675struct cmd_node vty_node =
2676{
2677 VTY_NODE,
2678 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00002679 1,
paul718e3742002-12-13 20:15:29 +00002680};
2681
2682/* Reset all VTY status. */
2683void
2684vty_reset ()
2685{
hasso8c328f12004-10-05 21:01:23 +00002686 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002687 struct vty *vty;
2688 struct thread *vty_serv_thread;
2689
2690 for (i = 0; i < vector_max (vtyvec); i++)
2691 if ((vty = vector_slot (vtyvec, i)) != NULL)
2692 {
2693 buffer_reset (vty->obuf);
2694 vty->status = VTY_CLOSE;
2695 vty_close (vty);
2696 }
2697
2698 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2699 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2700 {
2701 thread_cancel (vty_serv_thread);
2702 vector_slot (Vvty_serv_thread, i) = NULL;
2703 close (i);
2704 }
2705
2706 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2707
2708 if (vty_accesslist_name)
2709 {
2710 XFREE(MTYPE_VTY, vty_accesslist_name);
2711 vty_accesslist_name = NULL;
2712 }
2713
2714 if (vty_ipv6_accesslist_name)
2715 {
2716 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2717 vty_ipv6_accesslist_name = NULL;
2718 }
2719}
2720
2721/* for ospf6d easy temprary reload function */
2722/* vty_reset + close accept socket */
2723void
2724vty_finish ()
2725{
hasso8c328f12004-10-05 21:01:23 +00002726 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002727 struct vty *vty;
2728 struct thread *vty_serv_thread;
2729
2730 for (i = 0; i < vector_max (vtyvec); i++)
2731 if ((vty = vector_slot (vtyvec, i)) != NULL)
2732 {
2733 buffer_reset (vty->obuf);
2734 vty->status = VTY_CLOSE;
2735 vty_close (vty);
2736 }
2737
2738 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2739 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2740 {
2741 thread_cancel (vty_serv_thread);
2742 vector_slot (Vvty_serv_thread, i) = NULL;
2743 close (i);
2744 }
2745
2746 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2747
2748 if (vty_accesslist_name)
2749 {
2750 XFREE(MTYPE_VTY, vty_accesslist_name);
2751 vty_accesslist_name = NULL;
2752 }
2753
2754 if (vty_ipv6_accesslist_name)
2755 {
2756 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2757 vty_ipv6_accesslist_name = NULL;
2758 }
2759}
2760
2761void
2762vty_save_cwd ()
2763{
paul79ad2792003-10-15 22:09:28 +00002764 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00002765 char *c;
paul718e3742002-12-13 20:15:29 +00002766
paulccc92352003-10-22 02:49:38 +00002767 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002768
paulccc92352003-10-22 02:49:38 +00002769 if (!c)
paul79ad2792003-10-15 22:09:28 +00002770 {
2771 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00002772 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002773 }
paul718e3742002-12-13 20:15:29 +00002774
2775 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2776 strcpy (vty_cwd, cwd);
2777}
2778
2779char *
2780vty_get_cwd ()
2781{
2782 return vty_cwd;
2783}
2784
2785int
2786vty_shell (struct vty *vty)
2787{
2788 return vty->type == VTY_SHELL ? 1 : 0;
2789}
2790
2791int
2792vty_shell_serv (struct vty *vty)
2793{
2794 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2795}
2796
2797void
2798vty_init_vtysh ()
2799{
2800 vtyvec = vector_init (VECTOR_MIN_SIZE);
2801}
2802
2803/* Install vty's own commands like `who' command. */
2804void
paulb21b19c2003-06-15 01:28:29 +00002805vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00002806{
2807 /* For further configuration read, preserve current directory. */
2808 vty_save_cwd ();
2809
2810 vtyvec = vector_init (VECTOR_MIN_SIZE);
2811
paulb21b19c2003-06-15 01:28:29 +00002812 master = master_thread;
2813
paul718e3742002-12-13 20:15:29 +00002814 /* Initilize server thread vector. */
2815 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2816
2817 /* Install bgp top node. */
2818 install_node (&vty_node, vty_config_write);
2819
2820 install_element (VIEW_NODE, &config_who_cmd);
2821 install_element (VIEW_NODE, &show_history_cmd);
2822 install_element (ENABLE_NODE, &config_who_cmd);
2823 install_element (CONFIG_NODE, &line_vty_cmd);
2824 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2825 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2826 install_element (CONFIG_NODE, &show_history_cmd);
2827 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2828 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
2829 install_element (ENABLE_NODE, &show_history_cmd);
2830
2831 install_default (VTY_NODE);
2832 install_element (VTY_NODE, &exec_timeout_min_cmd);
2833 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2834 install_element (VTY_NODE, &no_exec_timeout_cmd);
2835 install_element (VTY_NODE, &vty_access_class_cmd);
2836 install_element (VTY_NODE, &no_vty_access_class_cmd);
2837 install_element (VTY_NODE, &vty_login_cmd);
2838 install_element (VTY_NODE, &no_vty_login_cmd);
2839#ifdef HAVE_IPV6
2840 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2841 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2842#endif /* HAVE_IPV6 */
2843}