diff options
Diffstat (limited to 'tools/regression/rpcsec_gss/rpctest.c')
| -rw-r--r-- | tools/regression/rpcsec_gss/rpctest.c | 398 | 
1 files changed, 398 insertions, 0 deletions
| diff --git a/tools/regression/rpcsec_gss/rpctest.c b/tools/regression/rpcsec_gss/rpctest.c new file mode 100644 index 000000000000..a179c82c6b1a --- /dev/null +++ b/tools/regression/rpcsec_gss/rpctest.c @@ -0,0 +1,398 @@ +/*- + * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ + * Authors: Doug Rabson <dfr@rabson.org> + * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __FreeBSD__ +#include <sys/cdefs.h> +#else +#define __unused +#endif + +#include <ctype.h> +#include <err.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rpc/rpc.h> +#include <rpc/rpcsec_gss.h> + +static rpc_gss_principal_t server_acl = NULL; + +static void +usage(void) +{ +	printf("rpctest client | server\n"); +	exit(1); +} + +static void +print_principal(rpc_gss_principal_t principal) +{ +	int i, len, n; +	uint8_t *p; + +	len = principal->len; +	p = (uint8_t *) principal->name; +	while (len > 0) { +		n = len; +		if (n > 16) +			n = 16; +		for (i = 0; i < n; i++) +			printf("%02x ", p[i]); +		for (; i < 16; i++) +			printf("   "); +		printf("|"); +		for (i = 0; i < n; i++) +			printf("%c", isprint(p[i]) ? p[i] : '.'); +		printf("|\n"); +		len -= n; +		p += n; +	} +} + +static void +test_client(int argc, const char **argv) +{ +	rpcproc_t prog = 123456; +	rpcvers_t vers = 1; +	const char *netid = "tcp"; +	char hostname[128], service[128+5]; +	CLIENT *client; +	AUTH *auth; +	const char **mechs; +	rpc_gss_options_req_t options_req; +	rpc_gss_options_ret_t options_ret; +	rpc_gss_service_t svc; +	struct timeval tv; +	enum clnt_stat stat; + +	if (argc == 2) +		strlcpy(hostname, argv[1], sizeof(hostname)); +	else +		gethostname(hostname, sizeof(hostname)); + +	client = clnt_create(hostname, prog, vers, netid); +	if (!client) { +		printf("rpc_createerr.cf_stat = %d\n", +		    rpc_createerr.cf_stat); +		printf("rpc_createerr.cf_error.re_errno = %d\n", +		    rpc_createerr.cf_error.re_errno); +		return; +	} +	 +	strcpy(service, "host"); +	strcat(service, "@"); +	strcat(service, hostname); + +	mechs = rpc_gss_get_mechanisms(); +	auth = NULL; +	while (*mechs) { +		options_req.req_flags = GSS_C_MUTUAL_FLAG; +		options_req.time_req = 600; +		options_req.my_cred = GSS_C_NO_CREDENTIAL; +		options_req.input_channel_bindings = NULL; +		auth = rpc_gss_seccreate(client, service, +		    *mechs, +		    rpc_gss_svc_none, +		    NULL, +		    &options_req, +		    &options_ret); +		if (auth) +			break; +		mechs++; +	} +	if (!auth) { +		clnt_pcreateerror("rpc_gss_seccreate"); +		printf("Can't authenticate with server %s.\n", +		    hostname); +		exit(1); +	} +	client->cl_auth = auth; + +	for (svc = rpc_gss_svc_none; svc <= rpc_gss_svc_privacy; svc++) { +		const char *svc_names[] = { +			"rpc_gss_svc_default", +			"rpc_gss_svc_none", +			"rpc_gss_svc_integrity", +			"rpc_gss_svc_privacy" +		}; +		int num; + +		rpc_gss_set_defaults(auth, svc, NULL); +		tv.tv_sec = 5; +		tv.tv_usec = 0; +		num = 42; +		stat = CLNT_CALL(client, 1, +		    (xdrproc_t) xdr_int, (char *) &num, +		    (xdrproc_t) xdr_int, (char *) &num, tv); +		if (stat == RPC_SUCCESS) { +			printf("succeeded with %s\n", svc_names[svc]); +			if (num != 142) +				printf("unexpected reply %d\n", num); +		} else { +			clnt_perror(client, "call failed"); +		} +	} +	AUTH_DESTROY(auth); +	CLNT_DESTROY(client); +} + +static void +server_program_1(struct svc_req *rqstp, register SVCXPRT *transp) +{ +	rpc_gss_rawcred_t *rcred; +	rpc_gss_ucred_t *ucred; +	int		i, num; + +	if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS) { +		svcerr_weakauth(transp); +		return; +	}		 +		 +	if (!rpc_gss_getcred(rqstp, &rcred, &ucred, NULL)) { +		svcerr_systemerr(transp); +		return; +	} + +	printf("svc=%d, mech=%s, uid=%d, gid=%d, gids={", +	    rcred->service, rcred->mechanism, ucred->uid, ucred->gid); +	for (i = 0; i < ucred->gidlen; i++) { +		if (i > 0) printf(","); +		printf("%d", ucred->gidlist[i]); +	} +	printf("}\n"); + +	switch (rqstp->rq_proc) { +	case 0: +		if (!svc_getargs(transp, (xdrproc_t) xdr_void, 0)) { +			svcerr_decode(transp); +			goto out; +		} +		if (!svc_sendreply(transp, (xdrproc_t) xdr_void, 0)) { +			svcerr_systemerr(transp); +		} +		goto out; + +	case 1: +		if (!svc_getargs(transp, (xdrproc_t) xdr_int, +			(char *) &num)) { +			svcerr_decode(transp); +			goto out; +		} +		num += 100; +		if (!svc_sendreply(transp, (xdrproc_t) xdr_int, +			(char *) &num)) { +			svcerr_systemerr(transp); +		} +		goto out; + +	default: +		svcerr_noproc(transp); +		goto out; +	} + +out: +	return; +} + +#if 0 +static void +report_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) +{ +	OM_uint32 maj_stat, min_stat; +	OM_uint32 message_context; +	gss_buffer_desc buf; + +	printf("major_stat=%d, minor_stat=%d\n", maj, min); + +	message_context = 0; +	do { +		maj_stat = gss_display_status(&min_stat, maj, +		    GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buf); +		printf("%.*s\n", (int)buf.length, (char *) buf.value); +		gss_release_buffer(&min_stat, &buf); +	} while (message_context); +	if (mech) { +		message_context = 0; +		do { +			maj_stat = gss_display_status(&min_stat, min, +			    GSS_C_MECH_CODE, mech, &message_context, &buf); +			printf("%.*s\n", (int)buf.length, (char *) buf.value); +			gss_release_buffer(&min_stat, &buf); +		} while (message_context); +	} +	exit(1); +} +#endif + +static bool_t +server_new_context(__unused struct svc_req *req, +    __unused gss_cred_id_t deleg, +    __unused gss_ctx_id_t gss_context, +    rpc_gss_lock_t *lock, +    __unused void **cookie) +{ +	rpc_gss_rawcred_t *rcred = lock->raw_cred; + +	printf("new security context version=%d, mech=%s, qop=%s:\n", +	    rcred->version, rcred->mechanism, rcred->qop); +	print_principal(rcred->client_principal); + +	if (!server_acl) +		return (TRUE); + +	if (rcred->client_principal->len != server_acl->len +	    || memcmp(rcred->client_principal->name, server_acl->name, +		server_acl->len)) { +		return (FALSE); +	} + +	return (TRUE); +} + +static void +test_server(__unused int argc, __unused const char **argv) +{ +	char hostname[128]; +	char principal[128 + 5]; +	const char **mechs; +	static rpc_gss_callback_t cb; + +	if (argc == 3) { +		if (!rpc_gss_get_principal_name(&server_acl, argv[1], +			argv[2], NULL, NULL)) { +			printf("Can't create %s ACL entry for %s\n", +			    argv[1], argv[2]); +			return; +		} +	} + +	gethostname(hostname, sizeof(hostname));; +	snprintf(principal, sizeof(principal), "host@%s", hostname); + +	mechs = rpc_gss_get_mechanisms(); +	while (*mechs) { +		if (!rpc_gss_set_svc_name(principal, *mechs, GSS_C_INDEFINITE, +			123456, 1)) { +			rpc_gss_error_t e; + +			rpc_gss_get_error(&e); +			printf("setting name for %s for %s failed: %d, %d\n", +			    principal, *mechs, +			     e.rpc_gss_error, e.system_error); + +#if 0 +			gss_OID mech_oid; +			gss_OID_set_desc oid_set; +			gss_name_t name; +			OM_uint32 maj_stat, min_stat; +			gss_buffer_desc namebuf; +			gss_cred_id_t cred; + +			rpc_gss_mech_to_oid(*mechs, &mech_oid); +			oid_set.count = 1; +			oid_set.elements = mech_oid; + +			namebuf.value = principal; +			namebuf.length = strlen(principal); +			maj_stat = gss_import_name(&min_stat, &namebuf, +			    GSS_C_NT_HOSTBASED_SERVICE, &name); +			if (maj_stat) { +				printf("gss_import_name failed\n"); +				report_error(mech_oid, maj_stat, min_stat); +			} +			maj_stat = gss_acquire_cred(&min_stat, name, +			    0, &oid_set, GSS_C_ACCEPT, &cred, NULL, NULL); +			if (maj_stat) { +				printf("gss_acquire_cred failed\n"); +				report_error(mech_oid, maj_stat, min_stat); +			} +#endif +		} +		mechs++; +	} + +	cb.program = 123456; +	cb.version = 1; +	cb.callback = server_new_context; +	rpc_gss_set_callback(&cb); + +	svc_create(server_program_1, 123456, 1, 0); +	svc_run(); +} + +static void +test_get_principal_name(int argc, const char **argv) +{ +	const char *mechname, *name, *node, *domain; +	rpc_gss_principal_t principal; + +	if (argc < 3 || argc > 5) { +		printf("usage: rpctest principal <mechname> <name> " +		    "[<node> [<domain>] ]\n"); +		exit(1); +	} + +	mechname = argv[1]; +	name = argv[2]; +	node = NULL; +	domain = NULL; +	if (argc > 3) { +		node = argv[3]; +		if (argc > 4) +			domain = argv[4]; +	} + +	if (rpc_gss_get_principal_name(&principal, mechname, name, +		node, domain)) { +		printf("succeeded:\n"); +		print_principal(principal); +		free(principal); +	} else { +		printf("failed\n"); +	} +} + +int +main(int argc, const char **argv) +{ + +	if (argc < 2) +		usage(); +	if (!strcmp(argv[1], "client")) +		test_client(argc - 1, argv + 1); +	else if (!strcmp(argv[1], "server")) +		test_server(argc - 1, argv + 1); +	else if (!strcmp(argv[1], "principal")) +		test_get_principal_name(argc - 1, argv + 1); +	else +		usage(); + +	return (0); +} | 
