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