Coverage Report

Created: 2023-03-20 06:33

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