Coverage Report

Created: 2026-01-09 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/src/messages.c
Line
Count
Source
1
/*
2
 * messages.c - message parsing for client and server
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2003-2013 by Aris Adamantiadis
7
 *
8
 * The SSH Library is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or (at your
11
 * option) any later version.
12
 *
13
 * The SSH Library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16
 * License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with the SSH Library; see the file COPYING.  If not, write to
20
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21
 * MA 02111-1307, USA.
22
 */
23
24
#include "config.h"
25
26
#include <string.h>
27
#include <stdlib.h>
28
29
#ifndef _WIN32
30
#include <netinet/in.h>
31
#include <arpa/inet.h>
32
#endif
33
34
#include "libssh/libssh.h"
35
#include "libssh/priv.h"
36
#include "libssh/ssh2.h"
37
#include "libssh/buffer.h"
38
#include "libssh/packet.h"
39
#include "libssh/channels.h"
40
#include "libssh/session.h"
41
#include "libssh/misc.h"
42
#include "libssh/pki.h"
43
#include "libssh/messages.h"
44
#include "libssh/socket.h"
45
#ifdef WITH_SERVER
46
#include "libssh/server.h"
47
#include "libssh/gssapi.h"
48
#endif
49
50
/**
51
 * @defgroup libssh_messages The SSH message functions
52
 * @ingroup libssh
53
 *
54
 * This file contains the message parsing utilities for client and server
55
 * programs using libssh.
56
 *
57
 * On the server the main loop of the program will call
58
 * ssh_message_get(session) to get messages as they come. They are not 1-1 with
59
 * the protocol messages. Then, the user will know what kind of a message it is
60
 * and use the appropriate functions to handle it (or use the default handlers
61
 * if you don't know what to do).
62
 *
63
 * @{
64
 */
65
66
static ssh_message ssh_message_new(ssh_session session)
67
0
{
68
0
    ssh_message msg = calloc(1, sizeof(struct ssh_message_struct));
69
0
    if (msg == NULL) {
70
0
        return NULL;
71
0
    }
72
0
    msg->session = session;
73
74
    /* Set states explicitly */
75
0
    msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_NONE;
76
77
0
    return msg;
78
0
}
79
80
#ifndef WITH_SERVER
81
82
/* Reduced version of the reply default that only replies with
83
 * SSH_MSG_UNIMPLEMENTED
84
 */
85
static int ssh_message_reply_default(ssh_message msg) {
86
  SSH_LOG(SSH_LOG_FUNCTIONS, "Reporting unknown packet");
87
88
  if (ssh_buffer_add_u8(msg->session->out_buffer, SSH2_MSG_UNIMPLEMENTED) < 0)
89
    goto error;
90
  if (ssh_buffer_add_u32(msg->session->out_buffer,
91
      htonl(msg->session->recv_seq-1)) < 0)
92
    goto error;
93
  return ssh_packet_send(msg->session);
94
  error:
95
  return SSH_ERROR;
96
}
97
98
#endif
99
100
static int ssh_send_disconnect(ssh_session session)
101
0
{
102
0
    int rc = SSH_ERROR;
103
104
0
    if (session == NULL) {
105
0
        return SSH_ERROR;
106
0
    }
107
108
0
    if (session->disconnect_message == NULL) {
109
0
        session->disconnect_message = strdup("Bye Bye");
110
0
        if (session->disconnect_message == NULL) {
111
0
            ssh_set_error_oom(session);
112
0
            return SSH_ERROR;
113
0
        }
114
0
    }
115
116
0
    if (session->socket != NULL && ssh_socket_is_open(session->socket)) {
117
0
        rc = ssh_buffer_pack(session->out_buffer,
118
0
                             "bdss",
119
0
                             SSH2_MSG_DISCONNECT,
120
0
                             SSH2_DISCONNECT_BY_APPLICATION,
121
0
                             session->disconnect_message,
122
0
                             ""); /* language tag */
123
0
        if (rc != SSH_OK) {
124
0
            ssh_set_error_oom(session);
125
0
            return SSH_ERROR;
126
0
        }
127
128
0
        rc = ssh_packet_send(session);
129
0
        ssh_session_socket_close(session);
130
0
    }
131
132
0
    return rc;
133
0
}
134
135
#ifdef WITH_SERVER
136
137
static int ssh_execute_server_request(ssh_session session, ssh_message msg)
138
0
{
139
0
    ssh_channel channel = NULL;
140
0
    int rc;
141
142
0
    switch(msg->type) {
143
0
        case SSH_REQUEST_AUTH:
144
0
            if (msg->auth_request.method == SSH_AUTH_METHOD_PASSWORD &&
145
0
                ssh_callbacks_exists(session->server_callbacks, auth_password_function)) {
146
0
                rc = session->server_callbacks->auth_password_function(session,
147
0
                        msg->auth_request.username, msg->auth_request.password,
148
0
                        session->server_callbacks->userdata);
149
0
                if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) {
150
0
                    ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
151
0
                } else {
152
0
                    ssh_message_reply_default(msg);
153
0
                }
154
155
0
                return SSH_OK;
156
0
            } else if(msg->auth_request.method == SSH_AUTH_METHOD_PUBLICKEY &&
157
0
                      ssh_callbacks_exists(session->server_callbacks, auth_pubkey_function)) {
158
0
               rc = session->server_callbacks->auth_pubkey_function(session,
159
0
                       msg->auth_request.username, msg->auth_request.pubkey,
160
0
                       msg->auth_request.signature_state,
161
0
                       session->server_callbacks->userdata);
162
0
               if (msg->auth_request.signature_state != SSH_PUBLICKEY_STATE_NONE) {
163
0
                 if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) {
164
0
                   ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
165
0
                 } else {
166
0
                   ssh_message_reply_default(msg);
167
0
                 }
168
0
               } else {
169
0
                 if (rc == SSH_AUTH_SUCCESS) {
170
0
                   ssh_message_auth_reply_pk_ok_simple(msg);
171
0
                 } else {
172
0
                   ssh_message_reply_default(msg);
173
0
                 }
174
0
               }
175
176
0
               return SSH_OK;
177
0
            } else if (msg->auth_request.method == SSH_AUTH_METHOD_NONE &&
178
0
                       ssh_callbacks_exists(session->server_callbacks, auth_none_function)) {
179
0
                rc = session->server_callbacks->auth_none_function(session,
180
0
                    msg->auth_request.username, session->server_callbacks->userdata);
181
0
                if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){
182
0
                    ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
183
0
                } else {
184
0
                    ssh_message_reply_default(msg);
185
0
                }
186
187
0
                return SSH_OK;
188
0
            } else if (msg->auth_request.method == SSH_AUTH_METHOD_INTERACTIVE &&
189
0
                       ssh_callbacks_exists(session->server_callbacks, auth_kbdint_function)) {
190
0
                rc = session->server_callbacks->auth_kbdint_function(msg,
191
0
                                                                     session,
192
0
                                                                     session->server_callbacks->userdata);
193
0
                if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) {
194
0
                    ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
195
0
                } else if (rc == SSH_AUTH_INFO) {
196
0
                    return SSH_OK;
197
0
                } else {
198
0
                    ssh_message_reply_default(msg);
199
0
                }
200
0
                return SSH_OK;
201
0
            }
202
0
            break;
203
0
        case SSH_REQUEST_CHANNEL_OPEN:
204
0
            if (msg->channel_request_open.type == SSH_CHANNEL_SESSION &&
205
0
                ssh_callbacks_exists(session->server_callbacks, channel_open_request_session_function)) {
206
0
                channel = session->server_callbacks->channel_open_request_session_function(session,
207
0
                        session->server_callbacks->userdata);
208
0
                if (channel != NULL) {
209
0
                    rc = ssh_message_channel_request_open_reply_accept_channel(msg, channel);
210
0
                    if (rc != SSH_OK) {
211
0
                        SSH_LOG(SSH_LOG_TRACE,
212
0
                                "Failed to send reply for accepting a channel "
213
0
                                "open");
214
0
                    }
215
0
                    return SSH_OK;
216
0
                } else {
217
0
                    ssh_message_reply_default(msg);
218
0
                }
219
220
0
                return SSH_OK;
221
0
#define CB channel_open_request_direct_tcpip_function
222
0
            } else if (msg->channel_request_open.type == SSH_CHANNEL_DIRECT_TCPIP &&
223
0
                       ssh_callbacks_exists(session->server_callbacks, CB)) {
224
0
                struct ssh_channel_request_open *rq = &msg->channel_request_open;
225
0
                channel = session->server_callbacks->CB(session,
226
0
                                                        rq->destination,
227
0
                                                        rq->destination_port,
228
0
                                                        rq->originator,
229
0
                                                        rq->originator_port,
230
0
                                                        session->server_callbacks->userdata);
231
0
#undef CB
232
0
                if (channel != NULL) {
233
0
                    rc = ssh_message_channel_request_open_reply_accept_channel(
234
0
                        msg,
235
0
                        channel);
236
0
                    if (rc != SSH_OK) {
237
0
                        SSH_LOG(SSH_LOG_TRACE,
238
0
                                "Failed to send reply for accepting a channel "
239
0
                                "open");
240
0
                    }
241
0
                    return SSH_OK;
242
0
                } else {
243
0
                    ssh_message_reply_default(msg);
244
0
                }
245
246
0
                return SSH_OK;
247
0
            }
248
249
0
            break;
250
0
        case SSH_REQUEST_CHANNEL:
251
0
            channel = msg->channel_request.channel;
252
253
0
            if (msg->channel_request.type == SSH_CHANNEL_REQUEST_PTY){
254
0
                ssh_callbacks_iterate(channel->callbacks,
255
0
                                      ssh_channel_callbacks,
256
0
                                      channel_pty_request_function) {
257
0
                    rc = ssh_callbacks_iterate_exec(channel_pty_request_function,
258
0
                                                    session,
259
0
                                                    channel,
260
0
                                                    msg->channel_request.TERM,
261
0
                                                    msg->channel_request.width,
262
0
                                                    msg->channel_request.height,
263
0
                                                    msg->channel_request.pxwidth,
264
0
                                                    msg->channel_request.pxheight);
265
0
                    if (rc == 0) {
266
0
                        ssh_message_channel_request_reply_success(msg);
267
0
                    } else {
268
0
                        ssh_message_reply_default(msg);
269
0
                    }
270
0
                    return SSH_OK;
271
0
                }
272
0
                ssh_callbacks_iterate_end();
273
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_SHELL){
274
0
                ssh_callbacks_iterate(channel->callbacks,
275
0
                                      ssh_channel_callbacks,
276
0
                                      channel_shell_request_function) {
277
0
                    rc = ssh_callbacks_iterate_exec(channel_shell_request_function,
278
0
                                                    session,
279
0
                                                    channel);
280
0
                    if (rc == 0) {
281
0
                        ssh_message_channel_request_reply_success(msg);
282
0
                    } else {
283
0
                        ssh_message_reply_default(msg);
284
0
                    }
285
0
                    return SSH_OK;
286
0
                }
287
0
                ssh_callbacks_iterate_end();
288
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_X11){
289
0
                ssh_callbacks_iterate(channel->callbacks,
290
0
                                      ssh_channel_callbacks,
291
0
                                      channel_x11_req_function) {
292
0
                    ssh_callbacks_iterate_exec(channel_x11_req_function,
293
0
                                               session,
294
0
                                               channel,
295
0
                                               msg->channel_request.x11_single_connection,
296
0
                                               msg->channel_request.x11_auth_protocol,
297
0
                                               msg->channel_request.x11_auth_cookie,
298
0
                                               msg->channel_request.x11_screen_number);
299
0
                    ssh_message_channel_request_reply_success(msg);
300
0
                    return SSH_OK;
301
0
                }
302
0
                ssh_callbacks_iterate_end();
303
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_WINDOW_CHANGE){
304
0
                ssh_callbacks_iterate(channel->callbacks,
305
0
                                      ssh_channel_callbacks,
306
0
                                      channel_pty_window_change_function) {
307
0
                    rc = ssh_callbacks_iterate_exec(channel_pty_window_change_function,
308
0
                                                    session,
309
0
                                                    channel,
310
0
                                                    msg->channel_request.width,
311
0
                                                    msg->channel_request.height,
312
0
                                                    msg->channel_request.pxwidth,
313
0
                                                    msg->channel_request.pxheight);
314
0
                    if (rc != SSH_OK) {
315
0
                        SSH_LOG(SSH_LOG_TRACE,
316
0
                                "Failed to iterate callbacks for window change");
317
0
                    }
318
0
                    return SSH_OK;
319
0
                }
320
0
                ssh_callbacks_iterate_end();
321
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_EXEC){
322
0
                ssh_callbacks_iterate(channel->callbacks,
323
0
                                      ssh_channel_callbacks,
324
0
                                      channel_exec_request_function) {
325
0
                    rc = ssh_callbacks_iterate_exec(channel_exec_request_function,
326
0
                                                    session,
327
0
                                                    channel,
328
0
                                                    msg->channel_request.command);
329
0
                    if (rc == 0) {
330
0
                        ssh_message_channel_request_reply_success(msg);
331
0
                    } else {
332
0
                        ssh_message_reply_default(msg);
333
0
                    }
334
335
0
                    return SSH_OK;
336
0
                }
337
0
                ssh_callbacks_iterate_end();
338
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_ENV){
339
0
                ssh_callbacks_iterate(channel->callbacks,
340
0
                                      ssh_channel_callbacks,
341
0
                                      channel_env_request_function) {
342
0
                    rc = ssh_callbacks_iterate_exec(channel_env_request_function,
343
0
                                                    session,
344
0
                                                    channel,
345
0
                                                    msg->channel_request.var_name,
346
0
                                                    msg->channel_request.var_value);
347
0
                    if (rc == 0) {
348
0
                        ssh_message_channel_request_reply_success(msg);
349
0
                    } else {
350
0
                        ssh_message_reply_default(msg);
351
0
                    }
352
0
                    return SSH_OK;
353
0
                }
354
0
                ssh_callbacks_iterate_end();
355
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_SUBSYSTEM){
356
0
                ssh_callbacks_iterate(channel->callbacks,
357
0
                                      ssh_channel_callbacks,
358
0
                                      channel_subsystem_request_function) {
359
0
                    rc = ssh_callbacks_iterate_exec(channel_subsystem_request_function,
360
0
                                                    session,
361
0
                                                    channel,
362
0
                                                    msg->channel_request.subsystem);
363
0
                    if (rc == 0) {
364
0
                        ssh_message_channel_request_reply_success(msg);
365
0
                    } else {
366
0
                        ssh_message_reply_default(msg);
367
0
                    }
368
369
0
                    return SSH_OK;
370
0
                }
371
0
                ssh_callbacks_iterate_end();
372
0
            }
373
0
            break;
374
0
        case SSH_REQUEST_SERVICE:
375
0
            if (ssh_callbacks_exists(session->server_callbacks, service_request_function)) {
376
0
                rc = session->server_callbacks->service_request_function(session,
377
0
                        msg->service_request.service, session->server_callbacks->userdata);
378
0
                if (rc == 0) {
379
0
                    ssh_message_reply_default(msg);
380
0
                } else {
381
0
                    ssh_send_disconnect(session);
382
0
                }
383
384
0
                return SSH_OK;
385
0
            }
386
387
0
            return SSH_AGAIN;
388
0
        case SSH_REQUEST_GLOBAL:
389
0
            break;
390
0
    }
391
392
0
    return SSH_AGAIN;
393
0
}
394
395
static int ssh_reply_channel_open_request(ssh_message msg, ssh_channel channel)
396
0
{
397
0
    if (channel != NULL) {
398
0
        return ssh_message_channel_request_open_reply_accept_channel(msg, channel);
399
0
    }
400
401
0
    ssh_message_reply_default(msg);
402
403
0
    return SSH_OK;
404
0
}
405
406
static int ssh_execute_client_request(ssh_session session, ssh_message msg)
407
0
{
408
0
    ssh_channel channel = NULL;
409
0
    int rc = SSH_AGAIN;
410
411
0
    if (msg->type == SSH_REQUEST_CHANNEL_OPEN
412
0
        && msg->channel_request_open.type == SSH_CHANNEL_X11
413
0
        && ssh_callbacks_exists(session->common.callbacks, channel_open_request_x11_function)) {
414
0
        channel = session->common.callbacks->channel_open_request_x11_function (session,
415
0
                msg->channel_request_open.originator,
416
0
                msg->channel_request_open.originator_port,
417
0
                session->common.callbacks->userdata);
418
419
0
        return ssh_reply_channel_open_request(msg, channel);
420
0
    } else if (msg->type == SSH_REQUEST_CHANNEL_OPEN
421
0
               && msg->channel_request_open.type == SSH_CHANNEL_AUTH_AGENT
422
0
               && ssh_callbacks_exists(session->common.callbacks, channel_open_request_auth_agent_function)) {
423
0
        channel = session->common.callbacks->channel_open_request_auth_agent_function (session,
424
0
                session->common.callbacks->userdata);
425
426
0
        return ssh_reply_channel_open_request(msg, channel);
427
0
    } else if (msg->type == SSH_REQUEST_CHANNEL_OPEN
428
0
               && msg->channel_request_open.type == SSH_CHANNEL_FORWARDED_TCPIP
429
0
               && ssh_callbacks_exists(session->common.callbacks, channel_open_request_forwarded_tcpip_function)) {
430
0
        channel = session->common.callbacks->channel_open_request_forwarded_tcpip_function(session,
431
0
                msg->channel_request_open.destination,
432
0
                msg->channel_request_open.destination_port,
433
0
                msg->channel_request_open.originator,
434
0
                msg->channel_request_open.originator_port,
435
0
                session->common.callbacks->userdata);
436
437
0
        return ssh_reply_channel_open_request(msg, channel);
438
0
    }
439
440
0
    return rc;
441
0
}
442
443
/** @internal
444
 * Executes the callbacks defined in session->server_callbacks, out of an ssh_message
445
 * I don't like ssh_message interface but it works.
446
 * @returns SSH_OK if the message has been handled, or SSH_AGAIN otherwise.
447
 */
448
0
static int ssh_execute_server_callbacks(ssh_session session, ssh_message msg){
449
0
    int rc = SSH_AGAIN;
450
451
0
    if (session->server_callbacks != NULL){
452
0
        rc = ssh_execute_server_request(session, msg);
453
0
    } else if (session->common.callbacks != NULL) {
454
        /* This one is in fact a client callback... */
455
0
        rc = ssh_execute_client_request(session, msg);
456
0
    }
457
458
0
    return rc;
459
0
}
460
461
#endif /* WITH_SERVER */
462
463
0
static int ssh_execute_message_callback(ssh_session session, ssh_message msg) {
464
0
  int ret;
465
0
    if(session->ssh_message_callback != NULL) {
466
0
        ret = session->ssh_message_callback(session, msg,
467
0
                session->ssh_message_callback_data);
468
0
        if(ret == 1) {
469
0
            ret = ssh_message_reply_default(msg);
470
0
            SSH_MESSAGE_FREE(msg);
471
0
            if(ret != SSH_OK) {
472
0
                return ret;
473
0
            }
474
0
        } else {
475
0
            SSH_MESSAGE_FREE(msg);
476
0
        }
477
0
    } else {
478
0
        ret = ssh_message_reply_default(msg);
479
0
        SSH_MESSAGE_FREE(msg);
480
0
        if(ret != SSH_OK) {
481
0
            return ret;
482
0
        }
483
0
    }
484
0
    return SSH_OK;
485
0
}
486
487
/**
488
 * @internal
489
 *
490
 * @brief Add a message to the current queue of messages to be parsed and/or call
491
 * the various callback functions.
492
 *
493
 * @param[in]  session  The SSH session to add the message.
494
 *
495
 * @param[in]  message  The message to add to the queue.
496
 */
497
static void ssh_message_queue(ssh_session session, ssh_message message)
498
0
{
499
0
#ifdef WITH_SERVER
500
0
    int ret;
501
0
#endif
502
503
0
    if (message == NULL) {
504
0
        return;
505
0
    }
506
507
0
#ifdef WITH_SERVER
508
    /* probably not the best place to execute server callbacks, but still better
509
     * than nothing.
510
     */
511
0
    ret = ssh_execute_server_callbacks(session, message);
512
0
    if (ret == SSH_OK) {
513
0
        SSH_MESSAGE_FREE(message);
514
0
        return;
515
0
    }
516
0
#endif /* WITH_SERVER */
517
518
0
    if (session->ssh_message_callback != NULL) {
519
        /* This will transfer the message, do not free. */
520
0
        ssh_execute_message_callback(session, message);
521
0
        return;
522
0
    }
523
524
0
    if (session->server_callbacks != NULL) {
525
        /* if we have server callbacks, but nothing was executed, it means we are
526
         * in non-synchronous mode, and we just don't care about the message we
527
         * received. Just send a default response. Do not queue it.
528
         */
529
0
        ssh_message_reply_default(message);
530
0
        SSH_MESSAGE_FREE(message);
531
0
        return;
532
0
    }
533
534
0
    if (session->ssh_message_list == NULL) {
535
0
        session->ssh_message_list = ssh_list_new();
536
0
        if (session->ssh_message_list == NULL) {
537
            /*
538
             * If the message list couldn't be allocated, the message can't be
539
             * enqueued
540
             */
541
0
            ssh_message_reply_default(message);
542
0
            ssh_set_error_oom(session);
543
0
            SSH_MESSAGE_FREE(message);
544
0
            return;
545
0
        }
546
0
    }
547
548
    /* This will transfer the message, do not free. */
549
0
    ssh_list_append(session->ssh_message_list, message);
550
0
    return;
551
0
}
552
553
/**
554
 * @internal
555
 *
556
 * @brief Pop a message from the message list and dequeue it.
557
 *
558
 * @param[in]  session  The SSH session to pop the message.
559
 *
560
 * @returns             The head message or NULL if it doesn't exist.
561
 */
562
ssh_message ssh_message_pop_head(ssh_session session)
563
0
{
564
0
    ssh_message msg = NULL;
565
0
    struct ssh_iterator *i = NULL;
566
567
0
    if (session->ssh_message_list == NULL)
568
0
        return NULL;
569
570
0
    i = ssh_list_get_iterator(session->ssh_message_list);
571
0
    if (i != NULL) {
572
0
        msg = ssh_iterator_value(ssh_message, i);
573
0
        ssh_list_remove(session->ssh_message_list, i);
574
0
    }
575
0
    return msg;
576
0
}
577
578
/* Returns 1 if there is a message available */
579
static int ssh_message_termination(void *s)
580
0
{
581
0
    ssh_session session = s;
582
0
    struct ssh_iterator *it = NULL;
583
584
0
    if (session->session_state == SSH_SESSION_STATE_ERROR)
585
0
        return 1;
586
587
0
    it = ssh_list_get_iterator(session->ssh_message_list);
588
0
    if (!it)
589
0
        return 0;
590
0
    else
591
0
        return 1;
592
0
}
593
/**
594
 * @brief Retrieve a SSH message from a SSH session.
595
 *
596
 * @param[in]  session  The SSH session to get the message.
597
 *
598
 * @returns             The SSH message received, NULL in case of error, or timeout
599
 *                      elapsed.
600
 *
601
 * @warning This function blocks until a message has been received. Betterset up
602
 *          a callback if this behavior is unwanted.
603
 */
604
ssh_message ssh_message_get(ssh_session session)
605
0
{
606
0
    ssh_message msg = NULL;
607
0
    int rc;
608
609
0
    msg = ssh_message_pop_head(session);
610
0
    if (msg != NULL) {
611
0
        return msg;
612
0
    }
613
0
    if (session->ssh_message_list == NULL) {
614
0
        session->ssh_message_list = ssh_list_new();
615
0
        if (session->ssh_message_list == NULL) {
616
0
            ssh_set_error_oom(session);
617
0
            return NULL;
618
0
        }
619
0
    }
620
0
    rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
621
0
                                        ssh_message_termination, session);
622
0
    if (rc || session->session_state == SSH_SESSION_STATE_ERROR) {
623
0
        return NULL;
624
0
    }
625
0
    msg = ssh_list_pop_head(ssh_message, session->ssh_message_list);
626
627
0
    return msg;
628
0
}
629
630
/**
631
 * @brief Get the type of the message.
632
 *
633
 * @param[in] msg       The message to get the type from.
634
 *
635
 * @return              The message type or -1 on error.
636
 */
637
0
int ssh_message_type(ssh_message msg) {
638
0
  if (msg == NULL) {
639
0
    return -1;
640
0
  }
641
642
0
  return msg->type;
643
0
}
644
645
/**
646
 * @brief Get the subtype of the message.
647
 *
648
 * @param[in] msg       The message to get the subtype from.
649
 *
650
 * @return              The message type or -1 on error.
651
 */
652
0
int ssh_message_subtype(ssh_message msg) {
653
0
  if (msg == NULL) {
654
0
    return -1;
655
0
  }
656
657
0
  switch(msg->type) {
658
0
    case SSH_REQUEST_AUTH:
659
0
      return msg->auth_request.method;
660
0
    case SSH_REQUEST_CHANNEL_OPEN:
661
0
      return msg->channel_request_open.type;
662
0
    case SSH_REQUEST_CHANNEL:
663
0
      return msg->channel_request.type;
664
0
    case SSH_REQUEST_GLOBAL:
665
0
      return msg->global_request.type;
666
0
  }
667
668
0
  return -1;
669
0
}
670
671
/**
672
 * @brief Free a SSH message.
673
 *
674
 * @param[in] msg       The message to release the memory.
675
 */
676
0
void ssh_message_free(ssh_message msg){
677
0
  if (msg == NULL) {
678
0
    return;
679
0
  }
680
681
0
  switch(msg->type) {
682
0
    case SSH_REQUEST_AUTH:
683
0
      SAFE_FREE(msg->auth_request.username);
684
0
      SAFE_FREE(msg->auth_request.sigtype);
685
0
      if (msg->auth_request.password) {
686
0
          ssh_burn(msg->auth_request.password,
687
0
                   strlen(msg->auth_request.password));
688
0
          SAFE_FREE(msg->auth_request.password);
689
0
      }
690
0
      ssh_key_free(msg->auth_request.pubkey);
691
0
      ssh_key_free(msg->auth_request.server_pubkey);
692
0
      break;
693
0
    case SSH_REQUEST_CHANNEL_OPEN:
694
0
      SAFE_FREE(msg->channel_request_open.originator);
695
0
      SAFE_FREE(msg->channel_request_open.destination);
696
0
      break;
697
0
    case SSH_REQUEST_CHANNEL:
698
0
      SAFE_FREE(msg->channel_request.TERM);
699
0
      SAFE_FREE(msg->channel_request.modes);
700
0
      SAFE_FREE(msg->channel_request.var_name);
701
0
      SAFE_FREE(msg->channel_request.var_value);
702
0
      SAFE_FREE(msg->channel_request.command);
703
0
      SAFE_FREE(msg->channel_request.subsystem);
704
0
      switch (msg->channel_request.type) {
705
0
      case SSH_CHANNEL_REQUEST_EXEC:
706
0
          SAFE_FREE(msg->channel_request.command);
707
0
          break;
708
0
      case SSH_CHANNEL_REQUEST_ENV:
709
0
          SAFE_FREE(msg->channel_request.var_name);
710
0
          SAFE_FREE(msg->channel_request.var_value);
711
0
          break;
712
0
      case SSH_CHANNEL_REQUEST_PTY:
713
0
          SAFE_FREE(msg->channel_request.TERM);
714
0
          break;
715
0
      case SSH_CHANNEL_REQUEST_SUBSYSTEM:
716
0
          SAFE_FREE(msg->channel_request.subsystem);
717
0
          break;
718
0
      case SSH_CHANNEL_REQUEST_X11:
719
0
          SAFE_FREE(msg->channel_request.x11_auth_protocol);
720
0
          SAFE_FREE(msg->channel_request.x11_auth_cookie);
721
0
          break;
722
0
      }
723
0
      break;
724
0
    case SSH_REQUEST_SERVICE:
725
0
      SAFE_FREE(msg->service_request.service);
726
0
      break;
727
0
    case SSH_REQUEST_GLOBAL:
728
0
      SAFE_FREE(msg->global_request.bind_address);
729
0
      break;
730
0
  }
731
0
  ZERO_STRUCTP(msg);
732
0
  SAFE_FREE(msg);
733
0
}
734
735
#ifdef WITH_SERVER
736
737
SSH_PACKET_CALLBACK(ssh_packet_service_request)
738
0
{
739
0
    char *service_c = NULL;
740
0
    ssh_message msg = NULL;
741
0
    int rc;
742
743
0
    (void)type;
744
0
    (void)user;
745
746
0
    rc = ssh_buffer_unpack(packet,
747
0
                           "s",
748
0
                           &service_c);
749
0
    if (rc != SSH_OK) {
750
0
        ssh_set_error(session,
751
0
                      SSH_FATAL,
752
0
                      "Invalid SSH_MSG_SERVICE_REQUEST packet");
753
0
        goto error;
754
0
    }
755
756
0
    SSH_LOG(SSH_LOG_PACKET,
757
0
            "Received a SERVICE_REQUEST for service %s",
758
0
            service_c);
759
760
0
    msg = ssh_message_new(session);
761
0
    if (msg == NULL) {
762
0
        SAFE_FREE(service_c);
763
0
        goto error;
764
0
    }
765
766
0
    msg->type = SSH_REQUEST_SERVICE;
767
0
    msg->service_request.service = service_c;
768
769
0
    ssh_message_queue(session, msg);
770
0
error:
771
772
0
    return SSH_PACKET_USED;
773
0
}
774
775
776
/*
777
 * This function concats in a buffer the values needed to do a signature
778
 * verification.
779
 */
780
static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
781
                                                ssh_message msg,
782
                                                const char *service,
783
                                                ssh_string algo,
784
                                                const char *method)
785
0
{
786
0
    struct ssh_crypto_struct *crypto = NULL;
787
0
    ssh_buffer buffer = NULL;
788
0
    ssh_string str = NULL;
789
0
    int rc;
790
791
0
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
792
0
    if (crypto == NULL) {
793
0
        return NULL;
794
0
    }
795
796
0
    buffer = ssh_buffer_new();
797
0
    if (buffer == NULL) {
798
0
        return NULL;
799
0
    }
800
0
    rc = ssh_pki_export_pubkey_blob(msg->auth_request.pubkey, &str);
801
0
    if (rc < 0) {
802
0
        SSH_BUFFER_FREE(buffer);
803
0
        return NULL;
804
0
    }
805
806
0
    rc = ssh_buffer_pack(buffer,
807
0
                         "dPbsssbsS",
808
0
                         (uint32_t)crypto->session_id_len, /* session ID string */
809
0
                         crypto->session_id_len,
810
0
                         crypto->session_id,
811
0
                         SSH2_MSG_USERAUTH_REQUEST, /* type */
812
0
                         msg->auth_request.username,
813
0
                         service,
814
0
                         method,
815
0
                         1, /* has to be signed (true) */
816
0
                         ssh_string_get_char(algo), /* pubkey algorithm */
817
0
                         str);                      /* public key as a blob */
818
819
0
    SSH_STRING_FREE(str);
820
0
    if (rc != SSH_OK) {
821
0
        ssh_set_error_oom(session);
822
0
        SSH_BUFFER_FREE(buffer);
823
0
        return NULL;
824
0
    }
825
826
    /* Add server public key for hostbound extension */
827
0
    if (strcmp(method, "publickey-hostbound-v00@openssh.com") == 0 &&
828
0
        msg->auth_request.server_pubkey != NULL) {
829
830
0
        rc = ssh_pki_export_pubkey_blob(msg->auth_request.server_pubkey, &str);
831
0
        if (rc < 0) {
832
0
            SSH_BUFFER_FREE(buffer);
833
0
            return NULL;
834
0
        }
835
836
0
        rc = ssh_buffer_add_ssh_string(buffer, str);
837
0
        SSH_STRING_FREE(str);
838
0
        if (rc < 0) {
839
0
            ssh_set_error_oom(session);
840
0
            SSH_BUFFER_FREE(buffer);
841
0
            return NULL;
842
0
        }
843
0
    }
844
845
0
    return buffer;
846
0
}
847
848
/**
849
 * @internal
850
 *
851
 * @brief Handle a SSH_MSG_MSG_USERAUTH_REQUEST packet and queue a
852
 * SSH Message
853
 */
854
SSH_PACKET_CALLBACK(ssh_packet_userauth_request)
855
0
{
856
0
    ssh_message msg = NULL;
857
0
    ssh_signature sig = NULL;
858
0
    char *service = NULL;
859
0
    char *method = NULL;
860
0
    int cmp;
861
0
    int rc;
862
863
0
    (void)user;
864
0
    (void)type;
865
866
0
    msg = ssh_message_new(session);
867
0
    if (msg == NULL) {
868
0
        ssh_set_error_oom(session);
869
0
        goto error;
870
0
    }
871
0
    msg->type = SSH_REQUEST_AUTH;
872
0
    rc = ssh_buffer_unpack(packet,
873
0
                           "sss",
874
0
                           &msg->auth_request.username,
875
0
                           &service,
876
0
                           &method);
877
878
0
    if (rc != SSH_OK) {
879
0
        goto error;
880
0
    }
881
882
0
    SSH_LOG(SSH_LOG_PACKET,
883
0
            "Auth request for service %s, method %s for user '%s'",
884
0
            service,
885
0
            method,
886
0
            msg->auth_request.username);
887
888
0
    cmp = strcmp(service, "ssh-connection");
889
0
    if (cmp != 0) {
890
0
        SSH_LOG(SSH_LOG_TRACE, "Invalid service request: %s", service);
891
0
        goto end;
892
0
    }
893
894
0
    if (strcmp(method, "none") == 0) {
895
0
        msg->auth_request.method = SSH_AUTH_METHOD_NONE;
896
0
        goto end;
897
0
    }
898
899
0
    if (strcmp(method, "password") == 0) {
900
0
        uint8_t tmp;
901
902
0
        msg->auth_request.method = SSH_AUTH_METHOD_PASSWORD;
903
0
        rc = ssh_buffer_unpack(packet, "bs", &tmp, &msg->auth_request.password);
904
0
        if (rc != SSH_OK) {
905
0
            goto error;
906
0
        }
907
0
        goto end;
908
0
    }
909
910
0
    if (strcmp(method, "keyboard-interactive") == 0) {
911
0
        ssh_string lang = NULL;
912
0
        ssh_string submethods = NULL;
913
914
0
        msg->auth_request.method = SSH_AUTH_METHOD_INTERACTIVE;
915
0
        lang = ssh_buffer_get_ssh_string(packet);
916
0
        if (lang == NULL) {
917
0
            goto error;
918
0
        }
919
        /* from the RFC 4256
920
         * 3.1.  Initial Exchange
921
         * "The language tag is deprecated and SHOULD be the empty string."
922
         */
923
0
        SSH_STRING_FREE(lang);
924
925
0
        submethods = ssh_buffer_get_ssh_string(packet);
926
0
        if (submethods == NULL) {
927
0
            goto error;
928
0
        }
929
        /* from the RFC 4256
930
         * 3.1.  Initial Exchange
931
         * "One possible implementation strategy of the submethods field on the
932
         *  server is that, unless the user may use multiple different
933
         *  submethods, the server ignores this field."
934
         */
935
0
        SSH_STRING_FREE(submethods);
936
937
0
        goto end;
938
0
    }
939
940
0
    if (strcmp(method, "publickey") == 0 ||
941
0
        strcmp(method, "publickey-hostbound-v00@openssh.com") == 0) {
942
0
        ssh_string algo = NULL;
943
0
        ssh_string pubkey_blob = NULL;
944
0
        ssh_string server_pubkey_blob = NULL;
945
0
        uint8_t has_sign;
946
947
0
        msg->auth_request.method = SSH_AUTH_METHOD_PUBLICKEY;
948
949
0
        rc = ssh_buffer_unpack(packet, "bSS", &has_sign, &algo, &pubkey_blob);
950
951
0
        if (rc != SSH_OK) {
952
0
            goto error;
953
0
        }
954
955
0
        cmp = strcmp(method, "publickey-hostbound-v00@openssh.com");
956
0
        if (cmp == 0) {
957
0
            server_pubkey_blob = ssh_buffer_get_ssh_string(packet);
958
0
            if (server_pubkey_blob == NULL) {
959
0
                SSH_STRING_FREE(pubkey_blob);
960
0
                SSH_STRING_FREE(algo);
961
0
                goto error;
962
0
            }
963
964
0
            rc = ssh_pki_import_pubkey_blob(server_pubkey_blob,
965
0
                                            &msg->auth_request.server_pubkey);
966
0
            SSH_STRING_FREE(server_pubkey_blob);
967
968
0
            if (rc < 0) {
969
0
                SSH_STRING_FREE(pubkey_blob);
970
0
                SSH_STRING_FREE(algo);
971
0
                goto error;
972
0
            }
973
0
        }
974
975
0
        rc = ssh_pki_import_pubkey_blob(pubkey_blob, &msg->auth_request.pubkey);
976
0
        SSH_STRING_FREE(pubkey_blob);
977
0
        pubkey_blob = NULL;
978
0
        if (rc < 0) {
979
0
            SSH_STRING_FREE(algo);
980
0
            algo = NULL;
981
0
            goto error;
982
0
        }
983
0
        msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_NONE;
984
0
        msg->auth_request.sigtype = strdup(ssh_string_get_char(algo));
985
0
        if (msg->auth_request.sigtype == NULL) {
986
0
            msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
987
0
            SSH_STRING_FREE(algo);
988
0
            algo = NULL;
989
0
            goto error;
990
0
        }
991
992
        // has a valid signature ?
993
0
        if (has_sign) {
994
0
            ssh_string sig_blob = NULL;
995
0
            ssh_buffer digest = NULL;
996
997
0
            sig_blob = ssh_buffer_get_ssh_string(packet);
998
0
            if (sig_blob == NULL) {
999
0
                SSH_LOG(SSH_LOG_PACKET, "Invalid signature packet from peer");
1000
0
                msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
1001
0
                SSH_STRING_FREE(algo);
1002
0
                algo = NULL;
1003
0
                goto error;
1004
0
            }
1005
1006
0
            digest = ssh_msg_userauth_build_digest(session,
1007
0
                                                   msg,
1008
0
                                                   service,
1009
0
                                                   algo,
1010
0
                                                   method);
1011
0
            SSH_STRING_FREE(algo);
1012
0
            algo = NULL;
1013
0
            if (digest == NULL) {
1014
0
                SSH_STRING_FREE(sig_blob);
1015
0
                SSH_LOG(SSH_LOG_PACKET, "Failed to get digest");
1016
0
                msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
1017
0
                goto error;
1018
0
            }
1019
1020
0
            rc = ssh_pki_import_signature_blob(sig_blob,
1021
0
                                               msg->auth_request.pubkey,
1022
0
                                               &sig);
1023
0
            if (rc == SSH_OK) {
1024
                /* Check if the signature from client matches server preferences
1025
                 */
1026
0
                if (session->opts.pubkey_accepted_types) {
1027
0
                    cmp = match_group(session->opts.pubkey_accepted_types,
1028
0
                                      sig->type_c);
1029
0
                    if (cmp != 1) {
1030
0
                        ssh_set_error(
1031
0
                            session,
1032
0
                            SSH_FATAL,
1033
0
                            "Public key from client (%s) doesn't match server "
1034
0
                            "preference (%s)",
1035
0
                            sig->type_c,
1036
0
                            session->opts.pubkey_accepted_types);
1037
0
                        rc = SSH_ERROR;
1038
0
                    }
1039
0
                }
1040
1041
0
                if (rc == SSH_OK) {
1042
0
                    rc = ssh_pki_signature_verify(session,
1043
0
                                                  sig,
1044
0
                                                  msg->auth_request.pubkey,
1045
0
                                                  ssh_buffer_get(digest),
1046
0
                                                  ssh_buffer_get_len(digest));
1047
0
                }
1048
0
            }
1049
0
            SSH_STRING_FREE(sig_blob);
1050
0
            SSH_BUFFER_FREE(digest);
1051
0
            ssh_signature_free(sig);
1052
0
            if (rc < 0) {
1053
0
                SSH_LOG(SSH_LOG_PACKET,
1054
0
                        "Received an invalid signature from peer");
1055
0
                msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
1056
0
                goto error;
1057
0
            }
1058
1059
0
            SSH_LOG(SSH_LOG_PACKET, "Valid signature received");
1060
1061
0
            cmp = strcmp(method, "publickey-hostbound-v00@openssh.com");
1062
0
            if (cmp == 0) {
1063
0
                ssh_key server_key = NULL;
1064
1065
0
                if (msg->auth_request.server_pubkey == NULL) {
1066
0
                    SSH_LOG(SSH_LOG_PACKET,
1067
0
                            "Server public key not provided by client");
1068
0
                    msg->auth_request.signature_state =
1069
0
                        SSH_PUBLICKEY_STATE_WRONG;
1070
0
                    goto error;
1071
0
                }
1072
1073
0
                rc = ssh_get_server_publickey(session, &server_key);
1074
0
                if (rc != SSH_OK) {
1075
0
                    SSH_LOG(SSH_LOG_PACKET,
1076
0
                            "Failed to get server public key for hostbound "
1077
0
                            "verification");
1078
0
                    msg->auth_request.signature_state =
1079
0
                        SSH_PUBLICKEY_STATE_ERROR;
1080
0
                    ssh_key_free(server_key);
1081
0
                    goto error;
1082
0
                }
1083
1084
0
                if (ssh_key_cmp(server_key,
1085
0
                                msg->auth_request.server_pubkey,
1086
0
                                SSH_KEY_CMP_PUBLIC) != 0) {
1087
0
                    SSH_LOG(SSH_LOG_PACKET,
1088
0
                            "Server public key doesn't match the one provided "
1089
0
                            "by client");
1090
0
                    msg->auth_request.signature_state =
1091
0
                        SSH_PUBLICKEY_STATE_WRONG;
1092
0
                    ssh_key_free(server_key);
1093
0
                    goto error;
1094
0
                }
1095
0
                ssh_key_free(server_key);
1096
0
            }
1097
1098
0
            msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_VALID;
1099
0
        }
1100
1101
0
        SAFE_FREE(method);
1102
0
        SSH_STRING_FREE(algo);
1103
0
        goto end;
1104
0
    }
1105
#ifdef WITH_GSSAPI
1106
    if (strcmp(method, "gssapi-with-mic") == 0) {
1107
        uint32_t n_oid;
1108
        ssh_string *oids = NULL;
1109
        ssh_string oid = NULL;
1110
        char *hexa = NULL;
1111
        int i;
1112
        ssh_buffer_get_u32(packet, &n_oid);
1113
        n_oid = ntohl(n_oid);
1114
        if (n_oid > 100) {
1115
            ssh_set_error(
1116
                session,
1117
                SSH_FATAL,
1118
                "USERAUTH_REQUEST: gssapi-with-mic OID count too big (%d)",
1119
                n_oid);
1120
            goto error;
1121
        }
1122
        SSH_LOG(SSH_LOG_PACKET, "gssapi: %d OIDs", n_oid);
1123
        oids = calloc(n_oid, sizeof(ssh_string));
1124
        if (oids == NULL) {
1125
            ssh_set_error_oom(session);
1126
            goto error;
1127
        }
1128
        for (i = 0; i < (int)n_oid; ++i) {
1129
            oid = ssh_buffer_get_ssh_string(packet);
1130
            if (oid == NULL) {
1131
                for (i = i - 1; i >= 0; --i) {
1132
                    SAFE_FREE(oids[i]);
1133
                }
1134
                SAFE_FREE(oids);
1135
                ssh_set_error(session,
1136
                              SSH_LOG_PACKET,
1137
                              "USERAUTH_REQUEST: gssapi-with-mic missing OID");
1138
                goto error;
1139
            }
1140
            oids[i] = oid;
1141
            if (session->common.log_verbosity >= SSH_LOG_PACKET) {
1142
                hexa = ssh_get_hexa(ssh_string_data(oid), ssh_string_len(oid));
1143
                SSH_LOG(SSH_LOG_PACKET, "gssapi: OID %d: %s", i, hexa);
1144
                SAFE_FREE(hexa);
1145
            }
1146
        }
1147
        ssh_gssapi_handle_userauth(session,
1148
                                   msg->auth_request.username,
1149
                                   n_oid,
1150
                                   oids);
1151
1152
        for (i = 0; i < (int)n_oid; ++i) {
1153
            SAFE_FREE(oids[i]);
1154
        }
1155
        SAFE_FREE(oids);
1156
        /* bypass the message queue thing */
1157
        SAFE_FREE(service);
1158
        SAFE_FREE(method);
1159
        SSH_MESSAGE_FREE(msg);
1160
1161
        return SSH_PACKET_USED;
1162
    }
1163
    if (strcmp(method, "gssapi-keyex") == 0) {
1164
        gss_buffer_desc received_mic = GSS_C_EMPTY_BUFFER;
1165
        gss_buffer_desc mic_buf = GSS_C_EMPTY_BUFFER;
1166
        ssh_string mic_token_string = NULL;
1167
        OM_uint32 maj_stat, min_stat;
1168
        ssh_buffer buf = NULL;
1169
1170
        if (!ssh_kex_is_gss(session->current_crypto)) {
1171
            ssh_set_error(session,
1172
                          SSH_FATAL,
1173
                          "Attempt to authenticate with gssapi-keyex without "
1174
                          "doing GSSAPI Key Exchange.");
1175
            ssh_auth_reply_default(session, 0);
1176
            goto error;
1177
        }
1178
1179
        if (session->gssapi == NULL || session->gssapi->ctx == NULL) {
1180
            ssh_set_error(session, SSH_FATAL, "GSSAPI context not initialized");
1181
            ssh_auth_reply_default(session, 0);
1182
            goto error;
1183
        }
1184
1185
        rc = ssh_buffer_unpack(packet, "S", &mic_token_string);
1186
        if (rc != SSH_OK) {
1187
            ssh_auth_reply_default(session, 0);
1188
            goto error;
1189
        }
1190
        received_mic.length = ssh_string_len(mic_token_string);
1191
        received_mic.value = ssh_string_data(mic_token_string);
1192
1193
        SAFE_FREE(session->gssapi->user);
1194
        session->gssapi->user = strdup(msg->auth_request.username);
1195
        buf = ssh_gssapi_build_mic(session, "gssapi-keyex");
1196
        if (buf == NULL) {
1197
            ssh_set_error_oom(session);
1198
            SSH_STRING_FREE(mic_token_string);
1199
            ssh_auth_reply_default(session, 0);
1200
            goto error;
1201
        }
1202
1203
        mic_buf.length = ssh_buffer_get_len(buf);
1204
        mic_buf.value = ssh_buffer_get(buf);
1205
1206
        maj_stat = gss_verify_mic(&min_stat,
1207
                                  session->gssapi->ctx,
1208
                                  &mic_buf,
1209
                                  &received_mic,
1210
                                  NULL);
1211
        if (maj_stat != GSS_S_COMPLETE) {
1212
            ssh_set_error(session,
1213
                          SSH_FATAL,
1214
                          "Failed to verify MIC for gssapi-keyex auth");
1215
            SSH_BUFFER_FREE(buf);
1216
            SSH_STRING_FREE(mic_token_string);
1217
            ssh_auth_reply_default(session, 0);
1218
            goto error;
1219
        }
1220
1221
        ssh_auth_reply_success(session, 0);
1222
1223
        /* bypass the message queue thing */
1224
        SAFE_FREE(service);
1225
        SAFE_FREE(method);
1226
        SSH_BUFFER_FREE(buf);
1227
        SSH_MESSAGE_FREE(msg);
1228
        SSH_STRING_FREE(mic_token_string);
1229
1230
        return SSH_PACKET_USED;
1231
    }
1232
#endif
1233
1234
0
    msg->auth_request.method = SSH_AUTH_METHOD_UNKNOWN;
1235
0
    SAFE_FREE(method);
1236
0
    goto end;
1237
0
error:
1238
0
    SAFE_FREE(service);
1239
0
    SAFE_FREE(method);
1240
1241
0
    SSH_MESSAGE_FREE(msg);
1242
1243
0
    return SSH_PACKET_USED;
1244
0
end:
1245
0
    SAFE_FREE(service);
1246
0
    SAFE_FREE(method);
1247
1248
0
    ssh_message_queue(session, msg);
1249
1250
0
    return SSH_PACKET_USED;
1251
0
}
1252
1253
#endif /* WITH_SERVER */
1254
/**
1255
 * @internal
1256
 *
1257
 * @brief Handle a SSH_MSG_MSG_USERAUTH_INFO_RESPONSE packet and queue a
1258
 * SSH Message
1259
 */
1260
#ifndef WITH_SERVER
1261
SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
1262
    (void)session;
1263
    (void)type;
1264
    (void)packet;
1265
    (void)user;
1266
    return SSH_PACKET_USED;
1267
}
1268
#else /* WITH_SERVER */
1269
0
SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
1270
0
  uint32_t nanswers;
1271
0
  uint32_t i;
1272
0
  ssh_string tmp = NULL;
1273
0
  int rc;
1274
1275
0
  ssh_message msg = NULL;
1276
1277
  /* GSSAPI_TOKEN has same packed number. XXX fix this */
1278
#ifdef WITH_GSSAPI
1279
  if (session->gssapi != NULL) {
1280
      return ssh_packet_userauth_gssapi_token(session, type, packet, user);
1281
  }
1282
#endif
1283
0
  (void)user;
1284
0
  (void)type;
1285
1286
0
  msg = ssh_message_new(session);
1287
0
  if (msg == NULL) {
1288
0
    ssh_set_error_oom(session);
1289
0
    goto error;
1290
0
  }
1291
1292
  /* HACK: we forge a message to be able to handle it in the
1293
   * same switch() as other auth methods */
1294
0
  msg->type = SSH_REQUEST_AUTH;
1295
0
  msg->auth_request.method = SSH_AUTH_METHOD_INTERACTIVE;
1296
0
  msg->auth_request.kbdint_response = 1;
1297
#if 0 // should we wipe the username ?
1298
  msg->auth_request.username = NULL;
1299
#endif
1300
1301
0
  rc = ssh_buffer_unpack(packet, "d", &nanswers);
1302
0
  if (rc != SSH_OK) {
1303
0
      ssh_set_error_invalid(session);
1304
0
      goto error;
1305
0
  }
1306
1307
0
  if (session->kbdint == NULL) {
1308
0
    SSH_LOG(SSH_LOG_DEBUG, "Warning: Got a keyboard-interactive "
1309
0
                        "response but it seems we didn't send the request.");
1310
1311
0
    session->kbdint = ssh_kbdint_new();
1312
0
    if (session->kbdint == NULL) {
1313
0
      ssh_set_error_oom(session);
1314
1315
0
      goto error;
1316
0
    }
1317
0
  } else if (session->kbdint->answers != NULL) {
1318
0
      uint32_t n;
1319
1320
0
      for (n = 0; n < session->kbdint->nanswers; n++) {
1321
0
          ssh_burn(session->kbdint->answers[n],
1322
0
                   strlen(session->kbdint->answers[n]));
1323
0
          SAFE_FREE(session->kbdint->answers[n]);
1324
0
      }
1325
0
      SAFE_FREE(session->kbdint->answers);
1326
0
      session->kbdint->nanswers = 0;
1327
0
  }
1328
1329
0
  SSH_LOG(SSH_LOG_PACKET,"kbdint: %" PRIu32 " answers", nanswers);
1330
0
  if (nanswers > KBDINT_MAX_PROMPT) {
1331
0
    ssh_set_error(session, SSH_FATAL,
1332
0
        "Too much answers received from client: %" PRIu32 " (0x%.4" PRIx32 ")",
1333
0
        nanswers, nanswers);
1334
0
    ssh_kbdint_free(session->kbdint);
1335
0
    session->kbdint = NULL;
1336
1337
0
    goto error;
1338
0
  }
1339
1340
0
  if(nanswers != session->kbdint->nprompts) {
1341
    /* warn but let the application handle this case */
1342
0
    SSH_LOG(SSH_LOG_DEBUG, "Warning: Number of prompts and answers"
1343
0
                " mismatch: p=%" PRIu32 " a=%" PRIu32, session->kbdint->nprompts, nanswers);
1344
0
  }
1345
0
  session->kbdint->nanswers = nanswers;
1346
1347
0
  session->kbdint->answers = calloc(nanswers, sizeof(char *));
1348
0
  if (session->kbdint->answers == NULL) {
1349
0
    session->kbdint->nanswers = 0;
1350
0
    ssh_set_error_oom(session);
1351
0
    ssh_kbdint_free(session->kbdint);
1352
0
    session->kbdint = NULL;
1353
1354
0
    goto error;
1355
0
  }
1356
1357
0
  for (i = 0; i < nanswers; i++) {
1358
0
    tmp = ssh_buffer_get_ssh_string(packet);
1359
0
    if (tmp == NULL) {
1360
0
      ssh_set_error(session, SSH_FATAL, "Short INFO_RESPONSE packet");
1361
0
      session->kbdint->nanswers = i;
1362
0
      ssh_kbdint_free(session->kbdint);
1363
0
      session->kbdint = NULL;
1364
1365
0
      goto error;
1366
0
    }
1367
0
    session->kbdint->answers[i] = ssh_string_to_char(tmp);
1368
0
    SSH_STRING_FREE(tmp);
1369
0
    if (session->kbdint->answers[i] == NULL) {
1370
0
      ssh_set_error_oom(session);
1371
0
      session->kbdint->nanswers = i;
1372
0
      ssh_kbdint_free(session->kbdint);
1373
0
      session->kbdint = NULL;
1374
1375
0
      goto error;
1376
0
    }
1377
0
  }
1378
1379
0
  ssh_message_queue(session,msg);
1380
1381
0
  return SSH_PACKET_USED;
1382
1383
0
error:
1384
0
  SSH_MESSAGE_FREE(msg);
1385
1386
0
  return SSH_PACKET_USED;
1387
0
}
1388
#endif /* WITH_SERVER */
1389
1390
0
SSH_PACKET_CALLBACK(ssh_packet_channel_open){
1391
0
  ssh_message msg = NULL;
1392
0
  char *type_c = NULL;
1393
0
  uint32_t originator_port, destination_port;
1394
0
  int rc;
1395
1396
0
  (void)type;
1397
0
  (void)user;
1398
0
  msg = ssh_message_new(session);
1399
0
  if (msg == NULL) {
1400
0
    ssh_set_error_oom(session);
1401
0
    goto error;
1402
0
  }
1403
1404
0
  msg->type = SSH_REQUEST_CHANNEL_OPEN;
1405
0
  rc = ssh_buffer_unpack(packet, "s", &type_c);
1406
0
  if (rc != SSH_OK){
1407
0
      goto error;
1408
0
  }
1409
1410
0
  SSH_LOG(SSH_LOG_PACKET,
1411
0
      "Clients wants to open a %s channel", type_c);
1412
1413
0
  ssh_buffer_unpack(packet,"ddd",
1414
0
          &msg->channel_request_open.sender,
1415
0
          &msg->channel_request_open.window,
1416
0
          &msg->channel_request_open.packet_size);
1417
1418
0
  if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED){
1419
0
    ssh_set_error(session,SSH_FATAL, "Invalid state when receiving channel open request (must be authenticated)");
1420
0
    goto error;
1421
0
  }
1422
1423
0
  if (strcmp(type_c, "session") == 0) {
1424
0
    if (session->flags & SSH_SESSION_FLAG_NO_MORE_SESSIONS) {
1425
0
        ssh_session_set_disconnect_message(session, "No more sessions allowed!");
1426
0
        ssh_set_error(session, SSH_FATAL, "No more sessions allowed!");
1427
0
        session->session_state = SSH_SESSION_STATE_ERROR;
1428
0
        ssh_send_disconnect(session);
1429
0
        goto error;
1430
0
    }
1431
1432
0
    msg->channel_request_open.type = SSH_CHANNEL_SESSION;
1433
0
    SAFE_FREE(type_c);
1434
0
    goto end;
1435
0
  }
1436
1437
0
  if (strcmp(type_c,"direct-tcpip") == 0) {
1438
0
    rc = ssh_buffer_unpack(packet,
1439
0
                           "sdsd",
1440
0
                           &msg->channel_request_open.destination,
1441
0
                           &destination_port,
1442
0
                           &msg->channel_request_open.originator,
1443
0
                           &originator_port);
1444
0
    if (rc != SSH_OK) {
1445
0
      goto error;
1446
0
    }
1447
1448
0
    msg->channel_request_open.destination_port = (uint16_t) destination_port;
1449
0
    msg->channel_request_open.originator_port = (uint16_t) originator_port;
1450
0
    msg->channel_request_open.type = SSH_CHANNEL_DIRECT_TCPIP;
1451
0
    goto end;
1452
0
  }
1453
1454
0
  if (strcmp(type_c,"forwarded-tcpip") == 0) {
1455
0
    rc = ssh_buffer_unpack(packet, "sdsd",
1456
0
            &msg->channel_request_open.destination,
1457
0
            &destination_port,
1458
0
            &msg->channel_request_open.originator,
1459
0
            &originator_port
1460
0
        );
1461
0
    if (rc != SSH_OK){
1462
0
        goto error;
1463
0
    }
1464
0
    msg->channel_request_open.destination_port = (uint16_t) destination_port;
1465
0
    msg->channel_request_open.originator_port = (uint16_t) originator_port;
1466
0
    msg->channel_request_open.type = SSH_CHANNEL_FORWARDED_TCPIP;
1467
0
    goto end;
1468
0
  }
1469
1470
0
  if (strcmp(type_c,"x11") == 0) {
1471
0
    rc = ssh_buffer_unpack(packet, "sd",
1472
0
            &msg->channel_request_open.originator,
1473
0
            &originator_port);
1474
0
    if (rc != SSH_OK){
1475
0
        goto error;
1476
0
    }
1477
0
    msg->channel_request_open.originator_port = (uint16_t) originator_port;
1478
0
    msg->channel_request_open.type = SSH_CHANNEL_X11;
1479
0
    goto end;
1480
0
  }
1481
1482
0
  if (strcmp(type_c,"auth-agent@openssh.com") == 0) {
1483
0
    msg->channel_request_open.type = SSH_CHANNEL_AUTH_AGENT;
1484
0
    goto end;
1485
0
  }
1486
1487
0
  msg->channel_request_open.type = SSH_CHANNEL_UNKNOWN;
1488
0
  goto end;
1489
1490
0
error:
1491
0
  SSH_MESSAGE_FREE(msg);
1492
0
end:
1493
0
  SAFE_FREE(type_c);
1494
0
  if(msg != NULL)
1495
0
    ssh_message_queue(session,msg);
1496
1497
0
  return SSH_PACKET_USED;
1498
0
}
1499
1500
/**
1501
 * @internal
1502
 *
1503
 * @brief This function accepts a channel open request for the specified channel.
1504
 *
1505
 * @param[in]  msg      The message.
1506
 *
1507
 * @param[in]  chan     The channel the request is made on.
1508
 *
1509
 * @returns             SSH_OK on success, SSH_ERROR if an error occurred.
1510
 */
1511
int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg,
1512
                                                          ssh_channel chan)
1513
0
{
1514
0
    ssh_session session = NULL;
1515
0
    int rc;
1516
1517
0
    if (msg == NULL) {
1518
0
        return SSH_ERROR;
1519
0
    }
1520
1521
0
    session = msg->session;
1522
1523
0
    chan->local_channel = ssh_channel_new_id(session);
1524
0
    chan->local_maxpacket = 35000;
1525
0
    chan->local_window = 32000;
1526
0
    chan->remote_channel = msg->channel_request_open.sender;
1527
0
    chan->remote_maxpacket = msg->channel_request_open.packet_size;
1528
0
    chan->remote_window = msg->channel_request_open.window;
1529
0
    chan->state = SSH_CHANNEL_STATE_OPEN;
1530
0
    chan->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND;
1531
1532
0
    rc = ssh_buffer_pack(session->out_buffer,
1533
0
                         "bdddd",
1534
0
                         SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
1535
0
                         chan->remote_channel,
1536
0
                         chan->local_channel,
1537
0
                         chan->local_window,
1538
0
                         chan->local_maxpacket);
1539
0
    if (rc != SSH_OK) {
1540
0
        ssh_set_error_oom(session);
1541
0
        return SSH_ERROR;
1542
0
    }
1543
1544
0
    SSH_LOG(SSH_LOG_PACKET,
1545
0
            "Accepting a channel request_open for chan %" PRIu32,
1546
0
            chan->remote_channel);
1547
1548
0
    rc = ssh_packet_send(session);
1549
1550
0
    return rc;
1551
0
}
1552
1553
/**
1554
 * @internal
1555
 *
1556
 * @brief This function accepts a channel open request.
1557
 *
1558
 * @param[in]  msg      The message.
1559
 *
1560
 * @returns a valid ssh_channel handle if the request is to be allowed
1561
 *
1562
 * @returns NULL in case of error
1563
 */
1564
ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg)
1565
0
{
1566
0
    ssh_channel chan = NULL;
1567
0
    int rc;
1568
1569
0
    if (msg == NULL) {
1570
0
        return NULL;
1571
0
    }
1572
1573
0
    chan = ssh_channel_new(msg->session);
1574
0
    if (chan == NULL) {
1575
0
        return NULL;
1576
0
    }
1577
0
    rc = ssh_message_channel_request_open_reply_accept_channel(msg, chan);
1578
0
    if (rc < 0) {
1579
0
        ssh_channel_free(chan);
1580
0
        chan = NULL;
1581
0
    }
1582
0
    return chan;
1583
0
}
1584
1585
/**
1586
 * @internal
1587
 *
1588
 * @brief This function parses the last end of a channel request packet.
1589
 *
1590
 * This is normally converted to a SSH message and placed in the queue.
1591
 *
1592
 * @param[in]  session  The SSH session.
1593
 *
1594
 * @param[in]  channel  The channel the request is made on.
1595
 *
1596
 * @param[in]  packet   The rest of the packet to be parsed.
1597
 *
1598
 * @param[in]  request  The type of request.
1599
 *
1600
 * @param[in]  want_reply The want_reply field from the request.
1601
 *
1602
 * @returns             SSH_OK on success, SSH_ERROR if an error occurred.
1603
 */
1604
int
1605
ssh_message_handle_channel_request(ssh_session session,
1606
                                   ssh_channel channel,
1607
                                   ssh_buffer packet,
1608
                                   const char *request,
1609
                                   uint8_t want_reply)
1610
0
{
1611
0
    ssh_message msg = NULL;
1612
0
    int rc;
1613
1614
0
    msg = ssh_message_new(session);
1615
0
    if (msg == NULL) {
1616
0
        ssh_set_error_oom(session);
1617
0
        goto error;
1618
0
    }
1619
1620
0
    SSH_LOG(SSH_LOG_PACKET,
1621
0
            "Received a %s channel_request for channel (%" PRIu32 ":%" PRIu32
1622
0
            ") (want_reply=%hhu)",
1623
0
            request,
1624
0
            channel->local_channel,
1625
0
            channel->remote_channel,
1626
0
            want_reply);
1627
1628
0
    msg->type = SSH_REQUEST_CHANNEL;
1629
0
    msg->channel_request.channel = channel;
1630
0
    msg->channel_request.want_reply = want_reply;
1631
1632
0
    if (strcmp(request, "pty-req") == 0) {
1633
0
        rc = ssh_buffer_unpack(packet,
1634
0
                               "sddddS",
1635
0
                               &msg->channel_request.TERM,
1636
0
                               &msg->channel_request.width,
1637
0
                               &msg->channel_request.height,
1638
0
                               &msg->channel_request.pxwidth,
1639
0
                               &msg->channel_request.pxheight,
1640
0
                               &msg->channel_request.modes);
1641
1642
0
        msg->channel_request.type = SSH_CHANNEL_REQUEST_PTY;
1643
1644
0
        if (rc != SSH_OK) {
1645
0
            goto error;
1646
0
        }
1647
0
        goto end;
1648
0
    }
1649
1650
0
    if (strcmp(request, "window-change") == 0) {
1651
0
        msg->channel_request.type = SSH_CHANNEL_REQUEST_WINDOW_CHANGE;
1652
0
        rc = ssh_buffer_unpack(packet,
1653
0
                               "dddd",
1654
0
                               &msg->channel_request.width,
1655
0
                               &msg->channel_request.height,
1656
0
                               &msg->channel_request.pxwidth,
1657
0
                               &msg->channel_request.pxheight);
1658
0
        if (rc != SSH_OK) {
1659
0
            goto error;
1660
0
        }
1661
0
        goto end;
1662
0
    }
1663
1664
0
    if (strcmp(request, "subsystem") == 0) {
1665
0
        rc = ssh_buffer_unpack(packet, "s", &msg->channel_request.subsystem);
1666
0
        msg->channel_request.type = SSH_CHANNEL_REQUEST_SUBSYSTEM;
1667
0
        if (rc != SSH_OK) {
1668
0
            goto error;
1669
0
        }
1670
0
        goto end;
1671
0
    }
1672
1673
0
    if (strcmp(request, "shell") == 0) {
1674
0
        msg->channel_request.type = SSH_CHANNEL_REQUEST_SHELL;
1675
0
        goto end;
1676
0
    }
1677
1678
0
    if (strcmp(request, "exec") == 0) {
1679
0
        rc = ssh_buffer_unpack(packet, "s", &msg->channel_request.command);
1680
0
        msg->channel_request.type = SSH_CHANNEL_REQUEST_EXEC;
1681
0
        if (rc != SSH_OK) {
1682
0
            goto error;
1683
0
        }
1684
0
        goto end;
1685
0
    }
1686
1687
0
    if (strcmp(request, "env") == 0) {
1688
0
        rc = ssh_buffer_unpack(packet,
1689
0
                               "ss",
1690
0
                               &msg->channel_request.var_name,
1691
0
                               &msg->channel_request.var_value);
1692
0
        msg->channel_request.type = SSH_CHANNEL_REQUEST_ENV;
1693
0
        if (rc != SSH_OK) {
1694
0
            goto error;
1695
0
        }
1696
0
        goto end;
1697
0
    }
1698
1699
0
    if (strcmp(request, "x11-req") == 0) {
1700
0
        rc = ssh_buffer_unpack(packet,
1701
0
                               "bssd",
1702
0
                               &msg->channel_request.x11_single_connection,
1703
0
                               &msg->channel_request.x11_auth_protocol,
1704
0
                               &msg->channel_request.x11_auth_cookie,
1705
0
                               &msg->channel_request.x11_screen_number);
1706
1707
0
        msg->channel_request.type = SSH_CHANNEL_REQUEST_X11;
1708
0
        if (rc != SSH_OK) {
1709
0
            goto error;
1710
0
        }
1711
1712
0
        goto end;
1713
0
    }
1714
1715
0
    msg->channel_request.type = SSH_CHANNEL_REQUEST_UNKNOWN;
1716
0
end:
1717
0
    ssh_message_queue(session, msg);
1718
1719
0
    return SSH_OK;
1720
0
error:
1721
0
    SSH_MESSAGE_FREE(msg);
1722
1723
0
    return SSH_ERROR;
1724
0
}
1725
1726
/** @internal
1727
 *
1728
 * @brief       Sends a successful channel request reply
1729
 *
1730
 * @param msg   A message to reply to
1731
 *
1732
 * @returns     SSH_OK on success, SSH_ERROR if an error occurred.
1733
 */
1734
int ssh_message_channel_request_reply_success(ssh_message msg)
1735
0
{
1736
0
    uint32_t channel;
1737
0
    int rc;
1738
1739
0
    if (msg == NULL) {
1740
0
        return SSH_ERROR;
1741
0
    }
1742
1743
0
    if (msg->channel_request.want_reply) {
1744
0
        channel = msg->channel_request.channel->remote_channel;
1745
1746
0
        SSH_LOG(SSH_LOG_PACKET,
1747
0
                "Sending a channel_request success to channel %" PRIu32,
1748
0
                channel);
1749
1750
0
        rc = ssh_buffer_pack(msg->session->out_buffer,
1751
0
                             "bd",
1752
0
                             SSH2_MSG_CHANNEL_SUCCESS,
1753
0
                             channel);
1754
0
        if (rc != SSH_OK) {
1755
0
            ssh_set_error_oom(msg->session);
1756
0
            return SSH_ERROR;
1757
0
        }
1758
1759
0
        return ssh_packet_send(msg->session);
1760
0
    }
1761
1762
0
    SSH_LOG(SSH_LOG_PACKET,
1763
0
            "The client doesn't want to know the request succeeded");
1764
1765
0
    return SSH_OK;
1766
0
}
1767
1768
#ifdef WITH_SERVER
1769
SSH_PACKET_CALLBACK(ssh_packet_global_request)
1770
0
{
1771
0
    ssh_message msg = NULL;
1772
0
    char *request = NULL;
1773
0
    uint8_t want_reply;
1774
0
    int rc = SSH_PACKET_USED;
1775
0
    int r;
1776
1777
0
    (void)user;
1778
0
    (void)type;
1779
0
    (void)packet;
1780
1781
0
    SSH_LOG(SSH_LOG_DEBUG,"Received SSH_MSG_GLOBAL_REQUEST packet");
1782
0
    r = ssh_buffer_unpack(packet, "sb", &request, &want_reply);
1783
0
    if (r != SSH_OK){
1784
0
        goto error;
1785
0
    }
1786
1787
0
    msg = ssh_message_new(session);
1788
0
    if (msg == NULL) {
1789
0
        ssh_set_error_oom(session);
1790
0
        goto error;
1791
0
    }
1792
0
    msg->type = SSH_REQUEST_GLOBAL;
1793
1794
0
    if (strcmp(request, "tcpip-forward") == 0) {
1795
1796
        /* According to RFC4254, the client SHOULD reject this message */
1797
0
        if (session->client) {
1798
0
            goto reply_with_failure;
1799
0
        }
1800
1801
0
        r = ssh_buffer_unpack(packet,
1802
0
                              "sd",
1803
0
                              &msg->global_request.bind_address,
1804
0
                              &msg->global_request.bind_port);
1805
0
        if (r != SSH_OK){
1806
0
            goto reply_with_failure;
1807
0
        }
1808
0
        msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD;
1809
0
        msg->global_request.want_reply = want_reply;
1810
1811
0
        SSH_LOG(SSH_LOG_DEBUG,
1812
0
                "Received SSH_MSG_GLOBAL_REQUEST %s %hhu %s:%d",
1813
0
                request,
1814
0
                want_reply,
1815
0
                msg->global_request.bind_address,
1816
0
                msg->global_request.bind_port);
1817
1818
0
        if (ssh_callbacks_exists(session->common.callbacks,
1819
0
                                 global_request_function)) {
1820
0
            SSH_LOG(SSH_LOG_DEBUG,
1821
0
                    "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %hhu %s:%d",
1822
0
                    request,
1823
0
                    want_reply,
1824
0
                    msg->global_request.bind_address,
1825
0
                    msg->global_request.bind_port);
1826
0
            session->common.callbacks->global_request_function(
1827
0
                session,
1828
0
                msg,
1829
0
                session->common.callbacks->userdata);
1830
0
        } else {
1831
0
            SAFE_FREE(request);
1832
0
            ssh_message_queue(session, msg);
1833
0
            return rc;
1834
0
        }
1835
0
    } else if (strcmp(request, "cancel-tcpip-forward") == 0) {
1836
1837
        /* According to RFC4254, the client SHOULD reject this message */
1838
0
        if (session->client) {
1839
0
            goto reply_with_failure;
1840
0
        }
1841
1842
0
        r = ssh_buffer_unpack(packet,
1843
0
                              "sd",
1844
0
                              &msg->global_request.bind_address,
1845
0
                              &msg->global_request.bind_port);
1846
0
        if (r != SSH_OK){
1847
0
            goto reply_with_failure;
1848
0
        }
1849
0
        msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD;
1850
0
        msg->global_request.want_reply = want_reply;
1851
1852
0
        SSH_LOG(SSH_LOG_DEBUG,
1853
0
                "Received SSH_MSG_GLOBAL_REQUEST %s %hhu %s:%d",
1854
0
                request,
1855
0
                want_reply,
1856
0
                msg->global_request.bind_address,
1857
0
                msg->global_request.bind_port);
1858
1859
0
        if (ssh_callbacks_exists(session->common.callbacks,
1860
0
                                 global_request_function)) {
1861
0
            session->common.callbacks->global_request_function(
1862
0
                session,
1863
0
                msg,
1864
0
                session->common.callbacks->userdata);
1865
0
        } else {
1866
0
            SAFE_FREE(request);
1867
0
            ssh_message_queue(session, msg);
1868
0
            return rc;
1869
0
        }
1870
0
    } else if(strcmp(request, "keepalive@openssh.com") == 0) {
1871
0
        msg->global_request.type = SSH_GLOBAL_REQUEST_KEEPALIVE;
1872
0
        msg->global_request.want_reply = want_reply;
1873
0
        SSH_LOG(SSH_LOG_DEBUG,
1874
0
                "Received keepalive@openssh.com %hhu",
1875
0
                want_reply);
1876
0
        if (ssh_callbacks_exists(session->common.callbacks,
1877
0
                                 global_request_function)) {
1878
0
            SSH_LOG(SSH_LOG_DEBUG,
1879
0
                    "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %hhu",
1880
0
                    request,
1881
0
                    want_reply);
1882
0
            session->common.callbacks->global_request_function(
1883
0
                session,
1884
0
                msg,
1885
0
                session->common.callbacks->userdata);
1886
0
        } else if (want_reply) {
1887
0
            ssh_message_global_request_reply_success(msg, 0);
1888
0
        }
1889
0
    } else if (strcmp(request, "no-more-sessions@openssh.com") == 0) {
1890
0
        msg->global_request.type = SSH_GLOBAL_REQUEST_NO_MORE_SESSIONS;
1891
0
        msg->global_request.want_reply = want_reply;
1892
1893
0
        SSH_LOG(SSH_LOG_PROTOCOL,
1894
0
                "Received no-more-sessions@openssh.com %hhu",
1895
0
                want_reply);
1896
0
        if (ssh_callbacks_exists(session->common.callbacks,
1897
0
                                 global_request_function)) {
1898
0
            SSH_LOG(SSH_LOG_DEBUG,
1899
0
                    "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %hhu",
1900
0
                    request,
1901
0
                    want_reply);
1902
0
            session->common.callbacks->global_request_function(
1903
0
                session,
1904
0
                msg,
1905
0
                session->common.callbacks->userdata);
1906
0
        } else if (want_reply) {
1907
0
            ssh_message_global_request_reply_success(msg, 0);
1908
0
        }
1909
1910
0
        session->flags |= SSH_SESSION_FLAG_NO_MORE_SESSIONS;
1911
0
    } else {
1912
0
        SSH_LOG(SSH_LOG_DEBUG,
1913
0
                "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s, want_reply = %hhu",
1914
0
                request,
1915
0
                want_reply);
1916
0
        goto reply_with_failure;
1917
0
    }
1918
1919
0
    SAFE_FREE(msg);
1920
0
    SAFE_FREE(request);
1921
0
    return rc;
1922
1923
0
reply_with_failure:
1924
    /* Only report the failure if requested */
1925
0
    if (want_reply) {
1926
0
        r = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_REQUEST_FAILURE);
1927
0
        if (r < 0) {
1928
0
            ssh_set_error_oom(session);
1929
0
            goto error;
1930
0
        }
1931
1932
0
        r = ssh_packet_send(session);
1933
0
        if (r != SSH_OK) {
1934
0
            goto error;
1935
0
        }
1936
0
    } else {
1937
0
        SSH_LOG(SSH_LOG_PACKET,
1938
0
                "The requester doesn't want to know the request failed!");
1939
0
    }
1940
1941
    /* Consume the message to avoid sending UNIMPLEMENTED later */
1942
0
    rc = SSH_PACKET_USED;
1943
0
error:
1944
0
    SAFE_FREE(msg);
1945
0
    SAFE_FREE(request);
1946
0
    SSH_LOG(SSH_LOG_TRACE, "Invalid SSH_MSG_GLOBAL_REQUEST packet");
1947
0
    return rc;
1948
0
}
1949
1950
#endif /* WITH_SERVER */
1951
1952
/** @} */