BIG merge from trunk. Features not copied over
[metze/old/v3-2-winbind-ndr.git] / source / rpc_server / srv_eventlog_nt.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Marcin Krzysztof Porwit    2005,
5  *  Copyright (C) Gerald (Jerry) Carter      2005.
6  *  
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *  
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *  
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21  
22 #include "includes.h"
23
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_RPC_SRV
26
27 typedef struct {
28         char *logname;
29         char *servername;
30         uint32 num_records;
31         uint32 oldest_entry;
32         uint32 flags;
33 } EventlogInfo;
34
35   
36 /********************************************************************
37  Inform the external eventlog machinery of default values (on startup 
38  probably)
39 ********************************************************************/
40
41 void eventlog_refresh_external_parameters( NT_USER_TOKEN *token )
42 {
43         const char **elogs = lp_eventlog_list();
44         int i;
45
46         if ( !elogs )
47                 return ;
48
49         if ( !*lp_eventlog_control_cmd() )
50                 return;
51
52         for ( i=0; elogs[i]; i++ ) {
53         
54                 DEBUG(10,("eventlog_refresh_external_parameters: Refreshing =>[%s]\n", 
55                         elogs[i]));     
56                 
57                 if ( !control_eventlog_hook( token, elogs[i] ) ) {
58                         DEBUG(0,("eventlog_refresh_external_parameters: failed to refresh [%s]\n",
59                                 elogs[i]));
60                 }
61         }  
62     
63         return;
64 }
65
66 /********************************************************************
67 ********************************************************************/
68
69 static void free_eventlog_info(void *ptr)
70 {
71         TALLOC_FREE( ptr );
72 }
73
74 /********************************************************************
75 ********************************************************************/
76
77 static EventlogInfo *find_eventlog_info_by_hnd(pipes_struct *p, POLICY_HND *handle)
78 {
79         EventlogInfo *info;
80     
81         if ( !find_policy_by_hnd(p,handle,(void **)&info) ) {
82                 DEBUG(2,("find_eventlog_info_by_hnd: eventlog not found.\n"));
83                 return NULL;
84         }
85
86         return info;
87 }
88
89 /********************************************************************
90  Callout to control the specified event log - passing out only 
91  the MaxSize and Retention values, along with eventlog name
92  uses smbrun...
93       INPUT: <control_cmd> <log name> <retention> <maxsize>
94       OUTPUT: nothing
95 ********************************************************************/
96
97 BOOL control_eventlog_hook(NT_USER_TOKEN *token, const char *elogname )
98 {
99         char *cmd = lp_eventlog_control_cmd();
100         pstring command;
101         int ret;
102         int fd = -1;
103         uint32 uiMaxSize, uiRetention;
104         pstring path;
105         REGISTRY_KEY *keyinfo;
106         REGISTRY_VALUE *val;
107         REGVAL_CTR *values;
108         WERROR wresult;
109
110         if ( !cmd || !*cmd ) {
111                 DEBUG(0, ("control_eventlog_hook: No \"eventlog control command\" defined in smb.conf!\n"));
112                 return False;
113         }
114
115         /* set resonable defaults.  512Kb on size and 1 week on time */
116         
117         uiMaxSize = 0x80000;
118         uiRetention = 604800;
119         
120         /* the general idea is to internally open the registry 
121            key and retreive the values.  That way we can continue 
122            to use the same fetch/store api that we use in 
123            srv_reg_nt.c */
124
125         pstr_sprintf( path, "%s/%s", KEY_EVENTLOG, elogname );
126         wresult = regkey_open_internal( &keyinfo, path, token, REG_KEY_READ );
127         
128         if ( !W_ERROR_IS_OK( wresult ) ) {
129                 DEBUG(4,("control_eventlog_hook: Failed to open key [%s] (%s)\n",
130                         path, dos_errstr(wresult) ));
131                 return False;
132         }
133         
134         if ( !(values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR )) ) {
135                 TALLOC_FREE( keyinfo );
136                 DEBUG(0,("control_eventlog_hook: talloc() failed!\n"));
137                 
138                 return False;
139         }
140         fetch_reg_values( keyinfo, values );
141         
142         if ( (val = regval_ctr_getvalue( values, "Retention" )) != NULL )
143                 uiRetention = IVAL( regval_data_p(val), 0 );
144
145         if ( (val = regval_ctr_getvalue( values, "MaxSize" )) != NULL )
146                 uiMaxSize = IVAL( regval_data_p(val), 0 );
147                 
148         TALLOC_FREE( keyinfo );
149         
150         /* now run the command */
151
152         pstr_sprintf(command, "%s \"%s\" %u %u", cmd, elogname, uiRetention, uiMaxSize );
153
154         DEBUG(10, ("control_eventlog_hook: Running [%s]\n", command));
155         ret = smbrun(command, &fd);
156         DEBUGADD(10, ("returned [%d]\n", ret));
157
158         if ( ret != 0 ) {
159                 DEBUG(10,("control_eventlog_hook: Command returned  [%d]\n", ret));
160                 if (fd != -1 )
161                         close(fd);
162                 return False;
163         }
164
165         close(fd);
166         return True;
167 }
168
169
170 /********************************************************************
171 ********************************************************************/
172
173 /**
174  * Callout to open the specified event log
175  * 
176  *   smbrun calling convention --
177  *     INPUT: <open_cmd> <log name> <policy handle>
178  *     OUTPUT: the string "SUCCESS" if the command succeeded
179  *             no such string if there was a failure.
180  */
181 static BOOL open_eventlog_hook( EventlogInfo *info )
182 {
183         char *cmd = lp_eventlog_open_cmd();
184         char **qlines;
185         pstring command;
186         int numlines = 0;
187         int ret;
188         int fd = -1;
189
190         if ( !cmd || !*cmd ) {
191                 DEBUG(0, ("Must define an \"eventlog open command\" entry in the config.\n"));
192                 return False;
193         }
194
195         pstr_sprintf(command, "%s \"%s\"", cmd, info->logname );
196
197         DEBUG(10, ("Running [%s]\n", command));
198         ret = smbrun(command, &fd);
199         DEBUGADD(10, ("returned [%d]\n", ret));
200
201         if(ret != 0) {
202                 if(fd != -1) {
203                         close(fd);
204                 }
205                 return False;
206         }
207
208         qlines = fd_lines_load(fd, &numlines);
209         DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
210         close(fd);
211
212         if(numlines) {
213                 DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
214                 if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS"))) {
215                         DEBUGADD(10, ("Able to open [%s].\n", info->logname));
216                         file_lines_free(qlines);
217                         return True;
218                 }
219         }
220
221         file_lines_free(qlines);
222
223         return False;
224 }
225
226 /********************************************************************
227 ********************************************************************/
228 /**
229  * Callout to get the number of records in the specified event log
230  * 
231  *   smbrun calling convention --
232  *     INPUT: <get_num_records_cmd> <log name> <policy handle>
233  *     OUTPUT: A single line with a single integer containing the number of
234  *             entries in the log. If there are no entries in the log, return 0.
235  */
236
237 static BOOL get_num_records_hook(EventlogInfo *info)
238 {
239         char *cmd = lp_eventlog_num_records_cmd();
240         char **qlines;
241         pstring command;
242         int numlines = 0;
243         int ret;
244         int fd = -1;
245
246         if ( !cmd || !*cmd ) {
247                 DEBUG(0, ("Must define an \"eventlog num records command\" entry in the config.\n"));
248                 return False;
249         }
250
251         pstr_sprintf( command, "%s \"%s\"", cmd, info->logname );
252
253         DEBUG(10, ("Running [%s]\n", command));
254         ret = smbrun(command, &fd);
255         DEBUGADD(10, ("returned [%d]\n", ret));
256
257         if(ret != 0) {
258                 if(fd != -1) {
259                         close(fd);
260                 }
261                 return False;
262         }
263
264         qlines = fd_lines_load(fd, &numlines);
265         DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
266         close(fd);
267
268         if(numlines) {
269                 DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
270                 sscanf(qlines[0], "%d", &(info->num_records));
271                 file_lines_free(qlines);
272                 return True;
273         }
274
275         file_lines_free(qlines);
276         return False;
277 }
278
279 /********************************************************************
280 ********************************************************************/
281
282 /**
283  * Callout to find the oldest record in the log
284  * 
285  *   smbrun calling convention --
286  *     INPUT: <oldest_entry_cmd> <log name> <policy handle>
287  *     OUTPUT: If there are entries in the event log, the index of the
288  *             oldest entry. Must be 1 or greater.
289  *             If there are no entries in the log, returns a 0
290  */
291
292 static BOOL get_oldest_entry_hook(EventlogInfo *info)
293 {
294         char *cmd = lp_eventlog_oldest_record_cmd();
295         char **qlines;
296         pstring command;
297         int numlines = 0;
298         int ret;
299         int fd = -1;
300
301         if ( !cmd || !*cmd ) {
302                 DEBUG(0, ("Must define an \"eventlog oldest record command\" entry in the config.\n"));
303                 return False;
304         }
305
306         pstr_sprintf( command, "%s \"%s\"", cmd, info->logname );
307
308         DEBUG(10, ("Running [%s]\n", command));
309         ret = smbrun(command, &fd);
310         DEBUGADD(10, ("returned [%d]\n", ret));
311
312         if(ret != 0) {
313                 if(fd != -1) {
314                         close(fd);
315                 }
316                 return False;
317         }
318
319         qlines = fd_lines_load(fd, &numlines);
320         DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
321         close(fd);
322
323         if(numlines) {
324                 DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
325                 sscanf(qlines[0], "%d", &(info->oldest_entry));
326                 file_lines_free(qlines);
327                 return True;
328         }
329
330         file_lines_free(qlines);
331         return False;
332 }
333
334 /********************************************************************
335 ********************************************************************/
336 /**
337  * Callout to close the specified event log
338  * 
339  *   smbrun calling convention --
340  *     INPUT: <close_cmd> <log name> <policy handle>
341  *     OUTPUT: the string "SUCCESS" if the command succeeded
342  *             no such string if there was a failure.
343  */
344
345 static BOOL close_eventlog_hook(EventlogInfo *info)
346 {
347         char *cmd = lp_eventlog_close_cmd();
348         char **qlines;
349         pstring command;
350         int numlines = 0;
351         int ret;
352         int fd = -1;
353
354         if ( !cmd || !*cmd ) {
355                 DEBUG(0, ("Must define an \"eventlog close command\" entry in the config.\n"));
356                 return False;
357         }
358
359         pstr_sprintf( command, "%s \"%s\"", cmd, info->logname );
360
361         DEBUG(10, ("Running [%s]\n", command));
362         ret = smbrun(command, &fd);
363         DEBUGADD(10, ("returned [%d]\n", ret));
364
365         if(ret != 0) {
366                 if(fd != -1) {
367                         close(fd);
368                 }
369                 return False;
370         }
371
372         qlines = fd_lines_load(fd, &numlines);
373         DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
374         close(fd);
375
376         if(numlines) {
377                 DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
378                 if(0 == strncmp(qlines[0], "SUCCESS", 7)) {
379                         DEBUGADD(10, ("Able to close [%s].\n", info->logname));
380                         file_lines_free(qlines);
381                         return True;
382                 }
383         }
384
385         file_lines_free(qlines);
386         return False;
387 }
388
389 /********************************************************************
390 ********************************************************************/
391
392 static BOOL parse_logentry(char *line, Eventlog_entry *entry, BOOL *eor)
393 {
394         char *start = NULL, *stop = NULL;
395         pstring temp;
396         int temp_len = 0, i;
397  
398         start = line;
399
400         /* empty line signyfiying record delimeter, or we're at the end of the buffer */
401         if(start == NULL || strlen(start) == 0) {
402                 DEBUG(6, ("parse_logentry: found end-of-record indicator.\n"));
403                 *eor = True;
404                 return True;
405         }
406         if(!(stop = strchr(line, ':'))) {
407                 return False;
408         }
409     
410         DEBUG(6, ("parse_logentry: trying to parse [%s].\n", line));
411
412         if(0 == strncmp(start, "LEN", stop - start)) {
413                 /* This will get recomputed later anyway -- probably not necessary */
414                 entry->record.length = atoi(stop + 1);
415         } else if(0 == strncmp(start, "RS1", stop - start)) {
416                 /* For now all these reserved entries seem to have the same value,
417                    which can be hardcoded to int(1699505740) for now */
418                 entry->record.reserved1 = atoi(stop + 1);
419         } else if(0 == strncmp(start, "RCN", stop - start)) {
420                 entry->record.record_number = atoi(stop + 1);
421         } else if(0 == strncmp(start, "TMG", stop - start)) {
422                 entry->record.time_generated = atoi(stop + 1);
423         } else if(0 == strncmp(start, "TMW", stop - start)) {
424                 entry->record.time_written = atoi(stop + 1);
425         } else if(0 == strncmp(start, "EID", stop - start)) {
426                 entry->record.event_id = atoi(stop + 1);
427         } else if(0 == strncmp(start, "ETP", stop - start)) {
428                 if(strstr(start, "ERROR")) {
429                         entry->record.event_type = EVENTLOG_ERROR_TYPE;
430                 } else if(strstr(start, "WARNING")) {
431                         entry->record.event_type = EVENTLOG_WARNING_TYPE;
432                 } else if(strstr(start, "INFO")) {
433                         entry->record.event_type = EVENTLOG_INFORMATION_TYPE;
434                 } else if(strstr(start, "AUDIT_SUCCESS")) {
435                         entry->record.event_type = EVENTLOG_AUDIT_SUCCESS;
436                 } else if(strstr(start, "AUDIT_FAILURE")) {
437                         entry->record.event_type = EVENTLOG_AUDIT_FAILURE;
438                 } else if(strstr(start, "SUCCESS")) {
439                         entry->record.event_type = EVENTLOG_SUCCESS;
440                 } else {
441                         /* some other eventlog type -- currently not defined in MSDN docs, so error out */
442                         return False;
443                 }
444         }
445 /*
446   else if(0 == strncmp(start, "NST", stop - start))
447   {
448   entry->record.num_strings = atoi(stop + 1);
449   }
450 */
451         else if(0 == strncmp(start, "ECT", stop - start)) {
452                 entry->record.event_category = atoi(stop + 1);
453         } else if(0 == strncmp(start, "RS2", stop - start)) {
454                 entry->record.reserved2 = atoi(stop + 1);
455         } else if(0 == strncmp(start, "CRN", stop - start)) {
456                 entry->record.closing_record_number = atoi(stop + 1);
457         } else if(0 == strncmp(start, "USL", stop - start)) {
458                 entry->record.user_sid_length = atoi(stop + 1);
459         } else if(0 == strncmp(start, "SRC", stop - start)) {
460                 memset(temp, 0, sizeof(temp));
461                 stop++;
462                 while(isspace(stop[0])) {
463                         stop++;
464                 }
465                 temp_len = strlen(stop);
466                 strncpy(temp, stop, temp_len);
467                 rpcstr_push((void *)(entry->data_record.source_name), temp, 
468                             sizeof(entry->data_record.source_name), STR_TERMINATE);
469                 entry->data_record.source_name_len = (strlen_w(entry->data_record.source_name)* 2) + 2;
470         } else if(0 == strncmp(start, "SRN", stop - start)) {
471                 memset(temp, 0, sizeof(temp));
472                 stop++;
473                 while(isspace(stop[0])) {
474                         stop++; 
475                 }
476                 temp_len = strlen(stop);
477                 strncpy(temp, stop, temp_len);
478                 rpcstr_push((void *)(entry->data_record.computer_name), temp,
479                             sizeof(entry->data_record.computer_name), STR_TERMINATE);
480                 entry->data_record.computer_name_len = (strlen_w(entry->data_record.computer_name)* 2) + 2;
481         } else if(0 == strncmp(start, "SID", stop - start)) {
482                 memset(temp, 0, sizeof(temp));
483                 stop++;
484                 while(isspace(stop[0])) {
485                         stop++;
486                 }
487                 temp_len = strlen(stop);
488                 strncpy(temp, stop, temp_len);
489                 rpcstr_push((void *)(entry->data_record.sid), temp,
490                             sizeof(entry->data_record.sid), STR_TERMINATE);
491                 entry->record.user_sid_length = (strlen_w(entry->data_record.sid) * 2) + 2;
492         } else if(0 == strncmp(start, "STR", stop - start)) {
493                 /* skip past initial ":" */
494                 stop++;
495                 /* now skip any other leading whitespace */
496                 while(isspace(stop[0])) {
497                         stop++;
498                 }
499                 temp_len = strlen(stop);
500                 memset(temp, 0, sizeof(temp));
501                 strncpy(temp, stop, temp_len);
502                 rpcstr_push((void *)(entry->data_record.strings + entry->data_record.strings_len),
503                             temp,
504                             sizeof(entry->data_record.strings) - entry->data_record.strings_len, 
505                             STR_TERMINATE);
506                 entry->data_record.strings_len += temp_len + 1;
507                 fprintf(stderr, "Dumping strings:\n");
508                 for(i = 0; i < entry->data_record.strings_len; i++) {
509                         fputc((char)entry->data_record.strings[i], stderr);
510                 }
511                 fprintf(stderr, "\nDone\n");
512                 entry->record.num_strings++;
513         } else if(0 == strncmp(start, "DAT", stop - start)) {
514                 /* Now that we're done processing the STR data, adjust the length to account for
515                    unicode, then proceed with the DAT data. */
516                 entry->data_record.strings_len *= 2;
517                 /* skip past initial ":" */
518                 stop++;
519                 /* now skip any other leading whitespace */
520                 while(isspace(stop[0])) {
521                         stop++;
522                 }
523                 entry->data_record.user_data_len = strlen(stop);
524                 memset(entry->data_record.user_data, 0, sizeof(entry->data_record.user_data));
525                 if(entry->data_record.user_data_len > 0) {
526                         /* copy no more than the first 1024 bytes */
527                         if(entry->data_record.user_data_len > sizeof(entry->data_record.user_data))
528                                 entry->data_record.user_data_len = sizeof(entry->data_record.user_data);
529                         memcpy(entry->data_record.user_data, stop, entry->data_record.user_data_len);
530                 }
531         } else {
532                 /* some other eventlog entry -- not implemented, so dropping on the floor */
533                 DEBUG(10, ("Unknown entry [%s]. Ignoring.\n", line));
534                 /* For now return true so that we can keep on parsing this mess. Eventually
535                    we will return False here. */
536                 return True;
537         }
538         return True;
539 }
540
541 /********************************************************************
542 ********************************************************************/
543
544 /**
545  * Callout to read entries from the specified event log
546  *
547  *   smbrun calling convention --
548  *     INPUT: <read_cmd> <log name> <direction> <starting record> <buffer size> <policy handle>
549  *            where direction is either "forward" or "backward", the starting record is somewhere
550  *            between the oldest_record and oldest_record+num_records, and the buffer size is the
551  *            maximum size of the buffer that the client can accomodate.
552  *     OUTPUT: A buffer containing a set of entries, one to a line, of the format:
553  *             Multiple log entries can be contained in the buffer, delimited by an empty line
554  *               line type:line data
555  *             These are the allowed line types:
556  *               RS1:(uint32) - reserved. All M$ entries seem to have int(1699505740) for now
557  *               RCN:(uint32) - record number of the record, however it may be calculated by the script
558  *               TMG:(uint32) - time generated, seconds since January 1, 1970, 0000 UTC
559  *               TMW:(uint32) - time written, seconds since January 1, 1970, 0000 UTC
560  *               EID:(uint32) - eventlog source defined event identifier. If there's a stringfile for the event, it is an index into that
561  *               ETP:(uint16) - eventlog type - one of ERROR, WARNING, INFO, AUDIT_SUCCESS, AUDIT_FAILURE
562  *               ECT:(uint16) - event category - depends on the eventlog generator... 
563  *               RS2:(uint16) - reserved, make it 0000
564  *               CRN:(uint32) - reserved, make it 00000000 for now
565  *               USL:(uint32) - user SID length. No sid? Make this 0. Must match SID below
566  *               SRC:[(uint8)] - Name of the source, for example ccPwdSvc, in hex bytes. Can not be multiline.
567  *               SRN:[(uint8)] - Name of the computer on which this is generated, the short hostname usually.
568  *               SID:[(uint8)] - User sid if one exists. Must be present even if there is no SID.
569  *               STR:[(uint8)] - String data. One string per line. Multiple strings can be specified using consecutive "STR" lines,
570  *                               up to a total aggregate string length of 1024 characters.
571  *               DAT:[(uint8)] - The user-defined data portion of the event log. Can not be multiple lines.
572  *               <empty line>  - end-of-record indicator 
573  */
574
575 static BOOL read_eventlog_hook(EventlogInfo *info, Eventlog_entry *entry, 
576                                          const char *direction, int starting_record, 
577                                          int buffer_size, BOOL *eof,
578                                          char ***buffer, int *numlines)
579 {
580         char *cmd = lp_eventlog_read_cmd();
581         pstring command;
582         int ret;
583         int fd = -1;
584
585         if ( !info )
586                 return False;
587
588         if ( !cmd || !*cmd ) {
589                 DEBUG(0, ("Must define an \"eventlog read command\" entry in the config.\n"));
590                 return False;
591         }
592
593         pstr_sprintf( command, "%s \"%s\" %s %d %d",
594                  cmd, info->logname, direction, starting_record, buffer_size );
595
596         *numlines = 0;
597
598         DEBUG(10, ("Running [%s]\n", command));
599         ret = smbrun(command, &fd);
600         DEBUGADD(10, ("returned [%d]\n", ret));
601
602         if(ret != 0) {
603                 if(fd != -1) {
604                         close(fd);
605                 }
606                 return False;
607         }
608
609         *buffer = fd_lines_load(fd, numlines);
610         DEBUGADD(10, ("Lines returned = [%d]\n", *numlines));
611         close(fd);
612     
613         if(*numlines) {
614                 /*
615                   for(i = 0; i < numlines; i++)
616                   {
617                   DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i]));
618                   parse_logentry(qlines[i], entry);
619                   }
620                   file_lines_free(qlines);
621                 */
622                 *eof = False;
623                 return True;
624         }
625         *eof = True;
626
627 /*    file_lines_free(qlines);*/
628         return False;
629 }
630
631 /********************************************************************
632 ********************************************************************/
633
634 static Eventlog_entry *read_package_entry(prs_struct *ps,
635                                                     EVENTLOG_Q_READ_EVENTLOG *q_u,
636                                                     EVENTLOG_R_READ_EVENTLOG *r_u,
637                                                     Eventlog_entry *entry)
638 {
639         uint8 *offset;
640         Eventlog_entry *ee_new = NULL;
641
642         ee_new = PRS_ALLOC_MEM(ps, Eventlog_entry, 1);
643         if(ee_new == NULL) {
644                 return NULL;
645         }
646
647         entry->data_record.sid_padding = ((4 - ((entry->data_record.source_name_len 
648                                                  + entry->data_record.computer_name_len) % 4)) %4);
649         entry->data_record.data_padding = (4 - ((entry->data_record.strings_len 
650                                                  + entry->data_record.user_data_len) % 4)) % 4;
651         entry->record.length = sizeof(Eventlog_record);
652         entry->record.length += entry->data_record.source_name_len;
653         entry->record.length += entry->data_record.computer_name_len;
654         if(entry->record.user_sid_length == 0) {
655                 /* Should not pad to a DWORD boundary for writing out the sid if there is
656                    no SID, so just propagate the padding to pad the data */
657                 entry->data_record.data_padding += entry->data_record.sid_padding;
658                 entry->data_record.sid_padding = 0;
659         }
660         DEBUG(10, ("sid_padding is [%d].\n", entry->data_record.sid_padding));
661         DEBUG(10, ("data_padding is [%d].\n", entry->data_record.data_padding));
662
663         entry->record.length += entry->data_record.sid_padding;
664         entry->record.length += entry->record.user_sid_length;
665         entry->record.length += entry->data_record.strings_len;
666         entry->record.length += entry->data_record.user_data_len;
667         entry->record.length += entry->data_record.data_padding;
668         /* need another copy of length at the end of the data */
669         entry->record.length += sizeof(entry->record.length);
670         DEBUG(10, ("entry->record.length is [%d].\n", entry->record.length));
671         entry->data = PRS_ALLOC_MEM(ps, uint8, entry->record.length - sizeof(Eventlog_record) - sizeof(entry->record.length));
672         if(entry->data == NULL) {
673                 return NULL;
674         }
675         offset = entry->data;
676         memcpy(offset, &(entry->data_record.source_name), entry->data_record.source_name_len);
677         offset += entry->data_record.source_name_len;
678         memcpy(offset, &(entry->data_record.computer_name), entry->data_record.computer_name_len);
679         offset += entry->data_record.computer_name_len;
680         /* SID needs to be DWORD-aligned */
681         offset += entry->data_record.sid_padding;
682         entry->record.user_sid_offset = sizeof(Eventlog_record) + (offset - entry->data);
683         memcpy(offset, &(entry->data_record.sid), entry->record.user_sid_length);
684         offset += entry->record.user_sid_length;
685         /* Now do the strings */
686         entry->record.string_offset = sizeof(Eventlog_record) + (offset - entry->data);
687         memcpy(offset, &(entry->data_record.strings), entry->data_record.strings_len);
688         offset += entry->data_record.strings_len;
689         /* Now do the data */
690         entry->record.data_length = entry->data_record.user_data_len;
691         entry->record.data_offset = sizeof(Eventlog_record) + (offset - entry->data);
692         memcpy(offset, &(entry->data_record.user_data), entry->data_record.user_data_len);
693         offset += entry->data_record.user_data_len;
694
695         memcpy(&(ee_new->record), &entry->record, sizeof(Eventlog_record));
696         memcpy(&(ee_new->data_record), &entry->data_record, sizeof(Eventlog_data_record));
697         ee_new->data = entry->data;
698
699         return ee_new;
700 }
701
702 /********************************************************************
703 ********************************************************************/
704
705 static BOOL add_record_to_resp(EVENTLOG_R_READ_EVENTLOG *r_u, Eventlog_entry *ee_new)
706 {
707         Eventlog_entry *insert_point;
708
709         insert_point=r_u->entry;
710
711         if (NULL == insert_point) {
712                 r_u->entry = ee_new;
713                 ee_new->next = NULL;
714         } else {
715                 while ((NULL != insert_point->next)) {
716                         insert_point=insert_point->next;
717                 }
718                 ee_new->next = NULL;
719                 insert_point->next = ee_new;
720         }
721         r_u->num_records++; 
722         r_u->num_bytes_in_resp += ee_new->record.length;
723
724         return True;
725 }
726
727 /********************************************************************
728 ********************************************************************/
729
730 /**
731  * Callout to clear (and optionally backup) a specified event log
732  *
733  *   smbrun calling convention --
734  *     INPUT:  <clear_eventlog_cmd> <log name> <policy handle>
735  *     OUTPUT: A single line with the string "SUCCESS" if the command succeeded.
736  *             Otherwise it is assumed to have failed
737  *
738  *     INPUT:  <clear_eventlog_cmd> <log name> <backup file> <policy handle>
739  *     OUTPUT: A single line with the string "SUCCESS" if the command succeeded.
740  *             Otherwise it is assumed to have failed
741  *             The given log is copied to that location on the server. See comments for
742  *               eventlog_io_q_clear_eventlog for info about odd file name behavior
743  */
744
745 static BOOL clear_eventlog_hook(EventlogInfo *info, pstring backup_file_name)
746 {
747         char *cmd = lp_eventlog_clear_cmd();
748         char **qlines;
749         pstring command;
750         int numlines = 0;
751         int ret;
752         int fd = -1;
753
754         if ( !cmd || !*cmd ) {
755                 DEBUG(0, ("Must define an \"eventlog clear command\" entry in the config.\n"));
756                 return False;
757         }
758
759         if ( strlen(backup_file_name) ) 
760                 pstr_sprintf( command, "%s \"%s\" \"%s\"", cmd, info->logname, backup_file_name );
761         else 
762                 pstr_sprintf( command, "%s \"%s\"", cmd, info->logname );
763
764         DEBUG(10, ("Running [%s]\n", command));
765         ret = smbrun(command, &fd);
766         DEBUGADD(10, ("returned [%d]\n", ret));
767
768         if(ret != 0) {
769                 if(fd != -1) {
770                         close(fd);
771                 }
772                 return False;
773         }
774
775         qlines = fd_lines_load(fd, &numlines);
776         DEBUGADD(10, ("Lines returned = [%d]\n", numlines));
777         close(fd);
778
779         if(numlines) {
780                 DEBUGADD(10, ("Line[0] = [%s]\n", qlines[0]));
781                 if(0 == strncmp(qlines[0], "SUCCESS", strlen("SUCCESS"))) {
782                         DEBUGADD(10, ("Able to clear [%s].\n", info->logname));
783                         file_lines_free(qlines);
784                         return True;
785                 }
786         }
787
788         file_lines_free(qlines);
789         return False;
790 }
791
792 /*******************************************************************
793 *******************************************************************/
794
795 WERROR _eventlog_open_eventlog(pipes_struct *p, EVENTLOG_Q_OPEN_EVENTLOG *q_u, EVENTLOG_R_OPEN_EVENTLOG *r_u)
796 {
797         EventlogInfo *info = NULL;
798         fstring str;
799     
800         if ( !(info = TALLOC_ZERO_P(NULL, EventlogInfo)) ) 
801                 return WERR_NOMEM;
802
803         fstrcpy( str, global_myname() );
804         if ( q_u->servername.string ) {
805                 rpcstr_pull( str, q_u->servername.string->buffer, 
806                         sizeof(str), q_u->servername.string->uni_str_len*2, 0 );
807         } 
808         info->servername = talloc_strdup( info, str );
809
810         fstrcpy( str, "Application" );
811         if ( q_u->logname.string ) {
812                 rpcstr_pull( str, q_u->logname.string->buffer, 
813                         sizeof(str), q_u->logname.string->uni_str_len*2, 0 );
814         } 
815         info->logname = talloc_strdup( info, str );
816
817         DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the server name.\n", info->servername));
818         DEBUG(10, ("_eventlog_open_eventlog: Using [%s] as the source log file.\n", info->logname));
819
820         if ( !create_policy_hnd(p, &r_u->handle, free_eventlog_info, (void *)info) ) {
821                 free_eventlog_info(info);
822                 return WERR_NOMEM;
823         }
824         
825         if ( !(open_eventlog_hook(info)) ) {
826                 close_policy_hnd(p, &r_u->handle);
827                 return WERR_BADFILE;
828         }
829         
830         return WERR_OK;
831 }
832
833 /********************************************************************
834 ********************************************************************/
835
836 WERROR _eventlog_clear_eventlog(pipes_struct *p, EVENTLOG_Q_CLEAR_EVENTLOG *q_u, EVENTLOG_R_CLEAR_EVENTLOG *r_u)
837 {
838         EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle);
839         pstring backup_file_name;
840
841         pstrcpy( backup_file_name, "" );
842
843         if ( q_u->backupfile.string ) 
844                 unistr2_to_ascii(backup_file_name, q_u->backupfile.string, sizeof(backup_file_name));
845
846         DEBUG(10, ("_eventlog_clear_eventlog: Using [%s] as the backup file name for log [%s].",
847                    backup_file_name, info->logname));
848
849         if ( !(clear_eventlog_hook(info, backup_file_name)) )
850                 return WERR_BADFILE;
851
852         return WERR_OK;
853 }
854
855 /********************************************************************
856 ********************************************************************/
857
858 WERROR _eventlog_close_eventlog(pipes_struct *p, EVENTLOG_Q_CLOSE_EVENTLOG *q_u, EVENTLOG_R_CLOSE_EVENTLOG *r_u)
859 {
860         EventlogInfo *info = find_eventlog_info_by_hnd(p,&q_u->handle);
861
862         if ( !(close_eventlog_hook(info)) )
863                 return WERR_BADFILE;
864
865         if ( !(close_policy_hnd(p, &q_u->handle)) ) {
866                 return WERR_BADFID;
867         }
868
869         return WERR_OK;
870 }
871
872 /********************************************************************
873 ********************************************************************/
874    
875 WERROR _eventlog_read_eventlog(pipes_struct *p, EVENTLOG_Q_READ_EVENTLOG *q_u, EVENTLOG_R_READ_EVENTLOG *r_u)
876 {
877         EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle);
878         Eventlog_entry entry, *ee_new;
879         BOOL eof = False, eor = False;
880         const char *direction = "";
881         uint32 num_records_read = 0;
882         prs_struct *ps;
883         int numlines, i;
884         char **buffer;
885
886         info->flags = q_u->flags;
887         ps = &p->out_data.rdata;
888
889         if ( info->flags & EVENTLOG_FORWARDS_READ ) 
890                 direction = "forward";
891         else if ( info->flags & EVENTLOG_BACKWARDS_READ )
892                 direction = "backward";
893
894         if ( !(read_eventlog_hook(info, &entry, direction, q_u->offset, q_u->max_read_size, &eof, &buffer, &numlines)) ) {
895                 if(eof == False) {
896                         return WERR_NOMEM;
897                 }
898         }
899
900         if(numlines > 0) {
901                 ZERO_STRUCT(entry);
902                 for(i = 0; i < numlines; i++) {
903                         num_records_read = r_u->num_records;
904                         DEBUGADD(10, ("Line[%d] = [%s]\n", i, buffer[i]));
905                         parse_logentry(buffer[i], &entry, &eor);
906                         if(eor == True) {
907                                 /* package ee_new entry */
908                                 if((ee_new = read_package_entry(ps, q_u, r_u, &entry)) == NULL) {
909                                         SAFE_FREE(buffer);
910                                         return WERR_NOMEM;
911                                 }
912                                 /* Now see if there is enough room to add */
913                                 if(r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size) {
914                                         r_u->bytes_in_next_record = ee_new->record.length;
915                                         /* response would be too big to fit in client-size buffer */
916                                         break;
917                                 }
918                                 add_record_to_resp(r_u, ee_new);
919                                 ZERO_STRUCT(entry);
920                                 eor=False;
921                                 num_records_read = r_u->num_records - num_records_read;
922                                 DEBUG(10, ("_eventlog_read_eventlog: read [%d] records for a total of [%d] records using [%d] bytes out of a max of [%d].\n",
923                                            num_records_read,
924                                            r_u->num_records,
925                                            r_u->num_bytes_in_resp,
926                                            q_u->max_read_size));
927                         }
928                 }
929                 SAFE_FREE(buffer);
930         }
931
932         return WERR_OK;
933 }
934
935 /********************************************************************
936 ********************************************************************/
937
938 WERROR _eventlog_get_oldest_entry(pipes_struct *p, EVENTLOG_Q_GET_OLDEST_ENTRY *q_u, EVENTLOG_R_GET_OLDEST_ENTRY *r_u)
939 {
940         EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle);
941
942         if ( !(get_oldest_entry_hook(info)) ) 
943                 return WERR_BADFILE;
944
945         r_u->oldest_entry = info->oldest_entry;
946
947         return WERR_OK;
948 }
949
950 /********************************************************************
951 ********************************************************************/
952
953 WERROR _eventlog_get_num_records(pipes_struct *p, EVENTLOG_Q_GET_NUM_RECORDS *q_u, EVENTLOG_R_GET_NUM_RECORDS *r_u)
954 {
955         EventlogInfo *info = find_eventlog_info_by_hnd(p, &q_u->handle);
956
957         if ( !(get_num_records_hook(info)) )
958                 return WERR_BADFILE;
959
960         r_u->num_records = info->num_records;
961
962         return WERR_OK;
963 }
964