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