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