1 /*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright 2025 Gleb Smirnoff <glebius@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted providing that the following conditions~
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <err.h>
30
31 #include <netinet/in.h>
32
33 #include <netlink/netlink.h>
34 #include <netlink/netlink_generic.h>
35 #include <netlink/netlink_snl.h>
36 #include <netlink/netlink_snl_generic.h>
37
38 #include <rpc/types.h>
39 #include <rpc/xdr.h>
40 #include <rpc/auth.h>
41 #include <rpc/clnt.h>
42 #include <rpc/rpc_msg.h>
43 #include <rpc/clnt_nl.h>
44
45 #include "genl.h"
46
47 struct nl_request_parsed {
48 uint32_t group;
49 struct nlattr *data;
50 };
51 static const struct snl_attr_parser rpcnl_attr_parser[] = {
52 #define OUT(field) offsetof(struct nl_request_parsed, field)
53 { .type = RPCNL_REQUEST_GROUP, .off = OUT(group),
54 .cb = snl_attr_get_uint32 },
55 { .type = RPCNL_REQUEST_BODY, .off = OUT(data), .cb = snl_attr_get_nla },
56 #undef OUT
57 };
58 SNL_DECLARE_PARSER(request_parser, struct genlmsghdr, snl_f_p_empty,
59 rpcnl_attr_parser);
60
61 void
parser_rpc(struct snl_state * ss __unused,struct nlmsghdr * hdr)62 parser_rpc(struct snl_state *ss __unused, struct nlmsghdr *hdr)
63 {
64 struct nl_request_parsed req;
65 struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
66 XDR xdrs;
67 struct rpc_msg msg;
68 struct opaque_auth *oa;
69 int32_t *buf;
70
71 if (!snl_parse_nlmsg(NULL, hdr, &request_parser, &req))
72 errx(EXIT_FAILURE, "failed to parse RPC message");
73
74 printf("RPC %s: group %8s[0x%2x] length %4u XDR length %4u\n",
75 ghdr->cmd == RPCNL_REQUEST ? "request" : "unknown",
76 group_name(req.group), req.group,
77 hdr->nlmsg_len, NLA_DATA_LEN(req.data));
78
79 xdrmem_create(&xdrs, NLA_DATA(req.data), NLA_DATA_LEN(req.data),
80 XDR_DECODE);
81 if ((buf = XDR_INLINE(&xdrs, 8 * BYTES_PER_XDR_UNIT)) == NULL) {
82 printf("\trunt datagram\n");
83 return;
84 }
85
86 msg.rm_xid = IXDR_GET_U_INT32(buf);
87 msg.rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
88 msg.rm_call.cb_rpcvers = IXDR_GET_U_INT32(buf);
89 msg.rm_call.cb_prog = IXDR_GET_U_INT32(buf);
90 msg.rm_call.cb_vers = IXDR_GET_U_INT32(buf);
91 msg.rm_call.cb_proc = IXDR_GET_U_INT32(buf);
92 printf(" %5s: xid 0x%-8x program 0x%08xv%u procedure %u\n",
93 msg.rm_direction == CALL ? "CALL" : "REPLY", msg.rm_xid,
94 msg.rm_call.cb_prog, msg.rm_call.cb_vers, msg.rm_call.cb_proc);
95
96 oa = &msg.rm_call.cb_cred;
97 oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
98 oa->oa_length = (u_int)IXDR_GET_U_INT32(buf);
99 if (oa->oa_length) {
100 printf("\tcb_cred auth flavor %u length %u\n",
101 oa->oa_flavor, oa->oa_length);
102 /*
103 * Excerpt from rpc_callmsg.c, if we want to parse cb_cred better.
104 if (oa->oa_length > MAX_AUTH_BYTES) {
105 return (FALSE);
106 }
107 if (oa->oa_base == NULL) {
108 oa->oa_base = (caddr_t)
109 mem_alloc(oa->oa_length);
110 if (oa->oa_base == NULL)
111 return (FALSE);
112 }
113 buf = XDR_INLINE(&xdrs, RNDUP(oa->oa_length));
114 if (buf == NULL) {
115 if (xdr_opaque(&xdrs, oa->oa_base,
116 oa->oa_length) == FALSE) {
117 return (FALSE);
118 }
119 } else {
120 memmove(oa->oa_base, buf,
121 oa->oa_length);
122 }
123 */
124 }
125 oa = &msg.rm_call.cb_verf;
126 buf = XDR_INLINE(&xdrs, 2 * BYTES_PER_XDR_UNIT);
127 if (buf == NULL) {
128 if (xdr_enum(&xdrs, &oa->oa_flavor) == FALSE ||
129 xdr_u_int(&xdrs, &oa->oa_length) == FALSE)
130 return;
131 } else {
132 oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
133 oa->oa_length = (u_int)IXDR_GET_U_INT32(buf);
134 }
135 if (oa->oa_length) {
136 printf("\tcb_verf auth flavor %u length %u\n",
137 oa->oa_flavor, oa->oa_length);
138 /*
139 * Excerpt from rpc_callmsg.c, if we want to parse cb_verf better.
140 if (oa->oa_length > MAX_AUTH_BYTES) {
141 return (FALSE);
142 }
143 if (oa->oa_base == NULL) {
144 oa->oa_base = (caddr_t)
145 mem_alloc(oa->oa_length);
146 if (oa->oa_base == NULL)
147 return (FALSE);
148 }
149 buf = XDR_INLINE(&xdrs, RNDUP(oa->oa_length));
150 if (buf == NULL) {
151 if (xdr_opaque(&xdrs, oa->oa_base,
152 oa->oa_length) == FALSE) {
153 return (FALSE);
154 }
155 } else {
156 memmove(oa->oa_base, buf,
157 oa->oa_length);
158 }
159 */
160 }
161 }
162