Annotation of embedaddon/mpd/src/console.c, revision 1.1.1.3
1.1 misho 1:
2: /*
3: * console.c
4: *
5: * Written by Archie Cobbs <archie@freebsd.org>
6: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
7: * See ``COPYRIGHT.whistle''
8: */
9:
10: #include "ppp.h"
11: #include "console.h"
12: #include "util.h"
13: #include <termios.h>
14:
15: /*
16: * DEFINITIONS
17: */
18:
19: #ifndef CTRL
20: #define CTRL(c) (c - '@')
21: #endif
22:
23: #define EchoOff() cs->write(cs, "\xFF\xFB\x01\xFF\xFD\x01");
24: #define EchoOn() cs->write(cs, "\xFF\xFC\x01\xFF\xFE\x01");
25:
26:
27: enum {
28: STATE_USERNAME = 0,
29: STATE_PASSWORD,
30: STATE_AUTHENTIC
31: };
32:
33: /* Set menu options */
34: enum {
35: SET_OPEN,
36: SET_CLOSE,
37: SET_SELF,
38: SET_DISABLE,
39: SET_ENABLE
40: };
41:
42:
43: /*
44: * INTERNAL FUNCTIONS
45: */
46:
47: static void ConsoleConnect(int type, void *cookie);
48: static void ConsoleSessionClose(ConsoleSession cs);
49: static void ConsoleSessionReadEvent(int type, void *cookie);
50: static void ConsoleSessionWrite(ConsoleSession cs, const char *fmt, ...);
51: static void ConsoleSessionWriteV(ConsoleSession cs, const char *fmt, va_list vl);
52: static void ConsoleSessionShowPrompt(ConsoleSession cs);
53:
54: static void StdConsoleSessionClose(ConsoleSession cs);
55: static void StdConsoleSessionWrite(ConsoleSession cs, const char *fmt, ...);
56: static void StdConsoleSessionWriteV(ConsoleSession cs, const char *fmt, va_list vl);
57:
58: static int ConsoleUserHashEqual(struct ghash *g, const void *item1,
59: const void *item2);
60: static u_int32_t ConsoleUserHash(struct ghash *g, const void *item);
61: static int ConsoleSetCommand(Context ctx, int ac, char *av[], void *arg);
62:
63:
64: /*
65: * GLOBAL VARIABLES
66: */
67:
68: const struct cmdtab ConsoleSetCmds[] = {
69: { "open", "Open the console" ,
70: ConsoleSetCommand, NULL, 2, (void *) SET_OPEN },
71: { "close", "Close the console" ,
72: ConsoleSetCommand, NULL, 2, (void *) SET_CLOSE },
73: { "self {ip} [{port}]", "Set console ip and port" ,
74: ConsoleSetCommand, NULL, 2, (void *) SET_SELF },
75: { "enable [opt ...]", "Enable this console option" ,
76: ConsoleSetCommand, NULL, 0, (void *) SET_ENABLE },
77: { "disable [opt ...]", "Disable this console option" ,
78: ConsoleSetCommand, NULL, 0, (void *) SET_DISABLE },
79: { NULL },
80: };
81:
82: struct ghash *gUsers; /* allowed users */
83: pthread_rwlock_t gUsersLock;
84:
85: /*
86: * INTERNAL VARIABLES
87: */
88:
89: static const struct confinfo gConfList[] = {
1.1.1.3 ! misho 90: { 0, CONSOLE_AUTH, "auth" },
! 91: { 0, 0, NULL },
! 92: };
! 93:
! 94: static const struct confinfo sConfList[] = {
1.1 misho 95: { 0, CONSOLE_LOGGING, "logging" },
96: { 0, 0, NULL },
97: };
98:
99: struct termios gOrigTermiosAttrs;
100: int gOrigFlags;
101:
102: /*
103: * ConsoleInit()
104: */
105:
106: int
107: ConsoleInit(Console c)
108: {
109: int ret;
110:
111: /* setup console-defaults */
112: memset(&gConsole, 0, sizeof(gConsole));
113: ParseAddr(DEFAULT_CONSOLE_IP, &c->addr, ALLOW_IPV4|ALLOW_IPV6);
114: c->port = DEFAULT_CONSOLE_PORT;
1.1.1.3 ! misho 115: Enable(&c->options, CONSOLE_AUTH);
1.1 misho 116:
117: SLIST_INIT(&c->sessions);
118:
119: if ((ret = pthread_rwlock_init (&c->lock, NULL)) != 0) {
120: Log(LG_ERR, ("Could not create rwlock %d", ret));
121: return (-1);
122: }
123:
124: gUsers = ghash_create(c, 0, 0, MB_CONS, ConsoleUserHash, ConsoleUserHashEqual, NULL, NULL);
125: if ((ret = pthread_rwlock_init (&gUsersLock, NULL)) != 0) {
126: Log(LG_ERR, ("Could not create rwlock %d", ret));
127: return (-1);
128: }
129:
130: return (0);
131: }
132:
133: /*
134: * ConsoleOpen()
135: */
136:
137: int
138: ConsoleOpen(Console c)
139: {
140: char addrstr[INET6_ADDRSTRLEN];
141:
142: if (c->fd) {
143: Log(LG_ERR, ("CONSOLE: Console already running"));
144: return -1;
145: }
146:
147: u_addrtoa(&c->addr, addrstr, sizeof(addrstr));
148: if ((c->fd = TcpGetListenPort(&c->addr, c->port, FALSE)) < 0) {
149: Log(LG_ERR, ("CONSOLE: Can't listen for connections on %s %d",
150: addrstr, c->port));
151: return -1;
152: }
153:
154: if (EventRegister(&c->event, EVENT_READ, c->fd,
155: EVENT_RECURRING, ConsoleConnect, c) < 0)
156: return -1;
157:
158: Log(LG_CONSOLE, ("CONSOLE: listening on %s %d",
159: addrstr, c->port));
160: return 0;
161: }
162:
163: /*
164: * ConsoleClose()
165: */
166:
167: int
168: ConsoleClose(Console c)
169: {
170: if (!c->fd)
171: return 0;
172: EventUnRegister(&c->event);
173: close(c->fd);
174: c->fd = 0;
175: return 0;
176: }
177:
178: /*
179: * ConsoleStat()
180: */
181:
182: int
183: ConsoleStat(Context ctx, int ac, char *av[], void *arg)
184: {
185: Console c = &gConsole;
186: ConsoleSession s;
187: ConsoleSession cs = ctx->cs;
188: char addrstr[INET6_ADDRSTRLEN];
189:
190: Printf("Configuration:\r\n");
191: Printf("\tState : %s\r\n", c->fd ? "OPENED" : "CLOSED");
192: Printf("\tIP-Address : %s\r\n", u_addrtoa(&c->addr,addrstr,sizeof(addrstr)));
193: Printf("\tPort : %d\r\n", c->port);
194:
195: RWLOCK_RDLOCK(c->lock);
196: Printf("Active sessions:\r\n");
197: SLIST_FOREACH(s, &c->sessions, next) {
198: Printf("\tUsername: %s\tFrom: %s\r\n",
199: s->user.username, u_addrtoa(&s->peer_addr,addrstr,sizeof(addrstr)));
200: }
201: RWLOCK_UNLOCK(c->lock);
202:
1.1.1.3 ! misho 203: Printf("Global options:\r\n");
! 204: OptStat(ctx, &c->options, gConfList);
1.1 misho 205: if (cs) {
206: Printf("This session options:\r\n");
1.1.1.3 ! misho 207: OptStat(ctx, &cs->options, sConfList);
1.1 misho 208: }
209: return 0;
210: }
211:
212: /*
213: * ConsoleConnect()
214: */
215:
216: static void
217: ConsoleConnect(int type, void *cookie)
218: {
219: Console c = cookie;
220: ConsoleSession cs;
221: const char *options =
222: "\xFF\xFB\x03" /* WILL Suppress Go-Ahead */
223: "\xFF\xFD\x03" /* DO Suppress Go-Ahead */
224: "\xFF\xFB\x01" /* WILL echo */
225: "\xFF\xFD\x01"; /* DO echo */
226: char addrstr[INET6_ADDRSTRLEN];
227: struct sockaddr_storage ss;
228:
229: Log(LG_CONSOLE, ("CONSOLE: Connect"));
230: cs = Malloc(MB_CONS, sizeof(*cs));
231: if ((cs->fd = TcpAcceptConnection(c->fd, &ss, FALSE)) < 0)
232: goto cleanup;
233: sockaddrtou_addr(&ss, &cs->peer_addr, &cs->peer_port);
234:
235: if (EventRegister(&cs->readEvent, EVENT_READ, cs->fd,
236: EVENT_RECURRING, ConsoleSessionReadEvent, cs) < 0)
237: goto fail;
238:
239: cs->console = c;
240: cs->close = ConsoleSessionClose;
241: cs->write = ConsoleSessionWrite;
242: cs->writev = ConsoleSessionWriteV;
243: cs->prompt = ConsoleSessionShowPrompt;
1.1.1.3 ! misho 244: if (!Enabled(&c->options, CONSOLE_AUTH)) {
! 245: cs->state = STATE_AUTHENTIC;
! 246: strcpy(cs->user.username, "root");
! 247: cs->context.priv = 2;
! 248: } else {
! 249: cs->state = STATE_USERNAME;
! 250: }
1.1 misho 251: cs->context.cs = cs;
252: RWLOCK_WRLOCK(c->lock);
253: SLIST_INSERT_HEAD(&c->sessions, cs, next);
254: RWLOCK_UNLOCK(c->lock);
255: Log(LG_CONSOLE, ("CONSOLE: Allocated new console session %p from %s",
256: cs, u_addrtoa(&cs->peer_addr,addrstr,sizeof(addrstr))));
257: cs->write(cs, "Multi-link PPP daemon for FreeBSD\r\n\r\n");
258: cs->write(cs, options);
259: cs->prompt(cs);
260: return;
261:
262: fail:
263: close(cs->fd);
264:
265: cleanup:
266: Freee(cs);
267: return;
268:
269: }
270:
271: /*
272: * StdConsoleConnect()
273: */
274:
275: Context
276: StdConsoleConnect(Console c)
277: {
278: ConsoleSession cs;
279: struct termios settings;
280:
281: cs = Malloc(MB_CONS, sizeof(*cs));
282:
283: /* Init stdin */
284: cs->fd = 0;
285:
286: /* Save original STDxxx flags */
287: gOrigFlags = fcntl(0, F_GETFL, 0);
288:
289: tcgetattr(cs->fd, &settings);
290: gOrigTermiosAttrs = settings;
291: settings.c_lflag &= (~ICANON);
292: settings.c_lflag &= (~ECHO); // don't echo the character
293: settings.c_cc[VTIME] = 0; // timeout (tenths of a second)
294: settings.c_cc[VMIN] = 0; // minimum number of characters
295: tcsetattr(cs->fd, TCSANOW, &settings);
296:
297: if (fcntl(cs->fd, F_SETFL, O_NONBLOCK) < 0) {
298: Perror("%s: fcntl", __FUNCTION__);
299: Freee(cs);
300: return(NULL);
301: }
302:
303: /* Init stdout */
304: if (fcntl(1, F_SETFL, O_NONBLOCK) < 0) {
305: Perror("%s: fcntl", __FUNCTION__);
306: Freee(cs);
307: return(NULL);
308: }
309:
310: Enable(&cs->options, CONSOLE_LOGGING);
311: cs->console = c;
312: cs->close = StdConsoleSessionClose;
313: cs->write = StdConsoleSessionWrite;
314: cs->writev = StdConsoleSessionWriteV;
315: cs->prompt = ConsoleSessionShowPrompt;
316: cs->state = STATE_AUTHENTIC;
317: cs->context.cs = cs;
318: strcpy(cs->user.username, "root");
319: cs->context.priv = 2;
320: RWLOCK_WRLOCK(c->lock);
321: SLIST_INSERT_HEAD(&c->sessions, cs, next);
322: RWLOCK_UNLOCK(c->lock);
323:
324: EventRegister(&cs->readEvent, EVENT_READ, cs->fd,
325: EVENT_RECURRING, ConsoleSessionReadEvent, cs);
326:
327: return (&cs->context);
328: }
329:
330:
331: /*
332: * ConsoleSessionClose()
333: * This function is potentially thread unsafe.
334: * To avois this locks should be used.
335: * The only unlocked place is ->readEvent,
336: * but it is actually the only place where ->close called.
337: */
338:
339: static void
340: ConsoleSessionClose(ConsoleSession cs)
341: {
342: cs->write(cs, "Console closed.\r\n");
343: RWLOCK_WRLOCK(cs->console->lock);
344: SLIST_REMOVE(&cs->console->sessions, cs, console_session, next);
345: RWLOCK_UNLOCK(cs->console->lock);
346: EventUnRegister(&cs->readEvent);
347: close(cs->fd);
348: Freee(cs);
349: return;
350: }
351:
352: /*
353: * StdConsoleSessionClose()
354: */
355:
356: static void
357: StdConsoleSessionClose(ConsoleSession cs)
358: {
359: cs->write(cs, "Console closed.\r\n");
360: EventUnRegister(&cs->readEvent);
361: /* Restore original attrs */
362: tcsetattr(cs->fd, TCSANOW, &gOrigTermiosAttrs);
363: /* Restore original STDxxx flags. */
364: if (gOrigFlags>=0)
365: fcntl(cs->fd, F_SETFL, gOrigFlags);
366: cs->close = NULL;
367: return;
368: }
369:
370: /*
371: * ConsoleSessionReadEvent()
372: */
373:
374: static void
375: ConsoleSessionReadEvent(int type, void *cookie)
376: {
377: ConsoleSession cs = cookie;
378: CmdTab cmd, tab;
379: int n, ac, ac2, i;
380: u_char c;
381: char compl[MAX_CONSOLE_LINE], line[MAX_CONSOLE_LINE];
382: char *av[MAX_CONSOLE_ARGS], *av2[MAX_CONSOLE_ARGS];
383: char *av_copy[MAX_CONSOLE_ARGS];
384: char addrstr[INET6_ADDRSTRLEN];
385:
386: while(1) {
387: if ((n = read(cs->fd, &c, 1)) <= 0) {
388: if (n < 0) {
389: if (errno == EAGAIN)
390: goto out;
391: Perror("CONSOLE: Error while reading");
392: } else {
1.1.1.2 misho 393: if (cs->fd == 0 && isatty(cs->fd))
1.1 misho 394: goto out;
395: Log(LG_ERR, ("CONSOLE: Connection closed by peer"));
396: }
397: goto abort;
398: }
399:
400: if (cs->context.lnk && cs->context.lnk->dead) {
401: UNREF(cs->context.lnk);
402: cs->context.lnk = NULL;
403: }
404: if (cs->context.bund && cs->context.bund->dead) {
405: UNREF(cs->context.bund);
406: cs->context.bund = NULL;
407: }
408: if (cs->context.rep && cs->context.rep->dead) {
409: UNREF(cs->context.rep);
410: cs->context.rep = NULL;
411: }
412:
413: /* deal with escapes, map cursors */
414: if (cs->escaped) {
415: if (cs->escaped == '[') {
416: switch(c) {
417: case 'A': /* up */
418: c = CTRL('P');
419: break;
420: case 'B': /* down */
421: c = CTRL('N');
422: break;
423: case 'C': /* right */
424: c = CTRL('F');
425: break;
426: case 'D': /* left */
427: c = CTRL('B');
428: break;
429: default:
430: c = 0;
431: }
432: cs->escaped = FALSE;
433: } else {
434: cs->escaped = c == '[' ? c : 0;
435: continue;
436: }
437: }
438:
439: switch(c) {
440: case 0:
441: break;
442: case 27: /* escape */
443: cs->escaped = TRUE;
444: break;
445: case 255: /* telnet option follows */
446: cs->telnet = TRUE;
447: break;
448: case 253: /* telnet option-code DO */
449: break;
450: case 9: /* TAB */
451: if (cs->state != STATE_AUTHENTIC)
452: break;
453: strcpy(line, cs->cmd);
454: ac = ParseLine(line, av, sizeof(av) / sizeof(*av), 1);
455: memset(compl, 0, sizeof(compl));
456: tab = gCommands;
457: for (i = 0; i < ac; i++) {
458:
459: if (FindCommand(&cs->context, tab, av[i], &cmd)) {
460: cs->write(cs, "\a");
461: goto notfound;
462: }
463: strcpy(line, cmd->name);
464: ac2 = ParseLine(line, av2, sizeof(av2) / sizeof(*av2), 1);
465: snprintf(&compl[strlen(compl)], sizeof(compl) - strlen(compl), "%s ", av2[0]);
466: FreeArgs(ac2, av2);
467: if (cmd->func != CMD_SUBMENU &&
468: (i != 0 || strcmp(compl, "help ") !=0)) {
469: i++;
470: if (i < ac) {
471: cs->write(cs, "\a");
472: for (; i < ac; i++) {
473: strcat(compl, av[i]);
474: if ((i+1) < ac)
475: strcat(compl, " ");
476: }
477: }
478: break;
479: } else if (cmd->func == CMD_SUBMENU) {
480: tab = cmd->arg;
481: }
482: }
483: for (i = 0; i < cs->cmd_len; i++)
484: cs->write(cs, "\b \b");
485: strcpy(cs->cmd, compl);
486: cs->cmd_len = strlen(cs->cmd);
487: cs->write(cs, cs->cmd);
488: notfound:
489: FreeArgs(ac, av);
490: break;
491: case CTRL('C'):
492: if (cs->telnet)
493: break;
494: cs->write(cs, "\r\n");
495: memset(cs->cmd, 0, MAX_CONSOLE_LINE);
496: cs->cmd_len = 0;
497: cs->prompt(cs);
498: cs->telnet = FALSE;
499: break;
500: case CTRL('P'): /* page up */
501: if ((cs->currhist < MAX_CONSOLE_HIST) &&
502: (cs->history[cs->currhist][0])) {
503: for (i = 0; i < cs->cmd_len; i++)
504: cs->write(cs, "\b \b");
505: memcpy(cs->cmd, cs->history[cs->currhist], MAX_CONSOLE_LINE);
506: cs->currhist++;
507: cs->cmd_len = strlen(cs->cmd);
508: cs->write(cs, cs->cmd);
509: }
510: break;
511: case CTRL('N'): /* page down */
512: if (cs->currhist > 1) {
513: for (i = 0; i < cs->cmd_len; i++)
514: cs->write(cs, "\b \b");
515: cs->currhist--;
516: memcpy(cs->cmd, cs->history[cs->currhist-1], MAX_CONSOLE_LINE);
517: cs->cmd_len = strlen(cs->cmd);
518: cs->write(cs, cs->cmd);
519: } else {
520: if (cs->cmd_len>0) {
521: if (strncmp(cs->cmd, cs->history[0], MAX_CONSOLE_LINE) != 0) {
522: for (i = MAX_CONSOLE_HIST - 1; i > 0; i--)
523: memcpy(cs->history[i], cs->history[i - 1], MAX_CONSOLE_LINE);
524: memcpy(cs->history[0], cs->cmd, MAX_CONSOLE_LINE);
525: cs->write(cs, "\r\n");
526: cs->prompt(cs);
527: } else {
528: for (i = 0; i < cs->cmd_len; i++)
529: cs->write(cs, "\b \b");
530: }
531: }
532: cs->currhist = 0;
533: memset(cs->cmd, 0, MAX_CONSOLE_LINE);
534: cs->cmd_len = 0;
535: }
536: break;
537: case CTRL('F'):
538: case CTRL('B'):
539: break;
540: case CTRL('H'):
541: case 127: /* BS */
542: if (cs->cmd_len > 0) {
543: cs->cmd_len -= 1;
544: cs->cmd[cs->cmd_len] = 0;
545: if (cs->state != STATE_PASSWORD)
546: cs->write(cs, "\b \b");
547: }
548: break;
549: case '\r':
550: case '\n':
551: case '?':
552: {
553: if (c == '?')
554: cs->write(cs, "?");
555: cs->write(cs, "\r\n");
556:
557: cs->telnet = FALSE;
558: if (cs->state == STATE_USERNAME) {
559: strlcpy(cs->user.username, cs->cmd, sizeof(cs->user.username));
560: memset(cs->cmd, 0, MAX_CONSOLE_LINE);
561: cs->cmd_len = 0;
562: cs->state = STATE_PASSWORD;
563: cs->prompt(cs);
564: break;
565: } else if (cs->state == STATE_PASSWORD) {
566: ConsoleUser u;
567:
568: RWLOCK_RDLOCK(gUsersLock);
569: u = ghash_get(gUsers, &cs->user);
570: RWLOCK_UNLOCK(gUsersLock);
571:
572: if (!u)
573: goto failed;
574:
575: if (strcmp(u->password, cs->cmd))
576: goto failed;
577:
578: cs->state = STATE_AUTHENTIC;
579: cs->user.priv = u->priv;
580: cs->context.priv = u->priv;
581: cs->write(cs, "\r\nWelcome!\r\nMpd pid %lu, version %s\r\n",
582: (u_long) gPid, gVersion);
583: goto success;
584:
585: failed:
586: cs->write(cs, "Login failed\r\n");
587: Log(LG_CONSOLE, ("CONSOLE: Failed login attempt from %s",
588: u_addrtoa(&cs->peer_addr,addrstr,sizeof(addrstr))));
589: cs->user.username[0] = 0;
590: cs->state = STATE_USERNAME;
591: success:
592: memset(cs->cmd, 0, MAX_CONSOLE_LINE);
593: cs->cmd_len = 0;
594: cs->prompt(cs);
595: break;
596: }
597:
598: memcpy(line, cs->cmd, sizeof(line));
599: ac = ParseLine(line, av, sizeof(av) / sizeof(*av), 1);
600: memcpy(av_copy, av, sizeof(av));
601: if (c != '?') {
602: Log2(LG_CONSOLE, ("[%s] CONSOLE: %s: %s",
603: cs->context.lnk ? cs->context.lnk->name :
604: (cs->context.bund? cs->context.bund->name : ""),
605: cs->user.username, cs->cmd));
606: DoCommand(&cs->context, ac, av, NULL, 0);
607: } else {
608: HelpCommand(&cs->context, ac, av, NULL);
609: }
610: FreeArgs(ac, av_copy);
611: if (cs->exit)
612: goto abort;
613: cs->prompt(cs);
614: if (c != '?') {
615: if (cs->cmd_len > 0 &&
616: strncmp(cs->cmd, cs->history[0], MAX_CONSOLE_LINE) != 0) {
617: for (i = MAX_CONSOLE_HIST - 1; i > 0; i--)
618: memcpy(cs->history[i], cs->history[i - 1], MAX_CONSOLE_LINE);
619: memcpy(cs->history[0], cs->cmd, MAX_CONSOLE_LINE);
620: }
621: cs->currhist = 0;
622: memset(cs->cmd, 0, MAX_CONSOLE_LINE);
623: cs->cmd_len = 0;
624: } else {
625: cs->write(cs, cs->cmd);
626: }
627: break;
628: }
629: /* "normal" char entered */
630: default:
631: if (cs->telnet) {
632: if (c < 251)
633: cs->telnet = FALSE;
634: break;
635: }
636:
637: if ((cs->cmd_len + 2) >= MAX_CONSOLE_LINE) {
638: cs->write(cs, "\a");
639: break;
640: }
641:
642: if (c < 32)
643: break;
644:
645: if (cs->state != STATE_PASSWORD)
646: cs->write(cs, "%c", c);
647:
648: cs->cmd[cs->cmd_len++] = c;
649: }
650: }
651:
652: abort:
653: if (cs->close) {
654: RESETREF(cs->context.lnk, NULL);
655: RESETREF(cs->context.bund, NULL);
656: RESETREF(cs->context.rep, NULL);
657: cs->close(cs);
658: }
659: out:
660: return;
661: }
662:
663: /*
664: * ConsoleSessionWrite()
665: */
666:
667: static void
668: ConsoleSessionWrite(ConsoleSession cs, const char *fmt, ...)
669: {
670: va_list vl;
671:
672: va_start(vl, fmt);
673: ConsoleSessionWriteV(cs, fmt, vl);
674: va_end(vl);
675: }
676:
677: /*
678: * ConsoleSessionWriteV()
679: */
680:
681: static void
682: ConsoleSessionWriteV(ConsoleSession cs, const char *fmt, va_list vl)
683: {
684: char *buf;
685: size_t len;
686:
687: len = vasprintf(&buf, fmt, vl);
688: write(cs->fd, buf, len);
689: free(buf);
690: }
691:
692: /*
693: * StdConsoleSessionWrite()
694: */
695:
696: static void
697: StdConsoleSessionWrite(ConsoleSession cs, const char *fmt, ...)
698: {
699: va_list vl;
700:
701: va_start(vl, fmt);
702: StdConsoleSessionWriteV(cs, fmt, vl);
703: va_end(vl);
704: }
705:
706: /*
707: * StdConsoleSessionWriteV()
708: */
709:
710: static void
711: StdConsoleSessionWriteV(ConsoleSession cs, const char *fmt, va_list vl)
712: {
713: vprintf(fmt, vl);
714: fflush(stdout);
715: }
716:
717: /*
718: * ConsoleShowPrompt()
719: */
720:
721: static void
722: ConsoleSessionShowPrompt(ConsoleSession cs)
723: {
724: switch(cs->state) {
725: case STATE_USERNAME:
726: cs->write(cs, "Username: ");
727: break;
728: case STATE_PASSWORD:
729: cs->write(cs, "Password: ");
730: break;
731: case STATE_AUTHENTIC:
732: if (cs->context.lnk)
733: cs->write(cs, "[%s] ", cs->context.lnk->name);
734: else if (cs->context.bund)
735: cs->write(cs, "[%s] ", cs->context.bund->name);
736: else if (cs->context.rep)
737: cs->write(cs, "[%s] ", cs->context.rep->name);
738: else
739: cs->write(cs, "[] ");
740: break;
741: }
742: }
743:
744:
745: /*
746: * ConsoleUserHash
747: *
748: * Fowler/Noll/Vo- hash
749: * see http://www.isthe.com/chongo/tech/comp/fnv/index.html
750: *
751: * By:
752: * chongo <Landon Curt Noll> /\oo/\
753: * http://www.isthe.com/chongo/
754: */
755:
756: static u_int32_t
757: ConsoleUserHash(struct ghash *g, const void *item)
758: {
759: ConsoleUser u = (ConsoleUser) item;
760: u_char *s = (u_char *) u->username;
761: u_int32_t hash = 0x811c9dc5;
762:
763: while (*s) {
764: hash += (hash<<1) + (hash<<4) + (hash<<7) + (hash<<8) + (hash<<24);
765: /* xor the bottom with the current octet */
766: hash ^= (u_int32_t)*s++;
767: }
768:
769: return hash;
770: }
771:
772: /*
773: * ConsoleUserHashEqual
774: */
775:
776: static int
777: ConsoleUserHashEqual(struct ghash *g, const void *item1, const void *item2)
778: {
779: ConsoleUser u1 = (ConsoleUser) item1;
780: ConsoleUser u2 = (ConsoleUser) item2;
781:
782: if (u1 && u2)
783: return (strcmp(u1->username, u2->username) == 0);
784: else
785: return 0;
786: }
787:
788: /*
789: * ConsoleSetCommand()
790: */
791:
792: static int
793: ConsoleSetCommand(Context ctx, int ac, char *av[], void *arg)
794: {
795: Console c = &gConsole;
796: ConsoleSession cs = ctx->cs;
797: int port;
798:
799: switch ((intptr_t)arg) {
800:
801: case SET_OPEN:
802: ConsoleOpen(c);
803: break;
804:
805: case SET_CLOSE:
806: ConsoleClose(c);
807: break;
808:
809: case SET_ENABLE:
1.1.1.3 ! misho 810: if (cs) {
! 811: if (strcmp(av[0], "auth") != 0)
! 812: EnableCommand(ac, av, &cs->options, sConfList);
! 813: } else
! 814: EnableCommand(ac, av, &c->options, gConfList);
1.1 misho 815: break;
816:
817: case SET_DISABLE:
1.1.1.3 ! misho 818: if (cs) {
! 819: if (strcmp(av[0], "auth") != 0)
! 820: DisableCommand(ac, av, &cs->options, sConfList);
! 821: } else
! 822: DisableCommand(ac, av, &c->options, gConfList);
1.1 misho 823: break;
824:
825: case SET_SELF:
826: if (ac < 1 || ac > 2)
827: return(-1);
828:
829: if (!ParseAddr(av[0], &c->addr, ALLOW_IPV4|ALLOW_IPV6))
830: Error("CONSOLE: Bogus IP address given %s", av[0]);
831:
832: if (ac == 2) {
833: port = strtol(av[1], NULL, 10);
834: if (port < 1 || port > 65535)
835: Error("CONSOLE: Bogus port given %s", av[1]);
836: c->port=port;
837: }
838: break;
839:
840: default:
841: return(-1);
842:
843: }
844:
845: return 0;
846: }
847:
848: /*
849: * ConsoleShutdown()
850: */
851:
852: void
853: ConsoleShutdown(Console c)
854: {
855: ConsoleSession s, tmp;
856:
857: SLIST_FOREACH_SAFE(s, &c->sessions, next, tmp) {
858: if (s->close != NULL)
859: s->close(s);
860: }
861: }
862:
863: /*
864: * UserCommand()
865: */
866:
867: int
868: UserCommand(Context ctx, int ac, char *av[], void *arg)
869: {
870: ConsoleUser u;
871:
872: if (ac < 2 || ac > 3)
873: return(-1);
874:
875: u = Malloc(MB_CONS, sizeof(*u));
876: strlcpy(u->username, av[0], sizeof(u->username));
877: strlcpy(u->password, av[1], sizeof(u->password));
878: if (ac == 3) {
879: if (!strcmp(av[2],"admin"))
880: u->priv = 2;
881: else if (!strcmp(av[2],"operator"))
882: u->priv = 1;
883: else if (!strcmp(av[2],"user"))
884: u->priv = 0;
885: else {
886: Freee(u);
887: return (-1);
888: }
889: }
890: RWLOCK_WRLOCK(gUsersLock);
891: ghash_put(gUsers, u);
892: RWLOCK_UNLOCK(gUsersLock);
893:
894: return (0);
895: }
896:
897: /*
898: * UserStat()
899: */
900:
901: int
902: UserStat(Context ctx, int ac, char *av[], void *arg)
903: {
904: struct ghash_walk walk;
905: ConsoleUser u;
906:
907: Printf("Configured users:\r\n");
908: RWLOCK_RDLOCK(gUsersLock);
909: ghash_walk_init(gUsers, &walk);
910: while ((u = ghash_walk_next(gUsers, &walk)) != NULL) {
1.1.1.3 ! misho 911: Printf("\tUsername: %-15s Priv: %s\r\n", u->username,
1.1 misho 912: ((u->priv == 2)?"admin":((u->priv == 1)?"operator":"user")));
913: }
914: RWLOCK_UNLOCK(gUsersLock);
915:
916: return 0;
917: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>