1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <unistd.h> 28 #include <time.h> 29 #include <syslog.h> 30 #include <thread.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <stdarg.h> 34 #include <dlfcn.h> 35 #include <sys/synch.h> 36 #include <sys/stat.h> 37 #include <sys/errno.h> 38 #include <ctype.h> 39 #include <smbsrv/ndl/eventlog.ndl> 40 #include <smbsrv/libmlsvc.h> 41 42 typedef struct logr_eventlog { 43 const char *el_name; 44 const char *el_path; 45 } logr_eventlog_t; 46 47 logr_eventlog_t logr_eventlog[] = { 48 { "System", "/var/adm/messages" }, 49 { "smbd", "/var/smb/smbd_log.txt" }, 50 { "smbrdr", "/var/smb/smbrdr_log.txt" } 51 }; 52 53 typedef enum { 54 LOGR_MONTH = 0, 55 LOGR_DAY, 56 LOGR_TIME, 57 LOGR_HOST, 58 LOGR_SOURCE, 59 LOGR_IDTAG, 60 LOGR_ID, 61 LOGR_PRI_FAC, 62 LOGR_NARG 63 } logr_syslog_tokens_t; 64 65 /* 66 * Event code translation struct for use in processing config file 67 */ 68 typedef struct logr_priority { 69 char *p_name; 70 int p_value; 71 } logr_priority_t; 72 73 static logr_priority_t logr_pri_names[] = { 74 "panic", LOG_EMERG, 75 "emerg", LOG_EMERG, 76 "alert", LOG_ALERT, 77 "crit", LOG_CRIT, 78 "err", LOG_ERR, 79 "error", LOG_ERR, 80 "warn", LOG_WARNING, 81 "warning", LOG_WARNING, 82 "notice", LOG_NOTICE, 83 "info", LOG_INFO, 84 "debug", LOG_DEBUG 85 }; 86 87 typedef struct logr_syslog_node { 88 list_node_t ln_node; 89 char ln_logline[LOGR_MAXENTRYLEN]; 90 } logr_syslog_node_t; 91 92 static void *logr_interposer_hdl = NULL; 93 static struct { 94 boolean_t (*logr_op_supported)(char *); 95 int (*logr_op_snapshot)(logr_context_t *); 96 } logr_interposer_ops; 97 98 /* 99 * Set the syslog timestamp. 100 * 101 * This is a private helper for logr_syslog_parse_entry(), which 102 * must ensure that the appropriate argv entries are non-null. 103 */ 104 static void 105 logr_syslog_set_timestamp(char **argv, logr_entry_t *le) 106 { 107 char *month = argv[LOGR_MONTH]; 108 char *day = argv[LOGR_DAY]; 109 char *time = argv[LOGR_TIME]; 110 struct timeval now; 111 struct tm tm, cur_tm; 112 char buf[32]; 113 114 bzero(&tm, sizeof (tm)); 115 (void) snprintf(buf, 32, "%s %s %s", month, day, time); 116 if (strptime(buf, "%b" "%d" "%H:%M:%S", &tm) == NULL) { 117 le->le_timestamp.tv_sec = 0; 118 return; 119 } 120 121 (void) gettimeofday(&now, NULL); 122 (void) localtime_r(&now.tv_sec, &cur_tm); 123 124 tm.tm_isdst = cur_tm.tm_isdst; 125 tm.tm_year = cur_tm.tm_year; 126 if (tm.tm_mon > cur_tm.tm_mon) 127 tm.tm_year--; 128 129 le->le_timestamp.tv_sec = mktime(&tm); 130 } 131 132 /* 133 * Set the syslog priority. 134 * 135 * This is a private helper for logr_syslog_parse_entry(), which 136 * must ensure that the appropriate argv entries are non-null. 137 */ 138 static void 139 logr_syslog_set_priority(char **argv, logr_entry_t *le) 140 { 141 logr_priority_t *entry; 142 char *token; 143 int sz = sizeof (logr_pri_names) / sizeof (logr_pri_names[0]); 144 int i; 145 146 le->le_pri = LOG_INFO; 147 148 if ((token = argv[LOGR_PRI_FAC]) == NULL) 149 return; 150 151 for (i = 0; i < sz; i++) { 152 entry = &logr_pri_names[i]; 153 154 if (strstr(token, entry->p_name) != NULL) { 155 le->le_pri = entry->p_value; 156 break; 157 } 158 } 159 } 160 161 /* 162 * Parse a syslog entry into a log_entry_t structure. A typical syslog 163 * entry has one of the following formats: 164 * 165 * <month> <day> <time> <host> <msg> 166 * <month> <day> <time> <host> <source>: [ID <ID> <facility.priority>] <msg> 167 * 168 * For Example: 169 * Oct 29 09:49:20 galaxy smbd[104039]: [ID 702911 daemon.info] init done 170 */ 171 static int 172 logr_syslog_parse_entry(char *logline, logr_entry_t *le) 173 { 174 char buf[LOGR_MAXENTRYLEN]; 175 char *argv[LOGR_NARG]; 176 char *value; 177 char *bp; 178 int i; 179 180 (void) memset(argv, 0, sizeof (char *) * LOGR_NARG); 181 (void) strlcpy(buf, logline, LOGR_MAXENTRYLEN); 182 183 for (bp = buf, i = 0; i < LOGR_NARG; ++i) { 184 if (i == LOGR_SOURCE) { 185 /* 186 * If the [ID key is not present, everything 187 * that follows is the message text. 188 */ 189 if (strstr(bp, "[ID") == NULL) 190 break; 191 } 192 193 do { 194 if ((value = strsep(&bp, " \t")) == NULL) 195 break; 196 } while (*value == '\0'); 197 198 if ((argv[i] = value) == NULL) 199 return (-1); 200 } 201 202 /* 203 * bp should be pointing at the remaining message text. 204 */ 205 if ((value = strchr(bp, '\n')) != NULL) 206 *value = '\0'; 207 208 (void) strlcpy(le->le_msg, bp, LOGR_MAXENTRYLEN); 209 (void) strlcpy(le->le_hostname, argv[LOGR_HOST], MAXHOSTNAMELEN); 210 logr_syslog_set_timestamp(argv, le); 211 logr_syslog_set_priority(argv, le); 212 return (0); 213 } 214 215 static void 216 logr_syslog_destroy_queue(list_t *queue) 217 { 218 logr_syslog_node_t *head; 219 220 while ((head = list_head(queue)) != NULL) { 221 list_remove(queue, head); 222 free(head); 223 } 224 list_destroy(queue); 225 } 226 227 static int 228 logr_syslog_construct_queue(FILE *fp, list_t *queue) 229 { 230 logr_syslog_node_t *node, *head; 231 int line_num = 0; 232 char logline[LOGR_MAXENTRYLEN]; 233 234 list_create(queue, sizeof (logr_syslog_node_t), 235 offsetof(logr_syslog_node_t, ln_node)); 236 237 bzero(logline, LOGR_MAXENTRYLEN); 238 while (fgets(logline, LOGR_MAXENTRYLEN, fp) != NULL) { 239 /* Read the last 1024 entries in the queue */ 240 if (line_num > LOGR_NMSGMASK) { 241 head = list_head(queue); 242 list_remove(queue, head); 243 free(head); 244 } 245 246 if ((node = malloc(sizeof (logr_syslog_node_t))) == NULL) { 247 logr_syslog_destroy_queue(queue); 248 return (-1); 249 } 250 bzero(node->ln_logline, LOGR_MAXENTRYLEN); 251 252 (void) strlcpy(node->ln_logline, logline, LOGR_MAXENTRYLEN); 253 list_insert_tail(queue, node); 254 bzero(logline, LOGR_MAXENTRYLEN); 255 line_num++; 256 } 257 258 return (0); 259 } 260 261 /* 262 * logr_syslog_load 263 * 264 * Loads the given log file into log_info_t structure format. 265 * 266 * Returns pointer to the allocated log structure on success. 267 * Note that the caller is responsible for freeing the allocated 268 * memory for returned log_info_t structure. 269 */ 270 static int 271 logr_syslog_load(FILE *fp, logr_info_t *log) 272 { 273 logr_entry_t *entry; 274 int i = 0; 275 276 list_t queue; 277 logr_syslog_node_t *node; 278 279 if (logr_syslog_construct_queue(fp, &queue) < 0) 280 return (-1); 281 282 node = list_head(&queue); 283 while (node) { 284 entry = &log->li_entry[i]; 285 286 if (logr_syslog_parse_entry(node->ln_logline, entry) != 0) { 287 node = list_next(&queue, node); 288 continue; 289 } 290 291 if (++i > LOGR_NMSGMASK) 292 break; 293 294 node = list_next(&queue, node); 295 } 296 297 logr_syslog_destroy_queue(&queue); 298 log->li_idx = i; 299 300 return (0); 301 } 302 303 /* 304 * logr_syslog_snapshot 305 * 306 * Return a snapshot of the given log in the buffer 307 * provided by the caller. Returns the number of entries in 308 * the log. 309 */ 310 static int 311 logr_syslog_snapshot(char *logname, logr_info_t *loginfo) 312 { 313 FILE *fp; 314 char path[MAXPATHLEN]; 315 int i; 316 317 if ((loginfo == NULL) || (!logr_is_supported(logname))) 318 return (-1); 319 320 path[0] = '\0'; 321 for (i = 0; i < sizeof (logr_eventlog)/sizeof (logr_eventlog[0]); ++i) { 322 if (strcasecmp(logname, logr_eventlog[i].el_name) == 0) 323 (void) strlcpy(path, logr_eventlog[i].el_path, 324 MAXPATHLEN); 325 } 326 327 if ((fp = fopen(path, "r")) == 0) 328 return (-1); 329 330 if (logr_syslog_load(fp, loginfo) < 0) { 331 (void) fclose(fp); 332 return (-1); 333 } 334 (void) fclose(fp); 335 336 if (loginfo->li_idx <= LOGR_NMSGMASK) 337 return (loginfo->li_idx); 338 339 return (LOGR_NMSGMASK+1); 340 } 341 342 /* 343 * logr_is_supported 344 * 345 * Determines if a given log is supported or not. 346 * Returns B_TRUE on success, B_FALSE on failure. 347 */ 348 boolean_t 349 logr_is_supported(char *log_name) 350 { 351 int i; 352 353 if (log_name == NULL) 354 return (B_FALSE); 355 356 if (logr_interposer_ops.logr_op_supported != NULL) 357 return (logr_interposer_ops.logr_op_supported(log_name)); 358 359 for (i = 0; i < sizeof (logr_eventlog)/sizeof (logr_eventlog[0]); ++i) { 360 if (strcasecmp(log_name, logr_eventlog[i].el_name) == 0) 361 return (B_TRUE); 362 } 363 364 return (B_FALSE); 365 } 366 367 /* 368 * logr_get_snapshot 369 * 370 * Allocate memory and make a copy, as a snapshot, from system log. 371 * Returns 0 on success, -1 on failure. 372 */ 373 int 374 logr_get_snapshot(logr_context_t *ctx) 375 { 376 logr_read_data_t *data = NULL; 377 378 if (logr_interposer_ops.logr_op_snapshot != NULL) 379 return (logr_interposer_ops.logr_op_snapshot(ctx)); 380 381 ctx->lc_cached_read_data = malloc(sizeof (logr_read_data_t)); 382 if (ctx->lc_cached_read_data != NULL) { 383 data = ctx->lc_cached_read_data; 384 385 data->rd_log = (logr_info_t *)malloc(sizeof (logr_info_t)); 386 if (data->rd_log == NULL) { 387 free(data); 388 return (-1); 389 } 390 bzero(data->rd_log, sizeof (logr_info_t)); 391 392 data->rd_tot_recnum = logr_syslog_snapshot(ctx->lc_source_name, 393 data->rd_log); 394 if (data->rd_tot_recnum < 0) { 395 free(data->rd_log); 396 free(data); 397 return (-1); 398 } 399 400 data->rd_first_read = 1; 401 402 return (0); 403 } 404 405 return (-1); 406 } 407 408 /* 409 * logr_init 410 * 411 * Initializes the Eventlog service. 412 * Checks to see if a event log utility library 413 * is interposed. If yes then it'll initializes logr_interposer_ops 414 * structure with function pointers from this library. 415 */ 416 void 417 logr_init(void) 418 { 419 logr_interposer_hdl = smb_dlopen(); 420 if (logr_interposer_hdl == NULL) 421 return; 422 423 bzero((void *)&logr_interposer_ops, sizeof (logr_interposer_ops)); 424 425 logr_interposer_ops.logr_op_supported = 426 (boolean_t (*)())dlsym(logr_interposer_hdl, "logr_is_supported"); 427 428 logr_interposer_ops.logr_op_snapshot = 429 (int (*)())dlsym(logr_interposer_hdl, "logr_get_snapshot"); 430 431 if (logr_interposer_ops.logr_op_supported == NULL || 432 logr_interposer_ops.logr_op_snapshot == NULL) 433 logr_fini(); 434 } 435 436 /* 437 * logr_fini 438 * 439 * Finalizes the Eventlog service. 440 * Closes handle to interposed library. 441 */ 442 void 443 logr_fini(void) 444 { 445 smb_dlclose(logr_interposer_hdl); 446 logr_interposer_hdl = NULL; 447 bzero((void *)&logr_interposer_ops, sizeof (logr_interposer_ops)); 448 } 449