Annotation of embedaddon/mpd/src/console.c, revision 1.1
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 {
! 379: if (cs->fd == 0)
! 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>