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