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