Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-pcnfsd.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-pcnfsd.c
2
 * Routines for PCNFSD dissection
3
 *
4
 * Wireshark - Network traffic analyzer
5
 * By Gerald Combs <gerald@wireshark.org>
6
 * Copyright 1998 Gerald Combs
7
 *
8
 * Copied from packet-ypbind.c
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
14
/*
15
Protocol information comes from the book
16
    "NFS Illustrated" by Brent Callaghan, ISBN 0-201-32570-5
17
*/
18
19
20
#include "config.h"
21
22
23
#include "packet-rpc.h"
24
#include "packet-pcnfsd.h"
25
26
void proto_register_pcnfsd(void);
27
void proto_reg_handoff_pcnfsd(void);
28
29
static int proto_pcnfsd;
30
static int hf_pcnfsd_procedure_v1;
31
static int hf_pcnfsd_procedure_v2;
32
static int hf_pcnfsd_auth_client;
33
static int hf_pcnfsd_auth_ident_obscure;
34
static int hf_pcnfsd_auth_ident_clear;
35
static int hf_pcnfsd_auth_password;
36
static int hf_pcnfsd_auth_password_obscure;
37
static int hf_pcnfsd_auth_password_clear;
38
static int hf_pcnfsd_comment;
39
static int hf_pcnfsd_status;
40
static int hf_pcnfsd_uid;
41
static int hf_pcnfsd_gid;
42
static int hf_pcnfsd_gids_count;
43
static int hf_pcnfsd_homedir;
44
static int hf_pcnfsd_def_umask;
45
static int hf_pcnfsd_mapreq;
46
static int hf_pcnfsd_mapreq_status;
47
static int hf_pcnfsd_username;
48
49
50
static int ett_pcnfsd;
51
static int ett_pcnfsd_auth_ident;
52
static int ett_pcnfsd_auth_password;
53
static int ett_pcnfsd_gids;
54
55
static int
56
dissect_pcnfsd_username(tvbuff_t *tvb, int offset, proto_tree *tree)
57
0
{
58
0
    return dissect_rpc_string(tvb, tree, hf_pcnfsd_username, offset, NULL);
59
0
}
60
61
#define MAP_REQ_UID     0
62
#define MAP_REQ_GID     1
63
#define MAP_REQ_UNAME   2
64
#define MAP_REQ_GNAME   3
65
66
static const value_string names_mapreq[] =
67
{
68
    { MAP_REQ_UID,   "MAP_REQ_UID"   },
69
    { MAP_REQ_GID,   "MAP_REQ_GID"   },
70
    { MAP_REQ_UNAME, "MAP_REQ_UNAME" },
71
    { MAP_REQ_GNAME, "MAP_REQ_GNAME" },
72
    { 0,  NULL    }
73
};
74
75
static int
76
dissect_pcnfsd2_dissect_mapreq_arg_item(tvbuff_t *tvb, int offset,
77
    packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
78
0
{
79
0
    proto_tree_add_item(tree, hf_pcnfsd_mapreq, tvb, offset, 4, ENC_BIG_ENDIAN);
80
0
    offset += 4;
81
82
0
    offset = dissect_rpc_uint32(tvb, tree, hf_pcnfsd_uid, offset);
83
84
0
    offset = dissect_pcnfsd_username(tvb, offset, tree);
85
86
0
    return offset;
87
0
}
88
89
static int
90
dissect_pcnfsd2_mapid_call(tvbuff_t *tvb, packet_info *pinfo,
91
    proto_tree *tree, void* data _U_)
92
0
{
93
0
    int offset = 0;
94
0
    offset = dissect_rpc_string(tvb, tree, hf_pcnfsd_comment, offset, NULL);
95
96
0
    offset = dissect_rpc_list(tvb, pinfo, tree, offset,
97
0
          dissect_pcnfsd2_dissect_mapreq_arg_item, NULL);
98
99
0
    return offset;
100
0
}
101
102
#define MAP_RES_OK      0
103
#define MAP_RES_UNKNOWN 1
104
#define MAP_RES_DENIED  2
105
106
static const value_string names_maprstat[] =
107
{
108
    { MAP_RES_OK,      "MAP_RES_OK" },
109
    { MAP_RES_UNKNOWN, "MAP_RES_UNKNOWN"    },
110
    { MAP_RES_DENIED,  "MAP_RES_DENIED" },
111
    { 0,    NULL    }
112
};
113
114
static int
115
dissect_pcnfsd2_dissect_mapreq_res_item(tvbuff_t *tvb, int offset,
116
    packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
117
0
{
118
0
    proto_tree_add_item(tree, hf_pcnfsd_mapreq, tvb, offset, 4, ENC_BIG_ENDIAN);
119
0
    offset += 4;
120
121
0
    proto_tree_add_item(tree, hf_pcnfsd_mapreq_status, tvb, offset, 4, ENC_BIG_ENDIAN);
122
0
    offset += 4;
123
124
0
    offset = dissect_rpc_uint32(tvb, tree, hf_pcnfsd_uid, offset);
125
126
0
    offset = dissect_pcnfsd_username(tvb, offset, tree);
127
128
0
    return offset;
129
0
}
130
131
static int
132
dissect_pcnfsd2_mapid_reply(tvbuff_t *tvb, packet_info *pinfo,
133
    proto_tree *tree, void* data _U_)
134
0
{
135
0
    int offset = 0;
136
0
    offset = dissect_rpc_string(tvb, tree, hf_pcnfsd_comment, offset, NULL);
137
138
0
    offset = dissect_rpc_list(tvb, pinfo, tree, offset,
139
0
          dissect_pcnfsd2_dissect_mapreq_res_item, NULL);
140
141
0
    return offset;
142
0
}
143
144
/* "NFS Illustrated 14.7.13 */
145
static char *
146
pcnfsd_decode_obscure(wmem_allocator_t *pool, const char* data, int len)
147
0
{
148
0
    char *decoded_buf;
149
0
    char *decoded_data;
150
151
0
    decoded_buf = (char *)wmem_alloc(pool, len);
152
0
    decoded_data = decoded_buf;
153
0
    for ( ; len>0 ; len--, data++, decoded_data++) {
154
0
        *decoded_data = (*data ^ 0x5b) & 0x7f;
155
0
    }
156
0
    return decoded_buf;
157
0
}
158
159
160
/* "NFS Illustrated" 14.7.13 */
161
static int
162
dissect_pcnfsd2_auth_call(tvbuff_t *tvb, packet_info *pinfo,
163
    proto_tree *tree, void* data _U_)
164
0
{
165
0
    int         newoffset;
166
0
    const char *ident         = NULL;
167
0
    const char *ident_decoded;
168
0
    proto_item *ident_item;
169
0
    proto_tree *ident_tree;
170
0
    const char *password      = NULL;
171
0
    proto_item *password_item = NULL;
172
0
    proto_tree *password_tree = NULL;
173
0
    int offset = 0;
174
175
0
    offset = dissect_rpc_string(tvb, tree,
176
0
        hf_pcnfsd_auth_client, offset, NULL);
177
178
0
    ident_tree = proto_tree_add_subtree(tree, tvb,
179
0
                offset, -1, ett_pcnfsd_auth_ident, &ident_item, "Authentication Ident");
180
181
0
    newoffset = dissect_rpc_string(tvb, ident_tree,
182
0
        hf_pcnfsd_auth_ident_obscure, offset, &ident);
183
0
    proto_item_set_len(ident_item, newoffset-offset);
184
185
0
    if (ident) {
186
        /* Only attempt to decode the ident if it has been specified */
187
0
        if (strcmp(ident, RPC_STRING_EMPTY) != 0)
188
0
            ident_decoded = pcnfsd_decode_obscure(pinfo->pool, ident, (int)strlen(ident));
189
0
        else
190
0
            ident_decoded = ident;
191
192
0
        if (ident_tree)
193
0
            proto_tree_add_string(ident_tree,
194
0
                hf_pcnfsd_auth_ident_clear,
195
0
                tvb, offset+4, (int)strlen(ident_decoded), ident_decoded);
196
0
    }
197
0
    if (ident_item) {
198
0
        proto_item_set_text(ident_item, "Authentication Ident: %s",
199
0
            ident);
200
0
    }
201
202
0
    offset = newoffset;
203
204
0
    password_item = proto_tree_add_string_format(tree, hf_pcnfsd_auth_password,
205
0
                                          tvb, 0, 0, "", "Authentication Password");
206
0
    password_tree = proto_item_add_subtree(password_item, ett_pcnfsd_auth_password);
207
208
0
    newoffset = dissect_rpc_string(tvb, password_tree,
209
0
        hf_pcnfsd_auth_password_obscure, offset, &password);
210
0
    if (password_item) {
211
0
        proto_item_set_len(password_item, newoffset-offset);
212
0
    }
213
214
0
    if (password) {
215
        /* Only attempt to decode the password if it has been specified */
216
0
        if (strcmp(password, RPC_STRING_EMPTY))
217
0
            pcnfsd_decode_obscure(pinfo->pool, password, (int)strlen(password));
218
219
0
        if (password_tree)
220
0
            proto_tree_add_string(password_tree,
221
0
                hf_pcnfsd_auth_password_clear,
222
0
                tvb, offset+4, (int)strlen(password), password);
223
0
    }
224
0
    if (password_item) {
225
0
        proto_item_set_text(password_item, "Authentication Password: %s",
226
0
            password);
227
0
    }
228
229
0
    offset = newoffset;
230
231
0
    offset = dissect_rpc_string(tvb, tree,
232
0
        hf_pcnfsd_comment, offset, NULL);
233
234
0
    return offset;
235
0
}
236
237
238
/* "NFS Illustrated" 14.7.13 */
239
static int
240
dissect_pcnfsd2_auth_reply(tvbuff_t *tvb, packet_info *pinfo _U_,
241
    proto_tree *tree, void* data _U_)
242
0
{
243
0
    int         gids_count;
244
0
    proto_tree *gtree;
245
0
    int         gids_i;
246
0
    int offset = 0;
247
248
0
    offset = dissect_rpc_uint32(tvb, tree, hf_pcnfsd_status, offset);
249
0
    offset = dissect_rpc_uint32(tvb, tree, hf_pcnfsd_uid, offset);
250
0
    offset = dissect_rpc_uint32(tvb, tree, hf_pcnfsd_gid, offset);
251
0
    gids_count = tvb_get_ntohl(tvb,offset+0);
252
0
    gtree = proto_tree_add_subtree_format(tree, tvb,
253
0
            offset, 4+gids_count*4, ett_pcnfsd_gids, NULL, "Group IDs: %d", gids_count);
254
255
0
    proto_tree_add_item(gtree, hf_pcnfsd_gids_count, tvb, offset, 4, ENC_BIG_ENDIAN);
256
257
0
    offset += 4;
258
0
    for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
259
0
        offset = dissect_rpc_uint32(tvb, gtree,
260
0
                hf_pcnfsd_gid, offset);
261
0
    }
262
0
    offset = dissect_rpc_string(tvb, tree,
263
0
        hf_pcnfsd_homedir, offset, NULL);
264
    /* should be signed int32 */
265
0
    offset = dissect_rpc_uint32(tvb, tree, hf_pcnfsd_def_umask, offset);
266
0
    offset = dissect_rpc_string(tvb, tree,
267
0
        hf_pcnfsd_comment, offset, NULL);
268
269
0
    return offset;
270
0
}
271
272
273
/* "NFS Illustrated", 14.6 */
274
/* proc number, "proc name", dissect_request, dissect_reply */
275
static const vsff pcnfsd1_proc[] = {
276
    { 0,    "NULL",     dissect_rpc_void,    dissect_rpc_void },
277
    { 1,    "AUTH",     dissect_rpc_unknown, dissect_rpc_unknown },
278
    { 2,    "PR_INIT",  dissect_rpc_unknown, dissect_rpc_unknown },
279
    { 3,    "PR_START", dissect_rpc_unknown, dissect_rpc_unknown },
280
    { 0,    NULL,       NULL,                NULL }
281
};
282
static const value_string pcnfsd1_proc_vals[] = {
283
    { 0,    "NULL" },
284
    { 1,    "AUTH" },
285
    { 2,    "PR_INIT" },
286
    { 3,    "PR_START" },
287
    { 0,    NULL }
288
};
289
/* end of PCNFS version 1 */
290
291
292
/* "NFS Illustrated", 14.7 */
293
static const vsff pcnfsd2_proc[] = {
294
    {  0,   "NULL",
295
    dissect_rpc_void, dissect_rpc_void },
296
    {  1,   "INFO",       dissect_rpc_unknown, dissect_rpc_unknown },
297
    {  2,   "PR_INIT",    dissect_rpc_unknown, dissect_rpc_unknown },
298
    {  3,   "PR_START",   dissect_rpc_unknown, dissect_rpc_unknown },
299
    {  4,   "PR_LIST",    dissect_rpc_unknown, dissect_rpc_unknown },
300
    {  5,   "PR_QUEUE",   dissect_rpc_unknown, dissect_rpc_unknown },
301
    {  6,   "PR_STATUS",  dissect_rpc_unknown, dissect_rpc_unknown },
302
    {  7,   "PR_CANCEL",  dissect_rpc_unknown, dissect_rpc_unknown },
303
    {  8,   "PR_ADMIN",   dissect_rpc_unknown, dissect_rpc_unknown },
304
    {  9,   "PR_REQUEUE", dissect_rpc_unknown, dissect_rpc_unknown },
305
    { 10,   "PR_HOLD",    dissect_rpc_unknown, dissect_rpc_unknown },
306
    { 11,   "PR_RELEASE", dissect_rpc_unknown, dissect_rpc_unknown },
307
    { 12,   "MAPID",
308
    dissect_pcnfsd2_mapid_call, dissect_pcnfsd2_mapid_reply },
309
    { 13,   "AUTH",
310
    dissect_pcnfsd2_auth_call,  dissect_pcnfsd2_auth_reply },
311
    { 14,   "ALERT",      dissect_rpc_unknown, dissect_rpc_unknown },
312
    { 0,    NULL,         NULL,               NULL }
313
};
314
static const value_string pcnfsd2_proc_vals[] = {
315
    {  0,   "NULL" },
316
    {  1,   "INFO" },
317
    {  2,   "PR_INIT" },
318
    {  3,   "PR_START" },
319
    {  4,   "PR_LIST" },
320
    {  5,   "PR_QUEUE" },
321
    {  6,   "PR_STATUS" },
322
    {  7,   "PR_CANCEL" },
323
    {  8,   "PR_ADMIN" },
324
    {  9,   "PR_REQUEUE" },
325
    { 10,   "PR_HOLD" },
326
    { 11,   "PR_RELEASE" },
327
    { 12,   "MAPID" },
328
    { 13,   "AUTH" },
329
    { 14,   "ALERT" },
330
    { 0,    NULL }
331
};
332
/* end of PCNFS version 2 */
333
334
static const rpc_prog_vers_info pcnfsd_vers_info[] = {
335
  { 1, pcnfsd1_proc, &hf_pcnfsd_procedure_v1 },
336
  { 2, pcnfsd2_proc, &hf_pcnfsd_procedure_v2 },
337
};
338
339
void
340
proto_register_pcnfsd(void)
341
14
{
342
14
    static hf_register_info hf[] = {
343
14
        { &hf_pcnfsd_procedure_v1, {
344
14
                "V1 Procedure", "pcnfsd.procedure_v1", FT_UINT32, BASE_DEC,
345
14
                VALS(pcnfsd1_proc_vals), 0, NULL, HFILL }},
346
14
        { &hf_pcnfsd_procedure_v2, {
347
14
                "V2 Procedure", "pcnfsd.procedure_v2", FT_UINT32, BASE_DEC,
348
14
                VALS(pcnfsd2_proc_vals), 0, NULL, HFILL }},
349
14
        { &hf_pcnfsd_auth_client, {
350
14
                "Authentication Client", "pcnfsd.auth.client", FT_STRING, BASE_NONE,
351
14
                NULL, 0, NULL, HFILL }},
352
14
        { &hf_pcnfsd_auth_ident_obscure, {
353
14
                "Obscure Ident", "pcnfsd.auth.ident.obscure", FT_STRING, BASE_NONE,
354
14
                NULL, 0, "Authentication Obscure Ident", HFILL }},
355
14
        { &hf_pcnfsd_auth_ident_clear, {
356
14
                "Clear Ident", "pcnfsd.auth.ident.clear", FT_STRING, BASE_NONE,
357
14
                NULL, 0, "Authentication Clear Ident", HFILL }},
358
14
        { &hf_pcnfsd_auth_password, {
359
14
                "Password", "pcnfsd.auth.password", FT_STRING, BASE_NONE,
360
14
                NULL, 0, NULL, HFILL }},
361
14
        { &hf_pcnfsd_auth_password_obscure, {
362
14
                "Obscure Password", "pcnfsd.auth.password.obscure", FT_STRING, BASE_NONE,
363
14
                NULL, 0, "Authentication Obscure Password", HFILL }},
364
14
        { &hf_pcnfsd_auth_password_clear, {
365
14
                "Clear Password", "pcnfsd.auth.password.clear", FT_STRING, BASE_NONE,
366
14
                NULL, 0, "Authentication Clear Password", HFILL }},
367
14
        { &hf_pcnfsd_comment, {
368
14
                "Comment", "pcnfsd.comment", FT_STRING, BASE_NONE,
369
14
                NULL, 0, NULL, HFILL }},
370
14
        { &hf_pcnfsd_status, {
371
14
                "Reply Status", "pcnfsd.status", FT_UINT32, BASE_DEC,
372
14
                NULL, 0, NULL, HFILL }},
373
14
        { &hf_pcnfsd_uid, {
374
14
                "User ID", "pcnfsd.uid", FT_UINT32, BASE_DEC,
375
14
                NULL, 0, NULL, HFILL }},
376
14
        { &hf_pcnfsd_gid, {
377
14
                "Group ID", "pcnfsd.gid", FT_UINT32, BASE_DEC,
378
14
                NULL, 0, NULL, HFILL }},
379
14
        { &hf_pcnfsd_gids_count, {
380
14
                "Group ID Count", "pcnfsd.gids.count", FT_UINT32, BASE_DEC,
381
14
                NULL, 0, NULL, HFILL }},
382
14
        { &hf_pcnfsd_homedir, {
383
14
                "Home Directory", "pcnfsd.homedir", FT_STRING, BASE_NONE,
384
14
                NULL, 0, NULL, HFILL }},
385
14
        { &hf_pcnfsd_def_umask, {
386
14
                "def_umask", "pcnfsd.def_umask", FT_UINT32, BASE_OCT,
387
14
                NULL, 0, NULL, HFILL }},
388
14
        { &hf_pcnfsd_mapreq, {
389
14
                "Request", "pcnfsd.mapreq", FT_UINT32, BASE_DEC,
390
14
                VALS(names_mapreq), 0, NULL, HFILL }},
391
14
        { &hf_pcnfsd_mapreq_status, {
392
14
                "Status", "pcnfsd.mapreq_status", FT_UINT32, BASE_DEC,
393
14
                VALS(names_maprstat), 0, NULL, HFILL }},
394
14
        { &hf_pcnfsd_username, {
395
14
                "User name", "pcnfsd.username", FT_STRING, BASE_NONE,
396
14
                NULL, 0, "pcnfsd.username", HFILL }},
397
14
    };
398
399
14
    static int *ett[] = {
400
14
        &ett_pcnfsd,
401
14
        &ett_pcnfsd_auth_ident,
402
14
        &ett_pcnfsd_auth_password,
403
14
        &ett_pcnfsd_gids
404
14
    };
405
406
14
    proto_pcnfsd = proto_register_protocol("PC NFS", "PCNFSD", "pcnfsd");
407
14
    proto_register_field_array(proto_pcnfsd, hf, array_length(hf));
408
14
    proto_register_subtree_array(ett, array_length(ett));
409
14
}
410
411
void
412
proto_reg_handoff_pcnfsd(void)
413
14
{
414
    /* Register the protocol as RPC */
415
14
    rpc_init_prog(proto_pcnfsd, PCNFSD_PROGRAM, ett_pcnfsd,
416
14
                  G_N_ELEMENTS(pcnfsd_vers_info), pcnfsd_vers_info);
417
14
}
418
419
/*
420
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
421
 *
422
 * Local variables:
423
 * c-basic-offset: 4
424
 * tab-width: 8
425
 * indent-tabs-mode: nil
426
 * End:
427
 *
428
 * vi: set shiftwidth=4 tabstop=8 expandtab:
429
 * :indentSize=4:tabSize=8:noTabs=true:
430
 */