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