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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/systm.h> 30 #include <sys/errno.h> 31 #include <sys/cmn_err.h> 32 #include <gssapi/gssapi.h> 33 #include <rpc/rpc.h> 34 #include <rpc/rpcsec_defs.h> 35 36 #ifdef RPCGSS_DEBUG 37 /* 38 * Kernel rpcsec_gss module debugging aid. The global variable "rpcgss_log" 39 * is a bit mask which allows various types of debugging messages to be printed 40 * out. 41 * 42 * rpcgss_log & 1 will cause actual failures to be printed. 43 * rpcgss_log & 2 will cause informational messages to be 44 * printed on the client side of rpcsec_gss. 45 * rpcgss_log & 4 will cause informational messages to be 46 * printed on the server side of rpcsec_gss. 47 * rpcgss_log & 8 will cause informational messages to be 48 * printed on both client and server side of rpcsec_gss. 49 */ 50 51 uint_t rpcgss_log = 0; 52 53 #endif /* RPCGSS_DEBUG */ 54 55 /* 56 * Internal utility routines. 57 */ 58 59 /* 60 * Duplicate a gss_OID value. 61 */ 62 void 63 __rpc_gss_dup_oid(gss_OID oid, gss_OID *ret) 64 { 65 gss_OID tmp; 66 67 if (oid == GSS_C_NULL_OID || oid->length == 0) { 68 *ret = NULL; 69 return; 70 } 71 72 tmp = (gss_OID) kmem_alloc(sizeof (gss_OID_desc), KM_SLEEP); 73 if (tmp) { 74 tmp->elements = kmem_alloc((oid->length), KM_SLEEP); 75 bcopy((char *)oid->elements, (char *)tmp->elements, oid->length); 76 tmp->length = oid->length; 77 *ret = tmp; 78 } else { 79 *ret = NULL; 80 } 81 } 82 83 /* 84 * Check if 2 gss_OID are the same. 85 */ 86 bool_t 87 __rpc_gss_oids_equal(oid1, oid2) 88 gss_OID oid1, oid2; 89 { 90 if ((oid1->length == 0) && (oid2->length == 0)) 91 return (TRUE); 92 93 if (oid1->length != oid2->length) 94 return (FALSE); 95 96 return (bcmp(oid1->elements, oid2->elements, oid1->length) == 0); 97 } 98 99 void 100 __rpc_gss_convert_name(principal, name, name_type) 101 rpc_gss_principal_t principal; 102 gss_buffer_desc *name; 103 gss_OID *name_type; 104 { 105 char *cp; 106 107 cp = principal->name; 108 if (*(int *)cp == 0) 109 *name_type = GSS_C_NULL_OID; 110 else { 111 (*name_type)->length = *(int *)cp; 112 (*name_type)->elements = (void *)(cp + sizeof (int)); 113 } 114 cp += RNDUP(*(int *)cp) + sizeof (int); 115 if ((name->length = *(int *)cp) == 0) 116 name->value = NULL; 117 else 118 name->value = cp + sizeof (int); 119 } 120 121 /* 122 * Make a client principal name from a flat exported gss name. 123 */ 124 bool_t 125 __rpc_gss_make_principal(principal, name) 126 rpc_gss_principal_t *principal; 127 gss_buffer_desc *name; 128 { 129 int plen; 130 char *s; 131 132 RPCGSS_LOG(8, "name-length = %lu\n", name->length); 133 RPCGSS_LOG(8, "name-value = 0x%p\n", (void *)name->value); 134 135 plen = RNDUP(name->length) + sizeof (int); 136 (*principal) = (rpc_gss_principal_t)kmem_alloc(plen, KM_SLEEP); 137 if ((*principal) == NULL) 138 return (FALSE); 139 bzero((caddr_t)(*principal), plen); 140 (*principal)->len = RNDUP(name->length); 141 s = (*principal)->name; 142 bcopy(name->value, s, name->length); 143 return (TRUE); 144 } 145 146 147 /* 148 * Make a copy of a principal name. 149 */ 150 rpc_gss_principal_t 151 __rpc_gss_dup_principal(principal) 152 rpc_gss_principal_t principal; 153 { 154 rpc_gss_principal_t pdup; 155 int len; 156 157 if (principal == NULL) 158 return (NULL); 159 len = principal->len + sizeof (int); 160 if ((pdup = (rpc_gss_principal_t)mem_alloc(len)) == NULL) 161 return (NULL); 162 pdup->len = len; 163 bcopy(principal->name, pdup->name, len); 164 return (pdup); 165 } 166 167 /* 168 * Returns highest and lowest versions of RPCSEC_GSS flavor supported. 169 */ 170 bool_t 171 rpc_gss_get_versions(vers_hi, vers_lo) 172 uint_t *vers_hi; 173 uint_t *vers_lo; 174 { 175 *vers_hi = RPCSEC_GSS_VERSION; 176 *vers_lo = RPCSEC_GSS_VERSION; 177 return (TRUE); 178 } 179 180 void 181 rpc_gss_display_status(major, minor, mech_type, 182 uid, gss_function_name) 183 OM_uint32 major, minor; 184 gss_OID mech_type; 185 uid_t uid; 186 char *gss_function_name; 187 188 { 189 int message_context; 190 int major_stat; 191 uint_t minor_stat; 192 gss_buffer_desc status_string; 193 194 /* 195 * Before we return let us see 196 * whether we can log more meaningful error 197 * string using kgss_display_status 198 * If we can not just log the gssstat in hex 199 * and return. 200 */ 201 message_context = 0; 202 203 /* 204 * First get the status string out of gss_major_code 205 */ 206 207 do { 208 major_stat = kgss_display_status(&minor_stat, major, 209 GSS_C_GSS_CODE, mech_type, 210 &message_context, &status_string, uid); 211 /* 212 * If we failed just log the original error codes 213 */ 214 if (major_stat != GSS_S_COMPLETE && 215 major != GSS_S_CONTINUE_NEEDED) { 216 217 RPCGSS_LOG1(1, "%s GSS major error 0x%x\n", 218 gss_function_name, major); 219 RPCGSS_LOG1(1, "%s GSS minor error 0x%x\n", 220 gss_function_name, minor); 221 222 return; 223 } else { 224 RPCGSS_LOG1(1, "%s GSS Error %s\n", 225 (char *)gss_function_name, 226 (char *)status_string.value); 227 (void) gss_release_buffer(&minor_stat, &status_string); 228 } 229 } while (message_context != 0); 230 /* 231 * Now get the status string out of gss_minor_code 232 * This is mechanism specific error which is most 233 * useful 234 */ 235 message_context = 0; 236 do { 237 major_stat = kgss_display_status(&minor_stat, minor, 238 GSS_C_MECH_CODE, mech_type, 239 &message_context, &status_string, uid); 240 if (major_stat != GSS_S_COMPLETE && 241 major_stat != GSS_S_CONTINUE_NEEDED) { 242 RPCGSS_LOG1(1, "%s GSS minor error 0x%x\n", 243 gss_function_name, minor); 244 return; 245 } else { 246 RPCGSS_LOG1(1, 247 "%s GSS Minor Error %s\n", 248 (char *)gss_function_name, (char *)status_string.value); 249 (void) gss_release_buffer(&minor_stat, 250 &status_string); 251 } 252 } while (message_context != 0); 253 } 254