10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
22*132Srobinson
230Sstevel@tonic-gate /*
24*132Srobinson * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25*132Srobinson * Use is subject to license terms.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <ctype.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include <syslog.h>
380Sstevel@tonic-gate #include <gssapi/gssapi.h>
390Sstevel@tonic-gate #include <gssapi/gssapi_ext.h>
400Sstevel@tonic-gate #include <rpc/rpc.h>
410Sstevel@tonic-gate #include <rpc/rpcsec_defs.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate #define SVC_INTEGRITY "integrity"
440Sstevel@tonic-gate #define SVC_PRIVACY "privacy"
450Sstevel@tonic-gate #define SVC_NONE "none"
460Sstevel@tonic-gate #define SVC_DEFAULT "default"
470Sstevel@tonic-gate
480Sstevel@tonic-gate #define MCALL_MSG_SIZE 24
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate * Private data kept per client handle
510Sstevel@tonic-gate */
520Sstevel@tonic-gate struct cu_data {
530Sstevel@tonic-gate int cu_fd; /* connections fd */
540Sstevel@tonic-gate bool_t cu_closeit; /* opened by library */
550Sstevel@tonic-gate struct netbuf cu_raddr; /* remote address */
560Sstevel@tonic-gate struct timeval cu_wait; /* retransmit interval */
570Sstevel@tonic-gate struct timeval cu_total; /* total time for the call */
580Sstevel@tonic-gate struct rpc_err cu_error;
590Sstevel@tonic-gate struct t_unitdata *cu_tr_data;
600Sstevel@tonic-gate XDR cu_outxdrs;
610Sstevel@tonic-gate char *cu_outbuf_start;
620Sstevel@tonic-gate char cu_outbuf[MCALL_MSG_SIZE];
63*132Srobinson uint_t cu_xdrpos;
64*132Srobinson uint_t cu_sendsz; /* send size */
65*132Srobinson uint_t cu_recvsz; /* recv size */
660Sstevel@tonic-gate struct pollfd pfdp;
670Sstevel@tonic-gate char cu_inbuf[1];
680Sstevel@tonic-gate };
690Sstevel@tonic-gate
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate * Internal utility routines.
720Sstevel@tonic-gate */
730Sstevel@tonic-gate bool_t
__rpc_gss_mech_to_oid(char * mech,rpc_gss_OID * oid)74*132Srobinson __rpc_gss_mech_to_oid(char *mech, rpc_gss_OID *oid)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE)
770Sstevel@tonic-gate return (FALSE);
780Sstevel@tonic-gate return (TRUE);
790Sstevel@tonic-gate }
800Sstevel@tonic-gate
810Sstevel@tonic-gate char *
__rpc_gss_oid_to_mech(rpc_gss_OID oid)82*132Srobinson __rpc_gss_oid_to_mech(rpc_gss_OID oid)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate return ((char *)__gss_oid_to_mech((const gss_OID)oid));
850Sstevel@tonic-gate }
860Sstevel@tonic-gate
870Sstevel@tonic-gate
880Sstevel@tonic-gate bool_t
__rpc_gss_qop_to_num(char * qop,char * mech,OM_uint32 * num)89*132Srobinson __rpc_gss_qop_to_num(char *qop, char *mech, OM_uint32 *num)
900Sstevel@tonic-gate {
910Sstevel@tonic-gate if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE)
920Sstevel@tonic-gate return (FALSE);
930Sstevel@tonic-gate return (TRUE);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate
960Sstevel@tonic-gate char *
__rpc_gss_num_to_qop(char * mech,OM_uint32 num)97*132Srobinson __rpc_gss_num_to_qop(char *mech, OM_uint32 num)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate char *qop;
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE)
1020Sstevel@tonic-gate return (NULL);
1030Sstevel@tonic-gate return (qop);
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate bool_t
__rpc_gss_svc_to_num(char * svc,rpc_gss_service_t * num)107*132Srobinson __rpc_gss_svc_to_num(char *svc, rpc_gss_service_t *num)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate if (strcasecmp(svc, SVC_INTEGRITY) == 0)
1100Sstevel@tonic-gate *num = rpc_gss_svc_integrity;
1110Sstevel@tonic-gate else if (strcasecmp(svc, SVC_PRIVACY) == 0)
1120Sstevel@tonic-gate *num = rpc_gss_svc_privacy;
1130Sstevel@tonic-gate else if (strcasecmp(svc, SVC_NONE) == 0)
1140Sstevel@tonic-gate *num = rpc_gss_svc_none;
1150Sstevel@tonic-gate else if (strcasecmp(svc, SVC_DEFAULT) == 0)
1160Sstevel@tonic-gate *num = rpc_gss_svc_default;
1170Sstevel@tonic-gate else
1180Sstevel@tonic-gate return (FALSE);
1190Sstevel@tonic-gate return (TRUE);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate char *
__rpc_gss_num_to_svc(rpc_gss_service_t num)123*132Srobinson __rpc_gss_num_to_svc(rpc_gss_service_t num)
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate switch (num) {
1260Sstevel@tonic-gate case rpc_gss_svc_integrity:
1270Sstevel@tonic-gate return (strdup(SVC_INTEGRITY));
1280Sstevel@tonic-gate case rpc_gss_svc_privacy:
1290Sstevel@tonic-gate return (strdup(SVC_PRIVACY));
1300Sstevel@tonic-gate case rpc_gss_svc_none:
1310Sstevel@tonic-gate return (strdup(SVC_NONE));
1320Sstevel@tonic-gate case rpc_gss_svc_default:
1330Sstevel@tonic-gate return (strdup(SVC_DEFAULT));
1340Sstevel@tonic-gate default:
1350Sstevel@tonic-gate return (NULL);
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate * Given the user name, node, and security domain, get the mechanism
1410Sstevel@tonic-gate * specific principal name (for the user name) in exported form.
1420Sstevel@tonic-gate */
1430Sstevel@tonic-gate bool_t
__rpc_gss_get_principal_name(rpc_gss_principal_t * principal,char * mech,char * user,char * node,char * secdomain)144*132Srobinson __rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mech,
145*132Srobinson char *user, char *node, char *secdomain)
1460Sstevel@tonic-gate {
1470Sstevel@tonic-gate gss_name_t gss_name, gss_canon_name;
1480Sstevel@tonic-gate gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
1490Sstevel@tonic-gate char user_name[256], *s;
1500Sstevel@tonic-gate gss_OID mech_oid;
1510Sstevel@tonic-gate int nlen = 0, slen = 0, plen;
1520Sstevel@tonic-gate OM_uint32 major, minor;
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate *principal = NULL;
1550Sstevel@tonic-gate if (user == NULL || strlen(user) == 0)
1560Sstevel@tonic-gate return (FALSE);
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) {
1590Sstevel@tonic-gate syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get"
1600Sstevel@tonic-gate "mech oid");
1610Sstevel@tonic-gate return (FALSE);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate if (secdomain != NULL)
1650Sstevel@tonic-gate slen = strlen(secdomain);
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate if (node != NULL)
1680Sstevel@tonic-gate nlen = strlen(node);
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate strcpy(user_name, user);
1710Sstevel@tonic-gate if (nlen > 0) {
1720Sstevel@tonic-gate strcat(user_name, "/");
1730Sstevel@tonic-gate strcat(user_name, node);
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate if (slen > 0) {
1770Sstevel@tonic-gate strcat(user_name, "@");
1780Sstevel@tonic-gate strcat(user_name, secdomain);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate name_buf.value = user_name;
1820Sstevel@tonic-gate name_buf.length = strlen(user_name);
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate * Convert a text string to a GSSAPI Internal name.
1860Sstevel@tonic-gate */
1870Sstevel@tonic-gate if ((major = gss_import_name(&minor, &name_buf,
1880Sstevel@tonic-gate (gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) {
1890Sstevel@tonic-gate syslog(LOG_ERR, "rpc_gss_get_principal_name: import name"
1900Sstevel@tonic-gate "failed 0x%x", major);
1910Sstevel@tonic-gate return (FALSE);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate /*
1950Sstevel@tonic-gate * Convert the GSSAPI Internal name to a MN - Mechanism Name
1960Sstevel@tonic-gate */
1970Sstevel@tonic-gate if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid,
1980Sstevel@tonic-gate &gss_canon_name)) != GSS_S_COMPLETE) {
1990Sstevel@tonic-gate syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name"
2000Sstevel@tonic-gate "failed 0x%x", major);
2010Sstevel@tonic-gate gss_release_name(&minor, &gss_name);
2020Sstevel@tonic-gate return (FALSE);
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate gss_release_name(&minor, &gss_name);
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate /*
2070Sstevel@tonic-gate * Convert the MN Internal name to an exported flat name, so
2080Sstevel@tonic-gate * it is suitable for binary comparison.
2090Sstevel@tonic-gate */
2100Sstevel@tonic-gate if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) !=
2110Sstevel@tonic-gate GSS_S_COMPLETE) {
2120Sstevel@tonic-gate syslog(LOG_ERR, "rpc_gss_get_principal_name: export name"
2130Sstevel@tonic-gate "failed %x", major);
2140Sstevel@tonic-gate gss_release_name(&minor, &gss_canon_name);
2150Sstevel@tonic-gate return (FALSE);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate gss_release_name(&minor, &gss_canon_name);
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate /*
2200Sstevel@tonic-gate * Put the exported name into rpc_gss_principal_t structure.
2210Sstevel@tonic-gate */
2220Sstevel@tonic-gate plen = RNDUP(name_buf.length) + sizeof (int);
223*132Srobinson (*principal) = malloc(plen);
2240Sstevel@tonic-gate if ((*principal) == NULL) {
2250Sstevel@tonic-gate gss_release_buffer(&minor, &name_buf);
2260Sstevel@tonic-gate return (FALSE);
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate bzero((caddr_t)(*principal), plen);
2290Sstevel@tonic-gate (*principal)->len = RNDUP(name_buf.length);
2300Sstevel@tonic-gate s = (*principal)->name;
2310Sstevel@tonic-gate memcpy(s, name_buf.value, name_buf.length);
2320Sstevel@tonic-gate gss_release_buffer(&minor, &name_buf);
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate return (TRUE);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate * Return supported mechanisms.
2390Sstevel@tonic-gate */
2400Sstevel@tonic-gate char **
__rpc_gss_get_mechanisms(void)241*132Srobinson __rpc_gss_get_mechanisms(void)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate static char *mech_list[MAX_MECH_OID_PAIRS+1];
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate *mech_list = NULL;
2460Sstevel@tonic-gate __gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
2470Sstevel@tonic-gate return (mech_list);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate * For a given mechanism, return information about it.
2520Sstevel@tonic-gate */
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate * static char *krb5_qop_list[] = {Q_DEFAULT, NULL};
2550Sstevel@tonic-gate */
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
2580Sstevel@tonic-gate /* Don't know how to get the service type for a given mech. */
2590Sstevel@tonic-gate /* "service" should NOT be there! */
2600Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate char **
__rpc_gss_get_mech_info(char * mech,rpc_gss_service_t * service)263*132Srobinson __rpc_gss_get_mech_info(char *mech, rpc_gss_service_t *service)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate char **l;
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *));
2680Sstevel@tonic-gate if (l == NULL)
2690Sstevel@tonic-gate return (NULL);
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) {
2720Sstevel@tonic-gate free(l);
2730Sstevel@tonic-gate return (NULL);
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate /* !!!!!!!!!!!!!!!! */
2760Sstevel@tonic-gate *service = rpc_gss_svc_privacy; /* What service type? */
2770Sstevel@tonic-gate /* !!!!!!!!!!!!!!!! */
2780Sstevel@tonic-gate return (l);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
2830Sstevel@tonic-gate */
2840Sstevel@tonic-gate bool_t
__rpc_gss_get_versions(uint_t * vers_hi,uint_t * vers_lo)285*132Srobinson __rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo)
2860Sstevel@tonic-gate {
2870Sstevel@tonic-gate *vers_hi = RPCSEC_GSS_VERSION;
2880Sstevel@tonic-gate *vers_lo = RPCSEC_GSS_VERSION;
2890Sstevel@tonic-gate return (TRUE);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate * Check if a mechanism is installed.
2940Sstevel@tonic-gate */
2950Sstevel@tonic-gate bool_t
__rpc_gss_is_installed(char * mech)296*132Srobinson __rpc_gss_is_installed(char *mech)
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate char **l;
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate if (mech == NULL)
3010Sstevel@tonic-gate return (FALSE);
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate if ((l = __rpc_gss_get_mechanisms()) == NULL)
3040Sstevel@tonic-gate return (FALSE);
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate while (*l != NULL) {
3070Sstevel@tonic-gate if (strcmp(*l, mech) == 0)
3080Sstevel@tonic-gate return (TRUE);
3090Sstevel@tonic-gate l++;
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate return (FALSE);
3120Sstevel@tonic-gate }
313