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 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