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