• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

proftpd / proftpd / 28042938174

23 Jun 2026 05:02PM UTC coverage: 92.464% (-0.6%) from 93.027%
28042938174

push

github

web-flow
It is possible for a client to say that it wishes to use the "sk-ssh-ed25519@openssh.com" algorithm for SSH user publickey authentication, but to _actually_ provide an "ssh-ed25519" public key.

The issue is that, when verifying the type of the public key provided by the client, we do not enforce that the provided key algorith matches the expected public key algorithm.

Thanks to Fabian Wahle of Hap Security for reporting this issue.

48661 of 52627 relevant lines covered (92.46%)

234.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.18
/src/data.c
1
/*
2
 * ProFTPD - FTP server daemon
3
 * Copyright (c) 1997, 1998 Public Flood Software
4
 * Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver@tos.net>
5
 * Copyright (c) 2001-2026 The ProFTPD Project team
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
19
 *
20
 * As a special exemption, Public Flood Software/MacGyver aka Habeeb J. Dihu
21
 * and other respective copyright holders give permission to link this program
22
 * with OpenSSL, and distribute the resulting executable, without including
23
 * the source code for OpenSSL in the source distribution.
24
 */
25

26
/* Data connection management functions */
27

28
#include "conf.h"
29

30
#ifdef HAVE_SYS_SENDFILE_H
31
#include <sys/sendfile.h>
32
#endif /* HAVE_SYS_SENDFILE_H */
33

34
#ifdef HAVE_SYS_UIO_H
35
#include <sys/uio.h>
36
#endif /* HAVE_SYS_UIO_H */
37

38
static const char *trace_channel = "data";
39
static const char *timing_channel = "timing";
40

41
#define PR_DATA_OPT_IGNORE_ASCII        0x0001
42
static unsigned long data_opts = 0UL;
43
static uint64_t data_start_ms = 0L;
44
static int data_first_byte_read = FALSE;
45
static int data_first_byte_written = FALSE;
46

47
/* local macro */
48

49
#define MODE_STRING        (session.sf_flags & (SF_ASCII|SF_ASCII_OVERRIDE) ? \
50
                         "ASCII" : "BINARY")
51

52
/* Internal usage: pointer to current data connection stream in use (may be
53
 * in either read or write mode)
54
 */
55
static pr_netio_stream_t *nstrm = NULL;
56

57
static long timeout_linger = PR_TUNABLE_TIMEOUTLINGER;
58

59
static int timeout_idle = PR_TUNABLE_TIMEOUTIDLE;
60
static int timeout_noxfer = PR_TUNABLE_TIMEOUTNOXFER;
61
static int timeout_stalled = PR_TUNABLE_TIMEOUTSTALLED;
62

63
/* Called if the "Stalled" timer goes off
64
 */
65
static int stalled_timeout_cb(CALLBACK_FRAME) {
×
66
  pr_event_generate("core.timeout-stalled", NULL);
×
67
  pr_log_pri(PR_LOG_NOTICE, "Data transfer stall timeout: %d %s",
×
68
    timeout_stalled, timeout_stalled != 1 ? "seconds" : "second");
×
69
  pr_session_disconnect(NULL, PR_SESS_DISCONNECT_TIMEOUT,
×
70
    "TimeoutStalled during data transfer");
71

72
  /* Prevent compiler warning. */
73
  return 0;
×
74
}
75

76
/* This signal is raised if we get OOB data on the control connection, and
77
 * a data transfer is in progress.
78
 */
79
static RETSIGTYPE data_urgent(int signo) {
×
80
  if (session.sf_flags & SF_XFER) {
×
81
    pr_trace_msg(trace_channel, 5, "received SIGURG signal (signal %d), "
×
82
      "setting 'aborted' session flag", signo);
83
    session.sf_flags |= SF_ABORT;
×
84

85
    if (nstrm) {
×
86
      pr_netio_abort(nstrm);
×
87
    }
88
  }
89

90
  signal(SIGURG, data_urgent);
×
91
}
×
92

93
static void data_new_xfer(char *filename, int direction) {
7✔
94
  pr_data_clear_xfer_pool();
7✔
95

96
  session.xfer.p = make_sub_pool(session.pool);
7✔
97
  pr_pool_tag(session.xfer.p, "Data Transfer pool");
7✔
98

99
  session.xfer.filename = pstrdup(session.xfer.p, filename);
7✔
100
  session.xfer.direction = direction;
7✔
101
  session.xfer.bufsize = pr_config_get_server_xfer_bufsz(direction);
7✔
102
  session.xfer.buf = pcalloc(session.xfer.p, session.xfer.bufsize + 1);
7✔
103
  pr_trace_msg(trace_channel, 8, "allocated data transfer buffer of %lu bytes",
7✔
104
    (unsigned long) session.xfer.bufsize);
7✔
105
  session.xfer.buf++;        /* leave room for ascii translation */
7✔
106
  session.xfer.buflen = 0;
7✔
107
}
7✔
108

109
static int data_passive_open(const char *reason, off_t size) {
3✔
110
  conn_t *c;
111
  int rev, xerrno = 0;
3✔
112

113
  if (reason == NULL &&
6✔
114
      session.xfer.filename != NULL) {
3✔
115
    reason = session.xfer.filename;
×
116
  }
117

118
  /* Set the "stalled" timer, if any, to prevent the connection
119
   * open from taking too long
120
   */
121
  if (timeout_stalled) {
3✔
122
    pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb,
3✔
123
      "TimeoutStalled");
124
  }
125

126
  /* We save the state of our current disposition for doing reverse
127
   * lookups, and then set it to what the configuration wants it to
128
   * be.
129
   */
130
  rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS);
3✔
131

132
  /* Protocol and socket options should be set before handshaking. */
133

134
  if (session.xfer.direction == PR_NETIO_IO_RD) {
3✔
135
    pr_inet_set_socket_opts2(session.d->pool, session.d,
4✔
136
      (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0,
2✔
137
      main_server->tcp_keepalive, 0);
2✔
138

139
  } else {
140
    pr_inet_set_socket_opts2(session.d->pool, session.d,
2✔
141
      0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0),
1✔
142
      main_server->tcp_keepalive, 0);
1✔
143
  }
144

145
  c = pr_inet_accept(session.pool, session.d, session.c, -1, -1, TRUE);
3✔
146
  pr_netaddr_set_reverse_dns(rev);
3✔
147

148
  if (c && c->mode != CM_ERROR) {
3✔
149
    pr_inet_close(session.pool, session.d);
×
150
    (void) pr_inet_set_nonblock(session.pool, c);
×
151
    session.d = c;
×
152

153
    pr_log_debug(DEBUG4, "passive data connection opened - local  : %s:%d",
×
154
      pr_netaddr_get_ipstr(session.d->local_addr), session.d->local_port);
155
    pr_log_debug(DEBUG4, "passive data connection opened - remote : %s:%d",
×
156
      pr_netaddr_get_ipstr(session.d->remote_addr), session.d->remote_port);
×
157

158
    if (session.xfer.xfer_type != STOR_UNIQUE) {
×
159
      if (size) {
×
160
        pr_response_send(R_150, _("Opening %s mode data connection for %s "
×
161
          "(%" PR_LU " %s)"), MODE_STRING, reason, (pr_off_t) size,
×
162
          size != 1 ? "bytes" : "byte");
163

164
      } else {
165
        pr_response_send(R_150, _("Opening %s mode data connection for %s"),
×
166
          MODE_STRING, reason);
×
167
      }
168

169
    } else {
170

171
      /* Format of 150 responses for STOU is explicitly dictated by
172
       * RFC 1123:
173
       *
174
       *  4.1.2.9  STOU Command: RFC-959 Section 4.1.3
175
       *
176
       *    The STOU command stores into a uniquely named file.  When it
177
       *    receives an STOU command, a Server-FTP MUST return the
178
       *    actual file name in the "125 Transfer Starting" or the "150
179
       *    Opening Data Connection" message that precedes the transfer
180
       *    (the 250 reply code mentioned in RFC-959 is incorrect).  The
181
       *    exact format of these messages is hereby defined to be as
182
       *    follows:
183
       *
184
       *        125 FILE: pppp
185
       *        150 FILE: pppp
186
       *
187
       *    where pppp represents the unique pathname of the file that
188
       *    will be written.
189
       */
190
      pr_response_send(R_150, "FILE: %s", reason);
×
191
    }
192

193
    return 0;
194
  }
195

196
  /* Check for error conditions. */
197
  if (c != NULL &&
3✔
198
      c->mode == CM_ERROR) {
×
199
    pr_log_pri(PR_LOG_ERR, "error: unable to accept an incoming data "
×
200
      "connection: %s", strerror(c->xerrno));
201
  }
202

203
  xerrno = session.d->xerrno;
3✔
204
  pr_response_add_err(R_425, _("Unable to build data connection: %s"),
3✔
205
    strerror(xerrno));
206
  pr_data_close2();
3✔
207

208
  errno = xerrno;
3✔
209
  return -1;
3✔
210
}
211

212
static int data_active_open(const char *reason, off_t size) {
8✔
213
  conn_t *conn;
214
  config_rec *c;
215
  int bind_port, rev, *root_revoke = NULL, tcp_nodelay = 1, xerrno;
8✔
216
  const pr_netaddr_t *bind_addr = NULL;
8✔
217

218
  if (session.c->remote_addr == NULL) {
8✔
219
    /* An opened but unconnected connection? */
220
    errno = EINVAL;
1✔
221
    return -1;
1✔
222
  }
223

224
  if (reason == NULL &&
14✔
225
      session.xfer.filename != NULL) {
7✔
226
    reason = session.xfer.filename;
4✔
227
  }
228

229
  if (pr_netaddr_get_family(session.c->local_addr) == pr_netaddr_get_family(session.c->remote_addr)) {
7✔
230
    bind_addr = session.c->local_addr;
7✔
231

232
  } else {
233
    /* In this scenario, the server has an IPv6 socket, but the remote client
234
     * is an IPv4 (or IPv4-mapped IPv6) peer.
235
     */
236
    bind_addr = pr_netaddr_v6tov4(session.xfer.p, session.c->local_addr);
×
237
  }
238

239
  /* Default source port to which to bind for the active transfer, as
240
   * per RFC959.
241
   */
242
  bind_port = session.c->local_port-1;
7✔
243

244
  root_revoke = get_param_ptr(TOPLEVEL_CONF, "RootRevoke", FALSE);
7✔
245
  if (root_revoke == NULL) {
7✔
246
    /* In the absence of any explicit RootRevoke, the default behavior is to
247
     * change the source port.  This means we are technically noncompliant,
248
     * but most clients do not enforce this behavior.
249
     */
250
    bind_port = INPORT_ANY;
251

252
  } else {
253
    /* A RootRevoke value of 0 indicates 'false', 1 indicates 'true', and
254
     * 2 indicates 'NonCompliantActiveTransfer'.  We change the source port for
255
     * a RootRevoke value of 2, and for a value of 1, we make sure that
256
     * that the port is not a privileged port.
257
     */
258
    switch (*root_revoke) {
4✔
259
      case 1:
2✔
260
        if (bind_port < 1024) {
2✔
261
          pr_log_debug(DEBUG0, "RootRevoke in effect, unable to bind to local "
1✔
262
            "port %d for active transfer", bind_port);
263
          errno = EPERM;
1✔
264
          return -1;
1✔
265
        }
266
        break;
267

268
      case 2:
1✔
269
        bind_port = INPORT_ANY;
1✔
270
        break;
1✔
271

272
      default:
273
        break;
274
    }
275
  }
276

277
  session.d = pr_inet_create_conn2(session.pool, -1, bind_addr, bind_port,
6✔
278
    PR_INET_CREATE_CONN_FL_RETRY_BIND);
279
  if (session.d == NULL) {
6✔
280
    xerrno = errno;
×
281

282
    pr_response_add_err(R_425, _("Unable to build data connection: %s"),
×
283
      strerror(xerrno));
284

285
    errno = xerrno;
×
286
    return -1;
×
287
  }
288

289
  /* Default remote address to which to connect for an active transfer,
290
   * if the client has not specified a different address via PORT/EPRT,
291
   * as per RFC 959.
292
   */
293
  if (pr_netaddr_get_family(&session.data_addr) == AF_UNSPEC) {
6✔
294
    pr_log_debug(DEBUG6, "Client has not sent previous PORT/EPRT command, "
2✔
295
      "defaulting to %s#%u for active transfer",
296
      pr_netaddr_get_ipstr(session.c->remote_addr), session.c->remote_port);
2✔
297

298
    pr_netaddr_set_family(&session.data_addr, pr_netaddr_get_family(session.c->remote_addr));
2✔
299
    pr_netaddr_set_sockaddr(&session.data_addr, pr_netaddr_get_sockaddr(session.c->remote_addr));
2✔
300
  }
301

302
  /* Set the "stalled" timer, if any, to prevent the connection
303
   * open from taking too long
304
   */
305
  if (timeout_stalled > 0) {
6✔
306
    pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb,
6✔
307
      "TimeoutStalled");
308
  }
309

310
  rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS);
6✔
311

312
  /* Protocol and socket options should be set before handshaking. */
313

314
  if (session.xfer.direction == PR_NETIO_IO_RD) {
6✔
315
    pr_inet_set_socket_opts2(session.d->pool, session.d,
8✔
316
      (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0,
4✔
317
      main_server->tcp_keepalive, 1);
4✔
318

319
  } else {
320
    pr_inet_set_socket_opts2(session.d->pool, session.d,
4✔
321
      0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0),
2✔
322
      main_server->tcp_keepalive, 1);
2✔
323
  }
324

325
  c = find_config(main_server->conf, CONF_PARAM, "TCPNoDelay", FALSE);
6✔
326
  if (c != NULL) {
6✔
327
    int data_use_nodelay;
328

329
    data_use_nodelay = *((int *) c->argv[1]);
×
330
    if (data_use_nodelay == FALSE) {
×
331
      tcp_nodelay = 0;
×
332
    }
333
  }
334

335
  session.d->use_nodelay = tcp_nodelay;
6✔
336
  pr_inet_set_proto_opts(session.pool, session.d, main_server->tcp_mss_len,
6✔
337
    tcp_nodelay, IPTOS_THROUGHPUT, 1);
338
  pr_inet_generate_socket_event("core.data-connect", main_server,
6✔
339
    session.d->local_addr, session.d->listen_fd);
6✔
340

341
  if (pr_inet_connect(session.d->pool, session.d, &session.data_addr,
6✔
342
      session.data_port) < 0) {
6✔
343
    xerrno = session.d->xerrno;
6✔
344

345
    pr_log_debug(DEBUG6,
12✔
346
      "Error connecting to %s#%u for active data transfer: %s",
347
      pr_netaddr_get_ipstr(&session.data_addr), session.data_port,
6✔
348
      strerror(xerrno));
349
    pr_response_add_err(R_425, _("Unable to build data connection: %s"),
6✔
350
      strerror(xerrno));
351
    pr_data_close2();
6✔
352

353
    errno = xerrno;
6✔
354
    return -1;
6✔
355
  }
356

357
  conn = pr_inet_openrw(session.pool, session.d, NULL, PR_NETIO_STRM_DATA,
×
358
    session.d->listen_fd, -1, -1, TRUE);
×
359

360
  pr_netaddr_set_reverse_dns(rev);
×
361

362
  if (conn != NULL) {
×
363
    pr_log_debug(DEBUG4, "active data connection opened - local  : %s:%d",
×
364
      pr_netaddr_get_ipstr(session.d->local_addr), session.d->local_port);
×
365
    pr_log_debug(DEBUG4, "active data connection opened - remote : %s:%d",
×
366
      pr_netaddr_get_ipstr(session.d->remote_addr), session.d->remote_port);
×
367

368
    if (session.xfer.xfer_type != STOR_UNIQUE) {
×
369
      if (size) {
×
370
        pr_response_send(R_150, _("Opening %s mode data connection for %s "
×
371
          "(%" PR_LU " %s)"), MODE_STRING, reason, (pr_off_t) size,
×
372
          size != 1 ? "bytes" : "byte");
373

374
      } else {
375
        pr_response_send(R_150, _("Opening %s mode data connection for %s"),
×
376
          MODE_STRING, reason);
×
377
      }
378

379
    } else {
380

381
      /* Format of 150 responses for STOU is explicitly dictated by
382
       * RFC 1123:
383
       *
384
       *  4.1.2.9  STOU Command: RFC-959 Section 4.1.3
385
       *
386
       *    The STOU command stores into a uniquely named file.  When it
387
       *    receives an STOU command, a Server-FTP MUST return the
388
       *    actual file name in the "125 Transfer Starting" or the "150
389
       *    Opening Data Connection" message that precedes the transfer
390
       *    (the 250 reply code mentioned in RFC-959 is incorrect).  The
391
       *    exact format of these messages is hereby defined to be as
392
       *    follows:
393
       *
394
       *        125 FILE: pppp
395
       *        150 FILE: pppp
396
       *
397
       *    where pppp represents the unique pathname of the file that
398
       *    will be written.
399
       */
400
      pr_response_send(R_150, "FILE: %s", reason);
×
401
    }
402

403
    pr_inet_close(session.pool, session.d);
×
404
    (void) pr_inet_set_nonblock(session.pool, session.d);
×
405
    session.d = conn;
×
406
    return 0;
×
407
  }
408

409
  pr_response_add_err(R_425, _("Unable to build data connection: %s"),
×
410
    strerror(session.d->xerrno));
×
411
  xerrno = session.d->xerrno;
×
412
  pr_data_close2();
×
413

414
  errno = xerrno;
×
415
  return -1;
×
416
}
417

418
void pr_data_set_linger(long linger) {
1✔
419
  timeout_linger = linger;
1✔
420
}
1✔
421

422
int pr_data_get_timeout(int id) {
7✔
423
  switch (id) {
7✔
424
    case PR_DATA_TIMEOUT_IDLE:
2✔
425
      return timeout_idle;
2✔
426

427
    case PR_DATA_TIMEOUT_NO_TRANSFER:
2✔
428
      return timeout_noxfer;
2✔
429

430
    case PR_DATA_TIMEOUT_STALLED:
2✔
431
      return timeout_stalled;
2✔
432

433
    default:
434
      break;
435
  }
436

437
  errno = EINVAL;
1✔
438
  return -1;
1✔
439
}
440

441
void pr_data_set_timeout(int id, int timeout) {
3✔
442
  switch (id) {
3✔
443
    case PR_DATA_TIMEOUT_IDLE:
1✔
444
      timeout_idle = timeout;
1✔
445
      break;
1✔
446

447
    case PR_DATA_TIMEOUT_NO_TRANSFER:
1✔
448
      timeout_noxfer = timeout;
1✔
449
      break;
1✔
450

451
    case PR_DATA_TIMEOUT_STALLED:
1✔
452
      timeout_stalled = timeout;
1✔
453
      break;
1✔
454

455
    default:
456
      break;
457
  }
458
}
3✔
459

460
void pr_data_clear_xfer_pool(void) {
19✔
461
  int xfer_type;
462

463
  if (session.xfer.p != NULL) {
19✔
464
    destroy_pool(session.xfer.p);
2✔
465
  }
466

467
  /* Note that session.xfer.xfer_type may have been set already, e.g.
468
   * for STOR_UNIQUE uploads.  To support this, we need to preserve that
469
   * value.
470
   */
471
  xfer_type = session.xfer.xfer_type;
19✔
472

473
  memset(&session.xfer, 0, sizeof(session.xfer));
19✔
474
  session.xfer.xfer_type = xfer_type;
19✔
475
}
19✔
476

477
void pr_data_reset(void) {
9✔
478
  /* Clear any leftover state from previous transfers. */
479
  pr_ascii_ftp_reset();
9✔
480

481
  if (session.d != NULL &&
10✔
482
      session.d->pool != NULL) {
1✔
483
    destroy_pool(session.d->pool);
1✔
484
  }
485

486
  session.d = NULL;
9✔
487
  session.sf_flags &= (SF_ALL^(SF_ABORT|SF_POST_ABORT|SF_XFER|SF_PASSIVE|SF_ASCII_OVERRIDE|SF_EPSV_ALL));
9✔
488
}
9✔
489

490
int pr_data_ignore_ascii(int ignore_ascii) {
5✔
491
  int res;
492

493
  if (ignore_ascii != TRUE &&
5✔
494
      ignore_ascii != FALSE) {
495
    errno = EINVAL;
1✔
496
    return -1;
1✔
497
  }
498

499
  if (data_opts & PR_DATA_OPT_IGNORE_ASCII) {
4✔
500
    if (!ignore_ascii) {
2✔
501
      data_opts &= ~PR_DATA_OPT_IGNORE_ASCII;
1✔
502
    }
503

504
    res = TRUE;
505

506
  } else {
507
    if (ignore_ascii) {
2✔
508
      data_opts |= PR_DATA_OPT_IGNORE_ASCII;
1✔
509
    }
510

511
    res = FALSE;
512
  }
513

514
  return res;
515
}
516

517
void pr_data_init(char *filename, int direction) {
3✔
518
  if (session.xfer.p == NULL) {
3✔
519
    data_new_xfer(filename, direction);
2✔
520

521
  } else {
522
    if (!(session.sf_flags & SF_PASSIVE)) {
1✔
523
      pr_log_debug(DEBUG5,
1✔
524
        "data_init oddity: session.xfer exists in non-PASV mode");
525
    }
526

527
    session.xfer.direction = direction;
1✔
528
  }
529

530
  /* Clear any leftover state from previous transfers. */
531
  pr_ascii_ftp_reset();
3✔
532
}
3✔
533

534
int pr_data_open(char *filename, char *reason, int direction, off_t size) {
15✔
535
  int res = 0;
15✔
536
#if defined(HAVE_SIGACTION)
537
  struct sigaction act;
538
#endif /* HAVE_SIGACTION */
539

540
  if (session.c == NULL) {
15✔
541
    errno = EINVAL;
2✔
542
    return -1;
2✔
543
  }
544

545
  if ((session.sf_flags & SF_PASSIVE) ||
22✔
546
      (session.sf_flags & SF_EPSV_ALL)) {
9✔
547
    /* For passive transfers, we expect there to already be an existing
548
     * data connection...
549
     */
550
    if (session.d == NULL) {
4✔
551
      errno = EINVAL;
1✔
552
      return -1;
1✔
553
    }
554

555
  } else {
556
    /* ...but for active transfers, we expect there to NOT be an existing
557
     * data connection.
558
     */
559
    if (session.d != NULL) {
9✔
560
      errno = session.d->xerrno = EINVAL;
1✔
561
      return -1;
1✔
562
    }
563
  }
564

565
  /* Make sure that any abort flags have been cleared. */
566
  session.sf_flags &= ~(SF_ABORT|SF_POST_ABORT);
11✔
567

568
  if (session.xfer.p == NULL) {
11✔
569
    data_new_xfer(filename, direction);
5✔
570

571
  } else {
572
    session.xfer.direction = direction;
6✔
573
  }
574

575
  if (reason == NULL) {
11✔
576
    reason = filename;
11✔
577
  }
578

579
  /* Passive data transfers... */
580
  if ((session.sf_flags & SF_PASSIVE) ||
19✔
581
      (session.sf_flags & SF_EPSV_ALL)) {
8✔
582
    res = data_passive_open(reason, size);
3✔
583

584
  /* Active data transfers... */
585
  } else {
586
    res = data_active_open(reason, size);
8✔
587
  }
588

589
  if (res < 0) {
11✔
590
    return res;
591
  }
592

593
  if (pr_netio_postopen(session.d->instrm) < 0) {
×
594
    int xerrno;
595

596
    pr_response_add_err(R_425, _("Unable to build data connection: %s"),
×
597
      strerror(session.d->xerrno));
×
598
    xerrno = session.d->xerrno;
×
599
    pr_data_close2();
×
600

601
    errno = xerrno;
×
602
    return -1;
×
603
  }
604

605
  if (pr_netio_postopen(session.d->outstrm) < 0) {
×
606
    int xerrno;
607

608
    pr_response_add_err(R_425, _("Unable to build data connection: %s"),
×
609
      strerror(session.d->xerrno));
×
610
    xerrno = session.d->xerrno;
×
611
    pr_data_close2();
×
612

613
    errno = xerrno;
×
614
    return -1;
×
615
  }
616

617
  memset(&session.xfer.start_time, '\0', sizeof(session.xfer.start_time));
×
618
  gettimeofday(&session.xfer.start_time, NULL);
×
619

620
  if (session.xfer.direction == PR_NETIO_IO_RD) {
×
621
    nstrm = session.d->instrm;
×
622

623
  } else {
624
    nstrm = session.d->outstrm;
×
625
  }
626

627
  session.sf_flags |= SF_XFER;
×
628

629
  if (timeout_noxfer) {
×
630
    pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE);
×
631
  }
632

633
  /* Allow aborts -- set the current NetIO stream to allow interrupted
634
   * syscalls, so our SIGURG handler can interrupt it
635
   */
636
  pr_netio_set_poll_interval(nstrm, 1);
×
637

638
  /* PORTABILITY: sigaction is used here to allow us to indicate
639
   * (w/ POSIX at least) that we want SIGURG to interrupt syscalls.  Put
640
   * in whatever is necessary for your arch here; probably not necessary
641
   * as the only _important_ interrupted syscall is select(), which on
642
   * any sensible system is interrupted.
643
   */
644

645
#if defined(HAVE_SIGACTION)
646
  act.sa_handler = data_urgent;
×
647
  sigemptyset(&act.sa_mask);
×
648
  act.sa_flags = 0;
649

650
# if defined(SA_INTERRUPT)
651
  act.sa_flags |= SA_INTERRUPT;
652
# endif /* SA_INTERRUPT */
653
# if defined(SA_RESTART)
654
  act.sa_flags &= SA_RESTART;
×
655
# endif /* SA_RESTART */
656

657
  if (sigaction(SIGURG, &act, NULL) < 0) {
×
658
    pr_log_pri(PR_LOG_WARNING,
×
659
      "warning: unable to set SIGURG signal handler: %s", strerror(errno));
×
660
  }
661

662
#elif defined(HAVE_SIGINTERRUPT)
663
  if (siginterrupt(SIGURG, 1) < 0) {
664
    pr_log_pri(PR_LOG_WARNING,
665
      "warning: unable to make SIGURG interrupt system calls: %s",
666
      strerror(errno));
667
  }
668
#endif /* HAVE_SIGACTION or HAVE_SIGINTERRUPT */
669

670
  /* Reset all of the timing-related variables for data transfers. */
671
  pr_gettimeofday_millis(&data_start_ms);
×
672
  data_first_byte_read = FALSE;
×
673
  data_first_byte_written = FALSE;
×
674

675
  return res;
×
676
}
677

678
void pr_data_close2(void) {
12✔
679
  nstrm = NULL;
12✔
680

681
  if (session.d != NULL) {
12✔
682
    pr_inet_lingering_close(session.pool, session.d, timeout_linger);
10✔
683
    session.d = NULL;
10✔
684
  }
685

686
  /* Aborts no longer necessary */
687
  signal(SIGURG, SIG_IGN);
12✔
688

689
  if (timeout_noxfer) {
12✔
690
    pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE);
12✔
691
  }
692

693
  if (timeout_stalled) {
12✔
694
    pr_timer_remove(PR_TIMER_STALLED, ANY_MODULE);
12✔
695
  }
696

697
  session.sf_flags &= (SF_ALL^SF_PASSIVE);
12✔
698
  session.sf_flags &= (SF_ALL^(SF_ABORT|SF_XFER|SF_PASSIVE|SF_ASCII_OVERRIDE));
12✔
699
  pr_session_set_idle();
12✔
700
}
12✔
701

702
/* close == successful transfer */
703
void pr_data_close(int quiet) {
3✔
704
  pr_data_close2();
3✔
705

706
  if (quiet == FALSE) {
3✔
707
    pr_response_add(R_226, _("Transfer complete"));
1✔
708
  }
709
}
3✔
710

711
/* Note: true_abort may be false in real abort situations, because
712
 * some ftp clients close the data connection at the same time as they
713
 * send the OOB byte (which results in a broken pipe on our
714
 * end).  Thus, it's a race between the OOB data and the tcp close
715
 * finishing.  Either way, it's ok (client will see either "Broken pipe"
716
 * error or "Aborted").  xfer_abor() in mod_xfer cleans up the session
717
 * flags in any case.  session flags will end up have SF_POST_ABORT
718
 * set if the OOB byte won the race.
719
 */
720
void pr_data_cleanup(void) {
2✔
721
  /* sanity check */
722
  if (session.d != NULL) {
2✔
723
    pr_inet_lingering_close(session.pool, session.d, timeout_linger);
1✔
724
    session.d = NULL;
1✔
725
  }
726

727
  pr_data_clear_xfer_pool();
2✔
728

729
  /* Clear/restore the default data transfer type. Otherwise, things like
730
   * APPEs or STOUs will be preserved for the next upload erroneously
731
   * (see Bug#3612).
732
   */
733
  session.xfer.xfer_type = STOR_DEFAULT;
2✔
734
}
2✔
735

736
/* In order to avoid clearing the transfer counters in session.xfer, we don't
737
 * clear session.xfer here, it should be handled by the appropriate
738
 * LOG_CMD/LOG_CMD_ERR handler calling pr_data_cleanup().
739
 */
740
void pr_data_abort(int err, int quiet) {
11✔
741
  int true_abort = XFER_ABORTED;
11✔
742
  nstrm = NULL;
11✔
743

744
  pr_trace_msg(trace_channel, 9,
11✔
745
    "aborting data transfer (errno = %s (%d), quiet = %s, true abort = %s)",
746
    strerror(err), err, quiet ? "true" : "false",
747
    true_abort ? "true" : "false");
748

749
  if (session.d != NULL) {
11✔
750
    if (true_abort) {
9✔
751
      /* For "true" aborts, we also asynchronously send a 426 response
752
       * message via the "lingering abort" functions.
753
       */
754
      pr_inet_lingering_abort(session.pool, session.d, timeout_linger);
8✔
755

756
    } else {
757
      pr_inet_lingering_close(session.pool, session.d, timeout_linger);
1✔
758
    }
759

760
    session.d = NULL;
9✔
761
  }
762

763
  if (timeout_noxfer) {
11✔
764
    pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE);
11✔
765
  }
766

767
  if (timeout_stalled) {
11✔
768
    pr_timer_remove(PR_TIMER_STALLED, ANY_MODULE);
11✔
769
  }
770

771
  session.sf_flags &= (SF_ALL^SF_PASSIVE);
11✔
772
  session.sf_flags &= (SF_ALL^(SF_XFER|SF_PASSIVE|SF_ASCII_OVERRIDE));
11✔
773
  pr_session_set_idle();
11✔
774

775
  if (!quiet) {
11✔
776
    char *respcode = R_426;
10✔
777
    char *msg = NULL;
10✔
778
    char msgbuf[64];
779

780
    switch (err) {
10✔
781

782
    case 0:
2✔
783
#ifdef ECONNABORTED
784
    case ECONNABORTED:        /* FALLTHROUGH */
785
#endif
786
#ifdef ECONNRESET
787
    case ECONNRESET:        /* FALLTHROUGH */
788
#endif
789
#ifdef EPIPE
790
    case EPIPE:
791
#endif
792
      respcode = R_426;
2✔
793
      msg = _("Data connection closed");
2✔
794
      break;
2✔
795

796
#ifdef ENXIO
797
    case ENXIO:
1✔
798
      respcode = R_451;
1✔
799
      msg = _("Unexpected streams hangup");
1✔
800
      break;
1✔
801
#endif
802

803
#ifdef EAGAIN
804
    case EAGAIN:                /* FALLTHROUGH */
1✔
805
#endif
806
#ifdef ENOMEM
807
    case ENOMEM:
808
#endif
809
#if defined(EAGAIN) || defined(ENOMEM)
810
      respcode = R_451;
1✔
811
      msg = _("Insufficient memory or file locked");
1✔
812
      break;
1✔
813
#endif
814

815
#ifdef ETXTBSY
816
    case ETXTBSY:                /* FALLTHROUGH */
817
#endif
818
#ifdef EBUSY
819
    case EBUSY:
820
#endif
821
#if defined(ETXTBSY) || defined(EBUSY)
822
      respcode = R_451;
823
      break;
824
#endif
825

826
#ifdef ENOSPC
827
    case ENOSPC:
828
      respcode = R_452;
829
      break;
830
#endif
831

832
#ifdef EDQUOT
833
    case EDQUOT:                /* FALLTHROUGH */
834
#endif
835
#ifdef EFBIG
836
    case EFBIG:
837
#endif
838
#if defined(EDQUOT) || defined(EFBIG)
839
      respcode = R_552;
840
      break;
841
#endif
842

843
#ifdef ECOMM
844
    case ECOMM:                /* FALLTHROUGH */
845
#endif
846
#ifdef EDEADLK
847
    case EDEADLK:                /* FALLTHROUGH */
848
#endif
849
#ifdef EDEADLOCK
850
# if !defined(EDEADLK) || (EDEADLOCK != EDEADLK)
851
    case EDEADLOCK:                /* FALLTHROUGH */
852
# endif
853
#endif
854
#ifdef EXFULL
855
    case EXFULL:                /* FALLTHROUGH */
856
#endif
857
#ifdef ENOSR
858
    case ENOSR:                /* FALLTHROUGH */
859
#endif
860
#ifdef EPROTO
861
    case EPROTO:                /* FALLTHROUGH */
862
#endif
863
#ifdef ETIME
864
    case ETIME:                /* FALLTHROUGH */
865
#endif
866
#ifdef EIO
867
    case EIO:                /* FALLTHROUGH */
868
#endif
869
#ifdef EFAULT
870
    case EFAULT:                /* FALLTHROUGH */
871
#endif
872
#ifdef ESPIPE
873
    case ESPIPE:                /* FALLTHROUGH */
874
#endif
875
#if defined(ECOMM) || defined(EDEADLK) ||  defined(EDEADLOCK) || \
876
    defined(EXFULL) || defined(ENOSR) || defined(EPROTO) || \
877
    defined(ETIME) || defined(EIO) || defined(EFAULT) || \
878
    defined(ESPIPE) || defined(EPIPE)
879
      respcode = R_451;
880
      break;
881
#endif
882

883
#ifdef EREMCHG
884
    case EREMCHG:                /* FALLTHROUGH */
×
885
#endif
886
#ifdef ESRMNT
887
    case ESRMNT:                /* FALLTHROUGH */
888
#endif
889
#ifdef ESTALE
890
    case ESTALE:                /* FALLTHROUGH */
891
#endif
892
#ifdef ENOLINK
893
    case ENOLINK:                /* FALLTHROUGH */
894
#endif
895
#ifdef ENOLCK
896
    case ENOLCK:                /* FALLTHROUGH */
897
#endif
898
#ifdef ENETRESET
899
    case ENETRESET:                /* FALLTHROUGH */
900
#endif
901
#ifdef ETIMEDOUT
902
    case ETIMEDOUT:
903
#endif
904
#if defined(EREMCHG) || defined(ESRMNT) ||  defined(ESTALE) || \
905
    defined(ENOLINK) || defined(ENOLCK) || defined(ENETRESET) || \
906
    defined(ECONNABORTED) || defined(ECONNRESET) || defined(ETIMEDOUT)
907
      respcode = R_450;
×
908
      msg = _("Link to file server lost");
×
909
      break;
×
910
#endif
911

912
    default:
2✔
913
      respcode = R_426;
2✔
914
      msg = _("Data connection closed");
2✔
915
      break;
2✔
916
    }
917

918
    if (msg == NULL &&
6✔
919
        (msg = strerror(err)) == NULL) {
920

921
      if (pr_snprintf(msgbuf, sizeof(msgbuf),
×
922
          _("Unknown or out of range errno [%d]"), err) > 0) {
×
923
        msg = msgbuf;
×
924
      }
925
    }
926

927
    pr_log_pri(PR_LOG_NOTICE, "notice: user %s: aborting transfer: %s",
10✔
928
      session.user ? session.user : "(unknown)", msg);
10✔
929

930
    /* If we are aborting, then a 426 response has already been sent via
931
     * pr_inet_lingering_abort(), and we don't want to add another to the
932
     * error queue.
933
     */
934
    if (true_abort == FALSE) {
10✔
935
      pr_response_add_err(respcode, _("Transfer aborted. %s"), msg ? msg : "");
2✔
936
    }
937

938
    /* Forcibly clear the data-transfer instigating command pool from the
939
     * Response API.
940
     */
941
    pr_response_set_pool(session.pool);
10✔
942
  }
943

944
  if (true_abort) {
11✔
945
    session.sf_flags |= SF_POST_ABORT;
8✔
946
  }
947
}
11✔
948

949
/* From response.c.  XXX Need to provide these symbols another way. */
950
extern pr_response_t *resp_list, *resp_err_list;
951

952
static int peek_is_abor_cmd(void) {
14✔
953
  int fd, res;
954
  fd_set rfds;
955
  struct timeval tv;
956
  ssize_t len;
957
  char buf[5];
958

959
  tv.tv_sec = 1;
14✔
960
  tv.tv_usec = 0;
14✔
961

962
  fd = PR_NETIO_FD(session.c->instrm);
14✔
963
  pr_trace_msg(trace_channel, 20, "peeking at next data for fd %d", fd);
14✔
964

965
  FD_ZERO(&rfds);
14✔
966
  FD_SET(fd, &rfds);
14✔
967

968
  res = select(fd + 1, &rfds, NULL, NULL, &tv);
14✔
969
  while (res < 0) {
14✔
970
    int xerrno = errno;
×
971

972
    if (xerrno == EINTR) {
×
973
      pr_signals_handle();
×
974
      res = select(fd + 1, &rfds, NULL, NULL, &tv);
×
975
      continue;
×
976
    }
977

978
    pr_trace_msg(trace_channel, 20,
×
979
      "error waiting for next data on fd %d: %s", fd, strerror(xerrno));
980
    return FALSE;
×
981
  }
982

983
  if (res == 0) {
14✔
984
    /* Timed out. */
985
    pr_trace_msg(trace_channel, 20, "timed out peeking for data on fd %d", fd);
13✔
986
    return FALSE;
13✔
987
  }
988

989
  /* If we reach here, the peer must have sent something.  Let's see what it
990
   * might be.  Chances are that we received at least 5 bytes, but to be
991
   * defensive, we use MSG_WAITALL anyway.  TCP allows for sending one byte
992
   * at time, if need be.  The shortest FTP command is 5 bytes, e.g. "CCC\r\n".
993
   * ABOR would be 6 bytes, but we do not want to block until we see 6 bytes;
994
   * we're peeking opportunistically, and optimistically.
995
   */
996
  memset(&buf, 0, sizeof(buf));
1✔
997
  len = recv(fd, buf, sizeof(buf), MSG_PEEK|MSG_WAITALL);
1✔
998
  while (len < 0) {
1✔
999
    int xerrno = errno;
1✔
1000

1001
    if (xerrno == EINTR) {
1✔
1002
      pr_signals_handle();
×
1003
      len = recv(fd, &buf, sizeof(buf), MSG_PEEK|MSG_WAITALL);
×
1004
      continue;
×
1005
    }
1006

1007
    pr_trace_msg(trace_channel, 20,
1✔
1008
      "error peeking at next data: %s", strerror(xerrno));
1009
    return FALSE;
1✔
1010
  }
1011

1012
  pr_trace_msg(trace_channel, 20, "peeking at %ld bytes of next data",
×
1013
    (long) len);
1014
  if (strncasecmp(buf, "ABOR\r", len) == 0) {
×
1015
    pr_trace_msg(trace_channel, 20, "peeked data probably 'ABOR' command");
×
1016
    return TRUE;
×
1017
  }
1018

1019
  pr_trace_msg(trace_channel, 20, "peeked data '%.*s' not ABOR command",
×
1020
    (int) len, buf);
1021
  return FALSE;
×
1022
}
1023

1024
static void poll_ctrl(void) {
26✔
1025
  int res;
1026

1027
  if (session.c == NULL) {
26✔
1028
    return;
1029
  }
1030

1031
  pr_trace_msg(trace_channel, 4, "polling for commands on control channel");
14✔
1032
  pr_netio_set_poll_interval(session.c->instrm, 0);
14✔
1033
  res = pr_netio_poll(session.c->instrm);
14✔
1034
  pr_netio_reset_poll_interval(session.c->instrm);
14✔
1035

1036
  if (res == 0 &&
28✔
1037
      !(session.sf_flags & SF_ABORT)) {
14✔
1038

1039
    /* First, we peek at the data, to see if it is an ABOR command.  Why?
1040
     *
1041
     * Consider the case where a client uses the TCP OOB mechanism and
1042
     * marks the ABOR command with the marker.  In that case, a SIGURG signal
1043
     * will have been raised, and the SF_ABORT flag set.  The actual "ABOR"
1044
     * data on the control connection will be read only AFTER the data transfer
1045
     * has been failed.  This leads the proper ordering of multiple responses
1046
     * (first for failed transfer, second for successful ABOR) in such cases.
1047
     *
1048
     * Now consider the case where a client does NOT use the TCP OOB mechanism,
1049
     * and only sends the ABOR command.  We want the same behavior in this case
1050
     * as for the TCP OOB case, BUT now, the SF_ABORT flag has NOT been set at
1051
     * this point in the flow.  Which means that we might read that "ABOR" text
1052
     * from the control connection _in the middle_ of the data transfer, which
1053
     * leads to different behavior, different ordering of responses.
1054
     *
1055
     * Thus we cheat here, and only peek at the control connection data.  IFF
1056
     * it is the "ABOR\r\n" text, then we set the SF_ABORT flag ourselves
1057
     * here, and preserve the expected semantics (Bug #4402).
1058
     */
1059
    if (peek_is_abor_cmd() == TRUE) {
14✔
1060
      pr_trace_msg(trace_channel, 5, "client sent 'ABOR' command during data "
×
1061
        "transfer, setting 'aborted' session flag");
1062

1063
      session.sf_flags |= SF_ABORT;
×
1064

1065
      if (nstrm != NULL) {
×
1066
        pr_netio_abort(nstrm);
×
1067
        errno = 0;
×
1068
      }
1069
    }
1070
  }
1071

1072
  if (res == 0 &&
28✔
1073
      !(session.sf_flags & SF_ABORT)) {
14✔
1074
    cmd_rec *cmd = NULL;
14✔
1075

1076
    pr_trace_msg(trace_channel, 1,
14✔
1077
      "data available for reading on control channel during data transfer, "
1078
      "reading control data");
1079
    res = pr_cmd_read(&cmd);
14✔
1080
    if (res < 0) {
14✔
1081
      int xerrno;
1082

1083
#if defined(ECONNABORTED)
1084
      xerrno = ECONNABORTED;
×
1085
#elif defined(ENOTCONN)
1086
      xerrno = ENOTCONN;
1087
#else
1088
      xerrno = EIO;
1089
#endif
1090

1091
      pr_trace_msg(trace_channel, 1,
×
1092
        "unable to read control command during data transfer: %s",
1093
        strerror(xerrno));
1094
      errno = xerrno;
×
1095

1096
#ifndef PR_DEVEL_NO_DAEMON
1097
      /* Otherwise, EOF */
1098
      pr_session_disconnect(NULL, PR_SESS_DISCONNECT_CLIENT_EOF, NULL);
×
1099
#else
1100
      return;
1101
#endif /* PR_DEVEL_NO_DAEMON */
1102

1103
    } else if (cmd != NULL) {
14✔
1104
      char *ch;
1105

1106
      for (ch = cmd->argv[0]; *ch; ch++) {
35✔
1107
        if (PR_ISALPHA((int) *ch)) {
28✔
1108
          *ch = toupper((int) *ch);
56✔
1109
        }
1110
      }
1111

1112
      cmd->cmd_id = pr_cmd_get_id(cmd->argv[0]);
7✔
1113

1114
      /* Only handle commands which do not involve data transfers; we
1115
       * already have a data transfer in progress.  For any data transfer
1116
       * command, send a 450 ("busy") reply.  Looks like almost all of the
1117
       * data transfer commands accept that response, as per RFC959.
1118
       *
1119
       * We also prevent the EPRT, EPSV, PASV, and PORT commands, since
1120
       * they will also interfere with the current data transfer.  In doing
1121
       * so, we break RFC compliance a little; RFC959 does not allow a
1122
       * response code of 450 for those commands (although it should).
1123
       */
1124
      if (pr_cmd_cmp(cmd, PR_CMD_APPE_ID) == 0 ||
14✔
1125
          pr_cmd_cmp(cmd, PR_CMD_LIST_ID) == 0 ||
14✔
1126
          pr_cmd_cmp(cmd, PR_CMD_MLSD_ID) == 0 ||
14✔
1127
          pr_cmd_cmp(cmd, PR_CMD_NLST_ID) == 0 ||
14✔
1128
          pr_cmd_cmp(cmd, PR_CMD_RETR_ID) == 0 ||
14✔
1129
          pr_cmd_cmp(cmd, PR_CMD_STOR_ID) == 0 ||
14✔
1130
          pr_cmd_cmp(cmd, PR_CMD_STOU_ID) == 0 ||
14✔
1131
          pr_cmd_cmp(cmd, PR_CMD_RNFR_ID) == 0 ||
14✔
1132
          pr_cmd_cmp(cmd, PR_CMD_RNTO_ID) == 0 ||
14✔
1133
          pr_cmd_cmp(cmd, PR_CMD_PORT_ID) == 0 ||
14✔
1134
          pr_cmd_cmp(cmd, PR_CMD_EPRT_ID) == 0 ||
14✔
1135
          pr_cmd_cmp(cmd, PR_CMD_PASV_ID) == 0 ||
12✔
1136
          pr_cmd_cmp(cmd, PR_CMD_EPSV_ID) == 0) {
7✔
1137
        pool *resp_pool;
1138

1139
        pr_trace_msg(trace_channel, 5,
2✔
1140
          "client sent '%s' command during data transfer, denying",
1141
          (char *) cmd->argv[0]);
2✔
1142

1143
        resp_list = resp_err_list = NULL;
2✔
1144
        resp_pool = pr_response_get_pool();
2✔
1145

1146
        pr_response_set_pool(cmd->pool);
2✔
1147

1148
        pr_response_add_err(R_450, _("%s: data transfer in progress"),
2✔
1149
          (char *) cmd->argv[0]);
2✔
1150

1151
        pr_response_flush(&resp_err_list);
2✔
1152

1153
        pr_response_set_pool(resp_pool);
2✔
1154
        destroy_pool(cmd->pool);
2✔
1155

1156
      /* We don't want to actually dispatch the NOOP command, since that
1157
       * would overwrite the scoreboard with the NOOP state; admins probably
1158
       * want to see the command that caused the data transfer.  And since
1159
       * NOOP doesn't take a 450 response (as per RFC959), we will simply
1160
       * return 200.
1161
       */
1162
      } else if (pr_cmd_cmp(cmd, PR_CMD_NOOP_ID) == 0) {
5✔
1163
        pool *resp_pool;
1164

1165
        pr_trace_msg(trace_channel, 5,
2✔
1166
          "client sent '%s' command during data transfer, ignoring",
1167
          (char *) cmd->argv[0]);
2✔
1168

1169
        resp_list = resp_err_list = NULL;
2✔
1170
        resp_pool = pr_response_get_pool();
2✔
1171

1172
        pr_response_set_pool(cmd->pool);
2✔
1173

1174
        pr_response_add(R_200, _("%s: data transfer in progress"),
2✔
1175
          (char *) cmd->argv[0]);
2✔
1176

1177
        pr_response_flush(&resp_list);
2✔
1178

1179
        pr_response_set_pool(resp_pool);
2✔
1180
        destroy_pool(cmd->pool);
2✔
1181

1182
      } else {
1183
        char *title_buf = NULL;
3✔
1184
        int curr_cmd_id = 0, title_len = -1;
3✔
1185
        const char *curr_cmd = NULL, *sce_cmd = NULL, *sce_cmd_arg = NULL;
3✔
1186
        cmd_rec *curr_cmd_rec = NULL;
3✔
1187
        pool *resp_pool;
1188

1189
        pr_trace_msg(trace_channel, 5,
3✔
1190
          "client sent '%s' command during data transfer, dispatching",
1191
          (char *) cmd->argv[0]);
3✔
1192

1193
        title_len = pr_proctitle_get(NULL, 0);
3✔
1194
        if (title_len > 0) {
3✔
1195
          title_buf = pcalloc(cmd->pool, title_len + 1);
×
1196
          pr_proctitle_get(title_buf, title_len + 1);
×
1197
        }
1198

1199
        curr_cmd = session.curr_cmd;
3✔
1200
        curr_cmd_id = session.curr_cmd_id;
3✔
1201
        curr_cmd_rec = session.curr_cmd_rec;
3✔
1202
        sce_cmd = pr_scoreboard_entry_get(PR_SCORE_CMD);
3✔
1203
        sce_cmd_arg = pr_scoreboard_entry_get(PR_SCORE_CMD_ARG);
3✔
1204

1205
        resp_list = resp_err_list = NULL;
3✔
1206
        resp_pool = pr_response_get_pool();
3✔
1207

1208
        pr_response_set_pool(cmd->pool);
3✔
1209
        pr_cmd_dispatch(cmd);
3✔
1210

1211
        pr_scoreboard_entry_update(session.pid,
3✔
1212
          PR_SCORE_CMD, "%s", sce_cmd, NULL, NULL);
1213
        pr_scoreboard_entry_update(session.pid,
3✔
1214
          PR_SCORE_CMD_ARG, "%s", sce_cmd_arg, NULL, NULL);
1215

1216
        if (title_len > 0) {
3✔
1217
          pr_proctitle_set_str(title_buf);
×
1218
        }
1219

1220
        pr_response_flush(&resp_list);
3✔
1221
        pr_response_set_pool(resp_pool);
3✔
1222
        destroy_pool(cmd->pool);
3✔
1223

1224
        session.curr_cmd = curr_cmd;
3✔
1225
        session.curr_cmd_id = curr_cmd_id;
3✔
1226
        session.curr_cmd_rec = curr_cmd_rec;
3✔
1227
      }
1228

1229
    } else {
1230
      pr_trace_msg(trace_channel, 3,
7✔
1231
        "invalid command sent, sending error response");
1232
      pr_response_send(R_500, _("Invalid command: try being more creative"));
7✔
1233
    }
1234
  }
1235
}
1236

1237
/* pr_data_xfer() actually transfers the data on the data connection.  ASCII
1238
 * translation is performed if necessary.  `direction' is set when the data
1239
 * connection was opened.
1240
 *
1241
 * We determine if the client buffer is read from or written to.  Returns 0 if
1242
 * reading and data connection closes, or -1 if error (with errno set).
1243
 */
1244
int pr_data_xfer(char *cl_buf, size_t cl_size) {
34✔
1245
  int len = 0;
34✔
1246
  int total = 0;
34✔
1247
  int res = 0;
34✔
1248
  pool *tmp_pool = NULL;
34✔
1249

1250
  if (cl_buf == NULL ||
68✔
1251
      cl_size == 0) {
34✔
1252
    errno = EINVAL;
8✔
1253
    return -1;
8✔
1254
  }
1255

1256
  /* Poll the control channel for any commands we should handle, like
1257
   * QUIT or ABOR.
1258
   */
1259
  poll_ctrl();
26✔
1260

1261
  /* If we don't have a data connection here (e.g. might have been closed
1262
   * by an ABOR), then return zero (no data transferred).
1263
   */
1264
  if (session.d == NULL) {
26✔
1265
    int xerrno;
1266

1267
#if defined(ECONNABORTED)
1268
    xerrno = ECONNABORTED;
4✔
1269
#elif defined(ENOTCONN)
1270
    xerrno = ENOTCONN;
1271
#else
1272
    xerrno = EIO;
1273
#endif
1274

1275
    pr_trace_msg(trace_channel, 1,
4✔
1276
      "data connection is null prior to data transfer (possibly from "
1277
      "aborted transfer), returning '%s' error", strerror(xerrno));
1278
    pr_log_debug(DEBUG5,
4✔
1279
      "data connection is null prior to data transfer (possibly from "
1280
       "aborted transfer), returning '%s' error", strerror(xerrno));
1281

1282
    errno = xerrno;
4✔
1283
    return -1;
4✔
1284
  }
1285

1286
  if (session.xfer.direction == PR_NETIO_IO_RD) {
22✔
1287
    char *buf;
1288

1289
    buf = session.xfer.buf;
12✔
1290

1291
    /* We use ASCII translation if:
1292
     *
1293
     * - SF_ASCII session flag is set, AND IGNORE_ASCII data opt NOT set
1294
     */
1295
    if (((session.sf_flags & SF_ASCII) &&
19✔
1296
        !(data_opts & PR_DATA_OPT_IGNORE_ASCII))) {
7✔
1297
      int adjlen, buflen;
1298

1299
      do {
1300
        buflen = session.xfer.buflen;        /* how much remains in buf */
7✔
1301
        adjlen = 0;
7✔
1302

1303
        pr_signals_handle();
7✔
1304

1305
        len = pr_netio_read(session.d->instrm, buf + buflen,
7✔
1306
          session.xfer.bufsize - buflen, 1);
7✔
1307
        while (len < 0) {
7✔
1308
          int xerrno = errno;
1✔
1309

1310
          if (xerrno == EAGAIN || xerrno == EINTR) {
1✔
1311
            /* Since our socket is in non-blocking mode, read(2) can return
1312
             * EAGAIN if there is no data yet for us.  Handle this by
1313
             * delaying temporarily, then trying again.
1314
             */
1315
            errno = EINTR;
×
1316
            pr_signals_handle();
×
1317

1318
            len = pr_netio_read(session.d->instrm, buf + buflen,
×
1319
              session.xfer.bufsize - buflen, 1);
×
1320
            continue;
×
1321
          }
1322

1323
          destroy_pool(tmp_pool);
1✔
1324
          errno = xerrno;
1✔
1325
          return -1;
1✔
1326
        }
1327

1328
        if (len > 0 &&
12✔
1329
            data_first_byte_read == FALSE) {
6✔
1330
          if (pr_trace_get_level(timing_channel)) {
2✔
1331
            unsigned long elapsed_ms;
1332
            uint64_t read_ms;
1333

1334
            pr_gettimeofday_millis(&read_ms);
2✔
1335
            elapsed_ms = (unsigned long) (read_ms - data_start_ms);
2✔
1336

1337
            pr_trace_msg(timing_channel, 7,
2✔
1338
              "Time for first data byte read: %lu ms", elapsed_ms);
1339
          }
1340

1341
          data_first_byte_read = TRUE;
2✔
1342
        }
1343

1344
        if (len > 0) {
6✔
1345
          pr_trace_msg(trace_channel, 19, "read %d %s from network", len,
6✔
1346
            len != 1 ? "bytes" : "byte");
1347

1348
          buflen += len;
6✔
1349

1350
          if (timeout_stalled) {
6✔
1351
            pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
6✔
1352
          }
1353
        }
1354

1355
        /* If buflen > 0, data remains in the buffer to be copied. */
1356
        if (len >= 0 &&
6✔
1357
            buflen > 0) {
6✔
1358

1359
          /* Perform ASCII translation:
1360
           *
1361
           * buflen: is returned as the modified buffer length after
1362
           *         translation
1363
           * res:    is returned as the number of characters unprocessed in
1364
           *         the buffer (to be dealt with later)
1365
           *
1366
           * We skip the call to pr_ascii_ftp_from_crlf() in one case:
1367
           * when we have one character in the buffer and have reached
1368
           * end of data, this is so that pr_ascii_ftp_from_crlf() won't sit
1369
           * forever waiting for the next character after a final '\r'.
1370
           */
1371
          if (len > 0 ||
12✔
1372
              buflen > 1) {
6✔
1373
            size_t outlen = 0;
6✔
1374

1375
            if (tmp_pool == NULL) {
6✔
1376
              tmp_pool = make_sub_pool(session.xfer.p);
6✔
1377
              pr_pool_tag(tmp_pool, "ASCII upload");
6✔
1378
            }
1379

1380
            res = pr_ascii_ftp_from_crlf(tmp_pool, buf, buflen, &buf, &outlen);
6✔
1381
            if (res < 0) {
6✔
1382
              pr_trace_msg(trace_channel, 3, "error reading ASCII data: %s",
×
1383
                strerror(errno));
×
1384

1385
            } else {
1386
              adjlen += res;
6✔
1387
              buflen = (int) outlen;
6✔
1388
            }
1389
          }
1390

1391
          /* Now copy everything we can into cl_buf */
1392
          if ((size_t) buflen > cl_size) {
6✔
1393
            /* Because we have to cut our buffer short, make sure this
1394
             * is made up for later by increasing adjlen.
1395
             */
1396
            adjlen += (buflen - cl_size);
×
1397
            buflen = cl_size;
×
1398
          }
1399

1400
          memcpy(cl_buf, buf, buflen);
12✔
1401

1402
          /* Copy whatever remains at the end of session.xfer.buf to the
1403
           * head of the buffer and adjust buf accordingly.
1404
           *
1405
           * adjlen is now the total bytes still waiting in buf, if
1406
           * anything remains, copy it to the start of the buffer.
1407
           */
1408

1409
          if (adjlen > 0) {
6✔
1410
            memcpy(buf, buf + buflen, adjlen);
1✔
1411
          }
1412

1413
          /* Store everything back in session.xfer. */
1414
          session.xfer.buflen = adjlen;
6✔
1415
          total += buflen;
6✔
1416
        }
1417
        
1418
        /* Restart if data was returned by pr_netio_read() (len > 0) but no
1419
         * data was copied to the client buffer (buflen = 0).  This indicates
1420
         * that pr_ascii_ftp_from_crlf() needs more data in order to
1421
         * translate, so we need to call pr_netio_read() again.
1422
         */
1423
      } while (len > 0 && buflen == 0);
6✔
1424

1425
      /* Return how much data we actually copied into the client buffer. */
1426
      len = buflen;
1427

1428
    } else {
1429
      len = pr_netio_read(session.d->instrm, cl_buf, cl_size, 1);
5✔
1430
      while (len < 0) {
10✔
1431
        int xerrno = errno;
1✔
1432

1433
        if (xerrno == EAGAIN || xerrno == EINTR) {
1✔
1434
          /* Since our socket is in non-blocking mode, read(2) can return
1435
           * EAGAIN if there is no data yet for us.  Handle this by
1436
           * delaying temporarily, then trying again.
1437
           */
1438
          errno = EINTR;
×
1439
          pr_signals_handle();
×
1440

1441
          len = pr_netio_read(session.d->instrm, cl_buf, cl_size, 1);
×
1442
          continue;
×
1443
        }
1444

1445
        break;
1446
      }
1447

1448
      if (len > 0) {
5✔
1449
        pr_trace_msg(trace_channel, 19, "read %d %s from network", len,
4✔
1450
          len != 1 ? "bytes" : "byte");
1451

1452
        if (data_first_byte_read == FALSE) {
4✔
1453
          if (pr_trace_get_level(timing_channel)) {
2✔
1454
            unsigned long elapsed_ms;
1455
            uint64_t read_ms;
1456

1457
            pr_gettimeofday_millis(&read_ms);
2✔
1458
            elapsed_ms = (unsigned long) (read_ms - data_start_ms);
2✔
1459

1460
            pr_trace_msg(timing_channel, 7,
2✔
1461
              "Time for first data byte read: %lu ms", elapsed_ms);
1462
          }
1463

1464
          data_first_byte_read = TRUE;
2✔
1465
        }
1466

1467
        /* Non-ASCII mode doesn't need to use session.xfer.buf */
1468
        if (timeout_stalled) {
4✔
1469
          pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
4✔
1470
        }
1471

1472
        total += len;
1473
      }
1474
    }
1475

1476
  } else { /* PR_NETIO_IO_WR */
1477

1478
    while (cl_size) {
18✔
1479
      int bwrote = 0;
10✔
1480
      int buflen = cl_size;
10✔
1481
      unsigned int xferbuflen;
1482
      char *xferbuf = NULL, *ascii_buf = NULL;
10✔
1483

1484
      pr_signals_handle();
10✔
1485

1486
      if (buflen > pr_config_get_server_xfer_bufsz(PR_NETIO_IO_WR)) {
10✔
1487
        buflen = pr_config_get_server_xfer_bufsz(PR_NETIO_IO_WR);
×
1488
      }
1489

1490
      xferbuf = cl_buf;
10✔
1491
      xferbuflen = buflen;
10✔
1492

1493
      /* We use ASCII translation if:
1494
       *
1495
       * - SF_ASCII_OVERRIDE session flag is set (e.g. for LIST/NLST)
1496
       * - SF_ASCII session flag is set, AND IGNORE_ASCII data opt NOT set
1497
       */
1498
      if ((session.sf_flags & SF_ASCII_OVERRIDE) ||
14✔
1499
          ((session.sf_flags & SF_ASCII) &&
5✔
1500
           !(data_opts & PR_DATA_OPT_IGNORE_ASCII))) {
1✔
1501
        char *out = NULL;
7✔
1502
        size_t outlen = 0;
7✔
1503

1504
        if (tmp_pool == NULL) {
7✔
1505
          tmp_pool = make_sub_pool(session.xfer.p);
7✔
1506
          pr_pool_tag(tmp_pool, "ASCII download");
7✔
1507
        }
1508

1509
        /* Fill up our internal buffer. */
1510
        memcpy(session.xfer.buf, cl_buf, buflen);
14✔
1511

1512
        /* Scan the internal buffer, looking for LFs with no preceding CRs.
1513
         * Add CRs (and expand the internal buffer) as necessary. xferbuflen
1514
         * will be adjusted so that it contains the length of data in
1515
         * the internal buffer, including any added CRs.
1516
         */
1517
        res = pr_ascii_ftp_to_crlf(tmp_pool, session.xfer.buf, xferbuflen,
7✔
1518
          &out, &outlen);
1519
        if (res < 0) {
7✔
1520
          pr_trace_msg(trace_channel, 1, "error writing ASCII data: %s",
×
1521
            strerror(errno));
×
1522

1523
        } else {
1524
          ascii_buf = session.xfer.buf;
7✔
1525
          session.xfer.buf = out;
7✔
1526
          session.xfer.buflen = xferbuflen = outlen;
7✔
1527
        }
1528

1529
        xferbuf = session.xfer.buf;
7✔
1530
      }
1531

1532
      bwrote = pr_netio_write(session.d->outstrm, xferbuf, xferbuflen);
10✔
1533
      while (bwrote < 0) {
10✔
1534
        int xerrno = errno;
4✔
1535

1536
        if (xerrno == EAGAIN ||
8✔
1537
            xerrno == EINTR) {
4✔
1538
          /* Since our socket may be in non-blocking mode, write(2) can return
1539
           * EAGAIN if there is not enough from for our data yet.  Handle
1540
           * this by delaying temporarily, then trying again.
1541
           */
1542
          errno = EINTR;
2✔
1543
          pr_signals_handle();
2✔
1544

1545
          bwrote = pr_netio_write(session.d->outstrm, xferbuf, xferbuflen);
2✔
1546
          continue;
2✔
1547
        }
1548

1549
        destroy_pool(tmp_pool);
2✔
1550
        if (ascii_buf != NULL) {
2✔
1551
          /* Free up the malloc'd memory. */
1552
          free(session.xfer.buf);
1✔
1553
          session.xfer.buf = ascii_buf;
1✔
1554
        }
1555

1556
        errno = xerrno;
2✔
1557
        return -1;
2✔
1558
      }
1559

1560
      if (bwrote > 0) {
8✔
1561
        pr_trace_msg(trace_channel, 19, "wrote %d %s to network", bwrote,
8✔
1562
          bwrote != 1 ? "bytes" : "byte");
1563

1564
        if (data_first_byte_written == FALSE) {
8✔
1565
          if (pr_trace_get_level(timing_channel)) {
3✔
1566
            unsigned long elapsed_ms;
1567
            uint64_t write_ms;
1568

1569
            pr_gettimeofday_millis(&write_ms);
3✔
1570
            elapsed_ms = (unsigned long) (write_ms - data_start_ms);
3✔
1571

1572
            pr_trace_msg(timing_channel, 7,
3✔
1573
              "Time for first data byte written: %lu ms", elapsed_ms);
1574
          }
1575

1576
          data_first_byte_written = TRUE;
3✔
1577
        }
1578

1579
        if (timeout_stalled) {
8✔
1580
          pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
8✔
1581
        }
1582

1583
        cl_size -= buflen;
8✔
1584
        cl_buf += buflen;
8✔
1585
        total += buflen;
8✔
1586
      }
1587

1588
      if (ascii_buf != NULL) {
8✔
1589
        /* Yes, we are using malloc et al here, rather than the memory pools.
1590
         * See Bug#4352 for details.
1591
         */
1592
        free(session.xfer.buf);
6✔
1593
        session.xfer.buf = ascii_buf;
6✔
1594
      }
1595
    }
1596

1597
    len = total;
1598
  }
1599

1600
  if (total &&
19✔
1601
      timeout_idle) {
1602
    pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE);
18✔
1603
  }
1604

1605
  session.xfer.total_bytes += total;
19✔
1606
  session.total_bytes += total;
19✔
1607
  if (session.xfer.direction == PR_NETIO_IO_RD) {
19✔
1608
    session.total_bytes_in += total;
11✔
1609

1610
  } else {
1611
    session.total_bytes_out += total;
8✔
1612
  }
1613

1614
  destroy_pool(tmp_pool);
19✔
1615
  return (len < 0 ? -1 : len);
19✔
1616
}
1617

1618
#if defined(HAVE_SENDFILE)
1619
/* pr_data_sendfile() actually transfers the data on the data connection.
1620
 * ASCII translation is not performed.
1621
 * return 0 if reading and data connection closes, or -1 if error
1622
 */
1623
pr_sendfile_t pr_data_sendfile(int retr_fd, off_t *offset, off_t count) {
7✔
1624
  int flags, error;
1625
  pr_sendfile_t len = 0, total = 0;
7✔
1626
# if defined(HAVE_AIX_SENDFILE)
1627
  struct sf_parms parms;
1628
  int rc;
1629
# endif /* HAVE_AIX_SENDFILE */
1630

1631
  if (offset == NULL ||
14✔
1632
      count == 0) {
7✔
1633
    errno = EINVAL;
3✔
1634
    return -1;
3✔
1635
  }
1636

1637
  if (session.xfer.direction == PR_NETIO_IO_RD) {
4✔
1638
    errno = EPERM;
1✔
1639
    return -1;
1✔
1640
  }
1641

1642
  if (session.d == NULL) {
3✔
1643
    errno = EPERM;
1✔
1644
    return -1;
1✔
1645
  }
1646

1647
  flags = fcntl(PR_NETIO_FD(session.d->outstrm), F_GETFL);
2✔
1648
  if (flags < 0) {
2✔
1649
    return -1;
1650
  }
1651

1652
  /* Set fd to blocking-mode for sendfile() */
1653
  if (flags & O_NONBLOCK) {
2✔
1654
    if (fcntl(PR_NETIO_FD(session.d->outstrm), F_SETFL, flags^O_NONBLOCK) < 0) {
×
1655
      return -1;
1656
    }
1657
  }
1658

1659
  for (;;) {
1660
# if defined(HAVE_LINUX_SENDFILE) || defined(HAVE_SOLARIS_SENDFILE)
1661
    off_t orig_offset = *offset;
2✔
1662

1663
    /* Linux semantics are fairly straightforward in a glibc 2.x world:
1664
     *
1665
     *   #include <sys/sendfile.h>
1666
     *
1667
     *   ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
1668
     *
1669
     * Unfortunately, this API does not allow for an off_t number of bytes
1670
     * to be sent, only a size_t.  This means we need to make sure that
1671
     * the given count does not exceed the maximum value for a size_t.  Even
1672
     * worse, the return value is a ssize_t, not a size_t, which means
1673
     * the maximum value used can only be of the maximum _signed_ value,
1674
     * not the maximum unsigned value.  This means calling sendfile() more
1675
     * times.  How annoying.
1676
     */
1677

1678
#  if defined(HAVE_LINUX_SENDFILE)
1679
    if (count > INT_MAX) {
2✔
1680
      count = INT_MAX;
×
1681
    }
1682
#  elif defined(HAVE_SOLARIS_SENDFILE)
1683
#   if SIZEOF_SIZE_T == SIZEOF_INT
1684
    if (count > INT_MAX) {
1685
      count = INT_MAX;
1686
    }
1687
#   elif SIZEOF_SIZE_T == SIZEOF_LONG
1688
    if (count > LONG_MAX) {
1689
      count = LONG_MAX;
1690
    }
1691
#   elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
1692
    if (count > LLONG_MAX) {
1693
      count = LLONG_MAX;
1694
    }
1695
#   endif
1696
#  endif /* !HAVE_SOLARIS_SENDFILE */
1697

1698
    errno = 0;
2✔
1699
    len = sendfile(PR_NETIO_FD(session.d->outstrm), retr_fd, offset, count);
2✔
1700

1701
    /* If no data could be written (e.g. the file was truncated), we're
1702
     * done (Bug#4318).
1703
     */
1704
    if (len == 0) {
2✔
1705
      if (errno != EINTR &&
×
1706
          errno != EAGAIN) {
1707
        break;
1708
      }
1709

1710
      /* Handle our interrupting signal, and continue. */
1711
      pr_signals_handle();
×
1712
    }
1713

1714
    if (len != -1 &&
4✔
1715
        len < count) {
2✔
1716
      /* Under Linux semantics, this occurs when a signal has interrupted
1717
       * sendfile().
1718
       */
1719
      if (XFER_ABORTED) {
×
1720
        errno = EINTR;
×
1721

1722
        session.xfer.total_bytes += len;
×
1723
        session.total_bytes += len;
×
1724
        session.total_bytes_out += len;
×
1725
        session.total_raw_out += len;
×
1726

1727
        return -1;
×
1728
      }
1729

1730
      count -= len;
×
1731

1732
      /* Only reset the timers if data have actually been written out. */
1733
      if (len > 0) {
×
1734
        if (timeout_stalled) {
×
1735
          pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
×
1736
        }
1737

1738
        if (timeout_idle) {
×
1739
          pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE);
×
1740
        }
1741
      }
1742

1743
      session.xfer.total_bytes += len;
×
1744
      session.total_bytes += len;
×
1745
      session.total_bytes_out += len;
×
1746
      session.total_raw_out += len;
×
1747
      total += len;
×
1748

1749
      pr_signals_handle();
×
1750
      continue;
×
1751
    }
1752

1753
    if (len == -1) {
2✔
1754
      /* Linux updates offset on error, not len like BSD, fix up so
1755
       * BSD-based code works.
1756
       */
1757
      len = *offset - orig_offset;
1✔
1758
      *offset = orig_offset;
1✔
1759

1760
# elif defined(HAVE_BSD_SENDFILE)
1761
    /* BSD semantics for sendfile are flexible...it'd be nice if we could
1762
     * standardize on something like it.  The semantics are:
1763
     *
1764
     *   #include <sys/types.h>
1765
     *   #include <sys/socket.h>
1766
     *   #include <sys/uio.h>
1767
     *
1768
     *   int sendfile(int in_fd, int out_fd, off_t offset, size_t count,
1769
     *                struct sf_hdtr *hdtr, off_t *len, int flags)
1770
     *
1771
     *  The comments above, about size_t versus off_t, apply here as
1772
     *  well.  Except that BSD's sendfile() uses an off_t * for returning
1773
     *  the number of bytes sent, so we can use the maximum unsigned
1774
     *  value.
1775
     */
1776

1777
#  if SIZEOF_SIZE_T == SIZEOF_INT
1778
    if (count > UINT_MAX) {
1779
      count = UINT_MAX;
1780
    }
1781
#  elif SIZEOF_SIZE_T == SIZEOF_LONG
1782
    if (count > ULONG_MAX) {
1783
      count = ULONG_MAX;
1784
    }
1785
#  elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
1786
    if (count > ULLONG_MAX) {
1787
      count = ULLONG_MAX;
1788
    }
1789
#  endif
1790

1791
    if (sendfile(retr_fd, PR_NETIO_FD(session.d->outstrm), *offset, count,
1792
        NULL, &len, 0) == -1) {
1793

1794
# elif defined(HAVE_MACOSX_SENDFILE)
1795
    off_t orig_len = count;
1796
    int res;
1797

1798
    /* Since Mac OSX uses the fourth argument as a value-return parameter,
1799
     * success or failure, we need to put the result into len after the
1800
     * call.
1801
     */
1802

1803
    res = sendfile(retr_fd, PR_NETIO_FD(session.d->outstrm), *offset, &orig_len,
1804
      NULL, 0);
1805
    len = orig_len;
1806

1807
    if (res < 0) {
1808
# elif defined(HAVE_AIX_SENDFILE)
1809

1810
    memset(&parms, 0, sizeof(parms));
1811

1812
    parms.file_descriptor = retr_fd;
1813
    parms.file_offset = (uint64_t) *offset;
1814
    parms.file_bytes = (int64_t) count;
1815

1816
    rc = send_file(&(PR_NETIO_FD(session.d->outstrm)), &(parms), (uint_t)0);
1817
    len = (int) parms.bytes_sent;
1818

1819
    if (rc < -1 || rc == 1) {
1820
# else
1821
    if (FALSE) {
1822
# endif /* HAVE_AIX_SENDFILE */
1823

1824
      /* IMO, BSD's semantics are warped.  Apparently, since we have our
1825
       * alarms tagged SA_INTERRUPT (allowing system calls to be
1826
       * interrupted - primarily for select), BSD will interrupt a
1827
       * sendfile operation as well, so we have to catch and handle this
1828
       * case specially.  It should also be noted that the sendfile(2) man
1829
       * page doesn't state any of this.
1830
       *
1831
       * HP/UX has the same semantics, however, EINTR is well documented
1832
       * as a side effect in the sendfile(2) man page.  HP/UX, however,
1833
       * is implemented horribly wrong.  If a signal would result in
1834
       * -1 being returned and EINTR being set, what ACTUALLY happens is
1835
       * that errno is cleared and the number of bytes written is returned.
1836
       *
1837
       * For obvious reasons, HP/UX sendfile is not supported yet.
1838
       */
1839
      if (errno == EINTR) {
1✔
1840
        if (XFER_ABORTED) {
×
1841
          session.xfer.total_bytes += len;
×
1842
          session.total_bytes += len;
×
1843
          session.total_bytes_out += len;
×
1844
          session.total_raw_out += len;
×
1845

1846
          return -1;
×
1847
        }
1848

1849
        pr_signals_handle();
×
1850

1851
        /* If we got everything in this transaction, we're done. */
1852
        if (len >= count) {
×
1853
          break;
1854
        }
1855

1856
        count -= len;
×
1857
        *offset += len;
×
1858

1859
        if (timeout_stalled) {
×
1860
          pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
×
1861
        }
1862

1863
        if (timeout_idle) {
×
1864
          pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE);
×
1865
        }
1866

1867
        session.xfer.total_bytes += len;
×
1868
        session.total_bytes += len;
×
1869
        session.total_bytes_out += len;
×
1870
        session.total_raw_out += len;
×
1871
        total += len;
×
1872

1873
        continue;
×
1874
      }
1875

1876
      error = errno;
1✔
1877
      (void) fcntl(PR_NETIO_FD(session.d->outstrm), F_SETFL, flags);
1✔
1878
      errno = error;
1✔
1879

1880
      return -1;
1✔
1881
    }
1882

1883
    break;
1884
  }
1885

1886
  if (flags & O_NONBLOCK) {
1✔
1887
    (void) fcntl(PR_NETIO_FD(session.d->outstrm), F_SETFL, flags);
×
1888
  }
1889

1890
  if (timeout_stalled) {
1✔
1891
    pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
1✔
1892
  }
1893

1894
  if (timeout_idle) {
1✔
1895
    pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE);
1✔
1896
  }
1897

1898
  session.xfer.total_bytes += len;
1✔
1899
  session.total_bytes += len;
1✔
1900
  session.total_bytes_out += len;
1✔
1901
  session.total_raw_out += len;
1✔
1902
  total += len;
1✔
1903

1904
  return total;
1✔
1905
}
1906
#else
1907
pr_sendfile_t pr_data_sendfile(int retr_fd, off_t *offset, off_t count) {
1908
  errno = ENOSYS;
1909
  return -1;
1910
}
1911
#endif /* HAVE_SENDFILE */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc