Final updates for 0.9.14.
[metze/wireshark/wip.git] / packet-dcerpc-atsvc.c
1 /* packet-dcerpc-atsvc.c
2  * Routines for SMB \pipe\atsvc packet disassembly
3  * Copyright 2003 Jean-Baptiste Marchand <jbm@hsc.fr>
4  *
5  * $Id: packet-dcerpc-atsvc.c,v 1.3 2003/06/26 04:30:26 tpot Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <glib.h>
32 #include <epan/packet.h>
33 #include "packet-dcerpc.h"
34 #include "packet-dcerpc-nt.h"
35 #include "packet-dcerpc-atsvc.h"
36 #include "smb.h"
37
38
39 static int proto_dcerpc_atsvc = -1;
40
41 static int hf_atsvc_server = -1;
42 static int hf_atsvc_command = -1;
43 static int hf_atsvc_opnum = -1;
44 static int hf_atsvc_rc = -1;
45 static int hf_atsvc_job_id = -1;
46 static int hf_atsvc_job_time = -1;
47 static int hf_atsvc_job_days_of_month = -1;
48 static int hf_atsvc_job_days_of_week = -1;
49 static int hf_atsvc_job_flags = -1;
50 static int hf_atsvc_min_job_id = -1;
51 static int hf_atsvc_max_job_id = -1;
52 static int hf_atsvc_job_flags_noninteractive = -1;
53 static int hf_atsvc_job_flags_add_current_date = -1;
54 static int hf_atsvc_job_flags_runs_today = -1;
55 static int hf_atsvc_job_flags_exec_error = -1;
56 static int hf_atsvc_job_flags_run_periodically = -1;
57 static int hf_atsvc_job_enum_hnd = -1;
58 static int hf_atsvc_jobs_count = -1;
59 static int hf_atsvc_enum_handle = -1;
60 static int hf_atsvc_pref_max = -1;
61 static int hf_atsvc_num_entries = -1;
62 static int hf_atsvc_total_entries = -1;
63
64 static gint ett_dcerpc_atsvc = -1;
65 static gint ett_dcerpc_atsvc_job = -1;
66 static gint ett_dcerpc_atsvc_job_flags = -1;
67
68
69 /* 
70 IDL [ uuid(1ff70682-0a51-30e8-076d-740be8cee98b),
71 IDL  version(1.0),
72 IDL  implicit_handle(handle_t rpc_binding)
73 IDL ] interface atsvc
74 */
75
76
77 static e_uuid_t uuid_dcerpc_atsvc = {
78         0x1ff70682, 0x0a51, 0x30e8,
79         { 0x07, 0x6d, 0x74, 0x0b, 0xe8, 0xce, 0xe9, 0x8b }
80 };
81
82 static guint16 ver_dcerpc_atsvc = 1; 
83
84
85 /*
86  IDL typedef struct {
87  IDL   long JobTime;
88  IDL   long DaysOfMonth;
89  IDL   char DaysOfWeek;
90  IDL   char Flags;
91  IDL   [unique] [string] wchar_t *Command;
92  IDL } AT_INFO;
93  */
94
95 static int
96 atsvc_dissect_AT_INFO_fields(tvbuff_t *tvb, int offset,
97         packet_info *pinfo, proto_tree *tree, char *drep)
98 {
99         proto_item *item = NULL;
100         proto_tree *flags_tree = NULL;
101         guint32 job_time;
102         guint8 job_flags;
103         guint8 job_hour, job_min, job_sec;
104         guint16 job_msec;
105         dcerpc_info *di = (dcerpc_info *) pinfo->private_data;
106
107         offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
108                         0, &job_time);
109
110         job_hour = job_time / 3600000;
111         job_min = (job_time - job_hour * 3600000) / 60000;
112         job_sec = (job_time - (job_hour * 3600000) - (job_min * 60000)) / 1000;
113         job_msec = (job_time - (job_hour * 3600000) - (job_min * 60000) - (job_sec * 1000));
114
115         proto_tree_add_uint_format(tree, hf_atsvc_job_time, tvb, offset - 4,
116                         4, job_time, "Time: %02d:%02d:%02d:%03d", job_hour, job_min, job_sec, job_msec);
117
118         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
119                         hf_atsvc_job_days_of_month, NULL);
120
121         offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, drep,
122                         hf_atsvc_job_days_of_week, NULL);
123
124         offset = dissect_ndr_uint8(tvb, offset, pinfo, NULL, drep,
125                         0, &job_flags);
126
127         item = proto_tree_add_text(tree, tvb, offset-1, 1, "Flags: 0x%02x", job_flags);
128         flags_tree = proto_item_add_subtree(item, ett_dcerpc_atsvc_job_flags);
129
130         if (flags_tree) {
131
132 #define JOB_RUN_PERIODICALLY 0x01
133 #define JOB_EXEC_ERROR 0x02
134 #define JOB_RUNS_TODAY 0x04
135 #define JOB_ADD_CURRENT_DATE 0x08
136 #define JOB_NONINTERACTIVE 0x10
137
138                 if (di->call_data->opnum == ATSVC_JOB_ADD) { 
139
140                         if (job_flags & JOB_RUN_PERIODICALLY) {
141                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_run_periodically,
142                                                 tvb, offset-1, 1, job_flags);
143                         }
144                         else {
145                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_run_periodically,
146                                                 tvb, offset-1, 1, 0);
147                         }
148
149
150                         if (job_flags & JOB_ADD_CURRENT_DATE) {
151                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_add_current_date,
152                                                 tvb, offset-1, 1, job_flags);
153                         }
154                         else {
155                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_add_current_date,
156                                                 tvb, offset-1, 1, 0);
157                         }
158
159
160                         if (job_flags & JOB_NONINTERACTIVE) {
161                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_noninteractive,
162                                                 tvb, offset-1, 1, job_flags);
163                         }
164                         else {
165                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_noninteractive,
166                                                 tvb, offset-1, 1, job_flags);
167                         }
168
169                 }
170
171                 if ((di->call_data->opnum == ATSVC_JOB_GETINFO) 
172                                 || (di->call_data->opnum == ATSVC_JOB_ENUM)) {
173
174
175                         if (job_flags & JOB_RUN_PERIODICALLY) {
176                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_run_periodically,
177                                                 tvb, offset-1, 1, job_flags);
178                         }
179                         else {
180                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_run_periodically,
181                                                 tvb, offset-1, 1, 0);
182                         }
183
184
185                         if (job_flags & JOB_EXEC_ERROR) {
186                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_exec_error,
187                                                 tvb, offset-1, 1, job_flags);
188                         }
189                         else {
190                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_exec_error,
191                                                 tvb, offset-1, 1, 0);
192                         }
193
194
195                         if (job_flags & JOB_RUNS_TODAY) {
196                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_runs_today,
197                                                 tvb, offset-1, 1, job_flags);
198                         }
199                         else {
200                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_runs_today,
201                                                 tvb, offset-1, 1, 0);
202                         }
203
204                         if (job_flags & JOB_NONINTERACTIVE) {
205                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_noninteractive,
206                                                 tvb, offset-1, 1, job_flags);
207                         }
208                         else {
209                                 proto_tree_add_boolean(flags_tree, hf_atsvc_job_flags_noninteractive,
210                                                 tvb, offset-1, 1, job_flags);
211                         }
212
213                 }
214
215         }
216
217         offset = dissect_ndr_str_pointer_item(tvb, offset, pinfo, tree, drep,
218                         NDR_POINTER_UNIQUE, "Command", hf_atsvc_command, 0);
219
220         return offset;
221 }
222
223 static int
224 atsvc_dissect_AT_INFO(tvbuff_t *tvb, int offset,
225         packet_info *pinfo, proto_tree *tree, char *drep)
226 {
227         proto_item *item = NULL;
228         proto_tree *subtree = NULL;
229
230         if (tree) {
231                 item = proto_tree_add_text(tree, tvb, offset, -1, "Job");
232                 subtree = proto_item_add_subtree(item, ett_dcerpc_atsvc_job);
233         }
234
235         offset = atsvc_dissect_AT_INFO_fields(tvb, offset, pinfo, subtree, drep);
236
237         return offset;
238 }
239
240
241
242 /*
243  IDL long NetrJobAdd(
244  IDL       [in] [unique] [string] wchar_t *Servername,
245  IDL       [in] [ref] AT_INFO *element_22,
246  IDL      [out] [ref] long *JobId
247  IDL );
248  */
249
250 static int
251 atsvc_dissect_add_rqst(tvbuff_t *tvb, int offset,
252         packet_info *pinfo, proto_tree *tree, char *drep)
253 {
254         offset = dissect_ndr_str_pointer_item(tvb, offset, pinfo, tree, drep,
255                         NDR_POINTER_UNIQUE, "Server", hf_atsvc_server, 0);
256
257         offset = atsvc_dissect_AT_INFO(tvb, offset, pinfo, tree, drep);
258
259         return offset;
260 }
261
262 static int
263 atsvc_dissect_add_reply(tvbuff_t *tvb, int offset,
264         packet_info *pinfo, proto_tree *tree, char *drep)
265 {
266         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
267                         hf_atsvc_job_id, NULL);
268         
269         offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, 
270                         hf_atsvc_rc, NULL);
271
272         return offset;
273 }
274
275
276 /*
277  IDL long NetrJobDel(
278  IDL       [in] [unique] [string] wchar_t *Servername,
279  IDL       [in] long MinJobId,
280  IDL       [in] long MaxJobId,
281  IDL );
282  */
283
284 static int
285 atsvc_dissect_del_rqst(tvbuff_t *tvb, int offset,
286         packet_info *pinfo, proto_tree *tree, char *drep)
287 {
288         offset = dissect_ndr_str_pointer_item(tvb, offset, pinfo, tree, drep,
289                         NDR_POINTER_UNIQUE, "Server", hf_atsvc_server, 0);
290
291         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
292                         hf_atsvc_min_job_id, NULL);
293
294         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
295                         hf_atsvc_max_job_id, NULL);
296
297         return offset;
298 }
299
300 static int
301 atsvc_dissect_del_reply(tvbuff_t *tvb, int offset,
302         packet_info *pinfo, proto_tree *tree, char *drep)
303 {
304         offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, 
305                         hf_atsvc_rc, NULL);
306         return offset;
307 }
308
309
310 /*
311  IDL typedef struct {
312  IDL   long JobId;
313  IDL   long JobTime;
314  IDL   long DaysOfMonth;
315  IDL   char DaysOfWeek;
316  IDL   char Flags;
317  IDL   [unique] [string] wchar_t *Command;
318  IDL } AT_ENUM;
319  */
320
321 static int
322 atsvc_dissect_AT_ENUM(tvbuff_t *tvb, int offset,
323         packet_info *pinfo, proto_tree *tree, char *drep)
324 {
325         proto_item *item = NULL;
326         proto_tree *subtree = NULL;
327         guint32 job_id;
328
329         offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep,
330                         0, &job_id);
331
332         if (tree) {
333                 item = proto_tree_add_text(tree, tvb, offset, -1, "Job %d", job_id);
334                 subtree = proto_item_add_subtree(item, ett_dcerpc_atsvc_job);
335         }
336
337         proto_tree_add_uint_format(subtree, hf_atsvc_job_id, tvb, offset - 4,
338                         4, job_id, "Job ID: %d", job_id);
339
340         offset = atsvc_dissect_AT_INFO_fields(tvb, offset, pinfo, subtree, drep);
341
342         return offset;
343 }
344
345
346 static int
347 atsvc_dissect_ENUM_HANDLE(tvbuff_t *tvb, int offset,
348                            packet_info *pinfo, proto_tree *tree,
349                            char *drep)
350 {
351         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
352                               hf_atsvc_enum_handle, 0);
353         return offset;
354
355 }
356
357 static int
358 atsvc_dissect_AT_ENUM_array(tvbuff_t *tvb, int offset,
359                                      packet_info *pinfo, proto_tree *tree,
360                                      char *drep)
361 {
362         offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, drep,
363                         atsvc_dissect_AT_ENUM);
364
365         return offset;
366 }
367
368 /*
369  IDL typedef struct {
370  IDL   long EntriesRead; 
371  IDL   [size_is(EntriesRead)] [unique] AT_ENUM *first_entry;
372  IDL } AT_ENUM_CONTAINER;
373  */
374
375 static int
376 atsvc_dissect_AT_ENUM_CONTAINER(tvbuff_t *tvb, int offset,
377                                      packet_info *pinfo, proto_tree *tree,
378                                      char *drep)
379 {
380         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
381                 hf_atsvc_num_entries, NULL);
382
383         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
384                 atsvc_dissect_AT_ENUM_array, NDR_POINTER_UNIQUE,
385                 "AT_ENUM array:", -1);
386
387         return offset;
388 }
389
390
391 /*
392  IDL long NetrJobEnum(
393  IDL       [in] [unique] [string] wchar_t *Servername,
394  IDL   [in,out] [ref] AT_ENUM_CONTAINER *PointerToBuffer,
395  IDL       [in] long PreferredMaximumLength,
396  IDL      [out] [ref] long *TotalEntries,
397  IDL   [in,out] [unique] long *ResumeHandle
398  IDL );
399  */
400
401 static int
402 atsvc_dissect_enum_rqst(tvbuff_t *tvb, int offset,
403         packet_info *pinfo, proto_tree *tree, char *drep)
404 {
405         offset = dissect_ndr_str_pointer_item(tvb, offset, pinfo, tree, drep,
406                         NDR_POINTER_UNIQUE, "Server", hf_atsvc_server, 0);
407
408         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
409                         atsvc_dissect_AT_ENUM_CONTAINER,
410                         NDR_POINTER_REF, "Job list", -1);
411
412         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, 
413                         hf_atsvc_pref_max, 0);
414
415         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep, 
416                                      atsvc_dissect_ENUM_HANDLE,
417                                      NDR_POINTER_UNIQUE, "Enum Handle", -1);
418
419         return offset;
420 }
421
422 static int
423 atsvc_dissect_enum_reply(tvbuff_t *tvb, int offset,
424         packet_info *pinfo, proto_tree *tree, char *drep)
425 {
426         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
427                         atsvc_dissect_AT_ENUM_CONTAINER,
428                         NDR_POINTER_REF, "Job list", -1);
429
430         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
431                                     hf_atsvc_total_entries, 0);
432
433         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep, 
434                                      atsvc_dissect_ENUM_HANDLE,
435                                      NDR_POINTER_UNIQUE, "Enum Handle", -1);
436
437         offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, 
438                         hf_atsvc_rc, NULL);
439
440         return offset;
441 }
442
443
444 /*
445  IDL long NetrJobGetInfo(
446  IDL       [in] [unique] [string] wchar_t *Servername,
447  IDL       [in] long JobId,
448  IDL      [out] [ref] AT_INFO **PointerToBuffer
449  IDL );
450  */
451
452 static int
453 atsvc_dissect_getinfo_rqst(tvbuff_t *tvb, int offset,
454         packet_info *pinfo, proto_tree *tree, char *drep)
455 {
456         offset = dissect_ndr_str_pointer_item(tvb, offset, pinfo, tree, drep,
457                         NDR_POINTER_UNIQUE, "Server", hf_atsvc_server, 0);
458
459         offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
460                         hf_atsvc_job_id, NULL);
461
462         return offset;
463 }
464
465 static int
466 atsvc_dissect_getinfo_reply(tvbuff_t *tvb, int offset,
467         packet_info *pinfo, proto_tree *tree, char *drep)
468 {
469         offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
470                         atsvc_dissect_AT_INFO, NDR_POINTER_UNIQUE,
471                         "Job info", -1);
472
473         offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, 
474                         hf_atsvc_rc, NULL);
475
476         return offset;
477 }
478
479 static dcerpc_sub_dissector dcerpc_atsvc_dissectors[] = {
480         { ATSVC_JOB_ADD, "NetrJobAdd", atsvc_dissect_add_rqst, atsvc_dissect_add_reply },
481         { ATSVC_JOB_DEL, "NetrJobDel", atsvc_dissect_del_rqst, atsvc_dissect_del_reply },
482         { ATSVC_JOB_ENUM, "NetrJobEnum", atsvc_dissect_enum_rqst, atsvc_dissect_enum_reply },
483         { ATSVC_JOB_GETINFO, "NetrJobGetInfo", atsvc_dissect_getinfo_rqst, atsvc_dissect_getinfo_reply },
484         { 0, NULL, NULL,  NULL }
485 };
486
487 static const value_string atsvc_job_day_of_month[] = {
488         {       0x00, "n/a" },
489         {       0x01, "01" },
490         {       0x02, "02" },
491         {       0x04, "03" },
492         {       0x08, "04" },
493         {       0x10, "05" },
494         {       0x20, "06" },
495         {       0x40, "07" },
496         {       0x80, "08" },
497         {      0x100, "09" },
498         {      0x200, "10" },
499         {      0x400, "11" },
500         {      0x800, "12" },
501         {     0x1000, "13" },
502         {     0x2000, "14" },
503         {     0x4000, "15" },
504         {     0x8000, "16" },
505         {    0x10000, "17" },
506         {    0x20000, "18" },
507         {    0x40000, "19" },
508         {    0x80000, "20" },
509         {   0x100000, "21" },
510         {   0x200000, "22" },
511         {   0x400000, "23" },
512         {   0x800000, "24" },
513         {  0x1000000, "25" },
514         {  0x2000000, "26" },
515         {  0x4000000, "27" },
516         {  0x8000000, "28" },
517         { 0x10000000, "29" },
518         { 0x20000000, "30" },
519         { 0x40000000, "31" },
520         { 0, NULL }
521 };
522
523
524
525 static const value_string atsvc_job_day_of_week[] = {
526         { 0x00, "n/a" },
527         { 0x01, "Monday" },
528         { 0x02, "Tuesday" },
529         { 0x04, "Wednesday" },
530         { 0x08, "Thursday" },
531         { 0x10, "Friday" },
532         { 0x20, "Saturday" },
533         { 0x40, "Sunday" },
534         { 0, NULL }
535 };
536
537 static const true_false_string tfs_job_flags_type = {
538         "Job runs periodically",
539         "Job runs once"
540 };
541
542 static const true_false_string tfs_job_flags_exec_error = {
543         "Last job execution FAILED",
544         "Last job execution was successful"
545 };
546
547 static const true_false_string tfs_job_flags_runs_today = {
548         "Job is scheduled to execute today",
549         "Job is NOT scheduled to execute today"
550 };
551
552 static const true_false_string tfs_job_flags_add_current_date = {
553         "Job is scheduled relative to current day of month",
554         "Job is NOT scheduled relative to current day of month"
555 };
556
557 static const true_false_string tfs_job_flags_noninteractive = {
558         "Job is NOT interactive", 
559         "Job is interactive"
560 };
561
562 void
563 proto_register_dcerpc_atsvc(void)
564 {
565
566         static hf_register_info hf[] = {
567
568                 { &hf_atsvc_server,
569                     { "Server", "atsvc.server", FT_STRING, BASE_NONE,
570                       NULL, 0x0, "Server Name", HFILL}},
571
572                 { &hf_atsvc_command,
573                     { "Command", "atsvc.command", FT_STRING, BASE_NONE,
574                       NULL, 0x0, "Command to execute", HFILL}},
575
576                 { &hf_atsvc_opnum, 
577                   { "Operation", "atsvc.opnum", FT_UINT16, BASE_DEC,
578                    NULL, 0x0, "Operation", HFILL }},    
579
580                 {&hf_atsvc_rc,
581                   { "Return code", "atsvc.rc", FT_UINT32, BASE_HEX,
582                     VALS(NT_errors), 0x0, "atsvc status code", HFILL }}, 
583
584                 { &hf_atsvc_job_id,
585                     { "Job ID", "atsvc.job_id", FT_UINT32,
586                       BASE_DEC, NULL, 0x0, "Job ID", HFILL}},
587
588                 { &hf_atsvc_job_time,
589                     { "Job time", "atsvc.job_time", FT_UINT32,
590                       BASE_DEC, NULL, 0x0, "Job time", HFILL}},
591
592                 { &hf_atsvc_job_days_of_month,
593                     { "Job day of the month", "atsvc.job_day_of_month", FT_UINT32,
594                       BASE_DEC, VALS(atsvc_job_day_of_month), 0x0, "Job day of the month", HFILL}},
595
596                 { &hf_atsvc_job_days_of_week,
597                     { "Job day of the week", "atsvc.job_day_of_week", FT_UINT8,
598                       BASE_DEC, VALS(atsvc_job_day_of_week), 0x0, "Job day of the week", HFILL}},
599
600                 { &hf_atsvc_job_flags,
601                     { "Job flags", "atsvc.job_flags", FT_UINT8,
602                       BASE_DEC, NULL, 0x0, "Job flags", HFILL}},
603
604                 { &hf_atsvc_min_job_id,
605                     { "Min job ID", "atsvc.min_id", FT_UINT32,
606                       BASE_DEC, NULL, 0x0, "Min job ID", HFILL}},
607
608                 { &hf_atsvc_max_job_id,
609                     { "Max job ID", "atsvc.max_id", FT_UINT32,
610                       BASE_DEC, NULL, 0x0, "Max job ID", HFILL}},
611
612                 { &hf_atsvc_job_flags_run_periodically,
613                     { "Job type", "atsvc.jobs.flags.type", FT_BOOLEAN, 8,
614                         TFS(&tfs_job_flags_type), JOB_RUN_PERIODICALLY, "Job type", HFILL }},
615
616                 { &hf_atsvc_job_flags_exec_error,
617                     { "Last job execution status", "atsvc.jobs.flags.exec_error", FT_BOOLEAN, 8,
618                         TFS(&tfs_job_flags_exec_error), JOB_EXEC_ERROR, "Last job execution status", HFILL }},
619
620                 { &hf_atsvc_job_flags_runs_today,
621                     { "Job schedule", "atsvc.jobs.flags.runs_today", FT_BOOLEAN, 8,
622                         TFS(&tfs_job_flags_runs_today), JOB_RUNS_TODAY, "Job schedule", HFILL }},
623
624                 { &hf_atsvc_job_flags_add_current_date,
625                     { "Job relative to current day of month", "atsvc.jobs.flags.add_current_date", FT_BOOLEAN, 8,
626                         TFS(&tfs_job_flags_add_current_date), JOB_ADD_CURRENT_DATE, "Job relative to current day of month", HFILL }},
627
628                 { &hf_atsvc_job_flags_noninteractive,
629                     { "Job interactive status", "atsvc.jobs.flags.noninteractive", FT_BOOLEAN, 8,
630                         TFS(&tfs_job_flags_noninteractive), JOB_NONINTERACTIVE, "Job interactive status", HFILL }},
631
632                 { &hf_atsvc_job_enum_hnd,
633                     { "Handle", "atsvc.job.hnd", FT_BYTES, BASE_NONE, NULL, 0x0, "Context handle", HFILL }},
634
635                 { &hf_atsvc_jobs_count,
636                     { "Jobs count", "atsvc.jobs_count", FT_UINT32,
637                       BASE_DEC, NULL, 0x0, "Number of jobs", HFILL}},
638
639               { &hf_atsvc_enum_handle,
640                     { "Enumeration handle", "atsvc.enum_hnd", FT_BYTES,
641                       BASE_HEX, NULL, 0x0, "Enumeration Handle", HFILL}},
642
643               { &hf_atsvc_pref_max, 
644                     { "Preferred max length", "atsvc.pref.max.len", FT_INT32,
645                     BASE_DEC, NULL, 0x0, "Preferred max length", HFILL}},
646
647               { &hf_atsvc_num_entries, 
648                    { "Returned entries", "atsvc.num.entries", FT_INT32,
649                    BASE_DEC, NULL, 0x0, "Number of returned entries", HFILL}},
650
651               { &hf_atsvc_total_entries, 
652                    { "Total entries", "atsvc.total.entries", FT_INT32,
653                    BASE_DEC, NULL, 0x0, "Total number of available entries", HFILL}},
654
655         };
656
657         static gint *ett[] = {
658                 &ett_dcerpc_atsvc,
659                 &ett_dcerpc_atsvc_job,
660                 &ett_dcerpc_atsvc_job_flags
661         };
662
663
664         proto_dcerpc_atsvc = proto_register_protocol(
665                 "Microsoft Task Scheduler Service", "ATSVC", "atsvc");
666
667         proto_register_field_array(proto_dcerpc_atsvc, hf, array_length(hf));
668
669         proto_register_subtree_array(ett, array_length(ett));
670
671 }
672
673
674 void
675 proto_reg_handoff_dcerpc_atsvc(void)
676 {
677         header_field_info *hf_info;
678
679         /* register protocol as dcerpc */
680
681         dcerpc_init_uuid(
682                 proto_dcerpc_atsvc, ett_dcerpc_atsvc, &uuid_dcerpc_atsvc,
683                 ver_dcerpc_atsvc, dcerpc_atsvc_dissectors, hf_atsvc_opnum);
684
685         /* Set opnum strings from subdissector list */
686
687         hf_info = proto_registrar_get_nth(hf_atsvc_opnum);
688         hf_info->strings = value_string_from_subdissectors(
689                 dcerpc_atsvc_dissectors, array_length(dcerpc_atsvc_dissectors));
690
691 }