]> git.proxmox.com Git - mirror_frr.git/blame - lib/vty.c
[lib/md5] md5_loop should take void pointer for more useful caller warnings.
[mirror_frr.git] / lib / vty.c
CommitLineData
718e3744 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"
b21b19c5 26#include "thread.h"
718e3744 27#include "buffer.h"
5e4fa164 28#include <lib/version.h>
718e3744 29#include "command.h"
30#include "sockunion.h"
718e3744 31#include "memory.h"
32#include "str.h"
33#include "log.h"
34#include "prefix.h"
35#include "filter.h"
b21b19c5 36#include "vty.h"
edd7c245 37#include "privs.h"
9fc7ebf1 38#include "network.h"
39
40#include <arpa/telnet.h>
718e3744 41
42/* Vty events */
43enum event
44{
45 VTY_SERV,
46 VTY_READ,
47 VTY_WRITE,
48 VTY_TIMEOUT_RESET,
49#ifdef VTYSH
50 VTYSH_SERV,
49ff6d9d 51 VTYSH_READ,
52 VTYSH_WRITE
718e3744 53#endif /* VTYSH */
54};
55
56static void vty_event (enum event, int, struct vty *);
57
58/* Extern host structure from command.c */
59extern struct host host;
60\f
61/* Vector which store each vty structure. */
62static vector vtyvec;
63
64/* Vty timeout value. */
65static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
66
67/* Vty access-class command */
68static char *vty_accesslist_name = NULL;
69
70/* Vty access-calss for IPv6. */
71static char *vty_ipv6_accesslist_name = NULL;
72
73/* VTY server thread. */
74vector Vvty_serv_thread;
75
76/* Current directory. */
77char *vty_cwd = NULL;
78
79/* Configure lock. */
80static int vty_config;
81
82/* Login password check. */
83static int no_password_check = 0;
84
85/* Integrated configuration file path */
86char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
87
88\f
89/* VTY standard output function. */
90int
91vty_out (struct vty *vty, const char *format, ...)
92{
93 va_list args;
94 int len = 0;
95 int size = 1024;
96 char buf[1024];
97 char *p = NULL;
718e3744 98
99 if (vty_shell (vty))
d246bd96 100 {
101 va_start (args, format);
102 vprintf (format, args);
103 va_end (args);
104 }
718e3744 105 else
106 {
107 /* Try to write to initial buffer. */
d246bd96 108 va_start (args, format);
718e3744 109 len = vsnprintf (buf, sizeof buf, format, args);
d246bd96 110 va_end (args);
718e3744 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
d246bd96 126 va_start (args, format);
718e3744 127 len = vsnprintf (p, size, format, args);
d246bd96 128 va_end (args);
718e3744 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. */
9fc7ebf1 140 buffer_put (vty->obuf, (u_char *) p, len);
718e3744 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
718e3744 147 return len;
148}
149
d246bd96 150static int
274a4a44 151vty_log_out (struct vty *vty, const char *level, const char *proto_str,
152 const char *format, va_list va)
718e3744 153{
9fc7ebf1 154 int ret;
718e3744 155 int len;
156 char buf[1024];
157
274a4a44 158 if (level)
9fc7ebf1 159 len = snprintf(buf, sizeof(buf), "%s: %s: ", level, proto_str);
274a4a44 160 else
9fc7ebf1 161 len = snprintf(buf, sizeof(buf), "%s: ", proto_str);
162 if ((len < 0) || ((size_t)len >= sizeof(buf)))
163 return -1;
718e3744 164
9fc7ebf1 165 if (((ret = vsnprintf(buf+len, sizeof(buf)-len, format, va)) < 0) ||
166 ((size_t)((len += ret)+2) > sizeof(buf)))
718e3744 167 return -1;
718e3744 168
9fc7ebf1 169 buf[len++] = '\r';
170 buf[len++] = '\n';
718e3744 171
9fc7ebf1 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;
718e3744 186}
187
188/* Output current time to the vty. */
189void
190vty_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. */
216void
217vty_hello (struct vty *vty)
218{
3b0c5d9a 219 if (host.motdfile)
220 {
221 FILE *f;
222 char buf[4096];
22085181 223
3b0c5d9a 224 f = fopen (host.motdfile, "r");
225 if (f)
226 {
b45da6f0 227 while (fgets (buf, sizeof (buf), f))
3b0c5d9a 228 {
b45da6f0 229 char *s;
22085181 230 /* work backwards to ignore trailling isspace() */
f80a016f 231 for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
22085181 232 s--);
233 *s = '\0';
234 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
235 }
3b0c5d9a 236 fclose (f);
237 }
238 else
b45da6f0 239 vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
3b0c5d9a 240 }
241 else if (host.motd)
718e3744 242 vty_out (vty, host.motd);
243}
244
245/* Put out prompt and wait input from user. */
246static void
247vty_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. */
9fc7ebf1 265static void
718e3744 266vty_will_echo (struct vty *vty)
267{
02ff83c5 268 unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
718e3744 269 vty_out (vty, "%s", cmd);
270}
271
272/* Make suppress Go-Ahead telnet option. */
273static void
274vty_will_suppress_go_ahead (struct vty *vty)
275{
02ff83c5 276 unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
718e3744 277 vty_out (vty, "%s", cmd);
278}
279
280/* Make don't use linemode over telnet. */
281static void
282vty_dont_linemode (struct vty *vty)
283{
02ff83c5 284 unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
718e3744 285 vty_out (vty, "%s", cmd);
286}
287
288/* Use window size. */
289static void
290vty_do_window_size (struct vty *vty)
291{
02ff83c5 292 unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
718e3744 293 vty_out (vty, "%s", cmd);
294}
295
296#if 0 /* Currently not used. */
297/* Make don't use lflow vty interface. */
298static void
299vty_dont_lflow_ahead (struct vty *vty)
300{
02ff83c5 301 unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
718e3744 302 vty_out (vty, "%s", cmd);
303}
304#endif /* 0 */
305
306/* Allocate new vty struct. */
307struct vty *
308vty_new ()
309{
310 struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
311
9fc7ebf1 312 new->obuf = buffer_new(0); /* Use default buffer size. */
718e3744 313 new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
314 new->max = VTY_BUFSIZ;
718e3744 315
316 return new;
317}
318
319/* Authentication of vty */
320static void
321vty_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. */
9fc7ebf1 386static int
718e3744 387vty_command (struct vty *vty, char *buf)
388{
389 int ret;
390 vector vline;
fbf5d033 391 const char *protocolname;
718e3744 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
924b9229 399#ifdef CONSUMED_TIME_CHECK
400 {
401 RUSAGE_T before;
402 RUSAGE_T after;
8b70d0b0 403 unsigned long realtime, cputime;
924b9229 404
405 GETRUSAGE(&before);
406#endif /* CONSUMED_TIME_CHECK */
407
87d683b0 408 ret = cmd_execute_command (vline, vty, NULL, 0);
718e3744 409
fbf5d033 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
924b9229 416#ifdef CONSUMED_TIME_CHECK
417 GETRUSAGE(&after);
8b70d0b0 418 if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
419 CONSUMED_TIME_CHECK)
924b9229 420 /* Warn about CPU hog that must be fixed. */
8b70d0b0 421 zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
422 realtime/1000, cputime/1000, buf);
924b9229 423 }
424#endif /* CONSUMED_TIME_CHECK */
425
718e3744 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:
fbf5d033 437 vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
718e3744 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
9fc7ebf1 448static const char telnet_backward_char = 0x08;
449static const char telnet_space_char = ' ';
718e3744 450
451/* Basic function to write buffer to vty. */
452static void
9fc7ebf1 453vty_write (struct vty *vty, const char *buf, size_t nbytes)
718e3744 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) ? */
9fc7ebf1 459 buffer_put (vty->obuf, buf, nbytes);
718e3744 460}
461
462/* Ensure length of input buffer. Is buffer is short, double it. */
463static void
464vty_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. */
474static void
475vty_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. */
494static void
495vty_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. */
510static void
511vty_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. */
521static void
522vty_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. */
532static void
533vty_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. */
543static void
544vty_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. */
551static void
552vty_end_of_line (struct vty *vty)
553{
554 while (vty->cp < vty->length)
555 vty_forward_char (vty);
556}
557
558static void vty_kill_line_from_beginning (struct vty *);
559static 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. */
563static void
564vty_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. */
9fc7ebf1 580static void
718e3744 581vty_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. */
9fc7ebf1 605static void
718e3744 606vty_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. */
625static void
626vty_redraw_line (struct vty *vty)
627{
628 vty_write (vty, vty->buf, vty->length);
629 vty->cp = vty->length;
630}
631
632/* Forward word. */
633static void
634vty_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. */
644static void
645vty_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. */
652static void
653vty_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. */
664static void
665vty_down_level (struct vty *vty)
666{
667 vty_out (vty, "%s", VTY_NEWLINE);
274a4a44 668 (*config_exit_cmd.func)(NULL, vty, 0, NULL);
718e3744 669 vty_prompt (vty);
670 vty->cp = 0;
671}
672
673/* When '^Z' is received from vty, move down to the enable mode. */
9fc7ebf1 674static void
718e3744 675vty_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:
1e836590 695 case BGP_IPV6M_NODE:
718e3744 696 case RMAP_NODE:
697 case OSPF_NODE:
698 case OSPF6_NODE:
9e867fe6 699 case ISIS_NODE:
718e3744 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. */
717static void
718vty_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. */
749static void
750vty_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. */
760static void
761vty_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. */
781static void
782vty_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. */
789static void
790vty_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. */
799static void
800vty_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. */
809static void
810vty_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. */
842static void
843vty_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
9fc7ebf1 919static void
718e3744 920vty_describe_fold (struct vty *vty, int cmd_width,
8c328f11 921 unsigned int desc_width, struct desc *desc)
718e3744 922{
8c328f11 923 char *buf;
924 const char *cmd, *p;
718e3744 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. */
959static void
960vty_describe_command (struct vty *vty)
961{
962 int ret;
963 vector vline;
964 vector describe;
8c328f11 965 unsigned int i, width, desc_width;
718e3744 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 cmd_free_strvec (vline);
989 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
990 vty_prompt (vty);
991 vty_redraw_line (vty);
992 return;
993 break;
994 case CMD_ERR_NO_MATCH:
995 cmd_free_strvec (vline);
996 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
997 vty_prompt (vty);
998 vty_redraw_line (vty);
999 return;
1000 break;
1001 }
1002
1003 /* Get width of command string. */
1004 width = 0;
55468c86 1005 for (i = 0; i < vector_active (describe); i++)
718e3744 1006 if ((desc = vector_slot (describe, i)) != NULL)
1007 {
8c328f11 1008 unsigned int len;
718e3744 1009
1010 if (desc->cmd[0] == '\0')
1011 continue;
1012
1013 len = strlen (desc->cmd);
1014 if (desc->cmd[0] == '.')
1015 len--;
1016
1017 if (width < len)
1018 width = len;
1019 }
1020
1021 /* Get width of description string. */
1022 desc_width = vty->width - (width + 6);
1023
1024 /* Print out description. */
55468c86 1025 for (i = 0; i < vector_active (describe); i++)
718e3744 1026 if ((desc = vector_slot (describe, i)) != NULL)
1027 {
1028 if (desc->cmd[0] == '\0')
1029 continue;
1030
1031 if (strcmp (desc->cmd, "<cr>") == 0)
1032 {
1033 desc_cr = desc;
1034 continue;
1035 }
1036
1037 if (!desc->str)
1038 vty_out (vty, " %-s%s",
1039 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1040 VTY_NEWLINE);
1041 else if (desc_width >= strlen (desc->str))
1042 vty_out (vty, " %-*s %s%s", width,
1043 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1044 desc->str, VTY_NEWLINE);
1045 else
1046 vty_describe_fold (vty, width, desc_width, desc);
1047
1048#if 0
1049 vty_out (vty, " %-*s %s%s", width
1050 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1051 desc->str ? desc->str : "", VTY_NEWLINE);
1052#endif /* 0 */
1053 }
1054
1055 if ((desc = desc_cr))
1056 {
1057 if (!desc->str)
1058 vty_out (vty, " %-s%s",
1059 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1060 VTY_NEWLINE);
1061 else if (desc_width >= strlen (desc->str))
1062 vty_out (vty, " %-*s %s%s", width,
1063 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1064 desc->str, VTY_NEWLINE);
1065 else
1066 vty_describe_fold (vty, width, desc_width, desc);
1067 }
1068
1069 cmd_free_strvec (vline);
1070 vector_free (describe);
1071
1072 vty_prompt (vty);
1073 vty_redraw_line (vty);
1074}
1075
9fc7ebf1 1076static void
718e3744 1077vty_clear_buf (struct vty *vty)
1078{
1079 memset (vty->buf, 0, vty->max);
1080}
1081
1082/* ^C stop current input and do not add command line to the history. */
1083static void
1084vty_stop_input (struct vty *vty)
1085{
1086 vty->cp = vty->length = 0;
1087 vty_clear_buf (vty);
1088 vty_out (vty, "%s", VTY_NEWLINE);
1089
1090 switch (vty->node)
1091 {
1092 case VIEW_NODE:
1093 case ENABLE_NODE:
1094 /* Nothing to do. */
1095 break;
1096 case CONFIG_NODE:
1097 case INTERFACE_NODE:
1098 case ZEBRA_NODE:
1099 case RIP_NODE:
1100 case RIPNG_NODE:
1101 case BGP_NODE:
1102 case RMAP_NODE:
1103 case OSPF_NODE:
1104 case OSPF6_NODE:
9e867fe6 1105 case ISIS_NODE:
718e3744 1106 case KEYCHAIN_NODE:
1107 case KEYCHAIN_KEY_NODE:
1108 case MASC_NODE:
1109 case VTY_NODE:
1110 vty_config_unlock (vty);
1111 vty->node = ENABLE_NODE;
1112 break;
1113 default:
1114 /* Unknown node, we have to ignore it. */
1115 break;
1116 }
1117 vty_prompt (vty);
1118
1119 /* Set history pointer to the latest one. */
1120 vty->hp = vty->hindex;
1121}
1122
1123/* Add current command line to the history buffer. */
1124static void
1125vty_hist_add (struct vty *vty)
1126{
1127 int index;
1128
1129 if (vty->length == 0)
1130 return;
1131
1132 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1133
1134 /* Ignore the same string as previous one. */
1135 if (vty->hist[index])
1136 if (strcmp (vty->buf, vty->hist[index]) == 0)
1137 {
1138 vty->hp = vty->hindex;
1139 return;
1140 }
1141
1142 /* Insert history entry. */
1143 if (vty->hist[vty->hindex])
1144 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1145 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1146
1147 /* History index rotation. */
1148 vty->hindex++;
1149 if (vty->hindex == VTY_MAXHIST)
1150 vty->hindex = 0;
1151
1152 vty->hp = vty->hindex;
1153}
1154
1155/* #define TELNET_OPTION_DEBUG */
1156
1157/* Get telnet window size. */
1158static int
1159vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1160{
1161#ifdef TELNET_OPTION_DEBUG
1162 int i;
1163
1164 for (i = 0; i < nbytes; i++)
1165 {
1166 switch (buf[i])
1167 {
1168 case IAC:
1169 vty_out (vty, "IAC ");
1170 break;
1171 case WILL:
1172 vty_out (vty, "WILL ");
1173 break;
1174 case WONT:
1175 vty_out (vty, "WONT ");
1176 break;
1177 case DO:
1178 vty_out (vty, "DO ");
1179 break;
1180 case DONT:
1181 vty_out (vty, "DONT ");
1182 break;
1183 case SB:
1184 vty_out (vty, "SB ");
1185 break;
1186 case SE:
1187 vty_out (vty, "SE ");
1188 break;
1189 case TELOPT_ECHO:
1190 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1191 break;
1192 case TELOPT_SGA:
1193 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1194 break;
1195 case TELOPT_NAWS:
1196 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1197 break;
1198 default:
1199 vty_out (vty, "%x ", buf[i]);
1200 break;
1201 }
1202 }
1203 vty_out (vty, "%s", VTY_NEWLINE);
1204
1205#endif /* TELNET_OPTION_DEBUG */
1206
1207 switch (buf[0])
1208 {
1209 case SB:
9fc7ebf1 1210 vty->sb_len = 0;
718e3744 1211 vty->iac_sb_in_progress = 1;
1212 return 0;
1213 break;
1214 case SE:
1215 {
5b8c1b0d 1216 if (!vty->iac_sb_in_progress)
718e3744 1217 return 0;
1218
9fc7ebf1 1219 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
718e3744 1220 {
1221 vty->iac_sb_in_progress = 0;
1222 return 0;
1223 }
9fc7ebf1 1224 switch (vty->sb_buf[0])
718e3744 1225 {
1226 case TELOPT_NAWS:
9fc7ebf1 1227 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1228 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1229 "should send %d characters, but we received %lu",
1230 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1231 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1232 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1233 "too small to handle the telnet NAWS option",
1234 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1235 else
1236 {
1237 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1238 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1239#ifdef TELNET_OPTION_DEBUG
1240 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1241 "width %d, height %d%s",
1242 vty->width, vty->height, VTY_NEWLINE);
1243#endif
1244 }
718e3744 1245 break;
1246 }
1247 vty->iac_sb_in_progress = 0;
1248 return 0;
1249 break;
1250 }
1251 default:
1252 break;
1253 }
1254 return 1;
1255}
1256
1257/* Execute current command line. */
1258static int
1259vty_execute (struct vty *vty)
1260{
1261 int ret;
1262
1263 ret = CMD_SUCCESS;
1264
1265 switch (vty->node)
1266 {
1267 case AUTH_NODE:
1268 case AUTH_ENABLE_NODE:
1269 vty_auth (vty, vty->buf);
1270 break;
1271 default:
1272 ret = vty_command (vty, vty->buf);
1273 if (vty->type == VTY_TERM)
1274 vty_hist_add (vty);
1275 break;
1276 }
1277
1278 /* Clear command line buffer. */
1279 vty->cp = vty->length = 0;
1280 vty_clear_buf (vty);
1281
5a646650 1282 if (vty->status != VTY_CLOSE )
718e3744 1283 vty_prompt (vty);
1284
1285 return ret;
1286}
1287
1288#define CONTROL(X) ((X) - '@')
1289#define VTY_NORMAL 0
1290#define VTY_PRE_ESCAPE 1
1291#define VTY_ESCAPE 2
1292
1293/* Escape character command map. */
1294static void
1295vty_escape_map (unsigned char c, struct vty *vty)
1296{
1297 switch (c)
1298 {
1299 case ('A'):
1300 vty_previous_line (vty);
1301 break;
1302 case ('B'):
1303 vty_next_line (vty);
1304 break;
1305 case ('C'):
1306 vty_forward_char (vty);
1307 break;
1308 case ('D'):
1309 vty_backward_char (vty);
1310 break;
1311 default:
1312 break;
1313 }
1314
1315 /* Go back to normal mode. */
1316 vty->escape = VTY_NORMAL;
1317}
1318
1319/* Quit print out to the buffer. */
1320static void
1321vty_buffer_reset (struct vty *vty)
1322{
1323 buffer_reset (vty->obuf);
1324 vty_prompt (vty);
1325 vty_redraw_line (vty);
1326}
1327
1328/* Read data via vty socket. */
1329static int
1330vty_read (struct thread *thread)
1331{
1332 int i;
718e3744 1333 int nbytes;
1334 unsigned char buf[VTY_READ_BUFSIZ];
1335
1336 int vty_sock = THREAD_FD (thread);
1337 struct vty *vty = THREAD_ARG (thread);
1338 vty->t_read = NULL;
1339
1340 /* Read raw data from socket */
9fc7ebf1 1341 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1342 {
1343 if (nbytes < 0)
1344 {
1345 if (ERRNO_IO_RETRY(errno))
1346 {
1347 vty_event (VTY_READ, vty_sock, vty);
1348 return 0;
1349 }
1350 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1351 __func__, vty->fd, safe_strerror(errno));
1352 }
1353 buffer_reset(vty->obuf);
1354 vty->status = VTY_CLOSE;
1355 }
718e3744 1356
1357 for (i = 0; i < nbytes; i++)
1358 {
1359 if (buf[i] == IAC)
1360 {
1361 if (!vty->iac)
1362 {
1363 vty->iac = 1;
1364 continue;
1365 }
1366 else
1367 {
1368 vty->iac = 0;
1369 }
1370 }
1371
1372 if (vty->iac_sb_in_progress && !vty->iac)
1373 {
9fc7ebf1 1374 if (vty->sb_len < sizeof(vty->sb_buf))
1375 vty->sb_buf[vty->sb_len] = buf[i];
1376 vty->sb_len++;
718e3744 1377 continue;
1378 }
1379
1380 if (vty->iac)
1381 {
1382 /* In case of telnet command */
5b8c1b0d 1383 int ret = 0;
e937253b 1384 ret = vty_telnet_option (vty, buf + i, nbytes - i);
718e3744 1385 vty->iac = 0;
1386 i += ret;
1387 continue;
1388 }
5b8c1b0d 1389
718e3744 1390
1391 if (vty->status == VTY_MORE)
1392 {
1393 switch (buf[i])
1394 {
1395 case CONTROL('C'):
1396 case 'q':
1397 case 'Q':
718e3744 1398 vty_buffer_reset (vty);
1399 break;
1400#if 0 /* More line does not work for "show ip bgp". */
1401 case '\n':
1402 case '\r':
1403 vty->status = VTY_MORELINE;
1404 break;
1405#endif
1406 default:
718e3744 1407 break;
1408 }
1409 continue;
1410 }
1411
1412 /* Escape character. */
1413 if (vty->escape == VTY_ESCAPE)
1414 {
1415 vty_escape_map (buf[i], vty);
1416 continue;
1417 }
1418
1419 /* Pre-escape status. */
1420 if (vty->escape == VTY_PRE_ESCAPE)
1421 {
1422 switch (buf[i])
1423 {
1424 case '[':
1425 vty->escape = VTY_ESCAPE;
1426 break;
1427 case 'b':
1428 vty_backward_word (vty);
1429 vty->escape = VTY_NORMAL;
1430 break;
1431 case 'f':
1432 vty_forward_word (vty);
1433 vty->escape = VTY_NORMAL;
1434 break;
1435 case 'd':
1436 vty_forward_kill_word (vty);
1437 vty->escape = VTY_NORMAL;
1438 break;
1439 case CONTROL('H'):
1440 case 0x7f:
1441 vty_backward_kill_word (vty);
1442 vty->escape = VTY_NORMAL;
1443 break;
1444 default:
1445 vty->escape = VTY_NORMAL;
1446 break;
1447 }
1448 continue;
1449 }
1450
1451 switch (buf[i])
1452 {
1453 case CONTROL('A'):
1454 vty_beginning_of_line (vty);
1455 break;
1456 case CONTROL('B'):
1457 vty_backward_char (vty);
1458 break;
1459 case CONTROL('C'):
1460 vty_stop_input (vty);
1461 break;
1462 case CONTROL('D'):
1463 vty_delete_char (vty);
1464 break;
1465 case CONTROL('E'):
1466 vty_end_of_line (vty);
1467 break;
1468 case CONTROL('F'):
1469 vty_forward_char (vty);
1470 break;
1471 case CONTROL('H'):
1472 case 0x7f:
1473 vty_delete_backward_char (vty);
1474 break;
1475 case CONTROL('K'):
1476 vty_kill_line (vty);
1477 break;
1478 case CONTROL('N'):
1479 vty_next_line (vty);
1480 break;
1481 case CONTROL('P'):
1482 vty_previous_line (vty);
1483 break;
1484 case CONTROL('T'):
1485 vty_transpose_chars (vty);
1486 break;
1487 case CONTROL('U'):
1488 vty_kill_line_from_beginning (vty);
1489 break;
1490 case CONTROL('W'):
1491 vty_backward_kill_word (vty);
1492 break;
1493 case CONTROL('Z'):
1494 vty_end_config (vty);
1495 break;
1496 case '\n':
1497 case '\r':
1498 vty_out (vty, "%s", VTY_NEWLINE);
1499 vty_execute (vty);
1500 break;
1501 case '\t':
1502 vty_complete_command (vty);
1503 break;
1504 case '?':
1505 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1506 vty_self_insert (vty, buf[i]);
1507 else
1508 vty_describe_command (vty);
1509 break;
1510 case '\033':
1511 if (i + 1 < nbytes && buf[i + 1] == '[')
1512 {
1513 vty->escape = VTY_ESCAPE;
1514 i++;
1515 }
1516 else
1517 vty->escape = VTY_PRE_ESCAPE;
1518 break;
1519 default:
1520 if (buf[i] > 31 && buf[i] < 127)
1521 vty_self_insert (vty, buf[i]);
1522 break;
1523 }
1524 }
1525
1526 /* Check status. */
1527 if (vty->status == VTY_CLOSE)
1528 vty_close (vty);
1529 else
1530 {
1531 vty_event (VTY_WRITE, vty_sock, vty);
1532 vty_event (VTY_READ, vty_sock, vty);
1533 }
1534 return 0;
1535}
1536
1537/* Flush buffer to the vty. */
1538static int
1539vty_flush (struct thread *thread)
1540{
1541 int erase;
9fc7ebf1 1542 buffer_status_t flushrc;
718e3744 1543 int vty_sock = THREAD_FD (thread);
1544 struct vty *vty = THREAD_ARG (thread);
9fc7ebf1 1545
718e3744 1546 vty->t_write = NULL;
1547
1548 /* Tempolary disable read thread. */
9fc7ebf1 1549 if ((vty->lines == 0) && vty->t_read)
1550 {
1551 thread_cancel (vty->t_read);
1552 vty->t_read = NULL;
1553 }
718e3744 1554
1555 /* Function execution continue. */
9fc7ebf1 1556 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
1557
1558 /* N.B. if width is 0, that means we don't know the window size. */
1559 if ((vty->lines == 0) || (vty->width == 0))
1560 flushrc = buffer_flush_available(vty->obuf, vty->fd);
1561 else if (vty->status == VTY_MORELINE)
1562 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1563 1, erase, 0);
1564 else
1565 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1566 vty->lines >= 0 ? vty->lines :
1567 vty->height,
1568 erase, 0);
1569 switch (flushrc)
1570 {
1571 case BUFFER_ERROR:
1572 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1573 vty->fd);
1574 buffer_reset(vty->obuf);
1575 vty_close(vty);
1576 return 0;
1577 case BUFFER_EMPTY:
1578 if (vty->status == VTY_CLOSE)
1579 vty_close (vty);
718e3744 1580 else
1581 {
9fc7ebf1 1582 vty->status = VTY_NORMAL;
718e3744 1583 if (vty->lines == 0)
9fc7ebf1 1584 vty_event (VTY_READ, vty_sock, vty);
718e3744 1585 }
9fc7ebf1 1586 break;
1587 case BUFFER_PENDING:
1588 /* There is more data waiting to be written. */
1589 vty->status = VTY_MORE;
1590 if (vty->lines == 0)
1591 vty_event (VTY_WRITE, vty_sock, vty);
1592 break;
1593 }
718e3744 1594
1595 return 0;
1596}
1597
1598/* Create new vty structure. */
9fc7ebf1 1599static struct vty *
718e3744 1600vty_create (int vty_sock, union sockunion *su)
1601{
1602 struct vty *vty;
1603
1604 /* Allocate new vty structure and set up default values. */
1605 vty = vty_new ();
1606 vty->fd = vty_sock;
1607 vty->type = VTY_TERM;
1608 vty->address = sockunion_su2str (su);
1609 if (no_password_check)
1610 {
1611 if (host.advanced)
1612 vty->node = ENABLE_NODE;
1613 else
1614 vty->node = VIEW_NODE;
1615 }
1616 else
1617 vty->node = AUTH_NODE;
1618 vty->fail = 0;
1619 vty->cp = 0;
1620 vty_clear_buf (vty);
1621 vty->length = 0;
1622 memset (vty->hist, 0, sizeof (vty->hist));
1623 vty->hp = 0;
1624 vty->hindex = 0;
1625 vector_set_index (vtyvec, vty_sock, vty);
1626 vty->status = VTY_NORMAL;
1627 vty->v_timeout = vty_timeout_val;
1628 if (host.lines >= 0)
1629 vty->lines = host.lines;
1630 else
1631 vty->lines = -1;
1632 vty->iac = 0;
1633 vty->iac_sb_in_progress = 0;
9fc7ebf1 1634 vty->sb_len = 0;
718e3744 1635
1636 if (! no_password_check)
1637 {
1638 /* Vty is not available if password isn't set. */
1639 if (host.password == NULL && host.password_encrypt == NULL)
1640 {
1641 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1642 vty->status = VTY_CLOSE;
1643 vty_close (vty);
1644 return NULL;
1645 }
1646 }
1647
1648 /* Say hello to the world. */
1649 vty_hello (vty);
1650 if (! no_password_check)
1651 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1652
1653 /* Setting up terminal. */
1654 vty_will_echo (vty);
1655 vty_will_suppress_go_ahead (vty);
1656
1657 vty_dont_linemode (vty);
1658 vty_do_window_size (vty);
1659 /* vty_dont_lflow_ahead (vty); */
1660
1661 vty_prompt (vty);
1662
1663 /* Add read/write thread. */
1664 vty_event (VTY_WRITE, vty_sock, vty);
1665 vty_event (VTY_READ, vty_sock, vty);
1666
1667 return vty;
1668}
1669
1670/* Accept connection from the network. */
1671static int
1672vty_accept (struct thread *thread)
1673{
1674 int vty_sock;
1675 struct vty *vty;
1676 union sockunion su;
1677 int ret;
1678 unsigned int on;
1679 int accept_sock;
1680 struct prefix *p = NULL;
1681 struct access_list *acl = NULL;
1682
1683 accept_sock = THREAD_FD (thread);
1684
1685 /* We continue hearing vty socket. */
1686 vty_event (VTY_SERV, accept_sock, NULL);
1687
1688 memset (&su, 0, sizeof (union sockunion));
1689
1690 /* We can handle IPv4 or IPv6 socket. */
1691 vty_sock = sockunion_accept (accept_sock, &su);
1692 if (vty_sock < 0)
1693 {
6099b3b5 1694 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
718e3744 1695 return -1;
1696 }
9fc7ebf1 1697 set_nonblocking(vty_sock);
718e3744 1698
1699 p = sockunion2hostprefix (&su);
1700
1701 /* VTY's accesslist apply. */
1702 if (p->family == AF_INET && vty_accesslist_name)
1703 {
1704 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1705 (access_list_apply (acl, p) == FILTER_DENY))
1706 {
1707 char *buf;
1708 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1709 (buf = sockunion_su2str (&su)));
1710 free (buf);
1711 close (vty_sock);
1712
1713 /* continue accepting connections */
1714 vty_event (VTY_SERV, accept_sock, NULL);
1715
1716 prefix_free (p);
1717
1718 return 0;
1719 }
1720 }
1721
1722#ifdef HAVE_IPV6
1723 /* VTY's ipv6 accesslist apply. */
1724 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1725 {
1726 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1727 (access_list_apply (acl, p) == FILTER_DENY))
1728 {
1729 char *buf;
1730 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1731 (buf = sockunion_su2str (&su)));
1732 free (buf);
1733 close (vty_sock);
1734
1735 /* continue accepting connections */
1736 vty_event (VTY_SERV, accept_sock, NULL);
1737
1738 prefix_free (p);
1739
1740 return 0;
1741 }
1742 }
1743#endif /* HAVE_IPV6 */
1744
1745 prefix_free (p);
1746
1747 on = 1;
1748 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1749 (char *) &on, sizeof (on));
1750 if (ret < 0)
1751 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
6099b3b5 1752 safe_strerror (errno));
718e3744 1753
1754 vty = vty_create (vty_sock, &su);
1755
1756 return 0;
1757}
1758
1759#if defined(HAVE_IPV6) && !defined(NRL)
9fc7ebf1 1760static void
718e3744 1761vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1762{
1763 int ret;
1764 struct addrinfo req;
1765 struct addrinfo *ainfo;
1766 struct addrinfo *ainfo_save;
1767 int sock;
1768 char port_str[BUFSIZ];
1769
1770 memset (&req, 0, sizeof (struct addrinfo));
1771 req.ai_flags = AI_PASSIVE;
1772 req.ai_family = AF_UNSPEC;
1773 req.ai_socktype = SOCK_STREAM;
1774 sprintf (port_str, "%d", port);
1775 port_str[sizeof (port_str) - 1] = '\0';
1776
1777 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1778
1779 if (ret != 0)
1780 {
1781 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1782 exit (1);
1783 }
1784
1785 ainfo_save = ainfo;
1786
1787 do
1788 {
1789 if (ainfo->ai_family != AF_INET
1790#ifdef HAVE_IPV6
1791 && ainfo->ai_family != AF_INET6
1792#endif /* HAVE_IPV6 */
1793 )
1794 continue;
1795
1796 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1797 if (sock < 0)
1798 continue;
1799
1800 sockopt_reuseaddr (sock);
1801 sockopt_reuseport (sock);
1802
1803 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1804 if (ret < 0)
1805 {
1806 close (sock); /* Avoid sd leak. */
1807 continue;
1808 }
1809
1810 ret = listen (sock, 3);
1811 if (ret < 0)
1812 {
1813 close (sock); /* Avoid sd leak. */
1814 continue;
1815 }
1816
1817 vty_event (VTY_SERV, sock, NULL);
1818 }
1819 while ((ainfo = ainfo->ai_next) != NULL);
1820
1821 freeaddrinfo (ainfo_save);
1822}
1823#endif /* HAVE_IPV6 && ! NRL */
1824
1825/* Make vty server socket. */
9fc7ebf1 1826static void
29db05b4 1827vty_serv_sock_family (const char* addr, unsigned short port, int family)
718e3744 1828{
1829 int ret;
1830 union sockunion su;
1831 int accept_sock;
29db05b4 1832 void* naddr=NULL;
718e3744 1833
1834 memset (&su, 0, sizeof (union sockunion));
1835 su.sa.sa_family = family;
29db05b4 1836 if(addr)
1837 switch(family)
1838 {
1839 case AF_INET:
1840 naddr=&su.sin.sin_addr;
1841#ifdef HAVE_IPV6
1842 case AF_INET6:
1843 naddr=&su.sin6.sin6_addr;
1844#endif
1845 }
1846
1847 if(naddr)
1848 switch(inet_pton(family,addr,naddr))
1849 {
1850 case -1:
1851 zlog_err("bad address %s",addr);
1852 naddr=NULL;
1853 break;
1854 case 0:
6099b3b5 1855 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
29db05b4 1856 naddr=NULL;
1857 }
718e3744 1858
1859 /* Make new socket. */
1860 accept_sock = sockunion_stream_socket (&su);
1861 if (accept_sock < 0)
1862 return;
1863
1864 /* This is server, so reuse address. */
1865 sockopt_reuseaddr (accept_sock);
1866 sockopt_reuseport (accept_sock);
1867
1868 /* Bind socket to universal address and given port. */
29db05b4 1869 ret = sockunion_bind (accept_sock, &su, port, naddr);
718e3744 1870 if (ret < 0)
1871 {
29db05b4 1872 zlog_warn("can't bind socket");
718e3744 1873 close (accept_sock); /* Avoid sd leak. */
1874 return;
1875 }
1876
1877 /* Listen socket under queue 3. */
1878 ret = listen (accept_sock, 3);
1879 if (ret < 0)
1880 {
1881 zlog (NULL, LOG_WARNING, "can't listen socket");
1882 close (accept_sock); /* Avoid sd leak. */
1883 return;
1884 }
1885
1886 /* Add vty server event. */
1887 vty_event (VTY_SERV, accept_sock, NULL);
1888}
1889
1890#ifdef VTYSH
1891/* For sockaddr_un. */
1892#include <sys/un.h>
1893
1894/* VTY shell UNIX domain socket. */
9fc7ebf1 1895static void
6ad96ea1 1896vty_serv_un (const char *path)
718e3744 1897{
1898 int ret;
75e15fe4 1899 int sock, len;
718e3744 1900 struct sockaddr_un serv;
1901 mode_t old_mask;
edd7c245 1902 struct zprivs_ids_t ids;
1903
718e3744 1904 /* First of all, unlink existing socket */
1905 unlink (path);
1906
1907 /* Set umask */
1921e6f8 1908 old_mask = umask (0007);
718e3744 1909
1910 /* Make UNIX domain socket. */
1911 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1912 if (sock < 0)
1913 {
6a52d0d1 1914 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
718e3744 1915 return;
1916 }
1917
1918 /* Make server socket. */
1919 memset (&serv, 0, sizeof (struct sockaddr_un));
1920 serv.sun_family = AF_UNIX;
1921 strncpy (serv.sun_path, path, strlen (path));
1922#ifdef HAVE_SUN_LEN
1923 len = serv.sun_len = SUN_LEN(&serv);
1924#else
1925 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1926#endif /* HAVE_SUN_LEN */
1927
1928 ret = bind (sock, (struct sockaddr *) &serv, len);
1929 if (ret < 0)
1930 {
6a52d0d1 1931 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
718e3744 1932 close (sock); /* Avoid sd leak. */
1933 return;
1934 }
1935
1936 ret = listen (sock, 5);
1937 if (ret < 0)
1938 {
6a52d0d1 1939 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
718e3744 1940 close (sock); /* Avoid sd leak. */
1941 return;
1942 }
1943
1944 umask (old_mask);
1945
edd7c245 1946 zprivs_get_ids(&ids);
1947
1948 if (ids.gid_vty > 0)
1949 {
1950 /* set group of socket */
1951 if ( chown (path, -1, ids.gid_vty) )
1952 {
1953 zlog_err ("vty_serv_un: could chown socket, %s",
6099b3b5 1954 safe_strerror (errno) );
edd7c245 1955 }
1956 }
1957
718e3744 1958 vty_event (VTYSH_SERV, sock, NULL);
1959}
1960
1961/* #define VTYSH_DEBUG 1 */
1962
1963static int
1964vtysh_accept (struct thread *thread)
1965{
1966 int accept_sock;
1967 int sock;
1968 int client_len;
1969 struct sockaddr_un client;
1970 struct vty *vty;
1971
1972 accept_sock = THREAD_FD (thread);
1973
1974 vty_event (VTYSH_SERV, accept_sock, NULL);
1975
1976 memset (&client, 0, sizeof (struct sockaddr_un));
1977 client_len = sizeof (struct sockaddr_un);
1978
e473b032 1979 sock = accept (accept_sock, (struct sockaddr *) &client,
1980 (socklen_t *) &client_len);
718e3744 1981
1982 if (sock < 0)
1983 {
6099b3b5 1984 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
718e3744 1985 return -1;
1986 }
1987
9fc7ebf1 1988 if (set_nonblocking(sock) < 0)
75e15fe4 1989 {
9fc7ebf1 1990 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
1991 " %s, closing", sock, safe_strerror (errno));
75e15fe4 1992 close (sock);
1993 return -1;
1994 }
dccfb190 1995
718e3744 1996#ifdef VTYSH_DEBUG
1997 printf ("VTY shell accept\n");
1998#endif /* VTYSH_DEBUG */
1999
2000 vty = vty_new ();
2001 vty->fd = sock;
2002 vty->type = VTY_SHELL_SERV;
2003 vty->node = VIEW_NODE;
2004
2005 vty_event (VTYSH_READ, sock, vty);
2006
2007 return 0;
2008}
2009
9fc7ebf1 2010static int
2011vtysh_flush(struct vty *vty)
2012{
2013 switch (buffer_flush_available(vty->obuf, vty->fd))
2014 {
2015 case BUFFER_PENDING:
2016 vty_event(VTYSH_WRITE, vty->fd, vty);
2017 break;
2018 case BUFFER_ERROR:
2019 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
2020 buffer_reset(vty->obuf);
2021 vty_close(vty);
2022 return -1;
2023 break;
2024 case BUFFER_EMPTY:
2025 break;
2026 }
2027 return 0;
2028}
2029
718e3744 2030static int
2031vtysh_read (struct thread *thread)
2032{
2033 int ret;
2034 int sock;
2035 int nbytes;
2036 struct vty *vty;
2037 unsigned char buf[VTY_READ_BUFSIZ];
9fc7ebf1 2038 unsigned char *p;
718e3744 2039 u_char header[4] = {0, 0, 0, 0};
2040
2041 sock = THREAD_FD (thread);
2042 vty = THREAD_ARG (thread);
2043 vty->t_read = NULL;
2044
9fc7ebf1 2045 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
718e3744 2046 {
9fc7ebf1 2047 if (nbytes < 0)
2048 {
2049 if (ERRNO_IO_RETRY(errno))
2050 {
2051 vty_event (VTYSH_READ, sock, vty);
2052 return 0;
2053 }
2054 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2055 __func__, sock, safe_strerror(errno));
2056 }
2057 buffer_reset(vty->obuf);
718e3744 2058 vty_close (vty);
2059#ifdef VTYSH_DEBUG
2060 printf ("close vtysh\n");
2061#endif /* VTYSH_DEBUG */
2062 return 0;
2063 }
2064
2065#ifdef VTYSH_DEBUG
9fc7ebf1 2066 printf ("line: %.*s\n", nbytes, buf);
718e3744 2067#endif /* VTYSH_DEBUG */
2068
9fc7ebf1 2069 for (p = buf; p < buf+nbytes; p++)
2070 {
2071 vty_ensure(vty, vty->length+1);
2072 vty->buf[vty->length++] = *p;
2073 if (*p == '\0')
2074 {
2075 /* Pass this line to parser. */
2076 ret = vty_execute (vty);
2077 /* Note that vty_execute clears the command buffer and resets
2078 vty->length to 0. */
718e3744 2079
9fc7ebf1 2080 /* Return result. */
718e3744 2081#ifdef VTYSH_DEBUG
9fc7ebf1 2082 printf ("result: %d\n", ret);
2083 printf ("vtysh node: %d\n", vty->node);
718e3744 2084#endif /* VTYSH_DEBUG */
2085
9fc7ebf1 2086 header[3] = ret;
2087 buffer_put(vty->obuf, header, 4);
2088
2089 if (!vty->t_write && (vtysh_flush(vty) < 0))
2090 /* Try to flush results; exit if a write error occurs. */
2091 return 0;
2092 }
2093 }
718e3744 2094
2095 vty_event (VTYSH_READ, sock, vty);
2096
2097 return 0;
2098}
49ff6d9d 2099
2100static int
2101vtysh_write (struct thread *thread)
2102{
2103 struct vty *vty = THREAD_ARG (thread);
2104
2105 vty->t_write = NULL;
9fc7ebf1 2106 vtysh_flush(vty);
976d8c73 2107 return 0;
49ff6d9d 2108}
2109
718e3744 2110#endif /* VTYSH */
2111
2112/* Determine address family to bind. */
2113void
6ad96ea1 2114vty_serv_sock (const char *addr, unsigned short port, const char *path)
718e3744 2115{
2116 /* If port is set to 0, do not listen on TCP/IP at all! */
2117 if (port)
2118 {
2119
2120#ifdef HAVE_IPV6
2121#ifdef NRL
29db05b4 2122 vty_serv_sock_family (addr, port, AF_INET);
2123 vty_serv_sock_family (addr, port, AF_INET6);
718e3744 2124#else /* ! NRL */
29db05b4 2125 vty_serv_sock_addrinfo (addr, port);
718e3744 2126#endif /* NRL*/
2127#else /* ! HAVE_IPV6 */
29db05b4 2128 vty_serv_sock_family (addr,port, AF_INET);
718e3744 2129#endif /* HAVE_IPV6 */
2130 }
2131
2132#ifdef VTYSH
2133 vty_serv_un (path);
2134#endif /* VTYSH */
2135}
2136
2137/* Close vty interface. */
2138void
2139vty_close (struct vty *vty)
2140{
2141 int i;
2142
2143 /* Cancel threads.*/
2144 if (vty->t_read)
2145 thread_cancel (vty->t_read);
2146 if (vty->t_write)
2147 thread_cancel (vty->t_write);
2148 if (vty->t_timeout)
2149 thread_cancel (vty->t_timeout);
718e3744 2150
2151 /* Flush buffer. */
9fc7ebf1 2152 buffer_flush_all (vty->obuf, vty->fd);
718e3744 2153
2154 /* Free input buffer. */
2155 buffer_free (vty->obuf);
2156
718e3744 2157 /* Free command history. */
2158 for (i = 0; i < VTY_MAXHIST; i++)
2159 if (vty->hist[i])
2160 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2161
2162 /* Unset vector. */
2163 vector_unset (vtyvec, vty->fd);
2164
2165 /* Close socket. */
2166 if (vty->fd > 0)
2167 close (vty->fd);
2168
2169 if (vty->address)
05865c90 2170 XFREE (MTYPE_TMP, vty->address);
718e3744 2171 if (vty->buf)
2172 XFREE (MTYPE_VTY, vty->buf);
2173
2174 /* Check configure. */
2175 vty_config_unlock (vty);
2176
2177 /* OK free vty. */
2178 XFREE (MTYPE_VTY, vty);
2179}
2180
2181/* When time out occur output message then close connection. */
2182static int
2183vty_timeout (struct thread *thread)
2184{
2185 struct vty *vty;
2186
2187 vty = THREAD_ARG (thread);
2188 vty->t_timeout = NULL;
2189 vty->v_timeout = 0;
2190
2191 /* Clear buffer*/
2192 buffer_reset (vty->obuf);
2193 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2194
2195 /* Close connection. */
2196 vty->status = VTY_CLOSE;
2197 vty_close (vty);
2198
2199 return 0;
2200}
2201
2202/* Read up configuration file from file_name. */
2203static void
2204vty_read_file (FILE *confp)
2205{
2206 int ret;
2207 struct vty *vty;
2208
2209 vty = vty_new ();
2210 vty->fd = 0; /* stdout */
2211 vty->type = VTY_TERM;
2212 vty->node = CONFIG_NODE;
2213
2214 /* Execute configuration file */
2215 ret = config_from_file (vty, confp);
2216
7021c425 2217 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
718e3744 2218 {
2219 switch (ret)
7021c425 2220 {
2221 case CMD_ERR_AMBIGUOUS:
2222 fprintf (stderr, "Ambiguous command.\n");
2223 break;
2224 case CMD_ERR_NO_MATCH:
2225 fprintf (stderr, "There is no such command.\n");
2226 break;
2227 }
718e3744 2228 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2229 vty->buf);
2230 vty_close (vty);
2231 exit (1);
2232 }
2233
2234 vty_close (vty);
2235}
2236
9fc7ebf1 2237static FILE *
718e3744 2238vty_use_backup_config (char *fullpath)
2239{
2240 char *fullpath_sav, *fullpath_tmp;
2241 FILE *ret = NULL;
2242 struct stat buf;
2243 int tmp, sav;
2244 int c;
2245 char buffer[512];
2246
2247 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2248 strcpy (fullpath_sav, fullpath);
2249 strcat (fullpath_sav, CONF_BACKUP_EXT);
2250 if (stat (fullpath_sav, &buf) == -1)
2251 {
2252 free (fullpath_sav);
2253 return NULL;
2254 }
2255
2256 fullpath_tmp = malloc (strlen (fullpath) + 8);
2257 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2258
2259 /* Open file to configuration write. */
2260 tmp = mkstemp (fullpath_tmp);
2261 if (tmp < 0)
2262 {
2263 free (fullpath_sav);
2264 free (fullpath_tmp);
2265 return NULL;
2266 }
2267
2268 sav = open (fullpath_sav, O_RDONLY);
2269 if (sav < 0)
2270 {
3dbf9969 2271 unlink (fullpath_tmp);
718e3744 2272 free (fullpath_sav);
2273 free (fullpath_tmp);
718e3744 2274 return NULL;
2275 }
2276
2277 while((c = read (sav, buffer, 512)) > 0)
2278 write (tmp, buffer, c);
2279
2280 close (sav);
2281 close (tmp);
2282
aa593d5e 2283 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2284 {
3dbf9969 2285 unlink (fullpath_tmp);
aa593d5e 2286 free (fullpath_sav);
2287 free (fullpath_tmp);
aa593d5e 2288 return NULL;
2289 }
2290
718e3744 2291 if (link (fullpath_tmp, fullpath) == 0)
2292 ret = fopen (fullpath, "r");
2293
2294 unlink (fullpath_tmp);
2295
2296 free (fullpath_sav);
2297 free (fullpath_tmp);
12f6ea23 2298 return ret;
718e3744 2299}
2300
2301/* Read up configuration file from file_name. */
2302void
2303vty_read_config (char *config_file,
320ec10a 2304 char *config_default_dir)
718e3744 2305{
ccc9235e 2306 char cwd[MAXPATHLEN];
718e3744 2307 FILE *confp = NULL;
2308 char *fullpath;
05865c90 2309 char *tmp = NULL;
718e3744 2310
2311 /* If -f flag specified. */
2312 if (config_file != NULL)
2313 {
2314 if (! IS_DIRECTORY_SEP (config_file[0]))
320ec10a 2315 {
2316 getcwd (cwd, MAXPATHLEN);
05865c90 2317 tmp = XMALLOC (MTYPE_TMP,
320ec10a 2318 strlen (cwd) + strlen (config_file) + 2);
05865c90 2319 sprintf (tmp, "%s/%s", cwd, config_file);
2320 fullpath = tmp;
320ec10a 2321 }
718e3744 2322 else
320ec10a 2323 fullpath = config_file;
718e3744 2324
2325 confp = fopen (fullpath, "r");
2326
2327 if (confp == NULL)
320ec10a 2328 {
3d1dc857 2329 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2330 __func__, fullpath, safe_strerror (errno));
2331
320ec10a 2332 confp = vty_use_backup_config (fullpath);
2333 if (confp)
2334 fprintf (stderr, "WARNING: using backup configuration file!\n");
2335 else
2336 {
2337 fprintf (stderr, "can't open configuration file [%s]\n",
3d1dc857 2338 config_file);
320ec10a 2339 exit(1);
2340 }
2341 }
718e3744 2342 }
2343 else
2344 {
718e3744 2345#ifdef VTYSH
320ec10a 2346 int ret;
2347 struct stat conf_stat;
2348
2349 /* !!!!PLEASE LEAVE!!!!
2350 * This is NEEDED for use with vtysh -b, or else you can get
2351 * a real configuration food fight with a lot garbage in the
2352 * merged configuration file it creates coming from the per
2353 * daemon configuration files. This also allows the daemons
2354 * to start if there default configuration file is not
2355 * present or ignore them, as needed when using vtysh -b to
2356 * configure the daemons at boot - MAG
2357 */
2358
2359 /* Stat for vtysh Zebra.conf, if found startup and wait for
2360 * boot configuration
2361 */
2362
2363 if ( strstr(config_default_dir, "vtysh") == NULL)
2364 {
2365 ret = stat (integrate_default, &conf_stat);
2366 if (ret >= 0)
2367 return;
2368 }
718e3744 2369#endif /* VTYSH */
2370
320ec10a 2371 confp = fopen (config_default_dir, "r");
2372 if (confp == NULL)
2373 {
3d1dc857 2374 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2375 __func__, config_default_dir, safe_strerror (errno));
2376
320ec10a 2377 confp = vty_use_backup_config (config_default_dir);
2378 if (confp)
2379 {
2380 fprintf (stderr, "WARNING: using backup configuration file!\n");
2381 fullpath = config_default_dir;
2382 }
2383 else
2384 {
2385 fprintf (stderr, "can't open configuration file [%s]\n",
2386 config_default_dir);
2387 exit (1);
3d1dc857 2388 }
320ec10a 2389 }
718e3744 2390 else
320ec10a 2391 fullpath = config_default_dir;
2392 }
2393
718e3744 2394 vty_read_file (confp);
2395
2396 fclose (confp);
2397
2398 host_config_set (fullpath);
05865c90 2399
2400 if (tmp)
2401 XFREE (MTYPE_TMP, fullpath);
718e3744 2402}
2403
2404/* Small utility function which output log to the VTY. */
2405void
274a4a44 2406vty_log (const char *level, const char *proto_str,
2407 const char *format, va_list va)
718e3744 2408{
8c328f11 2409 unsigned int i;
718e3744 2410 struct vty *vty;
2411
55468c86 2412 for (i = 0; i < vector_active (vtyvec); i++)
718e3744 2413 if ((vty = vector_slot (vtyvec, i)) != NULL)
2414 if (vty->monitor)
d246bd96 2415 {
2416 va_list ac;
2417 va_copy(ac, va);
274a4a44 2418 vty_log_out (vty, level, proto_str, format, ac);
d246bd96 2419 va_end(ac);
2420 }
718e3744 2421}
2422
274a4a44 2423/* Async-signal-safe version of vty_log for fixed strings. */
2424void
2425vty_log_fixed (const char *buf, size_t len)
2426{
2427 unsigned int i;
9fc7ebf1 2428 struct iovec iov[2];
2429
926fe8f1 2430 iov[0].iov_base = (void *)buf;
9fc7ebf1 2431 iov[0].iov_len = len;
926fe8f1 2432 iov[1].iov_base = (void *)"\r\n";
9fc7ebf1 2433 iov[1].iov_len = 2;
274a4a44 2434
55468c86 2435 for (i = 0; i < vector_active (vtyvec); i++)
274a4a44 2436 {
2437 struct vty *vty;
9fc7ebf1 2438 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2439 /* N.B. We don't care about the return code, since process is
2440 most likely just about to die anyway. */
2441 writev(vty->fd, iov, 2);
274a4a44 2442 }
2443}
2444
718e3744 2445int
2446vty_config_lock (struct vty *vty)
2447{
2448 if (vty_config == 0)
2449 {
2450 vty->config = 1;
2451 vty_config = 1;
2452 }
2453 return vty->config;
2454}
2455
2456int
2457vty_config_unlock (struct vty *vty)
2458{
2459 if (vty_config == 1 && vty->config == 1)
2460 {
2461 vty->config = 0;
2462 vty_config = 0;
2463 }
2464 return vty->config;
2465}
2466\f
2467/* Master of the threads. */
b21b19c5 2468static struct thread_master *master;
718e3744 2469
2470static void
2471vty_event (enum event event, int sock, struct vty *vty)
2472{
2473 struct thread *vty_serv_thread;
2474
2475 switch (event)
2476 {
2477 case VTY_SERV:
2478 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2479 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2480 break;
2481#ifdef VTYSH
2482 case VTYSH_SERV:
2483 thread_add_read (master, vtysh_accept, vty, sock);
2484 break;
2485 case VTYSH_READ:
49ff6d9d 2486 vty->t_read = thread_add_read (master, vtysh_read, vty, sock);
2487 break;
2488 case VTYSH_WRITE:
2489 vty->t_write = thread_add_write (master, vtysh_write, vty, sock);
718e3744 2490 break;
2491#endif /* VTYSH */
2492 case VTY_READ:
2493 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2494
2495 /* Time out treatment. */
2496 if (vty->v_timeout)
2497 {
2498 if (vty->t_timeout)
2499 thread_cancel (vty->t_timeout);
2500 vty->t_timeout =
2501 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2502 }
2503 break;
2504 case VTY_WRITE:
2505 if (! vty->t_write)
2506 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2507 break;
2508 case VTY_TIMEOUT_RESET:
2509 if (vty->t_timeout)
2510 {
2511 thread_cancel (vty->t_timeout);
2512 vty->t_timeout = NULL;
2513 }
2514 if (vty->v_timeout)
2515 {
2516 vty->t_timeout =
2517 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2518 }
2519 break;
2520 }
2521}
2522\f
2523DEFUN (config_who,
2524 config_who_cmd,
2525 "who",
2526 "Display who is on vty\n")
2527{
8c328f11 2528 unsigned int i;
718e3744 2529 struct vty *v;
2530
55468c86 2531 for (i = 0; i < vector_active (vtyvec); i++)
718e3744 2532 if ((v = vector_slot (vtyvec, i)) != NULL)
2533 vty_out (vty, "%svty[%d] connected from %s.%s",
2534 v->config ? "*" : " ",
2535 i, v->address, VTY_NEWLINE);
2536 return CMD_SUCCESS;
2537}
2538
2539/* Move to vty configuration mode. */
2540DEFUN (line_vty,
2541 line_vty_cmd,
2542 "line vty",
2543 "Configure a terminal line\n"
2544 "Virtual terminal\n")
2545{
2546 vty->node = VTY_NODE;
2547 return CMD_SUCCESS;
2548}
2549
2550/* Set time out value. */
9fc7ebf1 2551static int
9035efaa 2552exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
718e3744 2553{
2554 unsigned long timeout = 0;
2555
2556 /* min_str and sec_str are already checked by parser. So it must be
2557 all digit string. */
2558 if (min_str)
2559 {
2560 timeout = strtol (min_str, NULL, 10);
2561 timeout *= 60;
2562 }
2563 if (sec_str)
2564 timeout += strtol (sec_str, NULL, 10);
2565
2566 vty_timeout_val = timeout;
2567 vty->v_timeout = timeout;
2568 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2569
2570
2571 return CMD_SUCCESS;
2572}
2573
2574DEFUN (exec_timeout_min,
2575 exec_timeout_min_cmd,
2576 "exec-timeout <0-35791>",
2577 "Set timeout value\n"
2578 "Timeout value in minutes\n")
2579{
2580 return exec_timeout (vty, argv[0], NULL);
2581}
2582
2583DEFUN (exec_timeout_sec,
2584 exec_timeout_sec_cmd,
2585 "exec-timeout <0-35791> <0-2147483>",
2586 "Set the EXEC timeout\n"
2587 "Timeout in minutes\n"
2588 "Timeout in seconds\n")
2589{
2590 return exec_timeout (vty, argv[0], argv[1]);
2591}
2592
2593DEFUN (no_exec_timeout,
2594 no_exec_timeout_cmd,
2595 "no exec-timeout",
2596 NO_STR
2597 "Set the EXEC timeout\n")
2598{
2599 return exec_timeout (vty, NULL, NULL);
2600}
2601
2602/* Set vty access class. */
2603DEFUN (vty_access_class,
2604 vty_access_class_cmd,
2605 "access-class WORD",
2606 "Filter connections based on an IP access list\n"
2607 "IP access list\n")
2608{
2609 if (vty_accesslist_name)
2610 XFREE(MTYPE_VTY, vty_accesslist_name);
2611
2612 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2613
2614 return CMD_SUCCESS;
2615}
2616
2617/* Clear vty access class. */
2618DEFUN (no_vty_access_class,
2619 no_vty_access_class_cmd,
2620 "no access-class [WORD]",
2621 NO_STR
2622 "Filter connections based on an IP access list\n"
2623 "IP access list\n")
2624{
2625 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2626 {
2627 vty_out (vty, "Access-class is not currently applied to vty%s",
2628 VTY_NEWLINE);
2629 return CMD_WARNING;
2630 }
2631
2632 XFREE(MTYPE_VTY, vty_accesslist_name);
2633
2634 vty_accesslist_name = NULL;
2635
2636 return CMD_SUCCESS;
2637}
2638
2639#ifdef HAVE_IPV6
2640/* Set vty access class. */
2641DEFUN (vty_ipv6_access_class,
2642 vty_ipv6_access_class_cmd,
2643 "ipv6 access-class WORD",
2644 IPV6_STR
2645 "Filter connections based on an IP access list\n"
2646 "IPv6 access list\n")
2647{
2648 if (vty_ipv6_accesslist_name)
2649 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2650
2651 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2652
2653 return CMD_SUCCESS;
2654}
2655
2656/* Clear vty access class. */
2657DEFUN (no_vty_ipv6_access_class,
2658 no_vty_ipv6_access_class_cmd,
2659 "no ipv6 access-class [WORD]",
2660 NO_STR
2661 IPV6_STR
2662 "Filter connections based on an IP access list\n"
2663 "IPv6 access list\n")
2664{
2665 if (! vty_ipv6_accesslist_name ||
2666 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2667 {
2668 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2669 VTY_NEWLINE);
2670 return CMD_WARNING;
2671 }
2672
2673 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2674
2675 vty_ipv6_accesslist_name = NULL;
2676
2677 return CMD_SUCCESS;
2678}
2679#endif /* HAVE_IPV6 */
2680
2681/* vty login. */
2682DEFUN (vty_login,
2683 vty_login_cmd,
2684 "login",
2685 "Enable password checking\n")
2686{
2687 no_password_check = 0;
2688 return CMD_SUCCESS;
2689}
2690
2691DEFUN (no_vty_login,
2692 no_vty_login_cmd,
2693 "no login",
2694 NO_STR
2695 "Enable password checking\n")
2696{
2697 no_password_check = 1;
2698 return CMD_SUCCESS;
2699}
2700
2701DEFUN (service_advanced_vty,
2702 service_advanced_vty_cmd,
2703 "service advanced-vty",
2704 "Set up miscellaneous service\n"
2705 "Enable advanced mode vty interface\n")
2706{
2707 host.advanced = 1;
2708 return CMD_SUCCESS;
2709}
2710
2711DEFUN (no_service_advanced_vty,
2712 no_service_advanced_vty_cmd,
2713 "no service advanced-vty",
2714 NO_STR
2715 "Set up miscellaneous service\n"
2716 "Enable advanced mode vty interface\n")
2717{
2718 host.advanced = 0;
2719 return CMD_SUCCESS;
2720}
2721
2722DEFUN (terminal_monitor,
2723 terminal_monitor_cmd,
2724 "terminal monitor",
2725 "Set terminal line parameters\n"
2726 "Copy debug output to the current terminal line\n")
2727{
2728 vty->monitor = 1;
2729 return CMD_SUCCESS;
2730}
2731
2732DEFUN (terminal_no_monitor,
2733 terminal_no_monitor_cmd,
2734 "terminal no monitor",
2735 "Set terminal line parameters\n"
2736 NO_STR
2737 "Copy debug output to the current terminal line\n")
2738{
2739 vty->monitor = 0;
2740 return CMD_SUCCESS;
2741}
2742
2743DEFUN (show_history,
2744 show_history_cmd,
2745 "show history",
2746 SHOW_STR
2747 "Display the session command history\n")
2748{
2749 int index;
2750
2751 for (index = vty->hindex + 1; index != vty->hindex;)
2752 {
2753 if (index == VTY_MAXHIST)
2754 {
2755 index = 0;
2756 continue;
2757 }
2758
2759 if (vty->hist[index] != NULL)
2760 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2761
2762 index++;
2763 }
2764
2765 return CMD_SUCCESS;
2766}
2767
2768/* Display current configuration. */
9fc7ebf1 2769static int
718e3744 2770vty_config_write (struct vty *vty)
2771{
2772 vty_out (vty, "line vty%s", VTY_NEWLINE);
2773
2774 if (vty_accesslist_name)
2775 vty_out (vty, " access-class %s%s",
2776 vty_accesslist_name, VTY_NEWLINE);
2777
2778 if (vty_ipv6_accesslist_name)
2779 vty_out (vty, " ipv6 access-class %s%s",
2780 vty_ipv6_accesslist_name, VTY_NEWLINE);
2781
2782 /* exec-timeout */
2783 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2784 vty_out (vty, " exec-timeout %ld %ld%s",
2785 vty_timeout_val / 60,
2786 vty_timeout_val % 60, VTY_NEWLINE);
2787
2788 /* login */
2789 if (no_password_check)
2790 vty_out (vty, " no login%s", VTY_NEWLINE);
2791
2792 vty_out (vty, "!%s", VTY_NEWLINE);
2793
2794 return CMD_SUCCESS;
2795}
2796
2797struct cmd_node vty_node =
2798{
2799 VTY_NODE,
2800 "%s(config-line)# ",
e7168df4 2801 1,
718e3744 2802};
2803
2804/* Reset all VTY status. */
2805void
2806vty_reset ()
2807{
8c328f11 2808 unsigned int i;
718e3744 2809 struct vty *vty;
2810 struct thread *vty_serv_thread;
2811
55468c86 2812 for (i = 0; i < vector_active (vtyvec); i++)
718e3744 2813 if ((vty = vector_slot (vtyvec, i)) != NULL)
2814 {
2815 buffer_reset (vty->obuf);
2816 vty->status = VTY_CLOSE;
2817 vty_close (vty);
2818 }
2819
55468c86 2820 for (i = 0; i < vector_active (Vvty_serv_thread); i++)
718e3744 2821 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2822 {
2823 thread_cancel (vty_serv_thread);
2824 vector_slot (Vvty_serv_thread, i) = NULL;
2825 close (i);
2826 }
2827
2828 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2829
2830 if (vty_accesslist_name)
2831 {
2832 XFREE(MTYPE_VTY, vty_accesslist_name);
2833 vty_accesslist_name = NULL;
2834 }
2835
2836 if (vty_ipv6_accesslist_name)
2837 {
2838 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2839 vty_ipv6_accesslist_name = NULL;
2840 }
2841}
2842
9fc7ebf1 2843static void
2844vty_save_cwd (void)
718e3744 2845{
79ad2798 2846 char cwd[MAXPATHLEN];
ccc9235e 2847 char *c;
79ad2798 2848
ccc9235e 2849 c = getcwd (cwd, MAXPATHLEN);
718e3744 2850
ccc9235e 2851 if (!c)
79ad2798 2852 {
2853 chdir (SYSCONFDIR);
ccc9235e 2854 getcwd (cwd, MAXPATHLEN);
79ad2798 2855 }
718e3744 2856
2857 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2858 strcpy (vty_cwd, cwd);
2859}
2860
2861char *
2862vty_get_cwd ()
2863{
2864 return vty_cwd;
2865}
2866
2867int
2868vty_shell (struct vty *vty)
2869{
2870 return vty->type == VTY_SHELL ? 1 : 0;
2871}
2872
2873int
2874vty_shell_serv (struct vty *vty)
2875{
2876 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2877}
2878
2879void
2880vty_init_vtysh ()
2881{
2882 vtyvec = vector_init (VECTOR_MIN_SIZE);
2883}
2884
2885/* Install vty's own commands like `who' command. */
2886void
b21b19c5 2887vty_init (struct thread_master *master_thread)
718e3744 2888{
2889 /* For further configuration read, preserve current directory. */
2890 vty_save_cwd ();
2891
2892 vtyvec = vector_init (VECTOR_MIN_SIZE);
2893
b21b19c5 2894 master = master_thread;
2895
718e3744 2896 /* Initilize server thread vector. */
2897 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2898
2899 /* Install bgp top node. */
2900 install_node (&vty_node, vty_config_write);
2901
2902 install_element (VIEW_NODE, &config_who_cmd);
2903 install_element (VIEW_NODE, &show_history_cmd);
2904 install_element (ENABLE_NODE, &config_who_cmd);
2905 install_element (CONFIG_NODE, &line_vty_cmd);
2906 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2907 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2908 install_element (CONFIG_NODE, &show_history_cmd);
2909 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2910 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
2911 install_element (ENABLE_NODE, &show_history_cmd);
2912
2913 install_default (VTY_NODE);
2914 install_element (VTY_NODE, &exec_timeout_min_cmd);
2915 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2916 install_element (VTY_NODE, &no_exec_timeout_cmd);
2917 install_element (VTY_NODE, &vty_access_class_cmd);
2918 install_element (VTY_NODE, &no_vty_access_class_cmd);
2919 install_element (VTY_NODE, &vty_login_cmd);
2920 install_element (VTY_NODE, &no_vty_login_cmd);
2921#ifdef HAVE_IPV6
2922 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2923 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2924#endif /* HAVE_IPV6 */
2925}