Revert "s3:smbd: set req->smb2req->compat_chain_fsp in file_fsp()"
[Samba/gebeck_regimport.git] / source3 / lib / eventlog / eventlog.c
blob67583b8666c03eae15add015d5b6f29b01836866
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"
24 #include "system/filesys.h"
25 #include "lib/eventlog/eventlog.h"
26 #include "../libcli/security/security.h"
27 #include "util_tdb.h"
29 /* maintain a list of open eventlog tdbs with reference counts */
31 static ELOG_TDB *open_elog_list;
33 /********************************************************************
34 Init an Eventlog TDB, and return it. If null, something bad
35 happened.
36 ********************************************************************/
38 TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
40 TDB_CONTEXT *tdb;
42 DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
43 tdbfilename));
45 tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT,
46 O_RDWR|O_CREAT|O_TRUNC, 0660 );
48 if ( !tdb ) {
49 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
50 return NULL;
53 /* initialize with defaults, copy real values in here from registry */
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 );
60 tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
62 return tdb;
65 /********************************************************************
66 make the tdb file name for an event log, given destination buffer
67 and size. Caller must free memory.
68 ********************************************************************/
70 char *elog_tdbname(TALLOC_CTX *ctx, const char *name )
72 char *path;
73 char *file;
74 char *tdbname;
76 path = talloc_strdup(ctx, state_path("eventlog"));
77 if (!path) {
78 return NULL;
81 file = talloc_asprintf_strlower_m(path, "%s.tdb", name);
82 if (!file) {
83 talloc_free(path);
84 return NULL;
87 tdbname = talloc_asprintf(path, "%s/%s", state_path("eventlog"), file);
88 if (!tdbname) {
89 talloc_free(path);
90 return NULL;
93 return tdbname;
97 /********************************************************************
98 this function is used to count up the number of bytes in a
99 particular TDB
100 ********************************************************************/
102 struct trav_size_struct {
103 int size;
104 int rec_count;
107 static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
108 void *state )
110 struct trav_size_struct *tsize = (struct trav_size_struct *)state;
112 tsize->size += data.dsize;
113 tsize->rec_count++;
115 return 0;
118 /********************************************************************
119 returns the size of the eventlog, and if MaxSize is a non-null
120 ptr, puts the MaxSize there. This is purely a way not to have yet
121 another function that solely reads the maxsize of the eventlog.
122 Yeah, that's it.
123 ********************************************************************/
125 int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
127 struct trav_size_struct tsize;
129 if ( !tdb )
130 return 0;
132 ZERO_STRUCT( tsize );
134 tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
136 if ( MaxSize != NULL ) {
137 *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
140 if ( Retention != NULL ) {
141 *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
144 DEBUG( 1,
145 ( "eventlog size: [%d] for [%d] records\n", tsize.size,
146 tsize.rec_count ) );
147 return tsize.size;
150 /********************************************************************
151 Discard early event logs until we have enough for 'needed' bytes...
152 NO checking done beforehand to see that we actually need to do
153 this, and it's going to pluck records one-by-one. So, it's best
154 to determine that this needs to be done before doing it.
156 Setting whack_by_date to True indicates that eventlogs falling
157 outside of the retention range need to go...
159 return True if we made enough room to accommodate needed bytes
160 ********************************************************************/
162 static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32_t needed,
163 bool whack_by_date )
165 int32_t start_record, i, new_start;
166 int32_t end_record;
167 int32_t reclen, tresv1, trecnum, timegen, timewr;
168 int nbytes, len, Retention, MaxSize;
169 TDB_DATA key, ret;
170 time_t current_time, exp_time;
172 /* discard some eventlogs */
174 /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
175 although records not necessarily guaranteed to have successive times */
176 /* */
178 /* lock */
179 tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
180 /* read */
181 end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
182 start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
183 Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
184 MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
186 time( &current_time );
188 /* calculate ... */
189 exp_time = current_time - Retention; /* discard older than exp_time */
191 /* todo - check for sanity in next_record */
192 nbytes = 0;
194 DEBUG( 3,
195 ( "MaxSize [%d] Retention [%d] Current Time [%u] exp_time [%u]\n",
196 MaxSize, Retention, (unsigned int)current_time, (unsigned int)exp_time ) );
197 DEBUG( 3,
198 ( "Start Record [%u] End Record [%u]\n",
199 (unsigned int)start_record,
200 (unsigned int)end_record ));
202 for ( i = start_record; i < end_record; i++ ) {
203 /* read a record, add the amt to nbytes */
204 key.dsize = sizeof(int32_t);
205 key.dptr = (unsigned char *)&i;
206 ret = tdb_fetch_compat( the_tdb, key );
207 if ( ret.dsize == 0 ) {
208 DEBUG( 8,
209 ( "Can't find a record for the key, record [%d]\n",
210 i ) );
211 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
212 return False;
214 nbytes += ret.dsize; /* note this includes overhead */
216 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
217 &tresv1, &trecnum, &timegen, &timewr );
218 if (len == -1) {
219 DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
220 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
221 SAFE_FREE( ret.dptr );
222 return False;
225 DEBUG( 8,
226 ( "read record %u, record size is [%d], total so far [%d]\n",
227 (unsigned int)i, reclen, nbytes ) );
229 SAFE_FREE( ret.dptr );
231 /* note that other servers may just stop writing records when the size limit
232 is reached, and there are no records older than 'retention'. This doesn't
233 like a very useful thing to do, so instead we whack (as in sleeps with the
234 fishes) just enough records to fit the what we need. This behavior could
235 be changed to 'match', if the need arises. */
237 if ( !whack_by_date && ( nbytes >= needed ) )
238 break; /* done */
239 if ( whack_by_date && ( timegen >= exp_time ) )
240 break; /* done */
243 DEBUG( 3,
244 ( "nbytes [%d] needed [%d] start_record is [%u], should be set to [%u]\n",
245 nbytes, needed, (unsigned int)start_record, (unsigned int)i ) );
246 /* todo - remove eventlog entries here and set starting record to start_record... */
247 new_start = i;
248 if ( start_record != new_start ) {
249 for ( i = start_record; i < new_start; i++ ) {
250 key.dsize = sizeof(int32_t);
251 key.dptr = (unsigned char *)&i;
252 tdb_delete( the_tdb, key );
255 tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
257 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
258 return True;
261 /********************************************************************
262 some hygiene for an eventlog - see how big it is, and then
263 calculate how many bytes we need to remove
264 ********************************************************************/
266 bool prune_eventlog( TDB_CONTEXT * tdb )
268 int MaxSize, Retention, CalcdSize;
270 if ( !tdb ) {
271 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
272 return False;
275 CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
276 DEBUG( 3,
277 ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
278 MaxSize ) );
280 if ( CalcdSize > MaxSize ) {
281 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
282 False );
285 return make_way_for_eventlogs( tdb, 0, True );
288 /********************************************************************
289 ********************************************************************/
291 static bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32_t needed )
293 int calcd_size;
294 int MaxSize, Retention;
296 /* see if we can write to the eventlog -- do a policy enforcement */
297 if ( !tdb )
298 return False; /* tdb is null, so we can't write to it */
301 if ( needed < 0 )
302 return False;
303 MaxSize = 0;
304 Retention = 0;
306 calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
308 if ( calcd_size <= MaxSize )
309 return True; /* you betcha */
310 if ( calcd_size + needed < MaxSize )
311 return True;
313 if ( Retention == 0xffffffff ) {
314 return False; /* see msdn - we can't write no room, discard */
317 note don't have to test, but always good to show intent, in case changes needed
318 later
321 if ( Retention == 0x00000000 ) {
322 /* discard record(s) */
323 /* todo - decide when to remove a bunch vs. just what we need... */
324 return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
325 True );
328 return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
331 /*******************************************************************
332 *******************************************************************/
334 ELOG_TDB *elog_open_tdb( const char *logname, bool force_clear, bool read_only )
336 TDB_CONTEXT *tdb = NULL;
337 uint32_t vers_id;
338 ELOG_TDB *ptr;
339 char *tdbpath = NULL;
340 ELOG_TDB *tdb_node = NULL;
341 char *eventlogdir;
342 TALLOC_CTX *ctx = talloc_tos();
344 /* check for invalid options */
346 if (force_clear && read_only) {
347 DEBUG(1,("elog_open_tdb: Invalid flags\n"));
348 return NULL;
351 /* first see if we have an open context */
353 for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
354 if ( strequal( ptr->name, logname ) ) {
355 ptr->ref_count++;
357 /* trick to alow clearing of the eventlog tdb.
358 The force_clear flag should imply that someone
359 has done a force close. So make sure the tdb
360 is NULL. If this is a normal open, then just
361 return the existing reference */
363 if ( force_clear ) {
364 SMB_ASSERT( ptr->tdb == NULL );
365 break;
367 else
368 return ptr;
372 /* make sure that the eventlog dir exists */
374 eventlogdir = state_path( "eventlog" );
375 if ( !directory_exist( eventlogdir ) )
376 mkdir( eventlogdir, 0755 );
378 /* get the path on disk */
380 tdbpath = elog_tdbname(ctx, logname);
381 if (!tdbpath) {
382 return NULL;
385 DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
386 tdbpath, force_clear?"True":"False" ));
388 /* the tdb wasn't already open or this is a forced clear open */
390 if ( !force_clear ) {
392 tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, read_only ? O_RDONLY : O_RDWR , 0 );
393 if ( tdb ) {
394 vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
396 if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
397 DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
398 vers_id, tdbpath));
399 tdb_close( tdb );
400 tdb = elog_init_tdb( tdbpath );
405 if ( !tdb )
406 tdb = elog_init_tdb( tdbpath );
408 /* if we got a valid context, then add it to the list */
410 if ( tdb ) {
411 /* on a forced clear, just reset the tdb context if we already
412 have an open entry in the list */
414 if ( ptr ) {
415 ptr->tdb = tdb;
416 return ptr;
419 if ( !(tdb_node = talloc_zero( NULL, ELOG_TDB)) ) {
420 DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
421 tdb_close( tdb );
422 return NULL;
425 tdb_node->name = talloc_strdup( tdb_node, logname );
426 tdb_node->tdb = tdb;
427 tdb_node->ref_count = 1;
429 DLIST_ADD( open_elog_list, tdb_node );
432 return tdb_node;
435 /*******************************************************************
436 Wrapper to handle reference counts to the tdb
437 *******************************************************************/
439 int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
441 TDB_CONTEXT *tdb;
443 if ( !etdb )
444 return 0;
446 etdb->ref_count--;
448 SMB_ASSERT( etdb->ref_count >= 0 );
450 if ( etdb->ref_count == 0 ) {
451 tdb = etdb->tdb;
452 DLIST_REMOVE( open_elog_list, etdb );
453 TALLOC_FREE( etdb );
454 return tdb_close( tdb );
457 if ( force_close ) {
458 tdb = etdb->tdb;
459 etdb->tdb = NULL;
460 return tdb_close( tdb );
463 return 0;
466 /********************************************************************
467 Note that it's a pretty good idea to initialize the Eventlog_entry
468 structure to zero's before calling parse_logentry on an batch of
469 lines that may resolve to a record. ALSO, it's a good idea to
470 remove any linefeeds (that's EOL to you and me) on the lines
471 going in.
472 ********************************************************************/
474 bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
476 char *start = NULL, *stop = NULL;
478 start = line;
480 /* empty line signyfiying record delimeter, or we're at the end of the buffer */
481 if ( start == NULL || strlen( start ) == 0 ) {
482 DEBUG( 6,
483 ( "parse_logentry: found end-of-record indicator.\n" ) );
484 *eor = True;
485 return True;
487 if ( !( stop = strchr( line, ':' ) ) ) {
488 return False;
491 DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
493 if ( 0 == strncmp( start, "LEN", stop - start ) ) {
494 /* This will get recomputed later anyway -- probably not necessary */
495 entry->size = atoi( stop + 1 );
496 } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
497 /* For now all these reserved entries seem to have the same value,
498 which can be hardcoded to int(1699505740) for now */
499 entry->reserved = talloc_strdup(mem_ctx, "eLfL");
500 } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
501 entry->record_number = atoi( stop + 1 );
502 } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
503 entry->time_generated = atoi( stop + 1 );
504 } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
505 entry->time_written = atoi( stop + 1 );
506 } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
507 entry->event_id = atoi( stop + 1 );
508 } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
509 if ( strstr( start, "ERROR" ) ) {
510 entry->event_type = EVENTLOG_ERROR_TYPE;
511 } else if ( strstr( start, "WARNING" ) ) {
512 entry->event_type = EVENTLOG_WARNING_TYPE;
513 } else if ( strstr( start, "INFO" ) ) {
514 entry->event_type = EVENTLOG_INFORMATION_TYPE;
515 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
516 entry->event_type = EVENTLOG_AUDIT_SUCCESS;
517 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
518 entry->event_type = EVENTLOG_AUDIT_FAILURE;
519 } else if ( strstr( start, "SUCCESS" ) ) {
520 entry->event_type = EVENTLOG_SUCCESS;
521 } else {
522 /* some other eventlog type -- currently not defined in MSDN docs, so error out */
523 return False;
528 else if(0 == strncmp(start, "NST", stop - start))
530 entry->num_of_strings = atoi(stop + 1);
533 else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
534 entry->event_category = atoi( stop + 1 );
535 } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
536 entry->reserved_flags = atoi( stop + 1 );
537 } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
538 entry->closing_record_number = atoi( stop + 1 );
539 } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
540 entry->sid_length = atoi( stop + 1 );
541 } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
542 stop++;
543 while ( isspace( stop[0] ) ) {
544 stop++;
546 entry->source_name_len = strlen_m_term(stop);
547 entry->source_name = talloc_strdup(mem_ctx, stop);
548 if (entry->source_name_len == (uint32_t)-1 ||
549 entry->source_name == NULL) {
550 return false;
552 } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
553 stop++;
554 while ( isspace( stop[0] ) ) {
555 stop++;
557 entry->computer_name_len = strlen_m_term(stop);
558 entry->computer_name = talloc_strdup(mem_ctx, stop);
559 if (entry->computer_name_len == (uint32_t)-1 ||
560 entry->computer_name == NULL) {
561 return false;
563 } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
564 smb_ucs2_t *dummy = NULL;
565 stop++;
566 while ( isspace( stop[0] ) ) {
567 stop++;
569 entry->sid_length = rpcstr_push_talloc(mem_ctx,
570 &dummy,
571 stop);
572 if (entry->sid_length == (uint32_t)-1) {
573 return false;
575 entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
576 if (entry->sid.data == NULL) {
577 return false;
579 } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
580 size_t tmp_len;
581 int num_of_strings;
582 /* skip past initial ":" */
583 stop++;
584 /* now skip any other leading whitespace */
585 while ( isspace(stop[0])) {
586 stop++;
588 tmp_len = strlen_m_term(stop);
589 if (tmp_len == (size_t)-1) {
590 return false;
592 num_of_strings = entry->num_of_strings;
593 if (!add_string_to_array(mem_ctx, stop, &entry->strings,
594 &num_of_strings)) {
595 return false;
597 if (num_of_strings > 0xffff) {
598 return false;
600 entry->num_of_strings = num_of_strings;
601 entry->strings_len += tmp_len;
602 } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
603 /* skip past initial ":" */
604 stop++;
605 /* now skip any other leading whitespace */
606 while ( isspace( stop[0] ) ) {
607 stop++;
609 entry->data_length = strlen_m(stop);
610 entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
611 if (!entry->data.data) {
612 return false;
614 } else {
615 /* some other eventlog entry -- not implemented, so dropping on the floor */
616 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
617 /* For now return true so that we can keep on parsing this mess. Eventually
618 we will return False here. */
619 return true;
621 return true;
624 /*******************************************************************
625 calculate the correct fields etc for an eventlog entry
626 *******************************************************************/
628 size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
630 size_t size = 56; /* static size of integers before buffers start */
632 r->source_name_len = strlen_m_term(r->source_name) * 2;
633 r->computer_name_len = strlen_m_term(r->computer_name) * 2;
634 r->strings_len = ndr_size_string_array(r->strings,
635 r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
637 /* fix up the eventlog entry structure as necessary */
638 r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
639 r->padding = ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
641 if (r->sid_length == 0) {
642 /* Should not pad to a DWORD boundary for writing out the sid if there is
643 no SID, so just propagate the padding to pad the data */
644 r->padding += r->sid_padding;
645 r->sid_padding = 0;
648 size += r->source_name_len;
649 size += r->computer_name_len;
650 size += r->sid_padding;
651 size += r->sid_length;
652 size += r->strings_len;
653 size += r->data_length;
654 size += r->padding;
655 /* need another copy of length at the end of the data */
656 size += sizeof(r->size);
658 r->size = size;
660 return size;
664 /********************************************************************
665 ********************************************************************/
667 struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
668 TDB_CONTEXT *tdb,
669 uint32_t record_number)
671 struct eventlog_Record_tdb *r;
672 TDB_DATA data, key;
674 int32_t srecno;
675 enum ndr_err_code ndr_err;
676 DATA_BLOB blob;
678 srecno = record_number;
679 key.dptr = (unsigned char *)&srecno;
680 key.dsize = sizeof(int32_t);
682 data = tdb_fetch_compat(tdb, key);
683 if (data.dsize == 0) {
684 DEBUG(8,("evlog_pull_record_tdb: "
685 "Can't find a record for the key, record %d\n",
686 record_number));
687 return NULL;
690 r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
691 if (!r) {
692 goto done;
695 blob = data_blob_const(data.dptr, data.dsize);
697 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, r,
698 (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
700 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
701 DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
702 record_number));
703 TALLOC_FREE(r);
704 goto done;
707 if (DEBUGLEVEL >= 10) {
708 NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
711 DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
712 record_number));
713 done:
714 SAFE_FREE(data.dptr);
716 return r;
719 /********************************************************************
720 ********************************************************************/
722 struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
723 TDB_CONTEXT *tdb,
724 uint32_t record_number)
726 struct eventlog_Record_tdb *t;
727 struct EVENTLOGRECORD *r;
728 NTSTATUS status;
730 r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
731 if (!r) {
732 return NULL;
735 t = evlog_pull_record_tdb(r, tdb, record_number);
736 if (!t) {
737 talloc_free(r);
738 return NULL;
741 status = evlog_tdb_entry_to_evt_entry(r, t, r);
742 if (!NT_STATUS_IS_OK(status)) {
743 talloc_free(r);
744 return NULL;
747 r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, 0);
749 return r;
752 /********************************************************************
753 write an eventlog entry. Note that we have to lock, read next
754 eventlog, increment, write, write the record, unlock
756 coming into this, ee has the eventlog record, and the auxilliary date
757 (computer name, etc.) filled into the other structure. Before packing
758 into a record, this routine will calc the appropriate padding, etc.,
759 and then blast out the record in a form that can be read back in
760 ********************************************************************/
762 NTSTATUS evlog_push_record_tdb(TALLOC_CTX *mem_ctx,
763 TDB_CONTEXT *tdb,
764 struct eventlog_Record_tdb *r,
765 uint32_t *record_number)
767 TDB_DATA kbuf, ebuf;
768 DATA_BLOB blob;
769 enum ndr_err_code ndr_err;
770 int ret;
772 if (!r) {
773 return NT_STATUS_INVALID_PARAMETER;
776 if (!can_write_to_eventlog(tdb, r->size)) {
777 return NT_STATUS_EVENTLOG_CANT_START;
780 /* need to read the record number and insert it into the entry here */
782 /* lock */
783 ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
784 if (ret != 0) {
785 return NT_STATUS_LOCK_NOT_GRANTED;
788 /* read */
789 r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
791 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, r,
792 (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
793 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
794 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
795 return ndr_map_error2ntstatus(ndr_err);
798 /* increment the record count */
800 kbuf.dsize = sizeof(int32_t);
801 kbuf.dptr = (uint8_t *)&r->record_number;
803 ebuf.dsize = blob.length;
804 ebuf.dptr = blob.data;
806 ret = tdb_store(tdb, kbuf, ebuf, 0);
807 if (ret != 0) {
808 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
809 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
812 ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
813 if (ret != 0) {
814 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
815 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
817 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
819 if (record_number) {
820 *record_number = r->record_number;
823 return NT_STATUS_OK;
826 /********************************************************************
827 ********************************************************************/
829 NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
830 TDB_CONTEXT *tdb,
831 struct EVENTLOGRECORD *r,
832 uint32_t *record_number)
834 struct eventlog_Record_tdb *t;
835 NTSTATUS status;
837 t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
838 if (!t) {
839 return NT_STATUS_NO_MEMORY;
842 status = evlog_evt_entry_to_tdb_entry(t, r, t);
843 if (!NT_STATUS_IS_OK(status)) {
844 talloc_free(t);
845 return status;
848 status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
849 talloc_free(t);
851 return status;
854 /********************************************************************
855 ********************************************************************/
857 NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
858 const struct EVENTLOGRECORD *e,
859 struct eventlog_Record_tdb *t)
861 uint32_t i;
863 ZERO_STRUCTP(t);
865 t->size = e->Length;
866 t->reserved = e->Reserved;
867 t->record_number = e->RecordNumber;
868 t->time_generated = e->TimeGenerated;
869 t->time_written = e->TimeWritten;
870 t->event_id = e->EventID;
871 t->event_type = e->EventType;
872 t->num_of_strings = e->NumStrings;
873 t->event_category = e->EventCategory;
874 t->reserved_flags = e->ReservedFlags;
875 t->closing_record_number = e->ClosingRecordNumber;
877 t->stringoffset = e->StringOffset;
878 t->sid_length = e->UserSidLength;
879 t->sid_offset = e->UserSidOffset;
880 t->data_length = e->DataLength;
881 t->data_offset = e->DataOffset;
883 t->source_name_len = 2 * strlen_m_term(e->SourceName);
884 t->source_name = talloc_strdup(mem_ctx, e->SourceName);
885 NT_STATUS_HAVE_NO_MEMORY(t->source_name);
887 t->computer_name_len = 2 * strlen_m_term(e->Computername);
888 t->computer_name = talloc_strdup(mem_ctx, e->Computername);
889 NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
891 /* t->sid_padding; */
892 if (e->UserSidLength > 0) {
893 const char *sid_str = NULL;
894 smb_ucs2_t *dummy = NULL;
895 sid_str = sid_string_talloc(mem_ctx, &e->UserSid);
896 t->sid_length = rpcstr_push_talloc(mem_ctx, &dummy, sid_str);
897 if (t->sid_length == -1) {
898 return NT_STATUS_NO_MEMORY;
900 t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
901 NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
904 t->strings = talloc_array(mem_ctx, const char *, e->NumStrings);
905 for (i=0; i < e->NumStrings; i++) {
906 t->strings[i] = talloc_strdup(t->strings, e->Strings[i]);
907 NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
910 t->strings_len = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
911 t->data = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
912 /* t->padding = r->Pad; */
914 return NT_STATUS_OK;
917 /********************************************************************
918 ********************************************************************/
920 NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
921 const struct eventlog_Record_tdb *t,
922 struct EVENTLOGRECORD *e)
924 uint32_t i;
926 ZERO_STRUCTP(e);
928 e->Length = t->size;
929 e->Reserved = t->reserved;
930 e->RecordNumber = t->record_number;
931 e->TimeGenerated = t->time_generated;
932 e->TimeWritten = t->time_written;
933 e->EventID = t->event_id;
934 e->EventType = t->event_type;
935 e->NumStrings = t->num_of_strings;
936 e->EventCategory = t->event_category;
937 e->ReservedFlags = t->reserved_flags;
938 e->ClosingRecordNumber = t->closing_record_number;
940 e->StringOffset = t->stringoffset;
941 e->UserSidLength = t->sid_length;
942 e->UserSidOffset = t->sid_offset;
943 e->DataLength = t->data_length;
944 e->DataOffset = t->data_offset;
946 e->SourceName = talloc_strdup(mem_ctx, t->source_name);
947 NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
949 e->Computername = talloc_strdup(mem_ctx, t->computer_name);
950 NT_STATUS_HAVE_NO_MEMORY(e->Computername);
952 if (t->sid_length > 0) {
953 const char *sid_str = NULL;
954 size_t len;
955 if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
956 t->sid.data, t->sid.length,
957 (void *)&sid_str, &len)) {
958 return NT_STATUS_INVALID_SID;
960 if (len > 0) {
961 string_to_sid(&e->UserSid, sid_str);
965 e->Strings = talloc_array(mem_ctx, const char *, t->num_of_strings);
966 for (i=0; i < t->num_of_strings; i++) {
967 e->Strings[i] = talloc_strdup(e->Strings, t->strings[i]);
968 NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
971 e->Data = (uint8_t *)talloc_memdup(mem_ctx, t->data.data, t->data_length);
972 e->Pad = talloc_strdup(mem_ctx, "");
973 NT_STATUS_HAVE_NO_MEMORY(e->Pad);
975 e->Length2 = t->size;
977 return NT_STATUS_OK;
980 /********************************************************************
981 ********************************************************************/
983 NTSTATUS evlog_convert_tdb_to_evt(TALLOC_CTX *mem_ctx,
984 ELOG_TDB *etdb,
985 DATA_BLOB *blob_p,
986 uint32_t *num_records_p)
988 NTSTATUS status = NT_STATUS_OK;
989 enum ndr_err_code ndr_err;
990 DATA_BLOB blob;
991 uint32_t num_records = 0;
992 struct EVENTLOG_EVT_FILE evt;
993 uint32_t count = 1;
994 size_t endoffset = 0;
996 ZERO_STRUCT(evt);
998 while (1) {
1000 struct eventlog_Record_tdb *r;
1001 struct EVENTLOGRECORD e;
1003 r = evlog_pull_record_tdb(mem_ctx, etdb->tdb, count);
1004 if (!r) {
1005 break;
1008 status = evlog_tdb_entry_to_evt_entry(mem_ctx, r, &e);
1009 if (!NT_STATUS_IS_OK(status)) {
1010 goto done;
1013 endoffset += ndr_size_EVENTLOGRECORD(&e, 0);
1015 ADD_TO_ARRAY(mem_ctx, struct EVENTLOGRECORD, e, &evt.records, &num_records);
1016 count++;
1019 evt.hdr.StartOffset = 0x30;
1020 evt.hdr.EndOffset = evt.hdr.StartOffset + endoffset;
1021 evt.hdr.CurrentRecordNumber = count;
1022 evt.hdr.OldestRecordNumber = 1;
1023 evt.hdr.MaxSize = tdb_fetch_int32(etdb->tdb, EVT_MAXSIZE);
1024 evt.hdr.Flags = 0;
1025 evt.hdr.Retention = tdb_fetch_int32(etdb->tdb, EVT_RETENTION);
1027 if (DEBUGLEVEL >= 10) {
1028 NDR_PRINT_DEBUG(EVENTLOGHEADER, &evt.hdr);
1031 evt.eof.BeginRecord = 0x30;
1032 evt.eof.EndRecord = evt.hdr.StartOffset + endoffset;
1033 evt.eof.CurrentRecordNumber = evt.hdr.CurrentRecordNumber;
1034 evt.eof.OldestRecordNumber = evt.hdr.OldestRecordNumber;
1036 if (DEBUGLEVEL >= 10) {
1037 NDR_PRINT_DEBUG(EVENTLOGEOF, &evt.eof);
1040 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &evt,
1041 (ndr_push_flags_fn_t)ndr_push_EVENTLOG_EVT_FILE);
1042 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1043 status = ndr_map_error2ntstatus(ndr_err);
1044 goto done;
1047 *blob_p = blob;
1048 *num_records_p = num_records;
1050 done:
1051 return status;