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