1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1996-1997,2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/systm.h> 28 #include <sys/errno.h> 29 #include <sys/cmn_err.h> 30 #include <gssapi/gssapi.h> 31 #include <rpc/rpc.h> 32 #include <rpc/rpcsec_defs.h> 33 34 #ifdef RPCGSS_DEBUG 35 /* 36 * Kernel rpcsec_gss module debugging aid. The global variable "rpcgss_log" 37 * is a bit mask which allows various types of debugging messages to be printed 38 * out. 39 * 40 * rpcgss_log & 1 will cause actual failures to be printed. 41 * rpcgss_log & 2 will cause informational messages to be 42 * printed on the client side of rpcsec_gss. 43 * rpcgss_log & 4 will cause informational messages to be 44 * printed on the server side of rpcsec_gss. 45 * rpcgss_log & 8 will cause informational messages to be 46 * printed on both client and server side of rpcsec_gss. 47 */ 48 49 uint_t rpcgss_log = 0; 50 51 #endif /* RPCGSS_DEBUG */ 52 53 /* 54 * Internal utility routines. 55 */ 56 57 /* 58 * Duplicate a gss_OID value. 59 */ 60 void 61 __rpc_gss_dup_oid(gss_OID oid, gss_OID *ret) 62 { 63 gss_OID tmp; 64 65 if (oid == GSS_C_NULL_OID || oid->length == 0) { 66 *ret = NULL; 67 return; 68 } 69 70 tmp = (gss_OID) kmem_alloc(sizeof (gss_OID_desc), KM_SLEEP); 71 if (tmp) { 72 tmp->elements = kmem_alloc((oid->length), KM_SLEEP); 73 bcopy((char *)oid->elements, (char *)tmp->elements, oid->length); 74 tmp->length = oid->length; 75 *ret = tmp; 76 } else { 77 *ret = NULL; 78 } 79 } 80 81 /* 82 * Check if 2 gss_OID are the same. 83 */ 84 bool_t 85 __rpc_gss_oids_equal(oid1, oid2) 86 gss_OID oid1, oid2; 87 { 88 if ((oid1->length == 0) && (oid2->length == 0)) 89 return (TRUE); 90 91 if (oid1->length != oid2->length) 92 return (FALSE); 93 94 return (bcmp(oid1->elements, oid2->elements, oid1->length) == 0); 95 } 96 97 void 98 __rpc_gss_convert_name(principal, name, name_type) 99 rpc_gss_principal_t principal; 100 gss_buffer_desc *name; 101 gss_OID *name_type; 102 { 103 char *cp; 104 105 cp = principal->name; 106 if (*(int *)cp == 0) 107 *name_type = GSS_C_NULL_OID; 108 else { 109 (*name_type)->length = *(int *)cp; 110 (*name_type)->elements = (void *)(cp + sizeof (int)); 111 } 112 cp += RNDUP(*(int *)cp) + sizeof (int); 113 if ((name->length = *(int *)cp) == 0) 114 name->value = NULL; 115 else 116 name->value = cp + sizeof (int); 117 } 118 119 /* 120 * Make a client principal name from a flat exported gss name. 121 */ 122 bool_t 123 __rpc_gss_make_principal(principal, name) 124 rpc_gss_principal_t *principal; 125 gss_buffer_desc *name; 126 { 127 int plen; 128 char *s; 129 130 RPCGSS_LOG(8, "name-length = %lu\n", name->length); 131 RPCGSS_LOG(8, "name-value = 0x%p\n", (void *)name->value); 132 133 plen = RNDUP(name->length) + sizeof (int); 134 (*principal) = (rpc_gss_principal_t)kmem_alloc(plen, KM_SLEEP); 135 if ((*principal) == NULL) 136 return (FALSE); 137 bzero((caddr_t)(*principal), plen); 138 (*principal)->len = RNDUP(name->length); 139 s = (*principal)->name; 140 bcopy(name->value, s, name->length); 141 return (TRUE); 142 } 143 144 145 /* 146 * Make a copy of a principal name. 147 */ 148 rpc_gss_principal_t 149 __rpc_gss_dup_principal(principal) 150 rpc_gss_principal_t principal; 151 { 152 rpc_gss_principal_t pdup; 153 int len; 154 155 if (principal == NULL) 156 return (NULL); 157 len = principal->len + sizeof (int); 158 if ((pdup = (rpc_gss_principal_t)mem_alloc(len)) == NULL) 159 return (NULL); 160 pdup->len = len; 161 bcopy(principal->name, pdup->name, len); 162 return (pdup); 163 } 164 165 /* 166 * Returns highest and lowest versions of RPCSEC_GSS flavor supported. 167 */ 168 bool_t 169 rpc_gss_get_versions(vers_hi, vers_lo) 170 uint_t *vers_hi; 171 uint_t *vers_lo; 172 { 173 *vers_hi = RPCSEC_GSS_VERSION; 174 *vers_lo = RPCSEC_GSS_VERSION; 175 return (TRUE); 176 } 177 178 void 179 rpc_gss_display_status(major, minor, mech_type, 180 uid, gss_function_name) 181 OM_uint32 major, minor; 182 gss_OID mech_type; 183 uid_t uid; 184 char *gss_function_name; 185 186 { 187 int message_context; 188 int major_stat; 189 uint_t minor_stat; 190 gss_buffer_desc status_string; 191 192 /* 193 * Before we return let us see 194 * whether we can log more meaningful error 195 * string using kgss_display_status 196 * If we can not just log the gssstat in hex 197 * and return. 198 */ 199 message_context = 0; 200 201 /* 202 * First get the status string out of gss_major_code 203 */ 204 205 do { 206 major_stat = kgss_display_status(&minor_stat, major, 207 GSS_C_GSS_CODE, mech_type, 208 &message_context, &status_string, uid); 209 /* 210 * If we failed just log the original error codes 211 */ 212 if (major_stat != GSS_S_COMPLETE && 213 major != GSS_S_CONTINUE_NEEDED) { 214 215 RPCGSS_LOG1(1, "%s GSS major error 0x%x\n", 216 gss_function_name, major); 217 RPCGSS_LOG1(1, "%s GSS minor error 0x%x\n", 218 gss_function_name, minor); 219 220 return; 221 } else { 222 RPCGSS_LOG1(1, "%s GSS Error %s\n", 223 (char *)gss_function_name, 224 (char *)status_string.value); 225 (void) gss_release_buffer(&minor_stat, &status_string); 226 } 227 } while (message_context != 0); 228 /* 229 * Now get the status string out of gss_minor_code 230 * This is mechanism specific error which is most 231 * useful 232 */ 233 message_context = 0; 234 do { 235 major_stat = kgss_display_status(&minor_stat, minor, 236 GSS_C_MECH_CODE, mech_type, 237 &message_context, &status_string, uid); 238 if (major_stat != GSS_S_COMPLETE && 239 major_stat != GSS_S_CONTINUE_NEEDED) { 240 RPCGSS_LOG1(1, "%s GSS minor error 0x%x\n", 241 gss_function_name, minor); 242 return; 243 } else { 244 RPCGSS_LOG1(1, 245 "%s GSS Minor Error %s\n", 246 (char *)gss_function_name, (char *)status_string.value); 247 (void) gss_release_buffer(&minor_stat, 248 &status_string); 249 } 250 } while (message_context != 0); 251 } 252