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