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 
43 extern jmp_buf xdr_err;
44 
45 struct cache_struct *find_xid();
46 char *nameof_prog(int prog);
47 static void print_rpc_gss_init_arg(int, struct cache_struct *);
48 static void print_rpc_gss_init_res(int);
49 
50 char *
rpcsec_gss_proc_to_string(unsigned int proc)51 rpcsec_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 
66 char *
rpcsec_gss_service_to_string(rpc_gss_service_t service)67 rpcsec_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  */
81 void
print_rpcsec_gss_cred(int xid,int authlen)82 print_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  */
141 int
rpcsec_gss_pre_proto(int type,int flags,int xid,int prog,int vers,int proc)142 rpcsec_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  */
212 void
rpcsec_gss_post_proto(int flags,int xid)213 rpcsec_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  */
255 int
rpcsec_gss_control_proc(int type,int flags,int xid)256 rpcsec_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  */
294 void
extract_rpcsec_gss_cred_info(int xid)295 extract_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  */
325 static void
print_rpc_gss_init_arg(int flags,struct cache_struct * x)326 print_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  */
361 void
print_rpc_gss_init_res(int flags)362 print_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