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