Mercurial > dropbear
comparison svr-chansession.c @ 40:b4874d772210
- Added terminal mode handling etc for the client, and window change
- Refactored the terminal-mode handling for the server
- Improved session closing for the client
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 01 Aug 2004 08:54:01 +0000 |
parents | f789045062e6 |
children | 20563735e8b5 |
comparison
equal
deleted
inserted
replaced
39:0883c0906870 | 40:b4874d772210 |
---|---|
54 static int newchansess(struct Channel *channel); | 54 static int newchansess(struct Channel *channel); |
55 static void chansessionrequest(struct Channel *channel); | 55 static void chansessionrequest(struct Channel *channel); |
56 | 56 |
57 static void send_exitsignalstatus(struct Channel *channel); | 57 static void send_exitsignalstatus(struct Channel *channel); |
58 static int sesscheckclose(struct Channel *channel); | 58 static int sesscheckclose(struct Channel *channel); |
59 static void get_termmodes(struct ChanSess *chansess); | |
59 | 60 |
60 | 61 |
61 /* required to clear environment */ | 62 /* required to clear environment */ |
62 extern char** environ; | 63 extern char** environ; |
63 | 64 |
190 /* pty details */ | 191 /* pty details */ |
191 chansess->master = -1; | 192 chansess->master = -1; |
192 chansess->slave = -1; | 193 chansess->slave = -1; |
193 chansess->tty = NULL; | 194 chansess->tty = NULL; |
194 chansess->term = NULL; | 195 chansess->term = NULL; |
195 chansess->termw = 0; | |
196 chansess->termh = 0; | |
197 chansess->termc = 0; | |
198 chansess->termr = 0; | |
199 | 196 |
200 chansess->exited = 0; | 197 chansess->exited = 0; |
201 | 198 |
202 channel->typedata = chansess; | 199 channel->typedata = chansess; |
203 | 200 |
374 | 371 |
375 /* Let the process know that the window size has changed, as notified from the | 372 /* Let the process know that the window size has changed, as notified from the |
376 * client. Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ | 373 * client. Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ |
377 static int sessionwinchange(struct ChanSess *chansess) { | 374 static int sessionwinchange(struct ChanSess *chansess) { |
378 | 375 |
376 int termc, termr, termw, termh; | |
377 | |
379 if (chansess->master < 0) { | 378 if (chansess->master < 0) { |
380 /* haven't got a pty yet */ | 379 /* haven't got a pty yet */ |
381 return DROPBEAR_FAILURE; | 380 return DROPBEAR_FAILURE; |
382 } | 381 } |
383 | 382 |
384 chansess->termc = buf_getint(ses.payload); | 383 termc = buf_getint(ses.payload); |
385 chansess->termr = buf_getint(ses.payload); | 384 termr = buf_getint(ses.payload); |
386 chansess->termw = buf_getint(ses.payload); | 385 termw = buf_getint(ses.payload); |
387 chansess->termh = buf_getint(ses.payload); | 386 termh = buf_getint(ses.payload); |
388 | 387 |
389 pty_change_window_size(chansess->master, chansess->termr, chansess->termc, | 388 pty_change_window_size(chansess->master, termr, termc, termw, termh); |
390 chansess->termw, chansess->termh); | |
391 | 389 |
392 return DROPBEAR_FAILURE; | 390 return DROPBEAR_FAILURE; |
391 } | |
392 | |
393 static void get_termmodes(struct ChanSess *chansess) { | |
394 | |
395 struct termios termio; | |
396 unsigned char opcode; | |
397 unsigned int value; | |
398 const struct TermCode * termcode; | |
399 unsigned int len; | |
400 | |
401 TRACE(("enter get_termmodes")); | |
402 | |
403 /* Term modes */ | |
404 /* We'll ignore errors and continue if we can't set modes. | |
405 * We're ignoring baud rates since they seem evil */ | |
406 if (tcgetattr(chansess->master, &termio) == -1) { | |
407 return; | |
408 } | |
409 | |
410 len = buf_getint(ses.payload); | |
411 if (len != ses.payload->len - ses.payload->pos) { | |
412 dropbear_exit("bad term mode string"); | |
413 } | |
414 | |
415 if (len == 0) { | |
416 TRACE(("leave get_termmodes: empty terminal modes string")); | |
417 } | |
418 | |
419 while (((opcode = buf_getbyte(ses.payload)) != 0x00) && opcode <= 159) { | |
420 | |
421 /* must be before checking type, so that value is consumed even if | |
422 * we don't use it */ | |
423 value = buf_getint(ses.payload); | |
424 | |
425 /* handle types of code */ | |
426 if (opcode > MAX_TERMCODE) { | |
427 continue; | |
428 } | |
429 termcode = &termcodes[(unsigned int)opcode]; | |
430 | |
431 | |
432 switch (termcode->type) { | |
433 | |
434 case TERMCODE_NONE: | |
435 break; | |
436 | |
437 case TERMCODE_CONTROLCHAR: | |
438 termio.c_cc[termcode->mapcode] = value; | |
439 break; | |
440 | |
441 case TERMCODE_INPUT: | |
442 if (value) { | |
443 termio.c_iflag |= termcode->mapcode; | |
444 } else { | |
445 termio.c_iflag &= ~(termcode->mapcode); | |
446 } | |
447 break; | |
448 | |
449 case TERMCODE_OUTPUT: | |
450 if (value) { | |
451 termio.c_oflag |= termcode->mapcode; | |
452 } else { | |
453 termio.c_oflag &= ~(termcode->mapcode); | |
454 } | |
455 break; | |
456 | |
457 case TERMCODE_LOCAL: | |
458 if (value) { | |
459 termio.c_lflag |= termcode->mapcode; | |
460 } else { | |
461 termio.c_lflag &= ~(termcode->mapcode); | |
462 } | |
463 break; | |
464 | |
465 case TERMCODE_CONTROL: | |
466 if (value) { | |
467 termio.c_cflag |= termcode->mapcode; | |
468 } else { | |
469 termio.c_cflag &= ~(termcode->mapcode); | |
470 } | |
471 break; | |
472 | |
473 } | |
474 } | |
475 if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) { | |
476 dropbear_log(LOG_INFO, "error setting terminal attributes"); | |
477 } | |
478 TRACE(("leave get_termmodes")); | |
393 } | 479 } |
394 | 480 |
395 /* Set up a session pty which will be used to execute the shell or program. | 481 /* Set up a session pty which will be used to execute the shell or program. |
396 * The pty is allocated now, and kept for when the shell/program executes. | 482 * The pty is allocated now, and kept for when the shell/program executes. |
397 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ | 483 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ |
398 static int sessionpty(struct ChanSess * chansess) { | 484 static int sessionpty(struct ChanSess * chansess) { |
399 | 485 |
400 unsigned int termlen; | 486 unsigned int termlen; |
401 unsigned char namebuf[65]; | 487 unsigned char namebuf[65]; |
402 struct termios termio; | |
403 | 488 |
404 TRACE(("enter sessionpty")); | 489 TRACE(("enter sessionpty")); |
405 chansess->term = buf_getstring(ses.payload, &termlen); | 490 chansess->term = buf_getstring(ses.payload, &termlen); |
406 if (termlen > MAX_TERM_LEN) { | 491 if (termlen > MAX_TERM_LEN) { |
407 /* TODO send disconnect ? */ | 492 /* TODO send disconnect ? */ |
408 TRACE(("leave sessionpty: term len too long")); | 493 TRACE(("leave sessionpty: term len too long")); |
409 return DROPBEAR_FAILURE; | 494 return DROPBEAR_FAILURE; |
410 } | 495 } |
411 chansess->termc = buf_getint(ses.payload); | |
412 chansess->termr = buf_getint(ses.payload); | |
413 chansess->termw = buf_getint(ses.payload); | |
414 chansess->termh = buf_getint(ses.payload); | |
415 | 496 |
416 /* allocate the pty */ | 497 /* allocate the pty */ |
417 assert(chansess->master == -1); /* haven't already got one */ | 498 assert(chansess->master == -1); /* haven't already got one */ |
418 if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) { | 499 if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) { |
419 TRACE(("leave sessionpty: failed to allocate pty")); | 500 TRACE(("leave sessionpty: failed to allocate pty")); |
424 if (!chansess->tty) { | 505 if (!chansess->tty) { |
425 dropbear_exit("out of memory"); /* TODO disconnect */ | 506 dropbear_exit("out of memory"); /* TODO disconnect */ |
426 } | 507 } |
427 | 508 |
428 pty_setowner(ses.authstate.pw, chansess->tty); | 509 pty_setowner(ses.authstate.pw, chansess->tty); |
429 pty_change_window_size(chansess->master, chansess->termr, chansess->termc, | 510 |
430 chansess->termw, chansess->termh); | 511 /* Set up the rows/col counts */ |
431 | 512 sessionwinchange(chansess); |
432 /* Term modes */ | 513 |
433 /* We'll ignore errors and continue if we can't set modes. | 514 /* Read the terminal modes */ |
434 * We're ignoring baud rates since they seem evil */ | 515 get_termmodes(chansess); |
435 if (tcgetattr(chansess->master, &termio) == 0) { | |
436 unsigned char opcode; | |
437 unsigned int value; | |
438 const struct TermCode * termcode; | |
439 unsigned int len; | |
440 | |
441 len = buf_getint(ses.payload); | |
442 if (len != ses.payload->len - ses.payload->pos) { | |
443 dropbear_exit("bad term mode string"); | |
444 } | |
445 | |
446 if (len == 0) { | |
447 TRACE(("empty terminal modes string")); | |
448 return DROPBEAR_SUCCESS; | |
449 } | |
450 | |
451 while (((opcode = buf_getbyte(ses.payload)) != 0x00) && | |
452 opcode <= 159) { | |
453 | |
454 /* must be before checking type, so that value is consumed even if | |
455 * we don't use it */ | |
456 value = buf_getint(ses.payload); | |
457 | |
458 /* handle types of code */ | |
459 if (opcode > MAX_TERMCODE) { | |
460 continue; | |
461 } | |
462 termcode = &termcodes[(unsigned int)opcode]; | |
463 | |
464 | |
465 switch (termcode->type) { | |
466 | |
467 case TERMCODE_NONE: | |
468 break; | |
469 | |
470 case TERMCODE_CONTROLCHAR: | |
471 termio.c_cc[termcode->mapcode] = value; | |
472 break; | |
473 | |
474 case TERMCODE_INPUT: | |
475 if (value) { | |
476 termio.c_iflag |= termcode->mapcode; | |
477 } else { | |
478 termio.c_iflag &= ~(termcode->mapcode); | |
479 } | |
480 break; | |
481 | |
482 case TERMCODE_OUTPUT: | |
483 if (value) { | |
484 termio.c_oflag |= termcode->mapcode; | |
485 } else { | |
486 termio.c_oflag &= ~(termcode->mapcode); | |
487 } | |
488 break; | |
489 | |
490 case TERMCODE_LOCAL: | |
491 if (value) { | |
492 termio.c_lflag |= termcode->mapcode; | |
493 } else { | |
494 termio.c_lflag &= ~(termcode->mapcode); | |
495 } | |
496 break; | |
497 | |
498 case TERMCODE_CONTROL: | |
499 if (value) { | |
500 termio.c_cflag |= termcode->mapcode; | |
501 } else { | |
502 termio.c_cflag &= ~(termcode->mapcode); | |
503 } | |
504 break; | |
505 | |
506 } | |
507 } | |
508 if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) { | |
509 dropbear_log(LOG_INFO, "error setting terminal attributes"); | |
510 } | |
511 } | |
512 | 516 |
513 TRACE(("leave sessionpty")); | 517 TRACE(("leave sessionpty")); |
514 return DROPBEAR_SUCCESS; | 518 return DROPBEAR_SUCCESS; |
515 } | 519 } |
516 | 520 |