s3-eventlog: add my copyright.
[kai/samba-autobuild/.git] / source3 / rpc_server / srv_eventlog_lib.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 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 /*******************************************************************
450  write an eventlog entry. Note that we have to lock, read next
451  eventlog, increment, write, write the record, unlock
452
453  coming into this, ee has the eventlog record, and the auxilliary date
454  (computer name, etc.) filled into the other structure. Before packing
455  into a record, this routine will calc the appropriate padding, etc.,
456  and then blast out the record in a form that can be read back in
457 *******************************************************************/
458
459 #define MARGIN 512
460
461 int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee )
462 {
463         int32 next_record;
464         uint8 *packed_ee;
465         TALLOC_CTX *mem_ctx = NULL;
466         TDB_DATA kbuf, ebuf;
467         uint32_t n_packed;
468
469         if ( !ee )
470                 return 0;
471
472         mem_ctx = talloc_init( "write_eventlog_tdb" );
473
474         if ( mem_ctx == NULL )
475                 return 0;
476
477         /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
478         if ( ee->record.time_generated == 0 )
479                 return 0;
480
481         /* todo - check for sanity in next_record */
482
483         fixup_eventlog_entry( ee );
484
485         if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) {
486                 DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
487                 talloc_destroy( mem_ctx );
488                 return 0;
489         }
490
491         /* alloc mem for the packed version */
492         packed_ee = (uint8 *)TALLOC( mem_ctx, ee->record.length + MARGIN );
493         if ( !packed_ee ) {
494                 talloc_destroy( mem_ctx );
495                 return 0;
496         }
497
498         /* need to read the record number and insert it into the entry here */
499
500         /* lock */
501         tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
502         /* read */
503         next_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
504
505         n_packed =
506                 tdb_pack( (uint8 *)packed_ee, ee->record.length + MARGIN,
507                           "ddddddwwwwddddddBBdBBBd", ee->record.length,
508                           ee->record.reserved1, next_record,
509                           ee->record.time_generated, ee->record.time_written,
510                           ee->record.event_id, ee->record.event_type,
511                           ee->record.num_strings, ee->record.event_category,
512                           ee->record.reserved2,
513                           ee->record.closing_record_number,
514                           ee->record.string_offset,
515                           ee->record.user_sid_length,
516                           ee->record.user_sid_offset, ee->record.data_length,
517                           ee->record.data_offset,
518                           ee->data_record.source_name_len,
519                           ee->data_record.source_name,
520                           ee->data_record.computer_name_len,
521                           ee->data_record.computer_name,
522                           ee->data_record.sid_padding,
523                           ee->record.user_sid_length, ee->data_record.sid,
524                           ee->data_record.strings_len,
525                           ee->data_record.strings,
526                           ee->data_record.user_data_len,
527                           ee->data_record.user_data,
528                           ee->data_record.data_padding );
529
530         /*DEBUG(3,("write_eventlog_tdb: packed into  %d\n",n_packed)); */
531
532         /* increment the record count */
533
534         kbuf.dsize = sizeof( int32 );
535         kbuf.dptr = (uint8 * ) & next_record;
536
537         ebuf.dsize = n_packed;
538         ebuf.dptr = (uint8 *)packed_ee;
539
540         if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) {
541                 /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
542                 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
543                 talloc_destroy( mem_ctx );
544                 return 0;
545         }
546         next_record++;
547         tdb_store_int32( the_tdb, EVT_NEXT_RECORD, next_record );
548         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
549         talloc_destroy( mem_ctx );
550         return ( next_record - 1 );
551 }
552
553 /*******************************************************************
554  calculate the correct fields etc for an eventlog entry
555 *******************************************************************/
556
557 void fixup_eventlog_entry( Eventlog_entry * ee )
558 {
559         /* fix up the eventlog entry structure as necessary */
560
561         ee->data_record.sid_padding =
562                 ( ( 4 -
563                     ( ( ee->data_record.source_name_len +
564                         ee->data_record.computer_name_len ) % 4 ) ) % 4 );
565         ee->data_record.data_padding =
566                 ( 4 -
567                   ( ( ee->data_record.strings_len +
568                       ee->data_record.user_data_len ) % 4 ) ) % 4;
569         ee->record.length = sizeof( Eventlog_record );
570         ee->record.length += ee->data_record.source_name_len;
571         ee->record.length += ee->data_record.computer_name_len;
572         if ( ee->record.user_sid_length == 0 ) {
573                 /* Should not pad to a DWORD boundary for writing out the sid if there is
574                    no SID, so just propagate the padding to pad the data */
575                 ee->data_record.data_padding += ee->data_record.sid_padding;
576                 ee->data_record.sid_padding = 0;
577         }
578         /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
579         /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
580
581         ee->record.length += ee->data_record.sid_padding;
582         ee->record.length += ee->record.user_sid_length;
583         ee->record.length += ee->data_record.strings_len;
584         ee->record.length += ee->data_record.user_data_len;
585         ee->record.length += ee->data_record.data_padding;
586         /* need another copy of length at the end of the data */
587         ee->record.length += sizeof( ee->record.length );
588 }
589
590 /********************************************************************
591  Note that it's a pretty good idea to initialize the Eventlog_entry
592  structure to zero's before calling parse_logentry on an batch of
593  lines that may resolve to a record.  ALSO, it's a good idea to
594  remove any linefeeds (that's EOL to you and me) on the lines
595  going in.
596 ********************************************************************/
597
598 bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
599 {
600         char *start = NULL, *stop = NULL;
601
602         start = line;
603
604         /* empty line signyfiying record delimeter, or we're at the end of the buffer */
605         if ( start == NULL || strlen( start ) == 0 ) {
606                 DEBUG( 6,
607                        ( "parse_logentry: found end-of-record indicator.\n" ) );
608                 *eor = True;
609                 return True;
610         }
611         if ( !( stop = strchr( line, ':' ) ) ) {
612                 return False;
613         }
614
615         DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
616
617         if ( 0 == strncmp( start, "LEN", stop - start ) ) {
618                 /* This will get recomputed later anyway -- probably not necessary */
619                 entry->size = atoi( stop + 1 );
620         } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
621                 /* For now all these reserved entries seem to have the same value,
622                    which can be hardcoded to int(1699505740) for now */
623                 entry->reserved = talloc_strdup(mem_ctx, "eLfL");
624         } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
625                 entry->record_number = atoi( stop + 1 );
626         } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
627                 entry->time_generated = atoi( stop + 1 );
628         } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
629                 entry->time_written = atoi( stop + 1 );
630         } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
631                 entry->event_id = atoi( stop + 1 );
632         } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
633                 if ( strstr( start, "ERROR" ) ) {
634                         entry->event_type = EVENTLOG_ERROR_TYPE;
635                 } else if ( strstr( start, "WARNING" ) ) {
636                         entry->event_type = EVENTLOG_WARNING_TYPE;
637                 } else if ( strstr( start, "INFO" ) ) {
638                         entry->event_type = EVENTLOG_INFORMATION_TYPE;
639                 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
640                         entry->event_type = EVENTLOG_AUDIT_SUCCESS;
641                 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
642                         entry->event_type = EVENTLOG_AUDIT_FAILURE;
643                 } else if ( strstr( start, "SUCCESS" ) ) {
644                         entry->event_type = EVENTLOG_SUCCESS;
645                 } else {
646                         /* some other eventlog type -- currently not defined in MSDN docs, so error out */
647                         return False;
648                 }
649         }
650
651 /*
652   else if(0 == strncmp(start, "NST", stop - start))
653   {
654   entry->num_of_strings = atoi(stop + 1);
655   }
656 */
657         else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
658                 entry->event_category = atoi( stop + 1 );
659         } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
660                 entry->reserved_flags = atoi( stop + 1 );
661         } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
662                 entry->closing_record_number = atoi( stop + 1 );
663         } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
664                 entry->sid_length = atoi( stop + 1 );
665         } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
666                 stop++;
667                 while ( isspace( stop[0] ) ) {
668                         stop++;
669                 }
670                 entry->source_name_len = strlen_m_term(stop);
671                 entry->source_name = talloc_strdup(mem_ctx, stop);
672                 if (entry->source_name_len == (uint32_t)-1 ||
673                                 entry->source_name == NULL) {
674                         return false;
675                 }
676         } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
677                 stop++;
678                 while ( isspace( stop[0] ) ) {
679                         stop++;
680                 }
681                 entry->computer_name_len = strlen_m_term(stop);
682                 entry->computer_name = talloc_strdup(mem_ctx, stop);
683                 if (entry->computer_name_len == (uint32_t)-1 ||
684                                 entry->computer_name == NULL) {
685                         return false;
686                 }
687         } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
688                 smb_ucs2_t *dummy = NULL;
689                 stop++;
690                 while ( isspace( stop[0] ) ) {
691                         stop++;
692                 }
693                 entry->sid_length = rpcstr_push_talloc(mem_ctx,
694                                 &dummy,
695                                 stop);
696                 entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
697                 if (entry->sid_length == (uint32_t)-1 ||
698                                 entry->sid.data == NULL) {
699                         return false;
700                 }
701         } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
702                 size_t tmp_len;
703                 /* skip past initial ":" */
704                 stop++;
705                 /* now skip any other leading whitespace */
706                 while ( isspace(stop[0])) {
707                         stop++;
708                 }
709                 tmp_len = strlen_m_term(stop);
710                 if (tmp_len == (size_t)-1) {
711                         return false;
712                 }
713                 if (!add_string_to_array(mem_ctx, stop, &entry->strings,
714                                          (int *)&entry->num_of_strings)) {
715                         return false;
716                 }
717                 entry->strings_len += tmp_len;
718         } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
719                 /* skip past initial ":" */
720                 stop++;
721                 /* now skip any other leading whitespace */
722                 while ( isspace( stop[0] ) ) {
723                         stop++;
724                 }
725                 entry->data_length = strlen_m(stop);
726                 entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
727                 if (!entry->data.data) {
728                         return false;
729                 }
730         } else {
731                 /* some other eventlog entry -- not implemented, so dropping on the floor */
732                 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
733                 /* For now return true so that we can keep on parsing this mess. Eventually
734                    we will return False here. */
735                 return true;
736         }
737         return true;
738 }
739
740 /*******************************************************************
741  calculate the correct fields etc for an eventlog entry
742 *******************************************************************/
743
744 size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
745 {
746         size_t size = 56; /* static size of integers before buffers start */
747
748         r->source_name_len = strlen_m_term(r->source_name) * 2;
749         r->computer_name_len = strlen_m_term(r->computer_name) * 2;
750         r->strings_len = ndr_size_string_array(r->strings,
751                 r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
752
753         /* fix up the eventlog entry structure as necessary */
754         r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
755         r->padding =       ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
756
757         if (r->sid_length == 0) {
758                 /* Should not pad to a DWORD boundary for writing out the sid if there is
759                    no SID, so just propagate the padding to pad the data */
760                 r->padding += r->sid_padding;
761                 r->sid_padding = 0;
762         }
763
764         size += r->source_name_len;
765         size += r->computer_name_len;
766         size += r->sid_padding;
767         size += r->sid_length;
768         size += r->strings_len;
769         size += r->data_length;
770         size += r->padding;
771         /* need another copy of length at the end of the data */
772         size += sizeof(r->size);
773
774         r->size = size;
775
776         return size;
777 }
778
779
780 /********************************************************************
781  ********************************************************************/
782
783 struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
784                                                   TDB_CONTEXT *tdb,
785                                                   uint32_t record_number)
786 {
787         struct eventlog_Record_tdb *r;
788         TDB_DATA data, key;
789
790         int32_t srecno;
791         enum ndr_err_code ndr_err;
792         DATA_BLOB blob;
793
794         srecno = record_number;
795         key.dptr = (unsigned char *)&srecno;
796         key.dsize = sizeof(int32_t);
797
798         data = tdb_fetch(tdb, key);
799         if (data.dsize == 0) {
800                 DEBUG(8,("evlog_pull_record_tdb: "
801                         "Can't find a record for the key, record %d\n",
802                         record_number));
803                 return NULL;
804         }
805
806         r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
807         if (!r) {
808                 goto done;
809         }
810
811         blob = data_blob_const(data.dptr, data.dsize);
812
813         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, r,
814                            (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
815
816         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
817                 DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
818                         record_number));
819                 TALLOC_FREE(r);
820                 goto done;
821         }
822
823         if (DEBUGLEVEL >= 10) {
824                 NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
825         }
826
827         DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
828                 record_number));
829  done:
830         SAFE_FREE(data.dptr);
831
832         return r;
833 }
834
835 /********************************************************************
836  ********************************************************************/
837
838 struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
839                                          TDB_CONTEXT *tdb,
840                                          uint32_t record_number)
841 {
842         struct eventlog_Record_tdb *t;
843         struct EVENTLOGRECORD *r;
844         NTSTATUS status;
845
846         r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
847         if (!r) {
848                 return NULL;
849         }
850
851         t = evlog_pull_record_tdb(r, tdb, record_number);
852         if (!t) {
853                 talloc_free(r);
854                 return NULL;
855         }
856
857         status = evlog_tdb_entry_to_evt_entry(r, t, r);
858         if (!NT_STATUS_IS_OK(status)) {
859                 talloc_free(r);
860                 return NULL;
861         }
862
863         r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, NULL, 0);
864
865         return r;
866 }
867
868 /********************************************************************
869  write an eventlog entry. Note that we have to lock, read next
870  eventlog, increment, write, write the record, unlock
871
872  coming into this, ee has the eventlog record, and the auxilliary date
873  (computer name, etc.) filled into the other structure. Before packing
874  into a record, this routine will calc the appropriate padding, etc.,
875  and then blast out the record in a form that can be read back in
876  ********************************************************************/
877
878 NTSTATUS evlog_push_record_tdb(TALLOC_CTX *mem_ctx,
879                                TDB_CONTEXT *tdb,
880                                struct eventlog_Record_tdb *r,
881                                uint32_t *record_number)
882 {
883         TDB_DATA kbuf, ebuf;
884         DATA_BLOB blob;
885         enum ndr_err_code ndr_err;
886         int ret;
887
888         if (!r) {
889                 return NT_STATUS_INVALID_PARAMETER;
890         }
891
892         if (!can_write_to_eventlog(tdb, r->size)) {
893                 return NT_STATUS_EVENTLOG_CANT_START;
894         }
895
896         /* need to read the record number and insert it into the entry here */
897
898         /* lock */
899         ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
900         if (ret == -1) {
901                 return NT_STATUS_LOCK_NOT_GRANTED;
902         }
903
904         /* read */
905         r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
906
907         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, r,
908                       (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
909         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
910                 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
911                 return ndr_map_error2ntstatus(ndr_err);
912         }
913
914         /* increment the record count */
915
916         kbuf.dsize = sizeof(int32_t);
917         kbuf.dptr = (uint8_t *)&r->record_number;
918
919         ebuf.dsize = blob.length;
920         ebuf.dptr  = blob.data;
921
922         ret = tdb_store(tdb, kbuf, ebuf, 0);
923         if (ret == -1) {
924                 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
925                 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
926         }
927
928         ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
929         if (ret == -1) {
930                 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
931                 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
932         }
933         tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
934
935         if (record_number) {
936                 *record_number = r->record_number;
937         }
938
939         return NT_STATUS_OK;
940 }
941
942 /********************************************************************
943  ********************************************************************/
944
945 NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
946                            TDB_CONTEXT *tdb,
947                            struct EVENTLOGRECORD *r,
948                            uint32_t *record_number)
949 {
950         struct eventlog_Record_tdb *t;
951         NTSTATUS status;
952
953         t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
954         if (!t) {
955                 return NT_STATUS_NO_MEMORY;
956         }
957
958         status = evlog_evt_entry_to_tdb_entry(t, r, t);
959         if (!NT_STATUS_IS_OK(status)) {
960                 talloc_free(t);
961                 return status;
962         }
963
964         status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
965         talloc_free(t);
966
967         return status;
968 }
969
970 /********************************************************************
971  ********************************************************************/
972
973 NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
974                                       const struct EVENTLOGRECORD *e,
975                                       struct eventlog_Record_tdb *t)
976 {
977         uint32_t i;
978
979         ZERO_STRUCTP(t);
980
981         t->size                         = e->Length;
982         t->reserved                     = e->Reserved;
983         t->record_number                = e->RecordNumber;
984         t->time_generated               = e->TimeGenerated;
985         t->time_written                 = e->TimeWritten;
986         t->event_id                     = e->EventID;
987         t->event_type                   = e->EventType;
988         t->num_of_strings               = e->NumStrings;
989         t->event_category               = e->EventCategory;
990         t->reserved_flags               = e->ReservedFlags;
991         t->closing_record_number        = e->ClosingRecordNumber;
992
993         t->stringoffset                 = e->StringOffset;
994         t->sid_length                   = e->UserSidLength;
995         t->sid_offset                   = e->UserSidOffset;
996         t->data_length                  = e->DataLength;
997         t->data_offset                  = e->DataOffset;
998
999         t->source_name_len              = 2 * strlen_m_term(e->SourceName);
1000         t->source_name                  = talloc_strdup(mem_ctx, e->SourceName);
1001         NT_STATUS_HAVE_NO_MEMORY(t->source_name);
1002
1003         t->computer_name_len            = 2 * strlen_m_term(e->Computername);
1004         t->computer_name                = talloc_strdup(mem_ctx, e->Computername);
1005         NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
1006
1007         /* t->sid_padding; */
1008         if (e->UserSidLength > 0) {
1009                 const char *sid_str = NULL;
1010                 smb_ucs2_t *dummy = NULL;
1011                 sid_str = sid_string_talloc(mem_ctx, &e->UserSid);
1012                 t->sid_length = rpcstr_push_talloc(mem_ctx, &dummy, sid_str);
1013                 if (t->sid_length == -1) {
1014                         return NT_STATUS_NO_MEMORY;
1015                 }
1016                 t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
1017                 NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
1018         }
1019
1020         t->strings                      = talloc_array(mem_ctx, const char *, e->NumStrings);
1021         for (i=0; i < e->NumStrings; i++) {
1022                 t->strings[i]           = talloc_strdup(t->strings, e->Strings[i]);
1023                 NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
1024         }
1025
1026         t->strings_len                  = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
1027         t->data                         = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
1028         /* t->padding                   = r->Pad; */
1029
1030         return NT_STATUS_OK;
1031 }
1032
1033 /********************************************************************
1034  ********************************************************************/
1035
1036 NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
1037                                       const struct eventlog_Record_tdb *t,
1038                                       struct EVENTLOGRECORD *e)
1039 {
1040         uint32_t i;
1041
1042         ZERO_STRUCTP(e);
1043
1044         e->Length               = t->size;
1045         e->Reserved             = t->reserved;
1046         e->RecordNumber         = t->record_number;
1047         e->TimeGenerated        = t->time_generated;
1048         e->TimeWritten          = t->time_written;
1049         e->EventID              = t->event_id;
1050         e->EventType            = t->event_type;
1051         e->NumStrings           = t->num_of_strings;
1052         e->EventCategory        = t->event_category;
1053         e->ReservedFlags        = t->reserved_flags;
1054         e->ClosingRecordNumber  = t->closing_record_number;
1055
1056         e->StringOffset         = t->stringoffset;
1057         e->UserSidLength        = t->sid_length;
1058         e->UserSidOffset        = t->sid_offset;
1059         e->DataLength           = t->data_length;
1060         e->DataOffset           = t->data_offset;
1061
1062         e->SourceName           = talloc_strdup(mem_ctx, t->source_name);
1063         NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
1064
1065         e->Computername         = talloc_strdup(mem_ctx, t->computer_name);
1066         NT_STATUS_HAVE_NO_MEMORY(e->Computername);
1067
1068         if (t->sid_length > 0) {
1069                 const char *sid_str = NULL;
1070                 size_t len;
1071                 if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
1072                                            t->sid.data, t->sid.length,
1073                                            &sid_str, &len, false)) {
1074                         return NT_STATUS_INVALID_SID;
1075                 }
1076                 if (len > 0) {
1077                         e->UserSid = *string_sid_talloc(mem_ctx, sid_str);
1078                 }
1079         }
1080
1081         e->Strings              = talloc_array(mem_ctx, const char *, t->num_of_strings);
1082         for (i=0; i < t->num_of_strings; i++) {
1083                 e->Strings[i] = talloc_strdup(e->Strings, t->strings[i]);
1084                 NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
1085         }
1086
1087         e->Data                 = (uint8_t *)talloc_memdup(mem_ctx, t->data.data, t->data_length);
1088         e->Pad                  = talloc_strdup(mem_ctx, "");
1089         NT_STATUS_HAVE_NO_MEMORY(e->Pad);
1090
1091         e->Length2              = t->size;
1092
1093         return NT_STATUS_OK;
1094 }