Coverage Report

Created: 2024-09-30 06:24

/src/proftpd/src/log.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
/* ProFTPD logging support. */
28
29
#include "conf.h"
30
31
#ifdef HAVE_EXECINFO_H
32
# include <execinfo.h>
33
#endif
34
35
#define LOGBUFFER_SIZE    (PR_TUNABLE_PATH_MAX * 4)
36
37
/* From src/main.c */
38
extern unsigned char is_master;
39
40
static int syslog_open = FALSE;
41
static int syslog_discard = FALSE;
42
static unsigned long log_opts = PR_LOG_OPT_DEFAULT;
43
static int logstderr = TRUE;
44
static int debug_level = DEBUG0;
45
static int default_level = PR_LOG_NOTICE;
46
static int facility = LOG_DAEMON;
47
static int set_facility = -1;
48
static char systemlog_fn[PR_TUNABLE_PATH_MAX] = {'\0'};
49
static char systemlog_host[256] = {'\0'};
50
static int systemlog_fd = -1;
51
52
static const char *trace_channel = "log";
53
54
int syslog_sockfd = -1;
55
56
#ifdef PR_USE_NONBLOCKING_LOG_OPEN
57
0
static int fd_set_block(int fd) {
58
0
  int flags, res;
59
60
0
  flags = fcntl(fd, F_GETFL);
61
0
  res = fcntl(fd, F_SETFL, flags & (U32BITS ^ O_NONBLOCK));
62
63
0
  return res;
64
0
}
65
#endif /* PR_USE_NONBLOCKING_LOG_OPEN */
66
67
0
int pr_log_openfile(const char *log_file, int *log_fd, mode_t log_mode) {
68
0
  pool *tmp_pool = NULL;
69
0
  char *ptr = NULL, *lf;
70
0
  unsigned char have_stat = FALSE, *allow_log_symlinks = NULL;
71
0
  struct stat st;
72
73
  /* Sanity check */
74
0
  if (log_file == NULL ||
75
0
      log_fd == NULL) {
76
0
    errno = EINVAL;
77
0
    return -1;
78
0
  }
79
80
  /* Make a temporary copy of log_file in case it's a constant */
81
0
  tmp_pool = make_sub_pool(permanent_pool);
82
0
  pr_pool_tag(tmp_pool, "log_openfile() tmp pool");
83
0
  lf = pstrdup(tmp_pool, log_file);
84
85
0
  ptr = strrchr(lf, '/');
86
0
  if (ptr == NULL) {
87
0
    pr_log_debug(DEBUG0, "inappropriate log file: %s", lf);
88
0
    destroy_pool(tmp_pool);
89
90
0
    errno = EINVAL;
91
0
    return -1;
92
0
  }
93
94
  /* Set the path separator to zero, in order to obtain the directory
95
   * name, so that checks of the directory may be made.
96
   */
97
0
  if (ptr != lf) {
98
0
    *ptr = '\0';
99
0
  }
100
101
0
  if (stat(lf, &st) < 0) {
102
0
    int xerrno = errno;
103
0
    pr_log_debug(DEBUG0, "error: unable to stat() %s: %s", lf,
104
0
      strerror(errno));
105
0
    destroy_pool(tmp_pool);
106
107
0
    errno = xerrno;
108
0
    return -1;
109
0
  }
110
111
  /* The path must be in a valid directory */
112
0
  if (!S_ISDIR(st.st_mode)) {
113
0
    pr_log_debug(DEBUG0, "error: %s is not a directory", lf);
114
0
    destroy_pool(tmp_pool);
115
116
0
    errno = ENOTDIR;
117
0
    return -1;
118
0
  }
119
120
  /* Do not log to world-writable directories */
121
0
  if (st.st_mode & S_IWOTH) {
122
0
    pr_log_pri(PR_LOG_NOTICE, "error: %s is a world-writable directory", lf);
123
0
    destroy_pool(tmp_pool);
124
0
    return PR_LOG_WRITABLE_DIR;
125
0
  }
126
127
  /* Restore the path separator so that checks on the file itself may be
128
   * done.
129
   */
130
0
  if (ptr != lf) {
131
0
    *ptr = '/';
132
0
  }
133
134
0
  allow_log_symlinks = get_param_ptr(main_server->conf, "AllowLogSymlinks",
135
0
    FALSE);
136
137
0
  if (allow_log_symlinks == NULL ||
138
0
      *allow_log_symlinks == FALSE) {
139
0
    int flags = O_APPEND|O_CREAT|O_WRONLY;
140
141
0
#ifdef PR_USE_NONBLOCKING_LOG_OPEN
142
    /* Use the O_NONBLOCK flag when opening log files, as they might be
143
     * FIFOs whose other end is not currently running; we do not want to
144
     * block indefinitely in such cases.
145
     */
146
0
    flags |= O_NONBLOCK;
147
0
#endif /* PR_USE_NONBLOCKING_LOG_OPEN */
148
149
0
#ifdef O_NOFOLLOW
150
    /* On systems that support the O_NOFOLLOW flag (e.g. Linux and FreeBSD),
151
     * use it so that the path being opened, if it is a symlink, is not
152
     * followed.
153
     */
154
0
    flags |= O_NOFOLLOW;
155
156
#elif defined(SOLARIS2)
157
    /* Solaris doesn't support the O_NOFOLLOW flag.  Instead, in their
158
     * wisdom (hah!), Solaris decided that if the given path is a symlink
159
     * and the flags O_CREAT and O_EXCL are set, the link is not followed.
160
     * Right.  The problem here is the case where the path is not a symlink;
161
     * using O_CREAT|O_EXCL will then cause the open() to fail if the
162
     * file already exists.
163
     */
164
    flags |= O_EXCL;
165
#endif /* O_NOFOLLOW or SOLARIS2 */
166
167
0
    *log_fd = open(lf, flags, log_mode);
168
0
    if (*log_fd < 0) {
169
170
0
      if (errno != EEXIST) {
171
0
        destroy_pool(tmp_pool);
172
173
        /* More portability fun: Linux likes to report ELOOP if O_NOFOLLOW
174
         * is used to open a symlink file; FreeBSD likes to return EMLINK.
175
         * Both would lead to rather misleading error messages being
176
         * logged.  Catch these errnos, and return the value that properly
177
         * informs the caller that the given path was an illegal symlink.
178
         */
179
180
0
        switch (errno) {
181
0
#ifdef ELOOP
182
0
          case ELOOP:
183
0
            return PR_LOG_SYMLINK;
184
0
#endif /* ELOOP */
185
186
0
#ifdef EMLINK
187
0
          case EMLINK:
188
0
            return PR_LOG_SYMLINK;
189
0
#endif /* EMLINK */
190
0
        }
191
192
0
        return -1;
193
194
0
      } else {
195
#if defined(SOLARIS2)
196
        /* On Solaris, because of the stupid multiplexing of O_CREAT and
197
         * O_EXCL to get open() not to follow a symlink, it's possible that
198
         * the path already exists.  Now, we'll try to open() without
199
         * O_EXCL, then lstat() the path to see if this pre-existing file is
200
         * a symlink or a regular file.
201
         *
202
         * Note that because this check cannot be done atomically on Solaris,
203
         * the possibility of a race condition/symlink attack still exists.
204
         * Solaris doesn't provide a good way around this situation.
205
         */
206
        flags &= ~O_EXCL;
207
208
        *log_fd = open(lf, flags, log_mode);
209
        if (*log_fd < 0) {
210
          destroy_pool(tmp_pool);
211
          return -1;
212
        }
213
214
        /* The race condition on Solaris is here, between the open() call
215
         * above and the lstat() call below...
216
         */
217
218
        if (lstat(lf, &st) != -1)
219
          have_stat = TRUE;
220
#else
221
0
        destroy_pool(tmp_pool);
222
0
        return -1;
223
0
#endif /* SOLARIS2 */
224
0
      }
225
0
    }
226
227
    /* Stat the file using the descriptor, not the path */
228
0
    if (!have_stat &&
229
0
        fstat(*log_fd, &st) != -1) {
230
0
      have_stat = TRUE;
231
0
    }
232
233
0
    if (!have_stat ||
234
0
        S_ISLNK(st.st_mode)) {
235
0
      pr_log_debug(DEBUG0, !have_stat ? "error: unable to stat %s" :
236
0
        "error: %s is a symbolic link", lf);
237
238
0
      close(*log_fd);
239
0
      *log_fd = -1;
240
0
      destroy_pool(tmp_pool);
241
0
      return PR_LOG_SYMLINK;
242
0
    }
243
244
0
  } else {
245
0
    int flags = O_CREAT|O_APPEND|O_WRONLY;
246
247
0
#ifdef PR_USE_NONBLOCKING_LOG_OPEN
248
    /* Use the O_NONBLOCK flag when opening log files, as they might be
249
     * FIFOs whose other end is not currently running; we do not want to
250
     * block indefinitely in such cases.
251
     */
252
0
    flags |= O_NONBLOCK;
253
0
#endif /* PR_USE_NONBLOCKING_LOG_OPEN */
254
255
0
    *log_fd = open(lf, flags, log_mode);
256
0
    if (*log_fd < 0) {
257
0
      int xerrno = errno;
258
259
0
      destroy_pool(tmp_pool);
260
0
      errno = xerrno;
261
0
      return -1;
262
0
    }
263
0
  }
264
265
  /* Make sure we're dealing with an expected file type (i.e. NOT a
266
   * directory).
267
   */
268
0
  if (fstat(*log_fd, &st) < 0) {
269
0
    int xerrno = errno;
270
271
0
    pr_log_debug(DEBUG0, "error: unable to stat %s (fd %d): %s", lf, *log_fd,
272
0
      strerror(xerrno));
273
274
0
    (void) close(*log_fd);
275
0
    *log_fd = -1;
276
0
    destroy_pool(tmp_pool);
277
278
0
    errno = xerrno;
279
0
    return -1;
280
0
  }
281
282
0
  if (S_ISDIR(st.st_mode)) {
283
0
    int xerrno = EISDIR;
284
285
0
    pr_log_debug(DEBUG0, "error: unable to use %s: %s", lf, strerror(xerrno));
286
287
0
    (void) close(*log_fd);
288
0
    *log_fd = -1;
289
0
    destroy_pool(tmp_pool);
290
291
0
    errno = xerrno;
292
0
    return -1;
293
0
  }
294
295
  /* Find a usable fd for the just-opened log fd. */
296
0
  if (*log_fd <= STDERR_FILENO) {
297
0
    int res;
298
299
0
    res = pr_fs_get_usable_fd(*log_fd);
300
0
    if (res < 0) {
301
0
      pr_log_debug(DEBUG0, "warning: unable to find good fd for logfd %d: %s",
302
0
        *log_fd, strerror(errno));
303
304
0
    } else {
305
0
      close(*log_fd);
306
0
      *log_fd = res;
307
0
    }
308
0
  }
309
310
0
  if (fcntl(*log_fd, F_SETFD, FD_CLOEXEC) < 0) {
311
0
    pr_log_pri(PR_LOG_WARNING, "unable to set CLO_EXEC on log fd %d: %s",
312
0
      *log_fd, strerror(errno));
313
0
  }
314
315
  /* Advise the platform that we will be treating this log file as
316
   * write-only data.
317
   */
318
0
  pr_fs_fadvise(*log_fd, 0, 0, PR_FS_FADVISE_DONTNEED);
319
320
0
#ifdef PR_USE_NONBLOCKING_LOG_OPEN
321
  /* Return the fd to blocking mode. */
322
0
  (void) fd_set_block(*log_fd);
323
0
#endif /* PR_USE_NONBLOCKING_LOG_OPEN */
324
325
0
  destroy_pool(tmp_pool);
326
0
  return 0;
327
0
}
328
329
int pr_log_vwritefile(int logfd, const char *ident, const char *fmt,
330
0
    va_list msg) {
331
0
  pool *tmp_pool;
332
0
  char buf[LOGBUFFER_SIZE] = {'\0'};
333
0
  struct timeval now;
334
0
  struct tm *tm = NULL;
335
0
  size_t buflen, len;
336
0
  unsigned long millis;
337
338
0
  if (logfd < 0 ||
339
0
      ident == NULL) {
340
0
    errno = EINVAL;
341
0
    return -1;
342
0
  }
343
344
0
  tmp_pool = make_sub_pool(permanent_pool);
345
0
  pr_pool_tag(tmp_pool, "Log message pool");
346
347
0
  gettimeofday(&now, NULL);
348
0
  tm = pr_localtime(tmp_pool, (const time_t *) &(now.tv_sec));
349
0
  if (tm == NULL) {
350
0
    int xerrno = errno;
351
352
0
    destroy_pool(tmp_pool);
353
0
    errno = xerrno;
354
0
    return -1;
355
0
  }
356
357
  /* Prepend the timestamp */
358
0
  len = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm);
359
0
  buflen = len;
360
0
  buf[sizeof(buf)-1] = '\0';
361
362
  /* Convert microsecs to millisecs. */
363
0
  millis = now.tv_usec / 1000;
364
365
0
  len = pr_snprintf(buf + buflen, sizeof(buf) - len, ",%03lu ", millis);
366
0
  buflen += len;
367
368
  /* Prepend a small header */
369
0
  len = pr_snprintf(buf + buflen, sizeof(buf) - buflen, "%s[%u]: ", ident,
370
0
    (unsigned int) (session.pid ? session.pid : getpid()));
371
0
  buflen += len;
372
0
  buf[sizeof(buf)-1] = '\0';
373
374
  /* Affix the message */
375
0
  len = pr_vsnprintf(buf + buflen, sizeof(buf) - buflen - 1, fmt, msg);
376
0
  buflen += len;
377
0
  buf[sizeof(buf)-1] = '\0';
378
379
0
  if (buflen < (sizeof(buf) - 1)) {
380
0
    buf[buflen++] = '\n';
381
382
0
  } else {
383
0
    buf[sizeof(buf)-5] = '.';
384
0
    buf[sizeof(buf)-4] = '.';
385
0
    buf[sizeof(buf)-3] = '.';
386
0
    buf[sizeof(buf)-2] = '\n';
387
0
    buflen = sizeof(buf)-1;
388
0
  }
389
390
0
  pr_log_event_generate(PR_LOG_TYPE_UNSPEC, logfd, -1, buf, buflen);
391
0
  destroy_pool(tmp_pool);
392
393
0
  while (write(logfd, buf, buflen) < 0) {
394
0
    if (errno == EINTR) {
395
0
      pr_signals_handle();
396
0
      continue;
397
0
    }
398
399
0
    return -1;
400
0
  }
401
402
0
  return 0;
403
0
}
404
405
0
int pr_log_writefile(int logfd, const char *ident, const char *fmt, ...) {
406
0
  va_list msg;
407
0
  int res;
408
409
0
  if (logfd < 0) {
410
0
    errno = EINVAL;
411
0
    return -1;
412
0
  }
413
414
0
  va_start(msg, fmt);
415
0
  res = pr_log_vwritefile(logfd, ident, fmt, msg);
416
0
  va_end(msg);
417
418
0
  return res;
419
0
}
420
421
0
int log_opensyslog(const char *fn) {
422
0
  int res = 0;
423
424
0
  if (set_facility != -1) {
425
0
    facility = set_facility;
426
0
  }
427
428
0
  if (fn != NULL) {
429
0
    memset(systemlog_fn, '\0', sizeof(systemlog_fn));
430
0
    sstrncpy(systemlog_fn, fn, sizeof(systemlog_fn));
431
0
  }
432
433
0
  if (!*systemlog_fn) {
434
435
    /* The child may have inherited a valid socket from the parent. */
436
0
    pr_closelog(syslog_sockfd);
437
438
0
    syslog_sockfd = pr_openlog("proftpd", LOG_NDELAY|LOG_PID, facility);
439
0
    if (syslog_sockfd < 0) {
440
0
      int xerrno = errno;
441
442
0
      (void) pr_trace_msg(trace_channel, 1,
443
0
        "error opening syslog fd: %s", strerror(xerrno));
444
0
      errno = xerrno;
445
0
      return -1;
446
0
    }
447
448
    /* Find a usable fd for the just-opened socket fd. */
449
0
    if (syslog_sockfd <= STDERR_FILENO) {
450
0
      res = pr_fs_get_usable_fd(syslog_sockfd);
451
0
      if (res > 0) {
452
0
        (void) close(syslog_sockfd);
453
0
        syslog_sockfd = res;
454
0
      }
455
0
    }
456
457
0
    (void) fcntl(syslog_sockfd, F_SETFD, FD_CLOEXEC);
458
0
    systemlog_fd = -1;
459
460
0
  } else if ((res = pr_log_openfile(systemlog_fn, &systemlog_fd,
461
0
      PR_LOG_SYSTEM_MODE)) < 0) {
462
0
    memset(systemlog_fn, '\0', sizeof(systemlog_fn));
463
0
    return res;
464
0
  }
465
466
0
  syslog_open = TRUE;
467
0
  return 0;
468
0
}
469
470
0
void log_closesyslog(void) {
471
0
  (void) close(systemlog_fd);
472
0
  systemlog_fd = -1;
473
474
0
  (void) pr_closelog(syslog_sockfd);
475
0
  syslog_sockfd = -1;
476
477
0
  syslog_open = FALSE;
478
0
}
479
480
0
int log_getfacility(void) {
481
0
  return set_facility;
482
0
}
483
484
0
void log_setfacility(int f) {
485
0
  set_facility = f;
486
0
}
487
488
0
void log_discard(void) {
489
0
  syslog_discard = TRUE;
490
0
}
491
492
0
static size_t add_log_ts(pool *p, char *buf, size_t bufsz) {
493
0
  struct timeval now;
494
0
  struct tm *tm = NULL;
495
0
  unsigned long millis;
496
0
  size_t len;
497
498
0
  gettimeofday(&now, NULL);
499
0
  tm = pr_localtime(p, (const time_t *) &(now.tv_sec));
500
0
  if (tm == NULL) {
501
0
    return 0;
502
0
  }
503
504
0
  len = strftime(buf, bufsz-1, "%Y-%m-%d %H:%M:%S", tm);
505
0
  buf[bufsz-1] = '\0';
506
507
  /* Convert microsecs to millisecs. */
508
0
  millis = now.tv_usec / 1000;
509
510
0
  len += pr_snprintf(buf + len, bufsz - len, ",%03lu ", millis);
511
0
  return len;
512
0
}
513
514
0
static void log_write(int priority, int f, char *s, int discard) {
515
0
  int max_priority = 0, *ptr = NULL;
516
0
  char serverinfo[PR_TUNABLE_BUFFER_SIZE] = {'\0'};
517
518
0
  memset(serverinfo, '\0', sizeof(serverinfo));
519
520
0
  if (main_server != NULL &&
521
0
      main_server->ServerFQDN) {
522
0
    const pr_netaddr_t *remote_addr;
523
0
    const char *remote_name;
524
0
    size_t buflen = 0;
525
526
0
    remote_addr = pr_netaddr_get_sess_remote_addr();
527
0
    remote_name = pr_netaddr_get_sess_remote_name();
528
529
0
    if (log_opts & PR_LOG_OPT_USE_VHOST) {
530
0
      size_t len;
531
532
0
      len = pr_snprintf(serverinfo, sizeof(serverinfo)-1, "%s",
533
0
        main_server->ServerFQDN);
534
0
      buflen += len;
535
0
    }
536
537
0
    serverinfo[sizeof(serverinfo)-1] = '\0';
538
539
0
    if (remote_addr != NULL &&
540
0
        remote_name != NULL) {
541
0
      pr_snprintf(serverinfo + buflen, sizeof(serverinfo) - buflen,
542
0
        "%s(%s[%s])", (log_opts & PR_LOG_OPT_USE_VHOST) ? " " : "",
543
0
        remote_name, pr_netaddr_get_ipstr(remote_addr));
544
0
      serverinfo[sizeof(serverinfo)-1] = '\0';
545
0
    }
546
0
  }
547
548
0
  if (!discard &&
549
0
      (logstderr || !main_server)) {
550
0
    char buf[LOGBUFFER_SIZE] = {'\0'};
551
0
    size_t buflen = 0, len = 0;
552
0
    pid_t log_pid;
553
0
    const char *process_label = "proftpd";
554
555
0
    if (log_opts & PR_LOG_OPT_USE_TIMESTAMP) {
556
0
      pool *tmp_pool;
557
558
0
      tmp_pool = make_sub_pool(permanent_pool);
559
0
      pr_pool_tag(tmp_pool, "Log message pool");
560
561
0
      len = add_log_ts(tmp_pool, buf, sizeof(buf));
562
0
      destroy_pool(tmp_pool);
563
564
0
      buflen += len;
565
0
    }
566
567
0
    buf[sizeof(buf)-1] = '\0';
568
569
0
    if (log_opts & PR_LOG_OPT_USE_HOSTNAME) {
570
0
      len = pr_snprintf(buf + buflen, sizeof(buf) - buflen, "%s ",
571
0
        systemlog_host);
572
0
      buflen += len;
573
0
    }
574
575
0
    log_pid = session.pid ? session.pid : getpid();
576
577
0
    if (log_opts & PR_LOG_OPT_USE_ROLE_BASED_PROCESS_LABELS) {
578
0
      if (is_master) {
579
0
        process_label = "daemon";
580
581
0
      } else {
582
0
        process_label = "session";
583
0
      }
584
0
    }
585
586
0
    if (*serverinfo) {
587
0
      len = pr_snprintf(buf + buflen, sizeof(buf) - buflen,
588
0
        "%s[%u] %s: %s\n", process_label, (unsigned int) log_pid, serverinfo,
589
0
        s);
590
591
0
    } else {
592
0
      len = pr_snprintf(buf + buflen, sizeof(buf) - buflen,
593
0
        "%s[%u]: %s\n", process_label, (unsigned int) log_pid, s);
594
0
    }
595
596
0
    buflen += len;
597
0
    buf[sizeof(buf)-1] = '\0';
598
599
0
    pr_log_event_generate(PR_LOG_TYPE_SYSTEMLOG, STDERR_FILENO, priority,
600
0
      buf, buflen);
601
602
0
    fprintf(stderr, "%s", buf);
603
0
    fflush(stderr);
604
0
    return;
605
0
  }
606
607
0
  if (syslog_discard) {
608
    /* Only return now if we don't have any log listeners. */
609
0
    if (pr_log_event_listening(PR_LOG_TYPE_SYSLOG) <= 0 &&
610
0
        pr_log_event_listening(PR_LOG_TYPE_SYSTEMLOG) <= 0) {
611
0
      return;
612
0
    }
613
0
  }
614
615
0
  if (main_server != NULL) {
616
0
    ptr = get_param_ptr(main_server->conf, "SyslogLevel", FALSE);
617
0
  }
618
619
0
  if (ptr != NULL) {
620
0
    max_priority = *ptr;
621
622
0
  } else {
623
    /* Default SyslogLevel is NOTICE.  Note, however, that for backward
624
     * compatibility of debugging, if the DebugLevel is set higher
625
     * than DEBUG0, we will automatically ASSUME that the admin wants
626
     * the syslog level to be e.g. DEBUG.
627
     */
628
0
    max_priority = default_level;
629
0
    if (debug_level != DEBUG0) {
630
0
      max_priority = PR_LOG_DEBUG;
631
0
    }
632
0
  }
633
634
0
  if (priority > max_priority) {
635
    /* Only return now if we don't have any log listeners. */
636
0
    if (pr_log_event_listening(PR_LOG_TYPE_SYSLOG) <= 0 &&
637
0
        pr_log_event_listening(PR_LOG_TYPE_SYSTEMLOG) <= 0) {
638
0
      return;
639
0
    }
640
0
  }
641
642
0
  if (systemlog_fd != -1) {
643
0
    char buf[LOGBUFFER_SIZE] = {'\0'};
644
0
    size_t buflen = 0, len = 0;
645
0
    pid_t log_pid;
646
0
    const char *process_label = "proftpd";
647
648
0
    if (log_opts & PR_LOG_OPT_USE_TIMESTAMP) {
649
0
      pool *tmp_pool;
650
651
0
      tmp_pool = make_sub_pool(permanent_pool);
652
0
      pr_pool_tag(tmp_pool, "Log message pool");
653
654
0
      len = add_log_ts(tmp_pool, buf, sizeof(buf));
655
0
      destroy_pool(tmp_pool);
656
657
0
      buflen += len;
658
0
    }
659
660
0
    buf[sizeof(buf) - 1] = '\0';
661
662
0
    if (log_opts & PR_LOG_OPT_USE_HOSTNAME) {
663
0
      len = pr_snprintf(buf + buflen, sizeof(buf) - buflen, "%s ",
664
0
        systemlog_host);
665
0
      buflen += len;
666
0
    }
667
668
0
    log_pid = session.pid ? session.pid : getpid();
669
670
0
    if (log_opts & PR_LOG_OPT_USE_ROLE_BASED_PROCESS_LABELS) {
671
0
      if (is_master) {
672
0
        process_label = "daemon";
673
674
0
      } else {
675
0
        process_label = "session";
676
0
      }
677
0
    }
678
679
0
    if (*serverinfo) {
680
0
      len = pr_snprintf(buf + buflen, sizeof(buf) - buflen,
681
0
        "%s[%u] %s: %s\n", process_label, (unsigned int) log_pid, serverinfo,
682
0
        s);
683
684
0
    } else {
685
0
      len = pr_snprintf(buf + buflen, sizeof(buf) - buflen,
686
0
        "%s[%u]: %s\n", process_label, (unsigned int) log_pid, s);
687
0
    }
688
689
0
    buflen += len;
690
0
    buf[sizeof(buf)-1] = '\0';
691
692
0
    pr_log_event_generate(PR_LOG_TYPE_SYSTEMLOG, systemlog_fd, priority,
693
0
      buf, buflen);
694
695
    /* Now we need to enforce the discard, syslog_discard and SyslogLevel
696
     * filtering.
697
     */
698
0
    if (discard) {
699
0
      return;
700
0
    }
701
702
0
    if (syslog_discard) {
703
0
      return;
704
0
    }
705
706
0
    if (priority > max_priority) {
707
0
      return;
708
0
    }
709
710
0
    while (write(systemlog_fd, buf, buflen) < 0) {
711
0
      if (errno == EINTR) {
712
0
        pr_signals_handle();
713
0
        continue;
714
0
      }
715
716
0
      break;
717
0
    }
718
719
0
    return;
720
0
  }
721
722
0
  pr_log_event_generate(PR_LOG_TYPE_SYSLOG, syslog_sockfd, priority, s,
723
0
    strlen(s));
724
725
0
  if (set_facility != -1) {
726
0
    f = set_facility;
727
0
  }
728
729
0
  if (!syslog_open) {
730
0
    syslog_sockfd = pr_openlog("proftpd", LOG_NDELAY|LOG_PID, f);
731
0
    if (syslog_sockfd < 0) {
732
0
      (void) pr_trace_msg(trace_channel, 1,
733
0
        "error opening syslog fd: %s", strerror(errno));
734
0
      return;
735
0
    }
736
737
0
    syslog_open = TRUE;
738
739
0
  } else if (f != facility) {
740
    /* If this message is to be sent to a different log facility than a
741
     * default one (or the facility configured via SyslogFacility), then
742
     * OR in the facility with the priority value, as per the syslog(3)
743
     * docs.
744
     */
745
0
    priority |= f;
746
0
  }
747
748
0
  if (*serverinfo) {
749
0
    pr_syslog(syslog_sockfd, priority, "%s - %s\n", serverinfo, s);
750
751
0
  } else {
752
0
    pr_syslog(syslog_sockfd, priority, "%s\n", s);
753
0
  }
754
0
}
755
756
0
void pr_log_pri(int priority, const char *fmt, ...) {
757
0
  char buf[LOGBUFFER_SIZE] = {'\0'};
758
0
  va_list msg;
759
760
0
  va_start(msg, fmt);
761
0
  pr_vsnprintf(buf, sizeof(buf), fmt, msg);
762
0
  va_end(msg);
763
764
  /* Always make sure the buffer is NUL-terminated. */
765
0
  buf[sizeof(buf) - 1] = '\0';
766
767
0
  log_write(priority, facility, buf, FALSE);
768
0
}
769
770
/* Like pr_log_pri(), but sends the log entry in the LOG_AUTHPRIV
771
 * facility (presumably it doesn't need to be seen by everyone).
772
 */
773
0
void pr_log_auth(int priority, const char *fmt, ...) {
774
0
  char buf[LOGBUFFER_SIZE] = {'\0'};
775
0
  va_list msg;
776
777
0
  va_start(msg, fmt);
778
0
  pr_vsnprintf(buf, sizeof(buf), fmt, msg);
779
0
  va_end(msg);
780
781
  /* Always make sure the buffer is NUL-terminated. */
782
0
  buf[sizeof(buf) - 1] = '\0';
783
784
0
  log_write(priority, LOG_AUTHPRIV, buf, FALSE);
785
0
}
786
787
/* Disable logging to stderr, should be done right before forking
788
 * or disassociation from controlling tty.  After disabling stderr
789
 * logging, all messages go to syslog.
790
 */
791
0
void log_stderr(int bool) {
792
0
  logstderr = bool;
793
0
}
794
795
/* Set the debug logging level; see log.h for constants.  Higher
796
 * numbers mean print more, DEBUG0 (0) == print no debugging log
797
 * (default)
798
 */
799
0
int pr_log_setdebuglevel(int level) {
800
0
  int old_level = debug_level;
801
0
  debug_level = level;
802
0
  return old_level;
803
0
}
804
805
/* Set the default logging level; see log.h for constants. */
806
0
int pr_log_setdefaultlevel(int level) {
807
0
  int old_level = default_level;
808
0
  default_level = level;
809
0
  return old_level;
810
0
}
811
812
0
int pr_log_set_options(unsigned long opts) {
813
0
  log_opts = opts;
814
0
  return 0;
815
0
}
816
817
/* Convert a string into the matching syslog level value.  Return -1
818
 * if no matching level is found.
819
 */
820
0
int pr_log_str2sysloglevel(const char *name) {
821
822
0
  if (strcasecmp(name, "emerg") == 0) {
823
0
    return PR_LOG_EMERG;
824
0
  }
825
826
0
  if (strcasecmp(name, "alert") == 0) {
827
0
    return PR_LOG_ALERT;
828
0
  }
829
830
0
  if (strcasecmp(name, "crit") == 0) {
831
0
    return PR_LOG_CRIT;
832
0
  }
833
834
0
  if (strcasecmp(name, "error") == 0) {
835
0
    return PR_LOG_ERR;
836
0
  }
837
838
0
  if (strcasecmp(name, "warn") == 0) {
839
0
    return PR_LOG_WARNING;
840
0
  }
841
842
0
  if (strcasecmp(name, "notice") == 0) {
843
0
    return PR_LOG_NOTICE;
844
0
  }
845
846
0
  if (strcasecmp(name, "info") == 0) {
847
0
    return PR_LOG_INFO;
848
0
  }
849
850
0
  if (strcasecmp(name, "debug") == 0) {
851
0
    return PR_LOG_DEBUG;
852
0
  }
853
854
0
  errno = ENOENT;
855
0
  return -1;
856
0
}
857
858
0
void pr_log_debug(int level, const char *fmt, ...) {
859
0
  char buf[LOGBUFFER_SIZE] = {'\0'};
860
0
  va_list msg;
861
0
  int discard = FALSE;
862
863
0
  if (debug_level < level) {
864
0
    discard = TRUE;
865
866
0
    if (pr_log_event_listening(PR_LOG_TYPE_SYSLOG) <= 0 &&
867
0
        pr_log_event_listening(PR_LOG_TYPE_SYSTEMLOG) <= 0) {
868
0
      return;
869
0
    }
870
0
  }
871
872
0
  if (fmt == NULL) {
873
0
    return;
874
0
  }
875
876
0
  memset(buf, '\0', sizeof(buf));
877
0
  va_start(msg, fmt);
878
0
  pr_vsnprintf(buf, sizeof(buf), fmt, msg);
879
0
  va_end(msg);
880
881
  /* Always make sure the buffer is NUL-terminated. */
882
0
  buf[sizeof(buf) - 1] = '\0';
883
884
0
  log_write(PR_LOG_DEBUG, facility, buf, discard);
885
0
}
886
887
1.42k
static const char *get_log_event_name(unsigned int log_type) {
888
1.42k
  const char *event_name = NULL;
889
890
1.42k
  switch (log_type) {
891
0
    case PR_LOG_TYPE_UNSPEC:
892
0
      event_name = PR_LOG_NAME_UNSPEC;
893
0
      break;
894
895
0
    case PR_LOG_TYPE_XFERLOG:
896
0
      event_name = PR_LOG_NAME_XFERLOG;
897
0
      break;
898
899
0
    case PR_LOG_TYPE_SYSLOG:
900
0
      event_name = PR_LOG_NAME_SYSLOG;
901
0
      break;
902
903
0
    case PR_LOG_TYPE_SYSTEMLOG:
904
0
      event_name = PR_LOG_NAME_SYSTEMLOG;
905
0
      break;
906
907
0
    case PR_LOG_TYPE_EXTLOG:
908
0
      event_name = PR_LOG_NAME_EXTLOG;
909
0
      break;
910
911
1.42k
    case PR_LOG_TYPE_TRACELOG:
912
1.42k
      event_name = PR_LOG_NAME_TRACELOG;
913
1.42k
      break;
914
915
0
    default:
916
0
      errno = EINVAL;
917
0
      return NULL;
918
1.42k
  }
919
920
1.42k
  return event_name;
921
1.42k
}
922
923
int pr_log_event_generate(unsigned int log_type, int log_fd, int log_level,
924
0
    const char *log_msg, size_t log_msglen) {
925
0
  const char *event_name;
926
0
  pr_log_event_t le;
927
928
0
  if (log_msg == NULL ||
929
0
      log_msglen == 0) {
930
0
    errno = EINVAL;
931
0
    return -1;
932
0
  }
933
934
0
  if (pr_log_event_listening(log_type) <= 0) {
935
0
    errno = ENOENT;
936
0
    return -1;
937
0
  }
938
939
0
  event_name = get_log_event_name(log_type);
940
941
0
  memset(&le, 0, sizeof(le));
942
0
  le.log_type = log_type;
943
0
  le.log_fd = log_fd;
944
0
  le.log_level = log_level;
945
0
  le.log_msg = log_msg;
946
0
  le.log_msglen = log_msglen;
947
948
0
  pr_event_generate(event_name, &le);
949
0
  return 0;
950
0
}
951
952
1.42k
int pr_log_event_listening(unsigned int log_type) {
953
1.42k
  const char *event_name;
954
1.42k
  int res;
955
956
1.42k
  event_name = get_log_event_name(log_type);
957
1.42k
  if (event_name == NULL) {
958
0
    return FALSE;
959
0
  }
960
961
1.42k
  res = pr_event_listening(event_name);
962
1.42k
  if (res <= 0) {
963
1.42k
    return FALSE;
964
1.42k
  }
965
966
0
  return TRUE;
967
1.42k
}
968
969
0
void pr_log_stacktrace(int log_fd, const char *name) {
970
0
#if defined(HAVE_EXECINFO_H) && \
971
0
    defined(HAVE_BACKTRACE) && \
972
0
    defined(HAVE_BACKTRACE_SYMBOLS)
973
0
  void *trace[PR_TUNABLE_CALLER_DEPTH];
974
0
  int tracesz, use_fd = TRUE;
975
976
0
  if (log_fd < 0 ||
977
0
      name == NULL) {
978
0
    use_fd = FALSE;
979
0
  }
980
981
0
  if (use_fd) {
982
0
    (void) pr_log_writefile(log_fd, name, "%s", "-----BEGIN STACK TRACE-----");
983
984
0
  } else {
985
0
    (void) pr_log_pri(PR_LOG_WARNING, "-----BEGIN STACK TRACE-----");
986
0
  }
987
988
0
  tracesz = backtrace(trace, PR_TUNABLE_CALLER_DEPTH);
989
0
  if (tracesz < 0) {
990
0
    if (use_fd) {
991
0
      (void) pr_log_writefile(log_fd, name, "backtrace(3) error: %s",
992
0
        strerror(errno));
993
994
0
    } else {
995
0
      (void) pr_log_pri(PR_LOG_WARNING, "backtrace(3) error: %s",
996
0
        strerror(errno));
997
0
    }
998
999
0
  } else {
1000
0
    char **strings;
1001
1002
0
    strings = backtrace_symbols(trace, tracesz);
1003
0
    if (strings != NULL) {
1004
0
      register int i;
1005
1006
0
      for (i = 1; i < tracesz; i++) {
1007
0
        if (use_fd) {
1008
0
          (void) pr_log_writefile(log_fd, name, "[%d] %s", i-1, strings[i]);
1009
1010
0
        } else {
1011
0
          (void) pr_log_pri(PR_LOG_WARNING, "[%d] %s", i-1, strings[i]);
1012
0
        }
1013
0
      }
1014
1015
      /* Prevent memory leaks. */
1016
0
      free(strings);
1017
1018
0
    } else {
1019
0
      if (use_fd) {
1020
0
        (void) pr_log_writefile(log_fd, name,
1021
0
          "error obtaining backtrace symbols: %s", strerror(errno));
1022
1023
0
      } else {
1024
0
        (void) pr_log_pri(PR_LOG_WARNING,
1025
0
          "error obtaining backtrace symbols: %s", strerror(errno));
1026
0
      }
1027
0
    }
1028
0
  }
1029
1030
0
  if (use_fd) {
1031
0
    (void) pr_log_writefile(log_fd, name, "%s", "-----END STACK TRACE-----");
1032
1033
0
  } else {
1034
0
    (void) pr_log_pri(PR_LOG_WARNING, "%s", "-----END STACK TRACE-----");
1035
0
  }
1036
0
#endif
1037
0
}
1038
1039
0
void init_log(void) {
1040
0
  char buf[256];
1041
1042
0
  memset(buf, '\0', sizeof(buf));
1043
0
  if (gethostname(buf, sizeof(buf)) < 0) {
1044
0
    sstrncpy(buf, "localhost", sizeof(buf));
1045
0
  }
1046
1047
0
  sstrncpy(systemlog_host, (char *) pr_netaddr_validate_dns_str(buf),
1048
0
    sizeof(systemlog_host));
1049
0
  memset(systemlog_fn, '\0', sizeof(systemlog_fn));
1050
0
  log_closesyslog();
1051
0
}