blob: 1c2491221e6a9806507ac7a34eb7f386edb445cc [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"
28#include "version.h"
29#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{
224 char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
225 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{
232 char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
233 vty_out (vty, "%s", cmd);
234}
235
236/* Make don't use linemode over telnet. */
237static void
238vty_dont_linemode (struct vty *vty)
239{
240 char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
241 vty_out (vty, "%s", cmd);
242}
243
244/* Use window size. */
245static void
246vty_do_window_size (struct vty *vty)
247{
248 char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
249 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{
257 char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
258 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:
629 case KEYCHAIN_NODE:
630 case KEYCHAIN_KEY_NODE:
631 case MASC_NODE:
632 case VTY_NODE:
633 vty_config_unlock (vty);
634 vty->node = ENABLE_NODE;
635 break;
636 default:
637 /* Unknown node, we have to ignore it. */
638 break;
639 }
640
641 vty_prompt (vty);
642 vty->cp = 0;
643}
644
645/* Delete a charcter at the current point. */
646static void
647vty_delete_char (struct vty *vty)
648{
649 int i;
650 int size;
651
652 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
653 return;
654
655 if (vty->length == 0)
656 {
657 vty_down_level (vty);
658 return;
659 }
660
661 if (vty->cp == vty->length)
662 return; /* completion need here? */
663
664 size = vty->length - vty->cp;
665
666 vty->length--;
667 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
668 vty->buf[vty->length] = '\0';
669
670 vty_write (vty, &vty->buf[vty->cp], size - 1);
671 vty_write (vty, &telnet_space_char, 1);
672
673 for (i = 0; i < size; i++)
674 vty_write (vty, &telnet_backward_char, 1);
675}
676
677/* Delete a character before the point. */
678static void
679vty_delete_backward_char (struct vty *vty)
680{
681 if (vty->cp == 0)
682 return;
683
684 vty_backward_char (vty);
685 vty_delete_char (vty);
686}
687
688/* Kill rest of line from current point. */
689static void
690vty_kill_line (struct vty *vty)
691{
692 int i;
693 int size;
694
695 size = vty->length - vty->cp;
696
697 if (size == 0)
698 return;
699
700 for (i = 0; i < size; i++)
701 vty_write (vty, &telnet_space_char, 1);
702 for (i = 0; i < size; i++)
703 vty_write (vty, &telnet_backward_char, 1);
704
705 memset (&vty->buf[vty->cp], 0, size);
706 vty->length = vty->cp;
707}
708
709/* Kill line from the beginning. */
710static void
711vty_kill_line_from_beginning (struct vty *vty)
712{
713 vty_beginning_of_line (vty);
714 vty_kill_line (vty);
715}
716
717/* Delete a word before the point. */
718static void
719vty_forward_kill_word (struct vty *vty)
720{
721 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
722 vty_delete_char (vty);
723 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
724 vty_delete_char (vty);
725}
726
727/* Delete a word before the point. */
728static void
729vty_backward_kill_word (struct vty *vty)
730{
731 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
732 vty_delete_backward_char (vty);
733 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
734 vty_delete_backward_char (vty);
735}
736
737/* Transpose chars before or at the point. */
738static void
739vty_transpose_chars (struct vty *vty)
740{
741 char c1, c2;
742
743 /* If length is short or point is near by the beginning of line then
744 return. */
745 if (vty->length < 2 || vty->cp < 1)
746 return;
747
748 /* In case of point is located at the end of the line. */
749 if (vty->cp == vty->length)
750 {
751 c1 = vty->buf[vty->cp - 1];
752 c2 = vty->buf[vty->cp - 2];
753
754 vty_backward_char (vty);
755 vty_backward_char (vty);
756 vty_self_insert_overwrite (vty, c1);
757 vty_self_insert_overwrite (vty, c2);
758 }
759 else
760 {
761 c1 = vty->buf[vty->cp];
762 c2 = vty->buf[vty->cp - 1];
763
764 vty_backward_char (vty);
765 vty_self_insert_overwrite (vty, c1);
766 vty_self_insert_overwrite (vty, c2);
767 }
768}
769
770/* Do completion at vty interface. */
771static void
772vty_complete_command (struct vty *vty)
773{
774 int i;
775 int ret;
776 char **matched = NULL;
777 vector vline;
778
779 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
780 return;
781
782 vline = cmd_make_strvec (vty->buf);
783 if (vline == NULL)
784 return;
785
786 /* In case of 'help \t'. */
787 if (isspace ((int) vty->buf[vty->length - 1]))
788 vector_set (vline, '\0');
789
790 matched = cmd_complete_command (vline, vty, &ret);
791
792 cmd_free_strvec (vline);
793
794 vty_out (vty, "%s", VTY_NEWLINE);
795 switch (ret)
796 {
797 case CMD_ERR_AMBIGUOUS:
798 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
799 vty_prompt (vty);
800 vty_redraw_line (vty);
801 break;
802 case CMD_ERR_NO_MATCH:
803 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
804 vty_prompt (vty);
805 vty_redraw_line (vty);
806 break;
807 case CMD_COMPLETE_FULL_MATCH:
808 vty_prompt (vty);
809 vty_redraw_line (vty);
810 vty_backward_pure_word (vty);
811 vty_insert_word_overwrite (vty, matched[0]);
812 vty_self_insert (vty, ' ');
813 XFREE (MTYPE_TMP, matched[0]);
814 break;
815 case CMD_COMPLETE_MATCH:
816 vty_prompt (vty);
817 vty_redraw_line (vty);
818 vty_backward_pure_word (vty);
819 vty_insert_word_overwrite (vty, matched[0]);
820 XFREE (MTYPE_TMP, matched[0]);
821 vector_only_index_free (matched);
822 return;
823 break;
824 case CMD_COMPLETE_LIST_MATCH:
825 for (i = 0; matched[i] != NULL; i++)
826 {
827 if (i != 0 && ((i % 6) == 0))
828 vty_out (vty, "%s", VTY_NEWLINE);
829 vty_out (vty, "%-10s ", matched[i]);
830 XFREE (MTYPE_TMP, matched[i]);
831 }
832 vty_out (vty, "%s", VTY_NEWLINE);
833
834 vty_prompt (vty);
835 vty_redraw_line (vty);
836 break;
837 case CMD_ERR_NOTHING_TODO:
838 vty_prompt (vty);
839 vty_redraw_line (vty);
840 break;
841 default:
842 break;
843 }
844 if (matched)
845 vector_only_index_free (matched);
846}
847
848void
849vty_describe_fold (struct vty *vty, int cmd_width,
850 int desc_width, struct desc *desc)
851{
852 char *buf, *cmd, *p;
853 int pos;
854
855 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
856
857 if (desc_width <= 0)
858 {
859 vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
860 return;
861 }
862
863 buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
864
865 for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
866 {
867 for (pos = desc_width; pos > 0; pos--)
868 if (*(p + pos) == ' ')
869 break;
870
871 if (pos == 0)
872 break;
873
874 strncpy (buf, p, pos);
875 buf[pos] = '\0';
876 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
877
878 cmd = "";
879 }
880
881 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
882
883 XFREE (MTYPE_TMP, buf);
884}
885
886/* Describe matched command function. */
887static void
888vty_describe_command (struct vty *vty)
889{
890 int ret;
891 vector vline;
892 vector describe;
893 int i, width, desc_width;
894 struct desc *desc, *desc_cr = NULL;
895
896 vline = cmd_make_strvec (vty->buf);
897
898 /* In case of '> ?'. */
899 if (vline == NULL)
900 {
901 vline = vector_init (1);
902 vector_set (vline, '\0');
903 }
904 else
905 if (isspace ((int) vty->buf[vty->length - 1]))
906 vector_set (vline, '\0');
907
908 describe = cmd_describe_command (vline, vty, &ret);
909
910 vty_out (vty, "%s", VTY_NEWLINE);
911
912 /* Ambiguous error. */
913 switch (ret)
914 {
915 case CMD_ERR_AMBIGUOUS:
916 cmd_free_strvec (vline);
917 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
918 vty_prompt (vty);
919 vty_redraw_line (vty);
920 return;
921 break;
922 case CMD_ERR_NO_MATCH:
923 cmd_free_strvec (vline);
924 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
925 vty_prompt (vty);
926 vty_redraw_line (vty);
927 return;
928 break;
929 }
930
931 /* Get width of command string. */
932 width = 0;
933 for (i = 0; i < vector_max (describe); i++)
934 if ((desc = vector_slot (describe, i)) != NULL)
935 {
936 int len;
937
938 if (desc->cmd[0] == '\0')
939 continue;
940
941 len = strlen (desc->cmd);
942 if (desc->cmd[0] == '.')
943 len--;
944
945 if (width < len)
946 width = len;
947 }
948
949 /* Get width of description string. */
950 desc_width = vty->width - (width + 6);
951
952 /* Print out description. */
953 for (i = 0; i < vector_max (describe); i++)
954 if ((desc = vector_slot (describe, i)) != NULL)
955 {
956 if (desc->cmd[0] == '\0')
957 continue;
958
959 if (strcmp (desc->cmd, "<cr>") == 0)
960 {
961 desc_cr = desc;
962 continue;
963 }
964
965 if (!desc->str)
966 vty_out (vty, " %-s%s",
967 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
968 VTY_NEWLINE);
969 else if (desc_width >= strlen (desc->str))
970 vty_out (vty, " %-*s %s%s", width,
971 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
972 desc->str, VTY_NEWLINE);
973 else
974 vty_describe_fold (vty, width, desc_width, desc);
975
976#if 0
977 vty_out (vty, " %-*s %s%s", width
978 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
979 desc->str ? desc->str : "", VTY_NEWLINE);
980#endif /* 0 */
981 }
982
983 if ((desc = desc_cr))
984 {
985 if (!desc->str)
986 vty_out (vty, " %-s%s",
987 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
988 VTY_NEWLINE);
989 else if (desc_width >= strlen (desc->str))
990 vty_out (vty, " %-*s %s%s", width,
991 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
992 desc->str, VTY_NEWLINE);
993 else
994 vty_describe_fold (vty, width, desc_width, desc);
995 }
996
997 cmd_free_strvec (vline);
998 vector_free (describe);
999
1000 vty_prompt (vty);
1001 vty_redraw_line (vty);
1002}
1003
1004void
1005vty_clear_buf (struct vty *vty)
1006{
1007 memset (vty->buf, 0, vty->max);
1008}
1009
1010/* ^C stop current input and do not add command line to the history. */
1011static void
1012vty_stop_input (struct vty *vty)
1013{
1014 vty->cp = vty->length = 0;
1015 vty_clear_buf (vty);
1016 vty_out (vty, "%s", VTY_NEWLINE);
1017
1018 switch (vty->node)
1019 {
1020 case VIEW_NODE:
1021 case ENABLE_NODE:
1022 /* Nothing to do. */
1023 break;
1024 case CONFIG_NODE:
1025 case INTERFACE_NODE:
1026 case ZEBRA_NODE:
1027 case RIP_NODE:
1028 case RIPNG_NODE:
1029 case BGP_NODE:
1030 case RMAP_NODE:
1031 case OSPF_NODE:
1032 case OSPF6_NODE:
1033 case KEYCHAIN_NODE:
1034 case KEYCHAIN_KEY_NODE:
1035 case MASC_NODE:
1036 case VTY_NODE:
1037 vty_config_unlock (vty);
1038 vty->node = ENABLE_NODE;
1039 break;
1040 default:
1041 /* Unknown node, we have to ignore it. */
1042 break;
1043 }
1044 vty_prompt (vty);
1045
1046 /* Set history pointer to the latest one. */
1047 vty->hp = vty->hindex;
1048}
1049
1050/* Add current command line to the history buffer. */
1051static void
1052vty_hist_add (struct vty *vty)
1053{
1054 int index;
1055
1056 if (vty->length == 0)
1057 return;
1058
1059 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1060
1061 /* Ignore the same string as previous one. */
1062 if (vty->hist[index])
1063 if (strcmp (vty->buf, vty->hist[index]) == 0)
1064 {
1065 vty->hp = vty->hindex;
1066 return;
1067 }
1068
1069 /* Insert history entry. */
1070 if (vty->hist[vty->hindex])
1071 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1072 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1073
1074 /* History index rotation. */
1075 vty->hindex++;
1076 if (vty->hindex == VTY_MAXHIST)
1077 vty->hindex = 0;
1078
1079 vty->hp = vty->hindex;
1080}
1081
1082/* #define TELNET_OPTION_DEBUG */
1083
1084/* Get telnet window size. */
1085static int
1086vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1087{
1088#ifdef TELNET_OPTION_DEBUG
1089 int i;
1090
1091 for (i = 0; i < nbytes; i++)
1092 {
1093 switch (buf[i])
1094 {
1095 case IAC:
1096 vty_out (vty, "IAC ");
1097 break;
1098 case WILL:
1099 vty_out (vty, "WILL ");
1100 break;
1101 case WONT:
1102 vty_out (vty, "WONT ");
1103 break;
1104 case DO:
1105 vty_out (vty, "DO ");
1106 break;
1107 case DONT:
1108 vty_out (vty, "DONT ");
1109 break;
1110 case SB:
1111 vty_out (vty, "SB ");
1112 break;
1113 case SE:
1114 vty_out (vty, "SE ");
1115 break;
1116 case TELOPT_ECHO:
1117 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1118 break;
1119 case TELOPT_SGA:
1120 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1121 break;
1122 case TELOPT_NAWS:
1123 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1124 break;
1125 default:
1126 vty_out (vty, "%x ", buf[i]);
1127 break;
1128 }
1129 }
1130 vty_out (vty, "%s", VTY_NEWLINE);
1131
1132#endif /* TELNET_OPTION_DEBUG */
1133
1134 switch (buf[0])
1135 {
1136 case SB:
1137 buffer_reset(vty->sb_buffer);
1138 vty->iac_sb_in_progress = 1;
1139 return 0;
1140 break;
1141 case SE:
1142 {
paul5b8c1b02003-10-15 23:08:55 +00001143 char *buffer;
1144 int length;
paul718e3742002-12-13 20:15:29 +00001145
1146 if (!vty->iac_sb_in_progress)
1147 return 0;
1148
paul5b8c1b02003-10-15 23:08:55 +00001149 buffer = (char *)vty->sb_buffer->head->data;
1150 length = vty->sb_buffer->length;
1151
1152 if (buffer == NULL)
1153 return 0;
1154
paul718e3742002-12-13 20:15:29 +00001155 if (buffer[0] == '\0')
1156 {
1157 vty->iac_sb_in_progress = 0;
1158 return 0;
1159 }
1160 switch (buffer[0])
1161 {
1162 case TELOPT_NAWS:
1163 if (length < 5)
1164 break;
1165 vty->width = buffer[2];
1166 vty->height = vty->lines >= 0 ? vty->lines : buffer[4];
1167 break;
1168 }
1169 vty->iac_sb_in_progress = 0;
1170 return 0;
1171 break;
1172 }
1173 default:
1174 break;
1175 }
1176 return 1;
1177}
1178
1179/* Execute current command line. */
1180static int
1181vty_execute (struct vty *vty)
1182{
1183 int ret;
1184
1185 ret = CMD_SUCCESS;
1186
1187 switch (vty->node)
1188 {
1189 case AUTH_NODE:
1190 case AUTH_ENABLE_NODE:
1191 vty_auth (vty, vty->buf);
1192 break;
1193 default:
1194 ret = vty_command (vty, vty->buf);
1195 if (vty->type == VTY_TERM)
1196 vty_hist_add (vty);
1197 break;
1198 }
1199
1200 /* Clear command line buffer. */
1201 vty->cp = vty->length = 0;
1202 vty_clear_buf (vty);
1203
1204 if (vty->status != VTY_CLOSE
1205 && vty->status != VTY_START
1206 && vty->status != VTY_CONTINUE)
1207 vty_prompt (vty);
1208
1209 return ret;
1210}
1211
1212#define CONTROL(X) ((X) - '@')
1213#define VTY_NORMAL 0
1214#define VTY_PRE_ESCAPE 1
1215#define VTY_ESCAPE 2
1216
1217/* Escape character command map. */
1218static void
1219vty_escape_map (unsigned char c, struct vty *vty)
1220{
1221 switch (c)
1222 {
1223 case ('A'):
1224 vty_previous_line (vty);
1225 break;
1226 case ('B'):
1227 vty_next_line (vty);
1228 break;
1229 case ('C'):
1230 vty_forward_char (vty);
1231 break;
1232 case ('D'):
1233 vty_backward_char (vty);
1234 break;
1235 default:
1236 break;
1237 }
1238
1239 /* Go back to normal mode. */
1240 vty->escape = VTY_NORMAL;
1241}
1242
1243/* Quit print out to the buffer. */
1244static void
1245vty_buffer_reset (struct vty *vty)
1246{
1247 buffer_reset (vty->obuf);
1248 vty_prompt (vty);
1249 vty_redraw_line (vty);
1250}
1251
1252/* Read data via vty socket. */
1253static int
1254vty_read (struct thread *thread)
1255{
1256 int i;
paul718e3742002-12-13 20:15:29 +00001257 int nbytes;
1258 unsigned char buf[VTY_READ_BUFSIZ];
1259
1260 int vty_sock = THREAD_FD (thread);
1261 struct vty *vty = THREAD_ARG (thread);
1262 vty->t_read = NULL;
1263
1264 /* Read raw data from socket */
1265 nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ);
1266 if (nbytes <= 0)
1267 vty->status = VTY_CLOSE;
1268
1269 for (i = 0; i < nbytes; i++)
1270 {
1271 if (buf[i] == IAC)
1272 {
1273 if (!vty->iac)
1274 {
1275 vty->iac = 1;
1276 continue;
1277 }
1278 else
1279 {
1280 vty->iac = 0;
1281 }
1282 }
1283
1284 if (vty->iac_sb_in_progress && !vty->iac)
1285 {
1286 buffer_putc(vty->sb_buffer, buf[i]);
1287 continue;
1288 }
1289
1290 if (vty->iac)
1291 {
1292 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001293 int ret = 0;
1294 if (vty->iac_sb_in_progress)
1295 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001296 vty->iac = 0;
1297 i += ret;
1298 continue;
1299 }
paul5b8c1b02003-10-15 23:08:55 +00001300
paul718e3742002-12-13 20:15:29 +00001301
1302 if (vty->status == VTY_MORE)
1303 {
1304 switch (buf[i])
1305 {
1306 case CONTROL('C'):
1307 case 'q':
1308 case 'Q':
1309 if (vty->output_func)
1310 (*vty->output_func) (vty, 1);
1311 vty_buffer_reset (vty);
1312 break;
1313#if 0 /* More line does not work for "show ip bgp". */
1314 case '\n':
1315 case '\r':
1316 vty->status = VTY_MORELINE;
1317 break;
1318#endif
1319 default:
1320 if (vty->output_func)
1321 (*vty->output_func) (vty, 0);
1322 break;
1323 }
1324 continue;
1325 }
1326
1327 /* Escape character. */
1328 if (vty->escape == VTY_ESCAPE)
1329 {
1330 vty_escape_map (buf[i], vty);
1331 continue;
1332 }
1333
1334 /* Pre-escape status. */
1335 if (vty->escape == VTY_PRE_ESCAPE)
1336 {
1337 switch (buf[i])
1338 {
1339 case '[':
1340 vty->escape = VTY_ESCAPE;
1341 break;
1342 case 'b':
1343 vty_backward_word (vty);
1344 vty->escape = VTY_NORMAL;
1345 break;
1346 case 'f':
1347 vty_forward_word (vty);
1348 vty->escape = VTY_NORMAL;
1349 break;
1350 case 'd':
1351 vty_forward_kill_word (vty);
1352 vty->escape = VTY_NORMAL;
1353 break;
1354 case CONTROL('H'):
1355 case 0x7f:
1356 vty_backward_kill_word (vty);
1357 vty->escape = VTY_NORMAL;
1358 break;
1359 default:
1360 vty->escape = VTY_NORMAL;
1361 break;
1362 }
1363 continue;
1364 }
1365
1366 switch (buf[i])
1367 {
1368 case CONTROL('A'):
1369 vty_beginning_of_line (vty);
1370 break;
1371 case CONTROL('B'):
1372 vty_backward_char (vty);
1373 break;
1374 case CONTROL('C'):
1375 vty_stop_input (vty);
1376 break;
1377 case CONTROL('D'):
1378 vty_delete_char (vty);
1379 break;
1380 case CONTROL('E'):
1381 vty_end_of_line (vty);
1382 break;
1383 case CONTROL('F'):
1384 vty_forward_char (vty);
1385 break;
1386 case CONTROL('H'):
1387 case 0x7f:
1388 vty_delete_backward_char (vty);
1389 break;
1390 case CONTROL('K'):
1391 vty_kill_line (vty);
1392 break;
1393 case CONTROL('N'):
1394 vty_next_line (vty);
1395 break;
1396 case CONTROL('P'):
1397 vty_previous_line (vty);
1398 break;
1399 case CONTROL('T'):
1400 vty_transpose_chars (vty);
1401 break;
1402 case CONTROL('U'):
1403 vty_kill_line_from_beginning (vty);
1404 break;
1405 case CONTROL('W'):
1406 vty_backward_kill_word (vty);
1407 break;
1408 case CONTROL('Z'):
1409 vty_end_config (vty);
1410 break;
1411 case '\n':
1412 case '\r':
1413 vty_out (vty, "%s", VTY_NEWLINE);
1414 vty_execute (vty);
1415 break;
1416 case '\t':
1417 vty_complete_command (vty);
1418 break;
1419 case '?':
1420 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1421 vty_self_insert (vty, buf[i]);
1422 else
1423 vty_describe_command (vty);
1424 break;
1425 case '\033':
1426 if (i + 1 < nbytes && buf[i + 1] == '[')
1427 {
1428 vty->escape = VTY_ESCAPE;
1429 i++;
1430 }
1431 else
1432 vty->escape = VTY_PRE_ESCAPE;
1433 break;
1434 default:
1435 if (buf[i] > 31 && buf[i] < 127)
1436 vty_self_insert (vty, buf[i]);
1437 break;
1438 }
1439 }
1440
1441 /* Check status. */
1442 if (vty->status == VTY_CLOSE)
1443 vty_close (vty);
1444 else
1445 {
1446 vty_event (VTY_WRITE, vty_sock, vty);
1447 vty_event (VTY_READ, vty_sock, vty);
1448 }
1449 return 0;
1450}
1451
1452/* Flush buffer to the vty. */
1453static int
1454vty_flush (struct thread *thread)
1455{
1456 int erase;
1457 int dont_more;
1458 int vty_sock = THREAD_FD (thread);
1459 struct vty *vty = THREAD_ARG (thread);
1460 vty->t_write = NULL;
1461
1462 /* Tempolary disable read thread. */
1463 if (vty->lines == 0)
1464 if (vty->t_read)
1465 {
1466 thread_cancel (vty->t_read);
1467 vty->t_read = NULL;
1468 }
1469
1470 /* Function execution continue. */
1471 if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
1472 {
1473 if (vty->status == VTY_CONTINUE)
1474 erase = 1;
1475 else
1476 erase = 0;
1477
1478 if (vty->output_func == NULL)
1479 dont_more = 1;
1480 else
1481 dont_more = 0;
1482
1483 if (vty->lines == 0)
1484 {
1485 erase = 0;
1486 dont_more = 1;
1487 }
1488
1489 buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
1490
1491 if (vty->status == VTY_CLOSE)
1492 {
1493 vty_close (vty);
1494 return 0;
1495 }
1496
1497 if (vty->output_func == NULL)
1498 {
1499 vty->status = VTY_NORMAL;
1500 vty_prompt (vty);
1501 vty_event (VTY_WRITE, vty_sock, vty);
1502 }
1503 else
1504 vty->status = VTY_MORE;
1505
1506 if (vty->lines == 0)
1507 {
1508 if (vty->output_func == NULL)
1509 vty_event (VTY_READ, vty_sock, vty);
1510 else
1511 {
1512 if (vty->output_func)
1513 (*vty->output_func) (vty, 0);
1514 vty_event (VTY_WRITE, vty_sock, vty);
1515 }
1516 }
1517 }
1518 else
1519 {
1520 if (vty->status == VTY_MORE || vty->status == VTY_MORELINE)
1521 erase = 1;
1522 else
1523 erase = 0;
1524
1525 if (vty->lines == 0)
1526 buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
1527 else if (vty->status == VTY_MORELINE)
1528 buffer_flush_window (vty->obuf, vty->fd, vty->width, 1, erase, 0);
1529 else
1530 buffer_flush_window (vty->obuf, vty->fd, vty->width,
1531 vty->lines >= 0 ? vty->lines : vty->height,
1532 erase, 0);
1533
1534 if (buffer_empty (vty->obuf))
1535 {
1536 if (vty->status == VTY_CLOSE)
1537 vty_close (vty);
1538 else
1539 {
1540 vty->status = VTY_NORMAL;
1541
1542 if (vty->lines == 0)
1543 vty_event (VTY_READ, vty_sock, vty);
1544 }
1545 }
1546 else
1547 {
1548 vty->status = VTY_MORE;
1549
1550 if (vty->lines == 0)
1551 vty_event (VTY_WRITE, vty_sock, vty);
1552 }
1553 }
1554
1555 return 0;
1556}
1557
1558/* Create new vty structure. */
1559struct vty *
1560vty_create (int vty_sock, union sockunion *su)
1561{
1562 struct vty *vty;
1563
1564 /* Allocate new vty structure and set up default values. */
1565 vty = vty_new ();
1566 vty->fd = vty_sock;
1567 vty->type = VTY_TERM;
1568 vty->address = sockunion_su2str (su);
1569 if (no_password_check)
1570 {
1571 if (host.advanced)
1572 vty->node = ENABLE_NODE;
1573 else
1574 vty->node = VIEW_NODE;
1575 }
1576 else
1577 vty->node = AUTH_NODE;
1578 vty->fail = 0;
1579 vty->cp = 0;
1580 vty_clear_buf (vty);
1581 vty->length = 0;
1582 memset (vty->hist, 0, sizeof (vty->hist));
1583 vty->hp = 0;
1584 vty->hindex = 0;
1585 vector_set_index (vtyvec, vty_sock, vty);
1586 vty->status = VTY_NORMAL;
1587 vty->v_timeout = vty_timeout_val;
1588 if (host.lines >= 0)
1589 vty->lines = host.lines;
1590 else
1591 vty->lines = -1;
1592 vty->iac = 0;
1593 vty->iac_sb_in_progress = 0;
1594 vty->sb_buffer = buffer_new (1024);
1595
1596 if (! no_password_check)
1597 {
1598 /* Vty is not available if password isn't set. */
1599 if (host.password == NULL && host.password_encrypt == NULL)
1600 {
1601 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1602 vty->status = VTY_CLOSE;
1603 vty_close (vty);
1604 return NULL;
1605 }
1606 }
1607
1608 /* Say hello to the world. */
1609 vty_hello (vty);
1610 if (! no_password_check)
1611 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1612
1613 /* Setting up terminal. */
1614 vty_will_echo (vty);
1615 vty_will_suppress_go_ahead (vty);
1616
1617 vty_dont_linemode (vty);
1618 vty_do_window_size (vty);
1619 /* vty_dont_lflow_ahead (vty); */
1620
1621 vty_prompt (vty);
1622
1623 /* Add read/write thread. */
1624 vty_event (VTY_WRITE, vty_sock, vty);
1625 vty_event (VTY_READ, vty_sock, vty);
1626
1627 return vty;
1628}
1629
1630/* Accept connection from the network. */
1631static int
1632vty_accept (struct thread *thread)
1633{
1634 int vty_sock;
1635 struct vty *vty;
1636 union sockunion su;
1637 int ret;
1638 unsigned int on;
1639 int accept_sock;
1640 struct prefix *p = NULL;
1641 struct access_list *acl = NULL;
1642
1643 accept_sock = THREAD_FD (thread);
1644
1645 /* We continue hearing vty socket. */
1646 vty_event (VTY_SERV, accept_sock, NULL);
1647
1648 memset (&su, 0, sizeof (union sockunion));
1649
1650 /* We can handle IPv4 or IPv6 socket. */
1651 vty_sock = sockunion_accept (accept_sock, &su);
1652 if (vty_sock < 0)
1653 {
1654 zlog_warn ("can't accept vty socket : %s", strerror (errno));
1655 return -1;
1656 }
1657
1658 p = sockunion2hostprefix (&su);
1659
1660 /* VTY's accesslist apply. */
1661 if (p->family == AF_INET && vty_accesslist_name)
1662 {
1663 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1664 (access_list_apply (acl, p) == FILTER_DENY))
1665 {
1666 char *buf;
1667 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1668 (buf = sockunion_su2str (&su)));
1669 free (buf);
1670 close (vty_sock);
1671
1672 /* continue accepting connections */
1673 vty_event (VTY_SERV, accept_sock, NULL);
1674
1675 prefix_free (p);
1676
1677 return 0;
1678 }
1679 }
1680
1681#ifdef HAVE_IPV6
1682 /* VTY's ipv6 accesslist apply. */
1683 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1684 {
1685 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1686 (access_list_apply (acl, p) == FILTER_DENY))
1687 {
1688 char *buf;
1689 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1690 (buf = sockunion_su2str (&su)));
1691 free (buf);
1692 close (vty_sock);
1693
1694 /* continue accepting connections */
1695 vty_event (VTY_SERV, accept_sock, NULL);
1696
1697 prefix_free (p);
1698
1699 return 0;
1700 }
1701 }
1702#endif /* HAVE_IPV6 */
1703
1704 prefix_free (p);
1705
1706 on = 1;
1707 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1708 (char *) &on, sizeof (on));
1709 if (ret < 0)
1710 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
1711 strerror (errno));
1712
1713 vty = vty_create (vty_sock, &su);
1714
1715 return 0;
1716}
1717
1718#if defined(HAVE_IPV6) && !defined(NRL)
1719void
1720vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1721{
1722 int ret;
1723 struct addrinfo req;
1724 struct addrinfo *ainfo;
1725 struct addrinfo *ainfo_save;
1726 int sock;
1727 char port_str[BUFSIZ];
1728
1729 memset (&req, 0, sizeof (struct addrinfo));
1730 req.ai_flags = AI_PASSIVE;
1731 req.ai_family = AF_UNSPEC;
1732 req.ai_socktype = SOCK_STREAM;
1733 sprintf (port_str, "%d", port);
1734 port_str[sizeof (port_str) - 1] = '\0';
1735
1736 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1737
1738 if (ret != 0)
1739 {
1740 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1741 exit (1);
1742 }
1743
1744 ainfo_save = ainfo;
1745
1746 do
1747 {
1748 if (ainfo->ai_family != AF_INET
1749#ifdef HAVE_IPV6
1750 && ainfo->ai_family != AF_INET6
1751#endif /* HAVE_IPV6 */
1752 )
1753 continue;
1754
1755 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1756 if (sock < 0)
1757 continue;
1758
1759 sockopt_reuseaddr (sock);
1760 sockopt_reuseport (sock);
1761
1762 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1763 if (ret < 0)
1764 {
1765 close (sock); /* Avoid sd leak. */
1766 continue;
1767 }
1768
1769 ret = listen (sock, 3);
1770 if (ret < 0)
1771 {
1772 close (sock); /* Avoid sd leak. */
1773 continue;
1774 }
1775
1776 vty_event (VTY_SERV, sock, NULL);
1777 }
1778 while ((ainfo = ainfo->ai_next) != NULL);
1779
1780 freeaddrinfo (ainfo_save);
1781}
1782#endif /* HAVE_IPV6 && ! NRL */
1783
1784/* Make vty server socket. */
1785void
paul29db05b2003-05-08 20:10:22 +00001786vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001787{
1788 int ret;
1789 union sockunion su;
1790 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001791 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001792
1793 memset (&su, 0, sizeof (union sockunion));
1794 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001795 if(addr)
1796 switch(family)
1797 {
1798 case AF_INET:
1799 naddr=&su.sin.sin_addr;
1800#ifdef HAVE_IPV6
1801 case AF_INET6:
1802 naddr=&su.sin6.sin6_addr;
1803#endif
1804 }
1805
1806 if(naddr)
1807 switch(inet_pton(family,addr,naddr))
1808 {
1809 case -1:
1810 zlog_err("bad address %s",addr);
1811 naddr=NULL;
1812 break;
1813 case 0:
1814 zlog_err("error translating address %s: %s",addr,strerror(errno));
1815 naddr=NULL;
1816 }
paul718e3742002-12-13 20:15:29 +00001817
1818 /* Make new socket. */
1819 accept_sock = sockunion_stream_socket (&su);
1820 if (accept_sock < 0)
1821 return;
1822
1823 /* This is server, so reuse address. */
1824 sockopt_reuseaddr (accept_sock);
1825 sockopt_reuseport (accept_sock);
1826
1827 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001828 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001829 if (ret < 0)
1830 {
paul29db05b2003-05-08 20:10:22 +00001831 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001832 close (accept_sock); /* Avoid sd leak. */
1833 return;
1834 }
1835
1836 /* Listen socket under queue 3. */
1837 ret = listen (accept_sock, 3);
1838 if (ret < 0)
1839 {
1840 zlog (NULL, LOG_WARNING, "can't listen socket");
1841 close (accept_sock); /* Avoid sd leak. */
1842 return;
1843 }
1844
1845 /* Add vty server event. */
1846 vty_event (VTY_SERV, accept_sock, NULL);
1847}
1848
1849#ifdef VTYSH
1850/* For sockaddr_un. */
1851#include <sys/un.h>
1852
1853/* VTY shell UNIX domain socket. */
1854void
1855vty_serv_un (char *path)
1856{
1857 int ret;
1858 int sock, len;
1859 struct sockaddr_un serv;
1860 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00001861 struct zprivs_ids_t ids;
1862
paul718e3742002-12-13 20:15:29 +00001863 /* First of all, unlink existing socket */
1864 unlink (path);
1865
1866 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00001867 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00001868
1869 /* Make UNIX domain socket. */
1870 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1871 if (sock < 0)
1872 {
1873 perror ("sock");
1874 return;
1875 }
1876
1877 /* Make server socket. */
1878 memset (&serv, 0, sizeof (struct sockaddr_un));
1879 serv.sun_family = AF_UNIX;
1880 strncpy (serv.sun_path, path, strlen (path));
1881#ifdef HAVE_SUN_LEN
1882 len = serv.sun_len = SUN_LEN(&serv);
1883#else
1884 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1885#endif /* HAVE_SUN_LEN */
1886
1887 ret = bind (sock, (struct sockaddr *) &serv, len);
1888 if (ret < 0)
1889 {
1890 perror ("bind");
1891 close (sock); /* Avoid sd leak. */
1892 return;
1893 }
1894
1895 ret = listen (sock, 5);
1896 if (ret < 0)
1897 {
1898 perror ("listen");
1899 close (sock); /* Avoid sd leak. */
1900 return;
1901 }
1902
1903 umask (old_mask);
1904
pauledd7c242003-06-04 13:59:38 +00001905 zprivs_get_ids(&ids);
1906
1907 if (ids.gid_vty > 0)
1908 {
1909 /* set group of socket */
1910 if ( chown (path, -1, ids.gid_vty) )
1911 {
1912 zlog_err ("vty_serv_un: could chown socket, %s",
1913 strerror (errno) );
1914 }
1915 }
1916
paul718e3742002-12-13 20:15:29 +00001917 vty_event (VTYSH_SERV, sock, NULL);
1918}
1919
1920/* #define VTYSH_DEBUG 1 */
1921
1922static int
1923vtysh_accept (struct thread *thread)
1924{
1925 int accept_sock;
1926 int sock;
1927 int client_len;
1928 struct sockaddr_un client;
1929 struct vty *vty;
1930
1931 accept_sock = THREAD_FD (thread);
1932
1933 vty_event (VTYSH_SERV, accept_sock, NULL);
1934
1935 memset (&client, 0, sizeof (struct sockaddr_un));
1936 client_len = sizeof (struct sockaddr_un);
1937
1938 sock = accept (accept_sock, (struct sockaddr *) &client, &client_len);
1939
1940 if (sock < 0)
1941 {
1942 zlog_warn ("can't accept vty socket : %s", strerror (errno));
1943 return -1;
1944 }
1945
1946#ifdef VTYSH_DEBUG
1947 printf ("VTY shell accept\n");
1948#endif /* VTYSH_DEBUG */
1949
1950 vty = vty_new ();
1951 vty->fd = sock;
1952 vty->type = VTY_SHELL_SERV;
1953 vty->node = VIEW_NODE;
1954
1955 vty_event (VTYSH_READ, sock, vty);
1956
1957 return 0;
1958}
1959
1960static int
1961vtysh_read (struct thread *thread)
1962{
1963 int ret;
1964 int sock;
1965 int nbytes;
1966 struct vty *vty;
1967 unsigned char buf[VTY_READ_BUFSIZ];
1968 u_char header[4] = {0, 0, 0, 0};
1969
1970 sock = THREAD_FD (thread);
1971 vty = THREAD_ARG (thread);
1972 vty->t_read = NULL;
1973
1974 nbytes = read (sock, buf, VTY_READ_BUFSIZ);
1975 if (nbytes <= 0)
1976 {
1977 vty_close (vty);
1978#ifdef VTYSH_DEBUG
1979 printf ("close vtysh\n");
1980#endif /* VTYSH_DEBUG */
1981 return 0;
1982 }
1983
1984#ifdef VTYSH_DEBUG
1985 printf ("line: %s\n", buf);
1986#endif /* VTYSH_DEBUG */
1987
1988 vty_ensure (vty, nbytes);
1989 memcpy (vty->buf, buf, nbytes);
1990
1991 /* Pass this line to parser. */
1992 ret = vty_execute (vty);
1993
1994 vty_clear_buf (vty);
1995
1996 /* Return result. */
1997#ifdef VTYSH_DEBUG
1998 printf ("result: %d\n", ret);
1999 printf ("vtysh node: %d\n", vty->node);
2000#endif /* VTYSH_DEBUG */
2001
2002 header[3] = ret;
2003 write (vty->fd, header, 4);
2004
2005 vty_event (VTYSH_READ, sock, vty);
2006
2007 return 0;
2008}
2009#endif /* VTYSH */
2010
2011/* Determine address family to bind. */
2012void
paul29db05b2003-05-08 20:10:22 +00002013vty_serv_sock (const char *addr, unsigned short port, char *path)
paul718e3742002-12-13 20:15:29 +00002014{
2015 /* If port is set to 0, do not listen on TCP/IP at all! */
2016 if (port)
2017 {
2018
2019#ifdef HAVE_IPV6
2020#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002021 vty_serv_sock_family (addr, port, AF_INET);
2022 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002023#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002024 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002025#endif /* NRL*/
2026#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002027 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002028#endif /* HAVE_IPV6 */
2029 }
2030
2031#ifdef VTYSH
2032 vty_serv_un (path);
2033#endif /* VTYSH */
2034}
2035
2036/* Close vty interface. */
2037void
2038vty_close (struct vty *vty)
2039{
2040 int i;
2041
2042 /* Cancel threads.*/
2043 if (vty->t_read)
2044 thread_cancel (vty->t_read);
2045 if (vty->t_write)
2046 thread_cancel (vty->t_write);
2047 if (vty->t_timeout)
2048 thread_cancel (vty->t_timeout);
2049 if (vty->t_output)
2050 thread_cancel (vty->t_output);
2051
2052 /* Flush buffer. */
2053 if (! buffer_empty (vty->obuf))
2054 buffer_flush_all (vty->obuf, vty->fd);
2055
2056 /* Free input buffer. */
2057 buffer_free (vty->obuf);
2058
2059 /* Free SB buffer. */
2060 if (vty->sb_buffer)
2061 buffer_free (vty->sb_buffer);
2062
2063 /* Free command history. */
2064 for (i = 0; i < VTY_MAXHIST; i++)
2065 if (vty->hist[i])
2066 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2067
2068 /* Unset vector. */
2069 vector_unset (vtyvec, vty->fd);
2070
2071 /* Close socket. */
2072 if (vty->fd > 0)
2073 close (vty->fd);
2074
2075 if (vty->address)
2076 XFREE (0, vty->address);
2077 if (vty->buf)
2078 XFREE (MTYPE_VTY, vty->buf);
2079
2080 /* Check configure. */
2081 vty_config_unlock (vty);
2082
2083 /* OK free vty. */
2084 XFREE (MTYPE_VTY, vty);
2085}
2086
2087/* When time out occur output message then close connection. */
2088static int
2089vty_timeout (struct thread *thread)
2090{
2091 struct vty *vty;
2092
2093 vty = THREAD_ARG (thread);
2094 vty->t_timeout = NULL;
2095 vty->v_timeout = 0;
2096
2097 /* Clear buffer*/
2098 buffer_reset (vty->obuf);
2099 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2100
2101 /* Close connection. */
2102 vty->status = VTY_CLOSE;
2103 vty_close (vty);
2104
2105 return 0;
2106}
2107
2108/* Read up configuration file from file_name. */
2109static void
2110vty_read_file (FILE *confp)
2111{
2112 int ret;
2113 struct vty *vty;
2114
2115 vty = vty_new ();
2116 vty->fd = 0; /* stdout */
2117 vty->type = VTY_TERM;
2118 vty->node = CONFIG_NODE;
2119
2120 /* Execute configuration file */
2121 ret = config_from_file (vty, confp);
2122
paul7021c422003-07-15 12:52:22 +00002123 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002124 {
2125 switch (ret)
paul7021c422003-07-15 12:52:22 +00002126 {
2127 case CMD_ERR_AMBIGUOUS:
2128 fprintf (stderr, "Ambiguous command.\n");
2129 break;
2130 case CMD_ERR_NO_MATCH:
2131 fprintf (stderr, "There is no such command.\n");
2132 break;
2133 }
paul718e3742002-12-13 20:15:29 +00002134 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2135 vty->buf);
2136 vty_close (vty);
2137 exit (1);
2138 }
2139
2140 vty_close (vty);
2141}
2142
2143FILE *
2144vty_use_backup_config (char *fullpath)
2145{
2146 char *fullpath_sav, *fullpath_tmp;
2147 FILE *ret = NULL;
2148 struct stat buf;
2149 int tmp, sav;
2150 int c;
2151 char buffer[512];
2152
2153 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2154 strcpy (fullpath_sav, fullpath);
2155 strcat (fullpath_sav, CONF_BACKUP_EXT);
2156 if (stat (fullpath_sav, &buf) == -1)
2157 {
2158 free (fullpath_sav);
2159 return NULL;
2160 }
2161
2162 fullpath_tmp = malloc (strlen (fullpath) + 8);
2163 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2164
2165 /* Open file to configuration write. */
2166 tmp = mkstemp (fullpath_tmp);
2167 if (tmp < 0)
2168 {
2169 free (fullpath_sav);
2170 free (fullpath_tmp);
2171 return NULL;
2172 }
2173
2174 sav = open (fullpath_sav, O_RDONLY);
2175 if (sav < 0)
2176 {
2177 free (fullpath_sav);
2178 free (fullpath_tmp);
2179 unlink (fullpath_tmp);
2180 return NULL;
2181 }
2182
2183 while((c = read (sav, buffer, 512)) > 0)
2184 write (tmp, buffer, c);
2185
2186 close (sav);
2187 close (tmp);
2188
2189 if (link (fullpath_tmp, fullpath) == 0)
2190 ret = fopen (fullpath, "r");
2191
2192 unlink (fullpath_tmp);
2193
2194 free (fullpath_sav);
2195 free (fullpath_tmp);
2196 return fopen (fullpath, "r");
2197}
2198
2199/* Read up configuration file from file_name. */
2200void
2201vty_read_config (char *config_file,
2202 char *config_current_dir,
2203 char *config_default_dir)
2204{
2205 char *cwd;
2206 FILE *confp = NULL;
2207 char *fullpath;
2208
2209 /* If -f flag specified. */
2210 if (config_file != NULL)
2211 {
2212 if (! IS_DIRECTORY_SEP (config_file[0]))
2213 {
2214 cwd = getcwd (NULL, MAXPATHLEN);
2215 fullpath = XMALLOC (MTYPE_TMP,
2216 strlen (cwd) + strlen (config_file) + 2);
2217 sprintf (fullpath, "%s/%s", cwd, config_file);
2218 }
2219 else
2220 fullpath = config_file;
2221
2222 confp = fopen (fullpath, "r");
2223
2224 if (confp == NULL)
2225 {
2226 confp = vty_use_backup_config (fullpath);
2227 if (confp)
2228 fprintf (stderr, "WARNING: using backup configuration file!\n");
2229 else
2230 {
2231 fprintf (stderr, "can't open configuration file [%s]\n",
2232 config_file);
2233 exit(1);
2234 }
2235 }
2236 }
2237 else
2238 {
2239 /* Relative path configuration file open. */
2240 if (config_current_dir)
2241 {
2242 confp = fopen (config_current_dir, "r");
2243 if (confp == NULL)
2244 {
2245 confp = vty_use_backup_config (config_current_dir);
2246 if (confp)
2247 fprintf (stderr, "WARNING: using backup configuration file!\n");
2248 }
2249 }
2250
2251 /* If there is no relative path exists, open system default file. */
2252 if (confp == NULL)
2253 {
2254#ifdef VTYSH
2255 int ret;
2256 struct stat conf_stat;
2257
2258 /* !!!!PLEASE LEAVE!!!!
2259 This is NEEDED for use with vtysh -b, or else you can get
2260 a real configuration food fight with a lot garbage in the
2261 merged configuration file it creates coming from the per
2262 daemon configuration files. This also allows the daemons
2263 to start if there default configuration file is not
2264 present or ignore them, as needed when using vtysh -b to
2265 configure the daemons at boot - MAG */
2266
2267 /* Stat for vtysh Zebra.conf, if found startup and wait for
2268 boot configuration */
2269
2270 if ( strstr(config_default_dir, "vtysh") == NULL)
2271 {
2272 ret = stat (integrate_default, &conf_stat);
2273 if (ret >= 0)
2274 {
2275 return;
2276 }
2277 }
2278#endif /* VTYSH */
2279
2280 confp = fopen (config_default_dir, "r");
2281 if (confp == NULL)
2282 {
2283 confp = vty_use_backup_config (config_default_dir);
2284 if (confp)
2285 {
2286 fprintf (stderr, "WARNING: using backup configuration file!\n");
2287 fullpath = config_default_dir;
2288 }
2289 else
2290 {
2291 fprintf (stderr, "can't open configuration file [%s]\n",
2292 config_default_dir);
2293 exit (1);
2294 }
2295 }
2296 else
2297 fullpath = config_default_dir;
2298 }
2299 else
2300 {
2301 /* Rleative path configuration file. */
2302 cwd = getcwd (NULL, MAXPATHLEN);
2303 fullpath = XMALLOC (MTYPE_TMP,
2304 strlen (cwd) + strlen (config_current_dir) + 2);
2305 sprintf (fullpath, "%s/%s", cwd, config_current_dir);
2306 }
2307 }
2308 vty_read_file (confp);
2309
2310 fclose (confp);
2311
2312 host_config_set (fullpath);
2313}
2314
2315/* Small utility function which output log to the VTY. */
2316void
2317vty_log (const char *proto_str, const char *format, va_list va)
2318{
2319 int i;
2320 struct vty *vty;
2321
2322 for (i = 0; i < vector_max (vtyvec); i++)
2323 if ((vty = vector_slot (vtyvec, i)) != NULL)
2324 if (vty->monitor)
2325 vty_log_out (vty, proto_str, format, va);
2326}
2327
2328int
2329vty_config_lock (struct vty *vty)
2330{
2331 if (vty_config == 0)
2332 {
2333 vty->config = 1;
2334 vty_config = 1;
2335 }
2336 return vty->config;
2337}
2338
2339int
2340vty_config_unlock (struct vty *vty)
2341{
2342 if (vty_config == 1 && vty->config == 1)
2343 {
2344 vty->config = 0;
2345 vty_config = 0;
2346 }
2347 return vty->config;
2348}
2349
2350/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002351static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002352
2353static void
2354vty_event (enum event event, int sock, struct vty *vty)
2355{
2356 struct thread *vty_serv_thread;
2357
2358 switch (event)
2359 {
2360 case VTY_SERV:
2361 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2362 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2363 break;
2364#ifdef VTYSH
2365 case VTYSH_SERV:
2366 thread_add_read (master, vtysh_accept, vty, sock);
2367 break;
2368 case VTYSH_READ:
2369 thread_add_read (master, vtysh_read, vty, sock);
2370 break;
2371#endif /* VTYSH */
2372 case VTY_READ:
2373 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2374
2375 /* Time out treatment. */
2376 if (vty->v_timeout)
2377 {
2378 if (vty->t_timeout)
2379 thread_cancel (vty->t_timeout);
2380 vty->t_timeout =
2381 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2382 }
2383 break;
2384 case VTY_WRITE:
2385 if (! vty->t_write)
2386 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2387 break;
2388 case VTY_TIMEOUT_RESET:
2389 if (vty->t_timeout)
2390 {
2391 thread_cancel (vty->t_timeout);
2392 vty->t_timeout = NULL;
2393 }
2394 if (vty->v_timeout)
2395 {
2396 vty->t_timeout =
2397 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2398 }
2399 break;
2400 }
2401}
2402
2403DEFUN (config_who,
2404 config_who_cmd,
2405 "who",
2406 "Display who is on vty\n")
2407{
2408 int i;
2409 struct vty *v;
2410
2411 for (i = 0; i < vector_max (vtyvec); i++)
2412 if ((v = vector_slot (vtyvec, i)) != NULL)
2413 vty_out (vty, "%svty[%d] connected from %s.%s",
2414 v->config ? "*" : " ",
2415 i, v->address, VTY_NEWLINE);
2416 return CMD_SUCCESS;
2417}
2418
2419/* Move to vty configuration mode. */
2420DEFUN (line_vty,
2421 line_vty_cmd,
2422 "line vty",
2423 "Configure a terminal line\n"
2424 "Virtual terminal\n")
2425{
2426 vty->node = VTY_NODE;
2427 return CMD_SUCCESS;
2428}
2429
2430/* Set time out value. */
2431int
2432exec_timeout (struct vty *vty, char *min_str, char *sec_str)
2433{
2434 unsigned long timeout = 0;
2435
2436 /* min_str and sec_str are already checked by parser. So it must be
2437 all digit string. */
2438 if (min_str)
2439 {
2440 timeout = strtol (min_str, NULL, 10);
2441 timeout *= 60;
2442 }
2443 if (sec_str)
2444 timeout += strtol (sec_str, NULL, 10);
2445
2446 vty_timeout_val = timeout;
2447 vty->v_timeout = timeout;
2448 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2449
2450
2451 return CMD_SUCCESS;
2452}
2453
2454DEFUN (exec_timeout_min,
2455 exec_timeout_min_cmd,
2456 "exec-timeout <0-35791>",
2457 "Set timeout value\n"
2458 "Timeout value in minutes\n")
2459{
2460 return exec_timeout (vty, argv[0], NULL);
2461}
2462
2463DEFUN (exec_timeout_sec,
2464 exec_timeout_sec_cmd,
2465 "exec-timeout <0-35791> <0-2147483>",
2466 "Set the EXEC timeout\n"
2467 "Timeout in minutes\n"
2468 "Timeout in seconds\n")
2469{
2470 return exec_timeout (vty, argv[0], argv[1]);
2471}
2472
2473DEFUN (no_exec_timeout,
2474 no_exec_timeout_cmd,
2475 "no exec-timeout",
2476 NO_STR
2477 "Set the EXEC timeout\n")
2478{
2479 return exec_timeout (vty, NULL, NULL);
2480}
2481
2482/* Set vty access class. */
2483DEFUN (vty_access_class,
2484 vty_access_class_cmd,
2485 "access-class WORD",
2486 "Filter connections based on an IP access list\n"
2487 "IP access list\n")
2488{
2489 if (vty_accesslist_name)
2490 XFREE(MTYPE_VTY, vty_accesslist_name);
2491
2492 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2493
2494 return CMD_SUCCESS;
2495}
2496
2497/* Clear vty access class. */
2498DEFUN (no_vty_access_class,
2499 no_vty_access_class_cmd,
2500 "no access-class [WORD]",
2501 NO_STR
2502 "Filter connections based on an IP access list\n"
2503 "IP access list\n")
2504{
2505 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2506 {
2507 vty_out (vty, "Access-class is not currently applied to vty%s",
2508 VTY_NEWLINE);
2509 return CMD_WARNING;
2510 }
2511
2512 XFREE(MTYPE_VTY, vty_accesslist_name);
2513
2514 vty_accesslist_name = NULL;
2515
2516 return CMD_SUCCESS;
2517}
2518
2519#ifdef HAVE_IPV6
2520/* Set vty access class. */
2521DEFUN (vty_ipv6_access_class,
2522 vty_ipv6_access_class_cmd,
2523 "ipv6 access-class WORD",
2524 IPV6_STR
2525 "Filter connections based on an IP access list\n"
2526 "IPv6 access list\n")
2527{
2528 if (vty_ipv6_accesslist_name)
2529 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2530
2531 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2532
2533 return CMD_SUCCESS;
2534}
2535
2536/* Clear vty access class. */
2537DEFUN (no_vty_ipv6_access_class,
2538 no_vty_ipv6_access_class_cmd,
2539 "no ipv6 access-class [WORD]",
2540 NO_STR
2541 IPV6_STR
2542 "Filter connections based on an IP access list\n"
2543 "IPv6 access list\n")
2544{
2545 if (! vty_ipv6_accesslist_name ||
2546 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2547 {
2548 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2549 VTY_NEWLINE);
2550 return CMD_WARNING;
2551 }
2552
2553 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2554
2555 vty_ipv6_accesslist_name = NULL;
2556
2557 return CMD_SUCCESS;
2558}
2559#endif /* HAVE_IPV6 */
2560
2561/* vty login. */
2562DEFUN (vty_login,
2563 vty_login_cmd,
2564 "login",
2565 "Enable password checking\n")
2566{
2567 no_password_check = 0;
2568 return CMD_SUCCESS;
2569}
2570
2571DEFUN (no_vty_login,
2572 no_vty_login_cmd,
2573 "no login",
2574 NO_STR
2575 "Enable password checking\n")
2576{
2577 no_password_check = 1;
2578 return CMD_SUCCESS;
2579}
2580
2581DEFUN (service_advanced_vty,
2582 service_advanced_vty_cmd,
2583 "service advanced-vty",
2584 "Set up miscellaneous service\n"
2585 "Enable advanced mode vty interface\n")
2586{
2587 host.advanced = 1;
2588 return CMD_SUCCESS;
2589}
2590
2591DEFUN (no_service_advanced_vty,
2592 no_service_advanced_vty_cmd,
2593 "no service advanced-vty",
2594 NO_STR
2595 "Set up miscellaneous service\n"
2596 "Enable advanced mode vty interface\n")
2597{
2598 host.advanced = 0;
2599 return CMD_SUCCESS;
2600}
2601
2602DEFUN (terminal_monitor,
2603 terminal_monitor_cmd,
2604 "terminal monitor",
2605 "Set terminal line parameters\n"
2606 "Copy debug output to the current terminal line\n")
2607{
2608 vty->monitor = 1;
2609 return CMD_SUCCESS;
2610}
2611
2612DEFUN (terminal_no_monitor,
2613 terminal_no_monitor_cmd,
2614 "terminal no monitor",
2615 "Set terminal line parameters\n"
2616 NO_STR
2617 "Copy debug output to the current terminal line\n")
2618{
2619 vty->monitor = 0;
2620 return CMD_SUCCESS;
2621}
2622
2623DEFUN (show_history,
2624 show_history_cmd,
2625 "show history",
2626 SHOW_STR
2627 "Display the session command history\n")
2628{
2629 int index;
2630
2631 for (index = vty->hindex + 1; index != vty->hindex;)
2632 {
2633 if (index == VTY_MAXHIST)
2634 {
2635 index = 0;
2636 continue;
2637 }
2638
2639 if (vty->hist[index] != NULL)
2640 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2641
2642 index++;
2643 }
2644
2645 return CMD_SUCCESS;
2646}
2647
2648/* Display current configuration. */
2649int
2650vty_config_write (struct vty *vty)
2651{
2652 vty_out (vty, "line vty%s", VTY_NEWLINE);
2653
2654 if (vty_accesslist_name)
2655 vty_out (vty, " access-class %s%s",
2656 vty_accesslist_name, VTY_NEWLINE);
2657
2658 if (vty_ipv6_accesslist_name)
2659 vty_out (vty, " ipv6 access-class %s%s",
2660 vty_ipv6_accesslist_name, VTY_NEWLINE);
2661
2662 /* exec-timeout */
2663 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2664 vty_out (vty, " exec-timeout %ld %ld%s",
2665 vty_timeout_val / 60,
2666 vty_timeout_val % 60, VTY_NEWLINE);
2667
2668 /* login */
2669 if (no_password_check)
2670 vty_out (vty, " no login%s", VTY_NEWLINE);
2671
2672 vty_out (vty, "!%s", VTY_NEWLINE);
2673
2674 return CMD_SUCCESS;
2675}
2676
2677struct cmd_node vty_node =
2678{
2679 VTY_NODE,
2680 "%s(config-line)# ",
2681};
2682
2683/* Reset all VTY status. */
2684void
2685vty_reset ()
2686{
2687 int i;
2688 struct vty *vty;
2689 struct thread *vty_serv_thread;
2690
2691 for (i = 0; i < vector_max (vtyvec); i++)
2692 if ((vty = vector_slot (vtyvec, i)) != NULL)
2693 {
2694 buffer_reset (vty->obuf);
2695 vty->status = VTY_CLOSE;
2696 vty_close (vty);
2697 }
2698
2699 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2700 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2701 {
2702 thread_cancel (vty_serv_thread);
2703 vector_slot (Vvty_serv_thread, i) = NULL;
2704 close (i);
2705 }
2706
2707 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2708
2709 if (vty_accesslist_name)
2710 {
2711 XFREE(MTYPE_VTY, vty_accesslist_name);
2712 vty_accesslist_name = NULL;
2713 }
2714
2715 if (vty_ipv6_accesslist_name)
2716 {
2717 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2718 vty_ipv6_accesslist_name = NULL;
2719 }
2720}
2721
2722/* for ospf6d easy temprary reload function */
2723/* vty_reset + close accept socket */
2724void
2725vty_finish ()
2726{
2727 int i;
2728 struct vty *vty;
2729 struct thread *vty_serv_thread;
2730
2731 for (i = 0; i < vector_max (vtyvec); i++)
2732 if ((vty = vector_slot (vtyvec, i)) != NULL)
2733 {
2734 buffer_reset (vty->obuf);
2735 vty->status = VTY_CLOSE;
2736 vty_close (vty);
2737 }
2738
2739 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2740 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2741 {
2742 thread_cancel (vty_serv_thread);
2743 vector_slot (Vvty_serv_thread, i) = NULL;
2744 close (i);
2745 }
2746
2747 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2748
2749 if (vty_accesslist_name)
2750 {
2751 XFREE(MTYPE_VTY, vty_accesslist_name);
2752 vty_accesslist_name = NULL;
2753 }
2754
2755 if (vty_ipv6_accesslist_name)
2756 {
2757 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2758 vty_ipv6_accesslist_name = NULL;
2759 }
2760}
2761
2762void
2763vty_save_cwd ()
2764{
paul79ad2792003-10-15 22:09:28 +00002765 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002766
paul79ad2792003-10-15 22:09:28 +00002767 cwd[0] = getcwd (cwd, MAXPATHLEN);
2768
2769 if (!cwd)
2770 {
2771 chdir (SYSCONFDIR);
2772 cwd[0] = getcwd (cwd, MAXPATHLEN);
2773 }
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}