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

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