Project

General

Profile

Download (30.2 KB) Statistics
| Branch: | Tag: | Revision:
1

    
2
#include <stdio.h>
3
#include <stdarg.h>
4
#include <stdlib.h>
5
#include <unistd.h>
6
#include <string.h>
7
#include <errno.h>
8
#include <ctype.h>
9
#include <termios.h>
10

    
11
#include <sys/utsname.h>
12
#include <sys/param.h>
13

    
14
#include "zebvty.h"
15
#include "vty.h"
16
#include "command.h"
17
#include "buffer.h"
18

    
19
/* Vty events */
20
enum event {
21
	VTY_SERV,
22
	VTY_READ,
23
	VTY_WRITE,
24
	VTY_TIMEOUT_RESET,
25
#ifdef VTYSH
26
	VTYSH_SERV,
27
	VTYSH_READ,
28
	VTYSH_WRITE
29
#endif				/* VTYSH */
30
};
31

    
32
extern struct host host;
33

    
34
/* Vector which store each vty structure. */
35
static vector vtyvec;
36

    
37
vector Vvty_serv_thread;
38

    
39
char *vty_cwd = NULL;
40

    
41
/* Configure lock. */
42
static int vty_config;
43

    
44
static int no_password_check = 1;
45

    
46
static void vty_clear_buf(struct vty *vty)
47
{
48
	memset(vty->buf, 0, vty->max);
49
}
50

    
51
/* Allocate new vty struct. */
52
struct vty *vty_new()
53
{
54
	struct vty *new = malloc(sizeof(struct vty));
55

    
56
	if (!new)
57
		goto out;
58

    
59
	new->obuf = buffer_new(0);	/* Use default buffer size. */
60
	if (!new->obuf)
61
		goto out_new;
62
	new->buf = calloc(1, VTY_BUFSIZ);
63
	if (!new->buf)
64
		goto out_obuf;
65

    
66
	new->max = VTY_BUFSIZ;
67

    
68
	return new;
69

    
70
out_obuf:
71
	free(new->obuf);
72
out_new:
73
	free(new);
74
	new = NULL;
75
out:
76
	return new;
77
}
78

    
79
/* Authentication of vty */
80
static void vty_auth(struct vty *vty, char *buf)
81
{
82
	char *passwd = NULL;
83
	enum node_type next_node = 0;
84
	int fail;
85
	char *crypt(const char *, const char *);
86

    
87
	switch (vty->node) {
88
	case AUTH_NODE:
89
		if (host.encrypt)
90
			passwd = host.password_encrypt;
91
		else
92
			passwd = host.password;
93
		if (host.advanced)
94
			next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
95
		else
96
			next_node = VIEW_NODE;
97
		break;
98
	case AUTH_ENABLE_NODE:
99
		if (host.encrypt)
100
			passwd = host.enable_encrypt;
101
		else
102
			passwd = host.enable;
103
		next_node = ENABLE_NODE;
104
		break;
105
	}
106

    
107
	if (passwd) {
108
		if (host.encrypt)
109
			fail = strcmp(crypt(buf, passwd), passwd);
110
		else
111
			fail = strcmp(buf, passwd);
112
	} else
113
		fail = 1;
114

    
115
	if (!fail) {
116
		vty->fail = 0;
117
		vty->node = next_node;	/* Success ! */
118
	} else {
119
		vty->fail++;
120
		if (vty->fail >= 3) {
121
			if (vty->node == AUTH_NODE) {
122
				vty_out(vty,
123
					"%% Bad passwords, too many failures!%s",
124
					VTY_NEWLINE);
125
				vty->status = VTY_CLOSE;
126
			} else {
127
				/* AUTH_ENABLE_NODE */
128
				vty->fail = 0;
129
				vty_out(vty,
130
					"%% Bad enable passwords, too many failures!%s",
131
					VTY_NEWLINE);
132
				vty->node = VIEW_NODE;
133
			}
134
		}
135
	}
136
}
137

    
138
/* Close vty interface. */
139
void vty_close(struct vty *vty)
140
{
141
	int i;
142

    
143
	/* Flush buffer. */
144
	buffer_flush_all(vty->obuf, vty->fd);
145

    
146
	/* Free input buffer. */
147
	buffer_free(vty->obuf);
148

    
149
	/* Free command history. */
150
	for (i = 0; i < VTY_MAXHIST; i++)
151
		if (vty->hist[i])
152
			free(vty->hist[i]);
153

    
154
	/* Unset vector. */
155
	vector_unset(vtyvec, vty->fd);
156

    
157
	/* Close socket. */
158
	if (vty->fd > 0)
159
		close(vty->fd);
160

    
161
	if (vty->buf)
162
		free(vty->buf);
163

    
164
	/* Check configure. */
165
	vty_config_unlock(vty);
166

    
167
	/* OK free vty. */
168
	free(vty);
169
}
170

    
171
int vty_shell(struct vty *vty)
172
{
173
	return vty->type == VTY_SHELL ? 1 : 0;
174
}
175

    
176

    
177
/* VTY standard output function. */
178
int vty_out(struct vty *vty, const char *format, ...)
179
{
180
	va_list args;
181
	int len = 0;
182
	int size = 1024;
183
	char buf[1024];
184
	char *p = NULL;
185

    
186
	if (vty_shell(vty)) {
187
		va_start(args, format);
188
		vprintf(format, args);
189
		va_end(args);
190
	} else {
191
		/* Try to write to initial buffer.  */
192
		va_start(args, format);
193
		len = vsnprintf(buf, sizeof buf, format, args);
194
		va_end(args);
195

    
196
		/* Initial buffer is not enough.  */
197
		if (len < 0 || len >= size) {
198
			while (1) {
199
				if (len > -1)
200
					size = len + 1;
201
				else
202
					size = size * 2;
203

    
204
				p = realloc(p, size);
205
				if (!p)
206
					return -1;
207

    
208
				va_start(args, format);
209
				len = vsnprintf(p, size, format, args);
210
				va_end(args);
211

    
212
				if (len > -1 && len < size)
213
					break;
214
			}
215
		}
216

    
217
		/* When initial buffer is enough to store all output.  */
218
		if (!p)
219
			p = buf;
220

    
221
		/* Pointer p must point out buffer. */
222
		buffer_put(vty->obuf, (u_char *) p, len);
223

    
224
		/* If p is not different with buf, it is allocated buffer.  */
225
		if (p != buf)
226
			free(p);
227
	}
228

    
229
	return len;
230
}
231

    
232
int vty_out_newline(struct vty *vty)
233
{
234
	char *p = vty_newline(vty);
235
	buffer_put(vty->obuf, p, strlen(p));
236
}
237

    
238
int vty_config_lock(struct vty *vty)
239
{
240
	if (vty_config == 0) {
241
		vty->config = 1;
242
		vty_config = 1;
243
	}
244
	return vty->config;
245
}
246

    
247
int vty_config_unlock(struct vty *vty)
248
{
249
	if (vty_config == 1 && vty->config == 1) {
250
		vty->config = 0;
251
		vty_config = 0;
252
	}
253
	return vty->config;
254
}
255

    
256
static void vty_event(enum event event, int sock, struct vty *vty)
257
{
258
	//fprintf(stdout, "vty_event(%d, %d, %p)\n", event, sock, vty);
259
	buffer_flush_all(vty->obuf, sock);
260
}
261

    
262
/* Say hello to vty interface. */
263
void vty_hello(struct vty *vty)
264
{
265
	if (host.motdfile) {
266
		FILE *f;
267
		char buf[4096];
268

    
269
		f = fopen(host.motdfile, "r");
270
		if (f) {
271
			while (fgets(buf, sizeof(buf), f)) {
272
				char *s;
273
				/* work backwards to ignore trailling isspace() */
274
				for (s = buf + strlen(buf);
275
				     (s > buf) && isspace(*(s - 1)); s--) ;
276
				*s = '\0';
277
				vty_out(vty, "%s%s", buf, VTY_NEWLINE);
278
			}
279
			fclose(f);
280
		} else
281
			vty_out(vty, "MOTD file not found%s", VTY_NEWLINE);
282
	} else if (host.motd)
283
		vty_out(vty, host.motd);
284
}
285

    
286
/* Put out prompt and wait input from user. */
287
static void vty_prompt(struct vty *vty)
288
{
289
	struct utsname names;
290
	const char *hostname;
291

    
292
	if (vty->type == VTY_TERM) {
293
		hostname = host.name;
294
		if (!hostname) {
295
			uname(&names);
296
			hostname = names.nodename;
297
		}
298
		vty_out(vty, cmd_prompt(vty->node), hostname);
299
	}
300
}
301

    
302
/* Command execution over the vty interface. */
303
static int vty_command(struct vty *vty, char *buf)
304
{
305
	int ret;
306
	vector vline;
307

    
308
	/* Split readline string up into the vector */
309
	vline = cmd_make_strvec(buf);
310

    
311
	if (vline == NULL)
312
		return CMD_SUCCESS;
313

    
314
	ret = cmd_execute_command(vline, vty, NULL, 0);
315
	if (ret != CMD_SUCCESS)
316
		switch (ret) {
317
		case CMD_WARNING:
318
			if (vty->type == VTY_FILE)
319
				vty_out(vty, "Warning...%s", VTY_NEWLINE);
320
			break;
321
		case CMD_ERR_AMBIGUOUS:
322
			vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
323
			break;
324
		case CMD_ERR_NO_MATCH:
325
			vty_out(vty, "%% Unknown command.%s", VTY_NEWLINE);
326
			break;
327
		case CMD_ERR_INCOMPLETE:
328
			vty_out(vty, "%% Command incomplete.%s", VTY_NEWLINE);
329
			break;
330
		}
331
	cmd_free_strvec(vline);
332

    
333
	return ret;
334
}
335

    
336
static const char telnet_backward_char = 0x08;
337
static const char telnet_space_char = ' ';
338

    
339
/* Basic function to write buffer to vty. */
340
static void vty_write(struct vty *vty, const char *buf, size_t nbytes)
341
{
342
	if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
343
		return;
344

    
345
	/* Should we do buffering here ?  And make vty_flush (vty) ? */
346
	buffer_put(vty->obuf, buf, nbytes);
347
}
348

    
349
/* Ensure length of input buffer.  Is buffer is short, double it. */
350
static void vty_ensure(struct vty *vty, int length)
351
{
352
	if (vty->max <= length) {
353
		vty->max *= 2;
354
		vty->buf = realloc(vty->buf, vty->max);
355
		// FIXME: check return
356
	}
357
}
358

    
359
/* Basic function to insert character into vty. */
360
static void vty_self_insert(struct vty *vty, char c)
361
{
362
	int i;
363
	int length;
364

    
365
	vty_ensure(vty, vty->length + 1);
366
	length = vty->length - vty->cp;
367
	memmove(&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
368
	vty->buf[vty->cp] = c;
369

    
370
	vty_write(vty, &vty->buf[vty->cp], length + 1);
371
	for (i = 0; i < length; i++)
372
		vty_write(vty, &telnet_backward_char, 1);
373

    
374
	vty->cp++;
375
	vty->length++;
376
}
377

    
378
/* Self insert character 'c' in overwrite mode. */
379
static void vty_self_insert_overwrite(struct vty *vty, char c)
380
{
381
	vty_ensure(vty, vty->length + 1);
382
	vty->buf[vty->cp++] = c;
383

    
384
	if (vty->cp > vty->length)
385
		vty->length++;
386

    
387
	if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
388
		return;
389

    
390
	vty_write(vty, &c, 1);
391
}
392

    
393
/* Insert a word into vty interface with overwrite mode. */
394
static void vty_insert_word_overwrite(struct vty *vty, char *str)
395
{
396
	int len = strlen(str);
397
	vty_write(vty, str, len);
398
	strcpy(&vty->buf[vty->cp], str);
399
	vty->cp += len;
400
	vty->length = vty->cp;
401
}
402

    
403
/* Forward character. */
404
static void vty_forward_char(struct vty *vty)
405
{
406
	if (vty->cp < vty->length) {
407
		vty_write(vty, &vty->buf[vty->cp], 1);
408
		vty->cp++;
409
	}
410
}
411

    
412
/* Backward character. */
413
static void vty_backward_char(struct vty *vty)
414
{
415
	if (vty->cp > 0) {
416
		vty->cp--;
417
		vty_write(vty, &telnet_backward_char, 1);
418
	}
419
}
420

    
421
/* Move to the beginning of the line. */
422
static void vty_beginning_of_line(struct vty *vty)
423
{
424
	while (vty->cp)
425
		vty_backward_char(vty);
426
}
427

    
428
/* Move to the end of the line. */
429
static void vty_end_of_line(struct vty *vty)
430
{
431
	while (vty->cp < vty->length)
432
		vty_forward_char(vty);
433
}
434

    
435
/* Add current command line to the history buffer. */
436
static void vty_hist_add(struct vty *vty)
437
{
438
	int index;
439

    
440
	if (vty->length == 0)
441
		return;
442

    
443
	index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
444

    
445
	/* Ignore the same string as previous one. */
446
	if (vty->hist[index])
447
		if (strcmp(vty->buf, vty->hist[index]) == 0) {
448
			vty->hp = vty->hindex;
449
			return;
450
		}
451

    
452
	/* Insert history entry. */
453
	if (vty->hist[vty->hindex])
454
		free(vty->hist[vty->hindex]);
455
	vty->hist[vty->hindex] = strdup(vty->buf);
456

    
457
	/* History index rotation. */
458
	vty->hindex++;
459
	if (vty->hindex == VTY_MAXHIST)
460
		vty->hindex = 0;
461

    
462
	vty->hp = vty->hindex;
463
}
464

    
465
/* Execute current command line. */
466
static int vty_execute(struct vty *vty)
467
{
468
	int ret;
469

    
470
	ret = CMD_SUCCESS;
471

    
472
	switch (vty->node) {
473
	case AUTH_NODE:
474
	case AUTH_ENABLE_NODE:
475
		vty_auth(vty, vty->buf);
476
		break;
477
	default:
478
		ret = vty_command(vty, vty->buf);
479
		if (vty->type == VTY_TERM)
480
			vty_hist_add(vty);
481
		break;
482
	}
483

    
484
	/* Clear command line buffer. */
485
	vty->cp = vty->length = 0;
486
	vty_clear_buf(vty);
487

    
488
	if (vty->status != VTY_CLOSE)
489
		vty_prompt(vty);
490

    
491
	return ret;
492
}
493

    
494
static void vty_kill_line_from_beginning(struct vty *);
495
static void vty_redraw_line(struct vty *);
496

    
497
/* Print command line history.  This function is called from
498
   vty_next_line and vty_previous_line. */
499
static void vty_history_print(struct vty *vty)
500
{
501
	int length;
502

    
503
	vty_kill_line_from_beginning(vty);
504

    
505
	/* Get previous line from history buffer */
506
	length = strlen(vty->hist[vty->hp]);
507
	memcpy(vty->buf, vty->hist[vty->hp], length);
508
	vty->cp = vty->length = length;
509

    
510
	/* Redraw current line */
511
	vty_redraw_line(vty);
512
}
513

    
514
/* Show next command line history. */
515
static void vty_next_line(struct vty *vty)
516
{
517
	int try_index;
518

    
519
	if (vty->hp == vty->hindex)
520
		return;
521

    
522
	/* Try is there history exist or not. */
523
	try_index = vty->hp;
524
	if (try_index == (VTY_MAXHIST - 1))
525
		try_index = 0;
526
	else
527
		try_index++;
528

    
529
	/* If there is not history return. */
530
	if (vty->hist[try_index] == NULL)
531
		return;
532
	else
533
		vty->hp = try_index;
534

    
535
	vty_history_print(vty);
536
}
537

    
538
/* Show previous command line history. */
539
static void vty_previous_line(struct vty *vty)
540
{
541
	int try_index;
542

    
543
	try_index = vty->hp;
544
	if (try_index == 0)
545
		try_index = VTY_MAXHIST - 1;
546
	else
547
		try_index--;
548

    
549
	if (vty->hist[try_index] == NULL)
550
		return;
551
	else
552
		vty->hp = try_index;
553

    
554
	vty_history_print(vty);
555
}
556

    
557
/* This function redraw all of the command line character. */
558
static void vty_redraw_line(struct vty *vty)
559
{
560
	vty_write(vty, vty->buf, vty->length);
561
	vty->cp = vty->length;
562
}
563

    
564
/* Forward word. */
565
static void vty_forward_word(struct vty *vty)
566
{
567
	while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
568
		vty_forward_char(vty);
569

    
570
	while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
571
		vty_forward_char(vty);
572
}
573

    
574
/* Backward word without skipping training space. */
575
static void vty_backward_pure_word(struct vty *vty)
576
{
577
	while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
578
		vty_backward_char(vty);
579
}
580

    
581
/* Backward word. */
582
static void vty_backward_word(struct vty *vty)
583
{
584
	while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
585
		vty_backward_char(vty);
586

    
587
	while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
588
		vty_backward_char(vty);
589
}
590

    
591
/* When '^D' is typed at the beginning of the line we move to the down
592
   level. */
593
static void vty_down_level(struct vty *vty)
594
{
595
	vty_out(vty, "%s", VTY_NEWLINE);
596
	(*config_exit_cmd.func) (NULL, vty, 0, NULL);
597
	vty_prompt(vty);
598
	vty->cp = 0;
599
}
600

    
601
/* When '^Z' is received from vty, move down to the enable mode. */
602
static void vty_end_config(struct vty *vty)
603
{
604
	vty_out(vty, "%s", VTY_NEWLINE);
605

    
606
	switch (vty->node) {
607
	case VIEW_NODE:
608
	case ENABLE_NODE:
609
		/* Nothing to do. */
610
		break;
611
	case CONFIG_NODE:
612
	case INTERFACE_NODE:
613
	case ZEBRA_NODE:
614
	case RIP_NODE:
615
	case RIPNG_NODE:
616
	case BGP_NODE:
617
	case BGP_VPNV4_NODE:
618
	case BGP_IPV4_NODE:
619
	case BGP_IPV4M_NODE:
620
	case BGP_IPV6_NODE:
621
	case RMAP_NODE:
622
	case OSPF_NODE:
623
	case OSPF6_NODE:
624
	case ISIS_NODE:
625
	case KEYCHAIN_NODE:
626
	case KEYCHAIN_KEY_NODE:
627
	case MASC_NODE:
628
	case VTY_NODE:
629
		vty_config_unlock(vty);
630
		vty->node = ENABLE_NODE;
631
		break;
632
	default:
633
		/* Unknown node, we have to ignore it. */
634
		break;
635
	}
636

    
637
	vty_prompt(vty);
638
	vty->cp = 0;
639
}
640

    
641
/* Delete a charcter at the current point. */
642
static void vty_delete_char(struct vty *vty)
643
{
644
	int i;
645
	int size;
646

    
647
	if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
648
		return;
649

    
650
	if (vty->length == 0) {
651
		vty_down_level(vty);
652
		return;
653
	}
654

    
655
	if (vty->cp == vty->length)
656
		return;		/* completion need here? */
657

    
658
	size = vty->length - vty->cp;
659

    
660
	vty->length--;
661
	memmove(&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
662
	vty->buf[vty->length] = '\0';
663

    
664
	vty_write(vty, &vty->buf[vty->cp], size - 1);
665
	vty_write(vty, &telnet_space_char, 1);
666

    
667
	for (i = 0; i < size; i++)
668
		vty_write(vty, &telnet_backward_char, 1);
669
}
670

    
671
/* Delete a character before the point. */
672
static void vty_delete_backward_char(struct vty *vty)
673
{
674
	if (vty->cp == 0)
675
		return;
676

    
677
	vty_backward_char(vty);
678
	vty_delete_char(vty);
679
}
680

    
681
/* Kill rest of line from current point. */
682
static void vty_kill_line(struct vty *vty)
683
{
684
	int i;
685
	int size;
686

    
687
	size = vty->length - vty->cp;
688

    
689
	if (size == 0)
690
		return;
691

    
692
	for (i = 0; i < size; i++)
693
		vty_write(vty, &telnet_space_char, 1);
694
	for (i = 0; i < size; i++)
695
		vty_write(vty, &telnet_backward_char, 1);
696

    
697
	memset(&vty->buf[vty->cp], 0, size);
698
	vty->length = vty->cp;
699
}
700

    
701
/* Kill line from the beginning. */
702
static void vty_kill_line_from_beginning(struct vty *vty)
703
{
704
	vty_beginning_of_line(vty);
705
	vty_kill_line(vty);
706
}
707

    
708
/* Delete a word before the point. */
709
static void vty_forward_kill_word(struct vty *vty)
710
{
711
	while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
712
		vty_delete_char(vty);
713
	while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
714
		vty_delete_char(vty);
715
}
716

    
717
/* Delete a word before the point. */
718
static void vty_backward_kill_word(struct vty *vty)
719
{
720
	while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
721
		vty_delete_backward_char(vty);
722
	while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
723
		vty_delete_backward_char(vty);
724
}
725

    
726
/* Transpose chars before or at the point. */
727
static void vty_transpose_chars(struct vty *vty)
728
{
729
	char c1, c2;
730

    
731
	/* If length is short or point is near by the beginning of line then
732
	   return. */
733
	if (vty->length < 2 || vty->cp < 1)
734
		return;
735

    
736
	/* In case of point is located at the end of the line. */
737
	if (vty->cp == vty->length) {
738
		c1 = vty->buf[vty->cp - 1];
739
		c2 = vty->buf[vty->cp - 2];
740

    
741
		vty_backward_char(vty);
742
		vty_backward_char(vty);
743
		vty_self_insert_overwrite(vty, c1);
744
		vty_self_insert_overwrite(vty, c2);
745
	} else {
746
		c1 = vty->buf[vty->cp];
747
		c2 = vty->buf[vty->cp - 1];
748

    
749
		vty_backward_char(vty);
750
		vty_self_insert_overwrite(vty, c1);
751
		vty_self_insert_overwrite(vty, c2);
752
	}
753
}
754

    
755
/* Do completion at vty interface. */
756
static void vty_complete_command(struct vty *vty)
757
{
758
	int i;
759
	int ret;
760
	char **matched = NULL;
761
	vector vline;
762

    
763
	if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
764
		return;
765

    
766
	vline = cmd_make_strvec(vty->buf);
767
	if (vline == NULL)
768
		return;
769

    
770
	/* In case of 'help \t'. */
771
	if (isspace((int)vty->buf[vty->length - 1]))
772
		vector_set(vline, '\0');
773

    
774
	matched = cmd_complete_command(vline, vty, &ret);
775

    
776
	cmd_free_strvec(vline);
777

    
778
	vty_out(vty, "%s", VTY_NEWLINE);
779
	switch (ret) {
780
	case CMD_ERR_AMBIGUOUS:
781
		vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
782
		vty_prompt(vty);
783
		vty_redraw_line(vty);
784
		break;
785
	case CMD_ERR_NO_MATCH:
786
		/* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
787
		vty_prompt(vty);
788
		vty_redraw_line(vty);
789
		break;
790
	case CMD_COMPLETE_FULL_MATCH:
791
		vty_prompt(vty);
792
		vty_redraw_line(vty);
793
		vty_backward_pure_word(vty);
794
		vty_insert_word_overwrite(vty, matched[0]);
795
		vty_self_insert(vty, ' ');
796
		free(matched[0]);
797
		break;
798
	case CMD_COMPLETE_MATCH:
799
		vty_prompt(vty);
800
		vty_redraw_line(vty);
801
		vty_backward_pure_word(vty);
802
		vty_insert_word_overwrite(vty, matched[0]);
803
		free(matched[0]);
804
		vector_only_index_free(matched);
805
		return;
806
		break;
807
	case CMD_COMPLETE_LIST_MATCH:
808
		for (i = 0; matched[i] != NULL; i++) {
809
			if (i != 0 && ((i % 6) == 0))
810
				vty_out(vty, "%s", VTY_NEWLINE);
811
			vty_out(vty, "%-10s ", matched[i]);
812
			free(matched[i]);
813
		}
814
		vty_out(vty, "%s", VTY_NEWLINE);
815

    
816
		vty_prompt(vty);
817
		vty_redraw_line(vty);
818
		break;
819
	case CMD_ERR_NOTHING_TODO:
820
		vty_prompt(vty);
821
		vty_redraw_line(vty);
822
		break;
823
	default:
824
		break;
825
	}
826
	if (matched)
827
		vector_only_index_free(matched);
828
}
829

    
830
static void
831
vty_describe_fold(struct vty *vty, int cmd_width,
832
		  unsigned int desc_width, struct desc *desc)
833
{
834
	char *buf;
835
	const char *cmd, *p;
836
	int pos;
837

    
838
	cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
839

    
840
	if (desc_width <= 0) {
841
		vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, desc->str,
842
			VTY_NEWLINE);
843
		return;
844
	}
845

    
846
	buf = calloc(1, strlen(desc->str) + 1);
847
	if (!buf)
848
		return;
849

    
850
	for (p = desc->str; strlen(p) > desc_width; p += pos + 1) {
851
		for (pos = desc_width; pos > 0; pos--)
852
			if (*(p + pos) == ' ')
853
				break;
854

    
855
		if (pos == 0)
856
			break;
857

    
858
		strncpy(buf, p, pos);
859
		buf[pos] = '\0';
860
		vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
861

    
862
		cmd = "";
863
	}
864

    
865
	vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, p, VTY_NEWLINE);
866

    
867
	free(buf);
868
}
869

    
870
/* Describe matched command function. */
871
static void vty_describe_command(struct vty *vty)
872
{
873
	int ret;
874
	vector vline;
875
	vector describe;
876
	unsigned int i, width, desc_width;
877
	struct desc *desc, *desc_cr = NULL;
878

    
879
	vline = cmd_make_strvec(vty->buf);
880

    
881
	/* In case of '> ?'. */
882
	if (vline == NULL) {
883
		vline = vector_init(1);
884
		vector_set(vline, '\0');
885
	} else if (isspace((int)vty->buf[vty->length - 1]))
886
		vector_set(vline, '\0');
887

    
888
	describe = cmd_describe_command(vline, vty, &ret);
889

    
890
	vty_out(vty, "%s", VTY_NEWLINE);
891

    
892
	/* Ambiguous error. */
893
	switch (ret) {
894
	case CMD_ERR_AMBIGUOUS:
895
		cmd_free_strvec(vline);
896
		vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
897
		vty_prompt(vty);
898
		vty_redraw_line(vty);
899
		return;
900
		break;
901
	case CMD_ERR_NO_MATCH:
902
		cmd_free_strvec(vline);
903
		vty_out(vty, "%% There is no matched command.%s", VTY_NEWLINE);
904
		vty_prompt(vty);
905
		vty_redraw_line(vty);
906
		return;
907
		break;
908
	}
909

    
910
	/* Get width of command string. */
911
	width = 0;
912
	for (i = 0; i < vector_active(describe); i++)
913
		if ((desc = vector_slot(describe, i)) != NULL) {
914
			unsigned int len;
915

    
916
			if (desc->cmd[0] == '\0')
917
				continue;
918

    
919
			len = strlen(desc->cmd);
920
			if (desc->cmd[0] == '.')
921
				len--;
922

    
923
			if (width < len)
924
				width = len;
925
		}
926

    
927
	/* Get width of description string. */
928
	desc_width = vty->width - (width + 6);
929

    
930
	/* Print out description. */
931
	for (i = 0; i < vector_active(describe); i++)
932
		if ((desc = vector_slot(describe, i)) != NULL) {
933
			if (desc->cmd[0] == '\0')
934
				continue;
935

    
936
			if (strcmp(desc->cmd, "<cr>") == 0) {
937
				desc_cr = desc;
938
				continue;
939
			}
940

    
941
			if (!desc->str)
942
				vty_out(vty, "  %-s%s",
943
					desc->cmd[0] ==
944
					'.' ? desc->cmd + 1 : desc->cmd,
945
					VTY_NEWLINE);
946
			else if (desc_width >= strlen(desc->str))
947
				vty_out(vty, "  %-*s  %s%s", width,
948
					desc->cmd[0] ==
949
					'.' ? desc->cmd + 1 : desc->cmd,
950
					desc->str, VTY_NEWLINE);
951
			else
952
				vty_describe_fold(vty, width, desc_width, desc);
953

    
954
#if 0
955
			vty_out(vty, "  %-*s %s%s", width
956
				desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
957
				desc->str ? desc->str : "", VTY_NEWLINE);
958
#endif				/* 0 */
959
		}
960

    
961
	if ((desc = desc_cr)) {
962
		if (!desc->str)
963
			vty_out(vty, "  %-s%s",
964
				desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
965
				VTY_NEWLINE);
966
		else if (desc_width >= strlen(desc->str))
967
			vty_out(vty, "  %-*s  %s%s", width,
968
				desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
969
				desc->str, VTY_NEWLINE);
970
		else
971
			vty_describe_fold(vty, width, desc_width, desc);
972
	}
973

    
974
	cmd_free_strvec(vline);
975
	vector_free(describe);
976

    
977
	vty_prompt(vty);
978
	vty_redraw_line(vty);
979
}
980

    
981
/* ^C stop current input and do not add command line to the history. */
982
static void vty_stop_input(struct vty *vty)
983
{
984
	vty->cp = vty->length = 0;
985
	vty_clear_buf(vty);
986
	vty_out(vty, "%s", VTY_NEWLINE);
987

    
988
	switch (vty->node) {
989
	case VIEW_NODE:
990
	case ENABLE_NODE:
991
		/* Nothing to do. */
992
		break;
993
	case CONFIG_NODE:
994
	case INTERFACE_NODE:
995
	case ZEBRA_NODE:
996
	case RIP_NODE:
997
	case RIPNG_NODE:
998
	case BGP_NODE:
999
	case RMAP_NODE:
1000
	case OSPF_NODE:
1001
	case OSPF6_NODE:
1002
	case ISIS_NODE:
1003
	case KEYCHAIN_NODE:
1004
	case KEYCHAIN_KEY_NODE:
1005
	case MASC_NODE:
1006
	case VTY_NODE:
1007
		vty_config_unlock(vty);
1008
		vty->node = ENABLE_NODE;
1009
		break;
1010
	default:
1011
		/* Unknown node, we have to ignore it. */
1012
		break;
1013
	}
1014
	vty_prompt(vty);
1015

    
1016
	/* Set history pointer to the latest one. */
1017
	vty->hp = vty->hindex;
1018
}
1019

    
1020
#define CONTROL(X)  ((X) - '@')
1021
#define VTY_NORMAL     0
1022
#define VTY_PRE_ESCAPE 1
1023
#define VTY_ESCAPE     2
1024

    
1025
/* Escape character command map. */
1026
static void vty_escape_map(unsigned char c, struct vty *vty)
1027
{
1028
	switch (c) {
1029
	case ('A'):
1030
		vty_previous_line(vty);
1031
		break;
1032
	case ('B'):
1033
		vty_next_line(vty);
1034
		break;
1035
	case ('C'):
1036
		vty_forward_char(vty);
1037
		break;
1038
	case ('D'):
1039
		vty_backward_char(vty);
1040
		break;
1041
	default:
1042
		break;
1043
	}
1044

    
1045
	/* Go back to normal mode. */
1046
	vty->escape = VTY_NORMAL;
1047
}
1048

    
1049
/* Quit print out to the buffer. */
1050
static void vty_buffer_reset(struct vty *vty)
1051
{
1052
	buffer_reset(vty->obuf);
1053
	vty_prompt(vty);
1054
	vty_redraw_line(vty);
1055
}
1056

    
1057
/* Read data via vty socket. */
1058
int vty_read(struct vty *vty)
1059
{
1060
	int i;
1061
	int nbytes;
1062
	unsigned char buf[VTY_READ_BUFSIZ];
1063

    
1064
	int vty_sock = 0;
1065

    
1066
	/* Read raw data from socket */
1067
	if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) {
1068
		if (nbytes < 0) {
1069
			if (ERRNO_IO_RETRY(errno)) {
1070
				vty_event(VTY_READ, vty_sock, vty);
1071
				return 0;
1072
			}
1073
		}
1074
		buffer_reset(vty->obuf);
1075
		vty->status = VTY_CLOSE;
1076
	}
1077

    
1078
	for (i = 0; i < nbytes; i++) {
1079
#if 0
1080
		if (buf[i] == IAC) {
1081
			if (!vty->iac) {
1082
				vty->iac = 1;
1083
				continue;
1084
			} else {
1085
				vty->iac = 0;
1086
			}
1087
		}
1088

    
1089
		if (vty->iac_sb_in_progress && !vty->iac) {
1090
			if (vty->sb_len < sizeof(vty->sb_buf))
1091
				vty->sb_buf[vty->sb_len] = buf[i];
1092
			vty->sb_len++;
1093
			continue;
1094
		}
1095

    
1096
		if (vty->iac) {
1097
			/* In case of telnet command */
1098
			int ret = 0;
1099
			ret = vty_telnet_option(vty, buf + i, nbytes - i);
1100
			vty->iac = 0;
1101
			i += ret;
1102
			continue;
1103
		}
1104
#endif
1105

    
1106
		if (vty->status == VTY_MORE) {
1107
			switch (buf[i]) {
1108
			case CONTROL('C'):
1109
			case 'q':
1110
			case 'Q':
1111
				vty_buffer_reset(vty);
1112
				break;
1113
#if 0				/* More line does not work for "show ip bgp".  */
1114
			case '\n':
1115
			case '\r':
1116
				vty->status = VTY_MORELINE;
1117
				break;
1118
#endif
1119
			default:
1120
				break;
1121
			}
1122
			continue;
1123
		}
1124

    
1125
		/* Escape character. */
1126
		if (vty->escape == VTY_ESCAPE) {
1127
			vty_escape_map(buf[i], vty);
1128
			continue;
1129
		}
1130

    
1131
		/* Pre-escape status. */
1132
		if (vty->escape == VTY_PRE_ESCAPE) {
1133
			switch (buf[i]) {
1134
			case '[':
1135
				vty->escape = VTY_ESCAPE;
1136
				break;
1137
			case 'b':
1138
				vty_backward_word(vty);
1139
				vty->escape = VTY_NORMAL;
1140
				break;
1141
			case 'f':
1142
				vty_forward_word(vty);
1143
				vty->escape = VTY_NORMAL;
1144
				break;
1145
			case 'd':
1146
				vty_forward_kill_word(vty);
1147
				vty->escape = VTY_NORMAL;
1148
				break;
1149
			case CONTROL('H'):
1150
			case 0x7f:
1151
				vty_backward_kill_word(vty);
1152
				vty->escape = VTY_NORMAL;
1153
				break;
1154
			default:
1155
				vty->escape = VTY_NORMAL;
1156
				break;
1157
			}
1158
			continue;
1159
		}
1160

    
1161
		switch (buf[i]) {
1162
		case CONTROL('A'):
1163
			vty_beginning_of_line(vty);
1164
			break;
1165
		case CONTROL('B'):
1166
			vty_backward_char(vty);
1167
			break;
1168
		case CONTROL('C'):
1169
			vty_stop_input(vty);
1170
			break;
1171
		case CONTROL('D'):
1172
			vty_delete_char(vty);
1173
			break;
1174
		case CONTROL('E'):
1175
			vty_end_of_line(vty);
1176
			break;
1177
		case CONTROL('F'):
1178
			vty_forward_char(vty);
1179
			break;
1180
		case CONTROL('H'):
1181
		case 0x7f:
1182
			vty_delete_backward_char(vty);
1183
			break;
1184
		case CONTROL('K'):
1185
			vty_kill_line(vty);
1186
			break;
1187
		case CONTROL('N'):
1188
			vty_next_line(vty);
1189
			break;
1190
		case CONTROL('P'):
1191
			vty_previous_line(vty);
1192
			break;
1193
		case CONTROL('T'):
1194
			vty_transpose_chars(vty);
1195
			break;
1196
		case CONTROL('U'):
1197
			vty_kill_line_from_beginning(vty);
1198
			break;
1199
		case CONTROL('W'):
1200
			vty_backward_kill_word(vty);
1201
			break;
1202
		case CONTROL('Z'):
1203
			vty_end_config(vty);
1204
			break;
1205
		case '\n':
1206
		case '\r':
1207
			vty_out(vty, "%s", VTY_NEWLINE);
1208
			vty_execute(vty);
1209
			break;
1210
		case '\t':
1211
			vty_complete_command(vty);
1212
			break;
1213
		case '?':
1214
			if (vty->node == AUTH_NODE
1215
			    || vty->node == AUTH_ENABLE_NODE)
1216
				vty_self_insert(vty, buf[i]);
1217
			else
1218
				vty_describe_command(vty);
1219
			break;
1220
		case '\033':
1221
			if (i + 1 < nbytes && buf[i + 1] == '[') {
1222
				vty->escape = VTY_ESCAPE;
1223
				i++;
1224
			} else
1225
				vty->escape = VTY_PRE_ESCAPE;
1226
			break;
1227
		default:
1228
			if (buf[i] > 31 && buf[i] < 127)
1229
				vty_self_insert(vty, buf[i]);
1230
			break;
1231
		}
1232
	}
1233

    
1234
	/* Check status. */
1235
	if (vty->status == VTY_CLOSE)
1236
		vty_close(vty);
1237
	else {
1238
		vty_event(VTY_WRITE, vty_sock, vty);
1239
		vty_event(VTY_READ, vty_sock, vty);
1240
	}
1241
	return 0;
1242
}
1243

    
1244
/* Create new vty structure. */
1245
struct vty *
1246
vty_create (int vty_sock)
1247
{
1248
  struct vty *vty;
1249

    
1250
	struct termios t;
1251
	
1252
	tcgetattr(vty_sock, &t);
1253
	cfmakeraw(&t);
1254
	tcsetattr(vty_sock, TCSANOW, &t);
1255

    
1256
  /* Allocate new vty structure and set up default values. */
1257
  vty = vty_new ();
1258
  vty->fd = vty_sock;
1259
  vty->type = VTY_TERM;
1260
  if (no_password_check)
1261
    {
1262
      if (host.advanced)
1263
	vty->node = ENABLE_NODE;
1264
      else
1265
	vty->node = VIEW_NODE;
1266
    }
1267
  else
1268
    vty->node = AUTH_NODE;
1269
  vty->fail = 0;
1270
  vty->cp = 0;
1271
  vty_clear_buf (vty);
1272
  vty->length = 0;
1273
  memset (vty->hist, 0, sizeof (vty->hist));
1274
  vty->hp = 0;
1275
  vty->hindex = 0;
1276
  vector_set_index (vtyvec, vty_sock, vty);
1277
  vty->status = VTY_NORMAL;
1278
  if (host.lines >= 0)
1279
    vty->lines = host.lines;
1280
  else
1281
    vty->lines = -1;
1282

    
1283
  if (! no_password_check)
1284
    {
1285
      /* Vty is not available if password isn't set. */
1286
      if (host.password == NULL && host.password_encrypt == NULL)
1287
	{
1288
	  vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1289
	  vty->status = VTY_CLOSE;
1290
	  vty_close (vty);
1291
	  return NULL;
1292
	}
1293
    }
1294

    
1295
  /* Say hello to the world. */
1296
  vty_hello (vty);
1297
  if (! no_password_check)
1298
    vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1299

    
1300
#if 0
1301
  /* Setting up terminal. */
1302
  vty_will_echo (vty);
1303
  vty_will_suppress_go_ahead (vty);
1304

    
1305
  vty_dont_linemode (vty);
1306
  vty_do_window_size (vty);
1307
  /* vty_dont_lflow_ahead (vty); */
1308
#endif
1309

    
1310
  vty_prompt (vty);
1311

    
1312
  /* Add read/write thread. */
1313
  vty_event (VTY_WRITE, vty_sock, vty);
1314
  vty_event (VTY_READ, vty_sock, vty);
1315

    
1316
  return vty;
1317
}
1318

    
1319
DEFUN(config_who, config_who_cmd, "who", "Display who is on vty\n")
1320
{
1321
	unsigned int i;
1322
	struct vty *v;
1323

    
1324
	for (i = 0; i < vector_active(vtyvec); i++)
1325
		if ((v = vector_slot(vtyvec, i)) != NULL)
1326
			vty_out(vty, "%svty[%d] %s",
1327
				v->config ? "*" : " ", i, VTY_NEWLINE);
1328
	return CMD_SUCCESS;
1329
}
1330

    
1331
/* Move to vty configuration mode. */
1332
DEFUN(line_vty,
1333
      line_vty_cmd,
1334
      "line vty", "Configure a terminal line\n" "Virtual terminal\n")
1335
{
1336
	vty->node = VTY_NODE;
1337
	return CMD_SUCCESS;
1338
}
1339

    
1340
/* vty login. */
1341
DEFUN(vty_login, vty_login_cmd, "login", "Enable password checking\n")
1342
{
1343
	no_password_check = 0;
1344
	return CMD_SUCCESS;
1345
}
1346

    
1347
DEFUN(no_vty_login,
1348
      no_vty_login_cmd, "no login", NO_STR "Enable password checking\n")
1349
{
1350
	no_password_check = 1;
1351
	return CMD_SUCCESS;
1352
}
1353

    
1354
DEFUN(service_advanced_vty,
1355
      service_advanced_vty_cmd,
1356
      "service advanced-vty",
1357
      "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
1358
{
1359
	host.advanced = 1;
1360
	return CMD_SUCCESS;
1361
}
1362

    
1363
DEFUN(no_service_advanced_vty,
1364
      no_service_advanced_vty_cmd,
1365
      "no service advanced-vty",
1366
      NO_STR
1367
      "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
1368
{
1369
	host.advanced = 0;
1370
	return CMD_SUCCESS;
1371
}
1372

    
1373
DEFUN(terminal_monitor,
1374
      terminal_monitor_cmd,
1375
      "terminal monitor",
1376
      "Set terminal line parameters\n"
1377
      "Copy debug output to the current terminal line\n")
1378
{
1379
	vty->monitor = 1;
1380
	return CMD_SUCCESS;
1381
}
1382

    
1383
DEFUN(terminal_no_monitor,
1384
      terminal_no_monitor_cmd,
1385
      "terminal no monitor",
1386
      "Set terminal line parameters\n"
1387
      NO_STR "Copy debug output to the current terminal line\n")
1388
{
1389
	vty->monitor = 0;
1390
	return CMD_SUCCESS;
1391
}
1392

    
1393
DEFUN(show_history,
1394
      show_history_cmd,
1395
      "show history", SHOW_STR "Display the session command history\n")
1396
{
1397
	int index;
1398

    
1399
	for (index = vty->hindex + 1; index != vty->hindex;) {
1400
		if (index == VTY_MAXHIST) {
1401
			index = 0;
1402
			continue;
1403
		}
1404

    
1405
		if (vty->hist[index] != NULL)
1406
			vty_out(vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
1407

    
1408
		index++;
1409
	}
1410

    
1411
	return CMD_SUCCESS;
1412
}
1413

    
1414
/* Display current configuration. */
1415
static int vty_config_write(struct vty *vty)
1416
{
1417
	vty_out(vty, "line vty%s", VTY_NEWLINE);
1418

    
1419
	/* login */
1420
	if (no_password_check)
1421
		vty_out(vty, " no login%s", VTY_NEWLINE);
1422

    
1423
	vty_out(vty, "!%s", VTY_NEWLINE);
1424

    
1425
	return CMD_SUCCESS;
1426
}
1427

    
1428
struct cmd_node vty_node = {
1429
	VTY_NODE,
1430
	"%s(config-line)# ",
1431
	1,
1432
};
1433

    
1434
/* Reset all VTY status. */
1435
void vty_reset()
1436
{
1437
	unsigned int i;
1438
	struct vty *vty;
1439
	struct thread *vty_serv_thread;
1440

    
1441
	for (i = 0; i < vector_active(vtyvec); i++)
1442
		if ((vty = vector_slot(vtyvec, i)) != NULL) {
1443
			buffer_reset(vty->obuf);
1444
			vty->status = VTY_CLOSE;
1445
			vty_close(vty);
1446
		}
1447

    
1448
	for (i = 0; i < vector_active(Vvty_serv_thread); i++)
1449
		if ((vty_serv_thread =
1450
		     vector_slot(Vvty_serv_thread, i)) != NULL) {
1451
			//thread_cancel (vty_serv_thread);
1452
			vector_slot(Vvty_serv_thread, i) = NULL;
1453
			close(i);
1454
		}
1455
}
1456

    
1457
static void vty_save_cwd(void)
1458
{
1459
	char cwd[MAXPATHLEN];
1460
	char *c;
1461

    
1462
	c = getcwd(cwd, MAXPATHLEN);
1463

    
1464
	if (!c) {
1465
		chdir(SYSCONFDIR);
1466
		getcwd(cwd, MAXPATHLEN);
1467
	}
1468

    
1469
	vty_cwd = malloc(strlen(cwd) + 1);
1470
	strcpy(vty_cwd, cwd);
1471
}
1472

    
1473
char *vty_get_cwd()
1474
{
1475
	return vty_cwd;
1476
}
1477

    
1478
int vty_shell_serv(struct vty *vty)
1479
{
1480
	return vty->type == VTY_SHELL_SERV ? 1 : 0;
1481
}
1482

    
1483
void vty_init_vtysh()
1484
{
1485
	vtyvec = vector_init(VECTOR_MIN_SIZE);
1486
}
1487

    
1488
/* Install vty's own commands like `who' command. */
1489
void vty_init()
1490
{
1491
	/* For further configuration read, preserve current directory. */
1492
	vty_save_cwd();
1493

    
1494
	vtyvec = vector_init(VECTOR_MIN_SIZE);
1495

    
1496
	/* Install bgp top node. */
1497
	install_node(&vty_node, vty_config_write);
1498

    
1499
	install_element(VIEW_NODE, &config_who_cmd);
1500
	install_element(VIEW_NODE, &show_history_cmd);
1501
	install_element(ENABLE_NODE, &config_who_cmd);
1502
	install_element(CONFIG_NODE, &line_vty_cmd);
1503
	install_element(CONFIG_NODE, &service_advanced_vty_cmd);
1504
	install_element(CONFIG_NODE, &no_service_advanced_vty_cmd);
1505
	install_element(CONFIG_NODE, &show_history_cmd);
1506
	install_element(ENABLE_NODE, &terminal_monitor_cmd);
1507
	install_element(ENABLE_NODE, &terminal_no_monitor_cmd);
1508
	install_element(ENABLE_NODE, &show_history_cmd);
1509

    
1510
	install_default(VTY_NODE);
1511
#if 0
1512
	install_element(VTY_NODE, &vty_login_cmd);
1513
	install_element(VTY_NODE, &no_vty_login_cmd);
1514
#endif
1515
}
(8-8/10)
Add picture from clipboard (Maximum size: 48.8 MB)