You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

655 lines
16 KiB

  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. #if defined(HAVE_CONFIG_H)
  19. #include <config_ac.h>
  20. #endif
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <fcntl.h>
  24. #include <syslog.h>
  25. #include <stdarg.h>
  26. #include <stdio.h>
  27. #include <time.h>
  28. #include "list.h"
  29. #include "file.h"
  30. #include "os_calls.h"
  31. #include "thread_calls.h"
  32. /* Add a define here so that the log.h will hold more information
  33. * when compiled from this C file.
  34. * When compiled normally the log.h file only contain the public parts
  35. * of the operators in this file. */
  36. #define LOGINTERNALSTUFF
  37. #include "log.h"
  38. /* Here we store the current state and configuration of the log */
  39. static struct log_config *g_staticLogConfig = NULL;
  40. /* This file first start with all private functions.
  41. In the end of the file the public functions is defined */
  42. /**
  43. *
  44. * @brief Opens log file
  45. * @param fname log file name
  46. * @return see open(2) return values
  47. *
  48. */
  49. int
  50. internal_log_file_open(const char *fname)
  51. {
  52. int ret = -1;
  53. if (fname != NULL)
  54. {
  55. ret = open(fname, O_WRONLY | O_CREAT | O_APPEND | O_SYNC,
  56. S_IRUSR | S_IWUSR);
  57. }
  58. #ifdef FD_CLOEXEC
  59. if (ret != -1)
  60. {
  61. fcntl(ret, F_SETFD, FD_CLOEXEC);
  62. }
  63. #endif
  64. return ret;
  65. }
  66. /**
  67. *
  68. * @brief Converts xrdp log level to syslog logging level
  69. * @param xrdp logging level
  70. * @return syslog equivalent logging level
  71. *
  72. */
  73. int
  74. internal_log_xrdp2syslog(const enum logLevels lvl)
  75. {
  76. switch (lvl)
  77. {
  78. case LOG_LEVEL_ALWAYS:
  79. return LOG_CRIT;
  80. case LOG_LEVEL_ERROR:
  81. return LOG_ERR;
  82. case LOG_LEVEL_WARNING:
  83. return LOG_WARNING;
  84. case LOG_LEVEL_INFO:
  85. return LOG_INFO;
  86. case LOG_LEVEL_DEBUG:
  87. return LOG_DEBUG;
  88. default:
  89. g_writeln("Undefined log level - programming error");
  90. return LOG_DEBUG;
  91. }
  92. }
  93. /**
  94. * @brief Converts xrdp log levels to textual logging levels
  95. * @param lvl logging level
  96. * @param str pointer to a string, must be allocated before
  97. * @return The log string in str pointer.
  98. *
  99. */
  100. void
  101. internal_log_lvl2str(const enum logLevels lvl, char *str)
  102. {
  103. switch (lvl)
  104. {
  105. case LOG_LEVEL_ALWAYS:
  106. snprintf(str, 9, "%s", "[CORE ] ");
  107. break;
  108. case LOG_LEVEL_ERROR:
  109. snprintf(str, 9, "%s", "[ERROR] ");
  110. break;
  111. case LOG_LEVEL_WARNING:
  112. snprintf(str, 9, "%s", "[WARN ] ");
  113. break;
  114. case LOG_LEVEL_INFO:
  115. snprintf(str, 9, "%s", "[INFO ] ");
  116. break;
  117. case LOG_LEVEL_DEBUG:
  118. snprintf(str, 9, "%s", "[DEBUG] ");
  119. break;
  120. default:
  121. snprintf(str, 9, "%s", "PRG ERR!");
  122. g_writeln("Programming error - undefined log level!!!");
  123. }
  124. }
  125. /******************************************************************************/
  126. enum logReturns
  127. internal_log_start(struct log_config *l_cfg)
  128. {
  129. enum logReturns ret = LOG_GENERAL_ERROR;
  130. if (0 == l_cfg)
  131. {
  132. ret = LOG_ERROR_MALLOC;
  133. return ret;
  134. }
  135. /* if logfile is NULL, we return error */
  136. if (0 == l_cfg->log_file)
  137. {
  138. g_writeln("log_file not properly assigned");
  139. return ret;
  140. }
  141. /* if progname is NULL, we return error */
  142. if (0 == l_cfg->program_name)
  143. {
  144. g_writeln("program_name not properly assigned");
  145. return ret;
  146. }
  147. /* open file */
  148. l_cfg->fd = internal_log_file_open(l_cfg->log_file);
  149. if (-1 == l_cfg->fd)
  150. {
  151. return LOG_ERROR_FILE_OPEN;
  152. }
  153. /* if syslog is enabled, open it */
  154. if (l_cfg->enable_syslog)
  155. {
  156. openlog(l_cfg->program_name, LOG_CONS | LOG_PID, LOG_DAEMON);
  157. }
  158. #ifdef LOG_ENABLE_THREAD
  159. pthread_mutexattr_init(&(l_cfg->log_lock_attr));
  160. pthread_mutex_init(&(l_cfg->log_lock), &(l_cfg->log_lock_attr));
  161. #endif
  162. return LOG_STARTUP_OK;
  163. }
  164. /******************************************************************************/
  165. enum logReturns
  166. internal_log_end(struct log_config *l_cfg)
  167. {
  168. enum logReturns ret = LOG_GENERAL_ERROR;
  169. /* if log is closed, quit silently */
  170. if (0 == l_cfg)
  171. {
  172. return ret;
  173. }
  174. /* closing log file */
  175. log_message(LOG_LEVEL_ALWAYS, "shutting down log subsystem...");
  176. if (-1 != l_cfg->fd)
  177. {
  178. /* closing logfile... */
  179. g_file_close(l_cfg->fd);
  180. }
  181. /* if syslog is enabled, close it */
  182. if (l_cfg->enable_syslog)
  183. {
  184. closelog();
  185. }
  186. /* freeing allocated memory */
  187. if (0 != l_cfg->log_file)
  188. {
  189. g_free(l_cfg->log_file);
  190. l_cfg->log_file = 0;
  191. }
  192. ret = LOG_STARTUP_OK;
  193. return ret;
  194. }
  195. /**
  196. * Converts a string representing th log level to a value
  197. * @param buf
  198. * @return
  199. */
  200. enum logLevels
  201. internal_log_text2level(const char *buf)
  202. {
  203. if (0 == g_strcasecmp(buf, "0") ||
  204. 0 == g_strcasecmp(buf, "core"))
  205. {
  206. return LOG_LEVEL_ALWAYS;
  207. }
  208. else if (0 == g_strcasecmp(buf, "1") ||
  209. 0 == g_strcasecmp(buf, "error"))
  210. {
  211. return LOG_LEVEL_ERROR;
  212. }
  213. else if (0 == g_strcasecmp(buf, "2") ||
  214. 0 == g_strcasecmp(buf, "warn") ||
  215. 0 == g_strcasecmp(buf, "warning"))
  216. {
  217. return LOG_LEVEL_WARNING;
  218. }
  219. else if (0 == g_strcasecmp(buf, "3") ||
  220. 0 == g_strcasecmp(buf, "info"))
  221. {
  222. return LOG_LEVEL_INFO;
  223. }
  224. else if (0 == g_strcasecmp(buf, "4") ||
  225. 0 == g_strcasecmp(buf, "debug"))
  226. {
  227. return LOG_LEVEL_DEBUG;
  228. }
  229. g_writeln("Your configured log level is corrupt - we use debug log level");
  230. return LOG_LEVEL_DEBUG;
  231. }
  232. enum logReturns
  233. internalReadConfiguration(const char *inFilename, const char *applicationName)
  234. {
  235. int fd;
  236. enum logReturns ret = LOG_GENERAL_ERROR;
  237. struct list *sec;
  238. struct list *param_n;
  239. struct list *param_v;
  240. if (inFilename == NULL)
  241. {
  242. g_writeln("The inifile is null to readConfiguration!");
  243. return ret;
  244. }
  245. fd = g_file_open(inFilename);
  246. if (-1 == fd)
  247. {
  248. ret = LOG_ERROR_NO_CFG;
  249. g_writeln("We could not open the configuration file to read log parameters");
  250. return ret;
  251. }
  252. /* we initialize the memory for the configuration and set all content
  253. to zero. */
  254. ret = internalInitAndAllocStruct();
  255. if (ret != LOG_STARTUP_OK)
  256. {
  257. g_file_close(fd);
  258. return ret;
  259. }
  260. sec = list_create();
  261. sec->auto_free = 1;
  262. file_read_sections(fd, sec);
  263. param_n = list_create();
  264. param_n->auto_free = 1;
  265. param_v = list_create();
  266. param_v->auto_free = 1;
  267. /* read logging config */
  268. ret = internal_config_read_logging(fd, g_staticLogConfig, param_n,
  269. param_v, applicationName);
  270. if (ret != LOG_STARTUP_OK)
  271. {
  272. g_file_close(fd);
  273. return ret;
  274. }
  275. /* cleanup */
  276. list_delete(sec);
  277. list_delete(param_v);
  278. list_delete(param_n);
  279. g_file_close(fd);
  280. return ret;
  281. }
  282. /******************************************************************************/
  283. enum logReturns
  284. internal_config_read_logging(int file, struct log_config *lc,
  285. struct list *param_n,
  286. struct list *param_v,
  287. const char *applicationName)
  288. {
  289. int i;
  290. char *buf;
  291. char *temp_buf;
  292. list_clear(param_v);
  293. list_clear(param_n);
  294. /* setting defaults */
  295. lc->program_name = applicationName;
  296. lc->log_file = 0;
  297. lc->fd = 0;
  298. lc->log_level = LOG_LEVEL_DEBUG;
  299. lc->enable_syslog = 0;
  300. lc->syslog_level = LOG_LEVEL_DEBUG;
  301. file_read_section(file, SESMAN_CFG_LOGGING, param_n, param_v);
  302. for (i = 0; i < param_n->count; i++)
  303. {
  304. buf = (char *)list_get_item(param_n, i);
  305. if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_FILE))
  306. {
  307. lc->log_file = g_strdup((char *)list_get_item(param_v, i));
  308. if (lc->log_file != NULL)
  309. {
  310. if (lc->log_file[0] != '/')
  311. {
  312. temp_buf = (char *)g_malloc(512, 0);
  313. g_snprintf(temp_buf, 511, "%s/%s", XRDP_LOG_PATH, lc->log_file);
  314. g_free(lc->log_file);
  315. lc->log_file = temp_buf;
  316. }
  317. }
  318. }
  319. if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_LEVEL))
  320. {
  321. lc->log_level = internal_log_text2level((char *)list_get_item(param_v, i));
  322. }
  323. if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_SYSLOG))
  324. {
  325. lc->enable_syslog = g_text2bool((char *)list_get_item(param_v, i));
  326. }
  327. if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_SYSLOG_LEVEL))
  328. {
  329. lc->syslog_level = internal_log_text2level((char *)list_get_item(param_v, i));
  330. }
  331. }
  332. if (0 == lc->log_file)
  333. {
  334. lc->log_file = g_strdup("./sesman.log");
  335. }
  336. /* try to create path if not exist */
  337. g_create_path(lc->log_file);
  338. g_printf("logging configuration:\r\n");
  339. g_printf("\tLogFile: %s\r\n", lc->log_file);
  340. g_printf("\tLogLevel: %i\r\n", lc->log_level);
  341. g_printf("\tEnableSyslog: %i\r\n", lc->enable_syslog);
  342. g_printf("\tSyslogLevel: %i\r\n", lc->syslog_level);
  343. return LOG_STARTUP_OK;
  344. }
  345. enum logReturns
  346. internalInitAndAllocStruct(void)
  347. {
  348. enum logReturns ret = LOG_GENERAL_ERROR;
  349. g_staticLogConfig = g_new0(struct log_config, 1);
  350. if (g_staticLogConfig != NULL)
  351. {
  352. g_staticLogConfig->fd = -1;
  353. g_staticLogConfig->enable_syslog = 0;
  354. ret = LOG_STARTUP_OK;
  355. }
  356. else
  357. {
  358. g_writeln("could not allocate memory for log struct");
  359. ret = LOG_ERROR_MALLOC;
  360. }
  361. return ret;
  362. }
  363. /*
  364. * Here below the public functions
  365. */
  366. enum logReturns
  367. log_start_from_param(const struct log_config *iniParams)
  368. {
  369. enum logReturns ret = LOG_GENERAL_ERROR;
  370. if (g_staticLogConfig != NULL)
  371. {
  372. log_message(LOG_LEVEL_ALWAYS, "Log already initialized");
  373. return ret;
  374. }
  375. if (iniParams == NULL)
  376. {
  377. g_writeln("inparam to log_start_from_param is NULL");
  378. return ret;
  379. }
  380. else
  381. {
  382. /*Copy the struct information*/
  383. ret = internalInitAndAllocStruct();
  384. if (ret != LOG_STARTUP_OK)
  385. {
  386. g_writeln("internalInitAndAllocStruct failed");
  387. return ret;
  388. }
  389. g_staticLogConfig->enable_syslog = iniParams->enable_syslog;
  390. g_staticLogConfig->fd = iniParams->fd;
  391. g_staticLogConfig->log_file = g_strdup(iniParams->log_file);
  392. g_staticLogConfig->log_level = iniParams->log_level;
  393. g_staticLogConfig->log_lock = iniParams->log_lock;
  394. g_staticLogConfig->log_lock_attr = iniParams->log_lock_attr;
  395. g_staticLogConfig->program_name = iniParams->program_name;
  396. g_staticLogConfig->syslog_level = iniParams->syslog_level;
  397. ret = internal_log_start(g_staticLogConfig);
  398. if (ret != LOG_STARTUP_OK)
  399. {
  400. g_writeln("Could not start log");
  401. if (g_staticLogConfig != NULL)
  402. {
  403. g_free(g_staticLogConfig);
  404. g_staticLogConfig = NULL;
  405. }
  406. }
  407. }
  408. return ret;
  409. }
  410. /**
  411. * This function initialize the log facilities according to the configuration
  412. * file, that is described by the in parameter.
  413. * @param iniFile
  414. * @param applicationName, the name that is used in the log for the running application
  415. * @return 0 on success
  416. */
  417. enum logReturns
  418. log_start(const char *iniFile, const char *applicationName)
  419. {
  420. enum logReturns ret = LOG_GENERAL_ERROR;
  421. if (applicationName == NULL)
  422. {
  423. g_writeln("Programming error your application name cannot be null");
  424. return ret;
  425. }
  426. ret = internalReadConfiguration(iniFile, applicationName);
  427. if (ret == LOG_STARTUP_OK)
  428. {
  429. ret = internal_log_start(g_staticLogConfig);
  430. if (ret != LOG_STARTUP_OK)
  431. {
  432. g_writeln("Could not start log");
  433. if (g_staticLogConfig != NULL)
  434. {
  435. g_free(g_staticLogConfig);
  436. g_staticLogConfig = NULL;
  437. }
  438. }
  439. }
  440. else
  441. {
  442. g_writeln("Error reading configuration for log based on config: %s",
  443. iniFile);
  444. }
  445. return ret;
  446. }
  447. /**
  448. * Function that terminates all logging
  449. * @return
  450. */
  451. enum logReturns
  452. log_end(void)
  453. {
  454. enum logReturns ret = LOG_GENERAL_ERROR;
  455. ret = internal_log_end(g_staticLogConfig);
  456. if (g_staticLogConfig != NULL)
  457. {
  458. g_free(g_staticLogConfig);
  459. g_staticLogConfig = NULL;
  460. }
  461. return ret;
  462. }
  463. enum logReturns
  464. log_message(const enum logLevels lvl, const char *msg, ...)
  465. {
  466. char buff[LOG_BUFFER_SIZE + 31]; /* 19 (datetime) 4 (space+cr+lf+\0) */
  467. va_list ap;
  468. int len = 0;
  469. enum logReturns rv = LOG_STARTUP_OK;
  470. int writereply = 0;
  471. time_t now_t;
  472. struct tm *now;
  473. if (g_staticLogConfig == NULL)
  474. {
  475. g_writeln("The log reference is NULL - log not initialized properly");
  476. return LOG_ERROR_NO_CFG;
  477. }
  478. if (0 > g_staticLogConfig->fd && g_staticLogConfig->enable_syslog == 0)
  479. {
  480. return LOG_ERROR_FILE_NOT_OPEN;
  481. }
  482. now_t = time(&now_t);
  483. now = localtime(&now_t);
  484. snprintf(buff, 21, "[%.4d%.2d%.2d-%.2d:%.2d:%.2d] ", now->tm_year + 1900,
  485. now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min,
  486. now->tm_sec);
  487. internal_log_lvl2str(lvl, buff + 20);
  488. va_start(ap, msg);
  489. len = vsnprintf(buff + 28, LOG_BUFFER_SIZE, msg, ap);
  490. va_end(ap);
  491. /* checking for truncated messages */
  492. if (len > LOG_BUFFER_SIZE)
  493. {
  494. log_message(LOG_LEVEL_WARNING, "next message will be truncated");
  495. }
  496. /* forcing the end of message string */
  497. #ifdef _WIN32
  498. buff[len + 28] = '\r';
  499. buff[len + 29] = '\n';
  500. buff[len + 30] = '\0';
  501. #else
  502. #ifdef _MACOS
  503. buff[len + 28] = '\r';
  504. buff[len + 29] = '\0';
  505. #else
  506. buff[len + 28] = '\n';
  507. buff[len + 29] = '\0';
  508. #endif
  509. #endif
  510. if (g_staticLogConfig->enable_syslog && (lvl <= g_staticLogConfig->syslog_level))
  511. {
  512. /* log to syslog*/
  513. /* %s fix compiler warning 'not a string literal' */
  514. syslog(internal_log_xrdp2syslog(lvl), "(%d)(%lld)%s", g_getpid(),
  515. (long long) tc_get_threadid(), buff + 20);
  516. }
  517. if (lvl <= g_staticLogConfig->log_level)
  518. {
  519. /* log to console */
  520. g_printf("%s", buff);
  521. /* log to application logfile */
  522. #ifdef LOG_ENABLE_THREAD
  523. pthread_mutex_lock(&(g_staticLogConfig->log_lock));
  524. #endif
  525. if (g_staticLogConfig->fd > 0)
  526. {
  527. writereply = g_file_write(g_staticLogConfig->fd, buff, g_strlen(buff));
  528. if (writereply <= 0)
  529. {
  530. rv = LOG_ERROR_NULL_FILE;
  531. }
  532. }
  533. #ifdef LOG_ENABLE_THREAD
  534. pthread_mutex_unlock(&(g_staticLogConfig->log_lock));
  535. #endif
  536. }
  537. return rv;
  538. }
  539. /**
  540. * Return the configured log file name
  541. * @return
  542. */
  543. char *
  544. getLogFile(char *replybuf, int bufsize)
  545. {
  546. if (g_staticLogConfig)
  547. {
  548. if (g_staticLogConfig->log_file)
  549. {
  550. g_strncpy(replybuf, g_staticLogConfig->log_file, bufsize);
  551. }
  552. else
  553. {
  554. g_sprintf(replybuf, "The log_file name is NULL");
  555. }
  556. }
  557. else
  558. {
  559. g_snprintf(replybuf, bufsize, "The log is not properly started");
  560. }
  561. return replybuf;
  562. }