Coverage Report

Created: 2023-09-25 06:08

/src/dropbear/src/common-session.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Dropbear - a SSH2 server
3
 * 
4
 * Copyright (c) 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 "session.h"
27
#include "dbutil.h"
28
#include "packet.h"
29
#include "algo.h"
30
#include "buffer.h"
31
#include "dss.h"
32
#include "ssh.h"
33
#include "dbrandom.h"
34
#include "kex.h"
35
#include "channel.h"
36
#include "runopts.h"
37
#include "netio.h"
38
39
static void checktimeouts(void);
40
static long select_timeout(void);
41
static int ident_readln(int fd, char* buf, int count);
42
static void read_session_identification(void);
43
44
struct sshsession ses; /* GLOBAL */
45
46
/* called only at the start of a session, set up initial state */
47
1.63k
void common_session_init(int sock_in, int sock_out) {
48
1.63k
  time_t now;
49
50
#if DEBUG_TRACE
51
  debug_start_net();
52
#endif
53
54
1.63k
  TRACE(("enter session_init"))
55
56
1.63k
  ses.sock_in = sock_in;
57
1.63k
  ses.sock_out = sock_out;
58
1.63k
  ses.maxfd = MAX(sock_in, sock_out);
59
60
1.63k
  if (sock_in >= 0) {
61
1.63k
    setnonblocking(sock_in);
62
1.63k
  }
63
1.63k
  if (sock_out >= 0) {
64
1.63k
    setnonblocking(sock_out);
65
1.63k
  }
66
67
1.63k
  ses.socket_prio = DROPBEAR_PRIO_NORMAL;
68
  /* Sets it to lowdelay */
69
1.63k
  update_channel_prio();
70
71
#if !DROPBEAR_SVR_MULTIUSER
72
  /* A sanity check to prevent an accidental configuration option
73
     leaving multiuser systems exposed */
74
  errno = 0;
75
  getuid();
76
  if (errno != ENOSYS) {
77
    dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
78
  }
79
#endif
80
81
1.63k
  now = monotonic_now();
82
1.63k
  ses.connect_time = now;
83
1.63k
  ses.last_packet_time_keepalive_recv = now;
84
1.63k
  ses.last_packet_time_idle = now;
85
1.63k
  ses.last_packet_time_any_sent = 0;
86
1.63k
  ses.last_packet_time_keepalive_sent = 0;
87
  
88
1.63k
#if DROPBEAR_FUZZ
89
1.63k
  if (!fuzz.fuzzing)
90
0
#endif
91
0
  {
92
0
  if (pipe(ses.signal_pipe) < 0) {
93
0
    dropbear_exit("Signal pipe failed");
94
0
  }
95
0
  setnonblocking(ses.signal_pipe[0]);
96
0
  setnonblocking(ses.signal_pipe[1]);
97
0
  ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
98
0
  ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
99
0
  }
100
  
101
1.63k
  ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
102
1.63k
  ses.transseq = 0;
103
104
1.63k
  ses.readbuf = NULL;
105
1.63k
  ses.payload = NULL;
106
1.63k
  ses.recvseq = 0;
107
108
1.63k
  initqueue(&ses.writequeue);
109
110
1.63k
  ses.requirenext = SSH_MSG_KEXINIT;
111
1.63k
  ses.dataallowed = 1; /* we can send data until we actually 
112
              send the SSH_MSG_KEXINIT */
113
1.63k
  ses.ignorenext = 0;
114
1.63k
  ses.lastpacket = 0;
115
1.63k
  ses.reply_queue_head = NULL;
116
1.63k
  ses.reply_queue_tail = NULL;
117
118
  /* set all the algos to none */
119
1.63k
  ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
120
1.63k
  ses.newkeys = NULL;
121
1.63k
  ses.keys->recv.algo_crypt = &dropbear_nocipher;
122
1.63k
  ses.keys->trans.algo_crypt = &dropbear_nocipher;
123
1.63k
  ses.keys->recv.crypt_mode = &dropbear_mode_none;
124
1.63k
  ses.keys->trans.crypt_mode = &dropbear_mode_none;
125
  
126
1.63k
  ses.keys->recv.algo_mac = &dropbear_nohash;
127
1.63k
  ses.keys->trans.algo_mac = &dropbear_nohash;
128
129
1.63k
  ses.keys->algo_kex = NULL;
130
1.63k
  ses.keys->algo_hostkey = -1;
131
1.63k
  ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
132
1.63k
  ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
133
134
#ifndef DISABLE_ZLIB
135
  ses.keys->recv.zstream = NULL;
136
  ses.keys->trans.zstream = NULL;
137
#endif
138
139
  /* key exchange buffers */
140
1.63k
  ses.session_id = NULL;
141
1.63k
  ses.kexhashbuf = NULL;
142
1.63k
  ses.transkexinit = NULL;
143
1.63k
  ses.dh_K = NULL;
144
1.63k
  ses.remoteident = NULL;
145
146
1.63k
  ses.chantypes = NULL;
147
148
1.63k
  ses.allowprivport = 0;
149
150
#if DROPBEAR_PLUGIN
151
        ses.plugin_session = NULL;
152
#endif
153
154
1.63k
  TRACE(("leave session_init"))
155
1.63k
}
156
157
1.63k
void session_loop(void(*loophandler)(void)) {
158
159
1.63k
  fd_set readfd, writefd;
160
1.63k
  struct timeval timeout;
161
1.63k
  int val;
162
163
  /* main loop, select()s for all sockets in use */
164
503k
  for(;;) {
165
503k
    const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
166
167
503k
    timeout.tv_sec = select_timeout();
168
503k
    timeout.tv_usec = 0;
169
503k
    DROPBEAR_FD_ZERO(&writefd);
170
503k
    DROPBEAR_FD_ZERO(&readfd);
171
172
503k
    dropbear_assert(ses.payload == NULL);
173
174
    /* We get woken up when signal handlers write to this pipe.
175
       SIGCHLD in svr-chansession is the only one currently. */
176
503k
#if DROPBEAR_FUZZ
177
503k
    if (!fuzz.fuzzing) 
178
0
#endif
179
0
    {
180
0
    FD_SET(ses.signal_pipe[0], &readfd);
181
0
    }
182
183
    /* set up for channels which can be read/written */
184
503k
    setchannelfds(&readfd, &writefd, writequeue_has_space);
185
186
    /* Pending connections to test */
187
503k
    set_connect_fds(&writefd);
188
189
    /* We delay reading from the input socket during initial setup until
190
    after we have written out our initial KEXINIT packet (empty writequeue). 
191
    This means our initial packet can be in-flight while we're doing a blocking
192
    read for the remote ident.
193
    We also avoid reading from the socket if the writequeue is full, that avoids
194
    replies backing up */
195
503k
    if (ses.sock_in != -1 
196
503k
      && (ses.remoteident || isempty(&ses.writequeue)) 
197
503k
      && writequeue_has_space) {
198
447k
      FD_SET(ses.sock_in, &readfd);
199
447k
    }
200
201
    /* Ordering is important, this test must occur after any other function
202
    might have queued packets (such as connection handlers) */
203
503k
    if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
204
184k
      FD_SET(ses.sock_out, &writefd);
205
184k
    }
206
207
503k
    val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
208
209
503k
    if (ses.exitflag) {
210
0
      dropbear_exit("Terminated by signal");
211
0
    }
212
    
213
503k
    if (val < 0 && errno != EINTR) {
214
0
      dropbear_exit("Error in select");
215
0
    }
216
217
503k
    if (val <= 0) {
218
      /* If we were interrupted or the select timed out, we still
219
       * want to iterate over channels etc for reading, to handle
220
       * server processes exiting etc. 
221
       * We don't want to read/write FDs. */
222
18.0k
      DROPBEAR_FD_ZERO(&writefd);
223
18.0k
      DROPBEAR_FD_ZERO(&readfd);
224
18.0k
    }
225
    
226
    /* We'll just empty out the pipe if required. We don't do
227
    any thing with the data, since the pipe's purpose is purely to
228
    wake up the select() above. */
229
503k
    ses.channel_signal_pending = 0;
230
503k
    if (FD_ISSET(ses.signal_pipe[0], &readfd)) {
231
0
      char x;
232
0
      TRACE(("signal pipe set"))
233
0
      while (read(ses.signal_pipe[0], &x, 1) > 0) {}
234
0
      ses.channel_signal_pending = 1;
235
0
    }
236
237
    /* check for auth timeout, rekeying required etc */
238
503k
    checktimeouts();
239
240
    /* process session socket's incoming data */
241
503k
    if (ses.sock_in != -1) {
242
503k
      if (FD_ISSET(ses.sock_in, &readfd)) {
243
323k
        if (!ses.remoteident) {
244
          /* blocking read of the version string */
245
1.63k
          read_session_identification();
246
321k
        } else {
247
321k
          read_packet();
248
321k
        }
249
323k
      }
250
      
251
      /* Process the decrypted packet. After this, the read buffer
252
       * will be ready for a new packet */
253
503k
      if (ses.payload != NULL) {
254
60.7k
        process_packet();
255
60.7k
      }
256
503k
    }
257
258
    /* if required, flush out any queued reply packets that
259
    were being held up during a KEX */
260
503k
    maybe_flush_reply_queue();
261
262
503k
    handle_connect_fds(&writefd);
263
264
    /* loop handler prior to channelio, in case the server loophandler closes
265
    channels on process exit */
266
503k
    loophandler();
267
268
    /* process pipes etc for the channels, ses.dataallowed == 0
269
     * during rekeying ) */
270
503k
    channelio(&readfd, &writefd);
271
272
    /* process session socket's outgoing data */
273
503k
    if (ses.sock_out != -1) {
274
501k
      if (!isempty(&ses.writequeue)) {
275
236k
        write_packet();
276
236k
      }
277
501k
    }
278
279
503k
  } /* for(;;) */
280
  
281
  /* Not reached */
282
1.63k
}
283
284
11.4k
static void cleanup_buf(buffer **buf) {
285
11.4k
  if (!*buf) {
286
6.19k
    return;
287
6.19k
  }
288
5.26k
  buf_burn_free(*buf);
289
5.26k
  *buf = NULL;
290
5.26k
}
291
292
/* clean up a session on exit */
293
1.63k
void session_cleanup() {
294
  
295
1.63k
  TRACE(("enter session_cleanup"))
296
  
297
  /* we can't cleanup if we don't know the session state */
298
1.63k
  if (!ses.init_done) {
299
0
    TRACE(("leave session_cleanup: !ses.init_done"))
300
0
    return;
301
0
  }
302
303
  /* BEWARE of changing order of functions here. */
304
305
  /* Must be before extra_session_cleanup() */
306
1.63k
  chancleanup();
307
308
1.63k
  if (ses.extra_session_cleanup) {
309
1.63k
    ses.extra_session_cleanup();
310
1.63k
  }
311
312
  /* After these are freed most functions will fail */
313
1.63k
#if DROPBEAR_CLEANUP
314
  /* listeners call cleanup functions, this should occur before
315
  other session state is freed. */
316
1.63k
  remove_all_listeners();
317
318
1.63k
  remove_connect_pending();
319
320
6.50k
  while (!isempty(&ses.writequeue)) {
321
4.86k
    buf_free(dequeue(&ses.writequeue));
322
4.86k
  }
323
324
1.63k
  m_free(ses.newkeys);
325
#ifndef DISABLE_ZLIB
326
  if (ses.keys->recv.zstream != NULL) {
327
    if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
328
      dropbear_exit("Crypto error");
329
    }
330
    m_free(ses.keys->recv.zstream);
331
  }
332
#endif
333
334
1.63k
  m_free(ses.remoteident);
335
1.63k
  m_free(ses.authstate.pw_dir);
336
1.63k
  m_free(ses.authstate.pw_name);
337
1.63k
  m_free(ses.authstate.pw_shell);
338
1.63k
  m_free(ses.authstate.pw_passwd);
339
1.63k
  m_free(ses.authstate.username);
340
1.63k
#endif
341
342
1.63k
  cleanup_buf(&ses.session_id);
343
1.63k
  cleanup_buf(&ses.hash);
344
1.63k
  cleanup_buf(&ses.payload);
345
1.63k
  cleanup_buf(&ses.readbuf);
346
1.63k
  cleanup_buf(&ses.writepayload);
347
1.63k
  cleanup_buf(&ses.kexhashbuf);
348
1.63k
  cleanup_buf(&ses.transkexinit);
349
1.63k
  if (ses.dh_K) {
350
0
    mp_clear(ses.dh_K);
351
0
  }
352
1.63k
  m_free(ses.dh_K);
353
354
1.63k
  m_burn(ses.keys, sizeof(struct key_context));
355
1.63k
  m_free(ses.keys);
356
357
1.63k
  TRACE(("leave session_cleanup"))
358
1.63k
}
359
360
1.63k
void send_session_identification() {
361
1.63k
  buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
362
1.63k
  buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
363
1.63k
  writebuf_enqueue(writebuf);
364
1.63k
}
365
366
1.63k
static void read_session_identification() {
367
  /* max length of 255 chars */
368
1.63k
  char linebuf[256];
369
1.63k
  int len = 0;
370
1.63k
  char done = 0;
371
1.63k
  int i;
372
373
  /* Servers may send other lines of data before sending the
374
   * version string, client must be able to process such lines.
375
   * If they send more than 50 lines, something is wrong */
376
1.64k
  for (i = IS_DROPBEAR_CLIENT ? 50 : 1; i > 0; i--) {
377
1.63k
    len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
378
379
1.63k
    if (len < 0 && errno != EINTR) {
380
      /* It failed */
381
1
      break;
382
1
    }
383
384
1.63k
    if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) {
385
      /* start of line matches */
386
1.63k
      done = 1;
387
1.63k
      break;
388
1.63k
    }
389
1.63k
  }
390
391
1.63k
  if (!done) {
392
5
    TRACE(("error reading remote ident: %s\n", strerror(errno)))
393
5
    ses.remoteclosed();
394
1.63k
  } else {
395
    /* linebuf is already null terminated */
396
1.63k
    ses.remoteident = m_malloc(len);
397
1.63k
    memcpy(ses.remoteident, linebuf, len);
398
1.63k
  }
399
400
  /* Shall assume that 2.x will be backwards compatible. */
401
1.63k
  if (strncmp(ses.remoteident, "SSH-2.", 6) != 0
402
1.63k
      && strncmp(ses.remoteident, "SSH-1.99-", 9) != 0) {
403
0
    dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
404
0
  }
405
406
1.63k
  DEBUG1(("remoteident: %s", ses.remoteident))
407
408
1.63k
}
409
410
/* returns the length including null-terminating zero on success,
411
 * or -1 on failure */
412
1.63k
static int ident_readln(int fd, char* buf, int count) {
413
  
414
1.63k
  char in;
415
1.63k
  int pos = 0;
416
1.63k
  int num = 0;
417
1.63k
  fd_set fds;
418
1.63k
  struct timeval timeout;
419
420
1.63k
  TRACE(("enter ident_readln"))
421
422
1.63k
  if (count < 1) {
423
0
    return -1;
424
0
  }
425
426
1.63k
  DROPBEAR_FD_ZERO(&fds);
427
428
  /* select since it's a non-blocking fd */
429
  
430
  /* leave space to null-terminate */
431
46.0k
  while (pos < count-1) {
432
433
46.0k
    FD_SET(fd, &fds);
434
435
46.0k
    timeout.tv_sec = 1;
436
46.0k
    timeout.tv_usec = 0;
437
46.0k
    if (select(fd+1, &fds, NULL, NULL, &timeout) < 0) {
438
39
      if (errno == EINTR) {
439
39
        continue;
440
39
      }
441
0
      TRACE(("leave ident_readln: select error"))
442
0
      return -1;
443
39
    }
444
445
46.0k
    checktimeouts();
446
    
447
    /* Have to go one byte at a time, since we don't want to read past
448
     * the end, and have to somehow shove bytes back into the normal
449
     * packet reader */
450
46.0k
    if (FD_ISSET(fd, &fds)) {
451
46.0k
      num = read(fd, &in, 1);
452
      /* a "\n" is a newline, "\r" we want to read in and keep going
453
       * so that it won't be read as part of the next line */
454
46.0k
      if (num < 0) {
455
        /* error */
456
70
        if (errno == EINTR) {
457
70
          continue; /* not a real error */
458
70
        }
459
0
        TRACE(("leave ident_readln: read error"))
460
0
        return -1;
461
70
      }
462
45.9k
      if (num == 0) {
463
        /* EOF */
464
5
        TRACE(("leave ident_readln: EOF"))
465
5
        return -1;
466
5
      }
467
468
45.9k
#if DROPBEAR_FUZZ
469
45.9k
      fuzz_dump(&in, 1);
470
45.9k
#endif
471
472
45.9k
      if (in == '\n') {
473
        /* end of ident string */
474
1.63k
        break;
475
1.63k
      }
476
      /* we don't want to include '\r's */
477
44.2k
      if (in != '\r') {
478
32.5k
        buf[pos] = in;
479
32.5k
        pos++;
480
32.5k
      }
481
44.2k
    }
482
46.0k
  }
483
484
1.63k
  buf[pos] = '\0';
485
1.63k
  TRACE(("leave ident_readln: return %d", pos+1))
486
1.63k
  return pos+1;
487
1.63k
}
488
489
313
void ignore_recv_response() {
490
  /* Do nothing */
491
313
  TRACE(("Ignored msg_request_response"))
492
313
}
493
494
0
static void send_msg_keepalive() {
495
0
  time_t old_time_idle = ses.last_packet_time_idle;
496
0
  struct Channel *chan = get_any_ready_channel();
497
498
0
  CHECKCLEARTOWRITE();
499
500
0
  if (chan) {
501
    /* Channel requests are preferable, more implementations
502
    handle them than SSH_MSG_GLOBAL_REQUEST */
503
0
    TRACE(("keepalive channel request %d", chan->index))
504
0
    start_send_channel_request(chan, DROPBEAR_KEEPALIVE_STRING);
505
0
  } else {
506
0
    TRACE(("keepalive global request"))
507
    /* Some peers will reply with SSH_MSG_REQUEST_FAILURE, 
508
    some will reply with SSH_MSG_UNIMPLEMENTED, some will exit. */
509
0
    buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST); 
510
0
    buf_putstring(ses.writepayload, DROPBEAR_KEEPALIVE_STRING,
511
0
      strlen(DROPBEAR_KEEPALIVE_STRING));
512
0
  }
513
0
  buf_putbyte(ses.writepayload, 1); /* want_reply */
514
0
  encrypt_packet();
515
516
0
  ses.last_packet_time_keepalive_sent = monotonic_now();
517
518
  /* keepalives shouldn't update idle timeout, reset it back */
519
0
  ses.last_packet_time_idle = old_time_idle;
520
0
}
521
522
/* Returns the difference in seconds, clamped to LONG_MAX */
523
1.71M
static long elapsed(time_t now, time_t prev) {
524
1.71M
  time_t del = now - prev;
525
1.71M
  if (del > LONG_MAX) {
526
0
    return LONG_MAX;
527
0
  }
528
1.71M
  return (long)del;
529
1.71M
}
530
531
/* Check all timeouts which are required. Currently these are the time for
532
 * user authentication, and the automatic rekeying. */
533
549k
static void checktimeouts() {
534
535
549k
  time_t now;
536
549k
  now = monotonic_now();
537
538
549k
  if (IS_DROPBEAR_SERVER && ses.connect_time != 0
539
549k
    && elapsed(now, ses.connect_time) >= AUTH_TIMEOUT) {
540
0
      dropbear_close("Timeout before auth");
541
0
  }
542
543
  /* we can't rekey if we haven't done remote ident exchange yet */
544
549k
  if (ses.remoteident == NULL) {
545
50.9k
    return;
546
50.9k
  }
547
548
498k
  if (!ses.kexstate.sentkexinit
549
498k
      && (elapsed(now, ses.kexstate.lastkextime) >= KEX_REKEY_TIMEOUT
550
391k
      || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) {
551
0
    TRACE(("rekeying after timeout or max data reached"))
552
0
    send_msg_kexinit();
553
0
  }
554
555
498k
  if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
556
    /* Avoid sending keepalives prior to auth - those are
557
    not valid pre-auth packet types */
558
559
    /* Send keepalives if we've been idle */
560
0
    if (elapsed(now, ses.last_packet_time_any_sent) >= opts.keepalive_secs) {
561
0
      send_msg_keepalive();
562
0
    }
563
564
    /* Also send an explicit keepalive message to trigger a response
565
    if the remote end hasn't sent us anything */
566
0
    if (elapsed(now, ses.last_packet_time_keepalive_recv) >= opts.keepalive_secs
567
0
      && elapsed(now, ses.last_packet_time_keepalive_sent) >= opts.keepalive_secs) {
568
0
      send_msg_keepalive();
569
0
    }
570
571
0
    if (elapsed(now, ses.last_packet_time_keepalive_recv)
572
0
      >= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
573
0
      dropbear_exit("Keepalive timeout");
574
0
    }
575
0
  }
576
577
498k
  if (opts.idle_timeout_secs > 0
578
498k
      && elapsed(now, ses.last_packet_time_idle) >= opts.idle_timeout_secs) {
579
0
    dropbear_close("Idle timeout");
580
0
  }
581
498k
}
582
583
1.39M
static void update_timeout(long limit, time_t now, time_t last_event, long * timeout) {
584
1.39M
  TRACE2(("update_timeout limit %ld, now %llu, last %llu, timeout %ld",
585
1.39M
    limit,
586
1.39M
    (unsigned long long)now,
587
1.39M
    (unsigned long long)last_event, *timeout))
588
1.39M
  if (last_event > 0 && limit > 0) {
589
391k
    *timeout = MIN(*timeout, elapsed(now, last_event) + limit);
590
391k
    TRACE2(("new timeout %ld", *timeout))
591
391k
  }
592
1.39M
}
593
594
503k
static long select_timeout() {
595
  /* determine the minimum timeout that might be required, so
596
  as to avoid waking when unneccessary */
597
503k
  long timeout = KEX_REKEY_TIMEOUT;
598
503k
  time_t now = monotonic_now();
599
600
503k
  if (!ses.kexstate.sentkexinit) {
601
391k
    update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
602
391k
  }
603
604
503k
  if (ses.authstate.authdone != 1 && IS_DROPBEAR_SERVER) {
605
    /* AUTH_TIMEOUT is only relevant before authdone */
606
0
    update_timeout(AUTH_TIMEOUT, now, ses.connect_time, &timeout);
607
0
  }
608
609
503k
  if (ses.authstate.authdone) {
610
503k
    update_timeout(opts.keepalive_secs, now,
611
503k
      MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
612
503k
      &timeout);
613
503k
  }
614
615
503k
  update_timeout(opts.idle_timeout_secs, now, ses.last_packet_time_idle,
616
503k
    &timeout);
617
618
  /* clamp negative timeouts to zero - event has already triggered */
619
503k
  return MAX(timeout, 0);
620
503k
}
621
622
0
const char* get_user_shell() {
623
  /* an empty shell should be interpreted as "/bin/sh" */
624
0
  if (ses.authstate.pw_shell[0] == '\0') {
625
0
    return "/bin/sh";
626
0
  } else {
627
0
    return ses.authstate.pw_shell;
628
0
  }
629
0
}
630
1.63k
void fill_passwd(const char* username) {
631
1.63k
  struct passwd *pw = NULL;
632
1.63k
  if (ses.authstate.pw_name)
633
0
    m_free(ses.authstate.pw_name);
634
1.63k
  if (ses.authstate.pw_dir)
635
0
    m_free(ses.authstate.pw_dir);
636
1.63k
  if (ses.authstate.pw_shell)
637
0
    m_free(ses.authstate.pw_shell);
638
1.63k
  if (ses.authstate.pw_passwd)
639
0
    m_free(ses.authstate.pw_passwd);
640
641
1.63k
  pw = getpwnam(username);
642
1.63k
  if (!pw) {
643
0
    return;
644
0
  }
645
1.63k
  ses.authstate.pw_uid = pw->pw_uid;
646
1.63k
  ses.authstate.pw_gid = pw->pw_gid;
647
1.63k
  ses.authstate.pw_name = m_strdup(pw->pw_name);
648
1.63k
  ses.authstate.pw_dir = m_strdup(pw->pw_dir);
649
1.63k
  ses.authstate.pw_shell = m_strdup(pw->pw_shell);
650
1.63k
  {
651
1.63k
    char *passwd_crypt = pw->pw_passwd;
652
1.63k
#ifdef HAVE_SHADOW_H
653
    /* get the shadow password if possible */
654
1.63k
    struct spwd *spasswd = getspnam(ses.authstate.pw_name);
655
1.63k
    if (spasswd && spasswd->sp_pwdp) {
656
1.63k
      passwd_crypt = spasswd->sp_pwdp;
657
1.63k
    }
658
1.63k
#endif
659
1.63k
    if (!passwd_crypt) {
660
      /* android supposedly returns NULL */
661
0
      passwd_crypt = "!!";
662
0
    }
663
1.63k
    ses.authstate.pw_passwd = m_strdup(passwd_crypt);
664
1.63k
  }
665
1.63k
}
666
667
/* Called when channels are modified */
668
20.9k
void update_channel_prio() {
669
20.9k
  enum dropbear_prio new_prio;
670
20.9k
  int any = 0;
671
20.9k
  unsigned int i;
672
673
20.9k
  TRACE(("update_channel_prio"))
674
675
20.9k
  if (ses.sock_out < 0) {
676
3.21k
    TRACE(("leave update_channel_prio: no socket"))
677
3.21k
    return;
678
3.21k
  }
679
680
17.7k
  new_prio = DROPBEAR_PRIO_NORMAL;
681
109k
  for (i = 0; i < ses.chansize; i++) {
682
105k
    struct Channel *channel = ses.channels[i];
683
105k
    if (!channel) {
684
77.8k
      continue;
685
77.8k
    }
686
27.1k
    any = 1;
687
27.1k
    if (channel->prio == DROPBEAR_PRIO_LOWDELAY) {
688
13.3k
      new_prio = DROPBEAR_PRIO_LOWDELAY;
689
13.3k
      break;
690
13.3k
    }
691
27.1k
  }
692
693
17.7k
  if (any == 0) {
694
    /* lowdelay during setup */
695
2.48k
    TRACE(("update_channel_prio: not any"))
696
2.48k
    new_prio = DROPBEAR_PRIO_LOWDELAY;
697
2.48k
  }
698
699
17.7k
  if (new_prio != ses.socket_prio) {
700
4.01k
    TRACE(("Dropbear priority transitioning %d -> %d", ses.socket_prio, new_prio))
701
4.01k
    set_sock_priority(ses.sock_out, new_prio);
702
4.01k
    ses.socket_prio = new_prio;
703
4.01k
  }
704
17.7k
}
705