Coverage Report

Created: 2025-10-10 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dropbear/src/process-packet.c
Line
Count
Source
1
/*
2
 * Dropbear - a SSH2 server
3
 * 
4
 * Copyright (c) 2002-2004 Matt Johnston
5
 * All rights reserved.
6
 * 
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 * 
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 * 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE. */
24
25
#include "includes.h"
26
#include "packet.h"
27
#include "session.h"
28
#include "dbutil.h"
29
#include "ssh.h"
30
#include "algo.h"
31
#include "buffer.h"
32
#include "kex.h"
33
#include "dbrandom.h"
34
#include "service.h"
35
#include "auth.h"
36
#include "channel.h"
37
38
37.8k
#define MAX_UNAUTH_PACKET_TYPE SSH_MSG_USERAUTH_PK_OK
39
40
static void recv_unimplemented(void);
41
42
/* process a decrypted packet, call the appropriate handler */
43
56.9k
void process_packet() {
44
45
56.9k
  unsigned char type;
46
56.9k
  unsigned int i;
47
56.9k
  unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.recvfirstnewkeys;
48
56.9k
  time_t now;
49
50
56.9k
  TRACE2(("enter process_packet"))
51
52
56.9k
  type = buf_getbyte(ses.payload);
53
56.9k
  TRACE(("process_packet: packet type = %d,  len %d", type, ses.payload->len))
54
55
56.9k
  now = monotonic_now();
56
56.9k
  ses.last_packet_time_keepalive_recv = now;
57
58
59
56.9k
  if (type == SSH_MSG_DISCONNECT) {
60
    /* Allowed at any time */
61
3
    dropbear_close("Disconnect received");
62
3
  }
63
64
  /* These packets may be received at any time,
65
     except during first kex with strict kex */
66
56.9k
  if (!first_strict_kex) {
67
56.8k
    switch(type) {
68
255
      case SSH_MSG_IGNORE:
69
255
        goto out;
70
122
      case SSH_MSG_DEBUG:
71
122
        goto out;
72
228
      case SSH_MSG_UNIMPLEMENTED:
73
228
        TRACE(("SSH_MSG_UNIMPLEMENTED"))
74
228
        goto out;
75
56.8k
    }
76
56.8k
  }
77
78
  /* Ignore these packet types so that keepalives don't interfere with
79
  idle detection. This is slightly incorrect since a tcp forwarded
80
  global request with failure won't trigger the idle timeout,
81
  but that's probably acceptable */
82
56.3k
  if (!(type == SSH_MSG_GLOBAL_REQUEST 
83
56.3k
    || type == SSH_MSG_REQUEST_FAILURE
84
56.3k
    || type == SSH_MSG_CHANNEL_FAILURE)) {
85
56.3k
    ses.last_packet_time_idle = now;
86
56.3k
  }
87
88
  /* This applies for KEX, where the spec says the next packet MUST be
89
   * NEWKEYS */
90
56.3k
  if (ses.requirenext != 0) {
91
41.0k
    if (ses.requirenext == type)
92
22.7k
    {
93
      /* Got what we expected */
94
22.7k
      TRACE(("got expected packet %d during kexinit", type))
95
22.7k
    }
96
18.2k
    else
97
18.2k
    {
98
      /* RFC4253 7.1 - various messages are allowed at this point.
99
      The only ones we know about have already been handled though,
100
      so just return "unimplemented" */
101
18.2k
      if (type >= 1 && type <= 49
102
18.2k
        && type != SSH_MSG_SERVICE_REQUEST
103
18.2k
        && type != SSH_MSG_SERVICE_ACCEPT
104
18.2k
        && type != SSH_MSG_KEXINIT
105
18.2k
        && !first_strict_kex)
106
18.2k
      {
107
18.2k
        TRACE(("unknown allowed packet during kexinit"))
108
18.2k
        recv_unimplemented();
109
18.2k
        goto out;
110
18.2k
      }
111
62
      else
112
62
      {
113
62
        TRACE(("disallowed packet during kexinit"))
114
62
        dropbear_exit("Unexpected packet type %d, expected %d", type,
115
62
            ses.requirenext);
116
62
      }
117
18.2k
    }
118
41.0k
  }
119
120
  /* Check if we should ignore this packet. Used currently only for
121
   * KEX code, with first_kex_packet_follows */
122
38.0k
  if (ses.ignorenext) {
123
148
    TRACE(("Ignoring packet, type = %d", type))
124
148
    ses.ignorenext = 0;
125
148
    goto out;
126
148
  }
127
128
  /* Only clear the flag after we have checked ignorenext */
129
37.8k
  if (ses.requirenext != 0 && ses.requirenext == type)
130
22.6k
  {
131
22.6k
    ses.requirenext = 0;
132
22.6k
  }
133
134
135
  /* Kindly the protocol authors gave all the preauth packets type values
136
   * less-than-or-equal-to 60 ( == MAX_UNAUTH_PACKET_TYPE ).
137
   * NOTE: if the protocol changes and new types are added, revisit this 
138
   * assumption */
139
37.8k
  if ( !ses.authstate.authdone && type > MAX_UNAUTH_PACKET_TYPE ) {
140
4
    dropbear_exit("Received message %d before userauth", type);
141
4
  }
142
143
250k
  for (i = 0; ; i++) {
144
250k
    if (ses.packettypes[i].type == 0) {
145
      /* end of list */
146
2.63k
      break;
147
2.63k
    }
148
149
247k
    if (ses.packettypes[i].type == type) {
150
35.2k
      ses.packettypes[i].handler();
151
35.2k
      goto out;
152
35.2k
    }
153
247k
  }
154
155
  
156
  /* TODO do something more here? */
157
2.63k
  TRACE(("preauth unknown packet"))
158
2.63k
  recv_unimplemented();
159
160
55.3k
out:
161
55.3k
  ses.lastpacket = type;
162
55.3k
  buf_free(ses.payload);
163
55.3k
  ses.payload = NULL;
164
165
55.3k
  TRACE2(("leave process_packet"))
166
55.3k
}
167
168
169
170
/* This must be called directly after receiving the unimplemented packet.
171
 * Isn't the most clean implementation, it relies on packet processing
172
 * occurring directly after decryption (direct use of ses.recvseq).
173
 * This is reasonably valid, since there is only a single decryption buffer */
174
20.8k
static void recv_unimplemented() {
175
176
20.8k
  CHECKCLEARTOWRITE();
177
178
20.8k
  buf_putbyte(ses.writepayload, SSH_MSG_UNIMPLEMENTED);
179
  /* the decryption routine increments the sequence number, we must
180
   * decrement */
181
20.8k
  buf_putint(ses.writepayload, ses.recvseq - 1);
182
183
20.8k
  encrypt_packet();
184
20.8k
}