2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <ctype.h>
2N/A#include <strings.h>
2N/A#include <errno.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <syslog.h>
2N/A#include <gssapi/gssapi.h>
2N/A#include <gssapi/gssapi_ext.h>
2N/A#include <rpc/rpc.h>
2N/A#include <rpc/rpcsec_defs.h>
2N/A
2N/A#define SVC_INTEGRITY "integrity"
2N/A#define SVC_PRIVACY "privacy"
2N/A#define SVC_NONE "none"
2N/A#define SVC_DEFAULT "default"
2N/A
2N/A#define MCALL_MSG_SIZE 24
2N/A/*
2N/A * Private data kept per client handle
2N/A */
2N/Astruct cu_data {
2N/A int cu_fd; /* connections fd */
2N/A bool_t cu_closeit; /* opened by library */
2N/A struct netbuf cu_raddr; /* remote address */
2N/A struct timeval cu_wait; /* retransmit interval */
2N/A struct timeval cu_total; /* total time for the call */
2N/A struct rpc_err cu_error;
2N/A struct t_unitdata *cu_tr_data;
2N/A XDR cu_outxdrs;
2N/A char *cu_outbuf_start;
2N/A char cu_outbuf[MCALL_MSG_SIZE];
2N/A uint_t cu_xdrpos;
2N/A uint_t cu_sendsz; /* send size */
2N/A uint_t cu_recvsz; /* recv size */
2N/A struct pollfd pfdp;
2N/A char cu_inbuf[1];
2N/A};
2N/A
2N/A/*
2N/A * Internal utility routines.
2N/A */
2N/Abool_t
2N/A__rpc_gss_mech_to_oid(char *mech, rpc_gss_OID *oid)
2N/A{
2N/A if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE)
2N/A return (FALSE);
2N/A return (TRUE);
2N/A}
2N/A
2N/Achar *
2N/A__rpc_gss_oid_to_mech(rpc_gss_OID oid)
2N/A{
2N/A return ((char *)__gss_oid_to_mech((const gss_OID)oid));
2N/A}
2N/A
2N/A
2N/Abool_t
2N/A__rpc_gss_qop_to_num(char *qop, char *mech, OM_uint32 *num)
2N/A{
2N/A if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE)
2N/A return (FALSE);
2N/A return (TRUE);
2N/A}
2N/A
2N/Achar *
2N/A__rpc_gss_num_to_qop(char *mech, OM_uint32 num)
2N/A{
2N/A char *qop;
2N/A
2N/A if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE)
2N/A return (NULL);
2N/A return (qop);
2N/A}
2N/A
2N/Abool_t
2N/A__rpc_gss_svc_to_num(char *svc, rpc_gss_service_t *num)
2N/A{
2N/A if (strcasecmp(svc, SVC_INTEGRITY) == 0)
2N/A *num = rpc_gss_svc_integrity;
2N/A else if (strcasecmp(svc, SVC_PRIVACY) == 0)
2N/A *num = rpc_gss_svc_privacy;
2N/A else if (strcasecmp(svc, SVC_NONE) == 0)
2N/A *num = rpc_gss_svc_none;
2N/A else if (strcasecmp(svc, SVC_DEFAULT) == 0)
2N/A *num = rpc_gss_svc_default;
2N/A else
2N/A return (FALSE);
2N/A return (TRUE);
2N/A}
2N/A
2N/Achar *
2N/A__rpc_gss_num_to_svc(rpc_gss_service_t num)
2N/A{
2N/A switch (num) {
2N/A case rpc_gss_svc_integrity:
2N/A return (strdup(SVC_INTEGRITY));
2N/A case rpc_gss_svc_privacy:
2N/A return (strdup(SVC_PRIVACY));
2N/A case rpc_gss_svc_none:
2N/A return (strdup(SVC_NONE));
2N/A case rpc_gss_svc_default:
2N/A return (strdup(SVC_DEFAULT));
2N/A default:
2N/A return (NULL);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Given the user name, node, and security domain, get the mechanism
2N/A * specific principal name (for the user name) in exported form.
2N/A */
2N/Abool_t
2N/A__rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mech,
2N/A char *user, char *node, char *secdomain)
2N/A{
2N/A gss_name_t gss_name, gss_canon_name;
2N/A gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
2N/A char user_name[256], *s;
2N/A gss_OID mech_oid;
2N/A int nlen = 0, slen = 0, plen;
2N/A OM_uint32 major, minor;
2N/A
2N/A *principal = NULL;
2N/A if (user == NULL || strlen(user) == 0)
2N/A return (FALSE);
2N/A
2N/A if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) {
2N/A syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get"
2N/A "mech oid");
2N/A return (FALSE);
2N/A }
2N/A
2N/A if (secdomain != NULL)
2N/A slen = strlen(secdomain);
2N/A
2N/A if (node != NULL)
2N/A nlen = strlen(node);
2N/A
2N/A strcpy(user_name, user);
2N/A if (nlen > 0) {
2N/A strcat(user_name, "/");
2N/A strcat(user_name, node);
2N/A }
2N/A
2N/A if (slen > 0) {
2N/A strcat(user_name, "@");
2N/A strcat(user_name, secdomain);
2N/A }
2N/A
2N/A name_buf.value = user_name;
2N/A name_buf.length = strlen(user_name);
2N/A
2N/A /*
2N/A * Convert a text string to a GSSAPI Internal name.
2N/A */
2N/A if ((major = gss_import_name(&minor, &name_buf,
2N/A (gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) {
2N/A syslog(LOG_ERR, "rpc_gss_get_principal_name: import name"
2N/A "failed 0x%x", major);
2N/A return (FALSE);
2N/A }
2N/A
2N/A /*
2N/A * Convert the GSSAPI Internal name to a MN - Mechanism Name
2N/A */
2N/A if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid,
2N/A &gss_canon_name)) != GSS_S_COMPLETE) {
2N/A syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name"
2N/A "failed 0x%x", major);
2N/A gss_release_name(&minor, &gss_name);
2N/A return (FALSE);
2N/A }
2N/A gss_release_name(&minor, &gss_name);
2N/A
2N/A /*
2N/A * Convert the MN Internal name to an exported flat name, so
2N/A * it is suitable for binary comparison.
2N/A */
2N/A if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) !=
2N/A GSS_S_COMPLETE) {
2N/A syslog(LOG_ERR, "rpc_gss_get_principal_name: export name"
2N/A "failed %x", major);
2N/A gss_release_name(&minor, &gss_canon_name);
2N/A return (FALSE);
2N/A }
2N/A gss_release_name(&minor, &gss_canon_name);
2N/A
2N/A /*
2N/A * Put the exported name into rpc_gss_principal_t structure.
2N/A */
2N/A plen = RNDUP(name_buf.length) + sizeof (int);
2N/A (*principal) = malloc(plen);
2N/A if ((*principal) == NULL) {
2N/A gss_release_buffer(&minor, &name_buf);
2N/A return (FALSE);
2N/A }
2N/A bzero((caddr_t)(*principal), plen);
2N/A (*principal)->len = RNDUP(name_buf.length);
2N/A s = (*principal)->name;
2N/A memcpy(s, name_buf.value, name_buf.length);
2N/A gss_release_buffer(&minor, &name_buf);
2N/A
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Return supported mechanisms.
2N/A */
2N/Achar **
2N/A__rpc_gss_get_mechanisms(void)
2N/A{
2N/A static char *mech_list[MAX_MECH_OID_PAIRS+1];
2N/A
2N/A *mech_list = NULL;
2N/A __gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
2N/A return (mech_list);
2N/A}
2N/A
2N/A/*
2N/A * For a given mechanism, return information about it.
2N/A */
2N/A/*
2N/A * static char *krb5_qop_list[] = {Q_DEFAULT, NULL};
2N/A */
2N/A
2N/A/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
2N/A/* Don't know how to get the service type for a given mech. */
2N/A/* "service" should NOT be there! */
2N/A/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */
2N/A
2N/Achar **
2N/A__rpc_gss_get_mech_info(char *mech, rpc_gss_service_t *service)
2N/A{
2N/A char **l;
2N/A
2N/A l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *));
2N/A if (l == NULL)
2N/A return (NULL);
2N/A
2N/A if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) {
2N/A free(l);
2N/A return (NULL);
2N/A }
2N/A /* !!!!!!!!!!!!!!!! */
2N/A *service = rpc_gss_svc_privacy; /* What service type? */
2N/A /* !!!!!!!!!!!!!!!! */
2N/A return (l);
2N/A}
2N/A
2N/A/*
2N/A * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
2N/A */
2N/Abool_t
2N/A__rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo)
2N/A{
2N/A *vers_hi = RPCSEC_GSS_VERSION;
2N/A *vers_lo = RPCSEC_GSS_VERSION;
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Check if a mechanism is installed.
2N/A */
2N/Abool_t
2N/A__rpc_gss_is_installed(char *mech)
2N/A{
2N/A char **l;
2N/A
2N/A if (mech == NULL)
2N/A return (FALSE);
2N/A
2N/A if ((l = __rpc_gss_get_mechanisms()) == NULL)
2N/A return (FALSE);
2N/A
2N/A while (*l != NULL) {
2N/A if (strcmp(*l, mech) == 0)
2N/A return (TRUE);
2N/A l++;
2N/A }
2N/A return (FALSE);
2N/A}