Annotation of embedaddon/mpd/src/console.c, revision 1.1.1.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>