1 /* packet-dcerpc-svcctl.c
2 * Routines for SMB \PIPE\svcctl packet disassembly
3 * Copyright 2003, Tim Potter <tpot@samba.org>
4 * Copyright 2003, Ronnie Sahlberg, added function dissectors
6 * $Id: packet-dcerpc-svcctl.c,v 1.11 2003/08/04 02:48:59 tpot Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <epan/packet.h>
33 #include "packet-dcerpc.h"
34 #include "packet-dcerpc-svcctl.h"
35 #include "packet-dcerpc-nt.h"
37 #include "packet-smb-common.h"
39 static int proto_dcerpc_svcctl = -1;
40 static int hf_svcctl_opnum = -1;
41 static int hf_svcctl_machinename = -1;
42 static int hf_svcctl_database = -1;
43 static int hf_svcctl_access_mask = -1;
44 static int hf_svcctl_scm_rights_connect = -1;
45 static int hf_svcctl_scm_rights_create_service = -1;
46 static int hf_svcctl_scm_rights_enumerate_service = -1;
47 static int hf_svcctl_scm_rights_lock = -1;
48 static int hf_svcctl_scm_rights_query_lock_status = -1;
49 static int hf_svcctl_scm_rights_modify_boot_config = -1;
50 static int hf_svcctl_hnd = -1;
51 static int hf_svcctl_lock = -1;
52 static int hf_svcctl_rc = -1;
53 static int hf_svcctl_size = -1;
54 static int hf_svcctl_required_size = -1;
55 static int hf_svcctl_is_locked = -1;
56 static int hf_svcctl_lock_duration = -1;
57 static int hf_svcctl_lock_owner = -1;
58 static int hf_svcctl_service_type = -1;
59 static int hf_svcctl_service_state = -1;
60 static int hf_svcctl_resume = -1;
62 static gint ett_dcerpc_svcctl = -1;
64 static e_uuid_t uuid_dcerpc_svcctl = {
65 0x367abb81, 0x9844, 0x35f1,
66 { 0xad, 0x32, 0x98, 0xf0, 0x38, 0x00, 0x10, 0x03 }
69 static guint16 ver_dcerpc_svcctl = 2;
74 svcctl_dissect_pointer_long(tvbuff_t *tvb, int offset,
75 packet_info *pinfo, proto_tree *tree,
80 di=pinfo->private_data;
81 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
87 svcctl_scm_specific_rights(tvbuff_t *tvb, gint offset, proto_tree *tree,
90 proto_tree_add_boolean(tree, hf_svcctl_scm_rights_modify_boot_config, tvb, offset, 4, access);
91 proto_tree_add_boolean(tree, hf_svcctl_scm_rights_query_lock_status, tvb, offset, 4, access);
92 proto_tree_add_boolean(tree, hf_svcctl_scm_rights_lock, tvb, offset, 4, access);
93 proto_tree_add_boolean(tree, hf_svcctl_scm_rights_enumerate_service, tvb, offset, 4, access);
94 proto_tree_add_boolean(tree, hf_svcctl_scm_rights_create_service, tvb, offset, 4, access);
95 proto_tree_add_boolean(tree, hf_svcctl_scm_rights_connect, tvb, offset, 4, access);
98 struct access_mask_info svcctl_scm_access_mask_info = {
100 svcctl_scm_specific_rights,
101 NULL, /* Generic mapping table */
102 NULL /* Standard mapping table */
106 * IDL long OpenSCManager(
107 * IDL [in] [string] [unique] char *MachineName,
108 * IDL [in] [string] [unique] char *DatabaseName,
109 * IDL [in] long access_mask,
110 * IDL [out] SC_HANDLE handle,
114 svcctl_dissect_OpenSCManager_rqst(tvbuff_t *tvb, int offset,
115 packet_info *pinfo, proto_tree *tree,
119 offset = dissect_ndr_pointer_cb(
120 tvb, offset, pinfo, tree, drep,
121 dissect_ndr_char_cvstring, NDR_POINTER_UNIQUE,
122 "MachineName", hf_svcctl_machinename, cb_str_postprocess,
123 GINT_TO_POINTER(CB_STR_COL_INFO | CB_STR_SAVE | 1));
126 offset = dissect_ndr_pointer_cb(
127 tvb, offset, pinfo, tree, drep,
128 dissect_ndr_char_cvstring, NDR_POINTER_UNIQUE,
129 "Database", hf_svcctl_database, cb_str_postprocess,
130 GINT_TO_POINTER(CB_STR_COL_INFO | 1));
133 offset = dissect_nt_access_mask(
134 tvb, offset, pinfo, tree, drep, hf_svcctl_access_mask,
135 &svcctl_scm_access_mask_info);
141 svcctl_dissect_OpenSCManager_reply(tvbuff_t *tvb, int offset,
142 packet_info *pinfo, proto_tree *tree,
145 dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
146 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
147 e_ctx_hnd policy_hnd;
148 proto_item *hnd_item;
153 offset = dissect_nt_policy_hnd(
154 tvb, offset, pinfo, tree, drep, hf_svcctl_hnd, &policy_hnd,
155 &hnd_item, TRUE, FALSE);
157 offset = dissect_doserror(
158 tvb, offset, pinfo, tree, drep, hf_svcctl_rc, &status);
162 /* Associate the returned svcctl with a name */
164 if (dcv->private_data) {
167 pol_name = g_strdup_printf(
169 (char *)dcv->private_data);
171 dcerpc_smb_store_pol_name(&policy_hnd, pinfo, pol_name);
174 g_free(dcv->private_data);
175 dcv->private_data = NULL;
179 * If we have a name for the handle, attach it to the item.
181 * XXX - we can't just do that above, as this may be called
182 * twice (see "dissect_pipe_dcerpc()", which calls the
183 * DCE RPC dissector twice), and in the first call we're
184 * not building a protocol tree (so we don't have an item
185 * to which to attach it) and in the second call
186 * "dcv->private_data" is NULL so we don't construct a
190 if (hnd_item != NULL) {
193 if (dcerpc_smb_fetch_pol(&policy_hnd, &name, NULL, NULL,
194 pinfo->fd->num) && name != NULL)
195 proto_item_append_text(hnd_item, ": %s", name);
205 * IDL BOOL CloseServiceHandle(
206 * IDL [in][out] SC_HANDLE handle
210 svcctl_dissect_CloseServiceHandle_rqst(tvbuff_t *tvb, int offset,
211 packet_info *pinfo, proto_tree *tree,
214 e_ctx_hnd policy_hnd;
219 offset = dissect_nt_policy_hnd(
220 tvb, offset, pinfo, tree, drep, hf_svcctl_hnd, &policy_hnd,
223 dcerpc_smb_fetch_pol(&policy_hnd, &pol_name, NULL, NULL,
226 if (check_col(pinfo->cinfo, COL_INFO) && pol_name)
227 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
234 svcctl_dissect_CloseServiceHandle_reply(tvbuff_t *tvb, int offset,
235 packet_info *pinfo, proto_tree *tree,
238 offset = dissect_nt_policy_hnd(
239 tvb, offset, pinfo, tree, drep, hf_svcctl_hnd, NULL,
242 offset = dissect_doserror(
243 tvb, offset, pinfo, tree, drep, hf_svcctl_rc, NULL);
251 * IDL long LockServiceDatabase(
252 * IDL [in] SC_HANDLE dbhandle,
253 * IDL [out] SC_HANDLE lock,
257 svcctl_dissect_LockServiceDatabase_rqst(tvbuff_t *tvb, int offset,
258 packet_info *pinfo, proto_tree *tree,
261 /* XXX - why is the "is a close" argument TRUE? */
262 offset = dissect_nt_policy_hnd(
263 tvb, offset, pinfo, tree, drep, hf_svcctl_hnd, NULL,
269 svcctl_dissect_LockServiceDatabase_reply(tvbuff_t *tvb, int offset,
270 packet_info *pinfo, proto_tree *tree,
273 /* XXX - why is the "is an open" argument TRUE? */
274 offset = dissect_nt_policy_hnd(
275 tvb, offset, pinfo, tree, drep, hf_svcctl_lock, NULL,
278 offset = dissect_doserror(
279 tvb, offset, pinfo, tree, drep, hf_svcctl_rc, NULL);
287 * IDL long UnlockServiceDatabase(
288 * IDL [in][out] SC_HANDLE lock,
292 svcctl_dissect_UnlockServiceDatabase_rqst(tvbuff_t *tvb, int offset,
293 packet_info *pinfo, proto_tree *tree,
296 /* XXX - why is the "is a close" argument TRUE? */
297 offset = dissect_nt_policy_hnd(
298 tvb, offset, pinfo, tree, drep, hf_svcctl_lock, NULL,
304 svcctl_dissect_UnlockServiceDatabase_reply(tvbuff_t *tvb, int offset,
305 packet_info *pinfo, proto_tree *tree,
308 /* XXX - why is the "is an open" argument TRUE? */
309 offset = dissect_nt_policy_hnd(
310 tvb, offset, pinfo, tree, drep, hf_svcctl_lock, NULL,
313 offset = dissect_doserror(
314 tvb, offset, pinfo, tree, drep, hf_svcctl_rc, NULL);
321 * IDL typedef struct {
322 * IDL long is_locked,
323 * IDL [unique][string] char *lock_owner,
324 * IDL long lock_duration,
328 svcctl_dissect_QUERY_SERVICE_LOCK_STATUS(tvbuff_t *tvb, int offset,
329 packet_info *pinfo, proto_tree *tree,
332 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
333 hf_svcctl_is_locked, NULL);
335 offset = dissect_ndr_pointer(
336 tvb, offset, pinfo, tree, drep,
337 dissect_ndr_char_cvstring, NDR_POINTER_UNIQUE,
338 "Owner", hf_svcctl_lock_owner);
340 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
341 hf_svcctl_lock_duration, NULL);
347 * IDL long QueryServiceLockStatus(
348 * IDL [in] SC_HANDLE db_handle,
349 * IDL [in] long buf_size,
350 * IDL [out][ref] QUERY_SERVICE_LOCK_STATUS *status,
351 * IDL [out][ref] long *required_buf_size
355 svcctl_dissect_QueryServiceLockStatus_rqst(tvbuff_t *tvb, int offset,
356 packet_info *pinfo, proto_tree *tree,
359 /* XXX - why is the "is a close" argument TRUE? */
360 offset = dissect_nt_policy_hnd(
361 tvb, offset, pinfo, tree, drep, hf_svcctl_hnd, NULL,
364 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
365 hf_svcctl_size, NULL);
370 svcctl_dissect_QueryServiceLockStatus_reply(tvbuff_t *tvb, int offset,
371 packet_info *pinfo, proto_tree *tree,
374 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
375 svcctl_dissect_QUERY_SERVICE_LOCK_STATUS, NDR_POINTER_REF,
378 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
379 hf_svcctl_required_size, NULL);
381 offset = dissect_doserror(
382 tvb, offset, pinfo, tree, drep, hf_svcctl_rc, NULL);
389 #define SERVICE_DRIVER 0x0b
390 #define SERVICE_WIN32 0x30
391 static const value_string svcctl_service_type_vals[] = {
392 { SERVICE_DRIVER, "SERVICE_DRIVER" },
393 { SERVICE_WIN32, "SERVICE_WIN32" },
397 #define SERVICE_ACTIVE 0x01
398 #define SERVICE_INACTIVE 0x02
399 #define SERVICE_STATE_ALL 0x03
400 static const value_string svcctl_service_status_vals[] = {
401 { SERVICE_ACTIVE, "SERVICE_ACTIVE" },
402 { SERVICE_INACTIVE, "SERVICE_INACTIVE" },
403 { SERVICE_STATE_ALL, "SERVICE_STATE_ALL" },
408 * IDL long EnumServicesStatus(
409 * IDL [in] SC_HANDLE db_handle,
410 * IDL [in] long type,
411 * IDL [in] long status,
412 * IDL [in] long buf_size,
413 * IDL [in][unique] long *resume_handle,
417 svcctl_dissect_EnumServicesStatus_rqst(tvbuff_t *tvb, int offset,
418 packet_info *pinfo, proto_tree *tree,
421 /* XXX - why is the "is a close" argument TRUE? */
422 offset = dissect_nt_policy_hnd(
423 tvb, offset, pinfo, tree, drep, hf_svcctl_hnd, NULL,
426 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
427 hf_svcctl_service_type, NULL);
429 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
430 hf_svcctl_service_state, NULL);
432 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
433 hf_svcctl_size, NULL);
435 offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
436 svcctl_dissect_pointer_long, NDR_POINTER_UNIQUE,
437 "Resume Handle", hf_svcctl_resume);
446 static dcerpc_sub_dissector dcerpc_svcctl_dissectors[] = {
447 { SVC_CLOSE_SERVICE_HANDLE, "CloseServiceHandle",
448 svcctl_dissect_CloseServiceHandle_rqst,
449 svcctl_dissect_CloseServiceHandle_reply },
450 { SVC_STOP_SERVICE, "Stop", NULL, NULL },
451 { SVC_DELETE, "Delete", NULL, NULL },
452 { SVC_LOCK_SERVICE_DATABASE, "LockServiceDatabase",
453 svcctl_dissect_LockServiceDatabase_rqst,
454 svcctl_dissect_LockServiceDatabase_reply },
455 { SVC_GET_SVC_SEC, "Get security", NULL, NULL },
456 { SVC_UNLOCK_SERVICE_DATABASE, "UnlockServiceDatabase",
457 svcctl_dissect_UnlockServiceDatabase_rqst,
458 svcctl_dissect_UnlockServiceDatabase_reply },
459 { SVC_CHANGE_SVC_CONFIG, "Change config", NULL, NULL },
460 { SVC_ENUM_SVCS_STATUS, "Enum status", NULL, NULL },
461 { SVC_OPEN_SC_MAN, "Open SC Manager", NULL, NULL },
462 { SVC_OPEN_SERVICE, "Open service", NULL, NULL },
463 { SVC_QUERY_SVC_CONFIG, "Query config", NULL, NULL },
464 { SVC_START_SERVICE, "Start", NULL, NULL },
465 { SVC_QUERY_DISP_NAME, "Query display name", NULL, NULL },
466 { SVC_ENUM_SERVICES_STATUS, "EnumServicesStatus",
467 svcctl_dissect_EnumServicesStatus_rqst,
469 { SVC_OPEN_SC_MANAGER, "OpenSCManager",
470 svcctl_dissect_OpenSCManager_rqst,
471 svcctl_dissect_OpenSCManager_reply },
472 { SVC_OPEN_SERVICE_A, "Open Service A", NULL, NULL },
473 { SVC_QUERY_SERVICE_LOCK_STATUS, "QueryServiceLockStatus",
474 svcctl_dissect_QueryServiceLockStatus_rqst,
475 svcctl_dissect_QueryServiceLockStatus_reply },
476 {0, NULL, NULL, NULL}
480 proto_register_dcerpc_svcctl(void)
482 static hf_register_info hf[] = {
484 { "Operation", "svcctl.opnum", FT_UINT16, BASE_DEC,
485 NULL, 0x0, "Operation", HFILL }},
486 { &hf_svcctl_machinename,
487 { "MachineName", "svcctl.machinename", FT_STRING, BASE_NONE,
488 NULL, 0x0, "Name of the host we want to open the database on", HFILL }},
489 { &hf_svcctl_database,
490 { "Database", "svcctl.database", FT_STRING, BASE_NONE,
491 NULL, 0x0, "Name of the database to open", HFILL }},
492 { &hf_svcctl_access_mask,
493 { "Access Mask", "svcctl.access_mask", FT_UINT32, BASE_HEX,
494 NULL, 0x0, "SVCCTL Access Mask", HFILL }},
495 { &hf_svcctl_scm_rights_connect,
496 { "Connect", "svcctl.scm_rights_connect", FT_BOOLEAN, 32,
497 TFS(&flags_set_truth), 0x00000001, "SVCCTL Rights to connect to SCM", HFILL }},
498 { &hf_svcctl_scm_rights_create_service,
499 { "Create Service", "svcctl.scm_rights_create_service", FT_BOOLEAN, 32,
500 TFS(&flags_set_truth), 0x00000002, "SVCCTL Rights to create services", HFILL }},
501 { &hf_svcctl_scm_rights_enumerate_service,
502 { "Enumerate Service", "svcctl.scm_rights_enumerate_service", FT_BOOLEAN, 32,
503 TFS(&flags_set_truth), 0x00000004, "SVCCTL Rights to enumerate services", HFILL }},
504 { &hf_svcctl_scm_rights_lock,
505 { "Lock", "svcctl.scm_rights_lock", FT_BOOLEAN, 32,
506 TFS(&flags_set_truth), 0x00000008, "SVCCTL Rights to lock database", HFILL }},
507 { &hf_svcctl_scm_rights_query_lock_status,
508 { "Query Lock Status", "svcctl.scm_rights_query_lock_status", FT_BOOLEAN, 32,
509 TFS(&flags_set_truth), 0x00000010, "SVCCTL Rights to query database lock status", HFILL }},
510 { &hf_svcctl_scm_rights_modify_boot_config,
511 { "Modify Boot Config", "svcctl.scm_rights_modify_boot_config", FT_BOOLEAN, 32,
512 TFS(&flags_set_truth), 0x00000020, "SVCCTL Rights to modify boot config", HFILL }},
514 { "Context Handle", "svcctl.hnd", FT_BYTES, BASE_NONE,
515 NULL, 0x0, "SVCCTL Context handle", HFILL }},
517 { "Lock", "svcctl.lock", FT_BYTES, BASE_NONE,
518 NULL, 0x0, "SVCCTL Database Lock", HFILL }},
520 { "Return code", "svcctl.rc", FT_UINT32, BASE_HEX,
521 VALS(DOS_errors), 0x0, "SVCCTL return code", HFILL }},
523 { "Size", "svcctl.size", FT_UINT32, BASE_DEC,
524 NULL, 0x0, "SVCCTL size of buffer", HFILL }},
525 { &hf_svcctl_required_size,
526 { "Required Size", "svcctl.required_size", FT_UINT32, BASE_DEC,
527 NULL, 0x0, "SVCCTL required size of buffer for data to fit", HFILL }},
528 { &hf_svcctl_is_locked,
529 { "IsLocked", "svcctl.is_locked", FT_UINT32, BASE_DEC,
530 NULL, 0x0, "SVCCTL whether the database is locked or not", HFILL }},
531 { &hf_svcctl_lock_duration,
532 { "Duration", "svcctl.lock_duration", FT_UINT32, BASE_DEC,
533 NULL, 0x0, "SVCCTL number of seconds the database has been locked", HFILL }},
534 { &hf_svcctl_lock_owner,
535 { "Owner", "svcctl.lock_owner", FT_STRING, BASE_NONE,
536 NULL, 0x0, "SVCCTL the user that holds the database lock", HFILL }},
537 { &hf_svcctl_service_type,
538 { "Type", "svcctl.service_type", FT_UINT32, BASE_DEC,
539 VALS(svcctl_service_type_vals), 0x0, "SVCCTL type of service", HFILL }},
541 { &hf_svcctl_service_state,
542 { "State", "svcctl.service_state", FT_UINT32, BASE_DEC,
543 VALS(svcctl_service_status_vals), 0x0, "SVCCTL service state", HFILL }},
545 { "Resume Handle", "svcctl.resume", FT_UINT32, BASE_DEC,
546 NULL, 0x0, "SVCCTL resume handle", HFILL }},
549 static gint *ett[] = {
553 proto_dcerpc_svcctl = proto_register_protocol(
554 "Microsoft Service Control", "SVCCTL", "svcctl");
556 proto_register_field_array(proto_dcerpc_svcctl, hf, array_length(hf));
557 proto_register_subtree_array(ett, array_length(ett));
561 proto_reg_handoff_dcerpc_svcctl(void)
563 /* Register protocol as dcerpc */
565 dcerpc_init_uuid(proto_dcerpc_svcctl, ett_dcerpc_svcctl,
566 &uuid_dcerpc_svcctl, ver_dcerpc_svcctl,
567 dcerpc_svcctl_dissectors, hf_svcctl_opnum);