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

Annotation of src/usr.bin/ssh/roaming_client.c, Revision 1.7

1.7     ! djm         1: /* $OpenBSD: roaming_client.c,v 1.6 2013/10/16 02:31:46 djm Exp $ */
1.1       andreas     2: /*
                      3:  * Copyright (c) 2004-2009 AppGate Network Security AB
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17:
                     18: #include <sys/queue.h>
                     19: #include <sys/types.h>
                     20: #include <sys/socket.h>
                     21:
                     22: #include <inttypes.h>
                     23: #include <signal.h>
                     24: #include <string.h>
                     25: #include <unistd.h>
                     26:
                     27: #include <openssl/crypto.h>
                     28: #include <openssl/sha.h>
                     29:
                     30: #include "xmalloc.h"
                     31: #include "buffer.h"
                     32: #include "channels.h"
                     33: #include "cipher.h"
                     34: #include "dispatch.h"
                     35: #include "clientloop.h"
                     36: #include "log.h"
                     37: #include "match.h"
                     38: #include "misc.h"
                     39: #include "packet.h"
                     40: #include "ssh.h"
                     41: #include "key.h"
                     42: #include "kex.h"
                     43: #include "readconf.h"
                     44: #include "roaming.h"
                     45: #include "ssh2.h"
                     46: #include "sshconnect.h"
1.7     ! djm        47: #include "digest.h"
1.1       andreas    48:
                     49: /* import */
                     50: extern Options options;
                     51: extern char *host;
                     52: extern struct sockaddr_storage hostaddr;
                     53: extern int session_resumed;
                     54:
                     55: static u_int32_t roaming_id;
                     56: static u_int64_t cookie;
                     57: static u_int64_t lastseenchall;
                     58: static u_int64_t key1, key2, oldkey1, oldkey2;
                     59:
                     60: void
                     61: roaming_reply(int type, u_int32_t seq, void *ctxt)
                     62: {
                     63:        if (type == SSH2_MSG_REQUEST_FAILURE) {
                     64:                logit("Server denied roaming");
                     65:                return;
                     66:        }
                     67:        verbose("Roaming enabled");
                     68:        roaming_id = packet_get_int();
                     69:        cookie = packet_get_int64();
                     70:        key1 = oldkey1 = packet_get_int64();
                     71:        key2 = oldkey2 = packet_get_int64();
1.4       djm        72:        set_out_buffer_size(packet_get_int() + get_snd_buf_size());
1.1       andreas    73:        roaming_enabled = 1;
                     74: }
                     75:
                     76: void
                     77: request_roaming(void)
                     78: {
                     79:        packet_start(SSH2_MSG_GLOBAL_REQUEST);
                     80:        packet_put_cstring(ROAMING_REQUEST);
                     81:        packet_put_char(1);
                     82:        packet_put_int(get_recv_buf_size());
                     83:        packet_send();
                     84:        client_register_global_confirm(roaming_reply, NULL);
                     85: }
                     86:
                     87: static void
                     88: roaming_auth_required(void)
                     89: {
1.7     ! djm        90:        u_char digest[SSH_DIGEST_MAX_LENGTH];
1.1       andreas    91:        Buffer b;
                     92:        u_int64_t chall, oldchall;
                     93:
                     94:        chall = packet_get_int64();
                     95:        oldchall = packet_get_int64();
                     96:        if (oldchall != lastseenchall) {
                     97:                key1 = oldkey1;
                     98:                key2 = oldkey2;
                     99:        }
                    100:        lastseenchall = chall;
                    101:
                    102:        buffer_init(&b);
                    103:        buffer_put_int64(&b, cookie);
                    104:        buffer_put_int64(&b, chall);
1.7     ! djm       105:        if (ssh_digest_buffer(SSH_DIGEST_SHA1, &b, digest, sizeof(digest)) != 0)
        !           106:                fatal("%s: ssh_digest_buffer failed", __func__);
1.1       andreas   107:        buffer_free(&b);
                    108:
                    109:        packet_start(SSH2_MSG_KEX_ROAMING_AUTH);
                    110:        packet_put_int64(key1 ^ get_recv_bytes());
1.7     ! djm       111:        packet_put_raw(digest, ssh_digest_bytes(SSH_DIGEST_SHA1));
1.1       andreas   112:        packet_send();
                    113:
                    114:        oldkey1 = key1;
                    115:        oldkey2 = key2;
                    116:        calculate_new_key(&key1, cookie, chall);
                    117:        calculate_new_key(&key2, cookie, chall);
                    118:
1.3       dtucker   119:        debug("Received %llu bytes", (unsigned long long)get_recv_bytes());
1.1       andreas   120:        debug("Sent roaming_auth packet");
                    121: }
                    122:
                    123: int
                    124: resume_kex(void)
                    125: {
                    126:        /*
                    127:         * This should not happen - if the client sends the kex method
                    128:         * resume@appgate.com then the kex is done in roaming_resume().
                    129:         */
                    130:        return 1;
                    131: }
                    132:
                    133: static int
                    134: roaming_resume(void)
                    135: {
                    136:        u_int64_t recv_bytes;
                    137:        char *str = NULL, *kexlist = NULL, *c;
                    138:        int i, type;
                    139:        int timeout_ms = options.connection_timeout * 1000;
                    140:        u_int len;
                    141:        u_int32_t rnd = 0;
                    142:
                    143:        resume_in_progress = 1;
                    144:
                    145:        /* Exchange banners */
                    146:        ssh_exchange_identification(timeout_ms);
                    147:        packet_set_nonblocking();
                    148:
                    149:        /* Send a kexinit message with resume@appgate.com as only kex algo */
                    150:        packet_start(SSH2_MSG_KEXINIT);
                    151:        for (i = 0; i < KEX_COOKIE_LEN; i++) {
                    152:                if (i % 4 == 0)
                    153:                        rnd = arc4random();
                    154:                packet_put_char(rnd & 0xff);
                    155:                rnd >>= 8;
                    156:        }
                    157:        packet_put_cstring(KEX_RESUME);
                    158:        for (i = 1; i < PROPOSAL_MAX; i++) {
                    159:                /* kex algorithm added so start with i=1 and not 0 */
                    160:                packet_put_cstring(""); /* Not used when we resume */
                    161:        }
                    162:        packet_put_char(1); /* first kex_packet follows */
                    163:        packet_put_int(0); /* reserved */
                    164:        packet_send();
                    165:
                    166:        /* Assume that resume@appgate.com will be accepted */
                    167:        packet_start(SSH2_MSG_KEX_ROAMING_RESUME);
                    168:        packet_put_int(roaming_id);
                    169:        packet_send();
                    170:
                    171:        /* Read the server's kexinit and check for resume@appgate.com */
                    172:        if ((type = packet_read()) != SSH2_MSG_KEXINIT) {
                    173:                debug("expected kexinit on resume, got %d", type);
                    174:                goto fail;
                    175:        }
                    176:        for (i = 0; i < KEX_COOKIE_LEN; i++)
                    177:                (void)packet_get_char();
                    178:        kexlist = packet_get_string(&len);
                    179:        if (!kexlist
                    180:            || (str = match_list(KEX_RESUME, kexlist, NULL)) == NULL) {
                    181:                debug("server doesn't allow resume");
                    182:                goto fail;
                    183:        }
1.5       djm       184:        free(str);
1.1       andreas   185:        for (i = 1; i < PROPOSAL_MAX; i++) {
                    186:                /* kex algorithm taken care of so start with i=1 and not 0 */
1.5       djm       187:                free(packet_get_string(&len));
1.1       andreas   188:        }
                    189:        i = packet_get_char(); /* first_kex_packet_follows */
                    190:        if (i && (c = strchr(kexlist, ',')))
                    191:                *c = 0;
                    192:        if (i && strcmp(kexlist, KEX_RESUME)) {
                    193:                debug("server's kex guess (%s) was wrong, skipping", kexlist);
                    194:                (void)packet_read(); /* Wrong guess - discard packet */
                    195:        }
                    196:
                    197:        /*
                    198:         * Read the ROAMING_AUTH_REQUIRED challenge from the server and
                    199:         * send ROAMING_AUTH
                    200:         */
                    201:        if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_REQUIRED) {
                    202:                debug("expected roaming_auth_required, got %d", type);
                    203:                goto fail;
                    204:        }
                    205:        roaming_auth_required();
                    206:
                    207:        /* Read ROAMING_AUTH_OK from the server */
                    208:        if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_OK) {
                    209:                debug("expected roaming_auth_ok, got %d", type);
                    210:                goto fail;
                    211:        }
                    212:        recv_bytes = packet_get_int64() ^ oldkey2;
1.3       dtucker   213:        debug("Peer received %llu bytes", (unsigned long long)recv_bytes);
1.1       andreas   214:        resend_bytes(packet_get_connection_out(), &recv_bytes);
                    215:
                    216:        resume_in_progress = 0;
                    217:
                    218:        session_resumed = 1; /* Tell clientloop */
                    219:
                    220:        return 0;
                    221:
                    222: fail:
1.5       djm       223:        free(kexlist);
1.1       andreas   224:        if (packet_get_connection_in() == packet_get_connection_out())
                    225:                close(packet_get_connection_in());
                    226:        else {
                    227:                close(packet_get_connection_in());
                    228:                close(packet_get_connection_out());
                    229:        }
                    230:        return 1;
                    231: }
                    232:
                    233: int
                    234: wait_for_roaming_reconnect(void)
                    235: {
                    236:        static int reenter_guard = 0;
                    237:        int timeout_ms = options.connection_timeout * 1000;
                    238:        int c;
                    239:
                    240:        if (reenter_guard != 0)
                    241:                fatal("Server refused resume, roaming timeout may be exceeded");
                    242:        reenter_guard = 1;
                    243:
                    244:        fprintf(stderr, "[connection suspended, press return to resume]");
                    245:        fflush(stderr);
                    246:        packet_backup_state();
                    247:        /* TODO Perhaps we should read from tty here */
                    248:        while ((c = fgetc(stdin)) != EOF) {
                    249:                if (c == 'Z' - 64) {
                    250:                        kill(getpid(), SIGTSTP);
                    251:                        continue;
                    252:                }
                    253:                if (c != '\n' && c != '\r')
                    254:                        continue;
                    255:
1.6       djm       256:                if (ssh_connect(host, NULL, &hostaddr, options.port,
1.1       andreas   257:                    options.address_family, 1, &timeout_ms,
1.6       djm       258:                    options.tcp_keep_alive, options.use_privileged_port) == 0 &&
                    259:                    roaming_resume() == 0) {
1.1       andreas   260:                        packet_restore_state();
                    261:                        reenter_guard = 0;
                    262:                        fprintf(stderr, "[connection resumed]\n");
                    263:                        fflush(stderr);
                    264:                        return 0;
                    265:                }
                    266:
                    267:                fprintf(stderr, "[reconnect failed, press return to retry]");
                    268:                fflush(stderr);
                    269:        }
                    270:        fprintf(stderr, "[exiting]\n");
                    271:        fflush(stderr);
                    272:        exit(0);
                    273: }