Coverage Report

Created: 2025-07-12 06:23

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