blob: 8de32870951ef439ff433baa78a38feab70095f9 [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];
Andrew J. Schorr08942da2006-07-03 20:58:29 +0000157 struct tm *tm;
158
159 if ((tm = localtime(&recent_time.tv_sec)) != NULL)
160 len = strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S ", tm);
161 else
162 len = 0;
paul718e3742002-12-13 20:15:29 +0000163
ajs274a4a42004-12-07 15:39:31 +0000164 if (level)
Andrew J. Schorr08942da2006-07-03 20:58:29 +0000165 ret = snprintf(buf+len, sizeof(buf)-len, "%s: %s: ", level, proto_str);
ajs274a4a42004-12-07 15:39:31 +0000166 else
Andrew J. Schorr08942da2006-07-03 20:58:29 +0000167 ret = snprintf(buf+len, sizeof(buf)-len, "%s: ", proto_str);
168 if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf)))
paul718e3742002-12-13 20:15:29 +0000169 return -1;
paul718e3742002-12-13 20:15:29 +0000170
ajs9fc7ebf2005-02-23 15:12:34 +0000171 if (((ret = vsnprintf(buf+len, sizeof(buf)-len, format, va)) < 0) ||
172 ((size_t)((len += ret)+2) > sizeof(buf)))
173 return -1;
paul718e3742002-12-13 20:15:29 +0000174
ajs9fc7ebf2005-02-23 15:12:34 +0000175 buf[len++] = '\r';
176 buf[len++] = '\n';
177
178 if (write(vty->fd, buf, len) < 0)
179 {
180 if (ERRNO_IO_RETRY(errno))
181 /* Kernel buffer is full, probably too much debugging output, so just
182 drop the data and ignore. */
183 return -1;
184 /* Fatal I/O error. */
185 zlog_warn("%s: write failed to vty client fd %d, closing: %s",
186 __func__, vty->fd, safe_strerror(errno));
187 buffer_reset(vty->obuf);
188 vty_close(vty);
189 return -1;
190 }
191 return 0;
paul718e3742002-12-13 20:15:29 +0000192}
193
194/* Output current time to the vty. */
195void
196vty_time_print (struct vty *vty, int cr)
197{
198 time_t clock;
199 struct tm *tm;
200#define TIME_BUF 25
201 char buf [TIME_BUF];
202 int ret;
203
204 time (&clock);
205 tm = localtime (&clock);
206
207 ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
208 if (ret == 0)
209 {
210 zlog (NULL, LOG_INFO, "strftime error");
211 return;
212 }
213 if (cr)
214 vty_out (vty, "%s\n", buf);
215 else
216 vty_out (vty, "%s ", buf);
217
218 return;
219}
220
221/* Say hello to vty interface. */
222void
223vty_hello (struct vty *vty)
224{
paul3b0c5d92005-03-08 10:43:43 +0000225 if (host.motdfile)
226 {
227 FILE *f;
228 char buf[4096];
paul22085182005-03-08 16:00:12 +0000229
paul3b0c5d92005-03-08 10:43:43 +0000230 f = fopen (host.motdfile, "r");
231 if (f)
232 {
paulb45da6f2005-03-08 15:16:57 +0000233 while (fgets (buf, sizeof (buf), f))
paul3b0c5d92005-03-08 10:43:43 +0000234 {
paulb45da6f2005-03-08 15:16:57 +0000235 char *s;
paul22085182005-03-08 16:00:12 +0000236 /* work backwards to ignore trailling isspace() */
gdtf80a0162005-12-29 16:03:32 +0000237 for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
paul22085182005-03-08 16:00:12 +0000238 s--);
239 *s = '\0';
240 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
241 }
paul3b0c5d92005-03-08 10:43:43 +0000242 fclose (f);
243 }
244 else
paulb45da6f2005-03-08 15:16:57 +0000245 vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
paul3b0c5d92005-03-08 10:43:43 +0000246 }
247 else if (host.motd)
paul718e3742002-12-13 20:15:29 +0000248 vty_out (vty, host.motd);
249}
250
251/* Put out prompt and wait input from user. */
252static void
253vty_prompt (struct vty *vty)
254{
255 struct utsname names;
256 const char*hostname;
257
258 if (vty->type == VTY_TERM)
259 {
260 hostname = host.name;
261 if (!hostname)
262 {
263 uname (&names);
264 hostname = names.nodename;
265 }
266 vty_out (vty, cmd_prompt (vty->node), hostname);
267 }
268}
269
270/* Send WILL TELOPT_ECHO to remote server. */
ajs9fc7ebf2005-02-23 15:12:34 +0000271static void
paul718e3742002-12-13 20:15:29 +0000272vty_will_echo (struct vty *vty)
273{
paul02ff83c2004-06-11 11:27:03 +0000274 unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
paul718e3742002-12-13 20:15:29 +0000275 vty_out (vty, "%s", cmd);
276}
277
278/* Make suppress Go-Ahead telnet option. */
279static void
280vty_will_suppress_go_ahead (struct vty *vty)
281{
paul02ff83c2004-06-11 11:27:03 +0000282 unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
paul718e3742002-12-13 20:15:29 +0000283 vty_out (vty, "%s", cmd);
284}
285
286/* Make don't use linemode over telnet. */
287static void
288vty_dont_linemode (struct vty *vty)
289{
paul02ff83c2004-06-11 11:27:03 +0000290 unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
paul718e3742002-12-13 20:15:29 +0000291 vty_out (vty, "%s", cmd);
292}
293
294/* Use window size. */
295static void
296vty_do_window_size (struct vty *vty)
297{
paul02ff83c2004-06-11 11:27:03 +0000298 unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
paul718e3742002-12-13 20:15:29 +0000299 vty_out (vty, "%s", cmd);
300}
301
302#if 0 /* Currently not used. */
303/* Make don't use lflow vty interface. */
304static void
305vty_dont_lflow_ahead (struct vty *vty)
306{
paul02ff83c2004-06-11 11:27:03 +0000307 unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
paul718e3742002-12-13 20:15:29 +0000308 vty_out (vty, "%s", cmd);
309}
310#endif /* 0 */
311
312/* Allocate new vty struct. */
313struct vty *
314vty_new ()
315{
316 struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
317
ajs9fc7ebf2005-02-23 15:12:34 +0000318 new->obuf = buffer_new(0); /* Use default buffer size. */
paul718e3742002-12-13 20:15:29 +0000319 new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
320 new->max = VTY_BUFSIZ;
paul718e3742002-12-13 20:15:29 +0000321
322 return new;
323}
324
325/* Authentication of vty */
326static void
327vty_auth (struct vty *vty, char *buf)
328{
329 char *passwd = NULL;
330 enum node_type next_node = 0;
331 int fail;
332 char *crypt (const char *, const char *);
333
334 switch (vty->node)
335 {
336 case AUTH_NODE:
337 if (host.encrypt)
338 passwd = host.password_encrypt;
339 else
340 passwd = host.password;
341 if (host.advanced)
342 next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
343 else
344 next_node = VIEW_NODE;
345 break;
346 case AUTH_ENABLE_NODE:
347 if (host.encrypt)
348 passwd = host.enable_encrypt;
349 else
350 passwd = host.enable;
351 next_node = ENABLE_NODE;
352 break;
353 }
354
355 if (passwd)
356 {
357 if (host.encrypt)
358 fail = strcmp (crypt(buf, passwd), passwd);
359 else
360 fail = strcmp (buf, passwd);
361 }
362 else
363 fail = 1;
364
365 if (! fail)
366 {
367 vty->fail = 0;
368 vty->node = next_node; /* Success ! */
369 }
370 else
371 {
372 vty->fail++;
373 if (vty->fail >= 3)
374 {
375 if (vty->node == AUTH_NODE)
376 {
377 vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
378 vty->status = VTY_CLOSE;
379 }
380 else
381 {
382 /* AUTH_ENABLE_NODE */
383 vty->fail = 0;
384 vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
385 vty->node = VIEW_NODE;
386 }
387 }
388 }
389}
390
391/* Command execution over the vty interface. */
ajs9fc7ebf2005-02-23 15:12:34 +0000392static int
paul718e3742002-12-13 20:15:29 +0000393vty_command (struct vty *vty, char *buf)
394{
395 int ret;
396 vector vline;
vincentfbf5d032005-09-29 11:25:50 +0000397 const char *protocolname;
paul718e3742002-12-13 20:15:29 +0000398
399 /* Split readline string up into the vector */
400 vline = cmd_make_strvec (buf);
401
402 if (vline == NULL)
403 return CMD_SUCCESS;
404
ajs924b9222005-04-16 17:11:24 +0000405#ifdef CONSUMED_TIME_CHECK
406 {
407 RUSAGE_T before;
408 RUSAGE_T after;
ajs8b70d0b2005-04-28 01:31:13 +0000409 unsigned long realtime, cputime;
ajs924b9222005-04-16 17:11:24 +0000410
411 GETRUSAGE(&before);
412#endif /* CONSUMED_TIME_CHECK */
413
hasso87d683b2005-01-16 23:31:54 +0000414 ret = cmd_execute_command (vline, vty, NULL, 0);
paul718e3742002-12-13 20:15:29 +0000415
vincentfbf5d032005-09-29 11:25:50 +0000416 /* Get the name of the protocol if any */
417 if (zlog_default)
418 protocolname = zlog_proto_names[zlog_default->protocol];
419 else
420 protocolname = zlog_proto_names[ZLOG_NONE];
421
ajs924b9222005-04-16 17:11:24 +0000422#ifdef CONSUMED_TIME_CHECK
423 GETRUSAGE(&after);
ajs8b70d0b2005-04-28 01:31:13 +0000424 if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
425 CONSUMED_TIME_CHECK)
ajs924b9222005-04-16 17:11:24 +0000426 /* Warn about CPU hog that must be fixed. */
ajs8b70d0b2005-04-28 01:31:13 +0000427 zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
428 realtime/1000, cputime/1000, buf);
ajs924b9222005-04-16 17:11:24 +0000429 }
430#endif /* CONSUMED_TIME_CHECK */
431
paul718e3742002-12-13 20:15:29 +0000432 if (ret != CMD_SUCCESS)
433 switch (ret)
434 {
435 case CMD_WARNING:
436 if (vty->type == VTY_FILE)
437 vty_out (vty, "Warning...%s", VTY_NEWLINE);
438 break;
439 case CMD_ERR_AMBIGUOUS:
440 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
441 break;
442 case CMD_ERR_NO_MATCH:
vincentfbf5d032005-09-29 11:25:50 +0000443 vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000444 break;
445 case CMD_ERR_INCOMPLETE:
446 vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
447 break;
448 }
449 cmd_free_strvec (vline);
450
451 return ret;
452}
453
ajs9fc7ebf2005-02-23 15:12:34 +0000454static const char telnet_backward_char = 0x08;
455static const char telnet_space_char = ' ';
paul718e3742002-12-13 20:15:29 +0000456
457/* Basic function to write buffer to vty. */
458static void
ajs9fc7ebf2005-02-23 15:12:34 +0000459vty_write (struct vty *vty, const char *buf, size_t nbytes)
paul718e3742002-12-13 20:15:29 +0000460{
461 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
462 return;
463
464 /* Should we do buffering here ? And make vty_flush (vty) ? */
ajs9fc7ebf2005-02-23 15:12:34 +0000465 buffer_put (vty->obuf, buf, nbytes);
paul718e3742002-12-13 20:15:29 +0000466}
467
468/* Ensure length of input buffer. Is buffer is short, double it. */
469static void
470vty_ensure (struct vty *vty, int length)
471{
472 if (vty->max <= length)
473 {
474 vty->max *= 2;
475 vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
476 }
477}
478
479/* Basic function to insert character into vty. */
480static void
481vty_self_insert (struct vty *vty, char c)
482{
483 int i;
484 int length;
485
486 vty_ensure (vty, vty->length + 1);
487 length = vty->length - vty->cp;
488 memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
489 vty->buf[vty->cp] = c;
490
491 vty_write (vty, &vty->buf[vty->cp], length + 1);
492 for (i = 0; i < length; i++)
493 vty_write (vty, &telnet_backward_char, 1);
494
495 vty->cp++;
496 vty->length++;
497}
498
499/* Self insert character 'c' in overwrite mode. */
500static void
501vty_self_insert_overwrite (struct vty *vty, char c)
502{
503 vty_ensure (vty, vty->length + 1);
504 vty->buf[vty->cp++] = c;
505
506 if (vty->cp > vty->length)
507 vty->length++;
508
509 if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
510 return;
511
512 vty_write (vty, &c, 1);
513}
514
515/* Insert a word into vty interface with overwrite mode. */
516static void
517vty_insert_word_overwrite (struct vty *vty, char *str)
518{
519 int len = strlen (str);
520 vty_write (vty, str, len);
521 strcpy (&vty->buf[vty->cp], str);
522 vty->cp += len;
523 vty->length = vty->cp;
524}
525
526/* Forward character. */
527static void
528vty_forward_char (struct vty *vty)
529{
530 if (vty->cp < vty->length)
531 {
532 vty_write (vty, &vty->buf[vty->cp], 1);
533 vty->cp++;
534 }
535}
536
537/* Backward character. */
538static void
539vty_backward_char (struct vty *vty)
540{
541 if (vty->cp > 0)
542 {
543 vty->cp--;
544 vty_write (vty, &telnet_backward_char, 1);
545 }
546}
547
548/* Move to the beginning of the line. */
549static void
550vty_beginning_of_line (struct vty *vty)
551{
552 while (vty->cp)
553 vty_backward_char (vty);
554}
555
556/* Move to the end of the line. */
557static void
558vty_end_of_line (struct vty *vty)
559{
560 while (vty->cp < vty->length)
561 vty_forward_char (vty);
562}
563
564static void vty_kill_line_from_beginning (struct vty *);
565static void vty_redraw_line (struct vty *);
566
567/* Print command line history. This function is called from
568 vty_next_line and vty_previous_line. */
569static void
570vty_history_print (struct vty *vty)
571{
572 int length;
573
574 vty_kill_line_from_beginning (vty);
575
576 /* Get previous line from history buffer */
577 length = strlen (vty->hist[vty->hp]);
578 memcpy (vty->buf, vty->hist[vty->hp], length);
579 vty->cp = vty->length = length;
580
581 /* Redraw current line */
582 vty_redraw_line (vty);
583}
584
585/* Show next command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000586static void
paul718e3742002-12-13 20:15:29 +0000587vty_next_line (struct vty *vty)
588{
589 int try_index;
590
591 if (vty->hp == vty->hindex)
592 return;
593
594 /* Try is there history exist or not. */
595 try_index = vty->hp;
596 if (try_index == (VTY_MAXHIST - 1))
597 try_index = 0;
598 else
599 try_index++;
600
601 /* If there is not history return. */
602 if (vty->hist[try_index] == NULL)
603 return;
604 else
605 vty->hp = try_index;
606
607 vty_history_print (vty);
608}
609
610/* Show previous command line history. */
ajs9fc7ebf2005-02-23 15:12:34 +0000611static void
paul718e3742002-12-13 20:15:29 +0000612vty_previous_line (struct vty *vty)
613{
614 int try_index;
615
616 try_index = vty->hp;
617 if (try_index == 0)
618 try_index = VTY_MAXHIST - 1;
619 else
620 try_index--;
621
622 if (vty->hist[try_index] == NULL)
623 return;
624 else
625 vty->hp = try_index;
626
627 vty_history_print (vty);
628}
629
630/* This function redraw all of the command line character. */
631static void
632vty_redraw_line (struct vty *vty)
633{
634 vty_write (vty, vty->buf, vty->length);
635 vty->cp = vty->length;
636}
637
638/* Forward word. */
639static void
640vty_forward_word (struct vty *vty)
641{
642 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
643 vty_forward_char (vty);
644
645 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
646 vty_forward_char (vty);
647}
648
649/* Backward word without skipping training space. */
650static void
651vty_backward_pure_word (struct vty *vty)
652{
653 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
654 vty_backward_char (vty);
655}
656
657/* Backward word. */
658static void
659vty_backward_word (struct vty *vty)
660{
661 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
662 vty_backward_char (vty);
663
664 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
665 vty_backward_char (vty);
666}
667
668/* When '^D' is typed at the beginning of the line we move to the down
669 level. */
670static void
671vty_down_level (struct vty *vty)
672{
673 vty_out (vty, "%s", VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +0000674 (*config_exit_cmd.func)(NULL, vty, 0, NULL);
paul718e3742002-12-13 20:15:29 +0000675 vty_prompt (vty);
676 vty->cp = 0;
677}
678
679/* When '^Z' is received from vty, move down to the enable mode. */
ajs9fc7ebf2005-02-23 15:12:34 +0000680static void
paul718e3742002-12-13 20:15:29 +0000681vty_end_config (struct vty *vty)
682{
683 vty_out (vty, "%s", VTY_NEWLINE);
684
685 switch (vty->node)
686 {
687 case VIEW_NODE:
688 case ENABLE_NODE:
689 /* Nothing to do. */
690 break;
691 case CONFIG_NODE:
692 case INTERFACE_NODE:
693 case ZEBRA_NODE:
694 case RIP_NODE:
695 case RIPNG_NODE:
696 case BGP_NODE:
697 case BGP_VPNV4_NODE:
698 case BGP_IPV4_NODE:
699 case BGP_IPV4M_NODE:
700 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +0000701 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +0000702 case RMAP_NODE:
703 case OSPF_NODE:
704 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +0000705 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +0000706 case KEYCHAIN_NODE:
707 case KEYCHAIN_KEY_NODE:
708 case MASC_NODE:
709 case VTY_NODE:
710 vty_config_unlock (vty);
711 vty->node = ENABLE_NODE;
712 break;
713 default:
714 /* Unknown node, we have to ignore it. */
715 break;
716 }
717
718 vty_prompt (vty);
719 vty->cp = 0;
720}
721
722/* Delete a charcter at the current point. */
723static void
724vty_delete_char (struct vty *vty)
725{
726 int i;
727 int size;
728
729 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
730 return;
731
732 if (vty->length == 0)
733 {
734 vty_down_level (vty);
735 return;
736 }
737
738 if (vty->cp == vty->length)
739 return; /* completion need here? */
740
741 size = vty->length - vty->cp;
742
743 vty->length--;
744 memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
745 vty->buf[vty->length] = '\0';
746
747 vty_write (vty, &vty->buf[vty->cp], size - 1);
748 vty_write (vty, &telnet_space_char, 1);
749
750 for (i = 0; i < size; i++)
751 vty_write (vty, &telnet_backward_char, 1);
752}
753
754/* Delete a character before the point. */
755static void
756vty_delete_backward_char (struct vty *vty)
757{
758 if (vty->cp == 0)
759 return;
760
761 vty_backward_char (vty);
762 vty_delete_char (vty);
763}
764
765/* Kill rest of line from current point. */
766static void
767vty_kill_line (struct vty *vty)
768{
769 int i;
770 int size;
771
772 size = vty->length - vty->cp;
773
774 if (size == 0)
775 return;
776
777 for (i = 0; i < size; i++)
778 vty_write (vty, &telnet_space_char, 1);
779 for (i = 0; i < size; i++)
780 vty_write (vty, &telnet_backward_char, 1);
781
782 memset (&vty->buf[vty->cp], 0, size);
783 vty->length = vty->cp;
784}
785
786/* Kill line from the beginning. */
787static void
788vty_kill_line_from_beginning (struct vty *vty)
789{
790 vty_beginning_of_line (vty);
791 vty_kill_line (vty);
792}
793
794/* Delete a word before the point. */
795static void
796vty_forward_kill_word (struct vty *vty)
797{
798 while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
799 vty_delete_char (vty);
800 while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
801 vty_delete_char (vty);
802}
803
804/* Delete a word before the point. */
805static void
806vty_backward_kill_word (struct vty *vty)
807{
808 while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
809 vty_delete_backward_char (vty);
810 while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
811 vty_delete_backward_char (vty);
812}
813
814/* Transpose chars before or at the point. */
815static void
816vty_transpose_chars (struct vty *vty)
817{
818 char c1, c2;
819
820 /* If length is short or point is near by the beginning of line then
821 return. */
822 if (vty->length < 2 || vty->cp < 1)
823 return;
824
825 /* In case of point is located at the end of the line. */
826 if (vty->cp == vty->length)
827 {
828 c1 = vty->buf[vty->cp - 1];
829 c2 = vty->buf[vty->cp - 2];
830
831 vty_backward_char (vty);
832 vty_backward_char (vty);
833 vty_self_insert_overwrite (vty, c1);
834 vty_self_insert_overwrite (vty, c2);
835 }
836 else
837 {
838 c1 = vty->buf[vty->cp];
839 c2 = vty->buf[vty->cp - 1];
840
841 vty_backward_char (vty);
842 vty_self_insert_overwrite (vty, c1);
843 vty_self_insert_overwrite (vty, c2);
844 }
845}
846
847/* Do completion at vty interface. */
848static void
849vty_complete_command (struct vty *vty)
850{
851 int i;
852 int ret;
853 char **matched = NULL;
854 vector vline;
855
856 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
857 return;
858
859 vline = cmd_make_strvec (vty->buf);
860 if (vline == NULL)
861 return;
862
863 /* In case of 'help \t'. */
864 if (isspace ((int) vty->buf[vty->length - 1]))
865 vector_set (vline, '\0');
866
867 matched = cmd_complete_command (vline, vty, &ret);
868
869 cmd_free_strvec (vline);
870
871 vty_out (vty, "%s", VTY_NEWLINE);
872 switch (ret)
873 {
874 case CMD_ERR_AMBIGUOUS:
875 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
876 vty_prompt (vty);
877 vty_redraw_line (vty);
878 break;
879 case CMD_ERR_NO_MATCH:
880 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
881 vty_prompt (vty);
882 vty_redraw_line (vty);
883 break;
884 case CMD_COMPLETE_FULL_MATCH:
885 vty_prompt (vty);
886 vty_redraw_line (vty);
887 vty_backward_pure_word (vty);
888 vty_insert_word_overwrite (vty, matched[0]);
889 vty_self_insert (vty, ' ');
890 XFREE (MTYPE_TMP, matched[0]);
891 break;
892 case CMD_COMPLETE_MATCH:
893 vty_prompt (vty);
894 vty_redraw_line (vty);
895 vty_backward_pure_word (vty);
896 vty_insert_word_overwrite (vty, matched[0]);
897 XFREE (MTYPE_TMP, matched[0]);
898 vector_only_index_free (matched);
899 return;
900 break;
901 case CMD_COMPLETE_LIST_MATCH:
902 for (i = 0; matched[i] != NULL; i++)
903 {
904 if (i != 0 && ((i % 6) == 0))
905 vty_out (vty, "%s", VTY_NEWLINE);
906 vty_out (vty, "%-10s ", matched[i]);
907 XFREE (MTYPE_TMP, matched[i]);
908 }
909 vty_out (vty, "%s", VTY_NEWLINE);
910
911 vty_prompt (vty);
912 vty_redraw_line (vty);
913 break;
914 case CMD_ERR_NOTHING_TODO:
915 vty_prompt (vty);
916 vty_redraw_line (vty);
917 break;
918 default:
919 break;
920 }
921 if (matched)
922 vector_only_index_free (matched);
923}
924
ajs9fc7ebf2005-02-23 15:12:34 +0000925static void
paul718e3742002-12-13 20:15:29 +0000926vty_describe_fold (struct vty *vty, int cmd_width,
hasso8c328f12004-10-05 21:01:23 +0000927 unsigned int desc_width, struct desc *desc)
paul718e3742002-12-13 20:15:29 +0000928{
hasso8c328f12004-10-05 21:01:23 +0000929 char *buf;
930 const char *cmd, *p;
paul718e3742002-12-13 20:15:29 +0000931 int pos;
932
933 cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
934
935 if (desc_width <= 0)
936 {
937 vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
938 return;
939 }
940
941 buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
942
943 for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
944 {
945 for (pos = desc_width; pos > 0; pos--)
946 if (*(p + pos) == ' ')
947 break;
948
949 if (pos == 0)
950 break;
951
952 strncpy (buf, p, pos);
953 buf[pos] = '\0';
954 vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
955
956 cmd = "";
957 }
958
959 vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
960
961 XFREE (MTYPE_TMP, buf);
962}
963
964/* Describe matched command function. */
965static void
966vty_describe_command (struct vty *vty)
967{
968 int ret;
969 vector vline;
970 vector describe;
hasso8c328f12004-10-05 21:01:23 +0000971 unsigned int i, width, desc_width;
paul718e3742002-12-13 20:15:29 +0000972 struct desc *desc, *desc_cr = NULL;
973
974 vline = cmd_make_strvec (vty->buf);
975
976 /* In case of '> ?'. */
977 if (vline == NULL)
978 {
979 vline = vector_init (1);
980 vector_set (vline, '\0');
981 }
982 else
983 if (isspace ((int) vty->buf[vty->length - 1]))
984 vector_set (vline, '\0');
985
986 describe = cmd_describe_command (vline, vty, &ret);
987
988 vty_out (vty, "%s", VTY_NEWLINE);
989
990 /* Ambiguous error. */
991 switch (ret)
992 {
993 case CMD_ERR_AMBIGUOUS:
paul718e3742002-12-13 20:15:29 +0000994 vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
Paul Jakma2fe8aba2006-05-12 23:22:01 +0000995 goto out;
paul718e3742002-12-13 20:15:29 +0000996 break;
997 case CMD_ERR_NO_MATCH:
paul718e3742002-12-13 20:15:29 +0000998 vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
Paul Jakma2fe8aba2006-05-12 23:22:01 +0000999 goto out;
paul718e3742002-12-13 20:15:29 +00001000 break;
1001 }
1002
1003 /* Get width of command string. */
1004 width = 0;
paul55468c82005-03-14 20:19:01 +00001005 for (i = 0; i < vector_active (describe); i++)
paul718e3742002-12-13 20:15:29 +00001006 if ((desc = vector_slot (describe, i)) != NULL)
1007 {
hasso8c328f12004-10-05 21:01:23 +00001008 unsigned int len;
paul718e3742002-12-13 20:15:29 +00001009
1010 if (desc->cmd[0] == '\0')
1011 continue;
1012
1013 len = strlen (desc->cmd);
1014 if (desc->cmd[0] == '.')
1015 len--;
1016
1017 if (width < len)
1018 width = len;
1019 }
1020
1021 /* Get width of description string. */
1022 desc_width = vty->width - (width + 6);
1023
1024 /* Print out description. */
paul55468c82005-03-14 20:19:01 +00001025 for (i = 0; i < vector_active (describe); i++)
paul718e3742002-12-13 20:15:29 +00001026 if ((desc = vector_slot (describe, i)) != NULL)
1027 {
1028 if (desc->cmd[0] == '\0')
1029 continue;
1030
1031 if (strcmp (desc->cmd, "<cr>") == 0)
1032 {
1033 desc_cr = desc;
1034 continue;
1035 }
1036
1037 if (!desc->str)
1038 vty_out (vty, " %-s%s",
1039 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1040 VTY_NEWLINE);
1041 else if (desc_width >= strlen (desc->str))
1042 vty_out (vty, " %-*s %s%s", width,
1043 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1044 desc->str, VTY_NEWLINE);
1045 else
1046 vty_describe_fold (vty, width, desc_width, desc);
1047
1048#if 0
1049 vty_out (vty, " %-*s %s%s", width
1050 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1051 desc->str ? desc->str : "", VTY_NEWLINE);
1052#endif /* 0 */
1053 }
1054
1055 if ((desc = desc_cr))
1056 {
1057 if (!desc->str)
1058 vty_out (vty, " %-s%s",
1059 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1060 VTY_NEWLINE);
1061 else if (desc_width >= strlen (desc->str))
1062 vty_out (vty, " %-*s %s%s", width,
1063 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1064 desc->str, VTY_NEWLINE);
1065 else
1066 vty_describe_fold (vty, width, desc_width, desc);
1067 }
1068
Paul Jakma2fe8aba2006-05-12 23:22:01 +00001069out:
paul718e3742002-12-13 20:15:29 +00001070 cmd_free_strvec (vline);
Paul Jakmad16e0432006-05-15 10:56:46 +00001071 if (describe)
1072 vector_free (describe);
paul718e3742002-12-13 20:15:29 +00001073
1074 vty_prompt (vty);
1075 vty_redraw_line (vty);
1076}
1077
ajs9fc7ebf2005-02-23 15:12:34 +00001078static void
paul718e3742002-12-13 20:15:29 +00001079vty_clear_buf (struct vty *vty)
1080{
1081 memset (vty->buf, 0, vty->max);
1082}
1083
1084/* ^C stop current input and do not add command line to the history. */
1085static void
1086vty_stop_input (struct vty *vty)
1087{
1088 vty->cp = vty->length = 0;
1089 vty_clear_buf (vty);
1090 vty_out (vty, "%s", VTY_NEWLINE);
1091
1092 switch (vty->node)
1093 {
1094 case VIEW_NODE:
1095 case ENABLE_NODE:
1096 /* Nothing to do. */
1097 break;
1098 case CONFIG_NODE:
1099 case INTERFACE_NODE:
1100 case ZEBRA_NODE:
1101 case RIP_NODE:
1102 case RIPNG_NODE:
1103 case BGP_NODE:
1104 case RMAP_NODE:
1105 case OSPF_NODE:
1106 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00001107 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00001108 case KEYCHAIN_NODE:
1109 case KEYCHAIN_KEY_NODE:
1110 case MASC_NODE:
1111 case VTY_NODE:
1112 vty_config_unlock (vty);
1113 vty->node = ENABLE_NODE;
1114 break;
1115 default:
1116 /* Unknown node, we have to ignore it. */
1117 break;
1118 }
1119 vty_prompt (vty);
1120
1121 /* Set history pointer to the latest one. */
1122 vty->hp = vty->hindex;
1123}
1124
1125/* Add current command line to the history buffer. */
1126static void
1127vty_hist_add (struct vty *vty)
1128{
1129 int index;
1130
1131 if (vty->length == 0)
1132 return;
1133
1134 index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1135
1136 /* Ignore the same string as previous one. */
1137 if (vty->hist[index])
1138 if (strcmp (vty->buf, vty->hist[index]) == 0)
1139 {
1140 vty->hp = vty->hindex;
1141 return;
1142 }
1143
1144 /* Insert history entry. */
1145 if (vty->hist[vty->hindex])
1146 XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1147 vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1148
1149 /* History index rotation. */
1150 vty->hindex++;
1151 if (vty->hindex == VTY_MAXHIST)
1152 vty->hindex = 0;
1153
1154 vty->hp = vty->hindex;
1155}
1156
1157/* #define TELNET_OPTION_DEBUG */
1158
1159/* Get telnet window size. */
1160static int
1161vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1162{
1163#ifdef TELNET_OPTION_DEBUG
1164 int i;
1165
1166 for (i = 0; i < nbytes; i++)
1167 {
1168 switch (buf[i])
1169 {
1170 case IAC:
1171 vty_out (vty, "IAC ");
1172 break;
1173 case WILL:
1174 vty_out (vty, "WILL ");
1175 break;
1176 case WONT:
1177 vty_out (vty, "WONT ");
1178 break;
1179 case DO:
1180 vty_out (vty, "DO ");
1181 break;
1182 case DONT:
1183 vty_out (vty, "DONT ");
1184 break;
1185 case SB:
1186 vty_out (vty, "SB ");
1187 break;
1188 case SE:
1189 vty_out (vty, "SE ");
1190 break;
1191 case TELOPT_ECHO:
1192 vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1193 break;
1194 case TELOPT_SGA:
1195 vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1196 break;
1197 case TELOPT_NAWS:
1198 vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1199 break;
1200 default:
1201 vty_out (vty, "%x ", buf[i]);
1202 break;
1203 }
1204 }
1205 vty_out (vty, "%s", VTY_NEWLINE);
1206
1207#endif /* TELNET_OPTION_DEBUG */
1208
1209 switch (buf[0])
1210 {
1211 case SB:
ajs9fc7ebf2005-02-23 15:12:34 +00001212 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001213 vty->iac_sb_in_progress = 1;
1214 return 0;
1215 break;
1216 case SE:
1217 {
paul718e3742002-12-13 20:15:29 +00001218 if (!vty->iac_sb_in_progress)
1219 return 0;
1220
ajs9fc7ebf2005-02-23 15:12:34 +00001221 if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
paul718e3742002-12-13 20:15:29 +00001222 {
1223 vty->iac_sb_in_progress = 0;
1224 return 0;
1225 }
ajs9fc7ebf2005-02-23 15:12:34 +00001226 switch (vty->sb_buf[0])
paul718e3742002-12-13 20:15:29 +00001227 {
1228 case TELOPT_NAWS:
ajs9fc7ebf2005-02-23 15:12:34 +00001229 if (vty->sb_len != TELNET_NAWS_SB_LEN)
1230 zlog_warn("RFC 1073 violation detected: telnet NAWS option "
1231 "should send %d characters, but we received %lu",
1232 TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
1233 else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
1234 zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, "
1235 "too small to handle the telnet NAWS option",
1236 (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
1237 else
1238 {
1239 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
1240 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
1241#ifdef TELNET_OPTION_DEBUG
1242 vty_out(vty, "TELNET NAWS window size negotiation completed: "
1243 "width %d, height %d%s",
1244 vty->width, vty->height, VTY_NEWLINE);
1245#endif
1246 }
paul718e3742002-12-13 20:15:29 +00001247 break;
1248 }
1249 vty->iac_sb_in_progress = 0;
1250 return 0;
1251 break;
1252 }
1253 default:
1254 break;
1255 }
1256 return 1;
1257}
1258
1259/* Execute current command line. */
1260static int
1261vty_execute (struct vty *vty)
1262{
1263 int ret;
1264
1265 ret = CMD_SUCCESS;
1266
1267 switch (vty->node)
1268 {
1269 case AUTH_NODE:
1270 case AUTH_ENABLE_NODE:
1271 vty_auth (vty, vty->buf);
1272 break;
1273 default:
1274 ret = vty_command (vty, vty->buf);
1275 if (vty->type == VTY_TERM)
1276 vty_hist_add (vty);
1277 break;
1278 }
1279
1280 /* Clear command line buffer. */
1281 vty->cp = vty->length = 0;
1282 vty_clear_buf (vty);
1283
ajs5a646652004-11-05 01:25:55 +00001284 if (vty->status != VTY_CLOSE )
paul718e3742002-12-13 20:15:29 +00001285 vty_prompt (vty);
1286
1287 return ret;
1288}
1289
1290#define CONTROL(X) ((X) - '@')
1291#define VTY_NORMAL 0
1292#define VTY_PRE_ESCAPE 1
1293#define VTY_ESCAPE 2
1294
1295/* Escape character command map. */
1296static void
1297vty_escape_map (unsigned char c, struct vty *vty)
1298{
1299 switch (c)
1300 {
1301 case ('A'):
1302 vty_previous_line (vty);
1303 break;
1304 case ('B'):
1305 vty_next_line (vty);
1306 break;
1307 case ('C'):
1308 vty_forward_char (vty);
1309 break;
1310 case ('D'):
1311 vty_backward_char (vty);
1312 break;
1313 default:
1314 break;
1315 }
1316
1317 /* Go back to normal mode. */
1318 vty->escape = VTY_NORMAL;
1319}
1320
1321/* Quit print out to the buffer. */
1322static void
1323vty_buffer_reset (struct vty *vty)
1324{
1325 buffer_reset (vty->obuf);
1326 vty_prompt (vty);
1327 vty_redraw_line (vty);
1328}
1329
1330/* Read data via vty socket. */
1331static int
1332vty_read (struct thread *thread)
1333{
1334 int i;
paul718e3742002-12-13 20:15:29 +00001335 int nbytes;
1336 unsigned char buf[VTY_READ_BUFSIZ];
1337
1338 int vty_sock = THREAD_FD (thread);
1339 struct vty *vty = THREAD_ARG (thread);
1340 vty->t_read = NULL;
1341
1342 /* Read raw data from socket */
ajs9fc7ebf2005-02-23 15:12:34 +00001343 if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0)
1344 {
1345 if (nbytes < 0)
1346 {
1347 if (ERRNO_IO_RETRY(errno))
1348 {
1349 vty_event (VTY_READ, vty_sock, vty);
1350 return 0;
1351 }
1352 zlog_warn("%s: read error on vty client fd %d, closing: %s",
1353 __func__, vty->fd, safe_strerror(errno));
1354 }
1355 buffer_reset(vty->obuf);
1356 vty->status = VTY_CLOSE;
1357 }
paul718e3742002-12-13 20:15:29 +00001358
1359 for (i = 0; i < nbytes; i++)
1360 {
1361 if (buf[i] == IAC)
1362 {
1363 if (!vty->iac)
1364 {
1365 vty->iac = 1;
1366 continue;
1367 }
1368 else
1369 {
1370 vty->iac = 0;
1371 }
1372 }
1373
1374 if (vty->iac_sb_in_progress && !vty->iac)
1375 {
ajs9fc7ebf2005-02-23 15:12:34 +00001376 if (vty->sb_len < sizeof(vty->sb_buf))
1377 vty->sb_buf[vty->sb_len] = buf[i];
1378 vty->sb_len++;
paul718e3742002-12-13 20:15:29 +00001379 continue;
1380 }
1381
1382 if (vty->iac)
1383 {
1384 /* In case of telnet command */
paul5b8c1b02003-10-15 23:08:55 +00001385 int ret = 0;
paule9372532003-10-26 21:36:07 +00001386 ret = vty_telnet_option (vty, buf + i, nbytes - i);
paul718e3742002-12-13 20:15:29 +00001387 vty->iac = 0;
1388 i += ret;
1389 continue;
1390 }
paul5b8c1b02003-10-15 23:08:55 +00001391
paul718e3742002-12-13 20:15:29 +00001392
1393 if (vty->status == VTY_MORE)
1394 {
1395 switch (buf[i])
1396 {
1397 case CONTROL('C'):
1398 case 'q':
1399 case 'Q':
paul718e3742002-12-13 20:15:29 +00001400 vty_buffer_reset (vty);
1401 break;
1402#if 0 /* More line does not work for "show ip bgp". */
1403 case '\n':
1404 case '\r':
1405 vty->status = VTY_MORELINE;
1406 break;
1407#endif
1408 default:
paul718e3742002-12-13 20:15:29 +00001409 break;
1410 }
1411 continue;
1412 }
1413
1414 /* Escape character. */
1415 if (vty->escape == VTY_ESCAPE)
1416 {
1417 vty_escape_map (buf[i], vty);
1418 continue;
1419 }
1420
1421 /* Pre-escape status. */
1422 if (vty->escape == VTY_PRE_ESCAPE)
1423 {
1424 switch (buf[i])
1425 {
1426 case '[':
1427 vty->escape = VTY_ESCAPE;
1428 break;
1429 case 'b':
1430 vty_backward_word (vty);
1431 vty->escape = VTY_NORMAL;
1432 break;
1433 case 'f':
1434 vty_forward_word (vty);
1435 vty->escape = VTY_NORMAL;
1436 break;
1437 case 'd':
1438 vty_forward_kill_word (vty);
1439 vty->escape = VTY_NORMAL;
1440 break;
1441 case CONTROL('H'):
1442 case 0x7f:
1443 vty_backward_kill_word (vty);
1444 vty->escape = VTY_NORMAL;
1445 break;
1446 default:
1447 vty->escape = VTY_NORMAL;
1448 break;
1449 }
1450 continue;
1451 }
1452
1453 switch (buf[i])
1454 {
1455 case CONTROL('A'):
1456 vty_beginning_of_line (vty);
1457 break;
1458 case CONTROL('B'):
1459 vty_backward_char (vty);
1460 break;
1461 case CONTROL('C'):
1462 vty_stop_input (vty);
1463 break;
1464 case CONTROL('D'):
1465 vty_delete_char (vty);
1466 break;
1467 case CONTROL('E'):
1468 vty_end_of_line (vty);
1469 break;
1470 case CONTROL('F'):
1471 vty_forward_char (vty);
1472 break;
1473 case CONTROL('H'):
1474 case 0x7f:
1475 vty_delete_backward_char (vty);
1476 break;
1477 case CONTROL('K'):
1478 vty_kill_line (vty);
1479 break;
1480 case CONTROL('N'):
1481 vty_next_line (vty);
1482 break;
1483 case CONTROL('P'):
1484 vty_previous_line (vty);
1485 break;
1486 case CONTROL('T'):
1487 vty_transpose_chars (vty);
1488 break;
1489 case CONTROL('U'):
1490 vty_kill_line_from_beginning (vty);
1491 break;
1492 case CONTROL('W'):
1493 vty_backward_kill_word (vty);
1494 break;
1495 case CONTROL('Z'):
1496 vty_end_config (vty);
1497 break;
1498 case '\n':
1499 case '\r':
1500 vty_out (vty, "%s", VTY_NEWLINE);
1501 vty_execute (vty);
1502 break;
1503 case '\t':
1504 vty_complete_command (vty);
1505 break;
1506 case '?':
1507 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1508 vty_self_insert (vty, buf[i]);
1509 else
1510 vty_describe_command (vty);
1511 break;
1512 case '\033':
1513 if (i + 1 < nbytes && buf[i + 1] == '[')
1514 {
1515 vty->escape = VTY_ESCAPE;
1516 i++;
1517 }
1518 else
1519 vty->escape = VTY_PRE_ESCAPE;
1520 break;
1521 default:
1522 if (buf[i] > 31 && buf[i] < 127)
1523 vty_self_insert (vty, buf[i]);
1524 break;
1525 }
1526 }
1527
1528 /* Check status. */
1529 if (vty->status == VTY_CLOSE)
1530 vty_close (vty);
1531 else
1532 {
1533 vty_event (VTY_WRITE, vty_sock, vty);
1534 vty_event (VTY_READ, vty_sock, vty);
1535 }
1536 return 0;
1537}
1538
1539/* Flush buffer to the vty. */
1540static int
1541vty_flush (struct thread *thread)
1542{
1543 int erase;
ajs9fc7ebf2005-02-23 15:12:34 +00001544 buffer_status_t flushrc;
paul718e3742002-12-13 20:15:29 +00001545 int vty_sock = THREAD_FD (thread);
1546 struct vty *vty = THREAD_ARG (thread);
ajs9fc7ebf2005-02-23 15:12:34 +00001547
paul718e3742002-12-13 20:15:29 +00001548 vty->t_write = NULL;
1549
1550 /* Tempolary disable read thread. */
ajs9fc7ebf2005-02-23 15:12:34 +00001551 if ((vty->lines == 0) && vty->t_read)
1552 {
1553 thread_cancel (vty->t_read);
1554 vty->t_read = NULL;
1555 }
paul718e3742002-12-13 20:15:29 +00001556
1557 /* Function execution continue. */
ajs9fc7ebf2005-02-23 15:12:34 +00001558 erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE));
paul718e3742002-12-13 20:15:29 +00001559
ajs9fc7ebf2005-02-23 15:12:34 +00001560 /* N.B. if width is 0, that means we don't know the window size. */
1561 if ((vty->lines == 0) || (vty->width == 0))
1562 flushrc = buffer_flush_available(vty->obuf, vty->fd);
1563 else if (vty->status == VTY_MORELINE)
1564 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1565 1, erase, 0);
1566 else
1567 flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width,
1568 vty->lines >= 0 ? vty->lines :
1569 vty->height,
1570 erase, 0);
1571 switch (flushrc)
1572 {
1573 case BUFFER_ERROR:
1574 zlog_warn("buffer_flush failed on vty client fd %d, closing",
1575 vty->fd);
1576 buffer_reset(vty->obuf);
1577 vty_close(vty);
1578 return 0;
1579 case BUFFER_EMPTY:
1580 if (vty->status == VTY_CLOSE)
1581 vty_close (vty);
paul718e3742002-12-13 20:15:29 +00001582 else
1583 {
ajs9fc7ebf2005-02-23 15:12:34 +00001584 vty->status = VTY_NORMAL;
paul718e3742002-12-13 20:15:29 +00001585 if (vty->lines == 0)
ajs9fc7ebf2005-02-23 15:12:34 +00001586 vty_event (VTY_READ, vty_sock, vty);
paul718e3742002-12-13 20:15:29 +00001587 }
ajs9fc7ebf2005-02-23 15:12:34 +00001588 break;
1589 case BUFFER_PENDING:
1590 /* There is more data waiting to be written. */
1591 vty->status = VTY_MORE;
1592 if (vty->lines == 0)
1593 vty_event (VTY_WRITE, vty_sock, vty);
1594 break;
1595 }
paul718e3742002-12-13 20:15:29 +00001596
1597 return 0;
1598}
1599
1600/* Create new vty structure. */
ajs9fc7ebf2005-02-23 15:12:34 +00001601static struct vty *
paul718e3742002-12-13 20:15:29 +00001602vty_create (int vty_sock, union sockunion *su)
1603{
1604 struct vty *vty;
1605
1606 /* Allocate new vty structure and set up default values. */
1607 vty = vty_new ();
1608 vty->fd = vty_sock;
1609 vty->type = VTY_TERM;
1610 vty->address = sockunion_su2str (su);
1611 if (no_password_check)
1612 {
1613 if (host.advanced)
1614 vty->node = ENABLE_NODE;
1615 else
1616 vty->node = VIEW_NODE;
1617 }
1618 else
1619 vty->node = AUTH_NODE;
1620 vty->fail = 0;
1621 vty->cp = 0;
1622 vty_clear_buf (vty);
1623 vty->length = 0;
1624 memset (vty->hist, 0, sizeof (vty->hist));
1625 vty->hp = 0;
1626 vty->hindex = 0;
1627 vector_set_index (vtyvec, vty_sock, vty);
1628 vty->status = VTY_NORMAL;
1629 vty->v_timeout = vty_timeout_val;
1630 if (host.lines >= 0)
1631 vty->lines = host.lines;
1632 else
1633 vty->lines = -1;
1634 vty->iac = 0;
1635 vty->iac_sb_in_progress = 0;
ajs9fc7ebf2005-02-23 15:12:34 +00001636 vty->sb_len = 0;
paul718e3742002-12-13 20:15:29 +00001637
1638 if (! no_password_check)
1639 {
1640 /* Vty is not available if password isn't set. */
1641 if (host.password == NULL && host.password_encrypt == NULL)
1642 {
1643 vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1644 vty->status = VTY_CLOSE;
1645 vty_close (vty);
1646 return NULL;
1647 }
1648 }
1649
1650 /* Say hello to the world. */
1651 vty_hello (vty);
1652 if (! no_password_check)
1653 vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1654
1655 /* Setting up terminal. */
1656 vty_will_echo (vty);
1657 vty_will_suppress_go_ahead (vty);
1658
1659 vty_dont_linemode (vty);
1660 vty_do_window_size (vty);
1661 /* vty_dont_lflow_ahead (vty); */
1662
1663 vty_prompt (vty);
1664
1665 /* Add read/write thread. */
1666 vty_event (VTY_WRITE, vty_sock, vty);
1667 vty_event (VTY_READ, vty_sock, vty);
1668
1669 return vty;
1670}
1671
1672/* Accept connection from the network. */
1673static int
1674vty_accept (struct thread *thread)
1675{
1676 int vty_sock;
1677 struct vty *vty;
1678 union sockunion su;
1679 int ret;
1680 unsigned int on;
1681 int accept_sock;
1682 struct prefix *p = NULL;
1683 struct access_list *acl = NULL;
1684
1685 accept_sock = THREAD_FD (thread);
1686
1687 /* We continue hearing vty socket. */
1688 vty_event (VTY_SERV, accept_sock, NULL);
1689
1690 memset (&su, 0, sizeof (union sockunion));
1691
1692 /* We can handle IPv4 or IPv6 socket. */
1693 vty_sock = sockunion_accept (accept_sock, &su);
1694 if (vty_sock < 0)
1695 {
ajs6099b3b2004-11-20 02:06:59 +00001696 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001697 return -1;
1698 }
ajs9fc7ebf2005-02-23 15:12:34 +00001699 set_nonblocking(vty_sock);
paul718e3742002-12-13 20:15:29 +00001700
1701 p = sockunion2hostprefix (&su);
1702
1703 /* VTY's accesslist apply. */
1704 if (p->family == AF_INET && vty_accesslist_name)
1705 {
1706 if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1707 (access_list_apply (acl, p) == FILTER_DENY))
1708 {
1709 char *buf;
1710 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1711 (buf = sockunion_su2str (&su)));
1712 free (buf);
1713 close (vty_sock);
1714
1715 /* continue accepting connections */
1716 vty_event (VTY_SERV, accept_sock, NULL);
1717
1718 prefix_free (p);
1719
1720 return 0;
1721 }
1722 }
1723
1724#ifdef HAVE_IPV6
1725 /* VTY's ipv6 accesslist apply. */
1726 if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1727 {
1728 if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1729 (access_list_apply (acl, p) == FILTER_DENY))
1730 {
1731 char *buf;
1732 zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1733 (buf = sockunion_su2str (&su)));
1734 free (buf);
1735 close (vty_sock);
1736
1737 /* continue accepting connections */
1738 vty_event (VTY_SERV, accept_sock, NULL);
1739
1740 prefix_free (p);
1741
1742 return 0;
1743 }
1744 }
1745#endif /* HAVE_IPV6 */
1746
1747 prefix_free (p);
1748
1749 on = 1;
1750 ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
1751 (char *) &on, sizeof (on));
1752 if (ret < 0)
1753 zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
ajs6099b3b2004-11-20 02:06:59 +00001754 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001755
1756 vty = vty_create (vty_sock, &su);
1757
1758 return 0;
1759}
1760
1761#if defined(HAVE_IPV6) && !defined(NRL)
ajs9fc7ebf2005-02-23 15:12:34 +00001762static void
paul718e3742002-12-13 20:15:29 +00001763vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1764{
1765 int ret;
1766 struct addrinfo req;
1767 struct addrinfo *ainfo;
1768 struct addrinfo *ainfo_save;
1769 int sock;
1770 char port_str[BUFSIZ];
1771
1772 memset (&req, 0, sizeof (struct addrinfo));
1773 req.ai_flags = AI_PASSIVE;
1774 req.ai_family = AF_UNSPEC;
1775 req.ai_socktype = SOCK_STREAM;
1776 sprintf (port_str, "%d", port);
1777 port_str[sizeof (port_str) - 1] = '\0';
1778
1779 ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1780
1781 if (ret != 0)
1782 {
1783 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1784 exit (1);
1785 }
1786
1787 ainfo_save = ainfo;
1788
1789 do
1790 {
1791 if (ainfo->ai_family != AF_INET
1792#ifdef HAVE_IPV6
1793 && ainfo->ai_family != AF_INET6
1794#endif /* HAVE_IPV6 */
1795 )
1796 continue;
1797
1798 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1799 if (sock < 0)
1800 continue;
1801
1802 sockopt_reuseaddr (sock);
1803 sockopt_reuseport (sock);
1804
1805 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1806 if (ret < 0)
1807 {
1808 close (sock); /* Avoid sd leak. */
1809 continue;
1810 }
1811
1812 ret = listen (sock, 3);
1813 if (ret < 0)
1814 {
1815 close (sock); /* Avoid sd leak. */
1816 continue;
1817 }
1818
1819 vty_event (VTY_SERV, sock, NULL);
1820 }
1821 while ((ainfo = ainfo->ai_next) != NULL);
1822
1823 freeaddrinfo (ainfo_save);
1824}
1825#endif /* HAVE_IPV6 && ! NRL */
1826
1827/* Make vty server socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001828static void
paul29db05b2003-05-08 20:10:22 +00001829vty_serv_sock_family (const char* addr, unsigned short port, int family)
paul718e3742002-12-13 20:15:29 +00001830{
1831 int ret;
1832 union sockunion su;
1833 int accept_sock;
paul29db05b2003-05-08 20:10:22 +00001834 void* naddr=NULL;
paul718e3742002-12-13 20:15:29 +00001835
1836 memset (&su, 0, sizeof (union sockunion));
1837 su.sa.sa_family = family;
paul29db05b2003-05-08 20:10:22 +00001838 if(addr)
1839 switch(family)
1840 {
1841 case AF_INET:
1842 naddr=&su.sin.sin_addr;
1843#ifdef HAVE_IPV6
1844 case AF_INET6:
1845 naddr=&su.sin6.sin6_addr;
1846#endif
1847 }
1848
1849 if(naddr)
1850 switch(inet_pton(family,addr,naddr))
1851 {
1852 case -1:
1853 zlog_err("bad address %s",addr);
1854 naddr=NULL;
1855 break;
1856 case 0:
ajs6099b3b2004-11-20 02:06:59 +00001857 zlog_err("error translating address %s: %s",addr,safe_strerror(errno));
paul29db05b2003-05-08 20:10:22 +00001858 naddr=NULL;
1859 }
paul718e3742002-12-13 20:15:29 +00001860
1861 /* Make new socket. */
1862 accept_sock = sockunion_stream_socket (&su);
1863 if (accept_sock < 0)
1864 return;
1865
1866 /* This is server, so reuse address. */
1867 sockopt_reuseaddr (accept_sock);
1868 sockopt_reuseport (accept_sock);
1869
1870 /* Bind socket to universal address and given port. */
paul29db05b2003-05-08 20:10:22 +00001871 ret = sockunion_bind (accept_sock, &su, port, naddr);
paul718e3742002-12-13 20:15:29 +00001872 if (ret < 0)
1873 {
paul29db05b2003-05-08 20:10:22 +00001874 zlog_warn("can't bind socket");
paul718e3742002-12-13 20:15:29 +00001875 close (accept_sock); /* Avoid sd leak. */
1876 return;
1877 }
1878
1879 /* Listen socket under queue 3. */
1880 ret = listen (accept_sock, 3);
1881 if (ret < 0)
1882 {
1883 zlog (NULL, LOG_WARNING, "can't listen socket");
1884 close (accept_sock); /* Avoid sd leak. */
1885 return;
1886 }
1887
1888 /* Add vty server event. */
1889 vty_event (VTY_SERV, accept_sock, NULL);
1890}
1891
1892#ifdef VTYSH
1893/* For sockaddr_un. */
1894#include <sys/un.h>
1895
1896/* VTY shell UNIX domain socket. */
ajs9fc7ebf2005-02-23 15:12:34 +00001897static void
hasso6ad96ea2004-10-07 19:33:46 +00001898vty_serv_un (const char *path)
paul718e3742002-12-13 20:15:29 +00001899{
1900 int ret;
paul75e15fe2004-10-31 02:13:09 +00001901 int sock, len;
paul718e3742002-12-13 20:15:29 +00001902 struct sockaddr_un serv;
1903 mode_t old_mask;
pauledd7c242003-06-04 13:59:38 +00001904 struct zprivs_ids_t ids;
1905
paul718e3742002-12-13 20:15:29 +00001906 /* First of all, unlink existing socket */
1907 unlink (path);
1908
1909 /* Set umask */
paul1921e6f2003-05-23 08:12:36 +00001910 old_mask = umask (0007);
paul718e3742002-12-13 20:15:29 +00001911
1912 /* Make UNIX domain socket. */
1913 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1914 if (sock < 0)
1915 {
ajs6a52d0d2005-01-30 18:49:28 +00001916 zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001917 return;
1918 }
1919
1920 /* Make server socket. */
1921 memset (&serv, 0, sizeof (struct sockaddr_un));
1922 serv.sun_family = AF_UNIX;
1923 strncpy (serv.sun_path, path, strlen (path));
1924#ifdef HAVE_SUN_LEN
1925 len = serv.sun_len = SUN_LEN(&serv);
1926#else
1927 len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1928#endif /* HAVE_SUN_LEN */
1929
1930 ret = bind (sock, (struct sockaddr *) &serv, len);
1931 if (ret < 0)
1932 {
ajs6a52d0d2005-01-30 18:49:28 +00001933 zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001934 close (sock); /* Avoid sd leak. */
1935 return;
1936 }
1937
1938 ret = listen (sock, 5);
1939 if (ret < 0)
1940 {
ajs6a52d0d2005-01-30 18:49:28 +00001941 zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +00001942 close (sock); /* Avoid sd leak. */
1943 return;
1944 }
1945
1946 umask (old_mask);
1947
pauledd7c242003-06-04 13:59:38 +00001948 zprivs_get_ids(&ids);
1949
1950 if (ids.gid_vty > 0)
1951 {
1952 /* set group of socket */
1953 if ( chown (path, -1, ids.gid_vty) )
1954 {
1955 zlog_err ("vty_serv_un: could chown socket, %s",
ajs6099b3b2004-11-20 02:06:59 +00001956 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +00001957 }
1958 }
1959
paul718e3742002-12-13 20:15:29 +00001960 vty_event (VTYSH_SERV, sock, NULL);
1961}
1962
1963/* #define VTYSH_DEBUG 1 */
1964
1965static int
1966vtysh_accept (struct thread *thread)
1967{
1968 int accept_sock;
1969 int sock;
1970 int client_len;
1971 struct sockaddr_un client;
1972 struct vty *vty;
1973
1974 accept_sock = THREAD_FD (thread);
1975
1976 vty_event (VTYSH_SERV, accept_sock, NULL);
1977
1978 memset (&client, 0, sizeof (struct sockaddr_un));
1979 client_len = sizeof (struct sockaddr_un);
1980
hassoe473b032004-09-26 16:08:11 +00001981 sock = accept (accept_sock, (struct sockaddr *) &client,
1982 (socklen_t *) &client_len);
paul718e3742002-12-13 20:15:29 +00001983
1984 if (sock < 0)
1985 {
ajs6099b3b2004-11-20 02:06:59 +00001986 zlog_warn ("can't accept vty socket : %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001987 return -1;
1988 }
1989
ajs9fc7ebf2005-02-23 15:12:34 +00001990 if (set_nonblocking(sock) < 0)
paul75e15fe2004-10-31 02:13:09 +00001991 {
ajs9fc7ebf2005-02-23 15:12:34 +00001992 zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking,"
1993 " %s, closing", sock, safe_strerror (errno));
paul75e15fe2004-10-31 02:13:09 +00001994 close (sock);
1995 return -1;
1996 }
pauldccfb192004-10-29 08:29:36 +00001997
paul718e3742002-12-13 20:15:29 +00001998#ifdef VTYSH_DEBUG
1999 printf ("VTY shell accept\n");
2000#endif /* VTYSH_DEBUG */
2001
2002 vty = vty_new ();
2003 vty->fd = sock;
2004 vty->type = VTY_SHELL_SERV;
2005 vty->node = VIEW_NODE;
2006
2007 vty_event (VTYSH_READ, sock, vty);
2008
2009 return 0;
2010}
2011
2012static int
ajs9fc7ebf2005-02-23 15:12:34 +00002013vtysh_flush(struct vty *vty)
2014{
2015 switch (buffer_flush_available(vty->obuf, vty->fd))
2016 {
2017 case BUFFER_PENDING:
2018 vty_event(VTYSH_WRITE, vty->fd, vty);
2019 break;
2020 case BUFFER_ERROR:
2021 zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
2022 buffer_reset(vty->obuf);
2023 vty_close(vty);
2024 return -1;
2025 break;
2026 case BUFFER_EMPTY:
2027 break;
2028 }
2029 return 0;
2030}
2031
2032static int
paul718e3742002-12-13 20:15:29 +00002033vtysh_read (struct thread *thread)
2034{
2035 int ret;
2036 int sock;
2037 int nbytes;
2038 struct vty *vty;
2039 unsigned char buf[VTY_READ_BUFSIZ];
ajs9fc7ebf2005-02-23 15:12:34 +00002040 unsigned char *p;
paul718e3742002-12-13 20:15:29 +00002041 u_char header[4] = {0, 0, 0, 0};
2042
2043 sock = THREAD_FD (thread);
2044 vty = THREAD_ARG (thread);
2045 vty->t_read = NULL;
2046
ajs9fc7ebf2005-02-23 15:12:34 +00002047 if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0)
paul718e3742002-12-13 20:15:29 +00002048 {
ajs9fc7ebf2005-02-23 15:12:34 +00002049 if (nbytes < 0)
2050 {
2051 if (ERRNO_IO_RETRY(errno))
2052 {
2053 vty_event (VTYSH_READ, sock, vty);
2054 return 0;
2055 }
2056 zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
2057 __func__, sock, safe_strerror(errno));
2058 }
2059 buffer_reset(vty->obuf);
paul718e3742002-12-13 20:15:29 +00002060 vty_close (vty);
2061#ifdef VTYSH_DEBUG
2062 printf ("close vtysh\n");
2063#endif /* VTYSH_DEBUG */
2064 return 0;
2065 }
2066
2067#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002068 printf ("line: %.*s\n", nbytes, buf);
paul718e3742002-12-13 20:15:29 +00002069#endif /* VTYSH_DEBUG */
2070
ajs9fc7ebf2005-02-23 15:12:34 +00002071 for (p = buf; p < buf+nbytes; p++)
2072 {
2073 vty_ensure(vty, vty->length+1);
2074 vty->buf[vty->length++] = *p;
2075 if (*p == '\0')
2076 {
2077 /* Pass this line to parser. */
2078 ret = vty_execute (vty);
2079 /* Note that vty_execute clears the command buffer and resets
2080 vty->length to 0. */
paul718e3742002-12-13 20:15:29 +00002081
ajs9fc7ebf2005-02-23 15:12:34 +00002082 /* Return result. */
paul718e3742002-12-13 20:15:29 +00002083#ifdef VTYSH_DEBUG
ajs9fc7ebf2005-02-23 15:12:34 +00002084 printf ("result: %d\n", ret);
2085 printf ("vtysh node: %d\n", vty->node);
paul718e3742002-12-13 20:15:29 +00002086#endif /* VTYSH_DEBUG */
2087
ajs9fc7ebf2005-02-23 15:12:34 +00002088 header[3] = ret;
2089 buffer_put(vty->obuf, header, 4);
paul718e3742002-12-13 20:15:29 +00002090
ajs9fc7ebf2005-02-23 15:12:34 +00002091 if (!vty->t_write && (vtysh_flush(vty) < 0))
2092 /* Try to flush results; exit if a write error occurs. */
2093 return 0;
2094 }
2095 }
2096
paul718e3742002-12-13 20:15:29 +00002097 vty_event (VTYSH_READ, sock, vty);
2098
2099 return 0;
2100}
ajs49ff6d92004-11-04 19:26:16 +00002101
2102static int
2103vtysh_write (struct thread *thread)
2104{
2105 struct vty *vty = THREAD_ARG (thread);
2106
2107 vty->t_write = NULL;
ajs9fc7ebf2005-02-23 15:12:34 +00002108 vtysh_flush(vty);
ajs976d8c72004-11-10 15:40:09 +00002109 return 0;
ajs49ff6d92004-11-04 19:26:16 +00002110}
2111
paul718e3742002-12-13 20:15:29 +00002112#endif /* VTYSH */
2113
2114/* Determine address family to bind. */
2115void
hasso6ad96ea2004-10-07 19:33:46 +00002116vty_serv_sock (const char *addr, unsigned short port, const char *path)
paul718e3742002-12-13 20:15:29 +00002117{
2118 /* If port is set to 0, do not listen on TCP/IP at all! */
2119 if (port)
2120 {
2121
2122#ifdef HAVE_IPV6
2123#ifdef NRL
paul29db05b2003-05-08 20:10:22 +00002124 vty_serv_sock_family (addr, port, AF_INET);
2125 vty_serv_sock_family (addr, port, AF_INET6);
paul718e3742002-12-13 20:15:29 +00002126#else /* ! NRL */
paul29db05b2003-05-08 20:10:22 +00002127 vty_serv_sock_addrinfo (addr, port);
paul718e3742002-12-13 20:15:29 +00002128#endif /* NRL*/
2129#else /* ! HAVE_IPV6 */
paul29db05b2003-05-08 20:10:22 +00002130 vty_serv_sock_family (addr,port, AF_INET);
paul718e3742002-12-13 20:15:29 +00002131#endif /* HAVE_IPV6 */
2132 }
2133
2134#ifdef VTYSH
2135 vty_serv_un (path);
2136#endif /* VTYSH */
2137}
2138
2139/* Close vty interface. */
2140void
2141vty_close (struct vty *vty)
2142{
2143 int i;
2144
2145 /* Cancel threads.*/
2146 if (vty->t_read)
2147 thread_cancel (vty->t_read);
2148 if (vty->t_write)
2149 thread_cancel (vty->t_write);
2150 if (vty->t_timeout)
2151 thread_cancel (vty->t_timeout);
paul718e3742002-12-13 20:15:29 +00002152
2153 /* Flush buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +00002154 buffer_flush_all (vty->obuf, vty->fd);
paul718e3742002-12-13 20:15:29 +00002155
2156 /* Free input buffer. */
2157 buffer_free (vty->obuf);
2158
paul718e3742002-12-13 20:15:29 +00002159 /* Free command history. */
2160 for (i = 0; i < VTY_MAXHIST; i++)
2161 if (vty->hist[i])
2162 XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2163
2164 /* Unset vector. */
2165 vector_unset (vtyvec, vty->fd);
2166
2167 /* Close socket. */
2168 if (vty->fd > 0)
2169 close (vty->fd);
2170
2171 if (vty->address)
paul05865c92005-10-26 05:49:54 +00002172 XFREE (MTYPE_TMP, vty->address);
paul718e3742002-12-13 20:15:29 +00002173 if (vty->buf)
2174 XFREE (MTYPE_VTY, vty->buf);
2175
2176 /* Check configure. */
2177 vty_config_unlock (vty);
2178
2179 /* OK free vty. */
2180 XFREE (MTYPE_VTY, vty);
2181}
2182
2183/* When time out occur output message then close connection. */
2184static int
2185vty_timeout (struct thread *thread)
2186{
2187 struct vty *vty;
2188
2189 vty = THREAD_ARG (thread);
2190 vty->t_timeout = NULL;
2191 vty->v_timeout = 0;
2192
2193 /* Clear buffer*/
2194 buffer_reset (vty->obuf);
2195 vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2196
2197 /* Close connection. */
2198 vty->status = VTY_CLOSE;
2199 vty_close (vty);
2200
2201 return 0;
2202}
2203
2204/* Read up configuration file from file_name. */
2205static void
2206vty_read_file (FILE *confp)
2207{
2208 int ret;
2209 struct vty *vty;
2210
2211 vty = vty_new ();
2212 vty->fd = 0; /* stdout */
2213 vty->type = VTY_TERM;
2214 vty->node = CONFIG_NODE;
2215
2216 /* Execute configuration file */
2217 ret = config_from_file (vty, confp);
2218
paul7021c422003-07-15 12:52:22 +00002219 if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) )
paul718e3742002-12-13 20:15:29 +00002220 {
2221 switch (ret)
paul7021c422003-07-15 12:52:22 +00002222 {
2223 case CMD_ERR_AMBIGUOUS:
2224 fprintf (stderr, "Ambiguous command.\n");
2225 break;
2226 case CMD_ERR_NO_MATCH:
2227 fprintf (stderr, "There is no such command.\n");
2228 break;
2229 }
paul718e3742002-12-13 20:15:29 +00002230 fprintf (stderr, "Error occured during reading below line.\n%s\n",
2231 vty->buf);
2232 vty_close (vty);
2233 exit (1);
2234 }
2235
2236 vty_close (vty);
2237}
2238
ajs9fc7ebf2005-02-23 15:12:34 +00002239static FILE *
paul718e3742002-12-13 20:15:29 +00002240vty_use_backup_config (char *fullpath)
2241{
2242 char *fullpath_sav, *fullpath_tmp;
2243 FILE *ret = NULL;
2244 struct stat buf;
2245 int tmp, sav;
2246 int c;
2247 char buffer[512];
2248
2249 fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2250 strcpy (fullpath_sav, fullpath);
2251 strcat (fullpath_sav, CONF_BACKUP_EXT);
2252 if (stat (fullpath_sav, &buf) == -1)
2253 {
2254 free (fullpath_sav);
2255 return NULL;
2256 }
2257
2258 fullpath_tmp = malloc (strlen (fullpath) + 8);
2259 sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2260
2261 /* Open file to configuration write. */
2262 tmp = mkstemp (fullpath_tmp);
2263 if (tmp < 0)
2264 {
2265 free (fullpath_sav);
2266 free (fullpath_tmp);
2267 return NULL;
2268 }
2269
2270 sav = open (fullpath_sav, O_RDONLY);
2271 if (sav < 0)
2272 {
gdt3dbf9962003-12-22 20:18:18 +00002273 unlink (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002274 free (fullpath_sav);
2275 free (fullpath_tmp);
paul718e3742002-12-13 20:15:29 +00002276 return NULL;
2277 }
2278
2279 while((c = read (sav, buffer, 512)) > 0)
2280 write (tmp, buffer, c);
2281
2282 close (sav);
2283 close (tmp);
2284
gdtaa593d52003-12-22 20:15:53 +00002285 if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0)
2286 {
gdt3dbf9962003-12-22 20:18:18 +00002287 unlink (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002288 free (fullpath_sav);
2289 free (fullpath_tmp);
gdtaa593d52003-12-22 20:15:53 +00002290 return NULL;
2291 }
2292
paul718e3742002-12-13 20:15:29 +00002293 if (link (fullpath_tmp, fullpath) == 0)
2294 ret = fopen (fullpath, "r");
2295
2296 unlink (fullpath_tmp);
2297
2298 free (fullpath_sav);
2299 free (fullpath_tmp);
hasso12f6ea22005-03-07 08:35:39 +00002300 return ret;
paul718e3742002-12-13 20:15:29 +00002301}
2302
2303/* Read up configuration file from file_name. */
2304void
2305vty_read_config (char *config_file,
hasso320ec102004-06-20 19:54:37 +00002306 char *config_default_dir)
paul718e3742002-12-13 20:15:29 +00002307{
paulccc92352003-10-22 02:49:38 +00002308 char cwd[MAXPATHLEN];
paul718e3742002-12-13 20:15:29 +00002309 FILE *confp = NULL;
2310 char *fullpath;
paul05865c92005-10-26 05:49:54 +00002311 char *tmp = NULL;
paul718e3742002-12-13 20:15:29 +00002312
2313 /* If -f flag specified. */
2314 if (config_file != NULL)
2315 {
2316 if (! IS_DIRECTORY_SEP (config_file[0]))
hasso320ec102004-06-20 19:54:37 +00002317 {
2318 getcwd (cwd, MAXPATHLEN);
paul05865c92005-10-26 05:49:54 +00002319 tmp = XMALLOC (MTYPE_TMP,
hasso320ec102004-06-20 19:54:37 +00002320 strlen (cwd) + strlen (config_file) + 2);
paul05865c92005-10-26 05:49:54 +00002321 sprintf (tmp, "%s/%s", cwd, config_file);
2322 fullpath = tmp;
hasso320ec102004-06-20 19:54:37 +00002323 }
paul718e3742002-12-13 20:15:29 +00002324 else
hasso320ec102004-06-20 19:54:37 +00002325 fullpath = config_file;
paul718e3742002-12-13 20:15:29 +00002326
2327 confp = fopen (fullpath, "r");
2328
2329 if (confp == NULL)
hasso320ec102004-06-20 19:54:37 +00002330 {
paul3d1dc852005-04-05 00:45:23 +00002331 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2332 __func__, fullpath, safe_strerror (errno));
2333
hasso320ec102004-06-20 19:54:37 +00002334 confp = vty_use_backup_config (fullpath);
2335 if (confp)
2336 fprintf (stderr, "WARNING: using backup configuration file!\n");
2337 else
2338 {
2339 fprintf (stderr, "can't open configuration file [%s]\n",
paul3d1dc852005-04-05 00:45:23 +00002340 config_file);
hasso320ec102004-06-20 19:54:37 +00002341 exit(1);
2342 }
2343 }
paul718e3742002-12-13 20:15:29 +00002344 }
2345 else
2346 {
paul718e3742002-12-13 20:15:29 +00002347#ifdef VTYSH
hasso320ec102004-06-20 19:54:37 +00002348 int ret;
2349 struct stat conf_stat;
paul718e3742002-12-13 20:15:29 +00002350
hasso320ec102004-06-20 19:54:37 +00002351 /* !!!!PLEASE LEAVE!!!!
2352 * This is NEEDED for use with vtysh -b, or else you can get
2353 * a real configuration food fight with a lot garbage in the
2354 * merged configuration file it creates coming from the per
2355 * daemon configuration files. This also allows the daemons
2356 * to start if there default configuration file is not
2357 * present or ignore them, as needed when using vtysh -b to
2358 * configure the daemons at boot - MAG
2359 */
paul718e3742002-12-13 20:15:29 +00002360
hasso320ec102004-06-20 19:54:37 +00002361 /* Stat for vtysh Zebra.conf, if found startup and wait for
2362 * boot configuration
2363 */
paul718e3742002-12-13 20:15:29 +00002364
hasso320ec102004-06-20 19:54:37 +00002365 if ( strstr(config_default_dir, "vtysh") == NULL)
2366 {
2367 ret = stat (integrate_default, &conf_stat);
2368 if (ret >= 0)
2369 return;
2370 }
paul718e3742002-12-13 20:15:29 +00002371#endif /* VTYSH */
2372
hasso320ec102004-06-20 19:54:37 +00002373 confp = fopen (config_default_dir, "r");
2374 if (confp == NULL)
2375 {
paul3d1dc852005-04-05 00:45:23 +00002376 fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
2377 __func__, config_default_dir, safe_strerror (errno));
2378
hasso320ec102004-06-20 19:54:37 +00002379 confp = vty_use_backup_config (config_default_dir);
2380 if (confp)
2381 {
2382 fprintf (stderr, "WARNING: using backup configuration file!\n");
2383 fullpath = config_default_dir;
2384 }
2385 else
2386 {
2387 fprintf (stderr, "can't open configuration file [%s]\n",
2388 config_default_dir);
2389 exit (1);
paul3d1dc852005-04-05 00:45:23 +00002390 }
hasso320ec102004-06-20 19:54:37 +00002391 }
paul718e3742002-12-13 20:15:29 +00002392 else
hasso320ec102004-06-20 19:54:37 +00002393 fullpath = config_default_dir;
2394 }
2395
paul718e3742002-12-13 20:15:29 +00002396 vty_read_file (confp);
2397
2398 fclose (confp);
2399
2400 host_config_set (fullpath);
paul05865c92005-10-26 05:49:54 +00002401
2402 if (tmp)
2403 XFREE (MTYPE_TMP, fullpath);
paul718e3742002-12-13 20:15:29 +00002404}
2405
2406/* Small utility function which output log to the VTY. */
2407void
ajs274a4a42004-12-07 15:39:31 +00002408vty_log (const char *level, const char *proto_str,
2409 const char *format, va_list va)
paul718e3742002-12-13 20:15:29 +00002410{
hasso8c328f12004-10-05 21:01:23 +00002411 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002412 struct vty *vty;
Paul Jakmaa4b30302006-05-28 08:18:38 +00002413
2414 if (!vtyvec)
2415 return;
paul718e3742002-12-13 20:15:29 +00002416
paul55468c82005-03-14 20:19:01 +00002417 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002418 if ((vty = vector_slot (vtyvec, i)) != NULL)
2419 if (vty->monitor)
ajsd246bd92004-11-23 17:35:08 +00002420 {
2421 va_list ac;
2422 va_copy(ac, va);
ajs274a4a42004-12-07 15:39:31 +00002423 vty_log_out (vty, level, proto_str, format, ac);
ajsd246bd92004-11-23 17:35:08 +00002424 va_end(ac);
2425 }
paul718e3742002-12-13 20:15:29 +00002426}
2427
ajs274a4a42004-12-07 15:39:31 +00002428/* Async-signal-safe version of vty_log for fixed strings. */
2429void
2430vty_log_fixed (const char *buf, size_t len)
2431{
2432 unsigned int i;
ajs9fc7ebf2005-02-23 15:12:34 +00002433 struct iovec iov[2];
2434
Paul Jakmaa4b30302006-05-28 08:18:38 +00002435 /* vty may not have been initialised */
2436 if (!vtyvec)
2437 return;
2438
ajs926fe8f2005-04-08 18:50:40 +00002439 iov[0].iov_base = (void *)buf;
ajs9fc7ebf2005-02-23 15:12:34 +00002440 iov[0].iov_len = len;
ajs926fe8f2005-04-08 18:50:40 +00002441 iov[1].iov_base = (void *)"\r\n";
ajs9fc7ebf2005-02-23 15:12:34 +00002442 iov[1].iov_len = 2;
ajs274a4a42004-12-07 15:39:31 +00002443
paul55468c82005-03-14 20:19:01 +00002444 for (i = 0; i < vector_active (vtyvec); i++)
ajs274a4a42004-12-07 15:39:31 +00002445 {
2446 struct vty *vty;
ajs9fc7ebf2005-02-23 15:12:34 +00002447 if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
2448 /* N.B. We don't care about the return code, since process is
2449 most likely just about to die anyway. */
2450 writev(vty->fd, iov, 2);
ajs274a4a42004-12-07 15:39:31 +00002451 }
2452}
2453
paul718e3742002-12-13 20:15:29 +00002454int
2455vty_config_lock (struct vty *vty)
2456{
2457 if (vty_config == 0)
2458 {
2459 vty->config = 1;
2460 vty_config = 1;
2461 }
2462 return vty->config;
2463}
2464
2465int
2466vty_config_unlock (struct vty *vty)
2467{
2468 if (vty_config == 1 && vty->config == 1)
2469 {
2470 vty->config = 0;
2471 vty_config = 0;
2472 }
2473 return vty->config;
2474}
2475
2476/* Master of the threads. */
paulb21b19c2003-06-15 01:28:29 +00002477static struct thread_master *master;
paul718e3742002-12-13 20:15:29 +00002478
2479static void
2480vty_event (enum event event, int sock, struct vty *vty)
2481{
2482 struct thread *vty_serv_thread;
2483
2484 switch (event)
2485 {
2486 case VTY_SERV:
2487 vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2488 vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2489 break;
2490#ifdef VTYSH
2491 case VTYSH_SERV:
2492 thread_add_read (master, vtysh_accept, vty, sock);
2493 break;
2494 case VTYSH_READ:
ajs49ff6d92004-11-04 19:26:16 +00002495 vty->t_read = thread_add_read (master, vtysh_read, vty, sock);
2496 break;
2497 case VTYSH_WRITE:
2498 vty->t_write = thread_add_write (master, vtysh_write, vty, sock);
paul718e3742002-12-13 20:15:29 +00002499 break;
2500#endif /* VTYSH */
2501 case VTY_READ:
2502 vty->t_read = thread_add_read (master, vty_read, vty, sock);
2503
2504 /* Time out treatment. */
2505 if (vty->v_timeout)
2506 {
2507 if (vty->t_timeout)
2508 thread_cancel (vty->t_timeout);
2509 vty->t_timeout =
2510 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2511 }
2512 break;
2513 case VTY_WRITE:
2514 if (! vty->t_write)
2515 vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2516 break;
2517 case VTY_TIMEOUT_RESET:
2518 if (vty->t_timeout)
2519 {
2520 thread_cancel (vty->t_timeout);
2521 vty->t_timeout = NULL;
2522 }
2523 if (vty->v_timeout)
2524 {
2525 vty->t_timeout =
2526 thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2527 }
2528 break;
2529 }
2530}
2531
2532DEFUN (config_who,
2533 config_who_cmd,
2534 "who",
2535 "Display who is on vty\n")
2536{
hasso8c328f12004-10-05 21:01:23 +00002537 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002538 struct vty *v;
2539
paul55468c82005-03-14 20:19:01 +00002540 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002541 if ((v = vector_slot (vtyvec, i)) != NULL)
2542 vty_out (vty, "%svty[%d] connected from %s.%s",
2543 v->config ? "*" : " ",
2544 i, v->address, VTY_NEWLINE);
2545 return CMD_SUCCESS;
2546}
2547
2548/* Move to vty configuration mode. */
2549DEFUN (line_vty,
2550 line_vty_cmd,
2551 "line vty",
2552 "Configure a terminal line\n"
2553 "Virtual terminal\n")
2554{
2555 vty->node = VTY_NODE;
2556 return CMD_SUCCESS;
2557}
2558
2559/* Set time out value. */
ajs9fc7ebf2005-02-23 15:12:34 +00002560static int
paul9035efa2004-10-10 11:56:56 +00002561exec_timeout (struct vty *vty, const char *min_str, const char *sec_str)
paul718e3742002-12-13 20:15:29 +00002562{
2563 unsigned long timeout = 0;
2564
2565 /* min_str and sec_str are already checked by parser. So it must be
2566 all digit string. */
2567 if (min_str)
2568 {
2569 timeout = strtol (min_str, NULL, 10);
2570 timeout *= 60;
2571 }
2572 if (sec_str)
2573 timeout += strtol (sec_str, NULL, 10);
2574
2575 vty_timeout_val = timeout;
2576 vty->v_timeout = timeout;
2577 vty_event (VTY_TIMEOUT_RESET, 0, vty);
2578
2579
2580 return CMD_SUCCESS;
2581}
2582
2583DEFUN (exec_timeout_min,
2584 exec_timeout_min_cmd,
2585 "exec-timeout <0-35791>",
2586 "Set timeout value\n"
2587 "Timeout value in minutes\n")
2588{
2589 return exec_timeout (vty, argv[0], NULL);
2590}
2591
2592DEFUN (exec_timeout_sec,
2593 exec_timeout_sec_cmd,
2594 "exec-timeout <0-35791> <0-2147483>",
2595 "Set the EXEC timeout\n"
2596 "Timeout in minutes\n"
2597 "Timeout in seconds\n")
2598{
2599 return exec_timeout (vty, argv[0], argv[1]);
2600}
2601
2602DEFUN (no_exec_timeout,
2603 no_exec_timeout_cmd,
2604 "no exec-timeout",
2605 NO_STR
2606 "Set the EXEC timeout\n")
2607{
2608 return exec_timeout (vty, NULL, NULL);
2609}
2610
2611/* Set vty access class. */
2612DEFUN (vty_access_class,
2613 vty_access_class_cmd,
2614 "access-class WORD",
2615 "Filter connections based on an IP access list\n"
2616 "IP access list\n")
2617{
2618 if (vty_accesslist_name)
2619 XFREE(MTYPE_VTY, vty_accesslist_name);
2620
2621 vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2622
2623 return CMD_SUCCESS;
2624}
2625
2626/* Clear vty access class. */
2627DEFUN (no_vty_access_class,
2628 no_vty_access_class_cmd,
2629 "no access-class [WORD]",
2630 NO_STR
2631 "Filter connections based on an IP access list\n"
2632 "IP access list\n")
2633{
2634 if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2635 {
2636 vty_out (vty, "Access-class is not currently applied to vty%s",
2637 VTY_NEWLINE);
2638 return CMD_WARNING;
2639 }
2640
2641 XFREE(MTYPE_VTY, vty_accesslist_name);
2642
2643 vty_accesslist_name = NULL;
2644
2645 return CMD_SUCCESS;
2646}
2647
2648#ifdef HAVE_IPV6
2649/* Set vty access class. */
2650DEFUN (vty_ipv6_access_class,
2651 vty_ipv6_access_class_cmd,
2652 "ipv6 access-class WORD",
2653 IPV6_STR
2654 "Filter connections based on an IP access list\n"
2655 "IPv6 access list\n")
2656{
2657 if (vty_ipv6_accesslist_name)
2658 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2659
2660 vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2661
2662 return CMD_SUCCESS;
2663}
2664
2665/* Clear vty access class. */
2666DEFUN (no_vty_ipv6_access_class,
2667 no_vty_ipv6_access_class_cmd,
2668 "no ipv6 access-class [WORD]",
2669 NO_STR
2670 IPV6_STR
2671 "Filter connections based on an IP access list\n"
2672 "IPv6 access list\n")
2673{
2674 if (! vty_ipv6_accesslist_name ||
2675 (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2676 {
2677 vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2678 VTY_NEWLINE);
2679 return CMD_WARNING;
2680 }
2681
2682 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2683
2684 vty_ipv6_accesslist_name = NULL;
2685
2686 return CMD_SUCCESS;
2687}
2688#endif /* HAVE_IPV6 */
2689
2690/* vty login. */
2691DEFUN (vty_login,
2692 vty_login_cmd,
2693 "login",
2694 "Enable password checking\n")
2695{
2696 no_password_check = 0;
2697 return CMD_SUCCESS;
2698}
2699
2700DEFUN (no_vty_login,
2701 no_vty_login_cmd,
2702 "no login",
2703 NO_STR
2704 "Enable password checking\n")
2705{
2706 no_password_check = 1;
2707 return CMD_SUCCESS;
2708}
2709
2710DEFUN (service_advanced_vty,
2711 service_advanced_vty_cmd,
2712 "service advanced-vty",
2713 "Set up miscellaneous service\n"
2714 "Enable advanced mode vty interface\n")
2715{
2716 host.advanced = 1;
2717 return CMD_SUCCESS;
2718}
2719
2720DEFUN (no_service_advanced_vty,
2721 no_service_advanced_vty_cmd,
2722 "no service advanced-vty",
2723 NO_STR
2724 "Set up miscellaneous service\n"
2725 "Enable advanced mode vty interface\n")
2726{
2727 host.advanced = 0;
2728 return CMD_SUCCESS;
2729}
2730
2731DEFUN (terminal_monitor,
2732 terminal_monitor_cmd,
2733 "terminal monitor",
2734 "Set terminal line parameters\n"
2735 "Copy debug output to the current terminal line\n")
2736{
2737 vty->monitor = 1;
2738 return CMD_SUCCESS;
2739}
2740
2741DEFUN (terminal_no_monitor,
2742 terminal_no_monitor_cmd,
2743 "terminal no monitor",
2744 "Set terminal line parameters\n"
2745 NO_STR
2746 "Copy debug output to the current terminal line\n")
2747{
2748 vty->monitor = 0;
2749 return CMD_SUCCESS;
2750}
2751
paul789f78a2006-01-17 17:42:03 +00002752ALIAS (terminal_no_monitor,
2753 no_terminal_monitor_cmd,
2754 "no terminal monitor",
2755 NO_STR
2756 "Set terminal line parameters\n"
2757 "Copy debug output to the current terminal line\n")
2758
paul718e3742002-12-13 20:15:29 +00002759DEFUN (show_history,
2760 show_history_cmd,
2761 "show history",
2762 SHOW_STR
2763 "Display the session command history\n")
2764{
2765 int index;
2766
2767 for (index = vty->hindex + 1; index != vty->hindex;)
2768 {
2769 if (index == VTY_MAXHIST)
2770 {
2771 index = 0;
2772 continue;
2773 }
2774
2775 if (vty->hist[index] != NULL)
2776 vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
2777
2778 index++;
2779 }
2780
2781 return CMD_SUCCESS;
2782}
2783
2784/* Display current configuration. */
ajs9fc7ebf2005-02-23 15:12:34 +00002785static int
paul718e3742002-12-13 20:15:29 +00002786vty_config_write (struct vty *vty)
2787{
2788 vty_out (vty, "line vty%s", VTY_NEWLINE);
2789
2790 if (vty_accesslist_name)
2791 vty_out (vty, " access-class %s%s",
2792 vty_accesslist_name, VTY_NEWLINE);
2793
2794 if (vty_ipv6_accesslist_name)
2795 vty_out (vty, " ipv6 access-class %s%s",
2796 vty_ipv6_accesslist_name, VTY_NEWLINE);
2797
2798 /* exec-timeout */
2799 if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2800 vty_out (vty, " exec-timeout %ld %ld%s",
2801 vty_timeout_val / 60,
2802 vty_timeout_val % 60, VTY_NEWLINE);
2803
2804 /* login */
2805 if (no_password_check)
2806 vty_out (vty, " no login%s", VTY_NEWLINE);
2807
2808 vty_out (vty, "!%s", VTY_NEWLINE);
2809
2810 return CMD_SUCCESS;
2811}
2812
2813struct cmd_node vty_node =
2814{
2815 VTY_NODE,
2816 "%s(config-line)# ",
hassoe7168df2004-10-03 20:11:32 +00002817 1,
paul718e3742002-12-13 20:15:29 +00002818};
2819
2820/* Reset all VTY status. */
2821void
2822vty_reset ()
2823{
hasso8c328f12004-10-05 21:01:23 +00002824 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002825 struct vty *vty;
2826 struct thread *vty_serv_thread;
2827
paul55468c82005-03-14 20:19:01 +00002828 for (i = 0; i < vector_active (vtyvec); i++)
paul718e3742002-12-13 20:15:29 +00002829 if ((vty = vector_slot (vtyvec, i)) != NULL)
2830 {
2831 buffer_reset (vty->obuf);
2832 vty->status = VTY_CLOSE;
2833 vty_close (vty);
2834 }
2835
paul55468c82005-03-14 20:19:01 +00002836 for (i = 0; i < vector_active (Vvty_serv_thread); i++)
paul718e3742002-12-13 20:15:29 +00002837 if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2838 {
2839 thread_cancel (vty_serv_thread);
2840 vector_slot (Vvty_serv_thread, i) = NULL;
2841 close (i);
2842 }
2843
2844 vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2845
2846 if (vty_accesslist_name)
2847 {
2848 XFREE(MTYPE_VTY, vty_accesslist_name);
2849 vty_accesslist_name = NULL;
2850 }
2851
2852 if (vty_ipv6_accesslist_name)
2853 {
2854 XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2855 vty_ipv6_accesslist_name = NULL;
2856 }
2857}
2858
ajs9fc7ebf2005-02-23 15:12:34 +00002859static void
2860vty_save_cwd (void)
paul718e3742002-12-13 20:15:29 +00002861{
paul79ad2792003-10-15 22:09:28 +00002862 char cwd[MAXPATHLEN];
paulccc92352003-10-22 02:49:38 +00002863 char *c;
paul718e3742002-12-13 20:15:29 +00002864
paulccc92352003-10-22 02:49:38 +00002865 c = getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002866
paulccc92352003-10-22 02:49:38 +00002867 if (!c)
paul79ad2792003-10-15 22:09:28 +00002868 {
2869 chdir (SYSCONFDIR);
paulccc92352003-10-22 02:49:38 +00002870 getcwd (cwd, MAXPATHLEN);
paul79ad2792003-10-15 22:09:28 +00002871 }
paul718e3742002-12-13 20:15:29 +00002872
2873 vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2874 strcpy (vty_cwd, cwd);
2875}
2876
2877char *
2878vty_get_cwd ()
2879{
2880 return vty_cwd;
2881}
2882
2883int
2884vty_shell (struct vty *vty)
2885{
2886 return vty->type == VTY_SHELL ? 1 : 0;
2887}
2888
2889int
2890vty_shell_serv (struct vty *vty)
2891{
2892 return vty->type == VTY_SHELL_SERV ? 1 : 0;
2893}
2894
2895void
2896vty_init_vtysh ()
2897{
2898 vtyvec = vector_init (VECTOR_MIN_SIZE);
2899}
2900
2901/* Install vty's own commands like `who' command. */
2902void
paulb21b19c2003-06-15 01:28:29 +00002903vty_init (struct thread_master *master_thread)
paul718e3742002-12-13 20:15:29 +00002904{
2905 /* For further configuration read, preserve current directory. */
2906 vty_save_cwd ();
2907
2908 vtyvec = vector_init (VECTOR_MIN_SIZE);
2909
paulb21b19c2003-06-15 01:28:29 +00002910 master = master_thread;
2911
paul718e3742002-12-13 20:15:29 +00002912 /* Initilize server thread vector. */
2913 Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2914
2915 /* Install bgp top node. */
2916 install_node (&vty_node, vty_config_write);
2917
2918 install_element (VIEW_NODE, &config_who_cmd);
2919 install_element (VIEW_NODE, &show_history_cmd);
2920 install_element (ENABLE_NODE, &config_who_cmd);
2921 install_element (CONFIG_NODE, &line_vty_cmd);
2922 install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2923 install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2924 install_element (CONFIG_NODE, &show_history_cmd);
2925 install_element (ENABLE_NODE, &terminal_monitor_cmd);
2926 install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
paul789f78a2006-01-17 17:42:03 +00002927 install_element (ENABLE_NODE, &no_terminal_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00002928 install_element (ENABLE_NODE, &show_history_cmd);
2929
2930 install_default (VTY_NODE);
2931 install_element (VTY_NODE, &exec_timeout_min_cmd);
2932 install_element (VTY_NODE, &exec_timeout_sec_cmd);
2933 install_element (VTY_NODE, &no_exec_timeout_cmd);
2934 install_element (VTY_NODE, &vty_access_class_cmd);
2935 install_element (VTY_NODE, &no_vty_access_class_cmd);
2936 install_element (VTY_NODE, &vty_login_cmd);
2937 install_element (VTY_NODE, &no_vty_login_cmd);
2938#ifdef HAVE_IPV6
2939 install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2940 install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2941#endif /* HAVE_IPV6 */
2942}