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