2 * Routines for mount dissection
4 * $Id: packet-mount.c,v 1.10 2000/01/22 05:49:07 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
10 * Copied from packet-smb.c
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 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
37 #include "packet-rpc.h"
38 #include "packet-mount.h"
39 #include "packet-nfs.h"
42 static int proto_mount = -1;
43 static int hf_mount_path = -1;
44 static int hf_mount_status = -1;
45 static int hf_mount_pathconf_link_max = -1;
46 static int hf_mount_pathconf_max_canon = -1;
47 static int hf_mount_pathconf_max_input = -1;
48 static int hf_mount_pathconf_name_max = -1;
49 static int hf_mount_pathconf_path_max = -1;
50 static int hf_mount_pathconf_pipe_buf = -1;
51 static int hf_mount_pathconf_vdisable = -1;
52 static int hf_mount_pathconf_mask = -1;
53 static int hf_mount_pathconf_error_all = -1;
54 static int hf_mount_pathconf_error_link_max = -1;
55 static int hf_mount_pathconf_error_max_canon = -1;
56 static int hf_mount_pathconf_error_max_input = -1;
57 static int hf_mount_pathconf_error_name_max = -1;
58 static int hf_mount_pathconf_error_path_max = -1;
59 static int hf_mount_pathconf_error_pipe_buf = -1;
60 static int hf_mount_pathconf_chown_restricted = -1;
61 static int hf_mount_pathconf_no_trunc = -1;
62 static int hf_mount_pathconf_error_vdisable = -1;
63 static int hf_mount_flavors = -1;
64 static int hf_mount_flavor = -1;
66 static gint ett_mount = -1;
67 static gint ett_mount_pathconf_mask = -1;
70 /* RFC 1094, Page 24 */
72 dissect_fhstatus(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
76 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
77 status = EXTRACT_UINT(pd, offset+0);
79 proto_tree_add_item(tree, hf_mount_status, offset, 4, status);
85 offset = dissect_fhandle(pd,offset,fd,tree,"fhandle");
97 dissect_mount_dirpath_call(const u_char *pd, int offset, frame_data *fd,
102 offset = dissect_rpc_string(pd,offset,fd,tree,hf_mount_path,NULL);
109 /* RFC 1094, Page 25,26 */
111 dissect_mount_mnt_reply(const u_char *pd, int offset, frame_data *fd,
114 offset = dissect_fhstatus(pd, offset, fd, tree);
120 #define OFFS_MASK 32 /* offset of the "pc_mask" field */
122 #define PC_ERROR_ALL 0x0001
123 #define PC_ERROR_LINK_MAX 0x0002
124 #define PC_ERROR_MAX_CANON 0x0004
125 #define PC_ERROR_MAX_INPUT 0x0008
126 #define PC_ERROR_NAME_MAX 0x0010
127 #define PC_ERROR_PATH_MAX 0x0020
128 #define PC_ERROR_PIPE_BUF 0x0040
129 #define PC_CHOWN_RESTRICTED 0x0080
130 #define PC_NO_TRUNC 0x0100
131 #define PC_ERROR_VDISABLE 0x0200
133 static const true_false_string tos_error_all = {
135 "Some or all info valid"
138 static const true_false_string tos_error_link_max = {
143 static const true_false_string tos_error_max_canon = {
148 static const true_false_string tos_error_max_input = {
153 static const true_false_string tos_error_name_max = {
158 static const true_false_string tos_error_path_max = {
163 static const true_false_string tos_error_pipe_buf = {
168 static const true_false_string tos_chown_restricted = {
169 "Only a privileged user can change the ownership of a file",
170 "Users may give away their own files"
173 static const true_false_string tos_no_trunc = {
174 "File names that are too long will get an error",
175 "File names that are too long will be truncated"
178 static const true_false_string tos_error_vdisable = {
184 dissect_mount_pathconf_reply(const u_char *pd, int offset, frame_data *fd,
189 proto_tree *mask_tree;
192 * Extract the mask first, so we know which other fields the
193 * server was able to return to us.
195 if (!BYTES_ARE_IN_FRAME(offset + OFFS_MASK, 4))
197 pc_mask = EXTRACT_UINT(pd, offset+OFFS_MASK) & 0xFFFF;
199 if (!BYTES_ARE_IN_FRAME(offset + 0,4))
201 if (!(pc_mask & (PC_ERROR_LINK_MAX|PC_ERROR_ALL))) {
203 proto_tree_add_item(tree,
204 hf_mount_pathconf_link_max, offset, 4,
205 EXTRACT_UINT(pd, offset+0));
210 if (!BYTES_ARE_IN_FRAME(offset,4))
212 if (!(pc_mask & (PC_ERROR_MAX_CANON|PC_ERROR_ALL))) {
214 proto_tree_add_item(tree,
215 hf_mount_pathconf_max_canon, offset + 2, 2,
216 (EXTRACT_UINT(pd, offset+0)) & 0xFFFF);
222 if (!BYTES_ARE_IN_FRAME(offset,4))
224 if (!(pc_mask & (PC_ERROR_MAX_INPUT|PC_ERROR_ALL))) {
226 proto_tree_add_item(tree,
227 hf_mount_pathconf_max_input, offset + 2, 2,
228 (EXTRACT_UINT(pd, offset+0)) & 0xFFFF);
233 if (!BYTES_ARE_IN_FRAME(offset,4))
235 if (!(pc_mask & (PC_ERROR_NAME_MAX|PC_ERROR_ALL))) {
237 proto_tree_add_item(tree,
238 hf_mount_pathconf_name_max, offset + 2, 2,
239 (EXTRACT_UINT(pd, offset+0)) & 0xFFFF);
244 if (!BYTES_ARE_IN_FRAME(offset,4))
246 if (!(pc_mask & (PC_ERROR_PATH_MAX|PC_ERROR_ALL))) {
248 proto_tree_add_item(tree,
249 hf_mount_pathconf_path_max, offset + 2, 2,
250 (EXTRACT_UINT(pd, offset+0)) & 0xFFFF);
255 if (!BYTES_ARE_IN_FRAME(offset,4))
257 if (!(pc_mask & (PC_ERROR_PIPE_BUF|PC_ERROR_ALL))) {
259 proto_tree_add_item(tree,
260 hf_mount_pathconf_pipe_buf, offset + 2, 2,
261 (EXTRACT_UINT(pd, offset+0)) & 0xFFFF);
266 offset += 4; /* skip "pc_xxx" pad field */
268 if (!BYTES_ARE_IN_FRAME(offset,4))
270 if (!(pc_mask & (PC_ERROR_VDISABLE|PC_ERROR_ALL))) {
272 proto_tree_add_item(tree,
273 hf_mount_pathconf_vdisable, offset + 3, 1,
274 (EXTRACT_UINT(pd, offset+0)) & 0xFF);
280 ti = proto_tree_add_item(tree, hf_mount_pathconf_mask,
281 offset + 2, 2, pc_mask);
282 mask_tree = proto_item_add_subtree(ti, ett_mount_pathconf_mask);
283 proto_tree_add_item(mask_tree, hf_mount_pathconf_error_all,
284 offset + 2, 2, pc_mask);
285 proto_tree_add_item(mask_tree, hf_mount_pathconf_error_link_max,
286 offset + 2, 2, pc_mask);
287 proto_tree_add_item(mask_tree, hf_mount_pathconf_error_max_canon,
288 offset + 2, 2, pc_mask);
289 proto_tree_add_item(mask_tree, hf_mount_pathconf_error_max_input,
290 offset + 2, 2, pc_mask);
291 proto_tree_add_item(mask_tree, hf_mount_pathconf_error_name_max,
292 offset + 2, 2, pc_mask);
293 proto_tree_add_item(mask_tree, hf_mount_pathconf_error_path_max,
294 offset + 2, 2, pc_mask);
295 proto_tree_add_item(mask_tree, hf_mount_pathconf_error_pipe_buf,
296 offset + 2, 2, pc_mask);
297 proto_tree_add_item(mask_tree, hf_mount_pathconf_chown_restricted,
298 offset + 2, 2, pc_mask);
299 proto_tree_add_item(mask_tree, hf_mount_pathconf_no_trunc,
300 offset + 2, 2, pc_mask);
301 proto_tree_add_item(mask_tree, hf_mount_pathconf_error_vdisable,
302 offset + 2, 2, pc_mask);
308 /* proc number, "proc name", dissect_request, dissect_reply */
309 /* NULL as function pointer means: take the generic one. */
311 /* Mount protocol version 1, RFC 1094 */
312 static const vsff mount1_proc[] = {
313 { 0, "NULL", NULL, NULL },
314 { MOUNTPROC_MNT, "MNT",
315 dissect_mount_dirpath_call, dissect_mount_mnt_reply },
316 { MOUNTPROC_DUMP, "DUMP",
318 { MOUNTPROC_UMNT, "UMNT",
319 dissect_mount_dirpath_call, NULL },
320 { MOUNTPROC_UMNTALL, "UMNTALL",
322 { MOUNTPROC_EXPORT, "EXPORT",
324 { MOUNTPROC_EXPORTALL, "EXPORTALL",
326 { 0, NULL, NULL, NULL }
328 /* end of mount version 1 */
331 /* Mount protocol version 2, private communication from somebody at Sun;
332 mount V2 is V1 plus MOUNTPROC_PATHCONF to fetch information for the
333 POSIX "pathconf()" call. */
334 static const vsff mount2_proc[] = {
335 { 0, "NULL", NULL, NULL },
336 { MOUNTPROC_MNT, "MNT",
337 dissect_mount_dirpath_call, dissect_mount_mnt_reply },
338 { MOUNTPROC_DUMP, "DUMP",
340 { MOUNTPROC_UMNT, "UMNT",
341 dissect_mount_dirpath_call, NULL },
342 { MOUNTPROC_UMNTALL, "UMNTALL",
344 { MOUNTPROC_EXPORT, "EXPORT",
346 { MOUNTPROC_EXPORTALL, "EXPORTALL",
348 { MOUNTPROC_EXPORTALL, "EXPORTALL",
350 { MOUNTPROC_PATHCONF, "PATHCONF",
351 dissect_mount_dirpath_call, dissect_mount_pathconf_reply },
352 { 0, NULL, NULL, NULL }
354 /* end of mount version 2 */
357 /* RFC 1813, Page 107 */
358 static const value_string mount3_mountstat3[] =
364 { 13, "ERR_ACCESS" },
365 { 20, "ERR_NOTDIR" },
367 { 63, "ERR_NAMETOOLONG" },
368 { 10004, "ERR_NOTSUPP" },
369 { 10006, "ERR_SERVERFAULT" },
374 /* RFC 1813, Page 107 */
376 dissect_mountstat3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
377 int hfindex, guint32* status)
381 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
382 mountstat3 = EXTRACT_UINT(pd, offset+0);
385 proto_tree_add_item(tree, hfindex, offset, 4, mountstat3);
389 *status = mountstat3;
394 /* RFC 1831, Page 109 */
396 dissect_mount3_mnt_reply(const u_char *pd, int offset, frame_data *fd,
400 guint32 auth_flavors;
402 guint32 auth_flavor_i;
404 offset = dissect_mountstat3(pd, offset, fd, tree, hf_mount_status, &status);
407 offset = dissect_nfs_fh3(pd,offset,fd,tree,"fhandle");
408 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
409 auth_flavors = EXTRACT_UINT(pd,offset+0);
410 proto_tree_add_item(tree,hf_mount_flavors,
411 offset, 4, auth_flavors);
413 for (auth_flavor_i = 0 ; auth_flavor_i < hf_mount_flavors ; auth_flavor_i++) {
414 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
415 auth_flavor = EXTRACT_UINT(pd,offset+0);
416 proto_tree_add_item(tree,hf_mount_flavor,
417 offset, 4, auth_flavor);
429 /* Mount protocol version 3, RFC 1813 */
430 static const vsff mount3_proc[] = {
431 { 0, "NULL", NULL, NULL },
432 { MOUNTPROC_MNT, "MNT",
433 dissect_mount_dirpath_call, dissect_mount3_mnt_reply },
434 { MOUNTPROC_DUMP, "DUMP",
436 { MOUNTPROC_UMNT, "UMNT",
437 dissect_mount_dirpath_call, NULL },
438 { MOUNTPROC_UMNTALL, "UMNTALL",
440 { MOUNTPROC_EXPORT, "EXPORT",
442 { 0, NULL, NULL, NULL }
444 /* end of Mount protocol version 3 */
448 proto_register_mount(void)
450 static hf_register_info hf[] = {
452 "Path", "mount.path", FT_STRING, BASE_DEC,
454 { &hf_mount_status, {
455 "Status", "mount.status", FT_UINT32, BASE_DEC,
456 VALS(mount3_mountstat3), 0, "Status" }},
457 { &hf_mount_pathconf_link_max, {
458 "Maximum number of links to a file", "mount.pathconf.link_max",
460 NULL, 0, "Maximum number of links allowed to a file" }},
461 { &hf_mount_pathconf_max_canon, {
462 "Maximum terminal input line length", "mount.pathconf.max_canon",
464 NULL, 0, "Max tty input line length" }},
465 { &hf_mount_pathconf_max_input, {
466 "Terminal input buffer size", "mount.pathconf.max_input",
468 NULL, 0, "Terminal input buffer size" }},
469 { &hf_mount_pathconf_name_max, {
470 "Maximum file name length", "mount.pathconf.name_max",
472 NULL, 0, "Maximum file name length" }},
473 { &hf_mount_pathconf_path_max, {
474 "Maximum path name length", "mount.pathconf.path_max",
476 NULL, 0, "Maximum path name length" }},
477 { &hf_mount_pathconf_pipe_buf, {
478 "Pipe buffer size", "mount.pathconf.pipe_buf",
480 NULL, 0, "Maximum amount of data that can be written atomically to a pipe" }},
481 { &hf_mount_pathconf_vdisable, {
482 "VDISABLE character", "mount.pathconf.pipe_buf",
484 NULL, 0, "Character value to disable a terminal special character" }},
485 { &hf_mount_pathconf_mask, {
486 "Reply error/status bits", "mount.pathconf.mask",
488 NULL, 0, "Bit mask with error and status bits" }},
489 { &hf_mount_pathconf_error_all, {
490 "ERROR_ALL", "mount.pathconf.mask.error_all",
491 FT_BOOLEAN, 16, TFS(&tos_error_all),
493 { &hf_mount_pathconf_error_link_max, {
494 "ERROR_LINK_MAX", "mount.pathconf.mask.error_link_max",
495 FT_BOOLEAN, 16, TFS(&tos_error_link_max),
496 PC_ERROR_LINK_MAX, "" }},
497 { &hf_mount_pathconf_error_max_canon, {
498 "ERROR_MAX_CANON", "mount.pathconf.mask.error_max_canon",
499 FT_BOOLEAN, 16, TFS(&tos_error_max_canon),
500 PC_ERROR_MAX_CANON, "" }},
501 { &hf_mount_pathconf_error_max_input, {
502 "ERROR_MAX_INPUT", "mount.pathconf.mask.error_max_input",
503 FT_BOOLEAN, 16, TFS(&tos_error_max_input),
504 PC_ERROR_MAX_INPUT, "" }},
505 { &hf_mount_pathconf_error_name_max, {
506 "ERROR_NAME_MAX", "mount.pathconf.mask.error_name_max",
507 FT_BOOLEAN, 16, TFS(&tos_error_name_max),
508 PC_ERROR_NAME_MAX, "" }},
509 { &hf_mount_pathconf_error_path_max, {
510 "ERROR_PATH_MAX", "mount.pathconf.mask.error_path_max",
511 FT_BOOLEAN, 16, TFS(&tos_error_path_max),
512 PC_ERROR_PATH_MAX, "" }},
513 { &hf_mount_pathconf_error_pipe_buf, {
514 "ERROR_PIPE_BUF", "mount.pathconf.mask.error_pipe_buf",
515 FT_BOOLEAN, 16, TFS(&tos_error_pipe_buf),
516 PC_ERROR_PIPE_BUF, "" }},
517 { &hf_mount_pathconf_chown_restricted, {
518 "CHOWN_RESTRICTED", "mount.pathconf.mask.chown_restricted",
519 FT_BOOLEAN, 16, TFS(&tos_chown_restricted),
520 PC_CHOWN_RESTRICTED, "" }},
521 { &hf_mount_pathconf_no_trunc, {
522 "NO_TRUNC", "mount.pathconf.mask.no_trunc",
523 FT_BOOLEAN, 16, TFS(&tos_no_trunc),
525 { &hf_mount_pathconf_error_vdisable, {
526 "ERROR_VDISABLE", "mount.pathconf.mask.error_vdisable",
527 FT_BOOLEAN, 16, TFS(&tos_error_vdisable),
528 PC_ERROR_VDISABLE, "" }},
529 { &hf_mount_flavors, {
530 "Flavors", "mount.flavors", FT_UINT32, BASE_DEC,
531 NULL, 0, "Flavors" }},
532 { &hf_mount_flavor, {
533 "Flavor", "mount.flavor", FT_UINT32, BASE_DEC,
534 VALS(rpc_auth_flavor), 0, "Flavor" }},
536 static gint *ett[] = {
538 &ett_mount_pathconf_mask,
541 proto_mount = proto_register_protocol("Mount Service", "mount");
542 proto_register_field_array(proto_mount, hf, array_length(hf));
543 proto_register_subtree_array(ett, array_length(ett));
545 /* Register the protocol as RPC */
546 rpc_init_prog(proto_mount, MOUNT_PROGRAM, ett_mount);
547 /* Register the procedure tables */
548 rpc_init_proc_table(MOUNT_PROGRAM, 1, mount1_proc);
549 rpc_init_proc_table(MOUNT_PROGRAM, 2, mount2_proc);
550 rpc_init_proc_table(MOUNT_PROGRAM, 3, mount3_proc);