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