File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / console.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:56:12 2016 UTC (7 years, 8 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p1_cross, v5_8p1, v5_8, HEAD
mpd 5.8

    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_AUTH,		"auth"		},
   91:     { 0,	0,			NULL		},
   92:   };
   93: 
   94:   static const struct confinfo	sConfList[] = {
   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;
  115:   Enable(&c->options, CONSOLE_AUTH);
  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: 
  203:   Printf("Global options:\r\n");
  204:   OptStat(ctx, &c->options, gConfList);
  205:   if (cs) {
  206:     Printf("This session options:\r\n");
  207:     OptStat(ctx, &cs->options, sConfList);
  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;
  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:   }
  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 {
  393:         if (cs->fd == 0 && isatty(cs->fd))
  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:
  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);
  815:       break;
  816: 
  817:     case SET_DISABLE:
  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);
  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) {
  911: 	Printf("\tUsername: %-15s Priv: %s\r\n", u->username,
  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>