/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
*/
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/tiuser.h>
#include <setjmp.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/clnt.h>
#include <rpc/rpc_msg.h>
#include <rpc/rpcsec_gss.h>
#include <string.h>
#include "snoop.h"
extern jmp_buf xdr_err;
struct cache_struct *find_xid();
char *nameof_prog(int prog);
static void print_rpc_gss_init_arg(int, struct cache_struct *);
static void print_rpc_gss_init_res(int);
char *
rpcsec_gss_proc_to_string(unsigned int proc)
{
switch (proc) {
case RPCSEC_GSS_DATA: return "RPCSEC_GSS_DATA"; break;
case RPCSEC_GSS_INIT: return "RPCSEC_GSS_INIT"; break;
case RPCSEC_GSS_CONTINUE_INIT:
return ("RPCSEC_GSS_CONTINUE_INIT");
case RPCSEC_GSS_DESTROY:
return ("RPCSEC_GSS_DESTROY");
default: return ("unknown");
}
}
char *
rpcsec_gss_service_to_string(rpc_gss_service_t service)
{
switch (service) {
case rpc_gss_svc_none: return "none"; break;
case rpc_gss_svc_integrity: return "integrity"; break;
case rpc_gss_svc_privacy: return "privacy"; break;
default: return "unknown"; break;
}
}
/*
* Print detailed RPCSEC_GSS cred data.
*/
void
print_rpcsec_gss_cred(int xid, int authlen)
{
unsigned int seq_num;
unsigned int handle_len;
unsigned int rpcsec_gss_ver;
rpc_gss_service_t rpcsec_gss_service;
unsigned int rpcsec_gss_proc;
char *handle, *line;
struct cache_struct *x;
int pos;
pos = getxdr_pos();
rpcsec_gss_ver = getxdr_u_long();
/* see if we know this version or not */
if (rpcsec_gss_ver != 1) {
(void) showxdr_hex(authlen, "[%s]");
return;
}
rpcsec_gss_proc = getxdr_u_long();
seq_num = getxdr_u_long();
rpcsec_gss_service = getxdr_enum();
(void) sprintf(get_line(pos, getxdr_pos()),
" version = %u", rpcsec_gss_ver);
(void) sprintf(get_line(pos, getxdr_pos()),
" gss control procedure = %u (%s)",
rpcsec_gss_proc,
rpcsec_gss_proc_to_string(rpcsec_gss_proc));
(void) sprintf(get_line(pos, getxdr_pos()),
" sequence num = %u", seq_num);
(void) sprintf(get_line(pos, getxdr_pos()),
" service = %d (%s)", rpcsec_gss_service,
rpcsec_gss_service_to_string(rpcsec_gss_service));
pos = getxdr_pos();
handle_len = getxdr_u_long();
handle = getxdr_hex(handle_len);
line = get_line(pos, getxdr_pos());
sprintf(line, " handle: length = %d, data = [%s]",
handle_len, handle);
x = find_xid(xid);
if (x) {
x->xid_gss_proc = rpcsec_gss_proc;
x->xid_gss_service = rpcsec_gss_service;
}
}
/*
* Based on different RPCSEC_GSS services supported, maybe a
* special handling is needed before printing the arguments.
*
* For integrity service : print the sequence number.
* For privacy service : do not print the arguments.
*/
int
rpcsec_gss_pre_proto(int type, int flags, int xid,
int prog, int vers, int proc)
{
int seq;
struct cache_struct *x;
if (! (x = find_xid(xid)))
return (0);
switch (x->xid_gss_service) {
case rpc_gss_svc_default:
case rpc_gss_svc_none:
break; /* standard call args */
case rpc_gss_svc_integrity:
/* length of rpc_gss_data_t encoded in the databody_integ */
getxdr_u_long();
/* read the seq number */
seq = getxdr_u_long();
if (flags & F_ALLSUM) {
(void) sprintf(get_sum_line(), "%s %c seq_num = %u",
"RPC RPCSEC_GSS", type == CALL ? 'C' : 'R',
seq);
} else if (flags & F_DTAIL) {
sprintf(get_line(0, 0),
"RPCSEC_GSS data seq_num = %u", seq);
show_space();
}
/* call args follow */
break;
case rpc_gss_svc_privacy: {
char *progname = nameof_prog(prog);
char prognum[32];
if (*progname == '?') {
sprintf(prognum, "%d", prog);
progname = prognum;
}
if (flags & F_SUM || flags & F_ALLSUM) {
(void) sprintf(get_sum_line(),
"%s %c %s ver(%d) proc(%d) (data encrypted) ",
"RPC RPCSEC_GSS", type == CALL ? 'C' : 'R',
progname, vers, proc);
} else if (flags & F_DTAIL) {
unsigned int args_len;
args_len = getxdr_u_long();
sprintf(get_line(0, 0),
"RPCSEC_GSS %s ver(%d) proc(%d)",
progname, vers, proc);
sprintf(get_line(0, 0),
"(%s args encrypted, len = %d bytes)",
type == CALL ? "CALL" : "REPLY", args_len);
show_space();
}
}
return (1);
default:
break;
}
return (0);
}
/*
* Based on different RPCSEC_GSS services supported, maybe a
* special handling is needed after printing the arguments.
*
* For integrity service : print the checksum.
*/
void
rpcsec_gss_post_proto(int flags, int xid)
{
char *line;
struct cache_struct *x;
if (! (x = find_xid(xid)))
return;
switch (x->xid_gss_service) {
case rpc_gss_svc_default:
case rpc_gss_svc_none:
case rpc_gss_svc_privacy:
/* nothing left */
break;
case rpc_gss_svc_integrity:
if (flags & F_ALLSUM) {
line = get_sum_line();
sprintf(line, "RPC RPCSEC_GSS C (checksum)");
} else if (flags & F_DTAIL) {
unsigned int checksum_len;
char *checksum;
show_header("RPC: ", "RPCSEC_GSS", 0);
show_space();
checksum_len = getxdr_u_long();
checksum = getxdr_hex(checksum_len);
sprintf(get_line(0, 0),
"checksum: len = %d", checksum_len);
sprintf(get_line(0, 0), "[%s]", checksum);
show_trailer();
}
break;
default:
break;
}
}
/*
* Print RPCSEC_GSS control procedures protocol data,
* No-op for RPCSEC_GSS_DATA.
*/
int
rpcsec_gss_control_proc(int type, int flags, int xid)
{
int seq;
struct cache_struct *x;
if (! (x = find_xid(xid)))
return (0);
if (x->xid_gss_proc != RPCSEC_GSS_DATA) {
if (flags & F_SUM) {
if (type == CALL) {
(void) sprintf(get_sum_line(), "%s %c %u (%s)",
"RPC RPCSEC_GSS",
type == CALL ? 'C' : 'R',
x->xid_gss_proc,
rpcsec_gss_proc_to_string(x->xid_gss_proc));
}
} else if (flags & F_DTAIL) {
if (x->xid_gss_proc == RPCSEC_GSS_INIT ||
x->xid_gss_proc == RPCSEC_GSS_CONTINUE_INIT) {
if (type == CALL) {
print_rpc_gss_init_arg(flags, x);
} else {
print_rpc_gss_init_res(flags);
}
}
}
return (1);
}
return (0);
}
/*
* Skip the header RPCSEC_GSS cred data and
* put service and control type in the xid cache.
*/
void
extract_rpcsec_gss_cred_info(int xid)
{
unsigned int seq_num;
unsigned int handle_len;
unsigned int flavor_len;
unsigned int rpcsec_gss_ver;
rpc_gss_service_t rpcsec_gss_service;
unsigned int rpcsec_gss_proc;
struct cache_struct *x;
flavor_len = getxdr_u_long();
rpcsec_gss_ver = getxdr_u_long();
/* see if we know this version or not */
if (rpcsec_gss_ver != 1) {
longjmp(xdr_err, 1);
}
rpcsec_gss_proc = getxdr_u_long();
seq_num = getxdr_u_long();
rpcsec_gss_service = getxdr_enum();
/* skip the handle */
xdr_skip(RNDUP(getxdr_u_long()));
if (x = find_xid(xid)) {
x->xid_gss_service = rpcsec_gss_service;
x->xid_gss_proc = rpcsec_gss_proc;
}
}
/*
* Print the argument data for the RPCSEC_GSS_INIT control procedure.
*/
static void
print_rpc_gss_init_arg(int flags, struct cache_struct *x)
{
char *token, *line;
unsigned int token_len;
int pos = 0;
/*
* see if we need to print out the rpc_gss_init_arg structure
* or not.
*/
if (x->xid_gss_proc != RPCSEC_GSS_INIT &&
x->xid_gss_proc != RPCSEC_GSS_CONTINUE_INIT) {
return;
}
/* print it */
(void) sprintf(get_line(pos, getxdr_pos()),
"RPCSEC_GSS_INIT args:");
pos = getxdr_pos();
token_len = getxdr_u_long();
token = getxdr_hex(token_len);
line = get_line(pos, getxdr_pos());
sprintf(line, " gss token: length = %d, data = [%d bytes]",
token_len, token_len);
show_trailer();
}
/*
* Print the results data for the RPCSEC_GSS_INIT control procedure.
*/
void
print_rpc_gss_init_res(int flags)
{
char *handle, *token, *line;
unsigned int token_len, handle_len;
unsigned int major, minor, seq_window;
int pos = 0;
struct cache_struct *x;
/* print it */
(void) sprintf(get_line(pos, getxdr_pos()), "RPCSEC_GSS_INIT result:");
pos = getxdr_pos();
handle_len = getxdr_u_long();
handle = getxdr_hex(handle_len);
line = get_line(pos, getxdr_pos());
sprintf(line, " handle: length = %d, data = [%s]",
handle_len, handle);
pos = getxdr_pos();
major = getxdr_u_long();
minor = getxdr_u_long();
seq_window = getxdr_u_long();
(void) sprintf(get_line(pos, getxdr_pos()),
" gss_major status = %u", major);
(void) sprintf(get_line(pos, getxdr_pos()),
" gss_minor status = %u", minor);
(void) sprintf(get_line(pos, getxdr_pos()),
" sequence window = %u", seq_window);
pos = getxdr_pos();
token_len = getxdr_u_long();
token = getxdr_hex(token_len);
line = get_line(pos, getxdr_pos());
sprintf(line, " gss token: length = %d, data = [%d bytes]",
token_len, token_len);
show_trailer();
}