1 2 /* 3 * Samba Unix/Linux SMB client utility 4 * Write Eventlog records to a tdb, perform other eventlog related functions 5 * 6 * 7 * Copyright (C) Brian Moran 2005. 8 * Copyright (C) Guenther Deschner 2009. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 3 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, see <http://www.gnu.org/licenses/>. 22 */ 23 24 25 #include "includes.h" 26 #include "lib/eventlog/eventlog.h" 27 #include "registry.h" 28 #include "registry/reg_api.h" 29 #include "registry/reg_init_basic.h" 30 #include "registry/reg_util_token.h" 31 #include "registry/reg_backend_db.h" 32 #include "../libcli/registry/util_reg.h" 33 #include "cmdline_contexts.h" 34 35 extern int optind; 36 extern char *optarg; 37 38 int opt_debug = 0; 39 40 static void usage( char *s ) 41 { 42 printf( "\nUsage: %s [OPTION]\n\n", s ); 43 printf( " -o write <Eventlog Name> \t\t\t\t\tWrites records to eventlog from STDIN\n" ); 44 printf( " -o addsource <EventlogName> <sourcename> <msgfileDLLname> \tAdds the specified source & DLL eventlog registry entry\n" ); 45 printf( " -o dump <Eventlog Name> <starting_record>\t\t\t\t\tDump stored eventlog entries on STDOUT\n" ); 46 printf( "\nMiscellaneous options:\n" ); 47 printf( " -s <filename>\t\t\t\t\t\t\tUse configuration file <filename>.\n"); 48 printf( " -d\t\t\t\t\t\t\t\tturn debug on\n" ); 49 printf( " -h\t\t\t\t\t\t\t\tdisplay help\n\n" ); 50 } 51 52 static void display_eventlog_names( void ) 53 { 54 const char **elogs; 55 int i; 56 57 elogs = lp_eventlog_list( ); 58 printf( "Active eventlog names:\n" ); 59 printf( "--------------------------------------\n" ); 60 if ( elogs ) { 61 for ( i = 0; elogs[i]; i++ ) { 62 printf( "\t%s\n", elogs[i] ); 63 } 64 } 65 else 66 printf( "\t<None specified>\n"); 67 } 68 69 /********************************************************************* 70 for an eventlog, add in a source name. If the eventlog doesn't 71 exist (not in the list) do nothing. If a source for the log 72 already exists, change the information (remove, replace) 73 *********************************************************************/ 74 static bool eventlog_add_source( const char *eventlog, const char *sourcename, 75 const char *messagefile ) 76 { 77 /* Find all of the eventlogs, add keys for each of them */ _doprnt(const char * format,va_list ap,FILE * stream)78 /* need to add to the value KEY_EVENTLOG/<eventlog>/Sources string (Creating if necessary) 79 need to add KEY of source to KEY_EVENTLOG/<eventlog>/<source> */ 80 81 const char **elogs = lp_eventlog_list( ); 82 const char **wrklist, **wp; 83 char *evtlogpath = NULL; 84 int ii = 0; 85 bool already_in; 86 int i; 87 int numsources = 0; 88 TALLOC_CTX *ctx = talloc_stackframe(); 89 WERROR werr; 90 struct registry_key *key_hive, *key_eventlog, *key_source; 91 struct security_token *token = NULL; 92 const char *hive_name, *relpath; 93 enum winreg_CreateAction action; 94 struct registry_value *value; 95 static const uint32_t ACCESS = REG_KEY_READ | REG_KEY_WRITE; 96 bool ret = false; 97 98 if (!elogs) { 99 d_printf("No Eventlogs configured\n"); 100 goto done; 101 } 102 103 for ( i = 0; elogs[i]; i++ ) { 104 if ( strequal( elogs[i], eventlog ) ) 105 break; 106 } 107 108 if ( !elogs[i] ) { 109 d_printf("Eventlog [%s] not found in list of valid event logs\n", 110 eventlog); 111 goto done; 112 } 113 114 /* have to assume that the evenlog key itself exists at this point */ 115 /* add in a key of [sourcename] under the eventlog key */ 116 117 /* todo add to Sources */ 118 119 evtlogpath = talloc_asprintf(ctx, "%s\\%s", KEY_EVENTLOG, eventlog); 120 if (!evtlogpath) { 121 d_printf("Out of memory\n"); 122 goto done; 123 } 124 125 relpath = evtlogpath + sizeof(KEY_EVENTLOG); 126 hive_name = talloc_strndup(ctx, evtlogpath, relpath - evtlogpath); 127 if (!hive_name) { 128 d_printf("Out of memory\n"); 129 goto done; 130 } 131 relpath++; 132 133 werr = ntstatus_to_werror(registry_create_admin_token(ctx, &token)); 134 if (!W_ERROR_IS_OK(werr)) { 135 d_printf("Failed to create admin token: %s\n", win_errstr(werr)); 136 goto done; 137 } 138 139 werr = reg_openhive(ctx, hive_name, ACCESS, token, &key_hive); 140 if (!W_ERROR_IS_OK(werr)) { 141 d_printf("Failed to open hive [%s]: %s\n", hive_name, win_errstr(werr)); 142 goto done; 143 } 144 145 werr = reg_openkey(ctx, key_hive, relpath, ACCESS, &key_eventlog); 146 if (!W_ERROR_IS_OK(werr)) { 147 d_printf("Failed to open key [%s]: %s\n", evtlogpath, win_errstr(werr)); 148 goto done; 149 } 150 151 werr = reg_queryvalue(ctx, key_eventlog, "Sources", &value); 152 if (!W_ERROR_IS_OK(werr)) { 153 d_printf("Failed to get value \"Sources\" for [%s]: %s\n", evtlogpath, win_errstr(werr)); 154 goto done; 155 } 156 /* perhaps this adding a new string to a multi_sz should be a fn? */ 157 /* check to see if it's there already */ 158 159 if ( value->type != REG_MULTI_SZ ) { 160 d_printf("Wrong type for \"Sources\", should be REG_MULTI_SZ\n"); 161 goto done; 162 } 163 /* convert to a 'regulah' chars to do some comparisons */ 164 165 already_in = false; 166 wrklist = NULL; 167 dump_data(1, value->data.data, value->data.length); 168 169 if (!pull_reg_multi_sz(ctx, &value->data, &wrklist)) { 170 d_printf("Failed to pull REG_MULTI_SZ from \"Sources\"\n"); 171 goto done; 172 } 173 174 for (ii=0; wrklist[ii]; ii++) { 175 numsources++; 176 } 177 178 if (numsources > 0) { 179 /* see if it's in there already */ 180 wp = wrklist; 181 182 while (wp && *wp ) { 183 if ( strequal( *wp, sourcename ) ) { 184 d_printf("Source name [%s] already in list for [%s] \n", 185 sourcename, eventlog); 186 already_in = true; 187 break; 188 } 189 wp++; 190 } 191 } else { 192 d_printf("Nothing in the sources list, this might be a problem\n"); 193 } 194 195 if ( !already_in ) { 196 /* make a new list with an additional entry; copy values, add another */ 197 wp = talloc_realloc(ctx, wrklist, const char *, numsources + 2 ); 198 if ( !wp ) { 199 d_printf("Out of memory\n"); 200 goto done; 201 } 202 203 wp[numsources] = sourcename; 204 wp[numsources+1] = NULL; 205 if (!push_reg_multi_sz(ctx, &value->data, wp)) { 206 d_printf("Failed to push Sources\n"); 207 goto done; 208 } 209 dump_data( 1, value->data.data, value->data.length); 210 werr = reg_setvalue(key_eventlog, "Sources", value); 211 if (!W_ERROR_IS_OK(werr)) { 212 d_printf("Failed to set value Sources: %s\n", win_errstr(werr)); 213 goto done; 214 } 215 } else { 216 d_printf("Source name [%s] found in existing list of sources\n", 217 sourcename); 218 } 219 220 werr = reg_createkey(ctx, key_eventlog, sourcename, ACCESS, &key_source, &action); 221 if (!W_ERROR_IS_OK(werr)) { checkit(const char * format,...)222 d_printf("Failed to create subkey \"%s\" of \"%s\": %s\n", sourcename, evtlogpath, win_errstr(werr)); 223 goto done; 224 } 225 226 if (action == REG_CREATED_NEW_KEY) { 227 d_printf(" Source name [%s] for eventlog [%s] didn't exist, adding \n", 228 sourcename, eventlog); 229 } 230 231 /* at this point KEY_EVENTLOG/<eventlog>/<sourcename> key is in there. Now need to add EventMessageFile */ 232 233 /* now add the values to the KEY_EVENTLOG/Application form key */ 234 d_printf("Storing EventMessageFile [%s] to eventlog path of [%s]\n", main(void)235 messagefile, evtlogpath); 236 237 if (!push_reg_sz(ctx, &value->data, messagefile)) { 238 d_printf("Failed to push \"EventMessageFile\"\n"); 239 goto done; 240 } 241 value->type = REG_SZ; 242 243 werr = reg_setvalue(key_source, "EventMessageFile", value); 244 if (!W_ERROR_IS_OK(werr)) { 245 d_printf("Failed to set value \"EventMessageFile\": %s\n", win_errstr(werr)); 246 return false; 247 } 248 ret = true; 249 done: 250 talloc_free(ctx); 251 return ret; 252 } 253 254 static int DoAddSourceCommand( int argc, char **argv, bool debugflag, char *exename ) 255 { 256 WERROR werr; 257 258 if ( argc < 3 ) { 259 printf( "need more arguments:\n" ); 260 printf( "-o addsource EventlogName SourceName /path/to/EventMessageFile.dll\n" ); 261 return -1; 262 } 263 264 /* must open the registry before we access it */ 265 werr = registry_init_common(); 266 if (!W_ERROR_IS_OK(werr)) { 267 printf("Can't open the registry: %s.\n", win_errstr(werr)); 268 return -1; 269 } 270 werr = regdb_transaction_start(); 271 if (!W_ERROR_IS_OK(werr)) { 272 printf("Can't start transaction on registry: %s.\n", win_errstr(werr)); 273 return -1; 274 } 275 276 if ( !eventlog_add_source( argv[0], argv[1], argv[2] ) ) { 277 regdb_transaction_cancel(); 278 return -2; 279 } 280 werr = regdb_transaction_commit(); 281 if (!W_ERROR_IS_OK(werr)) { 282 printf("Failed to commit transaction on registry: %s.\n", win_errstr(werr)); 283 return -1; 284 } 285 return 0; 286 } 287 288 static int DoWriteCommand( int argc, char **argv, bool debugflag, char *exename ) 289 { 290 FILE *f1; 291 char *argfname; 292 ELOG_TDB *etdb; 293 NTSTATUS status; 294 295 /* fixed constants are bad bad bad */ 296 char linein[1024]; 297 bool is_eor; 298 struct eventlog_Record_tdb ee; 299 uint32_t record_number = 0; 300 TALLOC_CTX *mem_ctx = talloc_tos(); 301 302 f1 = stdin; 303 if ( !f1 ) { 304 printf( "Can't open STDIN\n" ); 305 return -1; 306 } 307 308 if ( debugflag ) { 309 printf( "Starting write for eventlog [%s]\n", argv[0] ); 310 display_eventlog_names( ); 311 } 312 313 argfname = argv[0]; 314 315 if ( !( etdb = elog_open_tdb( argfname, False, False ) ) ) { 316 printf( "can't open the eventlog TDB (%s)\n", argfname ); 317 return -1; 318 } 319 320 ZERO_STRUCT( ee ); /* MUST initialize between records */ 321 322 while ( !feof( f1 ) ) { 323 if (fgets( linein, sizeof( linein ) - 1, f1 ) == NULL) { 324 break; 325 } 326 if ((strlen(linein) > 0) 327 && (linein[strlen(linein)-1] == '\n')) { 328 linein[strlen(linein)-1] = 0; 329 } 330 331 if ( debugflag ) 332 printf( "Read line [%s]\n", linein ); 333 334 is_eor = False; 335 336 337 parse_logentry( mem_ctx, ( char * ) &linein, &ee, &is_eor ); 338 /* should we do something with the return code? */ 339 340 if ( is_eor ) { 341 fixup_eventlog_record_tdb( &ee ); 342 343 if ( opt_debug ) 344 printf( "record number [%d], tg [%d] , tw [%d]\n", 345 ee.record_number, (int)ee.time_generated, (int)ee.time_written ); 346 347 if ( ee.time_generated != 0 ) { 348 349 /* printf("Writing to the event log\n"); */ 350 351 status = evlog_push_record_tdb( mem_ctx, ELOG_TDB_CTX(etdb), 352 &ee, &record_number ); 353 if ( !NT_STATUS_IS_OK(status) ) { 354 printf( "Can't write to the event log: %s\n", 355 nt_errstr(status) ); 356 } else { 357 if ( opt_debug ) 358 printf( "Wrote record %d\n", 359 record_number ); 360 } 361 } else { 362 if ( opt_debug ) 363 printf( "<null record>\n" ); 364 } 365 ZERO_STRUCT( ee ); /* MUST initialize between records */ 366 } 367 } 368 369 elog_close_tdb( etdb , False ); 370 371 return 0; 372 } 373 374 static int DoDumpCommand(int argc, char **argv, bool debugflag, char *exename) 375 { 376 ELOG_TDB *etdb; 377 TALLOC_CTX *mem_ctx = talloc_tos(); 378 uint32_t count = 1; 379 380 if (argc > 2) { 381 return -1; 382 } 383 384 if (argc > 1) { 385 count = atoi(argv[1]); 386 } 387 388 etdb = elog_open_tdb(argv[0], false, true); 389 if (!etdb) { 390 printf("can't open the eventlog TDB (%s)\n", argv[0]); 391 return -1; 392 } 393 394 while (1) { 395 396 struct eventlog_Record_tdb *r; 397 char *s; 398 399 r = evlog_pull_record_tdb(mem_ctx, etdb->tdb, count); 400 if (!r) { 401 break; 402 } 403 404 printf("displaying record: %d\n", count); 405 406 s = NDR_PRINT_STRUCT_STRING(mem_ctx, eventlog_Record_tdb, r); 407 if (s) { 408 printf("%s\n", s); 409 talloc_free(s); 410 } 411 count++; 412 } 413 414 elog_close_tdb(etdb, false); 415 416 return 0; 417 } 418 419 /* would be nice to use the popT stuff here, however doing so forces us to drag in a lot of other infrastructure */ 420 421 int main( int argc, char *argv[] ) 422 { 423 int opt, rc; 424 char *exename; 425 char *configfile = NULL; 426 TALLOC_CTX *frame = talloc_stackframe(); 427 428 429 fstring opname; 430 431 smb_init_locale(); 432 433 opt_debug = 0; /* todo set this from getopts */ 434 435 exename = argv[0]; 436 437 /* default */ 438 439 fstrcpy( opname, "write" ); /* the default */ 440 441 #if 0 /* TESTING CODE */ 442 eventlog_add_source( "System", "TestSourceX", "SomeTestPathX" ); 443 #endif 444 while ( ( opt = getopt( argc, argv, "dho:s:" ) ) != EOF ) { 445 switch ( opt ) { 446 447 case 'o': 448 fstrcpy( opname, optarg ); 449 break; 450 451 case 'h': 452 usage( exename ); 453 display_eventlog_names( ); 454 exit( 0 ); 455 break; 456 457 case 'd': 458 opt_debug = 1; 459 break; 460 case 's': 461 configfile = talloc_strdup(frame, optarg); 462 break; 463 464 } 465 } 466 467 argc -= optind; 468 argv += optind; 469 470 if ( argc < 1 ) { 471 printf( "\nNot enough arguments!\n" ); 472 usage( exename ); 473 exit( 1 ); 474 } 475 476 if ( configfile == NULL ) { 477 lp_load_global(get_dyn_CONFIGFILE()); 478 } else if (!lp_load_global(configfile)) { 479 printf("Unable to parse configfile '%s'\n",configfile); 480 exit( 1 ); 481 } 482 483 /* note that the separate command types should call usage if they need to... */ 484 while ( 1 ) { 485 if ( !strcasecmp_m( opname, "addsource" ) ) { 486 rc = DoAddSourceCommand( argc, argv, opt_debug, 487 exename ); 488 break; 489 } 490 if ( !strcasecmp_m( opname, "write" ) ) { 491 rc = DoWriteCommand( argc, argv, opt_debug, exename ); 492 break; 493 } 494 if ( !strcasecmp_m( opname, "dump" ) ) { 495 rc = DoDumpCommand( argc, argv, opt_debug, exename ); 496 break; 497 } 498 printf( "unknown command [%s]\n", opname ); 499 usage( exename ); 500 exit( 1 ); 501 break; 502 } 503 TALLOC_FREE(frame); 504 return rc; 505 } 506