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