/*- * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ * Authors: Doug Rabson * Developed with Red Inc: Alfred Perlstein * * 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 #else #define __unused #endif #include #include #include #include #include #include #include #include #include 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 " "[ [] ]\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); }