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 }