blob: edfd99dd8d737a7c43e1cab1fd9bee96e472271c [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;
paule9372532003-10-26 21:36:07 +00001294 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001295 vty->iac = 0;
1296 i += ret;
1297 continue;
1298 }
paul5b8c1b02003-10-15 23:08:55 +00001299
paul718e3742002-12-13 20:15:29 +00001300
1301 if (vty->status == VTY_MORE)
1302 {
1303 switch (buf[i])
1304 {
1305 case CONTROL('C'):
1306 case 'q':
1307 case 'Q':
1308 if (vty->output_func)
1309 (*vty->output_func) (vty, 1);
1310 vty_buffer_reset (vty);
1311 break;
1312#if 0 /* More line does not work for "show ip bgp". */
1313 case '\n':
1314 case '\r':
1315 vty->status = VTY_MORELINE;
1316 break;
1317#endif
1318 default:
1319 if (vty->output_func)
1320 (*vty->output_func) (vty, 0);
1321 break;
1322 }
1323 continue;
1324 }
1325
1326 /* Escape character. */
1327 if (vty->escape == VTY_ESCAPE)
1328 {
1329 vty_escape_map (buf[i], vty);
1330 continue;
1331 }
1332
1333 /* Pre-escape status. */
1334 if (vty->escape == VTY_PRE_ESCAPE)
1335 {
1336 switch (buf[i])
1337 {
1338 case '[':
1339 vty->escape = VTY_ESCAPE;
1340 break;
1341 case 'b':
1342 vty_backward_word (vty);
1343 vty->escape = VTY_NORMAL;
1344 break;
1345 case 'f':
1346 vty_forward_word (vty);
1347 vty->escape = VTY_NORMAL;
1348 break;
1349 case 'd':
1350 vty_forward_kill_word (vty);
1351 vty->escape = VTY_NORMAL;
1352 break;
1353 case CONTROL('H'):
1354 case 0x7f:
1355 vty_backward_kill_word (vty);
1356 vty->escape = VTY_NORMAL;
1357 break;
1358 default:
1359 vty->escape = VTY_NORMAL;
1360 break;
1361 }
1362 continue;
1363 }
1364
1365 switch (buf[i])
1366 {
1367 case CONTROL('A'):
1368 vty_beginning_of_line (vty);
1369 break;
1370 case CONTROL('B'):
1371 vty_backward_char (vty);
1372 break;
1373 case CONTROL('C'):
1374 vty_stop_input (vty);
1375 break;
1376 case CONTROL('D'):
1377 vty_delete_char (vty);
1378 break;
1379 case CONTROL('E'):
1380 vty_end_of_line (vty);
1381 break;
1382 case CONTROL('F'):
1383 vty_forward_char (vty);
1384 break;
1385 case CONTROL('H'):
1386 case 0x7f:
1387 vty_delete_backward_char (vty);
1388 break;
1389 case CONTROL('K'):
1390 vty_kill_line (vty);
1391 break;
1392 case CONTROL('N'):
1393 vty_next_line (vty);
1394 break;
1395 case CONTROL('P'):
1396 vty_previous_line (vty);
1397 break;
1398 case CONTROL('T'):
1399 vty_transpose_chars (vty);
1400 break;
1401 case CONTROL('U'):
1402 vty_kill_line_from_beginning (vty);
1403 break;
1404 case CONTROL('W'):
1405 vty_backward_kill_word (vty);
1406 break;
1407 case CONTROL('Z'):
1408 vty_end_config (vty);
1409 break;
1410 case '\n':
1411 case '\r':
1412 vty_out (vty, "%s", VTY_NEWLINE);
1413 vty_execute (vty);
1414 break;
1415 case '\t':
1416 vty_complete_command (vty);
1417 break;
1418 case '?':
1419 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1420 vty_self_insert (vty, buf[i]);
1421 else
1422 vty_describe_command (vty);
1423 break;
1424 case '\033':
1425 if (i + 1 < nbytes && buf[i + 1] == '[')
1426 {
1427 vty->escape = VTY_ESCAPE;
1428 i++;
1429 }
1430 else
1431 vty->escape = VTY_PRE_ESCAPE;
1432 break;
1433 default:
1434 if (buf[i] > 31 && buf[i] < 127)
1435 vty_self_insert (vty, buf[i]);
1436 break;
1437 }
1438 }
1439
1440 /* Check status. */
1441 if (vty->status == VTY_CLOSE)
1442 vty_close (vty);
1443 else
1444 {
1445 vty_event (VTY_WRITE, vty_sock, vty);
1446 vty_event (VTY_READ, vty_sock, vty);
1447 }
1448 return 0;
1449}
1450
1451/* Flush buffer to the vty. */
1452static int
1453vty_flush (struct thread *thread)
1454{
1455 int erase;
1456 int dont_more;
1457 int vty_sock = THREAD_FD (thread);
1458 struct vty *vty = THREAD_ARG (thread);
1459 vty->t_write = NULL;
1460
1461 /* Tempolary disable read thread. */
1462 if (vty->lines == 0)
1463 if (vty->t_read)
1464 {
1465 thread_cancel (vty->t_read);
1466 vty->t_read = NULL;
1467 }
1468
1469 /* Function execution continue. */
1470 if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
1471 {
1472 if (vty->status == VTY_CONTINUE)
1473 erase = 1;
1474 else
1475 erase = 0;
1476
1477 if (vty->output_func == NULL)
1478 dont_more = 1;
1479 else
1480 dont_more = 0;
1481
1482 if (vty->lines == 0)
1483 {
1484 erase = 0;
1485 dont_more = 1;
1486 }
1487
1488 buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
1489
1490 if (vty->status == VTY_CLOSE)
1491 {
1492 vty_close (vty);
1493 return 0;
1494 }
1495
1496 if (vty->output_func == NULL)
1497 {
1498 vty->status = VTY_NORMAL;
1499 vty_prompt (vty);
1500 vty_event (VTY_WRITE, vty_sock, vty);
1501 }
1502 else
1503 vty->status = VTY_MORE;
1504
1505 if (vty->lines == 0)
1506 {
1507 if (vty->output_func == NULL)
1508 vty_event (VTY_READ, vty_sock, vty);
1509 else
1510 {
1511 if (vty->output_func)
1512 (*vty->output_func) (vty, 0);
1513 vty_event (VTY_WRITE, vty_sock, vty);
1514 }
1515 }
1516 }
1517 else
1518 {
1519 if (vty->status == VTY_MORE || vty->status == VTY_MORELINE)
1520 erase = 1;
1521 else
1522 erase = 0;
1523
1524 if (vty->lines == 0)
1525 buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
1526 else if (vty->status == VTY_MORELINE)
1527 buffer_flush_window (vty->obuf, vty->fd, vty->width, 1, erase, 0);
1528 else
1529 buffer_flush_window (vty->obuf, vty->fd, vty->width,
1530 vty->lines >= 0 ? vty->lines : vty->height,
1531 erase, 0);
1532
1533 if (buffer_empty (vty->obuf))
1534 {
1535 if (vty->status == VTY_CLOSE)
1536 vty_close (vty);
1537 else
1538 {
1539 vty->status = VTY_NORMAL;
1540
1541 if (vty->lines == 0)
1542 vty_event (VTY_READ, vty_sock, vty);
1543 }
1544 }
1545 else
1546 {
1547 vty->status = VTY_MORE;
1548
1549 if (vty->lines == 0)
1550 vty_event (VTY_WRITE, vty_sock, vty);
1551 }
1552 }
1553
1554 return 0;
1555}
1556
1557/* Create new vty structure. */
1558struct vty *
1559vty_create (int vty_sock, union sockunion *su)
1560{
1561 struct vty *vty;
1562
1563 /* Allocate new vty structure and set up default values. */
1564 vty = vty_new ();
1565 vty->fd = vty_sock;
1566 vty->type = VTY_TERM;
1567 vty->address = sockunion_su2str (su);
1568 if (no_password_check)
1569 {
1570 if (host.advanced)
1571 vty->node = ENABLE_NODE;
1572 else
1573 vty->node = VIEW_NODE;
1574 }
1575 else
1576 vty->node = AUTH_NODE;
1577 vty->fail = 0;
1578 vty->cp = 0;
1579 vty_clear_buf (vty);
1580 vty->length = 0;
1581 memset (vty->hist, 0, sizeof (vty->hist));
1582 vty->hp = 0;
1583 vty->hindex = 0;
1584 vector_set_index (vtyvec, vty_sock, vty);
1585 vty->status = VTY_NORMAL;
1586 vty->v_timeout = vty_timeout_val;
1587 if (host.lines >= 0)
1588 vty->lines = host.lines;
1589 else
1590 vty->lines = -1;
1591 vty->iac = 0;
1592 vty->iac_sb_in_progress = 0;
1593 vty->sb_buffer = buffer_new (1024);
1594
1595 if (! no_password_check)
1596 {
1597 /* Vty is not available if password isn't set. */
1598 if (host.password == NULL && host.password_encrypt == NULL)
1599 {
1600 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1601 vty->status = VTY_CLOSE;
1602 vty_close (vty);
1603 return NULL;
1604 }
1605 }
1606
1607 /* Say hello to the world. */
1608 vty_hello (vty);
1609 if (! no_password_check)
1610 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1611
1612 /* Setting up terminal. */
1613 vty_will_echo (vty);
1614 vty_will_suppress_go_ahead (vty);
1615
1616 vty_dont_linemode (vty);
1617 vty_do_window_size (vty);
1618 /* vty_dont_lflow_ahead (vty); */
1619
1620 vty_prompt (vty);
1621
1622 /* Add read/write thread. */
1623 vty_event (VTY_WRITE, vty_sock, vty);
1624 vty_event (VTY_READ, vty_sock, vty);
1625
1626 return vty;
1627}
1628
1629/* Accept connection from the network. */
1630static int
1631vty_accept (struct thread *thread)
1632{
1633 int vty_sock;
1634 struct vty *vty;
1635 union sockunion su;
1636 int ret;
1637 unsigned int on;
1638 int accept_sock;
1639 struct prefix *p = NULL;
1640 struct access_list *acl = NULL;
1641
1642 accept_sock = THREAD_FD (thread);
1643
1644 /* We continue hearing vty socket. */
1645 vty_event (VTY_SERV, accept_sock, NULL);
1646
1647 memset (&su, 0, sizeof (union sockunion));
1648
1649 /* We can handle IPv4 or IPv6 socket. */
1650 vty_sock = sockunion_accept (accept_sock, &su);
1651 if (vty_sock < 0)
1652 {
1653 zlog_warn ("can't accept vty socket : %s", strerror (errno));
1654 return -1;
1655 }
1656
1657 p = sockunion2hostprefix (&su);
1658
1659 /* VTY's accesslist apply. */
1660 if (p->family == AF_INET && vty_accesslist_name)
1661 {
1662 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1663 (access_list_apply (acl, p) == FILTER_DENY))
1664 {
1665 char *buf;
1666 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1667 (buf = sockunion_su2str (&su)));
1668 free (buf);
1669 close (vty_sock);
1670
1671 /* continue accepting connections */
1672 vty_event (VTY_SERV, accept_sock, NULL);
1673
1674 prefix_free (p);
1675
1676 return 0;
1677 }
1678 }
1679
1680#ifdef HAVE_IPV6
1681 /* VTY's ipv6 accesslist apply. */
1682 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1683 {
1684 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1685 (access_list_apply (acl, p) == FILTER_DENY))
1686 {
1687 char *buf;
1688 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1689 (buf = sockunion_su2str (&su)));
1690 free (buf);
1691 close (vty_sock);
1692
1693 /* continue accepting connections */
1694 vty_event (VTY_SERV, accept_sock, NULL);
1695
1696 prefix_free (p);
1697
1698 return 0;
1699 }
1700 }
1701#endif /* HAVE_IPV6 */
1702
1703 prefix_free (p);
1704
1705 on = 1;
1706 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1707 (char *) &on, sizeof (on));
1708 if (ret < 0)
1709 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
1710 strerror (errno));
1711
1712 vty = vty_create (vty_sock, &su);
1713
1714 return 0;
1715}
1716
1717#if defined(HAVE_IPV6) && !defined(NRL)
1718void
1719vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1720{
1721 int ret;
1722 struct addrinfo req;
1723 struct addrinfo *ainfo;
1724 struct addrinfo *ainfo_save;
1725 int sock;
1726 char port_str[BUFSIZ];
1727
1728 memset (&req, 0, sizeof (struct addrinfo));
1729 req.ai_flags = AI_PASSIVE;
1730 req.ai_family = AF_UNSPEC;
1731 req.ai_socktype = SOCK_STREAM;
1732 sprintf (port_str, "%d", port);
1733 port_str[sizeof (port_str) - 1] = '\0';
1734
1735 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1736
1737 if (ret != 0)
1738 {
1739 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1740 exit (1);
1741 }
1742
1743 ainfo_save = ainfo;
1744
1745 do
1746 {
1747 if (ainfo->ai_family != AF_INET
1748#ifdef HAVE_IPV6
1749 && ainfo->ai_family != AF_INET6
1750#endif /* HAVE_IPV6 */
1751 )
1752 continue;
1753
1754 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1755 if (sock < 0)
1756 continue;
1757
1758 sockopt_reuseaddr (sock);
1759 sockopt_reuseport (sock);
1760
1761 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1762 if (ret < 0)
1763 {
1764 close (sock); /* Avoid sd leak. */
1765 continue;
1766 }
1767
1768 ret = listen (sock, 3);
1769 if (ret < 0)
1770 {
1771 close (sock); /* Avoid sd leak. */
1772 continue;
1773 }
1774
1775 vty_event (VTY_SERV, sock, NULL);
1776 }
1777 while ((ainfo = ainfo->ai_next) != NULL);
1778
1779 freeaddrinfo (ainfo_save);
1780}
1781#endif /* HAVE_IPV6 && ! NRL */
1782
1783/* Make vty server socket. */
1784void
paul29db05b2003-05-08 20:10:22 +00001785vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001786{
1787 int ret;
1788 union sockunion su;
1789 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001790 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001791
1792 memset (&su, 0, sizeof (union sockunion));
1793 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001794 if(addr)
1795 switch(family)
1796 {
1797 case AF_INET:
1798 naddr=&su.sin.sin_addr;
1799#ifdef HAVE_IPV6
1800 case AF_INET6:
1801 naddr=&su.sin6.sin6_addr;
1802#endif
1803 }
1804
1805 if(naddr)
1806 switch(inet_pton(family,addr,naddr))
1807 {
1808 case -1:
1809 zlog_err("bad address %s",addr);
1810 naddr=NULL;
1811 break;
1812 case 0:
1813 zlog_err("error translating address %s: %s",addr,strerror(errno));
1814 naddr=NULL;
1815 }
paul718e3742002-12-13 20:15:29 +00001816
1817 /* Make new socket. */
1818 accept_sock = sockunion_stream_socket (&su);
1819 if (accept_sock < 0)
1820 return;
1821
1822 /* This is server, so reuse address. */
1823 sockopt_reuseaddr (accept_sock);
1824 sockopt_reuseport (accept_sock);
1825
1826 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001827 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001828 if (ret < 0)
1829 {
paul29db05b2003-05-08 20:10:22 +00001830 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001831 close (accept_sock); /* Avoid sd leak. */
1832 return;
1833 }
1834
1835 /* Listen socket under queue 3. */
1836 ret = listen (accept_sock, 3);
1837 if (ret < 0)
1838 {
1839 zlog (NULL, LOG_WARNING, "can't listen socket");
1840 close (accept_sock); /* Avoid sd leak. */
1841 return;
1842 }
1843
1844 /* Add vty server event. */
1845 vty_event (VTY_SERV, accept_sock, NULL);
1846}
1847
1848#ifdef VTYSH
1849/* For sockaddr_un. */
1850#include <sys/un.h>
1851
1852/* VTY shell UNIX domain socket. */
1853void
1854vty_serv_un (char *path)
1855{
1856 int ret;
1857 int sock, len;
1858 struct sockaddr_un serv;
1859 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00001860 struct zprivs_ids_t ids;
1861
paul718e3742002-12-13 20:15:29 +00001862 /* First of all, unlink existing socket */
1863 unlink (path);
1864
1865 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00001866 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00001867
1868 /* Make UNIX domain socket. */
1869 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1870 if (sock < 0)
1871 {
1872 perror ("sock");
1873 return;
1874 }
1875
1876 /* Make server socket. */
1877 memset (&serv, 0, sizeof (struct sockaddr_un));
1878 serv.sun_family = AF_UNIX;
1879 strncpy (serv.sun_path, path, strlen (path));
1880#ifdef HAVE_SUN_LEN
1881 len = serv.sun_len = SUN_LEN(&serv);
1882#else
1883 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1884#endif /* HAVE_SUN_LEN */
1885
1886 ret = bind (sock, (struct sockaddr *) &serv, len);
1887 if (ret < 0)
1888 {
1889 perror ("bind");
1890 close (sock); /* Avoid sd leak. */
1891 return;
1892 }
1893
1894 ret = listen (sock, 5);
1895 if (ret < 0)
1896 {
1897 perror ("listen");
1898 close (sock); /* Avoid sd leak. */
1899 return;
1900 }
1901
1902 umask (old_mask);
1903
pauledd7c242003-06-04 13:59:38 +00001904 zprivs_get_ids(&ids);
1905
1906 if (ids.gid_vty > 0)
1907 {
1908 /* set group of socket */
1909 if ( chown (path, -1, ids.gid_vty) )
1910 {
1911 zlog_err ("vty_serv_un: could chown socket, %s",
1912 strerror (errno) );
1913 }
1914 }
1915
paul718e3742002-12-13 20:15:29 +00001916 vty_event (VTYSH_SERV, sock, NULL);
1917}
1918
1919/* #define VTYSH_DEBUG 1 */
1920
1921static int
1922vtysh_accept (struct thread *thread)
1923{
1924 int accept_sock;
1925 int sock;
1926 int client_len;
1927 struct sockaddr_un client;
1928 struct vty *vty;
1929
1930 accept_sock = THREAD_FD (thread);
1931
1932 vty_event (VTYSH_SERV, accept_sock, NULL);
1933
1934 memset (&client, 0, sizeof (struct sockaddr_un));
1935 client_len = sizeof (struct sockaddr_un);
1936
1937 sock = accept (accept_sock, (struct sockaddr *) &client, &client_len);
1938
1939 if (sock < 0)
1940 {
1941 zlog_warn ("can't accept vty socket : %s", strerror (errno));
1942 return -1;
1943 }
1944
1945#ifdef VTYSH_DEBUG
1946 printf ("VTY shell accept\n");
1947#endif /* VTYSH_DEBUG */
1948
1949 vty = vty_new ();
1950 vty->fd = sock;
1951 vty->type = VTY_SHELL_SERV;
1952 vty->node = VIEW_NODE;
1953
1954 vty_event (VTYSH_READ, sock, vty);
1955
1956 return 0;
1957}
1958
1959static int
1960vtysh_read (struct thread *thread)
1961{
1962 int ret;
1963 int sock;
1964 int nbytes;
1965 struct vty *vty;
1966 unsigned char buf[VTY_READ_BUFSIZ];
1967 u_char header[4] = {0, 0, 0, 0};
1968
1969 sock = THREAD_FD (thread);
1970 vty = THREAD_ARG (thread);
1971 vty->t_read = NULL;
1972
1973 nbytes = read (sock, buf, VTY_READ_BUFSIZ);
1974 if (nbytes <= 0)
1975 {
1976 vty_close (vty);
1977#ifdef VTYSH_DEBUG
1978 printf ("close vtysh\n");
1979#endif /* VTYSH_DEBUG */
1980 return 0;
1981 }
1982
1983#ifdef VTYSH_DEBUG
1984 printf ("line: %s\n", buf);
1985#endif /* VTYSH_DEBUG */
1986
1987 vty_ensure (vty, nbytes);
1988 memcpy (vty->buf, buf, nbytes);
1989
1990 /* Pass this line to parser. */
1991 ret = vty_execute (vty);
1992
1993 vty_clear_buf (vty);
1994
1995 /* Return result. */
1996#ifdef VTYSH_DEBUG
1997 printf ("result: %d\n", ret);
1998 printf ("vtysh node: %d\n", vty->node);
1999#endif /* VTYSH_DEBUG */
2000
2001 header[3] = ret;
2002 write (vty->fd, header, 4);
2003
2004 vty_event (VTYSH_READ, sock, vty);
2005
2006 return 0;
2007}
2008#endif /* VTYSH */
2009
2010/* Determine address family to bind. */
2011void
paul29db05b2003-05-08 20:10:22 +00002012vty_serv_sock (const char *addr, unsigned short port, char *path)
paul718e3742002-12-13 20:15:29 +00002013{
2014 /* If port is set to 0, do not listen on TCP/IP at all! */
2015 if (port)
2016 {
2017
2018#ifdef HAVE_IPV6
2019#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002020 vty_serv_sock_family (addr, port, AF_INET);
2021 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002022#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002023 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002024#endif /* NRL*/
2025#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002026 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002027#endif /* HAVE_IPV6 */
2028 }
2029
2030#ifdef VTYSH
2031 vty_serv_un (path);
2032#endif /* VTYSH */
2033}
2034
2035/* Close vty interface. */
2036void
2037vty_close (struct vty *vty)
2038{
2039 int i;
2040
2041 /* Cancel threads.*/
2042 if (vty->t_read)
2043 thread_cancel (vty->t_read);
2044 if (vty->t_write)
2045 thread_cancel (vty->t_write);
2046 if (vty->t_timeout)
2047 thread_cancel (vty->t_timeout);
2048 if (vty->t_output)
2049 thread_cancel (vty->t_output);
2050
2051 /* Flush buffer. */
2052 if (! buffer_empty (vty->obuf))
2053 buffer_flush_all (vty->obuf, vty->fd);
2054
2055 /* Free input buffer. */
2056 buffer_free (vty->obuf);
2057
2058 /* Free SB buffer. */
2059 if (vty->sb_buffer)
2060 buffer_free (vty->sb_buffer);
2061
2062 /* Free command history. */
2063 for (i = 0; i < VTY_MAXHIST; i++)
2064 if (vty->hist[i])
2065 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2066
2067 /* Unset vector. */
2068 vector_unset (vtyvec, vty->fd);
2069
2070 /* Close socket. */
2071 if (vty->fd > 0)
2072 close (vty->fd);
2073
2074 if (vty->address)
2075 XFREE (0, vty->address);
2076 if (vty->buf)
2077 XFREE (MTYPE_VTY, vty->buf);
2078
2079 /* Check configure. */
2080 vty_config_unlock (vty);
2081
2082 /* OK free vty. */
2083 XFREE (MTYPE_VTY, vty);
2084}
2085
2086/* When time out occur output message then close connection. */
2087static int
2088vty_timeout (struct thread *thread)
2089{
2090 struct vty *vty;
2091
2092 vty = THREAD_ARG (thread);
2093 vty->t_timeout = NULL;
2094 vty->v_timeout = 0;
2095
2096 /* Clear buffer*/
2097 buffer_reset (vty->obuf);
2098 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2099
2100 /* Close connection. */
2101 vty->status = VTY_CLOSE;
2102 vty_close (vty);
2103
2104 return 0;
2105}
2106
2107/* Read up configuration file from file_name. */
2108static void
2109vty_read_file (FILE *confp)
2110{
2111 int ret;
2112 struct vty *vty;
2113
2114 vty = vty_new ();
2115 vty->fd = 0; /* stdout */
2116 vty->type = VTY_TERM;
2117 vty->node = CONFIG_NODE;
2118
2119 /* Execute configuration file */
2120 ret = config_from_file (vty, confp);
2121
paul7021c422003-07-15 12:52:22 +00002122 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002123 {
2124 switch (ret)
paul7021c422003-07-15 12:52:22 +00002125 {
2126 case CMD_ERR_AMBIGUOUS:
2127 fprintf (stderr, "Ambiguous command.\n");
2128 break;
2129 case CMD_ERR_NO_MATCH:
2130 fprintf (stderr, "There is no such command.\n");
2131 break;
2132 }
paul718e3742002-12-13 20:15:29 +00002133 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2134 vty->buf);
2135 vty_close (vty);
2136 exit (1);
2137 }
2138
2139 vty_close (vty);
2140}
2141
2142FILE *
2143vty_use_backup_config (char *fullpath)
2144{
2145 char *fullpath_sav, *fullpath_tmp;
2146 FILE *ret = NULL;
2147 struct stat buf;
2148 int tmp, sav;
2149 int c;
2150 char buffer[512];
2151
2152 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2153 strcpy (fullpath_sav, fullpath);
2154 strcat (fullpath_sav, CONF_BACKUP_EXT);
2155 if (stat (fullpath_sav, &buf) == -1)
2156 {
2157 free (fullpath_sav);
2158 return NULL;
2159 }
2160
2161 fullpath_tmp = malloc (strlen (fullpath) + 8);
2162 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2163
2164 /* Open file to configuration write. */
2165 tmp = mkstemp (fullpath_tmp);
2166 if (tmp < 0)
2167 {
2168 free (fullpath_sav);
2169 free (fullpath_tmp);
2170 return NULL;
2171 }
2172
2173 sav = open (fullpath_sav, O_RDONLY);
2174 if (sav < 0)
2175 {
2176 free (fullpath_sav);
2177 free (fullpath_tmp);
2178 unlink (fullpath_tmp);
2179 return NULL;
2180 }
2181
2182 while((c = read (sav, buffer, 512)) > 0)
2183 write (tmp, buffer, c);
2184
2185 close (sav);
2186 close (tmp);
2187
2188 if (link (fullpath_tmp, fullpath) == 0)
2189 ret = fopen (fullpath, "r");
2190
2191 unlink (fullpath_tmp);
2192
2193 free (fullpath_sav);
2194 free (fullpath_tmp);
2195 return fopen (fullpath, "r");
2196}
2197
2198/* Read up configuration file from file_name. */
2199void
2200vty_read_config (char *config_file,
2201 char *config_current_dir,
2202 char *config_default_dir)
2203{
paulccc92352003-10-22 02:49:38 +00002204 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002205 FILE *confp = NULL;
2206 char *fullpath;
2207
2208 /* If -f flag specified. */
2209 if (config_file != NULL)
2210 {
2211 if (! IS_DIRECTORY_SEP (config_file[0]))
2212 {
paulccc92352003-10-22 02:49:38 +00002213 getcwd (cwd, MAXPATHLEN);
paul718e3742002-12-13 20:15:29 +00002214 fullpath = XMALLOC (MTYPE_TMP,
2215 strlen (cwd) + strlen (config_file) + 2);
2216 sprintf (fullpath, "%s/%s", cwd, config_file);
2217 }
2218 else
2219 fullpath = config_file;
2220
2221 confp = fopen (fullpath, "r");
2222
2223 if (confp == NULL)
2224 {
2225 confp = vty_use_backup_config (fullpath);
2226 if (confp)
2227 fprintf (stderr, "WARNING: using backup configuration file!\n");
2228 else
2229 {
2230 fprintf (stderr, "can't open configuration file [%s]\n",
2231 config_file);
2232 exit(1);
2233 }
2234 }
2235 }
2236 else
2237 {
2238 /* Relative path configuration file open. */
2239 if (config_current_dir)
2240 {
2241 confp = fopen (config_current_dir, "r");
2242 if (confp == NULL)
2243 {
2244 confp = vty_use_backup_config (config_current_dir);
2245 if (confp)
2246 fprintf (stderr, "WARNING: using backup configuration file!\n");
2247 }
2248 }
2249
2250 /* If there is no relative path exists, open system default file. */
2251 if (confp == NULL)
2252 {
2253#ifdef VTYSH
2254 int ret;
2255 struct stat conf_stat;
2256
2257 /* !!!!PLEASE LEAVE!!!!
2258 This is NEEDED for use with vtysh -b, or else you can get
2259 a real configuration food fight with a lot garbage in the
2260 merged configuration file it creates coming from the per
2261 daemon configuration files. This also allows the daemons
2262 to start if there default configuration file is not
2263 present or ignore them, as needed when using vtysh -b to
2264 configure the daemons at boot - MAG */
2265
2266 /* Stat for vtysh Zebra.conf, if found startup and wait for
2267 boot configuration */
2268
2269 if ( strstr(config_default_dir, "vtysh") == NULL)
2270 {
2271 ret = stat (integrate_default, &conf_stat);
2272 if (ret >= 0)
2273 {
2274 return;
2275 }
2276 }
2277#endif /* VTYSH */
2278
2279 confp = fopen (config_default_dir, "r");
2280 if (confp == NULL)
2281 {
2282 confp = vty_use_backup_config (config_default_dir);
2283 if (confp)
2284 {
2285 fprintf (stderr, "WARNING: using backup configuration file!\n");
2286 fullpath = config_default_dir;
2287 }
2288 else
2289 {
2290 fprintf (stderr, "can't open configuration file [%s]\n",
2291 config_default_dir);
2292 exit (1);
2293 }
2294 }
2295 else
2296 fullpath = config_default_dir;
2297 }
2298 else
2299 {
2300 /* Rleative path configuration file. */
paulccc92352003-10-22 02:49:38 +00002301 getcwd (cwd, MAXPATHLEN);
paul718e3742002-12-13 20:15:29 +00002302 fullpath = XMALLOC (MTYPE_TMP,
2303 strlen (cwd) + strlen (config_current_dir) + 2);
2304 sprintf (fullpath, "%s/%s", cwd, config_current_dir);
2305 }
2306 }
2307 vty_read_file (confp);
2308
2309 fclose (confp);
2310
2311 host_config_set (fullpath);
2312}
2313
2314/* Small utility function which output log to the VTY. */
2315void
2316vty_log (const char *proto_str, const char *format, va_list va)
2317{
2318 int i;
2319 struct vty *vty;
2320
2321 for (i = 0; i < vector_max (vtyvec); i++)
2322 if ((vty = vector_slot (vtyvec, i)) != NULL)
2323 if (vty->monitor)
2324 vty_log_out (vty, proto_str, format, va);
2325}
2326
2327int
2328vty_config_lock (struct vty *vty)
2329{
2330 if (vty_config == 0)
2331 {
2332 vty->config = 1;
2333 vty_config = 1;
2334 }
2335 return vty->config;
2336}
2337
2338int
2339vty_config_unlock (struct vty *vty)
2340{
2341 if (vty_config == 1 && vty->config == 1)
2342 {
2343 vty->config = 0;
2344 vty_config = 0;
2345 }
2346 return vty->config;
2347}
2348
2349/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002350static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002351
2352static void
2353vty_event (enum event event, int sock, struct vty *vty)
2354{
2355 struct thread *vty_serv_thread;
2356
2357 switch (event)
2358 {
2359 case VTY_SERV:
2360 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2361 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2362 break;
2363#ifdef VTYSH
2364 case VTYSH_SERV:
2365 thread_add_read (master, vtysh_accept, vty, sock);
2366 break;
2367 case VTYSH_READ:
2368 thread_add_read (master, vtysh_read, vty, sock);
2369 break;
2370#endif /* VTYSH */
2371 case VTY_READ:
2372 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2373
2374 /* Time out treatment. */
2375 if (vty->v_timeout)
2376 {
2377 if (vty->t_timeout)
2378 thread_cancel (vty->t_timeout);
2379 vty->t_timeout =
2380 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2381 }
2382 break;
2383 case VTY_WRITE:
2384 if (! vty->t_write)
2385 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2386 break;
2387 case VTY_TIMEOUT_RESET:
2388 if (vty->t_timeout)
2389 {
2390 thread_cancel (vty->t_timeout);
2391 vty->t_timeout = NULL;
2392 }
2393 if (vty->v_timeout)
2394 {
2395 vty->t_timeout =
2396 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2397 }
2398 break;
2399 }
2400}
2401
2402DEFUN (config_who,
2403 config_who_cmd,
2404 "who",
2405 "Display who is on vty\n")
2406{
2407 int i;
2408 struct vty *v;
2409
2410 for (i = 0; i < vector_max (vtyvec); i++)
2411 if ((v = vector_slot (vtyvec, i)) != NULL)
2412 vty_out (vty, "%svty[%d] connected from %s.%s",
2413 v->config ? "*" : " ",
2414 i, v->address, VTY_NEWLINE);
2415 return CMD_SUCCESS;
2416}
2417
2418/* Move to vty configuration mode. */
2419DEFUN (line_vty,
2420 line_vty_cmd,
2421 "line vty",
2422 "Configure a terminal line\n"
2423 "Virtual terminal\n")
2424{
2425 vty->node = VTY_NODE;
2426 return CMD_SUCCESS;
2427}
2428
2429/* Set time out value. */
2430int
2431exec_timeout (struct vty *vty, char *min_str, char *sec_str)
2432{
2433 unsigned long timeout = 0;
2434
2435 /* min_str and sec_str are already checked by parser. So it must be
2436 all digit string. */
2437 if (min_str)
2438 {
2439 timeout = strtol (min_str, NULL, 10);
2440 timeout *= 60;
2441 }
2442 if (sec_str)
2443 timeout += strtol (sec_str, NULL, 10);
2444
2445 vty_timeout_val = timeout;
2446 vty->v_timeout = timeout;
2447 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2448
2449
2450 return CMD_SUCCESS;
2451}
2452
2453DEFUN (exec_timeout_min,
2454 exec_timeout_min_cmd,
2455 "exec-timeout <0-35791>",
2456 "Set timeout value\n"
2457 "Timeout value in minutes\n")
2458{
2459 return exec_timeout (vty, argv[0], NULL);
2460}
2461
2462DEFUN (exec_timeout_sec,
2463 exec_timeout_sec_cmd,
2464 "exec-timeout <0-35791> <0-2147483>",
2465 "Set the EXEC timeout\n"
2466 "Timeout in minutes\n"
2467 "Timeout in seconds\n")
2468{
2469 return exec_timeout (vty, argv[0], argv[1]);
2470}
2471
2472DEFUN (no_exec_timeout,
2473 no_exec_timeout_cmd,
2474 "no exec-timeout",
2475 NO_STR
2476 "Set the EXEC timeout\n")
2477{
2478 return exec_timeout (vty, NULL, NULL);
2479}
2480
2481/* Set vty access class. */
2482DEFUN (vty_access_class,
2483 vty_access_class_cmd,
2484 "access-class WORD",
2485 "Filter connections based on an IP access list\n"
2486 "IP access list\n")
2487{
2488 if (vty_accesslist_name)
2489 XFREE(MTYPE_VTY, vty_accesslist_name);
2490
2491 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2492
2493 return CMD_SUCCESS;
2494}
2495
2496/* Clear vty access class. */
2497DEFUN (no_vty_access_class,
2498 no_vty_access_class_cmd,
2499 "no access-class [WORD]",
2500 NO_STR
2501 "Filter connections based on an IP access list\n"
2502 "IP access list\n")
2503{
2504 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2505 {
2506 vty_out (vty, "Access-class is not currently applied to vty%s",
2507 VTY_NEWLINE);
2508 return CMD_WARNING;
2509 }
2510
2511 XFREE(MTYPE_VTY, vty_accesslist_name);
2512
2513 vty_accesslist_name = NULL;
2514
2515 return CMD_SUCCESS;
2516}
2517
2518#ifdef HAVE_IPV6
2519/* Set vty access class. */
2520DEFUN (vty_ipv6_access_class,
2521 vty_ipv6_access_class_cmd,
2522 "ipv6 access-class WORD",
2523 IPV6_STR
2524 "Filter connections based on an IP access list\n"
2525 "IPv6 access list\n")
2526{
2527 if (vty_ipv6_accesslist_name)
2528 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2529
2530 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2531
2532 return CMD_SUCCESS;
2533}
2534
2535/* Clear vty access class. */
2536DEFUN (no_vty_ipv6_access_class,
2537 no_vty_ipv6_access_class_cmd,
2538 "no ipv6 access-class [WORD]",
2539 NO_STR
2540 IPV6_STR
2541 "Filter connections based on an IP access list\n"
2542 "IPv6 access list\n")
2543{
2544 if (! vty_ipv6_accesslist_name ||
2545 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2546 {
2547 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2548 VTY_NEWLINE);
2549 return CMD_WARNING;
2550 }
2551
2552 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2553
2554 vty_ipv6_accesslist_name = NULL;
2555
2556 return CMD_SUCCESS;
2557}
2558#endif /* HAVE_IPV6 */
2559
2560/* vty login. */
2561DEFUN (vty_login,
2562 vty_login_cmd,
2563 "login",
2564 "Enable password checking\n")
2565{
2566 no_password_check = 0;
2567 return CMD_SUCCESS;
2568}
2569
2570DEFUN (no_vty_login,
2571 no_vty_login_cmd,
2572 "no login",
2573 NO_STR
2574 "Enable password checking\n")
2575{
2576 no_password_check = 1;
2577 return CMD_SUCCESS;
2578}
2579
2580DEFUN (service_advanced_vty,
2581 service_advanced_vty_cmd,
2582 "service advanced-vty",
2583 "Set up miscellaneous service\n"
2584 "Enable advanced mode vty interface\n")
2585{
2586 host.advanced = 1;
2587 return CMD_SUCCESS;
2588}
2589
2590DEFUN (no_service_advanced_vty,
2591 no_service_advanced_vty_cmd,
2592 "no service advanced-vty",
2593 NO_STR
2594 "Set up miscellaneous service\n"
2595 "Enable advanced mode vty interface\n")
2596{
2597 host.advanced = 0;
2598 return CMD_SUCCESS;
2599}
2600
2601DEFUN (terminal_monitor,
2602 terminal_monitor_cmd,
2603 "terminal monitor",
2604 "Set terminal line parameters\n"
2605 "Copy debug output to the current terminal line\n")
2606{
2607 vty->monitor = 1;
2608 return CMD_SUCCESS;
2609}
2610
2611DEFUN (terminal_no_monitor,
2612 terminal_no_monitor_cmd,
2613 "terminal no monitor",
2614 "Set terminal line parameters\n"
2615 NO_STR
2616 "Copy debug output to the current terminal line\n")
2617{
2618 vty->monitor = 0;
2619 return CMD_SUCCESS;
2620}
2621
2622DEFUN (show_history,
2623 show_history_cmd,
2624 "show history",
2625 SHOW_STR
2626 "Display the session command history\n")
2627{
2628 int index;
2629
2630 for (index = vty->hindex + 1; index != vty->hindex;)
2631 {
2632 if (index == VTY_MAXHIST)
2633 {
2634 index = 0;
2635 continue;
2636 }
2637
2638 if (vty->hist[index] != NULL)
2639 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2640
2641 index++;
2642 }
2643
2644 return CMD_SUCCESS;
2645}
2646
2647/* Display current configuration. */
2648int
2649vty_config_write (struct vty *vty)
2650{
2651 vty_out (vty, "line vty%s", VTY_NEWLINE);
2652
2653 if (vty_accesslist_name)
2654 vty_out (vty, " access-class %s%s",
2655 vty_accesslist_name, VTY_NEWLINE);
2656
2657 if (vty_ipv6_accesslist_name)
2658 vty_out (vty, " ipv6 access-class %s%s",
2659 vty_ipv6_accesslist_name, VTY_NEWLINE);
2660
2661 /* exec-timeout */
2662 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2663 vty_out (vty, " exec-timeout %ld %ld%s",
2664 vty_timeout_val / 60,
2665 vty_timeout_val % 60, VTY_NEWLINE);
2666
2667 /* login */
2668 if (no_password_check)
2669 vty_out (vty, " no login%s", VTY_NEWLINE);
2670
2671 vty_out (vty, "!%s", VTY_NEWLINE);
2672
2673 return CMD_SUCCESS;
2674}
2675
2676struct cmd_node vty_node =
2677{
2678 VTY_NODE,
2679 "%s(config-line)# ",
2680};
2681
2682/* Reset all VTY status. */
2683void
2684vty_reset ()
2685{
2686 int i;
2687 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{
2726 int i;
2727 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}