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/>.
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
32 ********************************************************************/
34 TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
38 DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
41 tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT,
42 O_RDWR|O_CREAT|O_TRUNC, 0660 );
45 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
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 );
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"),
79 /********************************************************************
80 this function is used to count up the number of bytes in a
82 ********************************************************************/
84 struct trav_size_struct {
89 static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
92 struct trav_size_struct *tsize = (struct trav_size_struct *)state;
94 tsize->size += data.dsize;
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.
105 ********************************************************************/
107 int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
109 struct trav_size_struct tsize;
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 );
127 ( "eventlog size: [%d] for [%d] records\n", 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,
147 int32_t start_record, i, new_start;
149 int32_t reclen, tresv1, trecnum, timegen, timewr;
150 int nbytes, len, Retention, MaxSize;
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 */
161 tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
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( ¤t_time );
171 exp_time = current_time - Retention; /* discard older than exp_time */
173 /* todo - check for sanity in next_record */
177 ( "MaxSize [%d] Retention [%d] Current Time [%u] exp_time [%u]\n",
178 MaxSize, Retention, (unsigned int)current_time, (unsigned int)exp_time ) );
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 ) {
191 ( "Can't find a record for the key, record [%d]\n",
193 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
196 nbytes += ret.dsize; /* note this includes overhead */
198 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
199 &tresv1, &trecnum, &timegen, &timewr );
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 );
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 ) )
221 if ( whack_by_date && ( timegen >= exp_time ) )
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... */
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 );
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;
253 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
257 CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
259 ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
262 if ( CalcdSize > MaxSize ) {
263 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
267 return make_way_for_eventlogs( tdb, 0, True );
270 /********************************************************************
271 ********************************************************************/
273 bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32_t needed )
276 int MaxSize, Retention;
278 /* see if we can write to the eventlog -- do a policy enforcement */
280 return False; /* tdb is null, so we can't write to it */
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 )
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
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,
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;
321 char *tdbpath = NULL;
322 ELOG_TDB *tdb_node = NULL;
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"));
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 ) ) {
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 */
346 SMB_ASSERT( ptr->tdb == NULL );
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);
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 );
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",
382 tdb = elog_init_tdb( tdbpath );
388 tdb = elog_init_tdb( tdbpath );
390 /* if we got a valid context, then add it to the list */
393 /* on a forced clear, just reset the tdb context if we already
394 have an open entry in the list */
401 if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) {
402 DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
407 tdb_node->name = talloc_strdup( tdb_node, logname );
409 tdb_node->ref_count = 1;
411 DLIST_ADD( open_elog_list, tdb_node );
417 /*******************************************************************
418 Wrapper to handle reference counts to the tdb
419 *******************************************************************/
421 int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
430 SMB_ASSERT( etdb->ref_count >= 0 );
432 if ( etdb->ref_count == 0 ) {
434 DLIST_REMOVE( open_elog_list, etdb );
436 return tdb_close( tdb );
442 return tdb_close( tdb );
449 /*******************************************************************
450 write an eventlog entry. Note that we have to lock, read next
451 eventlog, increment, write, write the record, unlock
453 coming into this, ee has the eventlog record, and the auxilliary date
454 (computer name, etc.) filled into the other structure. Before packing
455 into a record, this routine will calc the appropriate padding, etc.,
456 and then blast out the record in a form that can be read back in
457 *******************************************************************/
461 int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee )
465 TALLOC_CTX *mem_ctx = NULL;
472 mem_ctx = talloc_init( "write_eventlog_tdb" );
474 if ( mem_ctx == NULL )
477 /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
478 if ( ee->record.time_generated == 0 )
481 /* todo - check for sanity in next_record */
483 fixup_eventlog_entry( ee );
485 if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) {
486 DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
487 talloc_destroy( mem_ctx );
491 /* alloc mem for the packed version */
492 packed_ee = (uint8 *)TALLOC( mem_ctx, ee->record.length + MARGIN );
494 talloc_destroy( mem_ctx );
498 /* need to read the record number and insert it into the entry here */
501 tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
503 next_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
506 tdb_pack( (uint8 *)packed_ee, ee->record.length + MARGIN,
507 "ddddddwwwwddddddBBdBBBd", ee->record.length,
508 ee->record.reserved1, next_record,
509 ee->record.time_generated, ee->record.time_written,
510 ee->record.event_id, ee->record.event_type,
511 ee->record.num_strings, ee->record.event_category,
512 ee->record.reserved2,
513 ee->record.closing_record_number,
514 ee->record.string_offset,
515 ee->record.user_sid_length,
516 ee->record.user_sid_offset, ee->record.data_length,
517 ee->record.data_offset,
518 ee->data_record.source_name_len,
519 ee->data_record.source_name,
520 ee->data_record.computer_name_len,
521 ee->data_record.computer_name,
522 ee->data_record.sid_padding,
523 ee->record.user_sid_length, ee->data_record.sid,
524 ee->data_record.strings_len,
525 ee->data_record.strings,
526 ee->data_record.user_data_len,
527 ee->data_record.user_data,
528 ee->data_record.data_padding );
530 /*DEBUG(3,("write_eventlog_tdb: packed into %d\n",n_packed)); */
532 /* increment the record count */
534 kbuf.dsize = sizeof( int32 );
535 kbuf.dptr = (uint8 * ) & next_record;
537 ebuf.dsize = n_packed;
538 ebuf.dptr = (uint8 *)packed_ee;
540 if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) {
541 /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
542 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
543 talloc_destroy( mem_ctx );
547 tdb_store_int32( the_tdb, EVT_NEXT_RECORD, next_record );
548 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
549 talloc_destroy( mem_ctx );
550 return ( next_record - 1 );
553 /*******************************************************************
554 calculate the correct fields etc for an eventlog entry
555 *******************************************************************/
557 void fixup_eventlog_entry( Eventlog_entry * ee )
559 /* fix up the eventlog entry structure as necessary */
561 ee->data_record.sid_padding =
563 ( ( ee->data_record.source_name_len +
564 ee->data_record.computer_name_len ) % 4 ) ) % 4 );
565 ee->data_record.data_padding =
567 ( ( ee->data_record.strings_len +
568 ee->data_record.user_data_len ) % 4 ) ) % 4;
569 ee->record.length = sizeof( Eventlog_record );
570 ee->record.length += ee->data_record.source_name_len;
571 ee->record.length += ee->data_record.computer_name_len;
572 if ( ee->record.user_sid_length == 0 ) {
573 /* Should not pad to a DWORD boundary for writing out the sid if there is
574 no SID, so just propagate the padding to pad the data */
575 ee->data_record.data_padding += ee->data_record.sid_padding;
576 ee->data_record.sid_padding = 0;
578 /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
579 /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
581 ee->record.length += ee->data_record.sid_padding;
582 ee->record.length += ee->record.user_sid_length;
583 ee->record.length += ee->data_record.strings_len;
584 ee->record.length += ee->data_record.user_data_len;
585 ee->record.length += ee->data_record.data_padding;
586 /* need another copy of length at the end of the data */
587 ee->record.length += sizeof( ee->record.length );
590 /********************************************************************
591 Note that it's a pretty good idea to initialize the Eventlog_entry
592 structure to zero's before calling parse_logentry on an batch of
593 lines that may resolve to a record. ALSO, it's a good idea to
594 remove any linefeeds (that's EOL to you and me) on the lines
596 ********************************************************************/
598 bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
600 char *start = NULL, *stop = NULL;
604 /* empty line signyfiying record delimeter, or we're at the end of the buffer */
605 if ( start == NULL || strlen( start ) == 0 ) {
607 ( "parse_logentry: found end-of-record indicator.\n" ) );
611 if ( !( stop = strchr( line, ':' ) ) ) {
615 DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
617 if ( 0 == strncmp( start, "LEN", stop - start ) ) {
618 /* This will get recomputed later anyway -- probably not necessary */
619 entry->size = atoi( stop + 1 );
620 } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
621 /* For now all these reserved entries seem to have the same value,
622 which can be hardcoded to int(1699505740) for now */
623 entry->reserved = talloc_strdup(mem_ctx, "eLfL");
624 } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
625 entry->record_number = atoi( stop + 1 );
626 } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
627 entry->time_generated = atoi( stop + 1 );
628 } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
629 entry->time_written = atoi( stop + 1 );
630 } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
631 entry->event_id = atoi( stop + 1 );
632 } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
633 if ( strstr( start, "ERROR" ) ) {
634 entry->event_type = EVENTLOG_ERROR_TYPE;
635 } else if ( strstr( start, "WARNING" ) ) {
636 entry->event_type = EVENTLOG_WARNING_TYPE;
637 } else if ( strstr( start, "INFO" ) ) {
638 entry->event_type = EVENTLOG_INFORMATION_TYPE;
639 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
640 entry->event_type = EVENTLOG_AUDIT_SUCCESS;
641 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
642 entry->event_type = EVENTLOG_AUDIT_FAILURE;
643 } else if ( strstr( start, "SUCCESS" ) ) {
644 entry->event_type = EVENTLOG_SUCCESS;
646 /* some other eventlog type -- currently not defined in MSDN docs, so error out */
652 else if(0 == strncmp(start, "NST", stop - start))
654 entry->num_of_strings = atoi(stop + 1);
657 else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
658 entry->event_category = atoi( stop + 1 );
659 } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
660 entry->reserved_flags = atoi( stop + 1 );
661 } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
662 entry->closing_record_number = atoi( stop + 1 );
663 } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
664 entry->sid_length = atoi( stop + 1 );
665 } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
667 while ( isspace( stop[0] ) ) {
670 entry->source_name_len = strlen_m_term(stop);
671 entry->source_name = talloc_strdup(mem_ctx, stop);
672 if (entry->source_name_len == (uint32_t)-1 ||
673 entry->source_name == NULL) {
676 } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
678 while ( isspace( stop[0] ) ) {
681 entry->computer_name_len = strlen_m_term(stop);
682 entry->computer_name = talloc_strdup(mem_ctx, stop);
683 if (entry->computer_name_len == (uint32_t)-1 ||
684 entry->computer_name == NULL) {
687 } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
688 smb_ucs2_t *dummy = NULL;
690 while ( isspace( stop[0] ) ) {
693 entry->sid_length = rpcstr_push_talloc(mem_ctx,
696 entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
697 if (entry->sid_length == (uint32_t)-1 ||
698 entry->sid.data == NULL) {
701 } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
703 /* skip past initial ":" */
705 /* now skip any other leading whitespace */
706 while ( isspace(stop[0])) {
709 tmp_len = strlen_m_term(stop);
710 if (tmp_len == (size_t)-1) {
713 if (!add_string_to_array(mem_ctx, stop, &entry->strings,
714 (int *)&entry->num_of_strings)) {
717 entry->strings_len += tmp_len;
718 } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
719 /* skip past initial ":" */
721 /* now skip any other leading whitespace */
722 while ( isspace( stop[0] ) ) {
725 entry->data_length = strlen_m(stop);
726 entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
727 if (!entry->data.data) {
731 /* some other eventlog entry -- not implemented, so dropping on the floor */
732 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
733 /* For now return true so that we can keep on parsing this mess. Eventually
734 we will return False here. */
740 /*******************************************************************
741 calculate the correct fields etc for an eventlog entry
742 *******************************************************************/
744 size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
746 size_t size = 56; /* static size of integers before buffers start */
748 r->source_name_len = strlen_m_term(r->source_name) * 2;
749 r->computer_name_len = strlen_m_term(r->computer_name) * 2;
750 r->strings_len = ndr_size_string_array(r->strings,
751 r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
753 /* fix up the eventlog entry structure as necessary */
754 r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
755 r->padding = ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
757 if (r->sid_length == 0) {
758 /* Should not pad to a DWORD boundary for writing out the sid if there is
759 no SID, so just propagate the padding to pad the data */
760 r->padding += r->sid_padding;
764 size += r->source_name_len;
765 size += r->computer_name_len;
766 size += r->sid_padding;
767 size += r->sid_length;
768 size += r->strings_len;
769 size += r->data_length;
771 /* need another copy of length at the end of the data */
772 size += sizeof(r->size);
780 /********************************************************************
781 ********************************************************************/
783 struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
785 uint32_t record_number)
787 struct eventlog_Record_tdb *r;
791 enum ndr_err_code ndr_err;
794 srecno = record_number;
795 key.dptr = (unsigned char *)&srecno;
796 key.dsize = sizeof(int32_t);
798 data = tdb_fetch(tdb, key);
799 if (data.dsize == 0) {
800 DEBUG(8,("evlog_pull_record_tdb: "
801 "Can't find a record for the key, record %d\n",
806 r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
811 blob = data_blob_const(data.dptr, data.dsize);
813 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, r,
814 (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
816 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
817 DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
823 if (DEBUGLEVEL >= 10) {
824 NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
827 DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
830 SAFE_FREE(data.dptr);
835 /********************************************************************
836 ********************************************************************/
838 struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
840 uint32_t record_number)
842 struct eventlog_Record_tdb *t;
843 struct EVENTLOGRECORD *r;
846 r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
851 t = evlog_pull_record_tdb(r, tdb, record_number);
857 status = evlog_tdb_entry_to_evt_entry(r, t, r);
858 if (!NT_STATUS_IS_OK(status)) {
863 r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, NULL, 0);
868 /********************************************************************
869 write an eventlog entry. Note that we have to lock, read next
870 eventlog, increment, write, write the record, unlock
872 coming into this, ee has the eventlog record, and the auxilliary date
873 (computer name, etc.) filled into the other structure. Before packing
874 into a record, this routine will calc the appropriate padding, etc.,
875 and then blast out the record in a form that can be read back in
876 ********************************************************************/
878 NTSTATUS evlog_push_record_tdb(TALLOC_CTX *mem_ctx,
880 struct eventlog_Record_tdb *r,
881 uint32_t *record_number)
885 enum ndr_err_code ndr_err;
889 return NT_STATUS_INVALID_PARAMETER;
892 if (!can_write_to_eventlog(tdb, r->size)) {
893 return NT_STATUS_EVENTLOG_CANT_START;
896 /* need to read the record number and insert it into the entry here */
899 ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
901 return NT_STATUS_LOCK_NOT_GRANTED;
905 r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
907 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, r,
908 (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
909 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
910 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
911 return ndr_map_error2ntstatus(ndr_err);
914 /* increment the record count */
916 kbuf.dsize = sizeof(int32_t);
917 kbuf.dptr = (uint8_t *)&r->record_number;
919 ebuf.dsize = blob.length;
920 ebuf.dptr = blob.data;
922 ret = tdb_store(tdb, kbuf, ebuf, 0);
924 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
925 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
928 ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
930 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
931 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
933 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
936 *record_number = r->record_number;
942 /********************************************************************
943 ********************************************************************/
945 NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
947 struct EVENTLOGRECORD *r,
948 uint32_t *record_number)
950 struct eventlog_Record_tdb *t;
953 t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
955 return NT_STATUS_NO_MEMORY;
958 status = evlog_evt_entry_to_tdb_entry(t, r, t);
959 if (!NT_STATUS_IS_OK(status)) {
964 status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
970 /********************************************************************
971 ********************************************************************/
973 NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
974 const struct EVENTLOGRECORD *e,
975 struct eventlog_Record_tdb *t)
982 t->reserved = e->Reserved;
983 t->record_number = e->RecordNumber;
984 t->time_generated = e->TimeGenerated;
985 t->time_written = e->TimeWritten;
986 t->event_id = e->EventID;
987 t->event_type = e->EventType;
988 t->num_of_strings = e->NumStrings;
989 t->event_category = e->EventCategory;
990 t->reserved_flags = e->ReservedFlags;
991 t->closing_record_number = e->ClosingRecordNumber;
993 t->stringoffset = e->StringOffset;
994 t->sid_length = e->UserSidLength;
995 t->sid_offset = e->UserSidOffset;
996 t->data_length = e->DataLength;
997 t->data_offset = e->DataOffset;
999 t->source_name_len = 2 * strlen_m_term(e->SourceName);
1000 t->source_name = talloc_strdup(mem_ctx, e->SourceName);
1001 NT_STATUS_HAVE_NO_MEMORY(t->source_name);
1003 t->computer_name_len = 2 * strlen_m_term(e->Computername);
1004 t->computer_name = talloc_strdup(mem_ctx, e->Computername);
1005 NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
1007 /* t->sid_padding; */
1008 if (e->UserSidLength > 0) {
1009 const char *sid_str = NULL;
1010 smb_ucs2_t *dummy = NULL;
1011 sid_str = sid_string_talloc(mem_ctx, &e->UserSid);
1012 t->sid_length = rpcstr_push_talloc(mem_ctx, &dummy, sid_str);
1013 if (t->sid_length == -1) {
1014 return NT_STATUS_NO_MEMORY;
1016 t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
1017 NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
1020 t->strings = talloc_array(mem_ctx, const char *, e->NumStrings);
1021 for (i=0; i < e->NumStrings; i++) {
1022 t->strings[i] = talloc_strdup(t->strings, e->Strings[i]);
1023 NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
1026 t->strings_len = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
1027 t->data = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
1028 /* t->padding = r->Pad; */
1030 return NT_STATUS_OK;
1033 /********************************************************************
1034 ********************************************************************/
1036 NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
1037 const struct eventlog_Record_tdb *t,
1038 struct EVENTLOGRECORD *e)
1044 e->Length = t->size;
1045 e->Reserved = t->reserved;
1046 e->RecordNumber = t->record_number;
1047 e->TimeGenerated = t->time_generated;
1048 e->TimeWritten = t->time_written;
1049 e->EventID = t->event_id;
1050 e->EventType = t->event_type;
1051 e->NumStrings = t->num_of_strings;
1052 e->EventCategory = t->event_category;
1053 e->ReservedFlags = t->reserved_flags;
1054 e->ClosingRecordNumber = t->closing_record_number;
1056 e->StringOffset = t->stringoffset;
1057 e->UserSidLength = t->sid_length;
1058 e->UserSidOffset = t->sid_offset;
1059 e->DataLength = t->data_length;
1060 e->DataOffset = t->data_offset;
1062 e->SourceName = talloc_strdup(mem_ctx, t->source_name);
1063 NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
1065 e->Computername = talloc_strdup(mem_ctx, t->computer_name);
1066 NT_STATUS_HAVE_NO_MEMORY(e->Computername);
1068 if (t->sid_length > 0) {
1069 const char *sid_str = NULL;
1071 if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
1072 t->sid.data, t->sid.length,
1073 &sid_str, &len, false)) {
1074 return NT_STATUS_INVALID_SID;
1077 e->UserSid = *string_sid_talloc(mem_ctx, sid_str);
1081 e->Strings = talloc_array(mem_ctx, const char *, t->num_of_strings);
1082 for (i=0; i < t->num_of_strings; i++) {
1083 e->Strings[i] = talloc_strdup(e->Strings, t->strings[i]);
1084 NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
1087 e->Data = (uint8_t *)talloc_memdup(mem_ctx, t->data.data, t->data_length);
1088 e->Pad = talloc_strdup(mem_ctx, "");
1089 NT_STATUS_HAVE_NO_MEMORY(e->Pad);
1091 e->Length2 = t->size;
1093 return NT_STATUS_OK;