Coverage Report

Created: 2023-03-06 09:27

/src/dropbear/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
2.13k
void common_session_init(int sock_in, int sock_out) {
48
2.13k
  time_t now;
49
50
#if DEBUG_TRACE
51
  debug_start_net();
52
#endif
53
54
2.13k
  TRACE(("enter session_init"))
55
56
2.13k
  ses.sock_in = sock_in;
57
2.13k
  ses.sock_out = sock_out;
58
2.13k
  ses.maxfd = MAX(sock_in, sock_out);
59
60
2.13k
  if (sock_in >= 0) {
61
2.13k
    setnonblocking(sock_in);
62
2.13k
  }
63
2.13k
  if (sock_out >= 0) {
64
2.13k
    setnonblocking(sock_out);
65
2.13k
  }
66
67
2.13k
  ses.socket_prio = DROPBEAR_PRIO_NORMAL;
68
  /* Sets it to lowdelay */
69
2.13k
  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
2.13k
  now = monotonic_now();
82
2.13k
  ses.connect_time = now;
83
2.13k
  ses.last_packet_time_keepalive_recv = now;
84
2.13k
  ses.last_packet_time_idle = now;
85
2.13k
  ses.last_packet_time_any_sent = 0;
86
2.13k
  ses.last_packet_time_keepalive_sent = 0;
87
  
88
2.13k
#if DROPBEAR_FUZZ
89
2.13k
  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
2.13k
  ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
102
2.13k
  ses.transseq = 0;
103
104
2.13k
  ses.readbuf = NULL;
105
2.13k
  ses.payload = NULL;
106
2.13k
  ses.recvseq = 0;
107
108
2.13k
  initqueue(&ses.writequeue);
109
110
2.13k
  ses.requirenext = SSH_MSG_KEXINIT;
111
2.13k
  ses.dataallowed = 1; /* we can send data until we actually 
112
              send the SSH_MSG_KEXINIT */
113
2.13k
  ses.ignorenext = 0;
114
2.13k
  ses.lastpacket = 0;
115
2.13k
  ses.reply_queue_head = NULL;
116
2.13k
  ses.reply_queue_tail = NULL;
117
118
  /* set all the algos to none */
119
2.13k
  ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
120
2.13k
  ses.newkeys = NULL;
121
2.13k
  ses.keys->recv.algo_crypt = &dropbear_nocipher;
122
2.13k
  ses.keys->trans.algo_crypt = &dropbear_nocipher;
123
2.13k
  ses.keys->recv.crypt_mode = &dropbear_mode_none;
124
2.13k
  ses.keys->trans.crypt_mode = &dropbear_mode_none;
125
  
126
2.13k
  ses.keys->recv.algo_mac = &dropbear_nohash;
127
2.13k
  ses.keys->trans.algo_mac = &dropbear_nohash;
128
129
2.13k
  ses.keys->algo_kex = NULL;
130
2.13k
  ses.keys->algo_hostkey = -1;
131
2.13k
  ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
132
2.13k
  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
2.13k
  ses.session_id = NULL;
141
2.13k
  ses.kexhashbuf = NULL;
142
2.13k
  ses.transkexinit = NULL;
143
2.13k
  ses.dh_K = NULL;
144
2.13k
  ses.remoteident = NULL;
145
146
2.13k
  ses.chantypes = NULL;
147
148
2.13k
  ses.allowprivport = 0;
149
150
#if DROPBEAR_PLUGIN
151
        ses.plugin_session = NULL;
152
#endif
153
154
2.13k
  TRACE(("leave session_init"))
155
2.13k
}
156
157
2.13k
void session_loop(void(*loophandler)(void)) {
158
159
2.13k
  fd_set readfd, writefd;
160
2.13k
  struct timeval timeout;
161
2.13k
  int val;
162
163
  /* main loop, select()s for all sockets in use */
164
75.7k
  for(;;) {
165
75.7k
    const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
166
167
75.7k
    timeout.tv_sec = select_timeout();
168
75.7k
    timeout.tv_usec = 0;
169
75.7k
    DROPBEAR_FD_ZERO(&writefd);
170
75.7k
    DROPBEAR_FD_ZERO(&readfd);
171
172
75.7k
    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
75.7k
#if DROPBEAR_FUZZ
177
75.7k
    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
75.7k
    setchannelfds(&readfd, &writefd, writequeue_has_space);
185
186
    /* Pending connections to test */
187
75.7k
    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
75.7k
    if (ses.sock_in != -1 
196
75.7k
      && (ses.remoteident || isempty(&ses.writequeue)) 
197
75.7k
      && writequeue_has_space) {
198
71.4k
      FD_SET(ses.sock_in, &readfd);
199
71.4k
    }
200
201
    /* Ordering is important, this test must occur after any other function
202
    might have queued packets (such as connection handlers) */
203
75.7k
    if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
204
4.27k
      FD_SET(ses.sock_out, &writefd);
205
4.27k
    }
206
207
75.7k
    val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
208
209
75.7k
    if (ses.exitflag) {
210
0
      dropbear_exit("Terminated by signal");
211
0
    }
212
    
213
75.7k
    if (val < 0 && errno != EINTR) {
214
0
      dropbear_exit("Error in select");
215
0
    }
216
217
75.7k
    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
3.60k
      DROPBEAR_FD_ZERO(&writefd);
223
3.60k
      DROPBEAR_FD_ZERO(&readfd);
224
3.60k
    }
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
75.7k
    ses.channel_signal_pending = 0;
230
75.7k
    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
75.7k
    checktimeouts();
239
240
    /* process session socket's incoming data */
241
75.7k
    if (ses.sock_in != -1) {
242
75.7k
      if (FD_ISSET(ses.sock_in, &readfd)) {
243
68.1k
        if (!ses.remoteident) {
244
          /* blocking read of the version string */
245
2.13k
          read_session_identification();
246
66.0k
        } else {
247
66.0k
          read_packet();
248
66.0k
        }
249
68.1k
      }
250
      
251
      /* Process the decrypted packet. After this, the read buffer
252
       * will be ready for a new packet */
253
75.7k
      if (ses.payload != NULL) {
254
18.8k
        process_packet();
255
18.8k
      }
256
75.7k
    }
257
258
    /* if required, flush out any queued reply packets that
259
    were being held up during a KEX */
260
75.7k
    maybe_flush_reply_queue();
261
262
75.7k
    handle_connect_fds(&writefd);
263
264
    /* loop handler prior to channelio, in case the server loophandler closes
265
    channels on process exit */
266
75.7k
    loophandler();
267
268
    /* process pipes etc for the channels, ses.dataallowed == 0
269
     * during rekeying ) */
270
75.7k
    channelio(&readfd, &writefd);
271
272
    /* process session socket's outgoing data */
273
75.7k
    if (ses.sock_out != -1) {
274
73.5k
      if (!isempty(&ses.writequeue)) {
275
20.1k
        write_packet();
276
20.1k
      }
277
73.5k
    }
278
279
75.7k
  } /* for(;;) */
280
  
281
  /* Not reached */
282
2.13k
}
283
284
14.9k
static void cleanup_buf(buffer **buf) {
285
14.9k
  if (!*buf) {
286
8.97k
    return;
287
8.97k
  }
288
5.98k
  buf_burn_free(*buf);
289
5.98k
  *buf = NULL;
290
5.98k
}
291
292
/* clean up a session on exit */
293
2.13k
void session_cleanup() {
294
  
295
2.13k
  TRACE(("enter session_cleanup"))
296
  
297
  /* we can't cleanup if we don't know the session state */
298
2.13k
  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
2.13k
  chancleanup();
307
308
2.13k
  if (ses.extra_session_cleanup) {
309
2.13k
    ses.extra_session_cleanup();
310
2.13k
  }
311
312
  /* After these are freed most functions will fail */
313
2.13k
#if DROPBEAR_CLEANUP
314
  /* listeners call cleanup functions, this should occur before
315
  other session state is freed. */
316
2.13k
  remove_all_listeners();
317
318
2.13k
  remove_connect_pending();
319
320
2.13k
  while (!isempty(&ses.writequeue)) {
321
0
    buf_free(dequeue(&ses.writequeue));
322
0
  }
323
324
2.13k
  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
2.13k
  m_free(ses.remoteident);
335
2.13k
  m_free(ses.authstate.pw_dir);
336
2.13k
  m_free(ses.authstate.pw_name);
337
2.13k
  m_free(ses.authstate.pw_shell);
338
2.13k
  m_free(ses.authstate.pw_passwd);
339
2.13k
  m_free(ses.authstate.username);
340
2.13k
#endif
341
342
2.13k
  cleanup_buf(&ses.session_id);
343
2.13k
  cleanup_buf(&ses.hash);
344
2.13k
  cleanup_buf(&ses.payload);
345
2.13k
  cleanup_buf(&ses.readbuf);
346
2.13k
  cleanup_buf(&ses.writepayload);
347
2.13k
  cleanup_buf(&ses.kexhashbuf);
348
2.13k
  cleanup_buf(&ses.transkexinit);
349
2.13k
  if (ses.dh_K) {
350
0
    mp_clear(ses.dh_K);
351
0
  }
352
2.13k
  m_free(ses.dh_K);
353
354
2.13k
  m_burn(ses.keys, sizeof(struct key_context));
355
2.13k
  m_free(ses.keys);
356
357
2.13k
  TRACE(("leave session_cleanup"))
358
2.13k
}
359
360
2.13k
void send_session_identification() {
361
2.13k
  buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
362
2.13k
  buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
363
2.13k
  writebuf_enqueue(writebuf);
364
2.13k
}
365
366
2.13k
static void read_session_identification() {
367
  /* max length of 255 chars */
368
2.13k
  char linebuf[256];
369
2.13k
  int len = 0;
370
2.13k
  char done = 0;
371
2.13k
  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
2.36k
  for (i = IS_DROPBEAR_CLIENT ? 50 : 1; i > 0; i--) {
377
2.13k
    len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
378
379
2.13k
    if (len < 0 && errno != EINTR) {
380
      /* It failed */
381
512
      break;
382
512
    }
383
384
1.62k
    if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) {
385
      /* start of line matches */
386
1.40k
      done = 1;
387
1.40k
      break;
388
1.40k
    }
389
1.62k
  }
390
391
2.13k
  if (!done) {
392
736
    TRACE(("error reading remote ident: %s\n", strerror(errno)))
393
736
    ses.remoteclosed();
394
1.40k
  } else {
395
    /* linebuf is already null terminated */
396
1.40k
    ses.remoteident = m_malloc(len);
397
1.40k
    memcpy(ses.remoteident, linebuf, len);
398
1.40k
  }
399
400
  /* Shall assume that 2.x will be backwards compatible. */
401
2.13k
  if (strncmp(ses.remoteident, "SSH-2.", 6) != 0
402
2.13k
      && strncmp(ses.remoteident, "SSH-1.99-", 9) != 0) {
403
12
    dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
404
12
  }
405
406
2.13k
  DEBUG1(("remoteident: %s", ses.remoteident))
407
408
2.13k
}
409
410
/* returns the length including null-terminating zero on success,
411
 * or -1 on failure */
412
2.13k
static int ident_readln(int fd, char* buf, int count) {
413
  
414
2.13k
  char in;
415
2.13k
  int pos = 0;
416
2.13k
  int num = 0;
417
2.13k
  fd_set fds;
418
2.13k
  struct timeval timeout;
419
420
2.13k
  TRACE(("enter ident_readln"))
421
422
2.13k
  if (count < 1) {
423
0
    return -1;
424
0
  }
425
426
2.13k
  DROPBEAR_FD_ZERO(&fds);
427
428
  /* select since it's a non-blocking fd */
429
  
430
  /* leave space to null-terminate */
431
259k
  while (pos < count-1) {
432
433
259k
    FD_SET(fd, &fds);
434
435
259k
    timeout.tv_sec = 1;
436
259k
    timeout.tv_usec = 0;
437
259k
    if (select(fd+1, &fds, NULL, NULL, &timeout) < 0) {
438
398
      if (errno == EINTR) {
439
398
        continue;
440
398
      }
441
0
      TRACE(("leave ident_readln: select error"))
442
0
      return -1;
443
398
    }
444
445
258k
    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
258k
    if (FD_ISSET(fd, &fds)) {
451
258k
      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
258k
      if (num < 0) {
455
        /* error */
456
547
        if (errno == EINTR) {
457
468
          continue; /* not a real error */
458
468
        }
459
79
        TRACE(("leave ident_readln: read error"))
460
79
        return -1;
461
547
      }
462
258k
      if (num == 0) {
463
        /* EOF */
464
566
        TRACE(("leave ident_readln: EOF"))
465
566
        return -1;
466
566
      }
467
468
257k
#if DROPBEAR_FUZZ
469
257k
      fuzz_dump(&in, 1);
470
257k
#endif
471
472
257k
      if (in == '\n') {
473
        /* end of ident string */
474
1.31k
        break;
475
1.31k
      }
476
      /* we don't want to include '\r's */
477
256k
      if (in != '\r') {
478
154k
        buf[pos] = in;
479
154k
        pos++;
480
154k
      }
481
256k
    }
482
258k
  }
483
484
1.49k
  buf[pos] = '\0';
485
1.49k
  TRACE(("leave ident_readln: return %d", pos+1))
486
1.49k
  return pos+1;
487
2.13k
}
488
489
0
void ignore_recv_response() {
490
  /* Do nothing */
491
0
  TRACE(("Ignored msg_request_response"))
492
0
}
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
334k
static long elapsed(time_t now, time_t prev) {
524
334k
  time_t del = now - prev;
525
334k
  if (del > LONG_MAX) {
526
0
    return LONG_MAX;
527
0
  }
528
334k
  return (long)del;
529
334k
}
530
531
/* Check all timeouts which are required. Currently these are the time for
532
 * user authentication, and the automatic rekeying. */
533
334k
static void checktimeouts() {
534
535
334k
  time_t now;
536
334k
  now = monotonic_now();
537
538
334k
  if (IS_DROPBEAR_SERVER && ses.connect_time != 0
539
334k
    && 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
334k
  if (ses.remoteident == NULL) {
545
265k
    return;
546
265k
  }
547
548
69.0k
  if (!ses.kexstate.sentkexinit
549
69.0k
      && (elapsed(now, ses.kexstate.lastkextime) >= KEX_REKEY_TIMEOUT
550
0
      || 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
69.0k
  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
69.0k
  if (opts.idle_timeout_secs > 0
578
69.0k
      && elapsed(now, ses.last_packet_time_idle) >= opts.idle_timeout_secs) {
579
0
    dropbear_close("Idle timeout");
580
0
  }
581
69.0k
}
582
583
151k
static void update_timeout(long limit, time_t now, time_t last_event, long * timeout) {
584
151k
  TRACE2(("update_timeout limit %ld, now %llu, last %llu, timeout %ld",
585
151k
    limit,
586
151k
    (unsigned long long)now,
587
151k
    (unsigned long long)last_event, *timeout))
588
151k
  if (last_event > 0 && limit > 0) {
589
0
    *timeout = MIN(*timeout, elapsed(now, last_event) + limit);
590
0
    TRACE2(("new timeout %ld", *timeout))
591
0
  }
592
151k
}
593
594
75.7k
static long select_timeout() {
595
  /* determine the minimum timeout that might be required, so
596
  as to avoid waking when unneccessary */
597
75.7k
  long timeout = KEX_REKEY_TIMEOUT;
598
75.7k
  time_t now = monotonic_now();
599
600
75.7k
  if (!ses.kexstate.sentkexinit) {
601
0
    update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
602
0
  }
603
604
75.7k
  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
75.7k
  if (ses.authstate.authdone) {
610
75.7k
    update_timeout(opts.keepalive_secs, now,
611
75.7k
      MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
612
75.7k
      &timeout);
613
75.7k
  }
614
615
75.7k
  update_timeout(opts.idle_timeout_secs, now, ses.last_packet_time_idle,
616
75.7k
    &timeout);
617
618
  /* clamp negative timeouts to zero - event has already triggered */
619
75.7k
  return MAX(timeout, 0);
620
75.7k
}
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
2.13k
void fill_passwd(const char* username) {
631
2.13k
  struct passwd *pw = NULL;
632
2.13k
  if (ses.authstate.pw_name)
633
0
    m_free(ses.authstate.pw_name);
634
2.13k
  if (ses.authstate.pw_dir)
635
0
    m_free(ses.authstate.pw_dir);
636
2.13k
  if (ses.authstate.pw_shell)
637
0
    m_free(ses.authstate.pw_shell);
638
2.13k
  if (ses.authstate.pw_passwd)
639
0
    m_free(ses.authstate.pw_passwd);
640
641
2.13k
  pw = getpwnam(username);
642
2.13k
  if (!pw) {
643
0
    return;
644
0
  }
645
2.13k
  ses.authstate.pw_uid = pw->pw_uid;
646
2.13k
  ses.authstate.pw_gid = pw->pw_gid;
647
2.13k
  ses.authstate.pw_name = m_strdup(pw->pw_name);
648
2.13k
  ses.authstate.pw_dir = m_strdup(pw->pw_dir);
649
2.13k
  ses.authstate.pw_shell = m_strdup(pw->pw_shell);
650
2.13k
  {
651
2.13k
    char *passwd_crypt = pw->pw_passwd;
652
2.13k
#ifdef HAVE_SHADOW_H
653
    /* get the shadow password if possible */
654
2.13k
    struct spwd *spasswd = getspnam(ses.authstate.pw_name);
655
2.13k
    if (spasswd && spasswd->sp_pwdp) {
656
2.13k
      passwd_crypt = spasswd->sp_pwdp;
657
2.13k
    }
658
2.13k
#endif
659
2.13k
    if (!passwd_crypt) {
660
      /* android supposedly returns NULL */
661
0
      passwd_crypt = "!!";
662
0
    }
663
2.13k
    ses.authstate.pw_passwd = m_strdup(passwd_crypt);
664
2.13k
  }
665
2.13k
}
666
667
/* Called when channels are modified */
668
2.13k
void update_channel_prio() {
669
2.13k
  enum dropbear_prio new_prio;
670
2.13k
  int any = 0;
671
2.13k
  unsigned int i;
672
673
2.13k
  TRACE(("update_channel_prio"))
674
675
2.13k
  if (ses.sock_out < 0) {
676
0
    TRACE(("leave update_channel_prio: no socket"))
677
0
    return;
678
0
  }
679
680
2.13k
  new_prio = DROPBEAR_PRIO_NORMAL;
681
2.13k
  for (i = 0; i < ses.chansize; i++) {
682
0
    struct Channel *channel = ses.channels[i];
683
0
    if (!channel) {
684
0
      continue;
685
0
    }
686
0
    any = 1;
687
0
    if (channel->prio == DROPBEAR_PRIO_LOWDELAY) {
688
0
      new_prio = DROPBEAR_PRIO_LOWDELAY;
689
0
      break;
690
0
    }
691
0
  }
692
693
2.13k
  if (any == 0) {
694
    /* lowdelay during setup */
695
2.13k
    TRACE(("update_channel_prio: not any"))
696
2.13k
    new_prio = DROPBEAR_PRIO_LOWDELAY;
697
2.13k
  }
698
699
2.13k
  if (new_prio != ses.socket_prio) {
700
2.13k
    TRACE(("Dropbear priority transitioning %d -> %d", ses.socket_prio, new_prio))
701
2.13k
    set_sock_priority(ses.sock_out, new_prio);
702
2.13k
    ses.socket_prio = new_prio;
703
2.13k
  }
704
2.13k
}
705