247c8ac04b48b56813597cff4e4e4baad476d7f9
[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  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23
24 /* maintain a list of open eventlog tdbs with reference counts */
25
26 static ELOG_TDB *open_elog_list;
27
28 /********************************************************************
29  Init an Eventlog TDB, and return it. If null, something bad
30  happened.
31 ********************************************************************/
32
33 TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
34 {
35         TDB_CONTEXT *tdb;
36
37         DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
38                 tdbfilename));
39
40         tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT,
41                 O_RDWR|O_CREAT|O_TRUNC, 0660 );
42
43         if ( !tdb ) {
44                 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
45                 return NULL;
46         }
47
48         /* initialize with defaults, copy real values in here from registry */
49
50         tdb_store_int32( tdb, EVT_OLDEST_ENTRY, 1 );
51         tdb_store_int32( tdb, EVT_NEXT_RECORD, 1 );
52         tdb_store_int32( tdb, EVT_MAXSIZE, 0x80000 );
53         tdb_store_int32( tdb, EVT_RETENTION, 0x93A80 );
54
55         tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
56
57         return tdb;
58 }
59
60 /********************************************************************
61  make the tdb file name for an event log, given destination buffer
62  and size. Caller must free memory.
63 ********************************************************************/
64
65 char *elog_tdbname(TALLOC_CTX *ctx, const char *name )
66 {
67         char *path = talloc_asprintf(ctx, "%s/%s.tdb",
68                         state_path("eventlog"),
69                         name);
70         if (!path) {
71                 return NULL;
72         }
73         strlower_m(path);
74         return path;
75 }
76
77
78 /********************************************************************
79  this function is used to count up the number of bytes in a
80  particular TDB
81 ********************************************************************/
82
83 struct trav_size_struct {
84         int size;
85         int rec_count;
86 };
87
88 static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
89                           void *state )
90 {
91         struct trav_size_struct  *tsize = (struct trav_size_struct *)state;
92
93         tsize->size += data.dsize;
94         tsize->rec_count++;
95
96         return 0;
97 }
98
99 /********************************************************************
100  returns the size of the eventlog, and if MaxSize is a non-null
101  ptr, puts the MaxSize there. This is purely a way not to have yet
102  another function that solely reads the maxsize of the eventlog.
103  Yeah, that's it.
104 ********************************************************************/
105
106 int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
107 {
108         struct trav_size_struct tsize;
109
110         if ( !tdb )
111                 return 0;
112
113         ZERO_STRUCT( tsize );
114
115         tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
116
117         if ( MaxSize != NULL ) {
118                 *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
119         }
120
121         if ( Retention != NULL ) {
122                 *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
123         }
124
125         DEBUG( 1,
126                ( "eventlog size: [%d] for [%d] records\n", tsize.size,
127                  tsize.rec_count ) );
128         return tsize.size;
129 }
130
131 /********************************************************************
132  Discard early event logs until we have enough for 'needed' bytes...
133  NO checking done beforehand to see that we actually need to do
134  this, and it's going to pluck records one-by-one. So, it's best
135  to determine that this needs to be done before doing it.
136
137  Setting whack_by_date to True indicates that eventlogs falling
138  outside of the retention range need to go...
139
140  return True if we made enough room to accommodate needed bytes
141 ********************************************************************/
142
143 static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32_t needed,
144                                     bool whack_by_date )
145 {
146         int32_t start_record, i, new_start;
147         int32_t end_record;
148         int32_t reclen, tresv1, trecnum, timegen, timewr;
149         int nbytes, len, Retention, MaxSize;
150         TDB_DATA key, ret;
151         time_t current_time, exp_time;
152
153         /* discard some eventlogs */
154
155         /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
156            although records not necessarily guaranteed to have successive times */
157         /* */
158
159         /* lock */
160         tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
161         /* read */
162         end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
163         start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
164         Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
165         MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
166
167         time( &current_time );
168
169         /* calculate ... */
170         exp_time = current_time - Retention;    /* discard older than exp_time */
171
172         /* todo - check for sanity in next_record */
173         nbytes = 0;
174
175         DEBUG( 3,
176                ( "MaxSize [%d] Retention [%d] Current Time [%u]  exp_time [%u]\n",
177                  MaxSize, Retention, (unsigned int)current_time, (unsigned int)exp_time ) );
178         DEBUG( 3,
179                ( "Start Record [%u] End Record [%u]\n",
180                 (unsigned int)start_record,
181                 (unsigned int)end_record ));
182
183         for ( i = start_record; i < end_record; i++ ) {
184                 /* read a record, add the amt to nbytes */
185                 key.dsize = sizeof(int32_t);
186                 key.dptr = (unsigned char *)&i;
187                 ret = tdb_fetch( the_tdb, key );
188                 if ( ret.dsize == 0 ) {
189                         DEBUG( 8,
190                                ( "Can't find a record for the key, record [%d]\n",
191                                  i ) );
192                         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
193                         return False;
194                 }
195                 nbytes += ret.dsize;    /* note this includes overhead */
196
197                 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
198                                   &tresv1, &trecnum, &timegen, &timewr );
199                 if (len == -1) {
200                         DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
201                         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
202                         SAFE_FREE( ret.dptr );
203                         return False;
204                 }
205
206                 DEBUG( 8,
207                        ( "read record %u, record size is [%d], total so far [%d]\n",
208                          (unsigned int)i, reclen, nbytes ) );
209
210                 SAFE_FREE( ret.dptr );
211
212                 /* note that other servers may just stop writing records when the size limit
213                    is reached, and there are no records older than 'retention'. This doesn't
214                    like a very useful thing to do, so instead we whack (as in sleeps with the
215                    fishes) just enough records to fit the what we need.  This behavior could
216                    be changed to 'match', if the need arises. */
217
218                 if ( !whack_by_date && ( nbytes >= needed ) )
219                         break;  /* done */
220                 if ( whack_by_date && ( timegen >= exp_time ) )
221                         break;  /* done */
222         }
223
224         DEBUG( 3,
225                ( "nbytes [%d] needed [%d] start_record is [%u], should be set to [%u]\n",
226                  nbytes, needed, (unsigned int)start_record, (unsigned int)i ) );
227         /* todo - remove eventlog entries here and set starting record to start_record... */
228         new_start = i;
229         if ( start_record != new_start ) {
230                 for ( i = start_record; i < new_start; i++ ) {
231                         key.dsize = sizeof(int32_t);
232                         key.dptr = (unsigned char *)&i;
233                         tdb_delete( the_tdb, key );
234                 }
235
236                 tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
237         }
238         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
239         return True;
240 }
241
242 /********************************************************************
243   some hygiene for an eventlog - see how big it is, and then
244   calculate how many bytes we need to remove
245 ********************************************************************/
246
247 bool prune_eventlog( TDB_CONTEXT * tdb )
248 {
249         int MaxSize, Retention, CalcdSize;
250
251         if ( !tdb ) {
252                 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
253                 return False;
254         }
255
256         CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
257         DEBUG( 3,
258                ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
259                  MaxSize ) );
260
261         if ( CalcdSize > MaxSize ) {
262                 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
263                                                False );
264         }
265
266         return make_way_for_eventlogs( tdb, 0, True );
267 }
268
269 /********************************************************************
270 ********************************************************************/
271
272 bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32_t needed )
273 {
274         int calcd_size;
275         int MaxSize, Retention;
276
277         /* see if we can write to the eventlog -- do a policy enforcement */
278         if ( !tdb )
279                 return False;   /* tdb is null, so we can't write to it */
280
281
282         if ( needed < 0 )
283                 return False;
284         MaxSize = 0;
285         Retention = 0;
286
287         calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
288
289         if ( calcd_size <= MaxSize )
290                 return True;    /* you betcha */
291         if ( calcd_size + needed < MaxSize )
292                 return True;
293
294         if ( Retention == 0xffffffff ) {
295                 return False;   /* see msdn - we can't write no room, discard */
296         }
297         /*
298            note don't have to test, but always good to show intent, in case changes needed
299            later
300          */
301
302         if ( Retention == 0x00000000 ) {
303                 /* discard record(s) */
304                 /* todo  - decide when to remove a bunch vs. just what we need... */
305                 return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
306                                                True );
307         }
308
309         return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
310 }
311
312 /*******************************************************************
313 *******************************************************************/
314
315 ELOG_TDB *elog_open_tdb( const char *logname, bool force_clear, bool read_only )
316 {
317         TDB_CONTEXT *tdb = NULL;
318         uint32_t vers_id;
319         ELOG_TDB *ptr;
320         char *tdbpath = NULL;
321         ELOG_TDB *tdb_node = NULL;
322         char *eventlogdir;
323         TALLOC_CTX *ctx = talloc_tos();
324
325         /* check for invalid options */
326
327         if (force_clear && read_only) {
328                 DEBUG(1,("elog_open_tdb: Invalid flags\n"));
329                 return NULL;
330         }
331
332         /* first see if we have an open context */
333
334         for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
335                 if ( strequal( ptr->name, logname ) ) {
336                         ptr->ref_count++;
337
338                         /* trick to alow clearing of the eventlog tdb.
339                            The force_clear flag should imply that someone
340                            has done a force close.  So make sure the tdb
341                            is NULL.  If this is a normal open, then just
342                            return the existing reference */
343
344                         if ( force_clear ) {
345                                 SMB_ASSERT( ptr->tdb == NULL );
346                                 break;
347                         }
348                         else
349                                 return ptr;
350                 }
351         }
352
353         /* make sure that the eventlog dir exists */
354
355         eventlogdir = state_path( "eventlog" );
356         if ( !directory_exist( eventlogdir ) )
357                 mkdir( eventlogdir, 0755 );
358
359         /* get the path on disk */
360
361         tdbpath = elog_tdbname(ctx, logname);
362         if (!tdbpath) {
363                 return NULL;
364         }
365
366         DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
367                 tdbpath, force_clear?"True":"False" ));
368
369         /* the tdb wasn't already open or this is a forced clear open */
370
371         if ( !force_clear ) {
372
373                 tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, read_only ? O_RDONLY : O_RDWR , 0 );
374                 if ( tdb ) {
375                         vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
376
377                         if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
378                                 DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
379                                         vers_id, tdbpath));
380                                 tdb_close( tdb );
381                                 tdb = elog_init_tdb( tdbpath );
382                         }
383                 }
384         }
385
386         if ( !tdb )
387                 tdb = elog_init_tdb( tdbpath );
388
389         /* if we got a valid context, then add it to the list */
390
391         if ( tdb ) {
392                 /* on a forced clear, just reset the tdb context if we already
393                    have an open entry in the list */
394
395                 if ( ptr ) {
396                         ptr->tdb = tdb;
397                         return ptr;
398                 }
399
400                 if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) {
401                         DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
402                         tdb_close( tdb );
403                         return NULL;
404                 }
405
406                 tdb_node->name = talloc_strdup( tdb_node, logname );
407                 tdb_node->tdb = tdb;
408                 tdb_node->ref_count = 1;
409
410                 DLIST_ADD( open_elog_list, tdb_node );
411         }
412
413         return tdb_node;
414 }
415
416 /*******************************************************************
417  Wrapper to handle reference counts to the tdb
418 *******************************************************************/
419
420 int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
421 {
422         TDB_CONTEXT *tdb;
423
424         if ( !etdb )
425                 return 0;
426
427         etdb->ref_count--;
428
429         SMB_ASSERT( etdb->ref_count >= 0 );
430
431         if ( etdb->ref_count == 0 ) {
432                 tdb = etdb->tdb;
433                 DLIST_REMOVE( open_elog_list, etdb );
434                 TALLOC_FREE( etdb );
435                 return tdb_close( tdb );
436         }
437
438         if ( force_close ) {
439                 tdb = etdb->tdb;
440                 etdb->tdb = NULL;
441                 return tdb_close( tdb );
442         }
443
444         return 0;
445 }
446
447
448 /*******************************************************************
449  write an eventlog entry. Note that we have to lock, read next
450  eventlog, increment, write, write the record, unlock
451
452  coming into this, ee has the eventlog record, and the auxilliary date
453  (computer name, etc.) filled into the other structure. Before packing
454  into a record, this routine will calc the appropriate padding, etc.,
455  and then blast out the record in a form that can be read back in
456 *******************************************************************/
457
458 #define MARGIN 512
459
460 int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee )
461 {
462         int32 next_record;
463         uint8 *packed_ee;
464         TALLOC_CTX *mem_ctx = NULL;
465         TDB_DATA kbuf, ebuf;
466         uint32_t n_packed;
467
468         if ( !ee )
469                 return 0;
470
471         mem_ctx = talloc_init( "write_eventlog_tdb" );
472
473         if ( mem_ctx == NULL )
474                 return 0;
475
476         /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
477         if ( ee->record.time_generated == 0 )
478                 return 0;
479
480         /* todo - check for sanity in next_record */
481
482         fixup_eventlog_entry( ee );
483
484         if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) {
485                 DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
486                 talloc_destroy( mem_ctx );
487                 return 0;
488         }
489
490         /* alloc mem for the packed version */
491         packed_ee = (uint8 *)TALLOC( mem_ctx, ee->record.length + MARGIN );
492         if ( !packed_ee ) {
493                 talloc_destroy( mem_ctx );
494                 return 0;
495         }
496
497         /* need to read the record number and insert it into the entry here */
498
499         /* lock */
500         tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
501         /* read */
502         next_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
503
504         n_packed =
505                 tdb_pack( (uint8 *)packed_ee, ee->record.length + MARGIN,
506                           "ddddddwwwwddddddBBdBBBd", ee->record.length,
507                           ee->record.reserved1, next_record,
508                           ee->record.time_generated, ee->record.time_written,
509                           ee->record.event_id, ee->record.event_type,
510                           ee->record.num_strings, ee->record.event_category,
511                           ee->record.reserved2,
512                           ee->record.closing_record_number,
513                           ee->record.string_offset,
514                           ee->record.user_sid_length,
515                           ee->record.user_sid_offset, ee->record.data_length,
516                           ee->record.data_offset,
517                           ee->data_record.source_name_len,
518                           ee->data_record.source_name,
519                           ee->data_record.computer_name_len,
520                           ee->data_record.computer_name,
521                           ee->data_record.sid_padding,
522                           ee->record.user_sid_length, ee->data_record.sid,
523                           ee->data_record.strings_len,
524                           ee->data_record.strings,
525                           ee->data_record.user_data_len,
526                           ee->data_record.user_data,
527                           ee->data_record.data_padding );
528
529         /*DEBUG(3,("write_eventlog_tdb: packed into  %d\n",n_packed)); */
530
531         /* increment the record count */
532
533         kbuf.dsize = sizeof( int32 );
534         kbuf.dptr = (uint8 * ) & next_record;
535
536         ebuf.dsize = n_packed;
537         ebuf.dptr = (uint8 *)packed_ee;
538
539         if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) {
540                 /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
541                 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
542                 talloc_destroy( mem_ctx );
543                 return 0;
544         }
545         next_record++;
546         tdb_store_int32( the_tdb, EVT_NEXT_RECORD, next_record );
547         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
548         talloc_destroy( mem_ctx );
549         return ( next_record - 1 );
550 }
551
552 /*******************************************************************
553  calculate the correct fields etc for an eventlog entry
554 *******************************************************************/
555
556 void fixup_eventlog_entry( Eventlog_entry * ee )
557 {
558         /* fix up the eventlog entry structure as necessary */
559
560         ee->data_record.sid_padding =
561                 ( ( 4 -
562                     ( ( ee->data_record.source_name_len +
563                         ee->data_record.computer_name_len ) % 4 ) ) % 4 );
564         ee->data_record.data_padding =
565                 ( 4 -
566                   ( ( ee->data_record.strings_len +
567                       ee->data_record.user_data_len ) % 4 ) ) % 4;
568         ee->record.length = sizeof( Eventlog_record );
569         ee->record.length += ee->data_record.source_name_len;
570         ee->record.length += ee->data_record.computer_name_len;
571         if ( ee->record.user_sid_length == 0 ) {
572                 /* Should not pad to a DWORD boundary for writing out the sid if there is
573                    no SID, so just propagate the padding to pad the data */
574                 ee->data_record.data_padding += ee->data_record.sid_padding;
575                 ee->data_record.sid_padding = 0;
576         }
577         /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
578         /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
579
580         ee->record.length += ee->data_record.sid_padding;
581         ee->record.length += ee->record.user_sid_length;
582         ee->record.length += ee->data_record.strings_len;
583         ee->record.length += ee->data_record.user_data_len;
584         ee->record.length += ee->data_record.data_padding;
585         /* need another copy of length at the end of the data */
586         ee->record.length += sizeof( ee->record.length );
587 }
588
589 /********************************************************************
590  Note that it's a pretty good idea to initialize the Eventlog_entry
591  structure to zero's before calling parse_logentry on an batch of
592  lines that may resolve to a record.  ALSO, it's a good idea to
593  remove any linefeeds (that's EOL to you and me) on the lines
594  going in.
595 ********************************************************************/
596
597 bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
598 {
599         char *start = NULL, *stop = NULL;
600
601         start = line;
602
603         /* empty line signyfiying record delimeter, or we're at the end of the buffer */
604         if ( start == NULL || strlen( start ) == 0 ) {
605                 DEBUG( 6,
606                        ( "parse_logentry: found end-of-record indicator.\n" ) );
607                 *eor = True;
608                 return True;
609         }
610         if ( !( stop = strchr( line, ':' ) ) ) {
611                 return False;
612         }
613
614         DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
615
616         if ( 0 == strncmp( start, "LEN", stop - start ) ) {
617                 /* This will get recomputed later anyway -- probably not necessary */
618                 entry->size = atoi( stop + 1 );
619         } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
620                 /* For now all these reserved entries seem to have the same value,
621                    which can be hardcoded to int(1699505740) for now */
622                 entry->reserved = talloc_strdup(mem_ctx, "eLfL");
623         } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
624                 entry->record_number = atoi( stop + 1 );
625         } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
626                 entry->time_generated = atoi( stop + 1 );
627         } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
628                 entry->time_written = atoi( stop + 1 );
629         } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
630                 entry->event_id = atoi( stop + 1 );
631         } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
632                 if ( strstr( start, "ERROR" ) ) {
633                         entry->event_type = EVENTLOG_ERROR_TYPE;
634                 } else if ( strstr( start, "WARNING" ) ) {
635                         entry->event_type = EVENTLOG_WARNING_TYPE;
636                 } else if ( strstr( start, "INFO" ) ) {
637                         entry->event_type = EVENTLOG_INFORMATION_TYPE;
638                 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
639                         entry->event_type = EVENTLOG_AUDIT_SUCCESS;
640                 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
641                         entry->event_type = EVENTLOG_AUDIT_FAILURE;
642                 } else if ( strstr( start, "SUCCESS" ) ) {
643                         entry->event_type = EVENTLOG_SUCCESS;
644                 } else {
645                         /* some other eventlog type -- currently not defined in MSDN docs, so error out */
646                         return False;
647                 }
648         }
649
650 /*
651   else if(0 == strncmp(start, "NST", stop - start))
652   {
653   entry->num_of_strings = atoi(stop + 1);
654   }
655 */
656         else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
657                 entry->event_category = atoi( stop + 1 );
658         } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
659                 entry->reserved_flags = atoi( stop + 1 );
660         } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
661                 entry->closing_record_number = atoi( stop + 1 );
662         } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
663                 entry->sid_length = atoi( stop + 1 );
664         } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
665                 stop++;
666                 while ( isspace( stop[0] ) ) {
667                         stop++;
668                 }
669                 entry->source_name_len = strlen_m_term(stop);
670                 entry->source_name = talloc_strdup(mem_ctx, stop);
671                 if (entry->source_name_len == (uint32_t)-1 ||
672                                 entry->source_name == NULL) {
673                         return false;
674                 }
675         } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
676                 stop++;
677                 while ( isspace( stop[0] ) ) {
678                         stop++;
679                 }
680                 entry->computer_name_len = strlen_m_term(stop);
681                 entry->computer_name = talloc_strdup(mem_ctx, stop);
682                 if (entry->computer_name_len == (uint32_t)-1 ||
683                                 entry->computer_name == NULL) {
684                         return false;
685                 }
686         } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
687                 smb_ucs2_t *dummy = NULL;
688                 stop++;
689                 while ( isspace( stop[0] ) ) {
690                         stop++;
691                 }
692                 entry->sid_length = rpcstr_push_talloc(mem_ctx,
693                                 &dummy,
694                                 stop);
695                 entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
696                 if (entry->sid_length == (uint32_t)-1 ||
697                                 entry->sid.data == NULL) {
698                         return false;
699                 }
700         } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
701                 size_t tmp_len;
702                 /* skip past initial ":" */
703                 stop++;
704                 /* now skip any other leading whitespace */
705                 while ( isspace(stop[0])) {
706                         stop++;
707                 }
708                 tmp_len = strlen_m_term(stop);
709                 if (tmp_len == (size_t)-1) {
710                         return false;
711                 }
712                 if (!add_string_to_array(mem_ctx, stop, &entry->strings,
713                                          (int *)&entry->num_of_strings)) {
714                         return false;
715                 }
716                 entry->strings_len += tmp_len;
717         } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
718                 /* skip past initial ":" */
719                 stop++;
720                 /* now skip any other leading whitespace */
721                 while ( isspace( stop[0] ) ) {
722                         stop++;
723                 }
724                 entry->data_length = strlen_m(stop);
725                 entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
726                 if (!entry->data.data) {
727                         return false;
728                 }
729         } else {
730                 /* some other eventlog entry -- not implemented, so dropping on the floor */
731                 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
732                 /* For now return true so that we can keep on parsing this mess. Eventually
733                    we will return False here. */
734                 return true;
735         }
736         return true;
737 }
738
739 /*******************************************************************
740  calculate the correct fields etc for an eventlog entry
741 *******************************************************************/
742
743 size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
744 {
745         size_t size = 56; /* static size of integers before buffers start */
746
747         r->source_name_len = strlen_m_term(r->source_name) * 2;
748         r->computer_name_len = strlen_m_term(r->computer_name) * 2;
749         r->strings_len = ndr_size_string_array(r->strings,
750                 r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
751
752         /* fix up the eventlog entry structure as necessary */
753         r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
754         r->padding =       ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
755
756         if (r->sid_length == 0) {
757                 /* Should not pad to a DWORD boundary for writing out the sid if there is
758                    no SID, so just propagate the padding to pad the data */
759                 r->padding += r->sid_padding;
760                 r->sid_padding = 0;
761         }
762
763         size += r->source_name_len;
764         size += r->computer_name_len;
765         size += r->sid_padding;
766         size += r->sid_length;
767         size += r->strings_len;
768         size += r->data_length;
769         size += r->padding;
770         /* need another copy of length at the end of the data */
771         size += sizeof(r->size);
772
773         r->size = size;
774
775         return size;
776 }
777
778
779 /********************************************************************
780  ********************************************************************/
781
782 struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
783                                                   TDB_CONTEXT *tdb,
784                                                   uint32_t record_number)
785 {
786         struct eventlog_Record_tdb *r;
787         TDB_DATA data, key;
788
789         int32_t srecno;
790         enum ndr_err_code ndr_err;
791         DATA_BLOB blob;
792
793         srecno = record_number;
794         key.dptr = (unsigned char *)&srecno;
795         key.dsize = sizeof(int32_t);
796
797         data = tdb_fetch(tdb, key);
798         if (data.dsize == 0) {
799                 DEBUG(8,("evlog_pull_record_tdb: "
800                         "Can't find a record for the key, record %d\n",
801                         record_number));
802                 return NULL;
803         }
804
805         r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
806         if (!r) {
807                 goto done;
808         }
809
810         blob = data_blob_const(data.dptr, data.dsize);
811
812         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, r,
813                            (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
814
815         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
816                 DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
817                         record_number));
818                 TALLOC_FREE(r);
819                 goto done;
820         }
821
822         if (DEBUGLEVEL >= 10) {
823                 NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
824         }
825
826         DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
827                 record_number));
828  done:
829         SAFE_FREE(data.dptr);
830
831         return r;
832 }
833
834 /********************************************************************
835  write an eventlog entry. Note that we have to lock, read next
836  eventlog, increment, write, write the record, unlock
837
838  coming into this, ee has the eventlog record, and the auxilliary date
839  (computer name, etc.) filled into the other structure. Before packing
840  into a record, this routine will calc the appropriate padding, etc.,
841  and then blast out the record in a form that can be read back in
842  ********************************************************************/
843
844 NTSTATUS evlog_push_record_tdb(TALLOC_CTX *mem_ctx,
845                                TDB_CONTEXT *tdb,
846                                struct eventlog_Record_tdb *r,
847                                uint32_t *record_number)
848 {
849         TDB_DATA kbuf, ebuf;
850         DATA_BLOB blob;
851         enum ndr_err_code ndr_err;
852         int ret;
853
854         if (!r) {
855                 return NT_STATUS_INVALID_PARAMETER;
856         }
857
858         if (!can_write_to_eventlog(tdb, r->size)) {
859                 return NT_STATUS_EVENTLOG_CANT_START;
860         }
861
862         /* need to read the record number and insert it into the entry here */
863
864         /* lock */
865         ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
866         if (ret == -1) {
867                 return NT_STATUS_LOCK_NOT_GRANTED;
868         }
869
870         /* read */
871         r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
872
873         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, r,
874                       (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
875         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
876                 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
877                 return ndr_map_error2ntstatus(ndr_err);
878         }
879
880         /* increment the record count */
881
882         kbuf.dsize = sizeof(int32_t);
883         kbuf.dptr = (uint8_t *)&r->record_number;
884
885         ebuf.dsize = blob.length;
886         ebuf.dptr  = blob.data;
887
888         ret = tdb_store(tdb, kbuf, ebuf, 0);
889         if (ret == -1) {
890                 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
891                 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
892         }
893
894         ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
895         if (ret == -1) {
896                 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
897                 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
898         }
899         tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
900
901         if (record_number) {
902                 *record_number = r->record_number;
903         }
904
905         return NT_STATUS_OK;
906 }
907
908 /********************************************************************
909  ********************************************************************/
910
911 NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
912                                       const struct EVENTLOGRECORD *e,
913                                       struct eventlog_Record_tdb *t)
914 {
915         uint32_t i;
916
917         ZERO_STRUCTP(t);
918
919         t->size                         = e->Length;
920         t->reserved                     = e->Reserved;
921         t->record_number                = e->RecordNumber;
922         t->time_generated               = e->TimeGenerated;
923         t->time_written                 = e->TimeWritten;
924         t->event_id                     = e->EventID;
925         t->event_type                   = e->EventType;
926         t->num_of_strings               = e->NumStrings;
927         t->event_category               = e->EventCategory;
928         t->reserved_flags               = e->ReservedFlags;
929         t->closing_record_number        = e->ClosingRecordNumber;
930
931         t->stringoffset                 = e->StringOffset;
932         t->sid_length                   = e->UserSidLength;
933         t->sid_offset                   = e->UserSidOffset;
934         t->data_length                  = e->DataLength;
935         t->data_offset                  = e->DataOffset;
936
937         t->source_name_len              = 2 * strlen_m_term(e->SourceName);
938         t->source_name                  = talloc_strdup(mem_ctx, e->SourceName);
939         NT_STATUS_HAVE_NO_MEMORY(t->source_name);
940
941         t->computer_name_len            = 2 * strlen_m_term(e->Computername);
942         t->computer_name                = talloc_strdup(mem_ctx, e->Computername);
943         NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
944
945         /* t->sid_padding; */
946         if (e->UserSidLength > 0) {
947                 const char *sid_str = NULL;
948                 smb_ucs2_t *dummy = NULL;
949                 sid_str = sid_string_talloc(mem_ctx, &e->UserSid);
950                 t->sid_length = rpcstr_push_talloc(mem_ctx, &dummy, sid_str);
951                 if (t->sid_length == -1) {
952                         return NT_STATUS_NO_MEMORY;
953                 }
954                 t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
955                 NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
956         }
957
958         t->strings                      = talloc_array(mem_ctx, const char *, e->NumStrings);
959         for (i=0; i < e->NumStrings; i++) {
960                 t->strings[i]           = talloc_strdup(t->strings, e->Strings[i]);
961                 NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
962         }
963
964         t->strings_len                  = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
965         t->data                         = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
966         /* t->padding                   = r->Pad; */
967
968         return NT_STATUS_OK;
969 }