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