Coverage Report

Created: 2023-09-25 07:10

/src/libssh/src/messages.c
Line
Count
Source (jump to first uncovered line)
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/dh.h"
44
#include "libssh/messages.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
31.1k
{
68
31.1k
    ssh_message msg = calloc(1, sizeof(struct ssh_message_struct));
69
31.1k
    if (msg == NULL) {
70
0
        return NULL;
71
0
    }
72
31.1k
    msg->session = session;
73
74
    /* Set states explicitly */
75
31.1k
    msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_NONE;
76
77
31.1k
    return msg;
78
31.1k
}
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
#ifdef WITH_SERVER
101
102
static int ssh_execute_server_request(ssh_session session, ssh_message msg)
103
7.35k
{
104
7.35k
    ssh_channel channel = NULL;
105
7.35k
    int rc;
106
107
7.35k
    switch(msg->type) {
108
3.12k
        case SSH_REQUEST_AUTH:
109
3.12k
            if (msg->auth_request.method == SSH_AUTH_METHOD_PASSWORD &&
110
3.12k
                ssh_callbacks_exists(session->server_callbacks, auth_password_function)) {
111
0
                rc = session->server_callbacks->auth_password_function(session,
112
0
                        msg->auth_request.username, msg->auth_request.password,
113
0
                        session->server_callbacks->userdata);
114
0
                if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) {
115
0
                    ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
116
0
                } else {
117
0
                    ssh_message_reply_default(msg);
118
0
                }
119
120
0
                return SSH_OK;
121
3.12k
            } else if(msg->auth_request.method == SSH_AUTH_METHOD_PUBLICKEY &&
122
3.12k
                      ssh_callbacks_exists(session->server_callbacks, auth_pubkey_function)) {
123
0
               rc = session->server_callbacks->auth_pubkey_function(session,
124
0
                       msg->auth_request.username, msg->auth_request.pubkey,
125
0
                       msg->auth_request.signature_state,
126
0
                       session->server_callbacks->userdata);
127
0
               if (msg->auth_request.signature_state != SSH_PUBLICKEY_STATE_NONE) {
128
0
                 if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) {
129
0
                   ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
130
0
                 } else {
131
0
                   ssh_message_reply_default(msg);
132
0
                 }
133
0
               } else {
134
0
                 if (rc == SSH_AUTH_SUCCESS) {
135
0
                   ssh_message_auth_reply_pk_ok_simple(msg);
136
0
                 } else {
137
0
                   ssh_message_reply_default(msg);
138
0
                 }
139
0
               }
140
141
0
               return SSH_OK;
142
3.12k
            } else if (msg->auth_request.method == SSH_AUTH_METHOD_NONE &&
143
3.12k
                       ssh_callbacks_exists(session->server_callbacks, auth_none_function)) {
144
1.44k
                rc = session->server_callbacks->auth_none_function(session,
145
1.44k
                    msg->auth_request.username, session->server_callbacks->userdata);
146
1.44k
                if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){
147
1.44k
                    ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
148
1.44k
                } else {
149
0
                    ssh_message_reply_default(msg);
150
0
                }
151
152
1.44k
                return SSH_OK;
153
1.44k
            }
154
1.68k
            break;
155
1.68k
        case SSH_REQUEST_CHANNEL_OPEN:
156
405
            if (msg->channel_request_open.type == SSH_CHANNEL_SESSION &&
157
405
                ssh_callbacks_exists(session->server_callbacks, channel_open_request_session_function)) {
158
0
                channel = session->server_callbacks->channel_open_request_session_function(session,
159
0
                        session->server_callbacks->userdata);
160
0
                if (channel != NULL) {
161
0
                    rc = ssh_message_channel_request_open_reply_accept_channel(msg, channel);
162
0
                    if (rc != SSH_OK) {
163
0
                        SSH_LOG(SSH_LOG_TRACE,
164
0
                                "Failed to send reply for accepting a channel "
165
0
                                "open");
166
0
                    }
167
0
                    return SSH_OK;
168
0
                } else {
169
0
                    ssh_message_reply_default(msg);
170
0
                }
171
172
0
                return SSH_OK;
173
0
            }
174
405
            break;
175
405
        case SSH_REQUEST_CHANNEL:
176
0
            channel = msg->channel_request.channel;
177
178
0
            if (msg->channel_request.type == SSH_CHANNEL_REQUEST_PTY){
179
0
                ssh_callbacks_iterate(channel->callbacks,
180
0
                                      ssh_channel_callbacks,
181
0
                                      channel_pty_request_function) {
182
0
                    rc = ssh_callbacks_iterate_exec(channel_pty_request_function,
183
0
                                                    session,
184
0
                                                    channel,
185
0
                                                    msg->channel_request.TERM,
186
0
                                                    msg->channel_request.width,
187
0
                                                    msg->channel_request.height,
188
0
                                                    msg->channel_request.pxwidth,
189
0
                                                    msg->channel_request.pxheight);
190
0
                    if (rc == 0) {
191
0
                        ssh_message_channel_request_reply_success(msg);
192
0
                    } else {
193
0
                        ssh_message_reply_default(msg);
194
0
                    }
195
0
                    return SSH_OK;
196
0
                }
197
0
                ssh_callbacks_iterate_end();
198
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_SHELL){
199
0
                ssh_callbacks_iterate(channel->callbacks,
200
0
                                      ssh_channel_callbacks,
201
0
                                      channel_shell_request_function) {
202
0
                    rc = ssh_callbacks_iterate_exec(channel_shell_request_function,
203
0
                                                    session,
204
0
                                                    channel);
205
0
                    if (rc == 0) {
206
0
                        ssh_message_channel_request_reply_success(msg);
207
0
                    } else {
208
0
                        ssh_message_reply_default(msg);
209
0
                    }
210
0
                    return SSH_OK;
211
0
                }
212
0
                ssh_callbacks_iterate_end();
213
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_X11){
214
0
                ssh_callbacks_iterate(channel->callbacks,
215
0
                                      ssh_channel_callbacks,
216
0
                                      channel_x11_req_function) {
217
0
                    ssh_callbacks_iterate_exec(channel_x11_req_function,
218
0
                                               session,
219
0
                                               channel,
220
0
                                               msg->channel_request.x11_single_connection,
221
0
                                               msg->channel_request.x11_auth_protocol,
222
0
                                               msg->channel_request.x11_auth_cookie,
223
0
                                               msg->channel_request.x11_screen_number);
224
0
                    ssh_message_channel_request_reply_success(msg);
225
0
                    return SSH_OK;
226
0
                }
227
0
                ssh_callbacks_iterate_end();
228
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_WINDOW_CHANGE){
229
0
                ssh_callbacks_iterate(channel->callbacks,
230
0
                                      ssh_channel_callbacks,
231
0
                                      channel_pty_window_change_function) {
232
0
                    rc = ssh_callbacks_iterate_exec(channel_pty_window_change_function,
233
0
                                                    session,
234
0
                                                    channel,
235
0
                                                    msg->channel_request.width,
236
0
                                                    msg->channel_request.height,
237
0
                                                    msg->channel_request.pxwidth,
238
0
                                                    msg->channel_request.pxheight);
239
0
                    if (rc != SSH_OK) {
240
0
                        SSH_LOG(SSH_LOG_TRACE,
241
0
                                "Failed to iterate callbacks for window change");
242
0
                    }
243
0
                    return SSH_OK;
244
0
                }
245
0
                ssh_callbacks_iterate_end();
246
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_EXEC){
247
0
                ssh_callbacks_iterate(channel->callbacks,
248
0
                                      ssh_channel_callbacks,
249
0
                                      channel_exec_request_function) {
250
0
                    rc = ssh_callbacks_iterate_exec(channel_exec_request_function,
251
0
                                                    session,
252
0
                                                    channel,
253
0
                                                    msg->channel_request.command);
254
0
                    if (rc == 0) {
255
0
                        ssh_message_channel_request_reply_success(msg);
256
0
                    } else {
257
0
                        ssh_message_reply_default(msg);
258
0
                    }
259
260
0
                    return SSH_OK;
261
0
                }
262
0
                ssh_callbacks_iterate_end();
263
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_ENV){
264
0
                ssh_callbacks_iterate(channel->callbacks,
265
0
                                      ssh_channel_callbacks,
266
0
                                      channel_env_request_function) {
267
0
                    rc = ssh_callbacks_iterate_exec(channel_env_request_function,
268
0
                                                    session,
269
0
                                                    channel,
270
0
                                                    msg->channel_request.var_name,
271
0
                                                    msg->channel_request.var_value);
272
0
                    if (rc == 0) {
273
0
                        ssh_message_channel_request_reply_success(msg);
274
0
                    } else {
275
0
                        ssh_message_reply_default(msg);
276
0
                    }
277
0
                    return SSH_OK;
278
0
                }
279
0
                ssh_callbacks_iterate_end();
280
0
            } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_SUBSYSTEM){
281
0
                ssh_callbacks_iterate(channel->callbacks,
282
0
                                      ssh_channel_callbacks,
283
0
                                      channel_subsystem_request_function) {
284
0
                    rc = ssh_callbacks_iterate_exec(channel_subsystem_request_function,
285
0
                                                    session,
286
0
                                                    channel,
287
0
                                                    msg->channel_request.subsystem);
288
0
                    if (rc == 0) {
289
0
                        ssh_message_channel_request_reply_success(msg);
290
0
                    } else {
291
0
                        ssh_message_reply_default(msg);
292
0
                    }
293
294
0
                    return SSH_OK;
295
0
                }
296
0
                ssh_callbacks_iterate_end();
297
0
            }
298
0
            break;
299
3.82k
        case SSH_REQUEST_SERVICE:
300
3.82k
            if (ssh_callbacks_exists(session->server_callbacks, service_request_function)) {
301
0
                rc = session->server_callbacks->service_request_function(session,
302
0
                        msg->service_request.service, session->server_callbacks->userdata);
303
0
                if (rc == 0) {
304
0
                    ssh_message_reply_default(msg);
305
0
                } else {
306
0
                    ssh_disconnect(session);
307
0
                }
308
309
0
                return SSH_OK;
310
0
            }
311
312
3.82k
            return SSH_AGAIN;
313
0
        case SSH_REQUEST_GLOBAL:
314
0
            break;
315
7.35k
    }
316
317
2.08k
    return SSH_AGAIN;
318
7.35k
}
319
320
static int ssh_reply_channel_open_request(ssh_message msg, ssh_channel channel)
321
0
{
322
0
    if (channel != NULL) {
323
0
        return ssh_message_channel_request_open_reply_accept_channel(msg, channel);
324
0
    }
325
326
0
    ssh_message_reply_default(msg);
327
328
0
    return SSH_OK;
329
0
}
330
331
static int ssh_execute_client_request(ssh_session session, ssh_message msg)
332
0
{
333
0
    ssh_channel channel = NULL;
334
0
    int rc = SSH_AGAIN;
335
336
0
    if (msg->type == SSH_REQUEST_CHANNEL_OPEN
337
0
        && msg->channel_request_open.type == SSH_CHANNEL_X11
338
0
        && ssh_callbacks_exists(session->common.callbacks, channel_open_request_x11_function)) {
339
0
        channel = session->common.callbacks->channel_open_request_x11_function (session,
340
0
                msg->channel_request_open.originator,
341
0
                msg->channel_request_open.originator_port,
342
0
                session->common.callbacks->userdata);
343
344
0
        return ssh_reply_channel_open_request(msg, channel);
345
0
    } else if (msg->type == SSH_REQUEST_CHANNEL_OPEN
346
0
               && msg->channel_request_open.type == SSH_CHANNEL_AUTH_AGENT
347
0
               && ssh_callbacks_exists(session->common.callbacks, channel_open_request_auth_agent_function)) {
348
0
        channel = session->common.callbacks->channel_open_request_auth_agent_function (session,
349
0
                session->common.callbacks->userdata);
350
351
0
        return ssh_reply_channel_open_request(msg, channel);
352
0
    } else if (msg->type == SSH_REQUEST_CHANNEL_OPEN
353
0
               && msg->channel_request_open.type == SSH_CHANNEL_FORWARDED_TCPIP
354
0
               && ssh_callbacks_exists(session->common.callbacks, channel_open_request_forwarded_tcpip_function)) {
355
0
        channel = session->common.callbacks->channel_open_request_forwarded_tcpip_function(session,
356
0
                msg->channel_request_open.destination,
357
0
                msg->channel_request_open.destination_port,
358
0
                msg->channel_request_open.originator,
359
0
                msg->channel_request_open.originator_port,
360
0
                session->common.callbacks->userdata);
361
362
0
        return ssh_reply_channel_open_request(msg, channel);
363
0
    }
364
365
0
    return rc;
366
0
}
367
368
/** @internal
369
 * Executes the callbacks defined in session->server_callbacks, out of an ssh_message
370
 * I don't like ssh_message interface but it works.
371
 * @returns SSH_OK if the message has been handled, or SSH_AGAIN otherwise.
372
 */
373
7.35k
static int ssh_execute_server_callbacks(ssh_session session, ssh_message msg){
374
7.35k
    int rc = SSH_AGAIN;
375
376
7.35k
    if (session->server_callbacks != NULL){
377
7.35k
        rc = ssh_execute_server_request(session, msg);
378
7.35k
    } else if (session->common.callbacks != NULL) {
379
        /* This one is in fact a client callback... */
380
0
        rc = ssh_execute_client_request(session, msg);
381
0
    }
382
383
7.35k
    return rc;
384
7.35k
}
385
386
#endif /* WITH_SERVER */
387
388
0
static int ssh_execute_message_callback(ssh_session session, ssh_message msg) {
389
0
  int ret;
390
0
    if(session->ssh_message_callback != NULL) {
391
0
        ret = session->ssh_message_callback(session, msg,
392
0
                session->ssh_message_callback_data);
393
0
        if(ret == 1) {
394
0
            ret = ssh_message_reply_default(msg);
395
0
            SSH_MESSAGE_FREE(msg);
396
0
            if(ret != SSH_OK) {
397
0
                return ret;
398
0
            }
399
0
        } else {
400
0
            SSH_MESSAGE_FREE(msg);
401
0
        }
402
0
    } else {
403
0
        ret = ssh_message_reply_default(msg);
404
0
        SSH_MESSAGE_FREE(msg);
405
0
        if(ret != SSH_OK) {
406
0
            return ret;
407
0
        }
408
0
    }
409
0
    return SSH_OK;
410
0
}
411
412
/**
413
 * @internal
414
 *
415
 * @brief Add a message to the current queue of messages to be parsed and/or call
416
 * the various callback functions.
417
 *
418
 * @param[in]  session  The SSH session to add the message.
419
 *
420
 * @param[in]  message  The message to add to the queue.
421
 */
422
static void ssh_message_queue(ssh_session session, ssh_message message)
423
7.35k
{
424
7.35k
#ifdef WITH_SERVER
425
7.35k
    int ret;
426
7.35k
#endif
427
428
7.35k
    if (message == NULL) {
429
0
        return;
430
0
    }
431
432
7.35k
#ifdef WITH_SERVER
433
    /* probably not the best place to execute server callbacks, but still better
434
     * than nothing.
435
     */
436
7.35k
    ret = ssh_execute_server_callbacks(session, message);
437
7.35k
    if (ret == SSH_OK) {
438
1.44k
        SSH_MESSAGE_FREE(message);
439
1.44k
        return;
440
1.44k
    }
441
5.90k
#endif /* WITH_SERVER */
442
443
5.90k
    if (session->ssh_message_callback != NULL) {
444
        /* This will transfer the message, do not free. */
445
0
        ssh_execute_message_callback(session, message);
446
0
        return;
447
0
    }
448
449
5.90k
    if (session->server_callbacks != NULL) {
450
        /* if we have server callbacks, but nothing was executed, it means we are
451
         * in non-synchronous mode, and we just don't care about the message we
452
         * received. Just send a default response. Do not queue it.
453
         */
454
5.90k
        ssh_message_reply_default(message);
455
5.90k
        SSH_MESSAGE_FREE(message);
456
5.90k
        return;
457
5.90k
    }
458
459
0
    if (session->ssh_message_list == NULL) {
460
0
        session->ssh_message_list = ssh_list_new();
461
0
        if (session->ssh_message_list == NULL) {
462
            /*
463
             * If the message list couldn't be allocated, the message can't be
464
             * enqueued
465
             */
466
0
            ssh_message_reply_default(message);
467
0
            ssh_set_error_oom(session);
468
0
            SSH_MESSAGE_FREE(message);
469
0
            return;
470
0
        }
471
0
    }
472
473
    /* This will transfer the message, do not free. */
474
0
    ssh_list_append(session->ssh_message_list, message);
475
0
    return;
476
0
}
477
478
/**
479
 * @internal
480
 *
481
 * @brief Pop a message from the message list and dequeue it.
482
 *
483
 * @param[in]  session  The SSH session to pop the message.
484
 *
485
 * @returns             The head message or NULL if it doesn't exist.
486
 */
487
0
ssh_message ssh_message_pop_head(ssh_session session){
488
0
  ssh_message msg=NULL;
489
0
  struct ssh_iterator *i;
490
0
  if(session->ssh_message_list == NULL)
491
0
    return NULL;
492
0
  i=ssh_list_get_iterator(session->ssh_message_list);
493
0
  if(i != NULL){
494
0
    msg=ssh_iterator_value(ssh_message,i);
495
0
    ssh_list_remove(session->ssh_message_list,i);
496
0
  }
497
0
  return msg;
498
0
}
499
500
/* Returns 1 if there is a message available */
501
0
static int ssh_message_termination(void *s){
502
0
  ssh_session session = s;
503
0
  struct ssh_iterator *it;
504
0
  if(session->session_state == SSH_SESSION_STATE_ERROR)
505
0
    return 1;
506
0
  it = ssh_list_get_iterator(session->ssh_message_list);
507
0
  if(!it)
508
0
    return 0;
509
0
  else
510
0
    return 1;
511
0
}
512
/**
513
 * @brief Retrieve a SSH message from a SSH session.
514
 *
515
 * @param[in]  session  The SSH session to get the message.
516
 *
517
 * @returns             The SSH message received, NULL in case of error, or timeout
518
 *                      elapsed.
519
 *
520
 * @warning This function blocks until a message has been received. Betterset up
521
 *          a callback if this behavior is unwanted.
522
 */
523
ssh_message ssh_message_get(ssh_session session)
524
0
{
525
0
    ssh_message msg = NULL;
526
0
    int rc;
527
528
0
    msg = ssh_message_pop_head(session);
529
0
    if (msg != NULL) {
530
0
        return msg;
531
0
    }
532
0
    if (session->ssh_message_list == NULL) {
533
0
        session->ssh_message_list = ssh_list_new();
534
0
        if (session->ssh_message_list == NULL) {
535
0
            ssh_set_error_oom(session);
536
0
            return NULL;
537
0
        }
538
0
    }
539
0
    rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
540
0
                                        ssh_message_termination, session);
541
0
    if (rc || session->session_state == SSH_SESSION_STATE_ERROR) {
542
0
        return NULL;
543
0
    }
544
0
    msg = ssh_list_pop_head(ssh_message, session->ssh_message_list);
545
546
0
    return msg;
547
0
}
548
549
/**
550
 * @brief Get the type of the message.
551
 *
552
 * @param[in] msg       The message to get the type from.
553
 *
554
 * @return              The message type or -1 on error.
555
 */
556
0
int ssh_message_type(ssh_message msg) {
557
0
  if (msg == NULL) {
558
0
    return -1;
559
0
  }
560
561
0
  return msg->type;
562
0
}
563
564
/**
565
 * @brief Get the subtype of the message.
566
 *
567
 * @param[in] msg       The message to get the subtype from.
568
 *
569
 * @return              The message type or -1 on error.
570
 */
571
0
int ssh_message_subtype(ssh_message msg) {
572
0
  if (msg == NULL) {
573
0
    return -1;
574
0
  }
575
576
0
  switch(msg->type) {
577
0
    case SSH_REQUEST_AUTH:
578
0
      return msg->auth_request.method;
579
0
    case SSH_REQUEST_CHANNEL_OPEN:
580
0
      return msg->channel_request_open.type;
581
0
    case SSH_REQUEST_CHANNEL:
582
0
      return msg->channel_request.type;
583
0
    case SSH_REQUEST_GLOBAL:
584
0
      return msg->global_request.type;
585
0
  }
586
587
0
  return -1;
588
0
}
589
590
/**
591
 * @brief Free a SSH message.
592
 *
593
 * @param[in] msg       The message to release the memory.
594
 */
595
30.2k
void ssh_message_free(ssh_message msg){
596
30.2k
  if (msg == NULL) {
597
0
    return;
598
0
  }
599
600
30.2k
  switch(msg->type) {
601
25.9k
    case SSH_REQUEST_AUTH:
602
25.9k
      SAFE_FREE(msg->auth_request.username);
603
25.9k
      SAFE_FREE(msg->auth_request.sigtype);
604
25.9k
      if (msg->auth_request.password) {
605
47
        explicit_bzero(msg->auth_request.password,
606
47
                       strlen(msg->auth_request.password));
607
47
        SAFE_FREE(msg->auth_request.password);
608
47
      }
609
25.9k
      ssh_key_free(msg->auth_request.pubkey);
610
25.9k
      break;
611
435
    case SSH_REQUEST_CHANNEL_OPEN:
612
435
      SAFE_FREE(msg->channel_request_open.originator);
613
435
      SAFE_FREE(msg->channel_request_open.destination);
614
435
      break;
615
0
    case SSH_REQUEST_CHANNEL:
616
0
      SAFE_FREE(msg->channel_request.TERM);
617
0
      SAFE_FREE(msg->channel_request.modes);
618
0
      SAFE_FREE(msg->channel_request.var_name);
619
0
      SAFE_FREE(msg->channel_request.var_value);
620
0
      SAFE_FREE(msg->channel_request.command);
621
0
      SAFE_FREE(msg->channel_request.subsystem);
622
0
      switch (msg->channel_request.type) {
623
0
      case SSH_CHANNEL_REQUEST_EXEC:
624
0
          SAFE_FREE(msg->channel_request.command);
625
0
          break;
626
0
      case SSH_CHANNEL_REQUEST_ENV:
627
0
          SAFE_FREE(msg->channel_request.var_name);
628
0
          SAFE_FREE(msg->channel_request.var_value);
629
0
          break;
630
0
      case SSH_CHANNEL_REQUEST_PTY:
631
0
          SAFE_FREE(msg->channel_request.TERM);
632
0
          break;
633
0
      case SSH_CHANNEL_REQUEST_SUBSYSTEM:
634
0
          SAFE_FREE(msg->channel_request.subsystem);
635
0
          break;
636
0
      case SSH_CHANNEL_REQUEST_X11:
637
0
          SAFE_FREE(msg->channel_request.x11_auth_protocol);
638
0
          SAFE_FREE(msg->channel_request.x11_auth_cookie);
639
0
          break;
640
0
      }
641
0
      break;
642
3.82k
    case SSH_REQUEST_SERVICE:
643
3.82k
      SAFE_FREE(msg->service_request.service);
644
3.82k
      break;
645
0
    case SSH_REQUEST_GLOBAL:
646
0
      SAFE_FREE(msg->global_request.bind_address);
647
0
      break;
648
30.2k
  }
649
30.2k
  ZERO_STRUCTP(msg);
650
30.2k
  SAFE_FREE(msg);
651
30.2k
}
652
653
#ifdef WITH_SERVER
654
655
SSH_PACKET_CALLBACK(ssh_packet_service_request)
656
6.05k
{
657
6.05k
    char *service_c = NULL;
658
6.05k
    ssh_message msg = NULL;
659
6.05k
    int rc;
660
661
6.05k
    (void)type;
662
6.05k
    (void)user;
663
664
6.05k
    rc = ssh_buffer_unpack(packet,
665
6.05k
                           "s",
666
6.05k
                           &service_c);
667
6.05k
    if (rc != SSH_OK) {
668
2.23k
        ssh_set_error(session,
669
2.23k
                      SSH_FATAL,
670
2.23k
                      "Invalid SSH_MSG_SERVICE_REQUEST packet");
671
2.23k
        goto error;
672
2.23k
    }
673
674
3.82k
    SSH_LOG(SSH_LOG_PACKET,
675
3.82k
            "Received a SERVICE_REQUEST for service %s",
676
3.82k
            service_c);
677
678
3.82k
    msg = ssh_message_new(session);
679
3.82k
    if (msg == NULL) {
680
0
        SAFE_FREE(service_c);
681
0
        goto error;
682
0
    }
683
684
3.82k
    msg->type = SSH_REQUEST_SERVICE;
685
3.82k
    msg->service_request.service = service_c;
686
687
3.82k
    ssh_message_queue(session, msg);
688
6.05k
error:
689
690
6.05k
    return SSH_PACKET_USED;
691
3.82k
}
692
693
694
/*
695
 * This function concats in a buffer the values needed to do a signature
696
 * verification.
697
 */
698
static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
699
                                                ssh_message msg,
700
                                                const char *service,
701
                                                ssh_string algo)
702
13.3k
{
703
13.3k
    struct ssh_crypto_struct *crypto = NULL;
704
13.3k
    ssh_buffer buffer;
705
13.3k
    ssh_string str=NULL;
706
13.3k
    int rc;
707
708
13.3k
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
709
13.3k
    if (crypto == NULL) {
710
0
        return NULL;
711
0
    }
712
713
13.3k
    buffer = ssh_buffer_new();
714
13.3k
    if (buffer == NULL) {
715
0
        return NULL;
716
0
    }
717
13.3k
    rc = ssh_pki_export_pubkey_blob(msg->auth_request.pubkey, &str);
718
13.3k
    if (rc < 0) {
719
605
        SSH_BUFFER_FREE(buffer);
720
605
        return NULL;
721
605
    }
722
723
12.7k
    rc = ssh_buffer_pack(buffer,
724
12.7k
                         "dPbsssbsS",
725
12.7k
                         crypto->session_id_len, /* session ID string */
726
12.7k
                         crypto->session_id_len, crypto->session_id,
727
12.7k
                         SSH2_MSG_USERAUTH_REQUEST, /* type */
728
12.7k
                         msg->auth_request.username,
729
12.7k
                         service,
730
12.7k
                         "publickey", /* method */
731
12.7k
                         1, /* has to be signed (true) */
732
12.7k
                         ssh_string_get_char(algo), /* pubkey algorithm */
733
12.7k
                         str); /* public key as a blob */
734
735
12.7k
    SSH_STRING_FREE(str);
736
12.7k
    if (rc != SSH_OK) {
737
0
        ssh_set_error_oom(session);
738
0
        SSH_BUFFER_FREE(buffer);
739
0
        return NULL;
740
0
    }
741
742
12.7k
    return buffer;
743
12.7k
}
744
745
/**
746
 * @internal
747
 *
748
 * @brief Handle a SSH_MSG_MSG_USERAUTH_REQUEST packet and queue a
749
 * SSH Message
750
 */
751
25.9k
SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
752
25.9k
  ssh_message msg = NULL;
753
25.9k
  ssh_signature sig = NULL;
754
25.9k
  char *service = NULL;
755
25.9k
  char *method = NULL;
756
25.9k
  int cmp;
757
25.9k
  int rc;
758
759
25.9k
  (void)user;
760
25.9k
  (void)type;
761
762
25.9k
  msg = ssh_message_new(session);
763
25.9k
  if (msg == NULL) {
764
0
    ssh_set_error_oom(session);
765
0
    goto error;
766
0
  }
767
25.9k
  msg->type = SSH_REQUEST_AUTH;
768
25.9k
  rc = ssh_buffer_unpack(packet,
769
25.9k
                         "sss",
770
25.9k
                         &msg->auth_request.username,
771
25.9k
                         &service,
772
25.9k
                         &method);
773
774
25.9k
  if (rc != SSH_OK) {
775
5.34k
      goto error;
776
5.34k
  }
777
778
20.6k
  SSH_LOG(SSH_LOG_PACKET,
779
20.6k
      "Auth request for service %s, method %s for user '%s'",
780
20.6k
      service, method,
781
20.6k
      msg->auth_request.username);
782
783
20.6k
  cmp = strcmp(service, "ssh-connection");
784
20.6k
  if (cmp != 0) {
785
766
      SSH_LOG(SSH_LOG_TRACE,
786
766
              "Invalid service request: %s",
787
766
              service);
788
766
      goto end;
789
766
  }
790
791
19.8k
  if (strcmp(method, "none") == 0) {
792
1.44k
    msg->auth_request.method = SSH_AUTH_METHOD_NONE;
793
1.44k
    goto end;
794
1.44k
  }
795
796
18.4k
  if (strcmp(method, "password") == 0) {
797
246
    uint8_t tmp;
798
799
246
    msg->auth_request.method = SSH_AUTH_METHOD_PASSWORD;
800
246
    rc = ssh_buffer_unpack(packet, "bs", &tmp, &msg->auth_request.password);
801
246
    if (rc != SSH_OK) {
802
199
      goto error;
803
199
    }
804
47
    goto end;
805
246
  }
806
807
18.1k
  if (strcmp(method, "keyboard-interactive") == 0) {
808
166
    ssh_string lang = NULL;
809
166
    ssh_string submethods = NULL;
810
811
166
    msg->auth_request.method = SSH_AUTH_METHOD_INTERACTIVE;
812
166
    lang = ssh_buffer_get_ssh_string(packet);
813
166
    if (lang == NULL) {
814
66
      goto error;
815
66
    }
816
    /* from the RFC 4256
817
     * 3.1.  Initial Exchange
818
     * "The language tag is deprecated and SHOULD be the empty string."
819
     */
820
100
    SSH_STRING_FREE(lang);
821
822
100
    submethods = ssh_buffer_get_ssh_string(packet);
823
100
    if (submethods == NULL) {
824
66
      goto error;
825
66
    }
826
    /* from the RFC 4256
827
     * 3.1.  Initial Exchange
828
     * "One possible implementation strategy of the submethods field on the
829
     *  server is that, unless the user may use multiple different
830
     *  submethods, the server ignores this field."
831
     */
832
34
    SSH_STRING_FREE(submethods);
833
834
34
    goto end;
835
100
  }
836
837
18.0k
  if (strcmp(method, "publickey") == 0) {
838
17.3k
    ssh_string algo = NULL;
839
17.3k
    ssh_string pubkey_blob = NULL;
840
17.3k
    uint8_t has_sign;
841
842
17.3k
    msg->auth_request.method = SSH_AUTH_METHOD_PUBLICKEY;
843
17.3k
    SAFE_FREE(method);
844
17.3k
    rc = ssh_buffer_unpack(packet, "bSS",
845
17.3k
            &has_sign,
846
17.3k
            &algo,
847
17.3k
            &pubkey_blob
848
17.3k
            );
849
850
17.3k
    if (rc != SSH_OK) {
851
390
      goto error;
852
390
    }
853
854
16.9k
    rc = ssh_pki_import_pubkey_blob(pubkey_blob, &msg->auth_request.pubkey);
855
16.9k
    SSH_STRING_FREE(pubkey_blob);
856
16.9k
    pubkey_blob = NULL;
857
16.9k
    if (rc < 0) {
858
3.10k
        SSH_STRING_FREE(algo);
859
3.10k
        algo = NULL;
860
3.10k
        goto error;
861
3.10k
    }
862
13.8k
    msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_NONE;
863
13.8k
    msg->auth_request.sigtype = strdup(ssh_string_get_char(algo));
864
13.8k
    if (msg->auth_request.sigtype == NULL) {
865
0
        msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
866
0
        SSH_STRING_FREE(algo);
867
0
        algo = NULL;
868
0
        goto error;
869
0
    }
870
871
    // has a valid signature ?
872
13.8k
    if(has_sign) {
873
13.6k
        ssh_string sig_blob = NULL;
874
13.6k
        ssh_buffer digest = NULL;
875
876
13.6k
        sig_blob = ssh_buffer_get_ssh_string(packet);
877
13.6k
        if(sig_blob == NULL) {
878
285
            SSH_LOG(SSH_LOG_PACKET, "Invalid signature packet from peer");
879
285
            msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
880
285
            SSH_STRING_FREE(algo);
881
285
            algo = NULL;
882
285
            goto error;
883
285
        }
884
885
13.3k
        digest = ssh_msg_userauth_build_digest(session, msg, service, algo);
886
13.3k
        SSH_STRING_FREE(algo);
887
13.3k
        algo = NULL;
888
13.3k
        if (digest == NULL) {
889
605
            SSH_STRING_FREE(sig_blob);
890
605
            SSH_LOG(SSH_LOG_PACKET, "Failed to get digest");
891
605
            msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
892
605
            goto error;
893
605
        }
894
895
12.7k
        rc = ssh_pki_import_signature_blob(sig_blob,
896
12.7k
                                           msg->auth_request.pubkey,
897
12.7k
                                           &sig);
898
12.7k
        if (rc == SSH_OK) {
899
            /* Check if the signature from client matches server preferences */
900
2.77k
            if (session->opts.pubkey_accepted_types) {
901
0
                if (!ssh_match_group(session->opts.pubkey_accepted_types,
902
0
                            sig->type_c))
903
0
                {
904
0
                    ssh_set_error(session,
905
0
                            SSH_FATAL,
906
0
                            "Public key from client (%s) doesn't match server "
907
0
                            "preference (%s)",
908
0
                            sig->type_c,
909
0
                            session->opts.pubkey_accepted_types);
910
0
                    rc = SSH_ERROR;
911
0
                }
912
0
            }
913
914
2.77k
            if (rc == SSH_OK) {
915
2.77k
                rc = ssh_pki_signature_verify(session,
916
2.77k
                                              sig,
917
2.77k
                                              msg->auth_request.pubkey,
918
2.77k
                                              ssh_buffer_get(digest),
919
2.77k
                                              ssh_buffer_get_len(digest));
920
2.77k
            }
921
2.77k
        }
922
12.7k
        SSH_STRING_FREE(sig_blob);
923
12.7k
        SSH_BUFFER_FREE(digest);
924
12.7k
        ssh_signature_free(sig);
925
12.7k
        if (rc < 0) {
926
12.7k
            SSH_LOG(
927
12.7k
                    SSH_LOG_PACKET,
928
12.7k
                    "Received an invalid signature from peer");
929
12.7k
            msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
930
12.7k
            goto error;
931
12.7k
        }
932
933
0
        SSH_LOG(SSH_LOG_PACKET, "Valid signature received");
934
935
0
        msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_VALID;
936
0
    }
937
194
    SSH_STRING_FREE(algo);
938
194
    goto end;
939
13.8k
  }
940
#ifdef WITH_GSSAPI
941
  if (strcmp(method, "gssapi-with-mic") == 0) {
942
     uint32_t n_oid;
943
     ssh_string *oids;
944
     ssh_string oid;
945
     char *hexa;
946
     int i;
947
     ssh_buffer_get_u32(packet, &n_oid);
948
     n_oid=ntohl(n_oid);
949
     if(n_oid > 100){
950
       ssh_set_error(session, SSH_FATAL, "USERAUTH_REQUEST: gssapi-with-mic OID count too big (%d)",n_oid);
951
       goto error;
952
     }
953
     SSH_LOG(SSH_LOG_PACKET, "gssapi: %d OIDs", n_oid);
954
     oids = calloc(n_oid, sizeof(ssh_string));
955
     if (oids == NULL){
956
       ssh_set_error_oom(session);
957
       goto error;
958
     }
959
     for (i=0;i<(int) n_oid;++i){
960
       oid=ssh_buffer_get_ssh_string(packet);
961
       if(oid == NULL){
962
         for(i=i-1;i>=0;--i){
963
           SAFE_FREE(oids[i]);
964
         }
965
         SAFE_FREE(oids);
966
         ssh_set_error(session, SSH_LOG_PACKET, "USERAUTH_REQUEST: gssapi-with-mic missing OID");
967
         goto error;
968
       }
969
       oids[i] = oid;
970
       if(session->common.log_verbosity >= SSH_LOG_PACKET){
971
         hexa = ssh_get_hexa(ssh_string_data(oid), ssh_string_len(oid));
972
         SSH_LOG(SSH_LOG_PACKET,"gssapi: OID %d: %s",i, hexa);
973
         SAFE_FREE(hexa);
974
       }
975
     }
976
     ssh_gssapi_handle_userauth(session, msg->auth_request.username, n_oid, oids);
977
978
     for(i=0;i<(int)n_oid;++i){
979
       SAFE_FREE(oids[i]);
980
     }
981
     SAFE_FREE(oids);
982
     /* bypass the message queue thing */
983
     SAFE_FREE(service);
984
     SAFE_FREE(method);
985
     SSH_MESSAGE_FREE(msg);
986
987
     return SSH_PACKET_USED;
988
  }
989
#endif
990
991
641
  msg->auth_request.method = SSH_AUTH_METHOD_UNKNOWN;
992
641
  SAFE_FREE(method);
993
641
  goto end;
994
22.8k
error:
995
22.8k
  SAFE_FREE(service);
996
22.8k
  SAFE_FREE(method);
997
998
22.8k
  SSH_MESSAGE_FREE(msg);
999
1000
22.8k
  return SSH_PACKET_USED;
1001
3.12k
end:
1002
3.12k
  SAFE_FREE(service);
1003
3.12k
  SAFE_FREE(method);
1004
1005
3.12k
  ssh_message_queue(session,msg);
1006
1007
3.12k
  return SSH_PACKET_USED;
1008
18.0k
}
1009
1010
#endif /* WITH_SERVER */
1011
/**
1012
 * @internal
1013
 *
1014
 * @brief Handle a SSH_MSG_MSG_USERAUTH_INFO_RESPONSE packet and queue a
1015
 * SSH Message
1016
 */
1017
#ifndef WITH_SERVER
1018
SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
1019
    (void)session;
1020
    (void)type;
1021
    (void)packet;
1022
    (void)user;
1023
    return SSH_PACKET_USED;
1024
}
1025
#else /* WITH_SERVER */
1026
0
SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
1027
0
  uint32_t nanswers;
1028
0
  uint32_t i;
1029
0
  ssh_string tmp;
1030
0
  int rc;
1031
1032
0
  ssh_message msg = NULL;
1033
1034
  /* GSSAPI_TOKEN has same packed number. XXX fix this */
1035
#ifdef WITH_GSSAPI
1036
  if (session->gssapi != NULL) {
1037
      return ssh_packet_userauth_gssapi_token(session, type, packet, user);
1038
  }
1039
#endif
1040
0
  (void)user;
1041
0
  (void)type;
1042
1043
0
  msg = ssh_message_new(session);
1044
0
  if (msg == NULL) {
1045
0
    ssh_set_error_oom(session);
1046
0
    goto error;
1047
0
  }
1048
1049
  /* HACK: we forge a message to be able to handle it in the
1050
   * same switch() as other auth methods */
1051
0
  msg->type = SSH_REQUEST_AUTH;
1052
0
  msg->auth_request.method = SSH_AUTH_METHOD_INTERACTIVE;
1053
0
  msg->auth_request.kbdint_response = 1;
1054
#if 0 // should we wipe the username ?
1055
  msg->auth_request.username = NULL;
1056
#endif
1057
1058
0
  rc = ssh_buffer_unpack(packet, "d", &nanswers);
1059
0
  if (rc != SSH_OK) {
1060
0
      ssh_set_error_invalid(session);
1061
0
      goto error;
1062
0
  }
1063
1064
0
  if (session->kbdint == NULL) {
1065
0
    SSH_LOG(SSH_LOG_DEBUG, "Warning: Got a keyboard-interactive "
1066
0
                        "response but it seems we didn't send the request.");
1067
1068
0
    session->kbdint = ssh_kbdint_new();
1069
0
    if (session->kbdint == NULL) {
1070
0
      ssh_set_error_oom(session);
1071
1072
0
      goto error;
1073
0
    }
1074
0
  } else if (session->kbdint->answers != NULL) {
1075
0
      uint32_t n;
1076
1077
0
      for (n = 0; n < session->kbdint->nanswers; n++) {
1078
0
            explicit_bzero(session->kbdint->answers[n],
1079
0
                           strlen(session->kbdint->answers[n]));
1080
0
            SAFE_FREE(session->kbdint->answers[n]);
1081
0
      }
1082
0
      SAFE_FREE(session->kbdint->answers);
1083
0
      session->kbdint->nanswers = 0;
1084
0
  }
1085
1086
0
  SSH_LOG(SSH_LOG_PACKET,"kbdint: %" PRIu32 " answers", nanswers);
1087
0
  if (nanswers > KBDINT_MAX_PROMPT) {
1088
0
    ssh_set_error(session, SSH_FATAL,
1089
0
        "Too much answers received from client: %" PRIu32 " (0x%.4" PRIx32 ")",
1090
0
        nanswers, nanswers);
1091
0
    ssh_kbdint_free(session->kbdint);
1092
0
    session->kbdint = NULL;
1093
1094
0
    goto error;
1095
0
  }
1096
1097
0
  if(nanswers != session->kbdint->nprompts) {
1098
    /* warn but let the application handle this case */
1099
0
    SSH_LOG(SSH_LOG_DEBUG, "Warning: Number of prompts and answers"
1100
0
                " mismatch: p=%" PRIu32 " a=%" PRIu32, session->kbdint->nprompts, nanswers);
1101
0
  }
1102
0
  session->kbdint->nanswers = nanswers;
1103
1104
0
  session->kbdint->answers = calloc(nanswers, sizeof(char *));
1105
0
  if (session->kbdint->answers == NULL) {
1106
0
    session->kbdint->nanswers = 0;
1107
0
    ssh_set_error_oom(session);
1108
0
    ssh_kbdint_free(session->kbdint);
1109
0
    session->kbdint = NULL;
1110
1111
0
    goto error;
1112
0
  }
1113
1114
0
  for (i = 0; i < nanswers; i++) {
1115
0
    tmp = ssh_buffer_get_ssh_string(packet);
1116
0
    if (tmp == NULL) {
1117
0
      ssh_set_error(session, SSH_FATAL, "Short INFO_RESPONSE packet");
1118
0
      session->kbdint->nanswers = i;
1119
0
      ssh_kbdint_free(session->kbdint);
1120
0
      session->kbdint = NULL;
1121
1122
0
      goto error;
1123
0
    }
1124
0
    session->kbdint->answers[i] = ssh_string_to_char(tmp);
1125
0
    SSH_STRING_FREE(tmp);
1126
0
    if (session->kbdint->answers[i] == NULL) {
1127
0
      ssh_set_error_oom(session);
1128
0
      session->kbdint->nanswers = i;
1129
0
      ssh_kbdint_free(session->kbdint);
1130
0
      session->kbdint = NULL;
1131
1132
0
      goto error;
1133
0
    }
1134
0
  }
1135
1136
0
  ssh_message_queue(session,msg);
1137
1138
0
  return SSH_PACKET_USED;
1139
1140
0
error:
1141
0
  SSH_MESSAGE_FREE(msg);
1142
1143
0
  return SSH_PACKET_USED;
1144
0
}
1145
#endif /* WITH_SERVER */
1146
1147
435
SSH_PACKET_CALLBACK(ssh_packet_channel_open){
1148
435
  ssh_message msg = NULL;
1149
435
  char *type_c = NULL;
1150
435
  uint32_t originator_port, destination_port;
1151
435
  int rc;
1152
1153
435
  (void)type;
1154
435
  (void)user;
1155
435
  msg = ssh_message_new(session);
1156
435
  if (msg == NULL) {
1157
0
    ssh_set_error_oom(session);
1158
0
    goto error;
1159
0
  }
1160
1161
435
  msg->type = SSH_REQUEST_CHANNEL_OPEN;
1162
435
  rc = ssh_buffer_unpack(packet, "s", &type_c);
1163
435
  if (rc != SSH_OK){
1164
24
      goto error;
1165
24
  }
1166
1167
411
  SSH_LOG(SSH_LOG_PACKET,
1168
411
      "Clients wants to open a %s channel", type_c);
1169
1170
411
  ssh_buffer_unpack(packet,"ddd",
1171
411
          &msg->channel_request_open.sender,
1172
411
          &msg->channel_request_open.window,
1173
411
          &msg->channel_request_open.packet_size);
1174
1175
411
  if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED){
1176
0
    ssh_set_error(session,SSH_FATAL, "Invalid state when receiving channel open request (must be authenticated)");
1177
0
    goto error;
1178
0
  }
1179
1180
411
  if (strcmp(type_c, "session") == 0) {
1181
0
    if (session->flags & SSH_SESSION_FLAG_NO_MORE_SESSIONS) {
1182
0
        ssh_session_set_disconnect_message(session, "No more sessions allowed!");
1183
0
        ssh_set_error(session, SSH_FATAL, "No more sessions allowed!");
1184
0
        session->session_state = SSH_SESSION_STATE_ERROR;
1185
0
        ssh_disconnect(session);
1186
0
        goto error;
1187
0
    }
1188
1189
0
    msg->channel_request_open.type = SSH_CHANNEL_SESSION;
1190
0
    SAFE_FREE(type_c);
1191
0
    goto end;
1192
0
  }
1193
1194
411
  if (strcmp(type_c,"direct-tcpip") == 0) {
1195
0
    rc = ssh_buffer_unpack(packet,
1196
0
                           "sdsd",
1197
0
                           &msg->channel_request_open.destination,
1198
0
                           &destination_port,
1199
0
                           &msg->channel_request_open.originator,
1200
0
                           &originator_port);
1201
0
    if (rc != SSH_OK) {
1202
0
      goto error;
1203
0
    }
1204
1205
0
    msg->channel_request_open.destination_port = (uint16_t) destination_port;
1206
0
    msg->channel_request_open.originator_port = (uint16_t) originator_port;
1207
0
    msg->channel_request_open.type = SSH_CHANNEL_DIRECT_TCPIP;
1208
0
    goto end;
1209
0
  }
1210
1211
411
  if (strcmp(type_c,"forwarded-tcpip") == 0) {
1212
0
    rc = ssh_buffer_unpack(packet, "sdsd",
1213
0
            &msg->channel_request_open.destination,
1214
0
            &destination_port,
1215
0
            &msg->channel_request_open.originator,
1216
0
            &originator_port
1217
0
        );
1218
0
    if (rc != SSH_OK){
1219
0
        goto error;
1220
0
    }
1221
0
    msg->channel_request_open.destination_port = (uint16_t) destination_port;
1222
0
    msg->channel_request_open.originator_port = (uint16_t) originator_port;
1223
0
    msg->channel_request_open.type = SSH_CHANNEL_FORWARDED_TCPIP;
1224
0
    goto end;
1225
0
  }
1226
1227
411
  if (strcmp(type_c,"x11") == 0) {
1228
7
    rc = ssh_buffer_unpack(packet, "sd",
1229
7
            &msg->channel_request_open.originator,
1230
7
            &originator_port);
1231
7
    if (rc != SSH_OK){
1232
6
        goto error;
1233
6
    }
1234
1
    msg->channel_request_open.originator_port = (uint16_t) originator_port;
1235
1
    msg->channel_request_open.type = SSH_CHANNEL_X11;
1236
1
    goto end;
1237
7
  }
1238
1239
404
  if (strcmp(type_c,"auth-agent@openssh.com") == 0) {
1240
0
    msg->channel_request_open.type = SSH_CHANNEL_AUTH_AGENT;
1241
0
    goto end;
1242
0
  }
1243
1244
404
  msg->channel_request_open.type = SSH_CHANNEL_UNKNOWN;
1245
404
  goto end;
1246
1247
30
error:
1248
30
  SSH_MESSAGE_FREE(msg);
1249
435
end:
1250
435
  SAFE_FREE(type_c);
1251
435
  if(msg != NULL)
1252
405
    ssh_message_queue(session,msg);
1253
1254
435
  return SSH_PACKET_USED;
1255
30
}
1256
1257
/**
1258
 * @internal
1259
 *
1260
 * @brief This function accepts a channel open request for the specified channel.
1261
 *
1262
 * @param[in]  msg      The message.
1263
 *
1264
 * @param[in]  chan     The channel the request is made on.
1265
 *
1266
 * @returns             SSH_OK on success, SSH_ERROR if an error occurred.
1267
 */
1268
0
int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_channel chan) {
1269
0
    ssh_session session;
1270
0
    int rc;
1271
1272
0
    if (msg == NULL) {
1273
0
        return SSH_ERROR;
1274
0
    }
1275
1276
0
    session = msg->session;
1277
1278
0
    chan->local_channel = ssh_channel_new_id(session);
1279
0
    chan->local_maxpacket = 35000;
1280
0
    chan->local_window = 32000;
1281
0
    chan->remote_channel = msg->channel_request_open.sender;
1282
0
    chan->remote_maxpacket = msg->channel_request_open.packet_size;
1283
0
    chan->remote_window = msg->channel_request_open.window;
1284
0
    chan->state = SSH_CHANNEL_STATE_OPEN;
1285
0
    chan->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND;
1286
1287
0
    rc = ssh_buffer_pack(session->out_buffer,
1288
0
                         "bdddd",
1289
0
                         SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
1290
0
                         chan->remote_channel,
1291
0
                         chan->local_channel,
1292
0
                         chan->local_window,
1293
0
                         chan->local_maxpacket);
1294
0
    if (rc != SSH_OK) {
1295
0
        ssh_set_error_oom(session);
1296
0
        return SSH_ERROR;
1297
0
    }
1298
1299
0
    SSH_LOG(SSH_LOG_PACKET,
1300
0
            "Accepting a channel request_open for chan %" PRIu32,
1301
0
            chan->remote_channel);
1302
1303
0
    rc = ssh_packet_send(session);
1304
1305
0
    return rc;
1306
0
}
1307
1308
/**
1309
 * @internal
1310
 *
1311
 * @brief This function accepts a channel open request.
1312
 *
1313
 * @param[in]  msg      The message.
1314
 *
1315
 * @returns a valid ssh_channel handle if the request is to be allowed
1316
 *
1317
 * @returns NULL in case of error
1318
 */
1319
0
ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) {
1320
0
  ssh_channel chan;
1321
0
  int rc;
1322
1323
0
  if (msg == NULL) {
1324
0
      return NULL;
1325
0
  }
1326
1327
0
  chan = ssh_channel_new(msg->session);
1328
0
  if (chan == NULL) {
1329
0
    return NULL;
1330
0
  }
1331
0
  rc = ssh_message_channel_request_open_reply_accept_channel(msg, chan);
1332
0
  if (rc < 0) {
1333
0
    ssh_channel_free(chan);
1334
0
    chan = NULL;
1335
0
  }
1336
0
  return chan;
1337
1338
0
}
1339
1340
/**
1341
 * @internal
1342
 *
1343
 * @brief This function parses the last end of a channel request packet.
1344
 *
1345
 * This is normally converted to a SSH message and placed in the queue.
1346
 *
1347
 * @param[in]  session  The SSH session.
1348
 *
1349
 * @param[in]  channel  The channel the request is made on.
1350
 *
1351
 * @param[in]  packet   The rest of the packet to be parsed.
1352
 *
1353
 * @param[in]  request  The type of request.
1354
 *
1355
 * @param[in]  want_reply The want_reply field from the request.
1356
 *
1357
 * @returns             SSH_OK on success, SSH_ERROR if an error occurred.
1358
 */
1359
int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, ssh_buffer packet,
1360
0
    const char *request, uint8_t want_reply) {
1361
0
  ssh_message msg = NULL;
1362
0
  int rc;
1363
1364
0
  msg = ssh_message_new(session);
1365
0
  if (msg == NULL) {
1366
0
    ssh_set_error_oom(session);
1367
0
    goto error;
1368
0
  }
1369
1370
0
  SSH_LOG(SSH_LOG_PACKET,
1371
0
      "Received a %s channel_request for channel (%" PRIu32 ":%" PRIu32 ") (want_reply=%hhd)",
1372
0
      request, channel->local_channel, channel->remote_channel, want_reply);
1373
1374
0
  msg->type = SSH_REQUEST_CHANNEL;
1375
0
  msg->channel_request.channel = channel;
1376
0
  msg->channel_request.want_reply = want_reply;
1377
1378
0
  if (strcmp(request, "pty-req") == 0) {
1379
0
    rc = ssh_buffer_unpack(packet, "sddddS",
1380
0
            &msg->channel_request.TERM,
1381
0
            &msg->channel_request.width,
1382
0
            &msg->channel_request.height,
1383
0
            &msg->channel_request.pxwidth,
1384
0
            &msg->channel_request.pxheight,
1385
0
            &msg->channel_request.modes
1386
0
            );
1387
1388
0
    msg->channel_request.type = SSH_CHANNEL_REQUEST_PTY;
1389
1390
0
    if (rc != SSH_OK) {
1391
0
      goto error;
1392
0
    }
1393
0
    goto end;
1394
0
  }
1395
1396
0
  if (strcmp(request, "window-change") == 0) {
1397
0
    msg->channel_request.type = SSH_CHANNEL_REQUEST_WINDOW_CHANGE;
1398
0
    rc = ssh_buffer_unpack(packet, "dddd",
1399
0
            &msg->channel_request.width,
1400
0
            &msg->channel_request.height,
1401
0
            &msg->channel_request.pxwidth,
1402
0
            &msg->channel_request.pxheight);
1403
0
    if (rc != SSH_OK){
1404
0
        goto error;
1405
0
    }
1406
0
    goto end;
1407
0
  }
1408
1409
0
  if (strcmp(request, "subsystem") == 0) {
1410
0
    rc = ssh_buffer_unpack(packet, "s",
1411
0
            &msg->channel_request.subsystem);
1412
0
    msg->channel_request.type = SSH_CHANNEL_REQUEST_SUBSYSTEM;
1413
0
    if (rc != SSH_OK){
1414
0
        goto error;
1415
0
    }
1416
0
    goto end;
1417
0
  }
1418
1419
0
  if (strcmp(request, "shell") == 0) {
1420
0
    msg->channel_request.type = SSH_CHANNEL_REQUEST_SHELL;
1421
0
    goto end;
1422
0
  }
1423
1424
0
  if (strcmp(request, "exec") == 0) {
1425
0
    rc = ssh_buffer_unpack(packet, "s",
1426
0
            &msg->channel_request.command);
1427
0
    msg->channel_request.type = SSH_CHANNEL_REQUEST_EXEC;
1428
0
    if (rc != SSH_OK) {
1429
0
      goto error;
1430
0
    }
1431
0
    goto end;
1432
0
  }
1433
1434
0
  if (strcmp(request, "env") == 0) {
1435
0
    rc = ssh_buffer_unpack(packet, "ss",
1436
0
            &msg->channel_request.var_name,
1437
0
            &msg->channel_request.var_value);
1438
0
    msg->channel_request.type = SSH_CHANNEL_REQUEST_ENV;
1439
0
    if (rc != SSH_OK) {
1440
0
      goto error;
1441
0
    }
1442
0
    goto end;
1443
0
  }
1444
1445
0
  if (strcmp(request, "x11-req") == 0) {
1446
0
    rc = ssh_buffer_unpack(packet, "bssd",
1447
0
            &msg->channel_request.x11_single_connection,
1448
0
            &msg->channel_request.x11_auth_protocol,
1449
0
            &msg->channel_request.x11_auth_cookie,
1450
0
            &msg->channel_request.x11_screen_number);
1451
1452
0
    msg->channel_request.type = SSH_CHANNEL_REQUEST_X11;
1453
0
    if (rc != SSH_OK) {
1454
0
      goto error;
1455
0
    }
1456
1457
0
    goto end;
1458
0
  }
1459
1460
0
  msg->channel_request.type = SSH_CHANNEL_REQUEST_UNKNOWN;
1461
0
end:
1462
0
  ssh_message_queue(session,msg);
1463
1464
0
  return SSH_OK;
1465
0
error:
1466
0
  SSH_MESSAGE_FREE(msg);
1467
1468
0
  return SSH_ERROR;
1469
0
}
1470
1471
/** @internal
1472
 *
1473
 * @brief       Sends a successful channel request reply
1474
 *
1475
 * @param msg   A message to reply to
1476
 *
1477
 * @returns     SSH_OK on success, SSH_ERROR if an error occurred.
1478
 */
1479
0
int ssh_message_channel_request_reply_success(ssh_message msg) {
1480
0
  uint32_t channel;
1481
0
  int rc;
1482
1483
0
  if (msg == NULL) {
1484
0
    return SSH_ERROR;
1485
0
  }
1486
1487
0
  if (msg->channel_request.want_reply) {
1488
0
    channel = msg->channel_request.channel->remote_channel;
1489
1490
0
    SSH_LOG(SSH_LOG_PACKET,
1491
0
        "Sending a channel_request success to channel %" PRIu32, channel);
1492
1493
0
    rc = ssh_buffer_pack(msg->session->out_buffer,
1494
0
                         "bd",
1495
0
                         SSH2_MSG_CHANNEL_SUCCESS,
1496
0
                         channel);
1497
0
    if (rc != SSH_OK){
1498
0
      ssh_set_error_oom(msg->session);
1499
0
      return SSH_ERROR;
1500
0
    }
1501
1502
0
    return ssh_packet_send(msg->session);
1503
0
  }
1504
1505
0
  SSH_LOG(SSH_LOG_PACKET,
1506
0
      "The client doesn't want to know the request succeeded");
1507
1508
0
  return SSH_OK;
1509
0
}
1510
1511
#ifdef WITH_SERVER
1512
1.17k
SSH_PACKET_CALLBACK(ssh_packet_global_request){
1513
1.17k
    ssh_message msg = NULL;
1514
1.17k
    char *request=NULL;
1515
1.17k
    uint8_t want_reply;
1516
1.17k
    int rc = SSH_PACKET_USED;
1517
1.17k
    int r;
1518
1.17k
    (void)user;
1519
1.17k
    (void)type;
1520
1.17k
    (void)packet;
1521
1522
1.17k
    SSH_LOG(SSH_LOG_DEBUG,"Received SSH_MSG_GLOBAL_REQUEST packet");
1523
1.17k
    r = ssh_buffer_unpack(packet, "sb",
1524
1.17k
            &request,
1525
1.17k
            &want_reply);
1526
1.17k
    if (r != SSH_OK){
1527
283
        goto error;
1528
283
    }
1529
1530
894
    msg = ssh_message_new(session);
1531
894
    if (msg == NULL) {
1532
0
        ssh_set_error_oom(session);
1533
0
        goto error;
1534
0
    }
1535
894
    msg->type = SSH_REQUEST_GLOBAL;
1536
1537
894
    if (strcmp(request, "tcpip-forward") == 0) {
1538
1539
        /* According to RFC4254, the client SHOULD reject this message */
1540
0
        if (session->client) {
1541
0
            goto reply_with_failure;
1542
0
        }
1543
1544
0
        r = ssh_buffer_unpack(packet, "sd",
1545
0
                &msg->global_request.bind_address,
1546
0
                &msg->global_request.bind_port
1547
0
                );
1548
0
        if (r != SSH_OK){
1549
0
            goto reply_with_failure;
1550
0
        }
1551
0
        msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD;
1552
0
        msg->global_request.want_reply = want_reply;
1553
1554
0
        SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply,
1555
0
                msg->global_request.bind_address,
1556
0
                msg->global_request.bind_port);
1557
1558
0
        if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) {
1559
0
            SSH_LOG(SSH_LOG_DEBUG, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request,
1560
0
                    want_reply, msg->global_request.bind_address,
1561
0
                    msg->global_request.bind_port);
1562
0
            session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
1563
0
        } else {
1564
0
            SAFE_FREE(request);
1565
0
            ssh_message_queue(session, msg);
1566
0
            return rc;
1567
0
        }
1568
894
    } else if (strcmp(request, "cancel-tcpip-forward") == 0) {
1569
1570
        /* According to RFC4254, the client SHOULD reject this message */
1571
0
        if (session->client) {
1572
0
            goto reply_with_failure;
1573
0
        }
1574
1575
0
        r = ssh_buffer_unpack(packet, "sd",
1576
0
                &msg->global_request.bind_address,
1577
0
                &msg->global_request.bind_port);
1578
0
        if (r != SSH_OK){
1579
0
            goto reply_with_failure;
1580
0
        }
1581
0
        msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD;
1582
0
        msg->global_request.want_reply = want_reply;
1583
1584
0
        SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply,
1585
0
                msg->global_request.bind_address,
1586
0
                msg->global_request.bind_port);
1587
1588
0
        if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) {
1589
0
            session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
1590
0
        } else {
1591
0
            SAFE_FREE(request);
1592
0
            ssh_message_queue(session, msg);
1593
0
            return rc;
1594
0
        }
1595
894
    } else if(strcmp(request, "keepalive@openssh.com") == 0) {
1596
0
        msg->global_request.type = SSH_GLOBAL_REQUEST_KEEPALIVE;
1597
0
        msg->global_request.want_reply = want_reply;
1598
0
        SSH_LOG(SSH_LOG_DEBUG, "Received keepalive@openssh.com %d", want_reply);
1599
0
        if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) {
1600
0
            session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
1601
0
        } else {
1602
0
            ssh_message_global_request_reply_success(msg, 0);
1603
0
        }
1604
894
    } else if (strcmp(request, "no-more-sessions@openssh.com") == 0) {
1605
0
        msg->global_request.type = SSH_GLOBAL_REQUEST_NO_MORE_SESSIONS;
1606
0
        msg->global_request.want_reply = want_reply;
1607
1608
0
        SSH_LOG(SSH_LOG_PROTOCOL, "Received no-more-sessions@openssh.com %d", want_reply);
1609
1610
0
        ssh_message_global_request_reply_success(msg, 0);
1611
1612
0
        session->flags |= SSH_SESSION_FLAG_NO_MORE_SESSIONS;
1613
894
    } else {
1614
894
        SSH_LOG(SSH_LOG_DEBUG, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s, "
1615
894
                "want_reply = %d", request, want_reply);
1616
894
        goto reply_with_failure;
1617
894
    }
1618
1619
0
    SAFE_FREE(msg);
1620
0
    SAFE_FREE(request);
1621
0
    return rc;
1622
1623
894
reply_with_failure:
1624
    /* Only report the failure if requested */
1625
894
    if (want_reply) {
1626
856
        r = ssh_buffer_add_u8(session->out_buffer,
1627
856
                SSH2_MSG_REQUEST_FAILURE);
1628
856
        if (r < 0) {
1629
0
            ssh_set_error_oom(session);
1630
0
            goto error;
1631
0
        }
1632
1633
856
        r = ssh_packet_send(session);
1634
856
        if (r != SSH_OK) {
1635
0
            goto error;
1636
0
        }
1637
856
    } else {
1638
38
        SSH_LOG(SSH_LOG_PACKET,
1639
38
                "The requester doesn't want to know the request failed!");
1640
38
    }
1641
1642
    /* Consume the message to avoid sending UNIMPLEMENTED later */
1643
894
    rc = SSH_PACKET_USED;
1644
1.17k
error:
1645
1.17k
    SAFE_FREE(msg);
1646
1.17k
    SAFE_FREE(request);
1647
1.17k
    SSH_LOG(SSH_LOG_TRACE, "Invalid SSH_MSG_GLOBAL_REQUEST packet");
1648
1.17k
    return rc;
1649
894
}
1650
1651
#endif /* WITH_SERVER */
1652
1653
/** @} */