File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / console.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:32:47 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    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>