11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo /* 221991Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 231991Sheppo * Use is subject to license terms. 241991Sheppo */ 251991Sheppo 261991Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 271991Sheppo 281991Sheppo /* 291991Sheppo * Vntsd handles two types of special commands, one is telnet 301991Sheppo * commands and another is vntsd special commands. 311991Sheppo * telnet commands supported are: 321991Sheppo * WILL 331991Sheppo * WONT 341991Sheppo * DO 351991Sheppo * DONT 361991Sheppo * TEL_ECHO 371991Sheppo * SUPRESS 381991Sheppo * LINEMODE 391991Sheppo * BRK 401991Sheppo * AYT 411991Sheppo * HT 421991Sheppo * 431991Sheppo * Vntsd special commands are: 44*2109Slm66018 * Send break (~#) 45*2109Slm66018 * Exit (~.) 46*2109Slm66018 * Force write access (~w) 47*2109Slm66018 * Console next (~n) 48*2109Slm66018 * Console previous (~p) 49*2109Slm66018 * Help (~?) 501991Sheppo */ 511991Sheppo 521991Sheppo #include <stdio.h> 531991Sheppo #include <stdlib.h> 541991Sheppo #include <string.h> 551991Sheppo #include <unistd.h> 561991Sheppo #include <sys/types.h> 571991Sheppo #include <sys/socket.h> 581991Sheppo #include <netinet/in.h> 591991Sheppo #include <thread.h> 601991Sheppo #include <ctype.h> 611991Sheppo #include <sys/termio.h> 621991Sheppo #include <libintl.h> 631991Sheppo #include <syslog.h> 641991Sheppo #include "vntsd.h" 651991Sheppo #include "chars.h" 661991Sheppo 671991Sheppo char vntsd_eol[] = { CR, LF, 0}; 681991Sheppo 691991Sheppo typedef int (*e_func_t)(vntsd_client_t *clientp); 701991Sheppo /* structure for daemon special cmd */ 711991Sheppo typedef struct { 721991Sheppo char e_char; /* char to match on */ 731991Sheppo char *e_help; /* help string */ 741991Sheppo e_func_t e_func; /* command */ 751991Sheppo } esctable_t; 761991Sheppo 771991Sheppo /* genbrk() - send a break to vcc driver */ 781991Sheppo static int 791991Sheppo genbrk(vntsd_client_t *clientp) 801991Sheppo { 811991Sheppo 821991Sheppo vntsd_cons_t *consp; 831991Sheppo 841991Sheppo assert(clientp); 851991Sheppo assert(clientp->cons); 861991Sheppo 871991Sheppo consp = clientp->cons; 881991Sheppo D1(stderr, "t@%d genbrk fd=%d sockfd %d\n", thr_self(), 891991Sheppo consp->vcc_fd, clientp->sockfd); 901991Sheppo 911991Sheppo assert(consp->clientpq != NULL); 921991Sheppo if (consp->clientpq->handle != clientp) { 931991Sheppo /* reader */ 941991Sheppo return (vntsd_write_line(clientp, 951991Sheppo gettext(VNTSD_NO_WRITE_ACCESS_MSG))); 961991Sheppo } 971991Sheppo 981991Sheppo /* writer */ 991991Sheppo if (ioctl(consp->vcc_fd, TCSBRK, NULL)) { 1001991Sheppo return (VNTSD_ERR_VCC_IOCTL); 1011991Sheppo } 1021991Sheppo 1031991Sheppo return (VNTSD_STATUS_CONTINUE); 1041991Sheppo } 1051991Sheppo 1061991Sheppo /* 1071991Sheppo * console_forward() - cycle client to the next console 1081991Sheppo * in the group queue. 1091991Sheppo */ 1101991Sheppo static int 1111991Sheppo console_forward(void) 1121991Sheppo { 1131991Sheppo return (VNTSD_STATUS_MOV_CONS_FORWARD); 1141991Sheppo } 1151991Sheppo 1161991Sheppo /* 1171991Sheppo * console_backward() - cycle client to the previous 1181991Sheppo * console in the group queue. 1191991Sheppo */ 1201991Sheppo static int 1211991Sheppo console_backward(void) 1221991Sheppo { 1231991Sheppo return (VNTSD_STATUS_MOV_CONS_BACKWARD); 1241991Sheppo } 1251991Sheppo 1261991Sheppo /* acquire_write() - acquire write access to a console. */ 1271991Sheppo static int 1281991Sheppo acquire_write(vntsd_client_t *clientp) 1291991Sheppo { 1301991Sheppo int rv; 1311991Sheppo int yes_no = 1; 1321991Sheppo vntsd_cons_t *consp; 1331991Sheppo 1341991Sheppo assert(clientp); 1351991Sheppo consp = clientp->cons; 1361991Sheppo assert(consp); 1371991Sheppo 1381991Sheppo if (consp->clientpq->handle == clientp) { 1391991Sheppo /* client is a writer */ 1401991Sheppo if ((rv = vntsd_write_line(clientp, 1411991Sheppo gettext("You have write permission"))) != 1421991Sheppo VNTSD_SUCCESS) { 1431991Sheppo return (rv); 1441991Sheppo 1451991Sheppo } 1461991Sheppo return (VNTSD_STATUS_CONTINUE); 1471991Sheppo } 1481991Sheppo 1491991Sheppo /* message to client */ 1501991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 1511991Sheppo != VNTSD_SUCCESS) { 1521991Sheppo return (rv); 1531991Sheppo } 1541991Sheppo 1551991Sheppo /* 1561991Sheppo * TRANSLATION_NOTE 1571991Sheppo * The following string should be formatted to fit on multiple lines 1581991Sheppo * assuming a line width of at most 78 characters. There must be no 1591991Sheppo * trailing newline. 1601991Sheppo */ 1611991Sheppo if ((rv = vntsd_write_lines(clientp, 1621991Sheppo gettext("Warning: another user currently " 1631991Sheppo "has write permission\nto this console and forcibly removing " 1641991Sheppo "him/her will terminate\nany current write action and all work " 1651991Sheppo "will be lost."))) != VNTSD_SUCCESS) { 1661991Sheppo return (rv); 1671991Sheppo } 1681991Sheppo 1691991Sheppo /* get client yes no */ 1701991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, 1711991Sheppo VNTSD_EOL_LEN)) != VNTSD_SUCCESS) { 1721991Sheppo return (rv); 1731991Sheppo } 1741991Sheppo 1751991Sheppo if ((rv = vntsd_get_yes_no(clientp, 1761991Sheppo gettext("Would you like to continue?"), 1771991Sheppo &yes_no)) != VNTSD_SUCCESS) { 1781991Sheppo return (rv); 1791991Sheppo } 1801991Sheppo 1811991Sheppo if (yes_no == B_FALSE) { 1821991Sheppo /* client change mind no need to acquire write access */ 1831991Sheppo return (VNTSD_STATUS_CONTINUE); 1841991Sheppo } 1851991Sheppo 1861991Sheppo return (VNTSD_STATUS_ACQUIRE_WRITER); 1871991Sheppo } 1881991Sheppo 1891991Sheppo /* client_exit() - disconnect client from the console. */ 1901991Sheppo static int 1911991Sheppo client_exit(void) 1921991Sheppo { 1931991Sheppo return (VNTSD_STATUS_RESELECT_CONS); 1941991Sheppo } 1951991Sheppo 1961991Sheppo static int daemon_cmd_help(vntsd_client_t *clientp); 1971991Sheppo 1981991Sheppo /* table for daemon commands */ 1991991Sheppo 2001991Sheppo static esctable_t etable[] = { 2011991Sheppo 2021991Sheppo /* send a break to vcc */ 203*2109Slm66018 {'#', "Send break", genbrk}, 2041991Sheppo 2051991Sheppo /* exit */ 206*2109Slm66018 {'.', "Exit from this console", (e_func_t)client_exit}, 2071991Sheppo 2081991Sheppo /* acquire write access */ 209*2109Slm66018 {'w', "Force write access", acquire_write}, 2101991Sheppo 2111991Sheppo /* connect to next console in queue */ 212*2109Slm66018 {'n', "Console next", (e_func_t)console_forward}, 2131991Sheppo 2141991Sheppo /* connect to previous console in queue */ 215*2109Slm66018 {'p', "Console previous", (e_func_t)console_backward}, 2161991Sheppo 2171991Sheppo /* help must be next to last */ 218*2109Slm66018 {'?', "Help", daemon_cmd_help}, 2191991Sheppo 2201991Sheppo /* table terminator */ 2211991Sheppo {0, 0, 0} 2221991Sheppo }; 2231991Sheppo 2241991Sheppo void 2251991Sheppo vntsd_init_esctable_msgs(void) 2261991Sheppo { 2271991Sheppo esctable_t *p; 2281991Sheppo 2291991Sheppo for (p = etable; p->e_char != '\0'; p++) { 2301991Sheppo p->e_help = gettext(p->e_help); 2311991Sheppo } 2321991Sheppo } 2331991Sheppo 2341991Sheppo /* daemon_cmd_help() - print help. */ 2351991Sheppo static int 2361991Sheppo daemon_cmd_help(vntsd_client_t *clientp) 2371991Sheppo { 2381991Sheppo esctable_t *p; 2391991Sheppo int rv; 2401991Sheppo char buf[VNTSD_LINE_LEN]; 2411991Sheppo 2421991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, 2431991Sheppo VNTSD_EOL_LEN)) != VNTSD_SUCCESS) { 2441991Sheppo return (rv); 2451991Sheppo } 2461991Sheppo 2471991Sheppo /* 2481991Sheppo * TRANSLATION_NOTE 2491991Sheppo * VNTSD is the name of the VNTS daemon and should not be translated. 2501991Sheppo */ 2511991Sheppo if ((rv = vntsd_write_line(clientp, gettext("VNTSD commands"))) != 2521991Sheppo VNTSD_SUCCESS) { 2531991Sheppo return (rv); 2541991Sheppo } 2551991Sheppo 2561991Sheppo for (p = etable; p->e_char; p++) { 2571991Sheppo (void) snprintf(buf, sizeof (buf), 2581991Sheppo "~%c --%s", p->e_char, p->e_help); 2591991Sheppo 2601991Sheppo if ((rv = vntsd_write_line(clientp, buf)) != VNTSD_SUCCESS) { 2611991Sheppo return (rv); 2621991Sheppo } 2631991Sheppo } 2641991Sheppo 2651991Sheppo return (VNTSD_STATUS_CONTINUE); 2661991Sheppo } 2671991Sheppo 2681991Sheppo /* exit from daemon command */ 2691991Sheppo static int 2701991Sheppo exit_daemon_cmd(vntsd_client_t *clientp, int rv) 2711991Sheppo { 2721991Sheppo (void) mutex_lock(&clientp->lock); 2731991Sheppo clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD; 2741991Sheppo (void) mutex_unlock(&clientp->lock); 2751991Sheppo return (rv); 2761991Sheppo } 2771991Sheppo 2781991Sheppo /* vntsd_process_daemon_cmd() - special commands */ 2791991Sheppo int 2801991Sheppo vntsd_process_daemon_cmd(vntsd_client_t *clientp, char c) 2811991Sheppo { 2821991Sheppo esctable_t *p; 2831991Sheppo int rv; 2841991Sheppo 2851991Sheppo if (c != VNTSD_DAEMON_CMD) { 2861991Sheppo /* not a daemon command */ 2871991Sheppo return (VNTSD_SUCCESS); 2881991Sheppo } 2891991Sheppo 2901991Sheppo if (clientp->status & VNTSD_CLIENT_DISABLE_DAEMON_CMD) { 2911991Sheppo return (VNTSD_STATUS_CONTINUE); 2921991Sheppo } 2931991Sheppo 2941991Sheppo /* no reentry to process_daemon_cmd */ 2951991Sheppo (void) mutex_lock(&clientp->lock); 2961991Sheppo clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD; 2971991Sheppo (void) mutex_unlock(&clientp->lock); 2981991Sheppo 2991991Sheppo D3(stderr, "t@%d process_daemon_cmd %d %d \n", thr_self(), 3001991Sheppo clientp->cons->vcc_fd, clientp->sockfd); 3011991Sheppo 3021991Sheppo /* read in command */ 3031991Sheppo if ((rv = vntsd_read_char(clientp, &c)) != VNTSD_SUCCESS) { 3041991Sheppo return (exit_daemon_cmd(clientp, rv)); 3051991Sheppo } 3061991Sheppo 3071991Sheppo for (p = etable; p->e_char; p++) { 3081991Sheppo if (p->e_char == c) { 3091991Sheppo /* found match */ 3101991Sheppo assert(p->e_func); 3111991Sheppo rv = (*p->e_func)(clientp); 3121991Sheppo return (exit_daemon_cmd(clientp, rv)); 3131991Sheppo } 3141991Sheppo } 3151991Sheppo 3161991Sheppo /* no match, print out the help */ 3171991Sheppo p--; 3181991Sheppo assert(p->e_char == '?'); 3191991Sheppo rv = (*p->e_func)(clientp); 3201991Sheppo 3211991Sheppo return (exit_daemon_cmd(clientp, rv)); 3221991Sheppo 3231991Sheppo } 3241991Sheppo 3251991Sheppo /* vntsd_set_telnet_options() - change telnet client to character mode. */ 3261991Sheppo int 3271991Sheppo vntsd_set_telnet_options(int fd) 3281991Sheppo { 3291991Sheppo /* set client telnet options */ 3301991Sheppo uint8_t buf[] = {IAC, DONT, LINEMODE, IAC, WILL, SUPRESS, IAC, WILL, 3311991Sheppo TEL_ECHO, IAC, DONT, TERM_TYPE, IAC, DONT, TERM_SP, 3321991Sheppo IAC, DONT, STATUS, IAC, DONT, FC, IAC, DONT, TM, IAC, DONT, ENV, 3331991Sheppo IAC, DONT, WIN_SIZE}; 3341991Sheppo 3351991Sheppo return (vntsd_write_fd(fd, (char *)buf, 30)); 3361991Sheppo } 3371991Sheppo 3381991Sheppo /* vntsd_telnet_cmd() process telnet commands */ 3391991Sheppo int 3401991Sheppo vntsd_telnet_cmd(vntsd_client_t *clientp, char c) 3411991Sheppo { 3421991Sheppo uint8_t buf[4]; 3431991Sheppo char cmd; 3441991Sheppo int rv = VNTSD_STATUS_CONTINUE; 3451991Sheppo 3461991Sheppo bzero(buf, 4); 3471991Sheppo 3481991Sheppo if ((uint8_t)c != IAC) { 3491991Sheppo /* not telnet cmd */ 3501991Sheppo return (VNTSD_SUCCESS); 3511991Sheppo } 3521991Sheppo 3531991Sheppo if ((rv = vntsd_read_char(clientp, &cmd)) != VNTSD_SUCCESS) { 3541991Sheppo return (rv); 3551991Sheppo } 3561991Sheppo 3571991Sheppo if ((rv = vntsd_read_char(clientp, &c)) != VNTSD_SUCCESS) { 3581991Sheppo return (rv); 3591991Sheppo } 3601991Sheppo 3611991Sheppo 3621991Sheppo switch ((uint8_t)cmd) { 3631991Sheppo 3641991Sheppo case WILL: 3651991Sheppo 3661991Sheppo switch ((uint8_t)c) { 3671991Sheppo case TEL_ECHO: 3681991Sheppo case SUPRESS: 3691991Sheppo case LINEMODE: 3701991Sheppo break; 3711991Sheppo default: 3721991Sheppo syslog(LOG_ERR, "not support telnet WILL %x\n", c); 3731991Sheppo break; 3741991Sheppo } 3751991Sheppo break; 3761991Sheppo 3771991Sheppo case WONT: 3781991Sheppo 3791991Sheppo switch ((uint8_t)c) { 3801991Sheppo case TEL_ECHO: 3811991Sheppo case SUPRESS: 3821991Sheppo case LINEMODE: 3831991Sheppo default: 3841991Sheppo syslog(LOG_ERR, "not support telnet WONT %x\n", c); 3851991Sheppo break; 3861991Sheppo } 3871991Sheppo break; 3881991Sheppo 3891991Sheppo case DO: 3901991Sheppo case DONT: 3911991Sheppo 3921991Sheppo buf[0] = IAC; 3931991Sheppo buf[1] = WILL; 3941991Sheppo buf[2] = c; 3951991Sheppo rv = vntsd_write_client(clientp, (char *)buf, 3); 3961991Sheppo 3971991Sheppo break; 3981991Sheppo 3991991Sheppo case BRK: 4001991Sheppo 4011991Sheppo /* send break to vcc */ 4021991Sheppo rv = genbrk(clientp); 4031991Sheppo break; 4041991Sheppo 4051991Sheppo case IP: 4061991Sheppo 4071991Sheppo break; 4081991Sheppo 4091991Sheppo case AYT: 4101991Sheppo 4111991Sheppo rv = vntsd_write_client(clientp, &c, 1); 4121991Sheppo break; 4131991Sheppo 4141991Sheppo case HT: 4151991Sheppo return (VNTSD_STATUS_CONTINUE); 4161991Sheppo 4171991Sheppo default: 4181991Sheppo syslog(LOG_ERR, "not support telnet ctrl %x\n", c); 4191991Sheppo break; 4201991Sheppo } 4211991Sheppo 4221991Sheppo if (rv == VNTSD_SUCCESS) { 4231991Sheppo return (VNTSD_STATUS_CONTINUE); 4241991Sheppo } else { 4251991Sheppo return (rv); 4261991Sheppo } 4271991Sheppo } 4281991Sheppo 4291991Sheppo 4301991Sheppo /* 4311991Sheppo * vntsd_ctrl_cmd() - control keys 4321991Sheppo * read and write suspend are supported. 4331991Sheppo */ 4341991Sheppo int 4351991Sheppo vntsd_ctrl_cmd(vntsd_client_t *clientp, char c) 4361991Sheppo { 4371991Sheppo int cmd; 4381991Sheppo 4391991Sheppo D3(stderr, "t@%d vntsd_ctrl_cmd%d %d\n", thr_self(), 4401991Sheppo clientp->cons->vcc_fd, clientp->sockfd); 4411991Sheppo 4421991Sheppo if ((c != START) && (c != STOP)) { 4431991Sheppo /* not a supported control command */ 4441991Sheppo return (VNTSD_SUCCESS); 4451991Sheppo } 4461991Sheppo 4471991Sheppo if (c == START) { 4481991Sheppo 4491991Sheppo D3(stderr, "t@%d client restart\n", thr_self()); 4501991Sheppo 4511991Sheppo /* send resume read */ 4521991Sheppo cmd = 1; 4531991Sheppo 4541991Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 4551991Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 4561991Sheppo } 4571991Sheppo 4581991Sheppo /* send resume write */ 4591991Sheppo cmd = 3; 4601991Sheppo 4611991Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 4621991Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 4631991Sheppo } 4641991Sheppo } 4651991Sheppo 4661991Sheppo if (c == STOP) { 4671991Sheppo D3(stderr, "t@%d client suspend\n", thr_self()); 4681991Sheppo 4691991Sheppo /* send suspend read */ 4701991Sheppo cmd = 0; 4711991Sheppo 4721991Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 4731991Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 4741991Sheppo } 4751991Sheppo 4761991Sheppo /* send suspend write */ 4771991Sheppo cmd = 2; 4781991Sheppo 4791991Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 4801991Sheppo perror("ioctl TCXONC"); 4811991Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 4821991Sheppo } 4831991Sheppo } 4841991Sheppo 4851991Sheppo return (VNTSD_STATUS_CONTINUE); 4861991Sheppo } 487