Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Eventlog utility routines
4 : * Copyright (C) Marcin Krzysztof Porwit 2005,
5 : * Copyright (C) Brian Moran 2005.
6 : * Copyright (C) Gerald (Jerry) Carter 2005.
7 : * Copyright (C) Guenther Deschner 2009.
8 : *
9 : * This program is free software; you can redistribute it and/or modify
10 : * it under the terms of the GNU General Public License as published by
11 : * the Free Software Foundation; either version 3 of the License, or
12 : * (at your option) any later version.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/filesys.h"
25 : #include "lib/eventlog/eventlog.h"
26 : #include "../libcli/security/security.h"
27 : #include "util_tdb.h"
28 :
29 : /* maintain a list of open eventlog tdbs with reference counts */
30 :
31 : static ELOG_TDB *open_elog_list;
32 :
33 : /********************************************************************
34 : Init an Eventlog TDB, and return it. If null, something bad
35 : happened.
36 : ********************************************************************/
37 :
38 2 : TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
39 : {
40 0 : TDB_CONTEXT *tdb;
41 :
42 2 : DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
43 : tdbfilename));
44 :
45 2 : tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT,
46 : O_RDWR|O_CREAT|O_TRUNC, 0660 );
47 :
48 2 : if ( !tdb ) {
49 0 : DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
50 0 : return NULL;
51 : }
52 :
53 : /* initialize with defaults, copy real values in here from registry */
54 :
55 2 : tdb_store_int32( tdb, EVT_OLDEST_ENTRY, 1 );
56 2 : tdb_store_int32( tdb, EVT_NEXT_RECORD, 1 );
57 2 : tdb_store_int32( tdb, EVT_MAXSIZE, 0x80000 );
58 2 : tdb_store_int32( tdb, EVT_RETENTION, 0x93A80 );
59 :
60 2 : tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
61 :
62 2 : return tdb;
63 : }
64 :
65 : /********************************************************************
66 : make the tdb file name for an event log, given destination buffer
67 : and size. Caller must free memory.
68 : ********************************************************************/
69 :
70 24 : char *elog_tdbname(TALLOC_CTX *ctx, const char *name )
71 : {
72 0 : char *path;
73 0 : char *file;
74 0 : char *tdbname;
75 :
76 24 : path = state_path(talloc_tos(), "eventlog");
77 24 : if (!path) {
78 0 : return NULL;
79 : }
80 :
81 24 : file = talloc_asprintf_strlower_m(path, "%s.tdb", name);
82 24 : if (!file) {
83 0 : talloc_free(path);
84 0 : return NULL;
85 : }
86 :
87 24 : tdbname = talloc_asprintf(ctx, "%s/%s", path, file);
88 24 : if (!tdbname) {
89 0 : talloc_free(path);
90 0 : return NULL;
91 : }
92 :
93 24 : talloc_free(path);
94 24 : return tdbname;
95 : }
96 :
97 :
98 : /********************************************************************
99 : this function is used to count up the number of bytes in a
100 : particular TDB
101 : ********************************************************************/
102 :
103 : struct trav_size_struct {
104 : int size;
105 : int rec_count;
106 : };
107 :
108 74 : static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
109 : void *state )
110 : {
111 74 : struct trav_size_struct *tsize = (struct trav_size_struct *)state;
112 :
113 74 : tsize->size += data.dsize;
114 74 : tsize->rec_count++;
115 :
116 74 : return 0;
117 : }
118 :
119 : /********************************************************************
120 : returns the size of the eventlog, and if MaxSize is a non-null
121 : ptr, puts the MaxSize there. This is purely a way not to have yet
122 : another function that solely reads the maxsize of the eventlog.
123 : Yeah, that's it.
124 : ********************************************************************/
125 :
126 14 : int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
127 : {
128 0 : struct trav_size_struct tsize;
129 :
130 14 : if ( !tdb )
131 0 : return 0;
132 :
133 14 : ZERO_STRUCT( tsize );
134 :
135 14 : tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
136 :
137 14 : if ( MaxSize != NULL ) {
138 14 : *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
139 : }
140 :
141 14 : if ( Retention != NULL ) {
142 14 : *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
143 : }
144 :
145 14 : DEBUG( 1,
146 : ( "eventlog size: [%d] for [%d] records\n", tsize.size,
147 : tsize.rec_count ) );
148 14 : return tsize.size;
149 : }
150 :
151 : /********************************************************************
152 : Discard early event logs until we have enough for 'needed' bytes...
153 : NO checking done beforehand to see that we actually need to do
154 : this, and it's going to pluck records one-by-one. So, it's best
155 : to determine that this needs to be done before doing it.
156 :
157 : Setting whack_by_date to True indicates that eventlogs falling
158 : outside of the retention range need to go...
159 :
160 : return True if we made enough room to accommodate needed bytes
161 : ********************************************************************/
162 :
163 12 : static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32_t needed,
164 : bool whack_by_date )
165 : {
166 0 : int32_t start_record, i, new_start;
167 0 : int32_t end_record;
168 0 : int32_t reclen, tresv1, trecnum, timegen, timewr;
169 0 : int nbytes, len, Retention, MaxSize;
170 0 : TDB_DATA key, ret;
171 0 : time_t current_time, exp_time;
172 :
173 : /* discard some eventlogs */
174 :
175 : /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
176 : although records not necessarily guaranteed to have successive times */
177 : /* */
178 :
179 : /* lock */
180 12 : tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
181 : /* read */
182 12 : end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
183 12 : start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
184 12 : Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
185 12 : MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
186 :
187 12 : time( ¤t_time );
188 :
189 : /* calculate ... */
190 12 : exp_time = current_time - Retention; /* discard older than exp_time */
191 :
192 : /* todo - check for sanity in next_record */
193 12 : nbytes = 0;
194 :
195 12 : DEBUG( 3,
196 : ( "MaxSize [%d] Retention [%d] Current Time [%u] exp_time [%u]\n",
197 : MaxSize, Retention, (unsigned int)current_time, (unsigned int)exp_time ) );
198 12 : DEBUG( 3,
199 : ( "Start Record [%u] End Record [%u]\n",
200 : (unsigned int)start_record,
201 : (unsigned int)end_record ));
202 :
203 12 : for ( i = start_record; i < end_record; i++ ) {
204 : /* read a record, add the amt to nbytes */
205 4 : key.dsize = sizeof(int32_t);
206 4 : key.dptr = (unsigned char *)&i;
207 4 : ret = tdb_fetch( the_tdb, key );
208 4 : if ( ret.dsize == 0 ) {
209 0 : DEBUG( 8,
210 : ( "Can't find a record for the key, record [%d]\n",
211 : i ) );
212 0 : tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
213 0 : return False;
214 : }
215 4 : nbytes += ret.dsize; /* note this includes overhead */
216 :
217 4 : len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
218 : &tresv1, &trecnum, &timegen, &timewr );
219 4 : if (len == -1) {
220 0 : DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
221 0 : tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
222 0 : SAFE_FREE( ret.dptr );
223 0 : return False;
224 : }
225 :
226 4 : DEBUG( 8,
227 : ( "read record %u, record size is [%d], total so far [%d]\n",
228 : (unsigned int)i, reclen, nbytes ) );
229 :
230 4 : SAFE_FREE( ret.dptr );
231 :
232 : /* note that other servers may just stop writing records when the size limit
233 : is reached, and there are no records older than 'retention'. This doesn't
234 : like a very useful thing to do, so instead we whack (as in sleeps with the
235 : fishes) just enough records to fit the what we need. This behavior could
236 : be changed to 'match', if the need arises. */
237 :
238 4 : if ( !whack_by_date && ( nbytes >= needed ) )
239 0 : break; /* done */
240 4 : if ( whack_by_date && ( timegen >= exp_time ) )
241 4 : break; /* done */
242 : }
243 :
244 12 : DEBUG( 3,
245 : ( "nbytes [%d] needed [%d] start_record is [%u], should be set to [%u]\n",
246 : nbytes, needed, (unsigned int)start_record, (unsigned int)i ) );
247 : /* todo - remove eventlog entries here and set starting record to start_record... */
248 12 : new_start = i;
249 12 : if ( start_record != new_start ) {
250 0 : for ( i = start_record; i < new_start; i++ ) {
251 0 : key.dsize = sizeof(int32_t);
252 0 : key.dptr = (unsigned char *)&i;
253 0 : tdb_delete( the_tdb, key );
254 : }
255 :
256 0 : tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
257 : }
258 12 : tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
259 12 : return True;
260 : }
261 :
262 : /********************************************************************
263 : some hygiene for an eventlog - see how big it is, and then
264 : calculate how many bytes we need to remove
265 : ********************************************************************/
266 :
267 12 : bool prune_eventlog( TDB_CONTEXT * tdb )
268 : {
269 0 : int MaxSize, Retention, CalcdSize;
270 :
271 12 : if ( !tdb ) {
272 0 : DEBUG( 4, ( "No eventlog tdb handle\n" ) );
273 0 : return False;
274 : }
275 :
276 12 : CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
277 12 : DEBUG( 3,
278 : ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
279 : MaxSize ) );
280 :
281 12 : if ( CalcdSize > MaxSize ) {
282 0 : return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
283 : False );
284 : }
285 :
286 12 : return make_way_for_eventlogs( tdb, 0, True );
287 : }
288 :
289 : /********************************************************************
290 : ********************************************************************/
291 :
292 2 : static bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32_t needed )
293 : {
294 0 : int calcd_size;
295 0 : int MaxSize, Retention;
296 :
297 : /* see if we can write to the eventlog -- do a policy enforcement */
298 2 : if ( !tdb )
299 0 : return False; /* tdb is null, so we can't write to it */
300 :
301 :
302 2 : if ( needed < 0 )
303 0 : return False;
304 2 : MaxSize = 0;
305 2 : Retention = 0;
306 :
307 2 : calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
308 :
309 2 : if ( calcd_size <= MaxSize )
310 2 : return True; /* you betcha */
311 0 : if ( calcd_size + needed < MaxSize )
312 0 : return True;
313 :
314 0 : if ( Retention == 0xffffffff ) {
315 0 : return False; /* see msdn - we can't write no room, discard */
316 : }
317 : /*
318 : note don't have to test, but always good to show intent, in case changes needed
319 : later
320 : */
321 :
322 0 : if ( Retention == 0x00000000 ) {
323 : /* discard record(s) */
324 : /* todo - decide when to remove a bunch vs. just what we need... */
325 0 : return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
326 : True );
327 : }
328 :
329 0 : return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
330 : }
331 :
332 : /*******************************************************************
333 : *******************************************************************/
334 :
335 12 : ELOG_TDB *elog_open_tdb( const char *logname, bool force_clear, bool read_only )
336 : {
337 12 : TDB_CONTEXT *tdb = NULL;
338 0 : uint32_t vers_id;
339 0 : ELOG_TDB *ptr;
340 12 : char *tdbpath = NULL;
341 12 : ELOG_TDB *tdb_node = NULL;
342 0 : char *eventlogdir;
343 12 : TALLOC_CTX *ctx = talloc_tos();
344 0 : bool ok;
345 :
346 : /* check for invalid options */
347 :
348 12 : if (force_clear && read_only) {
349 0 : DEBUG(1,("elog_open_tdb: Invalid flags\n"));
350 0 : return NULL;
351 : }
352 :
353 : /* first see if we have an open context */
354 :
355 12 : for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
356 0 : if ( strequal( ptr->name, logname ) ) {
357 0 : ptr->ref_count++;
358 :
359 : /* trick to allow clearing of the eventlog tdb.
360 : The force_clear flag should imply that someone
361 : has done a force close. So make sure the tdb
362 : is NULL. If this is a normal open, then just
363 : return the existing reference */
364 :
365 0 : if ( force_clear ) {
366 0 : SMB_ASSERT( ptr->tdb == NULL );
367 0 : break;
368 : }
369 : else
370 0 : return ptr;
371 : }
372 : }
373 :
374 : /* make sure that the eventlog dir exists */
375 :
376 12 : eventlogdir = state_path(talloc_tos(), "eventlog");
377 12 : if (eventlogdir == NULL) {
378 0 : return NULL;
379 : }
380 12 : ok = directory_create_or_exist(eventlogdir, 0755);
381 12 : TALLOC_FREE(eventlogdir);
382 12 : if (!ok) {
383 0 : return NULL;
384 : }
385 :
386 : /* get the path on disk */
387 :
388 12 : tdbpath = elog_tdbname(ctx, logname);
389 12 : if (!tdbpath) {
390 0 : return NULL;
391 : }
392 :
393 12 : DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
394 : tdbpath, force_clear?"True":"False" ));
395 :
396 : /* the tdb wasn't already open or this is a forced clear open */
397 :
398 12 : if ( !force_clear ) {
399 :
400 12 : tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, read_only ? O_RDONLY : O_RDWR , 0 );
401 12 : if ( tdb ) {
402 10 : vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
403 :
404 10 : if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
405 0 : DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
406 : vers_id, tdbpath));
407 0 : tdb_close( tdb );
408 0 : tdb = elog_init_tdb( tdbpath );
409 : }
410 : }
411 : }
412 :
413 12 : if ( !tdb )
414 2 : tdb = elog_init_tdb( tdbpath );
415 :
416 : /* if we got a valid context, then add it to the list */
417 :
418 12 : if ( tdb ) {
419 : /* on a forced clear, just reset the tdb context if we already
420 : have an open entry in the list */
421 :
422 12 : if ( ptr ) {
423 0 : ptr->tdb = tdb;
424 0 : return ptr;
425 : }
426 :
427 12 : if ( !(tdb_node = talloc_zero( NULL, ELOG_TDB)) ) {
428 0 : DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
429 0 : tdb_close( tdb );
430 0 : return NULL;
431 : }
432 :
433 12 : tdb_node->name = talloc_strdup( tdb_node, logname );
434 12 : tdb_node->tdb = tdb;
435 12 : tdb_node->ref_count = 1;
436 :
437 12 : DLIST_ADD( open_elog_list, tdb_node );
438 : }
439 :
440 12 : return tdb_node;
441 : }
442 :
443 : /*******************************************************************
444 : Wrapper to handle reference counts to the tdb
445 : *******************************************************************/
446 :
447 12 : int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
448 : {
449 0 : TDB_CONTEXT *tdb;
450 :
451 12 : if ( !etdb )
452 0 : return 0;
453 :
454 12 : etdb->ref_count--;
455 :
456 12 : SMB_ASSERT( etdb->ref_count >= 0 );
457 :
458 12 : if ( etdb->ref_count == 0 ) {
459 12 : tdb = etdb->tdb;
460 12 : DLIST_REMOVE( open_elog_list, etdb );
461 12 : TALLOC_FREE( etdb );
462 12 : return tdb_close( tdb );
463 : }
464 :
465 0 : if ( force_close ) {
466 0 : tdb = etdb->tdb;
467 0 : etdb->tdb = NULL;
468 0 : return tdb_close( tdb );
469 : }
470 :
471 0 : return 0;
472 : }
473 :
474 : /********************************************************************
475 : Note that it's a pretty good idea to initialize the Eventlog_entry
476 : structure to zero's before calling parse_logentry on an batch of
477 : lines that may resolve to a record. ALSO, it's a good idea to
478 : remove any linefeeds (that's EOL to you and me) on the lines
479 : going in.
480 : ********************************************************************/
481 :
482 0 : bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
483 : {
484 0 : char *start = NULL, *stop = NULL;
485 :
486 0 : start = line;
487 :
488 : /* empty line signifying record delimiter, or we're at the end of the buffer */
489 0 : if ( start == NULL || strlen( start ) == 0 ) {
490 0 : DEBUG( 6,
491 : ( "parse_logentry: found end-of-record indicator.\n" ) );
492 0 : *eor = True;
493 0 : return True;
494 : }
495 0 : if ( !( stop = strchr( line, ':' ) ) ) {
496 0 : return False;
497 : }
498 :
499 0 : DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
500 :
501 0 : if ( 0 == strncmp( start, "LEN", stop - start ) ) {
502 : /* This will get recomputed later anyway -- probably not necessary */
503 0 : entry->size = atoi( stop + 1 );
504 0 : } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
505 : /* For now all these reserved entries seem to have the same value,
506 : which can be hardcoded to int(1699505740) for now */
507 0 : entry->reserved = talloc_strdup(mem_ctx, "eLfL");
508 0 : } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
509 0 : entry->record_number = atoi( stop + 1 );
510 0 : } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
511 0 : entry->time_generated = atoi( stop + 1 );
512 0 : } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
513 0 : entry->time_written = atoi( stop + 1 );
514 0 : } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
515 0 : entry->event_id = atoi( stop + 1 );
516 0 : } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
517 0 : if ( strstr( start, "ERROR" ) ) {
518 0 : entry->event_type = EVENTLOG_ERROR_TYPE;
519 0 : } else if ( strstr( start, "WARNING" ) ) {
520 0 : entry->event_type = EVENTLOG_WARNING_TYPE;
521 0 : } else if ( strstr( start, "INFO" ) ) {
522 0 : entry->event_type = EVENTLOG_INFORMATION_TYPE;
523 0 : } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
524 0 : entry->event_type = EVENTLOG_AUDIT_SUCCESS;
525 0 : } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
526 0 : entry->event_type = EVENTLOG_AUDIT_FAILURE;
527 0 : } else if ( strstr( start, "SUCCESS" ) ) {
528 0 : entry->event_type = EVENTLOG_SUCCESS;
529 : } else {
530 : /* some other eventlog type -- currently not defined in MSDN docs, so error out */
531 0 : return False;
532 : }
533 : }
534 :
535 : /*
536 : else if(0 == strncmp(start, "NST", stop - start))
537 : {
538 : entry->num_of_strings = atoi(stop + 1);
539 : }
540 : */
541 0 : else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
542 0 : entry->event_category = atoi( stop + 1 );
543 0 : } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
544 0 : entry->reserved_flags = atoi( stop + 1 );
545 0 : } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
546 0 : entry->closing_record_number = atoi( stop + 1 );
547 0 : } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
548 0 : entry->sid_length = atoi( stop + 1 );
549 0 : } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
550 0 : stop++;
551 0 : while ( isspace( stop[0] ) ) {
552 0 : stop++;
553 : }
554 0 : entry->source_name_len = strlen_m_term(stop);
555 0 : entry->source_name = talloc_strdup(mem_ctx, stop);
556 0 : if (entry->source_name_len == (uint32_t)-1 ||
557 0 : entry->source_name == NULL) {
558 0 : return false;
559 : }
560 0 : } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
561 0 : stop++;
562 0 : while ( isspace( stop[0] ) ) {
563 0 : stop++;
564 : }
565 0 : entry->computer_name_len = strlen_m_term(stop);
566 0 : entry->computer_name = talloc_strdup(mem_ctx, stop);
567 0 : if (entry->computer_name_len == (uint32_t)-1 ||
568 0 : entry->computer_name == NULL) {
569 0 : return false;
570 : }
571 0 : } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
572 0 : smb_ucs2_t *dummy = NULL;
573 0 : stop++;
574 0 : while ( isspace( stop[0] ) ) {
575 0 : stop++;
576 : }
577 0 : entry->sid_length = rpcstr_push_talloc(mem_ctx,
578 : &dummy,
579 : stop);
580 0 : if (entry->sid_length == (uint32_t)-1) {
581 0 : return false;
582 : }
583 0 : entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
584 0 : if (entry->sid.data == NULL) {
585 0 : return false;
586 : }
587 0 : } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
588 0 : size_t tmp_len;
589 0 : size_t num_of_strings;
590 : /* skip past initial ":" */
591 0 : stop++;
592 : /* now skip any other leading whitespace */
593 0 : while ( isspace(stop[0])) {
594 0 : stop++;
595 : }
596 0 : tmp_len = strlen_m_term(stop);
597 0 : if (tmp_len == (size_t)-1) {
598 0 : return false;
599 : }
600 0 : num_of_strings = entry->num_of_strings;
601 0 : if (!add_string_to_array(mem_ctx, stop, &entry->strings,
602 : &num_of_strings)) {
603 0 : return false;
604 : }
605 0 : if (num_of_strings > 0xffff) {
606 0 : return false;
607 : }
608 0 : entry->num_of_strings = num_of_strings;
609 0 : entry->strings_len += tmp_len;
610 0 : } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
611 : /* skip past initial ":" */
612 0 : stop++;
613 : /* now skip any other leading whitespace */
614 0 : while ( isspace( stop[0] ) ) {
615 0 : stop++;
616 : }
617 0 : entry->data_length = strlen_m(stop);
618 0 : entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
619 0 : if (!entry->data.data) {
620 0 : return false;
621 : }
622 : } else {
623 : /* some other eventlog entry -- not implemented, so dropping on the floor */
624 0 : DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
625 : /* For now return true so that we can keep on parsing this mess. Eventually
626 : we will return False here. */
627 0 : return true;
628 : }
629 0 : return true;
630 : }
631 :
632 : /*******************************************************************
633 : calculate the correct fields etc for an eventlog entry
634 : *******************************************************************/
635 :
636 0 : size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
637 : {
638 0 : size_t size = 56; /* static size of integers before buffers start */
639 :
640 0 : r->source_name_len = strlen_m_term(r->source_name) * 2;
641 0 : r->computer_name_len = strlen_m_term(r->computer_name) * 2;
642 0 : r->strings_len = ndr_size_string_array(r->strings,
643 0 : r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
644 :
645 : /* fix up the eventlog entry structure as necessary */
646 0 : r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
647 0 : r->padding = ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
648 :
649 0 : if (r->sid_length == 0) {
650 : /* Should not pad to a DWORD boundary for writing out the sid if there is
651 : no SID, so just propagate the padding to pad the data */
652 0 : r->padding += r->sid_padding;
653 0 : r->sid_padding = 0;
654 : }
655 :
656 0 : size += r->source_name_len;
657 0 : size += r->computer_name_len;
658 0 : size += r->sid_padding;
659 0 : size += r->sid_length;
660 0 : size += r->strings_len;
661 0 : size += r->data_length;
662 0 : size += r->padding;
663 : /* need another copy of length at the end of the data */
664 0 : size += sizeof(r->size);
665 :
666 0 : r->size = size;
667 :
668 0 : return size;
669 : }
670 :
671 :
672 : /********************************************************************
673 : ********************************************************************/
674 :
675 2 : struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
676 : TDB_CONTEXT *tdb,
677 : uint32_t record_number)
678 : {
679 0 : struct eventlog_Record_tdb *r;
680 0 : TDB_DATA data, key;
681 :
682 0 : int32_t srecno;
683 0 : enum ndr_err_code ndr_err;
684 0 : DATA_BLOB blob;
685 :
686 2 : srecno = record_number;
687 2 : key.dptr = (unsigned char *)&srecno;
688 2 : key.dsize = sizeof(int32_t);
689 :
690 2 : data = tdb_fetch(tdb, key);
691 2 : if (data.dsize == 0) {
692 2 : DEBUG(8,("evlog_pull_record_tdb: "
693 : "Can't find a record for the key, record %d\n",
694 : record_number));
695 2 : return NULL;
696 : }
697 :
698 0 : r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
699 0 : if (!r) {
700 0 : goto done;
701 : }
702 :
703 0 : blob = data_blob_const(data.dptr, data.dsize);
704 :
705 0 : ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, r,
706 : (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
707 :
708 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
709 0 : DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
710 : record_number));
711 0 : TALLOC_FREE(r);
712 0 : goto done;
713 : }
714 :
715 0 : if (DEBUGLEVEL >= 10) {
716 0 : NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
717 : }
718 :
719 0 : DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
720 : record_number));
721 0 : done:
722 0 : SAFE_FREE(data.dptr);
723 :
724 0 : return r;
725 : }
726 :
727 : /********************************************************************
728 : ********************************************************************/
729 :
730 2 : struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
731 : TDB_CONTEXT *tdb,
732 : uint32_t record_number)
733 : {
734 0 : struct eventlog_Record_tdb *t;
735 0 : struct EVENTLOGRECORD *r;
736 0 : NTSTATUS status;
737 :
738 2 : r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
739 2 : if (!r) {
740 0 : return NULL;
741 : }
742 :
743 2 : t = evlog_pull_record_tdb(r, tdb, record_number);
744 2 : if (!t) {
745 2 : talloc_free(r);
746 2 : return NULL;
747 : }
748 :
749 0 : status = evlog_tdb_entry_to_evt_entry(r, t, r);
750 0 : if (!NT_STATUS_IS_OK(status)) {
751 0 : talloc_free(r);
752 0 : return NULL;
753 : }
754 :
755 0 : r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, 0);
756 :
757 0 : return r;
758 : }
759 :
760 : /********************************************************************
761 : write an eventlog entry. Note that we have to lock, read next
762 : eventlog, increment, write, write the record, unlock
763 :
764 : coming into this, ee has the eventlog record, and the auxiliary date
765 : (computer name, etc.) filled into the other structure. Before packing
766 : into a record, this routine will calc the appropriate padding, etc.,
767 : and then blast out the record in a form that can be read back in
768 : ********************************************************************/
769 :
770 2 : NTSTATUS evlog_push_record_tdb(TALLOC_CTX *mem_ctx,
771 : TDB_CONTEXT *tdb,
772 : struct eventlog_Record_tdb *r,
773 : uint32_t *record_number)
774 : {
775 0 : TDB_DATA kbuf, ebuf;
776 0 : DATA_BLOB blob;
777 0 : enum ndr_err_code ndr_err;
778 0 : int ret;
779 :
780 2 : if (!r) {
781 0 : return NT_STATUS_INVALID_PARAMETER;
782 : }
783 :
784 2 : if (!can_write_to_eventlog(tdb, r->size)) {
785 0 : return NT_STATUS_EVENTLOG_CANT_START;
786 : }
787 :
788 : /* need to read the record number and insert it into the entry here */
789 :
790 : /* lock */
791 2 : ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
792 2 : if (ret != 0) {
793 0 : return NT_STATUS_LOCK_NOT_GRANTED;
794 : }
795 :
796 : /* read */
797 2 : r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
798 :
799 2 : ndr_err = ndr_push_struct_blob(&blob, mem_ctx, r,
800 : (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
801 2 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
802 0 : tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
803 0 : return ndr_map_error2ntstatus(ndr_err);
804 : }
805 :
806 : /* increment the record count */
807 :
808 2 : kbuf.dsize = sizeof(int32_t);
809 2 : kbuf.dptr = (uint8_t *)&r->record_number;
810 :
811 2 : ebuf.dsize = blob.length;
812 2 : ebuf.dptr = blob.data;
813 :
814 2 : ret = tdb_store(tdb, kbuf, ebuf, 0);
815 2 : if (ret != 0) {
816 0 : tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
817 0 : return NT_STATUS_EVENTLOG_FILE_CORRUPT;
818 : }
819 :
820 2 : ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
821 2 : if (ret != 0) {
822 0 : tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
823 0 : return NT_STATUS_EVENTLOG_FILE_CORRUPT;
824 : }
825 2 : tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
826 :
827 2 : if (record_number) {
828 2 : *record_number = r->record_number;
829 : }
830 :
831 2 : return NT_STATUS_OK;
832 : }
833 :
834 : /********************************************************************
835 : ********************************************************************/
836 :
837 2 : NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
838 : TDB_CONTEXT *tdb,
839 : struct EVENTLOGRECORD *r,
840 : uint32_t *record_number)
841 : {
842 0 : struct eventlog_Record_tdb *t;
843 0 : NTSTATUS status;
844 :
845 2 : t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
846 2 : if (!t) {
847 0 : return NT_STATUS_NO_MEMORY;
848 : }
849 :
850 2 : status = evlog_evt_entry_to_tdb_entry(t, r, t);
851 2 : if (!NT_STATUS_IS_OK(status)) {
852 0 : talloc_free(t);
853 0 : return status;
854 : }
855 :
856 2 : status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
857 2 : talloc_free(t);
858 :
859 2 : return status;
860 : }
861 :
862 : /********************************************************************
863 : ********************************************************************/
864 :
865 2 : NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
866 : const struct EVENTLOGRECORD *e,
867 : struct eventlog_Record_tdb *t)
868 : {
869 0 : uint32_t i;
870 :
871 2 : ZERO_STRUCTP(t);
872 :
873 2 : t->size = e->Length;
874 2 : t->reserved = e->Reserved;
875 2 : t->record_number = e->RecordNumber;
876 2 : t->time_generated = e->TimeGenerated;
877 2 : t->time_written = e->TimeWritten;
878 2 : t->event_id = e->EventID;
879 2 : t->event_type = e->EventType;
880 2 : t->num_of_strings = e->NumStrings;
881 2 : t->event_category = e->EventCategory;
882 2 : t->reserved_flags = e->ReservedFlags;
883 2 : t->closing_record_number = e->ClosingRecordNumber;
884 :
885 2 : t->stringoffset = e->StringOffset;
886 2 : t->sid_length = e->UserSidLength;
887 2 : t->sid_offset = e->UserSidOffset;
888 2 : t->data_length = e->DataLength;
889 2 : t->data_offset = e->DataOffset;
890 :
891 2 : t->source_name_len = 2 * strlen_m_term(e->SourceName);
892 2 : t->source_name = talloc_strdup(mem_ctx, e->SourceName);
893 2 : NT_STATUS_HAVE_NO_MEMORY(t->source_name);
894 :
895 2 : t->computer_name_len = 2 * strlen_m_term(e->Computername);
896 2 : t->computer_name = talloc_strdup(mem_ctx, e->Computername);
897 2 : NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
898 :
899 : /* t->sid_padding; */
900 2 : if (e->UserSidLength > 0) {
901 0 : struct dom_sid_buf sid_str;
902 0 : smb_ucs2_t *dummy = NULL;
903 0 : t->sid_length = rpcstr_push_talloc(
904 : mem_ctx,
905 : &dummy,
906 0 : dom_sid_str_buf(&e->UserSid, &sid_str));
907 0 : if (t->sid_length == -1) {
908 0 : return NT_STATUS_NO_MEMORY;
909 : }
910 0 : t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
911 0 : NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
912 : }
913 :
914 2 : t->strings = talloc_array(mem_ctx, const char *, e->NumStrings);
915 4 : for (i=0; i < e->NumStrings; i++) {
916 2 : t->strings[i] = talloc_strdup(t->strings, e->Strings[i]);
917 2 : NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
918 : }
919 :
920 2 : t->strings_len = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
921 2 : t->data = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
922 : /* t->padding = r->Pad; */
923 :
924 2 : return NT_STATUS_OK;
925 : }
926 :
927 : /********************************************************************
928 : ********************************************************************/
929 :
930 0 : NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
931 : const struct eventlog_Record_tdb *t,
932 : struct EVENTLOGRECORD *e)
933 : {
934 0 : uint32_t i;
935 :
936 0 : ZERO_STRUCTP(e);
937 :
938 0 : e->Length = t->size;
939 0 : e->Reserved = t->reserved;
940 0 : e->RecordNumber = t->record_number;
941 0 : e->TimeGenerated = t->time_generated;
942 0 : e->TimeWritten = t->time_written;
943 0 : e->EventID = t->event_id;
944 0 : e->EventType = t->event_type;
945 0 : e->NumStrings = t->num_of_strings;
946 0 : e->EventCategory = t->event_category;
947 0 : e->ReservedFlags = t->reserved_flags;
948 0 : e->ClosingRecordNumber = t->closing_record_number;
949 :
950 0 : e->StringOffset = t->stringoffset;
951 0 : e->UserSidLength = t->sid_length;
952 0 : e->UserSidOffset = t->sid_offset;
953 0 : e->DataLength = t->data_length;
954 0 : e->DataOffset = t->data_offset;
955 :
956 0 : e->SourceName = talloc_strdup(mem_ctx, t->source_name);
957 0 : NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
958 :
959 0 : e->Computername = talloc_strdup(mem_ctx, t->computer_name);
960 0 : NT_STATUS_HAVE_NO_MEMORY(e->Computername);
961 :
962 0 : if (t->sid_length > 0) {
963 0 : char *sid_str = NULL;
964 0 : size_t len;
965 0 : if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
966 0 : t->sid.data, t->sid.length,
967 : (void *)&sid_str, &len)) {
968 0 : return NT_STATUS_INVALID_SID;
969 : }
970 0 : if (len > 0) {
971 0 : bool ok = string_to_sid(&e->UserSid, sid_str);
972 0 : if (!ok) {
973 0 : return NT_STATUS_INVALID_SID;
974 : }
975 : }
976 0 : TALLOC_FREE(sid_str);
977 : }
978 :
979 0 : e->Strings = talloc_array(mem_ctx, const char *, t->num_of_strings);
980 0 : for (i=0; i < t->num_of_strings; i++) {
981 0 : e->Strings[i] = talloc_strdup(e->Strings, t->strings[i]);
982 0 : NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
983 : }
984 :
985 0 : e->Data = (uint8_t *)talloc_memdup(mem_ctx, t->data.data, t->data_length);
986 0 : e->Pad = talloc_strdup(mem_ctx, "");
987 0 : NT_STATUS_HAVE_NO_MEMORY(e->Pad);
988 :
989 0 : e->Length2 = t->size;
990 :
991 0 : return NT_STATUS_OK;
992 : }
993 :
994 : /********************************************************************
995 : ********************************************************************/
996 :
997 0 : NTSTATUS evlog_convert_tdb_to_evt(TALLOC_CTX *mem_ctx,
998 : ELOG_TDB *etdb,
999 : DATA_BLOB *blob_p,
1000 : uint32_t *num_records_p)
1001 : {
1002 0 : NTSTATUS status = NT_STATUS_OK;
1003 0 : enum ndr_err_code ndr_err;
1004 0 : DATA_BLOB blob;
1005 0 : uint32_t num_records = 0;
1006 0 : struct EVENTLOG_EVT_FILE evt;
1007 0 : uint32_t count = 1;
1008 0 : size_t endoffset = 0;
1009 :
1010 0 : ZERO_STRUCT(evt);
1011 :
1012 0 : while (1) {
1013 :
1014 0 : struct eventlog_Record_tdb *r;
1015 0 : struct EVENTLOGRECORD e;
1016 :
1017 0 : r = evlog_pull_record_tdb(mem_ctx, etdb->tdb, count);
1018 0 : if (!r) {
1019 0 : break;
1020 : }
1021 :
1022 0 : status = evlog_tdb_entry_to_evt_entry(mem_ctx, r, &e);
1023 0 : if (!NT_STATUS_IS_OK(status)) {
1024 0 : goto done;
1025 : }
1026 :
1027 0 : endoffset += ndr_size_EVENTLOGRECORD(&e, 0);
1028 :
1029 0 : ADD_TO_ARRAY(mem_ctx, struct EVENTLOGRECORD, e, &evt.records, &num_records);
1030 0 : count++;
1031 : }
1032 :
1033 0 : evt.hdr.StartOffset = 0x30;
1034 0 : evt.hdr.EndOffset = evt.hdr.StartOffset + endoffset;
1035 0 : evt.hdr.CurrentRecordNumber = count;
1036 0 : evt.hdr.OldestRecordNumber = 1;
1037 0 : evt.hdr.MaxSize = tdb_fetch_int32(etdb->tdb, EVT_MAXSIZE);
1038 0 : evt.hdr.Flags = 0;
1039 0 : evt.hdr.Retention = tdb_fetch_int32(etdb->tdb, EVT_RETENTION);
1040 :
1041 0 : if (DEBUGLEVEL >= 10) {
1042 0 : NDR_PRINT_DEBUG(EVENTLOGHEADER, &evt.hdr);
1043 : }
1044 :
1045 0 : evt.eof.BeginRecord = 0x30;
1046 0 : evt.eof.EndRecord = evt.hdr.StartOffset + endoffset;
1047 0 : evt.eof.CurrentRecordNumber = evt.hdr.CurrentRecordNumber;
1048 0 : evt.eof.OldestRecordNumber = evt.hdr.OldestRecordNumber;
1049 :
1050 0 : if (DEBUGLEVEL >= 10) {
1051 0 : NDR_PRINT_DEBUG(EVENTLOGEOF, &evt.eof);
1052 : }
1053 :
1054 0 : ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &evt,
1055 : (ndr_push_flags_fn_t)ndr_push_EVENTLOG_EVT_FILE);
1056 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1057 0 : status = ndr_map_error2ntstatus(ndr_err);
1058 0 : goto done;
1059 : }
1060 :
1061 0 : *blob_p = blob;
1062 0 : *num_records_p = num_records;
1063 :
1064 0 : done:
1065 0 : return status;
1066 : }
|