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