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 }