1/*- 2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 *
| 1/*- 2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 *
|
70#include "bundle.h" 71#include "chat.h" 72#include "chap.h" 73#include "cbcp.h" 74#include "datalink.h" 75#include "server.h" 76#include "main.h" 77 78static void 79prompt_Display(struct prompt *p) 80{ 81 /* XXX: See Index2Nam() - should we only figure this out once ? */ 82 static char shostname[MAXHOSTNAMELEN]; 83 const char *pconnect, *pauth; 84 85 if (p->TermMode || !p->needprompt) 86 return; 87 88 p->needprompt = 0; 89 90 if (p->nonewline) 91 p->nonewline = 0; 92 else 93 fprintf(p->Term, "\n"); 94 95 if (p->auth == LOCAL_AUTH) 96 pauth = " ON "; 97 else 98 pauth = " on "; 99 100 if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED) 101 pconnect = "PPP"; 102 else if (bundle_Phase(p->bundle) == PHASE_NETWORK) 103 pconnect = "PPp"; 104 else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE) 105 pconnect = "Ppp"; 106 else 107 pconnect = "ppp"; 108 109 if (*shostname == '\0') { 110 char *dot; 111 112 if (gethostname(shostname, sizeof shostname) || *shostname == '\0') 113 strcpy(shostname, "localhost"); 114 else if ((dot = strchr(shostname, '.'))) 115 *dot = '\0'; 116 } 117 118 fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname); 119 fflush(p->Term); 120} 121 122static int 123prompt_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 124{ 125 struct prompt *p = descriptor2prompt(d); 126 int sets; 127 128 sets = 0; 129 130 if (!p->active) 131 return sets; 132 133 if (p->fd_in >= 0) { 134 if (r) { 135 FD_SET(p->fd_in, r); 136 log_Printf(LogTIMER, "prompt %s: fdset(r) %d\n", p->src.from, p->fd_in); 137 sets++; 138 } 139 if (e) { 140 FD_SET(p->fd_in, e); 141 log_Printf(LogTIMER, "prompt %s: fdset(e) %d\n", p->src.from, p->fd_in); 142 sets++; 143 } 144 if (sets && *n < p->fd_in + 1) 145 *n = p->fd_in + 1; 146 } 147 148 prompt_Display(p); 149 150 return sets; 151} 152 153static int 154prompt_IsSet(struct fdescriptor *d, const fd_set *fdset) 155{ 156 struct prompt *p = descriptor2prompt(d); 157 return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset); 158} 159 160 161static void 162prompt_ShowHelp(struct prompt *p) 163{ 164 prompt_Printf(p, "The following commands are available:\n"); 165 prompt_Printf(p, " ~p\tEnter Packet mode\n"); 166 prompt_Printf(p, " ~t\tShow timers\n"); 167 prompt_Printf(p, " ~m\tShow memory map\n"); 168 prompt_Printf(p, " ~.\tTerminate program\n"); 169 prompt_Printf(p, " ~?\tThis help\n"); 170} 171 172static void 173prompt_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 174{ 175 struct prompt *p = descriptor2prompt(d); 176 struct prompt *op; 177 int n; 178 char ch; 179 char linebuff[LINE_LEN]; 180 181 if (p->TermMode == NULL) { 182 n = read(p->fd_in, linebuff, sizeof linebuff - 1); 183 if (n > 0) { 184 if (linebuff[n-1] == '\n') 185 linebuff[--n] = '\0'; 186 else 187 linebuff[n] = '\0'; 188 p->nonewline = 1; /* Maybe command_Decode does a prompt */ 189 prompt_Required(p); 190 if (n) { 191 if ((op = log_PromptContext) == NULL) 192 log_PromptContext = p; 193 if (!command_Decode(bundle, linebuff, n, p, p->src.from)) 194 prompt_Printf(p, "Syntax error\n"); 195 log_PromptContext = op; 196 } 197 } else if (n <= 0) { 198 log_Printf(LogPHASE, "%s: Client connection closed.\n", p->src.from); 199 if (!p->owner) 200 Cleanup(EX_NORMAL); 201 prompt_Destroy(p, 0); 202 } 203 return; 204 } 205 206 switch (p->TermMode->state) { 207 case DATALINK_CLOSED: 208 prompt_Printf(p, "Link lost, terminal mode.\n"); 209 prompt_TtyCommandMode(p); 210 p->nonewline = 0; 211 prompt_Required(p); 212 return; 213 214 case DATALINK_READY: 215 break; 216 217 case DATALINK_OPEN: 218 prompt_Printf(p, "\nPacket mode detected.\n"); 219 prompt_TtyCommandMode(p); 220 p->nonewline = 0; 221 /* We'll get a prompt because of our status change */ 222 /* Fall through */ 223 224 default: 225 /* Wait 'till we're in a state we care about */ 226 return; 227 } 228 229 /* 230 * We are in terminal mode, decode special sequences 231 */ 232 n = read(p->fd_in, &ch, 1); 233 log_Printf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 234 235 if (n > 0) { 236 switch (p->readtilde) { 237 case 0: 238 if (ch == '~') 239 p->readtilde = 1; 240 else 241 if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 242 log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 243 prompt_TtyCommandMode(p); 244 } 245 break; 246 case 1: 247 switch (ch) { 248 case '?': 249 prompt_ShowHelp(p); 250 break; 251 case 'p': 252 datalink_Up(p->TermMode, 0, 1); 253 prompt_Printf(p, "\nPacket mode.\n"); 254 prompt_TtyCommandMode(p); 255 break; 256 case '.': 257 prompt_TtyCommandMode(p); 258 p->nonewline = 0; 259 prompt_Required(p); 260 break; 261 case 't': 262 timer_Show(0, p); 263 break; 264 case 'm': 265 { 266 struct cmdargs arg; 267 268 arg.cmdtab = NULL; 269 arg.cmd = NULL; 270 arg.argc = 0; 271 arg.argn = 0; 272 arg.argv = NULL; 273 arg.bundle = bundle; 274 arg.cx = p->TermMode; 275 arg.prompt = p; 276 277 mbuf_Show(&arg); 278 } 279 break; 280 default: 281 if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 282 log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 283 prompt_TtyCommandMode(p); 284 } 285 break; 286 } 287 p->readtilde = 0; 288 break; 289 } 290 } 291} 292 293static int 294prompt_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 295{ 296 /* We never want to write here ! */ 297 log_Printf(LogALERT, "prompt_Write: Internal error: Bad call !\n"); 298 return 0; 299} 300 301struct prompt * 302prompt_Create(struct server *s, struct bundle *bundle, int fd) 303{ 304 struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt)); 305 306 if (p != NULL) { 307 p->desc.type = PROMPT_DESCRIPTOR; 308 p->desc.UpdateSet = prompt_UpdateSet; 309 p->desc.IsSet = prompt_IsSet; 310 p->desc.Read = prompt_Read; 311 p->desc.Write = prompt_Write; 312 313 if (fd == PROMPT_STD) { 314 char *tty = ttyname(STDIN_FILENO); 315 316 if (!tty) { 317 free(p); 318 return NULL; 319 } 320 p->fd_in = STDIN_FILENO; 321 p->fd_out = STDOUT_FILENO; 322 p->Term = stdout; 323 p->owner = NULL; 324 p->auth = LOCAL_AUTH; 325 p->src.type = "Controller"; 326 strncpy(p->src.from, tty, sizeof p->src.from - 1); 327 p->src.from[sizeof p->src.from - 1] = '\0'; 328 tcgetattr(p->fd_in, &p->oldtio); /* Save original tty mode */ 329 } else { 330 p->fd_in = p->fd_out = fd; 331 p->Term = fdopen(fd, "a+"); 332 p->owner = s; 333 p->auth = *s->cfg.passwd ? LOCAL_NO_AUTH : LOCAL_AUTH; 334 p->src.type = "unknown"; 335 *p->src.from = '\0'; 336 } 337 p->TermMode = NULL; 338 p->nonewline = 1; 339 p->needprompt = 1; 340 p->readtilde = 0; 341 p->bundle = bundle; 342 log_RegisterPrompt(p); 343 } 344 345 return p; 346} 347 348void 349prompt_Destroy(struct prompt *p, int verbose) 350{ 351 if (p) { 352 if (p->Term != stdout) { 353 fclose(p->Term); 354 close(p->fd_in); 355 if (p->fd_out != p->fd_in) 356 close(p->fd_out); 357 if (verbose) 358 log_Printf(LogPHASE, "%s: Client connection dropped.\n", p->src.from); 359 } else 360 prompt_TtyOldMode(p); 361 362 log_UnRegisterPrompt(p); 363 free(p); 364 } 365} 366 367void 368prompt_Printf(struct prompt *p, const char *fmt,...) 369{ 370 if (p && p->active) { 371 va_list ap; 372 373 va_start(ap, fmt); 374 prompt_vPrintf(p, fmt, ap); 375 va_end(ap); 376 } 377} 378 379void 380prompt_vPrintf(struct prompt *p, const char *fmt, va_list ap) 381{ 382 if (p && p->active) { 383 char nfmt[LINE_LEN]; 384 const char *pfmt; 385 386 if (p->TermMode) { 387 /* Stuff '\r' in front of '\n' 'cos we're in raw mode */ 388 int len = strlen(fmt); 389 390 if (len && len < sizeof nfmt - 1 && fmt[len-1] == '\n' && 391 (len == 1 || fmt[len-2] != '\r')) { 392 strcpy(nfmt, fmt); 393 strcpy(nfmt + len - 1, "\r\n"); 394 pfmt = nfmt; 395 } else 396 pfmt = fmt; 397 } else 398 pfmt = fmt; 399 vfprintf(p->Term, pfmt, ap); 400 fflush(p->Term); 401 p->nonewline = 1; 402 } 403} 404 405void 406prompt_TtyInit(struct prompt *p) 407{ 408 int stat, fd = p ? p->fd_in : STDIN_FILENO; 409 struct termios newtio; 410 411 stat = fcntl(fd, F_GETFL, 0); 412 if (stat > 0) { 413 stat |= O_NONBLOCK; 414 fcntl(fd, F_SETFL, stat); 415 } 416 417 if (p) 418 newtio = p->oldtio; 419 else 420 tcgetattr(fd, &newtio); 421 422 newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 423 newtio.c_iflag = 0; 424 newtio.c_oflag &= ~OPOST; 425 if (!p) 426 newtio.c_cc[VINTR] = _POSIX_VDISABLE; 427 newtio.c_cc[VMIN] = 1; 428 newtio.c_cc[VTIME] = 0; 429 newtio.c_cflag |= CS8; 430 tcsetattr(fd, TCSANOW, &newtio); 431 if (p) 432 p->comtio = newtio; 433} 434 435/* 436 * Set tty into command mode. We allow canonical input and echo processing. 437 */ 438void 439prompt_TtyCommandMode(struct prompt *p) 440{ 441 struct termios newtio; 442 int stat; 443 444 tcgetattr(p->fd_in, &newtio); 445 newtio.c_lflag |= (ECHO | ISIG | ICANON); 446 newtio.c_iflag = p->oldtio.c_iflag; 447 newtio.c_oflag |= OPOST; 448 tcsetattr(p->fd_in, TCSADRAIN, &newtio); 449 450 stat = fcntl(p->fd_in, F_GETFL, 0); 451 if (stat > 0) { 452 stat |= O_NONBLOCK; 453 fcntl(p->fd_in, F_SETFL, stat); 454 } 455 456 p->TermMode = NULL; 457} 458 459/* 460 * Set tty into terminal mode which is used while we invoke term command. 461 */ 462void 463prompt_TtyTermMode(struct prompt *p, struct datalink *dl) 464{ 465 int stat; 466 467 if (p->Term == stdout) 468 tcsetattr(p->fd_in, TCSADRAIN, &p->comtio); 469 470 stat = fcntl(p->fd_in, F_GETFL, 0); 471 if (stat > 0) { 472 stat &= ~O_NONBLOCK; 473 fcntl(p->fd_in, F_SETFL, stat); 474 } 475 p->TermMode = dl; 476} 477 478void 479prompt_TtyOldMode(struct prompt *p) 480{ 481 int stat; 482 483 stat = fcntl(p->fd_in, F_GETFL, 0); 484 if (stat > 0) { 485 stat &= ~O_NONBLOCK; 486 fcntl(p->fd_in, F_SETFL, stat); 487 } 488 489 if (p->Term == stdout) 490 tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio); 491} 492 493pid_t 494prompt_pgrp(struct prompt *p) 495{ 496 return tcgetpgrp(p->fd_in); 497} 498 499int 500PasswdCommand(struct cmdargs const *arg) 501{ 502 const char *pass; 503 504 if (!arg->prompt) { 505 log_Printf(LogWARN, "passwd: Cannot specify without a prompt\n"); 506 return 0; 507 } 508 509 if (arg->prompt->owner == NULL) { 510 log_Printf(LogWARN, "passwd: Not required\n"); 511 return 0; 512 } 513 514 if (arg->argc == arg->argn) 515 pass = ""; 516 else if (arg->argc > arg->argn+1) 517 return -1; 518 else 519 pass = arg->argv[arg->argn]; 520 521 if (!strcmp(arg->prompt->owner->cfg.passwd, pass)) 522 arg->prompt->auth = LOCAL_AUTH; 523 else 524 arg->prompt->auth = LOCAL_NO_AUTH; 525 526 return 0; 527} 528 529static struct pppTimer bgtimer; 530 531static void 532prompt_TimedContinue(void *v) 533{ 534 prompt_Continue((struct prompt *)v); 535} 536 537void 538prompt_Continue(struct prompt *p) 539{ 540 timer_Stop(&bgtimer); 541 if (getpgrp() == prompt_pgrp(p)) { 542 prompt_TtyCommandMode(p); 543 p->nonewline = 1; 544 prompt_Required(p); 545 log_ActivatePrompt(p); 546 } else if (!p->owner) { 547 bgtimer.func = prompt_TimedContinue; 548 bgtimer.name = "prompt bg"; 549 bgtimer.load = SECTICKS; 550 bgtimer.arg = p; 551 timer_Start(&bgtimer); 552 } 553} 554 555void 556prompt_Suspend(struct prompt *p) 557{ 558 if (getpgrp() == prompt_pgrp(p)) { 559 prompt_TtyOldMode(p); 560 log_DeactivatePrompt(p); 561 } 562}
| 75#include "bundle.h" 76#include "chat.h" 77#include "chap.h" 78#include "cbcp.h" 79#include "datalink.h" 80#include "server.h" 81#include "main.h" 82 83static void 84prompt_Display(struct prompt *p) 85{ 86 /* XXX: See Index2Nam() - should we only figure this out once ? */ 87 static char shostname[MAXHOSTNAMELEN]; 88 const char *pconnect, *pauth; 89 90 if (p->TermMode || !p->needprompt) 91 return; 92 93 p->needprompt = 0; 94 95 if (p->nonewline) 96 p->nonewline = 0; 97 else 98 fprintf(p->Term, "\n"); 99 100 if (p->auth == LOCAL_AUTH) 101 pauth = " ON "; 102 else 103 pauth = " on "; 104 105 if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED) 106 pconnect = "PPP"; 107 else if (bundle_Phase(p->bundle) == PHASE_NETWORK) 108 pconnect = "PPp"; 109 else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE) 110 pconnect = "Ppp"; 111 else 112 pconnect = "ppp"; 113 114 if (*shostname == '\0') { 115 char *dot; 116 117 if (gethostname(shostname, sizeof shostname) || *shostname == '\0') 118 strcpy(shostname, "localhost"); 119 else if ((dot = strchr(shostname, '.'))) 120 *dot = '\0'; 121 } 122 123 fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname); 124 fflush(p->Term); 125} 126 127static int 128prompt_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 129{ 130 struct prompt *p = descriptor2prompt(d); 131 int sets; 132 133 sets = 0; 134 135 if (!p->active) 136 return sets; 137 138 if (p->fd_in >= 0) { 139 if (r) { 140 FD_SET(p->fd_in, r); 141 log_Printf(LogTIMER, "prompt %s: fdset(r) %d\n", p->src.from, p->fd_in); 142 sets++; 143 } 144 if (e) { 145 FD_SET(p->fd_in, e); 146 log_Printf(LogTIMER, "prompt %s: fdset(e) %d\n", p->src.from, p->fd_in); 147 sets++; 148 } 149 if (sets && *n < p->fd_in + 1) 150 *n = p->fd_in + 1; 151 } 152 153 prompt_Display(p); 154 155 return sets; 156} 157 158static int 159prompt_IsSet(struct fdescriptor *d, const fd_set *fdset) 160{ 161 struct prompt *p = descriptor2prompt(d); 162 return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset); 163} 164 165 166static void 167prompt_ShowHelp(struct prompt *p) 168{ 169 prompt_Printf(p, "The following commands are available:\n"); 170 prompt_Printf(p, " ~p\tEnter Packet mode\n"); 171 prompt_Printf(p, " ~t\tShow timers\n"); 172 prompt_Printf(p, " ~m\tShow memory map\n"); 173 prompt_Printf(p, " ~.\tTerminate program\n"); 174 prompt_Printf(p, " ~?\tThis help\n"); 175} 176 177static void 178prompt_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 179{ 180 struct prompt *p = descriptor2prompt(d); 181 struct prompt *op; 182 int n; 183 char ch; 184 char linebuff[LINE_LEN]; 185 186 if (p->TermMode == NULL) { 187 n = read(p->fd_in, linebuff, sizeof linebuff - 1); 188 if (n > 0) { 189 if (linebuff[n-1] == '\n') 190 linebuff[--n] = '\0'; 191 else 192 linebuff[n] = '\0'; 193 p->nonewline = 1; /* Maybe command_Decode does a prompt */ 194 prompt_Required(p); 195 if (n) { 196 if ((op = log_PromptContext) == NULL) 197 log_PromptContext = p; 198 if (!command_Decode(bundle, linebuff, n, p, p->src.from)) 199 prompt_Printf(p, "Syntax error\n"); 200 log_PromptContext = op; 201 } 202 } else if (n <= 0) { 203 log_Printf(LogPHASE, "%s: Client connection closed.\n", p->src.from); 204 if (!p->owner) 205 Cleanup(EX_NORMAL); 206 prompt_Destroy(p, 0); 207 } 208 return; 209 } 210 211 switch (p->TermMode->state) { 212 case DATALINK_CLOSED: 213 prompt_Printf(p, "Link lost, terminal mode.\n"); 214 prompt_TtyCommandMode(p); 215 p->nonewline = 0; 216 prompt_Required(p); 217 return; 218 219 case DATALINK_READY: 220 break; 221 222 case DATALINK_OPEN: 223 prompt_Printf(p, "\nPacket mode detected.\n"); 224 prompt_TtyCommandMode(p); 225 p->nonewline = 0; 226 /* We'll get a prompt because of our status change */ 227 /* Fall through */ 228 229 default: 230 /* Wait 'till we're in a state we care about */ 231 return; 232 } 233 234 /* 235 * We are in terminal mode, decode special sequences 236 */ 237 n = read(p->fd_in, &ch, 1); 238 log_Printf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 239 240 if (n > 0) { 241 switch (p->readtilde) { 242 case 0: 243 if (ch == '~') 244 p->readtilde = 1; 245 else 246 if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 247 log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 248 prompt_TtyCommandMode(p); 249 } 250 break; 251 case 1: 252 switch (ch) { 253 case '?': 254 prompt_ShowHelp(p); 255 break; 256 case 'p': 257 datalink_Up(p->TermMode, 0, 1); 258 prompt_Printf(p, "\nPacket mode.\n"); 259 prompt_TtyCommandMode(p); 260 break; 261 case '.': 262 prompt_TtyCommandMode(p); 263 p->nonewline = 0; 264 prompt_Required(p); 265 break; 266 case 't': 267 timer_Show(0, p); 268 break; 269 case 'm': 270 { 271 struct cmdargs arg; 272 273 arg.cmdtab = NULL; 274 arg.cmd = NULL; 275 arg.argc = 0; 276 arg.argn = 0; 277 arg.argv = NULL; 278 arg.bundle = bundle; 279 arg.cx = p->TermMode; 280 arg.prompt = p; 281 282 mbuf_Show(&arg); 283 } 284 break; 285 default: 286 if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 287 log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 288 prompt_TtyCommandMode(p); 289 } 290 break; 291 } 292 p->readtilde = 0; 293 break; 294 } 295 } 296} 297 298static int 299prompt_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 300{ 301 /* We never want to write here ! */ 302 log_Printf(LogALERT, "prompt_Write: Internal error: Bad call !\n"); 303 return 0; 304} 305 306struct prompt * 307prompt_Create(struct server *s, struct bundle *bundle, int fd) 308{ 309 struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt)); 310 311 if (p != NULL) { 312 p->desc.type = PROMPT_DESCRIPTOR; 313 p->desc.UpdateSet = prompt_UpdateSet; 314 p->desc.IsSet = prompt_IsSet; 315 p->desc.Read = prompt_Read; 316 p->desc.Write = prompt_Write; 317 318 if (fd == PROMPT_STD) { 319 char *tty = ttyname(STDIN_FILENO); 320 321 if (!tty) { 322 free(p); 323 return NULL; 324 } 325 p->fd_in = STDIN_FILENO; 326 p->fd_out = STDOUT_FILENO; 327 p->Term = stdout; 328 p->owner = NULL; 329 p->auth = LOCAL_AUTH; 330 p->src.type = "Controller"; 331 strncpy(p->src.from, tty, sizeof p->src.from - 1); 332 p->src.from[sizeof p->src.from - 1] = '\0'; 333 tcgetattr(p->fd_in, &p->oldtio); /* Save original tty mode */ 334 } else { 335 p->fd_in = p->fd_out = fd; 336 p->Term = fdopen(fd, "a+"); 337 p->owner = s; 338 p->auth = *s->cfg.passwd ? LOCAL_NO_AUTH : LOCAL_AUTH; 339 p->src.type = "unknown"; 340 *p->src.from = '\0'; 341 } 342 p->TermMode = NULL; 343 p->nonewline = 1; 344 p->needprompt = 1; 345 p->readtilde = 0; 346 p->bundle = bundle; 347 log_RegisterPrompt(p); 348 } 349 350 return p; 351} 352 353void 354prompt_Destroy(struct prompt *p, int verbose) 355{ 356 if (p) { 357 if (p->Term != stdout) { 358 fclose(p->Term); 359 close(p->fd_in); 360 if (p->fd_out != p->fd_in) 361 close(p->fd_out); 362 if (verbose) 363 log_Printf(LogPHASE, "%s: Client connection dropped.\n", p->src.from); 364 } else 365 prompt_TtyOldMode(p); 366 367 log_UnRegisterPrompt(p); 368 free(p); 369 } 370} 371 372void 373prompt_Printf(struct prompt *p, const char *fmt,...) 374{ 375 if (p && p->active) { 376 va_list ap; 377 378 va_start(ap, fmt); 379 prompt_vPrintf(p, fmt, ap); 380 va_end(ap); 381 } 382} 383 384void 385prompt_vPrintf(struct prompt *p, const char *fmt, va_list ap) 386{ 387 if (p && p->active) { 388 char nfmt[LINE_LEN]; 389 const char *pfmt; 390 391 if (p->TermMode) { 392 /* Stuff '\r' in front of '\n' 'cos we're in raw mode */ 393 int len = strlen(fmt); 394 395 if (len && len < sizeof nfmt - 1 && fmt[len-1] == '\n' && 396 (len == 1 || fmt[len-2] != '\r')) { 397 strcpy(nfmt, fmt); 398 strcpy(nfmt + len - 1, "\r\n"); 399 pfmt = nfmt; 400 } else 401 pfmt = fmt; 402 } else 403 pfmt = fmt; 404 vfprintf(p->Term, pfmt, ap); 405 fflush(p->Term); 406 p->nonewline = 1; 407 } 408} 409 410void 411prompt_TtyInit(struct prompt *p) 412{ 413 int stat, fd = p ? p->fd_in : STDIN_FILENO; 414 struct termios newtio; 415 416 stat = fcntl(fd, F_GETFL, 0); 417 if (stat > 0) { 418 stat |= O_NONBLOCK; 419 fcntl(fd, F_SETFL, stat); 420 } 421 422 if (p) 423 newtio = p->oldtio; 424 else 425 tcgetattr(fd, &newtio); 426 427 newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 428 newtio.c_iflag = 0; 429 newtio.c_oflag &= ~OPOST; 430 if (!p) 431 newtio.c_cc[VINTR] = _POSIX_VDISABLE; 432 newtio.c_cc[VMIN] = 1; 433 newtio.c_cc[VTIME] = 0; 434 newtio.c_cflag |= CS8; 435 tcsetattr(fd, TCSANOW, &newtio); 436 if (p) 437 p->comtio = newtio; 438} 439 440/* 441 * Set tty into command mode. We allow canonical input and echo processing. 442 */ 443void 444prompt_TtyCommandMode(struct prompt *p) 445{ 446 struct termios newtio; 447 int stat; 448 449 tcgetattr(p->fd_in, &newtio); 450 newtio.c_lflag |= (ECHO | ISIG | ICANON); 451 newtio.c_iflag = p->oldtio.c_iflag; 452 newtio.c_oflag |= OPOST; 453 tcsetattr(p->fd_in, TCSADRAIN, &newtio); 454 455 stat = fcntl(p->fd_in, F_GETFL, 0); 456 if (stat > 0) { 457 stat |= O_NONBLOCK; 458 fcntl(p->fd_in, F_SETFL, stat); 459 } 460 461 p->TermMode = NULL; 462} 463 464/* 465 * Set tty into terminal mode which is used while we invoke term command. 466 */ 467void 468prompt_TtyTermMode(struct prompt *p, struct datalink *dl) 469{ 470 int stat; 471 472 if (p->Term == stdout) 473 tcsetattr(p->fd_in, TCSADRAIN, &p->comtio); 474 475 stat = fcntl(p->fd_in, F_GETFL, 0); 476 if (stat > 0) { 477 stat &= ~O_NONBLOCK; 478 fcntl(p->fd_in, F_SETFL, stat); 479 } 480 p->TermMode = dl; 481} 482 483void 484prompt_TtyOldMode(struct prompt *p) 485{ 486 int stat; 487 488 stat = fcntl(p->fd_in, F_GETFL, 0); 489 if (stat > 0) { 490 stat &= ~O_NONBLOCK; 491 fcntl(p->fd_in, F_SETFL, stat); 492 } 493 494 if (p->Term == stdout) 495 tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio); 496} 497 498pid_t 499prompt_pgrp(struct prompt *p) 500{ 501 return tcgetpgrp(p->fd_in); 502} 503 504int 505PasswdCommand(struct cmdargs const *arg) 506{ 507 const char *pass; 508 509 if (!arg->prompt) { 510 log_Printf(LogWARN, "passwd: Cannot specify without a prompt\n"); 511 return 0; 512 } 513 514 if (arg->prompt->owner == NULL) { 515 log_Printf(LogWARN, "passwd: Not required\n"); 516 return 0; 517 } 518 519 if (arg->argc == arg->argn) 520 pass = ""; 521 else if (arg->argc > arg->argn+1) 522 return -1; 523 else 524 pass = arg->argv[arg->argn]; 525 526 if (!strcmp(arg->prompt->owner->cfg.passwd, pass)) 527 arg->prompt->auth = LOCAL_AUTH; 528 else 529 arg->prompt->auth = LOCAL_NO_AUTH; 530 531 return 0; 532} 533 534static struct pppTimer bgtimer; 535 536static void 537prompt_TimedContinue(void *v) 538{ 539 prompt_Continue((struct prompt *)v); 540} 541 542void 543prompt_Continue(struct prompt *p) 544{ 545 timer_Stop(&bgtimer); 546 if (getpgrp() == prompt_pgrp(p)) { 547 prompt_TtyCommandMode(p); 548 p->nonewline = 1; 549 prompt_Required(p); 550 log_ActivatePrompt(p); 551 } else if (!p->owner) { 552 bgtimer.func = prompt_TimedContinue; 553 bgtimer.name = "prompt bg"; 554 bgtimer.load = SECTICKS; 555 bgtimer.arg = p; 556 timer_Start(&bgtimer); 557 } 558} 559 560void 561prompt_Suspend(struct prompt *p) 562{ 563 if (getpgrp() == prompt_pgrp(p)) { 564 prompt_TtyOldMode(p); 565 log_DeactivatePrompt(p); 566 } 567}
|