s3: Remove some pointless uses of string_sid_talloc
[Samba/nascimento.git] / source3 / lib / eventlog / eventlog.c
blob1c0dba980d54deffb181888f8ce412d4630b2576
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.
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.
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.
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/>.
23 #include "includes.h"
25 /* maintain a list of open eventlog tdbs with reference counts */
27 static ELOG_TDB *open_elog_list;
29 /********************************************************************
30 Init an Eventlog TDB, and return it. If null, something bad
31 happened.
32 ********************************************************************/
34 TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
36 TDB_CONTEXT *tdb;
38 DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
39 tdbfilename));
41 tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT,
42 O_RDWR|O_CREAT|O_TRUNC, 0660 );
44 if ( !tdb ) {
45 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
46 return NULL;
49 /* initialize with defaults, copy real values in here from registry */
51 tdb_store_int32( tdb, EVT_OLDEST_ENTRY, 1 );
52 tdb_store_int32( tdb, EVT_NEXT_RECORD, 1 );
53 tdb_store_int32( tdb, EVT_MAXSIZE, 0x80000 );
54 tdb_store_int32( tdb, EVT_RETENTION, 0x93A80 );
56 tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
58 return tdb;
61 /********************************************************************
62 make the tdb file name for an event log, given destination buffer
63 and size. Caller must free memory.
64 ********************************************************************/
66 char *elog_tdbname(TALLOC_CTX *ctx, const char *name )
68 char *path = talloc_asprintf(ctx, "%s/%s.tdb",
69 state_path("eventlog"),
70 name);
71 if (!path) {
72 return NULL;
74 strlower_m(path);
75 return path;
79 /********************************************************************
80 this function is used to count up the number of bytes in a
81 particular TDB
82 ********************************************************************/
84 struct trav_size_struct {
85 int size;
86 int rec_count;
89 static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
90 void *state )
92 struct trav_size_struct *tsize = (struct trav_size_struct *)state;
94 tsize->size += data.dsize;
95 tsize->rec_count++;
97 return 0;
100 /********************************************************************
101 returns the size of the eventlog, and if MaxSize is a non-null
102 ptr, puts the MaxSize there. This is purely a way not to have yet
103 another function that solely reads the maxsize of the eventlog.
104 Yeah, that's it.
105 ********************************************************************/
107 int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
109 struct trav_size_struct tsize;
111 if ( !tdb )
112 return 0;
114 ZERO_STRUCT( tsize );
116 tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
118 if ( MaxSize != NULL ) {
119 *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
122 if ( Retention != NULL ) {
123 *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
126 DEBUG( 1,
127 ( "eventlog size: [%d] for [%d] records\n", tsize.size,
128 tsize.rec_count ) );
129 return tsize.size;
132 /********************************************************************
133 Discard early event logs until we have enough for 'needed' bytes...
134 NO checking done beforehand to see that we actually need to do
135 this, and it's going to pluck records one-by-one. So, it's best
136 to determine that this needs to be done before doing it.
138 Setting whack_by_date to True indicates that eventlogs falling
139 outside of the retention range need to go...
141 return True if we made enough room to accommodate needed bytes
142 ********************************************************************/
144 static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32_t needed,
145 bool whack_by_date )
147 int32_t start_record, i, new_start;
148 int32_t end_record;
149 int32_t reclen, tresv1, trecnum, timegen, timewr;
150 int nbytes, len, Retention, MaxSize;
151 TDB_DATA key, ret;
152 time_t current_time, exp_time;
154 /* discard some eventlogs */
156 /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
157 although records not necessarily guaranteed to have successive times */
158 /* */
160 /* lock */
161 tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
162 /* read */
163 end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
164 start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
165 Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
166 MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
168 time( &current_time );
170 /* calculate ... */
171 exp_time = current_time - Retention; /* discard older than exp_time */
173 /* todo - check for sanity in next_record */
174 nbytes = 0;
176 DEBUG( 3,
177 ( "MaxSize [%d] Retention [%d] Current Time [%u] exp_time [%u]\n",
178 MaxSize, Retention, (unsigned int)current_time, (unsigned int)exp_time ) );
179 DEBUG( 3,
180 ( "Start Record [%u] End Record [%u]\n",
181 (unsigned int)start_record,
182 (unsigned int)end_record ));
184 for ( i = start_record; i < end_record; i++ ) {
185 /* read a record, add the amt to nbytes */
186 key.dsize = sizeof(int32_t);
187 key.dptr = (unsigned char *)&i;
188 ret = tdb_fetch( the_tdb, key );
189 if ( ret.dsize == 0 ) {
190 DEBUG( 8,
191 ( "Can't find a record for the key, record [%d]\n",
192 i ) );
193 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
194 return False;
196 nbytes += ret.dsize; /* note this includes overhead */
198 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
199 &tresv1, &trecnum, &timegen, &timewr );
200 if (len == -1) {
201 DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
202 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
203 SAFE_FREE( ret.dptr );
204 return False;
207 DEBUG( 8,
208 ( "read record %u, record size is [%d], total so far [%d]\n",
209 (unsigned int)i, reclen, nbytes ) );
211 SAFE_FREE( ret.dptr );
213 /* note that other servers may just stop writing records when the size limit
214 is reached, and there are no records older than 'retention'. This doesn't
215 like a very useful thing to do, so instead we whack (as in sleeps with the
216 fishes) just enough records to fit the what we need. This behavior could
217 be changed to 'match', if the need arises. */
219 if ( !whack_by_date && ( nbytes >= needed ) )
220 break; /* done */
221 if ( whack_by_date && ( timegen >= exp_time ) )
222 break; /* done */
225 DEBUG( 3,
226 ( "nbytes [%d] needed [%d] start_record is [%u], should be set to [%u]\n",
227 nbytes, needed, (unsigned int)start_record, (unsigned int)i ) );
228 /* todo - remove eventlog entries here and set starting record to start_record... */
229 new_start = i;
230 if ( start_record != new_start ) {
231 for ( i = start_record; i < new_start; i++ ) {
232 key.dsize = sizeof(int32_t);
233 key.dptr = (unsigned char *)&i;
234 tdb_delete( the_tdb, key );
237 tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
239 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
240 return True;
243 /********************************************************************
244 some hygiene for an eventlog - see how big it is, and then
245 calculate how many bytes we need to remove
246 ********************************************************************/
248 bool prune_eventlog( TDB_CONTEXT * tdb )
250 int MaxSize, Retention, CalcdSize;
252 if ( !tdb ) {
253 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
254 return False;
257 CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
258 DEBUG( 3,
259 ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
260 MaxSize ) );
262 if ( CalcdSize > MaxSize ) {
263 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
264 False );
267 return make_way_for_eventlogs( tdb, 0, True );
270 /********************************************************************
271 ********************************************************************/
273 static bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32_t needed )
275 int calcd_size;
276 int MaxSize, Retention;
278 /* see if we can write to the eventlog -- do a policy enforcement */
279 if ( !tdb )
280 return False; /* tdb is null, so we can't write to it */
283 if ( needed < 0 )
284 return False;
285 MaxSize = 0;
286 Retention = 0;
288 calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
290 if ( calcd_size <= MaxSize )
291 return True; /* you betcha */
292 if ( calcd_size + needed < MaxSize )
293 return True;
295 if ( Retention == 0xffffffff ) {
296 return False; /* see msdn - we can't write no room, discard */
299 note don't have to test, but always good to show intent, in case changes needed
300 later
303 if ( Retention == 0x00000000 ) {
304 /* discard record(s) */
305 /* todo - decide when to remove a bunch vs. just what we need... */
306 return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
307 True );
310 return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
313 /*******************************************************************
314 *******************************************************************/
316 ELOG_TDB *elog_open_tdb( const char *logname, bool force_clear, bool read_only )
318 TDB_CONTEXT *tdb = NULL;
319 uint32_t vers_id;
320 ELOG_TDB *ptr;
321 char *tdbpath = NULL;
322 ELOG_TDB *tdb_node = NULL;
323 char *eventlogdir;
324 TALLOC_CTX *ctx = talloc_tos();
326 /* check for invalid options */
328 if (force_clear && read_only) {
329 DEBUG(1,("elog_open_tdb: Invalid flags\n"));
330 return NULL;
333 /* first see if we have an open context */
335 for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
336 if ( strequal( ptr->name, logname ) ) {
337 ptr->ref_count++;
339 /* trick to alow clearing of the eventlog tdb.
340 The force_clear flag should imply that someone
341 has done a force close. So make sure the tdb
342 is NULL. If this is a normal open, then just
343 return the existing reference */
345 if ( force_clear ) {
346 SMB_ASSERT( ptr->tdb == NULL );
347 break;
349 else
350 return ptr;
354 /* make sure that the eventlog dir exists */
356 eventlogdir = state_path( "eventlog" );
357 if ( !directory_exist( eventlogdir ) )
358 mkdir( eventlogdir, 0755 );
360 /* get the path on disk */
362 tdbpath = elog_tdbname(ctx, logname);
363 if (!tdbpath) {
364 return NULL;
367 DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
368 tdbpath, force_clear?"True":"False" ));
370 /* the tdb wasn't already open or this is a forced clear open */
372 if ( !force_clear ) {
374 tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, read_only ? O_RDONLY : O_RDWR , 0 );
375 if ( tdb ) {
376 vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
378 if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
379 DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
380 vers_id, tdbpath));
381 tdb_close( tdb );
382 tdb = elog_init_tdb( tdbpath );
387 if ( !tdb )
388 tdb = elog_init_tdb( tdbpath );
390 /* if we got a valid context, then add it to the list */
392 if ( tdb ) {
393 /* on a forced clear, just reset the tdb context if we already
394 have an open entry in the list */
396 if ( ptr ) {
397 ptr->tdb = tdb;
398 return ptr;
401 if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) {
402 DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
403 tdb_close( tdb );
404 return NULL;
407 tdb_node->name = talloc_strdup( tdb_node, logname );
408 tdb_node->tdb = tdb;
409 tdb_node->ref_count = 1;
411 DLIST_ADD( open_elog_list, tdb_node );
414 return tdb_node;
417 /*******************************************************************
418 Wrapper to handle reference counts to the tdb
419 *******************************************************************/
421 int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
423 TDB_CONTEXT *tdb;
425 if ( !etdb )
426 return 0;
428 etdb->ref_count--;
430 SMB_ASSERT( etdb->ref_count >= 0 );
432 if ( etdb->ref_count == 0 ) {
433 tdb = etdb->tdb;
434 DLIST_REMOVE( open_elog_list, etdb );
435 TALLOC_FREE( etdb );
436 return tdb_close( tdb );
439 if ( force_close ) {
440 tdb = etdb->tdb;
441 etdb->tdb = NULL;
442 return tdb_close( tdb );
445 return 0;
448 /********************************************************************
449 Note that it's a pretty good idea to initialize the Eventlog_entry
450 structure to zero's before calling parse_logentry on an batch of
451 lines that may resolve to a record. ALSO, it's a good idea to
452 remove any linefeeds (that's EOL to you and me) on the lines
453 going in.
454 ********************************************************************/
456 bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
458 char *start = NULL, *stop = NULL;
460 start = line;
462 /* empty line signyfiying record delimeter, or we're at the end of the buffer */
463 if ( start == NULL || strlen( start ) == 0 ) {
464 DEBUG( 6,
465 ( "parse_logentry: found end-of-record indicator.\n" ) );
466 *eor = True;
467 return True;
469 if ( !( stop = strchr( line, ':' ) ) ) {
470 return False;
473 DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
475 if ( 0 == strncmp( start, "LEN", stop - start ) ) {
476 /* This will get recomputed later anyway -- probably not necessary */
477 entry->size = atoi( stop + 1 );
478 } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
479 /* For now all these reserved entries seem to have the same value,
480 which can be hardcoded to int(1699505740) for now */
481 entry->reserved = talloc_strdup(mem_ctx, "eLfL");
482 } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
483 entry->record_number = atoi( stop + 1 );
484 } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
485 entry->time_generated = atoi( stop + 1 );
486 } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
487 entry->time_written = atoi( stop + 1 );
488 } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
489 entry->event_id = atoi( stop + 1 );
490 } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
491 if ( strstr( start, "ERROR" ) ) {
492 entry->event_type = EVENTLOG_ERROR_TYPE;
493 } else if ( strstr( start, "WARNING" ) ) {
494 entry->event_type = EVENTLOG_WARNING_TYPE;
495 } else if ( strstr( start, "INFO" ) ) {
496 entry->event_type = EVENTLOG_INFORMATION_TYPE;
497 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
498 entry->event_type = EVENTLOG_AUDIT_SUCCESS;
499 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
500 entry->event_type = EVENTLOG_AUDIT_FAILURE;
501 } else if ( strstr( start, "SUCCESS" ) ) {
502 entry->event_type = EVENTLOG_SUCCESS;
503 } else {
504 /* some other eventlog type -- currently not defined in MSDN docs, so error out */
505 return False;
510 else if(0 == strncmp(start, "NST", stop - start))
512 entry->num_of_strings = atoi(stop + 1);
515 else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
516 entry->event_category = atoi( stop + 1 );
517 } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
518 entry->reserved_flags = atoi( stop + 1 );
519 } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
520 entry->closing_record_number = atoi( stop + 1 );
521 } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
522 entry->sid_length = atoi( stop + 1 );
523 } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
524 stop++;
525 while ( isspace( stop[0] ) ) {
526 stop++;
528 entry->source_name_len = strlen_m_term(stop);
529 entry->source_name = talloc_strdup(mem_ctx, stop);
530 if (entry->source_name_len == (uint32_t)-1 ||
531 entry->source_name == NULL) {
532 return false;
534 } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
535 stop++;
536 while ( isspace( stop[0] ) ) {
537 stop++;
539 entry->computer_name_len = strlen_m_term(stop);
540 entry->computer_name = talloc_strdup(mem_ctx, stop);
541 if (entry->computer_name_len == (uint32_t)-1 ||
542 entry->computer_name == NULL) {
543 return false;
545 } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
546 smb_ucs2_t *dummy = NULL;
547 stop++;
548 while ( isspace( stop[0] ) ) {
549 stop++;
551 entry->sid_length = rpcstr_push_talloc(mem_ctx,
552 &dummy,
553 stop);
554 if (entry->sid_length == (uint32_t)-1) {
555 return false;
557 entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
558 if (entry->sid.data == NULL) {
559 return false;
561 } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
562 size_t tmp_len;
563 int num_of_strings;
564 /* skip past initial ":" */
565 stop++;
566 /* now skip any other leading whitespace */
567 while ( isspace(stop[0])) {
568 stop++;
570 tmp_len = strlen_m_term(stop);
571 if (tmp_len == (size_t)-1) {
572 return false;
574 num_of_strings = entry->num_of_strings;
575 if (!add_string_to_array(mem_ctx, stop, &entry->strings,
576 &num_of_strings)) {
577 return false;
579 if (num_of_strings > 0xffff) {
580 return false;
582 entry->num_of_strings = num_of_strings;
583 entry->strings_len += tmp_len;
584 } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
585 /* skip past initial ":" */
586 stop++;
587 /* now skip any other leading whitespace */
588 while ( isspace( stop[0] ) ) {
589 stop++;
591 entry->data_length = strlen_m(stop);
592 entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
593 if (!entry->data.data) {
594 return false;
596 } else {
597 /* some other eventlog entry -- not implemented, so dropping on the floor */
598 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
599 /* For now return true so that we can keep on parsing this mess. Eventually
600 we will return False here. */
601 return true;
603 return true;
606 /*******************************************************************
607 calculate the correct fields etc for an eventlog entry
608 *******************************************************************/
610 size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
612 size_t size = 56; /* static size of integers before buffers start */
614 r->source_name_len = strlen_m_term(r->source_name) * 2;
615 r->computer_name_len = strlen_m_term(r->computer_name) * 2;
616 r->strings_len = ndr_size_string_array(r->strings,
617 r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
619 /* fix up the eventlog entry structure as necessary */
620 r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
621 r->padding = ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
623 if (r->sid_length == 0) {
624 /* Should not pad to a DWORD boundary for writing out the sid if there is
625 no SID, so just propagate the padding to pad the data */
626 r->padding += r->sid_padding;
627 r->sid_padding = 0;
630 size += r->source_name_len;
631 size += r->computer_name_len;
632 size += r->sid_padding;
633 size += r->sid_length;
634 size += r->strings_len;
635 size += r->data_length;
636 size += r->padding;
637 /* need another copy of length at the end of the data */
638 size += sizeof(r->size);
640 r->size = size;
642 return size;
646 /********************************************************************
647 ********************************************************************/
649 struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
650 TDB_CONTEXT *tdb,
651 uint32_t record_number)
653 struct eventlog_Record_tdb *r;
654 TDB_DATA data, key;
656 int32_t srecno;
657 enum ndr_err_code ndr_err;
658 DATA_BLOB blob;
660 srecno = record_number;
661 key.dptr = (unsigned char *)&srecno;
662 key.dsize = sizeof(int32_t);
664 data = tdb_fetch(tdb, key);
665 if (data.dsize == 0) {
666 DEBUG(8,("evlog_pull_record_tdb: "
667 "Can't find a record for the key, record %d\n",
668 record_number));
669 return NULL;
672 r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
673 if (!r) {
674 goto done;
677 blob = data_blob_const(data.dptr, data.dsize);
679 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, r,
680 (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
682 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
683 DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
684 record_number));
685 TALLOC_FREE(r);
686 goto done;
689 if (DEBUGLEVEL >= 10) {
690 NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
693 DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
694 record_number));
695 done:
696 SAFE_FREE(data.dptr);
698 return r;
701 /********************************************************************
702 ********************************************************************/
704 struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
705 TDB_CONTEXT *tdb,
706 uint32_t record_number)
708 struct eventlog_Record_tdb *t;
709 struct EVENTLOGRECORD *r;
710 NTSTATUS status;
712 r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
713 if (!r) {
714 return NULL;
717 t = evlog_pull_record_tdb(r, tdb, record_number);
718 if (!t) {
719 talloc_free(r);
720 return NULL;
723 status = evlog_tdb_entry_to_evt_entry(r, t, r);
724 if (!NT_STATUS_IS_OK(status)) {
725 talloc_free(r);
726 return NULL;
729 r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, NULL, 0);
731 return r;
734 /********************************************************************
735 write an eventlog entry. Note that we have to lock, read next
736 eventlog, increment, write, write the record, unlock
738 coming into this, ee has the eventlog record, and the auxilliary date
739 (computer name, etc.) filled into the other structure. Before packing
740 into a record, this routine will calc the appropriate padding, etc.,
741 and then blast out the record in a form that can be read back in
742 ********************************************************************/
744 NTSTATUS evlog_push_record_tdb(TALLOC_CTX *mem_ctx,
745 TDB_CONTEXT *tdb,
746 struct eventlog_Record_tdb *r,
747 uint32_t *record_number)
749 TDB_DATA kbuf, ebuf;
750 DATA_BLOB blob;
751 enum ndr_err_code ndr_err;
752 int ret;
754 if (!r) {
755 return NT_STATUS_INVALID_PARAMETER;
758 if (!can_write_to_eventlog(tdb, r->size)) {
759 return NT_STATUS_EVENTLOG_CANT_START;
762 /* need to read the record number and insert it into the entry here */
764 /* lock */
765 ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
766 if (ret == -1) {
767 return NT_STATUS_LOCK_NOT_GRANTED;
770 /* read */
771 r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
773 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, r,
774 (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
775 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
776 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
777 return ndr_map_error2ntstatus(ndr_err);
780 /* increment the record count */
782 kbuf.dsize = sizeof(int32_t);
783 kbuf.dptr = (uint8_t *)&r->record_number;
785 ebuf.dsize = blob.length;
786 ebuf.dptr = blob.data;
788 ret = tdb_store(tdb, kbuf, ebuf, 0);
789 if (ret == -1) {
790 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
791 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
794 ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
795 if (ret == -1) {
796 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
797 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
799 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
801 if (record_number) {
802 *record_number = r->record_number;
805 return NT_STATUS_OK;
808 /********************************************************************
809 ********************************************************************/
811 NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
812 TDB_CONTEXT *tdb,
813 struct EVENTLOGRECORD *r,
814 uint32_t *record_number)
816 struct eventlog_Record_tdb *t;
817 NTSTATUS status;
819 t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
820 if (!t) {
821 return NT_STATUS_NO_MEMORY;
824 status = evlog_evt_entry_to_tdb_entry(t, r, t);
825 if (!NT_STATUS_IS_OK(status)) {
826 talloc_free(t);
827 return status;
830 status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
831 talloc_free(t);
833 return status;
836 /********************************************************************
837 ********************************************************************/
839 NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
840 const struct EVENTLOGRECORD *e,
841 struct eventlog_Record_tdb *t)
843 uint32_t i;
845 ZERO_STRUCTP(t);
847 t->size = e->Length;
848 t->reserved = e->Reserved;
849 t->record_number = e->RecordNumber;
850 t->time_generated = e->TimeGenerated;
851 t->time_written = e->TimeWritten;
852 t->event_id = e->EventID;
853 t->event_type = e->EventType;
854 t->num_of_strings = e->NumStrings;
855 t->event_category = e->EventCategory;
856 t->reserved_flags = e->ReservedFlags;
857 t->closing_record_number = e->ClosingRecordNumber;
859 t->stringoffset = e->StringOffset;
860 t->sid_length = e->UserSidLength;
861 t->sid_offset = e->UserSidOffset;
862 t->data_length = e->DataLength;
863 t->data_offset = e->DataOffset;
865 t->source_name_len = 2 * strlen_m_term(e->SourceName);
866 t->source_name = talloc_strdup(mem_ctx, e->SourceName);
867 NT_STATUS_HAVE_NO_MEMORY(t->source_name);
869 t->computer_name_len = 2 * strlen_m_term(e->Computername);
870 t->computer_name = talloc_strdup(mem_ctx, e->Computername);
871 NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
873 /* t->sid_padding; */
874 if (e->UserSidLength > 0) {
875 const char *sid_str = NULL;
876 smb_ucs2_t *dummy = NULL;
877 sid_str = sid_string_talloc(mem_ctx, &e->UserSid);
878 t->sid_length = rpcstr_push_talloc(mem_ctx, &dummy, sid_str);
879 if (t->sid_length == -1) {
880 return NT_STATUS_NO_MEMORY;
882 t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
883 NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
886 t->strings = talloc_array(mem_ctx, const char *, e->NumStrings);
887 for (i=0; i < e->NumStrings; i++) {
888 t->strings[i] = talloc_strdup(t->strings, e->Strings[i]);
889 NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
892 t->strings_len = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
893 t->data = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
894 /* t->padding = r->Pad; */
896 return NT_STATUS_OK;
899 /********************************************************************
900 ********************************************************************/
902 NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
903 const struct eventlog_Record_tdb *t,
904 struct EVENTLOGRECORD *e)
906 uint32_t i;
908 ZERO_STRUCTP(e);
910 e->Length = t->size;
911 e->Reserved = t->reserved;
912 e->RecordNumber = t->record_number;
913 e->TimeGenerated = t->time_generated;
914 e->TimeWritten = t->time_written;
915 e->EventID = t->event_id;
916 e->EventType = t->event_type;
917 e->NumStrings = t->num_of_strings;
918 e->EventCategory = t->event_category;
919 e->ReservedFlags = t->reserved_flags;
920 e->ClosingRecordNumber = t->closing_record_number;
922 e->StringOffset = t->stringoffset;
923 e->UserSidLength = t->sid_length;
924 e->UserSidOffset = t->sid_offset;
925 e->DataLength = t->data_length;
926 e->DataOffset = t->data_offset;
928 e->SourceName = talloc_strdup(mem_ctx, t->source_name);
929 NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
931 e->Computername = talloc_strdup(mem_ctx, t->computer_name);
932 NT_STATUS_HAVE_NO_MEMORY(e->Computername);
934 if (t->sid_length > 0) {
935 const char *sid_str = NULL;
936 size_t len;
937 if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
938 t->sid.data, t->sid.length,
939 (void *)&sid_str, &len, false)) {
940 return NT_STATUS_INVALID_SID;
942 if (len > 0) {
943 string_to_sid(&e->UserSid, sid_str);
947 e->Strings = talloc_array(mem_ctx, const char *, t->num_of_strings);
948 for (i=0; i < t->num_of_strings; i++) {
949 e->Strings[i] = talloc_strdup(e->Strings, t->strings[i]);
950 NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
953 e->Data = (uint8_t *)talloc_memdup(mem_ctx, t->data.data, t->data_length);
954 e->Pad = talloc_strdup(mem_ctx, "");
955 NT_STATUS_HAVE_NO_MEMORY(e->Pad);
957 e->Length2 = t->size;
959 return NT_STATUS_OK;
962 /********************************************************************
963 ********************************************************************/
965 NTSTATUS evlog_convert_tdb_to_evt(TALLOC_CTX *mem_ctx,
966 ELOG_TDB *etdb,
967 DATA_BLOB *blob_p,
968 uint32_t *num_records_p)
970 NTSTATUS status = NT_STATUS_OK;
971 enum ndr_err_code ndr_err;
972 DATA_BLOB blob;
973 uint32_t num_records = 0;
974 struct EVENTLOG_EVT_FILE evt;
975 uint32_t count = 1;
976 size_t endoffset = 0;
978 ZERO_STRUCT(evt);
980 while (1) {
982 struct eventlog_Record_tdb *r;
983 struct EVENTLOGRECORD e;
985 r = evlog_pull_record_tdb(mem_ctx, etdb->tdb, count);
986 if (!r) {
987 break;
990 status = evlog_tdb_entry_to_evt_entry(mem_ctx, r, &e);
991 if (!NT_STATUS_IS_OK(status)) {
992 goto done;
995 endoffset += ndr_size_EVENTLOGRECORD(&e, NULL, 0);
997 ADD_TO_ARRAY(mem_ctx, struct EVENTLOGRECORD, e, &evt.records, &num_records);
998 count++;
1001 evt.hdr.StartOffset = 0x30;
1002 evt.hdr.EndOffset = evt.hdr.StartOffset + endoffset;
1003 evt.hdr.CurrentRecordNumber = count;
1004 evt.hdr.OldestRecordNumber = 1;
1005 evt.hdr.MaxSize = tdb_fetch_int32(etdb->tdb, EVT_MAXSIZE);
1006 evt.hdr.Flags = 0;
1007 evt.hdr.Retention = tdb_fetch_int32(etdb->tdb, EVT_RETENTION);
1009 if (DEBUGLEVEL >= 10) {
1010 NDR_PRINT_DEBUG(EVENTLOGHEADER, &evt.hdr);
1013 evt.eof.BeginRecord = 0x30;
1014 evt.eof.EndRecord = evt.hdr.StartOffset + endoffset;
1015 evt.eof.CurrentRecordNumber = evt.hdr.CurrentRecordNumber;
1016 evt.eof.OldestRecordNumber = evt.hdr.OldestRecordNumber;
1018 if (DEBUGLEVEL >= 10) {
1019 NDR_PRINT_DEBUG(EVENTLOGEOF, &evt.eof);
1022 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, &evt,
1023 (ndr_push_flags_fn_t)ndr_push_EVENTLOG_EVT_FILE);
1024 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1025 status = ndr_map_error2ntstatus(ndr_err);
1026 goto done;
1029 *blob_p = blob;
1030 *num_records_p = num_records;
1032 done:
1033 return status;