Coverage Report

Created: 2024-09-30 06:24

/src/proftpd/src/main.c
Line
Count
Source (jump to first uncovered line)
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-2023 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, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
20
 *
21
 * As a special exemption, Public Flood Software/MacGyver aka Habeeb J. Dihu
22
 * and other respective copyright holders give permission to link this program
23
 * with OpenSSL, and distribute the resulting executable, without including
24
 * the source code for OpenSSL in the source distribution.
25
 */
26
27
/* House initialization and main program loop */
28
29
#include "conf.h"
30
31
#ifdef HAVE_GETOPT_H
32
# include <getopt.h>
33
#endif
34
35
#ifdef HAVE_LIBUTIL_H
36
# include <libutil.h>
37
#endif /* HAVE_LIBUTIL_H */
38
39
#ifdef HAVE_UNAME
40
# include <sys/utsname.h>
41
#endif
42
43
#include "privs.h"
44
45
#ifdef PR_USE_OPENSSL
46
# include <openssl/opensslv.h>
47
#endif /* PR_USE_OPENSSL */
48
49
int (*cmd_auth_chk)(cmd_rec *);
50
void (*cmd_handler)(server_rec *, conn_t *);
51
52
/* From modules/module_glue.c */
53
extern module *static_modules[];
54
55
extern int have_dead_child;
56
extern xaset_t *server_list;
57
58
unsigned long max_connects = 0UL;
59
unsigned int max_connect_interval = 1;
60
61
session_t session;
62
63
/* Is this process the master standalone daemon process? */
64
unsigned char is_master = TRUE;
65
66
pid_t mpid = 0;       /* Master pid */
67
68
uid_t daemon_uid;
69
gid_t daemon_gid;
70
array_header *daemon_gids;
71
72
static time_t shut = 0, deny = 0, disc = 0;
73
static char shutmsg[81] = {'\0'};
74
75
/* The default command buffer size SHOULD be large enough to handle the
76
 * maximum path length, plus 4 bytes for the FTP command, plus 1 for the
77
 * whitespace separating command from path, and 2 for the terminating CRLF.
78
 */
79
0
#define PR_DEFAULT_CMD_BUFSZ  (PR_TUNABLE_PATH_MAX + 7)
80
81
/* From response.c */
82
extern pr_response_t *resp_list, *resp_err_list;
83
84
int nodaemon = 0;
85
86
static int no_forking = FALSE;
87
static int quiet = 0;
88
static int shutting_down = FALSE;
89
static int syntax_check = 0;
90
91
/* Command handling */
92
static void cmd_loop(server_rec *s, conn_t *conn);
93
94
static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags);
95
96
static const char *config_filename = PR_CONFIG_FILE_PATH;
97
98
/* Add child semaphore fds into the rfd for selecting */
99
0
static int semaphore_fds(fd_set *rfd, int maxfd) {
100
0
  if (child_count()) {
101
0
    pr_child_t *ch;
102
103
0
    for (ch = child_get(NULL); ch; ch = child_get(ch)) {
104
0
      pr_signals_handle_without_delay();
105
106
0
      if (ch->ch_pipefd != -1) {
107
0
        FD_SET(ch->ch_pipefd, rfd);
108
0
        if (ch->ch_pipefd > maxfd) {
109
0
          maxfd = ch->ch_pipefd;
110
0
        }
111
0
      }
112
0
    }
113
0
  }
114
115
0
  return maxfd;
116
0
}
117
118
0
void set_auth_check(int (*chk)(cmd_rec*)) {
119
0
  cmd_auth_chk = chk;
120
0
}
121
122
0
void pr_cmd_set_handler(void (*handler)(server_rec *, conn_t *)) {
123
0
  if (handler == NULL) {
124
0
    cmd_handler = cmd_loop;
125
126
0
  } else {
127
0
    cmd_handler = handler;
128
0
  }
129
0
}
130
131
0
void session_exit(int pri, void *lv, int exitval, void *dummy) {
132
0
  char *msg = (char *) lv;
133
134
0
  pr_log_pri(pri, "%s", msg);
135
136
0
  if (ServerType == SERVER_STANDALONE &&
137
0
      is_master) {
138
0
    pr_log_pri(PR_LOG_NOTICE, "ProFTPD " PROFTPD_VERSION_TEXT
139
0
      " standalone mode SHUTDOWN");
140
141
0
    PRIVS_ROOT
142
0
    pr_delete_scoreboard();
143
0
    if (nodaemon == FALSE) {
144
0
      pr_pidfile_remove();
145
0
    }
146
0
    PRIVS_RELINQUISH
147
0
  }
148
149
0
  pr_session_end(0);
150
0
}
151
152
0
void shutdown_end_session(void *d1, void *d2, void *d3, void *d4) {
153
0
  pool *p = permanent_pool;
154
155
0
  if (check_shutmsg(p, PR_SHUTMSG_PATH, &shut, &deny, &disc, shutmsg,
156
0
      sizeof(shutmsg)) == 1) {
157
0
    const char *user;
158
0
    time_t now;
159
0
    const char *msg, *serveraddress;
160
0
    config_rec *c = NULL;
161
0
    unsigned char *authenticated = get_param_ptr(main_server->conf,
162
0
      "authenticated", FALSE);
163
164
0
    serveraddress = (session.c && session.c->local_addr) ?
165
0
      pr_netaddr_get_ipstr(session.c->local_addr) :
166
0
      main_server->ServerAddress;
167
168
0
    c = find_config(main_server->conf, CONF_PARAM, "MasqueradeAddress", FALSE);
169
0
    if (c != NULL) {
170
0
      pr_netaddr_t *masq_addr = NULL;
171
172
0
      if (c->argv[0] != NULL) {
173
0
        masq_addr = c->argv[0];
174
0
      }
175
176
0
      if (masq_addr != NULL) {
177
0
        serveraddress = pr_netaddr_get_ipstr(masq_addr);
178
0
      }
179
0
    }
180
181
0
    time(&now);
182
0
    if (authenticated && *authenticated == TRUE) {
183
0
      user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);
184
185
0
    } else {
186
0
      user = "NONE";
187
0
    }
188
189
0
    msg = sreplace(p, shutmsg,
190
0
                   "%s", pstrdup(p, pr_strtime3(p, shut, FALSE)),
191
0
                   "%r", pstrdup(p, pr_strtime3(p, deny, FALSE)),
192
0
                   "%d", pstrdup(p, pr_strtime3(p, disc, FALSE)),
193
0
       "%C", (session.cwd[0] ? session.cwd : "(none)"),
194
0
       "%L", serveraddress,
195
0
       "%R", (session.c && session.c->remote_name ?
196
0
                         session.c->remote_name : "(unknown)"),
197
0
       "%T", pstrdup(p, pr_strtime3(p, now, FALSE)),
198
0
       "%U", user,
199
0
       "%V", main_server->ServerName,
200
0
                   NULL );
201
202
0
    pr_response_send_async(R_421, _("FTP server shutting down - %s"), msg);
203
204
0
    pr_log_pri(PR_LOG_NOTICE, "%s", msg);
205
0
    pr_session_disconnect(NULL, PR_SESS_DISCONNECT_SERVER_SHUTDOWN, NULL);
206
0
  }
207
208
0
  if (signal(SIGUSR1, pr_signals_handle_disconnect) == SIG_ERR) {
209
0
    pr_log_pri(PR_LOG_NOTICE,
210
0
      "unable to install SIGUSR1 (signal %d) handler: %s", SIGUSR1,
211
0
      strerror(errno));
212
0
  }
213
0
}
214
215
0
static int get_command_class(const char *name) {
216
0
  int idx = -1;
217
0
  unsigned int hash = 0;
218
0
  cmdtable *c;
219
220
0
  c = pr_stash_get_symbol2(PR_SYM_CMD, name, NULL, &idx, &hash);
221
0
  while (c && c->cmd_type != CMD) {
222
0
    pr_signals_handle();
223
0
    c = pr_stash_get_symbol2(PR_SYM_CMD, name, c, &idx, &hash);
224
0
  }
225
226
  /* By default, every command has a class of CL_ALL.  This insures that
227
   * any configured ExtendedLogs that default to "all" will log the command.
228
   */
229
0
  return (c ? c->cmd_class : CL_ALL);
230
0
}
231
232
0
static int _dispatch(cmd_rec *cmd, int cmd_type, int validate, char *match) {
233
0
  const char *cmdargstr = NULL;
234
0
  cmdtable *c;
235
0
  modret_t *mr;
236
0
  int success = 0, xerrno = 0;
237
0
  int send_error = 0;
238
0
  static int match_index_cache = -1;
239
0
  static unsigned int match_hash_cache = 0;
240
0
  static char *last_match = NULL;
241
0
  int *index_cache = NULL;
242
0
  unsigned int *hash_cache = NULL;
243
244
0
  send_error = (cmd_type == PRE_CMD || cmd_type == CMD ||
245
0
    cmd_type == POST_CMD_ERR);
246
247
0
  if (!match) {
248
0
    match = cmd->argv[0];
249
0
    index_cache = &cmd->stash_index;
250
0
    hash_cache = &cmd->stash_hash;
251
252
0
  } else {
253
0
    if (last_match != match) {
254
0
      match_index_cache = -1;
255
0
      last_match = match;
256
0
    }
257
258
0
    index_cache = &match_index_cache;
259
0
    hash_cache = &match_hash_cache;
260
0
  }
261
262
0
  c = pr_stash_get_symbol2(PR_SYM_CMD, match, NULL, index_cache, hash_cache);
263
264
0
  while (c && !success) {
265
0
    size_t cmdargstrlen = 0;
266
267
0
    pr_signals_handle();
268
269
0
    session.curr_cmd = cmd->argv[0];
270
0
    session.curr_cmd_id = cmd->cmd_id;
271
0
    session.curr_cmd_rec = cmd;
272
0
    session.curr_phase = cmd_type;
273
274
0
    if (c->cmd_type == cmd_type) {
275
0
      if (c->group) {
276
0
        cmd->group = pstrdup(cmd->pool, c->group);
277
0
      }
278
279
0
      if (c->requires_auth &&
280
0
          cmd_auth_chk &&
281
0
          !cmd_auth_chk(cmd)) {
282
0
        pr_trace_msg("command", 8,
283
0
          "command '%s' failed 'requires_auth' check for mod_%s.c",
284
0
          (char *) cmd->argv[0], c->m->name);
285
0
        errno = EACCES;
286
0
        return -1;
287
0
      }
288
289
0
      if (cmd->tmp_pool == NULL) {
290
0
        cmd->tmp_pool = make_sub_pool(cmd->pool);
291
0
        pr_pool_tag(cmd->tmp_pool, "cmd_rec tmp pool");
292
0
      }
293
294
0
      cmdargstr = pr_cmd_get_displayable_str(cmd, &cmdargstrlen);
295
296
0
      if (cmd_type == CMD) {
297
298
        /* The client has successfully authenticated... */
299
0
        if (session.user) {
300
0
          char *args = NULL;
301
302
          /* Be defensive, and check whether cmdargstrlen has a value.
303
           * If it's zero, assume we need to use strchr(3), rather than
304
           * memchr(2); see Bug#3714.
305
           */
306
0
          if (cmdargstrlen > 0) {
307
0
            args = memchr(cmdargstr, ' ', cmdargstrlen);
308
309
0
          } else {
310
0
            args = strchr(cmdargstr, ' ');
311
0
          }
312
313
0
          pr_scoreboard_entry_update(session.pid,
314
0
            PR_SCORE_CMD, "%s", cmd->argv[0], NULL, NULL);
315
0
          pr_scoreboard_entry_update(session.pid,
316
0
            PR_SCORE_CMD_ARG, "%s", args ? (args + 1) : "", NULL, NULL);
317
318
0
          pr_proctitle_set("%s - %s: %s", session.user, session.proc_prefix,
319
0
            cmdargstr);
320
321
        /* ...else the client has not yet authenticated */
322
0
        } else {
323
0
          pr_proctitle_set("%s:%d: %s", session.c->remote_addr ?
324
0
            pr_netaddr_get_ipstr(session.c->remote_addr) : "?",
325
0
            session.c->remote_port ? session.c->remote_port : 0, cmdargstr);
326
0
        }
327
0
      }
328
329
      /* Skip logging the internal CONNECT/DISCONNECT commands. */
330
0
      if (!(cmd->cmd_class & CL_CONNECT) &&
331
0
          !(cmd->cmd_class & CL_DISCONNECT)) {
332
333
0
        pr_log_debug(DEBUG4, "dispatching %s command '%s' to mod_%s",
334
0
          (cmd_type == PRE_CMD ? "PRE_CMD" :
335
0
           cmd_type == CMD ? "CMD" :
336
0
           cmd_type == POST_CMD ? "POST_CMD" :
337
0
           cmd_type == POST_CMD_ERR ? "POST_CMD_ERR" :
338
0
           cmd_type == LOG_CMD ? "LOG_CMD" :
339
0
           cmd_type == LOG_CMD_ERR ? "LOG_CMD_ERR" :
340
0
           "(unknown)"),
341
0
          cmdargstr, c->m->name);
342
343
0
        pr_trace_msg("command", 7, "dispatching %s command '%s' to mod_%s.c",
344
0
          (cmd_type == PRE_CMD ? "PRE_CMD" :
345
0
           cmd_type == CMD ? "CMD" :
346
0
           cmd_type == POST_CMD ? "POST_CMD" :
347
0
           cmd_type == POST_CMD_ERR ? "POST_CMD_ERR" :
348
0
           cmd_type == LOG_CMD ? "LOG_CMD" :
349
0
           cmd_type == LOG_CMD_ERR ? "LOG_CMD_ERR" :
350
0
           "(unknown)"),
351
0
          cmdargstr, c->m->name);
352
0
      }
353
354
0
      cmd->cmd_class |= c->cmd_class;
355
356
      /* KLUDGE: disable umask() for not G_WRITE operations.  Config/
357
       * Directory walking code will be completely redesigned in 1.3,
358
       * this is only necessary for performance reasons in 1.1/1.2
359
       */
360
361
0
      if (c->group == NULL ||
362
0
          strcmp(c->group, G_WRITE) != 0) {
363
0
        kludge_disable_umask();
364
0
      }
365
366
0
      mr = pr_module_call(c->m, c->handler, cmd);
367
0
      kludge_enable_umask();
368
369
0
      if (MODRET_ISHANDLED(mr)) {
370
0
        success = 1;
371
372
0
      } else if (MODRET_ISERROR(mr)) {
373
0
        xerrno = errno;
374
0
        success = -1;
375
376
0
        if (cmd_type == POST_CMD ||
377
0
            cmd_type == LOG_CMD ||
378
0
            cmd_type == LOG_CMD_ERR) {
379
0
          if (MODRET_ERRMSG(mr)) {
380
0
            pr_log_pri(PR_LOG_NOTICE, "%s", MODRET_ERRMSG(mr));
381
0
          }
382
383
          /* Even though we normally want to return a negative value
384
           * for success (indicating lack of success), for
385
           * LOG_CMD/LOG_CMD_ERR handlers, we always want to handle
386
           * errors as a success value of zero (meaning "keep looking").
387
           *
388
           * This will allow the cmd_rec to continue to be dispatched to
389
           * the other interested handlers (Bug#3633).
390
           */
391
0
          if (cmd_type == LOG_CMD ||
392
0
              cmd_type == LOG_CMD_ERR) {
393
0
            success = 0;
394
0
          }
395
396
0
        } else if (send_error) {
397
0
          if (MODRET_ERRNUM(mr) &&
398
0
              MODRET_ERRMSG(mr)) {
399
0
            pr_response_add_err(MODRET_ERRNUM(mr), "%s", MODRET_ERRMSG(mr));
400
401
0
          } else if (MODRET_ERRMSG(mr)) {
402
0
            pr_response_send_raw("%s", MODRET_ERRMSG(mr));
403
0
          }
404
0
        }
405
406
0
        errno = xerrno;
407
0
      }
408
409
0
      if (session.user &&
410
0
          !(session.sf_flags & SF_XFER) &&
411
0
          cmd_type == CMD) {
412
0
        pr_session_set_idle();
413
0
      }
414
415
0
      destroy_pool(cmd->tmp_pool);
416
0
      cmd->tmp_pool = NULL;
417
0
    }
418
419
0
    if (!success) {
420
0
      c = pr_stash_get_symbol2(PR_SYM_CMD, match, c, index_cache, hash_cache);
421
0
    }
422
0
  }
423
424
  /* Note: validate is only TRUE for the CMD phase, for specific handlers
425
   * (as opposed to any C_ANY handlers).
426
   */
427
428
0
  if (!c &&
429
0
      !success &&
430
0
      validate) {
431
0
    char *method;
432
433
    /* Prettify the command method, if need be. */
434
0
    if (strchr(cmd->argv[0], '_') == NULL) {
435
0
      method = cmd->argv[0];
436
437
0
    } else {
438
0
      register unsigned int i;
439
440
0
      method = pstrdup(cmd->pool, cmd->argv[0]);
441
0
      for (i = 0; method[i]; i++) {
442
0
        if (method[i] == '_') {
443
0
          method[i] = ' ';
444
0
        }
445
0
      }
446
0
    }
447
448
0
    pr_event_generate("core.unhandled-command", cmd);
449
450
0
    pr_response_add_err(R_500, _("%s not understood"), method);
451
0
    success = -1;
452
0
  }
453
454
0
  return success;
455
0
}
456
457
/* Returns the appropriate maximum buffer size to use for FTP commands
458
 * from the client.
459
 */
460
0
static size_t get_max_cmd_sz(void) {
461
0
  size_t res;
462
0
  size_t *bufsz = NULL;
463
464
0
  bufsz = get_param_ptr(main_server->conf, "CommandBufferSize", FALSE);
465
0
  if (bufsz == NULL) {
466
0
    res = PR_DEFAULT_CMD_BUFSZ;
467
468
0
  } else {
469
0
    pr_log_debug(DEBUG1, "setting CommandBufferSize to %lu",
470
0
      (unsigned long) *bufsz);
471
0
    res = *bufsz;
472
0
  }
473
474
0
  return res;
475
0
}
476
477
0
int pr_cmd_read(cmd_rec **res) {
478
0
  static long cmd_bufsz = -1;
479
0
  static char *cmd_buf = NULL;
480
0
  int cmd_buflen;
481
0
  unsigned int too_large_count = 0;
482
0
  char *ptr;
483
484
0
  if (res == NULL) {
485
0
    errno = EINVAL;
486
0
    return -1;
487
0
  }
488
489
0
  if (cmd_bufsz == -1) {
490
0
    cmd_bufsz = get_max_cmd_sz();
491
0
  }
492
493
0
  if (cmd_buf == NULL) {
494
0
    cmd_buf = pcalloc(session.pool, cmd_bufsz + 1);
495
0
  }
496
497
0
  while (TRUE) {
498
0
    pr_signals_handle();
499
500
0
    memset(cmd_buf, '\0', cmd_bufsz);
501
502
0
    cmd_buflen = pr_netio_telnet_gets2(cmd_buf, cmd_bufsz, session.c->instrm,
503
0
      session.c->outstrm);
504
0
    if (cmd_buflen < 0) {
505
0
      if (errno == E2BIG) {
506
        /* The client sent a too-long command which was ignored; give
507
         * them a few more chances, with minor delays?
508
         */
509
0
        too_large_count++;
510
0
        pr_timer_usleep(250 * 1000);
511
512
0
        if (too_large_count > 3) {
513
0
          return -1;
514
0
        }
515
516
0
        continue;
517
0
      }
518
519
0
      if (session.c->instrm->strm_errno == 0) {
520
0
        pr_trace_msg("command", 6,
521
0
          "client sent EOF, closing control connection");
522
0
      }
523
524
0
      return -1;
525
0
    }
526
527
0
    break;
528
0
  }
529
530
  /* If the read length is less than the cmd_bufsz, then there is no need to
531
   * truncate the buffer by inserting a NUL.
532
   */
533
0
  if (cmd_buflen > cmd_bufsz) {
534
0
    pr_log_debug(DEBUG0, "truncating incoming command length (%d bytes) to "
535
0
      "CommandBufferSize %lu; use the CommandBufferSize directive to increase "
536
0
      "the allowed command length", cmd_buflen, (unsigned long) cmd_bufsz);
537
0
    cmd_buf[cmd_bufsz-1] = '\0';
538
0
  }
539
540
0
  if (cmd_buflen > 0 &&
541
0
      (cmd_buf[cmd_buflen-1] == '\n' || cmd_buf[cmd_buflen-1] == '\r')) {
542
0
    cmd_buf[cmd_buflen-1] = '\0';
543
0
    cmd_buflen--;
544
545
0
    if (cmd_buflen > 0 &&
546
0
        (cmd_buf[cmd_buflen-1] == '\n' || cmd_buf[cmd_buflen-1] =='\r')) {
547
0
      cmd_buf[cmd_buflen-1] = '\0';
548
0
      cmd_buflen--;
549
0
    }
550
0
  }
551
552
0
  ptr = cmd_buf;
553
0
  if (*ptr == '\r') {
554
0
    ptr++;
555
0
  }
556
557
0
  if (*ptr) {
558
0
    int flags = 0;
559
0
    cmd_rec *cmd;
560
561
    /* If this is a SITE command, preserve embedded whitespace in the
562
     * command parameters, in order to handle file names that have multiple
563
     * spaces in the names.  Arguably this should be handled in the SITE
564
     * command handlers themselves, via cmd->arg.  This small hack
565
     * reduces the burden on SITE module developers, however.
566
     */
567
0
    if (strncasecmp(ptr, C_SITE, 4) == 0) {
568
0
      flags |= PR_STR_FL_PRESERVE_WHITESPACE;
569
0
    }
570
571
0
    cmd = make_ftp_cmd(session.pool, ptr, cmd_buflen, flags);
572
0
    if (cmd != NULL) {
573
0
      *res = cmd;
574
575
0
      if (pr_cmd_is_http(cmd) == TRUE) {
576
0
        cmd->is_ftp = FALSE;
577
0
        cmd->protocol = "HTTP";
578
579
0
      } else if (pr_cmd_is_ssh2(cmd) == TRUE) {
580
0
        cmd->is_ftp = FALSE;
581
0
        cmd->protocol = "SSH2";
582
583
0
      } else if (pr_cmd_is_smtp(cmd) == TRUE) {
584
0
        cmd->is_ftp = FALSE;
585
0
        cmd->protocol = "SMTP";
586
587
0
      } else {
588
        /* Assume that the client is sending valid FTP commands. */
589
0
        cmd->is_ftp = TRUE;
590
0
        cmd->protocol = "FTP";
591
0
      }
592
0
    }
593
0
  }
594
595
0
  return 0;
596
0
}
597
598
0
static int set_cmd_start_ms(cmd_rec *cmd) {
599
0
  void *v;
600
0
  uint64_t start_ms;
601
602
0
  if (cmd->notes == NULL) {
603
0
    return 0;
604
0
  }
605
606
0
  v = (void *) pr_table_get(cmd->notes, "start_ms", NULL);
607
0
  if (v != NULL) {
608
0
    return 0;
609
0
  }
610
611
0
  if (pr_gettimeofday_millis(&start_ms) < 0) {
612
0
    return -1;
613
0
  }
614
615
0
  v = palloc(cmd->pool, sizeof(uint64_t));
616
0
  memcpy(v, &start_ms, sizeof(uint64_t));
617
618
0
  return pr_table_add(cmd->notes, "start_ms", v, sizeof(uint64_t));
619
0
}
620
621
0
int pr_cmd_dispatch_phase(cmd_rec *cmd, int phase, int flags) {
622
0
  char *cp = NULL;
623
0
  int success = 0, xerrno = 0;
624
0
  pool *resp_pool = NULL;
625
626
0
  if (cmd == NULL) {
627
0
    errno = EINVAL;
628
0
    return -1;
629
0
  }
630
631
0
  cmd->server = main_server;
632
633
0
  if (flags & PR_CMD_DISPATCH_FL_CLEAR_RESPONSE) {
634
    /* Skip logging the internal CONNECT/DISCONNECT commands. */
635
0
    if (!(cmd->cmd_class & CL_CONNECT) &&
636
0
        !(cmd->cmd_class & CL_DISCONNECT)) {
637
0
      pr_trace_msg("response", 9,
638
0
        "clearing response lists before dispatching command '%s'",
639
0
        (char *) cmd->argv[0]);
640
0
    }
641
0
    pr_response_clear(&resp_list);
642
0
    pr_response_clear(&resp_err_list);
643
0
  }
644
645
  /* Get any previous pool that may be being used by the Response API.
646
   *
647
   * In most cases, this will be NULL.  However, if proftpd is in the
648
   * midst of a data transfer when a command comes in on the control
649
   * connection, then the pool in use will be that of the data transfer
650
   * instigating command.  We want to stash that pool, so that after this
651
   * command is dispatched, we can return the pool of the old command.
652
   * Otherwise, Bad Things (segfaults) happen.
653
   */
654
0
  resp_pool = pr_response_get_pool();
655
656
  /* Set the pool used by the Response API for this command. */
657
0
  pr_response_set_pool(cmd->pool);
658
659
0
  for (cp = cmd->argv[0]; *cp; cp++) {
660
0
    *cp = toupper((int) *cp);
661
0
  }
662
663
0
  if (cmd->cmd_class == 0) {
664
0
    cmd->cmd_class = get_command_class(cmd->argv[0]);
665
0
  }
666
667
0
  if (cmd->cmd_id == 0) {
668
0
    cmd->cmd_id = pr_cmd_get_id(cmd->argv[0]);
669
0
  }
670
671
0
  set_cmd_start_ms(cmd);
672
673
0
  if (phase == 0) {
674
    /* First, dispatch to wildcard PRE_CMD handlers. */
675
0
    success = _dispatch(cmd, PRE_CMD, FALSE, C_ANY);
676
0
    if (success == 0) {
677
      /* No success yet?  Run other PRE_CMD phase handlers. */
678
0
      success = _dispatch(cmd, PRE_CMD, FALSE, NULL);
679
0
    }
680
681
0
    if (success < 0) {
682
      /* Dispatch to POST_CMD_ERR handlers as well. */
683
684
0
      _dispatch(cmd, POST_CMD_ERR, FALSE, C_ANY);
685
0
      _dispatch(cmd, POST_CMD_ERR, FALSE, NULL);
686
687
0
      _dispatch(cmd, LOG_CMD_ERR, FALSE, C_ANY);
688
0
      _dispatch(cmd, LOG_CMD_ERR, FALSE, NULL);
689
690
0
      xerrno = errno;
691
0
      pr_trace_msg("response", 9, "flushing error response list for '%s'",
692
0
        (char *) cmd->argv[0]);
693
0
      pr_response_flush(&resp_err_list);
694
695
      /* Restore any previous pool to the Response API. */
696
0
      pr_response_set_pool(resp_pool);
697
698
0
      errno = xerrno;
699
0
      return success;
700
0
    }
701
702
0
    success = _dispatch(cmd, CMD, FALSE, C_ANY);
703
0
    if (success == 0) {
704
0
      success = _dispatch(cmd, CMD, TRUE, NULL);
705
0
    }
706
707
0
    if (success == 1) {
708
0
      success = _dispatch(cmd, POST_CMD, FALSE, C_ANY);
709
0
      if (success == 0) {
710
0
        success = _dispatch(cmd, POST_CMD, FALSE, NULL);
711
0
      }
712
713
0
      _dispatch(cmd, LOG_CMD, FALSE, C_ANY);
714
0
      _dispatch(cmd, LOG_CMD, FALSE, NULL);
715
716
0
      xerrno = errno;
717
0
      pr_trace_msg("response", 9, "flushing response list for '%s'",
718
0
        (char *) cmd->argv[0]);
719
0
      pr_response_flush(&resp_list);
720
721
0
      errno = xerrno;
722
723
0
    } else if (success < 0) {
724
      /* Allow for non-logging command handlers to be run if CMD fails. */
725
726
0
      success = _dispatch(cmd, POST_CMD_ERR, FALSE, C_ANY);
727
0
      if (success == 0) {
728
0
        success = _dispatch(cmd, POST_CMD_ERR, FALSE, NULL);
729
0
      }
730
731
0
      _dispatch(cmd, LOG_CMD_ERR, FALSE, C_ANY);
732
0
      _dispatch(cmd, LOG_CMD_ERR, FALSE, NULL);
733
734
0
      xerrno = errno;
735
0
      pr_trace_msg("response", 9, "flushing error response list for '%s'",
736
0
        (char *) cmd->argv[0]);
737
0
      pr_response_flush(&resp_err_list);
738
739
0
      errno = xerrno;
740
0
    }
741
742
0
  } else {
743
0
    switch (phase) {
744
0
      case PRE_CMD:
745
0
      case POST_CMD:
746
0
      case POST_CMD_ERR:
747
0
        success = _dispatch(cmd, phase, FALSE, C_ANY);
748
0
        if (success == 0) {
749
0
          success = _dispatch(cmd, phase, FALSE, NULL);
750
0
          xerrno = errno;
751
0
        }
752
0
        break;
753
754
0
      case CMD:
755
0
        success = _dispatch(cmd, phase, FALSE, C_ANY);
756
0
        if (success == 0) {
757
0
          success = _dispatch(cmd, phase, TRUE, NULL);
758
0
        }
759
0
        break;
760
761
0
      case LOG_CMD:
762
0
      case LOG_CMD_ERR:
763
0
        (void) _dispatch(cmd, phase, FALSE, C_ANY);
764
0
        (void) _dispatch(cmd, phase, FALSE, NULL);
765
0
        break;
766
767
0
      default:
768
        /* Restore any previous pool to the Response API. */
769
0
        pr_response_set_pool(resp_pool);
770
771
0
        errno = EINVAL;
772
0
        return -1;
773
0
    }
774
775
0
    if (flags & PR_CMD_DISPATCH_FL_SEND_RESPONSE) {
776
0
      xerrno = errno;
777
778
0
      if (success == 1) {
779
0
        pr_trace_msg("response", 9, "flushing response list for '%s'",
780
0
          (char *) cmd->argv[0]);
781
0
        pr_response_flush(&resp_list);
782
783
0
      } else if (success < 0) {
784
0
        pr_trace_msg("response", 9, "flushing error response list for '%s'",
785
0
          (char *) cmd->argv[0]);
786
0
        pr_response_flush(&resp_err_list);
787
0
      }
788
789
0
      errno = xerrno;
790
0
    }
791
0
  }
792
793
  /* Restore any previous pool to the Response API. */
794
0
  pr_response_set_pool(resp_pool);
795
796
0
  errno = xerrno;
797
0
  return success;
798
0
}
799
800
0
int pr_cmd_dispatch(cmd_rec *cmd) {
801
0
  return pr_cmd_dispatch_phase(cmd, 0,
802
0
    PR_CMD_DISPATCH_FL_SEND_RESPONSE|PR_CMD_DISPATCH_FL_CLEAR_RESPONSE);
803
0
}
804
805
0
static cmd_rec *make_ftp_cmd(pool *p, char *buf, size_t buflen, int flags) {
806
0
  register unsigned int i, j;
807
0
  char *arg, *ptr, *wrd;
808
0
  size_t arg_len;
809
0
  cmd_rec *cmd;
810
0
  pool *subpool;
811
0
  array_header *tarr;
812
0
  int have_crnul = FALSE, str_flags = PR_STR_FL_PRESERVE_COMMENTS|flags;
813
814
  /* Be pedantic (and RFC-compliant) by not allowing leading whitespace
815
   * in an issued FTP command.  Will this cause troubles with many clients?
816
   */
817
0
  if (PR_ISSPACE(buf[0])) {
818
0
    pr_trace_msg("ctrl", 5,
819
0
      "command '%s' has illegal leading whitespace, rejecting", buf);
820
0
    errno = EINVAL;
821
0
    return NULL;
822
0
  }
823
824
  /* By default, pr_str_get_word will handle quotes and backslashes for
825
   * escaping characters.  This can produce words which are shorter, use
826
   * fewer bytes than the corresponding input buffer.
827
   *
828
   * In this particular situation, we use the length of this initial word
829
   * for determining the length of the remaining buffer bytes, assumed to
830
   * contain the FTP command arguments.  If this initial word is thus
831
   * unexpectedly "shorter", due to nonconformant FTP text, it can lead
832
   * the subsequent buffer scan, looking for CRNUL sequencees, to access
833
   * unexpected memory addresses (Issue #1683).
834
   *
835
   * Thus for this particular situation, we tell the function to ignore/skip
836
   * such quote/backslash semantics, and treat them as any other character
837
   * using the IGNORE_QUOTES flag.
838
   */
839
840
0
  ptr = buf;
841
0
  wrd = pr_str_get_word(&ptr, str_flags|PR_STR_FL_IGNORE_QUOTES);
842
0
  if (wrd == NULL) {
843
    /* Nothing there...bail out. */
844
0
    pr_trace_msg("ctrl", 5, "command '%s' is empty, ignoring", buf);
845
0
    errno = ENOENT;
846
0
    return NULL;
847
0
  }
848
849
  /* Note that this first word is the FTP command.  This is why we make
850
   * use of the ptr buffer, which advances through the input buffer as
851
   * we read words from the buffer.
852
   */
853
854
0
  subpool = make_sub_pool(p);
855
0
  pr_pool_tag(subpool, "make_ftp_cmd pool");
856
0
  cmd = pcalloc(subpool, sizeof(cmd_rec));
857
0
  cmd->pool = subpool;
858
0
  cmd->tmp_pool = NULL;
859
0
  cmd->stash_index = -1;
860
0
  cmd->stash_hash = 0;
861
862
0
  tarr = make_array(cmd->pool, 2, sizeof(char *));
863
864
0
  *((char **) push_array(tarr)) = pstrdup(cmd->pool, wrd);
865
0
  cmd->argc++;
866
867
  /* Make a copy of the command argument; we need to scan through it,
868
   * looking for any CR+NUL sequences, per RFC 2640, Section 3.1.
869
   *
870
   * Note for future readers that this scanning may cause problems for
871
   * commands such as ADAT, ENC, and MIC.  Per RFC 2228, the arguments for
872
   * these commands are base64-encoded Telnet strings, thus there is no
873
   * chance of them containing CRNUL sequences.  Any modules which implement
874
   * the translating of those arguments, e.g. mod_gss, will need to ensure
875
   * it does the proper handling of CRNUL sequences itself.
876
   */
877
0
  arg_len = buflen - strlen(wrd);
878
0
  arg = pcalloc(cmd->pool, arg_len + 1);
879
880
  /* Remember that ptr here is advanced past the first word. */
881
0
  for (i = 0, j = 0; i < arg_len; i++) {
882
0
    pr_signals_handle();
883
0
    if (i > 1 &&
884
0
        ptr[i] == '\0' &&
885
0
        ptr[i-1] == '\r') {
886
887
      /* Strip out the NUL by simply not copying it into the new buffer. */
888
0
      have_crnul = TRUE;
889
890
0
    } else {
891
0
      arg[j++] = ptr[i];
892
0
    }
893
0
  }
894
895
0
  if (have_crnul == TRUE) {
896
0
    char *dup_arg;
897
898
    /* Now make a copy of the stripped argument; this is what we need to
899
     * tokenize into words, for further command dispatching/processing.
900
     */
901
0
    dup_arg = pstrdup(cmd->pool, arg);
902
0
    ptr = dup_arg;
903
0
  }
904
905
0
  cmd->arg = arg;
906
907
  /* Now we can read the remamining words, as command arguments, from the
908
   * input buffer.
909
   */
910
0
  while ((wrd = pr_str_get_word(&ptr, str_flags)) != NULL) {
911
0
    pr_signals_handle();
912
0
    *((char **) push_array(tarr)) = pstrdup(cmd->pool, wrd);
913
0
    cmd->argc++;
914
0
  }
915
916
0
  *((char **) push_array(tarr)) = NULL;
917
0
  cmd->argv = tarr->elts;
918
0
  pr_pool_tag(cmd->pool, cmd->argv[0]);
919
920
  /* This table will not contain that many entries, so a low number
921
   * of chains should suffice.
922
   */
923
0
  cmd->notes = pr_table_nalloc(cmd->pool, 0, 8);
924
925
0
  return cmd;
926
0
}
927
928
0
static void cmd_loop(server_rec *server, conn_t *c) {
929
930
0
  while (TRUE) {
931
0
    int res = 0;
932
0
    cmd_rec *cmd = NULL;
933
934
0
    pr_signals_handle();
935
936
0
    res = pr_cmd_read(&cmd);
937
0
    if (res < 0) {
938
0
      if (PR_NETIO_ERRNO(session.c->instrm) == EINTR) {
939
        /* Simple interrupted syscall */
940
0
        continue;
941
0
      }
942
943
0
#ifndef PR_DEVEL_NO_DAEMON
944
      /* Otherwise, EOF */
945
0
      pr_session_disconnect(NULL, PR_SESS_DISCONNECT_CLIENT_EOF, NULL);
946
#else
947
      return;
948
#endif /* PR_DEVEL_NO_DAEMON */
949
0
    }
950
951
    /* Data received, reset idle timer */
952
0
    if (pr_data_get_timeout(PR_DATA_TIMEOUT_IDLE) > 0) {
953
0
      pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE);
954
0
    }
955
956
0
    if (cmd != NULL) {
957
      /* Detect known commands for other protocols; if found, drop the
958
       * connection, lest we be used as part of an attack on a different
959
       * protocol server (Bug#4143).
960
       */
961
0
      if (cmd->is_ftp == FALSE) {
962
0
        pr_log_pri(PR_LOG_WARNING,
963
0
          "client sent %s command '%s', disconnecting", cmd->protocol,
964
0
          (char *) cmd->argv[0]);
965
0
        pr_event_generate("core.bad-protocol", cmd);
966
0
        pr_session_disconnect(NULL, PR_SESS_DISCONNECT_BAD_PROTOCOL,
967
0
          cmd->protocol);
968
0
      }
969
970
0
      pr_cmd_dispatch(cmd);
971
0
      destroy_pool(cmd->pool);
972
0
      session.curr_cmd = NULL;
973
0
      session.curr_cmd_id = 0;
974
0
      session.curr_cmd_rec = NULL;
975
976
0
    } else {
977
0
      pr_event_generate("core.invalid-command", NULL);
978
0
      pr_response_send(R_500, _("Invalid command: try being more creative"));
979
0
    }
980
981
    /* Release any working memory allocated in inet */
982
0
    pr_inet_clear();
983
0
  }
984
0
}
985
986
0
void restart_daemon(void *d1, void *d2, void *d3, void *d4) {
987
0
  int maxfd, res, xerrno;
988
0
  fd_set childfds;
989
0
  struct timeval restart_start, restart_finish;
990
0
  long restart_elapsed = 0;
991
992
0
  if (is_master == FALSE ||
993
0
      !mpid) {
994
    /* Child process -- cannot restart, log error */
995
0
    pr_log_pri(PR_LOG_ERR, "received SIGHUP, cannot restart child process");
996
0
    return;
997
0
  }
998
999
0
  pr_log_pri(PR_LOG_NOTICE,
1000
0
    "received SIGHUP -- master server reparsing configuration file");
1001
1002
0
  gettimeofday(&restart_start, NULL);
1003
1004
  /* Make sure none of our children haven't completed start up */
1005
0
  FD_ZERO(&childfds);
1006
0
  maxfd = -1;
1007
1008
0
  maxfd = semaphore_fds(&childfds, maxfd);
1009
0
  if (maxfd > -1) {
1010
0
    pr_log_pri(PR_LOG_NOTICE, "waiting for child processes to complete "
1011
0
      "initialization");
1012
1013
0
    while (maxfd != -1) {
1014
0
      int i;
1015
1016
0
      i = select(maxfd + 1, &childfds, NULL, NULL, NULL);
1017
0
      if (i > 0) {
1018
0
        pr_child_t *ch;
1019
1020
0
        for (ch = child_get(NULL); ch; ch = child_get(ch)) {
1021
0
          if (ch->ch_pipefd != -1 &&
1022
0
             FD_ISSET(ch->ch_pipefd, &childfds)) {
1023
0
            (void) close(ch->ch_pipefd);
1024
0
            ch->ch_pipefd = -1;
1025
0
          }
1026
0
        }
1027
0
      }
1028
1029
0
      FD_ZERO(&childfds);
1030
0
      maxfd = -1;
1031
0
      maxfd = semaphore_fds(&childfds, maxfd);
1032
0
    }
1033
0
  }
1034
1035
0
  free_bindings();
1036
1037
  /* Run through the list of registered restart callbacks. */
1038
0
  pr_event_generate("core.restart", NULL);
1039
1040
0
  init_log();
1041
0
  init_netaddr();
1042
0
  init_class();
1043
0
  init_config();
1044
0
  init_dirtree();
1045
1046
#ifdef PR_USE_NLS
1047
  encode_free();
1048
#endif /* PR_USE_NLS */
1049
1050
0
  pr_netaddr_clear_cache();
1051
0
  pr_parser_prepare(NULL, NULL);
1052
0
  pr_event_generate("core.preparse", NULL);
1053
1054
0
  PRIVS_ROOT
1055
0
  res = pr_parser_parse_file(NULL, config_filename, NULL, 0);
1056
0
  xerrno = errno;
1057
0
  PRIVS_RELINQUISH
1058
1059
0
  if (res < 0) {
1060
    /* Note: EPERM is used to indicate the presence of unrecognized
1061
     * configuration directives in the parsed file(s).
1062
     */
1063
0
    if (xerrno != EPERM) {
1064
0
      pr_log_pri(PR_LOG_WARNING,
1065
0
        "fatal: unable to read configuration file '%s': %s", config_filename,
1066
0
        strerror(xerrno));
1067
0
    }
1068
1069
0
    pr_session_end(0);
1070
0
  }
1071
1072
0
  if (pr_parser_cleanup() < 0) {
1073
0
    pr_log_pri(PR_LOG_WARNING,
1074
0
      "fatal: error processing configuration file '%s': "
1075
0
      "unclosed configuration section", config_filename);
1076
0
    pr_session_end(0);
1077
0
  }
1078
1079
#ifdef PR_USE_NLS
1080
  encode_init();
1081
#endif /* PR_USE_NLS */
1082
1083
  /* After configuration is complete, make sure that passwd, group
1084
   * aren't held open (unnecessary fds for master daemon)
1085
   */
1086
0
  endpwent();
1087
0
  endgrent();
1088
1089
0
  if (fixup_servers(server_list) < 0) {
1090
0
    pr_log_pri(PR_LOG_WARNING,
1091
0
      "fatal: error processing configuration file '%s'", config_filename);
1092
0
    pr_session_end(0);
1093
0
  }
1094
1095
0
  pr_event_generate("core.postparse", NULL);
1096
1097
  /* Recreate the listen connection.  Can an inetd-spawned server accept
1098
   * and process HUP?
1099
   */
1100
0
  init_bindings();
1101
1102
0
  gettimeofday(&restart_finish, NULL);
1103
1104
0
  restart_elapsed = ((restart_finish.tv_sec - restart_start.tv_sec) * 1000L) +
1105
0
    ((restart_finish.tv_usec - restart_start.tv_usec) / 1000L);
1106
0
  pr_trace_msg("config", 12, "restart took %ld millisecs", restart_elapsed);
1107
0
}
1108
1109
0
static void set_server_privs(void) {
1110
0
  uid_t *uid, server_uid, current_euid;
1111
0
  gid_t *gid, server_gid, current_egid;
1112
0
  unsigned char switch_server_id = FALSE;
1113
1114
0
  current_euid = geteuid();
1115
0
  current_egid = getegid();
1116
1117
0
  uid = get_param_ptr(main_server->conf, "UserID", FALSE);
1118
0
  if (uid != NULL) {
1119
0
    server_uid = *uid;
1120
0
    switch_server_id = TRUE;
1121
1122
0
  } else {
1123
0
    server_uid = current_euid;
1124
0
  }
1125
1126
0
  gid =  get_param_ptr(main_server->conf, "GroupID", FALSE);
1127
0
  if (gid != NULL) {
1128
0
    server_gid = *gid;
1129
0
    switch_server_id = TRUE;
1130
1131
0
  } else {
1132
0
    server_gid = current_egid;
1133
0
  }
1134
1135
0
  if (switch_server_id) {
1136
0
    PRIVS_ROOT
1137
1138
    /* Note: will it be necessary to double check this switch, as is done
1139
     * in elsewhere in this file?
1140
     */
1141
0
    PRIVS_SETUP(server_uid, server_gid);
1142
0
  }
1143
0
}
1144
1145
0
static void fork_server(int fd, conn_t *l, unsigned char no_fork) {
1146
0
  conn_t *conn = NULL;
1147
0
  int i, rev;
1148
0
  int semfds[2] = { -1, -1 };
1149
0
  int xerrno = 0;
1150
1151
0
#ifndef PR_DEVEL_NO_FORK
1152
0
  pid_t pid;
1153
0
  sigset_t sig_set;
1154
1155
0
  if (no_fork == FALSE) {
1156
1157
    /* A race condition exists on heavily loaded servers where the parent
1158
     * catches SIGHUP and attempts to close/re-open the main listening
1159
     * socket(s), however the children haven't finished closing them
1160
     * (EADDRINUSE).  We use a semaphore pipe here to flag the parent once
1161
     * the child has closed all former listening sockets.
1162
     */
1163
1164
0
    if (pipe(semfds) == -1) {
1165
0
      pr_log_pri(PR_LOG_ALERT, "pipe(2) failed: %s", strerror(errno));
1166
0
      (void) close(fd);
1167
0
      return;
1168
0
    }
1169
1170
    /* Need to make sure the child (writer) end of the pipe isn't
1171
     * < 2 (stdio/stdout/stderr) as this will cause problems later.
1172
     */
1173
0
    semfds[1] = pr_fs_get_usable_fd(semfds[1]);
1174
1175
    /* Make sure we set the close-on-exec flag for the parent's read side
1176
     * of the pipe.
1177
     */
1178
0
    (void) fcntl(semfds[0], F_SETFD, FD_CLOEXEC);
1179
1180
    /* We block SIGCHLD to prevent a race condition if the child
1181
     * dies before we can record it's pid.  Also block SIGTERM to
1182
     * prevent sig_terminate() from examining the child list
1183
     */
1184
1185
0
    sigemptyset(&sig_set);
1186
0
    sigaddset(&sig_set, SIGTERM);
1187
0
    sigaddset(&sig_set, SIGCHLD);
1188
0
    sigaddset(&sig_set, SIGUSR1);
1189
0
    sigaddset(&sig_set, SIGUSR2);
1190
1191
0
    if (sigprocmask(SIG_BLOCK, &sig_set, NULL) < 0) {
1192
0
      pr_log_pri(PR_LOG_NOTICE,
1193
0
        "unable to block signal set: %s", strerror(errno));
1194
0
    }
1195
1196
0
    pid = fork();
1197
0
    xerrno = errno;
1198
1199
0
    switch (pid) {
1200
1201
0
    case 0: /* child */
1202
      /* No longer the master process. */
1203
0
      is_master = FALSE;
1204
0
      if (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {
1205
0
        pr_log_pri(PR_LOG_NOTICE,
1206
0
          "unable to unblock signal set: %s", strerror(errno));
1207
0
      }
1208
1209
      /* No longer need the read side of the semaphore pipe. */
1210
0
      (void) close(semfds[0]);
1211
0
      break;
1212
1213
0
    case -1:
1214
0
      if (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {
1215
0
        pr_log_pri(PR_LOG_NOTICE,
1216
0
          "unable to unblock signal set: %s", strerror(errno));
1217
0
      }
1218
1219
0
      pr_log_pri(PR_LOG_ALERT, "unable to fork(): %s", strerror(xerrno));
1220
1221
      /* The parent doesn't need the socket open. */
1222
0
      (void) close(fd);
1223
0
      (void) close(semfds[0]);
1224
0
      (void) close(semfds[1]);
1225
1226
0
      return;
1227
1228
0
    default: /* parent */
1229
      /* The parent doesn't need the socket open */
1230
0
      (void) close(fd);
1231
1232
0
      child_add(pid, semfds[0]);
1233
0
      (void) close(semfds[1]);
1234
1235
      /* Unblock the signals now as sig_child() will catch
1236
       * an "immediate" death and remove the pid from the children list
1237
       */
1238
0
      if (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {
1239
0
        pr_log_pri(PR_LOG_NOTICE,
1240
0
          "unable to unblock signal set: %s", strerror(errno));
1241
0
      }
1242
1243
0
      return;
1244
0
    }
1245
0
  }
1246
1247
0
  session.pid = getpid();
1248
1249
  /* No longer need any listening fds. */
1250
0
  pr_ipbind_close_listeners();
1251
1252
  /* There would appear to be no useful purpose behind setting the process
1253
   * group of the newly forked child.  In daemon/inetd mode, we should have no
1254
   * controlling tty and either have the process group of the parent or of
1255
   * inetd.  In non-daemon mode (-n), doing this may cause SIGTTOU to be
1256
   * raised on output to the terminal (stderr logging).
1257
   *
1258
   * #ifdef HAVE_SETPGID
1259
   *   setpgid(0,getpid());
1260
   * #else
1261
   * # ifdef SETPGRP_VOID
1262
   *   setpgrp();
1263
   * # else
1264
   *   setpgrp(0,getpid());
1265
   * # endif
1266
   * #endif
1267
   *
1268
   */
1269
1270
  /* Reseed pseudo-randoms */
1271
0
  pr_random_init();
1272
1273
0
#endif /* PR_DEVEL_NO_FORK */
1274
1275
  /* Child is running here */
1276
0
  if (signal(SIGUSR1, pr_signals_handle_disconnect) == SIG_ERR) {
1277
0
    pr_log_pri(PR_LOG_NOTICE,
1278
0
      "unable to install SIGUSR1 (signal %d) handler: %s", SIGUSR1,
1279
0
      strerror(errno));
1280
0
  }
1281
1282
0
  if (signal(SIGUSR2, pr_signals_handle_event) == SIG_ERR) {
1283
0
    pr_log_pri(PR_LOG_NOTICE,
1284
0
      "unable to install SIGUSR2 (signal %d) handler: %s", SIGUSR2,
1285
0
      strerror(errno));
1286
0
  }
1287
1288
0
  if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
1289
0
    pr_log_pri(PR_LOG_NOTICE,
1290
0
      "unable to install SIGCHLD (signal %d) handler: %s", SIGCHLD,
1291
0
      strerror(errno));
1292
0
  }
1293
1294
0
  if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
1295
0
    pr_log_pri(PR_LOG_NOTICE,
1296
0
      "unable to install SIGHUP (signal %d) handler: %s", SIGHUP,
1297
0
      strerror(errno));
1298
0
  }
1299
1300
  /* From this point on, syslog stays open. We close it first so that the
1301
   * logger will pick up our new PID.
1302
   *
1303
   * We have to delay calling log_opensyslog() until after pr_inet_openrw()
1304
   * is called, otherwise the potential exists for the syslog FD to
1305
   * be overwritten and the user to see logging information.
1306
   *
1307
   * This isn't that big of a deal because the logging functions will
1308
   * just open it dynamically if they need to.
1309
   */
1310
0
  log_closesyslog();
1311
1312
  /* Specifically DO NOT perform reverse DNS at this point, to alleviate
1313
   * the race condition mentioned above.  Instead we do it after closing
1314
   * all former listening sockets.
1315
   */
1316
0
  conn = pr_inet_openrw(permanent_pool, l, NULL, PR_NETIO_STRM_CTRL, fd,
1317
0
    STDIN_FILENO, STDOUT_FILENO, FALSE);
1318
1319
  /* Capture errno here, if necessary. */
1320
0
  if (conn == NULL) {
1321
0
    xerrno = errno;
1322
0
  }
1323
1324
  /* Now do the permanent syslog open
1325
   */
1326
0
  pr_signals_block();
1327
0
  PRIVS_ROOT
1328
1329
0
  log_opensyslog(NULL);
1330
1331
0
  PRIVS_RELINQUISH
1332
0
  pr_signals_unblock();
1333
1334
0
  if (conn == NULL) {
1335
    /* There are some errors, e.g. ENOTCONN ("Transport endpoint is not
1336
     * connected") which can easily happen, as during scans/TCP
1337
     * probes/healthchecks, commonly done by load balancers, firewalls, and
1338
     * other clients.  By the time proftpd reaches the point of looking up
1339
     * the peer data for that connection, the client has disconnected.
1340
     *
1341
     * These are normal errors, and thus should not be logged as fatal
1342
     * conditions.
1343
     */
1344
0
    if (xerrno == ENOTCONN ||
1345
0
        xerrno == ECONNABORTED ||
1346
0
        xerrno == ECONNRESET) {
1347
0
      pr_log_pri(PR_LOG_DEBUG, "unable to open incoming connection: %s",
1348
0
        strerror(xerrno));
1349
1350
0
    } else {
1351
0
      pr_log_pri(PR_LOG_ERR, "fatal: unable to open incoming connection: %s",
1352
0
        strerror(xerrno));
1353
0
    }
1354
1355
0
    exit(1);
1356
0
  }
1357
1358
0
  pr_gettimeofday_millis(&session.connect_time_ms);
1359
0
  pr_event_generate("core.connect", conn);
1360
1361
  /* Find the server for this connection. */
1362
0
  main_server = pr_ipbind_get_server(conn->local_addr, conn->local_port);
1363
1364
  /* Make sure we allocate a session pool, even if this connection will
1365
   * dropped soon.
1366
   */
1367
0
  session.pool = make_sub_pool(permanent_pool);
1368
0
  pr_pool_tag(session.pool, "Session Pool");
1369
1370
0
  session.c = conn;
1371
0
  session.data_port = conn->remote_port - 1;
1372
0
  session.sf_flags = 0;
1373
0
  session.sp_flags = 0;
1374
0
  session.proc_prefix = "(connecting)";
1375
1376
  /* If no server is configured to handle the addr the user is connected to,
1377
   * drop them.
1378
   */
1379
0
  if (main_server == NULL) {
1380
0
    pr_log_debug(DEBUG2, "No server configuration found for IP address %s",
1381
0
      pr_netaddr_get_ipstr(conn->local_addr));
1382
0
    pr_log_debug(DEBUG2, "Use the DefaultServer directive to designate "
1383
0
      "a default server configuration to handle requests like this");
1384
1385
0
    pr_response_send(R_500,
1386
0
      _("Sorry, no server available to handle request on %s"),
1387
0
      pr_netaddr_get_dnsstr(conn->local_addr));
1388
0
    exit(0);
1389
0
  }
1390
1391
0
  pr_inet_set_proto_opts(permanent_pool, conn, 0, 1, IPTOS_LOWDELAY, 0);
1392
1393
  /* Close the write side of the semaphore pipe to tell the parent
1394
   * we are all grown up and have finished housekeeping (closing
1395
   * former listen sockets).
1396
   */
1397
0
  (void) close(semfds[1]);
1398
1399
  /* Now perform reverse DNS lookups. */
1400
0
  if (ServerUseReverseDNS) {
1401
0
    rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS);
1402
1403
0
    if (conn->remote_addr) {
1404
0
      conn->remote_name = pr_netaddr_get_dnsstr(conn->remote_addr);
1405
0
    }
1406
1407
0
    pr_netaddr_set_reverse_dns(rev);
1408
0
  }
1409
1410
0
  pr_netaddr_set_sess_addrs();
1411
1412
  /* Check and see if we are shutting down. */
1413
0
  if (shutting_down == TRUE) {
1414
0
    time_t now;
1415
1416
0
    time(&now);
1417
0
    if (!deny || deny <= now) {
1418
0
      pool *tmp_pool;
1419
0
      config_rec *c = NULL;
1420
0
      const char *reason = NULL, *serveraddress;
1421
1422
0
      serveraddress = (session.c && session.c->local_addr) ?
1423
0
        pr_netaddr_get_ipstr(session.c->local_addr) :
1424
0
        main_server->ServerAddress;
1425
1426
0
      c = find_config(main_server->conf, CONF_PARAM, "MasqueradeAddress",
1427
0
        FALSE);
1428
0
      if (c != NULL) {
1429
0
        pr_netaddr_t *masq_addr = NULL;
1430
1431
0
        if (c->argv[0] != NULL) {
1432
0
          masq_addr = c->argv[0];
1433
0
        }
1434
1435
0
        if (masq_addr != NULL) {
1436
0
          serveraddress = pr_netaddr_get_ipstr(masq_addr);
1437
0
        }
1438
0
      }
1439
1440
0
      tmp_pool = make_sub_pool(permanent_pool);
1441
0
      pr_pool_tag(tmp_pool, "shutmsg check pool");
1442
1443
0
      reason = sreplace(tmp_pool, shutmsg,
1444
0
                   "%s", pstrdup(tmp_pool, pr_strtime3(tmp_pool, shut, FALSE)),
1445
0
                   "%r", pstrdup(tmp_pool, pr_strtime3(tmp_pool, deny, FALSE)),
1446
0
                   "%d", pstrdup(tmp_pool, pr_strtime3(tmp_pool, disc, FALSE)),
1447
0
       "%C", (session.cwd[0] ? session.cwd : "(none)"),
1448
0
       "%L", serveraddress,
1449
0
       "%R", (session.c && session.c->remote_name ?
1450
0
                         session.c->remote_name : "(unknown)"),
1451
0
       "%T", pstrdup(tmp_pool, pr_strtime3(tmp_pool, now, FALSE)),
1452
0
       "%U", "NONE",
1453
0
       "%V", main_server->ServerName,
1454
0
                   NULL );
1455
1456
0
      pr_log_auth(PR_LOG_NOTICE, "connection refused (%s) from %s [%s]",
1457
0
        reason, session.c->remote_name,
1458
0
        pr_netaddr_get_ipstr(session.c->remote_addr));
1459
0
      pr_response_send(R_500,
1460
0
        _("FTP server shut down (%s) -- please try again later"), reason);
1461
1462
0
      destroy_pool(tmp_pool);
1463
0
      exit(0);
1464
0
    }
1465
0
  }
1466
1467
0
  if (main_server->listen) {
1468
0
    if (main_server->listen->listen_fd == conn->rfd ||
1469
0
        main_server->listen->listen_fd == conn->wfd) {
1470
0
      main_server->listen->listen_fd = -1;
1471
0
    }
1472
1473
0
    main_server->listen = NULL;
1474
0
  }
1475
1476
  /* Set the ID/privs for the User/Group in this server */
1477
0
  set_server_privs();
1478
1479
  /* Find the class for this session. */
1480
0
  session.conn_class = pr_class_match_addr(session.c->remote_addr);
1481
0
  if (session.conn_class != NULL) {
1482
0
    pr_log_debug(DEBUG2, "session requested from client in '%s' class",
1483
0
      session.conn_class->cls_name);
1484
1485
0
  } else {
1486
0
    pr_log_debug(DEBUG5, "session requested from client in unknown class");
1487
0
  }
1488
1489
  /* Check config tree for <Limit LOGIN> directives.  Do not perform
1490
   * this check until after the class of the session has been determined,
1491
   * in order to properly handle any AllowClass/DenyClass directives
1492
   * within the <Limit> section.
1493
   */
1494
0
  if (!login_check_limits(main_server->conf, TRUE, FALSE, &i)) {
1495
0
    pr_log_pri(PR_LOG_NOTICE, "Connection from %s [%s] denied",
1496
0
      session.c->remote_name,
1497
0
      pr_netaddr_get_ipstr(session.c->remote_addr));
1498
1499
    /* XXX Send DisplayConnect here? No chroot to worry about; modules have
1500
     * NOT been initialized, so generating an event would not work as
1501
     * expected.
1502
     */
1503
1504
0
    pr_session_disconnect(NULL, PR_SESS_DISCONNECT_CONFIG_ACL,
1505
0
      "Blocked by <Limit LOGIN>");
1506
0
  }
1507
1508
  /* Create a table for modules to use. */
1509
0
  session.notes = pr_table_alloc(session.pool, 0);
1510
0
  if (session.notes == NULL) {
1511
0
    pr_log_debug(DEBUG3, "error creating session.notes table: %s",
1512
0
      strerror(errno));
1513
0
  }
1514
1515
  /* Prepare the Timers API. */
1516
0
  timers_init();
1517
1518
  /* Inform all the modules that we are now a child */
1519
0
  pr_log_debug(DEBUG7, "performing module session initializations");
1520
0
  if (modules_session_init() < 0) {
1521
0
    pr_session_disconnect(NULL, PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
1522
0
  }
1523
1524
0
  pr_event_generate("core.connected", conn);
1525
1526
0
  pr_log_debug(DEBUG4, "connected - local  : %s:%d",
1527
0
    pr_netaddr_get_ipstr(session.c->local_addr), session.c->local_port);
1528
0
  pr_log_debug(DEBUG4, "connected - remote : %s:%d",
1529
0
    pr_netaddr_get_ipstr(session.c->remote_addr), session.c->remote_port);
1530
1531
0
  pr_proctitle_set("connected: %s (%s:%d)",
1532
0
    session.c->remote_name ? session.c->remote_name : "?",
1533
0
    session.c->remote_addr ? pr_netaddr_get_ipstr(session.c->remote_addr) : "?",
1534
0
    session.c->remote_port ? session.c->remote_port : 0);
1535
1536
0
  pr_log_pri(PR_LOG_INFO, "%s session opened.",
1537
0
    pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT));
1538
1539
  /* Make sure we can receive OOB data */
1540
0
  pr_inet_set_async(session.pool, session.c);
1541
1542
0
  pr_session_send_banner(main_server,
1543
0
    PR_DISPLAY_FL_NO_EOM|PR_DISPLAY_FL_SEND_NOW);
1544
1545
0
  cmd_handler(main_server, conn);
1546
1547
#ifdef PR_DEVEL_NO_DAEMON
1548
  /* Cleanup */
1549
  pr_session_end(PR_SESS_END_FL_NOEXIT);
1550
  main_server = NULL;
1551
  free_pools();
1552
  pr_proctitle_free();
1553
#endif /* PR_DEVEL_NO_DAEMON */
1554
0
}
1555
1556
0
static void disc_children(void) {
1557
1558
0
  if (disc && disc <= time(NULL) && child_count()) {
1559
0
    sigset_t sig_set;
1560
1561
0
    sigemptyset(&sig_set);
1562
0
    sigaddset(&sig_set, SIGTERM);
1563
0
    sigaddset(&sig_set, SIGCHLD);
1564
0
    sigaddset(&sig_set, SIGUSR1);
1565
0
    sigaddset(&sig_set, SIGUSR2);
1566
1567
0
    if (sigprocmask(SIG_BLOCK, &sig_set, NULL) < 0) {
1568
0
      pr_log_pri(PR_LOG_NOTICE,
1569
0
        "unable to block signal set: %s", strerror(errno));
1570
0
    }
1571
1572
0
    PRIVS_ROOT
1573
0
    child_signal(SIGUSR1);
1574
0
    PRIVS_RELINQUISH
1575
1576
0
    if (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {
1577
0
      pr_log_pri(PR_LOG_NOTICE,
1578
0
        "unable to unblock signal set: %s", strerror(errno));
1579
0
    }
1580
0
  }
1581
0
}
1582
1583
0
static void daemon_loop(void) {
1584
0
  static int running = 0;
1585
0
  fd_set listenfds;
1586
0
  conn_t *listen_conn;
1587
0
  int i, err_count = 0, fd, xerrno = 0;
1588
0
  unsigned long nconnects = 0UL;
1589
0
  time_t last_error;
1590
0
  struct timeval tv;
1591
1592
0
  pr_proctitle_set("(accepting connections)");
1593
1594
0
  time(&last_error);
1595
1596
0
  while (TRUE) {
1597
0
    int maxfd, res;
1598
1599
0
    run_schedule();
1600
1601
0
    FD_ZERO(&listenfds);
1602
0
    maxfd = pr_ipbind_listen(&listenfds);
1603
1604
    /* Monitor children pipes */
1605
0
    maxfd = semaphore_fds(&listenfds, maxfd);
1606
1607
    /* Check for ftp shutdown message file */
1608
0
    res = check_shutmsg(permanent_pool, PR_SHUTMSG_PATH, &shut, &deny, &disc,
1609
0
      shutmsg, sizeof(shutmsg));
1610
0
    if (res == 1) {
1611
0
      if (shutting_down == FALSE) {
1612
0
        disc_children();
1613
0
      }
1614
0
      shutting_down = TRUE;
1615
1616
0
    } else {
1617
0
      shutting_down = FALSE;
1618
0
      deny = disc = (time_t) 0;
1619
0
    }
1620
1621
0
    if (shutting_down == TRUE) {
1622
0
      tv.tv_sec = 5L;
1623
0
      tv.tv_usec = 0L;
1624
1625
0
    } else {
1626
0
      tv.tv_sec = PR_TUNABLE_SELECT_TIMEOUT;
1627
0
      tv.tv_usec = 0L;
1628
0
    }
1629
1630
    /* If running (a flag signaling whether proftpd is just starting up)
1631
     * AND shutting_down (a flag signalling the present of /etc/shutmsg) are
1632
     * true, then log an error stating this -- but don't stop the server.
1633
     */
1634
0
    if (shutting_down == TRUE &&
1635
0
        !running) {
1636
1637
      /* Check the value of the deny time_t struct w/ the current time.
1638
       * If the deny time has passed, log that all incoming connections
1639
       * will be refused.  If not, note the date at which they will be
1640
       * refused in the future.
1641
       */
1642
0
      time_t now = time(NULL);
1643
1644
0
      if (difftime(deny, now) < 0.0) {
1645
0
        pr_log_pri(PR_LOG_WARNING, PR_SHUTMSG_PATH
1646
0
          " present: all incoming connections will be refused");
1647
1648
0
      } else {
1649
0
#if defined(HAVE_CTIME_R)
1650
0
        char deny_ts[32];
1651
1652
0
        memset(deny_ts, '\0', sizeof(deny_ts));
1653
0
        (void) ctime_r(&deny, deny_ts);
1654
#else
1655
        char *deny_ts = NULL;
1656
        deny_ts = ctime(&deny);
1657
#endif /* HAVE_CTIME_R */
1658
1659
0
        pr_log_pri(PR_LOG_NOTICE,
1660
0
          PR_SHUTMSG_PATH " present: incoming connections "
1661
0
          "will be denied starting %s", CHOP(deny_ts));
1662
0
      }
1663
0
    }
1664
1665
0
    running = 1;
1666
0
    xerrno = errno = 0;
1667
1668
0
    PR_DEVEL_CLOCK(i = select(maxfd + 1, &listenfds, NULL, NULL, &tv));
1669
0
    xerrno = errno;
1670
1671
0
    if (i < 0 &&
1672
0
        xerrno == EINTR) {
1673
0
      errno = xerrno;
1674
0
      pr_signals_handle_without_delay();
1675
1676
      /* We handled our signal; clear errno. */
1677
0
      xerrno = errno = 0;
1678
0
      continue;
1679
0
    }
1680
1681
0
    if (have_dead_child) {
1682
0
      sigset_t sig_set;
1683
1684
0
      sigemptyset(&sig_set);
1685
0
      sigaddset(&sig_set, SIGCHLD);
1686
0
      sigaddset(&sig_set, SIGTERM);
1687
0
      pr_alarms_block();
1688
0
      if (sigprocmask(SIG_BLOCK, &sig_set, NULL) < 0) {
1689
0
        pr_log_pri(PR_LOG_NOTICE,
1690
0
          "unable to block signal set: %s", strerror(errno));
1691
0
      }
1692
1693
0
      have_dead_child = FALSE;
1694
0
      child_update();
1695
1696
0
      if (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {
1697
0
        pr_log_pri(PR_LOG_NOTICE,
1698
0
          "unable to unblock signal set: %s", strerror(errno));
1699
0
      }
1700
1701
0
      pr_alarms_unblock();
1702
0
    }
1703
1704
0
    if (i == -1) {
1705
0
      time_t this_error;
1706
1707
0
      time(&this_error);
1708
1709
0
      if ((this_error - last_error) <= 5 && err_count++ > 10) {
1710
0
        pr_log_pri(PR_LOG_ERR, "fatal: select(2) failing repeatedly, shutting "
1711
0
          "down");
1712
0
        exit(1);
1713
1714
0
      } else if ((this_error - last_error) > 5) {
1715
0
        last_error = this_error;
1716
0
        err_count = 0;
1717
0
      }
1718
1719
0
      pr_log_pri(PR_LOG_WARNING, "select(2) failed in daemon_loop(): %s",
1720
0
        strerror(xerrno));
1721
0
    }
1722
1723
0
    if (i == 0) {
1724
0
      continue;
1725
0
    }
1726
1727
    /* Reset the connection counter.  Take into account this current
1728
     * connection, which does not (yet) have an entry in the child list.
1729
     */
1730
0
    nconnects = 1UL;
1731
1732
    /* See if child semaphore pipes have signaled */
1733
0
    if (child_count()) {
1734
0
      pr_child_t *ch;
1735
0
      time_t now = time(NULL);
1736
1737
0
      for (ch = child_get(NULL); ch; ch = child_get(ch)) {
1738
0
  if (ch->ch_pipefd != -1 &&
1739
0
            FD_ISSET(ch->ch_pipefd, &listenfds)) {
1740
0
    (void) close(ch->ch_pipefd);
1741
0
    ch->ch_pipefd = -1;
1742
0
  }
1743
1744
        /* While we're looking, tally up the number of children forked in
1745
         * the past interval.
1746
         */
1747
0
        if (ch->ch_when >= (time_t) (now - (long) max_connect_interval)) {
1748
0
          nconnects++;
1749
0
        }
1750
0
      }
1751
0
    }
1752
1753
0
    pr_signals_handle_without_delay();
1754
1755
0
    if (i < 0) {
1756
0
      continue;
1757
0
    }
1758
1759
    /* Accept the connection. */
1760
0
    listen_conn = pr_ipbind_accept_conn(&listenfds, &fd);
1761
1762
    /* Fork off servers to handle each connection our job is to get back to
1763
     * answering connections ASAP, so leave the work of determining which
1764
     * server the connection is for to our child.
1765
     */
1766
1767
0
    if (listen_conn != NULL) {
1768
1769
      /* Check for exceeded MaxInstances. */
1770
0
      if (ServerMaxInstances > 0 &&
1771
0
          child_count() >= ServerMaxInstances) {
1772
0
        pr_event_generate("core.max-instances", NULL);
1773
1774
0
        pr_log_pri(PR_LOG_WARNING,
1775
0
          "MaxInstances (%lu) reached, new connection denied",
1776
0
          ServerMaxInstances);
1777
0
        close(fd);
1778
1779
      /* Check for exceeded MaxConnectionRate. */
1780
0
      } else if (max_connects && (nconnects > max_connects)) {
1781
0
        pr_event_generate("core.max-connection-rate", NULL);
1782
1783
0
        pr_log_pri(PR_LOG_WARNING,
1784
0
          "MaxConnectionRate (%lu/%u secs) reached, new connection denied",
1785
0
          max_connects, max_connect_interval);
1786
0
        close(fd);
1787
1788
      /* Fork off a child to handle the connection. */
1789
0
      } else {
1790
0
        PR_DEVEL_CLOCK(fork_server(fd, listen_conn, no_forking));
1791
0
      }
1792
0
    }
1793
#ifdef PR_DEVEL_NO_DAEMON
1794
    /* Do not continue the while() loop here if not daemonizing. */
1795
    break;
1796
#endif /* PR_DEVEL_NO_DAEMON */
1797
0
  }
1798
0
}
1799
1800
/* Returns 1 for the background daemon process, 0 for the foreground process,
1801
 * and -1 if there was an error.
1802
 */
1803
0
static int daemonize(void) {
1804
#ifndef HAVE_SETSID
1805
  int ttyfd;
1806
#endif
1807
0
  pid_t pid;
1808
1809
  /* Fork off and have parent exit.
1810
   */
1811
0
  pid = fork();
1812
0
  switch (pid) {
1813
0
    case -1:
1814
0
      perror("fork(2) error");
1815
0
      return -1;
1816
1817
0
    case 0:
1818
      /* Child process; keep going. */
1819
0
      break;
1820
1821
0
    default:
1822
      /* Parent process; we're done. */
1823
0
      pr_log_pri(PR_LOG_DEBUG, "forked daemon process (PID %lu)",
1824
0
        (unsigned long) pid);
1825
0
      return 0;
1826
0
  }
1827
1828
0
#ifdef HAVE_SETSID
1829
  /* setsid() is the preferred way to disassociate from the
1830
   * controlling terminal
1831
   */
1832
0
  setsid();
1833
#else
1834
  /* Open /dev/tty to access our controlling tty (if any) */
1835
  if ((ttyfd = open("/dev/tty", O_RDWR)) != -1) {
1836
    if (ioctl(ttyfd, TIOCNOTTY, NULL) == -1) {
1837
      perror("ioctl");
1838
      exit(1);
1839
    }
1840
1841
    close(ttyfd);
1842
  }
1843
#endif /* HAVE_SETSID */
1844
1845
  /* Close the three big boys */
1846
0
  close(fileno(stdin));
1847
0
  close(fileno(stdout));
1848
0
  close(fileno(stderr));
1849
1850
  /* Portable way to prevent re-acquiring a tty in the future */
1851
1852
0
#ifdef HAVE_SETPGID
1853
0
  setpgid(0, getpid());
1854
#else
1855
# ifdef SETPGRP_VOID
1856
  setpgrp();
1857
# else
1858
  setpgrp(0, getpid());
1859
# endif
1860
#endif
1861
1862
  /* Reset the cached "master PID" value to that of the daemon process;
1863
   * there are places in the code which check this value to see if they
1864
   * are the daemon process, e.g. at shutdown.
1865
   */
1866
0
  mpid = getpid();
1867
1868
0
  pr_fsio_chdir("/", 0);
1869
0
  return 1;
1870
0
}
1871
1872
0
static void inetd_main(void) {
1873
0
  int res = 0;
1874
1875
  /* Make sure the scoreboard file exists. */
1876
0
  PRIVS_ROOT
1877
0
  res = pr_open_scoreboard(O_RDWR);
1878
0
  if (res < 0) {
1879
0
    PRIVS_RELINQUISH
1880
1881
0
    switch (res) {
1882
0
      case PR_SCORE_ERR_BAD_MAGIC:
1883
0
        pr_log_pri(PR_LOG_ERR, "error opening scoreboard: bad/corrupted file");
1884
0
        return;
1885
1886
0
      case PR_SCORE_ERR_OLDER_VERSION:
1887
0
      case PR_SCORE_ERR_NEWER_VERSION:
1888
0
        pr_log_pri(PR_LOG_ERR, "error opening scoreboard: wrong version, "
1889
0
          "writing new scoreboard");
1890
1891
        /* Delete the scoreboard, then open it again. */
1892
0
        PRIVS_ROOT
1893
0
        pr_delete_scoreboard();
1894
0
        if (pr_open_scoreboard(O_RDWR) < 0) {
1895
0
          int xerrno = errno;
1896
1897
0
          PRIVS_RELINQUISH
1898
0
          pr_log_pri(PR_LOG_ERR, "error opening scoreboard: %s",
1899
0
            strerror(xerrno));
1900
0
          return;
1901
0
        }
1902
0
        break;
1903
1904
0
      default:
1905
0
        pr_log_pri(PR_LOG_ERR, "error opening scoreboard: %s",
1906
0
          strerror(errno));
1907
0
        return;
1908
0
    }
1909
0
  }
1910
0
  PRIVS_RELINQUISH
1911
0
  pr_close_scoreboard(FALSE);
1912
1913
0
  pr_event_generate("core.startup", NULL);
1914
1915
0
  init_bindings();
1916
1917
  /* Check our shutdown status */
1918
0
  if (check_shutmsg(permanent_pool, PR_SHUTMSG_PATH, &shut, &deny, &disc,
1919
0
      shutmsg, sizeof(shutmsg)) == 1) {
1920
0
    shutting_down = TRUE;
1921
0
  }
1922
1923
  /* Finally, call right into fork_server() to start servicing the
1924
   * connection immediately.
1925
   */
1926
0
  fork_server(STDIN_FILENO, main_server->listen, TRUE);
1927
0
}
1928
1929
0
static void standalone_main(void) {
1930
0
  int res = 0;
1931
1932
0
  if (nodaemon) {
1933
0
    log_stderr(quiet ? FALSE : TRUE);
1934
0
    close(fileno(stdin));
1935
0
    close(fileno(stdout));
1936
1937
0
  } else {
1938
0
    log_stderr(FALSE);
1939
0
    res = daemonize();
1940
0
    if (res != 1) {
1941
      /* We're either the foreground process, or there was an error.  Either
1942
       * way, we're done.
1943
       */
1944
0
      return;
1945
0
    }
1946
0
  }
1947
1948
0
  PRIVS_ROOT
1949
0
  pr_delete_scoreboard();
1950
0
  res = pr_open_scoreboard(O_RDWR);
1951
0
  if (res < 0) {
1952
0
    PRIVS_RELINQUISH
1953
1954
0
    switch (res) {
1955
0
      case PR_SCORE_ERR_BAD_MAGIC:
1956
0
        pr_log_pri(PR_LOG_ERR,
1957
0
          "error opening scoreboard: bad/corrupted file");
1958
0
        return;
1959
1960
0
      case PR_SCORE_ERR_OLDER_VERSION:
1961
0
        pr_log_pri(PR_LOG_ERR,
1962
0
          "error opening scoreboard: bad version (too old)");
1963
0
        return;
1964
1965
0
      case PR_SCORE_ERR_NEWER_VERSION:
1966
0
        pr_log_pri(PR_LOG_ERR,
1967
0
          "error opening scoreboard: bad version (too new)");
1968
0
        return;
1969
1970
0
      default:
1971
0
        pr_log_pri(PR_LOG_ERR, "error opening scoreboard: %s", strerror(errno));
1972
0
        return;
1973
0
    }
1974
0
  }
1975
0
  PRIVS_RELINQUISH
1976
0
  pr_close_scoreboard(TRUE);
1977
1978
0
  pr_event_generate("core.startup", NULL);
1979
1980
0
  init_bindings();
1981
1982
0
  if (pr_pidfile_write() < 0) {
1983
0
    pr_log_pri(PR_LOG_ERR, "error writing PidFile '%s': %s", pr_pidfile_get(),
1984
0
      strerror(errno));
1985
0
    exit(1);
1986
0
  }
1987
1988
0
  pr_log_pri(PR_LOG_NOTICE, "ProFTPD %s (built %s) standalone mode STARTUP",
1989
0
    PROFTPD_VERSION_TEXT " " PR_STATUS, BUILD_STAMP);
1990
1991
0
  daemon_loop();
1992
0
}
1993
1994
0
static int conftab_cmp(const void *a, const void *b) {
1995
0
  const conftable *tab1, *tab2;
1996
1997
0
  tab1 = *((conftable **) a);
1998
0
  tab2 = *((conftable **) b);
1999
0
  return strcmp(tab1->directive, tab2->directive);
2000
0
}
2001
2002
/* Similar to the `get_all_directives` function in src/parser.c, except
2003
 * that we sort the directives, and display their associated/implementing
2004
 * modules.
2005
 */
2006
0
static void list_directives(void) {
2007
0
  register unsigned int i;
2008
0
  pool *tmp_pool;
2009
0
  array_header *directives;
2010
0
  conftable *tab;
2011
0
  int idx;
2012
0
  unsigned int hash;
2013
2014
0
  tmp_pool = make_sub_pool(permanent_pool);
2015
0
  directives = make_array(tmp_pool, 1, sizeof(conftable **));
2016
2017
0
  idx = -1;
2018
0
  hash = 0;
2019
0
  tab = pr_stash_get_symbol2(PR_SYM_CONF, NULL, NULL, &idx, &hash);
2020
0
  while (idx != -1) {
2021
0
    pr_signals_handle();
2022
2023
0
    if (tab != NULL) {
2024
0
      *((conftable **) push_array(directives)) = tab;
2025
2026
0
    } else {
2027
0
      idx++;
2028
0
    }
2029
2030
0
    tab = pr_stash_get_symbol2(PR_SYM_CONF, NULL, tab, &idx, &hash);
2031
0
  }
2032
2033
0
  qsort((void *) directives->elts, directives->nelts, sizeof(conftable **),
2034
0
    conftab_cmp);
2035
2036
0
  printf("Configuration Directives:\n");
2037
0
  for (i = 0; i < directives->nelts; i++) {
2038
0
    conftable *conftab;
2039
2040
0
    conftab = ((conftable **) directives->elts)[i];
2041
0
    printf("  %s (from mod_%s)\n", conftab->directive, conftab->m->name);
2042
0
  }
2043
2044
0
  destroy_pool(tmp_pool);
2045
0
}
2046
2047
extern char *optarg;
2048
extern int optind, opterr, optopt;
2049
2050
#if defined(HAVE_GETOPT_LONG)
2051
static struct option opts[] = {
2052
  { "nocollision",    0, NULL, 'N' },
2053
  { "nodaemon",       0, NULL, 'n' },
2054
  { "quiet",        0, NULL, 'q' },
2055
  { "debug",        1, NULL, 'd' },
2056
  { "define",       1, NULL, 'D' },
2057
  { "config",       1, NULL, 'c' },
2058
  { "persistent",     1, NULL, 'p' },
2059
  { "list",           0, NULL, 'l' },
2060
  { "version",        0, NULL, 'v' },
2061
  { "settings",       0, NULL, 'V' },
2062
  { "version-status", 0, NULL, 1   },
2063
  { "configtest",     0, NULL, 't' },
2064
  { "help",       0, NULL, 'h' },
2065
  { "ipv4",           0, NULL, '4' },
2066
  { "ipv6",           0, NULL, '6' },
2067
  { NULL,       0, NULL,  0  }
2068
};
2069
#endif /* HAVE_GETOPT_LONG */
2070
2071
/* If there is an /etc/os-release file, display its contents; see:
2072
 *   https://www.freedesktop.org/software/systemd/man/os-release.html
2073
 */
2074
0
static void show_os_release(void) {
2075
0
  const char *os_release_path = "/etc/os-release";
2076
0
  FILE *fh;
2077
0
  char *line = NULL;
2078
0
  size_t linelen = 0;
2079
0
  ssize_t nread = 0;
2080
2081
0
  fh = fopen(os_release_path, "r");
2082
0
  if (fh == NULL) {
2083
0
    return;
2084
0
  }
2085
2086
0
  printf("%s", "  OS/Release:\n");
2087
2088
0
  nread = getline(&line, &linelen, fh);
2089
0
  while (nread >= 0) {
2090
0
    int skip_line = FALSE;
2091
2092
0
    pr_signals_handle();
2093
2094
    /* Skip any lines containing uninteresting info. */
2095
0
    if (strstr(line, "COLOR") != NULL ||
2096
0
        strstr(line, "LOGO") != NULL ||
2097
0
        strstr(line, "_URL") != NULL) {
2098
0
      skip_line = TRUE;
2099
0
    }
2100
2101
0
    if (skip_line == TRUE) {
2102
0
      nread = getline(&line, &linelen, fh);
2103
0
      continue;
2104
0
    }
2105
2106
0
    printf("    %s", line);
2107
0
    nread = getline(&line, &linelen, fh);
2108
0
  }
2109
2110
0
  if (line != NULL) {
2111
0
    free(line);
2112
0
  }
2113
2114
0
  (void) fclose(fh);
2115
0
}
2116
2117
0
static void show_settings(void) {
2118
0
#if defined(HAVE_UNAME)
2119
0
  int res;
2120
0
  struct utsname uts;
2121
0
#endif /* !HAVE_UNAME */
2122
2123
0
  printf("%s", "Compile-time Settings:\n");
2124
0
  printf("%s", "  Version: " PROFTPD_VERSION_TEXT " " PR_STATUS "\n");
2125
2126
0
#if defined(HAVE_UNAME)
2127
  /* We use uname(2) to get the 'machine', which will tell us whether
2128
   * we're a 32- or 64-bit machine.
2129
   */
2130
0
  res = uname(&uts);
2131
0
  if (res < 0) {
2132
0
    printf("%s", "  Platform: " PR_PLATFORM " [unavailable]\n");
2133
2134
0
  } else {
2135
0
    printf("  Platform: " PR_PLATFORM " [%s %s %s]\n", uts.sysname,
2136
0
      uts.release, uts.machine);
2137
0
  }
2138
#else
2139
  printf("%s", "  Platform: " PR_PLATFORM " [unknown]\n");
2140
#endif /* !HAVE_UNAME */
2141
2142
0
  show_os_release();
2143
2144
0
  printf("%s", "  Built: " BUILD_STAMP "\n");
2145
0
  printf("%s", "  Built With:\n    configure " PR_BUILD_OPTS "\n\n");
2146
2147
0
  printf("%s", "  CFLAGS: " PR_BUILD_CFLAGS "\n");
2148
0
  printf("%s", "  LDFLAGS: " PR_BUILD_LDFLAGS "\n");
2149
0
  printf("%s", "  LIBS: " PR_BUILD_LIBS "\n");
2150
2151
  /* Files/paths */
2152
0
  printf("%s", "\n  Files:\n");
2153
0
  printf("%s", "    Configuration File:\n");
2154
0
  printf("%s", "      " PR_CONFIG_FILE_PATH "\n");
2155
0
  printf("%s", "    Pid File:\n");
2156
0
  printf("%s", "      " PR_PID_FILE_PATH "\n");
2157
0
  printf("%s", "    Scoreboard File:\n");
2158
0
  printf("%s", "      " PR_RUN_DIR "/proftpd.scoreboard\n");
2159
#ifdef PR_USE_DSO
2160
  printf("%s", "    Header Directory:\n");
2161
  printf("%s", "      " PR_INCLUDE_DIR "/proftpd\n");
2162
  printf("%s", "    Shared Module Directory:\n");
2163
  printf("%s", "      " PR_LIBEXEC_DIR "\n");
2164
#endif /* PR_USE_DSO */
2165
2166
  /* Informational */
2167
0
  printf("%s", "\n  Info:\n");
2168
0
#if SIZEOF_UID_T == SIZEOF_INT
2169
0
  printf("    + Max supported UID: %u\n", UINT_MAX);
2170
#elif SIZEOF_UID_T == SIZEOF_LONG
2171
  printf("    + Max supported UID: %lu\n", ULONG_MAX);
2172
#elif SIZEOF_UID_T == SIZEOF_LONG_LONG
2173
  printf("    + Max supported UID: %llu\n", ULLONG_MAX);
2174
#endif
2175
2176
0
#if SIZEOF_GID_T == SIZEOF_INT
2177
0
  printf("    + Max supported GID: %u\n", UINT_MAX);
2178
#elif SIZEOF_GID_T == SIZEOF_LONG
2179
  printf("    + Max supported GID: %lu\n", ULONG_MAX);
2180
#elif SIZEOF_GID_T == SIZEOF_LONG_LONG
2181
  printf("    + Max supported GID: %llu\n", ULLONG_MAX);
2182
#endif
2183
2184
  /* Feature settings */
2185
0
  printf("%s", "\n  Features:\n");
2186
#ifdef PR_USE_AUTO_SHADOW
2187
  printf("%s", "    + Autoshadow support\n");
2188
#else
2189
0
  printf("%s", "    - Autoshadow support\n");
2190
0
#endif /* PR_USE_AUTO_SHADOW */
2191
2192
0
#ifdef PR_USE_CTRLS
2193
0
  printf("%s", "    + Controls support\n");
2194
#else
2195
  printf("%s", "    - Controls support\n");
2196
#endif /* PR_USE_CTRLS */
2197
2198
#if defined(PR_USE_CURSES) && defined(HAVE_LIBCURSES)
2199
  printf("%s", "    + curses support\n");
2200
#else
2201
0
  printf("%s", "    - curses support\n");
2202
0
#endif /* PR_USE_CURSES && HAVE_LIBCURSES */
2203
2204
#ifdef PR_USE_DEVEL
2205
  printf("%s", "    + Developer support\n");
2206
#else
2207
0
  printf("%s", "    - Developer support\n");
2208
0
#endif /* PR_USE_DEVEL */
2209
2210
#ifdef PR_USE_DSO
2211
  printf("%s", "    + DSO support\n");
2212
#else
2213
0
  printf("%s", "    - DSO support\n");
2214
0
#endif /* PR_USE_DSO */
2215
2216
0
#ifdef PR_USE_IPV6
2217
0
  printf("%s", "    + IPv6 support\n");
2218
#else
2219
  printf("%s", "    - IPv6 support\n");
2220
#endif /* PR_USE_IPV6 */
2221
2222
0
#ifdef PR_USE_LARGEFILES
2223
0
  printf("%s", "    + Largefile support\n");
2224
#else
2225
  printf("%s", "    - Largefile support\n");
2226
#endif /* PR_USE_LARGEFILES */
2227
2228
#ifdef PR_USE_LASTLOG
2229
  printf("%s", "    + Lastlog support\n");
2230
#else
2231
0
  printf("%s", "    - Lastlog support\n");
2232
0
#endif /* PR_USE_LASTLOG */
2233
2234
#ifdef PR_USE_MEMCACHE
2235
  printf("%s", "    + Memcache support\n");
2236
#else
2237
0
  printf("%s", "    - Memcache support\n");
2238
0
#endif /* PR_USE_MEMCACHE */
2239
2240
#if defined(PR_USE_NCURSESW) && defined(HAVE_LIBNCURSESW)
2241
  printf("%s", "    + ncursesw support\n");
2242
#elif defined(PR_USE_NCURSES) && defined(HAVE_LIBNCURSES)
2243
  printf("%s", "    + ncurses support\n");
2244
#else
2245
0
  printf("%s", "    - ncurses support\n");
2246
0
#endif
2247
2248
#ifdef PR_USE_NLS
2249
  printf("%s", "    + NLS support\n");
2250
#else
2251
0
  printf("%s", "    - NLS support\n");
2252
0
#endif /* PR_USE_NLS */
2253
2254
#ifdef PR_USE_OPENSSL
2255
# ifdef PR_USE_OPENSSL_FIPS
2256
    printf("    + OpenSSL support (%s, FIPS enabled)\n", OPENSSL_VERSION_TEXT);
2257
# else
2258
#  ifdef LIBRESSL_VERSION_NUMBER
2259
    printf("    + OpenSSL support (%s, LibreSSL)\n", OPENSSL_VERSION_TEXT);
2260
#  else
2261
    printf("    + OpenSSL support (%s)\n", OPENSSL_VERSION_TEXT);
2262
#  endif /* Have LibreSSL */
2263
# endif /* PR_USE_OPENSSL_FIPS */
2264
#else
2265
0
  printf("%s", "    - OpenSSL support\n");
2266
0
#endif /* PR_USE_OPENSSL */
2267
2268
#ifdef PR_USE_PCRE
2269
  printf("%s", "    + PCRE support\n");
2270
#else
2271
0
  printf("%s", "    - PCRE support\n");
2272
0
#endif /* PR_USE_PCRE */
2273
2274
#ifdef PR_USE_PCRE2
2275
  printf("%s", "    + PCRE2 support\n");
2276
#else
2277
0
  printf("%s", "    - PCRE2 support\n");
2278
0
#endif /* PR_USE_PCRE2 */
2279
2280
#ifdef PR_USE_FACL
2281
  printf("%s", "    + POSIX ACL support\n");
2282
#else
2283
0
  printf("%s", "    - POSIX ACL support\n");
2284
0
#endif /* PR_USE_FACL */
2285
2286
#ifdef PR_USE_REDIS
2287
  printf("%s", "    + Redis support\n");
2288
#else
2289
0
  printf("%s", "    - Redis support\n");
2290
0
#endif /* PR_USE_REDIS */
2291
2292
0
#ifdef PR_USE_SENDFILE
2293
0
  printf("%s", "    + Sendfile support\n");
2294
#else
2295
  printf("%s", "    - Sendfile support\n");
2296
#endif /* PR_USE_SENDFILE */
2297
2298
0
#ifdef PR_USE_SHADOW
2299
0
  printf("%s", "    + Shadow file support\n");
2300
#else
2301
  printf("%s", "    - Shadow file support\n");
2302
#endif /* PR_USE_SHADOW */
2303
2304
#ifdef PR_USE_SODIUM
2305
  printf("%s", "    + Sodium support\n");
2306
#else
2307
0
  printf("%s", "    - Sodium support\n");
2308
0
#endif /* PR_USE_SODIUM */
2309
2310
0
#ifdef PR_USE_TRACE
2311
0
  printf("%s", "    + Trace support\n");
2312
#else
2313
  printf("%s", "    - Trace support\n");
2314
#endif /* PR_USE_TRACE */
2315
2316
0
#ifdef PR_USE_XATTR
2317
0
  printf("%s", "    + xattr support\n");
2318
#else
2319
  printf("%s", "    - xattr support\n");
2320
#endif /* PR_USE_XATTR */
2321
2322
  /* Tunable settings */
2323
0
  printf("%s", "\n  Tunable Options:\n");
2324
0
  printf("    PR_TUNABLE_BUFFER_SIZE = %u\n", PR_TUNABLE_BUFFER_SIZE);
2325
0
  printf("    PR_TUNABLE_DEFAULT_RCVBUFSZ = %u\n", PR_TUNABLE_DEFAULT_RCVBUFSZ);
2326
0
  printf("    PR_TUNABLE_DEFAULT_SNDBUFSZ = %u\n", PR_TUNABLE_DEFAULT_SNDBUFSZ);
2327
0
  printf("    PR_TUNABLE_ENV_MAX = %u\n", PR_TUNABLE_ENV_MAX);
2328
0
  printf("    PR_TUNABLE_GLOBBING_MAX_MATCHES = %lu\n", PR_TUNABLE_GLOBBING_MAX_MATCHES);
2329
0
  printf("    PR_TUNABLE_GLOBBING_MAX_RECURSION = %u\n", PR_TUNABLE_GLOBBING_MAX_RECURSION);
2330
0
  printf("    PR_TUNABLE_HASH_TABLE_SIZE = %u\n", PR_TUNABLE_HASH_TABLE_SIZE);
2331
0
  printf("    PR_TUNABLE_LOGIN_MAX = %u\n", PR_TUNABLE_LOGIN_MAX);
2332
0
  printf("    PR_TUNABLE_NEW_POOL_SIZE = %u\n", PR_TUNABLE_NEW_POOL_SIZE);
2333
0
  printf("    PR_TUNABLE_PATH_MAX = %u\n", PR_TUNABLE_PATH_MAX);
2334
0
  printf("    PR_TUNABLE_SCOREBOARD_BUFFER_SIZE = %u\n",
2335
0
    PR_TUNABLE_SCOREBOARD_BUFFER_SIZE);
2336
0
  printf("    PR_TUNABLE_SCOREBOARD_SCRUB_TIMER = %u\n",
2337
0
    PR_TUNABLE_SCOREBOARD_SCRUB_TIMER);
2338
0
  printf("    PR_TUNABLE_SELECT_TIMEOUT = %u\n", PR_TUNABLE_SELECT_TIMEOUT);
2339
0
  printf("    PR_TUNABLE_TIMEOUTIDENT = %u\n", PR_TUNABLE_TIMEOUTIDENT);
2340
0
  printf("    PR_TUNABLE_TIMEOUTIDLE = %u\n", PR_TUNABLE_TIMEOUTIDLE);
2341
0
  printf("    PR_TUNABLE_TIMEOUTLINGER = %u\n", PR_TUNABLE_TIMEOUTLINGER);
2342
0
  printf("    PR_TUNABLE_TIMEOUTLOGIN = %u\n", PR_TUNABLE_TIMEOUTLOGIN);
2343
0
  printf("    PR_TUNABLE_TIMEOUTNOXFER = %u\n", PR_TUNABLE_TIMEOUTNOXFER);
2344
0
  printf("    PR_TUNABLE_TIMEOUTSTALLED = %u\n", PR_TUNABLE_TIMEOUTSTALLED);
2345
0
  printf("    PR_TUNABLE_XFER_SCOREBOARD_UPDATES = %u\n\n",
2346
0
    PR_TUNABLE_XFER_SCOREBOARD_UPDATES);
2347
0
}
2348
2349
static struct option_help {
2350
  const char *long_opt, *short_opt, *desc;
2351
2352
} opts_help[] = {
2353
  { "--help", "-h",
2354
    "Display proftpd usage"},
2355
2356
  { "--nocollision", "-N",
2357
    "Disable address/port collision checking" },
2358
2359
  { "--nodaemon", "-n",
2360
    "Disable background daemon mode (and send all output to stderr)" },
2361
2362
  { "--quiet", "-q",
2363
    "Don't send output to stderr when running with -n or --nodaemon" },
2364
2365
  { "--debug", "-d [level]",
2366
    "Set debugging level (0-10, 10 = most debugging)" },
2367
2368
  { "--define", "-D [definition]",
2369
    "Set arbitrary IfDefine definition" },
2370
2371
  { "--config", "-c [config-file]",
2372
    "Specify alternate configuration file" },
2373
2374
  { "--persistent", "-p [0|1]",
2375
    "Enable/disable default persistent passwd support" },
2376
2377
  { "--list", "-l",
2378
    "List all compiled-in modules" },
2379
2380
  { "--serveraddr", "-S",
2381
    "Specify IP address for server config" },
2382
2383
  { "--configtest", "-t",
2384
    "Test the syntax of the specified config" },
2385
2386
  { "--settings", "-V",
2387
    "Print compile-time settings and exit" },
2388
2389
  { "--version", "-v",
2390
    "Print version number and exit" },
2391
2392
  { "--version-status", "-vv",
2393
    "Print extended version information and exit" },
2394
2395
  { "--nofork", "-X",
2396
    "Non-forking debug mode; exits after one session" },
2397
2398
  { "--ipv4", "-4",
2399
    "Support IPv4 connections only" },
2400
2401
  { "--ipv6", "-6",
2402
    "Support IPv6 connections" },
2403
2404
  { NULL, NULL, NULL }
2405
};
2406
2407
0
static void show_usage(int exit_code) {
2408
0
  struct option_help *h;
2409
2410
0
  printf("%s", "usage: proftpd [options]\n");
2411
0
  for (h = opts_help; h->long_opt; h++) {
2412
0
#ifdef HAVE_GETOPT_LONG
2413
0
    printf(" %s, %s\n ", h->short_opt, h->long_opt);
2414
#else /* HAVE_GETOPT_LONG */
2415
    printf(" %s\n", h->short_opt);
2416
#endif /* HAVE_GETOPT_LONG */
2417
0
    printf("    %s\n", h->desc);
2418
0
  }
2419
2420
0
  exit(exit_code);
2421
0
}
2422
2423
0
int main2(int argc, char *argv[], char **envp) {
2424
0
  int optc, show_version = 0;
2425
0
  const char *cmdopts = "D:NVc:d:hlnp:qS:tvX46";
2426
0
  mode_t *main_umask = NULL;
2427
0
  socklen_t peerlen;
2428
0
  struct sockaddr peer;
2429
#if defined(PR_USE_NLS) && defined(HAVE_LOCALE_H)
2430
  const char *env_lang = NULL, *env_locale = NULL;
2431
#endif
2432
2433
#ifdef HAVE_SET_AUTH_PARAMETERS
2434
  (void) set_auth_parameters(argc, argv);
2435
#endif
2436
2437
0
#ifdef HAVE_TZSET
2438
  /* Preserve timezone information in jailed environments.
2439
   */
2440
0
  tzset();
2441
0
#endif
2442
2443
0
  memset(&session, 0, sizeof(session));
2444
2445
0
  pr_fs_close_extra_fds();
2446
0
  pr_proctitle_init(argc, argv, envp);
2447
2448
  /* Seed rand */
2449
0
  pr_random_init();
2450
2451
  /* getpeername() fails if the fd isn't a socket */
2452
0
  peerlen = sizeof(peer);
2453
0
  memset(&peer, 0, peerlen);
2454
0
  if (getpeername(fileno(stdin), &peer, &peerlen) != -1) {
2455
0
    log_stderr(FALSE);
2456
0
  }
2457
2458
  /* Open the syslog */
2459
0
  log_opensyslog(NULL);
2460
2461
  /* Initialize the memory subsystem here */
2462
0
  init_pools();
2463
2464
  /* Command line options supported:
2465
   *
2466
   * -D parameter       set run-time configuration parameter
2467
   * --define parameter
2468
   * -V
2469
   * --settings         report compile-time settings
2470
   * -c path            set the configuration path
2471
   * --config path
2472
   * -d n               set the debug level
2473
   * --debug n
2474
   * -q                 quiet mode; don't log to stderr when not daemonized
2475
   * --quiet
2476
   * -N                 disable address/port collision checks
2477
   * --nocollision
2478
   * -n                 standalone server does not daemonize, all logging
2479
   * --nodaemon         redirected to stderr
2480
   * -S                 specify the IP address for the 'server config',
2481
   * --serveraddr       rather than using DNS on the hostname
2482
   * -t                 syntax check of the configuration file
2483
   * --configtest
2484
   * -v                 report version number
2485
   * --version
2486
   * -X
2487
   * --nofork           debug/non-fork mode
2488
   * -4                 support IPv4 connections only
2489
   * --ipv4
2490
   * -6                 support IPv6 connections
2491
   * --ipv6
2492
   */
2493
2494
0
  opterr = 0;
2495
0
  while ((optc =
2496
0
#ifdef HAVE_GETOPT_LONG
2497
0
   getopt_long(argc, argv, cmdopts, opts, NULL)
2498
#else /* HAVE_GETOPT_LONG */
2499
   getopt(argc, argv, cmdopts)
2500
#endif /* HAVE_GETOPT_LONG */
2501
0
   ) != -1) {
2502
0
    switch (optc) {
2503
2504
0
    case 'D':
2505
0
      if (!optarg) {
2506
0
        pr_log_pri(PR_LOG_WARNING, "fatal: -D requires definition parameter");
2507
0
        exit(1);
2508
0
      }
2509
2510
0
      pr_define_add(optarg, TRUE);
2511
0
      break;
2512
2513
0
    case 'V':
2514
0
      show_settings();
2515
0
      exit(0);
2516
0
      break;
2517
2518
0
    case 'N':
2519
0
      AddressCollisionCheck = FALSE;
2520
0
      break;
2521
2522
0
    case 'n':
2523
0
      nodaemon++;
2524
#ifdef PR_USE_DEVEL
2525
      pr_pool_debug_set_flags(PR_POOL_DEBUG_FL_OOM_DUMP_POOLS);
2526
#endif
2527
0
      break;
2528
2529
0
    case 'q':
2530
0
      quiet++;
2531
0
      break;
2532
2533
0
    case 'd':
2534
0
      if (!optarg) {
2535
0
        pr_log_pri(PR_LOG_WARNING, "fatal: -d requires debug level parameter");
2536
0
        exit(1);
2537
0
      }
2538
0
      pr_log_setdebuglevel(atoi(optarg));
2539
2540
      /* If the admin uses -d on the command-line, they explicitly WANT
2541
       * debug logging, thus make sure the default SyslogLevel is set to
2542
       * DEBUG (rather than NOTICE); see Bug#3983.
2543
       */
2544
0
      pr_log_setdefaultlevel(PR_LOG_DEBUG);
2545
0
      break;
2546
2547
0
    case 'c':
2548
0
      if (!optarg) {
2549
0
        pr_log_pri(PR_LOG_WARNING,
2550
0
          "fatal: -c requires configuration path parameter");
2551
0
        exit(1);
2552
0
      }
2553
2554
      /* Note: we delay sanity-checking the given path until after the FSIO
2555
       * layer has been initialized.
2556
       */
2557
0
      config_filename = strdup(optarg);
2558
0
      break;
2559
2560
0
    case 'l':
2561
0
      modules_list2(NULL, PR_MODULES_LIST_FL_SHOW_STATIC);
2562
0
      exit(0);
2563
0
      break;
2564
2565
0
    case 'S':
2566
0
      if (!optarg) {
2567
0
        pr_log_pri(PR_LOG_WARNING, "fatal: -S requires IP address parameter");
2568
0
        exit(1);
2569
0
      }
2570
2571
0
      if (pr_netaddr_set_localaddr_str(optarg) < 0) {
2572
0
        pr_log_pri(PR_LOG_WARNING,
2573
0
          "fatal: unable to use '%s' as server address: %s", optarg,
2574
0
          strerror(errno));
2575
0
        exit(1);
2576
0
      }
2577
0
      break;
2578
2579
0
    case 't':
2580
0
      syntax_check = 1;
2581
0
      printf("%s", "Checking syntax of configuration file\n");
2582
0
      fflush(stdout);
2583
0
      break;
2584
2585
    /* Note: This is now unused, and should be deprecated in the next release.
2586
     * See Bug#3952 for details.
2587
     */
2588
0
    case 'p': {
2589
0
      if (!optarg ||
2590
0
          (atoi(optarg) != 1 && atoi(optarg) != 0)) {
2591
0
        pr_log_pri(PR_LOG_WARNING,
2592
0
          "fatal: -p requires Boolean (0|1) parameter");
2593
0
        exit(1);
2594
0
      }
2595
2596
0
      break;
2597
0
    }
2598
2599
0
    case 'v':
2600
0
      show_version++;
2601
0
      break;
2602
2603
0
    case 'X':
2604
0
      no_forking = TRUE;
2605
0
      break;
2606
2607
0
    case 1:
2608
0
      show_version = 2;
2609
0
      break;
2610
2611
0
    case 'h':
2612
0
      show_usage(0);
2613
0
      break;
2614
2615
0
    case '4':
2616
0
      pr_netaddr_disable_ipv6();
2617
0
      break;
2618
2619
0
    case '6':
2620
0
      pr_netaddr_enable_ipv6();
2621
0
      break;
2622
2623
0
    case '?':
2624
0
      pr_log_pri(PR_LOG_WARNING, "unknown option: %c", (char) optopt);
2625
0
      show_usage(1);
2626
0
      break;
2627
0
    }
2628
0
  }
2629
2630
  /* If we have any leftover parameters, it's an error. */
2631
0
  if (argv[optind]) {
2632
0
    pr_log_pri(PR_LOG_WARNING, "fatal: unknown parameter: '%s'", argv[optind]);
2633
0
    exit(1);
2634
0
  }
2635
2636
0
  if (show_version == 1) {
2637
0
    printf("%s", "ProFTPD Version " PROFTPD_VERSION_TEXT "\n");
2638
0
    exit(0);
2639
0
  }
2640
2641
0
  mpid = getpid();
2642
2643
  /* Initialize sub-systems */
2644
0
  init_signals();
2645
0
  init_pools();
2646
0
  init_privs();
2647
0
  init_log();
2648
0
  init_regexp();
2649
0
  init_inet();
2650
0
  init_netio();
2651
0
  init_netaddr();
2652
0
  init_fs();
2653
0
  init_class();
2654
0
  free_bindings();
2655
0
  init_config();
2656
0
  init_dirtree();
2657
0
  init_stash();
2658
0
  init_json();
2659
2660
0
#ifdef PR_USE_CTRLS
2661
0
  init_ctrls();
2662
0
#endif /* PR_USE_CTRLS */
2663
2664
0
  var_init();
2665
2666
#if defined(PR_USE_NLS)
2667
# if defined(HAVE_LOCALE_H)
2668
  /* Initialize the locale based on environment variables. */
2669
  env_lang = pr_env_get(permanent_pool, "LANG");
2670
2671
  env_locale = setlocale(LC_ALL, "");
2672
  if (env_locale == NULL) {
2673
    pr_log_pri(PR_LOG_WARNING, "warning: unknown/unsupported LANG environment "
2674
      "variable '%s', ignoring", env_lang != NULL ? env_lang : "(null)");
2675
    (void) setlocale(LC_ALL, "C");
2676
2677
  } else {
2678
    pr_log_debug(DEBUG9, "using '%s' locale based on LANG=%s environment "
2679
      "variable", env_locale, env_lang != NULL ? env_lang : "(null)");
2680
2681
    /* Make sure that LC_NUMERIC is always set to "C", so as not to interfere
2682
     * with formatting of strings (like printing out floats in SQL query
2683
     * strings).
2684
     */
2685
    (void) setlocale(LC_NUMERIC, "C");
2686
  }
2687
# endif /* !HAVE_LOCALE_H */
2688
2689
  encode_init();
2690
#endif /* PR_USE_NLS */
2691
2692
  /* Note that modules MUST be initialized AFTER the locale, so that we
2693
   * are consistent in handling of strings via _e.g._ tolower(3); see Bug#4466.
2694
   */
2695
0
  modules_init();
2696
2697
  /* Now, once the modules have had a chance to initialize themselves
2698
   * but before the configuration stream is actually parsed, check
2699
   * that the given configuration path is valid.
2700
   */
2701
0
  if (pr_fs_valid_path(config_filename) < 0) {
2702
0
    pr_log_pri(PR_LOG_WARNING, "fatal: -c requires an absolute path");
2703
0
    exit(1);
2704
0
  }
2705
2706
0
  pr_parser_prepare(NULL, NULL);
2707
2708
0
  pr_event_generate("core.preparse", NULL);
2709
2710
0
  if (pr_parser_parse_file(NULL, config_filename, NULL, 0) < 0) {
2711
    /* Note: EPERM is used to indicate the presence of unrecognized
2712
     * configuration directives in the parsed file(s).
2713
     */
2714
0
    if (errno != EPERM) {
2715
0
      pr_log_pri(PR_LOG_WARNING,
2716
0
        "fatal: unable to read configuration file '%s': %s", config_filename,
2717
0
        strerror(errno));
2718
0
    }
2719
2720
0
    exit(1);
2721
0
  }
2722
2723
0
  if (pr_parser_cleanup() < 0) {
2724
0
    pr_log_pri(PR_LOG_WARNING,
2725
0
      "fatal: error processing configuration file '%s': "
2726
0
      "unclosed configuration section", config_filename);
2727
0
    exit(1);
2728
0
  }
2729
2730
0
  if (fixup_servers(server_list) < 0) {
2731
0
    pr_log_pri(PR_LOG_WARNING,
2732
0
      "fatal: error processing configuration file '%s'", config_filename);
2733
0
    exit(1);
2734
0
  }
2735
2736
0
  pr_event_generate("core.postparse", NULL);
2737
2738
0
  if (show_version >= 2) {
2739
0
    printf("ProFTPD Version: %s", PROFTPD_VERSION_TEXT " " PR_STATUS "\n");
2740
0
    printf("  Scoreboard Version: %08x\n", PR_SCOREBOARD_VERSION);
2741
0
    printf("  Built: %s\n\n", BUILD_STAMP);
2742
2743
0
    modules_list2(NULL, PR_MODULES_LIST_FL_SHOW_VERSION);
2744
2745
0
    if (show_version >= 3) {
2746
0
      printf("\n");
2747
0
      list_directives();
2748
0
    }
2749
2750
0
    exit(0);
2751
0
  }
2752
2753
  /* We're only doing a syntax check of the configuration file. */
2754
0
  if (syntax_check) {
2755
0
    printf("%s", "Syntax check complete.\n");
2756
0
    pr_session_end(PR_SESS_END_FL_SYNTAX_CHECK);
2757
0
  }
2758
2759
  /* Security */
2760
0
  {
2761
0
    uid_t *uid = (uid_t *) get_param_ptr(main_server->conf, "UserID", FALSE);
2762
0
    gid_t *gid = (gid_t *) get_param_ptr(main_server->conf, "GroupID", FALSE);
2763
2764
0
    daemon_uid = (uid != NULL ? *uid : PR_ROOT_UID);
2765
0
    daemon_gid = (gid != NULL ? *gid : PR_ROOT_GID);
2766
0
  }
2767
2768
0
  if (daemon_uid != PR_ROOT_UID) {
2769
0
    pr_log_debug(DEBUG9, "ignoring supplemental groups for non-root UID %lu",
2770
0
      (unsigned long) daemon_uid);
2771
0
  }
2772
2773
  /* After configuration is complete, make sure that passwd, group
2774
   * aren't held open (unnecessary fds for master daemon)
2775
   */
2776
0
  endpwent();
2777
0
  endgrent();
2778
2779
0
  main_umask = get_param_ptr(main_server->conf, "Umask", FALSE);
2780
0
  if (main_umask == NULL) {
2781
0
    umask((mode_t) 0022);
2782
2783
0
  } else {
2784
0
    umask(*main_umask);
2785
0
  }
2786
2787
  /* Give up root and save our uid/gid for later use (if supported)
2788
   * If we aren't currently root, PRIVS_SETUP will get rid of setuid
2789
   * granted root and prevent further uid switching from being attempted.
2790
   */
2791
2792
0
  PRIVS_SETUP(daemon_uid, daemon_gid)
2793
2794
0
#ifndef PR_DEVEL_COREDUMP
2795
  /* Test to make sure that our uid/gid is correct.  Try to do this in
2796
   * a portable fashion *gah!*
2797
   */
2798
2799
0
  if (geteuid() != daemon_uid) {
2800
0
    pr_log_pri(PR_LOG_ERR, "unable to set UID to %s, current UID: %s",
2801
0
      pr_uid2str(permanent_pool, daemon_uid),
2802
0
      pr_uid2str(permanent_pool, geteuid()));
2803
0
    exit(1);
2804
0
  }
2805
2806
0
  if (getegid() != daemon_gid) {
2807
0
    pr_log_pri(PR_LOG_ERR, "unable to set GID to %s, current GID: %s",
2808
0
      pr_gid2str(permanent_pool, daemon_gid),
2809
0
      pr_gid2str(permanent_pool, getegid()));
2810
0
    exit(1);
2811
0
  }
2812
0
#endif /* PR_DEVEL_COREDUMP */
2813
2814
0
  switch (ServerType) {
2815
0
    case SERVER_STANDALONE:
2816
0
      standalone_main();
2817
0
      break;
2818
2819
0
    case SERVER_INETD:
2820
      /* Reset the variable containing the pid of the master/daemon process;
2821
       * it should only be non-zero in the case of standalone daemons.
2822
       */
2823
0
      mpid = 0;
2824
0
      inetd_main();
2825
0
      break;
2826
0
  }
2827
2828
#ifdef PR_DEVEL_NO_DAEMON
2829
  PRIVS_ROOT
2830
  chdir(PR_RUN_DIR);
2831
#endif /* PR_DEVEL_NO_DAEMON */
2832
2833
0
  return 0;
2834
0
}