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