s3-eventlog: split out evlog_convert_tdb_to_evt().
[nivanova/samba-autobuild/.git] / source3 / lib / eventlog / eventlog.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  Eventlog utility  routines
4  *  Copyright (C) Marcin Krzysztof Porwit    2005,
5  *  Copyright (C) Brian Moran                2005.
6  *  Copyright (C) Gerald (Jerry) Carter      2005.
7  *  Copyright (C) Guenther Deschner          2009.
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "includes.h"
24
25 /* maintain a list of open eventlog tdbs with reference counts */
26
27 static ELOG_TDB *open_elog_list;
28
29 /********************************************************************
30  Init an Eventlog TDB, and return it. If null, something bad
31  happened.
32 ********************************************************************/
33
34 TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
35 {
36         TDB_CONTEXT *tdb;
37
38         DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
39                 tdbfilename));
40
41         tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT,
42                 O_RDWR|O_CREAT|O_TRUNC, 0660 );
43
44         if ( !tdb ) {
45                 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
46                 return NULL;
47         }
48
49         /* initialize with defaults, copy real values in here from registry */
50
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 );
55
56         tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
57
58         return tdb;
59 }
60
61 /********************************************************************
62  make the tdb file name for an event log, given destination buffer
63  and size. Caller must free memory.
64 ********************************************************************/
65
66 char *elog_tdbname(TALLOC_CTX *ctx, const char *name )
67 {
68         char *path = talloc_asprintf(ctx, "%s/%s.tdb",
69                         state_path("eventlog"),
70                         name);
71         if (!path) {
72                 return NULL;
73         }
74         strlower_m(path);
75         return path;
76 }
77
78
79 /********************************************************************
80  this function is used to count up the number of bytes in a
81  particular TDB
82 ********************************************************************/
83
84 struct trav_size_struct {
85         int size;
86         int rec_count;
87 };
88
89 static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
90                           void *state )
91 {
92         struct trav_size_struct  *tsize = (struct trav_size_struct *)state;
93
94         tsize->size += data.dsize;
95         tsize->rec_count++;
96
97         return 0;
98 }
99
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 ********************************************************************/
106
107 int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
108 {
109         struct trav_size_struct tsize;
110
111         if ( !tdb )
112                 return 0;
113
114         ZERO_STRUCT( tsize );
115
116         tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
117
118         if ( MaxSize != NULL ) {
119                 *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
120         }
121
122         if ( Retention != NULL ) {
123                 *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
124         }
125
126         DEBUG( 1,
127                ( "eventlog size: [%d] for [%d] records\n", tsize.size,
128                  tsize.rec_count ) );
129         return tsize.size;
130 }
131
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.
137
138  Setting whack_by_date to True indicates that eventlogs falling
139  outside of the retention range need to go...
140
141  return True if we made enough room to accommodate needed bytes
142 ********************************************************************/
143
144 static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32_t needed,
145                                     bool whack_by_date )
146 {
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;
153
154         /* discard some eventlogs */
155
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         /* */
159
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 );
167
168         time( &current_time );
169
170         /* calculate ... */
171         exp_time = current_time - Retention;    /* discard older than exp_time */
172
173         /* todo - check for sanity in next_record */
174         nbytes = 0;
175
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 ));
183
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;
195                 }
196                 nbytes += ret.dsize;    /* note this includes overhead */
197
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;
205                 }
206
207                 DEBUG( 8,
208                        ( "read record %u, record size is [%d], total so far [%d]\n",
209                          (unsigned int)i, reclen, nbytes ) );
210
211                 SAFE_FREE( ret.dptr );
212
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. */
218
219                 if ( !whack_by_date && ( nbytes >= needed ) )
220                         break;  /* done */
221                 if ( whack_by_date && ( timegen >= exp_time ) )
222                         break;  /* done */
223         }
224
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 );
235                 }
236
237                 tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
238         }
239         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
240         return True;
241 }
242
243 /********************************************************************
244   some hygiene for an eventlog - see how big it is, and then
245   calculate how many bytes we need to remove
246 ********************************************************************/
247
248 bool prune_eventlog( TDB_CONTEXT * tdb )
249 {
250         int MaxSize, Retention, CalcdSize;
251
252         if ( !tdb ) {
253                 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
254                 return False;
255         }
256
257         CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
258         DEBUG( 3,
259                ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
260                  MaxSize ) );
261
262         if ( CalcdSize > MaxSize ) {
263                 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
264                                                False );
265         }
266
267         return make_way_for_eventlogs( tdb, 0, True );
268 }
269
270 /********************************************************************
271 ********************************************************************/
272
273 static bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32_t needed )
274 {
275         int calcd_size;
276         int MaxSize, Retention;
277
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 */
281
282
283         if ( needed < 0 )
284                 return False;
285         MaxSize = 0;
286         Retention = 0;
287
288         calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
289
290         if ( calcd_size <= MaxSize )
291                 return True;    /* you betcha */
292         if ( calcd_size + needed < MaxSize )
293                 return True;
294
295         if ( Retention == 0xffffffff ) {
296                 return False;   /* see msdn - we can't write no room, discard */
297         }
298         /*
299            note don't have to test, but always good to show intent, in case changes needed
300            later
301          */
302
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 );
308         }
309
310         return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
311 }
312
313 /*******************************************************************
314 *******************************************************************/
315
316 ELOG_TDB *elog_open_tdb( const char *logname, bool force_clear, bool read_only )
317 {
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();
325
326         /* check for invalid options */
327
328         if (force_clear && read_only) {
329                 DEBUG(1,("elog_open_tdb: Invalid flags\n"));
330                 return NULL;
331         }
332
333         /* first see if we have an open context */
334
335         for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
336                 if ( strequal( ptr->name, logname ) ) {
337                         ptr->ref_count++;
338
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 */
344
345                         if ( force_clear ) {
346                                 SMB_ASSERT( ptr->tdb == NULL );
347                                 break;
348                         }
349                         else
350                                 return ptr;
351                 }
352         }
353
354         /* make sure that the eventlog dir exists */
355
356         eventlogdir = state_path( "eventlog" );
357         if ( !directory_exist( eventlogdir ) )
358                 mkdir( eventlogdir, 0755 );
359
360         /* get the path on disk */
361
362         tdbpath = elog_tdbname(ctx, logname);
363         if (!tdbpath) {
364                 return NULL;
365         }
366
367         DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
368                 tdbpath, force_clear?"True":"False" ));
369
370         /* the tdb wasn't already open or this is a forced clear open */
371
372         if ( !force_clear ) {
373
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 );
377
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 );
383                         }
384                 }
385         }
386
387         if ( !tdb )
388                 tdb = elog_init_tdb( tdbpath );
389
390         /* if we got a valid context, then add it to the list */
391
392         if ( tdb ) {
393                 /* on a forced clear, just reset the tdb context if we already
394                    have an open entry in the list */
395
396                 if ( ptr ) {
397                         ptr->tdb = tdb;
398                         return ptr;
399                 }
400
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;
405                 }
406
407                 tdb_node->name = talloc_strdup( tdb_node, logname );
408                 tdb_node->tdb = tdb;
409                 tdb_node->ref_count = 1;
410
411                 DLIST_ADD( open_elog_list, tdb_node );
412         }
413
414         return tdb_node;
415 }
416
417 /*******************************************************************
418  Wrapper to handle reference counts to the tdb
419 *******************************************************************/
420
421 int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
422 {
423         TDB_CONTEXT *tdb;
424
425         if ( !etdb )
426                 return 0;
427
428         etdb->ref_count--;
429
430         SMB_ASSERT( etdb->ref_count >= 0 );
431
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 );
437         }
438
439         if ( force_close ) {
440                 tdb = etdb->tdb;
441                 etdb->tdb = NULL;
442                 return tdb_close( tdb );
443         }
444
445         return 0;
446 }
447
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 ********************************************************************/
455
456 bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
457 {
458         char *start = NULL, *stop = NULL;
459
460         start = line;
461
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;
468         }
469         if ( !( stop = strchr( line, ':' ) ) ) {
470                 return False;
471         }
472
473         DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
474
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;
506                 }
507         }
508
509 /*
510   else if(0 == strncmp(start, "NST", stop - start))
511   {
512   entry->num_of_strings = atoi(stop + 1);
513   }
514 */
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++;
527                 }
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;
533                 }
534         } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
535                 stop++;
536                 while ( isspace( stop[0] ) ) {
537                         stop++;
538                 }
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;
544                 }
545         } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
546                 smb_ucs2_t *dummy = NULL;
547                 stop++;
548                 while ( isspace( stop[0] ) ) {
549                         stop++;
550                 }
551                 entry->sid_length = rpcstr_push_talloc(mem_ctx,
552                                 &dummy,
553                                 stop);
554                 if (entry->sid_length == (uint32_t)-1) {
555                         return false;
556                 }
557                 entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
558                 if (entry->sid.data == NULL) {
559                         return false;
560                 }
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++;
569                 }
570                 tmp_len = strlen_m_term(stop);
571                 if (tmp_len == (size_t)-1) {
572                         return false;
573                 }
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;
578                 }
579                 if (num_of_strings > 0xffff) {
580                         return false;
581                 }
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++;
590                 }
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;
595                 }
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;
602         }
603         return true;
604 }
605
606 /*******************************************************************
607  calculate the correct fields etc for an eventlog entry
608 *******************************************************************/
609
610 size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
611 {
612         size_t size = 56; /* static size of integers before buffers start */
613
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;
618
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;
622
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;
628         }
629
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);
639
640         r->size = size;
641
642         return size;
643 }
644
645
646 /********************************************************************
647  ********************************************************************/
648
649 struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
650                                                   TDB_CONTEXT *tdb,
651                                                   uint32_t record_number)
652 {
653         struct eventlog_Record_tdb *r;
654         TDB_DATA data, key;
655
656         int32_t srecno;
657         enum ndr_err_code ndr_err;
658         DATA_BLOB blob;
659
660         srecno = record_number;
661         key.dptr = (unsigned char *)&srecno;
662         key.dsize = sizeof(int32_t);
663
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;
670         }
671
672         r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
673         if (!r) {
674                 goto done;
675         }
676
677         blob = data_blob_const(data.dptr, data.dsize);
678
679         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, r,
680                            (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
681
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;
687         }
688
689         if (DEBUGLEVEL >= 10) {
690                 NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
691         }
692
693         DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
694                 record_number));
695  done:
696         SAFE_FREE(data.dptr);
697
698         return r;
699 }
700
701 /********************************************************************
702  ********************************************************************/
703
704 struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
705                                          TDB_CONTEXT *tdb,
706                                          uint32_t record_number)
707 {
708         struct eventlog_Record_tdb *t;
709         struct EVENTLOGRECORD *r;
710         NTSTATUS status;
711
712         r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
713         if (!r) {
714                 return NULL;
715         }
716
717         t = evlog_pull_record_tdb(r, tdb, record_number);
718         if (!t) {
719                 talloc_free(r);
720                 return NULL;
721         }
722
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;
727         }
728
729         r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, NULL, 0);
730
731         return r;
732 }
733
734 /********************************************************************
735  write an eventlog entry. Note that we have to lock, read next
736  eventlog, increment, write, write the record, unlock
737
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  ********************************************************************/
743
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)
748 {
749         TDB_DATA kbuf, ebuf;
750         DATA_BLOB blob;
751         enum ndr_err_code ndr_err;
752         int ret;
753
754         if (!r) {
755                 return NT_STATUS_INVALID_PARAMETER;
756         }
757
758         if (!can_write_to_eventlog(tdb, r->size)) {
759                 return NT_STATUS_EVENTLOG_CANT_START;
760         }
761
762         /* need to read the record number and insert it into the entry here */
763
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;
768         }
769
770         /* read */
771         r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
772
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);
778         }
779
780         /* increment the record count */
781
782         kbuf.dsize = sizeof(int32_t);
783         kbuf.dptr = (uint8_t *)&r->record_number;
784
785         ebuf.dsize = blob.length;
786         ebuf.dptr  = blob.data;
787
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;
792         }
793
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;
798         }
799         tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
800
801         if (record_number) {
802                 *record_number = r->record_number;
803         }
804
805         return NT_STATUS_OK;
806 }
807
808 /********************************************************************
809  ********************************************************************/
810
811 NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
812                            TDB_CONTEXT *tdb,
813                            struct EVENTLOGRECORD *r,
814                            uint32_t *record_number)
815 {
816         struct eventlog_Record_tdb *t;
817         NTSTATUS status;
818
819         t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
820         if (!t) {
821                 return NT_STATUS_NO_MEMORY;
822         }
823
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;
828         }
829
830         status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
831         talloc_free(t);
832
833         return status;
834 }
835
836 /********************************************************************
837  ********************************************************************/
838
839 NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
840                                       const struct EVENTLOGRECORD *e,
841                                       struct eventlog_Record_tdb *t)
842 {
843         uint32_t i;
844
845         ZERO_STRUCTP(t);
846
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;
858
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;
864
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);
868
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);
872
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;
881                 }
882                 t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
883                 NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
884         }
885
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]);
890         }
891
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; */
895
896         return NT_STATUS_OK;
897 }
898
899 /********************************************************************
900  ********************************************************************/
901
902 NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
903                                       const struct eventlog_Record_tdb *t,
904                                       struct EVENTLOGRECORD *e)
905 {
906         uint32_t i;
907
908         ZERO_STRUCTP(e);
909
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;
921
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;
927
928         e->SourceName           = talloc_strdup(mem_ctx, t->source_name);
929         NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
930
931         e->Computername         = talloc_strdup(mem_ctx, t->computer_name);
932         NT_STATUS_HAVE_NO_MEMORY(e->Computername);
933
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;
941                 }
942                 if (len > 0) {
943                         e->UserSid = *string_sid_talloc(mem_ctx, sid_str);
944                 }
945         }
946
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]);
951         }
952
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);
956
957         e->Length2              = t->size;
958
959         return NT_STATUS_OK;
960 }
961
962 /********************************************************************
963  ********************************************************************/
964
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)
969 {
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;
977
978         ZERO_STRUCT(evt);
979
980         while (1) {
981
982                 struct eventlog_Record_tdb *r;
983                 struct EVENTLOGRECORD e;
984
985                 r = evlog_pull_record_tdb(mem_ctx, etdb->tdb, count);
986                 if (!r) {
987                         break;
988                 }
989
990                 status = evlog_tdb_entry_to_evt_entry(mem_ctx, r, &e);
991                 if (!NT_STATUS_IS_OK(status)) {
992                         goto done;
993                 }
994
995                 endoffset += ndr_size_EVENTLOGRECORD(&e, NULL, 0);
996
997                 ADD_TO_ARRAY(mem_ctx, struct EVENTLOGRECORD, e, &evt.records, &num_records);
998                 count++;
999         }
1000
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);
1008
1009         if (DEBUGLEVEL >= 10) {
1010                 NDR_PRINT_DEBUG(EVENTLOGHEADER, &evt.hdr);
1011         }
1012
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;
1017
1018         if (DEBUGLEVEL >= 10) {
1019                 NDR_PRINT_DEBUG(EVENTLOGEOF, &evt.eof);
1020         }
1021
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;
1027         }
1028
1029         *blob_p = blob;
1030         *num_records_p = num_records;
1031
1032  done:
1033         return status;
1034 }