diff options
Diffstat (limited to 'tools/regression')
-rw-r--r-- | tools/regression/kgssapi/Makefile | 9 | ||||
-rw-r--r-- | tools/regression/kgssapi/gsstest.c | 307 | ||||
-rw-r--r-- | tools/regression/rpcsec_gss/Makefile | 9 | ||||
-rw-r--r-- | tools/regression/rpcsec_gss/rpctest.c | 400 |
4 files changed, 725 insertions, 0 deletions
diff --git a/tools/regression/kgssapi/Makefile b/tools/regression/kgssapi/Makefile new file mode 100644 index 0000000..49059fa --- /dev/null +++ b/tools/regression/kgssapi/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG= gsstest +NO_MAN= +WARNS?= 2 +LDADD= -lgssapi -lgssapi_krb5 +DEBUG_FLAGS= -g -O0 + +.include <bsd.prog.mk> diff --git a/tools/regression/kgssapi/gsstest.c b/tools/regression/kgssapi/gsstest.c new file mode 100644 index 0000000..acebf4c --- /dev/null +++ b/tools/regression/kgssapi/gsstest.c @@ -0,0 +1,307 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/syscall.h> +#include <sys/module.h> + +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <unistd.h> +#include <stdlib.h> + +#include <krb5.h> +#include <gssapi/gssapi.h> +#include <gssapi/gssapi_krb5.h> + +struct gsstest_2_args { + int step; /* test step number */ + gss_buffer_desc input_token; /* token from userland */ + gss_buffer_desc output_token; /* buffer to receive reply token */ +}; +struct gsstest_2_res { + OM_uint32 maj_stat; /* maj_stat from kernel */ + OM_uint32 min_stat; /* min_stat from kernel */ + gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */ +}; + +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); + } +} + +int +main(int argc, char **argv) +{ + struct module_stat stat; + int mod; + int syscall_num; + + stat.version = sizeof(stat); + mod = modfind("gsstest_syscall"); + if (mod < 0) { + fprintf(stderr, "%s: kernel support not present\n", argv[0]); + exit(1); + } + modstat(mod, &stat); + syscall_num = stat.data.intval; + + switch (atoi(argv[1])) { + case 1: + syscall(syscall_num, 1, NULL, NULL); + break; + + case 2: { + struct gsstest_2_args args; + struct gsstest_2_res res; + char hostname[512]; + char token_buffer[8192]; + OM_uint32 maj_stat, min_stat; + gss_ctx_id_t client_context = GSS_C_NO_CONTEXT; + gss_cred_id_t client_cred; + gss_OID mech_type = GSS_C_NO_OID; + gss_buffer_desc name_buf, message_buf; + gss_name_t name; + int32_t enctypes[] = { + ETYPE_DES_CBC_CRC, + ETYPE_ARCFOUR_HMAC_MD5, + ETYPE_ARCFOUR_HMAC_MD5_56, + ETYPE_AES256_CTS_HMAC_SHA1_96, + ETYPE_AES128_CTS_HMAC_SHA1_96, + ETYPE_DES3_CBC_SHA1, + }; + int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); + int established; + int i; + + for (i = 0; i < num_enctypes; i++) { + printf("testing etype %d\n", enctypes[i]); + args.output_token.length = sizeof(token_buffer); + args.output_token.value = token_buffer; + + gethostname(hostname, sizeof(hostname)); + snprintf(token_buffer, sizeof(token_buffer), + "nfs@%s", hostname); + name_buf.length = strlen(token_buffer); + name_buf.value = token_buffer; + maj_stat = gss_import_name(&min_stat, &name_buf, + GSS_C_NT_HOSTBASED_SERVICE, &name); + if (GSS_ERROR(maj_stat)) { + printf("gss_import_name failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + + maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, + 0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred, + NULL, NULL); + if (GSS_ERROR(maj_stat)) { + printf("gss_acquire_cred (client) failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + + maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, + client_cred, 1, &enctypes[i]); + if (GSS_ERROR(maj_stat)) { + printf("gss_krb5_set_allowable_enctypes failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + + res.output_token.length = 0; + res.output_token.value = 0; + established = 0; + while (!established) { + maj_stat = gss_init_sec_context(&min_stat, + client_cred, + &client_context, + name, + GSS_C_NO_OID, + (GSS_C_MUTUAL_FLAG + |GSS_C_CONF_FLAG + |GSS_C_INTEG_FLAG + |GSS_C_SEQUENCE_FLAG + |GSS_C_REPLAY_FLAG), + 0, + GSS_C_NO_CHANNEL_BINDINGS, + &res.output_token, + &mech_type, + &args.input_token, + NULL, + NULL); + if (GSS_ERROR(maj_stat)) { + printf("gss_init_sec_context failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + if (args.input_token.length) { + args.step = 1; + syscall(syscall_num, 2, &args, &res); + gss_release_buffer(&min_stat, + &args.input_token); + if (res.maj_stat != GSS_S_COMPLETE + && res.maj_stat != GSS_S_CONTINUE_NEEDED) { + printf("gss_accept_sec_context (kernel) failed\n"); + report_error(mech_type, res.maj_stat, + res.min_stat); + goto out; + } + } + if (maj_stat == GSS_S_COMPLETE) + established = 1; + } + + message_buf.value = "Hello world"; + message_buf.length = strlen((char *) message_buf.value); + + maj_stat = gss_get_mic(&min_stat, client_context, + GSS_C_QOP_DEFAULT, &message_buf, &args.input_token); + if (GSS_ERROR(maj_stat)) { + printf("gss_get_mic failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + + args.step = 2; + syscall(syscall_num, 2, &args, &res); + gss_release_buffer(&min_stat, &args.input_token); + if (GSS_ERROR(res.maj_stat)) { + printf("kernel gss_verify_mic failed\n"); + report_error(mech_type, res.maj_stat, res.min_stat); + goto out; + } + + maj_stat = gss_verify_mic(&min_stat, client_context, + &message_buf, &res.output_token, NULL); + if (GSS_ERROR(maj_stat)) { + printf("gss_verify_mic failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + + maj_stat = gss_wrap(&min_stat, client_context, + TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, + &args.input_token); + if (GSS_ERROR(maj_stat)) { + printf("gss_wrap failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + + args.step = 3; + syscall(syscall_num, 2, &args, &res); + gss_release_buffer(&min_stat, &args.input_token); + if (GSS_ERROR(res.maj_stat)) { + printf("kernel gss_unwrap failed\n"); + report_error(mech_type, res.maj_stat, res.min_stat); + goto out; + } + + maj_stat = gss_unwrap(&min_stat, client_context, + &res.output_token, &message_buf, NULL, NULL); + if (GSS_ERROR(maj_stat)) { + printf("gss_unwrap failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + gss_release_buffer(&min_stat, &message_buf); + + maj_stat = gss_wrap(&min_stat, client_context, + FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL, + &args.input_token); + if (GSS_ERROR(maj_stat)) { + printf("gss_wrap failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + + args.step = 4; + syscall(syscall_num, 2, &args, &res); + gss_release_buffer(&min_stat, &args.input_token); + if (GSS_ERROR(res.maj_stat)) { + printf("kernel gss_unwrap failed\n"); + report_error(mech_type, res.maj_stat, res.min_stat); + goto out; + } + + maj_stat = gss_unwrap(&min_stat, client_context, + &res.output_token, &message_buf, NULL, NULL); + if (GSS_ERROR(maj_stat)) { + printf("gss_unwrap failed\n"); + report_error(mech_type, maj_stat, min_stat); + goto out; + } + gss_release_buffer(&min_stat, &message_buf); + + args.step = 5; + syscall(syscall_num, 2, &args, &res); + + gss_release_name(&min_stat, &name); + gss_release_cred(&min_stat, &client_cred); + gss_delete_sec_context(&min_stat, &client_context, + GSS_C_NO_BUFFER); + } + + break; + } + case 3: + syscall(syscall_num, 3, NULL, NULL); + break; + case 4: + syscall(syscall_num, 4, NULL, NULL); + break; + } + return (0); + +out: + return (1); +} diff --git a/tools/regression/rpcsec_gss/Makefile b/tools/regression/rpcsec_gss/Makefile new file mode 100644 index 0000000..29b14d6 --- /dev/null +++ b/tools/regression/rpcsec_gss/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG= rpctest +NO_MAN= +WARNS?= 6 +LDADD= -lrpcsec_gss +DEBUG_FLAGS= -g -O0 + +.include <bsd.prog.mk> diff --git a/tools/regression/rpcsec_gss/rpctest.c b/tools/regression/rpcsec_gss/rpctest.c new file mode 100644 index 0000000..847ae3b --- /dev/null +++ b/tools/regression/rpcsec_gss/rpctest.c @@ -0,0 +1,400 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#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); +} |