1 /**
2  * xrdp: A Remote Desktop Protocol server.
3  *
4  * Copyright (C) Jay Sorg 2004-2014
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #if defined(HAVE_CONFIG_H)
20 #include <config_ac.h>
21 #endif
22 
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <syslog.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <time.h>
30 #include "list.h"
31 #include "file.h"
32 #include "os_calls.h"
33 #include "thread_calls.h"
34 #include "string_calls.h"
35 
36 /* Add a define here so that the log.h will hold more information
37  * when compiled from this C file.
38  * When compiled normally the log.h file only contain the public parts
39  * of the operators in this file. */
40 #define LOGINTERNALSTUFF
41 #include "log.h"
42 
43 /* Here we store the current state and configuration of the log */
44 static struct log_config *g_staticLogConfig = NULL;
45 
46 /* This file first start with all private functions.
47    In the end of the file the public functions is defined */
48 
49 /**
50  *
51  * @brief Opens log file
52  * @param fname log file name
53  * @return see open(2) return values
54  *
55  */
56 int
internal_log_file_open(const char * fname)57 internal_log_file_open(const char *fname)
58 {
59     int ret = -1;
60 
61     if (fname != NULL)
62     {
63         ret = open(fname, O_WRONLY | O_CREAT | O_APPEND | O_SYNC,
64                    S_IRUSR | S_IWUSR);
65     }
66 
67 #ifdef FD_CLOEXEC
68     if (ret != -1)
69     {
70         fcntl(ret, F_SETFD, FD_CLOEXEC);
71     }
72 #endif
73 
74     return ret;
75 }
76 
77 /**
78  *
79  * @brief Converts xrdp log level to syslog logging level
80  * @param xrdp logging level
81  * @return syslog equivalent logging level
82  *
83  */
84 int
internal_log_xrdp2syslog(const enum logLevels lvl)85 internal_log_xrdp2syslog(const enum logLevels lvl)
86 {
87     switch (lvl)
88     {
89         case LOG_LEVEL_ALWAYS:
90             return LOG_CRIT;
91         case LOG_LEVEL_ERROR:
92             return LOG_ERR;
93         case LOG_LEVEL_WARNING:
94             return LOG_WARNING;
95         case LOG_LEVEL_INFO:
96             return LOG_INFO;
97         case LOG_LEVEL_DEBUG:
98         case LOG_LEVEL_TRACE:
99             return LOG_DEBUG;
100         default:
101             g_writeln("Undefined log level - programming error");
102             return LOG_DEBUG;
103     }
104 }
105 
106 /**
107  * @brief Converts xrdp log levels to textual logging levels
108  * @param lvl logging level
109  * @param str pointer to a string, must be allocated before
110  * @return The log string in str pointer.
111  *
112  */
113 void
internal_log_lvl2str(const enum logLevels lvl,char * str)114 internal_log_lvl2str(const enum logLevels lvl, char *str)
115 {
116     switch (lvl)
117     {
118         case LOG_LEVEL_ALWAYS:
119             snprintf(str, 9, "%s", "[CORE ] ");
120             break;
121         case LOG_LEVEL_ERROR:
122             snprintf(str, 9, "%s", "[ERROR] ");
123             break;
124         case LOG_LEVEL_WARNING:
125             snprintf(str, 9, "%s", "[WARN ] ");
126             break;
127         case LOG_LEVEL_INFO:
128             snprintf(str, 9, "%s", "[INFO ] ");
129             break;
130         case LOG_LEVEL_DEBUG:
131             snprintf(str, 9, "%s", "[DEBUG] ");
132             break;
133         case LOG_LEVEL_TRACE:
134             snprintf(str, 9, "%s", "[TRACE] ");
135             break;
136         default:
137             snprintf(str, 9, "%s", "PRG ERR!");
138             g_writeln("Programming error - undefined log level!!!");
139     }
140 }
141 
142 /******************************************************************************/
143 enum logReturns
internal_log_start(struct log_config * l_cfg)144 internal_log_start(struct log_config *l_cfg)
145 {
146     enum logReturns ret = LOG_GENERAL_ERROR;
147 
148     if (0 == l_cfg)
149     {
150         ret = LOG_ERROR_MALLOC;
151         return ret;
152     }
153 
154     /* if progname is NULL, we return error */
155     if (0 == l_cfg->program_name)
156     {
157         g_writeln("program_name not properly assigned");
158         return ret;
159     }
160 
161     if (l_cfg->dump_on_start)
162     {
163         internal_log_config_dump(l_cfg);
164     }
165 
166     /* open file */
167     if (l_cfg->log_file != NULL)
168     {
169         l_cfg->fd = internal_log_file_open(l_cfg->log_file);
170 
171         if (-1 == l_cfg->fd)
172         {
173             return LOG_ERROR_FILE_OPEN;
174         }
175     }
176 
177     /* if syslog is enabled, open it */
178     if (l_cfg->enable_syslog)
179     {
180         openlog(l_cfg->program_name, LOG_CONS | LOG_PID, LOG_DAEMON);
181     }
182 
183 #ifdef LOG_ENABLE_THREAD
184     pthread_mutexattr_init(&(l_cfg->log_lock_attr));
185     pthread_mutex_init(&(l_cfg->log_lock), &(l_cfg->log_lock_attr));
186 #endif
187 
188     return LOG_STARTUP_OK;
189 }
190 
191 /******************************************************************************/
192 enum logReturns
internal_log_end(struct log_config * l_cfg)193 internal_log_end(struct log_config *l_cfg)
194 {
195     enum logReturns ret = LOG_GENERAL_ERROR;
196 
197     /* if log is closed, quit silently */
198     if (0 == l_cfg)
199     {
200         return ret;
201     }
202 
203     if (-1 != l_cfg->fd)
204     {
205         /* closing logfile... */
206         g_file_close(l_cfg->fd);
207     }
208 
209     /* if syslog is enabled, close it */
210     if (l_cfg->enable_syslog)
211     {
212         closelog();
213     }
214 
215     /* freeing allocated memory */
216     if (0 != l_cfg->log_file)
217     {
218         g_free(l_cfg->log_file);
219         l_cfg->log_file = 0;
220     }
221 
222     ret = LOG_STARTUP_OK;
223     return ret;
224 }
225 
226 /**
227  * Converts a string representing th log level to a value
228  * @param buf
229  * @return
230  */
231 enum logLevels
internal_log_text2level(const char * buf)232 internal_log_text2level(const char *buf)
233 {
234     if (0 == g_strcasecmp(buf, "0") ||
235             0 == g_strcasecmp(buf, "core"))
236     {
237         return LOG_LEVEL_ALWAYS;
238     }
239     else if (0 == g_strcasecmp(buf, "1") ||
240              0 == g_strcasecmp(buf, "error"))
241     {
242         return LOG_LEVEL_ERROR;
243     }
244     else if (0 == g_strcasecmp(buf, "2") ||
245              0 == g_strcasecmp(buf, "warn") ||
246              0 == g_strcasecmp(buf, "warning"))
247     {
248         return LOG_LEVEL_WARNING;
249     }
250     else if (0 == g_strcasecmp(buf, "3") ||
251              0 == g_strcasecmp(buf, "info"))
252     {
253         return LOG_LEVEL_INFO;
254     }
255     else if (0 == g_strcasecmp(buf, "4") ||
256              0 == g_strcasecmp(buf, "debug"))
257     {
258         return LOG_LEVEL_DEBUG;
259     }
260     else if (0 == g_strcasecmp(buf, "5") ||
261              0 == g_strcasecmp(buf, "trace"))
262     {
263         return LOG_LEVEL_TRACE;
264     }
265 
266     g_writeln("Your configured log level is corrupt - we use debug log level");
267     return LOG_LEVEL_DEBUG;
268 }
269 
270 /******************************************************************************/
271 struct log_config *
internal_config_read_logging(int file,const char * applicationName,const char * section_prefix)272 internal_config_read_logging(int file,
273                              const char *applicationName,
274                              const char *section_prefix)
275 {
276     int i;
277     char *buf;
278     char *temp_buf;
279     char section_name[512];
280     struct log_config *lc;
281     struct list *param_n;
282     struct list *param_v;
283 
284     lc = internalInitAndAllocStruct();
285     if (lc == NULL)
286     {
287         return NULL;
288     }
289 
290     param_n = list_create();
291     param_n->auto_free = 1;
292     param_v = list_create();
293     param_v->auto_free = 1;
294 
295     list_clear(param_v);
296     list_clear(param_n);
297 
298     /* setting defaults */
299     lc->program_name = applicationName;
300     lc->log_file = 0;
301     lc->fd = -1;
302     lc->log_level = LOG_LEVEL_INFO;
303     lc->enable_console = 0;
304     lc->console_level = LOG_LEVEL_INFO;
305     lc->enable_syslog = 0;
306     lc->syslog_level = LOG_LEVEL_INFO;
307     lc->dump_on_start = 0;
308     lc->enable_pid = 0;
309 
310     g_snprintf(section_name, 511, "%s%s", section_prefix, SESMAN_CFG_LOGGING);
311     file_read_section(file, section_name, param_n, param_v);
312 
313     for (i = 0; i < param_n->count; i++)
314     {
315         buf = (char *)list_get_item(param_n, i);
316 
317         if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_FILE))
318         {
319             lc->log_file = g_strdup((char *)list_get_item(param_v, i));
320 
321             if (lc->log_file != NULL)
322             {
323                 if (lc->log_file[0] != '/')
324                 {
325                     temp_buf = (char *)g_malloc(512, 0);
326                     g_snprintf(temp_buf, 511, "%s/%s", XRDP_LOG_PATH, lc->log_file);
327                     g_free(lc->log_file);
328                     lc->log_file = temp_buf;
329                 }
330             }
331         }
332 
333         if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_LEVEL))
334         {
335             lc->log_level = internal_log_text2level((char *)list_get_item(param_v, i));
336         }
337 
338         if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_SYSLOG))
339         {
340             lc->enable_syslog = g_text2bool((char *)list_get_item(param_v, i));
341         }
342 
343         if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_SYSLOG_LEVEL))
344         {
345             lc->syslog_level = internal_log_text2level((char *)list_get_item(param_v, i));
346         }
347 
348         if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_CONSOLE))
349         {
350             lc->enable_console = g_text2bool((char *)list_get_item(param_v, i));
351         }
352 
353         if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_CONSOLE_LEVEL))
354         {
355             lc->console_level = internal_log_text2level((char *)list_get_item(param_v, i));
356         }
357 
358         if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_PID))
359         {
360             lc->enable_pid = g_text2bool((char *)list_get_item(param_v, i));
361         }
362     }
363 
364     if (0 == lc->log_file)
365     {
366         lc->log_file = g_strdup("./sesman.log");
367     }
368 
369     /* try to create path if not exist */
370     g_create_path(lc->log_file);
371 
372 #ifdef LOG_PER_LOGGER_LEVEL
373     int len;
374     struct log_logger_level *logger;
375 
376     list_clear(param_v);
377     list_clear(param_n);
378     g_snprintf(section_name, 511, "%s%s", section_prefix, SESMAN_CFG_LOGGING_LOGGER);
379     file_read_section(file, section_name, param_n, param_v);
380     for (i = 0; i < param_n->count; i++)
381     {
382         logger = (struct log_logger_level *)g_malloc(sizeof(struct log_logger_level), 1);
383         list_add_item(lc->per_logger_level, (tbus) logger);
384         logger->log_level = internal_log_text2level((char *)list_get_item(param_v, i));
385 
386         g_strncpy(logger->logger_name, (char *)list_get_item(param_n, i), LOGGER_NAME_SIZE);
387         logger->logger_name[LOGGER_NAME_SIZE] = '\0';
388         len = g_strlen(logger->logger_name);
389         if (len >= 2
390                 && logger->logger_name[len - 2] == '('
391                 && logger->logger_name[len - 1] == ')' )
392         {
393             logger->logger_type = LOG_TYPE_FUNCTION;
394             logger->logger_name[len - 2] = '\0';
395         }
396         else
397         {
398             logger->logger_type = LOG_TYPE_FILE;
399         }
400     }
401 #endif
402 
403     list_delete(param_v);
404     list_delete(param_n);
405     return lc;
406 }
407 
408 void
internal_log_config_dump(struct log_config * config)409 internal_log_config_dump(struct log_config *config)
410 {
411     char str_level[20];
412 #ifdef LOG_PER_LOGGER_LEVEL
413     struct log_logger_level *logger;
414     int i;
415 #endif
416 
417     g_printf("logging configuration:\r\n");
418     if (config->log_file)
419     {
420         internal_log_lvl2str(config->log_level, str_level);
421         g_printf("\tLogFile:       %s\r\n", config->log_file);
422         g_printf("\tLogLevel:      %s\r\n", str_level);
423     }
424     else
425     {
426         g_printf("\tLogFile:       %s\r\n", "<disabled>");
427     }
428 
429     if (config->enable_console)
430     {
431         internal_log_lvl2str(config->console_level, str_level);
432     }
433     else
434     {
435         g_strcpy(str_level, "<disabled>");
436     }
437     g_printf("\tConsoleLevel:  %s\r\n", str_level);
438 
439     if (config->enable_syslog)
440     {
441         internal_log_lvl2str(config->syslog_level, str_level);
442     }
443     else
444     {
445         g_strcpy(str_level, "<disabled>");
446     }
447     g_printf("\tSyslogLevel:   %s\r\n", str_level);
448 
449 #ifdef LOG_PER_LOGGER_LEVEL
450     g_printf("per logger configuration:\r\n");
451     for (i = 0; i < config->per_logger_level->count; i++)
452     {
453         logger = (struct log_logger_level *)list_get_item(config->per_logger_level, i);
454         internal_log_lvl2str(logger->log_level, str_level);
455         g_printf("\t%-*s: %s\r\n", LOGGER_NAME_SIZE, logger->logger_name, str_level);
456     }
457     if (config->per_logger_level->count == 0)
458     {
459         g_printf("\tNone\r\n");
460     }
461 #endif
462 }
463 
464 struct log_config *
internalInitAndAllocStruct(void)465 internalInitAndAllocStruct(void)
466 {
467     struct log_config *ret = g_new0(struct log_config, 1);
468 
469     if (ret != NULL)
470     {
471         ret->fd = -1;
472         ret->enable_syslog = 0;
473         ret->per_logger_level = list_create();
474         if (ret->per_logger_level != NULL)
475         {
476             ret->per_logger_level->auto_free = 1;
477         }
478         else
479         {
480             g_writeln("could not allocate memory for log struct");
481             g_free(ret);
482             ret = NULL;
483         }
484     }
485     else
486     {
487         g_writeln("could not allocate memory for log struct");
488     }
489 
490     return ret;
491 }
492 
493 void
internal_log_config_copy(struct log_config * dest,const struct log_config * src)494 internal_log_config_copy(struct log_config *dest, const struct log_config *src)
495 {
496     int i;
497 
498     dest->enable_syslog = src->enable_syslog;
499     dest->fd = src->fd;
500     dest->log_file = g_strdup(src->log_file);
501     dest->log_level = src->log_level;
502     dest->log_lock = src->log_lock;
503     dest->log_lock_attr = src->log_lock_attr;
504     dest->program_name = src->program_name;
505     dest->enable_syslog = src->enable_syslog;
506     dest->syslog_level = src->syslog_level;
507     dest->enable_console = src->enable_console;
508     dest->console_level = src->console_level;
509     dest->enable_pid = src->enable_pid;
510     dest->dump_on_start = src->dump_on_start;
511     for (i = 0; i < src->per_logger_level->count; ++i)
512     {
513         struct log_logger_level *dst_logger =
514             (struct log_logger_level *)g_malloc(sizeof(struct log_logger_level), 1);
515 
516         g_memcpy(dst_logger,
517                  (struct log_logger_level *) list_get_item(src->per_logger_level, i),
518                  sizeof(struct log_logger_level));
519 
520         list_add_item(dest->per_logger_level, (tbus) dst_logger);
521     }
522 }
523 
524 bool_t
internal_log_is_enabled_for_level(const enum logLevels log_level,const bool_t override_destination_level,const enum logLevels override_log_level)525 internal_log_is_enabled_for_level(const enum logLevels log_level,
526                                   const bool_t override_destination_level,
527                                   const enum logLevels override_log_level)
528 {
529     /* Is log initialized? */
530     if (g_staticLogConfig == NULL)
531     {
532         return 0;
533     }
534     else if (g_staticLogConfig->fd < 0
535              && !g_staticLogConfig->enable_syslog
536              && !g_staticLogConfig->enable_console)
537     {
538         /* all logging outputs are disabled */
539         return 0;
540     }
541     else if (override_destination_level)
542     {
543         /* Override is enabled - should the message should be logged? */
544         return log_level <= override_log_level;
545     }
546     /* Override is disabled - Is there at least one log destination
547      * which will accept the message based on the log level? */
548     else if (g_staticLogConfig->fd >= 0
549              && log_level <= g_staticLogConfig->log_level)
550     {
551         return 1;
552     }
553     else if (g_staticLogConfig->enable_syslog
554              && log_level <= g_staticLogConfig->syslog_level)
555     {
556         return 1;
557     }
558     else if (g_staticLogConfig->enable_console
559              && log_level <= g_staticLogConfig->console_level)
560     {
561         return 1;
562     }
563     else
564     {
565         return 0;
566     }
567 }
568 
569 bool_t
internal_log_location_overrides_level(const char * function_name,const char * file_name,enum logLevels * log_level_return)570 internal_log_location_overrides_level(const char *function_name,
571                                       const char *file_name,
572                                       enum logLevels *log_level_return)
573 {
574     struct log_logger_level *logger = NULL;
575     int i;
576 
577     if (g_staticLogConfig == NULL)
578     {
579         return 0;
580     }
581     for (i = 0; i < g_staticLogConfig->per_logger_level->count; i++)
582     {
583         logger = (struct log_logger_level *)list_get_item(g_staticLogConfig->per_logger_level, i);
584 
585         if ((logger->logger_type == LOG_TYPE_FILE
586                 && 0 == g_strncmp(logger->logger_name, file_name, LOGGER_NAME_SIZE))
587                 || (logger->logger_type == LOG_TYPE_FUNCTION
588                     && 0 == g_strncmp(logger->logger_name, function_name, LOGGER_NAME_SIZE)))
589         {
590             *log_level_return = logger->log_level;
591             return 1;
592         }
593     }
594 
595     return 0;
596 }
597 
598 /*
599  * Here below the public functions
600  */
601 
602 struct log_config *
log_config_init_for_console(enum logLevels lvl,const char * override_name)603 log_config_init_for_console(enum logLevels lvl, const char *override_name)
604 {
605     struct log_config *config = internalInitAndAllocStruct();
606 
607     if (config != NULL)
608     {
609         config->program_name = "<null>";
610         config->enable_console = 1;
611         if (override_name != NULL && override_name[0] != '\0')
612         {
613             config->console_level = internal_log_text2level(override_name);
614         }
615         else
616         {
617             config->console_level = lvl;
618         }
619     }
620     return config;
621 }
622 
623 
624 struct log_config *
log_config_init_from_config(const char * iniFilename,const char * applicationName,const char * section_prefix)625 log_config_init_from_config(const char *iniFilename,
626                             const char *applicationName,
627                             const char *section_prefix)
628 {
629     int fd;
630     struct log_config *config;
631 
632     if (applicationName == NULL)
633     {
634         g_writeln("Programming error your application name cannot be null");
635         return NULL;
636     }
637 
638     if (iniFilename == NULL)
639     {
640         g_writeln("The inifile is null to log_config_init_from_config!");
641         return NULL;
642     }
643 
644     fd = g_file_open_ex(iniFilename, 1, 0, 0, 0);
645 
646     if (-1 == fd)
647     {
648         g_writeln("We could not open the configuration file to read log parameters");
649         return NULL;
650     }
651 
652     /* read logging config */
653     config = internal_config_read_logging(fd, applicationName, section_prefix);
654 
655     /* cleanup */
656     g_file_close(fd);
657     return config;
658 }
659 
660 enum logReturns
log_config_free(struct log_config * config)661 log_config_free(struct log_config *config)
662 {
663     if (config != NULL)
664     {
665         if (config->per_logger_level != NULL)
666         {
667             list_delete(config->per_logger_level);
668             config->per_logger_level = NULL;
669         }
670         g_free(config);
671     }
672 
673     return LOG_STARTUP_OK;
674 }
675 
676 enum logReturns
log_start_from_param(const struct log_config * src_log_config)677 log_start_from_param(const struct log_config *src_log_config)
678 {
679     enum logReturns ret = LOG_GENERAL_ERROR;
680 
681     if (g_staticLogConfig != NULL)
682     {
683         log_message(LOG_LEVEL_ALWAYS, "Log already initialized");
684         return ret;
685     }
686 
687     if (src_log_config == NULL)
688     {
689         g_writeln("src_log_config to log_start_from_param is NULL");
690         return ret;
691     }
692     else
693     {
694         g_staticLogConfig = internalInitAndAllocStruct();
695         if (g_staticLogConfig == NULL)
696         {
697             g_writeln("internalInitAndAllocStruct failed");
698             return LOG_ERROR_MALLOC;
699         }
700         internal_log_config_copy(g_staticLogConfig, src_log_config);
701 
702         ret = internal_log_start(g_staticLogConfig);
703         if (ret != LOG_STARTUP_OK)
704         {
705             g_writeln("Could not start log");
706 
707             log_config_free(g_staticLogConfig);
708             g_staticLogConfig = NULL;
709         }
710     }
711 
712     return ret;
713 }
714 
715 /**
716  * This function initialize the log facilities according to the configuration
717  * file, that is described by the in parameter.
718  * @param iniFile
719  * @param applicationName, the name that is used in the log for the running application
720  * @return 0 on success
721  */
722 enum logReturns
log_start(const char * iniFile,const char * applicationName,bool_t dump_on_start)723 log_start(const char *iniFile, const char *applicationName,
724           bool_t dump_on_start)
725 {
726     enum logReturns ret = LOG_GENERAL_ERROR;
727     struct log_config *config;
728 
729     config = log_config_init_from_config(iniFile, applicationName, "");
730 
731     if (config != NULL)
732     {
733         config->dump_on_start = dump_on_start;
734         ret = log_start_from_param(config);
735         log_config_free(config);
736 
737         if (ret != LOG_STARTUP_OK)
738         {
739             g_writeln("Could not start log");
740         }
741     }
742     else
743     {
744         g_writeln("Error reading configuration for log based on config: %s",
745                   iniFile);
746     }
747 
748     return ret;
749 }
750 
751 /**
752  * Function that terminates all logging
753  * @return
754  */
755 enum logReturns
log_end(void)756 log_end(void)
757 {
758     enum logReturns ret = LOG_GENERAL_ERROR;
759     ret = internal_log_end(g_staticLogConfig);
760     log_config_free(g_staticLogConfig);
761     g_staticLogConfig = NULL;
762 
763     return ret;
764 }
765 
766 /*****************************************************************************/
767 /* log a hex dump */
768 enum logReturns
log_hexdump(const enum logLevels log_level,const char * message,const char * src,int len)769 log_hexdump(const enum logLevels log_level,
770             const char *message,
771             const char *src,
772             int len)
773 {
774     return log_hexdump_with_location("", "", 0, log_level, message, src, len);
775 }
776 
777 /*****************************************************************************/
778 /* log a hex dump */
779 enum logReturns
log_hexdump_with_location(const char * function_name,const char * file_name,const int line_number,const enum logLevels log_level,const char * message,const char * src,int len)780 log_hexdump_with_location(const char *function_name,
781                           const char *file_name,
782                           const int line_number,
783                           const enum logLevels log_level,
784                           const char *message,
785                           const char *src,
786                           int len)
787 {
788     char *dump_buffer;
789     enum logReturns rv = LOG_STARTUP_OK;
790     enum logLevels override_log_level;
791     bool_t override_destination_level = 0;
792 
793     override_destination_level = internal_log_location_overrides_level(
794         function_name,
795         file_name,
796         &override_log_level);
797     if (!internal_log_is_enabled_for_level(log_level, override_destination_level, override_log_level))
798     {
799         return LOG_STARTUP_OK;
800     }
801 
802     /* Start the dump on a new line so that the first line of the dump is
803        aligned to the first column instead of to after the log message
804        preamble (eg. time, log level, ...)
805     */
806 #ifdef _WIN32
807 #define HEX_DUMP_HEADER ("Hex Dump:\r\n")
808 #else
809 #ifdef _MACOS
810 #define HEX_DUMP_HEADER ("Hex Dump:\r")
811 #else
812 #define HEX_DUMP_HEADER ("Hex Dump:\n")
813 #endif
814 #endif
815 
816     dump_buffer = g_bytes_to_hexdump(src, len);
817 
818     if (dump_buffer != NULL)
819     {
820         if (g_strlen(file_name) > 0)
821         {
822             rv = log_message_with_location(function_name, file_name, line_number,
823                                            log_level, "%s %s%s",
824                                            message, HEX_DUMP_HEADER, dump_buffer);
825         }
826         else
827         {
828             rv = log_message(log_level, "%s %s%s",
829                              message, HEX_DUMP_HEADER, dump_buffer);
830         }
831         g_free(dump_buffer);
832     }
833     return rv;
834 }
835 
836 enum logReturns
log_message_with_location(const char * function_name,const char * file_name,const int line_number,const enum logLevels level,const char * msg,...)837 log_message_with_location(const char *function_name,
838                           const char *file_name,
839                           const int line_number,
840                           const enum logLevels level,
841                           const char *msg,
842                           ...)
843 {
844     va_list ap;
845     enum logReturns rv;
846     char buff[LOG_BUFFER_SIZE];
847     enum logLevels override_log_level = LOG_LEVEL_NEVER;
848     bool_t override_destination_level = 0;
849 
850     if (g_staticLogConfig == NULL)
851     {
852         g_writeln("The log reference is NULL - log not initialized properly "
853                   "when called from [%s(%s:%d)]",
854                   (function_name != NULL ? function_name : "unknown_function"),
855                   (file_name != NULL ? file_name : "unknown_file"),
856                   line_number);
857         return LOG_ERROR_NO_CFG;
858     }
859 
860     override_destination_level = internal_log_location_overrides_level(
861         function_name,
862         file_name,
863         &override_log_level);
864     if (!internal_log_is_enabled_for_level(level, override_destination_level, override_log_level))
865     {
866         return LOG_STARTUP_OK;
867     }
868 
869     g_snprintf(buff, LOG_BUFFER_SIZE, "[%s(%s:%d)] %s",
870                function_name, file_name, line_number, msg);
871 
872     va_start(ap, msg);
873     rv = internal_log_message(level, override_destination_level, override_log_level, buff, ap);
874     va_end(ap);
875     return rv;
876 }
877 
878 enum logReturns
log_message(const enum logLevels lvl,const char * msg,...)879 log_message(const enum logLevels lvl, const char *msg, ...)
880 {
881     va_list ap;
882     enum logReturns rv;
883 
884     va_start(ap, msg);
885     rv = internal_log_message(lvl, 0, LOG_LEVEL_NEVER, msg, ap);
886     va_end(ap);
887     return rv;
888 }
889 
890 enum logReturns
internal_log_message(const enum logLevels lvl,const bool_t override_destination_level,const enum logLevels override_log_level,const char * msg,va_list ap)891 internal_log_message(const enum logLevels lvl,
892                      const bool_t override_destination_level,
893                      const enum logLevels override_log_level,
894                      const char *msg,
895                      va_list ap)
896 {
897     char buff[LOG_BUFFER_SIZE + 31]; /* 19 (datetime) 4 (space+cr+lf+\0) */
898     int len = 0;
899     enum logReturns rv = LOG_STARTUP_OK;
900     int writereply = 0;
901     time_t now_t;
902     struct tm *now;
903 
904     if (g_staticLogConfig == NULL)
905     {
906         g_writeln("The log reference is NULL - log not initialized properly");
907         return LOG_ERROR_NO_CFG;
908     }
909 
910     if (0 > g_staticLogConfig->fd
911             && g_staticLogConfig->enable_syslog == 0
912             && g_staticLogConfig->enable_console == 0)
913     {
914         return LOG_ERROR_FILE_NOT_OPEN;
915     }
916 
917     if (!internal_log_is_enabled_for_level(lvl, override_destination_level, override_log_level))
918     {
919         return LOG_STARTUP_OK;
920     }
921 
922     now_t = time(&now_t);
923     now = localtime(&now_t);
924 
925     strftime(buff, 21, "[%Y%m%d-%H:%M:%S] ", now);
926 
927     internal_log_lvl2str(lvl, buff + 20);
928 
929     if (g_staticLogConfig->enable_pid)
930     {
931         g_snprintf(buff + 28, LOG_BUFFER_SIZE, "[pid:%d tid:%lld] ",
932                    g_getpid(), (long long) tc_get_threadid());
933         len = g_strlen(buff + 28);
934     }
935     len += vsnprintf(buff + 28 + len, LOG_BUFFER_SIZE - len, msg, ap);
936 
937     /* checking for truncated messages */
938     if (len > LOG_BUFFER_SIZE)
939     {
940         log_message(LOG_LEVEL_WARNING, "next message will be truncated");
941         len = LOG_BUFFER_SIZE;
942     }
943 
944     /* forcing the end of message string */
945 #ifdef _WIN32
946     buff[len + 28] = '\r';
947     buff[len + 29] = '\n';
948     buff[len + 30] = '\0';
949 #else
950 #ifdef _MACOS
951     buff[len + 28] = '\r';
952     buff[len + 29] = '\0';
953 #else
954     buff[len + 28] = '\n';
955     buff[len + 29] = '\0';
956 #endif
957 #endif
958 
959     if (g_staticLogConfig->enable_syslog
960             && ((override_destination_level && lvl <= override_log_level)
961                 || (!override_destination_level && lvl <= g_staticLogConfig->syslog_level)))
962     {
963         /* log to syslog*/
964         /* %s fix compiler warning 'not a string literal' */
965         syslog(internal_log_xrdp2syslog(lvl), "%s", buff + 20);
966     }
967 
968     if (g_staticLogConfig->enable_console
969             && ((override_destination_level && lvl <= override_log_level)
970                 || (!override_destination_level && lvl <= g_staticLogConfig->console_level)))
971     {
972         /* log to console */
973         g_printf("%s", buff);
974     }
975 
976     if ((override_destination_level && lvl <= override_log_level)
977             || (!override_destination_level && lvl <= g_staticLogConfig->log_level))
978     {
979         /* log to application logfile */
980         if (g_staticLogConfig->fd >= 0)
981         {
982 #ifdef LOG_ENABLE_THREAD
983             pthread_mutex_lock(&(g_staticLogConfig->log_lock));
984 #endif
985 
986             writereply = g_file_write(g_staticLogConfig->fd, buff, g_strlen(buff));
987 
988             if (writereply <= 0)
989             {
990                 rv = LOG_ERROR_NULL_FILE;
991             }
992 
993 #ifdef LOG_ENABLE_THREAD
994             pthread_mutex_unlock(&(g_staticLogConfig->log_lock));
995 #endif
996         }
997     }
998 
999     return rv;
1000 }
1001 
1002 /**
1003  * Return the configured log file name
1004  * @return
1005  */
1006 char *
getLogFile(char * replybuf,int bufsize)1007 getLogFile(char *replybuf, int bufsize)
1008 {
1009     if (g_staticLogConfig)
1010     {
1011         if (g_staticLogConfig->log_file)
1012         {
1013             g_strncpy(replybuf, g_staticLogConfig->log_file, bufsize);
1014         }
1015         else
1016         {
1017             g_sprintf(replybuf, "The log_file name is NULL");
1018         }
1019     }
1020     else
1021     {
1022         g_snprintf(replybuf, bufsize, "The log is not properly started");
1023     }
1024 
1025     return replybuf;
1026 }
1027