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 }