17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*61961e0fSrobinson 237c478bd9Sstevel@tonic-gate /* 24*61961e0fSrobinson * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25*61961e0fSrobinson * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <ctype.h> 337c478bd9Sstevel@tonic-gate #include <strings.h> 347c478bd9Sstevel@tonic-gate #include <errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/types.h> 367c478bd9Sstevel@tonic-gate #include <sys/stat.h> 377c478bd9Sstevel@tonic-gate #include <syslog.h> 387c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h> 397c478bd9Sstevel@tonic-gate #include <gssapi/gssapi_ext.h> 407c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 417c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_defs.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate #define SVC_INTEGRITY "integrity" 447c478bd9Sstevel@tonic-gate #define SVC_PRIVACY "privacy" 457c478bd9Sstevel@tonic-gate #define SVC_NONE "none" 467c478bd9Sstevel@tonic-gate #define SVC_DEFAULT "default" 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #define MCALL_MSG_SIZE 24 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * Private data kept per client handle 517c478bd9Sstevel@tonic-gate */ 527c478bd9Sstevel@tonic-gate struct cu_data { 537c478bd9Sstevel@tonic-gate int cu_fd; /* connections fd */ 547c478bd9Sstevel@tonic-gate bool_t cu_closeit; /* opened by library */ 557c478bd9Sstevel@tonic-gate struct netbuf cu_raddr; /* remote address */ 567c478bd9Sstevel@tonic-gate struct timeval cu_wait; /* retransmit interval */ 577c478bd9Sstevel@tonic-gate struct timeval cu_total; /* total time for the call */ 587c478bd9Sstevel@tonic-gate struct rpc_err cu_error; 597c478bd9Sstevel@tonic-gate struct t_unitdata *cu_tr_data; 607c478bd9Sstevel@tonic-gate XDR cu_outxdrs; 617c478bd9Sstevel@tonic-gate char *cu_outbuf_start; 627c478bd9Sstevel@tonic-gate char cu_outbuf[MCALL_MSG_SIZE]; 63*61961e0fSrobinson uint_t cu_xdrpos; 64*61961e0fSrobinson uint_t cu_sendsz; /* send size */ 65*61961e0fSrobinson uint_t cu_recvsz; /* recv size */ 667c478bd9Sstevel@tonic-gate struct pollfd pfdp; 677c478bd9Sstevel@tonic-gate char cu_inbuf[1]; 687c478bd9Sstevel@tonic-gate }; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * Internal utility routines. 727c478bd9Sstevel@tonic-gate */ 737c478bd9Sstevel@tonic-gate bool_t 74*61961e0fSrobinson __rpc_gss_mech_to_oid(char *mech, rpc_gss_OID *oid) 757c478bd9Sstevel@tonic-gate { 767c478bd9Sstevel@tonic-gate if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE) 777c478bd9Sstevel@tonic-gate return (FALSE); 787c478bd9Sstevel@tonic-gate return (TRUE); 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate char * 82*61961e0fSrobinson __rpc_gss_oid_to_mech(rpc_gss_OID oid) 837c478bd9Sstevel@tonic-gate { 847c478bd9Sstevel@tonic-gate return ((char *)__gss_oid_to_mech((const gss_OID)oid)); 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate bool_t 89*61961e0fSrobinson __rpc_gss_qop_to_num(char *qop, char *mech, OM_uint32 *num) 907c478bd9Sstevel@tonic-gate { 917c478bd9Sstevel@tonic-gate if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE) 927c478bd9Sstevel@tonic-gate return (FALSE); 937c478bd9Sstevel@tonic-gate return (TRUE); 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate char * 97*61961e0fSrobinson __rpc_gss_num_to_qop(char *mech, OM_uint32 num) 987c478bd9Sstevel@tonic-gate { 997c478bd9Sstevel@tonic-gate char *qop; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE) 1027c478bd9Sstevel@tonic-gate return (NULL); 1037c478bd9Sstevel@tonic-gate return (qop); 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate bool_t 107*61961e0fSrobinson __rpc_gss_svc_to_num(char *svc, rpc_gss_service_t *num) 1087c478bd9Sstevel@tonic-gate { 1097c478bd9Sstevel@tonic-gate if (strcasecmp(svc, SVC_INTEGRITY) == 0) 1107c478bd9Sstevel@tonic-gate *num = rpc_gss_svc_integrity; 1117c478bd9Sstevel@tonic-gate else if (strcasecmp(svc, SVC_PRIVACY) == 0) 1127c478bd9Sstevel@tonic-gate *num = rpc_gss_svc_privacy; 1137c478bd9Sstevel@tonic-gate else if (strcasecmp(svc, SVC_NONE) == 0) 1147c478bd9Sstevel@tonic-gate *num = rpc_gss_svc_none; 1157c478bd9Sstevel@tonic-gate else if (strcasecmp(svc, SVC_DEFAULT) == 0) 1167c478bd9Sstevel@tonic-gate *num = rpc_gss_svc_default; 1177c478bd9Sstevel@tonic-gate else 1187c478bd9Sstevel@tonic-gate return (FALSE); 1197c478bd9Sstevel@tonic-gate return (TRUE); 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate char * 123*61961e0fSrobinson __rpc_gss_num_to_svc(rpc_gss_service_t num) 1247c478bd9Sstevel@tonic-gate { 1257c478bd9Sstevel@tonic-gate switch (num) { 1267c478bd9Sstevel@tonic-gate case rpc_gss_svc_integrity: 1277c478bd9Sstevel@tonic-gate return (strdup(SVC_INTEGRITY)); 1287c478bd9Sstevel@tonic-gate case rpc_gss_svc_privacy: 1297c478bd9Sstevel@tonic-gate return (strdup(SVC_PRIVACY)); 1307c478bd9Sstevel@tonic-gate case rpc_gss_svc_none: 1317c478bd9Sstevel@tonic-gate return (strdup(SVC_NONE)); 1327c478bd9Sstevel@tonic-gate case rpc_gss_svc_default: 1337c478bd9Sstevel@tonic-gate return (strdup(SVC_DEFAULT)); 1347c478bd9Sstevel@tonic-gate default: 1357c478bd9Sstevel@tonic-gate return (NULL); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Given the user name, node, and security domain, get the mechanism 1417c478bd9Sstevel@tonic-gate * specific principal name (for the user name) in exported form. 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate bool_t 144*61961e0fSrobinson __rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mech, 145*61961e0fSrobinson char *user, char *node, char *secdomain) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate gss_name_t gss_name, gss_canon_name; 1487c478bd9Sstevel@tonic-gate gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER; 1497c478bd9Sstevel@tonic-gate char user_name[256], *s; 1507c478bd9Sstevel@tonic-gate gss_OID mech_oid; 1517c478bd9Sstevel@tonic-gate int nlen = 0, slen = 0, plen; 1527c478bd9Sstevel@tonic-gate OM_uint32 major, minor; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate *principal = NULL; 1557c478bd9Sstevel@tonic-gate if (user == NULL || strlen(user) == 0) 1567c478bd9Sstevel@tonic-gate return (FALSE); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) { 1597c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get" 1607c478bd9Sstevel@tonic-gate "mech oid"); 1617c478bd9Sstevel@tonic-gate return (FALSE); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate if (secdomain != NULL) 1657c478bd9Sstevel@tonic-gate slen = strlen(secdomain); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate if (node != NULL) 1687c478bd9Sstevel@tonic-gate nlen = strlen(node); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate strcpy(user_name, user); 1717c478bd9Sstevel@tonic-gate if (nlen > 0) { 1727c478bd9Sstevel@tonic-gate strcat(user_name, "/"); 1737c478bd9Sstevel@tonic-gate strcat(user_name, node); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if (slen > 0) { 1777c478bd9Sstevel@tonic-gate strcat(user_name, "@"); 1787c478bd9Sstevel@tonic-gate strcat(user_name, secdomain); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate name_buf.value = user_name; 1827c478bd9Sstevel@tonic-gate name_buf.length = strlen(user_name); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * Convert a text string to a GSSAPI Internal name. 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate if ((major = gss_import_name(&minor, &name_buf, 1887c478bd9Sstevel@tonic-gate (gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) { 1897c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rpc_gss_get_principal_name: import name" 1907c478bd9Sstevel@tonic-gate "failed 0x%x", major); 1917c478bd9Sstevel@tonic-gate return (FALSE); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate /* 1957c478bd9Sstevel@tonic-gate * Convert the GSSAPI Internal name to a MN - Mechanism Name 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid, 1987c478bd9Sstevel@tonic-gate &gss_canon_name)) != GSS_S_COMPLETE) { 1997c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name" 2007c478bd9Sstevel@tonic-gate "failed 0x%x", major); 2017c478bd9Sstevel@tonic-gate gss_release_name(&minor, &gss_name); 2027c478bd9Sstevel@tonic-gate return (FALSE); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate gss_release_name(&minor, &gss_name); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* 2077c478bd9Sstevel@tonic-gate * Convert the MN Internal name to an exported flat name, so 2087c478bd9Sstevel@tonic-gate * it is suitable for binary comparison. 2097c478bd9Sstevel@tonic-gate */ 2107c478bd9Sstevel@tonic-gate if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) != 2117c478bd9Sstevel@tonic-gate GSS_S_COMPLETE) { 2127c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rpc_gss_get_principal_name: export name" 2137c478bd9Sstevel@tonic-gate "failed %x", major); 2147c478bd9Sstevel@tonic-gate gss_release_name(&minor, &gss_canon_name); 2157c478bd9Sstevel@tonic-gate return (FALSE); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate gss_release_name(&minor, &gss_canon_name); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * Put the exported name into rpc_gss_principal_t structure. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate plen = RNDUP(name_buf.length) + sizeof (int); 223*61961e0fSrobinson (*principal) = malloc(plen); 2247c478bd9Sstevel@tonic-gate if ((*principal) == NULL) { 2257c478bd9Sstevel@tonic-gate gss_release_buffer(&minor, &name_buf); 2267c478bd9Sstevel@tonic-gate return (FALSE); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate bzero((caddr_t)(*principal), plen); 2297c478bd9Sstevel@tonic-gate (*principal)->len = RNDUP(name_buf.length); 2307c478bd9Sstevel@tonic-gate s = (*principal)->name; 2317c478bd9Sstevel@tonic-gate memcpy(s, name_buf.value, name_buf.length); 2327c478bd9Sstevel@tonic-gate gss_release_buffer(&minor, &name_buf); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate return (TRUE); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * Return supported mechanisms. 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate char ** 241*61961e0fSrobinson __rpc_gss_get_mechanisms(void) 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate static char *mech_list[MAX_MECH_OID_PAIRS+1]; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate *mech_list = NULL; 2467c478bd9Sstevel@tonic-gate __gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1); 2477c478bd9Sstevel@tonic-gate return (mech_list); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* 2517c478bd9Sstevel@tonic-gate * For a given mechanism, return information about it. 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * static char *krb5_qop_list[] = {Q_DEFAULT, NULL}; 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ 2587c478bd9Sstevel@tonic-gate /* Don't know how to get the service type for a given mech. */ 2597c478bd9Sstevel@tonic-gate /* "service" should NOT be there! */ 2607c478bd9Sstevel@tonic-gate /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */ 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate char ** 263*61961e0fSrobinson __rpc_gss_get_mech_info(char *mech, rpc_gss_service_t *service) 2647c478bd9Sstevel@tonic-gate { 2657c478bd9Sstevel@tonic-gate char **l; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *)); 2687c478bd9Sstevel@tonic-gate if (l == NULL) 2697c478bd9Sstevel@tonic-gate return (NULL); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) { 2727c478bd9Sstevel@tonic-gate free(l); 2737c478bd9Sstevel@tonic-gate return (NULL); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate /* !!!!!!!!!!!!!!!! */ 2767c478bd9Sstevel@tonic-gate *service = rpc_gss_svc_privacy; /* What service type? */ 2777c478bd9Sstevel@tonic-gate /* !!!!!!!!!!!!!!!! */ 2787c478bd9Sstevel@tonic-gate return (l); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * Returns highest and lowest versions of RPCSEC_GSS flavor supported. 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate bool_t 285*61961e0fSrobinson __rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo) 2867c478bd9Sstevel@tonic-gate { 2877c478bd9Sstevel@tonic-gate *vers_hi = RPCSEC_GSS_VERSION; 2887c478bd9Sstevel@tonic-gate *vers_lo = RPCSEC_GSS_VERSION; 2897c478bd9Sstevel@tonic-gate return (TRUE); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate * Check if a mechanism is installed. 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate bool_t 296*61961e0fSrobinson __rpc_gss_is_installed(char *mech) 2977c478bd9Sstevel@tonic-gate { 2987c478bd9Sstevel@tonic-gate char **l; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate if (mech == NULL) 3017c478bd9Sstevel@tonic-gate return (FALSE); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if ((l = __rpc_gss_get_mechanisms()) == NULL) 3047c478bd9Sstevel@tonic-gate return (FALSE); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate while (*l != NULL) { 3077c478bd9Sstevel@tonic-gate if (strcmp(*l, mech) == 0) 3087c478bd9Sstevel@tonic-gate return (TRUE); 3097c478bd9Sstevel@tonic-gate l++; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate return (FALSE); 3127c478bd9Sstevel@tonic-gate } 313