Frame numbers are unsigned.
[obnox/wireshark/wip.git] / packet-nfsacl.c
1 /* packet-nfsacl.c
2  * Stubs for Sun's NFS ACL RPC service (runs on port 2049, and is presumably
3  * handled by the same kernel server code that handles NFS)
4  *
5  * Guy Harris <guy@alum.mit.edu>
6  *
7  * $Id: packet-nfsacl.c,v 1.7 2003/04/22 20:34:19 guy Exp $
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "packet-rpc.h"
33 #include "packet-nfs.h"
34
35 static int proto_nfsacl = -1;
36 static int hf_nfsacl_procedure_v1 = -1;
37 static int hf_nfsacl_procedure_v2 = -1;
38 static int hf_nfsacl_procedure_v3 = -1;
39 static int hf_nfsacl_entry = -1;
40 static int hf_nfsacl_aclcnt = -1;
41 static int hf_nfsacl_dfaclcnt = -1;
42 static int hf_nfsacl2_status = -1;
43 static int hf_nfsacl3_status = -1;
44 static int hf_nfsacl_aclent = -1;
45 static int hf_nfsacl_aclent_type = -1;
46 static int hf_nfsacl_aclent_uid = 1;
47 static int hf_nfsacl_aclent_perm = -1;
48
49 static gint ett_nfsacl = -1;
50 static gint ett_nfsacl_mask = -1;
51 static gint ett_nfsacl_entry = -1;
52 static gint ett_nfsacl_aclent = -1;
53 static gint ett_nfsacl_aclent_perm = -1;
54 static gint ett_nfsacl_aclent_entries = -1;
55
56 #define NFSACL_PROGRAM  100227
57
58 #define NFSACLPROC_NULL         0
59
60 #define NFSACLPROC2_GETACL      1
61 #define NFSACLPROC2_SETACL      2
62 #define NFSACLPROC2_GETATTR     3
63 #define NFSACLPROC2_ACCESS      4
64
65 #define NFSACLPROC3_GETACL      1
66 #define NFSACLPROC3_SETACL      2
67
68 #define ACL2_OK 0
69 #define ACL3_OK 0
70
71 /* proc number, "proc name", dissect_request, dissect_reply */
72 /* NULL as function pointer means: type of arguments is "void". */
73 static const vsff nfsacl1_proc[] = {
74         { NFSACLPROC_NULL,      "NULL",
75                 NULL,   NULL },
76         { 0,    NULL,   NULL,   NULL }
77 };
78 static const value_string nfsacl1_proc_vals[] = {
79         { NFSACLPROC_NULL,      "NULL" },
80         { 0,    NULL }
81 };
82
83 static const vsff nfsacl2_proc[] = {
84         { NFSACLPROC_NULL,      "NULL",
85                 NULL,   NULL },
86         { NFSACLPROC2_GETACL,   "GETACL",
87                 NULL,   NULL },
88         { NFSACLPROC2_SETACL,   "SETACL",
89                 NULL,   NULL },
90         { NFSACLPROC2_GETATTR,  "GETATTR",
91                 NULL,   NULL },
92         { NFSACLPROC2_ACCESS,   "ACCESS",
93                 NULL,   NULL },
94         { 0,    NULL,   NULL,   NULL }
95 };
96 static const value_string nfsacl2_proc_vals[] = {
97         { NFSACLPROC_NULL,      "NULL" },
98         { NFSACLPROC2_GETACL,   "GETACL" },
99         { NFSACLPROC2_SETACL,   "SETACL" },
100         { NFSACLPROC2_GETATTR,  "GETATTR" },
101         { NFSACLPROC2_ACCESS,   "ACCESS" },
102         { 0,    NULL }
103 };
104
105 static int
106 dissect_nfsacl_mask(tvbuff_t *tvb, int offset, proto_tree *tree, 
107                 char *name)
108 {
109         guint32 mask;
110         proto_item *mask_item = NULL;
111         proto_tree *mask_tree = NULL;
112
113         mask = tvb_get_ntohl(tvb, offset + 0);
114
115         if (tree)
116         {
117                 mask_item = proto_tree_add_text(tree, tvb, offset, 4, "%s: 0x%02x",
118                                 name, mask);
119
120                 if (mask_item)
121                         mask_tree = proto_item_add_subtree(mask_item, ett_nfsacl_mask);
122         }
123
124         if (mask_tree)
125         {
126                 proto_tree_add_text(mask_tree, tvb, offset, 4, "%s",
127                                 decode_boolean_bitfield(mask, 0x01, 8, "ACL entry", 
128                                         "(no ACL entry)"));
129                 proto_tree_add_text(mask_tree, tvb, offset, 4, "%s",
130                                 decode_boolean_bitfield(mask, 0x02, 8, "ACL count", 
131                                         "(no ACL count)"));
132                 proto_tree_add_text(mask_tree, tvb, offset, 4, "%s",
133                                 decode_boolean_bitfield(mask, 0x04, 8, "default ACL entry", 
134                                         "(no default ACL entry)"));
135                 proto_tree_add_text(mask_tree, tvb, offset, 4, "%s",
136                                 decode_boolean_bitfield(mask, 0x08, 8, "default ACL count", 
137                                         "(no default ACL count)"));
138         }
139
140         offset += 4;
141         return offset;
142 }
143
144 static int
145 dissect_nfsacl3_getacl_call(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
146                 proto_tree *tree)
147 {
148         offset = dissect_nfs_fh3(tvb, offset, pinfo, tree, "fhandle");
149         offset = dissect_nfsacl_mask(tvb, offset, tree, "mask");
150
151         return offset;
152 }
153
154 #define NA_READ 0x4
155 #define NA_WRITE 0x2
156 #define NA_EXEC 0x1
157
158 static const value_string names_nfsacl_aclent_type[] = {
159 #define NA_USER_OBJ 0x1
160         { NA_USER_OBJ, "NA_USER_OBJ" },
161 #define NA_USER 0x2
162         { NA_USER, "NA_USER" },
163 #define NA_GROUP_OBJ 0x4
164         { NA_GROUP_OBJ, "NA_GROUP_OBJ" },
165 #define NA_GROUP 0x8
166         { NA_GROUP, "NA_GROUP" },
167 #define NA_CLASS_OBJ 0x10
168         { NA_CLASS_OBJ, "NA_CLASS_OBJ" },
169 #define NA_OTHER_OBJ 0x20
170         { NA_OTHER_OBJ, "NA_OTHER_OBJ" },
171 #define NA_ACL_DEFAULT 0x1000
172         { NA_ACL_DEFAULT, "NA_ACL_DEFAULT" },
173         { NA_ACL_DEFAULT | NA_USER_OBJ, "Default NA_USER_OBJ" },
174         { NA_ACL_DEFAULT | NA_USER, "Default NA_USER" },
175         { NA_ACL_DEFAULT | NA_GROUP_OBJ, "Default NA_GROUP_OBJ" },
176         { NA_ACL_DEFAULT | NA_GROUP, "Default NA_GROUP" },
177         { NA_ACL_DEFAULT | NA_CLASS_OBJ, "Default NA_CLASS_OBJ" },
178         { NA_ACL_DEFAULT | NA_OTHER_OBJ, "Default NA_OTHER_OBJ" },
179         { 0, NULL },
180 };
181
182 static int
183 dissect_nfsacl_aclent(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
184                 proto_tree* tree)
185 {
186         proto_item *entry_item = NULL;
187         proto_tree *entry_tree = NULL;
188         guint32 perm;
189         proto_item *perm_item = NULL;
190         proto_tree *perm_tree = NULL;
191
192         if (tree)
193         {
194                 entry_item = proto_tree_add_item(tree, hf_nfsacl_aclent, tvb, 
195                                 offset + 0, -1, FALSE);
196                 entry_tree = proto_item_add_subtree(entry_item, ett_nfsacl_aclent);
197         }
198
199         offset = dissect_rpc_uint32(tvb, entry_tree, hf_nfsacl_aclent_type, offset);
200         offset = dissect_rpc_uint32(tvb, entry_tree, hf_nfsacl_aclent_uid, offset);
201         
202         perm = tvb_get_ntohl(tvb, offset);
203
204         perm_item = proto_tree_add_uint(entry_tree, hf_nfsacl_aclent_perm, 
205                         tvb, offset, 4, perm);
206
207         if (perm_item)
208                 perm_tree = proto_item_add_subtree(perm_item, ett_nfsacl_aclent_perm);
209
210         if (perm_tree)
211         {
212                 proto_tree_add_text(perm_tree, tvb, offset, 4, "%s",
213                                 decode_boolean_bitfield(perm, NA_READ, 4, "READ", "no READ"));
214
215                 proto_tree_add_text(perm_tree, tvb, offset, 4, "%s",
216                                 decode_boolean_bitfield(perm, NA_WRITE, 4, "WRITE", "no WRITE"));
217
218                 proto_tree_add_text(perm_tree, tvb, offset, 4, "%s",
219                                 decode_boolean_bitfield(perm, NA_EXEC, 4, "EXEC", "no EXEC"));
220         }
221
222         offset += 4;
223
224         return offset;
225 }
226
227 static int
228 dissect_nfsacl_secattr(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
229                 proto_tree *tree)
230 {
231         guint32 aclcnt, dfaclcnt;
232         guint32 i;
233         proto_item *entry_item = NULL;
234         proto_tree *entry_tree = NULL;
235
236         offset = dissect_nfsacl_mask(tvb, offset, tree, "mask");
237         offset = dissect_rpc_uint32(tvb, tree, hf_nfsacl_aclcnt, offset);
238
239         aclcnt = tvb_get_ntohl(tvb, offset);
240
241         entry_item = proto_tree_add_text(tree, tvb, offset, 4, 
242                         "Total ACL entries: %d", aclcnt);
243
244         if (entry_item)
245                 entry_tree = proto_item_add_subtree(entry_item, 
246                                 ett_nfsacl_aclent_entries);
247
248         offset += 4;
249
250         if (aclcnt > 0)
251         {
252                 for (i = 0; i < aclcnt; i++)
253                         offset = dissect_nfsacl_aclent(tvb, offset, pinfo, entry_tree);
254         }
255
256         /* */
257
258         offset = dissect_rpc_uint32(tvb, tree, hf_nfsacl_dfaclcnt, offset);
259
260         dfaclcnt = tvb_get_ntohl(tvb, offset);
261
262         entry_item = proto_tree_add_text(tree, tvb, offset, 4, 
263                         "Total default ACL entries: %d", dfaclcnt);
264
265         if (entry_item)
266                 entry_tree = proto_item_add_subtree(entry_item,
267                                 ett_nfsacl_aclent_entries);
268
269         offset += 4;
270
271         if (dfaclcnt > 0)
272         {
273                 for (i = 0; i < dfaclcnt; i++)
274                         offset = dissect_nfsacl_aclent(tvb, offset, pinfo, entry_tree);
275         }
276
277         return offset;
278 }
279
280 static int
281 dissect_nfsacl3_getacl_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
282                 proto_tree *tree)
283 {
284         guint32 status;
285         proto_item *entry_item = NULL;
286         proto_tree *entry_tree = NULL;
287
288         status = tvb_get_ntohl(tvb, offset + 0);
289
290         if (tree)
291                 proto_tree_add_uint(tree, hf_nfsacl3_status, tvb, offset + 0, 4,
292                                 status);
293
294         offset += 4;
295
296         if (tree)
297         {
298                 entry_item = proto_tree_add_item(tree, hf_nfsacl_entry, tvb,
299                                 offset + 0, -1, FALSE);
300                 if (entry_item)
301                         entry_tree = proto_item_add_subtree(entry_item, ett_nfsacl_entry);
302         }
303
304         if (entry_tree)
305                 offset = dissect_nfs_post_op_attr(tvb, offset, entry_tree, "fattr");
306
307         if (status != ACL3_OK)
308                 return offset;
309
310         if (entry_tree)
311                 offset = dissect_nfsacl_secattr(tvb, offset, pinfo, entry_tree);
312
313         return offset;
314 }
315
316 static int
317 dissect_nfsacl3_setacl_call(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
318                 proto_tree *tree)
319
320 {
321         proto_item *acl_item = NULL;
322         proto_tree *acl_tree = NULL;
323
324         offset = dissect_nfs_fh3(tvb, offset, pinfo, tree, "fhandle");
325
326         if (tree)
327         {
328                 acl_item = proto_tree_add_item(tree, hf_nfsacl_entry, tvb, offset + 0, 
329                                 -1, FALSE);
330
331                 if (acl_item)
332                         acl_tree = proto_item_add_subtree(acl_item, ett_nfsacl_entry);
333         }
334
335         if (acl_tree)
336                 offset = dissect_nfsacl_secattr(tvb, offset, pinfo, acl_tree);
337
338         return offset;
339 }
340
341 static int
342 dissect_nfsacl3_setacl_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
343                 proto_tree *tree)
344 {
345         guint32 status = tvb_get_ntohl(tvb, offset + 0);
346
347         if (tree)
348                 proto_tree_add_uint(tree, hf_nfsacl3_status, tvb, offset + 0, 4,
349                                 status);
350
351         offset += 4;
352
353         /* if (entry_tree)
354                 offset = dissect_nfs_post_op_attr(tvb, offset, tree, "fattr"); */
355
356
357         return offset;
358 }
359
360 static const vsff nfsacl3_proc[] = {
361         { NFSACLPROC_NULL,      "NULL",
362                 NULL,   NULL },
363         { NFSACLPROC3_GETACL,   "GETACL",
364                 dissect_nfsacl3_getacl_call,    dissect_nfsacl3_getacl_reply },
365         { NFSACLPROC3_SETACL,   "SETACL",
366                 dissect_nfsacl3_setacl_call,    dissect_nfsacl3_setacl_reply },
367         { 0,    NULL,   NULL,   NULL }
368 };
369 static const value_string nfsacl3_proc_vals[] = {
370         { NFSACLPROC_NULL,      "NULL" },
371         { NFSACLPROC3_GETACL,   "GETACL" },
372         { NFSACLPROC3_SETACL,   "SETACL" },
373         { 0,    NULL }
374 };
375
376 static const value_string names_nfsacl2_status[] = {
377         { ACL2_OK, "ACL2_OK" },
378         { 0, NULL }
379 };
380
381 static const value_string names_nfsacl3_status[] = {
382         { ACL3_OK,      "ACL3_OK" },
383         { 0, NULL }
384 };
385
386 void
387 proto_register_nfsacl(void)
388 {
389         static hf_register_info hf[] = {
390                 { &hf_nfsacl_procedure_v1, {
391                         "V1 Procedure", "nfsacl.procedure_v1", FT_UINT32, BASE_DEC,
392                         VALS(nfsacl1_proc_vals), 0, "V1 Procedure", HFILL }},
393                 { &hf_nfsacl_procedure_v2, {
394                         "V2 Procedure", "nfsacl.procedure_v2", FT_UINT32, BASE_DEC,
395                         VALS(nfsacl2_proc_vals), 0, "V2 Procedure", HFILL }},
396                 { &hf_nfsacl_procedure_v3, {
397                         "V3 Procedure", "nfsacl.procedure_v3", FT_UINT32, BASE_DEC,
398                         VALS(nfsacl3_proc_vals), 0, "V3 Procedure", HFILL }},
399                         /* generic */
400                 { &hf_nfsacl_entry, {
401                         "ACL", "nfsacl.acl", FT_NONE, 0,
402                         NULL, 0, "ACL", HFILL }},
403                 { &hf_nfsacl_aclcnt, {
404                         "ACL count", "nfsacl.aclcnt", FT_UINT32, BASE_DEC,
405                         NULL, 0, "ACL count", HFILL }},
406                 { &hf_nfsacl_dfaclcnt, {
407                         "Default ACL count", "nfsacl.dfaclcnt", FT_UINT32, BASE_DEC,
408                         NULL, 0, "Default ACL count", HFILL }},
409                 { &hf_nfsacl_aclent, {
410                         "ACL Entry", "nfsacl.aclent", FT_NONE, 0,
411                         NULL, 0, "ACL", HFILL }},
412                 { &hf_nfsacl_aclent_type, {
413                         "Type", "nfsacl.aclent.type", FT_UINT32, BASE_DEC,
414                         VALS(names_nfsacl_aclent_type), 0, "Type", HFILL }},
415                 { &hf_nfsacl_aclent_uid, {
416                         "UID", "nfsacl.aclent.uid", FT_UINT32, BASE_DEC,
417                         NULL, 0, "UID", HFILL }},
418                 { &hf_nfsacl_aclent_perm, {
419                         "Permissions", "nfsacl.aclent.perm", FT_UINT32, BASE_DEC,
420                         NULL, 0, "Permissions", HFILL }},
421                         /* V2 */
422                 { &hf_nfsacl2_status, {
423                         "Status", "nfsacl.status2", FT_UINT32, BASE_DEC,
424                         VALS(names_nfsacl2_status), 0, "Status", HFILL }},
425                         /* V3 */
426                 { &hf_nfsacl3_status, {
427                         "Status", "nfsacl.status3", FT_UINT32, BASE_DEC,
428                         VALS(names_nfsacl3_status), 0, "Status", HFILL }},
429         };
430
431         static gint *ett[] = {
432                 &ett_nfsacl,
433                 &ett_nfsacl_mask,
434                 &ett_nfsacl_entry,
435                 &ett_nfsacl_aclent,
436                 &ett_nfsacl_aclent_perm,
437                 &ett_nfsacl_aclent_entries
438         };
439
440         proto_nfsacl = proto_register_protocol("NFSACL", "NFSACL", "nfsacl");
441         proto_register_field_array(proto_nfsacl, hf, array_length(hf));
442         proto_register_subtree_array(ett, array_length(ett));
443 }
444
445 void
446 proto_reg_handoff_nfsacl(void)
447 {
448         /* Register the protocol as RPC */
449         rpc_init_prog(proto_nfsacl, NFSACL_PROGRAM, ett_nfsacl);
450         /* Register the procedure tables */
451         rpc_init_proc_table(NFSACL_PROGRAM, 1, nfsacl1_proc, hf_nfsacl_procedure_v1);
452         rpc_init_proc_table(NFSACL_PROGRAM, 2, nfsacl2_proc, hf_nfsacl_procedure_v2);
453         rpc_init_proc_table(NFSACL_PROGRAM, 3, nfsacl3_proc, hf_nfsacl_procedure_v3);
454 }