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