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