Annotation of embedaddon/mpd/src/console.c, revision 1.1.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>