quota update partial NTGetUserQuota support
[obnox/wireshark/wip.git] / packet-portmap.c
1 /* packet-portmap.c
2  * Routines for portmap dissection
3  *
4  * $Id: packet-portmap.c,v 1.33 2002/01/20 22:12:27 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * Copied from packet-smb.c
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
34 #endif
35
36
37 #include "packet-rpc.h"
38 #include "packet-portmap.h"
39 #include "ipproto.h"
40
41 /*
42  * See:
43  *
44  *      RFC 1833, "Binding Protocols for ONC RPC Version 2".
45  */
46
47 static int proto_portmap = -1;
48 static int hf_portmap_proto = -1;
49 static int hf_portmap_prog = -1;
50 static int hf_portmap_proc = -1;
51 static int hf_portmap_version = -1;
52 static int hf_portmap_port = -1;
53 static int hf_portmap_answer = -1;
54 static int hf_portmap_args = -1;
55 static int hf_portmap_result = -1;
56 static int hf_portmap_rpcb = -1;
57 static int hf_portmap_rpcb_prog = -1;
58 static int hf_portmap_rpcb_version = -1;
59 static int hf_portmap_rpcb_netid = -1;
60 static int hf_portmap_rpcb_addr = -1;
61 static int hf_portmap_rpcb_owner = -1;
62 static int hf_portmap_uaddr = -1;
63
64
65 static gint ett_portmap = -1;
66 static gint ett_portmap_rpcb = -1;
67 static gint ett_portmap_entry = -1;
68
69
70 /* Dissect a getport call */
71 int dissect_getport_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
72         proto_tree *tree)
73 {
74         guint32 proto;
75         guint32 prog;
76
77         if ( tree )
78         {
79                 prog = tvb_get_ntohl(tvb, offset+0);
80                 proto_tree_add_uint_format(tree, hf_portmap_prog, tvb,
81                         offset, 4, prog, "Program: %s (%u)",
82                         rpc_prog_name(prog), prog);
83                 proto_tree_add_item(tree, hf_portmap_version, tvb,
84                         offset+4, 4, FALSE);
85
86                 proto = tvb_get_ntohl(tvb, offset+8);
87                 proto_tree_add_uint_format(tree, hf_portmap_proto, tvb,
88                         offset+8, 4, proto, "Proto: %s (%u)", ipprotostr(proto), proto);
89
90                 proto_tree_add_item(tree, hf_portmap_port, tvb,
91                         offset+12, 4, FALSE);
92         }
93         
94         return offset+16;
95 }
96
97 int dissect_getport_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
98         proto_tree *tree)
99 {
100         offset = dissect_rpc_uint32(tvb, pinfo, tree, hf_portmap_port,
101             offset);
102         return offset;
103 }
104
105 /* Dissect a 'set' call */
106 int dissect_set_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
107         proto_tree *tree)
108 {
109         guint32 proto;
110         guint32 prog;
111
112         if ( tree )
113         {
114                 prog = tvb_get_ntohl(tvb, offset+0);
115                 proto_tree_add_uint_format(tree, hf_portmap_prog, tvb,
116                         offset, 4, prog, "Program: %s (%d)",
117                         rpc_prog_name(prog), prog);
118                 proto_tree_add_item(tree, hf_portmap_version, tvb,
119                         offset+4, 4, FALSE);
120
121                 proto = tvb_get_ntohl(tvb, offset+8);
122                 proto_tree_add_uint_format(tree, hf_portmap_proto,tvb,
123                         offset+8, 4, proto, "Proto: %s (%d)", ipprotostr(proto), proto);
124
125                 proto_tree_add_item(tree, hf_portmap_port, tvb,
126                         offset+12, 4, FALSE);
127         }
128         
129         return offset+16;
130 }
131
132 /* Dissect a 'unset' call */
133 int dissect_unset_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
134         proto_tree *tree)
135 {
136         guint32 proto;
137         guint32 prog;
138
139         if ( tree )
140         {
141                 prog = tvb_get_ntohl(tvb, offset+0);
142                 proto_tree_add_uint_format(tree, hf_portmap_prog, tvb,
143                         offset, 4, prog, "Program: %s (%d)",
144                         rpc_prog_name(prog), prog);
145                 proto_tree_add_item(tree, hf_portmap_version, tvb,
146                         offset+4, 4, FALSE);
147
148                 proto = tvb_get_ntohl(tvb, offset+8);
149                 proto_tree_add_uint(tree, hf_portmap_proto, tvb,
150                         offset+8, 4, proto);
151
152                 proto_tree_add_item(tree, hf_portmap_port, tvb,
153                         offset+12, 4, FALSE);
154         }
155
156         return offset+16;
157 }
158
159 int dissect_set_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
160         proto_tree *tree)
161 {
162         offset = dissect_rpc_bool(tvb, pinfo, tree, hf_portmap_answer,
163             offset);
164         return offset;
165 }
166
167 static int
168 dissect_dump_entry(tvbuff_t *tvb, int offset, packet_info *pinfo,
169         proto_tree *tree)
170 {
171         int prog, version, proto, port;
172         proto_item *ti, *subtree;
173
174         prog = tvb_get_ntohl(tvb, offset+0);
175         version = tvb_get_ntohl(tvb, offset+4);
176         proto = tvb_get_ntohl(tvb, offset+8);
177         port = tvb_get_ntohl(tvb, offset+12);
178         if ( tree )
179         {
180                 ti = proto_tree_add_text(tree, tvb, offset, 16,
181                         "Map Entry: %s (%u) V%d",
182                         rpc_prog_name(prog), prog, version);
183                 subtree = proto_item_add_subtree(ti, ett_portmap_entry);
184
185                 proto_tree_add_uint_format(subtree, hf_portmap_prog, tvb,
186                         offset+0, 4, prog,
187                         "Program: %s (%u)", rpc_prog_name(prog), prog);
188                 proto_tree_add_uint(subtree, hf_portmap_version, tvb,
189                         offset+4, 4, version);
190                 proto_tree_add_uint_format(subtree, hf_portmap_proto, tvb,
191                         offset+8, 4, proto, 
192                         "Protocol: %s (0x%02x)", ipprotostr(proto), proto);
193                 proto_tree_add_uint(subtree, hf_portmap_port, tvb,
194                         offset+12, 4, port);
195         }
196         offset += 16;
197         return offset;
198 }
199
200 int dissect_dump_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
201         proto_tree *tree)
202 {
203         offset = dissect_rpc_list(tvb, pinfo, tree, offset,
204                 dissect_dump_entry);
205         return offset;
206 }
207
208 /* Dissect a callit call */
209 int dissect_callit_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
210         proto_tree *tree)
211 {
212         guint32 prog, vers, proc;
213
214         prog = tvb_get_ntohl(tvb, offset+0);
215         if ( tree )
216         {
217                 proto_tree_add_uint_format(tree, hf_portmap_prog, tvb,
218                         offset, 4, prog, "Program: %s (%u)",
219                         rpc_prog_name(prog), prog);
220         }
221
222         vers = tvb_get_ntohl(tvb, offset+4);
223         if ( tree )
224         {
225                 proto_tree_add_uint(tree, hf_portmap_version, tvb,
226                         offset+4, 4, vers);
227         }
228
229         proc = tvb_get_ntohl(tvb, offset+8);
230         if ( tree )
231         {
232                 proto_tree_add_uint_format(tree, hf_portmap_proc, tvb,
233                         offset+8, 4, proc, "Procedure: %s (%u)",
234                         rpc_proc_name(prog, vers, proc), proc);
235         }
236
237         offset += 12;
238
239         /* Dissect the arguments for this procedure.
240            Make the columns non-writable, so the dissector won't change
241            them out from under us. */
242         col_set_writable(pinfo->cinfo, FALSE);
243         offset = dissect_rpc_indir_call(tvb, pinfo, tree, offset,
244                 hf_portmap_args, prog, vers, proc);
245
246         return offset;
247 }
248
249 /* Dissect a callit reply */
250 int dissect_callit_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
251         proto_tree *tree)
252 {
253         if ( tree )
254         {
255                 proto_tree_add_item(tree, hf_portmap_port, tvb,
256                         offset, 4, FALSE);
257         }
258         offset += 4;
259
260         /* Dissect the result of this procedure.
261            Make the columns non-writable, so the dissector won't change
262            them out from under us. */
263         col_set_writable(pinfo->cinfo, FALSE);
264         offset = dissect_rpc_indir_reply(tvb, pinfo, tree, offset,
265                 hf_portmap_result, hf_portmap_prog, hf_portmap_version,
266                 hf_portmap_proc);
267
268         return offset;
269 }
270
271 /* proc number, "proc name", dissect_request, dissect_reply */
272 /* NULL as function pointer means: type of arguments is "void". */
273 static const vsff portmap1_proc[] = {
274         { PORTMAPPROC_NULL,     "NULL",         NULL,   NULL },
275         { PORTMAPPROC_SET,      "SET",          NULL,   NULL },
276         { PORTMAPPROC_UNSET,    "UNSET",        NULL,   NULL },
277         { PORTMAPPROC_GETPORT,  "GETPORT",      NULL,   NULL },
278         { PORTMAPPROC_DUMP,     "DUMP",         NULL,   NULL },
279         { PORTMAPPROC_CALLIT,   "CALLIT",       NULL,   NULL },
280         { 0,                    NULL,           NULL,   NULL }
281 };
282 /* end of Portmap version 1 */
283
284 static const vsff portmap2_proc[] = {
285         { PORTMAPPROC_NULL, "NULL",
286                 NULL, NULL },
287         { PORTMAPPROC_SET, "SET",
288                 dissect_set_call, dissect_set_reply },
289         { PORTMAPPROC_UNSET, "UNSET",
290                 dissect_unset_call, dissect_set_reply },
291         { PORTMAPPROC_GETPORT,  "GETPORT",
292                 dissect_getport_call, dissect_getport_reply },
293         { PORTMAPPROC_DUMP, "DUMP",
294                 NULL, dissect_dump_reply },
295         { PORTMAPPROC_CALLIT, "CALLIT",
296                 dissect_callit_call, dissect_callit_reply },
297         { 0, NULL, NULL, NULL }
298 };
299 /* end of Portmap version 2 */
300
301
302 /* RFC 1833, Page 3 */
303 static int
304 dissect_rpcb(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
305 {
306         proto_item* rpcb_item = NULL;
307         proto_tree* rpcb_tree = NULL;
308         int old_offset = offset;
309         guint32 prog;
310
311         if (tree) {
312                 rpcb_item = proto_tree_add_item(tree, hf_portmap_rpcb, tvb,
313                         offset, -1, FALSE);
314                 if (rpcb_item)
315                         rpcb_tree = proto_item_add_subtree(rpcb_item, ett_portmap_rpcb);
316         }
317
318         prog = tvb_get_ntohl(tvb, offset);
319         if (rpcb_tree)
320                 proto_tree_add_uint_format(rpcb_tree, hf_portmap_rpcb_prog, tvb,
321                         offset, 4, prog, 
322                         "Program: %s (%u)", rpc_prog_name(prog), prog);
323         offset += 4;
324
325         offset = dissect_rpc_uint32(tvb, pinfo, rpcb_tree,
326             hf_portmap_rpcb_version, offset);
327         offset = dissect_rpc_string(tvb, pinfo, rpcb_tree,
328             hf_portmap_rpcb_netid, offset, NULL);
329         offset = dissect_rpc_string(tvb, pinfo, rpcb_tree,
330             hf_portmap_rpcb_addr, offset, NULL);
331         offset = dissect_rpc_string(tvb, pinfo, rpcb_tree,
332             hf_portmap_rpcb_owner, offset, NULL);
333
334         /* now we know, that rpcb is shorter */
335         if (rpcb_item) {
336                 proto_item_set_len(rpcb_item, offset - old_offset);
337         }
338
339         return offset;
340 }
341
342
343
344 /* RFC 1833, Page 7 */
345 int dissect_rpcb3_getaddr_call(tvbuff_t *tvb, int offset, packet_info *pinfo,
346         proto_tree *tree)
347 {
348         offset = dissect_rpcb(tvb, offset, pinfo, tree);
349
350         return offset;
351 }
352
353
354 /* RFC 1833, Page 7 */
355 int dissect_rpcb3_getaddr_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
356         proto_tree *tree)
357 {
358         offset = dissect_rpc_string(tvb, pinfo, tree,
359             hf_portmap_uaddr, offset, NULL);
360
361         return offset;
362 }
363
364
365 /* RFC 1833, Page 7 */
366 int dissect_rpcb3_dump_reply(tvbuff_t *tvb, int offset, packet_info *pinfo,
367         proto_tree *tree)
368 {
369         offset = dissect_rpc_list(tvb, pinfo, tree, offset, dissect_rpcb);
370         return offset;
371 }
372
373 /* RFC 1833, page 4 */
374 int dissect_rpcb_rmtcallres(tvbuff_t *tvb, int offset, packet_info *pinfo,
375         proto_tree *tree)
376 {
377         /* Dissect the remote universal address. */
378         offset = dissect_rpc_string(tvb, pinfo, tree,
379             hf_portmap_rpcb_addr, offset, NULL);
380
381         /* Dissect the result of this procedure.
382            Make the columns non-writable, so the dissector won't change
383            them out from under us. */
384         col_set_writable(pinfo->cinfo, FALSE);
385         offset = dissect_rpc_indir_reply(tvb, pinfo, tree, offset,
386                 hf_portmap_result, hf_portmap_prog, hf_portmap_version,
387                 hf_portmap_proc);
388
389         return offset;
390 }
391
392
393 /* Portmapper version 3, RFC 1833, Page 7 */
394 static const vsff portmap3_proc[] = {
395         { RPCBPROC_NULL,        "NULL",
396                 NULL, NULL },
397         { RPCBPROC_SET,         "SET",
398                 NULL, NULL },
399         { RPCBPROC_UNSET,       "UNSET",
400                 NULL, NULL },
401         { RPCBPROC_GETADDR,     "GETADDR",
402                 dissect_rpcb3_getaddr_call, dissect_rpcb3_getaddr_reply},
403         { RPCBPROC_DUMP,        "DUMP",
404                 NULL, dissect_rpcb3_dump_reply },
405         { RPCBPROC_CALLIT,      "CALLIT",
406                 dissect_callit_call, dissect_rpcb_rmtcallres },
407         { RPCBPROC_GETTIME,     "GETTIME",
408                 NULL, NULL },
409         { RPCBPROC_UADDR2TADDR, "UADDR2TADDR",
410                 NULL, NULL },
411         { RPCBPROC_TADDR2UADDR, "TADDR2UADDR",
412                 NULL, NULL },
413         { 0, NULL, NULL, NULL }
414 };
415 /* end of Portmap version 3 */
416
417
418 /* Portmapper version 4, RFC 1833, Page 8 */
419 static const vsff portmap4_proc[] = {
420         { RPCBPROC_NULL,        "NULL",
421                 NULL, NULL },
422         { RPCBPROC_SET,         "SET",
423                 NULL, NULL },
424         { RPCBPROC_UNSET,       "UNSET",
425                 NULL, NULL },
426         { RPCBPROC_GETADDR,     "GETADDR",
427                 dissect_rpcb3_getaddr_call, dissect_rpcb3_getaddr_reply},
428         { RPCBPROC_DUMP,        "DUMP",
429                 NULL, dissect_rpcb3_dump_reply },
430         { RPCBPROC_BCAST,       "BCAST",
431                 dissect_callit_call, dissect_rpcb_rmtcallres },
432         { RPCBPROC_GETTIME,     "GETTIME",
433                 NULL, NULL },
434         { RPCBPROC_UADDR2TADDR, "UADDR2TADDR",
435                 NULL, NULL },
436         { RPCBPROC_TADDR2UADDR, "TADDR2UADDR",
437                 NULL, NULL },
438         { RPCBPROC_GETVERSADDR, "GETVERSADDR",
439                 NULL, NULL },
440         { RPCBPROC_INDIRECT,    "INDIRECT",
441                 dissect_callit_call, dissect_rpcb_rmtcallres },
442         { RPCBPROC_GETADDRLIST, "GETADDRLIST",
443                 NULL, NULL },
444         { RPCBPROC_GETSTAT,     "GETSTAT",
445                 NULL, NULL },
446         { 0, NULL, NULL, NULL }
447 };
448 /* end of Portmap version 4 */
449
450 void
451 proto_register_portmap(void)
452 {
453         static hf_register_info hf[] = {
454                 { &hf_portmap_prog, {
455                         "Program", "portmap.prog", FT_UINT32, BASE_DEC,
456                         NULL, 0, "Program", HFILL }},
457                 { &hf_portmap_port, {
458                         "Port", "portmap.port", FT_UINT32, BASE_DEC,
459                         NULL, 0, "Port", HFILL }},
460                 { &hf_portmap_proc, {
461                         "Procedure", "portmap.proc", FT_UINT32, BASE_DEC,
462                         NULL, 0, "Procedure", HFILL }},
463                 { &hf_portmap_proto, {
464                         "Protocol", "portmap.proto", FT_UINT32, BASE_DEC,
465                         NULL, 0, "Protocol", HFILL }},
466                 { &hf_portmap_version, {
467                         "Version", "portmap.version", FT_UINT32, BASE_DEC,
468                         NULL, 0, "Version", HFILL }},
469                 { &hf_portmap_answer, {
470                         "Answer", "portmap.answer", FT_BOOLEAN, BASE_DEC,
471                         NULL, 0, "Answer", HFILL }},
472                 { &hf_portmap_args, {
473                         "Arguments", "portmap.args", FT_BYTES, BASE_HEX,
474                         NULL, 0, "Arguments", HFILL }},
475                 { &hf_portmap_result, {
476                         "Result", "portmap.result", FT_BYTES, BASE_HEX,
477                         NULL, 0, "Result", HFILL }},
478                 { &hf_portmap_rpcb, {
479                         "RPCB", "portmap.rpcb", FT_NONE, 0,
480                         NULL, 0, "RPCB", HFILL }},
481                 { &hf_portmap_rpcb_prog, {
482                         "Program", "portmap.rpcb.prog", FT_UINT32, BASE_DEC,
483                         NULL, 0, "Program", HFILL }},
484                 { &hf_portmap_rpcb_version, {
485                         "Version", "portmap.rpcb.version", FT_UINT32, BASE_DEC,
486                         NULL, 0, "Version", HFILL }},
487                 { &hf_portmap_rpcb_netid, {
488                         "Network Id", "portmap.rpcb.netid", FT_STRING, BASE_DEC,
489                         NULL, 0, "Network Id", HFILL }},
490                 { &hf_portmap_rpcb_addr, {      /* address in rpcb structure in request */
491                         "Universal Address", "portmap.rpcb.addr", FT_STRING, BASE_DEC,
492                         NULL, 0, "Universal Address", HFILL }},
493                 { &hf_portmap_rpcb_owner, {
494                         "Owner of this Service", "portmap.rpcb.owner", FT_STRING, BASE_DEC,
495                         NULL, 0, "Owner of this Service", HFILL }},
496                 { &hf_portmap_uaddr, {  /* address in RPCBPROC_GETADDR reply */
497                         "Universal Address", "portmap.uaddr", FT_STRING, BASE_DEC,
498                         NULL, 0, "Universal Address", HFILL }},
499         };
500         static gint *ett[] = {
501                 &ett_portmap,
502                 &ett_portmap_rpcb,
503                 &ett_portmap_entry
504         };
505
506         proto_portmap = proto_register_protocol("Portmap", "Portmap", "portmap");
507         proto_register_field_array(proto_portmap, hf, array_length(hf));
508         proto_register_subtree_array(ett, array_length(ett));
509 }
510
511 void
512 proto_reg_handoff_portmap(void)
513 {
514         /* Register the protocol as RPC */
515         rpc_init_prog(proto_portmap, PORTMAP_PROGRAM, ett_portmap);
516         /* Register the procedure tables */
517         rpc_init_proc_table(PORTMAP_PROGRAM, 1, portmap1_proc);
518         rpc_init_proc_table(PORTMAP_PROGRAM, 2, portmap2_proc);
519         rpc_init_proc_table(PORTMAP_PROGRAM, 3, portmap3_proc);
520         rpc_init_proc_table(PORTMAP_PROGRAM, 4, portmap4_proc);
521 }