xref: /freebsd/usr.bin/genl/parser_rpc.c (revision 88cd1e17a7d8ba66eb5fb04441dd9264d48708b1)
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