blob: 887e3baad282d95f5ee794175acf757182c29053 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
2 * Virtual terminal [aka TeletYpe] interface routine.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "linklist.h"
paulb21b19c2003-06-15 01:28:29 +000026#include "thread.h"
paul718e3742002-12-13 20:15:29 +000027#include "buffer.h"
gdt5e4fa162004-03-16 14:38:36 +000028#include <lib/version.h>
paul718e3742002-12-13 20:15:29 +000029#include "command.h"
30#include "sockunion.h"
paul718e3742002-12-13 20:15:29 +000031#include "memory.h"
32#include "str.h"
33#include "log.h"
34#include "prefix.h"
35#include "filter.h"
paulb21b19c2003-06-15 01:28:29 +000036#include "vty.h"
pauledd7c242003-06-04 13:59:38 +000037#include "privs.h"
ajs9fc7ebf2005-02-23 15:12:34 +000038#include "network.h"
39
40#include <arpa/telnet.h>
paul718e3742002-12-13 20:15:29 +000041
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,
ajs49ff6d92004-11-04 19:26:16 +000051 VTYSH_READ,
52 VTYSH_WRITE
paul718e3742002-12-13 20:15:29 +000053#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
61/* Vector which store each vty structure. */
62static vector vtyvec;
63
64/* Vty timeout value. */
65static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
66
67/* Vty access-class command */
68static char *vty_accesslist_name = NULL;
69
70/* Vty access-calss for IPv6. */
71static char *vty_ipv6_accesslist_name = NULL;
72
73/* VTY server thread. */
74vector Vvty_serv_thread;
75
76/* Current directory. */
77char *vty_cwd = NULL;
78
79/* Configure lock. */
80static int vty_config;
81
82/* Login password check. */
83static int no_password_check = 0;
84
85/* Integrated configuration file path */
86char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
87
88
89/* VTY standard output function. */
90int
91vty_out (struct vty *vty, const char *format, ...)
92{
93 va_list args;
94 int len = 0;
95 int size = 1024;
96 char buf[1024];
97 char *p = NULL;
paul718e3742002-12-13 20:15:29 +000098
99 if (vty_shell (vty))
ajsd246bd92004-11-23 17:35:08 +0000100 {
101 va_start (args, format);
102 vprintf (format, args);
103 va_end (args);
104 }
paul718e3742002-12-13 20:15:29 +0000105 else
106 {
107 /* Try to write to initial buffer. */
ajsd246bd92004-11-23 17:35:08 +0000108 va_start (args, format);
paul718e3742002-12-13 20:15:29 +0000109 len = vsnprintf (buf, sizeof buf, format, args);
ajsd246bd92004-11-23 17:35:08 +0000110 va_end (args);
paul718e3742002-12-13 20:15:29 +0000111
112 /* Initial buffer is not enough. */
113 if (len < 0 || len >= size)
114 {
115 while (1)
116 {
117 if (len > -1)
118 size = len + 1;
119 else
120 size = size * 2;
121
122 p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
123 if (! p)
124 return -1;
125
ajsd246bd92004-11-23 17:35:08 +0000126 va_start (args, format);
paul718e3742002-12-13 20:15:29 +0000127 len = vsnprintf (p, size, format, args);
ajsd246bd92004-11-23 17:35:08 +0000128 va_end (args);
paul718e3742002-12-13 20:15:29 +0000129
130 if (len > -1 && len < size)
131 break;
132 }
133 }
134
135 /* When initial buffer is enough to store all output. */
136 if (! p)
137 p = buf;
138
139 /* Pointer p must point out buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +0000140 buffer_put (vty->obuf, (u_char *) p, len);
paul718e3742002-12-13 20:15:29 +0000141
142 /* If p is not different with buf, it is allocated buffer. */
143 if (p != buf)
144 XFREE (MTYPE_VTY_OUT_BUF, p);
145 }
146
paul718e3742002-12-13 20:15:29 +0000147 return len;
148}
149
ajsd246bd92004-11-23 17:35:08 +0000150static int
ajs274a4a42004-12-07 15:39:31 +0000151vty_log_out (struct vty *vty, const char *level, const char *proto_str,
152 const char *format, va_list va)
paul718e3742002-12-13 20:15:29 +0000153{
ajs9fc7ebf2005-02-23 15:12:34 +0000154 int ret;
paul718e3742002-12-13 20:15:29 +0000155 int len;
156 char buf[1024];
157
ajs274a4a42004-12-07 15:39:31 +0000158 if (level)
ajs9fc7ebf2005-02-23 15:12:34 +0000159 len = snprintf(buf, sizeof(buf), "%s: %s: ", level, proto_str);
ajs274a4a42004-12-07 15:39:31 +0000160 else
ajs9fc7ebf2005-02-23 15:12:34 +0000161 len = snprintf(buf, sizeof(buf), "%s: ", proto_str);
162 if ((len < 0) || ((size_t)len >= sizeof(buf)))
paul718e3742002-12-13 20:15:29 +0000163 return -1;
paul718e3742002-12-13 20:15:29 +0000164
ajs9fc7ebf2005-02-23 15:12:34 +0000165 if (((ret = vsnprintf(buf+len, sizeof(buf)-len, format, va)) < 0) ||
166 ((size_t)((len += ret)+2) > sizeof(buf)))
167 return -1;
paul718e3742002-12-13 20:15:29 +0000168
ajs9fc7ebf2005-02-23 15:12:34 +0000169 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;
paul718e3742002-12-13 20:15:29 +0000186}
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{
219 if (host.motd)
220 vty_out (vty, host.motd);
221}
222
223/* Put out prompt and wait input from user. */
224static void
225vty_prompt (struct vty *vty)
226{
227 struct utsname names;
228 const char*hostname;
229
230 if (vty->type == VTY_TERM)
231 {
232 hostname = host.name;
233 if (!hostname)
234 {
235 uname (&names);
236 hostname = names.nodename;
237 }
238 vty_out (vty, cmd_prompt (vty->node), hostname);
239 }
240}
241
242/* Send WILL TELOPT_ECHO to remote server. */
ajs9fc7ebf2005-02-23 15:12:34 +0000243static void
paul718e3742002-12-13 20:15:29 +0000244vty_will_echo (struct vty *vty)
245{
paul02ff83c2004-06-11 11:27:03 +0000246 unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
paul718e3742002-12-13 20:15:29 +0000247 vty_out (vty, "%s", cmd);
248}
249
250/* Make suppress Go-Ahead telnet option. */
251static void
252vty_will_suppress_go_ahead (struct vty *vty)
253{
paul02ff83c2004-06-11 11:27:03 +0000254 unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
paul718e3742002-12-13 20:15:29 +0000255 vty_out (vty, "%s", cmd);
256}
257
258/* Make don't use linemode over telnet. */
259static void
260vty_dont_linemode (struct vty *vty)
261{
paul02ff83c2004-06-11 11:27:03 +0000262 unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
paul718e3742002-12-13 20:15:29 +0000263 vty_out (vty, "%s", cmd);
264}
265
266/* Use window size. */
267static void
268vty_do_window_size (struct vty *vty)
269{
paul02ff83c2004-06-11 11:27:03 +0000270 unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
paul718e3742002-12-13 20:15:29 +0000271 vty_out (vty, "%s", cmd);
272}
273
274#if 0 /* Currently not used. */
275/* Make don't use lflow vty interface. */
276static void
277vty_dont_lflow_ahead (struct vty *vty)
278{
paul02ff83c2004-06-11 11:27:03 +0000279 unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
paul718e3742002-12-13 20:15:29 +0000280 vty_out (vty, "%s", cmd);
281}
282#endif /* 0 */
283
284/* Allocate new vty struct. */
285struct vty *
286vty_new ()
287{
288 struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
289
ajs9fc7ebf2005-02-23 15:12:34 +0000290 new->obuf = buffer_new(0); /* Use default buffer size. */
paul718e3742002-12-13 20:15:29 +0000291 new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
292 new->max = VTY_BUFSIZ;
paul718e3742002-12-13 20:15:29 +0000293
294 return new;
295}
296
297/* Authentication of vty */
298static void
299vty_auth (struct vty *vty, char *buf)
300{
301 char *passwd = NULL;
302 enum node_type next_node = 0;
303 int fail;
304 char *crypt (const char *, const char *);
305
306 switch (vty->node)
307 {
308 case AUTH_NODE:
309 if (host.encrypt)
310 passwd = host.password_encrypt;
311 else
312 passwd = host.password;
313 if (host.advanced)
314 next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
315 else
316 next_node = VIEW_NODE;
317 break;
318 case AUTH_ENABLE_NODE:
319 if (host.encrypt)
320 passwd = host.enable_encrypt;
321 else
322 passwd = host.enable;
323 next_node = ENABLE_NODE;
324 break;
325 }
326
327 if (passwd)
328 {
329 if (host.encrypt)
330 fail = strcmp (crypt(buf, passwd), passwd);
331 else
332 fail = strcmp (buf, passwd);
333 }
334 else
335 fail = 1;
336
337 if (! fail)
338 {
339 vty->fail = 0;
340 vty->node = next_node; /* Success ! */
341 }
342 else
343 {
344 vty->fail++;
345 if (vty->fail >= 3)
346 {
347 if (vty->node == AUTH_NODE)
348 {
349 vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
350 vty->status = VTY_CLOSE;
351 }
352 else
353 {
354 /* AUTH_ENABLE_NODE */
355 vty->fail = 0;
356 vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
357 vty->node = VIEW_NODE;
358 }
359 }
360 }
361}
362
363/* Command execution over the vty interface. */
ajs9fc7ebf2005-02-23 15:12:34 +0000364static int
paul718e3742002-12-13 20:15:29 +0000365vty_command (struct vty *vty, char *buf)
366{
367 int ret;
368 vector vline;
369
370 /* Split readline string up into the vector */
371 vline = cmd_make_strvec (buf);
372
373 if (vline == NULL)
374 return CMD_SUCCESS;
375
hasso87d683b2005-01-16 23:31:54 +0000376 ret = cmd_execute_command (vline, vty, NULL, 0);
paul718e3742002-12-13 20:15:29 +0000377
378 if (ret != CMD_SUCCESS)
379 switch (ret)
380 {
381 case CMD_WARNING:
382 if (vty->type == VTY_FILE)
383 vty_out (vty, "Warning...%s", VTY_NEWLINE);
384 break;
385 case CMD_ERR_AMBIGUOUS:
386 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
387 break;
388 case CMD_ERR_NO_MATCH:
389 vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
390 break;
391 case CMD_ERR_INCOMPLETE:
392 vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
393 break;
394 }
395 cmd_free_strvec (vline);
396
397 return ret;
398}
399
ajs9fc7ebf2005-02-23 15:12:34 +0000400static const char telnet_backward_char = 0x08;
401static const char telnet_space_char = ' ';
paul718e3742002-12-13 20:15:29 +0000402
403/* Basic function to write buffer to vty. */
404static void
ajs9fc7ebf2005-02-23 15:12:34 +0000405vty_write (struct vty *vty, const char *buf, size_t nbytes)
paul718e3742002-12-13 20:15:29 +0000406{
407 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
408 return;
409
410 /* Should we do buffering here ? And make vty_flush (vty) ? */
ajs9fc7ebf2005-02-23 15:12:34 +0000411 buffer_put (vty->obuf, buf, nbytes);
paul718e3742002-12-13 20:15:29 +0000412}
413
414/* Ensure length of input buffer. Is buffer is short, double it. */
415static void
416vty_ensure (struct vty *vty, int length)
417{
418 if (vty->max <= length)
419 {
420 vty->max *= 2;
421 vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
422 }
423}
424
425/* Basic function to insert character into vty. */
426static void
427vty_self_insert (struct vty *vty, char c)
428{
429 int i;
430 int length;
431
432 vty_ensure (vty, vty->length + 1);
433 length = vty->length - vty->cp;
434 memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
435 vty->buf[vty->cp] = c;
436
437 vty_write (vty, &vty->buf[vty->cp], length + 1);
438 for (i = 0; i < length; i++)
439 vty_write (vty, &telnet_backward_char, 1);
440
441 vty->cp++;
442 vty->length++;
443}
444
445/* Self insert character 'c' in overwrite mode. */
446static void
447vty_self_insert_overwrite (struct vty *vty, char c)
448{
449 vty_ensure (vty, vty->length + 1);
450 vty->buf[vty->cp++] = c;
451
452 if (vty->cp > vty->length)
453 vty->length++;
454
455 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
456 return;
457
458 vty_write (vty, &c, 1);
459}
460
461/* Insert a word into vty interface with overwrite mode. */
462static void
463vty_insert_word_overwrite (struct vty *vty, char *str)
464{
465 int len = strlen (str);
466 vty_write (vty, str, len);
467 strcpy (&vty->buf[vty->cp], str);
468 vty->cp += len;
469 vty->length = vty->cp;
470}
471
472/* Forward character. */
473static void
474vty_forward_char (struct vty *vty)
475{
476 if (vty->cp < vty->length)
477 {
478 vty_write (vty, &vty->buf[vty->cp], 1);
479 vty->cp++;
480 }
481}
482
483/* Backward character. */
484static void
485vty_backward_char (struct vty *vty)
486{
487 if (vty->cp > 0)
488 {
489 vty->cp--;
490 vty_write (vty, &telnet_backward_char, 1);
491 }
492}
493
494/* Move to the beginning of the line. */
495static void
496vty_beginning_of_line (struct vty *vty)
497{
498 while (vty->cp)
499 vty_backward_char (vty);
500}
501
502/* Move to the end of the line. */
503static void
504vty_end_of_line (struct vty *vty)
505{
506 while (vty->cp < vty->length)
507 vty_forward_char (vty);
508}
509
510static void vty_kill_line_from_beginning (struct vty *);
511static void vty_redraw_line (struct vty *);
512
513/* Print command line history. This function is called from
514 vty_next_line and vty_previous_line. */
515static void
516vty_history_print (struct vty *vty)
517{
518 int length;
519
520 vty_kill_line_from_beginning (vty);
521
522 /* Get previous line from history buffer */
523 length = strlen (vty->hist[vty->hp]);
524 memcpy (vty->buf, vty->hist[vty->hp], length);
525 vty->cp = vty->length = length;
526
527 /* Redraw current line */
528 vty_redraw_line (vty);
529}
530
531/* Show next command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000532static void
paul718e3742002-12-13 20:15:29 +0000533vty_next_line (struct vty *vty)
534{
535 int try_index;
536
537 if (vty->hp == vty->hindex)
538 return;
539
540 /* Try is there history exist or not. */
541 try_index = vty->hp;
542 if (try_index == (VTY_MAXHIST - 1))
543 try_index = 0;
544 else
545 try_index++;
546
547 /* If there is not history return. */
548 if (vty->hist[try_index] == NULL)
549 return;
550 else
551 vty->hp = try_index;
552
553 vty_history_print (vty);
554}
555
556/* Show previous command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000557static void
paul718e3742002-12-13 20:15:29 +0000558vty_previous_line (struct vty *vty)
559{
560 int try_index;
561
562 try_index = vty->hp;
563 if (try_index == 0)
564 try_index = VTY_MAXHIST - 1;
565 else
566 try_index--;
567
568 if (vty->hist[try_index] == NULL)
569 return;
570 else
571 vty->hp = try_index;
572
573 vty_history_print (vty);
574}
575
576/* This function redraw all of the command line character. */
577static void
578vty_redraw_line (struct vty *vty)
579{
580 vty_write (vty, vty->buf, vty->length);
581 vty->cp = vty->length;
582}
583
584/* Forward word. */
585static void
586vty_forward_word (struct vty *vty)
587{
588 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
589 vty_forward_char (vty);
590
591 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
592 vty_forward_char (vty);
593}
594
595/* Backward word without skipping training space. */
596static void
597vty_backward_pure_word (struct vty *vty)
598{
599 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
600 vty_backward_char (vty);
601}
602
603/* Backward word. */
604static void
605vty_backward_word (struct vty *vty)
606{
607 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
608 vty_backward_char (vty);
609
610 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
611 vty_backward_char (vty);
612}
613
614/* When '^D' is typed at the beginning of the line we move to the down
615 level. */
616static void
617vty_down_level (struct vty *vty)
618{
619 vty_out (vty, "%s", VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +0000620 (*config_exit_cmd.func)(NULL, vty, 0, NULL);
paul718e3742002-12-13 20:15:29 +0000621 vty_prompt (vty);
622 vty->cp = 0;
623}
624
625/* When '^Z' is received from vty, move down to the enable mode. */
ajs9fc7ebf2005-02-23 15:12:34 +0000626static void
paul718e3742002-12-13 20:15:29 +0000627vty_end_config (struct vty *vty)
628{
629 vty_out (vty, "%s", VTY_NEWLINE);
630
631 switch (vty->node)
632 {
633 case VIEW_NODE:
634 case ENABLE_NODE:
635 /* Nothing to do. */
636 break;
637 case CONFIG_NODE:
638 case INTERFACE_NODE:
639 case ZEBRA_NODE:
640 case RIP_NODE:
641 case RIPNG_NODE:
642 case BGP_NODE:
643 case BGP_VPNV4_NODE:
644 case BGP_IPV4_NODE:
645 case BGP_IPV4M_NODE:
646 case BGP_IPV6_NODE:
647 case RMAP_NODE:
648 case OSPF_NODE:
649 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +0000650 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +0000651 case KEYCHAIN_NODE:
652 case KEYCHAIN_KEY_NODE:
653 case MASC_NODE:
654 case VTY_NODE:
655 vty_config_unlock (vty);
656 vty->node = ENABLE_NODE;
657 break;
658 default:
659 /* Unknown node, we have to ignore it. */
660 break;
661 }
662
663 vty_prompt (vty);
664 vty->cp = 0;
665}
666
667/* Delete a charcter at the current point. */
668static void
669vty_delete_char (struct vty *vty)
670{
671 int i;
672 int size;
673
674 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
675 return;
676
677 if (vty->length == 0)
678 {
679 vty_down_level (vty);
680 return;
681 }
682
683 if (vty->cp == vty->length)
684 return; /* completion need here? */
685
686 size = vty->length - vty->cp;
687
688 vty->length--;
689 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
690 vty->buf[vty->length] = '\0';
691
692 vty_write (vty, &vty->buf[vty->cp], size - 1);
693 vty_write (vty, &telnet_space_char, 1);
694
695 for (i = 0; i < size; i++)
696 vty_write (vty, &telnet_backward_char, 1);
697}
698
699/* Delete a character before the point. */
700static void
701vty_delete_backward_char (struct vty *vty)
702{
703 if (vty->cp == 0)
704 return;
705
706 vty_backward_char (vty);
707 vty_delete_char (vty);
708}
709
710/* Kill rest of line from current point. */
711static void
712vty_kill_line (struct vty *vty)
713{
714 int i;
715 int size;
716
717 size = vty->length - vty->cp;
718
719 if (size == 0)
720 return;
721
722 for (i = 0; i < size; i++)
723 vty_write (vty, &telnet_space_char, 1);
724 for (i = 0; i < size; i++)
725 vty_write (vty, &telnet_backward_char, 1);
726
727 memset (&vty->buf[vty->cp], 0, size);
728 vty->length = vty->cp;
729}
730
731/* Kill line from the beginning. */
732static void
733vty_kill_line_from_beginning (struct vty *vty)
734{
735 vty_beginning_of_line (vty);
736 vty_kill_line (vty);
737}
738
739/* Delete a word before the point. */
740static void
741vty_forward_kill_word (struct vty *vty)
742{
743 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
744 vty_delete_char (vty);
745 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
746 vty_delete_char (vty);
747}
748
749/* Delete a word before the point. */
750static void
751vty_backward_kill_word (struct vty *vty)
752{
753 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
754 vty_delete_backward_char (vty);
755 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
756 vty_delete_backward_char (vty);
757}
758
759/* Transpose chars before or at the point. */
760static void
761vty_transpose_chars (struct vty *vty)
762{
763 char c1, c2;
764
765 /* If length is short or point is near by the beginning of line then
766 return. */
767 if (vty->length < 2 || vty->cp < 1)
768 return;
769
770 /* In case of point is located at the end of the line. */
771 if (vty->cp == vty->length)
772 {
773 c1 = vty->buf[vty->cp - 1];
774 c2 = vty->buf[vty->cp - 2];
775
776 vty_backward_char (vty);
777 vty_backward_char (vty);
778 vty_self_insert_overwrite (vty, c1);
779 vty_self_insert_overwrite (vty, c2);
780 }
781 else
782 {
783 c1 = vty->buf[vty->cp];
784 c2 = vty->buf[vty->cp - 1];
785
786 vty_backward_char (vty);
787 vty_self_insert_overwrite (vty, c1);
788 vty_self_insert_overwrite (vty, c2);
789 }
790}
791
792/* Do completion at vty interface. */
793static void
794vty_complete_command (struct vty *vty)
795{
796 int i;
797 int ret;
798 char **matched = NULL;
799 vector vline;
800
801 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
802 return;
803
804 vline = cmd_make_strvec (vty->buf);
805 if (vline == NULL)
806 return;
807
808 /* In case of 'help \t'. */
809 if (isspace ((int) vty->buf[vty->length - 1]))
810 vector_set (vline, '\0');
811
812 matched = cmd_complete_command (vline, vty, &ret);
813
814 cmd_free_strvec (vline);
815
816 vty_out (vty, "%s", VTY_NEWLINE);
817 switch (ret)
818 {
819 case CMD_ERR_AMBIGUOUS:
820 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
821 vty_prompt (vty);
822 vty_redraw_line (vty);
823 break;
824 case CMD_ERR_NO_MATCH:
825 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
826 vty_prompt (vty);
827 vty_redraw_line (vty);
828 break;
829 case CMD_COMPLETE_FULL_MATCH:
830 vty_prompt (vty);
831 vty_redraw_line (vty);
832 vty_backward_pure_word (vty);
833 vty_insert_word_overwrite (vty, matched[0]);
834 vty_self_insert (vty, ' ');
835 XFREE (MTYPE_TMP, matched[0]);
836 break;
837 case CMD_COMPLETE_MATCH:
838 vty_prompt (vty);
839 vty_redraw_line (vty);
840 vty_backward_pure_word (vty);
841 vty_insert_word_overwrite (vty, matched[0]);
842 XFREE (MTYPE_TMP, matched[0]);
843 vector_only_index_free (matched);
844 return;
845 break;
846 case CMD_COMPLETE_LIST_MATCH:
847 for (i = 0; matched[i] != NULL; i++)
848 {
849 if (i != 0 && ((i % 6) == 0))
850 vty_out (vty, "%s", VTY_NEWLINE);
851 vty_out (vty, "%-10s ", matched[i]);
852 XFREE (MTYPE_TMP, matched[i]);
853 }
854 vty_out (vty, "%s", VTY_NEWLINE);
855
856 vty_prompt (vty);
857 vty_redraw_line (vty);
858 break;
859 case CMD_ERR_NOTHING_TODO:
860 vty_prompt (vty);
861 vty_redraw_line (vty);
862 break;
863 default:
864 break;
865 }
866 if (matched)
867 vector_only_index_free (matched);
868}
869
ajs9fc7ebf2005-02-23 15:12:34 +0000870static void
paul718e3742002-12-13 20:15:29 +0000871vty_describe_fold (struct vty *vty, int cmd_width,
hasso8c328f12004-10-05 21:01:23 +0000872 unsigned int desc_width, struct desc *desc)
paul718e3742002-12-13 20:15:29 +0000873{
hasso8c328f12004-10-05 21:01:23 +0000874 char *buf;
875 const char *cmd, *p;
paul718e3742002-12-13 20:15:29 +0000876 int pos;
877
878 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
879
880 if (desc_width <= 0)
881 {
882 vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
883 return;
884 }
885
886 buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
887
888 for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
889 {
890 for (pos = desc_width; pos > 0; pos--)
891 if (*(p + pos) == ' ')
892 break;
893
894 if (pos == 0)
895 break;
896
897 strncpy (buf, p, pos);
898 buf[pos] = '\0';
899 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
900
901 cmd = "";
902 }
903
904 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
905
906 XFREE (MTYPE_TMP, buf);
907}
908
909/* Describe matched command function. */
910static void
911vty_describe_command (struct vty *vty)
912{
913 int ret;
914 vector vline;
915 vector describe;
hasso8c328f12004-10-05 21:01:23 +0000916 unsigned int i, width, desc_width;
paul718e3742002-12-13 20:15:29 +0000917 struct desc *desc, *desc_cr = NULL;
918
919 vline = cmd_make_strvec (vty->buf);
920
921 /* In case of '> ?'. */
922 if (vline == NULL)
923 {
924 vline = vector_init (1);
925 vector_set (vline, '\0');
926 }
927 else
928 if (isspace ((int) vty->buf[vty->length - 1]))
929 vector_set (vline, '\0');
930
931 describe = cmd_describe_command (vline, vty, &ret);
932
933 vty_out (vty, "%s", VTY_NEWLINE);
934
935 /* Ambiguous error. */
936 switch (ret)
937 {
938 case CMD_ERR_AMBIGUOUS:
939 cmd_free_strvec (vline);
940 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
941 vty_prompt (vty);
942 vty_redraw_line (vty);
943 return;
944 break;
945 case CMD_ERR_NO_MATCH:
946 cmd_free_strvec (vline);
947 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
948 vty_prompt (vty);
949 vty_redraw_line (vty);
950 return;
951 break;
952 }
953
954 /* Get width of command string. */
955 width = 0;
956 for (i = 0; i < vector_max (describe); i++)
957 if ((desc = vector_slot (describe, i)) != NULL)
958 {
hasso8c328f12004-10-05 21:01:23 +0000959 unsigned int len;
paul718e3742002-12-13 20:15:29 +0000960
961 if (desc->cmd[0] == '\0')
962 continue;
963
964 len = strlen (desc->cmd);
965 if (desc->cmd[0] == '.')
966 len--;
967
968 if (width < len)
969 width = len;
970 }
971
972 /* Get width of description string. */
973 desc_width = vty->width - (width + 6);
974
975 /* Print out description. */
976 for (i = 0; i < vector_max (describe); i++)
977 if ((desc = vector_slot (describe, i)) != NULL)
978 {
979 if (desc->cmd[0] == '\0')
980 continue;
981
982 if (strcmp (desc->cmd, "<cr>") == 0)
983 {
984 desc_cr = desc;
985 continue;
986 }
987
988 if (!desc->str)
989 vty_out (vty, " %-s%s",
990 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
991 VTY_NEWLINE);
992 else if (desc_width >= strlen (desc->str))
993 vty_out (vty, " %-*s %s%s", width,
994 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
995 desc->str, VTY_NEWLINE);
996 else
997 vty_describe_fold (vty, width, desc_width, desc);
998
999#if 0
1000 vty_out (vty, " %-*s %s%s", width
1001 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1002 desc->str ? desc->str : "", VTY_NEWLINE);
1003#endif /* 0 */
1004 }
1005
1006 if ((desc = desc_cr))
1007 {
1008 if (!desc->str)
1009 vty_out (vty, " %-s%s",
1010 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1011 VTY_NEWLINE);
1012 else if (desc_width >= strlen (desc->str))
1013 vty_out (vty, " %-*s %s%s", width,
1014 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1015 desc->str, VTY_NEWLINE);
1016 else
1017 vty_describe_fold (vty, width, desc_width, desc);
1018 }
1019
1020 cmd_free_strvec (vline);
1021 vector_free (describe);
1022
1023 vty_prompt (vty);
1024 vty_redraw_line (vty);
1025}
1026
ajs9fc7ebf2005-02-23 15:12:34 +00001027static void
paul718e3742002-12-13 20:15:29 +00001028vty_clear_buf (struct vty *vty)
1029{
1030 memset (vty->buf, 0, vty->max);
1031}
1032
1033/* ^C stop current input and do not add command line to the history. */
1034static void
1035vty_stop_input (struct vty *vty)
1036{
1037 vty->cp = vty->length = 0;
1038 vty_clear_buf (vty);
1039 vty_out (vty, "%s", VTY_NEWLINE);
1040
1041 switch (vty->node)
1042 {
1043 case VIEW_NODE:
1044 case ENABLE_NODE:
1045 /* Nothing to do. */
1046 break;
1047 case CONFIG_NODE:
1048 case INTERFACE_NODE:
1049 case ZEBRA_NODE:
1050 case RIP_NODE:
1051 case RIPNG_NODE:
1052 case BGP_NODE:
1053 case RMAP_NODE:
1054 case OSPF_NODE:
1055 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00001056 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00001057 case KEYCHAIN_NODE:
1058 case KEYCHAIN_KEY_NODE:
1059 case MASC_NODE:
1060 case VTY_NODE:
1061 vty_config_unlock (vty);
1062 vty->node = ENABLE_NODE;
1063 break;
1064 default:
1065 /* Unknown node, we have to ignore it. */
1066 break;
1067 }
1068 vty_prompt (vty);
1069
1070 /* Set history pointer to the latest one. */
1071 vty->hp = vty->hindex;
1072}
1073
1074/* Add current command line to the history buffer. */
1075static void
1076vty_hist_add (struct vty *vty)
1077{
1078 int index;
1079
1080 if (vty->length == 0)
1081 return;
1082
1083 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1084
1085 /* Ignore the same string as previous one. */
1086 if (vty->hist[index])
1087 if (strcmp (vty->buf, vty->hist[index]) == 0)
1088 {
1089 vty->hp = vty->hindex;
1090 return;
1091 }
1092
1093 /* Insert history entry. */
1094 if (vty->hist[vty->hindex])
1095 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1096 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1097
1098 /* History index rotation. */
1099 vty->hindex++;
1100 if (vty->hindex == VTY_MAXHIST)
1101 vty->hindex = 0;
1102
1103 vty->hp = vty->hindex;
1104}
1105
1106/* #define TELNET_OPTION_DEBUG */
1107
1108/* Get telnet window size. */
1109static int
1110vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1111{
1112#ifdef TELNET_OPTION_DEBUG
1113 int i;
1114
1115 for (i = 0; i < nbytes; i++)
1116 {
1117 switch (buf[i])
1118 {
1119 case IAC:
1120 vty_out (vty, "IAC ");
1121 break;
1122 case WILL:
1123 vty_out (vty, "WILL ");
1124 break;
1125 case WONT:
1126 vty_out (vty, "WONT ");
1127 break;
1128 case DO:
1129 vty_out (vty, "DO ");
1130 break;
1131 case DONT:
1132 vty_out (vty, "DONT ");
1133 break;
1134 case SB:
1135 vty_out (vty, "SB ");
1136 break;
1137 case SE:
1138 vty_out (vty, "SE ");
1139 break;
1140 case TELOPT_ECHO:
1141 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1142 break;
1143 case TELOPT_SGA:
1144 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1145 break;
1146 case TELOPT_NAWS:
1147 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1148 break;
1149 default:
1150 vty_out (vty, "%x ", buf[i]);
1151 break;
1152 }
1153 }
1154 vty_out (vty, "%s", VTY_NEWLINE);
1155
1156#endif /* TELNET_OPTION_DEBUG */
1157
1158 switch (buf[0])
1159 {
1160 case SB:
ajs9fc7ebf2005-02-23 15:12:34 +00001161 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001162 vty->iac_sb_in_progress = 1;
1163 return 0;
1164 break;
1165 case SE:
1166 {
paul718e3742002-12-13 20:15:29 +00001167 if (!vty->iac_sb_in_progress)
1168 return 0;
1169
ajs9fc7ebf2005-02-23 15:12:34 +00001170 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
paul718e3742002-12-13 20:15:29 +00001171 {
1172 vty->iac_sb_in_progress = 0;
1173 return 0;
1174 }
ajs9fc7ebf2005-02-23 15:12:34 +00001175 switch (vty->sb_buf[0])
paul718e3742002-12-13 20:15:29 +00001176 {
1177 case TELOPT_NAWS:
ajs9fc7ebf2005-02-23 15:12:34 +00001178 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1179 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1180 "should send %d characters, but we received %lu",
1181 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1182 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1183 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1184 "too small to handle the telnet NAWS option",
1185 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1186 else
1187 {
1188 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1189 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1190#ifdef TELNET_OPTION_DEBUG
1191 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1192 "width %d, height %d%s",
1193 vty->width, vty->height, VTY_NEWLINE);
1194#endif
1195 }
paul718e3742002-12-13 20:15:29 +00001196 break;
1197 }
1198 vty->iac_sb_in_progress = 0;
1199 return 0;
1200 break;
1201 }
1202 default:
1203 break;
1204 }
1205 return 1;
1206}
1207
1208/* Execute current command line. */
1209static int
1210vty_execute (struct vty *vty)
1211{
1212 int ret;
1213
1214 ret = CMD_SUCCESS;
1215
1216 switch (vty->node)
1217 {
1218 case AUTH_NODE:
1219 case AUTH_ENABLE_NODE:
1220 vty_auth (vty, vty->buf);
1221 break;
1222 default:
1223 ret = vty_command (vty, vty->buf);
1224 if (vty->type == VTY_TERM)
1225 vty_hist_add (vty);
1226 break;
1227 }
1228
1229 /* Clear command line buffer. */
1230 vty->cp = vty->length = 0;
1231 vty_clear_buf (vty);
1232
ajs5a646652004-11-05 01:25:55 +00001233 if (vty->status != VTY_CLOSE )
paul718e3742002-12-13 20:15:29 +00001234 vty_prompt (vty);
1235
1236 return ret;
1237}
1238
1239#define CONTROL(X) ((X) - '@')
1240#define VTY_NORMAL 0
1241#define VTY_PRE_ESCAPE 1
1242#define VTY_ESCAPE 2
1243
1244/* Escape character command map. */
1245static void
1246vty_escape_map (unsigned char c, struct vty *vty)
1247{
1248 switch (c)
1249 {
1250 case ('A'):
1251 vty_previous_line (vty);
1252 break;
1253 case ('B'):
1254 vty_next_line (vty);
1255 break;
1256 case ('C'):
1257 vty_forward_char (vty);
1258 break;
1259 case ('D'):
1260 vty_backward_char (vty);
1261 break;
1262 default:
1263 break;
1264 }
1265
1266 /* Go back to normal mode. */
1267 vty->escape = VTY_NORMAL;
1268}
1269
1270/* Quit print out to the buffer. */
1271static void
1272vty_buffer_reset (struct vty *vty)
1273{
1274 buffer_reset (vty->obuf);
1275 vty_prompt (vty);
1276 vty_redraw_line (vty);
1277}
1278
1279/* Read data via vty socket. */
1280static int
1281vty_read (struct thread *thread)
1282{
1283 int i;
paul718e3742002-12-13 20:15:29 +00001284 int nbytes;
1285 unsigned char buf[VTY_READ_BUFSIZ];
1286
1287 int vty_sock = THREAD_FD (thread);
1288 struct vty *vty = THREAD_ARG (thread);
1289 vty->t_read = NULL;
1290
1291 /* Read raw data from socket */
ajs9fc7ebf2005-02-23 15:12:34 +00001292 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1293 {
1294 if (nbytes < 0)
1295 {
1296 if (ERRNO_IO_RETRY(errno))
1297 {
1298 vty_event (VTY_READ, vty_sock, vty);
1299 return 0;
1300 }
1301 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1302 __func__, vty->fd, safe_strerror(errno));
1303 }
1304 buffer_reset(vty->obuf);
1305 vty->status = VTY_CLOSE;
1306 }
paul718e3742002-12-13 20:15:29 +00001307
1308 for (i = 0; i < nbytes; i++)
1309 {
1310 if (buf[i] == IAC)
1311 {
1312 if (!vty->iac)
1313 {
1314 vty->iac = 1;
1315 continue;
1316 }
1317 else
1318 {
1319 vty->iac = 0;
1320 }
1321 }
1322
1323 if (vty->iac_sb_in_progress && !vty->iac)
1324 {
ajs9fc7ebf2005-02-23 15:12:34 +00001325 if (vty->sb_len < sizeof(vty->sb_buf))
1326 vty->sb_buf[vty->sb_len] = buf[i];
1327 vty->sb_len++;
paul718e3742002-12-13 20:15:29 +00001328 continue;
1329 }
1330
1331 if (vty->iac)
1332 {
1333 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001334 int ret = 0;
paule9372532003-10-26 21:36:07 +00001335 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001336 vty->iac = 0;
1337 i += ret;
1338 continue;
1339 }
paul5b8c1b02003-10-15 23:08:55 +00001340
paul718e3742002-12-13 20:15:29 +00001341
1342 if (vty->status == VTY_MORE)
1343 {
1344 switch (buf[i])
1345 {
1346 case CONTROL('C'):
1347 case 'q':
1348 case 'Q':
paul718e3742002-12-13 20:15:29 +00001349 vty_buffer_reset (vty);
1350 break;
1351#if 0 /* More line does not work for "show ip bgp". */
1352 case '\n':
1353 case '\r':
1354 vty->status = VTY_MORELINE;
1355 break;
1356#endif
1357 default:
paul718e3742002-12-13 20:15:29 +00001358 break;
1359 }
1360 continue;
1361 }
1362
1363 /* Escape character. */
1364 if (vty->escape == VTY_ESCAPE)
1365 {
1366 vty_escape_map (buf[i], vty);
1367 continue;
1368 }
1369
1370 /* Pre-escape status. */
1371 if (vty->escape == VTY_PRE_ESCAPE)
1372 {
1373 switch (buf[i])
1374 {
1375 case '[':
1376 vty->escape = VTY_ESCAPE;
1377 break;
1378 case 'b':
1379 vty_backward_word (vty);
1380 vty->escape = VTY_NORMAL;
1381 break;
1382 case 'f':
1383 vty_forward_word (vty);
1384 vty->escape = VTY_NORMAL;
1385 break;
1386 case 'd':
1387 vty_forward_kill_word (vty);
1388 vty->escape = VTY_NORMAL;
1389 break;
1390 case CONTROL('H'):
1391 case 0x7f:
1392 vty_backward_kill_word (vty);
1393 vty->escape = VTY_NORMAL;
1394 break;
1395 default:
1396 vty->escape = VTY_NORMAL;
1397 break;
1398 }
1399 continue;
1400 }
1401
1402 switch (buf[i])
1403 {
1404 case CONTROL('A'):
1405 vty_beginning_of_line (vty);
1406 break;
1407 case CONTROL('B'):
1408 vty_backward_char (vty);
1409 break;
1410 case CONTROL('C'):
1411 vty_stop_input (vty);
1412 break;
1413 case CONTROL('D'):
1414 vty_delete_char (vty);
1415 break;
1416 case CONTROL('E'):
1417 vty_end_of_line (vty);
1418 break;
1419 case CONTROL('F'):
1420 vty_forward_char (vty);
1421 break;
1422 case CONTROL('H'):
1423 case 0x7f:
1424 vty_delete_backward_char (vty);
1425 break;
1426 case CONTROL('K'):
1427 vty_kill_line (vty);
1428 break;
1429 case CONTROL('N'):
1430 vty_next_line (vty);
1431 break;
1432 case CONTROL('P'):
1433 vty_previous_line (vty);
1434 break;
1435 case CONTROL('T'):
1436 vty_transpose_chars (vty);
1437 break;
1438 case CONTROL('U'):
1439 vty_kill_line_from_beginning (vty);
1440 break;
1441 case CONTROL('W'):
1442 vty_backward_kill_word (vty);
1443 break;
1444 case CONTROL('Z'):
1445 vty_end_config (vty);
1446 break;
1447 case '\n':
1448 case '\r':
1449 vty_out (vty, "%s", VTY_NEWLINE);
1450 vty_execute (vty);
1451 break;
1452 case '\t':
1453 vty_complete_command (vty);
1454 break;
1455 case '?':
1456 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1457 vty_self_insert (vty, buf[i]);
1458 else
1459 vty_describe_command (vty);
1460 break;
1461 case '\033':
1462 if (i + 1 < nbytes && buf[i + 1] == '[')
1463 {
1464 vty->escape = VTY_ESCAPE;
1465 i++;
1466 }
1467 else
1468 vty->escape = VTY_PRE_ESCAPE;
1469 break;
1470 default:
1471 if (buf[i] > 31 && buf[i] < 127)
1472 vty_self_insert (vty, buf[i]);
1473 break;
1474 }
1475 }
1476
1477 /* Check status. */
1478 if (vty->status == VTY_CLOSE)
1479 vty_close (vty);
1480 else
1481 {
1482 vty_event (VTY_WRITE, vty_sock, vty);
1483 vty_event (VTY_READ, vty_sock, vty);
1484 }
1485 return 0;
1486}
1487
1488/* Flush buffer to the vty. */
1489static int
1490vty_flush (struct thread *thread)
1491{
1492 int erase;
ajs9fc7ebf2005-02-23 15:12:34 +00001493 buffer_status_t flushrc;
paul718e3742002-12-13 20:15:29 +00001494 int vty_sock = THREAD_FD (thread);
1495 struct vty *vty = THREAD_ARG (thread);
ajs9fc7ebf2005-02-23 15:12:34 +00001496
paul718e3742002-12-13 20:15:29 +00001497 vty->t_write = NULL;
1498
1499 /* Tempolary disable read thread. */
ajs9fc7ebf2005-02-23 15:12:34 +00001500 if ((vty->lines == 0) && vty->t_read)
1501 {
1502 thread_cancel (vty->t_read);
1503 vty->t_read = NULL;
1504 }
paul718e3742002-12-13 20:15:29 +00001505
1506 /* Function execution continue. */
ajs9fc7ebf2005-02-23 15:12:34 +00001507 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
paul718e3742002-12-13 20:15:29 +00001508
ajs9fc7ebf2005-02-23 15:12:34 +00001509 /* N.B. if width is 0, that means we don't know the window size. */
1510 if ((vty->lines == 0) || (vty->width == 0))
1511 flushrc = buffer_flush_available(vty->obuf, vty->fd);
1512 else if (vty->status == VTY_MORELINE)
1513 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1514 1, erase, 0);
1515 else
1516 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1517 vty->lines >= 0 ? vty->lines :
1518 vty->height,
1519 erase, 0);
1520 switch (flushrc)
1521 {
1522 case BUFFER_ERROR:
1523 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1524 vty->fd);
1525 buffer_reset(vty->obuf);
1526 vty_close(vty);
1527 return 0;
1528 case BUFFER_EMPTY:
1529 if (vty->status == VTY_CLOSE)
1530 vty_close (vty);
paul718e3742002-12-13 20:15:29 +00001531 else
1532 {
ajs9fc7ebf2005-02-23 15:12:34 +00001533 vty->status = VTY_NORMAL;
paul718e3742002-12-13 20:15:29 +00001534 if (vty->lines == 0)
ajs9fc7ebf2005-02-23 15:12:34 +00001535 vty_event (VTY_READ, vty_sock, vty);
paul718e3742002-12-13 20:15:29 +00001536 }
ajs9fc7ebf2005-02-23 15:12:34 +00001537 break;
1538 case BUFFER_PENDING:
1539 /* There is more data waiting to be written. */
1540 vty->status = VTY_MORE;
1541 if (vty->lines == 0)
1542 vty_event (VTY_WRITE, vty_sock, vty);
1543 break;
1544 }
paul718e3742002-12-13 20:15:29 +00001545
1546 return 0;
1547}
1548
1549/* Create new vty structure. */
ajs9fc7ebf2005-02-23 15:12:34 +00001550static struct vty *
paul718e3742002-12-13 20:15:29 +00001551vty_create (int vty_sock, union sockunion *su)
1552{
1553 struct vty *vty;
1554
1555 /* Allocate new vty structure and set up default values. */
1556 vty = vty_new ();
1557 vty->fd = vty_sock;
1558 vty->type = VTY_TERM;
1559 vty->address = sockunion_su2str (su);
1560 if (no_password_check)
1561 {
1562 if (host.advanced)
1563 vty->node = ENABLE_NODE;
1564 else
1565 vty->node = VIEW_NODE;
1566 }
1567 else
1568 vty->node = AUTH_NODE;
1569 vty->fail = 0;
1570 vty->cp = 0;
1571 vty_clear_buf (vty);
1572 vty->length = 0;
1573 memset (vty->hist, 0, sizeof (vty->hist));
1574 vty->hp = 0;
1575 vty->hindex = 0;
1576 vector_set_index (vtyvec, vty_sock, vty);
1577 vty->status = VTY_NORMAL;
1578 vty->v_timeout = vty_timeout_val;
1579 if (host.lines >= 0)
1580 vty->lines = host.lines;
1581 else
1582 vty->lines = -1;
1583 vty->iac = 0;
1584 vty->iac_sb_in_progress = 0;
ajs9fc7ebf2005-02-23 15:12:34 +00001585 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001586
1587 if (! no_password_check)
1588 {
1589 /* Vty is not available if password isn't set. */
1590 if (host.password == NULL && host.password_encrypt == NULL)
1591 {
1592 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1593 vty->status = VTY_CLOSE;
1594 vty_close (vty);
1595 return NULL;
1596 }
1597 }
1598
1599 /* Say hello to the world. */
1600 vty_hello (vty);
1601 if (! no_password_check)
1602 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1603
1604 /* Setting up terminal. */
1605 vty_will_echo (vty);
1606 vty_will_suppress_go_ahead (vty);
1607
1608 vty_dont_linemode (vty);
1609 vty_do_window_size (vty);
1610 /* vty_dont_lflow_ahead (vty); */
1611
1612 vty_prompt (vty);
1613
1614 /* Add read/write thread. */
1615 vty_event (VTY_WRITE, vty_sock, vty);
1616 vty_event (VTY_READ, vty_sock, vty);
1617
1618 return vty;
1619}
1620
1621/* Accept connection from the network. */
1622static int
1623vty_accept (struct thread *thread)
1624{
1625 int vty_sock;
1626 struct vty *vty;
1627 union sockunion su;
1628 int ret;
1629 unsigned int on;
1630 int accept_sock;
1631 struct prefix *p = NULL;
1632 struct access_list *acl = NULL;
1633
1634 accept_sock = THREAD_FD (thread);
1635
1636 /* We continue hearing vty socket. */
1637 vty_event (VTY_SERV, accept_sock, NULL);
1638
1639 memset (&su, 0, sizeof (union sockunion));
1640
1641 /* We can handle IPv4 or IPv6 socket. */
1642 vty_sock = sockunion_accept (accept_sock, &su);
1643 if (vty_sock < 0)
1644 {
ajs6099b3b2004-11-20 02:06:59 +00001645 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001646 return -1;
1647 }
ajs9fc7ebf2005-02-23 15:12:34 +00001648 set_nonblocking(vty_sock);
paul718e3742002-12-13 20:15:29 +00001649
1650 p = sockunion2hostprefix (&su);
1651
1652 /* VTY's accesslist apply. */
1653 if (p->family == AF_INET && vty_accesslist_name)
1654 {
1655 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1656 (access_list_apply (acl, p) == FILTER_DENY))
1657 {
1658 char *buf;
1659 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1660 (buf = sockunion_su2str (&su)));
1661 free (buf);
1662 close (vty_sock);
1663
1664 /* continue accepting connections */
1665 vty_event (VTY_SERV, accept_sock, NULL);
1666
1667 prefix_free (p);
1668
1669 return 0;
1670 }
1671 }
1672
1673#ifdef HAVE_IPV6
1674 /* VTY's ipv6 accesslist apply. */
1675 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1676 {
1677 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1678 (access_list_apply (acl, p) == FILTER_DENY))
1679 {
1680 char *buf;
1681 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1682 (buf = sockunion_su2str (&su)));
1683 free (buf);
1684 close (vty_sock);
1685
1686 /* continue accepting connections */
1687 vty_event (VTY_SERV, accept_sock, NULL);
1688
1689 prefix_free (p);
1690
1691 return 0;
1692 }
1693 }
1694#endif /* HAVE_IPV6 */
1695
1696 prefix_free (p);
1697
1698 on = 1;
1699 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1700 (char *) &on, sizeof (on));
1701 if (ret < 0)
1702 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
ajs6099b3b2004-11-20 02:06:59 +00001703 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001704
1705 vty = vty_create (vty_sock, &su);
1706
1707 return 0;
1708}
1709
1710#if defined(HAVE_IPV6) && !defined(NRL)
ajs9fc7ebf2005-02-23 15:12:34 +00001711static void
paul718e3742002-12-13 20:15:29 +00001712vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1713{
1714 int ret;
1715 struct addrinfo req;
1716 struct addrinfo *ainfo;
1717 struct addrinfo *ainfo_save;
1718 int sock;
1719 char port_str[BUFSIZ];
1720
1721 memset (&req, 0, sizeof (struct addrinfo));
1722 req.ai_flags = AI_PASSIVE;
1723 req.ai_family = AF_UNSPEC;
1724 req.ai_socktype = SOCK_STREAM;
1725 sprintf (port_str, "%d", port);
1726 port_str[sizeof (port_str) - 1] = '\0';
1727
1728 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1729
1730 if (ret != 0)
1731 {
1732 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1733 exit (1);
1734 }
1735
1736 ainfo_save = ainfo;
1737
1738 do
1739 {
1740 if (ainfo->ai_family != AF_INET
1741#ifdef HAVE_IPV6
1742 && ainfo->ai_family != AF_INET6
1743#endif /* HAVE_IPV6 */
1744 )
1745 continue;
1746
1747 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1748 if (sock < 0)
1749 continue;
1750
1751 sockopt_reuseaddr (sock);
1752 sockopt_reuseport (sock);
1753
1754 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1755 if (ret < 0)
1756 {
1757 close (sock); /* Avoid sd leak. */
1758 continue;
1759 }
1760
1761 ret = listen (sock, 3);
1762 if (ret < 0)
1763 {
1764 close (sock); /* Avoid sd leak. */
1765 continue;
1766 }
1767
1768 vty_event (VTY_SERV, sock, NULL);
1769 }
1770 while ((ainfo = ainfo->ai_next) != NULL);
1771
1772 freeaddrinfo (ainfo_save);
1773}
1774#endif /* HAVE_IPV6 && ! NRL */
1775
1776/* Make vty server socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001777static void
paul29db05b2003-05-08 20:10:22 +00001778vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001779{
1780 int ret;
1781 union sockunion su;
1782 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001783 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001784
1785 memset (&su, 0, sizeof (union sockunion));
1786 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001787 if(addr)
1788 switch(family)
1789 {
1790 case AF_INET:
1791 naddr=&su.sin.sin_addr;
1792#ifdef HAVE_IPV6
1793 case AF_INET6:
1794 naddr=&su.sin6.sin6_addr;
1795#endif
1796 }
1797
1798 if(naddr)
1799 switch(inet_pton(family,addr,naddr))
1800 {
1801 case -1:
1802 zlog_err("bad address %s",addr);
1803 naddr=NULL;
1804 break;
1805 case 0:
ajs6099b3b2004-11-20 02:06:59 +00001806 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
paul29db05b2003-05-08 20:10:22 +00001807 naddr=NULL;
1808 }
paul718e3742002-12-13 20:15:29 +00001809
1810 /* Make new socket. */
1811 accept_sock = sockunion_stream_socket (&su);
1812 if (accept_sock < 0)
1813 return;
1814
1815 /* This is server, so reuse address. */
1816 sockopt_reuseaddr (accept_sock);
1817 sockopt_reuseport (accept_sock);
1818
1819 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001820 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001821 if (ret < 0)
1822 {
paul29db05b2003-05-08 20:10:22 +00001823 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001824 close (accept_sock); /* Avoid sd leak. */
1825 return;
1826 }
1827
1828 /* Listen socket under queue 3. */
1829 ret = listen (accept_sock, 3);
1830 if (ret < 0)
1831 {
1832 zlog (NULL, LOG_WARNING, "can't listen socket");
1833 close (accept_sock); /* Avoid sd leak. */
1834 return;
1835 }
1836
1837 /* Add vty server event. */
1838 vty_event (VTY_SERV, accept_sock, NULL);
1839}
1840
1841#ifdef VTYSH
1842/* For sockaddr_un. */
1843#include <sys/un.h>
1844
1845/* VTY shell UNIX domain socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001846static void
hasso6ad96ea2004-10-07 19:33:46 +00001847vty_serv_un (const char *path)
paul718e3742002-12-13 20:15:29 +00001848{
1849 int ret;
paul75e15fe2004-10-31 02:13:09 +00001850 int sock, len;
paul718e3742002-12-13 20:15:29 +00001851 struct sockaddr_un serv;
1852 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00001853 struct zprivs_ids_t ids;
1854
paul718e3742002-12-13 20:15:29 +00001855 /* First of all, unlink existing socket */
1856 unlink (path);
1857
1858 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00001859 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00001860
1861 /* Make UNIX domain socket. */
1862 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1863 if (sock < 0)
1864 {
ajs6a52d0d2005-01-30 18:49:28 +00001865 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001866 return;
1867 }
1868
1869 /* Make server socket. */
1870 memset (&serv, 0, sizeof (struct sockaddr_un));
1871 serv.sun_family = AF_UNIX;
1872 strncpy (serv.sun_path, path, strlen (path));
1873#ifdef HAVE_SUN_LEN
1874 len = serv.sun_len = SUN_LEN(&serv);
1875#else
1876 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1877#endif /* HAVE_SUN_LEN */
1878
1879 ret = bind (sock, (struct sockaddr *) &serv, len);
1880 if (ret < 0)
1881 {
ajs6a52d0d2005-01-30 18:49:28 +00001882 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001883 close (sock); /* Avoid sd leak. */
1884 return;
1885 }
1886
1887 ret = listen (sock, 5);
1888 if (ret < 0)
1889 {
ajs6a52d0d2005-01-30 18:49:28 +00001890 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001891 close (sock); /* Avoid sd leak. */
1892 return;
1893 }
1894
1895 umask (old_mask);
1896
pauledd7c242003-06-04 13:59:38 +00001897 zprivs_get_ids(&ids);
1898
1899 if (ids.gid_vty > 0)
1900 {
1901 /* set group of socket */
1902 if ( chown (path, -1, ids.gid_vty) )
1903 {
1904 zlog_err ("vty_serv_un: could chown socket, %s",
ajs6099b3b2004-11-20 02:06:59 +00001905 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +00001906 }
1907 }
1908
paul718e3742002-12-13 20:15:29 +00001909 vty_event (VTYSH_SERV, sock, NULL);
1910}
1911
1912/* #define VTYSH_DEBUG 1 */
1913
1914static int
1915vtysh_accept (struct thread *thread)
1916{
1917 int accept_sock;
1918 int sock;
1919 int client_len;
1920 struct sockaddr_un client;
1921 struct vty *vty;
1922
1923 accept_sock = THREAD_FD (thread);
1924
1925 vty_event (VTYSH_SERV, accept_sock, NULL);
1926
1927 memset (&client, 0, sizeof (struct sockaddr_un));
1928 client_len = sizeof (struct sockaddr_un);
1929
hassoe473b032004-09-26 16:08:11 +00001930 sock = accept (accept_sock, (struct sockaddr *) &client,
1931 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00001932
1933 if (sock < 0)
1934 {
ajs6099b3b2004-11-20 02:06:59 +00001935 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001936 return -1;
1937 }
1938
ajs9fc7ebf2005-02-23 15:12:34 +00001939 if (set_nonblocking(sock) < 0)
paul75e15fe2004-10-31 02:13:09 +00001940 {
ajs9fc7ebf2005-02-23 15:12:34 +00001941 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
1942 " %s, closing", sock, safe_strerror (errno));
paul75e15fe2004-10-31 02:13:09 +00001943 close (sock);
1944 return -1;
1945 }
pauldccfb192004-10-29 08:29:36 +00001946
paul718e3742002-12-13 20:15:29 +00001947#ifdef VTYSH_DEBUG
1948 printf ("VTY shell accept\n");
1949#endif /* VTYSH_DEBUG */
1950
1951 vty = vty_new ();
1952 vty->fd = sock;
1953 vty->type = VTY_SHELL_SERV;
1954 vty->node = VIEW_NODE;
1955
1956 vty_event (VTYSH_READ, sock, vty);
1957
1958 return 0;
1959}
1960
1961static int
ajs9fc7ebf2005-02-23 15:12:34 +00001962vtysh_flush(struct vty *vty)
1963{
1964 switch (buffer_flush_available(vty->obuf, vty->fd))
1965 {
1966 case BUFFER_PENDING:
1967 vty_event(VTYSH_WRITE, vty->fd, vty);
1968 break;
1969 case BUFFER_ERROR:
1970 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
1971 buffer_reset(vty->obuf);
1972 vty_close(vty);
1973 return -1;
1974 break;
1975 case BUFFER_EMPTY:
1976 break;
1977 }
1978 return 0;
1979}
1980
1981static int
paul718e3742002-12-13 20:15:29 +00001982vtysh_read (struct thread *thread)
1983{
1984 int ret;
1985 int sock;
1986 int nbytes;
1987 struct vty *vty;
1988 unsigned char buf[VTY_READ_BUFSIZ];
ajs9fc7ebf2005-02-23 15:12:34 +00001989 unsigned char *p;
paul718e3742002-12-13 20:15:29 +00001990 u_char header[4] = {0, 0, 0, 0};
1991
1992 sock = THREAD_FD (thread);
1993 vty = THREAD_ARG (thread);
1994 vty->t_read = NULL;
1995
ajs9fc7ebf2005-02-23 15:12:34 +00001996 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
paul718e3742002-12-13 20:15:29 +00001997 {
ajs9fc7ebf2005-02-23 15:12:34 +00001998 if (nbytes < 0)
1999 {
2000 if (ERRNO_IO_RETRY(errno))
2001 {
2002 vty_event (VTYSH_READ, sock, vty);
2003 return 0;
2004 }
2005 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2006 __func__, sock, safe_strerror(errno));
2007 }
2008 buffer_reset(vty->obuf);
paul718e3742002-12-13 20:15:29 +00002009 vty_close (vty);
2010#ifdef VTYSH_DEBUG
2011 printf ("close vtysh\n");
2012#endif /* VTYSH_DEBUG */
2013 return 0;
2014 }
2015
2016#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002017 printf ("line: %.*s\n", nbytes, buf);
paul718e3742002-12-13 20:15:29 +00002018#endif /* VTYSH_DEBUG */
2019
ajs9fc7ebf2005-02-23 15:12:34 +00002020 for (p = buf; p < buf+nbytes; p++)
2021 {
2022 vty_ensure(vty, vty->length+1);
2023 vty->buf[vty->length++] = *p;
2024 if (*p == '\0')
2025 {
2026 /* Pass this line to parser. */
2027 ret = vty_execute (vty);
2028 /* Note that vty_execute clears the command buffer and resets
2029 vty->length to 0. */
paul718e3742002-12-13 20:15:29 +00002030
ajs9fc7ebf2005-02-23 15:12:34 +00002031 /* Return result. */
paul718e3742002-12-13 20:15:29 +00002032#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002033 printf ("result: %d\n", ret);
2034 printf ("vtysh node: %d\n", vty->node);
paul718e3742002-12-13 20:15:29 +00002035#endif /* VTYSH_DEBUG */
2036
ajs9fc7ebf2005-02-23 15:12:34 +00002037 header[3] = ret;
2038 buffer_put(vty->obuf, header, 4);
paul718e3742002-12-13 20:15:29 +00002039
ajs9fc7ebf2005-02-23 15:12:34 +00002040 if (!vty->t_write && (vtysh_flush(vty) < 0))
2041 /* Try to flush results; exit if a write error occurs. */
2042 return 0;
2043 }
2044 }
2045
paul718e3742002-12-13 20:15:29 +00002046 vty_event (VTYSH_READ, sock, vty);
2047
2048 return 0;
2049}
ajs49ff6d92004-11-04 19:26:16 +00002050
2051static int
2052vtysh_write (struct thread *thread)
2053{
2054 struct vty *vty = THREAD_ARG (thread);
2055
2056 vty->t_write = NULL;
ajs9fc7ebf2005-02-23 15:12:34 +00002057 vtysh_flush(vty);
ajs976d8c72004-11-10 15:40:09 +00002058 return 0;
ajs49ff6d92004-11-04 19:26:16 +00002059}
2060
paul718e3742002-12-13 20:15:29 +00002061#endif /* VTYSH */
2062
2063/* Determine address family to bind. */
2064void
hasso6ad96ea2004-10-07 19:33:46 +00002065vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002066{
2067 /* If port is set to 0, do not listen on TCP/IP at all! */
2068 if (port)
2069 {
2070
2071#ifdef HAVE_IPV6
2072#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002073 vty_serv_sock_family (addr, port, AF_INET);
2074 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002075#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002076 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002077#endif /* NRL*/
2078#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002079 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002080#endif /* HAVE_IPV6 */
2081 }
2082
2083#ifdef VTYSH
2084 vty_serv_un (path);
2085#endif /* VTYSH */
2086}
2087
2088/* Close vty interface. */
2089void
2090vty_close (struct vty *vty)
2091{
2092 int i;
2093
2094 /* Cancel threads.*/
2095 if (vty->t_read)
2096 thread_cancel (vty->t_read);
2097 if (vty->t_write)
2098 thread_cancel (vty->t_write);
2099 if (vty->t_timeout)
2100 thread_cancel (vty->t_timeout);
paul718e3742002-12-13 20:15:29 +00002101
2102 /* Flush buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +00002103 buffer_flush_all (vty->obuf, vty->fd);
paul718e3742002-12-13 20:15:29 +00002104
2105 /* Free input buffer. */
2106 buffer_free (vty->obuf);
2107
paul718e3742002-12-13 20:15:29 +00002108 /* Free command history. */
2109 for (i = 0; i < VTY_MAXHIST; i++)
2110 if (vty->hist[i])
2111 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2112
2113 /* Unset vector. */
2114 vector_unset (vtyvec, vty->fd);
2115
2116 /* Close socket. */
2117 if (vty->fd > 0)
2118 close (vty->fd);
2119
2120 if (vty->address)
2121 XFREE (0, vty->address);
2122 if (vty->buf)
2123 XFREE (MTYPE_VTY, vty->buf);
2124
2125 /* Check configure. */
2126 vty_config_unlock (vty);
2127
2128 /* OK free vty. */
2129 XFREE (MTYPE_VTY, vty);
2130}
2131
2132/* When time out occur output message then close connection. */
2133static int
2134vty_timeout (struct thread *thread)
2135{
2136 struct vty *vty;
2137
2138 vty = THREAD_ARG (thread);
2139 vty->t_timeout = NULL;
2140 vty->v_timeout = 0;
2141
2142 /* Clear buffer*/
2143 buffer_reset (vty->obuf);
2144 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2145
2146 /* Close connection. */
2147 vty->status = VTY_CLOSE;
2148 vty_close (vty);
2149
2150 return 0;
2151}
2152
2153/* Read up configuration file from file_name. */
2154static void
2155vty_read_file (FILE *confp)
2156{
2157 int ret;
2158 struct vty *vty;
2159
2160 vty = vty_new ();
2161 vty->fd = 0; /* stdout */
2162 vty->type = VTY_TERM;
2163 vty->node = CONFIG_NODE;
2164
2165 /* Execute configuration file */
2166 ret = config_from_file (vty, confp);
2167
paul7021c422003-07-15 12:52:22 +00002168 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002169 {
2170 switch (ret)
paul7021c422003-07-15 12:52:22 +00002171 {
2172 case CMD_ERR_AMBIGUOUS:
2173 fprintf (stderr, "Ambiguous command.\n");
2174 break;
2175 case CMD_ERR_NO_MATCH:
2176 fprintf (stderr, "There is no such command.\n");
2177 break;
2178 }
paul718e3742002-12-13 20:15:29 +00002179 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2180 vty->buf);
2181 vty_close (vty);
2182 exit (1);
2183 }
2184
2185 vty_close (vty);
2186}
2187
ajs9fc7ebf2005-02-23 15:12:34 +00002188static FILE *
paul718e3742002-12-13 20:15:29 +00002189vty_use_backup_config (char *fullpath)
2190{
2191 char *fullpath_sav, *fullpath_tmp;
2192 FILE *ret = NULL;
2193 struct stat buf;
2194 int tmp, sav;
2195 int c;
2196 char buffer[512];
2197
2198 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2199 strcpy (fullpath_sav, fullpath);
2200 strcat (fullpath_sav, CONF_BACKUP_EXT);
2201 if (stat (fullpath_sav, &buf) == -1)
2202 {
2203 free (fullpath_sav);
2204 return NULL;
2205 }
2206
2207 fullpath_tmp = malloc (strlen (fullpath) + 8);
2208 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2209
2210 /* Open file to configuration write. */
2211 tmp = mkstemp (fullpath_tmp);
2212 if (tmp < 0)
2213 {
2214 free (fullpath_sav);
2215 free (fullpath_tmp);
2216 return NULL;
2217 }
2218
2219 sav = open (fullpath_sav, O_RDONLY);
2220 if (sav < 0)
2221 {
gdt3dbf9962003-12-22 20:18:18 +00002222 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002223 free (fullpath_sav);
2224 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002225 return NULL;
2226 }
2227
2228 while((c = read (sav, buffer, 512)) > 0)
2229 write (tmp, buffer, c);
2230
2231 close (sav);
2232 close (tmp);
2233
gdtaa593d52003-12-22 20:15:53 +00002234 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2235 {
gdt3dbf9962003-12-22 20:18:18 +00002236 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002237 free (fullpath_sav);
2238 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002239 return NULL;
2240 }
2241
paul718e3742002-12-13 20:15:29 +00002242 if (link (fullpath_tmp, fullpath) == 0)
2243 ret = fopen (fullpath, "r");
2244
2245 unlink (fullpath_tmp);
2246
2247 free (fullpath_sav);
2248 free (fullpath_tmp);
2249 return fopen (fullpath, "r");
2250}
2251
2252/* Read up configuration file from file_name. */
2253void
2254vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002255 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002256{
paulccc92352003-10-22 02:49:38 +00002257 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002258 FILE *confp = NULL;
2259 char *fullpath;
2260
2261 /* If -f flag specified. */
2262 if (config_file != NULL)
2263 {
2264 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002265 {
2266 getcwd (cwd, MAXPATHLEN);
2267 fullpath = XMALLOC (MTYPE_TMP,
2268 strlen (cwd) + strlen (config_file) + 2);
2269 sprintf (fullpath, "%s/%s", cwd, config_file);
2270 }
paul718e3742002-12-13 20:15:29 +00002271 else
hasso320ec102004-06-20 19:54:37 +00002272 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002273
2274 confp = fopen (fullpath, "r");
2275
2276 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002277 {
2278 confp = vty_use_backup_config (fullpath);
2279 if (confp)
2280 fprintf (stderr, "WARNING: using backup configuration file!\n");
2281 else
2282 {
2283 fprintf (stderr, "can't open configuration file [%s]\n",
2284 config_file);
2285 exit(1);
2286 }
2287 }
paul718e3742002-12-13 20:15:29 +00002288 }
2289 else
2290 {
paul718e3742002-12-13 20:15:29 +00002291#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002292 int ret;
2293 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002294
hasso320ec102004-06-20 19:54:37 +00002295 /* !!!!PLEASE LEAVE!!!!
2296 * This is NEEDED for use with vtysh -b, or else you can get
2297 * a real configuration food fight with a lot garbage in the
2298 * merged configuration file it creates coming from the per
2299 * daemon configuration files. This also allows the daemons
2300 * to start if there default configuration file is not
2301 * present or ignore them, as needed when using vtysh -b to
2302 * configure the daemons at boot - MAG
2303 */
paul718e3742002-12-13 20:15:29 +00002304
hasso320ec102004-06-20 19:54:37 +00002305 /* Stat for vtysh Zebra.conf, if found startup and wait for
2306 * boot configuration
2307 */
paul718e3742002-12-13 20:15:29 +00002308
hasso320ec102004-06-20 19:54:37 +00002309 if ( strstr(config_default_dir, "vtysh") == NULL)
2310 {
2311 ret = stat (integrate_default, &conf_stat);
2312 if (ret >= 0)
2313 return;
2314 }
paul718e3742002-12-13 20:15:29 +00002315#endif /* VTYSH */
2316
hasso320ec102004-06-20 19:54:37 +00002317 confp = fopen (config_default_dir, "r");
2318 if (confp == NULL)
2319 {
2320 confp = vty_use_backup_config (config_default_dir);
2321 if (confp)
2322 {
2323 fprintf (stderr, "WARNING: using backup configuration file!\n");
2324 fullpath = config_default_dir;
2325 }
2326 else
2327 {
2328 fprintf (stderr, "can't open configuration file [%s]\n",
2329 config_default_dir);
2330 exit (1);
2331 }
2332 }
paul718e3742002-12-13 20:15:29 +00002333 else
hasso320ec102004-06-20 19:54:37 +00002334 fullpath = config_default_dir;
2335 }
2336
paul718e3742002-12-13 20:15:29 +00002337 vty_read_file (confp);
2338
2339 fclose (confp);
2340
2341 host_config_set (fullpath);
2342}
2343
2344/* Small utility function which output log to the VTY. */
2345void
ajs274a4a42004-12-07 15:39:31 +00002346vty_log (const char *level, const char *proto_str,
2347 const char *format, va_list va)
paul718e3742002-12-13 20:15:29 +00002348{
hasso8c328f12004-10-05 21:01:23 +00002349 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002350 struct vty *vty;
2351
2352 for (i = 0; i < vector_max (vtyvec); i++)
2353 if ((vty = vector_slot (vtyvec, i)) != NULL)
2354 if (vty->monitor)
ajsd246bd92004-11-23 17:35:08 +00002355 {
2356 va_list ac;
2357 va_copy(ac, va);
ajs274a4a42004-12-07 15:39:31 +00002358 vty_log_out (vty, level, proto_str, format, ac);
ajsd246bd92004-11-23 17:35:08 +00002359 va_end(ac);
2360 }
paul718e3742002-12-13 20:15:29 +00002361}
2362
ajs274a4a42004-12-07 15:39:31 +00002363/* Async-signal-safe version of vty_log for fixed strings. */
2364void
2365vty_log_fixed (const char *buf, size_t len)
2366{
2367 unsigned int i;
ajs9fc7ebf2005-02-23 15:12:34 +00002368 struct iovec iov[2];
2369
2370 iov[0].iov_base = buf;
2371 iov[0].iov_len = len;
2372 iov[1].iov_base = "\r\n";
2373 iov[1].iov_len = 2;
ajs274a4a42004-12-07 15:39:31 +00002374
2375 for (i = 0; i < vector_max (vtyvec); i++)
2376 {
2377 struct vty *vty;
ajs9fc7ebf2005-02-23 15:12:34 +00002378 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2379 /* N.B. We don't care about the return code, since process is
2380 most likely just about to die anyway. */
2381 writev(vty->fd, iov, 2);
ajs274a4a42004-12-07 15:39:31 +00002382 }
2383}
2384
paul718e3742002-12-13 20:15:29 +00002385int
2386vty_config_lock (struct vty *vty)
2387{
2388 if (vty_config == 0)
2389 {
2390 vty->config = 1;
2391 vty_config = 1;
2392 }
2393 return vty->config;
2394}
2395
2396int
2397vty_config_unlock (struct vty *vty)
2398{
2399 if (vty_config == 1 && vty->config == 1)
2400 {
2401 vty->config = 0;
2402 vty_config = 0;
2403 }
2404 return vty->config;
2405}
2406
2407/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002408static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002409
2410static void
2411vty_event (enum event event, int sock, struct vty *vty)
2412{
2413 struct thread *vty_serv_thread;
2414
2415 switch (event)
2416 {
2417 case VTY_SERV:
2418 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2419 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2420 break;
2421#ifdef VTYSH
2422 case VTYSH_SERV:
2423 thread_add_read (master, vtysh_accept, vty, sock);
2424 break;
2425 case VTYSH_READ:
ajs49ff6d92004-11-04 19:26:16 +00002426 vty->t_read = thread_add_read (master, vtysh_read, vty, sock);
2427 break;
2428 case VTYSH_WRITE:
2429 vty->t_write = thread_add_write (master, vtysh_write, vty, sock);
paul718e3742002-12-13 20:15:29 +00002430 break;
2431#endif /* VTYSH */
2432 case VTY_READ:
2433 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2434
2435 /* Time out treatment. */
2436 if (vty->v_timeout)
2437 {
2438 if (vty->t_timeout)
2439 thread_cancel (vty->t_timeout);
2440 vty->t_timeout =
2441 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2442 }
2443 break;
2444 case VTY_WRITE:
2445 if (! vty->t_write)
2446 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2447 break;
2448 case VTY_TIMEOUT_RESET:
2449 if (vty->t_timeout)
2450 {
2451 thread_cancel (vty->t_timeout);
2452 vty->t_timeout = NULL;
2453 }
2454 if (vty->v_timeout)
2455 {
2456 vty->t_timeout =
2457 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2458 }
2459 break;
2460 }
2461}
2462
2463DEFUN (config_who,
2464 config_who_cmd,
2465 "who",
2466 "Display who is on vty\n")
2467{
hasso8c328f12004-10-05 21:01:23 +00002468 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002469 struct vty *v;
2470
2471 for (i = 0; i < vector_max (vtyvec); i++)
2472 if ((v = vector_slot (vtyvec, i)) != NULL)
2473 vty_out (vty, "%svty[%d] connected from %s.%s",
2474 v->config ? "*" : " ",
2475 i, v->address, VTY_NEWLINE);
2476 return CMD_SUCCESS;
2477}
2478
2479/* Move to vty configuration mode. */
2480DEFUN (line_vty,
2481 line_vty_cmd,
2482 "line vty",
2483 "Configure a terminal line\n"
2484 "Virtual terminal\n")
2485{
2486 vty->node = VTY_NODE;
2487 return CMD_SUCCESS;
2488}
2489
2490/* Set time out value. */
ajs9fc7ebf2005-02-23 15:12:34 +00002491static int
paul9035efa2004-10-10 11:56:56 +00002492exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002493{
2494 unsigned long timeout = 0;
2495
2496 /* min_str and sec_str are already checked by parser. So it must be
2497 all digit string. */
2498 if (min_str)
2499 {
2500 timeout = strtol (min_str, NULL, 10);
2501 timeout *= 60;
2502 }
2503 if (sec_str)
2504 timeout += strtol (sec_str, NULL, 10);
2505
2506 vty_timeout_val = timeout;
2507 vty->v_timeout = timeout;
2508 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2509
2510
2511 return CMD_SUCCESS;
2512}
2513
2514DEFUN (exec_timeout_min,
2515 exec_timeout_min_cmd,
2516 "exec-timeout <0-35791>",
2517 "Set timeout value\n"
2518 "Timeout value in minutes\n")
2519{
2520 return exec_timeout (vty, argv[0], NULL);
2521}
2522
2523DEFUN (exec_timeout_sec,
2524 exec_timeout_sec_cmd,
2525 "exec-timeout <0-35791> <0-2147483>",
2526 "Set the EXEC timeout\n"
2527 "Timeout in minutes\n"
2528 "Timeout in seconds\n")
2529{
2530 return exec_timeout (vty, argv[0], argv[1]);
2531}
2532
2533DEFUN (no_exec_timeout,
2534 no_exec_timeout_cmd,
2535 "no exec-timeout",
2536 NO_STR
2537 "Set the EXEC timeout\n")
2538{
2539 return exec_timeout (vty, NULL, NULL);
2540}
2541
2542/* Set vty access class. */
2543DEFUN (vty_access_class,
2544 vty_access_class_cmd,
2545 "access-class WORD",
2546 "Filter connections based on an IP access list\n"
2547 "IP access list\n")
2548{
2549 if (vty_accesslist_name)
2550 XFREE(MTYPE_VTY, vty_accesslist_name);
2551
2552 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2553
2554 return CMD_SUCCESS;
2555}
2556
2557/* Clear vty access class. */
2558DEFUN (no_vty_access_class,
2559 no_vty_access_class_cmd,
2560 "no access-class [WORD]",
2561 NO_STR
2562 "Filter connections based on an IP access list\n"
2563 "IP access list\n")
2564{
2565 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2566 {
2567 vty_out (vty, "Access-class is not currently applied to vty%s",
2568 VTY_NEWLINE);
2569 return CMD_WARNING;
2570 }
2571
2572 XFREE(MTYPE_VTY, vty_accesslist_name);
2573
2574 vty_accesslist_name = NULL;
2575
2576 return CMD_SUCCESS;
2577}
2578
2579#ifdef HAVE_IPV6
2580/* Set vty access class. */
2581DEFUN (vty_ipv6_access_class,
2582 vty_ipv6_access_class_cmd,
2583 "ipv6 access-class WORD",
2584 IPV6_STR
2585 "Filter connections based on an IP access list\n"
2586 "IPv6 access list\n")
2587{
2588 if (vty_ipv6_accesslist_name)
2589 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2590
2591 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2592
2593 return CMD_SUCCESS;
2594}
2595
2596/* Clear vty access class. */
2597DEFUN (no_vty_ipv6_access_class,
2598 no_vty_ipv6_access_class_cmd,
2599 "no ipv6 access-class [WORD]",
2600 NO_STR
2601 IPV6_STR
2602 "Filter connections based on an IP access list\n"
2603 "IPv6 access list\n")
2604{
2605 if (! vty_ipv6_accesslist_name ||
2606 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2607 {
2608 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2609 VTY_NEWLINE);
2610 return CMD_WARNING;
2611 }
2612
2613 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2614
2615 vty_ipv6_accesslist_name = NULL;
2616
2617 return CMD_SUCCESS;
2618}
2619#endif /* HAVE_IPV6 */
2620
2621/* vty login. */
2622DEFUN (vty_login,
2623 vty_login_cmd,
2624 "login",
2625 "Enable password checking\n")
2626{
2627 no_password_check = 0;
2628 return CMD_SUCCESS;
2629}
2630
2631DEFUN (no_vty_login,
2632 no_vty_login_cmd,
2633 "no login",
2634 NO_STR
2635 "Enable password checking\n")
2636{
2637 no_password_check = 1;
2638 return CMD_SUCCESS;
2639}
2640
2641DEFUN (service_advanced_vty,
2642 service_advanced_vty_cmd,
2643 "service advanced-vty",
2644 "Set up miscellaneous service\n"
2645 "Enable advanced mode vty interface\n")
2646{
2647 host.advanced = 1;
2648 return CMD_SUCCESS;
2649}
2650
2651DEFUN (no_service_advanced_vty,
2652 no_service_advanced_vty_cmd,
2653 "no service advanced-vty",
2654 NO_STR
2655 "Set up miscellaneous service\n"
2656 "Enable advanced mode vty interface\n")
2657{
2658 host.advanced = 0;
2659 return CMD_SUCCESS;
2660}
2661
2662DEFUN (terminal_monitor,
2663 terminal_monitor_cmd,
2664 "terminal monitor",
2665 "Set terminal line parameters\n"
2666 "Copy debug output to the current terminal line\n")
2667{
2668 vty->monitor = 1;
2669 return CMD_SUCCESS;
2670}
2671
2672DEFUN (terminal_no_monitor,
2673 terminal_no_monitor_cmd,
2674 "terminal no monitor",
2675 "Set terminal line parameters\n"
2676 NO_STR
2677 "Copy debug output to the current terminal line\n")
2678{
2679 vty->monitor = 0;
2680 return CMD_SUCCESS;
2681}
2682
2683DEFUN (show_history,
2684 show_history_cmd,
2685 "show history",
2686 SHOW_STR
2687 "Display the session command history\n")
2688{
2689 int index;
2690
2691 for (index = vty->hindex + 1; index != vty->hindex;)
2692 {
2693 if (index == VTY_MAXHIST)
2694 {
2695 index = 0;
2696 continue;
2697 }
2698
2699 if (vty->hist[index] != NULL)
2700 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2701
2702 index++;
2703 }
2704
2705 return CMD_SUCCESS;
2706}
2707
2708/* Display current configuration. */
ajs9fc7ebf2005-02-23 15:12:34 +00002709static int
paul718e3742002-12-13 20:15:29 +00002710vty_config_write (struct vty *vty)
2711{
2712 vty_out (vty, "line vty%s", VTY_NEWLINE);
2713
2714 if (vty_accesslist_name)
2715 vty_out (vty, " access-class %s%s",
2716 vty_accesslist_name, VTY_NEWLINE);
2717
2718 if (vty_ipv6_accesslist_name)
2719 vty_out (vty, " ipv6 access-class %s%s",
2720 vty_ipv6_accesslist_name, VTY_NEWLINE);
2721
2722 /* exec-timeout */
2723 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2724 vty_out (vty, " exec-timeout %ld %ld%s",
2725 vty_timeout_val / 60,
2726 vty_timeout_val % 60, VTY_NEWLINE);
2727
2728 /* login */
2729 if (no_password_check)
2730 vty_out (vty, " no login%s", VTY_NEWLINE);
2731
2732 vty_out (vty, "!%s", VTY_NEWLINE);
2733
2734 return CMD_SUCCESS;
2735}
2736
2737struct cmd_node vty_node =
2738{
2739 VTY_NODE,
2740 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00002741 1,
paul718e3742002-12-13 20:15:29 +00002742};
2743
2744/* Reset all VTY status. */
2745void
2746vty_reset ()
2747{
hasso8c328f12004-10-05 21:01:23 +00002748 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002749 struct vty *vty;
2750 struct thread *vty_serv_thread;
2751
2752 for (i = 0; i < vector_max (vtyvec); i++)
2753 if ((vty = vector_slot (vtyvec, i)) != NULL)
2754 {
2755 buffer_reset (vty->obuf);
2756 vty->status = VTY_CLOSE;
2757 vty_close (vty);
2758 }
2759
2760 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2761 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2762 {
2763 thread_cancel (vty_serv_thread);
2764 vector_slot (Vvty_serv_thread, i) = NULL;
2765 close (i);
2766 }
2767
2768 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2769
2770 if (vty_accesslist_name)
2771 {
2772 XFREE(MTYPE_VTY, vty_accesslist_name);
2773 vty_accesslist_name = NULL;
2774 }
2775
2776 if (vty_ipv6_accesslist_name)
2777 {
2778 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2779 vty_ipv6_accesslist_name = NULL;
2780 }
2781}
2782
2783/* for ospf6d easy temprary reload function */
2784/* vty_reset + close accept socket */
2785void
2786vty_finish ()
2787{
hasso8c328f12004-10-05 21:01:23 +00002788 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002789 struct vty *vty;
2790 struct thread *vty_serv_thread;
2791
2792 for (i = 0; i < vector_max (vtyvec); i++)
2793 if ((vty = vector_slot (vtyvec, i)) != NULL)
2794 {
2795 buffer_reset (vty->obuf);
2796 vty->status = VTY_CLOSE;
2797 vty_close (vty);
2798 }
2799
2800 for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2801 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2802 {
2803 thread_cancel (vty_serv_thread);
2804 vector_slot (Vvty_serv_thread, i) = NULL;
2805 close (i);
2806 }
2807
2808 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2809
2810 if (vty_accesslist_name)
2811 {
2812 XFREE(MTYPE_VTY, vty_accesslist_name);
2813 vty_accesslist_name = NULL;
2814 }
2815
2816 if (vty_ipv6_accesslist_name)
2817 {
2818 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2819 vty_ipv6_accesslist_name = NULL;
2820 }
2821}
2822
ajs9fc7ebf2005-02-23 15:12:34 +00002823static void
2824vty_save_cwd (void)
paul718e3742002-12-13 20:15:29 +00002825{
paul79ad2792003-10-15 22:09:28 +00002826 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00002827 char *c;
paul718e3742002-12-13 20:15:29 +00002828
paulccc92352003-10-22 02:49:38 +00002829 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002830
paulccc92352003-10-22 02:49:38 +00002831 if (!c)
paul79ad2792003-10-15 22:09:28 +00002832 {
2833 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00002834 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002835 }
paul718e3742002-12-13 20:15:29 +00002836
2837 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2838 strcpy (vty_cwd, cwd);
2839}
2840
2841char *
2842vty_get_cwd ()
2843{
2844 return vty_cwd;
2845}
2846
2847int
2848vty_shell (struct vty *vty)
2849{
2850 return vty->type == VTY_SHELL ? 1 : 0;
2851}
2852
2853int
2854vty_shell_serv (struct vty *vty)
2855{
2856 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2857}
2858
2859void
2860vty_init_vtysh ()
2861{
2862 vtyvec = vector_init (VECTOR_MIN_SIZE);
2863}
2864
2865/* Install vty's own commands like `who' command. */
2866void
paulb21b19c2003-06-15 01:28:29 +00002867vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00002868{
2869 /* For further configuration read, preserve current directory. */
2870 vty_save_cwd ();
2871
2872 vtyvec = vector_init (VECTOR_MIN_SIZE);
2873
paulb21b19c2003-06-15 01:28:29 +00002874 master = master_thread;
2875
paul718e3742002-12-13 20:15:29 +00002876 /* Initilize server thread vector. */
2877 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2878
2879 /* Install bgp top node. */
2880 install_node (&vty_node, vty_config_write);
2881
2882 install_element (VIEW_NODE, &config_who_cmd);
2883 install_element (VIEW_NODE, &show_history_cmd);
2884 install_element (ENABLE_NODE, &config_who_cmd);
2885 install_element (CONFIG_NODE, &line_vty_cmd);
2886 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2887 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2888 install_element (CONFIG_NODE, &show_history_cmd);
2889 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2890 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
2891 install_element (ENABLE_NODE, &show_history_cmd);
2892
2893 install_default (VTY_NODE);
2894 install_element (VTY_NODE, &exec_timeout_min_cmd);
2895 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2896 install_element (VTY_NODE, &no_exec_timeout_cmd);
2897 install_element (VTY_NODE, &vty_access_class_cmd);
2898 install_element (VTY_NODE, &no_vty_access_class_cmd);
2899 install_element (VTY_NODE, &vty_login_cmd);
2900 install_element (VTY_NODE, &no_vty_login_cmd);
2901#ifdef HAVE_IPV6
2902 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2903 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2904#endif /* HAVE_IPV6 */
2905}