1*1991Sheppo /* 2*1991Sheppo * CDDL HEADER START 3*1991Sheppo * 4*1991Sheppo * The contents of this file are subject to the terms of the 5*1991Sheppo * Common Development and Distribution License (the "License"). 6*1991Sheppo * You may not use this file except in compliance with the License. 7*1991Sheppo * 8*1991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1991Sheppo * or http://www.opensolaris.org/os/licensing. 10*1991Sheppo * See the License for the specific language governing permissions 11*1991Sheppo * and limitations under the License. 12*1991Sheppo * 13*1991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 14*1991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1991Sheppo * If applicable, add the following below this CDDL HEADER, with the 16*1991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 17*1991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 18*1991Sheppo * 19*1991Sheppo * CDDL HEADER END 20*1991Sheppo */ 21*1991Sheppo /* 22*1991Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*1991Sheppo * Use is subject to license terms. 24*1991Sheppo */ 25*1991Sheppo 26*1991Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 27*1991Sheppo 28*1991Sheppo /* 29*1991Sheppo * Vntsd handles two types of special commands, one is telnet 30*1991Sheppo * commands and another is vntsd special commands. 31*1991Sheppo * telnet commands supported are: 32*1991Sheppo * WILL 33*1991Sheppo * WONT 34*1991Sheppo * DO 35*1991Sheppo * DONT 36*1991Sheppo * TEL_ECHO 37*1991Sheppo * SUPRESS 38*1991Sheppo * LINEMODE 39*1991Sheppo * BRK 40*1991Sheppo * AYT 41*1991Sheppo * HT 42*1991Sheppo * 43*1991Sheppo * Vntsd special commands are: 44*1991Sheppo * send break (~#) 45*1991Sheppo * exit (~.) 46*1991Sheppo * force write access (~w) 47*1991Sheppo * cycle console down (~n) 48*1991Sheppo * cycle console up (~p) 49*1991Sheppo * help (~?) 50*1991Sheppo */ 51*1991Sheppo 52*1991Sheppo #include <stdio.h> 53*1991Sheppo #include <stdlib.h> 54*1991Sheppo #include <string.h> 55*1991Sheppo #include <unistd.h> 56*1991Sheppo #include <sys/types.h> 57*1991Sheppo #include <sys/socket.h> 58*1991Sheppo #include <netinet/in.h> 59*1991Sheppo #include <thread.h> 60*1991Sheppo #include <ctype.h> 61*1991Sheppo #include <sys/termio.h> 62*1991Sheppo #include <libintl.h> 63*1991Sheppo #include <syslog.h> 64*1991Sheppo #include "vntsd.h" 65*1991Sheppo #include "chars.h" 66*1991Sheppo 67*1991Sheppo char vntsd_eol[] = { CR, LF, 0}; 68*1991Sheppo 69*1991Sheppo typedef int (*e_func_t)(vntsd_client_t *clientp); 70*1991Sheppo /* structure for daemon special cmd */ 71*1991Sheppo typedef struct { 72*1991Sheppo char e_char; /* char to match on */ 73*1991Sheppo char *e_help; /* help string */ 74*1991Sheppo e_func_t e_func; /* command */ 75*1991Sheppo } esctable_t; 76*1991Sheppo 77*1991Sheppo /* genbrk() - send a break to vcc driver */ 78*1991Sheppo static int 79*1991Sheppo genbrk(vntsd_client_t *clientp) 80*1991Sheppo { 81*1991Sheppo 82*1991Sheppo vntsd_cons_t *consp; 83*1991Sheppo 84*1991Sheppo assert(clientp); 85*1991Sheppo assert(clientp->cons); 86*1991Sheppo 87*1991Sheppo consp = clientp->cons; 88*1991Sheppo D1(stderr, "t@%d genbrk fd=%d sockfd %d\n", thr_self(), 89*1991Sheppo consp->vcc_fd, clientp->sockfd); 90*1991Sheppo 91*1991Sheppo assert(consp->clientpq != NULL); 92*1991Sheppo if (consp->clientpq->handle != clientp) { 93*1991Sheppo /* reader */ 94*1991Sheppo return (vntsd_write_line(clientp, 95*1991Sheppo gettext(VNTSD_NO_WRITE_ACCESS_MSG))); 96*1991Sheppo } 97*1991Sheppo 98*1991Sheppo /* writer */ 99*1991Sheppo if (ioctl(consp->vcc_fd, TCSBRK, NULL)) { 100*1991Sheppo return (VNTSD_ERR_VCC_IOCTL); 101*1991Sheppo } 102*1991Sheppo 103*1991Sheppo return (VNTSD_STATUS_CONTINUE); 104*1991Sheppo } 105*1991Sheppo 106*1991Sheppo /* 107*1991Sheppo * console_forward() - cycle client to the next console 108*1991Sheppo * in the group queue. 109*1991Sheppo */ 110*1991Sheppo static int 111*1991Sheppo console_forward(void) 112*1991Sheppo { 113*1991Sheppo return (VNTSD_STATUS_MOV_CONS_FORWARD); 114*1991Sheppo } 115*1991Sheppo 116*1991Sheppo /* 117*1991Sheppo * console_backward() - cycle client to the previous 118*1991Sheppo * console in the group queue. 119*1991Sheppo */ 120*1991Sheppo static int 121*1991Sheppo console_backward(void) 122*1991Sheppo { 123*1991Sheppo return (VNTSD_STATUS_MOV_CONS_BACKWARD); 124*1991Sheppo } 125*1991Sheppo 126*1991Sheppo /* acquire_write() - acquire write access to a console. */ 127*1991Sheppo static int 128*1991Sheppo acquire_write(vntsd_client_t *clientp) 129*1991Sheppo { 130*1991Sheppo int rv; 131*1991Sheppo int yes_no = 1; 132*1991Sheppo vntsd_cons_t *consp; 133*1991Sheppo 134*1991Sheppo assert(clientp); 135*1991Sheppo consp = clientp->cons; 136*1991Sheppo assert(consp); 137*1991Sheppo 138*1991Sheppo if (consp->clientpq->handle == clientp) { 139*1991Sheppo /* client is a writer */ 140*1991Sheppo if ((rv = vntsd_write_line(clientp, 141*1991Sheppo gettext("You have write permission"))) != 142*1991Sheppo VNTSD_SUCCESS) { 143*1991Sheppo return (rv); 144*1991Sheppo 145*1991Sheppo } 146*1991Sheppo return (VNTSD_STATUS_CONTINUE); 147*1991Sheppo } 148*1991Sheppo 149*1991Sheppo /* message to client */ 150*1991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 151*1991Sheppo != VNTSD_SUCCESS) { 152*1991Sheppo return (rv); 153*1991Sheppo } 154*1991Sheppo 155*1991Sheppo /* 156*1991Sheppo * TRANSLATION_NOTE 157*1991Sheppo * The following string should be formatted to fit on multiple lines 158*1991Sheppo * assuming a line width of at most 78 characters. There must be no 159*1991Sheppo * trailing newline. 160*1991Sheppo */ 161*1991Sheppo if ((rv = vntsd_write_lines(clientp, 162*1991Sheppo gettext("Warning: another user currently " 163*1991Sheppo "has write permission\nto this console and forcibly removing " 164*1991Sheppo "him/her will terminate\nany current write action and all work " 165*1991Sheppo "will be lost."))) != VNTSD_SUCCESS) { 166*1991Sheppo return (rv); 167*1991Sheppo } 168*1991Sheppo 169*1991Sheppo /* get client yes no */ 170*1991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, 171*1991Sheppo VNTSD_EOL_LEN)) != VNTSD_SUCCESS) { 172*1991Sheppo return (rv); 173*1991Sheppo } 174*1991Sheppo 175*1991Sheppo if ((rv = vntsd_get_yes_no(clientp, 176*1991Sheppo gettext("Would you like to continue?"), 177*1991Sheppo &yes_no)) != VNTSD_SUCCESS) { 178*1991Sheppo return (rv); 179*1991Sheppo } 180*1991Sheppo 181*1991Sheppo if (yes_no == B_FALSE) { 182*1991Sheppo /* client change mind no need to acquire write access */ 183*1991Sheppo return (VNTSD_STATUS_CONTINUE); 184*1991Sheppo } 185*1991Sheppo 186*1991Sheppo return (VNTSD_STATUS_ACQUIRE_WRITER); 187*1991Sheppo } 188*1991Sheppo 189*1991Sheppo /* client_exit() - disconnect client from the console. */ 190*1991Sheppo static int 191*1991Sheppo client_exit(void) 192*1991Sheppo { 193*1991Sheppo return (VNTSD_STATUS_RESELECT_CONS); 194*1991Sheppo } 195*1991Sheppo 196*1991Sheppo static int daemon_cmd_help(vntsd_client_t *clientp); 197*1991Sheppo 198*1991Sheppo /* table for daemon commands */ 199*1991Sheppo 200*1991Sheppo static esctable_t etable[] = { 201*1991Sheppo 202*1991Sheppo /* send a break to vcc */ 203*1991Sheppo {'#', "send break", genbrk}, 204*1991Sheppo 205*1991Sheppo /* exit */ 206*1991Sheppo {'.', "exit from this console", (e_func_t)client_exit}, 207*1991Sheppo 208*1991Sheppo /* acquire write access */ 209*1991Sheppo {'w', "force write access", acquire_write}, 210*1991Sheppo 211*1991Sheppo /* connect to next console in queue */ 212*1991Sheppo {'n', "console down", (e_func_t)console_forward}, 213*1991Sheppo 214*1991Sheppo /* connect to previous console in queue */ 215*1991Sheppo {'p', "console up", (e_func_t)console_backward}, 216*1991Sheppo 217*1991Sheppo /* help must be next to last */ 218*1991Sheppo {'?', "_", daemon_cmd_help}, 219*1991Sheppo 220*1991Sheppo /* table terminator */ 221*1991Sheppo {0, 0, 0} 222*1991Sheppo }; 223*1991Sheppo 224*1991Sheppo void 225*1991Sheppo vntsd_init_esctable_msgs(void) 226*1991Sheppo { 227*1991Sheppo esctable_t *p; 228*1991Sheppo 229*1991Sheppo for (p = etable; p->e_char != '\0'; p++) { 230*1991Sheppo p->e_help = gettext(p->e_help); 231*1991Sheppo } 232*1991Sheppo } 233*1991Sheppo 234*1991Sheppo /* daemon_cmd_help() - print help. */ 235*1991Sheppo static int 236*1991Sheppo daemon_cmd_help(vntsd_client_t *clientp) 237*1991Sheppo { 238*1991Sheppo esctable_t *p; 239*1991Sheppo int rv; 240*1991Sheppo char buf[VNTSD_LINE_LEN]; 241*1991Sheppo 242*1991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, 243*1991Sheppo VNTSD_EOL_LEN)) != VNTSD_SUCCESS) { 244*1991Sheppo return (rv); 245*1991Sheppo } 246*1991Sheppo 247*1991Sheppo /* 248*1991Sheppo * TRANSLATION_NOTE 249*1991Sheppo * VNTSD is the name of the VNTS daemon and should not be translated. 250*1991Sheppo */ 251*1991Sheppo if ((rv = vntsd_write_line(clientp, gettext("VNTSD commands"))) != 252*1991Sheppo VNTSD_SUCCESS) { 253*1991Sheppo return (rv); 254*1991Sheppo } 255*1991Sheppo 256*1991Sheppo for (p = etable; p->e_char; p++) { 257*1991Sheppo (void) snprintf(buf, sizeof (buf), 258*1991Sheppo "~%c --%s", p->e_char, p->e_help); 259*1991Sheppo 260*1991Sheppo if ((rv = vntsd_write_line(clientp, buf)) != VNTSD_SUCCESS) { 261*1991Sheppo return (rv); 262*1991Sheppo } 263*1991Sheppo } 264*1991Sheppo 265*1991Sheppo return (VNTSD_STATUS_CONTINUE); 266*1991Sheppo } 267*1991Sheppo 268*1991Sheppo /* exit from daemon command */ 269*1991Sheppo static int 270*1991Sheppo exit_daemon_cmd(vntsd_client_t *clientp, int rv) 271*1991Sheppo { 272*1991Sheppo (void) mutex_lock(&clientp->lock); 273*1991Sheppo clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD; 274*1991Sheppo (void) mutex_unlock(&clientp->lock); 275*1991Sheppo return (rv); 276*1991Sheppo } 277*1991Sheppo 278*1991Sheppo /* vntsd_process_daemon_cmd() - special commands */ 279*1991Sheppo int 280*1991Sheppo vntsd_process_daemon_cmd(vntsd_client_t *clientp, char c) 281*1991Sheppo { 282*1991Sheppo esctable_t *p; 283*1991Sheppo int rv; 284*1991Sheppo 285*1991Sheppo if (c != VNTSD_DAEMON_CMD) { 286*1991Sheppo /* not a daemon command */ 287*1991Sheppo return (VNTSD_SUCCESS); 288*1991Sheppo } 289*1991Sheppo 290*1991Sheppo if (clientp->status & VNTSD_CLIENT_DISABLE_DAEMON_CMD) { 291*1991Sheppo return (VNTSD_STATUS_CONTINUE); 292*1991Sheppo } 293*1991Sheppo 294*1991Sheppo /* no reentry to process_daemon_cmd */ 295*1991Sheppo (void) mutex_lock(&clientp->lock); 296*1991Sheppo clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD; 297*1991Sheppo (void) mutex_unlock(&clientp->lock); 298*1991Sheppo 299*1991Sheppo D3(stderr, "t@%d process_daemon_cmd %d %d \n", thr_self(), 300*1991Sheppo clientp->cons->vcc_fd, clientp->sockfd); 301*1991Sheppo 302*1991Sheppo /* read in command */ 303*1991Sheppo if ((rv = vntsd_read_char(clientp, &c)) != VNTSD_SUCCESS) { 304*1991Sheppo return (exit_daemon_cmd(clientp, rv)); 305*1991Sheppo } 306*1991Sheppo 307*1991Sheppo for (p = etable; p->e_char; p++) { 308*1991Sheppo if (p->e_char == c) { 309*1991Sheppo /* found match */ 310*1991Sheppo assert(p->e_func); 311*1991Sheppo rv = (*p->e_func)(clientp); 312*1991Sheppo return (exit_daemon_cmd(clientp, rv)); 313*1991Sheppo } 314*1991Sheppo } 315*1991Sheppo 316*1991Sheppo /* no match, print out the help */ 317*1991Sheppo p--; 318*1991Sheppo assert(p->e_char == '?'); 319*1991Sheppo rv = (*p->e_func)(clientp); 320*1991Sheppo 321*1991Sheppo return (exit_daemon_cmd(clientp, rv)); 322*1991Sheppo 323*1991Sheppo } 324*1991Sheppo 325*1991Sheppo /* vntsd_set_telnet_options() - change telnet client to character mode. */ 326*1991Sheppo int 327*1991Sheppo vntsd_set_telnet_options(int fd) 328*1991Sheppo { 329*1991Sheppo /* set client telnet options */ 330*1991Sheppo uint8_t buf[] = {IAC, DONT, LINEMODE, IAC, WILL, SUPRESS, IAC, WILL, 331*1991Sheppo TEL_ECHO, IAC, DONT, TERM_TYPE, IAC, DONT, TERM_SP, 332*1991Sheppo IAC, DONT, STATUS, IAC, DONT, FC, IAC, DONT, TM, IAC, DONT, ENV, 333*1991Sheppo IAC, DONT, WIN_SIZE}; 334*1991Sheppo 335*1991Sheppo return (vntsd_write_fd(fd, (char *)buf, 30)); 336*1991Sheppo } 337*1991Sheppo 338*1991Sheppo /* vntsd_telnet_cmd() process telnet commands */ 339*1991Sheppo int 340*1991Sheppo vntsd_telnet_cmd(vntsd_client_t *clientp, char c) 341*1991Sheppo { 342*1991Sheppo uint8_t buf[4]; 343*1991Sheppo char cmd; 344*1991Sheppo int rv = VNTSD_STATUS_CONTINUE; 345*1991Sheppo 346*1991Sheppo bzero(buf, 4); 347*1991Sheppo 348*1991Sheppo if ((uint8_t)c != IAC) { 349*1991Sheppo /* not telnet cmd */ 350*1991Sheppo return (VNTSD_SUCCESS); 351*1991Sheppo } 352*1991Sheppo 353*1991Sheppo if ((rv = vntsd_read_char(clientp, &cmd)) != VNTSD_SUCCESS) { 354*1991Sheppo return (rv); 355*1991Sheppo } 356*1991Sheppo 357*1991Sheppo if ((rv = vntsd_read_char(clientp, &c)) != VNTSD_SUCCESS) { 358*1991Sheppo return (rv); 359*1991Sheppo } 360*1991Sheppo 361*1991Sheppo 362*1991Sheppo switch ((uint8_t)cmd) { 363*1991Sheppo 364*1991Sheppo case WILL: 365*1991Sheppo 366*1991Sheppo switch ((uint8_t)c) { 367*1991Sheppo case TEL_ECHO: 368*1991Sheppo case SUPRESS: 369*1991Sheppo case LINEMODE: 370*1991Sheppo break; 371*1991Sheppo default: 372*1991Sheppo syslog(LOG_ERR, "not support telnet WILL %x\n", c); 373*1991Sheppo break; 374*1991Sheppo } 375*1991Sheppo break; 376*1991Sheppo 377*1991Sheppo case WONT: 378*1991Sheppo 379*1991Sheppo switch ((uint8_t)c) { 380*1991Sheppo case TEL_ECHO: 381*1991Sheppo case SUPRESS: 382*1991Sheppo case LINEMODE: 383*1991Sheppo default: 384*1991Sheppo syslog(LOG_ERR, "not support telnet WONT %x\n", c); 385*1991Sheppo break; 386*1991Sheppo } 387*1991Sheppo break; 388*1991Sheppo 389*1991Sheppo case DO: 390*1991Sheppo case DONT: 391*1991Sheppo 392*1991Sheppo buf[0] = IAC; 393*1991Sheppo buf[1] = WILL; 394*1991Sheppo buf[2] = c; 395*1991Sheppo rv = vntsd_write_client(clientp, (char *)buf, 3); 396*1991Sheppo 397*1991Sheppo break; 398*1991Sheppo 399*1991Sheppo case BRK: 400*1991Sheppo 401*1991Sheppo /* send break to vcc */ 402*1991Sheppo rv = genbrk(clientp); 403*1991Sheppo break; 404*1991Sheppo 405*1991Sheppo case IP: 406*1991Sheppo 407*1991Sheppo break; 408*1991Sheppo 409*1991Sheppo case AYT: 410*1991Sheppo 411*1991Sheppo rv = vntsd_write_client(clientp, &c, 1); 412*1991Sheppo break; 413*1991Sheppo 414*1991Sheppo case HT: 415*1991Sheppo return (VNTSD_STATUS_CONTINUE); 416*1991Sheppo 417*1991Sheppo default: 418*1991Sheppo syslog(LOG_ERR, "not support telnet ctrl %x\n", c); 419*1991Sheppo break; 420*1991Sheppo } 421*1991Sheppo 422*1991Sheppo if (rv == VNTSD_SUCCESS) { 423*1991Sheppo return (VNTSD_STATUS_CONTINUE); 424*1991Sheppo } else { 425*1991Sheppo return (rv); 426*1991Sheppo } 427*1991Sheppo } 428*1991Sheppo 429*1991Sheppo 430*1991Sheppo /* 431*1991Sheppo * vntsd_ctrl_cmd() - control keys 432*1991Sheppo * read and write suspend are supported. 433*1991Sheppo */ 434*1991Sheppo int 435*1991Sheppo vntsd_ctrl_cmd(vntsd_client_t *clientp, char c) 436*1991Sheppo { 437*1991Sheppo int cmd; 438*1991Sheppo 439*1991Sheppo D3(stderr, "t@%d vntsd_ctrl_cmd%d %d\n", thr_self(), 440*1991Sheppo clientp->cons->vcc_fd, clientp->sockfd); 441*1991Sheppo 442*1991Sheppo if ((c != START) && (c != STOP)) { 443*1991Sheppo /* not a supported control command */ 444*1991Sheppo return (VNTSD_SUCCESS); 445*1991Sheppo } 446*1991Sheppo 447*1991Sheppo if (c == START) { 448*1991Sheppo 449*1991Sheppo D3(stderr, "t@%d client restart\n", thr_self()); 450*1991Sheppo 451*1991Sheppo /* send resume read */ 452*1991Sheppo cmd = 1; 453*1991Sheppo 454*1991Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 455*1991Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 456*1991Sheppo } 457*1991Sheppo 458*1991Sheppo /* send resume write */ 459*1991Sheppo cmd = 3; 460*1991Sheppo 461*1991Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 462*1991Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 463*1991Sheppo } 464*1991Sheppo } 465*1991Sheppo 466*1991Sheppo if (c == STOP) { 467*1991Sheppo D3(stderr, "t@%d client suspend\n", thr_self()); 468*1991Sheppo 469*1991Sheppo /* send suspend read */ 470*1991Sheppo cmd = 0; 471*1991Sheppo 472*1991Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 473*1991Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 474*1991Sheppo } 475*1991Sheppo 476*1991Sheppo /* send suspend write */ 477*1991Sheppo cmd = 2; 478*1991Sheppo 479*1991Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 480*1991Sheppo perror("ioctl TCXONC"); 481*1991Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 482*1991Sheppo } 483*1991Sheppo } 484*1991Sheppo 485*1991Sheppo return (VNTSD_STATUS_CONTINUE); 486*1991Sheppo } 487