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