1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 * Copyright 2017 Gary Mills
27 */
28
29#include <sys/types.h>
30#include <sys/errno.h>
31#include <sys/tiuser.h>
32#include <setjmp.h>
33
34#include <rpc/types.h>
35#include <rpc/xdr.h>
36#include <rpc/auth.h>
37#include <rpc/clnt.h>
38#include <rpc/rpc_msg.h>
39#include <rpc/rpcsec_gss.h>
40#include <string.h>
41#include "snoop.h"
42
43extern jmp_buf xdr_err;
44
45struct cache_struct *find_xid();
46char *nameof_prog(int prog);
47static void print_rpc_gss_init_arg(int, struct cache_struct *);
48static void print_rpc_gss_init_res(int);
49
50char *
51rpcsec_gss_proc_to_string(unsigned int proc)
52{
53	switch (proc) {
54	case RPCSEC_GSS_DATA:	return "RPCSEC_GSS_DATA"; break;
55	case RPCSEC_GSS_INIT:	return "RPCSEC_GSS_INIT"; break;
56	case RPCSEC_GSS_CONTINUE_INIT:
57				return ("RPCSEC_GSS_CONTINUE_INIT");
58	case RPCSEC_GSS_DESTROY:
59				return ("RPCSEC_GSS_DESTROY");
60	default:		return ("unknown");
61
62	}
63}
64
65
66char *
67rpcsec_gss_service_to_string(rpc_gss_service_t service)
68{
69	switch (service) {
70	case rpc_gss_svc_none:	return "none"; break;
71	case rpc_gss_svc_integrity: return "integrity"; break;
72	case rpc_gss_svc_privacy: return "privacy"; break;
73	default:		return "unknown";	  break;
74
75	}
76}
77
78/*
79 *  Print detailed RPCSEC_GSS cred data.
80 */
81void
82print_rpcsec_gss_cred(int xid, int authlen)
83{
84	unsigned int seq_num;
85	unsigned int handle_len;
86	unsigned int rpcsec_gss_ver;
87	rpc_gss_service_t rpcsec_gss_service;
88	unsigned int rpcsec_gss_proc;
89	char *handle, *line;
90	struct cache_struct *x;
91	int pos;
92
93	pos = getxdr_pos();
94	rpcsec_gss_ver = getxdr_u_long();
95
96	/* see if we know this version or not */
97
98	if (rpcsec_gss_ver != 1) {
99		(void) showxdr_hex(authlen, "[%s]");
100		return;
101	}
102
103	rpcsec_gss_proc   = getxdr_u_long();
104	seq_num    = getxdr_u_long();
105	rpcsec_gss_service    = getxdr_enum();
106
107	(void) sprintf(get_line(pos, getxdr_pos()),
108	    "   version = %u",  rpcsec_gss_ver);
109
110	(void) sprintf(get_line(pos, getxdr_pos()),
111	    "   gss control procedure = %u (%s)",
112	    rpcsec_gss_proc,
113	    rpcsec_gss_proc_to_string(rpcsec_gss_proc));
114
115	(void) sprintf(get_line(pos, getxdr_pos()),
116	    "   sequence num = %u", seq_num);
117
118	(void) sprintf(get_line(pos, getxdr_pos()),
119	    "   service = %d (%s)", rpcsec_gss_service,
120	    rpcsec_gss_service_to_string(rpcsec_gss_service));
121	pos = getxdr_pos();
122	handle_len = getxdr_u_long();
123	handle = getxdr_hex(handle_len);
124	line = get_line(pos, getxdr_pos());
125	sprintf(line, "   handle: length = %d, data = [%s]",
126	    handle_len, handle);
127	x = find_xid(xid);
128	if (x) {
129		x->xid_gss_proc    = rpcsec_gss_proc;
130		x->xid_gss_service = rpcsec_gss_service;
131	}
132}
133
134/*
135 *  Based on different RPCSEC_GSS services supported, maybe a
136 *  special handling is needed before printing the arguments.
137 *
138 *  For integrity service : print the sequence number.
139 *  For privacy service : do not print the arguments.
140 */
141int
142rpcsec_gss_pre_proto(int type, int flags, int xid,
143					int prog, int vers, int proc)
144{
145	int seq;
146	struct cache_struct *x;
147
148	if (! (x = find_xid(xid)))
149		return (0);
150
151	switch (x->xid_gss_service) {
152	case rpc_gss_svc_default:
153	case rpc_gss_svc_none:
154		break; /* standard call args */
155	case rpc_gss_svc_integrity:
156		/* length of rpc_gss_data_t encoded in the databody_integ */
157		getxdr_u_long();
158		/* read the seq number */
159		seq = getxdr_u_long();
160		if (flags & F_ALLSUM) {
161			(void) sprintf(get_sum_line(), "%s %c seq_num = %u",
162			    "RPC RPCSEC_GSS", type == CALL ? 'C' : 'R',
163			    seq);
164		} else if (flags & F_DTAIL) {
165			sprintf(get_line(0, 0),
166			    "RPCSEC_GSS data seq_num = %u", seq);
167			show_space();
168		}
169		/* call args follow */
170		break;
171	case rpc_gss_svc_privacy: {
172		char *progname = nameof_prog(prog);
173		char prognum[32];
174
175		if (*progname == '?') {
176			sprintf(prognum, "%d", prog);
177			progname = prognum;
178		}
179
180		if (flags & F_SUM || flags & F_ALLSUM) {
181			(void) sprintf(get_sum_line(),
182			    "%s %c %s ver(%d) proc(%d) (data encrypted) ",
183			    "RPC RPCSEC_GSS", type == CALL ? 'C' : 'R',
184			    progname, vers, proc);
185		} else if (flags & F_DTAIL) {
186			unsigned int args_len;
187
188			args_len = getxdr_u_long();
189			sprintf(get_line(0, 0),
190			    "RPCSEC_GSS %s ver(%d) proc(%d)",
191			    progname, vers, proc);
192			sprintf(get_line(0, 0),
193			    "(%s args encrypted, len = %d bytes)",
194			    type == CALL ? "CALL" : "REPLY", args_len);
195			show_space();
196		}
197		}
198		return (1);
199
200	default:
201		break;
202	}
203	return (0);
204}
205
206/*
207 *  Based on different RPCSEC_GSS services supported, maybe a
208 *  special handling is needed after printing the arguments.
209 *
210 *  For integrity service : print the checksum.
211 */
212void
213rpcsec_gss_post_proto(int flags, int xid)
214{
215	char *line;
216
217	struct cache_struct *x;
218
219	if (! (x = find_xid(xid)))
220		return;
221
222	switch (x->xid_gss_service) {
223	case rpc_gss_svc_default:
224	case rpc_gss_svc_none:
225	case rpc_gss_svc_privacy:
226		/* nothing left */
227		break;
228	case rpc_gss_svc_integrity:
229		if (flags & F_ALLSUM) {
230			line = get_sum_line();
231			sprintf(line, "RPC RPCSEC_GSS C (checksum)");
232		} else if (flags & F_DTAIL) {
233			unsigned int checksum_len;
234			char *checksum;
235
236			show_header("RPC:  ", "RPCSEC_GSS", 0);
237			show_space();
238			checksum_len = getxdr_u_long();
239			checksum = getxdr_hex(checksum_len);
240			sprintf(get_line(0, 0),
241			    "checksum: len = %d", checksum_len);
242			sprintf(get_line(0, 0), "[%s]", checksum);
243			show_trailer();
244		}
245		break;
246	default:
247		break;
248	}
249}
250
251/*
252 *  Print RPCSEC_GSS control procedures protocol data,
253 *  No-op for RPCSEC_GSS_DATA.
254 */
255int
256rpcsec_gss_control_proc(int type, int flags, int xid)
257{
258	int seq;
259
260	struct cache_struct *x;
261
262	if (! (x = find_xid(xid)))
263		return (0);
264
265	if (x->xid_gss_proc != RPCSEC_GSS_DATA) {
266		if (flags & F_SUM) {
267			if (type == CALL) {
268				(void) sprintf(get_sum_line(), "%s %c %u (%s)",
269				    "RPC RPCSEC_GSS",
270				    type == CALL ? 'C' : 'R',
271				    x->xid_gss_proc,
272				    rpcsec_gss_proc_to_string(x->xid_gss_proc));
273			}
274		} else if (flags & F_DTAIL) {
275			if (x->xid_gss_proc == RPCSEC_GSS_INIT ||
276			    x->xid_gss_proc == RPCSEC_GSS_CONTINUE_INIT) {
277				if (type == CALL) {
278					print_rpc_gss_init_arg(flags, x);
279				} else {
280					print_rpc_gss_init_res(flags);
281				}
282			}
283		}
284		return (1);
285	}
286
287	return (0);
288}
289
290/*
291 *  Skip the header RPCSEC_GSS cred data and
292 *  put service and control type in the xid cache.
293 */
294void
295extract_rpcsec_gss_cred_info(int xid)
296{
297	unsigned int handle_len;
298	unsigned int rpcsec_gss_ver;
299	rpc_gss_service_t rpcsec_gss_service;
300	unsigned int rpcsec_gss_proc;
301	struct cache_struct *x;
302
303	(void) getxdr_u_long();
304	rpcsec_gss_ver = getxdr_u_long();
305	/* see if we know this version or not */
306	if (rpcsec_gss_ver != 1) {
307		longjmp(xdr_err, 1);
308	}
309	rpcsec_gss_proc   = getxdr_u_long();
310	(void) getxdr_u_long();
311	rpcsec_gss_service    = getxdr_enum();
312	/* skip the handle */
313	xdr_skip(RNDUP(getxdr_u_long()));
314
315	if (x = find_xid(xid)) {
316		x->xid_gss_service = rpcsec_gss_service;
317		x->xid_gss_proc = rpcsec_gss_proc;
318	}
319
320}
321
322/*
323 *  Print the argument data for the RPCSEC_GSS_INIT control procedure.
324 */
325static void
326print_rpc_gss_init_arg(int flags, struct cache_struct *x)
327{
328
329	char  *line;
330	unsigned int token_len;
331	int pos = 0;
332
333	/*
334	 *  see if we need to print out the rpc_gss_init_arg structure
335	 *  or not.
336	 */
337
338	if (x->xid_gss_proc != RPCSEC_GSS_INIT &&
339	    x->xid_gss_proc != RPCSEC_GSS_CONTINUE_INIT) {
340		return;
341	}
342
343	/* print it */
344
345	(void) sprintf(get_line(pos, getxdr_pos()),
346	    "RPCSEC_GSS_INIT args:");
347
348	pos = getxdr_pos();
349	token_len = getxdr_u_long();
350	(void) getxdr_hex(token_len);
351	line = get_line(pos, getxdr_pos());
352	sprintf(line, "   gss token: length = %d, data = [%d bytes]",
353	    token_len, token_len);
354
355	show_trailer();
356}
357
358/*
359 *  Print the results data for the RPCSEC_GSS_INIT control procedure.
360 */
361void
362print_rpc_gss_init_res(int flags)
363{
364
365	char *handle, *line;
366	unsigned int token_len, handle_len;
367	unsigned int major, minor, seq_window;
368
369	int pos = 0;
370	struct cache_struct *x;
371
372	/* print it */
373
374	(void) sprintf(get_line(pos, getxdr_pos()), "RPCSEC_GSS_INIT result:");
375
376	pos = getxdr_pos();
377	handle_len = getxdr_u_long();
378	handle = getxdr_hex(handle_len);
379	line = get_line(pos, getxdr_pos());
380	sprintf(line, "   handle: length = %d, data = [%s]",
381	    handle_len, handle);
382	pos = getxdr_pos();
383	major = getxdr_u_long();
384	minor = getxdr_u_long();
385	seq_window = getxdr_u_long();
386
387	(void) sprintf(get_line(pos, getxdr_pos()),
388	    "   gss_major status = %u", major);
389
390	(void) sprintf(get_line(pos, getxdr_pos()),
391	    "   gss_minor status = %u", minor);
392
393	(void) sprintf(get_line(pos, getxdr_pos()),
394	    "   sequence window  = %u", seq_window);
395	pos = getxdr_pos();
396	token_len = getxdr_u_long();
397	(void) getxdr_hex(token_len);
398	line = get_line(pos, getxdr_pos());
399	sprintf(line, "   gss token: length = %d, data = [%d bytes]",
400	    token_len, token_len);
401	show_trailer();
402}
403