[BACK]Return to packet.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/packet.c, Revision 1.1

1.1     ! deraadt     1: /*
        !             2:
        !             3: packet.c
        !             4:
        !             5: Author: Tatu Ylonen <ylo@cs.hut.fi>
        !             6:
        !             7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
        !             8:                    All rights reserved
        !             9:
        !            10: Created: Sat Mar 18 02:40:40 1995 ylo
        !            11:
        !            12: This file contains code implementing the packet protocol and communication
        !            13: with the other side.  This same code is used both on client and server side.
        !            14:
        !            15: */
        !            16:
        !            17: #include "includes.h"
        !            18: RCSID("$Id: packet.c,v 1.7 1999/06/14 14:41:39 bg Exp $");
        !            19:
        !            20: #include "xmalloc.h"
        !            21: #include "randoms.h"
        !            22: #include "buffer.h"
        !            23: #include "packet.h"
        !            24: #include "bufaux.h"
        !            25: #include "ssh.h"
        !            26: #include "crc32.h"
        !            27: #include "cipher.h"
        !            28: #include "getput.h"
        !            29:
        !            30: #ifdef WITH_ZLIB
        !            31: #include "compress.h"
        !            32: #endif /* WITH_ZLIB */
        !            33:
        !            34: /* This variable contains the file descriptors used for communicating with
        !            35:    the other side.  connection_in is used for reading; connection_out
        !            36:    for writing.  These can be the same descriptor, in which case it is
        !            37:    assumed to be a socket. */
        !            38: static int connection_in = -1;
        !            39: static int connection_out = -1;
        !            40:
        !            41: /* Cipher type.  This value is only used to determine whether to pad the
        !            42:    packets with zeroes or random data. */
        !            43: static int cipher_type = SSH_CIPHER_NONE;
        !            44:
        !            45: /* Protocol flags for the remote side. */
        !            46: static unsigned int remote_protocol_flags = 0;
        !            47:
        !            48: /* Encryption context for receiving data.  This is only used for decryption. */
        !            49: static CipherContext receive_context;
        !            50: /* Encryption coontext for sending data.  This is only used for encryption. */
        !            51: static CipherContext send_context;
        !            52:
        !            53: /* Buffer for raw input data from the socket. */
        !            54: static Buffer input;
        !            55:
        !            56: /* Buffer for raw output data going to the socket. */
        !            57: static Buffer output;
        !            58:
        !            59: /* Buffer for the partial outgoing packet being constructed. */
        !            60: static Buffer outgoing_packet;
        !            61:
        !            62: /* Buffer for the incoming packet currently being processed. */
        !            63: static Buffer incoming_packet;
        !            64:
        !            65: /* Scratch buffer for packet compression/decompression. */
        !            66: static Buffer compression_buffer;
        !            67:
        !            68: #ifdef WITH_ZLIB
        !            69: /* Flag indicating whether packet compression/decompression is enabled. */
        !            70: static int packet_compression = 0;
        !            71: #endif /* WITH_ZLIB */
        !            72:
        !            73: /* Pointer to the random number generator state. */
        !            74: static RandomState *random_state;
        !            75:
        !            76: /* Flag indicating whether this module has been initialized. */
        !            77: static int initialized = 0;
        !            78:
        !            79: /* Set to true if the connection is interactive. */
        !            80: static int interactive_mode = 0;
        !            81:
        !            82: /* Sets the descriptors used for communication.  Disables encryption until
        !            83:    packet_set_encryption_key is called. */
        !            84:
        !            85: void packet_set_connection(int fd_in, int fd_out, RandomState *state)
        !            86: {
        !            87:   connection_in = fd_in;
        !            88:   connection_out = fd_out;
        !            89:   random_state = state;
        !            90:   cipher_type = SSH_CIPHER_NONE;
        !            91:   cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 1);
        !            92:   cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 0);
        !            93:   if (!initialized)
        !            94:     {
        !            95:       initialized = 1;
        !            96:       buffer_init(&input);
        !            97:       buffer_init(&output);
        !            98:       buffer_init(&outgoing_packet);
        !            99:       buffer_init(&incoming_packet);
        !           100:     }
        !           101:
        !           102:   /* Kludge: arrange the close function to be called from fatal(). */
        !           103:   fatal_add_cleanup((void (*)(void *))packet_close, NULL);
        !           104: }
        !           105:
        !           106: /* Sets the connection into non-blocking mode. */
        !           107:
        !           108: void packet_set_nonblocking()
        !           109: {
        !           110:   /* Set the socket into non-blocking mode. */
        !           111: #if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN)
        !           112:   if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0)
        !           113:     error("fcntl O_NONBLOCK: %.100s", strerror(errno));
        !           114: #else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
        !           115:   if (fcntl(connection_in, F_SETFL, O_NDELAY) < 0)
        !           116:     error("fcntl O_NDELAY: %.100s", strerror(errno));
        !           117: #endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
        !           118:
        !           119:   if (connection_out != connection_in)
        !           120:     {
        !           121: #if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN)
        !           122:       if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0)
        !           123:        error("fcntl O_NONBLOCK: %.100s", strerror(errno));
        !           124: #else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
        !           125:       if (fcntl(connection_out, F_SETFL, O_NDELAY) < 0)
        !           126:        error("fcntl O_NDELAY: %.100s", strerror(errno));
        !           127: #endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
        !           128:     }
        !           129: }
        !           130:
        !           131: /* Returns the socket used for reading. */
        !           132:
        !           133: int packet_get_connection_in()
        !           134: {
        !           135:   return connection_in;
        !           136: }
        !           137:
        !           138: /* Returns the descriptor used for writing. */
        !           139:
        !           140: int packet_get_connection_out()
        !           141: {
        !           142:   return connection_out;
        !           143: }
        !           144:
        !           145: /* Closes the connection and clears and frees internal data structures. */
        !           146:
        !           147: void packet_close()
        !           148: {
        !           149:   if (!initialized)
        !           150:     return;
        !           151:   initialized = 0;
        !           152:   if (connection_in == connection_out)
        !           153:     {
        !           154:       shutdown(connection_out, 2);
        !           155:       close(connection_out);
        !           156:     }
        !           157:   else
        !           158:     {
        !           159:       close(connection_in);
        !           160:       close(connection_out);
        !           161:     }
        !           162:   buffer_free(&input);
        !           163:   buffer_free(&output);
        !           164:   buffer_free(&outgoing_packet);
        !           165:   buffer_free(&incoming_packet);
        !           166: #ifdef WITH_ZLIB
        !           167:   if (packet_compression)
        !           168:     {
        !           169:       buffer_free(&compression_buffer);
        !           170:       buffer_compress_uninit();
        !           171:     }
        !           172: #endif /* WITH_ZLIB */
        !           173: }
        !           174:
        !           175: /* Sets remote side protocol flags. */
        !           176:
        !           177: void packet_set_protocol_flags(unsigned int protocol_flags)
        !           178: {
        !           179:   remote_protocol_flags = protocol_flags;
        !           180:   channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0);
        !           181: }
        !           182:
        !           183: /* Returns the remote protocol flags set earlier by the above function. */
        !           184:
        !           185: unsigned int packet_get_protocol_flags()
        !           186: {
        !           187:   return remote_protocol_flags;
        !           188: }
        !           189:
        !           190: #ifdef WITH_ZLIB
        !           191: /* Starts packet compression from the next packet on in both directions.
        !           192:    Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */
        !           193:
        !           194: void packet_start_compression(int level)
        !           195: {
        !           196:   if (packet_compression)
        !           197:     fatal("Compression already enabled.");
        !           198:   packet_compression = 1;
        !           199:   buffer_init(&compression_buffer);
        !           200:   buffer_compress_init(level);
        !           201: }
        !           202: #endif /* WITH_ZLIB */
        !           203:
        !           204: /* Encrypts the given number of bytes, copying from src to dest.
        !           205:    bytes is known to be a multiple of 8. */
        !           206:
        !           207: void packet_encrypt(CipherContext *cc, void *dest, void *src,
        !           208:                    unsigned int bytes)
        !           209: {
        !           210:   assert((bytes % 8) == 0);
        !           211:   cipher_encrypt(cc, dest, src, bytes);
        !           212: }
        !           213:
        !           214: /* Decrypts the given number of bytes, copying from src to dest.
        !           215:    bytes is known to be a multiple of 8. */
        !           216:
        !           217: void packet_decrypt(CipherContext *cc, void *dest, void *src,
        !           218:                    unsigned int bytes)
        !           219: {
        !           220:   assert((bytes % 8) == 0);
        !           221:   cipher_decrypt(cc, dest, src, bytes);
        !           222: }
        !           223:
        !           224: /* Causes any further packets to be encrypted using the given key.  The same
        !           225:    key is used for both sending and reception.  However, both directions
        !           226:    are encrypted independently of each other. */
        !           227:
        !           228: void packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
        !           229:                               int cipher, int is_client)
        !           230: {
        !           231:   cipher_type = cipher;
        !           232:   if (cipher == SSH_CIPHER_RC4)
        !           233:     {
        !           234:       if (is_client)
        !           235:        { /* In client: use first half for receiving, second for sending. */
        !           236:          cipher_set_key(&receive_context, cipher, key, keylen / 2, 0);
        !           237:          cipher_set_key(&send_context, cipher, key + keylen / 2,
        !           238:                         keylen / 2, 1);
        !           239:        }
        !           240:       else
        !           241:        { /* In server: use first half for sending, second for receiving. */
        !           242:          cipher_set_key(&receive_context, cipher, key + keylen / 2,
        !           243:                         keylen / 2, 0);
        !           244:          cipher_set_key(&send_context, cipher, key, keylen / 2, 1);
        !           245:        }
        !           246:     }
        !           247:   else
        !           248:     {
        !           249:       /* All other ciphers use the same key in both directions for now. */
        !           250:       cipher_set_key(&receive_context, cipher, key, keylen, 0);
        !           251:       cipher_set_key(&send_context, cipher, key, keylen, 1);
        !           252:     }
        !           253: }
        !           254:
        !           255: /* Starts constructing a packet to send. */
        !           256:
        !           257: void packet_start(int type)
        !           258: {
        !           259:   char buf[9];
        !           260:
        !           261:   buffer_clear(&outgoing_packet);
        !           262:   memset(buf, 0, 8);
        !           263:   buf[8] = type;
        !           264:   buffer_append(&outgoing_packet, buf, 9);
        !           265: }
        !           266:
        !           267: /* Appends a character to the packet data. */
        !           268:
        !           269: void packet_put_char(int value)
        !           270: {
        !           271:   char ch = value;
        !           272:   buffer_append(&outgoing_packet, &ch, 1);
        !           273: }
        !           274:
        !           275: /* Appends an integer to the packet data. */
        !           276:
        !           277: void packet_put_int(unsigned int value)
        !           278: {
        !           279:   buffer_put_int(&outgoing_packet, value);
        !           280: }
        !           281:
        !           282: /* Appends a string to packet data. */
        !           283:
        !           284: void packet_put_string(const char *buf, unsigned int len)
        !           285: {
        !           286:   buffer_put_string(&outgoing_packet, buf, len);
        !           287: }
        !           288:
        !           289: /* Appends an arbitrary precision integer to packet data. */
        !           290:
        !           291: void packet_put_mp_int(MP_INT *value)
        !           292: {
        !           293:   buffer_put_mp_int(&outgoing_packet, value);
        !           294: }
        !           295:
        !           296: /* Finalizes and sends the packet.  If the encryption key has been set,
        !           297:    encrypts the packet before sending. */
        !           298:
        !           299: void packet_send()
        !           300: {
        !           301:   char buf[8], *cp;
        !           302:   int i, padding, len;
        !           303:   unsigned long checksum;
        !           304:
        !           305: #ifdef WITH_ZLIB
        !           306:   /* If using packet compression, compress the payload of the outgoing
        !           307:      packet. */
        !           308:   if (packet_compression)
        !           309:     {
        !           310:       buffer_clear(&compression_buffer);
        !           311:       buffer_consume(&outgoing_packet, 8); /* Skip padding. */
        !           312:       buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); /* padding */
        !           313:       buffer_compress(&outgoing_packet, &compression_buffer);
        !           314:       buffer_clear(&outgoing_packet);
        !           315:       buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
        !           316:                    buffer_len(&compression_buffer));
        !           317:     }
        !           318: #endif /* WITH_ZLIB */
        !           319:
        !           320:   /* Compute packet length without padding (add checksum, remove padding). */
        !           321:   len = buffer_len(&outgoing_packet) + 4 - 8;
        !           322:
        !           323:   /* Insert padding. */
        !           324:   padding = 8 - len % 8;
        !           325:   if (cipher_type != SSH_CIPHER_NONE)
        !           326:     {
        !           327:       cp = buffer_ptr(&outgoing_packet);
        !           328:       for (i = 0; i < padding; i++)
        !           329:        cp[7 - i] = random_get_byte(random_state);
        !           330:     }
        !           331:   buffer_consume(&outgoing_packet, 8 - padding);
        !           332:
        !           333:   /* Add check bytes. */
        !           334:   checksum = crc32((unsigned char *)buffer_ptr(&outgoing_packet),
        !           335:                   buffer_len(&outgoing_packet));
        !           336:   PUT_32BIT(buf, checksum);
        !           337:   buffer_append(&outgoing_packet, buf, 4);
        !           338:
        !           339: #ifdef PACKET_DEBUG
        !           340:   fprintf(stderr, "packet_send plain: ");
        !           341:   buffer_dump(&outgoing_packet);
        !           342: #endif
        !           343:
        !           344:   /* Append to output. */
        !           345:   PUT_32BIT(buf, len);
        !           346:   buffer_append(&output, buf, 4);
        !           347:   buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
        !           348:   packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
        !           349:                 buffer_len(&outgoing_packet));
        !           350:
        !           351: #ifdef PACKET_DEBUG
        !           352:   fprintf(stderr, "encrypted: "); buffer_dump(&output);
        !           353: #endif
        !           354:
        !           355:   buffer_clear(&outgoing_packet);
        !           356:
        !           357:   /* Note that the packet is now only buffered in output.  It won\'t be
        !           358:      actually sent until packet_write_wait or packet_write_poll is called. */
        !           359: }
        !           360:
        !           361: /* Waits until a packet has been received, and returns its type.  Note that
        !           362:    no other data is processed until this returns, so this function should
        !           363:    not be used during the interactive session. */
        !           364:
        !           365: int packet_read(int *payload_len_ptr)
        !           366: {
        !           367:   int type, len;
        !           368:   fd_set set;
        !           369:   char buf[8192];
        !           370:
        !           371:   /* Since we are blocking, ensure that all written packets have been sent. */
        !           372:   packet_write_wait();
        !           373:
        !           374:   /* Stay in the loop until we have received a complete packet. */
        !           375:   for (;;)
        !           376:     {
        !           377:       /* Try to read a packet from the buffer. */
        !           378:       type = packet_read_poll(payload_len_ptr);
        !           379:       if (type == SSH_SMSG_SUCCESS
        !           380:          || type == SSH_SMSG_FAILURE
        !           381:          || type == SSH_CMSG_EOF
        !           382:          || type == SSH_CMSG_EXIT_CONFIRMATION)
        !           383:        packet_integrity_check(*payload_len_ptr, 0, type);
        !           384:       /* If we got a packet, return it. */
        !           385:       if (type != SSH_MSG_NONE)
        !           386:        return type;
        !           387:       /* Otherwise, wait for some data to arrive, add it to the buffer,
        !           388:         and try again. */
        !           389:       FD_ZERO(&set);
        !           390:       FD_SET(connection_in, &set);
        !           391:       /* Wait for some data to arrive. */
        !           392:       select(connection_in + 1, &set, NULL, NULL, NULL);
        !           393:       /* Read data from the socket. */
        !           394:       len = read(connection_in, buf, sizeof(buf));
        !           395:       if (len == 0)
        !           396:        fatal("Connection closed by remote host.");
        !           397:       if (len < 0)
        !           398:        fatal("Read from socket failed: %.100s", strerror(errno));
        !           399:       /* Append it to the buffer. */
        !           400:       packet_process_incoming(buf, len);
        !           401:     }
        !           402:   /*NOTREACHED*/
        !           403: }
        !           404:
        !           405: /* Waits until a packet has been received, verifies that its type matches
        !           406:    that given, and gives a fatal error and exits if there is a mismatch. */
        !           407:
        !           408: void packet_read_expect(int *payload_len_ptr, int expected_type)
        !           409: {
        !           410:   int type;
        !           411:
        !           412:   type = packet_read(payload_len_ptr);
        !           413:   if (type != expected_type)
        !           414:     packet_disconnect("Protocol error: expected packet type %d, got %d",
        !           415:                      expected_type, type);
        !           416: }
        !           417:
        !           418: /* Checks if a full packet is available in the data received so far via
        !           419:    packet_process_incoming.  If so, reads the packet; otherwise returns
        !           420:    SSH_MSG_NONE.  This does not wait for data from the connection.
        !           421:
        !           422:    SSH_MSG_DISCONNECT is handled specially here.  Also,
        !           423:    SSH_MSG_IGNORE messages are skipped by this function and are never returned
        !           424:    to higher levels.
        !           425:
        !           426:    The returned payload_len does include space consumed by:
        !           427:    Packet length
        !           428:    Padding
        !           429:    Packet type
        !           430:    Check bytes
        !           431:
        !           432:
        !           433:    */
        !           434:
        !           435: int packet_read_poll(int *payload_len_ptr)
        !           436: {
        !           437:   unsigned int len, padded_len;
        !           438:   unsigned char *ucp;
        !           439:   char buf[8], *cp;
        !           440:   unsigned long checksum, stored_checksum;
        !           441:
        !           442:  restart:
        !           443:
        !           444:   /* Check if input size is less than minimum packet size. */
        !           445:   if (buffer_len(&input) < 4 + 8)
        !           446:     return SSH_MSG_NONE;
        !           447:   /* Get length of incoming packet. */
        !           448:   ucp = (unsigned char *)buffer_ptr(&input);
        !           449:   len = GET_32BIT(ucp);
        !           450:   if (len < 1 + 2 + 2 || len > 256*1024)
        !           451:     packet_disconnect("Bad packet length %d.", len);
        !           452:   padded_len = (len + 8) & ~7;
        !           453:
        !           454:   /* Check if the packet has been entirely received. */
        !           455:   if (buffer_len(&input) < 4 + padded_len)
        !           456:     return SSH_MSG_NONE;
        !           457:
        !           458:   /* The entire packet is in buffer. */
        !           459:
        !           460:   /* Consume packet length. */
        !           461:   buffer_consume(&input, 4);
        !           462:
        !           463:   /* Copy data to incoming_packet. */
        !           464:   buffer_clear(&incoming_packet);
        !           465:   buffer_append_space(&incoming_packet, &cp, padded_len);
        !           466:   packet_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len);
        !           467:   buffer_consume(&input, padded_len);
        !           468:
        !           469: #ifdef PACKET_DEBUG
        !           470:   fprintf(stderr, "read_poll plain: "); buffer_dump(&incoming_packet);
        !           471: #endif
        !           472:
        !           473:   /* Compute packet checksum. */
        !           474:   checksum = crc32((unsigned char *)buffer_ptr(&incoming_packet),
        !           475:                   buffer_len(&incoming_packet) - 4);
        !           476:
        !           477:   /* Skip padding. */
        !           478:   buffer_consume(&incoming_packet, 8 - len % 8);
        !           479:
        !           480:   /* Test check bytes. */
        !           481:   assert(len == buffer_len(&incoming_packet));
        !           482:   ucp = (unsigned char *)buffer_ptr(&incoming_packet) + len - 4;
        !           483:   stored_checksum = GET_32BIT(ucp);
        !           484:   if (checksum != stored_checksum)
        !           485:     packet_disconnect("Corrupted check bytes on input.");
        !           486:   buffer_consume_end(&incoming_packet, 4);
        !           487:
        !           488: #ifdef WITH_ZLIB
        !           489:   /* If using packet compression, decompress the packet. */
        !           490:   if (packet_compression)
        !           491:     {
        !           492:       buffer_clear(&compression_buffer);
        !           493:       buffer_uncompress(&incoming_packet, &compression_buffer);
        !           494:       buffer_clear(&incoming_packet);
        !           495:       buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
        !           496:                    buffer_len(&compression_buffer));
        !           497:     }
        !           498: #endif /* WITH_ZLIB */
        !           499:
        !           500:   /* Get packet type. */
        !           501:   buffer_get(&incoming_packet, &buf[0], 1);
        !           502:
        !           503:   /* Return length of payload (without type field). */
        !           504:   *payload_len_ptr = buffer_len(&incoming_packet);
        !           505:
        !           506:   /* Handle disconnect message. */
        !           507:   if ((unsigned char)buf[0] == SSH_MSG_DISCONNECT)
        !           508:     fatal("%.900s", packet_get_string(NULL));
        !           509:
        !           510:   /* Ignore ignore messages. */
        !           511:   if ((unsigned char)buf[0] == SSH_MSG_IGNORE)
        !           512:     goto restart;
        !           513:
        !           514:   /* Send debug messages as debugging output. */
        !           515:   if ((unsigned char)buf[0] == SSH_MSG_DEBUG)
        !           516:     {
        !           517:       debug("Remote: %.900s", packet_get_string(NULL));
        !           518:       goto restart;
        !           519:     }
        !           520:
        !           521:   /* Return type. */
        !           522:   return (unsigned char)buf[0];
        !           523: }
        !           524:
        !           525: /* Buffers the given amount of input characters.  This is intended to be
        !           526:    used together with packet_read_poll. */
        !           527:
        !           528: void packet_process_incoming(const char *buf, unsigned int len)
        !           529: {
        !           530:   buffer_append(&input, buf, len);
        !           531: }
        !           532:
        !           533: /* Returns a character from the packet. */
        !           534:
        !           535: unsigned int packet_get_char()
        !           536: {
        !           537:   char ch;
        !           538:   buffer_get(&incoming_packet, &ch, 1);
        !           539:   return (unsigned char)ch;
        !           540: }
        !           541:
        !           542: /* Returns an integer from the packet data. */
        !           543:
        !           544: unsigned int packet_get_int()
        !           545: {
        !           546:   return buffer_get_int(&incoming_packet);
        !           547: }
        !           548:
        !           549: /* Returns an arbitrary precision integer from the packet data.  The integer
        !           550:    must have been initialized before this call. */
        !           551:
        !           552: void packet_get_mp_int(MP_INT *value, int *length_ptr)
        !           553: {
        !           554:   *length_ptr = buffer_get_mp_int(&incoming_packet, value);
        !           555: }
        !           556:
        !           557: /* Returns a string from the packet data.  The string is allocated using
        !           558:    xmalloc; it is the responsibility of the calling program to free it when
        !           559:    no longer needed.  The length_ptr argument may be NULL, or point to an
        !           560:    integer into which the length of the string is stored. */
        !           561:
        !           562: char *packet_get_string(unsigned int *length_ptr)
        !           563: {
        !           564:   return buffer_get_string(&incoming_packet, length_ptr);
        !           565: }
        !           566:
        !           567: /* Sends a diagnostic message from the server to the client.  This message
        !           568:    can be sent at any time (but not while constructing another message).
        !           569:    The message is printed immediately, but only if the client is being
        !           570:    executed in verbose mode.  These messages are primarily intended to
        !           571:    ease debugging authentication problems.   The length of the formatted
        !           572:    message must not exceed 1024 bytes.  This will automatically call
        !           573:    packet_write_wait. */
        !           574:
        !           575: void packet_send_debug(const char *fmt, ...)
        !           576: {
        !           577:   char buf[1024];
        !           578:   va_list args;
        !           579:
        !           580:   va_start(args, fmt);
        !           581:   vsnprintf(buf, sizeof(buf), fmt, args);
        !           582:   va_end(args);
        !           583:
        !           584:   packet_start(SSH_MSG_DEBUG);
        !           585:   packet_put_string(buf, strlen(buf));
        !           586:   packet_send();
        !           587:   packet_write_wait();
        !           588: }
        !           589:
        !           590: /* Logs the error plus constructs and sends a disconnect
        !           591:    packet, closes the connection, and exits.  This function never returns.
        !           592:    The error message should not contain a newline.  The length of the
        !           593:    formatted message must not exceed 1024 bytes. */
        !           594:
        !           595: void packet_disconnect(const char *fmt, ...)
        !           596: {
        !           597:   char buf[1024];
        !           598:   va_list args;
        !           599:   static int disconnecting = 0;
        !           600:   if (disconnecting) /* Guard against recursive invocations. */
        !           601:     fatal("packet_disconnect called recursively.");
        !           602:   disconnecting = 1;
        !           603:
        !           604:   /* Format the message.  Note that the caller must make sure the message
        !           605:      is of limited size. */
        !           606:   va_start(args, fmt);
        !           607:   vsnprintf(buf, sizeof(buf), fmt, args);
        !           608:   va_end(args);
        !           609:
        !           610:   /* Send the disconnect message to the other side, and wait for it to get
        !           611:      sent. */
        !           612:   packet_start(SSH_MSG_DISCONNECT);
        !           613:   packet_put_string(buf, strlen(buf));
        !           614:   packet_send();
        !           615:   packet_write_wait();
        !           616:
        !           617:   /* Stop listening for connections. */
        !           618:   channel_stop_listening();
        !           619:
        !           620:   /* Close the connection. */
        !           621:   packet_close();
        !           622:
        !           623:   /* Display the error locally and exit. */
        !           624:   fatal("Local: %.100s", buf);
        !           625: }
        !           626:
        !           627: /* Checks if there is any buffered output, and tries to write some of the
        !           628:    output. */
        !           629:
        !           630: void packet_write_poll()
        !           631: {
        !           632:   int len = buffer_len(&output);
        !           633:   if (len > 0)
        !           634:     {
        !           635:       len = write(connection_out, buffer_ptr(&output), len);
        !           636:       if (len <= 0)
        !           637:        if (errno == EAGAIN)
        !           638:          return;
        !           639:         else
        !           640:          fatal("Write failed: %.100s", strerror(errno));
        !           641:       buffer_consume(&output, len);
        !           642:     }
        !           643: }
        !           644:
        !           645: /* Calls packet_write_poll repeatedly until all pending output data has
        !           646:    been written. */
        !           647:
        !           648: void packet_write_wait()
        !           649: {
        !           650:   packet_write_poll();
        !           651:   while (packet_have_data_to_write())
        !           652:     {
        !           653:       fd_set set;
        !           654:       FD_ZERO(&set);
        !           655:       FD_SET(connection_out, &set);
        !           656:       select(connection_out + 1, NULL, &set, NULL, NULL);
        !           657:       packet_write_poll();
        !           658:     }
        !           659: }
        !           660:
        !           661: /* Returns true if there is buffered data to write to the connection. */
        !           662:
        !           663: int packet_have_data_to_write()
        !           664: {
        !           665:   return buffer_len(&output) != 0;
        !           666: }
        !           667:
        !           668: /* Returns true if there is not too much data to write to the connection. */
        !           669:
        !           670: int packet_not_very_much_data_to_write()
        !           671: {
        !           672:   if (interactive_mode)
        !           673:     return buffer_len(&output) < 16384;
        !           674:   else
        !           675:     return buffer_len(&output) < 128*1024;
        !           676: }
        !           677:
        !           678: /* Informs that the current session is interactive.  Sets IP flags for that. */
        !           679:
        !           680: void packet_set_interactive(int interactive, int keepalives)
        !           681: {
        !           682:   int on = 1;
        !           683:
        !           684:   /* Record that we are in interactive mode. */
        !           685:   interactive_mode = interactive;
        !           686:
        !           687:   /* Only set socket options if using a socket (as indicated by the descriptors
        !           688:      being the same). */
        !           689:   if (connection_in != connection_out)
        !           690:     return;
        !           691:
        !           692:   if (keepalives)
        !           693:     {
        !           694:       /* Set keepalives if requested. */
        !           695:       if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
        !           696:                     sizeof(on)) < 0)
        !           697:        error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
        !           698:     }
        !           699:
        !           700:   if (interactive)
        !           701:     {
        !           702:       /* Set IP options for an interactive connection.  Use IPTOS_LOWDELAY
        !           703:         and TCP_NODELAY. */
        !           704: #ifdef IPTOS_LOWDELAY
        !           705:       int lowdelay = IPTOS_LOWDELAY;
        !           706:       if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&lowdelay,
        !           707:                     sizeof(lowdelay)) < 0)
        !           708:        error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno));
        !           709: #endif /* IPTOS_LOWDELAY */
        !           710:       if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *)&on,
        !           711:                     sizeof(on)) < 0)
        !           712:        error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
        !           713:     }
        !           714:   else
        !           715:     {
        !           716:       /* Set IP options for a non-interactive connection.  Use
        !           717:         IPTOS_THROUGHPUT. */
        !           718: #ifdef IPTOS_THROUGHPUT
        !           719:       int throughput = IPTOS_THROUGHPUT;
        !           720:       if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&throughput,
        !           721:                     sizeof(throughput)) < 0)
        !           722:        error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
        !           723: #endif /* IPTOS_THROUGHPUT */
        !           724:     }
        !           725: }
        !           726:
        !           727: /* Returns true if the current connection is interactive. */
        !           728:
        !           729: int packet_is_interactive()
        !           730: {
        !           731:   return interactive_mode;
        !           732: }