source: vendor/current/source3/lib/eventlog/eventlog.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 29.3 KB
Line 
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
31static ELOG_TDB *open_elog_list;
32
33/********************************************************************
34 Init an Eventlog TDB, and return it. If null, something bad
35 happened.
36********************************************************************/
37
38TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
39{
40 TDB_CONTEXT *tdb;
41
42 DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
43 tdbfilename));
44
45 tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT,
46 O_RDWR|O_CREAT|O_TRUNC, 0660 );
47
48 if ( !tdb ) {
49 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
50 return NULL;
51 }
52
53 /* initialize with defaults, copy real values in here from registry */
54
55 tdb_store_int32( tdb, EVT_OLDEST_ENTRY, 1 );
56 tdb_store_int32( tdb, EVT_NEXT_RECORD, 1 );
57 tdb_store_int32( tdb, EVT_MAXSIZE, 0x80000 );
58 tdb_store_int32( tdb, EVT_RETENTION, 0x93A80 );
59
60 tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
61
62 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
70char *elog_tdbname(TALLOC_CTX *ctx, const char *name )
71{
72 char *path;
73 char *file;
74 char *tdbname;
75
76 path = state_path("eventlog");
77 if (!path) {
78 return NULL;
79 }
80
81 file = talloc_asprintf_strlower_m(path, "%s.tdb", name);
82 if (!file) {
83 talloc_free(path);
84 return NULL;
85 }
86
87 tdbname = talloc_asprintf(ctx, "%s/%s", path, file);
88 if (!tdbname) {
89 talloc_free(path);
90 return NULL;
91 }
92
93 talloc_free(path);
94 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
103struct trav_size_struct {
104 int size;
105 int rec_count;
106};
107
108static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
109 void *state )
110{
111 struct trav_size_struct *tsize = (struct trav_size_struct *)state;
112
113 tsize->size += data.dsize;
114 tsize->rec_count++;
115
116 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
126int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
127{
128 struct trav_size_struct tsize;
129
130 if ( !tdb )
131 return 0;
132
133 ZERO_STRUCT( tsize );
134
135 tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
136
137 if ( MaxSize != NULL ) {
138 *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
139 }
140
141 if ( Retention != NULL ) {
142 *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
143 }
144
145 DEBUG( 1,
146 ( "eventlog size: [%d] for [%d] records\n", tsize.size,
147 tsize.rec_count ) );
148 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
163static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32_t needed,
164 bool whack_by_date )
165{
166 int32_t start_record, i, new_start;
167 int32_t end_record;
168 int32_t reclen, tresv1, trecnum, timegen, timewr;
169 int nbytes, len, Retention, MaxSize;
170 TDB_DATA key, ret;
171 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 tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
181 /* read */
182 end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
183 start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
184 Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
185 MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
186
187 time( &current_time );
188
189 /* calculate ... */
190 exp_time = current_time - Retention; /* discard older than exp_time */
191
192 /* todo - check for sanity in next_record */
193 nbytes = 0;
194
195 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 DEBUG( 3,
199 ( "Start Record [%u] End Record [%u]\n",
200 (unsigned int)start_record,
201 (unsigned int)end_record ));
202
203 for ( i = start_record; i < end_record; i++ ) {
204 /* read a record, add the amt to nbytes */
205 key.dsize = sizeof(int32_t);
206 key.dptr = (unsigned char *)&i;
207 ret = tdb_fetch( the_tdb, key );
208 if ( ret.dsize == 0 ) {
209 DEBUG( 8,
210 ( "Can't find a record for the key, record [%d]\n",
211 i ) );
212 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
213 return False;
214 }
215 nbytes += ret.dsize; /* note this includes overhead */
216
217 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
218 &tresv1, &trecnum, &timegen, &timewr );
219 if (len == -1) {
220 DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
221 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
222 SAFE_FREE( ret.dptr );
223 return False;
224 }
225
226 DEBUG( 8,
227 ( "read record %u, record size is [%d], total so far [%d]\n",
228 (unsigned int)i, reclen, nbytes ) );
229
230 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 if ( !whack_by_date && ( nbytes >= needed ) )
239 break; /* done */
240 if ( whack_by_date && ( timegen >= exp_time ) )
241 break; /* done */
242 }
243
244 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 new_start = i;
249 if ( start_record != new_start ) {
250 for ( i = start_record; i < new_start; i++ ) {
251 key.dsize = sizeof(int32_t);
252 key.dptr = (unsigned char *)&i;
253 tdb_delete( the_tdb, key );
254 }
255
256 tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
257 }
258 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
259 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
267bool prune_eventlog( TDB_CONTEXT * tdb )
268{
269 int MaxSize, Retention, CalcdSize;
270
271 if ( !tdb ) {
272 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
273 return False;
274 }
275
276 CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
277 DEBUG( 3,
278 ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
279 MaxSize ) );
280
281 if ( CalcdSize > MaxSize ) {
282 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
283 False );
284 }
285
286 return make_way_for_eventlogs( tdb, 0, True );
287}
288
289/********************************************************************
290********************************************************************/
291
292static bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32_t needed )
293{
294 int calcd_size;
295 int MaxSize, Retention;
296
297 /* see if we can write to the eventlog -- do a policy enforcement */
298 if ( !tdb )
299 return False; /* tdb is null, so we can't write to it */
300
301
302 if ( needed < 0 )
303 return False;
304 MaxSize = 0;
305 Retention = 0;
306
307 calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
308
309 if ( calcd_size <= MaxSize )
310 return True; /* you betcha */
311 if ( calcd_size + needed < MaxSize )
312 return True;
313
314 if ( Retention == 0xffffffff ) {
315 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 if ( Retention == 0x00000000 ) {
323 /* discard record(s) */
324 /* todo - decide when to remove a bunch vs. just what we need... */
325 return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
326 True );
327 }
328
329 return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
330}
331
332/*******************************************************************
333*******************************************************************/
334
335ELOG_TDB *elog_open_tdb( const char *logname, bool force_clear, bool read_only )
336{
337 TDB_CONTEXT *tdb = NULL;
338 uint32_t vers_id;
339 ELOG_TDB *ptr;
340 char *tdbpath = NULL;
341 ELOG_TDB *tdb_node = NULL;
342 char *eventlogdir;
343 TALLOC_CTX *ctx = talloc_tos();
344 bool ok;
345
346 /* check for invalid options */
347
348 if (force_clear && read_only) {
349 DEBUG(1,("elog_open_tdb: Invalid flags\n"));
350 return NULL;
351 }
352
353 /* first see if we have an open context */
354
355 for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
356 if ( strequal( ptr->name, logname ) ) {
357 ptr->ref_count++;
358
359 /* trick to alow 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 if ( force_clear ) {
366 SMB_ASSERT( ptr->tdb == NULL );
367 break;
368 }
369 else
370 return ptr;
371 }
372 }
373
374 /* make sure that the eventlog dir exists */
375
376 eventlogdir = state_path("eventlog");
377 if (eventlogdir == NULL) {
378 return NULL;
379 }
380 ok = directory_create_or_exist(eventlogdir, 0755);
381 TALLOC_FREE(eventlogdir);
382 if (!ok) {
383 return NULL;
384 }
385
386 /* get the path on disk */
387
388 tdbpath = elog_tdbname(ctx, logname);
389 if (!tdbpath) {
390 return NULL;
391 }
392
393 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 if ( !force_clear ) {
399
400 tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, read_only ? O_RDONLY : O_RDWR , 0 );
401 if ( tdb ) {
402 vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
403
404 if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
405 DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
406 vers_id, tdbpath));
407 tdb_close( tdb );
408 tdb = elog_init_tdb( tdbpath );
409 }
410 }
411 }
412
413 if ( !tdb )
414 tdb = elog_init_tdb( tdbpath );
415
416 /* if we got a valid context, then add it to the list */
417
418 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 if ( ptr ) {
423 ptr->tdb = tdb;
424 return ptr;
425 }
426
427 if ( !(tdb_node = talloc_zero( NULL, ELOG_TDB)) ) {
428 DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
429 tdb_close( tdb );
430 return NULL;
431 }
432
433 tdb_node->name = talloc_strdup( tdb_node, logname );
434 tdb_node->tdb = tdb;
435 tdb_node->ref_count = 1;
436
437 DLIST_ADD( open_elog_list, tdb_node );
438 }
439
440 return tdb_node;
441}
442
443/*******************************************************************
444 Wrapper to handle reference counts to the tdb
445*******************************************************************/
446
447int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
448{
449 TDB_CONTEXT *tdb;
450
451 if ( !etdb )
452 return 0;
453
454 etdb->ref_count--;
455
456 SMB_ASSERT( etdb->ref_count >= 0 );
457
458 if ( etdb->ref_count == 0 ) {
459 tdb = etdb->tdb;
460 DLIST_REMOVE( open_elog_list, etdb );
461 TALLOC_FREE( etdb );
462 return tdb_close( tdb );
463 }
464
465 if ( force_close ) {
466 tdb = etdb->tdb;
467 etdb->tdb = NULL;
468 return tdb_close( tdb );
469 }
470
471 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
482bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
483{
484 char *start = NULL, *stop = NULL;
485
486 start = line;
487
488 /* empty line signyfiying record delimeter, or we're at the end of the buffer */
489 if ( start == NULL || strlen( start ) == 0 ) {
490 DEBUG( 6,
491 ( "parse_logentry: found end-of-record indicator.\n" ) );
492 *eor = True;
493 return True;
494 }
495 if ( !( stop = strchr( line, ':' ) ) ) {
496 return False;
497 }
498
499 DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
500
501 if ( 0 == strncmp( start, "LEN", stop - start ) ) {
502 /* This will get recomputed later anyway -- probably not necessary */
503 entry->size = atoi( stop + 1 );
504 } 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 entry->reserved = talloc_strdup(mem_ctx, "eLfL");
508 } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
509 entry->record_number = atoi( stop + 1 );
510 } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
511 entry->time_generated = atoi( stop + 1 );
512 } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
513 entry->time_written = atoi( stop + 1 );
514 } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
515 entry->event_id = atoi( stop + 1 );
516 } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
517 if ( strstr( start, "ERROR" ) ) {
518 entry->event_type = EVENTLOG_ERROR_TYPE;
519 } else if ( strstr( start, "WARNING" ) ) {
520 entry->event_type = EVENTLOG_WARNING_TYPE;
521 } else if ( strstr( start, "INFO" ) ) {
522 entry->event_type = EVENTLOG_INFORMATION_TYPE;
523 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
524 entry->event_type = EVENTLOG_AUDIT_SUCCESS;
525 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
526 entry->event_type = EVENTLOG_AUDIT_FAILURE;
527 } else if ( strstr( start, "SUCCESS" ) ) {
528 entry->event_type = EVENTLOG_SUCCESS;
529 } else {
530 /* some other eventlog type -- currently not defined in MSDN docs, so error out */
531 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 else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
542 entry->event_category = atoi( stop + 1 );
543 } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
544 entry->reserved_flags = atoi( stop + 1 );
545 } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
546 entry->closing_record_number = atoi( stop + 1 );
547 } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
548 entry->sid_length = atoi( stop + 1 );
549 } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
550 stop++;
551 while ( isspace( stop[0] ) ) {
552 stop++;
553 }
554 entry->source_name_len = strlen_m_term(stop);
555 entry->source_name = talloc_strdup(mem_ctx, stop);
556 if (entry->source_name_len == (uint32_t)-1 ||
557 entry->source_name == NULL) {
558 return false;
559 }
560 } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
561 stop++;
562 while ( isspace( stop[0] ) ) {
563 stop++;
564 }
565 entry->computer_name_len = strlen_m_term(stop);
566 entry->computer_name = talloc_strdup(mem_ctx, stop);
567 if (entry->computer_name_len == (uint32_t)-1 ||
568 entry->computer_name == NULL) {
569 return false;
570 }
571 } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
572 smb_ucs2_t *dummy = NULL;
573 stop++;
574 while ( isspace( stop[0] ) ) {
575 stop++;
576 }
577 entry->sid_length = rpcstr_push_talloc(mem_ctx,
578 &dummy,
579 stop);
580 if (entry->sid_length == (uint32_t)-1) {
581 return false;
582 }
583 entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
584 if (entry->sid.data == NULL) {
585 return false;
586 }
587 } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
588 size_t tmp_len;
589 size_t num_of_strings;
590 /* skip past initial ":" */
591 stop++;
592 /* now skip any other leading whitespace */
593 while ( isspace(stop[0])) {
594 stop++;
595 }
596 tmp_len = strlen_m_term(stop);
597 if (tmp_len == (size_t)-1) {
598 return false;
599 }
600 num_of_strings = entry->num_of_strings;
601 if (!add_string_to_array(mem_ctx, stop, &entry->strings,
602 &num_of_strings)) {
603 return false;
604 }
605 if (num_of_strings > 0xffff) {
606 return false;
607 }
608 entry->num_of_strings = num_of_strings;
609 entry->strings_len += tmp_len;
610 } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
611 /* skip past initial ":" */
612 stop++;
613 /* now skip any other leading whitespace */
614 while ( isspace( stop[0] ) ) {
615 stop++;
616 }
617 entry->data_length = strlen_m(stop);
618 entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
619 if (!entry->data.data) {
620 return false;
621 }
622 } else {
623 /* some other eventlog entry -- not implemented, so dropping on the floor */
624 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 return true;
628 }
629 return true;
630}
631
632/*******************************************************************
633 calculate the correct fields etc for an eventlog entry
634*******************************************************************/
635
636size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
637{
638 size_t size = 56; /* static size of integers before buffers start */
639
640 r->source_name_len = strlen_m_term(r->source_name) * 2;
641 r->computer_name_len = strlen_m_term(r->computer_name) * 2;
642 r->strings_len = ndr_size_string_array(r->strings,
643 r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
644
645 /* fix up the eventlog entry structure as necessary */
646 r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
647 r->padding = ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
648
649 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 r->padding += r->sid_padding;
653 r->sid_padding = 0;
654 }
655
656 size += r->source_name_len;
657 size += r->computer_name_len;
658 size += r->sid_padding;
659 size += r->sid_length;
660 size += r->strings_len;
661 size += r->data_length;
662 size += r->padding;
663 /* need another copy of length at the end of the data */
664 size += sizeof(r->size);
665
666 r->size = size;
667
668 return size;
669}
670
671
672/********************************************************************
673 ********************************************************************/
674
675struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
676 TDB_CONTEXT *tdb,
677 uint32_t record_number)
678{
679 struct eventlog_Record_tdb *r;
680 TDB_DATA data, key;
681
682 int32_t srecno;
683 enum ndr_err_code ndr_err;
684 DATA_BLOB blob;
685
686 srecno = record_number;
687 key.dptr = (unsigned char *)&srecno;
688 key.dsize = sizeof(int32_t);
689
690 data = tdb_fetch(tdb, key);
691 if (data.dsize == 0) {
692 DEBUG(8,("evlog_pull_record_tdb: "
693 "Can't find a record for the key, record %d\n",
694 record_number));
695 return NULL;
696 }
697
698 r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
699 if (!r) {
700 goto done;
701 }
702
703 blob = data_blob_const(data.dptr, data.dsize);
704
705 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, r,
706 (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
707
708 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
709 DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
710 record_number));
711 TALLOC_FREE(r);
712 goto done;
713 }
714
715 if (DEBUGLEVEL >= 10) {
716 NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
717 }
718
719 DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
720 record_number));
721 done:
722 SAFE_FREE(data.dptr);
723
724 return r;
725}
726
727/********************************************************************
728 ********************************************************************/
729
730struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
731 TDB_CONTEXT *tdb,
732 uint32_t record_number)
733{
734 struct eventlog_Record_tdb *t;
735 struct EVENTLOGRECORD *r;
736 NTSTATUS status;
737
738 r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
739 if (!r) {
740 return NULL;
741 }
742
743 t = evlog_pull_record_tdb(r, tdb, record_number);
744 if (!t) {
745 talloc_free(r);
746 return NULL;
747 }
748
749 status = evlog_tdb_entry_to_evt_entry(r, t, r);
750 if (!NT_STATUS_IS_OK(status)) {
751 talloc_free(r);
752 return NULL;
753 }
754
755 r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, 0);
756
757 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 auxilliary 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
770NTSTATUS 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 TDB_DATA kbuf, ebuf;
776 DATA_BLOB blob;
777 enum ndr_err_code ndr_err;
778 int ret;
779
780 if (!r) {
781 return NT_STATUS_INVALID_PARAMETER;
782 }
783
784 if (!can_write_to_eventlog(tdb, r->size)) {
785 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 ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
792 if (ret != 0) {
793 return NT_STATUS_LOCK_NOT_GRANTED;
794 }
795
796 /* read */
797 r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
798
799 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, r,
800 (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
801 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
802 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
803 return ndr_map_error2ntstatus(ndr_err);
804 }
805
806 /* increment the record count */
807
808 kbuf.dsize = sizeof(int32_t);
809 kbuf.dptr = (uint8_t *)&r->record_number;
810
811 ebuf.dsize = blob.length;
812 ebuf.dptr = blob.data;
813
814 ret = tdb_store(tdb, kbuf, ebuf, 0);
815 if (ret != 0) {
816 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
817 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
818 }
819
820 ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
821 if (ret != 0) {
822 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
823 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
824 }
825 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
826
827 if (record_number) {
828 *record_number = r->record_number;
829 }
830
831 return NT_STATUS_OK;
832}
833
834/********************************************************************
835 ********************************************************************/
836
837NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
838 TDB_CONTEXT *tdb,
839 struct EVENTLOGRECORD *r,
840 uint32_t *record_number)
841{
842 struct eventlog_Record_tdb *t;
843 NTSTATUS status;
844
845 t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
846 if (!t) {
847 return NT_STATUS_NO_MEMORY;
848 }
849
850 status = evlog_evt_entry_to_tdb_entry(t, r, t);
851 if (!NT_STATUS_IS_OK(status)) {
852 talloc_free(t);
853 return status;
854 }
855
856 status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
857 talloc_free(t);
858
859 return status;
860}
861
862/********************************************************************
863 ********************************************************************/
864
865NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
866 const struct EVENTLOGRECORD *e,
867 struct eventlog_Record_tdb *t)
868{
869 uint32_t i;
870
871 ZERO_STRUCTP(t);
872
873 t->size = e->Length;
874 t->reserved = e->Reserved;
875 t->record_number = e->RecordNumber;
876 t->time_generated = e->TimeGenerated;
877 t->time_written = e->TimeWritten;
878 t->event_id = e->EventID;
879 t->event_type = e->EventType;
880 t->num_of_strings = e->NumStrings;
881 t->event_category = e->EventCategory;
882 t->reserved_flags = e->ReservedFlags;
883 t->closing_record_number = e->ClosingRecordNumber;
884
885 t->stringoffset = e->StringOffset;
886 t->sid_length = e->UserSidLength;
887 t->sid_offset = e->UserSidOffset;
888 t->data_length = e->DataLength;
889 t->data_offset = e->DataOffset;
890
891 t->source_name_len = 2 * strlen_m_term(e->SourceName);
892 t->source_name = talloc_strdup(mem_ctx, e->SourceName);
893 NT_STATUS_HAVE_NO_MEMORY(t->source_name);
894
895 t->computer_name_len = 2 * strlen_m_term(e->Computername);
896 t->computer_name = talloc_strdup(mem_ctx, e->Computername);
897 NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
898
899 /* t->sid_padding; */
900 if (e->UserSidLength > 0) {
901 const char *sid_str = NULL;
902 smb_ucs2_t *dummy = NULL;
903 sid_str = sid_string_talloc(mem_ctx, &e->UserSid);
904 t->sid_length = rpcstr_push_talloc(mem_ctx, &dummy, sid_str);
905 if (t->sid_length == -1) {
906 return NT_STATUS_NO_MEMORY;
907 }
908 t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
909 NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
910 }
911
912 t->strings = talloc_array(mem_ctx, const char *, e->NumStrings);
913 for (i=0; i < e->NumStrings; i++) {
914 t->strings[i] = talloc_strdup(t->strings, e->Strings[i]);
915 NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
916 }
917
918 t->strings_len = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
919 t->data = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
920 /* t->padding = r->Pad; */
921
922 return NT_STATUS_OK;
923}
924
925/********************************************************************
926 ********************************************************************/
927
928NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
929 const struct eventlog_Record_tdb *t,
930 struct EVENTLOGRECORD *e)
931{
932 uint32_t i;
933
934 ZERO_STRUCTP(e);
935
936 e->Length = t->size;
937 e->Reserved = t->reserved;
938 e->RecordNumber = t->record_number;
939 e->TimeGenerated = t->time_generated;
940 e->TimeWritten = t->time_written;
941 e->EventID = t->event_id;
942 e->EventType = t->event_type;
943 e->NumStrings = t->num_of_strings;
944 e->EventCategory = t->event_category;
945 e->ReservedFlags = t->reserved_flags;
946 e->ClosingRecordNumber = t->closing_record_number;
947
948 e->StringOffset = t->stringoffset;
949 e->UserSidLength = t->sid_length;
950 e->UserSidOffset = t->sid_offset;
951 e->DataLength = t->data_length;
952 e->DataOffset = t->data_offset;
953
954 e->SourceName = talloc_strdup(mem_ctx, t->source_name);
955 NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
956
957 e->Computername = talloc_strdup(mem_ctx, t->computer_name);
958 NT_STATUS_HAVE_NO_MEMORY(e->Computername);
959
960 if (t->sid_length > 0) {
961 const char *sid_str = NULL;
962 size_t len;
963 if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
964 t->sid.data, t->sid.length,
965 (void *)&sid_str, &len)) {
966 return NT_STATUS_INVALID_SID;
967 }
968 if (len > 0) {
969 string_to_sid(&e->UserSid, sid_str);
970 }
971 }
972
973 e->Strings = talloc_array(mem_ctx, const char *, t->num_of_strings);
974 for (i=0; i < t->num_of_strings; i++) {
975 e->Strings[i] = talloc_strdup(e->Strings, t->strings[i]);
976 NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
977 }
978
979 e->Data = (uint8_t *)talloc_memdup(mem_ctx, t->data.data, t->data_length);
980 e->Pad = talloc_strdup(mem_ctx, "");
981 NT_STATUS_HAVE_NO_MEMORY(e->Pad);
982
983 e->Length2 = t->size;
984
985 return NT_STATUS_OK;
986}
987
988/********************************************************************
989 ********************************************************************/
990
991NTSTATUS evlog_convert_tdb_to_evt(TALLOC_CTX *mem_ctx,
992 ELOG_TDB *etdb,
993 DATA_BLOB *blob_p,
994 uint32_t *num_records_p)
995{
996 NTSTATUS status = NT_STATUS_OK;
997 enum ndr_err_code ndr_err;
998 DATA_BLOB blob;
999 uint32_t num_records = 0;
1000 struct EVENTLOG_EVT_FILE evt;
1001 uint32_t count = 1;
1002 size_t endoffset = 0;
1003
1004 ZERO_STRUCT(evt);
1005
1006 while (1) {
1007
1008 struct eventlog_Record_tdb *r;
1009 struct EVENTLOGRECORD e;
1010
1011 r = evlog_pull_record_tdb(mem_ctx, etdb->tdb, count);
1012 if (!r) {
1013 break;
1014 }
1015
1016 status = evlog_tdb_entry_to_evt_entry(mem_ctx, r, &e);
1017 if (!NT_STATUS_IS_OK(status)) {
1018 goto done;
1019 }
1020
1021 endoffset += ndr_size_EVENTLOGRECORD(&e, 0);
1022
1023 ADD_TO_ARRAY(mem_ctx, struct EVENTLOGRECORD, e, &evt.records, &num_records);
1024 count++;
1025 }
1026
1027 evt.hdr.StartOffset = 0x30;
1028 evt.hdr.EndOffset = evt.hdr.StartOffset + endoffset;
1029 evt.hdr.CurrentRecordNumber = count;
1030 evt.hdr.OldestRecordNumber = 1;
1031 evt.hdr.MaxSize = tdb_fetch_int32(etdb->tdb, EVT_MAXSIZE);
1032 evt.hdr.Flags = 0;
1033 evt.hdr.Retention = tdb_fetch_int32(etdb->tdb, EVT_RETENTION);
1034
1035 if (DEBUGLEVEL >= 10) {
1036 NDR_PRINT_DEBUG(EVENTLOGHEADER, &evt.hdr);
1037 }
1038
1039 evt.eof.BeginRecord = 0x30;
1040 evt.eof.EndRecord = evt.hdr.StartOffset + endoffset;
1041 evt.eof.CurrentRecordNumber = evt.hdr.CurrentRecordNumber;
1042 evt.eof.OldestRecordNumber = evt.hdr.OldestRecordNumber;
1043
1044 if (DEBUGLEVEL >= 10) {
1045 NDR_PRINT_DEBUG(EVENTLOGEOF, &evt.eof);
1046 }
1047
1048 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &evt,
1049 (ndr_push_flags_fn_t)ndr_push_EVENTLOG_EVT_FILE);
1050 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1051 status = ndr_map_error2ntstatus(ndr_err);
1052 goto done;
1053 }
1054
1055 *blob_p = blob;
1056 *num_records_p = num_records;
1057
1058 done:
1059 return status;
1060}
Note: See TracBrowser for help on using the repository browser.