Coverage Report

Created: 2026-10-22 06:47

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