r23779: Change from v2 or later to v3 or later.
[nivanova/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, write to the Free Software
20  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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( const char *name )
67 {
68         fstring path;
69         char *tdb_fullpath;
70         char *eventlogdir = lock_path( "eventlog" );
71         
72         pstr_sprintf( path, "%s/%s.tdb", eventlogdir, name );
73         strlower_m( path );
74         tdb_fullpath = SMB_STRDUP( path );
75         
76         return tdb_fullpath;
77 }
78
79
80 /********************************************************************
81  this function is used to count up the number of bytes in a 
82  particular TDB
83 ********************************************************************/
84
85 struct trav_size_struct {
86         int size;
87         int rec_count;
88 };
89
90 static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
91                           void *state )
92 {
93         struct trav_size_struct  *tsize = (struct trav_size_struct *)state;
94         
95         tsize->size += data.dsize;
96         tsize->rec_count++;
97         
98         return 0;
99 }
100
101 /********************************************************************
102  returns the size of the eventlog, and if MaxSize is a non-null 
103  ptr, puts the MaxSize there. This is purely a way not to have yet 
104  another function that solely reads the maxsize of the eventlog. 
105  Yeah, that's it.
106 ********************************************************************/
107
108 int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
109 {
110         struct trav_size_struct tsize;
111         
112         if ( !tdb )
113                 return 0;
114                 
115         ZERO_STRUCT( tsize );
116
117         tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
118
119         if ( MaxSize != NULL ) {
120                 *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
121         }
122
123         if ( Retention != NULL ) {
124                 *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
125         }
126
127         DEBUG( 1,
128                ( "eventlog size: [%d] for [%d] records\n", tsize.size,
129                  tsize.rec_count ) );
130         return tsize.size;
131 }
132
133 /********************************************************************
134  Discard early event logs until we have enough for 'needed' bytes...
135  NO checking done beforehand to see that we actually need to do 
136  this, and it's going to pluck records one-by-one. So, it's best 
137  to determine that this needs to be done before doing it.  
138
139  Setting whack_by_date to True indicates that eventlogs falling 
140  outside of the retention range need to go...
141  
142  return True if we made enough room to accommodate needed bytes
143 ********************************************************************/
144
145 BOOL make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32 needed,
146                              BOOL whack_by_date )
147 {
148         int start_record, i, new_start;
149         int end_record;
150         int nbytes, reclen, len, Retention, MaxSize;
151         int tresv1, trecnum, timegen, timewr;
152         TDB_DATA key, ret;
153         TALLOC_CTX *mem_ctx = NULL;
154         time_t current_time, exp_time;
155
156         /* discard some eventlogs */
157
158         /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
159            although records not necessarily guaranteed to have successive times */
160         /* */
161         mem_ctx = talloc_init( "make_way_for_eventlogs" );      /* Homage to BPG */
162
163         if ( mem_ctx == NULL )
164                 return False;   /* can't allocate memory indicates bigger problems */
165         /* lock */
166         tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
167         /* read */
168         end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
169         start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
170         Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
171         MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
172
173         time( &current_time );
174
175         /* calculate ... */
176         exp_time = current_time - Retention;    /* discard older than exp_time */
177
178         /* todo - check for sanity in next_record */
179         nbytes = 0;
180
181         DEBUG( 3,
182                ( "MaxSize [%d] Retention [%d] Current Time [%d]  exp_time [%d]\n",
183                  MaxSize, Retention, (uint32)current_time, (uint32)exp_time ) );
184         DEBUG( 3,
185                ( "Start Record [%d] End Record [%d]\n", start_record,
186                  end_record ) );
187
188         for ( i = start_record; i < end_record; i++ ) {
189                 /* read a record, add the amt to nbytes */
190                 key.dsize = sizeof( int32 );
191                 key.dptr = ( uint8 * ) ( int32 * ) & i;
192                 ret = tdb_fetch( the_tdb, key );
193                 if ( ret.dsize == 0 ) {
194                         DEBUG( 8,
195                                ( "Can't find a record for the key, record [%d]\n",
196                                  i ) );
197                         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
198                         return False;
199                 }
200                 nbytes += ret.dsize;    /* note this includes overhead */
201
202                 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
203                                   &tresv1, &trecnum, &timegen, &timewr );
204                 if (len == -1) {
205                         DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
206                         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
207                         return False;
208                 }
209
210                 DEBUG( 8,
211                        ( "read record %d, record size is [%d], total so far [%d]\n",
212                          i, reclen, nbytes ) );
213
214                 SAFE_FREE( ret.dptr );
215
216                 /* note that other servers may just stop writing records when the size limit
217                    is reached, and there are no records older than 'retention'. This doesn't 
218                    like a very useful thing to do, so instead we whack (as in sleeps with the 
219                    fishes) just enough records to fit the what we need.  This behavior could
220                    be changed to 'match', if the need arises. */
221
222                 if ( !whack_by_date && ( nbytes >= needed ) )
223                         break;  /* done */
224                 if ( whack_by_date && ( timegen >= exp_time ) )
225                         break;  /* done */
226         }
227
228         DEBUG( 3,
229                ( "nbytes [%d] needed [%d] start_record is [%d], should be set to [%d]\n",
230                  nbytes, needed, start_record, i ) );
231         /* todo - remove eventlog entries here and set starting record to start_record... */
232         new_start = i;
233         if ( start_record != new_start ) {
234                 for ( i = start_record; i < new_start; i++ ) {
235                         key.dsize = sizeof( int32 );
236                         key.dptr = ( uint8 * ) ( int32 * ) & i;
237                         tdb_delete( the_tdb, key );
238                 }
239
240                 tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
241         }
242         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
243         return True;
244 }
245
246 /********************************************************************
247   some hygiene for an eventlog - see how big it is, and then 
248   calculate how many bytes we need to remove                   
249 ********************************************************************/
250
251 BOOL prune_eventlog( TDB_CONTEXT * tdb )
252 {
253         int MaxSize, Retention, CalcdSize;
254
255         if ( !tdb ) {
256                 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
257                 return False;
258         }
259
260         CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
261         DEBUG( 3,
262                ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
263                  MaxSize ) );
264
265         if ( CalcdSize > MaxSize ) {
266                 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
267                                                False );
268         }
269
270         return make_way_for_eventlogs( tdb, 0, True );
271 }
272
273 /********************************************************************
274 ********************************************************************/
275
276 BOOL can_write_to_eventlog( TDB_CONTEXT * tdb, int32 needed )
277 {
278         int calcd_size;
279         int MaxSize, Retention;
280
281         /* see if we can write to the eventlog -- do a policy enforcement */
282         if ( !tdb )
283                 return False;   /* tdb is null, so we can't write to it */
284
285
286         if ( needed < 0 )
287                 return False;
288         MaxSize = 0;
289         Retention = 0;
290
291         calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
292
293         if ( calcd_size <= MaxSize )
294                 return True;    /* you betcha */
295         if ( calcd_size + needed < MaxSize )
296                 return True;
297
298         if ( Retention == 0xffffffff ) {
299                 return False;   /* see msdn - we can't write no room, discard */
300         }
301         /*
302            note don't have to test, but always good to show intent, in case changes needed
303            later
304          */
305
306         if ( Retention == 0x00000000 ) {
307                 /* discard record(s) */
308                 /* todo  - decide when to remove a bunch vs. just what we need... */
309                 return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
310                                                True );
311         }
312
313         return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
314 }
315
316 /*******************************************************************
317 *******************************************************************/
318
319 ELOG_TDB *elog_open_tdb( char *logname, BOOL force_clear )
320 {
321         TDB_CONTEXT *tdb = NULL;
322         uint32 vers_id;
323         ELOG_TDB *ptr;
324         char *tdbfilename;
325         pstring tdbpath;
326         ELOG_TDB *tdb_node = NULL;
327         char *eventlogdir;
328
329         /* first see if we have an open context */
330         
331         for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
332                 if ( strequal( ptr->name, logname ) ) {
333                         ptr->ref_count++;
334
335                         /* trick to alow clearing of the eventlog tdb.
336                            The force_clear flag should imply that someone
337                            has done a force close.  So make sure the tdb 
338                            is NULL.  If this is a normal open, then just 
339                            return the existing reference */
340
341                         if ( force_clear ) {
342                                 SMB_ASSERT( ptr->tdb == NULL );
343                                 break;
344                         }
345                         else
346                                 return ptr;
347                 }
348         }
349         
350         /* make sure that the eventlog dir exists */
351         
352         eventlogdir = lock_path( "eventlog" );
353         if ( !directory_exist( eventlogdir, NULL ) )
354                 mkdir( eventlogdir, 0755 );     
355         
356         /* get the path on disk */
357         
358         tdbfilename = elog_tdbname( logname );
359         pstrcpy( tdbpath, tdbfilename );
360         SAFE_FREE( tdbfilename );
361
362         DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n", 
363                 tdbpath, force_clear?"True":"False" ));
364                 
365         /* the tdb wasn't already open or this is a forced clear open */
366
367         if ( !force_clear ) {
368
369                 tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, O_RDWR , 0 );      
370                 if ( tdb ) {
371                         vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
372
373                         if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
374                                 DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
375                                         vers_id, tdbpath));
376                                 tdb_close( tdb );
377                                 tdb = elog_init_tdb( tdbpath );
378                         }
379                 }
380         }
381         
382         if ( !tdb )
383                 tdb = elog_init_tdb( tdbpath );
384         
385         /* if we got a valid context, then add it to the list */
386         
387         if ( tdb ) {
388                 /* on a forced clear, just reset the tdb context if we already
389                    have an open entry in the list */
390
391                 if ( ptr ) {
392                         ptr->tdb = tdb;
393                         return ptr;
394                 }
395
396                 if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) {
397                         DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
398                         tdb_close( tdb );
399                         return NULL;
400                 }
401                 
402                 tdb_node->name = talloc_strdup( tdb_node, logname );
403                 tdb_node->tdb = tdb;
404                 tdb_node->ref_count = 1;
405                 
406                 DLIST_ADD( open_elog_list, tdb_node );
407         }
408
409         return tdb_node;
410 }
411
412 /*******************************************************************
413  Wrapper to handle reference counts to the tdb
414 *******************************************************************/
415
416 int elog_close_tdb( ELOG_TDB *etdb, BOOL force_close )
417 {
418         TDB_CONTEXT *tdb;
419
420         if ( !etdb )
421                 return 0;
422                 
423         etdb->ref_count--;
424         
425         SMB_ASSERT( etdb->ref_count >= 0 );
426
427         if ( etdb->ref_count == 0 ) {
428                 tdb = etdb->tdb;
429                 DLIST_REMOVE( open_elog_list, etdb );
430                 TALLOC_FREE( etdb );
431                 return tdb_close( tdb );
432         }
433         
434         if ( force_close ) {
435                 tdb = etdb->tdb;
436                 etdb->tdb = NULL;
437                 return tdb_close( tdb );
438         }
439
440         return 0;
441 }
442
443
444 /*******************************************************************
445  write an eventlog entry. Note that we have to lock, read next 
446  eventlog, increment, write, write the record, unlock 
447  
448  coming into this, ee has the eventlog record, and the auxilliary date 
449  (computer name, etc.) filled into the other structure. Before packing 
450  into a record, this routine will calc the appropriate padding, etc., 
451  and then blast out the record in a form that can be read back in
452 *******************************************************************/
453  
454 #define MARGIN 512
455
456 int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee )
457 {
458         int32 next_record;
459         uint8 *packed_ee;
460         TALLOC_CTX *mem_ctx = NULL;
461         TDB_DATA kbuf, ebuf;
462         uint32 n_packed;
463
464         if ( !ee )
465                 return 0;
466
467         mem_ctx = talloc_init( "write_eventlog_tdb" );
468
469         if ( mem_ctx == NULL )
470                 return 0;
471
472         if ( !ee )
473                 return 0;
474         /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
475         if ( ee->record.time_generated == 0 )
476                 return 0;
477
478         /* todo - check for sanity in next_record */
479
480         fixup_eventlog_entry( ee );
481
482         if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) {
483                 DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
484                 talloc_destroy( mem_ctx );
485                 return 0;
486         }
487
488         /* alloc mem for the packed version */
489         packed_ee = (uint8 *)TALLOC( mem_ctx, ee->record.length + MARGIN );
490         if ( !packed_ee ) {
491                 talloc_destroy( mem_ctx );
492                 return 0;
493         }
494
495         /* need to read the record number and insert it into the entry here */
496
497         /* lock */
498         tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
499         /* read */
500         next_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
501
502         n_packed =
503                 tdb_pack( (uint8 *)packed_ee, ee->record.length + MARGIN,
504                           "ddddddwwwwddddddBBdBBBd", ee->record.length,
505                           ee->record.reserved1, next_record,
506                           ee->record.time_generated, ee->record.time_written,
507                           ee->record.event_id, ee->record.event_type,
508                           ee->record.num_strings, ee->record.event_category,
509                           ee->record.reserved2,
510                           ee->record.closing_record_number,
511                           ee->record.string_offset,
512                           ee->record.user_sid_length,
513                           ee->record.user_sid_offset, ee->record.data_length,
514                           ee->record.data_offset,
515                           ee->data_record.source_name_len,
516                           ee->data_record.source_name,
517                           ee->data_record.computer_name_len,
518                           ee->data_record.computer_name,
519                           ee->data_record.sid_padding,
520                           ee->record.user_sid_length, ee->data_record.sid,
521                           ee->data_record.strings_len,
522                           ee->data_record.strings,
523                           ee->data_record.user_data_len,
524                           ee->data_record.user_data,
525                           ee->data_record.data_padding );
526
527         /*DEBUG(3,("write_eventlog_tdb: packed into  %d\n",n_packed)); */
528
529         /* increment the record count */
530
531         kbuf.dsize = sizeof( int32 );
532         kbuf.dptr = (uint8 * ) & next_record;
533
534         ebuf.dsize = n_packed;
535         ebuf.dptr = (uint8 *)packed_ee;
536
537         if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) {
538                 /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
539                 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
540                 talloc_destroy( mem_ctx );
541                 return 0;
542         }
543         next_record++;
544         tdb_store_int32( the_tdb, EVT_NEXT_RECORD, next_record );
545         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
546         talloc_destroy( mem_ctx );
547         return ( next_record - 1 );
548 }
549
550 /*******************************************************************
551  calculate the correct fields etc for an eventlog entry
552 *******************************************************************/
553
554 void fixup_eventlog_entry( Eventlog_entry * ee )
555 {
556         /* fix up the eventlog entry structure as necessary */
557
558         ee->data_record.sid_padding =
559                 ( ( 4 -
560                     ( ( ee->data_record.source_name_len +
561                         ee->data_record.computer_name_len ) % 4 ) ) % 4 );
562         ee->data_record.data_padding =
563                 ( 4 -
564                   ( ( ee->data_record.strings_len +
565                       ee->data_record.user_data_len ) % 4 ) ) % 4;
566         ee->record.length = sizeof( Eventlog_record );
567         ee->record.length += ee->data_record.source_name_len;
568         ee->record.length += ee->data_record.computer_name_len;
569         if ( ee->record.user_sid_length == 0 ) {
570                 /* Should not pad to a DWORD boundary for writing out the sid if there is
571                    no SID, so just propagate the padding to pad the data */
572                 ee->data_record.data_padding += ee->data_record.sid_padding;
573                 ee->data_record.sid_padding = 0;
574         }
575         /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
576         /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
577
578         ee->record.length += ee->data_record.sid_padding;
579         ee->record.length += ee->record.user_sid_length;
580         ee->record.length += ee->data_record.strings_len;
581         ee->record.length += ee->data_record.user_data_len;
582         ee->record.length += ee->data_record.data_padding;
583         /* need another copy of length at the end of the data */
584         ee->record.length += sizeof( ee->record.length );
585 }
586
587 /********************************************************************
588  Note that it's a pretty good idea to initialize the Eventlog_entry 
589  structure to zero's before calling parse_logentry on an batch of 
590  lines that may resolve to a record.  ALSO, it's a good idea to 
591  remove any linefeeds (that's EOL to you and me) on the lines 
592  going in.
593 ********************************************************************/
594
595 BOOL parse_logentry( char *line, Eventlog_entry * entry, BOOL * eor )
596 {
597         char *start = NULL, *stop = NULL;
598         pstring temp;
599         int temp_len = 0;
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->record.length = 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->record.reserved1 = atoi( stop + 1 );
623         } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
624                 entry->record.record_number = atoi( stop + 1 );
625         } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
626                 entry->record.time_generated = atoi( stop + 1 );
627         } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
628                 entry->record.time_written = atoi( stop + 1 );
629         } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
630                 entry->record.event_id = atoi( stop + 1 );
631         } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
632                 if ( strstr( start, "ERROR" ) ) {
633                         entry->record.event_type = EVENTLOG_ERROR_TYPE;
634                 } else if ( strstr( start, "WARNING" ) ) {
635                         entry->record.event_type = EVENTLOG_WARNING_TYPE;
636                 } else if ( strstr( start, "INFO" ) ) {
637                         entry->record.event_type = EVENTLOG_INFORMATION_TYPE;
638                 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
639                         entry->record.event_type = EVENTLOG_AUDIT_SUCCESS;
640                 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
641                         entry->record.event_type = EVENTLOG_AUDIT_FAILURE;
642                 } else if ( strstr( start, "SUCCESS" ) ) {
643                         entry->record.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->record.num_strings = atoi(stop + 1);
654   }
655 */
656         else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
657                 entry->record.event_category = atoi( stop + 1 );
658         } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
659                 entry->record.reserved2 = atoi( stop + 1 );
660         } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
661                 entry->record.closing_record_number = atoi( stop + 1 );
662         } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
663                 entry->record.user_sid_length = atoi( stop + 1 );
664         } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
665                 memset( temp, 0, sizeof( temp ) );
666                 stop++;
667                 while ( isspace( stop[0] ) ) {
668                         stop++;
669                 }
670                 temp_len = strlen( stop );
671                 strncpy( temp, stop, temp_len );
672                 rpcstr_push( ( void * ) ( entry->data_record.source_name ),
673                              temp, sizeof( entry->data_record.source_name ),
674                              STR_TERMINATE );
675                 entry->data_record.source_name_len =
676                         ( strlen_w( entry->data_record.source_name ) * 2 ) +
677                         2;
678         } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
679                 memset( temp, 0, sizeof( temp ) );
680                 stop++;
681                 while ( isspace( stop[0] ) ) {
682                         stop++;
683                 }
684                 temp_len = strlen( stop );
685                 strncpy( temp, stop, temp_len );
686                 rpcstr_push( ( void * ) ( entry->data_record.computer_name ),
687                              temp, sizeof( entry->data_record.computer_name ),
688                              STR_TERMINATE );
689                 entry->data_record.computer_name_len =
690                         ( strlen_w( entry->data_record.computer_name ) * 2 ) +
691                         2;
692         } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
693                 memset( temp, 0, sizeof( temp ) );
694                 stop++;
695                 while ( isspace( stop[0] ) ) {
696                         stop++;
697                 }
698                 temp_len = strlen( stop );
699                 strncpy( temp, stop, temp_len );
700                 rpcstr_push( ( void * ) ( entry->data_record.sid ), temp,
701                              sizeof( entry->data_record.sid ),
702                              STR_TERMINATE );
703                 entry->record.user_sid_length =
704                         ( strlen_w( entry->data_record.sid ) * 2 ) + 2;
705         } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
706                 /* skip past initial ":" */
707                 stop++;
708                 /* now skip any other leading whitespace */
709                 while ( isspace( stop[0] ) ) {
710                         stop++;
711                 }
712                 temp_len = strlen( stop );
713                 memset( temp, 0, sizeof( temp ) );
714                 strncpy( temp, stop, temp_len );
715                 rpcstr_push( ( void * ) ( entry->data_record.strings +
716                                           ( entry->data_record.strings_len / 2 ) ),
717                              temp,
718                              sizeof( entry->data_record.strings ) -
719                              ( entry->data_record.strings_len / 2 ), STR_TERMINATE );
720                 entry->data_record.strings_len += ( temp_len * 2 ) + 2;
721                 entry->record.num_strings++;
722         } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
723                 /* skip past initial ":" */
724                 stop++;
725                 /* now skip any other leading whitespace */
726                 while ( isspace( stop[0] ) ) {
727                         stop++;
728                 }
729                 entry->data_record.user_data_len = strlen( stop );
730                 memset( entry->data_record.user_data, 0,
731                         sizeof( entry->data_record.user_data ) );
732                 if ( entry->data_record.user_data_len > 0 ) {
733                         /* copy no more than the first 1024 bytes */
734                         if ( entry->data_record.user_data_len >
735                              sizeof( entry->data_record.user_data ) )
736                                 entry->data_record.user_data_len =
737                                         sizeof( entry->data_record.
738                                                 user_data );
739                         memcpy( entry->data_record.user_data, stop,
740                                 entry->data_record.user_data_len );
741                 }
742         } else {
743                 /* some other eventlog entry -- not implemented, so dropping on the floor */
744                 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
745                 /* For now return true so that we can keep on parsing this mess. Eventually
746                    we will return False here. */
747                 return True;
748         }
749         return True;
750 }