Coverage Report

Created: 2023-09-25 06:11

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