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.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
24 /* maintain a list of open eventlog tdbs with reference counts */
26 static ELOG_TDB *open_elog_list;
28 /********************************************************************
29 Init an Eventlog TDB, and return it. If null, something bad
31 ********************************************************************/
33 TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
37 DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
40 tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT,
41 O_RDWR|O_CREAT|O_TRUNC, 0660 );
44 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
48 /* initialize with defaults, copy real values in here from registry */
50 tdb_store_int32( tdb, EVT_OLDEST_ENTRY, 1 );
51 tdb_store_int32( tdb, EVT_NEXT_RECORD, 1 );
52 tdb_store_int32( tdb, EVT_MAXSIZE, 0x80000 );
53 tdb_store_int32( tdb, EVT_RETENTION, 0x93A80 );
55 tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
60 /********************************************************************
61 make the tdb file name for an event log, given destination buffer
62 and size. Caller must free memory.
63 ********************************************************************/
65 char *elog_tdbname(TALLOC_CTX *ctx, const char *name )
67 char *path = talloc_asprintf(ctx, "%s/%s.tdb",
68 state_path("eventlog"),
78 /********************************************************************
79 this function is used to count up the number of bytes in a
81 ********************************************************************/
83 struct trav_size_struct {
88 static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
91 struct trav_size_struct *tsize = (struct trav_size_struct *)state;
93 tsize->size += data.dsize;
99 /********************************************************************
100 returns the size of the eventlog, and if MaxSize is a non-null
101 ptr, puts the MaxSize there. This is purely a way not to have yet
102 another function that solely reads the maxsize of the eventlog.
104 ********************************************************************/
106 int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
108 struct trav_size_struct tsize;
113 ZERO_STRUCT( tsize );
115 tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
117 if ( MaxSize != NULL ) {
118 *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
121 if ( Retention != NULL ) {
122 *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
126 ( "eventlog size: [%d] for [%d] records\n", tsize.size,
131 /********************************************************************
132 Discard early event logs until we have enough for 'needed' bytes...
133 NO checking done beforehand to see that we actually need to do
134 this, and it's going to pluck records one-by-one. So, it's best
135 to determine that this needs to be done before doing it.
137 Setting whack_by_date to True indicates that eventlogs falling
138 outside of the retention range need to go...
140 return True if we made enough room to accommodate needed bytes
141 ********************************************************************/
143 static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32_t needed,
146 int32_t start_record, i, new_start;
148 int32_t reclen, tresv1, trecnum, timegen, timewr;
149 int nbytes, len, Retention, MaxSize;
151 time_t current_time, exp_time;
153 /* discard some eventlogs */
155 /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
156 although records not necessarily guaranteed to have successive times */
160 tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
162 end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
163 start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
164 Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
165 MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
167 time( ¤t_time );
170 exp_time = current_time - Retention; /* discard older than exp_time */
172 /* todo - check for sanity in next_record */
176 ( "MaxSize [%d] Retention [%d] Current Time [%u] exp_time [%u]\n",
177 MaxSize, Retention, (unsigned int)current_time, (unsigned int)exp_time ) );
179 ( "Start Record [%u] End Record [%u]\n",
180 (unsigned int)start_record,
181 (unsigned int)end_record ));
183 for ( i = start_record; i < end_record; i++ ) {
184 /* read a record, add the amt to nbytes */
185 key.dsize = sizeof(int32_t);
186 key.dptr = (unsigned char *)&i;
187 ret = tdb_fetch( the_tdb, key );
188 if ( ret.dsize == 0 ) {
190 ( "Can't find a record for the key, record [%d]\n",
192 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
195 nbytes += ret.dsize; /* note this includes overhead */
197 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
198 &tresv1, &trecnum, &timegen, &timewr );
200 DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
201 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
202 SAFE_FREE( ret.dptr );
207 ( "read record %u, record size is [%d], total so far [%d]\n",
208 (unsigned int)i, reclen, nbytes ) );
210 SAFE_FREE( ret.dptr );
212 /* note that other servers may just stop writing records when the size limit
213 is reached, and there are no records older than 'retention'. This doesn't
214 like a very useful thing to do, so instead we whack (as in sleeps with the
215 fishes) just enough records to fit the what we need. This behavior could
216 be changed to 'match', if the need arises. */
218 if ( !whack_by_date && ( nbytes >= needed ) )
220 if ( whack_by_date && ( timegen >= exp_time ) )
225 ( "nbytes [%d] needed [%d] start_record is [%u], should be set to [%u]\n",
226 nbytes, needed, (unsigned int)start_record, (unsigned int)i ) );
227 /* todo - remove eventlog entries here and set starting record to start_record... */
229 if ( start_record != new_start ) {
230 for ( i = start_record; i < new_start; i++ ) {
231 key.dsize = sizeof(int32_t);
232 key.dptr = (unsigned char *)&i;
233 tdb_delete( the_tdb, key );
236 tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
238 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
242 /********************************************************************
243 some hygiene for an eventlog - see how big it is, and then
244 calculate how many bytes we need to remove
245 ********************************************************************/
247 bool prune_eventlog( TDB_CONTEXT * tdb )
249 int MaxSize, Retention, CalcdSize;
252 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
256 CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
258 ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
261 if ( CalcdSize > MaxSize ) {
262 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
266 return make_way_for_eventlogs( tdb, 0, True );
269 /********************************************************************
270 ********************************************************************/
272 bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32_t needed )
275 int MaxSize, Retention;
277 /* see if we can write to the eventlog -- do a policy enforcement */
279 return False; /* tdb is null, so we can't write to it */
287 calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
289 if ( calcd_size <= MaxSize )
290 return True; /* you betcha */
291 if ( calcd_size + needed < MaxSize )
294 if ( Retention == 0xffffffff ) {
295 return False; /* see msdn - we can't write no room, discard */
298 note don't have to test, but always good to show intent, in case changes needed
302 if ( Retention == 0x00000000 ) {
303 /* discard record(s) */
304 /* todo - decide when to remove a bunch vs. just what we need... */
305 return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
309 return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
312 /*******************************************************************
313 *******************************************************************/
315 ELOG_TDB *elog_open_tdb( const char *logname, bool force_clear, bool read_only )
317 TDB_CONTEXT *tdb = NULL;
320 char *tdbpath = NULL;
321 ELOG_TDB *tdb_node = NULL;
323 TALLOC_CTX *ctx = talloc_tos();
325 /* check for invalid options */
327 if (force_clear && read_only) {
328 DEBUG(1,("elog_open_tdb: Invalid flags\n"));
332 /* first see if we have an open context */
334 for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
335 if ( strequal( ptr->name, logname ) ) {
338 /* trick to alow clearing of the eventlog tdb.
339 The force_clear flag should imply that someone
340 has done a force close. So make sure the tdb
341 is NULL. If this is a normal open, then just
342 return the existing reference */
345 SMB_ASSERT( ptr->tdb == NULL );
353 /* make sure that the eventlog dir exists */
355 eventlogdir = state_path( "eventlog" );
356 if ( !directory_exist( eventlogdir ) )
357 mkdir( eventlogdir, 0755 );
359 /* get the path on disk */
361 tdbpath = elog_tdbname(ctx, logname);
366 DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
367 tdbpath, force_clear?"True":"False" ));
369 /* the tdb wasn't already open or this is a forced clear open */
371 if ( !force_clear ) {
373 tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, read_only ? O_RDONLY : O_RDWR , 0 );
375 vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
377 if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
378 DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
381 tdb = elog_init_tdb( tdbpath );
387 tdb = elog_init_tdb( tdbpath );
389 /* if we got a valid context, then add it to the list */
392 /* on a forced clear, just reset the tdb context if we already
393 have an open entry in the list */
400 if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) {
401 DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
406 tdb_node->name = talloc_strdup( tdb_node, logname );
408 tdb_node->ref_count = 1;
410 DLIST_ADD( open_elog_list, tdb_node );
416 /*******************************************************************
417 Wrapper to handle reference counts to the tdb
418 *******************************************************************/
420 int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
429 SMB_ASSERT( etdb->ref_count >= 0 );
431 if ( etdb->ref_count == 0 ) {
433 DLIST_REMOVE( open_elog_list, etdb );
435 return tdb_close( tdb );
441 return tdb_close( tdb );
448 /*******************************************************************
449 write an eventlog entry. Note that we have to lock, read next
450 eventlog, increment, write, write the record, unlock
452 coming into this, ee has the eventlog record, and the auxilliary date
453 (computer name, etc.) filled into the other structure. Before packing
454 into a record, this routine will calc the appropriate padding, etc.,
455 and then blast out the record in a form that can be read back in
456 *******************************************************************/
460 int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee )
464 TALLOC_CTX *mem_ctx = NULL;
471 mem_ctx = talloc_init( "write_eventlog_tdb" );
473 if ( mem_ctx == NULL )
476 /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
477 if ( ee->record.time_generated == 0 )
480 /* todo - check for sanity in next_record */
482 fixup_eventlog_entry( ee );
484 if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) {
485 DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
486 talloc_destroy( mem_ctx );
490 /* alloc mem for the packed version */
491 packed_ee = (uint8 *)TALLOC( mem_ctx, ee->record.length + MARGIN );
493 talloc_destroy( mem_ctx );
497 /* need to read the record number and insert it into the entry here */
500 tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
502 next_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
505 tdb_pack( (uint8 *)packed_ee, ee->record.length + MARGIN,
506 "ddddddwwwwddddddBBdBBBd", ee->record.length,
507 ee->record.reserved1, next_record,
508 ee->record.time_generated, ee->record.time_written,
509 ee->record.event_id, ee->record.event_type,
510 ee->record.num_strings, ee->record.event_category,
511 ee->record.reserved2,
512 ee->record.closing_record_number,
513 ee->record.string_offset,
514 ee->record.user_sid_length,
515 ee->record.user_sid_offset, ee->record.data_length,
516 ee->record.data_offset,
517 ee->data_record.source_name_len,
518 ee->data_record.source_name,
519 ee->data_record.computer_name_len,
520 ee->data_record.computer_name,
521 ee->data_record.sid_padding,
522 ee->record.user_sid_length, ee->data_record.sid,
523 ee->data_record.strings_len,
524 ee->data_record.strings,
525 ee->data_record.user_data_len,
526 ee->data_record.user_data,
527 ee->data_record.data_padding );
529 /*DEBUG(3,("write_eventlog_tdb: packed into %d\n",n_packed)); */
531 /* increment the record count */
533 kbuf.dsize = sizeof( int32 );
534 kbuf.dptr = (uint8 * ) & next_record;
536 ebuf.dsize = n_packed;
537 ebuf.dptr = (uint8 *)packed_ee;
539 if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) {
540 /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
541 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
542 talloc_destroy( mem_ctx );
546 tdb_store_int32( the_tdb, EVT_NEXT_RECORD, next_record );
547 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
548 talloc_destroy( mem_ctx );
549 return ( next_record - 1 );
552 /*******************************************************************
553 calculate the correct fields etc for an eventlog entry
554 *******************************************************************/
556 void fixup_eventlog_entry( Eventlog_entry * ee )
558 /* fix up the eventlog entry structure as necessary */
560 ee->data_record.sid_padding =
562 ( ( ee->data_record.source_name_len +
563 ee->data_record.computer_name_len ) % 4 ) ) % 4 );
564 ee->data_record.data_padding =
566 ( ( ee->data_record.strings_len +
567 ee->data_record.user_data_len ) % 4 ) ) % 4;
568 ee->record.length = sizeof( Eventlog_record );
569 ee->record.length += ee->data_record.source_name_len;
570 ee->record.length += ee->data_record.computer_name_len;
571 if ( ee->record.user_sid_length == 0 ) {
572 /* Should not pad to a DWORD boundary for writing out the sid if there is
573 no SID, so just propagate the padding to pad the data */
574 ee->data_record.data_padding += ee->data_record.sid_padding;
575 ee->data_record.sid_padding = 0;
577 /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
578 /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
580 ee->record.length += ee->data_record.sid_padding;
581 ee->record.length += ee->record.user_sid_length;
582 ee->record.length += ee->data_record.strings_len;
583 ee->record.length += ee->data_record.user_data_len;
584 ee->record.length += ee->data_record.data_padding;
585 /* need another copy of length at the end of the data */
586 ee->record.length += sizeof( ee->record.length );
589 /********************************************************************
590 Note that it's a pretty good idea to initialize the Eventlog_entry
591 structure to zero's before calling parse_logentry on an batch of
592 lines that may resolve to a record. ALSO, it's a good idea to
593 remove any linefeeds (that's EOL to you and me) on the lines
595 ********************************************************************/
597 bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
599 char *start = NULL, *stop = NULL;
603 /* empty line signyfiying record delimeter, or we're at the end of the buffer */
604 if ( start == NULL || strlen( start ) == 0 ) {
606 ( "parse_logentry: found end-of-record indicator.\n" ) );
610 if ( !( stop = strchr( line, ':' ) ) ) {
614 DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
616 if ( 0 == strncmp( start, "LEN", stop - start ) ) {
617 /* This will get recomputed later anyway -- probably not necessary */
618 entry->size = atoi( stop + 1 );
619 } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
620 /* For now all these reserved entries seem to have the same value,
621 which can be hardcoded to int(1699505740) for now */
622 entry->reserved = talloc_strdup(mem_ctx, "eLfL");
623 } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
624 entry->record_number = atoi( stop + 1 );
625 } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
626 entry->time_generated = atoi( stop + 1 );
627 } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
628 entry->time_written = atoi( stop + 1 );
629 } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
630 entry->event_id = atoi( stop + 1 );
631 } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
632 if ( strstr( start, "ERROR" ) ) {
633 entry->event_type = EVENTLOG_ERROR_TYPE;
634 } else if ( strstr( start, "WARNING" ) ) {
635 entry->event_type = EVENTLOG_WARNING_TYPE;
636 } else if ( strstr( start, "INFO" ) ) {
637 entry->event_type = EVENTLOG_INFORMATION_TYPE;
638 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
639 entry->event_type = EVENTLOG_AUDIT_SUCCESS;
640 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
641 entry->event_type = EVENTLOG_AUDIT_FAILURE;
642 } else if ( strstr( start, "SUCCESS" ) ) {
643 entry->event_type = EVENTLOG_SUCCESS;
645 /* some other eventlog type -- currently not defined in MSDN docs, so error out */
651 else if(0 == strncmp(start, "NST", stop - start))
653 entry->num_of_strings = atoi(stop + 1);
656 else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
657 entry->event_category = atoi( stop + 1 );
658 } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
659 entry->reserved_flags = atoi( stop + 1 );
660 } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
661 entry->closing_record_number = atoi( stop + 1 );
662 } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
663 entry->sid_length = atoi( stop + 1 );
664 } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
666 while ( isspace( stop[0] ) ) {
669 entry->source_name_len = strlen_m_term(stop);
670 entry->source_name = talloc_strdup(mem_ctx, stop);
671 if (entry->source_name_len == (uint32_t)-1 ||
672 entry->source_name == NULL) {
675 } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
677 while ( isspace( stop[0] ) ) {
680 entry->computer_name_len = strlen_m_term(stop);
681 entry->computer_name = talloc_strdup(mem_ctx, stop);
682 if (entry->computer_name_len == (uint32_t)-1 ||
683 entry->computer_name == NULL) {
686 } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
687 smb_ucs2_t *dummy = NULL;
689 while ( isspace( stop[0] ) ) {
692 entry->sid_length = rpcstr_push_talloc(mem_ctx,
695 entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
696 if (entry->sid_length == (uint32_t)-1 ||
697 entry->sid.data == NULL) {
700 } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
702 /* skip past initial ":" */
704 /* now skip any other leading whitespace */
705 while ( isspace(stop[0])) {
708 tmp_len = strlen_m_term(stop);
709 if (tmp_len == (size_t)-1) {
712 if (!add_string_to_array(mem_ctx, stop, &entry->strings,
713 (int *)&entry->num_of_strings)) {
716 entry->strings_len += tmp_len;
717 } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
718 /* skip past initial ":" */
720 /* now skip any other leading whitespace */
721 while ( isspace( stop[0] ) ) {
724 entry->data_length = strlen_m(stop);
725 entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
726 if (!entry->data.data) {
730 /* some other eventlog entry -- not implemented, so dropping on the floor */
731 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
732 /* For now return true so that we can keep on parsing this mess. Eventually
733 we will return False here. */
739 /*******************************************************************
740 calculate the correct fields etc for an eventlog entry
741 *******************************************************************/
743 size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
745 size_t size = 56; /* static size of integers before buffers start */
747 r->source_name_len = strlen_m_term(r->source_name) * 2;
748 r->computer_name_len = strlen_m_term(r->computer_name) * 2;
749 r->strings_len = ndr_size_string_array(r->strings,
750 r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
752 /* fix up the eventlog entry structure as necessary */
753 r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
754 r->padding = ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
756 if (r->sid_length == 0) {
757 /* Should not pad to a DWORD boundary for writing out the sid if there is
758 no SID, so just propagate the padding to pad the data */
759 r->padding += r->sid_padding;
763 size += r->source_name_len;
764 size += r->computer_name_len;
765 size += r->sid_padding;
766 size += r->sid_length;
767 size += r->strings_len;
768 size += r->data_length;
770 /* need another copy of length at the end of the data */
771 size += sizeof(r->size);
779 /********************************************************************
780 ********************************************************************/
782 struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
784 uint32_t record_number)
786 struct eventlog_Record_tdb *r;
790 enum ndr_err_code ndr_err;
793 srecno = record_number;
794 key.dptr = (unsigned char *)&srecno;
795 key.dsize = sizeof(int32_t);
797 data = tdb_fetch(tdb, key);
798 if (data.dsize == 0) {
799 DEBUG(8,("evlog_pull_record_tdb: "
800 "Can't find a record for the key, record %d\n",
805 r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
810 blob = data_blob_const(data.dptr, data.dsize);
812 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, r,
813 (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
815 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
816 DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
822 if (DEBUGLEVEL >= 10) {
823 NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
826 DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
829 SAFE_FREE(data.dptr);
834 /********************************************************************
835 ********************************************************************/
837 struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
839 uint32_t record_number)
841 struct eventlog_Record_tdb *t;
842 struct EVENTLOGRECORD *r;
845 r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
850 t = evlog_pull_record_tdb(r, tdb, record_number);
856 status = evlog_tdb_entry_to_evt_entry(r, t, r);
857 if (!NT_STATUS_IS_OK(status)) {
862 r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, NULL, 0);
867 /********************************************************************
868 write an eventlog entry. Note that we have to lock, read next
869 eventlog, increment, write, write the record, unlock
871 coming into this, ee has the eventlog record, and the auxilliary date
872 (computer name, etc.) filled into the other structure. Before packing
873 into a record, this routine will calc the appropriate padding, etc.,
874 and then blast out the record in a form that can be read back in
875 ********************************************************************/
877 NTSTATUS evlog_push_record_tdb(TALLOC_CTX *mem_ctx,
879 struct eventlog_Record_tdb *r,
880 uint32_t *record_number)
884 enum ndr_err_code ndr_err;
888 return NT_STATUS_INVALID_PARAMETER;
891 if (!can_write_to_eventlog(tdb, r->size)) {
892 return NT_STATUS_EVENTLOG_CANT_START;
895 /* need to read the record number and insert it into the entry here */
898 ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
900 return NT_STATUS_LOCK_NOT_GRANTED;
904 r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
906 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, r,
907 (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
908 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
909 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
910 return ndr_map_error2ntstatus(ndr_err);
913 /* increment the record count */
915 kbuf.dsize = sizeof(int32_t);
916 kbuf.dptr = (uint8_t *)&r->record_number;
918 ebuf.dsize = blob.length;
919 ebuf.dptr = blob.data;
921 ret = tdb_store(tdb, kbuf, ebuf, 0);
923 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
924 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
927 ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
929 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
930 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
932 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
935 *record_number = r->record_number;
941 /********************************************************************
942 ********************************************************************/
944 NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
946 struct EVENTLOGRECORD *r,
947 uint32_t *record_number)
949 struct eventlog_Record_tdb *t;
952 t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
954 return NT_STATUS_NO_MEMORY;
957 status = evlog_evt_entry_to_tdb_entry(t, r, t);
958 if (!NT_STATUS_IS_OK(status)) {
963 status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
969 /********************************************************************
970 ********************************************************************/
972 NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
973 const struct EVENTLOGRECORD *e,
974 struct eventlog_Record_tdb *t)
981 t->reserved = e->Reserved;
982 t->record_number = e->RecordNumber;
983 t->time_generated = e->TimeGenerated;
984 t->time_written = e->TimeWritten;
985 t->event_id = e->EventID;
986 t->event_type = e->EventType;
987 t->num_of_strings = e->NumStrings;
988 t->event_category = e->EventCategory;
989 t->reserved_flags = e->ReservedFlags;
990 t->closing_record_number = e->ClosingRecordNumber;
992 t->stringoffset = e->StringOffset;
993 t->sid_length = e->UserSidLength;
994 t->sid_offset = e->UserSidOffset;
995 t->data_length = e->DataLength;
996 t->data_offset = e->DataOffset;
998 t->source_name_len = 2 * strlen_m_term(e->SourceName);
999 t->source_name = talloc_strdup(mem_ctx, e->SourceName);
1000 NT_STATUS_HAVE_NO_MEMORY(t->source_name);
1002 t->computer_name_len = 2 * strlen_m_term(e->Computername);
1003 t->computer_name = talloc_strdup(mem_ctx, e->Computername);
1004 NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
1006 /* t->sid_padding; */
1007 if (e->UserSidLength > 0) {
1008 const char *sid_str = NULL;
1009 smb_ucs2_t *dummy = NULL;
1010 sid_str = sid_string_talloc(mem_ctx, &e->UserSid);
1011 t->sid_length = rpcstr_push_talloc(mem_ctx, &dummy, sid_str);
1012 if (t->sid_length == -1) {
1013 return NT_STATUS_NO_MEMORY;
1015 t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
1016 NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
1019 t->strings = talloc_array(mem_ctx, const char *, e->NumStrings);
1020 for (i=0; i < e->NumStrings; i++) {
1021 t->strings[i] = talloc_strdup(t->strings, e->Strings[i]);
1022 NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
1025 t->strings_len = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
1026 t->data = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
1027 /* t->padding = r->Pad; */
1029 return NT_STATUS_OK;
1032 /********************************************************************
1033 ********************************************************************/
1035 NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
1036 const struct eventlog_Record_tdb *t,
1037 struct EVENTLOGRECORD *e)
1043 e->Length = t->size;
1044 e->Reserved = t->reserved;
1045 e->RecordNumber = t->record_number;
1046 e->TimeGenerated = t->time_generated;
1047 e->TimeWritten = t->time_written;
1048 e->EventID = t->event_id;
1049 e->EventType = t->event_type;
1050 e->NumStrings = t->num_of_strings;
1051 e->EventCategory = t->event_category;
1052 e->ReservedFlags = t->reserved_flags;
1053 e->ClosingRecordNumber = t->closing_record_number;
1055 e->StringOffset = t->stringoffset;
1056 e->UserSidLength = t->sid_length;
1057 e->UserSidOffset = t->sid_offset;
1058 e->DataLength = t->data_length;
1059 e->DataOffset = t->data_offset;
1061 e->SourceName = talloc_strdup(mem_ctx, t->source_name);
1062 NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
1064 e->Computername = talloc_strdup(mem_ctx, t->computer_name);
1065 NT_STATUS_HAVE_NO_MEMORY(e->Computername);
1067 if (t->sid_length > 0) {
1068 const char *sid_str = NULL;
1070 if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
1071 t->sid.data, t->sid.length,
1072 &sid_str, &len, false)) {
1073 return NT_STATUS_INVALID_SID;
1076 e->UserSid = *string_sid_talloc(mem_ctx, sid_str);
1080 e->Strings = talloc_array(mem_ctx, const char *, t->num_of_strings);
1081 for (i=0; i < t->num_of_strings; i++) {
1082 e->Strings[i] = talloc_strdup(e->Strings, t->strings[i]);
1083 NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
1086 e->Data = (uint8_t *)talloc_memdup(mem_ctx, t->data.data, t->data_length);
1087 e->Pad = talloc_strdup(mem_ctx, "");
1088 NT_STATUS_HAVE_NO_MEMORY(e->Pad);
1090 e->Length2 = t->size;
1092 return NT_STATUS_OK;