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